Обработка ошибок загрузки

В i18next загрузка переводов является асинхронным процессом, который опирается на подключённый backend (HTTP, файловая система, custom loader). Любая ошибка на этом этапе приводит не к остановке приложения, а к переходу на деградированный режим работы с применением fallback-языков и частично загруженных ресурсов.

Ключевой принцип: система продолжает функционировать даже при неполной локализации, используя цепочку резервных языков и уже доступные namespaces.


Основные категории ошибок загрузки

Ошибки сетевого уровня

При использовании HTTP-backend (например, i18next-http-backend) типичными проблемами становятся:

  • таймаут запроса переводов
  • 404 (отсутствие файла ресурса)
  • 500 (ошибка сервера)
  • CORS-ограничения
  • разрыв соединения

Такие ошибки фиксируются как failedLoading и не прерывают инициализацию i18next.

Пример типичной конфигурации backend:

import i18next from 'i18next';
import HttpBackend from 'i18next-http-backend';

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

При отсутствии файла /locales/ru/common.json система автоматически попытается использовать fallback-язык.


Ошибки отсутствующих ресурсов

Если namespace не загружен и отсутствует fallback, возникает ситуация частично пустых ключей перевода. В этом случае i18next:

  • возвращает ключ перевода (если returnNull: false)
  • или null (если явно разрешено)
  • или fallback-строку из defaultValue

Конфигурационные параметры, влияющие на поведение:

i18next.init({
  fallbackLng: 'en',
  returnNull: false,
  returnEmptyString: false,
  defaultNS: 'common',
});

Ошибки парсинга ресурсов

Если загруженный JSON некорректен (битый формат, синтаксическая ошибка), backend завершает загрузку с ошибкой парсинга.

Типичные причины:

  • лишняя запятая в JSON
  • неверная кодировка файла
  • обрезанный ответ сервера

В таком случае ресурс считается не загруженным, и активируется fallback-цепочка языков.


Механизм события failedLoading

i18next предоставляет низкоуровневый механизм отслеживания ошибок загрузки через событие failedLoading.

i18next.on('failedLoading', (lng, ns, msg) => {
  console.log('Ошибка загрузки:', {
    language: lng,
    namespace: ns,
    message: msg,
  });
});

Событие вызывается при:

  • невозможности загрузить namespace
  • сетевых ошибках backend
  • ошибках парсинга ресурса

Это позволяет централизованно логировать проблемы или отправлять их в систему мониторинга.


Обработка ошибок в HTTP-backend

i18next-http-backend поддерживает расширенные механизмы обработки сбоев.

Поведение при ошибке запроса

По умолчанию backend:

  • не выбрасывает исключение наружу
  • возвращает ошибку в internal callback
  • инициирует fallback-загрузку

Дополнительно можно контролировать retry-логику:

import HttpBackend from 'i18next-http-backend';

i18next.use(HttpBackend).init({
  backend: {
    loadPath: '/locales/{{lng}}/{{ns}}.json',
    requestOptions: {
      timeout: 5000,
    },
    reloadInterval: false,
  },
});

Fallback-цепочка языков

При ошибке загрузки ресурсов система последовательно проходит fallback-цепочку:

  1. основной язык (lng)
  2. региональный вариант (ru-RU → ru)
  3. fallbackLng (en)
  4. дефолтные значения (defaultValue)
  5. ключ перевода

Пример:

i18next.init({
  lng: 'ru-KZ',
  fallbackLng: ['ru', 'en'],
});

Если ru-KZ недоступен, система пытается загрузить ru, затем en.


Проблемы частичной загрузки namespaces

В больших приложениях переводы разделяются на namespaces. Ошибка загрузки одного namespace не влияет на другие.

Пример:

  • common загружен успешно
  • profile не загружен
  • checkout не загружен

В результате:

  • интерфейс частично локализован
  • отсутствующие ключи заменяются fallback-значениями

Контроль загрузки:

i18next.on('loaded', (loaded) => {
  console.log('Загруженные ресурсы:', loaded);
});

Асинхронная инициализация и ошибки старта

Инициализация i18next может завершаться до фактической загрузки переводов.

Критический момент: ошибки загрузки не блокируют init(), если не используется принудительное ожидание ресурсов.

i18next.init({
  initImmediate: false,
});

При initImmediate: false система дожидается загрузки ресурсов, и ошибки становятся более явными на этапе старта.


Ошибки при динамической загрузке языков

При переключении языка вызывается загрузка новых ресурсов:

i18next.changeLanguage('de');

Возможные сбои:

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

Поведение:

  • текущий язык остаётся активным при ошибке
  • переключение откатывается
  • fallbackLng может примениться частично

Обработка ошибок в custom backend

При реализации собственного backend ответственность за обработку ошибок полностью ложится на разработчика.

Пример структуры:

class CustomBackend {
  read(language, namespace, callback) {
    fetch(`/api/translations/${language}/${namespace}`)
      .then(res => res.json())
      .then(data => callback(null, data))
      .catch(err => callback(err, false));
  }
}

Ключевой момент: второй параметр callback управляет успешностью загрузки. Если он false, i18next активирует fallback-логику.


Логирование и диагностика ошибок

Встроенный режим debug позволяет отслеживать проблемы загрузки:

i18next.init({
  debug: true,
});

В режиме debug фиксируются:

  • failed loading namespaces
  • missing resources
  • fallback resolution chain

Для продакшена чаще используется внешняя система логирования через failedLoading.


Потеря частичных данных и стратегия деградации

При нестабильной загрузке система может работать в смешанном режиме:

  • часть строк на основном языке
  • часть на fallback
  • часть в виде ключей

Эта модель считается нормальной для i18next и позволяет избежать полного отказа интерфейса.

Стратегия деградации зависит от конфигурации:

  • агрессивный fallback (много языков в цепочке)
  • минимальный fallback (только en)
  • отсутствие fallback (жёсткая локализация)

Ошибки кэширования ресурсов

При использовании HTTP-backend и CDN возможны ситуации:

  • устаревшие переводы
  • несоответствие версий namespace
  • частично обновлённые JSON

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

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

или отключение кэша на уровне сервера.


Конфликт загрузки при параллельных запросах

При одновременном запросе одного namespace несколькими компонентами:

  • i18next объединяет запросы
  • выполняется одна загрузка
  • результат кэшируется

Ошибки при этом распространяются на всех потребителей namespace, но не дублируются.


Поведение при отсутствующих ключах после ошибки загрузки

Если ресурс не загрузился полностью:

  • ключи возвращаются как строки-заполнители
  • может использоваться defaultValue
  • активируется интерполяция fallback
i18next.t('profile.name', {
  defaultValue: 'Unknown user',
});

Централизованная стратегия устойчивости

Типичная промышленная конфигурация обработки ошибок загрузки включает:

  • fallbackLng цепочку
  • event listener failedLoading
  • HTTP timeout
  • debug логирование в dev окружении
  • CDN cache busting
  • частичную деградацию интерфейса без блокировок
i18next
  .on('failedLoading', (lng, ns, msg) => {
    // отправка в мониторинг
  })
  .init({
    fallbackLng: ['ru', 'en'],
    returnNull: false,
    debug: false,
  });