Проблема с загрузкой переводов относится к числу наиболее распространённых при использовании I18next. Она может проявляться по-разному:
Для эффективной диагностики необходимо понимать механизм работы библиотеки.
В типичной конфигурации I18next выполняет следующие действия:
Например:
i18next
.use(HttpBackend)
.init({
lng: 'ru',
fallbackLng: 'en',
backend: {
loadPath: '/locales/{{lng}}/{{ns}}.json'
}
});
При обращении к ключу:
t('welcome')
I18next сначала проверяет наличие загружённого namespace, затем ищет ключ внутри соответствующего JSON-файла.
Если любой этап цепочки завершается ошибкой, перевод не будет найден.
Первое действие при отсутствии переводов — анализ вкладки Network в инструментах разработчика браузера.
Необходимо проверить:
Пример корректного запроса:
GET /locales/ru/translation.json
Ответ:
{
"welcome": "Добро пожаловать"
}
Если сервер возвращает:
404 Not Found
или
500 Internal Server Error
переводы загружены не будут.
Наиболее частая причина — неверная настройка
loadPath.
Ошибка:
backend: {
loadPath: '/locale/{{lng}}/{{ns}}.json'
}
Фактическая структура проекта:
public/
└── locales/
└── ru/
└── translation.json
Правильная настройка:
backend: {
loadPath: '/locales/{{lng}}/{{ns}}.json'
}
Даже одна лишняя буква в пути приводит к ошибке загрузки.
Во многих сборщиках фронтенд-приложений статические ресурсы должны располагаться в специальной директории.
Пример для React:
public/
└── locales/
├── en/
└── ru/
Если файл находится внутри:
src/locales
браузер может не иметь прямого доступа к нему.
В результате запрос:
/locales/ru/translation.json
вернёт ошибку 404.
I18next не умеет загружать JSON-файлы автоматически без соответствующего backend-модуля.
Ошибка:
i18next.init({
lng: 'ru'
});
При такой конфигурации библиотека не знает, откуда брать переводы.
Правильный вариант:
import HttpBackend from 'i18next-http-backend';
i18next
.use(HttpBackend)
.init({
lng: 'ru'
});
Порядок подключения имеет значение.
Неверно:
i18next.init({
lng: 'ru'
});
i18next.use(HttpBackend);
В этот момент инициализация уже завершилась.
Правильно:
i18next
.use(HttpBackend)
.init({
lng: 'ru'
});
I18next ожидает корректный JSON.
Ошибка:
{
"welcome": "Добро пожаловать",
}
Лишняя запятая делает JSON невалидным.
Ещё один пример:
{
"welcome": "Добро пожаловать"
Отсутствует закрывающая фигурная скобка.
Для проверки рекомендуется открывать файл напрямую в браузере либо использовать JSON-валидаторы.
Ключи должны соответствовать способу обращения к ним.
Файл:
{
"home": {
"welcome": "Добро пожаловать"
}
}
Получение перевода:
t('welcome')
Результат:
welcome
Правильный вызов:
t('home.welcome')
Либо изменение структуры файла:
{
"welcome": "Добро пожаловать"
}
I18next активно использует пространства имён.
Файл:
locales/
└── ru/
└── common.json
Конфигурация:
i18next.init({
ns: ['common']
});
Получение перевода:
t('welcome')
Будет работать только при активном namespace common.
Явное указание:
t('common:welcome')
Если namespace не зарегистрирован:
ns: ['translation']
а файл называется:
common.json
загрузка завершится ошибкой.
Конфигурация:
ns: ['translation']
I18next попытается загрузить:
translation.json
Но фактически существует:
translations.json
Разница в одной букве приводит к невозможности найти файл.
Конфигурация:
lng: 'ru'
I18next ожидает:
locales/ru/translation.json
Однако структура проекта выглядит так:
locales/russian/translation.json
Библиотека не сможет найти соответствующую локаль.
Необходимо использовать одинаковые идентификаторы:
lng: 'ru'
и
locales/ru
Иногда браузер определяет язык так:
ru-RU
или
en-US
При этом существуют только папки:
locales/ru
locales/en
I18next может искать:
locales/ru-RU/translation.json
и получать 404.
Решение:
load: 'languageOnly'
Пример:
i18next.init({
load: 'languageOnly'
});
Тогда:
ru-RU
будет преобразован в:
ru
Неверная конфигурация:
fallbackLng: 'english'
При наличии только:
locales/en
резервная локаль никогда не загрузится.
Корректно:
fallbackLng: 'en'
Иногда перевод запрашивается до завершения загрузки ресурсов.
Проблемный код:
i18next.init({
lng: 'ru'
});
console.log(i18next.t('welcome'));
В момент вызова файлы ещё могут не загрузиться.
Безопасный вариант:
i18next.init({
lng: 'ru'
}, () => {
console.log(i18next.t('welcome'));
});
Или:
await i18next.init({
lng: 'ru'
});
При использовании React возможна ситуация, когда интерфейс отображается до окончания загрузки переводов.
Часто проблема проявляется так:
welcome
вместо:
Добро пожаловать
Для корректной работы используется интеграция через React I18next:
import { initReactI18next } from 'react-i18next';
i18next.use(initReactI18next);
А также поддержка Suspense:
react: {
useSuspense: true
}
Если файлы переводов загружаются с другого домена:
https://cdn.example.com/locales
сервер обязан разрешить кросс-доменные запросы.
Без соответствующих заголовков браузер заблокирует ответ.
Типичное сообщение:
Access to fetch at ...
has been blocked by CORS policy
Необходим заголовок:
Access-Control-Allow-Origin: *
или более строгая настройка для конкретного домена.
Корректный ответ:
Content-Type: application/json
Некоторые серверы ошибочно возвращают:
Content-Type: text/html
или даже страницу ошибки вместо JSON.
В таких случаях I18next не сможет корректно обработать ресурс.
После обновления локализаций браузер может использовать устаревшую версию файла.
Симптом:
Часто помогает добавление версии:
backend: {
loadPath:
'/locales/{{lng}}/{{ns}}.json?v=2'
}
Либо настройка серверного контроля кэширования.
Для поиска причин рекомендуется включать подробное логирование.
i18next.init({
debug: true
});
В консоли появятся сообщения:
loading namespace translation
loaded namespace translation
failed loading
missingKey
По этим сообщениям легко определить этап возникновения проблемы.
После загрузки можно проверить внутреннее хранилище переводов.
console.log(i18next.store.data);
Ожидаемый результат:
{
ru: {
translation: {
welcome: 'Добро пожаловать'
}
}
}
Если объект пустой:
{}
ресурсы не были загружены.
Для диагностики полезно подписаться на события I18next.
Успешная загрузка:
i18next.on('loaded', loaded => {
console.log('loaded', loaded);
});
Ошибка:
i18next.on('failedLoading',
(lng, ns, msg) => {
console.error(lng, ns, msg);
}
);
Такие обработчики позволяют быстро определить проблемный язык или namespace.
При возникновении проблемы с загрузкой переводов необходимо последовательно проверить:
init().loadPath.i18next.store.data.debug.t().Content-Type.Систематическая проверка этих пунктов позволяет обнаружить практически все причины, по которым I18next не загружает переводы в приложении.