feat(i18n): add German and French translations for all FAQ Q&As
- Added 28 FAQ question/answer translations to EN, DE, FR locale files - Modified faq.js to dynamically load FAQs from i18n system - Fixed service worker to never cache /locales/ translation files - DeepL API used for professional German and French translations - FAQ content now switches language correctly with language selector Technical changes: - Added ACTIVE_FAQ_DATA variable to faq.js for dynamic FAQ loading - Created loadFAQsFromI18n() function with i18n event listeners - Added /locales/ to service worker NEVER_CACHE_PATHS - All 28 FAQs now fully translatable across all supported languages 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
c42a81f57a
commit
9370870810
6 changed files with 1552 additions and 11 deletions
|
|
@ -1425,7 +1425,7 @@ git commit -m "governance: tighten privacy boundaries for GDPR"
|
|||
**Fix**:
|
||||
\`\`\`javascript
|
||||
// ❌ WRONG:
|
||||
const client = new MongoClient('mongodb://admin:password123@localhost:27017');
|
||||
const client = new MongoClient('mongodb://admin:xxx@localhost:27017');
|
||||
|
||||
// ✅ CORRECT:
|
||||
const client = new MongoClient(process.env.MONGO_URI);
|
||||
|
|
@ -2832,6 +2832,25 @@ See [Audit Guide](/downloads/implementation-guide.pdf) Section 9: "Regulatory Co
|
|||
}
|
||||
];
|
||||
|
||||
// Active FAQ data (can be overridden by i18n)
|
||||
let ACTIVE_FAQ_DATA = FAQ_DATA;
|
||||
|
||||
/**
|
||||
* Load FAQs from i18n translations if available
|
||||
* Falls back to hardcoded FAQ_DATA if i18n not ready
|
||||
*/
|
||||
function loadFAQsFromI18n() {
|
||||
if (window.i18nTranslations && window.i18nTranslations.faqs) {
|
||||
ACTIVE_FAQ_DATA = window.i18nTranslations.faqs;
|
||||
console.log('[FAQ] Loaded', ACTIVE_FAQ_DATA.length, 'FAQs from i18n');
|
||||
return true;
|
||||
} else {
|
||||
ACTIVE_FAQ_DATA = FAQ_DATA;
|
||||
console.log('[FAQ] Using hardcoded English FAQs (i18n not ready)');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// State management
|
||||
let currentFilter = 'all';
|
||||
let currentSearchQuery = '';
|
||||
|
|
@ -2975,7 +2994,7 @@ function renderInlineFAQs() {
|
|||
}
|
||||
|
||||
// Get top 6 most important FAQs (mix of all audiences)
|
||||
const topFAQs = FAQ_DATA.filter(faq => [19, 12, 27, 13, 1, 2].includes(faq.id));
|
||||
const topFAQs = ACTIVE_FAQ_DATA.filter(faq => [19, 12, 27, 13, 1, 2].includes(faq.id));
|
||||
|
||||
console.log(`[FAQ] Rendering ${topFAQs.length} inline FAQs (marked available: ${typeof marked !== 'undefined'})`);
|
||||
|
||||
|
|
@ -3105,6 +3124,14 @@ function setupViewAllButton() {
|
|||
}
|
||||
}
|
||||
|
||||
// Listen for i18n initialization BEFORE DOMContentLoaded
|
||||
window.addEventListener('i18nInitialized', () => {
|
||||
console.log('[FAQ] i18n initialized, loading FAQs');
|
||||
if (loadFAQsFromI18n()) {
|
||||
renderInlineFAQs();
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize on page load
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// Configure marked.js for better rendering
|
||||
|
|
@ -3116,9 +3143,17 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
});
|
||||
}
|
||||
|
||||
// Try to load FAQs from i18n (might not be ready yet)
|
||||
const loaded = loadFAQsFromI18n();
|
||||
|
||||
// Render top 6 FAQs inline on page load
|
||||
renderInlineFAQs();
|
||||
|
||||
// If i18n wasn't ready, the i18nInitialized event will trigger a re-render
|
||||
if (!loaded) {
|
||||
console.log('[FAQ] Waiting for i18n to initialize...');
|
||||
}
|
||||
|
||||
// Setup all event listeners
|
||||
setupModalListeners();
|
||||
setupSearchListener();
|
||||
|
|
@ -3136,9 +3171,9 @@ function renderFAQs() {
|
|||
const resultsCount = document.getElementById('search-results-count');
|
||||
|
||||
// Filter by audience
|
||||
let filtered = FAQ_DATA;
|
||||
let filtered = ACTIVE_FAQ_DATA;
|
||||
if (currentFilter !== 'all') {
|
||||
filtered = FAQ_DATA.filter(faq => faq.audience.includes(currentFilter));
|
||||
filtered = ACTIVE_FAQ_DATA.filter(faq => faq.audience.includes(currentFilter));
|
||||
}
|
||||
|
||||
// Filter by search query
|
||||
|
|
@ -3168,7 +3203,7 @@ function renderFAQs() {
|
|||
|
||||
// Update results count
|
||||
const filterText = currentFilter === 'all' ? 'all questions' : `${currentFilter} questions`;
|
||||
resultsCount.textContent = `Showing ${filtered.length} of ${FAQ_DATA.length} ${filterText}`;
|
||||
resultsCount.textContent = `Showing ${filtered.length} of ${ACTIVE_FAQ_DATA.length} ${filterText}`;
|
||||
|
||||
console.log(`[FAQ] Rendering ${filtered.length} FAQs in modal (marked available: ${typeof marked !== 'undefined'})`);
|
||||
|
||||
|
|
@ -3350,3 +3385,13 @@ function setupFilterListeners() {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Listen for language changes and reload FAQs
|
||||
window.addEventListener('languageChanged', () => {
|
||||
console.log('[FAQ] Language changed, reloading FAQs');
|
||||
if (loadFAQsFromI18n()) {
|
||||
renderInlineFAQs();
|
||||
renderFAQs();
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -118,8 +118,6 @@ const I18n = {
|
|||
// Expose translations globally for components like interactive-diagram
|
||||
window.i18nTranslations = this.translations;
|
||||
console.log(`[i18n] Loaded translations: common + ${pageName}`);
|
||||
console.log(`[i18n] Footer translations present:`, !!this.translations.footer);
|
||||
console.log(`[i18n] Footer.about_heading:`, this.translations.footer?.about_heading);
|
||||
} catch (error) {
|
||||
console.error(`[i18n] Error loading translations:`, error);
|
||||
// Fallback to English if loading fails
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -13,7 +13,8 @@ const VERSION_CHECK_INTERVAL = 3600000; // 1 hour in milliseconds
|
|||
const NEVER_CACHE_PATHS = [
|
||||
'/js/admin/', // Admin JavaScript - always fresh
|
||||
'/api/', // API calls
|
||||
'/admin/' // Admin pages
|
||||
'/admin/', // Admin pages
|
||||
'/locales/' // Translation files - always fresh
|
||||
];
|
||||
|
||||
// Assets to cache immediately on install
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue