Intl.PluralRules полифилл

Назначение Intl.PluralRules в JavaScript

Intl.PluralRules — это часть стандарта ECMAScript Internationalization API, предназначенная для определения формы множественного числа в зависимости от языка и числа. Основная задача API — корректный выбор грамматической формы (например, «1 товар», «2 товара», «5 товаров») с учётом правил конкретной локали.

Ключевая проблема, которую решает Intl.PluralRules, заключается в том, что правила множественного числа в разных языках существенно различаются. Например:

  • В английском языке обычно 2 формы: singular и plural
  • В русском языке используется 3–4 формы в зависимости от числа
  • В некоторых языках (арабский, словенский) форм может быть ещё больше

Intl.PluralRules абстрагирует эти правила, предоставляя унифицированный API.


Базовый API Intl.PluralRules

Создание экземпляра происходит с указанием локали:

const rules = new Intl.PluralRules('ru-RU');

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

Метод select() возвращает категорию множественного числа:

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

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


Пример использования в реальной интерполяции

const ruRules = new Intl.PluralRules('ru-RU');

function formatCount(count) {
  const rule = ruRules.select(count);

  const forms = {
    one: 'товар',
    few: 'товара',
    many: 'товаров',
    other: 'товара'
  };

  return `${count} ${forms[rule]}`;
}

formatCount(1); // 1 товар
formatCount(3); // 3 товара
formatCount(10); // 10 товаров

Такой подход уже позволяет реализовать базовую локализацию без сторонних библиотек, но становится сложным при масштабировании.


Ограничения нативной реализации

Несмотря на стандартизацию, Intl.PluralRules имеет ряд ограничений:

  • Отсутствует встроенная интеграция с форматированием сообщений
  • Нет поддержки сложных шаблонов интерполяции
  • Не решает проблему ICU MessageFormat
  • В старых браузерах API может отсутствовать или быть неполным

Именно здесь появляется необходимость в полифилле.


Полифилл Intl.PluralRules в FormatJS

Экосистема FormatJS предоставляет полноценный полифилл Intl.PluralRules, обеспечивающий:

  • поддержку старых браузеров
  • полное соответствие ICU стандартам
  • корректные данные CLDR
  • стабильное поведение across environments (Node.js, браузеры)

Установка полифилла

Основной пакет:

npm install @formatjs/intl-pluralrules

Подключение полифилла

Для глобального расширения Intl:

import '@formatjs/intl-pluralrules/polyfill';

После подключения объект Intl.PluralRules становится доступным даже в средах, где он отсутствует.


Подключение локалей

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

import '@formatjs/intl-pluralrules/locale-data/en';
import '@formatjs/intl-pluralrules/locale-data/ru';
import '@formatjs/intl-pluralrules/locale-data/de';

Это позволяет контролировать размер приложения.


Использование после подключения

После полифилла API остаётся полностью идентичным стандартному:

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

console.log(rules.select(1)); // one
console.log(rules.select(2)); // few
console.log(rules.select(5)); // many

Разница заключается в том, что теперь поведение гарантировано даже в средах без нативной поддержки.


Архитектура полифилла

Полифилл состоит из нескольких уровней:

1. Core-реализация

Базовый слой реализует:

  • разбор локалей
  • загрузку CLDR данных
  • алгоритмы выбора plural category

2. CLDR data layer

Используются данные Unicode CLDR:

  • правила для каждой локали
  • диапазоны чисел
  • исключения

Это позволяет добиться поведения, идентичного нативной реализации современных браузеров.


3. API shim

Shim-слой подменяет глобальный Intl.PluralRules:

if (!global.Intl.PluralRules) {
  global.Intl.PluralRules = PolyfilledPluralRules;
}

Поддержка локалей и tree-shaking

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

Пример оптимальной сборки

import '@formatjs/intl-pluralrules/polyfill';
import '@formatjs/intl-pluralrules/locale-data/ru';

Такой подход:

  • уменьшает bundle size
  • ускоряет загрузку
  • позволяет контролировать i18n зависимости

Использование с форматированием сообщений

Хотя Intl.PluralRules работает отдельно, в реальных приложениях он часто используется вместе с ICU MessageFormat.

Пример:

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

const messages = {
  one: '{count} файл',
  few: '{count} файла',
  many: '{count} файлов'
};

function format(count) {
  return messages[rules.select(count)].replace('{count}', count);
}

Интеграция в серверный рендеринг (SSR)

В Node.js важно обеспечить одинаковое поведение на сервере и клиенте.

Полифилл позволяет:

  • унифицировать вывод
  • избежать hydration mismatch
  • гарантировать одинаковые plural rules

Пример SSR:

import '@formatjs/intl-pluralrules/polyfill';
import '@formatjs/intl-pluralrules/locale-data/ru';

export function render(count) {
  const rules = new Intl.PluralRules('ru');
  return rules.select(count);
}

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

Полифилл оптимизирован для:

  • ленивой загрузки локалей
  • минимального runtime overhead
  • кеширования экземпляров правил

Однако следует учитывать:

  • загрузка всех локалей увеличивает размер бандла
  • частое создание экземпляров PluralRules может быть дороже кешированного варианта

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

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

вместо создания на каждый вызов.


Сравнение с нативной реализацией

Характеристика Нативный Intl FormatJS polyfill
Поддержка старых браузеров Нет Да
Полнота локалей Зависит от браузера Полная CLDR база
Поведение Может отличаться Стандартизировано
Tree-shaking локалей Нет Да

Типичные ошибки при использовании

1. Игнорирование локали

new Intl.PluralRules(); // поведение зависит от окружения

Корректно:

new Intl.PluralRules('ru');

2. Неправильное сопоставление категорий

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

Ошибка: в русском языке недостаточно двух форм.


3. Создание экземпляра внутри функции

function format(n) {
  return new Intl.PluralRules('ru').select(n);
}

Это ухудшает производительность.


Использование в больших приложениях

В масштабных системах локализации Intl.PluralRules часто является базовым строительным блоком:

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

В экосистеме FormatJS он используется совместно с:

  • react-intl
  • intl-messageformat
  • @formatjs/intl polyfills

Поведение в разных языках

Пример различий:

Английский

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

Русский

new Intl.PluralRules('ru').select(1); // one
new Intl.PluralRules('ru').select(2); // few
new Intl.PluralRules('ru').select(5); // many

Арабский

new Intl.PluralRules('ar').select(0); // zero
new Intl.PluralRules('ar').select(2); // two
new Intl.PluralRules('ar').select(3); // few

Эти различия невозможно корректно реализовать вручную без CLDR-таблиц.


Роль в архитектуре i18n

Intl.PluralRules можно рассматривать как:

  • низкоуровневый слой определения грамматики
  • основу для message formatting
  • связующее звено между числом и локализованной строкой

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