
前幾天有個(gè)朋友問(wèn)我,他在做軟件本地化項(xiàng)目時(shí)遇到了一批特別棘手的文本,里面到處都是"%d個(gè)文件"、"%s已成功保存"這類奇怪的東西。他問(wèn)我這些到底該怎么翻,翻譯完了為什么程序里顯示的位置總是對(duì)不上。這讓我意識(shí)到,動(dòng)態(tài)字符串這個(gè)問(wèn)題,可能很多剛接觸本地化的人都會(huì)遇到。它不像普通句子那樣規(guī)整,里面藏著各種"機(jī)關(guān)",處理不好的話,翻譯出來(lái)的內(nèi)容要么顯示錯(cuò)亂,要么語(yǔ)法錯(cuò)誤,讀起來(lái)別扭極了。
那動(dòng)態(tài)字符串到底是怎么回事?專業(yè)點(diǎn)說(shuō),它是指那些包含變量占位符、格式說(shuō)明符或邏輯控制結(jié)構(gòu)的文本。在軟件界面中,開發(fā)者為了讓程序能靈活顯示不同內(nèi)容,會(huì)在字符串里預(yù)留一些"坑",等實(shí)際運(yùn)行時(shí)再填入具體數(shù)據(jù)。這些"坑"就是動(dòng)態(tài)字符串的標(biāo)志,也是本地化翻譯需要特別注意的地方。
舉個(gè)最常見的例子你就明白了。假設(shè)軟件里有個(gè)提示信息:"已成功刪除%d個(gè)文件"。這里的%d就是一個(gè)占位符,程序運(yùn)行時(shí)會(huì)把它替換成實(shí)際數(shù)字,可能是1,也可能是100。翻譯成英文可能就是"Successfully deleted %d files",但如果翻譯成德語(yǔ),情況就復(fù)雜了——德語(yǔ)的"文件"有陰性、陽(yáng)性、中性之分,而且"個(gè)"這個(gè)量詞在德語(yǔ)里根本不存在相應(yīng)的語(yǔ)法結(jié)構(gòu)。
再比如某些軟件里的復(fù)數(shù)處理。英語(yǔ)的復(fù)數(shù)形式比較簡(jiǎn)單,大多數(shù)詞加個(gè)"s"或者"es"就行了。但俄語(yǔ)的名詞復(fù)數(shù)形式可以根據(jù)數(shù)字不同變化三次:1對(duì)應(yīng)單數(shù),2、3、4對(duì)應(yīng)另一種形式,5以上又是一種形式。如果一個(gè)俄語(yǔ)軟件界面要顯示"您有%d條未讀消息",翻譯時(shí)就得為不同的數(shù)字準(zhǔn)備三種不同的表達(dá)方式。
還有一些更隱蔽的動(dòng)態(tài)字符串。比如某些語(yǔ)言存在性別語(yǔ)法,比如阿拉伯語(yǔ)、西班牙語(yǔ)、俄語(yǔ),動(dòng)詞或形容詞的形式要根據(jù)主語(yǔ)的性別變化。如果動(dòng)態(tài)字符串的主語(yǔ)是用戶輸入的名字,翻譯系統(tǒng)就得知道這個(gè)名字是男是女,才能給出正確的語(yǔ)法形式。這種情況下,翻譯已經(jīng)不是簡(jiǎn)單的文字替換,而是需要根據(jù)運(yùn)行時(shí)數(shù)據(jù)做出判斷。
根據(jù)我這些年接觸的本地化項(xiàng)目,動(dòng)態(tài)字符串大概可以分成這么幾類。每一類的處理方式都不太一樣,需要區(qū)別對(duì)待。

這是最常見的一種。開發(fā)者會(huì)在字符串里用特定的標(biāo)記預(yù)留位置,常見的有%d、%s、%f、%1$s這類格式。翻譯的時(shí)候,這些標(biāo)記的位置絕對(duì)不能動(dòng),但標(biāo)記周圍的文字是可以調(diào)整的。聽起來(lái)簡(jiǎn)單,但實(shí)際操作中很容易出問(wèn)題。比如中文"共%d個(gè)項(xiàng)目"翻譯成英文應(yīng)該是"%d projects in total",這里需要調(diào)整語(yǔ)序,把表示總數(shù)的部分移到后面。如果直接把"共"翻譯成"total"放在前面,就會(huì)變成"Total %d projects",雖然意思對(duì)了,但讀起來(lái)不如地道的說(shuō)法自然。
復(fù)數(shù)形式的處理是本地化的重災(zāi)區(qū)。英語(yǔ)只有單數(shù)和復(fù)數(shù)兩種形式,所以寫代碼的人有時(shí)候會(huì)偷懶,用類似"1 item(s)"這樣的方式來(lái)處理。但這種做法在很多語(yǔ)言里是行不通的。波蘭語(yǔ)的復(fù)數(shù)規(guī)則非常變態(tài),數(shù)字1對(duì)應(yīng)一種形式,2、3、4對(duì)應(yīng)第二種,5到21又對(duì)應(yīng)第一種,22到24又是第二種,以此類推。烏克蘭語(yǔ)的情況也差不多。如果軟件要面向這些市場(chǎng)本地化,翻譯團(tuán)隊(duì)必須為每種可能的情況準(zhǔn)備對(duì)應(yīng)的譯文字符串。
說(shuō)到性別語(yǔ)法,阿拉伯語(yǔ)和希伯來(lái)語(yǔ)是最讓人頭大的。這兩種語(yǔ)言的動(dòng)詞變位、形容詞變化都要與主語(yǔ)的語(yǔ)法性別保持一致。如果動(dòng)態(tài)字符串里的主語(yǔ)是變量——比如用戶輸入的人名——翻譯系統(tǒng)就必須能判斷這個(gè)名稱的性別,才能輸出正確的句子形式。法語(yǔ)也有類似的問(wèn)題,只不過(guò)影響范圍稍微小一點(diǎn)。這種情況下,翻譯工作單靠譯員手動(dòng)完成是不夠的,需要開發(fā)團(tuán)隊(duì)在程序里提供額外的性別標(biāo)記參數(shù)。
有些字符串本身不長(zhǎng),但放在不同的地方意思完全不一樣。比如"Apply"這個(gè)詞,在軟件設(shè)置界面可能翻譯成"應(yīng)用",在表單里可能翻譯成"提交",在圖片處理軟件里可能翻譯成"套用"。如果只看原文"Apply",譯者根本不知道該怎么翻。這類字符串在本地化行業(yè)里有個(gè)專門的叫法——"atom"或者"singleton string"。處理它們最好的辦法是提供截圖或者詳細(xì)的上下文說(shuō)明,讓譯者明白這個(gè)詞具體用在什么地方。

說(shuō)了這么多理論,該講點(diǎn)實(shí)際的了。作為康茂峰這樣的專業(yè)本地化服務(wù)商,在處理動(dòng)態(tài)字符串的時(shí)候都會(huì)遵循一些行之有效的方法論。這些方法不是憑空想出來(lái)的,而是一個(gè)個(gè)項(xiàng)目做下來(lái)慢慢積累的經(jīng)驗(yàn)。
翻譯動(dòng)態(tài)字符串的時(shí)候,占位符的位置是最敏感的部分。原則上,譯文中占位符的相對(duì)順序要和原文保持一致。但這只是理想情況,很多語(yǔ)言之間語(yǔ)序差異很大,這時(shí)候該怎么辦?
以中文和英語(yǔ)為例。中文說(shuō)"正在加載 %d 個(gè)文件",英語(yǔ)說(shuō)"Loading %d files"。兩個(gè)語(yǔ)言的語(yǔ)序差不多,直接翻譯就行。但如果換成"您收藏的%d個(gè)文件",翻譯成英語(yǔ)可能需要說(shuō)"%d files in your collection",語(yǔ)序就變了。遇到這種情況,國(guó)際化工程師應(yīng)該在代碼里使用帶編號(hào)的占位符,比如%1$d、%2$s,這樣即使語(yǔ)序需要調(diào)整,占位符也能對(duì)應(yīng)上正確的變量。翻譯的時(shí)候只需要調(diào)整占位符的順序就可以了。
處理復(fù)數(shù)形式最系統(tǒng)的做法是CLDR(Unicode公共本地化數(shù)據(jù)倉(cāng)庫(kù))提供的復(fù)數(shù)規(guī)則。CLDR為世界上幾乎所有主要語(yǔ)言都定義了復(fù)數(shù)分類,比如英語(yǔ)有one和other兩種,俄語(yǔ)有one、few、many三種。每種語(yǔ)言對(duì)應(yīng)哪些分類、每個(gè)分類適用什么數(shù)字范圍,CLDR都整理得清清楚楚。
本地化項(xiàng)目開始之前,開發(fā)團(tuán)隊(duì)需要先確定目標(biāo)語(yǔ)言屬于哪種復(fù)數(shù)類型,然后在代碼里為每種復(fù)數(shù)形式準(zhǔn)備獨(dú)立的字符串標(biāo)識(shí)。翻譯團(tuán)隊(duì)則需要為同一個(gè)中文句子提供多份譯文,分別對(duì)應(yīng)不同的復(fù)數(shù)情況。這樣程序運(yùn)行時(shí),根據(jù)實(shí)際數(shù)字選擇對(duì)應(yīng)的譯文就行了。雖然前期準(zhǔn)備工作量不小,但至少能保證出來(lái)的結(jié)果是正確的。
如果目標(biāo)語(yǔ)言存在語(yǔ)法性別問(wèn)題,程序必須能夠識(shí)別并傳遞相關(guān)性別信息。常見的做法是在用戶注冊(cè)階段就讓用戶選擇性別,或者根據(jù)用戶名的特征自動(dòng)推斷。獲得了性別信息之后,把它作為參數(shù)傳遞給翻譯模塊,模塊再根據(jù)性別選擇正確的譯文形式。
舉個(gè)具體的例子。假設(shè)某條消息是"用戶%s已更新了個(gè)人資料",需要翻譯成阿拉伯語(yǔ)。阿拉伯語(yǔ)的"更新了"有男性和女性兩種形式。如果參數(shù)里帶了性別標(biāo)記,男性用戶收到"???????? ???? ??? ?????? ???? ??????",女性用戶收到"??????? ???? ???? ?????? ????? ??????"。沒(méi)有這個(gè)標(biāo)記,翻譯系統(tǒng)就只能瞎蒙,出來(lái)的句子肯定語(yǔ)法錯(cuò)誤。
本地化翻譯不只是譯員的事,開發(fā)團(tuán)隊(duì)在技術(shù)層面的支持同樣重要。很多問(wèn)題如果前期設(shè)計(jì)得當(dāng),后續(xù)能省去大量麻煩。
主流的軟件開發(fā)框架都提供了專門管理本地化資源文件的方式。Android用strings.xml,iOS用Localizable.strings,Java用properties文件,.NET用resx文件。這些文件格式的共同特點(diǎn)是鍵值對(duì)結(jié)構(gòu)——一個(gè)標(biāo)識(shí)符對(duì)應(yīng)一份譯文。動(dòng)態(tài)字符串的占位符直接寫在值里面,翻譯時(shí)只需要處理值的內(nèi)容就行。
對(duì)于復(fù)數(shù)形式,不同框架的處理方式略有差異。以Android為例,它在strings.xml里支持復(fù)數(shù)標(biāo)簽,用
翻譯記憶庫(kù)(TM)是提升本地化效率的重要工具,但處理動(dòng)態(tài)字符串時(shí)需要特別小心。普通的句子可以整機(jī)匹配,但動(dòng)態(tài)字符串因?yàn)槔锩嬗凶兞浚耆恢碌钠ヅ浜苌僖姟_@時(shí)候需要用模糊匹配功能,找出相似的字符串供譯員參考。
更高級(jí)的做法是對(duì)動(dòng)態(tài)字符串進(jìn)行預(yù)處理——把占位符挖掉,只用周圍的核心詞匯做匹配。這樣匹配成功率會(huì)高很多。匹配結(jié)果出來(lái)之后,譯員再把占位符填回去。康茂峰在處理本地化項(xiàng)目時(shí)都會(huì)做這樣的預(yù)處理,一方面提高匹配效率,另一方面也能避免把占位符的位置搞錯(cuò)。
動(dòng)態(tài)字符串的測(cè)試和普通文本測(cè)試不一樣。普通文本只需看有沒(méi)有翻譯、讀起來(lái)順不順就行,動(dòng)態(tài)字符串必須驗(yàn)證在不同參數(shù)值下顯示是否正確。比如測(cè)試一條涉及數(shù)字的提示信息,1、2、5、21、101、111這些關(guān)鍵節(jié)點(diǎn)都要測(cè)到,因?yàn)椴煌Z(yǔ)言的復(fù)數(shù)規(guī)則在不同數(shù)字范圍內(nèi)表現(xiàn)不同。
性別語(yǔ)法的測(cè)試稍微麻煩點(diǎn),需要準(zhǔn)備不同性別的測(cè)試賬號(hào)或者測(cè)試數(shù)據(jù)。如果條件允許,最好請(qǐng)目標(biāo)語(yǔ)言的母語(yǔ)者做一輪驗(yàn)收,他們能發(fā)現(xiàn)母語(yǔ)者才能察覺的細(xì)微語(yǔ)法問(wèn)題。
在本地化行業(yè)摸爬滾打這些年,我見過(guò)不少因?yàn)閯?dòng)態(tài)字符串處理不當(dāng)導(dǎo)致的翻車現(xiàn)場(chǎng)。總結(jié)幾條避坑建議,希望能幫到大家。
第一個(gè)坑是占位符被翻譯。某些不太專業(yè)的翻譯會(huì)把%d、%s這些占位符當(dāng)成普通文字翻譯掉,比如把"%d個(gè)文件"翻譯成"%d個(gè)files"。結(jié)果程序運(yùn)行時(shí),屏幕上就顯示"5個(gè)files"這種鬼東西。解決這個(gè)問(wèn)題需要在翻譯指南里明確強(qiáng)調(diào)占位符是代碼標(biāo)記,絕對(duì)不能動(dòng),并且在上線前做嚴(yán)格的回歸測(cè)試。
第二個(gè)坑是復(fù)數(shù)形式不全。很多項(xiàng)目為了趕進(jìn)度,只做單數(shù)和復(fù)數(shù)兩種形式就上線了。結(jié)果某些數(shù)字對(duì)應(yīng)的句子讀起來(lái)語(yǔ)法錯(cuò)誤,特別是俄語(yǔ)、波蘭語(yǔ)這些復(fù)數(shù)規(guī)則復(fù)雜的語(yǔ)言。出來(lái)混總是要還的,后面還是要補(bǔ)做,所以還不如一開始就做完整。
第三個(gè)坑是上下文缺失。譯員拿到一條動(dòng)態(tài)字符串,根本不知道用在什么地方,只能憑感覺猜。猜對(duì)了萬(wàn)事大吉,猜錯(cuò)了就等著上線后被用戶吐槽吧。負(fù)責(zé)任的項(xiàng)目經(jīng)理應(yīng)該為每條關(guān)鍵字符串準(zhǔn)備截圖或者視頻演示,讓譯者看到實(shí)際使用場(chǎng)景。如果預(yù)算允許,譯前和譯者開個(gè)簡(jiǎn)短的溝通會(huì)也很有幫助。
動(dòng)態(tài)字符串的本地化處理,說(shuō)到底就是要在"變"與"不變"之間找到平衡。變的是運(yùn)行時(shí)填入的具體數(shù)據(jù),不變的是語(yǔ)言規(guī)則和語(yǔ)法結(jié)構(gòu)。本地化工作者的任務(wù),就是為每種可能的"變"準(zhǔn)備好對(duì)應(yīng)的正確譯文,同時(shí)確保無(wú)論數(shù)據(jù)怎么變,出來(lái)的句子都符合目標(biāo)語(yǔ)言的語(yǔ)法規(guī)范。
這事兒聽起來(lái)復(fù)雜,做起來(lái)也確實(shí)需要經(jīng)驗(yàn)。但只要方法對(duì)了、流程規(guī)范了,其實(shí)也沒(méi)那么可怕。關(guān)鍵是前期要把功課做足,別等到上線了才發(fā)現(xiàn)問(wèn)題。到那時(shí)候再改,成本可就高多了。
