This tutorial walks through creating a new Chinese translation of an English lecture series from scratch. By the end, you’ll have:
A GitHub repository for the translated content
All lectures translated with heading-maps and
.translate/metadataAutomated sync and review workflows configured
Time: ~30 minutes (plus translation time, which depends on project size)
Cost: ~$0.16/lecture for translation using claude-sonnet-5
Prerequisites¶
Before starting, make sure you have:
| Requirement | Check |
|---|---|
| Source repo cloned locally | ls ~/repos/lecture-python-intro/lectures/ |
gh CLI installed & authenticated | gh auth status |
| Node.js 18+ | node --version |
| Anthropic API key | console |
| action-translation installed | See Installation |
Overview¶
The fresh setup process has 5 steps:
Step 0: Install action-translation
Step 1: Scaffold the target repo (translate setup)
Step 2: Translate all lectures (translate init)
Step 3: Push and verify (git push + translate status)
Step 4: Configure workflows and secrets (manual GitHub setup)
Step 5: Test the pipeline (merge a test PR)Step 0: Install action-translation¶
git clone https://github.com/QuantEcon/action-translation.git
cd action-translation
npm install
npm run build:cliVerify it works:
npx translate --versionSet your API key for translation steps:
export ANTHROPIC_API_KEY=sk-ant-...Step 1: Scaffold the target repository¶
The setup command creates a new GitHub repository and plants the initial configuration files.
Preview first (dry run):
npx translate setup \
--source QuantEcon/lecture-python-intro \
--target-language zh-cn \
--dry-runThis shows what would be created without touching GitHub.
Create the repository:
npx translate setup \
--source QuantEcon/lecture-python-intro \
--target-language zh-cnThis:
Creates
QuantEcon/lecture-python-intro.zh-cnon GitHubClones it locally to
./lecture-python-intro.zh-cn/Writes
.translate/config.yml,.github/workflows/translation-sync.yml,.gitignore,README.mdCommits and pushes
What you get:
lecture-python-intro.zh-cn/
├── .translate/
│ └── config.yml # source-language: en, target-language: zh-cn
├── .github/
│ └── workflows/
│ └── translation-sync.yml
├── .gitignore
└── README.mdStep 2: Translate all lectures¶
The init command bulk-translates every lecture in the source project.
Preview first (dry run):
npx translate init \
-s ~/repos/lecture-python-intro \
-t ./lecture-python-intro.zh-cn \
--target-language zh-cn \
--dry-runThis lists all lectures that would be translated and all non-markdown files that would be copied, without making any API calls.
Run the translation:
npx translate init \
-s ~/repos/lecture-python-intro \
-t ./lecture-python-intro.zh-cn \
--target-language zh-cnThe init command runs a 7-phase pipeline:
| Phase | What happens |
|---|---|
| 1. Load glossary | Loads glossary/zh-cn.json (357 technical terms) |
2. Parse _toc.yml | Discovers all lectures in the source project |
| 3. Setup target | Creates the docs folder structure |
| 4. Copy non-markdown files | Images, _config.yml, _toc.yml, CSS, data files |
| 5. Translate lectures | Sequential translation with progress bar |
| 6. Generate heading-maps | Position-based section matching, injected into frontmatter |
| 7. Write report | TRANSLATION-REPORT.md with stats and any failures |
A progress bar shows the current lecture being translated.
If translation is interrupted, resume from where you left off:
npx translate init \
-s ~/repos/lecture-python-intro \
-t ./lecture-python-intro.zh-cn \
--target-language zh-cn \
--resume-from cobweb.mdLocalization options¶
By default, init localizes code cells: translates Python comments, matplotlib labels, and injects CJK font configuration. Control this with --localize:
# Translate everything except font configuration
npx translate init ... --localize code-comments,figure-labels
# No code-cell localization at all
npx translate init ... --localize noneFont setup (zh-cn only)¶
After translation, the CLI prints font download instructions. For Chinese, you need to place a font file at:
lectures/_fonts/SourceHanSerifSC-SemiBold.otfDownload from Adobe Source Han Serif releases.
What init produces¶
After translation, each lecture file contains:
---
title: 蛛网模型
translation:
title: 蛛网模型
headings:
overview: "概述"
equilibrium: "均衡"
exercises: "练习"
---And the .translate/state/ folder tracks sync metadata:
.translate/
├── config.yml
└── state/
├── intro.md.yml
├── cobweb.md.yml
└── solow.md.ymlStep 3: Push and verify¶
Commit the translated content and push:
cd lecture-python-intro.zh-cn
# Review what was created
ls lectures/
# Commit all translated content
git add .
git commit -m "Initial zh-cn translation via translate init"
git push origin mainVerify the sync state:
cd /path/to/action-translation
npx translate status \
-s ~/repos/lecture-python-intro \
-t ~/repos/lecture-python-intro.zh-cnAll files should show ✅ ALIGNED.
Run a health check to confirm everything is properly configured:
npx translate doctor \
-t ~/repos/lecture-python-intro.zh-cnAll checks should pass (✅) before proceeding to workflow configuration.
Step 4: Configure workflows and secrets¶
You need two workflows: one in the source repo (to trigger translations) and one in the target repo (to review them).
4a: Source repo — Sync workflow¶
Create .github/workflows/sync-translations.yml in the source (English) 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 }}4b: Source repo — Secrets¶
Add these secrets to the source repo (Settings → Secrets and variables → Actions):
| Secret | Value | Purpose |
|---|---|---|
ANTHROPIC_API_KEY | Your Anthropic API key | Pays for Claude translations |
TRANSLATION_PAT | GitHub PAT with repo scope | Creates PRs in the target repo |
The PAT needs repo scope because the action creates PRs in the target repository from the source repo’s workflow.
4c: Target repo — Review workflow (optional)¶
Create .github/workflows/review-translations.yml in the 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: 'zh-cn'
docs-folder: 'lectures'
anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
github-token: ${{ secrets.GITHUB_TOKEN }}Add the ANTHROPIC_API_KEY secret to the target repo as well (for the review workflow).
4d: Target repo — Secret¶
| Secret | Value | Purpose |
|---|---|---|
ANTHROPIC_API_KEY | Your Anthropic API key | Pays for AI-powered translation reviews |
The target repo uses ${{ secrets.GITHUB_TOKEN }} (automatic) for PR access — no PAT needed.
Step 5: Test the pipeline¶
Make a small change in the source repo and merge a PR to verify the full pipeline:
Create a branch in the source repo and edit a lecture (e.g., fix a typo in
cobweb.md)Open and merge a PR — the sync workflow triggers
Check the target repo — a translation PR should appear within a few minutes
Review the PR — if the review workflow is configured, it posts a quality assessment
Merge the translation PR — the target repo is now in sync
What happens going forward¶
Once configured, the automated pipeline handles ongoing changes:
You merge a PR in source repo
│
▼
Sync workflow detects changed sections
│
▼
Claude translates ONLY the changed sections
│
▼
Translation PR created in target repo
│
▼
Review workflow posts quality scores (optional)
│
▼
Human reviewer approves & mergesFor maintenance tasks (checking drift, finding backport suggestions, recovering from failed syncs), use the CLI tools:
# Quick status check
npx translate status -s ~/source -t ~/target
# Find improvements worth backporting to English
npx translate backward -s ~/source -t ~/target
# Resync drifted files
npx translate forward -s ~/source -t ~/targetTroubleshooting¶
gh repo create fails¶
Check
gh auth status— you may need to re-authenticateCheck the repo name isn’t already taken:
gh repo view QuantEcon/lecture-python-intro.zh-cn
init fails mid-translation¶
Use --resume-from to pick up where you left off. Check TRANSLATION-REPORT.md for details on which lectures failed and why.
Sync workflow doesn’t trigger¶
Verify the workflow file is on the default branch (
main)Check that the PR modified files matching the
pathsfilter (lectures/**/*.md)Verify the PR was merged (not just closed)
Translation PR has no changes¶
The changed sections may have translated identically to the existing content
Check the heading-map — if it’s missing, sections may not be matching correctly
Next steps¶
Tutorial: Connecting an Existing Target — for repos that were translated before action-translation
Tutorial: Resync a Drifted Target — for repos that have fallen out of sync
Tutorial: Backward Analysis & Review — find improvements in translations worth backporting
Tutorial: Adding a New Language — extend to additional target languages
CLI Reference — full command documentation
Heading Maps — how cross-language section matching works