FormatJS предоставляет систему форматирования сообщений, основанную на ICU MessageFormat, где основная гибкость достигается через композицию шаблонов, параметризацию и расширяемые правила форматирования. Пользовательские паттерны в этой архитектуре представляют собой способ описания логики вывода текста вне фиксированных языковых конструкций, позволяя адаптировать сообщения под доменную специфику приложения, бизнес-правила и контекст отображения.
В основе системы сообщений FormatJS лежит строковый шаблон, содержащий плейсхолдеры и управляющие конструкции:
const message = "У вас {count} новых сообщений";
При этом шаблон может включать сложные конструкции ICU:
const message = "{count, plural, one {# сообщение} few {# сообщения} many {# сообщений}}";
Пользовательские паттерны возникают там, где стандартных
plural, select, number,
date становится недостаточно для описания логики
вывода.
FormatJS поддерживает механизм именованных форматов, который позволяет задавать повторно используемые правила форматирования чисел, дат и времени. Это становится основой для пользовательских паттернов.
import { createIntl, createIntlCache } from 'react-intl';
const cache = createIntlCache();
const intl = createIntl(
{
locale: 'ru',
messages: {}
},
cache
);
intl.formatNumber(12345.67, {
style: 'currency',
currency: 'RUB'
});
Хотя этот пример использует стандартные опции, пользовательские паттерны формируются через оборачивание этих вызовов в доменные абстракции.
В прикладной архитектуре часто вводятся функции-обёртки, инкапсулирующие правила отображения:
const formatPrice = (intl, value) =>
intl.formatNumber(value, {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 2
});
Такой подход превращает форматирование в переиспользуемый паттерн, не зависящий от конкретного сообщения.
Далее он используется внутри сообщений:
intl.formatMessage(
{ id: 'product.price' },
{ price: formatPrice(intl, 99.99) }
);
Одним из ключевых механизмов является select,
позволяющий строить условные языковые конструкции:
const message = "{gender, select, male {Он добавил} female {Она добавила} other {Пользователь добавил}}";
На уровне паттернов это превращается в стратегию локализации поведения, а не текста.
Расширение этого механизма через доменные значения позволяет формировать более сложные паттерны:
const statusMessage =
"{status, select, pending {Ожидание} success {Успешно} error {Ошибка} other {Неизвестно}}";
Пользовательские паттерны часто строятся через композицию базовых шаблонов и функций форматирования.
const messages = {
invoice: "Счёт {id}: {amount, number, currency}",
invoiceDetailed: "Счёт {id} от {date, date, long}: {amount, number, currency}"
};
На уровне архитектуры приложения это может быть обёрнуто:
const formatInvoice = (intl, invoice) =>
intl.formatMessage(
{ id: 'invoiceDetailed' },
{
id: invoice.id,
date: invoice.date,
amount: invoice.amount
}
);
react-intl расширяет механизм FormatJS за счёт декларативных компонентов, в которых паттерны становятся частью UI-слоя.
<FormattedMessage
id="cart.summary"
values={{
count: items.length,
total: totalPrice
}}
/>
Пользовательские паттерны здесь формируются через:
<FormattedMessage>formatMessagevaluesFormatJS позволяет передавать не только значения, но и уже отформатированные строки. Это создаёт слой пользовательских паттернов, где форматирование становится промежуточной стадией.
const values = {
price: intl.formatNumber(1200, { style: 'currency', currency: 'EUR' }),
date: intl.formatDate(new Date(), { year: 'numeric', month: 'long' })
};
Далее они используются в сообщении без дополнительной логики:
intl.formatMessage({ id: 'order.summary' }, values);
В сложных системах формируется библиотека шаблонов, где пользовательские паттерны становятся частью доменной модели.
const TEMPLATES = {
USER_STATUS: "{name} сейчас {status}",
FILE_UPLOAD: "Файл {fileName} загружен на {date, date, short}",
NOTIFICATION:
"{level, select, info {Информация} warning {Предупреждение} error {Ошибка} other {Сообщение}}: {text}"
};
Такая структура позволяет использовать сообщения как конфигурируемые паттерны, а не как статические строки.
В некоторых случаях паттерны включают вычисляемые значения, подготовленные до передачи в FormatJS:
const buildValues = (user) => ({
name: user.name,
status: user.active ? 'активен' : 'неактивен'
});
И далее:
intl.formatMessage(
{ id: 'user.status' },
buildValues(user)
);
Такой подход отделяет бизнес-логику от шаблона, формируя устойчивый пользовательский паттерн.
ICU ListFormat используется для создания языковых правил перечислений:
intl.formatList(['яблоко', 'банан', 'груша'], { type: 'conjunction' });
Пользовательские паттерны здесь строятся вокруг выбора типа соединения:
Абстрагирование:
const formatAndList = (intl, items) =>
intl.formatList(items, { type: 'conjunction' });
На низком уровне FormatJS использует IntlMessageFormat,
который парсит ICU-строки в AST и выполняет их интерпретацию.
Пользовательские паттерны могут быть реализованы как слой компиляции сообщений:
import IntlMessageFormat from 'intl-messageformat';
const mf = new IntlMessageFormat(
"{count, plural, one {# файл} other {# файлов}}",
'ru'
);
mf.format({ count: 5 });
Оборачивание этого слоя позволяет создавать доменные DSL:
const createPluralPattern = (one, other) =>
`{count, plural, one {${one}} other {${other}}}`;
Паттерны могут формироваться динамически на основе конфигурации:
const buildMessage = (label) =>
`{value, number} ${label}`;
Это позволяет создавать адаптивные шаблоны без изменения исходного набора сообщений.
FormatJS поддерживает вложенные структуры, где значения могут содержать заранее отформатированные строки:
intl.formatMessage(
{ id: 'nested.example' },
{
outer: intl.formatMessage({ id: 'inner.message' })
}
);
Такая модель позволяет строить каскадные паттерны отображения.
В прикладных системах пользовательские паттерны часто отражают бизнес-логику:
Пример:
const ORDER_STATUS = {
created: "Создан",
paid: "Оплачен",
shipped: "Отправлен",
delivered: "Доставлен"
};
Использование в FormatJS:
intl.formatMessage(
{ id: 'order.status' },
{ status: ORDER_STATUS[order.status] }
);
Пользовательские паттерны становятся частью слоя i18n-инфраструктуры, где выделяются:
Такая структура позволяет изолировать локализацию от бизнес-кода, сохраняя при этом гибкость расширения шаблонов без изменения ядра системы.