多语言 thread 不是翻译问题:用 write 替代 translate,配 .length 本地闸门,一版就近限。
今天发了 5 篇文章。每篇带 6 种语言的推文 thread(en / zh / ja / ko / ar / id),每种语言 4 条,一共 120 条推文。
其中 4 篇都得给中文推文做裁剪。原始数字(script 打印,格式 chars/limit):
zh[1]=160/140 OVER
zh[2]=164/140 OVER
zh[3]=152/140 OVER
...
id[3]=286/280 OVER
zh[2]=163/140 OVER
zh[3]=148/140 OVER
zh[2]=152/140 OVER
每次都是同样的模式:英文四条先写好(每条 230-260 字符,接近 280 的限额),然后让 Claude "基于这四条生成中文版"。结果中文版本基本都超 140。
这事不是 bug,是你对 Claude 说了错词——"翻译"两个字会让它逐句翻,而多语言 thread 不是翻译问题,每种语言都得按自己的限额从头写。本文讲怎么让 Claude 第一版就近限,不用 3-5 轮裁剪。
X 的长度限制不是按"字符数"算,而是按 weighted characters:
- 拉丁字母、数字、标点:1 weight 每字符
- CJK 字符(中/日/韩)、某些 emoji:2 weight 每字符
- 推文总上限 280 weight
实际效果:
- 英文推文上限 280 字符
- 纯中文推文上限 140 字符(140 × 2 = 280)
- 中英混排按每字符 1 或 2 算
所以"英文 260 字符翻成中文"不是中文版 260 字——中文版只有 130 字的空间。英文保留的所有标点、引号、代码块 backtick 都还占位,但中文字符每个都 double。翻译出来必然超。
Claude 看到 "translate these 4 EN tweets to ZH" 时,第一反应是保留英文句子结构,只把字换成中文:
意思对,但:
- 保留了"并不相同"(比"不同"多一字)
- 保留了"已经点击了"("刚点完"更短)
- 保留了"并看着一个空白屏幕"("看着空白屏"更短)
每一处保留的冗余都占字——积累 4 条,差个 20-40 字轻松,然后就超限了。
对比两个措辞:
无效 prompt:
"Translate these 4 English tweets to Chinese, Japanese, Korean, Arabic, Indonesian."
有效 prompt:
"For each of these 4 points, write a thread in ZH / JA / KO / AR / ID. Each language gets a fresh pass — same argument, adjusted for that language's tweet budget.
- ZH: ≤ 140 chars per tweet, hook-first, cut detail if needed
- other languages: ≤ 280 chars
- use each language's natural phrasing, don't preserve EN sentence structure
- each tweet must be self-contained but add 🧵 only on tweet 1"
差别:
1. "write" 替代 "translate"——触发 Claude 的创作模式,不是翻译模式
2. "fresh pass" / "same argument"——允许 Claude 重新组织句子
3. "don't preserve EN sentence structure"——直接挡掉默认行为
4. "cut detail if needed"——给它删内容的权限(不给的话它会保留全部事实再超限)
5. 每语言明确限额——数字写死,不是"short"
.length别依赖肉眼数。写个小脚本每次都跑:
tweets.each do |loc, list|
list.each_with_index do |t, i|
len = t.length
limit = loc == "zh" ? 140 : 280
status = len > limit ? "OVER" : "ok"
puts "#{loc}[#{i}]=#{len}/#{limit} #{status}"
end
end
Ruby String#length 返回 Unicode codepoints——对 CJK 字符每个算 1。X 把 CJK 按 2 weighted char 算,但中文推文限 140 codepoints(因为 140 × 2 = 280 weighted),所以 .length 直接和 X 的限额对齐。误差只来自:
- emoji 的 codepoint 数(🧵 是 1 codepoint,但有些 emoji 由多个 codepoint 组成)
- 零宽字符(ZWJ 等)
绝大多数情况下 Ruby .length 对 CJK 推文 ± 1 字符就和 X 计数一致。用它做前置闸门比上 X 试发靠谱 100 倍。
中文推文里要省字,两类字符最先砍:
`)代码引用 `kamal exec` 在中文语境里每个 backtick 吃 1 字——一段代码引用就吃 2 字,还不贡献语义。做法:
- 能用冒号提示的就用冒号:「命令 kamal exec」而不是「`kamal exec`」
- 真必要保留 backtick 的地方只给关键标识符,不给整段 shell
🧵 只在 thread 第一条加。其他 emoji 在中文推文里慎用——每个 emoji 基本占 2 字(1 codepoint + 有时候 ZWJ 修饰符)。
'X')比全角(「X」)每对省 2 字让 Claude 生成多语言 thread 时这 4 个要拦:
症状:中文句子里出现「并不相同」「已经点击了」「一个空白屏幕」这种显然从英文直译过来的表达。
拦法:prompt 里明写 "don't preserve EN sentence structure"、"use natural ZH phrasing"。
症状:Claude 生成完说"done",实际超限但它不知道。
拦法:prompt 要求 Claude 生成完自己数一遍("count each tweet's char length and flag any over the limit"),或者你本地跑 script 作为闸门。我选后者——Claude 自己数不如 Ruby 精确。
症状:Claude 数的时候忽略 emoji 和全角引号的额外 weight。
拦法:不要问 Claude "是否超限"——直接本地算 .length,再根据结果让 Claude 缩。
症状:有时候 Claude 每条都加 🧵、有时候只加第一条、有时候加在 4/4 结尾。
拦法:prompt 明写"🧵 only on tweet 1"。这件事 Claude 不默认知道 thread 的视觉约定。
让 Claude 第一版就生成近限多语言 thread 的 6 条:
"cut detail if needed" 让 Claude 知道它可以损失细节去适配长度。.length 做前置闸门。比 Claude 自己数准、比上 X 试发快。真正的洞见:Claude 能写对多语言 thread,但它默认的反应是"翻译"——你要用 prompt 把它拨到"按每语言独立重写"的模式。加上 .length 闸门后,今天最后一篇的中文推文第一版就是 140/140 整好——不用裁剪。