Problem/Motivation

When blocking or activating a user as admin the mails are not send in the user's preferred language.

Steps to reproduce

Go to the user overview.
Go the the edit page of a user.
Select a preferred language for the user other than the default site language.
Block the user.

User wil get a mail in the site default language.

Proposed resolution

Make sure the config translations of the policies are being loaded in the adjuster plugins.

Remaining tasks

User interface changes

API changes

Data model changes

CommentFileSizeAuthor
#2 3372166.patch1.09 KBwouter waeytens
Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

Wouter Waeytens created an issue. See original summary.

wouter waeytens’s picture

StatusFileSize
new1.09 KB
adamps’s picture

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.

adamps’s picture

Status: Active » Closed (works as designed)
patrick r.’s picture

Version: 1.2.1 » 1.x-dev
Priority: Normal » Major
Status: Closed (works as designed) » Active
Issue tags: +multilingual

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. :-/

patrick r.’s picture

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);
    }
  }
}

adamps’s picture

Ah good point thanks for the update.

mingsong’s picture

I tested this issue with
Drupal 10.2.3
Symfony Mailer 1.4.1

And two issues I came across

  1. Imported policies didn't load the translation email content.
  2. Translate mailer policy wasn't applied to the email sent to the user in user's language.
mingsong’s picture

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 adjusters do not have the preRend() function, so nothing will be changed. The email subject and body still remain in the default language.

And so on, after this stage, all coming phases won't change the language at all.

So that is why the email will always be built in the default language of the website.

mingsong’s picture

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,
https://git.drupalcode.org/project/symfony_mailer/-/blob/1.x/src/Plugin/...

  public function preRender(EmailInterface $email) {
    $mail_config = \Drupal::config('symfony_mailer.mailer_policy.user.status_activated');
    // Load the configuration again in the changed language .
    $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's language.

adamps’s picture

Title: Mails not being send in user preferred language. » Mails not being send in user preferred language

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 builder

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:

    $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 #3421400: Change to the phases.

patrick r.’s picture

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. 🤔

adamps’s picture

There is now a MR for #3421400: Change to the phases. It should fix #9 but not #10. Review and testing very welcome please.

adamps’s picture

Status: Active » Needs review

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.

adamps’s picture

Version: 1.x-dev » 2.x-dev

MR here is now ready for review

oakulm’s picture

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’s picture

Status: Needs review » Fixed

Great thanks

oakulm’s picture

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 was looking at the wrong diff, so ignore this for now. This is the correct diff when applying the fix to 1.x branch https://git.drupalcode.org/issue/symfony_mailer-3372166/-/compare/1.x......

rfbrandsma’s picture

Status: Fixed » Needs work
Issue tags: -multilingual +needs backport to 1.x
adamps’s picture

Status: Needs work » Fixed
Issue tags: -needs backport to 1.x

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.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.