Интеграция системы интернационализации в современную фронтенд-сборку требует учета особенностей бандлинга, загрузки ресурсов и работы с динамическими модулями. В контексте i18next ключевая задача — обеспечить корректную загрузку переводов, оптимизацию чанков и предсказуемое поведение при lazy-loading языковых ресурсов.
i18next в браузерных приложениях обычно опирается на:
i18nexti18next-http-backend или
кастомный backend)i18next-browser-languagedetector)В условиях webpack и Vite критически важно разделять:
Это позволяет избежать увеличения initial bundle и обеспечить code splitting по языкам.
Рекомендуемая структура файлов:
/locales
/en
common.json
auth.json
/ru
common.json
auth.json
Разделение по namespace позволяет:
npm install i18next i18next-http-backend i18next-browser-languagedetector
import i18n from 'i18next';
import HttpBackend from 'i18next-http-backend';
import LanguageDetector from 'i18next-browser-languagedetector';
i18n
.use(HttpBackend)
.use(LanguageDetector)
.init({
fallbackLng: 'en',
debug: false,
backend: {
loadPath: '/locales/{{lng}}/{{ns}}.json'
},
ns: ['common', 'auth'],
defaultNS: 'common',
interpolation: {
escapeValue: false
}
});
export default i18n;
Webpack по умолчанию не обслуживает JSON как i18n-ресурсы без правильной конфигурации.
const path = require('path');
module.exports = {
devServer: {
static: {
directory: path.join(__dirname, 'public')
},
compress: true,
port: 3000
}
};
Переводы должны находиться в public/locales, чтобы быть
доступными через HTTP.
Вместо HTTP можно использовать статический импорт:
import enCommon from './locales/en/common.json';
import ruCommon from './locales/ru/common.json';
i18n.init({
resources: {
en: {
common: enCommon
},
ru: {
common: ruCommon
}
},
lng: 'en',
fallbackLng: 'en'
});
Webpack позволяет разделить переводы на чанки:
const loadLocale = (lng) => {
return import(
/* webpackChunkName: "locale-[request]" */
`./locales/${lng}/common.json`
);
};
Использование с i18next:
i18n.init({
lng: 'en',
fallbackLng: 'en',
resources: {}
});
export const setLanguage = async (lng) => {
const resources = await loadLocale(lng);
i18n.addResourceBundle(
lng,
'common',
resources.default || resources
);
i18n.changeLanguage(lng);
};
Vite использует ES modules и нативную поддержку динамических импортов, что упрощает работу с i18n-ресурсами.
npm install i18next i18next-http-backend i18next-browser-languagedetector
import i18n from 'i18next';
import HttpBackend from 'i18next-http-backend';
import LanguageDetector from 'i18next-browser-languagedetector';
i18n
.use(HttpBackend)
.use(LanguageDetector)
.init({
fallbackLng: 'en',
backend: {
loadPath: '/locales/{{lng}}/{{ns}}.json'
},
ns: ['common'],
defaultNS: 'common',
interpolation: {
escapeValue: false
}
});
export default i18n;
Vite автоматически обслуживает папку public.
Структура:
/public
/locales
/en/common.json
/ru/common.json
URL загрузки:
/locales/en/common.json
Vite предоставляет мощный механизм сборки переводов без HTTP backend.
const modules = import.meta.glob('./locales/*/*.json', {
eager: true
});
const resources = {};
for (const path in modules) {
const match = path.match(/\.\/locales\/(.+)\/(.+)\.json/);
if (match) {
const lng = match[1];
const ns = match[2];
resources[lng] = resources[lng] || {};
resources[lng][ns] = modules[path];
}
}
i18n.init({
resources,
lng: 'en',
fallbackLng: 'en'
});
export const loadLanguage = async (lng) => {
const modules = import.meta.glob('./locales/*/*.json');
const entries = Object.entries(modules);
for (const [path, loader] of entries) {
if (path.includes(`/${lng}/`)) {
const mod = await loader();
const nsMatch = path.match(/\.\/locales\/.+\/(.+)\.json/);
const ns = nsMatch ? nsMatch[1] : 'common';
i18n.addResourceBundle(lng, ns, mod.default || mod);
}
}
i18n.changeLanguage(lng);
};
При использовании HTTP backend важно учитывать:
Пример:
/locales/en/common.json?v=1.2.0
Разделение переводов:
common — базовый UIauth — авторизацияdashboard — интерфейс панелиerrors — сообщения ошибокПри сборке это позволяет:
При SSR важно:
i18n.init({
lng: 'en',
resources,
initImmediate: false
});