diff --git a/.changeset/wide-kiwis-write.md b/.changeset/wide-kiwis-write.md new file mode 100644 index 000000000..38719282e --- /dev/null +++ b/.changeset/wide-kiwis-write.md @@ -0,0 +1,5 @@ +--- +"gitbook": patch +--- + +Add support for localized site section titles diff --git a/bun.lock b/bun.lock index d59fabc6c..c38b2743b 100644 --- a/bun.lock +++ b/bun.lock @@ -348,7 +348,7 @@ "react-dom": "catalog:", }, "catalog": { - "@gitbook/api": "0.165.0", + "@gitbook/api": "0.166.0", "@scalar/api-client-react": "^1.3.46", "@tsconfig/node20": "^20.1.6", "@tsconfig/strictest": "^2.0.6", @@ -745,7 +745,7 @@ "@fortawesome/fontawesome-svg-core": ["@fortawesome/fontawesome-svg-core@7.1.0", "", { "dependencies": { "@fortawesome/fontawesome-common-types": "7.1.0" } }, "sha512-fNxRUk1KhjSbnbuBxlWSnBLKLBNun52ZBTcs22H/xEEzM6Ap81ZFTQ4bZBxVQGQgVY0xugKGoRcCbaKjLQ3XZA=="], - "@gitbook/api": ["@gitbook/api@0.165.0", "", { "dependencies": { "event-iterator": "^2.0.0", "eventsource-parser": "^3.0.0" } }, "sha512-FzdaQUrG/XEMuUiYUPold/xPKMOYQt/wBJXK+ChQh1B10KHoQOdDPezmK56WZewNHeFHcErOERcNfgQ5MdZsfQ=="], + "@gitbook/api": ["@gitbook/api@0.166.0", "", { "dependencies": { "event-iterator": "^2.0.0", "eventsource-parser": "^3.0.0" } }, "sha512-65wbJ6lQ6CFJ3zzkFnBcvqUbKon/2TMmt4ujZ625w8geP+2RTte7sTAeRYUA8EIxpjyDJtgChNxgTRFMPFrlNw=="], "@gitbook/browser-types": ["@gitbook/browser-types@workspace:packages/browser-types"], diff --git a/package.json b/package.json index b7b41d6c2..20d49b696 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "catalog": { "@tsconfig/strictest": "^2.0.6", "@tsconfig/node20": "^20.1.6", - "@gitbook/api": "0.165.0", + "@gitbook/api": "0.166.0", "@scalar/api-client-react": "^1.3.46", "@types/react": "^19.0.0", "@types/react-dom": "^19.0.0", diff --git a/packages/gitbook/src/components/SitePage/SitePage.tsx b/packages/gitbook/src/components/SitePage/SitePage.tsx index e75a89c34..349cce5e1 100644 --- a/packages/gitbook/src/components/SitePage/SitePage.tsx +++ b/packages/gitbook/src/components/SitePage/SitePage.tsx @@ -17,6 +17,7 @@ import { isPageIndexable, isSiteIndexable } from '@/lib/seo'; import { getResizedImageURL } from '@/lib/images'; import { resolveContentRef } from '@/lib/references'; +import { getSiteSectionTitle } from '@/lib/sites'; import { tcls } from '@/lib/tailwind'; import { getPageRSSURL } from '@/routes/rss'; import { PageContextProvider } from '../PageContext'; @@ -125,6 +126,7 @@ export async function generateSitePageViewport(context: GitBookSiteContext): Pro */ function getSiteStructureTitle(context: GitBookSiteContext): string | null { const { visibleSections: sections, siteSpace, visibleSiteSpaces: siteSpaces } = context; + const currentLanguage = siteSpace.space.language; const title = []; if ( @@ -132,7 +134,7 @@ function getSiteStructureTitle(context: GitBookSiteContext): string | null { sections.current.default === false && // Only if the current section is not the default one sections.list.filter((section) => section.object === 'site-section').length > 1 // Only if there are multiple sections ) { - title.push(sections.current.title); + title.push(getSiteSectionTitle(sections.current, currentLanguage)); } if ( siteSpaces.length > 1 && // Only if there are multiple variants diff --git a/packages/gitbook/src/components/SiteSections/encodeClientSiteSections.ts b/packages/gitbook/src/components/SiteSections/encodeClientSiteSections.ts index 500a98ada..228bb03a2 100644 --- a/packages/gitbook/src/components/SiteSections/encodeClientSiteSections.ts +++ b/packages/gitbook/src/components/SiteSections/encodeClientSiteSections.ts @@ -1,5 +1,5 @@ import type { GitBookSiteContext, SiteSections } from '@/lib/context'; -import { getSectionURL, getSiteSpaceURL } from '@/lib/sites'; +import { getSectionURL, getSiteSectionTitle, getSiteSpaceURL } from '@/lib/sites'; import type { SiteSection, SiteSectionGroup, SiteSpace } from '@gitbook/api'; import assertNever from 'assert-never'; @@ -99,9 +99,10 @@ function encodeChildren( } function encodeSection(context: GitBookSiteContext, section: SiteSection) { + const currentLanguage = context.siteSpace.space.language; return { id: section.id, - title: section.title, + title: getSiteSectionTitle(section, currentLanguage), description: section.description, icon: section.icon, object: section.object, diff --git a/packages/gitbook/src/lib/sites.ts b/packages/gitbook/src/lib/sites.ts index 4da397187..b095ad201 100644 --- a/packages/gitbook/src/lib/sites.ts +++ b/packages/gitbook/src/lib/sites.ts @@ -1,5 +1,11 @@ import type { GitBookSiteContext } from '@/lib/context'; -import type { SiteSection, SiteSectionGroup, SiteSpace, SiteStructure } from '@gitbook/api'; +import type { + SiteSection, + SiteSectionGroup, + SiteSpace, + SiteStructure, + TranslationLanguage, +} from '@gitbook/api'; import { joinPath } from './paths'; import { flattenSectionsFromGroup } from './utils'; @@ -177,3 +183,22 @@ function findSiteSpaceByIdInSiteSpaces( ): SiteSpace | null { return siteSpaces.find(predicate) ?? null; } + +/** + * Get the appropriate title for a siteSection. + * Uses localizedTitle if available and current language is provided, otherwise uses title. + */ +export function getSiteSectionTitle( + siteSection: SiteSection, + currentLanguage: TranslationLanguage | undefined +): string { + if ( + siteSection.localizedTitle && + currentLanguage && + siteSection.localizedTitle[currentLanguage] + ) { + return siteSection.localizedTitle[currentLanguage]; + } + + return siteSection.title; +} diff --git a/packages/gitbook/src/routes/llms.ts b/packages/gitbook/src/routes/llms.ts index 4d1af9d7e..c9e0b50c5 100644 --- a/packages/gitbook/src/routes/llms.ts +++ b/packages/gitbook/src/routes/llms.ts @@ -3,7 +3,7 @@ import { throwIfDataError } from '@/lib/data'; import type { GitBookLinker } from '@/lib/links'; import { joinPath } from '@/lib/paths'; import { type FlatPageEntry, getIndexablePages } from '@/lib/sitemap'; -import { getSiteStructureSections } from '@/lib/sites'; +import { getSiteSectionTitle, getSiteStructureSections } from '@/lib/sites'; import type { SiteSection, SiteSpace } from '@gitbook/api'; import assertNever from 'assert-never'; import type { ListItem, Paragraph, Root, RootContent } from 'mdast'; @@ -89,6 +89,7 @@ async function getNodesFromSections( withMarkdownPages: boolean; } ): Promise { + const currentLanguage = context.siteSpace.space.language; const all = await Promise.all( siteSections.map(async (siteSection): Promise => { const siteSpaceNodes = await getNodesFromSiteSpaces(context, siteSection.siteSpaces, { @@ -99,7 +100,9 @@ async function getNodesFromSections( { type: 'heading', depth: 2, - children: [{ type: 'text', value: siteSection.title }], + children: [ + { type: 'text', value: getSiteSectionTitle(siteSection, currentLanguage) }, + ], }, ...siteSpaceNodes, ];