专栏名称: 前端大全
分享 Web 前端相关的技术文章、工具资源、精选课程、热点资讯
目录
相关文章推荐
前端早读课  ·  【早阅】如何使用Vike和Vite构建可扩展 ... ·  昨天  
前端大全  ·  20个超好看的落地页/首页模板(附源码) ·  3 天前  
前端早读课  ·  【早阅】会话令牌和JWT结合的优势 ·  4 天前  
前端早读课  ·  【早阅】Shoelace:与任何框架兼容的W ... ·  1 周前  
51好读  ›  专栏  ›  前端大全

前端国际化解决方案“填坑日记”

前端大全  · 公众号  · 前端  · 2017-10-31 08:30

正文

(点击上方公众号,可快速关注)


来源:懒得安分 

http://www.cnblogs.com/landeanfen/p/7581609.html

如果好文章投稿,点击 → 了解详情


前言:最近,新的平台还没有开发完成,原来的老项目又提出了新的需求:系统国际化。如果是前后端完全分离的开发模式,要做国际化,真的太简单了,有现成的解决方案,基于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这种方案,既然大家都这么选型,那博主也按照这种思路去做好了。


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


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


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


1、需要引用的js文件


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



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


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页面的使用




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


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


对于第三方组件,我们自定义的代码里面的中文要做国际化,我只需要使用$.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 = $('