translatex 0.0.0-stage → 0.1.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 +41 -2
- package/bin/translatex.js +47 -0
- package/package.json +47 -4
- package/scripts/install.js +126 -0
package/README.md
CHANGED
|
@@ -1,3 +1,42 @@
|
|
|
1
|
-
#
|
|
1
|
+
# translatex
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Free translation for your agent — no API key, no signup, no config.**
|
|
4
|
+
|
|
5
|
+
`npm install -g translatex` puts a 6 MB static binary on `PATH`. 26 translation
|
|
6
|
+
providers raced in parallel, structured JSON out, one skill file for 24 coding
|
|
7
|
+
agents. The package itself is a shim: the binary is downloaded once from the
|
|
8
|
+
matching GitHub release.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install -g translatex
|
|
12
|
+
translatex translate "Hello world" -t zh
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Agent setup
|
|
16
|
+
|
|
17
|
+
The integration is the CLI plus a skill. Give your agent the skill from
|
|
18
|
+
[`integrations/skill/translatex/SKILL.md`](https://github.com/w21180239/translatex/blob/main/integrations/skill/translatex/SKILL.md),
|
|
19
|
+
or the short block in
|
|
20
|
+
[`integrations/guidance/AGENTS.md`](https://github.com/w21180239/translatex/blob/main/integrations/guidance/AGENTS.md)
|
|
21
|
+
for harnesses that read a project instructions file.
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
translatex translate "Hello world" -t zh --format json
|
|
25
|
+
translatex roundtrip "In today's landscape, …" --from en --format json
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Full harness matrix: https://github.com/w21180239/translatex/tree/main/integrations
|
|
29
|
+
|
|
30
|
+
## Offline install
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
TRANSLATEX_BINARY_PATH=/path/to/translatex npm install -g translatex
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Or skip npm entirely:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
cargo install translatex --locked
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Full documentation: https://github.com/w21180239/translatex
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
// Thin shim: the native binary is fetched by scripts/install.js at install
|
|
5
|
+
// time, so this package stays platform-neutral and a few kilobytes.
|
|
6
|
+
|
|
7
|
+
const { spawn } = require('node:child_process');
|
|
8
|
+
const fs = require('node:fs');
|
|
9
|
+
const path = require('node:path');
|
|
10
|
+
|
|
11
|
+
const exe = path.join(
|
|
12
|
+
__dirname,
|
|
13
|
+
process.platform === 'win32' ? 'translatex.exe' : 'translatex'
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
if (!fs.existsSync(exe)) {
|
|
17
|
+
process.stderr.write(
|
|
18
|
+
[
|
|
19
|
+
'translatex: the native binary is missing from this install.',
|
|
20
|
+
'',
|
|
21
|
+
'Reinstall it:',
|
|
22
|
+
' npm install -g translatex --force',
|
|
23
|
+
'',
|
|
24
|
+
'Or build from source:',
|
|
25
|
+
' cargo install translatex --locked',
|
|
26
|
+
'',
|
|
27
|
+
'If your platform has no prebuilt binary yet, use cargo.',
|
|
28
|
+
'',
|
|
29
|
+
].join('\n')
|
|
30
|
+
);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const child = spawn(exe, process.argv.slice(2), { stdio: 'inherit' });
|
|
35
|
+
|
|
36
|
+
child.on('error', (err) => {
|
|
37
|
+
process.stderr.write(`translatex: failed to start ${exe}: ${err.message}\n`);
|
|
38
|
+
process.exit(1);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
child.on('exit', (code, signal) => {
|
|
42
|
+
if (signal) {
|
|
43
|
+
process.kill(process.pid, signal);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
process.exit(code === null ? 1 : code);
|
|
47
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,49 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "translatex",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Free translation CLI for AI agents: no API key, no signup, no config. 26 providers, JSON output, one 6 MB binary.",
|
|
5
|
+
"license": "MIT OR Apache-2.0",
|
|
6
|
+
"author": "w21180239",
|
|
7
|
+
"homepage": "https://github.com/w21180239/translatex",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/w21180239/translatex.git"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/w21180239/translatex/issues"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"translation",
|
|
17
|
+
"translator",
|
|
18
|
+
"translate",
|
|
19
|
+
"cli",
|
|
20
|
+
"agent",
|
|
21
|
+
"agent-native",
|
|
22
|
+
"ai",
|
|
23
|
+
"llm",
|
|
24
|
+
"i18n",
|
|
25
|
+
"localization",
|
|
26
|
+
"free",
|
|
27
|
+
"no-api-key",
|
|
28
|
+
"humanizer",
|
|
29
|
+
"deai",
|
|
30
|
+
"mcp-alternative"
|
|
31
|
+
],
|
|
32
|
+
"bin": {
|
|
33
|
+
"translatex": "bin/translatex.js"
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"postinstall": "node scripts/install.js"
|
|
37
|
+
},
|
|
38
|
+
"files": [
|
|
39
|
+
"bin/translatex.js",
|
|
40
|
+
"scripts/install.js",
|
|
41
|
+
"README.md"
|
|
42
|
+
],
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=18"
|
|
45
|
+
},
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"access": "public"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
// Downloads the prebuilt binary for this platform from the matching GitHub
|
|
5
|
+
// release. Falls back with a clear message when no asset exists, so the package
|
|
6
|
+
// never installs a broken shim silently.
|
|
7
|
+
|
|
8
|
+
const fs = require('node:fs');
|
|
9
|
+
const path = require('node:path');
|
|
10
|
+
const https = require('node:https');
|
|
11
|
+
|
|
12
|
+
const pkg = require('../package.json');
|
|
13
|
+
const REPO = 'w21180239/translatex';
|
|
14
|
+
|
|
15
|
+
const TARGETS = {
|
|
16
|
+
'darwin-x64': 'translatex-x86_64-apple-darwin',
|
|
17
|
+
'darwin-arm64': 'translatex-aarch64-apple-darwin',
|
|
18
|
+
'linux-x64': 'translatex-x86_64-unknown-linux-gnu',
|
|
19
|
+
'linux-arm64': 'translatex-aarch64-unknown-linux-gnu',
|
|
20
|
+
'win32-x64': 'translatex-x86_64-pc-windows-msvc',
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
function target() {
|
|
24
|
+
const key = `${process.platform}-${process.arch}`;
|
|
25
|
+
const name = TARGETS[key];
|
|
26
|
+
if (!name) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
return name;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function download(url, destination, redirects = 0) {
|
|
33
|
+
return new Promise((resolve, reject) => {
|
|
34
|
+
if (redirects > 5) {
|
|
35
|
+
reject(new Error(`too many redirects for ${url}`));
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
https
|
|
39
|
+
.get(url, { headers: { 'user-agent': `translatex-npm/${pkg.version}` } }, (res) => {
|
|
40
|
+
const { statusCode, headers } = res;
|
|
41
|
+
if (statusCode >= 300 && statusCode < 400 && headers.location) {
|
|
42
|
+
res.resume();
|
|
43
|
+
download(headers.location, destination, redirects + 1).then(resolve, reject);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (statusCode !== 200) {
|
|
47
|
+
res.resume();
|
|
48
|
+
reject(new Error(`HTTP ${statusCode} for ${url}`));
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const out = fs.createWriteStream(destination);
|
|
52
|
+
res.pipe(out);
|
|
53
|
+
out.on('finish', () => out.close(resolve));
|
|
54
|
+
out.on('error', reject);
|
|
55
|
+
})
|
|
56
|
+
.on('error', reject);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function main() {
|
|
61
|
+
// Escape hatch for air-gapped installs and for trying a local build.
|
|
62
|
+
if (process.env.TRANSLATEX_BINARY_PATH) {
|
|
63
|
+
const from = process.env.TRANSLATEX_BINARY_PATH;
|
|
64
|
+
const to = path.join(__dirname, '..', 'bin', path.basename(from));
|
|
65
|
+
fs.copyFileSync(from, to);
|
|
66
|
+
process.stderr.write(`translatex: using ${from}\n`);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const name = target();
|
|
71
|
+
if (!name) {
|
|
72
|
+
process.stderr.write(
|
|
73
|
+
[
|
|
74
|
+
`translatex: no prebuilt binary for ${process.platform}/${process.arch}.`,
|
|
75
|
+
'',
|
|
76
|
+
'Install from source instead:',
|
|
77
|
+
' cargo install translatex --locked',
|
|
78
|
+
'',
|
|
79
|
+
].join('\n')
|
|
80
|
+
);
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const exe = process.platform === 'win32' ? 'translatex.exe' : 'translatex';
|
|
85
|
+
const destination = path.join(__dirname, '..', 'bin', exe);
|
|
86
|
+
|
|
87
|
+
if (fs.existsSync(destination)) {
|
|
88
|
+
fs.chmodSync(destination, 0o755);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const base = process.env.TRANSLATEX_RELEASE_BASE
|
|
93
|
+
|| `https://github.com/${REPO}/releases/download/v${pkg.version}`;
|
|
94
|
+
const url = `${base}/${name}.tar.gz`;
|
|
95
|
+
const tmp = `${destination}.tar.gz`;
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
process.stderr.write(`translatex: downloading ${url}\n`);
|
|
99
|
+
await download(url, tmp);
|
|
100
|
+
// The release asset is a .tar.gz holding the binary at its root.
|
|
101
|
+
await new Promise((resolve, reject) => {
|
|
102
|
+
const { execFile } = require('node:child_process');
|
|
103
|
+
execFile('tar', ['-xzf', tmp, '-C', path.dirname(destination)], (err) => {
|
|
104
|
+
if (err) reject(err);
|
|
105
|
+
else resolve();
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
fs.rmSync(tmp, { force: true });
|
|
109
|
+
fs.chmodSync(destination, 0o755);
|
|
110
|
+
process.stderr.write(`translatex: installed ${destination}\n`);
|
|
111
|
+
} catch (err) {
|
|
112
|
+
fs.rmSync(tmp, { force: true });
|
|
113
|
+
process.stderr.write(
|
|
114
|
+
[
|
|
115
|
+
`translatex: could not download the prebuilt binary (${err.message}).`,
|
|
116
|
+
'',
|
|
117
|
+
'Install from source instead:',
|
|
118
|
+
' cargo install translatex --locked',
|
|
119
|
+
'',
|
|
120
|
+
].join('\n')
|
|
121
|
+
);
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
main();
|