<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>

          Vite3+Vue3+ts+pinia+NaiveUI項目實戰(zhàn)--國際化配置

          共 8352字,需瀏覽 17分鐘

           ·

          2023-03-21 18:08


          作者:?亦黑迷失 https://juejin.cn/post/7174423843891576840

          因為項目是給設(shè)在新加坡、馬來西亞的海外自提站使用的后臺,所以國際化的配置必不可少。需要切換語言的內(nèi)容主要分為兩部分:

          1. 我們自己添加的文案內(nèi)容,需要用到 vue-i18n-next;
          2. naive ui 的組件,可以使用 n-config-provider 配置。
          vue-i18n-next

          安裝

          vue3 中使用 i18n 需要安裝的是 vue-i18n v9[1] 的版本:

                npm install vue-i18n@9

          配置 i18n

          創(chuàng)建 src\lang\index.ts,使用 createI18n 創(chuàng)建 i18n 實例:

                //?src\lang\index.ts
          import?{?createI18n?}?from?'vue-i18n'
          import?{?LANG_VALUE?}?from?'@/common/enum'
          import?zhHans?from?'./zh-Hans'
          import?en?from?'./en'

          const?i18n?=?createI18n({
          ??legacy:?false,
          ??locale:?getLanguage(),
          ??messages:?{
          ????[LANG_VALUE.Zh]:?zhHans,
          ????[LANG_VALUE.En]:?en
          ??}
          })
          export?default?i18n

          下面對傳入 createI18n() 的配置對象做些說明:

          • legacy:默認(rèn)為 true,但如果使用的是 Composition API 則需要定義為 false,否則會報類似下面的錯誤:
          63c92487bca4e466ecc3f9a90c3c1842.webp
          • locale:當(dāng)前要展示的語言。值為之前用戶的語言選擇,從瀏覽器緩存中讀取。如果緩存中沒有數(shù)據(jù),則通過 navigator.language 獲取瀏覽器使用的語言:
                //?src\lang\index.ts
          import?{?localCache?}?from?'@/utils'
          export?function?getLanguage()?{
          ??const?chooseLanguage?=?localCache.getItem(LANGUAGE)
          ??if?(chooseLanguage)?return?chooseLanguage

          ??//?如果沒有選擇語言
          ??const?language?=?navigator.language.toLowerCase()
          ??const?locales?=?[LANG_VALUE.En,?LANG_VALUE.Zh]
          ??for?(const?locale?of?locales)?{
          ????if?(language.indexOf(locale)?>?-1)?{
          ??????return?locale
          ????}
          ??}
          ??return?LANG_VALUE.Zh
          }

          因為 locale 值在多個文件中有使用到,所以我使用了 ts 新增類型 enum(枚舉類型)來保存:

                //?src\common\enum.ts
          export?enum?LANG_VALUE?{
          ??En?=?'en',
          ??Zh?=?'zh-Hans'
          }
          • messages:不同語言對應(yīng)的翻譯文件:

          中文翻譯包:

                //?src\lang\zh-Hans.ts
          export?default?{
          ??baoguochuku:?'包裹出庫',
          ??sousuo:?'搜索'
          }

          英文翻譯包:

                //?src\lang\en.ts
          export?default?{
          ??baoguochuku:?'Outbound',
          ??sousuo:?'Search'
          }

          在 main.ts 引入

                //?src\main.ts,省略其它代碼
          import?i18n?from?'./lang/index'
          app.use(i18n)

          在文件中使用

          vue 文件

          • <script lang="ts" setup> 中使用

          下面以側(cè)邊導(dǎo)航菜單中,對每條導(dǎo)航的名稱的配置為例。從 vue-i18n 中導(dǎo)入 useI18n,然后進(jìn)行調(diào)用生成 i18n 實例,再從里面解構(gòu)得到 t 方法,在第 6 行進(jìn)行使用 —— t(route.meta.title)route.meta.title 是我在路由里配置的內(nèi)容,其值就是在語言翻譯文件中定義的那些 key,比如 'baoguochuku' 等:

                <!-- src\components\Navigation\Navigation.vue,省略其它代碼 -->
          <script lang="ts" setup>
          import { useI18n } from 'vue-i18n'
          const { t } = useI18n()
          const menuOptions: MenuOption[] = modulesRoutes.map(route => ({
          label: () => t(route.meta.title),
          // ...
          }))
          </script>

          這里注意下 label 的值得寫成 getter 的形式,如果是寫成 label: t(route.meta.title) 這樣直接賦值,則切換語言時是沒有效果的。

          • <template> 中使用

          使用方法與之前在 vue2 中一樣:

                <template>
          <n-button>
          <slot name="submitBtnText">{{ $t('sousuo') }}</slot>
          </n-button>
          </template>

          這里之所以可以直接使用 $t 是因為有個叫做 globalInjection 的配置項默認(rèn)為 true,幫我們?nèi)肿⑷肓?$t 方法,如果設(shè)置為 false

                //?src\lang\index.ts
          const?i18n?=?createI18n({
          ??//?...
          ??globalInjection:?false
          })

          則會報錯:c6bbef5336167ce45d329cd0714e00dd.webp

          ts 文件

          在 ts 文件中,則需要引入我們之前在 src\lang\index.ts 配置生成的 i18n 實例,然后通過 i18n.global.t() 來定義文案:

                //?src\service\request\index.ts
          import?i18n?from?'@/lang'
          if?(!axios.isCancel(error))?{
          ??dialog.error({
          ????title:?i18n.global.t('tishi'),
          ????//?...
          ??})
          }

          至此,項目里我們自己添加的內(nèi)容的國際化就配置完成了,接下來是對 naive ui 組件的國際化配置。

          naive ui 組件

          對于 naive ui 的組件,默認(rèn)情況下均為英語,如果想改為中文,需要在根組件 src\App.vue 中使用 n-config-provider 對語言進(jìn)行配置,將用于設(shè)置全局語言的 locale 設(shè)為從 naive ui 導(dǎo)入的zhCN ,設(shè)置全局日期語言的 date-locale 為從 naive ui 導(dǎo)入的 dateZhCN

                <!-- src\App.vue -->
          <script setup lang="ts">
          import { storeToRefs } from 'pinia'
          import useAppStore from '@/stores/app'

          const appStore = useAppStore()
          const { locale, dateLocale } = storeToRefs(appStore)
          </script>

          <template>
          <n-config-provider
          :locale="locale"
          :date-locale="dateLocale"
          >
          <RouterView />
          </n-config-provider>
          </template>

          localedateLocale 作為由 pinia 管理的 getter 定義在 src\stores\app.ts:

                //?src\stores\app.ts
          import?{?defineStore?}?from?'pinia'
          import?{?zhCN,?dateZhCN?}?from?'naive-ui'
          import?{?LANG_VALUE?}?from?'@/common/enum'
          import?{?getLanguage?}?from?'@/lang'

          interface?IAppState?{
          ??language:?string
          ??//?...
          }

          const?useAppStore?=?defineStore('app',?{
          ??state:?():?IAppState?=>?({
          ????language:?getLanguage(),
          ????//?...
          ??}),
          ??getters:?{
          ????locale(state)?{
          ??????switch?(state.language)?{
          ????????case?LANG_VALUE.En:
          ??????????return?null
          ????????case?LANG_VALUE.Zh:
          ??????????return?zhCN
          ????????default:
          ??????????break
          ??????}
          ????},
          ????dateLocale(state)?{
          ??????switch?(state.language)?{
          ????????case?LANG_VALUE.En:
          ??????????return?null
          ????????case?LANG_VALUE.Zh:
          ??????????return?dateZhCN
          ????????default:
          ??????????break
          ??????}
          ????}
          ??},
          ??//?...
          })

          export?default?useAppStore

          當(dāng) language'en' 時,localedateLocale 就為 null;當(dāng) language'zh-Hans' 時,localedateLocale 就為 zhCNdateZhCN。而 language 的值由前面已經(jīng)介紹過了的 getLanguage() 獲取,首先是從瀏覽器緩存讀取用戶之前的選擇,而用戶是通過下面封裝的組件進(jìn)行語言選擇的。

          切換語言控件

          我選擇結(jié)合使用 naive ui 的 Popselect(彈出選擇)和 Icon(圖標(biāo))組件來實現(xiàn)切換語言的控件:

                <!-- src\components\LangSelect\LangSelect.vue -->
          <template>
          <div class="lang-select">
          <n-popselect
          v-model:value="value"
          :options="options"
          trigger="click"
          @update:value="handleUpdateValue"
          >
          <n-icon>
          <Language />
          </n-icon>
          </n-popselect>
          </div>
          </template>

          valueoptions 定義如下:

                <!-- src\components\LangSelect\LangSelect.vue -->
          <script lang="ts" setup>
          import { ref } from 'vue'
          import { storeToRefs } from 'pinia'
          import useAppStore from '@/stores/app'
          import { LANG_VALUE } from '@/common/enum'
          import type { SelectOption, SelectGroupOption } from 'naive-ui'

          const ENGLISH = 'English'
          const ZHONG_WEN = '中文'
          // 獲取當(dāng)前語言
          const appStore = useAppStore()
          const { language } = storeToRefs(appStore)
          // 彈出選擇 Popselect
          type valueType = string | null
          const value = ref<valueType>(getValue())
          function getValue() {
          switch (language.value) {
          case LANG_VALUE.En:
          return ENGLISH
          case LANG_VALUE.Zh:
          return ZHONG_WEN
          default:
          return ZHONG_WEN
          }
          }
          const options: Array<SelectOption | SelectGroupOption> = [
          {
          label: ENGLISH,
          value: ENGLISH
          },
          {
          label: ZHONG_WEN,
          value: ZHONG_WEN
          }
          ]
          </script>

          選項 options 就兩個:'English' 或 '中文'value 的默認(rèn)值根據(jù)存儲在 pinia 的 appStore 的 state language 決定。這里第 13 行使用 pinia 提供的 storeToRefs 處理是為了在解構(gòu)獲取 language 時保留其響應(yīng)式,其實用 vue3 的 toRefs 也可以。

          切換時觸發(fā)的 handleUpdateValue 定義如下:

                <!-- src\components\LangSelect\LangSelect.vue -->
          <script lang="ts" setup>
          import { setLocale } from '@/lang'

          let lang: langType
          function handleUpdateValue(value: valueType) {
          switch (value) {
          case ENGLISH:
          lang = LANG_VALUE.En
          break
          case ZHONG_WEN:
          lang = LANG_VALUE.Zh
          break
          default:
          break
          }
          setLocale(lang)
          }
          </script>

          將切換后的 value 傳給定義于 src\lang\index.ts(也就是前面配置 i18n 的文件) 的 setLocale() 處理:

                //?src\lang\index.ts
          export?function?setLocale(lang:?langType)?{
          ??//?獲取當(dāng)前語言
          ??const?appStore?=?useAppStore()
          ??const?{?language?}?=?storeToRefs(appStore)

          ??i18n.global.locale.value?=?lang?//?修改?i18n
          ??language.value?=?lang?//?修改?pinia
          ??localCache.setItem(LANGUAGE,?lang)?//?修改緩存
          }

          圖標(biāo)的使用

          順便說明下 naive ui 中圖標(biāo)的使用,圖標(biāo)選自 naive ui 文檔推薦的 xicons 圖標(biāo)庫,使用前需要根據(jù)所選用的圖標(biāo)做對應(yīng)的安裝:

                npm i -D @vicons/ionicons5

          然后進(jìn)行引入,并作為 <n-icon> 的默認(rèn)插槽內(nèi)容使用:

                <!-- src\components\LangSelect\LangSelect.vue -->
          <script lang="ts" setup>
          import { Language } from '@vicons/ionicons5'
          </script>
          <template>
          <n-icon>
          <Language />
          </n-icon>
          </template>
          解決控制臺警告

          做到這一步,如果打開瀏覽器控制臺,可能會看到如下警告:

          f198fa71ed240c5bd212c27cb1f0f84c.webp

          解決辦法是在 vite.config.ts 添加如下配置:

                export?default?defineConfig({
          ??//?...
          ??define:?{
          ????__VUE_I18N_FULL_INSTALL__:?true,
          ????__VUE_I18N_LEGACY_API__:?false,
          ????__INTLIFY_PROD_DEVTOOLS__:?false
          ??}
          })

          因為項目里都是使用 Composition API,無需啟用對選項式 api 的支持,所以 __VUE_I18N_LEGACY_API__ 的值由默認(rèn)的 true 改為了 false,其余兩項則維持默認(rèn)值。

          效果

          至此,本項目的國際化配置就完成了。最后來看一下效果(目前只做了部分文案的初步翻譯):

          140967fdf0cf68c79cfb43ebdf316990.webp

          參考資料

          [1]

          vue-i18n v9: https://github.com/intlify/vue-i18n-next

          前端大學(xué) 公眾號 祝 您:2023 年暴富!萬事如意! 分享前端干貨,點贊就是最大的支持,1b24fbd727dcc9d3e2303776929d71dc.webp比心??1b24fbd727dcc9d3e2303776929d71dc.webp
          瀏覽 139
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

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

          手機(jī)掃一掃分享

          分享
          舉報
          <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 |