В экосистеме FormatJS локаль представляет собой не просто строковый
идентификатор вида en или ru-RU, а набор
правил форматирования, включающий:
Каждая локаль в контексте Intl и FormatJS опирается на
CLDR-данные (Common Locale Data Repository), где даже близкие языки
могут иметь несовместимые поведенческие различия. Это становится
источником конфликтов при объединении или переключении локалей в одном
приложении.
Стандартная модель локалей основана на иерархии:
enen-GBen-USen-AUАналогично для других языков:
ruru-RUru-BYКонфликты возникают, когда система одновременно использует несколько уровней этой иерархии, особенно при:
FormatJS не выполняет автоматическое «слияние смысла» между локалями — каждая запись рассматривается как независимая сущность.
Наиболее распространённый тип конфликта связан с одинаковыми ключами сообщений в разных локалях.
Пример структуры:
const messages_en = {
title: "Settings",
save: "Save"
};
const messages_ru = {
title: "Настройки",
save: "Сохранить"
};
Проблема возникает при неправильной сборке бандла, когда:
Object.assign);В результате одна локаль может перезаписать другую, особенно при динамической загрузке.
FormatJS использует цепочку fallback-локалей, если сообщение отсутствует в текущем наборе.
Типичная логика:
ru-RU → ru → en
Конфликт возникает при:
Например:
// ru-RU
"cart.items": "{count} товар"
// ru
"cart.items": "{count} товаров"
// en
"cart.items": "{count} items"
Если одна из локалей содержит ошибочный ICU-формат, fallback может
привести к неожиданному рендеру или падению парсера
intl-messageformat.
FormatJS использует ICU MessageFormat, который строго парсится.
Конфликтные ситуации:
plural;Пример некорректного расхождения:
// en
"messages": "{count, plural, one {# item} other {# items}}"
// ru (ошибка структуры)
"messages": "{count, plural, one {# товар} few {# товара}}"
Для русского языка требуется полный набор категорий
one/few/many/other, и отсутствие одной ветки приводит к
логической ошибке форматирования.
В React-интеграции FormatJS через IntlProvider локаль и
сообщения передаются как единый контекст.
<IntlProvider locale="ru" messages={messages_ru}>
<App />
</IntlProvider>
Проблемные сценарии:
Особенно критичен случай, когда locale обновляется, но
messages остаются от предыдущей локали — возникает
несоответствие языка и контента.
При серверном рендеринге конфликт локалей проявляется как несоответствие HTML между сервером и клиентом.
Причины:
ru-RU, клиент —
en-US;Типичный эффект — предупреждения о hydration mismatch и перерисовка части интерфейса.
FormatJS опирается на Intl.NumberFormat и
Intl.DateTimeFormat, поведение которых зависит от
локали.
Примеры различий:
1,000.50 (en-US)1 000,50 (ru-RU)При неправильной синхронизации локали возможны ситуации, когда:
При масштабировании приложений часто применяется объединение сообщений из разных модулей:
const messages = {
...commonMessages,
...pageMessages,
...widgetMessages
};
Конфликты возникают при:
Поверхностное слияние не учитывает глубину структуры, поэтому вложенные ключи могут быть потеряны.
Locale identifier может быть записан в разных формах:
ru-RUru-ruRU-ruХотя стандарт требует BCP 47 нормализации, на практике источники
локалей могут быть неоднородны. FormatJS и Intl выполняют
частичную нормализацию, но:
Даже внутри одного языка возможны различия:
sr vs sr-Latnpt vs pt-BRzh vs zh-Hans / zh-HantPlural rules и форматы чисел могут отличаться, несмотря на общий язык.
Ошибка возникает, когда:
FormatJS активно использует кэширование форматтеров
(Intl.NumberFormat, Intl.DateTimeFormat).
Конфликтный сценарий:
Это особенно заметно при:
В крупных системах сообщения часто приходят из:
Конфликты возникают, когда:
В результате происходит двойная интерпретация или потеря параметров.
При ленивой загрузке:
import(`./locales/${locale}.json`)
возможны ситуации:
Если новый импорт завершается позже старого, он может перезаписать актуальную локаль устаревшими данными.