rancc 1.0.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 +455 -0
- package/dist/index.js +102328 -0
- package/package.json +63 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
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,455 @@
|
|
|
1
|
+
# Edge — AI-Powered i18n Automation CLI for React
|
|
2
|
+
|
|
3
|
+
> Built specifically for React projects. Edge takes the grunt work out of internationalization — from extracting strings to rewriting your components — so you can ship multilingual apps without the manual overhead.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## The Problem
|
|
8
|
+
|
|
9
|
+
If you've ever added i18n to a real React app, you know the pain:
|
|
10
|
+
|
|
11
|
+
- You have hundreds of components with hardcoded text like `<h1>Welcome Back</h1>` and `placeholder="Search..."`
|
|
12
|
+
- You have to hunt down every single string manually across every file
|
|
13
|
+
- Create a locale JSON file with consistent, meaningful keys
|
|
14
|
+
- Go back and replace every string with `t("welcome_back")` by hand
|
|
15
|
+
- Add `const { t } = useTranslation()` to every component that has text
|
|
16
|
+
- Add the import at the top of every file
|
|
17
|
+
- Then do all of that again for every language you support
|
|
18
|
+
- Then keep all of it in sync every time your UI text changes
|
|
19
|
+
|
|
20
|
+
For a mid-sized React app (50+ components) this process takes **days** and is full of human error — missed strings, inconsistent keys, untranslated languages, stale keys that pile up.
|
|
21
|
+
|
|
22
|
+
**Edge solves all of it from the terminal.**
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Stack
|
|
27
|
+
|
|
28
|
+
- **Runtime:** Bun
|
|
29
|
+
- **Language:** TypeScript
|
|
30
|
+
- **CLI:** Commander.js
|
|
31
|
+
- **AST:** `@babel/parser`, `@babel/traverse`, `@babel/types`, `@babel/generator`
|
|
32
|
+
- **Formatting:** Prettier
|
|
33
|
+
- **AI Translation:** Vercel AI SDK (`ai`)
|
|
34
|
+
- **Supported Providers:** OpenAI, Groq, Google Gemini, Claude, OpenRouter
|
|
35
|
+
- **i18n Library:** react-i18next (V2 transform only)
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
bun install
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Configuration
|
|
48
|
+
|
|
49
|
+
Running `Edge init` creates `auto-i18n-config.json` in the current directory:
|
|
50
|
+
|
|
51
|
+
```json
|
|
52
|
+
{
|
|
53
|
+
"sourceLang": "en",
|
|
54
|
+
"targetLang": ["hi", "fr", "de"],
|
|
55
|
+
"provider": "groq",
|
|
56
|
+
"localeDir": "./locales",
|
|
57
|
+
"ignore": ["**/node_modules/**", "**/.next/**", "**/dist/**", "**/build/**"],
|
|
58
|
+
"i18nLibrary": "react-i18next"
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Set your API key in a `.env` file in the project root where you run Edge:
|
|
63
|
+
|
|
64
|
+
```env
|
|
65
|
+
GROQ_API_KEY=your_key_here
|
|
66
|
+
# or
|
|
67
|
+
OPENAI_API_KEY=your_key_here
|
|
68
|
+
# or
|
|
69
|
+
GOOGLE_API_KEY=your_key_here
|
|
70
|
+
# or
|
|
71
|
+
ANTHROPIC_API_KEY=your_key_here
|
|
72
|
+
# or
|
|
73
|
+
OPENROUTER_API_KEY=your_key_here
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
> Bun automatically loads `.env` from the current working directory — no extra setup needed.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Commands
|
|
81
|
+
|
|
82
|
+
### `Edge init`
|
|
83
|
+
|
|
84
|
+
Interactive setup wizard. Prompts for:
|
|
85
|
+
- Source language
|
|
86
|
+
- Target languages
|
|
87
|
+
- Locale directory
|
|
88
|
+
- AI provider
|
|
89
|
+
- i18n library
|
|
90
|
+
|
|
91
|
+
Writes `auto-i18n-config.json`.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
### `Edge scan`
|
|
96
|
+
|
|
97
|
+
Scans all `.js`, `.jsx`, `.ts`, `.tsx` files in your project using Babel AST. Extracts:
|
|
98
|
+
- All JSX text content (`<h1>Hello</h1>`)
|
|
99
|
+
- Translatable attributes (`placeholder`, `alt`, `title`, `aria-label`, `aria-description`)
|
|
100
|
+
|
|
101
|
+
Writes extracted strings to `locales/en.json` (or your configured source locale).
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
┌─────────────────────────────────┐
|
|
105
|
+
│ 🔍 Starting i18n Scan │
|
|
106
|
+
└─────────────────────────────────┘
|
|
107
|
+
|
|
108
|
+
→ Loading config...
|
|
109
|
+
✓ Config loaded (source: en)
|
|
110
|
+
→ Scanning project files...
|
|
111
|
+
|
|
112
|
+
Scanning: src/App.tsx
|
|
113
|
+
Scanning: src/components/Navbar.tsx
|
|
114
|
+
|
|
115
|
+
✓ Extracted 42 strings
|
|
116
|
+
→ Locale dir ready: ./locales
|
|
117
|
+
✓ Saved to locales/en.json
|
|
118
|
+
|
|
119
|
+
✨ Scan complete!
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
### `Edge translate`
|
|
125
|
+
|
|
126
|
+
Translates `en.json` into all configured target languages using your AI provider.
|
|
127
|
+
|
|
128
|
+
**Incremental** — only translates keys that are missing from an existing target locale file. Already-translated keys are preserved.
|
|
129
|
+
|
|
130
|
+
- Sends strings in batches of 100 keys per request
|
|
131
|
+
- Retries each batch up to 3 times with backoff on failure
|
|
132
|
+
- Falls back to source value if a key fails after all retries
|
|
133
|
+
- Validates every key in the model response before merging
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
▶ Translating → hi (+5 new keys) — 1 chunk
|
|
137
|
+
[████████████████████] 100% (1/1 chunks)
|
|
138
|
+
✓ Saved locales/hi.json (38 existing + 5 new)
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
### `Edge check`
|
|
144
|
+
|
|
145
|
+
Shows every untranslated key per target language, with the source value alongside each missing key.
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
✓ Hindi (hi) — fully translated
|
|
149
|
+
⚠ French (fr) — 3 untranslated key(s):
|
|
150
|
+
• "contact_support" → "Contact Support"
|
|
151
|
+
• "order_status" → "Order Status"
|
|
152
|
+
• "delete_account" → "Delete Account"
|
|
153
|
+
|
|
154
|
+
⚠ 3 total untranslated key(s). Run `translate` to fix.
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
### `Edge clean`
|
|
160
|
+
|
|
161
|
+
Removes keys from target locale files that no longer exist in the source (`en.json`). Useful after you rename or remove strings.
|
|
162
|
+
|
|
163
|
+
```
|
|
164
|
+
✓ Hindi (hi) — nothing to clean
|
|
165
|
+
✓ French (fr) — removed 2 stale key(s): "old_key", "unused_label"
|
|
166
|
+
|
|
167
|
+
✓ Removed 2 stale key(s) total.
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
### `Edge stats`
|
|
173
|
+
|
|
174
|
+
Overview of your translation coverage.
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
┌──────────────────────────────────────┐
|
|
178
|
+
│ 📊 i18n Statistics │
|
|
179
|
+
└──────────────────────────────────────┘
|
|
180
|
+
|
|
181
|
+
Project
|
|
182
|
+
────────────────────────────────────────
|
|
183
|
+
Files Scanned : 34
|
|
184
|
+
Strings Extracted : 381
|
|
185
|
+
Source Language : en
|
|
186
|
+
|
|
187
|
+
Locales
|
|
188
|
+
────────────────────────────────────────
|
|
189
|
+
en.json : 381
|
|
190
|
+
hi.json : 381
|
|
191
|
+
fr.json : 378
|
|
192
|
+
|
|
193
|
+
Missing Keys
|
|
194
|
+
────────────────────────────────────────
|
|
195
|
+
fr:
|
|
196
|
+
3 key(s) missing — run `check` for details
|
|
197
|
+
|
|
198
|
+
Coverage
|
|
199
|
+
────────────────────────────────────────
|
|
200
|
+
en : 381 / 381 (100%)
|
|
201
|
+
hi : 381 / 381 (100%)
|
|
202
|
+
fr : 378 / 381 (99%)
|
|
203
|
+
|
|
204
|
+
✓ Done
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
#### `Edge stats --verbose`
|
|
208
|
+
|
|
209
|
+
Adds file type breakdown, duplicate string count, full list of missing keys, and last scan timestamp.
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
### `Edge modify-langs`
|
|
214
|
+
|
|
215
|
+
Interactive multi-select to add or remove target languages from your config. Automatically deletes locale files for removed languages.
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
### `Edge setup` *(V2)*
|
|
220
|
+
|
|
221
|
+
Generates the `react-i18next` runtime configuration for your React project.
|
|
222
|
+
|
|
223
|
+
1. Detects your React entry file (`src/main.tsx`, `src/main.jsx`, `src/index.tsx`, `src/index.jsx`)
|
|
224
|
+
2. Generates `src/i18n.ts` with all configured languages pre-wired
|
|
225
|
+
3. Injects `import "./i18n"` into your entry file (safe — never duplicates)
|
|
226
|
+
|
|
227
|
+
```ts
|
|
228
|
+
// generated src/i18n.ts
|
|
229
|
+
import i18n from "i18next";
|
|
230
|
+
import { initReactI18next } from "react-i18next";
|
|
231
|
+
|
|
232
|
+
import en from "../locales/en.json";
|
|
233
|
+
import hi from "../locales/hi.json";
|
|
234
|
+
import fr from "../locales/fr.json";
|
|
235
|
+
|
|
236
|
+
i18n.use(initReactI18next).init({
|
|
237
|
+
resources: {
|
|
238
|
+
en: { translation: en },
|
|
239
|
+
hi: { translation: hi },
|
|
240
|
+
fr: { translation: fr },
|
|
241
|
+
},
|
|
242
|
+
lng: localStorage.getItem("lang") ?? "en",
|
|
243
|
+
fallbackLng: "en",
|
|
244
|
+
interpolation: { escapeValue: false },
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
export default i18n;
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
After setup, it prints install instructions for all package managers:
|
|
251
|
+
|
|
252
|
+
```
|
|
253
|
+
Install required packages in your React project:
|
|
254
|
+
|
|
255
|
+
npm npm install i18next react-i18next
|
|
256
|
+
yarn yarn add i18next react-i18next
|
|
257
|
+
pnpm pnpm add i18next react-i18next
|
|
258
|
+
bun bun add i18next react-i18next
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
### `Edge transform` *(V2)*
|
|
264
|
+
|
|
265
|
+
**The core V2 feature.** Rewrites your React source files to replace hardcoded strings with `t()` calls. Fully AST-based — no regex, no string replacement.
|
|
266
|
+
|
|
267
|
+
#### What it transforms
|
|
268
|
+
|
|
269
|
+
**JSX text:**
|
|
270
|
+
```tsx
|
|
271
|
+
// before
|
|
272
|
+
<h1>Hello</h1>
|
|
273
|
+
<button>Buy Now</button>
|
|
274
|
+
|
|
275
|
+
// after
|
|
276
|
+
<h1>{t("Hello")}</h1>
|
|
277
|
+
<button>{t("Buy Now")}</button>
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
**Translatable attributes** (`placeholder`, `alt`, `title`, `aria-label`, `aria-description`):
|
|
281
|
+
```tsx
|
|
282
|
+
// before
|
|
283
|
+
<input placeholder="Search Products" />
|
|
284
|
+
|
|
285
|
+
// after
|
|
286
|
+
<input placeholder={t("Search Products")} />
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
**Hook injection** (if not already present):
|
|
290
|
+
```tsx
|
|
291
|
+
// before
|
|
292
|
+
function App() {
|
|
293
|
+
return <h1>Hello</h1>;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// after
|
|
297
|
+
function App() {
|
|
298
|
+
const { t } = useTranslation();
|
|
299
|
+
return <h1>{t("Hello")}</h1>;
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
**Import injection** (if not already present):
|
|
304
|
+
```tsx
|
|
305
|
+
import { useTranslation } from "react-i18next";
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
#### What it skips
|
|
309
|
+
|
|
310
|
+
- `{user.name}` — already an expression
|
|
311
|
+
- `{t("hello")}` — already translated
|
|
312
|
+
- `` {`${count} items`} `` — template literals
|
|
313
|
+
- Strings not found in `en.json` — only transforms known keys
|
|
314
|
+
- Ignored attributes: `id`, `key`, `className`, `type`, `name`, `src`, `href`, `value`, etc.
|
|
315
|
+
|
|
316
|
+
#### Supported component patterns
|
|
317
|
+
|
|
318
|
+
```tsx
|
|
319
|
+
function App() { ... } // named function declaration
|
|
320
|
+
const App = () => { ... } // arrow function with block body
|
|
321
|
+
const App = function() { ... } // function expression
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
#### Options
|
|
325
|
+
|
|
326
|
+
```bash
|
|
327
|
+
Edge transform # transform and write files
|
|
328
|
+
Edge transform --dry-run # preview diff, write nothing
|
|
329
|
+
Edge transform --backup # save originals to .edge-backups/ first
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
#### `--dry-run` output
|
|
333
|
+
|
|
334
|
+
```diff
|
|
335
|
+
~ src/App.tsx (3 strings)
|
|
336
|
+
@@ -4,7 +4,9 @@
|
|
337
|
+
function App() {
|
|
338
|
+
+ const { t } = useTranslation();
|
|
339
|
+
return (
|
|
340
|
+
- <h1>Hello</h1>
|
|
341
|
+
+ <h1>{t("Hello")}</h1>
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
#### `--backup`
|
|
347
|
+
|
|
348
|
+
Saves original files to `.edge-backups/` preserving folder structure before overwriting.
|
|
349
|
+
|
|
350
|
+
```
|
|
351
|
+
.edge-backups/
|
|
352
|
+
src/
|
|
353
|
+
App.tsx
|
|
354
|
+
components/
|
|
355
|
+
Navbar.tsx
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
---
|
|
359
|
+
|
|
360
|
+
## Complete Workflow
|
|
361
|
+
|
|
362
|
+
```bash
|
|
363
|
+
# 1. Set up config (one time)
|
|
364
|
+
Edge init
|
|
365
|
+
|
|
366
|
+
# 2. Extract all hardcoded strings from your codebase
|
|
367
|
+
Edge scan
|
|
368
|
+
|
|
369
|
+
# 3. Translate into all target languages
|
|
370
|
+
Edge translate
|
|
371
|
+
|
|
372
|
+
# 4. Check for any gaps
|
|
373
|
+
Edge check
|
|
374
|
+
|
|
375
|
+
# 5. Wire up react-i18next runtime (one time)
|
|
376
|
+
Edge setup
|
|
377
|
+
|
|
378
|
+
# Install packages printed by setup in your React project
|
|
379
|
+
npm install i18next react-i18next
|
|
380
|
+
|
|
381
|
+
# 6. Rewrite source files to use t()
|
|
382
|
+
Edge transform --dry-run # review first
|
|
383
|
+
Edge transform --backup # then apply
|
|
384
|
+
|
|
385
|
+
# 7. As your app grows — re-scan and re-translate incrementally
|
|
386
|
+
Edge scan
|
|
387
|
+
Edge translate # only new strings get sent to AI
|
|
388
|
+
|
|
389
|
+
# 8. Clean up stale keys after renames/deletions
|
|
390
|
+
Edge clean
|
|
391
|
+
|
|
392
|
+
# 9. Monitor coverage anytime
|
|
393
|
+
Edge stats
|
|
394
|
+
Edge stats --verbose
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
---
|
|
398
|
+
|
|
399
|
+
## Project Structure
|
|
400
|
+
|
|
401
|
+
```
|
|
402
|
+
auto-i18n-ai/
|
|
403
|
+
├── index.ts CLI entry — all Commander commands
|
|
404
|
+
├── constants.ts Language list, attribute sets
|
|
405
|
+
├── types.ts TransLationConfig type
|
|
406
|
+
├── auto-i18n-config.json Generated config (gitignore this or commit it)
|
|
407
|
+
├── locales/
|
|
408
|
+
│ ├── en.json Source locale (generated by scan)
|
|
409
|
+
│ ├── hi.json Target locale (generated by translate)
|
|
410
|
+
│ └── fr.json
|
|
411
|
+
├── Text_Extractor/
|
|
412
|
+
│ ├── method.ts Core scan, translate, check, clean, stats logic
|
|
413
|
+
│ └── config-ask.ts Interactive init wizard
|
|
414
|
+
└── src/
|
|
415
|
+
└── transform/
|
|
416
|
+
├── types.ts TransformResult, TransformOptions interfaces
|
|
417
|
+
├── reverseLookup.ts Builds value → key map from en.json
|
|
418
|
+
├── injectImport.ts AST: inject useTranslation import
|
|
419
|
+
├── injectHook.ts AST: inject const { t } = useTranslation()
|
|
420
|
+
├── replaceJSXText.ts AST: replace JSX text nodes with t()
|
|
421
|
+
├── replaceAttributes.ts AST: replace attribute values with t()
|
|
422
|
+
├── transformFile.ts Orchestrates parse → traverse → generate → prettier
|
|
423
|
+
├── transformProject.ts Discovers files, handles I/O, backup, dry-run
|
|
424
|
+
├── backup.ts .edge-backups/ management
|
|
425
|
+
├── dryRun.ts Coloured unified diff output
|
|
426
|
+
└── index.ts runTransform() + runSetup() entry points
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
---
|
|
430
|
+
|
|
431
|
+
## Supported AI Providers
|
|
432
|
+
|
|
433
|
+
| Provider | Config value | Env variable |
|
|
434
|
+
|---|---|---|
|
|
435
|
+
| OpenAI | `openai` | `OPENAI_API_KEY` |
|
|
436
|
+
| Groq | `groq` | `GROQ_API_KEY` |
|
|
437
|
+
| Google Gemini | `google-gemini` | `GOOGLE_API_KEY` |
|
|
438
|
+
| Anthropic Claude | `claude` | `ANTHROPIC_API_KEY` |
|
|
439
|
+
| OpenRouter | `openrouter` | `OPENROUTER_API_KEY` |
|
|
440
|
+
|
|
441
|
+
---
|
|
442
|
+
|
|
443
|
+
## Supported Languages
|
|
444
|
+
|
|
445
|
+
English, Hindi, French, German, Spanish, Italian, Portuguese, Russian, Japanese, Korean, Chinese
|
|
446
|
+
|
|
447
|
+
---
|
|
448
|
+
|
|
449
|
+
## Notes
|
|
450
|
+
|
|
451
|
+
- **Transform only acts on strings that exist in `en.json`** — run `scan` before `transform`
|
|
452
|
+
- **Transform is idempotent** — running it twice won't double-wrap strings
|
|
453
|
+
- **The CLI ignores its own source files** during scan and transform to prevent self-modification
|
|
454
|
+
- **Prettier formats output** using your project's own `.prettierrc` if present
|
|
455
|
+
- **Bun loads `.env` automatically** — no `dotenv` package needed
|