From 037e4f12dd2f460d66f72c9f2d992b95e74d2da9 Mon Sep 17 00:00:00 2001 From: Emanuele Stoppa Date: Wed, 7 Feb 2024 14:42:51 +0000 Subject: [PATCH] fix(i18n): don't consider URLs that start with the name of the defaut locale (#10016) --- .changeset/tough-socks-change.md | 5 ++ packages/astro/src/i18n/middleware.ts | 8 ++- .../i18n-routing/src/pages/endurance.astro | 9 +++ packages/astro/test/i18n-routing.test.js | 64 +++++++++++++++++++ 4 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 .changeset/tough-socks-change.md create mode 100644 packages/astro/test/fixtures/i18n-routing/src/pages/endurance.astro diff --git a/.changeset/tough-socks-change.md b/.changeset/tough-socks-change.md new file mode 100644 index 000000000000..1f6b2762e447 --- /dev/null +++ b/.changeset/tough-socks-change.md @@ -0,0 +1,5 @@ +--- +"astro": patch +--- + +Fixes a bug where routes with a name that start with the name of the `i18n.defaultLocale` were incorrectly returning a 404 response. diff --git a/packages/astro/src/i18n/middleware.ts b/packages/astro/src/i18n/middleware.ts index 5e9f17a6a851..1c05a956be1d 100644 --- a/packages/astro/src/i18n/middleware.ts +++ b/packages/astro/src/i18n/middleware.ts @@ -65,7 +65,13 @@ export function createI18nMiddleware( }; const prefixOtherLocales = (url: URL, response: Response): Response | undefined => { - const pathnameContainsDefaultLocale = url.pathname.includes(`/${i18n.defaultLocale}`); + let pathnameContainsDefaultLocale = false; + for (const segment of url.pathname.split('/')) { + if (normalizeTheLocale(segment) === normalizeTheLocale(i18n.defaultLocale)) { + pathnameContainsDefaultLocale = true; + break; + } + } if (pathnameContainsDefaultLocale) { const newLocation = url.pathname.replace(`/${i18n.defaultLocale}`, ''); response.headers.set('Location', newLocation); diff --git a/packages/astro/test/fixtures/i18n-routing/src/pages/endurance.astro b/packages/astro/test/fixtures/i18n-routing/src/pages/endurance.astro new file mode 100644 index 000000000000..8be48a7320ce --- /dev/null +++ b/packages/astro/test/fixtures/i18n-routing/src/pages/endurance.astro @@ -0,0 +1,9 @@ + + + Astro + + +Endurance + + + diff --git a/packages/astro/test/i18n-routing.test.js b/packages/astro/test/i18n-routing.test.js index 2e8256cac2ab..da22f03110e2 100644 --- a/packages/astro/test/i18n-routing.test.js +++ b/packages/astro/test/i18n-routing.test.js @@ -59,6 +59,30 @@ describe('astro:i18n virtual module', () => { }); }); describe('[DEV] i18n routing', () => { + describe('should render a page that stars with a locale but it is a page', () => { + /** @type {import('./test-utils').Fixture} */ + let fixture; + /** @type {import('./test-utils').DevServer} */ + let devServer; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/i18n-routing/', + }); + devServer = await fixture.startDevServer(); + }); + + after(async () => { + await devServer.stop(); + }); + + it('renders the page', async () => { + const response = await fixture.fetch('/endurance'); + expect(response.status).to.equal(200); + expect(await response.text()).includes('Endurance'); + }); + }); + describe('i18n routing', () => { /** @type {import('./test-utils').Fixture} */ let fixture; @@ -1005,6 +1029,23 @@ describe('[SSG] i18n routing', () => { }); }); + describe('should render a page that stars with a locale but it is a page', () => { + /** @type {import('./test-utils').Fixture} */ + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/i18n-routing/', + }); + await fixture.build(); + }); + + it('renders the page', async () => { + const html = await fixture.readFile('/endurance/index.html'); + expect(html).includes('Endurance'); + }); + }); + describe('current locale', () => { describe('with [prefix-other-locales]', () => { /** @type {import('./test-utils').Fixture} */ @@ -1068,6 +1109,29 @@ describe('[SSG] i18n routing', () => { }); describe('[SSR] i18n routing', () => { let app; + + describe('should render a page that stars with a locale but it is a page', () => { + /** @type {import('./test-utils').Fixture} */ + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/i18n-routing/', + output: 'server', + adapter: testAdapter(), + }); + await fixture.build(); + app = await fixture.loadTestAdapterApp(); + }); + + it('renders the page', async () => { + let request = new Request('http://example.com/endurance'); + let response = await app.render(request); + expect(response.status).to.equal(200); + expect(await response.text()).includes('Endurance'); + }); + }); + describe('default', () => { /** @type {import('./test-utils').Fixture} */ let fixture;