Библиотека Globalize предоставляет гибкий механизм форматирования данных на основе стандарта CLDR (Common Locale Data Repository). Помимо встроенных методов форматирования дат, чисел и валют, библиотека позволяет создавать собственные паттерны отображения значений. Это особенно важно в крупных приложениях, где стандартных локализационных форматов недостаточно.
Пользовательские паттерны используются для:
Внутри Globalize форматирование строится поверх данных CLDR. Библиотека не содержит жёстко закодированных шаблонов — она использует локализационные данные конкретной культуры.
Основные механизмы:
| Компонент | Назначение |
|---|---|
| CLDR | Источник локализованных данных |
| Globalize | API форматирования |
| Formatter | Скомпилированная функция форматирования |
| Skeleton / Pattern | Описание формата |
Для работы с пользовательскими паттернами требуется подключение соответствующих модулей.
const Globalize = require("globalize");
require("cldr-data").entireSupplemental();
require("cldr-data").entireMainFor("ru");
Globalize.load(
require("cldr-data/supplemental/likelySubtags.json"),
require("cldr-data/main/ru/numbers.json"),
require("cldr-data/main/ru/ca-gregorian.json")
);
Globalize.locale("ru");
Метод:
Globalize.numberFormatter(options)
создаёт функцию форматирования с заданными параметрами.
Пример:
const formatter = Globalize.numberFormatter({
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
console.log(formatter(15));
// 15,00
const formatter = Globalize.numberFormatter({
minimumFractionDigits: 3,
maximumFractionDigits: 5
});
console.log(formatter(12.3));
// 12,300
const formatter = Globalize.numberFormatter({
useGrouping: true
});
console.log(formatter(1000000));
// 1 000 000
Отключение группировки:
const formatter = Globalize.numberFormatter({
useGrouping: false
});
console.log(formatter(1000000));
// 1000000
const formatter = Globalize.numberFormatter({
style: "percent",
minimumFractionDigits: 1
});
console.log(formatter(0.256));
// 25,6 %
const formatter = Globalize.currencyFormatter("USD", {
minimumFractionDigits: 2
});
console.log(formatter(1500));
// 1 500,00 $
const formatter = Globalize.currencyFormatter("EUR", {
style: "symbol"
});
Возможные значения:
| Значение | Описание |
|---|---|
| symbol | Символ валюты |
| code | Код валюты |
| name | Полное название |
Во многих системах требуется нестандартное отображение отрицательных значений.
Например:
const formatter = Globalize.numberFormatter({
minimumFractionDigits: 2
});
console.log(formatter(-1500.5));
// -1 500,50
Однако иногда требуется бухгалтерский формат:
(1 500,50)
Стандартный API Globalize напрямую не поддерживает произвольные маски отрицательных значений, поэтому обычно применяется дополнительная обёртка:
const formatter = Globalize.numberFormatter({
minimumFractionDigits: 2
});
function accountingFormat(value) {
if (value < 0) {
return `(${formatter(Math.abs(value))})`;
}
return formatter(value);
}
console.log(accountingFormat(-1500.5));
// (1 500,50)
const formatter = Globalize.dateFormatter();
console.log(formatter(new Date()));
const formatter = Globalize.dateFormatter({
datetime: "medium"
});
Возможные варианты:
| Значение | Описание |
|---|---|
| short | Краткий формат |
| medium | Средний |
| long | Расширенный |
| full | Полный |
Skeleton — это декларативное описание структуры даты.
Пример:
const formatter = Globalize.dateFormatter({
skeleton: "yMMMd"
});
console.log(formatter(new Date()));
Результат для русской локали:
5 июл. 2025 г.
| Skeleton | Формат |
|---|---|
| yMd | дата |
| yMMMd | сокращённый месяц |
| yMMMMd | полный месяц |
| Hm | часы и минуты |
| Hms | часы, минуты, секунды |
| EEEE | день недели |
const formatter = Globalize.dateFormatter({
skeleton: "Hm"
});
console.log(formatter(new Date()));
// 14:35
const formatter = Globalize.dateFormatter({
skeleton: "yMMMMdHm"
});
console.log(formatter(new Date()));
const formatter = Globalize.dateFormatter({
skeleton: "yMMMM"
});
console.log(formatter(new Date()));
Globalize создаёт formatter-функции заранее. Это снижает нагрузку при многократном форматировании.
const numberFormatter = Globalize.numberFormatter({
minimumFractionDigits: 2
});
const dateFormatter = Globalize.dateFormatter({
skeleton: "yMMMd"
});
Далее функции переиспользуются:
items.forEach(item => {
console.log(numberFormatter(item.price));
});
В крупных проектах обычно создаётся единый слой форматирования.
class FormatterService {
constructor(locale) {
this.globalize = new Globalize(locale);
this.currency = this.globalize.currencyFormatter("USD");
this.date = this.globalize.dateFormatter({
skeleton: "yMMMd"
});
this.number = this.globalize.numberFormatter({
minimumFractionDigits: 2
});
}
formatCurrency(value) {
return this.currency(value);
}
formatDate(value) {
return this.date(value);
}
formatNumber(value) {
return this.number(value);
}
}
class MoneyFormatter {
constructor(locale, currencyCode) {
this.formatter =
new Globalize(locale)
.currencyFormatter(currencyCode, {
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
}
format(value) {
const result = this.formatter(Math.abs(value));
if (value < 0) {
return `[${result}]`;
}
return result;
}
}
Сам Globalize ограниченно работает с unit formatting, поэтому часто используются пользовательские паттерны.
const formatter = Globalize.numberFormatter({
minimumFractionDigits: 1
});
function formatWeight(value) {
return `${formatter(value)} кг`;
}
console.log(formatWeight(15.2));
// 15,2 кг
const dateFormatter = Globalize.dateFormatter({
skeleton: "yMMMd"
});
const numberFormatter = Globalize.numberFormatter({
minimumFractionDigits: 2
});
function buildReport(date, amount) {
return `
Дата: ${dateFormatter(date)}
Сумма: ${numberFormatter(amount)}
`;
}
function createFormatter(type) {
switch(type) {
case "money":
return Globalize.numberFormatter({
minimumFractionDigits: 2
});
case "integer":
return Globalize.numberFormatter({
maximumFractionDigits: 0
});
case "percent":
return Globalize.numberFormatter({
style: "percent"
});
default:
return Globalize.numberFormatter();
}
}
const ru = new Globalize("ru");
const en = new Globalize("en");
const ruFormatter = ru.numberFormatter();
const enFormatter = en.numberFormatter();
console.log(ruFormatter(123456.78));
// 123 456,78
console.log(enFormatter(123456.78));
// 123,456.78
Создание formatter-функций является сравнительно дорогой операцией.
Неправильно:
function render(value) {
const formatter =
Globalize.numberFormatter({
minimumFractionDigits: 2
});
return formatter(value);
}
Правильно:
const formatter =
Globalize.numberFormatter({
minimumFractionDigits: 2
});
function render(value) {
return formatter(value);
}
const dateFormatter = Globalize.dateFormatter({
skeleton: "yMdHms"
});
function log(message) {
const timestamp =
dateFormatter(new Date());
console.log(
`[${timestamp}] ${message}`
);
}
Globalize поддерживает обратное преобразование строк.
const parser =
Globalize.numberParser();
console.log(
parser("1 500,25")
);
// 1500.25
const parser =
Globalize.dateParser({
skeleton: "yMd"
});
console.log(
parser("10.07.2025")
);
В отличие от некоторых библиотек:
Globalize не использует строковые маски вида:
"DD.MM.YYYY"
"#,###.00"
Вместо этого применяется декларативный API CLDR.
Основные преимущества CLDR-модели:
| Особенность | Преимущество |
|---|---|
| Локализация | Автоматическая адаптация |
| Стандартизация | Совместимость ICU |
| Масштабируемость | Поддержка множества языков |
| Предсказуемость | Единое поведение |
class I18nFormatter {
constructor(locale) {
this.globalize =
new Globalize(locale);
this.formatters = {
money:
this.globalize.currencyFormatter("USD"),
percent:
this.globalize.numberFormatter({
style: "percent"
}),
integer:
this.globalize.numberFormatter({
maximumFractionDigits: 0
}),
date:
this.globalize.dateFormatter({
skeleton: "yMMMd"
})
};
}
format(type, value) {
const formatter =
this.formatters[type];
if (!formatter) {
throw new Error(
`Unknown formatter: ${type}`
);
}
return formatter(value);
}
}
const formatter =
Globalize.numberFormatter();
Плохо:
items.forEach(item => {
const formatter =
Globalize.numberFormatter();
console.log(
formatter(item.price)
);
});
Хорошо:
const formatter =
Globalize.numberFormatter();
items.forEach(item => {
console.log(
formatter(item.price)
);
});
const cache = new Map();
function getFormatter(locale) {
if (!cache.has(locale)) {
cache.set(
locale,
new Globalize(locale)
.numberFormatter()
);
}
return cache.get(locale);
}
E_MISSING_CLDR
Причина:
Globalize.load(...)
не был вызван.
Globalize.dateFormatter({
skeleton: "INVALID"
});
Особенно критично для:
const formatter =
Globalize.numberFormatter({
minimumFractionDigits: 2
});
function Price({ value }) {
return (
<span>
{formatter(value)}
</span>
);
}
Globalize.dateFormatter({
datetime: "short"
});
Простой способ быстрого форматирования.
Globalize.dateFormatter({
skeleton: "yMMMMd"
});
Более гибкий и точный подход.
| Сценарий | Решение |
|---|---|
| Простое приложение | datetime |
| Точный контроль | skeleton |
| Корпоративные системы | skeleton |
| Много локалей | skeleton |
Иногда создаётся собственный язык шаблонов поверх Globalize.
Пример:
const patterns = {
MONEY: {
minimumFractionDigits: 2
},
INTEGER: {
maximumFractionDigits: 0
},
PERCENT: {
style: "percent"
}
};
function createPattern(name) {
return Globalize.numberFormatter(
patterns[name]
);
}
Такой подход часто используется: