perf: lazy-load locale files per language instead of bundling all

Split 574KB monolithic locales chunk into per-language lazy chunks:
- ru: 211KB (loaded on startup as fallback)
- fa: 143KB, en: 121KB, zh: 101KB (loaded on demand)

Russian users save 63% bandwidth. Other languages loaded only when
user switches via LanguageSwitcher.
This commit is contained in:
Fringg
2026-03-13 06:16:27 +03:00
parent b42d84ffe6
commit 9ae9cccbd9
2 changed files with 35 additions and 14 deletions

View File

@@ -2,25 +2,36 @@ import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import ru from './locales/ru.json';
import en from './locales/en.json';
import zh from './locales/zh.json';
import fa from './locales/fa.json';
const resources = {
ru: { translation: ru },
en: { translation: en },
zh: { translation: zh },
fa: { translation: fa },
const localeLoaders: Record<string, () => Promise<{ default: Record<string, string> }>> = {
ru: () => import('./locales/ru.json'),
en: () => import('./locales/en.json'),
zh: () => import('./locales/zh.json'),
fa: () => import('./locales/fa.json'),
};
const SUPPORTED_LANGS = Object.keys(localeLoaders);
const FALLBACK_LNG = 'ru';
const loadedLanguages = new Set<string>();
async function loadLanguage(lng: string): Promise<void> {
if (loadedLanguages.has(lng)) return;
const loader = localeLoaders[lng];
if (!loader) return;
const mod = await loader();
i18n.addResourceBundle(lng, 'translation', mod.default, true, true);
loadedLanguages.add(lng);
}
i18n
.use(LanguageDetector)
.use(initReactI18next)
.init({
resources,
fallbackLng: 'ru',
supportedLngs: ['ru', 'en', 'zh', 'fa'],
fallbackLng: FALLBACK_LNG,
supportedLngs: SUPPORTED_LANGS,
partialBundledLanguages: true,
detection: {
order: ['localStorage', 'navigator'],
@@ -37,4 +48,15 @@ i18n
},
});
// Load detected language + fallback on startup
const detectedLng = i18n.language?.split('-')[0] || FALLBACK_LNG;
const langsToLoad = [FALLBACK_LNG, ...(detectedLng !== FALLBACK_LNG ? [detectedLng] : [])];
Promise.all(langsToLoad.map(loadLanguage));
// Lazy-load on language change
i18n.on('languageChanged', (lng: string) => {
const code = lng.split('-')[0];
loadLanguage(code);
});
export default i18n;