translatronx 1.0.2 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +825 -671
- package/dist/cli.js +941 -77
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +76 -0
- package/dist/index.js +314 -14
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,7 +20,6 @@ translatronx treats translations like source code:
|
|
|
20
20
|
|
|
21
21
|
> translatronx is not another translation management system. It is a **translation compiler** — it treats language like code: build once → ship everywhere → zero runtime cost.
|
|
22
22
|
|
|
23
|
-
|
|
24
23
|
## 🌟 Features
|
|
25
24
|
|
|
26
25
|
- **🔄 Incremental & Deterministic** - Only translates new/changed strings, same input = same output
|
|
@@ -31,19 +30,25 @@ translatronx treats translations like source code:
|
|
|
31
30
|
- **📊 State-Aware** - SQLite ledger tracks changes without storing actual translations
|
|
32
31
|
- **🛡️ Production-Ready** - Atomic writes, transaction safety, zero data loss on interruption
|
|
33
32
|
- **🎨 Customizable Prompts** - Fine-tune translation quality with formatting, glossaries, and brand voice
|
|
33
|
+
- **📝 Context Files** - Provide LLMs with context for each translation key to improve quality
|
|
34
34
|
- **📈 Comprehensive Reporting** - Detailed statistics, cost estimates, and audit trails
|
|
35
35
|
|
|
36
36
|
## 📋 Table of Contents
|
|
37
37
|
|
|
38
38
|
- [Installation](#-installation)
|
|
39
39
|
- [Quick Start](#-quick-start)
|
|
40
|
-
- [
|
|
40
|
+
- [Tutorial: Step-by-Step Guide](#-tutorial-step-by-step-guide)
|
|
41
|
+
- [Basic Translation Workflow](#1-basic-translation-workflow)
|
|
42
|
+
- [Using Context Files for Better Translations](#2-using-context-files-for-better-translations)
|
|
43
|
+
- [Managing Existing Translations](#3-managing-existing-translations)
|
|
44
|
+
- [Customizing Prompts](#4-customizing-prompts)
|
|
45
|
+
- [CI/CD Integration](#5-cicd-integration)
|
|
46
|
+
- [Configuration Reference](#-configuration-reference)
|
|
41
47
|
- [CLI Commands](#-cli-commands)
|
|
48
|
+
- [Context Files](#-context-files)
|
|
42
49
|
- [Advanced Usage](#-advanced-usage)
|
|
43
|
-
- [Edge Cases & Troubleshooting](#-edge-cases--troubleshooting)
|
|
44
50
|
- [Best Practices](#-best-practices)
|
|
45
51
|
- [API Reference](#-api-reference)
|
|
46
|
-
- [Contributing](#-contributing)
|
|
47
52
|
|
|
48
53
|
## 📦 Installation
|
|
49
54
|
|
|
@@ -76,39 +81,7 @@ npm install -g translatronx
|
|
|
76
81
|
npx translatronx init
|
|
77
82
|
```
|
|
78
83
|
|
|
79
|
-
This creates a `translatronx.config.ts` file in your project root
|
|
80
|
-
|
|
81
|
-
```typescript
|
|
82
|
-
import { defineConfig } from 'translatronx';
|
|
83
|
-
|
|
84
|
-
export default defineConfig({
|
|
85
|
-
sourceLanguage: 'en',
|
|
86
|
-
targetLanguages: [
|
|
87
|
-
{ language: 'French', shortCode: 'fr' },
|
|
88
|
-
{ language: 'German', shortCode: 'de' },
|
|
89
|
-
{ language: 'Spanish', shortCode: 'es' }
|
|
90
|
-
],
|
|
91
|
-
extractors: [
|
|
92
|
-
{
|
|
93
|
-
type: 'json',
|
|
94
|
-
pattern: './locales/en.json'
|
|
95
|
-
}
|
|
96
|
-
],
|
|
97
|
-
providers: [
|
|
98
|
-
{
|
|
99
|
-
name: 'openai',
|
|
100
|
-
type: 'openai',
|
|
101
|
-
model: 'gpt-4o-mini',
|
|
102
|
-
temperature: 0.3
|
|
103
|
-
}
|
|
104
|
-
],
|
|
105
|
-
output: {
|
|
106
|
-
dir: './locales',
|
|
107
|
-
format: 'json',
|
|
108
|
-
fileNaming: '{shortCode}.json'
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
```
|
|
84
|
+
This creates a `translatronx.config.ts` file in your project root.
|
|
112
85
|
|
|
113
86
|
### 2. Set API Key
|
|
114
87
|
|
|
@@ -165,481 +138,457 @@ This generates:
|
|
|
165
138
|
- `./locales/de.json`
|
|
166
139
|
- `./locales/es.json`
|
|
167
140
|
|
|
168
|
-
|
|
141
|
+
## 📚 Tutorial: Step-by-Step Guide
|
|
142
|
+
|
|
143
|
+
### 1. Basic Translation Workflow
|
|
144
|
+
|
|
145
|
+
#### Step 1.1: Initialize Your Project
|
|
169
146
|
|
|
170
147
|
```bash
|
|
171
|
-
|
|
148
|
+
# Create a new directory for your translations
|
|
149
|
+
mkdir my-app-i18n
|
|
150
|
+
cd my-app-i18n
|
|
151
|
+
|
|
152
|
+
# Initialize npm project
|
|
153
|
+
npm init -y
|
|
154
|
+
|
|
155
|
+
# Install translatronx
|
|
156
|
+
npm install --save-dev translatronx
|
|
157
|
+
|
|
158
|
+
# Initialize configuration
|
|
159
|
+
npx translatronx init
|
|
172
160
|
```
|
|
173
161
|
|
|
174
|
-
|
|
162
|
+
#### Step 1.2: Configure Your Project
|
|
175
163
|
|
|
176
|
-
|
|
164
|
+
Edit `translatronx.config.ts`:
|
|
177
165
|
|
|
178
166
|
```typescript
|
|
179
167
|
import { defineConfig } from 'translatronx';
|
|
180
168
|
|
|
181
169
|
export default defineConfig({
|
|
182
|
-
// Source language code (ISO 639-1)
|
|
183
170
|
sourceLanguage: 'en',
|
|
184
|
-
|
|
185
|
-
// Target languages with full names and short codes
|
|
186
171
|
targetLanguages: [
|
|
187
172
|
{ language: 'French', shortCode: 'fr' },
|
|
188
|
-
{ language: 'German
|
|
189
|
-
{ language: '
|
|
173
|
+
{ language: 'German', shortCode: 'de' },
|
|
174
|
+
{ language: 'Spanish', shortCode: 'es' }
|
|
190
175
|
],
|
|
191
|
-
|
|
192
|
-
// Extractors define how to find translatable strings
|
|
193
176
|
extractors: [
|
|
194
177
|
{
|
|
195
|
-
type: 'json',
|
|
196
|
-
pattern: './locales/en.json'
|
|
197
|
-
keyPrefix: 'app', // Optional: prefix for all keys
|
|
198
|
-
exclude: ['**/node_modules/**'] // Optional: exclude patterns
|
|
178
|
+
type: 'json',
|
|
179
|
+
pattern: './locales/en.json'
|
|
199
180
|
}
|
|
200
181
|
],
|
|
201
|
-
|
|
202
|
-
// LLM providers configuration
|
|
203
182
|
providers: [
|
|
204
183
|
{
|
|
205
|
-
name: 'openai
|
|
184
|
+
name: 'openai',
|
|
206
185
|
type: 'openai',
|
|
207
186
|
model: 'gpt-4o-mini',
|
|
208
|
-
temperature: 0.3
|
|
209
|
-
maxRetries: 3,
|
|
210
|
-
apiKey: process.env.OPENAI_API_KEY, // Optional: defaults to env var
|
|
211
|
-
fallback: 'anthropic-backup' // Optional: fallback provider
|
|
212
|
-
},
|
|
213
|
-
{
|
|
214
|
-
name: 'anthropic-backup',
|
|
215
|
-
type: 'anthropic',
|
|
216
|
-
model: 'claude-3-5-sonnet-20241022',
|
|
217
|
-
temperature: 0.3,
|
|
218
|
-
maxRetries: 2
|
|
187
|
+
temperature: 0.3
|
|
219
188
|
}
|
|
220
189
|
],
|
|
221
|
-
|
|
222
|
-
// Validation rules
|
|
223
|
-
validation: {
|
|
224
|
-
preservePlaceholders: true, // Ensure {var} placeholders are preserved
|
|
225
|
-
maxLengthRatio: 3, // Max target/source length ratio
|
|
226
|
-
preventSourceLeakage: true, // Prevent untranslated source text
|
|
227
|
-
brandNames: ['Acme', 'Widget'], // Protected brand names
|
|
228
|
-
customRules: [] // Custom validation functions
|
|
229
|
-
},
|
|
230
|
-
|
|
231
|
-
// Output configuration
|
|
232
190
|
output: {
|
|
233
191
|
dir: './locales',
|
|
234
|
-
format: 'json',
|
|
235
|
-
|
|
236
|
-
indent: 2, // JSON indentation
|
|
237
|
-
fileNaming: '{shortCode}.json', // File naming pattern
|
|
238
|
-
allowSameFolder: false // Allow source & target in same dir
|
|
239
|
-
},
|
|
240
|
-
|
|
241
|
-
// Prompt customization
|
|
242
|
-
prompts: {
|
|
243
|
-
customContext: 'This is a mobile banking app. Use financial terminology.',
|
|
244
|
-
formatting: 'formal', // 'formal' | 'casual' | 'technical'
|
|
245
|
-
glossary: {
|
|
246
|
-
'Dashboard': 'Tableau de bord',
|
|
247
|
-
'Settings': 'Paramètres'
|
|
248
|
-
},
|
|
249
|
-
brandVoice: 'Professional, trustworthy, and user-friendly',
|
|
250
|
-
userPrompt: [ // Custom user prompt (optional)
|
|
251
|
-
'Translate the following strings for a mobile app.',
|
|
252
|
-
'Maintain consistency with previous translations.'
|
|
253
|
-
]
|
|
254
|
-
},
|
|
255
|
-
|
|
256
|
-
// Advanced settings
|
|
257
|
-
advanced: {
|
|
258
|
-
batchSize: 20, // Strings per LLM call
|
|
259
|
-
concurrency: 3, // Parallel LLM requests
|
|
260
|
-
cacheDir: './.translatronx', // State directory
|
|
261
|
-
ledgerPath: './.translatronx/ledger.sqlite',
|
|
262
|
-
verbose: false // Enable verbose logging
|
|
192
|
+
format: 'json',
|
|
193
|
+
fileNaming: '{shortCode}.json'
|
|
263
194
|
}
|
|
264
195
|
});
|
|
265
196
|
```
|
|
266
197
|
|
|
267
|
-
|
|
198
|
+
#### Step 1.3: Create Your Source Translations
|
|
268
199
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
Each target language requires:
|
|
272
|
-
- `language`: Full language name (e.g., "French", "German (Formal)")
|
|
273
|
-
- `shortCode`: ISO code or custom code (e.g., "fr", "de-formal", "zh-Hans")
|
|
274
|
-
|
|
275
|
-
The `language` field provides context to the LLM for better translations.
|
|
276
|
-
|
|
277
|
-
#### Extractors
|
|
200
|
+
Create `./locales/en.json`:
|
|
278
201
|
|
|
279
|
-
|
|
280
|
-
```typescript
|
|
202
|
+
```json
|
|
281
203
|
{
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
204
|
+
"app": {
|
|
205
|
+
"title": "My Awesome App",
|
|
206
|
+
"description": "The best app you'll ever use"
|
|
207
|
+
},
|
|
208
|
+
"navigation": {
|
|
209
|
+
"home": "Home",
|
|
210
|
+
"about": "About",
|
|
211
|
+
"contact": "Contact Us"
|
|
212
|
+
},
|
|
213
|
+
"auth": {
|
|
214
|
+
"login": "Log in",
|
|
215
|
+
"logout": "Log out",
|
|
216
|
+
"signup": "Sign up",
|
|
217
|
+
"forgotPassword": "Forgot Password?"
|
|
218
|
+
},
|
|
219
|
+
"messages": {
|
|
220
|
+
"welcome": "Welcome, {username}!",
|
|
221
|
+
"goodbye": "See you soon, {username}!",
|
|
222
|
+
"error": "An error occurred. Please try again."
|
|
223
|
+
}
|
|
285
224
|
}
|
|
286
225
|
```
|
|
287
226
|
|
|
288
|
-
|
|
289
|
-
```typescript
|
|
290
|
-
{
|
|
291
|
-
type: 'typescript',
|
|
292
|
-
pattern: './src/**/*.ts',
|
|
293
|
-
keyPrefix: 'app'
|
|
294
|
-
}
|
|
295
|
-
```
|
|
227
|
+
#### Step 1.4: Run Your First Translation
|
|
296
228
|
|
|
297
|
-
|
|
229
|
+
```bash
|
|
230
|
+
# Set your API key
|
|
231
|
+
export OPENAI_API_KEY=your-api-key-here
|
|
298
232
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
{
|
|
302
|
-
name: 'openai',
|
|
303
|
-
type: 'openai',
|
|
304
|
-
model: 'gpt-4o-mini', // or 'gpt-4o', 'gpt-4-turbo'
|
|
305
|
-
temperature: 0.3,
|
|
306
|
-
apiKey: process.env.OPENAI_API_KEY
|
|
307
|
-
}
|
|
233
|
+
# Run translation sync
|
|
234
|
+
npx translatronx sync
|
|
308
235
|
```
|
|
309
236
|
|
|
310
|
-
**
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
apiKey: process.env.ANTHROPIC_API_KEY
|
|
318
|
-
}
|
|
319
|
-
```
|
|
237
|
+
**What happens:**
|
|
238
|
+
1. translatronx reads your source file (`en.json`)
|
|
239
|
+
2. Extracts all translatable strings
|
|
240
|
+
3. Batches them efficiently for the LLM
|
|
241
|
+
4. Generates translations for all target languages
|
|
242
|
+
5. Writes output files (`fr.json`, `de.json`, `es.json`)
|
|
243
|
+
6. Stores state in `.translatronx/ledger.sqlite`
|
|
320
244
|
|
|
321
|
-
|
|
322
|
-
```typescript
|
|
323
|
-
{
|
|
324
|
-
name: 'groq',
|
|
325
|
-
type: 'groq',
|
|
326
|
-
model: 'llama-3.3-70b-versatile',
|
|
327
|
-
temperature: 0.3,
|
|
328
|
-
apiKey: process.env.GROQ_API_KEY
|
|
329
|
-
}
|
|
330
|
-
```
|
|
245
|
+
#### Step 1.5: Check Translation Status
|
|
331
246
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
{
|
|
335
|
-
name: 'azure',
|
|
336
|
-
type: 'azure-openai',
|
|
337
|
-
model: 'gpt-4o',
|
|
338
|
-
baseUrl: 'https://your-resource.openai.azure.com',
|
|
339
|
-
apiKey: process.env.AZURE_OPENAI_KEY
|
|
340
|
-
}
|
|
247
|
+
```bash
|
|
248
|
+
npx translatronx status
|
|
341
249
|
```
|
|
342
250
|
|
|
343
|
-
**
|
|
344
|
-
```typescript
|
|
345
|
-
{
|
|
346
|
-
name: 'openrouter',
|
|
347
|
-
type: 'openrouter',
|
|
348
|
-
model: 'anthropic/claude-3.5-sonnet',
|
|
349
|
-
apiKey: process.env.OPENROUTER_API_KEY
|
|
350
|
-
}
|
|
251
|
+
**Output:**
|
|
351
252
|
```
|
|
253
|
+
📊 Translation Coverage Report
|
|
352
254
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
}
|
|
255
|
+
┌─────────────┬────────┬───────────┬──────────┬──────────┐
|
|
256
|
+
│ Language │ Total │ Clean │ Dirty │ Coverage │
|
|
257
|
+
├─────────────┼────────┼───────────┼──────────┼──────────┤
|
|
258
|
+
│ French (fr) │ 12 │ 12 │ 0 │ 100.0% │
|
|
259
|
+
│ German (de) │ 12 │ 12 │ 0 │ 100.0% │
|
|
260
|
+
│ Spanish (es)│ 12 │ 12 │ 0 │ 100.0% │
|
|
261
|
+
└─────────────┴────────┴───────────┴──────────┴──────────┘
|
|
361
262
|
```
|
|
362
263
|
|
|
363
|
-
####
|
|
264
|
+
#### Step 1.6: Update Source and Re-sync
|
|
364
265
|
|
|
365
|
-
|
|
366
|
-
- `{shortCode}` - Language short code (e.g., "fr")
|
|
367
|
-
- `{language}` - Full language name (e.g., "French")
|
|
266
|
+
Add a new string to `en.json`:
|
|
368
267
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
268
|
+
```json
|
|
269
|
+
{
|
|
270
|
+
"app": {
|
|
271
|
+
"title": "My Awesome App",
|
|
272
|
+
"description": "The best app you'll ever use",
|
|
273
|
+
"tagline": "Built with love ❤️" // NEW!
|
|
274
|
+
},
|
|
275
|
+
// ... rest of the file
|
|
276
|
+
}
|
|
277
|
+
```
|
|
373
278
|
|
|
374
|
-
|
|
279
|
+
Run sync again:
|
|
375
280
|
|
|
376
|
-
|
|
281
|
+
```bash
|
|
282
|
+
npx translatronx sync
|
|
283
|
+
```
|
|
377
284
|
|
|
378
|
-
|
|
285
|
+
**Output:**
|
|
286
|
+
```
|
|
287
|
+
✅ Translation sync complete!
|
|
379
288
|
|
|
380
|
-
|
|
381
|
-
|
|
289
|
+
Statistics:
|
|
290
|
+
Total strings: 13
|
|
291
|
+
Translated: 3 ← Only the new string!
|
|
292
|
+
Failed: 0
|
|
293
|
+
Skipped: 10 ← Existing translations skipped
|
|
382
294
|
```
|
|
383
295
|
|
|
384
|
-
|
|
296
|
+
**This is the power of incremental translation!** Only new/changed strings are translated, saving you time and money.
|
|
385
297
|
|
|
386
298
|
---
|
|
387
299
|
|
|
388
|
-
###
|
|
300
|
+
### 2. Using Context Files for Better Translations
|
|
389
301
|
|
|
390
|
-
|
|
302
|
+
Context files allow you to provide additional information to the LLM about each translation key, resulting in more accurate and contextually appropriate translations.
|
|
303
|
+
|
|
304
|
+
#### Step 2.1: Generate a Context File Template
|
|
391
305
|
|
|
392
306
|
```bash
|
|
393
|
-
translatronx
|
|
307
|
+
npx translatronx context generate --source ./locales/en.json
|
|
394
308
|
```
|
|
395
309
|
|
|
396
|
-
**
|
|
397
|
-
|
|
398
|
-
|
|
310
|
+
**Output:**
|
|
311
|
+
```
|
|
312
|
+
📝 Generating context file template...
|
|
399
313
|
|
|
400
|
-
|
|
314
|
+
Source: /path/to/locales/en.json
|
|
315
|
+
Output: /path/to/locales/en.context.json
|
|
316
|
+
Merge: No
|
|
401
317
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
318
|
+
✅ Context file generated successfully!
|
|
319
|
+
|
|
320
|
+
💡 Tip: Edit locales/en.context.json to add context for each translation key
|
|
321
|
+
```
|
|
405
322
|
|
|
406
|
-
|
|
407
|
-
translatronx sync --force
|
|
323
|
+
This creates `./locales/en.context.json`:
|
|
408
324
|
|
|
409
|
-
|
|
410
|
-
|
|
325
|
+
```json
|
|
326
|
+
{
|
|
327
|
+
"app": {
|
|
328
|
+
"title": {
|
|
329
|
+
"value": "My Awesome App",
|
|
330
|
+
"context": ""
|
|
331
|
+
},
|
|
332
|
+
"description": {
|
|
333
|
+
"value": "The best app you'll ever use",
|
|
334
|
+
"context": ""
|
|
335
|
+
},
|
|
336
|
+
"tagline": {
|
|
337
|
+
"value": "Built with love ❤️",
|
|
338
|
+
"context": ""
|
|
339
|
+
}
|
|
340
|
+
},
|
|
341
|
+
"navigation": {
|
|
342
|
+
"home": {
|
|
343
|
+
"value": "Home",
|
|
344
|
+
"context": ""
|
|
345
|
+
},
|
|
346
|
+
// ... etc
|
|
347
|
+
}
|
|
348
|
+
}
|
|
411
349
|
```
|
|
412
350
|
|
|
413
|
-
|
|
414
|
-
1. Extracts source strings from configured files
|
|
415
|
-
2. Computes hashes and detects changes
|
|
416
|
-
3. Identifies new/modified strings needing translation
|
|
417
|
-
4. Deduplicates identical strings across keys
|
|
418
|
-
5. Batches strings for efficient LLM calls
|
|
419
|
-
6. Translates using configured provider(s)
|
|
420
|
-
7. Validates translations (placeholders, length, etc.)
|
|
421
|
-
8. Atomically writes to target files
|
|
422
|
-
9. Updates ledger with new state
|
|
351
|
+
#### Step 2.2: Add Context to Your Keys
|
|
423
352
|
|
|
424
|
-
|
|
353
|
+
Edit `en.context.json` to add helpful context:
|
|
425
354
|
|
|
426
|
-
|
|
355
|
+
```json
|
|
356
|
+
{
|
|
357
|
+
"app": {
|
|
358
|
+
"title": {
|
|
359
|
+
"value": "My Awesome App",
|
|
360
|
+
"context": "Main application title shown in the header and browser tab"
|
|
361
|
+
},
|
|
362
|
+
"description": {
|
|
363
|
+
"value": "The best app you'll ever use",
|
|
364
|
+
"context": "Marketing tagline shown on the landing page. Should be enthusiastic and engaging."
|
|
365
|
+
},
|
|
366
|
+
"tagline": {
|
|
367
|
+
"value": "Built with love ❤️",
|
|
368
|
+
"context": "Footer tagline. Keep the heart emoji in all translations."
|
|
369
|
+
}
|
|
370
|
+
},
|
|
371
|
+
"auth": {
|
|
372
|
+
"login": {
|
|
373
|
+
"value": "Log in",
|
|
374
|
+
"context": "Button text for user authentication. Should be concise and action-oriented."
|
|
375
|
+
},
|
|
376
|
+
"logout": {
|
|
377
|
+
"value": "Log out",
|
|
378
|
+
"context": "Button text for ending user session."
|
|
379
|
+
},
|
|
380
|
+
"forgotPassword": {
|
|
381
|
+
"value": "Forgot Password?",
|
|
382
|
+
"context": "Link text for password recovery. Should be phrased as a question."
|
|
383
|
+
}
|
|
384
|
+
},
|
|
385
|
+
"messages": {
|
|
386
|
+
"welcome": {
|
|
387
|
+
"value": "Welcome, {username}!",
|
|
388
|
+
"context": "Greeting shown when user logs in. {username} is the user's display name."
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
```
|
|
427
393
|
|
|
428
|
-
|
|
394
|
+
#### Step 2.3: Validate Your Context File
|
|
429
395
|
|
|
430
396
|
```bash
|
|
431
|
-
translatronx
|
|
397
|
+
npx translatronx context validate
|
|
432
398
|
```
|
|
433
399
|
|
|
434
400
|
**Output:**
|
|
435
401
|
```
|
|
436
|
-
|
|
402
|
+
🔍 Validating context file...
|
|
437
403
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
Manual overrides: 3
|
|
404
|
+
Source: /path/to/locales/en.json
|
|
405
|
+
Context: /path/to/locales/en.context.json
|
|
441
406
|
|
|
442
|
-
|
|
443
|
-
French (fr):
|
|
444
|
-
✓ Translated: 127
|
|
445
|
-
✗ Failed: 0
|
|
446
|
-
Coverage: 100%
|
|
447
|
-
|
|
448
|
-
German (de):
|
|
449
|
-
✓ Translated: 124
|
|
450
|
-
✗ Failed: 3
|
|
451
|
-
Coverage: 98%
|
|
452
|
-
|
|
453
|
-
Latest Run:
|
|
454
|
-
Run ID: run_2026-01-29T06-30-00
|
|
455
|
-
Model: gpt-4o-mini
|
|
456
|
-
Cost: $0.0142
|
|
457
|
-
Duration: Completed
|
|
407
|
+
✅ Context file is valid!
|
|
458
408
|
```
|
|
459
409
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
### `translatronx retry`
|
|
410
|
+
#### Step 2.4: Enable Context in Configuration
|
|
463
411
|
|
|
464
|
-
|
|
412
|
+
Update `translatronx.config.ts`:
|
|
465
413
|
|
|
466
|
-
```
|
|
467
|
-
|
|
414
|
+
```typescript
|
|
415
|
+
export default defineConfig({
|
|
416
|
+
// ... other config
|
|
417
|
+
extractors: [
|
|
418
|
+
{
|
|
419
|
+
type: 'json',
|
|
420
|
+
pattern: './locales/en.json',
|
|
421
|
+
contextFile: {
|
|
422
|
+
enabled: true,
|
|
423
|
+
pattern: './locales/en.context.json',
|
|
424
|
+
autoGenerate: false,
|
|
425
|
+
autoUpdate: false
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
],
|
|
429
|
+
// ... rest of config
|
|
430
|
+
});
|
|
468
431
|
```
|
|
469
432
|
|
|
470
|
-
|
|
471
|
-
- `--batch <id>` - Specific batch ID to retry
|
|
472
|
-
- `--lang <code>` - Specific language to retry (comma-separated)
|
|
473
|
-
- `--dry-run` - Show what would be retried without making changes
|
|
433
|
+
#### Step 2.5: Re-translate with Context
|
|
474
434
|
|
|
475
|
-
|
|
435
|
+
To see the improvement, let's force a retranslation:
|
|
476
436
|
|
|
477
437
|
```bash
|
|
478
|
-
#
|
|
479
|
-
|
|
438
|
+
# Delete existing translations
|
|
439
|
+
rm ./locales/fr.json ./locales/de.json ./locales/es.json
|
|
480
440
|
|
|
481
|
-
#
|
|
482
|
-
|
|
441
|
+
# Clear the ledger to force retranslation
|
|
442
|
+
rm -rf .translatronx
|
|
483
443
|
|
|
484
|
-
#
|
|
485
|
-
translatronx
|
|
486
|
-
|
|
487
|
-
# Dry run to see what would be retried
|
|
488
|
-
translatronx retry --dry-run
|
|
444
|
+
# Run sync with context
|
|
445
|
+
npx translatronx sync
|
|
489
446
|
```
|
|
490
447
|
|
|
491
|
-
|
|
448
|
+
**The LLM now receives context for each string, resulting in better translations!**
|
|
492
449
|
|
|
493
|
-
|
|
450
|
+
For example, without context:
|
|
451
|
+
- "Log in" might be translated as "Connexion" (noun) in French
|
|
494
452
|
|
|
495
|
-
|
|
453
|
+
With context ("Button text for user authentication"):
|
|
454
|
+
- "Log in" is translated as "Se connecter" (verb/action) in French
|
|
496
455
|
|
|
497
|
-
|
|
498
|
-
translatronx check
|
|
499
|
-
```
|
|
456
|
+
---
|
|
500
457
|
|
|
501
|
-
|
|
502
|
-
- Placeholder preservation
|
|
503
|
-
- JSON structure integrity
|
|
504
|
-
- Length ratios
|
|
505
|
-
- Source text leakage
|
|
458
|
+
### 3. Managing Existing Translations
|
|
506
459
|
|
|
507
|
-
|
|
460
|
+
If you already have translations and want to add context files without affecting them:
|
|
508
461
|
|
|
509
|
-
|
|
462
|
+
#### Step 3.1: Import Context from Source
|
|
510
463
|
|
|
511
|
-
|
|
464
|
+
```bash
|
|
465
|
+
npx translatronx context import --source ./locales/en.json
|
|
466
|
+
```
|
|
512
467
|
|
|
513
|
-
|
|
468
|
+
**Output:**
|
|
469
|
+
```
|
|
470
|
+
📥 Importing context from source...
|
|
514
471
|
|
|
515
|
-
|
|
472
|
+
Source: /path/to/locales/en.json
|
|
473
|
+
Output: /path/to/locales/en.context.json
|
|
474
|
+
Merge: Yes
|
|
516
475
|
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
}
|
|
523
|
-
```
|
|
476
|
+
✅ Context imported from source successfully!
|
|
477
|
+
• Existing context preserved
|
|
478
|
+
• New keys from source added
|
|
479
|
+
• Source values updated to match current source
|
|
480
|
+
• Your existing translations are safe
|
|
524
481
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
{
|
|
529
|
-
"welcome": "Bienvenue sur notre plateforme !"
|
|
530
|
-
}
|
|
531
|
-
```
|
|
482
|
+
💡 Tip: Your existing translations will NOT be affected.
|
|
483
|
+
Context files only improve future translations.
|
|
484
|
+
```
|
|
532
485
|
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
486
|
+
**Key Points:**
|
|
487
|
+
- ✅ Your existing translation files (`fr.json`, `de.json`, etc.) are **never touched**
|
|
488
|
+
- ✅ Existing context you've written is **preserved**
|
|
489
|
+
- ✅ New keys from source are **added** with empty context
|
|
490
|
+
- ✅ Only **future translations** will benefit from context
|
|
537
491
|
|
|
538
|
-
|
|
539
|
-
```bash
|
|
540
|
-
translatronx sync --force
|
|
541
|
-
```
|
|
492
|
+
#### Step 3.2: Sync Context When Source Changes
|
|
542
493
|
|
|
543
|
-
|
|
494
|
+
When you add/remove keys in your source file:
|
|
544
495
|
|
|
545
|
-
|
|
496
|
+
```bash
|
|
497
|
+
npx translatronx context sync
|
|
498
|
+
```
|
|
546
499
|
|
|
547
|
-
|
|
548
|
-
providers: [
|
|
549
|
-
{
|
|
550
|
-
name: 'primary',
|
|
551
|
-
type: 'openai',
|
|
552
|
-
model: 'gpt-4o-mini',
|
|
553
|
-
fallback: 'backup'
|
|
554
|
-
},
|
|
555
|
-
{
|
|
556
|
-
name: 'backup',
|
|
557
|
-
type: 'anthropic',
|
|
558
|
-
model: 'claude-3-5-sonnet-20241022',
|
|
559
|
-
fallback: 'local'
|
|
560
|
-
},
|
|
561
|
-
{
|
|
562
|
-
name: 'local',
|
|
563
|
-
type: 'local',
|
|
564
|
-
model: 'llama3',
|
|
565
|
-
baseUrl: 'http://localhost:11434'
|
|
566
|
-
}
|
|
567
|
-
]
|
|
500
|
+
**Output:**
|
|
568
501
|
```
|
|
502
|
+
🔄 Syncing context file with source...
|
|
569
503
|
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
- Network errors
|
|
573
|
-
- Validation failures after max retries
|
|
504
|
+
Source: /path/to/locales/en.json
|
|
505
|
+
Context: /path/to/locales/en.context.json
|
|
574
506
|
|
|
575
|
-
|
|
507
|
+
✅ Context file synced successfully!
|
|
508
|
+
• New keys added
|
|
509
|
+
• Deleted keys removed
|
|
510
|
+
• Existing context preserved
|
|
511
|
+
```
|
|
576
512
|
|
|
577
|
-
|
|
513
|
+
---
|
|
578
514
|
|
|
579
|
-
|
|
580
|
-
prompts: {
|
|
581
|
-
// Context about your application
|
|
582
|
-
customContext: `
|
|
583
|
-
This is a healthcare application for patients and doctors.
|
|
584
|
-
Use medical terminology appropriately.
|
|
585
|
-
Maintain HIPAA-compliant language.
|
|
586
|
-
`,
|
|
587
|
-
|
|
588
|
-
// Tone and style
|
|
589
|
-
formatting: 'formal',
|
|
590
|
-
|
|
591
|
-
// Glossary for consistent terminology
|
|
592
|
-
glossary: {
|
|
593
|
-
'Appointment': 'Rendez-vous',
|
|
594
|
-
'Medical Record': 'Dossier médical',
|
|
595
|
-
'Prescription': 'Ordonnance'
|
|
596
|
-
},
|
|
515
|
+
### 4. Customizing Prompts
|
|
597
516
|
|
|
598
|
-
|
|
599
|
-
brandVoice: 'Compassionate, professional, and clear',
|
|
517
|
+
Improve translation quality by customizing the prompts sent to the LLM.
|
|
600
518
|
|
|
601
|
-
|
|
602
|
-
userPrompt: [
|
|
603
|
-
'Translate the following medical app strings.',
|
|
604
|
-
'Ensure all medical terms are accurate.',
|
|
605
|
-
'Use patient-friendly language where appropriate.'
|
|
606
|
-
]
|
|
607
|
-
}
|
|
608
|
-
```
|
|
519
|
+
#### Step 4.1: Add Custom Context
|
|
609
520
|
|
|
610
|
-
|
|
521
|
+
```typescript
|
|
522
|
+
export default defineConfig({
|
|
523
|
+
// ... other config
|
|
524
|
+
prompts: {
|
|
525
|
+
customContext: 'This is a mobile banking app. Use financial terminology and maintain a professional tone.',
|
|
526
|
+
}
|
|
527
|
+
});
|
|
528
|
+
```
|
|
611
529
|
|
|
612
|
-
|
|
530
|
+
#### Step 4.2: Add Glossary
|
|
613
531
|
|
|
614
532
|
```typescript
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
533
|
+
export default defineConfig({
|
|
534
|
+
// ... other config
|
|
535
|
+
prompts: {
|
|
536
|
+
glossary: {
|
|
537
|
+
'Dashboard': 'Tableau de bord',
|
|
538
|
+
'Account': 'Compte',
|
|
539
|
+
'Transaction': 'Transaction',
|
|
540
|
+
'Balance': 'Solde'
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
});
|
|
620
544
|
```
|
|
621
545
|
|
|
622
|
-
|
|
546
|
+
#### Step 4.3: Set Formatting Style
|
|
547
|
+
|
|
548
|
+
```typescript
|
|
549
|
+
export default defineConfig({
|
|
550
|
+
// ... other config
|
|
551
|
+
prompts: {
|
|
552
|
+
formatting: 'formal', // 'formal' | 'casual' | 'technical'
|
|
553
|
+
brandVoice: 'Professional, trustworthy, and user-friendly'
|
|
554
|
+
}
|
|
555
|
+
});
|
|
623
556
|
```
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
557
|
+
|
|
558
|
+
#### Step 4.4: Custom User Prompt
|
|
559
|
+
|
|
560
|
+
```typescript
|
|
561
|
+
export default defineConfig({
|
|
562
|
+
// ... other config
|
|
563
|
+
prompts: {
|
|
564
|
+
userPrompt: [
|
|
565
|
+
'Translate the following strings for a mobile banking application.',
|
|
566
|
+
'Maintain consistency with previous translations.',
|
|
567
|
+
'Use formal language and financial terminology.',
|
|
568
|
+
'Preserve all placeholders like {username} exactly as they appear.'
|
|
569
|
+
]
|
|
570
|
+
}
|
|
571
|
+
});
|
|
629
572
|
```
|
|
630
573
|
|
|
631
|
-
|
|
574
|
+
---
|
|
575
|
+
|
|
576
|
+
### 5. CI/CD Integration
|
|
632
577
|
|
|
633
|
-
#### GitHub Actions
|
|
578
|
+
#### Step 5.1: GitHub Actions
|
|
579
|
+
|
|
580
|
+
Create `.github/workflows/translations.yml`:
|
|
634
581
|
|
|
635
582
|
```yaml
|
|
636
|
-
name:
|
|
583
|
+
name: Update Translations
|
|
637
584
|
|
|
638
585
|
on:
|
|
639
586
|
push:
|
|
640
|
-
branches: [main]
|
|
641
587
|
paths:
|
|
642
588
|
- 'locales/en.json'
|
|
589
|
+
- 'locales/en.context.json'
|
|
590
|
+
branches:
|
|
591
|
+
- main
|
|
643
592
|
|
|
644
593
|
jobs:
|
|
645
594
|
translate:
|
|
@@ -650,449 +599,654 @@ jobs:
|
|
|
650
599
|
- name: Setup Node.js
|
|
651
600
|
uses: actions/setup-node@v3
|
|
652
601
|
with:
|
|
653
|
-
node-version: '
|
|
602
|
+
node-version: '20'
|
|
654
603
|
|
|
655
604
|
- name: Install dependencies
|
|
656
605
|
run: npm ci
|
|
657
606
|
|
|
658
|
-
- name:
|
|
607
|
+
- name: Run translations
|
|
659
608
|
env:
|
|
660
609
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
661
610
|
run: npx translatronx sync
|
|
662
611
|
|
|
663
612
|
- name: Commit translations
|
|
664
613
|
run: |
|
|
665
|
-
git config user.
|
|
666
|
-
git config user.
|
|
667
|
-
git add locales
|
|
668
|
-
git commit -m "chore: update translations"
|
|
614
|
+
git config --local user.email "action@github.com"
|
|
615
|
+
git config --local user.name "GitHub Action"
|
|
616
|
+
git add locales/*.json
|
|
617
|
+
git diff --quiet && git diff --staged --quiet || git commit -m "chore: update translations"
|
|
669
618
|
git push
|
|
670
619
|
```
|
|
671
620
|
|
|
672
|
-
#### GitLab CI
|
|
621
|
+
#### Step 5.2: GitLab CI
|
|
622
|
+
|
|
623
|
+
Create `.gitlab-ci.yml`:
|
|
673
624
|
|
|
674
625
|
```yaml
|
|
675
626
|
translate:
|
|
627
|
+
image: node:20
|
|
676
628
|
stage: build
|
|
677
|
-
image: node:18
|
|
678
|
-
script:
|
|
679
|
-
- npm ci
|
|
680
|
-
- npx translatronx sync
|
|
681
|
-
artifacts:
|
|
682
|
-
paths:
|
|
683
|
-
- locales/
|
|
684
629
|
only:
|
|
685
630
|
changes:
|
|
686
631
|
- locales/en.json
|
|
632
|
+
- locales/en.context.json
|
|
633
|
+
script:
|
|
634
|
+
- npm ci
|
|
635
|
+
- npx translatronx sync
|
|
636
|
+
- git config user.email "ci@gitlab.com"
|
|
637
|
+
- git config user.name "GitLab CI"
|
|
638
|
+
- git add locales/*.json
|
|
639
|
+
- git diff --quiet && git diff --staged --quiet || (git commit -m "chore: update translations" && git push)
|
|
640
|
+
variables:
|
|
641
|
+
OPENAI_API_KEY: $OPENAI_API_KEY
|
|
687
642
|
```
|
|
688
643
|
|
|
689
|
-
|
|
644
|
+
---
|
|
645
|
+
|
|
646
|
+
## ⚙️ Configuration Reference
|
|
690
647
|
|
|
691
|
-
|
|
648
|
+
### Complete Configuration Example
|
|
692
649
|
|
|
693
650
|
```typescript
|
|
694
|
-
import {
|
|
651
|
+
import { defineConfig } from 'translatronx';
|
|
695
652
|
|
|
696
|
-
|
|
697
|
-
//
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
// Create compiler instance
|
|
701
|
-
const compiler = new TranslationCompiler(config);
|
|
702
|
-
|
|
703
|
-
// Run sync
|
|
704
|
-
const stats = await compiler.sync({ verbose: true });
|
|
705
|
-
|
|
706
|
-
console.log(`Translated ${stats.translatedUnits} strings`);
|
|
707
|
-
console.log(`Cost: $${stats.costEstimateUsd.toFixed(4)}`);
|
|
708
|
-
|
|
709
|
-
// Close ledger connection
|
|
710
|
-
compiler.close();
|
|
711
|
-
}
|
|
653
|
+
export default defineConfig({
|
|
654
|
+
// Source language code (ISO 639-1)
|
|
655
|
+
sourceLanguage: 'en',
|
|
712
656
|
|
|
713
|
-
|
|
714
|
-
|
|
657
|
+
// Target languages with full names and short codes
|
|
658
|
+
targetLanguages: [
|
|
659
|
+
{ language: 'French', shortCode: 'fr' },
|
|
660
|
+
{ language: 'German (Formal)', shortCode: 'de-formal' },
|
|
661
|
+
{ language: 'Simplified Chinese', shortCode: 'zh-Hans' }
|
|
662
|
+
],
|
|
663
|
+
|
|
664
|
+
// Extractors define how to find translatable strings
|
|
665
|
+
extractors: [
|
|
666
|
+
{
|
|
667
|
+
type: 'json', // 'json' | 'typescript' | 'custom'
|
|
668
|
+
pattern: './locales/en.json', // Glob pattern(s)
|
|
669
|
+
keyPrefix: 'app', // Optional: prefix for all keys
|
|
670
|
+
exclude: ['**/node_modules/**'], // Optional: exclude patterns
|
|
671
|
+
contextFile: { // Optional: context file configuration
|
|
672
|
+
enabled: true,
|
|
673
|
+
pattern: './locales/en.context.json',
|
|
674
|
+
autoGenerate: false,
|
|
675
|
+
autoUpdate: false
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
],
|
|
715
679
|
|
|
716
|
-
|
|
680
|
+
// LLM providers configuration
|
|
681
|
+
providers: [
|
|
682
|
+
{
|
|
683
|
+
name: 'openai-primary',
|
|
684
|
+
type: 'openai',
|
|
685
|
+
model: 'gpt-4o-mini',
|
|
686
|
+
temperature: 0.3,
|
|
687
|
+
maxRetries: 3,
|
|
688
|
+
apiKey: process.env.OPENAI_API_KEY, // Optional: defaults to env var
|
|
689
|
+
fallback: 'anthropic-backup' // Optional: fallback provider
|
|
690
|
+
},
|
|
691
|
+
{
|
|
692
|
+
name: 'anthropic-backup',
|
|
693
|
+
type: 'anthropic',
|
|
694
|
+
model: 'claude-3-5-sonnet-20241022',
|
|
695
|
+
temperature: 0.3,
|
|
696
|
+
maxRetries: 2
|
|
697
|
+
}
|
|
698
|
+
],
|
|
717
699
|
|
|
718
|
-
|
|
700
|
+
// Validation rules
|
|
701
|
+
validation: {
|
|
702
|
+
preservePlaceholders: true, // Ensure {var} placeholders are preserved
|
|
703
|
+
maxLengthRatio: 3, // Max target/source length ratio
|
|
704
|
+
preventSourceLeakage: true, // Prevent untranslated source text
|
|
705
|
+
brandNames: ['Acme', 'Widget'], // Protected brand names
|
|
706
|
+
customRules: [] // Custom validation functions
|
|
707
|
+
},
|
|
719
708
|
|
|
720
|
-
|
|
709
|
+
// Output configuration
|
|
710
|
+
output: {
|
|
711
|
+
dir: './locales',
|
|
712
|
+
format: 'json', // 'json' | 'yaml' | 'typescript'
|
|
713
|
+
flat: false, // Flatten nested objects
|
|
714
|
+
indent: 2, // JSON indentation
|
|
715
|
+
fileNaming: '{shortCode}.json', // File naming pattern
|
|
716
|
+
allowSameFolder: false // Allow source & target in same dir
|
|
717
|
+
},
|
|
721
718
|
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
719
|
+
// Prompt customization
|
|
720
|
+
prompts: {
|
|
721
|
+
customContext: 'This is a mobile banking app. Use financial terminology.',
|
|
722
|
+
formatting: 'formal', // 'formal' | 'casual' | 'technical'
|
|
723
|
+
glossary: {
|
|
724
|
+
'Dashboard': 'Tableau de bord',
|
|
725
|
+
'Settings': 'Paramètres'
|
|
726
|
+
},
|
|
727
|
+
brandVoice: 'Professional, trustworthy, and user-friendly',
|
|
728
|
+
userPrompt: [ // Custom user prompt (optional)
|
|
729
|
+
'Translate the following strings for a mobile app.',
|
|
730
|
+
'Maintain consistency with previous translations.'
|
|
731
|
+
]
|
|
732
|
+
},
|
|
728
733
|
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
734
|
+
// Advanced settings
|
|
735
|
+
advanced: {
|
|
736
|
+
batchSize: 20, // Strings per LLM call
|
|
737
|
+
concurrency: 3, // Parallel LLM requests
|
|
738
|
+
cacheDir: './.translatronx', // State directory
|
|
739
|
+
ledgerPath: './.translatronx/ledger.sqlite',
|
|
740
|
+
verbose: false // Enable verbose logging
|
|
741
|
+
}
|
|
742
|
+
});
|
|
736
743
|
```
|
|
737
744
|
|
|
738
|
-
|
|
745
|
+
### Configuration Options
|
|
746
|
+
|
|
747
|
+
#### `sourceLanguage`
|
|
748
|
+
- **Type:** `string`
|
|
749
|
+
- **Required:** Yes
|
|
750
|
+
- **Description:** ISO 639-1 language code for source language
|
|
751
|
+
|
|
752
|
+
#### `targetLanguages`
|
|
753
|
+
- **Type:** `Array<{ language: string, shortCode: string }>`
|
|
754
|
+
- **Required:** Yes
|
|
755
|
+
- **Description:** Array of target languages with full names and codes
|
|
756
|
+
|
|
757
|
+
#### `extractors`
|
|
758
|
+
- **Type:** `Array<ExtractorConfig>`
|
|
759
|
+
- **Required:** Yes
|
|
760
|
+
- **Description:** Configuration for extracting translatable strings
|
|
761
|
+
|
|
762
|
+
##### Extractor Context File Options
|
|
763
|
+
- `enabled`: Enable context file support
|
|
764
|
+
- `pattern`: Path to context file (defaults to `{source}.context.json`)
|
|
765
|
+
- `autoGenerate`: Auto-generate context file if missing
|
|
766
|
+
- `autoUpdate`: Auto-update context file when source changes
|
|
767
|
+
|
|
768
|
+
#### `providers`
|
|
769
|
+
- **Type:** `Array<ProviderConfig>`
|
|
770
|
+
- **Required:** Yes
|
|
771
|
+
- **Description:** LLM provider configuration
|
|
772
|
+
|
|
773
|
+
Supported providers:
|
|
774
|
+
- `openai` - OpenAI (GPT-4, GPT-3.5, etc.)
|
|
775
|
+
- `anthropic` - Anthropic (Claude)
|
|
776
|
+
- `groq` - Groq
|
|
777
|
+
- `azure-openai` - Azure OpenAI
|
|
778
|
+
- `openrouter` - OpenRouter
|
|
779
|
+
|
|
780
|
+
#### `validation`
|
|
781
|
+
- **Type:** `ValidationConfig`
|
|
782
|
+
- **Required:** No
|
|
783
|
+
- **Description:** Translation validation rules
|
|
784
|
+
|
|
785
|
+
#### `output`
|
|
786
|
+
- **Type:** `OutputConfig`
|
|
787
|
+
- **Required:** Yes
|
|
788
|
+
- **Description:** Output file configuration
|
|
789
|
+
|
|
790
|
+
#### `prompts`
|
|
791
|
+
- **Type:** `PromptConfig`
|
|
792
|
+
- **Required:** No
|
|
793
|
+
- **Description:** Prompt customization options
|
|
794
|
+
|
|
795
|
+
#### `advanced`
|
|
796
|
+
- **Type:** `AdvancedConfig`
|
|
797
|
+
- **Required:** No
|
|
798
|
+
- **Description:** Advanced performance and behavior settings
|
|
739
799
|
|
|
740
|
-
|
|
800
|
+
---
|
|
741
801
|
|
|
742
|
-
|
|
802
|
+
## 🖥️ CLI Commands
|
|
743
803
|
|
|
744
|
-
|
|
804
|
+
### `translatronx sync`
|
|
745
805
|
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
806
|
+
Synchronize translations (incremental processing).
|
|
807
|
+
|
|
808
|
+
```bash
|
|
809
|
+
npx translatronx sync [options]
|
|
810
|
+
```
|
|
811
|
+
|
|
812
|
+
**Options:**
|
|
813
|
+
- `-f, --force` - Force regeneration of manual overrides
|
|
814
|
+
- `-v, --verbose` - Enable verbose output
|
|
815
|
+
|
|
816
|
+
**Example:**
|
|
817
|
+
```bash
|
|
818
|
+
npx translatronx sync --verbose
|
|
755
819
|
```
|
|
756
820
|
|
|
757
|
-
|
|
758
|
-
- `auth.login.title`
|
|
759
|
-
- `auth.login.button`
|
|
821
|
+
---
|
|
760
822
|
|
|
761
|
-
|
|
823
|
+
### `translatronx status`
|
|
762
824
|
|
|
763
|
-
|
|
825
|
+
Display coverage statistics and system state.
|
|
764
826
|
|
|
765
|
-
|
|
827
|
+
```bash
|
|
828
|
+
npx translatronx status
|
|
829
|
+
```
|
|
766
830
|
|
|
767
|
-
**
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
- Leading/trailing whitespace is preserved if intentional
|
|
831
|
+
**Output:**
|
|
832
|
+
```
|
|
833
|
+
📊 Translation Coverage Report
|
|
771
834
|
|
|
772
|
-
|
|
835
|
+
┌─────────────┬────────┬───────────┬──────────┬──────────┐
|
|
836
|
+
│ Language │ Total │ Clean │ Dirty │ Coverage │
|
|
837
|
+
├─────────────┼────────┼───────────┼──────────┼──────────┤
|
|
838
|
+
│ French (fr) │ 12 │ 12 │ 0 │ 100.0% │
|
|
839
|
+
│ German (de) │ 12 │ 11 │ 1 │ 91.7% │
|
|
840
|
+
└─────────────┴────────┴───────────┴──────────┴──────────┘
|
|
841
|
+
```
|
|
773
842
|
|
|
774
|
-
|
|
843
|
+
---
|
|
775
844
|
|
|
776
|
-
|
|
777
|
-
- Automatic chunking for strings > 1000 characters
|
|
778
|
-
- Configurable `maxLengthRatio` validation
|
|
779
|
-
- Warning if target exceeds `source length × maxLengthRatio`
|
|
845
|
+
### `translatronx retry`
|
|
780
846
|
|
|
781
|
-
|
|
847
|
+
Retry failed translation batches.
|
|
782
848
|
|
|
783
|
-
|
|
849
|
+
```bash
|
|
850
|
+
npx translatronx retry [options]
|
|
851
|
+
```
|
|
784
852
|
|
|
785
|
-
**
|
|
786
|
-
-
|
|
787
|
-
-
|
|
788
|
-
-
|
|
789
|
-
- HTML entities preserved
|
|
853
|
+
**Options:**
|
|
854
|
+
- `--batch <id>` - Specific batch ID to retry
|
|
855
|
+
- `--lang <code>` - Specific language to retry
|
|
856
|
+
- `--dry-run` - Show what would be retried without making changes
|
|
790
857
|
|
|
791
|
-
|
|
858
|
+
**Example:**
|
|
859
|
+
```bash
|
|
860
|
+
npx translatronx retry --lang fr --dry-run
|
|
861
|
+
```
|
|
792
862
|
|
|
793
|
-
|
|
863
|
+
---
|
|
794
864
|
|
|
795
|
-
|
|
796
|
-
- Atomic file writes (temp file → rename)
|
|
797
|
-
- Transactional ledger updates
|
|
798
|
-
- No partial/corrupted files
|
|
799
|
-
- Safe to re-run sync immediately
|
|
865
|
+
### `translatronx init`
|
|
800
866
|
|
|
801
|
-
|
|
867
|
+
Initialize translatronx configuration.
|
|
802
868
|
|
|
803
|
-
|
|
869
|
+
```bash
|
|
870
|
+
npx translatronx init
|
|
871
|
+
```
|
|
804
872
|
|
|
805
|
-
|
|
806
|
-
- Automatic retry with exponential backoff
|
|
807
|
-
- Fallback to secondary provider
|
|
808
|
-
- Configurable `maxRetries` per provider
|
|
809
|
-
- Batch size adjustment
|
|
873
|
+
Creates a `translatronx.config.ts` file in your project root.
|
|
810
874
|
|
|
811
|
-
|
|
875
|
+
---
|
|
812
876
|
|
|
813
|
-
|
|
877
|
+
### `translatronx context generate`
|
|
814
878
|
|
|
815
|
-
|
|
816
|
-
- Deduplication groups identical strings
|
|
817
|
-
- Single translation reused across all occurrences
|
|
818
|
-
- Glossary ensures terminology consistency
|
|
819
|
-
- Prompt version tracking for reproducibility
|
|
879
|
+
Generate context file template from source file.
|
|
820
880
|
|
|
821
|
-
|
|
881
|
+
```bash
|
|
882
|
+
npx translatronx context generate [options]
|
|
883
|
+
```
|
|
822
884
|
|
|
823
|
-
|
|
885
|
+
**Options:**
|
|
886
|
+
- `--source <path>` - Source file path (overrides config)
|
|
887
|
+
- `--output <path>` - Context file output path
|
|
888
|
+
- `--merge` - Merge with existing context file
|
|
889
|
+
- `--dry-run` - Preview changes without writing
|
|
824
890
|
|
|
891
|
+
**Example:**
|
|
825
892
|
```bash
|
|
826
|
-
|
|
893
|
+
npx translatronx context generate --source ./locales/en.json
|
|
827
894
|
```
|
|
828
895
|
|
|
829
|
-
|
|
896
|
+
---
|
|
897
|
+
|
|
898
|
+
### `translatronx context validate`
|
|
899
|
+
|
|
900
|
+
Validate context file matches source file.
|
|
901
|
+
|
|
830
902
|
```bash
|
|
831
|
-
translatronx
|
|
903
|
+
npx translatronx context validate [options]
|
|
832
904
|
```
|
|
833
905
|
|
|
834
|
-
|
|
906
|
+
**Options:**
|
|
907
|
+
- `--source <path>` - Source file path (overrides config)
|
|
908
|
+
- `--context <path>` - Context file path (overrides config)
|
|
835
909
|
|
|
910
|
+
**Example:**
|
|
836
911
|
```bash
|
|
837
|
-
|
|
912
|
+
npx translatronx context validate
|
|
838
913
|
```
|
|
839
914
|
|
|
840
|
-
|
|
915
|
+
---
|
|
916
|
+
|
|
917
|
+
### `translatronx context sync`
|
|
918
|
+
|
|
919
|
+
Sync context file with source (add new keys, remove deleted keys).
|
|
920
|
+
|
|
841
921
|
```bash
|
|
842
|
-
|
|
922
|
+
npx translatronx context sync [options]
|
|
843
923
|
```
|
|
844
924
|
|
|
845
|
-
|
|
925
|
+
**Options:**
|
|
926
|
+
- `--source <path>` - Source file path (overrides config)
|
|
927
|
+
- `--context <path>` - Context file path (overrides config)
|
|
928
|
+
- `--dry-run` - Preview changes without writing
|
|
846
929
|
|
|
930
|
+
**Example:**
|
|
847
931
|
```bash
|
|
848
|
-
|
|
849
|
-
Source: {name}, Target: {nom}
|
|
932
|
+
npx translatronx context sync --dry-run
|
|
850
933
|
```
|
|
851
934
|
|
|
852
|
-
|
|
935
|
+
---
|
|
853
936
|
|
|
854
|
-
|
|
937
|
+
### `translatronx context import`
|
|
938
|
+
|
|
939
|
+
Import/generate context file from source JSON (preserves existing translations).
|
|
855
940
|
|
|
856
941
|
```bash
|
|
857
|
-
|
|
942
|
+
npx translatronx context import [options]
|
|
858
943
|
```
|
|
859
944
|
|
|
860
|
-
**
|
|
945
|
+
**Options:**
|
|
946
|
+
- `--source <path>` - Source JSON file to generate context from
|
|
947
|
+
- `--output <path>` - Output context file path
|
|
948
|
+
- `--merge` - Merge with existing context file (default: true)
|
|
949
|
+
- `--dry-run` - Preview changes without writing
|
|
950
|
+
|
|
951
|
+
**Example:**
|
|
952
|
+
```bash
|
|
953
|
+
npx translatronx context import --source ./locales/en.json
|
|
954
|
+
```
|
|
861
955
|
|
|
862
|
-
|
|
956
|
+
**Use Case:** Perfect for users who already have translations and want to add context files without affecting existing translations.
|
|
863
957
|
|
|
864
|
-
|
|
958
|
+
---
|
|
865
959
|
|
|
866
|
-
|
|
867
|
-
- ✅ `translatronx.config.ts`
|
|
868
|
-
- ✅ All translation files (`*.json`, `*.yaml`)
|
|
869
|
-
- ✅ `.gitignore` entry for `.translatronx/`
|
|
960
|
+
## 📝 Context Files
|
|
870
961
|
|
|
871
|
-
|
|
872
|
-
- ❌ `.translatronx/` directory (state files)
|
|
873
|
-
- ❌ API keys (use environment variables)
|
|
962
|
+
Context files provide additional information to the LLM about each translation key, resulting in more accurate and contextually appropriate translations.
|
|
874
963
|
|
|
875
|
-
|
|
876
|
-
```gitignore
|
|
877
|
-
.translatronx/
|
|
878
|
-
*.sqlite
|
|
879
|
-
*.sqlite-journal
|
|
880
|
-
```
|
|
964
|
+
### Context File Structure
|
|
881
965
|
|
|
882
|
-
|
|
966
|
+
Context files mirror your source file structure:
|
|
883
967
|
|
|
884
|
-
**
|
|
885
|
-
```
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
968
|
+
**Source File (`en.json`):**
|
|
969
|
+
```json
|
|
970
|
+
{
|
|
971
|
+
"greeting": "Hello, {name}!",
|
|
972
|
+
"auth": {
|
|
973
|
+
"login": "Sign in",
|
|
974
|
+
"logout": "Sign out"
|
|
975
|
+
}
|
|
976
|
+
}
|
|
891
977
|
```
|
|
892
978
|
|
|
893
|
-
**
|
|
894
|
-
```
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
979
|
+
**Context File (`en.context.json`):**
|
|
980
|
+
```json
|
|
981
|
+
{
|
|
982
|
+
"greeting": {
|
|
983
|
+
"value": "Hello, {name}!",
|
|
984
|
+
"context": "Greeting shown when user logs in. {name} is the user's display name.",
|
|
985
|
+
"notes": "Keep it friendly and welcoming",
|
|
986
|
+
"maxLength": 50,
|
|
987
|
+
"tone": "casual"
|
|
988
|
+
},
|
|
989
|
+
"auth": {
|
|
990
|
+
"login": {
|
|
991
|
+
"value": "Sign in",
|
|
992
|
+
"context": "Button text for user authentication. Should be concise and action-oriented."
|
|
993
|
+
},
|
|
994
|
+
"logout": {
|
|
995
|
+
"value": "Sign out",
|
|
996
|
+
"context": "Button text for ending user session."
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
}
|
|
902
1000
|
```
|
|
903
1001
|
|
|
904
|
-
###
|
|
1002
|
+
### Context Metadata Fields
|
|
905
1003
|
|
|
906
|
-
|
|
1004
|
+
Each key in a context file can have:
|
|
907
1005
|
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
1006
|
+
- **`value`** (required): The source text (for validation)
|
|
1007
|
+
- **`context`** (optional): Descriptive text for the LLM
|
|
1008
|
+
- **`notes`** (optional): Additional notes
|
|
1009
|
+
- **`maxLength`** (optional): Maximum character length
|
|
1010
|
+
- **`tone`** (optional): Desired tone (e.g., "formal", "casual", "technical")
|
|
1011
|
+
|
|
1012
|
+
### Context File Workflow
|
|
1013
|
+
|
|
1014
|
+
1. **Generate template:**
|
|
1015
|
+
```bash
|
|
1016
|
+
npx translatronx context generate
|
|
1017
|
+
```
|
|
1018
|
+
|
|
1019
|
+
2. **Add context to keys:**
|
|
1020
|
+
Edit the generated `en.context.json` file
|
|
1021
|
+
|
|
1022
|
+
3. **Validate:**
|
|
1023
|
+
```bash
|
|
1024
|
+
npx translatronx context validate
|
|
1025
|
+
```
|
|
1026
|
+
|
|
1027
|
+
4. **Enable in config:**
|
|
1028
|
+
```typescript
|
|
1029
|
+
extractors: [{
|
|
1030
|
+
type: 'json',
|
|
1031
|
+
pattern: './locales/en.json',
|
|
1032
|
+
contextFile: {
|
|
1033
|
+
enabled: true,
|
|
1034
|
+
pattern: './locales/en.context.json'
|
|
1035
|
+
}
|
|
1036
|
+
}]
|
|
1037
|
+
```
|
|
1038
|
+
|
|
1039
|
+
5. **Run sync:**
|
|
1040
|
+
```bash
|
|
1041
|
+
npx translatronx sync
|
|
1042
|
+
```
|
|
1043
|
+
|
|
1044
|
+
### Benefits of Context Files
|
|
1045
|
+
|
|
1046
|
+
- **Better Translation Quality** - LLMs understand the purpose and usage of each string
|
|
1047
|
+
- **Consistency** - Maintain consistent terminology across your app
|
|
1048
|
+
- **Tone Control** - Specify formal vs. casual tone per string
|
|
1049
|
+
- **Length Constraints** - Ensure translations fit UI constraints
|
|
1050
|
+
- **Optional** - Works with or without context files
|
|
1051
|
+
- **Backward Compatible** - No breaking changes to existing workflows
|
|
1052
|
+
|
|
1053
|
+
---
|
|
1054
|
+
|
|
1055
|
+
## 🔧 Advanced Usage
|
|
1056
|
+
|
|
1057
|
+
### Manual Edits Protection
|
|
1058
|
+
|
|
1059
|
+
translatronx automatically detects and protects manual edits:
|
|
1060
|
+
|
|
1061
|
+
1. Translate your strings:
|
|
1062
|
+
```bash
|
|
1063
|
+
npx translatronx sync
|
|
1064
|
+
```
|
|
1065
|
+
|
|
1066
|
+
2. Manually edit a translation in `fr.json`:
|
|
1067
|
+
```json
|
|
1068
|
+
{
|
|
1069
|
+
"welcome": "Bienvenue chez nous!" // Manual edit
|
|
1070
|
+
}
|
|
1071
|
+
```
|
|
1072
|
+
|
|
1073
|
+
3. Run sync again:
|
|
1074
|
+
```bash
|
|
1075
|
+
npx translatronx sync
|
|
1076
|
+
```
|
|
1077
|
+
|
|
1078
|
+
4. Your manual edit is preserved! The ledger marks it as `MANUAL` status.
|
|
1079
|
+
|
|
1080
|
+
To force retranslation of manual edits:
|
|
939
1081
|
```bash
|
|
940
|
-
|
|
941
|
-
translatronx sync --dry-run
|
|
1082
|
+
npx translatronx sync --force
|
|
942
1083
|
```
|
|
943
1084
|
|
|
944
|
-
|
|
1085
|
+
---
|
|
945
1086
|
|
|
946
|
-
|
|
1087
|
+
### Multiple Providers with Fallback
|
|
947
1088
|
|
|
948
1089
|
```typescript
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
1090
|
+
export default defineConfig({
|
|
1091
|
+
providers: [
|
|
1092
|
+
{
|
|
1093
|
+
name: 'primary',
|
|
1094
|
+
type: 'openai',
|
|
1095
|
+
model: 'gpt-4o-mini',
|
|
1096
|
+
fallback: 'backup'
|
|
1097
|
+
},
|
|
1098
|
+
{
|
|
1099
|
+
name: 'backup',
|
|
1100
|
+
type: 'anthropic',
|
|
1101
|
+
model: 'claude-3-5-sonnet-20241022'
|
|
1102
|
+
}
|
|
1103
|
+
]
|
|
1104
|
+
});
|
|
955
1105
|
```
|
|
956
1106
|
|
|
957
|
-
|
|
958
|
-
1. Run `translatronx sync`
|
|
959
|
-
2. Review generated files
|
|
960
|
-
3. Manually edit if needed
|
|
961
|
-
4. Commit changes
|
|
962
|
-
5. Future syncs preserve manual edits
|
|
1107
|
+
If the primary provider fails, translatronx automatically uses the backup.
|
|
963
1108
|
|
|
964
|
-
|
|
1109
|
+
---
|
|
965
1110
|
|
|
966
|
-
|
|
1111
|
+
### Custom Validation Rules
|
|
967
1112
|
|
|
968
1113
|
```typescript
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
1114
|
+
export default defineConfig({
|
|
1115
|
+
validation: {
|
|
1116
|
+
customRules: [
|
|
1117
|
+
(source, target) => {
|
|
1118
|
+
// Ensure translations don't exceed source length by more than 50%
|
|
1119
|
+
if (target.length > source.length * 1.5) {
|
|
1120
|
+
return { isValid: false, error: 'Translation too long' };
|
|
1121
|
+
}
|
|
1122
|
+
return { isValid: true };
|
|
1123
|
+
}
|
|
1124
|
+
]
|
|
980
1125
|
}
|
|
981
|
-
}
|
|
1126
|
+
});
|
|
982
1127
|
```
|
|
983
1128
|
|
|
984
|
-
|
|
1129
|
+
---
|
|
1130
|
+
|
|
1131
|
+
### Importing Existing Translations
|
|
985
1132
|
|
|
986
|
-
|
|
987
|
-
```bash
|
|
988
|
-
translatronx sync --verbose
|
|
989
|
-
```
|
|
1133
|
+
If you have existing translations you want to import:
|
|
990
1134
|
|
|
991
|
-
**Check status regularly:**
|
|
992
1135
|
```bash
|
|
993
|
-
translatronx
|
|
1136
|
+
npx translatronx import --source ./old-translations/fr.json --target fr
|
|
994
1137
|
```
|
|
995
1138
|
|
|
996
|
-
|
|
997
|
-
```bash
|
|
998
|
-
# Ledger stores run history
|
|
999
|
-
sqlite3 .translatronx/ledger.sqlite "SELECT * FROM run_history ORDER BY started_at DESC LIMIT 5;"
|
|
1000
|
-
```
|
|
1139
|
+
This imports your existing translations and marks them as `MANUAL` in the ledger, protecting them from being overwritten.
|
|
1001
1140
|
|
|
1002
|
-
|
|
1141
|
+
---
|
|
1003
1142
|
|
|
1004
|
-
|
|
1143
|
+
## 💡 Best Practices
|
|
1005
1144
|
|
|
1006
|
-
|
|
1145
|
+
### 1. Use Context Files for Important Strings
|
|
1007
1146
|
|
|
1008
|
-
|
|
1009
|
-
|
|
1147
|
+
Add context to strings where:
|
|
1148
|
+
- The meaning is ambiguous (e.g., "Bank" - financial institution or river bank?)
|
|
1149
|
+
- Tone matters (e.g., error messages should be helpful, not scary)
|
|
1150
|
+
- Length constraints exist (e.g., button text must be short)
|
|
1151
|
+
- Cultural nuances matter (e.g., greetings, politeness levels)
|
|
1010
1152
|
|
|
1011
|
-
|
|
1012
|
-
// ... configuration
|
|
1013
|
-
});
|
|
1014
|
-
```
|
|
1153
|
+
### 2. Keep Source Files Clean
|
|
1015
1154
|
|
|
1016
|
-
|
|
1155
|
+
- Use clear, descriptive keys: `auth.loginButton` not `btn1`
|
|
1156
|
+
- Avoid abbreviations in source text
|
|
1157
|
+
- Use consistent placeholder format: `{variable}` not `{{variable}}` or `$variable`
|
|
1017
1158
|
|
|
1018
|
-
|
|
1159
|
+
### 3. Leverage Glossaries
|
|
1019
1160
|
|
|
1020
|
-
|
|
1021
|
-
|
|
1161
|
+
Create a glossary for:
|
|
1162
|
+
- Brand names
|
|
1163
|
+
- Product names
|
|
1164
|
+
- Technical terms
|
|
1165
|
+
- Domain-specific terminology
|
|
1022
1166
|
|
|
1023
|
-
|
|
1024
|
-
```
|
|
1167
|
+
### 4. Run Translations in CI/CD
|
|
1025
1168
|
|
|
1026
|
-
|
|
1169
|
+
Automate translations on source file changes:
|
|
1170
|
+
- Ensures translations are always up-to-date
|
|
1171
|
+
- Catches issues early
|
|
1172
|
+
- Reduces manual work
|
|
1027
1173
|
|
|
1028
|
-
|
|
1174
|
+
### 5. Review Generated Translations
|
|
1029
1175
|
|
|
1030
|
-
|
|
1031
|
-
|
|
1176
|
+
While LLMs are good, they're not perfect:
|
|
1177
|
+
- Review critical strings (legal, security, payments)
|
|
1178
|
+
- Have native speakers spot-check
|
|
1179
|
+
- Use the `status` command to track coverage
|
|
1032
1180
|
|
|
1033
|
-
|
|
1034
|
-
```
|
|
1181
|
+
### 6. Use Incremental Workflow
|
|
1035
1182
|
|
|
1036
|
-
|
|
1183
|
+
Don't retranslate everything:
|
|
1184
|
+
- Let translatronx track changes
|
|
1185
|
+
- Only force retranslation when necessary
|
|
1186
|
+
- Trust the ledger system
|
|
1037
1187
|
|
|
1038
|
-
|
|
1188
|
+
---
|
|
1039
1189
|
|
|
1040
|
-
|
|
1190
|
+
## 📖 API Reference
|
|
1191
|
+
|
|
1192
|
+
### Programmatic Usage
|
|
1041
1193
|
|
|
1042
1194
|
```typescript
|
|
1043
|
-
|
|
1044
|
-
force: false,
|
|
1045
|
-
verbose: false
|
|
1046
|
-
});
|
|
1047
|
-
```
|
|
1195
|
+
import { TranslationCompiler, loadConfig } from 'translatronx';
|
|
1048
1196
|
|
|
1049
|
-
|
|
1197
|
+
async function main() {
|
|
1198
|
+
// Load configuration
|
|
1199
|
+
const config = await loadConfig();
|
|
1050
1200
|
|
|
1051
|
-
|
|
1201
|
+
// Create compiler
|
|
1202
|
+
const compiler = new TranslationCompiler(config);
|
|
1052
1203
|
|
|
1053
|
-
|
|
1054
|
-
const stats = await compiler.
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
});
|
|
1058
|
-
```
|
|
1204
|
+
// Run sync
|
|
1205
|
+
const stats = await compiler.sync({ verbose: true });
|
|
1206
|
+
|
|
1207
|
+
console.log(`Translated ${stats.translatedUnits} strings`);
|
|
1208
|
+
console.log(`Cost: $${stats.costEstimateUsd.toFixed(4)}`);
|
|
1059
1209
|
|
|
1060
|
-
|
|
1210
|
+
// Close compiler
|
|
1211
|
+
compiler.close();
|
|
1212
|
+
}
|
|
1061
1213
|
|
|
1062
|
-
|
|
1214
|
+
main();
|
|
1215
|
+
```
|
|
1216
|
+
|
|
1217
|
+
### Configuration API
|
|
1063
1218
|
|
|
1064
1219
|
```typescript
|
|
1065
|
-
|
|
1220
|
+
import { defineConfig } from 'translatronx';
|
|
1221
|
+
|
|
1222
|
+
export default defineConfig({
|
|
1223
|
+
// Type-safe configuration
|
|
1224
|
+
sourceLanguage: 'en',
|
|
1225
|
+
targetLanguages: [
|
|
1226
|
+
{ language: 'French', shortCode: 'fr' }
|
|
1227
|
+
],
|
|
1228
|
+
// ... rest of config
|
|
1229
|
+
});
|
|
1066
1230
|
```
|
|
1067
1231
|
|
|
1068
|
-
###
|
|
1232
|
+
### Custom Extractors
|
|
1069
1233
|
|
|
1070
1234
|
```typescript
|
|
1071
|
-
|
|
1072
|
-
runId: string;
|
|
1073
|
-
startedAt: Date;
|
|
1074
|
-
finishedAt?: Date;
|
|
1075
|
-
totalUnits: number;
|
|
1076
|
-
translatedUnits: number;
|
|
1077
|
-
failedUnits: number;
|
|
1078
|
-
skippedUnits: number;
|
|
1079
|
-
tokensIn: number;
|
|
1080
|
-
tokensOut: number;
|
|
1081
|
-
costEstimateUsd: number;
|
|
1082
|
-
model: string;
|
|
1083
|
-
}
|
|
1235
|
+
import { type Extractor, type SourceUnit } from 'translatronx';
|
|
1084
1236
|
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1237
|
+
class CustomExtractor implements Extractor {
|
|
1238
|
+
async extract(sourceFiles: string[], config: ExtractorConfig): Promise<SourceUnit[]> {
|
|
1239
|
+
// Your custom extraction logic
|
|
1240
|
+
return [];
|
|
1241
|
+
}
|
|
1090
1242
|
}
|
|
1091
1243
|
```
|
|
1092
1244
|
|
|
1245
|
+
---
|
|
1246
|
+
|
|
1093
1247
|
## 🤝 Contributing
|
|
1094
1248
|
|
|
1095
|
-
|
|
1249
|
+
We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details.
|
|
1096
1250
|
|
|
1097
1251
|
### Development Setup
|
|
1098
1252
|
|
|
@@ -1126,8 +1280,8 @@ MIT © Shanthosh
|
|
|
1126
1280
|
|
|
1127
1281
|
## 📞 Support
|
|
1128
1282
|
|
|
1129
|
-
- **Issues:** [GitHub Issues](https://github.com/msalways/
|
|
1130
|
-
- **Discussions:** [GitHub Discussions](https://github.com/msalways/
|
|
1283
|
+
- **Issues:** [GitHub Issues](https://github.com/msalways/translatron/issues)
|
|
1284
|
+
- **Discussions:** [GitHub Discussions](https://github.com/msalways/translatron/discussions)
|
|
1131
1285
|
- **Email:** shanthubolt@gmail.com
|
|
1132
1286
|
|
|
1133
1287
|
---
|