altalandi 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/LICENSE +21 -0
- package/README.md +53 -0
- package/altalandi.mjs +87 -0
- package/package.json +17 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Altalandi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# altalandi
|
|
2
|
+
|
|
3
|
+
Turn English or stiff/AI-translated Icelandic into Icelandic that reads as if a
|
|
4
|
+
native wrote it — from your terminal. Thin client over the
|
|
5
|
+
[Altalandi API](https://altalandi.is). Zero dependencies (Node ≥ 18).
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
export ALTALANDI_API_KEY="rtv_..." # mint one at https://altalandi.is/portal
|
|
9
|
+
npx altalandi "Make sure to reach out to us today."
|
|
10
|
+
# → Hafðu samband við okkur í dag.
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
`stdout` is the refined text (pipe it anywhere); `stderr` carries the 0–100
|
|
14
|
+
nativeness score, the meaning verdict, and the diff.
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm i -g altalandi # then use `altalandi ...`
|
|
20
|
+
# or run without installing: npx altalandi "..."
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
altalandi "Some English or Icelandic text."
|
|
27
|
+
echo "some text" | altalandi --domain marketing
|
|
28
|
+
altalandi --json "..." # full JSON response
|
|
29
|
+
altalandi --fast "..." # skip the meaning + nativeness gates
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
| flag | default | meaning |
|
|
33
|
+
|------|---------|---------|
|
|
34
|
+
| `--domain` | `general` | `general` \| `marketing` \| `data-analysis` \| `childrens-fiction` |
|
|
35
|
+
| `--register` | `neutral` | `formal` \| `neutral` \| `warm` |
|
|
36
|
+
| `--json` | off | print the full API response |
|
|
37
|
+
| `--fast` | off | `preserveMeaning:false`, `scoreNativeness:false` (one model call) |
|
|
38
|
+
|
|
39
|
+
## The meaning guarantee
|
|
40
|
+
|
|
41
|
+
Altalandi never silently changes meaning. For Icelandic input where the rewrite
|
|
42
|
+
can't be verified to preserve meaning, it returns the **original unchanged** and
|
|
43
|
+
says so on `stderr` (or `meaningPreserved:false` with `--json`). Check it before
|
|
44
|
+
trusting the output in an automated pipeline.
|
|
45
|
+
|
|
46
|
+
## Config
|
|
47
|
+
|
|
48
|
+
| env | default | purpose |
|
|
49
|
+
|-----|---------|---------|
|
|
50
|
+
| `ALTALANDI_API_KEY` | — | your key (Bearer). Mint at https://altalandi.is/portal |
|
|
51
|
+
| `ALTALANDI_BASE_URL` | `https://altalandi.is/api` | API base (override for self-hosting) |
|
|
52
|
+
|
|
53
|
+
MIT licensed. The hosted API is metered per key (calls + words/day).
|
package/altalandi.mjs
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// altalandi — turn English or stiff/AI Icelandic into native Icelandic from
|
|
3
|
+
// your terminal. Zero dependencies (Node >= 18 has global fetch).
|
|
4
|
+
//
|
|
5
|
+
// export ALTALANDI_API_KEY=... # get one at https://altalandi.is
|
|
6
|
+
// altalandi "Make sure to reach out to us today."
|
|
7
|
+
// echo "some text" | altalandi --domain marketing
|
|
8
|
+
//
|
|
9
|
+
// stdout = the refined text (so you can pipe it); stderr = nativeness score,
|
|
10
|
+
// meaning verdict, and the diff.
|
|
11
|
+
|
|
12
|
+
const args = process.argv.slice(2);
|
|
13
|
+
const opts = { domain: "general", register: "neutral", json: false, fast: false };
|
|
14
|
+
const positional = [];
|
|
15
|
+
for (let i = 0; i < args.length; i++) {
|
|
16
|
+
const a = args[i];
|
|
17
|
+
if (a === "-h" || a === "--help") { help(); process.exit(0); }
|
|
18
|
+
else if (a === "--json") opts.json = true;
|
|
19
|
+
else if (a === "--fast") opts.fast = true;
|
|
20
|
+
else if (a === "--domain") opts.domain = args[++i];
|
|
21
|
+
else if (a === "--register") opts.register = args[++i];
|
|
22
|
+
else if (a === "--base-url") opts.baseUrl = args[++i];
|
|
23
|
+
else if (a === "--key") opts.key = args[++i];
|
|
24
|
+
else positional.push(a);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function help() {
|
|
28
|
+
console.log(`altalandi — native Icelandic from your terminal
|
|
29
|
+
|
|
30
|
+
Usage:
|
|
31
|
+
altalandi "text to refine"
|
|
32
|
+
echo "text" | altalandi
|
|
33
|
+
altalandi --domain marketing --register warm "text"
|
|
34
|
+
|
|
35
|
+
Options:
|
|
36
|
+
--domain general | marketing | data-analysis | childrens-fiction (default general)
|
|
37
|
+
--register formal | neutral | warm (default neutral)
|
|
38
|
+
--fast skip the meaning gate + nativeness score (faster, cheaper)
|
|
39
|
+
--json print the full JSON response
|
|
40
|
+
--base-url API base (default $ALTALANDI_BASE_URL or https://altalandi.is/api)
|
|
41
|
+
--key API key (default $ALTALANDI_API_KEY)
|
|
42
|
+
|
|
43
|
+
stdout = refined text; stderr = nativeness / meaning / diff.`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function readStdin() {
|
|
47
|
+
return new Promise((resolve) => {
|
|
48
|
+
if (process.stdin.isTTY) return resolve("");
|
|
49
|
+
let d = "";
|
|
50
|
+
process.stdin.setEncoding("utf8");
|
|
51
|
+
process.stdin.on("data", (c) => (d += c));
|
|
52
|
+
process.stdin.on("end", () => resolve(d));
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const baseUrl = (opts.baseUrl || process.env.ALTALANDI_BASE_URL || "https://altalandi.is/api").replace(/\/$/, "");
|
|
57
|
+
const key = opts.key || process.env.ALTALANDI_API_KEY || process.env.ALTALANDI_KEY;
|
|
58
|
+
|
|
59
|
+
const text = (positional.join(" ").trim()) || (await readStdin()).trim();
|
|
60
|
+
if (!text) { console.error("No input. Pass text as an argument or pipe via stdin. (altalandi --help)"); process.exit(2); }
|
|
61
|
+
if (!key) { console.error("No API key. Set ALTALANDI_API_KEY or pass --key. Get one at https://altalandi.is"); process.exit(2); }
|
|
62
|
+
|
|
63
|
+
const body = { text, domain: opts.domain, register: opts.register };
|
|
64
|
+
if (opts.fast) { body.preserveMeaning = false; body.scoreNativeness = false; }
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
const res = await fetch(`${baseUrl}/v1/refine`, {
|
|
68
|
+
method: "POST",
|
|
69
|
+
headers: { "content-type": "application/json", authorization: `Bearer ${key}` },
|
|
70
|
+
body: JSON.stringify(body),
|
|
71
|
+
});
|
|
72
|
+
const data = await res.json().catch(() => ({}));
|
|
73
|
+
if (!res.ok) { console.error(`Error ${res.status}: ${data.detail || res.statusText}`); process.exit(1); }
|
|
74
|
+
if (opts.json) { process.stdout.write(JSON.stringify(data, null, 2) + "\n"); process.exit(0); }
|
|
75
|
+
|
|
76
|
+
process.stdout.write(data.output + "\n");
|
|
77
|
+
const q = data.quality || {};
|
|
78
|
+
const meta = [];
|
|
79
|
+
if (q.nativenessScore != null) meta.push(`nativeness ${q.nativenessScore}/100`);
|
|
80
|
+
if (data.meaningPreserved === false) meta.push("⚠ MEANING DRIFT — returned the original");
|
|
81
|
+
else if (data.meaningPreserved === true) meta.push("meaning preserved");
|
|
82
|
+
if (meta.length) console.error("· " + meta.join(" · "));
|
|
83
|
+
for (const d of data.diffs || []) console.error(` − ${d.before}\n + ${d.after} (${d.reason})`);
|
|
84
|
+
} catch (e) {
|
|
85
|
+
console.error("Request failed:", e.message);
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "altalandi",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Turn English or stiff/AI-translated Icelandic into native-sounding Icelandic from your terminal — via the Altalandi API, with a meaning-preservation check.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": { "altalandi": "./altalandi.mjs" },
|
|
7
|
+
"files": ["altalandi.mjs", "README.md", "LICENSE"],
|
|
8
|
+
"keywords": [
|
|
9
|
+
"icelandic", "íslenska", "translation", "translationese", "nlp",
|
|
10
|
+
"altalandi", "cli", "i18n", "localization", "language"
|
|
11
|
+
],
|
|
12
|
+
"homepage": "https://altalandi.is",
|
|
13
|
+
"repository": { "type": "git", "url": "git+https://github.com/pbidhjorvar/ritvit.git", "directory": "tools/cli" },
|
|
14
|
+
"bugs": { "url": "https://github.com/pbidhjorvar/ritvit/issues" },
|
|
15
|
+
"engines": { "node": ">=18" },
|
|
16
|
+
"license": "MIT"
|
|
17
|
+
}
|