Механизм select в FormatJS основан на синтаксисе ICU
MessageFormat и предназначен для выбора строковых вариантов в
зависимости от дискретных значений параметра. В отличие от
plural, который ориентирован на числовые правила
множественности, select работает с произвольными
категориальными значениями, включая гендерные формы, статусы, типы
пользователей, роли и любые другие фиксированные наборы вариантов.
Основная область применения — языковая адаптация сообщений, где текст должен изменяться в зависимости от пола субъекта, к которому относится сообщение, или от грамматической категории, связанной с этим субъектом.
Формат select в ICU MessageFormat имеет следующую
структуру:
{variable, select,
key1 {значение 1}
key2 {значение 2}
other {значение по умолчанию}
}
Где:
variable — значение, передаваемое в сообщениеkey1, key2 — возможные вариантыother — обязательный fallback-вариантНаиболее распространённый сценарий использования select
— работа с гендерными формами. В языках с грамматическим родом
(например, русском) текст сообщения должен изменяться в зависимости от
пола субъекта.
Типичная модель значений:
male — мужской родfemale — женский родother — неопределённый или небинарный вариантimport { IntlMessageFormat } from 'intl-messageformat';
const message = new IntlMessageFormat(
'{gender, select, male {Он вошёл в систему} female {Она вошла в систему} other {Пользователь вошёл в систему}}',
'ru'
);
message.format({ gender: 'male' });
Результат:
Он вошёл в систему
FormatJS реализует ICU MessageFormat через несколько пакетов,
ключевым из которых является intl-messageformat. Он
обеспечивает парсинг строки сообщения и её интерпретацию в зависимости
от переданных параметров.
Пример базовой интеграции:
import { IntlMessageFormat } from 'intl-messageformat';
const msg = new IntlMessageFormat(
'{gender, select, male {Администратор обновил профиль} female {Администратор обновила профиль} other {Профиль обновлён}}',
'ru'
);
console.log(msg.format({ gender: 'female' }));
Ключ other является обязательным элементом конструкции
select. Он выполняет роль универсального обработчика
значений, которые не совпали ни с одним из перечисленных вариантов.
Это критически важно для устойчивости системы локализации, так как входные данные не всегда контролируются на уровне UI.
Пример:
'{gender, select, male {...} female {...} other {...}}'
Если передано значение:
gender: 'nonbinary'
будет использован блок other.
Внутри каждого варианта допускается использование интерполяции переменных. Это позволяет строить динамические сообщения.
const msg = new IntlMessageFormat(
'{gender, select, male {Пользователь {name} создал документ} female {Пользовательница {name} создала документ} other {Пользователь {name} создал документ}}',
'ru'
);
msg.format({ gender: 'female', name: 'Анна' });
Результат:
Пользовательница Анна создала документ
ICU MessageFormat допускает вложенность конструкций, что позволяет комбинировать разные типы условий.
'{gender, select,
male {
{status, select,
admin {Администратор вошёл}
user {Пользователь вошёл}
other {Гость вошёл}
}
}
female {
{status, select,
admin {Администратор вошла}
user {Пользовательница вошла}
other {Гостья вошла}
}
}
other {Система зафиксировала вход}
}'
Такая структура позволяет описывать сложные грамматические зависимости, сохраняя централизованную локализацию.
Несмотря на схожий синтаксис, select и
plural решают разные задачи:
select работает с категориями (gender, role, type)plural работает с числами и языковыми правилами
множественностиПример plural:
{count, plural, one {1 файл} few {# файла} many {# файлов}}
Пример select:
{gender, select, male {Он} female {Она} other {Они}}
В реальных приложениях категория gender не обязана
ограничиваться тремя значениями. Возможны расширенные модели:
malefemalenonbinaryunknownotherПример:
'{gender, select,
male {Он отправил сообщение}
female {Она отправила сообщение}
nonbinary {Они отправили сообщение}
other {Пользователь отправил сообщение}
}'
Такой подход позволяет избежать потери смысла при интернационализации и поддержке различных культурных контекстов.
FormatJS часто применяется в связке с React через
react-intl.
Пример:
import { FormattedMessage } fr om 'react-intl';
function UserStatus({ gender, name }) {
return (
<FormattedMessage
id="user.status"
values={{ gender, name }}
defaultMessage="{gender, select, male {Пользователь {name} активен} female {Пользовательница {name} активна} other {Пользователь {name} активен}}"
/>
);
}
В этом случае система автоматически выбирает нужную форму при каждом рендере компонента.
В FormatJS логика выбора форм может быть централизована в JSON-файлах локализации.
Пример структуры:
{
"user.status": "{gender, select, male {Он вошёл} female {Она вошла} other {Пользователь вошёл}}"
}
И использование:
intl.formatMessage(
{ id: 'user.status' },
{ gender: 'male' }
);
FormatJS позволяет комбинировать select с
форматированием дат, чисел и plural.
Пример:
{gender, select,
male {Он получил {count, plural, one {# уведомление} other {# уведомлений}}}
female {Она получила {count, plural, one {# уведомление} other {# уведомлений}}}
other {Пользователь получил {count, plural, one {# уведомление} other {# уведомлений}}}
}
Такая композиция позволяет строить полноценные языковые модели без дублирования логики в коде приложения.
При использовании select важно учитывать несколько
особенностей:
Male и male —
разные ключи)other приводит к ошибке парсинга или
некорректному поведениюПри интеграции в TypeScript-проекты часто вводится ограничение типов
для значений select.
Пример:
type Gender = 'male' | 'female' | 'other';
Это позволяет минимизировать ошибки несоответствия ключей и повышает стабильность локализационных сообщений.
Механизм select выступает фундаментальным инструментом
для отделения бизнес-логики от языковой логики. Вместо условий в
коде:
if (gender === 'male') ...
else if (gender === 'female') ...
логика переносится в слой сообщений:
{gender, select, male {...} female {...} other {...}}
Это обеспечивает: