Use Claude Code in your native language. Polyglot is a local ANTHROPIC_BASE_URL proxy that sits between Claude Code and the API:
- You type in your language → the proxy rewrites your messages into English before they reach the model (full replacement — the model never sees the original).
- Claude replies in English → the proxy translates the response stream back into your language, line by line, as it arrives.
Code is sacred: fenced blocks, inline code, file paths, URLs, CLI flags, env vars, and markdown structure are never sent to the translator. A real GFM parser (mdast) decides what is prose, and every message is reassembled byte-for-byte around everything else. Tool calls, tool results, system prompts, and thinking blocks pass through untouched.
Translation goes through Google Translate, and you pick which endpoint in the config:
| Mode | Endpoint | Key | Notes |
|---|---|---|---|
public (default) |
translate.googleapis.com/translate_a/single |
none | Nothing to set up. Unofficial and undocumented; Google rate-limits per IP and answers a captcha page when it decides you've had enough. |
key |
Cloud Translation API v2 | your Google Cloud API key | Official, documented, quota-backed, billed per character. |
polyglot api public # keyless endpoint
polyglot api key AIza... # Cloud Translation API v2
polyglot api # pick interactivelyThe key is stored in polyglot's config, or kept out of it entirely with POLYGLOT_GOOGLE_API_KEY (the env var wins). Switching modes is live — the proxy re-reads the config on every request.
npm install -g @migiht/claude-code-polyglot# your language (Claude's side defaults to English)
polyglot init ru# then just run Claude Code through the proxy
polyglot claudeinit asks which language you write in, which Google endpoint to use, and proves the choice works with a real translation. It is scriptable too:
polyglot init ru --api key --key AIza...polyglot claude starts the proxy on an ephemeral port, points ANTHROPIC_BASE_URL at it, and hands your terminal to claude — every argument passes through (polyglot claude --continue, polyglot claude -p "...", …). When claude exits, the proxy exits with it.
init also offers to install a shell alias for the language you set up, so you never type polyglot claude again:
ruclaude # = polyglot claude, in Russian
ruclaude --continue # arguments still pass throughEvery language gets one, named after the country you'd expect: ruclaude, chclaude (zh-Hans), twclaude (zh-Hant), jpclaude, uaclaude, krclaude, declaude, frclaude, esclaude, czclaude, inclaude (hi)… — the language code is the fallback.
polyglot alias # pick your shortcuts interactively
polyglot alias add ja zh-Hans # add more (each needs its own `polyglot init`)
polyglot alias remove ja
polyglot alias listAliases are written into a single managed block in ~/.bashrc, ~/.zshrc, and ~/.config/fish/config.fish (whichever exist), and removed again by polyglot uninstall. Each one pins its language with POLYGLOT_LANG=<code>, which overrides the configured language for that run only — so ruclaude and jpclaude work side by side in different terminals.
| Command | What it does |
|---|---|
polyglot init [source] [target] |
Pick languages and the translation backend (polyglot init ru, target defaults to en) |
polyglot claude [...args] |
Run Claude Code through the translation proxy |
polyglot api [public|key] [apiKey] |
Choose the Google endpoint: keyless or Cloud Translation API v2 |
polyglot alias [add|remove|list] [langs...] |
Manage the <lang>claude shell shortcuts (ruclaude, jpclaude, …) |
polyglot proxy [--port N] [--upstream URL] |
Standalone proxy; set ANTHROPIC_BASE_URL yourself |
polyglot scopes [on|off] [names...] |
Choose which markdown blocks get translated |
polyglot stats [--days N] [--reset] |
Translation metrics (calls, chars, latency) from local SQLite |
polyglot enable / polyglot disable |
Toggle translation live (the proxy re-reads config per request) |
polyglot status |
Languages, translation backend, proxy configuration |
polyglot translate <text> |
Run one string through the exact proxy pipeline (--reverse for the reply direction) |
polyglot uninstall |
Delete local data (config, API key, stats), uninstall the npm package |
Polyglot chains: if ANTHROPIC_BASE_URL is already set (a router, a corporate gateway, any other local proxy), polyglot claude uses it as the upstream instead of api.anthropic.com — the stack becomes claude → polyglot → your proxy → API. For manual stacks, polyglot proxy --upstream <url> pins it explicitly.
It also never touches ~/.claude/settings.json, hooks, or the Claude Code binary — tools like rtk (PreToolUse-hook based) keep working unchanged next to it. All requests polyglot doesn't understand (count_tokens, models, future endpoints) and all headers (OAuth/API keys, beta flags) are relayed verbatim.
поправь баг в `resolvePaths` — тесты в src/lib/paths.ts падают
reaches the model as:
fix the bug in `resolvePaths` — tests in src/lib/paths.ts fail
Always protected, in every mode:
- fenced code blocks (``` / ~~~), including fences split across stream chunks
- indented code blocks, inline code, HTML
- URLs, unix paths (
src/lib/config.ts:42), bare filenames (package.json) - CLI flags (
--verbose), env vars ($HOME,${PATH}) - all markdown syntax:
#, list markers,>, table pipes,**, link targets - tool calls and their JSON, tool results, system prompts, thinking blocks
Machine translation is trained on plain sentences, so structured blocks are also skipped by default — only plain paragraph text is translated. Opt structures in per block type with polyglot scopes on tables lists headings blockquotes.
Chunks already written in the target language are detected by script (Cyrillic, CJK, Arabic, … vs Latin) and skipped.
polyglot claude(orpolyglot proxy) starts a local HTTP relay; Claude Code talks to it viaANTHROPIC_BASE_URL.- On each
POST /v1/messages, user text blocks are translated into English; assistant history is restored to its byte-exact original English from a local translation memory (SQLite), so the model always sees a consistent English conversation and prompt caching keeps working. - The SSE response stream is translated per completed line, with code-fence state threaded across chunks; partial lines are held until they finish. Non-text events pass through untouched.
- Everything is fail-open: a translation error (rate limit, dead network, expired key) forwards the original bytes; a disabled config turns the proxy into a pure relay.
Only prose chunks are sent to Google, batched per message: the keyed API takes up to 64 segments per request, the public endpoint takes one and is called with a small parallelism. Transient failures (429/5xx) are retried twice with backoff.
50+ languages:
ar az be bg bn bs ca cs da de el es et eu fa fi fr gl gu he hi hr hu id is it ja kn ko lt lv ml ms mt nb nl nn pl pt ro ru sk sl sq sr sv ta te th tr uk vi zh-Hans zh-Hant
Codes Google names differently are mapped on the way out (zh-Hans → zh-CN, zh-Hant → zh-TW, nb/nn → no, he → iw).
Every translated request and reply is recorded into a local SQLite database (nothing leaves your machine):
polyglot statsShows calls, translated counts, characters in/out, and average/max latency per direction, plus a daily breakdown (--days N). polyglot stats --reset clears it.
POLYGLOT_DEBUG=1 polyglot claude # proxy errors are appended to the polyglot log dirpolyglot translate "любой текст"polyglot translate --reverse "any text"POLYGLOT_HOME=/some/dir sandboxes every path (config, stats, logs) — used by the test suite. POLYGLOT_GOOGLE_API_KEY=... overrides the stored key for one run.
npm install
npm test # node:test via tsx
npm run typecheck
npm run build # tsdown → dist/Requires Node ≥ 22.5 (built-in SQLite).
- Prose leaves your machine. Every translated chunk is sent to Google — code, paths, tool calls, and system prompts are not, but the sentences around them are. If that is unacceptable, keep polyglot disabled (
polyglot disable) for those sessions. - The
publicmode is an unofficial endpoint with no SLA: Google throttles it per IP and will eventually answer a captcha page instead of a translation. Polyglot reports that clearly and keeps relaying untranslated;polyglot api key <your-key>is the fix. - The
keymode is billed per character by Google Cloud — a long session translates a lot of characters.polyglot statsshows how many. - Machine translation is fast, not literary. Technical prose comes through fine; idioms may wobble.
- Claude's replies are stored in your language in the session transcript (the proxy restores the English original for the model on every turn).
- Latin↔Latin pairs (e.g. de↔en) can't be script-detected, so already-English prompts are still run through the translator.
- Thinking blocks stay in English (they are cryptographically signed and must not be modified).
MIT