locale-ai 0.2.3 → 0.3.1
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 +8 -10
- package/dist/catalog.js +30 -4
- package/package.json +8 -3
- package/scripts/trim-onnxruntime.cjs +54 -0
package/README.md
CHANGED
|
@@ -16,9 +16,9 @@ npx locale-ai translate --from en --to fr,es,de
|
|
|
16
16
|
locale-ai 0.2.0
|
|
17
17
|
Found 3 en files in locales/en/
|
|
18
18
|
Models to download (one time, then cached for every project):
|
|
19
|
-
en-fr
|
|
19
|
+
en-fr 345 MB khabouss/opus-mt-tc-big-en-fr-onnx
|
|
20
20
|
...
|
|
21
|
-
Download
|
|
21
|
+
Download 577 MB? (Y/n)
|
|
22
22
|
✓ fr 43 strings translated, 3 files written in 2.7s, 1 plural forms added
|
|
23
23
|
✓ es 43 strings translated, 3 files written in 2.5s, 1 plural forms added
|
|
24
24
|
✓ de 43 strings translated, 3 files written in 2.1s
|
|
@@ -98,11 +98,10 @@ then declare it in `locale-ai.config.json`:
|
|
|
98
98
|
- `prefix` is required for multi-target models (`convert` lists the model's `>>xx<<` tokens).
|
|
99
99
|
- Project models take priority over built-ins for their language pairs and can be used for pivoting (e.g. `ja → en → tr`).
|
|
100
100
|
|
|
101
|
-
**Recommended for quality**: the `opus-mt-tc-big-en-*` models (
|
|
101
|
+
**Recommended for quality**: the `opus-mt-tc-big-en-*` models (es, it, pt, ar, tr, and `zle` for ru/uk). They are ~3x larger (270–370 MB int8) and ~1.5x slower, and clearly better. `en-fr` already uses one of these as its built-in model (see [Languages](#languages)), hosted at [khabouss/opus-mt-tc-big-en-fr-onnx](https://huggingface.co/khabouss/opus-mt-tc-big-en-fr-onnx) — no conversion needed for it.
|
|
102
102
|
|
|
103
103
|
| Target | Built-in model, chrF / BLEU | tc-big model, chrF / BLEU |
|
|
104
104
|
|---|---|---|
|
|
105
|
-
| fr | 68.9 / 53.7 | **72.5 / 55.9** |
|
|
106
105
|
| es | 72.9 / 56.9 | **73.6 / 57.4** |
|
|
107
106
|
| it | 73.8 / 54.9 | **75.3 / 58.2** |
|
|
108
107
|
| pt | 68.3 / 44.4 | **70.6 / 47.7** (`>>por<<`, or `>>pob<<` for pt-BR) |
|
|
@@ -124,7 +123,7 @@ Measured on a sample app (see `test/fixtures`):
|
|
|
124
123
|
| Usable — review before shipping | it, ar, ru, zh-CN, zh-TW |
|
|
125
124
|
| Untested | the other pairs in `locale-ai models list` |
|
|
126
125
|
|
|
127
|
-
With the tc-big models above, it, ar and ru move up a tier and tr becomes available. Not available yet: ja, ko, pl and others; he works with a converted `opus-mt-en-he` (weaker). Moroccan Arabic (Darija): the tc-big en-ar model has a `>>ary<<` token, but its output is close to Modern Standard Arabic — not supported.
|
|
126
|
+
`en-fr` is already on the tc-big model (chrF 72.5 / BLEU 55.9) as a built-in, no config needed. With the other tc-big models above, it, ar and ru move up a tier and tr becomes available. Not available yet: ja, ko, pl and others; he works with a converted `opus-mt-en-he` (weaker). Moroccan Arabic (Darija): the tc-big en-ar model has a `>>ary<<` token, but its output is close to Modern Standard Arabic — not supported.
|
|
128
127
|
|
|
129
128
|
## How it works
|
|
130
129
|
|
|
@@ -136,13 +135,14 @@ With the tc-big models above, it, ar and ru move up a tier and tr becomes availa
|
|
|
136
135
|
- **Sentence splitting**: OPUS-MT drops sentences from multi-sentence inputs, so each sentence is translated separately.
|
|
137
136
|
- **Placeholder masking** with three marker styles tried in order (`{0}` / `<0>…</0>`, then numbers `900`, then `_P0_`), validating every marker; numbers survive models that mangle braces (en-zh, en-ru). A last-resort fallback translates around placeholders, and anything that needed it is listed for review.
|
|
138
137
|
- **Speed** (20-core CPU, ~1 GB RAM): sample app (43 strings) in ~3 s per language with beam search, ~2 s with `--fast`; full sentences at ~18/s (built-in, beam 4), ~12/s (tc-big, beam 4), ~33/s (tc-big, `--fast`).
|
|
138
|
+
- **Install size**: `onnxruntime-node` bundles binaries for every platform, and on linux/x64 downloads a ~260 MB CUDA provider by default — locale-ai only ever runs on CPU (`executionProviders: ["cpu"]`), so a `postinstall` script ([`scripts/trim-onnxruntime.cjs`](scripts/trim-onnxruntime.cjs)) removes the unused platforms and GPU providers after install, cutting it from ~550 MB to ~45 MB on your current platform.
|
|
139
139
|
|
|
140
140
|
## Development
|
|
141
141
|
|
|
142
142
|
```bash
|
|
143
143
|
npm install
|
|
144
144
|
npm test # unit tests (no models)
|
|
145
|
-
npm run test:e2e # real models, downloads ~
|
|
145
|
+
npm run test:e2e # real models, downloads ~345 MB once (en-fr, tc-big)
|
|
146
146
|
node bench/eval.ts --dir <model dir> --lang fr --beams 4 --out out.json # quality benchmark (see bench/README.md)
|
|
147
147
|
npm run dev -- translate --to fr # run from source (Node ≥ 22.18 strips types)
|
|
148
148
|
npm run build # → dist/
|
|
@@ -150,7 +150,5 @@ npm run build # → dist/
|
|
|
150
150
|
|
|
151
151
|
## Next steps
|
|
152
152
|
|
|
153
|
-
1. **
|
|
154
|
-
2. **
|
|
155
|
-
3. **More languages**: ja, ko, pl have no usable OPUS-MT model yet; a different model family would be needed.
|
|
156
|
-
4. **More formats**: YAML, `.po`, ARB, Apple `.strings`.
|
|
153
|
+
1. **More languages**: ja, ko, pl have no usable OPUS-MT model yet; a different model family would be needed.
|
|
154
|
+
2. **More formats**: YAML, `.po`, ARB, Apple `.strings`.
|
package/dist/catalog.js
CHANGED
|
@@ -8,8 +8,8 @@ const pair = (src, tgt) => ({
|
|
|
8
8
|
});
|
|
9
9
|
const DIRECT = [
|
|
10
10
|
"af-en", "ar-en", "cs-en", "da-de", "da-en", "de-en", "de-es", "de-fr",
|
|
11
|
-
"en-af", "en-cs", "en-da", "en-de", "en-es", "en-fi", "en-
|
|
12
|
-
"en-hu", "en-id", "en-it", "en-nl", "en-ro", "en-
|
|
11
|
+
"en-af", "en-cs", "en-da", "en-de", "en-es", "en-fi", "en-hi",
|
|
12
|
+
"en-hu", "en-id", "en-it", "en-nl", "en-ro", "en-sv",
|
|
13
13
|
"en-xh", "es-de", "es-en", "es-fr", "es-it", "es-ru", "et-en", "fi-de",
|
|
14
14
|
"fi-en", "fr-de", "fr-en", "fr-es", "fr-ro", "fr-ru", "hi-en", "hu-en",
|
|
15
15
|
"id-en", "it-en", "it-es", "it-fr", "ja-en", "ko-en", "nl-en", "nl-fr",
|
|
@@ -22,10 +22,36 @@ export const CATALOG = [
|
|
|
22
22
|
const [s, t] = p.split("-");
|
|
23
23
|
return pair(s, t);
|
|
24
24
|
}),
|
|
25
|
+
// tc-big: larger OPUS-MT checkpoints, clearly better than the defaults (see
|
|
26
|
+
// bench/README.md). Converted and hosted per the README's "Add a language,
|
|
27
|
+
// or a better model" section.
|
|
28
|
+
{ ...pair("en", "fr"), repo: "khabouss/opus-mt-tc-big-en-fr-onnx" }, // chrF 72.5 vs 68.9, BLEU 55.9 vs 53.7
|
|
29
|
+
{ ...pair("en", "es"), repo: "khabouss/opus-mt-tc-big-en-es-onnx" }, // chrF 73.6 vs 72.9, BLEU 57.4 vs 56.9
|
|
30
|
+
{ ...pair("en", "it"), repo: "khabouss/opus-mt-tc-big-en-it-onnx" }, // chrF 75.3 vs 73.8, BLEU 58.2 vs 54.9
|
|
31
|
+
// New: Turkish, not supported by any built-in model before this.
|
|
32
|
+
{ ...pair("en", "tr"), repo: "khabouss/opus-mt-tc-big-en-tr-onnx" }, // chrF 67.4, BLEU 42.1
|
|
25
33
|
{
|
|
26
|
-
//
|
|
27
|
-
//
|
|
34
|
+
// Multi-target: >>por<< (European) / >>pob<< (Brazilian). No individual built-in
|
|
35
|
+
// existed before; pt was only reachable via the weaker en-ROMANCE model.
|
|
36
|
+
id: "en-pt",
|
|
37
|
+
repo: "khabouss/opus-mt-tc-big-en-pt-onnx", // chrF 70.6 vs 68.3, BLEU 47.7 vs 44.4
|
|
38
|
+
sources: ["en"],
|
|
39
|
+
targets: ["pt"],
|
|
40
|
+
prefix: (t) => (t.region === "BR" ? ">>pob<<" : ">>por<<"),
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
// Multi-target East Slavic model, replaces the separate en-ru/en-uk built-ins.
|
|
44
|
+
id: "en-zle",
|
|
45
|
+
repo: "khabouss/opus-mt-tc-big-en-zle-onnx", // ru: chrF 68.2 vs 65.7, BLEU 48.1 vs 46.0
|
|
46
|
+
sources: ["en"],
|
|
47
|
+
targets: ["ru", "uk"],
|
|
48
|
+
prefix: (t) => (t.lang === "ru" ? ">>rus<<" : ">>ukr<<"),
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
// Note: the model card lists Moroccan Arabic ("ary") but its output stays close
|
|
52
|
+
// to Modern Standard Arabic, so Darija is not treated as supported.
|
|
28
53
|
...pair("en", "ar"),
|
|
54
|
+
repo: "khabouss/opus-mt-tc-big-en-ar-onnx", // chrF 49.7 vs 47.8, BLEU 19.9 vs 16.6 (greedy)
|
|
29
55
|
prefix: () => ">>ara<<",
|
|
30
56
|
},
|
|
31
57
|
{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "locale-ai",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Translate your i18n locale files locally on CPU. Free, offline, no API keys.",
|
|
5
5
|
"author": "Taha KHABOUSS",
|
|
6
6
|
"repository": {
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
},
|
|
18
18
|
"files": [
|
|
19
19
|
"dist",
|
|
20
|
-
"scripts/convert-marian.py"
|
|
20
|
+
"scripts/convert-marian.py",
|
|
21
|
+
"scripts/trim-onnxruntime.cjs"
|
|
21
22
|
],
|
|
22
23
|
"engines": {
|
|
23
24
|
"node": ">=22.18"
|
|
@@ -28,7 +29,8 @@
|
|
|
28
29
|
"dev": "node src/cli.ts",
|
|
29
30
|
"test": "node --test test/*.test.ts",
|
|
30
31
|
"test:e2e": "LOCALE_AI_E2E=1 node --test test/e2e.test.ts",
|
|
31
|
-
"prepublishOnly": "npm run build && npm test"
|
|
32
|
+
"prepublishOnly": "npm run build && npm test",
|
|
33
|
+
"postinstall": "node scripts/trim-onnxruntime.cjs"
|
|
32
34
|
},
|
|
33
35
|
"keywords": [
|
|
34
36
|
"i18n",
|
|
@@ -48,5 +50,8 @@
|
|
|
48
50
|
"devDependencies": {
|
|
49
51
|
"@types/node": "^26.6.6",
|
|
50
52
|
"typescript": "^7.0.2"
|
|
53
|
+
},
|
|
54
|
+
"allowScripts": {
|
|
55
|
+
"onnxruntime-node@1.30.0": true
|
|
51
56
|
}
|
|
52
57
|
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
// locale-ai only ever runs onnxruntime-node with executionProviders: ["cpu"]
|
|
5
|
+
// (see src/marian.ts) and only ever runs on one platform/arch per install.
|
|
6
|
+
// onnxruntime-node still bundles binaries for every platform, and on
|
|
7
|
+
// linux/x64 its own postinstall downloads a 260 MB CUDA provider we never
|
|
8
|
+
// use (see its script/install-metadata.js). This trims all of that after
|
|
9
|
+
// onnxruntime-node has finished installing, shrinking a ~550 MB unpacked
|
|
10
|
+
// dependency down to the one binary locale-ai actually loads.
|
|
11
|
+
//
|
|
12
|
+
// Best-effort: never fails the install, even if onnxruntime-node changes
|
|
13
|
+
// its layout in a future version.
|
|
14
|
+
|
|
15
|
+
const fs = require('fs');
|
|
16
|
+
const path = require('path');
|
|
17
|
+
|
|
18
|
+
function rm(p) {
|
|
19
|
+
try {
|
|
20
|
+
fs.rmSync(p, { recursive: true, force: true });
|
|
21
|
+
} catch {
|
|
22
|
+
// ignore — best-effort cleanup only
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
const pkgJson = require.resolve('onnxruntime-node/package.json');
|
|
28
|
+
const binRoot = path.join(path.dirname(pkgJson), 'bin', 'napi-v6');
|
|
29
|
+
if (!fs.existsSync(binRoot)) process.exit(0);
|
|
30
|
+
|
|
31
|
+
const platform = process.platform;
|
|
32
|
+
const arch = process.arch;
|
|
33
|
+
|
|
34
|
+
for (const entry of fs.readdirSync(binRoot)) {
|
|
35
|
+
const platformDir = path.join(binRoot, entry);
|
|
36
|
+
if (entry !== platform) {
|
|
37
|
+
rm(platformDir);
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
// Same platform: drop every other architecture.
|
|
41
|
+
for (const archEntry of fs.readdirSync(platformDir)) {
|
|
42
|
+
if (archEntry !== arch) rm(path.join(platformDir, archEntry));
|
|
43
|
+
}
|
|
44
|
+
// Drop GPU execution providers locale-ai never requests.
|
|
45
|
+
const archDir = path.join(platformDir, arch);
|
|
46
|
+
for (const name of fs.readdirSync(archDir)) {
|
|
47
|
+
if (/^libonnxruntime_providers_(cuda|tensorrt|rocm|dml)\./.test(name)) {
|
|
48
|
+
rm(path.join(archDir, name));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
} catch {
|
|
53
|
+
// onnxruntime-node not installed, or its layout changed — nothing to do.
|
|
54
|
+
}
|