Хранение переводов в системах интернационализации, построенных на 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, который поддерживает выражения для переменных, множественных форм, выборов и форматирования дат и чисел.
Простейший пример с переменной:
{
"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}"
}
Здесь хранится не конкретное значение, а правило форматирования, зависящее от локали.
Система ключей является фундаментальной частью хранения переводов. Используются несколько подходов:
{
"auth.login.title": "Login",
"auth.login.button": "Sign in"
}
{
"LoginForm.title": "Login",
"LoginForm.submit": "Submit"
}
Выбор структуры влияет на масштабируемость системы и удобство работы с автоматическими инструментами извлечения сообщений.
В экосистеме 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-файлов. Это позволяет проверять корректность ключей на этапе компиляции и исключать обращения к несуществующим сообщениям.
Структура хранения при этом остаётся неизменной, но добавляется слой статической проверки.
При росте объёма переводов применяются техники оптимизации:
Это особенно важно в SPA-приложениях, где загрузка всех языков одновременно приводит к увеличению времени первоначального рендеринга.
В связке с React Intl хранение переводов становится тесно связано с компонентами. Каждый компонент может ссылаться на собственный набор ключей, при этом глобальные словари остаются единым источником истины.
Такой подход формирует гибридную модель хранения, где глобальные переводы обслуживают общие элементы интерфейса, а локальные файлы описывают специфическую логику отдельных модулей.
Хранение переводов требует строгого контроля за экранированием специальных символов:
{} используются для переменныхЭто предотвращает некорректное интерпретирование сообщений и потенциальные XSS-уязвимости при неправильной обработке.
При развитии проекта структура переводов неизбежно меняется. Типичный процесс включает:
Сложность заключается в сохранении обратной совместимости, особенно если приложение поддерживает несколько версий интерфейса одновременно.
Для языков с высокой степенью морфологической изменчивости сообщения могут включать дополнительные контекстные параметры:
{
"invite.message": "{gender, select, male {Invite him} female {Invite her} other {Invite them}}"
}
Такие конструкции позволяют хранить логику вариативности прямо в переводе, избегая усложнения кода приложения.
При увеличении количества языков и сообщений основным фактором становится структура хранения. Плоские JSON-файлы могут достигать десятков мегабайт, что требует:
Эти подходы позволяют поддерживать высокую производительность даже при большом количестве локалей.
Хранение переводов включает механизмы проверки:
Такие проверки часто интегрируются в CI/CD-пайплайны и выполняются автоматически при каждом изменении языковых файлов.