npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

extract-i18n-plugin

v1.1.45

Published

A set of plugins for extracting i18n messages from source code and translate/compile them. Both supports React/Preact/Vue/Svelte/Solid/Qwik/Lit/Angular/Ember/Marko based apps

Readme

extract-i18n-plugin

中文 | English

zread npm version Stars Forks Issues GitHub contributors License

extract-i18n-plugin是一个集extract、compile、rewrite、translate于一身的vite/rollup/webpack/babel/cli插件,几乎支持目前已知的所有前端框架,如React、Preact、Vue(包括uni-app)、Svelte5、Solid、Qwik、Lit、Angular、Ember、Marko。查看示例获取更多信息. 有了该插件的加持,多语言工作将变得不再繁琐和痛苦,它将为你一站式搞定。

USAGE

Install

# npm
npm install extract-i18n-plugin -D
# yarn
yarn add extract-i18n-plugin -D
# pnpm
pnpm add extract-i18n-plugin -D
# bun
bun add extract-i18n-plugin -d

CLI

extract-i18n是一个命令行工具,主要功能:提取、编译、重写、翻译.

例如:

extract-i18n --includePath=src --rewrite

这会提取src目录下的所有allowedExtensions文件的fromLang,生成JSON语言包自动翻译并生成对应的翻译JSON文件.

Programming API

const { extractI18n } = require("extract-i18n-plugin");

extractI18n(options)
  .then(() => {
    console.log("extract done!");
  })
  .catch(err => {
    console.error("extract error:", err);
  });

Options

const defaultOptions = {
  translateKey: "$t", // 提取的函数的名称
  translateKeyForTemplate: null, // 在模板中要提取的函数名称,只对ember模板生效
  importIdentifier: null, // 自定义导入的标识符名称,如果不传则默认为translateKey配置的值,对`svelte-i18n`比较有用,例如:`import { t } from "svelte-i18n"`,但模板里使用的是auto-subscription语法`$t()`, 这时如果开启了`rewrite`模式, `importIdentifier`应该设为`t`.
  JSXElement: "Trans", // 提取的函数的 JSX 元素名称 默认为 Trans, 如:<Trans id="aaa" msg="xxx" />
  hooksIdentifier: "useTranslation", // 注入到组件的hook名称, 会注入const { $t } = useTranslation(),其中$t为translateKey的引用值
  destructuredHooks: true, // 是否生成解构hooks, 如:const { t } = useTranslation()否则生成 const t = useTranslation()
  injectHooks: false, // 是否将useTranslation自动注入到组件中
  jsx: false, // 是否启用 JSX 语法转换,开启后JSX里纯文本将转换为 <Trans id="aaa" msg="xxx" />而不是 $t("aaa")
  rewrite: false, // 是否将提取到的内容转换为id后重写入源文件
  pipeStyle: false, // 将Angular模板文本节点转换为pipe风格,如:<div>文本</div> -> <div>{{ 'id' | $t }}</div>,仅对Angular html模板有效
  extractFromText: true, // 是否允许从纯文本节点中提取翻译内容
  autoImportI18n: true, // 是否自动导入 i18n 模块
  autoTranslate: true, // 提取完成后是否自动翻译
  cleanTranslate: true, // 是否清理无用的翻译内容
  keepRaw: false, // 开启后只做转换不生成hash值,即:"测试" -> $t("测试"), 开启rewrite时生效
  keepDefaultMsg: false, // 保留默认消息,即:"测试" -> $t("hashedKey", "测试")
  defaultMsgPos: 1, // 默认消息参数位置,0表示第一个参数,1表示第二个参数,开启keepDefaultMsg时生效
  enableCombinedSourcemap: false, // 是否开启获取组合的源映射
  enabled: true, // 是否启用插件
  debug: true, // 是否打印日志
  translateInterval: 1000, // 翻译不同语种的间隔时间, 时间过短时可能会被限流
  extraImports: null, // 额外的导入项, 格式:[{ name: "t", as?: "_t" path: "@/i18n" }]
  extraImportIdentifier: null, // 额外的导入项的标识符名称,如:['customImport'] -> import { t, customImport } from "@/i18n"
  excludedCall: [], // 排除的调用函数名称数组,目前已内置的函数请参阅:https://github.com/semdy/extract-i18n-plugin/blob/main/lib/utils.js#L402
  includePath: ['src/'], // 包含路径的数组
  excludedPath: ['**/node_modules/**'], // 排除路径的数组 refer to https://github.com/mrmlnc/fast-glob?tab=readme-ov-file#how-to-exclude-directory-from-reading
  allowedExtensions: [".vue", ".nvue", ".uvue", ".svelte", ".tsx", ".ts", ".jsx", ".js", ".mjs", ".cjs", ".mts", ".cts", ".uts", ".marko", ".gjs",".gts",".hbs", ".html"], // 允许提取的文件扩展名
  fromLang: 'zh-cn', // 源语言, 目前支持提取的语言有:zh-cn(zh-tw), en, ja, ko, ru,其它语言请使用shouldExtract判断是否要被提取
  translateLangKeys: ["zh-tw", "en"], // 定义要翻译成哪些语言
  i18nPkgImportPath: "@/i18n", // i18n语言包导入路径
  outputPath: "src/i18n", // 提取的语言包输出文件路径
  generateId: null, // 自定义生成 key 的函数
  shouldExtract: null, // 自定义是否提取文本的判断函数
  customGenLangFileName: langKey => langKey, // 自定义生成语言文件名
  // 翻译后的文本处理函数,方便对翻译后的文本进行二次加工,如每个单词首字母大写, params: text: 翻译后的文本, toLang: 翻译后的目标语言,translateLangKeys的枚举成员
  customTranslatedText: (text, toLang) => text,
  /* 翻译器,默认使用GoogleTranslator,也可以自定义实现Translator接口 */
  translator: new GoogleTranslator()
  /** 如开启了端口代理,请配置port,如:7890 */
  translator: new GoogleTranslator({
    proxyOption: {
        port: 7890,
        host: '127.0.0.1',
        headers: {
            'User-Agent': 'Node'
        }
    }
  })
};

Configuration file

在项目根目录创建extract-i18n.config.js,用于cli和vite/webpack/babel插件的参数配置. 示例:

import { YoudaoTranslator } from "extract-i18n-plugin/translators";

export default {
  rewrite: false,
  translator: new YoudaoTranslator({
    appId: "youdao appId",
    appKey: "youdao appKey"
  }),
  ...
};

// ts支持
// extract-i18n.config.ts
import { defineConfig } from "extract-i18n-plugin";

export default defineConfig({
  rewrite: false,
  translator: new YoudaoTranslator({
    appId: "youdao appId",
    appKey: "youdao appKey"
  }),
  ...
});

Vite plugin

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import { vitePluginI18n } from "extract-i18n-plugin";

export default defineConfig({
  plugins: [
    vue(),
    // 用于运行时转换
    vitePluginI18n(userConfig)
  ]
});

参数优先级:userConfig > extract-i18n.config.js > defaultOptions

Rollup plugin

import vue from "rollup-plugin-vue";
import resolve from "@rollup/plugin-node-resolve";
import { rollupPluginI18n } from "extract-i18n-plugin";

export default {
  plugins: [
    resolve(),
    vue(),
    // 用于运行时转换
    rollupPluginI18n(userConfig)
  ]
};

参数优先级:同上

Webpack plugin

const { WebpackPluginI18n } = require("extract-i18n-plugin");

module.exports = {
  plugins: [
    new VueLoaderPlugin(),
    new HtmlWebpackPlugin({
      template: "./public/index.html"
    }),
    new WebpackPluginI18n(userConfig)
  ]
};

参数优先级:同上

Babel plugin

// babel.config.js
module.exports = {
  presets: ["@vue/cli-plugin-babel/preset"],
  plugins: [
    [
      "extract-i18n-plugin/babel-plugin-i18n",
      {
        ...userConfig
      }
    ]
  ]
};

参数优先级:同上

UmiJS

// config/config.ts
import { defineConfig } from "@umijs/max";
import { vitePluginI18n } from "extract-i18n-plugin";
import userConfig from '../extract-i18n.config';

export default defineConfig({
  // 方案一(推荐)
  vite: {
    plugins: [vitePluginI18n()]
  }
  // 方案二
  extraBabelPlugins: [
    [
      'extract-i18n-plugin/babel-plugin-i18n',
      {
        ...userConfig,
      },
    ],
  ],
});

方案一和方案二任选其一.

Deprecated

仓库中的babel-plugin-i18n-importrollup-plugin-i18n-importvite-plugin-i18n-importwebpack-i18n-import-loader已弃用,因为主插件中带有自动生成导入i18n的逻辑。

How It Works(工作原理)

插件会先将源码解析为 抽象语法树(AST),然后遍历其中的节点,提取可国际化的文本内容。主要处理的节点类型包括:

  • CallExpression

  • StringLiteral

  • TemplateElement

  • JSXText

  • JSXElement

  • JSXExpressionContainer

当启用 rewrite 选项时,插件会对源码进行重写,将原始文本替换为对应的国际化函数调用,并自动生成对应的 keyvalue,同时写入语言包文件。

例如:

<p>你好</p>
<p>{$t("测试")}</p>

会被转换为:

<p>{$t("03tpnc")}</p>
<p>{$t("03nbln")}</p>

如果开启了keepDefaultMsg则会生成:

<p>{$t("03tpnc", "你好")}</p>
<p>{$t("03nbln", "测试")}</p>

同时生成语言包:

{
  "03tpnc": "你好",
  "03nbln": "测试"
}

如果开启了autoTranslate则会自动翻译成其它语言并生成语言包,具体翻译成哪些语言由translateLangKeys决定。

如果开启了autoImportI18n,当前文件有国际化内容被提取,则会自动在该文件插入导入语句,如:import { $t } from "@/i18n"

如果开启了injectHooks则会在jsx/tsx组件中自动注入hooks以适应语言动态切换,如:const { t } = useTranslation().


Vue 编译优化处理

Vue 编译器在编译阶段会进行大量优化,例如:

  • 静态提升(Static Hoisting)

  • 缓存优化(_cache

  • 静态节点标记(PatchFlag

  • 动态属性依赖提升(hoisted dynamicProps

当插件将文本替换为 i18n 调用后,原本的静态节点需要变为动态节点。 为了保证运行时行为正确,插件需要执行以下处理:

  • 静态节点重新标记为动态节点

  • 移除 _cache 缓存优化

  • 更新或追加 dynamicProps 依赖

因此,在 Vue 项目中,这部分转换逻辑会相对复杂。


Qwik 编译优化处理

Qwik 编译器同样会在编译阶段对模板进行静态节点标记。

当插件对文本节点进行 i18n 转换后,这些原本被标记为静态的节点也需要重新标记为 动态节点,以确保运行时能够正确更新内容。

重要说明

在Vue3中,vue-i18n版本大于9.0.0时,legacy须设为false,否则在开发阶段会有Uncaught TypeError: 'set' on proxy: trap returned falsish for property '$t'的代理错误. 推荐写法如下:

import { createI18n } from "vue-i18n";
import zhMessages from "@/locales/zh-cn.json";
import enMessages from "@/locales/en.json";

const i18n = createI18n({
  legacy: false,
  globalInjection: true,
  allowComposition: true,
  fallbackLocale: "en",
  locale: "zh",
  messages: {
    en: enMessages,
    zh: zhMessages
  }
});

// 导出一个$t方法
export const $t = i18n.global.t.bind(i18n.global);

export default i18n;

如果不想使用vite/webpack插件,可以手动调用extract-i18n --rewrite,这会将转换后的代码重新写入源文件(小程序和uni-app X项目比较适合此模式).

Known issues & Guidelines

  • 由于svelte和solid-js编译器都有静态提升的优化策略,因此不支持纯文本提取,需要在源码中使用显式调用$t("文本")的方式。

  • Lit由于是静态模板,因此不支持纯文本提取,需要在源码中使用显式调用$t("文本")的方式。

  • vue编译器同样有静态提升以及静态节点标记(patchFlag)的优化,该插件会将它重新标记为动态节点,否则切换语言后,节点不会更新。绝大部分情况下纯文本提取没问题,有问题的地方建议使用显式调用$t("文本")的方式。

  • Angular底层编译工具链不基于babel,因此只能开启rewrite模式进行AOT编译,<div>文本</div>会被编译成pipe风格<div>{{ 'id' | t }}</div>.

  • Ember的模板编译产物是纯字符串,该插件无法参与其中做二次转换,因此也只支持rewriteAOT编译模式。

  • 基于uni-app的小程序项目的建议:开发时直接写纯文本,然后使用extract-i18n --rewrite --keepRaw转换,会将"文本"转换成$t("文本")并写入源码,不然该插件将无法正常工作,因为根据uni-app编译器策略,静态文本会保留在wxml文件中,只有动态内容才会编译到js文件中,这样才能被正常提取和转换。

  • uni-app X项目底层编译器是kotlin, 需要提前将源码进行转换。建议使用extract-i18n --rewrite --keepDefaultMsg"文本"转换成$t("id","文本"),这样既保证了i18n的功能也不影响对源码的阅读。

  • svelte4 typescript项目静态提取不受支持,因为svelte 4.0编译器的parser不支持typescript。

  • svelte项目建议添加prettier-plugin-svelte依赖,因为rewrite模式会调用prettier格式化.svelte文件,svelte文件格式化依赖这个插件.

  • 对于纯英文项目,建议在源码中使用显式调用$t("文本") + extractFromText:false的方式。因为该插件无法区分需要翻译的文本和代码中的字符串。

  • extractFromText设为false,则纯文本不会被提取,只会从$t()Trans组件中提取文本,能一定程序上提高性能。

  • 有动态插值的文本需要显式调用$t(),如:$t("{name}的余额为{balance}", {name: '张三', balance: 100})

总结:

纯文本编写有很好的便利性,但$t()有更好的稳定性和可靠性(特别是vue项目),当然也可以混用。该插件已经服务了公司内部多个涵盖React、Vue、uni-app(APP-PLUS、X、H5、小程序)的项目,不管用哪种方式,稳定性和可靠性都不错。

Translators

插件默认使用谷歌翻译(默认配置代理端口7890)。在网络不支持访问谷歌的情况下,我们推荐使用 有道翻译 ✨,其翻译效果优秀。目前插件已经内置谷歌、有道和百度翻译功能。如果需要自定义翻译器,可参考下方的示例。

Google Translate (default)

import { GoogleTranslator } from 'extract-i18n-plugin/translators'

...
translator: new GoogleTranslator({
    proxyOption: {
        host: '127.0.0.1',
        port: 7890,
        headers: {
            'User-Agent': 'Node'
        }
    }
})
...

有道Translate

需要申请api,api文档

import { YoudaoTranslator } from 'extract-i18n-plugin/translators'

...
translator: new YoudaoTranslator({
    appId: '你申请的appId',
    appKey: '你申请的appKey'
})
...

百度Translate

需要申请api,api文档

import { BaiduTranslator } from 'extract-i18n-plugin/translators'

...
translator: new BaiduTranslator({
    appId: '你申请的appId', // 百度翻译 AppId
    appKey: '你申请的appKey' // 百度翻译 AppKey
})
...

火山引擎AI Translate

支持调用 doubaodeepseek 进行翻译,AI大模型的翻译效果会比传统的API翻译更准确,但耗时较长。 火山引擎大模型介绍:https://www.volcengine.com/docs/82379/1099455。 需要开通大模型服务并申请API,api文档

import { VolcEngineTranslator } from 'extract-i18n-plugin/translators'

...
translator: new VolcEngineTranslator({
    apiKey: '你申请的apiKey',
    model: '你要调用的模型,如:`doubao-1-5-pro-32k-250115`,请确保使用前已在控制台开通了对应模型'
})
...

Empty Translate

如果只需要扫描目标语言,不进行翻译,该翻译器会生成 JSON 文件。

import { EmptyTranslator } from 'extract-i18n-plugin/translators'

...
translator: new EmptyTranslator()
...

Custom Translate

如果你有一个自用的翻译接口,可以通过以下方式自定义翻译器——

最简单的方式是使用 Translator 基类定义翻译器实例。

import { Translator } from 'extract-i18n-plugin/translators'
import axios from 'axios'

...
translator: new Translator({
    name: '我的翻译器',
    // 翻译的方法
    fetchMethod: (str, fromKey, toKey, _separator) => {
        // 实际的接口调用可能比示例更复杂,具体可参考源码中YoudaoTranslator的实现,路径:src\translators\youdao.js
        const myApi = 'https://www.my-i18n.cn/api/translate?from=${fromKey}&to=${toKey}&t={+new Date}'
        return axios.post(myApi, { str })
            .then(res => res.data)
    },
    // 接口触发间隔,有些接口频繁触发会被拉黑,请根据实际情况设置一个合理的接口触发间隔
    interval: 1000
})
...

如果需要更高阶的功能,可以使用继承,不过目前无相关场景。

import { Translator } from 'extract-i18n-plugin/translators'

class CustomTranslator extends Translator {
    constructor () {
        super({
            name: '我的翻译器',
            ...
        })
    }
}

...
translator: new CustomTranslator()
...

:copyright: License

MIT

Star History