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

@nstc-cli/i18n

v0.2.2

Published

> TODO: description

Readme

i18n 脚手架(@nstc-cli/i18n)

目标:为 Vue2(可逐步扩展到 Vue3/React) 项目提供一套“初始化配置 → 扫描提取中文 → 生成/合并多语言资源 → 自动替换源码为 $l() 调用 → 构建产物/校验”的 i18n 工具链。

本 README 是架构设计文档 + 使用说明,会随着实现迭代更新。


1. 现状与问题(基于当前代码)

当前 packages/i18n 已具备:

  • 命令入口:nstc i18n [name],已实现子命令:
    • init:在项目根生成 language.config.js(默认配置写死在 lib/create.js
    • etl:读取配置后递归遍历目录(lib/core/index.js),对 js/ts 调用 extractJs(目前仅 parse 并打印 AST)
  • 配置缓存:把执行参数 merge 到 ~/.nstc-cli/.cache/i18n_cache.yaml
  • 基础工具:findFiles(glob)、hasChinese/isChineseChar(中文检测)

当前缺口:

  • etl 只 parse,不产出“中文条目清单/资源文件”。
  • ts / build 还未落地(README 中仅有命令草案)。
  • Vue 文件处理、JS/TS AST 遍历、替换写回、备份、dry-run、资源合并策略等未定。

2. 总体架构(确定版)

把 i18n 流程拆为 4 个阶段,对应 4 个子命令:

  1. init:初始化工程 i18n 配置(生成 language.config.js
  2. etl:抽取(Extract)——扫描源码,提取中文与上下文,产出“词条表”
  3. ts:转换(Transform)——把源码中文替换为 $l(key),并确保 import/依赖注入(本工程要求:ts 只做替换,不写资源文件
  4. build:构建(Build)——将词条表与已有资源合并,生成最终资源文件(如 src/i18n.json 或拆分多文件),并做校验

推荐的运行方式(最常见):

# 1) 初始化(只需一次)
nstc i18n init -s .

# 2) 抽取中文(每次开发/合并都可跑)
nstc i18n etl -s .

# 3) 转换源码(通常在“抽取结果确认后”执行)
nstc i18n ts -s .

# 4) 生成/合并资源(CI 或本地都可跑)
nstc i18n build -s .

3. 命令设计

3.1 顶层命令

当前入口:nstc i18n [name]

  • name:子命令名(init|etl|ts|build

建议对 packages/i18n/lib/index.js 做扩展:

  • case "ts"tsCreate(opts)
  • case "build"buildCreate(opts)
  • 将未知命令提示改为包含 init, etl, ts, build

目前仅实现了 initetl

3.2 通用参数(建议统一)

| 参数 | 说明 | 默认值 | | ------------------------- | ------------------ | ----------------------------- | | -s, --source <path> | 源码根目录 | process.cwd() | | -e, --exclude <pattern> | 额外排除(glob) | "" | | --config <path> | 指定配置文件路径 | language.config.js | | -r, --dry-run | 仅预览不写回 | false | | -b, --no-backup | 不生成 .bak 备份 | true(注意 commander 语义) |

3.3 init

职责:

  • source 目录生成 language.config.js(若不存在)
  • 写入默认配置模板(允许后续自定义)
  • 将本次 opts merge 到全局 cache(当前已实现)

输出:

  • language.config.js

3.4 etl

职责(确定版):

  • 扫描 basePath(默认 ./src)下的源码文件
  • 识别中文字符串/文本节点
  • 产物路径跟随 language.config.jsoutput
  • 如果 output 已存在:执行 合并去重(保留旧翻译值,补齐新增 key)

产物:

  • output 对应的资源文件(例如 ./src/i18n.json

说明:由于 key = 中文原文,本阶段在抽取的同时即可直接补齐资源 key;资源合并策略与 build 一致(不覆盖旧翻译)。

3.5 ts

职责(确定版):

  • 读取 extract.json
  • 仅做“源码替换”:把中文替换为 $l(key)
  • 插入/补齐 import(如 $ln20-common-lib 引入)
  • 写回文件(dry-run 只打印 diff/patch)
  • 可选生成 .bak

重要约束:ts 不负责生成/合并资源文件,不写 i18n.json

3.6 build

职责(确定版):

  • 读取 extract.json
  • 读取已有资源文件(例如 ./src/i18n.json
  • 按语言维度合并并输出
  • 校验:
    • key 唯一
    • 资源覆盖率
    • 是否存在 $l() 引用但资源缺失

4. 配置协议(language.config.js)

当前默认模板(来自 lib/create.js):

  • output: './src/i18n.json'
  • exclude: 默认排除 node_modules/dist/... 等
  • languages: ['en', 'th', 'vi']
  • rules.vue.label: '$l'
  • rules.vue.importOriginal: "import { $l } from 'n20-common-lib'"

4.1 key 规则(本工程确定:key = 中文原文)

你已经确认:key 直接使用中文原文

这会带来几个必须明确的规则:

  1. 稳定性:同样的中文原文,在任何文件中出现,都使用同一个 key(即 key 复用)。
  2. 可表示性:key 作为 JSON 对象的属性名必须可序列化。
  3. 规范化(Normalize):为了避免“看起来一样但实际上不同”的 key,必须做规范化:
    • 去掉首尾空白:trim()
    • 将连续空白压缩为单个空格(可选,但建议开启)
    • 换行统一为 \n
  4. 非法/高风险 key 处理
    • 空字符串:丢弃
    • 超长文本(例如 > 200 字):建议提示并跳过,避免资源文件膨胀
    • 含有大量变量拼接/模板:不建议直接作为 key(建议交给开发手工改造)

注意:key=中文会导致资源文件的 key 体积较大,但优点是“可读、无需维护映射表”。这是你当前选择的权衡。

4.2 建议扩展字段(保持向后兼容)

module.exports = {
  // 扫描根目录(相对 source)
  basePath: "./src",

  // 资源输出(build 的输出)
  output: "./src/i18n.json",

  // 中间产物目录
  cacheDir: "./.cache/i18n",

  // 排除
  exclude: ["**/node_modules/**", "**/dist/**"],

  // 要生成的语言
  languages: ["zh-CN", "en", "th", "vi"],

  // key 策略:固定为 chinese(即 key=text)
  key: {
    strategy: "chinese",
  },

  rules: {
    vue: {
      label: "$l",
      importOriginal: "import { $l } from 'n20-common-lib'",
      translateAttrs: ["title", "placeholder", "label"],
    },
    js: {
      label: "$l",
      importOriginal: "import { $l } from 'n20-common-lib'",
    },
  },
};

5. 中间产物(extract.json)

当 key=中文时,中间产物建议变更为:

  • key = normalizedText
  • text 仍保留原文(用于定位差异)

示例:

{
  "meta": {
    "createdAt": "2026-01-22T00:00:00.000Z",
    "basePath": "./src",
    "toolVersion": "0.0.1",
    "keyStrategy": "chinese"
  },
  "items": [
    {
      "id": "...",
      "key": "中文原文",
      "text": "中文原文",
      "file": "src/views/a.vue",
      "type": "vue-template-text",
      "loc": {
        "start": { "line": 10, "column": 5 },
        "end": { "line": 10, "column": 12 }
      },
      "context": {
        "snippet": "<div>中文原文</div>"
      }
    }
  ]
}

etl 输出还应额外产出一个“去重后的词典视图”(可选,但强烈建议),便于 build 合并:

  • dict.json{ [key: string]: { occurrences: number, files: string[] } }

6. 资源文件结构(你们当前规范:结构2 / key 顶层)

你已经确认:output 资源文件采用 结构2

{
  "确定": { "en": "Confirm" },
  "取消": { "en": "Cancel" }
}

说明:

  • 顶层 key = 中文原文(规范化后)
  • value 必须是对象{ [lang]: translation }(不允许 string/number 等其它类型)
  • zh-CN 语言通常可省略;当缺失时,默认含义为“中文=key”(但为了工具链一致性,etl/build 在需要时会补齐 zh-CN

合并策略(etl/build 一致):

  • output 已存在:
    • 保留已有翻译(不覆盖已有字段)
    • 对每个新 key:补齐缺失语言字段(zh-CN 默认=key,其它语言默认空串)
    • 可选:输出 unused key 报告(源码已无引用的 key)

7. ts 替换策略(key=中文 的关键点)

7.1 替换规则

  • $l(key)key 直接使用中文原文:
    • 推荐输出:$l('中文')
    • 若包含单引号 ':改用双引号包裹:$l("中'文")
    • 若同时包含单双引号:使用转义(最终由生成器保证合法 JS 字符串)

7.2 同文案复用

当不同文件出现同样的中文:

  • extract.json 会生成同一个 key
  • ts 替换输出相同 $l(key)
  • build 资源也只维护一条 key

7.3 不替换场景(建议)

  • 注释中的中文(默认不替换)
  • console/debug 文案(可配置是否替换)
  • 单文件内超长大段文本(提示人工处理)

8. 与现有工程的对齐点

  • CLI 框架:@nstc-cli/command + commander
  • 全局 cache:~/.nstc-cli/.cache/i18n_cache.yaml
  • 项目内配置:language.config.js

建议补齐:

  • globalConfig() 目前只返回 config 文件内容,未将 cache/cli opts 统一 merge 到“最终 config”。建议调整为:
    • 明确优先级:CLI opts > config 文件 > 全局 cache
    • 最终返回 finalConfig

9. Roadmap(实现顺序建议)

  1. init(已有)
  2. etl:先实现 扫描 js/ts 字符串字面量 中的中文并输出 extract.json + dict.json
  3. build:把 extract.json/dict.json 合并生成 i18n.jsonzh-CN 默认=key,其它语言空串)
  4. ts:基于 extract.json 做源码替换(先从 js/ts 入手,再扩展 vue template;vue template 侧的抽取已升级为 AST 方案)
  5. Vue SFC:template 解析(已采用 @vue/compiler-sfc + @vue/compiler-dom 做 AST 级抽取,替换了早期正则 MVP 方案)
  6. 校验与 CI:missing key / unused key 检测