Globinours/scripts/check_translations.php

108 lines
3.6 KiB
PHP

<?php
declare(strict_types=1);
$root = dirname(__DIR__);
$fr = require $root . '/resources/lang/fr.php';
$en = require $root . '/resources/lang/en.php';
$used = [];
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($root . '/app', FilesystemIterator::SKIP_DOTS),
);
foreach ($iterator as $file) {
if ($file->getExtension() !== 'php') {
continue;
}
$source = file_get_contents($file->getPathname());
if ($source === false) {
continue;
}
preg_match_all("/\\bt(?:n)?\\(\\s*['\"]([^'\"]+)['\"]/", $source, $matches);
foreach ($matches[1] as $key) {
if (!str_ends_with($key, '.')) {
$used[$key] = true;
}
}
}
$missingFr = array_diff_key($used, $fr);
$missingEn = array_diff_key($used, $en);
$orphanFr = array_diff_key($fr, $en);
$orphanEn = array_diff_key($en, $fr);
foreach (
[
'fr manquantes' => $missingFr,
'en manquantes' => $missingEn,
'uniquement fr' => $orphanFr,
'uniquement en' => $orphanEn,
]
as $label => $keys
) {
if ($keys) {
fwrite(STDERR, $label . ' : ' . implode(', ', array_keys($keys)) . PHP_EOL);
}
}
$placeholderErrors = [];
foreach (array_intersect_key($fr, $en) as $key => $frText) {
preg_match_all('/:([a-zA-Z][a-zA-Z0-9_]*)/', (string) $frText, $frMatches);
preg_match_all('/:([a-zA-Z][a-zA-Z0-9_]*)/', (string) $en[$key], $enMatches);
$frVars = array_values(array_unique($frMatches[1]));
sort($frVars);
$enVars = array_values(array_unique($enMatches[1]));
sort($enVars);
if ($frVars !== $enVars) {
$placeholderErrors[] = $key . ' (FR: ' . implode(',', $frVars) . ' · EN: ' . implode(',', $enVars) . ')';
}
}
if ($placeholderErrors) {
fwrite(STDERR, 'variables incohérentes : ' . implode('; ', $placeholderErrors) . PHP_EOL);
}
$confirmationKeys = [
'data.confirm_reset_phrase',
'data.confirm_demo_phrase',
'asm3.confirm_import_phrase',
'asm3.confirm_replace_phrase',
];
$confirmationErrors = [];
foreach ($confirmationKeys as $key) {
if (trim((string) ($fr[$key] ?? '')) === '' || trim((string) ($en[$key] ?? '')) === '') {
$confirmationErrors[] = $key . ' vide';
} elseif ($fr[$key] === $en[$key]) {
$confirmationErrors[] = $key . ' identique en FR et EN';
}
}
if ($confirmationErrors) {
fwrite(STDERR, 'confirmations incohérentes : ' . implode('; ', $confirmationErrors) . PHP_EOL);
}
$rawOutput = [];
foreach (['/app/Controllers', '/app/Services'] as $relative) {
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($root . $relative, FilesystemIterator::SKIP_DOTS),
);
foreach ($files as $file) {
if (
$file->getExtension() !== 'php' ||
in_array($file->getFilename(), ['DevController.php', 'Migrations.php'], true)
) {
continue;
}
$source = file_get_contents($file->getPathname()) ?: '';
if (
preg_match(
'/(?:\becho\s*|throw\s+new\s+(?:RuntimeException|InvalidArgumentException)\s*\()\s*[\'\"][A-Za-zÀ-ÿ]/u',
$source,
)
) {
$rawOutput[] = str_replace($root . '/', '', $file->getPathname());
}
}
}
if ($rawOutput) {
fwrite(STDERR, 'sorties utilisateur codées en dur : ' . implode(', ', array_unique($rawOutput)) . PHP_EOL);
}
if ($missingFr || $missingEn || $orphanFr || $orphanEn || $placeholderErrors || $confirmationErrors || $rawOutput) {
exit(1);
}
echo count($used) .
' clés utilisées · ' .
count($fr) .
' traductions FR/EN cohérentes · variables et confirmations vérifiées' .
PHP_EOL;