美文网首页码农的世界dotNETC#
让多语言开发变得简单点

让多语言开发变得简单点

作者: BeckJin | 来源:发表于2017-05-19 15:37 被阅读2330次

    实现方式大概两种:

    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来完成的,具体实现方式可以根据情况而定。

    参考链接:

    相关文章

      网友评论

        本文标题:让多语言开发变得简单点

        本文链接:https://www.haomeiwen.com/subject/veuyxxtx.html