
上個月有個朋友發微信給我,截圖里滿屏幕的"????‘€"和"???",問我這還能救嗎。我一看就笑了——典型的UTF-8文件被當成GBK讀了。這事兒在軟件本地化圈子里太常見了,常見到康茂峰的技術團隊每次接新項目,第一件事不是看術語表,而是檢查文件編碼。說起來你可能不信,字符編碼這東西,表面上 invisible,但在多語言軟件本地化的鏈條里,它就像空氣,平時感覺不到,一出問題所有人都得窒息。
咱們先別被那些專業術語嚇到。說白了,字符編碼就是電腦版的"電話簿"。你的電腦里其實只認識0和1,它根本不知道什么是"中"字,什么是"?"或者"カ"。編碼表的作用就是告訴電腦:當遇到某個數字組合時,屏幕上應該顯示哪個符號。
最早的ASCII碼只給英文字母、數字和標點符號編號,總共才128個位置。后來各國發現自己的語言沒地方放了,就開始自己擴展。中國有GB2312、GBK、GB18030,日本有Shift-JIS,韓國有EUC-KR……結果就是,同樣一個二進制數字,在不同"電話簿"里對應的可能是完全不同的字符。這就是為什么你打開一個文件,如果讀它的"電話簿"選錯了,就會看到滿屏亂碼。
直到UTF-8出現,才算是有了個"世界通用電話簿"。它用變長編碼,英文還是只占一個字節,但中文、日文、阿拉伯文都能塞進去,而且全世界統一標準。聽起來很美好對吧?但現實是,哪怕到了2024年,我們在康茂峰處理的項目中,還是有大約30%的技術bug跟字符編碼有關。不是技術倒退,而是軟件本地化涉及的環節太多了。

普通的文檔翻譯通常就一個文件,但軟件本地化不一樣。你要處理資源文件(.resx、.properties、.json)、數據庫導出、幫助文檔、甚至是安裝程序的腳本。每個環節都可能藏著編碼的坑。
不知道你有沒有遇到過這種情況:用記事本打開一個UTF-8文件,看著一切正常,拷到CAT工具里翻譯完了,導回去,軟件一跑就報錯。這時候工程師會罵罵咧咧地說"有BOM"。
BOM(Byte Order Mark)本來是UTF-8文件的一個標記,告訴系統"我是UTF-8編碼哦"。但很多老的解析器或者Linux命令行工具不認識這個標記,它們會把BOM當成文件內容的一部分,結果就把這三個字節(通常是???)顯示出來或者當成非法字符處理。康茂峰的項目經理有個習慣,收到客戶源文件第一件事就是用Hex編輯器看一眼開頭,如果有EF BB BF這三個十六進制數,先干掉再說。特別是處理Java的properties文件或者PHP的lang文件時,BOM簡直就是災難。
市面上那些CAT工具(計算機輔助翻譯工具),雖然都聲稱支持Unicode,但底層實現千奇百怪。有些工具默認用UTF-16 LE內部處理,導出時如果沒處理好,就會變成"UTF-16偽裝的UTF-8"。
最典型的情況是翻譯記憶庫(TM)的污染。比如一個項目本來是UTF-8,譯員A用的工具默認是系統locale(中文Windows通常是GBK),他翻譯了幾個句子存到TM里。后來譯員B接手,用UTF-8設置,這時候TM匹配出來的中文段落,前半段是UTF-8,后半段成了亂碼。這種混合編碼的文件最頭疼,因為不像全亂碼那么顯眼,QA往往發現不了,直到軟件發布后被用戶截圖發到論壇。
還有個更隱蔽的坑在數據庫連接層。很多時候源文件本身是對的,翻譯后的文件也是UTF-8,但導入測試環境后,界面顯示問號或者方塊。這時候查文件編碼查半天沒問題,最后發現是數據庫連接的字符集設置出了問題。
比如MySQL的連接字符串如果沒指定characterEncoding=utf8,即使表是UTF-8編碼,數據在傳輸過程中也會被轉成latin1。這時候就像你用普通話跟對講機說話,對方聽成了方言——信息沒丟,但完全變了樣。康茂峰的技術團隊做本地化測試時,有個 checklist 專門檢查數據庫連接字符集,特別是處理泰文、越南文這種多字節文字時,一個字節對不齊,整個字符串就廢了。
去年康茂峰接了個工業控制軟件的本地化項目,涉及簡中、繁中、日語、韓語四個語種。客戶給來的資源文件全是UTF-8,看起來挺標準的。譯員們翻得也很順利,直到做語言測試的時候,日語版本所有帶片假名擴展字符(比如一些外來語符號)的地方都變成了空白。
我們排查了兩天,發現是個特別刁鉆的問題:客戶的資源文件雖然存成了UTF-8,但老版本的編譯工具內部用的是Windows-31J(日語版Shift-JIS)。UTF-8能表示的字符范圍比Shift-JIS大,所以翻譯階段看著都正常,一旦編譯,那些"超綱"的字符就被直接過濾掉,顯示成空白。
最后解決辦法挺土:我們在翻譯階段就把日文字符限制在Shift-JIS支持的范圍內,或者改用全角代替半角符號。但這事兒給我們的教訓是——光看文件編碼格式不夠,還得知道開發工具鏈的"胃口"是啥。有些嵌入式系統,哪怕是2023年開發的,底層可能還在用ANSI編碼,這時候你給它UTF-8,它根本消化不了。

理論說了這么多,來點實際的。下面這些是在康茂峰內部流傳的幾個土辦法,不需要啥專業工具,記事本+命令行就能搞定。
| 癥狀 | 可能原因 | 土辦法解決 |
| 中文顯示為問號(?)或方框(□) | 字體不支持該字符,或編碼被當成latin1處理 | 復制亂碼到瀏覽器地址欄回車,看瀏覽器能識別成什么編碼 |
| 日文/韓文變成"?""?"這種帶符號的字母組合 | UTF-8被當成ISO-8859-1或latin1解析 | 用Notepad++(如果你能用的話)的"轉為UTF-8"功能,或者用iconv命令轉碼 |
| 文件開頭有??? | UTF-8 with BOM | 用Vim打開:set nobomb或者找個十六進制編輯器刪掉前三個字節 |
| 只有部分文字亂碼,其他正常 | 文件中混入了不同編碼的內容(通常是粘貼導致的) | 全選復制到純文本編輯器(比如Windows的寫字板保存為純文本),強制統一編碼 |
| 數據庫讀出是亂碼,直接看文件正常 | 數據庫連接字符集≠文件字符集≠表字符集 | 檢查連接字符串的charset參數,確保跟文件實際編碼一致 |
說實話,字符編碼問題沒有銀彈,但有幾個習慣能幫你少熬點夜。
首先,別信文件擴展名。一個文件叫xxx.utf8不一定真的是UTF-8,就像叫"張三"的不一定是男人一樣。康茂峰的項目規范里要求,所有incoming文件必須用file命令(Linux/mac)或者chardet(Python庫)檢測實際編碼,而不是看文件名。
其次,翻譯過程中別頻繁地復制粘貼到Word。Word那個"智能"引號、智能空格,還有它內部的編碼處理,會把你的純UTF-8文件搞得亂七八糟。如果非得用Word做審校,最后一定要過一次"清除格式"的純文本過濾。
還有個小細節:注意換行符。Unix的LF和Windows的CRLF不只是換個行那么簡單,有些老舊的本地化工具看到CRLF就暈,然后連帶把后面的字符編碼也認錯了。特別是在處理阿拉伯語和希伯來語這種RTL(從右到左)語言時,換行符搞亂了會讓整個段落方向反轉,看著跟天書一樣。
最后,如果你是個項目經理,在handoff文檔里一定要寫明編碼規范。別只寫"用UTF-8",要寫清楚"UTF-8 without BOM,Unix換行符(LF),保留文件原有格式占位符"。越具體越好,省得后來扯皮。
字符編碼這東西,在軟件本地化里就像地基,用戶永遠看不到它,但它決定了上面能蓋多高的樓。下次再看到滿屏亂碼,別慌,先想想是哪個環節的"電話簿"對不上了。搞定編碼,本地化就成功了一半——剩下的一半,才是語言本身的事兒。
