diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php index bf2c0ec8fd179..028bc8778758c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php @@ -87,7 +87,7 @@ protected function configure(): void new InputOption('force', null, InputOption::VALUE_NONE, 'Should the extract be done'), new InputOption('clean', null, InputOption::VALUE_NONE, 'Should clean not found messages'), new InputOption('domain', null, InputOption::VALUE_OPTIONAL, 'Specify the domain to extract'), - new InputOption('sort', null, InputOption::VALUE_OPTIONAL, 'Return list of messages sorted alphabetically (only works with --dump-messages)', 'asc'), + new InputOption('sort', null, InputOption::VALUE_OPTIONAL, 'Return list of messages sorted alphabetically'), new InputOption('as-tree', null, InputOption::VALUE_OPTIONAL, 'Dump the messages as a tree-like structure: The given value defines the level where to switch to inline YAML'), ]) ->setHelp(<<<'EOF' @@ -116,6 +116,7 @@ protected function configure(): void You can dump a tree-like structure using the yaml format with --as-tree flag: php %command.full_name% --force --format=yaml --as-tree=3 en AcmeBundle + php %command.full_name% --force --format=yaml --sort=asc --as-tree=3 fr EOF ) @@ -234,19 +235,22 @@ protected function execute(InputInterface $input, OutputInterface $output): int $domainMessagesCount = \count($list); - if ($sort = $input->getOption('sort')) { - $sort = strtolower($sort); - if (!\in_array($sort, self::SORT_ORDERS, true)) { - $errorIo->error(['Wrong sort order', 'Supported formats are: '.implode(', ', self::SORT_ORDERS).'.']); + $sort = $input->getOption('sort'); + if (null === $sort) { + $sort = 'asc'; + } + + $sort = strtolower($sort); + if (!\in_array($sort, self::SORT_ORDERS, true)) { + $errorIo->error(['Wrong sort order', 'Supported formats are: '.implode(', ', self::SORT_ORDERS).'.']); - return 1; - } + return 1; + } - if (self::DESC === $sort) { - rsort($list); - } else { - sort($list); - } + if (self::DESC === $sort) { + rsort($list); + } else { + sort($list); } $io->section(sprintf('Messages extracted for domain "%s" (%d message%s)', $domain, $domainMessagesCount, $domainMessagesCount > 1 ? 's' : '')); @@ -277,7 +281,14 @@ protected function execute(InputInterface $input, OutputInterface $output): int $bundleTransPath = end($transPaths); } - $this->writer->write($operation->getResult(), $format, ['path' => $bundleTransPath, 'default_locale' => $this->defaultLocale, 'xliff_version' => $xliffVersion, 'as_tree' => $input->getOption('as-tree'), 'inline' => $input->getOption('as-tree') ?? 0]); + $this->writer->write($operation->getResult(), $format, [ + 'path' => $bundleTransPath, + 'default_locale' => $this->defaultLocale, + 'xliff_version' => $xliffVersion, + 'as_tree' => $input->getOption('as-tree'), + 'inline' => $input->getOption('as-tree') ?? 0, + 'sort' => $input->getOption('sort'), + ]); if (true === $input->getOption('dump-messages')) { $resultMessage .= ' and translation files were updated'; diff --git a/src/Symfony/Component/Translation/Dumper/CsvFileDumper.php b/src/Symfony/Component/Translation/Dumper/CsvFileDumper.php index 60b7441133770..dc8e04d35df67 100644 --- a/src/Symfony/Component/Translation/Dumper/CsvFileDumper.php +++ b/src/Symfony/Component/Translation/Dumper/CsvFileDumper.php @@ -27,7 +27,9 @@ public function formatCatalogue(MessageCatalogue $messages, string $domain, arra { $handle = fopen('php://memory', 'r+'); - foreach ($messages->all($domain) as $source => $target) { + $sort = $options['sort'] ?? null; + + foreach ($messages->all($domain, $sort) as $source => $target) { fputcsv($handle, [$source, $target], $this->delimiter, $this->enclosure); } diff --git a/src/Symfony/Component/Translation/Dumper/FileDumper.php b/src/Symfony/Component/Translation/Dumper/FileDumper.php index 3846e7380da5f..b6b9b29a0a7ad 100644 --- a/src/Symfony/Component/Translation/Dumper/FileDumper.php +++ b/src/Symfony/Component/Translation/Dumper/FileDumper.php @@ -44,6 +44,8 @@ public function dump(MessageCatalogue $messages, array $options = []): void throw new InvalidArgumentException('The file dumper needs a path option.'); } + $sort = $options['sort'] ?? null; + // save a file for each domain foreach ($messages->getDomains() as $domain) { $fullpath = $options['path'].'/'.$this->getRelativePath($domain, $messages->getLocale()); @@ -55,7 +57,7 @@ public function dump(MessageCatalogue $messages, array $options = []): void } $intlDomain = $domain.MessageCatalogue::INTL_DOMAIN_SUFFIX; - $intlMessages = $messages->all($intlDomain); + $intlMessages = $messages->all($intlDomain, $sort); if ($intlMessages) { $intlPath = $options['path'].'/'.$this->getRelativePath($intlDomain, $messages->getLocale()); @@ -64,7 +66,7 @@ public function dump(MessageCatalogue $messages, array $options = []): void $messages->replace([], $intlDomain); try { - if ($messages->all($domain)) { + if ($messages->all($domain, $sort)) { file_put_contents($fullpath, $this->formatCatalogue($messages, $domain, $options)); } continue; diff --git a/src/Symfony/Component/Translation/Dumper/IcuResFileDumper.php b/src/Symfony/Component/Translation/Dumper/IcuResFileDumper.php index e603ee8c48c99..9e4a78cae5325 100644 --- a/src/Symfony/Component/Translation/Dumper/IcuResFileDumper.php +++ b/src/Symfony/Component/Translation/Dumper/IcuResFileDumper.php @@ -25,8 +25,9 @@ class IcuResFileDumper extends FileDumper public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string { $data = $indexes = $resources = ''; + $sort = $options['sort'] ?? null; - foreach ($messages->all($domain) as $source => $target) { + foreach ($messages->all($domain, $sort) as $source => $target) { $indexes .= pack('v', \strlen($data) + 28); $data .= $source."\0"; } @@ -35,7 +36,7 @@ public function formatCatalogue(MessageCatalogue $messages, string $domain, arra $keyTop = $this->getPosition($data); - foreach ($messages->all($domain) as $source => $target) { + foreach ($messages->all($domain, $sort) as $source => $target) { $resources .= pack('V', $this->getPosition($data)); $data .= pack('V', \strlen($target)) @@ -46,7 +47,7 @@ public function formatCatalogue(MessageCatalogue $messages, string $domain, arra $resOffset = $this->getPosition($data); - $data .= pack('v', \count($messages->all($domain))) + $data .= pack('v', \count($messages->all($domain, $sort))) .$indexes .$this->writePadding($data) .$resources diff --git a/src/Symfony/Component/Translation/Dumper/IniFileDumper.php b/src/Symfony/Component/Translation/Dumper/IniFileDumper.php index 6cbdef606761a..d44227a2d34db 100644 --- a/src/Symfony/Component/Translation/Dumper/IniFileDumper.php +++ b/src/Symfony/Component/Translation/Dumper/IniFileDumper.php @@ -24,7 +24,9 @@ public function formatCatalogue(MessageCatalogue $messages, string $domain, arra { $output = ''; - foreach ($messages->all($domain) as $source => $target) { + $sort = $options['sort'] ?? null; + + foreach ($messages->all($domain, $sort) as $source => $target) { $escapeTarget = str_replace('"', '\"', $target); $output .= $source.'="'.$escapeTarget."\"\n"; } diff --git a/src/Symfony/Component/Translation/Dumper/JsonFileDumper.php b/src/Symfony/Component/Translation/Dumper/JsonFileDumper.php index e5035397f7c6c..9ce20322ccf90 100644 --- a/src/Symfony/Component/Translation/Dumper/JsonFileDumper.php +++ b/src/Symfony/Component/Translation/Dumper/JsonFileDumper.php @@ -23,8 +23,9 @@ class JsonFileDumper extends FileDumper public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string { $flags = $options['json_encoding'] ?? \JSON_PRETTY_PRINT; + $sort = $options['sort'] ?? null; - return json_encode($messages->all($domain), $flags); + return json_encode($messages->all($domain, $sort), $flags); } protected function getExtension(): string diff --git a/src/Symfony/Component/Translation/Dumper/MoFileDumper.php b/src/Symfony/Component/Translation/Dumper/MoFileDumper.php index 9ded5f4ef3855..f65e1eb4ec750 100644 --- a/src/Symfony/Component/Translation/Dumper/MoFileDumper.php +++ b/src/Symfony/Component/Translation/Dumper/MoFileDumper.php @@ -27,7 +27,9 @@ public function formatCatalogue(MessageCatalogue $messages, string $domain, arra $offsets = []; $size = 0; - foreach ($messages->all($domain) as $source => $target) { + $sort = $options['sort'] ?? null; + + foreach ($messages->all($domain, $sort) as $source => $target) { $offsets[] = array_map('strlen', [$sources, $source, $targets, $target]); $sources .= "\0".$source; $targets .= "\0".$target; diff --git a/src/Symfony/Component/Translation/Dumper/PhpFileDumper.php b/src/Symfony/Component/Translation/Dumper/PhpFileDumper.php index 51e90665d75fa..72b367a1e01f7 100644 --- a/src/Symfony/Component/Translation/Dumper/PhpFileDumper.php +++ b/src/Symfony/Component/Translation/Dumper/PhpFileDumper.php @@ -22,7 +22,9 @@ class PhpFileDumper extends FileDumper { public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string { - return "all($domain), true).";\n"; + $sort = $options['sort'] ?? null; + + return "all($domain, $sort), true).";\n"; } protected function getExtension(): string diff --git a/src/Symfony/Component/Translation/Dumper/PoFileDumper.php b/src/Symfony/Component/Translation/Dumper/PoFileDumper.php index a2d0deb78153a..dfdb1d24728cb 100644 --- a/src/Symfony/Component/Translation/Dumper/PoFileDumper.php +++ b/src/Symfony/Component/Translation/Dumper/PoFileDumper.php @@ -29,8 +29,10 @@ public function formatCatalogue(MessageCatalogue $messages, string $domain, arra $output .= '"Language: '.$messages->getLocale().'\n"'."\n"; $output .= "\n"; + $sort = $options['sort'] ?? null; + $newLine = false; - foreach ($messages->all($domain) as $source => $target) { + foreach ($messages->all($domain, $sort) as $source => $target) { if ($newLine) { $output .= "\n"; } else { diff --git a/src/Symfony/Component/Translation/Dumper/QtFileDumper.php b/src/Symfony/Component/Translation/Dumper/QtFileDumper.php index 0373e9c109542..b145c447d9b1a 100644 --- a/src/Symfony/Component/Translation/Dumper/QtFileDumper.php +++ b/src/Symfony/Component/Translation/Dumper/QtFileDumper.php @@ -28,7 +28,9 @@ public function formatCatalogue(MessageCatalogue $messages, string $domain, arra $context = $ts->appendChild($dom->createElement('context')); $context->appendChild($dom->createElement('name', $domain)); - foreach ($messages->all($domain) as $source => $target) { + $sort = $options['sort'] ?? null; + + foreach ($messages->all($domain, $sort) as $source => $target) { $message = $context->appendChild($dom->createElement('message')); $metadata = $messages->getMetadata($source, $domain); if (isset($metadata['sources'])) { diff --git a/src/Symfony/Component/Translation/Dumper/XliffFileDumper.php b/src/Symfony/Component/Translation/Dumper/XliffFileDumper.php index 22f0227b9d52f..90b8540a14fa6 100644 --- a/src/Symfony/Component/Translation/Dumper/XliffFileDumper.php +++ b/src/Symfony/Component/Translation/Dumper/XliffFileDumper.php @@ -43,7 +43,7 @@ public function formatCatalogue(MessageCatalogue $messages, string $domain, arra return $this->dumpXliff1($defaultLocale, $messages, $domain, $options); } if ('2.0' === $xliffVersion) { - return $this->dumpXliff2($defaultLocale, $messages, $domain); + return $this->dumpXliff2($defaultLocale, $messages, $domain, $options); } throw new InvalidArgumentException(sprintf('No support implemented for dumping XLIFF version "%s".', $xliffVersion)); @@ -56,6 +56,8 @@ protected function getExtension(): string private function dumpXliff1(string $defaultLocale, MessageCatalogue $messages, ?string $domain, array $options = []): string { + $sort = $options['sort'] ?? null; + $toolInfo = ['tool-id' => 'symfony', 'tool-name' => 'Symfony']; if (\array_key_exists('tool_info', $options)) { $toolInfo = array_merge($toolInfo, $options['tool_info']); @@ -90,7 +92,7 @@ private function dumpXliff1(string $defaultLocale, MessageCatalogue $messages, ? } $xliffBody = $xliffFile->appendChild($dom->createElement('body')); - foreach ($messages->all($domain) as $source => $target) { + foreach ($messages->all($domain, $sort) as $source => $target) { $translation = $dom->createElement('trans-unit'); $translation->setAttribute('id', strtr(substr(base64_encode(hash('sha256', $source, true)), 0, 7), '/+', '._')); @@ -137,8 +139,10 @@ private function dumpXliff1(string $defaultLocale, MessageCatalogue $messages, ? return $dom->saveXML(); } - private function dumpXliff2(string $defaultLocale, MessageCatalogue $messages, ?string $domain): string + private function dumpXliff2(string $defaultLocale, MessageCatalogue $messages, ?string $domain, array $options = []): string { + $sort = $options['sort'] ?? null; + $dom = new \DOMDocument('1.0', 'utf-8'); $dom->formatOutput = true; @@ -165,7 +169,7 @@ private function dumpXliff2(string $defaultLocale, MessageCatalogue $messages, ? } } - foreach ($messages->all($domain) as $source => $target) { + foreach ($messages->all($domain, $sort) as $source => $target) { $translation = $dom->createElement('unit'); $translation->setAttribute('id', strtr(substr(base64_encode(hash('sha256', $source, true)), 0, 7), '/+', '._')); diff --git a/src/Symfony/Component/Translation/Dumper/YamlFileDumper.php b/src/Symfony/Component/Translation/Dumper/YamlFileDumper.php index d2670331e6602..fd942514b3934 100644 --- a/src/Symfony/Component/Translation/Dumper/YamlFileDumper.php +++ b/src/Symfony/Component/Translation/Dumper/YamlFileDumper.php @@ -36,7 +36,9 @@ public function formatCatalogue(MessageCatalogue $messages, string $domain, arra throw new LogicException('Dumping translations in the YAML format requires the Symfony Yaml component.'); } - $data = $messages->all($domain); + $sort = $options['sort'] ?? null; + + $data = $messages->all($domain, $sort); if (isset($options['as_tree']) && $options['as_tree']) { $data = ArrayConverter::expandToTree($data); diff --git a/src/Symfony/Component/Translation/MessageCatalogue.php b/src/Symfony/Component/Translation/MessageCatalogue.php index 1ae29ff5d9113..69e1e5a49e383 100644 --- a/src/Symfony/Component/Translation/MessageCatalogue.php +++ b/src/Symfony/Component/Translation/MessageCatalogue.php @@ -55,15 +55,25 @@ public function getDomains(): array return array_values($domains); } - public function all(string $domain = null): array + public function all(string $domain = null, ?string $sort = null): array { + $sort = $sort ? strtolower($sort) : null; + if (null !== $domain) { // skip messages merge if intl-icu requested explicitly if (str_ends_with($domain, self::INTL_DOMAIN_SUFFIX)) { - return $this->messages[$domain] ?? []; + $messages = $this->messages[$domain] ?? []; + } else { + $messages = ($this->messages[$domain.self::INTL_DOMAIN_SUFFIX] ?? []) + ($this->messages[$domain] ?? []); + } + + if ('desc' === $sort) { + krsort($messages); + } elseif ('asc' === $sort) { + ksort($messages); } - return ($this->messages[$domain.self::INTL_DOMAIN_SUFFIX] ?? []) + ($this->messages[$domain] ?? []); + return $messages; } $allMessages = []; @@ -71,10 +81,18 @@ public function all(string $domain = null): array foreach ($this->messages as $domain => $messages) { if (str_ends_with($domain, self::INTL_DOMAIN_SUFFIX)) { $domain = substr($domain, 0, -\strlen(self::INTL_DOMAIN_SUFFIX)); - $allMessages[$domain] = $messages + ($allMessages[$domain] ?? []); + $messages = $messages + ($allMessages[$domain] ?? []); } else { - $allMessages[$domain] = ($allMessages[$domain] ?? []) + $messages; + $messages = ($allMessages[$domain] ?? []) + $messages; } + + if ('desc' === $sort) { + krsort($messages); + } elseif ('asc' === $sort) { + ksort($messages); + } + + $allMessages[$domain] = $messages; } return $allMessages;