让多语言开发变得简单点

实现方式大概两种:

1、key
使用方式:

在资源文件内定义 key,如果原语言是中文,key 通常是一个带含义的英文或者拼音;变态一点的就是 xxxx1111,xxxx1112(很荣幸,我们的项目很变态 /(ㄒoㄒ)/~~),然后在代码中通过 Resource.lang.xxxx1111 或者 lang.xxxx1111(js文件内) 方式引用;

问题:
  1. key 名难定义,就算定义得好也不见得大家都看得懂;
  2. 修改不方便(打开代码,看到的都是 lang.xxxx,我要修改的内容在哪)。如果开发直接修改资源文件,那么每个语言的都要修改,可是日语只会 "亚麻得";
  3. 如果项目是先按某个语言开发好功能,后期补翻译的,那就更悲催了,研发需要重新回来替换一次;

2、gettext
先了解三种文件类型:
  • .po 文件

PO 是 Portable Object(可移植对象)的缩写形式,它是面向翻译人员的、提取于源代码的一种资源文件;

  • .pot 文件

POT 是 Portable Object Template(可移植对象模板)的缩写形式,是一种模板文件,其实质与 .po 文件一样,其中包含了从源代码中提取所有的翻译字符串的列表,主要提供给翻译人员使用,可以通过 .pot 文件生成 .po 文件;

  • .mo 文件

MO 是 Machine Object(机器对象)的缩写形式,它是面向计算机的、由 .po 文件通过 GNU gettext 工具包编译而成的二进制文件,应用程序通过读取 .mo 文件使自身的界面转换成用户使用的语言;


使用方式:

在代码文件内写成:_("明道"),通过命令提取到 pot 文件中,通过 poedit 等工具根据 pot 文件创建其他语言对于的 po 文件

#: src/test.cs:36
msgid "明道"
msgstr ""
问题:

gettext 的方式的主要问题是因为 key 的唯一性会导致多义词、单复数难处理,但对于我们目前来说还是可以接受的,所以最终决定换成 gettext 方式


如果是基于 .NET Framework 的项目:

在需要支持翻译的项目 NuGet 安装 i18N:i18N详细介绍

Install-Package i18N

在使用文案的地方都按照以下方式来写:
1. [[[明道]]]   // 没有参数

2. [[[我在 %0 上班 ||| 明道 ]]]  // 带参数

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)
{
  // 默认语言(简体中文)
  i18n.LocalizedApplication.Current.DefaultLanguage = "zh-Hans"; 
  // url里面是否带语言参数 http://www.xxx.com/en, Void 表示不带语言参数(可按项目的实际要求,非Voide方式可能存在文件引用路径问题)
  i18n.UrlLocalizer.UrlLocalizationScheme = i18n.UrlLocalizationScheme.Void; 
  // 哪些ContentType文件需求支持多语言解析
  i18n.LocalizedApplication.Current.ContentTypesToLocalize = new Regex(@"^(?:(?:(?:text|application)/(?:plain|html|xml|json|x-json))(?:\s*;.*)?)$");
  //如果开发的项目没有考虑时区问题,需要设置成null,不然dateTime类型会按照时区重新计算
  i18n.LocalizedApplication.Current.SetPrincipalAppLanguageForRequestHandlers = null;
}
执行命令生成 pot 和 po 文件:
"$(TargetDir)i18n.PostBuild.exe" "$(ProjectDir)\web.config"
得到 pot 和 po 文件之后,可以使用以下方式来完成多语言的翻译:
1. poedit // 本地翻译软件,可以根据 pot 模板创建各语言的 po 文件,也可以直接对现有的 po 文件进行翻译

2. transifex // 在线翻译平台,可以导入 pot 模板,自动创建多个语言来在线翻译。也可以将现有的 po 文件导入

3. crowdin // 在线翻译平台(类似transifex)
我们使用的 NuGet 安装的 i18N 在多语言实现上并没有用到 mo 文件,所以可以不生成 mo 文件

</br>
对于所有访问资源都在所部署的IIS服务器的情况,以上配置基本就可以了


但是对于引用 CDN 的文件来说,以上的方式就不合适了,所以我们弃用 i18N 自带的 pot 模板生成工具 i18n.PostBuild,自己实现。

大概思路:

  1. 如果资源文件在所部署的 IIS 服务器上,依然使用以上的试试;

  2. 如果资源文件在 CDN 上(对于我们来说要翻译部分基本是 js、tpl、css、image),所以只需要处理 js、tpl 里面的多语言即可;

  3. 类似 [[[xxxx]]] 这样的语法,我们定义一个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% 的内容替换
        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. 根据 [[[xxxx]]] 和 _l('xxxx') 语法我们通过脚本来提取所有的 key,生成 pot 文件,大家可以注意文件内有一行 #: Disabled references:1,这里其实是有讲究的,我的方式是出于自动生成方便,大家有兴趣可以深入了解一下 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 模板导入到 transifex/crowdin 中,指定这个模板需要翻译出哪些语言,在线翻译完成后下载 po 文件;

    crowdin.png
    po.png
  6. 根据 po 文件生成js文件,把 js 引入到项目下就可以通过 _l('xxxx') 的方式使用了;

    local.png

    注意:如果使用第三方翻译平台,基本上都是按词数或者条数来收费的。为了减少一些成本,对于已经翻译好的内容,其实可以不用存储在翻译平台,翻译好后下载 po 文件后就可以把翻译平台上的内容清空。之后再导入新的 pot 文件,所以对 pot 的生成就要做一些处理,我们希望是增量式的。

    1. 提取站点中所有有效的 key

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

    3. 对比提取出来的 key 与现有翻译文件(已经清理过)中的 key

    4. 生成增量 key 的 pot 文件

    5. 导入只含增量 key 的 pot 文件,完成翻译

    6. 从翻译平台下载 po 文件,修改本地的 pot 和 po 文件(增量部分 copy 追加到文件中)

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

    以上的实现我们是通过 gulp 来完成的,具体实现方式可以根据情况而定。

参考链接:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,425评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,058评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,186评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,848评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,249评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,554评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,830评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,536评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,239评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,505评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,004评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,346评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,999评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,060评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,821评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,574评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,480评论 2 267

推荐阅读更多精彩内容