kurz
This commit is contained in:
@@ -21,353 +21,3 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
$baseDir = dirname(__DIR__);
|
$baseDir = dirname(__DIR__);
|
||||||
echo $deJson = $baseDir . '/public/assets/i18n/de.json';
|
echo $deJson = $baseDir . '/public/assets/i18n/de.json';
|
||||||
|
|
||||||
// -------------------------------
|
|
||||||
// 1) Bestehende de.json laden
|
|
||||||
// -------------------------------
|
|
||||||
if (!is_file($deJson)) {
|
|
||||||
die("de.json nicht gefunden unter: $deJson\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
$raw = file_get_contents($deJson);
|
|
||||||
if ($raw === false) {
|
|
||||||
die("Konnte de.json nicht lesen: $deJson\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = json_decode($raw, true);
|
|
||||||
if (!is_array($data)) {
|
|
||||||
die("Ungültiges JSON in de.json\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isset($data['meta']) || !is_array($data['meta'])) {
|
|
||||||
$data['meta'] = [
|
|
||||||
'code' => '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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 </...
|
|
||||||
* Ist nur ein Best-Effort; bei komplexeren Strukturen fällt es auf null zurück.
|
|
||||||
*/
|
|
||||||
function extractInlineTextForDataI18n(string $content, int $matchOffset, int $matchLength): ?string
|
|
||||||
{
|
|
||||||
$start = $matchOffset + $matchLength;
|
|
||||||
$gtPos = strpos($content, '>', $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('Content-Type: text/plain; charset=utf-8');
|
|
||||||
echo $output;
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user