@scoutello/i18n-magic
Version:
Intelligent CLI toolkit that automates internationalization workflows with AI-powered translations for JavaScript/TypeScript projects
1,340 lines (1,331 loc) • 67.8 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var glob = require('fast-glob');
var i18nextScanner = require('i18next-scanner');
var fs = require('node:fs');
var path = require('node:path');
var prompts = require('prompts');
var console$1 = require('console');
function _construct(t, e, r) {
if (_isNativeReflectConstruct()) return Reflect.construct.apply(null, arguments);
var o = [null];
o.push.apply(o, e);
var p = new (t.bind.apply(t, o))();
return r && _setPrototypeOf(p, r.prototype), p;
}
function _isNativeReflectConstruct() {
try {
var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
} catch (t) {}
return (_isNativeReflectConstruct = function () {
return !!t;
})();
}
function _regeneratorRuntime() {
_regeneratorRuntime = function () {
return e;
};
var t,
e = {},
r = Object.prototype,
n = r.hasOwnProperty,
o = Object.defineProperty || function (t, e, r) {
t[e] = r.value;
},
i = "function" == typeof Symbol ? Symbol : {},
a = i.iterator || "@@iterator",
c = i.asyncIterator || "@@asyncIterator",
u = i.toStringTag || "@@toStringTag";
function define(t, e, r) {
return Object.defineProperty(t, e, {
value: r,
enumerable: !0,
configurable: !0,
writable: !0
}), t[e];
}
try {
define({}, "");
} catch (t) {
define = function (t, e, r) {
return t[e] = r;
};
}
function wrap(t, e, r, n) {
var i = e && e.prototype instanceof Generator ? e : Generator,
a = Object.create(i.prototype),
c = new Context(n || []);
return o(a, "_invoke", {
value: makeInvokeMethod(t, r, c)
}), a;
}
function tryCatch(t, e, r) {
try {
return {
type: "normal",
arg: t.call(e, r)
};
} catch (t) {
return {
type: "throw",
arg: t
};
}
}
e.wrap = wrap;
var h = "suspendedStart",
l = "suspendedYield",
f = "executing",
s = "completed",
y = {};
function Generator() {}
function GeneratorFunction() {}
function GeneratorFunctionPrototype() {}
var p = {};
define(p, a, function () {
return this;
});
var d = Object.getPrototypeOf,
v = d && d(d(values([])));
v && v !== r && n.call(v, a) && (p = v);
var g = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(p);
function defineIteratorMethods(t) {
["next", "throw", "return"].forEach(function (e) {
define(t, e, function (t) {
return this._invoke(e, t);
});
});
}
function AsyncIterator(t, e) {
function invoke(r, o, i, a) {
var c = tryCatch(t[r], t, o);
if ("throw" !== c.type) {
var u = c.arg,
h = u.value;
return h && "object" == typeof h && n.call(h, "__await") ? e.resolve(h.__await).then(function (t) {
invoke("next", t, i, a);
}, function (t) {
invoke("throw", t, i, a);
}) : e.resolve(h).then(function (t) {
u.value = t, i(u);
}, function (t) {
return invoke("throw", t, i, a);
});
}
a(c.arg);
}
var r;
o(this, "_invoke", {
value: function (t, n) {
function callInvokeWithMethodAndArg() {
return new e(function (e, r) {
invoke(t, n, e, r);
});
}
return r = r ? r.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg();
}
});
}
function makeInvokeMethod(e, r, n) {
var o = h;
return function (i, a) {
if (o === f) throw Error("Generator is already running");
if (o === s) {
if ("throw" === i) throw a;
return {
value: t,
done: !0
};
}
for (n.method = i, n.arg = a;;) {
var c = n.delegate;
if (c) {
var u = maybeInvokeDelegate(c, n);
if (u) {
if (u === y) continue;
return u;
}
}
if ("next" === n.method) n.sent = n._sent = n.arg;else if ("throw" === n.method) {
if (o === h) throw o = s, n.arg;
n.dispatchException(n.arg);
} else "return" === n.method && n.abrupt("return", n.arg);
o = f;
var p = tryCatch(e, r, n);
if ("normal" === p.type) {
if (o = n.done ? s : l, p.arg === y) continue;
return {
value: p.arg,
done: n.done
};
}
"throw" === p.type && (o = s, n.method = "throw", n.arg = p.arg);
}
};
}
function maybeInvokeDelegate(e, r) {
var n = r.method,
o = e.iterator[n];
if (o === t) return r.delegate = null, "throw" === n && e.iterator.return && (r.method = "return", r.arg = t, maybeInvokeDelegate(e, r), "throw" === r.method) || "return" !== n && (r.method = "throw", r.arg = new TypeError("The iterator does not provide a '" + n + "' method")), y;
var i = tryCatch(o, e.iterator, r.arg);
if ("throw" === i.type) return r.method = "throw", r.arg = i.arg, r.delegate = null, y;
var a = i.arg;
return a ? a.done ? (r[e.resultName] = a.value, r.next = e.nextLoc, "return" !== r.method && (r.method = "next", r.arg = t), r.delegate = null, y) : a : (r.method = "throw", r.arg = new TypeError("iterator result is not an object"), r.delegate = null, y);
}
function pushTryEntry(t) {
var e = {
tryLoc: t[0]
};
1 in t && (e.catchLoc = t[1]), 2 in t && (e.finallyLoc = t[2], e.afterLoc = t[3]), this.tryEntries.push(e);
}
function resetTryEntry(t) {
var e = t.completion || {};
e.type = "normal", delete e.arg, t.completion = e;
}
function Context(t) {
this.tryEntries = [{
tryLoc: "root"
}], t.forEach(pushTryEntry, this), this.reset(!0);
}
function values(e) {
if (e || "" === e) {
var r = e[a];
if (r) return r.call(e);
if ("function" == typeof e.next) return e;
if (!isNaN(e.length)) {
var o = -1,
i = function next() {
for (; ++o < e.length;) if (n.call(e, o)) return next.value = e[o], next.done = !1, next;
return next.value = t, next.done = !0, next;
};
return i.next = i;
}
}
throw new TypeError(typeof e + " is not iterable");
}
return GeneratorFunction.prototype = GeneratorFunctionPrototype, o(g, "constructor", {
value: GeneratorFunctionPrototype,
configurable: !0
}), o(GeneratorFunctionPrototype, "constructor", {
value: GeneratorFunction,
configurable: !0
}), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, u, "GeneratorFunction"), e.isGeneratorFunction = function (t) {
var e = "function" == typeof t && t.constructor;
return !!e && (e === GeneratorFunction || "GeneratorFunction" === (e.displayName || e.name));
}, e.mark = function (t) {
return Object.setPrototypeOf ? Object.setPrototypeOf(t, GeneratorFunctionPrototype) : (t.__proto__ = GeneratorFunctionPrototype, define(t, u, "GeneratorFunction")), t.prototype = Object.create(g), t;
}, e.awrap = function (t) {
return {
__await: t
};
}, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, c, function () {
return this;
}), e.AsyncIterator = AsyncIterator, e.async = function (t, r, n, o, i) {
void 0 === i && (i = Promise);
var a = new AsyncIterator(wrap(t, r, n, o), i);
return e.isGeneratorFunction(r) ? a : a.next().then(function (t) {
return t.done ? t.value : a.next();
});
}, defineIteratorMethods(g), define(g, u, "Generator"), define(g, a, function () {
return this;
}), define(g, "toString", function () {
return "[object Generator]";
}), e.keys = function (t) {
var e = Object(t),
r = [];
for (var n in e) r.push(n);
return r.reverse(), function next() {
for (; r.length;) {
var t = r.pop();
if (t in e) return next.value = t, next.done = !1, next;
}
return next.done = !0, next;
};
}, e.values = values, Context.prototype = {
constructor: Context,
reset: function (e) {
if (this.prev = 0, this.next = 0, this.sent = this._sent = t, this.done = !1, this.delegate = null, this.method = "next", this.arg = t, this.tryEntries.forEach(resetTryEntry), !e) for (var r in this) "t" === r.charAt(0) && n.call(this, r) && !isNaN(+r.slice(1)) && (this[r] = t);
},
stop: function () {
this.done = !0;
var t = this.tryEntries[0].completion;
if ("throw" === t.type) throw t.arg;
return this.rval;
},
dispatchException: function (e) {
if (this.done) throw e;
var r = this;
function handle(n, o) {
return a.type = "throw", a.arg = e, r.next = n, o && (r.method = "next", r.arg = t), !!o;
}
for (var o = this.tryEntries.length - 1; o >= 0; --o) {
var i = this.tryEntries[o],
a = i.completion;
if ("root" === i.tryLoc) return handle("end");
if (i.tryLoc <= this.prev) {
var c = n.call(i, "catchLoc"),
u = n.call(i, "finallyLoc");
if (c && u) {
if (this.prev < i.catchLoc) return handle(i.catchLoc, !0);
if (this.prev < i.finallyLoc) return handle(i.finallyLoc);
} else if (c) {
if (this.prev < i.catchLoc) return handle(i.catchLoc, !0);
} else {
if (!u) throw Error("try statement without catch or finally");
if (this.prev < i.finallyLoc) return handle(i.finallyLoc);
}
}
}
},
abrupt: function (t, e) {
for (var r = this.tryEntries.length - 1; r >= 0; --r) {
var o = this.tryEntries[r];
if (o.tryLoc <= this.prev && n.call(o, "finallyLoc") && this.prev < o.finallyLoc) {
var i = o;
break;
}
}
i && ("break" === t || "continue" === t) && i.tryLoc <= e && e <= i.finallyLoc && (i = null);
var a = i ? i.completion : {};
return a.type = t, a.arg = e, i ? (this.method = "next", this.next = i.finallyLoc, y) : this.complete(a);
},
complete: function (t, e) {
if ("throw" === t.type) throw t.arg;
return "break" === t.type || "continue" === t.type ? this.next = t.arg : "return" === t.type ? (this.rval = this.arg = t.arg, this.method = "return", this.next = "end") : "normal" === t.type && e && (this.next = e), y;
},
finish: function (t) {
for (var e = this.tryEntries.length - 1; e >= 0; --e) {
var r = this.tryEntries[e];
if (r.finallyLoc === t) return this.complete(r.completion, r.afterLoc), resetTryEntry(r), y;
}
},
catch: function (t) {
for (var e = this.tryEntries.length - 1; e >= 0; --e) {
var r = this.tryEntries[e];
if (r.tryLoc === t) {
var n = r.completion;
if ("throw" === n.type) {
var o = n.arg;
resetTryEntry(r);
}
return o;
}
}
throw Error("illegal catch attempt");
},
delegateYield: function (e, r, n) {
return this.delegate = {
iterator: values(e),
resultName: r,
nextLoc: n
}, "next" === this.method && (this.arg = t), y;
}
}, e;
}
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
Promise.resolve(value).then(_next, _throw);
}
}
function _asyncToGenerator(fn) {
return function () {
var self = this,
args = arguments;
return new Promise(function (resolve, reject) {
var gen = fn.apply(self, args);
function _next(value) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
}
function _throw(err) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
}
_next(undefined);
});
};
}
function _extends() {
_extends = Object.assign ? Object.assign.bind() : function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
function _inheritsLoose(subClass, superClass) {
subClass.prototype = Object.create(superClass.prototype);
subClass.prototype.constructor = subClass;
_setPrototypeOf(subClass, superClass);
}
function _getPrototypeOf(o) {
_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) {
return o.__proto__ || Object.getPrototypeOf(o);
};
return _getPrototypeOf(o);
}
function _setPrototypeOf(o, p) {
_setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) {
o.__proto__ = p;
return o;
};
return _setPrototypeOf(o, p);
}
function _isNativeFunction(fn) {
try {
return Function.toString.call(fn).indexOf("[native code]") !== -1;
} catch (e) {
return typeof fn === "function";
}
}
function _wrapNativeSuper(Class) {
var _cache = typeof Map === "function" ? new Map() : undefined;
_wrapNativeSuper = function _wrapNativeSuper(Class) {
if (Class === null || !_isNativeFunction(Class)) return Class;
if (typeof Class !== "function") {
throw new TypeError("Super expression must either be null or a function");
}
if (typeof _cache !== "undefined") {
if (_cache.has(Class)) return _cache.get(Class);
_cache.set(Class, Wrapper);
}
function Wrapper() {
return _construct(Class, arguments, _getPrototypeOf(this).constructor);
}
Wrapper.prototype = Object.create(Class.prototype, {
constructor: {
value: Wrapper,
enumerable: false,
writable: true,
configurable: true
}
});
return _setPrototypeOf(Wrapper, Class);
};
return _wrapNativeSuper(Class);
}
function _unsupportedIterableToArray(o, minLen) {
if (!o) return;
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor) n = o.constructor.name;
if (n === "Map" || n === "Set") return Array.from(o);
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
}
function _arrayLikeToArray(arr, len) {
if (len == null || len > arr.length) len = arr.length;
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
return arr2;
}
function _createForOfIteratorHelperLoose(o, allowArrayLike) {
var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
if (it) return (it = it.call(o)).next.bind(it);
if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
if (it) o = it;
var i = 0;
return function () {
if (i >= o.length) return {
done: true
};
return {
done: false,
value: o[i++]
};
};
}
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
var languages = [{
label: "Deutsch",
name: "German",
value: "de"
}, {
label: "English",
name: "English",
value: "en"
}, {
label: "Español",
name: "Spanish",
value: "es"
}, {
label: "Français",
name: "French",
value: "fr"
}, {
label: "Dansk",
name: "Danish",
value: "dk"
}, {
label: "中文",
name: "Chinese",
value: "cn"
}, {
label: "Русский",
name: "Russian",
value: "ru"
}, {
label: "Italiano",
name: "Italian",
value: "it"
}, {
label: "Nederlands",
name: "Dutch",
value: "nl"
}, {
label: "Português",
name: "Portuguese",
value: "pt"
}, {
label: "Türkçe",
name: "Turkish",
value: "tr"
}, {
label: "Polski",
name: "Polish",
value: "pl"
}, {
label: "Українська",
name: "Ukrainian",
value: "ua"
}, {
label: "Suomi",
name: "Finnish",
value: "fi"
}, {
label: "Norsk",
name: "Norwegian",
value: "no"
}, {
label: "Svenska",
name: "Swedish",
value: "sv"
}, {
label: "Čeština",
name: "Czech",
value: "cz"
}, {
label: "Ελληνικά",
name: "Greek",
value: "gr"
}, {
label: "日本語",
name: "Japanese",
value: "jp"
}, {
label: "한국어",
name: "Korean",
value: "kr"
}, {
label: "Română",
name: "Romanian",
value: "ro"
}, {
label: "Hrvatski",
name: "Croatian",
value: "hr"
}, {
label: "Magyar",
name: "Hungarian",
value: "hu"
}, {
label: "Slovensky",
name: "Slovak",
value: "sk"
}, {
label: "हिन्दी",
name: "Hindi",
value: "hi"
}, {
label: "தமிழ்",
name: "Tamil",
value: "ta"
}, {
label: "Bahasa Indonesia",
name: "Indonesian",
value: "id"
}, {
label: "Tiếng Việt",
name: "Vietnamese",
value: "vn"
}];
var loadConfig = function loadConfig(_ref) {
var _ref$configPath = _ref.configPath,
configPath = _ref$configPath === void 0 ? "i18n-magic.js" : _ref$configPath;
var filePath = path.join(process.cwd(), configPath);
if (!fs.existsSync(filePath)) {
console.error("Config file does not exist:", filePath);
process.exit(1);
}
try {
var config = require(filePath);
// Validate config if needed
return config;
} catch (error) {
console.error("Error while loading config:", error);
process.exit(1);
}
};
function removeDuplicatesFromArray(arr) {
return arr.filter(function (item, index) {
return arr.indexOf(item) === index;
});
}
var translateKey = /*#__PURE__*/function () {
var _ref3 = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(_ref2) {
var inputLanguage, context, object, openai, outputLanguage, model, entries, chunks, i, result, existingInput, existingOutput, input, output, _i, _chunks, chunk, chunkObject, completion, translatedChunk;
return _regeneratorRuntime().wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
inputLanguage = _ref2.inputLanguage, context = _ref2.context, object = _ref2.object, openai = _ref2.openai, outputLanguage = _ref2.outputLanguage, model = _ref2.model;
// Split object into chunks of 100 keys
entries = Object.entries(object);
chunks = [];
for (i = 0; i < entries.length; i += 100) {
chunks.push(entries.slice(i, i + 100));
}
result = {};
existingInput = languages.find(function (l) {
return l.value === inputLanguage;
});
existingOutput = languages.find(function (l) {
return l.value === outputLanguage;
});
input = (existingInput == null ? void 0 : existingInput.label) || inputLanguage;
output = (existingOutput == null ? void 0 : existingOutput.label) || outputLanguage; // Translate each chunk
_i = 0, _chunks = chunks;
case 10:
if (!(_i < _chunks.length)) {
_context.next = 23;
break;
}
chunk = _chunks[_i];
chunkObject = Object.fromEntries(chunk);
_context.next = 15;
return openai.beta.chat.completions.parse({
model: model,
messages: [{
content: "You are a bot that translates the values of a locales JSON. " + (context ? "The user provided some additional context or guidelines about what to fill in the blanks: \"" + context + "\". " : "") + "The user provides you a JSON with a field named \"inputLanguage\", which defines the language the values of the JSON are defined in. It also has a field named \"outputLanguage\", which defines the language you should translate the values to. The last field is named \"data\", which includes the object with the values to translate. The keys of the values should never be changed. You output only a JSON, which has the same keys as the input, but with translated values. I give you an example input: {\"inputLanguage\": \"English\", outputLanguage: \"German\", \"keys\": {\"hello\": \"Hello\", \"world\": \"World\"}}. The output should be {\"hello\": \"Hallo\", \"world\": \"Welt\"}.",
role: "system"
}, {
content: JSON.stringify({
inputLanguage: input,
outputLanguage: output,
data: chunkObject
}),
role: "user"
}],
response_format: {
type: "json_object"
}
});
case 15:
completion = _context.sent;
translatedChunk = JSON.parse(completion.choices[0].message.content); // Merge translated chunk with result
result = _extends({}, result, translatedChunk);
// Optional: Add a small delay between chunks to avoid rate limiting
_context.next = 20;
return new Promise(function (resolve) {
return setTimeout(resolve, 100);
});
case 20:
_i++;
_context.next = 10;
break;
case 23:
return _context.abrupt("return", result);
case 24:
case "end":
return _context.stop();
}
}, _callee);
}));
return function translateKey(_x) {
return _ref3.apply(this, arguments);
};
}();
var loadLocalesFile = /*#__PURE__*/function () {
var _ref4 = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2(loadPath, locale, namespace) {
var resolvedPath, content, json;
return _regeneratorRuntime().wrap(function _callee2$(_context2) {
while (1) switch (_context2.prev = _context2.next) {
case 0:
if (!(typeof loadPath === "string")) {
_context2.next = 11;
break;
}
resolvedPath = loadPath.replace("{{lng}}", locale).replace("{{ns}}", namespace);
content = fs.readFileSync(resolvedPath, "utf-8");
_context2.prev = 3;
json = JSON.parse(content);
return _context2.abrupt("return", json);
case 8:
_context2.prev = 8;
_context2.t0 = _context2["catch"](3);
throw new TranslationError("Invalid JSON in locale file for " + locale + ":" + namespace + ". Path: " + resolvedPath, locale, namespace, _context2.t0 instanceof Error ? _context2.t0 : undefined);
case 11:
return _context2.abrupt("return", loadPath(locale, namespace));
case 12:
case "end":
return _context2.stop();
}
}, _callee2, null, [[3, 8]]);
}));
return function loadLocalesFile(_x2, _x3, _x4) {
return _ref4.apply(this, arguments);
};
}();
var writeLocalesFile = /*#__PURE__*/function () {
var _ref5 = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3(savePath, locale, namespace, data) {
var resolvedSavePath;
return _regeneratorRuntime().wrap(function _callee3$(_context3) {
while (1) switch (_context3.prev = _context3.next) {
case 0:
if (!(typeof savePath === "string")) {
_context3.next = 4;
break;
}
resolvedSavePath = savePath.replace("{{lng}}", locale).replace("{{ns}}", namespace);
fs.writeFileSync(resolvedSavePath, JSON.stringify(data, null, 2));
return _context3.abrupt("return");
case 4:
_context3.next = 6;
return savePath(locale, namespace, data);
case 6:
case "end":
return _context3.stop();
}
}, _callee3);
}));
return function writeLocalesFile(_x5, _x6, _x7, _x8) {
return _ref5.apply(this, arguments);
};
}();
var getPureKey = function getPureKey(key, namespace, isDefault) {
var splitted = key.split(":");
if (splitted.length === 1) {
if (isDefault) {
return key;
}
return null;
}
if (splitted[0] === namespace) {
return splitted[1];
}
return null;
};
var getMissingKeys = /*#__PURE__*/function () {
var _ref7 = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee4(_ref6) {
var globPatterns, namespaces, defaultNamespace, defaultLocale, loadPath, parser, files, keys, _iterator, _step, file, content, uniqueKeys, newKeys, _iterator2, _step2, namespace, existingKeys, _iterator3, _step3, key, pureKey;
return _regeneratorRuntime().wrap(function _callee4$(_context4) {
while (1) switch (_context4.prev = _context4.next) {
case 0:
globPatterns = _ref6.globPatterns, namespaces = _ref6.namespaces, defaultNamespace = _ref6.defaultNamespace, defaultLocale = _ref6.defaultLocale, loadPath = _ref6.loadPath;
parser = new i18nextScanner.Parser({
nsSeparator: false,
keySeparator: false
});
_context4.next = 4;
return glob([].concat(globPatterns, ["!**/node_modules/**"]));
case 4:
files = _context4.sent;
keys = [];
for (_iterator = _createForOfIteratorHelperLoose(files); !(_step = _iterator()).done;) {
file = _step.value;
content = fs.readFileSync(file, "utf-8");
parser.parseFuncFromString(content, {
list: ["t"]
}, function (key) {
keys.push(key);
});
}
uniqueKeys = removeDuplicatesFromArray(keys);
newKeys = [];
_iterator2 = _createForOfIteratorHelperLoose(namespaces);
case 10:
if ((_step2 = _iterator2()).done) {
_context4.next = 27;
break;
}
namespace = _step2.value;
_context4.next = 14;
return loadLocalesFile(loadPath, defaultLocale, namespace);
case 14:
existingKeys = _context4.sent;
console.log(Object.keys(existingKeys).length, "existing keys");
_iterator3 = _createForOfIteratorHelperLoose(uniqueKeys);
case 17:
if ((_step3 = _iterator3()).done) {
_context4.next = 25;
break;
}
key = _step3.value;
pureKey = getPureKey(key, namespace, namespace === defaultNamespace);
if (pureKey) {
_context4.next = 22;
break;
}
return _context4.abrupt("continue", 23);
case 22:
if (!existingKeys[pureKey]) {
newKeys.push({
key: pureKey,
namespace: namespace
});
}
case 23:
_context4.next = 17;
break;
case 25:
_context4.next = 10;
break;
case 27:
return _context4.abrupt("return", newKeys);
case 28:
case "end":
return _context4.stop();
}
}, _callee4);
}));
return function getMissingKeys(_x9) {
return _ref7.apply(this, arguments);
};
}();
var getTextInput = /*#__PURE__*/function () {
var _ref8 = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee5(prompt) {
var input;
return _regeneratorRuntime().wrap(function _callee5$(_context5) {
while (1) switch (_context5.prev = _context5.next) {
case 0:
_context5.next = 2;
return prompts({
name: "value",
type: "text",
message: prompt,
onState: function onState(state) {
if (state.aborted) {
process.nextTick(function () {
process.exit(0);
});
}
}
});
case 2:
input = _context5.sent;
return _context5.abrupt("return", input.value);
case 4:
case "end":
return _context5.stop();
}
}, _callee5);
}));
return function getTextInput(_x10) {
return _ref8.apply(this, arguments);
};
}();
var checkAllKeysExist = /*#__PURE__*/function () {
var _ref10 = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee6(_ref9) {
var namespaces, defaultLocale, loadPath, locales, context, openai, savePath, disableTranslation, model, _iterator4, _step4, namespace, defaultLocaleKeys, _iterator5, _step5, locale, localeKeys, missingKeys, _i2, _Object$entries, _Object$entries$_i, key, value, translatedValues, updatedLocaleKeys;
return _regeneratorRuntime().wrap(function _callee6$(_context6) {
while (1) switch (_context6.prev = _context6.next) {
case 0:
namespaces = _ref9.namespaces, defaultLocale = _ref9.defaultLocale, loadPath = _ref9.loadPath, locales = _ref9.locales, context = _ref9.context, openai = _ref9.openai, savePath = _ref9.savePath, disableTranslation = _ref9.disableTranslation, model = _ref9.model;
if (!disableTranslation) {
_context6.next = 3;
break;
}
return _context6.abrupt("return");
case 3:
_iterator4 = _createForOfIteratorHelperLoose(namespaces);
case 4:
if ((_step4 = _iterator4()).done) {
_context6.next = 31;
break;
}
namespace = _step4.value;
_context6.next = 8;
return loadLocalesFile(loadPath, defaultLocale, namespace);
case 8:
defaultLocaleKeys = _context6.sent;
_iterator5 = _createForOfIteratorHelperLoose(locales);
case 10:
if ((_step5 = _iterator5()).done) {
_context6.next = 29;
break;
}
locale = _step5.value;
if (!(locale === defaultLocale)) {
_context6.next = 14;
break;
}
return _context6.abrupt("continue", 27);
case 14:
_context6.next = 16;
return loadLocalesFile(loadPath, locale, namespace);
case 16:
localeKeys = _context6.sent;
missingKeys = {}; // Check which keys from default locale are missing in current locale
for (_i2 = 0, _Object$entries = Object.entries(defaultLocaleKeys); _i2 < _Object$entries.length; _i2++) {
_Object$entries$_i = _Object$entries[_i2], key = _Object$entries$_i[0], value = _Object$entries$_i[1];
if (!localeKeys[key]) {
missingKeys[key] = value;
}
}
// If there are missing keys, translate them
if (!(Object.keys(missingKeys).length > 0)) {
_context6.next = 27;
break;
}
console.log("Found " + Object.keys(missingKeys).length + " missing keys in " + locale + " (namespace: " + namespace + ")");
_context6.next = 23;
return translateKey({
inputLanguage: defaultLocale,
outputLanguage: locale,
context: context,
object: missingKeys,
openai: openai,
model: model
});
case 23:
translatedValues = _context6.sent;
// Merge translated values with existing ones
updatedLocaleKeys = _extends({}, localeKeys, translatedValues); // Save the updated translations
writeLocalesFile(savePath, locale, namespace, updatedLocaleKeys);
console.log("\u2713 Translated and saved missing keys for " + locale + " (namespace: " + namespace + ")");
case 27:
_context6.next = 10;
break;
case 29:
_context6.next = 4;
break;
case 31:
case "end":
return _context6.stop();
}
}, _callee6);
}));
return function checkAllKeysExist(_x11) {
return _ref10.apply(this, arguments);
};
}();
var TranslationError = /*#__PURE__*/function (_Error) {
function TranslationError(message, locale, namespace, cause) {
var _this;
_this = _Error.call(this, message) || this;
_this.locale = void 0;
_this.namespace = void 0;
_this.cause = void 0;
_this.locale = locale;
_this.namespace = namespace;
_this.cause = cause;
_this.name = "TranslationError";
return _this;
}
_inheritsLoose(TranslationError, _Error);
return TranslationError;
}( /*#__PURE__*/_wrapNativeSuper(Error));
var checkMissing = /*#__PURE__*/function () {
var _ref = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(config) {
var newKeys;
return _regeneratorRuntime().wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return getMissingKeys(config);
case 2:
newKeys = _context.sent;
if (newKeys.length > 0) {
console.error("Error: Missing translations found!");
process.exit(1);
}
case 4:
case "end":
return _context.stop();
}
}, _callee);
}));
return function checkMissing(_x) {
return _ref.apply(this, arguments);
};
}();
var removeUnusedKeys = /*#__PURE__*/function () {
var _ref = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(config) {
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;
return _regeneratorRuntime().wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
globPatterns = config.globPatterns, namespaces = config.namespaces, defaultNamespace = config.defaultNamespace, locales = config.locales, loadPath = config.loadPath, savePath = config.savePath; // Set up the parser
parser = new i18nextScanner.Parser({
nsSeparator: false,
keySeparator: false
}); // Find all files to scan
_context.next = 4;
return glob([].concat(globPatterns, ["!**/node_modules/**"]));
case 4:
files = _context.sent;
// Extract all translation keys from the codebase
extractedKeys = [];
for (_iterator = _createForOfIteratorHelperLoose(files); !(_step = _iterator()).done;) {
file = _step.value;
content = fs.readFileSync(file, "utf-8");
parser.parseFuncFromString(content, {
list: ["t"]
}, function (key) {
extractedKeys.push(key);
});
}
// Remove duplicates
uniqueExtractedKeys = removeDuplicatesFromArray(extractedKeys); // Track stats for reporting
stats = {
total: 0,
removed: 0
}; // Process each namespace and locale
_iterator2 = _createForOfIteratorHelperLoose(namespaces);
case 10:
if ((_step2 = _iterator2()).done) {
_context.next = 37;
break;
}
namespace = _step2.value;
// Build a set of pure keys that are actually used in the codebase for this namespace
usedKeysSet = new Set();
for (_iterator3 = _createForOfIteratorHelperLoose(uniqueExtractedKeys); !(_step3 = _iterator3()).done;) {
key = _step3.value;
pureKey = getPureKey(key, namespace, namespace === defaultNamespace);
if (pureKey) {
usedKeysSet.add(pureKey);
}
}
// Process each locale
_iterator4 = _createForOfIteratorHelperLoose(locales);
case 15:
if ((_step4 = _iterator4()).done) {
_context.next = 35;
break;
}
locale = _step4.value;
_context.next = 19;
return loadLocalesFile(loadPath, locale, namespace);
case 19:
existingKeys = _context.sent;
existingKeysCount = Object.keys(existingKeys).length;
stats.total += existingKeysCount;
// Create a new object with only the keys that are used
cleanedKeys = {};
removedCount = 0;
for (_i = 0, _Object$entries = Object.entries(existingKeys); _i < _Object$entries.length; _i++) {
_Object$entries$_i = _Object$entries[_i], _key = _Object$entries$_i[0], value = _Object$entries$_i[1];
if (usedKeysSet.has(_key)) {
cleanedKeys[_key] = value;
} else {
removedCount++;
}
}
stats.removed += removedCount;
// Only write the file if keys were removed
if (!(removedCount > 0)) {
_context.next = 32;
break;
}
_context.next = 29;
return writeLocalesFile(savePath, locale, namespace, cleanedKeys);
case 29:
console.log("\u2713 Removed " + removedCount + " unused keys from " + locale + ":" + namespace + " (" + Object.keys(cleanedKeys).length + " keys remaining)");
_context.next = 33;
break;
case 32:
console.log("No unused keys found in " + locale + ":" + namespace);
case 33:
_context.next = 15;
break;
case 35:
_context.next = 10;
break;
case 37:
if (stats.removed > 0) {
console.log("\u2705 Removed " + stats.removed + " unused keys (out of " + stats.total + " total keys)");
} else {
console.log("\u2705 No unused keys found in the project (" + stats.total + " total keys)");
}
case 38:
case "end":
return _context.stop();
}
}, _callee);
}));
return function removeUnusedKeys(_x) {
return _ref.apply(this, arguments);
};
}();
var createPrunedNamespace = /*#__PURE__*/function () {
var _ref = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(config) {
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;
return _regeneratorRuntime().wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
namespaces = config.namespaces, loadPath = config.loadPath, savePath = config.savePath, locales = config.locales, defaultNamespace = config.defaultNamespace; // Step 1: Ask for source namespace
_context.next = 3;
return prompts({
type: "select",
name: "value",
message: "Select source namespace to create pruned version from:",
choices: namespaces.map(function (namespace) {
return {
title: namespace,
value: namespace
};
}),
onState: function onState(state) {
if (state.aborted) {
process.nextTick(function () {
process.exit(0);
});
}
}
});
case 3:
sourceNamespaceResponse = _context.sent;
sourceNamespace = sourceNamespaceResponse.value; // Step 2: Ask for new namespace name
_context.next = 7;
return prompts({
type: "text",
name: "value",
message: "Enter the name for the new namespace:",
validate: function validate(value) {
if (!value) return "Namespace name cannot be empty";
if (namespaces.includes(value)) return "Namespace already exists";
return true;
},
onState: function onState(state) {
if (state.aborted) {
process.nextTick(function () {
process.exit(0);
});
}
}
});
case 7:
newNamespaceResponse = _context.sent;
newNamespace = newNamespaceResponse.value; // Step 3: Ask for glob patterns to find relevant keys
_context.next = 11;
return prompts({
type: "list",
name: "value",
message: "Enter glob patterns to find relevant keys (comma separated):",
initial: config.globPatterns.join(","),
separator: ",",
onState: function onState(state) {
if (state.aborted) {
process.nextTick(function () {
process.exit(0);
});
}
}
});
case 11:
globPatternsResponse = _context.sent;
selectedGlobPatterns = globPatternsResponse.value;
console.log("Finding keys used in files matching: " + selectedGlobPatterns.join(", "));
// Extract keys from files matching the glob patterns
parser = new i18nextScanner.Parser({
nsSeparator: false,
keySeparator: false
});
_context.next = 17;
return glob([].concat(selectedGlobPatterns, ["!**/node_modules/**"]));
case 17:
files = _context.sent;
console.log("Found " + files.length + " files to scan");
extractedKeys = [];
for (_iterator = _createForOfIteratorHelperLoose(files); !(_step = _iterator()).done;) {
file = _step.value;
content = fs.readFileSync(file, "utf-8");
parser.parseFuncFromString(content, {
list: ["t"]
}, function (key) {
extractedKeys.push(key);
});
}
uniqueExtractedKeys = removeDuplicatesFromArray(extractedKeys);
console.log("Found " + uniqueExtractedKeys.length + " unique translation keys");
// Filter keys that belong to the source namespace
relevantKeys = [];
for (_iterator2 = _createForOfIteratorHelperLoose(uniqueExtractedKeys); !(_step2 = _iterator2()).done;) {
key = _step2.value;
pureKey = getPureKey(key, sourceNamespace, sourceNamespace === defaultNamespace);
if (pureKey) {
relevantKeys.push(pureKey);
}
}
console.log("Found " + relevantKeys.length + " keys from namespace '" + sourceNamespace + "'");
if (!(relevantKeys.length === 0)) {
_context.next = 29;
break;
}
console.log("No relevant keys found. Exiting...");
return _context.abrupt("return");
case 29:
_iterator3 = _createForOfIteratorHelperLoose(locales);
case 30:
if ((_step3 = _iterator3()).done) {
_context.next = 48;
break;
}
locale = _step3.value;
_context.prev = 32;
_context.next = 35;
return loadLocalesFile(loadPath, locale, sourceNamespace);
case 35:
sourceTranslations = _context.sent;
// Create new namespace with only the keys used in the glob pattern files
newNamespaceTranslations = {};
for (_iterator4 = _createForOfIteratorHelperLoose(relevantKeys); !(_step4 = _iterator4()).done;) {
_key = _step4.value;
if (sourceTranslations[_key]) {
newNamespaceTranslations[_key] = sourceTranslations[_key];
}
}
// Write the new namespace file
_context.next = 40;
return writeLocalesFile(savePath, locale, newNamespace, newNamespaceTranslations);
case 40:
console.log("Created pruned namespace '" + newNamespace + "' for locale '" + locale + "' with " + Object.keys(newNamespaceTranslations).length + " keys");
_context.next = 46;
break;
case 43:
_context.prev = 43;
_context.t0 = _context["catch"](32);
console.error("Error creating pruned namespace for locale '" + locale + "':", _context.t0);
case 46:
_context.next = 30;
break;
case 48:
console.log("\u2705 Successfully created pruned namespace '" + newNamespace + "'");
case 49:
case "end":
return _context.stop();
}
}, _callee, null, [[32, 43]]);
}));
return function createPrunedNamespace(_x) {
return _ref.apply(this, arguments);
};
}();
var createPrunedNamespaceAutomated = /*#__PURE__*/function () {
var _ref = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(config, options) {
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;
return _regeneratorRuntime().wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
namespaces = config.namespaces, loadPath = config.loadPath, savePath = config.savePath, locales = config.locales, defaultNamespace = config.defaultNamespace;
sourceNamespace = options.sourceNamespace, newNamespace = options.newNamespace, globPatterns = options.globPatterns; // Validate inputs
if (namespaces.includes(sourceNamespace)) {
_context.next = 4;
break;
}
throw new Error("Source namespace '" + sourceNamespace + "' not found in configuration");
case 4:
if (!namespaces.includes(newNamespace)) {
_context.next = 6;
break;
}
throw new Error("Namespace '" + newNamespace + "' already exists");
case 6:
console.log("Creating pruned namespace '" + newNamespace + "' from '" + sourceNamespace + "'");
console.log("Using glob patterns: " + globPatterns.join(", "));
// Extract keys from files matching the glob patterns
parser = new i18nextScanner.Parser({
nsSeparator: false,
keySeparator: false
});
_context.next = 11;
return glob([].concat(globPatterns, ["!**/node_modules/**"]));
case 11:
files = _context.sent;
console.log("Found " + files.length + " files to scan");
extractedKeys = [];
for (_iterator = _createForOfIteratorHelperLoose(files); !(_step = _iterator()).done;) {
file = _step.value;
content = fs.readFileSync(file, "utf-8");
parser.parseFuncFromString(content, {
list: ["t"]
}, function (key) {
extractedKeys.push(key);
});
}
uniqueExtractedKeys = removeDuplicatesFromArray(extractedKeys);
console.log("Found " + uniqueExtractedKeys.length + " unique translation keys");
// Filter keys that belong to the source namespace
relevantKeys = [];
for (_iterator2 = _createForOfIteratorHelperLoose(uniqueExtractedKeys); !(_step2 = _iterator2()).done;) {
key = _step2.value;
pureKey = getPureKey(key, sourceNamespace, sourceNamespace === defaultNamespace);
if (pureKey) {
relevantKeys.push(pureKey);
}
}
console.log("Found " + relevantKeys.length + " keys from namespace '" + sourceNamespace + "'");
if (!(relevantKeys.length === 0)) {
_context.next = 23;
break;
}
console.log("No relevant keys found. Exiting...");
return _context.abrupt("return", {
success: false,
message: "No relevant keys found",
keysCount: 0
});
case 23:
// Get translations from source namespace and create new namespace files
results = [];
_iterator3 = _createForOfIteratorHelperLoose(locales);
case 25:
if ((_step3 = _iterator3()).done) {
_context.next = 46;
break;
}
locale = _step3.value;
_context.prev = 27;
_context.next = 30;
return loadLocalesFile(loadPath, locale, sourceNamespace);
case 30:
sourceTranslations = _context.sent;
// Create new namespace with only the keys used in the glob pattern files
newNamespaceTranslations = {};
for (_iterator4 = _createForOfIteratorHelperLoose(relevantKeys); !(_step4 = _iterator4()).done;) {
_key = _step4.value;
if (sourceTranslations[_key]) {
newNamespaceTranslations[_key] = sourceTranslations[_key];
}
}
// Write the new namespace file
_context.next = 35;
return writeLocalesFile(savePath, locale, newNamespace, newNamespaceTranslations);
case 35:
keyCount = Object.keys(newNamespaceTranslations).length;
console.log("Created pruned namespace '" + newNamespace + "' for locale '" + locale + "' with " + keyCount + " keys");
results.push({
locale: locale,
keyCount: keyCount,
success: true
});
_context.next = 44;
break;
case 40:
_context.prev = 40;
_context.t0 = _context["catch"](27);
console.error("Error creating pruned namespace for locale '" + locale + "':", _context.t0);
results.push({
locale: