В основе FormatJS лежит ICU MessageFormat, поддерживающий вложенные
конструкции, позволяющие строить динамические строки с несколькими
уровнями логики. Наиболее часто вложенность возникает при комбинировании
select, plural и интерполяции значений.
Базовый уровень выбора через select позволяет учитывать
произвольные категории, например пол или тип сущности:
const message = `
{gender, select,
male {Он отправил сообщение}
female {Она отправила сообщение}
other {Пользователь отправил сообщение}
}
`;
Вложенность начинается там, где внутри одного блока выбора требуется учитывать дополнительные параметры, например количество:
const message = `
{gender, select,
male {
{count, plural,
one {Он отправил # файл}
few {Он отправил # файла}
many {Он отправил # файлов}
other {Он отправил # файлов}
}
}
female {
{count, plural,
one {Она отправила # файл}
few {Она отправила # файла}
many {Она отправила # файлов}
other {Она отправила # файлов}
}
}
other {
{count, plural,
one {Пользователь отправил # файл}
few {Пользователь отправил # файла}
many {Пользователь отправил # файлов}
other {Пользователь отправил # файлов}
}
}
}
`;
Подобная структура демонстрирует типичную многоуровневую вложенность: сначала определяется контекст (gender), затем количественная форма (plural).
Конструкция plural может содержать внутри себя не только
текст, но и дополнительные выражения, включая форматирование чисел и
вложенные условия.
const message = `
В корзине {
itemCount, plural,
=0 {нет товаров}
one {# товар}
few {# товара}
many {# товаров}
other {# товара}
}
`;
В более сложных сценариях внутри plural может находиться
select, формируя двойную зависимость:
const message = `
{itemCount, plural,
=0 {Корзина пуста}
other {
{isDiscount, select,
true {# товаров со скидкой}
false {# товаров по полной цене}
other {# товаров}
}
}
}
`;
Такой подход позволяет комбинировать количественные и логические условия без выхода за пределы одного сообщения.
FormatJS поддерживает передачу форматтеров через values,
что позволяет вкладывать уже отформатированные значения в более сложные
сообщения.
intl.formatMessage(
{
id: "cart.summary",
defaultMessage: `
{count, plural,
one {# товар на сумму {price}}
other {# товара на сумму {price}}
}
`
},
{
count: 3,
price: intl.formatNumber(1500, { style: "currency", currency: "RUB" })
}
);
Здесь наблюдается логическая вложенность:
price)select может быть вложен в другой select,
создавая многоуровневую ветвящуюся структуру.
const message = `
{device, select,
mobile {
{os, select,
ios {Доступно на iPhone}
android {Доступно на Android}
other {Доступно на мобильных устройствах}
}
}
desktop {
{os, select,
windows {Доступно на Windows}
mac {Доступно на macOS}
other {Доступно на компьютере}
}
}
other {Доступно на неизвестной платформе}
}
`;
Подобная конструкция используется при необходимости учитывать несколько независимых параметров одновременно, например платформу и операционную систему.
В react-intl вложенные конструкции часто формируются
через компоненты <FormattedMessage> с передачей
сложных значений.
<FormattedMessage
id="order.status"
defaultMessage="
{status, select,
shipped {
Доставка: {date}
}
processing {
Обработка заказа: {progress}%
}
other {Статус неизвестен}
}
"
values={{
status,
date: intl.formatDate(shipDate),
progress
}}
/>
Здесь вложенность выражается не только в ICU-синтаксисе, но и в том, что значения предварительно формируются вне строки сообщения.
Одним из распространённых паттернов является вложение одного
сообщения в другое через предварительный вызов
formatMessage.
const fileMessage = intl.formatMessage(
{ id: "file.name", defaultMessage: "Файл {name}" },
{ name: "report.pdf" }
);
const message = intl.formatMessage(
{
id: "upload.summary",
defaultMessage: "Загружено: {fileInfo}"
},
{
fileInfo: fileMessage
}
);
Такой подход позволяет строить многоуровневые сообщения, где одна часть текста является результатом независимого форматирования.
FormatJS поддерживает rich-text форматирование, где HTML-подобные
теги могут быть вложены друг в друга через функции в
values.
const message = `
<bold>
Ошибка: <link>не удалось загрузить файл</link>
</bold>
`;
Реализация через intl.formatMessage:
intl.formatMessage(
{
id: "error.message",
defaultMessage: `
<bold>
Ошибка: <link>не удалось загрузить файл</link>
</bold>
`
},
{
bold: (chunks) => `<strong>${chunks}</strong>`,
link: (chunks) => `<a href="/help">${chunks}</a>`
}
);
В этом случае вложенность выражается через иерархию тегов, где один форматтер оборачивает другой.
Хотя числовые и датовые форматтеры обычно применяются как атомарные операции, они могут быть вложены в более сложные структуры сообщений.
const message = `
{count, plural,
one {Завершено {date}}
other {Завершено {date} — всего # операций}
}
`;
intl.formatMessage(
{
id: "task.summary",
defaultMessage: `
{count, plural,
one {Завершено {date}}
other {Завершено {date}, обработано {count} задач}
}
`
},
{
count,
date: intl.formatDate(new Date())
}
);
Здесь формат даты вкладывается в plural-структуру, создавая комбинированное представление данных.
Глубокая вложенность в ICU MessageFormat приводит к росту сложности парсинга и снижению читаемости шаблонов. Особенно это заметно при сочетании:
plural внутри selectselect внутри pluralselectordinalПример потенциально сложной конструкции:
{role, select,
admin {
{count, plural,
one {Администратор обработал # запрос}
other {
{priority, select,
high {Администратор обработал # срочных запросов}
other {Администратор обработал # запросов}
}
}
}
}
}
Такие конструкции требуют строгой дисциплины структуры, поскольку каждая ветка должна возвращать валидный ICU-выражение без нарушения синтаксиса.
В сложных интерфейсах вложенность может использоваться вместе с форматированием списков значений.
const message = `
{count, plural,
one {Файл: {files}}
other {Файлы: {files}}
}
`;
intl.formatMessage(
{
id: "files.summary",
defaultMessage: `
{count, plural,
one {Файл: {files}}
other {Файлы: {files}}
}
`
},
{
count,
files: fileList.join(", ")
}
);
В данном случае вложенность возникает между структурной логикой plural и агрегированным значением списка.
Основное назначение вложенных конструкций — перенос бизнес-логики представления текста в слой локализации. Это позволяет:
При этом структура сообщений становится декларативной, где вложенность отражает не программный контроль потока, а языковую и семантическую иерархию.