
在项目有语言国际化需求的时候,我们通常会选择相应的库,比如使用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项目中
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import Store from '@/store'
import messages from './messages/en' //默认语言
Vue.use(VueI18n)
new Vue({
router,
i18n,
vuetify,
store,
render: (h) => h(App)
}).$mount('#app')
这样注入到Vue对象中,我们就可以这样更改语言了,通过
i18n.locale=lang 去更改你需要的语言,就可以自动获取相应的语言了,在模版中使用$t('hello')来翻译。
vue-i18n更多使用姿势看这里:kazupon.github.io/vuei18n/int…
我就不过多讲解了,我主要说一下与UI框架的同步、异步加载和默认语言处理问题。
这里为了更好的性能,默认只加载一种语言,因为当语言过多时,全部加载存在性能问题,所以采取了异步加载语言模版的方案。
在i18n文件下,新建index.ts入口文件。
异步加载代码如下:
/**
* @functin setLang - 设置应用语言
* @param {string} lang - 要设置语言的名称
* @return {string} lang - 语言名称
*/
function _set(lang: string): string {
i18n.locale = lang
// i18n.fallbackLocale = lang
Axios.defaults.headers.common['Accept-Language'] = lang
Store.__s('app.language', lang)
return lang
}
/**
* @functin loadLangAsync - 异步加载语言模版
* @param {string} lang - 需要加载的语言名称
* @return {string} lang - 加载好的语言名称
*/
export function setLang(lang: string): Promise<string> {
if (__LOCALE__ !== __LANGS__) { // ___LOCALE__ 是本地已经加载好的语言模版数组
if (!__LANGS__.includes(lang)) { // 本地没有,则加载
return import(/* webpackChunkName: "lang-[request]" */ `@/i18n/messages/${lang}`).then(msgs => {
i18n.setLocaleMessage(lang, msgs.default[lang])
__LANGS__.push(lang)
return _set(lang)
})
}
return Promise.resolve(_set(lang))
}
return Promise.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 保持一致
*/
export const TranslateTable: 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/
*/
const localList = ['zhHans', 'en', 'ko', 'zhHant', 'ja'] //加载自己需要的语言
// webpack的api,自动模块化加载
const files = require.context('vuetify/lib/locale/', true, /\.js$/)
const locales: Array<any> = []
files.keys().forEach(key => {
const languageName = 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
*/
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import Axios from 'axios'
import Store from '@/store'
import messages from './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__)
}
const i18n = new VueI18n({
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 = lang
Axios.defaults.headers.common['Accept-Language'] = lang
Store.__s('app.language', lang)
return lang
}
/**
* @functin loadLangAsync - load language asynchronous
* @param {string} lang - the language will be loading
* @return {string} lang - loaded language name
*/
export function setLang(lang: string): Promise<string> {
if (__LOCALE__ !== __LANGS__) {
if (!__LANGS__.includes(lang)) {
return import(/* webpackChunkName: "lang-[request]" */ `@/i18n/messages/${lang}`).then(msgs => {
i18n.setLocaleMessage(lang, msgs.default[lang])
__LANGS__.push(lang)
return _set(lang)
})
}
return Promise.resolve(_set(lang))
}
return Promise.resolve(lang)
}
setLang(__LOCALE__) // initialization
export default i18n
如果需要源码的话,请关注wx公众号「前端攻城之路」,回复“语言国际化”,将自动获取到源码链接。
支持
如果这篇文章对你有帮助或者有启发的话,我想请你关注我,让我们一起在前端攻城路上进阶。