From 780becc9eaf794a40f54ad929f6f653a522f6ab2 Mon Sep 17 00:00:00 2001 From: TheFlow Date: Sun, 19 Oct 2025 14:49:17 +1300 Subject: [PATCH] fix(i18n): resolve footer translation keys showing on non-homepage pages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SUMMARY: Fixed critical bug where footer displayed translation keys (e.g., "footer.about_heading") instead of actual text on all pages except homepage. ROOT CAUSE: i18n-simple.js only loaded page-specific JSON files (e.g., privacy.json). Footer translations were in homepage.json, so other pages couldn't access them. SOLUTION: 1. Created common.json for Shared Translations: - Created locales/en/common.json (footer translations) - Created locales/de/common.json (footer translations) - Created locales/fr/common.json (footer translations) 2. Updated i18n-simple.js to Load Both: - Always loads common.json (footer, shared UI elements) - Loads page-specific JSON (privacy.json, about.json, etc.) - Merges both (page-specific takes precedence) IMPACT: ✓ Footer now displays correctly in all 3 languages on ALL pages ✓ Privacy page: Footer translates properly (en/de/fr) ✓ All pages: Footer translations work regardless of page-specific JSON ✓ Scalable: Easy to add more shared translations to common.json TESTING: - Verified locally on privacy.html (footer displays "Tractatus Framework") - All 3 languages load correctly from common.json - Page-specific translations still work (privacy content translates) 🤖 Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude --- public/js/i18n-simple.js | 24 ++++++++++++++++++++---- public/locales/de/common.json | 31 +++++++++++++++++++++++++++++++ public/locales/en/common.json | 31 +++++++++++++++++++++++++++++++ public/locales/fr/common.json | 31 +++++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+), 4 deletions(-) create mode 100644 public/locales/de/common.json create mode 100644 public/locales/en/common.json create mode 100644 public/locales/fr/common.json diff --git a/public/js/i18n-simple.js b/public/js/i18n-simple.js index 68347a82..18d0c7e4 100644 --- a/public/js/i18n-simple.js +++ b/public/js/i18n-simple.js @@ -74,13 +74,29 @@ const I18n = { async loadTranslations(lang) { try { + // Always load common translations (footer, navbar, etc.) + const commonResponse = await fetch(`/locales/${lang}/common.json`); + let commonTranslations = {}; + if (commonResponse.ok) { + commonTranslations = await commonResponse.json(); + } + + // Load page-specific translations const pageName = this.detectPageName(); - const response = await fetch(`/locales/${lang}/${pageName}.json`); - if (!response.ok) { + const pageResponse = await fetch(`/locales/${lang}/${pageName}.json`); + let pageTranslations = {}; + if (pageResponse.ok) { + pageTranslations = await pageResponse.json(); + } else if (pageName !== 'homepage') { + // If page-specific translations don't exist, that's okay for some pages + console.warn(`[i18n] No translations found for ${lang}/${pageName}, using common only`); + } else { throw new Error(`Failed to load translations for ${lang}/${pageName}`); } - this.translations = await response.json(); - console.log(`[i18n] Loaded translations for page: ${pageName}`); + + // Merge common and page-specific translations (page-specific takes precedence) + this.translations = { ...commonTranslations, ...pageTranslations }; + console.log(`[i18n] Loaded translations: common + ${pageName}`); } catch (error) { console.error(`[i18n] Error loading translations:`, error); // Fallback to English if loading fails diff --git a/public/locales/de/common.json b/public/locales/de/common.json new file mode 100644 index 00000000..ffc573e6 --- /dev/null +++ b/public/locales/de/common.json @@ -0,0 +1,31 @@ +{ + "footer": { + "about_heading": "Tractatus Framework", + "about_text": "Architektonische Beschränkungen für KI-Sicherheit, die menschliche Entscheidungsfreiheit durch strukturelle, nicht aspirationale, Garantien wahren.", + "documentation_heading": "Dokumentation", + "documentation_links": { + "framework_docs": "Framework-Dokumentation", + "about": "Über uns", + "core_values": "Grundwerte", + "interactive_demo": "Interaktive Demo" + }, + "support_heading": "Unterstützung", + "support_links": { + "koha": "Unterstützung (Koha)", + "transparency": "Transparenz", + "media_inquiries": "Medienanfragen", + "submit_case": "Fallstudie einreichen" + }, + "legal_heading": "Rechtliches", + "legal_links": { + "privacy": "Datenschutzerklärung", + "contact": "Kontakt", + "github": "GitHub" + }, + "te_tiriti_label": "Te Tiriti o Waitangi:", + "te_tiriti_text": "Wir erkennen Te Tiriti o Waitangi und unser Bekenntnis zu Partnerschaft, Schutz und Teilhabe an. Dieses Projekt respektiert die Māori-Datensouveränität (rangatiratanga) und kollektive Vormundschaft (kaitiakitanga).", + "copyright": "John G Stroh. Lizenziert unter", + "license": "Apache 2.0", + "location": "Hergestellt in Aotearoa Neuseeland 🇳🇿" + } +} diff --git a/public/locales/en/common.json b/public/locales/en/common.json new file mode 100644 index 00000000..9fc6357b --- /dev/null +++ b/public/locales/en/common.json @@ -0,0 +1,31 @@ +{ + "footer": { + "about_heading": "Tractatus Framework", + "about_text": "Architectural constraints for AI safety that preserve human agency through structural, not aspirational, guarantees.", + "documentation_heading": "Documentation", + "documentation_links": { + "framework_docs": "Framework Docs", + "about": "About", + "core_values": "Core Values", + "interactive_demo": "Interactive Demo" + }, + "support_heading": "Support", + "support_links": { + "koha": "Support (Koha)", + "transparency": "Transparency", + "media_inquiries": "Media Inquiries", + "submit_case": "Submit Case Study" + }, + "legal_heading": "Legal", + "legal_links": { + "privacy": "Privacy Policy", + "contact": "Contact Us", + "github": "GitHub" + }, + "te_tiriti_label": "Te Tiriti o Waitangi:", + "te_tiriti_text": "We acknowledge Te Tiriti o Waitangi and our commitment to partnership, protection, and participation. This project respects Māori data sovereignty (rangatiratanga) and collective guardianship (kaitiakitanga).", + "copyright": "John G Stroh. Licensed under", + "license": "Apache 2.0", + "location": "Made in Aotearoa New Zealand 🇳🇿" + } +} diff --git a/public/locales/fr/common.json b/public/locales/fr/common.json new file mode 100644 index 00000000..f0994f92 --- /dev/null +++ b/public/locales/fr/common.json @@ -0,0 +1,31 @@ +{ + "footer": { + "about_heading": "Tractatus Framework", + "about_text": "Contraintes architecturales pour la sécurité de l'IA qui préservent l'autonomie humaine par des garanties structurelles, et non aspirationnelles.", + "documentation_heading": "Documentation", + "documentation_links": { + "framework_docs": "Documentation du Framework", + "about": "À propos", + "core_values": "Valeurs fondamentales", + "interactive_demo": "Démo interactive" + }, + "support_heading": "Support", + "support_links": { + "koha": "Support (Koha)", + "transparency": "Transparence", + "media_inquiries": "Demandes des médias", + "submit_case": "Soumettre une étude de cas" + }, + "legal_heading": "Légal", + "legal_links": { + "privacy": "Politique de confidentialité", + "contact": "Nous contacter", + "github": "GitHub" + }, + "te_tiriti_label": "Te Tiriti o Waitangi :", + "te_tiriti_text": "Nous reconnaissons Te Tiriti o Waitangi et notre engagement envers le partenariat, la protection et la participation. Ce projet respecte la souveraineté des données māori (rangatiratanga) et la tutelle collective (kaitiakitanga).", + "copyright": "John G Stroh. Sous licence", + "license": "Apache 2.0", + "location": "Fabriqué en Aotearoa Nouvelle-Zélande 🇳🇿" + } +}