Библиотека Globalize построена поверх экосистемы CLDR и использует сложную цепочку загрузки локалей, форматтеров и правил интернационализации. Ошибки в таких системах редко ограничиваются обычными синтаксическими проблемами. Наиболее частые причины сбоев связаны с:
Поэтому логирование и отладка становятся обязательной частью архитектуры приложений, использующих Globalize.
Globalize не содержит встроенных данных локализации. Все данные поставляются отдельно через CLDR JSON-файлы.
Пример ошибки:
Error: E_MISSING_CLDR: Missing required CLDR content `main/en/numbers`
Причина:
Globalize.load({});
или загрузка неполного набора данных.
Корректная инициализация:
const Globalize = require("globalize");
const cldrData = require("cldr-data");
Globalize.load(
cldrData.entireSupplemental(),
cldrData.entireMainFor("en")
);
Globalize.locale("en");
Если локаль не была зарегистрирована, попытка форматирования вызовет исключение.
Пример:
Globalize.locale("fr");
const formatter = Globalize.numberFormatter();
console.log(formatter(100));
При отсутствии французских CLDR-данных:
E_MISSING_CLDR
Полезно логировать список загруженных локалей:
console.log(Globalize.cldr);
Модуль globalize/message использует ICU
MessageFormat.
Некорректный шаблон:
"{name"
Приведёт к ошибке парсинга.
Диагностический код:
try {
const formatter = Globalize.messageFormatter("{name");
} catch (error) {
console.error("Ошибка MessageFormat:", error.message);
}
Одна из важнейших практик — фиксировать этапы запуска системы локализации.
Пример:
console.log("Загрузка CLDR...");
Globalize.load(data);
console.log("Установка локали...");
Globalize.locale("ru");
console.log("Создание форматтеров...");
Такой подход позволяет быстро определить точку сбоя.
При динамическом переключении языков полезно всегда фиксировать текущую локаль.
console.log("Текущая локаль:", Globalize.locale().locale);
Пример вывода:
Текущая локаль: ru
Ошибки форматирования часто возникают из-за неожиданного типа данных.
Пример:
function formatPrice(value) {
console.log("Тип значения:", typeof value);
console.log("Значение:", value);
return Globalize.numberFormatter({
style: "currency",
currency: "USD"
})(value);
}
Globalize активно использует исключения. Любые операции форматирования желательно оборачивать в обработчики ошибок.
try {
const formatter = Globalize.numberFormatter();
console.log(formatter("abc"));
} catch (error) {
console.error(error);
}
try {
const formatter = Globalize.dateFormatter({
datetime: "medium"
});
console.log(formatter(new Date()));
} catch (error) {
console.error("Ошибка даты:", error.message);
}
try {
const msg = Globalize.messageFormatter("hello");
console.log(msg());
} catch (error) {
console.error("Ошибка сообщений:", error);
}
Globalize использует объект CLDR для хранения всех локализационных данных.
Проверка:
const cldr = require("cldrjs");
console.log(cldr._resolved);
const cldr = Globalize.cldr;
console.log(
cldr.main("numbers")
);
Если результат:
undefined
значит раздел не был загружен.
Многие ошибки возникают из-за отсутствия supplemental-файлов.
Например:
Globalize.load(
require("cldr-data/supplemental/likelySubtags.json")
);
Без них могут не работать:
Диагностика числовых настроек:
const formatter = Globalize.numberFormatter({
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
console.log(formatter(10));
Результат:
10,00
Если формат неожиданен, следует проверить:
Проблемы с датами часто связаны с часовыми поясами.
const formatter = Globalize.dateFormatter({
skeleton: "yMMMd"
});
console.log(formatter(new Date()));
Для диагностики полезно логировать исходный объект даты:
console.log(date.toISOString());
const formatter = Globalize.relativeTimeFormatter("day");
console.log(formatter(-1));
Если вывод неверный:
В production-сборке сообщения об ошибках могут минимизироваться.
Для полноценной диагностики:
mode: "development",
devtool: "source-map"
export default defineConfig({
build: {
sourcemap: true
}
});
export default {
output: {
sourcemap: true
}
};
Source maps позволяют получать исходные строки ошибок вместо минифицированного кода.
Частая ошибка:
Globalize.locale("de");
const formatter = Globalize.numberFormatter();
до завершения загрузки CLDR.
Корректный подход:
async function initLocale(locale) {
const data = await loadLocale(locale);
Globalize.load(data);
Globalize.locale(locale);
console.log("Локаль готова:", locale);
}
console.log("CLDR загружен:", !!Globalize.cldr);
Интеграция с Winston:
const winston = require("winston");
const logger = winston.createLogger({
transports: [
new winston.transports.Console()
]
});
try {
Globalize.locale("ru");
} catch (error) {
logger.error(error.message);
}
Пример с Pino:
const pino = require("pino");
const logger = pino();
logger.info("Локаль установлена");
В браузере полезно использовать разные уровни логирования.
console.info("Информация");
console.warn("Предупреждение");
console.error("Ошибка");
console.debug("Отладка");
process.on("uncaughtException", (error) => {
console.error("Глобальная ошибка:", error);
});
window.oner ror = function(message, source, line) {
console.error(message);
};
Типичный стек:
E_MISSING_CLDR: Missing required CLDR content
at validate (...)
at numberFormatter (...)
Ключевые элементы:
Source maps особенно важны при production-debugging.
Пример ошибки без source maps:
app.min.js:1
С source maps:
src/i18n/globalize.js:42
Плохая практика:
function render(value) {
return Globalize.numberFormatter()(value);
}
Formatter создаётся каждый вызов.
Корректнее:
const formatter = Globalize.numberFormatter();
function render(value) {
return formatter(value);
}
console.time("format");
formatter(100000);
console.timeEnd("format");
Пример:
const formatter = Globalize.pluralGenerator();
console.log(formatter(1));
console.log(formatter(2));
console.log(formatter(5));
Результаты помогают проверить корректность pluralization.
const formatter = Globalize.messageFormatter(
"Привет, {name}"
);
console.log(
formatter({
name: "Alex"
})
);
console.log(
formatter({})
);
Может привести к:
undefined
или ошибкам шаблона.
function changeLocale(locale) {
console.log("Смена локали:", locale);
Globalize.locale(locale);
console.log(
"Активная локаль:",
Globalize.locale().locale
);
}
При использовании React проблемы часто возникают из-за повторных рендеров.
useEffect(() => {
console.log("Locale changed:", locale);
}, [locale]);
const formatter = useMemo(() => {
return Globalize.numberFormatter();
}, [locale]);
Без useMemo formatter может создаваться слишком
часто.
В server-side rendering нельзя хранить locale глобально.
Плохой пример:
Globalize.locale(req.locale);
При параллельных запросах возможны конфликты.
Безопаснее:
const instance = new Globalize(req.locale);
Пример с Jest:
test("currency formatting", () => {
const formatter = Globalize.currencyFormatter("USD");
expect(formatter(10))
.toMatchSnapshot();
});
const locales = ["en", "ru", "fr"];
locales.forEach(locale => {
Globalize.locale(locale);
console.log(
locale,
Globalize.formatNumber(1000)
);
});
Если formatter создаётся для тысяч локалей:
cache[locale] = Globalize(locale).numberFormatter();
кэш может бесконтрольно расти.
Диагностика:
console.log(
Object.keys(cache).length
);
import("./locale/ru.json")
.then(data => {
console.log("Locale loaded");
})
.catch(error => {
console.error(error);
});
Хорошая практика:
logger.error({
locale: "ru",
module: "currency",
message: error.message
});
Вместо:
console.log(error);
Структурированные логи проще анализировать в:
Пример с Sentry:
Sentry.captureException(error, {
extra: {
locale: Globalize.locale().locale
}
});
Рекомендуется логировать:
Плохо:
try {
formatter(value);
} catch {}
Ошибка теряется полностью.
Плохо:
console.log("render");
внутри каждого рендера React-компонента.
Плохо:
console.error(error);
Лучше:
console.error({
locale: "ru",
currency: "KZT",
error: error.message
});
Полезно создать единый слой работы с Globalize.
class I18nService {
setLocale(locale) {
console.log("Switch locale:", locale);
Globalize.locale(locale);
}
formatNumber(value) {
try {
return Globalize.formatNumber(value);
} catch (error) {
console.error(error);
return value;
}
}
}
Такой подход упрощает: