@hagicode/hagi18n 0.1.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,8 +3,10 @@
3
3
  [![npm version](https://img.shields.io/npm/v/%40hagicode%2Fhagi18n?logo=npm&color=cb3837)](https://www.npmjs.com/package/@hagicode/hagi18n)
4
4
  [![npm downloads](https://img.shields.io/npm/dm/%40hagicode%2Fhagi18n?logo=npm&color=2d8cf0)](https://www.npmjs.com/package/@hagicode/hagi18n)
5
5
  [![license](https://img.shields.io/badge/license-MIT-ffd43b)](./LICENSE)
6
+ [![Node.js](https://img.shields.io/badge/node-%3E%3D24.0.0-339933?logo=node.js&logoColor=white)](https://nodejs.org/)
7
+ [![CI](https://img.shields.io/github/actions/workflow/status/HagiCode-org/hagi18n/ci.yml?branch=main&label=CI)](https://github.com/HagiCode-org/hagi18n/actions/workflows/ci.yml)
6
8
 
7
- `@hagicode/hagi18n` is a reusable YAML locale maintenance toolkit for HagiCode projects. It was abstracted from the mature Web workflow in `repos/web/buildTools`, but it runs as an independent package and CLI.
9
+ `@hagicode/hagi18n` is a reusable YAML locale maintenance toolkit for HagiCode projects. It runs as an independent package and CLI.
8
10
 
9
11
  It supports:
10
12
 
@@ -21,15 +23,15 @@ Use it when an AI agent needs to:
21
23
 
22
24
  - run or explain `hagi18n audit`, `doctor`, `sync`, or `prune`
23
25
  - add or review a `hagi18n.yaml` file
24
- - inspect or modify the source in `repos/hagi18n`
26
+ - inspect or modify the package source
25
27
  - validate locale maintenance workflows against a consumer repository
26
28
 
27
29
  The skill includes focused references for command usage, configuration, and package development.
28
30
 
29
31
  ## Requirements
30
32
 
31
- - Node.js 20 or newer
32
- - npm for package management
33
+ - Node.js 24 or newer
34
+ - pnpm for package management
33
35
 
34
36
  ## Installation
35
37
 
@@ -78,8 +80,16 @@ Example:
78
80
  localesRoot: src/locales
79
81
  repoRoot: .
80
82
  baseLocale: en-US
83
+ auditBaseLocales:
84
+ - en-US
85
+ - ja-JP
81
86
  targetLocales:
82
87
  - zh-CN
88
+ auditIdenticalAllowlist:
89
+ common.yml:
90
+ - brand.name
91
+ pages/home.yml:
92
+ - hero.cta
83
93
  doctor:
84
94
  excludedDirectories:
85
95
  - .git
@@ -103,6 +113,12 @@ Precedence is:
103
113
 
104
114
  Relative paths in `hagi18n.yaml` are resolved from the config file directory.
105
115
 
116
+ `baseLocale` remains the single structural baseline for mutation workflows like `sync` and `prune`. `auditBaseLocales` is audit-only, ordered, and additive: the first resolved locale becomes the structural audit baseline and any additional locales are used only for exact duplicate-value detection during `audit`, `report`, and `doctor`.
117
+
118
+ `auditIdenticalAllowlist` exempts specific translation keys whose value is intentionally identical to the baseline, such as a brand name or a technical identifier. Each key is a locale-relative YAML file path written with forward slashes, and each value is a list of dot-separated scalar key paths in that file. An entry is exact: it suppresses only the matching `baselineValueMatches` entry, applies to every target locale, and does not disable any other check. It does not accept globs, patterns, or value-based rules. Use it only for terms that are meant to stay identical to English.
119
+
120
+ This is different from `doctor.allowlist`. `doctor.allowlist` exempts repository-scan findings by rule id and source file path, and it does not apply to audit output. Across config layers, a higher-precedence list for a file replaces the lower-precedence list for that same file, and files defined only in the lower layer keep their lists.
121
+
106
122
  ## CLI Commands
107
123
 
108
124
  ```bash
@@ -117,31 +133,35 @@ hagi18n prune
117
133
  Examples:
118
134
 
119
135
  ```bash
120
- hagi18n audit --locales-root src/locales --base-locale en-US
136
+ hagi18n audit --locales-root src/locales --base-locale en-US --base-locale ja-JP
121
137
  hagi18n audit --config hagi18n.yaml --json
122
138
  hagi18n report --config hagi18n.yaml
123
- hagi18n doctor --config hagi18n.yaml
139
+ hagi18n doctor --config hagi18n.yaml --base-locale en-US --base-locale zh-CN
124
140
  hagi18n sync --from en-US --to zh-CN
125
141
  hagi18n sync --from en-US --to zh-CN --write
126
142
  hagi18n prune --from en-US --to zh-CN --write
127
143
  ```
128
144
 
145
+ `audit`, `report`, and `doctor` accept repeated `--base-locale` values. Repeated baselines are normalized, deduped, and preserved in order. `sync` and `prune` still use exactly one mutation baseline through `--from`.
146
+
129
147
  `sync` and `prune` are dry-run by default. Pass `--write` to mutate files.
130
148
 
131
149
  ## Option Reference
132
150
 
133
- | Option | Commands | Description |
134
- | --- | --- | --- |
135
- | `--config <path>` | all except `info` | Load defaults from a config file |
136
- | `--locales-root <path>` | audit, report, doctor, sync, prune | Locale root directory |
137
- | `--base-locale <locale>` | audit, report, doctor | Base locale for comparison |
138
- | `--from <locale>` | sync, prune | Base locale for mutation commands |
139
- | `--locale <locale>` | audit, report, doctor | Limit output to one or more locales |
140
- | `--to <locale>` | sync, prune | Limit mutations to one or more target locales |
141
- | `--repo-root <path>` | doctor | Repository root for repository scanning |
142
- | `--json` | audit, doctor, sync, prune | Print JSON instead of text |
143
- | `--dry-run` | sync, prune | Preview mutations without writing files |
144
- | `--write` | sync, prune | Apply mutations to disk |
151
+ | Option | Commands | Description |
152
+ | ------------------------- | ---------------------------------- | ----------------------------------------------------------------------------------------------------- |
153
+ | `--config <path>` | all except `info` | Load defaults from a config file |
154
+ | `--locales-root <path>` | audit, report, doctor, sync, prune | Locale root directory |
155
+ | `auditBaseLocales` | `hagi18n.yaml` | Ordered audit-only baselines; first resolved locale stays structural |
156
+ | `auditIdenticalAllowlist` | `hagi18n.yaml` | Exact file and key paths whose baseline-identical values are exempt from audit `baselineValueMatches` |
157
+ | `--base-locale <locale>` | audit, report, doctor | Audit baseline locale; can be repeated |
158
+ | `--from <locale>` | sync, prune | Base locale for mutation commands |
159
+ | `--locale <locale>` | audit, report, doctor | Limit output to one or more locales |
160
+ | `--to <locale>` | sync, prune | Limit mutations to one or more target locales |
161
+ | `--repo-root <path>` | doctor | Repository root for repository scanning |
162
+ | `--json` | audit, doctor, sync, prune | Print JSON instead of text |
163
+ | `--dry-run` | sync, prune | Preview mutations without writing files |
164
+ | `--write` | sync, prune | Apply mutations to disk |
145
165
 
146
166
  ## JSON Output and Exit Codes
147
167
 
@@ -151,7 +171,7 @@ hagi18n prune --from en-US --to zh-CN --write
151
171
  - `sync` and `prune` return exit code `1` only for parse or processing errors. Planned or applied mutations are reported in the summary.
152
172
  - Command parsing failures return exit code `1` from the current `commander` integration.
153
173
 
154
- The JSON payload is the same structured summary returned by the TypeScript API.
174
+ The JSON payload is the same structured summary returned by the TypeScript API. For multi-baseline audits it now includes additive `baselineLocales` at the summary level and `baselineValueMatches` for each target locale result.
155
175
 
156
176
  ## TypeScript API
157
177
 
@@ -167,7 +187,7 @@ import {
167
187
 
168
188
  const audit = await auditLocaleTree({
169
189
  localesRoot: "src/locales",
170
- baseLocale: "en-US"
190
+ auditBaseLocales: ["en-US", "ja-JP"]
171
191
  });
172
192
 
173
193
  console.log(formatAuditSummary(audit));
@@ -181,25 +201,6 @@ Main exports include:
181
201
  - text formatters such as `formatAuditSummary`, `formatDoctorSummary`, and `formatMutationSummary`
182
202
  - package metadata helpers such as `getPackageMetadata` and `createRuntimeInfo`
183
203
 
184
- ## Web Reference Mapping
185
-
186
- This package preserves the maintenance model from the Web repository:
187
-
188
- - `repos/web/buildTools/lib/i18nLocaleToolkit.mjs` -> `src/locale-toolkit.ts`
189
- - `repos/web/buildTools/i18n-locale-cli.mjs` -> `src/cli.ts`
190
-
191
- The Web project remains the behavior reference, but it does not need runtime changes to use this package later.
192
-
193
- ## Development
194
-
195
- Run commands from `repos/hagi18n/`:
196
-
197
- ```bash
198
- npm install
199
- npm test
200
- npm run build
201
- ```
202
-
203
204
  ## License
204
205
 
205
206
  MIT. See [LICENSE](./LICENSE).
package/README_cn.md CHANGED
@@ -1,6 +1,12 @@
1
1
  # Hagi18n
2
2
 
3
- `@hagicode/hagi18n` 是一个可复用的 YAML 语言包维护工具,抽象自 `repos/web/buildTools` 中已经成熟的 Web i18n 工作流,但可以作为独立 npm 包和 CLI 使用。
3
+ [![npm version](https://img.shields.io/npm/v/%40hagicode%2Fhagi18n?logo=npm&color=cb3837)](https://www.npmjs.com/package/@hagicode/hagi18n)
4
+ [![npm downloads](https://img.shields.io/npm/dm/%40hagicode%2Fhagi18n?logo=npm&color=2d8cf0)](https://www.npmjs.com/package/@hagicode/hagi18n)
5
+ [![license](https://img.shields.io/badge/license-MIT-ffd43b)](./LICENSE)
6
+ [![Node.js](https://img.shields.io/badge/node-%3E%3D24.0.0-339933?logo=node.js&logoColor=white)](https://nodejs.org/)
7
+ [![CI](https://img.shields.io/github/actions/workflow/status/HagiCode-org/hagi18n/ci.yml?branch=main&label=CI)](https://github.com/HagiCode-org/hagi18n/actions/workflows/ci.yml)
8
+
9
+ `@hagicode/hagi18n` 是一个可复用的 YAML 语言包维护工具,可作为独立 npm 包和 CLI 使用。
4
10
 
5
11
  它提供:
6
12
 
@@ -17,15 +23,15 @@
17
23
 
18
24
  - 执行或解释 `hagi18n audit`、`doctor`、`sync`、`prune`
19
25
  - 新增或审查 `hagi18n.yaml`
20
- - 检查或修改 `repos/hagi18n` 内源码
26
+ - 检查或修改该包的源码
21
27
  - 在消费方仓库中验证语言包维护流程
22
28
 
23
29
  skill 内还附带了命令使用、配置结构和包开发流程的拆分参考文档。
24
30
 
25
31
  ## 前提
26
32
 
27
- - Node.js 20 或更高版本
28
- - 使用 npm 管理依赖
33
+ - Node.js 24 或更高版本
34
+ - 使用 pnpm 管理依赖
29
35
 
30
36
  ## 安装
31
37
 
@@ -69,8 +75,16 @@ CLI 默认会在当前工作目录查找 `hagi18n.yaml`。也可以显式传入
69
75
  localesRoot: src/locales
70
76
  repoRoot: .
71
77
  baseLocale: en-US
78
+ auditBaseLocales:
79
+ - en-US
80
+ - ja-JP
72
81
  targetLocales:
73
82
  - zh-CN
83
+ auditIdenticalAllowlist:
84
+ common.yml:
85
+ - brand.name
86
+ pages/home.yml:
87
+ - hero.cta
74
88
  doctor:
75
89
  excludedDirectories:
76
90
  - .git
@@ -94,6 +108,12 @@ doctor:
94
108
 
95
109
  `hagi18n.yaml` 中的相对路径会相对于配置文件所在目录解析,因此不同项目可以用它自定义 `baseLocale`、`localesRoot`、`repoRoot` 和默认目标语言目录。
96
110
 
111
+ `baseLocale` 仍然是 `sync` / `prune` 这类变更命令使用的单一结构基线。`auditBaseLocales` 是仅用于审计的有序附加配置:第一个解析后的语言仍作为结构比较基线,其余语言只参与 `audit`、`report`、`doctor` 中的精确重复值检测。
112
+
113
+ `auditIdenticalAllowlist` 用于豁免那些有意与基线语言保持一致的译文键,例如品牌名或技术标识符。每个键是相对于语言目录的 YAML 文件路径(使用正斜杠),每个值是该文件中以点号分隔的标量键路径列表。该配置是精确匹配:它只抑制对应的 `baselineValueMatches` 条目,适用于所有目标语言,不会关闭其他任何检查,也不支持 glob、模式或基于值的规则。仅对确实应与英文保持相同的术语使用它。
114
+
115
+ 它与 `doctor.allowlist` 不同。`doctor.allowlist` 按规则 ID 和源文件路径豁免仓库扫描结果,并且不作用于审计输出。在配置层之间,同一文件的高优先级列表会替换低优先级列表;只在低优先级层中定义的文件则保留其列表。
116
+
97
117
  ## CLI 命令
98
118
 
99
119
  ```bash
@@ -108,31 +128,35 @@ hagi18n prune
108
128
  示例:
109
129
 
110
130
  ```bash
111
- hagi18n audit --locales-root src/locales --base-locale en-US
131
+ hagi18n audit --locales-root src/locales --base-locale en-US --base-locale ja-JP
112
132
  hagi18n audit --config hagi18n.yaml --json
113
133
  hagi18n report --config hagi18n.yaml
114
- hagi18n doctor --config hagi18n.yaml
134
+ hagi18n doctor --config hagi18n.yaml --base-locale en-US --base-locale zh-CN
115
135
  hagi18n sync --from en-US --to zh-CN
116
136
  hagi18n sync --from en-US --to zh-CN --write
117
137
  hagi18n prune --from en-US --to zh-CN --write
118
138
  ```
119
139
 
140
+ `audit`、`report`、`doctor` 现在支持重复传入 `--base-locale`。这些基线会按顺序规范化并去重。`sync` 和 `prune` 仍然只通过 `--from` 使用单一变更基线。
141
+
120
142
  `sync` 和 `prune` 默认不会写盘,只有传入 `--write` 才会真正修改文件。
121
143
 
122
144
  ## 参数说明
123
145
 
124
- | 参数 | 命令 | 说明 |
125
- | --- | --- | --- |
126
- | `--config <path>` | `info` 之外所有命令 | 加载配置文件 |
127
- | `--locales-root <path>` | audit, report, doctor, sync, prune | 语言包根目录 |
128
- | `--base-locale <locale>` | audit, report, doctor | 审计时使用的基准语言 |
129
- | `--from <locale>` | sync, prune | 变更时使用的基准语言 |
130
- | `--locale <locale>` | audit, report, doctor | 限定一个或多个目标语言 |
131
- | `--to <locale>` | sync, prune | 限定一个或多个目标语言 |
132
- | `--repo-root <path>` | doctor | 仓库扫描根目录 |
133
- | `--json` | audit, doctor, sync, prune | 输出 JSON |
134
- | `--dry-run` | sync, prune | 仅预览,不写盘 |
135
- | `--write` | sync, prune | 真正写入文件 |
146
+ | 参数 | 命令 | 说明 |
147
+ | ------------------------- | ---------------------------------- | ----------------------------------------------------------------------- |
148
+ | `--config <path>` | `info` 之外所有命令 | 加载配置文件 |
149
+ | `--locales-root <path>` | audit, report, doctor, sync, prune | 语言包根目录 |
150
+ | `auditBaseLocales` | `hagi18n.yaml` | 有序的审计专用基线列表;第一个解析结果仍为结构基线 |
151
+ | `auditIdenticalAllowlist` | `hagi18n.yaml` | 精确的文件与键路径,其与基线相同的值豁免审计中的 `baselineValueMatches` |
152
+ | `--base-locale <locale>` | audit, report, doctor | 审计基线语言;可重复传入 |
153
+ | `--from <locale>` | sync, prune | 变更时使用的基准语言 |
154
+ | `--locale <locale>` | audit, report, doctor | 限定一个或多个目标语言 |
155
+ | `--to <locale>` | sync, prune | 限定一个或多个目标语言 |
156
+ | `--repo-root <path>` | doctor | 仓库扫描根目录 |
157
+ | `--json` | audit, doctor, sync, prune | 输出 JSON |
158
+ | `--dry-run` | sync, prune | 仅预览,不写盘 |
159
+ | `--write` | sync, prune | 真正写入文件 |
136
160
 
137
161
  ## JSON 输出与退出码
138
162
 
@@ -141,7 +165,7 @@ hagi18n prune --from en-US --to zh-CN --write
141
165
  - `doctor`:审计或仓库扫描存在问题时返回 `1`
142
166
  - `sync` / `prune`:只有解析或处理错误时返回 `1`,正常的预览或写入结果都会输出摘要
143
167
 
144
- JSON 输出与 TypeScript API 返回的结构化 summary 保持一致。
168
+ JSON 输出与 TypeScript API 返回的结构化 summary 保持一致。多基线审计时,summary 会新增 `baselineLocales`,每个目标语言结果会新增 `baselineValueMatches`。
145
169
 
146
170
  ## TypeScript API
147
171
 
@@ -157,7 +181,7 @@ import {
157
181
 
158
182
  const audit = await auditLocaleTree({
159
183
  localesRoot: "src/locales",
160
- baseLocale: "en-US"
184
+ auditBaseLocales: ["en-US", "ja-JP"]
161
185
  });
162
186
 
163
187
  console.log(formatAuditSummary(audit));
@@ -171,21 +195,6 @@ console.log(formatAuditSummary(audit));
171
195
  - 文本格式化函数:`formatAuditSummary`、`formatDoctorSummary`、`formatMutationSummary`
172
196
  - 元数据函数:`getPackageMetadata`、`createRuntimeInfo`
173
197
 
174
- ## 与 Web 参考实现的对应关系
175
-
176
- 此包保留了 Web 项目的维护模型:
198
+ ## 许可证
177
199
 
178
- - `repos/web/buildTools/lib/i18nLocaleToolkit.mjs` -> `src/locale-toolkit.ts`
179
- - `repos/web/buildTools/i18n-locale-cli.mjs` -> `src/cli.ts`
180
-
181
- 也就是说,这次抽象保留了 Web 的参考行为,但不会要求 `repos/web` 立即修改运行时代码。
182
-
183
- ## 开发
184
-
185
- 在 `repos/hagi18n/` 目录执行:
186
-
187
- ```bash
188
- npm install
189
- npm test
190
- npm run build
191
- ```
200
+ MIT。参见 [LICENSE](./LICENSE)。
package/dist/cli.js CHANGED
@@ -7,13 +7,25 @@ function collectValues(value, previous = []) {
7
7
  previous.push(value);
8
8
  return previous;
9
9
  }
10
- function toToolkitOptions(options) {
10
+ function toLocaleArray(value) {
11
+ if (value === undefined) {
12
+ return undefined;
13
+ }
14
+ return Array.isArray(value) ? value : [value];
15
+ }
16
+ function getPrimaryBaseLocale(options) {
17
+ return toLocaleArray(options.baseLocale)?.[0] ?? options.from;
18
+ }
19
+ function toToolkitOptions(options, { includeAuditBaseLocales = false } = {}) {
11
20
  const targetLocales = [...(options.locale ?? []), ...(options.to ?? [])];
12
21
  return {
13
22
  configPath: options.config,
14
23
  localesRoot: options.localesRoot,
15
24
  repoRoot: options.repoRoot,
16
- baseLocale: options.baseLocale ?? options.from,
25
+ baseLocale: getPrimaryBaseLocale(options),
26
+ auditBaseLocales: includeAuditBaseLocales
27
+ ? toLocaleArray(options.baseLocale)
28
+ : undefined,
17
29
  targetLocales: targetLocales.length > 0 ? targetLocales : undefined
18
30
  };
19
31
  }
@@ -30,15 +42,20 @@ function printSummary(summary, { json = false, formatter }) {
30
42
  }
31
43
  process.stdout.write(`${formatter(summary)}\n`);
32
44
  }
33
- function applySharedOptions(command, { includeRepoRoot = false } = {}) {
45
+ function applySharedOptions(command, { includeRepoRoot = false, auditBaseLocaleMode = "none" } = {}) {
34
46
  command
35
47
  .addOption(new Option("--config <path>", "load defaults from a hagi18n.yaml file"))
36
48
  .addOption(new Option("--locales-root <path>", "locale root directory"))
37
- .addOption(new Option("--base-locale <locale>", "base locale to compare against"))
38
49
  .addOption(new Option("--from <locale>", "source locale used as the structure baseline"))
39
50
  .addOption(new Option("--locale <locale>", "limit the command to one or more locales").argParser(collectValues))
40
51
  .addOption(new Option("--to <locale>", "target locale; can be repeated").argParser(collectValues))
41
52
  .addOption(new Option("--json", "print machine-readable JSON output"));
53
+ if (auditBaseLocaleMode === "single") {
54
+ command.addOption(new Option("--base-locale <locale>", "base locale to compare against"));
55
+ }
56
+ if (auditBaseLocaleMode === "repeat") {
57
+ command.addOption(new Option("--base-locale <locale>", "audit baseline locale; can be repeated, first resolved locale stays structural").argParser(collectValues));
58
+ }
42
59
  if (includeRepoRoot) {
43
60
  command.addOption(new Option("--repo-root <path>", "repository root for doctor scanning"));
44
61
  }
@@ -66,37 +83,37 @@ export function createCli() {
66
83
  });
67
84
  applySharedOptions(program
68
85
  .command("audit")
69
- .description("audit YAML locale files for drift against a base locale")
86
+ .description("audit YAML locale files for drift against one or more baseline locales")
70
87
  .action(async (options) => {
71
- const summary = await auditLocaleTree(toToolkitOptions(options));
88
+ const summary = await auditLocaleTree(toToolkitOptions(options, { includeAuditBaseLocales: true }));
72
89
  printSummary(summary, {
73
90
  json: options.json,
74
91
  formatter: formatAuditSummary
75
92
  });
76
93
  process.exitCode = summary.hasIssues ? 1 : 0;
77
- }));
94
+ }), { auditBaseLocaleMode: "repeat" });
78
95
  applySharedOptions(program
79
96
  .command("report")
80
- .description("run audit and print JSON output")
97
+ .description("run multi-baseline audit and print JSON output")
81
98
  .action(async (options) => {
82
- const summary = await auditLocaleTree(toToolkitOptions(options));
99
+ const summary = await auditLocaleTree(toToolkitOptions(options, { includeAuditBaseLocales: true }));
83
100
  printSummary(summary, {
84
101
  json: true,
85
102
  formatter: formatAuditSummary
86
103
  });
87
104
  process.exitCode = summary.hasIssues ? 1 : 0;
88
- }));
105
+ }), { auditBaseLocaleMode: "repeat" });
89
106
  applySharedOptions(program
90
107
  .command("doctor")
91
- .description("audit locale drift and scan the repository for legacy locale references")
108
+ .description("run multi-baseline locale audit and scan the repository for legacy locale references")
92
109
  .action(async (options) => {
93
- const summary = await doctorLocaleTree(toToolkitOptions(options));
110
+ const summary = await doctorLocaleTree(toToolkitOptions(options, { includeAuditBaseLocales: true }));
94
111
  printSummary(summary, {
95
112
  json: options.json,
96
113
  formatter: formatDoctorSummary
97
114
  });
98
115
  process.exitCode = summary.hasIssues ? 1 : 0;
99
- }), { includeRepoRoot: true });
116
+ }), { includeRepoRoot: true, auditBaseLocaleMode: "repeat" });
100
117
  applyMutationOptions(program
101
118
  .command("sync")
102
119
  .description("add missing files and keys from the base locale")
@@ -128,9 +145,9 @@ export function createCli() {
128
145
  program.addHelpText("after", `
129
146
 
130
147
  Examples:
131
- hagi18n audit --locales-root src/locales --base-locale en-US
148
+ hagi18n audit --locales-root src/locales --base-locale en-US --base-locale ja-JP
132
149
  hagi18n report --config hagi18n.yaml
133
- hagi18n doctor --repo-root . --locales-root src/locales
150
+ hagi18n doctor --repo-root . --locales-root src/locales --base-locale en-US --base-locale zh-CN
134
151
  hagi18n sync --from en-US --to zh-CN --dry-run
135
152
  hagi18n prune --from en-US --to zh-CN --write
136
153
  `);
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
package/dist/config.d.ts CHANGED
@@ -20,7 +20,9 @@ export interface Hagi18nConfig {
20
20
  localesRoot?: string;
21
21
  repoRoot?: string;
22
22
  baseLocale?: string;
23
+ auditBaseLocales?: string[];
23
24
  targetLocales?: string[];
25
+ auditIdenticalAllowlist?: Record<string, string[]>;
24
26
  doctor?: Hagi18nDoctorConfig;
25
27
  }
26
28
  export interface ResolvedDoctorScanRule extends DoctorScanRuleConfig {
@@ -39,7 +41,9 @@ export interface ResolvedHagi18nConfig {
39
41
  localesRoot: string;
40
42
  repoRoot: string;
41
43
  baseLocale: string;
44
+ auditBaseLocales: string[];
42
45
  targetLocales: string[];
46
+ auditIdenticalAllowlist: Record<string, string[]>;
43
47
  doctor: ResolvedHagi18nDoctorConfig;
44
48
  }
45
49
  export interface LoadHagi18nConfigOptions {
package/dist/config.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { access, readFile } from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import yaml from "js-yaml";
4
+ import { normalizeLocaleName } from "./locale-name.js";
4
5
  export const DEFAULT_BASE_LOCALE = "en-US";
5
6
  export const DEFAULT_CONFIG_FILE_NAMES = ["hagi18n.yaml", "hagi18n.yml"];
6
7
  export const DEFAULT_DOCTOR_EXCLUDED_DIRECTORIES = [
@@ -94,6 +95,26 @@ function dedupeStrings(values) {
94
95
  }
95
96
  return output;
96
97
  }
98
+ function normalizeLocaleValue(value) {
99
+ if (value === undefined) {
100
+ return undefined;
101
+ }
102
+ return normalizeLocaleName(value) ?? value.trim();
103
+ }
104
+ function normalizeLocaleValues(values) {
105
+ if (!values) {
106
+ return undefined;
107
+ }
108
+ const output = [];
109
+ for (const value of values) {
110
+ const normalizedValue = normalizeLocaleName(value) ?? value.trim();
111
+ if (!normalizedValue || output.includes(normalizedValue)) {
112
+ continue;
113
+ }
114
+ output.push(normalizedValue);
115
+ }
116
+ return output;
117
+ }
97
118
  function normalizeAllowlist(value, fieldName) {
98
119
  if (value === undefined) {
99
120
  return undefined;
@@ -107,6 +128,33 @@ function normalizeAllowlist(value, fieldName) {
107
128
  }
108
129
  return output;
109
130
  }
131
+ function groupIdenticalAllowlist(entries) {
132
+ const grouped = new Map();
133
+ for (const [rawFilePath, keyPaths] of entries) {
134
+ const filePath = rawFilePath.trim().replace(/\\/g, "/");
135
+ if (!filePath) {
136
+ continue;
137
+ }
138
+ grouped.set(filePath, dedupeStrings([...(grouped.get(filePath) ?? []), ...keyPaths]));
139
+ }
140
+ return Object.fromEntries(grouped);
141
+ }
142
+ function normalizeIdenticalAllowlist(value, fieldName) {
143
+ if (value === undefined) {
144
+ return undefined;
145
+ }
146
+ if (!isPlainObject(value)) {
147
+ throw new Error(`${fieldName} must be a mapping of locale-relative file paths to scalar key path arrays.`);
148
+ }
149
+ const entries = Object.entries(value).map(([filePath, keyPaths]) => {
150
+ ensureString(filePath, `${fieldName} file path`);
151
+ return [
152
+ filePath,
153
+ ensureStringArray(keyPaths, `${fieldName}.${filePath}`) ?? []
154
+ ];
155
+ });
156
+ return groupIdenticalAllowlist(entries);
157
+ }
110
158
  function normalizeScanRules(value, fieldName) {
111
159
  if (value === undefined) {
112
160
  return undefined;
@@ -154,7 +202,9 @@ function parseConfigDocument(document, configPath) {
154
202
  localesRoot: ensureString(document.localesRoot, "localesRoot"),
155
203
  repoRoot: ensureString(document.repoRoot, "repoRoot"),
156
204
  baseLocale: ensureString(document.baseLocale, "baseLocale"),
205
+ auditBaseLocales: ensureStringArray(document.auditBaseLocales, "auditBaseLocales"),
157
206
  targetLocales: ensureStringArray(document.targetLocales, "targetLocales"),
207
+ auditIdenticalAllowlist: normalizeIdenticalAllowlist(document.auditIdenticalAllowlist, "auditIdenticalAllowlist"),
158
208
  doctor: parseDoctorConfig(document.doctor)
159
209
  };
160
210
  }
@@ -228,9 +278,11 @@ function resolveConfigLayer(config, { cwd, configPath }) {
228
278
  return {
229
279
  localesRoot: resolveStringPath(config.localesRoot, baseDirectory),
230
280
  repoRoot: resolveStringPath(config.repoRoot, baseDirectory),
231
- baseLocale: config.baseLocale?.trim(),
232
- targetLocales: config.targetLocales
233
- ? dedupeStrings(config.targetLocales)
281
+ baseLocale: normalizeLocaleValue(config.baseLocale),
282
+ auditBaseLocales: normalizeLocaleValues(config.auditBaseLocales),
283
+ targetLocales: normalizeLocaleValues(config.targetLocales),
284
+ auditIdenticalAllowlist: config.auditIdenticalAllowlist
285
+ ? groupIdenticalAllowlist(Object.entries(config.auditIdenticalAllowlist))
234
286
  : undefined,
235
287
  doctor: {
236
288
  excludedDirectories: config.doctor?.excludedDirectories
@@ -264,6 +316,11 @@ function mergeAllowlists(baseAllowlist, overrideAllowlist) {
264
316
  }
265
317
  return merged;
266
318
  }
319
+ function mergeIdenticalAllowlists(baseAllowlist, overrideAllowlist) {
320
+ // Replace per file: a higher-precedence list for a file wins outright,
321
+ // and files defined only in the lower layer keep their lists.
322
+ return { ...baseAllowlist, ...overrideAllowlist };
323
+ }
267
324
  function mergeResolvedDoctorConfig(baseConfig, overrideConfig) {
268
325
  if (!overrideConfig) {
269
326
  return {
@@ -297,7 +354,9 @@ function createDefaultResolvedConfig(cwd) {
297
354
  localesRoot: path.resolve(cwd, "src/locales"),
298
355
  repoRoot: cwd,
299
356
  baseLocale: DEFAULT_BASE_LOCALE,
357
+ auditBaseLocales: [DEFAULT_BASE_LOCALE],
300
358
  targetLocales: [],
359
+ auditIdenticalAllowlist: {},
301
360
  doctor: {
302
361
  excludedDirectories: [...DEFAULT_DOCTOR_EXCLUDED_DIRECTORIES],
303
362
  textFileExtensions: [...DEFAULT_DOCTOR_TEXT_FILE_EXTENSIONS],
@@ -319,22 +378,34 @@ export async function resolveHagi18nConfig(options = {}) {
319
378
  localesRoot: options.localesRoot,
320
379
  repoRoot: options.repoRoot,
321
380
  baseLocale: options.baseLocale,
381
+ auditBaseLocales: options.auditBaseLocales,
322
382
  targetLocales: options.targetLocales,
383
+ auditIdenticalAllowlist: options.auditIdenticalAllowlist,
323
384
  doctor: options.doctor
324
385
  }, {
325
386
  cwd,
326
387
  configPath: null
327
388
  });
328
389
  const mergedDoctor = mergeResolvedDoctorConfig(mergeResolvedDoctorConfig(defaults.doctor, fileLayer.doctor), overrideLayer.doctor);
390
+ const mergedBaseLocale = overrideLayer.baseLocale ?? fileLayer.baseLocale ?? defaults.baseLocale;
391
+ const mergedAuditBaseLocales = overrideLayer.auditBaseLocales && overrideLayer.auditBaseLocales.length > 0
392
+ ? overrideLayer.auditBaseLocales
393
+ : overrideLayer.baseLocale
394
+ ? [mergedBaseLocale]
395
+ : fileLayer.auditBaseLocales && fileLayer.auditBaseLocales.length > 0
396
+ ? fileLayer.auditBaseLocales
397
+ : [mergedBaseLocale];
329
398
  return {
330
399
  cwd,
331
400
  configPath: loaded.configPath,
332
401
  localesRoot: overrideLayer.localesRoot ?? fileLayer.localesRoot ?? defaults.localesRoot,
333
402
  repoRoot: overrideLayer.repoRoot ?? fileLayer.repoRoot ?? defaults.repoRoot,
334
- baseLocale: overrideLayer.baseLocale ?? fileLayer.baseLocale ?? defaults.baseLocale,
403
+ baseLocale: mergedBaseLocale,
404
+ auditBaseLocales: mergedAuditBaseLocales,
335
405
  targetLocales: overrideLayer.targetLocales ??
336
406
  fileLayer.targetLocales ??
337
407
  defaults.targetLocales,
408
+ auditIdenticalAllowlist: mergeIdenticalAllowlists(mergeIdenticalAllowlists(defaults.auditIdenticalAllowlist, fileLayer.auditIdenticalAllowlist), overrideLayer.auditIdenticalAllowlist),
338
409
  doctor: mergedDoctor
339
410
  };
340
411
  }