Подходы к многоязычности в SPA

Одностраничные приложения (SPA) часто требуют поддержки нескольких языков интерфейса. В Preact это достигается сочетанием архитектурных решений, управления состоянием и библиотек для интернационализации. Основные подходы можно разделить на статическую локализацию, динамическую загрузку переводов и использование контекстов для глобального доступа к языковым ресурсам.


Статическая локализация

Статическая локализация предполагает, что все строки для разных языков заранее включены в сборку приложения. Обычно это реализуется через JSON-файлы:

// en.json
{
  "greeting": "Hello",
  "farewell": "Goodbye"
}

// ru.json
{
  "greeting": "Привет",
  "farewell": "До свидания"
}

Импорт и использование в компонентах Preact может выглядеть так:

import { h } from 'preact';
import en from './locales/en.json';
import ru from './locales/ru.json';

const messages = { en, ru };
const currentLang = 'ru';

function Greeting() {
  return <div>{messages[currentLang].greeting}</div>;
}

Преимущества:

  • Простота реализации.
  • Отсутствие дополнительного запроса к серверу.

Недостатки:

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

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

Для крупных приложений предпочтительна динамическая загрузка переводов, которая позволяет подгружать только нужные языковые файлы при смене языка. В Preact это реализуется через import() и состояние:

import { h } from 'preact';
import { useState, useEffect } from 'preact/hooks';

function useTranslations(lang) {
  const [messages, setMessages] = useState({});

  useEffect(() => {
    import(`./locales/${lang}.json`).then(module => setMessages(module.default));
  }, [lang]);

  return messages;
}

function Greeting({ lang }) {
  const messages = useTranslations(lang);
  return <div>{messages.greeting || '...'}</div>;
}

Преимущества:

  • Сборка остаётся компактной.
  • Возможность добавления новых языков без пересборки приложения.

Недостатки:

  • Необходима обработка состояния загрузки.
  • Возможны кратковременные задержки при смене языка.

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

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

import { h, createContext } from 'preact';
import { useState, useContext } from 'preact/hooks';
import en from './locales/en.json';
import ru from './locales/ru.json';

const LanguageContext = createContext();

function LanguageProvider({ children }) {
  const [lang, setLang] = useState('en');
  const messages = { en, ru }[lang];
  
  return (
    <LanguageContext.Provider value={{ lang, setLang, messages }}>
      {children}
    </LanguageContext.Provider>
  );
}

function Greeting() {
  const { messages } = useContext(LanguageContext);
  return <div>{messages.greeting}</div>;
}

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


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

Для более сложных сценариев используют библиотеки вроде i18next или preact-i18n. Они предоставляют:

  • Поддержку параметров в строках (Hello, {{name}}!).
  • Возможность форматирования дат, чисел и валют.
  • Механизмы подгрузки языков по сети.

Пример с preact-i18n:

import { h } from 'preact';
import { Text, Localizer } from 'preact-i18n';
import en from './locales/en.json';
import ru from './locales/ru.json';

const messages = { en, ru };

function App({ lang }) {
  return (
    <Localizer language={lang} messages={messages[lang]}>
      <div>
        <Text id="greeting" />
      </div>
    </Localizer>
  );
}

Преимущества библиотек:

  • Полная поддержка многоязычности без ручного управления состоянием.
  • Лёгкая интеграция с существующими компонентами.

Недостатки:

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

Выбор подхода

Выбор метода интернационализации зависит от масштабов проекта и требований к производительности:

  • Малые SPA: достаточно статической локализации.
  • Средние и крупные SPA: рекомендуется динамическая загрузка переводов и использование контекста.
  • Приложения с высокой сложностью текста и форматирования: оптимально подключение специализированных библиотек интернационализации.

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