import { normalizeTheLocale, toCodes } from "../../i18n/index.js"; import { AstroError, AstroErrorData } from "../errors/index.js"; import { getParamsAndProps } from "./params-and-props.js"; const clientLocalsSymbol = Symbol.for("astro.locals"); async function createRenderContext(options) { const request = options.request; const pathname = options.pathname ?? new URL(request.url).pathname; const [params, props] = await getParamsAndProps({ mod: options.mod, route: options.route, routeCache: options.env.routeCache, pathname, logger: options.env.logger, ssr: options.env.ssr }); const context = { ...options, pathname, params, props, locales: options.locales, routing: options.routing, defaultLocale: options.defaultLocale }; Object.defineProperty(context, "locals", { enumerable: true, get() { return Reflect.get(request, clientLocalsSymbol); }, set(val) { if (typeof val !== "object") { throw new AstroError(AstroErrorData.LocalsNotAnObject); } else { Reflect.set(request, clientLocalsSymbol, val); } } }); return context; } function parseLocale(header) { if (header === "*") { return [{ locale: header, qualityValue: void 0 }]; } const result = []; const localeValues = header.split(",").map((str) => str.trim()); for (const localeValue of localeValues) { const split = localeValue.split(";").map((str) => str.trim()); const localeName = split[0]; const qualityValue = split[1]; if (!split) { continue; } if (qualityValue && qualityValue.startsWith("q=")) { const qualityValueAsFloat = Number.parseFloat(qualityValue.slice("q=".length)); if (Number.isNaN(qualityValueAsFloat) || qualityValueAsFloat > 1) { result.push({ locale: localeName, qualityValue: void 0 }); } else { result.push({ locale: localeName, qualityValue: qualityValueAsFloat }); } } else { result.push({ locale: localeName, qualityValue: void 0 }); } } return result; } function sortAndFilterLocales(browserLocaleList, locales) { const normalizedLocales = toCodes(locales).map(normalizeTheLocale); return browserLocaleList.filter((browserLocale) => { if (browserLocale.locale !== "*") { return normalizedLocales.includes(normalizeTheLocale(browserLocale.locale)); } return true; }).sort((a, b) => { if (a.qualityValue && b.qualityValue) { if (a.qualityValue > b.qualityValue) { return -1; } else if (a.qualityValue < b.qualityValue) { return 1; } } return 0; }); } function computePreferredLocale(request, locales) { const acceptHeader = request.headers.get("Accept-Language"); let result = void 0; if (acceptHeader) { const browserLocaleList = sortAndFilterLocales(parseLocale(acceptHeader), locales); const firstResult = browserLocaleList.at(0); if (firstResult && firstResult.locale !== "*") { for (const currentLocale of locales) { if (typeof currentLocale === "string") { if (normalizeTheLocale(currentLocale) === normalizeTheLocale(firstResult.locale)) { result = currentLocale; } } else { for (const currentCode of currentLocale.codes) { if (normalizeTheLocale(currentCode) === normalizeTheLocale(firstResult.locale)) { result = currentLocale.path; } } } } } } return result; } function computePreferredLocaleList(request, locales) { const acceptHeader = request.headers.get("Accept-Language"); let result = []; if (acceptHeader) { const browserLocaleList = sortAndFilterLocales(parseLocale(acceptHeader), locales); if (browserLocaleList.length === 1 && browserLocaleList.at(0).locale === "*") { return locales.map((locale) => { if (typeof locale === "string") { return locale; } else { return locale.codes.at(0); } }); } else if (browserLocaleList.length > 0) { for (const browserLocale of browserLocaleList) { for (const loopLocale of locales) { if (typeof loopLocale === "string") { if (normalizeTheLocale(loopLocale) === normalizeTheLocale(browserLocale.locale)) { result.push(loopLocale); } } else { for (const code of loopLocale.codes) { if (code === browserLocale.locale) { result.push(loopLocale.path); } } } } } } } return result; } function computeCurrentLocale(request, locales, routingStrategy, defaultLocale) { const requestUrl = new URL(request.url); for (const segment of requestUrl.pathname.split("/")) { for (const locale of locales) { if (typeof locale === "string") { if (normalizeTheLocale(locale) === normalizeTheLocale(segment)) { return locale; } } else { if (locale.path === segment) { return locale.codes.at(0); } } } } if (routingStrategy === "pathname-prefix-other-locales") { return defaultLocale; } return void 0; } export { computeCurrentLocale, computePreferredLocale, computePreferredLocaleList, createRenderContext, parseLocale };