Revert "Merge branch 'manage-translations' into 'master'"

This reverts commit cd99633d15, reversing
changes made to a9384bf734.
This commit is contained in:
2024-11-27 17:54:11 +01:00
parent cd99633d15
commit f6387212cb
30 changed files with 665 additions and 953 deletions

View File

@@ -1,181 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\Translation\Translator;
use Symfony\Component\Console\Helper\Table;
class DetectTranslationDuplicatesCommand extends Command
{
protected static $defaultName = 'chill:detect-duplicate-translations';
public function __construct(private readonly Translator $translator, private readonly KernelInterface $kernel)
{
parent::__construct();
}
protected function configure(): void
{
$this
->setDescription('Detects duplicate translations in YAML files.')
->addOption('locale', null, InputOption::VALUE_REQUIRED, 'Locale to check for duplicate translations', 'en')
->addOption('exclude-namespaces', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, 'Namespaces to exclude from duplicate detection', [])
->addArgument('verify-hash', InputArgument::OPTIONAL, 'The expected hash to verify translation integrity');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$locale = $input->getOption('locale');
$excludedNamespaces = $input->getOption('exclude-namespaces');
$expectedHash = $input->getArgument('verify-hash');
// Loop through all bundles and get the translation directories
foreach ($this->kernel->getBundles() as $bundle) {
$bundlePath = $bundle->getPath();
$translationDir = $this->getTranslationDirectory($bundle->getName(), $bundlePath);
if (null !== $translationDir && is_dir($translationDir)) {
foreach (glob($translationDir.'/*.yaml') as $file) {
$this->translator->addResource('yaml', $file, $locale);
}
}
}
$catalogue = $this->translator->getCatalogue($locale);
$allTranslations = [];
// Iterate through each domain in the catalogue
foreach ($catalogue->all() as $domain => $translations) {
foreach ($translations as $key => $value) {
if ($this->isExcludedNamespace("{$domain}.{$key}", $excludedNamespaces)) {
continue;
}
if (is_array($value)) {
$this->flattenTranslation($value, "{$domain}.{$key}", $allTranslations);
} else {
if (!isset($allTranslations[$value])) {
$allTranslations[$value] = [];
}
$allTranslations[$value][] = "{$domain}.{$key}";
}
}
}
// Detect values that appear in more than one key
$duplicates = array_filter($allTranslations, fn ($keys) => count($keys) > 1);
$duplicatesHash = $this->generateDuplicatesHash($duplicates);
if ('' !== $expectedHash) {
if ($duplicatesHash === $expectedHash) {
$output->writeln('<info>Translations are consistent with the expected hash.</info>');
$output->writeln("<info>Current duplicate hash: {$duplicatesHash}</info>");
return Command::SUCCESS;
}
$output->writeln('<error>Translation hash mismatch! Potential duplicate added.</error>');
$this->renderDuplicatesTable($output, $duplicates, $locale);
$output->writeln("<info>Current duplicate hash: {$duplicatesHash}</info>");
return Command::FAILURE;
}
$this->renderDuplicatesTable($output, $duplicates, $locale);
$output->writeln("<info>Current duplicate hash: {$duplicatesHash}</info>");
return Command::SUCCESS;
}
private function flattenTranslation(array $translations, string $prefix, array &$allTranslations): void
{
foreach ($translations as $key => $value) {
$fullKey = "{$prefix}.{$key}";
if (is_array($value)) {
$this->flattenTranslation($value, $fullKey, $allTranslations);
} else {
if (!isset($allTranslations[$value])) {
$allTranslations[$value] = [];
}
$allTranslations[$value][] = $fullKey;
}
}
}
private function getTranslationDirectory(string $bundleName, string $bundlePath): ?string
{
$translationDir = $bundlePath.'/translations';
if ('ChillAsideActivityBundle' === $bundleName) {
$translationDir = $bundlePath.'/src/translations';
}
return is_dir($translationDir) ? $translationDir : null;
}
private function wrapText(string $text, int $width): string
{
return wordwrap($text, $width, "\n", true);
}
private function isExcludedNamespace(string $key, array $excludedNamespaces): bool
{
foreach ($excludedNamespaces as $namespace) {
if (str_starts_with($key, (string) $namespace)) {
return true;
}
}
return false;
}
private function generateDuplicatesHash(array $duplicates): string
{
ksort($duplicates);
foreach ($duplicates as $translation => $keys) {
sort($keys);
}
return hash('md5', serialize($duplicates));
}
private function renderDuplicatesTable(OutputInterface $output, array $duplicates, string $locale): void
{
if ([] === $duplicates) {
$output->writeln("<info>No duplicate translations found for locale '{$locale}'.</info>");
return;
}
$output->writeln("<comment>Duplicate translations found for locale '{$locale}':</comment>");
$table = new Table($output);
$table->setHeaders(['Translation', 'Used in Keys']);
foreach ($duplicates as $translation => $keys) {
$wrappedTranslation = $this->wrapText($translation, 40);
$wrappedKeys = $this->wrapText(implode(', ', $keys), 80);
$table->addRow([$wrappedTranslation, $wrappedKeys]);
}
$table->render();
}
}