Skip to content

Commit 2b096c1

Browse files
committed
Introduce a translation:check command, to check the current translation status
1 parent 461a05a commit 2b096c1

File tree

3 files changed

+218
-0
lines changed

3 files changed

+218
-0
lines changed

Command/CheckCommand.php

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Translation\Bundle\Command;
5+
6+
use Symfony\Component\Console\Command\Command;
7+
use Symfony\Component\Console\Input\InputArgument;
8+
use Symfony\Component\Console\Input\InputInterface;
9+
use Symfony\Component\Console\Output\OutputInterface;
10+
use Symfony\Component\Console\Style\SymfonyStyle;
11+
use Symfony\Component\Finder\Finder;
12+
use Translation\Bundle\Catalogue\CatalogueCounter;
13+
use Translation\Bundle\Catalogue\CatalogueFetcher;
14+
use Translation\Bundle\Model\Configuration;
15+
use Translation\Bundle\Service\ConfigurationManager;
16+
use Translation\Bundle\Service\Importer;
17+
18+
final class CheckCommand extends Command
19+
{
20+
protected static $defaultName = 'translation:check';
21+
22+
/**
23+
* @var ConfigurationManager
24+
*/
25+
private $configurationManager;
26+
27+
/**
28+
* @var CatalogueFetcher
29+
*/
30+
private $catalogueFetcher;
31+
32+
/**
33+
* @var Importer
34+
*/
35+
private $importer;
36+
37+
/**
38+
* @var CatalogueCounter
39+
*/
40+
private $catalogueCounter;
41+
42+
public function __construct(
43+
ConfigurationManager $configurationManager,
44+
CatalogueFetcher $catalogueFetcher,
45+
Importer $importer,
46+
CatalogueCounter $catalogueCounter
47+
) {
48+
parent::__construct();
49+
50+
$this->configurationManager = $configurationManager;
51+
$this->catalogueFetcher = $catalogueFetcher;
52+
$this->importer = $importer;
53+
$this->catalogueCounter = $catalogueCounter;
54+
}
55+
56+
protected function configure(): void
57+
{
58+
$this
59+
->setName(self::$defaultName)
60+
->setDescription('Check that all translations for a given locale are extracted.')
61+
->addArgument('locale', InputArgument::REQUIRED, 'The locale to check')
62+
->addArgument('configuration', InputArgument::OPTIONAL, 'The configuration to use', 'default')
63+
;
64+
}
65+
66+
protected function execute(InputInterface $input, OutputInterface $output): int
67+
{
68+
$config = $this->configurationManager->getConfiguration($input->getArgument('configuration'));
69+
70+
$locale = $input->getArgument('locale');
71+
72+
$catalogues = $this->catalogueFetcher->getCatalogues($config, [$locale]);
73+
$finder = $this->getConfiguredFinder($config);
74+
75+
$result = $this->importer->extractToCatalogues(
76+
$finder,
77+
$catalogues,
78+
[
79+
'blacklist_domains' => $config->getBlacklistDomains(),
80+
'whitelist_domains' => $config->getWhitelistDomains(),
81+
'project_root' => $config->getProjectRoot(),
82+
]
83+
);
84+
85+
$definedBefore = $this->catalogueCounter->getNumberOfDefinedMessages($catalogues[0]);
86+
$definedAfter = $this->catalogueCounter->getNumberOfDefinedMessages($result->getMessageCatalogues()[0]);
87+
88+
$newMessages = $definedAfter - $definedBefore;
89+
90+
$io = new SymfonyStyle($input, $output);
91+
92+
if ($newMessages > 0) {
93+
$io->error(sprintf('%d new message(s) have been found, run bin/console translation:extract', $newMessages));
94+
95+
return 1;
96+
}
97+
98+
$io->success('No new translation messages');
99+
100+
return 0;
101+
}
102+
103+
private function getConfiguredFinder(Configuration $config): Finder
104+
{
105+
$finder = new Finder();
106+
$finder->in($config->getDirs());
107+
108+
foreach ($config->getExcludedDirs() as $exclude) {
109+
$finder->notPath($exclude);
110+
}
111+
112+
foreach ($config->getExcludedNames() as $exclude) {
113+
$finder->notName($exclude);
114+
}
115+
116+
return $finder;
117+
}
118+
}

Resources/config/console.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
11
services:
2+
Translation\Bundle\Command\CheckCommand:
3+
public: true
4+
arguments:
5+
- '@Translation\Bundle\Service\ConfigurationManager'
6+
- '@Translation\Bundle\Catalogue\CatalogueFetcher'
7+
- '@Translation\Bundle\Service\Importer'
8+
- '@Translation\Bundle\Catalogue\CatalogueCounter'
9+
tags:
10+
- { name: console.command, command: translation:check }
11+
212
Translation\Bundle\Command\DeleteObsoleteCommand:
313
public: true
414
arguments:
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Translation\Bundle\Tests\Functional\Command;
5+
6+
use Symfony\Bundle\FrameworkBundle\Console\Application;
7+
use Symfony\Component\Console\Tester\CommandTester;
8+
use Translation\Bundle\Tests\Functional\BaseTestCase;
9+
10+
class CheckCommandTest extends BaseTestCase
11+
{
12+
/**
13+
* @var Application
14+
*/
15+
private $application;
16+
17+
protected function setUp(): void
18+
{
19+
parent::setUp();
20+
21+
$this->kernel->addConfigFile(__DIR__.'/../app/config/normal_config.yaml');
22+
$this->bootKernel();
23+
$this->application = new Application($this->kernel);
24+
25+
\file_put_contents(__DIR__.'/../app/Resources/translations/messages.sv.xlf', <<<'XML'
26+
<?xml version="1.0" encoding="utf-8"?>
27+
<xliff xmlns="urn:oasis:names:tc:xliff:document:2.0" version="2.0" srcLang="en" trgLang="sv">
28+
<file id="messages.sv">
29+
<unit id="xx1">
30+
<segment>
31+
<source>translated.heading</source>
32+
<target>My translated heading</target>
33+
</segment>
34+
</unit>
35+
<unit id="xx2">
36+
<segment>
37+
<source>translated.paragraph0</source>
38+
<target>My translated paragraph0</target>
39+
</segment>
40+
</unit>
41+
<unit id="xx3">
42+
<notes>
43+
<note category="file-source" priority="1">foobar.html.twig:9</note>
44+
</notes>
45+
<segment>
46+
<source>translated.paragraph1</source>
47+
<target>My translated paragraph1</target>
48+
</segment>
49+
</unit>
50+
<unit id="xx4">
51+
<segment>
52+
<source>not.in.source</source>
53+
<target>This is not in the source code</target>
54+
</segment>
55+
</unit>
56+
</file>
57+
</xliff>
58+
XML
59+
);
60+
}
61+
62+
public function testReportsMissingTranslations(): void
63+
{
64+
$commandTester = new CommandTester($this->application->find('translation:check'));
65+
66+
$commandTester->execute(['locale' => 'sv', 'configuration' => 'app']);
67+
68+
$this->assertStringContainsString(
69+
'4 new message(s) have been found, run bin/console translation:extract',
70+
$commandTester->getDisplay()
71+
);
72+
$this->assertGreaterThan(0, $commandTester->getStatusCode());
73+
}
74+
75+
public function testReportsNoNewTranslationMessages(): void
76+
{
77+
// run translation:extract first, so all translations are extracted
78+
(new CommandTester($this->application->find('translation:extract')))->execute(['locale' => 'sv']);
79+
80+
$commandTester = new CommandTester($this->application->find('translation:check'));
81+
82+
$commandTester->execute(['locale' => 'sv', 'configuration' => 'app']);
83+
84+
$this->assertStringContainsString(
85+
'No new translation messages',
86+
$commandTester->getDisplay()
87+
);
88+
$this->assertSame(0, $commandTester->getStatusCode());
89+
}
90+
}

0 commit comments

Comments
 (0)