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>
90 lines
3.3 KiB
PHP
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);
|