欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Vue.js項(xiàng)目前端多語(yǔ)言方案的思路與實(shí)踐

 更新時(shí)間:2021年07月31日 11:17:59   作者:Paian  
前端的國(guó)際化是一個(gè)比較常見(jiàn)的需求,但網(wǎng)上關(guān)于這一方面的直接可用的方案卻不多,這篇文章主要給大家介紹了關(guān)于Vue.js項(xiàng)目前端多語(yǔ)言方案的思路與實(shí)踐,需要的朋友可以參考下

前端的國(guó)際化是一個(gè)比較常見(jiàn)的需求。但網(wǎng)上關(guān)于這一方面的直接可用的方案卻不多。最近剛做了一版基于Vue.js的多語(yǔ)言實(shí)現(xiàn),在此簡(jiǎn)單作一小結(jié)。

一、通常有哪些內(nèi)容需要處理

總的來(lái)說(shuō),一個(gè)Web應(yīng)用中,需要做多語(yǔ)言切換的內(nèi)容常見(jiàn)的包括如下方面:

1、模板中的內(nèi)容,如Vue.js的<template>標(biāo)簽中的文字內(nèi)容

2、JS代碼中的文字內(nèi)容

3、圖片中的文案內(nèi)容

4、頁(yè)面title

5、第三方組件中的文案(比如,我的項(xiàng)目中用到了Vux的組件)

6、后端接口中需要展示到前端的數(shù)據(jù)內(nèi)容

7、后端接口返回的錯(cuò)誤提示

二、基本思路

1、首先,需要確定以什么樣的方式來(lái)獲取到當(dāng)前應(yīng)該展示何種語(yǔ)言

我采用的是用URL傳遞?lang=en或者?lang=zh-CN這樣的傳遞參數(shù)的形式。這樣做的好處在于可以通過(guò)鏈接指定用哪種語(yǔ)言。但是,只依賴于地址欄參數(shù)也是不方便的。比如,在頁(yè)面跳轉(zhuǎn)的時(shí)候,這個(gè)地址欄參數(shù)可能就丟失了。這會(huì)導(dǎo)致你在頁(yè)面跳轉(zhuǎn)之后就不知道該用哪種語(yǔ)言展示了。而理想的的方式應(yīng)該是,進(jìn)入某個(gè)頁(yè)面的時(shí)候帶有這個(gè)參數(shù)(這個(gè)時(shí)候就獲取到該使用何種語(yǔ)言了),等再跳轉(zhuǎn)到其它頁(yè)面的時(shí)候就不必再帶這個(gè)lang參數(shù)了,因?yàn)榇藭r(shí)你已經(jīng)知道該用哪種語(yǔ)言了。所以,應(yīng)該在一進(jìn)入第一個(gè)頁(yè)面的時(shí)候就把這個(gè)參數(shù)存下來(lái),比如,存在localstorage中,存在vuex的state中。

這里,就引出來(lái)一個(gè)語(yǔ)言判斷的優(yōu)先級(jí)問(wèn)題。

因?yàn)榈刂窓诶锟赡苡衛(wèi)ang參數(shù),localstorage中可能也有相關(guān)的存儲(chǔ)字段(因?yàn)樯洗卧L問(wèn)過(guò)本應(yīng)用),你可能還想設(shè)置默認(rèn)的降級(jí)語(yǔ)言,等等。其優(yōu)先級(jí)應(yīng)該如何處理呢?

正確的優(yōu)先級(jí)應(yīng)該是:

先看地址欄參數(shù)中有沒(méi)有;

再看localstorage中有沒(méi)有;

然后再通過(guò)navigator.language獲取瀏覽器默認(rèn)語(yǔ)言,看是否是你的應(yīng)用所支持的語(yǔ)言,若是,則采用之;

最后才是使用回退語(yǔ)言(例如,比較通用的英語(yǔ))。

當(dāng)然,你可以根據(jù)你的需求來(lái)做一些簡(jiǎn)化。

2、其次,采用什么工具來(lái)解決語(yǔ)言轉(zhuǎn)換和打包的問(wèn)題?

(1)i18n相關(guān)工具的選擇——由誰(shuí)來(lái)提供多語(yǔ)言轉(zhuǎn)換函數(shù)(通常是$t)?

目前國(guó)際化通用方式多數(shù)基于i18n,我們也無(wú)需再去造輪子了。但就i18n的具體使用上,有很多不同的NPM模塊。比如vuex-i18n、vue-i18n、simplest-i18n等。因?yàn)槎鄶?shù)復(fù)雜一點(diǎn)的項(xiàng)目都會(huì)上vuex,所以復(fù)雜一點(diǎn)的項(xiàng)目選擇vuex-i18n會(huì)比vue-i18n更方便。

而simplest-i18n這個(gè)很小眾的模塊,其實(shí)也有它的好處。它支持下面這樣的寫法:

在模板中:

<span>$t('真實(shí)姓名', 'Real Name')</span>

或者在JS中:

this.$t('真實(shí)姓名', 'Real Name')

即將語(yǔ)言寫在一起,$t函數(shù)的每一個(gè)參數(shù)都是一種語(yǔ)言,一目了然,還是比較方便閱讀的。對(duì)小項(xiàng)目來(lái)說(shuō),不失為一種選擇。

其基本使用如下:

t.js文件:

import i18n from 'simplest-i18n';
import getLang from '../../getLang';

const t = i18n({
  locale: getLang.lang, // 當(dāng)前語(yǔ)言
  locales: getLang.langs // 支持的語(yǔ)言列表
});
export default t;

然后在應(yīng)用的入口文件中對(duì)Vue.js進(jìn)行擴(kuò)展:

import t from './t';
Vue.$t = Vue.prototype.$t = t;

這樣就把$t這個(gè)方法掛載到了Vue.js的全局。Vue實(shí)例中也可以通過(guò)this.$t訪問(wèn)到,使用上還是非常簡(jiǎn)單的。

但是,對(duì)于大項(xiàng)目來(lái)說(shuō),把語(yǔ)言包都寫在代碼里面,對(duì)維護(hù)并不友好。而且,靠它也解決不了我所用到的Vux組件的多語(yǔ)言化的問(wèn)題。

所以最終,我選擇了vuex-i18n作為基礎(chǔ)。

(2)組織和處理語(yǔ)言包的工具——語(yǔ)言包怎么組織,怎么打包處理?

對(duì)于這個(gè)問(wèn)題,我首先需要解決Vux第三方組件的多語(yǔ)言化問(wèn)題。

首先,在語(yǔ)言包的組織方面,比較常見(jiàn)的是寫成JSON配置文件。不過(guò),我最終采用了Yaml這種格式,它支持將多語(yǔ)言字段寫在一起。比如:

config.yml

confirm:
  zh-CN: 確認(rèn)
  en: confirm

而不是像下面那樣將一個(gè)字段的多語(yǔ)言拆成幾處,比如:

confirm: 確認(rèn)

confirm: confirm

這樣帶來(lái)的好處就是,可以方便地對(duì)照一個(gè)字段的不同語(yǔ)言版本,而且要修改或刪除某一個(gè)字段時(shí),也可以在一處完成,無(wú)需切換。況且,Yaml文件的語(yǔ)法也更加簡(jiǎn)單明了,省去了JSON文件必須寫雙引號(hào)、不可以出現(xiàn)注釋等諸多麻煩。

其次,在語(yǔ)言包的打包方面,我找到了vux-loader。它可以和現(xiàn)有的webpack配置結(jié)合,不僅能完成Vux組件多語(yǔ)言配置的打包,還允許在自定義的Vue組件中使用<i18n>標(biāo)簽。比如,在自定義組件中我可以這么寫:

<i18n>
confirm:
  zh-CN: 確認(rèn)
  en: confirm
<i18n>

打包時(shí),vux-loader會(huì)將<i18n>標(biāo)簽中的多語(yǔ)言配置信息導(dǎo)出至我們所配置的一個(gè)Yaml文件中,而把<i18n>標(biāo)簽從我們的自定義組件中移除。

那么,對(duì)于Yaml文件如何處理呢?可以用json-loader和yaml-loader。它們可以將Yaml文件轉(zhuǎn)換成我們所需要的json格式,方便在JS函數(shù)中使用,就像這樣:

const componentsLocales = require('json-loader!yaml-loader!../../locales/components.yml'); // 這就得到了一個(gè)語(yǔ)言包的json格式

3、如何通知后端接口返回何種語(yǔ)言的數(shù)據(jù)?

因?yàn)樯婕暗皆S多接口都要通知后端采用哪種語(yǔ)言,所以,我選擇了使用header頭的方式。在axios的interceptor中給請(qǐng)求統(tǒng)一添加了header頭:Accept-Language, 并把這個(gè)值的內(nèi)容設(shè)置成前端所獲得應(yīng)使用的語(yǔ)言(如,zh-CN 或 en 等)。這樣,就集中在一處把這個(gè)問(wèn)題處理掉了。

三、具體實(shí)踐中的一些細(xì)節(jié)

1、獲取當(dāng)前應(yīng)該采用何種語(yǔ)言的getLang模塊的實(shí)現(xiàn)

import { getQueryObj } from '../utils/url';
import { setItem, getItem } from '../utils/storage';

const langs = ['zh-CN', 'en']; // 支持哪些語(yǔ)言
const defaultLang = 'en'; // 默認(rèn)語(yǔ)言,暫時(shí)并沒(méi)有對(duì)外拋出

function getLang() {
  let queries = getQueryObj();
  let storeLang = getItem('lang');
  let rawLang;
  let flag = false;

  if (queries && queries['lang']) {
    rawLang = queries['lang'];
    setItem('lang', rawLang);
  } else {
    rawLang = storeLang || navigator.language;
  }

  langs.map(item => {
    if (item === rawLang) {
      flag = true;
    }
  });
  return flag ? rawLang : defaultLang;
}

const lang = getLang(langs, defaultLang);

export default {
    lang, // 獲取到當(dāng)前語(yǔ)言
    langs // 所支持的語(yǔ)言列表
}

2、Vux組件的多語(yǔ)言包的配置

可以從Vux的官方github中找到src/locales/all.yml拷貝過(guò)來(lái)(同一目錄下的src/locales/zh-CN.yml、src/locales/en.yml分別是其中文部分和英文部分),根據(jù)你自己的需要略作修改即可。

然后在你的應(yīng)用的應(yīng)用的入口文件中引入:

const vuxLocales = require('json-loader!yaml-loader!../../locales/all.yml');

3、vux-loader的配置

webpack.dev.conf.js中:

resolve(vuxLoader.merge(devWebpackConfig, {
    plugins_dir: [
        'vux-ui',
        {
            name: 'i18n',
            vuxStaticReplace: false,
            staticReplace: false,
            extractToFiles: 'src/locales/components.yml',
            localeList: ['en','zh-CN']
        }
    ]
}))

webpack.prod.conf.js中:

resolve(vuxLoader.merge(buildWebpackConfig, {
    plugins_dir: [
        'vux-ui',
        {
            name: 'i18n',
            vuxStaticReplace: false,
            staticReplace: false,
            extractToFiles: 'src/locales/components.yml',
            localeList: ['en','zh-CN']
        }
    ]
}))

其中的localeList: ['en','zh-CN']就是指定你的應(yīng)用支持哪幾種語(yǔ)言。

而extractToFiles: 'src/locales/components.yml'就是指定你的自定義組件中所用到的那些<i18n>標(biāo)簽中的語(yǔ)言包信息,應(yīng)該導(dǎo)出到哪個(gè)Yaml文件中。也就是說(shuō),你在各個(gè)自定義組件中使用的<i18n>標(biāo)簽中的語(yǔ)言包信息都會(huì)被vux-loader集中抽取到這個(gè)文件中。

然后在應(yīng)用的入口文件中引入這個(gè)語(yǔ)言包文件:

const componentsLocales = require('json-loader!yaml-loader!../../locales/components.yml');

4、自定義組件內(nèi)外文案的多語(yǔ)言化

(1)對(duì)于自定義組件內(nèi)部的文案的多語(yǔ)言化信息,寫在組件的<i18n>標(biāo)簽中即可。同時(shí),為了避免不同的自定義組件中多語(yǔ)言字段的命名沖突,在每個(gè)字段的名字前面加上以組件名-式的前綴。

(2)對(duì)于頁(yè)面的標(biāo)題、一些錯(cuò)誤提示等文案,它們是出現(xiàn)在組件之外的,因此不適合寫在組件的<i18n>標(biāo)簽中,所以我們單獨(dú)新建一個(gè)global.yml來(lái)存放這些全局性的多語(yǔ)言信息。這些內(nèi)容直接寫在global.yml中即可,并且,為了表面與其它的語(yǔ)言包字段相沖突,我們?cè)诿總€(gè)字段的前面加上global-前綴。

然后在應(yīng)用的入口文件中引入這個(gè)語(yǔ)言包文件:

const componentsLocales = require('json-loader!yaml-loader!../../locales/global.yml');

5、vuex-i18n的實(shí)現(xiàn)

在src/store/index.js文件中:

import VuexI18n from 'vuex-i18n';

export default new Vuex.Store中增加:

    i18n: VuexI18n.store

在應(yīng)用的入口文件中:

import VuexI18n from 'vuex-i18n';
import getLang from '../../getLang';

Vue.use(VuexI18n.plugin, store);

const vuxLocales = require('json-loader!yaml-loader!../../locales/all.yml');
const componentsLocales = require('json-loader!yaml-loader!../../locales/components.yml');

const finalLocales = {
  'en': Object.assign(vuxLocales['en'], componentsLocales['en']),
  'zh-CN': Object.assign(vuxLocales['zh-CN'], componentsLocales['zh-CN'])
}

for (let i in finalLocales) {
  Vue.i18n.add(i, finalLocales[i])
}

Vue.i18n.set(globalVars.lang);

6、圖片的多語(yǔ)言化

對(duì)于圖片中的文案信息,多語(yǔ)言化主要有這么兩種方式:一是根據(jù)不同的語(yǔ)言展示不同的圖片;二是盡將文字從圖片背景中分離出來(lái),采用文字層加背景圖片層的方式,這樣文字層就可以作為普通文本來(lái)實(shí)現(xiàn)多語(yǔ)言化了。都比較簡(jiǎn)單,不再贅述。

7、在當(dāng)前頁(yè)面通過(guò)按鈕切換當(dāng)前語(yǔ)言后,如何更新當(dāng)前頁(yè)面的內(nèi)容?

如果你的應(yīng)用并不需要在頁(yè)面內(nèi)部切換語(yǔ)言版本,那么直接通過(guò)URL中傳入不同的lang參數(shù)就可以了,并不涉及到此問(wèn)題。

第一種方式:刷新頁(yè)面

<button @click="changeLang('zh-CN')">中文</button>
<button @click="changeLang('en')">英文</button>
changeLang(lang){
    location.href = this.$utils.url.replaceParam(this.$router.history.current.path, 'lang', lang);
},

第二種方式:watch當(dāng)前頁(yè)data中l(wèi)ang字段的變化,通過(guò)v-if局部刷新某些相關(guān)組件:

data(){
    return {
        lang: this.$i18n.locale()
    }
}

changeLang(lang){
    this.$i18n.set(lang);
    this.lang = this.$i18n.locale();
},

watch: {
    lang(newVal, oldVal) {
        if(newVal === oldVal) {
            return;
        }

        // 在這里通過(guò)改變某個(gè)標(biāo)志位 結(jié)合 v-if 來(lái)觸發(fā)某個(gè)局部組件的重新渲染
    }
}

第三種方式:結(jié)合vuex派發(fā)全局的語(yǔ)言狀態(tài),接收到狀態(tài)變化時(shí)進(jìn)行更新,或者自己簡(jiǎn)單地改寫vuex-i18n的實(shí)現(xiàn)。這種方式相對(duì)復(fù)雜一些。

具體根據(jù)自己的業(yè)務(wù)需求選擇。

8、Yaml中特殊字符的轉(zhuǎn)義

對(duì)于一些包含特殊字符的yaml鍵值,比如[、]等,需要進(jìn)行轉(zhuǎn)義。轉(zhuǎn)的方式是給鍵值加上單引號(hào)引起來(lái)。

如果你的語(yǔ)言包信息中有單引號(hào),則必須連續(xù)使用兩個(gè)單引號(hào)轉(zhuǎn)義。例如:

str: 'labor''s day'

總結(jié)

到此這篇關(guān)于Vue.js項(xiàng)目前端多語(yǔ)言方案的思路與實(shí)踐的文章就介紹到這了,更多相關(guān)Vue.js前端多語(yǔ)言內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 如何用Vue實(shí)現(xiàn)父子組件通信

    如何用Vue實(shí)現(xiàn)父子組件通信

    這篇文章主要介紹了如何用Vue實(shí)現(xiàn)父子組件通信,對(duì)Vue感興趣的同學(xué),可以參考下
    2021-05-05
  • vue3+ts使用APlayer的示例代碼

    vue3+ts使用APlayer的示例代碼

    這篇文章主要介紹了vue3+ts使用APlayer的示例代碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-08-08
  • 詳細(xì)介紹解決vue和jsp結(jié)合的方法

    詳細(xì)介紹解決vue和jsp結(jié)合的方法

    這篇文章主要介紹了詳細(xì)介紹解決vue和jsp結(jié)合的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • vuejs簡(jiǎn)單驗(yàn)證碼功能完整示例

    vuejs簡(jiǎn)單驗(yàn)證碼功能完整示例

    這篇文章主要介紹了vuejs簡(jiǎn)單驗(yàn)證碼功能,結(jié)合完整實(shí)例形式分析了vue.js驗(yàn)證碼的生成、顯示、校驗(yàn)等相關(guān)操作技巧,需要的朋友可以參考下
    2019-01-01
  • 使用vue-router切換頁(yè)面時(shí),獲取上一頁(yè)url以及當(dāng)前頁(yè)面url的方法

    使用vue-router切換頁(yè)面時(shí),獲取上一頁(yè)url以及當(dāng)前頁(yè)面url的方法

    這篇文章主要介紹了使用vue-router切換頁(yè)面時(shí),獲取上一頁(yè)url以及當(dāng)前頁(yè)面url的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • vue打開(kāi)子組件彈窗都刷新功能的實(shí)現(xiàn)

    vue打開(kāi)子組件彈窗都刷新功能的實(shí)現(xiàn)

    這篇文章主要介紹了vue打開(kāi)子組件彈窗都刷新功能的實(shí)現(xiàn),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-09-09
  • 談?wù)勔騐ue.js引發(fā)關(guān)于getter和setter的思考

    談?wù)勔騐ue.js引發(fā)關(guān)于getter和setter的思考

    最近因?yàn)楣镜男马?xiàng)目決定使用Vue.js來(lái)做,但在使用的過(guò)程中發(fā)現(xiàn)了一個(gè)有趣的事情,因?yàn)榘l(fā)現(xiàn)的這個(gè)事情展開(kāi)了一些對(duì)于getter和setter的思考,具體是什么下面通過(guò)這篇文章來(lái)一起看看吧,有需要的朋友們可以參考學(xué)習(xí)。
    2016-12-12
  • vue如何根據(jù)條件判斷按鈕是否可以點(diǎn)擊

    vue如何根據(jù)條件判斷按鈕是否可以點(diǎn)擊

    這篇文章主要介紹了vue如何根據(jù)條件判斷按鈕是否可以點(diǎn)擊,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • vue如何動(dòng)態(tài)配置ip與端口

    vue如何動(dòng)態(tài)配置ip與端口

    這篇文章主要介紹了vue如何動(dòng)態(tài)配置ip與端口,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • 基于vue v-for 循環(huán)復(fù)選框-默認(rèn)勾選第一個(gè)的實(shí)現(xiàn)方法

    基于vue v-for 循環(huán)復(fù)選框-默認(rèn)勾選第一個(gè)的實(shí)現(xiàn)方法

    下面小編就為大家分享一篇基于vue v-for 循環(huán)復(fù)選框-默認(rèn)勾選第一個(gè)的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-03-03

最新評(píng)論