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

FAST Element предоставляет современный подход к созданию веб-компонентов на базе стандартов Web Components и позволяет интегрировать динамическую локализацию без использования внешних фреймворков. Основной механизм построен на реактивных свойствах компонентов и возможности связывать данные с шаблоном через директивы.

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

В FAST Element любое свойство, объявленное с помощью декоратора @attr или через статическое поле observedAttributes, автоматически становится реактивным. Для реализации динамической смены языка удобно создать свойство locale:

import { FASTElement, html, css } from "@microsoft/fast-element";

class LocalizedComponent extends FASTElement {
    static styles = css`
        :host { display: block; font-family: sans-serif; }
    `;

    locale = 'en';

    translations = {
        en: { greeting: "Hello", farewell: "Goodbye" },
        ru: { greeting: "Привет", farewell: "До свидания" }
    };

    get greeting() {
        return this.translations[this.locale].greeting;
    }

    get farewell() {
        return this.translations[this.locale].farewell;
    }
}

LocalizedComponent.define({
    name: 'localized-component',
    template: html`
        <div>
            <p>${x => x.greeting}</p>
            <p>${x => x.farewell}</p>
        </div>
    `
});

В этом примере свойства greeting и farewell автоматически пересчитываются при изменении locale, что позволяет динамически менять язык интерфейса.

Директивы для реактивного отображения

FAST Element предоставляет директивы, такие как repeat и if, для управления отображением контента на основе данных. При работе с локализацией удобно использовать функцию вычисления текста внутри шаблона:

html`${x => x.translations[x.locale].greeting}`

Это позволяет не создавать отдельные геттеры для каждого текстового блока и упрощает поддержку большого количества языков.

События и переключение языка

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

changeLanguage(lang) {
    if (this.translations[lang]) {
        this.locale = lang;
    }
}

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

const component = document.querySelector('localized-component');
component.changeLanguage('ru');

После вызова changeLanguage FAST Element автоматически обновит все места, где используется реактивное свойство locale.

Интеграция с внешними источниками переводов

Для крупных проектов локализацию удобно вынести в отдельные JSON-файлы и загружать их асинхронно:

async loadTranslations(lang) {
    const response = await fetch(`/locales/${lang}.json`);
    this.translations[lang] = await response.json();
    this.locale = lang;
}

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

Использование шаблонов и слотов

При работе с локализацией важно учитывать поддержку динамического контента в слоте:

html`
    <slot name="header">${x => x.translations[x.locale].greeting}</slot>
`

Если в слоте пользователь передаёт собственный текст, директива ${x => ...} не перезапишет его, что обеспечивает гибкость и расширяемость компонентов.

Реактивные вычисления и производные свойства

FAST Element позволяет определять производные свойства на основе реактивных данных. Например, для форматирования даты или чисел под конкретный язык:

get formattedDate() {
    return new Intl.DateTimeFormat(this.locale, { dateStyle: 'long' }).format(new Date());
}

Изменение locale автоматически обновит отображение даты.

Практика построения масштабируемой локализации

  1. Создание глобального объекта локализации или сервиса, доступного через контекст компонентов.
  2. Разделение текстов по категориям (ошибки, интерфейс, уведомления) для удобного управления.
  3. Использование реактивных свойств и геттеров для минимизации дублирования шаблонного кода.
  4. Асинхронная загрузка языковых пакетов по мере необходимости.

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

  • Избегать вычислений текста непосредственно в шаблоне при больших объёмах данных; лучше использовать геттеры или функции-кеши.
  • Ограничивать количество реактивных свойств, изменяющих множество элементов одновременно.
  • При массовой смене языка применять методы FASTElement#$emit или пакетное обновление данных, чтобы уменьшить количество перерисовок.

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

class AppComponent extends FASTElement {
    locale = 'en';
    translations = {};

    async connectedCallback() {
        super.connectedCallback();
        await this.loadTranslations('en');
    }

    async loadTranslations(lang) {
        const res = await fetch(`/locales/${lang}.json`);
        this.translations[lang] = await res.json();
        this.locale = lang;
    }

    changeLanguage(lang) {
        if (this.translations[lang]) {
            this.locale = lang;
        } else {
            this.loadTranslations(lang);
        }
    }

    get greeting() {
        return this.translations[this.locale]?.greeting || '';
    }
}

AppComponent.define({
    name: 'app-component',
    template: html`<p>${x => x.greeting}</p>`
});

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