eslint-plugin-vue-i18n
是 vue-i18n
官方團隊另外做的 ESLint Plugin,可以用其去抓一些 i18n
實作上可能會犯的錯,例如傳入不存在的 key。因為官方文件寫得不是很清楚、範例也都還是 Vue 2 的,這篇文就詳細記錄一下安裝 eslint-plugin-vue-i18n
的方式。
這邊有一份實作完成的 Repo,裡面是用 Vue 3 + TS5 + i18n,如果懶得讀文字歡迎直接 Fork 或 Clone 過去嘗試,當然也可以參考我接下來的筆記。
開始
首先,我們從 Vite 建立一個 Vue 專案:
pnpm create vite vue-eslint-i18n --template vue-ts
cd vue-eslint-i18n
pnpm install
完成安裝後,安裝 eslint
:
pnpm create @eslint/config@latest
完成選擇後,可以先試試看在 src/components/HelloWorld.vue
中撰寫一行違反規定的程式碼:
<script setup lang="ts">
import { ref } from 'vue'
const props = defineProps<{ msg: string }>()
// 違反 vue/no-mutating-props
props.msg += ' with Vite'
const count = ref(0)
</script>
// ...
在終端機執行 npx eslint src
對 src
資料夾內進行 lint ,就會跳出錯誤:
6:1 error Unexpected mutation of "msg" prop vue/no-mutating-props
恢復異動後,我們就可以來安裝 vue-i18n
:
pnpm add vue-i18n@10
建立 src/locales
資料夾,並新增 zh-TW.json
和 en-US.json
mkdir src/locales
touch src/locales/zh-TW.json
touch src/locales/en-US.json
src/locales/zh-TW.json
資料如下:
{
"message": {
"hello": "你好",
"goodbye": "再見",
"welcome": "歡迎來到世界"
},
"description": "描述"
}
src/locales/en-US.json
資料如下:
{
"message": {
"hello": "hello world",
"goodbye": "goodbye world",
"welcome": "welcome to the world"
},
"description": "This is a description"
}
src/i18n.ts
內容如下:
import { createI18n, type I18nOptions } from 'vue-i18n'
import enUS from './locales/en-US.json'
import zhTW from './locales/zh-TW.json'
export type MessageSchema = typeof enUS
const options: I18nOptions = {
legacy: false,
locale: 'en-US',
fallbackLocale: 'en-US',
messages: {
'en-US': enUS,
'zh-TW': zhTW
}
}
export const i18n = createI18n<false, typeof options>(options)
修改 src/main.ts
import { createApp } from 'vue'
import { i18n } from './i18n'
import './style.css'
import App from './App.vue'
createApp(App).use(i18n).mount('#app')
及 src/App.vue
<script setup lang="ts">
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const description = t('description')
</script>
<template>
<div>
<div>{{ t('message.goodbye') }}</div>
<div>{{ t('message.welcome') }}</div>
<div>{{ description }}</div>
</div>
</template>
<style></style>
輸入 pnpm dev
並進入 localhost:5173
,應該可以看到畫面:
接下來就可以安裝 eslint-plugin-vue-i18n
,關閉 dev 伺服器,並輸入:
pnpm add @intlify/eslint-plugin-vue-i18n
在 eslint.config.js
中新增:
import globals from "globals";
import pluginJs from "@eslint/js";
import tseslint from "typescript-eslint";
import pluginVue from "eslint-plugin-vue";
import vueI18n from "@intlify/eslint-plugin-vue-i18n"; // 新增這行
/** @type {import('eslint').Linter.Config[]} */
export default [
{
files: ["**/*.{js,mjs,cjs,ts,vue}"]
},
{
languageOptions: {
globals: globals.browser
}
},
pluginJs.configs.recommended,
...tseslint.configs.recommended,
...pluginVue.configs["flat/essential"],
...vueI18n.configs['flat/recommended'], // 新增這行
{ // 新增這段
settings: {
'vue-i18n': {
localeDir: './src/locales/*.{json,json5,yaml,yml}',
messageSyntaxVersion: '^10.0.0'
},
}
},
{
files: ["**/*.vue"],
languageOptions: { parserOptions: { parser: tseslint.parser } },
}
];
...vueI18n.configs['flat/recommended']
這行可以簡單理解為「採用 eslint-plugin-vue-i18n 推薦的規則」;
{ // 新增這段
settings: {
'vue-i18n': {
localeDir: './src/locales/*.{json,json5,yaml,yml}',
messageSyntaxVersion: '^10.0.0'
},
}
},
這段則是指定 localeDir
的位置及告知 eslint-plugin-vue-i18n
我們使用的 vue-i18n
版本,回到推薦的規則,例如 no-missing-keys。假如在 Vue 組件中輸入了一個不存在於 locales
內的 key:
// src/App.vue
<script setup lang="ts">
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const description = t('description')
</script>
<template>
<div>
<div>{{ t('message.goodbye') }}</div>
<div>{{ t('message.welcome') }}</div>
<div>{{ t('message.sorry') }}</div>
<div>{{ description }}</div>
</div>
</template>
<style></style>
如果這時候跑 npx eslint src
,應該會看到:
11:13 warning 'message.sorry' does not exist in localization message resources @intlify/vue-i18n/no-missing-keys
此外,應該也會看到許多 no-raw-text 的警告出現,因為 Vite 建立的 vue 專案預設並沒有考慮使用者會需要 i18n。
在繼續進行前,可以將 eslint 的一些警告進行清除。進入 src/components/HelloWorld.vue
並修改:
<script setup lang="ts">
defineProps<{ msg: string }>()
</script>
<template>
<h1>{{ msg }}</h1>
</template>
此時輸入 npx eslint src
應該不會有任何文字出現,因為專案已通過所有檢查。
eslint-plugin-vue-i18n
還提供了一些可選擇加入的檢查,例如 no-missing-keys-in-other-locales 可以為開發者檢查是不是所有 locale 都是一致的。例如在 src/locale/en-US.json
加入 sorry
:
{
"message": {
"hello": "hello world",
"goodbye": "goodbye world",
"welcome": "welcome to the world",
"sorry": "sorry"
},
"description": "This is a description"
}
並在 eslint.config.js
中加入這個規則:
import globals from "globals";
import pluginJs from "@eslint/js";
import tseslint from "typescript-eslint";
import pluginVue from "eslint-plugin-vue";
import vueI18n from "@intlify/eslint-plugin-vue-i18n";
/** @type {import('eslint').Linter.Config[]} */
export default [
{
files: ["**/*.{js,mjs,cjs,ts,vue}"]
},
{
languageOptions: {
globals: globals.browser
}
},
pluginJs.configs.recommended,
...tseslint.configs.recommended,
...pluginVue.configs["flat/essential"],
...vueI18n.configs['flat/recommended'],
{
rules: {
'@intlify/vue-i18n/no-missing-keys-in-other-locales': 'error', // 新增這行
},
settings: {
'vue-i18n': {
localeDir: './src/locales/*.{json,json5,yaml,yml}',
messageSyntaxVersion: '^10.0.0'
},
}
},
{
files: ["**/*.vue"],
languageOptions: { parserOptions: { parser: tseslint.parser } },
}
];
’@intlify/vue-i18n/no-missing-keys-in-other-locales’: ‘error’
可以簡單理解為:若開發者違反了「no-missing-keys-in-other-locales」,我需要在 eslint 執行時回報錯誤。
輸入 npx eslint src
,應該就會如期跳出錯誤:
6:5 error 'message.sorry' does not exist in 'zh-TW' locale(s) @intlify/vue-i18n/no-missing-keys-in-other-locales
我們也可以針對預設的 eslint 檢查行為進行複寫。例如當我們希望嚴格看管 no-raw-text 的規則時:
rules: {
'@intlify/vue-i18n/no-missing-keys-in-other-locales': 'error',
'@intlify/vue-i18n/no-raw-text': 'error', // 新增這行
},
直接在 rules
新增,便可將預設的 warning 轉為 error。提升 eslint 的回報層級有許多好處,例如在 CI 中可以因為 eslint 的 error 而將此 CI 中斷,等同藉由機器來盯著我們把程式給寫好。
其他的規則就不一一詳細說明,都可以在此參照。
結語
以上就是 eslint-plugin-vue-i18n 的安裝及使用筆記,目前我們的產品 ESLint 正在進行升級,未來若沒意外應該會引用其來讓 locale 變得更乾淨。希望這篇文有幫助到你,若有任何問題或需要更正的地方也都可以留言給我,祝安裝順利!
References: