summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Swithinbank2024-01-31 10:57:51 +0100
committerGitHub2024-01-31 10:57:51 +0100
commit1a642e4d74ee4c30e85bce37b41888b1eae0544a (patch)
tree7e65ab26e6d839ef0ebbf71d5fa6304dc29cf22c
parentc5f4a71c69dfa820876101821c138928e5960fa6 (diff)
downloadIT.starlight-1a642e4d74ee4c30e85bce37b41888b1eae0544a.tar.gz
IT.starlight-1a642e4d74ee4c30e85bce37b41888b1eae0544a.tar.bz2
IT.starlight-1a642e4d74ee4c30e85bce37b41888b1eae0544a.zip
Update `localizedUrl()` to handle `.html` routes correctly (#1442)
-rw-r--r--.changeset/hip-otters-deny.md5
-rw-r--r--packages/starlight/__tests__/basics/localizedUrl.test.ts27
-rw-r--r--packages/starlight/__tests__/i18n-root-locale/localizedUrl.test.ts84
-rw-r--r--packages/starlight/__tests__/i18n/localizedUrl.test.ts48
-rw-r--r--packages/starlight/utils/localizedUrl.ts22
5 files changed, 155 insertions, 31 deletions
diff --git a/.changeset/hip-otters-deny.md b/.changeset/hip-otters-deny.md
new file mode 100644
index 00000000..81121007
--- /dev/null
+++ b/.changeset/hip-otters-deny.md
@@ -0,0 +1,5 @@
+---
+'@astrojs/starlight': patch
+---
+
+Fixes URLs in language picker for sites with `build.format: 'file'`
diff --git a/packages/starlight/__tests__/basics/localizedUrl.test.ts b/packages/starlight/__tests__/basics/localizedUrl.test.ts
index 0c56a291..f65529cb 100644
--- a/packages/starlight/__tests__/basics/localizedUrl.test.ts
+++ b/packages/starlight/__tests__/basics/localizedUrl.test.ts
@@ -1,7 +1,26 @@
-import { expect, test } from 'vitest';
+import { describe, expect, test } from 'vitest';
import { localizedUrl } from '../../utils/localizedUrl';
-test('it has no effect in a monolingual project', () => {
- const url = new URL('https://example.com/en/guide/');
- expect(localizedUrl(url, undefined).href).toBe(url.href);
+describe('with `build.output: "directory"`', () => {
+ test('it has no effect in a monolingual project', () => {
+ const url = new URL('https://example.com/en/guide/');
+ expect(localizedUrl(url, undefined).href).toBe(url.href);
+ });
+
+ test('has no effect on index route in a monolingual project', () => {
+ const url = new URL('https://example.com/');
+ expect(localizedUrl(url, undefined).href).toBe(url.href);
+ });
+});
+
+describe('with `build.output: "file"`', () => {
+ test('it has no effect in a monolingual project', () => {
+ const url = new URL('https://example.com/en/guide.html');
+ expect(localizedUrl(url, undefined).href).toBe(url.href);
+ });
+
+ test('has no effect on index route in a monolingual project', () => {
+ const url = new URL('https://example.com/index.html');
+ expect(localizedUrl(url, undefined).href).toBe(url.href);
+ });
});
diff --git a/packages/starlight/__tests__/i18n-root-locale/localizedUrl.test.ts b/packages/starlight/__tests__/i18n-root-locale/localizedUrl.test.ts
index fb1b0aac..51ed335d 100644
--- a/packages/starlight/__tests__/i18n-root-locale/localizedUrl.test.ts
+++ b/packages/starlight/__tests__/i18n-root-locale/localizedUrl.test.ts
@@ -1,22 +1,76 @@
-import { expect, test } from 'vitest';
+import { describe, expect, test } from 'vitest';
import { localizedUrl } from '../../utils/localizedUrl';
-test('it has no effect if locale matches', () => {
- const url = new URL('https://example.com/en/guide/');
- expect(localizedUrl(url, 'en').href).toBe(url.href);
-});
+describe('with `build.output: "directory"`', () => {
+ test('it has no effect if locale matches', () => {
+ const url = new URL('https://example.com/en/guide/');
+ expect(localizedUrl(url, 'en').href).toBe(url.href);
+ });
-test('it changes locale to requested locale', () => {
- const url = new URL('https://example.com/en/guide/');
- expect(localizedUrl(url, 'ar').href).toBe('https://example.com/ar/guide/');
-});
+ test('it has no effect if locale matches for index', () => {
+ const url = new URL('https://example.com/en/');
+ expect(localizedUrl(url, 'en').href).toBe(url.href);
+ });
+
+ test('it changes locale to requested locale', () => {
+ const url = new URL('https://example.com/en/guide/');
+ expect(localizedUrl(url, 'ar').href).toBe('https://example.com/ar/guide/');
+ });
-test('it can change to root locale', () => {
- const url = new URL('https://example.com/en/guide/');
- expect(localizedUrl(url, undefined).href).toBe('https://example.com/guide/');
+ test('it changes locale to requested locale for index', () => {
+ const url = new URL('https://example.com/en/');
+ expect(localizedUrl(url, 'ar').href).toBe('https://example.com/ar/');
+ });
+
+ test('it can change to root locale', () => {
+ const url = new URL('https://example.com/en/guide/');
+ expect(localizedUrl(url, undefined).href).toBe('https://example.com/guide/');
+ });
+
+ test('it can change from root locale', () => {
+ const url = new URL('https://example.com/guide/');
+ expect(localizedUrl(url, 'en').href).toBe('https://example.com/en/guide/');
+ });
});
-test('it can change from root locale', () => {
- const url = new URL('https://example.com/guide/');
- expect(localizedUrl(url, 'en').href).toBe('https://example.com/en/guide/');
+describe('with `build.output: "file"`', () => {
+ test('it has no effect if locale matches', () => {
+ const url = new URL('https://example.com/en/guide.html');
+ expect(localizedUrl(url, 'en').href).toBe(url.href);
+ });
+
+ test('it has no effect if locale matches for index', () => {
+ const url = new URL('https://example.com/en.html');
+ expect(localizedUrl(url, 'en').href).toBe(url.href);
+ });
+
+ test('it changes locale to requested locale', () => {
+ const url = new URL('https://example.com/en/guide.html');
+ expect(localizedUrl(url, 'ar').href).toBe('https://example.com/ar/guide.html');
+ });
+
+ test('it changes locale to requested locale for index', () => {
+ const url = new URL('https://example.com/en.html');
+ expect(localizedUrl(url, 'ar').href).toBe('https://example.com/ar.html');
+ });
+
+ test('it can change to root locale', () => {
+ const url = new URL('https://example.com/en/guide.html');
+ expect(localizedUrl(url, undefined).href).toBe('https://example.com/guide.html');
+ });
+
+ test('it can change to root locale from index', () => {
+ const url = new URL('https://example.com/en.html');
+ expect(localizedUrl(url, undefined).href).toBe('https://example.com/index.html');
+ });
+
+ test('it can change from root locale', () => {
+ const url = new URL('https://example.com/guide.html');
+ expect(localizedUrl(url, 'en').href).toBe('https://example.com/en/guide.html');
+ });
+
+ test('it can change from root locale from index', () => {
+ const url = new URL('https://example.com/index.html');
+ expect(localizedUrl(url, 'en').href).toBe('https://example.com/en.html');
+ });
});
diff --git a/packages/starlight/__tests__/i18n/localizedUrl.test.ts b/packages/starlight/__tests__/i18n/localizedUrl.test.ts
index 5bdc5e08..fb4ec2d7 100644
--- a/packages/starlight/__tests__/i18n/localizedUrl.test.ts
+++ b/packages/starlight/__tests__/i18n/localizedUrl.test.ts
@@ -1,12 +1,46 @@
-import { expect, test } from 'vitest';
+import { describe, expect, test } from 'vitest';
import { localizedUrl } from '../../utils/localizedUrl';
-test('it has no effect if locale matches', () => {
- const url = new URL('https://example.com/en/guide/');
- expect(localizedUrl(url, 'en').href).toBe(url.href);
+describe('with `build.output: "directory"`', () => {
+ test('it has no effect if locale matches', () => {
+ const url = new URL('https://example.com/en/guide/');
+ expect(localizedUrl(url, 'en').href).toBe(url.href);
+ });
+
+ test('it has no effect if locale matches for index', () => {
+ const url = new URL('https://example.com/en/');
+ expect(localizedUrl(url, 'en').href).toBe(url.href);
+ });
+
+ test('it changes locale to requested locale', () => {
+ const url = new URL('https://example.com/en/guide/');
+ expect(localizedUrl(url, 'fr').href).toBe('https://example.com/fr/guide/');
+ });
+
+ test('it changes locale to requested locale for index', () => {
+ const url = new URL('https://example.com/en/');
+ expect(localizedUrl(url, 'fr').href).toBe('https://example.com/fr/');
+ });
});
-test('it changes locale to requested locale', () => {
- const url = new URL('https://example.com/en/guide/');
- expect(localizedUrl(url, 'fr').href).toBe('https://example.com/fr/guide/');
+describe('with `build.output: "file"`', () => {
+ test('it has no effect if locale matches', () => {
+ const url = new URL('https://example.com/en/guide.html');
+ expect(localizedUrl(url, 'en').href).toBe(url.href);
+ });
+
+ test('it has no effect if locale matches for index', () => {
+ const url = new URL('https://example.com/en.html');
+ expect(localizedUrl(url, 'en').href).toBe(url.href);
+ });
+
+ test('it changes locale to requested locale', () => {
+ const url = new URL('https://example.com/en/guide.html');
+ expect(localizedUrl(url, 'fr').href).toBe('https://example.com/fr/guide.html');
+ });
+
+ test('it changes locale to requested locale for index', () => {
+ const url = new URL('https://example.com/en.html');
+ expect(localizedUrl(url, 'fr').href).toBe('https://example.com/fr.html');
+ });
});
diff --git a/packages/starlight/utils/localizedUrl.ts b/packages/starlight/utils/localizedUrl.ts
index c7e35255..95e35f9d 100644
--- a/packages/starlight/utils/localizedUrl.ts
+++ b/packages/starlight/utils/localizedUrl.ts
@@ -17,14 +17,26 @@ export function localizedUrl(url: URL, locale: string | undefined): URL {
// Temporarily remove base to simplify
if (hasBase) url.pathname = url.pathname.replace(base, '');
const [_leadingSlash, baseSegment] = url.pathname.split('/');
- if (baseSegment && baseSegment in config.locales) {
+ // Strip .html extension to handle file output builds where URL might be e.g. `/en.html`
+ const htmlExt = '.html';
+ const isRootHtml = baseSegment?.endsWith(htmlExt);
+ const baseSlug = isRootHtml ? baseSegment?.slice(0, -1 * htmlExt.length) : baseSegment;
+ if (baseSlug && baseSlug in config.locales) {
// We’re in a localized route, substitute the new locale (or strip for root lang).
- url.pathname = locale
- ? url.pathname.replace(baseSegment, locale)
- : url.pathname.replace('/' + baseSegment, '');
+ if (locale) {
+ url.pathname = url.pathname.replace(baseSlug, locale);
+ } else if (isRootHtml) {
+ url.pathname = '/index.html';
+ } else {
+ url.pathname = url.pathname.replace('/' + baseSlug, '');
+ }
} else if (locale) {
// We’re in the root language. Inject the new locale if we have one.
- url.pathname = '/' + locale + url.pathname;
+ if (baseSegment === 'index.html') {
+ url.pathname = '/' + locale + '.html';
+ } else {
+ url.pathname = '/' + locale + url.pathname;
+ }
}
// Restore base
if (hasBase) url.pathname = base + url.pathname;