前端的国际化是一个比较普遍的需求。但是这方面网上直接可用的解决方案并不多。最近做了一个基于Vue.js多语言实现的版本,这里简单总结一下。1、通常需要处理哪些内容一般来说,在一个web应用中,需要在多语言之间切换的内容一般包括以下几个方面:1、模板中的内容,比如Vue.js的标签Content2.JS代码中的文本内容3.复制图片中的内容4.页面标题5.复制第三方组件中的文本(比如我的项目中使用了Vux组件)6.后台end界面需要在前端显示7.后端界面返回的错误信息2.基本思路1.首先需要确定如何获取此时应该显示的语言。我在URL中使用?lang=en或?lang=zh-CN这样的形式传递参数。这样做的好处是您可以通过链接指定使用哪种语言。但是,仅依靠地址栏参数也不方便。比如页面跳转时,地址栏参数可能丢失。这会导致你在页面跳转后不知道用什么语言来显示。理想的方式应该是在进入某个页面的时候就包含这个参数(这时候就可以获取使用的语言),然后跳转到其他页面的时候就不需要带这个lang参数了。因为此时你已经知道使用哪种语言了。所以这个参数应该在你进入第一个页面的时候就保存起来,比如在localstorage中,在vuex的state中。这里,就引出了语言判断的优先级问题。因为地址栏中可能有lang参数,localstorage中可能有相关存储字段(因为上次访问过应用),可能还想设置默认降级语言等等。它的优先级应该如何处理?正确的优先级应该是:首先检查地址栏中是否有参数;然后检查localstorage中是否有;然后通过navigator.language获取浏览器的默认语言,看看是不是你应用支持的语言,如果是,就用最后一个;最后使用备用语言(例如,更通用的英语)。当然,你可以根据自己的需要做一些简化。2、其次,用什么工具来解决语言转换和打包的问题?(1)i18n相关工具的选择——多语言转换功能谁来提供(一般是$t)?目前通用的国际化方式大部分都是基于i18n的,我们不用造轮子了。但是对于i18n的具体使用,有很多不同的NPM模块。比如vuex-i18n、vue-i18n、simplest-i18n等。因为大多数复杂的项目都会用到vuex,所以对于复杂的项目选择vuex-i18n比vue-i18n更方便。最简单的-i18n,一个很小的模块,其实也有它的好处。支持如下写法:模板中:$t('realname','RealName')或者JS中:this.$t('realname','RealName')即将语言写在一起,$t函数的每个参数都是一种语言,一目了然,也比较容易阅读。对于小型项目,这是一种选择。它的基本用法如下:t.js文件:importi18nfrom'simplest-i18n';importgetLangfrom'../../getLang';constt=i18n({locale:getLang.lang,//当前语言locales:getLang.langs//支持的语言列表});导出默认值;然后在应用的入口文件中扩展Vue.js:importtfrom'./t';Vue.$t=Vue.prototype.$t=t;该方法被挂载到Vue.js的全局。也可以在Vue实例中通过this.$t来访问,使用起来非常简单。但是对于大型项目来说,在代码中编写语言包对维护来说并不友好。而且也解决不了我用的Vux组件多语言化的问题。所以最终,我选择了vuex-i18n作为基础。(2)语言包整理处理工具——如何整理语言包?对于这个问题,我首先需要解决Vux第三方组件的多语言化问题。首先,在语言包的组织上,比较常见的是写成JSON配置文件。不过我最终还是使用了Yaml格式,支持多语言字段一起写。例如:config.ymlconfirm:zh-CN:confirmen:confirm而不是像下面这样把一个字段的多语言拆分到几个地方,例如:confirm:confirmconfirm:confirm这样做的好处是可以方便的比较一个不同语言版本的字段,当你想修改或删除某个字段时,也可以在一处完成,无需切换。而且Yaml文件的语法也更加简洁明了,省去了在JSON文件中写双引号,也不能出现注释。其次,在语言包打包方面,我找到了vux-loader。可以结合已有的webpack配置,不仅可以完成Vux组件的多语言配置打包,还允许在自定义Vue组件中使用标签。比如在自定义组件中,我可以这样写:confirm:zh-CN:confirmen:confirm打包的时候,vux-loader会把标签中的多语言配置信息导出到我们的config中一个yaml文件,并从我们的自定义组件中删除标签。那么,如何处理Yaml文件呢?您可以使用json-loader和yaml-loader。他们可以将Yaml文件转换成我们需要的json格式,方便在JS函数中使用,像这样:constcomponentsLocales=require('json-loader!yaml-loader!../../locales/components.yml');//这是一个语言包的json格式。3、如何通知后台接口返回哪种语言的数据?因为涉及到很多接口来通知后端使用哪种语言,所以我选择使用header标头。在axios的拦截器中,headerheader:Accept-Language被统一添加到请求中,这个值的内容设置为前端应该使用的语言(比如zh-CN或者en等)。这样一来,问题就在一处解决了。三、具体实践中的一些细节1、获取当前应该使用哪种语言的getLang模块的实现import{getQueryObj}from'../utils/url';import{setItem,getItem}from'../utils/storage';constlangs=['zh-CN','en'];//支持哪些语言constdefaultLang='en';//默认语言,不抛出函数getLang(){letqueries=getQueryObj();letstoreLang=getItem('lang');letrawLang;letflag=false;if(queries&&queries['lang']){rawLang=queries['lang'];setItem('lang',rawLang);}else{rawLang=storeLang||导航器.language;}langs.map(item=>{if(item===rawLang){flag=true;}});returnflag?rawLang:defaultLang;}constlang=getLang(langs,defaultLang);exportdefault{lang,//获取当前语言langs//支持的语言列表}2、Vux组件多语言包的配置可以在Vux官方github的src/locales/all.yml中找到,复制(src/locales/同目录下的zh-CN.yml、src/locales/en.yml是它的中文部分和English部分),大家可以根据自己的需要稍作修改。然后在你的应用的入口文件中引入:constvuxLocales=require('json-loader!yaml-loader!../../locales/all.yml');3.vux-loader配置webpack.dev.conf.js:resolve(vuxLoader.merge(devWebpackConfig,{plugins_dir:['vux-ui',{name:'i18n',vuxStaticReplace:false,staticReplace:false,extractToFiles:'src/locales/components.yml',localeList:['en','zh-CN']}]}))在webpack.prod.conf.js中:resolve(vuxLoader.merge(buildWebpackConfig,{plugins_dir:['vux-ui',{name:'i18n',vuxStaticReplace:false,staticReplace:false,extractToFiles:'src/locales/components.yml',localeList:['en','zh-CN']}]}))其中localeList:['en','zh-CN']就是指定你的应用支持哪些语言。而extractToFiles:'src/locales/components.yml'就是指定你的自定义组件中使用的标签中的语言包信息应该导出到哪个Yaml文件中。也就是说,你在每个自定义组件中使用的标签中的语言包信息,都会被vux-loader集中提取到这个文件中。然后在应用的入口文件中引入这个语言包文件:constcomponentsLocales=require('json-loader!yaml-loader!../../locales/components.yml');4.自定义组件内外多语言文案(1)自定义组件内部文案的多语言信息,写在组件的标签中。同时,为了避免不同自定义组件中多语言字段的命名冲突,在每个字段名称前添加组件名称样式前缀。(2)对于页面的标题,一些错误信息等文案,它们出现在组件外部,所以不适合写在组件的标签中,所以我们单独创建一个global.yml来存放这些全球性的多语言信息。这些内容可以直接写在global.yml中,为了和表面上的其他语言包字段冲突,我们在每个字段前加了一个global-前缀。然后在应用的入口文件中引入这个语言包文件:constcomponentsLocales=require('json-loader!yaml-loader!../../locales/global.yml');5、vuex-i18n的实现是在src/store/index.js文件中:importVuexI18nfrom'vuex-i18n';exportdefaultnewVuex.Storeadded:i18n:VuexI18n.store应用的入口文件中:importVuexI18nfrom'vuex-i18n';importgetLangfrom'../../getLang';Vue.use(VuexI18n.plugin,store);constvuxLocales=require('json-loader!yaml-loader!../../locales/all.yml');constcomponentsLocales=require('json-loader!yaml-loader!../../locales/components.yml');constfinalLocales={'en':Object.assign(vuxLocales['en'],componentsLocales['en']),'zh-CN':Object.assign(vuxLocales['zh-CN'],componentsLocales['zh-CN'])}for(letiinfinalLocales){Vue.i18n.add(i,finalLocales[i])}Vue.i18n.set(globalVars.lang);6、图片的多语言化对于图片中的文案信息,多语言化的方式主要有两种:一是根据不同的语言显示不同的图片;另一种是尽可能将文字与图片背景分开,采用文字层加背景图片层,使文字层可以当普通文字使用,实现多语言化。它们比较简单,这里不再赘述。7、通过当前页面的按钮切换当前语言后如何更新当前页面的内容?如果你的应用不需要在页面内部切换语言版本,直接在URL中传入不同的lang参数即可,不涉及这个问题。第一种方式:刷新页面changeLang(lang){location.href=this.$utils.url.replaceParam(this.$router.history.current.path,'lang',lang);},方法二:观察数据中lang字段的变化当前页面,通过v-if刷新部分相关组件:data(){return{lang:this.$i18n.locale()}}changeLang(lang){this.$i18n.set(lang);this.lang=这个。$i18n.locale();},watch:{lang(newVal,oldVal){if(newVal===oldVal){return;}//这里通过改变某个flag并结合v-if重新触发一个local组件的渲染}}第三种方式:结合vuex分发全局语言状态,接收状态变化时更新,或者干脆自己重写vuex-i18n的实现。这种方法比较复杂。根据您的业务需求进行选择。8、Yaml中特殊字符的转义一些包含特殊字符的yamlkey值,比如[,]]等,需要进行转义。转的方法是给key值加上单引号。如果你的语言包信息中有单引号,必须用两个连续的单引号转义。例如:str:'labor''sday'