@shipi18n/cli 2.3.0 → 2.4.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/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # @shipi18n/cli
2
2
 
3
+ ## 2.4.0
4
+
5
+ - Fix: `check --semantic` explains a `judged 0`. When every translated key has a structural error
6
+ there is nothing for the judge to look at — correct, but it looked broken. The CLI now says how
7
+ many keys it skipped and to fix those first.
8
+ - Fix (via core 2.4.0): the missing-SDK error names the install that works for the `npx` path.
9
+ - Note: the npm description on this page was stale until this release — npm only refreshes it on
10
+ publish, so the registry still led with translation after the project repositioned around QA.
11
+
3
12
  ## 2.3.0
4
13
 
5
14
  - New: `shipi18n lock [path]` — record hand-edited translations in a readable, commit-friendly
package/README.md CHANGED
@@ -1,15 +1,42 @@
1
1
  # @shipi18n/cli
2
2
 
3
- Open-source, **bring-your-own-LLM** i18n translation CLI. Translate your locale files with your own
4
- OpenAI or Anthropic key — no Shipi18n account, no hosted API.
3
+ **Catch broken translations before you ship them** and translate with your own LLM key when you
4
+ want to. Open-source, no account, no hosted API.
5
+
6
+ ## Quickstart — check, no API key
5
7
 
6
8
  ```bash
7
- npm i -g @shipi18n/cli @anthropic-ai/sdk # or add `openai` for the OpenAI provider
9
+ npx @shipi18n/cli check ./locales -s en
10
+ ```
11
+
12
+ Reports missing and orphaned keys, dropped placeholders, collapsed plurals, empty values,
13
+ untranslated copy and per-language coverage. Deterministic and offline — no LLM, no key, nothing
14
+ leaves your machine. Exit code `1` when there are errors, so it works as a CI gate as-is.
15
+
16
+ Then, for the errors structure cannot see, bring a key. The judge needs a provider SDK next to the
17
+ CLI, so install both:
18
+
19
+ ```bash
20
+ npm i -D @shipi18n/cli @anthropic-ai/sdk # or `openai`
21
+ export ANTHROPIC_API_KEY=sk-ant-...
22
+ npx shipi18n check ./locales -s en --semantic
8
23
  ```
9
24
 
10
- ## Quickstart
25
+ An LLM reads each source/translation pair and reports mistranslations, omissions and additions —
26
+ advisory by default, so it never fails your build unless you ask it to.
27
+
28
+ > **Note.** `--semantic` only judges keys that pass the structural checks, so if a tree is full of
29
+ > missing keys and dropped placeholders you will see `judged 0` and no model calls. That is by
30
+ > design — fix the structural errors first, then re-run for meaning.
31
+
32
+ **Measured** on a 228-pair corpus committed before the judge was written: **100% of planted errors
33
+ caught, 7.1% false positives.** Full harness in the repo under `evals/semantic/` — run it against
34
+ your own model.
35
+
36
+ ## Translating
11
37
 
12
38
  ```bash
39
+ npm i -g @shipi18n/cli @anthropic-ai/sdk # or add `openai` for the OpenAI provider
13
40
  export ANTHROPIC_API_KEY=sk-ant-...
14
41
  shipi18n translate en.json --target es,fr,de
15
42
  ```
@@ -107,12 +134,22 @@ already failed the structural check are never sent to the judge.
107
134
  What it flags: `semantic-mistranslation` (says something different), `semantic-omission` (meaning
108
135
  dropped), `semantic-addition` (meaning invented).
109
136
 
110
- **Measured** (2026-08-16, committed 228-pair corpus, thresholds fixed before the judge was built,
111
- default judge `claude-haiku-4-5`, 3 passes): **100%** of planted errors caught (100% per category,
112
- 100% label accuracy), **7.1%** false positives on clean pairs, 6/6 glossary violations with 0 false,
113
- ~62k tokens in 141s. On a real 478-pair production tree it flagged 3.6% of keys; the warm-cache
114
- rerun made **zero** model calls. Full harness: `evals/semantic/` in the repo — run it against your
115
- own model.
137
+ **Measured** (committed 228-pair corpus, thresholds fixed before the judge was built, default judge
138
+ `claude-haiku-4-5`, 3 passes). Two independent runs, 2026-08-16 and 2026-08-17:
139
+
140
+ | | 2026-08-16 | 2026-08-17 |
141
+ | --- | --- | --- |
142
+ | planted errors caught | 54/54 (100%) | 54/54 (100%) |
143
+ | per-category recall | 100% | 100% |
144
+ | label accuracy | 100% | 53/54 (98.1%) |
145
+ | false positives on clean pairs | 12/168 (7.1%) | 12/168 (7.1%) |
146
+ | glossary violations | 6/6, 0 false | 6/6, 0 false |
147
+ | cost | ~62k tokens / 141s | ~59k tokens / 156s, 48 calls |
148
+
149
+ The judge is a model, so treat these as a range, not a constant — label accuracy moved between runs
150
+ while catch and false-positive rates held. On a real 478-pair production tree it flagged 3.6% of keys;
151
+ the warm-cache rerun made **zero** model calls. Full harness: `evals/semantic/` in the repo — run it
152
+ against your own model and publish what you get.
116
153
 
117
154
  ### Glossary (deterministic — no LLM)
118
155
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@shipi18n/cli",
3
- "version": "2.3.0",
4
- "description": "Open-source, bring-your-own-LLM i18n translation CLI. Translate locale files with your own OpenAI/Anthropic key.",
3
+ "version": "2.4.0",
4
+ "description": "Catch broken translations before you ship: dropped placeholders, missing keys, collapsed plurals and with your own LLM key — mistranslations the structure checks cannot see. CI-ready (SARIF, JUnit, exit codes). Translates too.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "shipi18n": "./bin/shipi18n.js"
@@ -19,6 +19,11 @@
19
19
  "access": "public"
20
20
  },
21
21
  "keywords": [
22
+ "sarif",
23
+ "ci",
24
+ "lint",
25
+ "translation-quality",
26
+ "i18n-qa",
22
27
  "i18n",
23
28
  "cli",
24
29
  "translation",
@@ -39,7 +44,7 @@
39
44
  "chalk": "^5.3.0",
40
45
  "commander": "^12.0.0",
41
46
  "ora": "^8.0.1",
42
- "@shipi18n/core": "^2.3.0"
47
+ "@shipi18n/core": "^2.4.0"
43
48
  },
44
49
  "peerDependencies": {
45
50
  "@anthropic-ai/sdk": ">=0.30.0",
@@ -132,6 +132,16 @@ export function checkCommand(program) {
132
132
  `${judge.calls} model call(s), ${judge.parseFailures} discarded pass(es)`
133
133
  )
134
134
  )
135
+ // "judged 0" on a badly broken tree is correct but reads as a broken
136
+ // feature: the judge skips keys that already carry a structural error.
137
+ if (judge.judged === 0 && judge.excluded > 0) {
138
+ console.error(
139
+ chalk.yellow(
140
+ `note: nothing was judged — all ${judge.excluded} translated key(s) have structural ` +
141
+ `errors, which the semantic pass skips. Fix those first, then re-run with --semantic.`
142
+ )
143
+ )
144
+ }
135
145
  } catch (err) {
136
146
  console.error(chalk.red(`Semantic pass failed: ${err.message}`))
137
147
  process.exitCode = 2