Skip to content

Commit e3bfd93

Browse files
fix(i18n): parse params and props correctly with fallback (#12709)
Co-authored-by: Emanuele Stoppa <[email protected]>
1 parent 358eae8 commit e3bfd93

File tree

5 files changed

+104
-10
lines changed

5 files changed

+104
-10
lines changed

.changeset/selfish-paws-play.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'astro': patch
3+
---
4+
5+
Fixes a bug where Astro couldn't correctly parse `params` and `props` when receiving i18n fallback URLs

packages/astro/src/core/render/params-and-props.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ export async function getProps(opts: GetParamsAndPropsOptions): Promise<Props> {
4747
base,
4848
});
4949

50-
// The pathname used here comes from the server, which already encored.
50+
if (!staticPaths.length) return {};
51+
// The pathname used here comes from the server, which already encoded.
5152
// Since we decided to not mess up with encoding anymore, we need to decode them back so the parameters can match
5253
// the ones expected from the users
5354
const params = getParams(route, decodeURI(pathname));
@@ -77,7 +78,11 @@ export function getParams(route: RouteData, pathname: string): Params {
7778
if (!route.params.length) return {};
7879
// The RegExp pattern expects a decoded string, but the pathname is encoded
7980
// when the URL contains non-English characters.
80-
const paramsMatch = route.pattern.exec(pathname);
81+
const paramsMatch =
82+
route.pattern.exec(pathname) ||
83+
route.fallbackRoutes
84+
.map((fallbackRoute) => fallbackRoute.pattern.exec(pathname))
85+
.find((x) => x);
8186
if (!paramsMatch) return {};
8287
const params: Params = {};
8388
route.params.forEach((key, i) => {
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,28 @@
11
---
2+
// for SSR
3+
const blogs = {
4+
1: { content: "Hello world" },
5+
2: { content: "Eat Something" },
6+
3: { content: "How are you?" },
7+
}
8+
const id = Astro.params?.id;
9+
const ssrContent = id && blogs[id]?.content;
10+
11+
// for SSG
212
export function getStaticPaths() {
313
return [
414
{params: {id: '1'}, props: { content: "Hello world" }},
515
{params: {id: '2'}, props: { content: "Eat Something" }},
616
{params: {id: '3'}, props: { content: "How are you?" }},
7-
];
17+
]
818
}
9-
const { content } = Astro.props;
19+
const { content } = Astro.props
1020
---
1121
<html>
1222
<head>
1323
<title>Astro</title>
1424
</head>
1525
<body>
16-
{content}
26+
{content || ssrContent}
1727
</body>
1828
</html>

packages/astro/test/fixtures/i18n-routing-fallback/src/pages/pt/blog/[id].astro

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
---
2+
const blogs = {
3+
1: { content: "Hola mundo" },
4+
2: { content: "Eat Something" },
5+
3: { content: "How are you?" },
6+
}
7+
const id = Astro.params?.id;
8+
const ssrContent = id && blogs[id]?.content;
9+
210
export function getStaticPaths() {
311
return [
412
{params: {id: '1'}, props: { content: "Hola mundo" }},
@@ -13,6 +21,6 @@ const { content } = Astro.props;
1321
<title>Astro</title>
1422
</head>
1523
<body>
16-
{content}
24+
{content || ssrContent}
1725
</body>
1826
</html>

packages/astro/test/i18n-routing.test.js

+70-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1+
import * as cheerio from 'cheerio';
12
import * as assert from 'node:assert/strict';
23
import { after, afterEach, before, describe, it } from 'node:test';
3-
import * as cheerio from 'cheerio';
44
import testAdapter from './test-adapter.js';
55
import { loadFixture } from './test-utils.js';
66

@@ -2000,12 +2000,14 @@ describe('Fallback rewrite dev server', () => {
20002000
root: './fixtures/i18n-routing-fallback/',
20012001
i18n: {
20022002
defaultLocale: 'en',
2003-
locales: ['en', 'fr'],
2003+
locales: ['en', 'fr', 'es', 'it', 'pt'],
20042004
routing: {
20052005
prefixDefaultLocale: false,
20062006
},
20072007
fallback: {
20082008
fr: 'en',
2009+
it: 'en',
2010+
es: 'pt',
20092011
},
20102012
fallbackType: 'rewrite',
20112013
},
@@ -2021,6 +2023,27 @@ describe('Fallback rewrite dev server', () => {
20212023
assert.match(html, /Hello/);
20222024
// assert.fail()
20232025
});
2026+
2027+
it('should render fallback locale paths with path parameters correctly (fr)', async () => {
2028+
let response = await fixture.fetch('/fr/blog/1');
2029+
assert.equal(response.status, 200);
2030+
const text = await response.text();
2031+
assert.match(text, /Hello world/);
2032+
});
2033+
2034+
it('should render fallback locale paths with path parameters correctly (es)', async () => {
2035+
let response = await fixture.fetch('/es/blog/1');
2036+
assert.equal(response.status, 200);
2037+
const text = await response.text();
2038+
assert.match(text, /Hola mundo/);
2039+
});
2040+
2041+
it('should render fallback locale paths with query parameters correctly (it)', async () => {
2042+
let response = await fixture.fetch('/it/blog/1');
2043+
assert.equal(response.status, 200);
2044+
const text = await response.text();
2045+
assert.match(text, /Hello world/);
2046+
});
20242047
});
20252048

20262049
describe('Fallback rewrite SSG', () => {
@@ -2032,13 +2055,15 @@ describe('Fallback rewrite SSG', () => {
20322055
root: './fixtures/i18n-routing-fallback/',
20332056
i18n: {
20342057
defaultLocale: 'en',
2035-
locales: ['en', 'fr'],
2058+
locales: ['en', 'fr', 'es', 'it', 'pt'],
20362059
routing: {
20372060
prefixDefaultLocale: false,
20382061
fallbackType: 'rewrite',
20392062
},
20402063
fallback: {
20412064
fr: 'en',
2065+
it: 'en',
2066+
es: 'pt',
20422067
},
20432068
},
20442069
});
@@ -2051,6 +2076,21 @@ describe('Fallback rewrite SSG', () => {
20512076
assert.match(html, /Hello/);
20522077
// assert.fail()
20532078
});
2079+
2080+
it('should render fallback locale paths with path parameters correctly (fr)', async () => {
2081+
const html = await fixture.readFile('/fr/blog/1/index.html');
2082+
assert.match(html, /Hello world/);
2083+
});
2084+
2085+
it('should render fallback locale paths with path parameters correctly (es)', async () => {
2086+
const html = await fixture.readFile('/es/blog/1/index.html');
2087+
assert.match(html, /Hola mundo/);
2088+
});
2089+
2090+
it('should render fallback locale paths with query parameters correctly (it)', async () => {
2091+
const html = await fixture.readFile('/it/blog/1/index.html');
2092+
assert.match(html, /Hello world/);
2093+
});
20542094
});
20552095

20562096
describe('Fallback rewrite SSR', () => {
@@ -2066,13 +2106,15 @@ describe('Fallback rewrite SSR', () => {
20662106
adapter: testAdapter(),
20672107
i18n: {
20682108
defaultLocale: 'en',
2069-
locales: ['en', 'fr'],
2109+
locales: ['en', 'fr', 'es', 'it', 'pt'],
20702110
routing: {
20712111
prefixDefaultLocale: false,
20722112
fallbackType: 'rewrite',
20732113
},
20742114
fallback: {
20752115
fr: 'en',
2116+
it: 'en',
2117+
es: 'pt',
20762118
},
20772119
},
20782120
});
@@ -2087,4 +2129,28 @@ describe('Fallback rewrite SSR', () => {
20872129
const html = await response.text();
20882130
assert.match(html, /Hello/);
20892131
});
2132+
2133+
it('should render fallback locale paths with path parameters correctly (fr)', async () => {
2134+
let request = new Request('http://example.com/new-site/fr/blog/1');
2135+
let response = await app.render(request);
2136+
assert.equal(response.status, 200);
2137+
const text = await response.text();
2138+
assert.match(text, /Hello world/);
2139+
});
2140+
2141+
it('should render fallback locale paths with path parameters correctly (es)', async () => {
2142+
let request = new Request('http://example.com/new-site/es/blog/1');
2143+
let response = await app.render(request);
2144+
assert.equal(response.status, 200);
2145+
const text = await response.text();
2146+
assert.match(text, /Hola mundo/);
2147+
});
2148+
2149+
it('should render fallback locale paths with query parameters correctly (it)', async () => {
2150+
let request = new Request('http://example.com/new-site/it/blog/1');
2151+
let response = await app.render(request);
2152+
assert.equal(response.status, 200);
2153+
const text = await response.text();
2154+
assert.match(text, /Hello world/);
2155+
});
20902156
});

0 commit comments

Comments
 (0)