Императивное форматирование в контексте FormatJS опирается на прямое
использование API форматирования без декларативных конструкций
React-компонентов. В отличие от <FormattedMessage />,
<FormattedNumber /> и других компонентов,
императивный подход предполагает явное создание экземпляра
международного контекста и вызов методов форматирования напрямую в
коде.
Основой служит пакет react-intl, предоставляющий API
createIntl, который позволяет формировать локализованные
сообщения вне React-дерева.
Для работы вне компонентов требуется инициализация объекта
intl, содержащего все методы форматирования.
Ключевые сущности:
createIntl — создание экземпляра intlcreateIntlCache — кэширование сообщений и
форматтеровIntlShape — типизация объекта intlimport { createIntl, createIntlCache } from 'react-intl';
const cache = createIntlCache();
const intl = createIntl(
{
locale: 'ru-RU',
messages: {
greeting: 'Привет, {name}',
balance: 'Баланс: {value, number, currency}'
}
},
cache
);
Объект intl теперь содержит полный набор методов:
formatMessageformatNumberformatDateformatTimeformatRelativeTimeformatPluralМетод formatMessage является центральной точкой
императивного API. Он позволяет получать локализованные строки без
JSX.
const text = intl.formatMessage(
{ id: 'greeting' },
{ name: 'Алексей' }
);
console.log(text); // Привет, Алексей
Сообщение может быть определено не только в messages, но
и динамически:
const text = intl.formatMessage(
{
id: 'welcome',
defaultMessage: 'Добро пожаловать, {name}'
},
{ name: 'Мария' }
);
Метод formatNumber использует стандарты
Intl.NumberFormat, но добавляет слой абстракции
FormatJS.
const result = intl.formatNumber(123456.78);
console.log(result);
const price = intl.formatNumber(1999.99, {
style: 'currency',
currency: 'USD'
});
Поддерживаются все параметры Intl.NumberFormat:
stylecurrencyminimumFractionDigitsmaximumFractionDigitsuseGroupingИмперативное форматирование дат осуществляется через
formatDate и formatTime.
const date = intl.formatDate(new Date(), {
year: 'numeric',
month: 'long',
day: '2-digit'
});
const time = intl.formatTime(new Date(), {
hour: '2-digit',
minute: '2-digit'
});
Эти методы являются обёртками над
Intl.DateTimeFormat.
Метод formatRelativeTime позволяет выражать временные
интервалы относительно текущего момента.
const relative = intl.formatRelativeTime(-3, 'day');
console.log(relative); // 3 дня назад
Параметры:
'second' | 'minute' | 'hour' | 'day' | 'month' | 'year'Pluralization реализуется через formatPlural, который
возвращает категорию множественного числа для текущей локали.
const category = intl.formatPlural(5);
console.log(category); // few / many / other (зависит от локали)
Применение чаще всего комбинируется с formatMessage:
const message = intl.formatMessage(
{
id: 'items'
},
{
count: 5,
type: intl.formatPlural(5)
}
);
Императивный API особенно полезен в следующих сценариях:
export function formatUserBalance(intl, balance) {
return intl.formatMessage(
{
id: 'balance',
defaultMessage: 'Баланс: {value}'
},
{
value: intl.formatNumber(balance, {
style: 'currency',
currency: 'EUR'
})
}
);
}
Императивный подход подразумевает явную инъекцию intl в
функции и сервисы.
class InvoiceService {
constructor(intl) {
this.intl = intl;
}
formatInvoiceTotal(amount) {
return this.intl.formatMessage(
{
id: 'invoice.total',
defaultMessage: 'Итого: {amount}'
},
{
amount: this.intl.formatNumber(amount, {
style: 'currency',
currency: 'USD'
})
}
);
}
}
Такой подход обеспечивает:
В системах с мультиарендностью или динамической сменой локали
создаются отдельные экземпляры intl.
function createUserIntl(locale, messages) {
const cache = createIntlCache();
return createIntl(
{
locale,
messages
},
cache
);
}
Каждый пользователь может получать собственный контекст форматирования.
Императивный API позволяет пересоздавать intl без
перезагрузки приложения.
let intl = createIntl({ locale: 'en', messages }, cache);
function switchLocale(locale, messages) {
intl = createIntl({ locale, messages }, cache);
}
createIntlCache снижает накладные расходы на создание
форматтеров:
Intl.* объектовБез кеша каждое форматирование приводит к пересозданию внутренних структур.
Императивный формат отличается от React-компонентного следующим:
Декларативный подход:
<FormattedMessage id="greeting" values={{ name }} />
Императивный подход:
intl.formatMessage({ id: 'greeting' }, { name });
Несмотря на гибкость, существуют особенности:
intlЭти ограничения компенсируются контролем над выполнением и возможностью использования вне React.
В Node.js императивное форматирование часто применяется для генерации текстов:
import { createIntl, createIntlCache } from 'react-intl';
const cache = createIntlCache();
const intl = createIntl({
locale: 'ru',
messages: {
report: 'Отчёт за {date}'
}
}, cache);
const output = intl.formatMessage(
{ id: 'report' },
{ date: intl.formatDate(new Date()) }
);
Такой подход позволяет формировать локализованные ответы API без зависимости от клиентского слоя.
Императивный API позволяет вкладывать форматтеры друг в друга:
const message = intl.formatMessage(
{
id: 'summary',
defaultMessage: '{count} товаров на сумму {total}'
},
{
count: 3,
total: intl.formatNumber(1500, {
style: 'currency',
currency: 'USD'
})
}
);
Композиция обеспечивает единый контроль над локализацией сложных строк.
Императивный форматировщик становится базовым инструментом в средах:
Он обеспечивает доступ к инфраструктуре FormatJS без зависимости от
UI-фреймворков, сохраняя совместимость с Intl-стандартами
ECMAScript.