翻译排队的邮件(本地化)

Translate queued mails (localization)

我正在寻找一个可行的解决方案,翻译 中排队的电子邮件。 不幸的是,所有电子邮件都使用 默认区域设置 (在 app.locale 下定义)。

假设,我们在 管道 中有两封电子邮件,一封给英语 en 用户,另一封给日语 jp 用户。

我应该将什么数据传递到 Mail 门面以 翻译(本地化)排队的电子邮件

  // User model
  $user = User:find(1)->first();

  Mailer::queue($email, 'Party at Batman\'s cave (Batcave)', 'emails.party-invitation', [

    ...

    'locale' => $user->getLocale(), // value: "jp", but does not work
    'lang' => $user->getLocale(), // value: "jp", but does not work
    'language' => $user->getLocale(), // value: "jp", but does not work
  ]);

我遇到了同样的问题

在不扩展队列的情况下class最快/最肮脏的解决方案是为每个语言环境创建一个电子邮件模板。

然后当您创建队列时,select 本地模板即

Mail::queue('emails.'.App::getLocale().'notification', function($message) 
{
    $message->to($emails)->subject('hello');
});

如果本地设置为 IT(意大利语)这将加载视图 emails/itnotification。blade.php

正如我所说...脏!

因为这个方法实在是太可怕了所以才遇到的this answer 它对我有用,你实际上将电子邮件的整个翻译 html 版本发送到队列中,并有一个空白的 blade 文件在队列运行时回显变量。

我一直在努力以更有效的方式完成这项工作。目前我已经这样设置了。希望这对将来解决此问题的人有所帮助:

// Fetch the locale of the receiver.
$user = Auth::user();
$locale = $user->locale;
Mail::queue('emails.welcome.template', ['user' => $user, 'locale' => $locale], function($mail) use ($user, $locale) {
     $mail->to($user->email);
     $mail->subject(
          trans(
               'mails.subject_welcome',
               [], null, $locale
          )
     );
});

并在您的模板中使用以下内容:

{{ trans('mails.welcome', ['name' => ucfirst($user['first_name'])], null, $locale) }}

注意:不要忘记重启队列

如果您的电子邮件继承了内置 Illuminate\Mail\Mailable class,您可以构建自己的 Mailable class 来处理翻译。

创建您自己的 SendQueuedMailable class,继承自 Illuminate\Mail\SendQueuedMailable。 Class 构造函数将从配置中获取当前 app.location 并将其记住在 属性 中(因为 laravel 队列将其序列化)。 在队列工作者中,它将从配置中取回 属性 并将设置设置为当前环境。

<?php

namespace App\Mail;

use Illuminate\Contracts\Mail\Mailer as MailerContract;
use Illuminate\Contracts\Mail\Mailable as MailableContract;
use Illuminate\Mail\SendQueuedMailable as IlluminateSendQueuedMailable;

class SendQueuedMailable extends IlluminateSendQueuedMailable
{
    protected $locale;

    public function __construct(MailableContract $mailable)
    {
        parent::__construct($mailable);

        $this->locale = config('app.locale');
    }

    public function handle(MailerContract $mailer)
    {
        config(['app.locale' => $this->locale]);
        app('translator')->setLocale($this->locale);

        parent::handle($mailer);
    }
}

然后,创建您自己的 Mail class 继承自 Illuminate\Mail\Mailable

<?php

namespace App\Mail;

use Illuminate\Contracts\Queue\Factory as Queue;
use Illuminate\Mail\Mailable as IlluminateMailable;

class Mailable extends IlluminateMailable
{
    public function queue(Queue $queue)
    {
        $connection = property_exists($this, 'connection') ? $this->connection : null;

        $queueName = property_exists($this, 'queue') ? $this->queue : null;

        return $queue->connection($connection)->pushOn(
            $queueName ?: null, new SendQueuedMailable($this)
        );
    }
}

而且,瞧,从 App\Mailable class 继承的所有排队的邮件将自动处理当前的语言环境。

这是一个对我有用的解决方案。在我的示例中,我使用专用的 Job class.

在队列中处理预订

当您在队列中调度作业时,传递语言环境,您希望您的电子邮件进入。例如:

ProcessBooking::dispatch($booking, \App::getLocale());

然后,在您的作业中 class(在我的示例中为 ProcessBooking)将语言环境存储在 属性:

protected $booking;
protected $locale;

public function __construct(Booking $booking, $locale)
{
    $this->booking = $booking;
    $this->locale = $locale;
}

并在您的 handle 方法中临时切换语言环境:

public function handle()
{
    // store the locale the queue is currently running in
    $previousLocale = \App::getLocale();

    // change the locale to the one you need for job to run in
    \App::setLocale($this->locale);

    // Do the stuff you need, e.g. send an email
    Mail::to($this->booking->customer->email)->send(new NewBooking($this->booking));

    // go back to the original locale
    \App::setLocale($previousLocale);
}

为什么我们需要这样做?

排队的电子邮件获得默认语言环境,因为队列工作人员是单独的 Laravel 应用程序。如果你曾经 运行 遇到问题,当你清除缓存时,但排队 'stuff' (例如电子邮件)仍然显示旧内容,这是因为那个。这是来自 Laravel docs 的解释:

Remember, queue workers are long-lived processes and store the booted application state in memory. As a result, they will not notice changes in your code base after they have been started. So, during your deployment process, be sure to restart your queue workers.

在Laravel 5.6中是一个添加到Mailable的语言环境功能: $infoMail->local('jp'); Mail::queue($infoMail);

Laravel 5.7.7引入了HasLocalePreference界面来解决这个问题。

class User extends Model implements HasLocalePreference
{
    public function preferredLocale() { return $this->locale; }
}

现在,如果您使用 Mail::to() 函数,Laravel 将使用正确的区域设置发送。

还介绍了 Mail 可链接 locale() 函数。

Mail::to($address)->locale($locale)->send(new Email());

使用 preferredLocale() 是“官方”的方式。

您可以实施 HasLocalePreference 并将方法 preferredLocale() 添加到通知模型(如 @Peter-M 建议的那样):

use Illuminate\Contracts\Translation\HasLocalePreference;

class User extends Model implements HasLocalePreference
{
    /**
     * Get the user's preferred locale.
     *
     * @return string
     */
    public function preferredLocale()
    {
        return $this->locale;
    }
}

然后您只需将通知发送到该模型,区域设置将自动应用到您的电子邮件模板

$user->notify(new InvoicePaid($invoice));

这也适用于排队的邮件通知。

在此处阅读更多内容: https://floyk.com/en/post/how-to-change-language-for-laravel-email-notifications