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);
+}