`generate-template`: Generates a translation template from en.ts for a target locale
()
| 289 | |
| 290 | /** `generate-template`: Generates a translation template from en.ts for a target locale */ |
| 291 | async function generateTemplate() { |
| 292 | const targetLocale = process.argv[3]; |
| 293 | |
| 294 | if (!targetLocale) { |
| 295 | console.error('❌ Error: Please specify a target locale'); |
| 296 | console.error('Usage: npm run i18n:generate-template <locale>'); |
| 297 | console.error('Example: npm run i18n:generate-template fr'); |
| 298 | process.exit(1); |
| 299 | } |
| 300 | |
| 301 | console.log(`Generating translation template for locale: ${targetLocale}\n`); |
| 302 | |
| 303 | // Load manifest and state to use same logic as verify |
| 304 | const manifest = loadJson(MANIFEST_PATH); |
| 305 | const state = loadJson(STATE_PATH); |
| 306 | |
| 307 | if (Object.keys(manifest).length === 0) { |
| 308 | console.error('❌ Error: No manifest found. Run "npm run i18n:sync" first.'); |
| 309 | process.exit(1); |
| 310 | } |
| 311 | |
| 312 | // Load the English source for values |
| 313 | const sourceMap = await getLocaleMap(SOURCE_LOCALE); |
| 314 | if (Object.keys(sourceMap).length === 0) { |
| 315 | console.error(`❌ Error: Could not load source locale "${SOURCE_LOCALE}"`); |
| 316 | process.exit(1); |
| 317 | } |
| 318 | |
| 319 | // Load existing translations if available |
| 320 | let existingMap = {}; |
| 321 | const targetPath = path.join(RESOURCES_DIR, `${targetLocale}.ts`); |
| 322 | if (fs.existsSync(targetPath)) { |
| 323 | existingMap = await getLocaleMap(targetLocale); |
| 324 | console.log(`📝 Found existing ${targetLocale}.ts with ${Object.keys(existingMap).length} keys`); |
| 325 | } else { |
| 326 | console.log(`📝 Creating new ${targetLocale}.ts`); |
| 327 | } |
| 328 | |
| 329 | // Check state for this locale |
| 330 | const localeState = state[targetLocale] || {}; |
| 331 | |
| 332 | // Build nested structure from flat keys |
| 333 | function buildNestedObject(flatMap, existingFlatMap, manifest, localeState) { |
| 334 | const result = {}; |
| 335 | let missingCount = 0; |
| 336 | let staleCount = 0; |
| 337 | |
| 338 | for (const [key, value] of Object.entries(flatMap)) { |
| 339 | const parts = key.split('.'); |
| 340 | let current = result; |
| 341 | |
| 342 | for (let i = 0; i < parts.length - 1; i++) { |
| 343 | const part = parts[i]; |
| 344 | if (!current[part]) { |
| 345 | current[part] = {}; |
| 346 | } |
| 347 | current = current[part]; |
| 348 | } |
no test coverage detected