다국어 스레드는 번역 문제가 아니다. '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의 첫 드래프트를 한도 근처로 뽑아내서 3~5라운드 손절을 피하는 방법이다.
X의 길이 제한은 "글자 수"가 아니라 weighted characters로 계산된다:
- 라틴 문자, 숫자, 구두점: 글자당 1 weight
- CJK 문자(중/일/한), 일부 이모지: 글자당 2 weight
- 트윗 총 상한 280 weight
실제 효과:
- 영어 트윗 상한 280자
- 순수 중국어 트윗 상한 140자(140 × 2 = 280)
- 혼합: 글자별 1 또는 2로 계산
그래서 "영어 260자를 중국어로 번역"은 중국어 260자가 아니라 — 중국어 버전은 실제로 약 130자 공간뿐이다. 영문에 남은 구두점·따옴표·backtick은 그대로 자리를 차지하고, 중국어 글자는 전부 두 배로 센다. 직역하면 초과는 거의 확실하다.
Claude가 "translate these 4 EN tweets to ZH"를 보면, 첫 반응은 영어 문장 구조를 유지한 채 단어만 중국어로 바꾸는 것이다:
의미는 맞다. 하지만:
- "并不相同"을 유지("不同"보다 한 글자 길다)
- "已经点击了"를 유지("刚点完"이 더 짧다)
- "并看着一个空白屏幕"를 유지("看着空白屏"이 더 짧다)
유지된 잉여 표현 하나하나가 글자를 먹는다. 트윗 4개에 누적하면 20~40자 초과는 쉽게 발생하고, 한도를 넘긴다.
두 표현 비교:
안 되는 프롬프트:
"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배 안정적이다.
중국어 트윗을 줄일 때 가장 먼저 손대야 할 두 범주:
`)`kamal exec` 같은 코드 인용은 중국어 맥락에서 backtick 하나당 1글자를 먹는다 — 한 쌍이면 2글자, 의미에는 기여하지 않는다. 대처:
- 콜론으로 대체 가능하면 콜론: "명령 kamal exec"이 "`kamal exec`"보다 짧다
- 꼭 backtick을 남겨야 하면 핵심 식별자만(전체 shell 라인은 안 된다)
🧵는 스레드 첫 트윗에만 붙인다. 다른 이모지는 중국어 트윗에서 신중하게 — 이모지 하나는 사실상 2글자(1 코드포인트 + 때때로 ZWJ 수식자).
'X')를 쓰면 전각(「X」)보다 쌍당 2글자 절약다국어 스레드를 생성할 때 막아야 할 4가지:
증상: 중국어 문장에 "并不相同", "已经点击了", "一个空白屏幕"처럼 영어에서 직역된 게 뻔한 표현이 등장한다.
차단: 프롬프트에 "don't preserve EN sentence structure" / "use natural ZH phrasing"를 명시한다.
증상: Claude가 생성 후 "done"이라 말하지만 실제로는 한도 초과인데 본인은 모른다.
차단: 프롬프트에서 생성 후 스스로 세도록 지시("count each tweet's char length and flag any over the limit")하거나 로컬 스크립트로 게이트한다. 나는 후자 — Ruby가 더 정확하다.
증상: Claude가 셀 때 이모지와 전각 따옴표의 추가 weight를 무시한다.
차단: Claude에게 "한도 넘었어?"라고 묻지 말 것 — 로컬에서 .length를 계산하고 그 수치를 기준으로 Claude에게 줄이라고 시킨다.
증상: 어떤 때는 모든 트윗에 🧵, 어떤 때는 첫 트윗에만, 어떤 때는 4/4 끝에 붙는다.
차단: 프롬프트에 "🧵 only on tweet 1"로 고정. Claude는 스레드의 시각적 관례를 기본적으로 모른다.
Claude의 첫 드래프트를 한도 근처 다국어 스레드로 뽑는 6가지 규칙:
"cut detail if needed"로 길이 때문에 사실을 버려도 된다고 알린다..length 게이트. Claude 자체 카운트보다 정확하고, X 시험 게시보다 빠르다.진짜 통찰: Claude는 다국어 스레드를 맞게 쓸 수 있다. 그런데 기본 반응은 "번역"이다. 프롬프트로 "언어별 독립 재작성" 모드로 돌리는 건 당신 몫이다. .length 게이트를 더했더니, 오늘 마지막 기사의 중국어 스레드는 첫 드래프트에 140/140 딱 — 잘라낼 필요 없었다.