poly-lexis 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1364 @@
1
+ #!/usr/bin/env node
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
5
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
6
+ }) : x)(function(x) {
7
+ if (typeof require !== "undefined") return require.apply(this, arguments);
8
+ throw Error('Dynamic require of "' + x + '" is not supported');
9
+ });
10
+ var __esm = (fn, res) => function __init() {
11
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
12
+ };
13
+ var __export = (target, all) => {
14
+ for (var name in all)
15
+ __defProp(target, name, { get: all[name], enumerable: true });
16
+ };
17
+
18
+ // node_modules/tsup/assets/esm_shims.js
19
+ import path from "path";
20
+ import { fileURLToPath } from "url";
21
+ var init_esm_shims = __esm({
22
+ "node_modules/tsup/assets/esm_shims.js"() {
23
+ "use strict";
24
+ }
25
+ });
26
+
27
+ // src/translations/utils/utils.ts
28
+ import * as fs from "fs";
29
+ import * as path2 from "path";
30
+ function readTranslations(translationsPath, language) {
31
+ const langPath = path2.join(translationsPath, language);
32
+ if (!fs.existsSync(langPath)) {
33
+ return {};
34
+ }
35
+ const files = fs.readdirSync(langPath).filter((f) => f.endsWith(".json"));
36
+ const translations = {};
37
+ for (const file of files) {
38
+ const namespace = path2.basename(file, ".json");
39
+ const filePath = path2.join(langPath, file);
40
+ const content = fs.readFileSync(filePath, "utf-8");
41
+ translations[namespace] = JSON.parse(content);
42
+ }
43
+ return translations;
44
+ }
45
+ function writeTranslation(translationsPath, language, namespace, translations) {
46
+ const langPath = path2.join(translationsPath, language);
47
+ if (!fs.existsSync(langPath)) {
48
+ fs.mkdirSync(langPath, { recursive: true });
49
+ }
50
+ const filePath = path2.join(langPath, `${namespace}.json`);
51
+ fs.writeFileSync(filePath, JSON.stringify(translations, null, 2) + "\n", "utf-8");
52
+ }
53
+ function getAvailableLanguages(translationsPath) {
54
+ if (!fs.existsSync(translationsPath)) {
55
+ return [];
56
+ }
57
+ return fs.readdirSync(translationsPath, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
58
+ }
59
+ function getNamespaces(translationsPath, language) {
60
+ const langPath = path2.join(translationsPath, language);
61
+ if (!fs.existsSync(langPath)) {
62
+ return [];
63
+ }
64
+ return fs.readdirSync(langPath).filter((f) => f.endsWith(".json")).map((f) => path2.basename(f, ".json"));
65
+ }
66
+ function sortKeys(obj) {
67
+ const sorted = {};
68
+ const keys = Object.keys(obj).sort();
69
+ for (const key of keys) {
70
+ sorted[key] = obj[key];
71
+ }
72
+ return sorted;
73
+ }
74
+ function ensureTranslationsStructure(translationsPath, languages) {
75
+ if (!fs.existsSync(translationsPath)) {
76
+ fs.mkdirSync(translationsPath, { recursive: true });
77
+ }
78
+ for (const lang of languages) {
79
+ const langPath = path2.join(translationsPath, lang);
80
+ if (!fs.existsSync(langPath)) {
81
+ fs.mkdirSync(langPath, { recursive: true });
82
+ }
83
+ }
84
+ }
85
+ var init_utils = __esm({
86
+ "src/translations/utils/utils.ts"() {
87
+ "use strict";
88
+ init_esm_shims();
89
+ }
90
+ });
91
+
92
+ // src/translations/core/schema.ts
93
+ function isValidLanguage(lang) {
94
+ return SUPPORTED_LANGUAGES.includes(lang);
95
+ }
96
+ function validateLanguages(languages) {
97
+ const invalid = languages.filter((lang) => !isValidLanguage(lang));
98
+ return {
99
+ valid: invalid.length === 0,
100
+ invalid
101
+ };
102
+ }
103
+ var SUPPORTED_LANGUAGES;
104
+ var init_schema = __esm({
105
+ "src/translations/core/schema.ts"() {
106
+ "use strict";
107
+ init_esm_shims();
108
+ SUPPORTED_LANGUAGES = [
109
+ "en",
110
+ // English
111
+ "fr",
112
+ // French
113
+ "it",
114
+ // Italian
115
+ "pl",
116
+ // Polish
117
+ "es",
118
+ // Spanish
119
+ "pt",
120
+ // Portuguese
121
+ "de",
122
+ // German
123
+ "de_at",
124
+ // German (Austria)
125
+ "nl",
126
+ // Dutch
127
+ "sv",
128
+ // Swedish
129
+ "hu",
130
+ // Hungarian
131
+ "cs",
132
+ // Czech
133
+ "ja",
134
+ // Japanese
135
+ "zh_hk",
136
+ // Chinese (Hong Kong)
137
+ "zh_cn",
138
+ // Chinese (Simplified)
139
+ "ko",
140
+ // Korean
141
+ "ru",
142
+ // Russian
143
+ "ar",
144
+ // Arabic
145
+ "he",
146
+ // Hebrew
147
+ "tr",
148
+ // Turkish
149
+ "da",
150
+ // Danish
151
+ "fi",
152
+ // Finnish
153
+ "no",
154
+ // Norwegian
155
+ "pt_br"
156
+ // Portuguese (Brazil)
157
+ ];
158
+ }
159
+ });
160
+
161
+ // src/translations/core/types.ts
162
+ var DEFAULT_CONFIG, DEFAULT_LANGUAGES;
163
+ var init_types = __esm({
164
+ "src/translations/core/types.ts"() {
165
+ "use strict";
166
+ init_esm_shims();
167
+ DEFAULT_CONFIG = {
168
+ translationsPath: "public/static/locales",
169
+ languages: ["en"],
170
+ sourceLanguage: "en",
171
+ typesOutputPath: "src/types/i18nTypes.ts"
172
+ };
173
+ DEFAULT_LANGUAGES = [
174
+ "en",
175
+ "fr",
176
+ "it",
177
+ "pl",
178
+ "es",
179
+ "pt",
180
+ "de",
181
+ "de_at",
182
+ "nl",
183
+ "sv",
184
+ "hu",
185
+ "cs",
186
+ "ja",
187
+ "zh_hk"
188
+ ];
189
+ }
190
+ });
191
+
192
+ // src/translations/cli/init.ts
193
+ var init_exports = {};
194
+ __export(init_exports, {
195
+ detectExistingTranslations: () => detectExistingTranslations,
196
+ initTranslations: () => initTranslations,
197
+ loadConfig: () => loadConfig
198
+ });
199
+ import * as fs2 from "fs";
200
+ import * as path3 from "path";
201
+ function detectExistingTranslations(projectRoot) {
202
+ const possiblePaths = ["public/static/locales", "public/locales", "src/locales", "locales", "i18n", "translations"];
203
+ for (const possiblePath of possiblePaths) {
204
+ const fullPath = path3.join(projectRoot, possiblePath);
205
+ if (fs2.existsSync(fullPath)) {
206
+ const languages = getAvailableLanguages(fullPath);
207
+ if (languages.length > 0) {
208
+ return { path: possiblePath, languages };
209
+ }
210
+ }
211
+ }
212
+ return { path: null, languages: [] };
213
+ }
214
+ function initTranslations(projectRoot, config = {}) {
215
+ console.log("=====");
216
+ console.log("Initializing translation structure");
217
+ console.log("=====");
218
+ const existing = detectExistingTranslations(projectRoot);
219
+ let finalConfig = { ...DEFAULT_CONFIG, ...config };
220
+ if (existing.path && existing.languages.length > 0) {
221
+ console.log(`\u2713 Detected existing translations at: ${existing.path}`);
222
+ console.log(`\u2713 Found languages: ${existing.languages.join(", ")}`);
223
+ const validation2 = validateLanguages(existing.languages);
224
+ if (!validation2.valid) {
225
+ console.log(`\u26A0\uFE0F Warning: Invalid language codes found: ${validation2.invalid.join(", ")}`);
226
+ console.log("These languages will be skipped.");
227
+ }
228
+ const validLanguages = existing.languages.filter((lang) => !validation2.invalid.includes(lang));
229
+ finalConfig = {
230
+ ...finalConfig,
231
+ translationsPath: existing.path,
232
+ languages: validLanguages.length > 0 ? validLanguages : finalConfig.languages
233
+ };
234
+ }
235
+ const translationsPath = path3.join(projectRoot, finalConfig.translationsPath);
236
+ const languages = finalConfig.languages.length > 0 ? finalConfig.languages : [...DEFAULT_LANGUAGES];
237
+ console.log(`Project root: ${projectRoot}`);
238
+ console.log(`Translations path: ${translationsPath}`);
239
+ console.log(`Languages: ${languages.join(", ")}`);
240
+ console.log("=====");
241
+ const validation = validateLanguages(languages);
242
+ if (!validation.valid) {
243
+ throw new Error(`Invalid language codes: ${validation.invalid.join(", ")}`);
244
+ }
245
+ ensureTranslationsStructure(translationsPath, languages);
246
+ const sourceLanguage = finalConfig.sourceLanguage;
247
+ const sourcePath = path3.join(translationsPath, sourceLanguage);
248
+ const commonPath = path3.join(sourcePath, "common.json");
249
+ if (!fs2.existsSync(commonPath)) {
250
+ const sampleTranslations = {
251
+ LOADING: "Loading",
252
+ SAVE: "Save",
253
+ CANCEL: "Cancel",
254
+ SUBMIT: "Submit",
255
+ ERROR: "Error",
256
+ SUCCESS: "Success"
257
+ };
258
+ fs2.writeFileSync(commonPath, JSON.stringify(sampleTranslations, null, 2) + "\n", "utf-8");
259
+ console.log(`Created sample file: ${commonPath}`);
260
+ }
261
+ for (const lang of languages) {
262
+ if (lang === sourceLanguage) continue;
263
+ const langCommonPath = path3.join(translationsPath, lang, "common.json");
264
+ if (!fs2.existsSync(langCommonPath)) {
265
+ fs2.writeFileSync(langCommonPath, "{}\n", "utf-8");
266
+ console.log(`Created empty file: ${langCommonPath}`);
267
+ }
268
+ }
269
+ const configPath = path3.join(projectRoot, ".translationsrc.json");
270
+ if (!fs2.existsSync(configPath)) {
271
+ const configContent = {
272
+ $schema: "./node_modules/@repo/env-scripts/dist/translations/core/translations-config.schema.json",
273
+ translationsPath: finalConfig.translationsPath,
274
+ languages,
275
+ sourceLanguage,
276
+ typesOutputPath: finalConfig.typesOutputPath
277
+ };
278
+ fs2.writeFileSync(configPath, JSON.stringify(configContent, null, 2) + "\n", "utf-8");
279
+ console.log(`Created config file: ${configPath}`);
280
+ }
281
+ console.log("=====");
282
+ console.log("Translation structure initialized successfully!");
283
+ console.log("=====");
284
+ }
285
+ function loadConfig(projectRoot) {
286
+ const configPath = path3.join(projectRoot, ".translationsrc.json");
287
+ if (!fs2.existsSync(configPath)) {
288
+ const existing = detectExistingTranslations(projectRoot);
289
+ if (existing.path && existing.languages.length > 0) {
290
+ console.log(`\u2139\uFE0F No config found, but detected translations at ${existing.path}`);
291
+ return {
292
+ ...DEFAULT_CONFIG,
293
+ translationsPath: existing.path,
294
+ languages: existing.languages
295
+ };
296
+ }
297
+ return DEFAULT_CONFIG;
298
+ }
299
+ const configContent = fs2.readFileSync(configPath, "utf-8");
300
+ const config = JSON.parse(configContent);
301
+ if (config.languages) {
302
+ const validation = validateLanguages(config.languages);
303
+ if (!validation.valid) {
304
+ console.warn(`\u26A0\uFE0F Warning: Invalid language codes in config: ${validation.invalid.join(", ")}`);
305
+ console.warn("Please update .translationsrc.json with valid language codes.");
306
+ }
307
+ }
308
+ return { ...DEFAULT_CONFIG, ...config };
309
+ }
310
+ var init_init = __esm({
311
+ "src/translations/cli/init.ts"() {
312
+ "use strict";
313
+ init_esm_shims();
314
+ init_schema();
315
+ init_types();
316
+ init_utils();
317
+ }
318
+ });
319
+
320
+ // src/translations/cli/generate-types.ts
321
+ var generate_types_exports = {};
322
+ __export(generate_types_exports, {
323
+ generateTranslationTypes: () => generateTranslationTypes
324
+ });
325
+ import { execSync } from "child_process";
326
+ import * as fs3 from "fs";
327
+ import * as path8 from "path";
328
+ function generateTranslationTypes(projectRoot = process.cwd()) {
329
+ console.log("=====");
330
+ console.time("i18n types generated");
331
+ console.log("Generating i18n types");
332
+ console.log("=====");
333
+ const config = loadConfig(projectRoot);
334
+ const translationsPath = path8.join(projectRoot, config.translationsPath);
335
+ const sourceLanguage = config.sourceLanguage;
336
+ const outputFilePath = path8.join(projectRoot, config.typesOutputPath);
337
+ const dirPath = path8.join(translationsPath, sourceLanguage);
338
+ if (!fs3.existsSync(dirPath)) {
339
+ throw new Error(`Source language directory not found: ${dirPath}`);
340
+ }
341
+ const namespaces = getNamespaces(translationsPath, sourceLanguage);
342
+ if (namespaces.length === 0) {
343
+ throw new Error(`No translation files found in ${dirPath}`);
344
+ }
345
+ const translations = readTranslations(translationsPath, sourceLanguage);
346
+ let allKeys = [];
347
+ for (const namespace of namespaces) {
348
+ const keys = Object.keys(translations[namespace] || {});
349
+ allKeys = allKeys.concat(keys);
350
+ }
351
+ const outputDir = path8.dirname(outputFilePath);
352
+ if (!fs3.existsSync(outputDir)) {
353
+ fs3.mkdirSync(outputDir, { recursive: true });
354
+ }
355
+ const typeString = typeTemplate(allKeys, namespaces);
356
+ fs3.writeFileSync(outputFilePath, typeString, "utf8");
357
+ console.log(`Generated types with ${allKeys.length} keys and ${namespaces.length} namespaces`);
358
+ console.log(`Output: ${outputFilePath}`);
359
+ try {
360
+ execSync(`pnpm biome format --write ${outputFilePath}`, { stdio: "inherit", cwd: projectRoot });
361
+ } catch {
362
+ console.warn("Failed to format with Biome, continuing without formatting...");
363
+ }
364
+ console.timeEnd("i18n types generated");
365
+ console.log("=====");
366
+ }
367
+ var typeTemplate;
368
+ var init_generate_types = __esm({
369
+ "src/translations/cli/generate-types.ts"() {
370
+ "use strict";
371
+ init_esm_shims();
372
+ init_utils();
373
+ init_init();
374
+ typeTemplate = (translationKeys, namespaceKeys) => `
375
+ export const translationKeys = [${translationKeys.map((key) => `"${key}"`).join(", ")}] as const;
376
+ export const namespaceKeys = [${namespaceKeys.map((key) => `"${key}"`).join(", ")}] as const;
377
+
378
+ export type TranslationKey = typeof translationKeys[number];
379
+ export type TranslationNamespace = typeof namespaceKeys[number];
380
+ `;
381
+ }
382
+ });
383
+
384
+ // src/cli/translations.ts
385
+ init_esm_shims();
386
+ import "dotenv/config";
387
+ import { confirm as confirm2, input as input2, select } from "@inquirer/prompts";
388
+ import * as fs5 from "fs";
389
+ import * as path10 from "path";
390
+ import { parseArgs } from "util";
391
+
392
+ // src/translations/cli/add-key.ts
393
+ init_esm_shims();
394
+ import * as path4 from "path";
395
+
396
+ // src/translations/utils/translator.ts
397
+ init_esm_shims();
398
+ async function translateText(text, targetLang, sourceLang = "en", apiKey) {
399
+ if (!apiKey) {
400
+ throw new Error("Google Translate API key is required. Set GOOGLE_TRANSLATE_API_KEY environment variable.");
401
+ }
402
+ const variableMap = /* @__PURE__ */ new Map();
403
+ let placeholderIndex = 0;
404
+ const textWithPlaceholders = text.replace(/\{\{([^}]+)\}\}/g, (match) => {
405
+ const placeholder = `__PLACEHOLDER_${placeholderIndex}__`;
406
+ variableMap.set(placeholder, match);
407
+ placeholderIndex++;
408
+ return placeholder;
409
+ });
410
+ const url = `https://translation.googleapis.com/language/translate/v2?key=${apiKey}`;
411
+ const response = await fetch(url, {
412
+ method: "POST",
413
+ headers: {
414
+ "Content-Type": "application/json"
415
+ },
416
+ body: JSON.stringify({
417
+ q: textWithPlaceholders,
418
+ source: sourceLang,
419
+ target: targetLang.split("_")[0],
420
+ // Convert 'pt_BR' to 'pt'
421
+ format: "text"
422
+ })
423
+ });
424
+ const data = await response.json();
425
+ if (data.error) {
426
+ throw new Error(`Google Translate API error: ${data.error.message}`);
427
+ }
428
+ let translatedText = data.data.translations[0].translatedText;
429
+ for (const [placeholder, original] of variableMap) {
430
+ translatedText = translatedText.replace(new RegExp(placeholder, "g"), original);
431
+ }
432
+ return translatedText;
433
+ }
434
+
435
+ // src/translations/cli/add-key.ts
436
+ init_utils();
437
+ init_init();
438
+ async function addTranslationKey(projectRoot, options) {
439
+ const config = loadConfig(projectRoot);
440
+ const translationsPath = path4.join(projectRoot, config.translationsPath);
441
+ const { namespace, key, value, autoTranslate = false, apiKey } = options;
442
+ console.log("=====");
443
+ console.log("Adding translation key");
444
+ console.log("=====");
445
+ console.log(`Namespace: ${namespace}`);
446
+ console.log(`Key: ${key}`);
447
+ console.log(`Value (${config.sourceLanguage}): ${value}`);
448
+ console.log("=====");
449
+ const sourceLang = config.sourceLanguage;
450
+ const sourceTranslations = readTranslations(translationsPath, sourceLang);
451
+ if (!sourceTranslations[namespace]) {
452
+ sourceTranslations[namespace] = {};
453
+ }
454
+ if (sourceTranslations[namespace][key]) {
455
+ console.log(`\u26A0 Warning: Key "${key}" already exists in ${namespace}. Updating value.`);
456
+ }
457
+ sourceTranslations[namespace][key] = value;
458
+ const sortedSource = sortKeys(sourceTranslations[namespace]);
459
+ writeTranslation(translationsPath, sourceLang, namespace, sortedSource);
460
+ console.log(`\u2713 Added to ${sourceLang}/${namespace}.json`);
461
+ const otherLanguages = config.languages.filter((lang) => lang !== sourceLang);
462
+ if (autoTranslate && apiKey) {
463
+ console.log("\nAuto-translating to other languages...");
464
+ for (const lang of otherLanguages) {
465
+ try {
466
+ const targetTranslations = readTranslations(translationsPath, lang);
467
+ if (!targetTranslations[namespace]) {
468
+ targetTranslations[namespace] = {};
469
+ }
470
+ if (!targetTranslations[namespace][key] || targetTranslations[namespace][key].trim() === "") {
471
+ const translated = await translateText(value, lang, sourceLang, apiKey);
472
+ targetTranslations[namespace][key] = translated;
473
+ const sorted = sortKeys(targetTranslations[namespace]);
474
+ writeTranslation(translationsPath, lang, namespace, sorted);
475
+ console.log(` \u2713 ${lang}: "${translated}"`);
476
+ await new Promise((resolve) => setTimeout(resolve, 100));
477
+ } else {
478
+ console.log(` - ${lang}: Already exists, skipping`);
479
+ }
480
+ } catch (error) {
481
+ console.error(` \u2717 ${lang}: Translation failed - ${error instanceof Error ? error.message : "Unknown error"}`);
482
+ }
483
+ }
484
+ } else {
485
+ console.log("\nAdding empty values to other languages...");
486
+ for (const lang of otherLanguages) {
487
+ const targetTranslations = readTranslations(translationsPath, lang);
488
+ if (!targetTranslations[namespace]) {
489
+ targetTranslations[namespace] = {};
490
+ }
491
+ if (!targetTranslations[namespace][key]) {
492
+ targetTranslations[namespace][key] = "";
493
+ const sorted = sortKeys(targetTranslations[namespace]);
494
+ writeTranslation(translationsPath, lang, namespace, sorted);
495
+ console.log(` \u2713 ${lang}/${namespace}.json`);
496
+ } else {
497
+ console.log(` - ${lang}/${namespace}.json: Already exists`);
498
+ }
499
+ }
500
+ if (!autoTranslate) {
501
+ console.log("\n\u2139 Use --auto-translate flag to automatically translate to all languages");
502
+ }
503
+ }
504
+ console.log("=====");
505
+ console.log("Translation key added successfully!");
506
+ console.log("=====");
507
+ }
508
+
509
+ // src/cli/translations.ts
510
+ init_init();
511
+
512
+ // src/translations/cli/init-interactive.ts
513
+ init_esm_shims();
514
+ init_schema();
515
+ init_types();
516
+ init_init();
517
+ import * as path5 from "path";
518
+ import { checkbox, confirm, input } from "@inquirer/prompts";
519
+ async function initTranslationsInteractive(projectRoot = process.cwd()) {
520
+ console.log("\n\u{1F30D} Translation System Setup\n");
521
+ const configPath = path5.join(projectRoot, ".translationsrc.json");
522
+ const alreadyExists = __require("fs").existsSync(configPath);
523
+ if (alreadyExists) {
524
+ console.log("\u26A0\uFE0F Configuration file already exists at .translationsrc.json\n");
525
+ const shouldOverwrite = await confirm({
526
+ message: "Would you like to reconfigure?",
527
+ default: false
528
+ });
529
+ if (!shouldOverwrite) {
530
+ console.log("\u2713 Keeping existing configuration");
531
+ return;
532
+ }
533
+ }
534
+ const { detectExistingTranslations: detectExistingTranslations2 } = await Promise.resolve().then(() => (init_init(), init_exports));
535
+ const existing = detectExistingTranslations2(projectRoot);
536
+ let translationsPath;
537
+ let languages;
538
+ if (existing.path) {
539
+ console.log(`\u2713 Found existing translations at: ${existing.path}`);
540
+ const useExisting = await confirm({
541
+ message: "Use this location?",
542
+ default: true
543
+ });
544
+ if (useExisting) {
545
+ translationsPath = existing.path;
546
+ } else {
547
+ translationsPath = await input({
548
+ message: "Enter translations directory path:",
549
+ default: DEFAULT_CONFIG.translationsPath,
550
+ validate: (value) => {
551
+ if (!value.trim()) return "Path is required";
552
+ return true;
553
+ }
554
+ });
555
+ }
556
+ } else {
557
+ translationsPath = await input({
558
+ message: "Where should translations be stored?",
559
+ default: DEFAULT_CONFIG.translationsPath,
560
+ validate: (value) => {
561
+ if (!value.trim()) return "Path is required";
562
+ return true;
563
+ }
564
+ });
565
+ }
566
+ if (existing.languages.length > 0) {
567
+ console.log(`\u2713 Found existing languages: ${existing.languages.join(", ")}`);
568
+ const useExistingLangs = await confirm({
569
+ message: "Use these languages?",
570
+ default: true
571
+ });
572
+ if (useExistingLangs) {
573
+ languages = existing.languages;
574
+ } else {
575
+ languages = await selectLanguages();
576
+ }
577
+ } else {
578
+ languages = await selectLanguages();
579
+ }
580
+ const sourceLanguage = await input({
581
+ message: "What is your source language?",
582
+ default: "en",
583
+ validate: (value) => {
584
+ if (!SUPPORTED_LANGUAGES.includes(value)) {
585
+ return `Invalid language code. Must be one of: ${SUPPORTED_LANGUAGES.join(", ")}`;
586
+ }
587
+ if (!languages.includes(value)) {
588
+ return "Source language must be in the list of supported languages";
589
+ }
590
+ return true;
591
+ }
592
+ });
593
+ const typesOutputPath = await input({
594
+ message: "Where should TypeScript types be generated?",
595
+ default: DEFAULT_CONFIG.typesOutputPath
596
+ });
597
+ console.log("\n\u{1F4CB} Configuration Summary:");
598
+ console.log(` Translations: ${translationsPath}`);
599
+ console.log(` Languages: ${languages.join(", ")}`);
600
+ console.log(` Source: ${sourceLanguage}`);
601
+ console.log(` Types: ${typesOutputPath}`);
602
+ const confirmInit = await confirm({
603
+ message: "\nProceed with initialization?",
604
+ default: true
605
+ });
606
+ if (!confirmInit) {
607
+ console.log("\u274C Cancelled");
608
+ return;
609
+ }
610
+ const config = {
611
+ translationsPath,
612
+ languages,
613
+ sourceLanguage,
614
+ typesOutputPath
615
+ };
616
+ console.log();
617
+ initTranslations(projectRoot, config);
618
+ console.log("\n\u{1F4DD} Configuration saved to: .translationsrc.json");
619
+ console.log("\n\u{1F4A1} Next steps:");
620
+ console.log(' 1. Run "translations add" to add your first translation key');
621
+ console.log(' 2. Run "translations" to validate and generate types');
622
+ console.log(" 3. Check the .translationsrc.json file for your configuration\n");
623
+ }
624
+ async function selectLanguages() {
625
+ const languageChoices = SUPPORTED_LANGUAGES.map((lang) => ({
626
+ name: `${lang} - ${getLanguageName(lang)}`,
627
+ value: lang,
628
+ checked: lang === "en"
629
+ // English selected by default
630
+ }));
631
+ const selected = await checkbox({
632
+ message: "Select languages to support (space to select, enter to confirm):",
633
+ choices: languageChoices,
634
+ required: true,
635
+ pageSize: 15,
636
+ loop: false
637
+ });
638
+ return selected;
639
+ }
640
+ function getLanguageName(code) {
641
+ const names = {
642
+ en: "English",
643
+ fr: "French",
644
+ it: "Italian",
645
+ pl: "Polish",
646
+ es: "Spanish",
647
+ pt: "Portuguese",
648
+ de: "German",
649
+ de_at: "German (Austria)",
650
+ nl: "Dutch",
651
+ sv: "Swedish",
652
+ hu: "Hungarian",
653
+ cs: "Czech",
654
+ ja: "Japanese",
655
+ zh_hk: "Chinese (Hong Kong)",
656
+ zh_cn: "Chinese (Simplified)",
657
+ ko: "Korean",
658
+ ru: "Russian",
659
+ ar: "Arabic",
660
+ he: "Hebrew",
661
+ tr: "Turkish",
662
+ da: "Danish",
663
+ fi: "Finnish",
664
+ no: "Norwegian",
665
+ pt_br: "Portuguese (Brazil)"
666
+ };
667
+ return names[code] || code;
668
+ }
669
+
670
+ // src/translations/cli/manage.ts
671
+ init_esm_shims();
672
+ import * as fs4 from "fs";
673
+ import * as path9 from "path";
674
+
675
+ // src/translations/cli/auto-fill.ts
676
+ init_esm_shims();
677
+ import * as path7 from "path";
678
+ init_utils();
679
+ init_init();
680
+
681
+ // src/translations/cli/validate.ts
682
+ init_esm_shims();
683
+ init_utils();
684
+ init_init();
685
+ import * as path6 from "path";
686
+ function validateTranslations(projectRoot = process.cwd()) {
687
+ const config = loadConfig(projectRoot);
688
+ const translationsPath = path6.join(projectRoot, config.translationsPath);
689
+ const sourceLanguage = config.sourceLanguage;
690
+ const missing = [];
691
+ const empty = [];
692
+ const sourceTranslations = readTranslations(translationsPath, sourceLanguage);
693
+ const sourceNamespaces = getNamespaces(translationsPath, sourceLanguage);
694
+ const languages = getAvailableLanguages(translationsPath).filter((lang) => lang !== sourceLanguage);
695
+ console.log("=====");
696
+ console.log("Validating translations");
697
+ console.log("=====");
698
+ console.log(`Source language: ${sourceLanguage}`);
699
+ console.log(`Target languages: ${languages.join(", ")}`);
700
+ console.log(`Namespaces: ${sourceNamespaces.join(", ")}`);
701
+ console.log("=====");
702
+ for (const language of languages) {
703
+ const targetTranslations = readTranslations(translationsPath, language);
704
+ for (const namespace of sourceNamespaces) {
705
+ const sourceKeys = sourceTranslations[namespace] || {};
706
+ const targetKeys = targetTranslations[namespace] || {};
707
+ for (const [key, sourceValue] of Object.entries(sourceKeys)) {
708
+ const targetValue = targetKeys[key];
709
+ if (targetValue === void 0) {
710
+ missing.push({
711
+ namespace,
712
+ key,
713
+ language,
714
+ sourceValue
715
+ });
716
+ } else if (typeof targetValue === "string" && targetValue.trim() === "") {
717
+ empty.push({
718
+ namespace,
719
+ key,
720
+ language,
721
+ sourceValue
722
+ });
723
+ }
724
+ }
725
+ }
726
+ }
727
+ const valid = missing.length === 0 && empty.length === 0;
728
+ if (valid) {
729
+ console.log("\u2713 All translations are valid!");
730
+ } else {
731
+ if (missing.length > 0) {
732
+ console.log(`
733
+ \u26A0 Found ${missing.length} missing translations:`);
734
+ for (const item of missing.slice(0, 10)) {
735
+ console.log(` ${item.language}/${item.namespace}.json -> ${item.key}`);
736
+ }
737
+ if (missing.length > 10) {
738
+ console.log(` ... and ${missing.length - 10} more`);
739
+ }
740
+ }
741
+ if (empty.length > 0) {
742
+ console.log(`
743
+ \u26A0 Found ${empty.length} empty translations:`);
744
+ for (const item of empty.slice(0, 10)) {
745
+ console.log(` ${item.language}/${item.namespace}.json -> ${item.key}`);
746
+ }
747
+ if (empty.length > 10) {
748
+ console.log(` ... and ${empty.length - 10} more`);
749
+ }
750
+ }
751
+ }
752
+ console.log("=====");
753
+ return { valid, missing, empty };
754
+ }
755
+ function getMissingForLanguage(projectRoot, language) {
756
+ const result = validateTranslations(projectRoot);
757
+ const items = [
758
+ ...result.missing.filter((m) => m.language === language).map((m) => ({ ...m, type: "missing" })),
759
+ ...result.empty.filter((e) => e.language === language).map((e) => ({ ...e, type: "empty" }))
760
+ ];
761
+ return items;
762
+ }
763
+
764
+ // src/translations/cli/auto-fill.ts
765
+ async function autoFillTranslations(projectRoot = process.cwd(), options = {}) {
766
+ const config = loadConfig(projectRoot);
767
+ const translationsPath = path7.join(projectRoot, config.translationsPath);
768
+ const { apiKey, limit = 1e3, delayMs = 100, dryRun = false } = options;
769
+ if (!apiKey) {
770
+ throw new Error("Google Translate API key is required. Set GOOGLE_TRANSLATE_API_KEY or pass --api-key");
771
+ }
772
+ const languagesToProcess = options.language ? [options.language] : config.languages.filter((lang) => lang !== config.sourceLanguage);
773
+ console.log("=====");
774
+ console.log("Auto-filling translations");
775
+ console.log("=====");
776
+ console.log(`Languages: ${languagesToProcess.join(", ")}`);
777
+ console.log(`Limit: ${limit}`);
778
+ console.log(`Dry run: ${dryRun}`);
779
+ console.log("=====");
780
+ let totalProcessed = 0;
781
+ let totalTranslated = 0;
782
+ for (const language of languagesToProcess) {
783
+ if (totalProcessed >= limit) {
784
+ console.log(`
785
+ Reached limit of ${limit} translations`);
786
+ break;
787
+ }
788
+ console.log(`
789
+ Processing language: ${language}`);
790
+ const missing = getMissingForLanguage(projectRoot, language);
791
+ if (missing.length === 0) {
792
+ console.log(" No missing or empty translations");
793
+ continue;
794
+ }
795
+ console.log(` Found ${missing.length} translations to fill`);
796
+ const remainingLimit = limit - totalProcessed;
797
+ const itemsToProcess = missing.slice(0, remainingLimit);
798
+ for (const item of itemsToProcess) {
799
+ totalProcessed++;
800
+ try {
801
+ console.log(` [${totalProcessed}/${limit}] Translating ${item.namespace}.${item.key}`);
802
+ console.log(` EN: "${item.sourceValue}"`);
803
+ const translated = await translateText(item.sourceValue, language, config.sourceLanguage, apiKey);
804
+ console.log(` ${language.toUpperCase()}: "${translated}"`);
805
+ if (!dryRun) {
806
+ const translations = readTranslations(translationsPath, language);
807
+ if (!translations[item.namespace]) {
808
+ translations[item.namespace] = {};
809
+ }
810
+ translations[item.namespace][item.key] = translated;
811
+ const sorted = sortKeys(translations[item.namespace]);
812
+ writeTranslation(translationsPath, language, item.namespace, sorted);
813
+ console.log(" \u2713 Saved");
814
+ } else {
815
+ console.log(" \u2713 Dry run - not saved");
816
+ }
817
+ totalTranslated++;
818
+ if (delayMs > 0 && totalProcessed < limit) {
819
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
820
+ }
821
+ } catch (error) {
822
+ console.error(` \u2717 Error: ${error instanceof Error ? error.message : "Unknown error"}`);
823
+ }
824
+ }
825
+ }
826
+ console.log("\n=====");
827
+ console.log(`Total processed: ${totalProcessed}`);
828
+ console.log(`Total translated: ${totalTranslated}`);
829
+ if (dryRun) {
830
+ console.log("\u26A0 Dry run - no changes were saved");
831
+ }
832
+ console.log("=====");
833
+ }
834
+
835
+ // src/translations/cli/manage.ts
836
+ init_generate_types();
837
+ init_init();
838
+ async function manageTranslations(projectRoot = process.cwd(), options = {}) {
839
+ const { autoFill = false, apiKey, limit = 1e3, language, skipTypes = false, dryRun = false } = options;
840
+ console.log("=====");
841
+ console.log("Translation Management");
842
+ console.log("=====");
843
+ const configPath = path9.join(projectRoot, ".translationsrc.json");
844
+ const isInitialized = fs4.existsSync(configPath);
845
+ if (!isInitialized) {
846
+ console.log("\u{1F4C1} No translation configuration found. Initializing...\n");
847
+ initTranslations(projectRoot);
848
+ console.log("\n\u2705 Initialization complete!\n");
849
+ } else {
850
+ console.log("\u2713 Translation structure initialized\n");
851
+ }
852
+ const config = loadConfig(projectRoot);
853
+ const translationsPath = path9.join(projectRoot, config.translationsPath);
854
+ const sourceLangPath = path9.join(translationsPath, config.sourceLanguage);
855
+ if (!fs4.existsSync(sourceLangPath)) {
856
+ console.log(`\u26A0\uFE0F Source language directory not found: ${sourceLangPath}`);
857
+ console.log("Please add translation files to the source language directory.\n");
858
+ return;
859
+ }
860
+ console.log("\u{1F50D} Validating translations...\n");
861
+ const validationResult = validateTranslations(projectRoot);
862
+ if (validationResult.valid) {
863
+ console.log("\n\u2705 All translations are complete!\n");
864
+ } else {
865
+ const totalMissing = validationResult.missing.length + validationResult.empty.length;
866
+ if (autoFill) {
867
+ if (!apiKey) {
868
+ console.log("\n\u26A0\uFE0F Auto-fill requested but no API key provided.");
869
+ console.log("Set GOOGLE_TRANSLATE_API_KEY or pass --api-key to enable auto-fill.\n");
870
+ } else {
871
+ console.log(`
872
+ \u{1F916} Auto-filling ${totalMissing} missing translations...
873
+ `);
874
+ await autoFillTranslations(projectRoot, {
875
+ apiKey,
876
+ limit,
877
+ language,
878
+ dryRun,
879
+ delayMs: 100
880
+ });
881
+ if (!dryRun) {
882
+ console.log("\n\u{1F50D} Re-validating after auto-fill...\n");
883
+ const revalidation = validateTranslations(projectRoot);
884
+ if (revalidation.valid) {
885
+ console.log("\n\u2705 All translations are now complete!\n");
886
+ }
887
+ }
888
+ }
889
+ } else {
890
+ console.log(`
891
+ \u{1F4A1} Tip: Run with --auto-fill to automatically translate missing keys.
892
+ `);
893
+ }
894
+ }
895
+ if (!skipTypes && !dryRun) {
896
+ console.log("\u{1F4DD} Generating TypeScript types...\n");
897
+ generateTranslationTypes(projectRoot);
898
+ console.log("\n\u2705 Types generated!\n");
899
+ } else if (skipTypes) {
900
+ console.log("\u23ED\uFE0F Skipping type generation (--skip-types)\n");
901
+ } else if (dryRun) {
902
+ console.log("\u23ED\uFE0F Skipping type generation (--dry-run)\n");
903
+ }
904
+ console.log("=====");
905
+ console.log("Summary");
906
+ console.log("=====");
907
+ console.log(`Configuration: ${configPath}`);
908
+ console.log(`Translations: ${translationsPath}`);
909
+ console.log(`Languages: ${config.languages.join(", ")}`);
910
+ console.log(`Source language: ${config.sourceLanguage}`);
911
+ if (!validationResult.valid && !autoFill) {
912
+ console.log(`
913
+ \u26A0\uFE0F ${validationResult.missing.length} missing translations`);
914
+ console.log(`\u26A0\uFE0F ${validationResult.empty.length} empty translations`);
915
+ console.log("\nNext steps:");
916
+ console.log(" 1. Add missing translations manually, or");
917
+ console.log(" 2. Run with --auto-fill to translate automatically");
918
+ } else if (validationResult.valid) {
919
+ console.log("\n\u2705 All systems ready!");
920
+ }
921
+ console.log("=====\n");
922
+ }
923
+
924
+ // src/cli/translations.ts
925
+ init_utils();
926
+ var { values, positionals } = parseArgs({
927
+ options: {
928
+ "auto-fill": {
929
+ type: "boolean",
930
+ short: "a",
931
+ default: false
932
+ },
933
+ "api-key": {
934
+ type: "string"
935
+ },
936
+ limit: {
937
+ type: "string",
938
+ default: "1000"
939
+ },
940
+ language: {
941
+ type: "string",
942
+ short: "l"
943
+ },
944
+ "skip-types": {
945
+ type: "boolean",
946
+ default: false
947
+ },
948
+ "dry-run": {
949
+ type: "boolean",
950
+ short: "d",
951
+ default: false
952
+ },
953
+ namespace: {
954
+ type: "string",
955
+ short: "n"
956
+ },
957
+ key: {
958
+ type: "string",
959
+ short: "k"
960
+ },
961
+ value: {
962
+ type: "string",
963
+ short: "v"
964
+ },
965
+ help: {
966
+ type: "boolean",
967
+ short: "h"
968
+ }
969
+ },
970
+ allowPositionals: true
971
+ });
972
+ if (values.help) {
973
+ console.log(`
974
+ Usage: translations [command] [options]
975
+
976
+ Smart translation management - automatically handles initialization, validation,
977
+ auto-filling, and type generation based on your project's current state.
978
+
979
+ Commands:
980
+ (none) Smart mode - validates, fills, and generates types
981
+ add Add a new translation key
982
+
983
+ Options (Smart Mode):
984
+ -a, --auto-fill Auto-fill missing translations with Google Translate
985
+ --api-key <key> Google Translate API key (or set GOOGLE_TRANSLATE_API_KEY)
986
+ -l, --language <lang> Process only this language
987
+ --limit <number> Max translations to process (default: 1000)
988
+ --skip-types Skip TypeScript type generation
989
+ -d, --dry-run Preview changes without saving
990
+ -h, --help Show this help
991
+
992
+ Options (Add Mode):
993
+ -n, --namespace <name> Namespace for the translation
994
+ -k, --key <key> Translation key
995
+ -v, --value <value> Translation value in source language
996
+ -a, --auto-fill Auto-translate to all languages
997
+
998
+ (no options) Interactive mode - prompts for all inputs
999
+
1000
+ Examples:
1001
+ # Smart mode - check and validate translations
1002
+ translations
1003
+
1004
+ # Smart mode - validate and auto-fill missing translations
1005
+ export GOOGLE_TRANSLATE_API_KEY=your_key
1006
+ translations --auto-fill
1007
+
1008
+ # Smart mode - auto-fill only French translations
1009
+ translations --auto-fill --language fr
1010
+
1011
+ # Preview what would be translated (dry-run)
1012
+ translations --auto-fill --dry-run
1013
+
1014
+ # Add a new translation key (interactive mode)
1015
+ translations add
1016
+
1017
+ # Add with flags (non-interactive)
1018
+ translations add --namespace common --key HELLO --value "Hello"
1019
+
1020
+ # Add with auto-translation
1021
+ translations add -n common -k WELCOME -v "Welcome" --auto-fill
1022
+
1023
+ What happens in smart mode:
1024
+ 1. Checks if translations are initialized (creates .translationsrc.json if needed)
1025
+ 2. Validates all translations against source language
1026
+ 3. Auto-fills missing translations if --auto-fill is provided
1027
+ 4. Generates TypeScript types (unless --skip-types)
1028
+ 5. Shows summary and next steps
1029
+ `);
1030
+ process.exit(0);
1031
+ }
1032
+ var command = positionals[0];
1033
+ if (command === "add") {
1034
+ if (!values.namespace && !values.key && !values.value) {
1035
+ (async () => {
1036
+ try {
1037
+ console.log("\n\u2728 Add a new translation key\n");
1038
+ const configPath = path10.join(process.cwd(), ".translationsrc.json");
1039
+ const isInitialized = fs5.existsSync(configPath);
1040
+ if (!isInitialized) {
1041
+ console.log("\u26A0\uFE0F Translation structure not initialized.");
1042
+ const shouldInit = await confirm2({
1043
+ message: "Would you like to initialize it now?",
1044
+ default: true
1045
+ });
1046
+ if (shouldInit) {
1047
+ await initTranslationsInteractive(process.cwd());
1048
+ console.log();
1049
+ } else {
1050
+ console.log("\u274C Cannot add translations without initialization.");
1051
+ process.exit(1);
1052
+ }
1053
+ }
1054
+ const config = loadConfig(process.cwd());
1055
+ const translationsPath = path10.join(process.cwd(), config.translationsPath);
1056
+ const existingNamespaces = getNamespaces(translationsPath, config.sourceLanguage);
1057
+ let namespace;
1058
+ if (existingNamespaces.length > 0) {
1059
+ const namespaceChoice = await select({
1060
+ message: "Select namespace:",
1061
+ choices: [
1062
+ ...existingNamespaces.map((ns) => ({ name: ns, value: ns })),
1063
+ { name: "\u2795 Create new namespace", value: "__new__" }
1064
+ ]
1065
+ });
1066
+ if (namespaceChoice === "__new__") {
1067
+ namespace = await input2({
1068
+ message: "Enter new namespace name:",
1069
+ validate: (value2) => {
1070
+ if (!value2.trim()) return "Namespace is required";
1071
+ if (!/^[a-z0-9-]+$/.test(value2)) {
1072
+ return "Namespace must contain only lowercase letters, numbers, and hyphens";
1073
+ }
1074
+ return true;
1075
+ }
1076
+ });
1077
+ } else {
1078
+ namespace = namespaceChoice;
1079
+ }
1080
+ } else {
1081
+ namespace = await input2({
1082
+ message: "Enter namespace name (e.g., common, members):",
1083
+ default: "common",
1084
+ validate: (value2) => {
1085
+ if (!value2.trim()) return "Namespace is required";
1086
+ if (!/^[a-z0-9-]+$/.test(value2)) {
1087
+ return "Namespace must contain only lowercase letters, numbers, and hyphens";
1088
+ }
1089
+ return true;
1090
+ }
1091
+ });
1092
+ }
1093
+ const key = await input2({
1094
+ message: "Enter translation key (UPPERCASE_SNAKE_CASE):",
1095
+ validate: (value2) => {
1096
+ if (!value2.trim()) return "Key is required";
1097
+ if (!/^[A-Z0-9_]+$/.test(value2)) {
1098
+ return "Key should use UPPERCASE_SNAKE_CASE (e.g., SAVE_CHANGES)";
1099
+ }
1100
+ return true;
1101
+ },
1102
+ transformer: (value2) => value2.toUpperCase()
1103
+ });
1104
+ const value = await input2({
1105
+ message: `Enter ${config.sourceLanguage.toUpperCase()} translation:`,
1106
+ validate: (value2) => {
1107
+ if (!value2.trim()) return "Translation value is required";
1108
+ return true;
1109
+ }
1110
+ });
1111
+ const autoTranslate = await confirm2({
1112
+ message: `Auto-translate to ${config.languages.length - 1} other languages?`,
1113
+ default: true
1114
+ });
1115
+ let apiKey;
1116
+ if (autoTranslate) {
1117
+ apiKey = values["api-key"] || process.env.GOOGLE_TRANSLATE_API_KEY;
1118
+ if (!apiKey) {
1119
+ console.log("\n\u26A0\uFE0F GOOGLE_TRANSLATE_API_KEY environment variable not found.");
1120
+ console.log("Skipping auto-translation. Set this variable to enable auto-translation.\n");
1121
+ }
1122
+ }
1123
+ console.log();
1124
+ await addTranslationKey(process.cwd(), {
1125
+ namespace,
1126
+ key: key.toUpperCase(),
1127
+ value,
1128
+ autoTranslate: autoTranslate && !!apiKey,
1129
+ apiKey
1130
+ });
1131
+ console.log('\n\u{1F4A1} Run "translations" to validate and generate types');
1132
+ } catch (error) {
1133
+ if (error.message === "User force closed the prompt") {
1134
+ console.log("\n\u274C Cancelled");
1135
+ process.exit(0);
1136
+ }
1137
+ console.error("Error:", error instanceof Error ? error.message : error);
1138
+ process.exit(1);
1139
+ }
1140
+ })();
1141
+ } else {
1142
+ if (!values.namespace || !values.key || !values.value) {
1143
+ console.error("Error: --namespace, --key, and --value are required for add command");
1144
+ console.log("Use --help for usage information");
1145
+ process.exit(1);
1146
+ }
1147
+ const apiKey = values["api-key"] || process.env.GOOGLE_TRANSLATE_API_KEY;
1148
+ if (values["auto-fill"] && !apiKey) {
1149
+ console.error(
1150
+ "Error: --api-key or GOOGLE_TRANSLATE_API_KEY environment variable is required for auto-translation"
1151
+ );
1152
+ process.exit(1);
1153
+ }
1154
+ addTranslationKey(process.cwd(), {
1155
+ namespace: values.namespace,
1156
+ key: values.key,
1157
+ value: values.value,
1158
+ autoTranslate: values["auto-fill"],
1159
+ apiKey
1160
+ }).then(() => {
1161
+ console.log('\n\u{1F4A1} Run "translations" to validate and generate types');
1162
+ }).catch((error) => {
1163
+ console.error("Error:", error instanceof Error ? error.message : error);
1164
+ process.exit(1);
1165
+ });
1166
+ }
1167
+ } else if (command) {
1168
+ console.error(`Unknown command: ${command}`);
1169
+ console.log("Use --help for usage information");
1170
+ process.exit(1);
1171
+ } else {
1172
+ const hasFlags = values["auto-fill"] || values.language || values["skip-types"] || values["dry-run"];
1173
+ if (hasFlags) {
1174
+ const apiKey = values["api-key"] || process.env.GOOGLE_TRANSLATE_API_KEY;
1175
+ const limit = Number.parseInt(values.limit || "1000", 10);
1176
+ manageTranslations(process.cwd(), {
1177
+ autoFill: values["auto-fill"],
1178
+ apiKey,
1179
+ limit,
1180
+ language: values.language,
1181
+ skipTypes: values["skip-types"],
1182
+ dryRun: values["dry-run"]
1183
+ }).catch((error) => {
1184
+ console.error("Error:", error instanceof Error ? error.message : error);
1185
+ process.exit(1);
1186
+ });
1187
+ } else {
1188
+ (async () => {
1189
+ try {
1190
+ const configPath = path10.join(process.cwd(), ".translationsrc.json");
1191
+ const isInitialized = fs5.existsSync(configPath);
1192
+ console.log("\n\u{1F30D} Translation Management\n");
1193
+ const action = await select({
1194
+ message: "What would you like to do?",
1195
+ choices: [
1196
+ {
1197
+ name: "\u2728 Add a new translation key",
1198
+ value: "add",
1199
+ description: "Add a translation key to all languages"
1200
+ },
1201
+ {
1202
+ name: "\u{1F50D} Validate translations",
1203
+ value: "validate",
1204
+ description: "Check for missing or empty translations"
1205
+ },
1206
+ {
1207
+ name: "\u{1F916} Auto-fill missing translations",
1208
+ value: "autofill",
1209
+ description: "Automatically translate missing keys with Google Translate"
1210
+ },
1211
+ {
1212
+ name: "\u{1F4DD} Generate TypeScript types",
1213
+ value: "types",
1214
+ description: "Generate types from translation files"
1215
+ },
1216
+ {
1217
+ name: "\u2699\uFE0F Initialize/reconfigure",
1218
+ value: "init",
1219
+ description: "Set up or change translation configuration"
1220
+ },
1221
+ {
1222
+ name: "\u{1F4CA} Full check (validate + types)",
1223
+ value: "full",
1224
+ description: "Validate translations and generate types"
1225
+ }
1226
+ ]
1227
+ });
1228
+ console.log();
1229
+ if (action === "add") {
1230
+ if (!isInitialized) {
1231
+ console.log("\u26A0\uFE0F Translation structure not initialized.");
1232
+ const shouldInit = await confirm2({
1233
+ message: "Would you like to initialize it now?",
1234
+ default: true
1235
+ });
1236
+ if (shouldInit) {
1237
+ await initTranslationsInteractive(process.cwd());
1238
+ console.log();
1239
+ } else {
1240
+ console.log("\u274C Cannot add translations without initialization.");
1241
+ process.exit(1);
1242
+ }
1243
+ }
1244
+ const config = loadConfig(process.cwd());
1245
+ const translationsPath = path10.join(process.cwd(), config.translationsPath);
1246
+ const existingNamespaces = getNamespaces(translationsPath, config.sourceLanguage);
1247
+ let namespace;
1248
+ if (existingNamespaces.length > 0) {
1249
+ const namespaceChoice = await select({
1250
+ message: "Select namespace:",
1251
+ choices: [
1252
+ ...existingNamespaces.map((ns) => ({ name: ns, value: ns })),
1253
+ { name: "\u2795 Create new namespace", value: "__new__" }
1254
+ ]
1255
+ });
1256
+ if (namespaceChoice === "__new__") {
1257
+ namespace = await input2({
1258
+ message: "Enter new namespace name:",
1259
+ validate: (value2) => {
1260
+ if (!value2.trim()) return "Namespace is required";
1261
+ if (!/^[a-z0-9-]+$/.test(value2)) {
1262
+ return "Namespace must contain only lowercase letters, numbers, and hyphens";
1263
+ }
1264
+ return true;
1265
+ }
1266
+ });
1267
+ } else {
1268
+ namespace = namespaceChoice;
1269
+ }
1270
+ } else {
1271
+ namespace = await input2({
1272
+ message: "Enter namespace name (e.g., common, members):",
1273
+ default: "common",
1274
+ validate: (value2) => {
1275
+ if (!value2.trim()) return "Namespace is required";
1276
+ if (!/^[a-z0-9-]+$/.test(value2)) {
1277
+ return "Namespace must contain only lowercase letters, numbers, and hyphens";
1278
+ }
1279
+ return true;
1280
+ }
1281
+ });
1282
+ }
1283
+ const key = await input2({
1284
+ message: "Enter translation key (UPPERCASE_SNAKE_CASE):",
1285
+ validate: (value2) => {
1286
+ if (!value2.trim()) return "Key is required";
1287
+ if (!/^[A-Z0-9_]+$/.test(value2)) {
1288
+ return "Key should use UPPERCASE_SNAKE_CASE (e.g., SAVE_CHANGES)";
1289
+ }
1290
+ return true;
1291
+ },
1292
+ transformer: (value2) => value2.toUpperCase()
1293
+ });
1294
+ const value = await input2({
1295
+ message: `Enter ${config.sourceLanguage.toUpperCase()} translation:`,
1296
+ validate: (value2) => {
1297
+ if (!value2.trim()) return "Translation value is required";
1298
+ return true;
1299
+ }
1300
+ });
1301
+ const autoTranslate = await confirm2({
1302
+ message: `Auto-translate to ${config.languages.length - 1} other languages?`,
1303
+ default: true
1304
+ });
1305
+ let apiKey;
1306
+ if (autoTranslate) {
1307
+ apiKey = process.env.GOOGLE_TRANSLATE_API_KEY;
1308
+ if (!apiKey) {
1309
+ console.log("\n\u26A0\uFE0F GOOGLE_TRANSLATE_API_KEY environment variable not found.");
1310
+ console.log("Skipping auto-translation. Set this variable to enable auto-translation.\n");
1311
+ }
1312
+ }
1313
+ console.log();
1314
+ await addTranslationKey(process.cwd(), {
1315
+ namespace,
1316
+ key: key.toUpperCase(),
1317
+ value,
1318
+ autoTranslate: autoTranslate && !!apiKey,
1319
+ apiKey
1320
+ });
1321
+ console.log('\n\u{1F4A1} Run "translations" again to validate and generate types');
1322
+ } else if (action === "init") {
1323
+ await initTranslationsInteractive(process.cwd());
1324
+ } else if (action === "validate") {
1325
+ await manageTranslations(process.cwd(), {
1326
+ skipTypes: true
1327
+ });
1328
+ } else if (action === "autofill") {
1329
+ const apiKey = process.env.GOOGLE_TRANSLATE_API_KEY;
1330
+ if (!apiKey) {
1331
+ console.log("\u26A0\uFE0F GOOGLE_TRANSLATE_API_KEY environment variable not found.");
1332
+ console.log("Please set it to enable auto-translation.\n");
1333
+ process.exit(1);
1334
+ }
1335
+ const shouldContinue = await confirm2({
1336
+ message: "This will auto-translate all missing keys. Continue?",
1337
+ default: true
1338
+ });
1339
+ if (shouldContinue) {
1340
+ await manageTranslations(process.cwd(), {
1341
+ autoFill: true,
1342
+ apiKey
1343
+ });
1344
+ }
1345
+ } else if (action === "types") {
1346
+ console.log("\u{1F4DD} Generating TypeScript types...\n");
1347
+ const { generateTranslationTypes: generateTranslationTypes2 } = await Promise.resolve().then(() => (init_generate_types(), generate_types_exports));
1348
+ generateTranslationTypes2(process.cwd());
1349
+ console.log("\n\u2705 Types generated!\n");
1350
+ } else if (action === "full") {
1351
+ await manageTranslations(process.cwd());
1352
+ }
1353
+ } catch (error) {
1354
+ if (error.message === "User force closed the prompt") {
1355
+ console.log("\n\u274C Cancelled");
1356
+ process.exit(0);
1357
+ }
1358
+ console.error("Error:", error instanceof Error ? error.message : error);
1359
+ process.exit(1);
1360
+ }
1361
+ })();
1362
+ }
1363
+ }
1364
+ //# sourceMappingURL=translations.js.map