@concircle/i18n-ai-translator 0.1.2 β†’ 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +165 -353
  2. package/package.json +5 -5
package/README.md CHANGED
@@ -3,33 +3,32 @@
3
3
  <table>
4
4
  <tr>
5
5
  <td width="200" valign="top">
6
- <img src="https://bitbucket.org/concircle/i18n-ai-translator/raw/HEAD/assets/logo.png" alt="Concircle logo" />
6
+ <img src="https://raw.githubusercontent.com/concircle/i18n-ai-translator/main/assets/logo.png" alt="Concircle logo" />
7
7
  </td>
8
8
  <td valign="top">
9
- AI-powered internationalization (i18n) translator for UI5 applications. Automatically translates <code>i18n.properties</code> files to multiple languages using OpenAI, with support for glossaries, placeholder preservation, and intelligent caching.
9
+ Translates UI5 <code>i18n.properties</code> files with OpenAI, preserves placeholders, supports glossary terms, and writes language-specific <code>.properties</code> files.
10
10
  </td>
11
11
  </tr>
12
12
  </table>
13
13
 
14
14
  ## Features
15
15
 
16
- - πŸ€– **AI-Powered Translation**: Uses OpenAI GPT-4 for accurate, context-aware translations
17
- - πŸ”’ **Placeholder Preservation**: Protects UI5 placeholders like `{0}`, `{name}`, `%s`, `${variable}` from being translated
18
- - πŸ“š **Glossary Support**: Define domain-specific vocabulary (e.g., SAP terminology) for consistent translations
19
- - πŸš€ **Batch Processing**: Parallel translation requests for efficiency
20
- - πŸ’Ύ **Smart Caching**: Local file-based cache with TTL and glossary hash invalidation
21
- - πŸ”Œ **Extensible Architecture**: Plugin-ready for future AI providers (Claude, Gemini, etc.)
22
- - πŸ“¦ **Dual Format**: CommonJS and ES Modules support
23
- - βœ… **Fully Tested**: Comprehensive test suite with focus on placeholder preservation
24
- - πŸ“„ **TypeScript**: Full type safety and IntelliSense support
16
+ - Preserves placeholders like `{0}`, `{name}`, `%s`, `${variable}`, and `%1$s`
17
+ - Supports `missing` and `overwrite` translation modes
18
+ - Applies shared and language-specific glossary terms
19
+ - Writes UI5-style language files such as `i18n_de.properties`
20
+ - Supports optional Unicode escaping with per-language overrides
21
+ - Uses a local cache to avoid repeated translation requests
25
22
 
26
23
  ## Installation
27
24
 
28
25
  ```bash
29
- npm install @concircle/i18n-ai-translator
26
+ npm install --save-dev @concircle/i18n-ai-translator
30
27
  ```
31
28
 
32
- Then add a script in the consuming app:
29
+ ## CLI
30
+
31
+ Example `package.json` script:
33
32
 
34
33
  ```json
35
34
  {
@@ -39,7 +38,13 @@ Then add a script in the consuming app:
39
38
  }
40
39
  ```
41
40
 
42
- If your target system expects Java-style Unicode escapes in `.properties` files, enable them with:
41
+ Show CLI help:
42
+
43
+ ```bash
44
+ npx i18n-ai-translator --help
45
+ ```
46
+
47
+ Enable Unicode escaping:
43
48
 
44
49
  ```json
45
50
  {
@@ -49,426 +54,233 @@ If your target system expects Java-style Unicode escapes in `.properties` files,
49
54
  }
50
55
  ```
51
56
 
52
- Or set it in your config file:
53
-
54
- ```json
55
- {
56
- "encodeUnicode": true
57
- }
58
- ```
57
+ ## Configuration
59
58
 
60
- If you only want escapes for specific target languages, use per-language overrides:
59
+ Example `i18n-ai.config.json`:
61
60
 
62
61
  ```json
63
62
  {
63
+ "sourceLanguage": "en",
64
+ "targetLanguages": ["de", "uk"],
65
+ "translationMode": "missing",
64
66
  "encodeUnicode": false,
65
67
  "languageOptions": {
66
68
  "de": { "encodeUnicode": true },
67
69
  "uk": { "encodeUnicode": false }
68
- }
69
- }
70
- ```
71
-
72
- This keeps languages like Ukrainian readable in UTF-8:
73
-
74
- ```properties
75
- ai.button_tooltip = Π¨Π† ΠΏΠ»Π°Π½ΡƒΠ²Π°Π»ΡŒΠ½ΠΈΠΊ
76
- ```
77
-
78
- Run it with:
79
-
80
- ```bash
81
- npm run i18n:translate
82
- ```
83
-
84
- ## Quick Start
85
-
86
- ### Basic Usage (ES Modules)
87
-
88
- ```javascript
89
- import { Translator } from '@concircle/i18n-ai-translator';
90
-
91
- const translator = new Translator({
92
- provider: 'openai',
93
- openai: {
94
- apiKey: process.env.OPENAI_API_KEY,
95
70
  },
96
- targetLanguages: ['de', 'fr'],
97
- });
98
-
99
- const result = await translator.translate({
100
- inputPath: './src/i18n/i18n.properties',
101
- outputFormat: 'new-files',
102
- });
103
-
104
- console.log('Translation complete!', result);
105
- ```
106
-
107
- ### With Glossary (Domain Vocabulary)
108
-
109
- ```javascript
110
- const translator = new Translator({
111
- provider: 'openai',
112
- openai: { apiKey: process.env.OPENAI_API_KEY },
113
- targetLanguages: ['de'],
114
- glossary: {
115
- 'SAP': { doNotTranslate: true },
116
- 'HANA': { translation: 'SAP HANA', context: 'database' },
117
- 'Fiori': { doNotTranslate: true },
71
+ "provider": "openai",
72
+ "providerOptions": {
73
+ "apiKey": "sk-...",
74
+ "model": "gpt-4.1-mini",
75
+ "temperature": 0,
76
+ "maxOutputTokens": 4000
118
77
  },
119
- });
120
-
121
- // Ensures SAP terms are correctly handled during translation
122
- ```
123
-
124
- ### Load Config from File
125
-
126
- ```javascript
127
- import { loadConfig, Translator } from '@concircle/i18n-ai-translator';
128
-
129
- const config = loadConfig('./config.json');
130
- const translator = new Translator(config);
78
+ "files": {
79
+ "input": "./webapp/i18n/i18n.properties"
80
+ },
81
+ "cache": {
82
+ "enabled": true,
83
+ "ttlMs": 604800000
84
+ },
85
+ "batchSize": 20,
86
+ "verbose": false
87
+ }
131
88
  ```
132
89
 
133
- ## Configuration
134
-
135
- ### TranslatorConfig Interface
90
+ Supported top-level config fields:
136
91
 
137
- ```typescript
92
+ ```ts
138
93
  interface TranslatorConfig {
139
- provider: 'openai'; // Future: 'claude', 'gemini'
140
- openai: {
141
- apiKey: string; // Required: OpenAI API key
142
- model?: string; // Default: 'gpt-4'
143
- temperature?: number; // Default: 0.3
144
- maxTokens?: number; // Default: 2000
94
+ sourceLanguage?: string;
95
+ targetLanguages: string[];
96
+ translationMode?: 'missing' | 'overwrite';
97
+ encodeUnicode?: boolean;
98
+ languageOptions?: Record<string, { encodeUnicode?: boolean }>;
99
+ provider?: 'openai';
100
+ providerOptions?: {
101
+ apiKey?: string;
102
+ model?: string;
103
+ baseURL?: string;
104
+ organization?: string;
105
+ temperature?: number;
106
+ maxOutputTokens?: number;
107
+ };
108
+ files?: {
109
+ input?: string;
110
+ outputDir?: string;
111
+ languageFilePattern?: string;
145
112
  };
146
- targetLanguages: string[]; // Required: e.g., ['de', 'fr', 'es']
147
- encodeUnicode?: boolean; // Default: false, escape non-ASCII as \uXXXX
148
- languageOptions?: Record<string, {
149
- encodeUnicode?: boolean; // Per-language override
150
- }>;
151
- glossary?: Glossary; // Optional: Domain-specific vocabulary
113
+ glossary?: GlossaryConfig | string;
152
114
  cache?: {
153
- enabled?: boolean; // Default: true
154
- ttl?: number; // Default: 7 days (ms)
155
- dir?: string; // Default: ~/.i18n-ai-translator-cache
115
+ enabled?: boolean;
116
+ ttlMs?: number;
117
+ dir?: string;
156
118
  };
157
- batchSize?: number; // Default: 10 (parallel requests)
158
- debug?: boolean; // Default: false
119
+ rules?: string[];
120
+ batchSize?: number;
121
+ verbose?: boolean;
159
122
  }
160
123
  ```
161
124
 
162
- ### Example Configuration File (config.json)
163
-
164
- ```json
165
- {
166
- "provider": "openai",
167
- "openai": {
168
- "apiKey": "sk-...",
169
- "model": "gpt-4",
170
- "temperature": 0.3,
171
- "maxTokens": 2000
172
- },
173
- "targetLanguages": ["de", "fr", "es"],
174
- "encodeUnicode": false,
175
- "languageOptions": {
176
- "de": { "encodeUnicode": true },
177
- "uk": { "encodeUnicode": false }
178
- },
179
- "glossary": "./glossary.json",
180
- "cache": {
181
- "enabled": true,
182
- "ttl": 604800000
183
- },
184
- "batchSize": 10,
185
- "debug": false
186
- }
187
- ```
125
+ ## Glossary
188
126
 
189
- ### Example Glossary File (glossary.json)
127
+ Example glossary file:
190
128
 
191
129
  ```json
192
130
  {
193
- "SAP": {
194
- "term": "SAP",
195
- "translation": "SAP",
196
- "doNotTranslate": true,
197
- "context": "Enterprise Resource Planning System"
198
- },
199
- "HANA": {
200
- "term": "HANA",
201
- "translation": "SAP HANA",
202
- "doNotTranslate": true,
203
- "context": "In-memory database"
204
- },
205
- "module": {
206
- "term": "module",
207
- "translation": "Modul",
208
- "context": "German translation"
131
+ "shared": [
132
+ {
133
+ "source": "Order",
134
+ "target": "Auftrag",
135
+ "context": "SAP sales document"
136
+ }
137
+ ],
138
+ "languages": {
139
+ "de": [
140
+ {
141
+ "source": "Plant",
142
+ "target": "Werk"
143
+ }
144
+ ],
145
+ "uk": [
146
+ {
147
+ "source": "AI",
148
+ "target": "Π¨I"
149
+ }
150
+ ]
209
151
  }
210
152
  }
211
153
  ```
212
154
 
213
- ## API Reference
155
+ ## Programmatic Usage
214
156
 
215
- ### Translator Class
157
+ Translate a file directly:
216
158
 
217
- #### Constructor
218
-
219
- ```typescript
220
- new Translator(config: TranslatorConfig): Translator
221
- ```
222
-
223
- #### Methods
159
+ ```js
160
+ import { Translator } from '@concircle/i18n-ai-translator';
224
161
 
225
- ##### `translate(job: TranslationJob): Promise<TranslationResult>`
162
+ const translator = new Translator({
163
+ sourceLanguage: 'en',
164
+ targetLanguages: ['de'],
165
+ translationMode: 'missing',
166
+ provider: 'openai',
167
+ providerOptions: {
168
+ apiKey: process.env.OPENAI_API_KEY
169
+ },
170
+ files: {
171
+ input: './webapp/i18n/i18n.properties'
172
+ }
173
+ });
226
174
 
227
- Translate a properties file to configured target languages.
175
+ const result = await translator.translateFile();
176
+ console.log(result);
177
+ ```
228
178
 
229
- **Parameters:**
230
- - `job.inputPath`: Path to source `i18n.properties` file
231
- - `job.outputFormat`: `'new-files'` | `'update-existing'` (default: `'new-files'`)
232
- - `job.outputDir`: Output directory for new files
233
- - `job.languages`: Override config languages for this job
179
+ Load config from file:
234
180
 
235
- **Returns:** Object with translation results per language
181
+ ```js
182
+ import { Translator } from '@concircle/i18n-ai-translator';
236
183
 
237
- ```javascript
238
- const result = await translator.translate({
239
- inputPath: './src/i18n/i18n.properties',
240
- outputFormat: 'new-files',
241
- outputDir: './src/i18n',
242
- languages: ['de'], // Optional: override
184
+ const translator = await Translator.fromConfig({
185
+ configPath: './i18n-ai.config.json'
243
186
  });
244
187
 
245
- // Result example:
246
- // {
247
- // sourceFile: './src/i18n/i18n.properties',
248
- // translations: {
249
- // de: {
250
- // outputFile: './src/i18n/i18n_de.properties',
251
- // success: true,
252
- // translatedKeysCount: 42
253
- // },
254
- // fr: {
255
- // outputFile: './src/i18n/i18n_fr.properties',
256
- // success: true,
257
- // translatedKeysCount: 42
258
- // }
259
- // }
260
- // }
188
+ const result = await translator.translateProject();
189
+ console.log(result);
261
190
  ```
262
191
 
263
- ##### `clearCache(): void`
264
-
265
- Clear the translation cache (useful for testing or after glossary changes)
266
-
267
- ```javascript
268
- translator.clearCache();
269
- ```
192
+ Use the top-level helper:
270
193
 
271
- ##### `getCacheStats(): object`
194
+ ```js
195
+ import { translateProject } from '@concircle/i18n-ai-translator';
272
196
 
273
- Get cache statistics
197
+ const result = await translateProject({
198
+ inputPath: './webapp/i18n/i18n.properties',
199
+ languages: ['de'],
200
+ dryRun: true
201
+ });
274
202
 
275
- ```javascript
276
- const stats = translator.getCacheStats();
277
- // { enabled: true, cacheDir: '...', ttl: ..., entriesCount: 5 }
203
+ console.log(result);
278
204
  ```
279
205
 
280
- ##### `getGlossary(): Glossary`
281
-
282
- Get current glossary
283
-
284
- ```javascript
285
- const glossary = translator.getGlossary();
286
- ```
206
+ ## Translation Modes
287
207
 
288
- ##### `getGlossaryTerms(): string[]`
208
+ - `missing`: only translates keys that are missing or empty in the target file
209
+ - `overwrite`: retranslates all keys from the source file
289
210
 
290
- Get all glossary terms
211
+ ## Placeholder Handling
291
212
 
292
- ```javascript
293
- const terms = translator.getGlossaryTerms();
294
- ```
213
+ The translator masks placeholders before sending text to the model and validates that they are still present afterwards.
295
214
 
296
- ## UI5 Properties File Format
215
+ Supported placeholder styles:
297
216
 
298
- ### Input Example (i18n.properties)
217
+ - `{0}`, `{1}`
218
+ - `{name}`, `{email}`
219
+ - `%s`, `%d`
220
+ - `%1$s`, `%2$d`
221
+ - `${variable}`
299
222
 
300
- ```properties
301
- # Application messages
302
- app.title=My Application
303
- app.version=1.0.0
223
+ ## Output Files
304
224
 
305
- # Messages with placeholders (will be preserved)
306
- msg.save=Save {0} items
307
- msg.delete=Delete {0} from {1}
225
+ By default, UI5-style language files are generated next to the source file:
308
226
 
309
- # Named placeholders
310
- form.email=Please enter {email}
227
+ - `i18n.properties`
228
+ - `i18n_de.properties`
229
+ - `i18n_fr.properties`
311
230
 
312
- # Format specifiers (preserved)
313
- msg.count=Found %d results
314
- msg.user=User %s not found
315
- ```
231
+ You can override the output directory or file naming pattern in `files.outputDir` and `files.languageFilePattern`.
316
232
 
317
- ### Output Example (i18n_de.properties)
233
+ ## Cache
318
234
 
319
- ```properties
320
- # Application messages
321
- app.title=Meine Anwendung
322
- app.version=1.0.0
235
+ Caching is enabled by default. Cache keys include:
323
236
 
324
- # Messages with placeholders (PRESERVED unchanged)
325
- msg.save=Speichern Sie {0} Elemente
326
- msg.delete=LΓΆschen Sie {0} von {1}
237
+ - provider
238
+ - model
239
+ - source language
240
+ - target language
241
+ - source value
242
+ - glossary terms
243
+ - translation rules
327
244
 
328
- # Named placeholders
329
- form.email=Bitte geben Sie {email} ein
245
+ Default cache location:
330
246
 
331
- # Format specifiers (PRESERVED)
332
- msg.count=Es wurden %d Ergebnisse gefunden
333
- msg.user=Benutzer %s nicht gefunden
247
+ ```text
248
+ ~/.i18n-ai-translator-cache/
334
249
  ```
335
250
 
336
- ## Placeholder Protection
337
-
338
- All placeholder types are automatically detected and preserved during translation:
339
-
340
- - `{0}`, `{1}`, etc. - Numeric placeholders
341
- - `{name}`, `{email}`, etc. - Named placeholders
342
- - `%s`, `%d`, etc. - Printf-style format specifiers
343
- - `${variable}` - Template variable syntax
344
- - `%1$s`, `%2$d`, etc. - Positional format specifiers
345
-
346
251
  ## Environment Variables
347
252
 
348
- Configuration can also be provided via environment variables:
253
+ Supported environment variables:
349
254
 
350
255
  ```bash
351
256
  export OPENAI_API_KEY=sk-...
352
- export OPENAI_MODEL=gpt-4
353
- export TARGET_LANGUAGES=de,fr,es
354
- export GLOSSARY_FILE=./glossary.json
257
+ export OPENAI_MODEL=gpt-4.1-mini
355
258
  ```
356
259
 
357
260
  ## Examples
358
261
 
359
- See `examples/` directory for complete working examples:
360
-
361
- - `basic.mjs` - Minimal setup with environment variables
362
- - `with-glossary.mjs` - Using domain-specific vocabulary
363
- - `advanced.mjs` - Full configuration with caching and debugging
364
-
365
- Run examples:
262
+ See [`examples/`](./examples/) for small runnable examples:
366
263
 
367
- ```bash
368
- export OPENAI_API_KEY=sk-...
369
- node examples/basic.mjs
370
- ```
371
-
372
- ## Caching
373
-
374
- The translator uses smart, local file-based caching to:
375
-
376
- - **Reduce API costs**: Skip repeated translations
377
- - **Improve performance**: Instant retrieval from cache
378
- - **Invalidate on glossary changes**: Cache is invalidated when glossary is updated
379
- - **Support TTL**: Default 7-day cache expiration
380
-
381
- Cache location: `~/.i18n-ai-translator-cache/`
382
-
383
- ### Cache Configuration
384
-
385
- ```javascript
386
- cache: {
387
- enabled: true, // Enable/disable caching
388
- ttl: 7 * 24 * 60 * 60 * 1000, // 7 days in milliseconds
389
- dir: '/custom/cache/dir' // Custom cache directory
390
- }
391
- ```
392
-
393
- ## Performance & Batching
394
-
395
- Translations are processed in parallel batches for efficiency:
396
-
397
- ```javascript
398
- batchSize: 10 // Process up to 10 translations in parallel
399
- ```
400
-
401
- This balances between:
402
- - **Throughput**: Parallel processing speeds up translation
403
- - **API Limits**: Stays within OpenAI rate limits (default 10 concurrent)
404
- - **Cost**: Fewer API calls due to combining texts
405
-
406
- ## Future Provider Support
264
+ - [`basic.mjs`](./examples/basic.mjs)
265
+ - [`with-glossary.mjs`](./examples/with-glossary.mjs)
266
+ - [`advanced.mjs`](./examples/advanced.mjs)
407
267
 
408
- The architecture supports adding new AI providers. Implement the `AIProvider` interface:
409
-
410
- ```typescript
411
- interface AIProvider {
412
- translateTexts(texts: string[], targetLanguage: string, context?: string): Promise<string[]>;
413
- getName(): string;
414
- }
415
- ```
416
-
417
- Future providers planned:
418
- - Claude (Anthropic)
419
- - Gemini (Google)
420
- - Offline/Local models
421
-
422
- ## Error Handling
423
-
424
- The translator provides detailed error information:
425
-
426
- ```javascript
427
- try {
428
- const result = await translator.translate({...});
429
-
430
- for (const [lang, langResult] of Object.entries(result.translations)) {
431
- if (!langResult.success) {
432
- console.error(`Translation failed for ${lang}: ${langResult.error}`);
433
- }
434
- }
435
- } catch (error) {
436
- console.error('Translation job failed:', error.message);
437
- }
438
- ```
439
-
440
- ## Testing
441
-
442
- Run the comprehensive test suite:
268
+ ## Development
443
269
 
444
270
  ```bash
445
- npm test # Run tests
446
- npm run test:watch # Watch mode
447
- npm run test:coverage # Coverage report
271
+ npm run build
272
+ npm run lint
273
+ npm test
448
274
  ```
449
275
 
450
- Tests include:
451
- - βœ… Placeholder extraction and restoration (critical)
452
- - βœ… Properties file parsing and writing
453
- - βœ… Glossary management and injection
454
- - βœ… Cache behavior and TTL
455
- - βœ… Configuration validation
456
-
457
276
  ## License
458
277
 
459
278
  MIT Β© 2026 Herbert Kaintz - Concircle
460
279
 
461
280
  ## Contributing
462
281
 
463
- Contributions welcome! See [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines.
282
+ See [`CONTRIBUTING.md`](./CONTRIBUTING.md).
464
283
 
465
284
  ## Security
466
285
 
467
- Please report security vulnerabilities to security contacts via email rather than public issues. See [SECURITY.md](./SECURITY.md) for details.
468
-
469
- ## Support
470
-
471
- - πŸ“– [API Documentation](./docs/)
472
- - πŸ“š [Examples](./examples/)
473
- - 🀝 [Contributing Guide](./CONTRIBUTING.md)
474
- - πŸ”’ [Security Policy](./SECURITY.md)
286
+ See [`SECURITY.md`](./SECURITY.md).
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@concircle/i18n-ai-translator",
3
- "version": "0.1.2",
4
- "description": "AI-powered i18n translator for UI5 apps. Translates i18n.properties files using OpenAI (extensible for other AI providers).",
3
+ "version": "0.1.3",
4
+ "description": "Translates UI5 i18n.properties files with OpenAI, preserving placeholders and glossary terms.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "i18n-ai-translator": "./bin/i18n-ai-translator.mjs"
@@ -64,12 +64,12 @@
64
64
  "license": "MIT",
65
65
  "repository": {
66
66
  "type": "git",
67
- "url": "https://bitbucket.org/concircle/i18n-ai-translator.git"
67
+ "url": "https://github.com/concircle/i18n-ai-translator.git"
68
68
  },
69
69
  "bugs": {
70
- "url": "https://bitbucket.org/concircle/i18n-ai-translator/issues"
70
+ "url": "https://github.com/concircle/i18n-ai-translator/issues"
71
71
  },
72
- "homepage": "https://bitbucket.org/concircle/i18n-ai-translator",
72
+ "homepage": "https://www.concircle.com/en/",
73
73
  "engines": {
74
74
  "node": ">=20.0.0"
75
75
  }