translatronx 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/README.md +1121 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +1599 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +444 -0
- package/dist/index.js +1441 -0
- package/dist/index.js.map +1 -0
- package/package.json +83 -0
package/README.md
ADDED
|
@@ -0,0 +1,1121 @@
|
|
|
1
|
+
# translatronx
|
|
2
|
+
|
|
3
|
+
**Deterministic, incremental, build-time translation compiler using LLMs**
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/translatronx)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
> translatronx is not another translation management system. It is a **translation compiler** — it treats language like code: build once → ship everywhere → zero runtime cost.
|
|
9
|
+
|
|
10
|
+
## 🌟 Features
|
|
11
|
+
|
|
12
|
+
- **🔄 Incremental & Deterministic** - Only translates new/changed strings, same input = same output
|
|
13
|
+
- **💰 Cost-Efficient** - Deduplication and intelligent batching minimize LLM API costs
|
|
14
|
+
- **🔒 Developer Authority** - Manual edits are detected and protected forever (unless forced)
|
|
15
|
+
- **🎯 Provider-Agnostic** - OpenAI, Anthropic, Groq, Azure OpenAI, OpenRouter, or local models
|
|
16
|
+
- **⚡ CI/CD Ready** - Integrates seamlessly into GitHub Actions, GitLab CI, CircleCI, etc.
|
|
17
|
+
- **📊 State-Aware** - SQLite ledger tracks changes without storing actual translations
|
|
18
|
+
- **🛡️ Production-Ready** - Atomic writes, transaction safety, zero data loss on interruption
|
|
19
|
+
- **🎨 Customizable Prompts** - Fine-tune translation quality with formatting, glossaries, and brand voice
|
|
20
|
+
- **📈 Comprehensive Reporting** - Detailed statistics, cost estimates, and audit trails
|
|
21
|
+
|
|
22
|
+
## 📋 Table of Contents
|
|
23
|
+
|
|
24
|
+
- [Installation](#-installation)
|
|
25
|
+
- [Quick Start](#-quick-start)
|
|
26
|
+
- [Configuration](#-configuration)
|
|
27
|
+
- [CLI Commands](#-cli-commands)
|
|
28
|
+
- [Advanced Usage](#-advanced-usage)
|
|
29
|
+
- [Edge Cases & Troubleshooting](#-edge-cases--troubleshooting)
|
|
30
|
+
- [Best Practices](#-best-practices)
|
|
31
|
+
- [API Reference](#-api-reference)
|
|
32
|
+
- [Contributing](#-contributing)
|
|
33
|
+
|
|
34
|
+
## 📦 Installation
|
|
35
|
+
|
|
36
|
+
### Prerequisites
|
|
37
|
+
|
|
38
|
+
- **Node.js** >= 18.0.0
|
|
39
|
+
- **npm**, **yarn**, or **pnpm**
|
|
40
|
+
|
|
41
|
+
### Install as Dev Dependency
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm install --save-dev translatronx
|
|
45
|
+
# or
|
|
46
|
+
yarn add --dev translatronx
|
|
47
|
+
# or
|
|
48
|
+
pnpm add -D translatronx
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Install Globally (Optional)
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npm install -g translatronx
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## 🚀 Quick Start
|
|
58
|
+
|
|
59
|
+
### 1. Initialize Configuration
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npx translatronx init
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
This creates a `translatronx.config.ts` file in your project root:
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
import { defineConfig } from 'translatronx';
|
|
69
|
+
|
|
70
|
+
export default defineConfig({
|
|
71
|
+
sourceLanguage: 'en',
|
|
72
|
+
targetLanguages: [
|
|
73
|
+
{ language: 'French', shortCode: 'fr' },
|
|
74
|
+
{ language: 'German', shortCode: 'de' },
|
|
75
|
+
{ language: 'Spanish', shortCode: 'es' }
|
|
76
|
+
],
|
|
77
|
+
extractors: [
|
|
78
|
+
{
|
|
79
|
+
type: 'json',
|
|
80
|
+
pattern: './locales/en.json'
|
|
81
|
+
}
|
|
82
|
+
],
|
|
83
|
+
providers: [
|
|
84
|
+
{
|
|
85
|
+
name: 'openai',
|
|
86
|
+
type: 'openai',
|
|
87
|
+
model: 'gpt-4o-mini',
|
|
88
|
+
temperature: 0.3
|
|
89
|
+
}
|
|
90
|
+
],
|
|
91
|
+
output: {
|
|
92
|
+
dir: './locales',
|
|
93
|
+
format: 'json',
|
|
94
|
+
fileNaming: '{shortCode}.json'
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### 2. Set API Key
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
# For OpenAI
|
|
103
|
+
export OPENAI_API_KEY=your-api-key
|
|
104
|
+
|
|
105
|
+
# For Anthropic
|
|
106
|
+
export ANTHROPIC_API_KEY=your-api-key
|
|
107
|
+
|
|
108
|
+
# For Groq
|
|
109
|
+
export GROQ_API_KEY=your-api-key
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### 3. Create Source Translation File
|
|
113
|
+
|
|
114
|
+
Create `./locales/en.json`:
|
|
115
|
+
|
|
116
|
+
```json
|
|
117
|
+
{
|
|
118
|
+
"welcome": "Welcome to our app!",
|
|
119
|
+
"greeting": "Hello, {name}!",
|
|
120
|
+
"auth": {
|
|
121
|
+
"login": "Log in",
|
|
122
|
+
"logout": "Log out",
|
|
123
|
+
"signup": "Sign up"
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### 4. Run Translation Sync
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
npx translatronx sync
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**Output:**
|
|
135
|
+
```
|
|
136
|
+
🔄 Syncing translations...
|
|
137
|
+
|
|
138
|
+
✅ Translation sync complete!
|
|
139
|
+
|
|
140
|
+
Statistics:
|
|
141
|
+
Total strings: 5
|
|
142
|
+
Translated: 15
|
|
143
|
+
Failed: 0
|
|
144
|
+
Skipped: 0
|
|
145
|
+
Tokens used: 245 (input) + 312 (output)
|
|
146
|
+
Duration: 3.42s
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
This generates:
|
|
150
|
+
- `./locales/fr.json`
|
|
151
|
+
- `./locales/de.json`
|
|
152
|
+
- `./locales/es.json`
|
|
153
|
+
|
|
154
|
+
### 5. Check Status
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
npx translatronx status
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## ⚙️ Configuration
|
|
161
|
+
|
|
162
|
+
### Complete Configuration Reference
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
import { defineConfig } from 'translatronx';
|
|
166
|
+
|
|
167
|
+
export default defineConfig({
|
|
168
|
+
// Source language code (ISO 639-1)
|
|
169
|
+
sourceLanguage: 'en',
|
|
170
|
+
|
|
171
|
+
// Target languages with full names and short codes
|
|
172
|
+
targetLanguages: [
|
|
173
|
+
{ language: 'French', shortCode: 'fr' },
|
|
174
|
+
{ language: 'German (Formal)', shortCode: 'de-formal' },
|
|
175
|
+
{ language: 'Simplified Chinese', shortCode: 'zh-Hans' }
|
|
176
|
+
],
|
|
177
|
+
|
|
178
|
+
// Extractors define how to find translatable strings
|
|
179
|
+
extractors: [
|
|
180
|
+
{
|
|
181
|
+
type: 'json', // 'json' | 'typescript' | 'custom'
|
|
182
|
+
pattern: './locales/en.json', // Glob pattern(s)
|
|
183
|
+
keyPrefix: 'app', // Optional: prefix for all keys
|
|
184
|
+
exclude: ['**/node_modules/**'] // Optional: exclude patterns
|
|
185
|
+
}
|
|
186
|
+
],
|
|
187
|
+
|
|
188
|
+
// LLM providers configuration
|
|
189
|
+
providers: [
|
|
190
|
+
{
|
|
191
|
+
name: 'openai-primary',
|
|
192
|
+
type: 'openai',
|
|
193
|
+
model: 'gpt-4o-mini',
|
|
194
|
+
temperature: 0.3,
|
|
195
|
+
maxRetries: 3,
|
|
196
|
+
apiKey: process.env.OPENAI_API_KEY, // Optional: defaults to env var
|
|
197
|
+
fallback: 'anthropic-backup' // Optional: fallback provider
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
name: 'anthropic-backup',
|
|
201
|
+
type: 'anthropic',
|
|
202
|
+
model: 'claude-3-5-sonnet-20241022',
|
|
203
|
+
temperature: 0.3,
|
|
204
|
+
maxRetries: 2
|
|
205
|
+
}
|
|
206
|
+
],
|
|
207
|
+
|
|
208
|
+
// Validation rules
|
|
209
|
+
validation: {
|
|
210
|
+
preservePlaceholders: true, // Ensure {var} placeholders are preserved
|
|
211
|
+
maxLengthRatio: 3, // Max target/source length ratio
|
|
212
|
+
preventSourceLeakage: true, // Prevent untranslated source text
|
|
213
|
+
brandNames: ['Acme', 'Widget'], // Protected brand names
|
|
214
|
+
customRules: [] // Custom validation functions
|
|
215
|
+
},
|
|
216
|
+
|
|
217
|
+
// Output configuration
|
|
218
|
+
output: {
|
|
219
|
+
dir: './locales',
|
|
220
|
+
format: 'json', // 'json' | 'yaml' | 'typescript'
|
|
221
|
+
flat: false, // Flatten nested objects
|
|
222
|
+
indent: 2, // JSON indentation
|
|
223
|
+
fileNaming: '{shortCode}.json', // File naming pattern
|
|
224
|
+
allowSameFolder: false // Allow source & target in same dir
|
|
225
|
+
},
|
|
226
|
+
|
|
227
|
+
// Prompt customization
|
|
228
|
+
prompts: {
|
|
229
|
+
customContext: 'This is a mobile banking app. Use financial terminology.',
|
|
230
|
+
formatting: 'formal', // 'formal' | 'casual' | 'technical'
|
|
231
|
+
glossary: {
|
|
232
|
+
'Dashboard': 'Tableau de bord',
|
|
233
|
+
'Settings': 'Paramètres'
|
|
234
|
+
},
|
|
235
|
+
brandVoice: 'Professional, trustworthy, and user-friendly',
|
|
236
|
+
userPrompt: [ // Custom user prompt (optional)
|
|
237
|
+
'Translate the following strings for a mobile app.',
|
|
238
|
+
'Maintain consistency with previous translations.'
|
|
239
|
+
]
|
|
240
|
+
},
|
|
241
|
+
|
|
242
|
+
// Advanced settings
|
|
243
|
+
advanced: {
|
|
244
|
+
batchSize: 20, // Strings per LLM call
|
|
245
|
+
concurrency: 3, // Parallel LLM requests
|
|
246
|
+
cacheDir: './.translatronx', // State directory
|
|
247
|
+
ledgerPath: './.translatronx/ledger.sqlite',
|
|
248
|
+
verbose: false // Enable verbose logging
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Configuration Options Explained
|
|
254
|
+
|
|
255
|
+
#### Target Languages
|
|
256
|
+
|
|
257
|
+
Each target language requires:
|
|
258
|
+
- `language`: Full language name (e.g., "French", "German (Formal)")
|
|
259
|
+
- `shortCode`: ISO code or custom code (e.g., "fr", "de-formal", "zh-Hans")
|
|
260
|
+
|
|
261
|
+
The `language` field provides context to the LLM for better translations.
|
|
262
|
+
|
|
263
|
+
#### Extractors
|
|
264
|
+
|
|
265
|
+
**JSON Extractor:**
|
|
266
|
+
```typescript
|
|
267
|
+
{
|
|
268
|
+
type: 'json',
|
|
269
|
+
pattern: './locales/**/*.json',
|
|
270
|
+
exclude: ['**/node_modules/**']
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
**TypeScript Extractor:**
|
|
275
|
+
```typescript
|
|
276
|
+
{
|
|
277
|
+
type: 'typescript',
|
|
278
|
+
pattern: './src/**/*.ts',
|
|
279
|
+
keyPrefix: 'app'
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
#### Providers
|
|
284
|
+
|
|
285
|
+
**OpenAI:**
|
|
286
|
+
```typescript
|
|
287
|
+
{
|
|
288
|
+
name: 'openai',
|
|
289
|
+
type: 'openai',
|
|
290
|
+
model: 'gpt-4o-mini', // or 'gpt-4o', 'gpt-4-turbo'
|
|
291
|
+
temperature: 0.3,
|
|
292
|
+
apiKey: process.env.OPENAI_API_KEY
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
**Anthropic:**
|
|
297
|
+
```typescript
|
|
298
|
+
{
|
|
299
|
+
name: 'anthropic',
|
|
300
|
+
type: 'anthropic',
|
|
301
|
+
model: 'claude-3-5-sonnet-20241022',
|
|
302
|
+
temperature: 0.3,
|
|
303
|
+
apiKey: process.env.ANTHROPIC_API_KEY
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
**Groq:**
|
|
308
|
+
```typescript
|
|
309
|
+
{
|
|
310
|
+
name: 'groq',
|
|
311
|
+
type: 'groq',
|
|
312
|
+
model: 'llama-3.3-70b-versatile',
|
|
313
|
+
temperature: 0.3,
|
|
314
|
+
apiKey: process.env.GROQ_API_KEY
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
**Azure OpenAI:**
|
|
319
|
+
```typescript
|
|
320
|
+
{
|
|
321
|
+
name: 'azure',
|
|
322
|
+
type: 'azure-openai',
|
|
323
|
+
model: 'gpt-4o',
|
|
324
|
+
baseUrl: 'https://your-resource.openai.azure.com',
|
|
325
|
+
apiKey: process.env.AZURE_OPENAI_KEY
|
|
326
|
+
}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
**OpenRouter:**
|
|
330
|
+
```typescript
|
|
331
|
+
{
|
|
332
|
+
name: 'openrouter',
|
|
333
|
+
type: 'openrouter',
|
|
334
|
+
model: 'anthropic/claude-3.5-sonnet',
|
|
335
|
+
apiKey: process.env.OPENROUTER_API_KEY
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
**Local Models:**
|
|
340
|
+
```typescript
|
|
341
|
+
{
|
|
342
|
+
name: 'local',
|
|
343
|
+
type: 'local',
|
|
344
|
+
model: 'llama3',
|
|
345
|
+
baseUrl: 'http://localhost:11434' // Ollama endpoint
|
|
346
|
+
}
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
#### Output File Naming
|
|
350
|
+
|
|
351
|
+
Use placeholders in `fileNaming`:
|
|
352
|
+
- `{shortCode}` - Language short code (e.g., "fr")
|
|
353
|
+
- `{language}` - Full language name (e.g., "French")
|
|
354
|
+
|
|
355
|
+
Examples:
|
|
356
|
+
- `{shortCode}.json` → `fr.json`
|
|
357
|
+
- `{language}.translation.json` → `French.translation.json`
|
|
358
|
+
- `translations/{shortCode}/app.json` → `translations/fr/app.json`
|
|
359
|
+
|
|
360
|
+
## 🎮 CLI Commands
|
|
361
|
+
|
|
362
|
+
### `translatronx init`
|
|
363
|
+
|
|
364
|
+
Initialize translatronx configuration.
|
|
365
|
+
|
|
366
|
+
```bash
|
|
367
|
+
translatronx init
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
Creates `translatronx.config.ts` with default settings.
|
|
371
|
+
|
|
372
|
+
---
|
|
373
|
+
|
|
374
|
+
### `translatronx sync`
|
|
375
|
+
|
|
376
|
+
Synchronize translations (incremental processing).
|
|
377
|
+
|
|
378
|
+
```bash
|
|
379
|
+
translatronx sync [options]
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
**Options:**
|
|
383
|
+
- `-f, --force` - Force regeneration of manual overrides
|
|
384
|
+
- `-v, --verbose` - Enable verbose output with streaming
|
|
385
|
+
|
|
386
|
+
**Examples:**
|
|
387
|
+
|
|
388
|
+
```bash
|
|
389
|
+
# Normal incremental sync
|
|
390
|
+
translatronx sync
|
|
391
|
+
|
|
392
|
+
# Force regenerate all translations (ignores manual edits)
|
|
393
|
+
translatronx sync --force
|
|
394
|
+
|
|
395
|
+
# Verbose mode with detailed logging
|
|
396
|
+
translatronx sync --verbose
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
**What happens during sync:**
|
|
400
|
+
1. Extracts source strings from configured files
|
|
401
|
+
2. Computes hashes and detects changes
|
|
402
|
+
3. Identifies new/modified strings needing translation
|
|
403
|
+
4. Deduplicates identical strings across keys
|
|
404
|
+
5. Batches strings for efficient LLM calls
|
|
405
|
+
6. Translates using configured provider(s)
|
|
406
|
+
7. Validates translations (placeholders, length, etc.)
|
|
407
|
+
8. Atomically writes to target files
|
|
408
|
+
9. Updates ledger with new state
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
### `translatronx status`
|
|
413
|
+
|
|
414
|
+
Display coverage statistics and system state.
|
|
415
|
+
|
|
416
|
+
```bash
|
|
417
|
+
translatronx status
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
**Output:**
|
|
421
|
+
```
|
|
422
|
+
📊 Checking status...
|
|
423
|
+
|
|
424
|
+
Project Statistics:
|
|
425
|
+
Total keys: 127
|
|
426
|
+
Manual overrides: 3
|
|
427
|
+
|
|
428
|
+
Language Coverage:
|
|
429
|
+
French (fr):
|
|
430
|
+
✓ Translated: 127
|
|
431
|
+
✗ Failed: 0
|
|
432
|
+
Coverage: 100%
|
|
433
|
+
|
|
434
|
+
German (de):
|
|
435
|
+
✓ Translated: 124
|
|
436
|
+
✗ Failed: 3
|
|
437
|
+
Coverage: 98%
|
|
438
|
+
|
|
439
|
+
Latest Run:
|
|
440
|
+
Run ID: run_2026-01-29T06-30-00
|
|
441
|
+
Model: gpt-4o-mini
|
|
442
|
+
Cost: $0.0142
|
|
443
|
+
Duration: Completed
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
---
|
|
447
|
+
|
|
448
|
+
### `translatronx retry`
|
|
449
|
+
|
|
450
|
+
Retry failed translation batches.
|
|
451
|
+
|
|
452
|
+
```bash
|
|
453
|
+
translatronx retry [options]
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
**Options:**
|
|
457
|
+
- `--batch <id>` - Specific batch ID to retry
|
|
458
|
+
- `--lang <code>` - Specific language to retry (comma-separated)
|
|
459
|
+
- `--dry-run` - Show what would be retried without making changes
|
|
460
|
+
|
|
461
|
+
**Examples:**
|
|
462
|
+
|
|
463
|
+
```bash
|
|
464
|
+
# Retry all failed translations
|
|
465
|
+
translatronx retry
|
|
466
|
+
|
|
467
|
+
# Retry only French translations
|
|
468
|
+
translatronx retry --lang fr
|
|
469
|
+
|
|
470
|
+
# Retry multiple languages
|
|
471
|
+
translatronx retry --lang fr,de,es
|
|
472
|
+
|
|
473
|
+
# Dry run to see what would be retried
|
|
474
|
+
translatronx retry --dry-run
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
---
|
|
478
|
+
|
|
479
|
+
### `translatronx check`
|
|
480
|
+
|
|
481
|
+
Validate target files without making changes.
|
|
482
|
+
|
|
483
|
+
```bash
|
|
484
|
+
translatronx check
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
**Note:** This command validates:
|
|
488
|
+
- Placeholder preservation
|
|
489
|
+
- JSON structure integrity
|
|
490
|
+
- Length ratios
|
|
491
|
+
- Source text leakage
|
|
492
|
+
|
|
493
|
+
---
|
|
494
|
+
|
|
495
|
+
## 🔥 Advanced Usage
|
|
496
|
+
|
|
497
|
+
### Manual Override Protection
|
|
498
|
+
|
|
499
|
+
translatronx detects when you manually edit translations and protects them from being overwritten.
|
|
500
|
+
|
|
501
|
+
**Workflow:**
|
|
502
|
+
|
|
503
|
+
1. **Initial translation:**
|
|
504
|
+
```json
|
|
505
|
+
// fr.json (auto-generated)
|
|
506
|
+
{
|
|
507
|
+
"welcome": "Bienvenue dans notre application !"
|
|
508
|
+
}
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
2. **Manual edit:**
|
|
512
|
+
```json
|
|
513
|
+
// fr.json (manually edited)
|
|
514
|
+
{
|
|
515
|
+
"welcome": "Bienvenue sur notre plateforme !"
|
|
516
|
+
}
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
3. **Next sync:**
|
|
520
|
+
- translatronx detects hash mismatch
|
|
521
|
+
- Marks as `MANUAL` status in ledger
|
|
522
|
+
- **Skips** this key in future syncs
|
|
523
|
+
|
|
524
|
+
4. **Force regeneration (if needed):**
|
|
525
|
+
```bash
|
|
526
|
+
translatronx sync --force
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
### Provider Fallback Chain
|
|
530
|
+
|
|
531
|
+
Configure multiple providers with automatic fallback:
|
|
532
|
+
|
|
533
|
+
```typescript
|
|
534
|
+
providers: [
|
|
535
|
+
{
|
|
536
|
+
name: 'primary',
|
|
537
|
+
type: 'openai',
|
|
538
|
+
model: 'gpt-4o-mini',
|
|
539
|
+
fallback: 'backup'
|
|
540
|
+
},
|
|
541
|
+
{
|
|
542
|
+
name: 'backup',
|
|
543
|
+
type: 'anthropic',
|
|
544
|
+
model: 'claude-3-5-sonnet-20241022',
|
|
545
|
+
fallback: 'local'
|
|
546
|
+
},
|
|
547
|
+
{
|
|
548
|
+
name: 'local',
|
|
549
|
+
type: 'local',
|
|
550
|
+
model: 'llama3',
|
|
551
|
+
baseUrl: 'http://localhost:11434'
|
|
552
|
+
}
|
|
553
|
+
]
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
**Fallback triggers:**
|
|
557
|
+
- API rate limits
|
|
558
|
+
- Network errors
|
|
559
|
+
- Validation failures after max retries
|
|
560
|
+
|
|
561
|
+
### Custom Prompt Engineering
|
|
562
|
+
|
|
563
|
+
Fine-tune translation quality with custom prompts:
|
|
564
|
+
|
|
565
|
+
```typescript
|
|
566
|
+
prompts: {
|
|
567
|
+
// Context about your application
|
|
568
|
+
customContext: `
|
|
569
|
+
This is a healthcare application for patients and doctors.
|
|
570
|
+
Use medical terminology appropriately.
|
|
571
|
+
Maintain HIPAA-compliant language.
|
|
572
|
+
`,
|
|
573
|
+
|
|
574
|
+
// Tone and style
|
|
575
|
+
formatting: 'formal',
|
|
576
|
+
|
|
577
|
+
// Glossary for consistent terminology
|
|
578
|
+
glossary: {
|
|
579
|
+
'Appointment': 'Rendez-vous',
|
|
580
|
+
'Medical Record': 'Dossier médical',
|
|
581
|
+
'Prescription': 'Ordonnance'
|
|
582
|
+
},
|
|
583
|
+
|
|
584
|
+
// Brand voice
|
|
585
|
+
brandVoice: 'Compassionate, professional, and clear',
|
|
586
|
+
|
|
587
|
+
// Custom user prompt (advanced)
|
|
588
|
+
userPrompt: [
|
|
589
|
+
'Translate the following medical app strings.',
|
|
590
|
+
'Ensure all medical terms are accurate.',
|
|
591
|
+
'Use patient-friendly language where appropriate.'
|
|
592
|
+
]
|
|
593
|
+
}
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
### Same-Folder Source and Target
|
|
597
|
+
|
|
598
|
+
By default, translatronx prevents source and target files in the same directory to avoid confusion. Enable if needed:
|
|
599
|
+
|
|
600
|
+
```typescript
|
|
601
|
+
output: {
|
|
602
|
+
dir: './locales',
|
|
603
|
+
allowSameFolder: true,
|
|
604
|
+
fileNaming: '{shortCode}.json'
|
|
605
|
+
}
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
**Example structure:**
|
|
609
|
+
```
|
|
610
|
+
locales/
|
|
611
|
+
├── en.json (source)
|
|
612
|
+
├── fr.json (target)
|
|
613
|
+
├── de.json (target)
|
|
614
|
+
└── es.json (target)
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
### CI/CD Integration
|
|
618
|
+
|
|
619
|
+
#### GitHub Actions
|
|
620
|
+
|
|
621
|
+
```yaml
|
|
622
|
+
name: Sync Translations
|
|
623
|
+
|
|
624
|
+
on:
|
|
625
|
+
push:
|
|
626
|
+
branches: [main]
|
|
627
|
+
paths:
|
|
628
|
+
- 'locales/en.json'
|
|
629
|
+
|
|
630
|
+
jobs:
|
|
631
|
+
translate:
|
|
632
|
+
runs-on: ubuntu-latest
|
|
633
|
+
steps:
|
|
634
|
+
- uses: actions/checkout@v3
|
|
635
|
+
|
|
636
|
+
- name: Setup Node.js
|
|
637
|
+
uses: actions/setup-node@v3
|
|
638
|
+
with:
|
|
639
|
+
node-version: '18'
|
|
640
|
+
|
|
641
|
+
- name: Install dependencies
|
|
642
|
+
run: npm ci
|
|
643
|
+
|
|
644
|
+
- name: Sync translations
|
|
645
|
+
env:
|
|
646
|
+
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
647
|
+
run: npx translatronx sync
|
|
648
|
+
|
|
649
|
+
- name: Commit translations
|
|
650
|
+
run: |
|
|
651
|
+
git config user.name "Translation Bot"
|
|
652
|
+
git config user.email "bot@example.com"
|
|
653
|
+
git add locales/
|
|
654
|
+
git commit -m "chore: update translations" || exit 0
|
|
655
|
+
git push
|
|
656
|
+
```
|
|
657
|
+
|
|
658
|
+
#### GitLab CI
|
|
659
|
+
|
|
660
|
+
```yaml
|
|
661
|
+
translate:
|
|
662
|
+
stage: build
|
|
663
|
+
image: node:18
|
|
664
|
+
script:
|
|
665
|
+
- npm ci
|
|
666
|
+
- npx translatronx sync
|
|
667
|
+
artifacts:
|
|
668
|
+
paths:
|
|
669
|
+
- locales/
|
|
670
|
+
only:
|
|
671
|
+
changes:
|
|
672
|
+
- locales/en.json
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
### Programmatic API Usage
|
|
676
|
+
|
|
677
|
+
Use translatronx programmatically in Node.js:
|
|
678
|
+
|
|
679
|
+
```typescript
|
|
680
|
+
import { TranslationCompiler, loadConfig } from 'translatronx';
|
|
681
|
+
|
|
682
|
+
async function translateApp() {
|
|
683
|
+
// Load configuration
|
|
684
|
+
const config = await loadConfig();
|
|
685
|
+
|
|
686
|
+
// Create compiler instance
|
|
687
|
+
const compiler = new TranslationCompiler(config);
|
|
688
|
+
|
|
689
|
+
// Run sync
|
|
690
|
+
const stats = await compiler.sync({ verbose: true });
|
|
691
|
+
|
|
692
|
+
console.log(`Translated ${stats.translatedUnits} strings`);
|
|
693
|
+
console.log(`Cost: $${stats.costEstimateUsd.toFixed(4)}`);
|
|
694
|
+
|
|
695
|
+
// Close ledger connection
|
|
696
|
+
compiler.close();
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
translateApp().catch(console.error);
|
|
700
|
+
```
|
|
701
|
+
|
|
702
|
+
## 🐛 Edge Cases & Troubleshooting
|
|
703
|
+
|
|
704
|
+
### Edge Case 1: Placeholder Variations
|
|
705
|
+
|
|
706
|
+
**Problem:** Different placeholder formats in your app.
|
|
707
|
+
|
|
708
|
+
**Solution:** translatronx automatically detects and preserves:
|
|
709
|
+
- `{variable}` - Single braces
|
|
710
|
+
- `{{variable}}` - Double braces
|
|
711
|
+
- `$variable` - Dollar sign
|
|
712
|
+
- `%s`, `%d` - Printf-style
|
|
713
|
+
- `%1$s` - Positional
|
|
714
|
+
|
|
715
|
+
**Example:**
|
|
716
|
+
```json
|
|
717
|
+
{
|
|
718
|
+
"greeting": "Hello, {name}!",
|
|
719
|
+
"count": "You have {{count}} messages",
|
|
720
|
+
"format": "User: %s, ID: %d"
|
|
721
|
+
}
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
All placeholders are preserved exactly in translations.
|
|
725
|
+
|
|
726
|
+
### Edge Case 2: Nested JSON Structures
|
|
727
|
+
|
|
728
|
+
**Problem:** Deep nesting in translation files.
|
|
729
|
+
|
|
730
|
+
**Solution:** translatronx flattens keys internally using dot notation:
|
|
731
|
+
|
|
732
|
+
```json
|
|
733
|
+
{
|
|
734
|
+
"auth": {
|
|
735
|
+
"login": {
|
|
736
|
+
"title": "Sign In",
|
|
737
|
+
"button": "Log In"
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
```
|
|
742
|
+
|
|
743
|
+
Internally tracked as:
|
|
744
|
+
- `auth.login.title`
|
|
745
|
+
- `auth.login.button`
|
|
746
|
+
|
|
747
|
+
Output maintains original structure.
|
|
748
|
+
|
|
749
|
+
### Edge Case 3: Empty or Whitespace Strings
|
|
750
|
+
|
|
751
|
+
**Problem:** Empty strings or whitespace-only values.
|
|
752
|
+
|
|
753
|
+
**Behavior:**
|
|
754
|
+
- Empty strings (`""`) are skipped
|
|
755
|
+
- Whitespace-only strings are normalized and translated
|
|
756
|
+
- Leading/trailing whitespace is preserved if intentional
|
|
757
|
+
|
|
758
|
+
### Edge Case 4: Very Long Strings
|
|
759
|
+
|
|
760
|
+
**Problem:** Strings exceeding token limits.
|
|
761
|
+
|
|
762
|
+
**Solution:**
|
|
763
|
+
- Automatic chunking for strings > 1000 characters
|
|
764
|
+
- Configurable `maxLengthRatio` validation
|
|
765
|
+
- Warning if target exceeds `source length × maxLengthRatio`
|
|
766
|
+
|
|
767
|
+
### Edge Case 5: Special Characters & Encoding
|
|
768
|
+
|
|
769
|
+
**Problem:** Unicode, emojis, RTL languages.
|
|
770
|
+
|
|
771
|
+
**Solution:**
|
|
772
|
+
- All text normalized to Unicode NFC
|
|
773
|
+
- Full Unicode support including emojis 🎉
|
|
774
|
+
- RTL languages (Arabic, Hebrew) handled correctly
|
|
775
|
+
- HTML entities preserved
|
|
776
|
+
|
|
777
|
+
### Edge Case 6: Interrupted Sync
|
|
778
|
+
|
|
779
|
+
**Problem:** Process killed during translation.
|
|
780
|
+
|
|
781
|
+
**Solution:**
|
|
782
|
+
- Atomic file writes (temp file → rename)
|
|
783
|
+
- Transactional ledger updates
|
|
784
|
+
- No partial/corrupted files
|
|
785
|
+
- Safe to re-run sync immediately
|
|
786
|
+
|
|
787
|
+
### Edge Case 7: API Rate Limits
|
|
788
|
+
|
|
789
|
+
**Problem:** Provider rate limits exceeded.
|
|
790
|
+
|
|
791
|
+
**Solution:**
|
|
792
|
+
- Automatic retry with exponential backoff
|
|
793
|
+
- Fallback to secondary provider
|
|
794
|
+
- Configurable `maxRetries` per provider
|
|
795
|
+
- Batch size adjustment
|
|
796
|
+
|
|
797
|
+
### Edge Case 8: Inconsistent Translations
|
|
798
|
+
|
|
799
|
+
**Problem:** Same source string translated differently.
|
|
800
|
+
|
|
801
|
+
**Solution:**
|
|
802
|
+
- Deduplication groups identical strings
|
|
803
|
+
- Single translation reused across all occurrences
|
|
804
|
+
- Glossary ensures terminology consistency
|
|
805
|
+
- Prompt version tracking for reproducibility
|
|
806
|
+
|
|
807
|
+
### Common Errors
|
|
808
|
+
|
|
809
|
+
#### Error: "Configuration file not found"
|
|
810
|
+
|
|
811
|
+
```bash
|
|
812
|
+
Error: Could not find translatronx.config.ts
|
|
813
|
+
```
|
|
814
|
+
|
|
815
|
+
**Solution:**
|
|
816
|
+
```bash
|
|
817
|
+
translatronx init
|
|
818
|
+
```
|
|
819
|
+
|
|
820
|
+
#### Error: "API key not set"
|
|
821
|
+
|
|
822
|
+
```bash
|
|
823
|
+
Error: OPENAI_API_KEY environment variable not set
|
|
824
|
+
```
|
|
825
|
+
|
|
826
|
+
**Solution:**
|
|
827
|
+
```bash
|
|
828
|
+
export OPENAI_API_KEY=your-key
|
|
829
|
+
```
|
|
830
|
+
|
|
831
|
+
#### Error: "Placeholder mismatch"
|
|
832
|
+
|
|
833
|
+
```bash
|
|
834
|
+
ValidationError: Placeholder mismatch in key "greeting"
|
|
835
|
+
Source: {name}, Target: {nom}
|
|
836
|
+
```
|
|
837
|
+
|
|
838
|
+
**Solution:** This is a validation error preventing incorrect translations. The LLM will retry automatically.
|
|
839
|
+
|
|
840
|
+
#### Error: "Source file not found"
|
|
841
|
+
|
|
842
|
+
```bash
|
|
843
|
+
Error: Source file not found: ./locales/en.json
|
|
844
|
+
```
|
|
845
|
+
|
|
846
|
+
**Solution:** Create the source file or update `extractors.pattern` in config.
|
|
847
|
+
|
|
848
|
+
## ✅ Best Practices
|
|
849
|
+
|
|
850
|
+
### 1. Version Control
|
|
851
|
+
|
|
852
|
+
**Do commit:**
|
|
853
|
+
- ✅ `translatronx.config.ts`
|
|
854
|
+
- ✅ All translation files (`*.json`, `*.yaml`)
|
|
855
|
+
- ✅ `.gitignore` entry for `.translatronx/`
|
|
856
|
+
|
|
857
|
+
**Don't commit:**
|
|
858
|
+
- ❌ `.translatronx/` directory (state files)
|
|
859
|
+
- ❌ API keys (use environment variables)
|
|
860
|
+
|
|
861
|
+
**Recommended `.gitignore`:**
|
|
862
|
+
```gitignore
|
|
863
|
+
.translatronx/
|
|
864
|
+
*.sqlite
|
|
865
|
+
*.sqlite-journal
|
|
866
|
+
```
|
|
867
|
+
|
|
868
|
+
### 2. Source File Organization
|
|
869
|
+
|
|
870
|
+
**Good:**
|
|
871
|
+
```
|
|
872
|
+
locales/
|
|
873
|
+
├── en.json # Single source of truth
|
|
874
|
+
├── fr.json # Generated
|
|
875
|
+
├── de.json # Generated
|
|
876
|
+
└── es.json # Generated
|
|
877
|
+
```
|
|
878
|
+
|
|
879
|
+
**Better:**
|
|
880
|
+
```
|
|
881
|
+
locales/
|
|
882
|
+
├── source/
|
|
883
|
+
│ └── en.json # Source (manually edited)
|
|
884
|
+
└── generated/
|
|
885
|
+
├── fr.json # Generated (auto-managed)
|
|
886
|
+
├── de.json
|
|
887
|
+
└── es.json
|
|
888
|
+
```
|
|
889
|
+
|
|
890
|
+
### 3. Incremental Adoption
|
|
891
|
+
|
|
892
|
+
Start small, expand gradually:
|
|
893
|
+
|
|
894
|
+
```typescript
|
|
895
|
+
// Phase 1: Single language
|
|
896
|
+
targetLanguages: [
|
|
897
|
+
{ language: 'French', shortCode: 'fr' }
|
|
898
|
+
]
|
|
899
|
+
|
|
900
|
+
// Phase 2: Add more languages
|
|
901
|
+
targetLanguages: [
|
|
902
|
+
{ language: 'French', shortCode: 'fr' },
|
|
903
|
+
{ language: 'German', shortCode: 'de' },
|
|
904
|
+
{ language: 'Spanish', shortCode: 'es' }
|
|
905
|
+
]
|
|
906
|
+
|
|
907
|
+
// Phase 3: Regional variants
|
|
908
|
+
targetLanguages: [
|
|
909
|
+
{ language: 'French (France)', shortCode: 'fr-FR' },
|
|
910
|
+
{ language: 'French (Canada)', shortCode: 'fr-CA' },
|
|
911
|
+
{ language: 'Spanish (Spain)', shortCode: 'es-ES' },
|
|
912
|
+
{ language: 'Spanish (Mexico)', shortCode: 'es-MX' }
|
|
913
|
+
]
|
|
914
|
+
```
|
|
915
|
+
|
|
916
|
+
### 4. Cost Optimization
|
|
917
|
+
|
|
918
|
+
**Minimize costs:**
|
|
919
|
+
- Use smaller models for simple strings (`gpt-4o-mini`)
|
|
920
|
+
- Increase `batchSize` for fewer API calls
|
|
921
|
+
- Use deduplication (enabled by default)
|
|
922
|
+
- Set appropriate `temperature` (0.3 recommended)
|
|
923
|
+
|
|
924
|
+
**Cost estimation:**
|
|
925
|
+
```bash
|
|
926
|
+
# Dry run to estimate cost
|
|
927
|
+
translatronx sync --dry-run
|
|
928
|
+
```
|
|
929
|
+
|
|
930
|
+
### 5. Quality Assurance
|
|
931
|
+
|
|
932
|
+
**Multi-stage validation:**
|
|
933
|
+
|
|
934
|
+
```typescript
|
|
935
|
+
validation: {
|
|
936
|
+
preservePlaceholders: true,
|
|
937
|
+
maxLengthRatio: 3,
|
|
938
|
+
preventSourceLeakage: true,
|
|
939
|
+
brandNames: ['YourBrand', 'ProductName']
|
|
940
|
+
}
|
|
941
|
+
```
|
|
942
|
+
|
|
943
|
+
**Manual review workflow:**
|
|
944
|
+
1. Run `translatronx sync`
|
|
945
|
+
2. Review generated files
|
|
946
|
+
3. Manually edit if needed
|
|
947
|
+
4. Commit changes
|
|
948
|
+
5. Future syncs preserve manual edits
|
|
949
|
+
|
|
950
|
+
### 6. Prompt Optimization
|
|
951
|
+
|
|
952
|
+
**Effective prompts:**
|
|
953
|
+
|
|
954
|
+
```typescript
|
|
955
|
+
prompts: {
|
|
956
|
+
customContext: `
|
|
957
|
+
Context: E-commerce checkout flow
|
|
958
|
+
Audience: International shoppers
|
|
959
|
+
Tone: Clear, reassuring, action-oriented
|
|
960
|
+
`,
|
|
961
|
+
formatting: 'casual',
|
|
962
|
+
glossary: {
|
|
963
|
+
'Cart': 'Panier',
|
|
964
|
+
'Checkout': 'Passer commande',
|
|
965
|
+
'Shipping': 'Livraison'
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
```
|
|
969
|
+
|
|
970
|
+
### 7. Monitoring & Debugging
|
|
971
|
+
|
|
972
|
+
**Enable verbose mode:**
|
|
973
|
+
```bash
|
|
974
|
+
translatronx sync --verbose
|
|
975
|
+
```
|
|
976
|
+
|
|
977
|
+
**Check status regularly:**
|
|
978
|
+
```bash
|
|
979
|
+
translatronx status
|
|
980
|
+
```
|
|
981
|
+
|
|
982
|
+
**Review run history:**
|
|
983
|
+
```bash
|
|
984
|
+
# Ledger stores run history
|
|
985
|
+
sqlite3 .translatronx/ledger.sqlite "SELECT * FROM run_history ORDER BY started_at DESC LIMIT 5;"
|
|
986
|
+
```
|
|
987
|
+
|
|
988
|
+
## 📚 API Reference
|
|
989
|
+
|
|
990
|
+
### `defineConfig(config: translatronxConfig)`
|
|
991
|
+
|
|
992
|
+
Define and validate translatronx configuration.
|
|
993
|
+
|
|
994
|
+
```typescript
|
|
995
|
+
import { defineConfig } from 'translatronx';
|
|
996
|
+
|
|
997
|
+
export default defineConfig({
|
|
998
|
+
// ... configuration
|
|
999
|
+
});
|
|
1000
|
+
```
|
|
1001
|
+
|
|
1002
|
+
### `loadConfig(configPath?: string)`
|
|
1003
|
+
|
|
1004
|
+
Load configuration from file.
|
|
1005
|
+
|
|
1006
|
+
```typescript
|
|
1007
|
+
import { loadConfig } from 'translatronx';
|
|
1008
|
+
|
|
1009
|
+
const config = await loadConfig('./custom.config.ts');
|
|
1010
|
+
```
|
|
1011
|
+
|
|
1012
|
+
### `TranslationCompiler`
|
|
1013
|
+
|
|
1014
|
+
Main orchestrator for translation compilation.
|
|
1015
|
+
|
|
1016
|
+
```typescript
|
|
1017
|
+
import { TranslationCompiler } from 'translatronx';
|
|
1018
|
+
|
|
1019
|
+
const compiler = new TranslationCompiler(config);
|
|
1020
|
+
```
|
|
1021
|
+
|
|
1022
|
+
**Methods:**
|
|
1023
|
+
|
|
1024
|
+
#### `sync(options?: SyncOptions): Promise<RunStatistics>`
|
|
1025
|
+
|
|
1026
|
+
Synchronize translations.
|
|
1027
|
+
|
|
1028
|
+
```typescript
|
|
1029
|
+
const stats = await compiler.sync({
|
|
1030
|
+
force: false,
|
|
1031
|
+
verbose: false
|
|
1032
|
+
});
|
|
1033
|
+
```
|
|
1034
|
+
|
|
1035
|
+
#### `retryFailed(options?: RetryOptions): Promise<RetryStatistics>`
|
|
1036
|
+
|
|
1037
|
+
Retry failed translations.
|
|
1038
|
+
|
|
1039
|
+
```typescript
|
|
1040
|
+
const stats = await compiler.retryFailed({
|
|
1041
|
+
lang: 'fr',
|
|
1042
|
+
dryRun: false
|
|
1043
|
+
});
|
|
1044
|
+
```
|
|
1045
|
+
|
|
1046
|
+
#### `close(): void`
|
|
1047
|
+
|
|
1048
|
+
Close ledger connection.
|
|
1049
|
+
|
|
1050
|
+
```typescript
|
|
1051
|
+
compiler.close();
|
|
1052
|
+
```
|
|
1053
|
+
|
|
1054
|
+
### Types
|
|
1055
|
+
|
|
1056
|
+
```typescript
|
|
1057
|
+
interface RunStatistics {
|
|
1058
|
+
runId: string;
|
|
1059
|
+
startedAt: Date;
|
|
1060
|
+
finishedAt?: Date;
|
|
1061
|
+
totalUnits: number;
|
|
1062
|
+
translatedUnits: number;
|
|
1063
|
+
failedUnits: number;
|
|
1064
|
+
skippedUnits: number;
|
|
1065
|
+
tokensIn: number;
|
|
1066
|
+
tokensOut: number;
|
|
1067
|
+
costEstimateUsd: number;
|
|
1068
|
+
model: string;
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
interface RetryStatistics {
|
|
1072
|
+
recoveredUnits: number;
|
|
1073
|
+
remainingFailed: number;
|
|
1074
|
+
tokensIn: number;
|
|
1075
|
+
tokensOut: number;
|
|
1076
|
+
}
|
|
1077
|
+
```
|
|
1078
|
+
|
|
1079
|
+
## 🤝 Contributing
|
|
1080
|
+
|
|
1081
|
+
Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
1082
|
+
|
|
1083
|
+
### Development Setup
|
|
1084
|
+
|
|
1085
|
+
```bash
|
|
1086
|
+
# Clone repository
|
|
1087
|
+
git clone https://github.com/yourusername/translatronx.git
|
|
1088
|
+
cd translatronx
|
|
1089
|
+
|
|
1090
|
+
# Install dependencies
|
|
1091
|
+
npm install
|
|
1092
|
+
|
|
1093
|
+
# Run tests
|
|
1094
|
+
npm test
|
|
1095
|
+
|
|
1096
|
+
# Build
|
|
1097
|
+
npm run build
|
|
1098
|
+
|
|
1099
|
+
# Lint
|
|
1100
|
+
npm run lint
|
|
1101
|
+
```
|
|
1102
|
+
|
|
1103
|
+
## 📄 License
|
|
1104
|
+
|
|
1105
|
+
MIT © [Your Name]
|
|
1106
|
+
|
|
1107
|
+
## 🙏 Acknowledgments
|
|
1108
|
+
|
|
1109
|
+
- Inspired by the TypeScript compiler philosophy
|
|
1110
|
+
- Built with [OpenAI](https://openai.com), [Anthropic](https://anthropic.com), and [Groq](https://groq.com)
|
|
1111
|
+
- Uses [better-sqlite3](https://github.com/WiseLibs/better-sqlite3) for state management
|
|
1112
|
+
|
|
1113
|
+
## 📞 Support
|
|
1114
|
+
|
|
1115
|
+
- **Issues:** [GitHub Issues](https://github.com/yourusername/translatronx/issues)
|
|
1116
|
+
- **Discussions:** [GitHub Discussions](https://github.com/yourusername/translatronx/discussions)
|
|
1117
|
+
- **Email:** support@translatronx.dev
|
|
1118
|
+
|
|
1119
|
+
---
|
|
1120
|
+
|
|
1121
|
+
**Made with ❤️ by developers, for developers**
|