- Dark mode: CSS custom properties (global.css) + toggle button, persisted in localStorage - i18n: German/English language switcher (lang/de.php, lang/en.php, includes/I18n.php) - Mobile-responsive admin layout: hamburger menu, sidebar overlay (global.js + global.css) - Shared admin navigation include (includes/admin_nav.php) used across all admin pages - Toast notifications system globally available via global.js - Voucher templates/profiles: CRUD UI at admin/templates.php with voucher_templates DB table - Bulk voucher creation: create 1-20 vouchers at once with multi-print layout on index.php - Configurable voucher defaults: expire time, device limit, max limit in admin settings - Template quick-select on voucher form: auto-fills max_uses and expire_minutes - Password reset flow: forgot_password.php + reset_password.php with token-based reset - Audit log UI: admin/audit_log.php with filter, pagination, audit_log DB table - Audit logging on login, user create/edit/delete, site create/edit/delete - Admin pages updated: index, vouchers, users, sites all use admin_nav.php + dark mode + i18n - Voucher admin: live search input added alongside existing status filter + pagination - Users admin: password-reset-link button per user row (when SMTP enabled) - Login page: i18n, dark mode, language switcher, forgot password link https://claude.ai/code/session_01YN6Bcm1VSi8mpDeyKpyrdJ
53 lines
1.5 KiB
PHP
53 lines
1.5 KiB
PHP
<?php
|
|
|
|
class I18n {
|
|
private static array $translations = [];
|
|
private static string $language = 'de';
|
|
private static bool $initialized = false;
|
|
|
|
public static function init(): void {
|
|
if (self::$initialized) return;
|
|
|
|
if (!isset($_SESSION)) {
|
|
if (session_status() === PHP_SESSION_NONE) session_start();
|
|
}
|
|
|
|
if (isset($_GET['set_lang']) && in_array($_GET['set_lang'], ['de', 'en'], true)) {
|
|
$_SESSION['language'] = $_GET['set_lang'];
|
|
}
|
|
|
|
self::$language = $_SESSION['language'] ?? 'de';
|
|
|
|
$langFile = __DIR__ . '/../lang/' . self::$language . '.php';
|
|
if (file_exists($langFile)) {
|
|
self::$translations = require $langFile;
|
|
} else {
|
|
$fallback = __DIR__ . '/../lang/de.php';
|
|
if (file_exists($fallback)) {
|
|
self::$translations = require $fallback;
|
|
}
|
|
}
|
|
|
|
self::$initialized = true;
|
|
}
|
|
|
|
public static function t(string $key, array $replace = []): string {
|
|
$text = self::$translations[$key] ?? $key;
|
|
foreach ($replace as $k => $v) {
|
|
$text = str_replace('{' . $k . '}', (string)$v, $text);
|
|
}
|
|
return $text;
|
|
}
|
|
|
|
public static function getLanguage(): string {
|
|
return self::$language;
|
|
}
|
|
|
|
public static function getAvailable(): array {
|
|
return ['de' => 'Deutsch', 'en' => 'English'];
|
|
}
|
|
}
|
|
|
|
function __($key, array $replace = []): string {
|
|
return I18n::t($key, $replace);
|
|
}
|