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

fix(i18n): render 404.astro when i18n is enabled (#12525)

Co-authored-by: Chris Swithinbank <swithinbank@gmail.com>


Co-authored-by: delucis <357379+delucis@users.noreply.github.com>
Co-authored-by: bluwy <34116392+bluwy@users.noreply.github.com>
This commit is contained in:
Emanuele Stoppa 2024-11-26 15:21:06 +00:00 committed by GitHub
parent 8b0e36ca91
commit cf0d8b08a0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 28 additions and 25 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Fixes an issue where with `i18n` enabled, Astro couldn't render the `404.astro` component for non-existent routes.

View file

@ -1,6 +1,6 @@
import type { APIContext, MiddlewareHandler, SSRManifest } from '../@types/astro.js'; import type { APIContext, MiddlewareHandler, SSRManifest } from '../@types/astro.js';
import type { SSRManifestI18n } from '../core/app/types.js'; import type { SSRManifestI18n } from '../core/app/types.js';
import { ROUTE_TYPE_HEADER } from '../core/constants.js'; import { REROUTE_DIRECTIVE_HEADER, ROUTE_TYPE_HEADER } from '../core/constants.js';
import { import {
type MiddlewarePayload, type MiddlewarePayload,
normalizeTheLocale, normalizeTheLocale,
@ -65,6 +65,12 @@ export function createI18nMiddleware(
return async (context, next) => { return async (context, next) => {
const response = await next(); const response = await next();
const type = response.headers.get(ROUTE_TYPE_HEADER); const type = response.headers.get(ROUTE_TYPE_HEADER);
// This is case where we are internally rendering a 404/500, so we need to bypass checks that were done already
const isReroute = response.headers.get(REROUTE_DIRECTIVE_HEADER);
if (isReroute === 'no' && typeof i18n.fallback === 'undefined') {
return response;
}
// If the route we're processing is not a page, then we ignore it // If the route we're processing is not a page, then we ignore it
if (type !== 'page' && type !== 'fallback') { if (type !== 'page' && type !== 'fallback') {
return response; return response;

View file

@ -63,7 +63,6 @@ export async function handleRequest({
url, url,
pathname: resolvedPathname, pathname: resolvedPathname,
body, body,
origin,
pipeline, pipeline,
manifestData, manifestData,
incomingRequest: incomingRequest, incomingRequest: incomingRequest,

View file

@ -127,7 +127,6 @@ type HandleRoute = {
url: URL; url: URL;
pathname: string; pathname: string;
body: ArrayBuffer | undefined; body: ArrayBuffer | undefined;
origin: string;
manifestData: ManifestData; manifestData: ManifestData;
incomingRequest: http.IncomingMessage; incomingRequest: http.IncomingMessage;
incomingResponse: http.ServerResponse; incomingResponse: http.ServerResponse;
@ -139,7 +138,6 @@ export async function handleRoute({
url, url,
pathname, pathname,
body, body,
origin,
pipeline, pipeline,
manifestData, manifestData,
incomingRequest, incomingRequest,
@ -156,12 +154,10 @@ export async function handleRoute({
let request: Request; let request: Request;
let renderContext: RenderContext; let renderContext: RenderContext;
let mod: ComponentInstance | undefined = undefined; let mod: ComponentInstance | undefined = undefined;
let options: SSROptions | undefined = undefined;
let route: RouteData; let route: RouteData;
const middleware = (await loadMiddleware(loader)).onRequest; const middleware = (await loadMiddleware(loader)).onRequest;
const locals = Reflect.get(incomingRequest, clientLocalsSymbol); const locals = Reflect.get(incomingRequest, clientLocalsSymbol);
const filePath: URL | undefined = matchedRoute.filePath;
const { preloadedComponent } = matchedRoute; const { preloadedComponent } = matchedRoute;
route = matchedRoute.route; route = matchedRoute.route;
// Allows adapters to pass in locals in dev mode. // Allows adapters to pass in locals in dev mode.
@ -181,15 +177,6 @@ export async function handleRoute({
if (value) incomingResponse.setHeader(name, value); if (value) incomingResponse.setHeader(name, value);
} }
options = {
pipeline,
filePath,
preload: preloadedComponent,
pathname,
request,
route,
};
mod = preloadedComponent; mod = preloadedComponent;
renderContext = await RenderContext.create({ renderContext = await RenderContext.create({
@ -248,18 +235,17 @@ export async function handleRoute({
if (statusCode === 404 && response.headers.get(REROUTE_DIRECTIVE_HEADER) !== 'no') { if (statusCode === 404 && response.headers.get(REROUTE_DIRECTIVE_HEADER) !== 'no') {
const fourOhFourRoute = await matchRoute('/404', manifestData, pipeline); const fourOhFourRoute = await matchRoute('/404', manifestData, pipeline);
if (options && options.route !== fourOhFourRoute?.route) if (fourOhFourRoute) {
return handleRoute({ renderContext = await RenderContext.create({
...options, locals,
matchedRoute: fourOhFourRoute,
url: new URL(pathname, url),
body,
origin,
pipeline, pipeline,
manifestData, pathname,
incomingRequest, middleware: isDefaultPrerendered404(fourOhFourRoute.route) ? undefined : middleware,
incomingResponse, request,
routeData: fourOhFourRoute.route,
}); });
response = await renderContext.render(fourOhFourRoute.preloadedComponent);
}
} }
// We remove the internally-used header before we send the response to the user agent. // We remove the internally-used header before we send the response to the user agent.

View file

@ -7,6 +7,7 @@ const currentLocale = Astro.currentLocale;
</head> </head>
<body> <body>
<h1>404 - Not Found</h1> <h1>404 - Not Found</h1>
<h2>Custom 404</h2>
<p>Current Locale: {currentLocale ? currentLocale : "none"}</p> <p>Current Locale: {currentLocale ? currentLocale : "none"}</p>
</body> </body>
</html> </html>

View file

@ -83,6 +83,12 @@ describe('[DEV] i18n routing', () => {
assert.equal((await response.text()).includes('Endurance'), true); assert.equal((await response.text()).includes('Endurance'), true);
}); });
it('should render the 404.astro file', async () => {
const response = await fixture.fetch('/do-not-exist');
assert.equal(response.status, 404);
assert.match(await response.text(), /Custom 404/);
});
it('should return the correct locale on 404 page for non existing default locale page', async () => { it('should return the correct locale on 404 page for non existing default locale page', async () => {
const response = await fixture.fetch('/es/nonexistent-page'); const response = await fixture.fetch('/es/nonexistent-page');
assert.equal(response.status, 404); assert.equal(response.status, 404);