@intl-party/cli 1.0.0 → 1.1.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.
Files changed (5) hide show
  1. package/LICENSE +2 -2
  2. package/README.md +413 -0
  3. package/dist/cli.js +1267 -163
  4. package/dist/index.js +909 -46
  5. package/package.json +14 -6
package/dist/index.js CHANGED
@@ -51,7 +51,7 @@ var import_core = require("@intl-party/core");
51
51
 
52
52
  // src/utils/config.ts
53
53
  var import_fs_extra = __toESM(require("fs-extra"));
54
- var import_path = __toESM(require("path"));
54
+ var import_node_path = __toESM(require("path"));
55
55
  var DEFAULT_CONFIG = {
56
56
  locales: ["en", "es", "fr"],
57
57
  defaultLocale: "en",
@@ -95,8 +95,8 @@ async function loadConfig(configPath) {
95
95
  const content = await import_fs_extra.default.readFile(configFile, "utf-8");
96
96
  config = JSON.parse(content);
97
97
  } else {
98
- delete require.cache[import_path.default.resolve(configFile)];
99
- config = require(import_path.default.resolve(configFile));
98
+ delete require.cache[import_node_path.default.resolve(configFile)];
99
+ config = require(import_node_path.default.resolve(configFile));
100
100
  if (config.default) {
101
101
  config = config.default;
102
102
  }
@@ -138,20 +138,20 @@ async function autoDetectConfig() {
138
138
  try {
139
139
  const entries = await import_fs_extra.default.readdir(basePath);
140
140
  const locales = entries.filter(
141
- (entry) => import_fs_extra.default.statSync(import_path.default.join(basePath, entry)).isDirectory()
141
+ (entry) => import_fs_extra.default.statSync(import_node_path.default.join(basePath, entry)).isDirectory()
142
142
  );
143
143
  if (locales.length > 0) {
144
144
  config.locales = locales;
145
145
  config.translationPaths = {};
146
- const firstLocaleDir = import_path.default.join(basePath, locales[0]);
146
+ const firstLocaleDir = import_node_path.default.join(basePath, locales[0]);
147
147
  const namespaceFiles = await import_fs_extra.default.readdir(firstLocaleDir);
148
- const namespaces = namespaceFiles.filter((file) => file.endsWith(".json")).map((file) => import_path.default.basename(file, ".json"));
148
+ const namespaces = namespaceFiles.filter((file) => file.endsWith(".json")).map((file) => import_node_path.default.basename(file, ".json"));
149
149
  if (namespaces.length > 0) {
150
150
  config.namespaces = namespaces;
151
151
  for (const locale of locales) {
152
152
  config.translationPaths[locale] = {};
153
153
  for (const namespace of namespaces) {
154
- config.translationPaths[locale][namespace] = import_path.default.join(
154
+ config.translationPaths[locale][namespace] = import_node_path.default.join(
155
155
  basePath,
156
156
  locale,
157
157
  `${namespace}.json`
@@ -168,7 +168,7 @@ async function autoDetectConfig() {
168
168
  return config;
169
169
  }
170
170
  function mergeConfig(defaultConfig, userConfig) {
171
- return {
171
+ const merged = {
172
172
  ...defaultConfig,
173
173
  ...userConfig,
174
174
  validation: {
@@ -188,6 +188,15 @@ function mergeConfig(defaultConfig, userConfig) {
188
188
  ...userConfig.translationPaths
189
189
  }
190
190
  };
191
+ if (userConfig.messages && !userConfig.outputDir) {
192
+ merged.outputDir = userConfig.messages;
193
+ }
194
+ if (userConfig.sourceDir && !userConfig.sourcePatterns) {
195
+ merged.sourcePatterns = [
196
+ import_node_path.default.join(userConfig.sourceDir, "**/*.{ts,tsx,js,jsx}")
197
+ ];
198
+ }
199
+ return merged;
191
200
  }
192
201
  async function saveConfig(config, configPath = "intl-party.config.json") {
193
202
  await import_fs_extra.default.writeFile(configPath, JSON.stringify(config, null, 2));
@@ -195,7 +204,7 @@ async function saveConfig(config, configPath = "intl-party.config.json") {
195
204
 
196
205
  // src/utils/translations.ts
197
206
  var import_fs_extra2 = __toESM(require("fs-extra"));
198
- var import_path2 = __toESM(require("path"));
207
+ var import_node_path2 = __toESM(require("path"));
199
208
  async function loadTranslations(translationPaths, locales, namespaces) {
200
209
  const translations = {};
201
210
  for (const locale of locales) {
@@ -226,7 +235,7 @@ async function saveTranslations(translations, translationPaths) {
226
235
  )) {
227
236
  const translationPath = translationPaths[locale]?.[namespace];
228
237
  if (translationPath) {
229
- await import_fs_extra2.default.ensureDir(import_path2.default.dirname(translationPath));
238
+ await import_fs_extra2.default.ensureDir(import_node_path2.default.dirname(translationPath));
230
239
  await import_fs_extra2.default.writeJson(translationPath, namespaceTranslations, {
231
240
  spaces: 2
232
241
  });
@@ -398,12 +407,22 @@ var import_chalk2 = __toESM(require("chalk"));
398
407
  var import_ora2 = __toESM(require("ora"));
399
408
  var import_glob = require("glob");
400
409
  var import_fs_extra4 = __toESM(require("fs-extra"));
401
- var import_path3 = __toESM(require("path"));
410
+ var import_node_path3 = __toESM(require("path"));
402
411
  async function extractCommand(options) {
403
- const spinner = (0, import_ora2.default)("Extracting translation keys...").start();
412
+ const spinner = (0, import_ora2.default)("Loading configuration...").start();
413
+ let config;
404
414
  try {
405
- const sourcePatterns = options.source || ["src/**/*.{ts,tsx,js,jsx}"];
406
- const outputDir = options.output || "./translations";
415
+ config = await loadConfig(options.config);
416
+ spinner.succeed("Configuration loaded");
417
+ } catch (error) {
418
+ spinner.fail("Failed to load configuration");
419
+ console.error(import_chalk2.default.red("Error:"), error instanceof Error ? error.message : error);
420
+ process.exit(1);
421
+ }
422
+ spinner.start("Extracting translation keys...");
423
+ try {
424
+ const sourcePatterns = options.source || config.sourcePatterns || ["src/**/*.{ts,tsx,js,jsx}"];
425
+ const outputDir = options.output || config.outputDir || "./messages";
407
426
  const files = await (0, import_glob.glob)(sourcePatterns);
408
427
  spinner.succeed(`Found ${files.length} source files`);
409
428
  const extractedKeys = /* @__PURE__ */ new Set();
@@ -420,7 +439,7 @@ async function extractCommand(options) {
420
439
  });
421
440
  return;
422
441
  }
423
- await writeExtractedKeys(Array.from(extractedKeys), outputDir, options);
442
+ await writeExtractedKeys(Array.from(extractedKeys), outputDir, config, options);
424
443
  console.log(import_chalk2.default.green(`\u2713 Translation keys extracted to ${outputDir}`));
425
444
  } catch (error) {
426
445
  spinner.fail("Extraction failed");
@@ -438,6 +457,8 @@ function extractKeysFromContent(content) {
438
457
  // t('key')
439
458
  /useTranslations\(\)\(['"`]([^'"`]+)['"`]\)/g,
440
459
  // useTranslations()('key')
460
+ /useTranslations\(['"`]([^'"`]+)['"`]\)\(['"`]([^'"`]+)['"`]\)/g,
461
+ // useTranslations('ns')('key')
441
462
  /i18nKey=['"`]([^'"`]+)['"`]/g,
442
463
  // i18nKey="key"
443
464
  /\{\s*t\(['"`]([^'"`]+)['"`]\)\s*\}/g
@@ -446,12 +467,16 @@ function extractKeysFromContent(content) {
446
467
  for (const pattern of patterns) {
447
468
  let match;
448
469
  while ((match = pattern.exec(content)) !== null) {
449
- keys.push(match[1]);
470
+ if (match[2]) {
471
+ keys.push(`${match[1]}.${match[2]}`);
472
+ } else {
473
+ keys.push(match[1]);
474
+ }
450
475
  }
451
476
  }
452
477
  return keys;
453
478
  }
454
- async function writeExtractedKeys(keys, outputDir, options) {
479
+ async function writeExtractedKeys(keys, outputDir, config, options) {
455
480
  await import_fs_extra4.default.ensureDir(outputDir);
456
481
  const namespaces = { common: [] };
457
482
  for (const key of keys) {
@@ -467,46 +492,271 @@ async function writeExtractedKeys(keys, outputDir, options) {
467
492
  namespaces.common.push(key);
468
493
  }
469
494
  }
470
- for (const [namespace, namespaceKeys] of Object.entries(namespaces)) {
471
- if (namespaceKeys.length === 0) continue;
472
- const filePath = import_path3.default.join(outputDir, "en", `${namespace}.json`);
473
- await import_fs_extra4.default.ensureDir(import_path3.default.dirname(filePath));
474
- let translations = {};
475
- if (options.update && await import_fs_extra4.default.pathExists(filePath)) {
476
- try {
477
- translations = await import_fs_extra4.default.readJson(filePath);
478
- } catch {
495
+ const locales = config.locales || ["en"];
496
+ for (const locale of locales) {
497
+ for (const [namespace, namespaceKeys] of Object.entries(namespaces)) {
498
+ if (namespaceKeys.length === 0) continue;
499
+ const filePath = import_node_path3.default.join(outputDir, locale, `${namespace}.json`);
500
+ await import_fs_extra4.default.ensureDir(import_node_path3.default.dirname(filePath));
501
+ let translations = {};
502
+ if ((options.update || locale !== config.defaultLocale) && await import_fs_extra4.default.pathExists(filePath)) {
503
+ try {
504
+ translations = await import_fs_extra4.default.readJson(filePath);
505
+ } catch {
506
+ }
479
507
  }
480
- }
481
- for (const key of namespaceKeys) {
482
- if (!translations[key]) {
483
- translations[key] = key;
508
+ for (const key of namespaceKeys) {
509
+ if (!translations[key]) {
510
+ translations[key] = locale === config.defaultLocale ? key : "";
511
+ }
484
512
  }
513
+ if (config.extraction?.sortKeys !== false) {
514
+ const sortedTranslations = {};
515
+ Object.keys(translations).sort().forEach((k) => {
516
+ sortedTranslations[k] = translations[k];
517
+ });
518
+ translations = sortedTranslations;
519
+ }
520
+ await import_fs_extra4.default.writeJson(filePath, translations, { spaces: 2 });
485
521
  }
486
- await import_fs_extra4.default.writeJson(filePath, translations, { spaces: 2 });
487
522
  }
488
523
  }
489
524
 
490
525
  // src/commands/sync.ts
491
526
  var import_chalk3 = __toESM(require("chalk"));
527
+ var import_ora3 = __toESM(require("ora"));
528
+ var import_inquirer = __toESM(require("inquirer"));
492
529
  async function syncCommand(options) {
493
- console.log(import_chalk3.default.blue("Sync command not yet implemented"));
494
- console.log("Options:", options);
530
+ const spinner = (0, import_ora3.default)("Loading configuration...").start();
531
+ try {
532
+ const config = await loadConfig(options.config);
533
+ spinner.text = "Loading translations...";
534
+ const translations = await loadTranslations(
535
+ config.translationPaths,
536
+ config.locales,
537
+ config.namespaces
538
+ );
539
+ spinner.succeed("Configuration loaded");
540
+ const baseLocale = options.base || config.defaultLocale;
541
+ const targetLocales = options.target || config.locales.filter((l) => l !== baseLocale);
542
+ if (!config.locales.includes(baseLocale)) {
543
+ throw new Error(`Base locale '${baseLocale}' not found in configuration`);
544
+ }
545
+ const analysis = analyzeTranslations(
546
+ translations,
547
+ baseLocale,
548
+ targetLocales,
549
+ config.namespaces
550
+ );
551
+ if (options.verbose) {
552
+ displayAnalysis(analysis);
553
+ }
554
+ if (options.interactive && (analysis.missingKeys.length > 0 || analysis.unusedKeys.length > 0)) {
555
+ const shouldProceed = await confirmSync(analysis);
556
+ if (!shouldProceed) {
557
+ console.log(import_chalk3.default.yellow("Sync cancelled by user"));
558
+ return;
559
+ }
560
+ }
561
+ const updatedTranslations = await performSync(
562
+ translations,
563
+ analysis,
564
+ baseLocale,
565
+ targetLocales,
566
+ config.namespaces,
567
+ options
568
+ );
569
+ spinner.start("Saving translations...");
570
+ await saveTranslations(updatedTranslations, config.translationPaths);
571
+ spinner.succeed("Translations synchronized successfully");
572
+ displaySummary(analysis, updatedTranslations);
573
+ } catch (error) {
574
+ spinner.fail("Sync failed");
575
+ console.error(
576
+ import_chalk3.default.red("Error:"),
577
+ error instanceof Error ? error.message : error
578
+ );
579
+ process.exit(1);
580
+ }
581
+ }
582
+ function analyzeTranslations(translations, baseLocale, targetLocales, namespaces) {
583
+ const missingKeys = [];
584
+ const unusedKeys = [];
585
+ const baseKeys = /* @__PURE__ */ new Set();
586
+ for (const namespace of namespaces) {
587
+ const baseTranslations = translations[baseLocale]?.[namespace] || {};
588
+ collectKeys(baseTranslations, "", baseKeys);
589
+ }
590
+ for (const locale of targetLocales) {
591
+ for (const namespace of namespaces) {
592
+ const targetTranslations = translations[locale]?.[namespace] || {};
593
+ const targetKeys = /* @__PURE__ */ new Set();
594
+ collectKeys(targetTranslations, "", targetKeys);
595
+ for (const key of baseKeys) {
596
+ if (!targetKeys.has(key)) {
597
+ missingKeys.push({ locale, namespace, key });
598
+ }
599
+ }
600
+ }
601
+ }
602
+ for (const locale of targetLocales) {
603
+ for (const namespace of namespaces) {
604
+ const targetTranslations = translations[locale]?.[namespace] || {};
605
+ const targetKeys = /* @__PURE__ */ new Set();
606
+ collectKeys(targetTranslations, "", targetKeys);
607
+ for (const key of targetKeys) {
608
+ if (!baseKeys.has(key)) {
609
+ unusedKeys.push({ locale, namespace, key });
610
+ }
611
+ }
612
+ }
613
+ }
614
+ return {
615
+ missingKeys,
616
+ unusedKeys,
617
+ totalKeys: baseKeys.size,
618
+ missingCount: missingKeys.length,
619
+ unusedCount: unusedKeys.length
620
+ };
621
+ }
622
+ function collectKeys(obj, prefix, keys) {
623
+ for (const [key, value] of Object.entries(obj)) {
624
+ const fullKey = prefix ? `${prefix}.${key}` : key;
625
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
626
+ collectKeys(value, fullKey, keys);
627
+ } else {
628
+ keys.add(fullKey);
629
+ }
630
+ }
631
+ }
632
+ function displayAnalysis(analysis) {
633
+ console.log(import_chalk3.default.bold("\n\u{1F4CA} Translation Analysis:"));
634
+ console.log(`Total keys in base locale: ${import_chalk3.default.blue(analysis.totalKeys)}`);
635
+ console.log(`Missing keys: ${import_chalk3.default.yellow(analysis.missingCount)}`);
636
+ console.log(`Unused keys: ${import_chalk3.default.red(analysis.unusedCount)}`);
637
+ if (analysis.missingKeys.length > 0) {
638
+ console.log(import_chalk3.default.yellow("\n\u26A0\uFE0F Missing Keys:"));
639
+ const grouped = groupKeysByLocale(analysis.missingKeys);
640
+ for (const [locale, keys] of Object.entries(grouped)) {
641
+ console.log(import_chalk3.default.gray(` ${locale}: ${keys.length} keys`));
642
+ if (keys.length <= 10) {
643
+ keys.forEach(
644
+ (key) => console.log(import_chalk3.default.gray(` - ${key.namespace}.${key.key}`))
645
+ );
646
+ }
647
+ }
648
+ }
649
+ if (analysis.unusedKeys.length > 0) {
650
+ console.log(import_chalk3.default.red("\n\u{1F5D1}\uFE0F Unused Keys:"));
651
+ const grouped = groupKeysByLocale(analysis.unusedKeys);
652
+ for (const [locale, keys] of Object.entries(grouped)) {
653
+ console.log(import_chalk3.default.gray(` ${locale}: ${keys.length} keys`));
654
+ if (keys.length <= 10) {
655
+ keys.forEach(
656
+ (key) => console.log(import_chalk3.default.gray(` - ${key.namespace}.${key.key}`))
657
+ );
658
+ }
659
+ }
660
+ }
661
+ }
662
+ function groupKeysByLocale(keys) {
663
+ return keys.reduce(
664
+ (acc, key) => {
665
+ if (!acc[key.locale]) acc[key.locale] = [];
666
+ acc[key.locale].push(key);
667
+ return acc;
668
+ },
669
+ {}
670
+ );
671
+ }
672
+ async function confirmSync(analysis) {
673
+ const questions = [];
674
+ if (analysis.missingCount > 0) {
675
+ questions.push({
676
+ type: "confirm",
677
+ name: "addMissing",
678
+ message: `Add ${analysis.missingCount} missing translation keys?`,
679
+ default: true
680
+ });
681
+ }
682
+ if (analysis.unusedCount > 0) {
683
+ questions.push({
684
+ type: "confirm",
685
+ name: "removeUnused",
686
+ message: `Remove ${analysis.unusedCount} unused translation keys?`,
687
+ default: false
688
+ });
689
+ }
690
+ const answers = await import_inquirer.default.prompt(questions);
691
+ return answers.addMissing || answers.removeUnused;
692
+ }
693
+ async function performSync(translations, analysis, baseLocale, targetLocales, namespaces, options) {
694
+ const updatedTranslations = JSON.parse(JSON.stringify(translations));
695
+ if (analysis.missingKeys.length > 0 && (options.missingOnly || !options.missingOnly)) {
696
+ for (const missing of analysis.missingKeys) {
697
+ const baseValue = getNestedValue(
698
+ updatedTranslations[baseLocale]?.[missing.namespace] || {},
699
+ missing.key
700
+ );
701
+ setNestedValue(
702
+ updatedTranslations[missing.locale][missing.namespace],
703
+ missing.key,
704
+ baseValue
705
+ );
706
+ }
707
+ }
708
+ if (analysis.unusedKeys.length > 0 && !options.missingOnly) {
709
+ for (const unused of analysis.unusedKeys) {
710
+ removeNestedValue(
711
+ updatedTranslations[unused.locale][unused.namespace],
712
+ unused.key
713
+ );
714
+ }
715
+ }
716
+ return updatedTranslations;
717
+ }
718
+ function getNestedValue(obj, path6) {
719
+ return path6.split(".").reduce((current, key) => current?.[key], obj);
720
+ }
721
+ function setNestedValue(obj, path6, value) {
722
+ const keys = path6.split(".");
723
+ const lastKey = keys.pop();
724
+ const target = keys.reduce((current, key) => {
725
+ if (!current[key]) current[key] = {};
726
+ return current[key];
727
+ }, obj);
728
+ target[lastKey] = value;
729
+ }
730
+ function removeNestedValue(obj, path6) {
731
+ const keys = path6.split(".");
732
+ const lastKey = keys.pop();
733
+ const target = keys.reduce((current, key) => current?.[key], obj);
734
+ if (target) {
735
+ delete target[lastKey];
736
+ }
737
+ }
738
+ function displaySummary(analysis, translations) {
739
+ console.log(import_chalk3.default.bold.green("\n\u2705 Sync Complete!"));
740
+ console.log(`Added ${import_chalk3.default.green(analysis.missingCount)} missing keys`);
741
+ console.log(`Removed ${import_chalk3.default.red(analysis.unusedCount)} unused keys`);
742
+ console.log(
743
+ `Total translations: ${Object.keys(translations).length} locales`
744
+ );
495
745
  }
496
746
 
497
747
  // src/commands/init.ts
498
748
  var import_chalk4 = __toESM(require("chalk"));
499
- var import_ora3 = __toESM(require("ora"));
749
+ var import_ora4 = __toESM(require("ora"));
500
750
  var import_fs_extra5 = __toESM(require("fs-extra"));
501
- var import_path4 = __toESM(require("path"));
502
- var import_inquirer = __toESM(require("inquirer"));
751
+ var import_node_path4 = __toESM(require("path"));
752
+ var import_inquirer2 = __toESM(require("inquirer"));
503
753
  async function initCommand(options) {
504
- const spinner = (0, import_ora3.default)("Initializing IntlParty configuration...").start();
754
+ const spinner = (0, import_ora4.default)("Initializing IntlParty configuration...").start();
505
755
  try {
506
756
  const configPath = "intl-party.config.json";
507
757
  if (await import_fs_extra5.default.pathExists(configPath) && !options.force) {
508
758
  spinner.stop();
509
- const { overwrite } = await import_inquirer.default.prompt([
759
+ const { overwrite } = await import_inquirer2.default.prompt([
510
760
  {
511
761
  type: "confirm",
512
762
  name: "overwrite",
@@ -521,7 +771,7 @@ async function initCommand(options) {
521
771
  }
522
772
  spinner.start("Setting up configuration...");
523
773
  spinner.stop();
524
- const answers = await import_inquirer.default.prompt([
774
+ const answers = await import_inquirer2.default.prompt([
525
775
  {
526
776
  type: "input",
527
777
  name: "defaultLocale",
@@ -583,7 +833,7 @@ async function initCommand(options) {
583
833
  for (const locale of answers.locales) {
584
834
  config.translationPaths[locale] = {};
585
835
  for (const namespace of answers.namespaces) {
586
- config.translationPaths[locale][namespace] = import_path4.default.join(
836
+ config.translationPaths[locale][namespace] = import_node_path4.default.join(
587
837
  answers.translationsDir,
588
838
  locale,
589
839
  `${namespace}.json`
@@ -593,10 +843,10 @@ async function initCommand(options) {
593
843
  spinner.start("Creating directory structure...");
594
844
  await import_fs_extra5.default.ensureDir(answers.translationsDir);
595
845
  for (const locale of answers.locales) {
596
- const localeDir = import_path4.default.join(answers.translationsDir, locale);
846
+ const localeDir = import_node_path4.default.join(answers.translationsDir, locale);
597
847
  await import_fs_extra5.default.ensureDir(localeDir);
598
848
  for (const namespace of answers.namespaces) {
599
- const filePath = import_path4.default.join(localeDir, `${namespace}.json`);
849
+ const filePath = import_node_path4.default.join(localeDir, `${namespace}.json`);
600
850
  if (!await import_fs_extra5.default.pathExists(filePath)) {
601
851
  await import_fs_extra5.default.writeJson(filePath, {}, { spaces: 2 });
602
852
  }
@@ -740,10 +990,10 @@ console.log(i18n.t('welcome'));
740
990
 
741
991
  // src/commands/check.ts
742
992
  var import_chalk5 = __toESM(require("chalk"));
743
- var import_ora4 = __toESM(require("ora"));
993
+ var import_ora5 = __toESM(require("ora"));
744
994
  var import_core2 = require("@intl-party/core");
745
995
  async function checkCommand(options) {
746
- const spinner = (0, import_ora4.default)("Loading configuration...").start();
996
+ const spinner = (0, import_ora5.default)("Loading configuration...").start();
747
997
  try {
748
998
  const config = await loadConfig(options.config);
749
999
  spinner.succeed("Configuration loaded");
@@ -865,10 +1115,623 @@ async function checkCommand(options) {
865
1115
  }
866
1116
 
867
1117
  // src/commands/generate.ts
1118
+ var import_fs_extra6 = __toESM(require("fs-extra"));
1119
+ var import_node_path5 = __toESM(require("path"));
1120
+ var import_crypto = __toESM(require("crypto"));
868
1121
  var import_chalk6 = __toESM(require("chalk"));
1122
+ var import_ora6 = __toESM(require("ora"));
1123
+ var import_chokidar = require("chokidar");
1124
+ async function getMessageData(configPath, options) {
1125
+ let config;
1126
+ let locales;
1127
+ let namespaces;
1128
+ let translationPaths;
1129
+ if (configPath && await import_fs_extra6.default.pathExists(configPath)) {
1130
+ config = await loadConfig(configPath);
1131
+ locales = config.locales;
1132
+ namespaces = config.namespaces;
1133
+ translationPaths = config.translationPaths;
1134
+ } else {
1135
+ if (options?.verbose) {
1136
+ console.log(
1137
+ import_chalk6.default.gray("No config file found, auto-detecting from filesystem...")
1138
+ );
1139
+ }
1140
+ const autoDetected = await autoDetectMessages(options);
1141
+ locales = autoDetected.locales;
1142
+ namespaces = autoDetected.namespaces;
1143
+ translationPaths = autoDetected.translationPaths;
1144
+ }
1145
+ if (config) {
1146
+ const nextjsConfig = config.shared;
1147
+ if (nextjsConfig && nextjsConfig.messagesPath && nextjsConfig.locales && nextjsConfig.namespaces) {
1148
+ translationPaths = {};
1149
+ for (const locale of nextjsConfig.locales) {
1150
+ translationPaths[locale] = {};
1151
+ for (const namespace of nextjsConfig.namespaces) {
1152
+ translationPaths[locale][namespace] = import_node_path5.default.join(
1153
+ process.cwd(),
1154
+ nextjsConfig.messagesPath,
1155
+ locale,
1156
+ `${namespace}.json`
1157
+ );
1158
+ }
1159
+ }
1160
+ locales = nextjsConfig.locales;
1161
+ namespaces = nextjsConfig.namespaces;
1162
+ if (options?.verbose) {
1163
+ console.log(
1164
+ import_chalk6.default.gray(
1165
+ `Using Next.js config: ${locales.length} locales, ${namespaces.length} namespaces`
1166
+ )
1167
+ );
1168
+ console.log(import_chalk6.default.gray(`Messages path: ${nextjsConfig.messagesPath}`));
1169
+ }
1170
+ } else if (config.messagesPath && config.locales && config.namespaces) {
1171
+ const standardConfig = config;
1172
+ translationPaths = {};
1173
+ for (const locale of standardConfig.locales) {
1174
+ translationPaths[locale] = {};
1175
+ for (const namespace of standardConfig.namespaces) {
1176
+ translationPaths[locale][namespace] = import_node_path5.default.join(
1177
+ process.cwd(),
1178
+ standardConfig.messagesPath,
1179
+ locale,
1180
+ `${namespace}.json`
1181
+ );
1182
+ }
1183
+ }
1184
+ locales = standardConfig.locales;
1185
+ namespaces = standardConfig.namespaces;
1186
+ if (options?.verbose) {
1187
+ console.log(
1188
+ import_chalk6.default.gray(
1189
+ `Using standard config: ${locales.length} locales, ${namespaces.length} namespaces`
1190
+ )
1191
+ );
1192
+ console.log(
1193
+ import_chalk6.default.gray(`Messages path: ${standardConfig.messagesPath}`)
1194
+ );
1195
+ }
1196
+ }
1197
+ }
1198
+ const messages = await loadTranslations(
1199
+ translationPaths,
1200
+ locales,
1201
+ namespaces
1202
+ );
1203
+ const translationKeys = /* @__PURE__ */ new Set();
1204
+ const namespaceKeys = /* @__PURE__ */ new Set();
1205
+ for (const locale of locales) {
1206
+ for (const namespace of namespaces) {
1207
+ const extractKeys = (obj, prefix = "") => {
1208
+ for (const [key, value] of Object.entries(obj)) {
1209
+ const fullKey = prefix ? `${prefix}.${key}` : key;
1210
+ const namespaceKey = prefix ? key : fullKey;
1211
+ translationKeys.add(fullKey);
1212
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
1213
+ extractKeys(value, fullKey);
1214
+ } else {
1215
+ const dotNotationKey = fullKey.replace(`${namespace}.`, "");
1216
+ namespaceKeys.add(dotNotationKey);
1217
+ }
1218
+ }
1219
+ };
1220
+ if (messages[locale]?.[namespace]) {
1221
+ extractKeys(messages[locale][namespace], namespace);
1222
+ }
1223
+ }
1224
+ }
1225
+ return {
1226
+ locales,
1227
+ namespaces,
1228
+ messages,
1229
+ translationKeys: Array.from(translationKeys).sort(),
1230
+ namespaceKeys: Array.from(namespaceKeys).sort()
1231
+ };
1232
+ }
1233
+ function generateTypescriptTypes(data) {
1234
+ const { locales, namespaces, translationKeys, namespaceKeys } = data;
1235
+ const keyUnion = translationKeys.map((key) => `"${key}"`).join(" | ");
1236
+ const namespaceKeyUnion = namespaceKeys.map((key) => `"${key}"`).join(" | ");
1237
+ const namespaceTypes = namespaces.map((ns) => {
1238
+ const messageStructure = data.messages[locales[0]]?.[ns];
1239
+ if (!messageStructure) return ` "${ns}": {};`;
1240
+ const generateNestedInterface = (obj, indent = 2) => {
1241
+ const spaces = " ".repeat(indent);
1242
+ const entries = Object.entries(obj);
1243
+ if (entries.length === 0) return "{}";
1244
+ const interfaceLines = entries.map(([key, value]) => {
1245
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
1246
+ return `${spaces}"${key}": ${generateNestedInterface(value, indent + 1)};`;
1247
+ } else {
1248
+ return `${spaces}"${key}": string;`;
1249
+ }
1250
+ });
1251
+ return `{
1252
+ ${interfaceLines.join("\n")}
1253
+ ${" ".repeat(indent - 1)}}`;
1254
+ };
1255
+ return ` "${ns}": ${generateNestedInterface(messageStructure)};`;
1256
+ }).join("\n");
1257
+ const localeTypes = locales.map((locale) => {
1258
+ return ` "${locale}": {
1259
+ ${namespaceTypes}
1260
+ };`;
1261
+ }).join("\n");
1262
+ return `// Generated by @intl-party/cli - do not edit
1263
+ // This file contains type-safe definitions for your translations
1264
+
1265
+ export type TranslationKey = ${keyUnion};
1266
+
1267
+ export type NamespaceTranslationKey = ${namespaceKeyUnion};
1268
+
1269
+ export type TranslationNamespace = ${namespaces.map((ns) => `"${ns}"`).join(" | ")};
1270
+
1271
+ export type Locale = ${locales.map((locale) => `"${locale}"`).join(" | ")};
1272
+
1273
+ export interface Translations {
1274
+ ${localeTypes}
1275
+ }
1276
+
1277
+ export interface NamespaceTranslations {
1278
+ ${namespaceTypes}
1279
+ }
1280
+
1281
+ // Helper type for getting translation value type
1282
+ export type TranslationValue<T extends TranslationKey> = string;
1283
+
1284
+ // Helper type for getting namespace translations
1285
+ export type GetNamespaceTranslations<N extends TranslationNamespace> =
1286
+ Translations[Locale][N];
1287
+
1288
+ // Type-safe translation function signature
1289
+ export interface TranslationFunction {
1290
+ <T extends TranslationKey>(key: T, options?: Record<string, any>): TranslationValue<T>;
1291
+ <T extends TranslationNamespace>(namespace: T): GetNamespaceTranslations<T>;
1292
+ }
1293
+
1294
+ // Default messages object (for runtime usage)
1295
+ export const defaultMessages: Translations = ${JSON.stringify(data.messages, null, 2)} as const;
1296
+ `;
1297
+ }
1298
+ function generateClientMessages(data) {
1299
+ return `// Generated by @intl-party/cli - do not edit
1300
+ // This file contains runtime message data for the client package
1301
+
1302
+ import type { Translations } from './translations.generated';
1303
+
1304
+ export const messages: Translations = ${JSON.stringify(data.messages, null, 2)} as const;
1305
+
1306
+ // Re-export for convenience
1307
+ export { messages as defaultMessages } from './translations.generated';
1308
+ `;
1309
+ }
1310
+ function generateJavaScriptMessages(data) {
1311
+ return `// Generated by @intl-party/cli - do not edit
1312
+ // This file contains runtime message data for easy imports
1313
+
1314
+ export const defaultMessages = ${JSON.stringify(data.messages, null, 2)};
1315
+
1316
+ // Export individual locale messages for convenience
1317
+ ${data.locales.map((locale) => `export const ${locale}Messages = defaultMessages.${locale};`).join("\n")}
1318
+ `;
1319
+ }
1320
+ function generateClientIndex() {
1321
+ return `// Generated by @intl-party/cli - do not edit
1322
+ // This file is the main entry point for the client package
1323
+
1324
+ export * from './translations.generated';
1325
+ export * from './messages.generated';
1326
+ `;
1327
+ }
1328
+ function generateJsonSchemas(data) {
1329
+ const schemas = {};
1330
+ for (const locale of data.locales) {
1331
+ for (const namespace of data.namespaces) {
1332
+ const messages = data.messages[locale]?.[namespace] || {};
1333
+ const schema = createJsonSchema(messages);
1334
+ const schemaName = `${locale}_${namespace}`;
1335
+ schemas[schemaName] = {
1336
+ $schema: "http://json-schema.org/draft-07/schema#",
1337
+ $id: `#/schemas/${schemaName}`,
1338
+ title: `Translation schema for ${locale}/${namespace}`,
1339
+ description: `JSON schema for translation keys in ${namespace} namespace for ${locale} locale`,
1340
+ type: "object",
1341
+ properties: schema.properties,
1342
+ required: schema.required,
1343
+ additionalProperties: false
1344
+ };
1345
+ }
1346
+ }
1347
+ const combinedSchema = {
1348
+ $schema: "http://json-schema.org/draft-07/schema#",
1349
+ $id: "#/schemas/translations",
1350
+ title: "IntlParty Translation Schema",
1351
+ description: "JSON schema for all IntlParty translations",
1352
+ type: "object",
1353
+ properties: {},
1354
+ definitions: {}
1355
+ };
1356
+ for (const locale of data.locales) {
1357
+ combinedSchema.properties[locale] = {
1358
+ type: "object",
1359
+ description: `Translations for ${locale} locale`,
1360
+ properties: {}
1361
+ };
1362
+ for (const namespace of data.namespaces) {
1363
+ const schemaName = `${locale}_${namespace}`;
1364
+ combinedSchema.properties[locale].properties[namespace] = {
1365
+ $ref: `#/definitions/${schemaName}`
1366
+ };
1367
+ combinedSchema.definitions[schemaName] = schemas[schemaName];
1368
+ }
1369
+ }
1370
+ return JSON.stringify(
1371
+ {
1372
+ schemas,
1373
+ combined: combinedSchema,
1374
+ metadata: {
1375
+ generated: (/* @__PURE__ */ new Date()).toISOString(),
1376
+ locales: data.locales,
1377
+ namespaces: data.namespaces,
1378
+ version: "1.0.0"
1379
+ }
1380
+ },
1381
+ null,
1382
+ 2
1383
+ );
1384
+ }
1385
+ function createJsonSchema(obj, prefix = "") {
1386
+ const properties = {};
1387
+ const required = [];
1388
+ for (const [key, value] of Object.entries(obj)) {
1389
+ const fullKey = prefix ? `${prefix}.${key}` : key;
1390
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
1391
+ const nestedSchema = createJsonSchema(value, fullKey);
1392
+ properties[key] = {
1393
+ type: "object",
1394
+ properties: nestedSchema.properties,
1395
+ required: nestedSchema.required,
1396
+ description: `Translation key: ${fullKey}`
1397
+ };
1398
+ } else {
1399
+ properties[key] = {
1400
+ type: "string",
1401
+ description: `Translation key: ${fullKey}`,
1402
+ examples: [value]
1403
+ };
1404
+ required.push(key);
1405
+ }
1406
+ }
1407
+ return { properties, required };
1408
+ }
1409
+ function generateDocumentation(data) {
1410
+ const lines = [];
1411
+ lines.push("# Translation Documentation");
1412
+ lines.push("");
1413
+ lines.push(`Generated on: ${(/* @__PURE__ */ new Date()).toISOString()}`);
1414
+ lines.push(`Locales: ${data.locales.join(", ")}`);
1415
+ lines.push(`Namespaces: ${data.namespaces.join(", ")}`);
1416
+ lines.push("");
1417
+ lines.push("## Table of Contents");
1418
+ for (const locale of data.locales) {
1419
+ lines.push(`- [${locale.toUpperCase()}](#${locale.toLowerCase()})`);
1420
+ }
1421
+ lines.push("");
1422
+ for (const locale of data.locales) {
1423
+ lines.push(`## ${locale.toUpperCase()}`);
1424
+ lines.push("");
1425
+ for (const namespace of data.namespaces) {
1426
+ const messages = data.messages[locale]?.[namespace] || {};
1427
+ if (Object.keys(messages).length === 0) {
1428
+ continue;
1429
+ }
1430
+ lines.push(`### ${namespace} namespace`);
1431
+ lines.push("");
1432
+ generateNamespaceDocumentation(messages, lines, "");
1433
+ }
1434
+ lines.push("");
1435
+ }
1436
+ lines.push("## Summary");
1437
+ lines.push("");
1438
+ const totalKeys = Object.values(data.messages).flatMap((locale) => Object.values(locale)).reduce((total, namespace) => {
1439
+ return total + countKeys(namespace);
1440
+ }, 0);
1441
+ lines.push(`- **Total locales**: ${data.locales.length}`);
1442
+ lines.push(`- **Total namespaces**: ${data.namespaces.length}`);
1443
+ lines.push(`- **Total translation keys**: ${totalKeys}`);
1444
+ lines.push("");
1445
+ lines.push("### Keys by Locale");
1446
+ lines.push("");
1447
+ for (const locale of data.locales) {
1448
+ const localeKeys = Object.values(data.messages[locale] || {}).reduce(
1449
+ (total, namespace) => total + countKeys(namespace),
1450
+ 0
1451
+ );
1452
+ lines.push(`- **${locale}**: ${localeKeys} keys`);
1453
+ }
1454
+ return lines.join("\n");
1455
+ }
1456
+ function generateNamespaceDocumentation(obj, lines, prefix) {
1457
+ for (const [key, value] of Object.entries(obj)) {
1458
+ const fullKey = prefix ? `${prefix}.${key}` : key;
1459
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
1460
+ lines.push(`#### ${fullKey}`);
1461
+ lines.push("");
1462
+ lines.push("Nested translation object containing:");
1463
+ lines.push("");
1464
+ const nestedKeys = Object.keys(value);
1465
+ for (const nestedKey of nestedKeys) {
1466
+ lines.push(`- \`${fullKey}.${nestedKey}\``);
1467
+ }
1468
+ lines.push("");
1469
+ generateNamespaceDocumentation(value, lines, fullKey);
1470
+ } else {
1471
+ lines.push(`#### ${fullKey}`);
1472
+ lines.push("");
1473
+ lines.push(`**Translation**: \`"${value}"\``);
1474
+ lines.push("");
1475
+ const interpolationMatches = String(value).match(/\{\{([^}]+)\}\}/g);
1476
+ if (interpolationMatches) {
1477
+ lines.push("**Interpolation variables**:");
1478
+ lines.push("");
1479
+ const variables = interpolationMatches.map(
1480
+ (match) => match.replace(/[{}]/g, "")
1481
+ );
1482
+ const uniqueVariables = [...new Set(variables)];
1483
+ for (const variable of uniqueVariables) {
1484
+ lines.push(`- \`${variable}\``);
1485
+ }
1486
+ lines.push("");
1487
+ }
1488
+ }
1489
+ }
1490
+ }
1491
+ function countKeys(obj) {
1492
+ let count = 0;
1493
+ for (const value of Object.values(obj)) {
1494
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
1495
+ count += countKeys(value);
1496
+ } else {
1497
+ count += 1;
1498
+ }
1499
+ }
1500
+ return count;
1501
+ }
1502
+ async function autoDetectMessages(options) {
1503
+ const cwd = process.cwd();
1504
+ const possibleMessageDirs = [
1505
+ import_node_path5.default.join(cwd, "messages"),
1506
+ import_node_path5.default.join(cwd, "locales"),
1507
+ import_node_path5.default.join(cwd, "translations"),
1508
+ import_node_path5.default.join(cwd, "i18n")
1509
+ ];
1510
+ let messagesDir = null;
1511
+ for (const dir of possibleMessageDirs) {
1512
+ if (await import_fs_extra6.default.pathExists(dir)) {
1513
+ messagesDir = dir;
1514
+ break;
1515
+ }
1516
+ }
1517
+ if (!messagesDir) {
1518
+ throw new Error(
1519
+ "No messages directory found. Expected one of: messages/, locales/, translations/, i18n/"
1520
+ );
1521
+ }
1522
+ if (options?.verbose) {
1523
+ console.log(import_chalk6.default.gray(`Found messages directory: ${messagesDir}`));
1524
+ }
1525
+ const localeDirs = await import_fs_extra6.default.readdir(messagesDir);
1526
+ const detectedLocales = localeDirs.filter(async (dir) => {
1527
+ const localePath = import_node_path5.default.join(messagesDir, dir);
1528
+ const stat = await import_fs_extra6.default.stat(localePath);
1529
+ return stat.isDirectory();
1530
+ });
1531
+ const validLocales = [];
1532
+ for (const dir of localeDirs) {
1533
+ const localePath = import_node_path5.default.join(messagesDir, dir);
1534
+ const stat = await import_fs_extra6.default.stat(localePath);
1535
+ if (stat.isDirectory()) {
1536
+ validLocales.push(dir);
1537
+ }
1538
+ }
1539
+ if (validLocales.length === 0) {
1540
+ throw new Error(`No locale directories found in ${messagesDir}`);
1541
+ }
1542
+ const firstLocale = validLocales[0];
1543
+ const firstLocalePath = import_node_path5.default.join(messagesDir, firstLocale);
1544
+ const namespaceFiles = await import_fs_extra6.default.readdir(firstLocalePath);
1545
+ const detectedNamespaces = namespaceFiles.filter((file) => file.endsWith(".json")).map((file) => import_node_path5.default.basename(file, ".json"));
1546
+ if (detectedNamespaces.length === 0) {
1547
+ throw new Error(`No JSON files found in ${firstLocalePath}`);
1548
+ }
1549
+ const translationPaths = {};
1550
+ for (const locale of validLocales) {
1551
+ translationPaths[locale] = {};
1552
+ for (const namespace of detectedNamespaces) {
1553
+ translationPaths[locale][namespace] = import_node_path5.default.join(
1554
+ messagesDir,
1555
+ locale,
1556
+ `${namespace}.json`
1557
+ );
1558
+ }
1559
+ }
1560
+ if (options?.verbose) {
1561
+ console.log(
1562
+ import_chalk6.default.gray(
1563
+ `Auto-detected ${validLocales.length} locales: ${validLocales.join(", ")}`
1564
+ )
1565
+ );
1566
+ console.log(
1567
+ import_chalk6.default.gray(
1568
+ `Auto-detected ${detectedNamespaces.length} namespaces: ${detectedNamespaces.join(", ")}`
1569
+ )
1570
+ );
1571
+ }
1572
+ return {
1573
+ locales: validLocales,
1574
+ namespaces: detectedNamespaces,
1575
+ translationPaths
1576
+ };
1577
+ }
1578
+ function generateCacheHash(data) {
1579
+ const content = JSON.stringify({
1580
+ locales: data.locales.sort(),
1581
+ namespaces: data.namespaces.sort(),
1582
+ messages: data.messages
1583
+ });
1584
+ return import_crypto.default.createHash("md5").update(content).digest("hex");
1585
+ }
1586
+ async function writeGeneratedFiles(data, outputDir, options) {
1587
+ await import_fs_extra6.default.ensureDir(outputDir);
1588
+ const cacheHash = generateCacheHash(data);
1589
+ const cacheFilePath = import_node_path5.default.join(outputDir, ".intl-party-cache");
1590
+ let shouldRegenerate = true;
1591
+ if (await import_fs_extra6.default.pathExists(cacheFilePath)) {
1592
+ const existingHash = await import_fs_extra6.default.readFile(cacheFilePath, "utf-8");
1593
+ if (existingHash === cacheHash) {
1594
+ shouldRegenerate = false;
1595
+ }
1596
+ }
1597
+ if (!shouldRegenerate && !options.watch && !options.client) {
1598
+ if (options.verbose) {
1599
+ console.log(import_chalk6.default.gray("No changes detected, skipping generation"));
1600
+ }
1601
+ return;
1602
+ }
1603
+ if (options.types !== false) {
1604
+ const typesContent = generateTypescriptTypes(data);
1605
+ const typesFilePath = import_node_path5.default.join(outputDir, "translations.generated.ts");
1606
+ await import_fs_extra6.default.writeFile(typesFilePath, typesContent);
1607
+ const jsContent = generateJavaScriptMessages(data);
1608
+ const jsFilePath = import_node_path5.default.join(outputDir, "messages.generated.js");
1609
+ await import_fs_extra6.default.writeFile(jsFilePath, jsContent);
1610
+ if (options.verbose) {
1611
+ console.log(import_chalk6.default.green(`\u2713 Generated types: ${typesFilePath}`));
1612
+ }
1613
+ }
1614
+ if (options.schemas) {
1615
+ const schemasContent = generateJsonSchemas(data);
1616
+ const schemasFilePath = import_node_path5.default.join(outputDir, "schemas.json");
1617
+ await import_fs_extra6.default.writeFile(schemasFilePath, schemasContent);
1618
+ if (options.verbose) {
1619
+ console.log(import_chalk6.default.green(`\u2713 Generated schemas: ${schemasFilePath}`));
1620
+ }
1621
+ }
1622
+ if (options.docs) {
1623
+ const docsContent = generateDocumentation(data);
1624
+ const docsFilePath = import_node_path5.default.join(outputDir, "translations.md");
1625
+ await import_fs_extra6.default.writeFile(docsFilePath, docsContent);
1626
+ if (options.verbose) {
1627
+ console.log(import_chalk6.default.green(`\u2713 Generated documentation: ${docsFilePath}`));
1628
+ }
1629
+ }
1630
+ await import_fs_extra6.default.writeFile(cacheFilePath, cacheHash);
1631
+ }
1632
+ async function generateClientPackage(data, options) {
1633
+ console.log(import_chalk6.default.blue("\u{1F527} Generating client package files..."));
1634
+ if (options.verbose) {
1635
+ console.log(import_chalk6.default.gray(`Data: ${JSON.stringify(data, null, 2)}`));
1636
+ }
1637
+ let rootDir = process.cwd();
1638
+ while (rootDir !== import_node_path5.default.dirname(rootDir)) {
1639
+ const packageJsonPath = import_node_path5.default.join(rootDir, "package.json");
1640
+ if (await import_fs_extra6.default.pathExists(packageJsonPath)) {
1641
+ const packageJson = await import_fs_extra6.default.readJson(packageJsonPath);
1642
+ if (packageJson.name === "@intl-party/monorepo") {
1643
+ break;
1644
+ }
1645
+ }
1646
+ rootDir = import_node_path5.default.dirname(rootDir);
1647
+ }
1648
+ const clientDir = import_node_path5.default.join(rootDir, "packages/client/generated");
1649
+ await import_fs_extra6.default.ensureDir(clientDir);
1650
+ const typesContent = generateTypescriptTypes(data);
1651
+ const typesFilePath = import_node_path5.default.join(clientDir, "translations.generated.ts");
1652
+ if (options.verbose) {
1653
+ console.log(import_chalk6.default.gray(`Writing types to: ${typesFilePath}`));
1654
+ }
1655
+ await import_fs_extra6.default.writeFile(typesFilePath, typesContent);
1656
+ const messagesContent = generateClientMessages(data);
1657
+ const messagesFilePath = import_node_path5.default.join(clientDir, "messages.generated.ts");
1658
+ if (options.verbose) {
1659
+ console.log(import_chalk6.default.gray(`Writing messages to: ${messagesFilePath}`));
1660
+ }
1661
+ await import_fs_extra6.default.writeFile(messagesFilePath, messagesContent);
1662
+ const indexContent = generateClientIndex();
1663
+ const indexPath = import_node_path5.default.join(clientDir, "index.generated.ts");
1664
+ if (options.verbose) {
1665
+ console.log(import_chalk6.default.gray(`Writing index to: ${indexPath}`));
1666
+ }
1667
+ await import_fs_extra6.default.writeFile(indexPath, indexContent);
1668
+ if (options.verbose) {
1669
+ console.log(
1670
+ import_chalk6.default.green(`\u2713 Generated client package files in ${clientDir}`)
1671
+ );
1672
+ }
1673
+ }
1674
+ async function setupWatcher(configPath, outputDir, options) {
1675
+ const config = await loadConfig(configPath);
1676
+ const { translationPaths } = config;
1677
+ const watchPaths = [];
1678
+ for (const localePaths of Object.values(translationPaths)) {
1679
+ watchPaths.push(...Object.values(localePaths));
1680
+ }
1681
+ console.log(
1682
+ import_chalk6.default.blue(`\u{1F440} Watching for changes in ${watchPaths.length} files...`)
1683
+ );
1684
+ const watcher = (0, import_chokidar.watch)(watchPaths, {
1685
+ ignoreInitial: true,
1686
+ persistent: true
1687
+ });
1688
+ watcher.on("change", async (filePath) => {
1689
+ console.log(import_chalk6.default.yellow(`\u{1F4DD} File changed: ${filePath}`));
1690
+ try {
1691
+ const data = await getMessageData(configPath);
1692
+ await writeGeneratedFiles(data, outputDir, options);
1693
+ console.log(import_chalk6.default.green("\u2713 Regenerated translations"));
1694
+ } catch (error) {
1695
+ console.error(import_chalk6.default.red("\u2717 Failed to regenerate:"), error);
1696
+ }
1697
+ });
1698
+ process.on("SIGINT", () => {
1699
+ watcher.close();
1700
+ console.log(import_chalk6.default.gray("\n\u{1F44B} Stopped watching"));
1701
+ process.exit(0);
1702
+ });
1703
+ }
869
1704
  async function generateCommand(options) {
870
- console.log(import_chalk6.default.blue("Generate command not yet implemented"));
871
- console.log("Options:", options);
1705
+ const spinner = (0, import_ora6.default)("Loading translation data...").start();
1706
+ if (options.verbose) {
1707
+ console.log(
1708
+ import_chalk6.default.gray(`Debug options: ${JSON.stringify(options, null, 2)}`)
1709
+ );
1710
+ }
1711
+ try {
1712
+ const data = await getMessageData(options.config, options);
1713
+ spinner.succeed(
1714
+ `Loaded ${data.locales.length} locales, ${data.namespaces.length} namespaces, ${data.translationKeys.length} keys`
1715
+ );
1716
+ const outputDir = options.output || "./node_modules/.intl-party";
1717
+ spinner.start("Generating files...");
1718
+ await writeGeneratedFiles(data, outputDir, options);
1719
+ spinner.succeed("Files generated successfully");
1720
+ console.log(import_chalk6.default.green(`\u2713 Generated translation files in ${outputDir}`));
1721
+ if (options.client) {
1722
+ await generateClientPackage(data, options);
1723
+ }
1724
+ if (options.watch) {
1725
+ await setupWatcher(options.config, outputDir, options);
1726
+ }
1727
+ } catch (error) {
1728
+ spinner.fail("Generation failed");
1729
+ console.error(
1730
+ import_chalk6.default.red("Error:"),
1731
+ error instanceof Error ? error.message : error
1732
+ );
1733
+ process.exit(1);
1734
+ }
872
1735
  }
873
1736
  // Annotate the CommonJS export names for ESM import in node:
874
1737
  0 && (module.exports = {