Множественное число и select нужны в случаях, когда одной исходной строки недостаточно — перевод зависит от числа или категории. @lingo.dev/react предоставляет два удобных хелпера — l.plural и l.select. Внутри они компилируются в ICU MessageFormat, поэтому переводчики работают со стандартным синтаксисом, а runtime остаётся прежним.
Множественное число#
l.plural(count, forms, { context }) выбирает нужную форму на основе count и правил множественного числа CLDR для текущей локали.
const l = useLingo();
l.plural(items.length, {
one: "1 item",
other: "{count} items",
}, { context: "Cart summary" });
// → "1 item" (en, count=1) / "5 items" (en, count=5)
// → "1 Eintrag" / "5 Einträge" (de, after translation)Формы в разных локалях#
Объект форм поддерживает все категории множественного числа из CLDR — zero, one, two, few, many, other. Каждая локаль использует только нужные ей категории:
- В английском используются
oneиother(1 и всё остальное) - В русском используются
one,few,manyиother(1; 2-4; 5-20; 21, 31, ...) - В арабском используются все шесть
- В японском используется только
other(без различения форм множественного числа)
Достаточно указать только те формы, которые использует исходная локаль, — переводчики добавят остальные под целевую локаль.
{count} автоматически подставляется в любую форму множественного числа. Передавать его через values не нужно — оно берётся из первого аргумента.
Как сочетать с другими плейсхолдерами#
Если в предложении есть и количество, и другие переменные, просто добавьте переменные в строки форм — они будут переданы в ICU.
l.plural(notifications.length, {
one: "1 message from {sender}",
other: "{count} messages from {sender}",
}, { context: "Inbox header" });Дальше передайте значения при вызове — но есть нюанс: у l.plural в сигнатуре только { context }. Для смешанных случаев используйте l.text напрямую с ICU-синтаксисом множественного числа:
l.text(`{count, plural, one {1 message from {sender}} other {# messages from {sender}}}`, {
values: { count: notifications.length, sender: user.name },
context: "Inbox header",
});Токен # заменяется значением количества как есть — это удобно, если оно нужно без интерполяции в фигурных скобках.
Select#
l.select(value, forms, { context }) выбирает форму по строковому ключу — например, по роду, роли или типу контента.
l.select(user.gender, {
male: "He uploaded a photo",
female: "She uploaded a photo",
other: "They uploaded a photo",
}, { context: "Activity feed" });other обязателен как запасной вариант. Совпадение должно быть точным — без неточного поиска и без игнорирования регистра.
Selectordinal#
Для порядковых числительных (1st, 2nd, 3rd) используйте ICU selectordinal напрямую через l.text:
l.text(`You finished in {place, selectordinal, one {#st} two {#nd} few {#rd} other {#th}} place`, {
values: { place: rank },
context: "Leaderboard",
});
// → "You finished in 1st place" / "2nd" / "3rd" / "4th, 5th, ..."Во что это компилируется#
И l.plural, и l.select собирают строку в формате ICU MessageFormat и передают её в l.text. Именно эта скомпилированная форма извлекается через lingo extract и сохраняется в файлы локали — переводчики редактируют напрямую ICU-синтаксис, а не объектный литерал JS.
Например, l.plural(n, { one: "1 item", other: "{count} items" }, { context: "Cart" }) извлекается так:
{count, plural, one {1 item} other {{count} items}}Это значит, что переводчики могут адаптировать категории под каждую локаль, включая те, которых нет в исходном тексте. Например, для русского получится {count, plural, one {...} few {...} many {...} other {...}} — и без каких-либо изменений в коде.
Когда это не нужно#
- Простая булева логика "1 или много". Два вызова
l.textвнутриifвполне подойдут, и переводчикам их проще заметить. - Программный enum, который не видит пользователь. Plural / select нужны для перевода категориальных сообщений, а не для маршрутизации логики приложения.
Что дальше#
- useLingo — базовая семантика
l.textиl.rich. - Formatting — форматирование чисел, валют, дат и списков через нативный Intl.
