В системе интернационализации Globalize сообщения строятся на основе ICU MessageFormat, что позволяет описывать динамические строки с учётом языка, грамматики и контекста. Ключевая идея заключается в том, что строка перестаёт быть простым шаблоном и превращается в структуру, где каждый параметр имеет тип и правила отображения.
Типизированные сообщения в Globalize позволяют:
Сообщение определяется строкой с плейсхолдерами:
"cart.items": "В корзине {count} товаров"
При этом значение count не просто подставляется как
строка, а проходит через форматирование, соответствующее локали:
const message = Globalize.messageFormatter("cart.items");
message({ count: 5 });
// "В корзине 5 товаров"
Даже в базовом виде параметр считается типизированным значением, так как Globalize определяет его поведение в зависимости от контекста использования.
Одной из ключевых возможностей является работа с множественными
формами. В разных языках правила различаются, и простое добавление
s (как в английском) неприменимо.
ICU-формат позволяет задать поведение для разных количеств:
"cart.items": "{count, plural, one {# товар} few {# товара} many {# товаров} other {# товара}}"
Использование:
const message = Globalize.messageFormatter("cart.items");
message({ count: 1 }); // "1 товар"
message({ count: 3 }); // "3 товара"
message({ count: 10 }); // "10 товаров"
Типизация здесь проявляется в том, что count
интерпретируется как числовое значение, которое сопоставляется с набором
правил языка через CLDR.
Помимо чисел, сообщения могут опираться на категориальные значения: статус, пол, тип объекта, режим работы.
"notification.status":
"{status, select,
success {Операция выполнена успешно}
error {Произошла ошибка}
pending {Ожидание обработки}
other {Неизвестный статус}
}"
Использование:
const message = Globalize.messageFormatter("notification.status");
message({ status: "success" });
// "Операция выполнена успешно"
Здесь параметр status рассматривается как строковый тип
с дискретным набором допустимых значений, сопоставляемых с ветвями
выбора.
Типизированные сообщения поддерживают комбинации plural и select, что позволяет строить сложные языковые конструкции.
"tasks.summary":
"{gender, select,
male {{count, plural, one {Он выполнил # задачу} few {Он выполнил # задачи} many {Он выполнил # задач}}}
female {{count, plural, one {Она выполнила # задачу} few {Она выполнила # задачи} many {Она выполнила # задач}}}
other {{count, plural, one {Выполнено # задание} few {Выполнено # задания} many {Выполнено # заданий}}}
}"
Использование:
const message = Globalize.messageFormatter("tasks.summary");
message({ gender: "female", count: 3 });
// "Она выполнила 3 задачи"
В таких структурах типизация становится иерархической: сначала
определяется категориальный тип (gender), затем числовой
(count), и только после этого выбирается конкретная
строка.
Параметры в сообщениях могут быть не просто вставлены, а отформатированы через встроенные механизмы Globalize.
"price": "Цена: {value, number, currency}"
const message = Globalize.messageFormatter("price");
message({ value: 1234.5 });
// "Цена: 1 234,50 ₸" (в зависимости от локали)
Тип number активирует числовой форматтер с указанным
стилем.
"event.date": "Дата события: {date, date, long}"
const message = Globalize.messageFormatter("event.date");
message({ date: new Date(2026, 4, 28) });
// "Дата события: 28 мая 2026 г."
Здесь параметр date интерпретируется как объект
Date и проходит через локализованный форматтер дат.
ICU-синтаксис требует строгого соблюдения правил экранирования:
Пример:
"info": "У вас {count, plural, one {# сообщение} other {# сообщений}} в системе"
Ошибки в структуре приводят к невозможности компиляции сообщения, поскольку типизация выполняется на этапе разбора шаблона.
Globalize предварительно компилирует сообщения в функции форматирования. Это означает, что типизация параметров фиксируется заранее, а не вычисляется при каждом вызове.
const formatter = Globalize.messageFormatter("cart.items");
В момент создания форматтера:
При последующих вызовах происходит только подстановка значений без повторного парсинга строки.
Несмотря на строгую структуру, Globalize допускает неявные преобразования:
Date объекты приводятся к timestamp;other.Пример:
message({ count: "3" });
Значение "3" будет приведено к числу для определения
plural-категории.
Выбор ветки в типизированных сообщениях полностью детерминирован и зависит от CLDR-правил конкретной локали. Это исключает ручное управление грамматикой в коде.
Для одного и того же значения:
Типизированные сообщения допускают вложенные форматтеры:
"report":
"{value, number, percent} завершено к {date, date, short}"
const message = Globalize.messageFormatter("report");
message({
value: 0.87,
date: new Date()
});
Каждый параметр обрабатывается независимо, но результат собирается в единую строку.
При всей гибкости ICU-подхода существуют ограничения:
Эти ограничения обеспечивают предсказуемость и кросс-языковую согласованность.
Если передано значение, не соответствующее ни одной ветке
select или plural, используется fallback
other.
"{level, select, high {Высокий} low {Низкий} other {Средний}}"
Это гарантирует стабильность отображения даже при расширении доменной модели приложения.
При комбинировании нескольких параметров важно учитывать их независимость. Каждый параметр обрабатывается отдельно в своём типовом пространстве:
Такое разделение позволяет строить сложные сообщения без конфликтов между типами данных и правилами локализации.