Обработка ошибок

Природа ошибок в экосистеме FormatJS

Библиотека FormatJS и её ключевые компоненты (intl-messageformat, react-intl, @formatjs/intl, CLI-инструменты) опираются на стандарт ICU MessageFormat и API Intl в JavaScript. Это определяет особый класс ошибок: они возникают как на этапе компиляции сообщений, так и во время выполнения приложения.

Ошибки в FormatJS условно делятся на несколько категорий:

  • синтаксические ошибки ICU MessageFormat
  • ошибки отсутствующих сообщений локализации
  • ошибки параметров форматирования (date, number, plural)
  • ошибки окружения Intl
  • ошибки сборки и извлечения сообщений
  • ошибки интеграции с React (например, react-intl)

Каждая категория требует собственного подхода к обработке, поскольку часть проблем выявляется статически, а часть — только в рантайме.


Синтаксические ошибки ICU MessageFormat

ICU MessageFormat является основой строк локализации в FormatJS. Любое сообщение имеет строгий синтаксис:

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

Нарушение структуры приводит к ошибкам парсинга.

Типичные причины:

  • пропущенные фигурные скобки
  • некорректные селекторы (plural, select, number)
  • отсутствие fallback-ветки (other)
  • незакрытые блоки

Пример некорректного сообщения:

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

Результат — исключение парсера intl-messageformat при инициализации сообщения.

Внутренне такие ошибки часто проявляются как:

  • SyntaxError в ICU parser
  • FormatError при компиляции message AST

Стратегия обработки включает:

  • валидацию сообщений на этапе CI
  • использование @formatjs/cli для проверки синтаксиса
  • отказ от динамической генерации ICU-строк

Ошибки отсутствующих переводов

Одной из наиболее распространённых ситуаций является отсутствие ключа перевода в выбранной локали.

В react-intl это проявляется при вызове:

intl.formatMessage({ id: "app.title" })

Если сообщение отсутствует, поведение зависит от конфигурации:

  • использование defaultMessage
  • fallback на defaultLocale
  • выброс ошибки (в строгом режиме)

Типовые сценарии:

Отсутствие message id

При отсутствии ключа:

[React Intl] Missing message: "app.title" for locale "ru"

Отсутствие fallback-значения

Если defaultMessage не задан, результатом может быть:

  • возврат id
  • пустая строка
  • предупреждение в консоли

Строгий режим

Включение onError позволяет централизованно управлять ошибками:

const intl = createIntl({
  locale: "ru",
  messages,
  onError: (err) => {
    console.error(err);
  }
});

Ошибки параметров форматирования

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

Числовые параметры

intl.formatNumber(value)

Проблемные случаи:

  • value = undefined
  • value = "abc"
  • value = null

Результат:

  • RangeError
  • NaN в зависимости от реализации Intl.NumberFormat

Форматирование дат

intl.formatDate(date)

Ошибки:

  • некорректный объект Date
  • строка вместо Date
  • Invalid Date

Поведение:

  • выброс RangeError: Invalid time value
  • или fallback к текущей дате при обёртке

Plural rules и несовместимость значений

ICU plural rules зависят от локали. Ошибка возникает, если отсутствует обязательная форма.

Пример:

{count, plural, one {1 file}}

Отсутствует other, что делает сообщение невалидным для большинства локалей.

Результат:

  • ошибка компиляции MessageFormat
  • отказ рендеринга сообщения

Ошибки окружения Intl

FormatJS опирается на нативный Intl API. В средах с ограниченной поддержкой возникают критические сбои.

Отсутствие Intl API

Старые Node.js версии или специфические окружения могут не содержать:

  • Intl.NumberFormat
  • Intl.DateTimeFormat
  • Intl.PluralRules

В этом случае поведение:

  • падение приложения при инициализации
  • необходимость полифиллов (@formatjs/intl-pluralrules, @formatjs/intl-datetimeformat)

Неполная локализационная база

Некоторые среды имеют частичную поддержку локалей:

  • отсутствие ru-KZ
  • fallback на ru или en

Это влияет на:

  • plural rules
  • формат дат
  • отображение чисел

Ошибки react-intl в runtime

В React-интеграции ошибки часто проявляются на уровне компонентов.

MissingProviderError

Возникает при отсутствии IntlProvider:

[React Intl] Could not find required `intl` object

Причины:

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

Форматирование вне контекста локали

Если injectIntl или useIntl используется без провайдера:

  • intl равен undefined
  • вызовы методов приводят к runtime crash

Ошибки CLI-инструментов FormatJS

Инструменты @formatjs/cli используются для извлечения и проверки сообщений.

extract-errors

Типичные проблемы:

  • дублирующиеся id
  • некорректный AST ICU
  • нераспознанные конструкции

compile-errors

При компиляции JSON сообщений:

  • неверный JSON формат
  • несовместимость типов значений
  • некорректные ICU выражения

Стратегии централизованной обработки ошибок

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

Единая точка перехвата ошибок:

const intl = createIntl({
  locale: "ru",
  messages,
  onError: (err) => {
    if (err.code === "MISSING_MESSAGE") {
      return;
    }
    throw err;
  }
});

Позволяет:

  • подавлять некритичные ошибки
  • логировать отсутствующие переводы
  • сохранять стабильность UI

Fallback-механизмы

Типовые уровни fallback:

  1. message id
  2. defaultMessage
  3. base locale
  4. статическая строка

Валидация сообщений на этапе сборки

CI-подход включает:

  • проверку ICU синтаксиса
  • проверку наличия other в plural
  • сверку всех id с кодовой базой

Типизация и предотвращение ошибок

Использование TypeScript снижает количество ошибок:

  • строгие типы параметров сообщений
  • проверка наличия ключей
  • контроль типов дат и чисел

Пример типизированных сообщений:

type Messages = {
  "app.title": string;
  "items.count": (count: number) => string;
};

Ошибки при динамическом формировании сообщений

Динамическая генерация ICU строк является источником трудноотлавливаемых проблем.

Проблемные паттерны:

  • конкатенация ICU выражений
  • условная вставка plural блоков
  • runtime-формирование селекторов

Результат:

  • некорректный AST
  • ошибки парсера intl-messageformat

Обработка ошибок в серверном рендеринге

При SSR (например, Next.js) ошибки локализации особенно критичны.

Сценарии:

  • несинхронизированные messages между сервером и клиентом
  • различие локали при гидратации
  • отсутствие polyfill Intl на сервере

Подходы:

  • синхронизация сообщений через общий store
  • явная инициализация Intl на сервере
  • изоляция ошибок через try/catch на уровне renderToString

Логирование и наблюдаемость

Для устойчивых систем обработки ошибок применяются:

  • централизованные логгеры (Winston, Pino)
  • трассировка отсутствующих ключей
  • метрики частоты missing translations
  • группировка ошибок по locale и module

Типовые события:

  • translation_missing
  • icu_syntax_error
  • intl_runtime_failure

Поведение в деградированном режиме

При частичных сбоях система локализации может переходить в деградированный режим:

  • отображение ключей вместо текста
  • отключение plural-форматирования
  • упрощённый формат чисел и дат
  • использование базовой локали en

Такой режим предотвращает полное падение интерфейса при ошибках локализации.