<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Vue 項目前端多語言方案

          共 9360字,需瀏覽 19分鐘

           ·

          2021-09-27 23:24

          作者:Paian
          http://mobilesite.github.io

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

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

          總的來說,一個Web應(yīng)用中,需要做多語言切換的內(nèi)容常見的包括如下方面:
          1、模板中的內(nèi)容,如Vue.js的<template>標(biāo)簽中的文字內(nèi)容
          2、JS代碼中的文字內(nèi)容
          3、圖片中的文案內(nèi)容
          4、頁面title
          5、第三方組件中的文案(比如,我的項目中用到了Vux的組件)
          6、后端接口中需要展示到前端的數(shù)據(jù)內(nèi)容
          7、后端接口返回的錯誤提示

          二、基本思路

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

          我采用的是用URL傳遞?lang=en或者?lang=zh-CN這樣的傳遞參數(shù)的形式。這樣做的好處在于可以通過鏈接指定用哪種語言。但是,只依賴于地址欄參數(shù)也是不方便的。比如,在頁面跳轉(zhuǎn)的時候,這個地址欄參數(shù)可能就丟失了。這會導(dǎo)致你在頁面跳轉(zhuǎn)之后就不知道該用哪種語言展示了。而理想的的方式應(yīng)該是,進入某個頁面的時候帶有這個參數(shù)(這個時候就獲取到該使用何種語言了),等再跳轉(zhuǎn)到其它頁面的時候就不必再帶這個lang參數(shù)了,因為此時你已經(jīng)知道該用哪種語言了。所以,應(yīng)該在一進入第一個頁面的時候就把這個參數(shù)存下來,比如,存在localstorage中,存在vuex的state中。
          這里,就引出來一個語言判斷的優(yōu)先級問題。
          因為地址欄里可能有lang參數(shù),localstorage中可能也有相關(guān)的存儲字段(因為上次訪問過本應(yīng)用),你可能還想設(shè)置默認的降級語言,等等。其優(yōu)先級應(yīng)該如何處理呢?
          正確的優(yōu)先級應(yīng)該是:
          先看地址欄參數(shù)中有沒有;
          再看localstorage中有沒有;
          然后再通過navigator.language獲取瀏覽器默認語言,看是否是你的應(yīng)用所支持的語言,若是,則采用之;
          最后才是使用回退語言(例如,比較通用的英語)。
          當(dāng)然,你可以根據(jù)你的需求來做一些簡化。

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

          (1)i18n相關(guān)工具的選擇——由誰來提供多語言轉(zhuǎn)換函數(shù)(通常是$t)?
          目前國際化通用方式多數(shù)基于i18n,我們也無需再去造輪子了。但就i18n的具體使用上,有很多不同的NPM模塊。比如vuex-i18n、vue-i18n、simplest-i18n等。因為多數(shù)復(fù)雜一點的項目都會上vuex,所以復(fù)雜一點的項目選擇vuex-i18n會比vue-i18n更方便。
          而simplest-i18n這個很小眾的模塊,其實也有它的好處。它支持下面這樣的寫法:
          在模板中:
          <span>$t('真實姓名', 'Real Name')</span>
          或者在JS中:
          this.$t('真實姓名''Real Name')
          即將語言寫在一起,$t函數(shù)的每一個參數(shù)都是一種語言,一目了然,還是比較方便閱讀的。對小項目來說,不失為一種選擇。
          其基本使用如下:
          t.js文件:
          import i18n from 'simplest-i18n';
          import getLang from '../../getLang';

          const t = i18n({
            locale: getLang.lang, // 當(dāng)前語言
            locales: getLang.langs // 支持的語言列表
          });
          export default t;
          然后在應(yīng)用的入口文件中對Vue.js進行擴展:
          import t from './t';
          Vue.$t = Vue.prototype.$t = t;
          這樣就把$t這個方法掛載到了Vue.js的全局。Vue實例中也可以通過this.$t訪問到,使用上還是非常簡單的。
          但是,對于大項目來說,把語言包都寫在代碼里面,對維護并不友好。而且,靠它也解決不了我所用到的Vux組件的多語言化的問題。
          所以最終,我選擇了vuex-i18n作為基礎(chǔ)。
          (2)組織和處理語言包的工具——語言包怎么組織,怎么打包處理?
          對于這個問題,我首先需要解決Vux第三方組件的多語言化問題。
          首先,在語言包的組織方面,比較常見的是寫成JSON配置文件。不過,我最終采用了Yaml這種格式,它支持將多語言字段寫在一起。比如:
          config.yml
          confirm:
            zh-CN: 確認
            en: confirm
          而不是像下面那樣將一個字段的多語言拆成幾處,比如:
          confirm: 確認
          confirm: confirm
          這樣帶來的好處就是,可以方便地對照一個字段的不同語言版本,而且要修改或刪除某一個字段時,也可以在一處完成,無需切換。況且,Yaml文件的語法也更加簡單明了,省去了JSON文件必須寫雙引號、不可以出現(xiàn)注釋等諸多麻煩。
          其次,在語言包的打包方面,我找到了vux-loader。它可以和現(xiàn)有的webpack配置結(jié)合,不僅能完成Vux組件多語言配置的打包,還允許在自定義的Vue組件中使用<i18n>標(biāo)簽。比如,在自定義組件中我可以這么寫:
          <i18n>
          confirm:
            zh-CN: 確認
            en: confirm
          <i18n>
          打包時,vux-loader會將<i18n>標(biāo)簽中的多語言配置信息導(dǎo)出至我們所配置的一個Yaml文件中,而把<i18n>標(biāo)簽從我們的自定義組件中移除。
          那么,對于Yaml文件如何處理呢?可以用json-loader和yaml-loader。它們可以將Yaml文件轉(zhuǎn)換成我們所需要的json格式,方便在JS函數(shù)中使用,就像這樣:
          const componentsLocales = require('json-loader!yaml-loader!../../locales/components.yml'); // 這就得到了一個語言包的json格式

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

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

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

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

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

          const langs = ['zh-CN''en']; // 支持哪些語言
          const defaultLang = 'en'// 默認語言,暫時并沒有對外拋出

          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)前語言
              langs // 所支持的語言列表
          }

          2、Vux組件的多語言包的配置

          可以從Vux的官方github中找到src/locales/all.yml拷貝過來(同一目錄下的src/locales/zh-CN.ymlsrc/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',
                      vuxStaticReplacefalse,
                      staticReplacefalse,
                      extractToFiles'src/locales/components.yml',
                      localeList: ['en','zh-CN']
                  }
              ]
          }))
          webpack.prod.conf.js中:
          resolve(vuxLoader.merge(buildWebpackConfig, {
              plugins_dir: [
                  'vux-ui',
                  {
                      name'i18n',
                      vuxStaticReplacefalse,
                      staticReplacefalse,
                      extractToFiles'src/locales/components.yml',
                      localeList: ['en','zh-CN']
                  }
              ]
          }))
          其中的localeList: ['en','zh-CN']就是指定你的應(yīng)用支持哪幾種語言。
          extractToFiles: 'src/locales/components.yml'就是指定你的自定義組件中所用到的那些<i18n>標(biāo)簽中的語言包信息,應(yīng)該導(dǎo)出到哪個Yaml文件中。也就是說,你在各個自定義組件中使用的<i18n>標(biāo)簽中的語言包信息都會被vux-loader集中抽取到這個文件中。
          然后在應(yīng)用的入口文件中引入這個語言包文件:
          const componentsLocales = require('json-loader!yaml-loader!../../locales/components.yml');

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

          (1)對于自定義組件內(nèi)部的文案的多語言化信息,寫在組件的<i18n>標(biāo)簽中即可。同時,為了避免不同的自定義組件中多語言字段的命名沖突,在每個字段的名字前面加上以組件名-式的前綴。
          (2)對于頁面的標(biāo)題、一些錯誤提示等文案,它們是出現(xiàn)在組件之外的,因此不適合寫在組件的<i18n>標(biāo)簽中,所以我們單獨新建一個global.yml來存放這些全局性的多語言信息。這些內(nèi)容直接寫在global.yml中即可,并且,為了表面與其它的語言包字段相沖突,我們在每個字段的前面加上global-前綴。
          然后在應(yīng)用的入口文件中引入這個語言包文件:
          const componentsLocales = require('json-loader!yaml-loader!../../locales/global.yml');

          5、vuex-i18n的實現(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、圖片的多語言化

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

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

          如果你的應(yīng)用并不需要在頁面內(nèi)部切換語言版本,那么直接通過URL中傳入不同的lang參數(shù)就可以了,并不涉及到此問題。
          第一種方式:刷新頁面
          <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)前頁data中lang字段的變化,通過v-if局部刷新某些相關(guān)組件:
          data(){
              return {
                  langthis.$i18n.locale()
              }
          }

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

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

                  // 在這里通過改變某個標(biāo)志位 結(jié)合 v-if 來觸發(fā)某個局部組件的重新渲染
              }
          }
          第三種方式:結(jié)合vuex派發(fā)全局的語言狀態(tài),接收到狀態(tài)變化時進行更新,或者自己簡單地改寫vuex-i18n的實現(xiàn)。這種方式相對復(fù)雜一些。
          具體根據(jù)自己的業(yè)務(wù)需求選擇。

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

          對于一些包含特殊字符的yaml鍵值,比如[、]等,需要進行轉(zhuǎn)義。轉(zhuǎn)的方式是給鍵值加上單引號引起來。
          如果你的語言包信息中有單引號,則必須連續(xù)使用兩個單引號轉(zhuǎn)義。例如:
          str: 'labor''s day'

          逆鋒起筆是一個專注于程序員圈子的技術(shù)平臺,你可以收獲最新技術(shù)動態(tài)最新內(nèi)測資格BAT等大廠的經(jīng)驗精品學(xué)習(xí)資料職業(yè)路線副業(yè)思維,微信搜索逆鋒起筆關(guān)注!

          推薦 9 個 VUE3 UI 框架

          Vue 實現(xiàn)數(shù)組四級聯(lián)動

          Vue 項目打包部署總結(jié)

          Vue3.0 七大亮點是什么??

          Vue 實戰(zhàn)中的一些小魔法

          瀏覽 56
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  女人片60免费视频18 | 国产一级性爱电影 | 自拍偷拍网页 | 久久国产一区 | 国产精品豆花 |