272 lines
7.8 KiB
JavaScript
272 lines
7.8 KiB
JavaScript
import { appendForwardSlash, joinPaths } from "@astrojs/internal-helpers/path";
|
|
import { shouldAppendForwardSlash } from "../core/build/util.js";
|
|
import { REROUTE_DIRECTIVE_HEADER } from "../core/constants.js";
|
|
import { MissingLocale, i18nNoLocaleFoundInPath } from "../core/errors/errors-data.js";
|
|
import { AstroError } from "../core/errors/index.js";
|
|
import { createI18nMiddleware } from "./middleware.js";
|
|
function requestHasLocale(locales) {
|
|
return function(context) {
|
|
return pathHasLocale(context.url.pathname, locales);
|
|
};
|
|
}
|
|
function requestIs404Or500(request, base = "") {
|
|
const url = new URL(request.url);
|
|
return url.pathname.startsWith(`${base}/404`) || url.pathname.startsWith(`${base}/500`);
|
|
}
|
|
function pathHasLocale(path, locales) {
|
|
const segments = path.split("/");
|
|
for (const segment of segments) {
|
|
for (const locale of locales) {
|
|
if (typeof locale === "string") {
|
|
if (normalizeTheLocale(segment) === normalizeTheLocale(locale)) {
|
|
return true;
|
|
}
|
|
} else if (segment === locale.path) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
function getLocaleRelativeUrl({
|
|
locale,
|
|
base,
|
|
locales: _locales,
|
|
trailingSlash,
|
|
format,
|
|
path,
|
|
prependWith,
|
|
normalizeLocale = true,
|
|
strategy = "pathname-prefix-other-locales",
|
|
defaultLocale
|
|
}) {
|
|
const codeToUse = peekCodePathToUse(_locales, locale);
|
|
if (!codeToUse) {
|
|
throw new AstroError({
|
|
...MissingLocale,
|
|
message: MissingLocale.message(locale)
|
|
});
|
|
}
|
|
const pathsToJoin = [base, prependWith];
|
|
const normalizedLocale = normalizeLocale ? normalizeTheLocale(codeToUse) : codeToUse;
|
|
if (strategy === "pathname-prefix-always" || strategy === "pathname-prefix-always-no-redirect" || strategy === "domains-prefix-always" || strategy === "domains-prefix-always-no-redirect") {
|
|
pathsToJoin.push(normalizedLocale);
|
|
} else if (locale !== defaultLocale) {
|
|
pathsToJoin.push(normalizedLocale);
|
|
}
|
|
pathsToJoin.push(path);
|
|
if (shouldAppendForwardSlash(trailingSlash, format)) {
|
|
return appendForwardSlash(joinPaths(...pathsToJoin));
|
|
} else {
|
|
return joinPaths(...pathsToJoin);
|
|
}
|
|
}
|
|
function getLocaleAbsoluteUrl({ site, isBuild, ...rest }) {
|
|
const localeUrl = getLocaleRelativeUrl(rest);
|
|
const { domains, locale } = rest;
|
|
let url;
|
|
if (isBuild && domains && domains[locale]) {
|
|
const base = domains[locale];
|
|
url = joinPaths(base, localeUrl.replace(`/${rest.locale}`, ""));
|
|
} else {
|
|
if (site) {
|
|
url = joinPaths(site, localeUrl);
|
|
} else {
|
|
url = localeUrl;
|
|
}
|
|
}
|
|
if (shouldAppendForwardSlash(rest.trailingSlash, rest.format)) {
|
|
return appendForwardSlash(url);
|
|
} else {
|
|
return url;
|
|
}
|
|
}
|
|
function getLocaleRelativeUrlList({
|
|
locales: _locales,
|
|
...rest
|
|
}) {
|
|
const locales = toPaths(_locales);
|
|
return locales.map((locale) => {
|
|
return getLocaleRelativeUrl({ ...rest, locales, locale });
|
|
});
|
|
}
|
|
function getLocaleAbsoluteUrlList(params) {
|
|
const locales = toCodes(params.locales);
|
|
return locales.map((currentLocale) => {
|
|
return getLocaleAbsoluteUrl({ ...params, locale: currentLocale });
|
|
});
|
|
}
|
|
function getPathByLocale(locale, locales) {
|
|
for (const loopLocale of locales) {
|
|
if (typeof loopLocale === "string") {
|
|
if (loopLocale === locale) {
|
|
return loopLocale;
|
|
}
|
|
} else {
|
|
for (const code of loopLocale.codes) {
|
|
if (code === locale) {
|
|
return loopLocale.path;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
throw new AstroError(i18nNoLocaleFoundInPath);
|
|
}
|
|
function getLocaleByPath(path, locales) {
|
|
for (const locale of locales) {
|
|
if (typeof locale !== "string") {
|
|
if (locale.path === path) {
|
|
const code = locale.codes.at(0);
|
|
if (code === void 0) throw new AstroError(i18nNoLocaleFoundInPath);
|
|
return code;
|
|
}
|
|
} else if (locale === path) {
|
|
return locale;
|
|
}
|
|
}
|
|
throw new AstroError(i18nNoLocaleFoundInPath);
|
|
}
|
|
function normalizeTheLocale(locale) {
|
|
return locale.replaceAll("_", "-").toLowerCase();
|
|
}
|
|
function toCodes(locales) {
|
|
return locales.map((loopLocale) => {
|
|
if (typeof loopLocale === "string") {
|
|
return loopLocale;
|
|
} else {
|
|
return loopLocale.codes[0];
|
|
}
|
|
});
|
|
}
|
|
function toPaths(locales) {
|
|
return locales.map((loopLocale) => {
|
|
if (typeof loopLocale === "string") {
|
|
return loopLocale;
|
|
} else {
|
|
return loopLocale.path;
|
|
}
|
|
});
|
|
}
|
|
function peekCodePathToUse(locales, locale) {
|
|
for (const loopLocale of locales) {
|
|
if (typeof loopLocale === "string") {
|
|
if (loopLocale === locale) {
|
|
return loopLocale;
|
|
}
|
|
} else {
|
|
for (const code of loopLocale.codes) {
|
|
if (code === locale) {
|
|
return loopLocale.path;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return void 0;
|
|
}
|
|
function redirectToDefaultLocale({
|
|
trailingSlash,
|
|
format,
|
|
base,
|
|
defaultLocale
|
|
}) {
|
|
return function(context, statusCode) {
|
|
if (shouldAppendForwardSlash(trailingSlash, format)) {
|
|
return context.redirect(`${appendForwardSlash(joinPaths(base, defaultLocale))}`, statusCode);
|
|
} else {
|
|
return context.redirect(`${joinPaths(base, defaultLocale)}`, statusCode);
|
|
}
|
|
};
|
|
}
|
|
function notFound({ base, locales }) {
|
|
return function(context, response) {
|
|
if (response?.headers.get(REROUTE_DIRECTIVE_HEADER) === "no") return response;
|
|
const url = context.url;
|
|
const isRoot = url.pathname === base + "/" || url.pathname === base;
|
|
if (!(isRoot || pathHasLocale(url.pathname, locales))) {
|
|
if (response) {
|
|
response.headers.set(REROUTE_DIRECTIVE_HEADER, "no");
|
|
return new Response(response.body, {
|
|
status: 404,
|
|
headers: response.headers
|
|
});
|
|
} else {
|
|
return new Response(null, {
|
|
status: 404,
|
|
headers: {
|
|
[REROUTE_DIRECTIVE_HEADER]: "no"
|
|
}
|
|
});
|
|
}
|
|
}
|
|
return void 0;
|
|
};
|
|
}
|
|
function redirectToFallback({
|
|
fallback,
|
|
locales,
|
|
defaultLocale,
|
|
strategy,
|
|
base,
|
|
fallbackType
|
|
}) {
|
|
return async function(context, response) {
|
|
if (response.status >= 300 && fallback) {
|
|
const fallbackKeys = fallback ? Object.keys(fallback) : [];
|
|
const segments = context.url.pathname.split("/");
|
|
const urlLocale = segments.find((segment) => {
|
|
for (const locale of locales) {
|
|
if (typeof locale === "string") {
|
|
if (locale === segment) {
|
|
return true;
|
|
}
|
|
} else if (locale.path === segment) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
});
|
|
if (urlLocale && fallbackKeys.includes(urlLocale)) {
|
|
const fallbackLocale = fallback[urlLocale];
|
|
const pathFallbackLocale = getPathByLocale(fallbackLocale, locales);
|
|
let newPathname;
|
|
if (pathFallbackLocale === defaultLocale && strategy === "pathname-prefix-other-locales") {
|
|
if (context.url.pathname.includes(`${base}`)) {
|
|
newPathname = context.url.pathname.replace(`/${urlLocale}`, ``);
|
|
} else {
|
|
newPathname = context.url.pathname.replace(`/${urlLocale}`, `/`);
|
|
}
|
|
} else {
|
|
newPathname = context.url.pathname.replace(`/${urlLocale}`, `/${pathFallbackLocale}`);
|
|
}
|
|
if (fallbackType === "rewrite") {
|
|
return await context.rewrite(newPathname);
|
|
} else {
|
|
return context.redirect(newPathname);
|
|
}
|
|
}
|
|
}
|
|
return response;
|
|
};
|
|
}
|
|
function createMiddleware(i18nManifest, base, trailingSlash, format) {
|
|
return createI18nMiddleware(i18nManifest, base, trailingSlash, format);
|
|
}
|
|
export {
|
|
createMiddleware,
|
|
getLocaleAbsoluteUrl,
|
|
getLocaleAbsoluteUrlList,
|
|
getLocaleByPath,
|
|
getLocaleRelativeUrl,
|
|
getLocaleRelativeUrlList,
|
|
getPathByLocale,
|
|
normalizeTheLocale,
|
|
notFound,
|
|
pathHasLocale,
|
|
redirectToDefaultLocale,
|
|
redirectToFallback,
|
|
requestHasLocale,
|
|
requestIs404Or500,
|
|
toCodes,
|
|
toPaths
|
|
};
|