Repository: withastro/starlight (2025-07-16T10:58:07Z)

Issue:
The default locale `root` is not present in the `i18n.locales` array.
### What version of `starlight` are you using?

0.34.7

### What version of `astro` are you using?

5.11.1

### What package manager are you using?

bun

### What operating system are you using?

Mac

### What browser are you using?

Chrome, Firefox, Safari

### Describe the Bug

From Starlight 0.34.5 onwards, the following i18n config throws an error:

```
17:56:01 [ERROR] [@astrojs/starlight] An error occurred while updating the config
17:56:01 [ERROR] [config] The default locale `root` is not present in the `i18n.locales` array.
  Stack trace:
    at /Users/huijing/Sites/root-locale/node_modules/zod/v3/types.js:39:31
    [...] See full stack trace in the browser, or rerun with --verbose.
```

Downgrading to 0.34.4 resolves the issue.
Unclear if it was related to changes made in https://github.com/withastro/starlight/pull/3288

### Link to Minimal Reproducible Example

https://idx.google.com/root-locale-79481169

### Participation

- [ ] I am willing to submit a pull request for this issue.


Discussion:
Thanks for the issue @huijing! IDX workspaces aren’t public I don’t think? I’m not able to access the reproduction. Could you share it as a GitHub repo or StackBlitz maybe?



Patch:
diff --git a/.changeset/early-kings-fly.md b/.changeset/early-kings-fly.md
new file mode 100644
index 00000000000..ec0178a6257
--- /dev/null
+++ b/.changeset/early-kings-fly.md
@@ -0,0 +1,5 @@
+---
+'@astrojs/starlight': patch
+---
+
+Fixes a regression in Starlight version `0.34.5` that caused multilingual sites with a default locale explicitly set to `root` to report a configuration error.
diff --git a/packages/starlight/utils/i18n.ts b/packages/starlight/utils/i18n.ts
index 4b23c0a5eb2..c212c7bf13c 100644
--- a/packages/starlight/utils/i18n.ts
+++ b/packages/starlight/utils/i18n.ts
@@ -57,7 +57,10 @@ function getAstroI18nConfig(config: StarlightConfig): NonNullable<AstroConfig['i
 		// In Starlight, this matches the `locale` property if defined, and we fallback to the `lang`
 		// property if not (which would be set to the language’s directory name by default).
 		defaultLocale:
-			config.defaultLocale.locale ?? config.defaultLocale.lang ?? BuiltInDefaultLocale.lang,
+			// If the default locale is explicitly set to `root`, we use the `lang` property instead.
+			(config.defaultLocale.locale === 'root'
+				? config.defaultLocale.lang
+				: (config.defaultLocale.locale ?? config.defaultLocale.lang)) ?? BuiltInDefaultLocale.lang,
 		locales: config.locales
 			? Object.entries(config.locales).map(([locale, localeConfig]) => {
 					return {


Test patch:
diff --git a/packages/starlight/__tests__/i18n-root-default-locale/i18n.test.ts b/packages/starlight/__tests__/i18n-root-default-locale/i18n.test.ts
new file mode 100644
index 00000000000..fb48dcf4afc
--- /dev/null
+++ b/packages/starlight/__tests__/i18n-root-default-locale/i18n.test.ts
@@ -0,0 +1,39 @@
+import { assert, describe, expect, test } from 'vitest';
+import config from 'virtual:starlight/user-config';
+import { processI18nConfig } from '../../utils/i18n';
+
+describe('processI18nConfig', () => {
+	test('returns Astro i18n config for a multilingual site with a root default locale', () => {
+		const { astroI18nConfig, starlightConfig } = processI18nConfig(config, undefined);
+
+		// The default locale matches the root locale's `lang` property.
+		expect(astroI18nConfig.defaultLocale).toBe('fr');
+		expect(astroI18nConfig.locales).toMatchInlineSnapshot(`
+			[
+			  {
+			    "codes": [
+			      "fr",
+			    ],
+			    "path": "fr",
+			  },
+			  {
+			    "codes": [
+			      "en-US",
+			    ],
+			    "path": "en",
+			  },
+			  {
+			    "codes": [
+			      "ar",
+			    ],
+			    "path": "ar",
+			  },
+			]
+		`);
+		assert(typeof astroI18nConfig.routing !== 'string');
+		expect(astroI18nConfig.routing?.prefixDefaultLocale).toBe(false);
+
+		// The Starlight configuration should not be modified.
+		expect(config).toStrictEqual(starlightConfig);
+	});
+});
diff --git a/packages/starlight/__tests__/i18n-root-default-locale/vitest.config.ts b/packages/starlight/__tests__/i18n-root-default-locale/vitest.config.ts
new file mode 100644
index 00000000000..a677045a41c
--- /dev/null
+++ b/packages/starlight/__tests__/i18n-root-default-locale/vitest.config.ts
@@ -0,0 +1,11 @@
+import { defineVitestConfig } from '../test-config';
+
+export default defineVitestConfig({
+	title: 'i18n with root default locale',
+	defaultLocale: 'root',
+	locales: {
+		root: { label: 'French', lang: 'fr' },
+		en: { label: 'English', lang: 'en-US' },
+		ar: { label: 'Arabic', dir: 'rtl' },
+	},
+});