Initial commit: New MoreminiMore website with fresh design
This commit is contained in:
46
node_modules/astro/dist/i18n/fallback.d.ts
generated
vendored
Normal file
46
node_modules/astro/dist/i18n/fallback.d.ts
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
import type { SSRManifest, SSRManifestI18n } from '../core/app/types.js';
|
||||
import type { APIContext } from '../types/public/context.js';
|
||||
/**
|
||||
* Fallback routing decision types
|
||||
*/
|
||||
export type FallbackRouteResult = {
|
||||
type: 'none';
|
||||
} | {
|
||||
type: 'redirect';
|
||||
pathname: string;
|
||||
} | {
|
||||
type: 'rewrite';
|
||||
pathname: string;
|
||||
};
|
||||
/**
|
||||
* Options for computing fallback routes.
|
||||
* Uses types from APIContext and SSRManifest to ensure type safety.
|
||||
*/
|
||||
export interface ComputeFallbackRouteOptions {
|
||||
/** Pathname from url.pathname */
|
||||
pathname: APIContext['url']['pathname'];
|
||||
/** Response status code */
|
||||
responseStatus: number;
|
||||
/** Current locale from APIContext */
|
||||
currentLocale: APIContext['currentLocale'];
|
||||
/** Fallback configuration from i18n manifest */
|
||||
fallback: NonNullable<SSRManifestI18n['fallback']>;
|
||||
/** Fallback type from i18n manifest */
|
||||
fallbackType: SSRManifestI18n['fallbackType'];
|
||||
/** Locales from i18n manifest */
|
||||
locales: SSRManifestI18n['locales'];
|
||||
/** Default locale from i18n manifest */
|
||||
defaultLocale: SSRManifestI18n['defaultLocale'];
|
||||
/** Routing strategy from i18n manifest */
|
||||
strategy: SSRManifestI18n['strategy'];
|
||||
/** Base path from manifest */
|
||||
base: SSRManifest['base'];
|
||||
}
|
||||
/**
|
||||
* Compute fallback route for failed responses.
|
||||
* Pure function - no APIContext, no Response objects, no URL objects.
|
||||
*
|
||||
* This function determines whether a failed request should be redirected or rewritten
|
||||
* to a fallback locale based on the i18n configuration.
|
||||
*/
|
||||
export declare function computeFallbackRoute(options: ComputeFallbackRouteOptions): FallbackRouteResult;
|
||||
58
node_modules/astro/dist/i18n/fallback.js
generated
vendored
Normal file
58
node_modules/astro/dist/i18n/fallback.js
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
import { getPathByLocale } from "./index.js";
|
||||
function computeFallbackRoute(options) {
|
||||
const {
|
||||
pathname,
|
||||
responseStatus,
|
||||
fallback,
|
||||
fallbackType,
|
||||
locales,
|
||||
defaultLocale,
|
||||
strategy,
|
||||
base
|
||||
} = options;
|
||||
if (responseStatus !== 404) {
|
||||
return { type: "none" };
|
||||
}
|
||||
if (!fallback || Object.keys(fallback).length === 0) {
|
||||
return { type: "none" };
|
||||
}
|
||||
const segments = 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) {
|
||||
return { type: "none" };
|
||||
}
|
||||
const fallbackKeys = Object.keys(fallback);
|
||||
if (!fallbackKeys.includes(urlLocale)) {
|
||||
return { type: "none" };
|
||||
}
|
||||
const fallbackLocale = fallback[urlLocale];
|
||||
const pathFallbackLocale = getPathByLocale(fallbackLocale, locales);
|
||||
let newPathname;
|
||||
if (pathFallbackLocale === defaultLocale && strategy === "pathname-prefix-other-locales") {
|
||||
if (pathname.includes(`${base}`)) {
|
||||
newPathname = pathname.replace(`/${urlLocale}`, ``);
|
||||
} else {
|
||||
newPathname = pathname.replace(`/${urlLocale}`, `/`);
|
||||
}
|
||||
} else {
|
||||
newPathname = pathname.replace(`/${urlLocale}`, `/${pathFallbackLocale}`);
|
||||
}
|
||||
return {
|
||||
type: fallbackType,
|
||||
pathname: newPathname
|
||||
};
|
||||
}
|
||||
export {
|
||||
computeFallbackRoute
|
||||
};
|
||||
110
node_modules/astro/dist/i18n/index.d.ts
generated
vendored
Normal file
110
node_modules/astro/dist/i18n/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
import type { RoutingStrategies } from '../core/app/common.js';
|
||||
import type { SSRManifest } from '../core/app/types.js';
|
||||
import type { AstroConfig, Locales, ValidRedirectStatus } from '../types/public/config.js';
|
||||
import type { APIContext } from '../types/public/context.js';
|
||||
export declare function requestHasLocale(locales: Locales): (context: APIContext) => boolean;
|
||||
export declare function pathHasLocale(path: string, locales: Locales): boolean;
|
||||
type GetLocaleRelativeUrl = GetLocaleOptions & {
|
||||
locale: string;
|
||||
base: string;
|
||||
locales: Locales;
|
||||
trailingSlash: AstroConfig['trailingSlash'];
|
||||
format: NonNullable<AstroConfig['build']['format']>;
|
||||
strategy?: RoutingStrategies;
|
||||
defaultLocale: string;
|
||||
domains: Record<string, string> | undefined;
|
||||
path?: string;
|
||||
};
|
||||
export type GetLocaleOptions = {
|
||||
/**
|
||||
* Makes the locale URL-friendly by replacing underscores with dashes, and converting the locale to lowercase.
|
||||
* @default true
|
||||
*/
|
||||
normalizeLocale?: boolean;
|
||||
/**
|
||||
* An optional path to prepend to `locale`.
|
||||
*/
|
||||
prependWith?: string;
|
||||
};
|
||||
type GetLocaleAbsoluteUrl = GetLocaleRelativeUrl & {
|
||||
site: AstroConfig['site'];
|
||||
isBuild: boolean;
|
||||
};
|
||||
/**
|
||||
* The base URL
|
||||
*/
|
||||
export declare function getLocaleRelativeUrl({ locale, base, locales: _locales, trailingSlash, format, path, prependWith, normalizeLocale, strategy, defaultLocale, }: GetLocaleRelativeUrl): string;
|
||||
/**
|
||||
* The absolute URL
|
||||
*/
|
||||
export declare function getLocaleAbsoluteUrl({ site, isBuild, ...rest }: GetLocaleAbsoluteUrl): string;
|
||||
interface GetLocalesRelativeUrlList extends GetLocaleOptions {
|
||||
base: string;
|
||||
path?: string;
|
||||
locales: Locales;
|
||||
trailingSlash: AstroConfig['trailingSlash'];
|
||||
format: AstroConfig['build']['format'];
|
||||
strategy?: RoutingStrategies;
|
||||
defaultLocale: string;
|
||||
domains: Record<string, string> | undefined;
|
||||
}
|
||||
export declare function getLocaleRelativeUrlList({ locales: _locales, ...rest }: GetLocalesRelativeUrlList): string[];
|
||||
interface GetLocalesAbsoluteUrlList extends GetLocalesRelativeUrlList {
|
||||
site: AstroConfig['site'];
|
||||
isBuild: boolean;
|
||||
}
|
||||
export declare function getLocaleAbsoluteUrlList(params: GetLocalesAbsoluteUrlList): string[];
|
||||
/**
|
||||
* Given a locale (code), it returns its corresponding path
|
||||
* @param locale
|
||||
* @param locales
|
||||
*/
|
||||
export declare function getPathByLocale(locale: string, locales: Locales): string;
|
||||
/**
|
||||
* A utility function that retrieves the preferred locale that correspond to a path.
|
||||
*
|
||||
* @param path
|
||||
* @param locales
|
||||
*/
|
||||
export declare function getLocaleByPath(path: string, locales: Locales): string;
|
||||
/**
|
||||
*
|
||||
* Given a locale, this function:
|
||||
* - replaces the `_` with a `-`;
|
||||
* - transforms all letters to be lowercase;
|
||||
*/
|
||||
export declare function normalizeTheLocale(locale: string): string;
|
||||
/**
|
||||
*
|
||||
* Given a path or path segment, this function:
|
||||
* - removes the `.html` extension if it exists
|
||||
*/
|
||||
export declare function normalizeThePath(path: string): string;
|
||||
/**
|
||||
* Returns an array of only locales, by picking the `code`
|
||||
* @param locales
|
||||
*/
|
||||
export declare function getAllCodes(locales: Locales): string[];
|
||||
export declare function toCodes(locales: Locales): string[];
|
||||
/**
|
||||
* It returns the array of paths
|
||||
* @param locales
|
||||
*/
|
||||
export declare function toPaths(locales: Locales): string[];
|
||||
export type MiddlewarePayload = {
|
||||
base: string;
|
||||
locales: Locales;
|
||||
trailingSlash: AstroConfig['trailingSlash'];
|
||||
format: AstroConfig['build']['format'];
|
||||
strategy: RoutingStrategies;
|
||||
defaultLocale: string;
|
||||
domains: Record<string, string> | undefined;
|
||||
fallback: Record<string, string> | undefined;
|
||||
fallbackType: 'redirect' | 'rewrite';
|
||||
};
|
||||
export declare function redirectToDefaultLocale({ trailingSlash, format, base, defaultLocale, }: MiddlewarePayload): (context: APIContext, statusCode?: ValidRedirectStatus) => Response;
|
||||
export declare function notFound({ base, locales, fallback }: MiddlewarePayload): (context: APIContext, response?: Response) => Response | undefined;
|
||||
export type RedirectToFallback = (context: APIContext, response: Response) => Promise<Response>;
|
||||
export declare function redirectToFallback({ fallback, locales, defaultLocale, strategy, base, fallbackType, }: MiddlewarePayload): (context: APIContext, response: Response) => Promise<Response>;
|
||||
export declare function createMiddleware(i18nManifest: SSRManifest['i18n'], base: SSRManifest['base'], trailingSlash: SSRManifest['trailingSlash'], format: SSRManifest['buildFormat']): import("../index.js").MiddlewareHandler;
|
||||
export {};
|
||||
291
node_modules/astro/dist/i18n/index.js
generated
vendored
Normal file
291
node_modules/astro/dist/i18n/index.js
generated
vendored
Normal file
@@ -0,0 +1,291 @@
|
||||
import { appendForwardSlash, joinPaths } from "@astrojs/internal-helpers/path";
|
||||
import { shouldAppendForwardSlash } from "../core/build/util.js";
|
||||
import { REROUTE_DIRECTIVE_HEADER } from "../core/constants.js";
|
||||
import { i18nNoLocaleFoundInPath, MissingLocale } 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 pathHasLocale(path, locales) {
|
||||
const segments = path.split("/").map(normalizeThePath);
|
||||
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);
|
||||
let relativePath;
|
||||
if (shouldAppendForwardSlash(trailingSlash, format)) {
|
||||
relativePath = appendForwardSlash(joinPaths(...pathsToJoin));
|
||||
} else {
|
||||
relativePath = joinPaths(...pathsToJoin);
|
||||
}
|
||||
if (relativePath === "") {
|
||||
return "/";
|
||||
}
|
||||
return relativePath;
|
||||
}
|
||||
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 (localeUrl === "/") {
|
||||
url = site || "/";
|
||||
} 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 normalizeThePath(path) {
|
||||
return path.endsWith(".html") ? path.slice(0, -5) : path;
|
||||
}
|
||||
function getAllCodes(locales) {
|
||||
const result = [];
|
||||
for (const loopLocale of locales) {
|
||||
if (typeof loopLocale === "string") {
|
||||
result.push(loopLocale);
|
||||
} else {
|
||||
result.push(...loopLocale.codes);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
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, fallback }) {
|
||||
return function(context, response) {
|
||||
if (response?.headers.get(REROUTE_DIRECTIVE_HEADER) === "no" && typeof fallback === "undefined") {
|
||||
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 === 404 && 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 + context.url.search);
|
||||
} else {
|
||||
return context.redirect(newPathname + context.url.search);
|
||||
}
|
||||
}
|
||||
}
|
||||
return response;
|
||||
};
|
||||
}
|
||||
function createMiddleware(i18nManifest, base, trailingSlash, format) {
|
||||
return createI18nMiddleware(i18nManifest, base, trailingSlash, format);
|
||||
}
|
||||
export {
|
||||
createMiddleware,
|
||||
getAllCodes,
|
||||
getLocaleAbsoluteUrl,
|
||||
getLocaleAbsoluteUrlList,
|
||||
getLocaleByPath,
|
||||
getLocaleRelativeUrl,
|
||||
getLocaleRelativeUrlList,
|
||||
getPathByLocale,
|
||||
normalizeTheLocale,
|
||||
normalizeThePath,
|
||||
notFound,
|
||||
pathHasLocale,
|
||||
redirectToDefaultLocale,
|
||||
redirectToFallback,
|
||||
requestHasLocale,
|
||||
toCodes,
|
||||
toPaths
|
||||
};
|
||||
3
node_modules/astro/dist/i18n/middleware.d.ts
generated
vendored
Normal file
3
node_modules/astro/dist/i18n/middleware.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
import type { SSRManifest } from '../core/app/types.js';
|
||||
import type { MiddlewareHandler } from '../types/public/common.js';
|
||||
export declare function createI18nMiddleware(i18n: SSRManifest['i18n'], base: SSRManifest['base'], trailingSlash: SSRManifest['trailingSlash'], format: SSRManifest['buildFormat']): MiddlewareHandler;
|
||||
97
node_modules/astro/dist/i18n/middleware.js
generated
vendored
Normal file
97
node_modules/astro/dist/i18n/middleware.js
generated
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
import { appendForwardSlash } from "@astrojs/internal-helpers/path";
|
||||
import { shouldAppendForwardSlash } from "../core/build/util.js";
|
||||
import { REROUTE_DIRECTIVE_HEADER, ROUTE_TYPE_HEADER } from "../core/constants.js";
|
||||
import { computeFallbackRoute } from "./fallback.js";
|
||||
import { I18nRouter } from "./router.js";
|
||||
function createI18nMiddleware(i18n, base, trailingSlash, format) {
|
||||
if (!i18n) return (_, next) => next();
|
||||
const i18nRouter = new I18nRouter({
|
||||
strategy: i18n.strategy,
|
||||
defaultLocale: i18n.defaultLocale,
|
||||
locales: i18n.locales,
|
||||
base,
|
||||
domains: i18n.domainLookupTable ? Object.keys(i18n.domainLookupTable).reduce(
|
||||
(acc, domain) => {
|
||||
const locale = i18n.domainLookupTable[domain];
|
||||
if (!acc[domain]) {
|
||||
acc[domain] = [];
|
||||
}
|
||||
acc[domain].push(locale);
|
||||
return acc;
|
||||
},
|
||||
{}
|
||||
) : void 0
|
||||
});
|
||||
return async (context, next) => {
|
||||
const response = await next();
|
||||
const typeHeader = response.headers.get(ROUTE_TYPE_HEADER);
|
||||
const isReroute = response.headers.get(REROUTE_DIRECTIVE_HEADER);
|
||||
if (isReroute === "no" && typeof i18n.fallback === "undefined") {
|
||||
return response;
|
||||
}
|
||||
if (typeHeader !== "page" && typeHeader !== "fallback") {
|
||||
return response;
|
||||
}
|
||||
const routerContext = {
|
||||
currentLocale: context.currentLocale,
|
||||
currentDomain: context.url.hostname,
|
||||
routeType: typeHeader,
|
||||
isReroute: isReroute === "yes"
|
||||
};
|
||||
const routeDecision = i18nRouter.match(context.url.pathname, routerContext);
|
||||
switch (routeDecision.type) {
|
||||
case "redirect": {
|
||||
let location = routeDecision.location;
|
||||
if (shouldAppendForwardSlash(trailingSlash, format)) {
|
||||
location = appendForwardSlash(location);
|
||||
}
|
||||
return context.redirect(location, routeDecision.status);
|
||||
}
|
||||
case "notFound": {
|
||||
if (context.isPrerendered) {
|
||||
const prerenderedRes = new Response(response.body, {
|
||||
status: 404,
|
||||
headers: response.headers
|
||||
});
|
||||
prerenderedRes.headers.set(REROUTE_DIRECTIVE_HEADER, "no");
|
||||
if (routeDecision.location) {
|
||||
prerenderedRes.headers.set("Location", routeDecision.location);
|
||||
}
|
||||
return prerenderedRes;
|
||||
}
|
||||
const headers = new Headers();
|
||||
if (routeDecision.location) {
|
||||
headers.set("Location", routeDecision.location);
|
||||
}
|
||||
return new Response(null, { status: 404, headers });
|
||||
}
|
||||
case "continue":
|
||||
break;
|
||||
}
|
||||
if (i18n.fallback && i18n.fallbackType) {
|
||||
const fallbackDecision = computeFallbackRoute({
|
||||
pathname: context.url.pathname,
|
||||
responseStatus: response.status,
|
||||
currentLocale: context.currentLocale,
|
||||
fallback: i18n.fallback,
|
||||
fallbackType: i18n.fallbackType,
|
||||
locales: i18n.locales,
|
||||
defaultLocale: i18n.defaultLocale,
|
||||
strategy: i18n.strategy,
|
||||
base
|
||||
});
|
||||
switch (fallbackDecision.type) {
|
||||
case "redirect":
|
||||
return context.redirect(fallbackDecision.pathname + context.url.search);
|
||||
case "rewrite":
|
||||
return await context.rewrite(fallbackDecision.pathname + context.url.search);
|
||||
case "none":
|
||||
break;
|
||||
}
|
||||
}
|
||||
return response;
|
||||
};
|
||||
}
|
||||
export {
|
||||
createI18nMiddleware
|
||||
};
|
||||
86
node_modules/astro/dist/i18n/router.d.ts
generated
vendored
Normal file
86
node_modules/astro/dist/i18n/router.d.ts
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
import type { SSRManifest, SSRManifestI18n } from '../core/app/types.js';
|
||||
import type { ValidRedirectStatus } from '../types/public/config.js';
|
||||
import type { APIContext } from '../types/public/context.js';
|
||||
/**
|
||||
* I18n routing decision types
|
||||
*/
|
||||
export type I18nRouterMatch = {
|
||||
type: 'continue';
|
||||
} | {
|
||||
type: 'redirect';
|
||||
location: string;
|
||||
status?: ValidRedirectStatus;
|
||||
} | {
|
||||
type: 'notFound';
|
||||
location?: string;
|
||||
};
|
||||
/**
|
||||
* Options for i18n router.
|
||||
* Uses types from SSRManifest to ensure type safety.
|
||||
*/
|
||||
export interface I18nRouterOptions {
|
||||
/** Routing strategy from i18n manifest */
|
||||
strategy: SSRManifestI18n['strategy'];
|
||||
/** Default locale from i18n manifest */
|
||||
defaultLocale: SSRManifestI18n['defaultLocale'];
|
||||
/** Locales from i18n manifest */
|
||||
locales: SSRManifestI18n['locales'];
|
||||
/** Base path from manifest */
|
||||
base: SSRManifest['base'];
|
||||
/** Domain mapping (domain -> locale[]) */
|
||||
domains?: Record<string, string[]>;
|
||||
}
|
||||
/**
|
||||
* Context for i18n router decisions.
|
||||
* Uses types from APIContext to ensure type safety.
|
||||
*/
|
||||
export interface I18nRouterContext {
|
||||
/** Current locale from APIContext */
|
||||
currentLocale: APIContext['currentLocale'];
|
||||
/** Current domain from url.hostname */
|
||||
currentDomain: APIContext['url']['hostname'];
|
||||
/** Route type from response headers */
|
||||
routeType?: 'page' | 'fallback';
|
||||
/** Whether this is a reroute from response headers */
|
||||
isReroute: boolean;
|
||||
}
|
||||
/**
|
||||
* Router for i18n routing strategy decisions.
|
||||
* Determines whether to continue, redirect, or return 404 based on pathname and locale.
|
||||
*
|
||||
* This is a pure class that returns decision objects (not HTTP Responses).
|
||||
* The middleware layer is responsible for converting decisions to HTTP responses.
|
||||
*/
|
||||
export declare class I18nRouter {
|
||||
#private;
|
||||
constructor(options: I18nRouterOptions);
|
||||
/**
|
||||
* Evaluate routing strategy for a pathname.
|
||||
* Returns decision object (not HTTP Response).
|
||||
*/
|
||||
match(pathname: string, context: I18nRouterContext): I18nRouterMatch;
|
||||
/**
|
||||
* Check if i18n processing should be skipped for this request
|
||||
*/
|
||||
private shouldSkipProcessing;
|
||||
/**
|
||||
* Strategy: pathname-prefix-always
|
||||
* All locales must have a prefix, including the default locale.
|
||||
*/
|
||||
private matchPrefixAlways;
|
||||
/**
|
||||
* Strategy: pathname-prefix-other-locales
|
||||
* Default locale has no prefix, other locales must have a prefix.
|
||||
*/
|
||||
private matchPrefixOtherLocales;
|
||||
/**
|
||||
* Strategy: pathname-prefix-always-no-redirect
|
||||
* Like prefix-always but allows root to serve instead of redirecting
|
||||
*/
|
||||
private matchPrefixAlwaysNoRedirect;
|
||||
/**
|
||||
* Check if the current locale doesn't belong to the configured domain.
|
||||
* Used for domain-based routing strategies.
|
||||
*/
|
||||
private localeHasntDomain;
|
||||
}
|
||||
143
node_modules/astro/dist/i18n/router.js
generated
vendored
Normal file
143
node_modules/astro/dist/i18n/router.js
generated
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
import { removeTrailingForwardSlash } from "@astrojs/internal-helpers/path";
|
||||
import { normalizeTheLocale, pathHasLocale } from "./index.js";
|
||||
class I18nRouter {
|
||||
#strategy;
|
||||
#defaultLocale;
|
||||
#locales;
|
||||
#base;
|
||||
#domains;
|
||||
constructor(options) {
|
||||
this.#strategy = options.strategy;
|
||||
this.#defaultLocale = options.defaultLocale;
|
||||
this.#locales = options.locales;
|
||||
this.#base = options.base === "/" ? "/" : removeTrailingForwardSlash(options.base || "");
|
||||
this.#domains = options.domains;
|
||||
}
|
||||
/**
|
||||
* Evaluate routing strategy for a pathname.
|
||||
* Returns decision object (not HTTP Response).
|
||||
*/
|
||||
match(pathname, context) {
|
||||
if (this.shouldSkipProcessing(pathname, context)) {
|
||||
return { type: "continue" };
|
||||
}
|
||||
switch (this.#strategy) {
|
||||
case "manual":
|
||||
return { type: "continue" };
|
||||
case "pathname-prefix-always":
|
||||
return this.matchPrefixAlways(pathname, context);
|
||||
case "domains-prefix-always":
|
||||
if (this.localeHasntDomain(context.currentLocale, context.currentDomain)) {
|
||||
return { type: "continue" };
|
||||
}
|
||||
return this.matchPrefixAlways(pathname, context);
|
||||
case "pathname-prefix-other-locales":
|
||||
return this.matchPrefixOtherLocales(pathname, context);
|
||||
case "domains-prefix-other-locales":
|
||||
if (this.localeHasntDomain(context.currentLocale, context.currentDomain)) {
|
||||
return { type: "continue" };
|
||||
}
|
||||
return this.matchPrefixOtherLocales(pathname, context);
|
||||
case "pathname-prefix-always-no-redirect":
|
||||
return this.matchPrefixAlwaysNoRedirect(pathname, context);
|
||||
case "domains-prefix-always-no-redirect":
|
||||
if (this.localeHasntDomain(context.currentLocale, context.currentDomain)) {
|
||||
return { type: "continue" };
|
||||
}
|
||||
return this.matchPrefixAlwaysNoRedirect(pathname, context);
|
||||
default:
|
||||
return { type: "continue" };
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Check if i18n processing should be skipped for this request
|
||||
*/
|
||||
shouldSkipProcessing(pathname, context) {
|
||||
if (pathname.includes("/404") || pathname.includes("/500")) {
|
||||
return true;
|
||||
}
|
||||
if (pathname.includes("/_server-islands/")) {
|
||||
return true;
|
||||
}
|
||||
if (context.isReroute) {
|
||||
return true;
|
||||
}
|
||||
if (context.routeType && context.routeType !== "page" && context.routeType !== "fallback") {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Strategy: pathname-prefix-always
|
||||
* All locales must have a prefix, including the default locale.
|
||||
*/
|
||||
matchPrefixAlways(pathname, _context) {
|
||||
const isRoot = pathname === this.#base + "/" || pathname === this.#base;
|
||||
if (isRoot) {
|
||||
const basePrefix = this.#base === "/" ? "" : this.#base;
|
||||
return {
|
||||
type: "redirect",
|
||||
location: `${basePrefix}/${this.#defaultLocale}`
|
||||
};
|
||||
}
|
||||
if (!pathHasLocale(pathname, this.#locales)) {
|
||||
return { type: "notFound" };
|
||||
}
|
||||
return { type: "continue" };
|
||||
}
|
||||
/**
|
||||
* Strategy: pathname-prefix-other-locales
|
||||
* Default locale has no prefix, other locales must have a prefix.
|
||||
*/
|
||||
matchPrefixOtherLocales(pathname, _context) {
|
||||
let pathnameContainsDefaultLocale = false;
|
||||
for (const segment of pathname.split("/")) {
|
||||
if (normalizeTheLocale(segment) === normalizeTheLocale(this.#defaultLocale)) {
|
||||
pathnameContainsDefaultLocale = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pathnameContainsDefaultLocale) {
|
||||
const newLocation = pathname.replace(`/${this.#defaultLocale}`, "");
|
||||
return {
|
||||
type: "notFound",
|
||||
location: newLocation
|
||||
};
|
||||
}
|
||||
return { type: "continue" };
|
||||
}
|
||||
/**
|
||||
* Strategy: pathname-prefix-always-no-redirect
|
||||
* Like prefix-always but allows root to serve instead of redirecting
|
||||
*/
|
||||
matchPrefixAlwaysNoRedirect(pathname, _context) {
|
||||
const isRoot = pathname === this.#base + "/" || pathname === this.#base;
|
||||
if (isRoot) {
|
||||
return { type: "continue" };
|
||||
}
|
||||
if (!pathHasLocale(pathname, this.#locales)) {
|
||||
return { type: "notFound" };
|
||||
}
|
||||
return { type: "continue" };
|
||||
}
|
||||
/**
|
||||
* Check if the current locale doesn't belong to the configured domain.
|
||||
* Used for domain-based routing strategies.
|
||||
*/
|
||||
localeHasntDomain(currentLocale, currentDomain) {
|
||||
if (!this.#domains || !currentDomain) {
|
||||
return false;
|
||||
}
|
||||
if (!currentLocale) {
|
||||
return false;
|
||||
}
|
||||
const localesForDomain = this.#domains[currentDomain];
|
||||
if (!localesForDomain) {
|
||||
return true;
|
||||
}
|
||||
return !localesForDomain.includes(currentLocale);
|
||||
}
|
||||
}
|
||||
export {
|
||||
I18nRouter
|
||||
};
|
||||
30
node_modules/astro/dist/i18n/utils.d.ts
generated
vendored
Normal file
30
node_modules/astro/dist/i18n/utils.d.ts
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
import type { Locales } from '../types/public/config.js';
|
||||
type BrowserLocale = {
|
||||
locale: string;
|
||||
qualityValue: number | undefined;
|
||||
};
|
||||
/**
|
||||
* Parses the value of the `Accept-Language` header:
|
||||
*
|
||||
* More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language
|
||||
*
|
||||
* Complex example: `fr-CH, fr;q=0.9, en;q=0.8, de;q=0.7, *;q=0.5`
|
||||
*
|
||||
*/
|
||||
export declare function parseLocale(header: string): BrowserLocale[];
|
||||
/**
|
||||
* Set the current locale by parsing the value passed from the `Accept-Header`.
|
||||
*
|
||||
* If multiple locales are present in the header, they are sorted by their quality value and the highest is selected as current locale.
|
||||
*
|
||||
*/
|
||||
export declare function computePreferredLocale(request: Request, locales: Locales): string | undefined;
|
||||
export declare function computePreferredLocaleList(request: Request, locales: Locales): string[];
|
||||
export declare function computeCurrentLocale(pathname: string, locales: Locales, defaultLocale: string): string | undefined;
|
||||
/**
|
||||
* Check if any of the route's resolved param values match a configured locale.
|
||||
* This handles dynamic routes like `[locale]` or `[...path]` where the locale
|
||||
* isn't in a static segment of the route pathname.
|
||||
*/
|
||||
export declare function computeCurrentLocaleFromParams(params: Record<string, string | undefined>, locales: Locales): string | undefined;
|
||||
export {};
|
||||
164
node_modules/astro/dist/i18n/utils.js
generated
vendored
Normal file
164
node_modules/astro/dist/i18n/utils.js
generated
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
import { getAllCodes, normalizeTheLocale, normalizeThePath } from "./index.js";
|
||||
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 = getAllCodes(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) {
|
||||
return Math.sign(b.qualityValue - a.qualityValue);
|
||||
}
|
||||
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;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
for (const currentCode of currentLocale.codes) {
|
||||
if (normalizeTheLocale(currentCode) === normalizeTheLocale(firstResult.locale)) {
|
||||
result = currentCode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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 getAllCodes(locales);
|
||||
} 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(code);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function computeCurrentLocale(pathname, locales, defaultLocale) {
|
||||
for (const segment of pathname.split("/").map(normalizeThePath)) {
|
||||
for (const locale of locales) {
|
||||
if (typeof locale === "string") {
|
||||
if (!segment.includes(locale)) continue;
|
||||
if (normalizeTheLocale(locale) === normalizeTheLocale(segment)) {
|
||||
return locale;
|
||||
}
|
||||
} else {
|
||||
if (locale.path === segment) {
|
||||
return locale.codes.at(0);
|
||||
} else {
|
||||
for (const code of locale.codes) {
|
||||
if (normalizeTheLocale(code) === normalizeTheLocale(segment)) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const locale of locales) {
|
||||
if (typeof locale === "string") {
|
||||
if (locale === defaultLocale) {
|
||||
return locale;
|
||||
}
|
||||
} else {
|
||||
if (locale.path === defaultLocale) {
|
||||
return locale.codes.at(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function computeCurrentLocaleFromParams(params, locales) {
|
||||
const byNormalizedCode = /* @__PURE__ */ new Map();
|
||||
const byPath = /* @__PURE__ */ new Map();
|
||||
for (const locale of locales) {
|
||||
if (typeof locale === "string") {
|
||||
byNormalizedCode.set(normalizeTheLocale(locale), locale);
|
||||
} else {
|
||||
byPath.set(locale.path, locale.codes[0]);
|
||||
for (const code of locale.codes) {
|
||||
byNormalizedCode.set(normalizeTheLocale(code), code);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const value of Object.values(params)) {
|
||||
if (!value) continue;
|
||||
const pathMatch = byPath.get(value);
|
||||
if (pathMatch) return pathMatch;
|
||||
const codeMatch = byNormalizedCode.get(normalizeTheLocale(value));
|
||||
if (codeMatch) return codeMatch;
|
||||
}
|
||||
}
|
||||
export {
|
||||
computeCurrentLocale,
|
||||
computeCurrentLocaleFromParams,
|
||||
computePreferredLocale,
|
||||
computePreferredLocaleList,
|
||||
parseLocale
|
||||
};
|
||||
7
node_modules/astro/dist/i18n/vite-plugin-i18n.d.ts
generated
vendored
Normal file
7
node_modules/astro/dist/i18n/vite-plugin-i18n.d.ts
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
import type * as vite from 'vite';
|
||||
import type { AstroSettings } from '../types/astro.js';
|
||||
type AstroInternationalization = {
|
||||
settings: AstroSettings;
|
||||
};
|
||||
export default function astroInternationalization({ settings, }: AstroInternationalization): vite.Plugin;
|
||||
export {};
|
||||
24
node_modules/astro/dist/i18n/vite-plugin-i18n.js
generated
vendored
Normal file
24
node_modules/astro/dist/i18n/vite-plugin-i18n.js
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
import { AstroError } from "../core/errors/errors.js";
|
||||
import { AstroErrorData } from "../core/errors/index.js";
|
||||
const VIRTUAL_MODULE_ID = "astro:i18n";
|
||||
function astroInternationalization({
|
||||
settings
|
||||
}) {
|
||||
const { i18n } = settings.config;
|
||||
return {
|
||||
name: VIRTUAL_MODULE_ID,
|
||||
enforce: "pre",
|
||||
resolveId: {
|
||||
filter: {
|
||||
id: new RegExp(`^${VIRTUAL_MODULE_ID}$`)
|
||||
},
|
||||
handler() {
|
||||
if (i18n === void 0) throw new AstroError(AstroErrorData.i18nNotEnabled);
|
||||
return this.resolve("astro/virtual-modules/i18n.js");
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
export {
|
||||
astroInternationalization as default
|
||||
};
|
||||
Reference in New Issue
Block a user