diff --git a/src/i18n.ts b/src/i18n.ts index 9a95cf8d..bd6ebd1a 100644 --- a/src/i18n.ts +++ b/src/i18n.ts @@ -95,6 +95,7 @@ function resolveLocaleFile(lng: string): string | undefined { * already-loaded locales). */ const loadedLocales = new Set(['en']); +let languageChangeRequest = 0; async function loadLocale(lng: string): Promise { const file = resolveLocaleFile(lng); @@ -134,6 +135,21 @@ async function loadLocale(lng: string): Promise { loadedLocales.add(file); } +/** + * Switch languages only after the target locale has been registered. + * + * Calling i18next.changeLanguage() first can render React components against a + * missing lazy-loaded bundle, leaving them stuck on fallback English until an + * unrelated render happens. The request counter keeps rapid clicks ordered so a + * slower earlier download cannot overwrite the latest selection. + */ +export async function changeAppLanguage(lng: string): Promise { + const request = ++languageChangeRequest; + await loadLocale(lng); + if (request !== languageChangeRequest) return; + await i18n.changeLanguage(lng); +} + i18n .use(LanguageDetector) .use(initReactI18next) @@ -161,6 +177,9 @@ i18n caches: ['localStorage'], lookupLocalStorage: 'i18nextLng', }, + react: { + bindI18nStore: 'added', + }, }); // Load the locale the detector picked on startup. If it isn't English the diff --git a/src/pages/LanguageSettingsPage.tsx b/src/pages/LanguageSettingsPage.tsx index da35aefd..c60c1b52 100644 --- a/src/pages/LanguageSettingsPage.tsx +++ b/src/pages/LanguageSettingsPage.tsx @@ -3,7 +3,7 @@ import { Check, Languages } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import { PageHeader } from '@/components/PageHeader'; import { useAppContext } from '@/hooks/useAppContext'; -import i18n, { SUPPORTED_LANGUAGES, isRTLLanguage } from '@/i18n'; +import { SUPPORTED_LANGUAGES, changeAppLanguage, isRTLLanguage } from '@/i18n'; import { cn } from '@/lib/utils'; export function LanguageSettingsPage() { @@ -42,7 +42,7 @@ export function LanguageSettingsPage() { const handleSelect = (code: string) => { if (code === currentLng) return; - void i18n.changeLanguage(code); + void changeAppLanguage(code); }; return (