В библиотеке i18next обработка множественных форм основана на
встроенном PluralResolver, который опирается на правила
CLDR (Unicode Common Locale Data Repository). Для большинства языков
достаточно стандартных правил, однако в реальных приложениях часто
возникает необходимость переопределять или расширять поведение, особенно
при работе с нестандартными локалями, бизнес-логикой отображения или
исторически сложившимися форматами перевода.
Плюрализация в i18next реализуется через комбинацию ключей ресурсов,
количества (count) и набора правил, определяющих выбор
формы.
i18next использует соглашение по ключам:
itemitem_pluralitem_two (для некоторых языков)item_few, item_manyitem_zero (опционально)Выбор формы зависит от локали и значения count.
Пример структуры ресурсов:
{
"item": "Элемент",
"item_plural": "Элементы"
}
При вызове:
i18next.t("item", { count: 5 });
будет выбрана форма item_plural.
Внутренний PluralResolver выполняет следующие шаги:
lng)count_plural, _few,
_many и т.д.)Важным элементом является зависимость от CLDR-правил, которые покрывают большинство языков, но не всегда соответствуют прикладной логике.
i18next позволяет переопределять правила через addRule в
pluralResolver.
Основной интерфейс:
i18next.services.pluralResolver.addRule(lng, {
numbers: [],
plurals: function (n) {
return index;
}
});
Каждое правило содержит:
numbers: массив допустимых значений
countplurals: функция, возвращающая индекс формыappend: (опционально) добавление суффиксовcoverage: описание диапазонов (используется
внутренне)Рассмотрим упрощённый пример языка, где существует только две формы:
i18next.services.pluralResolver.addRule("custom-lang", {
numbers: [1, 2],
plurals: function (n) {
return n === 1 ? 0 : 1;
}
});
В этом случае индекс 0 соответствует базовой форме, а
1 — множественной.
Ресурсы:
{
"car": "машина",
"car_plural": "машины"
}
Некоторые языки требуют более детальной логики, например три формы:
Реализация:
i18next.services.pluralResolver.addRule("ru-custom", {
numbers: [1, 2, 5],
plurals: function (n) {
if (n % 10 === 1 && n % 100 !== 11) return 0;
if (n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20)) return 1;
return 2;
}
});
Ресурсы:
{
"comment": "комментарий",
"comment_few": "комментария",
"comment_many": "комментариев"
}
Ключевым механизмом является параметр count, который
автоматически передаётся в функцию перевода:
i18next.t("comment", { count: 3 });
При этом:
count не только влияет на выбор формыПример:
{
"comment": "{{count}} комментарий",
"comment_few": "{{count}} комментария",
"comment_many": "{{count}} комментариев"
}
По умолчанию i18next использует _ как разделитель:
key_plural
key_few
Его можно изменить:
i18next.init({
pluralSeparator: "|"
});
Тогда структура ключей становится:
key|plural
key|few
Это важно при интеграции с системами, где символ _ уже
зарезервирован.
Плюрализация может комбинироваться с context, что
создаёт дополнительный уровень выбора:
i18next.t("friend", { count: 2, context: "male" });
Ресурсы:
{
"friend_male": "друг",
"friend_male_plural": "друзья",
"friend_female": "подруга",
"friend_female_plural": "подруги"
}
Здесь сначала применяется контекст, затем плюрализация.
Внутренний механизм разрешения выполняется по следующей иерархии:
key_context_pluralkey_contextkey_pluralkeyЭто означает, что наиболее специфичная форма имеет приоритет.
Некоторые локали требуют обработки не только целых чисел, но и дробных значений.
Пример кастомного правила:
i18next.services.pluralResolver.addRule("xx", {
numbers: [0, 1, 2],
plurals: function (n) {
if (n === 0) return 0;
if (n === 1) return 1;
return 2;
}
});
Использование:
i18next.t("point", { count: 0.5 });
Встроенные правила могут быть переопределены полностью, если зарегистрировать локаль с тем же кодом:
i18next.services.pluralResolver.addRule("en", {
numbers: [1, 2],
plurals: function (n) {
return n === 1 ? 0 : 1;
}
});
Такое переопределение требует аккуратности, так как затрагивает все переводы для языка.
Правила могут добавляться в рантайме, что позволяет изменять поведение без пересборки приложения:
function registerPluralRule(lng) {
i18next.services.pluralResolver.addRule(lng, {
numbers: [1, 2],
plurals: n => (n === 1 ? 0 : 1)
});
}
Это часто используется в плагинах или модульных системах.
Если для текущей локали отсутствует правило плюрализации, используется fallback:
i18next.init({
fallbackLng: "en"
});
При этом выбор формы будет определяться языком fallback, даже если ресурсы локализованы иначе.
Плюрализация может сочетаться с форматтерами:
i18next.t("balance", {
count: 1500,
formatParams: {
count: {
minimumFractionDigits: 0
}
}
});
Это позволяет отделить логику формы от отображения чисел.
При создании собственных правил важно учитывать:
numbers и возвращаемого индекса приводит
к fallbackЕсли соответствующий ключ отсутствует, i18next:
Это важно при неполных ресурсах, особенно при кастомных правилах.
Кастомные правила часто применяются в следующих случаях:
Такие сценарии требуют строгого контроля соответствия индексов и ключей ресурсов, поскольку i18next не валидирует корректность семантики форм, ограничиваясь механикой выбора.