Add initial implementation of sidebar keys

This commit is contained in:
sebastien 2025-06-27 15:45:09 +02:00
parent 222a077d85
commit 3a5010a83a
9 changed files with 349 additions and 34 deletions

View file

@ -7,6 +7,7 @@
import _ from 'lodash';
import {mergeTranslations} from '@docusaurus/utils';
import logger from '@docusaurus/logger';
import {CURRENT_VERSION_NAME} from './constants';
import {
collectSidebarCategories,
@ -40,20 +41,50 @@ function getVersionFileName(versionName: string): string {
return `version-${versionName}`;
}
type TranslationMessageEntry = [string, TranslationMessage];
function ensureNoSidebarDuplicateEntries(
translationEntries: TranslationMessageEntry[],
): void {
const grouped = _.groupBy(translationEntries, (entry) => entry[0]);
const duplicates = Object.entries(grouped).filter(
(entry) => entry[1].length > 1,
);
if (duplicates.length > 0) {
throw new Error(`Multiple docs sidebar items produce the same translation key.
- ${duplicates
.map(([translationKey, entries]) => {
return `${translationKey}: ${
entries.length
} duplicates found:\n - ${entries
.map((duplicate) => {
return logger.interpolate`name=${duplicate[1].message} (subdue=${duplicate[1].description})}`;
})
.join('\n - ')}`;
})
.join('\n\n- ')}
To avoid translation key conflicts, use the ${logger.code(
'key',
)} attribute on the sidebar items above to uniquely identify them.
`);
}
}
function getSidebarTranslationFileContent(
sidebar: Sidebar,
sidebarName: string,
): TranslationFileContent {
type TranslationMessageEntry = [string, TranslationMessage];
const categories = collectSidebarCategories(sidebar);
const categoryEntries: TranslationMessageEntry[] = categories.flatMap(
(category) => {
const entries: TranslationMessageEntry[] = [];
const categoryKey = category.key ?? category.label;
entries.push([
`sidebar.${sidebarName}.category.${category.label}`,
`sidebar.${sidebarName}.category.${categoryKey}`,
{
message: category.label,
description: `The label for category ${category.label} in sidebar ${sidebarName}`,
@ -63,7 +94,7 @@ function getSidebarTranslationFileContent(
if (category.link?.type === 'generated-index') {
if (category.link.title) {
entries.push([
`sidebar.${sidebarName}.category.${category.label}.link.generated-index.title`,
`sidebar.${sidebarName}.category.${categoryKey}.link.generated-index.title`,
{
message: category.link.title,
description: `The generated-index page title for category ${category.label} in sidebar ${sidebarName}`,
@ -72,7 +103,7 @@ function getSidebarTranslationFileContent(
}
if (category.link.description) {
entries.push([
`sidebar.${sidebarName}.category.${category.label}.link.generated-index.description`,
`sidebar.${sidebarName}.category.${categoryKey}.link.generated-index.description`,
{
message: category.link.description,
description: `The generated-index page description for category ${category.label} in sidebar ${sidebarName}`,
@ -85,45 +116,37 @@ function getSidebarTranslationFileContent(
},
);
_.chain(categoryEntries)
.groupBy((entry) => entry[0])
.forEach((group, key) => {
if (group.length > 1) {
console.warn(`KEY CONFLICT FOR key = ${key}`, group.length);
}
})
.value();
const categoryContent: TranslationFileContent =
Object.fromEntries(categoryEntries);
const links = collectSidebarLinks(sidebar);
const linksContent: TranslationFileContent = Object.fromEntries(
links.map((link) => [
`sidebar.${sidebarName}.link.${link.label}`,
const linksEntries: TranslationMessageEntry[] = links.map((link) => {
const linkKey = link.key ?? link.label;
return [
`sidebar.${sidebarName}.link.${linkKey}`,
{
message: link.label,
description: `The label for link ${link.label} in sidebar ${sidebarName}, linking to ${link.href}`,
},
]),
);
];
});
const docs = collectSidebarDocItems(sidebar)
.concat(collectSidebarRefs(sidebar))
.filter((item) => item.translatable);
const docLinksContent: TranslationFileContent = Object.fromEntries(
docs.map((doc) => [
`sidebar.${sidebarName}.doc.${doc.label!}`,
const docLinksEntries: TranslationMessageEntry[] = docs.map((doc) => {
const docKey = doc.key ?? doc.label!;
return [
`sidebar.${sidebarName}.doc.${docKey}`,
{
message: doc.label!,
description: `The label for the doc item ${doc.label!} in sidebar ${sidebarName}, linking to the doc ${
doc.id
}`,
},
]),
);
];
});
return mergeTranslations([categoryContent, linksContent, docLinksContent]);
const allEntries = [...categoryEntries, ...linksEntries, ...docLinksEntries];
ensureNoSidebarDuplicateEntries(allEntries);
return Object.fromEntries(allEntries);
}
function translateSidebar({
@ -162,27 +185,30 @@ function translateSidebar({
return transformSidebarItems(sidebar, (item) => {
if (item.type === 'category') {
const link = transformSidebarCategoryLink(item);
const categoryKey = item.key ?? item.label;
return {
...item,
label:
sidebarsTranslations[`sidebar.${sidebarName}.category.${item.label}`]
sidebarsTranslations[`sidebar.${sidebarName}.category.${categoryKey}`]
?.message ?? item.label,
...(link && {link}),
};
}
if (item.type === 'link') {
const linkKey = item.key ?? item.label;
return {
...item,
label:
sidebarsTranslations[`sidebar.${sidebarName}.link.${item.label}`]
sidebarsTranslations[`sidebar.${sidebarName}.link.${linkKey}`]
?.message ?? item.label,
};
}
if ((item.type === 'doc' || item.type === 'ref') && item.translatable) {
const docKey = item.key ?? item.label!;
return {
...item,
label:
sidebarsTranslations[`sidebar.${sidebarName}.doc.${item.label!}`]
sidebarsTranslations[`sidebar.${sidebarName}.doc.${docKey}`]
?.message ?? item.label,
};
}