UNPKG

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
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 };