Select для гендерных форм

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

Основная область применения — языковая адаптация сообщений, где текст должен изменяться в зависимости от пола субъекта, к которому относится сообщение, или от грамматической категории, связанной с этим субъектом.


Базовый синтаксис select

Формат select в ICU MessageFormat имеет следующую структуру:

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

Где:

  • variable — значение, передаваемое в сообщение
  • key1, key2 — возможные варианты
  • other — обязательный fallback-вариант

Гендерные формы как частный случай select

Наиболее распространённый сценарий использования select — работа с гендерными формами. В языках с грамматическим родом (например, русском) текст сообщения должен изменяться в зависимости от пола субъекта.

Типичная модель значений:

  • male — мужской род
  • female — женский род
  • other — неопределённый или небинарный вариант

Базовый пример

import { IntlMessageFormat } from 'intl-messageformat';

const message = new IntlMessageFormat(
  '{gender, select, male {Он вошёл в систему} female {Она вошла в систему} other {Пользователь вошёл в систему}}',
  'ru'
);

message.format({ gender: 'male' });

Результат:

Он вошёл в систему

Интеграция FormatJS в JavaScript-окружении

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

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

Это критически важно для устойчивости системы локализации, так как входные данные не всегда контролируются на уровне UI.

Пример:

'{gender, select, male {...} female {...} other {...}}'

Если передано значение:

gender: 'nonbinary'

будет использован блок other.


Использование переменных внутри sel ect-блоков

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

const msg = new IntlMessageFormat(
  '{gender, select, male {Пользователь {name} создал документ} female {Пользовательница {name} создала документ} other {Пользователь {name} создал документ}}',
  'ru'
);

msg.format({ gender: 'female', name: 'Анна' });

Результат:

Пользовательница Анна создала документ

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

ICU MessageFormat допускает вложенность конструкций, что позволяет комбинировать разные типы условий.

Пример вложенного select

'{gender, select,
  male {
    {status, select,
      admin {Администратор вошёл}
      user {Пользователь вошёл}
      other {Гость вошёл}
    }
  }
  female {
    {status, select,
      admin {Администратор вошла}
      user {Пользовательница вошла}
      other {Гостья вошла}
    }
  }
  other {Система зафиксировала вход}
}'

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


Отличие select от plural

Несмотря на схожий синтаксис, select и plural решают разные задачи:

  • select работает с категориями (gender, role, type)
  • plural работает с числами и языковыми правилами множественности

Пример plural:

{count, plural, one {1 файл} few {# файла} many {# файлов}}

Пример select:

{gender, select, male {Он} female {Она} other {Они}}

Гендерная нейтральность и расширение категорий

В реальных приложениях категория gender не обязана ограничиваться тремя значениями. Возможны расширенные модели:

  • male
  • female
  • nonbinary
  • unknown
  • other

Пример:

'{gender, select,
  male {Он отправил сообщение}
  female {Она отправила сообщение}
  nonbinary {Они отправили сообщение}
  other {Пользователь отправил сообщение}
}'

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


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

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' }
);

Сложные комбинации select и других типов форматирования

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 в архитектуре локализации

Механизм select выступает фундаментальным инструментом для отделения бизнес-логики от языковой логики. Вместо условий в коде:

if (gender === 'male') ...
else if (gender === 'female') ...

логика переносится в слой сообщений:

{gender, select, male {...} female {...} other {...}}

Это обеспечивает:

  • единый источник истины для текстов
  • независимость UI от языковых правил
  • возможность изменения форм без изменения кода приложения