summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Swithinbank2023-05-28 22:11:05 +0200
committerGitHub2023-05-28 22:11:05 +0200
commitde24b54971577912979a3fb67570f4c95efe27a6 (patch)
tree86be98c39cfe7b7fb0bd2b9e76ded40232dbf9c2
parentfe1c489a41a48eceed3cf559374d07d67c325248 (diff)
downloadIT.starlight-de24b54971577912979a3fb67570f4c95efe27a6.tar.gz
IT.starlight-de24b54971577912979a3fb67570f4c95efe27a6.tar.bz2
IT.starlight-de24b54971577912979a3fb67570f4c95efe27a6.zip
Support translations in sidebar config (#95)
-rw-r--r--.changeset/calm-buttons-wink.md5
-rw-r--r--docs/astro.config.mjs26
-rw-r--r--docs/src/content/docs/reference/configuration.md36
-rw-r--r--packages/starlight/utils/i18n.ts16
-rw-r--r--packages/starlight/utils/navigation.ts10
-rw-r--r--packages/starlight/utils/user-config.ts44
6 files changed, 96 insertions, 41 deletions
diff --git a/.changeset/calm-buttons-wink.md b/.changeset/calm-buttons-wink.md
new file mode 100644
index 00000000..22be7e42
--- /dev/null
+++ b/.changeset/calm-buttons-wink.md
@@ -0,0 +1,5 @@
+---
+"@astrojs/starlight": patch
+---
+
+Support translations in sidebar config
diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs
index c81072e1..b64d8383 100644
--- a/docs/astro.config.mjs
+++ b/docs/astro.config.mjs
@@ -30,22 +30,14 @@ export default defineConfig({
},
],
locales: {
- root: {
- label: 'English',
- lang: 'en',
- },
- de: {
- label: 'Deutsch',
- lang: 'de',
- },
- es: {
- label: 'Español',
- lang: 'es',
- }
+ root: { label: 'English', lang: 'en' },
+ de: { label: 'Deutsch', lang: 'de' },
+ es: { label: 'Español', lang: 'es' },
},
sidebar: [
{
label: 'Start Here',
+ translations: { de: 'Beginne hier', es: 'Comienza aqui' },
items: [
{ label: 'Welcome, world', link: '/' },
{ label: 'Getting Started', link: 'getting-started' },
@@ -54,15 +46,13 @@ export default defineConfig({
},
{
label: 'Guides',
- autogenerate: {
- directory: 'guides',
- },
+ translations: { de: 'Anleitungen', es: 'Guías' },
+ autogenerate: { directory: 'guides' },
},
{
label: 'Reference',
- autogenerate: {
- directory: 'reference',
- },
+ translations: { de: 'Referenz', es: 'Referencias' },
+ autogenerate: { directory: 'reference' },
},
],
}),
diff --git a/docs/src/content/docs/reference/configuration.md b/docs/src/content/docs/reference/configuration.md
index 06381c86..4413311d 100644
--- a/docs/src/content/docs/reference/configuration.md
+++ b/docs/src/content/docs/reference/configuration.md
@@ -89,18 +89,42 @@ starlight({
// A group linking to all pages in the reference directory.
{
label: 'Reference',
- autogenerate: {
- directory: 'reference',
- },
+ autogenerate: { directory: 'reference' },
},
],
});
```
-:::note[Sorting]
+#### Sorting
+
Autogenerated sidebar groups are sorted by filename alphabetically.
For example, a page generated from `astro.md` would appear above the page for `starlight.md`.
-:::
+
+#### Translating labels
+
+If your site is multilingual, each item’s `label` is considered to be in the default locale. You can set a `translations` property to provide labels for your other supported languages:
+
+```js
+sidebar: [
+ // An example sidebar with labels translated to French.
+ {
+ label: 'Start Here',
+ translations: { fr: 'Commencez ici' },
+ items: [
+ {
+ label: 'Getting Started',
+ translations: { fr: 'Bien démarrer' },
+ link: '/getting-started',
+ },
+ {
+ label: 'Project Structure',
+ translations: { fr: 'Structure du projet' },
+ link: '/structure',
+ },
+ ],
+ },
+];
+```
#### `SidebarGroup`
@@ -108,10 +132,12 @@ For example, a page generated from `astro.md` would appear above the page for `s
type SidebarGroup =
| {
label: string;
+ translations?: Record<string, string>;
items: Array<LinkItem | SidebarGroup>;
}
| {
label: string;
+ translations?: Record<string, string>;
autogenerate: {
directory: string;
};
diff --git a/packages/starlight/utils/i18n.ts b/packages/starlight/utils/i18n.ts
new file mode 100644
index 00000000..2dd43c3b
--- /dev/null
+++ b/packages/starlight/utils/i18n.ts
@@ -0,0 +1,16 @@
+/**
+ * Get the string for the passed language from a dictionary object.
+ *
+ * TODO: Make this clever. Currently a simple key look-up, but should use
+ * BCP-47 mapping so that e.g. `en-US` returns `en` strings, and use the
+ * site’s default locale as a last resort.
+ *
+ * @example
+ * pickLang({ en: 'Hello', fr: 'Bonjour' }, 'en'); // => 'Hello'
+ */
+export function pickLang<T extends Record<string, string>>(
+ dictionary: T,
+ lang: keyof T
+): string | undefined {
+ return dictionary[lang];
+}
diff --git a/packages/starlight/utils/navigation.ts b/packages/starlight/utils/navigation.ts
index e7e6a91e..bcdf79cf 100644
--- a/packages/starlight/utils/navigation.ts
+++ b/packages/starlight/utils/navigation.ts
@@ -1,8 +1,9 @@
import { basename, dirname } from 'node:path';
import config from 'virtual:starlight/user-config';
import { withBase } from './base';
+import { pickLang } from './i18n';
import { Route, getLocaleRoutes, routes } from './routing';
-import { slugToPathname } from './slugs';
+import { localeToLang, slugToPathname } from './slugs';
import type {
AutoSidebarGroup,
SidebarItem,
@@ -48,7 +49,7 @@ function configItemToEntry(
} else {
return {
type: 'group',
- label: item.label,
+ label: pickLang(item.translations, localeToLang(locale)) || item.label,
entries: item.items.map((i) =>
configItemToEntry(i, currentPathname, locale, routes)
),
@@ -75,7 +76,7 @@ function groupFromAutogenerateConfig(
const tree = treeify(dirDocs, localeDir);
return {
type: 'group',
- label: item.label,
+ label: pickLang(item.translations, localeToLang(locale)) || item.label,
entries: sidebarFromDir(tree, currentPathname, locale),
};
}
@@ -102,7 +103,8 @@ function linkFromConfig(
// Inject current locale into link.
if (locale) href = '/' + locale + href;
}
- return makeLink(href, item.label, currentPathname);
+ const label = pickLang(item.translations, localeToLang(locale)) || item.label;
+ return makeLink(href, label, currentPathname);
}
/** Create a link entry. */
diff --git a/packages/starlight/utils/user-config.ts b/packages/starlight/utils/user-config.ts
index 9aea7325..bca6cfff 100644
--- a/packages/starlight/utils/user-config.ts
+++ b/packages/starlight/utils/user-config.ts
@@ -27,17 +27,20 @@ const LocaleSchema = z.object({
),
});
-const SidebarLinkItemSchema = z.object({
+const SidebarBaseSchema = z.object({
/** The visible label for this item in the sidebar. */
label: z.string(),
+ /** Translations of the `label` for each supported language. */
+ translations: z.record(z.string()).default({}),
+});
+
+const SidebarLinkItemSchema = SidebarBaseSchema.extend({
/** The link to this item’s content. Can be a relative link to local files or the full URL of an external page. */
link: z.string(),
});
export type SidebarLinkItem = z.infer<typeof SidebarLinkItemSchema>;
-const AutoSidebarGroupSchema = z.object({
- /** The visible label for this item in the sidebar. */
- label: z.string(),
+const AutoSidebarGroupSchema = SidebarBaseSchema.extend({
/** Enable autogenerating a sidebar category from a specific docs directory. */
autogenerate: z.object({
/** The directory to generate sidebar items for. */
@@ -49,20 +52,29 @@ const AutoSidebarGroupSchema = z.object({
});
export type AutoSidebarGroup = z.infer<typeof AutoSidebarGroupSchema>;
-type ManualSidebarGroup = {
- /** The visible label for this item in the sidebar. */
- label: string;
+type ManualSidebarGroupInput = z.input<typeof SidebarBaseSchema> & {
/** Array of links and subcategories to display in this category. */
items: Array<
- | SidebarLinkItem
- | z.infer<typeof AutoSidebarGroupSchema>
- | ManualSidebarGroup
+ | z.input<typeof SidebarLinkItemSchema>
+ | z.input<typeof AutoSidebarGroupSchema>
+ | ManualSidebarGroupInput
>;
};
-const ManualSidebarGroupSchema: z.ZodType<ManualSidebarGroup> = z.object({
- /** The visible label for this item in the sidebar. */
- label: z.string(),
+type ManualSidebarGroupOutput = z.output<typeof SidebarBaseSchema> & {
+ /** Array of links and subcategories to display in this category. */
+ items: Array<
+ | z.output<typeof SidebarLinkItemSchema>
+ | z.output<typeof AutoSidebarGroupSchema>
+ | ManualSidebarGroupOutput
+ >;
+};
+
+const ManualSidebarGroupSchema: z.ZodType<
+ ManualSidebarGroupOutput,
+ z.ZodTypeDef,
+ ManualSidebarGroupInput
+> = SidebarBaseSchema.extend({
/** Array of links and subcategories to display in this category. */
items: z.lazy(() =>
z
@@ -83,7 +95,11 @@ const SidebarItemSchema = z.union([
export type SidebarItem = z.infer<typeof SidebarItemSchema>;
const SidebarGroupSchema: z.ZodType<
- ManualSidebarGroup | z.infer<typeof AutoSidebarGroupSchema>
+ | z.output<typeof ManualSidebarGroupSchema>
+ | z.output<typeof AutoSidebarGroupSchema>,
+ z.ZodTypeDef,
+ | z.input<typeof ManualSidebarGroupSchema>
+ | z.input<typeof AutoSidebarGroupSchema>
> = z.union([ManualSidebarGroupSchema, AutoSidebarGroupSchema]);
const UserConfigSchema = z.object({