Порядковые числа

Порядковые числа в интернационализации отличаются от количественных тем, что отражают позицию элемента в последовательности: первый, второй, третий и так далее. В разных языках правила формирования порядковых числительных значительно различаются, и простое добавление суффиксов наподобие “st”, “nd”, “rd”, “th” (как в английском) не является универсальным решением.

В Globalize работа с порядковыми числительными опирается на данные CLDR (Unicode Common Locale Data Repository), где для каждой локали определены правила формирования ординалов и соответствующие языковые формы.


Локализационная модель порядковых чисел

В основе механизма лежит концепция ordinal rules — набора правил, которые определяют форму порядкового числительного в зависимости от значения числа и языка.

Ключевой принцип:

  • число не форматируется «по шаблону»
  • выбирается категория ординала (например: one, two, few, other)
  • затем применяется локализованная форма

В CLDR для каждой локали описано:

  • какие категории ординалов существуют
  • какие числа относятся к каждой категории
  • как должна выглядеть текстовая форма

Например:

  • английский: 1st, 2nd, 3rd, 4th…
  • французский: 1er, 2e, 3e…
  • русский: формально ординалы совпадают с прилагательными (1-й, 2-й, 3-й), но используются разные грамматические формы в зависимости от контекста

Подготовка Globalize к работе с ординалами

Globalize не содержит языковых данных внутри ядра. Все локализационные данные подключаются отдельно через CLDR JSON.

Минимальная подготовка включает:

  • подключение CLDR данных
  • загрузку нужной локали
  • инициализацию Globalize
Globalize.load(
  require("cldr-data").all()
);

Globalize.loadMessages(
  require("./messages/ru")
);

Globalize.locale("ru");

Важно учитывать: для корректной работы порядковых числительных должны быть загружены данные numbers/ordinals для конкретной локали.


Формирование порядковых чисел

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

Общий подход выглядит так:

  1. передаётся число
  2. определяется ordinal category
  3. выбирается строка шаблона для локали
  4. возвращается локализованное представление

Использование ординалов через CLDR rules

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

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

const globalize = new Globalize("en");

const ordinal = globalize.ordinal(1);

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


Форматирование порядковых чисел через messages

Практический способ работы с порядковыми числами в Globalize — использование сообщений с plural/ordinal rules.

Пример сообщений

{
  "rank": "{count, ordinal, one {#st} two {#nd} few {#rd} other {#th}}"
}

Использование

const globalize = new Globalize("en");

const formatRank = globalize.messageFormatter("rank");

formatRank({ count: 1 }); // 1st
formatRank({ count: 2 }); // 2nd
formatRank({ count: 3 }); // 3rd
formatRank({ count: 4 }); // 4th

Система автоматически выбирает нужную форму на основе правил CLDR.


Отличие ordinal от plural

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

Тип Назначение Пример
plural количество объектов 1 apple, 2 apples
ordinal позиция 1st place, 2nd place

В Globalize это два разных механизма:

  • plural rules используются для количеств
  • ordinal rules используются для рангов и позиций

Локализация на примере разных языков

Английский

{ "place": "{count, ordinal, one {#st} two {#nd} few {#rd} other {#th}}" }

Результаты:

  • 1 → 1st
  • 2 → 2nd
  • 3 → 3rd
  • 11 → 11th

Французский

{ "place": "{count, ordinal, other {#e}}" }

Результаты:

  • 1 → 1er (в зависимости от расширенных правил может быть обработано отдельно)
  • 2 → 2e

Русский

{ "place": "{count, ordinal, other {#-й}}" }

Результаты:

  • 1 → 1-й
  • 2 → 2-й
  • 3 → 3-й

Внутренние правила CLDR ordinal

CLDR определяет категории:

  • one
  • two
  • few
  • many
  • other

Каждая локаль может использовать часть этих категорий или все сразу.

Например:

  • английский: one, two, few, other (упрощённо)
  • русская локаль: one, few, many, other

Globalize использует эти категории как основу для выбора формы.


Сложные случаи: зависимость от диапазонов

В некоторых языках ординалы зависят не только от последней цифры, но и от диапазонов значений.

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

  • 1, 21, 31 → one
  • 2, 22, 32 → two
  • 11–13 → other (исключение)

Globalize не требует ручного кодирования этих правил — они уже описаны в CLDR и применяются автоматически при выборе формы.


Интеграция с форматированием интерфейсов

Порядковые числа часто используются в интерфейсах:

  • рейтинги
  • позиции в списке
  • шаги в инструкциях
  • спортивные результаты

Пример:

const stepMessage = globalize.messageFormatter("step");

stepMessage({ count: 1 }); // 1st step
stepMessage({ count: 2 }); // 2nd step

Комбинирование ординалов с датами и другими форматами

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

const dateFormatter = globalize.dateFormatter({ datetime: "medium" });
const rankFormatter = globalize.messageFormatter("rank");

const date = dateFormatter(new Date());
const rank = rankFormatter({ count: 1 });

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


Производительность и кеширование

Форматирование ординалов в Globalize зависит от:

  • загрузки CLDR данных
  • компиляции messageFormatter
  • кэширования функций форматирования

Рекомендуется:

  • создавать форматтеры один раз
  • переиспользовать их
  • избегать повторного создания в циклах
const rankFormatter = globalize.messageFormatter("rank");

// использовать многократно
for (let i = 1; i <= 10; i++) {
  console.log(rankFormatter({ count: i }));
}

Типичные ошибки при работе с порядковыми числами

  • отсутствие загрузки ordinal data из CLDR
  • использование plural правил вместо ordinal
  • ручное добавление суффиксов без учета локали
  • отсутствие тестирования на языках с несколькими категориями (например, русский)

Расширяемость через пользовательские шаблоны

Globalize позволяет определять собственные правила отображения:

{
  "level": "{count, ordinal, one {уровень #} other {уровень #}}"
}

Это особенно полезно, когда ординалы используются не как грамматическая конструкция, а как часть UI-логики (например, уровни доступа или прогресс).