-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Translation] correctly handle intl domains with TargetOperation #42361
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…Commands (acran) This PR was merged into the 5.4 branch. Discussion ---------- [FrameworkBundle] remove dead conditions in Translation Commands | Q | A | ------------- | --- | Branch? | 5.4 | Bug fix? | no | New feature? | no | Deprecations? | no | Tickets | - | License | MIT | Doc PR | - This is just a trivial removal of unused code I stumbled upon while debugging #42361. In the [original code](https://github.com/symfony/symfony/blob/e617a9b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php#L165-L170): ~~~php $transPaths = [$path.'/translations']; $codePaths = [$path.'/templates']; if (!is_dir($transPaths[0]) && !isset($transPaths[1])) { throw new InvalidArgumentException(sprintf('"%s" is neither an enabled bundle nor a directory.', $transPaths[0])); } ~~~ The second part of the condition `isset($transPaths[1])` will **always** evaluate to true, since `$targetPath` is just set 3 lines above but only has a single element. This check was originally to support legacy paths which was removed in b6eb1f4: * in [`TranslationDebugCommand.php`](b6eb1f4#diff-67afa5b8860d0df4e44f1e1fc89f444b7ac77de515b698a6824dd5403a0acdbcL187-L194) * in [`TranslationUpdateCommand.php `](b6eb1f4#diff-a01c7858e84f1868a427634740511da7c8c73e56772baa78bdcd98200d7125c0L180-L187) Rebased from 5.3 to 5.4, see #42362 /cc `@fabpot` Commits ------- 22db5ad [FrameworkBundle] remove dead conditions in Translation Commands
/cc @yceruto |
@acran Could you add a unit test? |
I can try 🤓 Also digging a bit further in this I found though 33e6af5 was the commit that introduced the offending line it was actually just the result of refactorings and code style fixes and the problem was introduced in c71dfb9. Looking at that commit it definitely smells like a copy&paste mistake. |
@@ -71,13 +71,45 @@ public function testGetResultWithMixedDomains() | |||
{ | |||
$this->assertEquals( | |||
new MessageCatalogue('en', [ | |||
'messages+intl-icu' => ['a' => 'old_a'], | |||
'messages' => ['a' => 'old_a'], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is fixing the broken test by saying the test was wrong I now really need someone with a deep understanding of the code to look into this 🙈
But my reasoning for why this is actually the correct and intended behavior was:
Existing messages should always stay in their current domain. Moving new messages to the intl-icu domain is (at least in recent versions) handled by AbstractOperation::moveMessagesToIntlDomainsIfPossible()
, see
$operation->moveMessagesToIntlDomainsIfPossible('new'); |
symfony/src/Symfony/Component/Translation/Catalogue/AbstractOperation.php
Lines 157 to 183 in 1629b59
public function moveMessagesToIntlDomainsIfPossible(string $batch = self::ALL_BATCH): void | |
{ | |
// If MessageFormatter class does not exists, intl domains are not supported. | |
if (!class_exists(\MessageFormatter::class)) { | |
return; | |
} | |
foreach ($this->getDomains() as $domain) { | |
$intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX; | |
switch ($batch) { | |
case self::OBSOLETE_BATCH: $messages = $this->getObsoleteMessages($domain); break; | |
case self::NEW_BATCH: $messages = $this->getNewMessages($domain); break; | |
case self::ALL_BATCH: $messages = $this->getMessages($domain); break; | |
default: throw new \InvalidArgumentException(sprintf('$batch argument must be one of ["%s", "%s", "%s"].', self::ALL_BATCH, self::NEW_BATCH, self::OBSOLETE_BATCH)); | |
} | |
if (!$messages || (!$this->source->all($intlDomain) && $this->source->all($domain))) { | |
continue; | |
} | |
$result = $this->getResult(); | |
$allIntlMessages = $result->all($intlDomain); | |
$currentMessages = array_diff_key($messages, $result->all($domain)); | |
$result->replace($currentMessages, $domain); | |
$result->replace($allIntlMessages + $messages, $intlDomain); | |
} | |
} |
This Test was introduced in b72b7d3 which also should only have affected new messages. So was in my interpretation already wrong at that point.
)->getResult() | ||
); | ||
|
||
$this->assertEquals( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is testing the behavior when merging with new messages and mixed domains. Should this be moved into a separate function/test case? Or is it OK to have it all in the same function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer a data provider with some explanations for each data, but this is only a recommendation.
Any progress on this? Who could best review this PR?? |
Thank you @acran. |
@acran Could you do a follow-up PR to take into account @OskarStark's suggestion about documenting the tests? |
Executing
translations:update
with--clean
was producing erratic result: creating duplicate non-/intl files for domains, removing used translations...TL;DR: judging from context this was most probably just a typo in 33e6af5
How to reproduce
Setup Test Project
A fresh minimal project to verify this can be setup with
composer create-project symfony/skeleton translations_test cd translations_test/ composer require translation
and adding extractable translations into a file in
src/
, e.g.Otherwise any existing project should work as well.
Steps to reproduce
Case 1: duplicate translation files
Case 2: lost translations
The Fix
The previous code was trying to merge with the
target
messages instead of thesource
. This was probably just a typo since$keyMetadata
is take fromsource
just below it and theforeach
block below which is basically doing the same inverse just switchestarget
andsource
.Also the code is mostly identical to
MergeOperation
which also usessource
at the respective line.The code in both files was introduced in 33e6af5