Skip to content

Commit

Permalink
i18n fixes and improvements (#2444)
Browse files Browse the repository at this point in the history
Co-authored-by: Chris Swithinbank <[email protected]>
  • Loading branch information
HiDeoo and delucis authored Oct 28, 2024
1 parent 8ea0d9f commit d585b3e
Show file tree
Hide file tree
Showing 17 changed files with 43 additions and 33 deletions.
5 changes: 5 additions & 0 deletions .changeset/cool-walls-draw.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.
5 changes: 5 additions & 0 deletions .changeset/silly-foxes-kick.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@astrojs/starlight': patch
---

Refactors various components to use the new built-in localization system to access translated UI strings.
5 changes: 3 additions & 2 deletions docs/src/content/docs/guides/i18n.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -392,12 +392,13 @@ See the [`dir()` reference in the i18next documentation](https://www.i18next.com

You can use [`Astro.currentLocale`](https://docs.astro.build/en/reference/api-reference/#astrocurrentlocale) to read the current locale in `.astro` components.

The following example reads the current locale and uses it to generate a link to an about page in the current language:
The following example reads the current locale and uses it with the [`getRelativeLocaleUrl()`](https://docs.astro.build/en/reference/api-reference/#getrelativelocaleurl) helper to generate a link to an about page in the current language:

```astro
---
// src/components/AboutLink.astro
import { getRelativeLocaleUrl } from 'astro:i18n';
---
<a href={`/${Astro.currentLocale}/about`}>About</a>
<a href={getRelativeLocaleUrl(Astro.currentLocale ?? 'en', 'about')}>About</a>
```
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ describe('useTranslations()', () => {
});

test('uses user-defined regional translations when available', () => {
const t = useTranslations('pt-br');
const t = useTranslations('pt-BR');
expect(t('page.editLink')).toBe('Modifique esse doc!');
expect(t('page.editLink')).not.toBe(translations.pt?.['page.editLink']);
});
Expand Down
2 changes: 1 addition & 1 deletion packages/starlight/__tests__/i18n/translations.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ describe('useTranslations()', () => {
});

test('uses built-in translations for regional variants', () => {
const t = useTranslations('pt-br');
const t = useTranslations('pt-BR');
expect(t('page.nextLink')).toBe(translations.pt?.['page.nextLink']);
expect(t('page.nextLink')).not.toBe(translations.en?.['page.nextLink']);
});
Expand Down
2 changes: 1 addition & 1 deletion packages/starlight/__tests__/plugins/translations.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ describe('useTranslations()', () => {
});

test('uses user-defined translations for untranslated strings injected by plugins', () => {
const t = useTranslations('pt-br');
const t = useTranslations('pt-BR');
// @ts-expect-error - translation key injected by a test plugin.
expect(t('testPlugin3.doThing')).toBe('Do the Plugin 3 thing');
});
Expand Down
7 changes: 6 additions & 1 deletion packages/starlight/__tests__/remark-rehype/asides.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { describe, expect, test } from 'vitest';
import { starlightAsides, remarkDirectivesRestoration } from '../../integrations/asides';
import { createTranslationSystemFromFs } from '../../utils/translations-fs';
import { StarlightConfigSchema, type StarlightUserConfig } from '../../utils/user-config';
import { BuiltInDefaultLocale } from '../../utils/i18n';

const starlightConfig = StarlightConfigSchema.parse({
title: 'Asides Tests',
Expand Down Expand Up @@ -198,7 +199,11 @@ test('runs without locales config', async () => {
const processor = await createMarkdownProcessor({
remarkPlugins: [
...starlightAsides({
starlightConfig: { locales: undefined },
starlightConfig: {
// With no locales config, the default built-in locale is used.
defaultLocale: { ...BuiltInDefaultLocale, locale: 'en' },
locales: undefined,
},
astroConfig: {
root: new URL(import.meta.url),
srcDir: new URL('./_src/', import.meta.url),
Expand Down
6 changes: 4 additions & 2 deletions packages/starlight/integrations/asides.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ import { visit } from 'unist-util-visit';
import type { StarlightConfig } from '../types';
import type { createTranslationSystemFromFs } from '../utils/translations-fs';
import { pathToLocale } from './shared/pathToLocale';
import { localeToLang } from './shared/localeToLang';

interface AsidesOptions {
starlightConfig: { locales: StarlightConfig['locales'] };
starlightConfig: Pick<StarlightConfig, 'defaultLocale' | 'locales'>;
astroConfig: { root: AstroConfig['root']; srcDir: AstroConfig['srcDir'] };
useTranslations: ReturnType<typeof createTranslationSystemFromFs>;
}
Expand Down Expand Up @@ -151,7 +152,8 @@ function remarkAsides(options: AsidesOptions): Plugin<[], Root> {

const transformer: Transformer<Root> = (tree, file) => {
const locale = pathToLocale(file.history[0], options);
const t = options.useTranslations(locale);
const lang = localeToLang(options.starlightConfig, locale);
const t = options.useTranslations(lang);
visit(tree, (node, index, parent) => {
if (!parent || index === undefined || !isNodeDirective(node)) {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ function addTranslationsForLocale(
useTranslations: ReturnType<typeof createTranslationSystemFromFs>
) {
const lang = localeToLang(config, locale);
const t = useTranslations(locale);
const t = useTranslations(lang);
const translationKeys = [
'expressiveCode.copyButtonCopied',
'expressiveCode.copyButtonTooltip',
Expand Down
5 changes: 4 additions & 1 deletion packages/starlight/integrations/shared/localeToLang.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import { BuiltInDefaultLocale } from '../../utils/i18n';
* Get the BCP-47 language tag for the given locale.
* @param locale Locale string or `undefined` for the root locale.
*/
export function localeToLang(config: StarlightConfig, locale: string | undefined): string {
export function localeToLang(
config: Pick<StarlightConfig, 'defaultLocale' | 'locales'>,
locale: string | undefined
): string {
const lang = locale ? config.locales?.[locale]?.lang : config.locales?.root?.lang;
const defaultLang = config.defaultLocale?.lang || config.defaultLocale?.locale;
return lang || defaultLang || BuiltInDefaultLocale.lang;
Expand Down
4 changes: 1 addition & 3 deletions packages/starlight/routes/static/404.astro
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { getEntry } from 'astro:content';
import config from 'virtual:starlight/user-config';
import EmptyContent from '../../components/EmptyMarkdown.md';
import type { Route, StarlightDocsEntry } from '../../utils/routing';
import { useTranslations } from '../../utils/translations';
import { BuiltInDefaultLocale } from '../../utils/i18n';
import CommonPage from '../common.astro';
Expand All @@ -15,7 +14,6 @@ let locale = config.defaultLocale?.locale;
if (locale === 'root') locale = undefined;
const entryMeta = { dir, lang, locale };
const t = useTranslations(locale);
const fallbackEntry: StarlightDocsEntry = {
slug: '404',
Expand All @@ -27,7 +25,7 @@ const fallbackEntry: StarlightDocsEntry = {
template: 'splash',
editUrl: false,
head: [],
hero: { tagline: t('404.text'), actions: [] },
hero: { tagline: Astro.locals.t('404.text'), actions: [] },
pagefind: false,
sidebar: { hidden: false, attrs: {} },
draft: false,
Expand Down
5 changes: 1 addition & 4 deletions packages/starlight/user-components/Aside.astro
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
---
import { AstroError } from 'astro/errors';
import { slugToLocaleData, urlToSlug } from '../utils/slugs';
import { useTranslations } from '../utils/translations';
import Icon from './Icon.astro';
const asideVariants = ['note', 'tip', 'caution', 'danger'] as const;
Expand All @@ -23,8 +21,7 @@ if (!asideVariants.includes(type)) {
}
if (!title) {
const { locale } = slugToLocaleData(urlToSlug(Astro.url));
title = useTranslations(locale)(`aside.${type}`);
title = Astro.locals.t(`aside.${type}`);
}
---

Expand Down
8 changes: 1 addition & 7 deletions packages/starlight/user-components/FileTree.astro
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
---
import { stripLeadingAndTrailingSlashes } from '../utils/path';
import { slugToLocaleData } from '../utils/slugs';
import { useTranslations } from '../utils/translations';
import { processFileTree } from './rehype-file-tree';
const slug = stripLeadingAndTrailingSlashes(Astro.url.pathname);
const t = useTranslations(slugToLocaleData(slug).locale);
const fileTreeHtml = await Astro.slots.render('default');
const html = processFileTree(fileTreeHtml, t('fileTree.directory'));
const html = processFileTree(fileTreeHtml, Astro.locals.t('fileTree.directory'));
---

<starlight-file-tree set:html={html} class="not-content" data-pagefind-ignore />
Expand Down
8 changes: 4 additions & 4 deletions packages/starlight/utils/createTranslationSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@ export function createTranslationSystem<T extends i18nSchemaOutput>(
});

/**
* Generate a utility function that returns UI strings for the given `locale`.
* Generate a utility function that returns UI strings for the given language.
*
* Also includes a few utility methods:
* - `all()` method for getting the entire dictionary.
* - `exists()` method for checking if a key exists in the dictionary.
* - `dir()` method for getting the text direction of the locale.
*
* @param {string | undefined} [locale]
* @param {string | undefined} [lang]
* @example
* const t = useTranslations('en');
* const label = t('search.label');
Expand All @@ -68,8 +68,8 @@ export function createTranslationSystem<T extends i18nSchemaOutput>(
* const dir = t.dir();
* // => 'ltr'
*/
return (locale: string | undefined) => {
const lang = localeToLang(locale, config.locales, config.defaultLocale);
return (lang: string | undefined) => {
lang ??= config.defaultLocale?.lang || BuiltInDefaultLocale.lang;

const t = i18n.getFixedT(lang, I18nextNamespace) as I18nT;
t.all = () => i18n.getResourceBundle(lang, I18nextNamespace);
Expand Down
4 changes: 2 additions & 2 deletions packages/starlight/utils/route-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,15 @@ export function generateRouteData({
};
}

export function getToC({ entry, locale, headings }: PageProps) {
export function getToC({ entry, lang, headings }: PageProps) {
const tocConfig =
entry.data.template === 'splash'
? false
: entry.data.tableOfContents !== undefined
? entry.data.tableOfContents
: config.tableOfContents;
if (!tocConfig) return;
const t = useTranslations(locale);
const t = useTranslations(lang);
return {
...tocConfig,
items: generateToC(headings, { ...tocConfig, title: t('tableOfContents.overview') }),
Expand Down
4 changes: 2 additions & 2 deletions packages/starlight/utils/translations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ async function loadTranslations() {
}

/**
* Generate a utility function that returns UI strings for the given `locale`.
* @param {string | undefined} [locale]
* Generate a utility function that returns UI strings for the given language.
* @param {string | undefined} [lang]
* @example
* const t = useTranslations('en');
* const label = t('search.label'); // => 'Search'
Expand Down
2 changes: 1 addition & 1 deletion packages/starlight/vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export default defineConfig({
autoUpdate: true,
lines: 89.26,
functions: 92.78,
branches: 92.83,
branches: 92.48,
statements: 89.26,
},
},
Expand Down

0 comments on commit d585b3e

Please sign in to comment.