В экосистеме FormatJS диагностика ошибок и отладка
строятся вокруг нескольких источников информации: парсинг ICU-строк,
работа с IntlMessageFormat, поведение провайдера
локализации в react-intl, а также этапы сборки сообщений
через CLI и Babel-плагины.
Ключевое разделение:
defaultMessage.@formatjs/cli.Каждый уровень требует отдельной стратегии логирования, иначе диагностика становится фрагментарной и трудно воспроизводимой.
Базовый механизм FormatJS — класс IntlMessageFormat. Он
выбрасывает исключения при некорректных ICU-строках и неконсистентных
данных.
Типовой подход к перехвату:
import { IntlMessageFormat } from 'intl-messageformat';
try {
const msg = new IntlMessageFormat(
'Hello {name}, you have {count, plural, one {# message} other {# messages}}',
'en'
);
const output = msg.format({ name: 'Alex', count: 2 });
} catch (e) {
console.error('Ошибка форматирования сообщения:', e);
}
Важный момент: исключения здесь не всегда критические. В ряде случаев FormatJS возвращает fallback-строку или частично отформатированный результат. Поэтому логирование должно различать:
В react-intl ключевой источник диагностической
информации — отсутствие перевода для id.
Механизм fallback:
id не найден → используется
defaultMessagedefaultMessage отсутствует → возвращается
idЧтобы фиксировать такие ситуации, используется onError в
IntlProvider.
import { IntlProvider } from 'react-intl';
function errorHandler(err) {
console.warn('Intl error:', err.message);
}
<IntlProvider locale="en" messages={{}} onEr ror={errorHandler}>
<App />
</IntlProvider>
Типы ошибок, которые поступают в onError:
Логирование этих событий позволяет строить карту «дыр» в локализации, особенно при масштабных проектах с сотнями сообщений.
defaultMessage часто используется как fallback, но в
режиме строгой локализации он становится индикатором проблемы.
Практика логирования:
defaultMessage в
productionconst trackMissing = (id, message) => {
console.log(`[i18n missing] ${id}: ${message}`);
};
В связке с HOC или hooks (useIntl) можно перехватывать
форматирование на уровне обёртки.
Пакет eslint-plugin-formatjs позволяет выявлять проблемы
до выполнения кода.
Основные проверки:
id в сообщенияхПример конфигурации:
module.exports = {
plugins: ['formatjs'],
rules: {
'formatjs/enforce-id': 'error',
'formatjs/enforce-default-message': 'warn',
'formatjs/no-missing-icu-plural': 'error'
}
};
Логически ESLint становится первым уровнем «логирования», хотя работает статически.
@formatjs/cli используется для извлечения сообщений из
кода:
formatjs extract "src/**/*.ts" --out-file messages.json
Диагностически важные сценарии:
idПри включении verbose-режима CLI выводит информацию о каждом найденном сообщении, что позволяет отслеживать:
В react-intl критический инструмент — перехват ошибок
через IntlProvider.
Дополнительные стратегии:
const intl = useIntl();
function safeFormatMessage(descriptor, values) {
try {
return intl.formatMessage(descriptor, values);
} catch (e) {
console.error('formatMessage error:', descriptor, e);
return descriptor.defaultMessage || descriptor.id;
}
}
Это позволяет фиксировать:
ICU MessageFormat имеет строгий синтаксис, и FormatJS чувствителен к следующим случаям:
{count, plural, one {# item} other {# items}}
Ошибки возникают при:
otherHello {name}
Если name не передан, логирование фиксирует
MISSING_DATA.
В крупных приложениях FormatJS логирование интегрируется с внешними системами:
Общая схема:
onErrorfunction intlErrorHandler(error) {
const normalized = {
message: error.message,
code: error.code,
timestamp: Date.now()
};
sendToLogger(normalized);
}
В development режиме FormatJS должен быть максимально шумным:
В production:
const isDev = process.env.NODE_ENV === 'development';
const errorHandler = (err) => {
if (isDev) {
console.error(err);
} else {
reportError(err);
}
};
Message descriptor — центральная структура:
{
id: 'user.greeting',
defaultMessage: 'Hello {name}'
}
Логирование на этом уровне позволяет:
idРасширенная практика — внедрение middleware:
function trackDescriptor(descriptor) {
console.log('i18n usage:', descriptor.id);
return descriptor;
}
FormatJS поддерживает rich text форматирование:
Hello <b>{name}</b>
Типовые проблемы:
defaultRichTextElementsЛогирование таких ошибок особенно важно, поскольку они часто проявляются только в runtime.
Fallback-логика FormatJS влияет на диагностику:
Поэтому логирование должно фиксировать сам факт fallback-ветки, а не только ошибку.
Расширенная стратегия — замена провайдера на кастомный слой:
function LoggingIntlProvider(props) {
return (
<IntlProvider
{...props}
onEr ror={(err) => {
console.warn('[i18n]', err);
}}
/>
);
}
Это позволяет централизовать всю диагностику без изменения бизнес-логики компонентов.
Логирование в FormatJS часто превращается в систему метрик:
Такие метрики используются для оценки зрелости локализации и стабильности i18n слоя в приложении.