Обратная совместимость

Эволюция API и причины несовместимости

Библиотека Globalize в экосистеме JavaScript прошла несколько этапов развития, каждый из которых сопровождался существенными изменениями архитектуры и API. Наиболее заметный разрыв связан с переходом от версии, основанной на форматировании через локальные данные jQuery UI, к современной реализации, использующей стандартизированные данные CLDR (Unicode Common Locale Data Repository).

Ключевые причины несовместимости между версиями:

  • переход от частично встроенных локалей к полной зависимости от CLDR;
  • отказ от синхронной загрузки локализационных данных в пользу модульной структуры;
  • изменение модели форматирования (строки формата заменены на ICU-подобные паттерны);
  • пересмотр API чисел, дат и валют;
  • переход на явную инициализацию локалей вместо неявного поведения.

Каждое из этих изменений направлено на повышение предсказуемости и соответствие международным стандартам, однако приводит к необходимости адаптации существующего кода.


Основные поколения Globalize и точки разрыва

Globalize до версии 0.x

Ранние версии ориентировались на интеграцию с jQuery и использовали упрощённую модель локализации:

  • данные локали часто встраивались частично;
  • форматирование дат и чисел выполнялось через ограниченный набор шаблонов;
  • отсутствовала строгая зависимость от CLDR;
  • поведение было тесно связано с браузерной средой.

Типичный код:

$.global.format(1234.56, "n2");
$.global.format(new Date(), "D");

Проблемы данной модели:

  • отсутствие единых правил локализации;
  • ограниченная поддержка региональных особенностей;
  • невозможность масштабирования на большое количество языков;
  • зависимость от jQuery как обязательного слоя.

Globalize 1.x и переход к CLDR

С версии 1.x архитектура была полностью переработана. Основой стала библиотека CLDR, предоставляющая стандартизированные данные о локалях.

Основные изменения:

  • отказ от jQuery-зависимости;
  • введение явной загрузки CLDR-данных;
  • разделение функциональности на модули;
  • использование ICU-подобных шаблонов;
  • асинхронная подготовка окружения локали.

Пример современного подхода:

Globalize.load(
  require("cldr-data").entireSupplemental(),
  require("cldr-data").entireMainFor("ru")
);

Несовместимость API как структурная особенность

Изменение модели инициализации

Старый подход допускал неявную локализацию:

  • локаль определялась автоматически;
  • данные могли подгружаться частично;
  • поведение зависело от окружения.

Современная модель требует явной подготовки:

Globalize.locale("ru");

Перед этим необходимо загрузить соответствующие CLDR-данные. Отсутствие данных приводит к исключениям или деградации функциональности.


Форматы чисел

Существенные изменения затронули форматирование чисел.

Ранее:

$.global.format(12345.67, "n2");

Современный вариант:

Globalize.numberFormatter({ minimumFractionDigits: 2 })(12345.67);

Различия:

  • строковые паттерны заменены объектами конфигурации;
  • добавлена поддержка расширенных правил округления;
  • поведение строго привязано к локали;
  • устранены неоднозначности форматов.

Форматы дат

Старые версии использовали фиксированные обозначения:

  • “d”, “D”, “t”, “T”.

Новая модель опирается на CLDR:

Globalize.dateFormatter({ datetime: "short" })(new Date());

Изменения:

  • унификация форматов между языками;
  • разделение date, time и datetime;
  • расширенная настройка календарей;
  • поддержка нестандартных локалей.

Стратегии обеспечения обратной совместимости

Обёртки над старым API

Один из подходов заключается в создании адаптеров, имитирующих старое поведение поверх новой версии.

Пример концептуальной обёртки:

function formatNumberLegacy(value, format) {
  if (format === "n2") {
    return Globalize.numberFormatter({ minimumFractionDigits: 2 })(value);
  }
}

Такие адаптеры:

  • снижают затраты на миграцию;
  • позволяют поэтапно заменять устаревший код;
  • увеличивают поддерживаемость старых проектов.

Миграционные слои

В крупных приложениях используется промежуточный слой локализации:

  • единая точка доступа к форматированию;
  • изоляция зависимости от Globalize;
  • возможность замены реализации без изменения бизнес-кода.

Пример структуры:

/i18n
  formatter.js
  date.js
  number.js

Этот слой:

  • скрывает различия версий;
  • позволяет тестировать локализацию отдельно;
  • упрощает поддержку нескольких библиотек.

Поддержка параллельных версий

В некоторых системах допускается одновременное использование старой и новой версии Globalize:

  • legacy-модули используют старый API;
  • новые модули переходят на CLDR-основу;
  • общий слой маршрутизации определяет, какая версия используется.

Риски такого подхода:

  • увеличение размера бандла;
  • дублирование локализационных данных;
  • усложнение отладки.

Проблемы миграции между версиями

Несовпадение форматов

Одной из наиболее частых проблем становится различие в интерпретации форматов:

  • старые паттерны не имеют прямых аналогов;
  • поведение округления может отличаться;
  • разные правила разделителей тысяч и десятичных знаков.

Отсутствие автоматического преобразования

Переход между API не поддерживает автоматическую трансляцию:

  • строковые форматы не конвертируются в ICU-паттерны;
  • конфигурационные объекты требуют ручной настройки;
  • поведение локали зависит от загруженных CLDR-данных.

Различия в загрузке данных

Старый подход:

  • локали часто включены в сборку;
  • нет строгой структуры данных.

Новый подход:

  • обязательная загрузка main + supplemental данных CLDR;
  • строгая зависимость от версии данных;
  • необходимость синхронизации версий CLDR и Globalize.

Подходы к снижению затрат на переход

Инкапсуляция форматирования

Выделение всех операций локализации в отдельный слой позволяет:

  • ограничить распространение устаревших API;
  • централизовать изменения;
  • упростить тестирование.

Использование фасадов

Фасадный слой скрывает различия между версиями:

const i18n = {
  formatNumber: (value) => Globalize.numberFormatter()(value),
  formatDate: (date) => Globalize.dateFormatter()(date)
};

Фасады обеспечивают:

  • стабильный интерфейс;
  • независимость бизнес-логики;
  • возможность замены реализации.

Инкрементальная миграция

Миграция выполняется поэтапно:

  • выделение модулей локализации;
  • замена форматирования чисел;
  • переход на даты;
  • финальное удаление legacy-слоя.

Каждый этап снижает риск регрессий и упрощает контроль изменений.


Влияние обратной совместимости на архитектуру приложений

Переход между версиями Globalize оказывает влияние на структуру приложения:

  • усиливается модульность;
  • вводится явная зависимость от локализационного слоя;
  • уменьшается количество неявных глобальных состояний;
  • повышается предсказуемость поведения в разных регионах.

Архитектура становится более строгой, но требует дисциплины при управлении зависимостями и локализационными данными.