cctrans 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -15,6 +15,24 @@ A **bilingual overlay** for Claude Code: every reply gets a translated line (Chi
15
15
  - **No history pollution, no main-loop tokens**: translation runs through a **separate cheap backend**, completely outside your Claude Code session.
16
16
  - **One-key toggle**: on by default; switch it off instantly when you want plain English.
17
17
 
18
+ ## Why
19
+
20
+ Two problems, one architecture:
21
+
22
+ **1. Claude Code keeps replying in English.** Skills and docs must stay English, and even with a "reply in my language" rule in CLAUDE.md, replies drift back to English. Re-asking for a translation costs a full model turn and pollutes the conversation history.
23
+
24
+ **2. Working in your language has a hidden token tax — on Claude specifically.** Expressing the same meaning costs **~1.5–3× more tokens** than English (Claude's tokenizer compresses non-Latin scripts poorly), and Claude Code's 5-hour window and weekly caps are measured in tokens — so non-English sessions burn your plan 1.5–3× faster. Crucially, **answer quality is not the problem**: Claude scores >90% on multilingual benchmarks. The pain is purely cost.
25
+
26
+ | | ja | ko | ru | hi | zh |
27
+ |---|---|---|---|---|---|
28
+ | Token cost vs English | ~2–3× | ~2–3×+ | ~1.5× | ~2–3×+ | ~2–3× |
29
+
30
+ Anthropic's tracking issue for language-adjusted limits ([#26401](https://github.com/anthropics/claude-code/issues/26401)) was closed *not planned* — there is no first-party remedy.
31
+
32
+ **So the cheapest correct design is exactly what this tool does:** the session stays English end-to-end (prompts, transcript, model context — zero extra main-loop tokens), and your language exists only where the human needs it: a display-only translated line under each English line, rendered by a separate cheap backend.
33
+
34
+ Full research notes with sources: [MOTIVATION.md](MOTIVATION.md).
35
+
18
36
  ## How it works
19
37
 
20
38
  Built on Claude Code's native **`MessageDisplay` hook** (v2.1.152+): it fires while each assistant message renders, handing the hook each completed text chunk (`delta`); the `displayContent` the hook returns **replaces the on-screen rendering only**, never the stored message.
@@ -35,72 +53,72 @@ Claude streams English
35
53
  ## Install
36
54
 
37
55
  ```bash
38
- npm install -g cctrans && tt install
56
+ npm install -g cctrans && cctrans install
39
57
 
40
58
  # from source:
41
59
  git clone https://github.com/roy-jiang-opus/cctranslate.git
42
60
  cd cctranslate
43
- node bin/tt.js install # registers the hooks, links tt into ~/.local/bin, then runs the setup wizard
61
+ node bin/cctrans.js install # registers the hooks, links cctrans into ~/.local/bin, then runs the setup wizard
44
62
  ```
45
63
 
46
64
  Then **restart Claude Code** (new session) so the hook loads. Send any message — replies become bilingual.
47
65
 
48
66
  > Requires `~/.local/bin` on your PATH; otherwise use an alias:
49
- > `alias tt='node /path/to/cctranslate/bin/tt.js'`
67
+ > `alias cctrans='node /path/to/cctranslate/bin/cctrans.js'`
50
68
 
51
69
  ## Usage
52
70
 
53
71
  | Command | What it does |
54
72
  |---------|--------------|
55
- | `tt on` / `tt off` / `tt toggle` | turn translation on / off / toggle |
56
- | `tt status` | show state (toggle, hook, backend, language) |
57
- | `tt lang [code]` | show/set target language: `zh-Hans` `zh-Hant` `ja` `ko` `ru` `hi` |
58
- | `tt backend <id>` | switch translation engine |
59
- | `tt backends` | list engines and their availability |
60
- | `tt setup` | interactive wizard: language, backend, API keys |
61
- | `tt key [id] [value]` | manage API keys in `~/.cc-translate/keys.json` |
62
- | `tt input on` / `tt input off` | translate non-English input to English (sent as context) |
63
- | `tt last [N]` | translate the latest (or N-back) reply to the terminal |
64
- | `tt test <text>` | translate ad-hoc text to verify the engine |
65
- | `tt install` / `tt uninstall` | register / remove the hook |
66
-
67
- **Fastest toggle**: type `!tt off` or `!tt on` inside Claude Code's input box (`!` is CC's built-in bash mode — no model call, no tokens).
73
+ | `cctrans on` / `cctrans off` / `cctrans toggle` | turn translation on / off / toggle |
74
+ | `cctrans status` | show state (toggle, hook, backend, language) |
75
+ | `cctrans lang [code]` | show/set target language: `zh-Hans` `zh-Hant` `ja` `ko` `ru` `hi` |
76
+ | `cctrans backend <id>` | switch translation engine |
77
+ | `cctrans backends` | list engines and their availability |
78
+ | `cctrans setup` | interactive wizard: language, backend, API keys |
79
+ | `cctrans key [id] [value]` | manage API keys in `~/.cc-translate/keys.json` |
80
+ | `cctrans input on` / `cctrans input off` | translate non-English input to English (sent as context) |
81
+ | `cctrans last [N]` | translate the latest (or N-back) reply to the terminal |
82
+ | `cctrans test <text>` | translate ad-hoc text to verify the engine |
83
+ | `cctrans install` / `cctrans uninstall` | register / remove the hook |
84
+
85
+ **Fastest toggle**: type `!cctrans off` or `!cctrans on` inside Claude Code's input box (`!` is CC's built-in bash mode — no model call, no tokens).
68
86
 
69
87
  ## Translation backends
70
88
 
71
89
  | Backend | Requires | Speed | Quality | Notes |
72
90
  |---------|----------|-------|---------|-------|
73
- | `openai` (default when key present) | `tt key openai` | ~1.4s/chunk | high | `gpt-4o-mini` batched line translation, preserves code/paths |
74
- | `anthropic` | `tt key anthropic` | ~1s/chunk | high | `claude-haiku-4-5` + structured outputs, strict same-length line arrays (~$0.0005/chunk) |
75
- | `deepl` | `tt key deepl` (free tier: 500k chars/mo) | ~0.5s/chunk | high | best traditional MT; array API aligns lines natively |
76
- | `azure` | `tt key azure` (free: 2M chars/mo) | ~0.5s/chunk | mid-high | optionally `tt key azure-region` |
91
+ | `openai` (default when key present) | `cctrans key openai` | ~1.4s/chunk | high | `gpt-4o-mini` batched line translation, preserves code/paths |
92
+ | `anthropic` | `cctrans key anthropic` | ~1s/chunk | high | `claude-haiku-4-5` + structured outputs, strict same-length line arrays (~$0.0005/chunk) |
93
+ | `deepl` | `cctrans key deepl` (free tier: 500k chars/mo) | ~0.5s/chunk | high | best traditional MT; array API aligns lines natively |
94
+ | `azure` | `cctrans key azure` (free: 2M chars/mo) | ~0.5s/chunk | mid-high | optionally `cctrans key azure-region` |
77
95
  | `google` | nothing | ~0.3s/chunk | mid | free unofficial endpoint; **the fallback when everything else fails** |
78
96
  | `claude-code` | `claude` CLI logged in | ~3-6s/chunk | high | runs on your **Claude subscription** (`claude -p` headless) — zero extra cost but noticeably slower |
79
97
 
80
98
  If the primary backend fails or times out, the chain **falls back to google** — the session is never blocked. Every translated line is cached by backend + language + content hash.
81
99
 
82
- API keys live **only** in `~/.cc-translate/keys.json` (chmod 600) — set them with `tt setup` / `tt key`, or edit the file directly. Shell environment variables are never read, so this tool's keys and your terminal's keys can't contaminate each other.
100
+ API keys live **only** in `~/.cc-translate/keys.json` (chmod 600) — set them with `cctrans setup` / `cctrans key`, or edit the file directly. Shell environment variables are never read, so this tool's keys and your terminal's keys can't contaminate each other.
83
101
 
84
- All other settings (backend, language, marker, models, Azure endpoint) live in `~/.cc-translate/state.json` — change them via `tt` commands or edit the file directly.
102
+ All other settings (backend, language, marker, models, Azure endpoint) live in `~/.cc-translate/state.json` — change them via `cctrans` commands or edit the file directly.
85
103
 
86
104
  ## Languages
87
105
 
88
106
  Target languages cover **CJK + Russian + Hindi** (non-Latin scripts, so "this line is already in the target language" can be detected for free via Unicode ranges and skipped):
89
107
 
90
108
  ```bash
91
- tt lang ja # Japanese
92
- tt lang ko # Korean
93
- tt lang ru # Russian
94
- tt lang hi # Hindi
95
- tt lang zh-Hant # Traditional Chinese
96
- tt lang zh-Hans # Simplified Chinese (default)
109
+ cctrans lang ja # Japanese
110
+ cctrans lang ko # Korean
111
+ cctrans lang ru # Russian
112
+ cctrans lang hi # Hindi
113
+ cctrans lang zh-Hant # Traditional Chinese
114
+ cctrans lang zh-Hans # Simplified Chinese (default)
97
115
  ```
98
116
 
99
117
  Chinese uses BCP-47 **script** codes (`zh-Hans`/`zh-Hant`) — Traditional Chinese is a script, not a region; `zh-CN` / `zh-TW` are accepted as aliases and normalized. Switching takes effect immediately (the hook re-reads state on every call); each language has its own cache.
100
118
 
101
119
  ## Input translation
102
120
 
103
- `tt input on` enables a `UserPromptSubmit` hook: when your prompt is mostly non-English, an English translation is attached as context the model treats as the canonical instruction — you keep typing in your language, the model works in English. (Verified on CC 2.1.169: hooks cannot rewrite the prompt itself, so the original stays in history with the English alongside.) English prompts pass through untouched; any error falls back to sending your prompt as-is.
121
+ `cctrans input on` enables a `UserPromptSubmit` hook: when your prompt is mostly non-English, an English translation is attached as context the model treats as the canonical instruction — you keep typing in your language, the model works in English. (Verified on CC 2.1.169: hooks cannot rewrite the prompt itself, so the original stays in history with the English alongside.) English prompts pass through untouched; any error falls back to sending your prompt as-is.
104
122
 
105
123
  ## Behavior & limits (verified)
106
124
 
@@ -112,5 +130,5 @@ Chinese uses BCP-47 **script** codes (`zh-Hans`/`zh-Hant`) — Traditional Chine
112
130
  ## Uninstall
113
131
 
114
132
  ```bash
115
- node bin/tt.js uninstall # removes the hook; restart Claude Code to take effect
133
+ node bin/cctrans.js uninstall # removes the hook; restart Claude Code to take effect
116
134
  ```
package/README.ru.md CHANGED
@@ -15,6 +15,24 @@
15
15
  - **Не загрязняет историю, не тратит токены основного цикла**: перевод выполняется через **отдельный дешёвый бэкенд**, полностью вне вашей сессии Claude Code.
16
16
  - **Переключение одной командой**: включён по умолчанию; мгновенно выключается, когда нужен чистый английский.
17
17
 
18
+ ## Зачем это нужно
19
+
20
+ Две проблемы, одна архитектура:
21
+
22
+ **1. Claude Code упорно отвечает по-английски.** Skills и документация должны оставаться английскими, и даже с правилом «отвечай по-русски» в CLAUDE.md ответы сползают обратно в английский. Просить перевод заново — это целый ход модели и замусоренная история диалога.
23
+
24
+ **2. Работа на родном языке несёт скрытый «токенный налог» — именно на Claude.** Одно и то же значение стоит **в ~1.5–3 раза больше токенов**, чем по-английски (токенизатор Claude плохо сжимает нелатинские письменности), а 5-часовое окно и недельные лимиты Claude Code измеряются в токенах — неанглийские сессии сжигают тариф в 1.5–3 раза быстрее. Главное: **качество ответов — не проблема**: Claude набирает >90% в мультиязычных бенчмарках. Боль — чисто в стоимости.
25
+
26
+ | | японский | корейский | русский | хинди | китайский |
27
+ |---|---|---|---|---|---|
28
+ | Стоимость токенов vs английский | ~2–3× | ~2–3×+ | ~1.5× | ~2–3×+ | ~2–3× |
29
+
30
+ Issue Anthropic о лимитах с поправкой на язык ([#26401](https://github.com/anthropics/claude-code/issues/26401)) закрыт как *not planned* — официального решения нет.
31
+
32
+ **Поэтому самый дешёвый и правильный дизайн — ровно то, что делает этот инструмент:** сессия остаётся английской от начала до конца (промпты, транскрипт, контекст модели — ноль лишних токенов основного цикла), а ваш язык существует только там, где его читает человек: строка перевода только-для-отображения под каждой английской строкой, отрисованная отдельным дешёвым бэкендом.
33
+
34
+ Полные заметки исследования с источниками: [MOTIVATION.md](MOTIVATION.md).
35
+
18
36
  ## Как это работает
19
37
 
20
38
  Использует нативный хук **`MessageDisplay`** Claude Code (v2.1.152+): он срабатывает при рендеринге каждого сообщения ассистента, передавая хуку завершённый фрагмент текста (`delta`); возвращаемый хуком `displayContent` **заменяет только отображение на экране**, не меняя сохранённое сообщение.
@@ -36,72 +54,72 @@ Claude стримит английский текст
36
54
  ## Установка
37
55
 
38
56
  ```bash
39
- npm install -g cctrans && tt install
57
+ npm install -g cctrans && cctrans install
40
58
 
41
59
  # from source:
42
60
  git clone https://github.com/roy-jiang-opus/cctranslate.git
43
61
  cd cctranslate
44
- node bin/tt.js install # регистрирует хуки, линкует tt в ~/.local/bin, затем запускает мастер настройки
62
+ node bin/cctrans.js install # регистрирует хуки, линкует cctrans в ~/.local/bin, затем запускает мастер настройки
45
63
  ```
46
64
 
47
65
  Затем **перезапустите Claude Code** (новая сессия), чтобы хук загрузился. Отправьте любое сообщение — ответы станут двуязычными.
48
66
 
49
67
  > Требуется `~/.local/bin` в PATH; иначе используйте алиас:
50
- > `alias tt='node /path/to/cctranslate/bin/tt.js'`
68
+ > `alias cctrans='node /path/to/cctranslate/bin/cctrans.js'`
51
69
 
52
70
  ## Использование
53
71
 
54
72
  | Команда | Действие |
55
73
  |---------|----------|
56
- | `tt on` / `tt off` / `tt toggle` | включить / выключить / переключить перевод |
57
- | `tt status` | показать состояние (переключатель, хук, бэкенд, язык) |
58
- | `tt lang [code]` | показать/задать целевой язык: `zh-Hans` `zh-Hant` `ja` `ko` `ru` `hi` |
59
- | `tt backend <id>` | сменить движок перевода |
60
- | `tt backends` | список движков и их доступность |
61
- | `tt setup` | интерактивный мастер: язык, бэкенд, API-ключи |
62
- | `tt key [id] [value]` | управление ключами в `~/.cc-translate/keys.json` |
63
- | `tt input on` / `tt input off` | переводить неанглийский ввод на английский (отправляется как контекст) |
64
- | `tt last [N]` | перевести последний (или N-й с конца) ответ в терминал |
65
- | `tt test <текст>` | перевести произвольный текст для проверки движка |
66
- | `tt install` / `tt uninstall` | зарегистрировать / удалить хук |
67
-
68
- **Самый быстрый способ переключения**: набрать `!tt off` или `!tt on` прямо в поле ввода Claude Code (`!` — встроенный bash-режим CC: без вызова модели, без токенов).
74
+ | `cctrans on` / `cctrans off` / `cctrans toggle` | включить / выключить / переключить перевод |
75
+ | `cctrans status` | показать состояние (переключатель, хук, бэкенд, язык) |
76
+ | `cctrans lang [code]` | показать/задать целевой язык: `zh-Hans` `zh-Hant` `ja` `ko` `ru` `hi` |
77
+ | `cctrans backend <id>` | сменить движок перевода |
78
+ | `cctrans backends` | список движков и их доступность |
79
+ | `cctrans setup` | интерактивный мастер: язык, бэкенд, API-ключи |
80
+ | `cctrans key [id] [value]` | управление ключами в `~/.cc-translate/keys.json` |
81
+ | `cctrans input on` / `cctrans input off` | переводить неанглийский ввод на английский (отправляется как контекст) |
82
+ | `cctrans last [N]` | перевести последний (или N-й с конца) ответ в терминал |
83
+ | `cctrans test <текст>` | перевести произвольный текст для проверки движка |
84
+ | `cctrans install` / `cctrans uninstall` | зарегистрировать / удалить хук |
85
+
86
+ **Самый быстрый способ переключения**: набрать `!cctrans off` или `!cctrans on` прямо в поле ввода Claude Code (`!` — встроенный bash-режим CC: без вызова модели, без токенов).
69
87
 
70
88
  ## Бэкенды перевода
71
89
 
72
90
  | Бэкенд | Требует | Скорость | Качество | Примечание |
73
91
  |--------|---------|----------|----------|------------|
74
- | `openai` (по умолчанию при наличии ключа) | `tt key openai` | ~1.4с/фрагмент | высокое | `gpt-4o-mini`, пакетный перевод строк, сохраняет код/пути |
75
- | `anthropic` | `tt key anthropic` | ~1с/фрагмент | высокое | `claude-haiku-4-5` + structured outputs, строгие массивы строк равной длины (~$0.0005/фрагмент) |
76
- | `deepl` | `tt key deepl` (бесплатно: 500 тыс. симв./мес) | ~0.5с/фрагмент | высокое | лучший классический MT; массивный API нативно выравнивает строки |
77
- | `azure` | `tt key azure` (бесплатно: 2 млн симв./мес) | ~0.5с/фрагмент | среднее+ | опционально `tt key azure-region` |
92
+ | `openai` (по умолчанию при наличии ключа) | `cctrans key openai` | ~1.4с/фрагмент | высокое | `gpt-4o-mini`, пакетный перевод строк, сохраняет код/пути |
93
+ | `anthropic` | `cctrans key anthropic` | ~1с/фрагмент | высокое | `claude-haiku-4-5` + structured outputs, строгие массивы строк равной длины (~$0.0005/фрагмент) |
94
+ | `deepl` | `cctrans key deepl` (бесплатно: 500 тыс. симв./мес) | ~0.5с/фрагмент | высокое | лучший классический MT; массивный API нативно выравнивает строки |
95
+ | `azure` | `cctrans key azure` (бесплатно: 2 млн симв./мес) | ~0.5с/фрагмент | среднее+ | опционально `cctrans key azure-region` |
78
96
  | `google` | ничего | ~0.3с/фрагмент | среднее | бесплатный неофициальный эндпоинт; **резерв при отказе остальных** |
79
97
  | `claude-code` | выполнен вход в `claude` CLI | ~3-6с/фрагмент | высокое | работает на вашей **подписке Claude** (`claude -p` headless) — без доплат, но заметно медленнее |
80
98
 
81
99
  При сбое/таймауте основного бэкенда цепочка **автоматически откатывается на google** — сессия никогда не блокируется. Каждая переведённая строка кэшируется по хэшу «бэкенд + язык + содержимое».
82
100
 
83
- API-ключи хранятся **только** в `~/.cc-translate/keys.json` (chmod 600) — задавайте их через `tt setup` / `tt key` или редактируйте файл напрямую. Переменные окружения оболочки никогда не читаются, поэтому ключи инструмента и ключи терминала не загрязняют друг друга.
101
+ API-ключи хранятся **только** в `~/.cc-translate/keys.json` (chmod 600) — задавайте их через `cctrans setup` / `cctrans key` или редактируйте файл напрямую. Переменные окружения оболочки никогда не читаются, поэтому ключи инструмента и ключи терминала не загрязняют друг друга.
84
102
 
85
- Остальные настройки (бэкенд, язык, маркер, модели, эндпоинт Azure) находятся в `~/.cc-translate/state.json` — меняйте их командами `tt` или правьте файл напрямую.
103
+ Остальные настройки (бэкенд, язык, маркер, модели, эндпоинт Azure) находятся в `~/.cc-translate/state.json` — меняйте их командами `cctrans` или правьте файл напрямую.
86
104
 
87
105
  ## Языки
88
106
 
89
107
  Целевые языки — **CJK + русский + хинди** (нелатинские письменности, поэтому «строка уже на целевом языке» определяется бесплатно по диапазонам Unicode и пропускается):
90
108
 
91
109
  ```bash
92
- tt lang ja # японский
93
- tt lang ko # корейский
94
- tt lang ru # русский
95
- tt lang hi # хинди
96
- tt lang zh-Hant # традиционный китайский
97
- tt lang zh-Hans # упрощённый китайский (по умолчанию)
110
+ cctrans lang ja # японский
111
+ cctrans lang ko # корейский
112
+ cctrans lang ru # русский
113
+ cctrans lang hi # хинди
114
+ cctrans lang zh-Hant # традиционный китайский
115
+ cctrans lang zh-Hans # упрощённый китайский (по умолчанию)
98
116
  ```
99
117
 
100
118
  Для китайского используются **коды письменности** BCP-47 (`zh-Hans`/`zh-Hant`) — традиционный китайский это письменность, а не регион; `zh-CN` / `zh-TW` принимаются как алиасы и нормализуются автоматически. Смена языка применяется мгновенно (хук перечитывает состояние при каждом вызове); кэши языков независимы.
101
119
 
102
120
  ## Перевод ввода
103
121
 
104
- `tt input on` включает хук `UserPromptSubmit`: когда ваш промпт в основном не на английском, английский перевод прикрепляется как контекст, который модель считает каноничной инструкцией — вы продолжаете печатать на родном языке, модель работает на английском. (Проверено на CC 2.1.169: хуки не могут переписать сам промпт, поэтому оригинал остаётся в истории рядом с английским.) Английский ввод проходит без изменений; при любой ошибке промпт безопасно отправляется как есть.
122
+ `cctrans input on` включает хук `UserPromptSubmit`: когда ваш промпт в основном не на английском, английский перевод прикрепляется как контекст, который модель считает каноничной инструкцией — вы продолжаете печатать на родном языке, модель работает на английском. (Проверено на CC 2.1.169: хуки не могут переписать сам промпт, поэтому оригинал остаётся в истории рядом с английским.) Английский ввод проходит без изменений; при любой ошибке промпт безопасно отправляется как есть.
105
123
 
106
124
  ## Поведение и ограничения (проверено)
107
125
 
@@ -113,5 +131,5 @@ tt lang zh-Hans # упрощённый китайский (по умолчан
113
131
  ## Удаление
114
132
 
115
133
  ```bash
116
- node bin/tt.js uninstall # удаляет хук; вступает в силу после перезапуска Claude Code
134
+ node bin/cctrans.js uninstall # удаляет хук; вступает в силу после перезапуска Claude Code
117
135
  ```
package/README.zh-Hans.md CHANGED
@@ -15,6 +15,24 @@
15
15
  - **不污染历史、不耗主对话 token**:翻译由一个**独立的便宜后端**完成,跟你的 Claude Code 会话完全无关。
16
16
  - **一个键开关**:默认常开;读纯英文/代码时一键关掉。
17
17
 
18
+ ## 为什么做这个
19
+
20
+ 两个痛点,一个架构解决:
21
+
22
+ **1. Claude Code 老是回英文。** Skills 和文档必须保持英文,即使在 CLAUDE.md 里写了"用中文回复",回复还是会漂回英文。手动让它重答一遍中文,既花一整轮模型调用,又污染对话历史。
23
+
24
+ **2. 用母语工作有一笔隐形的 token 税——尤其在 Claude 上。** 表达同样的意思,非英语要多花 **约 1.5–3 倍 token**(Claude 的分词器对非拉丁文字压缩很差),而 Claude Code 的 5 小时窗口和每周额度都按 token 计——非英语会话烧额度快 1.5–3 倍。关键是,**模型质量根本不是问题**:Claude 多语言基准 >90%。痛点纯粹是成本。
25
+
26
+ | | 日语 | 韩语 | 俄语 | 印地语 | 中文 |
27
+ |---|---|---|---|---|---|
28
+ | 相对英文的 token 开销 | ~2–3× | ~2–3×+ | ~1.5× | ~2–3×+ | ~2–3× |
29
+
30
+ Anthropic 关于按语言调整额度的 issue([#26401](https://github.com/anthropics/claude-code/issues/26401))已被关闭(*not planned*)——官方没有解法。
31
+
32
+ **所以最省钱且正确的设计正是本工具的做法:** 会话全程保持英文(输入、转录、模型上下文——主对话零额外 token),你的语言只出现在人需要读的地方:每行英文下面一行仅作显示的译文,由独立的便宜后端渲染。
33
+
34
+ 完整调研数据与来源:[MOTIVATION.md](MOTIVATION.md)。
35
+
18
36
  ## 工作原理
19
37
 
20
38
  利用 Claude Code 原生的 **`MessageDisplay` 钩子**(v2.1.152+):它在每条助手消息渲染时触发,把完成的文本片段(`delta`)交给钩子;钩子返回的 `displayContent` **替换屏幕显示**,但不改变存储的消息。
@@ -35,72 +53,72 @@ Claude 流式输出英文
35
53
  ## 安装
36
54
 
37
55
  ```bash
38
- npm install -g cctrans && tt install
56
+ npm install -g cctrans && cctrans install
39
57
 
40
58
  # from source:
41
59
  git clone https://github.com/roy-jiang-opus/cctranslate.git
42
60
  cd cctranslate
43
- node bin/tt.js install # 注册钩子、链接 tt 到 ~/.local/bin,然后运行 setup 向导
61
+ node bin/cctrans.js install # 注册钩子、链接 cctrans 到 ~/.local/bin,然后运行 setup 向导
44
62
  ```
45
63
 
46
64
  然后**重启 Claude Code**(开新会话)让钩子生效。发任意消息,回复就会双语对照。
47
65
 
48
66
  > 需要 `~/.local/bin` 在 PATH 里;否则用别名:
49
- > `alias tt='node /path/to/cctranslate/bin/tt.js'`
67
+ > `alias cctrans='node /path/to/cctranslate/bin/cctrans.js'`
50
68
 
51
69
  ## 使用
52
70
 
53
71
  | 命令 | 作用 |
54
72
  |------|------|
55
- | `tt on` / `tt off` / `tt toggle` | 开 / 关 / 切换翻译 |
56
- | `tt status` | 查看状态(开关、钩子、后端、语言) |
57
- | `tt lang [code]` | 查看/切换目标语言:`zh-Hans` `zh-Hant` `ja` `ko` `ru` `hi` |
58
- | `tt backend <id>` | 切换翻译引擎 |
59
- | `tt backends` | 列出所有引擎及其可用性 |
60
- | `tt setup` | 交互式向导:语言、后端、API key |
61
- | `tt key [id] [value]` | 管理 `~/.cc-translate/keys.json` 里的 API key |
62
- | `tt input on` / `tt input off` | 把非英文输入翻译成英文(作为上下文发给模型) |
63
- | `tt last [N]` | 把最近(或往前第 N 条)回复翻译到终端 |
64
- | `tt test <文本>` | 翻译一段文本,验证引擎 |
65
- | `tt install` / `tt uninstall` | 注册 / 移除钩子 |
66
-
67
- **最快的开关方式**:在 Claude Code 输入框里直接输入 `!tt off` 或 `!tt on`(`!` 是 CC 的内置 bash 模式,不调用模型、不花 token)。
73
+ | `cctrans on` / `cctrans off` / `cctrans toggle` | 开 / 关 / 切换翻译 |
74
+ | `cctrans status` | 查看状态(开关、钩子、后端、语言) |
75
+ | `cctrans lang [code]` | 查看/切换目标语言:`zh-Hans` `zh-Hant` `ja` `ko` `ru` `hi` |
76
+ | `cctrans backend <id>` | 切换翻译引擎 |
77
+ | `cctrans backends` | 列出所有引擎及其可用性 |
78
+ | `cctrans setup` | 交互式向导:语言、后端、API key |
79
+ | `cctrans key [id] [value]` | 管理 `~/.cc-translate/keys.json` 里的 API key |
80
+ | `cctrans input on` / `cctrans input off` | 把非英文输入翻译成英文(作为上下文发给模型) |
81
+ | `cctrans last [N]` | 把最近(或往前第 N 条)回复翻译到终端 |
82
+ | `cctrans test <文本>` | 翻译一段文本,验证引擎 |
83
+ | `cctrans install` / `cctrans uninstall` | 注册 / 移除钩子 |
84
+
85
+ **最快的开关方式**:在 Claude Code 输入框里直接输入 `!cctrans off` 或 `!cctrans on`(`!` 是 CC 的内置 bash 模式,不调用模型、不花 token)。
68
86
 
69
87
  ## 翻译后端
70
88
 
71
89
  | 后端 | 前提 | 速度 | 质量 | 说明 |
72
90
  |------|------|------|------|------|
73
- | `openai`(有 key 时默认) | `tt key openai` | ~1.4s/段 | 高 | `gpt-4o-mini` 批量行翻译,保留代码/路径 |
74
- | `anthropic` | `tt key anthropic` | ~1s/段 | 高 | `claude-haiku-4-5` + structured outputs,严格等长行数组(约 $0.0005/段) |
75
- | `deepl` | `tt key deepl`(免费档 50 万字符/月) | ~0.5s/段 | 高 | 传统 MT 质量天花板;数组接口天然对齐行 |
76
- | `azure` | `tt key azure`(免费 200 万字符/月) | ~0.5s/段 | 中高 | 可加 `tt key azure-region` |
91
+ | `openai`(有 key 时默认) | `cctrans key openai` | ~1.4s/段 | 高 | `gpt-4o-mini` 批量行翻译,保留代码/路径 |
92
+ | `anthropic` | `cctrans key anthropic` | ~1s/段 | 高 | `claude-haiku-4-5` + structured outputs,严格等长行数组(约 $0.0005/段) |
93
+ | `deepl` | `cctrans key deepl`(免费档 50 万字符/月) | ~0.5s/段 | 高 | 传统 MT 质量天花板;数组接口天然对齐行 |
94
+ | `azure` | `cctrans key azure`(免费 200 万字符/月) | ~0.5s/段 | 中高 | 可加 `cctrans key azure-region` |
77
95
  | `google` | 无 | ~0.3s/段 | 中 | 免费非官方接口;**所有后端失败时的兜底** |
78
96
  | `claude-code` | `claude` CLI 已登录 | ~3-6s/段 | 高 | 走你的 **Claude 订阅**(`claude -p` headless),零额外费用但明显慢 |
79
97
 
80
98
  主后端失败/超时会自动**降级到 google**,任何情况下都不会卡住会话。每行译文按「后端+语言+内容」哈希缓存。
81
99
 
82
- API key **只**存放在 `~/.cc-translate/keys.json`(chmod 600)——用 `tt setup` / `tt key` 设置,或直接编辑该文件。终端环境变量永远不会被读取,本工具的 key 和终端的 key 互不污染。
100
+ API key **只**存放在 `~/.cc-translate/keys.json`(chmod 600)——用 `cctrans setup` / `cctrans key` 设置,或直接编辑该文件。终端环境变量永远不会被读取,本工具的 key 和终端的 key 互不污染。
83
101
 
84
- 其余设置(后端、语言、标记、模型、Azure 端点)都在 `~/.cc-translate/state.json` 里——用 `tt` 命令修改或直接编辑文件。
102
+ 其余设置(后端、语言、标记、模型、Azure 端点)都在 `~/.cc-translate/state.json` 里——用 `cctrans` 命令修改或直接编辑文件。
85
103
 
86
104
  ## 多语言
87
105
 
88
106
  目标语言支持 **CJK + 俄语 + 印地语**(非拉丁文字,可按 Unicode 区间零成本判断"该行已是目标语言"并跳过):
89
107
 
90
108
  ```bash
91
- tt lang ja # 日语
92
- tt lang ko # 韩语
93
- tt lang ru # 俄语
94
- tt lang hi # 印地语
95
- tt lang zh-Hant # 繁体中文
96
- tt lang zh-Hans # 简体中文(默认)
109
+ cctrans lang ja # 日语
110
+ cctrans lang ko # 韩语
111
+ cctrans lang ru # 俄语
112
+ cctrans lang hi # 印地语
113
+ cctrans lang zh-Hant # 繁体中文
114
+ cctrans lang zh-Hans # 简体中文(默认)
97
115
  ```
98
116
 
99
117
  中文采用 BCP-47 **文字码**(`zh-Hans`/`zh-Hant`)——繁体是文字系统而非地区;`zh-CN` / `zh-TW` 仍可作为别名使用,会自动归一化。切换语言即刻生效(钩子每次调用都读状态),不同语言的缓存相互独立。
100
118
 
101
119
  ## 输入翻译
102
120
 
103
- `tt input on` 启用 `UserPromptSubmit` 钩子:当你的输入大部分是非英文时,英文译文会作为上下文附给模型并被视为权威指令——你继续用母语打字,模型按英文工作。(已在 CC 2.1.169 核实:钩子无法改写 prompt 本身,所以原文仍在历史里,英文随附。)英文输入原样通过;任何错误都安全回退为原样发送。
121
+ `cctrans input on` 启用 `UserPromptSubmit` 钩子:当你的输入大部分是非英文时,英文译文会作为上下文附给模型并被视为权威指令——你继续用母语打字,模型按英文工作。(已在 CC 2.1.169 核实:钩子无法改写 prompt 本身,所以原文仍在历史里,英文随附。)英文输入原样通过;任何错误都安全回退为原样发送。
104
122
 
105
123
  ## 行为与限制(已核实)
106
124
 
@@ -112,5 +130,5 @@ tt lang zh-Hans # 简体中文(默认)
112
130
  ## 卸载
113
131
 
114
132
  ```bash
115
- node bin/tt.js uninstall # 移除钩子;重启 Claude Code 生效
133
+ node bin/cctrans.js uninstall # 移除钩子;重启 Claude Code 生效
116
134
  ```
package/README.zh-Hant.md CHANGED
@@ -15,6 +15,24 @@
15
15
  - **不污染歷史、不耗主對話 token**:翻譯由一個**獨立的低成本後端**完成,與你的 Claude Code 工作階段完全無關。
16
16
  - **一鍵開關**:預設常開;想讀純英文/程式碼時一鍵關閉。
17
17
 
18
+ ## 為什麼做這個
19
+
20
+ 兩個痛點,一個架構解決:
21
+
22
+ **1. Claude Code 老是回英文。** Skills 與文件必須保持英文,即使在 CLAUDE.md 裡寫了「用中文回覆」,回覆仍會飄回英文。手動讓它重答一遍中文,既花一整輪模型呼叫,又污染對話歷史。
23
+
24
+ **2. 用母語工作有一筆隱形的 token 稅——尤其在 Claude 上。** 表達同樣的意思,非英語要多花 **約 1.5–3 倍 token**(Claude 的分詞器對非拉丁文字壓縮很差),而 Claude Code 的 5 小時視窗與每週額度都按 token 計——非英語工作階段燒額度快 1.5–3 倍。關鍵是,**模型品質根本不是問題**:Claude 多語言基準 >90%。痛點純粹是成本。
25
+
26
+ | | 日語 | 韓語 | 俄語 | 印地語 | 中文 |
27
+ |---|---|---|---|---|---|
28
+ | 相對英文的 token 開銷 | ~2–3× | ~2–3×+ | ~1.5× | ~2–3×+ | ~2–3× |
29
+
30
+ Anthropic 關於按語言調整額度的 issue([#26401](https://github.com/anthropics/claude-code/issues/26401))已被關閉(*not planned*)——官方沒有解法。
31
+
32
+ **所以最省錢且正確的設計正是本工具的做法:** 工作階段全程保持英文(輸入、轉錄、模型上下文——主對話零額外 token),你的語言只出現在人需要讀的地方:每行英文下方一行僅作顯示的譯文,由獨立的低成本後端渲染。
33
+
34
+ 完整調研資料與來源:[MOTIVATION.md](MOTIVATION.md)。
35
+
18
36
  ## 運作原理
19
37
 
20
38
  利用 Claude Code 原生的 **`MessageDisplay` 鉤子**(v2.1.152+):它在每則助理訊息渲染時觸發,把完成的文字片段(`delta`)交給鉤子;鉤子回傳的 `displayContent` **只替換螢幕顯示**,不改變儲存的訊息。
@@ -35,72 +53,72 @@ Claude 串流輸出英文
35
53
  ## 安裝
36
54
 
37
55
  ```bash
38
- npm install -g cctrans && tt install
56
+ npm install -g cctrans && cctrans install
39
57
 
40
58
  # from source:
41
59
  git clone https://github.com/roy-jiang-opus/cctranslate.git
42
60
  cd cctranslate
43
- node bin/tt.js install # 註冊鉤子、連結 tt 到 ~/.local/bin,然後執行 setup 精靈
61
+ node bin/cctrans.js install # 註冊鉤子、連結 cctrans 到 ~/.local/bin,然後執行 setup 精靈
44
62
  ```
45
63
 
46
64
  接著**重新啟動 Claude Code**(開新工作階段)讓鉤子生效。送出任意訊息,回覆就會雙語對照。
47
65
 
48
66
  > 需要 `~/.local/bin` 在 PATH 中;否則使用別名:
49
- > `alias tt='node /path/to/cctranslate/bin/tt.js'`
67
+ > `alias cctrans='node /path/to/cctranslate/bin/cctrans.js'`
50
68
 
51
69
  ## 使用
52
70
 
53
71
  | 指令 | 作用 |
54
72
  |------|------|
55
- | `tt on` / `tt off` / `tt toggle` | 開 / 關 / 切換翻譯 |
56
- | `tt status` | 檢視狀態(開關、鉤子、後端、語言) |
57
- | `tt lang [code]` | 檢視/切換目標語言:`zh-Hans` `zh-Hant` `ja` `ko` `ru` `hi` |
58
- | `tt backend <id>` | 切換翻譯引擎 |
59
- | `tt backends` | 列出所有引擎及其可用性 |
60
- | `tt setup` | 互動式精靈:語言、後端、API key |
61
- | `tt key [id] [value]` | 管理 `~/.cc-translate/keys.json` 中的 API key |
62
- | `tt input on` / `tt input off` | 把非英文輸入翻譯成英文(作為上下文傳給模型) |
63
- | `tt last [N]` | 把最近(或往前第 N 則)回覆翻譯到終端機 |
64
- | `tt test <文字>` | 翻譯一段文字,驗證引擎 |
65
- | `tt install` / `tt uninstall` | 註冊 / 移除鉤子 |
66
-
67
- **最快的開關方式**:在 Claude Code 輸入框直接輸入 `!tt off` 或 `!tt on`(`!` 是 CC 內建的 bash 模式,不呼叫模型、不花 token)。
73
+ | `cctrans on` / `cctrans off` / `cctrans toggle` | 開 / 關 / 切換翻譯 |
74
+ | `cctrans status` | 檢視狀態(開關、鉤子、後端、語言) |
75
+ | `cctrans lang [code]` | 檢視/切換目標語言:`zh-Hans` `zh-Hant` `ja` `ko` `ru` `hi` |
76
+ | `cctrans backend <id>` | 切換翻譯引擎 |
77
+ | `cctrans backends` | 列出所有引擎及其可用性 |
78
+ | `cctrans setup` | 互動式精靈:語言、後端、API key |
79
+ | `cctrans key [id] [value]` | 管理 `~/.cc-translate/keys.json` 中的 API key |
80
+ | `cctrans input on` / `cctrans input off` | 把非英文輸入翻譯成英文(作為上下文傳給模型) |
81
+ | `cctrans last [N]` | 把最近(或往前第 N 則)回覆翻譯到終端機 |
82
+ | `cctrans test <文字>` | 翻譯一段文字,驗證引擎 |
83
+ | `cctrans install` / `cctrans uninstall` | 註冊 / 移除鉤子 |
84
+
85
+ **最快的開關方式**:在 Claude Code 輸入框直接輸入 `!cctrans off` 或 `!cctrans on`(`!` 是 CC 內建的 bash 模式,不呼叫模型、不花 token)。
68
86
 
69
87
  ## 翻譯後端
70
88
 
71
89
  | 後端 | 前提 | 速度 | 品質 | 說明 |
72
90
  |------|------|------|------|------|
73
- | `openai`(有 key 時預設) | `tt key openai` | ~1.4s/段 | 高 | `gpt-4o-mini` 批次行翻譯,保留程式碼/路徑 |
74
- | `anthropic` | `tt key anthropic` | ~1s/段 | 高 | `claude-haiku-4-5` + structured outputs,嚴格等長行陣列(約 $0.0005/段) |
75
- | `deepl` | `tt key deepl`(免費額度 50 萬字元/月) | ~0.5s/段 | 高 | 傳統 MT 品質天花板;陣列介面天然對齊行 |
76
- | `azure` | `tt key azure`(免費 200 萬字元/月) | ~0.5s/段 | 中高 | 可加 `tt key azure-region` |
91
+ | `openai`(有 key 時預設) | `cctrans key openai` | ~1.4s/段 | 高 | `gpt-4o-mini` 批次行翻譯,保留程式碼/路徑 |
92
+ | `anthropic` | `cctrans key anthropic` | ~1s/段 | 高 | `claude-haiku-4-5` + structured outputs,嚴格等長行陣列(約 $0.0005/段) |
93
+ | `deepl` | `cctrans key deepl`(免費額度 50 萬字元/月) | ~0.5s/段 | 高 | 傳統 MT 品質天花板;陣列介面天然對齊行 |
94
+ | `azure` | `cctrans key azure`(免費 200 萬字元/月) | ~0.5s/段 | 中高 | 可加 `cctrans key azure-region` |
77
95
  | `google` | 無 | ~0.3s/段 | 中 | 免費非官方介面;**所有後端失敗時的保底** |
78
96
  | `claude-code` | `claude` CLI 已登入 | ~3-6s/段 | 高 | 走你的 **Claude 訂閱**(`claude -p` headless),零額外費用但明顯較慢 |
79
97
 
80
98
  主後端失敗/逾時會自動**降級到 google**,任何情況下都不會卡住工作階段。每行譯文按「後端+語言+內容」雜湊快取。
81
99
 
82
- API key **只**存放在 `~/.cc-translate/keys.json`(chmod 600)——用 `tt setup` / `tt key` 設定,或直接編輯該檔案。終端機環境變數永遠不會被讀取,本工具的 key 與終端機的 key 互不污染。
100
+ API key **只**存放在 `~/.cc-translate/keys.json`(chmod 600)——用 `cctrans setup` / `cctrans key` 設定,或直接編輯該檔案。終端機環境變數永遠不會被讀取,本工具的 key 與終端機的 key 互不污染。
83
101
 
84
- 其餘設定(後端、語言、標記、模型、Azure 端點)都在 `~/.cc-translate/state.json` 中——用 `tt` 指令修改或直接編輯檔案。
102
+ 其餘設定(後端、語言、標記、模型、Azure 端點)都在 `~/.cc-translate/state.json` 中——用 `cctrans` 指令修改或直接編輯檔案。
85
103
 
86
104
  ## 多語言
87
105
 
88
106
  目標語言支援 **CJK + 俄語 + 印地語**(非拉丁文字,可按 Unicode 區間零成本判斷「該行已是目標語言」並跳過):
89
107
 
90
108
  ```bash
91
- tt lang ja # 日語
92
- tt lang ko # 韓語
93
- tt lang ru # 俄語
94
- tt lang hi # 印地語
95
- tt lang zh-Hant # 繁體中文
96
- tt lang zh-Hans # 簡體中文(預設)
109
+ cctrans lang ja # 日語
110
+ cctrans lang ko # 韓語
111
+ cctrans lang ru # 俄語
112
+ cctrans lang hi # 印地語
113
+ cctrans lang zh-Hant # 繁體中文
114
+ cctrans lang zh-Hans # 簡體中文(預設)
97
115
  ```
98
116
 
99
117
  中文採用 BCP-47 **文字碼**(`zh-Hans`/`zh-Hant`)——繁體是文字系統而非地區;`zh-CN` / `zh-TW` 仍可作為別名使用,會自動正規化。切換語言立即生效(鉤子每次呼叫都讀取狀態),不同語言的快取相互獨立。
100
118
 
101
119
  ## 輸入翻譯
102
120
 
103
- `tt input on` 啟用 `UserPromptSubmit` 鉤子:當你的輸入大多是非英文時,英文譯文會作為上下文附給模型並被視為權威指令——你繼續用母語打字,模型按英文工作。(已在 CC 2.1.169 核實:鉤子無法改寫 prompt 本身,所以原文仍在歷史中,英文隨附。)英文輸入原樣通過;任何錯誤都安全回退為原樣送出。
121
+ `cctrans input on` 啟用 `UserPromptSubmit` 鉤子:當你的輸入大多是非英文時,英文譯文會作為上下文附給模型並被視為權威指令——你繼續用母語打字,模型按英文工作。(已在 CC 2.1.169 核實:鉤子無法改寫 prompt 本身,所以原文仍在歷史中,英文隨附。)英文輸入原樣通過;任何錯誤都安全回退為原樣送出。
104
122
 
105
123
  ## 行為與限制(已核實)
106
124
 
@@ -112,5 +130,5 @@ tt lang zh-Hans # 簡體中文(預設)
112
130
  ## 解除安裝
113
131
 
114
132
  ```bash
115
- node bin/tt.js uninstall # 移除鉤子;重新啟動 Claude Code 生效
133
+ node bin/cctrans.js uninstall # 移除鉤子;重新啟動 Claude Code 生效
116
134
  ```
package/ROADMAP.md CHANGED
@@ -3,13 +3,13 @@
3
3
  ## Shipped
4
4
 
5
5
  ### ✅ Input translation — write in your language, send in English
6
- `tt input on` enables a `UserPromptSubmit` hook: prompts that are mostly non-English get an English translation attached as `additionalContext`, which the model treats as the canonical instruction. Implementation note: Claude Code hooks provably cannot rewrite the prompt itself (verified against the 2.1.169 **and 2.1.170** binaries — the `UserPromptSubmit`/`UserPromptExpansion` output schemas only allow `additionalContext` and block), so attach-as-context is the strongest available form; the original prompt stays in history with the English alongside. If a future CC release adds a prompt-rewrite field, switching to true replacement is a one-line change in `hook/user-prompt-submit.js`.
6
+ `cctrans input on` enables a `UserPromptSubmit` hook: prompts that are mostly non-English get an English translation attached as `additionalContext`, which the model treats as the canonical instruction. Implementation note: Claude Code hooks provably cannot rewrite the prompt itself (verified against the 2.1.169 **and 2.1.170** binaries — the `UserPromptSubmit`/`UserPromptExpansion` output schemas only allow `additionalContext` and block), so attach-as-context is the strongest available form; the original prompt stays in history with the English alongside. If a future CC release adds a prompt-rewrite field, switching to true replacement is a one-line change in `hook/user-prompt-submit.js`.
7
7
 
8
8
  ### ✅ Interactive setup wizard
9
- `tt install` registers both hooks and launches the wizard; `tt setup` re-runs it anytime. Walks through target language → backend selection → key entry for the chosen backend → live translation verification. Non-interactive flags: `--lang`, `--backend`, `--key`, `--yes`.
9
+ `cctrans install` registers both hooks and launches the wizard; `cctrans setup` re-runs it anytime. Walks through target language → backend selection → key entry for the chosen backend → live translation verification. Non-interactive flags: `--lang`, `--backend`, `--key`, `--yes`.
10
10
 
11
11
  ### ✅ Per-tool API-key config (no env cross-pollution)
12
- Keys live **only** in `~/.cc-translate/keys.json` (chmod 600, atomic writes), managed via `tt key <id> [value|--clear]`, the setup wizard, or direct file edits. Shell environment variables are **never** consulted — no overrides, no opt-in. All non-secret settings (backend, language, marker, models, Azure endpoint) live in `~/.cc-translate/state.json`. The only env vars the tool reads are internal plumbing: `TT_HOME` / `TT_TRANSCRIPT` (tests) and `TT_DISABLE` / `TT_DEBUG_STDIN` (hook internals).
12
+ Keys live **only** in `~/.cc-translate/keys.json` (chmod 600, atomic writes), managed via `cctrans key <id> [value|--clear]`, the setup wizard, or direct file edits. Shell environment variables are **never** consulted — no overrides, no opt-in. All non-secret settings (backend, language, marker, models, Azure endpoint) live in `~/.cc-translate/state.json`. The only env vars the tool reads are internal plumbing: `CCTRANS_HOME` / `CCTRANS_TRANSCRIPT` (tests) and `CCTRANS_DISABLE` / `CCTRANS_DEBUG_STDIN` (hook internals).
13
13
 
14
14
  ## Planned
15
15