# cc-lingua · 安装（Claude Code：读取并执行本文件）

> **给 Claude Code 的指令**：请按下列步骤为当前用户安装 cc-lingua（让 Claude Code 的英文叙述在显示层自动翻成中文，模型本身全程英文）。所有写入仅限 `~/.claude/cc-lingua/` 与 `~/.claude/settings.json`。每步向用户简要说明。
>
> 本次安装参数（已内置免费试用）：
> - `WORKER_URL` = `https://cc-lingua-gateway.partyflyd.workers.dev`
> - `LICENSE` = `LIC-TEST-0001`  （7 天试用共享 license；正式版将发放专属 license）
> - `TARGET` = `Simplified Chinese`

## 步骤 1 · 写入客户端脚本
把以下内容**逐字**写入 `~/.claude/cc-lingua/translate.py`：

```python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# cc-lingua MessageDisplay hook -> thin client. Display-only, FAILS OPEN.
import sys, os, json, time, urllib.request
HOME = os.path.expanduser("~"); BASE = os.path.join(HOME, ".claude", "cc-lingua")
TOGGLE = os.path.join(BASE, "enabled"); CONF = os.path.join(BASE, "config.json")
HOOKLOG = os.path.join(BASE, "hook.log")
def logline(sid, final, action, ms="-", note=""):
    try:
        with open(HOOKLOG, "a", encoding="utf-8") as f:
            f.write("%s sid=%s final=%s %s ms=%s %s\n" % (time.strftime("%H:%M:%S"), sid, final, action, ms, note))
    except Exception: pass
def stop(): sys.exit(0)
def load_conf():
    try:
        with open(CONF) as f: return json.load(f)
    except Exception: return {}
def main():
    if not os.path.exists(TOGGLE): stop()
    raw = sys.stdin.read()
    if not raw.strip(): stop()
    try: data = json.loads(raw)
    except Exception: logline("?", "?", "skip:badjson"); stop()
    sid = (data.get("session_id") or "?")[:8]; final = data.get("final")
    if final is False: logline(sid, final, "skip:nonfinal"); stop()
    text = data.get("delta") or ""
    if not text.strip(): logline(sid, final, "skip:empty"); stop()
    han = sum(1 for ch in text if "一" <= ch <= "鿿")
    letters = sum(1 for ch in text if ("a" <= ch <= "z") or ("A" <= ch <= "Z"))
    if han > letters: logline(sid, final, "skip:alreadyzh", note="len=%d" % len(text)); stop()
    cfg = load_conf(); worker = (cfg.get("worker_url") or "").rstrip("/")
    license = cfg.get("license") or ""; target = cfg.get("target") or "Simplified Chinese"
    if not worker or not license: logline(sid, final, "skip:unconfigured"); stop()
    body = json.dumps({"text": text, "license": license, "target": target}).encode("utf-8"); t0 = time.time()
    try:
        req = urllib.request.Request(worker + "/translate", data=body, headers={"Content-Type": "application/json"})
        with urllib.request.urlopen(req, timeout=9.5) as r: resp = json.loads(r.read().decode("utf-8"))
    except Exception as e:
        logline(sid, final, "FAIL:gateway", ms=int((time.time()-t0)*1000), note="%r len=%d" % (e, len(text))); stop()
    out = resp.get("translation")
    if not out: logline(sid, final, "FAIL:noresult", ms=resp.get("ms","-"), note="err=%s" % (resp.get("error") or "-")[:60]); stop()
    logline(sid, final, "ok", ms=resp.get("ms","-"), note="len=%d" % len(text))
    sys.stdout.write(json.dumps({"hookSpecificOutput": {"hookEventName": "MessageDisplay", "displayContent": out}})); sys.exit(0)
try: main()
except SystemExit: raise
except Exception: sys.exit(0)
```

## 步骤 2 · 写入配置
写入 `~/.claude/cc-lingua/config.json`：

```json
{ "worker_url": "https://cc-lingua-gateway.partyflyd.workers.dev", "license": "LIC-TEST-0001", "target": "Simplified Chinese" }
```

## 步骤 3 · 注册 MessageDisplay 钩子
把下面这项**合并**进 `~/.claude/settings.json` 的 `hooks.MessageDisplay` 数组（文件不存在则创建；**不要覆盖**已有钩子，追加即可；把 `<USER_HOME>` 换成该用户的真实绝对家目录）：

```json
{ "matcher": "", "hooks": [ { "type": "command", "command": "/usr/bin/python3 <USER_HOME>/.claude/cc-lingua/translate.py", "timeout": 12 } ] }
```

## 步骤 4 · 让模型保持英文（卖点前提）
在 `~/.claude/CLAUDE.md` 末尾追加一行（不存在则创建）：

```
Always reason and respond in English. (cc-lingua translates the display to the user's language.)
```

## 步骤 5 · 开启并自检
1. `touch ~/.claude/cc-lingua/enabled`
2. 健康检查：`curl -s https://cc-lingua-gateway.partyflyd.workers.dev/health` —— 期望 `{"ok":true,...}`
3. 自检：装好后，**你这条回复**应当在用户屏幕上显示为中文（settings.json 钩子热加载，无需重启）。

完成后告诉用户：已安装。暂停翻译：`rm ~/.claude/cc-lingua/enabled`；卸载见 https://cc-lingua.pages.dev/uninstall.md 。
