From 850a04d62863774156c462897c966589d1c81787 Mon Sep 17 00:00:00 2001 From: Friederich Loheide Date: Wed, 23 Sep 2026 06:34:25 +0000 Subject: [PATCH] =?UTF-8?q?Englische=20=C3=9Cbersetzungen=20f=C3=BCr=20die?= =?UTF-8?q?=20restlichen=20Admin-Seiten?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit API-Schlüssel, Integration & Wartung, Voucher-Import, Backup & Restore, Reporting, Sicherheit (2FA) und Audit-Log waren fest auf Deutsch verdrahtet, obwohl in der Kopfzeile ein DE/EN-Umschalter sitzt. Diese Seiten laufen jetzt komplett über lang/de.php bzw. lang/en.php. - rund 200 neue Sprachschlüssel, beide Dateien deckungsgleich - Aktionsnamen im Audit-Log werden übersetzt statt fest ausgegeben - Bestätigungsdialoge und Statusmeldungen in JavaScript ebenfalls - admin/security.php initialisiert jetzt I18n und setzt passend zur Auswahl Co-Authored-By: Claude Opus 5 --- admin/api_keys.php | 54 +++---- admin/audit_log.php | 29 ++-- admin/backup.php | 32 ++-- admin/import.php | 22 +-- admin/integrations.php | 80 +++++----- admin/reports.php | 38 ++--- admin/security.php | 73 +++++---- admin/settings.php | 26 +-- admin/sites.php | 6 +- admin/templates.php | 6 +- admin/users.php | 2 +- admin/vouchers.php | 2 +- index.php | 8 +- lang/de.php | 194 +++++++++++++++++++++++ lang/en.php | 194 +++++++++++++++++++++++ tools/demo/overlay/includes/Database.php | 10 +- 16 files changed, 580 insertions(+), 196 deletions(-) diff --git a/admin/api_keys.php b/admin/api_keys.php index 4817b71..550bd03 100644 --- a/admin/api_keys.php +++ b/admin/api_keys.php @@ -37,7 +37,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['create_key'])) { ); $auth->writeAuditLog($_SESSION['user_id'], 'api_key_create', 'api_key', null, "API-Key '$name' erstellt"); $newKey = $k['plain']; - $success = 'API-Schlüssel erstellt. Bitte JETZT kopieren – er wird nur einmal angezeigt!'; + $success = __('api_created_once'); } } } @@ -46,14 +46,14 @@ if (isset($_GET['toggle']) && isset($_GET['token']) && $auth->validateCsrfToken( $row = $db->fetchOne("SELECT is_active FROM api_keys WHERE id = ?", [(int)$_GET['toggle']]); if ($row) { $db->query("UPDATE api_keys SET is_active = ? WHERE id = ?", [$row['is_active'] ? 0 : 1, (int)$_GET['toggle']]); - $success = 'Status aktualisiert.'; + $success = __('api_status_updated'); } } if (isset($_GET['delete']) && isset($_GET['token']) && $auth->validateCsrfToken($_GET['token'])) { $db->query("DELETE FROM api_keys WHERE id = ?", [(int)$_GET['delete']]); $auth->writeAuditLog($_SESSION['user_id'], 'api_key_delete', 'api_key', (int)$_GET['delete'], 'API-Key gelöscht'); - $success = 'API-Schlüssel gelöscht.'; + $success = __('api_deleted'); } $keys = $db->fetchAll("SELECT k.*, u.name AS creator FROM api_keys k LEFT JOIN users u ON k.created_by = u.id ORDER BY k.created_at DESC"); @@ -66,12 +66,12 @@ $adminBase = ''; -API-Schlüssel – <?= htmlspecialchars($appTitle) ?> +<?= __('api_title') ?> – <?= htmlspecialchars($appTitle) ?> @@ -80,55 +80,55 @@ $adminBase = '';
-

Neuer Schlüssel

-

Kopieren Sie ihn jetzt – aus Sicherheitsgründen wird er nicht erneut angezeigt.

+

+

-

Neuen API-Schlüssel erstellen

+

- - + +
- +
- - + +
- +
-

Vorhandene Schlüssel

+

-

Noch keine API-Schlüssel angelegt.

+

- + - + - + @@ -138,8 +138,8 @@ $adminBase = '';
-

Verwendung

-

Authentifizierung per Header Authorization: Bearer <key> oder X-API-Key: <key>.

+

+

Authorization: Bearer <key> oder X-API-Key: <key>.

# Voucher erstellen
 curl -X POST https://IHRE-DOMAIN/api/vouchers.php \
   -H "Authorization: Bearer uvt_…" \
@@ -148,7 +148,7 @@ curl -X POST https://IHRE-DOMAIN/api/vouchers.php \
 
 # Sites auflisten
 curl https://IHRE-DOMAIN/api/sites.php -H "X-API-Key: uvt_…"
-

OpenAPI-Spezifikation (Import in Postman/Swagger): /api/openapi.php

+

/api/openapi.php

diff --git a/admin/audit_log.php b/admin/audit_log.php index edde07b..551a042 100644 --- a/admin/audit_log.php +++ b/admin/audit_log.php @@ -45,23 +45,14 @@ $users = $db->fetchAll("SELECT id, name FROM users WHERE is_active = 1 ORDER BY $currentPage = 'audit_log'; $adminBase = ''; -$actionLabels = [ - 'voucher_created' => 'Voucher erstellt', - 'voucher_bulk' => 'Bulk Voucher', - 'user_login' => 'Login', - 'user_logout' => 'Logout', - 'user_created' => 'Benutzer erstellt', - 'user_updated' => 'Benutzer geändert', - 'user_deleted' => 'Benutzer gelöscht', - 'site_added' => 'Site hinzugefügt', - 'site_updated' => 'Site geändert', - 'site_deleted' => 'Site gelöscht', - 'settings_saved' => 'Einstellungen gespeichert', - 'password_reset' => 'Passwort-Reset', - 'template_created' => 'Profil erstellt', - 'template_updated' => 'Profil geändert', - 'template_deleted' => 'Profil gelöscht', -]; +// Aktionsnamen uebersetzt anzeigen; unbekannte Aktionen bleiben technisch. +$actionLabels = []; +foreach (['voucher_created', 'voucher_bulk', 'user_login', 'user_logout', 'user_created', + 'user_updated', 'user_deleted', 'site_added', 'site_updated', 'site_deleted', + 'settings_saved', 'password_reset', 'template_created', 'template_updated', + 'template_deleted'] as $action) { + $actionLabels[$action] = __('audit_action_' . $action); +} ?> @@ -97,7 +88,7 @@ $actionLabels = [

- - - - + + + +
diff --git a/admin/import.php b/admin/import.php index d938ac5..d32b357 100644 --- a/admin/import.php +++ b/admin/import.php @@ -74,7 +74,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['do_import'])) { Notifier::voucherCreated($created, $site['name'], $_SESSION['user_name'] ?? null); $auth->writeAuditLog($_SESSION['user_id'], 'voucher_import', 'site', $siteId, "$created Voucher importiert"); } - $success = "$created Voucher erstellt."; + $success = str_replace('{count}', (string)$created, __('import_created')); } catch (Exception $e) { $error = $e->getMessage(); } @@ -95,8 +95,8 @@ $adminBase = ''; @@ -104,27 +104,27 @@ $adminBase = '';
-

Mehrere Voucher erstellen

-

Eine Zeile pro Voucher: Name,MaxGeräte,Minuten – MaxGeräte und Minuten sind optional (Standardwerte greifen). Max. 200 Zeilen. Beispiel:
+

+

Name,MaxGeräte,Minuten
Gast Müller,1,480 · Konferenzraum A,5,240 · Tagespass

- + - + - + - +
-

Ergebnis

-
NamePräfixScopeLimitStatusZuletzt genutztErstellt von
uvt_ - - Löschen + +
+

+
NameCode / FehlerStatus
diff --git a/admin/integrations.php b/admin/integrations.php index 683c5ad..cfc7c83 100644 --- a/admin/integrations.php +++ b/admin/integrations.php @@ -49,13 +49,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['save'])) { $db->setSetting('cleanup_audit_days', max(0, (int)($_POST['cleanup_audit_days'] ?? 0))); $db->setSetting('cleanup_login_days', max(0, (int)($_POST['cleanup_login_days'] ?? 30))); $auth->writeAuditLog($_SESSION['user_id'], 'settings_update', 'config', null, 'Integration/Wartung gespeichert'); - $success = 'Einstellungen gespeichert.'; + $success = __('settings_saved'); } } if (isset($_GET['test_webhook']) && isset($_GET['token']) && $auth->validateCsrfToken($_GET['token'])) { Notifier::send('✅ Test-Benachrichtigung vom UniFi Voucher System.', ['type' => 'test']); - $success = 'Test-Benachrichtigung gesendet (sofern Webhook aktiv & URL gültig).'; + $success = __('int_webhook_test_sent'); } $enforce2fa = $db->getSetting('enforce_2fa_admins', '0') === '1'; @@ -92,12 +92,12 @@ $adminBase = ''; -Integration & Wartung – <?= htmlspecialchars($appTitle) ?> +<?= __('int_title') ?> – <?= htmlspecialchars($appTitle) ?> @@ -108,64 +108,64 @@ $adminBase = '';
-

Sicherheitsrichtlinie

-

Erzwingt Zwei-Faktor-Authentifizierung für alle Administrator-Konten (lokale Accounts). Admins ohne 2FA werden bei der nächsten Aktion zur Einrichtung geleitet.

- - +

+

+ + - + - +
-
+
-

Reverse-Proxy

-

IP-Adressen vertrauenswürdiger Proxies (kommasepariert). Nur dann wird die echte Client-IP aus X-Forwarded-For für Rate-Limit & Audit verwendet.

+

+

X-Forwarded-For

-

Webhook-Benachrichtigungen

-

Slack-, Microsoft-Teams- oder generische JSON-Webhook-URL. Wird bei Voucher-Erstellung ausgelöst.

- - +

+

+ +
-

SMS-Versand (Twilio)

-

Voucher-Codes optional per SMS versenden. Erfordert ein Twilio-Konto.

- +

+

+
-
-
+
+
-

Single Sign-On (OpenID Connect)

-

Generischer OIDC-Provider (z.B. Keycloak, Authentik, Google, Auth0). Redirect-URI:

- +

+

+
-
+
-
+
@@ -174,18 +174,18 @@ $adminBase = '';
-

Datenhaltung & Cleanup (DSGVO)

-

Aufbewahrungsfristen in Tagen (0 = deaktiviert). Ausführung per cron_cleanup.php (täglich empfohlen). -
Letzter Lauf: +

+

cron_cleanup.php +

-
-
-
+
+
+
- + diff --git a/admin/reports.php b/admin/reports.php index 6d4076c..cfd7d51 100644 --- a/admin/reports.php +++ b/admin/reports.php @@ -96,46 +96,46 @@ $adminBase = ''; -Reporting – <?= htmlspecialchars($appTitle) ?> +<?= __('rep_title') ?> – <?= htmlspecialchars($appTitle) ?>
- + - CSV (täglich) - CSV (pro Site) - CSV (pro Nutzer) - + + + +
-
Vouchers gesamt
-
Gültig
-
Verwendet
-
In Tagen erstellt
+
+
+
+
-

Erstellte Voucher ( Tage)

+

-

Pro Site

-
+

+
SiteGesamtGültigVerwendetAbgelaufen
@@ -143,12 +143,12 @@ $adminBase = '';
-

Top-Nutzer

-
+

+
BenutzerVoucher erstellt
- +
Keine Daten
diff --git a/admin/security.php b/admin/security.php index c1fb1aa..d71fcc3 100644 --- a/admin/security.php +++ b/admin/security.php @@ -6,8 +6,11 @@ ini_set('log_errors', 1); require_once __DIR__ . '/../config.php'; require_once __DIR__ . '/../includes/Database.php'; require_once __DIR__ . '/../includes/Auth.php'; +require_once __DIR__ . '/../includes/I18n.php'; require_once __DIR__ . '/../includes/Ui.php'; +I18n::init(); + $auth = new Auth(); $auth->requireLogin(); @@ -25,20 +28,20 @@ $setupRequired = isset($_GET['setup_required']); // 2FA aktivieren (Code bestaetigen) if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['enable_totp'])) { if (!$auth->validateCsrfToken($_POST['csrf_token'] ?? '')) { - $error = 'Ungültiges Sicherheits-Token'; + $error = __('sec_token_invalid'); } else { $secret = $_SESSION['totp_setup_secret'] ?? ''; $code = trim($_POST['code'] ?? ''); if ($secret === '') { - $error = 'Setup abgelaufen, bitte erneut starten.'; + $error = __('sec_setup_expired'); } elseif (!Totp::verify($secret, $code)) { - $error = 'Code ungültig. Bitte erneut versuchen.'; + $error = __('sec_code_invalid'); } else { $backupCodes = $auth->enableTotp($user['id'], $secret); unset($_SESSION['totp_setup_secret']); $totpEnabled = true; $user = $auth->getCurrentUser(); - $success = 'Zwei-Faktor-Authentifizierung wurde aktiviert. Bitte Recovery-Codes sicher speichern!'; + $success = __('sec_enabled'); } } } @@ -46,32 +49,32 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['enable_totp'])) { // Überall abmelden (andere Sessions beenden) if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['logout_others'])) { if (!$auth->validateCsrfToken($_POST['csrf_token'] ?? '')) { - $error = 'Ungültiges Sicherheits-Token'; + $error = __('sec_token_invalid'); } else { $auth->logoutOtherSessions(); - $success = 'Alle anderen Sitzungen wurden beendet.'; + $success = __('sec_sessions_closed'); } } // Recovery-Codes neu erzeugen if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['regen_codes'])) { if (!$auth->validateCsrfToken($_POST['csrf_token'] ?? '')) { - $error = 'Ungültiges Sicherheits-Token'; + $error = __('sec_token_invalid'); } elseif (!empty($user['totp_enabled'])) { $backupCodes = $auth->regenerateBackupCodes($user['id']); $user = $auth->getCurrentUser(); - $success = 'Neue Recovery-Codes erzeugt. Die alten sind jetzt ungültig.'; + $success = __('sec_codes_new'); } } // 2FA deaktivieren if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['disable_totp'])) { if (!$auth->validateCsrfToken($_POST['csrf_token'] ?? '')) { - $error = 'Ungültiges Sicherheits-Token'; + $error = __('sec_token_invalid'); } else { $auth->disableTotp($user['id']); $totpEnabled = false; - $success = 'Zwei-Faktor-Authentifizierung wurde deaktiviert.'; + $success = __('sec_disabled'); } } @@ -88,11 +91,11 @@ $dbSessions = $db->getSetting('session_driver', 'php') === 'db'; $activeSessions = $dbSessions ? $auth->activeSessionCount() : 0; ?> - + -Zwei-Faktor-Authentifizierung – <?= htmlspecialchars($appTitle) ?> +<?= __('sec_title') ?> – <?= htmlspecialchars($appTitle) ?> @@ -103,21 +106,21 @@ $activeSessions = $dbSessions ? $auth->activeSessionCount() : 0;
-

Zwei-Faktor-Authentifizierung

-

Konto:

+

+

-
Aus Sicherheitsgründen ist 2FA für Administratoren verpflichtend. Bitte jetzt einrichten.
+
- Recovery-Codes -

Bewahren Sie diese sicher auf. Jeder Code funktioniert einmal, falls Sie keinen Zugriff auf Ihre App haben.

+ +

@@ -125,34 +128,34 @@ $activeSessions = $dbSessions ? $auth->activeSessionCount() : 0; -
Nicht verfügbar
-

Ihr Konto meldet sich über Microsoft 365 an. 2FA wird dort in Ihrem Microsoft-Konto verwaltet.

+
+

-
Aktiv
-

Bei jeder Anmeldung wird zusätzlich ein Code aus Ihrer Authenticator-App abgefragt.
- Verbleibende Recovery-Codes: backupCodesRemaining($user) ?>

+
+


+ backupCodesRemaining($user) ?>

- +
-
+ - +
-
Inaktiv
+
    -
  1. Authenticator-App öffnen (Google Authenticator, Authy, Microsoft Authenticator …)
  2. -
  3. QR-Code scannen oder Secret manuell eingeben
  4. -
  5. Den angezeigten 6-stelligen Code unten eingeben
  6. +
  7. +
  8. +
- + - +