Normalize undefined site-space language to English in variant categorization (fix language selector) (#4002)

This commit is contained in:
Zeno Kapitein
2026-02-13 09:43:45 +01:00
committed by GitHub
parent 833b07b284
commit 152490cd67
2 changed files with 21 additions and 15 deletions
@@ -98,16 +98,15 @@ describe('categorizeVariants', () => {
]);
});
it('keeps one-per-language translations when there are more than 1 language and an undefined language', () => {
it('treats undefined language as English when mixed with translated spaces', () => {
const ctx = makeContext(englishA, [englishA, frenchA, undefinedLanguage]);
const result = categorizeVariants(ctx);
expect(result.generic.map((s) => s.id)).toEqual(['en-a']);
expect(result.generic.map((s) => s.id)).toEqual(['en-a', 'undefined']);
expect(result.translations.map((s) => ({ id: s.id, title: s.title }))).toEqual([
{ id: 'en-a', title: 'Docs EN A' },
{ id: 'fr-a', title: 'Docs FR A' },
{ id: 'undefined', title: 'Docs in Undefined Language' },
]);
});
@@ -139,11 +138,10 @@ describe('categorizeVariants', () => {
const result = categorizeVariants(ctx);
expect(result.generic.map((s) => s.id)).toEqual(['en-a', 'en-b']);
expect(result.generic.map((s) => s.id)).toEqual(['en-a', 'en-b', 'undefined']);
expect(result.translations.map((s) => ({ id: s.id, title: s.title }))).toEqual([
{ id: 'en-a', title: languages.en.language },
{ id: 'fr-a', title: languages.fr.language },
{ id: 'undefined', title: 'Docs in Undefined Language' },
{ id: 'unsupported', title: 'Docs in Unsupported Language' },
]);
});
@@ -6,26 +6,34 @@ import type { GitBookSiteContext } from '@/lib/context';
*/
export function categorizeVariants(context: GitBookSiteContext) {
const { siteSpace, visibleSiteSpaces: siteSpaces } = context;
const currentLanguage = siteSpace.space.language;
const normalizeLanguage = (language: string | undefined) =>
language === undefined ? languages.en.locale : language;
const currentLanguage = normalizeLanguage(siteSpace.space.language);
// Get all languages of the variants.
const variantLanguages = [...new Set(siteSpaces.map((space) => space.space.language))];
const variantLanguages = [
...new Set(siteSpaces.map((space) => normalizeLanguage(space.space.language))),
];
// We only show the language picker if there are at least 2 distinct languages, excluding undefined.
const isMultiLanguage =
variantLanguages.filter((language) => language !== undefined).length > 1;
// We show the language picker when there are at least 2 distinct languages.
// Spaces without an explicit language are treated as English, matching runtime defaults.
const isMultiLanguage = variantLanguages.length > 1;
// Generic variants are all spaces that have the same language as the current (can also be undefined).
const toNormalizedLanguage = (space: (typeof siteSpaces)[number]) =>
normalizeLanguage(space.space.language);
// Generic variants are all spaces that have the same language as the current (undefined is normalized to English).
const genericVariants = isMultiLanguage
? siteSpaces.filter(
(space) => space === siteSpace || space.space.language === currentLanguage
(space) => space === siteSpace || toNormalizedLanguage(space) === currentLanguage
)
: siteSpaces;
// Translation variants are all spaces that have a different language than the current.
let translationVariants = isMultiLanguage
? siteSpaces.filter(
(space) => space === siteSpace || space.space.language !== currentLanguage
(space) => space === siteSpace || toNormalizedLanguage(space) !== currentLanguage
)
: [];
@@ -35,13 +43,13 @@ export function categorizeVariants(context: GitBookSiteContext) {
translationVariants = variantLanguages
// Get the first space of each language.
.map((variantLanguage) =>
translationVariants.find((space) => space.space.language === variantLanguage)
translationVariants.find((space) => toNormalizedLanguage(space) === variantLanguage)
)
// Filter out unmatched languages.
.filter((space) => space !== undefined)
// Transform the title to include the language name if we have a translation. Otherwise, use the original title.
.map((space) => {
const language = languages[space.space.language as keyof typeof languages];
const language = languages[toNormalizedLanguage(space) as keyof typeof languages];
return {
...space,
title: language ? language.language : space.title,