Переход на библиотеку Globalize в существующих JavaScript-проектах
обычно связан с необходимостью аккуратно заменить разрозненные механизмы
форматирования дат, чисел и сообщений на единый слой
интернационализации. В реальных приложениях такие механизмы часто
распределены между самописными утилитами, сторонними библиотеками и
частичным использованием Intl, что усложняет замену на
одном этапе. Поэтому применяется стратегия постепенного внедрения, при
которой Globalize вводится параллельно с существующей системой.
На этапе миграции типичной практикой становится одновременная работа двух слоёв:
Такой подход позволяет минимизировать риск регрессий и постепенно переносить функциональность без изменения всей кодовой базы одновременно.
Ключевым элементом становится абстракция над форматированием, которая изолирует конкретные реализации:
export function formatDate(value) {
return legacyFormatDate(value);
}
После внедрения Globalize эта же точка становится маршрутизатором:
import Globalize from "globalize";
export function formatDate(value, locale) {
return useGlobalize
? Globalize(locale).dateFormatter({ datetime: "medium" })(value)
: legacyFormatDate(value);
}
Такой слой позволяет переключать поведение через конфигурацию без изменения вызовов в бизнес-логике.
Globalize требует наличия CLDR-данных. На этапе миграции важным аспектом становится их предварительная загрузка и организация.
Типовая структура включает:
Инициализация выполняется централизованно:
import Globalize from "globalize";
import likelySubtags from "cldr-data/supplemental/likelySubtags.json";
import numberingSystems from "cldr-data/supplemental/numberingSystems.json";
import plurals from "cldr-data/supplemental/plurals.json";
Globalize.load(likelySubtags);
Globalize.load(numberingSystems);
Globalize.load(plurals);
На этапе постепенной миграции загрузка данных часто разделяется по локалям, чтобы не увеличивать стартовый вес приложения. Это приводит к появлению динамической подгрузки:
async function loadLocaleData(locale) {
const cldrData = await import(`cldr-data/main/${locale}/ca-gregorian.json`);
Globalize.load(cldrData);
}
Одной из первых зон миграции становится работа с числами, так как она имеет минимальную зависимость от бизнес-логики.
Legacy-реализация:
function formatNumber(value) {
return value.toLocaleString("ru-RU");
}
После введения Globalize добавляется альтернативный путь:
const globalize = Globalize("ru");
function formatNumber(value) {
return globalize.numberFormatter()(value);
}
На промежуточном этапе часто сохраняются оба механизма, а переключение происходит на уровне конфигурации или feature flag.
Работа с датами требует большей осторожности из-за различий в форматах и временных зонах.
Legacy-код:
function formatDate(date) {
return new Date(date).toLocaleDateString("ru-RU");
}
После подключения Globalize вводится форматтер:
const globalize = Globalize("ru");
const dateFormatter = globalize.dateFormatter({
date: "long"
});
function formatDate(date) {
return dateFormatter(new Date(date));
}
При постепенной миграции часто создаётся промежуточный адаптер,
унифицирующий входные типы данных, поскольку разные части системы могут
передавать строки, timestamp или объекты Date.
Наиболее сложной частью является переход от конкатенации строк и простых шаблонов к message formatting.
Legacy-подход:
function greet(name) {
return "Привет, " + name + "!";
}
Globalize-эквивалент:
const globalize = Globalize("ru");
const message = globalize.messageFormatter("greeting");
message({ name: "Иван" });
Где ресурс сообщений:
{
"greeting": "Привет, {name}!"
}
На этапе миграции часто используется смешанный подход: часть сообщений остаётся в legacy-формате, часть переносится в CLDR-совместимые структуры.
Основным инструментом постепенной миграции становится слой адаптеров, который изолирует использование Globalize от остального кода.
Пример универсального форматтера:
class I18n {
constructor(locale) {
this.globalize = Globalize(locale);
}
formatNumber(value) {
return this.globalize.numberFormatter()(value);
}
formatDate(value) {
return this.globalize.dateFormatter({ date: "medium" })(value);
}
formatMessage(key, data) {
return this.globalize.messageFormatter(key)(data);
}
}
Дальнейшая миграция сводится к постепенному замещению внутренних реализаций методов этого класса без изменения его публичного интерфейса.
Переход на Globalize редко происходит сразу для всех типов форматирования. Типичный порядок миграции:
Такой порядок обусловлен степенью зависимости от бизнес-логики: числа и валюты обычно являются наиболее изолированными элементами, тогда как сообщения часто встроены в интерфейсные компоненты.
Для контроля миграции используется система флагов:
const useGlobalize = featureFlags.i18nGlobalize;
Флаг может применяться на уровне:
Это позволяет проводить частичную миграцию без нарушения стабильности всей системы.
В процессе миграции часто выявляются расхождения в форматах данных:
Date;Globalize требует строгой консистентности входных данных, поэтому вводится слой нормализации:
function normalizeDate(input) {
return input instanceof Date ? input : new Date(input);
}
Такой слой становится частью адаптера, минимизируя расхождения между legacy и новым кодом.
На этапе миграции интерфейс часто оказывается в состоянии смешанной локализации, когда разные компоненты используют разные механизмы форматирования.
Для устранения этого вводится правило приоритета:
При постепенной миграции важным становится уменьшение первоначального объёма загружаемых данных. Используется ленивое подключение локалей:
const localeCache = new Map();
async function getGlobalize(locale) {
if (!localeCache.has(locale)) {
await loadLocaleData(locale);
localeCache.set(locale, Globalize(locale));
}
return localeCache.get(locale);
}
Такой подход снижает нагрузку на старт приложения и позволяет масштабировать поддержку множества языков.
Проверка корректности перехода включает:
Часто используется режим двойного вычисления:
const legacyResult = legacyFormat(value);
const newResult = globalizeFormat(value);
if (legacyResult !== newResult) {
logMismatch(value, legacyResult, newResult);
}
Это позволяет выявлять расхождения до полного переключения системы.
После завершения миграции удаление старой системы происходит постепенно:
При этом сохраняется единая точка инициализации локализации, обеспечивающая консистентность всей системы форматирования.