Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
667 views
in Technique[技术] by (71.8m points)

php - How to translate emails when sending them asynchronously with Symfony Messenger?

I configured the Symfony mailer to send emails with messenger.

https://symfony.com/doc/current/mailer.html#sending-messages-async

I have my emails in two languages and I rely on the requests to detect the language, but now the emails are not translated.

How can I get the messages to be translated in the language detected in the request?

In my controller:

$mailer->send(
            $user->email,
            $this->translator->trans('mails.recover.subject'),
            'email/client/password-recovery.html.twig',
            compact('user', 'hash', 'target')
        );

Template:

{% extends 'email/base.html.twig' %}

{% block content %}
    <h2>{{ 'mails.recover.header' | trans({'%name%': user.name}) }}</h2>

    <p style="margin: 25px 0;">
        {{ 'mails.recover.text1' | trans({'%url%': url('default')}) | raw }}
    </p>

// More code

Messenger config:

framework:
    messenger:
        # Uncomment this (and the failed transport below) to send failed messages to this transport for later handling.
        # failure_transport: failed

        transports:
            # https://symfony.com/doc/current/messenger.html#transport-configuration
            async: '%env(MESSENGER_TRANSPORT_DSN)%'
            # failed: 'doctrine://default?queue_name=failed'
            # sync: 'sync://'

        routing:
            # Route your messages to the transports
            # 'AppMessageYourMessage': async
            'SymfonyComponentMailerMessengerSendEmailMessage':  async

Looking better the subject of the mail if it is translated correctly, the body of the mail does not

If I remove the line

'SymfonyComponentMailerMessengerSendEmailMessage':  async

in messegner config, translation work.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The problem you have is that the Symfony Translator component gets the user's locale form the incoming request, and when sending your mails asynchronously by the time the mail is actually sent the request is long finished and gone, and then the context the message consumer (command line) and there is no request locale information.

There are two solutions for this:

First Option: You pass the values already translated to the template (which is what you are doing with the email subject).

E.g. something like this:

$mailer->send(
        $user->email,
        $this->translator->trans('mails.recover.subject'),
        'email/client/password-recovery.html.twig',
            [
                'user' => $user,
                'hash' => $hash,
                'target' => $target,
                'labels' => [
                  'header' => $this->translator
                                   ->trans('mails.recover.subject', [ 'name' => $user->getName()]),
                  'text1'  => $this->translator
                                    ->trans('mails.recover.text1', ['url', => $defaulUrl])
            ]
);

And then in your template you use the values directly:

{% extends 'email/base.html.twig' %}

{% block content %}
    <h2>{{ texts.header }}</h2>
    <p style="margin: 25px 0;">{{ texts.text1 }}</p>
{% endblock %}

This would be my preferred approach, since it makes the template as dumb as possible and easy to reuse in different contexts. The templates themselves do not need to know anything not pertaining the actual rendering of its content.

Second Option: Let the templating system know what user locale you want to translate to:

$mailer->send(
        $user->email,
        $this->translator->trans('mails.recover.subject'),
        'email/client/password-recovery.html.twig',
            [
                'user'   => $user,
                'hash'   => $hash,
                'target' => $target,
                'requestLocale' =>  $locale
                // get the locale from the request
                // (https://symfony.com/doc/current/translation/locale.html)
            ]
);

Then you use the received locale in the filter you are using, as described here:

<h2>{{ 'mails.recover.header' | trans({'%name%': user.name}, 'app', requestLocale) }}</h2>

While I prefer the first one, playing with either option should let you get your desired results.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...