Механизм множественных форм в JavaScript основан на стандарте CLDR
(Common Locale Data Repository) и реализуется через
Intl.PluralRules. Он определяет набор категорий, которые
используются для выбора правильной формы слова в зависимости от
числа.
Система категорий не является фиксированной для всех языков. Вместо универсального правила используется набор семантических групп, которые интерпретируются локалью. Основные категории:
Каждая локаль использует только часть этих категорий. Например,
английский язык применяет в основном one и
other, тогда как арабский задействует почти весь набор.
Базовый интерфейс работы с категориями реализован через объект
Intl.PluralRules.
const pr = new Intl.PluralRules('en-US');
pr.select(1); // "one"
pr.select(2); // "other"
pr.select(0); // "other"
Метод select() возвращает строку-категорию,
соответствующую числу в контексте выбранной локали.
Категория zero применяется в языках, где ноль имеет отдельную грамматическую форму.
В большинстве западноевропейских языков ноль попадает в
other, однако в некоторых локалях он выделяется
отдельно.
Пример логики:
const pr = new Intl.PluralRules('lv'); // латышский
pr.select(0); // "zero"
Категория zero используется для специальных форм,
связанных с отсутствием предметов, когда грамматика требует уникального
выражения.
Категория one соответствует единичному количеству,
но её определение не всегда строго равно 1.
В разных языках правило может включать:
Пример:
const pr = new Intl.PluralRules('en');
pr.select(1); // "one"
pr.select(1.0); // "one"
В языках с более сложной морфологией категория one может
зависеть от формы числа, а не только от его значения.
Категория two характерна для языков с различием двойственного числа.
Она используется в ограниченном числе локалей, где грамматика выделяет ровно два объекта как отдельную форму.
Пример:
const pr = new Intl.PluralRules('ar');
pr.select(2); // "two"
Категория two часто встречается в семитских языках и
некоторых исторических формах индоевропейских языков.
Категория few применяется для небольших количеств, которые не равны 1 или 2, но всё ещё считаются «малым числом» в грамматике языка.
Пример использования:
const pr = new Intl.PluralRules('ru');
pr.select(3); // "few"
pr.select(4); // "few"
В русском языке категория few соответствует числам,
заканчивающимся на 2, 3 или 4 (за исключением 12–14).
Морфологическая логика:
Категория many используется для больших чисел или чисел с определёнными окончаниями, которые в языке требуют отдельной формы множественного числа.
Пример для русского языка:
const pr = new Intl.PluralRules('ru');
pr.select(5); // "many"
pr.select(11); // "many"
pr.select(21); // "one"
Категория many часто охватывает диапазоны чисел, которые
не попадают в few, а также специальные случаи с
исключениями (например, подростки чисел 11–14 в славянских языках).
Категория other является универсальной и используется как значение по умолчанию, когда число не соответствует ни одной специализированной форме.
Пример:
const pr = new Intl.PluralRules('en-US');
pr.select(0); // "other"
pr.select(2); // "other"
В английском языке:
one → 1other → все остальные значенияКатегория other играет роль fallback-ветки и
присутствует во всех локалях без исключения.
Разные языки используют разные подмножества категорий:
new Intl.PluralRules('en').select(1); // one
new Intl.PluralRules('en').select(5); // other
const pr = new Intl.PluralRules('ru');
pr.select(1); // "one"
pr.select(2); // "few"
pr.select(5); // "many"
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, которые формально описывают условия:
n = 1 → onen mod 10 in 2..4 and n mod 100 not in 12..14 → fewn mod 10 = 0 or n mod 10 in 5..9 → manyЭти правила интерпретируются движком Intl.PluralRules и
скрыты от разработчика, но определяют результат
select().
Если локаль не поддерживает определённую категорию, происходит автоматическое сведение к доступной форме:
otherТакая модель обеспечивает универсальность API независимо от языка и набора правил.