Интернационализация (i18n) — это процесс подготовки приложения к поддержке нескольких языков и региональных особенностей. В контексте Hyperapp подход к i18n строится на минимализме, реактивности и простой архитектуре состояния. Рассмотрим ключевые аспекты реализации интернационализации на примере реального приложения.
Hyperapp опирается на одно глобальное состояние, которое обновляется через actions. Для i18n удобнее всего хранить текущую локаль и словари переводов именно в состоянии.
import { h, app } from "hyperapp";
const state = {
locale: "en",
translations: {
en: {
greeting: "Hello",
farewell: "Goodbye"
},
ru: {
greeting: "Привет",
farewell: "До свидания"
}
}
};
const actions = {
setLocale: locale => state => ({ locale })
};
В этом примере locale определяет текущий язык
приложения, а translations хранит переводы для каждого
языка. Использование состояния Hyperapp обеспечивает автоматическое
обновление UI при смене локали.
Чтобы избежать дублирования кода, создается функция-обертка, которая возвращает нужный перевод на основе текущей локали:
const t = (key) => (state) => state.translations[state.locale][key] || key;
Применение:
const view = (state, actions) => h("div", {}, [
h("h1", {}, t("greeting")(state)),
h("button", { onclick: () => actions.setLocale("ru") }, "RU"),
h("button", { onclick: () => actions.setLocale("en") }, "EN")
]);
Ключевым моментом является ленивое вычисление перевода через
состояние, что позволяет при смене locale
автоматически обновлять все тексты в приложении.
Для крупных приложений рекомендуется структурировать переводы по модулям:
/i18n
en.js
ru.js
Пример en.js:
export default {
greeting: "Hello",
farewell: "Goodbye",
menu: {
home: "Home",
about: "About"
}
};
Импорт и объединение словарей:
import en from "./i18n/en";
import ru from "./i18n/ru";
const state = {
locale: "en",
translations: { en, ru }
};
Такой подход облегчает поддержку большого количества переводов и упрощает масштабирование.
В современных приложениях часто требуется ленивая загрузка локалей, чтобы не грузить все переводы сразу. В Hyperapp это можно реализовать через асинхронные actions:
const actions = {
loadLocale: locale => async state => {
const translations = await import(`./i18n/${locale}.js`);
return { locale, translations: { ...state.translations, [locale]: translations.default } };
}
};
Использование:
h("button", { onclick: () => actions.loadLocale("ru") }, "RU")
Такой подход минимизирует начальный размер бандла и ускоряет загрузку приложения.
Интернационализация включает не только тексты, но и
форматирование чисел, валют и дат. Для этого
используется стандартный объект Intl:
const formatDate = (date, locale) =>
new Intl.DateTimeFormat(locale, { year: "numeric", month: "long", day: "numeric" }).format(date);
const formatCurrency = (amount, locale, currency) =>
new Intl.NumberFormat(locale, { style: "currency", currency }).format(amount);
Пример использования в компоненте:
h("p", {}, `Сегодня: ${formatDate(new Date(), state.locale)}`)
Такой подход гарантирует корректное отображение данных для разных регионов без необходимости вручную управлять форматами.
Основной принцип Hyperapp — реактивное обновление UI при
изменении состояния. При смене locale весь
интерфейс, использующий функцию t, автоматически
перерендеривается. Это позволяет создавать динамически переводимые
интерфейсы без дополнительных библиотек для реактивности.
Для приложений с большим числом локалей полезно внедрять вспомогательные функции:
const availableLocales = ["en", "ru", "fr", "de"];
const isLocaleAvailable = (locale) => availableLocales.includes(locale);
Это предотвращает ошибки при попытке загрузить неизвестный язык и упрощает работу с переключением локалей в интерфейсе.
Hyperapp позволяет строить локализованные компоненты следующим образом:
const Greeting = ({ state }) => h("h1", {}, t("greeting")(state));
const Farewell = ({ state }) => h("h2", {}, t("farewell")(state));
const view = (state, actions) => h("div", {}, [
Greeting({ state }),
Farewell({ state }),
h("button", { onclick: () => actions.setLocale("ru") }, "RU"),
h("button", { onclick: () => actions.setLocale("en") }, "EN")
]);
Компоненты остаются полностью переиспользуемыми, а локализация управляется через состояние.
Intl для форматирования
дат, времени и чисел.Hyperapp предоставляет минималистичный, но мощный каркас для реализации интернационализации. Реактивное состояние, простая архитектура actions и возможность динамической загрузки локалей позволяют создавать гибкие, легкие и поддерживаемые многоязычные приложения.