const fs = require('fs'); const path = require('path'); const localesDir = path.join(__dirname, '..', 'locales'); const files = fs.readdirSync(localesDir).filter(f => f.endsWith('.json')); // priority order for falling back when filling missing translations const priority = ['en.json', 'ko.json', 'ru.json', 'kk.json']; function readJSON(file) { try { return JSON.parse(fs.readFileSync(path.join(localesDir, file), 'utf8')); } catch (e) { console.error('Failed to read', file, e.message); return {}; } } function flatten(obj, prefix = '') { const res = {}; for (const k of Object.keys(obj)) { const val = obj[k]; const key = prefix ? `${prefix}.${k}` : k; if (val && typeof val === 'object' && !Array.isArray(val)) { Object.assign(res, flatten(val, key)); } else { res[key] = val; } } return res; } function unflatten(flat) { const res = {}; for (const flatKey of Object.keys(flat)) { const parts = flatKey.split('.'); let cur = res; for (let i = 0; i < parts.length; i++) { const p = parts[i]; if (i === parts.length - 1) { cur[p] = flat[flatKey]; } else { cur[p] = cur[p] || {}; cur = cur[p]; } } } return res; } // load all const data = {}; for (const f of files) { data[f] = readJSON(f); } // use en.json as canonical key set if exists, else merge all keys let canonical = {}; if (files.includes('en.json')) { canonical = flatten(data['en.json']); } else { for (const f of files) { canonical = Object.assign(canonical, flatten(data[f])); } } function getFallback(key, currentFile) { for (const p of priority) { if (p === currentFile) continue; if (!files.includes(p)) continue; const flat = flatten(data[p]); if (flat[key] && typeof flat[key] === 'string' && flat[key].trim()) return flat[key]; } return null; } let report = {}; for (const f of files) { const flat = flatten(data[f]); report[f] = { added: 0, marked: 0 }; const out = {}; for (const key of Object.keys(canonical)) { if (flat.hasOwnProperty(key)) { out[key] = flat[key]; } else { const fb = getFallback(key, f); if (fb) { out[key] = fb; } else { out[key] = '[TRANSLATE] ' + canonical[key]; report[f].marked++; } report[f].added++; } } // also keep any extra keys present in this file but not in canonical for (const key of Object.keys(flat)) { if (!out.hasOwnProperty(key)) { out[key] = flat[key]; } } // write back const nested = unflatten(out); try { fs.writeFileSync(path.join(localesDir, f), JSON.stringify(nested, null, 2), 'utf8'); } catch (e) { console.error('Failed to write', f, e.message); } } console.log('Locale sync report:'); for (const f of files) { console.log(`- ${f}: added ${report[f].added} keys, ${report[f].marked} marked for translation`); } console.log('Done. Review files in locales/ and replace [TRANSLATE] placeholders with correct translations.');