diff --git a/src/Symfony/Component/Translation/CHANGELOG.md b/src/Symfony/Component/Translation/CHANGELOG.md index d82c37d38090c..a2051ca50c955 100644 --- a/src/Symfony/Component/Translation/CHANGELOG.md +++ b/src/Symfony/Component/Translation/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG --- * Give current locale to `LocaleSwitcher::runWithLocale()`'s callback + * Add `--as-tree` option to `translation:pull` command to write YAML messages as a tree-like structure 6.3 --- diff --git a/src/Symfony/Component/Translation/Command/TranslationPullCommand.php b/src/Symfony/Component/Translation/Command/TranslationPullCommand.php index 646b92c83243b..5d9c092c389d2 100644 --- a/src/Symfony/Component/Translation/Command/TranslationPullCommand.php +++ b/src/Symfony/Component/Translation/Command/TranslationPullCommand.php @@ -95,6 +95,7 @@ protected function configure(): void new InputOption('domains', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Specify the domains to pull.'), new InputOption('locales', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Specify the locales to pull.'), new InputOption('format', null, InputOption::VALUE_OPTIONAL, 'Override the default output format.', 'xlf12'), + new InputOption('as-tree', null, InputOption::VALUE_OPTIONAL, 'Write messages as a tree-like structure. Needs --format=yaml. The given value defines the level where to switch to inline YAML'), ]) ->setHelp(<<<'EOF' The %command.name% command pulls translations from the given provider. Only @@ -126,6 +127,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $locales = $input->getOption('locales') ?: $this->enabledLocales; $domains = $input->getOption('domains'); $format = $input->getOption('format'); + $asTree = (int) $input->getOption('as-tree'); $xliffVersion = '1.2'; if ($intlIcu && !$force) { @@ -142,6 +144,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int 'path' => end($this->transPaths), 'xliff_version' => $xliffVersion, 'default_locale' => $this->defaultLocale, + 'as_tree' => (bool) $asTree, + 'inline' => $asTree, ]; if (!$domains) { diff --git a/src/Symfony/Component/Translation/Tests/Command/TranslationProviderTestCase.php b/src/Symfony/Component/Translation/Tests/Command/TranslationProviderTestCase.php index e6488f61ea9f2..33775b5ff9817 100644 --- a/src/Symfony/Component/Translation/Tests/Command/TranslationProviderTestCase.php +++ b/src/Symfony/Component/Translation/Tests/Command/TranslationProviderTestCase.php @@ -55,6 +55,22 @@ protected function getProviderCollection(ProviderInterface $provider, array $pro return new TranslationProviderCollection($collection); } + protected function createYamlFile(array $messages = ['node' => 'NOTE'], $targetLanguage = 'en', $fileNamePattern = 'messages.%locale%.yml'): string + { + $yamlContent = ''; + foreach ($messages as $key => $value) { + $yamlContent .= "$key: $value\n"; + } + $yamlContent .= "\n"; + + $filename = sprintf('%s/%s', $this->translationAppDir.'/translations', str_replace('%locale%', $targetLanguage, $fileNamePattern)); + file_put_contents($filename, $yamlContent); + + $this->files[] = $filename; + + return $filename; + } + protected function createFile(array $messages = ['note' => 'NOTE'], $targetLanguage = 'en', $fileNamePattern = 'messages.%locale%.xlf', string $xlfVersion = 'xlf12'): string { if ('xlf12' === $xlfVersion) { diff --git a/src/Symfony/Component/Translation/Tests/Command/TranslationPullCommandTest.php b/src/Symfony/Component/Translation/Tests/Command/TranslationPullCommandTest.php index 6587a8c71b210..c753495f9ddd7 100644 --- a/src/Symfony/Component/Translation/Tests/Command/TranslationPullCommandTest.php +++ b/src/Symfony/Component/Translation/Tests/Command/TranslationPullCommandTest.php @@ -16,8 +16,10 @@ use Symfony\Component\Console\Tester\CommandTester; use Symfony\Component\Translation\Command\TranslationPullCommand; use Symfony\Component\Translation\Dumper\XliffFileDumper; +use Symfony\Component\Translation\Dumper\YamlFileDumper; use Symfony\Component\Translation\Loader\ArrayLoader; use Symfony\Component\Translation\Loader\XliffFileLoader; +use Symfony\Component\Translation\Loader\YamlFileLoader; use Symfony\Component\Translation\Provider\ProviderInterface; use Symfony\Component\Translation\Reader\TranslationReader; use Symfony\Component\Translation\TranslatorBag; @@ -235,6 +237,96 @@ public function testPullNewXlf20Messages() , file_get_contents($filenameFr)); } + public function testPullNewYamlMessagesAsInlined() + { + $arrayLoader = new ArrayLoader(); + $filenameEn = $this->createYamlFile(['note' => 'NOTE'], 'en', 'messages.%locale%.yml'); + $filenameFr = $this->createYamlFile(['note' => 'NOTE'], 'fr', 'messages.%locale%.yml'); + $locales = ['en', 'fr']; + $domains = ['messages']; + + $providerReadTranslatorBag = new TranslatorBag(); + $providerReadTranslatorBag->addCatalogue($arrayLoader->load([ + 'note' => 'NOTE', + 'new.foo' => 'newFoo', + ], 'en')); + $providerReadTranslatorBag->addCatalogue($arrayLoader->load([ + 'note' => 'NOTE', + 'new.foo' => 'nouveauFoo', + ], 'fr')); + + $provider = $this->createMock(ProviderInterface::class); + $provider->expects($this->once()) + ->method('read') + ->with($domains, $locales) + ->willReturn($providerReadTranslatorBag); + + $provider->expects($this->once()) + ->method('__toString') + ->willReturn('null://default'); + + $tester = $this->createCommandTester($provider, $locales, $domains); + $tester->execute(['--locales' => ['en', 'fr'], '--domains' => ['messages'], '--format' => 'yml']); + + $this->assertStringContainsString('[OK] New translations from "null" has been written locally (for "en, fr" locale(s), and "messages" domain(s)).', trim($tester->getDisplay())); + $this->assertEquals(<<assertEquals(<<createYamlFile(['note' => 'NOTE'], 'en', 'messages.%locale%.yml'); + $filenameFr = $this->createYamlFile(['note' => 'NOTE'], 'fr', 'messages.%locale%.yml'); + $locales = ['en', 'fr']; + $domains = ['messages']; + + $providerReadTranslatorBag = new TranslatorBag(); + $providerReadTranslatorBag->addCatalogue($arrayLoader->load([ + 'note' => 'NOTE', + 'new.foo' => 'newFoo', + ], 'en')); + $providerReadTranslatorBag->addCatalogue($arrayLoader->load([ + 'note' => 'NOTE', + 'new.foo' => 'nouveauFoo', + ], 'fr')); + + $provider = $this->createMock(ProviderInterface::class); + $provider->expects($this->once()) + ->method('read') + ->with($domains, $locales) + ->willReturn($providerReadTranslatorBag); + + $provider->expects($this->once()) + ->method('__toString') + ->willReturn('null://default'); + + $tester = $this->createCommandTester($provider, $locales, $domains); + $tester->execute(['--locales' => ['en', 'fr'], '--domains' => ['messages'], '--format' => 'yml', '--as-tree' => 10]); + + $this->assertStringContainsString('[OK] New translations from "null" has been written locally (for "en, fr" locale(s), and "messages" domain(s)).', trim($tester->getDisplay())); + $this->assertEquals(<<assertEquals(<<addDumper('xlf', new XliffFileDumper()); + $writer->addDumper('yml', new YamlFileDumper()); $reader = new TranslationReader(); $reader->addLoader('xlf', new XliffFileLoader()); + $reader->addLoader('yml', new YamlFileLoader()); return new TranslationPullCommand( $this->getProviderCollection($provider, $providerNames, $locales, $domains),