From ecb4292551699cccf289767b04853feb755be871 Mon Sep 17 00:00:00 2001 From: "Nolann B." <100787331+nolannbiron@users.noreply.github.com> Date: Mon, 13 Apr 2026 21:53:42 +0200 Subject: [PATCH] Fix llms.txt and llms-full.txt language variants filtering (#4179) --- .../SpaceLayout/categorizeVariants.ts | 7 ++--- packages/gitbook/src/lib/sites.test.ts | 31 +++++++++++++++++++ packages/gitbook/src/lib/sites.ts | 26 +++++++++++++++- 3 files changed, 58 insertions(+), 6 deletions(-) create mode 100644 packages/gitbook/src/lib/sites.test.ts diff --git a/packages/gitbook/src/components/SpaceLayout/categorizeVariants.ts b/packages/gitbook/src/components/SpaceLayout/categorizeVariants.ts index f2a3b5942..664383510 100644 --- a/packages/gitbook/src/components/SpaceLayout/categorizeVariants.ts +++ b/packages/gitbook/src/components/SpaceLayout/categorizeVariants.ts @@ -1,20 +1,17 @@ import { languages } from '@/intl/translations'; import type { GitBookSiteContext } from '@/lib/context'; +import { getSiteSpaceLanguages, normalizeLanguage } from '@/lib/sites'; /** * Categorize the variants of the space into generic and translation variants. */ export function categorizeVariants(context: GitBookSiteContext) { const { siteSpace, visibleSiteSpaces: siteSpaces } = context; - const normalizeLanguage = (language: string | undefined) => - language === undefined ? languages.en.locale : language; const currentLanguage = normalizeLanguage(context.locale); // Get all languages of the variants. - const variantLanguages = [ - ...new Set(siteSpaces.map((space) => normalizeLanguage(space.space.language))), - ]; + const variantLanguages = getSiteSpaceLanguages(siteSpaces); // 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. diff --git a/packages/gitbook/src/lib/sites.test.ts b/packages/gitbook/src/lib/sites.test.ts new file mode 100644 index 000000000..e5bb7fbea --- /dev/null +++ b/packages/gitbook/src/lib/sites.test.ts @@ -0,0 +1,31 @@ +import { describe, expect, it } from 'bun:test'; +import type { SiteSpace } from '@gitbook/api'; +import { TranslationLanguage } from '@gitbook/api'; + +import { filterSiteSpacesByLocale } from './sites'; + +function makeSiteSpace(language: TranslationLanguage | undefined): SiteSpace { + return { space: { language } } as unknown as SiteSpace; +} + +describe('filterSiteSpacesByLocale', () => { + it('returns all spaces on a single-language site', () => { + const spaces = [makeSiteSpace(undefined), makeSiteSpace(undefined)]; + expect(filterSiteSpacesByLocale(spaces, TranslationLanguage.En)).toEqual(spaces); + }); + + it('filters by locale on a multi-language site', () => { + const en = makeSiteSpace(TranslationLanguage.En); + const fr = makeSiteSpace(TranslationLanguage.Fr); + expect(filterSiteSpacesByLocale([en, fr], TranslationLanguage.Fr)).toEqual([fr]); + }); + + it('treats undefined language as English', () => { + const undefinedLanguage = makeSiteSpace(undefined); + const en = makeSiteSpace(TranslationLanguage.En); + expect(filterSiteSpacesByLocale([undefinedLanguage, en], TranslationLanguage.En)).toEqual([ + undefinedLanguage, + en, + ]); + }); +}); diff --git a/packages/gitbook/src/lib/sites.ts b/packages/gitbook/src/lib/sites.ts index dea13229d..aae773614 100644 --- a/packages/gitbook/src/lib/sites.ts +++ b/packages/gitbook/src/lib/sites.ts @@ -1,3 +1,4 @@ +import { languages } from '@/intl/translations'; import type { GitBookSiteContext } from '@/lib/context'; import type { LocalizedString, @@ -39,6 +40,21 @@ export function getSiteStructureSections( : []; } +/** + * Normalize a space language to a locale string. + * Spaces without an explicit language are treated as English, matching runtime defaults. + */ +export function normalizeLanguage(language: string | undefined): string { + return language === undefined ? languages.en.locale : language; +} + +/** + * Return the distinct normalized languages across a set of site spaces. + */ +export function getSiteSpaceLanguages(siteSpaces: SiteSpace[]): string[] { + return [...new Set(siteSpaces.map((space) => normalizeLanguage(space.space.language)))]; +} + /** * Filter site spaces to only include those matching the given locale */ @@ -46,7 +62,15 @@ export function filterSiteSpacesByLocale( siteSpaces: SiteSpace[], locale: TranslationLanguage | undefined ): SiteSpace[] { - return siteSpaces.filter((siteSpace) => siteSpace.space.language === locale); + const variantLanguages = getSiteSpaceLanguages(siteSpaces); + if (variantLanguages.length <= 1) { + return siteSpaces; + } + + const normalizedLocale = normalizeLanguage(locale); + return siteSpaces.filter( + (siteSpace) => normalizeLanguage(siteSpace.space.language) === normalizedLocale + ); } /*