103 lines
6.6 KiB
PHP
103 lines
6.6 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* Prüft die Übersetzungen, die Plugins selbst mitbringen (lang/<Sprachcode>.json): Sie gelten nur für aktive Plugins und nur in der
|
|
* gewählten Sprache, das Sprachpaket hat bei gleichem Text Vorrang, Muster mit {} funktionieren, ungültige Dateien stören nicht,
|
|
* und die Übersicht unter Sprachen kennt sie.
|
|
*/
|
|
|
|
$pluginDir = sys_get_temp_dir() . '/deskhub-i18n-pl-' . bin2hex(random_bytes(4));
|
|
mkdir($pluginDir, 0755, true);
|
|
putenv('DESKHUB_PLUGINS_DIR=' . $pluginDir);
|
|
putenv('DESKHUB_TESTING=1');
|
|
putenv('DESKHUB_CATALOG_DEFAULTS=' . __DIR__ . '/fixtures/no-catalog.php');
|
|
putenv('DESKHUB_SQLITE_PATH=:memory:');
|
|
require_once dirname(__DIR__) . '/includes/bootstrap.php';
|
|
|
|
$failures = [];
|
|
$check = function (bool $ok, string $what) use (&$failures): void { if (!$ok) $failures[] = $what; };
|
|
$pdo = get_db();
|
|
$mkZip = function (array $files): string {
|
|
$path = sys_get_temp_dir() . '/plp-' . bin2hex(random_bytes(3)) . '.zip';
|
|
$z = new ZipArchive();
|
|
$z->open($path, ZipArchive::CREATE);
|
|
foreach ($files as $name => $content) $z->addFromString($name, $content);
|
|
$z->close();
|
|
return $path;
|
|
};
|
|
$flag = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 3 2"><rect width="3" height="2" fill="#009246"/></svg>';
|
|
|
|
// Sprachpaket "xx" mit einem Text, der auch im Plugin steht (Sprachpaket gewinnt)
|
|
$pack = $mkZip([
|
|
'plugin.json' => json_encode(['slug' => 'lang-xx', 'name' => 'Testsprache', 'version' => '1.0.0', 'entry' => 'plugin.php', 'permissions' => [], 'language' => ['code' => 'xx', 'name' => 'Testsprache', 'flag' => 'flag.svg', 'strings' => 'strings.json']]),
|
|
'plugin.php' => "<?php\n",
|
|
'flag.svg' => $flag,
|
|
'strings.json' => json_encode(['Gemeinsamer Text' => 'Shared (pack)', 'Nur im Sprachpaket' => 'Only in pack'], JSON_UNESCAPED_UNICODE),
|
|
]);
|
|
$check(plugin_install_zip($pdo, $pack)['ok'] && plugin_set_active($pdo, 'lang-xx', true, [])['ok'], 'Sprachpaket installiert und aktiv');
|
|
|
|
// Plugin mit eigenen Übersetzungen
|
|
$mkPlugin = function (string $slug, array $langFiles) use ($mkZip, $pdo): array {
|
|
$files = [
|
|
'plugin.json' => json_encode(['slug' => $slug, 'name' => 'Plugin ' . $slug, 'version' => '1.0.0', 'entry' => 'plugin.php', 'permissions' => []]),
|
|
'plugin.php' => "<?php\n",
|
|
];
|
|
foreach ($langFiles as $name => $content) $files['lang/' . $name] = $content;
|
|
return plugin_install_zip($pdo, $mkZip($files));
|
|
};
|
|
$strs = fn(array $a) => json_encode($a, JSON_UNESCAPED_UNICODE);
|
|
$r1 = $mkPlugin('probe-a', [
|
|
'xx.json' => $strs(['_info' => 'Test', 'Plugin-Text' => 'Plugin text', 'Gemeinsamer Text' => 'Shared (plugin)', '{#} Treffer im Plugin' => '{} hits in plugin', 'Hallo, {}' => 'Hi, {}']),
|
|
'yy.json' => $strs(['Plugin-Text' => 'Texte du plugin']),
|
|
'Kaputt.json' => '{}',
|
|
]);
|
|
$r2 = $mkPlugin('probe-b', ['xx.json' => '{ das ist kein JSON', 'zz.json' => $strs(['Nur b' => 'Only b'])]);
|
|
$check($r1['ok'] && $r2['ok'], 'Test-Plugins lassen sich installieren: ' . json_encode([$r1, $r2]));
|
|
$tr = fn(string $html, string $code = 'xx') => i18n_translate_html($html, $code);
|
|
|
|
// Solange das Plugin nicht aktiv ist, gilt seine Datei nicht
|
|
i18n_languages(true);
|
|
$check(!str_contains($tr('<p>Plugin-Text</p>'), 'Plugin text'), 'inaktives Plugin: seine Übersetzungen gelten nicht');
|
|
$check(plugin_set_active($pdo, 'probe-a', true, [])['ok'], 'Plugin lässt sich aktivieren');
|
|
$check(plugin_set_active($pdo, 'probe-b', true, [])['ok'], 'zweites Plugin lässt sich aktivieren');
|
|
// Wörterbuch direkt aufbauen (i18n_dictionary() merkt sich je Anfrage ein Ergebnis)
|
|
$dict = ['exact' => [], 'patterns' => [], 'count' => 0];
|
|
foreach (i18n_plugin_string_files('xx') as $f) i18n_load_strings_file($f, $dict);
|
|
i18n_load_strings_file((string) (i18n_languages(true)['xx']['strings'] ?? ''), $dict);
|
|
$check(isset($dict['exact']['Plugin-Text']) && $dict['exact']['Plugin-Text'] === 'Plugin text', 'Text aus lang/xx.json eines aktiven Plugins wird geladen');
|
|
$check(($dict['exact']['Gemeinsamer Text'] ?? '') === 'Shared (pack)', 'Bei gleichem Text gewinnt das Sprachpaket');
|
|
$check(($dict['exact']['Nur im Sprachpaket'] ?? '') === 'Only in pack', 'Texte nur im Sprachpaket bleiben erhalten');
|
|
$check(i18n_lookup('7 Treffer im Plugin', $dict) === '7 hits in plugin', 'Muster mit {#} aus dem Plugin funktioniert: ' . var_export(i18n_lookup('7 Treffer im Plugin', $dict), true));
|
|
$check(i18n_lookup('Hallo, Anna', $dict) === 'Hi, Anna', 'Muster mit {} aus dem Plugin funktioniert');
|
|
$check(!isset($dict['exact']['_info']), 'Schlüssel mit Unterstrich („_info“) werden ignoriert');
|
|
$files = i18n_plugin_string_files('xx');
|
|
$check(array_keys($files) === ['probe-a', 'probe-b'] && ($dict['count'] ?? 0) >= 5, 'beide Plugins liefern ihre Datei; die kaputte Datei von probe-b stört nicht');
|
|
$check(i18n_plugin_string_files('yy') === ['probe-a' => $pluginDir . '/probe-a/lang/yy.json'], 'eine andere Sprache bekommt nur die passenden Dateien');
|
|
$check(i18n_plugin_string_files('de') === [] && i18n_plugin_string_files('../etc') === [] && i18n_plugin_string_files('XX') === [], 'Deutsch, ungültige Codes und Großbuchstaben liefern nichts');
|
|
|
|
// Übersicht unter Sprachen
|
|
$ov = i18n_plugin_language_overview();
|
|
$check(($ov['probe-a']['xx'] ?? null) === 4 && ($ov['probe-a']['yy'] ?? null) === 1 && ($ov['probe-b']['xx'] ?? null) === 0 && ($ov['probe-b']['zz'] ?? null) === 1, 'Übersicht zählt die Texte je Plugin und Sprache: ' . json_encode($ov));
|
|
$check(!isset($ov['probe-a']['Kaputt']) && !isset($ov['probe-a']['kaputt']), 'Dateien mit ungültigem Sprachcode im Namen werden nicht aufgeführt');
|
|
|
|
// Plugin deaktivieren: Datei gilt nicht mehr
|
|
plugin_set_active($pdo, 'probe-a', false, []);
|
|
$check(array_keys(i18n_plugin_string_files('xx')) === ['probe-b'], 'deaktiviertes Plugin liefert keine Übersetzungen mehr');
|
|
// Fertige Seite: Plugin-Text und Muster werden übersetzt
|
|
plugin_set_active($pdo, 'probe-a', true, []);
|
|
i18n_dictionary('xx', true);
|
|
$page = $tr('<h1>Plugin-Text</h1><p>Hallo, Anna</p><p>Gemeinsamer Text</p><p>Nicht übersetzt</p>');
|
|
$check(str_contains($page, '<h1>Plugin text</h1>') && str_contains($page, 'Hi, Anna') && str_contains($page, 'Shared (pack)') && str_contains($page, 'Nicht übersetzt'), 'fertige Seite wird mit den Texten der Plugins übersetzt: ' . $page);
|
|
|
|
foreach (scandir($pluginDir) ?: [] as $entry) {
|
|
if ($entry === '.' || $entry === '..') continue;
|
|
is_dir($pluginDir . '/' . $entry) ? plugin_rmdir($pluginDir . '/' . $entry) : @unlink($pluginDir . '/' . $entry);
|
|
}
|
|
@rmdir($pluginDir);
|
|
if ($failures) {
|
|
fwrite(STDERR, "Fehlgeschlagen:\n - " . implode("\n - ", $failures) . "\n");
|
|
exit(1);
|
|
}
|
|
echo "Plugin language files checks passed.\n";
|