mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
Improve script to find translation duplicates
Format the output using a table. Use existing translator.default service to fetch translation files and extract keys and translations from the translation catalogue for a certain locale.
This commit is contained in:
parent
155066be13
commit
23d882d4cd
@ -15,118 +15,115 @@ use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
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';
|
||||
|
||||
private const string BASE_DIR = 'vendor/chill-project/chill-bundles';
|
||||
public function __construct(private readonly TranslatorInterface $translator, private readonly KernelInterface $kernel)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setDescription('Detects duplicate translations in YAML files.')
|
||||
->addOption('path', null, InputOption::VALUE_REQUIRED, 'The directory or file path containing translation files', 'translations');
|
||||
// ->addOption('output', null, InputOption::VALUE_OPTIONAL, 'The file path to write the output to', 'php://stdout');
|
||||
->addOption('locale', null, InputOption::VALUE_REQUIRED, 'Locale to check for duplicate translations', 'en');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$relativePath = $input->getOption('path');
|
||||
$basePath = self::BASE_DIR;
|
||||
$fullPath = $basePath . '/' . $relativePath;
|
||||
$locale = $input->getOption('locale');
|
||||
|
||||
// $outputPath = $input->getOption('output');
|
||||
// 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 (!file_exists($fullPath)) {
|
||||
$output->writeln("<error>The path '$fullPath' does not exist.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$translationMap = [];
|
||||
|
||||
if (is_dir($fullPath)) {
|
||||
// Process all YAML files in the directory
|
||||
foreach (glob($fullPath . '/*.yaml') as $file) {
|
||||
$this->processFile($file, $translationMap);
|
||||
if ($translationDir && is_dir($translationDir)) {
|
||||
foreach (glob($translationDir . '/*.yaml') as $file) {
|
||||
$this->translator->addResource('yaml', $file, $locale);
|
||||
}
|
||||
}
|
||||
} elseif (is_file($fullPath)) {
|
||||
// Process the specific YAML file
|
||||
$this->processFile($fullPath, $translationMap);
|
||||
} else {
|
||||
$output->writeln("<error>The path '$fullPath' is neither a directory nor a file.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$duplicates = array_filter($translationMap, function($keys) {
|
||||
$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 (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, function ($keys) {
|
||||
return count($keys) > 1;
|
||||
});
|
||||
|
||||
if (empty($duplicates)) {
|
||||
$output->writeln("<info>No duplicate translations found.</info>");
|
||||
$output->writeln("<info>No duplicate translations found for locale '$locale'.</info>");
|
||||
} else {
|
||||
$output->writeln("<comment>Duplicate translations found:</comment>");
|
||||
foreach ($duplicates as $translation => $keys) {
|
||||
$output->writeln("<info>Translation:</info> '$translation' <info>is used in keys:</info> " . implode(', ', $keys));
|
||||
}
|
||||
}
|
||||
$output->writeln("<comment>Duplicate translations found for locale '$locale':</comment>");
|
||||
|
||||
/* $outputText = "";
|
||||
if (empty($duplicates)) {
|
||||
$outputText .= "No duplicate translations found.\n";
|
||||
} else {
|
||||
$outputText .= "Duplicate translations found:\n";
|
||||
foreach ($duplicates as $translation => $keys) {
|
||||
$outputText .= "Translation: '$translation' is used in keys: " . implode(', ', $keys) . "\n";
|
||||
}
|
||||
}
|
||||
// Display the duplicates in a table
|
||||
$table = new Table($output);
|
||||
$table->setHeaders(['Translation', 'Used in Keys']);
|
||||
|
||||
// Write output to the specified file or to stdout
|
||||
if ($outputPath === 'php://stdout') {
|
||||
$output->writeln($outputText);
|
||||
} else {
|
||||
try {
|
||||
file_put_contents($outputPath, $outputText);
|
||||
$output->writeln("<info>Output written to '$outputPath'</info>");
|
||||
} catch (\Exception $e) {
|
||||
$output->writeln("<error>Failed to write to '$outputPath': " . $e->getMessage() . "</error>");
|
||||
return Command::FAILURE;
|
||||
foreach ($duplicates as $translation => $keys) {
|
||||
$wrappedTranslation = $this->wrapText($translation, 40);
|
||||
$wrappedKeys = $this->wrapText(implode(', ', $keys), 80);
|
||||
|
||||
$table->addRow([$wrappedTranslation, $wrappedKeys]);
|
||||
}
|
||||
}*/
|
||||
|
||||
$table->render();
|
||||
}
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
private function processFile($file, &$translationMap): void
|
||||
private function flattenTranslation(array $translations, string $prefix, array &$allTranslations): void
|
||||
{
|
||||
try {
|
||||
$translations = Yaml::parseFile($file);
|
||||
|
||||
// Flatten the array to handle nested keys
|
||||
$this->flattenArray($translations, '', $translationMap);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
// Handle YAML parsing exceptions
|
||||
// You might want to log the error or notify the user
|
||||
}
|
||||
}
|
||||
|
||||
private function flattenArray(array $array, $prefix, &$translationMap): void
|
||||
{
|
||||
foreach ($array as $key => $value) {
|
||||
$fullKey = $prefix ? $prefix . '.' . $key : $key;
|
||||
foreach ($translations as $key => $value) {
|
||||
$fullKey = "$prefix.$key";
|
||||
if (is_array($value)) {
|
||||
// Recursively process nested arrays
|
||||
$this->flattenArray($value, $fullKey, $translationMap);
|
||||
$this->flattenTranslation($value, $fullKey, $allTranslations);
|
||||
} else {
|
||||
// Handle translation value
|
||||
if (isset($translationMap[$value])) {
|
||||
$translationMap[$value][] = $fullKey;
|
||||
} else {
|
||||
$translationMap[$value] = [$fullKey];
|
||||
if (!isset($allTranslations[$value])) {
|
||||
$allTranslations[$value] = [];
|
||||
}
|
||||
$allTranslations[$value][] = $fullKey;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function getTranslationDirectory(string $bundleName, string $bundlePath): ?string
|
||||
{
|
||||
$translationDir = $bundlePath . '/translations';
|
||||
|
||||
if ($bundleName === 'ChillAsideActivityBundle') {
|
||||
$translationDir = $bundlePath . '/src/translations';
|
||||
}
|
||||
|
||||
return is_dir($translationDir) ? $translationDir : null;
|
||||
}
|
||||
|
||||
private function wrapText(string $text, int $width): string
|
||||
{
|
||||
return wordwrap($text, $width, "\n", true);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user