Неправильная плюрализация

В системе i18next обработка множественных форм основана на правилах CLDR (Common Locale Data Repository), где каждая локаль имеет собственный набор категорий: zero, one, two, few, many, other. Библиотека автоматически выбирает нужную форму на основе значения count, однако корректность результата зависит от структуры переводов и соответствия языковым правилам.

Основной принцип: значение count определяет ключ, который будет использован при выборе перевода. Ошибка возникает, когда структура ресурсов не учитывает все формы или когда используется упрощённая схема с одной-двумя формами для языков, где требуется больше вариантов.


Структура ключей множественного числа

В i18next допускаются два основных подхода:

Суффиксный формат

item_one
item_few
item_many
item_other

или более компактный вариант:

item
item_plural

Однако упрощённый вариант корректен только для языков с бинарной системой (например, английский), где различаются только singular/plural.

Пример конфигурации:

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

Ошибки при использовании упрощённой схемы

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

Пример некорректной структуры:

{
  "item_one": "{{count}} элемент",
  "item_other": "{{count}} элементов"
}

Для русского языка этого недостаточно, поскольку отсутствуют формы few и many. В результате библиотека вынуждена подставлять fallback, что приводит к грамматически неправильным строкам.


Правила русского языка и CLDR категории

Русская локаль использует три основные формы:

  • one — 1, 21, 31, 41…
  • few — 2–4, 22–24, 32–34…
  • many — 0, 5–20, 25–30…
  • other — резервная форма

i18next маппит эти правила автоматически, но только при наличии соответствующих ключей.

Корректная структура:

{
  "car_one": "{{count}} машина",
  "car_few": "{{count}} машины",
  "car_many": "{{count}} машин"
}

Использование параметра count

Ключевой источник ошибок — некорректная передача count. i18next использует его для выбора формы.

Пример корректного вызова:

i18next.t('car', { count: 5 });

При этом ресурс должен быть структурирован как:

{
  "car_one": "машина",
  "car_few": "машины",
  "car_many": "машин"
}

Если count передаётся как строка, возможны ошибки приведения типов, особенно при использовании кастомных интерполяций:

i18next.t('car', { count: "5" });

В этом случае поведение зависит от конфигурации returnObjects и внутренних преобразований.


Несоответствие ключей и namespace

Частая ошибка связана с рассинхронизацией ключей в разных namespace.

Пример:

i18next.t('common:car', { count: 2 });

Если в common отсутствует car_few, система может перейти к fallback-локали или использовать other, что ломает грамматическую корректность.


Игнорирование нулевой формы

Некоторые языки выделяют отдельную форму zero. В i18next она поддерживается, но часто не используется.

Ошибка:

{
  "message_one": "сообщение",
  "message_other": "сообщения"
}

При count = 0 может потребоваться отдельная форма:

{
  "message_zero": "сообщений нет",
  "message_one": "1 сообщение",
  "message_few": "{{count}} сообщения",
  "message_many": "{{count}} сообщений"
}

Отсутствие zero приводит к неестественным формулировкам вроде «0 сообщений» там, где требуется специальная семантика.


Влияние интерполяции на формы множественного числа

i18next позволяет комбинировать pluralization и interpolation:

{
  "apples_one": "Есть {{count}} яблоко",
  "apples_few": "Есть {{count}} яблока",
  "apples_many": "Есть {{count}} яблок"
}

Ошибка возникает при попытке использовать вложенные выражения:

{
  "apples_many": "Есть {{formatCount count}} яблок"
}

Функции интерполяции не должны вмешиваться в выбор plural key. Нарушение этого правила приводит к тому, что plural resolver работает с некорректным значением.


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

При отсутствии формы в текущей локали i18next обращается к fallback.

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

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

Проблема возникает, когда fallback локаль имеет другую систему plural forms. Например, английский использует только one/other, а русский требует few/many. В результате fallback может возвращать грамматически неправильные строки.


Ошибки при использовании суффикса _plural

Упрощённый формат:

{
  "item": "item",
  "item_plural": "items"
}

Работает только для языков с бинарной системой. При использовании в русской локали происходит деградация до other, что создаёт систематические ошибки в формах 2–4 и 5+.


Влияние кастомного pluralResolver

i18next позволяет переопределять правила:

i18next.init({
  pluralResolver: {
    getPluralFormsOfKey: () => []
  }
});

Ошибочная реализация приводит к тому, что все значения count сводятся к одному ключу. Это полностью ломает систему морфологии и делает локализацию статической.


Конфликты с ICU форматированием

При использовании i18next-icu появляется альтернативный синтаксис:

{count, plural, one {# файл} few {# файла} many {# файлов}}

Конфликт возникает при смешивании ICU и стандартных суффиксов i18next. В этом случае:

  • ICU берёт приоритет над ключами
  • стандартные plural keys игнорируются
  • возможна потеря части переводов при миграции

Дублирование ключей и переопределение форм

При объединении ресурсов через merge возможна ситуация:

{
  "file_one": "файл"
}

и позже:

{
  "file_few": "файла"
}

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


Ошибки локализации при динамических ключах

Антипаттерн:

i18next.t(`item_${type}`, { count });

Если type не синхронизирован с plural системой, возникает расхождение между выбранной формой и фактическим count. Это приводит к несоответствию:

  • грамматики
  • числового значения
  • семантики текста

Несогласованность между UI и переводами

Часто plural формы проектируются без учёта интерфейсной логики:

  • UI показывает «0 товаров»
  • перевод ожидает «товаров нет»
  • отсутствует ключ zero

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