astro
Version:
Astro is a modern site builder with web best practices, performance, and DX front-of-mind.
133 lines (132 loc) • 4.05 kB
JavaScript
import { REROUTE_DIRECTIVE_HEADER, ROUTE_TYPE_HEADER } from "../core/constants.js";
import { isRequestServerIsland, requestIs404Or500 } from "../core/routing/match.js";
import {
normalizeTheLocale,
notFound,
redirectToDefaultLocale,
redirectToFallback,
requestHasLocale
} from "./index.js";
function createI18nMiddleware(i18n, base, trailingSlash, format) {
if (!i18n) return (_, next) => next();
const payload = {
...i18n,
trailingSlash,
base,
format,
domains: {}
};
const _redirectToDefaultLocale = redirectToDefaultLocale(payload);
const _noFoundForNonLocaleRoute = notFound(payload);
const _requestHasLocale = requestHasLocale(payload.locales);
const _redirectToFallback = redirectToFallback(payload);
const prefixAlways = (context, response) => {
const url = context.url;
if (url.pathname === base + "/" || url.pathname === base) {
return _redirectToDefaultLocale(context);
} else if (!_requestHasLocale(context)) {
return _noFoundForNonLocaleRoute(context, response);
}
return void 0;
};
const prefixOtherLocales = (context, response) => {
let pathnameContainsDefaultLocale = false;
const url = context.url;
for (const segment of url.pathname.split("/")) {
if (normalizeTheLocale(segment) === normalizeTheLocale(i18n.defaultLocale)) {
pathnameContainsDefaultLocale = true;
break;
}
}
if (pathnameContainsDefaultLocale) {
const newLocation = url.pathname.replace(`/${i18n.defaultLocale}`, "");
response.headers.set("Location", newLocation);
return _noFoundForNonLocaleRoute(context);
}
return void 0;
};
return async (context, next) => {
const response = await next();
const type = response.headers.get(ROUTE_TYPE_HEADER);
const isReroute = response.headers.get(REROUTE_DIRECTIVE_HEADER);
if (isReroute === "no" && typeof i18n.fallback === "undefined") {
return response;
}
if (type !== "page" && type !== "fallback") {
return response;
}
if (requestIs404Or500(context.request, base)) {
return response;
}
if (isRequestServerIsland(context.request, base)) {
return response;
}
const { currentLocale } = context;
switch (i18n.strategy) {
// NOTE: theoretically, we should never hit this code path
case "manual": {
return response;
}
case "domains-prefix-other-locales": {
if (localeHasntDomain(i18n, currentLocale)) {
const result = prefixOtherLocales(context, response);
if (result) {
return result;
}
}
break;
}
case "pathname-prefix-other-locales": {
const result = prefixOtherLocales(context, response);
if (result) {
return result;
}
break;
}
case "domains-prefix-always-no-redirect": {
if (localeHasntDomain(i18n, currentLocale)) {
const result = _noFoundForNonLocaleRoute(context, response);
if (result) {
return result;
}
}
break;
}
case "pathname-prefix-always-no-redirect": {
const result = _noFoundForNonLocaleRoute(context, response);
if (result) {
return result;
}
break;
}
case "pathname-prefix-always": {
const result = prefixAlways(context, response);
if (result) {
return result;
}
break;
}
case "domains-prefix-always": {
if (localeHasntDomain(i18n, currentLocale)) {
const result = prefixAlways(context, response);
if (result) {
return result;
}
}
break;
}
}
return _redirectToFallback(context, response);
};
}
function localeHasntDomain(i18n, currentLocale) {
for (const domainLocale of Object.values(i18n.domainLookupTable)) {
if (domainLocale === currentLocale) {
return false;
}
}
return true;
}
export {
createI18nMiddleware
};