| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 |
- <?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\Component\Translation\Command;
- use Symfony\Component\Console\Attribute\AsCommand;
- use Symfony\Component\Console\Command\Command;
- use Symfony\Component\Console\Completion\CompletionInput;
- use Symfony\Component\Console\Completion\CompletionSuggestions;
- 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\Exception\ExceptionInterface;
- use Symfony\Component\Translation\TranslatorBagInterface;
- use Symfony\Contracts\Translation\TranslatorInterface;
- /**
- * Lint translations files syntax and outputs encountered errors.
- *
- * @author Hugo Alliaume <hugo@alliau.me>
- */
- #[AsCommand(name: 'lint:translations', description: 'Lint translations files syntax and outputs encountered errors')]
- class TranslationLintCommand extends Command
- {
- private SymfonyStyle $io;
- public function __construct(
- private TranslatorInterface&TranslatorBagInterface $translator,
- private array $enabledLocales = [],
- ) {
- parent::__construct();
- }
- public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
- {
- if ($input->mustSuggestOptionValuesFor('locale')) {
- $suggestions->suggestValues($this->enabledLocales);
- }
- }
- protected function configure(): void
- {
- $this
- ->setDefinition([
- new InputOption('locale', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Specify the locales to lint.', $this->enabledLocales),
- ])
- ->setHelp(<<<'EOF'
- The <info>%command.name%</> command lint translations.
- <info>php %command.full_name%</>
- EOF
- );
- }
- protected function initialize(InputInterface $input, OutputInterface $output): void
- {
- $this->io = new SymfonyStyle($input, $output);
- }
- protected function execute(InputInterface $input, OutputInterface $output): int
- {
- $locales = $input->getOption('locale');
- /** @var array<string, array<string, array<string, \Throwable>> $errors */
- $errors = [];
- $domainsByLocales = [];
- foreach ($locales as $locale) {
- $messageCatalogue = $this->translator->getCatalogue($locale);
- foreach ($domainsByLocales[$locale] = $messageCatalogue->getDomains() as $domain) {
- foreach ($messageCatalogue->all($domain) as $id => $translation) {
- try {
- $this->translator->trans($id, [], $domain, $messageCatalogue->getLocale());
- } catch (ExceptionInterface $e) {
- $errors[$locale][$domain][$id] = $e;
- }
- }
- }
- }
- if (!$domainsByLocales) {
- $this->io->error('No translation files were found.');
- return Command::SUCCESS;
- }
- $this->io->table(
- ['Locale', 'Domains', 'Valid?'],
- array_map(
- static fn (string $locale, array $domains) => [
- $locale,
- implode(', ', $domains),
- !\array_key_exists($locale, $errors) ? '<info>Yes</>' : '<error>No</>',
- ],
- array_keys($domainsByLocales),
- $domainsByLocales
- ),
- );
- if ($errors) {
- foreach ($errors as $locale => $domains) {
- foreach ($domains as $domain => $domainsErrors) {
- $this->io->section(\sprintf('Errors for locale "%s" and domain "%s"', $locale, $domain));
- foreach ($domainsErrors as $id => $error) {
- $this->io->text(\sprintf('Translation key "%s" is invalid:', $id));
- $this->io->error($error->getMessage());
- }
- }
- }
- return Command::FAILURE;
- }
- $this->io->success('All translations are valid.');
- return Command::SUCCESS;
- }
- }
|