Add comprehensive internationalization support for implementer.html: - Added 277 data-i18n attributes across all major sections: * Hero section (title, subtitle, 3 value props) * Quick Links navigation (8 items) * How It Works section * Architecture diagrams (3 sections) * Hook Architecture (~50+ elements) * Deployment guide * Core Services (6 service cards) * API Reference (4 examples) * Integration Examples & Patterns (8 items) * Development Roadmap (6 items + CTA) * Resources section - Translation files: * EN: 289 keys (complete structure) * DE: 282 keys translated via DeepL Pro API (0 errors) * FR: 282 keys translated via DeepL Pro API (0 errors) * Validation: 100% - all 277 HTML keys present in all languages - Added automation scripts: * translate-implementer-deepl.js - DeepL translation automation * validate-implementer-i18n.js - Translation validation Follows successful pattern from researcher page translation. All translations professionally formatted with proper formality. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
88 lines
3 KiB
JavaScript
Executable file
88 lines
3 KiB
JavaScript
Executable file
#!/usr/bin/env node
|
|
|
|
/**
|
|
* Validate implementer.html i18n keys against translation files
|
|
*/
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
// Read HTML file and extract data-i18n keys
|
|
const htmlPath = path.join(__dirname, '../public/implementer.html');
|
|
const html = fs.readFileSync(htmlPath, 'utf8');
|
|
|
|
const keyPattern = /data-i18n="([^"]+)"/g;
|
|
const htmlKeys = new Set();
|
|
let match;
|
|
|
|
while ((match = keyPattern.exec(html)) !== null) {
|
|
htmlKeys.add(match[1]);
|
|
}
|
|
|
|
console.log('═══════════════════════════════════════════════════════════');
|
|
console.log(' Implementer.html i18n Validation');
|
|
console.log('═══════════════════════════════════════════════════════════\n');
|
|
|
|
console.log(`📄 Total data-i18n keys in HTML: ${htmlKeys.size}`);
|
|
|
|
// Load translation files
|
|
const enPath = path.join(__dirname, '../public/locales/en/implementer.json');
|
|
const dePath = path.join(__dirname, '../public/locales/de/implementer.json');
|
|
const frPath = path.join(__dirname, '../public/locales/fr/implementer.json');
|
|
|
|
const enData = JSON.parse(fs.readFileSync(enPath, 'utf8'));
|
|
const deData = JSON.parse(fs.readFileSync(dePath, 'utf8'));
|
|
const frData = JSON.parse(fs.readFileSync(frPath, 'utf8'));
|
|
|
|
// Helper to check if nested key exists
|
|
function hasNestedKey(obj, keyPath) {
|
|
const keys = keyPath.split('.');
|
|
let current = obj;
|
|
|
|
for (const key of keys) {
|
|
if (current && typeof current === 'object' && key in current) {
|
|
current = current[key];
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return typeof current === 'string' && current.length > 0;
|
|
}
|
|
|
|
// Check each language
|
|
const languages = [
|
|
{ name: 'English (EN)', code: 'en', data: enData },
|
|
{ name: 'German (DE)', code: 'de', data: deData },
|
|
{ name: 'French (FR)', code: 'fr', data: frData }
|
|
];
|
|
|
|
let allValid = true;
|
|
|
|
for (const lang of languages) {
|
|
const missingKeys = [];
|
|
|
|
for (const key of htmlKeys) {
|
|
if (!hasNestedKey(lang.data, key)) {
|
|
missingKeys.push(key);
|
|
}
|
|
}
|
|
|
|
console.log(`\n🌐 ${lang.name}`);
|
|
if (missingKeys.length === 0) {
|
|
console.log(` ✅ All ${htmlKeys.size} keys found`);
|
|
} else {
|
|
console.log(` ❌ Missing ${missingKeys.length} keys:`);
|
|
missingKeys.forEach(key => console.log(` • ${key}`));
|
|
allValid = false;
|
|
}
|
|
}
|
|
|
|
console.log('\n═══════════════════════════════════════════════════════════');
|
|
if (allValid) {
|
|
console.log('✅ VALIDATION PASSED: All i18n keys are properly translated');
|
|
} else {
|
|
console.log('❌ VALIDATION FAILED: Some keys are missing');
|
|
process.exit(1);
|
|
}
|
|
console.log('═══════════════════════════════════════════════════════════\n');
|