Подходы к i18n в Slim.js

Slim.js — это лёгкий и высокопроизводительный фреймворк для создания веб-компонентов и реактивных интерфейсов на JavaScript. При работе с многоязычными приложениями ключевым становится подход к интернационализации (i18n), который позволяет эффективно управлять переводами и локализацией без снижения производительности.

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

Структура локализационных файлов

Для поддержки i18n принято использовать JSON-файлы, где ключи представляют уникальные идентификаторы строк, а значения — переводы:

{
  "greeting": "Привет",
  "farewell": "До свидания",
  "button.submit": "Отправить"
}

Каждая локаль хранится в отдельном файле, например en.json, ru.json, fr.json. Такой подход упрощает управление переводами и добавление новых языков.

Реактивное связывание текстов

Slim.js предоставляет реактивные свойства, которые позволяют автоматически обновлять тексты в компоненте при смене языка. Пример использования:

class MyComponent extends Slim {
  static get observedAttributes() { return ['lang']; }

  constructor() {
    super();
    this.lang = 'ru';
    this.translations = {};
  }

  onBeforeRender() {
    this.loadTranslations(this.lang);
  }

  loadTranslations(lang) {
    fetch(`/i18n/${lang}.json`)
      .then(res => res.json())
      .then(data => {
        this.translations = data;
        this.update();
      });
  }

  render() {
    return `
      <h1>${this.translations.greeting || '...'}</h1>
      <button>${this.translations['button.submit'] || '...'}</button>
    `;
  }
}

customElements.define('my-component', MyComponent);

Особенности подхода:

  • Использование реактивного свойства translations позволяет автоматически обновлять DOM при смене языка.
  • Метод onBeforeRender гарантирует, что компоненты загружены с актуальными переводами до рендера.

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

Slim.js поддерживает обновление локали в рантайме без пересоздания компонента:

const component = document.querySelector('my-component');
component.lang = 'en'; // автоматически подгрузит переводы и обновит интерфейс

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

export const i18nService = {
  currentLang: 'ru',
  subscribers: [],
  
  setLang(lang) {
    this.currentLang = lang;
    this.subscribers.forEach(cb => cb(lang));
  },

  subscribe(cb) {
    this.subscribers.push(cb);
  }
};

Компоненты подписываются на изменения языка:

i18nService.subscribe(lang => {
  component.lang = lang;
});

Шаблоны с параметрами

Переводы часто содержат динамические параметры. Slim.js позволяет использовать простые шаблонные функции для подстановки значений:

{
  "welcomeUser": "Добро пожаловать, {name}!"
}
render() {
  const name = 'Алексей';
  const text = this.translations.welcomeUser.replace('{name}', name);
  return `<p>${text}</p>`;
}

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

Организация i18n в больших приложениях

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

  1. Разделять переводы по модулям. Каждый компонент хранит свои ключи, чтобы уменьшить вероятность конфликтов.
  2. Использовать кеширование локалей. При загрузке JSON-файлов можно хранить данные в памяти или IndexedDB для быстрого доступа.
  3. Создавать обёртку для компонентов. Функция translate(key) позволяет абстрагировать доступ к переводам:
function translate(key, params = {}) {
  let text = Slim.i18n[currentLang][key] || key;
  for (const [k, v] of Object.entries(params)) {
    text = text.replace(`{${k}}`, v);
  }
  return text;
}
  1. Следить за реактивностью. Все компоненты должны обновляться при смене языка, чтобы избежать устаревших текстов на странице.

Локализация форматов даты и чисел

Помимо текстов, важным аспектом i18n является форматирование дат, чисел и валют. В Slim.js это можно реализовать через стандартный API Intl:

const date = new Date();
const formattedDate = new Intl.DateTimeFormat('ru-RU', { dateStyle: 'long' }).format(date);

const number = 123456.78;
const formattedNumber = new Intl.NumberFormat('ru-RU', { style: 'currency', currency: 'RUB' }).format(number);

Комбинирование реактивных свойств и Intl позволяет создавать полностью локализованные интерфейсы без сторонних библиотек.

Интеграция с существующими решениями

Slim.js легко интегрируется с внешними i18n-библиотеками. Основной принцип — обёртывание реактивного свойства компонента в механизм подписки на изменения языка. Это позволяет использовать такие возможности, как:

  • Lazy loading переводов — подгрузка только нужных языков.
  • Fallbacks — автоматический переход на дефолтный язык при отсутствии перевода.
  • Pluralization и gender forms — управление формами слов в зависимости от числительных и рода.

Практические советы

  • Держать ключи переводов краткими, но уникальными.
  • Избегать дублирования текстов между компонентами.
  • Использовать реактивные свойства Slim.js для синхронизации интерфейса при смене языка.
  • Проверять корректность подстановки параметров в шаблонах, чтобы избежать ошибок отображения.

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