Một bài 19 ngôn ngữ: cấu trúc file, prompt dịch, 5 cái bẫy thực tế, cách POST một lần.
Tài liệu chính thức của Anthropic và OpenAI chỉ có tiếng Anh. Đó là khoảng trống lớn trong hệ sinh thái nội dung cho developer AI toàn cầu. how2claude đang lấp khoảng trống đó — mỗi bài ra mắt bằng 19 ngôn ngữ cùng lúc: zh / en / zh-TW / ja / ko / es / pt-BR / id / vi / tr / ar / fr / de / it / ru / uk / pl / he / th.
Thuê người thì không thực tế (20 bản dịch mỗi bài, mỗi bản vài nghìn đô). Để Claude làm đưa chi phí biên về gần zero — nhưng ném một câu "dịch sang tiếng Nhật" qua hàng rào sẽ nhận lại bản dịch đậm mùi máy móc và tiếng nói tác giả bay sạch. Dưới đây là quy trình đầy đủ để làm đúng: cấu trúc file, cách viết prompt dịch, nơi Claude chắc chắn sẽ vấp, cách POST 19 ngôn ngữ cùng các tweet theo ngôn ngữ tới API trong một lần gọi.
Hai thứ khác nhau rất nhiều.
Dịch đưa ý nghĩa từ ngôn ngữ A sang B — việc Google Translate làm. Đọc "đúng" nhưng "phẳng".
Bản địa hóa giữ nguyên phong cách, nhịp điệu, độ chuyên nghiệp của tác giả, viết lại bằng "giọng blog kỹ thuật" của ngôn ngữ đích. Kết quả đọc như được viết bởi người bản địa.
Dịch là công việc 5 phút với Claude; bản địa hóa đòi hỏi prompt phải chỉ rõ:
Lệnh /write-article của how2claude nhúng sẵn yêu cầu phong cách cho từng ngôn ngữ:
| File ngôn ngữ | Yêu cầu phong cách |
|---|---|
ja.md |
Giọng blog kỹ thuật, tiếng Nhật tự nhiên |
ko.md |
Giọng blog kỹ thuật, tiếng Hàn tự nhiên |
zh-TW.md |
Dùng từ Đài Loan, phồn thể |
ar.md |
Tiếng Ả-rập chuẩn hiện đại (viết) |
id.md |
Tiếng Indonesia chuẩn |
Nhìn như thêm một dòng. Nhưng với Claude đó là quyết định — không có dòng này, mặc định sinh ra "bản dịch sách giáo khoa".
Một thư mục cho mỗi bản nháp, 20 file:
docs/drafts/let-claude-translate-articles/
├── meta.json # title + summary cho tất cả 19 ngôn ngữ
├── zh.md # tiếng Trung (nguồn, viết trước)
├── en.md # tiếng Anh (lô dịch đầu tiên)
├── zh-TW.md
├── ja.md
├── ko.md
├── ...(14 ngôn ngữ khác)
└── th.md
meta.json:
{
"category_slug": "use-cases",
"series_slug": "writing",
"free": true,
"title": {
"zh": "让 Claude 把一篇文章翻译成 19 种语言",
"en": "Letting Claude Translate One Article Into 19 Languages",
"vi": "Để Claude dịch một bài viết sang 19 ngôn ngữ",
"...": "..."
},
"summary": {
"vi": "Một bài 19 ngôn ngữ: cấu trúc file, prompt dịch, 5 cái bẫy thực tế, cách POST một lần.",
"...": "..."
}
}
Dòng đầu mỗi file .md là # tiêu đề, phần còn lại là thân bài. Title không lấy từ dòng đầu md — lấy từ meta.json, nhờ vậy tiêu đề từng ngôn ngữ là câu ngắn được chuốt riêng, không phải câu mở đầu bài có thể đã bị kéo dài khi dịch.
Hai quy trình sai:
Sai: dịch chuỗi. zh → en → ja → ko → ...
Vấn đề: ja dựa trên en, ko dựa trên ja — mỗi lần nhảy rò rỉ chút ý. Tới th (tiếng Thái) đã là thông tin qua bốn tay.
Đúng: dịch tỏa. Chốt zh → sinh en / ja / ko / ar / id / ... thẳng từ nguồn.
Mọi ngôn ngữ sinh trực tiếp từ bản gốc, không trạm trung chuyển.
Cấu trúc prompt (đóng gói trong /write-article):
Đây là bài blog kỹ thuật về X, nguồn tiếng Trung:
[toàn bộ zh.md]
Dịch sang các ngôn ngữ sau, với yêu cầu riêng từng ngôn ngữ:
- ja.md: giọng blog kỹ thuật, tiếng Nhật tự nhiên
- ko.md: giọng blog kỹ thuật, tiếng Hàn tự nhiên
- ar.md: tiếng Ả-rập chuẩn hiện đại (viết)
...
Quy tắc:
1. Giữ giọng trực tiếp, chuyên nghiệp, hơi tự giễu của tác giả
2. Không dịch code block, câu lệnh, tên API, URL
3. Tiêu đề, tiểu mục, mạch đoạn được phép tái cấu trúc
4. Xuất title riêng cho từng ngôn ngữ — ngắn, có hook, không dịch sát tiêu đề gốc
Dịch 18 ngôn ngữ song song, một phiên Claude là xong. Một chi tiết then chốt: làm trong cùng một phiên / cùng phiên bản model — giọng điệu trôi dạt qua các phiên và qua các thế hệ model.
X đếm ký tự CJK (Trung/Nhật/Hàn) khắt khe hơn. Tôi yêu cầu Claude sinh tweet với ràng buộc này:
Lần chạy đầu tiên, ba tweet tiếng Trung vượt (160, 164, 152). Claude đã dịch sát tweet tiếng Anh — tweet Anh 260 ký tự dịch sang Trung đúng chạm giới hạn.
Quy tắc: tweet tiếng Trung phải viết lại, không phải dịch. Yêu cầu: trần 140 ký tự, bắt buộc có hook, mất chi tiết chút được.
zh → zh-TW rất dễ lười: quăng qua công cụ giản thể → phồn thể. Ký tự khớp, từ vựng không:
| zh | zh-TW (sai) | zh-TW (đúng) |
|---|---|---|
| 文件 | 文件 | 檔案 |
| 信息 | 信息 | 資訊 |
| 软件 | 軟件 | 軟體 |
| 视频 | 視頻 | 影片 |
Khi yêu cầu zh-TW từ Claude, nói đủ hai vế: "dùng từ Đài Loan, phồn thể". Chỉ nói "phồn thể" sẽ nhận chuyển đổi ký tự.
Tiếng Ả-rập và Hebrew đọc từ phải sang trái. Phía Rails cần <html dir="rtl"> và các biến thể rtl: của Tailwind. Nhưng bản thân phần dịch cũng có bẫy:
unicode-bidi: isolate, nếu không code sẽ bị "hút" vào dòng chảy RTL، thay ,, ؟ thay ?. Claude mặc định dùng dấu tiếng Anh; phải chỉ rõ2026) trong đoạn văn phải-sang-trái. Trình duyệt xử lý, nhưng Claude thường lẫn lộn khi viết text thôCác cụm khẩu ngữ bản gốc ("một phát xong", "đạp hầm", "lật kèo") Claude dịch sang Nhật/Hàn mặc định thành dạng viết trang trọng (「一気に実装」「落とし穴」「失敗」) — nghĩa khớp, giọng bay hơi.
Sửa: nói rõ trong prompt — "giữ giọng blog kỹ thuật trực tiếp, hơi tự giễu, không trang trọng; không hàn lâm hóa". Dù vậy, một số ngôn ngữ (Đức, Nga) vẫn hạ cánh "trang trọng" hơn bản gốc một chút — bản thân ngôn ngữ đó có thiên lệch về đăng ký viết.
Chuỗi trong code thuộc hai rổ — chữ UI (dịch) và placeholder/tên biến (không):
t("pricing.page_title") # không dịch (i18n key)
"user_id" # không dịch (tên biến)
"Monthly subscription" # hiển thị làm ví dụ trong bài → không dịch
Với bất cứ thứ gì kề code, "không dịch" là mặc định an toàn hơn. Dịch file locale i18n (config/locales/xx.yml) là việc riêng.
/publish-article POST bản nháp lên how2claude.com/api/articles:
{
"category_slug": "use-cases",
"series_slug": "writing",
"free": true,
"thread": true,
"title": { "zh": "...", "en": "...", "ja": "...", ... },
"summary": { "zh": "...", "en": "...", ... },
"content": { "zh": "<md>", "en": "<md>", ... },
"tweets": { "en": ["...", "..."], "zh": [...], ... }
}
Một request khoảng 300KB (19 ngôn ngữ × ~15KB). Server tách về các bảng DB:
articles, title / summary / content là jsonb key theo localex_queue_tweets, theo locale + account, đẩy vào queue lịch đăngTweet chỉ gửi cho locale có tài khoản X đã kết nối (hiện tại en/zh/ja/ko/ar/id — 6). Ngôn ngữ chưa kết nối gửi []. Kiểm tra tài khoản:
Account.all.each { |a| puts "#{a.locale}: #{a.name}" }
# en: @how2claude
# zh: @howtoclaude
# ja: @how2claude_ja
# ko: @how2claude_ko
# ar: @how2claude_ar
# id: @how2claude_id
Để Claude dịch một bài viết sang 19 ngôn ngữ — checklist đầy đủ:
dir="rtl" + biến thể rtl: của Tailwind phía Rails. Dấu câu pha trộn và cô lập code block xử lý riêng.Nút thắt thực sự không phải chất lượng dịch — model cỡ Claude 4 dịch sang Nhật/Hàn/Ả-rập/Nga gần bằng bản địa. Nút thắt là bạn có sẵn sàng đặt một bài viết trước mặt độc giả 19 ngôn ngữ hay không. Kỹ thuật mất 5 phút. Về nội dung, chỉ cần ý chí phục vụ 200 lần lượng độc giả cùng lúc.