From 69a29ab5a826add0d0884032075ffd4cdacbe7c6 Mon Sep 17 00:00:00 2001 From: Peter White Date: Thu, 8 Oct 2026 14:24:18 +0200 Subject: [PATCH] Support fr-ca, es-mx and es-419 site UI locales --- .../src/intl/translations/index.test.ts | 20 +++++++++++++++++++ .../gitbook/src/intl/translations/index.ts | 20 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 packages/gitbook/src/intl/translations/index.test.ts diff --git a/packages/gitbook/src/intl/translations/index.test.ts b/packages/gitbook/src/intl/translations/index.test.ts new file mode 100644 index 000000000..4441ccc5a --- /dev/null +++ b/packages/gitbook/src/intl/translations/index.test.ts @@ -0,0 +1,20 @@ +import { describe, expect, it } from 'bun:test'; + +import { es } from './es'; +import { fr } from './fr'; +import { isAvailableLanguage, languages, loadLanguage } from './index'; + +describe('regional language variants', () => { + it.each([ + ['fr-ca', fr], + ['es-mx', es], + ['es-419', es], + ] as const)('loads %s with its own metadata and the base strings', async (locale, base) => { + expect(isAvailableLanguage(locale)).toBe(true); + + const language = await loadLanguage(locale); + + expect(language).toEqual({ ...base, ...languages[locale] }); + expect(language.locale).toBe(locale); + }); +}); diff --git a/packages/gitbook/src/intl/translations/index.ts b/packages/gitbook/src/intl/translations/index.ts index 18b55b4d7..691f9eb69 100644 --- a/packages/gitbook/src/intl/translations/index.ts +++ b/packages/gitbook/src/intl/translations/index.ts @@ -25,6 +25,10 @@ const languageDefinitions = { metadata: { locale: 'fr', language: 'Français', flag: '🇫🇷' }, load: () => import('./fr').then((module) => module.fr), }, + 'fr-ca': { + metadata: { locale: 'fr-ca', language: 'Français (Canada)', flag: '🇨🇦' }, + load: () => import('./fr').then((module) => withMetadata(module.fr, 'fr-ca')), + }, de: { metadata: { locale: 'de', language: 'Deutsch', flag: '🇩🇪' }, load: () => import('./de').then((module) => module.de), @@ -33,6 +37,14 @@ const languageDefinitions = { metadata: { locale: 'es', language: 'Español', flag: '🇪🇸' }, load: () => import('./es').then((module) => module.es), }, + 'es-mx': { + metadata: { locale: 'es-mx', language: 'Español (México)', flag: '🇲🇽' }, + load: () => import('./es').then((module) => withMetadata(module.es, 'es-mx')), + }, + 'es-419': { + metadata: { locale: 'es-419', language: 'Español (Latinoamérica)', flag: '🌎' }, + load: () => import('./es').then((module) => withMetadata(module.es, 'es-419')), + }, it: { metadata: { locale: 'it', language: 'Italiano', flag: '🇮🇹' }, load: () => import('./it').then((module) => module.it), @@ -177,6 +189,14 @@ const languageDefinitions = { export type TranslationLocale = keyof typeof languageDefinitions; +// Regional variants reuse their base language's strings but keep their own locale, name and flag. +function withMetadata( + base: TranslationLanguage, + locale: 'fr-ca' | 'es-mx' | 'es-419' +): TranslationLanguage { + return { ...base, ...languageDefinitions[locale].metadata }; +} + export const languages = Object.fromEntries( Object.entries(languageDefinitions).map(([locale, definition]) => [locale, definition.metadata]) ) as {