diff options
author | HiDeoo | 2024-04-05 15:28:03 +0200 |
---|---|---|
committer | GitHub | 2024-04-05 15:28:03 +0200 |
commit | a72cb96600798c1fbc7558f8fd24556ca442d312 (patch) | |
tree | a122f36c6d775e615bd0013f307977183e1e3bcb | |
parent | b26238f22990dcf8ba002bea6a50c66f20ad5786 (diff) | |
download | IT.starlight-a72cb96600798c1fbc7558f8fd24556ca442d312.tar.gz IT.starlight-a72cb96600798c1fbc7558f8fd24556ca442d312.tar.bz2 IT.starlight-a72cb96600798c1fbc7558f8fd24556ca442d312.zip |
Fix various Expressive Code translation issues (#1708)
Co-authored-by: Chris Swithinbank <357379+delucis@users.noreply.github.com>
Co-authored-by: Hippo <6137925+hippotastic@users.noreply.github.com>
5 files changed, 163 insertions, 19 deletions
diff --git a/.changeset/wet-lemons-drum.md b/.changeset/wet-lemons-drum.md new file mode 100644 index 00000000..79a013a9 --- /dev/null +++ b/.changeset/wet-lemons-drum.md @@ -0,0 +1,5 @@ +--- +'@astrojs/starlight': patch +--- + +Fixes translation issues with Expressive Code when using a default language other than English diff --git a/packages/starlight/__tests__/i18n/translations-ec.test.ts b/packages/starlight/__tests__/i18n/translations-ec.test.ts new file mode 100644 index 00000000..cbefb76f --- /dev/null +++ b/packages/starlight/__tests__/i18n/translations-ec.test.ts @@ -0,0 +1,117 @@ +import { pluginFramesTexts } from 'astro-expressive-code'; +import { afterEach, expect, test, vi } from 'vitest'; +import { addTranslations } from '../../integrations/expressive-code/translations'; +import { StarlightConfigSchema, type StarlightUserConfig } from '../../utils/user-config'; + +vi.mock('astro-expressive-code', async () => { + const mod = await vi.importActual<typeof import('astro-expressive-code')>( + 'astro-expressive-code' + ); + return { + ...mod, + pluginFramesTexts: { + ...mod.pluginFramesTexts, + overrideTexts: vi.fn(), + }, + }; +}); + +afterEach(() => { + vi.clearAllMocks(); +}); + +test('adds default english translations with no i18n config', async () => { + const [config, useTranslations] = getStarlightConfigAndUseTranslations(undefined); + + addTranslations(config, useTranslations); + + expect(getExpressiveCodeOverridenLanguages()).toEqual(['en']); +}); + +test('adds translations in a monolingual site with english as root locale', async () => { + const [config, useTranslations] = getStarlightConfigAndUseTranslations({ + root: { label: 'English', lang: 'en' }, + }); + + addTranslations(config, useTranslations); + + expect(getExpressiveCodeOverridenLanguages()).toEqual(['en']); +}); + +test('adds translations in a monolingual site with french as root locale', async () => { + const [config, useTranslations] = getStarlightConfigAndUseTranslations({ + root: { label: 'Français', lang: 'fr' }, + }); + + addTranslations(config, useTranslations); + + expect(getExpressiveCodeOverridenLanguages()).toEqual(['fr']); +}); + +test('add translations in a multilingual site with english as root locale', async () => { + const [config, useTranslations] = getStarlightConfigAndUseTranslations({ + root: { label: 'English', lang: 'en' }, + fr: { label: 'French' }, + }); + + addTranslations(config, useTranslations); + + expect(getExpressiveCodeOverridenLanguages()).toEqual(['en', 'fr']); +}); + +test('add translations in a multilingual site with french as root locale', async () => { + const [config, useTranslations] = getStarlightConfigAndUseTranslations({ + root: { label: 'French', lang: 'fr' }, + ru: { label: 'Русский', lang: 'ru' }, + }); + + addTranslations(config, useTranslations); + + expect(getExpressiveCodeOverridenLanguages()).toEqual(['fr', 'ru']); +}); + +test('add translations in a multilingual site with english as default locale', async () => { + const [config, useTranslations] = getStarlightConfigAndUseTranslations( + { + en: { label: 'English', lang: 'en' }, + fr: { label: 'French' }, + }, + 'en' + ); + + addTranslations(config, useTranslations); + + expect(getExpressiveCodeOverridenLanguages()).toEqual(['en', 'fr']); +}); + +test('add translations in a multilingual site with french as default locale', async () => { + const [config, useTranslations] = getStarlightConfigAndUseTranslations( + { + fr: { label: 'French', lang: 'fr' }, + ru: { label: 'Русский', lang: 'ru' }, + }, + 'fr' + ); + + addTranslations(config, useTranslations); + + expect(getExpressiveCodeOverridenLanguages()).toEqual(['fr', 'ru']); +}); + +function getStarlightConfigAndUseTranslations( + locales: StarlightUserConfig['locales'], + defaultLocale?: StarlightUserConfig['defaultLocale'] +) { + return [ + StarlightConfigSchema.parse({ + title: 'Expressive Code Translations Test', + locales, + defaultLocale, + }), + vi.fn().mockReturnValue(() => 'test UI string'), + ] as const; +} + +function getExpressiveCodeOverridenLanguages() { + return [...new Set(vi.mocked(pluginFramesTexts.overrideTexts).mock.calls.map(([lang]) => lang))]; +} diff --git a/packages/starlight/integrations/expressive-code/index.ts b/packages/starlight/integrations/expressive-code/index.ts index 0c1a0af6..fc9962f8 100644 --- a/packages/starlight/integrations/expressive-code/index.ts +++ b/packages/starlight/integrations/expressive-code/index.ts @@ -77,7 +77,6 @@ export function getStarlightEcConfigPreprocessor({ return (input): AstroExpressiveCodeOptions => { const astroConfig = input.astroConfig; const ecConfig = input.ecConfig as StarlightExpressiveCodeOptions; - const { locales } = starlightConfig; const { themes: themesInput, @@ -111,7 +110,7 @@ export function getStarlightEcConfigPreprocessor({ }); // Add Expressive Code UI translations (if any) for all defined locales - if (useTranslations) addTranslations(locales, useTranslations); + if (useTranslations) addTranslations(starlightConfig, useTranslations); return { themes, @@ -124,6 +123,7 @@ export function getStarlightEcConfigPreprocessor({ } return theme; }, + defaultLocale: starlightConfig.defaultLocale?.lang ?? starlightConfig.defaultLocale?.locale, themeCssSelector: (theme, { styleVariants }) => { // If one dark and one light theme are available, and the user has not disabled it, // generate theme CSS selectors compatible with Starlight's dark mode switch diff --git a/packages/starlight/integrations/expressive-code/translations.ts b/packages/starlight/integrations/expressive-code/translations.ts index 1ff1c286..7aa5a4a1 100644 --- a/packages/starlight/integrations/expressive-code/translations.ts +++ b/packages/starlight/integrations/expressive-code/translations.ts @@ -1,26 +1,37 @@ import { pluginFramesTexts } from 'astro-expressive-code'; import type { StarlightConfig } from '../../types'; import type { createTranslationSystemFromFs } from '../../utils/translations-fs'; +import { localeToLang } from '../shared/localeToLang'; export function addTranslations( - locales: StarlightConfig['locales'], + config: StarlightConfig, useTranslations: ReturnType<typeof createTranslationSystemFromFs> ) { - for (const locale in locales) { - const lang = locales[locale]?.lang; - if (!lang) continue; - - const t = useTranslations(locale); - const translationKeys = [ - 'expressiveCode.copyButtonCopied', - 'expressiveCode.copyButtonTooltip', - 'expressiveCode.terminalWindowFallbackTitle', - ] as const; - translationKeys.forEach((key) => { - const translation = t(key); - if (!translation) return; - const ecId = key.replace(/^expressiveCode\./, ''); - pluginFramesTexts.overrideTexts(lang, { [ecId]: translation }); - }); + addTranslationsForLocale(config.defaultLocale.locale, config, useTranslations); + if (config.isMultilingual) { + for (const locale in config.locales) { + if (locale === config.defaultLocale.locale || locale === 'root') continue; + addTranslationsForLocale(locale, config, useTranslations); + } } } + +function addTranslationsForLocale( + locale: string | undefined, + config: StarlightConfig, + useTranslations: ReturnType<typeof createTranslationSystemFromFs> +) { + const lang = localeToLang(config, locale); + const t = useTranslations(locale); + const translationKeys = [ + 'expressiveCode.copyButtonCopied', + 'expressiveCode.copyButtonTooltip', + 'expressiveCode.terminalWindowFallbackTitle', + ] as const; + translationKeys.forEach((key) => { + const translation = t(key); + if (!translation) return; + const ecId = key.replace(/^expressiveCode\./, ''); + pluginFramesTexts.overrideTexts(lang, { [ecId]: translation }); + }); +} diff --git a/packages/starlight/integrations/shared/localeToLang.ts b/packages/starlight/integrations/shared/localeToLang.ts new file mode 100644 index 00000000..5d79d017 --- /dev/null +++ b/packages/starlight/integrations/shared/localeToLang.ts @@ -0,0 +1,11 @@ +import type { StarlightConfig } from '../../types'; + +/** + * 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 { + const lang = locale ? config.locales?.[locale]?.lang : config.locales?.root?.lang; + const defaultLang = config.defaultLocale?.lang || config.defaultLocale?.locale; + return lang || defaultLang || 'en'; +} |