Категории: zero, one, two, few, many, other

Механизм множественных форм в JavaScript основан на стандарте CLDR (Common Locale Data Repository) и реализуется через Intl.PluralRules. Он определяет набор категорий, которые используются для выбора правильной формы слова в зависимости от числа.

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

  • zero
  • one
  • two
  • few
  • many
  • other

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

Intl.PluralRules и определение категории

Базовый интерфейс работы с категориями реализован через объект Intl.PluralRules.

const pr = new Intl.PluralRules('en-US');

pr.select(1);   // "one"
pr.select(2);   // "other"
pr.select(0);   // "other"

Метод select() возвращает строку-категорию, соответствующую числу в контексте выбранной локали.

Категория zero

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

В большинстве западноевропейских языков ноль попадает в other, однако в некоторых локалях он выделяется отдельно.

Пример логики:

const pr = new Intl.PluralRules('lv'); // латышский

pr.select(0); // "zero"

Категория zero используется для специальных форм, связанных с отсутствием предметов, когда грамматика требует уникального выражения.

Категория one

Категория one соответствует единичному количеству, но её определение не всегда строго равно 1.

В разных языках правило может включать:

  • только 1
  • 1.0
  • числа, удовлетворяющие локальным условиям

Пример:

const pr = new Intl.PluralRules('en');

pr.select(1);   // "one"
pr.select(1.0); // "one"

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

Категория two

Категория two характерна для языков с различием двойственного числа.

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

Пример:

const pr = new Intl.PluralRules('ar');

pr.select(2); // "two"

Категория two часто встречается в семитских языках и некоторых исторических формах индоевропейских языков.

Категория few

Категория few применяется для небольших количеств, которые не равны 1 или 2, но всё ещё считаются «малым числом» в грамматике языка.

Пример использования:

const pr = new Intl.PluralRules('ru');

pr.select(3); // "few"
pr.select(4); // "few"

В русском языке категория few соответствует числам, заканчивающимся на 2, 3 или 4 (за исключением 12–14).

Морфологическая логика:

  • 1 → one
  • 2–4 → few
  • 5–20 → many

Категория many

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

Пример для русского языка:

const pr = new Intl.PluralRules('ru');

pr.select(5);  // "many"
pr.select(11); // "many"
pr.select(21); // "one"

Категория many часто охватывает диапазоны чисел, которые не попадают в few, а также специальные случаи с исключениями (например, подростки чисел 11–14 в славянских языках).

Категория other

Категория other является универсальной и используется как значение по умолчанию, когда число не соответствует ни одной специализированной форме.

Пример:

const pr = new Intl.PluralRules('en-US');

pr.select(0); // "other"
pr.select(2); // "other"

В английском языке:

  • one → 1
  • other → все остальные значения

Категория other играет роль fallback-ветки и присутствует во всех локалях без исключения.

Сравнение категорий в разных локалях

Разные языки используют разные подмножества категорий:

Английский (en)

  • one
  • other
new Intl.PluralRules('en').select(1); // one
new Intl.PluralRules('en').select(5); // other

Русский (ru)

  • one
  • few
  • many
  • other (редко используется напрямую)
const pr = new Intl.PluralRules('ru');

pr.select(1); // "one"
pr.select(2); // "few"
pr.select(5); // "many"

Арабский (ar)

  • zero
  • one
  • two
  • few
  • many
  • other
const pr = new Intl.PluralRules('ar');

pr.select(0); // "zero"
pr.select(1); // "one"
pr.select(2); // "two"
pr.select(3); // "few"

Использование категорий для выбора строк

Категории применяются для динамического формирования текстовых форм:

const pr = new Intl.PluralRules('ru');

const forms = {
  one: 'сообщение',
  few: 'сообщения',
  many: 'сообщений',
  other: 'сообщения'
};

function format(count) {
  const form = pr.select(count);
  return `${count} ${forms[form]}`;
}

format(1);
format(3);
format(5);

Дробные числа и категории

Множественные правила учитывают не только целые числа:

const pr = new Intl.PluralRules('en');

pr.select(1.5); // "other"
pr.select(0.5); // "other"

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

Диапазоны и семантика выбора

Категории не привязаны напрямую к математическим диапазонам. Они определяются набором правил CLDR:

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

Роль категории в форматировании сообщений

Категории используются не только для чисел, но и для любых структур, где требуется согласование:

  • количество элементов в списке
  • сообщения интерфейса
  • локализованные уведомления
  • динамические заголовки
const pr = new Intl.PluralRules('en');

const messages = {
  one: 'file',
  other: 'files'
};

function label(n) {
  return `${n} ${messages[pr.select(n)]}`;
}

Связь с CLDR правилами

Каждая категория определяется через выражения CLDR, которые формально описывают условия:

  • n = 1 → one
  • n mod 10 in 2..4 and n mod 100 not in 12..14 → few
  • n mod 10 = 0 or n mod 10 in 5..9 → many

Эти правила интерпретируются движком Intl.PluralRules и скрыты от разработчика, но определяют результат select().

Поведение fallback-логики

Если локаль не поддерживает определённую категорию, происходит автоматическое сведение к доступной форме:

  • отсутствующие категории игнорируются
  • используется other
  • структура остаётся согласованной

Такая модель обеспечивает универсальность API независимо от языка и набора правил.