From e5a863a98b2e5335e122ca440dcb84e9426939b4 Mon Sep 17 00:00:00 2001 From: Chris Swithinbank Date: Wed, 29 Nov 2023 20:25:09 +0100 Subject: Expose localized UI strings in route data (#1135) --- .changeset/pink-mirrors-cough.md | 7 +++++ docs/src/content/docs/reference/overrides.md | 6 ++++ packages/starlight/404.astro | 2 +- .../starlight/__tests__/basics/route-data.test.ts | 10 +++++++ .../starlight/__tests__/i18n/route-data.test.ts | 32 ++++++++++++++++++++++ .../starlight/__tests__/i18n/translations.test.ts | 8 ------ packages/starlight/components/EditLink.astro | 6 ++-- .../components/FallbackContentNotice.astro | 5 ++-- packages/starlight/components/LanguageSelect.astro | 5 ++-- packages/starlight/components/LastUpdated.astro | 6 ++-- .../starlight/components/MobileMenuToggle.astro | 6 ++-- .../components/MobileTableOfContents.astro | 6 ++-- packages/starlight/components/PageFrame.astro | 9 ++---- packages/starlight/components/Pagination.astro | 8 ++---- packages/starlight/components/Search.astro | 26 +++++++++++------- packages/starlight/components/SkipLink.astro | 5 ++-- .../starlight/components/TableOfContents.astro | 6 ++-- packages/starlight/components/ThemeSelect.astro | 11 ++++---- .../starlight/utils/createTranslationSystem.ts | 11 ++++++-- packages/starlight/utils/route-data.ts | 3 ++ 20 files changed, 110 insertions(+), 68 deletions(-) create mode 100644 .changeset/pink-mirrors-cough.md create mode 100644 packages/starlight/__tests__/i18n/route-data.test.ts diff --git a/.changeset/pink-mirrors-cough.md b/.changeset/pink-mirrors-cough.md new file mode 100644 index 00000000..c43df8ed --- /dev/null +++ b/.changeset/pink-mirrors-cough.md @@ -0,0 +1,7 @@ +--- +'@astrojs/starlight': minor +--- + +Exposes localized UI strings in route data + +Component overrides can now access a `labels` object in their props which includes all the localized UI strings for the current page. \ No newline at end of file diff --git a/docs/src/content/docs/reference/overrides.md b/docs/src/content/docs/reference/overrides.md index 387e485d..9bd6cc9c 100644 --- a/docs/src/content/docs/reference/overrides.md +++ b/docs/src/content/docs/reference/overrides.md @@ -135,6 +135,12 @@ JavaScript `Date` object representing when this page was last updated if enabled `URL` object for the address where this page can be edited if enabled. +#### `labels` + +**Type:** `Record` + +An object containing UI strings localized for the current page. See the [“Translate Starlight’s UI”](/guides/i18n/#translate-starlights-ui) guide for a list of all the available keys. + --- ## Components diff --git a/packages/starlight/404.astro b/packages/starlight/404.astro index 913c5143..61358234 100644 --- a/packages/starlight/404.astro +++ b/packages/starlight/404.astro @@ -26,7 +26,7 @@ const fallbackEntry: StarlightDocsEntry = { head: [], hero: { tagline: t('404.text'), actions: [] }, pagefind: false, - sidebar: { hidden: false }, + sidebar: { hidden: false, attrs: {} }, }, render: async () => ({ Content: EmptyContent, diff --git a/packages/starlight/__tests__/basics/route-data.test.ts b/packages/starlight/__tests__/basics/route-data.test.ts index 13522d02..eacd5334 100644 --- a/packages/starlight/__tests__/basics/route-data.test.ts +++ b/packages/starlight/__tests__/basics/route-data.test.ts @@ -85,3 +85,13 @@ test('uses explicit last updated date from frontmatter', () => { expect(data.lastUpdated).toBeInstanceOf(Date); expect(data.lastUpdated).toEqual(route.entry.data.lastUpdated); }); + +test('includes localized labels', () => { + const route = routes[0]!; + const data = generateRouteData({ + props: { ...route, headings: [{ depth: 1, slug: 'heading-1', text: 'Heading 1' }] }, + url: new URL('https://example.com'), + }); + expect(data.labels).toBeDefined(); + expect(data.labels['skipLink.label']).toBe('Skip to content'); +}); diff --git a/packages/starlight/__tests__/i18n/route-data.test.ts b/packages/starlight/__tests__/i18n/route-data.test.ts new file mode 100644 index 00000000..57beed0c --- /dev/null +++ b/packages/starlight/__tests__/i18n/route-data.test.ts @@ -0,0 +1,32 @@ +import { expect, test, vi } from 'vitest'; +import { generateRouteData } from '../../utils/route-data'; +import { routes } from '../../utils/routing'; + +vi.mock('astro:content', async () => + (await import('../test-utils')).mockedAstroContent({ + docs: [ + ['fr/index.mdx', { title: 'Accueil' }], + ['pt-br/index.mdx', { title: 'Pagina inicial' }], + ], + }) +); + +test('includes localized labels (fr)', () => { + const route = routes[0]!; + const data = generateRouteData({ + props: { ...route, headings: [{ depth: 1, slug: 'heading-1', text: 'Heading 1' }] }, + url: new URL('https://example.com'), + }); + expect(data.labels).toBeDefined(); + expect(data.labels['skipLink.label']).toBe('Aller au contenu'); +}); + +test('includes localized labels (pt-br)', () => { + const route = routes[1]!; + const data = generateRouteData({ + props: { ...route, headings: [{ depth: 1, slug: 'heading-1', text: 'Heading 1' }] }, + url: new URL('https://example.com'), + }); + expect(data.labels).toBeDefined(); + expect(data.labels['skipLink.label']).toBe('Pular para o conteúdo'); +}); diff --git a/packages/starlight/__tests__/i18n/translations.test.ts b/packages/starlight/__tests__/i18n/translations.test.ts index a8442166..1e9fd032 100644 --- a/packages/starlight/__tests__/i18n/translations.test.ts +++ b/packages/starlight/__tests__/i18n/translations.test.ts @@ -22,14 +22,6 @@ describe('useTranslations()', () => { expect(t('page.editLink')).toBe(translations.en?.['page.editLink']); }); - test('returns a pick method for filtering by key', () => { - const t = useTranslations('en'); - expect(t.pick('tableOfContents.')).toEqual({ - 'tableOfContents.onThisPage': 'On this page', - 'tableOfContents.overview': 'Overview', - }); - }); - test('uses built-in translations for regional variants', () => { const t = useTranslations('pt-br'); expect(t('page.nextLink')).toBe(translations.pt?.['page.nextLink']); diff --git a/packages/starlight/components/EditLink.astro b/packages/starlight/components/EditLink.astro index f5f5f65b..74be4c8f 100644 --- a/packages/starlight/components/EditLink.astro +++ b/packages/starlight/components/EditLink.astro @@ -1,17 +1,15 @@ --- import Icon from '../user-components/Icon.astro'; import type { Props } from '../props'; -import { useTranslations } from '../utils/translations'; -const t = useTranslations(Astro.props.locale); -const { editUrl } = Astro.props; +const { editUrl, labels } = Astro.props; --- { editUrl && ( - {t('page.editLink')} + {labels['page.editLink']} ) } diff --git a/packages/starlight/components/FallbackContentNotice.astro b/packages/starlight/components/FallbackContentNotice.astro index 171eeb15..44d553a4 100644 --- a/packages/starlight/components/FallbackContentNotice.astro +++ b/packages/starlight/components/FallbackContentNotice.astro @@ -1,14 +1,13 @@ --- import Icon from '../user-components/Icon.astro'; import type { Props } from '../props'; -import { useTranslations } from '../utils/translations'; -const t = useTranslations(Astro.props.locale); +const { labels } = Astro.props; ---

{t('i18n.untranslatedContent')}{labels['i18n.untranslatedContent']}

diff --git a/packages/starlight/components/LanguageSelect.astro b/packages/starlight/components/LanguageSelect.astro index 077935b3..c85292dc 100644 --- a/packages/starlight/components/LanguageSelect.astro +++ b/packages/starlight/components/LanguageSelect.astro @@ -1,7 +1,6 @@ --- import config from 'virtual:starlight/user-config'; import { localizedUrl } from '../utils/localizedUrl'; -import { useTranslations } from '../utils/translations'; import Select from './Select.astro'; import type { Props } from '../props'; @@ -12,7 +11,7 @@ function localizedPathname(locale: string | undefined): string { return localizedUrl(Astro.url, locale).pathname; } -const t = useTranslations(Astro.props.locale); +const { labels } = Astro.props; --- { @@ -20,7 +19,7 @@ const t = useTranslations(Astro.props.locale); diff --git a/packages/starlight/utils/createTranslationSystem.ts b/packages/starlight/utils/createTranslationSystem.ts index 188b176c..9f2a5bf3 100644 --- a/packages/starlight/utils/createTranslationSystem.ts +++ b/packages/starlight/utils/createTranslationSystem.ts @@ -19,10 +19,16 @@ export function createTranslationSystem( /** * Generate a utility function that returns UI strings for the given `locale`. + * + * Also includes an `all()` method for getting the entire dictionary. + * * @param {string | undefined} [locale] * @example * const t = useTranslations('en'); - * const label = t('search.label'); // => 'Search' + * const label = t('search.label'); + * // => 'Search' + * const dictionary = t.all(); + * // => { 'skipLink.label': 'Skip to content', 'search.label': 'Search', ... } */ return function useTranslations(locale: string | undefined) { const lang = localeToLang(locale, config.locales, config.defaultLocale); @@ -32,8 +38,7 @@ export function createTranslationSystem( userTranslations[lang] ); const t = (key: K) => dictionary[key]; - t.pick = (startOfKey: string) => - Object.fromEntries(Object.entries(dictionary).filter(([k]) => k.startsWith(startOfKey))); + t.all = () => dictionary; return t; }; } diff --git a/packages/starlight/utils/route-data.ts b/packages/starlight/utils/route-data.ts index 966f780e..484fea08 100644 --- a/packages/starlight/utils/route-data.ts +++ b/packages/starlight/utils/route-data.ts @@ -29,6 +29,8 @@ export interface StarlightRouteData extends Route { lastUpdated: Date | undefined; /** URL object for the address where this page can be edited if enabled. */ editUrl: URL | undefined; + /** Record of UI strings localized for the current page. */ + labels: ReturnType['all']>; } export function generateRouteData({ @@ -48,6 +50,7 @@ export function generateRouteData({ toc: getToC(props), lastUpdated: getLastUpdated(props), editUrl: getEditUrl(props), + labels: useTranslations(locale).all(), }; } -- cgit