This tutorial walks through adding support for a new target language — for example, adding Japanese (ja) to a project that already has Chinese (zh-cn). By the end, you’ll have:
A language configuration with language-specific translation rules
A glossary for consistent technical terminology
A new target repository with automated sync
Time: ~1 hour for configuration, plus translation time (~$0.16/lecture)
Overview¶
Adding a new language involves four areas:
Step 1: Create a glossary (glossary/ja.json)
Step 2: Add language-specific rules (language-config.ts)
Step 3: Set up the target repository (translate setup + init)
Step 4: Configure multi-language workflows (.github/workflows/)Steps 1–2 are one-time project contributions (merged into action-translation). Steps 3–4 are per-project setup.
Step 1: Create a glossary¶
The glossary ensures consistent translation of technical terms. Each glossary is a JSON file at glossary/{code}.json.
Start from an existing glossary¶
Copy an existing glossary as a template:
cd /path/to/action-translation
cp glossary/zh-cn.json glossary/ja.jsonEdit the glossary¶
Update the file with Japanese translations. The format:
{
"version": "1.0",
"description": "Translation glossary for QuantEcon lectures (English to Japanese)",
"terms": [
{
"en": "utility function",
"ja": "効用関数",
"context": "economics"
},
{
"en": "Bellman equation",
"ja": "ベルマン方程式",
"context": "dynamic programming"
},
{
"en": "steady state",
"ja": "定常状態",
"context": "macroeconomics"
}
]
}Each term has:
| Field | Description |
|---|---|
en | English source term |
{lang-code} | Translation in the target language (must match the language code) |
context | Domain hint for disambiguation (e.g., “economics”, “statistics”, “programming”) |
Quality guidelines¶
Use established translations from authoritative academic sources
Include context when a term has multiple translations in different fields
Prefer commonly accepted academic translations over literal translations
Keep terms concise — short phrases, not full sentences
Cover key domains: economics, mathematics, statistics, programming, named theorists
The existing glossaries have 357 terms organized across:
Economic terms (~160): equilibrium, GDP, fiscal policy, etc.
Mathematical terms (~100): matrix, eigenvalue, convergence, etc.
Statistical terms (~35): normal distribution, regression, variance, etc.
Economist names (~45): Robert Solow, Milton Friedman, etc.
You don’t need all 357 terms from day one. Start with the most important terms and expand over time.
Step 2: Add language-specific rules¶
Language rules control how Claude handles language-specific formatting in translations. They’re defined in src/language-config.ts.
What rules do¶
Rules are injected into every translation prompt. They tell Claude about punctuation conventions, typography, and style expectations specific to the target language. Without rules, Claude uses its general knowledge (which usually works but may be inconsistent).
Current configurations¶
| Language | Key rules |
|---|---|
zh-cn (Chinese) | Use full-width punctuation: , : 。 ! ? (not ASCII) |
fa (Farsi) | Use Persian punctuation: ، ؛ ؟; keep technical terms in English; formal/academic style |
Add a new language entry¶
Edit src/language-config.ts and add an entry to the LANGUAGE_CONFIGS object:
ja: {
code: 'ja',
name: 'Japanese',
additionalRules: [
'Use Japanese punctuation: 、(読点) for commas, 。(句点) for periods.',
'Use full-width parentheses()and brackets【】for Japanese text.',
'Keep mathematical notation and code in half-width ASCII characters.',
'Use です/ます (polite) form for explanatory text, である form for formal definitions.',
'Translate technical terms using standard Japanese academic conventions.',
],
},Localization rules (optional)¶
If the language uses a non-Latin script and needs special fonts for matplotlib figures (like Chinese does), you may need to add font configuration to src/localization-rules.ts. Currently:
zh-cnhas font configuration (Source Han Serif SC)fasilently skips font configuration (standard fonts work)
For Japanese, you would add a font entry if matplotlib’s default fonts don’t render Japanese characters correctly.
Build and test¶
After editing the source:
npm run build # Compile TypeScript + bundle the action (updates dist-action/)
npm test # Run all testsContribute back¶
If this is a generally useful language, contribute the glossary and config back:
git checkout -b add-japanese-language
git add glossary/ja.json src/language-config.ts
git commit -m "Add Japanese language support with glossary"
# Open a PR to QuantEcon/action-translationStep 3: Set up the target repository¶
Now create the target repository and translate the content. This follows the same process as Tutorial: Fresh Setup, adapted for the new language.
Scaffold the target repo¶
npx translate setup \
--source QuantEcon/lecture-python-intro \
--target-language jaThis creates QuantEcon/lecture-python-intro.ja on GitHub with the scaffolding files.
Translate the content¶
npx translate init \
-s ~/repos/lecture-python-intro \
-t ./lecture-python-intro.ja \
--target-language ja \
--dry-run # Preview first
npx translate init \
-s ~/repos/lecture-python-intro \
-t ./lecture-python-intro.ja \
--target-language jaPush the translated content¶
cd lecture-python-intro.ja
git add .
git commit -m "Initial Japanese translation via translate init"
git push origin mainStep 4: Configure multi-language workflows¶
If your source repo already syncs to one language, add the new language as a parallel job.
Source repo — Multi-language sync workflow¶
Update .github/workflows/sync-translations.yml in the source repository:
name: Sync Translations
on:
pull_request:
types: [closed]
paths:
- 'lectures/**/*.md'
- '_toc.yml'
issue_comment:
types: [created]
jobs:
sync-to-chinese:
if: >
(github.event_name == 'pull_request' && github.event.pull_request.merged == true) ||
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '\translate-resync'))
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2
- uses: QuantEcon/action-translation@v0
with:
mode: sync
target-repo: 'QuantEcon/lecture-python-intro.zh-cn'
target-language: 'zh-cn'
docs-folder: 'lectures'
anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
github-token: ${{ secrets.TRANSLATION_PAT }}
sync-to-japanese:
if: >
(github.event_name == 'pull_request' && github.event.pull_request.merged == true) ||
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '\translate-resync'))
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2
- uses: QuantEcon/action-translation@v0
with:
mode: sync
target-repo: 'QuantEcon/lecture-python-intro.ja'
target-language: 'ja'
docs-folder: 'lectures'
anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
github-token: ${{ secrets.TRANSLATION_PAT }}The jobs run in parallel — each language is translated independently.
Target repo — Review workflow¶
Create .github/workflows/review-translations.yml in the new target repository:
name: Review Translations
on:
pull_request:
types: [opened, synchronize]
jobs:
review:
if: contains(github.event.pull_request.labels.*.name, 'action-translation')
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
# One review per PR — supersede an in-flight review instead of running both
concurrency:
group: review-translations-${{ github.event.pull_request.number }}
cancel-in-progress: true
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2
- uses: QuantEcon/action-translation@v0
with:
mode: review
source-repo: 'QuantEcon/lecture-python-intro'
source-language: 'en'
target-language: 'ja'
docs-folder: 'lectures'
anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
github-token: ${{ secrets.GITHUB_TOKEN }}Secrets¶
Add these secrets to the relevant repos:
| Repo | Secret | Purpose |
|---|---|---|
| Source repo | ANTHROPIC_API_KEY | Claude translations |
| Source repo | TRANSLATION_PAT | Cross-repo PR creation (needs repo scope for all target repos) |
| New target repo | ANTHROPIC_API_KEY | Translation reviews |
The TRANSLATION_PAT in the source repo needs access to the new target repo. If you’re using a fine-grained PAT, update its repository scope.
Step 5: Verify the setup¶
Check sync status¶
npx translate status \
-s ~/repos/lecture-python-intro \
-t ~/repos/lecture-python-intro.ja \
-l jaAll files should show ✅ ALIGNED.
Health check¶
For a comprehensive verification that covers configuration, state, workflows, and heading-maps:
npx translate doctor \
-t ~/repos/lecture-python-intro.jaAny ❌ items should be addressed before moving to production.
Test the pipeline¶
Make a small edit in the source repo
Open and merge a PR
Check both target repos — you should see translation PRs in both
.zh-cnand.jarepos
Working without a glossary or language config¶
Both the glossary and language config are optional. The system works with any language code — you just get fewer guardrails:
| Component | Without it | Impact |
|---|---|---|
| Glossary | Claude uses its own terminology choices | Less consistent technical terms |
| Language config | No language-specific prompt rules | Claude uses general knowledge (usually fine) |
You can add both later and run forward to bring existing translations into alignment with the new glossary.
Maintaining multiple language targets¶
With multiple target languages, the CLI tools work the same way — just specify the language:
# Status for Japanese target
npx translate status -s ~/source -t ~/target-ja -l ja
# Backward analysis for Japanese
npx translate backward -s ~/source -t ~/target-ja -l ja
# Forward resync for Japanese
npx translate forward -s ~/source -t ~/target-ja -l jaEach target repository maintains its own .translate/state/ independently.
Checklist¶
Glossary created at
glossary/{code}.jsonLANGUAGE_CONFIGSentry added insrc/language-config.ts(required — sync throws for language codes without one; a glossary alone does not enable a language)Font configuration added if needed (optional)
Source rebuilt:
npm run buildTarget repo scaffolded:
translate setupContent translated:
translate initTranslated content pushed to target repo
Source workflow updated with new language job
Target workflow created for review
Secrets configured in both repos
Pipeline tested with a small change
Next steps¶
Tutorial: Fresh Setup — detailed walkthrough of the setup + init process
Tutorial: Resync a Drifted Target — recovering from drift
Glossary Guide — detailed glossary format and guidelines
Language Configuration — full language config reference