From 9e5b54516579e3c201362ffa13361a1610f6e5bd Mon Sep 17 00:00:00 2001 From: Naheel Muhammed Date: Tue, 24 Mar 2026 21:49:13 +0530 Subject: [PATCH] refactor(i18n): --- bin/index.js | 22 ++++++---------------- lib/matcher.js | 30 +++++++++++++++++++++++------- locales/de.json | 14 +++++++------- locales/es.json | 2 +- package.json | 5 +---- scripts/extractlocals.js | 2 +- 6 files changed, 39 insertions(+), 36 deletions(-) diff --git a/bin/index.js b/bin/index.js index 46775eb..5c2b6b4 100644 --- a/bin/index.js +++ b/bin/index.js @@ -118,38 +118,28 @@ program }); // ----------------- ANALYZE COMMAND ----------------- -program + program .command("analyze ") .description("Analyze a specific error string") .option("--lang ", "output language (e.g. hi, es, fr)", "en") - .argument("", "error to explain") - - - .action(async (errorString,options) => { + .action(async (errorString, options) => { const { default: chalk } = await import("chalk"); const isJson = Boolean(program.opts().json); - const { count, matches } = findError(errorString,options.lang); + const { count, matches } = findError(errorString, options.lang); const exitCode = count > 0 ? 1 : 0; if (isJson) { - console.log( - JSON.stringify({ code: exitCode, count, matches }, null, 2) - ); + console.log(JSON.stringify({ code: exitCode, count, matches }, null, 2)); process.exit(exitCode); } if (count > 0) { - console.log( - chalk.bold.cyan(`\n🚀 ErrLens Analysis (${count} Issue(s)):`) - ); + console.log(chalk.bold.cyan(`\n🚀 ErrLens Analysis (${count} Issue(s)):`)); matches.forEach((m) => console.log(formatError(m))); } else { - console.log( - chalk.red.bold("\n❌ Crash detected (No known fix in database):") - ); + console.log(chalk.red.bold("\n❌ Crash detected (No known fix in database):")); console.log(chalk.gray(errorString)); } - process.exit(exitCode); }); diff --git a/lib/matcher.js b/lib/matcher.js index e1536df..a4fa008 100644 --- a/lib/matcher.js +++ b/lib/matcher.js @@ -4,13 +4,29 @@ const path = require("path"); // Loading the locale file function loadLocale(lang = "en"){ - const filepath = path.join(__dirname,"../locales", `${lang}.json`); - const fallback = path.join(__dirname,"../locales/en.json"); + const localesDir = path.resolve(__dirname, "../locales"); + const normalizedLang = + typeof lang === "string" && /^[a-zA-Z0-9_-]+$/.test(lang) + ? lang + : "en"; + const filepath = path.resolve(localesDir, `${normalizedLang}.json`); + const fallback = path.resolve(localesDir, "en.json"); + const relativeToLocales = path.relative(localesDir, filepath); + const safeFilepath = + !relativeToLocales.startsWith("..") && !path.isAbsolute(relativeToLocales) + ? filepath + : fallback; + try { - return JSON.parse(fs.readFileSync(filepath,"utf8")) - } catch (error) { - return JSON.parse(fs.readFileSync(fallback,"utf8")) - + return JSON.parse(fs.readFileSync(safeFilepath,"utf8")) + } catch (primaryError) { + try { + return JSON.parse(fs.readFileSync(fallback,"utf8")) + } catch (fallbackError) { + throw new Error( + `Failed to load locale \"${normalizedLang}\" at \"${safeFilepath}\" and fallback \"${fallback}\". Primary error: ${primaryError.message}. Fallback error: ${fallbackError.message}` + ) + } } } @@ -21,7 +37,7 @@ function translateEntry(entry,locale){ ...entry, explanation:locale[`${key}__explanation`] || entry.explanation, why: locale[`${key}__why`] || entry.why, - fixes: entry.fixes.map( + fixes: (Array.isArray(entry.fixes) ? entry.fixes : []).map( (fix,i) =>locale[`${key}__fix_${i}`] || fix ) } diff --git a/locales/de.json b/locales/de.json index a6bf04c..8455da0 100644 --- a/locales/de.json +++ b/locales/de.json @@ -187,13 +187,13 @@ "npm ERR! 404__why": "Tippfehler im Paketnamen oder es ist ein privates Paket.", "npm ERR! 404__fix_0": "Prüfe die Schreibweise des Pakets", "npm ERR! 404__fix_1": "npm login", - "Unexpected end of input__explanation": "Dein Code wurde abrupt beendet, wahrscheinlich fehlt eine schließende Klammer.", - "Unexpected end of input__why": "Du hast eine ( [ oder { geöffnet, aber vergessen, sie mit ) ] oder } zu schließen.", - "Unexpected end of input__fix_0": "Prüfe auf fehlende schließende Klammern )", - "Unexpected end of input__fix_1": "Prüfe auf fehlende geschweifte Klammern }", + "Unexpected end of input__explanation": "Ihr Code wurde abrupt beendet, wahrscheinlich fehlt eine schließende Klammer.", + "Unexpected end of input__why": "Sie haben eine ( [ oder { geöffnet, aber vergessen, sie mit ) ] oder } zu schließen.", + "Unexpected end of input__fix_0": "Prüfen Sie auf fehlende schließende Klammern )", + "Unexpected end of input__fix_1": "Prüfen Sie auf fehlende geschweifte Klammern }", "Unexpected end of input__fix_2": "Stelle sicher, dass alle Anführungszeichen ' oder \" geschlossen sind", - "missing ) after argument list__explanation": "Du hast vergessen, einen Funktionsaufruf mit ')' zu schließen.", + "missing ) after argument list__explanation": "Sie haben vergessen, einen Funktionsaufruf mit ')' zu schließen.", "missing ) after argument list__why": "Eine Klammer wurde geöffnet, aber die Zeile endete oder ein anderes Symbol erschien, bevor sie geschlossen wurde.", - "missing ) after argument list__fix_0": "Füge eine ')' am Ende deines Funktionsaufrufs hinzu", - "missing ) after argument list__fix_1": "Prüfe, ob du versehentlich eine ')' beim Tippen gelöscht hast" + "missing ) after argument list__fix_0": "Fügen Sie eine ')' am Ende Ihres Funktionsaufrufs hinzu", + "missing ) after argument list__fix_1": "Prüfen Sie, ob Sie versehentlich eine ')' beim Tippen gelöscht haben" } \ No newline at end of file diff --git a/locales/es.json b/locales/es.json index 4be3c68..cacbee6 100644 --- a/locales/es.json +++ b/locales/es.json @@ -99,7 +99,7 @@ "EACCES__explanation": "No tienes permiso para acceder a este archivo/puerto.", "EACCES__why": "Necesitas permisos de administrador o el archivo está bloqueado.", "EACCES__fix_0": "Usa 'sudo' (Linux/Mac)", - "EACCES__fix_1": "Verificar los permisos del archivo", + "EACCES__fix_1": "Verifica los permisos del archivo", "has already been declared__explanation": "Declaraste el mismo nombre de variable dos veces.", "has already been declared__why": "Usar 'let' o 'const' en un nombre que ya existe en el mismo ámbito.", "has already been declared__fix_0": "Renombrar una de las variables", diff --git a/package.json b/package.json index dac9257..f6f22da 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,4 @@ { - "name": "errlens", "version": "1.0.9", "description": "Professional CLI tool that explains JavaScript and Node.js errors in plain English with actionable fixes directly in your terminal.", @@ -34,8 +33,6 @@ ], "scripts": { "test": "node --test test/**/*.test-lang.js" - - }, "repository": { "type": "git", @@ -59,4 +56,4 @@ "directories": { "lib": "lib" } -} \ No newline at end of file +} diff --git a/scripts/extractlocals.js b/scripts/extractlocals.js index 5f32284..a5eaee1 100644 --- a/scripts/extractlocals.js +++ b/scripts/extractlocals.js @@ -13,7 +13,7 @@ for (const entry of db){ en[`${key}__explanation`] = entry.explanation en[`${key}__why`] = entry.why - entry.fixes.forEach((fix,i) => { + (Array.isArray(entry.fixes) ? entry.fixes : []).forEach((fix,i) => { en[`${key}__fix_${i}`] = fix }) }