diff --git a/.changeset/shy-wolves-ring.md b/.changeset/shy-wolves-ring.md
new file mode 100644
index 000000000000..f48a8de75e30
--- /dev/null
+++ b/.changeset/shy-wolves-ring.md
@@ -0,0 +1,5 @@
+---
+"astro": patch
+---
+
+Fixes a bug in `Astro.currentLocale` that wasn't returning the correct locale when a locale is configured via `path`
diff --git a/.changeset/six-fishes-beg.md b/.changeset/six-fishes-beg.md
new file mode 100644
index 000000000000..e753dc59ccac
--- /dev/null
+++ b/.changeset/six-fishes-beg.md
@@ -0,0 +1,5 @@
+---
+"astro": patch
+---
+
+Fixes a regression in `Astro.currentLocale` where it stopped working properly with dynamic routes
diff --git a/packages/astro/src/core/render/context.ts b/packages/astro/src/core/render/context.ts
index faba9b86a266..8511942f348a 100644
--- a/packages/astro/src/core/render/context.ts
+++ b/packages/astro/src/core/render/context.ts
@@ -249,20 +249,32 @@ export function computeCurrentLocale(
if (!routeData) {
return defaultLocale;
}
-
- for (const segment of routeData.route.split('/')) {
+ // Typically, RouteData::pathname has the correct information in SSR, but it's not available in SSG, so we fall back
+ // to use the pathname from the Request
+ const pathname = routeData.pathname ?? new URL(request.url).pathname;
+ for (const segment of pathname.split('/').filter(Boolean)) {
for (const locale of locales) {
if (typeof locale === 'string') {
+ // we skip ta locale that isn't present in the current segment
+
+ if (!segment.includes(locale)) continue;
if (normalizeTheLocale(locale) === normalizeTheLocale(segment)) {
return locale;
}
} else {
if (locale.path === segment) {
return locale.codes.at(0);
+ } else {
+ for (const code of locale.codes) {
+ if (normalizeTheLocale(code) === normalizeTheLocale(segment)) {
+ return code;
+ }
+ }
}
}
}
}
+
if (
routingStrategy === 'pathname-prefix-other-locales' ||
routingStrategy === 'domains-prefix-other-locales'
diff --git a/packages/astro/test/fixtures/i18n-routing/src/pages/blog/[...lang]/index.astro b/packages/astro/test/fixtures/i18n-routing/src/pages/blog/[...lang]/index.astro
new file mode 100644
index 000000000000..f67085be8a5b
--- /dev/null
+++ b/packages/astro/test/fixtures/i18n-routing/src/pages/blog/[...lang]/index.astro
@@ -0,0 +1,22 @@
+---
+const currentLocale = Astro.currentLocale;
+
+
+export async function getStaticPaths() {
+ return [
+ { params: { lang: undefined } },
+ { params: { lang: 'es' } }
+ ]
+}
+
+---
+
+
+
+
+ Astro
+
+
+Current Locale: {currentLocale ? currentLocale : "none"}
+
+
diff --git a/packages/astro/test/fixtures/i18n-routing/src/pages/spanish/index.astro b/packages/astro/test/fixtures/i18n-routing/src/pages/spanish/index.astro
new file mode 100644
index 000000000000..052be7d8cd85
--- /dev/null
+++ b/packages/astro/test/fixtures/i18n-routing/src/pages/spanish/index.astro
@@ -0,0 +1,13 @@
+---
+const currentLocale = Astro.currentLocale;
+
+---
+
+
+
+ Astro
+
+
+Current Locale: {currentLocale ? currentLocale : "none"}
+
+
diff --git a/packages/astro/test/i18n-routing.test.js b/packages/astro/test/i18n-routing.test.js
index b3d496ff41ba..2e8256cac2ab 100644
--- a/packages/astro/test/i18n-routing.test.js
+++ b/packages/astro/test/i18n-routing.test.js
@@ -52,7 +52,6 @@ describe('astro:i18n virtual module', () => {
let html = await response.text();
let $ = cheerio.load(html);
- console.log(html);
expect($('body').text()).includes("Virtual module doesn't break");
expect($('body').text()).includes('Absolute URL pt: https://example.pt/about');
expect($('body').text()).includes('Absolute URL it: http://it.example.com/');
@@ -1005,6 +1004,67 @@ describe('[SSG] i18n routing', () => {
expect(html).to.include('Redirecting to: /new-site/');
});
});
+
+ describe('current locale', () => {
+ describe('with [prefix-other-locales]', () => {
+ /** @type {import('./test-utils').Fixture} */
+ let fixture;
+
+ before(async () => {
+ fixture = await loadFixture({
+ root: './fixtures/i18n-routing/',
+ });
+ await fixture.build();
+ });
+
+ it('should return the default locale', async () => {
+ const html = await fixture.readFile('/current-locale/index.html');
+ expect(html).includes('Current Locale: en');
+ });
+
+ it('should return the default locale when rendering a route with spread operator', async () => {
+ const html = await fixture.readFile('/blog/es/index.html');
+ expect(html).includes('Current Locale: es');
+ });
+
+ it('should return the default locale of the current URL', async () => {
+ const html = await fixture.readFile('/pt/start/index.html');
+ expect(html).includes('Current Locale: pt');
+ });
+
+ it('should return the default locale when a route is dynamic', async () => {
+ const html = await fixture.readFile('/dynamic/lorem/index.html');
+ expect(html).includes('Current Locale: en');
+ });
+
+ it('should returns the correct locale when requesting a locale via path', async () => {
+ const html = await fixture.readFile('/spanish/index.html');
+ expect(html).includes('Current Locale: es');
+ });
+ });
+
+ describe('with [pathname-prefix-always]', () => {
+ /** @type {import('./test-utils').Fixture} */
+ let fixture;
+
+ before(async () => {
+ fixture = await loadFixture({
+ root: './fixtures/i18n-routing-prefix-always/',
+ });
+ await fixture.build();
+ });
+
+ it('should return the locale of the current URL (en)', async () => {
+ const html = await fixture.readFile('/en/start/index.html');
+ expect(html).includes('Current Locale: en');
+ });
+
+ it('should return the locale of the current URL (pt)', async () => {
+ const html = await fixture.readFile('/pt/start/index.html');
+ expect(html).includes('Current Locale: pt');
+ });
+ });
+ });
});
describe('[SSR] i18n routing', () => {
let app;
@@ -1525,6 +1585,13 @@ describe('[SSR] i18n routing', () => {
expect(await response.text()).includes('Current Locale: en');
});
+ it('should return the default locale when rendering a route with spread operator', async () => {
+ let request = new Request('http://example.com/blog/es', {});
+ let response = await app.render(request);
+ expect(response.status).to.equal(200);
+ expect(await response.text()).includes('Current Locale: es');
+ });
+
it('should return the default locale of the current URL', async () => {
let request = new Request('http://example.com/pt/start', {});
let response = await app.render(request);