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