Peter
Peter

Reputation: 2711

how change locale in email being sent from controller - laravel 5.4

I am successfully sending emails with this piece of code:

 \App::setLocale('pl');
 Mail::send('emails.new_'.$itemtype, ['object' => $object, 'email' =>     $email_recipee], function ($m) use ( $email_recipee, $object, $itemtype) {
 $m->to($email_recipee, 'Title')->subject(' Subject of email');
 //
 });

But the emails are translated to en, the default language of the app.

My question

How make Laravel send email with a locale declared just for a particular email (each recipient has a different language set).

What I tried:

dirty (?) solution

For now I just add a line inside the email view:

{{ \App::setLocale($lead->client->lang)}}

Any better way to do it? Thank you.

Upvotes: 10

Views: 13458

Answers (4)

Adam
Adam

Reputation: 29059

Update: Since Laravel 5.7 you can use localize mailables:

Mail::to($request->user())->locale('es')->send(
    new OrderShipped($order)
);

Before Laravel 5.7:

What you proposed should work. Just change the locale before sending the mail. However you should be sure to reset the locale:

$temp = \App::getLocale();
\App::setLocale($user->language);
\Mail::to($user)->send(new OrderShipped($order));
\App::setLocale($temp);

Since this is a bit bloated you could simplify that to

\App\Mail\SendMail::to($user, '\App\Mail\OrderShipped', [$order]);

if you create the following SendMail class:

<?php

namespace App\Mail;

use App\User;

class SendMail
{

  /**
   * Send Mail to correct emailadress and set correct language
   * @param  User   $user
   * @param  String $classname
   * @param  Array  $data
   * @return void
   */
  public static function to(User $user, String $class, Array $params)
  {
    $temp = \App::getLocale();
    \App::setLocale($user->lang);

    $reflection_class = new \ReflectionClass($class);
    $mailclass = $reflection_class->newInstanceArgs($params);

    \Mail::to($user)->send($mailclass);

    \App::setLocale($temp);
  }
}

Maybe its also usefull to know that you can get your language content also without setLocale . For instance __('birthday_parole', [], 'pl') will try to give you the polish version, despite the settings of setLocale.

Upvotes: 4

jacek.ciach
jacek.ciach

Reputation: 1042

TL;DR: Just set a $locale field in an object of Mailable class:

class ResetPassword extends Mailable
{
   // ...

    /**
     * Create a new message instance.
     */
    public function __construct(User $user, string $token)
    {
        $this->user = $user;
        $this->token = $token;
        /*
         * Set locale of mail to User's locale
         */
        $this->locale = $this->user->locale; // <-- of course adapt this line to YOUR User model :]
    }

Long story:

There is a trait Localizable. It declares a method withLocale that calls a given function "enveloped" in a specified locale. By "enveloping" I mean: remember a current locale, set a new locale, call a function, restore the remembered locale.

An example of usage can be found in \Illuminate\Mail\Mailable::send:

public function send(MailerContract $mailer)
{
    return $this->withLocale($this->locale, function () use ($mailer) {
        Container::getInstance()->call([$this, 'build']);

        return $mailer->send($this->buildView(), $this->buildViewData(), function ($message) {
            $this->buildFrom($message)
                 ->buildRecipients($message)
                 ->buildSubject($message)
                 ->runCallbacks($message)
                 ->buildAttachments($message);
        });
    });
}

However, this method gives us a clue how to change a locale for a mail - in the first line there is $this->locale. Indeed, Mailable has this field defined:

class Mailable implements MailableContract, Renderable
{
   // ...

    /**
     * The locale of the message.
     *
     * @var string
     */
    public $locale;

Upvotes: 13

Brad Ahrens
Brad Ahrens

Reputation: 5168

For anyone using Laravel 6.* and viewing this post, it looks like things have changed more recently.

Now, you can define the locale within the controller itself, simply by adding ->locale() to the Mail.

For example:

Mail::to($request->user())->locale('es')->send(
    new OrderShipped($order)
);

For more information, please see the official documentation.

Happy coding!

Upvotes: 8

Marco Cazzaro
Marco Cazzaro

Reputation: 701

You can use the Mailable class Docs In the constructor __construct(User $user) you can type hint the user, and set the locale from there:

            <?php

            namespace App\Mail;

            use Illuminate\Bus\Queueable;
            use Illuminate\Mail\Mailable;
            use Illuminate\Queue\SerializesModels;
            use Illuminate\Contracts\Queue\ShouldQueue;
            use App\User;

            class Welcome extends Mailable
            {
                use Queueable, SerializesModels;

                protected $user;

                /**
                 * Create a new message instance.
                 *
                 * @return void
                 */
                public function __construct(User $lead)
                {
                    \App::setLocale($lead->client->lang);
                    $this->user = $lead;
                    $this->subject = trans('welcome_title');
                }

                /**
                 * Build the message.
                 *
                 * @return $this
                 */
                public function build()
                {
                    return $this->view('emails.welcome')->with('user', $this->user);
                }
            }

Upvotes: 1

Related Questions