From d3ee6fc643de7a320a6bb83432cdcfbb0a4e4289 Mon Sep 17 00:00:00 2001
From: Chris Swithinbank
Date: Tue, 23 May 2023 15:18:26 +0200
Subject: Implement UI string translation using data collections (#78)
---
.changeset/afraid-zoos-retire.md | 16 ++++
.changeset/light-eggs-relax.md | 5 ++
docs/package.json | 2 +-
docs/src/content/config.ts | 7 +-
docs/src/content/docs/guides/i18n.md | 59 ++++++++++++++
examples/basics/package.json | 2 +-
examples/basics/src/content/config.ts | 7 +-
package.json | 2 +-
packages/starlight/404.astro | 4 +-
packages/starlight/components/EditLink.astro | 5 +-
.../components/FallbackContentNotice.astro | 9 ++-
packages/starlight/components/Header.astro | 4 +-
packages/starlight/components/LanguageSelect.astro | 5 +-
packages/starlight/components/LastUpdated.astro | 7 +-
.../starlight/components/MobileMenuToggle.astro | 9 ++-
packages/starlight/components/PrevNextLinks.astro | 9 ++-
packages/starlight/components/RightSidebar.astro | 7 +-
packages/starlight/components/Search.astro | 25 ++++--
packages/starlight/components/Sidebar.astro | 8 +-
packages/starlight/components/SkipLink.astro | 12 ++-
.../starlight/components/TableOfContents.astro | 15 +++-
.../TableOfContents/MobileTableOfContents.astro | 14 +++-
.../TableOfContents/TableOfContentsList.astro | 4 +-
packages/starlight/components/ThemeSelect.astro | 20 +++--
packages/starlight/index.astro | 18 ++---
packages/starlight/layout/PageFrame.astro | 12 ++-
packages/starlight/package.json | 4 +-
packages/starlight/schema.ts | 1 +
packages/starlight/schemas/i18n.ts | 91 ++++++++++++++++++++++
packages/starlight/translations/de.json | 20 +++++
packages/starlight/translations/en.json | 20 +++++
packages/starlight/translations/es.json | 20 +++++
packages/starlight/translations/index.ts | 10 +++
packages/starlight/utils/slugs.ts | 6 +-
packages/starlight/utils/translations.ts | 58 ++++++++++++++
packages/starlight/utils/user-config.ts | 7 +-
pnpm-lock.yaml | 69 ++++++++++++----
37 files changed, 513 insertions(+), 80 deletions(-)
create mode 100644 .changeset/afraid-zoos-retire.md
create mode 100644 .changeset/light-eggs-relax.md
create mode 100644 packages/starlight/schemas/i18n.ts
create mode 100644 packages/starlight/translations/de.json
create mode 100644 packages/starlight/translations/en.json
create mode 100644 packages/starlight/translations/es.json
create mode 100644 packages/starlight/translations/index.ts
create mode 100644 packages/starlight/utils/translations.ts
diff --git a/.changeset/afraid-zoos-retire.md b/.changeset/afraid-zoos-retire.md
new file mode 100644
index 00000000..e2a41c27
--- /dev/null
+++ b/.changeset/afraid-zoos-retire.md
@@ -0,0 +1,16 @@
+---
+'@astrojs/starlight': patch
+---
+
+Add support for customising and translating Starlight’s UI.
+
+Users can provide translations in JSON files in `src/content/i18n/` which is a data collection. For example, a `src/content/i18n/de.json` might translate the search UI:
+
+```json
+{
+ "search.label": "Suchen",
+ "search.shortcutLabel": "(Drücke / zum Suchen)"
+}
+```
+
+This change also allows Starlight to provide built-in support for more languages than just English and adds German & Spanish support.
diff --git a/.changeset/light-eggs-relax.md b/.changeset/light-eggs-relax.md
new file mode 100644
index 00000000..f10a7525
--- /dev/null
+++ b/.changeset/light-eggs-relax.md
@@ -0,0 +1,5 @@
+---
+"@astrojs/starlight": patch
+---
+
+Require a minimum Astro version of 2.5.0
diff --git a/docs/package.json b/docs/package.json
index 312abf25..a5b8663c 100644
--- a/docs/package.json
+++ b/docs/package.json
@@ -15,7 +15,7 @@
},
"dependencies": {
"@astrojs/starlight": "workspace:*",
- "astro": "^2.4.3"
+ "astro": "^2.5.0"
},
"devDependencies": {
"@size-limit/file": "^8.2.4",
diff --git a/docs/src/content/config.ts b/docs/src/content/config.ts
index 4cdd345e..02ea2ac0 100644
--- a/docs/src/content/config.ts
+++ b/docs/src/content/config.ts
@@ -1,8 +1,7 @@
import { defineCollection } from 'astro:content';
-import { docsSchema } from '@astrojs/starlight/schema';
+import { docsSchema, i18nSchema } from '@astrojs/starlight/schema';
export const collections = {
- docs: defineCollection({
- schema: docsSchema(),
- }),
+ docs: defineCollection({ schema: docsSchema() }),
+ i18n: defineCollection({ type: 'data', schema: i18nSchema() }),
};
diff --git a/docs/src/content/docs/guides/i18n.md b/docs/src/content/docs/guides/i18n.md
index 13fe9e3f..eb2afc76 100644
--- a/docs/src/content/docs/guides/i18n.md
+++ b/docs/src/content/docs/guides/i18n.md
@@ -92,8 +92,67 @@ When using a `root` locale, place pages for that language directly in `src/conte
- zh/
- index.md
+#### Monolingual sites
+
+If you have a single language site, you can set the root locale to configure its language.
+This allows you to override Starlight’s default language, which is English, but won’t enable other internationalization features like the language picker.
+
## Fallback content
Starlight expects you to create equivalent pages in all your languages. For example, if you have an `en/about.md` file, you should create an `about.md` for each other language you support.
If a translation is not yet available for a language, Starlight will show readers the content for that page in the default language (set via `defaultLocale`). For example, if you have not yet created a French version of an about page and your default language is English, visitors to `/fr/about` will see the English content. This helps you add content in your default language and then progressively translate it when your translators have time.
+
+## Translate Starlight’s UI
+
+Some of Starlight’s default UI requires text labels to work.
+For example, the table of contents on this page has an “On this page” heading in English.
+We aim to ship these labels in as many languages as possible but currently only have support for English, German, and Spanish.
+
+You can provide translations for additional languages you support — or override our default labels — via the `i18n` data collection.
+
+1. Configure the `i18n` data collection in `src/content/config.ts` if it isn’t configured already:
+
+ ```js
+ import { defineCollection } from 'astro:content';
+ import { docsSchema, i18nSchema } from '@astrojs/starlight/schema';
+
+ export const collections = {
+ docs: defineCollection({ schema: docsSchema() }),
+ i18n: defineCollection({ type: 'data', schema: i18nSchema() }),
+ };
+ ```
+
+2. Create a JSON file in `src/content/i18n/` for each locale you want to translate Starlight’s UI for.
+ For example, this would add translation files for Arabic and Simplified Chinese:
+
+ - src/
+ - content/
+ - i18n/
+ - ar.json
+ - zh-CN.json
+
+3. Add translations for the keys you want to translate to the JSON files. You can use the English defaults to help you translate:
+
+ ```json
+ {
+ "skipLink.label": "Skip to content",
+ "search.label": "Search",
+ "search.shortcutLabel": "(Press / to Search)",
+ "search.cancelLabel": "Cancel",
+ "themeSelect.accessibleLabel": "Select theme",
+ "themeSelect.dark": "Dark",
+ "themeSelect.light": "Light",
+ "themeSelect.auto": "Auto",
+ "languageSelect.accessibleLabel": "Select language",
+ "menuButton.accessibleLabel": "Menu",
+ "sidebarNav.accessibleLabel": "Main",
+ "tableOfContents.onThisPage": "On this page",
+ "tableOfContents.overview": "Overview",
+ "i18n.untranslatedContent": "This content is not available in your language yet.",
+ "page.editLink": "Edit page",
+ "page.lastUpdated": "Last updated:",
+ "page.previousLink": "Next",
+ "page.nextLink": "Previous"
+ }
+ ```
diff --git a/examples/basics/package.json b/examples/basics/package.json
index c5d7a3b9..4700f196 100644
--- a/examples/basics/package.json
+++ b/examples/basics/package.json
@@ -12,6 +12,6 @@
},
"dependencies": {
"@astrojs/starlight": "^0.0.8",
- "astro": "^2.4.1"
+ "astro": "^2.5.0"
}
}
diff --git a/examples/basics/src/content/config.ts b/examples/basics/src/content/config.ts
index 4cdd345e..02ea2ac0 100644
--- a/examples/basics/src/content/config.ts
+++ b/examples/basics/src/content/config.ts
@@ -1,8 +1,7 @@
import { defineCollection } from 'astro:content';
-import { docsSchema } from '@astrojs/starlight/schema';
+import { docsSchema, i18nSchema } from '@astrojs/starlight/schema';
export const collections = {
- docs: defineCollection({
- schema: docsSchema(),
- }),
+ docs: defineCollection({ schema: docsSchema() }),
+ i18n: defineCollection({ type: 'data', schema: i18nSchema() }),
};
diff --git a/package.json b/package.json
index f4cb8e31..ef3d5816 100644
--- a/package.json
+++ b/package.json
@@ -8,7 +8,7 @@
"devDependencies": {
"@changesets/changelog-github": "^0.4.8",
"@changesets/cli": "^2.26.1",
- "astro": "^2.4.3"
+ "astro": "^2.5.0"
},
"packageManager": "pnpm@8.2.0"
}
diff --git a/packages/starlight/404.astro b/packages/starlight/404.astro
index de897a79..00d0cab0 100644
--- a/packages/starlight/404.astro
+++ b/packages/starlight/404.astro
@@ -30,8 +30,8 @@ const { lang = 'en', dir = 'ltr', locale } = config.defaultLocale || {};
-
-
+
+
404
diff --git a/packages/starlight/components/EditLink.astro b/packages/starlight/components/EditLink.astro
index 833be123..c72c25ac 100644
--- a/packages/starlight/components/EditLink.astro
+++ b/packages/starlight/components/EditLink.astro
@@ -1,12 +1,15 @@
---
import type { CollectionEntry } from 'astro:content';
import config from 'virtual:starlight/user-config';
+import { useTranslations } from '../utils/translations';
interface Props {
data: CollectionEntry<'docs'>['data'];
id: CollectionEntry<'docs'>['id'];
+ locale: string | undefined;
}
+const t = useTranslations(Astro.props.locale);
const { editUrl } = Astro.props.data;
let { baseUrl } = config.editLink;
@@ -20,4 +23,4 @@ const url =
: undefined;
---
-{editUrl !== false && url && Edit this page}
+{editUrl !== false && url && {t('page.editLink')}}
diff --git a/packages/starlight/components/FallbackContentNotice.astro b/packages/starlight/components/FallbackContentNotice.astro
index fc05938d..0faf151b 100644
--- a/packages/starlight/components/FallbackContentNotice.astro
+++ b/packages/starlight/components/FallbackContentNotice.astro
@@ -1,5 +1,12 @@
---
+import { useTranslations } from '../utils/translations';
import Icon from './Icon.astro';
+
+interface Props {
+ locale: string | undefined;
+}
+
+const t = useTranslations(Astro.props.locale);
---
@@ -7,7 +14,7 @@ import Icon from './Icon.astro';
name={'warning'}
size="1.5em"
color="var(--sl-color-orange-high)"
- />This content is not available in your language yet.
+ />{t('i18n.untranslatedContent')}