diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
index 3d6acb26a1368..3227eddc20e21 100644
--- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
+++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
@@ -20,6 +20,7 @@ CHANGELOG
* Add the ability to use an existing service as a lock/semaphore resource
* Add support for configuring multiple serializer instances via the configuration
* Add support for `SYMFONY_TRUSTED_PROXIES`, `SYMFONY_TRUSTED_HEADERS`, `SYMFONY_TRUST_X_SENDFILE_TYPE_HEADER` and `SYMFONY_TRUSTED_HOSTS` env vars
+ * Add `--no-fill` option to `translation:extract` command
7.1
---
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php
index 04f812146d167..b26d3f9ad20dd 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php
@@ -19,7 +19,6 @@
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
-use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\HttpKernel\KernelInterface;
@@ -49,6 +48,7 @@ class TranslationUpdateCommand extends Command
'xlf12' => ['xlf', '1.2'],
'xlf20' => ['xlf', '2.0'],
];
+ private const NO_FILL_PREFIX = "\0NoFill\0";
public function __construct(
private TranslationWriterInterface $writer,
@@ -71,6 +71,7 @@ protected function configure(): void
new InputArgument('locale', InputArgument::REQUIRED, 'The locale'),
new InputArgument('bundle', InputArgument::OPTIONAL, 'The bundle name or directory where to load the messages'),
new InputOption('prefix', null, InputOption::VALUE_OPTIONAL, 'Override the default prefix', '__'),
+ new InputOption('no-fill', null, InputOption::VALUE_NONE, 'Extract translation keys without filling in values'),
new InputOption('format', null, InputOption::VALUE_OPTIONAL, 'Override the default output format', 'xlf12'),
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 extract be done'),
@@ -85,7 +86,8 @@ protected function configure(): void
the new ones into the translation files.
When new translation strings are found it can automatically add a prefix to the translation
-message.
+message. However, if the --no-fill option is used, the --prefix
+option has no effect, since the translation values are left empty.
Example running against a Bundle (AcmeBundle)
@@ -113,9 +115,6 @@ protected function configure(): void
protected function execute(InputInterface $input, OutputInterface $output): int
{
- $io = new SymfonyStyle($input, $output);
- $errorIo = $output instanceof ConsoleOutputInterface ? new SymfonyStyle($input, $output->getErrorOutput()) : $io;
-
$io = new SymfonyStyle($input, $output);
$errorIo = $io->getErrorStyle();
@@ -181,7 +180,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$io->comment(\sprintf('Generating "%s" translation files for "%s"', $input->getArgument('locale'), $currentName));
$io->comment('Parsing templates...');
- $extractedCatalogue = $this->extractMessages($input->getArgument('locale'), $codePaths, $input->getOption('prefix'));
+ $prefix = $input->getOption('no-fill') ? self::NO_FILL_PREFIX : $input->getOption('prefix');
+ $extractedCatalogue = $this->extractMessages($input->getArgument('locale'), $codePaths, $prefix);
$io->comment('Loading translation files...');
$currentCatalogue = $this->loadCurrentMessages($input->getArgument('locale'), $transPaths);
@@ -271,6 +271,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$operationResult = $this->sortCatalogue($operationResult, $sort);
}
+ if (true === $input->getOption('no-fill')) {
+ $this->removeNoFillTranslations($operationResult);
+ }
+
$this->writer->write($operationResult, $format, ['path' => $bundleTransPath, 'default_locale' => $this->defaultLocale, 'xliff_version' => $xliffVersion, 'as_tree' => $input->getOption('as-tree'), 'inline' => $input->getOption('as-tree') ?? 0]);
if (true === $input->getOption('dump-messages')) {
@@ -485,4 +489,13 @@ private function getRootCodePaths(KernelInterface $kernel): array
return $codePaths;
}
+
+ private function removeNoFillTranslations(MessageCatalogueInterface $operation): void
+ {
+ foreach ($operation->all('messages') as $key => $message) {
+ if (str_starts_with($message, self::NO_FILL_PREFIX)) {
+ $operation->set($key, '', 'messages');
+ }
+ }
+ }
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandTest.php
index 2304e75addbef..3a1bd8e3788c8 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandTest.php
@@ -21,6 +21,7 @@
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\Translation\Extractor\ExtractorInterface;
use Symfony\Component\Translation\MessageCatalogue;
+use Symfony\Component\Translation\MessageCatalogueInterface;
use Symfony\Component\Translation\Reader\TranslationReader;
use Symfony\Component\Translation\Translator;
use Symfony\Component\Translation\Writer\TranslationWriter;
@@ -176,6 +177,45 @@ public function testFilterDuplicateTransPaths()
$this->assertEquals($expectedPaths, $filteredTransPaths);
}
+ /**
+ * @dataProvider removeNoFillProvider
+ */
+ public function testRemoveNoFillTranslationsMethod($noFillCounter, $messages)
+ {
+ // Preparing mock
+ $operation = $this->createMock(MessageCatalogueInterface::class);
+ $operation
+ ->method('all')
+ ->with('messages')
+ ->willReturn($messages);
+ $operation
+ ->expects($this->exactly($noFillCounter))
+ ->method('set');
+
+ // Calling private method
+ $translationUpdate = $this->createMock(TranslationUpdateCommand::class);
+ $reflection = new \ReflectionObject($translationUpdate);
+ $method = $reflection->getMethod('removeNoFillTranslations');
+ $method->invokeArgs($translationUpdate, [$operation]);
+ }
+
+ public function removeNoFillProvider(): array
+ {
+ return [
+ [0, []],
+ [0, ['foo' => 'foo', 'bar' => 'bar', 'baz' => 'baz']],
+ [0, ['foo' => "\0foo"]],
+ [0, ['foo' => "foo\0NoFill\0"]],
+ [0, ['foo' => "f\0NoFill\000"]],
+ [0, ['foo' => 'foo', 'bar' => 'bar']],
+ [1, ['foo' => "\0NoFill\0foo"]],
+ [1, ['foo' => "\0NoFill\0foo", 'bar' => 'bar']],
+ [1, ['foo' => 'foo', 'bar' => "\0NoFill\0bar"]],
+ [2, ['foo' => "\0NoFill\0foo", 'bar' => "\0NoFill\0bar"]],
+ [3, ['foo' => "\0NoFill\0foo", 'bar' => "\0NoFill\0bar", 'baz' => "\0NoFill\0baz"]],
+ ];
+ }
+
protected function setUp(): void
{
$this->fs = new Filesystem();