feat(i18n): Claude Code CLI fallback for auto-translation (TOOLING-I18N-CLAUDE-CODE-TRANSLATE) - #118
Merged
Merged
Conversation
Grilled with docs, 2026-08-10. Formalizes the roadmap idea surfaced during FIX-I18N-DEBT-REPAYMENT: translate_i18n.py only auto-translates when ANTHROPIC_API_KEY is set, leaving a Claude Code subscriber without a separate API key with no auto-translation at all. Adds a Claude Code CLI (claude -p) fallback backend, dual mode with the existing API path unchanged and first-priority. No CI change needed - i18n-guard inspects dictionary content only.
translate_i18n.py gains a second backend: when ANTHROPIC_API_KEY is absent, fall back to the Claude Code CLI (claude -p) instead of giving up, authenticating via the Code subscription rather than a separate API key. Dual mode - the API path is unchanged and stays first-priority whenever the key is set. New _select_backend() pure function (unit tested) decides which path to attempt. Model pinned to claude-haiku-4-5-20251001 on the CLI call too, matching the API path's deliberate cheap/fast choice. No pre-flight availability check - failures are caught by the same non-blocking exception handling already used for API errors, with a combined warning naming both ways to enable auto-translation. Two real bugs found and fixed during manual verification against the live claude CLI: subprocess doesn't resolve claude's Windows .cmd shim via PATHEXT without shell=True (fixed via shutil.which), and the multi-line, JSON-punctuated prompt was mangled when passed as a CLI argument to that .cmd shim (now passed via stdin instead). Also strips the markdown fence Claude sometimes wraps its JSON response in. No change to merge_CTLD.ps1, generate_i18n_dicts.ps1, check_i18n_diff.py, or the i18n-guard CI job. pytest tools/build/ 19/19 green (2 new tests). See ADR 0014.
Reviewer's GuideAdds a dual-backend i18n auto-translation mechanism that prefers the Anthropic API when ANTHROPIC_API_KEY is set and falls back to the Claude Code CLI otherwise, including supporting utilities, tests, and documentation/ADR updates. Sequence diagram for dual i18n auto-translation backends (API vs Claude Code CLI)sequenceDiagram
actor Contributor
participant merge_CTLD_ps1 as merge_CTLD_ps1
participant translate_i18n_py as translate_i18n_py
participant AnthropicAPI as AnthropicAPI
participant ClaudeCLI as ClaudeCLI
Contributor->>merge_CTLD_ps1: run
merge_CTLD_ps1->>translate_i18n_py: main()
translate_i18n_py->>translate_i18n_py: _select_backend(has_api_key)
alt backend == api
translate_i18n_py->>AnthropicAPI: anthropic.Anthropic(api_key)
AnthropicAPI-->>translate_i18n_py: client
translate_i18n_py->>AnthropicAPI: client.messages.create(model=MODEL, content=_build_prompt)
AnthropicAPI-->>translate_i18n_py: message.content[0].text
translate_i18n_py->>translate_i18n_py: json.loads(raw)
translate_i18n_py->>translate_i18n_py: _apply_translations(...)
else backend == cli
translate_i18n_py->>ClaudeCLI: shutil.which("claude")
ClaudeCLI-->>translate_i18n_py: claude_bin
translate_i18n_py->>ClaudeCLI: subprocess.run([claude_bin, "-p", "--output-format", "json", "--model", MODEL], input=_build_prompt)
ClaudeCLI-->>translate_i18n_py: result.stdout
translate_i18n_py->>translate_i18n_py: json.loads(result.stdout)["result"]
translate_i18n_py->>translate_i18n_py: _strip_markdown_fence(text)
translate_i18n_py->>translate_i18n_py: json.loads(raw)
translate_i18n_py->>translate_i18n_py: _apply_translations(...)
end
note over translate_i18n_py: On any exception: print warning (API error or CLI failure) and skip language without failing build
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
tools/build/translate_i18n.pyonly auto-translates i18n stubs whenANTHROPIC_API_KEYis set (separate Anthropic Console billing). A contributor with a Claude Code subscription but no such key got nothing - lived concretely on FIX-I18N-DEBT-REPAYMENT (fix(i18n): repay pre-existing KO/ES translation debt (FIX-I18N-DEBT-REPAYMENT) #116), where 140 entries were translated by hand for want of a key.claude -p), authenticating via the Code subscription instead. Dual mode - API path unchanged and stays first-priority whenever the key is set, never displaced by a CLI fallback even if the key turns out invalid._select_backend()pure function (unit tested) decides which path to attempt. Model pinned toclaude-haiku-4-5-20251001on the CLI call too, matching the API path's deliberate cheap/fast choice rather than inheriting the session's default model.claudeCLI:subprocessdoesn't resolveclaude's Windows.cmdshim viaPATHEXTwithoutshell=True(fixed viashutil.which), and the multi-line, JSON-punctuated prompt was mangled when passed as a CLI argument to that.cmdshim (now passed via stdin instead). Also strips the markdown fence Claude sometimes wraps its JSON response in despite being asked not to.merge_CTLD.ps1,generate_i18n_dicts.ps1,check_i18n_diff.py, or thei18n-guardCI job - CI never auto-translates (ADR 0013), and the guard only inspects dictionary content, never the mechanism that produced it..backlog/TOOLING-I18N-CLAUDE-CODE-TRANSLATE/- PRD plus 1 ticket.Test plan
_select_backend)_translate_batch_cli('French', {'Cut Slingload': 'Cut Slingload'})->{'Cut Slingload': 'Larguer la charge'}_translate_batch_apiis a rename with no logic change)Generated with Claude Code
Summary by Sourcery
Add a dual-backend i18n auto-translation path that prefers the Anthropic API but falls back to the Claude Code CLI when no API key is available, and formalize the related product and ADR documentation.
New Features:
Bug Fixes:
Enhancements:
Documentation:
Tests:
Chores: