Управление переводами и локализацией

Локализация в приложениях на Riot.js предполагает управление текстовым содержимым интерфейса в зависимости от языка пользователя. В Riot.js нет встроенной системы интернационализации, поэтому обычно используются внешние библиотеки, такие как i18next, Polyglot.js или собственные решения на основе JSON-файлов. Важно структурировать проект так, чтобы строки текста были отделены от кода компонентов, что облегчает поддержку и добавление новых языков.

Файлы локализации обычно представляют собой JSON-объекты, где ключ — это идентификатор строки, а значение — перевод. Пример структуры для английского и русского языков:

// en.json
{
  "welcome_message": "Welcome to Riot.js app",
  "login_button": "Login",
  "logout_button": "Logout"
}

// ru.json
{
  "welcome_message": "Добро пожаловать в приложение Riot.js",
  "login_button": "Вход",
  "logout_button": "Выход"
}

Интеграция локализации в компоненты

Компоненты Riot.js создаются с использованием тегов и шаблонов, что позволяет легко вставлять переводы через переменные. Для динамической подстановки текста необходимо загрузить нужный JSON и хранить его в состоянии приложения.

Пример использования i18next с Riot.js:

import i18next from 'i18next';

i18next.init({
  lng: 'ru',
  resources: {
    ru: { translation: require('./locales/ru.json') },
    en: { translation: require('./locales/en.json') }
  }
});

<my-component>
  <p>{ i18next.t('welcome_message') }</p>

  <button oncl ick={ toggleLanguage }>{ i18next.t('login_button') }</button>

  <script>
    toggleLanguage() {
      const newLang = i18next.language === 'ru' ? 'en' : 'ru';
      i18next.changeLanguage(newLang);
      this.update();
    }
  </script>
</my-component>

В этом примере i18next.t('ключ') возвращает перевод для текущего языка, а метод changeLanguage динамически меняет язык интерфейса. Вызов this.update() гарантирует, что компоненты будут перерендерены с новым языком.

Динамическая подстановка и плейсхолдеры

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

{
  "greeting": "Привет, {{name}}!"
}

В компоненте:

<p>{ i18next.t('greeting', { name: userName }) }</p>

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

Организация структуры переводов

Для крупных приложений рекомендуется разбивать переводы по модулям или страницам. Например:

/locales
  /ru
    common.json
    dashboard.json
    profile.json
  /en
    common.json
    dashboard.json
    profile.json

Загрузка может выполняться лениво, чтобы экономить ресурсы:

import i18next from 'i18next';

async function loadLocale(lang) {
  const resources = await import(`./locales/${lang}/common.json`);
  i18next.addResources(lang, 'translation', resources.default);
  i18next.changeLanguage(lang);
}

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

Реактивное обновление компонентов

В Riot.js состояния компонентов являются реактивными. Для автоматического обновления текста при смене языка необходимо использовать наблюдаемый объект или подписку на событие смены языка.

Пример с использованием подписки на событие i18next:

i18next.on('languageChanged', () => {
  riot.update();
});

В этом случае все компоненты, содержащие i18next.t(), будут автоматически обновлены при смене языка.

Выбор формата дат и чисел

Локализация включает не только текст, но и форматирование дат, времени и чисел. i18next совместим с библиотеками moment.js или Intl API, что позволяет адаптировать контент под региональные стандарты:

const date = new Date();
<p>{ new Intl.DateTimeFormat(i18next.language).format(date) }</p>
<p>{ new Intl.NumberFormat(i18next.language, { style: 'currency', currency: 'RUB' }).format(1000) }</p>

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

Управление языковыми переключателями

Часто в приложении требуется предоставить пользователю возможность выбора языка. Переключатель может быть простым <select>:

<select oncha nge={ changeLang }>
  <option value="ru">Русский</option>
  <option value="en">English</option>
</select>

<script>
  changeLang(e) {
    i18next.changeLanguage(e.target.value);
  }
</script>

После смены языка все тексты автоматически обновятся, если использовать реактивное обновление компонентов.

Обработка отсутствующих переводов

Для стабильной работы приложения важно предусмотреть fallback. i18next позволяет задать язык по умолчанию:

i18next.init({
  lng: 'ru',
  fallbackLng: 'en',
  resources: { /* ... */ }
});

Если ключ не найден для текущего языка, будет использоваться перевод из fallback. Это предотвращает появление пустых строк и ошибок в интерфейсе.

Итоговая архитектура

  • JSON-файлы для хранения переводов, структурированные по модулям.
  • i18next или аналог для управления переводами и смены языков.
  • Реактивное обновление компонентов через подписки или this.update().
  • Плейсхолдеры и параметризация строк для динамического текста.
  • Форматирование дат и чисел через Intl API или сторонние библиотеки.
  • Fallback-стратегия для отсутствующих переводов.

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