diff --git a/apps/venus/src/app/common/Header.tsx b/apps/venus/src/app/common/Header.tsx index 9a2e8d0173..2dc7c50ff0 100644 --- a/apps/venus/src/app/common/Header.tsx +++ b/apps/venus/src/app/common/Header.tsx @@ -13,7 +13,7 @@ import AFFiNETextLogo from './affine-text-logo.png'; import { HoverMenu } from './HoverMenu'; import { MobileHeader } from './MobileHeader'; -import { options } from '../i18n'; +import { LOCALES } from '../i18n'; export const AFFiNEHeader = () => { const matches = useMediaQuery('(max-width: 1024px)'); @@ -140,15 +140,15 @@ export const AFFiNEHeader = () => { }} /> diff --git a/apps/venus/src/app/i18n/index.ts b/apps/venus/src/app/i18n/index.ts index 9ddaa8330d..f4428a9b09 100644 --- a/apps/venus/src/app/i18n/index.ts +++ b/apps/venus/src/app/i18n/index.ts @@ -1,25 +1,63 @@ -import i18next from 'i18next'; -import { initReactI18next } from 'react-i18next'; -import en_US from './resources/en.json'; -import zh_CN from './resources/zh.json'; +import i18next, { Resource } from 'i18next'; +import { + I18nextProvider, + initReactI18next, + useTranslation, +} from 'react-i18next'; +import { LOCALES } from './resources'; +import type en_US from './resources/en.json'; -const resources = { - en: en_US, - zh: zh_CN, -} as const; +// See https://react.i18next.com/latest/typescript +declare module 'react-i18next' { + interface CustomTypeOptions { + // custom namespace type if you changed it + // defaultNS: 'ns1'; + // custom resources type + resources: { + en: typeof en_US; + }; + } +} + +const STORAGE_KEY = 'i18n_lng'; + +export { i18n, useTranslation, I18nProvider, LOCALES }; + +const resources = LOCALES.reduce( + (acc, { tag, res }) => ({ ...acc, [tag]: { translation: res } }), + {} +); + +const fallbackLng = LOCALES[0].tag; +const standardizeLocale = (language: string) => { + if (LOCALES.find(locale => locale.tag === language)) return language; + if ( + LOCALES.find( + locale => locale.tag === language.slice(0, 2).toLowerCase() + ) + ) + return language; + return fallbackLng; +}; + +const language = standardizeLocale( + localStorage.getItem(STORAGE_KEY) ?? navigator.language +); + +const i18n = i18next.createInstance(); +i18n.use(initReactI18next).init({ + lng: language, + fallbackLng, + debug: process.env['NODE_ENV'] === 'development', -i18next.use(initReactI18next).init({ - lng: 'en', - fallbackLng: 'en', resources, interpolation: { escapeValue: false, // not needed for react as it escapes by default }, }); -export const options = [ - { value: 'en', text: 'English' }, - { value: 'zh', text: '简体中文' }, -]; +i18n.on('languageChanged', lng => { + localStorage.setItem(STORAGE_KEY, lng); +}); -export { i18next }; +const I18nProvider = I18nextProvider;