feat(i18n): initialize i18n infrastructure
This commit is contained in:
parent
9be635eaf3
commit
74f38d0d42
0
i18n/en.json
Normal file
0
i18n/en.json
Normal file
0
i18n/zh.json
Normal file
0
i18n/zh.json
Normal file
32
i18next.config.ts
Normal file
32
i18next.config.ts
Normal file
@ -0,0 +1,32 @@
|
||||
export default {
|
||||
// supported languages
|
||||
locales: ["en", "zh", "de", "fr"],
|
||||
|
||||
// extraction config (for i18next-cli)
|
||||
extract: {
|
||||
input: "src/**/*.{js,jsx,ts,tsx}",
|
||||
output: "public/locales/{{language}}/{{ns}}.json",
|
||||
namespaceSeparator: false,
|
||||
},
|
||||
|
||||
// default namespace
|
||||
defaultNamespace: "translation",
|
||||
|
||||
// output path pattern
|
||||
resource: {
|
||||
jsonIndent: 2,
|
||||
lineEnding: "\n",
|
||||
},
|
||||
|
||||
// sort keys in output
|
||||
sort: true,
|
||||
|
||||
// fail on missing keys during dev
|
||||
// quiet: false,
|
||||
|
||||
// metadata for translation files
|
||||
metadata: {
|
||||
description: "Generated by i18next-cli",
|
||||
generatedAt: new Date().toISOString(),
|
||||
},
|
||||
};
|
||||
28
src/lib/i18n.ts
Normal file
28
src/lib/i18n.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import i18n from 'i18next';
|
||||
import {initReactI18next} from 'react-i18next';
|
||||
import HttpBackend from 'i18next-http-backend';
|
||||
import LanguageDetector from 'i18next-browser-languagedetector';
|
||||
|
||||
i18n
|
||||
.use(HttpBackend)
|
||||
.use(LanguageDetector)
|
||||
.use(initReactI18next)
|
||||
.init({
|
||||
fallbackLng: 'en',
|
||||
supportedLngs: ['en', 'zh', 'de', 'fr'],
|
||||
defaultNS: 'translation',
|
||||
ns: ['translation'],
|
||||
backend: {
|
||||
loadPath: '/locales/{{lng}}/{{ns}}.json',
|
||||
},
|
||||
detection: {
|
||||
order: ['localStorage', 'navigator'],
|
||||
caches: ['localStorage'],
|
||||
lookupLocalStorage: 'i18nextLng',
|
||||
},
|
||||
interpolation: {
|
||||
escapeValue: false,
|
||||
},
|
||||
});
|
||||
|
||||
export default i18n;
|
||||
32
src/lib/language-provider.tsx
Normal file
32
src/lib/language-provider.tsx
Normal file
@ -0,0 +1,32 @@
|
||||
import {useQuery} from '@tanstack/react-query';
|
||||
import {type ReactNode, useEffect} from 'react';
|
||||
import {getPreferences} from '@/client';
|
||||
import {useUser} from '@/contexts';
|
||||
import i18n from '@/lib/i18n';
|
||||
|
||||
/**
|
||||
* Syncs the user's server-side language preference to i18n after login.
|
||||
* This ensures the API-stored preference takes precedence over browser detection.
|
||||
*/
|
||||
export function LanguageProvider({children}: {children: ReactNode}) {
|
||||
const {isAuthenticated} = useUser();
|
||||
|
||||
const {data: preferences} = useQuery({
|
||||
queryKey: ['userPreferences'],
|
||||
queryFn: async () => {
|
||||
const resp = await getPreferences();
|
||||
return resp.data?.data ?? null;
|
||||
},
|
||||
enabled: isAuthenticated,
|
||||
staleTime: 5 * 60 * 1000,
|
||||
retry: false,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (preferences?.language && preferences.language !== i18n.language) {
|
||||
i18n.changeLanguage(preferences.language);
|
||||
}
|
||||
}, [preferences]);
|
||||
|
||||
return children;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user