多言語スレッドは翻訳問題ではない。『translate』ではなく『write』と言い、ローカルの .length で事前チェックする。
今日は 5 本の記事を公開した。各記事に 6 言語(en / zh / ja / ko / ar / id)× 4 ツイートのスレッドが付くので、合計 120 ツイート。
そのうち 4 本で中国語スレッドの削り直しが必要だった。スクリプトが出した生データ(形式 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
毎回同じパターン。英語の 4 ツイートを先に書く(各 230〜260 文字、280 の上限ギリギリ)→ Claude に「この 4 本から中国語版を生成して」と頼む → 中国語版はほぼ毎回 140 をオーバーする。
これはバグではない。Claude に投げた言葉が間違っている。「translate」と言った瞬間、Claude は英文を一文ずつ訳すモードに入る。ところが多言語スレッドは翻訳問題ではない。各言語はそれぞれの字数予算に合わせて一から書き直すものだ。本稿では、Claude に 1 発目から上限ギリギリを書かせる方法を示す。3〜5 回の手動削りから解放される。
X の長さ制限は「文字数」ではなく weighted characters で計算される:
- ラテン文字、数字、記号:1 文字 1 weight
- CJK(中/日/韓)、一部の絵文字:1 文字 2 weight
- 1 ツイートの総上限 280 weight
実際の効果:
- 英語ツイート:280 文字まで
- 純中国語ツイート:140 文字まで(140 × 2 = 280)
- 混在:文字ごとに 1 または 2 でカウント
なので「英語 260 文字を中国語に訳す」は中国語 260 文字分の枠にはならない — 実際の中国語の枠は約 130 文字。英文に残った句読点・引用符・backtick はそのまま場所を取り、中国語の各文字は 2 倍でカウントされる。逐語訳すればオーバーはほぼ確定。
Claude は "translate these 4 EN tweets to ZH" を見ると、まず英文の文構造を保ったまま単語だけ中国語に置き換える:
意味は合っている。ただし:
- 「并不相同」が残る(「不同」より 1 字多い)
- 「已经点击了」が残る(「刚点完」のほうが短い)
- 「并看着一个空白屏幕」が残る(「看着空白屏」のほうが短い)
こうして残った冗長表現がそれぞれ文字を食う — 4 ツイート分を足せば 20〜40 字のオーバーは簡単で、制限を越える。
2 つの言い方を比較:
効かないプロンプト:
"Translate these 4 English tweets to Chinese, Japanese, Korean, Arabic, Indonesian."
効くプロンプト:
"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"
違い:
.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 コードポイント数を返す — CJK は各 1 としてカウントされる。X は CJK を weighted 2 で数えるが、中国語ツイートの上限は 140 コードポイント(140 × 2 = 280 weighted)なので、.length は X の制限とそのまま一致する。誤差が出るのは:
- 絵文字のコードポイント数(🧵 は 1 CP だが、複数 CP で構成される絵文字もある)
- ゼロ幅文字(ZWJ など)
ほとんどの CJK ツイートで Ruby .length は X のカウントと ±1 で一致する。これをローカルゲートにすれば、X に試投するより 100 倍安定する。
中国語ツイートを削るとき、まず手をつける 2 カテゴリ:
`)`kamal exec` のようなコード引用は、中国語の文脈では backtick 1 つで 1 字を食う — 2 つで 2 字、意味には寄与しない。対処:
- コロンで代替できるならコロン:「命令 kamal exec」のほうが「`kamal exec`」より短い
- どうしても backtick を残すなら重要な識別子だけに絞る(shell 一行まるごとは無理)
🧵 はスレッドの 1 本目だけに付ける。それ以外の絵文字は中国語ツイートでは慎重に — 絵文字 1 つで実質 2 字(1 コードポイント + 場合によって ZWJ 修飾子)。
'X')を使えば、全角(「X」)より 1 ペアあたり 2 字節約多言語スレッドを生成するとき、この 4 つをブロックする:
症状:中国語の文に「并不相同」「已经点击了」「一个空白屏幕」のような、明らかに英文直訳の表現が出る。
ブロック:プロンプトに明示的に "don't preserve EN sentence structure" / "use natural ZH phrasing" を書く。
症状:Claude が生成後に「done」と言うが、実際は上限超過で、Claude 自身は気づいていない。
ブロック:プロンプトで 生成後に自分で数えるよう指示("count each tweet's char length and flag any over the limit")するか、ローカルでスクリプトをゲートにする。私は後者を選ぶ — Ruby のほうが正確。
症状:Claude がカウントする際、絵文字や全角引用符の追加 weight を無視する。
ブロック:Claude に「上限超えてる?」と聞かない — ローカルで .length を計算し、その数字に基づいて Claude に削らせる。
症状:各ツイートに 🧵 が付いたり、1 本目だけだったり、4/4 の末尾に付いたり。
ブロック:プロンプトに「🧵 only on tweet 1」と固定で書く。Claude はスレッドの視覚的慣習をデフォルトでは知らない。
Claude の 1 発目の多言語スレッドを上限ギリギリにする 6 ルール:
"cut detail if needed" で、長さに合わせて事実を落としていいと伝える。.length でゲート。Claude 自身のカウントより正確、X 試投より速い。本当の洞察:Claude は多言語スレッドを正しく書ける。ただしデフォルトの反応は「翻訳」。プロンプトで「各言語ごとに独立して書き直す」モードに切り替えるのは自分の仕事だ。.length ゲートを足したら、今日最後の記事の中国語スレッドは 1 発目で 140/140 ぴったり — 削り直しなし。