Выбор по значению через select

Механизм select в FormatJS основан на ICU MessageFormat и предназначен для выбора текстового варианта в зависимости от конкретного значения переменной. В отличие от plural, который ориентирован на числовые формы, select работает с произвольными строковыми ключами и используется для ветвления логики формирования сообщения.

Базовая структура выражения:

{variable, select,
  key1 {вариант 1}
  key2 {вариант 2}
  other {значение по умолчанию}
}

Ключевой элемент — сопоставление значения переменной с заранее определёнными ветками. Если совпадение не найдено, используется other.


Синтаксис select в FormatJS

В экосистеме FormatJS select применяется внутри сообщений react-intl или напрямую через API форматирования сообщений.

Пример базового сообщения:

const messages = {
  status: {
    id: 'user.status',
    defaultMessage: '{status, select, active {Активен} inactive {Неактивен} pending {Ожидает} other {Неизвестно}}'
  }
};

Использование:

intl.formatMessage(messages.status, {
  status: 'active'
});

Результат:

Активен

Механизм выполняет строгое сравнение значения status с ключами active, inactive, pending.


Роль fallback-ветки other

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

{role, select,
  admin {Администратор}
  user {Пользователь}
  other {Гость}
}

Если role содержит значение moderator, не предусмотренное в списке, будет выбрана ветка other.

Это предотвращает разрыв UI при изменении данных или расширении бизнес-логики.


Использование select для языковых ролей и статусов

Наиболее частые сценарии применения select связаны с классификацией сущностей:

  • роли пользователей
  • статусы заказов
  • этапы процесса
  • типы интерфейсных режимов

Пример статусов заказа:

const orderMessage = {
  id: 'order.status',
  defaultMessage:
    '{status, select, created {Создан} paid {Оплачен} shipped {Отправлен} delivered {Доставлен} canceled {Отменён} other {Неизвестно}}'
};
intl.formatMessage(orderMessage, { status: 'shipped' });

Вложенные структуры select

FormatJS позволяет комбинировать select с другими ICU-конструкциями, включая plural и интерполяцию переменных.

Пример вложенности:

const message = {
  id: 'notification.message',
  defaultMessage:
    '{gender, select, male {Он получил {count, plural, one {# сообщение} few {# сообщения} other {# сообщений}}} female {Она получила {count, plural, one {# сообщение} few {# сообщения} other {# сообщений}}} other {Пользователь получил {count, plural, one {# сообщение} few {# сообщения} other {# сообщений}}}}'
};

Здесь выполняется двухуровневая логика:

  1. Сначала выбирается форма по gender
  2. Затем внутри ветки применяется plural для count

select в контексте React Intl

В react-intl select используется через компонент FormattedMessage или хук useIntl.

Формат через FormattedMessage

<FormattedMessage
  id="profile.badge"
  defaultMessage="{tier, select, gold {Золотой уровень} silver {Серебряный уровень} bronze {Бронзовый уровень} other {Без уровня}}"
  values={{ tier: userTier }}
/>

Формат через useIntl

const intl = useIntl();

const label = intl.formatMessage(
  {
    id: 'profile.badge',
    defaultMessage:
      '{tier, select, gold {Золото} silver {Серебро} bronze {Бронза} other {Нет}}'
  },
  { tier: userTier }
);

Типизация значений и ограничения select

select не выполняет типизацию значений. Все сравнения происходят как строковые ключи.

Это означает:

  • active и Active считаются разными значениями
  • числа автоматически приводятся к строкам
  • отсутствует неявная нормализация

Пример:

{mode, select,
  1 {Режим 1}
  2 {Режим 2}
  other {Неизвестно}
}

При передаче mode: 1 фактически используется строковое сравнение "1".


Практика: динамические интерфейсные тексты

select широко применяется для интерфейсных сообщений, зависящих от состояния приложения.

Пример состояния загрузки:

const loadingMessage = {
  id: 'app.loading',
  defaultMessage:
    '{state, select, idle {Ожидание} loading {Загрузка...} success {Готово} error {Ошибка} other {Неизвестно}}'
};

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


select и локализация бизнес-логики

Одно из ключевых применений — перенос части ветвлений из кода в слой локализации.

Пример отображения типа подписки:

const subscription = {
  id: 'user.subscription',
  defaultMessage:
    '{plan, select, free {Бесплатный план} pro {Профессиональный план} enterprise {Корпоративный план} other {Неизвестный план}}'
};

Это позволяет:

  • уменьшить количество if/else в UI
  • унифицировать тексты
  • централизовать перевод

Композиция select с несколькими переменными

FormatJS поддерживает использование нескольких переменных внутри одного сообщения, где select управляет только одной из них.

{
  id: 'system.event',
  defaultMessage:
    '{env, select, prod {Продакшн} dev {Разработка} other {Среда}}: {status}'
}

В этом случае env управляет ветвлением, а status подставляется напрямую.


Поведение при отсутствии значения

Если переменная:

  • undefined
  • null
  • отсутствует в values

то механизм переходит к other.

Пример:

{theme, select,
  dark {Тёмная тема}
  light {Светлая тема}
  other {Стандартная тема}
}

При отсутствии theme всегда используется other.


Частые ошибки при использовании select

Одной из распространённых проблем является несоответствие ключей данных и ICU-шаблона:

  • различие регистра (Admin vs admin)
  • пробелы в значениях ("in progress" без кавычек недопустим в ключах)
  • попытка использовать сложные выражения вместо фиксированных ключей

Корректная форма:

{status, select,
  in_progress {В процессе}
  done {Завершено}
  other {Неизвестно}
}

Нельзя использовать:

{status, select,
  in progress {В процессе}
}

без нормализации ключа в in_progress.


Сравнение select и conditional logic в коде

До внедрения ICU-форматов логика часто выглядела так:

let label;

if (role === 'admin') {
  label = 'Администратор';
} else if (role === 'user') {
  label = 'Пользователь';
} else {
  label = 'Гость';
}

С использованием select:

const message = '{role, select, admin {Администратор} user {Пользователь} other {Гость}}';

Это переносит ветвление в декларативную форму, совместимую с системой переводов FormatJS.


Поведение в runtime и оптимизация

FormatJS компилирует ICU-строки в эффективные функции форматирования. select обрабатывается как hash-lookup по ключам, что обеспечивает:

  • стабильную производительность
  • отсутствие глубокой вложенной логики в runtime
  • предсказуемое поведение при локализации

Использование select в масштабируемых системах локализации

В больших приложениях select становится частью стандарта описания UI-состояний:

  • статусные метки
  • типы сущностей
  • режимы отображения
  • флаги функциональности

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