diff --git a/locales/en.json b/locales/en.json index 12fcf4971..9cf3d46f7 100644 --- a/locales/en.json +++ b/locales/en.json @@ -11,6 +11,17 @@ "sign_in_to": "Sign in to" }, "settings": { + "titles": { + "general": "General", + "appearance": "Appearance", + "actions": "Actions", + "integration": "Integration", + "about": "About", + "profile": "Profile", + "shortcuts": "Shortcuts", + "power": "Power", + "invitations": "Invitations" + }, "general": { "app": "App", "launch_at_login": "Launch at login", diff --git a/locales/namespaces/common/en.json b/locales/namespaces/common/en.json new file mode 100644 index 000000000..75966ec17 --- /dev/null +++ b/locales/namespaces/common/en.json @@ -0,0 +1,5 @@ +{ + "confirm": "Confirm", + "ok": "OK", + "cancel": "Cancel" +} diff --git a/locales/namespaces/common/zh_CN.json b/locales/namespaces/common/zh_CN.json new file mode 100644 index 000000000..cdeef8285 --- /dev/null +++ b/locales/namespaces/common/zh_CN.json @@ -0,0 +1,5 @@ +{ + "confirm": "确认", + "ok": "好", + "cancel": "取消" +} diff --git a/locales/modules/lang/en.json b/locales/namespaces/lang/en.json similarity index 100% rename from locales/modules/lang/en.json rename to locales/namespaces/lang/en.json diff --git a/locales/modules/lang/zh_CN.json b/locales/namespaces/lang/zh_CN.json similarity index 100% rename from locales/modules/lang/zh_CN.json rename to locales/namespaces/lang/zh_CN.json diff --git a/locales/zh_CN.json b/locales/zh_CN.json index 7c1a65271..46cd0b576 100644 --- a/locales/zh_CN.json +++ b/locales/zh_CN.json @@ -11,6 +11,17 @@ "sign_in_to": "登录到" }, "settings": { + "titles": { + "general": "常规", + "appearance": "外观", + "actions": "操作", + "integration": "集成", + "about": "关于", + "profile": "个人资料", + "shortcuts": "热键", + "power": "Power", + "invitations": "邀请" + }, "general": { "app": "应用程序", "data_persist": { diff --git a/src/renderer/src/@types/resources.ts b/src/renderer/src/@types/resources.ts index 9d7e85559..6165e475e 100644 --- a/src/renderer/src/@types/resources.ts +++ b/src/renderer/src/@types/resources.ts @@ -1,16 +1,20 @@ import en from "../../../../locales/en.json" -import lang_en from "../../../../locales/modules/lang/en.json" -import lang_zhCN from "../../../../locales/modules/lang/zh_CN.json" +import common_en from "../../../../locales/namespaces/common/en.json" +import common_zhCN from "../../../../locales/namespaces/common/zh_CN.json" +import lang_en from "../../../../locales/namespaces/lang/en.json" +import lang_zhCN from "../../../../locales/namespaces/lang/zh_CN.json" import zhCN from "../../../../locales/zh_CN.json" const resources = { en: { translation: en, lang: lang_en, + common: common_en, }, zh_CN: { translation: zhCN, lang: lang_zhCN, + common: common_zhCN, }, } export default resources diff --git a/src/renderer/src/global.d.ts b/src/renderer/src/global.d.ts index f442b950e..ac3a35caf 100644 --- a/src/renderer/src/global.d.ts +++ b/src/renderer/src/global.d.ts @@ -1,3 +1,4 @@ +import type { t } from "i18next" import type { FC, PropsWithChildren } from "react" declare global { @@ -28,6 +29,12 @@ declare global { } export function tw(strings: TemplateStringsArray, ...values: any[]): string + + export type I18nKeys = OmitStringType[0]> + + type IsLiteralString = T extends string ? (string extends T ? never : T) : never + + type OmitStringType = T extends any[] ? OmitStringType : IsLiteralString } export {} diff --git a/src/renderer/src/i18n.ts b/src/renderer/src/i18n.ts index 625eff633..1f574f477 100644 --- a/src/renderer/src/i18n.ts +++ b/src/renderer/src/i18n.ts @@ -15,11 +15,8 @@ export const initI18n = async () => { lng: language, fallbackLng: fallbackLanguage, defaultNS, - ns: [defaultNS], debug: true, resources, - - backend: [], }) } @@ -32,16 +29,16 @@ if (import.meta.hot) { const resources = JSON.parse(content) // `file` is absolute path e.g. /Users/innei/git/follow/locales/en.json - // Absolute path e.g. /Users/innei/git/follow/locales/modules//en.json + // Absolute path e.g. /Users/innei/git/follow/locales/namespaces//en.json // 1. parse root language - if (!file.includes("locales/modules")) { + if (!file.includes("locales/namespaces")) { const lang = file.split("/").pop()?.replace(".json", "") if (!lang) return i18next.addResourceBundle(lang, defaultNS, resources, true, true) i18next.reloadResources(lang, defaultNS) } else { - const nsName = file.match(/locales\/modules\/(.+?)\//)?.[1] + const nsName = file.match(/locales\/namespaces\/(.+?)\//)?.[1] if (!nsName) return const lang = file.split("/").pop()?.replace(".json", "") diff --git a/src/renderer/src/modules/settings/constants.ts b/src/renderer/src/modules/settings/constants.ts index db41adaf1..a3f23fbe9 100644 --- a/src/renderer/src/modules/settings/constants.ts +++ b/src/renderer/src/modules/settings/constants.ts @@ -4,7 +4,7 @@ function getSettings() { const map = import.meta.glob("../../pages/settings/\\(settings\\)/*", { eager: true }) const settings = [] as { - name: string + name: I18nKeys iconName: string path: string Component: () => JSX.Element diff --git a/src/renderer/src/modules/settings/title.tsx b/src/renderer/src/modules/settings/title.tsx index b3ac0d995..173e30a2f 100644 --- a/src/renderer/src/modules/settings/title.tsx +++ b/src/renderer/src/modules/settings/title.tsx @@ -1,4 +1,5 @@ import { cn } from "@renderer/lib/utils" +import { useTranslation } from "react-i18next" import { useLoaderData } from "react-router-dom" import { settings } from "./constants" @@ -7,6 +8,7 @@ import type { SettingPageConfig } from "./utils" export const SettingsSidebarTitle = ({ path, className }: { path: string; className?: string }) => { const tab = settings.find((t) => t.path === path) + const { t } = useTranslation() if (!tab) { return null } @@ -14,7 +16,7 @@ export const SettingsSidebarTitle = ({ path, className }: { path: string; classN return (
- {tab.name} + {t(tab.name as any)}
) } diff --git a/src/renderer/src/modules/settings/utils.ts b/src/renderer/src/modules/settings/utils.ts index 32066d680..4e8ce319b 100644 --- a/src/renderer/src/modules/settings/utils.ts +++ b/src/renderer/src/modules/settings/utils.ts @@ -1,9 +1,10 @@ + export interface SettingPageConfig { iconName: string - name: string + name: I18nKeys priority: number headerIcon?: string } -export const defineSettingPage = (config: SettingPageConfig) => () => ({ +export const defineSettingPageData = (config: SettingPageConfig) => () => ({ ...config, }) diff --git a/src/renderer/src/pages/settings/(settings)/about.tsx b/src/renderer/src/pages/settings/(settings)/about.tsx index 0b79145a9..cac930c73 100644 --- a/src/renderer/src/pages/settings/(settings)/about.tsx +++ b/src/renderer/src/pages/settings/(settings)/about.tsx @@ -1,9 +1,9 @@ import { SettingAbout } from "@renderer/modules/settings/tabs/about" -import { defineSettingPage } from "@renderer/modules/settings/utils" +import { defineSettingPageData } from "@renderer/modules/settings/utils" -export const loader = defineSettingPage({ +export const loader = defineSettingPageData({ iconName: "i-mgc-information-cute-re", - name: "About", + name: "settings.titles.about", priority: 9999, }) export const Component = () => diff --git a/src/renderer/src/pages/settings/(settings)/actions.tsx b/src/renderer/src/pages/settings/(settings)/actions.tsx index 32134384e..1966897d4 100644 --- a/src/renderer/src/pages/settings/(settings)/actions.tsx +++ b/src/renderer/src/pages/settings/(settings)/actions.tsx @@ -10,19 +10,19 @@ import type { } from "@renderer/models" import { ActionCard } from "@renderer/modules/settings/action-card" import { SettingsTitle } from "@renderer/modules/settings/title" -import { defineSettingPage } from "@renderer/modules/settings/utils" +import { defineSettingPageData } from "@renderer/modules/settings/utils" import { Queries } from "@renderer/queries" import { useMutation } from "@tanstack/react-query" import { useEffect, useState } from "react" import { toast } from "sonner" const iconName = "i-mgc-magic-2-cute-re" -const name = "Actions" + const priority = 1020 -export const loader = defineSettingPage({ +export const loader = defineSettingPageData({ iconName, - name, + name: "settings.titles.actions", priority, }) diff --git a/src/renderer/src/pages/settings/(settings)/appearance.tsx b/src/renderer/src/pages/settings/(settings)/appearance.tsx index f69eda3b9..fad4c4c5d 100644 --- a/src/renderer/src/pages/settings/(settings)/appearance.tsx +++ b/src/renderer/src/pages/settings/(settings)/appearance.tsx @@ -1,13 +1,13 @@ import { SettingAppearance } from "@renderer/modules/settings/tabs/apperance" -import { defineSettingPage } from "@renderer/modules/settings/utils" +import { defineSettingPageData } from "@renderer/modules/settings/utils" const iconName = "i-mgc-palette-cute-re" -const name = "Appearance" + const priority = 1010 -export const loader = defineSettingPage({ +export const loader = defineSettingPageData({ iconName, - name, + name: "settings.titles.appearance", priority, }) diff --git a/src/renderer/src/pages/settings/(settings)/general.tsx b/src/renderer/src/pages/settings/(settings)/general.tsx index a54e6969b..dd5c208ec 100644 --- a/src/renderer/src/pages/settings/(settings)/general.tsx +++ b/src/renderer/src/pages/settings/(settings)/general.tsx @@ -1,13 +1,13 @@ import { SettingGeneral } from "@renderer/modules/settings/tabs/general" -import { defineSettingPage } from "@renderer/modules/settings/utils" +import { defineSettingPageData } from "@renderer/modules/settings/utils" const iconName = "i-mgc-settings-7-cute-re" -const name = "General" + const priority = 1000 -export const loader = defineSettingPage({ +export const loader = defineSettingPageData({ iconName, - name, + name: "settings.titles.general", priority, }) diff --git a/src/renderer/src/pages/settings/(settings)/integration.tsx b/src/renderer/src/pages/settings/(settings)/integration.tsx index b96519afe..9a67c8b25 100644 --- a/src/renderer/src/pages/settings/(settings)/integration.tsx +++ b/src/renderer/src/pages/settings/(settings)/integration.tsx @@ -1,13 +1,13 @@ import { SettingIntegration } from "@renderer/modules/settings/tabs/integration" -import { defineSettingPage } from "@renderer/modules/settings/utils" +import { defineSettingPageData } from "@renderer/modules/settings/utils" const iconName = "i-mgc-department-cute-re" -const name = "Integration" + const priority = 1025 -export const loader = defineSettingPage({ +export const loader = defineSettingPageData({ iconName, - name, + name: "settings.titles.integration", priority, }) diff --git a/src/renderer/src/pages/settings/(settings)/invitations.tsx b/src/renderer/src/pages/settings/(settings)/invitations.tsx index 98e71e83e..fa043e3d0 100644 --- a/src/renderer/src/pages/settings/(settings)/invitations.tsx +++ b/src/renderer/src/pages/settings/(settings)/invitations.tsx @@ -1,13 +1,13 @@ import { SettingInvitations } from "@renderer/modules/settings/tabs/invitations" -import { defineSettingPage } from "@renderer/modules/settings/utils" +import { defineSettingPageData } from "@renderer/modules/settings/utils" const iconName = "i-mgc-heart-hand-cute-re" -const name = "Invitations" + const priority = 1055 -export const loader = defineSettingPage({ +export const loader = defineSettingPageData({ iconName, - name, + name: "settings.titles.invitations", priority, }) diff --git a/src/renderer/src/pages/settings/(settings)/profile.tsx b/src/renderer/src/pages/settings/(settings)/profile.tsx index 13ed89dd3..e181629f1 100644 --- a/src/renderer/src/pages/settings/(settings)/profile.tsx +++ b/src/renderer/src/pages/settings/(settings)/profile.tsx @@ -1,13 +1,13 @@ import { ProfileSettingForm } from "@renderer/modules/profile/profile-setting-form" import { SettingsTitle } from "@renderer/modules/settings/title" -import { defineSettingPage } from "@renderer/modules/settings/utils" +import { defineSettingPageData } from "@renderer/modules/settings/utils" const iconName = "i-mgc-user-setting-cute-re" -const name = "Profile" + const priority = 1030 -export const loader = defineSettingPage({ +export const loader = defineSettingPageData({ iconName, - name, + name: "settings.titles.profile", priority, }) diff --git a/src/renderer/src/pages/settings/(settings)/shortcuts.tsx b/src/renderer/src/pages/settings/(settings)/shortcuts.tsx index 14321c393..d884ce869 100644 --- a/src/renderer/src/pages/settings/(settings)/shortcuts.tsx +++ b/src/renderer/src/pages/settings/(settings)/shortcuts.tsx @@ -2,15 +2,15 @@ import { KbdCombined } from "@renderer/components/ui/kbd/Kbd" import { shortcuts } from "@renderer/constants/shortcuts" import { cn } from "@renderer/lib/utils" import { SettingsTitle } from "@renderer/modules/settings/title" -import { defineSettingPage } from "@renderer/modules/settings/utils" +import { defineSettingPageData } from "@renderer/modules/settings/utils" const iconName = "i-mgc-hotkey-cute-re" -const name = "Shortcuts" + const priority = 1040 -export const loader = defineSettingPage({ +export const loader = defineSettingPageData({ iconName, - name, + name: "settings.titles.shortcuts", priority, }) export function Component() { diff --git a/src/renderer/src/pages/settings/(settings)/wallet.tsx b/src/renderer/src/pages/settings/(settings)/wallet.tsx index d5b171b44..26d10a299 100644 --- a/src/renderer/src/pages/settings/(settings)/wallet.tsx +++ b/src/renderer/src/pages/settings/(settings)/wallet.tsx @@ -1,13 +1,13 @@ import { SettingWallet } from "@renderer/modules/settings/tabs/wallet" -import { defineSettingPage } from "@renderer/modules/settings/utils" +import { defineSettingPageData } from "@renderer/modules/settings/utils" const iconName = `i-mgc-power-outline` -const name = "Power" + const priority = 1050 -export const loader = defineSettingPage({ +export const loader = defineSettingPageData({ iconName, - name, + name: "settings.titles.power", priority, headerIcon: `i-mgc-power text-accent`, })