Translations¶
The docs site ships in the same 16 languages as the product: en plus zh, ar, hi, es, fr, pt, ru, de, ja, ko, it, id, vi, tr, ur. That list mirrors LOCALES in lib/i18n/config.ts — the app and the docs deliberately support the same set, so a reader who uses the site in Japanese isn’t dropped into English documentation.
ar and ur are right-to-left, matching RTL_LOCALES in the same module.
English is authoritative. Everything is written in English first and translated from it.
How it works¶
Sphinx uses gettext. Catalogs live in docs/locale/<lang>/LC_MESSAGES/, one .po file per document (gettext_compact = False), and fall back per string: an untranslated paragraph renders in English while the rest of the page stays translated. A partially translated page is therefore usable rather than broken, which is what makes incremental translation viable at all.
Coverage¶
Translations are maintained for the reader-facing pages:
Page |
Why |
|---|---|
|
The docs landing page. |
|
What the platform is. |
|
Overview, authentication, scopes, rate limits, errors, pagination, idempotency, webhooks, changelog. |
Deliberately not translated:
developer-api/endpoints/*— the generated endpoint reference. It is mostly HTTP verbs, paths, JSON bodies and one-line summaries; the translatable fraction is small, and it regenerates whenever the registry changes, which would invalidate the translations on every API change.developer-api/internals.mdand the rest ofdocs/— ~190 dated design docs, plans, audits and per-game specs. These are internal working documents written for contributors, they churn constantly, and machine-translating them would add tens of thousands of catalog entries that nobody reads.
The subset lives in TRANSLATED in scripts/docs-i18n.sh. To start translating another page, add its docname there and run extract then update.
Workflow¶
pip install -r docs/requirements.txt sphinx-intl
scripts/docs-i18n.sh extract # English sources → .pot
scripts/docs-i18n.sh update # merge into every locale's .po
scripts/docs-i18n.sh build ja # build one language locally
scripts/docs-i18n.sh stats # per-locale translated/untranslated counts
update merges: a string whose English text changed is marked fuzzy with its old translation kept, rather than silently discarded. Fuzzy entries are ignored at build time — the page falls back to English for that string until someone re-translates it. So editing English prose degrades a translation gracefully instead of leaving a stale claim in place, which is the failure mode that matters.
Rules for translators¶
Never touch
msgid. Only fill inmsgstr.Leave the contents of inline code spans in English — identifiers, file paths, HTTP header names, scope ids, error codes and route paths are part of the API, not prose.
`read:profile`is a literal value a developer types.Preserve Markdown and MyST syntax exactly, including directive names (```{note}), roles, and link targets. Translate link text, never the target.
Don’t translate brand names or URLs.
For
arandur, do not insert Unicode directional control marks. Pages render withdir="rtl"and the browser’s bidi algorithm handles mixed-script runs; embedded control characters corrupt output and are invisible in review.
Read the Docs setup¶
Read the Docs models translations as separate projects linked to a parent, not as one multilingual build. For each language:
Create a project pointing at the same repository, named e.g.
rmhstudios-ja.Set its Language to that locale in the project’s settings.
On the English project, add it under Translations.
RTD then passes -D language=<code> to Sphinx and serves the result at /<code>/, with the language switcher in the flyout wired up automatically. docs/conf.py sets language = "en" and is otherwise identical across every project — nothing per-language is committed except the catalogs.