首先,我們先來介紹一下右锨,什么是語言國際化辫封。i18n(其來源是英文單詞 internationalization的首末字符i和n厉熟,18為中間的字符數(shù))是“國際化”的簡稱息拜。在資訊領(lǐng)域溉潭,國際化(i18n)指讓網(wǎng)站無需做大的改變就能夠適應(yīng)不同的語言和地區(qū)的需要。對程序來說该溯,在不修改內(nèi)部代碼的情況下岛抄,能根據(jù)不同語言及地區(qū)顯示相應(yīng)的界面。簡單來說狈茉,就是你的網(wǎng)站可以有多種語言夫椭。
在項(xiàng)目有語言國際化需求的時(shí)候,我們通常會(huì)選擇相應(yīng)的庫氯庆,比如使用Vue框架時(shí)蹭秋,我們會(huì)選擇vue-i18n,當(dāng)我們使react時(shí),我們也許會(huì)使用react-int等堤撵,但在具體實(shí)踐中仁讨,往往只是會(huì)用這個(gè)庫還不行,你還得解決如何同步UI框架的組件語言國際化实昨,以及如何處理從瀏覽器獲取默認(rèn)語言同步問題洞豁。總的來說,要充分考慮到這三個(gè)環(huán)境的語言問題丈挟。
現(xiàn)在我就以在Vue項(xiàng)目下刁卜,使用vue-i18n整個(gè)框架,并且同步更改UI框架Vuetify的組件語言國際化來作為例子曙咽,一步一步實(shí)現(xiàn)整個(gè)項(xiàng)目的語言國際化蛔趴。
安裝
npm
npm install --save vue-i18n@next
yarn
yarn add vue-i18n@next
1.1 定義好語言模版
安裝好這個(gè)庫之后,我們可以先在src目錄下新建一個(gè)i18n文件夾例朱,然后在messages文件夾下面定義好語言模版(名稱沒有硬性要求孝情,后面會(huì)說到命名方案),如圖所示:
1.2 然后洒嗤,將Vue-i18n引入到Vue項(xiàng)目中
importVuefrom'vue'importVueI18nfrom'vue-i18n'importStorefrom'@/store'importmessagesfrom'./messages/en'//默認(rèn)語言 Vue.use(VueI18n)newVue({? router,? i18n,? vuetify,? store,render:(h) =>h(App)}).$mount('#app')
這樣注入到Vue對象中箫荡,我們就可以這樣更改語言了,通過
i18n.locale=lang 去更改你需要的語言烁竭,就可以自動(dòng)獲取相應(yīng)的語言了菲茬,在模版中使用$t('hello')來翻譯。
vue-i18n更多使用姿勢看這里:http://kazupon.github.io/vuei18n/introduction.html#sponsors
我就不過多講解了派撕,我主要說一下與UI框架的同步婉弹、異步加載和默認(rèn)語言處理問題。
這里為了更好的性能终吼,默認(rèn)只加載一種語言镀赌,因?yàn)楫?dāng)語言過多時(shí),全部加載存在性能問題际跪,所以采取了異步加載語言模版的方案商佛。
在i18n文件下,新建index.ts入口文件姆打。
異步加載代碼如下:
/**
* @functin setLang - 設(shè)置應(yīng)用語言
* @param {string} lang - 要設(shè)置語言的名稱
* @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__? 是本地已經(jīng)加載好的語言模版數(shù)組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 持久化和默認(rèn)語言問題
const__LANGS__ = ['enUS']// 默認(rèn)語言let__LOCALE__ = Store.state.app.language// 獲取本地存儲(chǔ)的語言// 首次加載沒有存儲(chǔ)的語言,則默認(rèn)使用瀏覽器的語言if(!__LOCALE__) {? __LOCALE__ =window.navigator.language.split('-').join('')? Store.commit('SETLANG', __LOCALE__)}
設(shè)置好語言應(yīng)該添加到vuex的store里面幔戏,并且同步到localstorage玛追,做好語言持久化處理。
這時(shí)候闲延,異步加載和默認(rèn)語言處理問題已經(jīng)解決好了痊剖,現(xiàn)在我們再來說同步Vuetify組件國際化問題。
1.4 同步UI組件國際化
不同UI框架都有自己的組件國際化API垒玲,vuetify提供的是
this.$vuetify.lang.current = lang
因此陆馁,我們只要調(diào)用vue-i18n的setLang方法時(shí),同步調(diào)用這個(gè)方法就好了合愈。
lang() {? ? ? setLang(this.d_language)this.setVuetifyLang(this.d_language) }
這時(shí)叮贩,又有一個(gè)命名的問題击狮,我們的vue-i18n這個(gè)插件可以自己命名語言模版名,但是vuetify的語言名已經(jīng)命名好了妇汗,無法更改的帘不,如下:
因此,這里需要我們的模版名稱應(yīng)該和這里的命名一致杨箭,如簡體中文的模版名應(yīng)該為zhHans,但是我們默認(rèn)語言處理是以瀏覽器的語言來處理的储狭,瀏覽器的語言名使用SO 639-1標(biāo)準(zhǔn) 為各種語言定義了縮略詞互婿,就是以一種簡稱代替某種語言,如英文用en辽狈,中文用zh慈参,部分列表如下:
因?yàn)槊Q不一致,為了統(tǒng)一命名刮萌,我們還應(yīng)該添加一個(gè)翻譯表驮配,以瀏覽器的語言為標(biāo)準(zhǔn),建立語言模版名着茸,并且將與vutify組件不一致的名稱翻譯過來壮锻,如瀏覽器的enUS對應(yīng)vuetify的en,部分翻譯如下:
/**
*? 使 I18n and vuetify 保持一致
*/exportconstTranslateTable: TranslateItem = {enUS:'en',zhCN:'zhHans',zhTW:'zhHant',ja:'ja',ko:'ko'}
當(dāng)然涮阔,vuetify的模版語言可以使可以按需加載的
/**
* the vuetify-i18n language list
* see more :? https://vuetifyjs.com/en/customization/internationalization/
*/constlocalList = ['zhHans','en','ko','zhHant','ja']//加載自己需要的語言// webpack的api猜绣,自動(dòng)模塊化加載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:這里有個(gè)小技巧,當(dāng)默認(rèn)語言為英語時(shí)敬特,我們可以在默認(rèn)不添加翻譯掰邢,如this.$t("hello"),當(dāng)沒有對應(yīng)翻譯時(shí)伟阔,會(huì)翻譯成hello辣之,這樣是不是很方便呢?
所以我的項(xiàng)目中皱炉,都是以英文作為翻譯的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
如果需要源碼的話梳猪,請關(guān)注wx公眾號(hào)「前端攻城之路」麻削,回復(fù)“語言國際化”蒸痹,將自動(dòng)獲取到源碼鏈接。
支持
如果這篇文章對你有幫助或者有啟發(fā)的話呛哟,我想請你關(guān)注我叠荠,讓我們一起在前端攻城路上進(jìn)階。