diff --git a/src/Bundle/ChillMainBundle/Command/DetectTranslationDuplicatesCommand.php b/src/Bundle/ChillMainBundle/Command/DetectTranslationDuplicatesCommand.php
index 16e0c0b24..a2038a309 100644
--- a/src/Bundle/ChillMainBundle/Command/DetectTranslationDuplicatesCommand.php
+++ b/src/Bundle/ChillMainBundle/Command/DetectTranslationDuplicatesCommand.php
@@ -12,6 +12,7 @@ declare(strict_types=1);
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;
@@ -19,6 +20,7 @@ use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use Symfony\Component\Console\Helper\Table;
+
class DetectTranslationDuplicatesCommand extends Command
{
protected static $defaultName = 'app:detect-duplicate-translations';
@@ -32,12 +34,16 @@ class DetectTranslationDuplicatesCommand extends Command
{
$this
->setDescription('Detects duplicate translations in YAML files.')
- ->addOption('locale', null, InputOption::VALUE_REQUIRED, 'Locale to check for duplicate translations', 'en');
+ ->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) {
@@ -58,6 +64,9 @@ class DetectTranslationDuplicatesCommand extends Command
// 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 {
@@ -74,25 +83,27 @@ class DetectTranslationDuplicatesCommand extends Command
return count($keys) > 1;
});
- if (empty($duplicates)) {
- $output->writeln("No duplicate translations found for locale '$locale'.");
- } else {
- $output->writeln("Duplicate translations found for locale '$locale':");
+ $duplicatesHash = $this->generateDuplicatesHash($duplicates);
- // Display the duplicates in a table
- $table = new Table($output);
- $table->setHeaders(['Translation', 'Used in Keys']);
+ if ($expectedHash) {
+ if ($duplicatesHash === $expectedHash) {
+ $output->writeln('Translations are consistent with the expected hash.');
- foreach ($duplicates as $translation => $keys) {
- $wrappedTranslation = $this->wrapText($translation, 40);
- $wrappedKeys = $this->wrapText(implode(', ', $keys), 80);
+ $output->writeln("Current duplicate hash: $duplicatesHash");
+ return Command::SUCCESS;
+ } else {
+ $output->writeln('Translation hash mismatch! Potential duplicate added.');
+ $this->renderDuplicatesTable($output, $duplicates, $locale);
- $table->addRow([$wrappedTranslation, $wrappedKeys]);
+ $output->writeln("Current duplicate hash: $duplicatesHash");
+ return Command::FAILURE;
}
-
- $table->render();
}
+ $this->renderDuplicatesTable($output, $duplicates, $locale);
+
+ $output->writeln("Current duplicate hash: $duplicatesHash");
+
return Command::SUCCESS;
}
@@ -126,4 +137,44 @@ class DetectTranslationDuplicatesCommand extends Command
{
return wordwrap($text, $width, "\n", true);
}
+
+ private function isExcludedNamespace(string $key, array $excludedNamespaces): bool
+ {
+ foreach ($excludedNamespaces as $namespace) {
+ if (str_starts_with($key, $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 (empty($duplicates)) {
+ $output->writeln("No duplicate translations found for locale '$locale'.");
+ return;
+ }
+
+ $output->writeln("Duplicate translations found for locale '$locale':");
+ $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();
+ }
}