123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 |
- <?php
- /*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
- namespace Symfony\Bundle\FrameworkBundle\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\Console\Style\SymfonyStyle;
- use Symfony\Component\Translation\Catalogue\MergeOperation;
- use Symfony\Component\Translation\Catalogue\TargetOperation;
- use Symfony\Component\Translation\MessageCatalogue;
- /**
- * A command that parses templates to extract translation messages and adds them
- * into the translation files.
- *
- * @author Michel Salib <michelsalib@hotmail.com>
- */
- class TranslationUpdateCommand extends ContainerAwareCommand
- {
- /**
- * {@inheritdoc}
- */
- protected function configure()
- {
- $this
- ->setName('translation:update')
- ->setDefinition(array(
- new InputArgument('locale', InputArgument::REQUIRED, 'The locale'),
- new InputArgument('bundle', InputArgument::OPTIONAL, 'The bundle name or directory where to load the messages, defaults to app/Resources folder'),
- new InputOption('prefix', null, InputOption::VALUE_OPTIONAL, 'Override the default prefix', '__'),
- new InputOption('output-format', null, InputOption::VALUE_OPTIONAL, 'Override the default output format', 'yml'),
- new InputOption('dump-messages', null, InputOption::VALUE_NONE, 'Should the messages be dumped in the console'),
- new InputOption('force', null, InputOption::VALUE_NONE, 'Should the update be done'),
- new InputOption('no-backup', null, InputOption::VALUE_NONE, 'Should backup be disabled'),
- new InputOption('clean', null, InputOption::VALUE_NONE, 'Should clean not found messages'),
- ))
- ->setDescription('Updates the translation file')
- ->setHelp(<<<'EOF'
- The <info>%command.name%</info> command extracts translation strings from templates
- of a given bundle or the app folder. It can display them or merge the new ones into the translation files.
- When new translation strings are found it can automatically add a prefix to the translation
- message.
- Example running against a Bundle (AcmeBundle)
- <info>php %command.full_name% --dump-messages en AcmeBundle</info>
- <info>php %command.full_name% --force --prefix="new_" fr AcmeBundle</info>
- Example running against app messages (app/Resources folder)
- <info>php %command.full_name% --dump-messages en</info>
- <info>php %command.full_name% --force --prefix="new_" fr</info>
- EOF
- )
- ;
- }
- /**
- * {@inheritdoc}
- */
- protected function execute(InputInterface $input, OutputInterface $output)
- {
- $io = new SymfonyStyle($input, $output);
- // check presence of force or dump-message
- if (true !== $input->getOption('force') && true !== $input->getOption('dump-messages')) {
- $io->error('You must choose one of --force or --dump-messages');
- return 1;
- }
- // check format
- $writer = $this->getContainer()->get('translation.writer');
- $supportedFormats = $writer->getFormats();
- if (!\in_array($input->getOption('output-format'), $supportedFormats)) {
- $io->error(array('Wrong output format', 'Supported formats are: '.implode(', ', $supportedFormats).'.'));
- return 1;
- }
- $kernel = $this->getContainer()->get('kernel');
- // Define Root Path to App folder
- $transPaths = array($kernel->getRootDir().'/Resources/');
- $currentName = 'app folder';
- // Override with provided Bundle info
- if (null !== $input->getArgument('bundle')) {
- try {
- $foundBundle = $kernel->getBundle($input->getArgument('bundle'));
- $transPaths = array(
- $foundBundle->getPath().'/Resources/',
- sprintf('%s/Resources/%s/', $kernel->getRootDir(), $foundBundle->getName()),
- );
- $currentName = $foundBundle->getName();
- } catch (\InvalidArgumentException $e) {
- // such a bundle does not exist, so treat the argument as path
- $transPaths = array($input->getArgument('bundle').'/Resources/');
- $currentName = $transPaths[0];
- if (!is_dir($transPaths[0])) {
- throw new \InvalidArgumentException(sprintf('"%s" is neither an enabled bundle nor a directory.', $transPaths[0]));
- }
- }
- }
- $io->title('Translation Messages Extractor and Dumper');
- $io->comment(sprintf('Generating "<info>%s</info>" translation files for "<info>%s</info>"', $input->getArgument('locale'), $currentName));
- // load any messages from templates
- $extractedCatalogue = new MessageCatalogue($input->getArgument('locale'));
- $io->comment('Parsing templates...');
- $extractor = $this->getContainer()->get('translation.extractor');
- $extractor->setPrefix($input->getOption('prefix'));
- foreach ($transPaths as $path) {
- $path .= 'views';
- if (is_dir($path)) {
- $extractor->extract($path, $extractedCatalogue);
- }
- }
- // load any existing messages from the translation files
- $currentCatalogue = new MessageCatalogue($input->getArgument('locale'));
- $io->comment('Loading translation files...');
- $loader = $this->getContainer()->get('translation.loader');
- foreach ($transPaths as $path) {
- $path .= 'translations';
- if (is_dir($path)) {
- $loader->loadMessages($path, $currentCatalogue);
- }
- }
- // process catalogues
- $operation = $input->getOption('clean')
- ? new TargetOperation($currentCatalogue, $extractedCatalogue)
- : new MergeOperation($currentCatalogue, $extractedCatalogue);
- // Exit if no messages found.
- if (!\count($operation->getDomains())) {
- $io->warning('No translation messages were found.');
- return;
- }
- $resultMessage = 'Translation files were successfully updated';
- // show compiled list of messages
- if (true === $input->getOption('dump-messages')) {
- $extractedMessagesCount = 0;
- $io->newLine();
- foreach ($operation->getDomains() as $domain) {
- $newKeys = array_keys($operation->getNewMessages($domain));
- $allKeys = array_keys($operation->getMessages($domain));
- $list = array_merge(
- array_diff($allKeys, $newKeys),
- array_map(function ($id) {
- return sprintf('<fg=green>%s</>', $id);
- }, $newKeys),
- array_map(function ($id) {
- return sprintf('<fg=red>%s</>', $id);
- }, array_keys($operation->getObsoleteMessages($domain)))
- );
- $domainMessagesCount = \count($list);
- $io->section(sprintf('Messages extracted for domain "<info>%s</info>" (%d message%s)', $domain, $domainMessagesCount, $domainMessagesCount > 1 ? 's' : ''));
- $io->listing($list);
- $extractedMessagesCount += $domainMessagesCount;
- }
- if ('xlf' == $input->getOption('output-format')) {
- $io->comment('Xliff output version is <info>1.2</info>');
- }
- $resultMessage = sprintf('%d message%s successfully extracted', $extractedMessagesCount, $extractedMessagesCount > 1 ? 's were' : ' was');
- }
- if (true === $input->getOption('no-backup')) {
- $writer->disableBackup();
- }
- // save the files
- if (true === $input->getOption('force')) {
- $io->comment('Writing files...');
- $bundleTransPath = false;
- foreach ($transPaths as $path) {
- $path .= 'translations';
- if (is_dir($path)) {
- $bundleTransPath = $path;
- }
- }
- if (!$bundleTransPath) {
- $bundleTransPath = end($transPaths).'translations';
- }
- $writer->writeTranslations($operation->getResult(), $input->getOption('output-format'), array('path' => $bundleTransPath, 'default_locale' => $this->getContainer()->getParameter('kernel.default_locale')));
- if (true === $input->getOption('dump-messages')) {
- $resultMessage .= ' and translation files were updated';
- }
- }
- $io->success($resultMessage.'.');
- }
- }
|