@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/cli.js CHANGED
@@ -6,8 +6,12 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __getProtoOf = Object.getPrototypeOf;
8
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
- var __commonJS = (cb, mod) => function __require() {
10
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
9
+ var __esm = (fn, res) => function __init() {
10
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
+ };
12
+ var __export = (target, all) => {
13
+ for (var name in all)
14
+ __defProp(target, name, { get: all[name], enumerable: true });
11
15
  };
12
16
  var __copyProps = (to, from, except, desc) => {
13
17
  if (from && typeof from === "object" || typeof from === "function") {
@@ -26,107 +30,12 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
26
30
  mod
27
31
  ));
28
32
 
29
- // package.json
30
- var require_package = __commonJS({
31
- "package.json"(exports2, module2) {
32
- module2.exports = {
33
- name: "@intl-party/cli",
34
- version: "1.0.0",
35
- description: "Command-line interface for IntlParty - validation, extraction, and management tools",
36
- main: "dist/index.js",
37
- types: "dist/index.d.ts",
38
- bin: {
39
- "intl-party": "./dist/cli.js",
40
- ip: "./dist/cli.js"
41
- },
42
- files: [
43
- "dist"
44
- ],
45
- scripts: {
46
- build: "tsup src/cli.ts src/index.ts --format cjs",
47
- dev: "tsup src/cli.ts src/index.ts --format cjs --dts --watch",
48
- test: "vitest",
49
- "test:watch": "vitest --watch",
50
- lint: "eslint src --ext .ts",
51
- typecheck: "tsc --noEmit",
52
- clean: "rm -rf dist"
53
- },
54
- keywords: [
55
- "cli",
56
- "i18n",
57
- "internationalization",
58
- "validation",
59
- "extraction",
60
- "typescript"
61
- ],
62
- author: "IntlParty Team",
63
- license: "MIT",
64
- dependencies: {
65
- "@intl-party/core": "workspace:*",
66
- commander: "^11.1.0",
67
- chalk: "^5.3.0",
68
- glob: "^10.3.10",
69
- "fs-extra": "^11.2.0",
70
- ora: "^7.0.1",
71
- inquirer: "^9.2.12"
72
- },
73
- devDependencies: {
74
- "@types/fs-extra": "^11.0.4",
75
- "@types/inquirer": "^9.0.7",
76
- "@types/node": "^20.10.0",
77
- eslint: "^8.55.0",
78
- jsdom: "^23.0.1",
79
- tsup: "^8.0.1",
80
- typescript: "^5.3.0",
81
- vitest: "^1.0.0"
82
- },
83
- repository: {
84
- type: "git",
85
- url: "https://github.com/intl-party/intl-party.git",
86
- directory: "packages/cli"
87
- }
88
- };
89
- }
90
- });
91
-
92
- // src/cli.ts
93
- var import_commander = require("commander");
94
- var import_chalk7 = __toESM(require("chalk"));
95
-
96
- // src/commands/validate.ts
97
- var import_chalk = __toESM(require("chalk"));
98
- var import_ora = __toESM(require("ora"));
99
- var import_fs_extra3 = __toESM(require("fs-extra"));
100
- var import_core = require("@intl-party/core");
101
-
102
33
  // src/utils/config.ts
103
- var import_fs_extra = __toESM(require("fs-extra"));
104
- var import_path = __toESM(require("path"));
105
- var DEFAULT_CONFIG = {
106
- locales: ["en", "es", "fr"],
107
- defaultLocale: "en",
108
- namespaces: ["common"],
109
- translationPaths: {},
110
- sourcePatterns: ["src/**/*.{ts,tsx,js,jsx}"],
111
- outputDir: "./translations",
112
- validation: {
113
- strict: false,
114
- logMissing: true,
115
- throwOnMissing: false,
116
- validateFormats: true
117
- },
118
- extraction: {
119
- keyPrefix: "",
120
- markExtracted: true,
121
- sortKeys: true,
122
- includeMetadata: false
123
- },
124
- sync: {
125
- removeUnused: false,
126
- addMissing: true,
127
- preserveOrder: true
128
- }
129
- };
34
+ var config_exports = {};
35
+ __export(config_exports, {
36
+ loadConfig: () => loadConfig,
37
+ saveConfig: () => saveConfig
38
+ });
130
39
  async function loadConfig(configPath) {
131
40
  const configFiles = [
132
41
  configPath,
@@ -145,8 +54,8 @@ async function loadConfig(configPath) {
145
54
  const content = await import_fs_extra.default.readFile(configFile, "utf-8");
146
55
  config = JSON.parse(content);
147
56
  } else {
148
- delete require.cache[import_path.default.resolve(configFile)];
149
- config = require(import_path.default.resolve(configFile));
57
+ delete require.cache[import_node_path.default.resolve(configFile)];
58
+ config = require(import_node_path.default.resolve(configFile));
150
59
  if (config.default) {
151
60
  config = config.default;
152
61
  }
@@ -162,9 +71,9 @@ async function loadConfig(configPath) {
162
71
  const packageJsonPath = "package.json";
163
72
  if (await import_fs_extra.default.pathExists(packageJsonPath)) {
164
73
  try {
165
- const packageJson2 = await import_fs_extra.default.readJson(packageJsonPath);
166
- if (packageJson2["intl-party"]) {
167
- return mergeConfig(DEFAULT_CONFIG, packageJson2["intl-party"]);
74
+ const packageJson = await import_fs_extra.default.readJson(packageJsonPath);
75
+ if (packageJson["intl-party"]) {
76
+ return mergeConfig(DEFAULT_CONFIG, packageJson["intl-party"]);
168
77
  }
169
78
  } catch {
170
79
  }
@@ -188,20 +97,20 @@ async function autoDetectConfig() {
188
97
  try {
189
98
  const entries = await import_fs_extra.default.readdir(basePath);
190
99
  const locales = entries.filter(
191
- (entry) => import_fs_extra.default.statSync(import_path.default.join(basePath, entry)).isDirectory()
100
+ (entry) => import_fs_extra.default.statSync(import_node_path.default.join(basePath, entry)).isDirectory()
192
101
  );
193
102
  if (locales.length > 0) {
194
103
  config.locales = locales;
195
104
  config.translationPaths = {};
196
- const firstLocaleDir = import_path.default.join(basePath, locales[0]);
105
+ const firstLocaleDir = import_node_path.default.join(basePath, locales[0]);
197
106
  const namespaceFiles = await import_fs_extra.default.readdir(firstLocaleDir);
198
- const namespaces = namespaceFiles.filter((file) => file.endsWith(".json")).map((file) => import_path.default.basename(file, ".json"));
107
+ const namespaces = namespaceFiles.filter((file) => file.endsWith(".json")).map((file) => import_node_path.default.basename(file, ".json"));
199
108
  if (namespaces.length > 0) {
200
109
  config.namespaces = namespaces;
201
110
  for (const locale of locales) {
202
111
  config.translationPaths[locale] = {};
203
112
  for (const namespace of namespaces) {
204
- config.translationPaths[locale][namespace] = import_path.default.join(
113
+ config.translationPaths[locale][namespace] = import_node_path.default.join(
205
114
  basePath,
206
115
  locale,
207
116
  `${namespace}.json`
@@ -218,7 +127,7 @@ async function autoDetectConfig() {
218
127
  return config;
219
128
  }
220
129
  function mergeConfig(defaultConfig, userConfig) {
221
- return {
130
+ const merged = {
222
131
  ...defaultConfig,
223
132
  ...userConfig,
224
133
  validation: {
@@ -238,13 +147,67 @@ function mergeConfig(defaultConfig, userConfig) {
238
147
  ...userConfig.translationPaths
239
148
  }
240
149
  };
150
+ if (userConfig.messages && !userConfig.outputDir) {
151
+ merged.outputDir = userConfig.messages;
152
+ }
153
+ if (userConfig.sourceDir && !userConfig.sourcePatterns) {
154
+ merged.sourcePatterns = [
155
+ import_node_path.default.join(userConfig.sourceDir, "**/*.{ts,tsx,js,jsx}")
156
+ ];
157
+ }
158
+ return merged;
241
159
  }
242
160
  async function saveConfig(config, configPath = "intl-party.config.json") {
243
161
  await import_fs_extra.default.writeFile(configPath, JSON.stringify(config, null, 2));
244
162
  }
163
+ var import_fs_extra, import_node_path, DEFAULT_CONFIG;
164
+ var init_config = __esm({
165
+ "src/utils/config.ts"() {
166
+ "use strict";
167
+ import_fs_extra = __toESM(require("fs-extra"));
168
+ import_node_path = __toESM(require("path"));
169
+ DEFAULT_CONFIG = {
170
+ locales: ["en", "es", "fr"],
171
+ defaultLocale: "en",
172
+ namespaces: ["common"],
173
+ translationPaths: {},
174
+ sourcePatterns: ["src/**/*.{ts,tsx,js,jsx}"],
175
+ outputDir: "./translations",
176
+ validation: {
177
+ strict: false,
178
+ logMissing: true,
179
+ throwOnMissing: false,
180
+ validateFormats: true
181
+ },
182
+ extraction: {
183
+ keyPrefix: "",
184
+ markExtracted: true,
185
+ sortKeys: true,
186
+ includeMetadata: false
187
+ },
188
+ sync: {
189
+ removeUnused: false,
190
+ addMissing: true,
191
+ preserveOrder: true
192
+ }
193
+ };
194
+ }
195
+ });
196
+
197
+ // src/cli.ts
198
+ var import_commander2 = require("commander");
199
+ var import_chalk8 = __toESM(require("chalk"));
200
+
201
+ // src/commands/validate.ts
202
+ var import_chalk = __toESM(require("chalk"));
203
+ var import_ora = __toESM(require("ora"));
204
+ var import_fs_extra3 = __toESM(require("fs-extra"));
205
+ var import_core = require("@intl-party/core");
206
+ init_config();
245
207
 
246
208
  // src/utils/translations.ts
247
209
  var import_fs_extra2 = __toESM(require("fs-extra"));
210
+ var import_node_path2 = __toESM(require("path"));
248
211
  async function loadTranslations(translationPaths, locales, namespaces) {
249
212
  const translations = {};
250
213
  for (const locale of locales) {
@@ -268,6 +231,21 @@ async function loadTranslations(translationPaths, locales, namespaces) {
268
231
  }
269
232
  return translations;
270
233
  }
234
+ async function saveTranslations(translations, translationPaths) {
235
+ for (const [locale, localeTranslations] of Object.entries(translations)) {
236
+ for (const [namespace, namespaceTranslations] of Object.entries(
237
+ localeTranslations
238
+ )) {
239
+ const translationPath = translationPaths[locale]?.[namespace];
240
+ if (translationPath) {
241
+ await import_fs_extra2.default.ensureDir(import_node_path2.default.dirname(translationPath));
242
+ await import_fs_extra2.default.writeJson(translationPath, namespaceTranslations, {
243
+ spaces: 2
244
+ });
245
+ }
246
+ }
247
+ }
248
+ }
271
249
 
272
250
  // src/commands/validate.ts
273
251
  async function validateCommand(options) {
@@ -432,12 +410,23 @@ var import_chalk2 = __toESM(require("chalk"));
432
410
  var import_ora2 = __toESM(require("ora"));
433
411
  var import_glob = require("glob");
434
412
  var import_fs_extra4 = __toESM(require("fs-extra"));
435
- var import_path2 = __toESM(require("path"));
413
+ var import_node_path3 = __toESM(require("path"));
414
+ init_config();
436
415
  async function extractCommand(options) {
437
- const spinner = (0, import_ora2.default)("Extracting translation keys...").start();
416
+ const spinner = (0, import_ora2.default)("Loading configuration...").start();
417
+ let config;
418
+ try {
419
+ config = await loadConfig(options.config);
420
+ spinner.succeed("Configuration loaded");
421
+ } catch (error) {
422
+ spinner.fail("Failed to load configuration");
423
+ console.error(import_chalk2.default.red("Error:"), error instanceof Error ? error.message : error);
424
+ process.exit(1);
425
+ }
426
+ spinner.start("Extracting translation keys...");
438
427
  try {
439
- const sourcePatterns = options.source || ["src/**/*.{ts,tsx,js,jsx}"];
440
- const outputDir = options.output || "./translations";
428
+ const sourcePatterns = options.source || config.sourcePatterns || ["src/**/*.{ts,tsx,js,jsx}"];
429
+ const outputDir = options.output || config.outputDir || "./messages";
441
430
  const files = await (0, import_glob.glob)(sourcePatterns);
442
431
  spinner.succeed(`Found ${files.length} source files`);
443
432
  const extractedKeys = /* @__PURE__ */ new Set();
@@ -454,7 +443,7 @@ async function extractCommand(options) {
454
443
  });
455
444
  return;
456
445
  }
457
- await writeExtractedKeys(Array.from(extractedKeys), outputDir, options);
446
+ await writeExtractedKeys(Array.from(extractedKeys), outputDir, config, options);
458
447
  console.log(import_chalk2.default.green(`\u2713 Translation keys extracted to ${outputDir}`));
459
448
  } catch (error) {
460
449
  spinner.fail("Extraction failed");
@@ -472,6 +461,8 @@ function extractKeysFromContent(content) {
472
461
  // t('key')
473
462
  /useTranslations\(\)\(['"`]([^'"`]+)['"`]\)/g,
474
463
  // useTranslations()('key')
464
+ /useTranslations\(['"`]([^'"`]+)['"`]\)\(['"`]([^'"`]+)['"`]\)/g,
465
+ // useTranslations('ns')('key')
475
466
  /i18nKey=['"`]([^'"`]+)['"`]/g,
476
467
  // i18nKey="key"
477
468
  /\{\s*t\(['"`]([^'"`]+)['"`]\)\s*\}/g
@@ -480,12 +471,16 @@ function extractKeysFromContent(content) {
480
471
  for (const pattern of patterns) {
481
472
  let match;
482
473
  while ((match = pattern.exec(content)) !== null) {
483
- keys.push(match[1]);
474
+ if (match[2]) {
475
+ keys.push(`${match[1]}.${match[2]}`);
476
+ } else {
477
+ keys.push(match[1]);
478
+ }
484
479
  }
485
480
  }
486
481
  return keys;
487
482
  }
488
- async function writeExtractedKeys(keys, outputDir, options) {
483
+ async function writeExtractedKeys(keys, outputDir, config, options) {
489
484
  await import_fs_extra4.default.ensureDir(outputDir);
490
485
  const namespaces = { common: [] };
491
486
  for (const key of keys) {
@@ -501,46 +496,273 @@ async function writeExtractedKeys(keys, outputDir, options) {
501
496
  namespaces.common.push(key);
502
497
  }
503
498
  }
504
- for (const [namespace, namespaceKeys] of Object.entries(namespaces)) {
505
- if (namespaceKeys.length === 0) continue;
506
- const filePath = import_path2.default.join(outputDir, "en", `${namespace}.json`);
507
- await import_fs_extra4.default.ensureDir(import_path2.default.dirname(filePath));
508
- let translations = {};
509
- if (options.update && await import_fs_extra4.default.pathExists(filePath)) {
510
- try {
511
- translations = await import_fs_extra4.default.readJson(filePath);
512
- } catch {
499
+ const locales = config.locales || ["en"];
500
+ for (const locale of locales) {
501
+ for (const [namespace, namespaceKeys] of Object.entries(namespaces)) {
502
+ if (namespaceKeys.length === 0) continue;
503
+ const filePath = import_node_path3.default.join(outputDir, locale, `${namespace}.json`);
504
+ await import_fs_extra4.default.ensureDir(import_node_path3.default.dirname(filePath));
505
+ let translations = {};
506
+ if ((options.update || locale !== config.defaultLocale) && await import_fs_extra4.default.pathExists(filePath)) {
507
+ try {
508
+ translations = await import_fs_extra4.default.readJson(filePath);
509
+ } catch {
510
+ }
513
511
  }
514
- }
515
- for (const key of namespaceKeys) {
516
- if (!translations[key]) {
517
- translations[key] = key;
512
+ for (const key of namespaceKeys) {
513
+ if (!translations[key]) {
514
+ translations[key] = locale === config.defaultLocale ? key : "";
515
+ }
516
+ }
517
+ if (config.extraction?.sortKeys !== false) {
518
+ const sortedTranslations = {};
519
+ Object.keys(translations).sort().forEach((k) => {
520
+ sortedTranslations[k] = translations[k];
521
+ });
522
+ translations = sortedTranslations;
518
523
  }
524
+ await import_fs_extra4.default.writeJson(filePath, translations, { spaces: 2 });
519
525
  }
520
- await import_fs_extra4.default.writeJson(filePath, translations, { spaces: 2 });
521
526
  }
522
527
  }
523
528
 
524
529
  // src/commands/sync.ts
525
530
  var import_chalk3 = __toESM(require("chalk"));
531
+ var import_ora3 = __toESM(require("ora"));
532
+ var import_inquirer = __toESM(require("inquirer"));
533
+ init_config();
526
534
  async function syncCommand(options) {
527
- console.log(import_chalk3.default.blue("Sync command not yet implemented"));
528
- console.log("Options:", options);
535
+ const spinner = (0, import_ora3.default)("Loading configuration...").start();
536
+ try {
537
+ const config = await loadConfig(options.config);
538
+ spinner.text = "Loading translations...";
539
+ const translations = await loadTranslations(
540
+ config.translationPaths,
541
+ config.locales,
542
+ config.namespaces
543
+ );
544
+ spinner.succeed("Configuration loaded");
545
+ const baseLocale = options.base || config.defaultLocale;
546
+ const targetLocales = options.target || config.locales.filter((l) => l !== baseLocale);
547
+ if (!config.locales.includes(baseLocale)) {
548
+ throw new Error(`Base locale '${baseLocale}' not found in configuration`);
549
+ }
550
+ const analysis = analyzeTranslations(
551
+ translations,
552
+ baseLocale,
553
+ targetLocales,
554
+ config.namespaces
555
+ );
556
+ if (options.verbose) {
557
+ displayAnalysis(analysis);
558
+ }
559
+ if (options.interactive && (analysis.missingKeys.length > 0 || analysis.unusedKeys.length > 0)) {
560
+ const shouldProceed = await confirmSync(analysis);
561
+ if (!shouldProceed) {
562
+ console.log(import_chalk3.default.yellow("Sync cancelled by user"));
563
+ return;
564
+ }
565
+ }
566
+ const updatedTranslations = await performSync(
567
+ translations,
568
+ analysis,
569
+ baseLocale,
570
+ targetLocales,
571
+ config.namespaces,
572
+ options
573
+ );
574
+ spinner.start("Saving translations...");
575
+ await saveTranslations(updatedTranslations, config.translationPaths);
576
+ spinner.succeed("Translations synchronized successfully");
577
+ displaySummary(analysis, updatedTranslations);
578
+ } catch (error) {
579
+ spinner.fail("Sync failed");
580
+ console.error(
581
+ import_chalk3.default.red("Error:"),
582
+ error instanceof Error ? error.message : error
583
+ );
584
+ process.exit(1);
585
+ }
586
+ }
587
+ function analyzeTranslations(translations, baseLocale, targetLocales, namespaces) {
588
+ const missingKeys = [];
589
+ const unusedKeys = [];
590
+ const baseKeys = /* @__PURE__ */ new Set();
591
+ for (const namespace of namespaces) {
592
+ const baseTranslations = translations[baseLocale]?.[namespace] || {};
593
+ collectKeys(baseTranslations, "", baseKeys);
594
+ }
595
+ for (const locale of targetLocales) {
596
+ for (const namespace of namespaces) {
597
+ const targetTranslations = translations[locale]?.[namespace] || {};
598
+ const targetKeys = /* @__PURE__ */ new Set();
599
+ collectKeys(targetTranslations, "", targetKeys);
600
+ for (const key of baseKeys) {
601
+ if (!targetKeys.has(key)) {
602
+ missingKeys.push({ locale, namespace, key });
603
+ }
604
+ }
605
+ }
606
+ }
607
+ for (const locale of targetLocales) {
608
+ for (const namespace of namespaces) {
609
+ const targetTranslations = translations[locale]?.[namespace] || {};
610
+ const targetKeys = /* @__PURE__ */ new Set();
611
+ collectKeys(targetTranslations, "", targetKeys);
612
+ for (const key of targetKeys) {
613
+ if (!baseKeys.has(key)) {
614
+ unusedKeys.push({ locale, namespace, key });
615
+ }
616
+ }
617
+ }
618
+ }
619
+ return {
620
+ missingKeys,
621
+ unusedKeys,
622
+ totalKeys: baseKeys.size,
623
+ missingCount: missingKeys.length,
624
+ unusedCount: unusedKeys.length
625
+ };
626
+ }
627
+ function collectKeys(obj, prefix, keys) {
628
+ for (const [key, value] of Object.entries(obj)) {
629
+ const fullKey = prefix ? `${prefix}.${key}` : key;
630
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
631
+ collectKeys(value, fullKey, keys);
632
+ } else {
633
+ keys.add(fullKey);
634
+ }
635
+ }
636
+ }
637
+ function displayAnalysis(analysis) {
638
+ console.log(import_chalk3.default.bold("\n\u{1F4CA} Translation Analysis:"));
639
+ console.log(`Total keys in base locale: ${import_chalk3.default.blue(analysis.totalKeys)}`);
640
+ console.log(`Missing keys: ${import_chalk3.default.yellow(analysis.missingCount)}`);
641
+ console.log(`Unused keys: ${import_chalk3.default.red(analysis.unusedCount)}`);
642
+ if (analysis.missingKeys.length > 0) {
643
+ console.log(import_chalk3.default.yellow("\n\u26A0\uFE0F Missing Keys:"));
644
+ const grouped = groupKeysByLocale(analysis.missingKeys);
645
+ for (const [locale, keys] of Object.entries(grouped)) {
646
+ console.log(import_chalk3.default.gray(` ${locale}: ${keys.length} keys`));
647
+ if (keys.length <= 10) {
648
+ keys.forEach(
649
+ (key) => console.log(import_chalk3.default.gray(` - ${key.namespace}.${key.key}`))
650
+ );
651
+ }
652
+ }
653
+ }
654
+ if (analysis.unusedKeys.length > 0) {
655
+ console.log(import_chalk3.default.red("\n\u{1F5D1}\uFE0F Unused Keys:"));
656
+ const grouped = groupKeysByLocale(analysis.unusedKeys);
657
+ for (const [locale, keys] of Object.entries(grouped)) {
658
+ console.log(import_chalk3.default.gray(` ${locale}: ${keys.length} keys`));
659
+ if (keys.length <= 10) {
660
+ keys.forEach(
661
+ (key) => console.log(import_chalk3.default.gray(` - ${key.namespace}.${key.key}`))
662
+ );
663
+ }
664
+ }
665
+ }
666
+ }
667
+ function groupKeysByLocale(keys) {
668
+ return keys.reduce(
669
+ (acc, key) => {
670
+ if (!acc[key.locale]) acc[key.locale] = [];
671
+ acc[key.locale].push(key);
672
+ return acc;
673
+ },
674
+ {}
675
+ );
676
+ }
677
+ async function confirmSync(analysis) {
678
+ const questions = [];
679
+ if (analysis.missingCount > 0) {
680
+ questions.push({
681
+ type: "confirm",
682
+ name: "addMissing",
683
+ message: `Add ${analysis.missingCount} missing translation keys?`,
684
+ default: true
685
+ });
686
+ }
687
+ if (analysis.unusedCount > 0) {
688
+ questions.push({
689
+ type: "confirm",
690
+ name: "removeUnused",
691
+ message: `Remove ${analysis.unusedCount} unused translation keys?`,
692
+ default: false
693
+ });
694
+ }
695
+ const answers = await import_inquirer.default.prompt(questions);
696
+ return answers.addMissing || answers.removeUnused;
697
+ }
698
+ async function performSync(translations, analysis, baseLocale, targetLocales, namespaces, options) {
699
+ const updatedTranslations = JSON.parse(JSON.stringify(translations));
700
+ if (analysis.missingKeys.length > 0 && (options.missingOnly || !options.missingOnly)) {
701
+ for (const missing of analysis.missingKeys) {
702
+ const baseValue = getNestedValue(
703
+ updatedTranslations[baseLocale]?.[missing.namespace] || {},
704
+ missing.key
705
+ );
706
+ setNestedValue(
707
+ updatedTranslations[missing.locale][missing.namespace],
708
+ missing.key,
709
+ baseValue
710
+ );
711
+ }
712
+ }
713
+ if (analysis.unusedKeys.length > 0 && !options.missingOnly) {
714
+ for (const unused of analysis.unusedKeys) {
715
+ removeNestedValue(
716
+ updatedTranslations[unused.locale][unused.namespace],
717
+ unused.key
718
+ );
719
+ }
720
+ }
721
+ return updatedTranslations;
722
+ }
723
+ function getNestedValue(obj, path6) {
724
+ return path6.split(".").reduce((current, key) => current?.[key], obj);
725
+ }
726
+ function setNestedValue(obj, path6, value) {
727
+ const keys = path6.split(".");
728
+ const lastKey = keys.pop();
729
+ const target = keys.reduce((current, key) => {
730
+ if (!current[key]) current[key] = {};
731
+ return current[key];
732
+ }, obj);
733
+ target[lastKey] = value;
734
+ }
735
+ function removeNestedValue(obj, path6) {
736
+ const keys = path6.split(".");
737
+ const lastKey = keys.pop();
738
+ const target = keys.reduce((current, key) => current?.[key], obj);
739
+ if (target) {
740
+ delete target[lastKey];
741
+ }
742
+ }
743
+ function displaySummary(analysis, translations) {
744
+ console.log(import_chalk3.default.bold.green("\n\u2705 Sync Complete!"));
745
+ console.log(`Added ${import_chalk3.default.green(analysis.missingCount)} missing keys`);
746
+ console.log(`Removed ${import_chalk3.default.red(analysis.unusedCount)} unused keys`);
747
+ console.log(
748
+ `Total translations: ${Object.keys(translations).length} locales`
749
+ );
529
750
  }
530
751
 
531
752
  // src/commands/init.ts
532
753
  var import_chalk4 = __toESM(require("chalk"));
533
- var import_ora3 = __toESM(require("ora"));
754
+ var import_ora4 = __toESM(require("ora"));
534
755
  var import_fs_extra5 = __toESM(require("fs-extra"));
535
- var import_path3 = __toESM(require("path"));
536
- var import_inquirer = __toESM(require("inquirer"));
756
+ var import_node_path4 = __toESM(require("path"));
757
+ var import_inquirer2 = __toESM(require("inquirer"));
758
+ init_config();
537
759
  async function initCommand(options) {
538
- const spinner = (0, import_ora3.default)("Initializing IntlParty configuration...").start();
760
+ const spinner = (0, import_ora4.default)("Initializing IntlParty configuration...").start();
539
761
  try {
540
762
  const configPath = "intl-party.config.json";
541
763
  if (await import_fs_extra5.default.pathExists(configPath) && !options.force) {
542
764
  spinner.stop();
543
- const { overwrite } = await import_inquirer.default.prompt([
765
+ const { overwrite } = await import_inquirer2.default.prompt([
544
766
  {
545
767
  type: "confirm",
546
768
  name: "overwrite",
@@ -555,7 +777,7 @@ async function initCommand(options) {
555
777
  }
556
778
  spinner.start("Setting up configuration...");
557
779
  spinner.stop();
558
- const answers = await import_inquirer.default.prompt([
780
+ const answers = await import_inquirer2.default.prompt([
559
781
  {
560
782
  type: "input",
561
783
  name: "defaultLocale",
@@ -617,7 +839,7 @@ async function initCommand(options) {
617
839
  for (const locale of answers.locales) {
618
840
  config.translationPaths[locale] = {};
619
841
  for (const namespace of answers.namespaces) {
620
- config.translationPaths[locale][namespace] = import_path3.default.join(
842
+ config.translationPaths[locale][namespace] = import_node_path4.default.join(
621
843
  answers.translationsDir,
622
844
  locale,
623
845
  `${namespace}.json`
@@ -627,10 +849,10 @@ async function initCommand(options) {
627
849
  spinner.start("Creating directory structure...");
628
850
  await import_fs_extra5.default.ensureDir(answers.translationsDir);
629
851
  for (const locale of answers.locales) {
630
- const localeDir = import_path3.default.join(answers.translationsDir, locale);
852
+ const localeDir = import_node_path4.default.join(answers.translationsDir, locale);
631
853
  await import_fs_extra5.default.ensureDir(localeDir);
632
854
  for (const namespace of answers.namespaces) {
633
- const filePath = import_path3.default.join(localeDir, `${namespace}.json`);
855
+ const filePath = import_node_path4.default.join(localeDir, `${namespace}.json`);
634
856
  if (!await import_fs_extra5.default.pathExists(filePath)) {
635
857
  await import_fs_extra5.default.writeJson(filePath, {}, { spaces: 2 });
636
858
  }
@@ -774,10 +996,11 @@ console.log(i18n.t('welcome'));
774
996
 
775
997
  // src/commands/check.ts
776
998
  var import_chalk5 = __toESM(require("chalk"));
777
- var import_ora4 = __toESM(require("ora"));
999
+ var import_ora5 = __toESM(require("ora"));
1000
+ init_config();
778
1001
  var import_core2 = require("@intl-party/core");
779
1002
  async function checkCommand(options) {
780
- const spinner = (0, import_ora4.default)("Loading configuration...").start();
1003
+ const spinner = (0, import_ora5.default)("Loading configuration...").start();
781
1004
  try {
782
1005
  const config = await loadConfig(options.config);
783
1006
  spinner.succeed("Configuration loaded");
@@ -899,46 +1122,927 @@ async function checkCommand(options) {
899
1122
  }
900
1123
 
901
1124
  // src/commands/generate.ts
1125
+ var import_fs_extra6 = __toESM(require("fs-extra"));
1126
+ var import_node_path5 = __toESM(require("path"));
1127
+ var import_crypto = __toESM(require("crypto"));
902
1128
  var import_chalk6 = __toESM(require("chalk"));
1129
+ var import_ora6 = __toESM(require("ora"));
1130
+ var import_chokidar = require("chokidar");
1131
+ init_config();
1132
+ async function getMessageData(configPath, options) {
1133
+ let config;
1134
+ let locales;
1135
+ let namespaces;
1136
+ let translationPaths;
1137
+ if (configPath && await import_fs_extra6.default.pathExists(configPath)) {
1138
+ config = await loadConfig(configPath);
1139
+ locales = config.locales;
1140
+ namespaces = config.namespaces;
1141
+ translationPaths = config.translationPaths;
1142
+ } else {
1143
+ if (options?.verbose) {
1144
+ console.log(
1145
+ import_chalk6.default.gray("No config file found, auto-detecting from filesystem...")
1146
+ );
1147
+ }
1148
+ const autoDetected = await autoDetectMessages(options);
1149
+ locales = autoDetected.locales;
1150
+ namespaces = autoDetected.namespaces;
1151
+ translationPaths = autoDetected.translationPaths;
1152
+ }
1153
+ if (config) {
1154
+ const nextjsConfig = config.shared;
1155
+ if (nextjsConfig && nextjsConfig.messagesPath && nextjsConfig.locales && nextjsConfig.namespaces) {
1156
+ translationPaths = {};
1157
+ for (const locale of nextjsConfig.locales) {
1158
+ translationPaths[locale] = {};
1159
+ for (const namespace of nextjsConfig.namespaces) {
1160
+ translationPaths[locale][namespace] = import_node_path5.default.join(
1161
+ process.cwd(),
1162
+ nextjsConfig.messagesPath,
1163
+ locale,
1164
+ `${namespace}.json`
1165
+ );
1166
+ }
1167
+ }
1168
+ locales = nextjsConfig.locales;
1169
+ namespaces = nextjsConfig.namespaces;
1170
+ if (options?.verbose) {
1171
+ console.log(
1172
+ import_chalk6.default.gray(
1173
+ `Using Next.js config: ${locales.length} locales, ${namespaces.length} namespaces`
1174
+ )
1175
+ );
1176
+ console.log(import_chalk6.default.gray(`Messages path: ${nextjsConfig.messagesPath}`));
1177
+ }
1178
+ } else if (config.messagesPath && config.locales && config.namespaces) {
1179
+ const standardConfig = config;
1180
+ translationPaths = {};
1181
+ for (const locale of standardConfig.locales) {
1182
+ translationPaths[locale] = {};
1183
+ for (const namespace of standardConfig.namespaces) {
1184
+ translationPaths[locale][namespace] = import_node_path5.default.join(
1185
+ process.cwd(),
1186
+ standardConfig.messagesPath,
1187
+ locale,
1188
+ `${namespace}.json`
1189
+ );
1190
+ }
1191
+ }
1192
+ locales = standardConfig.locales;
1193
+ namespaces = standardConfig.namespaces;
1194
+ if (options?.verbose) {
1195
+ console.log(
1196
+ import_chalk6.default.gray(
1197
+ `Using standard config: ${locales.length} locales, ${namespaces.length} namespaces`
1198
+ )
1199
+ );
1200
+ console.log(
1201
+ import_chalk6.default.gray(`Messages path: ${standardConfig.messagesPath}`)
1202
+ );
1203
+ }
1204
+ }
1205
+ }
1206
+ const messages = await loadTranslations(
1207
+ translationPaths,
1208
+ locales,
1209
+ namespaces
1210
+ );
1211
+ const translationKeys = /* @__PURE__ */ new Set();
1212
+ const namespaceKeys = /* @__PURE__ */ new Set();
1213
+ for (const locale of locales) {
1214
+ for (const namespace of namespaces) {
1215
+ const extractKeys = (obj, prefix = "") => {
1216
+ for (const [key, value] of Object.entries(obj)) {
1217
+ const fullKey = prefix ? `${prefix}.${key}` : key;
1218
+ const namespaceKey = prefix ? key : fullKey;
1219
+ translationKeys.add(fullKey);
1220
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
1221
+ extractKeys(value, fullKey);
1222
+ } else {
1223
+ const dotNotationKey = fullKey.replace(`${namespace}.`, "");
1224
+ namespaceKeys.add(dotNotationKey);
1225
+ }
1226
+ }
1227
+ };
1228
+ if (messages[locale]?.[namespace]) {
1229
+ extractKeys(messages[locale][namespace], namespace);
1230
+ }
1231
+ }
1232
+ }
1233
+ return {
1234
+ locales,
1235
+ namespaces,
1236
+ messages,
1237
+ translationKeys: Array.from(translationKeys).sort(),
1238
+ namespaceKeys: Array.from(namespaceKeys).sort()
1239
+ };
1240
+ }
1241
+ function generateTypescriptTypes(data) {
1242
+ const { locales, namespaces, translationKeys, namespaceKeys } = data;
1243
+ const keyUnion = translationKeys.map((key) => `"${key}"`).join(" | ");
1244
+ const namespaceKeyUnion = namespaceKeys.map((key) => `"${key}"`).join(" | ");
1245
+ const namespaceTypes = namespaces.map((ns) => {
1246
+ const messageStructure = data.messages[locales[0]]?.[ns];
1247
+ if (!messageStructure) return ` "${ns}": {};`;
1248
+ const generateNestedInterface = (obj, indent = 2) => {
1249
+ const spaces = " ".repeat(indent);
1250
+ const entries = Object.entries(obj);
1251
+ if (entries.length === 0) return "{}";
1252
+ const interfaceLines = entries.map(([key, value]) => {
1253
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
1254
+ return `${spaces}"${key}": ${generateNestedInterface(value, indent + 1)};`;
1255
+ } else {
1256
+ return `${spaces}"${key}": string;`;
1257
+ }
1258
+ });
1259
+ return `{
1260
+ ${interfaceLines.join("\n")}
1261
+ ${" ".repeat(indent - 1)}}`;
1262
+ };
1263
+ return ` "${ns}": ${generateNestedInterface(messageStructure)};`;
1264
+ }).join("\n");
1265
+ const localeTypes = locales.map((locale) => {
1266
+ return ` "${locale}": {
1267
+ ${namespaceTypes}
1268
+ };`;
1269
+ }).join("\n");
1270
+ return `// Generated by @intl-party/cli - do not edit
1271
+ // This file contains type-safe definitions for your translations
1272
+
1273
+ export type TranslationKey = ${keyUnion};
1274
+
1275
+ export type NamespaceTranslationKey = ${namespaceKeyUnion};
1276
+
1277
+ export type TranslationNamespace = ${namespaces.map((ns) => `"${ns}"`).join(" | ")};
1278
+
1279
+ export type Locale = ${locales.map((locale) => `"${locale}"`).join(" | ")};
1280
+
1281
+ export interface Translations {
1282
+ ${localeTypes}
1283
+ }
1284
+
1285
+ export interface NamespaceTranslations {
1286
+ ${namespaceTypes}
1287
+ }
1288
+
1289
+ // Helper type for getting translation value type
1290
+ export type TranslationValue<T extends TranslationKey> = string;
1291
+
1292
+ // Helper type for getting namespace translations
1293
+ export type GetNamespaceTranslations<N extends TranslationNamespace> =
1294
+ Translations[Locale][N];
1295
+
1296
+ // Type-safe translation function signature
1297
+ export interface TranslationFunction {
1298
+ <T extends TranslationKey>(key: T, options?: Record<string, any>): TranslationValue<T>;
1299
+ <T extends TranslationNamespace>(namespace: T): GetNamespaceTranslations<T>;
1300
+ }
1301
+
1302
+ // Default messages object (for runtime usage)
1303
+ export const defaultMessages: Translations = ${JSON.stringify(data.messages, null, 2)} as const;
1304
+ `;
1305
+ }
1306
+ function generateClientMessages(data) {
1307
+ return `// Generated by @intl-party/cli - do not edit
1308
+ // This file contains runtime message data for the client package
1309
+
1310
+ import type { Translations } from './translations.generated';
1311
+
1312
+ export const messages: Translations = ${JSON.stringify(data.messages, null, 2)} as const;
1313
+
1314
+ // Re-export for convenience
1315
+ export { messages as defaultMessages } from './translations.generated';
1316
+ `;
1317
+ }
1318
+ function generateJavaScriptMessages(data) {
1319
+ return `// Generated by @intl-party/cli - do not edit
1320
+ // This file contains runtime message data for easy imports
1321
+
1322
+ export const defaultMessages = ${JSON.stringify(data.messages, null, 2)};
1323
+
1324
+ // Export individual locale messages for convenience
1325
+ ${data.locales.map((locale) => `export const ${locale}Messages = defaultMessages.${locale};`).join("\n")}
1326
+ `;
1327
+ }
1328
+ function generateClientIndex() {
1329
+ return `// Generated by @intl-party/cli - do not edit
1330
+ // This file is the main entry point for the client package
1331
+
1332
+ export * from './translations.generated';
1333
+ export * from './messages.generated';
1334
+ `;
1335
+ }
1336
+ function generateJsonSchemas(data) {
1337
+ const schemas = {};
1338
+ for (const locale of data.locales) {
1339
+ for (const namespace of data.namespaces) {
1340
+ const messages = data.messages[locale]?.[namespace] || {};
1341
+ const schema = createJsonSchema(messages);
1342
+ const schemaName = `${locale}_${namespace}`;
1343
+ schemas[schemaName] = {
1344
+ $schema: "http://json-schema.org/draft-07/schema#",
1345
+ $id: `#/schemas/${schemaName}`,
1346
+ title: `Translation schema for ${locale}/${namespace}`,
1347
+ description: `JSON schema for translation keys in ${namespace} namespace for ${locale} locale`,
1348
+ type: "object",
1349
+ properties: schema.properties,
1350
+ required: schema.required,
1351
+ additionalProperties: false
1352
+ };
1353
+ }
1354
+ }
1355
+ const combinedSchema = {
1356
+ $schema: "http://json-schema.org/draft-07/schema#",
1357
+ $id: "#/schemas/translations",
1358
+ title: "IntlParty Translation Schema",
1359
+ description: "JSON schema for all IntlParty translations",
1360
+ type: "object",
1361
+ properties: {},
1362
+ definitions: {}
1363
+ };
1364
+ for (const locale of data.locales) {
1365
+ combinedSchema.properties[locale] = {
1366
+ type: "object",
1367
+ description: `Translations for ${locale} locale`,
1368
+ properties: {}
1369
+ };
1370
+ for (const namespace of data.namespaces) {
1371
+ const schemaName = `${locale}_${namespace}`;
1372
+ combinedSchema.properties[locale].properties[namespace] = {
1373
+ $ref: `#/definitions/${schemaName}`
1374
+ };
1375
+ combinedSchema.definitions[schemaName] = schemas[schemaName];
1376
+ }
1377
+ }
1378
+ return JSON.stringify(
1379
+ {
1380
+ schemas,
1381
+ combined: combinedSchema,
1382
+ metadata: {
1383
+ generated: (/* @__PURE__ */ new Date()).toISOString(),
1384
+ locales: data.locales,
1385
+ namespaces: data.namespaces,
1386
+ version: "1.0.0"
1387
+ }
1388
+ },
1389
+ null,
1390
+ 2
1391
+ );
1392
+ }
1393
+ function createJsonSchema(obj, prefix = "") {
1394
+ const properties = {};
1395
+ const required = [];
1396
+ for (const [key, value] of Object.entries(obj)) {
1397
+ const fullKey = prefix ? `${prefix}.${key}` : key;
1398
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
1399
+ const nestedSchema = createJsonSchema(value, fullKey);
1400
+ properties[key] = {
1401
+ type: "object",
1402
+ properties: nestedSchema.properties,
1403
+ required: nestedSchema.required,
1404
+ description: `Translation key: ${fullKey}`
1405
+ };
1406
+ } else {
1407
+ properties[key] = {
1408
+ type: "string",
1409
+ description: `Translation key: ${fullKey}`,
1410
+ examples: [value]
1411
+ };
1412
+ required.push(key);
1413
+ }
1414
+ }
1415
+ return { properties, required };
1416
+ }
1417
+ function generateDocumentation(data) {
1418
+ const lines = [];
1419
+ lines.push("# Translation Documentation");
1420
+ lines.push("");
1421
+ lines.push(`Generated on: ${(/* @__PURE__ */ new Date()).toISOString()}`);
1422
+ lines.push(`Locales: ${data.locales.join(", ")}`);
1423
+ lines.push(`Namespaces: ${data.namespaces.join(", ")}`);
1424
+ lines.push("");
1425
+ lines.push("## Table of Contents");
1426
+ for (const locale of data.locales) {
1427
+ lines.push(`- [${locale.toUpperCase()}](#${locale.toLowerCase()})`);
1428
+ }
1429
+ lines.push("");
1430
+ for (const locale of data.locales) {
1431
+ lines.push(`## ${locale.toUpperCase()}`);
1432
+ lines.push("");
1433
+ for (const namespace of data.namespaces) {
1434
+ const messages = data.messages[locale]?.[namespace] || {};
1435
+ if (Object.keys(messages).length === 0) {
1436
+ continue;
1437
+ }
1438
+ lines.push(`### ${namespace} namespace`);
1439
+ lines.push("");
1440
+ generateNamespaceDocumentation(messages, lines, "");
1441
+ }
1442
+ lines.push("");
1443
+ }
1444
+ lines.push("## Summary");
1445
+ lines.push("");
1446
+ const totalKeys = Object.values(data.messages).flatMap((locale) => Object.values(locale)).reduce((total, namespace) => {
1447
+ return total + countKeys(namespace);
1448
+ }, 0);
1449
+ lines.push(`- **Total locales**: ${data.locales.length}`);
1450
+ lines.push(`- **Total namespaces**: ${data.namespaces.length}`);
1451
+ lines.push(`- **Total translation keys**: ${totalKeys}`);
1452
+ lines.push("");
1453
+ lines.push("### Keys by Locale");
1454
+ lines.push("");
1455
+ for (const locale of data.locales) {
1456
+ const localeKeys = Object.values(data.messages[locale] || {}).reduce(
1457
+ (total, namespace) => total + countKeys(namespace),
1458
+ 0
1459
+ );
1460
+ lines.push(`- **${locale}**: ${localeKeys} keys`);
1461
+ }
1462
+ return lines.join("\n");
1463
+ }
1464
+ function generateNamespaceDocumentation(obj, lines, prefix) {
1465
+ for (const [key, value] of Object.entries(obj)) {
1466
+ const fullKey = prefix ? `${prefix}.${key}` : key;
1467
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
1468
+ lines.push(`#### ${fullKey}`);
1469
+ lines.push("");
1470
+ lines.push("Nested translation object containing:");
1471
+ lines.push("");
1472
+ const nestedKeys = Object.keys(value);
1473
+ for (const nestedKey of nestedKeys) {
1474
+ lines.push(`- \`${fullKey}.${nestedKey}\``);
1475
+ }
1476
+ lines.push("");
1477
+ generateNamespaceDocumentation(value, lines, fullKey);
1478
+ } else {
1479
+ lines.push(`#### ${fullKey}`);
1480
+ lines.push("");
1481
+ lines.push(`**Translation**: \`"${value}"\``);
1482
+ lines.push("");
1483
+ const interpolationMatches = String(value).match(/\{\{([^}]+)\}\}/g);
1484
+ if (interpolationMatches) {
1485
+ lines.push("**Interpolation variables**:");
1486
+ lines.push("");
1487
+ const variables = interpolationMatches.map(
1488
+ (match) => match.replace(/[{}]/g, "")
1489
+ );
1490
+ const uniqueVariables = [...new Set(variables)];
1491
+ for (const variable of uniqueVariables) {
1492
+ lines.push(`- \`${variable}\``);
1493
+ }
1494
+ lines.push("");
1495
+ }
1496
+ }
1497
+ }
1498
+ }
1499
+ function countKeys(obj) {
1500
+ let count = 0;
1501
+ for (const value of Object.values(obj)) {
1502
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
1503
+ count += countKeys(value);
1504
+ } else {
1505
+ count += 1;
1506
+ }
1507
+ }
1508
+ return count;
1509
+ }
1510
+ async function autoDetectMessages(options) {
1511
+ const cwd = process.cwd();
1512
+ const possibleMessageDirs = [
1513
+ import_node_path5.default.join(cwd, "messages"),
1514
+ import_node_path5.default.join(cwd, "locales"),
1515
+ import_node_path5.default.join(cwd, "translations"),
1516
+ import_node_path5.default.join(cwd, "i18n")
1517
+ ];
1518
+ let messagesDir = null;
1519
+ for (const dir of possibleMessageDirs) {
1520
+ if (await import_fs_extra6.default.pathExists(dir)) {
1521
+ messagesDir = dir;
1522
+ break;
1523
+ }
1524
+ }
1525
+ if (!messagesDir) {
1526
+ throw new Error(
1527
+ "No messages directory found. Expected one of: messages/, locales/, translations/, i18n/"
1528
+ );
1529
+ }
1530
+ if (options?.verbose) {
1531
+ console.log(import_chalk6.default.gray(`Found messages directory: ${messagesDir}`));
1532
+ }
1533
+ const localeDirs = await import_fs_extra6.default.readdir(messagesDir);
1534
+ const detectedLocales = localeDirs.filter(async (dir) => {
1535
+ const localePath = import_node_path5.default.join(messagesDir, dir);
1536
+ const stat = await import_fs_extra6.default.stat(localePath);
1537
+ return stat.isDirectory();
1538
+ });
1539
+ const validLocales = [];
1540
+ for (const dir of localeDirs) {
1541
+ const localePath = import_node_path5.default.join(messagesDir, dir);
1542
+ const stat = await import_fs_extra6.default.stat(localePath);
1543
+ if (stat.isDirectory()) {
1544
+ validLocales.push(dir);
1545
+ }
1546
+ }
1547
+ if (validLocales.length === 0) {
1548
+ throw new Error(`No locale directories found in ${messagesDir}`);
1549
+ }
1550
+ const firstLocale = validLocales[0];
1551
+ const firstLocalePath = import_node_path5.default.join(messagesDir, firstLocale);
1552
+ const namespaceFiles = await import_fs_extra6.default.readdir(firstLocalePath);
1553
+ const detectedNamespaces = namespaceFiles.filter((file) => file.endsWith(".json")).map((file) => import_node_path5.default.basename(file, ".json"));
1554
+ if (detectedNamespaces.length === 0) {
1555
+ throw new Error(`No JSON files found in ${firstLocalePath}`);
1556
+ }
1557
+ const translationPaths = {};
1558
+ for (const locale of validLocales) {
1559
+ translationPaths[locale] = {};
1560
+ for (const namespace of detectedNamespaces) {
1561
+ translationPaths[locale][namespace] = import_node_path5.default.join(
1562
+ messagesDir,
1563
+ locale,
1564
+ `${namespace}.json`
1565
+ );
1566
+ }
1567
+ }
1568
+ if (options?.verbose) {
1569
+ console.log(
1570
+ import_chalk6.default.gray(
1571
+ `Auto-detected ${validLocales.length} locales: ${validLocales.join(", ")}`
1572
+ )
1573
+ );
1574
+ console.log(
1575
+ import_chalk6.default.gray(
1576
+ `Auto-detected ${detectedNamespaces.length} namespaces: ${detectedNamespaces.join(", ")}`
1577
+ )
1578
+ );
1579
+ }
1580
+ return {
1581
+ locales: validLocales,
1582
+ namespaces: detectedNamespaces,
1583
+ translationPaths
1584
+ };
1585
+ }
1586
+ function generateCacheHash(data) {
1587
+ const content = JSON.stringify({
1588
+ locales: data.locales.sort(),
1589
+ namespaces: data.namespaces.sort(),
1590
+ messages: data.messages
1591
+ });
1592
+ return import_crypto.default.createHash("md5").update(content).digest("hex");
1593
+ }
1594
+ async function writeGeneratedFiles(data, outputDir, options) {
1595
+ await import_fs_extra6.default.ensureDir(outputDir);
1596
+ const cacheHash = generateCacheHash(data);
1597
+ const cacheFilePath = import_node_path5.default.join(outputDir, ".intl-party-cache");
1598
+ let shouldRegenerate = true;
1599
+ if (await import_fs_extra6.default.pathExists(cacheFilePath)) {
1600
+ const existingHash = await import_fs_extra6.default.readFile(cacheFilePath, "utf-8");
1601
+ if (existingHash === cacheHash) {
1602
+ shouldRegenerate = false;
1603
+ }
1604
+ }
1605
+ if (!shouldRegenerate && !options.watch && !options.client) {
1606
+ if (options.verbose) {
1607
+ console.log(import_chalk6.default.gray("No changes detected, skipping generation"));
1608
+ }
1609
+ return;
1610
+ }
1611
+ if (options.types !== false) {
1612
+ const typesContent = generateTypescriptTypes(data);
1613
+ const typesFilePath = import_node_path5.default.join(outputDir, "translations.generated.ts");
1614
+ await import_fs_extra6.default.writeFile(typesFilePath, typesContent);
1615
+ const jsContent = generateJavaScriptMessages(data);
1616
+ const jsFilePath = import_node_path5.default.join(outputDir, "messages.generated.js");
1617
+ await import_fs_extra6.default.writeFile(jsFilePath, jsContent);
1618
+ if (options.verbose) {
1619
+ console.log(import_chalk6.default.green(`\u2713 Generated types: ${typesFilePath}`));
1620
+ }
1621
+ }
1622
+ if (options.schemas) {
1623
+ const schemasContent = generateJsonSchemas(data);
1624
+ const schemasFilePath = import_node_path5.default.join(outputDir, "schemas.json");
1625
+ await import_fs_extra6.default.writeFile(schemasFilePath, schemasContent);
1626
+ if (options.verbose) {
1627
+ console.log(import_chalk6.default.green(`\u2713 Generated schemas: ${schemasFilePath}`));
1628
+ }
1629
+ }
1630
+ if (options.docs) {
1631
+ const docsContent = generateDocumentation(data);
1632
+ const docsFilePath = import_node_path5.default.join(outputDir, "translations.md");
1633
+ await import_fs_extra6.default.writeFile(docsFilePath, docsContent);
1634
+ if (options.verbose) {
1635
+ console.log(import_chalk6.default.green(`\u2713 Generated documentation: ${docsFilePath}`));
1636
+ }
1637
+ }
1638
+ await import_fs_extra6.default.writeFile(cacheFilePath, cacheHash);
1639
+ }
1640
+ async function generateClientPackage(data, options) {
1641
+ console.log(import_chalk6.default.blue("\u{1F527} Generating client package files..."));
1642
+ if (options.verbose) {
1643
+ console.log(import_chalk6.default.gray(`Data: ${JSON.stringify(data, null, 2)}`));
1644
+ }
1645
+ let rootDir = process.cwd();
1646
+ while (rootDir !== import_node_path5.default.dirname(rootDir)) {
1647
+ const packageJsonPath = import_node_path5.default.join(rootDir, "package.json");
1648
+ if (await import_fs_extra6.default.pathExists(packageJsonPath)) {
1649
+ const packageJson = await import_fs_extra6.default.readJson(packageJsonPath);
1650
+ if (packageJson.name === "@intl-party/monorepo") {
1651
+ break;
1652
+ }
1653
+ }
1654
+ rootDir = import_node_path5.default.dirname(rootDir);
1655
+ }
1656
+ const clientDir = import_node_path5.default.join(rootDir, "packages/client/generated");
1657
+ await import_fs_extra6.default.ensureDir(clientDir);
1658
+ const typesContent = generateTypescriptTypes(data);
1659
+ const typesFilePath = import_node_path5.default.join(clientDir, "translations.generated.ts");
1660
+ if (options.verbose) {
1661
+ console.log(import_chalk6.default.gray(`Writing types to: ${typesFilePath}`));
1662
+ }
1663
+ await import_fs_extra6.default.writeFile(typesFilePath, typesContent);
1664
+ const messagesContent = generateClientMessages(data);
1665
+ const messagesFilePath = import_node_path5.default.join(clientDir, "messages.generated.ts");
1666
+ if (options.verbose) {
1667
+ console.log(import_chalk6.default.gray(`Writing messages to: ${messagesFilePath}`));
1668
+ }
1669
+ await import_fs_extra6.default.writeFile(messagesFilePath, messagesContent);
1670
+ const indexContent = generateClientIndex();
1671
+ const indexPath = import_node_path5.default.join(clientDir, "index.generated.ts");
1672
+ if (options.verbose) {
1673
+ console.log(import_chalk6.default.gray(`Writing index to: ${indexPath}`));
1674
+ }
1675
+ await import_fs_extra6.default.writeFile(indexPath, indexContent);
1676
+ if (options.verbose) {
1677
+ console.log(
1678
+ import_chalk6.default.green(`\u2713 Generated client package files in ${clientDir}`)
1679
+ );
1680
+ }
1681
+ }
1682
+ async function setupWatcher(configPath, outputDir, options) {
1683
+ const config = await loadConfig(configPath);
1684
+ const { translationPaths } = config;
1685
+ const watchPaths = [];
1686
+ for (const localePaths of Object.values(translationPaths)) {
1687
+ watchPaths.push(...Object.values(localePaths));
1688
+ }
1689
+ console.log(
1690
+ import_chalk6.default.blue(`\u{1F440} Watching for changes in ${watchPaths.length} files...`)
1691
+ );
1692
+ const watcher = (0, import_chokidar.watch)(watchPaths, {
1693
+ ignoreInitial: true,
1694
+ persistent: true
1695
+ });
1696
+ watcher.on("change", async (filePath) => {
1697
+ console.log(import_chalk6.default.yellow(`\u{1F4DD} File changed: ${filePath}`));
1698
+ try {
1699
+ const data = await getMessageData(configPath);
1700
+ await writeGeneratedFiles(data, outputDir, options);
1701
+ console.log(import_chalk6.default.green("\u2713 Regenerated translations"));
1702
+ } catch (error) {
1703
+ console.error(import_chalk6.default.red("\u2717 Failed to regenerate:"), error);
1704
+ }
1705
+ });
1706
+ process.on("SIGINT", () => {
1707
+ watcher.close();
1708
+ console.log(import_chalk6.default.gray("\n\u{1F44B} Stopped watching"));
1709
+ process.exit(0);
1710
+ });
1711
+ }
903
1712
  async function generateCommand(options) {
904
- console.log(import_chalk6.default.blue("Generate command not yet implemented"));
905
- console.log("Options:", options);
1713
+ const spinner = (0, import_ora6.default)("Loading translation data...").start();
1714
+ if (options.verbose) {
1715
+ console.log(
1716
+ import_chalk6.default.gray(`Debug options: ${JSON.stringify(options, null, 2)}`)
1717
+ );
1718
+ }
1719
+ try {
1720
+ const data = await getMessageData(options.config, options);
1721
+ spinner.succeed(
1722
+ `Loaded ${data.locales.length} locales, ${data.namespaces.length} namespaces, ${data.translationKeys.length} keys`
1723
+ );
1724
+ const outputDir = options.output || "./node_modules/.intl-party";
1725
+ spinner.start("Generating files...");
1726
+ await writeGeneratedFiles(data, outputDir, options);
1727
+ spinner.succeed("Files generated successfully");
1728
+ console.log(import_chalk6.default.green(`\u2713 Generated translation files in ${outputDir}`));
1729
+ if (options.client) {
1730
+ await generateClientPackage(data, options);
1731
+ }
1732
+ if (options.watch) {
1733
+ await setupWatcher(options.config, outputDir, options);
1734
+ }
1735
+ } catch (error) {
1736
+ spinner.fail("Generation failed");
1737
+ console.error(
1738
+ import_chalk6.default.red("Error:"),
1739
+ error instanceof Error ? error.message : error
1740
+ );
1741
+ process.exit(1);
1742
+ }
1743
+ }
1744
+
1745
+ // src/commands/nextjs.ts
1746
+ var import_commander = require("commander");
1747
+ var import_node_fs = require("fs");
1748
+ var import_node_path6 = require("path");
1749
+ var import_chalk7 = __toESM(require("chalk"));
1750
+ async function initializeNextjsProject(force = false) {
1751
+ console.log(import_chalk7.default.cyan("\u{1F680} Initializing IntlParty for Next.js..."));
1752
+ if ((0, import_node_fs.existsSync)("intl-party.config.ts") || (0, import_node_fs.existsSync)("intl-party.config.js")) {
1753
+ if (!force) {
1754
+ console.log(import_chalk7.default.yellow("\u26A0\uFE0F IntlParty already initialized!"));
1755
+ return true;
1756
+ }
1757
+ console.log(import_chalk7.default.yellow("\u26A0\uFE0F Force flag set, overwriting existing files..."));
1758
+ }
1759
+ const hasSrcDir = (0, import_node_fs.existsSync)("src");
1760
+ const baseDir = hasSrcDir ? "src" : ".";
1761
+ const appDir = (0, import_node_path6.join)(baseDir, "app");
1762
+ const configContent = `// IntlParty configuration for Next.js
1763
+ export default {
1764
+ locales: ["en", "es", "fr"],
1765
+ defaultLocale: "en",
1766
+ messages: "./messages",
1767
+ // localePrefix defaults to "never" for clean URLs
1768
+ // cookieName defaults to "INTL_LOCALE"
1769
+ };`;
1770
+ (0, import_node_fs.writeFileSync)("intl-party.config.ts", configContent);
1771
+ console.log(import_chalk7.default.green("\u2705 Created intl-party.config.ts"));
1772
+ const messagesDir = "messages";
1773
+ if (!(0, import_node_fs.existsSync)(messagesDir)) {
1774
+ (0, import_node_fs.mkdirSync)(messagesDir, { recursive: true });
1775
+ }
1776
+ const locales = ["en", "es", "fr"];
1777
+ const sampleMessagesBase = {
1778
+ welcome: "Welcome to IntlParty!",
1779
+ description: "A modern i18n solution for Next.js",
1780
+ navigation: {
1781
+ home: "Home",
1782
+ about: "About",
1783
+ contact: "Contact"
1784
+ }
1785
+ };
1786
+ locales.forEach((locale) => {
1787
+ const localeDir = (0, import_node_path6.join)(messagesDir, locale);
1788
+ if (!(0, import_node_fs.existsSync)(localeDir)) {
1789
+ (0, import_node_fs.mkdirSync)(localeDir, { recursive: true });
1790
+ }
1791
+ const messages = {
1792
+ ...sampleMessagesBase,
1793
+ navigation: { ...sampleMessagesBase.navigation }
1794
+ };
1795
+ if (locale === "es") {
1796
+ messages.welcome = "\xA1Bienvenido a IntlParty!";
1797
+ messages.description = "Una soluci\xF3n i18n moderna para Next.js";
1798
+ messages.navigation.home = "Inicio";
1799
+ messages.navigation.about = "Acerca de";
1800
+ messages.navigation.contact = "Contacto";
1801
+ } else if (locale === "fr") {
1802
+ messages.welcome = "Bienvenue chez IntlParty !";
1803
+ messages.description = "Une solution i18n moderne pour Next.js";
1804
+ messages.navigation.home = "Accueil";
1805
+ messages.navigation.about = "\xC0 propos";
1806
+ messages.navigation.contact = "Contact";
1807
+ }
1808
+ (0, import_node_fs.writeFileSync)(
1809
+ (0, import_node_path6.join)(localeDir, "common.json"),
1810
+ JSON.stringify(messages, null, 2)
1811
+ );
1812
+ });
1813
+ console.log(import_chalk7.default.green("\u2705 Created sample message files in ./messages"));
1814
+ const middlewarePath = hasSrcDir ? "src/middleware.ts" : "middleware.ts";
1815
+ const middlewareContent = `import { createSetup } from "@intl-party/nextjs";
1816
+ import config from "${hasSrcDir ? "../" : "./"}intl-party.config";
1817
+
1818
+ const { middleware, middlewareConfig } = createSetup(config);
1819
+
1820
+ export { middleware };
1821
+ export const config = middlewareConfig;`;
1822
+ (0, import_node_fs.writeFileSync)(middlewarePath, middlewareContent);
1823
+ console.log(import_chalk7.default.green(`\u2705 Created ${middlewarePath}`));
1824
+ if ((0, import_node_fs.existsSync)("next.config.js")) {
1825
+ const nextConfigIntlPath = "next.config.intl-party.js";
1826
+ const nextConfigContent = `const { createNextConfigWithIntl } = require("@intl-party/nextjs");
1827
+
1828
+ /** @type {import('next').NextConfig} */
1829
+ const nextConfig = {
1830
+ reactStrictMode: true,
1831
+ };
1832
+
1833
+ module.exports = createNextConfigWithIntl(
1834
+ {
1835
+ i18nConfig: require("./intl-party.config").default,
1836
+ autoGenerate: true,
1837
+ watchMode: true,
1838
+ },
1839
+ nextConfig
1840
+ );`;
1841
+ (0, import_node_fs.writeFileSync)(nextConfigIntlPath, nextConfigContent);
1842
+ console.log(
1843
+ import_chalk7.default.green(
1844
+ `\u2705 Created ${nextConfigIntlPath} (merge with your next.config.js)`
1845
+ )
1846
+ );
1847
+ }
1848
+ if (!(0, import_node_fs.existsSync)(appDir)) {
1849
+ (0, import_node_fs.mkdirSync)(appDir, { recursive: true });
1850
+ }
1851
+ const layoutContent = `import { createSetup } from "@intl-party/nextjs";
1852
+ import config from "${hasSrcDir ? "../../" : "../"}intl-party.config";
1853
+
1854
+ const { getLocale, getMessages, Provider } = createSetup(config);
1855
+
1856
+ export default async function RootLayout({
1857
+ children,
1858
+ }: {
1859
+ children: React.ReactNode;
1860
+ }) {
1861
+ const locale = await getLocale();
1862
+ const messages = await getMessages(locale);
1863
+
1864
+ return (
1865
+ <html lang={locale}>
1866
+ <body>
1867
+ <Provider locale={locale} initialMessages={messages}>
1868
+ {children}
1869
+ </Provider>
1870
+ </body>
1871
+ </html>
1872
+ );
1873
+ }`;
1874
+ (0, import_node_fs.writeFileSync)((0, import_node_path6.join)(appDir, "layout.intl-party.tsx"), layoutContent);
1875
+ const pageContent = `import { useTranslations } from "@intl-party/nextjs";
1876
+
1877
+ export default function HomePage() {
1878
+ const t = useTranslations("common");
1879
+
1880
+ return (
1881
+ <div style={{ padding: "2rem", fontFamily: "system-ui, sans-serif" }}>
1882
+ <h1>{t("welcome")}</h1>
1883
+ <p>{t("description")}</p>
1884
+
1885
+ <nav style={{ display: "flex", gap: "1rem", marginTop: "1rem" }}>
1886
+ <a href="/">{t("navigation.home")}</a>
1887
+ <a href="/about">{t("navigation.about")}</a>
1888
+ <a href="/contact">{t("navigation.contact")}</a>
1889
+ </nav>
1890
+ </div>
1891
+ );
1892
+ }`;
1893
+ (0, import_node_fs.writeFileSync)((0, import_node_path6.join)(appDir, "page.intl-party.tsx"), pageContent);
1894
+ console.log(import_chalk7.default.green(`\u2705 Created example files in ${appDir}`));
1895
+ if ((0, import_node_fs.existsSync)(".gitignore")) {
1896
+ const gitignore = (0, import_node_fs.readFileSync)(".gitignore", "utf-8");
1897
+ if (!gitignore.includes(".intl-party")) {
1898
+ console.log(import_chalk7.default.blue("\n\u{1F4A1} Tip: Add .intl-party/ to your .gitignore"));
1899
+ }
1900
+ }
1901
+ console.log(import_chalk7.default.blue("\n\u{1F4A1} Tip: Make sure to install the dependency:"));
1902
+ console.log(import_chalk7.default.white(" npm install @intl-party/nextjs"));
1903
+ console.log(import_chalk7.default.green("\n\u{1F389} IntlParty initialized successfully!"));
1904
+ console.log("\n\u{1F4DD} Next steps:");
1905
+ console.log("1. Review the generated configuration files");
1906
+ console.log(
1907
+ `2. Move/merge ${appDir}/layout.intl-party.tsx into your RootLayout`
1908
+ );
1909
+ console.log("3. Add translations to your message files in ./messages");
1910
+ console.log("4. Run your development server");
1911
+ console.log(`
1912
+ \u{1F4DA} For more information, visit: https://intl-party.ai/docs`);
1913
+ return true;
906
1914
  }
1915
+ var nextjsCommand = new import_commander.Command("nextjs").description("Next.js specific commands for IntlParty").option("--init", "Initialize IntlParty in a Next.js project").option("--force", "Force overwrite existing files").action(async (options) => {
1916
+ if (options.init) {
1917
+ await initializeNextjsProject(options.force);
1918
+ } else {
1919
+ console.log("Please specify an action. Use --init to initialize.");
1920
+ }
1921
+ });
1922
+
1923
+ // package.json
1924
+ var package_default = {
1925
+ name: "@intl-party/cli",
1926
+ version: "1.1.1",
1927
+ description: "Command-line interface for IntlParty - validation, extraction, and management tools",
1928
+ main: "dist/index.js",
1929
+ types: "dist/index.d.ts",
1930
+ bin: {
1931
+ "intl-party": "./dist/cli.js",
1932
+ ip: "./dist/cli.js"
1933
+ },
1934
+ files: [
1935
+ "dist"
1936
+ ],
1937
+ scripts: {
1938
+ build: "tsup src/cli.ts src/index.ts --format cjs",
1939
+ dev: "tsup src/cli.ts src/index.ts --format cjs --dts --watch",
1940
+ test: "vitest --run",
1941
+ "test:watch": "vitest",
1942
+ lint: "eslint src --ext .ts",
1943
+ typecheck: "tsc --noEmit",
1944
+ clean: "rm -rf dist"
1945
+ },
1946
+ keywords: [
1947
+ "cli",
1948
+ "i18n",
1949
+ "internationalization",
1950
+ "validation",
1951
+ "extraction",
1952
+ "typescript"
1953
+ ],
1954
+ author: "RodrigoEspinosa",
1955
+ license: "MIT",
1956
+ homepage: "https://github.com/RodrigoEspinosa/intl-party#readme",
1957
+ bugs: {
1958
+ url: "https://github.com/RodrigoEspinosa/intl-party/issues"
1959
+ },
1960
+ dependencies: {
1961
+ "@intl-party/core": "workspace:*",
1962
+ commander: "^11.1.0",
1963
+ chalk: "^5.3.0",
1964
+ chokidar: "^3.5.3",
1965
+ glob: "^10.3.10",
1966
+ "fs-extra": "^11.2.0",
1967
+ ora: "^7.0.1",
1968
+ inquirer: "^9.2.12"
1969
+ },
1970
+ devDependencies: {
1971
+ "@types/fs-extra": "^11.0.4",
1972
+ "@types/inquirer": "^9.0.7",
1973
+ "@types/node": "^20.10.0",
1974
+ eslint: "^8.55.0",
1975
+ jsdom: "^23.0.1",
1976
+ tsup: "^8.0.1",
1977
+ typescript: "^5.3.0",
1978
+ vitest: "^1.0.0"
1979
+ },
1980
+ repository: {
1981
+ type: "git",
1982
+ url: "https://github.com/RodrigoEspinosa/intl-party.git",
1983
+ directory: "packages/cli"
1984
+ },
1985
+ engines: {
1986
+ node: ">=18.0.0"
1987
+ }
1988
+ };
907
1989
 
908
1990
  // src/cli.ts
909
- var packageJson = require_package();
910
- import_commander.program.name("intl-party").description("CLI for IntlParty internationalization library").version(packageJson.version);
911
- import_commander.program.option("-c, --config <path>", "path to config file", "intl-party.config.js").option("-v, --verbose", "verbose output").option("--no-color", "disable colored output");
912
- import_commander.program.command("validate").description("validate translation files for completeness and consistency").option("-l, --locales <locales...>", "specific locales to validate").option("-n, --namespaces <namespaces...>", "specific namespaces to validate").option("--strict", "enable strict validation mode").option("--format <format>", "output format (text|json|junit)", "text").option("--output <file>", "output file path").action(validateCommand);
913
- import_commander.program.command("extract").description("extract translation keys from source code").option("-s, --source <patterns...>", "source file patterns", [
1991
+ import_commander2.program.name("intl-party").description("CLI for IntlParty internationalization library").version(package_default.version);
1992
+ import_commander2.program.option("-c, --config <path>", "path to config file", "intl-party.config.js").option("-v, --verbose", "verbose output").option("--no-color", "disable colored output");
1993
+ import_commander2.program.command("validate").description("validate translation files for completeness and consistency").option("-l, --locales <locales...>", "specific locales to validate").option("-n, --namespaces <namespaces...>", "specific namespaces to validate").option("--strict", "enable strict validation mode").option("--format <format>", "output format (text|json|junit)", "text").option("--output <file>", "output file path").action(validateCommand);
1994
+ import_commander2.program.command("extract").description("extract translation keys from source code").option("-s, --source <patterns...>", "source file patterns", [
914
1995
  "src/**/*.{ts,tsx,js,jsx}"
915
1996
  ]).option(
916
1997
  "-o, --output <dir>",
917
1998
  "output directory for extracted keys",
918
- "./translations"
1999
+ "./messages"
919
2000
  ).option("--dry-run", "show what would be extracted without writing files").option("--update", "update existing translation files with new keys").option("--remove-unused", "remove unused translation keys").action(extractCommand);
920
- import_commander.program.command("sync").description("synchronize translations across locales").option("-b, --base <locale>", "base locale to sync from", "en").option("-t, --target <locales...>", "target locales to sync to").option("--missing-only", "only add missing keys, don't remove extras").option("--interactive", "interactive mode for conflict resolution").action(syncCommand);
921
- import_commander.program.command("init").description("initialize intl-party configuration and structure").option("--force", "overwrite existing configuration").option(
2001
+ import_commander2.program.command("sync").description("synchronize translations across locales").option("-b, --base <locale>", "base locale to sync from", "en").option("-t, --target <locales...>", "target locales to sync to").option("--missing-only", "only add missing keys, don't remove extras").option("--interactive", "interactive mode for conflict resolution").action(syncCommand);
2002
+ import_commander2.program.command("init").description("initialize intl-party configuration and structure").option("--force", "overwrite existing configuration").option(
922
2003
  "--template <template>",
923
2004
  "template to use (nextjs|react|vanilla)",
924
2005
  "react"
925
2006
  ).action(initCommand);
926
- import_commander.program.command("check").description("check for issues in translations and configuration").option("--missing", "check for missing translations").option("--unused", "check for unused translation keys").option("--duplicates", "check for duplicate keys").option("--format-errors", "check for format errors in translations").option("--fix", "automatically fix issues where possible").action(checkCommand);
927
- import_commander.program.command("generate").description("generate TypeScript definitions and other files").option("-t, --types", "generate TypeScript type definitions").option("-s, --schemas", "generate JSON schemas").option("-d, --docs", "generate documentation").option("--watch", "watch for changes and regenerate").action(generateCommand);
928
- import_commander.program.command("completion").description("generate shell completion scripts").option("--shell <shell>", "shell type (bash|zsh|fish)", "bash").action((options) => {
2007
+ import_commander2.program.command("check").description("check for issues in translations and configuration").option("--missing", "check for missing translations").option("--unused", "check for unused translation keys").option("--duplicates", "check for duplicate keys").option("--format-errors", "check for format errors in translations").option("--fix", "automatically fix issues where possible").action(checkCommand);
2008
+ import_commander2.program.command("check-config").description("validate your intl-party configuration").option("-c, --config <path>", "path to config file").action(async (options) => {
2009
+ const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
2010
+ const spinner = (await import("ora")).default("Validating configuration...").start();
2011
+ try {
2012
+ const config = await loadConfig2(options.config);
2013
+ spinner.succeed("Configuration is valid!");
2014
+ if (options.verbose) {
2015
+ console.log(JSON.stringify(config, null, 2));
2016
+ }
2017
+ } catch (error) {
2018
+ spinner.fail("Configuration is invalid");
2019
+ console.error(
2020
+ import_chalk8.default.red("Error:"),
2021
+ error instanceof Error ? error.message : error
2022
+ );
2023
+ process.exit(1);
2024
+ }
2025
+ });
2026
+ import_commander2.program.command("generate").description("generate TypeScript definitions and other files").option("-t, --types", "generate TypeScript type definitions").option("-s, --schemas", "generate JSON schemas").option("-d, --docs", "generate documentation").option("-c, --client", "generate client package files").option(
2027
+ "-o, --output <dir>",
2028
+ "output directory for generated files",
2029
+ "./node_modules/.intl-party"
2030
+ ).option("--watch", "watch for changes and regenerate").option("--verbose", "verbose output").action(generateCommand);
2031
+ import_commander2.program.addCommand(nextjsCommand);
2032
+ import_commander2.program.command("completion").description("generate shell completion scripts").option("--shell <shell>", "shell type (bash|zsh|fish)", "bash").action((_options) => {
929
2033
  console.log("Shell completion not implemented yet");
930
2034
  });
931
- import_commander.program.exitOverride((err) => {
2035
+ import_commander2.program.exitOverride((err) => {
932
2036
  if (err.code === "commander.help") {
933
2037
  process.exit(0);
934
2038
  }
935
2039
  if (err.code === "commander.version") {
936
2040
  process.exit(0);
937
2041
  }
938
- console.error(import_chalk7.default.red("Error:"), err.message);
2042
+ console.error(import_chalk8.default.red("Error:"), err.message);
939
2043
  process.exit(1);
940
2044
  });
941
- import_commander.program.parse();
2045
+ import_commander2.program.parse();
942
2046
  if (!process.argv.slice(2).length) {
943
- import_commander.program.outputHelp();
2047
+ import_commander2.program.outputHelp();
944
2048
  }