From 5769fe5015af47746eb0e051cac3aae06ce6fa38 Mon Sep 17 00:00:00 2001 From: 4RH1T3CT0R7 Date: Sat, 14 Feb 2026 23:50:36 +0300 Subject: [PATCH 1/5] fix(content-docs): use category key for generated-index translation lookup When a sidebar category has a custom `key` attribute, the translation system generates keys using `category.key ?? category.label`. However, the read phase (`transformSidebarCategoryLink`) was using `category.label` directly for generated-index title and description lookups, causing a key mismatch and silent translation failure. This aligns the generated-index lookup with the existing pattern already used for category labels, link labels, and doc labels. Fixes #11738 --- .../src/__tests__/translations.test.ts | 91 ++++++++++++++++++- .../src/translations.ts | 5 +- 2 files changed, 93 insertions(+), 3 deletions(-) diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/translations.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/translations.test.ts index 26666037c589..ff25eee67c3c 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/translations.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/translations.test.ts @@ -201,6 +201,21 @@ describe('getLoadedContentTranslationFiles', () => { collapsible: true, ...(withUniqueKeys && {key: 'key-cat2'}), }, + { + type: 'category', + label: 'COMMON LABEL', + items: [], + collapsed: false, + collapsible: true, + link: { + type: 'generated-index', + slug: '/category/gen-index-slug', + permalink: '/docs/category/gen-index-slug', + title: 'Generated index title', + description: 'Generated index description', + }, + ...(withUniqueKeys && {key: 'key-cat-with-link'}), + }, { type: 'link', href: 'https://example.com', @@ -231,6 +246,18 @@ describe('getLoadedContentTranslationFiles', () => { [ { "content": { + "sidebar.sidebarWithConflicts.category.key-cat-with-link": { + "description": "The label for category 'COMMON LABEL' in sidebar 'sidebarWithConflicts'", + "message": "COMMON LABEL", + }, + "sidebar.sidebarWithConflicts.category.key-cat-with-link.link.generated-index.description": { + "description": "The generated-index page description for category 'COMMON LABEL' in sidebar 'sidebarWithConflicts'", + "message": "Generated index description", + }, + "sidebar.sidebarWithConflicts.category.key-cat-with-link.link.generated-index.title": { + "description": "The generated-index page title for category 'COMMON LABEL' in sidebar 'sidebarWithConflicts'", + "message": "Generated index title", + }, "sidebar.sidebarWithConflicts.category.key-cat1": { "description": "The label for category 'COMMON LABEL' in sidebar 'sidebarWithConflicts'", "message": "COMMON LABEL", @@ -278,7 +305,8 @@ describe('getLoadedContentTranslationFiles', () => { expect(() => runTest({withUniqueKeys: false})) .toThrowErrorMatchingInlineSnapshot(` "Multiple docs sidebar items produce the same translation key. - - \`sidebar.sidebarWithConflicts.category.COMMON LABEL\`: 2 duplicates found: + - \`sidebar.sidebarWithConflicts.category.COMMON LABEL\`: 3 duplicates found: + - COMMON LABEL (The label for category 'COMMON LABEL' in sidebar 'sidebarWithConflicts') - COMMON LABEL (The label for category 'COMMON LABEL' in sidebar 'sidebarWithConflicts') - COMMON LABEL (The label for category 'COMMON LABEL' in sidebar 'sidebarWithConflicts') @@ -316,4 +344,65 @@ describe('translateLoadedContent', () => { translateLoadedContent(SampleLoadedContent, translationFiles), ).toMatchSnapshot(); }); + + it('translates generated-index title/description using category key', () => { + const loadedContent: LoadedContent = { + loadedVersions: [ + createSampleVersion({ + versionName: CURRENT_VERSION_NAME, + sidebars: { + mySidebar: [ + { + type: 'category', + label: 'My Category', + key: 'my-custom-key', + collapsed: false, + collapsible: true, + link: { + type: 'generated-index', + slug: '/category/my-cat', + permalink: '/docs/category/my-cat', + title: 'Original Title', + description: 'Original Description', + }, + items: [], + }, + ], + }, + }), + ], + }; + + const translationFiles = getLoadedContentTranslationFiles(loadedContent); + + // Verify that translation keys use the custom key, not the label + const content = translationFiles[0]!.content; + expect( + content[ + 'sidebar.mySidebar.category.my-custom-key.link.generated-index.title' + ], + ).toBeDefined(); + expect( + content[ + 'sidebar.mySidebar.category.my-custom-key.link.generated-index.description' + ], + ).toBeDefined(); + + // Now translate and verify round-trip + const translatedFiles = translationFiles.map((f) => + updateTranslationFileMessages(f, (message) => `${message} (translated)`), + ); + const translated = translateLoadedContent(loadedContent, translatedFiles); + const sidebar = translated.loadedVersions[0]!.sidebars.mySidebar!; + const category = sidebar[0]!; + expect(category).toMatchObject({ + type: 'category', + label: 'My Category (translated)', + link: { + type: 'generated-index', + title: 'Original Title (translated)', + description: 'Original Description (translated)', + }, + }); + }); }); diff --git a/packages/docusaurus-plugin-content-docs/src/translations.ts b/packages/docusaurus-plugin-content-docs/src/translations.ts index 9ad1a148b039..ecea3252d438 100644 --- a/packages/docusaurus-plugin-content-docs/src/translations.ts +++ b/packages/docusaurus-plugin-content-docs/src/translations.ts @@ -177,13 +177,14 @@ function translateSidebar({ return undefined; } if (category.link.type === 'generated-index') { + const categoryKey = category.key ?? category.label; const title = sidebarsTranslations[ - `sidebar.${sidebarName}.category.${category.label}.link.generated-index.title` + `sidebar.${sidebarName}.category.${categoryKey}.link.generated-index.title` ]?.message ?? category.link.title; const description = sidebarsTranslations[ - `sidebar.${sidebarName}.category.${category.label}.link.generated-index.description` + `sidebar.${sidebarName}.category.${categoryKey}.link.generated-index.description` ]?.message ?? category.link.description; return { ...category.link, From af08bca6078b3eac8fe7a43804e521e71a2bb9e0 Mon Sep 17 00:00:00 2001 From: 4RH1T3CT0R7 Date: Sat, 14 Feb 2026 23:58:30 +0300 Subject: [PATCH 2/5] chore: trigger CLA bot From fe9722a8150c3406ced54ef91b3ad10397550fec Mon Sep 17 00:00:00 2001 From: sebastien Date: Thu, 19 Feb 2026 14:07:13 +0100 Subject: [PATCH 3/5] simplify test --- .../__snapshots__/translations.test.ts.snap | 81 +++++++++++++++++++ .../src/__tests__/translations.test.ts | 76 ++++------------- 2 files changed, 96 insertions(+), 61 deletions(-) diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/translations.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/translations.test.ts.snap index 82dedb7cbeb0..8d5f668a1b26 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/translations.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/translations.test.ts.snap @@ -24,6 +24,18 @@ exports[`getLoadedContentTranslationFiles returns translation files 1`] = ` "description": "The label for link 'Link label' in sidebar 'docs', linking to 'https://facebook.com'", "message": "Link label", }, + "sidebar.otherSidebar.category.cat-with-key": { + "description": "The label for category 'Category with key' in sidebar 'otherSidebar'", + "message": "Category with key", + }, + "sidebar.otherSidebar.category.cat-with-key.link.generated-index.description": { + "description": "The generated-index page description for category 'Category with key' in sidebar 'otherSidebar'", + "message": "Category with key - index description", + }, + "sidebar.otherSidebar.category.cat-with-key.link.generated-index.title": { + "description": "The generated-index page title for category 'Category with key' in sidebar 'otherSidebar'", + "message": "Category with key - index title", + }, "sidebar.otherSidebar.doc.Fifth doc translatable": { "description": "The label for the doc item 'Fifth doc translatable' in sidebar 'otherSidebar', linking to the doc doc5", "message": "Fifth doc translatable", @@ -57,6 +69,18 @@ exports[`getLoadedContentTranslationFiles returns translation files 1`] = ` "description": "The label for link 'Link label' in sidebar 'docs', linking to 'https://facebook.com'", "message": "Link label", }, + "sidebar.otherSidebar.category.cat-with-key": { + "description": "The label for category 'Category with key' in sidebar 'otherSidebar'", + "message": "Category with key", + }, + "sidebar.otherSidebar.category.cat-with-key.link.generated-index.description": { + "description": "The generated-index page description for category 'Category with key' in sidebar 'otherSidebar'", + "message": "Category with key - index description", + }, + "sidebar.otherSidebar.category.cat-with-key.link.generated-index.title": { + "description": "The generated-index page title for category 'Category with key' in sidebar 'otherSidebar'", + "message": "Category with key - index title", + }, "sidebar.otherSidebar.doc.Fifth doc translatable": { "description": "The label for the doc item 'Fifth doc translatable' in sidebar 'otherSidebar', linking to the doc doc5", "message": "Fifth doc translatable", @@ -90,6 +114,18 @@ exports[`getLoadedContentTranslationFiles returns translation files 1`] = ` "description": "The label for link 'Link label' in sidebar 'docs', linking to 'https://facebook.com'", "message": "Link label", }, + "sidebar.otherSidebar.category.cat-with-key": { + "description": "The label for category 'Category with key' in sidebar 'otherSidebar'", + "message": "Category with key", + }, + "sidebar.otherSidebar.category.cat-with-key.link.generated-index.description": { + "description": "The generated-index page description for category 'Category with key' in sidebar 'otherSidebar'", + "message": "Category with key - index description", + }, + "sidebar.otherSidebar.category.cat-with-key.link.generated-index.title": { + "description": "The generated-index page title for category 'Category with key' in sidebar 'otherSidebar'", + "message": "Category with key - index title", + }, "sidebar.otherSidebar.doc.Fifth doc translatable": { "description": "The label for the doc item 'Fifth doc translatable' in sidebar 'otherSidebar', linking to the doc doc5", "message": "Fifth doc translatable", @@ -273,6 +309,21 @@ exports[`translateLoadedContent returns translated loaded content 1`] = ` "translatable": true, "type": "ref", }, + { + "collapsed": false, + "collapsible": true, + "items": [], + "key": "cat-with-key", + "label": "Category with key (translated)", + "link": { + "description": "Category with key - index description (translated)", + "permalink": "/docs/category/cat-with-key", + "slug": "/category/cat-with-key-slug", + "title": "Category with key - index title (translated)", + "type": "generated-index", + }, + "type": "category", + }, ], }, "tagsPath": "/tags/", @@ -444,6 +495,21 @@ exports[`translateLoadedContent returns translated loaded content 1`] = ` "translatable": true, "type": "ref", }, + { + "collapsed": false, + "collapsible": true, + "items": [], + "key": "cat-with-key", + "label": "Category with key (translated)", + "link": { + "description": "Category with key - index description (translated)", + "permalink": "/docs/category/cat-with-key", + "slug": "/category/cat-with-key-slug", + "title": "Category with key - index title (translated)", + "type": "generated-index", + }, + "type": "category", + }, ], }, "tagsPath": "/tags/", @@ -615,6 +681,21 @@ exports[`translateLoadedContent returns translated loaded content 1`] = ` "translatable": true, "type": "ref", }, + { + "collapsed": false, + "collapsible": true, + "items": [], + "key": "cat-with-key", + "label": "Category with key (translated)", + "link": { + "description": "Category with key - index description (translated)", + "permalink": "/docs/category/cat-with-key", + "slug": "/category/cat-with-key-slug", + "title": "Category with key - index title (translated)", + "type": "generated-index", + }, + "type": "category", + }, ], }, "tagsPath": "/tags/", diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/translations.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/translations.test.ts index ff25eee67c3c..61ca401e344d 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/translations.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/translations.test.ts @@ -116,6 +116,21 @@ function createSampleVersion( label: 'Fifth doc translatable', translatable: true, }, + { + type: 'category', + key: 'cat-with-key', + label: 'Category with key', + collapsed: false, + collapsible: true, + link: { + type: 'generated-index', + slug: '/category/cat-with-key-slug', + permalink: '/docs/category/cat-with-key', + title: 'Category with key - index title', + description: 'Category with key - index description', + }, + items: [], + }, ], }, ...version, @@ -344,65 +359,4 @@ describe('translateLoadedContent', () => { translateLoadedContent(SampleLoadedContent, translationFiles), ).toMatchSnapshot(); }); - - it('translates generated-index title/description using category key', () => { - const loadedContent: LoadedContent = { - loadedVersions: [ - createSampleVersion({ - versionName: CURRENT_VERSION_NAME, - sidebars: { - mySidebar: [ - { - type: 'category', - label: 'My Category', - key: 'my-custom-key', - collapsed: false, - collapsible: true, - link: { - type: 'generated-index', - slug: '/category/my-cat', - permalink: '/docs/category/my-cat', - title: 'Original Title', - description: 'Original Description', - }, - items: [], - }, - ], - }, - }), - ], - }; - - const translationFiles = getLoadedContentTranslationFiles(loadedContent); - - // Verify that translation keys use the custom key, not the label - const content = translationFiles[0]!.content; - expect( - content[ - 'sidebar.mySidebar.category.my-custom-key.link.generated-index.title' - ], - ).toBeDefined(); - expect( - content[ - 'sidebar.mySidebar.category.my-custom-key.link.generated-index.description' - ], - ).toBeDefined(); - - // Now translate and verify round-trip - const translatedFiles = translationFiles.map((f) => - updateTranslationFileMessages(f, (message) => `${message} (translated)`), - ); - const translated = translateLoadedContent(loadedContent, translatedFiles); - const sidebar = translated.loadedVersions[0]!.sidebars.mySidebar!; - const category = sidebar[0]!; - expect(category).toMatchObject({ - type: 'category', - label: 'My Category (translated)', - link: { - type: 'generated-index', - title: 'Original Title (translated)', - description: 'Original Description (translated)', - }, - }); - }); }); From c86c14efb9b597b5187535a0d8429c387caf0d6d Mon Sep 17 00:00:00 2001 From: sebastien Date: Thu, 19 Feb 2026 14:10:46 +0100 Subject: [PATCH 4/5] simplify test --- .../src/__tests__/translations.test.ts | 30 +------------------ 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/translations.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/translations.test.ts index 61ca401e344d..87485078fad5 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/translations.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/translations.test.ts @@ -216,21 +216,6 @@ describe('getLoadedContentTranslationFiles', () => { collapsible: true, ...(withUniqueKeys && {key: 'key-cat2'}), }, - { - type: 'category', - label: 'COMMON LABEL', - items: [], - collapsed: false, - collapsible: true, - link: { - type: 'generated-index', - slug: '/category/gen-index-slug', - permalink: '/docs/category/gen-index-slug', - title: 'Generated index title', - description: 'Generated index description', - }, - ...(withUniqueKeys && {key: 'key-cat-with-link'}), - }, { type: 'link', href: 'https://example.com', @@ -261,18 +246,6 @@ describe('getLoadedContentTranslationFiles', () => { [ { "content": { - "sidebar.sidebarWithConflicts.category.key-cat-with-link": { - "description": "The label for category 'COMMON LABEL' in sidebar 'sidebarWithConflicts'", - "message": "COMMON LABEL", - }, - "sidebar.sidebarWithConflicts.category.key-cat-with-link.link.generated-index.description": { - "description": "The generated-index page description for category 'COMMON LABEL' in sidebar 'sidebarWithConflicts'", - "message": "Generated index description", - }, - "sidebar.sidebarWithConflicts.category.key-cat-with-link.link.generated-index.title": { - "description": "The generated-index page title for category 'COMMON LABEL' in sidebar 'sidebarWithConflicts'", - "message": "Generated index title", - }, "sidebar.sidebarWithConflicts.category.key-cat1": { "description": "The label for category 'COMMON LABEL' in sidebar 'sidebarWithConflicts'", "message": "COMMON LABEL", @@ -320,8 +293,7 @@ describe('getLoadedContentTranslationFiles', () => { expect(() => runTest({withUniqueKeys: false})) .toThrowErrorMatchingInlineSnapshot(` "Multiple docs sidebar items produce the same translation key. - - \`sidebar.sidebarWithConflicts.category.COMMON LABEL\`: 3 duplicates found: - - COMMON LABEL (The label for category 'COMMON LABEL' in sidebar 'sidebarWithConflicts') + - \`sidebar.sidebarWithConflicts.category.COMMON LABEL\`: 2 duplicates found: - COMMON LABEL (The label for category 'COMMON LABEL' in sidebar 'sidebarWithConflicts') - COMMON LABEL (The label for category 'COMMON LABEL' in sidebar 'sidebarWithConflicts') From 41df6863dda979286f208e8ccaac1e401cf71d7f Mon Sep 17 00:00:00 2001 From: sebastien Date: Thu, 19 Feb 2026 14:54:34 +0100 Subject: [PATCH 5/5] increase test timeout on windows --- jest.config.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jest.config.mjs b/jest.config.mjs index ca2be525b050..3d6ac4dfca18 100644 --- a/jest.config.mjs +++ b/jest.config.mjs @@ -34,7 +34,7 @@ export default { verbose: true, // Default 5s timeout often fails on Windows :s, // see https://github.com/facebook/docusaurus/pull/8259 - testTimeout: 15000, + testTimeout: 25000, setupFiles: ['./jest/setup.ts'], testEnvironmentOptions: { url: 'https://docusaurus.io/',