Библиотека NPM для интернационализации и локализации i18n
очень популярен, но в последние годы он сильно вырос. Он имеет множество функций для локализации дат, чисел, множественного числа, двунаправленных алфавитов, загрузки локалей с сервера и множества других вещей. На сайте i18next это уже называетсярамки интернационализации“.
вплоть до точки
Новый авиалайнер. Хозяйка входит в каюту:
— Вы на нашем новом авиалайнере. У нас есть кинозал в носу самолета, зал игровых автоматов в хвосте, бассейн на нижней палубе и сауна на верхней палубе. А теперь, дамы и господа, пристегните ремни, и мы попробуем взлететь со всем этим дерьмом.
В то же время для определения местоположения сайта в большинстве случаев требуются очень простые вещи, занимающие всего несколько процентов от набора функций тяжеловеса i18n.
В частности, мне лично нужно:
-
Поиск перевода по составному ключу –
t("finance.transactions.deposit")
-
Перевод с параметром –
t("hello-message", "Вася")
-
Таблицы для списков или абзацев текста
На примере Vue 3 я покажу вам, как избавиться от i18next
без потери функциональности в этом случае, не только за счет облегчения js бандла, но и за счет сокращения кода, при этом сохраняя отзывчивость (смена языка сайта на лету)
Простота и элегантность рефакторинга, описанного ниже, будут обеспечены Vue 3 Composition API, но в целом этот метод подойдет для любого адаптивного фреймворка.
Ваш i18n
Вот чистая реализация вышеуказанного функционала в 30 строк против полутора мегабайт без всяких зависимостей — https://stackblitz.com/edit/i18n-detox?file=src%2FApp.vue
Проект Vue 3 с i18next
По умолчанию в проекте с API композиции подключение и использование i18next происходит так
Для
// main.js
import { i18n, useI18n } from "@/app/composables/i18n";
const { initI18n } = useI18n();
initI18n();
app.use(i18n);
// useI18n.js
import { ref } from "vue";
import { api } from "@/services";
import { createI18n } from "vue-i18n";
const locales = [
{
code: "en",
name: "English",
flag: "england",
},
{
code: "ru",
name: "Pусский",
flag: "russian",
},
];
const locale = ref();
export const i18n = createI18n({
I18nScope: "global",
globalInjection: true,
legacy: false,
allowComposition: true,
fallbackLocale: import.meta.env.VITE_I18N_FALLBACK_LOCALE || "en",
formatFallbackMessages: true,
});
export function useI18n() {
function initI18n() {
const lang =
localStorage.getItem(import.meta.env.VITE_APP_NAME + "_lang") ??
(import.meta.env.VITE_DEFAULT_LOCALE || "en");
loadLanguage(lang);
}
async function loadLanguage(lang) {
if (i18n.global.locale !== lang) {
locale.value = locales.find((l) => l.code === lang);
const data = await api.utils.downloadLanguage(lang);
i18n.global.setLocaleMessage(lang, data[lang]);
i18n.global.locale.value = lang;
localStorage.setItem(import.meta.env.VITE_APP_NAME + "_lang", lang);
}
}
return {
i18n,
locale,
locales,
initI18n,
loadLanguage,
};
};
// Использование в компонентах Composition API
import { useI18n } from "vue-i18n";
const { t } = useI18n();
t("finance.transactions.deposit"),
// Использование в js файлах
import { i18n } from "@/app/composables/i18n";
i18n.global.t("finance.transactions.deposit")
Все, что вам нужно, чтобы избавиться от i18next
заключается в явном определении объекта messages
чтобы сохранить все локали и добавить в useI18n()
реактивная функция t()
который будет просто обрабатывать составной ключ, параметр и массив.
После этого вы можете прокомментировать все использование библиотеки vue-i18n
После
// main.js
import { useI18n } from "@/app/composables/i18n";
const { initI18n } = useI18n();
initI18n();
// app.use(i18n);
// useI18n.js
import { ref } from "vue";
import { api } from "@/services";
// import { createI18n } from "vue-i18n";
const locales = [
{
code: "en",
name: "English",
flag: "england",
},
{
code: "ru",
name: "Pусский",
flag: "russian",
},
];
// export const i18n = createI18n({
// I18nScope: "global",
// globalInjection: true,
// legacy: false,
// allowComposition: true,
// fallbackLocale: import.meta.env.VITE_I18N_FALLBACK_LOCALE || "en",
// formatFallbackMessages: true,
// // messages: { en: messages }
// });
const locale = ref();
let messages;
// Делаем доступ для использования в js модулях
export const t = useI18n().t;
export function useI18n() {
function initI18n() {
messages = [];
const lang =
localStorage.getItem(import.meta.env.VITE_APP_NAME + "_lang") ??
(import.meta.env.VITE_APP_DEFAULT_LOCALE || "en");
loadLanguage(lang);
}
async function loadLanguage(lang) {
if (locale.value !== lang) {
const localeMessages = await api.utils.downloadLanguage(lang);
messages[lang] = localeMessages[lang];
locale.value = locales.find((l) => l.code === lang);
// i18n.global.setLocaleMessage(lang, localeMessages[lang]);
// i18n.global.locale.value = lang;
localStorage.setItem(import.meta.env.VITE_APP_NAME + "_lang", lang);
}
}
function t(msg, param = null) {
let val = msg.split(".").reduce((val, part) => val[part], messages[locale.value.code]);
if (param) {
val = val.replace("{0}", param);
}
return val;
}
return {
t,
// i18n,
locale,
locales,
initI18n,
loadLanguage,
};
}
// Использование в компонентах Composition API
import { useI18n } from "@/app/composables/i18n";
const { t } = useI18n();
t("finance.transactions.deposit"),
// ИЛИ
import { t } from "@/app/composables/i18n";
t("finance.transactions.deposit")
// Использование в js файлах
import { t } from "@/app/composables/i18n";
t("finance.transactions.deposit")
В этом примере перевод для определенной локали загружается с сервера по запросу, но объект messages
вы можете иметь на клиенте немедленно
А.к.а export const t = useI18n().t;
позволяет использовать тот же синтаксис в компонентах и модулях js.
I18следующие расширения
ты I18next
есть расширение для `Vue DevTools` (довольно бесполезное), а есть расширение I18следующий союзник для кода MS VS (очень полезно). так вот I18next Ally
работает с новой реализацией, если package.json содержит пакет vue-i18n
в зависимостях (нет необходимости включать его в код). Я рекомендую. Однако оба расширения потребляют много ресурсов, поэтому лучше использовать их по мере необходимости.
Общий
Мы закомментировали больше строк, чем добавили, а размер пакета JavaScript после сборки уменьшился на 50 КБ, функциональность осталась. Реагент.
До (vue 3, vue-router, тостер, vue-i18n)

После (vue 3, vue-router, тостер)

Спасибо, I18next, и до свидания.
Другой мой пост на эту тему — «Работа с i18n — автоматизация Google Translate и другие полезные советы».