From e7b0e742dffb7c4a8f4619297e4bd6e5a8015edb Mon Sep 17 00:00:00 2001 From: HiDeoo Date: Tue, 7 Jan 2025 15:35:33 +0100 Subject: Fix translation issue for languages with a region subtag (#2757) Co-authored-by: Chris Swithinbank --- .changeset/brave-kings-vanish.md | 5 +++++ packages/starlight/__tests__/test-utils.ts | 3 ++- packages/starlight/utils/navigation.ts | 13 ++++++------- packages/starlight/utils/path.ts | 6 ++++++ packages/starlight/utils/translations.ts | 15 +++++++++++++-- packages/starlight/virtual-internal.d.ts | 13 ------------- packages/starlight/virtual.d.ts | 15 +++++++++++++++ 7 files changed, 47 insertions(+), 23 deletions(-) create mode 100644 .changeset/brave-kings-vanish.md diff --git a/.changeset/brave-kings-vanish.md b/.changeset/brave-kings-vanish.md new file mode 100644 index 00000000..22a63b76 --- /dev/null +++ b/.changeset/brave-kings-vanish.md @@ -0,0 +1,5 @@ +--- +'@astrojs/starlight': patch +--- + +Fixes a UI string translation issue for languages with a region subtag. diff --git a/packages/starlight/__tests__/test-utils.ts b/packages/starlight/__tests__/test-utils.ts index d6e3a711..12ebc804 100644 --- a/packages/starlight/__tests__/test-utils.ts +++ b/packages/starlight/__tests__/test-utils.ts @@ -52,8 +52,9 @@ function mockDoc( function mockDict(id: string, data: z.input>) { return { - id, + id: project.legacyCollections ? id : id.toLocaleLowerCase(), data: i18nSchema().parse(data), + filePath: project.legacyCollections ? undefined : `src/content/i18n/${id}.yml`, }; } diff --git a/packages/starlight/utils/navigation.ts b/packages/starlight/utils/navigation.ts index 0944eb5d..37184627 100644 --- a/packages/starlight/utils/navigation.ts +++ b/packages/starlight/utils/navigation.ts @@ -13,7 +13,12 @@ import type { import { createPathFormatter } from './createPathFormatter'; import { formatPath } from './format-path'; import { BuiltInDefaultLocale, pickLang } from './i18n'; -import { ensureLeadingSlash, ensureTrailingSlash, stripLeadingAndTrailingSlashes } from './path'; +import { + ensureLeadingSlash, + ensureTrailingSlash, + stripExtension, + stripLeadingAndTrailingSlashes, +} from './path'; import { getLocaleRoutes, routes, type Route } from './routing'; import { localeToLang, localizedId, slugToPathname } from './slugs'; import type { StarlightConfig } from './user-config'; @@ -510,12 +515,6 @@ function applyPrevNextLinkConfig( return paginationEnabled ? link : undefined; } -/** Remove the extension from a path. */ -function stripExtension(path: string) { - const periodIndex = path.lastIndexOf('.'); - return path.slice(0, periodIndex > -1 ? periodIndex : undefined); -} - /** Get a sidebar badge for a given item. */ function getSidebarBadge( config: I18nBadgeConfig, diff --git a/packages/starlight/utils/path.ts b/packages/starlight/utils/path.ts index 68b1f5c2..cf30d038 100644 --- a/packages/starlight/utils/path.ts +++ b/packages/starlight/utils/path.ts @@ -50,3 +50,9 @@ export function ensureHtmlExtension(path: string) { } return ensureLeadingSlash(path); } + +/** Remove the extension from a path. */ +export function stripExtension(path: string) { + const periodIndex = path.lastIndexOf('.'); + return path.slice(0, periodIndex > -1 ? periodIndex : undefined); +} diff --git a/packages/starlight/utils/translations.ts b/packages/starlight/utils/translations.ts index 499ded29..71ce6e72 100644 --- a/packages/starlight/utils/translations.ts +++ b/packages/starlight/utils/translations.ts @@ -1,15 +1,20 @@ import { getCollection, type CollectionEntry, type DataCollectionKey } from 'astro:content'; import config from 'virtual:starlight/user-config'; +import project from 'virtual:starlight/project-context'; import pluginTranslations from 'virtual:starlight/plugin-translations'; import type { i18nSchemaOutput } from '../schemas/i18n'; import { createTranslationSystem } from './createTranslationSystem'; import type { RemoveIndexSignature } from './types'; +import { getCollectionPathFromRoot } from './collection'; +import { stripExtension, stripLeadingSlash } from './path'; // @ts-ignore - This may be a type error in projects without an i18n collection and running // `tsc --noEmit` in their project. Note that it is not possible to inline this type in // `UserI18nSchema` because this would break types for users having multiple data collections. type i18nCollection = CollectionEntry<'i18n'>; +const i18nCollectionPathFromRoot = getCollectionPathFromRoot('i18n', project); + export type UserI18nSchema = 'i18n' extends DataCollectionKey ? i18nCollection extends { data: infer T } ? i18nSchemaOutput & T @@ -17,14 +22,20 @@ export type UserI18nSchema = 'i18n' extends DataCollectionKey : i18nSchemaOutput; export type UserI18nKeys = keyof RemoveIndexSignature; -/** Get all translation data from the i18n collection, keyed by `id`, which matches locale. */ +/** Get all translation data from the i18n collection, keyed by `lang`, which are BCP-47 language tags. */ async function loadTranslations() { // Briefly override `console.warn()` to silence logging when a project has no i18n collection. const warn = console.warn; console.warn = () => {}; const userTranslations: Record = Object.fromEntries( // @ts-ignore — may be a type error in projects without an i18n collection - (await getCollection('i18n')).map(({ id, data }) => [id, data] as const) + (await getCollection('i18n')).map(({ id, data, filePath }) => { + const lang = + project.legacyCollections || !filePath + ? id + : stripExtension(stripLeadingSlash(filePath.replace(i18nCollectionPathFromRoot, ''))); + return [lang, data] as const; + }) ); // Restore the original warn implementation. console.warn = warn; diff --git a/packages/starlight/virtual-internal.d.ts b/packages/starlight/virtual-internal.d.ts index 3c4d5ef9..10292513 100644 --- a/packages/starlight/virtual-internal.d.ts +++ b/packages/starlight/virtual-internal.d.ts @@ -1,16 +1,3 @@ -declare module 'virtual:starlight/project-context' { - const ProjectContext: { - root: string; - srcDir: string; - trailingSlash: import('astro').AstroConfig['trailingSlash']; - build: { - format: import('astro').AstroConfig['build']['format']; - }; - legacyCollections: boolean; - }; - export default ProjectContext; -} - declare module 'virtual:starlight/git-info' { export function getNewestCommitDate(file: string): Date; } diff --git a/packages/starlight/virtual.d.ts b/packages/starlight/virtual.d.ts index 17ed33d5..5ff0c53c 100644 --- a/packages/starlight/virtual.d.ts +++ b/packages/starlight/virtual.d.ts @@ -7,3 +7,18 @@ declare module 'virtual:starlight/plugin-translations' { const PluginTranslations: import('./utils/plugins').PluginTranslations; export default PluginTranslations; } + +// TODO: Move back to `virtual-internal.d.ts` when possible. For example, when dropping support for +// legacy collections, `utils/translations.ts` would no longer need to import project context. +declare module 'virtual:starlight/project-context' { + const ProjectContext: { + root: string; + srcDir: string; + trailingSlash: import('astro').AstroConfig['trailingSlash']; + build: { + format: import('astro').AstroConfig['build']['format']; + }; + legacyCollections: boolean; + }; + export default ProjectContext; +} -- cgit