В JavaScript работа с порядковыми числительными строится вокруг двух
основных механизмов международного API: Intl.PluralRules и
Intl.NumberFormat. Оба инструмента решают задачу языковой
адаптации чисел, но делают это на разных уровнях: первый определяет
грамматическую категорию числа, второй формирует конечное отображение
строки с учётом локали.
Порядковые числительные (first, second, third; первый, второй, третий
и т.д.) в разных языках подчиняются различным грамматическим правилам. В
английском языке достаточно различать суффиксы st,
nd, rd, th, тогда как в
славянских языках система сложнее и зависит от падежных и числовых
форм.
Интерфейс Intl.PluralRules предоставляет метод
классификации чисел по языковым категориям. Для порядковых числительных
используется тип ordinal.
Базовый набор категорий включает:
one — первая формаtwo — вторая формаfew — ограниченное количество (в некоторых языках)other — остальные случаиВажно учитывать, что конкретные категории зависят от локали. Например:
one, two,
few, other фактически сводятся к различению
суффиксовone,
few, many, other, но для
порядковых форм поведение отличается от количественныхОсновной инструмент для определения порядковой формы:
const rules = new Intl.PluralRules('en-US', { type: 'ordinal' });
rules.select(1); // "one"
rules.select(2); // "two"
rules.select(3); // "few"
rules.select(4); // "other"
Фактическая интерпретация значений зависит от локали. В английском языке эти категории затем сопоставляются с суффиксами:
function getOrdinalSuffix(n) {
const pr = new Intl.PluralRules('en-US', { type: 'ordinal' });
const category = pr.select(n);
const suffixes = {
one: 'st',
two: 'nd',
few: 'rd',
other: 'th'
};
return `${n}${suffixes[category]}`;
}
getOrdinalSuffix(1); // "1st"
getOrdinalSuffix(2); // "2nd"
getOrdinalSuffix(3); // "3rd"
getOrdinalSuffix(4); // "4th"
Английская система порядковых числительных содержит исключения:
Они не подчиняются стандартным правилам 1 → st,
2 → nd, 3 → rd. Поэтому корректная реализация
должна учитывать диапазон 10–20:
function getEnglishOrdinal(n) {
const mod100 = n % 100;
if (mod100 >= 11 && mod100 <= 13) {
return `${n}th`;
}
const mod10 = n % 10;
switch (mod10) {
case 1:
return `${n}st`;
case 2:
return `${n}nd`;
case 3:
return `${n}rd`;
default:
return `${n}th`;
}
}
Intl.PluralRules сам по себе не формирует строку, но
позволяет отделить логику определения категории от логики
форматирования.
Современный подход в браузерах включает использование
Intl.NumberFormat с параметром
style: 'ordinal'.
const formatter = new Intl.NumberFormat('en-US', {
style: 'ordinal'
});
formatter.format(1); // "1st"
formatter.format(2); // "2nd"
formatter.format(3); // "3rd"
formatter.format(4); // "4th"
Этот способ скрывает внутреннюю логику определения суффиксов и полностью делегирует её движку интернационализации.
Для en-US и en-GB поведение предсказуемо и
основано на суффиксах:
const f = new Intl.NumberFormat('en-GB', { style: 'ordinal' });
f.format(21); // "21st"
f.format(22); // "22nd"
f.format(23); // "23rd"
f.format(24); // "24th"
В русском языке порядковые числительные зависят от падежа, рода и
числа, поэтому Intl не всегда возвращает буквенную форму
числительного. Часто результат ограничивается числовым представлением
без суффиксов.
const pr = new Intl.PluralRules('ru', { type: 'ordinal' });
pr.select(1); // "one"
pr.select(2); // "few"
pr.select(5); // "many"
Однако стандартная библиотека не предоставляет встроенного форматирования порядковых слов (например, «первый», «второй»), поскольку это требует лексической базы языка.
В Intl.PluralRules существует два типа:
cardinal — количественные числительные (1 яблоко, 2
яблока)ordinal — порядковые (1-й, 2-й, 3-й)Пример сравнения:
const cardinal = new Intl.PluralRules('en-US', { type: 'cardinal' });
const ordinal = new Intl.PluralRules('en-US', { type: 'ordinal' });
cardinal.select(1); // "one"
ordinal.select(1); // "one" (но другая семантика)
Несмотря на совпадение категорий в некоторых локалях, интерпретация различается.
При проектировании системы форматирования чисел используется разделение:
Пример архитектуры:
const rules = new Intl.PluralRules('en-US', { type: 'ordinal' });
const suffixMap = new Map([
['one', 'st'],
['two', 'nd'],
['few', 'rd'],
['other', 'th']
]);
function formatOrdinal(n) {
const category = rules.select(n);
return `${n}${suffixMap.get(category)}`;
}
Такой подход позволяет заменять локаль без изменения бизнес-логики.
Создание экземпляров Intl.PluralRules и
Intl.NumberFormat связано с затратами на инициализацию
локали. В высоконагруженных системах используется кэширование:
const cache = new Map();
function getRules(locale) {
if (!cache.has(locale)) {
cache.set(locale, new Intl.PluralRules(locale, { type: 'ordinal' }));
}
return cache.get(locale);
}
Аналогичный подход применяется к форматтерам чисел.
Несмотря на универсальность, существуют ограничения:
Intl.NumberFormatIntl.PluralRules не возвращает готовую текстовую форму
числительногоПорядковые числительные часто используются вместе с:
Intl.DateTimeFormat (даты: 1st January)Intl.RelativeTimeFormat (1st day ago)Intl.ListFormat (списки элементов с порядком)Пример интеграции:
const ordinal = new Intl.NumberFormat('en-US', { style: 'ordinal' });
const day = ordinal.format(1);
const month = new Intl.DateTimeFormat('en-US', { month: 'long' }).format(new Date());
`${day} ${month}`; // "1st May"
В интерфейсах порядковые числительные часто используются для:
При этом предпочтительно отделять форматирование от бизнес-логики, чтобы UI мог переключать локали без переработки данных.
function formatStep(n, locale) {
const formatter = new Intl.NumberFormat(locale, { style: 'ordinal' });
return `Step ${formatter.format(n)}`;
}
Разные среды исполнения могут по-разному поддерживать
style: 'ordinal':
Поэтому часто используется резервный механизм через
Intl.PluralRules.
Архитектурно процесс можно описать как цепочку:
Intl.PluralRules)Такая модель позволяет масштабировать интернационализацию на десятки языков без изменения основной логики приложения.