@scoutello/i18n-magic 0.15.2 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/README.md +178 -17
  2. package/dist/cli.d.ts +2 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +101 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/commands/check-missing.d.ts +1 -0
  7. package/dist/commands/check-missing.d.ts.map +1 -0
  8. package/dist/commands/check-missing.js +13 -0
  9. package/dist/commands/check-missing.js.map +1 -0
  10. package/dist/commands/clean.d.ts +3 -0
  11. package/dist/commands/clean.d.ts.map +1 -0
  12. package/dist/commands/clean.js +81 -0
  13. package/dist/commands/clean.js.map +1 -0
  14. package/dist/commands/create-pruned-namespace-automated.d.ts +20 -0
  15. package/dist/commands/create-pruned-namespace-automated.d.ts.map +1 -0
  16. package/dist/commands/create-pruned-namespace-automated.js +98 -0
  17. package/dist/commands/create-pruned-namespace-automated.js.map +1 -0
  18. package/dist/commands/create-pruned-namespace.d.ts +3 -0
  19. package/dist/commands/create-pruned-namespace.d.ts.map +1 -0
  20. package/dist/commands/create-pruned-namespace.js +122 -0
  21. package/dist/commands/create-pruned-namespace.js.map +1 -0
  22. package/dist/commands/replace.d.ts +1 -0
  23. package/dist/commands/replace.d.ts.map +1 -0
  24. package/dist/commands/replace.js +58 -0
  25. package/dist/commands/replace.js.map +1 -0
  26. package/dist/commands/scan.d.ts +1 -0
  27. package/dist/commands/scan.d.ts.map +1 -0
  28. package/dist/commands/scan.js +70 -0
  29. package/dist/commands/scan.js.map +1 -0
  30. package/dist/commands/sync-locales.d.ts +1 -0
  31. package/dist/commands/sync-locales.d.ts.map +1 -0
  32. package/dist/commands/sync-locales.js +78 -0
  33. package/dist/commands/sync-locales.js.map +1 -0
  34. package/dist/i18n-magic.cjs.development.js +458 -126
  35. package/dist/i18n-magic.cjs.development.js.map +1 -1
  36. package/dist/i18n-magic.cjs.production.min.js +1 -1
  37. package/dist/i18n-magic.cjs.production.min.js.map +1 -1
  38. package/dist/i18n-magic.esm.js +449 -126
  39. package/dist/i18n-magic.esm.js.map +1 -1
  40. package/dist/index.d.ts +11 -1
  41. package/dist/index.d.ts.map +1 -0
  42. package/dist/index.js +22 -9
  43. package/dist/index.js.map +1 -0
  44. package/dist/lib/languges.d.ts +1 -0
  45. package/dist/lib/languges.d.ts.map +1 -0
  46. package/dist/lib/languges.js +146 -0
  47. package/dist/lib/languges.js.map +1 -0
  48. package/dist/lib/types.d.ts +8 -0
  49. package/dist/lib/types.d.ts.map +1 -0
  50. package/dist/lib/types.js +3 -0
  51. package/dist/lib/types.js.map +1 -0
  52. package/dist/lib/utils.d.ts +1 -0
  53. package/dist/lib/utils.d.ts.map +1 -0
  54. package/dist/lib/utils.js +220 -0
  55. package/dist/lib/utils.js.map +1 -0
  56. package/package.json +37 -14
  57. package/src/cli.ts +117 -0
  58. package/src/commands/clean.ts +105 -0
  59. package/src/commands/create-pruned-namespace-automated.ts +165 -0
  60. package/src/commands/create-pruned-namespace.ts +165 -0
  61. package/src/commands/scan.ts +12 -0
  62. package/src/index.ts +23 -106
  63. package/src/lib/types.ts +8 -0
@@ -1,11 +1,9 @@
1
- import { Command } from 'commander';
2
- import dotenv from 'dotenv';
3
- import OpenAI from 'openai';
4
1
  import glob from 'fast-glob';
5
2
  import { Parser } from 'i18next-scanner';
6
3
  import fs from 'node:fs';
7
4
  import path from 'node:path';
8
5
  import prompts from 'prompts';
6
+ import console$1 from 'console';
9
7
 
10
8
  function _construct(t, e, r) {
11
9
  if (_isNativeReflectConstruct()) return Reflect.construct.apply(null, arguments);
@@ -965,6 +963,403 @@ var checkMissing = /*#__PURE__*/function () {
965
963
  };
966
964
  }();
967
965
 
966
+ var removeUnusedKeys = /*#__PURE__*/function () {
967
+ var _ref = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(config) {
968
+ var globPatterns, namespaces, defaultNamespace, locales, loadPath, savePath, parser, files, extractedKeys, _iterator, _step, file, content, uniqueExtractedKeys, stats, _iterator2, _step2, namespace, usedKeysSet, _iterator3, _step3, key, pureKey, _iterator4, _step4, locale, existingKeys, existingKeysCount, cleanedKeys, removedCount, _i, _Object$entries, _Object$entries$_i, _key, value;
969
+ return _regeneratorRuntime().wrap(function _callee$(_context) {
970
+ while (1) switch (_context.prev = _context.next) {
971
+ case 0:
972
+ globPatterns = config.globPatterns, namespaces = config.namespaces, defaultNamespace = config.defaultNamespace, locales = config.locales, loadPath = config.loadPath, savePath = config.savePath; // Set up the parser
973
+ parser = new Parser({
974
+ nsSeparator: false,
975
+ keySeparator: false
976
+ }); // Find all files to scan
977
+ _context.next = 4;
978
+ return glob([].concat(globPatterns, ["!**/node_modules/**"]));
979
+ case 4:
980
+ files = _context.sent;
981
+ // Extract all translation keys from the codebase
982
+ extractedKeys = [];
983
+ for (_iterator = _createForOfIteratorHelperLoose(files); !(_step = _iterator()).done;) {
984
+ file = _step.value;
985
+ content = fs.readFileSync(file, "utf-8");
986
+ parser.parseFuncFromString(content, {
987
+ list: ["t"]
988
+ }, function (key) {
989
+ extractedKeys.push(key);
990
+ });
991
+ }
992
+ // Remove duplicates
993
+ uniqueExtractedKeys = removeDuplicatesFromArray(extractedKeys); // Track stats for reporting
994
+ stats = {
995
+ total: 0,
996
+ removed: 0
997
+ }; // Process each namespace and locale
998
+ _iterator2 = _createForOfIteratorHelperLoose(namespaces);
999
+ case 10:
1000
+ if ((_step2 = _iterator2()).done) {
1001
+ _context.next = 37;
1002
+ break;
1003
+ }
1004
+ namespace = _step2.value;
1005
+ // Build a set of pure keys that are actually used in the codebase for this namespace
1006
+ usedKeysSet = new Set();
1007
+ for (_iterator3 = _createForOfIteratorHelperLoose(uniqueExtractedKeys); !(_step3 = _iterator3()).done;) {
1008
+ key = _step3.value;
1009
+ pureKey = getPureKey(key, namespace, namespace === defaultNamespace);
1010
+ if (pureKey) {
1011
+ usedKeysSet.add(pureKey);
1012
+ }
1013
+ }
1014
+ // Process each locale
1015
+ _iterator4 = _createForOfIteratorHelperLoose(locales);
1016
+ case 15:
1017
+ if ((_step4 = _iterator4()).done) {
1018
+ _context.next = 35;
1019
+ break;
1020
+ }
1021
+ locale = _step4.value;
1022
+ _context.next = 19;
1023
+ return loadLocalesFile(loadPath, locale, namespace);
1024
+ case 19:
1025
+ existingKeys = _context.sent;
1026
+ existingKeysCount = Object.keys(existingKeys).length;
1027
+ stats.total += existingKeysCount;
1028
+ // Create a new object with only the keys that are used
1029
+ cleanedKeys = {};
1030
+ removedCount = 0;
1031
+ for (_i = 0, _Object$entries = Object.entries(existingKeys); _i < _Object$entries.length; _i++) {
1032
+ _Object$entries$_i = _Object$entries[_i], _key = _Object$entries$_i[0], value = _Object$entries$_i[1];
1033
+ if (usedKeysSet.has(_key)) {
1034
+ cleanedKeys[_key] = value;
1035
+ } else {
1036
+ removedCount++;
1037
+ }
1038
+ }
1039
+ stats.removed += removedCount;
1040
+ // Only write the file if keys were removed
1041
+ if (!(removedCount > 0)) {
1042
+ _context.next = 32;
1043
+ break;
1044
+ }
1045
+ _context.next = 29;
1046
+ return writeLocalesFile(savePath, locale, namespace, cleanedKeys);
1047
+ case 29:
1048
+ console.log("\u2713 Removed " + removedCount + " unused keys from " + locale + ":" + namespace + " (" + Object.keys(cleanedKeys).length + " keys remaining)");
1049
+ _context.next = 33;
1050
+ break;
1051
+ case 32:
1052
+ console.log("No unused keys found in " + locale + ":" + namespace);
1053
+ case 33:
1054
+ _context.next = 15;
1055
+ break;
1056
+ case 35:
1057
+ _context.next = 10;
1058
+ break;
1059
+ case 37:
1060
+ if (stats.removed > 0) {
1061
+ console.log("\u2705 Removed " + stats.removed + " unused keys (out of " + stats.total + " total keys)");
1062
+ } else {
1063
+ console.log("\u2705 No unused keys found in the project (" + stats.total + " total keys)");
1064
+ }
1065
+ case 38:
1066
+ case "end":
1067
+ return _context.stop();
1068
+ }
1069
+ }, _callee);
1070
+ }));
1071
+ return function removeUnusedKeys(_x) {
1072
+ return _ref.apply(this, arguments);
1073
+ };
1074
+ }();
1075
+
1076
+ var createPrunedNamespace = /*#__PURE__*/function () {
1077
+ var _ref = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(config) {
1078
+ var namespaces, loadPath, savePath, locales, defaultNamespace, sourceNamespaceResponse, sourceNamespace, newNamespaceResponse, newNamespace, globPatternsResponse, selectedGlobPatterns, parser, files, extractedKeys, _iterator, _step, file, content, uniqueExtractedKeys, relevantKeys, _iterator2, _step2, key, pureKey, _iterator3, _step3, locale, sourceTranslations, newNamespaceTranslations, _iterator4, _step4, _key;
1079
+ return _regeneratorRuntime().wrap(function _callee$(_context) {
1080
+ while (1) switch (_context.prev = _context.next) {
1081
+ case 0:
1082
+ namespaces = config.namespaces, loadPath = config.loadPath, savePath = config.savePath, locales = config.locales, defaultNamespace = config.defaultNamespace; // Step 1: Ask for source namespace
1083
+ _context.next = 3;
1084
+ return prompts({
1085
+ type: "select",
1086
+ name: "value",
1087
+ message: "Select source namespace to create pruned version from:",
1088
+ choices: namespaces.map(function (namespace) {
1089
+ return {
1090
+ title: namespace,
1091
+ value: namespace
1092
+ };
1093
+ }),
1094
+ onState: function onState(state) {
1095
+ if (state.aborted) {
1096
+ process.nextTick(function () {
1097
+ process.exit(0);
1098
+ });
1099
+ }
1100
+ }
1101
+ });
1102
+ case 3:
1103
+ sourceNamespaceResponse = _context.sent;
1104
+ sourceNamespace = sourceNamespaceResponse.value; // Step 2: Ask for new namespace name
1105
+ _context.next = 7;
1106
+ return prompts({
1107
+ type: "text",
1108
+ name: "value",
1109
+ message: "Enter the name for the new namespace:",
1110
+ validate: function validate(value) {
1111
+ if (!value) return "Namespace name cannot be empty";
1112
+ if (namespaces.includes(value)) return "Namespace already exists";
1113
+ return true;
1114
+ },
1115
+ onState: function onState(state) {
1116
+ if (state.aborted) {
1117
+ process.nextTick(function () {
1118
+ process.exit(0);
1119
+ });
1120
+ }
1121
+ }
1122
+ });
1123
+ case 7:
1124
+ newNamespaceResponse = _context.sent;
1125
+ newNamespace = newNamespaceResponse.value; // Step 3: Ask for glob patterns to find relevant keys
1126
+ _context.next = 11;
1127
+ return prompts({
1128
+ type: "list",
1129
+ name: "value",
1130
+ message: "Enter glob patterns to find relevant keys (comma separated):",
1131
+ initial: config.globPatterns.join(","),
1132
+ separator: ",",
1133
+ onState: function onState(state) {
1134
+ if (state.aborted) {
1135
+ process.nextTick(function () {
1136
+ process.exit(0);
1137
+ });
1138
+ }
1139
+ }
1140
+ });
1141
+ case 11:
1142
+ globPatternsResponse = _context.sent;
1143
+ selectedGlobPatterns = globPatternsResponse.value;
1144
+ console.log("Finding keys used in files matching: " + selectedGlobPatterns.join(", "));
1145
+ // Extract keys from files matching the glob patterns
1146
+ parser = new Parser({
1147
+ nsSeparator: false,
1148
+ keySeparator: false
1149
+ });
1150
+ _context.next = 17;
1151
+ return glob([].concat(selectedGlobPatterns, ["!**/node_modules/**"]));
1152
+ case 17:
1153
+ files = _context.sent;
1154
+ console.log("Found " + files.length + " files to scan");
1155
+ extractedKeys = [];
1156
+ for (_iterator = _createForOfIteratorHelperLoose(files); !(_step = _iterator()).done;) {
1157
+ file = _step.value;
1158
+ content = fs.readFileSync(file, "utf-8");
1159
+ parser.parseFuncFromString(content, {
1160
+ list: ["t"]
1161
+ }, function (key) {
1162
+ extractedKeys.push(key);
1163
+ });
1164
+ }
1165
+ uniqueExtractedKeys = removeDuplicatesFromArray(extractedKeys);
1166
+ console.log("Found " + uniqueExtractedKeys.length + " unique translation keys");
1167
+ // Filter keys that belong to the source namespace
1168
+ relevantKeys = [];
1169
+ for (_iterator2 = _createForOfIteratorHelperLoose(uniqueExtractedKeys); !(_step2 = _iterator2()).done;) {
1170
+ key = _step2.value;
1171
+ pureKey = getPureKey(key, sourceNamespace, sourceNamespace === defaultNamespace);
1172
+ if (pureKey) {
1173
+ relevantKeys.push(pureKey);
1174
+ }
1175
+ }
1176
+ console.log("Found " + relevantKeys.length + " keys from namespace '" + sourceNamespace + "'");
1177
+ if (!(relevantKeys.length === 0)) {
1178
+ _context.next = 29;
1179
+ break;
1180
+ }
1181
+ console.log("No relevant keys found. Exiting...");
1182
+ return _context.abrupt("return");
1183
+ case 29:
1184
+ _iterator3 = _createForOfIteratorHelperLoose(locales);
1185
+ case 30:
1186
+ if ((_step3 = _iterator3()).done) {
1187
+ _context.next = 48;
1188
+ break;
1189
+ }
1190
+ locale = _step3.value;
1191
+ _context.prev = 32;
1192
+ _context.next = 35;
1193
+ return loadLocalesFile(loadPath, locale, sourceNamespace);
1194
+ case 35:
1195
+ sourceTranslations = _context.sent;
1196
+ // Create new namespace with only the keys used in the glob pattern files
1197
+ newNamespaceTranslations = {};
1198
+ for (_iterator4 = _createForOfIteratorHelperLoose(relevantKeys); !(_step4 = _iterator4()).done;) {
1199
+ _key = _step4.value;
1200
+ if (sourceTranslations[_key]) {
1201
+ newNamespaceTranslations[_key] = sourceTranslations[_key];
1202
+ }
1203
+ }
1204
+ // Write the new namespace file
1205
+ _context.next = 40;
1206
+ return writeLocalesFile(savePath, locale, newNamespace, newNamespaceTranslations);
1207
+ case 40:
1208
+ console.log("Created pruned namespace '" + newNamespace + "' for locale '" + locale + "' with " + Object.keys(newNamespaceTranslations).length + " keys");
1209
+ _context.next = 46;
1210
+ break;
1211
+ case 43:
1212
+ _context.prev = 43;
1213
+ _context.t0 = _context["catch"](32);
1214
+ console.error("Error creating pruned namespace for locale '" + locale + "':", _context.t0);
1215
+ case 46:
1216
+ _context.next = 30;
1217
+ break;
1218
+ case 48:
1219
+ console.log("\u2705 Successfully created pruned namespace '" + newNamespace + "'");
1220
+ case 49:
1221
+ case "end":
1222
+ return _context.stop();
1223
+ }
1224
+ }, _callee, null, [[32, 43]]);
1225
+ }));
1226
+ return function createPrunedNamespace(_x) {
1227
+ return _ref.apply(this, arguments);
1228
+ };
1229
+ }();
1230
+
1231
+ var createPrunedNamespaceAutomated = /*#__PURE__*/function () {
1232
+ var _ref = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(config, options) {
1233
+ var namespaces, loadPath, savePath, locales, defaultNamespace, sourceNamespace, newNamespace, globPatterns, parser, files, extractedKeys, _iterator, _step, file, content, uniqueExtractedKeys, relevantKeys, _iterator2, _step2, key, pureKey, results, _iterator3, _step3, locale, sourceTranslations, newNamespaceTranslations, _iterator4, _step4, _key, keyCount;
1234
+ return _regeneratorRuntime().wrap(function _callee$(_context) {
1235
+ while (1) switch (_context.prev = _context.next) {
1236
+ case 0:
1237
+ namespaces = config.namespaces, loadPath = config.loadPath, savePath = config.savePath, locales = config.locales, defaultNamespace = config.defaultNamespace;
1238
+ sourceNamespace = options.sourceNamespace, newNamespace = options.newNamespace, globPatterns = options.globPatterns; // Validate inputs
1239
+ if (namespaces.includes(sourceNamespace)) {
1240
+ _context.next = 4;
1241
+ break;
1242
+ }
1243
+ throw new Error("Source namespace '" + sourceNamespace + "' not found in configuration");
1244
+ case 4:
1245
+ if (!namespaces.includes(newNamespace)) {
1246
+ _context.next = 6;
1247
+ break;
1248
+ }
1249
+ throw new Error("Namespace '" + newNamespace + "' already exists");
1250
+ case 6:
1251
+ console.log("Creating pruned namespace '" + newNamespace + "' from '" + sourceNamespace + "'");
1252
+ console.log("Using glob patterns: " + globPatterns.join(", "));
1253
+ // Extract keys from files matching the glob patterns
1254
+ parser = new Parser({
1255
+ nsSeparator: false,
1256
+ keySeparator: false
1257
+ });
1258
+ _context.next = 11;
1259
+ return glob([].concat(globPatterns, ["!**/node_modules/**"]));
1260
+ case 11:
1261
+ files = _context.sent;
1262
+ console.log("Found " + files.length + " files to scan");
1263
+ extractedKeys = [];
1264
+ for (_iterator = _createForOfIteratorHelperLoose(files); !(_step = _iterator()).done;) {
1265
+ file = _step.value;
1266
+ content = fs.readFileSync(file, "utf-8");
1267
+ parser.parseFuncFromString(content, {
1268
+ list: ["t"]
1269
+ }, function (key) {
1270
+ extractedKeys.push(key);
1271
+ });
1272
+ }
1273
+ uniqueExtractedKeys = removeDuplicatesFromArray(extractedKeys);
1274
+ console.log("Found " + uniqueExtractedKeys.length + " unique translation keys");
1275
+ // Filter keys that belong to the source namespace
1276
+ relevantKeys = [];
1277
+ for (_iterator2 = _createForOfIteratorHelperLoose(uniqueExtractedKeys); !(_step2 = _iterator2()).done;) {
1278
+ key = _step2.value;
1279
+ pureKey = getPureKey(key, sourceNamespace, sourceNamespace === defaultNamespace);
1280
+ if (pureKey) {
1281
+ relevantKeys.push(pureKey);
1282
+ }
1283
+ }
1284
+ console.log("Found " + relevantKeys.length + " keys from namespace '" + sourceNamespace + "'");
1285
+ if (!(relevantKeys.length === 0)) {
1286
+ _context.next = 23;
1287
+ break;
1288
+ }
1289
+ console.log("No relevant keys found. Exiting...");
1290
+ return _context.abrupt("return", {
1291
+ success: false,
1292
+ message: "No relevant keys found",
1293
+ keysCount: 0
1294
+ });
1295
+ case 23:
1296
+ // Get translations from source namespace and create new namespace files
1297
+ results = [];
1298
+ _iterator3 = _createForOfIteratorHelperLoose(locales);
1299
+ case 25:
1300
+ if ((_step3 = _iterator3()).done) {
1301
+ _context.next = 46;
1302
+ break;
1303
+ }
1304
+ locale = _step3.value;
1305
+ _context.prev = 27;
1306
+ _context.next = 30;
1307
+ return loadLocalesFile(loadPath, locale, sourceNamespace);
1308
+ case 30:
1309
+ sourceTranslations = _context.sent;
1310
+ // Create new namespace with only the keys used in the glob pattern files
1311
+ newNamespaceTranslations = {};
1312
+ for (_iterator4 = _createForOfIteratorHelperLoose(relevantKeys); !(_step4 = _iterator4()).done;) {
1313
+ _key = _step4.value;
1314
+ if (sourceTranslations[_key]) {
1315
+ newNamespaceTranslations[_key] = sourceTranslations[_key];
1316
+ }
1317
+ }
1318
+ // Write the new namespace file
1319
+ _context.next = 35;
1320
+ return writeLocalesFile(savePath, locale, newNamespace, newNamespaceTranslations);
1321
+ case 35:
1322
+ keyCount = Object.keys(newNamespaceTranslations).length;
1323
+ console.log("Created pruned namespace '" + newNamespace + "' for locale '" + locale + "' with " + keyCount + " keys");
1324
+ results.push({
1325
+ locale: locale,
1326
+ keyCount: keyCount,
1327
+ success: true
1328
+ });
1329
+ _context.next = 44;
1330
+ break;
1331
+ case 40:
1332
+ _context.prev = 40;
1333
+ _context.t0 = _context["catch"](27);
1334
+ console.error("Error creating pruned namespace for locale '" + locale + "':", _context.t0);
1335
+ results.push({
1336
+ locale: locale,
1337
+ keyCount: 0,
1338
+ success: false,
1339
+ error: _context.t0 instanceof Error ? _context.t0.message : String(_context.t0)
1340
+ });
1341
+ case 44:
1342
+ _context.next = 25;
1343
+ break;
1344
+ case 46:
1345
+ console.log("\u2705 Successfully created pruned namespace '" + newNamespace + "'");
1346
+ return _context.abrupt("return", {
1347
+ success: true,
1348
+ message: "Created pruned namespace '" + newNamespace + "' with " + relevantKeys.length + " keys",
1349
+ keysCount: relevantKeys.length,
1350
+ results: results
1351
+ });
1352
+ case 48:
1353
+ case "end":
1354
+ return _context.stop();
1355
+ }
1356
+ }, _callee, null, [[27, 40]]);
1357
+ }));
1358
+ return function createPrunedNamespaceAutomated(_x, _x2) {
1359
+ return _ref.apply(this, arguments);
1360
+ };
1361
+ }();
1362
+
968
1363
  var getKeyToReplace = /*#__PURE__*/function () {
969
1364
  var _ref = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(keys) {
970
1365
  var keyToReplace;
@@ -1092,69 +1487,79 @@ var replaceTranslation = /*#__PURE__*/function () {
1092
1487
 
1093
1488
  var translateMissing = /*#__PURE__*/function () {
1094
1489
  var _ref = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(config) {
1095
- var loadPath, savePath, defaultLocale, namespaces, locales, context, openai, disableTranslation, newKeys, newKeysWithDefaultLocale, _iterator, _step, newKey, answer, newKeysObject, allLocales, _iterator2, _step2, locale, translatedValues, _loop, _iterator3, _step3;
1490
+ var loadPath, savePath, defaultLocale, namespaces, locales, context, openai, disableTranslation, autoClear, newKeys, newKeysWithDefaultLocale, _iterator, _step, newKey, answer, newKeysObject, allLocales, _iterator2, _step2, locale, translatedValues, _loop, _iterator3, _step3;
1096
1491
  return _regeneratorRuntime().wrap(function _callee$(_context2) {
1097
1492
  while (1) switch (_context2.prev = _context2.next) {
1098
1493
  case 0:
1099
- loadPath = config.loadPath, savePath = config.savePath, defaultLocale = config.defaultLocale, namespaces = config.namespaces, locales = config.locales, context = config.context, openai = config.openai, disableTranslation = config.disableTranslation;
1100
- _context2.next = 3;
1494
+ loadPath = config.loadPath, savePath = config.savePath, defaultLocale = config.defaultLocale, namespaces = config.namespaces, locales = config.locales, context = config.context, openai = config.openai, disableTranslation = config.disableTranslation, autoClear = config.autoClear; // Run clean command first if autoClear is enabled
1495
+ if (!autoClear) {
1496
+ _context2.next = 6;
1497
+ break;
1498
+ }
1499
+ console$1.log("🧹 Auto-clearing unused translations before scanning...");
1500
+ _context2.next = 5;
1501
+ return removeUnusedKeys(config);
1502
+ case 5:
1503
+ console$1.log("✅ Auto-clear completed. Now scanning for missing translations...\n");
1504
+ case 6:
1505
+ _context2.next = 8;
1101
1506
  return getMissingKeys(config);
1102
- case 3:
1507
+ case 8:
1103
1508
  newKeys = _context2.sent;
1104
1509
  if (!(newKeys.length === 0)) {
1105
- _context2.next = 9;
1510
+ _context2.next = 14;
1106
1511
  break;
1107
1512
  }
1108
- console.log("No new keys found.");
1109
- _context2.next = 8;
1513
+ console$1.log("No new keys found.");
1514
+ _context2.next = 13;
1110
1515
  return checkAllKeysExist(config);
1111
- case 8:
1516
+ case 13:
1112
1517
  return _context2.abrupt("return");
1113
- case 9:
1114
- console.log(newKeys.length + " keys are missing. Please provide the values for the following keys in " + defaultLocale + ":");
1518
+ case 14:
1519
+ console$1.log(newKeys.length + " keys are missing. Please provide the values for the following keys in " + defaultLocale + ":");
1115
1520
  newKeysWithDefaultLocale = [];
1116
1521
  _iterator = _createForOfIteratorHelperLoose(newKeys);
1117
- case 12:
1522
+ case 17:
1118
1523
  if ((_step = _iterator()).done) {
1119
- _context2.next = 20;
1524
+ _context2.next = 25;
1120
1525
  break;
1121
1526
  }
1122
1527
  newKey = _step.value;
1123
- _context2.next = 16;
1528
+ _context2.next = 21;
1124
1529
  return getTextInput(newKey.key);
1125
- case 16:
1530
+ case 21:
1126
1531
  answer = _context2.sent;
1127
1532
  newKeysWithDefaultLocale.push({
1128
1533
  key: newKey.key,
1129
1534
  namespace: newKey.namespace,
1130
1535
  value: answer
1131
1536
  });
1132
- case 18:
1133
- _context2.next = 12;
1537
+ case 23:
1538
+ _context2.next = 17;
1134
1539
  break;
1135
- case 20:
1540
+ case 25:
1136
1541
  newKeysObject = newKeysWithDefaultLocale.reduce(function (prev, next) {
1137
1542
  prev[next.key] = next.value;
1138
1543
  return prev;
1139
1544
  }, {});
1140
1545
  allLocales = disableTranslation ? [defaultLocale] : locales;
1141
1546
  _iterator2 = _createForOfIteratorHelperLoose(allLocales);
1142
- case 23:
1547
+ case 28:
1143
1548
  if ((_step2 = _iterator2()).done) {
1144
- _context2.next = 43;
1549
+ _context2.next = 48;
1145
1550
  break;
1146
1551
  }
1147
1552
  locale = _step2.value;
1148
1553
  translatedValues = {};
1149
1554
  if (!(locale === defaultLocale)) {
1150
- _context2.next = 30;
1555
+ _context2.next = 35;
1151
1556
  break;
1152
1557
  }
1153
1558
  translatedValues = newKeysObject;
1154
- _context2.next = 33;
1559
+ _context2.next = 38;
1155
1560
  break;
1156
- case 30:
1157
- _context2.next = 32;
1561
+ case 35:
1562
+ _context2.next = 37;
1158
1563
  return translateKey({
1159
1564
  inputLanguage: defaultLocale,
1160
1565
  outputLanguage: locale,
@@ -1163,9 +1568,9 @@ var translateMissing = /*#__PURE__*/function () {
1163
1568
  openai: openai,
1164
1569
  model: config.model
1165
1570
  });
1166
- case 32:
1571
+ case 37:
1167
1572
  translatedValues = _context2.sent;
1168
- case 33:
1573
+ case 38:
1169
1574
  _loop = /*#__PURE__*/_regeneratorRuntime().mark(function _loop() {
1170
1575
  var namespace, existingKeys, relevantKeys, _iterator4, _step4, key;
1171
1576
  return _regeneratorRuntime().wrap(function _loop$(_context) {
@@ -1197,30 +1602,30 @@ var translateMissing = /*#__PURE__*/function () {
1197
1602
  }, _loop);
1198
1603
  });
1199
1604
  _iterator3 = _createForOfIteratorHelperLoose(namespaces);
1200
- case 35:
1605
+ case 40:
1201
1606
  if ((_step3 = _iterator3()).done) {
1202
- _context2.next = 41;
1607
+ _context2.next = 46;
1203
1608
  break;
1204
1609
  }
1205
- return _context2.delegateYield(_loop(), "t0", 37);
1206
- case 37:
1610
+ return _context2.delegateYield(_loop(), "t0", 42);
1611
+ case 42:
1207
1612
  if (!_context2.t0) {
1208
- _context2.next = 39;
1613
+ _context2.next = 44;
1209
1614
  break;
1210
1615
  }
1211
- return _context2.abrupt("continue", 39);
1212
- case 39:
1213
- _context2.next = 35;
1616
+ return _context2.abrupt("continue", 44);
1617
+ case 44:
1618
+ _context2.next = 40;
1214
1619
  break;
1215
- case 41:
1216
- _context2.next = 23;
1620
+ case 46:
1621
+ _context2.next = 28;
1217
1622
  break;
1218
- case 43:
1219
- _context2.next = 45;
1623
+ case 48:
1624
+ _context2.next = 50;
1220
1625
  return checkAllKeysExist(config);
1221
- case 45:
1222
- console.log("Successfully translated " + newKeys.length + " keys.");
1223
- case 46:
1626
+ case 50:
1627
+ console$1.log("Successfully translated " + newKeys.length + " keys.");
1628
+ case 51:
1224
1629
  case "end":
1225
1630
  return _context2.stop();
1226
1631
  }
@@ -1367,87 +1772,5 @@ var syncLocales = /*#__PURE__*/function () {
1367
1772
  };
1368
1773
  }();
1369
1774
 
1370
- // Only run CLI initialization when this file is executed directly
1371
- var program = /*#__PURE__*/new Command();
1372
- program.name("i18n-magic").description("CLI to help you manage your locales JSON with translations, replacements, etc. with OpenAI.").version("0.2.0").option("-c, --config <path>", "path to config file").option("-e, --env <path>", "path to .env file");
1373
- var commands = [{
1374
- name: "scan",
1375
- description: "Scan for missing translations, get prompted for each, translate it to the other locales and save it to the JSON file.",
1376
- action: translateMissing
1377
- }, {
1378
- name: "replace",
1379
- description: "Replace a translation based on the key, and translate it to the other locales and save it to the JSON file.",
1380
- action: replaceTranslation
1381
- }, {
1382
- name: "check-missing",
1383
- description: "Check if there are any missing translations. Useful for a CI/CD pipeline or husky hook.",
1384
- action: checkMissing
1385
- }, {
1386
- name: "sync",
1387
- description: "Sync the translations from the default locale to the other locales. Useful for a CI/CD pipeline or husky hook.",
1388
- action: syncLocales
1389
- }];
1390
- var _loop = function _loop() {
1391
- var command = _commands[_i];
1392
- var cmd = program.command(command.name).description(command.description);
1393
- // Add key option to replace command
1394
- if (command.name === "replace") {
1395
- cmd.option("-k, --key <key>", "translation key to replace").allowExcessArguments(true).argument("[key]", "translation key to replace");
1396
- }
1397
- cmd.action( /*#__PURE__*/function () {
1398
- var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(arg, options) {
1399
- var _config$model;
1400
- var res, config, isGemini, openaiKey, geminiKey, key, keyType, openai, keyToUse;
1401
- return _regeneratorRuntime().wrap(function _callee$(_context) {
1402
- while (1) switch (_context.prev = _context.next) {
1403
- case 0:
1404
- res = dotenv.config({
1405
- path: program.opts().env || ".env"
1406
- });
1407
- _context.next = 3;
1408
- return loadConfig({
1409
- configPath: program.opts().config
1410
- });
1411
- case 3:
1412
- config = _context.sent;
1413
- isGemini = (_config$model = config.model) == null ? void 0 : _config$model.includes("gemini"); // Get API key from environment or config
1414
- openaiKey = res.parsed.OPENAI_API_KEY || config.OPENAI_API_KEY;
1415
- geminiKey = res.parsed.GEMINI_API_KEY || config.GEMINI_API_KEY; // Select appropriate key based on model type
1416
- key = isGemini ? geminiKey : openaiKey;
1417
- if (!key) {
1418
- keyType = isGemini ? "GEMINI_API_KEY" : "OPENAI_API_KEY";
1419
- console.error("Please provide a" + (isGemini ? " Gemini" : "n OpenAI") + " API key in your .env file or config, called " + keyType + ".");
1420
- process.exit(1);
1421
- }
1422
- openai = new OpenAI(_extends({
1423
- apiKey: key
1424
- }, isGemini && {
1425
- baseURL: "https://generativelanguage.googleapis.com/v1beta/openai/"
1426
- })); // For replace command, check for key in argument or option
1427
- if (command.name === "replace") {
1428
- // If key is provided as positional argument, use that first
1429
- keyToUse = typeof arg === "string" ? arg : options.key;
1430
- command.action(_extends({}, config, {
1431
- openai: openai
1432
- }), keyToUse);
1433
- } else {
1434
- command.action(_extends({}, config, {
1435
- openai: openai
1436
- }));
1437
- }
1438
- case 11:
1439
- case "end":
1440
- return _context.stop();
1441
- }
1442
- }, _callee);
1443
- }));
1444
- return function (_x, _x2) {
1445
- return _ref.apply(this, arguments);
1446
- };
1447
- }());
1448
- };
1449
- for (var _i = 0, _commands = commands; _i < _commands.length; _i++) {
1450
- _loop();
1451
- }
1452
- program.parse(process.argv);
1775
+ export { checkMissing, createPrunedNamespace, createPrunedNamespaceAutomated, loadConfig, removeUnusedKeys, replaceTranslation, syncLocales, translateMissing };
1453
1776
  //# sourceMappingURL=i18n-magic.esm.js.map