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;