Slim.js — легковесный фреймворк для создания веб-компонентов, предоставляющий реактивное связывание данных и удобное управление состоянием компонентов. В современных приложениях важным аспектом является интернационализация (i18n) — возможность отображать интерфейс на разных языках. Интеграция i18n-библиотек в Slim.js требует понимания жизненного цикла компонентов и реактивности свойств.
Для работы с i18n чаще всего используют библиотеки вроде i18next, Polyglot.js или messageformat.js. Подключение осуществляется стандартным образом через npm:
npm install i18next
После установки библиотеку нужно инициализировать перед использованием в компонентах:
import i18next from 'i18next';
i18next.init({
lng: 'en',
resources: {
en: {
translation: {
greeting: "Hello, {{name}}!"
}
},
ru: {
translation: {
greeting: "Привет, {{name}}!"
}
}
}
});
Инициализация создаёт глобальный объект, через который можно получать локализованные строки.
Slim.js позволяет создавать реактивные свойства компонентов с помощью
декораторов @prop или объявления через массив
observedAttributes. Для интеграции i18n необходимо
привязать отображаемые значения к локализованным строкам:
import { Slim, html } from 'slim-js';
class GreetingComponent extends Slim {
static get observedAttributes() { return ['name', 'lang']; }
onBeforeCreated() {
this.name = this.name || 'User';
this.lang = this.lang || 'en';
}
get greeting() {
return i18next.getFixedT(this.lang)('greeting', { name: this.name });
}
render() {
return html`<p>${this.greeting}</p>`;
}
}
customElements.define('greeting-component', GreetingComponent);
Ключевой момент: свойство lang
реагирует на изменения, что позволяет динамически обновлять язык
компонента без перезагрузки страницы.
Slim.js поддерживает автоматический ререндер при изменении атрибутов. Для полноценного реагирования на смену языка нужно использовать наблюдаемые свойства и методы жизненного цикла:
attributeChangedCallback(attrName, oldVal, newVal) {
if (attrName === 'lang' && oldVal !== newVal) {
this.update();
}
}
Метод update() инициирует перерисовку компонента с
новыми локализованными строками.
В больших приложениях часто используется иерархия компонентов. Для передачи текущего языка вниз по дереву удобно использовать контекстные свойства или кастомные события:
// Родительский компонент
class AppRoot extends Slim {
static get observedAttributes() { return ['lang']; }
attributeChangedCallback(attrName, oldVal, newVal) {
if (attrName === 'lang') {
this.querySelectorAll('child-component').forEach(child => {
child.lang = newVal;
});
}
}
render() {
return html`
<child-component name="Alice" lang="${this.lang}"></child-component>
<child-component name="Bob" lang="${this.lang}"></child-component>
`;
}
}
Такой подход гарантирует, что все вложенные компоненты автоматически получают актуальный язык при изменении родительского свойства.
Библиотеки i18n поддерживают плейсхолдеры, что позволяет внедрять динамические значения в переводы. В Slim.js это удобно делать через вычисляемые свойства:
get farewell() {
return i18next.getFixedT(this.lang)('farewell', { name: this.name, date: new Date().toLocaleDateString(this.lang) });
}
Динамическая подстановка значений работает напрямую с реактивной системой Slim.js, обеспечивая синхронизацию интерфейса с данными.
Для крупных приложений часто требуется ленивая загрузка языковых файлов. i18next поддерживает загрузку ресурсов через XHR или fetch. В Slim.js можно использовать асинхронную инициализацию внутри жизненного цикла компонента:
async onBeforeCreated() {
await i18next.init({
lng: this.lang,
backend: {
loadPath: '/locales/{{lng}}.json'
}
});
}
После загрузки переводов можно вызвать this.update() для
обновления интерфейса.
class Dashboard extends Slim {
static get observedAttributes() { return ['lang']; }
async onBeforeCreated() {
await i18next.init({
lng: this.lang,
backend: { loadPath: `/locales/{{lng}}.json` }
});
this.update();
}
get title() {
return i18next.getFixedT(this.lang)('dashboard.title');
}
get welcomeMessage() {
return i18next.getFixedT(this.lang)('dashboard.welcome', { user: this.userName });
}
render() {
return html`
<h1>${this.title}</h1>
<p>${this.welcomeMessage}</p>
`;
}
}
customElements.define('dashboard-component', Dashboard);
В этом примере демонстрируется полная интеграция с динамическими переводами, реактивными свойствами и поддержкой асинхронной загрузки языковых ресурсов.