From b02036086b2d86be6dba55c9febc927f10c5659f Mon Sep 17 00:00:00 2001 From: Marek Snopkowski Date: Tue, 24 Aug 2021 13:10:36 +0200 Subject: [PATCH 01/28] Remove both "normal" and ICU domain from messages set https://github.com/php-translation/symfony-bundle/issues/300 --- Catalogue/CatalogueFetcher.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Catalogue/CatalogueFetcher.php b/Catalogue/CatalogueFetcher.php index 0ee5cf00..09298987 100644 --- a/Catalogue/CatalogueFetcher.php +++ b/Catalogue/CatalogueFetcher.php @@ -53,8 +53,8 @@ public function getCatalogues(Configuration $config, array $locales = []): array foreach ($currentCatalogue->getDomains() as $domain) { if (!$this->isValidDomain($config, $domain)) { - $messages = $currentCatalogue->all(); - unset($messages[$domain]); + $messages = NSA::getProperty($currentCatalogue, 'messages'); + unset($messages[$domain], $messages[$domain . '+intl-icu' /* MessageCatalogueInterface::INTL_DOMAIN_SUFFIX */]); NSA::setProperty($currentCatalogue, 'messages', $messages); } } From d4c78c2747e79cd8e61dbede0dce0d9755b96ff9 Mon Sep 17 00:00:00 2001 From: Marek Snopkowski Date: Tue, 24 Aug 2021 13:11:36 +0200 Subject: [PATCH 02/28] Add new configuration for new message format It will allow us to control if we want to use new ICU format (with suffixed domain with "+intl-icu") or format. Configuration has normalizer (making sure string is in lower case) and validator (making sure it's a string and either "" or "icu"). Setting `new_message_format: ""` we'll end up with new translations in container like: {domain}.{locale}.{ext}. Setting `new_message_format: "icu"` we'll end up with new translations in container like: {domain}+intl-icu.{locale}.{ext}. https://github.com/php-translation/symfony-bundle/issues/300 --- DependencyInjection/Configuration.php | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index da7753b4..3a0feac1 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -164,6 +164,28 @@ private function configsNode(ArrayNodeDefinition $root): void ->scalarNode('output_dir')->cannotBeEmpty()->defaultValue('%kernel.project_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('xliff_version')->info('The version of XLIFF XML you want to use (if dumping to this format).')->defaultValue('2.0')->end() + ->scalarNode('new_message_format') + ->info('Use "icu" to place new translations in "{domain}+intl-icu.{locale}.{ext}" container') + ->defaultValue('icu') + ->beforeNormalization() + ->ifTrue( + function ($format) { + return \is_string($format); + } + ) + ->then( + function (string $format) { + return \strtolower($format); + } + ) + ->end() + ->validate() + ->ifTrue(function ($value) { + return !\is_string($value) || !\in_array($value, ['', 'icu']); + }) + ->thenInvalid('The "new_message_format" must be either: "" or "icu"; got "%s"') + ->end() + ->end() ->variableNode('local_file_storage_options') ->info('Options passed to the local file storage\'s dumper.') ->defaultValue([]) From 3952ec89761e62912075216ee1a27736a498127d Mon Sep 17 00:00:00 2001 From: Marek Snopkowski Date: Tue, 24 Aug 2021 13:14:42 +0200 Subject: [PATCH 03/28] Add new field and getter based on recently added new config option https://github.com/php-translation/symfony-bundle/issues/300 --- Model/Configuration.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Model/Configuration.php b/Model/Configuration.php index 1945c7bd..2ddb5e99 100644 --- a/Model/Configuration.php +++ b/Model/Configuration.php @@ -92,6 +92,11 @@ final class Configuration */ private $xliffVersion; + /** + * @var string + */ + private $newMessageFormat; + public function __construct(array $data) { $this->name = $data['name']; @@ -106,6 +111,7 @@ public function __construct(array $data) $this->blacklistDomains = $data['blacklist_domains']; $this->whitelistDomains = $data['whitelist_domains']; $this->xliffVersion = $data['xliff_version']; + $this->newMessageFormat = $data['new_message_format']; } public function getName(): string @@ -177,6 +183,15 @@ public function getXliffVersion(): string return $this->xliffVersion; } + /** + * If set to "icu" it'll place all new translations in "{domain}+intl-icu.{locale}.{ext}" file. + * Otherwise normal "{domain}.{locale}.{ext}" file will be used. + */ + public function getNewMessageFormat(): string + { + return $this->newMessageFormat; + } + /** * Reconfigures the directories so we can use one configuration for extracting * the messages only from one bundle. From bdad56532afb2ec158f59177769ca62b230c1f6a Mon Sep 17 00:00:00 2001 From: Marek Snopkowski Date: Tue, 24 Aug 2021 13:43:42 +0200 Subject: [PATCH 04/28] Make sure importer is ICU format aware Add new argument to converter methods to make sure we're able to recognize existing translations (and use correct domain - either standard or ICU format). In case translation is new we're going to use predefined format (using new configuration option new_message_format). https://github.com/php-translation/symfony-bundle/issues/300 --- Service/Importer.php | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/Service/Importer.php b/Service/Importer.php index 3fb8677b..74928e1f 100644 --- a/Service/Importer.php +++ b/Service/Importer.php @@ -11,6 +11,7 @@ namespace Translation\Bundle\Service; +use Nyholm\NSA; use Symfony\Component\Finder\Finder; use Symfony\Component\Translation\MessageCatalogue; use Translation\Bundle\Catalogue\Operation\ReplaceOperation; @@ -74,7 +75,7 @@ public function extractToCatalogues(Finder $finder, array $catalogues, array $co $results = []; foreach ($catalogues as $catalogue) { $target = new MessageCatalogue($catalogue->getLocale()); - $this->convertSourceLocationsToMessages($target, $sourceCollection); + $this->convertSourceLocationsToMessages($target, $sourceCollection, $catalogue); // Remove all SourceLocation and State form catalogue. foreach ($catalogue->getDomains() as $domain) { @@ -120,8 +121,13 @@ public function extractToCatalogues(Finder $finder, array $catalogues, array $co return new ImportResult($results, $sourceCollection->getErrors()); } - private function convertSourceLocationsToMessages(MessageCatalogue $catalogue, SourceCollection $collection): void - { + private function convertSourceLocationsToMessages( + MessageCatalogue $catalogue, + SourceCollection $collection, + MessageCatalogue $currentCatalogue + ): void { + $currentMessages = NSA::getProperty($currentCatalogue, 'messages'); + /** @var SourceLocation $sourceLocation */ foreach ($collection as $sourceLocation) { $context = $sourceLocation->getContext(); @@ -131,11 +137,23 @@ private function convertSourceLocationsToMessages(MessageCatalogue $catalogue, S continue; } + $intlDomain = $domain . '+intl-icu' /* MessageCatalogueInterface::INTL_DOMAIN_SUFFIX */; + $key = $sourceLocation->getMessage(); - $catalogue->add([$key => null], $domain); + + if (array_key_exists($key, $currentMessages[$intlDomain] ?? [])) { + $messageDomain = $intlDomain; + } elseif (array_key_exists($key, $currentMessages[$domain] ?? [])) { + $messageDomain = $domain; + } else { + // New translation + $messageDomain = 'icu' === $this->config['new_message_format'] ? $intlDomain : $domain; + } + + $catalogue->add([$key => null], $messageDomain); $trimLength = 1 + \strlen($this->config['project_root']); - $meta = $this->getMetadata($catalogue, $key, $domain); + $meta = $this->getMetadata($catalogue, $key, $messageDomain); $meta->addCategory('file-source', \sprintf('%s:%s', \substr($sourceLocation->getPath(), $trimLength), $sourceLocation->getLine())); if (isset($sourceLocation->getContext()['desc'])) { $meta->addCategory('desc', $sourceLocation->getContext()['desc']); @@ -143,7 +161,7 @@ private function convertSourceLocationsToMessages(MessageCatalogue $catalogue, S if (isset($sourceLocation->getContext()['translation'])) { $meta->addCategory('translation', $sourceLocation->getContext()['translation']); } - $this->setMetadata($catalogue, $key, $domain, $meta); + $this->setMetadata($catalogue, $key, $messageDomain, $meta); } } From c7284ed130ffdbd4f0b3c1bb65ac3ae114ab72f7 Mon Sep 17 00:00:00 2001 From: Marek Snopkowski Date: Tue, 24 Aug 2021 13:45:27 +0200 Subject: [PATCH 05/28] Make sure new_message_format configuration is defined Let the default configuration overlap with Symfony configuration option default value. https://github.com/php-translation/symfony-bundle/issues/300 --- Service/Importer.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Service/Importer.php b/Service/Importer.php index 74928e1f..905fa23d 100644 --- a/Service/Importer.php +++ b/Service/Importer.php @@ -196,6 +196,7 @@ private function processConfig(array $config): void 'project_root' => '', 'blacklist_domains' => [], 'whitelist_domains' => [], + 'new_message_format' => 'icu', ]; $config = \array_merge($default, $config); From ab6631dcbc89689af5fcb25e8ff52c855a9126af Mon Sep 17 00:00:00 2001 From: Marek Snopkowski Date: Tue, 24 Aug 2021 13:46:32 +0200 Subject: [PATCH 06/28] Pass to converter new_message_format configuration https://github.com/php-translation/symfony-bundle/issues/300 --- Command/CheckMissingCommand.php | 1 + Command/ExtractCommand.php | 1 + 2 files changed, 2 insertions(+) diff --git a/Command/CheckMissingCommand.php b/Command/CheckMissingCommand.php index 9618e105..7d8158ec 100644 --- a/Command/CheckMissingCommand.php +++ b/Command/CheckMissingCommand.php @@ -80,6 +80,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int 'blacklist_domains' => $config->getBlacklistDomains(), 'whitelist_domains' => $config->getWhitelistDomains(), 'project_root' => $config->getProjectRoot(), + 'new_message_format' => $config->getNewMessageFormat(), ] ); diff --git a/Command/ExtractCommand.php b/Command/ExtractCommand.php index 5000c362..d87b7451 100644 --- a/Command/ExtractCommand.php +++ b/Command/ExtractCommand.php @@ -106,6 +106,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int 'blacklist_domains' => $config->getBlacklistDomains(), 'whitelist_domains' => $config->getWhitelistDomains(), 'project_root' => $config->getProjectRoot(), + 'new_message_format' => $config->getNewMessageFormat(), ]); $errors = $result->getErrors(); From bd68a10bfb366a446c0e53aaa0a4941ef7e424d0 Mon Sep 17 00:00:00 2001 From: Marek Snopkowski Date: Tue, 24 Aug 2021 13:48:34 +0200 Subject: [PATCH 07/28] Make sure importer is aware of ICU domain format Because of MessageCatalogue interface limitation we're using NSA to access raw messages data. Additionally because defines() method uses isset() were force to check raw messages data directly to check if key exits (translations from source collection are all set to NULL). https://github.com/php-translation/symfony-bundle/issues/300 --- Service/Importer.php | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/Service/Importer.php b/Service/Importer.php index 905fa23d..f3a77b91 100644 --- a/Service/Importer.php +++ b/Service/Importer.php @@ -78,8 +78,8 @@ public function extractToCatalogues(Finder $finder, array $catalogues, array $co $this->convertSourceLocationsToMessages($target, $sourceCollection, $catalogue); // Remove all SourceLocation and State form catalogue. - foreach ($catalogue->getDomains() as $domain) { - foreach ($catalogue->all($domain) as $key => $translation) { + foreach (NSA::getProperty($catalogue, 'messages') as $domain => $translations) { + foreach ($translations as $key => $translation) { $meta = $this->getMetadata($catalogue, $key, $domain); $meta->removeAllInCategory('file-source'); $meta->removeAllInCategory('state'); @@ -91,28 +91,36 @@ public function extractToCatalogues(Finder $finder, array $catalogues, array $co $result = $merge->getResult(); $domains = $merge->getDomains(); + $resultMessages = NSA::getProperty($result, 'messages'); + // Mark new messages as new/obsolete foreach ($domains as $domain) { + $intlDomain = $domain . '+intl-icu' /* MessageCatalogueInterface::INTL_DOMAIN_SUFFIX */; + foreach ($merge->getNewMessages($domain) as $key => $translation) { - $meta = $this->getMetadata($result, $key, $domain); + $messageDomain = array_key_exists($key, $resultMessages[$intlDomain] ?? []) ? $intlDomain : $domain; + + $meta = $this->getMetadata($result, $key, $messageDomain); $meta->setState('new'); - $this->setMetadata($result, $key, $domain, $meta); + $this->setMetadata($result, $key, $messageDomain, $meta); // Add custom translations that we found in the source if (null === $translation) { if (null !== $newTranslation = $meta->getTranslation()) { - $result->set($key, $newTranslation, $domain); + $result->set($key, $newTranslation, $messageDomain); // We do not want "translation" key stored anywhere. $meta->removeAllInCategory('translation'); } elseif (null !== ($newTranslation = $meta->getDesc()) && $catalogue->getLocale() === $this->defaultLocale) { - $result->set($key, $newTranslation, $domain); + $result->set($key, $newTranslation, $messageDomain); } } } foreach ($merge->getObsoleteMessages($domain) as $key => $translation) { - $meta = $this->getMetadata($result, $key, $domain); + $messageDomain = array_key_exists($key, $resultMessages[$intlDomain] ?? []) ? $intlDomain : $domain; + + $meta = $this->getMetadata($result, $key, $messageDomain); $meta->setState('obsolete'); - $this->setMetadata($result, $key, $domain, $meta); + $this->setMetadata($result, $key, $messageDomain, $meta); } } $results[] = $result; From 6429fb49c6e14f60787cb3f8ed7f87e9e7cfcfbd Mon Sep 17 00:00:00 2001 From: Marek Snopkowski Date: Tue, 24 Aug 2021 13:50:39 +0200 Subject: [PATCH 08/28] Let code "breath" a bit https://github.com/php-translation/symfony-bundle/issues/300 --- Service/Importer.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Service/Importer.php b/Service/Importer.php index f3a77b91..0033883d 100644 --- a/Service/Importer.php +++ b/Service/Importer.php @@ -115,6 +115,7 @@ public function extractToCatalogues(Finder $finder, array $catalogues, array $co } } } + foreach ($merge->getObsoleteMessages($domain) as $key => $translation) { $messageDomain = array_key_exists($key, $resultMessages[$intlDomain] ?? []) ? $intlDomain : $domain; @@ -140,6 +141,7 @@ private function convertSourceLocationsToMessages( foreach ($collection as $sourceLocation) { $context = $sourceLocation->getContext(); $domain = $context['domain'] ?? 'messages'; + // Check with white/black list if (!$this->isValidDomain($domain)) { continue; From ef9c691b4a0239d2c2e467d8c08b58fbfe1696c1 Mon Sep 17 00:00:00 2001 From: Marek Snopkowski Date: Tue, 24 Aug 2021 13:51:35 +0200 Subject: [PATCH 09/28] Make sure we're always aware of ICU domain https://github.com/php-translation/symfony-bundle/issues/300 --- Catalogue/Operation/ReplaceOperation.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Catalogue/Operation/ReplaceOperation.php b/Catalogue/Operation/ReplaceOperation.php index 7b572103..12a53176 100644 --- a/Catalogue/Operation/ReplaceOperation.php +++ b/Catalogue/Operation/ReplaceOperation.php @@ -37,11 +37,8 @@ protected function processDomain($domain): void 'new' => [], 'obsolete' => [], ]; - if (\defined(\sprintf('%s::INTL_DOMAIN_SUFFIX', MessageCatalogueInterface::class))) { - $intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX; - } else { - $intlDomain = $domain; - } + + $intlDomain = $domain . '+intl-icu' /* MessageCatalogueInterface::INTL_DOMAIN_SUFFIX */; foreach ($this->source->all($domain) as $id => $message) { $messageDomain = $this->source->defines($id, $intlDomain) ? $intlDomain : $domain; From af2089840fbe199b74e59447f1c9e03c526ec4cb Mon Sep 17 00:00:00 2001 From: Marek Snopkowski Date: Tue, 24 Aug 2021 13:53:01 +0200 Subject: [PATCH 10/28] Make sure we're aware of 3 different message domains We have: 1. Source message domain. 2. Target message domain. 3. Result message domain (this is tied to 2 of the above). This solution assumes we'd always like to use ICU format (result message domain) if we use it in any of source or target catalogue. Additionally because of default NULL values in source catalogue (internal extractor design to set NULL for "target" when creating messages catalogue from source collection) we have to check if desired catalogue's messages field has a key (within requested domain) or not. Using MessageCatalogue::defines() would return false for catalogue without translation (NULL value). Lastly - make sure internal messages field utilised result message domain for consistency with result field. https://github.com/php-translation/symfony-bundle/issues/300 --- Catalogue/Operation/ReplaceOperation.php | 43 +++++++++++++++--------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/Catalogue/Operation/ReplaceOperation.php b/Catalogue/Operation/ReplaceOperation.php index 12a53176..5400aa75 100644 --- a/Catalogue/Operation/ReplaceOperation.php +++ b/Catalogue/Operation/ReplaceOperation.php @@ -11,6 +11,7 @@ namespace Translation\Bundle\Catalogue\Operation; +use Nyholm\NSA; use Symfony\Component\Translation\Catalogue\AbstractOperation; use Symfony\Component\Translation\MessageCatalogueInterface; use Symfony\Component\Translation\MetadataAwareInterface; @@ -40,20 +41,28 @@ protected function processDomain($domain): void $intlDomain = $domain . '+intl-icu' /* MessageCatalogueInterface::INTL_DOMAIN_SUFFIX */; + $sourceMessages = NSA::getProperty($this->source, 'messages'); + $targetMessages = NSA::getProperty($this->target, 'messages'); + foreach ($this->source->all($domain) as $id => $message) { - $messageDomain = $this->source->defines($id, $intlDomain) ? $intlDomain : $domain; + $sourceIdInIntl = array_key_exists($id, $sourceMessages[$intlDomain] ?? []); + $targetIdInIntl = array_key_exists($id, $targetMessages[$intlDomain] ?? []); + + $sourceMessageDomain = $sourceIdInIntl ? $intlDomain : $domain; + $targetMessageDomain = $targetIdInIntl ? $intlDomain : $domain; + $resultMessageDomain = $sourceIdInIntl || $targetIdInIntl ? $intlDomain : $domain; if (!$this->target->has($id, $domain)) { // No merge required $translation = $message; - $this->messages[$domain]['new'][$id] = $message; - $resultMeta = $this->getMetadata($this->source, $messageDomain, $id); + $this->messages[$resultMessageDomain]['new'][$id] = $message; + $resultMeta = $this->getMetadata($this->source, $sourceMessageDomain, $id); } else { // Merge required - $translation = $message ?? $this->target->get($id, $domain); + $translation = $message ?? $this->target->get($id, $targetMessageDomain); $resultMeta = null; - $sourceMeta = $this->getMetadata($this->source, $messageDomain, $id); - $targetMeta = $this->getMetadata($this->target, $this->target->defines($id, $intlDomain) ? $intlDomain : $domain, $id); + $sourceMeta = $this->getMetadata($this->source, $sourceMessageDomain, $id); + $targetMeta = $this->getMetadata($this->target, $targetMessageDomain, $id); if (\is_array($sourceMeta) && \is_array($targetMeta)) { // We can only merge meta if both is an array $resultMeta = $this->mergeMetadata($sourceMeta, $targetMeta); @@ -65,11 +74,11 @@ protected function processDomain($domain): void } } - $this->messages[$domain]['all'][$id] = $translation; - $this->result->add([$id => $translation], $messageDomain); + $this->messages[$resultMessageDomain]['all'][$id] = $translation; + $this->result->add([$id => $translation], $resultMessageDomain); if (!empty($resultMeta)) { - $this->result->setMetadata($id, $resultMeta, $messageDomain); + $this->result->setMetadata($id, $resultMeta, $resultMessageDomain); } } @@ -80,14 +89,18 @@ protected function processDomain($domain): void continue; } - $messageDomain = $this->target->defines($id, $intlDomain) ? $intlDomain : $domain; - $this->messages[$domain]['all'][$id] = $message; - $this->messages[$domain]['obsolete'][$id] = $message; - $this->result->add([$id => $message], $messageDomain); + $sourceIdInIntl = array_key_exists($id, $sourceMessages[$intlDomain] ?? []); + $targetIdInIntl = array_key_exists($id, $targetMessages[$intlDomain] ?? []); + + $resultMessageDomain = $sourceIdInIntl || $targetIdInIntl ? $intlDomain : $domain; + + $this->messages[$resultMessageDomain]['all'][$id] = $message; + $this->messages[$resultMessageDomain]['obsolete'][$id] = $message; + $this->result->add([$id => $message], $resultMessageDomain); - $resultMeta = $this->getMetadata($this->target, $messageDomain, $id); + $resultMeta = $this->getMetadata($this->target, $resultMessageDomain, $id); if (!empty($resultMeta)) { - $this->result->setMetadata($id, $resultMeta, $messageDomain); + $this->result->setMetadata($id, $resultMeta, $resultMessageDomain); } } } From 04a1f1e0efa6a4e9ab23bb1ab1167e3617d0e691 Mon Sep 17 00:00:00 2001 From: Marek Snopkowski Date: Mon, 30 Aug 2021 09:55:04 +0200 Subject: [PATCH 11/28] Persist PHP CS Fixer changes https://github.com/php-translation/symfony-bundle/issues/300 --- Catalogue/CatalogueFetcher.php | 2 +- Catalogue/Operation/ReplaceOperation.php | 10 +++++----- Service/Importer.php | 12 ++++++------ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Catalogue/CatalogueFetcher.php b/Catalogue/CatalogueFetcher.php index 09298987..b04843f6 100644 --- a/Catalogue/CatalogueFetcher.php +++ b/Catalogue/CatalogueFetcher.php @@ -54,7 +54,7 @@ public function getCatalogues(Configuration $config, array $locales = []): array foreach ($currentCatalogue->getDomains() as $domain) { if (!$this->isValidDomain($config, $domain)) { $messages = NSA::getProperty($currentCatalogue, 'messages'); - unset($messages[$domain], $messages[$domain . '+intl-icu' /* MessageCatalogueInterface::INTL_DOMAIN_SUFFIX */]); + unset($messages[$domain], $messages[$domain.'+intl-icu' /* MessageCatalogueInterface::INTL_DOMAIN_SUFFIX */]); NSA::setProperty($currentCatalogue, 'messages', $messages); } } diff --git a/Catalogue/Operation/ReplaceOperation.php b/Catalogue/Operation/ReplaceOperation.php index 5400aa75..bb4b3793 100644 --- a/Catalogue/Operation/ReplaceOperation.php +++ b/Catalogue/Operation/ReplaceOperation.php @@ -39,14 +39,14 @@ protected function processDomain($domain): void 'obsolete' => [], ]; - $intlDomain = $domain . '+intl-icu' /* MessageCatalogueInterface::INTL_DOMAIN_SUFFIX */; + $intlDomain = $domain.'+intl-icu' /* MessageCatalogueInterface::INTL_DOMAIN_SUFFIX */; $sourceMessages = NSA::getProperty($this->source, 'messages'); $targetMessages = NSA::getProperty($this->target, 'messages'); foreach ($this->source->all($domain) as $id => $message) { - $sourceIdInIntl = array_key_exists($id, $sourceMessages[$intlDomain] ?? []); - $targetIdInIntl = array_key_exists($id, $targetMessages[$intlDomain] ?? []); + $sourceIdInIntl = \array_key_exists($id, $sourceMessages[$intlDomain] ?? []); + $targetIdInIntl = \array_key_exists($id, $targetMessages[$intlDomain] ?? []); $sourceMessageDomain = $sourceIdInIntl ? $intlDomain : $domain; $targetMessageDomain = $targetIdInIntl ? $intlDomain : $domain; @@ -89,8 +89,8 @@ protected function processDomain($domain): void continue; } - $sourceIdInIntl = array_key_exists($id, $sourceMessages[$intlDomain] ?? []); - $targetIdInIntl = array_key_exists($id, $targetMessages[$intlDomain] ?? []); + $sourceIdInIntl = \array_key_exists($id, $sourceMessages[$intlDomain] ?? []); + $targetIdInIntl = \array_key_exists($id, $targetMessages[$intlDomain] ?? []); $resultMessageDomain = $sourceIdInIntl || $targetIdInIntl ? $intlDomain : $domain; diff --git a/Service/Importer.php b/Service/Importer.php index 0033883d..5e623026 100644 --- a/Service/Importer.php +++ b/Service/Importer.php @@ -95,10 +95,10 @@ public function extractToCatalogues(Finder $finder, array $catalogues, array $co // Mark new messages as new/obsolete foreach ($domains as $domain) { - $intlDomain = $domain . '+intl-icu' /* MessageCatalogueInterface::INTL_DOMAIN_SUFFIX */; + $intlDomain = $domain.'+intl-icu' /* MessageCatalogueInterface::INTL_DOMAIN_SUFFIX */; foreach ($merge->getNewMessages($domain) as $key => $translation) { - $messageDomain = array_key_exists($key, $resultMessages[$intlDomain] ?? []) ? $intlDomain : $domain; + $messageDomain = \array_key_exists($key, $resultMessages[$intlDomain] ?? []) ? $intlDomain : $domain; $meta = $this->getMetadata($result, $key, $messageDomain); $meta->setState('new'); @@ -117,7 +117,7 @@ public function extractToCatalogues(Finder $finder, array $catalogues, array $co } foreach ($merge->getObsoleteMessages($domain) as $key => $translation) { - $messageDomain = array_key_exists($key, $resultMessages[$intlDomain] ?? []) ? $intlDomain : $domain; + $messageDomain = \array_key_exists($key, $resultMessages[$intlDomain] ?? []) ? $intlDomain : $domain; $meta = $this->getMetadata($result, $key, $messageDomain); $meta->setState('obsolete'); @@ -147,13 +147,13 @@ private function convertSourceLocationsToMessages( continue; } - $intlDomain = $domain . '+intl-icu' /* MessageCatalogueInterface::INTL_DOMAIN_SUFFIX */; + $intlDomain = $domain.'+intl-icu' /* MessageCatalogueInterface::INTL_DOMAIN_SUFFIX */; $key = $sourceLocation->getMessage(); - if (array_key_exists($key, $currentMessages[$intlDomain] ?? [])) { + if (\array_key_exists($key, $currentMessages[$intlDomain] ?? [])) { $messageDomain = $intlDomain; - } elseif (array_key_exists($key, $currentMessages[$domain] ?? [])) { + } elseif (\array_key_exists($key, $currentMessages[$domain] ?? [])) { $messageDomain = $domain; } else { // New translation From c040dab378b09c7b6b02741c0e5da6be91b4b8f1 Mon Sep 17 00:00:00 2001 From: Marek Snopkowski Date: Tue, 24 Aug 2021 13:10:36 +0200 Subject: [PATCH 12/28] Remove both "normal" and ICU domain from messages set https://github.com/php-translation/symfony-bundle/issues/300 --- Catalogue/CatalogueFetcher.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Catalogue/CatalogueFetcher.php b/Catalogue/CatalogueFetcher.php index 504d305e..cef5a244 100644 --- a/Catalogue/CatalogueFetcher.php +++ b/Catalogue/CatalogueFetcher.php @@ -53,8 +53,8 @@ public function getCatalogues(Configuration $config, array $locales = []): array foreach ($currentCatalogue->getDomains() as $domain) { if (!$this->isValidDomain($config, $domain)) { - $messages = $currentCatalogue->all(); - unset($messages[$domain]); + $messages = NSA::getProperty($currentCatalogue, 'messages'); + unset($messages[$domain], $messages[$domain . '+intl-icu' /* MessageCatalogueInterface::INTL_DOMAIN_SUFFIX */]); NSA::setProperty($currentCatalogue, 'messages', $messages); } } From 1e88a3784b60f7d977ece1663f7306442733b030 Mon Sep 17 00:00:00 2001 From: Marek Snopkowski Date: Tue, 24 Aug 2021 13:11:36 +0200 Subject: [PATCH 13/28] Add new configuration for new message format It will allow us to control if we want to use new ICU format (with suffixed domain with "+intl-icu") or format. Configuration has normalizer (making sure string is in lower case) and validator (making sure it's a string and either "" or "icu"). Setting `new_message_format: ""` we'll end up with new translations in container like: {domain}.{locale}.{ext}. Setting `new_message_format: "icu"` we'll end up with new translations in container like: {domain}+intl-icu.{locale}.{ext}. https://github.com/php-translation/symfony-bundle/issues/300 --- DependencyInjection/Configuration.php | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 518eea73..f883af1f 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -164,6 +164,28 @@ private function configsNode(ArrayNodeDefinition $root): void ->scalarNode('output_dir')->cannotBeEmpty()->defaultValue('%kernel.project_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('xliff_version')->info('The version of XLIFF XML you want to use (if dumping to this format).')->defaultValue('2.0')->end() + ->scalarNode('new_message_format') + ->info('Use "icu" to place new translations in "{domain}+intl-icu.{locale}.{ext}" container') + ->defaultValue('icu') + ->beforeNormalization() + ->ifTrue( + function ($format) { + return \is_string($format); + } + ) + ->then( + function (string $format) { + return \strtolower($format); + } + ) + ->end() + ->validate() + ->ifTrue(function ($value) { + return !\is_string($value) || !\in_array($value, ['', 'icu']); + }) + ->thenInvalid('The "new_message_format" must be either: "" or "icu"; got "%s"') + ->end() + ->end() ->variableNode('local_file_storage_options') ->info('Options passed to the local file storage\'s dumper.') ->defaultValue([]) From a383c2453382445d085dab7ec8632f2f90ddfd21 Mon Sep 17 00:00:00 2001 From: Marek Snopkowski Date: Tue, 24 Aug 2021 13:14:42 +0200 Subject: [PATCH 14/28] Add new field and getter based on recently added new config option https://github.com/php-translation/symfony-bundle/issues/300 --- Model/Configuration.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Model/Configuration.php b/Model/Configuration.php index e4f7bdac..20b25138 100644 --- a/Model/Configuration.php +++ b/Model/Configuration.php @@ -92,6 +92,11 @@ final class Configuration */ private $xliffVersion; + /** + * @var string + */ + private $newMessageFormat; + public function __construct(array $data) { $this->name = $data['name']; @@ -106,6 +111,7 @@ public function __construct(array $data) $this->blacklistDomains = $data['blacklist_domains']; $this->whitelistDomains = $data['whitelist_domains']; $this->xliffVersion = $data['xliff_version']; + $this->newMessageFormat = $data['new_message_format']; } public function getName(): string @@ -177,6 +183,15 @@ public function getXliffVersion(): string return $this->xliffVersion; } + /** + * If set to "icu" it'll place all new translations in "{domain}+intl-icu.{locale}.{ext}" file. + * Otherwise normal "{domain}.{locale}.{ext}" file will be used. + */ + public function getNewMessageFormat(): string + { + return $this->newMessageFormat; + } + /** * Reconfigures the directories so we can use one configuration for extracting * the messages only from one bundle. From 5b321e1498f241abf5b06abeb99d12914f0e3c34 Mon Sep 17 00:00:00 2001 From: Marek Snopkowski Date: Thu, 24 Nov 2022 16:27:09 +0100 Subject: [PATCH 15/28] Make sure importer is ICU format aware Add new argument to converter methods to make sure we're able to recognize existing translations (and use correct domain - either standard or ICU format). In case translation is new we're going to use predefined format (using new configuration option new_message_format). https://github.com/php-translation/symfony-bundle/issues/300 --- Service/Importer.php | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/Service/Importer.php b/Service/Importer.php index 146add31..73429f7e 100644 --- a/Service/Importer.php +++ b/Service/Importer.php @@ -11,6 +11,7 @@ namespace Translation\Bundle\Service; +use Nyholm\NSA; use Symfony\Component\Finder\Finder; use Symfony\Component\Translation\MessageCatalogue; use Translation\Bundle\Catalogue\Operation\ReplaceOperation; @@ -74,7 +75,7 @@ public function extractToCatalogues(Finder $finder, array $catalogues, array $co $results = []; foreach ($catalogues as $catalogue) { $target = new MessageCatalogue($catalogue->getLocale()); - $this->convertSourceLocationsToMessages($target, $sourceCollection); + $this->convertSourceLocationsToMessages($target, $sourceCollection, $catalogue); // Remove all SourceLocation and State form catalogue. foreach ($catalogue->getDomains() as $domain) { @@ -120,8 +121,13 @@ public function extractToCatalogues(Finder $finder, array $catalogues, array $co return new ImportResult($results, $sourceCollection->getErrors()); } - private function convertSourceLocationsToMessages(MessageCatalogue $catalogue, SourceCollection $collection): void - { + private function convertSourceLocationsToMessages( + MessageCatalogue $catalogue, + SourceCollection $collection, + MessageCatalogue $currentCatalogue + ): void { + $currentMessages = NSA::getProperty($currentCatalogue, 'messages'); + /** @var SourceLocation $sourceLocation */ foreach ($collection as $sourceLocation) { $context = $sourceLocation->getContext(); @@ -131,11 +137,23 @@ private function convertSourceLocationsToMessages(MessageCatalogue $catalogue, S continue; } + $intlDomain = $domain . '+intl-icu' /* MessageCatalogueInterface::INTL_DOMAIN_SUFFIX */; + $key = $sourceLocation->getMessage(); - $catalogue->add([$key => null], $domain); + + if (array_key_exists($key, $currentMessages[$intlDomain] ?? [])) { + $messageDomain = $intlDomain; + } elseif (array_key_exists($key, $currentMessages[$domain] ?? [])) { + $messageDomain = $domain; + } else { + // New translation + $messageDomain = 'icu' === $this->config['new_message_format'] ? $intlDomain : $domain; + } + + $catalogue->add([$key => null], $messageDomain); $trimLength = 1 + \strlen($this->config['project_root']); - $meta = $this->getMetadata($catalogue, $key, $domain); + $meta = $this->getMetadata($catalogue, $key, $messageDomain); $meta->addCategory('file-source', sprintf('%s:%s', substr($sourceLocation->getPath(), $trimLength), $sourceLocation->getLine())); if (isset($sourceLocation->getContext()['desc'])) { $meta->addCategory('desc', $sourceLocation->getContext()['desc']); @@ -143,7 +161,7 @@ private function convertSourceLocationsToMessages(MessageCatalogue $catalogue, S if (isset($sourceLocation->getContext()['translation'])) { $meta->addCategory('translation', $sourceLocation->getContext()['translation']); } - $this->setMetadata($catalogue, $key, $domain, $meta); + $this->setMetadata($catalogue, $key, $messageDomain, $meta); } } From a39113e60330138a4b10577e65eb6faa77d95f06 Mon Sep 17 00:00:00 2001 From: Marek Snopkowski Date: Tue, 24 Aug 2021 13:45:27 +0200 Subject: [PATCH 16/28] Make sure new_message_format configuration is defined Let the default configuration overlap with Symfony configuration option default value. https://github.com/php-translation/symfony-bundle/issues/300 --- Service/Importer.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Service/Importer.php b/Service/Importer.php index 73429f7e..482813a7 100644 --- a/Service/Importer.php +++ b/Service/Importer.php @@ -196,6 +196,7 @@ private function processConfig(array $config): void 'project_root' => '', 'blacklist_domains' => [], 'whitelist_domains' => [], + 'new_message_format' => 'icu', ]; $config = array_merge($default, $config); From 592b8f2e47d5f1c60f2a7dc5baedf5a927814a09 Mon Sep 17 00:00:00 2001 From: Marek Snopkowski Date: Tue, 24 Aug 2021 13:46:32 +0200 Subject: [PATCH 17/28] Pass to converter new_message_format configuration https://github.com/php-translation/symfony-bundle/issues/300 --- Command/CheckMissingCommand.php | 1 + Command/ExtractCommand.php | 1 + 2 files changed, 2 insertions(+) diff --git a/Command/CheckMissingCommand.php b/Command/CheckMissingCommand.php index 46a09e09..58a6ac4d 100644 --- a/Command/CheckMissingCommand.php +++ b/Command/CheckMissingCommand.php @@ -80,6 +80,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int 'blacklist_domains' => $config->getBlacklistDomains(), 'whitelist_domains' => $config->getWhitelistDomains(), 'project_root' => $config->getProjectRoot(), + 'new_message_format' => $config->getNewMessageFormat(), ] ); diff --git a/Command/ExtractCommand.php b/Command/ExtractCommand.php index 7dd27bfd..f61290dd 100644 --- a/Command/ExtractCommand.php +++ b/Command/ExtractCommand.php @@ -106,6 +106,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int 'blacklist_domains' => $config->getBlacklistDomains(), 'whitelist_domains' => $config->getWhitelistDomains(), 'project_root' => $config->getProjectRoot(), + 'new_message_format' => $config->getNewMessageFormat(), ]); $errors = $result->getErrors(); From c3dbe3b9875b955d3161f305f04815c4d9cd8f42 Mon Sep 17 00:00:00 2001 From: Marek Snopkowski Date: Tue, 24 Aug 2021 13:48:34 +0200 Subject: [PATCH 18/28] Make sure importer is aware of ICU domain format Because of MessageCatalogue interface limitation we're using NSA to access raw messages data. Additionally because defines() method uses isset() were force to check raw messages data directly to check if key exits (translations from source collection are all set to NULL). https://github.com/php-translation/symfony-bundle/issues/300 --- Service/Importer.php | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/Service/Importer.php b/Service/Importer.php index 482813a7..f90eaa9a 100644 --- a/Service/Importer.php +++ b/Service/Importer.php @@ -78,8 +78,8 @@ public function extractToCatalogues(Finder $finder, array $catalogues, array $co $this->convertSourceLocationsToMessages($target, $sourceCollection, $catalogue); // Remove all SourceLocation and State form catalogue. - foreach ($catalogue->getDomains() as $domain) { - foreach ($catalogue->all($domain) as $key => $translation) { + foreach (NSA::getProperty($catalogue, 'messages') as $domain => $translations) { + foreach ($translations as $key => $translation) { $meta = $this->getMetadata($catalogue, $key, $domain); $meta->removeAllInCategory('file-source'); $meta->removeAllInCategory('state'); @@ -91,28 +91,36 @@ public function extractToCatalogues(Finder $finder, array $catalogues, array $co $result = $merge->getResult(); $domains = $merge->getDomains(); + $resultMessages = NSA::getProperty($result, 'messages'); + // Mark new messages as new/obsolete foreach ($domains as $domain) { + $intlDomain = $domain . '+intl-icu' /* MessageCatalogueInterface::INTL_DOMAIN_SUFFIX */; + foreach ($merge->getNewMessages($domain) as $key => $translation) { - $meta = $this->getMetadata($result, $key, $domain); + $messageDomain = array_key_exists($key, $resultMessages[$intlDomain] ?? []) ? $intlDomain : $domain; + + $meta = $this->getMetadata($result, $key, $messageDomain); $meta->setState('new'); - $this->setMetadata($result, $key, $domain, $meta); + $this->setMetadata($result, $key, $messageDomain, $meta); // Add custom translations that we found in the source if (null === $translation) { if (null !== $newTranslation = $meta->getTranslation()) { - $result->set($key, $newTranslation, $domain); + $result->set($key, $newTranslation, $messageDomain); // We do not want "translation" key stored anywhere. $meta->removeAllInCategory('translation'); } elseif (null !== ($newTranslation = $meta->getDesc()) && $catalogue->getLocale() === $this->defaultLocale) { - $result->set($key, $newTranslation, $domain); + $result->set($key, $newTranslation, $messageDomain); } } } foreach ($merge->getObsoleteMessages($domain) as $key => $translation) { - $meta = $this->getMetadata($result, $key, $domain); + $messageDomain = array_key_exists($key, $resultMessages[$intlDomain] ?? []) ? $intlDomain : $domain; + + $meta = $this->getMetadata($result, $key, $messageDomain); $meta->setState('obsolete'); - $this->setMetadata($result, $key, $domain, $meta); + $this->setMetadata($result, $key, $messageDomain, $meta); } } $results[] = $result; From ee0cc66657708a251724e131b60d210fcb166da0 Mon Sep 17 00:00:00 2001 From: Marek Snopkowski Date: Tue, 24 Aug 2021 13:50:39 +0200 Subject: [PATCH 19/28] Let code "breath" a bit https://github.com/php-translation/symfony-bundle/issues/300 --- Service/Importer.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Service/Importer.php b/Service/Importer.php index f90eaa9a..ee9334e0 100644 --- a/Service/Importer.php +++ b/Service/Importer.php @@ -115,6 +115,7 @@ public function extractToCatalogues(Finder $finder, array $catalogues, array $co } } } + foreach ($merge->getObsoleteMessages($domain) as $key => $translation) { $messageDomain = array_key_exists($key, $resultMessages[$intlDomain] ?? []) ? $intlDomain : $domain; @@ -140,6 +141,7 @@ private function convertSourceLocationsToMessages( foreach ($collection as $sourceLocation) { $context = $sourceLocation->getContext(); $domain = $context['domain'] ?? 'messages'; + // Check with white/black list if (!$this->isValidDomain($domain)) { continue; From d3b44d96b3ee4a83e2cbe01de65900520fcd10d5 Mon Sep 17 00:00:00 2001 From: Marek Snopkowski Date: Thu, 24 Nov 2022 16:27:44 +0100 Subject: [PATCH 20/28] Make sure we're always aware of ICU domain https://github.com/php-translation/symfony-bundle/issues/300 --- Catalogue/Operation/ReplaceOperation.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Catalogue/Operation/ReplaceOperation.php b/Catalogue/Operation/ReplaceOperation.php index 6267876b..d0463f1c 100644 --- a/Catalogue/Operation/ReplaceOperation.php +++ b/Catalogue/Operation/ReplaceOperation.php @@ -37,11 +37,8 @@ protected function processDomain($domain): void 'new' => [], 'obsolete' => [], ]; - if (\defined(sprintf('%s::INTL_DOMAIN_SUFFIX', MessageCatalogueInterface::class))) { - $intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX; - } else { - $intlDomain = $domain; - } + + $intlDomain = $domain . '+intl-icu' /* MessageCatalogueInterface::INTL_DOMAIN_SUFFIX */; foreach ($this->source->all($domain) as $id => $message) { $messageDomain = $this->source->defines($id, $intlDomain) ? $intlDomain : $domain; From 1c7da76b2aa8ffe7e7de48479cd4023a8d0835c3 Mon Sep 17 00:00:00 2001 From: Marek Snopkowski Date: Tue, 24 Aug 2021 13:53:01 +0200 Subject: [PATCH 21/28] Make sure we're aware of 3 different message domains We have: 1. Source message domain. 2. Target message domain. 3. Result message domain (this is tied to 2 of the above). This solution assumes we'd always like to use ICU format (result message domain) if we use it in any of source or target catalogue. Additionally because of default NULL values in source catalogue (internal extractor design to set NULL for "target" when creating messages catalogue from source collection) we have to check if desired catalogue's messages field has a key (within requested domain) or not. Using MessageCatalogue::defines() would return false for catalogue without translation (NULL value). Lastly - make sure internal messages field utilised result message domain for consistency with result field. https://github.com/php-translation/symfony-bundle/issues/300 --- Catalogue/Operation/ReplaceOperation.php | 43 +++++++++++++++--------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/Catalogue/Operation/ReplaceOperation.php b/Catalogue/Operation/ReplaceOperation.php index d0463f1c..c9d0cd60 100644 --- a/Catalogue/Operation/ReplaceOperation.php +++ b/Catalogue/Operation/ReplaceOperation.php @@ -11,6 +11,7 @@ namespace Translation\Bundle\Catalogue\Operation; +use Nyholm\NSA; use Symfony\Component\Translation\Catalogue\AbstractOperation; use Symfony\Component\Translation\MessageCatalogueInterface; use Symfony\Component\Translation\MetadataAwareInterface; @@ -40,20 +41,28 @@ protected function processDomain($domain): void $intlDomain = $domain . '+intl-icu' /* MessageCatalogueInterface::INTL_DOMAIN_SUFFIX */; + $sourceMessages = NSA::getProperty($this->source, 'messages'); + $targetMessages = NSA::getProperty($this->target, 'messages'); + foreach ($this->source->all($domain) as $id => $message) { - $messageDomain = $this->source->defines($id, $intlDomain) ? $intlDomain : $domain; + $sourceIdInIntl = array_key_exists($id, $sourceMessages[$intlDomain] ?? []); + $targetIdInIntl = array_key_exists($id, $targetMessages[$intlDomain] ?? []); + + $sourceMessageDomain = $sourceIdInIntl ? $intlDomain : $domain; + $targetMessageDomain = $targetIdInIntl ? $intlDomain : $domain; + $resultMessageDomain = $sourceIdInIntl || $targetIdInIntl ? $intlDomain : $domain; if (!$this->target->has($id, $domain)) { // No merge required $translation = $message; - $this->messages[$domain]['new'][$id] = $message; - $resultMeta = $this->getMetadata($this->source, $messageDomain, $id); + $this->messages[$resultMessageDomain]['new'][$id] = $message; + $resultMeta = $this->getMetadata($this->source, $sourceMessageDomain, $id); } else { // Merge required - $translation = $message ?? $this->target->get($id, $domain); + $translation = $message ?? $this->target->get($id, $targetMessageDomain); $resultMeta = null; - $sourceMeta = $this->getMetadata($this->source, $messageDomain, $id); - $targetMeta = $this->getMetadata($this->target, $this->target->defines($id, $intlDomain) ? $intlDomain : $domain, $id); + $sourceMeta = $this->getMetadata($this->source, $sourceMessageDomain, $id); + $targetMeta = $this->getMetadata($this->target, $targetMessageDomain, $id); if (\is_array($sourceMeta) && \is_array($targetMeta)) { // We can only merge meta if both is an array $resultMeta = $this->mergeMetadata($sourceMeta, $targetMeta); @@ -65,11 +74,11 @@ protected function processDomain($domain): void } } - $this->messages[$domain]['all'][$id] = $translation; - $this->result->add([$id => $translation], $messageDomain); + $this->messages[$resultMessageDomain]['all'][$id] = $translation; + $this->result->add([$id => $translation], $resultMessageDomain); if (!empty($resultMeta)) { - $this->result->setMetadata($id, $resultMeta, $messageDomain); + $this->result->setMetadata($id, $resultMeta, $resultMessageDomain); } } @@ -80,14 +89,18 @@ protected function processDomain($domain): void continue; } - $messageDomain = $this->target->defines($id, $intlDomain) ? $intlDomain : $domain; - $this->messages[$domain]['all'][$id] = $message; - $this->messages[$domain]['obsolete'][$id] = $message; - $this->result->add([$id => $message], $messageDomain); + $sourceIdInIntl = array_key_exists($id, $sourceMessages[$intlDomain] ?? []); + $targetIdInIntl = array_key_exists($id, $targetMessages[$intlDomain] ?? []); + + $resultMessageDomain = $sourceIdInIntl || $targetIdInIntl ? $intlDomain : $domain; + + $this->messages[$resultMessageDomain]['all'][$id] = $message; + $this->messages[$resultMessageDomain]['obsolete'][$id] = $message; + $this->result->add([$id => $message], $resultMessageDomain); - $resultMeta = $this->getMetadata($this->target, $messageDomain, $id); + $resultMeta = $this->getMetadata($this->target, $resultMessageDomain, $id); if (!empty($resultMeta)) { - $this->result->setMetadata($id, $resultMeta, $messageDomain); + $this->result->setMetadata($id, $resultMeta, $resultMessageDomain); } } } From 8802b6f3798f9ff4b4ebd30c95398847cbb355a0 Mon Sep 17 00:00:00 2001 From: Marek Snopkowski Date: Mon, 30 Aug 2021 09:55:04 +0200 Subject: [PATCH 22/28] Persist PHP CS Fixer changes https://github.com/php-translation/symfony-bundle/issues/300 --- Catalogue/CatalogueFetcher.php | 2 +- Catalogue/Operation/ReplaceOperation.php | 10 +++++----- Service/Importer.php | 12 ++++++------ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Catalogue/CatalogueFetcher.php b/Catalogue/CatalogueFetcher.php index cef5a244..ec83b0b4 100644 --- a/Catalogue/CatalogueFetcher.php +++ b/Catalogue/CatalogueFetcher.php @@ -54,7 +54,7 @@ public function getCatalogues(Configuration $config, array $locales = []): array foreach ($currentCatalogue->getDomains() as $domain) { if (!$this->isValidDomain($config, $domain)) { $messages = NSA::getProperty($currentCatalogue, 'messages'); - unset($messages[$domain], $messages[$domain . '+intl-icu' /* MessageCatalogueInterface::INTL_DOMAIN_SUFFIX */]); + unset($messages[$domain], $messages[$domain.'+intl-icu' /* MessageCatalogueInterface::INTL_DOMAIN_SUFFIX */]); NSA::setProperty($currentCatalogue, 'messages', $messages); } } diff --git a/Catalogue/Operation/ReplaceOperation.php b/Catalogue/Operation/ReplaceOperation.php index c9d0cd60..746a6861 100644 --- a/Catalogue/Operation/ReplaceOperation.php +++ b/Catalogue/Operation/ReplaceOperation.php @@ -39,14 +39,14 @@ protected function processDomain($domain): void 'obsolete' => [], ]; - $intlDomain = $domain . '+intl-icu' /* MessageCatalogueInterface::INTL_DOMAIN_SUFFIX */; + $intlDomain = $domain.'+intl-icu' /* MessageCatalogueInterface::INTL_DOMAIN_SUFFIX */; $sourceMessages = NSA::getProperty($this->source, 'messages'); $targetMessages = NSA::getProperty($this->target, 'messages'); foreach ($this->source->all($domain) as $id => $message) { - $sourceIdInIntl = array_key_exists($id, $sourceMessages[$intlDomain] ?? []); - $targetIdInIntl = array_key_exists($id, $targetMessages[$intlDomain] ?? []); + $sourceIdInIntl = \array_key_exists($id, $sourceMessages[$intlDomain] ?? []); + $targetIdInIntl = \array_key_exists($id, $targetMessages[$intlDomain] ?? []); $sourceMessageDomain = $sourceIdInIntl ? $intlDomain : $domain; $targetMessageDomain = $targetIdInIntl ? $intlDomain : $domain; @@ -89,8 +89,8 @@ protected function processDomain($domain): void continue; } - $sourceIdInIntl = array_key_exists($id, $sourceMessages[$intlDomain] ?? []); - $targetIdInIntl = array_key_exists($id, $targetMessages[$intlDomain] ?? []); + $sourceIdInIntl = \array_key_exists($id, $sourceMessages[$intlDomain] ?? []); + $targetIdInIntl = \array_key_exists($id, $targetMessages[$intlDomain] ?? []); $resultMessageDomain = $sourceIdInIntl || $targetIdInIntl ? $intlDomain : $domain; diff --git a/Service/Importer.php b/Service/Importer.php index ee9334e0..75ca10ed 100644 --- a/Service/Importer.php +++ b/Service/Importer.php @@ -95,10 +95,10 @@ public function extractToCatalogues(Finder $finder, array $catalogues, array $co // Mark new messages as new/obsolete foreach ($domains as $domain) { - $intlDomain = $domain . '+intl-icu' /* MessageCatalogueInterface::INTL_DOMAIN_SUFFIX */; + $intlDomain = $domain.'+intl-icu' /* MessageCatalogueInterface::INTL_DOMAIN_SUFFIX */; foreach ($merge->getNewMessages($domain) as $key => $translation) { - $messageDomain = array_key_exists($key, $resultMessages[$intlDomain] ?? []) ? $intlDomain : $domain; + $messageDomain = \array_key_exists($key, $resultMessages[$intlDomain] ?? []) ? $intlDomain : $domain; $meta = $this->getMetadata($result, $key, $messageDomain); $meta->setState('new'); @@ -117,7 +117,7 @@ public function extractToCatalogues(Finder $finder, array $catalogues, array $co } foreach ($merge->getObsoleteMessages($domain) as $key => $translation) { - $messageDomain = array_key_exists($key, $resultMessages[$intlDomain] ?? []) ? $intlDomain : $domain; + $messageDomain = \array_key_exists($key, $resultMessages[$intlDomain] ?? []) ? $intlDomain : $domain; $meta = $this->getMetadata($result, $key, $messageDomain); $meta->setState('obsolete'); @@ -147,13 +147,13 @@ private function convertSourceLocationsToMessages( continue; } - $intlDomain = $domain . '+intl-icu' /* MessageCatalogueInterface::INTL_DOMAIN_SUFFIX */; + $intlDomain = $domain.'+intl-icu' /* MessageCatalogueInterface::INTL_DOMAIN_SUFFIX */; $key = $sourceLocation->getMessage(); - if (array_key_exists($key, $currentMessages[$intlDomain] ?? [])) { + if (\array_key_exists($key, $currentMessages[$intlDomain] ?? [])) { $messageDomain = $intlDomain; - } elseif (array_key_exists($key, $currentMessages[$domain] ?? [])) { + } elseif (\array_key_exists($key, $currentMessages[$domain] ?? [])) { $messageDomain = $domain; } else { // New translation From f2e80e0a65670e0bebd093e1b11676e342e73973 Mon Sep 17 00:00:00 2001 From: Marek Snopkowski Date: Thu, 24 Nov 2022 21:18:34 +0100 Subject: [PATCH 23/28] Apply PHP CS fixer automated fix --- DependencyInjection/Configuration.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index f883af1f..0de8fd2a 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -175,7 +175,7 @@ function ($format) { ) ->then( function (string $format) { - return \strtolower($format); + return strtolower($format); } ) ->end() From bc9bd5ff8e046782cd3eed92bfb8bdecef16b982 Mon Sep 17 00:00:00 2001 From: Marek Snopkowski Date: Thu, 24 Nov 2022 21:36:08 +0100 Subject: [PATCH 24/28] Fix main PHPUnit issue We're now providing getter method name for new field. --- Tests/Functional/Catalogue/CatalogueFetcherTest.php | 1 + Tests/Unit/Model/ConfigurationTest.php | 1 + 2 files changed, 2 insertions(+) diff --git a/Tests/Functional/Catalogue/CatalogueFetcherTest.php b/Tests/Functional/Catalogue/CatalogueFetcherTest.php index 234fb069..05f1026b 100644 --- a/Tests/Functional/Catalogue/CatalogueFetcherTest.php +++ b/Tests/Functional/Catalogue/CatalogueFetcherTest.php @@ -81,6 +81,7 @@ public static function getDefaultData(): array 'blacklist_domains' => ['getBlacklistDomains'], 'whitelist_domains' => ['getWhitelistDomains'], 'xliff_version' => ['getXliffVersion'], + 'new_message_format' => ['getNewMessageFormat'], ]; } diff --git a/Tests/Unit/Model/ConfigurationTest.php b/Tests/Unit/Model/ConfigurationTest.php index 7160b491..effee503 100644 --- a/Tests/Unit/Model/ConfigurationTest.php +++ b/Tests/Unit/Model/ConfigurationTest.php @@ -56,6 +56,7 @@ public static function getDefaultData(): array 'blacklist_domains' => ['getBlacklistDomains'], 'whitelist_domains' => ['getWhitelistDomains'], 'xliff_version' => 'getXliffVersion', + 'new_message_format' => 'getNewMessageFormat', ]; } } From 1e099ec2668cfc14806cae2fc6032fb72c4606e7 Mon Sep 17 00:00:00 2001 From: Marek Snopkowski Date: Thu, 24 Nov 2022 22:43:41 +0100 Subject: [PATCH 25/28] Fix catalogue counter --- Catalogue/CatalogueCounter.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Catalogue/CatalogueCounter.php b/Catalogue/CatalogueCounter.php index f3636156..14e838f3 100644 --- a/Catalogue/CatalogueCounter.php +++ b/Catalogue/CatalogueCounter.php @@ -57,7 +57,9 @@ public function getCatalogueStatistics(MessageCatalogueInterface $catalogue): ar $result[$domain]['approved'] = 0; foreach ($catalogue->all($domain) as $key => $text) { - $metadata = new Metadata($catalogue->getMetadata($key, $domain)); + $intlDomain = $domain.'+intl-icu' /* MessageCatalogueInterface::INTL_DOMAIN_SUFFIX */; + $rawMetadata = $catalogue->getMetadata($key, $domain) ?: $catalogue->getMetadata($key, $intlDomain); + $metadata = new Metadata($rawMetadata); $state = $metadata->getState(); if ('new' === $state) { ++$result[$domain]['new']; From 4116221bf2289ee49fddc1cfebb68d4ee3bcc81e Mon Sep 17 00:00:00 2001 From: Marek Snopkowski Date: Thu, 24 Nov 2022 22:44:02 +0100 Subject: [PATCH 26/28] Make assertion more wordy --- Tests/Functional/Command/ExtractCommandTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/Functional/Command/ExtractCommandTest.php b/Tests/Functional/Command/ExtractCommandTest.php index 29574436..e16f2ea8 100644 --- a/Tests/Functional/Command/ExtractCommandTest.php +++ b/Tests/Functional/Command/ExtractCommandTest.php @@ -111,9 +111,9 @@ public function testExecute(): void } $meta = new Metadata($catalogue->getMetadata('not.in.source')); - $this->assertTrue('obsolete' === $meta->getState()); + self::assertSame('obsolete', $meta->getState(), 'Expect meta state to be correct'); $meta = new Metadata($catalogue->getMetadata('translated.title')); - $this->assertTrue('new' === $meta->getState()); + self::assertSame('new', $meta->getState(), 'Expect meta state to be correct'); } } From cabf00a25f72cd94988853687bbb57c30dff5011 Mon Sep 17 00:00:00 2001 From: Marek Snopkowski Date: Thu, 24 Nov 2022 22:45:12 +0100 Subject: [PATCH 27/28] Update configuration to have passing tests Add new ICU messages domain. Make sure configuration is set to before-the-modification configuration. New messages will not be added to ICU domain. An additional tests must be run with new option set to ICU. This however may require functional tests refactor. --- .../Functional/Command/StatusCommandTest.php | 6 ++--- .../app/Resources/translations/.gitignore | 1 + .../translations/messages+intl-icu.en.xlf | 27 +++++++++++++++++++ .../Functional/app/config/normal_config.yaml | 2 ++ 4 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 Tests/Functional/app/Resources/translations/messages+intl-icu.en.xlf diff --git a/Tests/Functional/Command/StatusCommandTest.php b/Tests/Functional/Command/StatusCommandTest.php index 0733eb81..d113fefd 100644 --- a/Tests/Functional/Command/StatusCommandTest.php +++ b/Tests/Functional/Command/StatusCommandTest.php @@ -55,9 +55,9 @@ public function testExecute(): void $this->assertArrayHasKey('new', $total); $this->assertArrayHasKey('obsolete', $total); $this->assertArrayHasKey('approved', $total); - $this->assertEquals(2, $total['defined']); - $this->assertEquals(1, $total['new']); + $this->assertEquals(4, $total['defined']); + $this->assertEquals(2, $total['new']); $this->assertEquals(0, $total['obsolete']); - $this->assertEquals(1, $total['approved']); + $this->assertEquals(2, $total['approved']); } } diff --git a/Tests/Functional/app/Resources/translations/.gitignore b/Tests/Functional/app/Resources/translations/.gitignore index 1351b683..c716ed44 100644 --- a/Tests/Functional/app/Resources/translations/.gitignore +++ b/Tests/Functional/app/Resources/translations/.gitignore @@ -1,2 +1,3 @@ +messages+intl-icu.sv.xlf messages.sv.xlf *~ diff --git a/Tests/Functional/app/Resources/translations/messages+intl-icu.en.xlf b/Tests/Functional/app/Resources/translations/messages+intl-icu.en.xlf new file mode 100644 index 00000000..8885246b --- /dev/null +++ b/Tests/Functional/app/Resources/translations/messages+intl-icu.en.xlf @@ -0,0 +1,27 @@ + + + + + + new + true + user login + + + key2 + trans2 + + + + + Resources/views/translated.html.twig:12 + file-source + status:new + + + key3 + trans3 + + + + diff --git a/Tests/Functional/app/config/normal_config.yaml b/Tests/Functional/app/config/normal_config.yaml index fbc00d2e..bb83d961 100644 --- a/Tests/Functional/app/config/normal_config.yaml +++ b/Tests/Functional/app/config/normal_config.yaml @@ -9,7 +9,9 @@ translation: dirs: ["%test.project_dir%/Resources/views"] output_dir: "%test.project_dir%/Resources/translations" project_root: "%test.project_dir%" + new_message_format: '' app_with_transchoice: dirs: ["%test.project_dir%/Resources/views_with_transchoice"] output_dir: "%test.project_dir%/Resources/translations" project_root: "%test.project_dir%" + new_message_format: '' From 4c52eec420380ea14c9a9fc1ca49b0d3354815c7 Mon Sep 17 00:00:00 2001 From: Marek Snopkowski Date: Wed, 11 Jan 2023 15:59:47 +0100 Subject: [PATCH 28/28] Apply PHP-CS-Fixer suggestion --- Catalogue/CatalogueCounter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Catalogue/CatalogueCounter.php b/Catalogue/CatalogueCounter.php index 14e838f3..f1b4747b 100644 --- a/Catalogue/CatalogueCounter.php +++ b/Catalogue/CatalogueCounter.php @@ -57,7 +57,7 @@ public function getCatalogueStatistics(MessageCatalogueInterface $catalogue): ar $result[$domain]['approved'] = 0; foreach ($catalogue->all($domain) as $key => $text) { - $intlDomain = $domain.'+intl-icu' /* MessageCatalogueInterface::INTL_DOMAIN_SUFFIX */; + $intlDomain = $domain.'+intl-icu' /* MessageCatalogueInterface::INTL_DOMAIN_SUFFIX */; $rawMetadata = $catalogue->getMetadata($key, $domain) ?: $catalogue->getMetadata($key, $intlDomain); $metadata = new Metadata($rawMetadata); $state = $metadata->getState();