首先,我们先来介绍一下,什么是语言国际化。i18n(其来源是英文单词 internationalization的首末字符i和n,18为中间的字符数)是“国际化”的简称。在资讯领域,国际化(i18n)指让网站无需做大的改变就能够适应不同的语言和地区的需要。对程序来说,在不修改内部代码的情况下,能根据不同语言及地区显示相应的界面。简单来说,就是你的网站可以有多种语言。
在项目有语言国际化需求的时候,我们通常会选择相应的库,比如使用Vue框架时,我们会选择vue-i18n,当我们使react时,我们也许会使用react-int等,但在具体实践中,往往只是会用这个库还不行,你还得解决如何同步UI框架的组件语言国际化,以及如何处理从浏览器获取默认语言同步问题。总的来说,要充分考虑到这三个环境的语言问题。
现在我就以在Vue项目下,使用vue-i18n整个框架,并且同步更改UI框架Vuetify的组件语言国际化来作为例子,一步一步实现整个项目的语言国际化。
安装
npm
npm install --save vue-i18n@next
yarn
yarn add vue-i18n@next
1.1 定义好语言模版
安装好这个库之后,我们可以先在src目录下新建一个i18n文件夹,然后在messages文件夹下面定义好语言模版(名称没有硬性要求,后面会说到命名方案),如图所示:
1.2 然后,将Vue-i18n引入到Vue项目中
importVuefrom'vue'importVueI18nfrom'vue-i18n'importStorefrom'@/store'importmessagesfrom'./messages/en'//默认语言 Vue.use(VueI18n)newVue({ router, i18n, vuetify, store,render:(h) =>h(App)}).$mount('#app')
这样注入到Vue对象中,我们就可以这样更改语言了,通过
i18n.locale=lang 去更改你需要的语言,就可以自动获取相应的语言了,在模版中使用$t('hello')来翻译。
vue-i18n更多使用姿势看这里:http://kazupon.github.io/vuei18n/introduction.html#sponsors
我就不过多讲解了,我主要说一下与UI框架的同步、异步加载和默认语言处理问题。
这里为了更好的性能,默认只加载一种语言,因为当语言过多时,全部加载存在性能问题,所以采取了异步加载语言模版的方案。
在i18n文件下,新建index.ts入口文件。
异步加载代码如下:
/**
* @functin setLang - 设置应用语言
* @param {string} lang - 要设置语言的名称
* @return {string} lang - 语言名称
*/function_set(lang: string):string{ i18n.locale = lang// i18n.fallbackLocale = langAxios.defaults.headers.common['Accept-Language'] = lang Store.__s('app.language', lang)returnlang}/**
* @functin loadLangAsync - 异步加载语言模版
* @param {string} lang - 需要加载的语言名称
* @return {string} lang - 加载好的语言名称
*/exportfunctionsetLang(lang: string):Promise{if(__LOCALE__ !== __LANGS__) {// ___LOCALE__ 是本地已经加载好的语言模版数组if(!__LANGS__.includes(lang)) {// 本地没有,则加载returnimport(/* webpackChunkName: "lang-[request]" */`@/i18n/messages/${lang}`).then(msgs=>{ i18n.setLocaleMessage(lang, msgs.default[lang]) __LANGS__.push(lang)return_set(lang) }) }returnPromise.resolve(_set(lang)) }returnPromise.resolve(lang)}
1.3 持久化和默认语言问题
const__LANGS__ = ['enUS']// 默认语言let__LOCALE__ = Store.state.app.language// 获取本地存储的语言// 首次加载没有存储的语言,则默认使用浏览器的语言if(!__LOCALE__) { __LOCALE__ =window.navigator.language.split('-').join('') Store.commit('SETLANG', __LOCALE__)}
设置好语言应该添加到vuex的store里面,并且同步到localstorage,做好语言持久化处理。
这时候,异步加载和默认语言处理问题已经解决好了,现在我们再来说同步Vuetify组件国际化问题。
1.4 同步UI组件国际化
不同UI框架都有自己的组件国际化API,vuetify提供的是
this.$vuetify.lang.current = lang
因此,我们只要调用vue-i18n的setLang方法时,同步调用这个方法就好了。
lang() { setLang(this.d_language)this.setVuetifyLang(this.d_language) }
这时,又有一个命名的问题,我们的vue-i18n这个插件可以自己命名语言模版名,但是vuetify的语言名已经命名好了,无法更改的,如下:
因此,这里需要我们的模版名称应该和这里的命名一致,如简体中文的模版名应该为zhHans,但是我们默认语言处理是以浏览器的语言来处理的,浏览器的语言名使用SO 639-1标准 为各种语言定义了缩略词,就是以一种简称代替某种语言,如英文用en,中文用zh,部分列表如下:
因为名称不一致,为了统一命名,我们还应该添加一个翻译表,以浏览器的语言为标准,建立语言模版名,并且将与vutify组件不一致的名称翻译过来,如浏览器的enUS对应vuetify的en,部分翻译如下:
/**
* 使 I18n and vuetify 保持一致
*/exportconstTranslateTable: TranslateItem = {enUS:'en',zhCN:'zhHans',zhTW:'zhHant',ja:'ja',ko:'ko'}
当然,vuetify的模版语言可以使可以按需加载的
/**
* the vuetify-i18n language list
* see more : https://vuetifyjs.com/en/customization/internationalization/
*/constlocalList = ['zhHans','en','ko','zhHant','ja']//加载自己需要的语言// webpack的api,自动模块化加载constfiles =require.context('vuetify/lib/locale/',true, /\.js$/)constlocales:Array = []files.keys().forEach(key=>{constlanguageName = key .replace('./','') .replace('.js','') .replace('-','')if(localList.includes(languageName)) { locales.push({ [languageName]: files(key).default }) }})
Tips:这里有个小技巧,当默认语言为英语时,我们可以在默认不添加翻译,如this.$t("hello"),当没有对应翻译时,会翻译成hello,这样是不是很方便呢?
所以我的项目中,都是以英文作为翻译的key,就不用添加英文的翻译了,懒人必备。
至此,我们就完成所有的语言国际化工作了,是不是很简单呢?
赶快Get吧,10分钟就可以轻松入门。
完整的封装如下:
/**
* vue-i18n
* see more : https://kazupon.github.io/vue-i18n/zh/guide/lazy-loading.html
*/importVuefrom'vue'importVueI18nfrom'vue-i18n'importAxiosfrom'axios'importStorefrom'@/store'importmessagesfrom'./messages/en'Vue.use(VueI18n)const__LANGS__ = ['enUS']let__LOCALE__ = Store.__s('app.language')if(!__LOCALE__) { __LOCALE__ =window.navigator.language.split('-').join('') Store.__s('app.language', __LOCALE__)}consti18n =newVueI18n({locale: __LOCALE__,fallbackLocale:'enUS',silentTranslationWarn:false, messages})/**
* @functin setLang - set the app's language
* @param {string} lang - the language will be setted
* @return {string} lang - langguage name
*/function_set(lang: string):string{ i18n.locale = lang// i18n.fallbackLocale = langAxios.defaults.headers.common['Accept-Language'] = lang Store.__s('app.language', lang)returnlang}/**
* @functin loadLangAsync - load language asynchronous
* @param {string} lang - the language will be loading
* @return {string} lang - loaded language name
*/exportfunctionsetLang(lang: string):Promise{if(__LOCALE__ !== __LANGS__) {if(!__LANGS__.includes(lang)) {returnimport(/* webpackChunkName: "lang-[request]" */`@/i18n/messages/${lang}`).then(msgs=>{ i18n.setLocaleMessage(lang, msgs.default[lang]) __LANGS__.push(lang)return_set(lang) }) }returnPromise.resolve(_set(lang)) }returnPromise.resolve(lang)}setLang(__LOCALE__)// initializationexportdefaulti18n
如果需要源码的话,请关注wx公众号「前端攻城之路」,回复“语言国际化”,将自动获取到源码链接。
支持
如果这篇文章对你有帮助或者有启发的话,我想请你关注我,让我们一起在前端攻城路上进阶。