poly-lexis 0.1.0 → 0.2.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/dist/index.js CHANGED
@@ -14,33 +14,84 @@ var __export = (target, all) => {
14
14
  __defProp(target, name, { get: all[name], enumerable: true });
15
15
  };
16
16
 
17
- // src/translations/core/types.ts
18
- var DEFAULT_CONFIG, DEFAULT_LANGUAGES;
19
- var init_types = __esm({
20
- "src/translations/core/types.ts"() {
17
+ // src/translations/utils/utils.ts
18
+ import * as fs from "fs";
19
+ import * as path from "path";
20
+ function readTranslations(translationsPath, language) {
21
+ const langPath = path.join(translationsPath, language);
22
+ if (!fs.existsSync(langPath)) {
23
+ return {};
24
+ }
25
+ const files = fs.readdirSync(langPath).filter((f) => f.endsWith(".json"));
26
+ const translations = {};
27
+ for (const file of files) {
28
+ const namespace = path.basename(file, ".json");
29
+ const filePath = path.join(langPath, file);
30
+ const content = fs.readFileSync(filePath, "utf-8");
31
+ translations[namespace] = JSON.parse(content);
32
+ }
33
+ return translations;
34
+ }
35
+ function writeTranslation(translationsPath, language, namespace, translations) {
36
+ const langPath = path.join(translationsPath, language);
37
+ if (!fs.existsSync(langPath)) {
38
+ fs.mkdirSync(langPath, { recursive: true });
39
+ }
40
+ const filePath = path.join(langPath, `${namespace}.json`);
41
+ fs.writeFileSync(filePath, `${JSON.stringify(translations, null, 2)}
42
+ `, "utf-8");
43
+ }
44
+ function getAvailableLanguages(translationsPath) {
45
+ if (!fs.existsSync(translationsPath)) {
46
+ return [];
47
+ }
48
+ return fs.readdirSync(translationsPath, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
49
+ }
50
+ function getNamespaces(translationsPath, language) {
51
+ const langPath = path.join(translationsPath, language);
52
+ if (!fs.existsSync(langPath)) {
53
+ return [];
54
+ }
55
+ return fs.readdirSync(langPath).filter((f) => f.endsWith(".json")).map((f) => path.basename(f, ".json"));
56
+ }
57
+ function hasInterpolation(text) {
58
+ return /\{\{[^}]+\}\}/g.test(text);
59
+ }
60
+ function extractVariables(text) {
61
+ const matches = text.match(/\{\{([^}]+)\}\}/g);
62
+ if (!matches) return [];
63
+ return matches.map((match) => match.replace(/\{\{|\}\}/g, "").trim());
64
+ }
65
+ function validateVariables(sourceText, translatedText) {
66
+ const sourceVars = extractVariables(sourceText).sort();
67
+ const translatedVars = extractVariables(translatedText).sort();
68
+ if (sourceVars.length !== translatedVars.length) {
69
+ return false;
70
+ }
71
+ return sourceVars.every((v, i) => v === translatedVars[i]);
72
+ }
73
+ function sortKeys(obj) {
74
+ const sorted = {};
75
+ const keys = Object.keys(obj).sort();
76
+ for (const key of keys) {
77
+ sorted[key] = obj[key];
78
+ }
79
+ return sorted;
80
+ }
81
+ function ensureTranslationsStructure(translationsPath, languages) {
82
+ if (!fs.existsSync(translationsPath)) {
83
+ fs.mkdirSync(translationsPath, { recursive: true });
84
+ }
85
+ for (const lang of languages) {
86
+ const langPath = path.join(translationsPath, lang);
87
+ if (!fs.existsSync(langPath)) {
88
+ fs.mkdirSync(langPath, { recursive: true });
89
+ }
90
+ }
91
+ }
92
+ var init_utils = __esm({
93
+ "src/translations/utils/utils.ts"() {
21
94
  "use strict";
22
- DEFAULT_CONFIG = {
23
- translationsPath: "public/static/locales",
24
- languages: ["en"],
25
- sourceLanguage: "en",
26
- typesOutputPath: "src/types/i18nTypes.ts"
27
- };
28
- DEFAULT_LANGUAGES = [
29
- "en",
30
- "fr",
31
- "it",
32
- "pl",
33
- "es",
34
- "pt",
35
- "de",
36
- "de_at",
37
- "nl",
38
- "sv",
39
- "hu",
40
- "cs",
41
- "ja",
42
- "zh_hk"
43
- ];
44
95
  }
45
96
  });
46
97
 
@@ -60,54 +111,274 @@ var init_schema = __esm({
60
111
  "src/translations/core/schema.ts"() {
61
112
  "use strict";
62
113
  SUPPORTED_LANGUAGES = [
114
+ "af",
115
+ // Afrikaans
116
+ "sq",
117
+ // Albanian
118
+ "am",
119
+ // Amharic
120
+ "ar",
121
+ // Arabic
122
+ "hy",
123
+ // Armenian
124
+ "as",
125
+ // Assamese
126
+ "ay",
127
+ // Aymara
128
+ "az",
129
+ // Azerbaijani
130
+ "bm",
131
+ // Bambara
132
+ "eu",
133
+ // Basque
134
+ "be",
135
+ // Belarusian
136
+ "bn",
137
+ // Bengali
138
+ "bho",
139
+ // Bhojpuri
140
+ "bs",
141
+ // Bosnian
142
+ "bg",
143
+ // Bulgarian
144
+ "ca",
145
+ // Catalan
146
+ "ceb",
147
+ // Cebuano
148
+ "ny",
149
+ // Chichewa
150
+ "zh",
151
+ // Chinese (Simplified) - Google uses 'zh' or 'zh-CN'
152
+ "zh_cn",
153
+ // Chinese (Simplified) - alternative format
154
+ "zh_tw",
155
+ // Chinese (Traditional)
156
+ "co",
157
+ // Corsican
158
+ "hr",
159
+ // Croatian
160
+ "cs",
161
+ // Czech
162
+ "da",
163
+ // Danish
164
+ "dv",
165
+ // Dhivehi
166
+ "doi",
167
+ // Dogri
168
+ "nl",
169
+ // Dutch
63
170
  "en",
64
171
  // English
172
+ "eo",
173
+ // Esperanto
174
+ "et",
175
+ // Estonian
176
+ "ee",
177
+ // Ewe
178
+ "tl",
179
+ // Filipino (Tagalog)
180
+ "fi",
181
+ // Finnish
65
182
  "fr",
66
183
  // French
67
- "it",
68
- // Italian
69
- "pl",
70
- // Polish
71
- "es",
72
- // Spanish
73
- "pt",
74
- // Portuguese
184
+ "gl",
185
+ // Galician
186
+ "ka",
187
+ // Georgian
75
188
  "de",
76
189
  // German
77
- "de_at",
78
- // German (Austria)
79
- "nl",
80
- // Dutch
81
- "sv",
82
- // Swedish
190
+ "el",
191
+ // Greek
192
+ "gn",
193
+ // Guarani
194
+ "gu",
195
+ // Gujarati
196
+ "ht",
197
+ // Haitian Creole
198
+ "ha",
199
+ // Hausa
200
+ "haw",
201
+ // Hawaiian
202
+ "iw",
203
+ // Hebrew (legacy code, 'he' is preferred)
204
+ "he",
205
+ // Hebrew
206
+ "hi",
207
+ // Hindi
208
+ "hmn",
209
+ // Hmong
83
210
  "hu",
84
211
  // Hungarian
85
- "cs",
86
- // Czech
212
+ "is",
213
+ // Icelandic
214
+ "ig",
215
+ // Igbo
216
+ "ilo",
217
+ // Ilocano
218
+ "id",
219
+ // Indonesian
220
+ "ga",
221
+ // Irish
222
+ "it",
223
+ // Italian
87
224
  "ja",
88
225
  // Japanese
89
- "zh_hk",
90
- // Chinese (Hong Kong)
91
- "zh_cn",
92
- // Chinese (Simplified)
226
+ "jw",
227
+ // Javanese
228
+ "kn",
229
+ // Kannada
230
+ "kk",
231
+ // Kazakh
232
+ "km",
233
+ // Khmer
234
+ "rw",
235
+ // Kinyarwanda
236
+ "gom",
237
+ // Konkani
93
238
  "ko",
94
239
  // Korean
240
+ "kri",
241
+ // Krio
242
+ "ku",
243
+ // Kurdish (Kurmanji)
244
+ "ckb",
245
+ // Kurdish (Sorani)
246
+ "ky",
247
+ // Kyrgyz
248
+ "lo",
249
+ // Lao
250
+ "la",
251
+ // Latin
252
+ "lv",
253
+ // Latvian
254
+ "ln",
255
+ // Lingala
256
+ "lt",
257
+ // Lithuanian
258
+ "lg",
259
+ // Luganda
260
+ "lb",
261
+ // Luxembourgish
262
+ "mk",
263
+ // Macedonian
264
+ "mai",
265
+ // Maithili
266
+ "mg",
267
+ // Malagasy
268
+ "ms",
269
+ // Malay
270
+ "ml",
271
+ // Malayalam
272
+ "mt",
273
+ // Maltese
274
+ "mi",
275
+ // Maori
276
+ "mr",
277
+ // Marathi
278
+ "mni",
279
+ // Meiteilon (Manipuri)
280
+ "lus",
281
+ // Mizo
282
+ "mn",
283
+ // Mongolian
284
+ "my",
285
+ // Myanmar (Burmese)
286
+ "ne",
287
+ // Nepali
288
+ "no",
289
+ // Norwegian
290
+ "or",
291
+ // Odia
292
+ "om",
293
+ // Oromo
294
+ "ps",
295
+ // Pashto
296
+ "fa",
297
+ // Persian
298
+ "pl",
299
+ // Polish
300
+ "pt",
301
+ // Portuguese
302
+ "pt_br",
303
+ // Portuguese (Brazil)
304
+ "pa",
305
+ // Punjabi
306
+ "qu",
307
+ // Quechua
308
+ "ro",
309
+ // Romanian
95
310
  "ru",
96
311
  // Russian
97
- "ar",
98
- // Arabic
99
- "he",
100
- // Hebrew
312
+ "sm",
313
+ // Samoan
314
+ "sa",
315
+ // Sanskrit
316
+ "gd",
317
+ // Scottish Gaelic
318
+ "sr",
319
+ // Serbian
320
+ "st",
321
+ // Sesotho
322
+ "sn",
323
+ // Shona
324
+ "sd",
325
+ // Sindhi
326
+ "si",
327
+ // Sinhala
328
+ "sk",
329
+ // Slovak
330
+ "sl",
331
+ // Slovenian
332
+ "so",
333
+ // Somali
334
+ "es",
335
+ // Spanish
336
+ "su",
337
+ // Sundanese
338
+ "sw",
339
+ // Swahili
340
+ "sv",
341
+ // Swedish
342
+ "tg",
343
+ // Tajik
344
+ "ta",
345
+ // Tamil
346
+ "tt",
347
+ // Tatar
348
+ "te",
349
+ // Telugu
350
+ "th",
351
+ // Thai
352
+ "ti",
353
+ // Tigrinya
354
+ "ts",
355
+ // Tsonga
101
356
  "tr",
102
357
  // Turkish
103
- "da",
104
- // Danish
105
- "fi",
106
- // Finnish
107
- "no",
108
- // Norwegian
109
- "pt_br"
110
- // Portuguese (Brazil)
358
+ "tk",
359
+ // Turkmen
360
+ "ak",
361
+ // Twi
362
+ "uk",
363
+ // Ukrainian
364
+ "ur",
365
+ // Urdu
366
+ "ug",
367
+ // Uyghur
368
+ "uz",
369
+ // Uzbek
370
+ "vi",
371
+ // Vietnamese
372
+ "cy",
373
+ // Welsh
374
+ "xh",
375
+ // Xhosa
376
+ "yi",
377
+ // Yiddish
378
+ "yo",
379
+ // Yoruba
380
+ "zu"
381
+ // Zulu
111
382
  ];
112
383
  TRANSLATION_CONFIG_SCHEMA = {
113
384
  $schema: "http://json-schema.org/draft-07/schema#",
@@ -148,83 +419,33 @@ var init_schema = __esm({
148
419
  }
149
420
  });
150
421
 
151
- // src/translations/utils/utils.ts
152
- import * as fs from "fs";
153
- import * as path from "path";
154
- function readTranslations(translationsPath, language) {
155
- const langPath = path.join(translationsPath, language);
156
- if (!fs.existsSync(langPath)) {
157
- return {};
158
- }
159
- const files = fs.readdirSync(langPath).filter((f) => f.endsWith(".json"));
160
- const translations = {};
161
- for (const file of files) {
162
- const namespace = path.basename(file, ".json");
163
- const filePath = path.join(langPath, file);
164
- const content = fs.readFileSync(filePath, "utf-8");
165
- translations[namespace] = JSON.parse(content);
166
- }
167
- return translations;
168
- }
169
- function writeTranslation(translationsPath, language, namespace, translations) {
170
- const langPath = path.join(translationsPath, language);
171
- if (!fs.existsSync(langPath)) {
172
- fs.mkdirSync(langPath, { recursive: true });
173
- }
174
- const filePath = path.join(langPath, `${namespace}.json`);
175
- fs.writeFileSync(filePath, JSON.stringify(translations, null, 2) + "\n", "utf-8");
176
- }
177
- function getAvailableLanguages(translationsPath) {
178
- if (!fs.existsSync(translationsPath)) {
179
- return [];
180
- }
181
- return fs.readdirSync(translationsPath, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
182
- }
183
- function getNamespaces(translationsPath, language) {
184
- const langPath = path.join(translationsPath, language);
185
- if (!fs.existsSync(langPath)) {
186
- return [];
187
- }
188
- return fs.readdirSync(langPath).filter((f) => f.endsWith(".json")).map((f) => path.basename(f, ".json"));
189
- }
190
- function hasInterpolation(text) {
191
- return /\{\{[^}]+\}\}/g.test(text);
192
- }
193
- function extractVariables(text) {
194
- const matches = text.match(/\{\{([^}]+)\}\}/g);
195
- if (!matches) return [];
196
- return matches.map((match) => match.replace(/\{\{|\}\}/g, "").trim());
197
- }
198
- function validateVariables(sourceText, translatedText) {
199
- const sourceVars = extractVariables(sourceText).sort();
200
- const translatedVars = extractVariables(translatedText).sort();
201
- if (sourceVars.length !== translatedVars.length) {
202
- return false;
203
- }
204
- return sourceVars.every((v, i) => v === translatedVars[i]);
205
- }
206
- function sortKeys(obj) {
207
- const sorted = {};
208
- const keys = Object.keys(obj).sort();
209
- for (const key of keys) {
210
- sorted[key] = obj[key];
211
- }
212
- return sorted;
213
- }
214
- function ensureTranslationsStructure(translationsPath, languages) {
215
- if (!fs.existsSync(translationsPath)) {
216
- fs.mkdirSync(translationsPath, { recursive: true });
217
- }
218
- for (const lang of languages) {
219
- const langPath = path.join(translationsPath, lang);
220
- if (!fs.existsSync(langPath)) {
221
- fs.mkdirSync(langPath, { recursive: true });
222
- }
223
- }
224
- }
225
- var init_utils = __esm({
226
- "src/translations/utils/utils.ts"() {
422
+ // src/translations/core/types.ts
423
+ var DEFAULT_CONFIG, DEFAULT_LANGUAGES;
424
+ var init_types = __esm({
425
+ "src/translations/core/types.ts"() {
227
426
  "use strict";
427
+ DEFAULT_CONFIG = {
428
+ translationsPath: "public/static/locales",
429
+ languages: ["en"],
430
+ sourceLanguage: "en",
431
+ typesOutputPath: "src/types/i18nTypes.ts"
432
+ };
433
+ DEFAULT_LANGUAGES = [
434
+ "en",
435
+ "fr",
436
+ "it",
437
+ "pl",
438
+ "es",
439
+ "pt",
440
+ "de",
441
+ "de_at",
442
+ "nl",
443
+ "sv",
444
+ "hu",
445
+ "cs",
446
+ "ja",
447
+ "zh_hk"
448
+ ];
228
449
  }
229
450
  });
230
451
 
@@ -294,7 +515,8 @@ function initTranslations(projectRoot, config = {}) {
294
515
  ERROR: "Error",
295
516
  SUCCESS: "Success"
296
517
  };
297
- fs2.writeFileSync(commonPath, JSON.stringify(sampleTranslations, null, 2) + "\n", "utf-8");
518
+ fs2.writeFileSync(commonPath, `${JSON.stringify(sampleTranslations, null, 2)}
519
+ `, "utf-8");
298
520
  console.log(`Created sample file: ${commonPath}`);
299
521
  }
300
522
  for (const lang of languages) {
@@ -314,7 +536,8 @@ function initTranslations(projectRoot, config = {}) {
314
536
  sourceLanguage,
315
537
  typesOutputPath: finalConfig.typesOutputPath
316
538
  };
317
- fs2.writeFileSync(configPath, JSON.stringify(configContent, null, 2) + "\n", "utf-8");
539
+ fs2.writeFileSync(configPath, `${JSON.stringify(configContent, null, 2)}
540
+ `, "utf-8");
318
541
  console.log(`Created config file: ${configPath}`);
319
542
  }
320
543
  console.log("=====");
@@ -355,16 +578,11 @@ var init_init = __esm({
355
578
  }
356
579
  });
357
580
 
358
- // src/translations/index.ts
359
- init_types();
360
- init_schema();
361
- init_utils();
581
+ // src/translations/cli/add-key.ts
582
+ import * as path3 from "path";
362
583
 
363
- // src/translations/utils/translator.ts
364
- async function translateText(text, targetLang, sourceLang = "en", apiKey) {
365
- if (!apiKey) {
366
- throw new Error("Google Translate API key is required. Set GOOGLE_TRANSLATE_API_KEY environment variable.");
367
- }
584
+ // src/translations/utils/google-translate-provider.ts
585
+ function preserveVariables(text) {
368
586
  const variableMap = /* @__PURE__ */ new Map();
369
587
  let placeholderIndex = 0;
370
588
  const textWithPlaceholders = text.replace(/\{\{([^}]+)\}\}/g, (match) => {
@@ -373,209 +591,99 @@ async function translateText(text, targetLang, sourceLang = "en", apiKey) {
373
591
  placeholderIndex++;
374
592
  return placeholder;
375
593
  });
376
- const url = `https://translation.googleapis.com/language/translate/v2?key=${apiKey}`;
377
- const response = await fetch(url, {
378
- method: "POST",
379
- headers: {
380
- "Content-Type": "application/json"
381
- },
382
- body: JSON.stringify({
383
- q: textWithPlaceholders,
384
- source: sourceLang,
385
- target: targetLang.split("_")[0],
386
- // Convert 'pt_BR' to 'pt'
387
- format: "text"
388
- })
389
- });
390
- const data = await response.json();
391
- if (data.error) {
392
- throw new Error(`Google Translate API error: ${data.error.message}`);
393
- }
394
- let translatedText = data.data.translations[0].translatedText;
594
+ return { textWithPlaceholders, variableMap };
595
+ }
596
+ function restoreVariables(text, variableMap) {
597
+ let result = text;
395
598
  for (const [placeholder, original] of variableMap) {
396
- translatedText = translatedText.replace(new RegExp(placeholder, "g"), original);
599
+ result = result.replace(new RegExp(placeholder, "g"), original);
397
600
  }
398
- return translatedText;
601
+ return result;
399
602
  }
400
- async function translateBatch(texts, targetLang, sourceLang = "en", apiKey, delayMs = 100) {
401
- const results = [];
402
- for (const text of texts) {
403
- const translated = await translateText(text, targetLang, sourceLang, apiKey);
404
- results.push(translated);
405
- if (delayMs > 0) {
406
- await new Promise((resolve) => setTimeout(resolve, delayMs));
603
+ var GoogleTranslateProvider = class {
604
+ async translate(options) {
605
+ const { text, sourceLang, targetLang, apiKey } = options;
606
+ if (!apiKey) {
607
+ throw new Error(
608
+ "Google Translate API key is required. Set GOOGLE_TRANSLATE_API_KEY environment variable or provide apiKey in options."
609
+ );
407
610
  }
611
+ const { textWithPlaceholders, variableMap } = preserveVariables(text);
612
+ const url = `https://translation.googleapis.com/language/translate/v2?key=${apiKey}`;
613
+ const response = await fetch(url, {
614
+ method: "POST",
615
+ headers: {
616
+ "Content-Type": "application/json"
617
+ },
618
+ body: JSON.stringify({
619
+ q: textWithPlaceholders,
620
+ source: sourceLang,
621
+ target: targetLang.split("_")[0],
622
+ // Convert 'pt_BR' to 'pt'
623
+ format: "text"
624
+ })
625
+ });
626
+ const data = await response.json();
627
+ if (data.error) {
628
+ throw new Error(`Google Translate API error: ${data.error.message}`);
629
+ }
630
+ const translatedText = data.data.translations[0].translatedText;
631
+ return restoreVariables(translatedText, variableMap);
408
632
  }
409
- return results;
410
- }
411
-
412
- // src/translations/index.ts
413
- init_init();
414
-
415
- // src/translations/cli/init-interactive.ts
416
- init_schema();
417
- init_types();
418
- init_init();
419
- import * as path3 from "path";
420
- import { checkbox, confirm, input } from "@inquirer/prompts";
421
- async function initTranslationsInteractive(projectRoot = process.cwd()) {
422
- console.log("\n\u{1F30D} Translation System Setup\n");
423
- const configPath = path3.join(projectRoot, ".translationsrc.json");
424
- const alreadyExists = __require("fs").existsSync(configPath);
425
- if (alreadyExists) {
426
- console.log("\u26A0\uFE0F Configuration file already exists at .translationsrc.json\n");
427
- const shouldOverwrite = await confirm({
428
- message: "Would you like to reconfigure?",
429
- default: false
430
- });
431
- if (!shouldOverwrite) {
432
- console.log("\u2713 Keeping existing configuration");
433
- return;
434
- }
435
- }
436
- const { detectExistingTranslations: detectExistingTranslations2 } = await Promise.resolve().then(() => (init_init(), init_exports));
437
- const existing = detectExistingTranslations2(projectRoot);
438
- let translationsPath;
439
- let languages;
440
- if (existing.path) {
441
- console.log(`\u2713 Found existing translations at: ${existing.path}`);
442
- const useExisting = await confirm({
443
- message: "Use this location?",
444
- default: true
445
- });
446
- if (useExisting) {
447
- translationsPath = existing.path;
448
- } else {
449
- translationsPath = await input({
450
- message: "Enter translations directory path:",
451
- default: DEFAULT_CONFIG.translationsPath,
452
- validate: (value) => {
453
- if (!value.trim()) return "Path is required";
454
- return true;
455
- }
456
- });
457
- }
458
- } else {
459
- translationsPath = await input({
460
- message: "Where should translations be stored?",
461
- default: DEFAULT_CONFIG.translationsPath,
462
- validate: (value) => {
463
- if (!value.trim()) return "Path is required";
464
- return true;
465
- }
466
- });
467
- }
468
- if (existing.languages.length > 0) {
469
- console.log(`\u2713 Found existing languages: ${existing.languages.join(", ")}`);
470
- const useExistingLangs = await confirm({
471
- message: "Use these languages?",
472
- default: true
473
- });
474
- if (useExistingLangs) {
475
- languages = existing.languages;
476
- } else {
477
- languages = await selectLanguages();
478
- }
479
- } else {
480
- languages = await selectLanguages();
481
- }
482
- const sourceLanguage = await input({
483
- message: "What is your source language?",
484
- default: "en",
485
- validate: (value) => {
486
- if (!SUPPORTED_LANGUAGES.includes(value)) {
487
- return `Invalid language code. Must be one of: ${SUPPORTED_LANGUAGES.join(", ")}`;
488
- }
489
- if (!languages.includes(value)) {
490
- return "Source language must be in the list of supported languages";
491
- }
492
- return true;
493
- }
494
- });
495
- const typesOutputPath = await input({
496
- message: "Where should TypeScript types be generated?",
497
- default: DEFAULT_CONFIG.typesOutputPath
498
- });
499
- console.log("\n\u{1F4CB} Configuration Summary:");
500
- console.log(` Translations: ${translationsPath}`);
501
- console.log(` Languages: ${languages.join(", ")}`);
502
- console.log(` Source: ${sourceLanguage}`);
503
- console.log(` Types: ${typesOutputPath}`);
504
- const confirmInit = await confirm({
505
- message: "\nProceed with initialization?",
506
- default: true
507
- });
508
- if (!confirmInit) {
509
- console.log("\u274C Cancelled");
510
- return;
511
- }
512
- const config = {
513
- translationsPath,
514
- languages,
515
- sourceLanguage,
516
- typesOutputPath
517
- };
518
- console.log();
519
- initTranslations(projectRoot, config);
520
- console.log("\n\u{1F4DD} Configuration saved to: .translationsrc.json");
521
- console.log("\n\u{1F4A1} Next steps:");
522
- console.log(' 1. Run "translations add" to add your first translation key');
523
- console.log(' 2. Run "translations" to validate and generate types');
524
- console.log(" 3. Check the .translationsrc.json file for your configuration\n");
633
+ async translateBatch(texts, sourceLang, targetLang, apiKey, delayMs = 100) {
634
+ const results = [];
635
+ for (const text of texts) {
636
+ const translated = await this.translate({
637
+ text,
638
+ sourceLang,
639
+ targetLang,
640
+ apiKey
641
+ });
642
+ results.push(translated);
643
+ if (delayMs > 0) {
644
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
645
+ }
646
+ }
647
+ return results;
648
+ }
649
+ async validateConfig() {
650
+ const apiKey = process.env.GOOGLE_TRANSLATE_API_KEY;
651
+ return !!apiKey;
652
+ }
653
+ };
654
+
655
+ // src/translations/utils/translator.ts
656
+ var defaultProvider = new GoogleTranslateProvider();
657
+ var customProvider = null;
658
+ function setTranslationProvider(provider) {
659
+ customProvider = provider;
525
660
  }
526
- async function selectLanguages() {
527
- const languageChoices = SUPPORTED_LANGUAGES.map((lang) => ({
528
- name: `${lang} - ${getLanguageName(lang)}`,
529
- value: lang,
530
- checked: lang === "en"
531
- // English selected by default
532
- }));
533
- const selected = await checkbox({
534
- message: "Select languages to support (space to select, enter to confirm):",
535
- choices: languageChoices,
536
- required: true,
537
- pageSize: 15,
538
- loop: false
661
+ function getTranslationProvider() {
662
+ return customProvider || defaultProvider;
663
+ }
664
+ function resetTranslationProvider() {
665
+ customProvider = null;
666
+ }
667
+ async function translateText(text, targetLang, sourceLang = "en", apiKey) {
668
+ const provider = getTranslationProvider();
669
+ return provider.translate({
670
+ text,
671
+ sourceLang,
672
+ targetLang,
673
+ apiKey
539
674
  });
540
- return selected;
541
675
  }
542
- function getLanguageName(code) {
543
- const names = {
544
- en: "English",
545
- fr: "French",
546
- it: "Italian",
547
- pl: "Polish",
548
- es: "Spanish",
549
- pt: "Portuguese",
550
- de: "German",
551
- de_at: "German (Austria)",
552
- nl: "Dutch",
553
- sv: "Swedish",
554
- hu: "Hungarian",
555
- cs: "Czech",
556
- ja: "Japanese",
557
- zh_hk: "Chinese (Hong Kong)",
558
- zh_cn: "Chinese (Simplified)",
559
- ko: "Korean",
560
- ru: "Russian",
561
- ar: "Arabic",
562
- he: "Hebrew",
563
- tr: "Turkish",
564
- da: "Danish",
565
- fi: "Finnish",
566
- no: "Norwegian",
567
- pt_br: "Portuguese (Brazil)"
568
- };
569
- return names[code] || code;
676
+ async function translateBatch(texts, targetLang, sourceLang = "en", apiKey, delayMs = 100) {
677
+ const provider = getTranslationProvider();
678
+ return provider.translateBatch(texts, sourceLang, targetLang, apiKey, delayMs);
570
679
  }
571
680
 
572
681
  // src/translations/cli/add-key.ts
573
- import * as path4 from "path";
574
682
  init_utils();
575
683
  init_init();
576
684
  async function addTranslationKey(projectRoot, options) {
577
685
  const config = loadConfig(projectRoot);
578
- const translationsPath = path4.join(projectRoot, config.translationsPath);
686
+ const translationsPath = path3.join(projectRoot, config.translationsPath);
579
687
  const { namespace, key, value, autoTranslate = false, apiKey } = options;
580
688
  console.log("=====");
581
689
  console.log("Adding translation key");
@@ -656,13 +764,18 @@ async function addTranslationKeys(projectRoot, entries, autoTranslate = false, a
656
764
  }
657
765
  }
658
766
 
767
+ // src/translations/cli/auto-fill.ts
768
+ import * as path5 from "path";
769
+ init_utils();
770
+ init_init();
771
+
659
772
  // src/translations/cli/validate.ts
660
773
  init_utils();
661
774
  init_init();
662
- import * as path5 from "path";
775
+ import * as path4 from "path";
663
776
  function validateTranslations(projectRoot = process.cwd()) {
664
777
  const config = loadConfig(projectRoot);
665
- const translationsPath = path5.join(projectRoot, config.translationsPath);
778
+ const translationsPath = path4.join(projectRoot, config.translationsPath);
666
779
  const sourceLanguage = config.sourceLanguage;
667
780
  const missing = [];
668
781
  const empty = [];
@@ -739,12 +852,9 @@ function getMissingForLanguage(projectRoot, language) {
739
852
  }
740
853
 
741
854
  // src/translations/cli/auto-fill.ts
742
- import * as path6 from "path";
743
- init_utils();
744
- init_init();
745
855
  async function autoFillTranslations(projectRoot = process.cwd(), options = {}) {
746
856
  const config = loadConfig(projectRoot);
747
- const translationsPath = path6.join(projectRoot, config.translationsPath);
857
+ const translationsPath = path5.join(projectRoot, config.translationsPath);
748
858
  const { apiKey, limit = 1e3, delayMs = 100, dryRun = false } = options;
749
859
  if (!apiKey) {
750
860
  throw new Error("Google Translate API key is required. Set GOOGLE_TRANSLATE_API_KEY or pass --api-key");
@@ -813,7 +923,7 @@ Processing language: ${language}`);
813
923
  }
814
924
  async function fillNamespace(projectRoot, language, namespace, apiKey) {
815
925
  const config = loadConfig(projectRoot);
816
- const translationsPath = path6.join(projectRoot, config.translationsPath);
926
+ const translationsPath = path5.join(projectRoot, config.translationsPath);
817
927
  console.log(`Filling translations for ${language}/${namespace}.json`);
818
928
  const sourceTranslations = readTranslations(translationsPath, config.sourceLanguage);
819
929
  const targetTranslations = readTranslations(translationsPath, language);
@@ -845,7 +955,7 @@ init_utils();
845
955
  init_init();
846
956
  import { execSync } from "child_process";
847
957
  import * as fs3 from "fs";
848
- import * as path7 from "path";
958
+ import * as path6 from "path";
849
959
  var typeTemplate = (translationKeys, namespaceKeys) => `
850
960
  export const translationKeys = [${translationKeys.map((key) => `"${key}"`).join(", ")}] as const;
851
961
  export const namespaceKeys = [${namespaceKeys.map((key) => `"${key}"`).join(", ")}] as const;
@@ -859,10 +969,10 @@ function generateTranslationTypes(projectRoot = process.cwd()) {
859
969
  console.log("Generating i18n types");
860
970
  console.log("=====");
861
971
  const config = loadConfig(projectRoot);
862
- const translationsPath = path7.join(projectRoot, config.translationsPath);
972
+ const translationsPath = path6.join(projectRoot, config.translationsPath);
863
973
  const sourceLanguage = config.sourceLanguage;
864
- const outputFilePath = path7.join(projectRoot, config.typesOutputPath);
865
- const dirPath = path7.join(translationsPath, sourceLanguage);
974
+ const outputFilePath = path6.join(projectRoot, config.typesOutputPath);
975
+ const dirPath = path6.join(translationsPath, sourceLanguage);
866
976
  if (!fs3.existsSync(dirPath)) {
867
977
  throw new Error(`Source language directory not found: ${dirPath}`);
868
978
  }
@@ -876,7 +986,7 @@ function generateTranslationTypes(projectRoot = process.cwd()) {
876
986
  const keys = Object.keys(translations[namespace] || {});
877
987
  allKeys = allKeys.concat(keys);
878
988
  }
879
- const outputDir = path7.dirname(outputFilePath);
989
+ const outputDir = path6.dirname(outputFilePath);
880
990
  if (!fs3.existsSync(outputDir)) {
881
991
  fs3.mkdirSync(outputDir, { recursive: true });
882
992
  }
@@ -885,7 +995,10 @@ function generateTranslationTypes(projectRoot = process.cwd()) {
885
995
  console.log(`Generated types with ${allKeys.length} keys and ${namespaces.length} namespaces`);
886
996
  console.log(`Output: ${outputFilePath}`);
887
997
  try {
888
- execSync(`pnpm biome format --write ${outputFilePath}`, { stdio: "inherit", cwd: projectRoot });
998
+ execSync(`pnpm biome format --write ${outputFilePath}`, {
999
+ stdio: "inherit",
1000
+ cwd: projectRoot
1001
+ });
889
1002
  } catch {
890
1003
  console.warn("Failed to format with Biome, continuing without formatting...");
891
1004
  }
@@ -893,6 +1006,166 @@ function generateTranslationTypes(projectRoot = process.cwd()) {
893
1006
  console.log("=====");
894
1007
  }
895
1008
 
1009
+ // src/translations/index.ts
1010
+ init_init();
1011
+
1012
+ // src/translations/cli/init-interactive.ts
1013
+ init_schema();
1014
+ init_types();
1015
+ init_init();
1016
+ import * as path7 from "path";
1017
+ import { checkbox, confirm, input } from "@inquirer/prompts";
1018
+ async function initTranslationsInteractive(projectRoot = process.cwd()) {
1019
+ console.log("\n\u{1F30D} Translation System Setup\n");
1020
+ const configPath = path7.join(projectRoot, ".translationsrc.json");
1021
+ const alreadyExists = __require("fs").existsSync(configPath);
1022
+ if (alreadyExists) {
1023
+ console.log("\u26A0\uFE0F Configuration file already exists at .translationsrc.json\n");
1024
+ const shouldOverwrite = await confirm({
1025
+ message: "Would you like to reconfigure?",
1026
+ default: false
1027
+ });
1028
+ if (!shouldOverwrite) {
1029
+ console.log("\u2713 Keeping existing configuration");
1030
+ return;
1031
+ }
1032
+ }
1033
+ const { detectExistingTranslations: detectExistingTranslations2 } = await Promise.resolve().then(() => (init_init(), init_exports));
1034
+ const existing = detectExistingTranslations2(projectRoot);
1035
+ let translationsPath;
1036
+ let languages;
1037
+ if (existing.path) {
1038
+ console.log(`\u2713 Found existing translations at: ${existing.path}`);
1039
+ const useExisting = await confirm({
1040
+ message: "Use this location?",
1041
+ default: true
1042
+ });
1043
+ if (useExisting) {
1044
+ translationsPath = existing.path;
1045
+ } else {
1046
+ translationsPath = await input({
1047
+ message: "Enter translations directory path:",
1048
+ default: DEFAULT_CONFIG.translationsPath,
1049
+ validate: (value) => {
1050
+ if (!value.trim()) return "Path is required";
1051
+ return true;
1052
+ }
1053
+ });
1054
+ }
1055
+ } else {
1056
+ translationsPath = await input({
1057
+ message: "Where should translations be stored?",
1058
+ default: DEFAULT_CONFIG.translationsPath,
1059
+ validate: (value) => {
1060
+ if (!value.trim()) return "Path is required";
1061
+ return true;
1062
+ }
1063
+ });
1064
+ }
1065
+ if (existing.languages.length > 0) {
1066
+ console.log(`\u2713 Found existing languages: ${existing.languages.join(", ")}`);
1067
+ const useExistingLangs = await confirm({
1068
+ message: "Use these languages?",
1069
+ default: true
1070
+ });
1071
+ if (useExistingLangs) {
1072
+ languages = existing.languages;
1073
+ } else {
1074
+ languages = await selectLanguages();
1075
+ }
1076
+ } else {
1077
+ languages = await selectLanguages();
1078
+ }
1079
+ const sourceLanguage = await input({
1080
+ message: "What is your source language?",
1081
+ default: "en",
1082
+ validate: (value) => {
1083
+ if (!SUPPORTED_LANGUAGES.includes(value)) {
1084
+ return `Invalid language code. Must be one of: ${SUPPORTED_LANGUAGES.join(", ")}`;
1085
+ }
1086
+ if (!languages.includes(value)) {
1087
+ return "Source language must be in the list of supported languages";
1088
+ }
1089
+ return true;
1090
+ }
1091
+ });
1092
+ const typesOutputPath = await input({
1093
+ message: "Where should TypeScript types be generated?",
1094
+ default: DEFAULT_CONFIG.typesOutputPath
1095
+ });
1096
+ console.log("\n\u{1F4CB} Configuration Summary:");
1097
+ console.log(` Translations: ${translationsPath}`);
1098
+ console.log(` Languages: ${languages.join(", ")}`);
1099
+ console.log(` Source: ${sourceLanguage}`);
1100
+ console.log(` Types: ${typesOutputPath}`);
1101
+ const confirmInit = await confirm({
1102
+ message: "\nProceed with initialization?",
1103
+ default: true
1104
+ });
1105
+ if (!confirmInit) {
1106
+ console.log("\u274C Cancelled");
1107
+ return;
1108
+ }
1109
+ const config = {
1110
+ translationsPath,
1111
+ languages,
1112
+ sourceLanguage,
1113
+ typesOutputPath
1114
+ };
1115
+ console.log();
1116
+ initTranslations(projectRoot, config);
1117
+ console.log("\n\u{1F4DD} Configuration saved to: .translationsrc.json");
1118
+ console.log("\n\u{1F4A1} Next steps:");
1119
+ console.log(' 1. Run "translations add" to add your first translation key');
1120
+ console.log(' 2. Run "translations" to validate and generate types');
1121
+ console.log(" 3. Check the .translationsrc.json file for your configuration\n");
1122
+ }
1123
+ async function selectLanguages() {
1124
+ const languageChoices = SUPPORTED_LANGUAGES.map((lang) => ({
1125
+ name: `${lang} - ${getLanguageName(lang)}`,
1126
+ value: lang,
1127
+ checked: lang === "en"
1128
+ // English selected by default
1129
+ }));
1130
+ const selected = await checkbox({
1131
+ message: "Select languages to support (space to select, enter to confirm):",
1132
+ choices: languageChoices,
1133
+ required: true,
1134
+ pageSize: 15,
1135
+ loop: false
1136
+ });
1137
+ return selected;
1138
+ }
1139
+ function getLanguageName(code) {
1140
+ const names = {
1141
+ en: "English",
1142
+ fr: "French",
1143
+ it: "Italian",
1144
+ pl: "Polish",
1145
+ es: "Spanish",
1146
+ pt: "Portuguese",
1147
+ de: "German",
1148
+ de_at: "German (Austria)",
1149
+ nl: "Dutch",
1150
+ sv: "Swedish",
1151
+ hu: "Hungarian",
1152
+ cs: "Czech",
1153
+ ja: "Japanese",
1154
+ zh_hk: "Chinese (Hong Kong)",
1155
+ zh_cn: "Chinese (Simplified)",
1156
+ ko: "Korean",
1157
+ ru: "Russian",
1158
+ ar: "Arabic",
1159
+ he: "Hebrew",
1160
+ tr: "Turkish",
1161
+ da: "Danish",
1162
+ fi: "Finnish",
1163
+ no: "Norwegian",
1164
+ pt_br: "Portuguese (Brazil)"
1165
+ };
1166
+ return names[code] || code;
1167
+ }
1168
+
896
1169
  // src/translations/cli/manage.ts
897
1170
  import * as fs4 from "fs";
898
1171
  import * as path8 from "path";
@@ -982,9 +1255,15 @@ async function manageTranslations(projectRoot = process.cwd(), options = {}) {
982
1255
  }
983
1256
  console.log("=====\n");
984
1257
  }
1258
+
1259
+ // src/translations/index.ts
1260
+ init_schema();
1261
+ init_types();
1262
+ init_utils();
985
1263
  export {
986
1264
  DEFAULT_CONFIG,
987
1265
  DEFAULT_LANGUAGES,
1266
+ GoogleTranslateProvider,
988
1267
  SUPPORTED_LANGUAGES,
989
1268
  TRANSLATION_CONFIG_SCHEMA,
990
1269
  addTranslationKey,
@@ -998,6 +1277,7 @@ export {
998
1277
  getAvailableLanguages,
999
1278
  getMissingForLanguage,
1000
1279
  getNamespaces,
1280
+ getTranslationProvider,
1001
1281
  hasInterpolation,
1002
1282
  initTranslations,
1003
1283
  initTranslationsInteractive,
@@ -1005,6 +1285,8 @@ export {
1005
1285
  loadConfig,
1006
1286
  manageTranslations,
1007
1287
  readTranslations,
1288
+ resetTranslationProvider,
1289
+ setTranslationProvider,
1008
1290
  sortKeys,
1009
1291
  translateBatch,
1010
1292
  translateText,