Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Translation] added an --all option to the debug:translation command #14237 #14320

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
234 changes: 147 additions & 87 deletions src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@

namespace Symfony\Bundle\FrameworkBundle\Command;

use Symfony\Component\Translation\Catalogue\MergeOperation;
use Symfony\Bundle\FrameworkBundle\Translation\TranslationLoader;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Translation\Catalogue\MergeOperation;
use Symfony\Component\Translation\MessageCatalogue;
use Symfony\Component\Translation\Translator;

Expand Down Expand Up @@ -48,6 +50,7 @@ protected function configure()
new InputOption('domain', null, InputOption::VALUE_OPTIONAL, 'The messages domain'),
new InputOption('only-missing', null, InputOption::VALUE_NONE, 'Displays only missing messages'),
new InputOption('only-unused', null, InputOption::VALUE_NONE, 'Displays only unused messages'),
new InputOption('all', null, InputOption::VALUE_NONE, 'Load messages from all registered bundles'),
))
->setDescription('Displays translation messages information')
->setHelp(<<<EOF
Expand Down Expand Up @@ -75,6 +78,10 @@ protected function configure()

<info>php %command.full_name% en</info>

You can display information about translations in all registered bundles in a specific locale:

<info>php %command.full_name% --all en</info>

EOF
)
;
Expand All @@ -91,129 +98,123 @@ protected function execute(InputInterface $input, OutputInterface $output)

$locale = $input->getArgument('locale');
$domain = $input->getOption('domain');
/** @var TranslationLoader $loader */
$loader = $this->getContainer()->get('translation.loader');
/** @var Kernel $kernel */
$kernel = $this->getContainer()->get('kernel');

// Define Root Path to App folder
$rootPath = $kernel->getRootDir();
$rootPaths = array($kernel->getRootDir());

// Override with provided Bundle info
if (null !== $input->getArgument('bundle')) {
try {
$rootPath = $kernel->getBundle($input->getArgument('bundle'))->getPath();
$rootPaths = array($kernel->getBundle($input->getArgument('bundle'))->getPath());
} catch (\InvalidArgumentException $e) {
// such a bundle does not exist, so treat the argument as path
$rootPath = $input->getArgument('bundle');
$rootPaths = array($input->getArgument('bundle'));

if (!is_dir($rootPath)) {
throw new \InvalidArgumentException(sprintf('<error>"%s" is neither an enabled bundle nor a directory.</error>', $rootPath));
if (!is_dir($rootPaths[0])) {
throw new \InvalidArgumentException(
sprintf('<error>"%s" is neither an enabled bundle nor a directory.</error>', $rootPaths[0])
);
}
}
} elseif ($input->getOption('all')) {
foreach ($kernel->getBundles() as $bundle) {
$rootPaths[] = $bundle->getPath();
}
}

// get bundle directory
$translationsPath = $rootPath.'/Resources/translations';
foreach ($rootPaths as $rootPath) {
// get bundle directory
$translationsPath = $rootPath.'/Resources/translations';

// Extract used messages
$extractedCatalogue = new MessageCatalogue($locale);
if (is_dir($rootPath.'/Resources/views')) {
$this->getContainer()->get('translation.extractor')->extract($rootPath.'/Resources/views', $extractedCatalogue);
}
$output->writeln(sprintf('Translations in <info>%s</info>', $translationsPath));

// Load defined messages
$currentCatalogue = new MessageCatalogue($locale);
if (is_dir($translationsPath)) {
$loader->loadMessages($translationsPath, $currentCatalogue);
}

// Merge defined and extracted messages to get all message ids
$mergeOperation = new MergeOperation($extractedCatalogue, $currentCatalogue);
$allMessages = $mergeOperation->getResult()->all($domain);
if (null !== $domain) {
$allMessages = array($domain => $allMessages);
}
// Extract used messages
$extractedCatalogue = $this->extractMessages($locale, $rootPath);

// No defined or extracted messages
if (empty($allMessages) || null !== $domain && empty($allMessages[$domain])) {
$outputMessage = sprintf('<info>No defined or extracted messages for locale "%s"</info>', $locale);
// Load defined messages
$currentCatalogue = $this->loadCurrentMessages($locale, $translationsPath, $loader);

// Merge defined and extracted messages to get all message ids
$mergeOperation = new MergeOperation($extractedCatalogue, $currentCatalogue);
$allMessages = $mergeOperation->getResult()->all($domain);
if (null !== $domain) {
$outputMessage .= sprintf(' <info>and domain "%s"</info>', $domain);
$allMessages = array($domain => $allMessages);
}

$output->writeln($outputMessage);

return;
}
// No defined or extracted messages
if (empty($allMessages) || null !== $domain && empty($allMessages[$domain])) {
$outputMessage = sprintf('<info>No defined or extracted messages for locale "%s"</info>', $locale);

// Load the fallback catalogues
$fallbackCatalogues = array();
$translator = $this->getContainer()->get('translator');
if ($translator instanceof Translator) {
foreach ($translator->getFallbackLocales() as $fallbackLocale) {
if ($fallbackLocale === $locale) {
continue;
if (null !== $domain) {
$outputMessage .= sprintf(' <info>and domain "%s"</info>', $domain);
}

$fallbackCatalogue = new MessageCatalogue($fallbackLocale);
$loader->loadMessages($translationsPath, $fallbackCatalogue);
$fallbackCatalogues[] = $fallbackCatalogue;
}
}
$output->writeln($outputMessage);

if (class_exists('Symfony\Component\Console\Helper\Table')) {
$table = new Table($output);
} else {
$table = $this->getHelperSet()->get('table');
}
continue;
}

// Display header line
$headers = array('State', 'Domain', 'Id', sprintf('Message Preview (%s)', $locale));
foreach ($fallbackCatalogues as $fallbackCatalogue) {
$headers[] = sprintf('Fallback Message Preview (%s)', $fallbackCatalogue->getLocale());
}
$table->setHeaders($headers);
// Load the fallback catalogues
$fallbackCatalogues = $this->loadFallbackCatalogues($locale, $translationsPath, $loader);
if (class_exists('Symfony\Component\Console\Helper\Table')) {
$table = new Table($output);
} else {
$table = $this->getHelperSet()->get('table');
}

// Iterate all message ids and determine their state
foreach ($allMessages as $domain => $messages) {
foreach (array_keys($messages) as $messageId) {
$value = $currentCatalogue->get($messageId, $domain);
$states = array();
// Display header line
$headers = array('State', 'Domain', 'Id', sprintf('Message Preview (%s)', $locale));
foreach ($fallbackCatalogues as $fallbackCatalogue) {
$headers[] = sprintf('Fallback Message Preview (%s)', $fallbackCatalogue->getLocale());
}
$table->setHeaders($headers);

// Iterate all message ids and determine their state
foreach ($allMessages as $domain => $messages) {
foreach (array_keys($messages) as $messageId) {
$value = $currentCatalogue->get($messageId, $domain);
$states = array();

if ($extractedCatalogue->defines($messageId, $domain)) {
if (!$currentCatalogue->defines($messageId, $domain)) {
$states[] = self::MESSAGE_MISSING;
}
} elseif ($currentCatalogue->defines($messageId, $domain)) {
$states[] = self::MESSAGE_UNUSED;
}

if ($extractedCatalogue->defines($messageId, $domain)) {
if (!$currentCatalogue->defines($messageId, $domain)) {
$states[] = self::MESSAGE_MISSING;
if (!in_array(self::MESSAGE_UNUSED, $states) && true === $input->getOption('only-unused')
|| !in_array(self::MESSAGE_MISSING, $states) && true === $input->getOption('only-missing')) {
continue;
}
} elseif ($currentCatalogue->defines($messageId, $domain)) {
$states[] = self::MESSAGE_UNUSED;
}

if (!in_array(self::MESSAGE_UNUSED, $states) && true === $input->getOption('only-unused')
|| !in_array(self::MESSAGE_MISSING, $states) && true === $input->getOption('only-missing')) {
continue;
}
foreach ($fallbackCatalogues as $fallbackCatalogue) {
if ($fallbackCatalogue->defines($messageId, $domain) && $value === $fallbackCatalogue->get($messageId, $domain)) {
$states[] = self::MESSAGE_EQUALS_FALLBACK;

foreach ($fallbackCatalogues as $fallbackCatalogue) {
if ($fallbackCatalogue->defines($messageId, $domain) && $value === $fallbackCatalogue->get($messageId, $domain)) {
$states[] = self::MESSAGE_EQUALS_FALLBACK;
break;
}
}

break;
$row = array($this->formatStates($states), $domain, $this->formatId($messageId), $this->sanitizeString($value));
foreach ($fallbackCatalogues as $fallbackCatalogue) {
$row[] = $this->sanitizeString($fallbackCatalogue->get($messageId, $domain));
}
}

$row = array($this->formatStates($states), $domain, $this->formatId($messageId), $this->sanitizeString($value));
foreach ($fallbackCatalogues as $fallbackCatalogue) {
$row[] = $this->sanitizeString($fallbackCatalogue->get($messageId, $domain));
$table->addRow($row);
}

$table->addRow($row);
}
}

if (class_exists('Symfony\Component\Console\Helper\Table')) {
$table->render();
} else {
$table->render($output);
if (class_exists('Symfony\Component\Console\Helper\Table')) {
$table->render();
} else {
$table->render($output);
}
$output->writeln('');
}
}

Expand Down Expand Up @@ -263,4 +264,63 @@ private function sanitizeString($string, $length = 40)

return $string;
}

/**
* @param string $locale
* @param string $rootPath
*
* @return MessageCatalogue
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

white-line before return (you can use php-cs-fixer)

*/
private function extractMessages($locale, $rootPath)
{
$extractedCatalogue = new MessageCatalogue($locale);
if (is_dir($rootPath.'/Resources/views')) {
$this->getContainer()->get('translation.extractor')->extract($rootPath.'/Resources/views', $extractedCatalogue);
}

return $extractedCatalogue;
}

/**
* @param string $locale
* @param string $translationsPath
* @param TranslationLoader $loader
*
* @return MessageCatalogue
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

*/
private function loadCurrentMessages($locale, $translationsPath, TranslationLoader $loader)
{
$currentCatalogue = new MessageCatalogue($locale);
if (is_dir($translationsPath)) {
$loader->loadMessages($translationsPath, $currentCatalogue);
}

return $currentCatalogue;
}

/**
* @param string $locale
* @param string $translationsPath
* @param TranslationLoader $loader
*
* @return MessageCatalogue[]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

*/
private function loadFallbackCatalogues($locale, $translationsPath, TranslationLoader $loader)
{
$fallbackCatalogues = array();
$translator = $this->getContainer()->get('translator');
if ($translator instanceof Translator) {
foreach ($translator->getFallbackLocales() as $fallbackLocale) {
if ($fallbackLocale === $locale) {
continue;
}

$fallbackCatalogue = new MessageCatalogue($fallbackLocale);
$loader->loadMessages($translationsPath, $fallbackCatalogue);
$fallbackCatalogues[] = $fallbackCatalogue;
}
}

return $fallbackCatalogues;
}
}