0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2025-01-06 22:10:10 -05:00

fix(i18n): fallback index when routing is prefix-always (#9032)

* fix(i18n): fallback index when routing is prefix-always

* chore: add comment as per feedback
This commit is contained in:
Emanuele Stoppa 2023-11-09 14:32:57 +00:00 committed by GitHub
parent 4e63467d74
commit 4e9f171ef2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 107 additions and 70 deletions

View file

@ -161,7 +161,11 @@ export class BuildPipeline extends Pipeline {
for (const pageData of pageDataList) { for (const pageData of pageDataList) {
if (routeIsRedirect(pageData.route)) { if (routeIsRedirect(pageData.route)) {
pages.set(pageData, path); pages.set(pageData, path);
} else if (routeIsFallback(pageData.route) && i18nHasFallback(this.getConfig())) { } else if (
routeIsFallback(pageData.route) &&
(i18nHasFallback(this.getConfig()) ||
(routeIsFallback(pageData.route) && pageData.route.route === '/'))
) {
pages.set(pageData, path); pages.set(pageData, path);
} }
} }

View file

@ -485,13 +485,13 @@ export function createRouteManifest(
routes.push(routeData); routes.push(routeData);
}); });
const i18n = settings.config.experimental.i18n; const i18n = settings.config.experimental.i18n;
if (i18n) {
if (i18n && i18n.fallback) { // In this block of code we group routes based on their locale
let fallback = Object.entries(i18n.fallback);
// A map like: locale => RouteData[] // A map like: locale => RouteData[]
const routesByLocale = new Map<string, RouteData[]>(); const routesByLocale = new Map<string, RouteData[]>();
// We create a set, so we can remove the routes that have been added to the previous map // This type is here only as a helper. We copy the routes and make them unique, so we don't "process" the same route twice.
// The assumption is that a route in the file system belongs to only one locale.
const setRoutes = new Set(routes); const setRoutes = new Set(routes);
// First loop // First loop
@ -524,70 +524,110 @@ export function createRouteManifest(
setRoutes.delete(route); setRoutes.delete(route);
} }
if (fallback.length > 0) { // Work done, now we start creating "fallback" routes based on the configuration
for (const [fallbackFromLocale, fallbackToLocale] of fallback) {
let fallbackToRoutes;
if (fallbackToLocale === i18n.defaultLocale) {
fallbackToRoutes = routesByLocale.get(i18n.defaultLocale);
} else {
fallbackToRoutes = routesByLocale.get(fallbackToLocale);
}
const fallbackFromRoutes = routesByLocale.get(fallbackFromLocale);
// Technically, we should always have a fallback to. Added this to make TS happy. if (i18n.routingStrategy === 'prefix-always') {
if (!fallbackToRoutes) { // we attempt to retrieve the index page of the default locale
continue; const defaultLocaleRoutes = routesByLocale.get(i18n.defaultLocale);
} if (defaultLocaleRoutes) {
const indexDefaultRoute = defaultLocaleRoutes.find((routeData) => {
// it should be safe to assume that an index page has "index" in their name
return routeData.component.includes('index');
});
if (indexDefaultRoute) {
// we found the index of the default locale, now we create a root index that will redirect to the index of the default locale
const pathname = '/';
const route = '/';
for (const fallbackToRoute of fallbackToRoutes) { const segments = removeLeadingForwardSlash(route)
const hasRoute = .split(path.posix.sep)
fallbackFromRoutes && .filter(Boolean)
// we check if the fallback from locale (the origin) has already this route .map((s: string) => {
fallbackFromRoutes.some((route) => { validateSegment(s);
return getParts(s, route);
});
routes.push({
...indexDefaultRoute,
pathname,
route,
segments,
pattern: getPattern(segments, config),
type: 'fallback',
});
}
}
}
if (i18n.fallback) {
let fallback = Object.entries(i18n.fallback);
if (fallback.length > 0) {
for (const [fallbackFromLocale, fallbackToLocale] of fallback) {
let fallbackToRoutes;
if (fallbackToLocale === i18n.defaultLocale) {
fallbackToRoutes = routesByLocale.get(i18n.defaultLocale);
} else {
fallbackToRoutes = routesByLocale.get(fallbackToLocale);
}
const fallbackFromRoutes = routesByLocale.get(fallbackFromLocale);
// Technically, we should always have a fallback to. Added this to make TS happy.
if (!fallbackToRoutes) {
continue;
}
for (const fallbackToRoute of fallbackToRoutes) {
const hasRoute =
fallbackFromRoutes &&
// we check if the fallback from locale (the origin) has already this route
fallbackFromRoutes.some((route) => {
if (fallbackToLocale === i18n.defaultLocale) {
return (
route.route.replace(`/${fallbackFromLocale}`, '') === fallbackToRoute.route
);
} else {
return (
route.route.replace(`/${fallbackToLocale}`, `/${fallbackFromLocale}`) ===
fallbackToRoute.route
);
}
});
if (!hasRoute) {
let pathname: string | undefined;
let route: string;
if (fallbackToLocale === i18n.defaultLocale) { if (fallbackToLocale === i18n.defaultLocale) {
return route.route.replace(`/${fallbackFromLocale}`, '') === fallbackToRoute.route; if (fallbackToRoute.pathname) {
pathname = `/${fallbackFromLocale}${fallbackToRoute.pathname}`;
}
route = `/${fallbackFromLocale}${fallbackToRoute.route}`;
} else { } else {
return ( pathname = fallbackToRoute.pathname?.replace(
route.route.replace(`/${fallbackToLocale}`, `/${fallbackFromLocale}`) === `/${fallbackToLocale}`,
fallbackToRoute.route `/${fallbackFromLocale}`
);
route = fallbackToRoute.route.replace(
`/${fallbackToLocale}`,
`/${fallbackFromLocale}`
); );
} }
});
if (!hasRoute) { const segments = removeLeadingForwardSlash(route)
let pathname: string | undefined; .split(path.posix.sep)
let route: string; .filter(Boolean)
if (fallbackToLocale === i18n.defaultLocale) { .map((s: string) => {
if (fallbackToRoute.pathname) { validateSegment(s);
pathname = `/${fallbackFromLocale}${fallbackToRoute.pathname}`; return getParts(s, route);
} });
route = `/${fallbackFromLocale}${fallbackToRoute.route}`; routes.push({
} else { ...fallbackToRoute,
pathname = fallbackToRoute.pathname?.replace( pathname,
`/${fallbackToLocale}`, route,
`/${fallbackFromLocale}` segments,
); pattern: getPattern(segments, config),
route = fallbackToRoute.route.replace( type: 'fallback',
`/${fallbackToLocale}`,
`/${fallbackFromLocale}`
);
}
const segments = removeLeadingForwardSlash(route)
.split(path.posix.sep)
.filter(Boolean)
.map((s: string) => {
validateSegment(s);
return getParts(s, route);
}); });
routes.push({ }
...fallbackToRoute,
pathname,
route,
segments,
pattern: getPattern(segments, config),
type: 'fallback',
});
} }
} }
} }

View file

@ -187,7 +187,8 @@ export async function handleRoute({
.some((segment) => { .some((segment) => {
return locales.includes(segment); return locales.includes(segment);
}); });
if (!pathNameHasLocale) { // Even when we have `config.base`, the pathname is still `/` because it gets stripped before
if (!pathNameHasLocale && pathname !== '/') {
return handle404Response(origin, incomingRequest, incomingResponse); return handle404Response(origin, incomingRequest, incomingResponse);
} }
request = createRequest({ request = createRequest({

View file

@ -1,8 +0,0 @@
<html>
<head>
<title>Astro</title>
</head>
<body>
Hello
</body>
</html>