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

          對國際化 i18n 項(xiàng)目的一點(diǎn)思考

          共 11241字,需瀏覽 23分鐘

           ·

          2022-10-21 14:20

          點(diǎn)擊上方 前端Q,關(guān)注公眾號

          回復(fù)加群,加入前端Q技術(shù)交流群

          國際化是什么?

          國際化 對應(yīng)的英文單詞為 Internationalization,又稱 **i18n**:

          • i 為單詞的 【第一個(gè)】 字母
          • 18 為 【**in 之間**】 單詞的個(gè)數(shù)
          • n 代表這個(gè)單詞的 【最后一個(gè)】 字母

          如果你的項(xiàng)目是 Vue,那么相信你在實(shí)現(xiàn)國際化功能時(shí),也必不可少的會(huì)使用到 **`vue-i18n`**[2] 這個(gè)庫,接下來本文也是通過這個(gè)庫搭配 Vue 實(shí)現(xiàn)最基本的國際化功能,但關(guān)注點(diǎn)并不是如何使用這個(gè)庫,而是在實(shí)現(xiàn)的過程中思考 可優(yōu)化的點(diǎn)。

          實(shí)現(xiàn)基本國際化功能

          這里就不再多余演示 demo 項(xiàng)目的創(chuàng)建過程了,并且文中只演示最基本的 中英文 切換,好了現(xiàn)在直奔核心吧!

          05873B02.jpg

          集成 vue-i18n

          安裝依賴

          熟悉的命令:npm install vue-i18n \-S

          配置 vue-i18n

          image.png
          • src 目錄下創(chuàng)建 language 目錄用于保持和語言切換相關(guān)的內(nèi)容
          • language 目錄下創(chuàng)建 lang 目錄用于保存不同語言的映射關(guān)系,如中文對應(yīng) zh.js、英文對應(yīng) en.js
          • language 目錄下創(chuàng)建 index.js 作為默認(rèn)導(dǎo)出,并在其中創(chuàng)建 i18n 對象

          import { createI18n } from "vue-i18n"; import zh from './lang/zh'; import en from './lang/en'; const i18n = createI18n({ legacy: false, locale: "zh", // 初始化配置語言 messages: { zh, en, }, });

          export default i18n; 復(fù)制代碼


          ### main.js 注冊 i18n

          內(nèi)容非常簡單,直接上代碼:

          ```js
          import { createApp } from "vue";
          import i18n from "./language";
          import store from "./store";
          import App from "./App.vue";

          createApp(App)
            .use(store)
            .use(i18n)
            .mount("#app");
          復(fù)制代碼

          實(shí)際上在通過 use(i18n) 時(shí),會(huì)調(diào)用 i18n.install() 方法,大概內(nèi)容如下:

          • 通過 app.provide(app.__VUE_I18N_SYMBOL__, i18n)i18n 對象提供給應(yīng)用中的所有后代組件可通過 inject 注入
          • 通過 app.config.globalProperties.xxx = xxx 的方式為應(yīng)用添加 全局屬性/方法,實(shí)際上是對 Vue2 中 Vue.prototype 使用方式的一種替代
            • 常見全局屬性,如 $i18n 通過 app.config.globalProperties.$i18n = i18n 添加到全局
            • 常見全局方法,如:$t, $rt, $d, $n, $tm 通過 Object.defineProperty(app.config.globalProperties, `$${method}`, desc) 添加到全局
          • 通過 aplly(...) 方法注冊常用的 全局指令 v-t全局組件 i18n
          • 在根組件卸載時(shí)移除/釋放 i18n 相關(guān)內(nèi)容
            const unmountApp = app.unmount;
            app.unmount = () => {
              i18n.dispose();
              unmountApp();
            };
            復(fù)制代碼
          • 注冊 vue-devtools 的相關(guān)插件

          根據(jù)數(shù)據(jù)信息填充國際化內(nèi)容

          頁面渲染

          假設(shè)需要渲染如下數(shù)據(jù)對應(yīng)的列表,并且要實(shí)現(xiàn)國際化:

          const data = [
            {
              url: vueImg,
              title'Vue',
              describe'漸進(jìn)式 JavaScript 框架'
            },
            {
              url: reactImg,
              title'React',
              describe'用于構(gòu)建用戶界面的 JavaScript 庫'
            },
            {
              url: angularImg,
              title'Angular',
              describe'現(xiàn)代 Web 開發(fā)平臺(tái)'
            },
            {
              url: nodeImg,
              title'Node',
              describe'Node.js 是一個(gè)基于 Chrome V8 引擎的 JavaScript 運(yùn)行時(shí)'
            },
            {
              url: webpackImg,
              title'Webpack',
              describe'webpack 是一個(gè)用于現(xiàn)代 JavaScript 應(yīng)用程序的靜態(tài)模塊打包工具'
            },
          ];
          復(fù)制代碼

          對應(yīng) App.vue 組件模板內(nèi)容如下:

          <template>
            <button class="btn" @click="changeLang">{{ $t("中/英") }}</button>
            <List :data="data" />
          </template>
          復(fù)制代碼

          對應(yīng)的頁面效果如下:

          image.png

          填充 lang 目錄下映射關(guān)系

          lang/zh.js 文件中:

          export default {
            "漸進(jìn)式 JavaScript 框架""漸進(jìn)式 JavaScript 框架",

            "用于構(gòu)建用戶界面的 JavaScript 庫""用于構(gòu)建用戶界面的 JavaScript 庫",

            "現(xiàn)代 Web 開發(fā)平臺(tái)""現(xiàn)代 Web 開發(fā)平臺(tái)",

            "Node.js 是一個(gè)基于 Chrome V8 引擎的 JavaScript 運(yùn)行時(shí)":
              "Node.js 是一個(gè)基于 Chrome V8 引擎的 JavaScript 運(yùn)行時(shí)",

            "webpack 是一個(gè)用于現(xiàn)代 JavaScript 應(yīng)用程序的靜態(tài)模塊打包工具":
              "webpack 是一個(gè)用于現(xiàn)代 JavaScript 應(yīng)用程序的靜態(tài)模塊打包工具",

            "中/英""中/英",
          };
          復(fù)制代碼

          lang/zh.js 文件中:

          export default {
            "漸進(jìn)式 JavaScript 框架""Progressive JavaScript framework",

            "用于構(gòu)建用戶界面的 JavaScript 庫":
              "JavaScript library for building user interface",

            "現(xiàn)代 Web 開發(fā)平臺(tái)""Modern web development platform",

            "Node.js 是一個(gè)基于 Chrome V8 引擎的 JavaScript 運(yùn)行時(shí)":
              "Node.js is a JavaScript runtime based on the chrome V8 engine",

            "webpack 是一個(gè)用于現(xiàn)代 JavaScript 應(yīng)用程序的靜態(tài)模塊打包工具":
              "Webpack is a static module packaging tool for modern JavaScript applications",

            "中/英""Chinese / English",
          };
          復(fù)制代碼

          <List /> 組件中進(jìn)行翻譯處理

          翻譯處理可通過如下方式處理:

          • 使用 $t(...) 方法
          • 使用 v-t 指令
          • 使用 <i18n-t></i18n-t> 組件

          這里選擇第一種,因?yàn)樗`活,能使用的范圍也更廣,指令和組件形式限定在了 template 中:

          效果演示

          1.gif

          優(yōu)化 i18n 配置

          基于以上簡單的例子,已經(jīng)能夠?qū)崿F(xiàn)了國際化切換功能,但其中需要考慮的優(yōu)化點(diǎn)還不少,下面的內(nèi)容僅屬于 拋轉(zhuǎn)引玉,不一定全面。

          05F51BEA.jpg

          優(yōu)化翻譯文件中的 key

          現(xiàn)在很明顯的一點(diǎn),就是 zh.js、en.js 文件中用于映射的 key 太長了,導(dǎo)致整個(gè)文件看起來會(huì)很多、很亂,因此我們可以將對應(yīng)的 key 進(jìn)行精簡,如下:

          // zh.js
          export default {
            "Vue 簡介""漸進(jìn)式 JavaScript 框架",
            
            "React 簡介""用于構(gòu)建用戶界面的 JavaScript 庫",

            "Angular 簡介""現(xiàn)代 Web 開發(fā)平臺(tái)",

            "Node 簡介""Node.js 是一個(gè)基于 Chrome V8 引擎的 JavaScript 運(yùn)行時(shí)",

            "Webpack 簡介":
              "webpack 是一個(gè)用于現(xiàn)代 JavaScript 應(yīng)用程序的靜態(tài)模塊打包工具",

            "中/英""中/英",
          };

          // en.js
          export default {
            "Vue 簡介""Progressive JavaScript framework",

            "React 簡介""JavaScript library for building user interface",

            "Angular 簡介""Modern web development platform",

            "Node 簡介""Node.js is a JavaScript runtime based on the chrome V8 engine",

            "Webpack 簡介":
              "Webpack is a static module packaging tool for modern JavaScript applications",

            "中/英""Chinese / English",
          };
          復(fù)制代碼

          那么對應(yīng)到外部傳入需要渲染的數(shù)據(jù)源 data 就可以簡寫為:

          const data = [
            {
              url: vueImg,
              title"Vue",
              describe"Vue 簡介",
            },
            {
              url: reactImg,
              title"React",
              describe"React 簡介",
            },
            {
              url: angularImg,
              title"Angular",
              describe"Angular 簡介",
            },
            {
              url: nodeImg,
              title"Node",
              describe"Node 簡介",
            },
            {
              url: webpackImg,
              title"Webpack",
              describe"Webpack 簡介",
            },
          ];
          復(fù)制代碼

          另一種精簡方式就是將 key 用對應(yīng)的類似于 變量命名 的方式來定義,但我個(gè)人不是很喜歡這種方式,首先在語義上很難直接讀出相關(guān)信息,而且很難用一兩個(gè)英文單詞去概括文字內(nèi)容,而且在后期需要排查對應(yīng)問題并需要定位 tmeplate 時(shí)是極其不方便.

          轉(zhuǎn)換翻譯文件類型

          .js 轉(zhuǎn) .json

          上述的翻譯文件是 .js 文件,因此,為了能夠讓其能被其他文件導(dǎo)入,我們不得不在文件中使用 export defualtexport 將對應(yīng)文件內(nèi)容向外導(dǎo)出,但其實(shí)我們可以將 .js 文件轉(zhuǎn)換為 .json 文件直接使用,如下:

          excel 轉(zhuǎn) .json

          在實(shí)際項(xiàng)目中翻譯的內(nèi)容通常是由業(yè)務(wù)專門找對應(yīng)的翻譯人員提供的,而真正到了開發(fā)者手中往往就是一個(gè) excel 類型的表格文件,如果我們使用的是前面的純 json 方式,免不了要自己一個(gè)一個(gè)從表格中復(fù)制對應(yīng)的內(nèi)容到我們對應(yīng)的 .json 文件中,而且是分別填充到 zh.jsonen.json 中,值得注意的是現(xiàn)在才是僅支持兩個(gè)國家的語言,如果后續(xù)支持的國家變多,那么手動(dòng)復(fù)制的方式豈不是要

          因此,最好的做法是我們根據(jù)業(yè)務(wù)方提供的表格自動(dòng)轉(zhuǎn)成 json 格式的數(shù)據(jù),避免不必要的手動(dòng)操作,用命令幫我們處理這個(gè)內(nèi)容:

          • 安裝依賴 npm install xlsx-to-json

          • 將對應(yīng)的轉(zhuǎn)換操作封裝 excel2json.js 文件中,基于第三方庫簡單封裝即可

            const xlsx2json = require("xlsx-to-json");
            const path = require("path");

            xlsx2json(
            {
              input: path.join(__dirname, "./i18n.xlsx"),
              output: path.join(__dirname, "./i18n.json"),
            },
            function (err, result{
              if (err) {
                console.error(err);
              } else {
                console.log(result);
              }
            }
            );
            復(fù)制代碼
          • 修改 i18n 配置的入口文件 src\language\index.js

            import { createI18n } from "vue-i18n";
            import i18njson from "./i18n.json";

            // 動(dòng)態(tài)獲取 message 信息
            function getMessage() {

          const messages = { zh: {}, en: {} }; i18njson.forEach(({Short, Chinese, English}) => { messages.zh[Short] = Chinese; messages.en[Short] = English; }); return messages; }

          const i18n = createI18n({ legacy: false, locale: "zh", // 初始化配置語言 messages: getMessage(), });

          export default i18n; 復(fù)制代碼


          - 提供 `i18n.xlsx` 文件作為數(shù)據(jù)源

          ![](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/48e8dc4d4cf8411e9884d42f1f4b9728~tplv-k3u1fbpfcp-zoom-in-crop-mark:3024:0:0:0.awebp?)

          - 在 `package.json` 問文件中添加對應(yīng)轉(zhuǎn)換命令

          ```js
          "scripts": {
              "dev""vite",
              "build""vite build",
              "preview""vite preview",
              "i18n""node ./src/language/excel2json.js"
            }
          復(fù)制代碼

          具體效果如下:

          升級為 i18n 系統(tǒng)

          上面已經(jīng)將對應(yīng)的翻譯包從 *.xlsx 轉(zhuǎn)成了 *.json 的形式,這樣一定程度上能減少重復(fù)勞動(dòng)力,但在 復(fù)用/協(xié)作 方面還是不夠理想,因此可以從更高的維度將這整個(gè)內(nèi)容升級到 i18n 系統(tǒng),并提供對應(yīng)的翻譯包上傳、自動(dòng)解析、去重、添加命名空間等功能,再加上對應(yīng)的列表管理功能,重點(diǎn)是可供多人員、多系統(tǒng)進(jìn)行 復(fù)用/協(xié)作,對前端來講就可以通過 接口 獲取對應(yīng)的翻譯包數(shù)據(jù),也能減少前端最終構(gòu)建產(chǎn)物的體積。

          處理翻譯文件中重復(fù)的內(nèi)容

          06A99BDD.gif

          什么叫重復(fù)的內(nèi)容呢?其實(shí)很簡單,比如有個(gè)文字內(nèi)容為 確認(rèn) 按鈕,它在 A 頁面需要翻譯為 Confirm,它在 B 頁面需要翻譯為 OK,而它的中文內(nèi)容就是 **確認(rèn)**,意味著它對應(yīng)的數(shù)據(jù)內(nèi)容為:

          [
            { "Short""確認(rèn)""Chinese""確認(rèn)""English""Confirm" },
            { "Short""確認(rèn)""Chinese""確認(rèn)""English""OK" }
          ]
          復(fù)制代碼

          但這樣其實(shí)是不行的,這樣最終會(huì)被后面的內(nèi)容覆蓋掉,即 A、B 頁面最終的翻譯內(nèi)容都為 OK,因?yàn)閿?shù)據(jù)中的 Short 其實(shí)就是最終的不同語言映射的 key,如下:

          const messages = {
              zh: {
               "確認(rèn)""確認(rèn)",
               "確認(rèn)""確認(rèn)"
              },
              en: {
               "確認(rèn)""Confirm",
               "確認(rèn)""OK"
              }
          };
          復(fù)制代碼

          既然這樣,那么其實(shí)我們只要為不同的翻譯內(nèi)容設(shè)置不同的 Short 值即可,如下:

          [
            { "Short""確認(rèn)1""Chinese""確認(rèn)""English""Confirm" },
            { "Short""確認(rèn)2""Chinese""確認(rèn)""English""OK" }
          ]
          復(fù)制代碼

          這樣變動(dòng)小,并且也沒有丟失掉原本的語義。

          考慮不同語言的樣式

          由于不同語言的表現(xiàn)形式不同,內(nèi)容長度也不一致,因此在前端進(jìn)行展示時(shí),就必須要考慮到最終的顯式問題,否則一旦切換語言環(huán)境那么一定會(huì)導(dǎo)致頁面的布局展示出現(xiàn)問題,處理方式無非幾種:

          • 允許文字內(nèi)容換行展示,在文字發(fā)生換行時(shí),要通過 CSS 設(shè)置按完整詞換行

          • 不允許換行的,就要控制固定寬度,超出部分打點(diǎn)展示,鼠標(biāo)移入展示全部內(nèi)容等

          • 單獨(dú)為不同語言環(huán)境設(shè)置樣式,具體還是得看展示需求,如需要考慮不同語言環(huán)境下文字的對齊方式、文字間距等

          • 針對難以處理的翻譯內(nèi)容,可以通過和業(yè)務(wù)溝通是否可以替換翻譯內(nèi)容、縮減文字長度等等

            06C8791C.png

          考慮后端接口語言環(huán)境變更

          一個(gè)項(xiàng)目的國際化不可能都是前端來實(shí)現(xiàn)的,一些接口動(dòng)態(tài)返回的內(nèi)容也是需要后端去處理的,通常接口的請求頭中會(huì)存儲(chǔ)一個(gè)用于標(biāo)識當(dāng)前頁面語言環(huán)境的字段,然后再?zèng)Q定返回給前端頁面的具體內(nèi)容。

          06D25789.jpg

          基于前面處理的國家化切換功能,本身是會(huì)基于 vue 的響應(yīng)式來切換翻譯內(nèi)容的,即不會(huì)刷新頁面,因此在切換對應(yīng)翻譯內(nèi)容后,同樣需要修改后續(xù)接口請求頭中的語言環(huán)境。

          但這樣還是有問題的,已經(jīng)通過接口返回的數(shù)據(jù)內(nèi)容,此時(shí)沒有辦法切換成對應(yīng)的翻譯內(nèi)容,因?yàn)楫?dāng)前的國際化切換是基于頁面的變動(dòng),但基于接口變動(dòng)的部分還沒重新請求獲取新的內(nèi)容,那怎么處理呢?

          • 前端切換語言環(huán)境后,重新刷新頁面,讓接口也重新獲取新的內(nèi)容
          • 后端在返回?cái)?shù)據(jù)時(shí),將對應(yīng)的不同語言環(huán)境的翻譯內(nèi)容一起返回,由前端根據(jù)語言環(huán)境決定如何渲染
          • 將所有的翻譯內(nèi)容全部交由前端管理,一開始就初始化好各個(gè)語言環(huán)境對應(yīng)的翻譯內(nèi)容

          最后

          以上內(nèi)容是基于國際化功能的一點(diǎn)思考,文中對應(yīng)的思考點(diǎn)是筆者自己在項(xiàng)目中遇到的點(diǎn),并不一定適合所有項(xiàng)目,當(dāng)然也期待評論區(qū)給出更多、更好的方案。

          關(guān)于本文

          作者:熊的貓

          https://juejin.cn/post/7131737709231472670

          往期推薦


          純前端實(shí)現(xiàn)「羊了個(gè)羊」小游戲
          你的圖片加載,一點(diǎn)都不酷炫!不信 You Look Look
          qiankun微前端改造實(shí)戰(zhàn),超級詳細(xì) Vue 代碼干貨篇!

          最后


          • 歡迎加我微信,拉你進(jìn)技術(shù)群,長期交流學(xué)習(xí)...

          • 歡迎關(guān)注「前端Q」,認(rèn)真學(xué)前端,做個(gè)專業(yè)的技術(shù)人...

          點(diǎn)個(gè)在看支持我吧

          瀏覽 69
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

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

          手機(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>
                  超碰在线免费成人午夜剧场97 | 天天天天射天天天搞天天要 | 三级片精品播放 | h片免费在线观看视频 | A级视频在线观看不卡一二三四区 |