feat: wip support i18n

This commit is contained in:
lleohao
2024-09-01 13:22:13 +00:00
parent cd1a848b45
commit 2bef37a1d0
9 changed files with 72 additions and 23 deletions

View File

@ -98,7 +98,10 @@
"Active": "Active", "Active": "Active",
"Add members": "Add members", "Add members": "Add members",
"Search for users": "Search for users", "Search for users": "Search for users",
"No user found": "No user found" "No user found": "No user found",
"Add groups": "Add groups",
"Search for groups": "Search for groups",
"No group found": "No group found"
}, },
"space": { "space": {
"Spaces": "Spaces", "Spaces": "Spaces",

View File

@ -5,6 +5,20 @@
"No pages yet": "No pages yet", "No pages yet": "No pages yet",
"Failed to load page. An error occurred.": "Failed to load page. An error occurred." "Failed to load page. An error occurred.": "Failed to load page. An error occurred."
}, },
"role": {
"Full access": "Full access",
"Has full access to space settings and pages.": "Has full access to space settings and pages.",
"Can edit": "Can edit",
"Can create and edit pages in space.": "Can create and edit pages in space.",
"Can view": "Can view",
"Can view pages in space but not edit.": "Can view pages in space but not edit.",
"Owner": "Owner",
"Can manage workspace": "Can manage workspace",
"Admin": "Admin",
"Can manage workspace but cannot delete it": "Can manage workspace but cannot delete it",
"Member": "Member",
"Can become members of groups and spaces in workspace": "Can become members of groups and spaces in workspace"
},
"layout": { "layout": {
"Home": "Home", "Home": "Home",
"Workspace": "Workspace", "Workspace": "Workspace",

View File

@ -98,7 +98,10 @@
"Active": "活跃", "Active": "活跃",
"Add members": "添加成员", "Add members": "添加成员",
"Search for users": "搜索用户", "Search for users": "搜索用户",
"No user found": "未找到用户" "No user found": "未找到用户",
"Add groups": "添加群组",
"Search for groups": "搜索群组",
"No group found": "未找到群组"
}, },
"space": { "space": {
"Spaces": "空间", "Spaces": "空间",

View File

@ -5,6 +5,20 @@
"No pages yet": "暂无页面", "No pages yet": "暂无页面",
"Failed to load page. An error occurred.": "加载页面失败。发生错误。" "Failed to load page. An error occurred.": "加载页面失败。发生错误。"
}, },
"role": {
"Full access": "完全访问",
"Has full access to space settings and pages": "具有对空间设置和页面的完全访问权限",
"Can edit": "可以编辑",
"Can create and edit pages in space": "可以在空间中创建和编辑页面",
"Can view": "可以查看",
"Can view pages in space but not edit": "可以查看空间中的页面但不能编辑",
"Owner": "所有者",
"Can manage workspace": "可以管理工作区",
"Admin": "管理员",
"Can manage workspace but cannot delete it": "可以管理工作区但不能删除它",
"Member": "成员",
"Can become members of groups and spaces in workspace": "可以成为工作区中群组和空间的成员"
},
"layout": { "layout": {
"Home": "首页", "Home": "首页",
"Workspace": "工作区", "Workspace": "工作区",

View File

@ -2,6 +2,7 @@ import React, { forwardRef } from "react";
import { IconCheck, IconChevronDown } from "@tabler/icons-react"; import { IconCheck, IconChevronDown } from "@tabler/icons-react";
import { Group, Text, Menu, Button } from "@mantine/core"; import { Group, Text, Menu, Button } from "@mantine/core";
import { IRoleData } from "@/lib/types.ts"; import { IRoleData } from "@/lib/types.ts";
import { useTranslation } from "react-i18next";
interface RoleButtonProps extends React.ComponentPropsWithoutRef<"button"> { interface RoleButtonProps extends React.ComponentPropsWithoutRef<"button"> {
name: string; name: string;
@ -36,10 +37,14 @@ export default function RoleSelectMenu({
onChange, onChange,
disabled, disabled,
}: RoleMenuProps) { }: RoleMenuProps) {
const { t } = useTranslation("translation", {
keyPrefix: "role",
});
return ( return (
<Menu withArrow> <Menu withArrow>
<Menu.Target> <Menu.Target>
<RoleButton name={roleName} disabled={disabled} /> <RoleButton name={t(roleName)} disabled={disabled} />
</Menu.Target> </Menu.Target>
<Menu.Dropdown> <Menu.Dropdown>
@ -50,9 +55,9 @@ export default function RoleSelectMenu({
> >
<Group flex="1" gap="xs"> <Group flex="1" gap="xs">
<div> <div>
<Text size="sm">{item.label}</Text> <Text size="sm">{t(item.label)}</Text>
<Text size="xs" opacity={0.65}> <Text size="xs" opacity={0.65}>
{item.description} {t(item.description)}
</Text> </Text>
</div> </div>
{item.label === roleName && <IconCheck size={20} />} {item.label === roleName && <IconCheck size={20} />}

View File

@ -4,6 +4,7 @@ import { Group, MultiSelect, MultiSelectProps, Text } from "@mantine/core";
import { useGetGroupsQuery } from "@/features/group/queries/group-query.ts"; import { useGetGroupsQuery } from "@/features/group/queries/group-query.ts";
import { IGroup } from "@/features/group/types/group.types.ts"; import { IGroup } from "@/features/group/types/group.types.ts";
import { IconUsersGroup } from "@tabler/icons-react"; import { IconUsersGroup } from "@tabler/icons-react";
import { useTranslation } from "react-i18next";
interface MultiGroupSelectProps { interface MultiGroupSelectProps {
onChange: (value: string[]) => void; onChange: (value: string[]) => void;
@ -29,6 +30,9 @@ export function MultiGroupSelect({
description, description,
mt, mt,
}: MultiGroupSelectProps) { }: MultiGroupSelectProps) {
const { t } = useTranslation("settings", {
keyPrefix: "workspace.group",
});
const [searchValue, setSearchValue] = useState(""); const [searchValue, setSearchValue] = useState("");
const [debouncedQuery] = useDebouncedValue(searchValue, 500); const [debouncedQuery] = useDebouncedValue(searchValue, 500);
const { data: groups, isLoading } = useGetGroupsQuery({ const { data: groups, isLoading } = useGetGroupsQuery({
@ -64,8 +68,8 @@ export function MultiGroupSelect({
hidePickedOptions hidePickedOptions
maxDropdownHeight={300} maxDropdownHeight={300}
description={description} description={description}
label={label || "Add groups"} label={label || t("Add groups")}
placeholder="Search for groups" placeholder={t("Search for groups")}
mt={mt} mt={mt}
searchable searchable
searchValue={searchValue} searchValue={searchValue}
@ -73,7 +77,7 @@ export function MultiGroupSelect({
clearable clearable
variant="filled" variant="filled"
onChange={onChange} onChange={onChange}
nothingFoundMessage="No group found" nothingFoundMessage={t("No group found")}
maxValues={50} maxValues={50}
/> />
); );

View File

@ -9,7 +9,7 @@ export const spaceRoleData: IRoleData[] = [
{ {
label: "Can edit", label: "Can edit",
value: SpaceRole.WRITER, value: SpaceRole.WRITER,
description: "Can create and edit pages in space.", description: "Can create and edit pages in space",
}, },
{ {
label: "Can view", label: "Can view",

View File

@ -11,9 +11,7 @@ interface Props {
onClose: () => void; onClose: () => void;
} }
export function WorkspaceInviteForm({ onClose }: Props) { export function WorkspaceInviteForm({ onClose }: Props) {
const { t } = useTranslation("settings", { const { t } = useTranslation(["settings", "translation"]);
keyPrefix: "workspace.member",
});
const [emails, setEmails] = useState<string[]>([]); const [emails, setEmails] = useState<string[]>([]);
const [role, setRole] = useState<string | null>(UserRole.MEMBER); const [role, setRole] = useState<string | null>(UserRole.MEMBER);
const [groupIds, setGroupIds] = useState<string[]>([]); const [groupIds, setGroupIds] = useState<string[]>([]);
@ -49,10 +47,10 @@ export function WorkspaceInviteForm({ onClose }: Props) {
<TagsInput <TagsInput
mt="sm" mt="sm"
description={t( description={t(
"Enter valid email addresses separated by comma or space max_50", "workspace.member.Enter valid email addresses separated by comma or space max_50",
)} )}
label={t("Invite by email")} label={t("workspace.member.Invite by email")}
placeholder={t("enter valid emails addresses")} placeholder={t("workspace.member.enter valid emails addresses")}
variant="filled" variant="filled"
splitChars={[",", " "]} splitChars={[",", " "]}
maxDropdownHeight={200} maxDropdownHeight={200}
@ -62,11 +60,19 @@ export function WorkspaceInviteForm({ onClose }: Props) {
<Select <Select
mt="sm" mt="sm"
description={t("Select role to assign to all invited members")} description={t(
label={t("Select role")} "workspace.member.Select role to assign to all invited members",
placeholder={t("Choose a role")} )}
label={t("workspace.member.Select role")}
placeholder={t("workspace.member.Choose a role")}
variant="filled" variant="filled"
data={userRoleData.filter((role) => role.value !== UserRole.OWNER)} data={userRoleData
.filter((role) => role.value !== UserRole.OWNER)
.map((role) => ({
...role,
label: t(`role.${role.label}`, { ns: "translation" }),
description: t(`role.${role.description}`, { ns: "translation" }),
}))}
defaultValue={UserRole.MEMBER} defaultValue={UserRole.MEMBER}
allowDeselect={false} allowDeselect={false}
checkIconPosition="right" checkIconPosition="right"
@ -76,9 +82,9 @@ export function WorkspaceInviteForm({ onClose }: Props) {
<MultiGroupSelect <MultiGroupSelect
mt="sm" mt="sm"
description={t( description={t(
"Invited members will be granted access to spaces the groups can access", "workspace.member.Invited members will be granted access to spaces the groups can access",
)} )}
label={t("Add to groups")} label={t("workspace.member.Add to groups")}
onChange={handleGroupSelect} onChange={handleGroupSelect}
/> />
@ -87,7 +93,7 @@ export function WorkspaceInviteForm({ onClose }: Props) {
onClick={handleSubmit} onClick={handleSubmit}
loading={createInvitationMutation.isPending} loading={createInvitationMutation.isPending}
> >
{t("Send invitation")} {t("workspace.member.Send invitation")}
</Button> </Button>
</Group> </Group>
</Box> </Box>

View File

@ -14,7 +14,7 @@ export const userRoleData: IRoleData[] = [
{ {
label: "Member", label: "Member",
value: UserRole.MEMBER, value: UserRole.MEMBER,
description: "Can become members of groups and spaces in workspace.", description: "Can become members of groups and spaces in workspace",
}, },
]; ];