276 lines
10 KiB
JavaScript
276 lines
10 KiB
JavaScript
import { isArray, isString, isObject } from "@intlify/shared";
|
|
import { hasProtocol } from "ufo";
|
|
import isHTTPS from "is-https";
|
|
import {
|
|
useRequestHeaders,
|
|
useRequestEvent,
|
|
useCookie as useNuxtCookie,
|
|
useRuntimeConfig,
|
|
useNuxtApp,
|
|
unref
|
|
} from "#imports";
|
|
import { NUXT_I18N_MODULE_ID, DEFAULT_COOKIE_KEY, isSSG, localeCodes, normalizedLocales } from "#build/i18n.options.mjs";
|
|
import { findBrowserLocale, getI18nTarget, getLocalesRegex } from "./routing/utils.js";
|
|
import { createLogger, initCommonComposableOptions } from "./utils.js";
|
|
export function formatMessage(message) {
|
|
return NUXT_I18N_MODULE_ID + " " + message;
|
|
}
|
|
export function callVueI18nInterfaces(i18n, name, ...args) {
|
|
const target = getI18nTarget(i18n);
|
|
const [obj, method] = [target, target[name]];
|
|
return Reflect.apply(method, obj, [...args]);
|
|
}
|
|
export function getVueI18nPropertyValue(i18n, name) {
|
|
const target = getI18nTarget(i18n);
|
|
return unref(target[name]);
|
|
}
|
|
export function defineGetter(obj, key, val) {
|
|
Object.defineProperty(obj, key, { get: () => val });
|
|
}
|
|
export function wrapComposable(fn, common = initCommonComposableOptions()) {
|
|
return (...args) => fn(common, ...args);
|
|
}
|
|
export function parseAcceptLanguage(input) {
|
|
return input.split(",").map((tag) => tag.split(";")[0]);
|
|
}
|
|
export function getBrowserLocale() {
|
|
let ret;
|
|
if (import.meta.client) {
|
|
if (navigator.languages) {
|
|
ret = findBrowserLocale(normalizedLocales, navigator.languages);
|
|
__DEBUG__ && console.log("getBrowserLocale (navigator.languages, ret) -", navigator.languages, ret);
|
|
}
|
|
} else if (import.meta.server) {
|
|
const header = useRequestHeaders(["accept-language"]);
|
|
__DEBUG__ && console.log("getBrowserLocale accept-language", header);
|
|
const accept = header["accept-language"];
|
|
if (accept) {
|
|
ret = findBrowserLocale(normalizedLocales, parseAcceptLanguage(accept));
|
|
__DEBUG__ && console.log("getBrowserLocale ret", ret);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
export function getI18nCookie() {
|
|
const detect = runtimeDetectBrowserLanguage();
|
|
const cookieKey = detect && detect.cookieKey || DEFAULT_COOKIE_KEY;
|
|
const date = /* @__PURE__ */ new Date();
|
|
const cookieOptions = {
|
|
expires: new Date(date.setDate(date.getDate() + 365)),
|
|
path: "/",
|
|
sameSite: detect && detect.cookieCrossOrigin ? "none" : "lax",
|
|
secure: detect && detect.cookieCrossOrigin || detect && detect.cookieSecure
|
|
};
|
|
if (detect && detect.cookieDomain) {
|
|
cookieOptions.domain = detect.cookieDomain;
|
|
}
|
|
return useNuxtCookie(cookieKey, cookieOptions);
|
|
}
|
|
export function getLocaleCookie(cookieRef, detect, defaultLocale) {
|
|
__DEBUG__ && console.log("getLocaleCookie", {
|
|
useCookie: detect && detect.useCookie,
|
|
cookieKey: detect && detect.cookieKey,
|
|
localeCodes
|
|
});
|
|
if (detect === false || !detect.useCookie) {
|
|
return;
|
|
}
|
|
const localeCode = cookieRef.value ?? void 0;
|
|
const env = import.meta.client ? "client" : "server";
|
|
if (localeCode == null) {
|
|
__DEBUG__ && console.log(`getLocaleCookie (${env}) - none`);
|
|
return;
|
|
}
|
|
if (localeCodes.includes(localeCode)) {
|
|
__DEBUG__ && console.log(`getLocaleCookie (${env}) - locale from cookie: `, localeCode);
|
|
return localeCode;
|
|
}
|
|
if (defaultLocale) {
|
|
__DEBUG__ && console.log(
|
|
`getLocaleCookie (${env}) - unknown locale cookie (${localeCode}), setting to defaultLocale (${defaultLocale})`
|
|
);
|
|
cookieRef.value = defaultLocale;
|
|
return defaultLocale;
|
|
}
|
|
__DEBUG__ && console.log(`getLocaleCookie (${env}) - unknown locale cookie (${localeCode}), unsetting cookie`);
|
|
cookieRef.value = void 0;
|
|
return;
|
|
}
|
|
export function setLocaleCookie(cookieRef, locale, detect) {
|
|
if (detect === false || !detect.useCookie) {
|
|
return;
|
|
}
|
|
cookieRef.value = locale;
|
|
}
|
|
export var DetectFailure = /* @__PURE__ */ ((DetectFailure2) => {
|
|
DetectFailure2["NOT_FOUND"] = "not_found_match";
|
|
DetectFailure2["FIRST_ACCESS"] = "first_access_only";
|
|
DetectFailure2["NO_REDIRECT_ROOT"] = "not_redirect_on_root";
|
|
DetectFailure2["NO_REDIRECT_NO_PREFIX"] = "not_redirect_on_no_prefix";
|
|
DetectFailure2["SSG_IGNORE"] = "detect_ignore_on_ssg";
|
|
return DetectFailure2;
|
|
})(DetectFailure || {});
|
|
var DetectFrom = /* @__PURE__ */ ((DetectFrom2) => {
|
|
DetectFrom2["COOKIE"] = "cookie";
|
|
DetectFrom2["NAVIGATOR_HEADER"] = "navigator_or_header";
|
|
DetectFrom2["FALLBACK"] = "fallback";
|
|
return DetectFrom2;
|
|
})(DetectFrom || {});
|
|
export const DefaultDetectBrowserLanguageFromResult = { locale: "" };
|
|
export function detectBrowserLanguage(route, detectLocaleContext, locale = "") {
|
|
const logger = createLogger("detectBrowserLanguage");
|
|
const _detect = runtimeDetectBrowserLanguage();
|
|
if (!_detect) {
|
|
return DefaultDetectBrowserLanguageFromResult;
|
|
}
|
|
const { strategy } = useRuntimeConfig().public.i18n;
|
|
const { ssg, callType, firstAccess, localeCookie } = detectLocaleContext;
|
|
__DEBUG__ && logger.log({ ssg, callType, firstAccess });
|
|
if (isSSG && strategy === "no_prefix" && (import.meta.server || ssg === "ssg_ignore")) {
|
|
return { locale: "", reason: "detect_ignore_on_ssg" /* SSG_IGNORE */ };
|
|
}
|
|
if (!firstAccess) {
|
|
return { locale: strategy === "no_prefix" ? locale : "", reason: "first_access_only" /* FIRST_ACCESS */ };
|
|
}
|
|
const { redirectOn, alwaysRedirect, useCookie, fallbackLocale } = _detect;
|
|
const path = isString(route) ? route : route.path;
|
|
__DEBUG__ && logger.log({ locale, path, strategy, alwaysRedirect, redirectOn });
|
|
if (strategy !== "no_prefix") {
|
|
if (redirectOn === "root" && path !== "/") {
|
|
__DEBUG__ && logger.log("not root", { path });
|
|
return { locale: "", reason: "not_redirect_on_root" /* NO_REDIRECT_ROOT */ };
|
|
}
|
|
__DEBUG__ && redirectOn === "no prefix" && logger.log("no prefix -", { path });
|
|
if (redirectOn === "no prefix" && !alwaysRedirect && path.match(getLocalesRegex(localeCodes))) {
|
|
return { locale: "", reason: "not_redirect_on_no_prefix" /* NO_REDIRECT_NO_PREFIX */ };
|
|
}
|
|
}
|
|
let from;
|
|
const cookieMatch = useCookie && localeCookie || void 0;
|
|
if (useCookie) {
|
|
from = "cookie" /* COOKIE */;
|
|
}
|
|
const browserMatch = getBrowserLocale();
|
|
if (!cookieMatch) {
|
|
from = "navigator_or_header" /* NAVIGATOR_HEADER */;
|
|
}
|
|
const matchedLocale = cookieMatch || browserMatch;
|
|
const resolved = matchedLocale || fallbackLocale || "";
|
|
if (!matchedLocale && fallbackLocale) {
|
|
from = "fallback" /* FALLBACK */;
|
|
}
|
|
__DEBUG__ && logger.log({ locale: resolved, cookieMatch, browserMatch, from });
|
|
return { locale: resolved, from };
|
|
}
|
|
export function getHost() {
|
|
let host;
|
|
if (import.meta.client) {
|
|
host = window.location.host;
|
|
} else if (import.meta.server) {
|
|
const header = useRequestHeaders(["x-forwarded-host", "host"]);
|
|
let detectedHost;
|
|
if ("x-forwarded-host" in header) {
|
|
detectedHost = header["x-forwarded-host"];
|
|
} else if ("host" in header) {
|
|
detectedHost = header["host"];
|
|
}
|
|
host = isArray(detectedHost) ? detectedHost[0] : detectedHost;
|
|
}
|
|
return host;
|
|
}
|
|
export function getLocaleDomain(locales, strategy, route) {
|
|
let host = getHost() || "";
|
|
if (host) {
|
|
__DEBUG__ && console.log(
|
|
`MultiDomainsMultiLocales: locating domain for host: `,
|
|
host,
|
|
strategy,
|
|
isObject(route) ? route.path : route
|
|
);
|
|
let matchingLocale;
|
|
const matchingLocales = locales.filter((locale) => {
|
|
if (locale && locale.domain) {
|
|
let domain = locale.domain;
|
|
if (hasProtocol(locale.domain)) {
|
|
domain = locale.domain.replace(/(http|https):\/\//, "");
|
|
}
|
|
return domain === host;
|
|
} else if (Array.isArray(locale?.domains)) {
|
|
return locale.domains.includes(host);
|
|
}
|
|
return false;
|
|
});
|
|
if (matchingLocales.length === 1) {
|
|
matchingLocale = matchingLocales[0];
|
|
__DEBUG__ && console.log(`MultiDomainsMultiLocales: found only one matching domain: `, host, matchingLocales[0].code);
|
|
} else if (matchingLocales.length > 1) {
|
|
if (strategy === "no_prefix") {
|
|
console.warn(
|
|
formatMessage(
|
|
"Multiple matching domains found! This is not supported for no_prefix strategy in combination with differentDomains!"
|
|
)
|
|
);
|
|
matchingLocale = matchingLocales[0];
|
|
} else {
|
|
if (route) {
|
|
const routePath = isObject(route) ? route.path : isString(route) ? route : "";
|
|
__DEBUG__ && console.log(`MultiDomainsMultiLocales: Check in matched domain for locale match in path: `, routePath, host);
|
|
if (routePath && routePath !== "") {
|
|
const matches = routePath.match(getLocalesRegex(matchingLocales.map((l) => l.code)));
|
|
if (matches && matches.length > 1) {
|
|
matchingLocale = matchingLocales.find((l) => l.code === matches[1]);
|
|
__DEBUG__ && console.log(
|
|
`MultiDomainsMultiLocales: Found matching locale from path. MatchingLocale is now`,
|
|
matchingLocale?.code
|
|
);
|
|
}
|
|
}
|
|
}
|
|
if (!matchingLocale) {
|
|
matchingLocale = matchingLocales.find(
|
|
(l) => Array.isArray(l.defaultForDomains) ? l.defaultForDomains.includes(host) : l.domainDefault
|
|
);
|
|
__DEBUG__ && console.log(
|
|
`MultiDomainsMultiLocales: matching locale not found - trying to get default for this domain. MatchingLocale is now`,
|
|
matchingLocale?.code
|
|
);
|
|
}
|
|
}
|
|
}
|
|
if (matchingLocale) {
|
|
return matchingLocale.code;
|
|
} else {
|
|
host = "";
|
|
}
|
|
}
|
|
return host;
|
|
}
|
|
export function getDomainFromLocale(localeCode) {
|
|
const runtimeConfig = useRuntimeConfig();
|
|
const nuxtApp = useNuxtApp();
|
|
const host = getHost();
|
|
const config = runtimeConfig.public.i18n;
|
|
const lang = normalizedLocales.find((locale) => locale.code === localeCode);
|
|
const domain = config?.locales?.[localeCode]?.domain || lang?.domain || config?.locales?.[localeCode]?.domains?.find((v) => v === host) || lang?.domains?.find((v) => v === host);
|
|
if (domain) {
|
|
if (hasProtocol(domain, { strict: true })) {
|
|
return domain;
|
|
}
|
|
let protocol;
|
|
if (import.meta.server) {
|
|
const {
|
|
node: { req }
|
|
} = useRequestEvent(nuxtApp);
|
|
protocol = req && isHTTPS(req) ? "https:" : "http:";
|
|
} else {
|
|
protocol = new URL(window.location.origin).protocol;
|
|
}
|
|
return protocol + "//" + domain;
|
|
}
|
|
console.warn(formatMessage("Could not find domain name for locale " + localeCode));
|
|
}
|
|
export const runtimeDetectBrowserLanguage = (opts = useRuntimeConfig().public.i18n) => {
|
|
if (opts?.detectBrowserLanguage === false) return false;
|
|
return opts?.detectBrowserLanguage;
|
|
};
|