feat: comprehensive UI/UX and feature improvements
- 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
This commit is contained in:
parent
bf3e55a967
commit
a1021a0f84
20 changed files with 5281 additions and 5471 deletions
53
includes/I18n.php
Normal file
53
includes/I18n.php
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
<?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);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue