Preact, как легковесная альтернатива React, не включает встроенной поддержки интернационализации, однако архитектура фреймворка позволяет гибко интегрировать решения для управления переводами. Основной подход заключается в создании контекста для хранения текущего языка и словаря переводов, а также в использовании хуков для динамического получения локализованных строк в компонентах.
Для централизованного управления языковыми ресурсами удобно
использовать Preact.createContext. Контекст позволяет
любому компоненту получать доступ к текущему языку и функции
переключения без необходимости пробрасывать пропсы на каждом уровне.
import { createContext } from 'preact';
import { useState } from 'preact/hooks';
const TranslationContext = createContext({
language: 'en',
translations: {},
setLanguage: () => {}
});
export const TranslationProvider = ({ children, defaultLanguage = 'en', dictionaries }) => {
const [language, setLanguage] = useState(defaultLanguage);
const value = {
language,
translations: dictionaries[language] || {},
setLanguage
};
return (
<TranslationContext.Provider value={value}>
{children}
</TranslationContext.Provider>
);
};
Ключевые моменты:
dictionaries — объект, где ключи — языковые коды
('en', 'ru'), а значения — словари.setLanguage позволяет динамически менять текущий язык
приложения.Для удобства можно создать кастомный хук useTranslation,
который будет возвращать функцию для поиска перевода по ключу:
import { useContext } from 'preact/hooks';
export const useTranslation = () => {
const { translations } = useContext(TranslationContext);
const t = (key, fallback = '') => translations[key] || fallback;
return { t };
};
Особенности реализации:
t принимает ключ перевода и опциональный
fallback.Смена языка в приложении сводится к вызову функции
setLanguage из контекста. Это позволяет мгновенно обновить
все компоненты, которые используют переводы через хук.
import { useContext } from 'preact/hooks';
import { TranslationContext } from './TranslationProvider';
const LanguageSwitcher = () => {
const { setLanguage } = useContext(TranslationContext);
return (
<div>
<button onCl ick={() => setLanguage('en')}>English</button>
<button onCl ick={() => setLanguage('ru')}>Русский</button>
</div>
);
};
Эффект:
useTranslation.Словари переводов удобно хранить в виде отдельных модулей:
export const en = {
welcome: "Welcome",
login: "Login",
logout: "Logout"
};
export const ru = {
welcome: "Добро пожаловать",
login: "Войти",
logout: "Выйти"
};
Рекомендации по структуре:
auth.login, menu.home), с соответствующей
обработкой в функции t.Использование перевода в компонентах выглядит лаконично:
import { useTranslation } from './useTranslation';
const Header = () => {
const { t } = useTranslation();
return (
<header>
<h1>{t('welcome')}</h1>
<nav>
<a href="/login">{t('login')}</a>
<a href="/logout">{t('logout')}</a>
</nav>
</header>
);
};
Преимущества такого подхода:
Для крупных приложений имеет смысл подгружать словари динамически, чтобы уменьшить начальный размер бандла:
const loadTranslations = async (lang) => {
const module = await import(`./locales/${lang}.js`);
return module.default;
};
Suspense можно показывать индикатор
загрузки при смене языка.Базовый подход с объектами подходит для простых приложений, но для
сложных случаев можно использовать библиотеку i18next или
formatjs. В Preact они интегрируются аналогично, используя
контекст и хуки, сохраняя преимущества реактивного обновления при смене
языка.
i18next поддерживает интерполяцию переменных и
вложенные ключи.formatjs обеспечивает поддержку форматирования дат,
чисел и валют в зависимости от локали.Такой подход обеспечивает гибкость, минимальную зависимость от сторонних библиотек и полную реактивность интерфейса при смене языка.