'de', 'label' => 'Deutsch', 'flag' => '🇩🇪', ]; } // ------------------------------- // 2) Verzeichnisse zum Scannen // ------------------------------- $scanDirs = [ $baseDir . '/public/landingpage', $baseDir . '/partials/landing', $baseDir . '/partials/structure', $baseDir . '/partials/partials', // nur, falls vorhanden ]; $allowedExtensions = ['php', 'html', 'htm']; // ------------------------------- // 3) Helper-Funktionen // ------------------------------- function dotKeyExists(array $data, string $key): bool { $segments = explode('.', $key); $node = $data; foreach ($segments as $seg) { if (!is_array($node) || !array_key_exists($seg, $node)) { return false; } $node = $node[$seg]; } return true; } function addDotKey(array &$data, string $key, string $default = ''): void { if (dotKeyExists($data, $key)) { return; } $segments = explode('.', $key); $node =& $data; $last = array_pop($segments); foreach ($segments as $seg) { if (!isset($node[$seg]) || !is_array($node[$seg])) { $node[$seg] = []; } $node =& $node[$seg]; } if (!array_key_exists($last, $node)) { $node[$last] = $default; } } function simpleKeyExistsRecursive(array $data, string $key): bool { foreach ($data as $k => $v) { if ($k === $key) { return true; } if (is_array($v) && simpleKeyExistsRecursive($v, $key)) { return true; } } return false; } /** * Fügt einen einfachen Key unter $data['auto'] hinzu, * sofern er nicht irgendwo in der Struktur bereits existiert. * * WICHTIG: $defaultValue ist explizit nullable, um * deprecation unter PHP 8.4+ zu vermeiden. */ function addSimpleKey(array &$data, string $key, ?string $defaultValue = null): void { if (simpleKeyExistsRecursive($data, $key)) { return; } if (!isset($data['auto']) || !is_array($data['auto'])) { $data['auto'] = []; } if ($defaultValue === null || $defaultValue === '') { $defaultValue = $key; } if (!array_key_exists($key, $data['auto'])) { $data['auto'][$key] = $defaultValue; } } /** * Key einfügen, mit optionalem Default-Text. * Dot-Notation → verschachtelt, * Simple-Key → unter "auto". */ function addKeyToData(array &$data, string $key, ?string $defaultValue = null): void { $key = trim($key); if ($key === '') { return; } $default = ($defaultValue !== null && $defaultValue !== '') ? $defaultValue : $key; if (strpos($key, '.') !== false) { addDotKey($data, $key, $default); } else { addSimpleKey($data, $key, $default); } } /** * Extrahiert den „aktuellen Inhalt“ eines data-i18n-Elements * ganz grob über Regex: * ... data-i18n="key"> Inhalt ', $start); if ($gtPos === false) { return null; } $closePos = strpos($content, '<', $gtPos + 1); if ($closePos === false) { return null; } $inner = substr($content, $gtPos + 1, $closePos - $gtPos - 1); $inner = trim($inner); if ($inner === '') { return null; } // Ganz grob Tags entfernen $inner = strip_tags($inner); $inner = trim($inner); return $inner !== '' ? $inner : null; } /** * Scannt eine Datei nach i18n-Keys und möglichen Default-Texten. * * Rückgabe: * [ 'key1' => 'Default-Text oder null', 'key2' => null, ... ] */ function collectKeysFromFile(string $file): array { $content = file_get_contents($file); if ($content === false || $content === '') { return []; } $keysWithDefaults = []; // --- data-i18n="key" / 'key' --- if (preg_match_all('/data-i18n\s*=\s*(["\'])(.+?)\1/i', $content, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) { foreach ($matches as $m) { $fullMatch = $m[0][0]; $fullOffset = $m[0][1]; $key = trim($m[2][0]); // Versuche, den Inline-Text zu extrahieren: >Text< $inlineText = extractInlineTextForDataI18n($content, $fullOffset, strlen($fullMatch)); if (!array_key_exists($key, $keysWithDefaults)) { $keysWithDefaults[$key] = $inlineText; } elseif ($keysWithDefaults[$key] === null && $inlineText !== null) { // Falls wir bisher keinen Default hatten, aber jetzt einen finden: $keysWithDefaults[$key] = $inlineText; } } } // --- i18n_get('path.to.key', 'Default') --- if (preg_match_all( '/\bi18n_get\s*\(\s*(["\'])([^"\']+)\1\s*(,\s*(["\'])(.*?)\4)?/i', $content, $m2, PREG_SET_ORDER )) { foreach ($m2 as $match) { $key = trim($match[2]); $default = isset($match[5]) ? trim($match[5]) : null; if ($default !== null && $default !== '') { // expliziter Default im PHP-Code → höchste Priorität $keysWithDefaults[$key] = $default; } else { if (!array_key_exists($key, $keysWithDefaults)) { $keysWithDefaults[$key] = null; } } } } // --- i18n_get_fmt("path.to.key", "Default", ...) --- if (preg_match_all( '/\bi18n_get_fmt\s*\(\s*(["\'])([^"\']+)\1\s*(,\s*(["\'])(.*?)\4)?/i', $content, $m3, PREG_SET_ORDER )) { foreach ($m3 as $match) { $key = trim($match[2]); $default = isset($match[5]) ? trim($match[5]) : null; if ($default !== null && $default !== '') { $keysWithDefaults[$key] = $default; } else { if (!array_key_exists($key, $keysWithDefaults)) { $keysWithDefaults[$key] = null; } } } } return $keysWithDefaults; } // ------------------------------- // 4) Dateien durchlaufen & Keys sammeln // ------------------------------- $foundKeys = []; // key => defaultText|null foreach ($scanDirs as $dir) { if (!is_dir($dir)) { continue; } $it = new RecursiveIteratorIterator( new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS) ); foreach ($it as $fileInfo) { /** @var SplFileInfo $fileInfo */ if (!$fileInfo->isFile()) { continue; } $ext = strtolower($fileInfo->getExtension()); if (!in_array($ext, $allowedExtensions, true)) { continue; } $filePath = $fileInfo->getPathname(); $keysInFile = collectKeysFromFile($filePath); foreach ($keysInFile as $key => $defaultText) { if (!array_key_exists($key, $foundKeys)) { $foundKeys[$key] = $defaultText; } else { // Wenn wir bisher keinen Default hatten, aber jetzt einen haben → übernehmen if (($foundKeys[$key] === null || $foundKeys[$key] === '') && $defaultText !== null && $defaultText !== '' ) { $foundKeys[$key] = $defaultText; } } } } } // ------------------------------- // 5) Gefundene Keys in de.json eintragen // ------------------------------- $addedCount = 0; $skippedCount = 0; $newKeys = []; foreach ($foundKeys as $key => $defaultText) { $before = json_encode($data); addKeyToData($data, $key, $defaultText); $after = json_encode($data); if ($before === $after) { $skippedCount++; } else { $addedCount++; $newKeys[] = $key; } } // ------------------------------- // 6) de.json zurückschreiben // ------------------------------- $newJson = json_encode( $data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES ); if ($newJson === false) { die("Fehler beim JSON-Encode von de.json\n"); } if (file_put_contents($deJson, $newJson) === false) { die("Konnte de.json nicht schreiben: $deJson\n"); } // ------------------------------- // 7) Ausgabe // ------------------------------- $isCli = (php_sapi_name() === 'cli'); $output = "i18n-Collect abgeschlossen.\n"; $output .= "Gefundene Keys gesamt: " . count($foundKeys) . "\n"; $output .= "Neu hinzugefügt: " . $addedCount . "\n"; $output .= "Übersprungen (bereits vorhanden): $skippedCount\n"; $output .= "Datei aktualisiert: $deJson\n"; if (!empty($newKeys)) { $output .= "\nNeu angelegte Keys:\n"; foreach ($newKeys as $k) { $output .= " - " . $k . "\n"; } } if ($isCli) { echo $output; } else { // Header nur setzen, wenn noch nichts gesendet wurde if (!headers_sent()) { header('Content-Type: text/plain; charset=utf-8'); } echo $output; }