Skip to content

Commit 52ad0a8

Browse files
authored
docs: publish translated docs in twelve languages and the tool that maintains them (#3280)
1 parent 14aa889 commit 52ad0a8

658 files changed

Lines changed: 89737 additions & 54 deletions

File tree

Some content is hidden

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

.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+
# translated pages and the language registry feed the site/<code>/ sites
16+
- i18n/**
1517
- mkdocs.yml
1618
- src/mcp/**
1719
- src/mcp-types/**

.github/workflows/docs-preview.yml

Lines changed: 1 addition & 0 deletions
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

.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 docs tree
149+
# of each translated site).
149150
/docs/api/
150151
/mkdocs.gen.yml
152+
/mkdocs.*.gen.yml
153+
/.build/
151154

152155
# mypy
153156
.mypy_cache/

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 tool can't tell a hand edit from its own output, so the edit persists unchecked, is carried forward into future runs, and hides the real fix. 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 re-run `translate --lang <code> --pages <page> …` for the affected pages; the fix then 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/js/language-switch.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// The theme links each language-switcher entry to that language's home page.
2+
// Point the entries at the current page on each language's site instead: every
3+
// prose page exists at the same path on all of them. The API reference is
4+
// English-only, so from there the entries keep pointing at the site roots.
5+
// Instant navigation swaps the page but keeps the header, so re-run on every
6+
// page the theme loads (`document$`) rather than once.
7+
const base = JSON.parse(document.getElementById("__config").textContent).base;
8+
// The site root as a directory path; `base` lacks the trailing slash on 404 pages.
9+
const site = new URL(base.replace(/\/?$/, "/"), location).pathname;
10+
11+
document$.subscribe(() => {
12+
let page = location.pathname.slice(site.length);
13+
if (page.startsWith("api/")) page = "";
14+
for (const entry of document.querySelectorAll(".md-select__link[hreflang]")) {
15+
// The language root the theme rendered, relative to the page first shown.
16+
entry.dataset.site ??= new URL(entry.getAttribute("href"), location).pathname;
17+
entry.href = entry.dataset.site + page;
18+
}
19+
});

docs/translations.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Translations
2+
3+
This documentation is written in English. To make it useful to more people, we also publish machine-translated editions of it, 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** in twelve languages: Deutsch, español, français, हिन्दी, 日本語, 한국어, português (Brasil), русский язык, Türkçe, українська мова, 简体中文 and 繁體中文. Pick one from the language switcher at the top of any page. More languages may follow once these have proved themselves.
8+
9+
The API reference is not translated: the translated 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. Every page of a translated site opens with one of three notes saying where it stands:
14+
15+
- **Machine translation** — the page was translated automatically and links to its English original.
16+
- **Translation behind the English page** — the English original changed after the page was translated. You are still reading that translation, so parts of it may be out of date until it catches up; the note links to the current English page.
17+
- **Shown in English** — the page has not been translated yet, so you are reading the English text.
18+
19+
## How the translations are made
20+
21+
Translated pages are machine-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.
22+
23+
## Reporting a translation problem
24+
25+
Found a wrong term, an awkward sentence, or a translation that says something the English doesn't? [Open an issue](https://github.com/modelcontextprotocol/python-sdk/issues) with the language, the page and the passage; reports from native speakers are especially valuable. If you know the fix, propose it directly as a pull request against that language's style guide (`instructions.md`) or glossary (`glossary.json`) under [`i18n/`](https://github.com/modelcontextprotocol/python-sdk/tree/main/i18n) — the correction then reaches 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: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Documentation translations
2+
3+
The English pages under `docs/` are the source. This directory holds what steers their machine translation and the generated result; [`docs/translations.md`](../docs/translations.md) is the reader-facing explanation.
4+
5+
- `languages.yml` — the registry: one entry per translated site (served at `/<code>/`), the model id, and the nav pages that stay in English.
6+
- `general-prompt.md` — translation rules shared by every language. `notices.md` — English source of the three notes staged onto the pages of a translated site.
7+
- `<code>/instructions.md` (register, voice, typography, terminology) and `<code>/glossary.json` (`keep`: terms that stay in English; `terms`: required renderings, each with an optional `note` and banned `avoid` renderings, which are checked) — human-authored, sent with every request.
8+
- `<code>/pages/**` and `<code>/notices.md`**generated**, never edited by hand: a correction goes into that language's `instructions.md` or `glossary.json` (or the English page), and the affected pages are re-run.
9+
10+
## The tool
11+
12+
```text
13+
uv run --frozen python scripts/docs/translations.py status [--lang CODE]
14+
uv run --frozen --group translate python scripts/docs/translations.py translate --lang CODE [--pages PATH ...]
15+
uv run --frozen python scripts/docs/translations.py stage [--lang CODE]
16+
```
17+
18+
`status` is offline: per language it lists missing, outdated (with the sections that changed), current and removable pages (translations whose English page is gone — `git rm` them). `translate` calls the Claude API (`ANTHROPIC_API_KEY` in the environment; the registry's model, or `DOCS_TRANSLATE_MODEL` to trial another) for the missing and outdated pages, retranslating only the English sections that changed and keeping the rest byte for byte; `--pages` instead re-translates exactly the named pages from scratch, which is also how a glossary or instructions change reaches existing pages (each generated page records the English section hashes it reflects, so editing those inputs invalidates nothing). `stage` assembles the tree each language site is built from (every language's, or one with `--lang`): each generated page exactly as it was generated, under an "outdated" notice linking the current English page when the English has changed since, and the English page where nothing was generated yet; `scripts/docs/build.sh` runs it before building them. Commit the generated pages in an ordinary pull request.
19+
20+
To add a language, add an entry to `languages.yml`, write `<code>/instructions.md` (the sections the `pt` file has) and `<code>/glossary.json`, then run `translate --lang <code>`.

0 commit comments

Comments
 (0)