Создание файлов переводов

Файлы переводов формируют основу любой локализации в i18next и определяют, как именно приложение будет отделять языковую логику от бизнес-кода. На уровне структуры это обычные JSON-документы, в которых ключи соответствуют идентификаторам строк интерфейса, а значения — переведённому тексту или вложенным объектам с вариантами форм.

В простейшем виде файл перевода представляет собой плоский JSON-объект:

{
  "welcome": "Добро пожаловать",
  "logout": "Выйти",
  "login": "Войти"
}

Такой формат удобен для небольших проектов, однако при росте приложения он быстро становится ограничивающим. Основная проблема плоской структуры — отсутствие логического группирования ключей.

Группировка ключей и вложенные структуры

i18next поддерживает вложенные объекты, позволяя организовывать переводы по смысловым блокам:

{
  "auth": {
    "login": "Войти",
    "logout": "Выйти",
    "register": "Регистрация"
  },
  "profile": {
    "title": "Профиль пользователя",
    "edit": "Редактировать профиль"
  }
}

При обращении к таким ключам используется точечная нотация:

i18next.t('auth.login');
i18next.t('profile.title');

Вложенная структура снижает когнитивную нагрузку и упрощает масштабирование словаря.

Использование пространств имён (namespaces)

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

Типичная структура каталогов:

locales/
  ru/
    common.json
    auth.json
    dashboard.json
  en/
    common.json
    auth.json
    dashboard.json

Пример auth.json:

{
  "login": "Войти",
  "logout": "Выйти"
}

Подключение пространства имён:

i18next.init({
  lng: 'ru',
  ns: ['common', 'auth'],
  defaultNS: 'common',
  resources: {
    ru: {
      common: require('./locales/ru/common.json'),
      auth: require('./locales/ru/auth.json')
    }
  }
});

Использование ключей с указанием namespace:

i18next.t('auth:login');

Такой подход обеспечивает модульность и снижает риск конфликтов ключей.

Интерполяция значений

Файлы переводов поддерживают динамические параметры. Это позволяет формировать строки с переменными значениями:

{
  "greeting": "Привет, {{name}}",
  "messages": "У вас {{count}} сообщений"
}

Использование:

i18next.t('greeting', { name: 'Алексей' });
i18next.t('messages', { count: 5 });

Интерполяция позволяет полностью исключить конкатенацию строк в коде и централизовать форматирование текста.

Множественные формы (pluralization)

Одним из ключевых аспектов файлов переводов является поддержка множественных форм:

{
  "apple_one": "Яблоко",
  "apple_other": "Яблок",
  "apple_few": "Яблока"
}

Использование:

i18next.t('apple', { count: 1 });
i18next.t('apple', { count: 3 });

i18next автоматически выбирает нужную форму в зависимости от языка и переданного значения count.

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

Контекстные переводы

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

{
  "button_save": "Сохранить",
  "button_save_context_admin": "Сохранить как администратор"
}

Использование:

i18next.t('button_save', { context: 'admin' });

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

Экранирование и безопасная вставка HTML

Файлы переводов по умолчанию предназначены для текстового содержимого, однако иногда требуется вставка HTML-разметки:

{
  "privacy": "Ознакомьтесь с <1>политикой конфиденциальности</1>"
}

В React или аналогичных библиотеках это обрабатывается через компоненты интерполяции, где числа обозначают вложенные элементы.

При этом важно учитывать настройку escapeValue, предотвращающую XSS-уязвимости:

i18next.init({
  interpolation: {
    escapeValue: false
  }
});

Форматирование и стандартизация ключей

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

Доменная структура

{
  "auth.login.title": "Вход в систему",
  "auth.login.submit": "Отправить"
}

Иерархическая структура

{
  "auth": {
    "login": {
      "title": "Вход в систему",
      "submit": "Отправить"
    }
  }
}

Иерархическая модель более предпочтительна при сложных интерфейсах, так как отражает структуру приложения.

Разделение по языкам

Каждый язык хранится в отдельной директории. Это позволяет независимо развивать переводы:

locales/
  en/
    common.json
  ru/
    common.json
  de/
    common.json

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

Динамическая загрузка файлов переводов

В крупных приложениях файлы переводов часто загружаются по требованию:

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

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

Использование fallback-языков

Файлы переводов могут быть неполными, поэтому задаётся резервный язык:

i18next.init({
  fallbackLng: 'en'
});

Если ключ отсутствует в текущем языке, система автоматически обращается к fallback-файлу переводов.

Согласованность структуры переводов

При работе с несколькими языками критически важно поддерживать идентичную структуру файлов. Любое расхождение в ключах приводит к отсутствующим переводам.

Пример корректной синхронизации:

en/auth.json -> login, logout, register
ru/auth.json -> login, logout, register
de/auth.json -> login, logout, register

Несовпадение структуры:

en/auth.json -> login, logout
ru/auth.json -> login, register

Такая ситуация приводит к непредсказуемому поведению интерфейса.

Использование JSON как основного формата

JSON выбран как основной формат благодаря:

  • строгой структуре данных;
  • простоте парсинга;
  • поддержке вложенности;
  • совместимости с JavaScript-экосистемой.

При необходимости допускается использование YAML или других форматов, однако они требуют дополнительного преобразования перед передачей в i18next.

Ключи как контракт между кодом и переводами

Файлы переводов фактически выступают контрактом между интерфейсом и логикой локализации. Изменение ключа без обновления кода приводит к разрыву связи между слоями приложения.

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