В ICU MessageFormat, на котором основан FormatJS, строка сообщения не является простым текстом. Она представляет собой синтаксически значимую конструкцию, где фигурные скобки, кавычки, запятые и ключевые слова выполняют управляющие функции. Любой символ, участвующий в синтаксисе форматирования, требует корректного экранирования при использовании в пользовательском тексте.
Неправильная обработка таких символов приводит к ошибкам парсинга, неожиданному разбиению сообщений или полному отказу их рендеринга. В контексте интернационализации это особенно критично, поскольку текст часто формируется динамически и включает данные, не контролируемые разработчиком.
FormatJS использует ICU MessageFormat, где специальные символы имеют функциональное значение:
{ и } — обозначение плейсхолдеров и блоков
форматирования# — используется в plural-форматах как счетчик' — символ экранирования литералов, — разделитель параметров| (в некоторых расширениях) — служебный
разделительЛюбой из этих символов в пользовательском тексте может быть интерпретирован как часть синтаксиса сообщения.
В ICU MessageFormat применяется экранирование через одинарные кавычки:
'...' воспринимается как литералПростейший пример:
import { defineMessages } from 'react-intl';
const messages = defineMessages({
example: {
id: 'app.example',
defaultMessage: "Символы '{', '}' и '#' используются в синтаксисе"
}
});
Здесь фигурные скобки и решётка выводятся как обычный текст, а не как управляющие элементы.
Одинарная кавычка имеет двойную роль: она открывает и закрывает литеральный блок, а также сама экранируется удвоением.
'text' — литеральный блок'' — символ одиночной кавычкиПример:
const message = "Это ''кавычка'' и '{плейсхолдер}'";
Результат:
Это 'кавычка' и {плейсхолдер}
Фигурные скобки являются ключевым элементом интерполяции:
"Привет, {name}"
Для отображения их как текста требуется обрамление в литеральный блок:
"Синтаксис '{name}' не будет интерпретирован"
В сложных случаях используется комбинированный подход:
"Формат сообщения: '{user}: {value}'"
Здесь вся конструкция отображается буквально, без попытки подстановки значений.
Наиболее частая ошибка возникает при смешивании текста и переменных:
"Значение {count} элементов: {items}"
Если items не определён как переменная, парсер
воспринимает это как ошибку.
"Значение {count} элементов: '{items}'"
или при необходимости буквального вывода:
"Значение {count} элементов: '{{items}}'"
Двойные фигурные скобки используются только в случаях, когда требуется вывести сам синтаксис интерполяции как текст.
Plural-структуры вводят дополнительные ограничения:
"{count, plural, one {# файл} other {# файлов}}"
Здесь символ # автоматически заменяется значением
счётчика. Если требуется вывести # как символ, его
необходимо экранировать:
"{count, plural, one {'#' файл} other {'#' файлов}}"
Литеральные кавычки блокируют интерпретацию #.
FormatJS поддерживает вложенные выражения, где экранирование становится многоуровневым.
Пример:
"{count, plural, one {Значение '{value}'} other {Значения '{value}'}}"
Если требуется показать фигурные скобки внутри plural-ветки:
"{count, plural, one {'{один}'} other {'{много}'} }"
Каждый слой должен быть корректно закрыт, иначе парсер MessageFormat выдаёт ошибку синтаксиса.
Одинарная кавычка внутри литерального блока требует удвоения:
"Он сказал: ''готово''"
Результат:
Он сказал: 'готово'
Если кавычки сочетаются с интерполяцией:
"Результат: '{value}' и ''готовое значение''"
FormatJS не интерпретирует HTML, однако символы < и
> могут вводить неоднозначность при генерации сообщений
в UI-слое.
Рекомендуемый подход:
"Сравнение: 'a < b' и 'c > d'"
или при динамическом формировании:
"Условие '{a < b}' недопустимо"
"Текст 'не закрыт"
Последствие — полный разбор сообщения ломается.
"Значение {count элементов}"
Парсер воспринимает count элементов как выражение, что
вызывает ошибку.
"'{count}' = {count}"
Первое count выводится как текст, второе — как
переменная. Нарушение логики может привести к путанице в UI.
{ и }#MessageFormat строго валидирует строку сообщения. При обнаружении некорректного синтаксиса:
defaultMessage или ключНаиболее чувствительными являются случаи с незакрытыми кавычками и некорректными фигурными скобками.
Разные версии ICU могут незначительно отличаться в обработке экранирования, особенно в сложных вложенных конструкциях. FormatJS стремится к стабильной совместимости, однако поведение всегда определяется спецификацией ICU MessageFormat, а не самим JavaScript-кодом.
В результате экранирование следует считать частью контрактной логики локализационных строк, а не вспомогательной синтаксической деталью.