diff --git a/Catalogue/CatalogueCounter.php b/Catalogue/CatalogueCounter.php index 205c4fe5..536861bc 100644 --- a/Catalogue/CatalogueCounter.php +++ b/Catalogue/CatalogueCounter.php @@ -64,6 +64,7 @@ public function getCatalogueStatistics(MessageCatalogueInterface $catalogue) foreach ($domains as $domain) { $result[$domain]['new'] = 0; $result[$domain]['obsolete'] = 0; + $result[$domain]['approved'] = 0; foreach ($catalogue->all($domain) as $key => $text) { $metadata = new Metadata($catalogue->getMetadata($key, $domain)); @@ -85,6 +86,7 @@ public function getCatalogueStatistics(MessageCatalogueInterface $catalogue) // Sum the number of new and obsolete messages. $result['_total']['new'] = 0; $result['_total']['obsolete'] = 0; + $result['_total']['approved'] = 0; foreach ($domains as $domain) { $result['_total']['new'] += $result[$domain]['new']; $result['_total']['obsolete'] += $result[$domain]['obsolete']; diff --git a/Catalogue/CatalogueWriter.php b/Catalogue/CatalogueWriter.php index 90c7e12e..59ea0aa1 100644 --- a/Catalogue/CatalogueWriter.php +++ b/Catalogue/CatalogueWriter.php @@ -59,6 +59,7 @@ public function writeCatalogues(Configuration $config, array $catalogues) [ 'path' => $config->getOutputDir(), 'default_locale' => $this->defaultLocale, + 'xliff_version' => $config->getXliffVersion(), ] ); } diff --git a/Catalogue/Operation/ReplaceOperation.php b/Catalogue/Operation/ReplaceOperation.php index 2e294e2e..ce9c298f 100644 --- a/Catalogue/Operation/ReplaceOperation.php +++ b/Catalogue/Operation/ReplaceOperation.php @@ -48,9 +48,15 @@ protected function processDomain($domain) } foreach ($sourceMessages as $id => $message) { - $this->messages[$domain]['all'][$id] = $message; + if (!empty($message)) { + $this->messages[$domain]['all'][$id] = $message; + } + if (!$this->target->has($id, $domain)) { $this->messages[$domain]['new'][$id] = $message; + + // Make sure to add it to the source if even if empty($message) + $this->messages[$domain]['all'][$id] = $message; } } diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index c22b00c8..c6eec9d1 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -158,7 +158,8 @@ private function configsNode(ArrayNodeDefinition $root) ->prototype('scalar')->end() ->end() ->scalarNode('output_dir')->cannotBeEmpty()->defaultValue('%kernel.root_dir%/Resources/translations')->end() - ->scalarNode('project_root')->info("The root dir of your project. By default this will be kernel_root's parent. ")->end() + ->scalarNode('project_root')->info("The root dir of your project. By default this will be kernel_root's parent.")->end() + ->scalarNode('xliff_version')->info('The version of XLIFF XML you want to use (if dumping to this format).')->defaultValue('2.0')->end() ->variableNode('local_file_storage_options') ->info('Options passed to the local file storage\'s dumper.') ->defaultValue([]) diff --git a/Model/Configuration.php b/Model/Configuration.php index bff1adde..512aaa34 100644 --- a/Model/Configuration.php +++ b/Model/Configuration.php @@ -87,6 +87,11 @@ final class Configuration */ private $whitelistDomains; + /** + * @var string + */ + private $xliffVersion; + /** * @param array $data */ @@ -103,6 +108,7 @@ public function __construct(array $data) $this->outputFormat = $data['output_format']; $this->blacklistDomains = $data['blacklist_domains']; $this->whitelistDomains = $data['whitelist_domains']; + $this->xliffVersion = $data['xliff_version']; } /** @@ -203,4 +209,12 @@ public function getPathsToTranslationFiles() { return array_merge($this->externalTranslationsDirs, [$this->getOutputDir()]); } + + /** + * @return string + */ + public function getXliffVersion() + { + return $this->xliffVersion; + } } diff --git a/Tests/Functional/Command/ExtractCommandTest.php b/Tests/Functional/Command/ExtractCommandTest.php new file mode 100644 index 00000000..cd9f4343 --- /dev/null +++ b/Tests/Functional/Command/ExtractCommandTest.php @@ -0,0 +1,107 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Translation\Bundle\Tests\Functional\Command; + +use Symfony\Bundle\FrameworkBundle\Console\Application; +use Symfony\Component\Console\Tester\CommandTester; +use Translation\Bundle\Command\ExtractCommand; +use Translation\Bundle\Model\Metadata; +use Translation\Bundle\Tests\Functional\BaseTestCase; + +class ExtractCommandTest extends BaseTestCase +{ + protected function setUp() + { + parent::setUp(); + $this->kernel->addConfigFile(__DIR__.'/../app/config/normal_config.yml'); + + file_put_contents(__DIR__.'/../app/Resources/translations/messages.sv.xlf', <<<'XML' + + + + + + translated.heading + My translated heading + + + + + translated.paragraph0 + My translated paragraph0 + + + + + foobar.html.twig:9 + + + translated.paragraph1 + My translated paragraph1 + + + + + not.in.source + This is not in the source code + + + + + +XML + ); + } + + public function testExecute() + { + $this->bootKernel(); + $application = new Application($this->kernel); + + $application->add(new ExtractCommand()); + + $command = $application->find('translation:extract'); + $commandTester = new CommandTester($command); + $commandTester->execute([ + 'command' => $command->getName(), + 'configuration' => 'app', + 'locale' => 'sv', + ]); + + // the output of the command in the console + $output = $commandTester->getDisplay(); + + // Make sure we have 4 new messages + $this->assertRegExp('|New messages +4|s', $output); + $this->assertRegExp('|Total defined messages +8|s', $output); + + $container = $this->getContainer(); + $config = $container->get('php_translation.configuration_manager')->getConfiguration('app'); + $catalogues = $container->get('php_translation.catalogue_fetcher')->getCatalogues($config, ['sv']); + + $catalogue = $catalogues[0]; + $this->assertEquals('My translated heading', $catalogue->get('translated.heading'), 'Translated strings MUST NOT disappear.'); + + // Test meta, source-location + $meta = new Metadata($catalogue->getMetadata('translated.paragraph1')); + $this->assertFalse($meta->getState() === 'new'); + foreach ($meta->getSourceLocations() as $sourceLocation) { + $this->assertNotEquals('foobar.html.twig', $sourceLocation['path']); + } + + $meta = new Metadata($catalogue->getMetadata('not.in.source')); + $this->assertTrue($meta->getState() === 'obsolete'); + + $meta = new Metadata($catalogue->getMetadata('translated.title')); + $this->assertTrue($meta->getState() === 'new'); + } +} diff --git a/Tests/Functional/Command/StatusCommandTest.php b/Tests/Functional/Command/StatusCommandTest.php new file mode 100644 index 00000000..36b32b1a --- /dev/null +++ b/Tests/Functional/Command/StatusCommandTest.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Translation\Bundle\Tests\Functional\Command; + +use Symfony\Bundle\FrameworkBundle\Console\Application; +use Symfony\Component\Console\Tester\CommandTester; +use Translation\Bundle\Command\StatusCommand; +use Translation\Bundle\Tests\Functional\BaseTestCase; + +class StatusCommandTest extends BaseTestCase +{ + protected function setUp() + { + parent::setUp(); + $this->kernel->addConfigFile(__DIR__.'/../app/config/normal_config.yml'); + } + + public function testExecute() + { + $this->bootKernel(); + $application = new Application($this->kernel); + + $application->add(new StatusCommand()); + + $command = $application->find('translation:status'); + $commandTester = new CommandTester($command); + $commandTester->execute([ + 'command' => $command->getName(), + 'configuration' => 'app', + 'locale' => 'en', + '--json' => true, + ]); + + // the output of the command in the console + $output = $commandTester->getDisplay(); + $data = json_decode($output, true); + + $this->assertArrayHasKey('en', $data); + $this->assertArrayHasKey('messages', $data['en']); + $this->assertArrayHasKey('_total', $data['en']); + + $total = $data['en']['_total']; + $this->assertArrayHasKey('defined', $total); + $this->assertArrayHasKey('new', $total); + $this->assertArrayHasKey('obsolete', $total); + $this->assertArrayHasKey('approved', $total); + $this->assertEquals(2, $total['defined']); + $this->assertEquals(1, $total['new']); + $this->assertEquals(0, $total['obsolete']); + $this->assertEquals(1, $total['approved']); + } +} diff --git a/Tests/Functional/app/Resources/translations/.gitignore b/Tests/Functional/app/Resources/translations/.gitignore index cd4f20e6..1351b683 100644 --- a/Tests/Functional/app/Resources/translations/.gitignore +++ b/Tests/Functional/app/Resources/translations/.gitignore @@ -1 +1,2 @@ messages.sv.xlf +*~ diff --git a/Tests/Functional/app/config/normal_config.yml b/Tests/Functional/app/config/normal_config.yml index a6bdd8e1..01f5a04f 100644 --- a/Tests/Functional/app/config/normal_config.yml +++ b/Tests/Functional/app/config/normal_config.yml @@ -8,3 +8,4 @@ translation: app: dirs: ["%test.root_dir%/Resources/views"] output_dir: "%test.root_dir%/Resources/translations" + project_root: "%test.root_dir%" diff --git a/Tests/Unit/Model/ConfigurationTest.php b/Tests/Unit/Model/ConfigurationTest.php index 9f7b92fb..cd8f3f1b 100644 --- a/Tests/Unit/Model/ConfigurationTest.php +++ b/Tests/Unit/Model/ConfigurationTest.php @@ -58,6 +58,7 @@ public static function getDefaultData() 'output_format' => 'getOutputFormat', 'blacklist_domains' => ['getBlacklistDomains'], 'whitelist_domains' => ['getWhitelistDomains'], + 'xliff_version' => ['getXliffVersion'], ]; } } diff --git a/composer.json b/composer.json index d7713c34..741bf94b 100644 --- a/composer.json +++ b/composer.json @@ -27,6 +27,7 @@ "php-http/curl-client": "^1.7", "php-http/message": "^1.6", "php-http/message-factory": "^1.0.2", + "symfony/console": "^2.7 || ^3.0", "symfony/twig-bundle": "^2.7 || ^3.0", "symfony/twig-bridge": "^2.7 || ^3.0", "symfony/asset": "^2.7 || ^3.0",