From 4ec60643178db3f8a08fd339df709d1c28be0ddc Mon Sep 17 00:00:00 2001 From: Xavi Lee Date: Thu, 8 Jan 2026 21:25:26 +0800 Subject: [PATCH 1/2] feat: add localization support for sidebar navigation in documentation This update introduces localization mappings for sidebar display text, allowing for titles and summaries to be presented in Chinese. The changes include a new `sidebarI18n` object for managing translations and modifications to the navigation generation logic to utilize localized titles and summaries while maintaining stable English-based IDs. --- .../generateDocsNavigationPerLanguage.js | 79 +++++++++++++++++-- 1 file changed, 72 insertions(+), 7 deletions(-) diff --git a/packages/documentation/scripts/generateDocsNavigationPerLanguage.js b/packages/documentation/scripts/generateDocsNavigationPerLanguage.js index e7cc3d88..446a727c 100644 --- a/packages/documentation/scripts/generateDocsNavigationPerLanguage.js +++ b/packages/documentation/scripts/generateDocsNavigationPerLanguage.js @@ -25,6 +25,52 @@ const { read: readMarkdownFile } = require("gray-matter"); pnpm run --filter=documentation create-handbook-nav */ +// Localization mappings for sidebar display text (titles and summaries). +// The `id` generation always uses the English title to keep anchors stable. +/** @type {Record>} */ +const sidebarI18n = { + zh: { + // Section titles and summaries + "Get Started": { title: "快速开始", summary: "根据你的背景或偏好快速入门。" }, + "Handbook": { title: "手册", summary: "日常 TypeScript 工作的绝佳入门读物。" }, + "Reference": { title: "参考", summary: "深入的参考资料。" }, + "Modules Reference": { title: "模块参考", summary: "TypeScript 如何处理 JavaScript 模块。" }, + "Tutorials": { title: "教程", summary: "在各种环境中使用 TypeScript。" }, + "What's New": { title: "新增功能", summary: "了解 TypeScript 的发展历程和各版本的新增功能。" }, + "Declaration Files": { title: "声明文件", summary: "学习如何编写声明文件来描述现有的 JavaScript。对 DefinitelyTyped 贡献很重要。" }, + "JavaScript": { title: "JavaScript", summary: "如何使用 TypeScript 驱动的 JavaScript 工具。" }, + "Project Configuration": { title: "项目配置", summary: "编译器配置参考。" }, + // Sub-section titles (non-file items) + "Type Manipulation": { title: "类型操作" }, + "Guides": { title: "指南" }, + "Appendices": { title: "附录" }, + ".d.ts Templates": { title: ".d.ts 模板" }, + // Special link items + "Cheat Sheets": { title: "速查表", summary: "常见代码的语法概览" }, + "TSConfig Reference": { title: "TSConfig 参考", summary: "涵盖所有 TSConfig 选项的页面" }, + // Modules Reference sub-items with explicit titles + "Introduction": { title: "简介" }, + "Theory": { title: "理论" }, + // "Reference" is already defined above (used for both section and sub-item) + "Choosing Compiler Options": { title: "选择编译器选项" }, + }, +}; + +/** + * Get localized text for a given key, with fallback to original. + * @param {string} lang + * @param {string} key - The English text to look up + * @param {"title" | "summary"} field + * @returns {string} + */ +function getLocalizedText(lang, key, field) { + const langMap = sidebarI18n[lang]; + if (langMap && langMap[key] && langMap[key][field]) { + return langMap[key][field]; + } + return field === "summary" ? key : key; // fallback to original +} + /** @type {HandbookNavItem[]} */ // prettier-ignore const handbookPages = [ @@ -244,10 +290,16 @@ for (const lang of langs) { codeForTheHandbook.push(`navigations.${lang} = [`); handbookPages.forEach((section, sectionIndex) => { - // Section metadata: + // Section metadata (use localized title/summary for display, but keep id based on English title) + const localizedTitle = getLocalizedText(lang, section.title, "title"); + // Look up summary using the section title as key (not the summary text itself) + const langMap = sidebarI18n[lang]; + const localizedSummary = (langMap && langMap[section.title] && langMap[section.title].summary) + ? langMap[section.title].summary + : section.summary; codeForTheHandbook.push(`{ - title: "${section.title}", - oneline: "${section.summary}", + title: "${localizedTitle}", + oneline: "${localizedSummary}", id: "${section.title.toLowerCase().replace(/\s/g, "-")}", chronological: ${section.chronological || false}, `); @@ -263,16 +315,25 @@ for (const lang of langs) { // Is it a special link? if ("href" in subItem) { + // Use localized title/oneliner for display, keep id based on English title + const localizedLinkTitle = getLocalizedText(lang, subItem.title, "title"); + // Look up oneliner using the link title as key + const linkLangMap = sidebarI18n[lang]; + const localizedLinkOneliner = (linkLangMap && linkLangMap[subItem.title] && linkLangMap[subItem.title].summary) + ? linkLangMap[subItem.title].summary + : subItem.oneliner; codeForTheHandbook.push(` - title: "${subItem.title}", + title: "${localizedLinkTitle}", id: "${toID(sectionIndex, subItem.title)}", permalink: "${subItem.href}", - oneline: "${subItem.oneliner}" + oneline: "${localizedLinkOneliner}" },`); } else if ("items" in subItem) { //Is is a sub-sub-section? + // Use localized title for display, keep id based on English title + const localizedSubTitle = getLocalizedText(lang, subItem.title, "title"); codeForTheHandbook.push(` - title: "${subItem.title}", + title: "${localizedSubTitle}", id: "${toID(sectionIndex, subItem.title)}", oneline: "${subItem.oneliner}", chronological: ${subItem.chronological || false}, @@ -284,12 +345,16 @@ for (const lang of langs) { const subNavInfo = langInfo[lang].get(subItem.file) || langInfo["en"].get(subItem.file); + // Get English info for stable id generation + const enNavInfo = langInfo["en"].get(subItem.file); if (!subNavInfo) throwForUnfoundFile(subItem, lang, langInfo["en"]); + // Use localized title from frontmatter, but keep id based on English title + const enTitle = enNavInfo ? enNavInfo.data.title : subNavInfo.data.title; codeForTheHandbook.push(` title: "${subNavInfo.data.short || subNavInfo.data.title}", - id: "${toID(sectionIndex, subNavInfo.data.title)}", + id: "${toID(sectionIndex, enTitle)}", permalink: "${subNavInfo.data.permalink}", oneline: "${subNavInfo.data.oneline}", `); From 647b21e106161a4587269ee3d9b26c057d2f5811 Mon Sep 17 00:00:00 2001 From: Xavi Lee Date: Thu, 8 Jan 2026 22:00:52 +0800 Subject: [PATCH 2/2] refactor: move sidebar localization data to separate module This change refactors the sidebar localization logic by moving the localization mappings from the main script to a dedicated `sidebarLocales.js` module. The navigation generation logic has been updated to utilize this new module, improving code organization and maintainability. --- .../generateDocsNavigationPerLanguage.js | 40 ++------ .../documentation/scripts/sidebarLocales.js | 95 +++++++++++++++++++ 2 files changed, 101 insertions(+), 34 deletions(-) create mode 100644 packages/documentation/scripts/sidebarLocales.js diff --git a/packages/documentation/scripts/generateDocsNavigationPerLanguage.js b/packages/documentation/scripts/generateDocsNavigationPerLanguage.js index 446a727c..a5168319 100644 --- a/packages/documentation/scripts/generateDocsNavigationPerLanguage.js +++ b/packages/documentation/scripts/generateDocsNavigationPerLanguage.js @@ -5,6 +5,7 @@ const { join } = require("path"); const { format } = require("prettier"); const { enRoot, getFilePaths } = require("./generateTypesForFilesInDocs"); const { read: readMarkdownFile } = require("gray-matter"); +const { sidebarLocales } = require("./sidebarLocales"); // This file is the definitive sidebar navigation source. It takes either: // @@ -23,38 +24,9 @@ const { read: readMarkdownFile } = require("gray-matter"); /* Run this after any changes to propagate: pnpm run --filter=documentation create-handbook-nav -*/ -// Localization mappings for sidebar display text (titles and summaries). -// The `id` generation always uses the English title to keep anchors stable. -/** @type {Record>} */ -const sidebarI18n = { - zh: { - // Section titles and summaries - "Get Started": { title: "快速开始", summary: "根据你的背景或偏好快速入门。" }, - "Handbook": { title: "手册", summary: "日常 TypeScript 工作的绝佳入门读物。" }, - "Reference": { title: "参考", summary: "深入的参考资料。" }, - "Modules Reference": { title: "模块参考", summary: "TypeScript 如何处理 JavaScript 模块。" }, - "Tutorials": { title: "教程", summary: "在各种环境中使用 TypeScript。" }, - "What's New": { title: "新增功能", summary: "了解 TypeScript 的发展历程和各版本的新增功能。" }, - "Declaration Files": { title: "声明文件", summary: "学习如何编写声明文件来描述现有的 JavaScript。对 DefinitelyTyped 贡献很重要。" }, - "JavaScript": { title: "JavaScript", summary: "如何使用 TypeScript 驱动的 JavaScript 工具。" }, - "Project Configuration": { title: "项目配置", summary: "编译器配置参考。" }, - // Sub-section titles (non-file items) - "Type Manipulation": { title: "类型操作" }, - "Guides": { title: "指南" }, - "Appendices": { title: "附录" }, - ".d.ts Templates": { title: ".d.ts 模板" }, - // Special link items - "Cheat Sheets": { title: "速查表", summary: "常见代码的语法概览" }, - "TSConfig Reference": { title: "TSConfig 参考", summary: "涵盖所有 TSConfig 选项的页面" }, - // Modules Reference sub-items with explicit titles - "Introduction": { title: "简介" }, - "Theory": { title: "理论" }, - // "Reference" is already defined above (used for both section and sub-item) - "Choosing Compiler Options": { title: "选择编译器选项" }, - }, -}; + Sidebar localization data is in: ./sidebarLocales.js +*/ /** * Get localized text for a given key, with fallback to original. @@ -64,7 +36,7 @@ const sidebarI18n = { * @returns {string} */ function getLocalizedText(lang, key, field) { - const langMap = sidebarI18n[lang]; + const langMap = sidebarLocales[lang]; if (langMap && langMap[key] && langMap[key][field]) { return langMap[key][field]; } @@ -293,7 +265,7 @@ for (const lang of langs) { // Section metadata (use localized title/summary for display, but keep id based on English title) const localizedTitle = getLocalizedText(lang, section.title, "title"); // Look up summary using the section title as key (not the summary text itself) - const langMap = sidebarI18n[lang]; + const langMap = sidebarLocales[lang]; const localizedSummary = (langMap && langMap[section.title] && langMap[section.title].summary) ? langMap[section.title].summary : section.summary; @@ -318,7 +290,7 @@ for (const lang of langs) { // Use localized title/oneliner for display, keep id based on English title const localizedLinkTitle = getLocalizedText(lang, subItem.title, "title"); // Look up oneliner using the link title as key - const linkLangMap = sidebarI18n[lang]; + const linkLangMap = sidebarLocales[lang]; const localizedLinkOneliner = (linkLangMap && linkLangMap[subItem.title] && linkLangMap[subItem.title].summary) ? linkLangMap[subItem.title].summary : subItem.oneliner; diff --git a/packages/documentation/scripts/sidebarLocales.js b/packages/documentation/scripts/sidebarLocales.js new file mode 100644 index 00000000..21383bef --- /dev/null +++ b/packages/documentation/scripts/sidebarLocales.js @@ -0,0 +1,95 @@ +// @ts-check +/** + * Sidebar localization data for documentation navigation. + * + * To add a new language: + * 1. Add a new key (e.g., "ja", "ko") to sidebarLocales + * 2. Translate the titles and summaries + * 3. Run: pnpm run --filter=documentation create-handbook-nav + * + * Note: The `id` generation always uses the English title to keep anchors/URLs stable. + * Only display text (title/summary) should be translated here. + */ + +/** @type {Record>} */ +const sidebarLocales = { + zh: { + // ============================================ + // Section titles and summaries (顶级章节) + // ============================================ + "Get Started": { + title: "快速开始", + summary: "根据你的背景或偏好快速入门。" + }, + "Handbook": { + title: "手册", + summary: "日常 TypeScript 工作的绝佳入门读物。" + }, + "Reference": { + title: "参考", + summary: "深入的参考资料。" + }, + "Modules Reference": { + title: "模块参考", + summary: "TypeScript 如何处理 JavaScript 模块。" + }, + "Tutorials": { + title: "教程", + summary: "在各种环境中使用 TypeScript。" + }, + "What's New": { + title: "新增功能", + summary: "了解 TypeScript 的发展历程和各版本的新增功能。" + }, + "Declaration Files": { + title: "声明文件", + summary: "学习如何编写声明文件来描述现有的 JavaScript。对 DefinitelyTyped 贡献很重要。" + }, + "JavaScript": { + title: "JavaScript", + summary: "如何使用 TypeScript 驱动的 JavaScript 工具。" + }, + "Project Configuration": { + title: "项目配置", + summary: "编译器配置参考。" + }, + + // ============================================ + // Sub-section titles (子章节,非文件引用) + // ============================================ + "Type Manipulation": { title: "类型操作" }, + "Guides": { title: "指南" }, + "Appendices": { title: "附录" }, + ".d.ts Templates": { title: ".d.ts 模板" }, + + // ============================================ + // Special link items (特殊链接) + // ============================================ + "Cheat Sheets": { + title: "速查表", + summary: "常见代码的语法概览" + }, + "TSConfig Reference": { + title: "TSConfig 参考", + summary: "涵盖所有 TSConfig 选项的页面" + }, + + // ============================================ + // Modules Reference sub-items (模块参考子项) + // ============================================ + "Introduction": { title: "简介" }, + "Theory": { title: "理论" }, + "Choosing Compiler Options": { title: "选择编译器选项" }, + // Note: "Reference" is already defined above (used for both section and sub-item) + }, + + // ============================================ + // Add more languages here, e.g.: + // ============================================ + // ja: { + // "Get Started": { title: "はじめに", summary: "..." }, + // ... + // }, +}; + +module.exports = { sidebarLocales };