Фолбэк стратегии

В основе стратегии фолбэка в FormatJS лежит построение цепочки локалей (locale chain), по которой система пытается найти подходящее сообщение.

Типичный порядок разрешения локали:

  1. Полная локаль (ru-KZ)
  2. Базовая локаль (ru)
  3. Язык по умолчанию приложения (en)
  4. Явно заданный fallback locale
  5. Встроенное значение defaultMessage (если используется react-intl)
  6. Пустая строка или ключ сообщения (в зависимости от конфигурации)

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


Фолбэк сообщений в ICU MessageFormat

FormatJS использует ICU MessageFormat как базовый синтаксис сообщений. Если сообщение отсутствует или некорректно определено, применяется несколько уровней восстановления.

Отсутствующий ключ сообщения

Если ключ не найден:

  • используется defaultMessage (если задан)
  • иначе возвращается ID сообщения
  • при строгом режиме может быть выброшено исключение

Пример поведения:

intl.formatMessage(
  { id: 'user.profile.title', defaultMessage: 'Profile' }
)

Если перевод отсутствует, будет использовано defaultMessage.


Стратегии через defaultMessage

defaultMessage выполняет роль встроенного фолбэка на уровне компонента или вызова API.

Особенности:

  • используется как резервный текст
  • может содержать ICU-синтаксис
  • участвует в извлечении сообщений (@formatjs/cli)

Пример:

formatMessage({
  id: 'cart.items.count',
  defaultMessage: 'Items: {count}'
}, { count: 3 })

При отсутствии перевода значение остаётся работоспособным без внешних ресурсов локализации.


Fallback locale и конфигурация IntlProvider

В React Intl ключевая роль фолбэка задаётся через конфигурацию провайдера:

<IntlProvider locale="ru-KZ" defaultLocale="en">

Параметры:

  • locale — текущая локаль пользователя
  • defaultLocale — язык, используемый при отсутствии переводов

При разрешении сообщений система перебирает доступные словари по приоритету локалей.


Поведение при частично отсутствующих переводах

Часто встречается ситуация, когда часть ключей переведена, а часть нет. FormatJS применяет точечный фолбэк:

  • отсутствующий ключ → fallback
  • существующий ключ → локализованное значение
  • разные ключи внутри одного namespace могут иметь разные источники

Это позволяет постепенно внедрять локализацию без полной готовности всех ресурсов.


Фолбэк в ICU-выражениях (plural, select)

ICU-конструкции могут содержать ветки other, zero, one, few и т.д. Фолбэк здесь встроен в сам стандарт ICU.

Пример:

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

Если конкретная форма не поддерживается текущей локалью, используется other как универсальный резервный вариант.


Нестандартные и ошибочные сообщения

При ошибках форматирования (например, синтаксическая ошибка ICU):

  • в development режиме выводится диагностическое сообщение
  • в production часто используется фолбэк на исходный текст или ID
  • возможна замена через error handler

Типичные ошибки:

  • незакрытые скобки {
  • некорректные селекторы plural
  • отсутствие параметров интерполяции

Обработка через onError

FormatJS предоставляет централизованную стратегию перехвата ошибок форматирования.

const intl = createIntl({
  locale: 'ru',
  defaultLocale: 'en',
  messages,
  onError: (err) => {
    console.warn(err)
  }
})

Через onError реализуются стратегии:

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

Fallback на уровне formatMessage

Поведение formatMessage можно считать базовой точкой фолбэка:

Порядок:

  1. Найти сообщение по id
  2. Если найдено — применить ICU форматирование
  3. Если не найдено — использовать defaultMessage
  4. Если отсутствует и он — вернуть id

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

В крупных приложениях применяется агрегация сообщений:

  • базовый словарь (en)
  • региональный словарь (en-GB, en-US)
  • feature-specific словари
  • динамические загрузки (code splitting)

При этом fallback работает между слоями словарей:

feature messages → base locale → default locale → defaultMessage

Асинхронные фолбэки при ленивой загрузке

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

  • словарь ещё не загружен
  • частично загружен
  • ошибка загрузки

Стратегии обработки:

  • временный fallback locale
  • отображение defaultMessage
  • кеширование последнего успешного словаря
  • повторная попытка загрузки

Фолбэк чисел и дат через Intl API

FormatJS опирается на нативный Intl:

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

При отсутствии поддержки локали:

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

Пример цепочки:

ru-KZ → ru → en-US → en

Псевдолокализация как стратегия проверки фолбэка

В процессе разработки применяется псевдолокализация:

  • расширение текста
  • замена символов
  • добавление маркеров

Это позволяет выявлять:

  • незамещённые строки
  • пропущенные ключи
  • неконсистентные fallback-пути

Фолбэк в runtime-извлечении сообщений

При использовании runtime-режима сообщений (без предварительной компиляции):

  • ключи проверяются динамически
  • отсутствующие значения не блокируют выполнение
  • fallback активируется немедленно

При компиляции через CLI возможна альтернатива:

  • удаление отсутствующих ключей
  • подстановка дефолтов
  • генерация отчёта покрытия

Стратегии комбинирования fallback-механизмов

На практике применяются гибридные схемы:

1. Жёсткий fallback

locale → defaultLocale → defaultMessage → id

2. Мягкий fallback

locale → defaultMessage → пустая строка

3. Диагностический fallback

locale → throw error → log → id

Поведение при неполных ICU данных

ICU сообщения могут зависеть от параметров:

  • отсутствующий параметр → fallback ветка
  • некорректный тип → ошибка форматирования
  • null/undefined → переход к defaultMessage или string fallback

Пример:

formatMessage(
  { id: 'greeting', defaultMessage: 'Hello {name}' },
  { name: undefined }
)

Результат зависит от конфигурации — либо подстановка fallback, либо предупреждение.


Фолбэк в связке с code splitting переводов

При разделении переводов по чанкам:

  • отсутствующий чанк → fallback locale
  • задержка загрузки → временный defaultMessage
  • ошибка сети → повтор загрузки или резервный словарь

Сценарий особенно важен для SPA с множеством языков.


Приоритеты разрешения значений

Обобщённая схема приоритетов:

  1. runtime messages (загруженные переводы)
  2. merged locale chain
  3. defaultMessage
  4. message id
  5. fallback locale root

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