ai-i18n-tools 1.8.0 → 1.8.2

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.
Files changed (53) hide show
  1. package/README.md +46 -359
  2. package/dist/api/llm-client.d.ts +4 -3
  3. package/dist/api/llm-client.d.ts.map +1 -1
  4. package/dist/api/llm-client.js +6 -5
  5. package/dist/api/llm-client.js.map +1 -1
  6. package/dist/build-info.generated.d.ts +1 -1
  7. package/dist/build-info.generated.js +1 -1
  8. package/dist/cli/index.js +13 -2
  9. package/dist/cli/index.js.map +1 -1
  10. package/dist/core/cache.d.ts +17 -0
  11. package/dist/core/cache.d.ts.map +1 -1
  12. package/dist/core/cache.js +43 -0
  13. package/dist/core/cache.js.map +1 -1
  14. package/dist/core/config.d.ts +2 -2
  15. package/dist/core/config.d.ts.map +1 -1
  16. package/dist/core/config.js +2 -2
  17. package/dist/core/config.js.map +1 -1
  18. package/dist/core/han-variant-data.d.ts +1 -1
  19. package/dist/core/han-variant-data.js +1 -1
  20. package/dist/core/locale-utils.d.ts +9 -0
  21. package/dist/core/locale-utils.d.ts.map +1 -1
  22. package/dist/core/locale-utils.js +24 -0
  23. package/dist/core/locale-utils.js.map +1 -1
  24. package/dist/core/prompt-builder.d.ts +7 -6
  25. package/dist/core/prompt-builder.d.ts.map +1 -1
  26. package/dist/core/prompt-builder.js +6 -5
  27. package/dist/core/prompt-builder.js.map +1 -1
  28. package/dist/core/prompts.d.ts +1 -1
  29. package/dist/core/prompts.d.ts.map +1 -1
  30. package/dist/core/ui-languages.d.ts +7 -0
  31. package/dist/core/ui-languages.d.ts.map +1 -1
  32. package/dist/core/ui-languages.js +39 -0
  33. package/dist/core/ui-languages.js.map +1 -1
  34. package/dist/dashboard-app/ai-i18n-tools_logo.svg +99 -0
  35. package/dist/dashboard-app/favicon.ico +0 -0
  36. package/dist/dashboard-app/index.html +13 -1
  37. package/dist/dashboard-app/styles.css +13 -0
  38. package/dist/i18n/locales/de.json +2 -1
  39. package/dist/i18n/locales/es.json +2 -1
  40. package/dist/i18n/locales/fr.json +2 -1
  41. package/dist/i18n/locales/hi.json +656 -0
  42. package/dist/i18n/locales/ja.json +2 -1
  43. package/dist/i18n/locales/ko.json +2 -1
  44. package/dist/i18n/locales/pt-BR.json +2 -1
  45. package/dist/i18n/locales/ui-languages.json +3 -3
  46. package/dist/i18n/locales/zh-Hans.json +2 -1
  47. package/dist/i18n/locales/zh-Hant.json +2 -1
  48. package/dist/index.d.ts +2 -2
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +2 -2
  51. package/dist/index.js.map +1 -1
  52. package/docs/ai-i18n-tools-context.md +89 -23
  53. package/package.json +2 -3
package/README.md CHANGED
@@ -1,395 +1,82 @@
1
- <a id="ai-i18n-tools"></a>
2
- # ai-i18n-tools
3
-
4
- [![npm version](https://img.shields.io/npm/v/ai-i18n-tools.svg)](https://www.npmjs.com/package/ai-i18n-tools) [![npm downloads](https://img.shields.io/npm/dm/ai-i18n-tools.svg)](https://www.npmjs.com/package/ai-i18n-tools) [![Node.js](https://img.shields.io/node/v/ai-i18n-tools.svg)](https://nodejs.org/) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/wsj-br/ai-i18n-tools/blob/main/LICENSE) [![CI](https://github.com/wsj-br/ai-i18n-tools/actions/workflows/ci.yml/badge.svg)](https://github.com/wsj-br/ai-i18n-tools/actions/workflows/ci.yml)
5
-
6
-
7
- <small id="lang-list">[English (UK)](./README.md) · [Deutsch](./translated-docs/README.de.md) · [Español](./translated-docs/README.es.md) · [Français](./translated-docs/README.fr.md) · [Hindi (Roman)](./translated-docs/README.hi-Latn.md) · [日本語](./translated-docs/README.ja.md) · [한국어](./translated-docs/README.ko.md) · [Português (Brasil)](./translated-docs/README.pt-BR.md) · [简体中文](./translated-docs/README.zh-Hans.md) · [繁體中文](./translated-docs/README.zh-Hant.md)</small>
8
-
9
-
10
-
11
- **Translate your app and documentation using the AI model of your choice: no lock-in, no rewrites.**
12
-
13
-
14
-
15
- `ai-i18n-tools` is a CLI and toolkit for internationalizing JavaScript/TypeScript applications and documentation sites - including Docusaurus, Astro, Starlight, VitePress, Nextra, Fumadocs, and plain Markdown/MDX - using large language models.
16
-
17
- Choose from built-in presets (**OpenAI**, **Anthropic**, **Google Gemini**, **NVIDIA**, **DeepSeek**, **Groq**, **Mistral**, **xAI**, **Cerebras**, **Alibaba**, **APIFUN**, **OpenRouter**, **Ollama**) or point at any OpenAI-compatible API. Switch providers or models per project—or even per language—without modifying your codebase.
18
-
19
- One config file drives three translation modes, so you can mix and match based on how your content is structured:
20
-
21
- - **UI strings** — Extracts `t("…")` calls from JS/TS (and optionally `.astro` files) and generates flat, per-locale JSON for i18next or static SSG lookup.
22
- - **Documents** — Translates Markdown, MDX, and `.astro` pages listed in `docs[].contentPaths` using `translate-docs`. Works with **VitePress**, **Starlight**, **Docusaurus**, **Nextra**, **Fumadocs**, Astro-based sites, or any static site generator that reads from Markdown/MDX/`.astro` source files.
23
- - **JSON** — Translates arbitrary nested JSON bundles defined in `json[]`. Use `translate-json` when UI copy lives in per-locale JSON files instead of `t()` calls in source.
24
-
25
- **SVG** assets get their own path: `features.translateSVG`, the top-level `svg` block, and `translate-svg`—not `docs[].contentPaths`.
26
-
27
- **Which should I use?**
28
-
29
- | Your content | Command |
30
- |-------------------------------------------------------------------------------|---------------------------------------------|
31
- | Source code uses `t()` | **UI strings** — `extract` / `translate-ui` |
32
- | Localized pages or docs sites (VitePress, Starlight, Docusaurus, Nextra, Fumadocs, Astro, etc.) | **Documents** — `translate-docs` |
33
- | Standalone, nested JSON locale files | **JSON** — `translate-json` |
34
-
35
- All three share a file/SQLite cache, so only new or changed segments (strings or text chunks) are ever re-sent to the model — reruns are fast and cheap regardless of which provider you're using.
1
+ <p align="center">
2
+ <img src="docs/public/ai-i18n-tools_logo.png" alt="ai-i18n-tools logo" width="128" />
3
+ </p>
36
4
 
5
+ # ai-i18n-tools
37
6
 
38
- <!-- START doctoc generated TOC please keep comment here to allow auto update -->
39
- <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
40
- **Table of Contents**
7
+ <small id="lang-list">[English (UK)](./README.md) · [Deutsch](./translated-docs/README.de.md) · [Español](./translated-docs/README.es.md) · [Français](./translated-docs/README.fr.md) · [हिन्दी](./translated-docs/README.hi.md) · [日本語](./translated-docs/README.ja.md) · [한국어](./translated-docs/README.ko.md) · [Português (Brasil)](./translated-docs/README.pt-BR.md) · [简体中文](./translated-docs/README.zh-Hans.md) · [繁體中文](./translated-docs/README.zh-Hant.md)</small>
41
8
 
42
- - [Translation types](#translation-types)
43
- - [Installation](#installation)
44
- - [Using the CLI](#using-the-cli)
45
- - [LLM providers](#llm-providers)
46
- - [Quick start](#quick-start)
47
- - [UI strings](#ui-strings)
48
- - [Documents](#documents)
49
- - [VitePress](#vitepress)
50
- - [Nextra](#nextra)
51
- - [Fumadocs](#fumadocs)
52
- - [Astro (plain Astro & Starlight)](#astro-plain-astro--starlight)
53
- - [Combined sync](#combined-sync)
54
- - [Runtime helpers](#runtime-helpers)
55
- - [CLI commands](#cli-commands)
56
- - [Tool UI language (logs, help, dashboard)](#tool-ui-language-logs-help-dashboard)
57
- - [Documentation](#documentation)
58
- - [License](#license)
9
+ [![npm version](https://img.shields.io/npm/v/ai-i18n-tools.svg)](https://www.npmjs.com/package/ai-i18n-tools) [![npm downloads](https://img.shields.io/npm/dm/ai-i18n-tools.svg)](https://www.npmjs.com/package/ai-i18n-tools) [![Node.js](https://img.shields.io/node/v/ai-i18n-tools.svg)](https://nodejs.org/) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/wsj-br/ai-i18n-tools/blob/main/LICENSE) [![CI](https://github.com/wsj-br/ai-i18n-tools/actions/workflows/ci.yml/badge.svg)](https://github.com/wsj-br/ai-i18n-tools/actions/workflows/ci.yml)
59
10
 
60
- <!-- END doctoc generated TOC please keep comment here to allow auto update -->
11
+ **Translate your app and documentation with the AI model of your choice no lock-in, no rewrites.**
61
12
 
13
+ CLI and toolkit for internationalizing JavaScript/TypeScript apps and documentation sites (VitePress, Starlight, Docusaurus, Nextra, Fumadocs, Astro, plain Markdown/MDX). Use built-in presets for OpenAI, Anthropic, Gemini, OpenRouter, Ollama, and more — or any OpenAI-compatible API. Switch provider or model per project or per locale without changing your codebase.
62
14
 
15
+ ## Features
63
16
 
64
- <a id="translation-types"></a>
65
- ## Translation types
17
+ | | |
18
+ | --- | --- |
19
+ | **UI strings** | Extract `t("…")` from JS/TS/Astro (and `data-i18n*` in HTML) → flat per-locale JSON |
20
+ | **Documents** | Translate Markdown, MDX, and `.astro` pages for major doc frameworks |
21
+ | **JSON** | Translate nested locale bundles when copy lives outside `t()` calls |
22
+ | **SVG** | Translate illustrated SVG labels via `translate-svg` |
23
+ | **Smart cache** | Shared SQLite cache — only new or changed segments hit the model |
24
+ | **One `sync`** | Runs extract → UI → SVG → docs → JSON in the right order from one config |
66
25
 
67
- Each translation type has its own guide with full configuration details: [UI strings](docs/guide/ui-strings/), [Documents](docs/guide/documents/), and [JSON](docs/guide/json.md). See [What is ai-i18n-tools?](docs/guide/what-is-ai-i18n-tools.md) for a side-by-side comparison.
26
+ ## Which pipeline?
68
27
 
69
- A few things worth knowing up front: UI strings translates missing entries per locale via the active LLM provider (see [LLM providers](#llm-providers)) and writes flat JSON files (`de.json`, `pt-BR.json`, …), with the English source text as the runtime lookup key — `strings.json` is the extraction cache, not the runtime bundle. Documents supports `docs[].docsOutput.style` values `"nested"`, `"flat"`, `"doc-system"`, and aliases `"docusaurus"` / `"astro-starlight"` / `"vitepress"` / `"nextra"` / `"fumadocs"` (see [Output layouts](docs/guide/documents/output-layouts.md)). All three share `ai-i18n-tools.config.json` and can be combined; `sync` runs extract, UI translation, translate SVG, `translate-docs`, and `translate-json` in order according to your `features` flags.
28
+ | Your content | Command |
29
+ | --- | --- |
30
+ | Source uses `t()` or HTML markers | **UI strings** — `extract` / `translate-ui` |
31
+ | Localized pages or docs sites | **Documents** — `translate-docs` |
32
+ | Standalone nested JSON locale files | **JSON** — `translate-json` |
70
33
 
71
- ---
34
+ See [What is ai-i18n-tools?](docs/guide/what-is-ai-i18n-tools.md) for a full comparison.
72
35
 
73
- <a id="installation"></a>
74
- ## Installation
36
+ ## Install
75
37
 
76
- The published package is **ESM-only** (`"type": "module"`). Node.js `>=22.16.0` required.
38
+ ESM-only. Requires Node.js `>=22.16.0`.
77
39
 
78
40
  ```bash
79
- npm install ai-i18n-tools
80
- # or
81
41
  pnpm add ai-i18n-tools
42
+ # or: npm install ai-i18n-tools
82
43
  ```
83
44
 
84
- <a id="using-the-cli"></a>
85
- ### Using the CLI
86
-
87
- After you install the package in your project, npm/pnpm/yarn link the published bin entry (`bin/ai-i18n-tools.mjs`) into `node_modules/.bin/ai-i18n-tools`. That shim loads the compiled CLI from the installed package.
88
-
89
- To type the bare `ai-i18n-tools` command in an interactive shell, configure one of the options below. Without setup, the shell cannot find the binary even after a local install.
90
-
91
- **direnv** — add to a `.envrc` in the project root (bash/zsh; see [direnv.net](https://direnv.net/)):
92
-
93
- ```bash
94
- PATH_add node_modules/.bin
95
- ```
96
-
97
- After `direnv allow`, the bare command is available whenever you `cd` into the project.
98
-
99
- **Manual PATH** — from the project root in an interactive shell:
45
+ Set an API key for your provider (default `init` uses OpenRouter; Ollama needs none):
100
46
 
101
47
  ```bash
102
- # bash/zsh
103
- export PATH="$PWD/node_modules/.bin:$PATH"
104
- ai-i18n-tools sync
105
- ```
106
-
107
- ```powershell
108
- # Windows PowerShell
109
- $env:Path = "$PWD\node_modules\.bin;$env:Path"
110
- ai-i18n-tools sync
111
- ```
112
-
113
- **Global install** — install the CLI once and invoke it from any directory:
114
-
115
- ```bash
116
- npm install -g ai-i18n-tools
117
- # or
118
- pnpm add -g ai-i18n-tools
119
- ```
120
-
121
- A global install uses the globally pinned version. For per-project version pinning, prefer direnv or manual PATH so `node_modules/.bin` resolves to the project's dependency.
122
-
123
- **`package.json` scripts** — when npm or pnpm runs a script, it prepends `node_modules/.bin` to `PATH`, so the bare command name works inside scripts without shell PATH changes:
124
-
125
- ```json
126
- "scripts": {
127
- "i18n:extract": "ai-i18n-tools extract",
128
- "i18n:sync": "ai-i18n-tools sync",
129
- "i18n:translate:ui": "ai-i18n-tools translate-ui",
130
- "i18n:translate:svg": "ai-i18n-tools translate-svg",
131
- "i18n:translate:docs": "ai-i18n-tools translate-docs",
132
- "i18n:translate:json": "ai-i18n-tools translate-json",
133
- "i18n:translate": "ai-i18n-tools translate-docs",
134
- "i18n:dashboard": "ai-i18n-tools dashboard"
135
- }
136
- ```
137
-
138
- Then run e.g. `pnpm run i18n:sync` — scripts resolve the local binary without extra shell setup.
139
-
140
- **Alternatives** — if you prefer not to adjust `PATH`: `npx ai-i18n-tools …` (npm) or `pnpm exec ai-i18n-tools …` (pnpm). For a zero-install one-off with no `package.json` entry: `npx ai-i18n-tools <cmd>` or `pnpm dlx ai-i18n-tools <cmd>`.
141
-
142
- Prefer `sync` over hand-chaining `extract`, `translate-ui`, `translate-svg`, `translate-docs`, and `translate-json` — order and feature flags are easy to get wrong when run manually. See [Recommended `package.json` scripts](docs/guide/quick-start.md#recommended-packagejson-scripts) in the Quick start guide.
143
-
144
- Set the API key for your chosen provider (environment variable names are in [LLM providers](#llm-providers)):
145
-
146
- ```bash
147
- export PROVIDER_API_KEY=sk-your-key-here
148
- ```
149
-
150
- ---
151
-
152
- <a id="llm-providers"></a>
153
- ## LLM providers
154
-
155
- Translation commands (`translate-ui`, `translate-docs`, `translate-json`, `sync`, `check-models`, and related scripts) call an LLM provider; `check-markdown`, `mark-html`, and `extract` do not.
156
-
157
- Configure providers under a top-level `providers` map and pick the active one with a top-level `provider` selector (optional when exactly one provider is configured). Most providers need only a `translationModels` list — `baseUrl` and the API-key environment variable come from a built-in preset; you can override `baseUrl`, `apiKeyEnv`, `headers`, `maxTokens`, `temperature`, and `requestTimeoutMs` per provider. `requestTimeoutMs` is the maximum time in milliseconds to wait for each request (default `30000`).
158
-
159
- Optional model tiers on each provider block:
160
-
161
- - `translationModels` — global ordered fallback chain (required for translation features).
162
- - `uiModels` — UI-only chain (`translate-ui`, plural generation, `proofread-ui`): tried after any matching `localeModels` entry, before `translationModels`.
163
- - `localeModels` — per-locale overrides for **all** pipelines: each entry maps a BCP-47 locale to an ordered model list tried first for that locale only (`pt-br` matches `pt-BR`).
164
-
165
- Resolution order: **UI** → `localeModels(locale)` → `uiModels` → `translationModels`; **docs / JSON / SVG** → `localeModels(locale)` → `translationModels`. Duplicate model ids are skipped while preserving order.
166
-
167
- To switch providers for a single run without editing the config, pass the global `-P` / `--provider <name>` option (e.g. `ai-i18n-tools -P groq translate-ui`); the name must be one of the configured `providers` keys.
168
-
169
- ```jsonc
170
- {
171
- "provider": "ollama",
172
- "providers": {
173
- "groq": { "translationModels": ["llama-3.3-70b-versatile"] },
174
- "openrouter": {
175
- "translationModels": ["qwen/qwen3-235b-a22b-2507", "openai/gpt-4o-mini"],
176
- "uiModels": ["anthropic/claude-sonnet-latest"],
177
- "localeModels": [
178
- { "locale": "pt-BR", "models": ["google/gemini-3-flash-preview"] }
179
- ]
180
- },
181
- "ollama": { "baseUrl": "http://localhost:11434/v1", "translationModels": ["llama3.2"] }
182
- }
183
- }
48
+ export OPENROUTER_API_KEY=sk-or-v1-your-key-here
184
49
  ```
185
50
 
186
- Built-in provider presets (key base URLAPI-key env var):
51
+ Configure the bare `ai-i18n-tools` command (direnv, PATH, `package.json` scripts, or `npx`) see [Installation](docs/guide/installation.md).
187
52
 
188
- | Provider | Base URL | API-key env var |
189
- |--------------|-----------------------------------------------------------|----------------------|
190
- | `alibaba` | `https://dashscope-intl.aliyuncs.com/compatible-mode/v1` | `ALIBABA_API_KEY` |
191
- | `anthropic` | `https://api.anthropic.com/v1` | `ANTHROPIC_API_KEY` |
192
- | `apifun` | `https://api.apikey.fun/v1` | `APIFUN_API_KEY` |
193
- | `cerebras` | `https://api.cerebras.ai/v1` | `CEREBRAS_API_KEY` |
194
- | `deepseek` | `https://api.deepseek.com` | `DEEPSEEK_API_KEY` |
195
- | `gemini` | `https://generativelanguage.googleapis.com/v1beta/openai` | `GOOGLE_API_KEY` |
196
- | `groq` | `https://api.groq.com/openai/v1` | `GROQ_API_KEY` |
197
- | `mistral` | `https://api.mistral.ai/v1` | `MISTRAL_API_KEY` |
198
- | `nvidia` | `https://integrate.api.nvidia.com/v1` | `NVIDIA_API_KEY` |
199
- | `ollama` | `http://localhost:11434/v1` | (none) |
200
- | `openai` | `https://api.openai.com/v1` | `OPENAI_API_KEY` |
201
- | `openrouter` | `https://openrouter.ai/api/v1` | `OPENROUTER_API_KEY` |
202
- | `xai` | `https://api.x.ai/v1` | `XAI_API_KEY` |
203
-
204
- Define a custom OpenAI-compatible provider by adding a new key with `baseUrl` (and `apiKeyEnv` unless it needs no key). Model ids are plain upstream ids — the provider is chosen at the config level, so no `provider/` prefix is needed (OpenRouter ids keep their native `vendor/model` form).
205
-
206
- Token usage is reported for every provider; exact USD cost is shown only when the provider returns it. `ai-i18n-tools check-models` validates all configured model ids (`translationModels`, `uiModels`, and every `localeModels` entry) against the active provider's live `GET /models` list, and shows pricing when the provider returns it. `ai-i18n-tools list-models` lists every model the active provider advertises (use `-P` / `--provider` to inspect another configured provider). `ai-i18n-tools bench-models` benchmarks every unique configured model id (`translationModels`, `uiModels`, and `localeModels`) by translating a sample in isolation (models run in parallel, bounded by `concurrency`) and prints per-model input/output tokens, wall-clock time, and USD cost.
207
-
208
- For a hands-on demo of switching providers with `-P` on a single document, see [`examples/multi-provider`](https://github.com/wsj-br/ai-i18n-tools/tree/main/examples/multi-provider/).
209
-
210
- ---
211
-
212
- <a id="quick-start"></a>
213
53
  ## Quick start
214
54
 
215
- Configure your shell for the bare command first — see [Using the CLI](#using-the-cli).
216
-
217
- <a id="ui-strings"></a>
218
- ### UI strings
219
-
220
- ```bash
221
- # 1. Create config (default ui-markdown; plain Astro: init -t ui-astro-website)
222
- ai-i18n-tools init [-P <provider>]
223
-
224
- # 2. Extract UI strings to strings.json
225
- ai-i18n-tools extract
226
-
227
- # 3. Translate to all target locales
228
- ai-i18n-tools translate-ui
229
- ```
230
-
231
- Then wire i18next in your app using the helpers from `'ai-i18n-tools/runtime'`. See [Step 4: Wire i18next at runtime](docs/guide/ui-strings/i18next-runtime.md) in the UI strings guide for the full setup.
232
-
233
- <a id="documents"></a>
234
- ### Documents
235
-
236
- The default `init` template (`ui-markdown`) enables UI extraction only. Use a docs-oriented template (or enable `features.translateDocs` and add `docs[]`) before `translate-docs`:
237
-
238
- ```bash
239
- # Docusaurus docs + optional write-translations catalog
240
- ai-i18n-tools init -t ui-docusaurus [-P <provider>]
241
-
242
- # Astro Starlight documentation
243
- # ai-i18n-tools init -t ui-starlight [-P <provider>]
244
-
245
- # VitePress documentation (pages + theme catalog)
246
- # ai-i18n-tools init -t ui-vitepress [-P <provider>]
247
-
248
- # Nextra documentation (pages + _meta.ts + theme dictionary)
249
- # ai-i18n-tools init -t ui-nextra [-P <provider>]
250
-
251
- # Fumadocs documentation (pages + meta.json + UI catalog)
252
- # ai-i18n-tools init -t ui-fumadocs [-P <provider>]
253
-
254
- # Plain Astro website — UI extraction for t() in .astro; add docs[] for page HTML (see Astro below)
255
- # ai-i18n-tools init -t ui-astro-website [-P <provider>]
256
-
257
- ai-i18n-tools translate-docs
258
- ai-i18n-tools status
259
- # ai-i18n-tools translate-docs --locale de # single locale
260
- ```
261
-
262
- Edit `ai-i18n-tools.config.json`: set `docs[].contentPaths` to markdown, MDX, and/or `.astro` sources; `docs[].outputDir` and `docs[].docsOutput.style` (`"docusaurus"`, `"astro-starlight"`, `"vitepress"`, `"nextra"`, `"fumadocs"`, `"flat"`, etc.). Full field reference: [Documents](docs/guide/documents/).
263
-
264
- <a id="vitepress"></a>
265
- ### VitePress
266
-
267
- `init -t ui-vitepress` scaffolds `docsOutput.style: "vitepress"` plus `docsOutput.vitepressThemeCatalog` for nav/sidebar/footer strings. Run `sync` to translate page markdown and the theme catalog together — no separate JSON pipeline. See [VitePress integration](docs/guide/integrations/vitepress.md) and [examples/vitepress-docs](https://github.com/wsj-br/ai-i18n-tools/tree/main/examples/vitepress-docs/).
268
-
269
- <a id="nextra"></a>
270
- ### Nextra
271
-
272
- `init -t ui-nextra` scaffolds `docsOutput.style: "nextra"`. `translate-docs` automatically collects and translates `_meta.ts` sidebar labels; set `docs[].nextraDictionaryPath` to also translate the theme dictionary module (e.g. `app/_dictionaries/en.ts`) — all in the same `sync` run, no JSON sidecars. See [Nextra integration](docs/guide/integrations/nextra.md) and [examples/nextra-docs](https://github.com/wsj-br/ai-i18n-tools/tree/main/examples/nextra-docs/).
273
-
274
- <a id="fumadocs"></a>
275
- ### Fumadocs
276
-
277
- `init -t ui-fumadocs` scaffolds `docsOutput.style: "fumadocs"` with the dot parser (default) or dir parser for Nextra-style locale folders. `translate-docs` automatically collects and translates `meta.json` sidebar labels; set `docsOutput.fumadocsUiCatalog` to also translate UI overrides in `lib/layout.shared.ts` — all in the same `sync` run, no JSON sidecars. See [Fumadocs integration](docs/guide/integrations/fumadocs.md) and [examples/fumadocs-docs](https://github.com/wsj-br/ai-i18n-tools/tree/main/examples/fumadocs-docs/).
278
-
279
- <a id="astro-plain-astro--starlight"></a>
280
- ### Astro (plain Astro & Starlight)
281
-
282
- **Astro Starlight** — `init -t ui-starlight`, then `translate-docs`. Starlight UI overrides can use `src/content/i18n/en.json` with `jsonPathTemplate` in a separate `docs[]` block when needed ([Documents — initialise for documentation](docs/guide/documents/index.md#step-1-initialise-for-documentation)).
283
-
284
- **Plain Astro** (marketing or app sites, not Starlight) — combine [Astro built-in i18n routing](https://docs.astro.build/en/guides/internationalization/) with ai-i18n-tools. Reference project: [`examples/astro-website`](https://github.com/wsj-br/ai-i18n-tools/tree/main/examples/astro-website/) (English at `/`, locales at `/{locale}/`).
285
-
286
- Most teams use a **hybrid** of two pipelines:
287
-
288
- | Pipeline | Use for | Commands | Output |
289
- |------------------------|----------------------------------------------------------------------|----------------------------|--------------------------------------------------------|
290
- | **Page HTML** | Headings, paragraphs, nav labels, inline arrays in the template body | `translate-docs` | `src/pages/{locale}/index.astro` per locale |
291
- | **UI strings (`t()`)** | Frontmatter data, tab labels, shared arrays | `extract` → `translate-ui` | `public/locales/{locale}.json` (English source as key) |
292
-
293
- Scaffold UI with `init -t ui-astro-website`. For hardcoded HTML in `.astro` pages, enable `features.translateDocs` and add a `docs[]` block with `docsOutput.style: "astro-starlight"` (see [Astro website pages (parse-and-replace)](docs/guide/ui-strings/astro-website.md#astro-website-pages-parse-and-replace)). Keep `targetLocales`, `i18n.locales` in `astro.config.mjs`, and `ui-languages.json` aligned (Astro routes use lowercase codes such as `pt-br`; flat bundle filenames follow config casing, e.g. `pt-BR.json`).
294
-
295
- Wire `t()` at build time without i18next unless you add client islands — see [Astro website UI strings (SSG)](docs/guide/ui-strings/astro-website.md#astro-website-ui-strings-ssg) and the example’s `src/i18n/t.ts`.
296
-
297
- <a id="combined-sync"></a>
298
- ### Combined sync
299
-
300
55
  ```bash
301
- ai-i18n-tools sync # extract → translate-ui translate-svg translate-docs translate-json (per features)
56
+ ai-i18n-tools init [-P <provider>] # scaffold config (default: UI strings)
57
+ ai-i18n-tools sync # extract + translate per features
302
58
  ```
303
59
 
304
- ---
305
-
306
- <a id="runtime-helpers"></a>
307
- ## Runtime helpers
308
-
309
- The following helpers are exported from `'ai-i18n-tools/runtime'` and work in any JavaScript environment. You do not need to import i18next to use them:
60
+ Docs-oriented scaffolds: `-t ui-docusaurus`, `ui-starlight`, `ui-vitepress`, `ui-nextra`, `ui-fumadocs`, `ui-astro-website`, or `ui-json-bundles`.
310
61
 
311
- | Helper | Description |
312
- |------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------|
313
- | `defaultI18nInitOptions(sourceLocale)` | Standard i18next init options for key-as-default setups. |
314
- | `setupKeyAsDefaultT(i18n, { stringsJson, sourcePluralFlatBundle? })` | Recommended wiring: key-trim + plural `wrapT` from `strings.json`, optionally merges `translate-ui` `{sourceLocale}.json` plural keys. |
315
- | `wrapT(i18n, options)` | Lower-level plural-aware `t()` wrapper (usually installed by `setupKeyAsDefaultT`). |
316
- | `buildPluralIndexFromStringsJson(entries)` | Builds the plural group index `wrapT` uses from catalog rows with `"plural": true`. |
317
- | `extractInterpolationNamesForWrap(key)` | Parses `{{var}}` names from a source key for `wrapT` / key-trim fallback. |
318
- | `wrapI18nWithKeyTrim(i18n)` | Lower-level key-trim wrapper only (deprecated for app wiring; prefer `setupKeyAsDefaultT`). |
319
- | `makeLocaleLoadersFromManifest(uiLanguages, sourceLocale, makeLoader)` | Builds the `localeLoaders` map for `makeLoadLocale` from `ui-languages.json` (every `code` except `sourceLocale`). |
320
- | `makeLoadLocale(i18n, loaders, sourceLocale)` | Factory for async locale file loading. |
321
- | `getTextDirection(lng)` | Returns `'ltr'` or `'rtl'` for a BCP-47 code. |
322
- | `applyDirection(lng, element?)` | Sets `dir` attribute on `document.documentElement`. |
323
- | `getUILanguageLabel(lang, t)` | Display label for a language menu row (with i18n). |
324
- | `getUILanguageLabelNative(lang)` | Display label without calling `t()` (header-style). |
325
- | `interpolateTemplate(str, vars)` | Low-level `{{var}}` substitution on a plain string (used internally; app code should use `t()` instead). |
326
- | `flipUiArrowsForRtl(text, isRtl)` | Flip `→` to `←` for RTL layouts. |
62
+ Prefer `sync` over chaining individual translate commands. Full walkthrough: [Quick start](docs/guide/quick-start.md).
327
63
 
328
- ---
329
-
330
- <a id="cli-commands"></a>
331
- ## CLI commands
332
-
333
- ```bash
334
- ai-i18n-tools version
335
- ai-i18n-tools check-models
336
- ai-i18n-tools list-models
337
- ai-i18n-tools bench-models [--model <ids>] [--text <text>|--file <path>] [--source <locale>] [--target <locale>]
338
- ai-i18n-tools list-languages [search]
339
- ai-i18n-tools init [-t ui-markdown|ui-docusaurus|ui-starlight|ui-vitepress|ui-nextra|ui-fumadocs|ui-astro-website|ui-json-bundles] [-o path] [-P <provider>] [--with-translate-ignore]
340
- ai-i18n-tools write-heading-ids …
341
- ai-i18n-tools mark-html [paths...] [--write]
342
- ai-i18n-tools extract
343
- ai-i18n-tools translate-docs …
344
- ai-i18n-tools translate-json …
345
- ai-i18n-tools translate-svg …
346
- ai-i18n-tools translate-ui …
347
- ai-i18n-tools sync-ui …
348
- ai-i18n-tools proofread-ui …
349
- ai-i18n-tools check-markdown [-p|--path <path>] [-f|--file <path>] [--json] [--no-cache]
350
- ai-i18n-tools export-ui-xliff …
351
- ai-i18n-tools sync …
352
- ai-i18n-tools status …
353
- ai-i18n-tools statistics …
354
- ai-i18n-tools cleanup …
355
- ai-i18n-tools clean-temp …
356
- ai-i18n-tools purge-locale -l <code> [-l <code> …] [--dry-run] [-y|--yes] [-f|--force] [--keep-files] [--backup <path>]
357
- ai-i18n-tools dashboard …
358
- ai-i18n-tools generate-ui-languages [--master path] [--dry-run]
359
- ai-i18n-tools glossary-generate
360
- ai-i18n-tools help [command]
361
- ```
362
-
363
-
364
- For plain HTML apps, annotate elements with bare `data-i18n` / `data-i18n-title` / `data-i18n-placeholder` markers (the source text is taken from the element's own textContent / title / placeholder, written once); `mark-html` inserts them for you and `extract` then captures them into `strings.json`. See [Marking HTML for translation](docs/guide/ui-strings/plain-html.md#marking-html-for-translation).
365
-
366
- Complete per-command flag lists are in [CLI reference](docs/reference/cli-commands/). Run `ai-i18n-tools <command> --help` for built-in usage text.
367
-
368
- Global options: `-c <config>` (default: `ai-i18n-tools.config.json`), `-v` (verbose), `-P` / `--provider <name>` (override the active LLM provider; must be configured under `providers`), `-L` / `--ui-lang <code>` (language for the tool's own UI/logs), `-V` / `--version`, and `-h` / `--help` — accepted on every command. `-w` / `--write-logs [path]` tees console output to a log file (default: under the translation cache directory), but only takes effect on the translation and sync commands (`translate-docs`, `translate-json`, `translate-svg`, `translate-ui`, `sync-ui`, `sync`, `cleanup`). Several commands accept `-l` / `--locale <codes>` (comma-separated BCP-47) to limit target locales; `proofread-ui` uses a single source locale. See [CLI reference](docs/reference/cli-commands/) for the command overview.
369
-
370
- <a id="tool-ui-language-logs-help-dashboard"></a>
371
- ### Tool UI language (logs, help, dashboard)
372
-
373
- The tool localizes its own CLI help, log summaries, and Translation Dashboard independently of the locales you translate. By default it follows your OS locale; override with `-L pt-BR`, `export AI_I18N_LANG=es`, or `"uiLanguage"` in config. See [Tool UI language](docs/guide/tool-ui-language.md) for locale resolution, shipped languages, and dashboard behaviour.
374
-
375
- ---
376
-
377
- <a id="documentation"></a>
378
64
  ## Documentation
379
65
 
380
- - [Documentation site](https://wsj-br.github.io/ai-i18n-tools/) — VitePress guide (9 locales on GitHub Pages); slim entry point with links into the full guide.
381
- - [Quick start](docs/guide/quick-start.md) setup for UI strings, documents, and JSON (UI, docs/`.astro`, JSON bundles, VitePress, Nextra, Fumadocs, Astro Starlight and plain Astro).
382
- - [Locale assets guide](docs/guide/images-and-screenshots/) - screenshots and illustrated SVGs in translated docs (flat link rewriter, screenshot scripts).
383
- - [Architecture](docs/reference/architecture.md) - architecture, internals, programmatic API, and extension points.
384
- - [AI Agent Context](https://github.com/wsj-br/ai-i18n-tools/blob/main/docs/ai-i18n-tools-context.md) - **for apps using the package:** integration prompts for downstream projects (copy into your repo’s agent rules).
385
- - Maintainer guide for **this** repository: `AGENT.md` (rules and workflows; clone-only; not on npm). Pipeline reference: `docs/reference/`. Local dev and publishing: `dev/DEVEL.md`.
66
+ - [Documentation site](https://wsj-br.github.io/ai-i18n-tools/) — guides, integrations, and reference
67
+ - [Installation](docs/guide/installation.md) · [Quick start](docs/guide/quick-start.md) · [Providers and models](docs/guide/providers-and-models.md)
68
+ - [UI strings](docs/guide/ui-strings/) · [Documents](docs/guide/documents/) · [JSON](docs/guide/json.md) · [SVG](docs/guide/svg-translation/)
69
+ - [Integrations](docs/guide/integrations/) VitePress, Nextra, Fumadocs, Docusaurus, Astro
70
+ - [CLI reference](docs/reference/cli-commands/) · [Configuration](docs/reference/configuration.md) · [Runtime helpers](docs/guide/runtime-helpers.md)
71
+ - [Examples](https://github.com/wsj-br/ai-i18n-tools/tree/main/examples/) runnable demos (`npx degit …`)
72
+ - [AI Agent Context](https://github.com/wsj-br/ai-i18n-tools/blob/main/docs/ai-i18n-tools-context.md) — integration guide for assistants in consumer repos
73
+
74
+ ## Contributing
386
75
 
387
- ---
76
+ Issues and pull requests are welcome. Maintainer workflows for this repository: [`AGENTS.md`](https://github.com/wsj-br/ai-i18n-tools/blob/main/AGENTS.md) and [`dev/DEVEL.md`](https://github.com/wsj-br/ai-i18n-tools/blob/main/dev/DEVEL.md).
388
77
 
389
- <a id="license"></a>
390
78
  ## License
391
79
 
392
- This project is licensed under the MIT License.
393
- See the [LICENSE](https://github.com/wsj-br/ai-i18n-tools/blob/main/LICENSE) file for details.
80
+ MIT see [LICENSE](https://github.com/wsj-br/ai-i18n-tools/blob/main/LICENSE).
394
81
 
395
- Copyright &copy; 2026 Waldemar Scudeller Jr.
82
+ Copyright © 2026 Waldemar Scudeller Jr.
@@ -87,14 +87,15 @@ export declare class LlmClient {
87
87
  */
88
88
  private languageLabelForPrompt;
89
89
  /**
90
- * Enforce the target locale's ISO 15924 script subtag on a model response, throwing
90
+ * Enforce the target locale's expected script on a model response, throwing
91
91
  * {@link ScriptValidationError} so the model-fallback loop retries with the next model.
92
92
  *
93
93
  * Uses a statistical dominant-script check ({@link scriptValidationIssue}): Latin text
94
94
  * (code, URLs, brand names, placeholders) and letter-like symbols such as `ℹ` are ignored,
95
95
  * a stray foreign-language quote does not fail the output, and `zh-Hans`/`zh-Hant` are told
96
- * apart via variant-distinct characters. Locales without a script subtag, and composite
97
- * scripts (e.g. `Jpan`, `Kore`), are not enforced.
96
+ * apart via variant-distinct characters. Uses {@link effectiveScriptSubtag} so bare `hi`
97
+ * (Devanagari by default) is enforced like an explicit `*-Deva` tag. Locales with no
98
+ * effective script, and composite scripts (e.g. `Jpan`, `Kore`), are not enforced.
98
99
  */
99
100
  private assertExpectedScript;
100
101
  private appendDebugLog;
@@ -1 +1 @@
1
- {"version":3,"file":"llm-client.d.ts","sourceRoot":"","sources":["../../src/api/llm-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"llm-client.d.ts","sourceRoot":"","sources":["../../src/api/llm-client.ts"],"names":[],"mappings":"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"}
@@ -4,7 +4,7 @@ import { generateText } from "ai";
4
4
  import { createOpenAICompatible, } from "@ai-sdk/openai-compatible";
5
5
  import { BatchTranslationError, } from "../core/types.js";
6
6
  import { englishLanguageNameForLocale, normalizeLocale, resolveTranslationModels, } from "../core/config.js";
7
- import { scriptSubtag, scriptValidationIssue } from "../core/locale-utils.js";
7
+ import { effectiveScriptSubtag, scriptValidationIssue } from "../core/locale-utils.js";
8
8
  import { OPENROUTER_PROVIDER_KEY, resolveActiveProvider, resolveApiKey, resolveProviderSettings, } from "../core/llm-providers.js";
9
9
  import { buildDocumentBatchPrompt, buildDocumentSinglePrompt, buildProofreadUIPromptMessages, buildUIPromptMessages, parseBatchJsonArrayResponse, parseBatchJsonObjectResponse, parseBatchTranslationResponse, parseProofreadUIBatchResponse, parsePluralFormsJsonResponse, parseUIJsonArrayResponse, ScriptValidationError, } from "../core/prompt-builder.js";
10
10
  /** OpenRouter: prefer throughput; allow backup providers (top-level `provider` routing field). */
@@ -144,17 +144,18 @@ export class LlmClient {
144
144
  return localeCode;
145
145
  }
146
146
  /**
147
- * Enforce the target locale's ISO 15924 script subtag on a model response, throwing
147
+ * Enforce the target locale's expected script on a model response, throwing
148
148
  * {@link ScriptValidationError} so the model-fallback loop retries with the next model.
149
149
  *
150
150
  * Uses a statistical dominant-script check ({@link scriptValidationIssue}): Latin text
151
151
  * (code, URLs, brand names, placeholders) and letter-like symbols such as `ℹ` are ignored,
152
152
  * a stray foreign-language quote does not fail the output, and `zh-Hans`/`zh-Hant` are told
153
- * apart via variant-distinct characters. Locales without a script subtag, and composite
154
- * scripts (e.g. `Jpan`, `Kore`), are not enforced.
153
+ * apart via variant-distinct characters. Uses {@link effectiveScriptSubtag} so bare `hi`
154
+ * (Devanagari by default) is enforced like an explicit `*-Deva` tag. Locales with no
155
+ * effective script, and composite scripts (e.g. `Jpan`, `Kore`), are not enforced.
155
156
  */
156
157
  assertExpectedScript(text, targetLocale) {
157
- const script = scriptSubtag(targetLocale);
158
+ const script = effectiveScriptSubtag(targetLocale);
158
159
  if (!script) {
159
160
  return;
160
161
  }