FormatJS опирается на концепцию компиляции интернационализации на этапе сборки. В этой архитектуре ключевую роль выполняют Babel-плагины, обеспечивающие статический анализ сообщений, извлечение переводов и трансформацию кода в оптимизированный формат для выполнения в рантайме.
Babel используется как промежуточный слой между исходным JavaScript/TypeScript кодом и финальным бандлом. Плагины FormatJS интегрируются в pipeline трансформации AST и позволяют обрабатывать ICU-сообщения, JSX-компоненты и API интернационализации без дополнительной ручной обработки.
Основная идея Babel-плагинов FormatJS заключается в переносе части работы с интернационализацией из runtime в build-time. Это позволяет:
Сообщения интернационализации в FormatJS чаще всего используют ICU Message Format, который поддерживает:
Babel-плагины анализируют AST и находят вызовы функций или JSX-компоненты, содержащие такие сообщения.
Основной плагин экосистемы — babel-plugin-formatjs. Он
выполняет статический анализ кода и извлекает сообщения из следующих
конструкций:
defineMessages<FormattedMessage />intl.formatMessageuseIntl().formatMessageПример обрабатываемого кода:
import { defineMessages } from 'react-intl';
const messages = defineMessages({
title: {
id: 'app.title',
defaultMessage: 'Dashboard'
},
unread: {
defaultMessage: 'Unread messages: {count}'
}
});
После обработки Babel формирует JSON-структуру:
{
"app.title": {
"defaultMessage": "Dashboard"
},
"generated_id_1": {
"defaultMessage": "Unread messages: {count}"
}
}
Плагин поддерживает несколько стратегий идентификаторов:
id, заданные разработчикомdefaultMessageИспользование хеширования снижает вероятность коллизий и облегчает дедупликацию строк в больших приложениях.
Работа плагина основана на обходе AST-дерева Babel. Основные этапы:
Особое внимание уделяется определению статических значений. Динамические выражения:
formatMessage({ defaultMessage: getTitle() })
не могут быть извлечены полностью и либо игнорируются, либо частично маркируются.
ICU Message Format требует специализированного парсинга. Babel-плагин не просто извлекает строки, но и проверяет их корректность.
Пример:
formatMessage({
defaultMessage: 'You have {count, plural, one {# message} other {# messages}}'
});
На этапе анализа выполняется:
Ошибки в ICU-синтаксисе могут быть обнаружены на этапе сборки, что исключает runtime-исключения.
Экосистема часто используется совместно с react-intl. Babel-плагины обеспечивают совместимость между JSX-компонентами и системой извлечения сообщений.
Поддерживаемые конструкции:
<FormattedMessage
defaultMessage="Profile"
description="User profile title"
/>
Плагин преобразует JSX в структуру сообщений, извлекая:
Одной из задач Babel-плагина является оптимизация production-кода. В процессе трансформации могут быть удалены:
Это снижает размер итогового бандла и уменьшает количество ненужных вычислений.
Плагин часто используется вместе с CLI-инструментами FormatJS для формирования файлов переводов.
Типичный pipeline:
Babel проходит по исходному коду
извлекает сообщения в JSON
CLI объединяет сообщения из разных файлов
формируется master catalog
выполняется экспорт в форматы:
Структура каталога может выглядеть следующим образом:
{
"en": {
"app.title": "Dashboard",
"generated_id_1": "Unread messages: {count}"
},
"ru": {
"app.title": "Панель управления"
}
}
Babel-плагин выполняет оптимизацию повторяющихся строк. Если
несколько компонентов используют одинаковый defaultMessage,
система:
Нормализация включает:
При использовании TypeScript плагин анализирует:
formatMessageMessageDescriptorAST-анализ выполняется независимо от типов, но учитывает синтаксическую структуру, включая:
В рамках FormatJS Babel-плагины могут участвовать в генерации псевдолокалей (pseudo-locales), используемых для тестирования UI.
Пример трансформации:
Dashboard → [Ďåšhbôãřd]
Это позволяет выявлять:
Несмотря на мощь AST-парсинга, существуют ограничения:
id не могут быть стабильно
определеныПример проблемного случая:
formatMessage({
defaultMessage: 'Hello ' + user.name
});
Такой код не подлежит корректной интерпретации Babel-плагином.
Использование Babel-плагинов FormatJS влияет на build-time:
Однако это компенсируется:
Некоторые конфигурации сборщиков поддерживают кеширование результатов Babel-плагинов. Это позволяет:
Особенно эффективно при больших monorepo-структурах.
Плагин babel-plugin-formatjs поддерживает параметры:
idInterpolationPatternextractFromFormatMessageCallremoveDefaultMessageadditionalFunctionNamesast режимПример конфигурации:
{
"plugins": [
["formatjs", {
"removeDefaultMessage": false,
"idInterpolationPattern": "[sha512:contenthash:base64:6]"
}]
]
}
FormatJS-плагины часто комбинируются с:
Порядок выполнения влияет на результат, поскольку AST может быть модифицирован до или после извлечения сообщений.
При использовании Higher-Order Components и render props анализ усложняется:
withIntl(MyComponent)
Плагин должен:
intl пропсыЭто требует расширенного AST traversal с контекстной привязкой.
Babel-плагины FormatJS формируют слой compile-time интернационализации, который:
Интеграция с FormatJS и Babel делает систему частью конвейера сборки, а не runtime-библиотекой обработки текста.