@nuxtjs/i18n
Version:
Internationalization for Nuxt
123 lines (122 loc) • 5.29 kB
JavaScript
import { isRef, unref } from "vue";
import { useState, useCookie, useRequestURL } from "#imports";
import { localeLoaders } from "#build/i18n-options.mjs";
import { getLocaleMessagesMergedCached } from "./shared/messages.js";
import { createBaseUrlGetter, createComposableContext } from "./utils.js";
import { getI18nTarget } from "./compatibility.js";
import { domainFromLocale } from "./shared/domain.js";
import { isSupportedLocale } from "./shared/locales.js";
import { resolveRootRedirect, useI18nDetection, useRuntimeI18n } from "./shared/utils.js";
import { joinURL } from "ufo";
import { isString } from "@intlify/shared";
export const useLocaleConfigs = () => useState(
"i18n:cached-locale-configs",
() => void 0
);
export const useResolvedLocale = () => useState("i18n:resolved-locale", () => "");
function useI18nCookie({ cookieCrossOrigin, cookieDomain, cookieSecure, cookieKey }) {
const date = /* @__PURE__ */ new Date();
return useCookie(cookieKey || __DEFAULT_COOKIE_KEY__, {
path: "/",
readonly: false,
expires: new Date(date.setDate(date.getDate() + 365)),
sameSite: cookieCrossOrigin ? "none" : "lax",
domain: cookieDomain || void 0,
secure: cookieCrossOrigin || cookieSecure
});
}
export function createNuxtI18nContext(nuxt, vueI18n, defaultLocale) {
const i18n = getI18nTarget(vueI18n);
const runtimeI18n = useRuntimeI18n(nuxt);
const detectConfig = useI18nDetection(nuxt);
const serverLocaleConfigs = useLocaleConfigs();
const localeCookie = useI18nCookie(detectConfig);
const getLocaleConfig = (locale) => serverLocaleConfigs.value[locale];
const getDomainFromLocale = (locale) => domainFromLocale(runtimeI18n.domainLocales, useRequestURL({ xForwardedHost: true }), locale);
const baseUrl = createBaseUrlGetter(nuxt, runtimeI18n.baseUrl, defaultLocale, getDomainFromLocale);
const resolvedLocale = useResolvedLocale();
if (__I18N_SERVER_REDIRECT__ && import.meta.server && nuxt.ssrContext?.event?.context?.nuxtI18n?.detectLocale) {
resolvedLocale.value = nuxt.ssrContext.event.context.nuxtI18n.detectLocale;
}
const loadMessagesFromClient = async (locale) => {
const locales = getLocaleConfig(locale)?.fallbacks ?? [];
if (!locales.includes(locale)) locales.push(locale);
for (const k of locales) {
const msg = await nuxt.runWithContext(() => getLocaleMessagesMergedCached(k, localeLoaders[k]));
i18n.mergeLocaleMessage(k, msg);
}
};
const loadMessagesFromServer = async (locale) => {
if (locale in localeLoaders === false) return;
const headers = getLocaleConfig(locale)?.cacheable ? {} : { "Cache-Control": "no-cache" };
const messages = await $fetch(`/_i18n/${__I18N_HASH__}/${locale}/messages.json`, { headers });
for (const k of Object.keys(messages)) {
i18n.mergeLocaleMessage(k, messages[k]);
}
};
const ctx = {
vueI18n,
initial: true,
preloaded: false,
config: runtimeI18n,
rootRedirect: resolveRootRedirect(runtimeI18n.rootRedirect),
redirectStatusCode: runtimeI18n.redirectStatusCode ?? 302,
dynamicResourcesSSG: !__IS_SSR__ || !__I18N_FULL_STATIC__ && (import.meta.prerender || __IS_SSG__),
getDefaultLocale: () => defaultLocale,
getLocale: () => unref(i18n.locale),
setLocale: async (locale) => {
const oldLocale = ctx.getLocale();
if (locale === oldLocale || !isSupportedLocale(locale)) return;
if (isRef(i18n.locale)) {
i18n.locale.value = locale;
} else {
i18n.locale = locale;
}
await nuxt.callHook("i18n:localeSwitched", { newLocale: locale, oldLocale });
resolvedLocale.value = locale;
},
setLocaleSuspend: async (locale) => {
if (!isSupportedLocale(locale)) return;
ctx.vueI18n.__pendingLocale = locale;
ctx.vueI18n.__pendingLocalePromise = new Promise((resolve) => {
ctx.vueI18n.__resolvePendingLocalePromise = async () => {
ctx.setCookieLocale(locale);
await ctx.setLocale(locale);
ctx.vueI18n.__pendingLocale = void 0;
resolve();
};
});
if (import.meta.server || nuxt.isHydrating || !ctx.config.skipSettingLocaleOnNavigate) {
await ctx.vueI18n.__resolvePendingLocalePromise?.();
}
},
getLocales: () => unref(i18n.locales).map((x) => isString(x) ? { code: x } : x),
setCookieLocale: (locale) => {
if (detectConfig.useCookie && isSupportedLocale(locale)) {
localeCookie.value = locale;
}
},
getBaseUrl: (locale) => {
if (locale) {
return joinURL(getDomainFromLocale(locale) || baseUrl(), nuxt.$config.app.baseURL);
}
return joinURL(baseUrl(), nuxt.$config.app.baseURL);
},
loadMessages: async (locale) => {
try {
return ctx.dynamicResourcesSSG || import.meta.dev ? await loadMessagesFromClient(locale) : await loadMessagesFromServer(locale);
} catch (e) {
console.warn(`Failed to load messages for locale "${locale}"`, e);
}
},
composableCtx: void 0
};
ctx.composableCtx = createComposableContext(ctx, nuxt);
return ctx;
}
export function useNuxtI18nContext(nuxt) {
if (nuxt._nuxtI18n == null) {
throw new Error("Nuxt I18n context has not been set up yet.");
}
return nuxt._nuxtI18n;
}