讓多語言開發(fā)變得簡單點(diǎn)

實(shí)現(xiàn)方式大概兩種:

1蒋困、key
使用方式:

在資源文件內(nèi)定義 key,如果原語言是中文挽唉,key 通常是一個(gè)帶含義的英文或者拼音程拭;變態(tài)一點(diǎn)的就是 xxxx1111定踱,xxxx1112(很榮幸,我們的項(xiàng)目很變態(tài) /(ㄒoㄒ)/~~)恃鞋,然后在代碼中通過 Resource.lang.xxxx1111 或者 lang.xxxx1111(js文件內(nèi)) 方式引用崖媚;

問題:
  1. key 名難定義,就算定義得好也不見得大家都看得懂恤浪;
  2. 修改不方便(打開代碼畅哑,看到的都是 lang.xxxx,我要修改的內(nèi)容在哪)水由。如果開發(fā)直接修改資源文件荠呐,那么每個(gè)語言的都要修改,可是日語只會(huì) "亞麻得";
  3. 如果項(xiàng)目是先按某個(gè)語言開發(fā)好功能泥张,后期補(bǔ)翻譯的呵恢,那就更悲催了,研發(fā)需要重新回來替換一次媚创;

2渗钉、gettext
先了解三種文件類型:
  • .po 文件

PO 是 Portable Object(可移植對(duì)象)的縮寫形式,它是面向翻譯人員的钞钙、提取于源代碼的一種資源文件晌姚;

  • .pot 文件

POT 是 Portable Object Template(可移植對(duì)象模板)的縮寫形式,是一種模板文件歇竟,其實(shí)質(zhì)與 .po 文件一樣,其中包含了從源代碼中提取所有的翻譯字符串的列表抵恋,主要提供給翻譯人員使用焕议,可以通過 .pot 文件生成 .po 文件;

  • .mo 文件

MO 是 Machine Object(機(jī)器對(duì)象)的縮寫形式弧关,它是面向計(jì)算機(jī)的盅安、由 .po 文件通過 GNU gettext 工具包編譯而成的二進(jìn)制文件,應(yīng)用程序通過讀取 .mo 文件使自身的界面轉(zhuǎn)換成用戶使用的語言世囊;


使用方式:

在代碼文件內(nèi)寫成:_("明道")别瞭,通過命令提取到 pot 文件中,通過 poedit 等工具根據(jù) pot 文件創(chuàng)建其他語言對(duì)于的 po 文件

#: src/test.cs:36
msgid "明道"
msgstr ""
問題:

gettext 的方式的主要問題是因?yàn)?key 的唯一性會(huì)導(dǎo)致多義詞株憾、單復(fù)數(shù)難處理蝙寨,但對(duì)于我們目前來說還是可以接受的,所以最終決定換成 gettext 方式


如果是基于 .NET Framework 的項(xiàng)目:

在需要支持翻譯的項(xiàng)目 NuGet 安裝 i18N:i18N詳細(xì)介紹

Install-Package i18N

在使用文案的地方都按照以下方式來寫:
1. [[[明道]]]   // 沒有參數(shù)

2. [[[我在 %0 上班 ||| 明道 ]]]  // 帶參數(shù)

3. string.Format("[[[welcome %1, today is %0|||{0}|||{1}]]]", day, name) //string.Format 方式   

web.config 配置:
<appSettings>
  <!-- 定義資源文件名稱(.po)-->
  <add key="i18n.LocaleFilename" value="mdTranslation" />
</appSettings>
<system.webServer>
  <modules>
    <add name="i18n.LocalizingModule" type="i18n.LocalizingModule, i18n" />
  </modules>
</system.webServer>
Application_Start 配置:
void Application_Start(object sender, EventArgs e)
{
  // 默認(rèn)語言(簡體中文)
  i18n.LocalizedApplication.Current.DefaultLanguage = "zh-Hans"; 
  // url里面是否帶語言參數(shù) http://www.xxx.com/en, Void 表示不帶語言參數(shù)(可按項(xiàng)目的實(shí)際要求嗤瞎,非Voide方式可能存在文件引用路徑問題)
  i18n.UrlLocalizer.UrlLocalizationScheme = i18n.UrlLocalizationScheme.Void; 
  // 哪些ContentType文件需求支持多語言解析
  i18n.LocalizedApplication.Current.ContentTypesToLocalize = new Regex(@"^(?:(?:(?:text|application)/(?:plain|html|xml|json|x-json))(?:\s*;.*)?)$");
  //如果開發(fā)的項(xiàng)目沒有考慮時(shí)區(qū)問題墙歪,需要設(shè)置成null,不然dateTime類型會(huì)按照時(shí)區(qū)重新計(jì)算
  i18n.LocalizedApplication.Current.SetPrincipalAppLanguageForRequestHandlers = null;
}
執(zhí)行命令生成 pot 和 po 文件:
"$(TargetDir)i18n.PostBuild.exe" "$(ProjectDir)\web.config"
得到 pot 和 po 文件之后贝奇,可以使用以下方式來完成多語言的翻譯:
1. poedit // 本地翻譯軟件虹菲,可以根據(jù) pot 模板創(chuàng)建各語言的 po 文件,也可以直接對(duì)現(xiàn)有的 po 文件進(jìn)行翻譯

2. transifex // 在線翻譯平臺(tái)掉瞳,可以導(dǎo)入 pot 模板毕源,自動(dòng)創(chuàng)建多個(gè)語言來在線翻譯。也可以將現(xiàn)有的 po 文件導(dǎo)入

3. crowdin // 在線翻譯平臺(tái)(類似transifex)
我們使用的 NuGet 安裝的 i18N 在多語言實(shí)現(xiàn)上并沒有用到 mo 文件陕习,所以可以不生成 mo 文件

</br>
對(duì)于所有訪問資源都在所部署的IIS服務(wù)器的情況霎褐,以上配置基本就可以了


但是對(duì)于引用 CDN 的文件來說,以上的方式就不合適了衡查,所以我們棄用 i18N 自帶的 pot 模板生成工具 i18n.PostBuild瘩欺,自己實(shí)現(xiàn)。

大概思路:

  1. 如果資源文件在所部署的 IIS 服務(wù)器上,依然使用以上的試試俱饿;

  2. 如果資源文件在 CDN 上(對(duì)于我們來說要翻譯部分基本是 js歌粥、tpl、css拍埠、image)失驶,所以只需要處理 js、tpl 里面的多語言即可枣购;

  3. 類似 [[[xxxx]]] 這樣的語法嬉探,我們定義一個(gè)js里面的語法,_l('xxxx')棉圈;

    _l("明道")
    
    _l("我在 %0 上班","明道")
    
    window._l = function () {
      var args = arguments;
      if (args) {
        var key = args[0];
        var content = key;
        if (typeof mdTranslation != 'undefined' && mdTranslation[key])
          content = mdTranslation[key];
        // 含0% 1% 的內(nèi)容替換
        if (args.length > 1) {
          for (var i = 1; i < args.length; i++) {
            content = content.replace(new RegExp('%' + (i - 1), 'g'), args[i]);
          }
        }
        return content;
      }
      return '';
    };
    
    
  4. 根據(jù) [[[xxxx]]] 和 _l('xxxx') 語法我們通過腳本來提取所有的 key涩堤,生成 pot 文件,大家可以注意文件內(nèi)有一行 #: Disabled references:1分瘾,這里其實(shí)是有講究的胎围,我的方式是出于自動(dòng)生成方便,大家有興趣可以深入了解一下 gettext;

    msgid ""
    msgstr ""
    "Project-Id-Version: \n"
    "POT-Creation-Date: 2017-05-17 15:12:04+08:00\n"
    "MIME-Version: 1.0\n"
    "Content-Type: text/plain; charset=utf-8\n"
    "Content-Transfer-Encoding: 8bit\n"
    "X-Generator: i18n.POTGenerator\n"
    
    #: Disabled references:1
    msgid "明道"
    msgstr ""
    
    #: Disabled references:1
    msgid "我在 %0 上班"
    msgstr ""
    
  5. 將 pot 模板導(dǎo)入到 transifex/crowdin 中德召,指定這個(gè)模板需要翻譯出哪些語言白魂,在線翻譯完成后下載 po 文件;

    crowdin.png
    po.png
  6. 根據(jù) po 文件生成js文件上岗,把 js 引入到項(xiàng)目下就可以通過 _l('xxxx') 的方式使用了福荸;

    local.png

    注意:如果使用第三方翻譯平臺(tái),基本上都是按詞數(shù)或者條數(shù)來收費(fèi)的肴掷。為了減少一些成本敬锐,對(duì)于已經(jīng)翻譯好的內(nèi)容,其實(shí)可以不用存儲(chǔ)在翻譯平臺(tái)捆等,翻譯好后下載 po 文件后就可以把翻譯平臺(tái)上的內(nèi)容清空滞造。之后再導(dǎo)入新的 pot 文件,所以對(duì) pot 的生成就要做一些處理栋烤,我們希望是增量式的谒养。

    1. 提取站點(diǎn)中所有有效的 key

    2. 清理 pot 和 po 文件中無效的 key

    3. 對(duì)比提取出來的 key 與現(xiàn)有翻譯文件(已經(jīng)清理過)中的 key

    4. 生成增量 key 的 pot 文件

    5. 導(dǎo)入只含增量 key 的 pot 文件,完成翻譯

    6. 從翻譯平臺(tái)下載 po 文件明郭,修改本地的 pot 和 po 文件(增量部分 copy 追加到文件中)

    7. 重新更新 po 文件生成 js 文件

    以上的實(shí)現(xiàn)我們是通過 gulp 來完成的买窟,具體實(shí)現(xiàn)方式可以根據(jù)情況而定。

參考鏈接:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末薯定,一起剝皮案震驚了整個(gè)濱河市始绍,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌话侄,老刑警劉巖亏推,帶你破解...
    沈念sama閱讀 212,185評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件学赛,死亡現(xiàn)場離奇詭異,居然都是意外死亡吞杭,警方通過查閱死者的電腦和手機(jī)盏浇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,445評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來芽狗,“玉大人绢掰,你說我怎么就攤上這事⊥妫” “怎么了滴劲?”我有些...
    開封第一講書人閱讀 157,684評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長顾复。 經(jīng)常有香客問我班挖,道長,這世上最難降的妖魔是什么芯砸? 我笑而不...
    開封第一講書人閱讀 56,564評(píng)論 1 284
  • 正文 為了忘掉前任聪姿,我火速辦了婚禮,結(jié)果婚禮上乙嘀,老公的妹妹穿的比我還像新娘。我一直安慰自己破喻,他們只是感情好虎谢,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,681評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著曹质,像睡著了一般婴噩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上羽德,一...
    開封第一講書人閱讀 49,874評(píng)論 1 290
  • 那天几莽,我揣著相機(jī)與錄音,去河邊找鬼宅静。 笑死章蚣,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的姨夹。 我是一名探鬼主播纤垂,決...
    沈念sama閱讀 39,025評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼磷账!你這毒婦竟也來了峭沦?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,761評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤逃糟,失蹤者是張志新(化名)和其女友劉穎吼鱼,沒想到半個(gè)月后蓬豁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,217評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡菇肃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,545評(píng)論 2 327
  • 正文 我和宋清朗相戀三年地粪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片巷送。...
    茶點(diǎn)故事閱讀 38,694評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡驶忌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出笑跛,到底是詐尸還是另有隱情付魔,我是刑警寧澤,帶...
    沈念sama閱讀 34,351評(píng)論 4 332
  • 正文 年R本政府宣布飞蹂,位于F島的核電站几苍,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏陈哑。R本人自食惡果不足惜妻坝,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,988評(píng)論 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望惊窖。 院中可真熱鬧刽宪,春花似錦、人聲如沸界酒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,778評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽毁欣。三九已至庇谆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間凭疮,已是汗流浹背饭耳。 一陣腳步聲響...
    開封第一講書人閱讀 32,007評(píng)論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留执解,地道東北人寞肖。 一個(gè)月前我還...
    沈念sama閱讀 46,427評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像衰腌,于是被迫代替她去往敵國和親逝淹。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,580評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容