Releases: QuantEcon/action-translation
v0.15.0 — Rebase Mode
Rebase Mode — Automatic conflict resolution for translation PRs
This release adds rebase mode, which eliminates merge conflicts when multiple upstream PRs modify the same translated file. Previously, 62% of translation-sync PRs conflicted because they replace entire files — merging one makes any sibling PR's "unchanged sections" stale.
How it works
When a translation-sync-* PR is merged in the target repo, rebase mode:
- Finds sibling translation-sync PRs with overlapping files
- Re-runs the translation pipeline against updated
main - Reuses cached translations for unchanged sections (zero Claude API calls in the common case)
- Force-pushes the rebased result
Setup
Add examples/rebase-translations.yml to your target repo's .github/workflows/ directory (see template).
What's new
- Rebase mode (
mode: rebase) — triggered bypull_request.closedontranslation-sync-branches - Translation cache — section-level cache using
targetBaseShain PR metadata; unchanged sections skip Claude entirely - Structured PR metadata — machine-readable JSON in PR body for pipeline reconstruction
- File type metadata — supports markdown, renamed, removed, and toc files during rebase
- Rebase workflow template —
examples/rebase-translations.ymlwith concurrency group - 29 new tests (976 → 1005 total, 39 suites)
Fixes #63
v0.14.1
Fixed
- Heading-map injection for new files:
processFull()now builds and injects atranslation:frontmatter block (heading-map + title) into newly translated files. Previously, only section-based updates viaprocessSectionBasedgot heading-maps; new files were missing them. MISSING_HEADINGMAPfalse positive for title-only files:translate statusno longer flags files with no##sections as missing a heading-map. These files have only a title — an empty heading-map is expected.
Refactored
- Moved
buildHeadingMapfrom CLI module (headingmap.ts) to shared module (heading-map.ts) to avoid coupling the Action bundle to CLI-only dependencies. - Added try/catch around heading-map injection in
processFullso malformed translations fall back gracefully.
Documentation
- Documented language-targeted
\translate-resyncsyntax across README, quickstart, action-reference, and FAQ (e.g.,\translate-resync fato retrigger only Farsi).
Tests
976 pass (39 suites) — 4 new tests added.
v0.14.0
Fixed
- Retry on Anthropic
overloaded_error: Theoverloaded_error(APIError withstatus: undefined) is now retried with exponential backoff instead of failing immediately. Narrowed to matchoverloadedin the error message so unrelated status-less errors are not retried. ImprovedformatApiErrorto show a clear message when retries are exhausted. Fixes #57
Added
- Language-targeted
\translate-resynccommand:\translate-resync fatriggers only the Farsi workflow;\translate-resync zh-cntriggers only zh-cn. Bare\translate-resync(no argument) still triggers all languages for backward compatibility. Language argument is validated against supported languages; unsupported values are ignored with a warning and fall back to all-language resync. Fixes #58 - Copilot PR review workflow in
copilot-instructions.md: Documented the fetch, fix, reply, resolve process for addressing Copilot review comments - 5 tests: 2 for overloaded_error retry, 3 for language-targeted resync parsing (967 -> 972 total)
v0.13.1
Fixed
- Headingmap CLI MyST role stripping:
cleanHeading()in theheadingmapCLI now strips MyST inline roles viaMystParser.stripMystRoles(), matching the sync pipeline behavior from v0.12.5. Previously, roles like{index}`Mutable <single: Mutable>`appeared verbatim in heading-map keys/values when runningnpx translate headingmap.
Added
- 1 test for MyST role stripping in
buildHeadingMap(966 → 967 total)
v0.13.0 — Translation Frontmatter
What's Changed
Changed
- Heading-map → translation frontmatter: Replaced flat
heading-map:YAML block with structuredtranslation: { title, headings }format. Title is now stored as an explicit field instead of a heading-map entry, resolving the inconsistency between the sync pipeline and theheadingmapCLI.
Migration
Backward compatible — reads both old heading-map: and new translation: formats. Always writes new format. Existing documents migrate automatically on next sync or headingmap rebuild.
To proactively migrate a target repo:
npx translate headingmap -s <source-repo> -t <target-repo>Details
heading-map.ts:extractHeadingMapreadstranslation.headingswithheading-mapfallback; newextractTranslationTitle();serializeHeadingMapandinjectHeadingMapwritetranslation:formatfile-processor.ts: Title tracked separately, passed toinjectHeadingMapheadingmapCLI: Write gate checks(generatedMap || generatedTitle)for title-only filesinitCLI:generateHeadingMapreturns{map, title}, both injectedreviewer.ts: LLM prompts reference new format- 966 tests (39 suites)
Full Changelog: v0.12.5...v0.13.0
v0.12.5 — Heading-map MyST role fix
Bug Fix
- Heading-map MyST role pollution: Headings with MyST inline roles like
{index}`Pandas <single: Pandas>`were stored verbatim as heading-map keys/values instead of the clean display text (Pandas). AddedMystParser.stripMystRoles()static method using global regex replacement to handle single roles, multiple roles, and mixed role+text headings. Applied across all heading-map paths: parser title extraction, file-processor heading-map updates,cleanHeadinginupdateHeadingMap, andlookupTargetHeading. Covers#titles and##+ section/subsection headings. Affects 7 lectures in lecture-python-programming that use{index}roles in titles.
Tests
- 19 tests for MyST role stripping — unit tests for
stripMystRoles(including mixed role+text headings), title extraction integration, and heading-map operations with role syntax (935 → 954 total)
v0.12.4 — CJK–MyST spacing rule & target-label cleanup
Addresses feedback from lecture-python-programming.zh-cn PR #6.
Added
- CJK–MyST spacing rule for zh-cn: New language-config rule instructs Claude to insert a space between Chinese characters and inline MyST directives (
{doc},{ref}, etc.) or Markdown links, preventing rendering failures (e.g.请参阅 {doc}not请参阅{doc}) - MyST target-label blank-line cleanup:
reconstructFromComponentsnow strips blank lines between MyST target labels ((label)=) and headings in post-processing, so targets always attach to their heading correctly - 1 test for target-label blank-line removal (934 → 935 total)
v0.12.3 — Scoped translation PRs
What's Changed
Fixes #45 — translation PRs are now scoped to the source PR's actual changes, preventing superset accumulation when earlier translation PRs are still open.
Fixed
- Scope translation PRs to source PR's actual changes: Unchanged sections missing from target (pending an earlier unmerged translation PR) are now skipped instead of re-translated. Git's 3-way merge combines the PRs when merged independently. Recovery via
/translate-resyncif an earlier PR is abandoned. - Heading-map corruption when sections are skipped:
includedSourceSectionsarray keeps index-alignment withresultSectionssoupdateHeadingMap()pairs sections correctly. - Markdown injection in PR body: Skipped section headings wrapped in backticks to neutralize Markdown syntax.
Added
- Skipped sections notice: Translation PRs include a
⚠️ Sections Pending Earlier Translation PRnotice listing which sections were skipped per file. onSkippedSectioncallback andskippedSectionsin sync pipeline for tracking skipped sections.- 4 new tests (934 total).
Full Changelog: v0.12.2...v0.12.3
v0.12.2
What's Changed
Fixed
-
Position fallback guard for mismatched section counts:
findTargetSectionByHeadingMapno longer uses position-based fallback when source and target have different section counts. Previously, when a new section was added to source but the translation PR hadn't been merged yet, the position fallback would grab the wrong target section, producing incorrect heading-map values. Now unmatched sections fall through totranslateNewSectioninstead. (PR #43) -
Resync uses PR merge commit SHA:
\translate-resyncnow uses the PR'smerge_commit_shainstead ofgithub.context.sha(which points to HEAD of main forissue_commentevents). Previously,oldContentandnewContentcould both reference the current main tip, causing the diff detector to miss the PR's actual changes. (PR #44)
Added
- 3 new tests for position fallback guard (927 → 930 total)
Full Changelog: v0.12.1...v0.12.2
v0.12.1 — Sync evaluation bug fixes
Bug fix release addressing 5 issues identified in the real-world sync evaluation of lecture-python-programming → .zh-cn / .fa.
Fixed
- Duplicate preamble regression (Critical): Fixed intro extraction that duplicated pre-title content (anchors, raw blocks) in translated documents. Regression from v0.11.2.
- Case-insensitive heading-map lookup (High): Heading case changes (e.g. "Iterables and Iterators" → "Iterables and iterators") no longer cause full section re-translations. Falls back to case-insensitive matching.
- Position-based section fallback (High): Section matching now falls back to position when both heading-map and ID lookups fail, preventing unnecessary NEW section translations for translated headings.
- Label retry on PR creation (Medium): Label application retries 3× with 2s delays, fixing GitHub API propagation failures that caused review workflows to skip.
- Review response parsing with retry (Medium): Review evaluations now retry on parse failures with robust multi-strategy JSON extraction (direct parse, code block, greedy regex), preventing single malformed LLM responses from crashing the review workflow.
Added
- E2E test fixture #25 (pre-title content) and #26 (heading case change)
- 14 new
parseJsonResponsetests (927 total, 39 suites)
Full Changelog: v0.12.0...v0.12.1