@nuxtjs/i18n
Version:
Internationalization for Nuxt
135 lines (134 loc) • 6.73 kB
JavaScript
import { computed, ref, watch } from "vue";
import { createI18n } from "vue-i18n";
import { defineNuxtPlugin, prerenderRoutes, useNuxtApp, useRequestEvent, useRequestURL } from "#imports";
import { localeCodes, normalizedLocales } from "#build/i18n-options.mjs";
import { loadAndSetLocale, navigate } from "../utils.js";
import { extendI18n } from "../routing/i18n.js";
import { getI18nTarget } from "../compatibility.js";
import { _useLocaleHead, localeHead } from "../routing/head.js";
import { useLocalePath, useLocaleRoute, useRouteBaseName, useSwitchLocalePath } from "../composables/index.js";
import { createLocaleConfigs, getDefaultLocaleForDomain, resolveSupportedLocale } from "../shared/locales.js";
import { setupVueI18nOptions } from "../shared/vue-i18n.js";
import { createNuxtI18nContext, useLocaleConfigs } from "../context.js";
import { useI18nDetection, useRuntimeI18n } from "../shared/utils.js";
import { useDetectors } from "../shared/detection.js";
import { setupMultiDomainLocales } from "../routing/domain.js";
export default defineNuxtPlugin({
name: "i18n:plugin",
parallel: __PARALLEL_PLUGIN__,
async setup(_nuxt) {
Object.defineProperty(_nuxt.versions, "nuxtI18n", { get: () => __NUXT_I18N_VERSION__ });
const nuxt = useNuxtApp(_nuxt._id);
const runtimeI18n = useRuntimeI18n(nuxt);
const preloadedOptions = nuxt.ssrContext?.event?.context?.nuxtI18n?.vueI18nOptions;
const _defaultLocale = getDefaultLocaleForDomain(useRequestURL({ xForwardedHost: true }).host) || runtimeI18n.defaultLocale || "";
const optionsI18n = preloadedOptions || await setupVueI18nOptions(_defaultLocale);
const localeConfigs = useLocaleConfigs();
if (import.meta.server) {
localeConfigs.value = useRequestEvent().context.nuxtI18n?.localeConfigs || {};
} else {
localeConfigs.value ??= createLocaleConfigs(optionsI18n.fallbackLocale);
}
if (__MULTI_DOMAIN_LOCALES__) {
setupMultiDomainLocales(optionsI18n.defaultLocale);
}
prerenderRoutes(localeCodes.map((locale) => `${__I18N_SERVER_ROUTE__}/${locale}/messages.json`));
const i18n = createI18n(optionsI18n);
const detectors = useDetectors(useRequestEvent(nuxt), useI18nDetection(nuxt), nuxt);
const ctx = createNuxtI18nContext(nuxt, i18n, optionsI18n.defaultLocale);
nuxt._nuxtI18n = ctx;
if (__I18N_STRIP_UNUSED__ && import.meta.server) {
wrapTranslationFunctions(ctx);
}
extendI18n(i18n, {
extendComposer(composer) {
composer.locales = computed(() => runtimeI18n.locales);
composer.localeCodes = computed(() => localeCodes);
const _baseUrl = ref(ctx.getBaseUrl());
composer.baseUrl = computed(() => _baseUrl.value);
if (import.meta.client) {
watch(composer.locale, () => _baseUrl.value = ctx.getBaseUrl());
}
composer.strategy = __I18N_STRATEGY__;
composer.localeProperties = computed(
() => normalizedLocales.find((l) => l.code === composer.locale.value) || { code: composer.locale.value }
);
composer.setLocale = async (locale) => {
await loadAndSetLocale(nuxt, locale);
await nuxt.runWithContext(() => navigate(nuxt, nuxt.$router.currentRoute.value, locale));
};
composer.loadLocaleMessages = ctx.loadMessages;
composer.differentDomains = __DIFFERENT_DOMAINS__;
composer.defaultLocale = optionsI18n.defaultLocale;
composer.getBrowserLocale = () => import.meta.client ? resolveSupportedLocale(detectors.navigator()) : resolveSupportedLocale(detectors.header());
composer.getLocaleCookie = () => resolveSupportedLocale(detectors.cookie());
composer.setLocaleCookie = ctx.setCookieLocale;
composer.finalizePendingLocaleChange = async () => {
if (!i18n.__pendingLocale) {
return;
}
await i18n.__resolvePendingLocalePromise?.();
};
composer.waitForPendingLocaleChange = async () => {
await i18n?.__pendingLocalePromise;
};
},
extendComposerInstance(instance, c) {
const props = [
["locales", () => c.locales],
["localeCodes", () => c.localeCodes],
["baseUrl", () => c.baseUrl],
["strategy", () => __I18N_STRATEGY__],
["localeProperties", () => c.localeProperties],
["setLocale", () => (locale) => Reflect.apply(c.setLocale, c, [locale])],
["loadLocaleMessages", () => (locale) => Reflect.apply(c.loadLocaleMessages, c, [locale])],
["differentDomains", () => __DIFFERENT_DOMAINS__],
["defaultLocale", () => c.defaultLocale],
["getBrowserLocale", () => () => Reflect.apply(c.getBrowserLocale, c, [])],
["getLocaleCookie", () => () => Reflect.apply(c.getLocaleCookie, c, [])],
["setLocaleCookie", () => (locale) => Reflect.apply(c.setLocaleCookie, c, [locale])],
["finalizePendingLocaleChange", () => () => Reflect.apply(c.finalizePendingLocaleChange, c, [])],
["waitForPendingLocaleChange", () => () => Reflect.apply(c.waitForPendingLocaleChange, c, [])]
];
for (const [key, get] of props) {
Object.defineProperty(instance, key, { get });
}
}
});
nuxt.vueApp.use(i18n);
Object.defineProperty(nuxt, "$i18n", { get: () => getI18nTarget(i18n) });
nuxt.provide("localeHead", (options) => localeHead(nuxt._nuxtI18n.composableCtx, options));
nuxt.provide("localePath", useLocalePath(nuxt));
nuxt.provide("localeRoute", useLocaleRoute(nuxt));
nuxt.provide("routeBaseName", useRouteBaseName(nuxt));
nuxt.provide("getRouteBaseName", useRouteBaseName(nuxt));
nuxt.provide("switchLocalePath", useSwitchLocalePath(nuxt));
if (__I18N_STRICT_SEO__) {
nuxt.hook(import.meta.server ? "app:rendered" : "app:mounted", () => {
_useLocaleHead(nuxt._nuxtI18n.composableCtx, { dir: true, lang: true, seo: true });
});
}
}
});
function wrapTranslationFunctions(ctx, serverI18n = useRequestEvent()?.context?.nuxtI18n) {
if (!serverI18n) {
return;
}
const i18n = ctx.vueI18n.global;
const originalT = i18n.t.bind(i18n);
i18n.t = (key, listOrNamed, opts) => {
const locale = typeof opts === "object" && opts?.locale || ctx.getLocale();
serverI18n?.trackKey(key, locale);
return originalT(key, listOrNamed, opts);
};
const originalTe = i18n.te.bind(i18n);
i18n.te = (key, locale) => {
serverI18n?.trackKey(key, locale || ctx.getLocale());
return originalTe(key, locale);
};
const originalTm = i18n.tm.bind(i18n);
i18n.tm = (key) => {
serverI18n?.trackKey(key, ctx.getLocale());
return originalTm(key);
};
}