Skip to content

Commit

Permalink
Fix translation issue for languages with a region subtag (#2757)
Browse files Browse the repository at this point in the history
Co-authored-by: Chris Swithinbank <swithinbank@gmail.com>
  • Loading branch information
HiDeoo and delucis authored Jan 7, 2025
1 parent d56bda7 commit e7b0e74
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 23 deletions.
5 changes: 5 additions & 0 deletions .changeset/brave-kings-vanish.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@astrojs/starlight': patch
---

Fixes a UI string translation issue for languages with a region subtag.
3 changes: 2 additions & 1 deletion packages/starlight/__tests__/test-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,9 @@ function mockDoc(

function mockDict(id: string, data: z.input<ReturnType<typeof i18nSchema>>) {
return {
id,
id: project.legacyCollections ? id : id.toLocaleLowerCase(),
data: i18nSchema().parse(data),
filePath: project.legacyCollections ? undefined : `src/content/i18n/${id}.yml`,
};
}

Expand Down
13 changes: 6 additions & 7 deletions packages/starlight/utils/navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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,
Expand Down
6 changes: 6 additions & 0 deletions packages/starlight/utils/path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
15 changes: 13 additions & 2 deletions packages/starlight/utils/translations.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,41 @@
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
: i18nSchemaOutput
: i18nSchemaOutput;
export type UserI18nKeys = keyof RemoveIndexSignature<UserI18nSchema>;

/** 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<string, UserI18nSchema> = 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;
Expand Down
13 changes: 0 additions & 13 deletions packages/starlight/virtual-internal.d.ts
Original file line number Diff line number Diff line change
@@ -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;
}
Expand Down
15 changes: 15 additions & 0 deletions packages/starlight/virtual.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

0 comments on commit e7b0e74

Please sign in to comment.