При интернационализации приложений возникает фундаментальная проблема: данные должны храниться в одном, стабильном и предсказуемом виде, но отображаться — в соответствии с локалью пользователя. В разных странах различаются:
Библиотека Globalize решает эту задачу через разделение:
Такой подход позволяет избежать ошибок при обработке данных и одновременно обеспечить корректный интерфейс для пользователей разных регионов.
Учетный формат представляет собой внутренний способ хранения данных, независимый от локали пользователя.
Например:
| Тип данных | Учетный формат |
|---|---|
| Числа | 12345.67 |
| Дата | 2026-05-27 |
| Время | 18:45:00 |
| Валюта | 1500.25 |
| Timestamp | 2026-05-27T18:45:00Z |
Основные свойства учетного формата:
Число:
1,234
может означать:
Если хранить данные в пользовательском виде, возникает риск некорректной обработки.
Отображаемый формат предназначен исключительно для взаимодействия с пользователем.
Один и тот же учетный формат:
12345.67
может отображаться так:
| Локаль | Результат |
|---|---|
| en | 12,345.67 |
| de | 12.345,67 |
| fr | 12 345,67 |
| ru | 12 345,67 |
Globalize автоматически выполняет преобразование на основе текущей локали.
Globalize строится поверх данных CLDR (Common Locale Data Repository), содержащих:
Типичная схема работы выглядит следующим образом:
Учетные данные
↓
Globalize
↓
Локализованный вывод
const Globalize = require("globalize");
Globalize.locale("en");
const formatter = Globalize.numberFormatter();
console.log(formatter(12345.67));
Результат:
12,345.67
Для немецкой локали:
Globalize.locale("de");
const formatter = Globalize.numberFormatter();
console.log(formatter(12345.67));
Результат:
12.345,67
Внутри приложения число должно оставаться числом:
const amount = 12345.67;
Нельзя хранить:
"12.345,67"
или:
"12,345.67"
Причины:
Globalize применяется только на этапе отображения:
const formatter = Globalize.numberFormatter();
const visibleValue = formatter(amount);
Учетное значение:
0.35
Отображение:
const formatter = Globalize.numberFormatter({
style: "percent"
});
console.log(formatter(0.35));
Результат:
35%
Для разных локалей формат может отличаться:
Правильный вариант:
{
amount: 1500.75,
currency: "USD"
}
Неправильный вариант:
"$1,500.75"
или:
"1 500,75 ₽"
const formatter = Globalize.currencyFormatter("USD");
console.log(formatter(1500.75));
Результат для en:
$1,500.75
Для fr:
1 500,75 $US
Для ru:
1 500,75 $
const formatter = Globalize.numberFormatter({
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
console.log(formatter(12));
Результат:
12.00
Рекомендуемые форматы:
2026-05-27
или:
2026-05-27T14:30:00Z
Использование локальных строк:
27.05.2026
или:
05/27/2026
для хранения данных является ошибкой.
const date = new Date(2026, 4, 27);
Globalize.locale("en");
const formatter = Globalize.dateFormatter({
datetime: "medium"
});
console.log(formatter(date));
Результат:
May 27, 2026
Для русской локали:
27 мая 2026 г.
const formatter = Globalize.dateFormatter({
skeleton: "yMd"
});
Возможный результат:
27.05.2026
const formatter = Globalize.dateFormatter({
datetime: "full"
});
Результат:
Wednesday, May 27, 2026
или:
среда, 27 мая 2026 г.
const formatter = Globalize.dateFormatter({
skeleton: "Hm"
});
console.log(formatter(new Date()));
В разных локалях возможны:
Форматирование — только половина задачи. Пользователь вводит данные в локальном формате, а приложение должно преобразовать их в учетный формат.
Globalize.locale("de");
const parser = Globalize.numberParser();
console.log(parser("12.345,67"));
Результат:
12345.67
const parser = Globalize.numberParser({
style: "percent"
});
console.log(parser("35%"));
Результат:
0.35
const parser = Globalize.dateParser({
skeleton: "yMd"
});
console.log(parser("27.05.2026"));
Результатом будет объект Date.
Наиболее опасная ошибка — смешивание учетного и отображаемого представления.
const total = "12.345,67";
const result = total * 2;
Результат:
NaN
const parser = Globalize.numberParser();
const value = parser("12.345,67");
const result = value * 2;
Пользователь из Германии вводит:
1.234,50
Внутри приложения должно храниться:
1234.5
Алгоритм:
Globalize.locale("en");
Globalize.locale("fr");
Globalize.locale("ru");
После смены локали форматирование автоматически меняется.
function renderPrice(price, locale) {
Globalize.locale(locale);
const formatter = Globalize.currencyFormatter("EUR");
return formatter(price);
}
При обмене данными между клиентом и сервером необходимо использовать только нейтральные форматы.
Правильный вариант:
{
"price": 1234.56,
"date": "2026-05-27"
}
Неправильный вариант:
{
"price": "1.234,56",
"date": "27.05.2026"
}
Стандартный формат даты:
2026-05-27T14:30:00Z
Преимущества:
Учетное время часто хранится в UTC:
2026-05-27T12:00:00Z
Но пользователь должен видеть локальное время.
Globalize форматирует дату с учетом локали, однако преобразование временных зон обычно выполняется отдельно.
Практическая архитектура обычно выглядит так:
| Уровень | Формат |
|---|---|
| База данных | ISO / UTC |
| API | JSON / ISO |
| Бизнес-логика | Числа и Date |
| Интерфейс | Localized string |
| Пользовательский ввод | Localized string |
Создание форматтеров — относительно дорогая операция.
Неэффективно:
function render(value) {
return Globalize.numberFormatter()(value);
}
Лучше:
const formatter = Globalize.numberFormatter();
function render(value) {
return formatter(value);
}
Для крупных приложений используется кэш:
const cache = {};
function getFormatter(locale) {
if (!cache[locale]) {
Globalize.locale(locale);
cache[locale] =
Globalize.numberFormatter();
}
return cache[locale];
}
Важно понимать различие между:
const parser = Globalize.numberParser();
const value = parser(input);
if (isNaN(value)) {
console.log("Некорректное число");
}
Ошибка:
"1 234,56 ₽"
вместо:
1234.56
Ошибка:
price.toFixed(2).replace(".", ",")
Проблемы:
parseFloatОшибка:
parseFloat("12.345,67")
Результат:
12.345
Globalize корректно учитывает локаль.
Типичный цикл работы:
Пользовательский ввод
↓
Парсинг через Globalize
↓
Учетный формат
↓
Бизнес-логика
↓
Форматирование через Globalize
↓
Интерфейс
Globalize.locale("fr");
const parser =
Globalize.numberParser();
const formatter =
Globalize.currencyFormatter("EUR");
const userInput = "1 250,75";
const value = parser(userInput);
console.log(value);
Результат:
1250.75
Отображение:
console.log(formatter(value));
Результат:
1 250,75 €
Globalize не заменяет внутренние форматы хранения данных. Библиотека выступает промежуточным слоем между:
Именно такое разделение делает международные приложения: