fix(i18n): complete architecture page translations and fix diagram modals

- Added data-i18n to service card descriptions (validator, pressure, metacognitive, deliberation)
- Fixed interactive-diagram.js to properly load translations from i18n system
- Added language change handlers for dynamic modal updates
- All service cards and modals now fully translate across EN/DE/FR
This commit is contained in:
TheFlow 2025-10-26 13:20:56 +13:00
parent 8b3b37bdee
commit 5643050eb6
2 changed files with 114 additions and 50 deletions

View file

@ -251,7 +251,7 @@
<h3 class="text-lg font-bold text-gray-900 break-words overflow-wrap-anywhere" data-i18n="services.validator.name"></h3>
</div>
<p class="text-gray-600 text-sm mb-3 break-words overflow-wrap-anywhere">
Validates AI actions against instruction history. Aims to prevent pattern bias overriding explicit directives.
<span data-i18n="services.validator.description"></span>
</p>
<div class="text-xs rounded px-3 py-2" class="badge-validator" data-i18n-html="services.validator.promise">
<strong>Early Promise:</strong> Independent verification—AI claims checked against external source.
@ -268,7 +268,7 @@
<h3 class="text-lg font-bold text-gray-900 break-words overflow-wrap-anywhere" data-i18n="services.pressure.name"></h3>
</div>
<p class="text-gray-600 text-sm mb-3 break-words overflow-wrap-anywhere">
Monitors AI performance degradation. Escalates when context pressure threatens quality.
<span data-i18n="services.pressure.description"></span>
</p>
<div class="text-xs rounded px-3 py-2" class="badge-pressure" data-i18n-html="services.pressure.promise">
<strong>Early Promise:</strong> Objective metrics may detect manipulation attempts early.
@ -285,7 +285,7 @@
<h3 class="text-lg font-bold text-gray-900 break-words overflow-wrap-anywhere" data-i18n="services.metacognitive.name"></h3>
</div>
<p class="text-gray-600 text-sm mb-3 break-words overflow-wrap-anywhere">
Requires AI to pause and verify complex operations before execution. Structural safety check.
<span data-i18n="services.metacognitive.description"></span>
</p>
<div class="text-xs rounded px-3 py-2" class="badge-metacognitive" data-i18n-html="services.metacognitive.promise">
<strong>Early Promise:</strong> Architectural gates aim to enforce verification steps.
@ -302,7 +302,7 @@
<h3 class="text-lg font-bold text-gray-900 break-words overflow-wrap-anywhere" data-i18n="services.deliberation.name"></h3>
</div>
<p class="text-gray-600 text-sm mb-3 break-words overflow-wrap-anywhere">
Facilitates multi-stakeholder deliberation for values conflicts. AI provides facilitation, not authority.
<span data-i18n="services.deliberation.description"></span>
</p>
<div class="text-xs rounded px-3 py-2" class="badge-deliberation" data-i18n-html="services.deliberation.promise">
<strong>Early Promise:</strong> Human judgment required—architecturally enforced escalation for values.

View file

@ -57,6 +57,116 @@ class InteractiveDiagram {
console.log('[InteractiveDiagram] Loaded translations for', Object.keys(this.serviceData).length, 'services');
}
handleLanguageChange() {
console.log('[InteractiveDiagram] Language changed, reloading translations');
this.loadTranslations();
// Re-render current service if one is active
if (this.activeService) {
const service = this.serviceData[this.activeService];
if (service) {
this.renderServicePanel(service);
}
}
}
init() {
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => this.setup());
} else {
this.setup();
}
console.log('[InteractiveDiagram] Initialized');
}
setup() {
// SVG is loaded via <object> tag, need to access its contentDocument
const objectElement = document.getElementById('interactive-svg-object');
if (!objectElement) {
console.warn('[InteractiveDiagram] SVG object element not found');
return;
}
// Wait for object to load with retry mechanism
const initializeSVG = () => {
const svgDoc = objectElement.contentDocument;
if (!svgDoc) {
console.warn('[InteractiveDiagram] Could not access SVG contentDocument, retrying...');
setTimeout(initializeSVG, 100);
return;
}
// The SVG is the document element itself, or we can query for it
let svg = svgDoc.getElementById('interactive-arch-diagram');
if (!svg) {
// Try getting the root SVG element
svg = svgDoc.documentElement;
console.log('[InteractiveDiagram] Using documentElement as SVG');
}
if (!svg) {
console.warn('[InteractiveDiagram] SVG diagram not found in contentDocument');
return;
}
// Verify it's actually an SVG element (case-insensitive check)
const tagName = svg.tagName ? svg.tagName.toLowerCase() : '';
if (tagName !== 'svg') {
console.warn('[InteractiveDiagram] Element found but not SVG, tagName:', tagName, '- retrying...');
// This is the race condition - contentDocument is HTML, not SVG yet
setTimeout(initializeSVG, 100);
return;
}
// Store reference to SVG document for later use
this.svgDoc = svgDoc;
this.svg = svg;
const nodes = svg.querySelectorAll('.service-node');
console.log(`[InteractiveDiagram] Found ${nodes.length} service nodes`);
if (nodes.length === 0) {
console.warn('[InteractiveDiagram] No service nodes found in SVG');
return;
}
nodes.forEach(node => {
const serviceId = node.getAttribute('data-service');
// Click handler
node.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
this.showServiceDetails(serviceId);
}, true);
// Touch support for mobile devices
node.addEventListener('touchstart', (e) => {
e.preventDefault();
const serviceId = node.getAttribute('data-service');
this.showServiceDetails(serviceId);
}, { passive: false });
// Hover effects
node.addEventListener('mouseenter', () => {
this.highlightService(serviceId);
});
node.addEventListener('mouseleave', () => {
this.unhighlightService(serviceId);
});
// Add pointer cursor via JavaScript (CSP-compliant)
node.style.cursor = 'pointer';
});
this.addKeyboardNavigation(nodes);
// Show initial state (overview)
this.showServiceDetails('overview');
console.log('[InteractiveDiagram] Setup complete, showing overview');
};
// FIXED: Better load detection with SVG verification
const checkAndInit = () => {
const svgDoc = objectElement.contentDocument;
@ -263,52 +373,6 @@ class InteractiveDiagram {
}
}
if (typeof window !== 'undefined') {
window.interactiveDiagram = new InteractiveDiagram();
}
if (typeof module !== 'undefined' && module.exports) {
module.exports = InteractiveDiagram;
}
// Listen for language changes and reload translations
handleLanguageChange() {
console.log('[InteractiveDiagram] Language changed, reloading translations');
this.loadTranslations();
// Re-render current service if one is active
if (this.activeService) {
const service = this.serviceData[this.activeService];
if (service) {
this.renderServicePanel(service);
}
}
}
}
// Initialize and listen for language changes
if (typeof window !== 'undefined') {
window.interactiveDiagram = new InteractiveDiagram();
// Listen for i18n initialization and language changes
window.addEventListener('i18nInitialized', () => {
if (window.interactiveDiagram) {
window.interactiveDiagram.handleLanguageChange();
// Listen for language changes and reload translations
handleLanguageChange() {
console.log('[InteractiveDiagram] Language changed, reloading translations');
this.loadTranslations();
// Re-render current service if one is active
if (this.activeService) {
const service = this.serviceData[this.activeService];
if (service) {
this.renderServicePanel(service);
}
}
}
}
// Initialize and listen for language changes
if (typeof window !== 'undefined') {
window.interactiveDiagram = new InteractiveDiagram();