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

В экосистеме FormatJS обратная совместимость рассматривается как сочетание стабильности формата сообщений, предсказуемости API и контролируемой эволюции библиотек для интернационализации. Основная цель заключается в том, чтобы приложения, однажды внедрившие ICU MessageFormat и инфраструктуру форматирования, могли обновлять версии библиотек без переписывания текстов, шаблонов и значительной части логики локализации.


Стабильность ICU MessageFormat как фундамент совместимости

Ключевым элементом совместимости выступает ICU MessageFormat. Синтаксис сообщений в FormatJS опирается на стандарт ICU, который изначально проектировался как кросс-языковая система форматирования.

Базовая устойчивость синтаксиса

Сообщения вида:

Hello, {name}!

или более сложные конструкции:

{count, plural,
  one {# item}
  other {# items}
}

сохраняют совместимость между версиями библиотек, поскольку:

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

CLDR как источник неизменяемых правил

Библиотека использует данные Unicode CLDR для правил локализации. Это означает:

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

Совместимость между версиями formatjs runtime

Внутренние пакеты runtime (например, intl-messageformat) развиваются с учётом строгих контрактов:

  • вход: строка ICU-сообщения + набор переменных;
  • выход: локализованная строка;
  • побочные эффекты отсутствуют.

Это позволяет обеспечивать совместимость даже при изменении внутренних алгоритмов форматирования.

Изоляция внутреннего парсера

Парсер сообщений может меняться между версиями, но:

  • AST (абстрактное синтаксическое дерево) не экспонируется наружу;
  • публичный API остаётся неизменным;
  • сериализация сообщений обратно в строку не требуется.

Совместимость React-интеграции

В связке с React широко используется React Intl, который является обёрткой над core FormatJS API.

Модель неизменяемых компонентов

Компоненты:

<FormattedMessage id="app.title" defaultMessage="Hello world" />

сохраняют поведение между версиями благодаря следующим принципам:

  • id остаётся ключевым контрактом;
  • defaultMessage используется как fallback без зависимости от сборки;
  • форматирование происходит через стабильный runtime.

Минимизация breaking changes

При переходах между major-версиями:

  • изменения чаще касаются TypeScript типов, а не runtime;
  • устаревшие API помечаются deprecated перед удалением;
  • сохранение поведения форматирования считается приоритетом.

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

Одним из критических факторов является поддержка Intl в JavaScript.

Нативный Intl vs polyfill

FormatJS использует:

  • нативный Intl в современных средах;
  • полифиллы для старых браузеров и Node.js окружений.

Типичная схема:

  • если Intl.PluralRules отсутствует → подключается polyfill;
  • если Intl.NumberFormat ограничен → расширяется shim-реализацией.

Контроль версий polyfill

Пакеты вида @formatjs/intl-* проектируются так, чтобы:

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

Совместимость при сборке и транспиляции

Система сборки сообщений через Babel и CLI-инструменты играет ключевую роль в стабильности.

Message extraction и стабильные AST

Инструменты извлечения сообщений:

  • анализируют исходный код;
  • формируют JSON-структуры сообщений;
  • не зависят от runtime-версии FormatJS.

Пример результата:

{
  "app.greeting": {
    "defaultMessage": "Hello {name}",
    "description": "Greeting message"
  }
}

Эта структура сохраняется между версиями CLI.


Версионирование и стратегия изменений

Semantic Versioning в FormatJS

Экосистема придерживается semver-подхода:

  • patch: исправления форматирования, багфиксы CLDR;
  • minor: добавление новых функций без изменения поведения;
  • major: потенциально breaking изменения API.

Контракт на поведение сообщений

Основное правило совместимости:

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

Даже при внутренних изменениях алгоритмов результат нормализуется под CLDR-правила.


Совместимость между браузерами и Node.js

Различия окружений

Проблемы обратной совместимости часто возникают не в самой библиотеке, а в среде выполнения:

  • разные версии Node.js имеют разные уровни Intl поддержки;
  • старые браузеры требуют полифиллов;
  • server-side rendering может использовать ICU-lite сборки.

Унификация поведения

FormatJS компенсирует различия:

  • единая точка форматирования;
  • детектирование возможностей окружения;
  • fallback-цепочки для Intl API.

Стабильность типов и TypeScript-слой

В TypeScript-экосистеме обратная совместимость поддерживается через:

  • расширяемые интерфейсы сообщений;
  • генерацию типов из JSON каталогов;
  • минимизацию breaking changes в типах props.

Пример типовой структуры:

type Messages = {
  "app.title": string;
  "app.count": number;
};

Изменения в типах происходят аккуратно, чтобы не ломать существующие проекты при обновлении minor-версий.


Совместимость message formats и расширений ICU

FormatJS расширяет ICU, добавляя:

  • вложенные форматтеры;
  • селекторы;
  • кастомные форматы дат и чисел.

Несмотря на расширения:

  • базовый ICU синтаксис не изменяется;
  • расширения добавляются как надстройки;
  • старые сообщения продолжают корректно интерпретироваться.

Обратная совместимость и кэширование сообщений

В продакшн-системах используется кэширование:

  • сериализованные сообщения;
  • precompiled ICU AST;
  • локализованные словари.

FormatJS обеспечивает:

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

Миграции без нарушения контрактов

Эволюция между версиями сопровождается механиками мягкой миграции:

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

Типичный сценарий:

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

Совместимость локалей и данных CLDR

CLDR обновляется регулярно, что влияет на:

  • правила множественных форм;
  • форматирование дат;
  • валютные обозначения.

FormatJS минимизирует риск несовместимости:

  • обновления CLDR не изменяют API;
  • изменения локалей отражаются только в результатах форматирования;
  • поведение старых сообщений остаётся корректным.

Контракт стабильности форматирования

Главный принцип совместимости можно выразить как:

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

Это позволяет сохранять предсказуемость поведения при обновлениях библиотек и инфраструктуры интернационализации.