Transfer mail (localization) in the queue

I am looking for a working solution to queue emails in . Unfortunately, all emails use a standard locale (defined in app.locale ).

Suppose we have two letters in the pipeline: one for the English user en and the other for the Japanese user jp .

What data should I go to the Mail facade to translate (localize) messages in the queue ?

  // User model $user = User:find(1)->first(); Mailer::queue($email, 'Party at Batman\ 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 ]); 
+6
source share
6 answers

I tried my best to do it in a more efficient way. Currently I configured it like this. Hope this helps someone solve this problem in the future:

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

And use the following in your template:

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

If your emails inherit the built-in Illuminate\Mail\Mailable , you can create your own Mailable class that takes care of translations.

Create your own SendQueuedMailable class, which inherits from Illuminate\Mail\SendQueuedMailable . The class constructor will use the current app.location from config and remember it in the property (because laravel queues serialize it). In the queue desktop, it will return the property from the configuration and set it to the current environment.

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

Then create your own Mail class, which inherits from 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) ); } } 

And voila, all your mailing lists inherited from the App\Mailable class will automatically take care of the current locale.

+3
source

In Laravel 5.6, a locale function has been added to Mailable: $ infoMail-> locale ('jp'); Mail :: queues ($ infoMail);

+3
source

Here is a solution that worked for me. In my example, I process an order in a queue using the selected Job class.

When you submit the task to the queue, skip the locale, you want your email address to be. For instance:

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

Then in your job class ( ProcessBooking in my example) save the locale in the property:

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

And in your handle method, temporarily switch the locales:

 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, eg send an email Mail::to($this->booking->customer->email)->send(new NewBooking($this->booking)); // go back to the original locale \App::setLocale($previousLocale); } 

Why do we need this?

The email queue receives the default locale because the queue workers are separate Laravel applications. If you ever had a problem when you cleared your cache, but in the queue β€œthings” (for example, emails) still showed the old content, because of this. Here's an explanation from the Laravel docs :

Remember that work queues are long-lived processes and store the state of a loaded application in memory. As a result, they will not notice changes in the code base after they are launched. Therefore, be sure to restart your queue employees during the deployment process.

0
source

In Laravel 5.7.7, the HasLocalePreference interface HasLocalePreference to solve this problem.

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

Now, if you use the Mail::to() function, Laravel will send with the correct language.

In addition, the Mail chain locale() function was introduced.

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

I faced the same problem

Without extending the queue class, the fastest / dirtiest solution would be to create an email template for each locale.

Then, when you create the queue, select the local template ie

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

If locally set to IT (italian), this will load emails of the form /itnotification.blade.php

Like I said ... dirty!

Since this method is really terrible, I came across this answer And it works for me, you actually send the entire translated html version of the email to the variable in the queue and have an empty blade file that allocates the variable when the queue starts.

-1
source

Source: https://habr.com/ru/post/1214776/


All Articles