[筆記] 在 Vite 上安裝 eslint-plugin-vue-i18n

Eason Lin
12 min readJan 17, 2025

--

Photo by Mark König on Unsplash

eslint-plugin-vue-i18nvue-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 srcsrc 資料夾內進行 lint ,就會跳出錯誤:

6:1  error  Unexpected mutation of "msg" prop  vue/no-mutating-props

恢復異動後,我們就可以來安裝 vue-i18n

pnpm add vue-i18n@10

建立 src/locales 資料夾,並新增 zh-TW.jsonen-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:

--

--

Eason Lin
Eason Lin

Written by Eason Lin

Frontend Web Developer | Books

No responses yet