Формат хранения переводов

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

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

На практике переводы в FormatJS чаще всего организуются в виде JSON-файлов, где каждый файл соответствует конкретной локали:

/locales
  /en.json
  /ru.json
  /de.json

Каждый файл содержит плоскую или иерархическую структуру ключей:

{
  "app.title": "Dashboard",
  "app.description": "System overview",
  "user.greeting": "Hello, {name}"
}

Или в виде вложенной структуры:

{
  "app": {
    "title": "Dashboard",
    "description": "System overview"
  },
  "user": {
    "greeting": "Hello, {name}"
  }
}

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

Формат сообщений ICU MessageFormat

В основе хранения динамических переводов лежит ICU MessageFormat, который поддерживает выражения для переменных, множественных форм, выборов и форматирования дат и чисел.

Простейший пример с переменной:

{
  "welcome": "Welcome, {username}"
}

Значение username подставляется во время рендеринга сообщения, не изменяя сам перевод.

Работа с множественными формами

Одной из ключевых особенностей хранения переводов в FormatJS является поддержка plural rules. Вместо хранения нескольких отдельных строк используется единое сообщение с правилами выбора формы:

{
  "messages.count": "{count, plural, one {# message} other {# messages}}"
}

Такая структура позволяет централизованно описывать правила для разных языков, поскольку plural rules зависят от локали. Например, в русском языке форм больше, чем в английском:

{
  "messages.count": "{count, plural, one {# сообщение} few {# сообщения} many {# сообщений} other {# сообщения}}"
}

Хранение переводов в таком формате исключает необходимость ручного выбора формы в коде приложения.

Выбор и условия внутри сообщений

MessageFormat поддерживает конструкции выбора (sel ect), которые позволяют хранить альтернативные варианты текста в одном ключе:

{
  "user.status": "{gender, select, male {He is online} female {She is online} other {They are online}}"
}

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

Хранение чисел и дат

FormatJS предполагает, что форматирование чисел и дат не хранится в переводах напрямую, но может быть встроено в сообщение:

{
  "event.date": "Event date: {date, date, long}"
}

или

{
  "balance": "Your balance is {amount, number, currency}"
}

Здесь хранится не конкретное значение, а правило форматирования, зависящее от локали.

Ключи сообщений и нейминг

Система ключей является фундаментальной частью хранения переводов. Используются несколько подходов:

  1. Доменная структура:
{
  "auth.login.title": "Login",
  "auth.login.button": "Sign in"
}
  1. Компонентная структура:
{
  "LoginForm.title": "Login",
  "LoginForm.submit": "Submit"
}
  1. Смешанный подход, где домены и компоненты комбинируются для предотвращения коллизий.

Выбор структуры влияет на масштабируемость системы и удобство работы с автоматическими инструментами извлечения сообщений.

Автоматическое извлечение сообщений

В экосистеме FormatJS широко используется извлечение сообщений из исходного кода. Переводы могут быть собраны из компонентов, где используются API форматирования:

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

const messages = {
  title: "Hello {name}"
};

В процессе сборки такие сообщения извлекаются и формируют JSON-каталоги. Это снижает вероятность рассинхронизации между кодом и переводами.

Нормализация и хранение данных

Хранение переводов предполагает нормализацию структуры:

  • единый формат ключей
  • единый стиль кавычек и экранирования
  • отсутствие логики внутри переводов
  • минимизация дублирования

JSON остаётся наиболее распространённым форматом, однако в крупных системах используются и альтернативы: YAML, PO-файлы, AST-структуры.

Версионирование переводов

При масштабировании приложений важным аспектом становится версионирование языковых ресурсов. Обычно применяется стратегия:

  • отдельные ветки или теги для переводов
  • синхронизация с релизами приложения
  • контроль несовместимых изменений ключей

Удаление или переименование ключей считается критическим изменением, поскольку оно может привести к отсутствию текста в интерфейсе.

Переиспользование сообщений

Для уменьшения дублирования часто вводится система ссылок на другие ключи:

{
  "button.save": "Save",
  "form.saveButton": "@:button.save"
}

Хотя не все реализации FormatJS используют такую механику напрямую, концепция переиспользования активно применяется через общие словари и базовые наборы переводов.

Разделение по доменам и модулям

При больших проектах переводы делятся по функциональным модулям:

/locales
  /auth.json
  /dashboard.json
  /profile.json

Такой подход уменьшает размер загружаемых файлов и позволяет динамически подгружать переводы при необходимости.

Локализационные фоллбеки

Хранение переводов включает механизм fallback-цепочек. Если ключ отсутствует в текущей локали, используется базовый язык:

ru -> en -> default

Это требует строгого контроля полноты переводов, особенно при добавлении новых ключей.

Совместимость с типизацией

В современных проектах переводы часто сопровождаются TypeScript-типами, которые генерируются на основе JSON-файлов. Это позволяет проверять корректность ключей на этапе компиляции и исключать обращения к несуществующим сообщениям.

Структура хранения при этом остаётся неизменной, но добавляется слой статической проверки.

Оптимизация хранения

При росте объёма переводов применяются техники оптимизации:

  • сжатие JSON
  • разделение по чанкам
  • lazy-loading языковых пакетов
  • кэширование на уровне клиента

Это особенно важно в SPA-приложениях, где загрузка всех языков одновременно приводит к увеличению времени первоначального рендеринга.

Интеграция с компонентной моделью

В связке с React Intl хранение переводов становится тесно связано с компонентами. Каждый компонент может ссылаться на собственный набор ключей, при этом глобальные словари остаются единым источником истины.

Такой подход формирует гибридную модель хранения, где глобальные переводы обслуживают общие элементы интерфейса, а локальные файлы описывают специфическую логику отдельных модулей.

Экранирование и безопасность данных

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

  • фигурные скобки {} используются для переменных
  • апострофы требуют экранирования в некоторых случаях
  • HTML-разметка должна быть либо запрещена, либо строго контролироваться

Это предотвращает некорректное интерпретирование сообщений и потенциальные XSS-уязвимости при неправильной обработке.

Миграция и эволюция схемы переводов

При развитии проекта структура переводов неизбежно меняется. Типичный процесс включает:

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

Сложность заключается в сохранении обратной совместимости, особенно если приложение поддерживает несколько версий интерфейса одновременно.

Хранение контекста и вариативности

Для языков с высокой степенью морфологической изменчивости сообщения могут включать дополнительные контекстные параметры:

{
  "invite.message": "{gender, select, male {Invite him} female {Invite her} other {Invite them}}"
}

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

Масштабируемость словарей

При увеличении количества языков и сообщений основным фактором становится структура хранения. Плоские JSON-файлы могут достигать десятков мегабайт, что требует:

  • разбиения по модулям
  • серверной агрегации
  • динамической загрузки
  • CDN-дистрибуции

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

Контроль качества переводов

Хранение переводов включает механизмы проверки:

  • наличие всех ключей во всех локалях
  • соответствие формата ICU
  • отсутствие неиспользуемых сообщений
  • проверка длины строк для UI-ограничений

Такие проверки часто интегрируются в CI/CD-пайплайны и выполняются автоматически при каждом изменении языковых файлов.