Проблемы локализации в приложениях часто проявляются не как явные ошибки, а как «тихие» расхождения в отображении данных: разные форматы дат, неожиданное округление чисел, некорректные валютные символы, смещённые временные зоны. Библиотека Intl API в JavaScript предоставляет инструменты для стандартизированной работы с локалями, но без системного логирования её поведения диагностика становится затруднительной.
Любой объект Intl после инициализации может возвращать информацию о том, какие параметры были реально применены. Это критично, поскольку запрошенная локаль не всегда совпадает с фактически использованной.
const formatter = new Intl.NumberFormat('ru-KZ');
console.log(formatter.resolvedOptions());
Результат содержит ключевые поля:
Логирование resolvedOptions() позволяет фиксировать
расхождения между ожидаемыми и реальными настройками:
const formatter = new Intl.DateTimeFormat('fr-FR', {
timeZone: 'Asia/Almaty'
});
const options = formatter.resolvedOptions();
console.log(JSON.stringify({
requestedLocale: 'fr-FR',
resolvedLocale: options.locale,
timeZone: options.timeZone
}));
Такой подход позволяет обнаруживать случаи fallback-локалей, когда запрошенная локаль недоступна в среде выполнения.
Перед использованием локали полезно фиксировать её каноническую форму. Это снижает риск несоответствий между сервером и клиентом.
const locales = Intl.getCanonicalLocales(['ru-kz', 'RU-KZ', 'ru']);
console.log(locales);
Функция Intl.getCanonicalLocales помогает:
Логирование до и после нормализации позволяет отслеживать ошибки пользовательского ввода или конфигурации.
Ошибки в числовом представлении часто связаны с разделителями,
округлением и валютами. Intl.NumberFormat предоставляет способ
детализировать результат через formatToParts.
const formatter = new Intl.NumberFormat('de-DE', {
style: 'currency',
currency: 'EUR'
});
const parts = formatter.formatToParts(123456.78);
console.log(parts);
Для логирования важно не только итоговое значение, но и структура:
function logNumberFormatting(value, locale, options) {
const formatter = new Intl.NumberFormat(locale, options);
console.log(JSON.stringify({
input: value,
locale,
resolved: formatter.resolvedOptions(),
formatted: formatter.format(value),
parts: formatter.formatToParts(value)
}));
}
Разбор formatToParts позволяет выявить:
Intl.DateTimeFormat чувствителен к часовым поясам, системным настройкам и политике окружения. Ошибки часто проявляются как «сдвиги» даты или времени.
const dtf = new Intl.DateTimeFormat('en-GB', {
timeZone: 'UTC',
dateStyle: 'full',
timeStyle: 'short'
});
console.log(dtf.format(new Date()));
console.log(dtf.resolvedOptions());
При логировании важно фиксировать:
function logDateFormatting(date, locale, options) {
const formatter = new Intl.DateTimeFormat(locale, options);
console.log(JSON.stringify({
inputTimestamp: date.getTime(),
iso: date.toISOString(),
localeRequested: locale,
localeResolved: formatter.resolvedOptions().locale,
timeZone: formatter.resolvedOptions().timeZone,
output: formatter.format(date)
}));
}
Такой лог помогает выявлять:
Intl API использует цепочки fallback, если конкретная локаль недоступна. Это может приводить к неожиданным результатам, особенно в минималистичных средах выполнения.
const f = new Intl.NumberFormat('xx-YY');
console.log(f.resolvedOptions().locale);
Если локаль недоступна, система может заменить её на базовую
(например, en-US). Без логирования это поведение остаётся
незаметным.
Практика фиксации:
function createFormatter(locale, options) {
const formatter = new Intl.NumberFormat(locale, options);
const resolved = formatter.resolvedOptions().locale;
if (resolved !== locale) {
console.warn(JSON.stringify({
message: 'Locale fallback occurred',
requested: locale,
resolved
}));
}
return formatter;
}
Intl.Collator часто используется для сортировки, но различия в локалях могут радикально менять порядок элементов.
const collator = new Intl.Collator('tr', { sensitivity: 'base' });
console.log(['i', 'I', 'İ', 'ı'].sort(collator.compare));
Логирование важно для:
function logSorting(locale, array) {
const collator = new Intl.Collator(locale);
console.log(JSON.stringify({
locale,
input: array,
output: [...array].sort(collator.compare),
resolved: collator.resolvedOptions().locale
}));
}
Одной из скрытых проблем является различие ICU-данных между средами:
Это приводит к тому, что одна и та же локаль может давать разные результаты форматирования.
Логирование должно включать идентификацию среды:
function logIntlEnvironment() {
const nf = new Intl.NumberFormat('ru-RU');
console.log(JSON.stringify({
engine: typeof process !== 'undefined' ? 'node' : 'browser',
locale: nf.resolvedOptions().locale,
hasIntl: typeof Intl !== 'undefined'
}));
}
Эффективный подход — единый формат логов для всех Intl-операций.
function intlLog(event, payload) {
console.log(JSON.stringify({
event,
timestamp: Date.now(),
...payload
}));
}
Использование:
const formatter = new Intl.NumberFormat('ru-KZ');
intlLog('number_format', {
requested: 'ru-KZ',
resolved: formatter.resolvedOptions().locale,
sample: formatter.format(12345.67)
});
Такой формат позволяет:
Одной из типичных проблем является логирование только итоговой строки без контекста:
console.log(new Intl.DateTimeFormat('ru-RU').format(new Date()));
Такой лог не содержит информации о:
Другая ошибка — игнорирование formatToParts, из-за чего
теряется структура результата и становится невозможным анализ причин
визуальных расхождений.
Также часто недооценивается влияние окружения: одинаковый код может давать разные результаты на сервере и клиенте, особенно при серверном рендеринге.
В приложениях с SSR критично фиксировать совпадение локалей между рендерами.
function compareIntlOnServerAndClient(locale) {
const server = new Intl.NumberFormat(locale).resolvedOptions().locale;
// имитация клиентского окружения
const client = new Intl.NumberFormat(locale).resolvedOptions().locale;
intlLog('ssr_locale_check', {
server,
client,
match: server === client
});
}
Даже при совпадении значений полезно логировать обе стороны для будущей диагностики.
Некоторые среды используют сложные цепочки замены локалей. Это может приводить к неожиданным региональным форматам.
function traceLocaleFallback(locale) {
const formatter = new Intl.DateTimeFormat(locale);
const resolved = formatter.resolvedOptions().locale;
intlLog('locale_fallback_trace', {
requested: locale,
resolved
});
}
Регулярное накопление таких логов позволяет выявлять системные несоответствия конфигурации локалей и ICU-пакетов.