什么是国际化?internationalization对应的英文单词是Internationalization,也叫i18n:i是单词的[first]字母,18是单词的个数[betweeniandn]n代表单词的[last]字母如果你的项目如果是Vue,那么相信大家在实现国际化功能的时候,肯定也用到了vue-i18n这个库。接下来,本文也将这个库与Vue一起使用,实现了最基本的国际化功能,但重点不是如何使用这个库,而是思考实现过程中可以优化的点。实现基本的国际化功能,不再需要演示demo工程的创建过程,本文只演示最基本的中英文切换,现在就直奔核心吧!集成vue-i18n安装依赖熟悉的命令:npminstallvue-i18n-S配置vue-i18n在src目录下创建language目录,存放语言切换相关内容在language目录下创建lang目录,保存不同语言的文件映射关系,比如中文对应zh.js,英文对应en.js等。在language目录下创建index.js作为默认导出,并创建一个i18n对象import{createI18n}from"vue-i18n";从'./lang/zh';从'./lang/en'导入en;consti18n=createI18n({legacy:false,locale:"zh",//初始化配置语言消息:{zh,en,},});exportdefaulti18n;main.js注册i18n内容很简单,直接上传代码:import{createApp}from"vue";importi18nfrom"./language";importstorefrom"./store";importApp来自"./App.vue";createApp(App).use(store).use(i18n).mount("#app");其实在传递use(i18n)的时候,会调用i18n.install()方法,大致内容如下:通过app.provide(app.__VUE_I18N_SYMBOL__,i18n)为应用中的所有后代组件提供i18n对象并通过app.config.globalProperties.xxx=xxx=xxx通过inject注入将全局属性/方法添加到应用程序中,实际上以上是Vue2中Vue.prototype使用的通用全局属性的替代,比如$i18n通过app.config.globalProperties.$i18n=i18n添加到全局通用全局方法,比如:$t,$rt,$d,$n,$tm通过Object.defineProperty(app.config.globalProperties,`$${method}`,desc)注册常用的全局指令v-t和全局组件i18n通过aplly(...)根方法在卸载组件时删除/释放i18n相关内容constunmountApp=app.unmount;app.unmount=()=>{i18n.dispose();卸载应用程序();};注册vue-devtools相关插件,填写国际化数据信息假设内容页渲染需要渲染如下数据对应的列表,实现国际化:constdata=[{url:vueImg,title:'Vue',describe:'ProgressiveJavaScriptframework'},{url:reactImg,title:'React',describe:'一个用于构建用户界面的JavaScript库'},{url:angularImg,title:'Angular',describe:'一个现代网络开发平台'},{url:nodeImg,title:'Node',describe:'Node.js是一个基于ChromeV8引擎的JavaScript运行时'},{url:webpackImg,title:'Webpack',describe:'webpack是现代JavaScript应用程序的静态模块打包器'},];对应的App.vue组件模板内容如下:{{$t("Chinese/English")}}</button>对应的页面效果如下:在lang/zh.js文件中lang目录下填写映射关系:exportdefault{"ProgressiveJavaScriptframework":"ProgressiveJavaScriptFrameworks","JavaScriptLibrariesforBuildingUserInterfaces":"JavaScriptLibrariesforBuildingUserInterfaces","ModernWebDevelopmentPlatforms":"ModernWebDevelopmentPlatforms","Node.jsisachrome-basedAJavaScriptruntimefortheV8engine》:《Node.jsisaJavaScriptruntimebasedonChrome'sV8engine》,《webpackisastaticmodulebundlerformodernJavaScriptapplications》:《webpackisaJavaScriptruntimeformodernJavaScriptapplicationsStaticmodulepackaging》toolfortheprogram","Chinese/English":"Chinese/English",};在lang/zh.js文件中:exportdefault{"ProgressiveJavaScriptframework":"ProgressiveJavaScriptframework","forAJavaScriptlibraryforbuildinguserinterfaces":"JavaScriptlibraryforbuildinguserinterface","Modernwebdevelopmentplatform":《现代Web开发平台》,《Node.js是一个基于ChromeV8引擎的JavaScript运行时》:《Node.js是一个JavaScript运行时基础edonthechromeV8engine","webpackisastaticmodulepackagingtoolformodernJavaScriptapplications":"WebpackisastaticmodulepackagingtoolformodernJavaScriptapplications","中/英":"Chinese/English",};
组件中的翻译处理翻译处理可以通过以下方式处理:使用$t(...)方法,使用v-t命令,使用组件这里选择第一个,因为比较灵活,适用范围更广,指令和组件的形式仅限于模板:效果演示优化i18n配置基于上面简单的例子,已经实现了国际化切换功能实现了,但是还有一些需要考虑的地方还有很多优化点,下面的内容只是随便乱扔,不一定全面优化翻译文件中的key现在可以明显看出zh.js和en.js文件中用于映射的key过长,导致整个文件看起来杂乱无章,所以我们可以将对应的key进行简化,如下://zh.jsexportdefault{"IntroductiontoVue":"AprogressiveJavaScriptframework","IntroductiontoReact":"AJavaScriptlibraryforbuildinguserinterfaces","IntroductiontoAngular":"Amodernwebdevelopmentplatform》,《Node简介》:《Node.js是一个基于ChromeV8引擎的JavaScript运行时》,《Webpack简介》:《webpack是现代JavaScript应用的静态模块打包工具》,《中文/英文》:"Chinese/English",};//en.jsexportdefault{"Vue简介":"渐进式JavaScript框架","React简介":"用于构建用户界面的JavaScript库","Angular简介":"现代Web开发平台》、《Node入门》:《Node.js是基于chromeV8引擎的JavaScript运行时》、《Webpack入门》:《Webpack是现代JavaScript应用的静态模块打包工具》、《中文/英语”:”Chinese/English",};那么对应需要渲染的外部数据源数据可以简写为:constdata=[{url:vueImg,title:"Vue",describe:"VueIntroduction",},{url:reactImg,title:"React",describe:"React简介",},{url:angularImg,title:"Angular",describe:"Angular简介",},{url:nodeImg,title:"Node",describe:"Node介绍",},{url:webpackImg,title:"Webpack",describe:"Webpack介绍",},];另一种精简的方式是用类似于variable的对应方式定义key命名,但我个人不是很喜欢这种方式,首先很难从语义上直接读懂相关信息,很难用一两个英文单词来概括文本内容,难度极大去排查对应的问题,后期定位tmeplate,不方便,把翻译文件类型从.js转成.json,上面的翻译文件是.js文件。所以,为了让它能够被其他文件导入,我们不得不在文件中使用exportdefualt或者export来导出对应的文件内容,但实际上我们可以将.js文件转为.json文件直接使用,如下:excel转.json实际项目中翻译的内容通常是由业务专门找的相应翻译器提供的,但它是开发人员手中往往是excel类型的表格文件。如果我们使用之前的纯json方式,那么我们必然要将表格中的相应内容,一张一张复制到我们对应的.json文件中,分别填充到zh.json和en中。.json,值得注意的是现在是只支持两个国家的语言或者说,如果以后要支持的国家多了,是不是就不用手动复制了?所以最好的办法就是我们根据业务方提供的表格自动将数据转换成json格式,避免不必要的手动操作,使用命令帮助我们处理这个内容:安装依赖npminstallxlsx-to-json将对应的转换操作封装在excel2json.js文件中,基于第三方库constxlsx2json=require("xlsx-to-json");简单封装即可constpath=require("path");xlsx2json({输入:path.join(__dirname,"./i18n.xlsx"),output:path.join(__dirname,"./i18n.json"),},函数(err,result){if(err){console.error(err);}else{console.log(result);}});修改i18n配置入口文件src\language\index.jsimport{createI18n}from"vue-i18n";从“./i18n.json”导入i18njson;//动态获取消息信息functiongetMessage(){constmessages={zh:{},en:{}};i18njson.forEach(({Short,Chinese,English})=>{messages.zh[Short]=Chinese;messages.en[Short]=English;});回复消息;}consti18n=createI18n({legacy:false,locale:"zh",//初始化配置语言消息:getMessage(),});导出默认i18n;提供i18n.xlsx文件作为数据源,在package.json文件中添加对应的转换命令"scripts":{"dev":"vite","build":"vitebuild","preview":"vitepreview","i18n":"node./src/language/excel2json.js"}具体效果如下:升级到i18n系统后,对应的翻译包已经由*.xlsx转换为*.json,即可以在一定程度上减少重复劳动,但在复用/协作方面并不理想。因此,可以将整个内容从更高维度升级到i18n系统,并提供相应的翻译包上传、自动解析、去重等功能,添加命名空间等功能,加上相应的列表管理功能,重点是让多人多系统复用/协作。对于前端,可以通过接口获取对应的翻译包数据,也可以减少前端最终构建产品的体积处理翻译文件中的重复内容什么是重复内容?其实很简单。比如有一个文本内容是一个确认按钮。在A页面需要翻译成Confirm,在B页面需要翻译成OK,其中文内容为confirmation,也就是说其对应的数据内容为:[{"Short":"Confirm","Chinese":"Confirm","English":"Confirm"},{"Short":"Confirm","Chinese":"Confirm","English":"OK"}]但是这个其实是不行的,而且最终会被下面的内容覆盖,也就是A页和B页的最终翻译内容都OK,因为数据中的Short其实是不同语言映射的最终key,如下:constmessages={zh:{"Confirm":"Confirm","Confirm":"Confirm"},en:{"Confirm":"Confirm","Confirm":"OK"}};这种情况下,我们只需要为不同的翻译设置不同的Short值即可,如下:[{"Short":"Confirm1","Chinese":"Confirm","English":"Confirm"},{"Short":"Confirm2","Chinese":"Confirm","English":"OK"}]这个改动很小,没有丢失原来的语义。考虑不同语言的风格因为不同的语言有不同的表达方式和内容长度,所以在前端展示的时候,必须要考虑最后显式的问题,否则一旦语言环境切换,页面的布局就会肯定出现。处理问题的方法只有几种:允许文本内容换行显示。当文本被换行时,需要设置CSS设置将单词换行为一个完整的单词。如果不让行,需要控制固定宽度,显示多余部分,移动鼠标显示全部内容等。针对不同语言环境分别设置样式,根据显示要求。如果需要考虑文本在不同语言环境下的对齐方式、文本间距等。对于难以处理的翻译内容,可以与业务沟通,看看是否可以更换翻译内容,减少文本长度等考虑后端界面语言环境的变化。一个项目的国际化不是靠前端就能实现的。接口动态返回的一些内容也需要后端处理。通常,接口的请求头中会存储一个ID,用于标识。当前页面locale的字段,然后判断返回给前端页面的具体内容。基于前面处理的国化切换功能,翻译内容会根据vue的响应性进行切换,即页面不会刷新。因此,切换对应的翻译内容后,后续的接口请求头中的语言环境也需要修改。但这仍然存在问题。已经通过接口返回的数据内容此时无法切换到对应的翻译内容,因为目前国际化切换是基于页面变化,但是基于接口变化的部分还没有重新请求获取新的那些。内容,如何处理?前端切换语言环境后,再次刷新页面,让界面也能重新获取新的内容。后台返回数据时,会返回不同语言环境对应的翻译内容。前端根据语言环境决定如何渲染所有的翻译内容。全部由前端管理,一开始就初始化各个语言环境对应的翻译内容。最后,以上内容是基于对国际化功能的一点思考。所有的项目,当然也期待评论区有更多更好的解决方案。本文参加了SegmentFault思维写作挑战赛,欢迎正在阅读的你加入。