zoukankan      html  css  js  c++  java
  • 公司国际化笔记

    国际化原因

    为了更加方便切换版本,让代码应该一次完成,多国使用,除了使用英语外,还要可以进行单独语言包的一个添加,文章就是这样的一个例子.

    公司接到一个国外的项目,需要法文版本的,但是公司通晓法文的基本没有,于是商量降低要求之后开始国际化采用英文展示就行,于是任务就开始了.

    目录

    需求分析

    项目的代码全部国际化任务量不小,公司基本没有用什么框架,基本采用的是js,html实现数据的展示,没有采用框架,只是有一些简单的逻辑分层,加大了不少国际化的难度.

    但是针对java部分的代码,虽说稍微熟悉一些,但是国际化就暂时不需要我负责了,虽说我也只是之前弄过纯java的一些简单的国际化.

    我的话暂时只是需要复杂光伏预测系统的web展示界面.其他的国际化暂时不需要修改,毕竟最为直接的只是能够看到的部分.计算过程中的一些说明日志什么的,可以后面再继续更改.

    准备工作

    开始准手国际化之前,先查阅了一下相关的文章,在前端方面需要修改的部分方法有如下几种:

    • vue + vue-i18n
    • angular + angular-translate
    • react + react-intl
    • jquery.i18n.properties

    由于考虑到公司原本的代码没有使用什么现在的最新框架,只是采用的最后一个,也就是jquery.i18n.properties这样子的一个解决方案了,目前方案就暂时这么定来下了,然后下载对应的jQuery文件和jQuery.i18n文件了.

    由于文件更新比较快,这里就不单独提供下载连接了,自行搜索,测试版本的时候使用的是3.3的版本.对应的浏览器需要ie10及以上,谷歌基本没问题.

    开始着手

    引入jQuery相关js

    首先是引入jQuery的文件.有两种方案了,一种是在每个页面一个个添加,这样子效率不高,但是稳定,还有一种是采用js直接内部引入外部的js的方法,两种方法的代码如下:

    <!-- 页面添加连接 -->
    <script type="text/javascript" language="JavaScript"
      src="../jsCommon/jquery-3.3.1.js"></script>
    <script type="text/javascript" language="JavaScript"
      src="../jsCommon/jquery.i18n.properties.min.js"></script> 
    <!--           <script type="text/javascript" language="JavaScript"
      src="../jsCommon/jquery.i18n.properties.js"></script> -->
    

    这里其实是指需要两个,多的一个min的包,只是为了后面加速加载之用,开发测试的话,一般用不压缩的js包,因为看起来有些难度.

    //js内部添加外部js
    document.write('<script type="text/javascript" language="JavaScript"  src="../jsCommon/jquery-3.3.1.js"></script>');
    document.write('<!-- <script type="text/javascript" language="JavaScript"  src="../jsCommon/jquery.i18n.properties.min.js">	</script> -->');
    document.write('<script type="text/javascript" language="JavaScript"  src="../jsCommon/jquery.i18n.properties.js"></script>');
    

    这里需要注意一下的是,添加这个之后,才能使用这个引入的js,并且不能在这个js里面使用引入的一些方法,因为会找不到,你可以尝试一下.

    采用第二种方法的话,需要找一个所有页面都存在的js文件才可以,可以根据自己的需要选择,没有这样的一个js的话,就差不多只能选择第一个方法,或者自己写这么一个js了.

    初始化参数

    引入之后js就需要初始化了,代码以及参数如下:

    var currentLang = navigator.language;   //判断除IE外其他浏览器使用语言
    if(!currentLang){//判断IE浏览器使用语言
       currentLang = navigator.browserLanguage;
    }
    console.info("Browser: "+ currentLang);
    //currentLang = 'en-US';
    //currentLang = 'zh_CN';
    
    
    jQuery.i18n.properties({
    		name: 'nari', //必须和配置文件一致
    		path : '../jsCommon/', // 资源文件路径
    		mode : 'map', // 用 Map 的方式使用资源文件中的值
    //		language : 'en_US',
    		language : currentLang, 
    //		cache:false, 
    //		encoding: 'UTF-8', 
    		callback: function(){ 
    			console.info( $.i18n.prop('info'));
    			console.info(currentLang);
    		}
    

    这里的话分为两个部分了,前面部分只是为了自动识别浏览器的语言,做的一个判断,可以不要,然后下面的参数的话,没有注释的部分,一般就是都需要填写的了,除了那个language除外,那个也是可以省略.

    国际化页面

    上面的那个初始化的代码可以放在页面加载完成之前,也可以放在页面加载完成之后.加载的方法有两种,一种是统一加载,一种是按需加载.

    统一加载

    放在页面加载完成之后的话,这个部分的代码就需要放在js的最后面了,然后在callback方法里面,通过id号或者其他的标志进行国际化操作了.
    网络上面多是这么一个案例,找到应该不难,这里就copy一份例子,没有经过实际代码验证:

    jQuery.i18n.properties({
            name: 'common',
            path: '/Content/i18n/' + i18nLanguage + '/', //资源文件路径
            mode: 'map', //用Map的方式使用资源文件中的值
            language: i18nLanguage,
            callback: function () {//加载成功后设置显示内容
                console.log("i18n赋值中...");
                try {
                    //初始化页面元素
                    $('[data-i18n-placeholder]').each(function () {
                        $(this).attr('placeholder', $.i18n.prop($(this).data('i18n-placeholder')));
                    });
                    $('[data-i18n-text]').each(function () {
                        //如果text里面还有html需要过滤掉
                        var html = $(this).html();
                        var reg = /<(.*)>/;
                        if (reg.test(html)) {
                            var htmlValue = reg.exec(html)[0];
                            $(this).html(htmlValue + $.i18n.prop($(this).data('i18n-text')));
                        }
                        else {
                            $(this).text($.i18n.prop($(this).data('i18n-text')));
                        }
                    });
                    $('[data-i18n-value]').each(function () {
                        $(this).val($.i18n.prop($(this).data('i18n-value')));
                    });
                }
                catch(ex){ }
                console.log("i18n写入完毕");
            }
        });
    

    这里需要注意的是,这里需要每一个需要更改的位置都添加类似如下的标记:

    <input class="typeahead" type="text" id="menu_search" data-i18n-placeholder = "searchPlaceholder"/>
    
    <span data-i18n-text="setting"></span>
    

    这里的话如果是开始开发或者只是短小一些的英文的话,还是可以考虑的,但是如果是完整的项目的话,任务栏就不小了.自行选择处理.下面介绍第二种方法.

    按需加载

    前面的那段初始化代码如果放在页面加载之前的话,就是放在引入jQuery之后,直接初始化,然后在其他位置,需要替换成国际化的位置,按照如下的格式替换就行.

    //old
    alert("hello");
    
    //new
    alert($.i18n.prop('hello'));
    

    配置文件

    能够知道国际化,上面的那个替换位置的用处自然不用多说,还是提一句吧 ,这样子看似复杂了,但是后面需要修改的话,
    不需要改动这里的js,而是只需要更改对应的nari.properties(具体名字根据自己的配置来)就行了,还可以根据需要自动判断语言包.

    对应的nari.properties文件中文文件包的名字是nari_zh.properties和nari_zh-CN.properties,
    也可以多一个繁体字的nari_zh-TW.properties,英文的对应的是nari_en.properties,
    nari_en-US.properties,nari_en-UK.properties,其他国家和语言的就自己查询了,然后里面的内容大致如下格式:

    #nari_zh.properties
    #Chinese character need transfer to unicode 
    hello = u4F60u597D
    
    #nari_en.properties
    hello = hello 
    

    其他国际化内容

    上面基本上可以完成大部分页面的处理了,但是还是有一些其他的需要注意一下.

    标题的国际化

    这里由于标题在最先加载,不管上面的那种方法,都是在这个标题之后,只能在加载之后,通过js的方法进行标题更改了.这里简单罗列一下几个有趣的方法,作用看名字就懂了.

    document.getElementsByTagName("title")[0].innerText = '需要设置的值';
    
    window.onfocus = function () {
     document.title = '恢复正常了...';
    };
    window.onblur = function () {
     document.title = '快回来~页面崩溃了';
    };
     
    $('title').html('')
    

    需要修改的位置,只是需要把对应的字符串替换成$.i18n.prop('Title')就行了.

    这里还有个问题是,如果你的浏览器加载比较慢的话,在浏览英文时候,可能会看到标题先是英文,之后才变成中文,这是应为标题加载是在js运行之前的缘故了,这个暂时没有找到好的解决办法,
    一般浏览器的加载速度基本都发现不了这个现象,如果非要解决的话,就把原先的html里面的标题设置成空格把,这样就看不到中文了.

    一些未启用的界面的国际化

    这个部分,emmmmm,既然没启用,也没有直接的连接跳转过去,我也不启用吧.这次里面有两个不知道干嘛的页面FSDayGrid和OverhaulCapacity.

    针对一些插件的处理

    针对一些插件的处理的话,如果插件本身没有国际化的功能,就直接按照上面的那个按需国际化加载就行了,比方说根据自身需要引入的一些数据表格之类的插件.还有一些固定的菜单之类的等等,
    当你需要同样的差不多的插件,但是有不完全相同时候,需要全部国际化是多么令人头疼的一件事情.

    你能猜猜下面三个文件的作用吗?

    //差不多的功能,就不能放一个文件里面处理吗?
    
    // /PVForecast(s)1.24/WebRoot/PVForecast/jsCommon/command/MyEWISUtil.js
    /PVForecast(s)1.24/WebRoot/PVForecast/jsCommon/Mcommand/MyEWISUtil.js
    /PVForecast(s)1.24/WebRoot/PVForecast/jsCommon/Mcommand/MyEWISUtil1.js//runalarm
    /PVForecast(s)1.24/WebRoot/PVForecast/jsCommon/command_cx/MyEWISUtil.js//StationRTList
    
    //page部分的双引用已经更改为一个引用,两个部分完全一致,但是不能自动国际化,则选择性修改后者.
    
    <!--<script type="text/javascript" src="../jsCommon/ext/build/locale/ext-lang-zh_CN.js"></script> -->   
    //index StationRTLists PlanCapacity
           
     <script type="text/javascript" src="../jsCommon/ext/source/locale/ext-lang-zh_CN.js"></script>
    //RunAlarm SolRadFigureF PowerFigureF ContrastPowerFigureF ContrastUShortRealtimeTheory ContrastLists
    
     <script type="text/javascript" src="../Datetime/ext-lang-zh_CN.js"></script>
    /PVForecast(s)1.24/WebRoot/PVForecast/Datetime/ext-lang-zh_CN.js
    
    //针对一些表格位置的中文,发现是createGrid这个函数加载的,主要是针对xml文档的一个解析分析了.
    //这个如果是返回或得到的数据的话,就不是很好处理了,需要在发送请求时候特殊处理.
    // 数据显示的空间,针对角标的显示,有四处不同的引用,修改需要针对不同的部分进行修改.文件名至少都是GeneralGrid.js类似的名字.
    //时间选择控件针对google的兼容性不是很好,需要进行处理,
    //同时,日期对应的格式需要转化为国际化的形式,注意文件的位置,和时间控件有三个
    
    /PVForecast(s)1.24/WebRoot/PVForecast/jsCommon/command/EditorGrid.js
    /PVForecast(s)1.24/WebRoot/PVForecast/jsCommon/command/GeneralGrid.js
    /PVForecast(s)1.24/WebRoot/PVForecast/jsCommon/command/GeneralGrid1.js
    /PVForecast(s)1.24/WebRoot/PVForecast/jsCommon/command/GeneralGrid2.js
    /PVForecast(s)1.24/WebRoot/PVForecast/jsCommon/command/GeneralGrid3.js
    /PVForecast(s)1.24/WebRoot/PVForecast/jsCommon/command/GeneralGrid4.js
    /PVForecast(s)1.24/WebRoot/PVForecast/jsCommon/command_cx/GeneralGrid.js
    /PVForecast(s)1.24/WebRoot/PVForecast/jsCommon/command_cx/GeneralGrid1.js
    

    如果一些插件本身是带有国际化的,一般通过一些方法引入就行了.下面的一个例子可以参考一下:

    var userLanguage = getlanguageCookie("userLanguage");
    //如果cookie里面没有,则使用默认值
    if (!userLanguage) {
    	userLanguage = 'zh-CN';
    }
    if (userLanguage == 'zh-CN') {
    	var script = $('<script></script>');
    	script.attr('src', '/Content/bootstrap-table/locale/bootstrap-table-zh-CN.js');
    	$('body').append(script);
    }
    else if (userLanguage == 'en') {
    	var script = $('<script></script>');
    	script.attr('src', '/Content/bootstrap-table/locale/bootstrap-table-en-US.js');
    	$('body').append(script);
    }
    

    这个是自动判断中英文然后加载了,代码没有验证成功,getlanguageCookie函数加载失败了,可能要自己写.不过有一个自动化一点的可以参考,代码已经经过验证:

    console.info(currentLang);
    currentLang=currentLang.replace('-','_');
    var scr= '<script type="text/javascript" src="../jsCommon/ext/source/locale/ext-lang-'+currentLang+'.js"></script>';
    document.write(scr);
    

    代码是可以正常运行了,但是需要注意一下文件的名字和路径的问题.

    针对返回数据的处理

    有些位置通过定时查询数据库是否有异常数据之后直接alert获取到的数据,你就没办法了,如果是java代码还好,还可以采用java代码的国际化,这里后面有机会再提了.方法和这个类似.

    如果你硬是要通过解析判断获取到数据的中文,然后写一个替换的过程的话,我在精神上面支持你,也欢迎你把写好的代码评论一番.

    针对xml文件的配置国际化

    针对一些通过xml动态配置页面的部分,解决方案就太多了,一个是在所有的节点旁边配置一个英文节点,但是后面维护,估计不好添加其他的语言.

    那就再重写一套英文的?暂时就这么处理吧,复制一份为英文,中文的还是保留,可以在需要中文时候加载中文的配置文件,这里暂时就先自动化处理了,等后面有时间的话再添加.

    复制之后,基本把所有的中文,改成英文,就完成了.

    配置文件的双语处理

    在处理国际化时候,为了方便对比中英文,我是专门坐了一个中英文的文件的,但是分开时候就很伤脑经了,因为有六百多行的中文英文都是如下的一个格式:

    index = index 主页
    help = help 帮助
    

    想要分开,有些难度,索性好在有正则表达式这个东西,大部分的数据是可以处理了,少部分带标点的就自行修改了.

    寿险,复制一份之后(你不想失误操作之后就全没了吧?),通过浏览器转换成unicode的形式,然后代码成这个样子了:

    index = index u4E3Bu9875
    help = help u5E2Eu52A9
    

    然后在能够使用正则表达式的位置查找替换=[sw+]+\这个就行了,这个是将=之后和之前的英文选中.全部处理完差不多就是中文的了,可能要注意一些带有符号的中英文了.

    再复制一份之后通过这个\[wS+]+$ ,选中所有的中文,替换为空格就解决了,这个就是英文的配置文档了.

    网上了解到有直接通过unicode查找汉字的,但是通过notepad+没有测试成功,就没有实际使用了,而且还要主意一下中文之间的符号问题,虽说是少数了.有更好的解决方案欢迎点评指正.

    说明

    欢迎评论,欢迎指正,转载也请注明出处.

    参考博客

    前端系列_jquery.i18n.properties前端国际化解决方案“填坑日记”

    js 前端实现国际化配置

    CommanderXL/di18n_translate: di18n_translate

    Java中的国际化

    JS判断浏览器语言及终端类型

    js笔记浏览器及版本判断

    js 获取浏览器版本信

    BrowserInfo

    JavaScript进阶(二)在一个JS文件中引用另一个JS文件

    版本记录

    20180606 起草任务
    20180627 完成翻译
    20180728 完成文章

  • 相关阅读:
    解剖PetShop系列之六PetShop表示层设计
    解剖PetShop系列之五PetShop之业务逻辑层设计
    用memset给一个char设置0xff,然后将该char和0xff ==,能相等么?
    用gdb如何查看指定地址的内存内容?
    Open a pipe will block if other side hasn't opened this pipe
    inet_aton和inet_pton的区别
    很多源码中看到的ignore SIGCHLD信号是做什么用的?
    Linux下getopt函数使用Tips
    Linux下编译一个静态链接的程序的注意点
    Linux 脚本和程序对SIGINT的处理方案,脚本通过kill给程序传递信号
  • 原文地址:https://www.cnblogs.com/wangkun1993/p/9240177.html
Copyright © 2011-2022 走看看