В интернационализации приложений с использованием i18next ключевым аспектом является сохранение выбора языка между сессиями пользователя. Без механизма устойчивого хранения интерфейс будет возвращаться к языку по умолчанию при каждом обновлении страницы, что разрушает пользовательский опыт и делает невозможным персонализацию.
Сохранение языкового выбора реализуется на нескольких уровнях: через встроенные плагины определения языка, через ручное управление состоянием и через интеграцию с браузерными механизмами хранения данных.
Поведение системы интернационализации строится вокруг трёх состояний:
Ключевая задача — обеспечить приоритет пользовательского выбора над всеми остальными источниками.
Типичная иерархия:
В i18next используется модуль
i18next-browser-languagedetector, который отвечает за
извлечение языка из различных источников.
Основные источники:
cookielocalStoragesessionStoragequerystringnavigatorhtmlTagКонфигурация определяет порядок проверки:
import i18n from 'i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
i18n
.use(LanguageDetector)
.init({
detection: {
order: ['localStorage', 'cookie', 'querystring', 'navigator', 'htmlTag'],
caches: ['localStorage', 'cookie']
},
fallbackLng: 'en',
resources: {
en: { translation: {} },
ru: { translation: {} }
}
});
localStorage является наиболее простым и
распространённым способом сохранения выбора пользователя.
При изменении языка i18next автоматически записывает значение:
i18n.changeLanguage('ru');
После вызова происходит:
localStorage (если включён
cache);Можно явно задать ключ хранения:
detection: {
order: ['localStorage'],
lookupLocalStorage: 'app_language',
caches: ['localStorage']
}
Cookies используются в сценариях, где требуется серверная синхронизация языка (SSR, multi-domain приложения).
Конфигурация:
detection: {
order: ['cookie'],
lookupCookie: 'i18next',
caches: ['cookie'],
cookieMinutes: 60 * 24 * 365
}
Параметры:
lookupCookie — имя cookie;cookieMinutes — срок хранения;cookieDomain — домен для доступности cookie.Преимущество cookie заключается в доступности на сервере, что позволяет рендерить страницу уже на нужном языке.
Язык может передаваться через URL:
https://example.com?lng=ru
Конфигурация:
detection: {
order: ['querystring'],
lookupQuerystring: 'lng'
}
Этот механизм применяется для:
Несмотря на автоматическое сохранение через detector, часто требуется явное управление состоянием.
Изменение языка:
i18n.changeLanguage('de');
После этого происходит:
languageChanged;Прослушивание изменений:
i18n.on('languageChanged', (lng) => {
console.log('Текущий язык:', lng);
});
Это позволяет синхронизировать язык с внешними системами состояния.
В случаях, когда требуется нестандартное хранилище (например, IndexedDB или серверный профиль пользователя), используется кастомный language detector.
Пример реализации:
const customDetector = {
name: 'customDetector',
lookup() {
return sessionStorage.getItem('lang') || 'en';
},
cacheUserLanguage(lng) {
sessionStorage.setItem('lang', lng);
}
};
i18n
.use({
type: 'languageDetector',
init() {},
detect: () => customDetector.lookup(),
cacheUserLanguage: (lng) => customDetector.cacheUserLanguage(lng)
})
.init();
Такая модель позволяет полностью отделить i18next от браузерных ограничений.
При одновременном наличии нескольких источников возникает конфликт определения языка.
Пример конфигурации:
detection: {
order: ['querystring', 'cookie', 'localStorage', 'navigator'],
caches: ['localStorage', 'cookie']
}
Логика:
fallbackLng определяет язык, если ни один источник не
дал результата или язык не поддерживается.
fallbackLng: 'en'
Также возможна более сложная структура:
fallbackLng: {
'ru-KZ': ['ru', 'en'],
default: ['en']
}
Это позволяет учитывать региональные вариации языков.
При использовании localStorage изменение языка в одной
вкладке не всегда отражается в других. Для синхронизации применяется
событие storage:
window.addEventListener('storage', (event) => {
if (event.key === 'i18nextLng') {
i18n.changeLanguage(event.newValue);
}
});
Это обеспечивает единое состояние интерфейса во всех открытых вкладках.
В серверных приложениях язык должен определяться до рендера страницы.
Типичный подход:
i18n.init;i18n.init({
lng: req.cookies.i18next || 'en',
resources,
fallbackLng: 'en'
});
Это устраняет «мигание» языка при гидратации клиента.
Стабильное поведение достигается за счёт строгого соблюдения порядка:
Нарушение этого порядка приводит к непредсказуемому переключению языка при обновлении страницы или переходах.
В условиях строгой приватности браузера (инкогнито, блокировка cookies, ограниченный localStorage) сохранение языка может быть недоступно.
В таких случаях:
Изменение языка часто связано с глобальным состоянием интерфейса:
const handleLanguageSwitch = (lng) => {
i18n.changeLanguage(lng);
setAppState(prev => ({ ...prev, language: lng }));
};
Такой подход обеспечивает синхронизацию перевода, форматирования дат и чисел, а также других локализованных компонентов.
Если сохранённый язык больше не поддерживается приложением, i18next выполняет нормализацию:
Пример:
fr-CA;fr;fr.