Комбинирование форматтеров в Globalize строится на принципе композиции независимых функций форматирования: чисел, дат, валют, сообщений и правил множественности. Каждый форматтер возвращает локализованное представление значения, а итоговая строка формируется через вложение результатов одного форматтера в другой или через использование шаблонов сообщений ICU.
Внутри Globalize форматтеры создаются как функции, сохраняющие локаль и правила CLDR. Каждый тип форматтера решает узкую задачу:
Комбинирование происходит не через магическую “цепочку”, а через явное использование результатов одного форматтера в другом или через шаблонные строки сообщений.
Простейший уровень композиции — вложение форматированных значений в строку сообщения:
const Globalize = require("globalize");
Globalize.locale("ru");
const numberFormatter = Globalize.numberFormatter();
const currencyFormatter = Globalize.currencyFormatter("USD");
const messageFormatter = Globalize.messageFormatter(
"{count} товаров на сумму {total}"
);
const count = numberFormatter(1250);
const total = currencyFormatter(1250);
messageFormatter({
count,
total
});
Здесь форматирование числа и валюты выполняется отдельно, после чего результаты объединяются в message formatter.
Наиболее устойчивый способ комбинирования форматтеров — использование ICU-синтаксиса, встроенного в message formatter. Он позволяет включать числовые и текстовые форматтеры прямо в шаблон, устраняя необходимость ручного форматирования промежуточных значений.
ICU-сообщение поддерживает вложенные правила:
Пример комбинирования числа и множественного числа:
const msg = Globalize.messageFormatter(
"{count, plural, one {# файл} few {# файла} other {# файлов}}"
);
msg({ count: 1 });
msg({ count: 3 });
msg({ count: 10 });
В данном случае число одновременно участвует в двух процессах:
#Такой подход исключает необходимость предварительного форматирования
числа через numberFormatter, поскольку ICU сам применяет
локальные правила.
ICU-синтаксис позволяет комбинировать числовое форматирование и текст в одном выражении:
const msg = Globalize.messageFormatter(
"Баланс: {balance, number, currency}"
);
msg({ balance: 15320.5 });
Здесь происходит автоматическое применение currency formatter,
соответствующего текущей локали. Это означает, что явное создание
currencyFormatter не требуется, если форматирование описано
в message template.
Поддерживаются различные стили:
Пример комбинирования нескольких числовых представлений:
const msg = Globalize.messageFormatter(
"Доход: {income, number, currency}, рост: {growth, number, percent}"
);
msg({
income: 5000,
growth: 0.12
});
Каждое значение форматируется независимо, но итоговая строка формируется единым механизмом.
Форматтер дат часто используется совместно с текстовыми шаблонами. В отличие от чисел, даты требуют контекста локали и календаря.
const dateFormatter = Globalize.dateFormatter({ datetime: "medium" });
const msg = Globalize.messageFormatter(
"Последнее обновление: {date}"
);
msg({
date: dateFormatter(new Date(2026, 4, 27))
});
Такой способ является базовым уровнем композиции: форматтер даты применяется отдельно, затем результат вставляется в сообщение.
Однако ICU позволяет встроить форматирование даты напрямую:
const msg = Globalize.messageFormatter(
"Последнее обновление: {date, date, medium}"
);
msg({
date: new Date(2026, 4, 27)
});
Здесь отсутствует промежуточный форматтер, а композиция происходит внутри message engine.
Более сложная композиция возникает при работе с объектами, содержащими несколько полей локализации.
const msg = Globalize.messageFormatter(
"Заказ {id}: {quantity, plural, one {# позиция} other {# позиций}} на сумму {total, number, currency}"
);
msg({
id: 9821,
quantity: 3,
total: 2599.99
});
В одном сообщении комбинируются:
Здесь композиция становится декларативной: форматтеры не вызываются вручную, а описываются как часть структуры сообщения.
Хотя message formatter покрывает большинство сценариев, иногда требуется ручная композиция функций для повторного использования.
const Globalize = require("globalize");
Globalize.locale("ru");
const formatPrice = Globalize.currencyFormatter("USD");
const formatCount = Globalize.numberFormatter();
function formatOrder(order) {
return `Заказ ${order.id}: ${formatCount(order.items)} шт., ${formatPrice(order.total)}`;
}
Здесь форматтеры используются как чистые функции, что позволяет:
Такая модель ближе к функциональному стилю, чем к ICU-шаблонам.
В сложных интерфейсах часто возникает необходимость создавать промежуточные структуры данных, содержащие уже частично отформатированные значения.
const numberFormatter = Globalize.numberFormatter();
const percentFormatter = Globalize.numberFormatter({ style: "percent" });
const stats = {
users: numberFormatter(12000),
conversion: percentFormatter(0.034)
};
const msg = Globalize.messageFormatter(
"Пользователи: {users}, конверсия: {conversion}"
);
msg(stats);
Такой подход фиксирует форматирование на уровне модели данных, а message formatter отвечает только за структуру текста.
При комбинировании форматтеров важно учитывать, что повторное форматирование уже отформатированной строки приводит к потере типовой информации.
Например:
const nf = Globalize.numberFormatter();
const msg = Globalize.messageFormatter("{value, number}");
msg({ value: nf(1000) });
Здесь результат nf(1000) уже является строкой, поэтому
ICU не может применить числовое форматирование корректно.
Правильная модель — передавать исходные значения:
msg({ value: 1000 });
Это демонстрирует принцип: форматтеры должны применяться либо внутри ICU, либо на уровне данных, но не одновременно к одному значению.
В прикладных системах часто требуется динамическое формирование сообщений, где структура заранее неизвестна.
function buildMessage(data) {
const msg = Globalize.messageFormatter(
"{title}: {value}"
);
return msg({
title: data.title,
value: data.isCurrency
? Globalize.currencyFormatter(data.currency)(data.value)
: Globalize.numberFormatter()(data.value)
});
}
Здесь форматтер выбирается динамически, а итоговая композиция формируется на уровне функции.
Такой подход используется при:
В сложных интерфейсах форматтеры образуют многоуровневую систему:
Пример цепочки:
const price = Globalize.currencyFormatter("EUR");
const date = Globalize.dateFormatter({ datetime: "short" });
const msg = Globalize.messageFormatter(
"От {date} стоимость составила {price}"
);
msg({
date: date(new Date()),
price: price(199.99)
});
Каждый слой выполняет строго ограниченную роль, а композиция возникает через передачу результатов между слоями.
Создание форматтеров в Globalize связано с затратами на инициализацию CLDR-данных. При частом комбинировании важно учитывать:
Пример корректного кэширования:
const formatters = {
price: Globalize.currencyFormatter("USD"),
count: Globalize.numberFormatter(),
message: Globalize.messageFormatter(
"{count} items for {price}"
)
};
Повторное использование снижает нагрузку и упрощает композицию.
Комбинирование форматтеров в Globalize формируется вокруг трёх устойчивых стратегий:
Каждая стратегия применима в зависимости от сложности структуры данных и требований к локализации, при этом базовый принцип остаётся неизменным: форматирование всегда разделяется на независимые операции, объединяемые на уровне сообщения или функции.