-
Notifications
You must be signed in to change notification settings - Fork 11k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[5.6] Ability to set locale on sent Mailable #23178
Conversation
Does this also work if we queue the mails using the |
Yes @sisve, both works:
|
Would it be possible to only initialise the translator if a locale is set? Seems unnecessary to always initialise translator at the service provider level when there's many apps that aren't multi lingual. |
@garygreen but we don't initialise it, we just register the instance if it's already bound to the container. |
src/Illuminate/Mail/Mailable.php
Outdated
if ($mailer->translator) { | ||
$mailer->translator->setLocale($currentLocale); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you have an interest in offering a ChangesLocale
concerns trait that can be re-purposed in user-land?
trait ChangesLocale
{
/**
* @param \Illuminate\Contracts\Translation\Translator $translator
* @param string $locale
* @param callable $callback
*
* @return mixed
*/
public function asLocale($translator, $locale, callable $callback)
{
if ($translator && $locale) {
try {
$currentLocale = $translator->getLocale();
$translator->setLocale($locale);
return $callback($locale);
} finally {
$translator->setLocale($currentLocale);
}
} else {
return $callback($locale);
}
}
}
Then send()
simplifies to:
public function send(MailerContract $mailer)
{
$this->asLocale($mailer->translator, $this->locale, function () use ($mailer) {
Container::getInstance()->call([$this, 'build']);
$mailer->send($this->buildView(), $this->buildViewData(), function ($message) {
$this->buildFrom($message)
->buildRecipients($message)
->buildSubject($message)
->runCallbacks($message)
->buildAttachments($message);
});
});
}
The trait I've been wrapping Mailer@send()
with for awhile is much simpler when assuming a translator is bound to the app container:
trait ChangesLocale
{
public function asLocale($locale, callable $callback)
{
try {
$currentLocale = app()->getLocale();
if ($locale) {
app()->setLocale($locale);
}
return $callback($locale);
} finally {
if ($locale) {
app()->setLocale($currentLocale);
}
}
}
}
It would be great to also have the ability for users to have an email region/language preference. It can be pulled from a model attribute in a
Here's an potential commit to follow this pull request: derekmd@3c48884 |
@derekmd per recipient locale makes sense yes, I'll just wait and see if this implementation is the best way to go and then add your idea. Will also need to work on the Notifications locale part, so will just wait till this PR is merged/rejected/edited. |
Thinking about @derekmd's suggestion of a pretty generic trait that wraps up @themsaid's try / finally logic is pretty interesting. Could we basically "solve" this feature by adding that trait in Illuminate\Support or Illuminate\Foundation and not even make any changes to mailables or notifications? We would just let people pass whatever locale they want into the mailable or notification and call the trait method if they need it? |
Would be nice to have one point of setup that handles mailables, notifications, ánd framework notifications like password resets! Makes total sense to enable sending stuff in the language of the recipient and not the sender or default app locale. |
Thing is recipients can be multiple each with different locales, so you must decide which locale the mail will be sent with. |
Yeah, otherwise we would basically have to sort out the recipients by locale and send a mail for each locale. That may be complicated to implement. Not sure. It could possibly be done in the PendingDispatch destructor. |
How would sending a notification in a specific locale look like? Notification::locale('ar')->send($users, new InvoicePaid($invoice));
// and
$user->locale('ar')->notify(new InvoicePaid($invoice)); Like that? Or even: $user->notify(new InvoicePaid($invoice)); Where the locale is resolved automatically like I'm not aware of all the internal code that handles this so thinking out loud here, but if you leave handling locales for multiple recipients to the developer, they can e.g. create a Notification macro that loops the recipients and sends the notification in each recipient's locale separately (I'm doing something similar in a current project). Or you could provide an internal method that splits recipients with locales and those without, then send a generic version of the notification to those without (in the current app's locale or a default provided one) and a translated notification to each user that has a locale resolve method implemented. |
I don't know. We can probably do the simplest implementation on notifications and go from there. |
Of course, already happy this issue is getting some traction :) Think the most "urgent" use case would be sending any kind of notification (whether it be a notification, mailable, …) to a single recipient in their locale and ideally having that auto-resolved like what's done for notification's |
timezones needs to be localized as well, great job. |
Sorry, this post turned out too long. It doesn't apply to notification channels like Slack and SMS that don't offer any multi-reply ability (as in, the recipient responds to the notification they received.) TLDR: Make user-land decide what to do for multiple recipients of mailables. Proposed branch for recipient locale preference on
|
So, perhaps we should unlock the internals thread again? Because this PR does not completely cover all the cases discussed in it. Or should this PR be considered incomplete based on lacking functionality discussed in the internals thread? |
Might be good inside the Notification too @themsaid.
Suggest:
This should help when the notification is pushed to queuing, as we have localization inside the messages when using OneSignal/Pusher, and should automatically switch from the passed locale. Workaround/Old Way
|
Why only set the locale of the translator, and not the locale of the app? My use case is that I rely on |
I've got exactly the same use case as @CyrilMazur. |
Is something like this for notifications already working in the current release?
|
@Razorsheep you might interpreted as It was like this: And you need to implement it on your own, which does the same thing. Then under your base notification you can create an accessor |
When you save the email text in a variable in your |
Translatable text must be set in your mailable's |
Perhaps late for the party, but can fallback locale be set on a Mailable? For example, Swiss-German (de_CH) has some subtle changes to German (de), we want to set the primary locale to de_CH and then fallback to de if a translation isn't found. On an app level we do this through a helper function in Middleware: function setAppropriateLocale($locale = 'en'): string
{
// Set the primary locale ie 'de_CH'
app()->setLocale($locale);
// Extract the primary language code (first 2 letters like de,it,es)
$primaryLanguage = substr($locale, 0, 2);
// Set the fallback locale based on the primary language code
app()->setFallbackLocale($primaryLanguage);
Session::put('locale', $primaryLanguage);
return $primaryLanguage;
} It would however be great to have this possible also for queued Mailables, perhaps a second optional parameter to the locale method? |
This PR is an attempt to allow configuring a specific locale that'll be used while sending a Mailable.
Let's say the current locale is English, while user B has a default language of Arabic, system is sending a queued mail to user B and want to specify that the language to be used while building the email message is to be Arabic.
Doing so will instruct Laravel to switch the default language right before building the email to Arabic, and then once the email is sent it sets it back to whatever it was before the change.
This, based on my tests, ensures the daemon worker process will have the default locale set back to its original value after the mail is sent.