Files
hotel/docker/find-missing-translations.php
DanielS 8434d950dd Add German front-office translations
The German language pack leaves ~180 shop strings in English (search
bar, cart, room cards, footer, account menu). docker/apply-translations.php
fills only missing keys from docker/translations-de-front.php and fixes
English values in the theme language file; docker/find-missing-translations.php
lists remaining gaps. Module/theme de.php files are git-ignored upstream
(downloaded on install), so the script is re-run after each install.
Also includes the language-pack updates the installer wrote to the
tracked module de.php files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 00:33:32 +01:00

90 lines
3.3 KiB
PHP

<?php
/**
* Lists front-office strings without a translation for the given language.
* Usage: docker compose exec -u www-data app php docker/find-missing-translations.php [iso] > missing.json
* Scans theme templates and the front templates of active front modules.
*/
if (PHP_SAPI !== 'cli') {
exit;
}
$iso = isset($argv[1]) ? $argv[1] : 'de';
$root = realpath(__DIR__.'/..');
$theme = $root.'/themes/hotel-reservation-theme';
$_LANG = array();
include $theme.'/lang/'.$iso.'.php';
$themeLang = $_LANG;
$re = '/\{l\s+s=(?:\'((?:[^\'\\\\]|\\\\.)*)\'|"((?:[^"\\\\]|\\\\.)*)")(?:\s+mod=[\'"]([\w-]+)[\'"])?[^}]*\}/';
$out = array('theme' => array(), 'modules' => array());
$moduleLangCache = array();
$moduleLang = function ($mod) use (&$moduleLangCache, $root, $theme, $iso) {
if (!isset($moduleLangCache[$mod])) {
$_MODULE = array();
foreach (array($root.'/modules/'.$mod.'/translations/'.$iso.'.php', $theme.'/modules/'.$mod.'/translations/'.$iso.'.php') as $f) {
if (is_file($f)) {
include $f;
}
}
$moduleLangCache[$mod] = $_MODULE;
}
return $moduleLangCache[$mod];
};
$files = array();
$it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($theme, FilesystemIterator::SKIP_DOTS));
foreach ($it as $f) {
if (substr($f, -4) === '.tpl' && strpos($f, '/mobile/') === false && strpos($f, '/pdf/') === false) {
$files[] = (string)$f;
}
}
// older modules keep front templates in the module root
foreach (glob($root.'/modules/*/*.tpl') as $f) {
$files[] = $f;
}
foreach (glob($root.'/modules/*/views/templates/{hook,front}/*.tpl', GLOB_BRACE) as $f) {
$files[] = $f;
}
foreach (glob($root.'/modules/*/views/templates/{hook,front}/*/*.tpl', GLOB_BRACE) as $f) {
$files[] = $f;
}
foreach ($files as $file) {
$src = file_get_contents($file);
if (!preg_match_all($re, $src, $m, PREG_SET_ORDER)) {
continue;
}
$base = basename($file, '.tpl');
foreach ($m as $match) {
$string = $match[1] !== '' ? $match[1] : (isset($match[2]) ? $match[2] : '');
$string = stripslashes($string);
$mod = isset($match[3]) ? $match[3] : '';
$md5 = md5(str_replace('\'', '\\\'', $string));
if ($mod === '' && strpos($file, '/modules/') === false || $mod === '' && strpos($file, $theme) === 0 && strpos($file, $theme.'/modules/') === false) {
$key = $base.'_'.$md5;
if (empty($themeLang[$key])) {
$out['theme'][$key] = $string;
}
} else {
if ($mod === '') {
preg_match('#/modules/([\w-]+)/#', $file, $mm);
$mod = $mm[1];
}
$lang = $moduleLang($mod);
$md5m = md5($string);
$k1 = strtolower('<{'.$mod.'}hotel-reservation-theme>'.$base).'_'.$md5m;
$k2 = strtolower('<{'.$mod.'}prestashop>'.$base).'_'.$md5m;
if (empty($lang[$k1]) && empty($lang[$k2])) {
$out['modules'][$mod][$k2] = $string;
}
}
}
}
$counts = array('theme' => count($out['theme']));
foreach ($out['modules'] as $mod => $s) {
$counts[$mod] = count($s);
}
fwrite(STDERR, json_encode($counts, JSON_PRETTY_PRINT).PHP_EOL);
echo json_encode($out, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);