| title | GitHub Action Reference |
|---|
Complete reference for the QuantEcon/action-translation GitHub Action.
The action operates in two modes, specified by the mode input:
Runs in the source (English) repository. When a PR is merged that changes Markdown files, the action:
- Detects which files and sections changed
- Translates only the changed sections using Claude
- Reconstructs the target document, preserving unchanged sections
- Creates a PR in the target repository with the updated translations
- Posts a confirmation comment on the source PR
If sync fails, it automatically opens a GitHub Issue with error details and recovery instructions.
Runs in the target (translated) repository. When a translation PR is opened (typically by sync mode), the action:
- Compares the translation against the source content
- Evaluates translation quality and diff accuracy
- Posts a review comment with scores and suggestions
| Input | Description |
|---|---|
mode |
Operation mode: sync or review |
anthropic-api-key |
Anthropic API key for Claude |
github-token |
GitHub token for API access (cross-repo requires a PAT with repo scope) |
| Input | Default | Description |
|---|---|---|
target-repo |
(required) | Target repository for translations (owner/repo) |
target-language |
(required) | Target language code (e.g., zh-cn, fa) |
docs-folder |
lectures/ |
Documentation folder containing Markdown files |
source-language |
en |
Source language code |
glossary-path |
(empty) | Path to custom glossary JSON file. If empty, the built-in glossary for the target language is used |
toc-file |
_toc.yml |
Table of contents file name |
claude-model |
claude-sonnet-4-6 |
Claude model for translation |
pr-labels |
action-translation,automated |
Comma-separated labels for created PRs |
pr-reviewers |
(empty) | GitHub usernames to request as reviewers |
pr-team-reviewers |
(empty) | GitHub team slugs to request as reviewers |
test-mode |
false |
Use PR head commit instead of merge commit (for testing) |
| Input | Default | Description |
|---|---|---|
source-repo |
(required) | Source repository for English content (owner/repo) |
source-language |
en |
Source language code |
target-language |
(required for review) | Target language code |
docs-folder |
lectures/ |
Documentation folder |
max-suggestions |
5 |
Maximum improvement suggestions in review comment |
claude-model |
claude-sonnet-4-6 |
Claude model for review |
| Output | Description |
|---|---|
pr-url |
URL of the created translation PR |
files-synced |
Number of files synchronized |
| Output | Description |
|---|---|
review-verdict |
Review verdict: PASS, WARN, or FAIL |
translation-score |
Overall translation quality score (1–10) |
diff-score |
Diff accuracy score (1–10) |
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.11
with:
mode: sync
target-repo: 'QuantEcon/lecture-intro.zh-cn'
target-language: 'zh-cn'
docs-folder: 'lectures/'
anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
github-token: ${{ secrets.TRANSLATION_PAT }}The issue_comment trigger enables the \translate-resync command — comment it on any merged PR to retry a failed sync. To retrigger only one language, add the language code: \translate-resync fa or \translate-resync zh-cn. Bare \translate-resync retriggers all languages.
Use separate jobs for each target language. They run in parallel and create independent PRs:
name: Sync Translations
on:
pull_request:
types: [closed]
paths:
- 'lectures/**/*.md'
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.11
with:
mode: sync
target-repo: 'QuantEcon/lecture-intro.zh-cn'
target-language: 'zh-cn'
anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
github-token: ${{ secrets.TRANSLATION_PAT }}
sync-to-farsi:
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.11
with:
mode: sync
target-repo: 'QuantEcon/lecture-intro.fa'
target-language: 'fa'
anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
github-token: ${{ secrets.TRANSLATION_PAT }}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
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2
- uses: QuantEcon/action-translation@v0.11
with:
mode: review
source-repo: 'QuantEcon/lecture-python-intro'
source-language: 'en'
target-language: 'zh-cn'
docs-folder: 'lectures/'
max-suggestions: 5
anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
github-token: ${{ secrets.GITHUB_TOKEN }}- uses: QuantEcon/action-translation@v0.11
id: translate
with:
mode: sync
# ... other inputs
- name: Comment on PR
if: steps.translate.outputs.pr-url
run: |
echo "Translation PR created: ${{ steps.translate.outputs.pr-url }}"
echo "Files synced: ${{ steps.translate.outputs.files-synced }}"When a PR is merged, sync mode:
- Identifies changed files — Compares the PR's diff against the docs folder pattern
- Classifies each file — New file (full translation) or existing file (section-level update)
- Parses sections — Splits documents at
##headings using a stack-based parser - Detects section changes — Compares old and new source to find which sections differ
- Translates changed sections — Sends only modified sections to Claude (UPDATE mode)
- Reconstructs the document — Merges translated sections back with unchanged content
- Updates heading-map — Refreshes the section ID mapping in the target frontmatter
- Creates a PR — Commits all updated files to a branch in the target repo
- Posts a success comment — Confirms sync completion on the source PR with a link to the translation PR
If any files fail to process, the action opens a GitHub Issue with error details and a link to the source PR. Comment \translate-resync on the merged PR to retry all languages, or \translate-resync fa to retry a specific language.
For new files, the entire document is translated in a single call (NEW mode).
The default model is claude-sonnet-4-6, which provides excellent translation quality at reasonable cost. Options:
| Model | Cost | Best for |
|---|---|---|
claude-sonnet-4-6 |
~$0.05/file | Daily sync operations (recommended) |
claude-opus-4 |
~$0.25/file | High-stakes translations needing maximum quality |
claude-haiku-3.5 |
~$0.01/file | Budget-conscious bulk operations |
The action follows QuantEcon's repository naming convention:
- Source:
lecture-python-intro(English) - Target:
lecture-intro.zh-cn(Chinese),lecture-intro.fa(Farsi)
The target-repo input must be the full owner/repo path (e.g., QuantEcon/lecture-intro.zh-cn).
If your Markdown files are in the repository root (not a subfolder), set docs-folder to .:
docs-folder: '.'The action handles this correctly, filtering only top-level .md files.