Механизм формирования множественного числа в разных языках не является универсальным: он зависит от грамматики конкретной локали. В одних языках существует только две формы (единственное и множественное число), в других — три и более, а в некоторых языках выбор формы определяется не только количеством, но и контекстом. Библиотека Globalize учитывает эти различия и предоставляет доступ к правилам pluralization через CLDR (Unicode Common Locale Data Repository).
Globalize опирается на стандартизированные категории множественного числа, определённые CLDR. Каждая локаль содержит набор правил, которые сопоставляют числовое значение с одной из категорий.
Основные категории:
Важно, что не каждая локаль использует все категории. Например, в
английском языке применяются только one и
other, тогда как в славянских языках набор категорий
значительно шире.
В Globalize правила множественного числа доступны через загрузку соответствующих CLDR-данных и использование метода:
Globalize.pluralGenerator(locale)
Метод возвращает функцию, которая принимает числовое значение и возвращает категорию множественного числа для заданной локали.
Пример:
const Globalize = require("globalize");
Globalize.load(
require("cldr-data/supplemental/likelySubtags"),
require("cldr-data/supplemental/plurals"),
require("cldr-data/main/en/numbers")
);
const en = new Globalize("en");
const plural = en.pluralGenerator();
plural(1); // "one"
plural(2); // "other"
plural(0); // "other"
Функция не выполняет форматирование текста — она только определяет категорию.
Разные локали используют разные логические выражения для определения категорий.
В английском языке правило максимально простое:
one — только для значения 1other — для всех остальных значенийplural(1); // "one"
plural(5); // "other"
Русский язык использует три основные формы: one,
few, many.
Правила зависят от последних цифр числа:
one — 1, 21, 31, 41…few — 2-4, 22-24…many — 0, 5-20, 25-30…Пример:
const ru = new Globalize("ru");
const pluralRu = ru.pluralGenerator();
pluralRu(1); // "one"
pluralRu(2); // "few"
pluralRu(5); // "many"
pluralRu(21); // "one"
Эти правила полностью определяются CLDR и не задаются вручную в коде.
Основная задача правил множественного числа — выбор корректной строки при выводе сообщений.
Globalize использует совместно с ICU MessageFormat:
const message = new Globalize("en").messageFormatter(
"{count, plural, one {# file} other {# files}}"
);
message({ count: 1 }); // "1 file"
message({ count: 5 }); // "5 files"
Здесь plural автоматически вызывает внутренний механизм
определения категории.
Символ # внутри шаблона заменяется на числовое значение,
переданное в сообщение.
"{count, plural, one {# item} other {# items}}"
Результат:
count = 1 → 1 itemcount = 3 → 3 itemsPlural-правила могут комбинироваться с другими конструкциями ICU:
"{count, plural,
one {# file}
few {# files (few)}
other {# files}
}"
"{count, plural,
one {# file in # folder}
other {# files in # folders}
}"
Каждая переменная обрабатывается независимо, но выбор формы
определяется только значением, привязанным к plural.
CLDR определяет правила через математические выражения, которые учитывают:
Пример логики для некоторых языков:
n % 10 == 1 → onen % 10 in 2..4 → fewn % 100 in 11..14 → manyGlobalize не хранит эти правила в коде, а использует данные CLDR, что позволяет поддерживать десятки языков без изменения реализации.
Некоторые языки учитывают дробные значения отдельно от целых.
plural(1.0); // может быть "one"
plural(1.5); // обычно "other"
CLDR определяет, как именно трактовать дроби в каждой локали.
Создание генератора множественного числа — относительно дорогая операция, поскольку требуется обработка CLDR-данных.
Рекомендуется создавать его один раз на локаль:
const pluralEn = new Globalize("en").pluralGenerator();
const pluralRu = new Globalize("ru").pluralGenerator();
Повторное использование одной функции предпочтительнее повторного вызова конструктора.
При работе с большими интерфейсами, где множество строк зависит от чисел, plural-логика становится центральным элементом интернационализации.
Типичная схема:
const g = new Globalize(userLocale);
const plural = g.pluralGenerator();
const format = g.messageFormatter(MESSAGE);
Plural-правила не зависят от форматирования чисел, но часто используются совместно с:
numberFormattercurrencyFormatterunitFormatterПример:
const number = new Globalize("en").numberFormatter();
const msg = new Globalize("en").messageFormatter(
"{count, plural, one {# file} other {# files}}"
);
msg({ count: number(1200) });
Важно понимать, что plural работает с сырым числовым значением, а не с отформатированной строкой.
Наиболее распространённые ошибки:
// неправильно
msg({ count: "1,200" });
// нежелательно
if (n === 1) { ... }
Такая логика ломает поддержку локалей с более сложными правилами.
Некоторые разработчики предполагают только one и
other, что приводит к некорректным формулировкам в языках
со сложной морфологией.
Если локаль не содержит явного правила для категории, используется
other.
"{count, plural, one {# file} other {# files}}"
В языках без категории few или many всё
равно будет работать корректно через other.
При смене языка необходимо пересоздавать Globalize-инстанс, так как pluralGenerator привязан к конкретной локали:
const g = new Globalize("en");
const pluralEn = g.pluralGenerator();
const gRu = new Globalize("ru");
const pluralRu = gRu.pluralGenerator();
Переключение локали требует пересборки всех зависимых форматтеров.
Правила множественного числа являются базовым уровнем интернационализации, поскольку:
Globalize обеспечивает единый доступ к этим правилам через стандартизированные CLDR-данные, исключая необходимость ручной поддержки языковых особенностей.