Skip to content

翻译工作流 ​

本页介绍核心翻译操作:翻译单文件、翻译文件夹、一致性检查和回滚。

加载语言 ​

可选:在正式开始翻译生成之前的准备工作,自动加载指定目录下的 json。以下是 webpack 和 vite 的常用方式:

webpack ​

js
const enContext = require.context('./module', true, /\/en-US\.json$/)
const zhContext = require.context('./module', true, /\/zh-CN\.json$/)

const contextToModuleMap = (context) => Object.fromEntries(context.keys().map((key) => [key, context(key)]))

const enMds = contextToModuleMap(enContext)
const zhMds = contextToModuleMap(zhContext)

const getLocaleCollect = (m) => Object.values(m).reduce((o, k) => ({ ...o, ...k }), {})

const enUsCollect = getLocaleCollect(enMds)
const zhCnCollect = getLocaleCollect(zhMds)

vite ​

js
const enMds = import.meta.glob('./module/**/en-US.json', { eager: true, import: 'default' })
const zhMds = import.meta.glob('./module/**/zh-CN.json', { eager: true, import: 'default' })

const getLocaleCollect = (m) => Object.values(m).reduce((o, k) => ({ ...o, ...k }), {})

const enUsCollect = getLocaleCollect(enMds)
const zhCnCollect = getLocaleCollect(zhMds)

翻译单文件 ​

hitf tf 用于翻译一个文件。它会提取源语言文案、生成 key、写入语言包,并把源文件中的文案替换为国际化调用。

默认兼容中文源码项目。配置 locales: ["en-US", "zh-CN", "ja-JP"] 后,可以提取英文文案并翻译到 zh-CN 和 ja-JP。

基本命令 ​

sh
hitf tf views\demo\index.vue

支持常见文件类型:

类型说明
.vueVue SFC,包含 <template>、<script>、<script setup>
.js / .tsJavaScript 和 TypeScript 业务代码
.jsx / .tsxReact JSX / TSX
.jsonJSON 文案值

基本选项 ​

sh
hitf tf src\views\demo\index.vue demo -d
hitf tf src\views\demo\index.vue demo -i
hitf tf src\views\demo\index.vue demo -r .hitf\reports\demo.json
hitf tf apps\main\src\views\index.vue home -p main
选项简写说明
-n, --name <name>-n国际化对象 key(默认使用父级目录名)
-p, --project <project>-poutDir 为对象时指定项目
-d, --dry-run-d仅预览翻译计划:逐项列出提取文本与位置,不执行翻译、不写文件
-i, --interactive-i树形多选要翻译的文本;未选中的项自动添加忽略注释,不参与翻译
-r, --report <file>-r写入 JSON 翻译报告
-v, --verbose-v输出详细日志

预览模式 ​

-d / --dry-run 仅预览翻译计划:不调用翻译、不写入任何文件。单文件 tf 逐项列出提取的文本及其源码位置(文件:行:列),并附被跳过(未提取)的字符串及原因:

sh
hitf tf src\views\demo\index.vue -d

输出示例:

text
  合适 → src/views/demo/index.vue:2:21
  测试 → src/views/demo/index.vue:3:21

tf -d 不会生成语言包、不会修改源码,适合在正式翻译前核对取词范围。

交互式选择 ​

-i / --interactive 以树形多选框选择需要翻译的文本,只有选中的项会参与翻译并生成 key;未选中的项就地标记为忽略,下次提取自动跳过:

sh
hitf tf src\views\demo\index.vue demo -i

按键操作:

按键作用
↑ / ↓上下移动
← / →折叠 / 展开分组
Space勾选 / 取消:叶子切换自身;分组切换整支(◉ 全选 / ◐ 半选 / ◯ 未选)
Ctrl+A全选当前可见叶子
Ctrl+I(兼容 Tab)反选当前可见叶子
Enter确认提交(至少选择 1 项)
输入字符按文本过滤搜索,Backspace 删除搜索词

确认后仅翻译选中的项,未选中的项会提示「已跳过 N 个文本(将添加忽略注释)」,并在源码中自动插入忽略注释(详见下文忽略注释):

  • JS / TS:/* @hitf-i18n-ignore-start */ … /* @hitf-i18n-ignore-end */
  • Vue 模板文本:<!-- @hitf-i18n-ignore-start --> … <!-- @hitf-i18n-ignore-end -->
  • JSX:{/* @hitf-i18n-ignore-start */} … {/* @hitf-i18n-ignore-end */}
  • Vue 模板静态属性:<!-- @hitf-i18n-ignore:prop:<attrName> -->(置于目标标签正上方)
  • JSON 文件:不插入注释,而是记录到 .hitf/i18n-ignore.json,后续提取自动过滤

交互中断(如 Ctrl+C)会中止翻译,不产生任何写入。

取词范围 ​

会提取用户可见或运行时展示的文案:

js
message.success('Save successfully')
toast('Copied')

const item = {
  label: 'User Name',
  title: 'User Detail',
  placeholder: 'Enter username',
  description: 'Please select a user'
}

支持逻辑表达式里的兜底文案:

js
const text = data?.text || 'Default text'
const desc = data?.description ?? 'No description'

Vue 模板中也支持:

vue
{{ data?.text || 'Default text' }}
{{ data?.description ?? 'No description' }}

解构默认值和函数参数默认值默认不取,避免把类型/数据结构兜底误认为 UI 文案:

js
const { propertyName = 'User name' } = objectToDestruct
function submit(label = 'Save') {}

Vue 模板 ​

文本节点会替换为 $t:

vue
<button>登录</button>
vue
<button>{{ $t('demo.login') }}</button>

插值旁边的中文会保留表达式边界:

vue
<h1>留言({{ remarkList ? remarkList.length : 0 }})</h1>
vue
<h1>{{ $t('demo.leave_a_message') }}({{ remarkList ? remarkList.length : 0 }})</h1>

属性 ​

用户可见属性会被翻译:

vue
<input placeholder="请输入用户名" />
vue
<input :placeholder="$t('demo.please_enter_username')" />

资源路径属性不会翻译,避免破坏文件引用:

vue
<img src="@/assets/images/ssHome/供应商总数量1.png" alt="供应商总数量" />
vue
<img src="@/assets/images/ssHome/供应商总数量1.png" :alt="$t('demo.total_number_of_suppliers')" />

当前建议跳过的资源属性包括 src、srcset、href、poster。

样式相关内容会跳过,包括 class、动态 class、行内 style 和 <style> 块:

vue
<div class="user-card" :style="{ color: 'red' }">用户详情</div>

<style lang="scss" scoped>
.user-card {}
</style>

JavaScript 字符串 ​

脚本中的源语言字符串会替换为翻译函数调用:

js
const title = '登录'
js
const title = t('demo.login')

英文源码示例:

json
{
  "translationSetting": {
    "locales": ["en-US", "zh-CN", "ja-JP"]
  }
}
vue
<button>Login</button>
vue
<button>{{ $t('demo.login') }}</button>

正则中的中文属于匹配规则,不建议自动翻译:

js
const regex = /中文|English/giu

已处理过的 $t(...)、this.$t(...)、t(...) 会跳过,Vue2 的 this.$t 会保留支持。

JSX ​

JSX 文本会替换为 {t(...)}:

jsx
<h1>留言({remarkList ? remarkList.length : 0})</h1>
jsx
<h1>{t('jsxAll.leave_a_message')}({remarkList ? remarkList.length : 0})</h1>

长段自然语言应尽量作为一个完整文案处理,避免按逗号、句号拆成过多 key。

JSX/TSX 中 className、style、事件属性、type、role、data-*、aria-* 会跳过;自定义展示属性可以提取,例如:

tsx
<Comp title="User Detail" label="User Name" />

Vue SFC 中的 <script setup lang="jsx"> 和 <script setup lang="tsx"> 也会按 JSX/TSX 解析,支持 render function 和 defineComponent 中返回的 JSX 文案。

忽略注释 ​

临时不希望处理的代码可以用忽略注释:

js
// @hitf-i18n-ignore-next
message.success('Keep original')

/* @hitf-i18n-ignore-start */
const a = 'Keep original'
const b = 'Keep original too'
/* @hitf-i18n-ignore-end */

Vue 模板:

vue
<!-- @hitf-i18n-ignore-next -->
<div>保持原文</div>

整文件忽略:

js
// @hitf-i18n-ignore-file

指令说明:

指令作用
@hitf-i18n-ignore-next忽略下一段可提取文本
@hitf-i18n-ignore-start / -end忽略区间内的所有文本
@hitf-i18n-ignore-file忽略整个文件
@hitf-i18n-ignore:prop:<attrName>忽略 Vue 模板中指定静态属性(如 <!-- @hitf-i18n-ignore:prop:placeholder -->)

这些注释也可以由 -i 交互取消选中时自动插入:JS / TS 用 /* */、Vue 模板用 <!-- -->、JSX 用 {/* */},Vue 模板静态属性用 <!-- @hitf-i18n-ignore:prop:<attrName> --> 置于标签正上方。JSON 文件不支持注释,取消选中项会记录到 .hitf/i18n-ignore.json,后续提取自动过滤。

输出 ​

翻译后通常会产生两类变化:

  1. 原文件中的中文被替换为 $t 或 t 调用。
  2. locale 目录中生成对应语言包。

示例:

text
src\locale\module\demo\zh-CN.json
src\locale\module\demo\en-US.json

翻译文件夹 ​

hitf tfo 用于递归翻译整个文件夹。

基本命令 ​

sh
hitf tfo src\views

递归处理目录下所有 .vue、.js、.ts、.jsx、.tsx、.json 文件。

常用选项 ​

sh
# 预览模式
hitf tfo src\views demo -d

# 交互确认
hitf tfo src\views demo -i

# 生成报告
hitf tfo src\views demo -r .hitf\reports\demo.json
选项简写说明
-n, --name <name>-n国际化对象 key(默认使用父级目录名)
-p, --project <project>-poutDir 为对象时指定项目
-d, --dry-run-d仅预览翻译计划:逐项列出提取文本与位置,不执行翻译、不写文件
-i, --interactive-i树形多选要翻译的文本;未选中的项自动添加忽略注释,不参与翻译
-r, --report <file>-r写入 JSON 翻译报告
-v, --verbose-v输出详细日志

文件夹预览(树形浏览) ​

tfo -d 在扫描完成后以只读树形界面展示「目录 > 文件 > 文本」三级翻译计划(叶子带 [译] 标记,默认全部翻译):

sh
hitf tfo src\views demo -d

树形浏览按键:↑/↓ 移动 · ←/→ 展开/折叠 · 输入字符搜索 · Enter 结束。结束后输出将翻译的总条数及各处被跳过的字符串明细。不执行翻译、不写文件。

非 TTY 环境(脚本 / CI / 管道)下 tfo -d 不弹交互界面,自动回退为静态树形打印,预览结果同样完整输出。

文件夹交互选择 ​

tfo -i 以树形多选框按「目录 > 文件 > 文本」选择需要翻译的文本,未选中的项自动添加忽略注释(行为与单文件 tf -i 一致,见上文交互式选择):

sh
hitf tfo src\views demo -i

排除文件 ​

使用 --exclude 排除特定文件:

sh
hitf tfo src --exclude "**/*.test.js"

批量输出 ​

翻译结果写入 outDir 下对应的 namespace 目录:

text
src\locale\module\demo\zh-CN.json
src\locale\module\demo\en-US.json

一致性检查 ​

hitf tcheck 用于检查源码中的 $t(...)、this.$t(...)、t(...) 引用和 locale JSON 是否一致。

基本命令 ​

sh
hitf tcheck src
hitf tcheck src -r .hitf\reports\tcheck.json

检查内容 ​

类型说明
missing源码引用了但所有语言包都不存在的 key
unused语言包存在但源码没有引用的 key
inconsistent某个 key 在部分 locale JSON 中缺失
invalid locale files无法解析的 JSON 语言包

输出示例 ​

text
Translation check summary
  missing: 2
  unused: 0
  inconsistent: 0
  invalid locale files: 0
  missing hello
    src/App.vue:2:11
  missing welcome
    src/App.vue:3:9

tcheck 适合在批量迁移后执行,也适合放进 CI,阻止缺失语言包或 JSON 损坏进入主分支。

回滚操作 ​

hitf rollback 用于回滚上一次翻译操作。

基本命令 ​

sh
hitf rollback              # 回滚最近一次
hitf rollback -l          # 查看可用备份
hitf rollback -n xxx       # 回滚指定备份
hitf rollback -k 5         # 仅保留最近 5 个备份

选项 ​

选项简写说明
-l, --list-l列出所有可用备份
-n, --name <name>-n回滚指定名称的备份
-k, --keep <count>-k仅保留最近 N 个备份

使用场景 ​

  1. 翻译结果不满意:回滚后调整配置重新翻译
  2. 误操作恢复:回滚到翻译前的状态
  3. 备份管理:清理旧备份释放空间

翻译报告 ​

tf 和 tfo 都支持 -r, --report <file> 生成翻译报告:

sh
hitf tf src\views\user\index.vue user -d -r .hitf\reports\user.json
hitf tfo src\views user -r .hitf\reports\user-folder.json

报告是 JSON 格式,适合人工审查、CI 上传或后续脚本处理:

json
{
  "mode": "dry-run",
  "summary": {
    "filesScanned": 1,
    "filesWithExtractions": 1,
    "replacements": 3,
    "written": 0,
    "skipped": 1,
    "failed": 0
  },
  "files": [
    {
      "file": "src/views/user/index.vue",
      "outputFile": ".hitf/lang/user/index.vue",
      "replacements": [
        {
          "text": "User Detail",
          "key": "user.user_detail",
          "context": "attribute",
          "start": 42,
          "end": 53
        }
      ]
    }
  ],
  "failedFiles": []
}

字段含义:

字段说明
modedry-run 或 write
summary.filesScanned实际扫描的文件数量
summary.filesWithExtractions有取词结果的文件数量
summary.replacements准备替换或已替换的文案数量
summary.written已写入文件数量
summary.skipped跳过文件数量
summary.failed失败文件数量
files[].replacements每个文件内的取词、key、上下文和位置
failedFiles语法校验失败或处理失败的文件

Released under the MIT License.