前言:最近,新的平台还没有开发完成,原来的老项目又提出了新的需求:系统国际化。如果是前后端完全分离的开发模式,要做国际化,真的太简单了,有现成的解决方案,基于Node构建的时下热门的任何一种技术选型都有成熟的方案,比如:

  • vue + vue-i18n

  • angular + angular-translate

  • react + react-intl

但现在的情况是老的项目并没有使用这类架构。说起国际化,博主几年前就做过,在MVC里面实现国际化有通用的解决方案,主要就是通过资源文件的方式定义多语言。最初接到这个任务,并没有太多顾虑,毕竟这种东西有很成熟的解决方案,实现起来难点不会很大。可当真正动起来手来去实现的时候发现一些问题,这里先介绍下我们老平台的架构:MVC+WebApi,MVC项目负责页面渲染,webapi负责数据接口,是一种很传统的架构方式。国际化主要在MVC端去做就好了,可是由于MVC项目里面使用了大量第三方bootstrap组件,几乎95%的组件都是通过js去实现的,比如bootstrapTable,比如bootstrap-select,比如bootstrap-fileinput。如果按照传统的方式,仅仅在MVC里面去实现国际化,那么大量的js代码里面的中文没法统一处理,并且很多第三方组件有自己的本地化local文件,和后端的国际化很难统一处理;可能有人又说,那就前后端分开国际化呗,这种方案博主真的想过,但是想到要维护两套资源文件,果断放弃。最后还是决定直接维护一套,做前端国际化好了。于是在网上搜索基于jquery的国际化,千篇一律,几乎都说的是jquery + jquery.i18n.properties这种方案,既然大家都这么选型,那博主也按照这种思路去做好了。

在实现的过程中,有很多值得注意和分享的东西,在此写一个填坑笔记,希望对大家有帮助!接下来,博主就一步一步带领大家解决这个过程中遇到的一些坑,如果有这个需求的童鞋可以关注下,可能这些问题你也会遇到。

本文原创地址:http://www.cnblogs.com/landeanfen/p/7581609.html

一、jquery.i18n.properties通用解决方案

关于jquery.i18n.properties的使用,网上资料很多,比较完整的使用可以参考 这篇 ,有比较详细的使用说明。这里博主简单概述下过程。

1、需要引用的js文件

先在你的项目文件里面添加如下目录结构

首先页面引用的js文件如下

   <script src="~/Scripts/jquery-1.9.1.min.js"></script>
<script src="~/Content/i18n/jquery.i18n.properties.js"></script>
<script src="~/Content/i18n/language.extensions.js"></script>

其中jquery-1.9.1.min.js和jquery.i18n.properties.js文件是开源组件,直接去网上找到即可

第三个文件language.extensions.js是我们自定义的js文件,如果你将国际化的代码直接写在html页面里面,这个文件就是不用的。

2、html文件和国际化组件的初始化

这里直接引用上面示例文章里面的代码,首先需要一个切换中英文的标签,比如是一个select

        <select id="language">
<option value="zh-CN">中文简体</option>
<option value="en">English</option>
</select>

然后是一些查看效果的html标签

<div>
<input type="search" class="i18n-input" selectname="searchPlaceholder" selectattr="placeholder">
</div>

最后就是我们需要封装的language.extensions.js文件的内容了,里面做了以下几件事:

  • 初始化页面的时候去当前域的cookie里面取当前浏览器保存语言的cookie,根据取到的当前语言版本去初始化国际化组件,然后初始化select组件的选中值
  • 注册select组件的change事件,根据当前选中的语言,更新cookie里面的语言信息,然后刷新页面。

这个文件的内容这里就不展示了,可以参考上面的使用示例文章

3、资源文件准备

根据上面的目录可以看出,我们打算将不同的语言的资源文件放到不同语言的文件夹里面,这里暂时不分文件,所有的语言资源放到一个文件common.properties里面,比如内容如下:

en/common.properties

searchPlaceholder=Please input serach information
signOut=Login Out station=Station
partno=Part No
description=Description
query=Query pleaseSelect=Please Select add=Add
edit=Edit
delete=Delete

zh-CN/common.properties

searchPlaceholder=请输入关键字
signOut=退出 station=站点
partno=零件号
description=描述
query=查询 pleaseSelect=请选择 add=新增
edit=编辑
delete=删除

貌似大功告成!当你down源码直接在google浏览器里面运行的时候你会发现一个跨域的问题。

要求你在一种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#程序员肯定是不陌生的,无非就两个原因:

  1. url不正确,这个目录下面确实没有找到这个资源文件
  2. 文件的类型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);
}

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

六、总结

排除了以上几步的困难,我们的国际化在项目里面基本就能正常运行起来了,至于WebApi里面返回消息的中文,如果你也想做国际化,我们可以通过将返回消息封装,统一返回前端处理。本篇文章的“填坑方式”或许不是最好的,但至少给大家提供了一种实现思路,如果大家有更好的实现方式,欢迎留言交流。如果你觉得本文能够帮助你,可以右边随意 打赏 博主。

本文原创出处:http://www.cnblogs.com/landeanfen/

欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利

前端系列——jquery前端国际化解决方案“填坑日记”的更多相关文章

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

    前言:最近,新的平台还没有开发完成,原来的老项目又提出了新的需求:系统国际化.如果是前后端完全分离的开发模式,要做国际化,真的太简单了,有现成的解决方案,基于Node构建的时下热门的任何一种技术选型都 ...

  2. jquery.i18n.properties前端国际化解决方案“填坑日记”

    但现在的情况是老的项目并没有使用这类架构.说起国际化,博主几年前就做过,在MVC里面实现国际化有通用的解决方案,主要就是通过资源文件的方式定义多语言.最初接到这个任务,并没有太多顾虑,毕竟这种东西有很 ...

  3. WindowsPhone&amp;Windows8.1&amp;Windows8&amp;Unity3d 填坑日记

    近期的游戏开发大体上接近尾声,总结了不少关于Unity3d面向Windows几大平台开发时遇到的各种坑以及怎样填坑的经验.总的来说,Windows8.1 Windows8/RT以及WindowsPho ...

  4. 九、VueJs 填坑日记之在项目中使用jQuery

    很多人学习 js 都是从 jQuery 开始的,我也不例外.有时候进行一些操作的时候,还是感觉 jQuery 比较好用,那么,我们如何在项目中使用 jQuery 呢?这篇博文带你实践. 引用 jQue ...

  5. 一、VueJs 填坑日记之基础概念知识解释

    概述在最开始听说vuejs这个词是在2016年,当时天真的认为自己是个后端开发工程师不需要学习太多的前端知识,不过紧接着在2017年在公司就用到了vuejs.对于初学者(尤其是干后端的初学者)来说,刚 ...

  6. 五、VueJs 填坑日记之将接口用webpack代理到本地

    上一篇博文,我们已经顺利的从cnodejs.org请求到了数据,但是大家可以注意到我们的/src/api/index.js的第一句就是: // 配置API接口地址 var root = 'https: ...

  7. 六、VueJs 填坑日记之初识*.Vue文件

    上一篇博文中,我们将接口的地址通过webpack代理到了本地,解决了跨域的问题.在之前的文章中,我们一直对项目进行配置,并没有真正的切入正题,可能很多人还不明白我们要做什么?那么今天,我们就要开写代码 ...

  8. 二、VueJs 填坑日记之基础项目构建

    在上一篇文章中,大致介绍了一下本系列博文以及学习vuejs我们需要了解的一些概念,希望大家认真阅读,所谓知己知彼,百战百胜,学习也一样,工欲善其事,必先利其器,要想学好vuejs,那前提的概念一定要熟 ...

  9. 三、VueJs 填坑日记之项目文件认识

    上一篇博文,我们搭建了一套基础的vuejs的环境,首先安装node.js,然后利用npm包管理器,安装vue-cli,设置淘宝镜像,初始化项目,安装依赖,运行.在这一篇,我们将认识vuejs项目里的各 ...

随机推荐

  1. 简说JS中的循环部分

    JS中的循环语句是JS基础的最最重要的部分,没有之一,后面所学的其他的一些重要的知识也是需要在此的基础啥古玩城更高级的设置,先来简单的说一下循环的一些知识点. 一.循环结构的执行步骤 1.声明循环变量 ...

  2. 支付宝小程序PHP全栈开发--前端样式的设计.acss样式详解

    关于.acss文件 在视频中已经说过了,小程序的设计思想和原生app的设计思想颇为相似,基本的应用单元为页面.当然对于一个页面来说每一个元素的放置位置在哪儿以及显示成什么样子这个是由样式来决定的.我们 ...

  3. Nginx + Memcached 实现Session共享的负载均衡

    session共享 我们在做站点的试试,通常需要保存用户的一些基本信息,比如登录就会用到Session:当使用Nginx做负载均衡的时候,用户浏览站点的时候会被分配到不同的服务器上,此时如果登录后Se ...

  4. 堆排序Java实现

    package practice; import edu.princeton.cs.algs4.StdRandom; public class TestMain { public static voi ...

  5. Semaphore实现原理分析

    synchronized的语义是互斥锁,就是在同一时刻,只有一个线程能获得执行代码的锁.但是现实生活中,有好多的场景,锁不止一把. 比如说,又到了十一假期,买票是重点,必须圈起来.在购票大厅里,有5个 ...

  6. CSS中的路径裁剪样式clip-path

    前面的话 CSS借鉴了SVG裁剪的概念,设置了clip-path样式,本文将详细介绍路径裁剪clip-path 概述 clip-path属性可以防止部分元素通过定义的剪切区域来显示,仅通过显示的特殊区 ...

  7. linux为用户配置java环境变量

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt226 一. 解压安装jdk 在shell终端下进入jdk-6u14-linu ...

  8. Spring定时任务quartz表达式

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcytp32 0 0 12 * * ?---------------在每天中午12: ...

  9. html5中的video标签和audio标签

    不管是否承认,flash早已不像过往那样如日中天了.亚马逊全面放弃flash.苹果放弃flash.安卓也放弃了移动端的flash支持.事实上flash已经不太适合web开发了,因为HTML5中的vid ...

  10. FileInputStream 小Demo

    要求:设计如下界面  文本框里面可以输入的路径和文件名  单机按钮可以读取在 指定的文件  并把文件内容显示到一个文本域里面来 代码: /** * */ package com.niit.homewo ...