Синтаксис ICU MessageFormat

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

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

Простейший случай — вставка переменной в текст:

"Привет, {name}"

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

В более общем виде:

{variableName}

Переменная может быть числом, строкой, датой или объектом, форматирование которого зависит от контекста ICU.

Типы аргументов

ICU MessageFormat поддерживает явное указание типа аргумента:

  • number
  • date
  • time
  • plural
  • select
  • selectordinal

Пример числового форматирования:

{price, number}

Система локализации автоматически применяет правила форматирования чисел в зависимости от текущей локали: разделители тысяч, десятичные знаки и т.д.

Формат даты:

{createdAt, date}

или с уточнением стиля:

{createdAt, date, long}

Аналогично для времени:

{createdAt, time, short}

Выбор формата через select

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

Общий синтаксис:

{gender, select,
  male {Он вошёл в систему}
  female {Она вошла в систему}
  other {Пользователь вошёл в систему}
}

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

select работает как сопоставление ключ-значение, где ключи — строки без кавычек, а значения — вложенные сообщения.

Работа с множественными формами через plural

Наиболее сложная и важная часть ICU — множественные формы. Конструкция plural учитывает грамматику языка, где форма слова зависит от числа.

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

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

Символ # автоматически заменяется значением переменной count.

ICU использует правила CLDR (Common Locale Data Repository), поэтому категории one, few, many, other зависят от языка.

В английском языке чаще используются:

{count, plural,
  one {# file}
  other {# files}
}

selectordinal: порядковые числительные

Для порядковых форм используется selectordinal, который учитывает не количество объектов, а позицию:

{place, selectordinal,
  one {#-й}
  two {#-й}
  few {#-й}
  other {#-й}
}

Применяется для выражений типа «1-й», «2-й», «3-й» и т.д., где правила также зависят от локали.

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

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

Пример комбинированного использования:

{gender, select,
  male {
    {count, plural,
      one {Он добавил # элемент}
      other {Он добавил # элементов}
    }
  }
  female {
    {count, plural,
      one {Она добавила # элемент}
      other {Она добавила # элементов}
    }
  }
  other {
    {count, plural,
      one {Добавлен # элемент}
      other {Добавлено # элементов}
    }
  }
}

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

Экранирование символов

Фигурные скобки имеют специальное значение, поэтому для вывода литералов используется экранирование через апостроф:

'{name} не будет интерпретировано'

Если необходимо использовать апостроф внутри строки, применяется удвоение:

''text''

Также важно учитывать, что любые служебные символы ICU должны быть либо внутри строковых литералов, либо корректно экранированы.

Форматирование чисел

Тип number поддерживает дополнительные стили:

{value, number, integer}
{value, number, percent}
{value, number, currency}

Каждый стиль влияет на отображение:

  • integer — без дробной части
  • percent — формат процента
  • currency — валютный формат с учётом локали

Пример:

{balance, number, currency}

В зависимости от локали это может отображаться как 1 000,00 ₽, $1,000.00 и т.д.

Обработка дат и времени

ICU использует локализованные стили:

{date, date, short}
{date, date, medium}
{date, date, long}
{date, date, full}

И аналогично для времени:

{time, time, short}

Различия между стилями зависят от региона: порядок дня, месяца, года, использование 12/24-часового формата.

Сложные сообщения и производительность

ICU MessageFormat компилируется в функции форматирования, что позволяет заранее оптимизировать структуру сообщений. FormatJS использует парсер, который преобразует строку в AST (абстрактное синтаксическое дерево), после чего выполняется интерполяция значений.

При большом количестве сообщений рекомендуется:

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

Локализационные правила CLDR

Вся логика plural и selectordinal основана на CLDR-правилах. Это означает, что одинаковая конструкция может вести себя по-разному в разных языках.

Например:

  • в русском языке 4 категории множественного числа
  • в английском — 2
  • в арабском — более 5

ICU автоматически применяет нужную категорию, основываясь на локали, переданной в IntlProvider FormatJS.

Использование вложенных переменных

Переменные могут быть не только примитивами, но и результатами форматирования:

{userCount, number} пользователей онлайн

или внутри других конструкций:

{status, select,
  active {{name} активен}
  inactive {{name} неактивен}
}

Такая гибкость позволяет строить адаптивные интерфейсы без ручной обработки строк.

Особенности синтаксического анализа

ICU MessageFormat строго чувствителен к структуре:

  • каждая открывающая скобка должна иметь закрывающую
  • вложенные конструкции должны быть корректно разделены пробелами
  • ключи select и plural не могут содержать пробелов
  • строки внутри блоков интерпретируются как отдельные подшаблоны

Ошибки в синтаксисе приводят к падению парсинга или возврату исходного ключа сообщения без форматирования.

Комбинирование с форматированием FormatJS

В экосистеме FormatJS ICU используется через react-intl или @formatjs/intl. Сообщения описываются как шаблоны, а затем передаются в компоненты или функции форматирования.

Пример логики:

intl.formatMessage({
  id: 'messages.items',
  defaultMessage: '{count, plural, one {# элемент} other {# элементов}}'
}, { count: 5 })

ICU-строка остаётся независимой от JavaScript-логики, что обеспечивает переносимость и поддержку локалей.

Ограничения синтаксиса

ICU MessageFormat не поддерживает:

  • произвольные JavaScript-выражения внутри шаблонов
  • вычисления и арифметику
  • динамическое изменение структуры сообщения во время парсинга

Все условия должны быть выражены через select, plural или внешнюю логику приложения.