0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2024-12-16 21:46:22 -05:00

fix(i18n): parse params and props correctly with fallback (#12709)

Co-authored-by: Emanuele Stoppa <my.burning@gmail.com>
This commit is contained in:
mtwilliams 2024-12-12 08:29:46 -05:00 committed by GitHub
parent 358eae83b7
commit e3bfd93969
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 104 additions and 10 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Fixes a bug where Astro couldn't correctly parse `params` and `props` when receiving i18n fallback URLs

View file

@ -47,7 +47,8 @@ export async function getProps(opts: GetParamsAndPropsOptions): Promise<Props> {
base,
});
// The pathname used here comes from the server, which already encored.
if (!staticPaths.length) return {};
// The pathname used here comes from the server, which already encoded.
// Since we decided to not mess up with encoding anymore, we need to decode them back so the parameters can match
// the ones expected from the users
const params = getParams(route, decodeURI(pathname));
@ -77,7 +78,11 @@ export function getParams(route: RouteData, pathname: string): Params {
if (!route.params.length) return {};
// The RegExp pattern expects a decoded string, but the pathname is encoded
// when the URL contains non-English characters.
const paramsMatch = route.pattern.exec(pathname);
const paramsMatch =
route.pattern.exec(pathname) ||
route.fallbackRoutes
.map((fallbackRoute) => fallbackRoute.pattern.exec(pathname))
.find((x) => x);
if (!paramsMatch) return {};
const params: Params = {};
route.params.forEach((key, i) => {

View file

@ -1,18 +1,28 @@
---
// for SSR
const blogs = {
1: { content: "Hello world" },
2: { content: "Eat Something" },
3: { content: "How are you?" },
}
const id = Astro.params?.id;
const ssrContent = id && blogs[id]?.content;
// for SSG
export function getStaticPaths() {
return [
{params: {id: '1'}, props: { content: "Hello world" }},
{params: {id: '2'}, props: { content: "Eat Something" }},
{params: {id: '3'}, props: { content: "How are you?" }},
];
]
}
const { content } = Astro.props;
const { content } = Astro.props
---
<html>
<head>
<title>Astro</title>
</head>
<body>
{content}
{content || ssrContent}
</body>
</html>

View file

@ -1,4 +1,12 @@
---
const blogs = {
1: { content: "Hola mundo" },
2: { content: "Eat Something" },
3: { content: "How are you?" },
}
const id = Astro.params?.id;
const ssrContent = id && blogs[id]?.content;
export function getStaticPaths() {
return [
{params: {id: '1'}, props: { content: "Hola mundo" }},
@ -13,6 +21,6 @@ const { content } = Astro.props;
<title>Astro</title>
</head>
<body>
{content}
{content || ssrContent}
</body>
</html>

View file

@ -1,6 +1,6 @@
import * as cheerio from 'cheerio';
import * as assert from 'node:assert/strict';
import { after, afterEach, before, describe, it } from 'node:test';
import * as cheerio from 'cheerio';
import testAdapter from './test-adapter.js';
import { loadFixture } from './test-utils.js';
@ -2000,12 +2000,14 @@ describe('Fallback rewrite dev server', () => {
root: './fixtures/i18n-routing-fallback/',
i18n: {
defaultLocale: 'en',
locales: ['en', 'fr'],
locales: ['en', 'fr', 'es', 'it', 'pt'],
routing: {
prefixDefaultLocale: false,
},
fallback: {
fr: 'en',
it: 'en',
es: 'pt',
},
fallbackType: 'rewrite',
},
@ -2021,6 +2023,27 @@ describe('Fallback rewrite dev server', () => {
assert.match(html, /Hello/);
// assert.fail()
});
it('should render fallback locale paths with path parameters correctly (fr)', async () => {
let response = await fixture.fetch('/fr/blog/1');
assert.equal(response.status, 200);
const text = await response.text();
assert.match(text, /Hello world/);
});
it('should render fallback locale paths with path parameters correctly (es)', async () => {
let response = await fixture.fetch('/es/blog/1');
assert.equal(response.status, 200);
const text = await response.text();
assert.match(text, /Hola mundo/);
});
it('should render fallback locale paths with query parameters correctly (it)', async () => {
let response = await fixture.fetch('/it/blog/1');
assert.equal(response.status, 200);
const text = await response.text();
assert.match(text, /Hello world/);
});
});
describe('Fallback rewrite SSG', () => {
@ -2032,13 +2055,15 @@ describe('Fallback rewrite SSG', () => {
root: './fixtures/i18n-routing-fallback/',
i18n: {
defaultLocale: 'en',
locales: ['en', 'fr'],
locales: ['en', 'fr', 'es', 'it', 'pt'],
routing: {
prefixDefaultLocale: false,
fallbackType: 'rewrite',
},
fallback: {
fr: 'en',
it: 'en',
es: 'pt',
},
},
});
@ -2051,6 +2076,21 @@ describe('Fallback rewrite SSG', () => {
assert.match(html, /Hello/);
// assert.fail()
});
it('should render fallback locale paths with path parameters correctly (fr)', async () => {
const html = await fixture.readFile('/fr/blog/1/index.html');
assert.match(html, /Hello world/);
});
it('should render fallback locale paths with path parameters correctly (es)', async () => {
const html = await fixture.readFile('/es/blog/1/index.html');
assert.match(html, /Hola mundo/);
});
it('should render fallback locale paths with query parameters correctly (it)', async () => {
const html = await fixture.readFile('/it/blog/1/index.html');
assert.match(html, /Hello world/);
});
});
describe('Fallback rewrite SSR', () => {
@ -2066,13 +2106,15 @@ describe('Fallback rewrite SSR', () => {
adapter: testAdapter(),
i18n: {
defaultLocale: 'en',
locales: ['en', 'fr'],
locales: ['en', 'fr', 'es', 'it', 'pt'],
routing: {
prefixDefaultLocale: false,
fallbackType: 'rewrite',
},
fallback: {
fr: 'en',
it: 'en',
es: 'pt',
},
},
});
@ -2087,4 +2129,28 @@ describe('Fallback rewrite SSR', () => {
const html = await response.text();
assert.match(html, /Hello/);
});
it('should render fallback locale paths with path parameters correctly (fr)', async () => {
let request = new Request('http://example.com/new-site/fr/blog/1');
let response = await app.render(request);
assert.equal(response.status, 200);
const text = await response.text();
assert.match(text, /Hello world/);
});
it('should render fallback locale paths with path parameters correctly (es)', async () => {
let request = new Request('http://example.com/new-site/es/blog/1');
let response = await app.render(request);
assert.equal(response.status, 200);
const text = await response.text();
assert.match(text, /Hola mundo/);
});
it('should render fallback locale paths with query parameters correctly (it)', async () => {
let request = new Request('http://example.com/new-site/it/blog/1');
let response = await app.render(request);
assert.equal(response.status, 200);
const text = await response.text();
assert.match(text, /Hello world/);
});
});