您的位置:首页 > Web前端 > JQuery

基于jQuery.i18n.properties插件实现前端页面国际化

2017-12-01 10:59 881 查看

一、简介

在介绍 jQuery.i18n.properties 之前,我们先来看一下什么是国际化。国际化英文单词为:Internationalization,又称 i18n,“i”为单词的第一个字母,“18”为“i”和“n”之间单词的个数,而“n”代表这个单词的最后一个字母。在计算机领域,国际化是指设计能够适应各种区域和语言环境的软件的过程。

jQuery.i18n.properties 是一款轻量级的 jQuery 国际化插件。与 Java 里的资源文件类似,jQuery.i18n.properties 采用 .properties 文件对 JavaScript 进行国际化。jQuery.i18n.properties 插件根据用户指定的(或浏览器提供的 )语言和国家编码(符合 ISO-639 和 ISO-3166 标准)来解析对应的以“.properties”为后缀的资源文件。

利用资源文件实现国际化是一种比较流行的方式,例如 Android 应用就可以采用以语言和国家编码命名的资源文件来实现国际化。jQuery.i18n.properties 插件中的资源文件以“.properties”为后缀,包含了区域相关的键值对。我们知道,Java 程序也可以使用以 .properties 为后缀的资源文件来实现国际化,因此,当我们要在 Java 程序和前端 JavaScript 程序中共享资源文件时,这种方式就显得特别有用。jQuery.i18n.properties
插件首先加载默认的资源文件(例如:strings.properties),然后加载针对特定语言环境的资源文件(例如:strings_zh.properties),这就保证了在未提供某种语言的翻译时,默认值始终有效。开发人员可以以 JavaScript 变量(或函数)或 Map 的方式使用资源文件中的 key。rties 插件首先加载默认的资源文件(例如:strings.properties),然后加载针对特定语言环境的资源文件(例如:strings_zh.properties),这就保证了在未提供某种语言的翻译时,默认值始终有效。开发人员可以以
JavaScript 变量(或函数)或 Map 的方式使用资源文件中的 key。


二、jQuery.i18n.properties API

jQuery.i18n.properties 的 API 非常简单,只有少数几个 API,即 jQuery.i18n.properties()、jQuery.i18n.prop()、jQuery.i18n.browserLang()。当然,和其他 jQuery 插件一样,我们也可以采用
$.i18n.properties()、$.i18n.prop() 和 $.i18n.browserLang() 的形式使用这用这些 API。


jQuery.i18n.properties(settings)

该方法加载资源文件,其中 settings 是配置加载选项的一系列键值对,各配置项的具体描述如表 1 所示。

表 1. settings


选项描述类型可选?
name资源文件的名称,例如 strings 或 [strings1,strings2],前者代表一个资源文件,后者代表资源文件数组。String 或 String[]
path资源文件所在目录的路径String
mode加载模式:“vars”表示以 JavaScript 变量或函数的形式使用资源文件中的 Key,“map”表示以 Map 的方式使用资源文件中的 Key,“both”表示可以同时使用两种方式。如果资源文件中的 Key 包含 JavaScript 的关键字,则只能采用“map”。默认值是“vars”。String
languageISO-639 指定的语言编码(如:“en”表示英文、“zh”表示中文),或同时使用 ISO-639 指定的语言编码和 ISO-3166 指定的国家编码(如:“en_US”,“zh_CN”等)。如果不指定,则采用浏览器报告的语言编码。String
cache指定浏览器是否对资源文件进行缓存,默认为 false。boolean
encoding加载资源文件时使用的编码。默认为 UTF-8。String
callback代码执行完成时运行的回调函数function
jQuery.i18n.properties() 的使用方法如清单 1 所示。

清单 1. jQuery.i18n.properties() 用法



jQuery.i18n.prop(key)

该方法以 map 的方式使用资源文件中的值,其中 key 指的是资源文件中的 key。当 key 指定的值含有占位符时,可以使用 jQuery.i18n.prop(key,var1,var2 … ) 的形式,其中 var1,var2 …对各占位符依次进行替换。例如资源文件中有“msg_hello= 您好 {0},今天是 {1}。”的键值对,则我们可以采用“jQuery.i18n.prop( ‘ msg_hello ’ , ’小明’ , ’星期一’ );”的形式使用 msg_hello。

jQuery.i18n.browserLang() 用于获取浏览浏览器的语言信息,这里不再单独介绍。

三、具体实现国际化的思路

1.首次进入浏览器,前端页面会根据浏览器设置的语言来显示对应的语言,一般大陆地区显示的简体中文(zh-CN),港澳台地区会显示繁体中文(zh-TW/zh-HK..),国外则是英文(en\en-US),如何查看或者设置浏览器语言??打开浏览器-设置-高级设置-语言即可看到,拿谷歌为例。



代码会根据浏览器的语言,将浏览器语言保存到cookie中,看清楚,一定要存到cookie中,不能存到session,原因是session一旦关闭了浏览器就会消失,而cookie不会,会根据你设置的时间保留起来(主要目的是为了下次登录仍然显示cookie保存的语言)

2.然后,前端页面(一般在头部)应该有个下拉框,选择是简体中文、繁体中文、英文等,绑定选择事件,选择某个后就会刷新浏览器中的cookie,自动刷新页面后,语言显示也会随之改变。

四、如何实现?

1.引入jquery和i18n插件(jQuery.i18n.properties)还有cookie插件(jquery.cookie.js)以及我们的language.js(该js是自己定义)

插件的目录结构应该是这样的,下面还有对应的en(英文),zh-CN(简体中文)的文件包,下面有对应的properties文件,



2.html代码

<html lang="en">
<head>
<meta charset="UTF-8">
<title class="i18n" name='title'></title>
<meta id="i18n_pagename" content="index-common">
<meta name="viewport" content="width=device-width">
<meta name="keywords" content="" />
<meta name="description" content=""/>
<link rel="stylesheet" href="css/index.css">
</head>
<body>
<div class="lan">
<div class="lan1"><label class="i18n" name="lan"></label></div>
<div class="lan2">
<select id="language">
<option value="zh-CN">中文简体</option>
<option value="zh-TW">中文繁體</option>
<option value="en">English</option>
</select>
</div>
</div>
<br>
<hr>
<div><label class="i18n" name="hellomsg1"></label><label class="i18n" name="hellomsg2"></label></div><br>
<div><label class="i18n" name="commonmsg1"></label><label class="i18n" name="commonmsg2"></label></div><br>
<div>
<input type="search" class="i18n-input" selectname="searchPlaceholder" selectattr="placeholder">
</div>

<script src="js/jquery.js "></script>
<script src="js/jquery.cookie.js"></script>
<!-- 加载语言包文件 -->
<script src="js/jquery.i18n.properties.js"></script>
<script src="js/language.js"></script>
</body>
</html>


language.js代码如下:

/**
* 获取浏览器语言类型
* @return {string} 浏览器国家语言
*/
var getNavLanguage = function(){
if(navigator.appName == "Netscape"){
var navLanguage = navigator.language;
return navLanguage;
}
return false;
}

/**
* 设置语言类型: 默认为中文
*/
var i18nLanguage = "zh-CN";

/*
设置一下网站支持的语言种类
*/
var webLanguage = ['zh-CN', 'zh-TW', 'en'];

/**
* 执行页面i18n方法
* @return
*/
var execI18n = function(){
/*
获取一下资源文件名
*/
var optionEle = $("#i18n_pagename");
if (optionEle.length < 1) {
console.log("未找到页面名称元素,请在页面写入\n <meta id=\"i18n_pagename\" content=\"页面名(对应语言包的语言文件名)\">");
return false;
};
var sourceName = optionEle.attr('content');
sourceName = sourceName.split('-');

/*
首先获取用户浏览器设备之前选择过的语言类型
*/
if ($.cookie('userLanguage')!=undefined||$.cookie('userLanguage')!=null||$.cookie('userLanguage')!="") {

i18nLanguage = $.cookie('userLanguage');

console.log(i18nLanguage);

} else{
// 获取浏览器语言
var navLanguage = getNavLanguage();

console.log(navLanguage);

if (navLanguage) {
// 判断是否在网站支持语言数组里
var charSize = $.inArray(navLanguage, webLanguage);
if (charSize > -1) {
i18nLanguage = navLanguage;
// 存到缓存中
$.cookie('userLanguage',navLanguage, { expires: 30})
};
} else{
console.log("not navigator");
return false;
}
}
/* 需要引入 i18n 文件*/
if ($.i18n == undefined) {
console.log("请引入i18n js 文件")
return false;
};

/*
这里需要进行i18n的翻译
*/
jQuery.i18n.properties({
name : sourceName, //资源文件名称
path : 'i18n/' + i18nLanguage +'/', //资源文件路径
mode : 'map', //用Map的方式使用资源文件中的值
language : i18nLanguage,
callback : function() {//加载成功后设置显示内容
var insertEle = $(".i18n");
console.log(".i18n 写入中...");
insertEle.each(function() {
// 根据i18n元素的 name 获取内容写入
$(this).html($.i18n.prop($(this).attr('name')));
});
console.log("写入完毕");

console.log(".i18n-input 写入中...");
var insertInputEle = $(".i18n-input");
insertInputEle.each(function() {
var selectAttr = $(this).attr('selectattr');
if (!selectAttr) {
selectAttr = "value";
};
$(this).attr(selectAttr, $.i18n.prop($(this).attr('selectname')));
});
console.log("写入完毕");
}
});

}

/*页面执行加载执行*/
$(function(){

/*执行I18n翻译*/
execI18n();

/*将语言选择默认选中缓存中的值*/
$("#language option[value="+i18nLanguage+"]").attr("selected",true);

/* 选择语言 */
$("#language").bind('change', function() {
var language = $(this).children('option:selected').val()
console.log(language);

$.cookie('userLanguage',language, { expires: 30});

location.reload();
});
});

简体中文界面:


繁体中文界面:




英文界面:




对应的三个语言的资源文件如下:




可以看到界面展示图片中浏览器控制台有404报错信息





要求你在一种webServer里面去访问.properties文件,这个问题你只需要使用任何一种webserver运行即可,比如IIS、Apache、Node的web服务器等。博主的代码是在Visual Studio里面跑的,所以是基于IIS的,当你把代码搬到VS里面跑的时候,第一个问题来了


坑一:配置IIS对.properties文件的支持

如果本文仅仅是上面的内容,是没啥意义的。接下来才是本文要介绍的重点!

将上述代码直接搬到VS里面,运行的时候你会发现第一个问题:



为什么这里会请求三个properties文件?因为jquery.i18n.properties.js组件支持三种类型的命名方式,这点很多文章都有介绍,组件代码运行的时候会去请求三种规则的properties文件,只要找到任何一种规则的文件都可以读取到里面的内容。按照博主上文给出的文件目录



根据这个目录,那我们通过 http://localhost:12770/Content/i18n/zh-CN/common.properties 这个url应该能访问到zh-CN/common.properties这个文件,可实际情况确实这样:



对于这种IIS报错404的问题,C#程序员肯定是不陌生的,无非就两个原因:
url不正确,这个目录下面确实没有找到这个资源文件
文件的类型iis默认不支持,直接拒绝请求

排除了第一个原因,那么只可能是第二个原因引起的了。那么我们如何处理呢,在网上搜索半天资料,找到一种解决方案:



这样确实能绕过IIS的文件名验证,但是改源码不是一个好的解决方案,博主有一千个理由来说明改源码的弊端。这种方式肯定不是一个最好的解决方案,于是博主决定另辟蹊径。

还记得当初博主学习less的时候,iis默认也是不支持.less文件的,于是我们在web.config里面加了如下一些配置:



这绝对属于同类型的问题,加这个配置是显式告诉IIS,我们系统里面某种后缀的文件需要哪种Processer(处理器或处理组件)去处理,受此启发,那么我们这里的.properties文件的404问题是不是也可以通过此种方式解决?如果需要通过这种思路去解决,首要问题是需要找到.properties文件的mimeType,博主思考,既然是在js里面调用这个.properties文件,那么我们是否可以使用JavaScript的处理机制来处理.properties文件呢,考虑到上面那种将所有.properties替换成.js的处理方式,似乎.properties和.js有很多相似之处,于是我们加上如下一条配置:



得到结果:



试验成功,就是这么简单。当然如果发布到IIS,可能需要在IIS的MIME类型里面添加.properties这种类型的映射。



好了,这个问题就这么愉快的解决了。如果你的WebServer不是基于IIS的,可能没有这个问题,但我想思路或许相通,供参考!

回到顶部


坑二:使用html的data属性初始化国际化内容

一般情况下,我们标签里面的内容如果要做国际化,需要使用 $('#id').text($.i18n.prop('proName')); 来给标签赋值,现在问题来了,我们开发一个界面,有很多地方都需要去做国际化,我们总不能这样每一个页面每一个标签通过这种方式去赋值吧,这样工作量不是一点大,于是乎博主想,有没有一种比较好的通用的解决方案去给这些需要做国际化的标签统一赋值呢。html的data属性似乎是一个不错的选择!它具有可读性强、可维护性强、兼容jquery的data()方法等优点。比如我们修改国际化组件的方法如下:

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写入完毕");
}
});


 通过data属性获取标签,然后对每个标签通过对应的data-i18n-属性进行国际化赋值即可,这里暂时定义了三种类型data-i18n-placeholder、data-i18n-text、data-i18n-value的属性,如果有其他需求,可以增加其他类型。

然后看下我们html页面的使用

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


<span data-i18n-text="setting"></span>


这样不用写一句标签的赋值代码,即可对标签进行国际化。

回到顶部


坑三:第三方组件的国际化(一)

对于第三方组件,我们自定义的代码里面的中文要做国际化,我只需要使用$.i18n.prop('key')即可,比如bootstrapTable:

{
field: 'AuditEventType',
title: '业务类型',
width: '12%'
}


直接使用

{
field: 'AuditEventType',
title: $.i18n.prop('bllType'),
width: '12%'
}


即可。这个解决思路很简单,没啥好说的,可是有一些第三方组件,自己有国际化的功能,初始化的时候需要指定国际化的类型,形如:

$(".date").datetimepicker({
format: 'YYYY-MM-DD',//日期格式化,只显示日期
locale: 'zh-CN'      //中文化
});


目前想到的解决方案,就是根据cookie里面存储的当前语言来显式赋值

//获取cookie里面的语言
var userLanguage = getlanguageCookie("userLanguage");
$(".date").datetimepicker({
format: 'YYYY-MM-DD',//日期格式化,只显示日期
locale: userLanguage =='zh-CN'?'zh-CN':'en-US'     //国际化
});


如果是多种语言,这里可以在前端自己去处理。

回到顶部


坑四:第三方组件的国际化(二)

 上面介绍了第三方组件初始化时候指定国际化,除此之外,还有另外一种情况,就是很多组件有自己的本地化(关于国际化和本地化的区别,请自行谷歌)文件,它的国际化是通过引用不同的本地化js文件来实现的,比如博主常用的bootstrapTable组件,它的目录:



还有其他组件也是这样,比如:



 



那么针对这种情况,我们的国际化该如何实现了,这里博主提供的思路是动态引用js,通过当前cookie里面保存的语言的类型来引用对应语言的js文件,比如针对bootstrapTable,我们这样去动态引用js

     //组件根据国际化动态引入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);
}


如果要想代码写得更加优雅,可以自己去实现前端的抽象工厂,这里只是提供一种实现思路。

示例下载链接:去下载

本文参考:
https://www.cnblogs.com/landeanfen/p/7581609.html https://www.ibm.com/developerworks/cn/web/1305_hezj_jqueryi18n/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息