<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】Vue-i18n 變量使用以及采坑總結(jié)

          共 7809字,需瀏覽 16分鐘

           ·

          2021-05-05 08:36


          前言

          筆者目前在 Shopee 工作,我們公司主要業(yè)務(wù)是跨境電商,業(yè)務(wù)涉及到多個(gè)國家,所以我們各個(gè)系統(tǒng)都會(huì)涉及到國際化翻譯。我們 Vue 項(xiàng)目技術(shù)上采用了 Vue-i18n 這個(gè)庫。

          今天就聊聊這個(gè)庫的一個(gè)功能,在國際化時(shí)候使用變量。在翻譯中使用變量是一個(gè)非常常見的場景,最簡單的例子,比如以下的文案要國際化

          I am Gopal.I am from China

          但其中 GopalChina 是需要變量傳入的,這個(gè)時(shí)候我們?cè)趺崔k呢?

          簡單的傳參

          首先我們定義要翻譯的字符如下

          "introTips""I am {name}.I am from {region}"

          然后在模板中使用

          $t('introTips', { name'Gopal一號(hào)'region'China' })

          就可以渲染出 I am Gopal 一號(hào).I am from China

          需要給變量加個(gè)顏色

          假如說我們 Gopal 不僅僅是一個(gè)文案,還需要變成紅色?我們?cè)撛趺崔k?我們可以直接使用 v-html 渲染 html。這個(gè)時(shí)候我們就要修改翻譯的字符如下

          introTipsTwo: "I am <span class='name'>{name}</span>.I am from {region}"

          使用 v-html 直接渲染

          <div
            class="text"
            v-html="$t('introTipsTwo', { name: 'Gopal一號(hào)', region: 'China' })"
          >
          </div>

          渲染結(jié)果如下

          <div data-v-763db97b="" class="text">
            I am <span class="name">Gopal一號(hào)</span>.I am from China
          </div>
          image-20210430112350433

          注意:這個(gè)方法很可能引發(fā) XSS 攻擊,所以不推薦使用該方法

          使用 place 屬性

          首先翻譯的文案先改回最開始變量的版本

          introTips: "I am {name}.I am from {region}"

          直接使用 i18n 組件以及 place 屬性,其中 path 指的是上面的 key,place 指定變量

          <i18n path="introTips" tag="div">
            <span class="name" place="name">Gopal 二號(hào)</span>
            <span place="region">China</span>
          </i18n>

          渲染結(jié)果如下:

          <div data-v-763db97b="">
            I am <span data-v-763db97b="" place="name" class="name">Gopal 二號(hào)</span>.I am from <span data-v-763db97b="" place="region">China</span>
          </div>
          image-20210430113555745

          我們已經(jīng)實(shí)現(xiàn)了我們的方案,但這個(gè)方法會(huì)在下個(gè)版本中被淘汰,仔細(xì)看,這不是 Vue 中的插槽么?沒錯(cuò),官方推薦的最終的解決方案是 Slot,用法跟上面的非常相似

          最終的方案 ——Slot

          直接上代碼:

          <i18n path="introTips" tag="div">
            <template v-slot:name>
              <span class="name">Gopal 三號(hào)</span>
            </template>
            <template v-slot:region>
              <span>China</span>
            </template>
          </i18n>

          渲染的結(jié)果跟上面的類似

          <div data-v-763db97b="">
            I am <span data-v-763db97b="" class="name">Gopal 三號(hào)</span>.I am from <span data-v-763db97b="">China</span></div>

          問題

          在項(xiàng)目中使用的時(shí)候,卻報(bào)錯(cuò)了...

          我的辦法跟上面的可謂是一模一樣...

          報(bào)錯(cuò)

          <i18n path="introTips" tag="div">
            <template v-slot:name>
              <span class="name">Gopal 三號(hào)</span>
            </template>
            <template v-slot:region>
              <span>China</span>
            </template>
          </i18n>
          vue.esm.js:628 [Vue warn]: Error in nextTick: "TypeError: Cannot create property 'isRootInsert' on string 'You submit '"

          我感覺我又要掉頭發(fā)了...。

          斷點(diǎn)查看

          Google 了一下這個(gè)報(bào)錯(cuò)以及看了一下報(bào)錯(cuò)的堆棧信息,看起來像是 vNode 渲染的問題,然后我在報(bào)錯(cuò)的地方打了一個(gè)斷點(diǎn),可以看到下面 children 中數(shù)組的各項(xiàng)并不都是 vnode,第一項(xiàng)就是字符串,這應(yīng)該就是導(dǎo)致報(bào)錯(cuò)的罪魁禍?zhǔn)?/p>

          閱讀源碼

          我看了一下 node_modules 中 vue-i18n 的源碼,這里注意我目前使用的版本是 8.15.0

          發(fā)現(xiàn)在 i18n 這個(gè)函數(shù)式組件的源碼中有兩句非常奇怪的代碼,這個(gè)函數(shù)式組件源碼見鏈接 [1]

          export default {
            name'i18n',
            functionaltrue,
            props: {
              // 留意這里
              tag: {
                typeString
              },
            // ...
            },
            render (h: Function, { data, parent, props, slots }: Object) {
              const { $i18n } = parent
            // ...
              const { path, locale, places } = props
              const params = slots()
              const children = $i18n.i(
                path,
                locale,
                onlyHasDefaultPlace(params) || places
                  ? useLegacyPlaces(params.default, places)
                  : params
              )

              const tag = props.tag || 'span'
              return tag ? h(tag, data, children) : children
            }
          }

          留意最后兩行代碼

          const tag = props.tag || 'span'
          return tag ? h(tag, data, children) : children

          啊,這。。。children 是不是永遠(yuǎn)沒有機(jī)會(huì)執(zhí)行了?

          我嘗試直接 return 回 children。額成功了...

          嘗試升級(jí)版本

          我想了想,升級(jí)到較新的版本試下?

          果然,這個(gè)組件修改了...,簡化了一下代碼,源碼可見鏈接 [2]

          export default {
            name'i18n',
            functionaltrue,
            props: {
              // 留意這里
              tag: {
                type: [StringBooleanObject],
                default'span'
              }
              // ...
            },
            render (h: Function, { data, parent, props, slots }: Object) {
              // ....
            // 留意這里
              const tag = (!!props.tag && props.tag !== true) || props.tag === false ? props.tag : 'span'
              return tag ? h(tag, data, children) : children
            }
          }

          這里的 tag 可以傳 String,Boolean 和 Object

          看了一下官方文檔

          You can choose the root container's node type by specifying a tag prop. If omitted, it defaults to 'span'. You can also set it to the boolean value false to insert the child nodes directly without creating a root element.

          簡單來說 tag 可以傳 false,這樣就不需要在翻譯的外層再多加一個(gè)節(jié)點(diǎn)了

          我再去找了一下修改這個(gè) PR[3] 以及對(duì)應(yīng)的 Issue[4]

          解決問題

          雖然看起來為了解決不需要配置根節(jié)點(diǎn)的問題的,但我感覺也可以解決我的問題,以下升級(jí)版本后,我修改了一下我的代碼

          <div class="test-container">
            <i18n path="introTips" :tag="false">
              <template v-slot:name>
                <span class="name">Gopal 三號(hào)</span>
              </template>
              <template v-slot:region>
                <span>China</span>
              </template>
            </i18n>
          </div>

          這回真的成功了,非常開心,最終它的渲染如下

          <div data-v-0b89d11d="" class="test-container">
            <!-- 這里外層沒有節(jié)點(diǎn)了 -->
            I am <span data-v-0b89d11d="" class="name">Gopal 三號(hào)</span>.I am from <span data-v-0b89d11d="">China</span></div>

          可以看到這個(gè)時(shí)候渲染出來就沒有最外層的 tag 了

          總結(jié)

          本文介紹了 vue-i18n 變量的使用方法,幾種方法都較為簡單易懂。主要是記錄了自己踩過的一個(gè)坑,也算是學(xué)到了一些經(jīng)驗(yàn)

          • 當(dāng)沒有思路的時(shí)候,可以看看源碼。可以直接 node_modules 中查看,甚至在 dist  文件中找到相對(duì)應(yīng)的代碼,斷點(diǎn)調(diào)試
          • 源碼調(diào)試不僅僅對(duì)定位問題有所幫助,也可以擴(kuò)寬視野。比如上面提到的 i18n 函數(shù)式組件的實(shí)現(xiàn)。我當(dāng)時(shí)看的時(shí)候,假如讓我來寫,我可以寫出來么?
          • 留意官方的 ISSUE,不過這次前期我都找過,只是都不是我這個(gè)錯(cuò)誤...
          • 官方的文檔英文比較全,中文版和英文版差異較大(應(yīng)該是翻譯滯后了)

          最后

          之前提到了,筆者在 Shopee 工作,有需要換工作的同學(xué)可以找我內(nèi)推哈~

          五月份專場非常多機(jī)會(huì),具體可以查看 鏈接 [5]。一線大廠薪資,少加班(公司提倡高效工作),團(tuán)隊(duì)氛圍好,晉升機(jī)會(huì)多,感興趣的同學(xué)請(qǐng)抓緊時(shí)間,發(fā)送簡歷到我郵箱 [email protected]

          參考資料

          [1]

          鏈接: https://github.com/kazupon/vue-i18n/blob/v8.15.0/src/components/interpolation.js#L42

          [2]

          鏈接: https://github.com/kazupon/vue-i18n/blob/v8.22.0/src/components/interpolation.js

          [3]

          PR: https://github.com/kazupon/vue-i18n/pull/878

          [4]

          Issue: https://github.com/kazupon/vue-i18n/issues/876

          [5]

          鏈接: https://app.mokahr.com/apply/shopee/2963#/

          瀏覽 186
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  毛片操逼 | 91久久久久久久久久久久 | 中文字幕手机在线观看 | jiujiujiu999 | WWW高清视频一区在线观看 |