亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

vue實現多語言切換的方法

發布時間:2020-11-03 15:46:39 來源:億速云 閱讀:591 作者:Leah 欄目:開發技術

今天就跟大家聊聊有關vue實現多語言切換的方法,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。

vue實現多語言切換的方法

鑒于以上原因,瀏覽器自帶的 Google 翻譯方案基本不考慮了。

現在只剩下第二種方案了,語言配置文件和頁面結構分離。前面提過,vue-i18n用得不徹底,如果把所有組件重新規范化,工作量太大了。有沒有辦法不修改現有代碼,也能實現文本翻譯呢?很自然地就想到了 Google 翻譯的思路,直接對頁面渲染結果進行翻譯。自己翻譯的優勢就是,可以精細地控制 DOM 操作,比如可以把輸入框里的文本和placeholder也翻譯出來。同時,經過研究發現,Vue 組件通過數據綁定渲染出來的 DOM 元素,包含的文本內容不能直接通過 innerHTML或者innerText修改,這樣會導致響應式失效。解決辦法是操作它的子元素,也就是文本節點(nodeType為3的節點),修改它的 textContent屬性。

多語言配置映射表

跟 Google 翻譯不同之處在于,我們采用靜態翻譯,也就是通過多語言配置文件映射。 vue-i18n 是每種語言準備一個 JSON 文件,屬性名用英文,用命名空間(多層級對象)的方式避免命名沖突。我直接簡化了,用一個 JS 對象存儲所有語言版本,鍵名就是頁面用到的中文。隨著日積月累的開發迭代,這些中文散落在幾百個文件里……我的做法是用 VS Code 全局正則搜索,把查找結果復制出來,寫一個 JS 方法把這些字符串處理成 JS 對象。

vue實現多語言切換的方法

匹配中文的正則(不夠全面,有些還夾雜了其他符號):

[A-Z]*[\u4e00-\u9fa5][,,!! 0-9a-zA-Z\u4e00-\u9fa5]*

將結果復制到翻譯工具翻譯,再寫一個函數把這些文本合并成對象,并保存到labels.js文件中備用。

var kv = dist.reduce((acc,cur, index) => {
acc[cur]=en[index] || cur;return acc;
},{})

對象的結構大致如下:

// labels.js
export default {
 客戶性名: {
  en: 'Customer Name',
 },
 // 動態文本,后面會講到
 '剩余{0}臺礦機未登記': {
  en: '{0} unregistered',
 },
 xxxx: {
  en: 'XXX',
 }
}

操作 DOM

跟 Google 翻譯類似,我們也采取事后更新 DOM 的方式來進行翻譯。由于是單頁應用,隨著用戶的操作,會不停地更新 DOM。一開始的想法是監聽整個 body的變化,在回調里再更新 DOM。監聽 DOM 變化有一個原生的 API 可用,就是 MutationObserver。

mounted() {
 this.observeDOM(document.body);
},
methods: {
 observeDOM(el) {
  let mutationTimer;
  const vm = this;
  const observer = new MutationObserver(() => {
   // 類似于 debounce 的效果,多次調用合并為一次
   clearTimeout(mutationTimer);
   mutationTimer = setTimeout(() => {
    if (!vm.mutationFromTrans) {
     translate();
     vm.mutationFromTrans = true;
     setTimeout(() => {
      vm.mutationFromTrans = false;
     }, 300);
    }
   }, 100);
  });
  const options = {
   childList: true, // 監視node直接子節點的變動
   subtree: true, // 監視node所有后代的變動
   attributes: true, // 監視node屬性的變動
   characterData: true, // 監視指定目標節點或子節點樹中節點所包含的字符數據的變化。
  };
  if (this.language === 'en') {
   observer.observe(el, options);
  }
 },
}

但是試過之后發現這會導致無線循環,因為沒有判斷 DOM 的變化來自用戶操作還是翻譯本身。所以代碼里后面加了判斷,但是結果依然不理想。這種操作代價太大了,頁面性能受了很大影響。而且還有個很明顯的問題,就是進入到新的界面會閃一下,從中文變成英文。這個體驗太糟糕了。后面有改進辦法。

翻譯

先來來看下翻譯的過程。翻譯就是從多語言配置對象里查找匹配的屬性名,獲取對應語言的屬性值。這對于靜態文本來說比較簡單,直接用屬性名就好了。但是對于動態的文本怎么處理呢?由于中英文表達方式不一樣,這種文本不能簡單地拆分成多個部分單獨處理,而是要在英文的表達方式里替換動態數據。我的做法是使用帶格式的鍵名,比如{0}這樣的占位符。在查找的時候,優先匹配固定文本。因為大部分情況是固定文本,而且這種匹配是O(1)時間復雜度的,優先判斷會提高性能。匹配失敗的時候才去提前構造好的正則列表里遍歷匹配,成功則提取正則匹配的group用于替換動態數據。如果失敗,說明沒有對應的翻譯,直接返回原始字符串就行了。

const keys = Object.keys(words);
// 提前緩存正則,避免重復執行消耗性能
const regExps = keys.reduce((acc, key) => {
 // 模板型鍵名
 if (key.indexOf('{0}') > -1) {
  const reg = new RegExp(key.replace('{0}', '(.+)'));
  acc.push({
   expression: reg,
   key,
  });
 }
 return acc;
}, []);
export function translate(el = document.body, lang = 'en') {
 const kv = words;
 if (!el.querySelectorAll) {
  return;
 }
 const _trans = label => {
  const text = label?.trim?.();
  if (!text) {
   return label;
  }
  if (kv[text]?.[lang]) {
   return kv[text]?.[lang];
  }
  for (let index = 0; index < regExps.length; index++) {
   const regItem = regExps[index];
   const m = text.match(regItem.expression);
   if (m) {
    return kv[regItem.key][lang].replace('{0}', m[1]);
   }
  }
  return text;
 };
 [...el.querySelectorAll('*')].forEach(node => {
  // 不能直接修改node.innerText,會導致Vue響應式失效
  // node.innerText = kv[node.innerText&#63;.trim&#63;.()] || node.innerText;
  if (node.nodeName === 'INPUT' && node.type === 'text') {
   node.value = _trans(node.value);
   node.placeholder = _trans(node.placeholder);
  }
  const textNodes = [...node.childNodes].filter(n => n.nodeType === 3);
  textNodes.forEach(textNode => {
   textNode.textContent = _trans(textNode.textContent);
  });
 });
}

改進后的 DOM 操作

前面提過,如果在 DOM 渲染后再執行翻譯,頁面性能非常差。于是想到了 Vue 本身的渲染過程,能不能攔截 Vue 組件渲染過程,插入一些額外的邏輯呢?通過扒源碼發現,Vue 原型上有個__patch__方法,每次更新 DOM 的時候都會執行。就從這里入手, 重寫這個方法,對還沒掛載到文檔樹的 DOM 元素執行翻譯操作。

const __patch__ = Vue.prototype.__patch__;
Vue.prototype.__patch__ = function() {
 const elm = __patch__.apply(this, arguments);
 if (this.$store&#63;.getters&#63;.language) {
  translate(elm, this.$store&#63;.getters&#63;.language);
 }
 return elm;
};

至此,基本完成了多語言翻譯。經過權衡對比,這個方案算是比較省時省力又能完成需求的了。當然,這種方案或多或少對頁面性能有一定影響,畢竟增加了 DOM 更新的時間。尤其是動態文本較多的情況,涉及到遍歷正則匹配,比較耗時。

看完上述內容,你們對vue實現多語言切換的方法有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

江津市| 张家口市| 南雄市| 石楼县| 磐石市| 望奎县| 龙江县| 泽普县| 报价| 陆丰市| 松桃| 兴宁市| 东宁县| 历史| 绥化市| 宁陕县| 称多县| 宜春市| 商河县| 嘉黎县| 沾益县| 怀仁县| 安平县| 苏尼特左旗| 平凉市| 太和县| 临沂市| 罗源县| 杭锦后旗| 金山区| 红安县| 郎溪县| 衢州市| 文化| 洪雅县| 宁阳县| 嵩明县| 雷山县| 班玛县| 阳谷县| 广宁县|