poly-lexis 0.1.0 → 0.2.1

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