Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

kendrick's avatar

Passing locale to all queued Mails?

When I queue a Mail like:

dispatch(new Verify($user)); 

I forgot to add the language of the session.

Now, I could request the session's language in front of every dispatch and pass $language to the queue:

if ($request->session()->has('lang') && $request->session()->get('lang') === 'en') {   
        $language = 'en';
    } elseif ($request->session()->has('lang') && $request->session()->get('lang') === 'es') {
        $language = 'es';
    } else {
        $language = 'en';
}

dispatch(new Verify($user, $language)); 

and then reference it within the Jobs:

Mail::to($this->user->email)->locale($language)->send($email);

That would be no problem, but a bit repetitive. Is there a path, where I would not have to add $language to every dispatch in every Controller?

0 likes
29 replies
kendrick's avatar

@bezhansalleh - I have a Langauge.php Middleware. How could I trigger the queue factor in it?

if(auth()->user()->language_id == 1) {
    Carbon::setLocale('en');
    $request->session()->put('lang', 'en');
} elseif(auth()->user()->language_id == 2) {
    Carbon::setLocale('es');
    $request->session()->put('lang', 'es');
}

\App::setLocale($request->session()->get('lang'));
 return $next($request);
BezhanSalleh's avatar

@splendidkeen i don't get the whole picture but as far as i can understand it, you are dispatching a verification job which then sends an email based on the user's locale right? if so you can dispatch the job in the RedirectIfAuthenticated middleware which already ships with laravel. or in your Language middleware.

as i said i don't have the whole picture what you are trying to accomplish here... hope my answer gets you one step closer though...

kendrick's avatar

@bezhansalleh - I am just trying to send Mails in the correct language, when logged in. Through my Language.php middleware I check on the language_id of the User. Currently all Mails sent through the queue are in English, even if the User's language is e.g. 'es' (language_id = 2). If I dd($language), I get 'es' correctly.

As the Mails are still send in English, I asked if there is a way to add the $language to the Job, other than adjusting every Job and dispatch.

kendrick's avatar

@bezhansalleh - Thank you, I created the job middleware:

public function handle($job, $request, Closure $next)
{
        if ($request->session()->has('lang') && $request->session()->get('lang') === 'en') {   
            $language = 'en';
        } elseif ($request->session()->has('lang') && $request->session()->get('lang') === 'es') {
            $language = 'es';
        } else {
            $language = 'en';
        }

        $job->locale($language);
}

added it to the Job:

public function middleware()
{
	return [new Language];
}

and currently am seeing: FatalThrowableError: Too few arguments to function App\Jobs\Middleware\Language::handle(), 2 passed in and exactly 3 expected

BezhanSalleh's avatar

@splendidkeen that's becuase you didn't implemented right... anyway go throught the docs and maybe find another examples but basically your middleware should look somthing like this.

public function handle($job, $next)
{
        if ($request->session()->has('lang')  &&  $request->session()->get('lang') === 'es') {
            $language = 'es'; 
        } else {
            $language = 'en';
        }

        $job->locale($language);

	$next($job);
}

so you check your session and set the job locale and then it gets the next job so on and forth....

kendrick's avatar

@bezhansalleh - Thank you for coming back.

This one returns ErrorException: Undefined variable: request. If I add public function handle($job, $next, $request) it returns Symfony\Component\Debug\Exception\FatalThrowableError: Too few arguments to function

BezhanSalleh's avatar

@splendidkeen try this

public function handle($job, $next)
{
        if (request()->session()->has('lang')  &&  request()->session()->get('lang') === 'es') {
            $language = 'es'; 
        } else {
            $language = 'en';
        }

        $job->locale($language);

	$next($job);
}
BezhanSalleh's avatar

@splendidkeen apologies on mobile device ... anyways you can shorten the code even more... try it now... btw make sure that your route middleware triggers the session condition first...

public function handle($job, $next)
{
        if (session()->has('lang')  &&  session('lang') === 'es') {
            $language = 'es'; 
        } else {
            $language = 'en';
        }

        $job->locale($language);

	$next($job);
}
kendrick's avatar

@bezhansalleh - Now it returns Symfony\Component\Debug\Exception\FatalThrowableError: Call to undefined method App\Jobs\user\SendExampleMail::locale()

on this line in the middleware: $job->locale($language);

BezhanSalleh's avatar

@splendidkeen let me see the code for this job Verify($user, $language) you might not even need the middleware you might need on trait to use it in your jobs so it would set the locale for all your jobs... just post the code for the Verify job....

kendrick's avatar

Controller

if ($request->session()->has('lang') && $request->session()->get('lang') === 'es') {
        $language = 'es';
    } else {
        $language = 'en';
}

dispatch(new Verify($user, $language)); 

Job


protected $user;
protected $language;

/**
 * Create a new job instance.
 *
 * @return void
 */
public function __construct($user, $language)
{
    $this->user = $user;
    $this->language = $language;
}

/**
 * Execute the job.
 *
 * @return void
 */
public function handle()
{
    $email = new Verify($this->user);
    
    Mail::to($this->user->email)->locale($language)->send($email);
} 

BezhanSalleh's avatar

@splendidkeen no post the original one before you implemented the job middleware... also your code worked before this refactor right? becuase right now you are not passing the language for the emails you wanna send

kendrick's avatar

@bezhansalleh - Edited above. And yes, it worked as described above - but I asked if there is a way to not pass $language to every dispatch, either create a middleware as you mentioned. Because now I would need to go through every Controller and add the lines above, and pass $language to the Job and add locale($language) to every Mail::to

BezhanSalleh's avatar

@splendidkeen yes you can use the middleware but it might takes some time and knowing how but just revert the changes you made till now and create a trait that returns the current language or locale based on the session and use that trait on your jobs...

trait SetJobLocaleForMails
{
   public function getCurrentLocale()
   {
	 if( session()->has('lang') && session('lang') === 'es') 
         {
		return 'es';
	 }
	
         return 'en';
   }
}

Now based on where you put the trait - normally a folder named Traits but here is how your jobs would look like from now on

use SetJobLocaleForMails;
protected $user;

/**
 * Create a new job instance.
 *
 * @return void
 */
public function __construct($user)
{
    $this->user = $user;
}

/**
 * Execute the job.
 *
 * @return void
 */
public function handle()
{
    $email = new Verify($this->user);
    
    Mail::to($this->user->email)->locale($this->getCurrentLocale())->send($email);
} 

let me know how it goes...

kendrick's avatar

@bezhansalleh - thank you for the Traits logic. It makes sense, and I set everything up following your example. Unfortunately it still sends only in en, even if I dd($language) and it returns 'es'. Obviously, when I hardcode locale('es') it works - but it doesn't get it from the Trait.

BezhanSalleh's avatar
Level 25

@splendidkeen you need to check your logic for when changing languages, whether it changes the language for the session or not. If you have a middleware you need to include it on the routes or it depends on how you are handling the language change because this solution works just fine for setting the locale or language for the jobs or mails...

so basically it would be somthing like this. LanguageSwitcher Middleware


namespace App\Http\Middleware;

use Closure;
use Carbon\Carbon;

class LanguageSwitcher
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if(session()->has('locale')){
            app()->setLocale(session()->get('locale'));

            Carbon::setLocale(session()->get('locale'));
        }
        return $next($request);
    }
}

Register in the app\Http\Kernel.php

    protected $middlewareGroups = [
        'web' => [
		...
            \App\Http\Middleware\LanguageSwitcher::class,
		...
    ];

LanguageSwitcherController.php

class LanguageSwitcherController extends Controller
{
    public function switch($locale){

        session()->put('locale', $locale);
        session()->save();
        return back();
    }

}

Route

Route::get('locale/{locale}', 'LanguageSwitcherController@switch');

blade/html snippet - you can change it based on your design...

<div class="btn-group btn-collection btn-icon-group mr-3">
    <a class="btn btn-secondary" href="/locale/en">EN</a>
    <a class="btn btn-secondary" href="/locale/es">ES</a>
</div>

if you have this setup for changing the language this trait for the jobs would work just fine.

kendrick's avatar

@bezhansalleh - Yes, sorry, I believe that your logic works. And thank you for your patience. But what am I missing?

Right before dispatching the Job I add this:

if (session()->has('lang') && session()->get('lang') === 'es') {
            $language = 'es';
        }else {
            $language = 'en';
        }

        dd($language);

	dispatch(new SendVerifyEmail($user)); 

and it return "es" - here basically it works - but why can't it grab the value in the Job?

I also included my Language.php Middleware in Kernel.php like:

protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            ...
            \App\Http\Middleware\Language::class, // here
        ], 
  ];

Middleware

class Language
{
    protected $default = 'es';

    protected $languages = [
         'en',
         'es', 
    ];

    public function handle($request, Closure $next)
    {
        if($request->has('lang')) {
            $lang = $request->lang;
            if(array_search($lang, $this->languages) === false) {
                $lang = $this->default;
            }
            Carbon::setLocale($request->lang);
            $request->session()->put('lang', $request->lang);
        }

        if(Auth::check()){
            if(auth()->user()->language_id == 1) {
                Carbon::setLocale('en');
                $request->session()->put('lang', 'en');
            } elseif(auth()->user()->language_id == 2) {
                Carbon::setLocale('es');
                $request->session()->put('lang', 'es');
            }
        }  
        \App::setLocale($request->session()->get('lang'));

        return $next($request);
    }
}

BezhanSalleh's avatar

@splendidkeen inside the job do logger('lang from session'.session('lang')) and i think you need to adjust the Language middleware logic as well.

        if($request->has('lang')) {
            $lang = $request->lang;
            if(array_search($lang, $this->languages) === false) {
                $lang = $this->default;
            }
            session()->put('lang', $lang);
            session()->save();
        }

        if(Auth::check()){
            if(auth()->user()->language_id == 2) 
            {
                session()->put('lang', 'es');
                session()->save();
            }
            else{
                session()->put('lang','en');
                session()->save();
            }
        }
          
        Carbon::setLocale(session()->get('lang'));
        app()->setLocale(session()->get('lang'));

        return $next($request);

you don't need the trait anymore you can just do this

Mail::to($this->user->email)
        ->locale(app()->getLocale())
        ->send($email);

i believe you will be good to go...

kendrick's avatar

@bezhansalleh - In log: local.DEBUG: lang from session It misses the lang.

logger('lang from session'. $this->getCurrentLocale()); returns local.DEBUG: lang from session en - so it basically gets something, but its not es - weird.

kendrick's avatar

@bezhansalleh - Sorry, from Job Middleware, to Traits to just app()->getLocale(), it just won't grab the correct lang in the Job. Have you tested it?

logger('lang from session'. app()->getLocale()) still returns "en", which is false. Even when I change my Language Middleware as you suggested.

I think it is just something I should pass in as a parameter - it gets lost in the queue.

kendrick's avatar

@bezhansalleh - Thank you for the repo. You are not sending any Mail in there. Just logging the app()->getLocale(). If I dd this logic in the Controller, I get the correct lang, but if I log app()->getLocale() in the Job, once again, I get the default of en. And the Mail is also send in English, so something gets lost in-between.

I am trying to find out more about it - and if it only works if I pass the parameter from the Controller to the Job.

BezhanSalleh's avatar

@splendidkeen it doesnt matter if i'm sending an email or not i'm getting the correct locale or language inside the handle method of the job so your issue is somewhere else in your code... maybe remove the default language variable from your middleware and set your default locale inside config/app.php -> locale. anyways delete your post and maybe repost it. don't want someone else going in circles as well. cheers.

just last try can i see the controller code and its route ... caz my test works and the issue is somewhere in your code.

kendrick's avatar

@bezhansalleh - Already sent you the Controller method, and it is a simple POST method? Also you can't just delete a post?

kendrick's avatar

Additionally, add a locale field to the User model, to send Mails like: Mail::to($this->user->email)->locale($this->user->locale)->send($email);

1 like

Please or to participate in this conversation.