diff --git a/.changeset/loud-pianos-pretend.md b/.changeset/loud-pianos-pretend.md
new file mode 100644
index 000000000000..17fadba3dcb9
--- /dev/null
+++ b/.changeset/loud-pianos-pretend.md
@@ -0,0 +1,5 @@
+---
+"astro": patch
+---
+
+Fixes the overwriting of localised index pages with redirects
diff --git a/packages/astro/src/core/build/generate.ts b/packages/astro/src/core/build/generate.ts
index 022261323543..fea2447b0ba3 100644
--- a/packages/astro/src/core/build/generate.ts
+++ b/packages/astro/src/core/build/generate.ts
@@ -327,12 +327,6 @@ async function getPathsForRoute(
if (route.pathname) {
paths.push(route.pathname);
builtPaths.add(route.pathname);
- for (const virtualRoute of route.fallbackRoutes) {
- if (virtualRoute.pathname) {
- paths.push(virtualRoute.pathname);
- builtPaths.add(virtualRoute.pathname);
- }
- }
} else {
const staticPaths = await callGetStaticPaths({
mod,
@@ -485,6 +479,19 @@ async function generatePath(
addPageName(pathname, options);
}
+ // Do not render the fallback route if there is already a translated page
+ // with the same path
+ if (
+ route.type === 'fallback' &&
+ // If route is index page, continue rendering. The index page should
+ // always be rendered
+ route.pathname !== '/' &&
+ // Check if there is a translated page with the same path
+ Object.values(options.allPages).some((val) => pathname.match(val.route.pattern))
+ ) {
+ return;
+ }
+
const url = getUrlForPath(
pathname,
config.base,
diff --git a/packages/astro/test/fixtures/i18n-routing-fallback-index/astro.config.mjs b/packages/astro/test/fixtures/i18n-routing-fallback-index/astro.config.mjs
new file mode 100644
index 000000000000..48f19651ac33
--- /dev/null
+++ b/packages/astro/test/fixtures/i18n-routing-fallback-index/astro.config.mjs
@@ -0,0 +1,15 @@
+import { defineConfig } from "astro/config";
+
+export default defineConfig({
+ base: "new-site",
+ i18n: {
+ defaultLocale: 'en',
+ locales: [
+ 'en', 'pt', 'it'
+ ],
+ fallback: {
+ "it": "en",
+ pt: "en"
+ }
+ }
+})
diff --git a/packages/astro/test/fixtures/i18n-routing-fallback-index/package.json b/packages/astro/test/fixtures/i18n-routing-fallback-index/package.json
new file mode 100644
index 000000000000..5db10a91aabe
--- /dev/null
+++ b/packages/astro/test/fixtures/i18n-routing-fallback-index/package.json
@@ -0,0 +1,8 @@
+{
+ "name": "@test/i18n-routing-fallback-index",
+ "version": "0.0.0",
+ "private": true,
+ "dependencies": {
+ "astro": "workspace:*"
+ }
+}
diff --git a/packages/astro/test/fixtures/i18n-routing-fallback-index/src/pages/index.astro b/packages/astro/test/fixtures/i18n-routing-fallback-index/src/pages/index.astro
new file mode 100644
index 000000000000..34b39fcd6747
--- /dev/null
+++ b/packages/astro/test/fixtures/i18n-routing-fallback-index/src/pages/index.astro
@@ -0,0 +1,13 @@
+
+
+ Astro
+
+
+
+ Hello
+
+
+
+
diff --git a/packages/astro/test/fixtures/i18n-routing-fallback-index/src/pages/pt/index.astro b/packages/astro/test/fixtures/i18n-routing-fallback-index/src/pages/pt/index.astro
new file mode 100644
index 000000000000..6c45f4dc291b
--- /dev/null
+++ b/packages/astro/test/fixtures/i18n-routing-fallback-index/src/pages/pt/index.astro
@@ -0,0 +1,12 @@
+---
+const currentLocale = Astro.currentLocale;
+---
+
+
+
+ Astro
+
+
+Oi essa e index: {currentLocale}
+
+
diff --git a/packages/astro/test/fixtures/i18n-routing-fallback/package.json b/packages/astro/test/fixtures/i18n-routing-fallback/package.json
index 0741df455398..6949c63de1cd 100644
--- a/packages/astro/test/fixtures/i18n-routing-fallback/package.json
+++ b/packages/astro/test/fixtures/i18n-routing-fallback/package.json
@@ -1,5 +1,5 @@
{
- "name": "@test/i18n-routing-fallabck",
+ "name": "@test/i18n-routing-fallback",
"version": "0.0.0",
"private": true,
"dependencies": {
diff --git a/packages/astro/test/i18n-routing.test.js b/packages/astro/test/i18n-routing.test.js
index 7287fc041c93..07965bea1052 100644
--- a/packages/astro/test/i18n-routing.test.js
+++ b/packages/astro/test/i18n-routing.test.js
@@ -935,6 +935,37 @@ describe('[SSG] i18n routing', () => {
let $ = cheerio.load(html);
assert.equal($('script').text().includes('console.log("this is a script")'), true);
});
+
+ describe('with localised index pages', () => {
+ before(async () => {
+ fixture = await loadFixture({
+ root: './fixtures/i18n-routing-fallback-index/',
+ i18n: {
+ defaultLocale: 'en',
+ locales: [
+ 'en',
+ 'pt',
+ 'it',
+ {
+ path: 'spanish',
+ codes: ['es', 'es-AR'],
+ },
+ ],
+ fallback: {
+ it: 'en',
+ spanish: 'en',
+ },
+ },
+ });
+ await fixture.build();
+ });
+
+ it('should render correctly', async () => {
+ let html = await fixture.readFile('/pt/index.html');
+ let $ = cheerio.load(html);
+ assert.equal($('body').text().includes('Oi essa e index'), true);
+ });
+ })
});
describe('i18n routing with fallback and [pathname-prefix-always]', () => {
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 20ca6e1fccc0..8b796f4b0838 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -131,6 +131,42 @@ importers:
specifier: workspace:*
version: link:../../../scripts
+ examples/astro-missing-headers:
+ dependencies:
+ '@astrojs/check':
+ specifier: ^0.5.4
+ version: 0.5.5(prettier-plugin-astro@0.12.3)(prettier@3.1.1)(typescript@5.3.3)
+ '@astrojs/node':
+ specifier: ^8.2.0
+ version: link:../../packages/integrations/node
+ astro:
+ specifier: ^4.4.0
+ version: link:../../packages/astro
+ typescript:
+ specifier: ^5.3.3
+ version: 5.3.3
+
+ examples/astro-svelte-repro:
+ dependencies:
+ '@astrojs/check':
+ specifier: ^0.5.4
+ version: 0.5.5(prettier-plugin-astro@0.12.3)(prettier@3.1.1)(typescript@5.3.3)
+ '@astrojs/mdx':
+ specifier: ^2.1.1
+ version: link:../../packages/integrations/mdx
+ '@astrojs/svelte':
+ specifier: ^5.0.3
+ version: link:../../packages/integrations/svelte
+ astro:
+ specifier: ^4.4.0
+ version: link:../../packages/astro
+ svelte:
+ specifier: 5.0.0-next.60
+ version: 5.0.0-next.60
+ typescript:
+ specifier: ^5.3.3
+ version: 5.3.3
+
examples/basics:
dependencies:
astro:
@@ -2882,6 +2918,12 @@ importers:
specifier: workspace:*
version: link:../../..
+ packages/astro/test/fixtures/i18n-routing-fallback-index:
+ dependencies:
+ astro:
+ specifier: workspace:*
+ version: link:../../..
+
packages/astro/test/fixtures/i18n-routing-prefix-always:
dependencies:
astro:
@@ -5482,6 +5524,23 @@ packages:
- prettier-plugin-astro
dev: false
+ /@astrojs/check@0.5.5(prettier-plugin-astro@0.12.3)(prettier@3.1.1)(typescript@5.3.3):
+ resolution: {integrity: sha512-05LjyUB14Cv2mkLNqY4r2igI2eu0bq/HcKCfFNIoBPLyNW7VUDr9tciD9VJXXT3s0e6JHneIs6bQW5ipjmaRcw==}
+ hasBin: true
+ peerDependencies:
+ typescript: ^5.0.0
+ dependencies:
+ '@astrojs/language-server': 2.7.5(prettier-plugin-astro@0.12.3)(prettier@3.1.1)(typescript@5.3.3)
+ chokidar: 3.5.3
+ fast-glob: 3.3.2
+ kleur: 4.1.5
+ typescript: 5.3.3
+ yargs: 17.7.2
+ transitivePeerDependencies:
+ - prettier
+ - prettier-plugin-astro
+ dev: false
+
/@astrojs/cli-kit@0.2.5:
resolution: {integrity: sha512-j6zpNUjtHJGEIKkTrTPvQD3G/sJUKyseJty42iVR3HqytzqHwLK165vptdT4NZKfZ082yLnUtsOXxRyIdfm/AQ==}
dependencies:
@@ -5575,6 +5634,40 @@ packages:
- typescript
dev: false
+ /@astrojs/language-server@2.7.5(prettier-plugin-astro@0.12.3)(prettier@3.1.1)(typescript@5.3.3):
+ resolution: {integrity: sha512-iMfZ3UaqTgIL+z/eUDOppRa1bGUAteWRihbWq5mGAgvr/hu384ZXUKJcqV3BBux0MBsRXwjxzrC2dJu9IpAaoA==}
+ hasBin: true
+ peerDependencies:
+ prettier: ^3.0.0
+ prettier-plugin-astro: '>=0.11.0'
+ peerDependenciesMeta:
+ prettier:
+ optional: true
+ prettier-plugin-astro:
+ optional: true
+ dependencies:
+ '@astrojs/compiler': 2.5.3
+ '@jridgewell/sourcemap-codec': 1.4.15
+ '@volar/kit': 2.0.4(typescript@5.3.3)
+ '@volar/language-core': 2.0.4
+ '@volar/language-server': 2.0.4
+ '@volar/language-service': 2.0.4
+ '@volar/typescript': 2.0.4
+ fast-glob: 3.3.2
+ prettier: 3.1.1
+ prettier-plugin-astro: 0.12.3
+ volar-service-css: 0.0.30(@volar/language-service@2.0.4)
+ volar-service-emmet: 0.0.30(@volar/language-service@2.0.4)
+ volar-service-html: 0.0.30(@volar/language-service@2.0.4)
+ volar-service-prettier: 0.0.30(@volar/language-service@2.0.4)(prettier@3.1.1)
+ volar-service-typescript: 0.0.30(@volar/language-service@2.0.4)(@volar/typescript@2.0.4)
+ volar-service-typescript-twoslash-queries: 0.0.30(@volar/language-service@2.0.4)
+ vscode-html-languageservice: 5.1.2
+ vscode-uri: 3.0.8
+ transitivePeerDependencies:
+ - typescript
+ dev: false
+
/@babel/code-frame@7.23.5:
resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==}
engines: {node: '>=6.9.0'}
@@ -8532,6 +8625,19 @@ packages:
vscode-uri: 3.0.8
dev: false
+ /@volar/kit@2.0.4(typescript@5.3.3):
+ resolution: {integrity: sha512-USRx/o0jKz7o8+lEKWMxWqbqvC46XFrf3IE6CZBYzRo9kM7RERQLwUYaoT2bOcHt5DQWublpnTgdgHMm37Gysg==}
+ peerDependencies:
+ typescript: '*'
+ dependencies:
+ '@volar/language-service': 2.0.4
+ '@volar/typescript': 2.0.4
+ typesafe-path: 0.2.2
+ typescript: 5.3.3
+ vscode-languageserver-textdocument: 1.0.11
+ vscode-uri: 3.0.8
+ dev: false
+
/@volar/language-core@1.10.10:
resolution: {integrity: sha512-nsV1o3AZ5n5jaEAObrS3MWLBWaGwUj/vAsc15FVNIv+DbpizQRISg9wzygsHBr56ELRH8r4K75vkYNMtsSNNWw==}
dependencies:
@@ -8771,6 +8877,14 @@ packages:
dependencies:
acorn: 8.11.3
+ /acorn-typescript@1.4.13(acorn@8.11.3):
+ resolution: {integrity: sha512-xsc9Xv0xlVfwp2o7sQ+GCQ1PgbkdcpWdTzrwXxO3xDMTAywVS3oXVOcOHuRjAPkS4P9b+yc/qNF15460v+jp4Q==}
+ peerDependencies:
+ acorn: '>=8.9.0'
+ dependencies:
+ acorn: 8.11.3
+ dev: false
+
/acorn-walk@8.3.2:
resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==}
engines: {node: '>=0.4.0'}
@@ -10543,6 +10657,10 @@ packages:
- supports-color
dev: true
+ /esm-env@1.0.0:
+ resolution: {integrity: sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==}
+ dev: false
+
/esm@3.2.25:
resolution: {integrity: sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==}
engines: {node: '>=6'}
@@ -10569,6 +10687,13 @@ packages:
estraverse: 5.3.0
dev: true
+ /esrap@1.2.1:
+ resolution: {integrity: sha512-dhkcOLfN/aDdMFI1iwPEcy/XqAZzGNfgfEJjZozy2tia6u0dQoZyXzkRshHTckuNsM+c0CYQndY+uRFe3N+AIQ==}
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.4.15
+ '@types/estree': 1.0.5
+ dev: false
+
/esrecurse@4.3.0:
resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
engines: {node: '>=4.0'}
@@ -15703,6 +15828,25 @@ packages:
magic-string: 0.30.5
periscopic: 3.1.0
+ /svelte@5.0.0-next.60:
+ resolution: {integrity: sha512-1BchsRCMVLqt4BY8DxELt0TGveYQgDGaTkAXt/QMjyKEbXnwRAHp7/9KwUOJPGW68huZGccXo3Cez83fMv7yBA==}
+ engines: {node: '>=18'}
+ dependencies:
+ '@ampproject/remapping': 2.2.1
+ '@jridgewell/sourcemap-codec': 1.4.15
+ '@types/estree': 1.0.5
+ acorn: 8.11.3
+ acorn-typescript: 1.4.13(acorn@8.11.3)
+ aria-query: 5.3.0
+ axobject-query: 4.0.0
+ esm-env: 1.0.0
+ esrap: 1.2.1
+ is-reference: 3.0.2
+ locate-character: 3.0.0
+ magic-string: 0.30.7
+ zimmerframe: 1.1.2
+ dev: false
+
/svg-tags@1.0.0:
resolution: {integrity: sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==}
dev: false
@@ -16186,6 +16330,12 @@ packages:
hasBin: true
dev: false
+ /typescript@5.3.3:
+ resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==}
+ engines: {node: '>=14.17'}
+ hasBin: true
+ dev: false
+
/ufo@1.4.0:
resolution: {integrity: sha512-Hhy+BhRBleFjpJ2vchUNN40qgkh0366FWJGqVLYBHev0vpHTrXSA0ryT+74UiW6KWsldNurQMKGqCm1M2zBciQ==}
dev: false
@@ -17274,6 +17424,10 @@ packages:
engines: {node: '>=12.20'}
dev: false
+ /zimmerframe@1.1.2:
+ resolution: {integrity: sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==}
+ dev: false
+
/zod@3.22.4:
resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==}
dev: false