Валидация и проверка полноты

Статическая проверка структуры сообщений

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

Сообщение интерпретируется через AST-парсер (@formatjs/icu-messageformat-parser), который выявляет синтаксические ошибки:

  • незакрытые фигурные скобки
  • некорректные селекторы plural и select
  • ошибки вложенности (например, вложенные plurals без корректной структуры)
  • некорректные типы аргументов (number, date, time, selectordinal)

При обнаружении ошибки парсинга формируется структурированное исключение, содержащее позицию в строке и тип нарушения.

Типичный пример некорректного сообщения:

const msg = "У вас {count, plural, one {1 файл} other {# файлов}";
// отсутствует закрывающая скобка

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


Валидация соответствия аргументов сообщения

FormatJS строго связывает строку сообщения с набором входных параметров. На этапе компиляции или выполнения проверяется:

  • наличие всех требуемых аргументов
  • отсутствие лишних аргументов (в строгом режиме)
  • соответствие типов аргументов ожидаемым форматам ICU

Пример несоответствия:

const message = "У пользователя {name} {age, number} лет";

formatMessage(message, {
  name: "Алексей"
});

Отсутствие age приводит к ошибке или использованию fallback-режима в зависимости от конфигурации.

В строгой конфигурации react-intl такие ошибки обрабатываются как критические, поскольку нарушают целостность локализационного контракта.


Контроль полноты переводов (message coverage)

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

Извлечение сообщений

Используется CLI-инструмент @formatjs/cli:

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

Результатом является единый каталог сообщений:

{
  "app.title": {
    "defaultMessage": "Dashboard"
  },
  "user.greeting": {
    "defaultMessage": "Hello, {name}"
  }
}

Сравнение локалей

Для каждой локали формируется отдельный файл переводов. Далее выполняется проверка:

  • отсутствующие ключи переводов
  • устаревшие ключи (не присутствующие в исходных сообщениях)
  • дублирующиеся идентификаторы
  • пустые строки перевода

Типичная структура проверки:

en.json   -> источник истины
ru.json   -> проверяемая локаль
de.json   -> проверяемая локаль

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

  • missing translation
  • fallback to defaultMessage (если разрешено)

Проверка ICU-полноты (plural/sel ect completeness)

ICU MessageFormat требует соблюдения полноты ветвлений, особенно для plural и select.

Пример:

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

Для языков с более сложной системой множественных форм (например, славянские языки) отсутствие одной из форм приводит к некорректному отображению.

Валидация проверяет:

  • наличие other ветки (обязательная по ICU)
  • корректность ключей plural rules для текущей локали
  • соответствие CLDR-правилам

При несоответствии возникает ошибка компиляции или предупреждение зависимости от режима strictness.


Интеграция с CLDR и проверка локализационных правил

FormatJS использует данные CLDR (Common Locale Data Repository) для определения правил форматирования чисел, дат и множественных форм.

Валидация включает:

  • проверку доступности locale data
  • соответствие plural rules текущей локали
  • корректность форматов дат/времени

Если локаль не зарегистрирована:

import { IntlProvider } fr om "react-intl";

<IntlProvider locale="ru">

и отсутствуют данные CLDR, возможны fallback-режимы или ошибки форматирования.


Runtime-валидация через react-intl

В react-intl проверки происходят во время выполнения:

  • отсутствие сообщения по id
  • несовпадение аргументов форматирования
  • ошибки форматирования даты, числа, относительного времени

Пример отсутствующего сообщения:

formatMessage({ id: "missing.key" })

Результат зависит от конфигурации:

  • fallback на defaultMessage
  • возврат id
  • выброс исключения в dev-режиме

Строгий режим (strict mode)

Strict mode усиливает контроль качества локализации. Включение режима приводит к:

  • выбросу ошибок при отсутствии переводов
  • запрету использования fallback без явного указания
  • проверке всех аргументов message descriptor

Пример конфигурации:

<IntlProvider
  locale="ru"
  defaultLocale="en"
  onEr ror={(err) => {
    console.error(err);
  }}
/>

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


Проверка через ESLint (eslint-plugin-formatjs)

Статическая валидация усиливается через линтер.

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

  • formatjs/no-missing-message-id
  • formatjs/enforce-id
  • formatjs/no-missing-plural
  • formatjs/no-invalid-icu

Пример конфигурации:

rules: {
  "formatjs/enforce-id": "error",
  "formatjs/no-missing-message-id": "error"
}

Линтер позволяет выявлять ошибки до этапа сборки, включая:

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

Проверка уникальности идентификаторов

Система сообщений требует уникальности ключей в пределах проекта. При использовании extract CLI или Babel-плагинов может возникать ситуация:

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

Типичный конфликт:

"user.title": "User"
"user.title": "Account"

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


Валидация форматирования чисел и дат

FormatJS опирается на Intl.NumberFormat, Intl.DateTimeFormat, Intl.RelativeTimeFormat.

Проверяются:

  • допустимость форматов (short, long, numeric)
  • корректность единиц измерения
  • совместимость с локалью

Пример:

formatNumber(1000, {
  style: "currency",
  currency: "KZT"
});

Если валюта или формат не поддерживаются окружением, происходит fallback или ошибка в зависимости от polyfill-конфигурации.


Проверка согласованности fallback-цепочек

Fallback-цепочки локалей контролируются через:

  • defaultLocale
  • цепочку наследования переводов
  • наличие частичных переводов

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

ru-KZ → ru → en

Валидация фиксирует:

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

Компиляционная проверка сообщений

При использовании компилятора FormatJS сообщения преобразуются в оптимизированный формат.

На этапе компиляции проверяются:

  • синтаксис ICU
  • корректность AST
  • наличие всех обязательных ветвлений
  • совместимость с runtime форматтером

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


Проверка Rich Text и вложенных форматирований

FormatJS поддерживает rich-text синтаксис:

"Привет, <b>{name}</b>"

или ICU-style rich format:

{
  b: (chunks) => <b>{chunks}</b>
}

Валидация контролирует:

  • корректность тегов
  • отсутствие незакрытых rich-элементов
  • соответствие между тегами и функциями форматирования
  • отсутствие запрещённых вложений

Ошибки в rich-text приводят к потере структуры или падению форматирования в рантайме.


Контроль согласованности типов сообщений

MessageDescriptor требует строгой структуры:

  • id
  • defaultMessage
  • description (опционально)

Валидация проверяет:

  • наличие id при включённой политике enforce-id
  • отсутствие пустых defaultMessage
  • соответствие типов данных (string, object при rich messages)

Любое отклонение фиксируется как нарушение контракта локализации.


Диагностика ошибок локализации

Система ошибок FormatJS обычно классифицирует проблемы:

  • MISSING_TRANSLATION
  • INVALID_FORMAT
  • MISSING_VALUE
  • FORMAT_ERROR
  • PARSE_ERROR

Каждая ошибка содержит:

  • message id
  • локаль
  • контекст вызова
  • тип форматтера

Это позволяет строить централизованную систему мониторинга качества локализации в приложениях с большим количеством языков и сообщений.