Skip to content

docs: translated documentation sites and the tooling behind them (slim) - #3265

Draft
maxisbey wants to merge 2 commits into
mainfrom
docs/i18n-slim
Draft

docs: translated documentation sites and the tooling behind them (slim)#3265
maxisbey wants to merge 2 commits into
mainfrom
docs/i18n-slim

Conversation

@maxisbey

@maxisbey maxisbey commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

A leaner redo of #3231: machine-translated preview sites for Simplified
Chinese, Japanese, Korean and Brazilian Portuguese (a few pages each to start),
served at /zh-CN/, /ja/, /ko/ and /pt-BR/ next to the English site.
English stays the single source of truth; everything else is generated and
never hand-edited. Compared to #3231 this is roughly half the diff and about
a fifth of the code, with the English pages untouched.

  • One scriptscripts/docs/translations.py (status, translate,
    stage, languages). translate re-translates only the ## sections
    whose English changed and carries the rest of the page over byte-for-byte
    from the previous translation, then gates the result: heading anchors and
    code blocks are re-imposed from the English rather than validated, the
    structure (sections, headings, fences, links, inline code, admonitions,
    glossary keep/ban rules, abridgement markers, untranslated headings) is
    checked with the findings fed back for up to two more attempts, and a
    stronger model reviews the meaning against the English (one correction
    round; a surviving blocker fails the page).
  • Inputs, not edits — per-language instructions.md (register, voice,
    typography) and glossary.json (termbase, keep-in-English list, banned
    renderings) are the human-authored part; the pages and state.json are
    generated, so a correction goes into the inputs and holds across every
    future run. Sidebar labels and page notices are translated the same way (one
    JSON call per language) and follow the same correction loop.
  • No changes to docs/ — instead of pinning {#anchor} on every English
    heading, each heading's id is computed exactly as the site renders it and
    pinned into the translation, so #fragment links resolve on every language
    site. (Verified against a real build: 511/511 heading ids across 50 pages.)
  • The buildscripts/docs/build.sh builds English into site/, then
    for each language stages the tree (English pages overlaid with that
    language's translations, notices stamped in — machine-translated / may be
    behind the English / shown in English — and links into the API reference
    pointed at the single English one) and builds it strictly into
    site/<code>/. Every config carries the same extra.alternate switcher; a
    language site drops mkdocstrings. Four languages add ~10s to the build.
  • Staleness — each translated page records the English content hash, its
    section hashes and the fingerprint of the prompt inputs it was made from;
    status reports missing / outdated / current. An outdated translation is
    served with a warning notice unless the English page's links or heading
    anchors moved under it — then the English page is served until the next
    translate run refreshes it, so an English edit can never break a language
    build. docs/translations.md explains all this to readers, with an issue
    form for reports.

Motivation and Context

Same as #3231 (make the docs useful to more people, with translations that stay
correctable at the source), redone from scratch to minimise the code the repo
carries: no anchor churn across the English pages, no offline
checker/validator commands duplicating what the build already enforces, and
generated state kept to what the pipeline actually reads.

How Has This Been Tested?

  • Ran the tool end to end against the Claude API: generated the 12 sample
    pages plus the four languages' UI strings, and exercised the staleness
    contract with real edits (prose edit → outdated notice; heading reword →
    translation withdrawn; a one-section English edit re-translates only that
    section and carries the rest over byte-for-byte).
  • Built and served the full site (English + four language sites, all
    --strict) and browsed it: switcher on every page, hreflang alternates,
    translated sidebars and notices, English heading anchors resolving on the
    language sites, API Reference nav entry linking the English reference.
  • Adversarial review of the 12 pages by bilingual reviewers against both the
    English and docs: translated documentation sites and the tooling behind them #3231's translations of the same pages: no meaning blockers;
    the tool's gates were extended (untranslated-heading and inline-code checks)
    for the two structural slips found, and those pages regenerated.
  • tests/test_docs_i18n.py covers the pure logic offline (mechanical repair,
    section carry-forward, the structural gate, the reviewer round-trip with a
    scripted model, staging/withdrawal, status, UI strings).

Breaking Changes

None to the SDK. Docs builds now also produce the four language sites.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

  • Suggested reading order: i18n/general-prompt.md
    i18n/ja/instructions.mddocs/translations.mdi18n/README.md → the
    sample pages under i18n/*/pages/scripts/docs/translations.py (top to
    bottom) → tests/test_docs_i18n.py.
  • Merge checklist: create the translation label the issue form applies.
  • Model access: running translate needs ANTHROPIC_API_KEY (or an auth
    token); nothing in CI calls the API. translate --lang <code> --fresh
    redoes a whole language from scratch (e.g. after changing the model).
  • Coverage is deliberately a preview: 3 pages per language, everything else
    served in English with a notice. Translating the full corpus is one command
    per language whenever we want it.
  • Known limitations (same as docs: translated documentation sites and the tooling behind them #3231): the theme's hreflang alternates point
    at each site root rather than the equivalent page, and CJK search has no
    word segmentation.

AI Disclaimer

Ship preview translations of the docs in Simplified Chinese, Japanese,
Korean and Brazilian Portuguese, served at /zh-CN/, /ja/, /ko/ and /pt-BR/
next to the English site (three pages each to start). English stays the
single source of truth; everything else is generated and never hand-edited.

scripts/docs/translations.py drives it (status / translate / stage /
languages). `translate` re-translates only the `##` sections whose English
changed and carries the rest of the page over byte-for-byte from the previous
translation, then gates the result: heading anchors and code blocks are
re-imposed from the English, the structure (sections, headings, fences, links,
inline code, admonitions, glossary rules) is checked with the findings fed
back for another attempt, and a stronger model reviews the meaning against the
English. Per-language inputs — instructions.md (register, voice, typography)
and glossary.json (termbase, keep-in-English list, banned renderings) — are the
human-edited part; the pages and state.json under i18n/<code>/ are generated,
so a correction goes into the inputs and holds across every future run.

The build stages each language over the English tree (translations overlaid,
notices stamped in — machine-translated, may be behind English, not translated
— and links into the API reference pointed at the English one) and builds it
strictly into site/<code>/. Heading ids are pinned into the translations from
the ids the English site renders, so #fragment links resolve on every language
site without touching the English pages. An outdated translation is served
with a warning unless the English page's links or anchors moved under it, so an
English edit can never break a language build. Every config carries the same
language switcher.
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

📚 Documentation preview

Preview https://pr-3265.mcp-python-docs.pages.dev
Deployment https://ca2d60b9.mcp-python-docs.pages.dev
Commit 3b2927f
Triggered by @maxisbey
Updated 2026-08-07 11:45:16 UTC

The test fixture wrote its throwaway repo tree with the platform default
encoding, which cannot represent the Japanese fixtures on Windows; write it
(and the tool's own generated pages and state) explicitly as UTF-8 with LF
newlines so the output is identical everywhere.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant