Globalize работает поверх данных CLDR и предоставляет единый слой для форматирования и парсинга данных в зависимости от активной локали. При масштабировании приложения с поддержкой нескольких языков и регионов возникает отдельный слой задач — фиксация того, какие локали фактически используются в рантайме, как часто происходит переключение, и какие форматы применяются в различных частях интерфейса.
Отслеживание использования локалей в приложениях на Globalize становится частью инфраструктуры интернационализации и используется не только для аналитики, но и для диагностики, оптимизации загрузки CLDR-данных и управления кэшированием.
В Globalize локаль представляет собой строковый идентификатор вида
en, en-US, ru,
fr-FR. Она влияет на:
Ключевая точка управления локалью — глобальное состояние:
Globalize.locale("ru");
Именно изменение этого состояния становится первичной точкой отслеживания использования локалей. Любое решение о наблюдении строится вокруг перехвата или обёртки этой операции.
Базовый механизм фиксации смены локали строится через обёртку над
Globalize.locale.
import Globalize from "globalize";
const localeUsageLog = [];
const originalLocale = Globalize.locale;
Globalize.locale = function (locale) {
const previous = originalLocale.call(Globalize);
if (locale !== undefined) {
localeUsageLog.push({
from: previous,
to: locale,
timestamp: Date.now()
});
}
return originalLocale.call(Globalize, locale);
};
В данной схеме фиксируются:
Такой подход формирует базовую телеметрию переключений без изменения внутренней логики библиотеки.
Во многих приложениях локаль не только устанавливается, но и запрашивается:
const current = Globalize.locale();
Для фиксации фактического использования вводится прокси-слой:
let lastAccessLog = null;
const originalLocaleGetter = Globalize.locale;
Globalize.locale = function (locale) {
if (locale === undefined) {
lastAccessLog = {
locale: originalLocale.call(Globalize),
timestamp: Date.now(),
type: "read"
};
}
return originalLocale.call(Globalize, locale);
};
Это позволяет различать:
Локаль фактически проявляется не только при установке, но и при вызовах форматеров:
Globalize.dateFormatterGlobalize.numberFormatterGlobalize.currencyFormatterGlobalize.messageFormatterКаждый из этих методов может быть обёрнут для регистрации использования конкретной локали.
const formatUsage = [];
function trackFormatter(methodName, originalMethod) {
return function (...args) {
const formatter = originalMethod.apply(this, args);
return function (value) {
const result = formatter(value);
formatUsage.push({
method: methodName,
locale: Globalize.locale(),
timestamp: Date.now()
});
return result;
};
};
}
Globalize.numberFormatter = trackFormatter(
"numberFormatter",
Globalize.numberFormatter
);
Globalize.dateFormatter = trackFormatter(
"dateFormatter",
Globalize.dateFormatter
);
Такая модель позволяет фиксировать:
Собранные данные формируют структуру наблюдений:
const localeStats = {};
function registerLocale(locale, feature) {
if (!localeStats[locale]) {
localeStats[locale] = {
number: 0,
date: 0,
currency: 0,
message: 0
};
}
localeStats[locale][feature]++;
}
Интеграция с форматерами:
function trackFormatter(methodName, originalMethod, featureKey) {
return function (...args) {
const formatter = originalMethod.apply(this, args);
return function (value) {
const result = formatter(value);
registerLocale(Globalize.locale(), featureKey);
return result;
};
};
}
Результатом становится распределение:
Globalize требует предварительной загрузки CLDR сегментов. Этот процесс также может быть наблюдаемым:
const cldrLoadLog = [];
function trackCldrLoad(fn) {
return async function (data) {
cldrLoadLog.push({
size: JSON.stringify(data).length,
timestamp: Date.now()
});
return fn(data);
};
}
Применение:
Globalize.load = trackCldrLoad(Globalize.load);
Фиксируются:
Для оценки поведения интерфейса используется граф переходов:
const transitions = {};
function recordTransition(from, to) {
const key = `${from} -> ${to}`;
if (!transitions[key]) {
transitions[key] = 0;
}
transitions[key]++;
}
Интеграция с перехватом Globalize.locale:
Globalize.locale = function (locale) {
const current = originalLocale.call(Globalize);
if (locale) {
recordTransition(current, locale);
}
return originalLocale.call(Globalize, locale);
};
Это позволяет выявлять:
При сложной архитектуре приложения локали могут различаться по модулям:
Для этого вводится контекст:
let currentContext = "global";
function setLocaleContext(context) {
currentContext = context;
}
И расширение логирования:
function registerLocale(locale, feature) {
const key = `${currentContext}:${locale}`;
if (!localeStats[key]) {
localeStats[key] = {};
}
localeStats[key][feature] =
(localeStats[key][feature] || 0) + 1;
}
Таким образом локаль перестаёт быть глобальной сущностью и становится контекстной характеристикой.
Для оценки качества интернационализации вводятся метрики:
Пример расчёта средней продолжительности:
function calculateAverageDuration(log) {
let total = 0;
for (let i = 1; i < log.length; i++) {
total += log[i].timestamp - log[i - 1].timestamp;
}
return total / (log.length - 1);
}
Отслеживание локалей позволяет выявлять:
Такая диагностика строится на агрегированных логах, собранных из всех точек перехвата.
Собранные данные обычно направляются в единый лог-слой:
function flushLocaleLogs() {
sendToAnalytics({
transitions,
localeUsageLog,
formatUsage,
localeStats
});
}
Передача может выполняться:
Отслеживание локалей тесно связано с кэшированием форматеров:
const formatterCache = new Map();
function getNumberFormatter(locale) {
if (!formatterCache.has(locale)) {
Globalize.locale(locale);
formatterCache.set(locale, Globalize.numberFormatter());
}
return formatterCache.get(locale);
}
Логирование позволяет контролировать:
Собранные данные могут быть связаны с действиями:
Это достигается через расширение контекста событий:
function trackAction(action, locale) {
localeEventLog.push({
action,
locale,
timestamp: Date.now()
});
}
Анализ логов позволяет выделить типовые паттерны:
Каждый паттерн отражается в графе переходов и распределении частот использования.
Результаты отслеживания используются для:
Такая оптимизация опирается не на конфигурацию, а на реальные данные использования локалей в Globalize.