Skip to content

feat(i18n): Claude Code CLI fallback for auto-translation (TOOLING-I18N-CLAUDE-CODE-TRANSLATE) - #118

Merged
FullGas1 merged 3 commits into
developfrom
tooling/i18n-claude-code-translate
Aug 10, 2026
Merged

feat(i18n): Claude Code CLI fallback for auto-translation (TOOLING-I18N-CLAUDE-CODE-TRANSLATE)#118
FullGas1 merged 3 commits into
developfrom
tooling/i18n-claude-code-translate

Conversation

@FullGas1

@FullGas1 FullGas1 commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • tools/build/translate_i18n.py only auto-translates i18n stubs when ANTHROPIC_API_KEY is 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.
  • Adds a second backend: when the API key is absent, fall back to the Claude Code CLI (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.
  • 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 rather than inheriting the session's default model.
  • No pre-flight check for CLI/session availability - a failure is caught by the same non-blocking exception handling already used for API errors, with a combined warning naming both ways to enable auto-translation when neither is available.
  • 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 despite being asked not to.
  • No change to merge_CTLD.ps1, generate_i18n_dicts.ps1, check_i18n_diff.py, or the i18n-guard CI job - CI never auto-translates (ADR 0013), and the guard only inspects dictionary content, never the mechanism that produced it.
  • Grilled with docs 2026-08-10, ADR 0014. Lot: .backlog/TOOLING-I18N-CLAUDE-CODE-TRANSLATE/ - PRD plus 1 ticket.

Test plan

  • pytest tools/build/ - 19/19 green (2 new tests for _select_backend)
  • CLI backend verified for real in a plain terminal: _translate_batch_cli('French', {'Cut Slingload': 'Cut Slingload'}) -> {'Cut Slingload': 'Larguer la charge'}
  • API path verified unchanged by diff review (_translate_batch_api is a rename with no logic change)
  • Neither-available combined-warning path verified by code review (not live-executed: the Claude Code CLI refuses to launch nested inside the Claude Code session used to develop this ticket)
  • CI green on this PR

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:

  • Enable i18n stub auto-translation via the Claude Code CLI when ANTHROPIC_API_KEY is not set, authenticating through a Claude Code subscription as a local fallback.
  • Introduce a backend-selection mechanism that chooses between Anthropic API and CLI backends while keeping existing API-based behavior unchanged when a key is present.

Bug Fixes:

  • Fix Windows-specific issues invoking the Claude CLI shim and handling multi-line JSON prompts, including resolving the executable via PATHEXT and passing prompts via stdin, and strip markdown fences from CLI JSON responses.

Enhancements:

  • Refactor translate_i18n.py to split prompt construction and API calls into clearer helpers and improve warning messages when translation backends are unavailable.
  • Add unit tests covering backend selection logic for the translation tool.

Documentation:

  • Document the new CLI fallback behavior and constraints in the changelog, backlog PRD/ticket, roadmap, and a new ADR describing the i18n Claude Code CLI fallback design.

Tests:

  • Extend tools/build test coverage with tests for backend selection to prevent regressions in choosing between API and CLI translation paths.

Chores:

  • Record the TOOLING-I18N-CLAUDE-CODE-TRANSLATE lot in the backlog index and link it to its PRD and ADR.

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.
@FullGas1
FullGas1 requested a review from davidp57 as a code owner August 10, 2026 11:46
@sourcery-ai

sourcery-ai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds 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
Loading

File-Level Changes

Change Details Files
Introduce dual translation backends in translate_i18n.py with API-first selection and Claude Code CLI fallback, plus supporting helpers and error handling.
  • Refactor prompt construction into a reusable _build_prompt() helper and rename the existing batch translation path to _translate_batch_api() without logic changes.
  • Add a pure _select_backend(has_api_key) function to decide between 'api' and 'cli' backends, and use it in main() based on ANTHROPIC_API_KEY.
  • Implement a CLI-backed translation path _translate_batch_cli() that resolves the claude binary via shutil.which, streams the prompt via stdin, pins the model, and parses structured JSON output with markdown-fence stripping via _strip_markdown_fence().
  • Update main() to initialize the Anthropic client only when the API backend is selected, branch per-language translation through API vs CLI, adjust logging messages to include backend, and emit a combined warning when CLI translation fails.
tools/build/translate_i18n.py
Add unit coverage for backend selection and adjust test module scope.
  • Extend existing translate_i18n tests to import and exercise _select_backend().
  • Add tests verifying that _select_backend() chooses 'api' when an API key is present and 'cli' when absent.
  • Update the test module docstring to reflect coverage of backend selection in addition to stub detection.
tools/build/test_translate_i18n.py
Document the new Claude Code CLI fallback feature in changelog, backlog, roadmap, and ADRs.
  • Add an Unreleased changelog entry describing the CLI fallback behavior, model pinning, error-handling behavior, Windows-specific fixes, and lack of CI impact.
  • Replace the detailed roadmap item about future CLI-based i18n translation with a short pointer to the finalized TOOLING-I18N-CLAUDE-CODE-TRANSLATE lot.
  • Register a new backlog lot entry for TOOLING-I18N-CLAUDE-CODE-TRANSLATE in the backlog README, linking to its PRD and summarizing scope.
  • Add ADR 0014 describing the dual-mode decision, rejected alternatives, and consequences for i18n auto-translation.
CHANGELOG.md
dev/roadmap.md
.backlog/README.md
dev/adr/0014-i18n-claude-code-cli-fallback.md
dev/adr/README.md
Introduce structured backlog artefacts (PRD and ticket) for TOOLING-I18N-CLAUDE-CODE-TRANSLATE.
  • Add a PRD describing the problem, dual-backend solution, user stories, implementation/testing decisions, and out-of-scope items for the Claude Code CLI fallback.
  • Add a ticket detailing what to build, acceptance criteria, and constraints for implementing the CLI fallback behavior.
  • Ensure both documents align with ADR 0014 and existing ADRs on i18n tooling and CI guard behavior.
.backlog/TOOLING-I18N-CLAUDE-CODE-TRANSLATE/PRD.md
.backlog/TOOLING-I18N-CLAUDE-CODE-TRANSLATE/tickets/01-claude-code-cli-fallback.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@FullGas1
FullGas1 merged commit 3c4bd02 into develop Aug 10, 2026
9 checks passed
@FullGas1
FullGas1 deleted the tooling/i18n-claude-code-translate branch August 10, 2026 11:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant