diff --git a/package.json b/package.json index 120b135..033afd4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vue-nonograms-solid", - "version": "1.14.2", + "version": "1.14.3", "homepage": "https://nonograms.7u.pl/", "type": "module", "scripts": { diff --git a/src/components/ImageImportModal.vue b/src/components/ImageImportModal.vue index f2bd08d..22cd890 100644 --- a/src/components/ImageImportModal.vue +++ b/src/components/ImageImportModal.vue @@ -486,8 +486,8 @@ onUnmounted(() => { max="99" />
- Low Density - High Density + {{ t('image.lowDensity') }} + {{ t('image.highDensity') }}
diff --git a/src/composables/useI18n.js b/src/composables/useI18n.js index 4c5022f..4396699 100644 --- a/src/composables/useI18n.js +++ b/src/composables/useI18n.js @@ -49,6 +49,8 @@ const messages = { 'image.calculating': 'Obliczanie...', 'image.calculatingSolvability': 'Obliczanie rozwiązywalności...', 'image.create': 'STWÓRZ NONOGRAM', + 'image.lowDensity': 'Niska gęstość', + 'image.highDensity': 'Wysoka gęstość', 'difficulty.easy': 'Łatwy', 'difficulty.medium': 'Średni', 'difficulty.hard': 'Trudny', @@ -229,10 +231,31 @@ const messages = { 'custom.sizeError': 'Size must be between 5 and 80!', 'custom.fillRate': 'Fill Rate', 'custom.difficulty': 'Difficulty', + 'image.title': 'Import Image', + 'image.drop': 'Drag image here', + 'image.select': 'Select File', + 'image.camera': 'Take Photo', + 'image.capture': 'Capture', + 'image.switch': 'Switch Camera', + 'image.cameraError': 'Cannot access camera', + 'image.change': 'Change Image', + 'image.size': 'Grid Size', + 'image.threshold': 'Threshold', + 'image.solvability': 'Solvability', + 'image.warning': 'This image might require guessing!', + 'image.difficulty': 'Difficulty', + 'image.calculating': 'Calculating...', + 'image.calculatingSolvability': 'Calculating solvability...', + 'image.create': 'CREATE NONOGRAM', + 'image.lowDensity': 'Low Density', + 'image.highDensity': 'High Density', 'difficulty.easy': 'Easy', + 'difficulty.medium': 'Medium', + 'difficulty.hard': 'Hard', 'difficulty.harder': 'Harder', 'difficulty.hardest': 'Hardest', 'difficulty.extreme': 'Extreme', + 'difficulty.unknown': 'Unknown', 'win.title': 'CONGRATULATIONS!', 'win.message': 'You solved the puzzle!', 'win.time': 'Time:', @@ -404,10 +427,31 @@ const messages = { 'custom.sizeError': '尺寸必须在 5 到 80 之间!', 'custom.fillRate': '填充率', 'custom.difficulty': '难度', + 'image.title': 'IMPORT IMAGE', + 'image.drop': 'Drag image here', + 'image.select': 'Select File', + 'image.camera': 'Take Photo', + 'image.capture': 'Capture', + 'image.switch': 'Switch Camera', + 'image.cameraError': 'Cannot access camera', + 'image.change': 'Change Image', + 'image.size': 'Grid Size', + 'image.threshold': 'Threshold', + 'image.solvability': 'Solvability', + 'image.warning': 'This image might require guessing!', + 'image.difficulty': 'Difficulty', + 'image.calculating': 'Calculating...', + 'image.calculatingSolvability': 'Calculating solvability...', + 'image.create': 'CREATE NONOGRAM', + 'image.lowDensity': 'Low Density', + 'image.highDensity': 'High Density', 'difficulty.easy': '简单', + 'difficulty.medium': '中等', + 'difficulty.hard': '困难', 'difficulty.harder': '较难', 'difficulty.hardest': '最难', 'difficulty.extreme': '极限', + 'difficulty.unknown': '未知', 'win.title': '恭喜!', 'win.message': '你解开了谜题!', 'win.time': '时间:', @@ -462,21 +506,7 @@ const messages = { 'simulation.table.density': '密度', 'simulation.table.solved': '已解(逻辑)', 'simulation.empty': '点击开始运行蒙特卡罗模拟', - 'custom.simulationHelp': 'How is this calculated?', - 'custom.hideMap': 'Hide difficulty map', - 'custom.showMap': 'Show difficulty map', - 'simulation.title': 'Difficulty Simulation', - 'simulation.status.ready': 'Ready', - 'simulation.status.stopped': 'Stopped', - 'simulation.status.completed': 'Completed', - 'simulation.status.simulating': 'Simulating {size}x{size} @ {density}%', - 'simulation.start': 'Start Simulation', - 'simulation.stop': 'Stop', - 'simulation.table.size': 'Size', - 'simulation.table.density': 'Density', - 'simulation.table.solved': 'Solved (Logic)', - 'simulation.empty': 'Press Start to run Monte Carlo simulation', - + 'language.de': 'German', 'language.it': 'Italian', 'language.nl': 'Dutch', @@ -627,34 +657,8 @@ const messages = { 'language.searchPlaceholder': '輸入語言名稱...', 'nav.newGame': '新遊戲', 'nav.guide': '指南', - 'custom.simulationHelp': 'How is this calculated?', - 'custom.hideMap': 'Hide difficulty map', - 'custom.showMap': 'Show difficulty map', - 'simulation.title': 'Difficulty Simulation', - 'simulation.status.ready': 'Ready', - 'simulation.status.stopped': 'Stopped', - 'simulation.status.completed': 'Completed', - 'simulation.status.simulating': 'Simulating {size}x{size} @ {density}%', - 'simulation.start': 'Start Simulation', - 'simulation.stop': 'Stop', - 'simulation.table.size': 'Size', - 'simulation.table.density': 'Density', - 'simulation.table.solved': 'Solved (Logic)', - 'simulation.empty': 'Press Start to run Monte Carlo simulation', - 'custom.simulationHelp': 'How is this calculated?', - 'custom.hideMap': 'Hide difficulty map', - 'custom.showMap': 'Show difficulty map', - 'simulation.title': 'Difficulty Simulation', - 'simulation.status.ready': 'Ready', - 'simulation.status.stopped': 'Stopped', - 'simulation.status.completed': 'Completed', - 'simulation.status.simulating': 'Simulating {size}x{size} @ {density}%', - 'simulation.start': 'Start Simulation', - 'simulation.stop': 'Stop', - 'simulation.table.size': 'Size', - 'simulation.table.density': 'Density', - 'simulation.table.solved': 'Solved (Logic)', - 'simulation.empty': 'Press Start to run Monte Carlo simulation', + + 'language.de': 'German', 'language.it': 'Italian', @@ -819,20 +823,7 @@ const messages = { 'simulation.table.density': 'घनत्व', 'simulation.table.solved': 'हल (तर्क)', 'simulation.empty': 'मोंटे कार्लो सिमुलेशन चलाने के लिए स्टार्ट दबाएँ', - 'custom.simulationHelp': 'How is this calculated?', - 'custom.hideMap': 'Hide difficulty map', - 'custom.showMap': 'Show difficulty map', - 'simulation.title': 'Difficulty Simulation', - 'simulation.status.ready': 'Ready', - 'simulation.status.stopped': 'Stopped', - 'simulation.status.completed': 'Completed', - 'simulation.status.simulating': 'Simulating {size}x{size} @ {density}%', - 'simulation.start': 'Start Simulation', - 'simulation.stop': 'Stop', - 'simulation.table.size': 'Size', - 'simulation.table.density': 'Density', - 'simulation.table.solved': 'Solved (Logic)', - 'simulation.empty': 'Press Start to run Monte Carlo simulation', + 'language.de': 'German', 'language.it': 'Italian', @@ -1006,20 +997,7 @@ const messages = { 'simulation.table.density': 'Densidad', 'simulation.table.solved': 'Resuelto (Lógica)', 'simulation.empty': 'Pulsa Iniciar para ejecutar la simulación Monte Carlo', - 'custom.simulationHelp': 'How is this calculated?', - 'custom.hideMap': 'Hide difficulty map', - 'custom.showMap': 'Show difficulty map', - 'simulation.title': 'Difficulty Simulation', - 'simulation.status.ready': 'Ready', - 'simulation.status.stopped': 'Stopped', - 'simulation.status.completed': 'Completed', - 'simulation.status.simulating': 'Simulating {size}x{size} @ {density}%', - 'simulation.start': 'Start Simulation', - 'simulation.stop': 'Stop', - 'simulation.table.size': 'Size', - 'simulation.table.density': 'Density', - 'simulation.table.solved': 'Solved (Logic)', - 'simulation.empty': 'Press Start to run Monte Carlo simulation', + 'language.de': 'German', 'language.it': 'Italian', diff --git a/verify_i18n.js b/verify_i18n.js new file mode 100644 index 0000000..e3f163e --- /dev/null +++ b/verify_i18n.js @@ -0,0 +1,107 @@ + +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; +import { execSync } from 'child_process'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +// 1. Parse useI18n.js to get keys +const i18nPath = path.join(__dirname, 'src/composables/useI18n.js'); +const i18nContent = fs.readFileSync(i18nPath, 'utf8'); + +function extractKeys(lang) { + // Find start of lang block: " en: {" + const startRegex = new RegExp(`\\s+${lang}:\\s*\\{`); + const startMatch = i18nContent.match(startRegex); + if (!startMatch) return new Set(); + + const startIndex = startMatch.index + startMatch[0].length; + let braceCount = 1; + let inString = false; + let stringChar = ''; + let endIndex = -1; + + for (let i = startIndex; i < i18nContent.length; i++) { + const char = i18nContent[i]; + + if (inString) { + if (char === stringChar && i18nContent[i-1] !== '\\') { + inString = false; + } + } else { + if (char === "'" || char === '"' || char === '`') { + inString = true; + stringChar = char; + } else if (char === '{') { + braceCount++; + } else if (char === '}') { + braceCount--; + if (braceCount === 0) { + endIndex = i; + break; + } + } + } + } + + if (endIndex === -1) return new Set(); + + const block = i18nContent.substring(startIndex, endIndex); + const keys = new Set(); + const keyRegex = /['"]([\w.-]+)['"]\s*:/g; + let match; + while ((match = keyRegex.exec(block)) !== null) { + keys.add(match[1]); + } + return keys; +} + +const enKeys = extractKeys('en'); +console.log(`Found ${enKeys.size} keys in en block.`); + +if (enKeys.has('image.title')) { + console.log("'image.title' IS present in en block."); +} else { + console.log("'image.title' is MISSING in en block."); +} + +// 2. Scan src for usages +try { + const grepOutput = execSync(`grep -r "t(['\\"]" src | grep -v "node_modules"`, { encoding: 'utf8' }); + + const usedKeys = new Set(); + const usageRegex = /t\(['"]([\w.-]+)['"]/g; + + const lines = grepOutput.split('\n'); + for (const line of lines) { + let m; + while ((m = usageRegex.exec(line)) !== null) { + usedKeys.add(m[1]); + } + } + + console.log(`Found ${usedKeys.size} used keys in src.`); + + // 3. Compare + const missingKeys = []; + for (const key of usedKeys) { + // Skip dynamic keys or composed keys if any (heuristic) + if (key.includes('${')) continue; + + if (!enKeys.has(key)) { + missingKeys.push(key); + } + } + + if (missingKeys.length > 0) { + console.log("Missing translations in en:"); + missingKeys.forEach(k => console.log(` - ${k}`)); + } else { + console.log("No missing translations found in en."); + } + +} catch (e) { + console.error("Error running grep:", e); +}