diff --git a/public/components/modal.js b/public/components/modal.js
index 890d290..83e4ebd 100644
--- a/public/components/modal.js
+++ b/public/components/modal.js
@@ -4,12 +4,15 @@
* Focus-Restore, Scroll-Lock und aria-modal.
* Auf Mobile: Bottom Sheet mit Swipe-to-Close und Slide-out-Animation.
* Abhängigkeiten: CSS-Klassen aus layout.css (.modal-overlay, .modal-panel, etc.)
+ * i18n.js (t)
*
* API:
* openModal({ title, content, onSave, onDelete, size }) → void
* closeModal() → void
*/
+import { t } from '/i18n.js';
+
let activeOverlay = null;
let previouslyFocused = null;
let focusTrapHandler = null;
@@ -191,7 +194,7 @@ export function openModal({ title, content, onSave, onDelete, size = 'md' } = {}
aria-labelledby="shared-modal-title">
diff --git a/public/components/oikos-install-prompt.js b/public/components/oikos-install-prompt.js
index 2a0d407..5b5a3ff 100644
--- a/public/components/oikos-install-prompt.js
+++ b/public/components/oikos-install-prompt.js
@@ -1,7 +1,7 @@
/**
* Modul: Install-Prompt Web Component
* Zweck: Dezentes Banner für PWA-Installation (Chrome/Android) und iOS-Anleitung
- * Abhängigkeiten: Design Tokens aus tokens.css (via CSS custom properties)
+ * Abhängigkeiten: Design Tokens aus tokens.css (via CSS custom properties), i18n.js (t)
*
* Verhalten:
* - Chrome/Android: Fängt beforeinstallprompt ab, zeigt Install-Banner
@@ -11,6 +11,8 @@
* - Timing: Banner erst nach 2 Nutzer-Interaktionen anzeigen
*/
+import { t } from '/i18n.js';
+
const DISMISS_KEY = 'oikos-install-dismissed';
const DISMISS_DURATION_MS = 7 * 24 * 60 * 60 * 1000; // 7 Tage
@@ -39,6 +41,14 @@ class OikosInstallPrompt extends HTMLElement {
return;
}
+ // locale-changed: Banner neu rendern wenn Sprache wechselt
+ this._onLocaleChanged = () => {
+ if (this._currentIsIOS !== undefined) {
+ this._showBanner(this._currentIsIOS);
+ }
+ };
+ window.addEventListener('locale-changed', this._onLocaleChanged);
+
// Noch nicht genug Interaktionen
const interactions = Number(localStorage.getItem(INTERACTION_KEY) || '0');
if (interactions < INTERACTION_THRESHOLD) {
@@ -56,6 +66,9 @@ class OikosInstallPrompt extends HTMLElement {
disconnectedCallback() {
window.removeEventListener('beforeinstallprompt', this._onBeforeInstall);
if (this._offInteraction) this._offInteraction();
+ if (this._onLocaleChanged) {
+ window.removeEventListener('locale-changed', this._onLocaleChanged);
+ }
}
_waitForInteractions() {
@@ -97,6 +110,7 @@ class OikosInstallPrompt extends HTMLElement {
/** Banner rendern */
_showBanner(isIOS) {
+ this._currentIsIOS = isIOS;
this._shadow.innerHTML = '';
const style = document.createElement('style');
@@ -242,7 +256,7 @@ class OikosInstallPrompt extends HTMLElement {
const title = document.createElement('div');
title.className = 'title';
- title.textContent = 'Oikos installieren';
+ title.textContent = t('install.title');
const subtitle = document.createElement('div');
subtitle.className = 'subtitle';
@@ -251,12 +265,12 @@ class OikosInstallPrompt extends HTMLElement {
// iOS: Teilen-Icon als SVG inline
subtitle.innerHTML = '';
subtitle.append(
- document.createTextNode('Tippe auf '),
+ document.createTextNode(t('install.iosTip1')),
this._createShareIcon(),
- document.createTextNode(' → „Zum Home-Bildschirm"')
+ document.createTextNode(t('install.iosTip2'))
);
} else {
- subtitle.textContent = 'Zur App hinzufügen';
+ subtitle.textContent = t('install.subtitle');
}
text.appendChild(title);
@@ -267,7 +281,7 @@ class OikosInstallPrompt extends HTMLElement {
if (!isIOS) {
const btn = document.createElement('button');
btn.className = 'btn-install';
- btn.textContent = 'Installieren';
+ btn.textContent = t('install.installButton');
btn.addEventListener('click', () => this._onInstallClick());
banner.appendChild(btn);
}
@@ -275,7 +289,7 @@ class OikosInstallPrompt extends HTMLElement {
// Dismiss-Button
const dismiss = document.createElement('button');
dismiss.className = 'btn-dismiss';
- dismiss.setAttribute('aria-label', 'Schließen');
+ dismiss.setAttribute('aria-label', t('install.dismissLabel'));
dismiss.innerHTML = ``;
dismiss.addEventListener('click', () => this._dismiss());
banner.appendChild(dismiss);