Поддержка множественных языков

Stimulus — это легковесный JavaScript-фреймворк, ориентированный на улучшение взаимодействия с DOM без необходимости сложной структуры компонентов. Одной из часто встречающихся задач является реализация поддержки множественных языков (i18n) на клиентской стороне. Stimulus обеспечивает удобный способ организации кода для динамического изменения текста и поведения интерфейса в зависимости от выбранного языка.


Использование контроллеров для локализации

Контроллеры Stimulus позволяют инкапсулировать логику управления DOM-элементами. Для поддержки нескольких языков создается отдельный контроллер, отвечающий за локализацию.

// controllers/locale_controller.js
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static values = {
    locale: String,
    translations: Object
  }

  connect() {
    this.updateText()
  }

  changeLocale(event) {
    this.localeValue = event.target.value
    this.updateText()
  }

  updateText() {
    const texts = this.translationsValue[this.localeValue] || {}
    Object.entries(texts).forEach(([key, value]) => {
      const element = this.element.querySelector(`[data-locale-key="${key}"]`)
      if (element) element.textContent = value
    })
  }
}

Ключевые моменты:

  • static values позволяет передавать контроллеру данные из HTML.
  • Метод updateText динамически обновляет содержимое элементов на основе выбранного языка.
  • Атрибут data-locale-key используется для привязки конкретных элементов к соответствующим переводам.

Структура данных для переводов

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

{
  en: {
    greeting: "Hello",
    farewell: "Goodbye"
  },
  ru: {
    greeting: "Привет",
    farewell: "До свидания"
  },
  es: {
    greeting: "Hola",
    farewell: "Adiós"
  }
}

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


Подключение контроллера в HTML

<div data-controller="locale"
     data-locale-locale-value="en"
     data-locale-translations-value='{
       "en": {"greeting":"Hello","farewell":"Goodbye"},
       "ru": {"greeting":"Привет","farewell":"До свидания"},
       "es": {"greeting":"Hola","farewell":"Adiós"}
     }'>
  <p data-locale-key="greeting"></p>
  <p data-locale-key="farewell"></p>

  <select data-action="change->locale#changeLocale">
    <option value="en">English</option>
    <option value="ru">Русский</option>
    <option value="es">Español</option>
  </select>
</div>

Особенности реализации:

  • data-controller="locale" подключает контроллер к DOM-элементу.
  • Селектор <select> с data-action="change->locale#changeLocale" автоматически вызывает метод контроллера при смене языка.
  • JSON с переводами передается через data-locale-translations-value. Для больших наборов переводов рекомендуется загружать их асинхронно через fetch.

Динамическая подгрузка переводов

В больших проектах загрузка всех языков сразу может быть неоптимальна. Stimulus позволяет интегрировать асинхронную подгрузку:

async changeLocale(event) {
  const newLocale = event.target.value
  const response = await fetch(`/locales/${newLocale}.json`)
  this.translationsValue = await response.json()
  this.localeValue = newLocale
  this.updateText()
}

Преимущества такого подхода:

  • Минимизируется первоначальный вес страницы.
  • Легко поддерживать отдельные JSON-файлы для каждого языка.
  • Можно кэшировать переводы в локальном хранилище для повторного использования.

Реактивное обновление интерфейса

Stimulus использует минималистичный реактивный подход. Изменение значения localeValue автоматически отражается на всех связанных элементах через вызов метода updateText. Это исключает необходимость ручного управления DOM при каждом изменении языка и делает код более чистым и поддерживаемым.


Совмещение с серверной локализацией

Для проектов с серверной генерацией страниц удобно комбинировать Stimulus с серверными библиотеками i18n:

  1. Сервер передает дефолтный язык и переводы в HTML.
  2. Stimulus контроллер обеспечивает переключение языков без перезагрузки страницы.
  3. Для сложных динамических данных используется асинхронная подгрузка.

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

Для масштабных приложений рекомендуется:

  • Разделять контроллеры по функциональности (например, отдельный контроллер для меню, отдельный для форм).
  • Хранить переводы в отдельных JSON-файлах, структурированных по компонентам.
  • Использовать системные ключи для переводов, избегая дублирования строк.
  • Подключать тесты на корректность отображения текста при смене языка.

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