dsad
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
<?php
|
<?php
|
||||||
$mainversion = 1;
|
$mainversion = 1;
|
||||||
$subversion = 0;
|
$subversion = 0;
|
||||||
$patchversion = 1;
|
$patchversion = 2;
|
||||||
@@ -10,6 +10,3 @@ $version = $GLOBALS['app_version'] ?? null;
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
<?php if ($version): ?>
|
|
||||||
<div class="app-version-fixed">v <?= htmlspecialchars($version) ?></div>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|||||||
@@ -46,8 +46,6 @@ $sharedCss = [
|
|||||||
.user-menu-item{display:block;width:100%;text-align:left;padding:.45rem .75rem;border-radius:.65rem;font-size:.9rem;color:#0f172a}
|
.user-menu-item{display:block;width:100%;text-align:left;padding:.45rem .75rem;border-radius:.65rem;font-size:.9rem;color:#0f172a}
|
||||||
.user-menu-item:hover{background:#f1f5f9}
|
.user-menu-item:hover{background:#f1f5f9}
|
||||||
.page-shell{min-height:100vh;display:flex;flex-direction:column;}
|
.page-shell{min-height:100vh;display:flex;flex-direction:column;}
|
||||||
.app-version-fixed{position:fixed;right:12px;bottom:12px;z-index:2147483000;font-size:12px;font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;color:#0f172a;background:rgba(248,250,252,.85);border:1px solid rgba(148,163,184,.6);border-radius:999px;padding:4px 10px;box-shadow:0 8px 20px rgba(15,23,42,.15);backdrop-filter:blur(6px);}
|
|
||||||
@media print {.app-version-fixed{display:none}}
|
|
||||||
</style>
|
</style>
|
||||||
<?php foreach ($layoutExtraHead as $snippet): ?>
|
<?php foreach ($layoutExtraHead as $snippet): ?>
|
||||||
<?= $snippet . PHP_EOL ?>
|
<?= $snippet . PHP_EOL ?>
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
<?php if (!defined('MATOMO_SITE_ID')) return; ?>
|
|
||||||
<?php if (!defined('MATOMO_ENABLED') || !MATOMO_ENABLED) return; ?>
|
|
||||||
<?php
|
|
||||||
$matomoDomains = [];
|
|
||||||
$primaryDomain = app_primary_domain();
|
|
||||||
$fakecheckDomain = app_fakecheck_domain();
|
|
||||||
|
|
||||||
$matomoDomains[] = '*.' . $primaryDomain;
|
|
||||||
$matomoDomains[] = '*.' . $fakecheckDomain;
|
|
||||||
$matomoDomains[] = '*.' . $primaryDomain . '/fakecheck';
|
|
||||||
?>
|
|
||||||
|
|
||||||
<!-- Matomo -->
|
|
||||||
<script>
|
|
||||||
var _paq = window._paq = window._paq || [];
|
|
||||||
_paq.push(["setDomains", <?= json_encode($matomoDomains, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) ?>]);
|
|
||||||
_paq.push(['trackPageView']);
|
|
||||||
_paq.push(['enableLinkTracking']);
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
var u = "<?= rtrim(MATOMO_URL, '/') ?>/";
|
|
||||||
_paq.push(['setTrackerUrl', u + 'matomo.php']);
|
|
||||||
_paq.push(['setSiteId', '<?= MATOMO_SITE_ID ?>']);
|
|
||||||
|
|
||||||
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
|
|
||||||
g.async=true;
|
|
||||||
g.src=u + 'matomo.js';
|
|
||||||
s.parentNode.insertBefore(g,s);
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<noscript>
|
|
||||||
<p>
|
|
||||||
<img referrerpolicy="no-referrer-when-downgrade"
|
|
||||||
src="<?= rtrim(MATOMO_URL,'/') ?>/matomo.php?idsite=<?= MATOMO_SITE_ID ?>&rec=1"
|
|
||||||
style="border:0;" alt="" />
|
|
||||||
</p>
|
|
||||||
</noscript>
|
|
||||||
<!-- End Matomo -->
|
|
||||||
@@ -1,84 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
$base = rtrim(dirname($_SERVER['SCRIPT_NAME']), '/') ?: '';
|
$pageTitle = 'Email Template System – Admin';
|
||||||
$assetVersion = defined('ASSET_VERSION') ? ASSET_VERSION : time();
|
$pageId = 'home';
|
||||||
$appBaseUrl = rtrim($GLOBALS['app_base_url'] ?? '', '/');
|
$navActive = null;
|
||||||
$appApiBase = rtrim($GLOBALS['app_api_base'] ?? '', '/');
|
require __DIR__ . '/../partials/structure/layout_start.php';
|
||||||
?>
|
?>
|
||||||
<!doctype html>
|
<main class="max-w-6xl mx-auto p-4 flex-1 w-full">
|
||||||
<html lang="de">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8"/>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
|
||||||
<title>Email Template System – Admin</title>
|
|
||||||
|
|
||||||
<!-- UI bis zur Auth verdecken -->
|
|
||||||
<script>document.documentElement.classList.add('auth-pending');</script>
|
|
||||||
<style>
|
|
||||||
html.auth-pending body { visibility: hidden; }
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.APP_BASE_URL = <?= json_encode($appBaseUrl, JSON_UNESCAPED_SLASHES) ?>;
|
|
||||||
window.APP_API_BASE = <?= json_encode($appApiBase, JSON_UNESCAPED_SLASHES) ?>;
|
|
||||||
</script>
|
|
||||||
<!-- Tailwind zuerst -->
|
|
||||||
<script src="https://cdn.tailwindcss.com"></script>
|
|
||||||
|
|
||||||
<!-- Admin-Theme (neu) -->
|
|
||||||
<link rel="stylesheet" href="assets/css/admin.css?v=<?= htmlspecialchars($assetVersion, ENT_QUOTES) ?>">
|
|
||||||
|
|
||||||
<!-- Toast danach -->
|
|
||||||
<link rel="stylesheet" href="assets/css/toast.css?v=<?= htmlspecialchars($assetVersion, ENT_QUOTES) ?>">
|
|
||||||
|
|
||||||
<!-- Kleine Hilfs-Utilities (belassen, falls admin.css andere Werte hat) -->
|
|
||||||
<style>
|
|
||||||
:root { color-scheme: light; }
|
|
||||||
.btn{display:inline-flex;align-items:center;gap:.5rem;padding:.35rem .7rem;border-radius:.7rem;border:1px solid #e5e7eb;background:#fff;font-size:.9rem;cursor:pointer;}
|
|
||||||
.btn:hover{background:#f8fafc}.btn-danger{border-color:#fecaca;color:#b91c1c}.btn-danger:hover{background:#fef2f2}
|
|
||||||
.chip{display:inline-flex;align-items:center;gap:.35rem;padding:.15rem .5rem;border-radius:999px;background:#f1f5f9;color:#334155;font-size:.75rem;border:1px solid #e5e7eb}
|
|
||||||
.chip .dot{width:.5rem;height:.5rem;border-radius:999px;background:#64748b}
|
|
||||||
dialog::backdrop{background:rgba(15,23,42,.3)}
|
|
||||||
#toast-root{z-index:2147483647}
|
|
||||||
.truncate{max-width:22rem;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}
|
|
||||||
.hidden{display:none}
|
|
||||||
.btn-avatar{padding:.35rem;border-radius:999px;width:38px;height:38px;justify-content:center;font-weight:600;background:#0ea5e9;color:#fff;border:none}
|
|
||||||
.btn-avatar:hover{background:#0284c7}
|
|
||||||
.section-card{background:#fff;border:1px solid #e2e8f0;border-radius:1rem;padding:1rem;margin-bottom:1.25rem}
|
|
||||||
.section-card h4{margin:0 0 .75rem;font-size:1rem;font-weight:600;color:#0f172a}
|
|
||||||
.input{width:100%;border:1px solid #cbd5f5;border-radius:.5rem;padding:.5rem .75rem}
|
|
||||||
.user-menu{position:absolute;top:calc(100% + .5rem);right:0;min-width:180px;background:#fff;border:1px solid #e2e8f0;border-radius:.75rem;box-shadow:0 20px 35px rgba(15,23,42,.15);padding:.35rem;z-index:50}
|
|
||||||
.user-menu-item{display:block;width:100%;text-align:left;padding:.45rem .75rem;border-radius:.6rem;font-size:.9rem;color:#0f172a}
|
|
||||||
.user-menu-item:hover{background:#f1f5f9}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body class="page-admin bg-slate-50 text-slate-800">
|
|
||||||
<header class="sticky top-0 z-30 bg-white/90 backdrop-blur border-b">
|
|
||||||
<div class="max-w-6xl mx-auto px-4 py-3 flex items-center gap-3">
|
|
||||||
<h1 class="font-semibold text-lg">Email Template System</h1>
|
|
||||||
<nav class="isolate inline-flex rounded-2xl shadow-sm border bg-white overflow-hidden ms-6">
|
|
||||||
<button type="button" data-tab="templates" class="px-4 py-2 text-sm border-e bg-sky-50 text-sky-700">Templates</button>
|
|
||||||
<button type="button" data-tab="sections" class="px-4 py-2 text-sm border-e">Sections</button>
|
|
||||||
<button type="button" data-tab="blocks" class="px-4 py-2 text-sm border-e">Blocks</button>
|
|
||||||
<button type="button" data-tab="snippets" class="px-4 py-2 text-sm">Snippets</button>
|
|
||||||
</nav>
|
|
||||||
<div class="ms-auto flex gap-3 items-center">
|
|
||||||
<button id="btn-new" type="button" class="btn">Neu …</button>
|
|
||||||
<div class="relative" id="userMenu">
|
|
||||||
<button id="btn-user" type="button" class="btn-avatar" aria-haspopup="true" aria-expanded="false">
|
|
||||||
<span id="userAvatar">U</span>
|
|
||||||
</button>
|
|
||||||
<div id="userMenuPanel" class="user-menu hidden" role="menu">
|
|
||||||
<a href="/admin/profile.php" class="user-menu-item" data-menu="profile">Profil</a>
|
|
||||||
<a href="/admin/dashboard.php" class="user-menu-item" data-role="admin">Dashboard</a>
|
|
||||||
<a href="/admin/settings.php" class="user-menu-item" data-role="admin">Administration</a>
|
|
||||||
<button id="btn-logout" type="button" class="user-menu-item text-red-600">Logout</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<main class="max-w-6xl mx-auto p-4">
|
|
||||||
<section id="view-templates" class="view"></section>
|
<section id="view-templates" class="view"></section>
|
||||||
<section id="view-sections" class="view hidden"></section>
|
<section id="view-sections" class="view hidden"></section>
|
||||||
<section id="view-blocks" class="view hidden"></section>
|
<section id="view-blocks" class="view hidden"></section>
|
||||||
@@ -185,8 +111,9 @@ $appApiBase = rtrim($GLOBALS['app_api_base'] ?? '', '/');
|
|||||||
</dialog>
|
</dialog>
|
||||||
|
|
||||||
<div id="toast-root"></div>
|
<div id="toast-root"></div>
|
||||||
|
<?php
|
||||||
<script src="assets/js/toast.js?v=<?= htmlspecialchars($assetVersion, ENT_QUOTES) ?>"></script>
|
$layoutScripts = [
|
||||||
<script type="module" src="assets/js/app.js?v=<?= htmlspecialchars($assetVersion, ENT_QUOTES) ?>"></script>
|
['src' => app_asset_url('/assets/js/toast.js')],
|
||||||
</body>
|
['src' => app_asset_url('/assets/js/app.js'), 'module' => true],
|
||||||
</html>
|
];
|
||||||
|
require __DIR__ . '/../partials/structure/layout_end.php';
|
||||||
|
|||||||
@@ -1,320 +0,0 @@
|
|||||||
<?php
|
|
||||||
$GLOBALS['page_header_scripts'] = $GLOBALS['page_header_scripts'] ?? [];
|
|
||||||
$GLOBALS['page_footer_scripts'] = $GLOBALS['page_footer_scripts'] ?? [];
|
|
||||||
$GLOBALS['page_styles'] = $GLOBALS['page_styles'] ?? [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Primäre Domain / URL (Brand)
|
|
||||||
*/
|
|
||||||
function app_primary_domain(): string
|
|
||||||
{
|
|
||||||
return defined('APP_DOMAIN_PRIMARY') ? APP_DOMAIN_PRIMARY : 'usbcheck.it';
|
|
||||||
}
|
|
||||||
|
|
||||||
function app_primary_url(): string
|
|
||||||
{
|
|
||||||
$url = defined('APP_URL_PRIMARY') ? APP_URL_PRIMARY : 'https://usbcheck.it';
|
|
||||||
return rtrim($url, '/');
|
|
||||||
}
|
|
||||||
|
|
||||||
function app_fakecheck_domain(): string
|
|
||||||
{
|
|
||||||
return defined('APP_DOMAIN_FAKECHECK') ? APP_DOMAIN_FAKECHECK : 'ismyusbfake.com';
|
|
||||||
}
|
|
||||||
|
|
||||||
function app_fakecheck_url(): string
|
|
||||||
{
|
|
||||||
$url = defined('APP_URL_FAKECHECK') ? APP_URL_FAKECHECK : 'https://ismyusbfake.com';
|
|
||||||
return rtrim($url, '/');
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------------
|
|
||||||
Zentrale Request-/URL-Helper
|
|
||||||
------------------------------------------------- */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Aktuelles Schema (http / https), inkl. Proxy-Header-Fallback.
|
|
||||||
*/
|
|
||||||
function app_request_scheme(): string
|
|
||||||
{
|
|
||||||
// Proxy / Loadbalancer
|
|
||||||
if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
|
|
||||||
$proto = strtolower((string)$_SERVER['HTTP_X_FORWARDED_PROTO']);
|
|
||||||
if ($proto === 'https' || $proto === 'http') {
|
|
||||||
return $proto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Direkt
|
|
||||||
if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') {
|
|
||||||
return 'https';
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'http';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Aktueller Host (inkl. Port, falls im Host-Header).
|
|
||||||
*/
|
|
||||||
function app_request_host(): string
|
|
||||||
{
|
|
||||||
return $_SERVER['HTTP_HOST'] ?? app_primary_domain();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Basis-URL der aktuellen Anfrage, z. B. https://staging.usbcheck.it
|
|
||||||
*/
|
|
||||||
function app_current_base_url(): string
|
|
||||||
{
|
|
||||||
return app_request_scheme() . '://' . app_request_host();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Aktueller Pfad ohne Query, z. B. /login/ oder /fakecheck/demo
|
|
||||||
*/
|
|
||||||
function app_current_path(): string
|
|
||||||
{
|
|
||||||
return strtok($_SERVER['REQUEST_URI'] ?? '/', '?');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Aktuelle URL, optional mit Query-String.
|
|
||||||
*/
|
|
||||||
function app_current_url(bool $withQuery = true): string
|
|
||||||
{
|
|
||||||
$base = app_current_base_url();
|
|
||||||
$uri = $_SERVER['REQUEST_URI'] ?? '/';
|
|
||||||
|
|
||||||
if ($withQuery) {
|
|
||||||
return $base . $uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $base . strtok($uri, '?');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Canonical-URL bestimmen.
|
|
||||||
* - Wenn $override gesetzt: exakt diesen Wert verwenden.
|
|
||||||
* - Sonst: aktuelle URL ohne Query.
|
|
||||||
*/
|
|
||||||
function app_canonical_url(?string $override = null): string
|
|
||||||
{
|
|
||||||
if (is_string($override) && $override !== '') {
|
|
||||||
return $override;
|
|
||||||
}
|
|
||||||
|
|
||||||
return app_current_url(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------------
|
|
||||||
Assets: JS / CSS
|
|
||||||
------------------------------------------------- */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Script registrieren
|
|
||||||
*/
|
|
||||||
function tpl_add_script(
|
|
||||||
string $src,
|
|
||||||
string $pos = 'footer',
|
|
||||||
bool $defer = true,
|
|
||||||
bool $async = false,
|
|
||||||
string $type = '',
|
|
||||||
?string $version = null
|
|
||||||
): void {
|
|
||||||
if ($version === null && defined('ASSET_VERSION')) {
|
|
||||||
$version = ASSET_VERSION;
|
|
||||||
}
|
|
||||||
|
|
||||||
$GLOBALS['page_header_scripts'] = $GLOBALS['page_header_scripts'] ?? [];
|
|
||||||
$GLOBALS['page_footer_scripts'] = $GLOBALS['page_footer_scripts'] ?? [];
|
|
||||||
|
|
||||||
$data = [
|
|
||||||
'src' => $src,
|
|
||||||
'defer' => $defer,
|
|
||||||
'async' => $async,
|
|
||||||
'type' => $type,
|
|
||||||
'version' => $version,
|
|
||||||
];
|
|
||||||
|
|
||||||
if ($pos === 'header') {
|
|
||||||
$GLOBALS['page_header_scripts'][] = $data;
|
|
||||||
} else {
|
|
||||||
$GLOBALS['page_footer_scripts'][] = $data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CSS registrieren – MIT Cache-Buster und Priorität
|
|
||||||
*
|
|
||||||
* @param string $href Pfad zur CSS-Datei oder externe URL
|
|
||||||
* @param string $pos aktuell nur 'header' relevant (aber für Symmetrie drin)
|
|
||||||
* @param string $priority 'early' | 'normal' | 'late'
|
|
||||||
* @param string|null $version null = nutze ASSET_VERSION (falls definiert),
|
|
||||||
* '' = kein ?v=,
|
|
||||||
* 'xyz'= erzwinge diese Version
|
|
||||||
*/
|
|
||||||
function tpl_add_style(
|
|
||||||
string $href,
|
|
||||||
string $pos = 'header',
|
|
||||||
string $priority = 'normal',
|
|
||||||
?string $version = null
|
|
||||||
): void {
|
|
||||||
if ($version === null && defined('ASSET_VERSION')) {
|
|
||||||
$version = ASSET_VERSION;
|
|
||||||
}
|
|
||||||
|
|
||||||
$GLOBALS['page_styles'][] = [
|
|
||||||
'href' => $href,
|
|
||||||
'pos' => $pos,
|
|
||||||
'priority' => $priority,
|
|
||||||
'version' => $version,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------------
|
|
||||||
Template Loader
|
|
||||||
------------------------------------------------- */
|
|
||||||
|
|
||||||
function tpl(string $file, string $type = 'structure', string $site = 'main'): void
|
|
||||||
{
|
|
||||||
$base = __DIR__ . '/../partials/';
|
|
||||||
|
|
||||||
if (preg_match('/[^a-zA-Z0-9_\-]/', $file)) {
|
|
||||||
echo "<!-- tpl(): Ungültiger Template-Name -->";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (preg_match('/[^a-zA-Z0-9_\-]/', $type)) {
|
|
||||||
echo "<!-- tpl(): Ungültiger Type -->";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (preg_match('/[^a-zA-Z0-9_\-]/', $site)) {
|
|
||||||
echo "<!-- tpl(): Ungültiger Site -->";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($type === 'landing') {
|
|
||||||
$path = $base . "landing/$site/$file.php";
|
|
||||||
} else {
|
|
||||||
$path = $base . "structure/$file.php";
|
|
||||||
}
|
|
||||||
|
|
||||||
extract($GLOBALS, EXTR_SKIP);
|
|
||||||
|
|
||||||
if (file_exists($path)) {
|
|
||||||
include $path;
|
|
||||||
} else {
|
|
||||||
echo "<!-- tpl(): Datei nicht gefunden: $path -->";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------------
|
|
||||||
Flash-Messages
|
|
||||||
------------------------------------------------- */
|
|
||||||
|
|
||||||
function flash_set(string $type, string $message, ?string $context = null): void
|
|
||||||
{
|
|
||||||
if (session_status() !== PHP_SESSION_ACTIVE) {
|
|
||||||
@session_start();
|
|
||||||
}
|
|
||||||
|
|
||||||
$_SESSION['flash'] = [
|
|
||||||
'type' => $type,
|
|
||||||
'message' => $message,
|
|
||||||
'context' => $context,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
function flash_get(): ?array
|
|
||||||
{
|
|
||||||
if (session_status() !== PHP_SESSION_ACTIVE) {
|
|
||||||
@session_start();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty($_SESSION['flash']) || !is_array($_SESSION['flash'])) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$flash = $_SESSION['flash'];
|
|
||||||
unset($_SESSION['flash']);
|
|
||||||
|
|
||||||
$flash['type'] = $flash['type'] ?? 'info';
|
|
||||||
$flash['message'] = $flash['message'] ?? '';
|
|
||||||
$flash['context'] = $flash['context'] ?? null;
|
|
||||||
|
|
||||||
return $flash;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------------
|
|
||||||
i18n Helper
|
|
||||||
------------------------------------------------- */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* interner Helper für dot-notation keys
|
|
||||||
*/
|
|
||||||
function _i18n_traverse_array(array $data, string $key)
|
|
||||||
{
|
|
||||||
$segments = explode('.', $key);
|
|
||||||
$node = $data;
|
|
||||||
|
|
||||||
foreach ($segments as $seg) {
|
|
||||||
if (!is_array($node) || !array_key_exists($seg, $node)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
$node = $node[$seg];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $node;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hauptfunktion i18n_get
|
|
||||||
*/
|
|
||||||
function i18n_get(string $path, $default = null, array $replacements = []): string
|
|
||||||
{
|
|
||||||
if (!isset($GLOBALS['i18n']) || !is_array($GLOBALS['i18n'])) {
|
|
||||||
return $default !== null ? (string)$default : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
$current = $GLOBALS['i18n']['current'] ?? [];
|
|
||||||
$fallback = $GLOBALS['i18n']['fallback'] ?? [];
|
|
||||||
|
|
||||||
$value = _i18n_traverse_array($current, $path);
|
|
||||||
|
|
||||||
if ($value === null && !empty($fallback)) {
|
|
||||||
$value = _i18n_traverse_array($fallback, $path);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_string($value)) {
|
|
||||||
return $default !== null ? (string)$default : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
$text = $value;
|
|
||||||
|
|
||||||
// built-in placeholder
|
|
||||||
$builtIn = [
|
|
||||||
'{year}' => date('Y'),
|
|
||||||
'{{primary_domain}}' => function_exists('app_primary_domain') ? app_primary_domain() : '',
|
|
||||||
'{{primary_url}}' => function_exists('app_primary_url') ? app_primary_url() : '',
|
|
||||||
];
|
|
||||||
|
|
||||||
foreach ($builtIn as $ph => $val) {
|
|
||||||
$text = str_replace($ph, $val, $text);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($replacements as $key => $val) {
|
|
||||||
$val = (string)$val;
|
|
||||||
$text = str_replace('{' . $key . '}', $val, $text);
|
|
||||||
$text = str_replace('{{' . $key . '}}', $val, $text);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $text;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Kurzform für i18n_get
|
|
||||||
*/
|
|
||||||
function i18n_get_fmt(string $path, $default = '', array $vars = []): string
|
|
||||||
{
|
|
||||||
$def = $default ?? '';
|
|
||||||
return i18n_get($path, $def, $vars);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user