Переводы не загружаются

Проблема с загрузкой переводов относится к числу наиболее распространённых при использовании I18next. Она может проявляться по-разному:

  • на странице отображаются ключи вместо переводов;
  • текст остаётся на языке по умолчанию;
  • часть переводов загружается, а часть отсутствует;
  • переключение языка не оказывает никакого эффекта;
  • в консоли появляются ошибки загрузки ресурсов.

Для эффективной диагностики необходимо понимать механизм работы библиотеки.

Как происходит загрузка переводов

В типичной конфигурации I18next выполняет следующие действия:

  1. Инициализирует экземпляр библиотеки.
  2. Определяет текущий язык.
  3. Формирует путь к файлу перевода.
  4. Загружает ресурс через HTTP-запрос.
  5. Помещает переводы в хранилище ресурсов.
  6. Выполняет поиск ключей внутри загруженных данных.

Например:

i18next
  .use(HttpBackend)
  .init({
    lng: 'ru',
    fallbackLng: 'en',
    backend: {
      loadPath: '/locales/{{lng}}/{{ns}}.json'
    }
  });

При обращении к ключу:

t('welcome')

I18next сначала проверяет наличие загружённого namespace, затем ищет ключ внутри соответствующего JSON-файла.

Если любой этап цепочки завершается ошибкой, перевод не будет найден.


Проверка сетевых запросов

Первое действие при отсутствии переводов — анализ вкладки Network в инструментах разработчика браузера.

Необходимо проверить:

  • выполняется ли запрос;
  • какой URL используется;
  • какой код ответа возвращает сервер;
  • какие данные приходят в ответе.

Пример корректного запроса:

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'
}

Даже одна лишняя буква в пути приводит к ошибке загрузки.


Файлы находятся вне директории public

Во многих сборщиках фронтенд-приложений статические ресурсы должны располагаться в специальной директории.

Пример для React:

public/
└── locales/
    ├── en/
    └── ru/

Если файл находится внутри:

src/locales

браузер может не иметь прямого доступа к нему.

В результате запрос:

/locales/ru/translation.json

вернёт ошибку 404.


Отсутствие backend-плагина

I18next не умеет загружать JSON-файлы автоматически без соответствующего backend-модуля.

Ошибка:

i18next.init({
  lng: 'ru'
});

При такой конфигурации библиотека не знает, откуда брать переводы.

Правильный вариант:

import HttpBackend from 'i18next-http-backend';

i18next
  .use(HttpBackend)
  .init({
    lng: 'ru'
  });

Backend зарегистрирован после init

Порядок подключения имеет значение.

Неверно:

i18next.init({
  lng: 'ru'
});

i18next.use(HttpBackend);

В этот момент инициализация уже завершилась.

Правильно:

i18next
  .use(HttpBackend)
  .init({
    lng: 'ru'
  });

Ошибки в JSON-файлах

I18next ожидает корректный JSON.

Ошибка:

{
  "welcome": "Добро пожаловать",
}

Лишняя запятая делает JSON невалидным.

Ещё один пример:

{
  "welcome": "Добро пожаловать"

Отсутствует закрывающая фигурная скобка.

Для проверки рекомендуется открывать файл напрямую в браузере либо использовать JSON-валидаторы.


Неверная структура JSON

Ключи должны соответствовать способу обращения к ним.

Файл:

{
  "home": {
    "welcome": "Добро пожаловать"
  }
}

Получение перевода:

t('welcome')

Результат:

welcome

Правильный вызов:

t('home.welcome')

Либо изменение структуры файла:

{
  "welcome": "Добро пожаловать"
}

Несоответствие namespace

I18next активно использует пространства имён.

Файл:

locales/
└── ru/
    └── common.json

Конфигурация:

i18next.init({
  ns: ['common']
});

Получение перевода:

t('welcome')

Будет работать только при активном namespace common.

Явное указание:

t('common:welcome')

Если namespace не зарегистрирован:

ns: ['translation']

а файл называется:

common.json

загрузка завершится ошибкой.


Неправильное имя namespace-файла

Конфигурация:

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

Ошибки fallback-языка

Неверная конфигурация:

fallbackLng: 'english'

При наличии только:

locales/en

резервная локаль никогда не загрузится.

Корректно:

fallbackLng: 'en'

Асинхронная загрузка и преждевременный вызов t()

Иногда перевод запрашивается до завершения загрузки ресурсов.

Проблемный код:

i18next.init({
  lng: 'ru'
});

console.log(i18next.t('welcome'));

В момент вызова файлы ещё могут не загрузиться.

Безопасный вариант:

i18next.init({
  lng: 'ru'
}, () => {
  console.log(i18next.t('welcome'));
});

Или:

await i18next.init({
  lng: 'ru'
});

React-компонент рендерится раньше инициализации

При использовании React возможна ситуация, когда интерфейс отображается до окончания загрузки переводов.

Часто проблема проявляется так:

welcome

вместо:

Добро пожаловать

Для корректной работы используется интеграция через React I18next:

import { initReactI18next } from 'react-i18next';

i18next.use(initReactI18next);

А также поддержка Suspense:

react: {
  useSuspense: true
}

Проблемы CORS

Если файлы переводов загружаются с другого домена:

https://cdn.example.com/locales

сервер обязан разрешить кросс-доменные запросы.

Без соответствующих заголовков браузер заблокирует ответ.

Типичное сообщение:

Access to fetch at ...
has been blocked by CORS policy

Необходим заголовок:

Access-Control-Allow-Origin: *

или более строгая настройка для конкретного домена.


Сервер отдаёт неправильный Content-Type

Корректный ответ:

Content-Type: application/json

Некоторые серверы ошибочно возвращают:

Content-Type: text/html

или даже страницу ошибки вместо JSON.

В таких случаях I18next не сможет корректно обработать ресурс.


Кэширование старых переводов

После обновления локализаций браузер может использовать устаревшую версию файла.

Симптом:

  • новый перевод присутствует в файле;
  • приложение показывает старый текст.

Часто помогает добавление версии:

backend: {
  loadPath:
    '/locales/{{lng}}/{{ns}}.json?v=2'
}

Либо настройка серверного контроля кэширования.


Диагностика через debug-режим

Для поиска причин рекомендуется включать подробное логирование.

i18next.init({
  debug: true
});

В консоли появятся сообщения:

loading namespace translation
loaded namespace translation
failed loading
missingKey

По этим сообщениям легко определить этап возникновения проблемы.


Проверка содержимого Resource Store

После загрузки можно проверить внутреннее хранилище переводов.

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.


Проверочный список

При возникновении проблемы с загрузкой переводов необходимо последовательно проверить:

  1. Подключён ли backend-модуль.
  2. Зарегистрирован ли backend до вызова init().
  3. Верен ли путь loadPath.
  4. Существуют ли файлы по указанному адресу.
  5. Нет ли ошибок 404 и 500 в Network.
  6. Корректен ли JSON.
  7. Совпадают ли имена namespace.
  8. Совпадают ли языковые коды.
  9. Загружены ли данные в i18next.store.data.
  10. Отсутствуют ли проблемы CORS.
  11. Не используется ли устаревший кэш.
  12. Включён ли режим debug.
  13. Завершилась ли инициализация до вызова t().
  14. Не возникает ли ошибка при определении языка браузера.
  15. Возвращает ли сервер JSON с корректным Content-Type.

Систематическая проверка этих пунктов позволяет обнаружить практически все причины, по которым I18next не загружает переводы в приложении.