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 🙏

© 2025 – Pkg Stats / Ryan Hefner

jdy-intl-babel

v1.1.1

Published

通用前端国际化转译工具,基于 babel v7

Downloads

13

Readme

babel 国际化插件

通用前端国际化转译工具,基于 babel v7

它能做什么?

它能识别泛 js 代码(js、ts、jsx、tsx、vue...)中的硬编码中文,参照一定的格式进行转换并保存识别到的中文。

  • 可以指定路径范围,支持 glob 模式解析路径。
  • 自定义国际化转译函数。
  • 指定中文提取包保存路径。
  • 性能优化,提供批量编译配置。

它没有做什么...

该库仅对 babel 插件做了两层封装,只做转换工作,对于其他工程化工具不做限制。在使用该工具的同时,项目中应该还要存在:

  1. 代码格式化工具(prettier 等):babel 在转换过程中并不会刻意保留源代码的格式,在转换后的代码格式会出现较大改动,请参考下面的示例对转换后的代码进行格式化后保存。
  2. (可选)提交流检查工具(lint-staged 等):该工具可集成到各种提交流工具中,方便提交时自动对修改处国际化。

安装

该插件目前位于公开npm源中,可直接执行任意安装命令

yarn add @jdy/intl-babel

随后安装依赖:(推荐 yarn or pnpm)

yarn install

使用

场景 1 - 项目整体国际化

// 这里以node的commonJs为例,使用esm请自行进行转换。
const fs = require("fs");
const path = require("path");
const prettier = require("prettier");
const { default: I18nPlugin, writeFileAsync } = require("@jdy/intl-babel");
// 常量
const projectPath = path.resolve(__dirname, "./"),
  prettierConfPath = path.join(projectPath, ".prettierrc"),
  saveJsonPath = path.join(projectPath, "lang", "zh_CN.json");
// prettier 配置项
const prettierConf = JSON.parse(
  fs.readFileSync(prettierConfPath, { encoding: "utf-8" })
);

I18nPlugin({
  //这里是解析路径的规则
  pathOption: {
    // 解析匹配到下面路径的文件
    pattern: ["src/**/*.{js,ts,tsx,jsx}"],
    // 传递给Glob的参数
    options: {
      // 忽略配置文件、文档文件、测试文件(默认不以./开头)
      ignore: ["src/**/*.{config,stories,test}.{js,ts,jsx,tsx}"],
    },
  },
  // 此次转换收集到的所有国际化字典的回调,需要自行执行保存
  dictCallback:(Intldict)=>saveJson(IntlDict).then(....)
  // 国际化转译相关配置
  i18nOptions: {
    // 插件配置
    pluginOptions: {
      /**
       * 翻译函数的导入形式,请使用alias形式的导入。以下是判断注入方式:
       * 1. 当前文件内不存在需要翻译的地方,不注入
       * 2. 当前文件内存在需要翻译的地方
       *  2.1 若已存在相同导入,则不再注入
       *  2.2 未导入(该文件第一次被翻译)则在文件首行注入
       */
      injectIntlImport: 'import  {getLangMsg}  from "@/utils/intl";',
      /**
       * 项目内中文的替换形式,请注意必须满足翻译函数(hash).默认值(code)的形式;
       * 其中hash是中文的md5值,code则是被替换的中文;
       * t是翻译库的翻译函数,d则是当t函数传参hash得到空字符串时的默认值(也用于帮助开发了解该文本内容)
       */
      getIntlFunc: (hash, sourceMsg) => `getLangMsg(${hash}).d(${sourceMsg})`,
    },
    // 默认为["jsx", "typescript"],当项目中用到dva等高阶HOC时使用下面的配置
    parserPlugins: ["jsx", "typescript", "decorators-legacy"],
  },
  callback: (dict) => {
    // 插件不会默认替换掉目标文件
    const { code, filePath } = dict;
    // 这里假设你使用prettier v3进行格式化代码
    return prettier
      .format(code, { ...prettierConf, filepath: filePath })
      .then((formatCode) => writeFileAsync(filePath, formatCode));
  },
}).then((dict) => {
  /** 在这里dict表示此次转换拿到的对应映射
   * dict 是一个对象,里面类似:
   * {
   *  "02ddbbf19885bc7": "已还款",
   *  "02ec202bc579881": "请输入",
   *  "041b02ca833756e": "事由",
   *  "049ca0b50228c4c": "预计还款日期:{arg0}",
   * }
   * 这里需要对一些情况进行说明:
   * 1. 当一份文件第一次被翻译时,可以拿到该文件内所有被翻译的映射
   * 2. 当该文件没有有关中文的改动再次被翻译时,返回的是空的对象
   * 3. 当该文件内有部分中文被改动,执行翻译后,拿到的是改动过后的映射对象。
   */
});

场景 2 - 接入提交流

首先新建一个文件 intl-plugin.js

// scripts/intl-plugin.js
const path = require("path");
const fs = require("fs");
const prettier = require("prettier");
const { default: I18nPlugin } = require("@jdy/intl-babel");
// 常量
const projectPath = path.resolve(__dirname, "../"),
  prettierConfPath = path.join(projectPath, ".prettierrc"),
  srcPath = path.join(projectPath, "src"),
  saveJsonPath = path.join(projectPath, "lang", "zh_CN.json");
// prettier 配置项
const prettierConf = JSON.parse(
  fs.readFileSync(prettierConfPath, { encoding: "utf-8" })
);
//获取命令行传递过来的参数
const args = process.argv.slice(2);
const fileList = args
  .map((filePath) => path.resolve(filePath))
  // 确保是在src内的文件,甚至可以更上一步,确保是tsx等类型文件
  .filter((filePath) => filePath.startsWith(srcPath));
I18nPlugin({
  pathOption: {
    pattern: fileList,
    options: {
      // 忽略配置文件、文档文件、测试文件
      ignore: ["src/**/*.{config,stories,test}.{js,ts,jsx,tsx}"],
    },
  },
  i18nOptions: {
    pluginOptions: {
      injectIntlImport: 'import {t} from "@/utils/intl"',
      getIntlFunc: (hash, code) => `t(${hash}).d(${code})`,
    },
  },
  callback: (dict) => {
    const { code, filePath } = dict;
    // 这里prettier可格式化可不格式化,如果你配置了提交自动格式化的话
    return prettier
      .format(code, { ...prettierConf, filepath: filePath })
      .then((formatCode) =>
        fs.writeFileSync(filePath, formatCode, { encoding: "utf-8" })
      );
  },
}).then(() => {
  // 这里格式化一下json文件
  const jsonData = fs.readFileSync(saveJsonPath, { encoding: "utf-8" });
  prettier
    .format(jsonData, { ...prettierConf, filepath: saveJsonPath })
    .then((formatCode) =>
      fs.writeFileSync(saveJsonPath, formatCode, { encoding: "utf-8" })
    );
});
// 这里假设你使用lint-staged作为提交流检查工具
//lintstagedrc.js
const handler18n = (filenames) =>
  `node ./scripts/intl-plugin.js ${filenames.join(" ")}`;
module.exports = {
  // 这里会按照顺序执行
  "*.{js,ts,tsx,md,json}": [
    handler18n,
    "git add ./lang/zh_CN.json",
    "prettier --write",
  ],
};

提交流注意事项

  1. 提交流不会删除 json 内不再使用的字段,只能新增字段。
  2. 插件本身会对 json 内字段进行排序(需确保在 es3 以上),尽量避免合并冲突。
  3. 若需要发布时对 json 进行 shaking,可参考以下方案:
  • 以 zh_CN 为准,删除 en_US 内多余的字段(en_US 只在 release 时更新)。
  • 以 en_US 为准,找出 zh_CN 内多余的字段,与上面提取的多余字段做差集。

编译提速

插件内实现了线程池,由于线程之间数据交换需要序列化和解析,请酌情使用。

I18nPlugin({
  threadOptions: {
    // 必须显示开启
    enable: true,
    // 请务必提供一个大于0的数
    num: 6,
  },
  //...其他配置项
});

或者可以使用 bun 替代 node,具体示例如下:

# 之前是这样执行的
node your-script.js
# 改成这样即可
bun your-script.js

参考案例1:销售助手(全面扫描 800+文件,提取 3700+词条)

配置 m1 pro 16gb

| 编译模式 | 编译速度 | | ------------------------ | -------- | | 普通编译 (node 16.20.0) | 13~15s | | 普通编译(node 20.11.0) | 10~11s | | thread-6 (node 16.20.0) | 9.247s | | thread-6(node 20.11.0) | 8.5s | | bun 1.0.29 | 10.9s | | thread-6 & bun | 7.3s |

参考案例2:pos-h5(全面扫描1000+文件,提取词条6600+词条)

配置 m1 pro 16gb

| 编译模式 | 编译速度 | | ------------------------ | -------- | | 普通编译 (node 16.20.0) | 21~25s | | 普通编译(node 20.11.0) | 19~21s | | thread-6 (node 16.20.0) | 16~18.5s | | thread-6(node 20.11.0) | 15~16s | | bun 1.1.30 | 18~21s | | thread-6 & bun | 14~15s |

调试

I18nPlugin({
  _debugger: {
    // 测速
    timer: true,
    // json相关操作结果打印
    console: true,
  },
  //...其他配置项
});

接入其他框架

  • 目前已支持vue2