Strict mode конфигурация

Строгая конфигурация в FormatJS формирует набор правил, при которых система интернационализации перестаёт быть «гибкой по умолчанию» и начинает требовать явной дисциплины в описании сообщений, идентификаторов и структуры переводов. Основная цель — исключить неоднозначности между исходным кодом и файлами локализации, а также предотвратить ситуации, когда интерфейс частично работает на fallback-языке без явного контроля.

Строгий режим затрагивает сразу несколько уровней: статический анализ (ESLint), компиляцию сообщений (Babel-плагин), извлечение переводов (CLI-инструменты) и поведение runtime-библиотек (react-intl, intl-messageformat).


Концептуальная модель строгого режима

В экосистеме FormatJS строгий режим опирается на три ключевых принципа:

Явные идентификаторы сообщений Каждое сообщение должно иметь стабильный id, исключающий зависимость от текста как ключа.

Полная формализация ICU-синтаксиса Сообщения должны соответствовать ICU Message Format без синтаксических неоднозначностей.

Запрет неявных fallback-сценариев Отсутствие перевода, некорректный формат или пропущенные поля рассматриваются как ошибка, а не как допустимое состояние.


ESLint как первый уровень строгого контроля

Статический анализ через eslint-plugin-formatjs является основным механизмом внедрения строгого режима на этапе разработки.

Обязательные идентификаторы сообщений

Правило formatjs/enforce-id требует наличия id во всех вызовах форматирования сообщений.

import { defineMessages } from 'react-intl';

const messages = defineMessages({
  welcome: {
    id: 'app.home.welcome',
    defaultMessage: 'Добро пожаловать'
  }
});

В строгой конфигурации отсутствие id приводит к ошибке линтинга, а не предупреждению.


Запрет «сырых» строк

Правило formatjs/no-raw-text предотвращает появление текстовых строк вне системы интернационализации.

// Ошибка в строгом режиме
<div>Привет</div>

// Корректный вариант
import { FormattedMessage } from 'react-intl';

<div>
  <FormattedMessage id="app.greeting" defaultMessage="Привет" />
</div>

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


Контроль структуры сообщений

Некорректный ICU-синтаксис может быть выявлен на этапе линтинга:

// Ошибка: некорректная ICU-конструкция
const msg = {
  id: 'app.errors.count',
  defaultMessage: 'Ошибок {count plural one {# ошибка} other {# ошибок}'
};

В строгом режиме такие ошибки блокируют сборку.


Babel-плагин и строгая трансформация сообщений

babel-plugin-formatjs отвечает за подготовку сообщений к извлечению и оптимизации. В строгой конфигурации он используется не только как трансформатор, но и как валидатор.

Ключевые параметры строгого режима

idInterpolationPattern

Позволяет стандартизировать генерацию идентификаторов:

{
  "plugins": [
    [
      "formatjs",
      {
        "idInterpolationPattern": "[sha512:contenthash:base64:6]"
      }
    ]
  ]
}

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


strictMessage

Некоторые сборки используют режим строгой проверки сообщений:

{
  "plugins": [
    [
      "formatjs",
      {
        "ast": true,
        "strict": true
      }
    ]
  ]
}

В этом режиме любые некорректные ICU-выражения вызывают ошибку трансформации.


preserveEmptyDefaultMessage

В строгих конфигурациях этот параметр часто отключается:

{
  "preserveEmptyDefaultMessage": false
}

Это означает, что сообщения без defaultMessage считаются неполными и не допускаются к извлечению.


CLI-инструменты и строгая экстракция сообщений

@formatjs/cli используется для извлечения сообщений из кода в JSON-файлы локализации. В строгом режиме он выполняет дополнительную валидацию структуры сообщений.

Строгий extract

formatjs extract "src/**/*.{ts,tsx,js}" --out-file messages.json --strict

Флаг --strict включает дополнительные проверки:

  • обязательность id
  • проверка ICU-синтаксиса
  • проверка дубликатов ключей
  • запрет пустых defaultMessage

Контроль целостности переводов

При строгом извлечении CLI может сравнивать существующие файлы локализации:

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

Runtime-строгий режим в react-intl

На уровне исполнения строгий режим влияет на поведение IntlProvider и функций форматирования.

Поведение при отсутствии перевода

В строгих конфигурациях отсутствующий перевод не заменяется тихим fallback:

<IntlProvider locale="ru" messages={{}}>
  <App />
</IntlProvider>

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

  • либо выбрасывается ошибка
  • либо включается режим явного fallback с логированием (в зависимости от конфигурации)

Проверка параметров ICU

При форматировании сообщений выполняется проверка соответствия переданных значений шаблону:

intl.formatMessage(
  {
    id: 'app.cart.items',
    defaultMessage: 'Товаров: {count}'
  },
  { count: undefined }
);

В строгом режиме отсутствие count рассматривается как ошибка выполнения, а не как подстановка пустого значения.


Строгие правила идентификаторов

Строгая конфигурация часто требует единообразной стратегии ID.

Детерминированные идентификаторы

Подход на основе хэшей:

app.header.title → a8f3c1

Преимущества:

  • исключение коллизий
  • стабильность при рефакторинге текста

Недостатки:

  • сложность ручной отладки

Семантические идентификаторы

{
  "id": "settings.profile.saveButton"
}

В строгом режиме допускается только структурированная иерархия, а не произвольные строки.


Валидация ICU-синтаксиса как часть строгого режима

FormatJS использует ICU Message Format как основу интернационализации. В строгой конфигурации синтаксис проверяется на нескольких уровнях.

Проверка плейсхолдеров

{
  "defaultMessage": "Привет, {name}"
}

Ошибкой считается:

  • отсутствие переменной name при форматировании
  • передача лишних параметров без использования

Плюрализация

{
  "defaultMessage": "{count, plural, one {# файл} few {# файла} other {# файлов}}"
}

Строгий режим требует:

  • полного набора форм
  • корректного соответствия локали
  • наличия числового параметра count

Интеграция строгого режима в CI/CD

Строгая конфигурация FormatJS чаще всего закрепляется на уровне пайплайна сборки.

Пример этапа проверки

- name: Extract messages
  run: npx formatjs extract "src/**/*.{ts,tsx}" --strict

- name: Lint messages
  run: npx eslint "src/**/*.{ts,tsx}" --rule 'formatjs/enforce-id:error'

При нарушении правил:

  • сборка останавливается
  • артефакты не публикуются
  • ошибка возвращается в систему контроля версий

Строгий режим и масштабируемость локализации

При увеличении количества языков строгая конфигурация становится механизмом защиты целостности переводов.

Основные эффекты:

  • синхронизация структуры всех языковых файлов
  • предотвращение «разъезда» ключей
  • контроль консистентности ICU-параметров
  • снижение риска runtime-ошибок на продакшене

Конфигурационная модель строгого режима

Типичная строгая конфигурация объединяет ESLint, Babel и CLI:

{
  "eslint": {
    "rules": {
      "formatjs/enforce-id": "error",
      "formatjs/no-raw-text": "error"
    }
  },
  "babel": {
    "plugins": [
      [
        "formatjs",
        {
          "ast": true,
          "idInterpolationPattern": "[sha512:contenthash:base64:6]",
          "preserveEmptyDefaultMessage": false
        }
      ]
    ]
  },
  "cli": {
    "strict": true
  }
}

Поведение системы при нарушении строгих правил

Строгий режим переводит FormatJS из «инструмента поддержки локализации» в «контрактную систему».

При нарушениях:

  • линтер блокирует коммит
  • Babel прерывает трансформацию
  • CLI не формирует output-файлы
  • runtime выбрасывает исключения вместо fallback

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