Skip to content

Commit

Permalink
fix(i18n): render 404.astro when i18n is enabled (#12525)
Browse files Browse the repository at this point in the history
Co-authored-by: Chris Swithinbank <[email protected]>


Co-authored-by: delucis <[email protected]>
Co-authored-by: bluwy <[email protected]>
  • Loading branch information
3 people authored Nov 26, 2024
1 parent 8b0e36c commit cf0d8b0
Show file tree
Hide file tree
Showing 6 changed files with 28 additions and 25 deletions.
5 changes: 5 additions & 0 deletions .changeset/hot-dingos-dress.md
Original file line number Diff line number Diff line change
@@ -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.
8 changes: 7 additions & 1 deletion packages/astro/src/i18n/middleware.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { APIContext, MiddlewareHandler, SSRManifest } from '../@types/astro.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 {
type MiddlewarePayload,
normalizeTheLocale,
Expand Down Expand Up @@ -65,6 +65,12 @@ export function createI18nMiddleware(
return async (context, next) => {
const response = await next();
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 (type !== 'page' && type !== 'fallback') {
return response;
Expand Down
1 change: 0 additions & 1 deletion packages/astro/src/vite-plugin-astro-server/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ export async function handleRequest({
url,
pathname: resolvedPathname,
body,
origin,
pipeline,
manifestData,
incomingRequest: incomingRequest,
Expand Down
32 changes: 9 additions & 23 deletions packages/astro/src/vite-plugin-astro-server/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,6 @@ type HandleRoute = {
url: URL;
pathname: string;
body: ArrayBuffer | undefined;
origin: string;
manifestData: ManifestData;
incomingRequest: http.IncomingMessage;
incomingResponse: http.ServerResponse;
Expand All @@ -139,7 +138,6 @@ export async function handleRoute({
url,
pathname,
body,
origin,
pipeline,
manifestData,
incomingRequest,
Expand All @@ -156,12 +154,10 @@ export async function handleRoute({
let request: Request;
let renderContext: RenderContext;
let mod: ComponentInstance | undefined = undefined;
let options: SSROptions | undefined = undefined;
let route: RouteData;
const middleware = (await loadMiddleware(loader)).onRequest;
const locals = Reflect.get(incomingRequest, clientLocalsSymbol);

const filePath: URL | undefined = matchedRoute.filePath;
const { preloadedComponent } = matchedRoute;
route = matchedRoute.route;
// Allows adapters to pass in locals in dev mode.
Expand All @@ -181,15 +177,6 @@ export async function handleRoute({
if (value) incomingResponse.setHeader(name, value);
}

options = {
pipeline,
filePath,
preload: preloadedComponent,
pathname,
request,
route,
};

mod = preloadedComponent;

renderContext = await RenderContext.create({
Expand Down Expand Up @@ -248,18 +235,17 @@ export async function handleRoute({

if (statusCode === 404 && response.headers.get(REROUTE_DIRECTIVE_HEADER) !== 'no') {
const fourOhFourRoute = await matchRoute('/404', manifestData, pipeline);
if (options && options.route !== fourOhFourRoute?.route)
return handleRoute({
...options,
matchedRoute: fourOhFourRoute,
url: new URL(pathname, url),
body,
origin,
if (fourOhFourRoute) {
renderContext = await RenderContext.create({
locals,
pipeline,
manifestData,
incomingRequest,
incomingResponse,
pathname,
middleware: isDefaultPrerendered404(fourOhFourRoute.route) ? undefined : middleware,
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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const currentLocale = Astro.currentLocale;
</head>
<body>
<h1>404 - Not Found</h1>
<h2>Custom 404</h2>
<p>Current Locale: {currentLocale ? currentLocale : "none"}</p>
</body>
</html>
6 changes: 6 additions & 0 deletions packages/astro/test/i18n-routing.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@ describe('[DEV] i18n routing', () => {
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 () => {
const response = await fixture.fetch('/es/nonexistent-page');
assert.equal(response.status, 404);
Expand Down

0 comments on commit cf0d8b0

Please sign in to comment.