diff --git a/docs/src/content/docs/zh/getting-started.mdx b/docs/src/content/docs/zh/getting-started.mdx index 486fde140e1..235066371cd 100644 --- a/docs/src/content/docs/zh/getting-started.mdx +++ b/docs/src/content/docs/zh/getting-started.mdx @@ -88,7 +88,7 @@ description: This is a page in my Starlight-powered site ## 更新 Starlight -:::tip[提示] +:::tip 由于 Starlight 是 beta 软件,所以会经常更新和改进。请务必定期更新 Starlight! ::: diff --git a/packages/starlight/integrations/asides.ts b/packages/starlight/integrations/asides.ts index 3af3b6715fb..d78f504abfd 100644 --- a/packages/starlight/integrations/asides.ts +++ b/packages/starlight/integrations/asides.ts @@ -5,6 +5,63 @@ import remarkDirective from 'remark-directive'; import type { Plugin, Transformer } from 'unified'; import { remove } from 'unist-util-remove'; import { visit } from 'unist-util-visit'; +import builtinTranslations from '../translations'; +import type { StarlightConfig } from '../types'; + + +/** Build a dictionary by layering preferred translation sources. */ +function buildDictionary( + base: (typeof builtinTranslations)[string], + ...dictionaries: (CollectionEntry<'i18n'>['data'] | undefined)[] +) { + const dictionary = { ...base }; + // Iterate over alternate dictionaries to avoid overwriting preceding values with `undefined`. + for (const dict of dictionaries) { + for (const key in dict) { + const value = dict[key as keyof typeof dict]; + if (value) dictionary[key as keyof typeof dict] = value; + } + } + return dictionary; +} + +// TODO get defaultLocale +const defaultLocale = 'root'; + +/** All translation data from the i18n collection, keyed by `id`, which matches locale. */ +let userTranslations = {}; +try { + // Load the user’s i18n collection and ignore the error if it doesn’t exist. + // TODO How to get user i18n collection +} catch {} + +/** Default map of UI strings based on Starlight and user-configured defaults. */ +const defaults = buildDictionary( + builtinTranslations.en!, + userTranslations.en, + builtinTranslations[defaultLocale], + userTranslations[defaultLocale] +); + +function localeToLang(locale: string | undefined): string { + return 'zh'; +} + +/** + * Generate a utility function that returns UI strings for the given `locale`. + * @param {string | undefined} [locale] + * @example + * const t = useTranslations('en'); + * const label = t('search.label'); // => 'Search' + */ +export function useTranslations(locale: string | undefined) { + const lang = localeToLang(locale); + const dictionary = buildDictionary(defaults, builtinTranslations[lang], userTranslations[lang]); + const t = (key: K) => dictionary[key]; + t.pick = (startOfKey: string) => + Object.fromEntries(Object.entries(dictionary).filter(([k]) => k.startsWith(startOfKey))); + return t; +} /** Hacky function that generates an mdast HTML tree ready for conversion to HTML by rehype. */ function h(el: string, attrs: Properties = {}, children: any[] = []): P { @@ -54,14 +111,9 @@ function remarkAsides(): Plugin<[], Root> { type Variant = 'note' | 'tip' | 'caution' | 'danger'; const variants = new Set(['note', 'tip', 'caution', 'danger']); const isAsideVariant = (s: string): s is Variant => variants.has(s); - - // TODO: hook these up for i18n once the design for translating strings is ready - const defaultTitles = { - note: 'Note', - tip: 'Tip', - caution: 'Caution', - danger: 'Danger', - }; + // TODO how to get current locale + const locale = 'en'; + const t = useTranslations(locale); const iconPaths = { // Information icon @@ -96,18 +148,19 @@ function remarkAsides(): Plugin<[], Root> { }; const transformer: Transformer = (tree) => { + + // console.log('Astro.props', Astro.props); visit(tree, (node, index, parent) => { if (!parent || index === null || node.type !== 'containerDirective') { return; } const variant = node.name; if (!isAsideVariant(variant)) return; - // remark-directive converts a container’s “label” to a paragraph in // its children, but we want to pass it as the title prop to