Соглашения команды

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

На практике применяются два распространённых подхода:

  • Составные ключи через точку

    {
      "auth.login.title": "Вход",
      "auth.login.button": "Войти"
    }
  • Вложенная структура объектов

    {
      "auth": {
        "login": {
          "title": "Вход",
          "button": "Войти"
        }
      }
    }

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

Чаще выбирается точечная нотация, поскольку она лучше масштабируется при автоматической генерации и поиске ключей в кодовой базе.


Стандартизация нейминга ключей

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

  • использование camelCase или snake_case, но не обоих одновременно
  • отсутствие глаголов в ключах уровня сущностей
  • разделение по функциональным доменам
  • запрет на контекстные описания внутри ключа

Примеры допустимых ключей:

user.profile.title
cart.item.removeButton
order.status.pending

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

clickRemoveItemNow
button_for_deleting_item_from_cart
removeItemFromCartWhenUserClicks

Ключи должны описывать сущность и назначение, а не действие или сценарий.


Соглашения по namespaces

i18next активно использует концепцию пространств имён (namespaces), которая позволяет разделять переводы по модулям приложения.

Типовая структура:

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

Каждый namespace соответствует функциональному блоку:

  • common — общие элементы интерфейса
  • auth — авторизация и регистрация
  • cart — корзина покупок
  • profile — пользовательские данные

В коде это отражается явно:

i18next.t('login.title', { ns: 'auth' });

В командных соглашениях фиксируется правило: каждый новый модуль обязан иметь собственный namespace, чтобы избежать разрастания common.


Правила организации файлов переводов

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

Рекомендуемая организация:

locales/
  en/
    auth.json
    cart.json
  ru/
    auth.json
    cart.json
  de/
    auth.json
    cart.json

Основные правила:

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

Нарушение симметрии приводит к ошибкам fallback-механизма и усложняет автоматические проверки покрытия переводов.


Соглашения по интерполяции

i18next поддерживает интерполяцию значений через синтаксис:

t('welcome', { name: 'Alex' });

И соответствующий перевод:

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

В командных соглашениях фиксируются следующие правила:

  • всегда использовать {{variable}}, без альтернативных синтаксисов
  • не включать бизнес-логику в строку перевода
  • не формировать длинные составные выражения внутри i18n

Недопустимо:

{
  "price": "Цена: {{price * taxRate}}"
}

Корректный подход:

const total = price * taxRate;
t('price', { value: total });

Плюрализация и числовые формы

i18next поддерживает plural rules в зависимости от языка:

{
  "item": "1 предмет",
  "item_other": "{{count}} предметов"
}

В коде:

t('item', { count: 5 });

Командные стандарты обычно требуют:

  • обязательное использование count как единственного параметра
  • запрет на ручную обработку форм множественного числа в коде
  • использование встроенных правил ICU или i18next pluralization engine

Для языков со сложной морфологией (русский, польский) допускается расширенная форма:

{
  "item_one": "{{count}} предмет",
  "item_few": "{{count}} предмета",
  "item_many": "{{count}} предметов"
}

Использование контекста (context)

Контекст позволяет изменять перевод в зависимости от состояния:

t('button', { context: 'save' });
t('button', { context: 'delete' });

Файл перевода:

{
  "button_save": "Сохранить",
  "button_delete": "Удалить"
}

Соглашения команды обычно ограничивают использование context:

  • использовать только для UI-элементов с одинаковым смыслом
  • не применять для бизнес-логики
  • избегать глубоких цепочек контекста

Контекст не должен заменять namespace.


ICU и формат сообщений

В современных проектах часто применяется ICU MessageFormat через i18next-icu.

Пример:

{
  "cart": "{count, plural, one {# товар} few {# товара} other {# товаров}}"
}

Соглашения:

  • использовать ICU для сложных грамматических конструкций
  • избегать смешивания ICU и ручных plural keys в одном namespace
  • не перегружать строки вложенными условиями

Форматирование дат, чисел и валют

i18next не занимается форматированием напрямую, но интегрируется с Intl.

Соглашения команды:

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

Пример неправильного подхода:

{
  "date": "Сегодня 12.05.2026"
}

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

{
  "date": "Сегодня {{date}}"
}

И форматирование в коде:

const formatted = new Intl.DateTimeFormat('ru-RU').format(date);
t('date', { date: formatted });

Соглашения по fallback-логике

Fallback является важной частью архитектуры локализации.

Типичная конфигурация:

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

Командные правила:

  • fallback язык всегда должен быть один
  • запрещено каскадное fallback-дерево более чем из 2 уровней
  • отсутствие перевода в fallback считается ошибкой сборки

Контроль качества ключей

Для поддержания консистентности переводов применяются автоматические проверки:

  • проверка отсутствующих ключей
  • сравнение структуры JSON между языками
  • выявление неиспользуемых ключей
  • валидация интерполяционных переменных

Пример правила линтера:

rules: {
  'i18n/no-missing-keys': 'error',
  'i18n/no-unused-keys': 'warn'
}

Соглашения по переиспользованию ключей

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

Запрещается:

  • использовать один ключ для разных UI-смыслов
  • переиспользовать тексты кнопок в разных доменах без анализа

Допускается:

  • общие UI-элементы в common
  • системные сообщения (error, loading, success)

Разделение ответственности между разработкой и переводами

Командная модель работы с i18next требует четкого разграничения:

  • разработчики определяют структуру ключей и namespaces
  • переводчики работают только с текстовыми значениями
  • продуктовая логика не должна проникать в строки локализации

Ключи рассматриваются как стабильный API, который не должен меняться без миграции.


Версионирование переводов

В крупных системах вводится версионирование локалей:

  • синхронизация с версиями приложения
  • контроль несовместимых изменений ключей
  • миграционные скрипты для переименований

Пример стратегии:

v1/auth.json
v2/auth.json

или через миграции ключей:

renameKey('auth.login.title', 'auth.signIn.title');

Ограничения на длину и структуру строк

Для предотвращения проблем UI применяются ограничения:

  • строки не должны содержать HTML-разметку
  • запрещены вложенные списки и сложные конструкции
  • текст должен оставаться атомарным

Допускается:

{
  "warning": "Действие необратимо"
}

Недопустимо:

{
  "warning": "<b>Внимание:</b> действие необратимо, нажмите OK"
}