-
Notifications
You must be signed in to change notification settings - Fork 28
[Bug/Proposal] Locale missing from queues / queued emails and listeners #394
Comments
I don't think it's the responsibility of the queue to know what the locale of the request that set it was. Thats something you should pass in as a parameter if needed. |
Your answer makes no sense. It's like these theoretical discussions about best practices that lack common sense. This leads to a lot of unnecessary code duplication for no reason, because I have to retrieve the locale, pass it in and set it in every job, when Laravel could do this for me automatically. Especially since even people not needing this feature, it won't hurt them. It's also something people would assume happens automatically when they make they emails and notifications queueable. But now they get a nasty surprise when all of a sudden their language files work no more! Very "non-Laravel". |
Fact is that most people don't need that by default on their jobs. My main
app at work uses queues extensively and I have never needed locales.
While laravel could handle that for you it wouldn't apply to 95% of use
cases so in my mind it's not worth it by default. It would consume memory
in the queue if you process a lot of jobs like I do daily (in the millions).
You could use a simple base class for your jobs that do that automatically.
If other people are interested it would be a pretty easy package to write.
|
You are saying that 95% of Laravel apps are not using more than one language? Where do you get that number from? Just interested... The memory a 2-byte locale consumes in a queue must be marginal! Curious to see how other people out there feel about this... but it's Taylor's show the end of the day... |
I have the same problem. Here's what I did: In my base Mailable class: namespace App\Mail;
use Illuminate\Mail\Mailable as NativeMailable;
use Illuminate\Support\Facades\App;
class Mailable extends NativeMailable
{
/**
* Locale used for rendering this email.
*
* @var string
*/
public $locale;
/**
* Create a new message instance.
*/
public function __construct()
{
$this->locale = App::getLocale();
}
} Then in my email view: <h1>{{ trans('emails.welcome', null, $locale) !!}</h1> The That's the best I could come up with. I agree something like this should be embedded in Laravel by default. It's especially cumbersome to have to add the $locale parameter to all the calls to the |
I agree it would make sense to preserve the locale in the queues. |
The solution of @CyrilMazur, which is I think the only way to get around it, won't cover the default date format or number format: you'll have to add a |
You would need to have a listener for the JobProcessing event that calls |
I know how to do it. But I think this is something that Laravel should do for all queues. |
I'd be ok with this if it was optional like the For instance you might do it this way: dispatch((new SendWelcomeEmail($user))->onQueue('emails')->setLocale()); In that case, the setLocale() method would by default pull from the current request if an argument was not provided. |
When would you ever not want your jobs to have the current locale? |
Definitely; the Locale should be set in queues by reading the application's configuration/environment variable. If not this should clearly be addressed as a bug. |
@barryvdh exactly! Because the answer is "never" it is a bug/oversight. |
@RemiCollin It should be set/passed into the queue/job to whatever |
@elasticsteve : I agree with you ; that's what I meant by reading from Env/Config ;) /**
* Get the current application locale.
*
* @return string
*/
public function getLocale()
{
return $this['config']->get('app.locale');
} |
@RemiCollin Yes, of course the Facade is setting |
While it makes sense for mail, its useless for other types of jobs like calculating statistics, processing web hooks, etc. Setting locale on the jobs makes sense if you explicitly set the app locale to something other than the default though. |
Yes but it would never hurt to pass it along, even if it's just the default. |
@tomschlick : not everybody has |
@RemiCollin I get that, which is why I don't think it would be a bad thing to do it if the current locale != the default. |
I ended up having different applications for each language and setting language in .env file. |
And this would be another one to make locales easier with notifications :) |
So… what's the status of this issue? Running into the same problem. |
No one has submitted a PR yet. I wouldn't personally use it but I can see the need for it. I would suggest including the locale if it != the default set in |
I wrongfully assumed that if I queue a mail(able) when the locale was set to French, it'd be sent in French and not the fallback locale. So basically you get a different result when opting to use a queue, which is not desired and can lead to weird situation few people are aware of. IMO a bug as previously mentioned. Currently storing the current application's locale in a public class variable in the (queueable) mailable's constructor and restoring it when it gets triggered. Not sure if there's a better way to do this, seems highly redundant having to call 2 extra methods per queued job. |
Anyone have any ideas on how this would actually even be implemented? |
Since each queued job is completely isolated from the rest, would it be possible to store the current application's |
My idea is that queued jobs would have current App:getLocale() attached as data, and upon handling the job (or whatever) it would get the locale from data and run App::setLocale()
At least that’s what I do in my current apps — apart from some, where I have set locale in my environment variables and have different apps running; one for each language. Simply passing along an extra attribute to the job with locale, and setting in the handler.
I don’t know if it is even an option, haven’t looked much at the framework queue code. If I have a few hours tonight, I’ll look at it and hopefully find a solution.
Sebastiaan was faster, hah. What he said, basically.
|
Indeed, add the locale to the payload en re-set the locale on fire? Something like this? (not tested) Queue/Queue.php
protected function createObjectPayload($job)
{
return [
'displayName' => $this->getDisplayName($job),
'job' => 'Illuminate\Queue\CallQueuedHandler@call',
'maxTries' => isset($job->tries) ? $job->tries : null,
'timeout' => isset($job->timeout) ? $job->timeout : null,
'locale' => isset($job->locale) ? $job->locale : config('app.locale'),
'data' => [
'commandName' => get_class($job),
'command' => serialize(clone $job),
],
];
}
Queue/Jobs/Job.php
/**
* Fire the job.
*
* @return void
*/
public function fire()
{
$payload = $this->payload();
config(['app.locale' => $payload['locale']]);
list($class, $method) = JobName::parse($payload['job']);
with($this->instance = $this->resolve($class))->{$method}($this, $payload['data']);
} |
@barryvdh will config('app.locale') output the same ass \App::getLocale(); — For example if locale has been changed using \App::setLocale() |
@LasseRafn Was thinking the same, but double checked and |
No, you're right, that would be more appropriate. (getLocale does return the same thing, but setLocale also updates the translator and fires an event). See https://github.com/laravel/framework/blob/075220049df5859a39a05df02f74a36f20079d23/src/Illuminate/Foundation/Application.php#L1025-L1048 |
I would love to see a feature like this. But i feel that this would still have issues, What if we have a application where users could set their preferred language . If a French user is logged in the application the App::getLocale() would be French. But if this user triggers emails/notifications to other users , those emails would be in the French language even if the user that receives this notification wants his emails in english. I would love to have the ability to specify the language to a notification/mailable. |
Currently finishing up a medium project that required translated (queued) notifications. Each notification can be sent to different recipients who each have their preferred language, but can also be sent to an entire group (as a thread message) for which it takes the language of the group creator. So basically I needed to clone each notification per recipient, set the language of the notification for that user, set the application's locale for the duration of it, have everything the recipient receives translated correctly, and then reset the locale so it won't interfere with other translations as part of that job/notification. It was a real hassle to end up with the somewhat hacky solution I have now. Would love localization support in queued jobs, notifications, etc. |
Still no solution ? |
@fsasvari Create a $locale in your Mailable class, then pass it. new AnyMailableClass($arg1, $arg2, app()->getLocale()); |
No other way ? Bugger... Then I need to use |
@fsasvari This solution is OK. Type-hint Best |
You could set it using |
Thanks @barryvdh it's working, placed |
I'm really, really, really pissed.. hours of searching without finding a working solution. <h2>{{ trans('Password reset instructions', [], 'de') }}</h2> The corresponding translation is available within resources/lang/de/messages.php as array key: <?php
return [
'Password reset instructions' => 'Instruktionen zum Zurücksetzen des Passwortes',
]; I also tried to set locale with app()->setLocale('de') but without any effect. I'm desperate! |
@renepardon I struggled with that myself. It's important to know where you're setting the locale here. See this gist: https://gist.github.com/sebastiaanluca/acaec76770d13daa3f0845f35195238e. Regular notifications can be wrapped, e-mail notifications cannot as they get constructed after the mail message is returned. |
@sebastiaanluca I've tried it in the Mailable constructor, in the Event Listener constructor, within the handle method of the Listener, within the build method of a Mailable... works nowhere for me. :( |
This is how my Event listener and Mailable looks like. Maybe you see a mistake but I can't :) Listener: Mailable: This is how it look like now. But I've tried explicit 'de' as well which does not work too. EDIT: I forgot to mention that setUserLocale() does nothing else than app()->setLocale('de') and Carbon::setLocale('de') |
Queued listeners might be a different case, my example works for queued notifications. I suggest you debug the value of the app locale first. In your mailable's build method, log the value of |
Hi @sebastiaanluca yes, I understood this one and already tried debugging the getLocale() which is 'de'. So I think the translations are just not loaded during job execution for some reason. I also tried throwing an exception, catched it and saw that only queue related stuff is executed. Nothing related to the application or translation. I also thought about creating a mail template for every language but this makes no sense as I would like to grow rapidly and then I have templates just for translation?! ;) Another idea would be to create a custom translation helper which explicitly requires the correct translation files?! I really don't understand why such a huge framework like laravel does not support something like this. |
app()->getLocale() returns de as locale which is true. |
I think this might be something related to your app, not Laravel core. Setting the app locale and then calling |
Ok, finally I gave up... I've created a helper trait which loads the messages.php manually based on provided locale and translate by replacing key with value.... Hope this helps someone else: I just pass the current class as "translator" to the email view template and can then call: {{ $translator->translate('translationkey') }} |
Any developtment on this? @barryvdh solution seems to be the best approach so far. |
Still using my RemembersLocale trait (https://gist.github.com/sebastiaanluca/acaec76770d13daa3f0845f35195238e), no other way. For a new project, I wrapped the I can now understand @taylorotwell's point though and don't see how this can implemented in a universal way. Maybe a basic feature where each queued job, handler, listener, and notification is in the same locale as when it was added to the queue. Then it's mostly the sender's locale that determines the translations to use, not the recipient's. Still better than the default app locale. |
We have a merged implementation of this here: laravel/framework#23178 It is currently on latest dev of 5.6, we would appreciate if anyone could give us feedback before the next 5.6 tag. Please direct further discussion there. |
I develop a multi language app. To my disappointment I just noticed that the locale doesn't get passed into queued emails! They launch always with the default "en" locale.
I would have thought that passing on the locale is a default feature. Any queued job should be launched under the original locale that launched it. Kind of common sense, no? Is saw this issue filed by several people as a bug (which I think it is too), but closed by Graham right away.
The text was updated successfully, but these errors were encountered: