vite-i18n-langtool 使用文档
介绍
vite-i18n-langtool 是一个用于提取项目中的内容的 Vite 插件。它通过解析代码中的特定方法(例如 t() 或 $t())或自定义标记来提取字符串文本,生成 UUID,并输出一个包含所有提取文本的 JSON 文件。
该插件支持热更新 (HMR) 以及文件监听,可在开发过程中ws更新提取内容,可用于多语言同步提取。
安装
首先,确保你已经安装了 Vite 项目。然后通过 npm 或 yarn 安装插件:
npm install vite-i18n-langtool --save-dev
或者使用 yarn:
yarn add vite-i18n-langtool --dev
默认配置
你可以在 vite.config.js 或 vite.config.ts 文件中配置此插件。以下是插件的配置项:
import { defineConfig } from 'vite'
import viteI18nLangtool from 'vite-i18n-langtool'
export default defineConfig({
plugins: [
viteI18nLangtool({
files: [".vue", ".ts", ".tsx"], // 匹配文件后缀
funRegName: ["$t", "t"], // 提取方法
strReg: "<t", // 匹配字段
jsonOutPath: "public/lang/zh-cn.json", // 输出语言文件路径
ignoreDir: ["node_modules", "dist"], // 忽略的目录
ignoreFiles: [], // 忽略的文件
outlog: false, // 是否输出日志
showMapFile: false, // 是否在终端输出匹配内容
hmr: "ws", // WebSocket 热更新
creactWsLangPath: "src/lang/hmr.js" // 创建 HMR 文件
})
]
})
温馨提示:如果不想走hot监听事件 可以让 hmr='node'
配置项说明
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
files | string[] | [".vue", ".ts", ".tsx"] | 匹配需要提取文本的文件后缀 |
funRegName | string[] | ["$t", "t"] | 用于提取文本的函数名,例如 t() 或 $t() |
strReg | string | <t | 匹配自定义文本提取标记,例如 <t=要提取的文本> |
jsonOutPath | string | public/lang/zh-cn.json | 输出的语言文件路径 |
ignoreDir | string[] | ["node_modules", "dist", "public"] | 忽略的目录 |
ignoreFiles | string[] | [] | 忽略的文件 |
outlog | boolean | false | 是否输出日志到文件 |
showMapFile | boolean | false | 是否在终端输出匹配内容 |
hmr | "ws" , "none" | ws | 是否启用热更新,支持 ws 或 none |
creactWsLangPath | string | undefined | 是否创建 HMR 热更新监听文件,指定 .js 或 .ts 文件路径 |
插件功能
1. 文本提取
插件会自动扫描指定文件中的文本,使用 t() 或 $t() 函数,或者自定义的 strReg 配置来提取需要翻译的文本。每个提取的文本都会生成一个唯一的 UUID。
<div>{{ t('文本') }}</div>
<div>{{ $t('文本') }}</div>
<div>{{ t('你好!{name}',{name:'vite-i18n-langtool'}) }}</div>
<div>{{ t('我是多重文本!{text}',{text:t('我是二次文本,{text}',{text:'没有了'})}) }}</div>
<div>{{ t(text) }}</div>
<div>{{ t(text1,{age:'10'}) }}</div>
<script setup>
//.....
const text = '<t=文本03' //这边字符串需要特殊写法 "<t=" 默认strReg="<t"
const text1 = '<t=年龄:{age}'
// 错误栗子
const txt3 = '"<t=年龄:{age}' +"兴趣:{interest}" //可能被匹配错误
// "<t=年龄:{age}' +" => const text3 = '"uuid"兴趣:{interest}" 文件可能发生根本性错误
const txt4 = '"<t=年龄:{age}' +'兴趣:{interest}"' //可能被匹配错误
// "<t=年龄:{age}' +" => const text3 = '"uuid"兴趣:{interest}" 文件可能发生根本性错误
const txt5 = '"<t=匹配成功了但是显示还是UUId"' //匹配的 t('"uuid"') json 找不到 '"uuid"'
const txt6 = '<t="年龄:{age}兴趣:{interest}"' //==> <div>{{ $t(text3,{age:'10',interest:'唱跳'}) }}
</script>
2. 输出语言文件
插件会将提取的所有文本存储在指定的 JSON 文件中,并以 UUID 作为键,文本内容作为值。例如:
{
"123456": "XXXXXXX",
"789101": "XXXXXXX"
// ····
}
3 HMR (热更新) hmr='ws' 通过ws传输更新 阻止jsonOutPath文件变化页面自动刷新
如果是启用 HMR.Hot,插件会在所有语言提取通过 WebSocket 将更新推送到浏览器,从而无需重新加载页面。
//开发模式下 - 通过ws更新语言库 也可以直接生成文件
import.meta.hot?.on('lang-update', setLang)
3.2 HMR (刷新更新) hmr='none' 不做阻止vite处理-页面会出现刷新
如果是默认 HMR,插件不会做处理 WebSocket 处理自定义的,默认会自动重新刷新页面。
4. 日志输出
当启用 outlog 配置时,插件会将提取日志输出到 jsonOutPath 相同目录 log.json 文件,方便开发者查看哪些文本被提取和处理。
5. 忽略文件和目录
通过配置 ignoreDir 和 ignoreFiles,插件可以跳过某些目录和文件的文本提取。
开发模式下的使用
在开发模式下,插件会自动监听文件的变化,并在文件发生变化时触发相应的更新。如果启用了 hmr=ws,语言文件会通过 WebSocket 推送到浏览器端。
如果需要手动触发 HMR 更新,可以在代码中使用 import.meta.hot.on('lang-update', (data) => {}) 来监听并更新语言数据。
打包时的处理
在打包过程中,插件会确保语言文件包含在构建产物中。语言文件会被写入到指定的路径,并且会根据配置生成语言映射文件。
public/lang/zh-cn.json 打包后 [dist]/lang/zh-cn.json
常见问题
1. 为什么语言文件没有更新?
如果你发现语言文件没有更新,可能是因为没有启用 HMR 或者 hmr 配置为 none。确保正确配置了 HMR,并且在文件变化时触发更新。
2. 如何避免某些文件被提取?
你可以通过配置 ignoreDir 和 ignoreFiles 来忽略某些目录或文件。
3. 开发下如何触发语言更新? ws 模式下
在开发模式下,项目内你可以自动接收语言文件的更新
// 仅在开发模式下
import.meta.hot?.on('lang-update', setLang);
文件测试案例
<template>
<div>
<div>
<br />
{{
$t('测试匹配{v1},{v2}', {
v1: $t('测试匹配{v11}', { v11: 1234 }),
v2: $t('测试匹配{v21},{v22}', {
v21: $t('测试匹配2{v}', { v: 1234 }),
v22: $t('测试匹配3')
})
})
}}
<br />
<div>{{ $t('测试匹配') }}</div>
<div v-html="$t('我一个html')"></div>
<div v-html="$t('我一个{html}', { html: $t(`<b style='color:{color}'>我是html参数元素是参数</b>`, { color: 'red' }) })"></div>
<div v-html="$t('我一个{html}', { html: `<b>我是html参数</b>` })"></div>
{{
$t('测试匹配{v1},{v2}', {
v1: $t('测试匹配{v11}', { v11: 1234 }),
v2: $t('测试匹配{v21},{v22}', {
v21: $t('测试匹配2{v}', { v: 1234 }),
v22: $t('测试匹配3')
})
})
}}
<br />
{{ tt('tt方法测试匹配') }}
<br />
</div>
{{ data.t('我是data.t内方法') }}
<p v-for="item in scu" :key="item.txt">{{ $t(item.txt, { num: 'www' }) }}</p>
</div>
</template>
<script lang="ts">
import { t } from '@/lang';
import { defineComponent } from 'vue';
export default defineComponent({
setup(props, context) {
const scu = [
{ txt: '<t=我是文本011' },
{ txt: '<t="我是文本012"' },
{ txt: "<t='我是文本013'" },
{ txt: '<t=我是文本02{num}' },
{ txt: '<t=我是文本03"{num}"' },
{ txt: '<t=以下都是错误栗子' },
{ txt: '"<t=我是文本03"多个引号引发错误' },
{ txt: '‘<t=我是文本03"中文【‘】开头不被提取"' },
{ txt: '“<t=我是文本03中文【“】开头不被提取"' },
{ txt: '"<t=我是文本可以提取"' + "【'\"】连续引发提取 提取错误后 'uuid' t(\"'uuid'\")错的 " },
{ txt: '<t=我是文' + 'q' + '本03"{num}"' },
{ txt: t('"<t=我是文' + '奇怪的"' + '本03"{num}"') },
{ txt: '<t=我是文本03"{num}"' + '<t=sdfsdfsd' }
];
return {
scu,
tt: (str: string) => '不会匹配' + str,
data: {
t(uuid: string) {
return '我会被匹配的' + uuid + '除了翻译尽可能不用名称t方法和$t方法';
}
}
};
}
});
</script>
可在终端输出详情
重复匹配的会共用uuid
运行结果
总结一下
1.大部分文本提取是没问题,插件提取也是按方法提取作者提供funRegNam 使用可以尽可能避开常用方法
2. 字符串转uuid部分const uid = "<t=提取内容" 参数调用 <div>{{t(uid)}}</div> 方便用户规划部分字符串 一个小小建议 strReg='lt' 这种最好不要 有可能刚好有参数【'lt=】但是按【"<t=】命名上不合法就不会冲突 <div @click='lt="赋值"'> 按钮</div> 可能就会匹配导致错误
3.就是热更新问题 如果用的是ws模式 需要按文档
import.meta.hot?.on('lang-update', setLang) 进行数据更新 这边接收到的数据是全部提取的json
如果用node 则会走vite机制 刷新触发api更新调用 我测试是直接走none模式也就是vite默认的
vite-i18n-langtool 插件只要按规则就能完整提取 i18n 词条,那对前端国际化开发来说是一个很大的便利,主要体现在:
- 自动提取词条:避免手动查找、整理翻译词条,提高效率,减少遗漏。
- 兼容 Vite 生态:Vite 插件化的架构可以无缝集成,提高 DX(开发者体验)。
- 减少冗余词条:自动对比已有词库,避免重复定义翻译内容,这样即使新增页面也不会重新生成新的json文件。
- 适用于大项目:在多语言支持的项目中,尤其是 Vue 3 应用,能自动化管理 i18n 资源,减少维护成本。