При использовании Globalize в приложениях с модульной сборкой ключевую роль играет корректная интеграция с Rollup, поскольку библиотека опирается на внешние CLDR-данные, имеет модульную структуру и требует аккуратной настройки tree-shaking и загрузки культурных файлов.
Globalize построен как набор независимых модулей, которые подключаются по мере необходимости: форматирование чисел, дат, сообщений, работа с CLDR и выбор локалей. Это означает, что при сборке Rollup не должен объединять всё в единый тяжёлый бандл без контроля, иначе теряется смысл модульности.
Основная сложность заключается в двух аспектах:
Rollup в связке с Globalize требует строгого контроля импортов: любые
«широкие» импорты вида import * as Globalize ухудшают
оптимизацию и увеличивают размер сборки.
Базовый набор включает сам Globalize, Rollup и плагины для работы с node_modules:
npm install globalize
npm install rollup @rollup/plugin-node-resolve @rollup/plugin-commonjs
Дополнительно для обработки JSON (CLDR-данные поставляются в JSON-формате):
npm install @rollup/plugin-json
Если используется TypeScript:
npm install typescript @rollup/plugin-typescript
Типичная структура при работе с Globalize:
src/
index.js
i18n/
globalize.js
cldr-data.js
node_modules/
rollup.config.js
Отдельное выделение i18n-слоя позволяет изолировать всю работу с локализацией и не смешивать её с бизнес-логикой.
Минимальная конфигурация для сборки приложения с Globalize:
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import json from '@rollup/plugin-json';
export default {
input: 'src/index.js',
output: {
file: 'dist/bundle.js',
format: 'esm',
sourcemap: true
},
plugins: [
json(),
resolve({
browser: true
}),
commonjs()
]
};
Ключевой момент — подключение @rollup/plugin-json, без
которого CLDR-данные не будут корректно импортироваться.
Globalize не включает данные локалей по умолчанию. Они должны быть импортированы вручную.
Пример загрузки минимального набора данных:
import Globalize from 'globalize';
import likelySubtags from 'cldr-data/supplemental/likelySubtags.json';
import currencyData from 'cldr-data/supplemental/currencyData.json';
import timeData from 'cldr-data/supplemental/timeData.json';
import numbers from 'cldr-data/main/ru/numbers.json';
import currencies from 'cldr-data/main/ru/currencies.json';
import caGregorian from 'cldr-data/main/ru/ca-gregorian.json';
import dateFields from 'cldr-data/main/ru/dateFields.json';
Globalize.load(
likelySubtags,
currencyData,
timeData,
numbers,
currencies,
caGregorian,
dateFields
);
Globalize.locale('ru');
Такая схема позволяет точно контролировать объём данных и исключает попадание лишних локалей в финальный бандл.
Чтобы Rollup корректно оптимизировал код, инициализация Globalize должна быть вынесена в отдельный модуль:
// src/i18n/globalize.js
import Globalize from 'globalize';
export function initLocale(locale = 'ru') {
Globalize.locale(locale);
return Globalize;
}
export default Globalize;
Это позволяет избежать повторной инициализации и упрощает тестирование.
Rollup эффективно удаляет неиспользуемый код только при условии, что импортируется конкретная функциональность:
Правильный вариант:
import formatDate from 'globalize/date';
import formatNumber from 'globalize/number';
Нежелательный вариант:
import Globalize from 'globalize';
Во втором случае Rollup часто сохраняет больше кода, чем требуется, поскольку не может точно определить используемые внутренние модули.
Globalize сильно зависит от CLDR, поэтому основной вес приложения формируется именно данными локализации.
Стратегии оптимизации:
Пример ленивой загрузки:
export async function loadRussianLocale() {
const [
likelySubtags,
numbers,
currencies,
caGregorian,
dateFields
] = await Promise.all([
import('cldr-data/supplemental/likelySubtags.json'),
import('cldr-data/main/ru/numbers.json'),
import('cldr-data/main/ru/currencies.json'),
import('cldr-data/main/ru/ca-gregorian.json'),
import('cldr-data/main/ru/dateFields.json')
]);
const Globalize = (await import('globalize')).default;
Globalize.load(
likelySubtags.default,
numbers.default,
currencies.default,
caGregorian.default,
dateFields.default
);
Globalize.locale('ru');
return Globalize;
}
Такой подход уменьшает начальный размер бандла и переносит загрузку локализации на этап выполнения.
Rollup позволяет создавать несколько выходных файлов, каждый из которых содержит свою локаль:
export default [
{
input: 'src/locales/ru.js',
output: {
file: 'dist/ru.js',
format: 'esm'
},
plugins: [resolve(), commonjs(), json()]
},
{
input: 'src/locales/en.js',
output: {
file: 'dist/en.js',
format: 'esm'
},
plugins: [resolve(), commonjs(), json()]
}
];
Такое разделение удобно для приложений с динамическим переключением языка без пересборки основного кода.
При использовании CommonJS-версий зависимостей Globalize иногда
возникают проблемы интероперабельности. Решаются они настройкой
commonjs():
commonjs({
include: 'node_modules/**',
transformMixedEsModules: true
})
Важно следить за порядком плагинов: json() должен идти
до commonjs(), иначе JSON-модули могут быть обработаны
некорректно.
При масштабных проектах удобно инкапсулировать CLDR-данные в виртуальные модули:
// rollup plugin example
export function cldrVirtualPlugin() {
return {
name: 'cldr-virtual',
resolveId(id) {
if (id === 'virtual:cldr-ru') return id;
},
load(id) {
if (id === 'virtual:cldr-ru') {
return `
import numbers from 'cldr-data/main/ru/numbers.json';
export default { numbers };
`;
}
}
};
}
Это позволяет централизовать управление локалями и упрощает переиспользование.
Некорректная настройка Rollup и Globalize часто приводит к следующим проблемам:
Globalize is not defined locale data при вызове
форматирования;Большинство этих проблем связано не с самой библиотекой, а с тем, как Rollup обрабатывает зависимости.
Для production-сборки добавляются дополнительные оптимизации:
import terser from '@rollup/plugin-terser';
export default {
input: 'src/index.js',
output: {
file: 'dist/app.min.js',
format: 'esm',
sourcemap: false
},
plugins: [
json(),
resolve({
browser: true,
preferBuiltins: false
}),
commonjs({
transformMixedEsModules: true
}),
terser()
]
};
Минификация имеет смысл только после корректной настройки локалей, иначе диагностика ошибок становится затруднительной.
При построении системы локализации на базе Globalize и Rollup важно соблюдать несколько структурных принципов:
Такая архитектура позволяет сохранять предсказуемость поведения локализации при масштабировании приложения и добавлении новых языков.