首先,我們先來介紹一下,什么是語言國際化。i18n(其來源是英文單詞 internationalization的首末字符i和n,18為中間的字符數(shù))是“國際化”的簡稱。在資訊領(lǐng)域,國際化(i18n)指讓網(wǎng)站無需做大的改變就能夠適應(yīng)不同的語言和地區(qū)的需要。對(duì)程序來說,在不修改內(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對(duì)象中,我們就可以這樣更改語言了,通過
i18n.locale=lang 去更改你需要的語言,就可以自動(dòng)獲取相應(yīng)的語言了,在模版中使用$t('hello')來翻譯。
vue-i18n更多使用姿勢(shì)看這里: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)在我們?cè)賮碚f同步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對(duì)應(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)沒有對(duì)應(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
如果需要源碼的話,請(qǐng)關(guān)注wx公眾號(hào)「前端攻城之路」,回復(fù)“語言國際化”,將自動(dòng)獲取到源碼鏈接。
支持
如果這篇文章對(duì)你有幫助或者有啟發(fā)的話,我想請(qǐng)你關(guān)注我,讓我們一起在前端攻城路上進(jìn)階。