Skip to content

Commit 5150037

Browse files
committed
Add machine-translated docs sites for zh-CN, ja, ko and pt-BR
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.
1 parent a4f4ccd commit 5150037

43 files changed

Lines changed: 5870 additions & 32 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
# Generated
22
uv.lock linguist-generated=true
3+
i18n/*/pages/** linguist-generated=true
4+
i18n/*/state.json linguist-generated=true
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
name: 🌐 Translation problem
2+
description: Report a wrong, awkward, or misleading passage in a translated docs page
3+
labels: ["translation"]
4+
5+
body:
6+
- type: markdown
7+
attributes:
8+
value: |
9+
The translated docs are machine-generated from the English pages; https://py.sdk.modelcontextprotocol.io/translations/ explains how.
10+
Fixes never go into the translated text directly. They go into that language's glossary or style guide under `i18n/`, so you can also open a PR there instead of an issue.
11+
12+
- type: dropdown
13+
id: language
14+
attributes:
15+
label: Language
16+
options:
17+
- Simplified Chinese (zh-CN)
18+
- Japanese (ja)
19+
- Korean (ko)
20+
- Brazilian Portuguese (pt-BR)
21+
validations:
22+
required: true
23+
24+
- type: input
25+
id: page
26+
attributes:
27+
label: Page URL
28+
description: The translated page where you found the problem.
29+
placeholder: https://py.sdk.modelcontextprotocol.io/ja/servers/tools/
30+
validations:
31+
required: true
32+
33+
- type: textarea
34+
id: passage
35+
attributes:
36+
label: The passage
37+
description: Quote the translated text that's wrong, and the English it corresponds to if you have it.
38+
validations:
39+
required: true
40+
41+
- type: textarea
42+
id: problem
43+
attributes:
44+
label: What's wrong, or how it should read
45+
description: A wrong term, awkward phrasing, meaning that drifted from the English, tone that's off. If you know the better rendering, give it.
46+
validations:
47+
required: true
48+
49+
- type: dropdown
50+
id: native-speaker
51+
attributes:
52+
label: Are you a native or fluent speaker of this language?
53+
options:
54+
- "Yes"
55+
- "No"
56+
validations:
57+
required: true

.github/workflows/deploy-docs.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ on:
1212
# docs pages include their code blocks from these files via `--8<--`, so a
1313
# change here changes the rendered site even when no .md file moves.
1414
- docs_src/**
15+
# the translated pages and the language registry feed the language sites
16+
- i18n/**
1517
- mkdocs.yml
1618
- src/mcp/**
1719
- src/mcp-types/**

.github/workflows/docs-preview.yml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ on:
2121
paths:
2222
- docs/**
2323
- docs_src/**
24+
- i18n/**
2425
- mkdocs.yml
2526
- scripts/docs/**
2627
- pyproject.toml
@@ -137,7 +138,17 @@ jobs:
137138
# /preview-docs, still build with MkDocs. Both arms must write the site
138139
# to site/. Keep the detection in sync with build_site() in
139140
# scripts/build-docs.sh.
140-
- run: |
141+
#
142+
# DOCS_SITE_URL is the preview's Cloudflare branch-alias host (deploy
143+
# publishes to `--branch=pr-<N>`, served at pr-<N>.<project>.pages.dev),
144+
# so the absolute links the build bakes (language switcher, language
145+
# sites' links into the English API reference) point at the preview
146+
# instead of production; empty when no Pages project is configured, which
147+
# makes build.sh fall back to the production site_url.
148+
- env:
149+
DOCS_SITE_URL: >-
150+
${{ vars.CLOUDFLARE_PAGES_PROJECT && format('https://pr-{0}.{1}.pages.dev', needs.authorize.outputs.pr_number, vars.CLOUDFLARE_PAGES_PROJECT) || '' }}
151+
run: |
141152
if [ -f scripts/docs/build.sh ]; then
142153
bash scripts/docs/build.sh
143154
else

.gitignore

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,13 @@ venv.bak/
144144
# documentation
145145
/site
146146
/.worktrees/
147-
# Generated at build time by scripts/docs/ (the API reference tree and the
148-
# concrete Zensical config spliced from mkdocs.yml).
147+
# Generated at build time by scripts/docs/ (the API reference tree, the
148+
# concrete Zensical configs spliced from mkdocs.yml, and the staged
149+
# per-language docs trees).
149150
/docs/api/
151+
/.build/
150152
/mkdocs.gen.yml
153+
/mkdocs.*.gen.yml
151154

152155
# mypy
153156
.mypy_cache/

.pre-commit-config.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ repos:
2525
"/tool/markdown/lint",
2626
]
2727
types: [markdown]
28+
# Machine-translated pages are generated artefacts: corrections flow
29+
# through i18n/<code>/{instructions.md,glossary.json}, never through
30+
# hand or linter edits to the pages themselves.
31+
exclude: ^i18n/[^/]+/pages/
2832

2933
- repo: local
3034
hooks:

CONTRIBUTING.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ pre-commit run --all-files
126126
- Add type hints to all functions
127127
- Include docstrings for public APIs
128128

129+
## Documentation and Translations
130+
131+
Documentation contributions are English only: the pages under `docs/` are the source of truth, and the translated documentation sites are generated from them, guided by the per-language style guides and glossaries under `i18n/<lang>/`. Never edit the generated pages under `i18n/<lang>/pages/`—the next translation run overwrites them. To fix a translation, change that language's `instructions.md` or `glossary.json` (or the English page, if that's where the problem is), and the fix carries into every future run. See [`i18n/README.md`](i18n/README.md) for the details.
132+
129133
## Pull Requests
130134

131135
By the time you open a PR, the "what" and "why" should already be settled in an issue. This keeps reviews focused on implementation.

docs/translations.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Translations
2+
3+
This documentation is written in English. To make it useful to more people, we also publish it in a few other languages. Those editions are machine-translated, and this page explains what that means for you and how to help improve them.
4+
5+
## What's available
6+
7+
Translated documentation is currently a **preview**: it covers a growing subset of the pages, published in four languages — Simplified Chinese, Japanese, Korean and Brazilian Portuguese. Pick one from the language switcher at the top of any page.
8+
9+
Every translated page opens with a note saying it was machine-translated and linking to its English original. The API reference is not translated: every language site links to the single English one.
10+
11+
## English is the source of truth
12+
13+
If a translated page and its English original disagree, the English page is correct. Two situations are called out on the page itself:
14+
15+
- A page that hasn't been translated yet shows the English text, with a note saying so.
16+
- A page whose English original changed after it was translated carries a warning that it may be behind, until the translation catches up.
17+
18+
## How the translations are made
19+
20+
Translated pages are generated by a tool in this repository from the English pages under `docs/`, guided by two human-written inputs per language: a style guide (register, tone, typography, how to handle jokes and idioms) and a glossary (which terms stay in English, and the required and forbidden renderings for the rest). The generated text is never edited by hand. Every improvement goes into those inputs instead, so it survives the next time the pages are regenerated.
21+
22+
## Reporting a translation problem
23+
24+
Found a wrong term, an awkward sentence, or a translation that says something the English doesn't? [Open a translation issue](https://github.com/modelcontextprotocol/python-sdk/issues/new?template=translation.yaml) with the language, the page and the passage; reports from native speakers are especially valuable, and maintainers track these with the `translation` label. If you know the fix, propose it directly as a pull request against that language's style guide or glossary under [`i18n/`](https://github.com/modelcontextprotocol/python-sdk/tree/main/i18n) — the correction then shows up on every affected page the next time the translations are regenerated. Problems with the English text itself are fixed in the pages under `docs/`, like any other documentation change.

i18n/README.md

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Documentation translations
2+
3+
The English pages under `docs/` are the source of truth. This directory holds
4+
what steers their machine translation (human-authored) and the generated
5+
result; the public-facing explanation is [`docs/translations.md`](../docs/translations.md).
6+
7+
- `languages.yml` — the language registry (one entry per translated site,
8+
served at `/<code>/`), the pages that stay English, the model IDs, and the
9+
English text of the notices staged onto every translated page.
10+
- `general-prompt.md` — the translation rules shared by every language.
11+
- `<code>/instructions.md` — register, voice, humour and typography for one
12+
language. Human-authored.
13+
- `<code>/glossary.json` — the termbase for one language: terms that stay in
14+
English, required renderings, and banned ones (`"enforce": true` makes a ban
15+
a hard check). Human-authored.
16+
- `<code>/pages/` and `<code>/state.json` — generated: the translated pages and
17+
the record of what each was made from (English content and section hashes, prompt
18+
inputs, model, timestamp), plus the translated sidebar labels and notices. Never
19+
edited by hand.
20+
21+
## The tool
22+
23+
`scripts/docs/translations.py` (run from the repository root):
24+
25+
```bash
26+
uv run --frozen --group docs python scripts/docs/translations.py status # missing/outdated/current per language
27+
uv run --frozen --group docs python scripts/docs/translations.py translate --lang ja # translate what is missing or outdated
28+
uv run --frozen --group docs python scripts/docs/translations.py stage --lang ja # the docs tree the ja site builds from
29+
```
30+
31+
`translate` calls the Claude API (set `ANTHROPIC_API_KEY` or
32+
`ANTHROPIC_AUTH_TOKEN`). It re-translates only the `##` sections whose English
33+
changed and carries the rest of the page over byte-for-byte from the previous
34+
translation, then gates the result: heading anchors and code blocks are
35+
re-imposed from the English, the page's structure (headings, code fences,
36+
links, admonitions, glossary rules) is checked with the findings fed back for
37+
another attempt, and a stronger model reviews the meaning against the English.
38+
`--pages a.md b.md` narrows a run (a page that is already current comes back
39+
unchanged), `--fresh` re-translates from scratch instead of updating (every
40+
page when no `--pages` are given — the way to redo a language after a model
41+
change), `--dry-run` shows what it would do, and `--no-verify` skips the
42+
meaning review. A page that failed its gates keeps its previous translation and
43+
the run exits non-zero; translations whose English page has left the nav are
44+
deleted. Everything else is offline; `scripts/docs/build.sh` runs `stage` for
45+
each language and builds it at `site/<code>/`.
46+
47+
## Correcting a translation
48+
49+
Never edit a file under `<code>/pages/` — the next run overwrites it. Fix the
50+
input instead: a wrong term goes into `glossary.json`, a recurring style or
51+
register problem into `instructions.md`, and ambiguous English into the page
52+
under `docs/`. Editing a glossary or instructions marks that language's pages
53+
outdated, so the next `translate` run regenerates them with the fix in place.
54+
Readers report problems through the "Translation problem" issue form.
55+
56+
## Staleness
57+
58+
A page is *current* when the English content and the prompt inputs it was
59+
translated from are unchanged, *outdated* otherwise, and *missing* when it has
60+
no translation. The build serves an outdated translation with a warning
61+
notice, unless the English page's links or heading anchors moved under it —
62+
then the English page is served until the next `translate` run refreshes it.
63+
Untranslated and excluded pages are served in English with a notice.
64+
65+
## Adding a language
66+
67+
Add an entry to `languages.yml` (`code`, native `name`; `theme_language` and
68+
`hreflang` default to the code and must be values the theme knows), write
69+
`<code>/instructions.md` and `<code>/glossary.json` (start from an existing
70+
language), then run `translate --lang <code>` and commit the generated `pages/`
71+
and `state.json`. Also name the language in `docs/translations.md` and the
72+
"Translation problem" issue form's dropdown.

i18n/general-prompt.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Translation rules
2+
3+
You are translating a page of the MCP Python SDK documentation from English into the target language named in the language instructions that follow. The readers are software developers using the SDK.
4+
5+
## Your role
6+
7+
- Write natural, native-quality prose in the target language. The page should read as if a developer who is a native speaker wrote it, not as a translation.
8+
- Keep the meaning exact. Do not add claims, drop caveats, reorder steps, or change the strength of a requirement (must / should / may).
9+
- Follow the language instructions and the glossary strictly. Where the two disagree, the glossary wins.
10+
- Translate the whole page. Never summarise, abridge, or leave a placeholder such as "translation continues below".
11+
12+
## Never translate
13+
14+
Copy the following byte-for-byte from the English source:
15+
16+
- Fenced code blocks: the fence markers, the info string, and every line inside them, including code comments.
17+
- Inline code spans (text between backticks).
18+
- URLs and link destinations, including `#fragment` anchors, and image paths.
19+
- HTML tags and their attribute values.
20+
- Front matter keys (the `key:` part of each front matter line).
21+
- Snippet-include lines containing `--8<--`.
22+
- Code-annotation markers such as `# (1)!`.
23+
- Heading anchor attributes: the `{#some-id}` at the end of a heading (it may also be written with spaces, `{ #some-id }`; copy it exactly as it appears).
24+
- The syntax markers for admonitions, collapsible blocks and content tabs (`!!!`, `???`, `???+`, `///`, `===`) and the block-type keyword that follows them (`note`, `tip`, `warning`, ...).
25+
- Footnote labels (`[^1]`), abbreviation definitions (`*[HTML]: ...`) and emoji shortcodes (`:smile:`).
26+
- Mermaid diagram source inside `mermaid` fences.
27+
28+
Do translate the human-language text around those elements: prose, headings, link text, image alt text, table cells, list items, admonition titles (the quoted text after `!!! type`) and bodies, and content-tab labels (the quoted text after `===`).
29+
30+
## Preserve the structure exactly
31+
32+
The translation must have the same shape as the English source, block for block:
33+
34+
- The same headings, at the same levels, in the same order, each ending in the same `{#anchor}` attribute as the source.
35+
- The same number and type of admonitions, collapsible blocks and content-tab groups, in the same order.
36+
- The same tables, with the same number of rows and columns.
37+
- The same lists (same nesting, same number of items) and the same code fences (same count, same info strings, identical contents).
38+
- The same links and images, in the same order. Never add, remove or merge a link.
39+
- The same footnotes, and the same blank lines separating blocks.
40+
41+
Do not add explanatory notes, translator's remarks or extra examples.
42+
43+
## Links and anchors
44+
45+
- Keep every link destination exactly as written in the source, whether it is an absolute URL, a relative path such as `../servers/tools.md`, or a bare `#anchor`. Only the link text is translated.
46+
- Do not add anchors the source does not have, and never rewrite a fragment: heading anchors are pinned in the English source, so the same `#id` is valid on every language site.
47+
- Preserve the link syntax the source uses (Markdown `[text](target)` or HTML `<a href="...">`).
48+
49+
## Updating an existing translation
50+
51+
When the request includes a previous translation of the page and marks which sections of the English page changed:
52+
53+
- Outside the changed sections, reproduce the previous translation verbatim. Do not rephrase, "improve" or re-punctuate text whose English has not changed.
54+
- Inside the changed sections, translate the new English following all of the rules above, and keep terminology, register and tone consistent with the surrounding unchanged text.
55+
- A section is the page's front matter, the text before the first second-level heading, or one second-level heading (`##`) together with everything under it up to the next.
56+
57+
## Output
58+
59+
Return only the translated Markdown document, from its first line to its last. Do not add a preamble, a summary or any commentary, and do not wrap the document in a code fence.

0 commit comments

Comments
 (0)