- Issue created by @Wouter Waeytens
- ๐ฌ๐งUnited Kingdom adamps
I don't think that's the right way to do translation. The email body and subject come from a config entity. Instead you should use the Drupal mechanism for translations of config.
- Status changed to Closed: works as designed
over 1 year ago 9:41am 2 August 2023 - Status changed to Active
10 months ago 8:42am 31 January 2024 - ๐ฉ๐ชGermany Patrick R.
While the proposed patch is certainly not the way to go the problem with mails being sent in the wrong language when using adjusters like SubjectEmailAdjuster or BodyEmailAdjuster still persists. The adjuster plugins are already instantiated during initEmail() in the EmailFactory class which is happening quite some time before the eventual language switch might happen in Mailer::doSend(), so there's no way to get mails sent in the correct language using these adjusters even when using config translation properly. Not seeing a simple solution for this though. :-/
- ๐ฉ๐ชGermany Patrick R.
Added the following as a workaround to my email builder plugin. Not overly pretty, but it seems to work. ๐คท๐ปโโ๏ธ
/** * {@inheritdoc} */ public function preRender(EmailInterface $email) { $adjusters = ['email_body', 'email_subject']; $suggestions = $email->getSuggestions('', '.'); $adjuster_manager = \Drupal::service('plugin.manager.email_adjuster'); $policy_config = MailerPolicy::loadInheritedConfig(end($suggestions)); foreach ($policy_config as $plugin_id => $config) { if (in_array($plugin_id, $adjusters) && $adjuster_manager->hasDefinition($plugin_id)) { $adjuster_manager->createInstance($plugin_id, $config)->build($email); } } }
- ๐ฆ๐บAustralia mingsong ๐ฆ๐บ
I tested this issue with
Drupal 10.2.3
Symfony Mailer 1.4.1And two issues I came across
- Imported policies didn't load the translation email content.
- Translate mailer policy wasn't applied to the email sent to the user in user's language.
- ๐ฆ๐บAustralia mingsong ๐ฆ๐บ
Right. after debugging the code, I think I figure out what is happening here.
In the Mailer::doSend() function,
https://git.drupalcode.org/project/symfony_mailer/-/blob/1.x/src/Mailer....
We have four phases to process an email.
In phase 'build', https://git.drupalcode.org/project/symfony_mailer/-/blob/1.x/src/Mailer....
The email body, subject and other contents were built in the default language since the configuration language hasn't been changed yet.
After that, the language will be changed to user's language at line 224
https://git.drupalcode.org/project/symfony_mailer/-/blob/1.x/src/Mailer....Next phase is 'PHASE_PRE_RENDER', in this phase, the $email->process() will call the 'preRend()' function for each email adjuster, including the subject and body adjuster.
BodyEmailAdjuster https://git.drupalcode.org/project/symfony_mailer/-/blob/1.x/src/Plugin/...
SubjectEmailAdjuster https://git.drupalcode.org/project/symfony_mailer/-/blob/1.x/src/Plugin/...But the problem is that those email address doesn't have the preRend() fuction, so they won't change anything. The email subject and body still remain in the default language.
And so on, after this stage, all coming phase won't change the language at all.
So that is why the email will always be built in the default language of the website.
- ๐ฆ๐บAustralia mingsong ๐ฆ๐บ
Another problem with the translation of an email is that, the configuration of an adjuster plugin is loaded in the default language when the plugin is initiated.
Even if the languageManager->setConfigOverrideLanguage($language) is called after that, the configuration loaded before won't be changed, until the configuration is loaded again.So if I add the following preRender function to SubjectEmailAdjuster class,
public function preRender(EmailInterface $email) { $mail_config = \Drupal::config('symfony_mailer.mailer_policy.user.status_activated'); $config = $mail_config->get('configuration.email_subject'); if (isset($config['value'])) { $subject = $config['value']; } else { $subject = $this->configuration['value']; } $email->setSubject($subject, TRUE); }
Then the email subject is translated to the user language.
- ๐ฌ๐งUnited Kingdom adamps
Yes I feel that #6 and #10 both contain the seed of the solution. But both are hard-coded to a specific case of course we can't check them in as is.
- The problem could apply to many adjusters (the plain text body; the addresses have a display name; even the skip sending has a displayed message)
- And to any builderI propose that once we have chosen the language in Mailer.php then we should reload the policy with the correct language. The code that loaded them originally was in EmailFactory:
$this->emailAdjusterManager->applyPolicy($email);
However at the moment, Email::addProcessor() would also keep the original adjusters - they don't overwrite. We can fix that by changing the code to
$this->processors[$phase][$id] =
But we still have a problem that the subject/body are being used mainly in the build() function that had already run. We also need a fix to ๐ Change to the phases Active .
- ๐ฉ๐ชGermany Patrick R.
I propose that once we have chosen the language in Mailer.php then we should reload the policy with the correct language. The code that loaded them originally was in EmailFactory:
Might also be an idea to only instantiate adjuster plugins when they are applied during a certain phase and have the plugins use different phases - address adjusters should probably run earlier than e.g. subject or body adjusters since they could be responsible for determining the language of the email. SearchApiProcessor plugins use "stages" in their plugin annotations, maybe EmailAdjuster plugins should define "phases" in their annotations. ๐ค
- ๐ฌ๐งUnited Kingdom adamps
There is now a MR for ๐ Change to the phases Active . It should fix #9 but not #10. Review and testing very welcome please.
- ๐ฌ๐งUnited Kingdom adamps
I have written code that reloads the config at the start of the build phase.
It's in a 2nd MR https://git.drupalcode.org/project/symfony_mailer/-/merge_requests/106. It's on the other issue, because it depends on that first fix and I could see any way to link between one fork and another.
I haven't tested it as I don't use multi-lingual on any sites, and I'm not familiar with how to set it up. However I have run some basic testing to see that the code that should reload the config is being executed.
- ๐ซ๐ฎFinland oakulm
Great news! I can see that the patch applies to 1.x-dev and emails are being sent in user preferred language. Subject and body are both working and fallback language is also working if there's no translation.
For someone to verify go to admin/config/system/mailer/test translate the test email policy, add email of existing user to recipient email address field and hit send. Also make sure the user prefered language is correct in user edit page.
I also made custom email policy and it seems to work as well. I'm not familiar with 2.x-dev branch and have not tested on that.
-
adamps โ
committed 93829480 on 2.x
Issue #3372166 by adamps, Wouter Waeytens, patrick r., mingsong, oakulm...
-
adamps โ
committed 93829480 on 2.x
- ๐ซ๐ฎFinland oakulm
Sorry to come back to this but for some reason the patch does not apply anymore to 1.5. Not exactly sure why it was working before. But the problem is here: https://git.drupalcode.org/project/symfony_mailer/-/merge_requests/107/d... in src/EmailFactory.php
I can make the patch apply cleanly with this change but the code itself does not seem to work.
diff --git a/src/EmailFactory.php b/src/EmailFactory.php index 53e6be0..e7a0714 100644 --- a/src/EmailFactory.php +++ b/src/EmailFactory.php @@ -96,9 +96,7 @@ class EmailFactory implements EmailFactoryInterface { } // Apply policy. - $this->emailAdjusterManager->applyPolicy($email); - - $email->initDone(); + $email->addProcessor($this->emailAdjusterManager); return $email; }
addProcessor expects callable as a param. Any ideas?
- ๐ฌ๐งUnited Kingdom adamps
This bug has been fixed in 2.x, so I like to keep the issue summary clear and correct for that please.
I am willing to do a backport. Please create a separate issue that includes the working MR for 1.x. Please don't just create the issue and expect that someone else will do the work๐. The backport issue without the MR is just an annoyance for the maintainer.