公司国际化笔记

国际化原因

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

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

目录

[TOC]

需求分析

项目的代码全部国际化任务量不小,公司基本没有用什么框架,基本采用的是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 = \u4F60\u597D

#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 \u4E3B\u9875
help = help \u5E2E\u52A9

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

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

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏美码师

补习系列-springboot项目基础搭建课

springboot 最近火的不行,目前几乎已经是 spring 家族最耀眼的项目了。抛开微服务、技术社区这些推广因素不说,框架本身的确有非常多的优点。比如

492
来自专栏纯洁的微笑

springcloud(六):配置中心git示例

随着线上项目变的日益庞大,每个项目都散落着各种配置文件,如果采用分布式的开发模式,需要的配置文件随着服务增加而不断增多。某一个基础服务信息变更,都会引起一系列的...

29310
来自专栏QQ会员技术团队的专栏

kubernetes 容器编排系统介绍

Kubernetes作为容器编排生态圈中重要一员,是Google大规模容器管理系统borg的开源版本实现,吸收借鉴了google过去十年间在生产环境上所学到的经...

11.5K3
来自专栏拭心的安卓进阶之路

npm 与 package.json 快速入门

npm 是前端开发广泛使用的包管理工具,之前使用 Weex 时看了阮一峰前辈的文章了解了一些,这次结合官方文章总结一下,加深下理解吧! 什么是 npm? ? 官...

3168
来自专栏Laoqi's Linux运维专列

部署Java项目(Ⅱ)

1615
来自专栏我有一个梦想

Python 项目实践三(Web应用程序)第五篇

 接着上节继续学习,在这一节,我们将建立一个用户注册和身份验证系统,让用户能够注册账户,进而登录和注销。我们将创建一个新的应用程序,其中包含与处理用户账户相关的...

1848
来自专栏搜云库

《深入理解Java虚拟机》(五)JVM调优 - 工具

JVM调优 - 工具 JConsole:Java监视与管理控制台 JConsole是一个机遇JMX(Java Management Extensions,即Ja...

2349
来自专栏工科狗和生物喵

【计算机本科补全计划】Mysql 学习小计(3)

正文之前 想到自己每天中午还要玩一小时手机,就自责不已,今天看成甲的好好学习一书,颇有收获,晚上写给大伙看,现在还是谢谢 Mysql,到了后面感觉越来越难了呢!...

2754
来自专栏北京马哥教育

Linux运维常见故障排查和处理的33个技巧汇总

作为linux运维,多多少少会碰见这样那样的问题或故障,从中总结经验,查找问题,汇总并分析故障的原因,这是一个Linux运维工程师良好的习惯。每一次技术的突破,...

3336
来自专栏文渊之博

探索SQL Server元数据(一)

  在数据库中,我们除了存储数据外,还存储了大量的元数据。它们主要的作用就是描述数据库怎么建立、配置、以及各种对象的属性等。本篇简单介绍如何使用和查询元数据,如...

1012

扫码关注云+社区