vite-i18n-langtool 翻译规则提取工具

243 阅读3分钟

vite-i18n-langtool 使用文档

www.npmjs.com/package/vit…

介绍

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.jsvite.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'

配置项说明

配置项类型默认值说明
filesstring[][".vue", ".ts", ".tsx"]匹配需要提取文本的文件后缀
funRegNamestring[]["$t", "t"]用于提取文本的函数名,例如 t()$t()
strRegstring<t匹配自定义文本提取标记,例如 <t=要提取的文本>
jsonOutPathstringpublic/lang/zh-cn.json输出的语言文件路径
ignoreDirstring[]["node_modules", "dist", "public"]忽略的目录
ignoreFilesstring[][]忽略的文件
outlogbooleanfalse是否输出日志到文件
showMapFilebooleanfalse是否在终端输出匹配内容
hmr"ws" , "none"ws是否启用热更新,支持 wsnone
creactWsLangPathstringundefined是否创建 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. 忽略文件和目录

通过配置 ignoreDirignoreFiles,插件可以跳过某些目录和文件的文本提取。

开发模式下的使用

在开发模式下,插件会自动监听文件的变化,并在文件发生变化时触发相应的更新。如果启用了 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. 如何避免某些文件被提取?

你可以通过配置 ignoreDirignoreFiles 来忽略某些目录或文件。

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>

可在终端输出详情

image.png 重复匹配的会共用uuid

运行结果

image.png

总结一下

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 词条,那对前端国际化开发来说是一个很大的便利,主要体现在:

  1. 自动提取词条:避免手动查找、整理翻译词条,提高效率,减少遗漏。
  2. 兼容 Vite 生态:Vite 插件化的架构可以无缝集成,提高 DX(开发者体验)。
  3. 减少冗余词条:自动对比已有词库,避免重复定义翻译内容,这样即使新增页面也不会重新生成新的json文件。
  4. 适用于大项目:在多语言支持的项目中,尤其是 Vue 3 应用,能自动化管理 i18n 资源,减少维护成本。