Механизм плюрализации в FormatJS основан на стандарте ICU MessageFormat и опирается на данные CLDR (Unicode Common Locale Data Repository), что обеспечивает корректное отображение форм множественного числа в зависимости от локали и числовых правил языка. В отличие от простых условных конструкций, здесь учитываются языковые категории, а не только арифметическая логика.
Формат сообщения строится вокруг конструкции plural, где
ключом выступает числовое значение, а значениями — варианты строк для
различных категорий:
{count, plural,
one {# элемент}
few {# элемента}
many {# элементов}
other {# элементов}
}
Ключевой особенностью является то, что выбор формы определяется не разработчиком вручную, а системой правил языка.
ICU использует набор категорий plural rules, определяемых CLDR:
zeroonetwofewmanyotherНе все языки используют весь набор. Например:
one, otherone, few, many,
otherotherВ русском языке логика распределения чисел следующая:
one → 1, 21, 31, 41…few → 2–4, 22–24, 32–34…many → 0, 5–20, 25–30…other → используется для дробных чисел и исключений
ICUЭта модель исключает необходимость ручного ветвления в коде.
FormatJS позволяет задавать точные числовые совпадения через
=:
{count, plural,
=0 {Нет элементов}
one {# элемент}
few {# элемента}
many {# элементов}
other {# элементов}
}
Правило =0 имеет более высокий приоритет, чем языковые
категории. Это позволяет переопределять стандартную логику ICU для
конкретных значений.
Такая конструкция часто используется для улучшения UX при нулевых значениях, когда языковая форма становится вторичной по сравнению с семантикой сообщения.
Сложные сценарии возникают при комбинировании plural с
select. Это необходимо, когда грамматическая форма зависит
не только от числа, но и от дополнительных параметров, например пола или
типа объекта.
{gender, select,
male {{count, plural, one {Он добавил # элемент} other {Он добавил # элементов}}}
female {{count, plural, one {Она добавила # элемент} other {Она добавила # элементов}}}
other {{count, plural, one {Добавлено # элемент} other {Добавлено # элементов}}}
}
Такая структура демонстрирует каскадную зависимость:
Глубина вложенности может увеличиваться, однако рост сложности резко ухудшает читаемость и усложняет поддержку.
Отдельная форма selectordinal используется для
порядковых чисел:
{place, selectordinal,
one {#-й}
two {#-й}
few {#-й}
other {#-й}
}
В английском языке различие выглядит так:
FormatJS автоматически применяет соответствующие правила CLDR, исключая ручную обработку суффиксов.
Особое поведение наблюдается при работе с дробями:
{count, plural,
one {# элемент}
other {# элементов}
}
Числа вроде 1.5, 2.3, 0.7 практически всегда попадают в категорию
other, даже в языках с развитой системой множественных
форм.
Это связано с тем, что plural rules CLDR разделяют целые и нецелые числа.
Одной из частых проблем является отсутствие необходимых категорий:
{count, plural,
one {# элемент}
}
При передаче значения, не соответствующего one, система
автоматически использует other. Если other не
определён, возникает ошибка форматирования или пустой вывод.
Корректная реализация всегда должна включать минимум
other, даже если кажется, что он не используется.
Plural-конструкции часто содержат интерполяцию переменных:
{count, plural,
one {Найден # результат по запросу "{query}"}
other {Найдено # результатов по запросу "{query}"}
}
Здесь одновременно работают:
#{query}Важно учитывать, что # автоматически заменяется на
значение count, а не на произвольную переменную.
FormatJS поддерживает использование других форматтеров внутри plural-веток:
{count, plural,
one {# элемент, обновлённый {updatedAt, date, short}}
other {# элементов, обновлённых {updatedAt, date, short}}
}
Это позволяет создавать сообщения, в которых числовая грамматика и форматирование даты работают совместно.
Некоторые языки имеют нетривиальные правила, например:
two, few,
otherFormatJS не реализует эти правила вручную, а полностью полагается на CLDR, что делает поведение предсказуемым при смене локали.
При вычислении формы используется следующая логика:
=n)otherЕсли несколько веток теоретически подходят, всегда выбирается наиболее специфичная.
Внутри реализации FormatJS применяется Intl.PluralRules,
который предоставляет API уровня ECMAScript:
const rules = new Intl.PluralRules('ru-RU');
rules.select(5); // "many"
FormatJS расширяет эту логику, добавляя ICU MessageFormat синтаксис и интеграцию с шаблонами сообщений.
Типовая проблема возникает при передаче строк вместо чисел:
count: "5"
В этом случае поведение зависит от внутреннего преобразования, которое может привести к некорректной категории или fallback-ветке.
Корректная модель данных требует строгого числового типа:
count: 5
В реальных интерфейсах встречаются сообщения с несколькими числовыми параметрами:
{files, plural,
one {# файл в # папке}
other {# файлов в # папках}
}
При этом оба числа могут влиять на грамматику, что приводит к необходимости дублирования plural-конструкций или введения дополнительных переменных.
Некоторые сценарии требуют особого внимания:
other)FormatJS не интерпретирует семантику числа, ограничиваясь грамматическими правилами языка.
При интенсивном использовании plural-конструкций в интерфейсе важную
роль играет кеширование результатов Intl.PluralRules.
FormatJS оптимизирует повторные вычисления, однако сложные вложенные
сообщения могут увеличивать стоимость рендеринга.
Особенно это заметно при: