From 98bac6a0e474d0d9bbe93bc6cb410dbc6331f43e Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 5 Apr 2026 14:29:14 +0100 Subject: [PATCH] docs: generate full locale nav during publish sync --- docs/.i18n/README.md | 3 +- scripts/docs-sync-publish.mjs | 116 +++++++++++++++++++++++++++++++--- 2 files changed, 108 insertions(+), 11 deletions(-) diff --git a/docs/.i18n/README.md b/docs/.i18n/README.md index e0c40b671a0..7e165972ddc 100644 --- a/docs/.i18n/README.md +++ b/docs/.i18n/README.md @@ -32,7 +32,8 @@ Generated locale trees and live translation memory now live in the publish repo: ## Files in this folder - `glossary..json` — preferred term mappings used as prompt guidance. -- `ar-navigation.json`, `de-navigation.json`, `es-navigation.json`, `fr-navigation.json`, `ja-navigation.json`, `ko-navigation.json`, `pt-BR-navigation.json`, `zh-Hans-navigation.json` — Mintlify locale picker blocks reinserted into the publish repo during sync. +- `zh-Hans-navigation.json` — curated zh-Hans Mintlify locale navigation reinserted into the publish repo during sync. +- `ar-navigation.json`, `de-navigation.json`, `es-navigation.json`, `fr-navigation.json`, `ja-navigation.json`, `ko-navigation.json`, `pt-BR-navigation.json` — starter locale metadata kept alongside the source repo, but the publish sync now clones the full English nav tree for these locales so translated pages are visible in Mintlify without hand-maintaining per-locale nav JSON. - `.tm.jsonl` — translation memory keyed by workflow + model + text hash. In this repo, generated locale TM files such as `docs/.i18n/zh-CN.tm.jsonl`, `docs/.i18n/ja-JP.tm.jsonl`, `docs/.i18n/es.tm.jsonl`, `docs/.i18n/pt-BR.tm.jsonl`, `docs/.i18n/ko.tm.jsonl`, `docs/.i18n/de.tm.jsonl`, `docs/.i18n/fr.tm.jsonl`, and `docs/.i18n/ar.tm.jsonl` are intentionally no longer committed. diff --git a/scripts/docs-sync-publish.mjs b/scripts/docs-sync-publish.mjs index ae976c28773..d322f1eafa0 100644 --- a/scripts/docs-sync-publish.mjs +++ b/scripts/docs-sync-publish.mjs @@ -15,14 +15,57 @@ const GENERATED_LOCALES = [ dir: "zh-CN", navFile: "zh-Hans-navigation.json", tmFile: "zh-CN.tm.jsonl", + navMode: "overlay", + }, + { + language: "ja", + dir: "ja-JP", + navFile: "ja-navigation.json", + tmFile: "ja-JP.tm.jsonl", + navMode: "clone-en", + }, + { + language: "es", + dir: "es", + navFile: "es-navigation.json", + tmFile: "es.tm.jsonl", + navMode: "clone-en", + }, + { + language: "pt-BR", + dir: "pt-BR", + navFile: "pt-BR-navigation.json", + tmFile: "pt-BR.tm.jsonl", + navMode: "clone-en", + }, + { + language: "ko", + dir: "ko", + navFile: "ko-navigation.json", + tmFile: "ko.tm.jsonl", + navMode: "clone-en", + }, + { + language: "de", + dir: "de", + navFile: "de-navigation.json", + tmFile: "de.tm.jsonl", + navMode: "clone-en", + }, + { + language: "fr", + dir: "fr", + navFile: "fr-navigation.json", + tmFile: "fr.tm.jsonl", + navMode: "clone-en", + }, + { + language: "ar", + dir: "ar", + navFile: "ar-navigation.json", + tmFile: "ar.tm.jsonl", + navMode: "clone-en", }, - { language: "ja", dir: "ja-JP", navFile: "ja-navigation.json", tmFile: "ja-JP.tm.jsonl" }, - { language: "es", dir: "es", navFile: "es-navigation.json", tmFile: "es.tm.jsonl" }, - { language: "pt-BR", dir: "pt-BR", navFile: "pt-BR-navigation.json", tmFile: "pt-BR.tm.jsonl" }, - { language: "ko", dir: "ko", navFile: "ko-navigation.json", tmFile: "ko.tm.jsonl" }, - { language: "de", dir: "de", navFile: "de-navigation.json", tmFile: "de.tm.jsonl" }, - { language: "fr", dir: "fr", navFile: "fr-navigation.json", tmFile: "fr.tm.jsonl" }, - { language: "ar", dir: "ar", navFile: "ar-navigation.json", tmFile: "ar.tm.jsonl" }, ]; function parseArgs(argv) { @@ -80,6 +123,60 @@ function writeJson(filePath, value) { fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`); } +function prefixLocalePage(entry, localeDir) { + if (typeof entry === "string") { + return `${localeDir}/${entry}`; + } + if (Array.isArray(entry)) { + return entry.map((item) => prefixLocalePage(item, localeDir)); + } + if (!entry || typeof entry !== "object") { + return entry; + } + + const clone = { ...entry }; + if (typeof clone.page === "string") { + clone.page = `${localeDir}/${clone.page}`; + } + if (Array.isArray(clone.pages)) { + clone.pages = clone.pages.map((item) => prefixLocalePage(item, localeDir)); + } + return clone; +} + +function cloneEnglishLanguageNav(englishNav, locale) { + if (!englishNav) { + throw new Error("docs/docs.json is missing navigation.languages.en"); + } + return { + ...englishNav, + language: locale.language, + tabs: Array.isArray(englishNav.tabs) + ? englishNav.tabs.map((tab) => ({ + ...tab, + pages: Array.isArray(tab.pages) + ? tab.pages.map((entry) => prefixLocalePage(entry, locale.dir)) + : tab.pages, + groups: Array.isArray(tab.groups) + ? tab.groups.map((group) => ({ + ...group, + pages: Array.isArray(group.pages) + ? group.pages.map((entry) => prefixLocalePage(entry, locale.dir)) + : group.pages, + })) + : tab.groups, + })) + : englishNav.tabs, + }; +} + +function composeLocaleNav(locale, englishNav) { + if (locale.navMode === "clone-en") { + return cloneEnglishLanguageNav(englishNav, locale); + } + return readJson(path.join(SOURCE_DOCS_DIR, ".i18n", locale.navFile)); +} + function composeDocsConfig() { const sourceConfig = readJson(SOURCE_CONFIG_PATH); const languages = sourceConfig?.navigation?.languages; @@ -88,12 +185,11 @@ function composeDocsConfig() { throw new Error("docs/docs.json is missing navigation.languages"); } + const englishNav = languages.find((entry) => entry?.language === "en"); const generatedLanguageSet = new Set(GENERATED_LOCALES.map((entry) => entry.language)); const withoutGenerated = languages.filter((entry) => !generatedLanguageSet.has(entry?.language)); const enIndex = withoutGenerated.findIndex((entry) => entry?.language === "en"); - const generated = GENERATED_LOCALES.map((entry) => - readJson(path.join(SOURCE_DOCS_DIR, ".i18n", entry.navFile)), - ); + const generated = GENERATED_LOCALES.map((entry) => composeLocaleNav(entry, englishNav)); if (enIndex === -1) { withoutGenerated.push(...generated); } else {