專案地址https://github.com/goblin-pitcher/i18n-collector
老專案引入i18n
國際化後,需要對專案中所有中文包裹$t('中文')
方法,物件不同,包裹的方法也有差異:
- 在
vue
的template
中,直接對中文包裹$t('中文')
- 在
vue
的元件程式碼中,由於$t
是全域性引入,因此需包裹成this.$t('中文')
- 對於純
js
部分,需importi18n
模組,並對中文包裹i18n.t('中文')
- 對於帶數字的字串,如【
共計${count}條資料
】,需轉換為$t('共計count條資料', {count: 100})
的結構,轉換前的程式碼在不同地方可能有不一樣的表示,比如在vue
的template
中,轉換前的詞條可能是這樣:【共計{{count}}條資料
】
問題分析
面對此類問題,首先想到的自然是將程式碼轉換成ast
樹,對其中的中文字串進行處理,再轉換為程式碼,但實際會遇到以下幾個問題:
- 一般的parser(如
@bable/parser
)只能處理js
或jsx
檔案,無法處理vue
模板,利用vue-loader
將.vue
檔案轉換成.js
檔案雖然可以配合@bable/parser
進行解析,但轉換成.js
檔案後的程式碼,沒有相關的轉換器將其反過來轉換成.vue
程式碼,這和我們的需求不符 - 即使有
.vue
檔案的parser(如vue-eslint-parser
),但是沒有對應的traverse和generator工具,不能將解析的ast
反過來轉換成程式碼 - 即使有
.vue
檔案的parser、traverse、generator配套工具,重新生成的vue
程式碼格式很大概率無法滿足eslint
校驗,需要自動進行格式修正
解決思路
通過對當前問題的分析,目前面臨的問題有兩個:
- 需要有
.vue
檔案配套的解析、生成工具 - 解決轉換後程式碼的
eslint
格式問題
問題2可以通過在生成處理後的.vue
檔案時,執行專案中的eslint --fix
命令實現,若專案不校驗格式,自然不會安裝eslint
,但若校驗格式,則必定會安裝eslint
,也就是可以執行eslint --fix
命令。
當前主要矛盾是問題1,而觀察問題1,.vue
檔案中js
檔案有配套的轉換工具,主要矛盾集中在template
上,而目前雖然沒有template
的生成工具,但可以將其視作html
解析,template
特性的解析作為html parser
的外掛完成。
用法
npm i git+https://github.com/goblin-pitcher/i18n-collector.git -D
---------------------------------
npx i18n-collect
引數
引數名 | 簡寫 | 說明 | 預設值 |
---|---|---|---|
dir | d | 需要進行國際化處理的目錄 | ./ |
ignoredir | i | 需要忽略的檔案或者資料夾 如 -i car.js 會忽略掉所有以 car.js 結尾的檔案 | 無論傳不傳此引數,都會忽略掉i18n 資料夾 |
fix | f | 執行完collect之後是否自動執行eslint --fix, 預設開啟,--fix false即關閉eslint執行 | true |
配置
新建i18n-collect.config.js
檔案可傳入具體配置,預設配置如下:
const defConfig = {
// 轉換當前目錄下的檔案
dir: './',
// 忽略項
ignoredir: [],
// 是否執行eslint --fix
fix: true,
// 收集中文詞條的檔名
output: 'zh-CN.js',
// 檔案處理配置
file: {
// 模板中包裹中文的函式名,如$t('中文')
template: { prefix: "$t" },
// 對於純js檔案的處理
js: {
// 若有中文詞條需要提取,需要先引入i18n相關包才能包裹,該配置為新增引入檔案的配置
// 預設引入時新增 import {i18n} from '@/utils/i18n.utils'
addImport: {
from: "@/utils/i18n.utils",
data: ["i18n"],
},
// 包裹中文詞條的方法,如i18n.t('中文')
prefix: "i18n.t",
},
// .vue檔案中script包裹中文的方法, 如this.$t('中文')
// 遇到sparePrefix配置,即i18n.t('中文')的欄位,也會當作已包裹轉換方法的字串,而不會再用this.$t包裹一次
vue: { prefix: "this.$t", sparePrefix: 'i18n.t' }
}
};