Динамическая смена языков

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


Организация структуры данных для локализации

Основой динамической локализации является объект с текстами на разных языках. Он может быть оформлен в виде JSON или JavaScript-объекта:

const translations = {
  en: {
    welcome: "Welcome",
    login: "Login",
    logout: "Logout"
  },
  ru: {
    welcome: "Добро пожаловать",
    login: "Войти",
    logout: "Выйти"
  },
  es: {
    welcome: "Bienvenido",
    login: "Iniciar sesión",
    logout: "Cerrar sesión"
  }
};

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


Создание контроллера Stimulus для смены языка

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

import { Controller } from "@hotwired/stimulus";

export default class extends Controller {
  static targets = ["text"];
  static values = { language: String };

  connect() {
    this.languageValue ||= "en"; // язык по умолчанию
    this.updateTexts();
  }

  changeLanguage(event) {
    this.languageValue = event.target.value;
    this.updateTexts();
  }

  updateTexts() {
    this.textTargets.forEach((element) => {
      const key = element.dataset.translationKey;
      if (translations[this.languageValue][key]) {
        element.textContent = translations[this.languageValue][key];
      }
    });
  }
}

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

  • textTargets — элементы страницы, подлежащие локализации.
  • dataset.translationKey — ключ текста в объекте переводов.
  • languageValue — текущий выбранный язык, управляемый через Stimulus values.
  • updateTexts() — метод, обновляющий текст на странице в соответствии с выбранным языком.

Связывание HTML с контроллером

Для работы контроллера необходимо правильно расставить атрибуты data-controller, data-action и data-target. Пример:

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

  <h1 data-i18n-target="text" data-translation-key="welcome"></h1>
  <button data-i18n-target="text" data-translation-key="login"></button>
  <button data-i18n-target="text" data-translation-key="logout"></button>
</div>

В этом примере <select> инициирует событие change, которое вызывает метод changeLanguage контроллера i18n. Все элементы с data-i18n-target="text" автоматически обновляются при смене языка.


Поддержка динамического контента

Если элементы создаются динамически (через AJAX или другие методы), Stimulus позволяет автоматически подключать их к контроллеру, если они находятся внутри области действия контроллера. Необходимо лишь убедиться, что у вновь созданных элементов корректно проставлены data-i18n-target и data-translation-key. После вставки можно вызвать updateTexts():

const newElement = document.createElement("button");
newElement.dataset.i18nTarget = "text";
newElement.dataset.translationKey = "login";
this.element.appendChild(newElement);
this.updateTexts();

Расширение функциональности

  1. Поддержка нескольких областей страницы: Stimulus позволяет создать несколько контроллеров на одной странице, каждый из которых управляет своей областью локализации.
  2. Сохранение выбора языка: Выбранный язык можно сохранять в localStorage или cookies для восстановления при следующем посещении.
  3. Асинхронная загрузка переводов: Для больших приложений переводы можно загружать с сервера по мере необходимости через fetch, а затем вызывать updateTexts().

Работа с атрибутами и плейсхолдерами

Переводы часто нужны не только для текстового содержимого, но и для атрибутов, например, placeholder:

<input type="text" data-i18n-target="text" data-translation-key="login_placeholder">

Контроллер может расширяться, обновляя не только textContent, но и атрибуты:

updateAttributes() {
  this.textTargets.forEach((element) => {
    const key = element.dataset.translationKey;
    if (translations[this.languageValue][key]) {
      if (element.tagName === "INPUT") {
        element.placeholder = translations[this.languageValue][key];
      } else {
        element.textContent = translations[this.languageValue][key];
      }
    }
  });
}

Интеграция с другими библиотеками

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


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