When having a multi-locale website, a common task is to make sure the application has the correct locale to use.
We are currently using router_context for passing down the context of the router during the async rendering and sending of emails. This has one big limitatation:
Flow:
Given the base structure of the application is /{_locale}.
A forget password at /{_locale}/forget-password will trigger an email that will be handled by e.g. rabbitMQ.
We are currently using the router_context to pass down the HTTP router context to the messenger consumer
So if the TWIG email uses {{ url('reset-password', {token: token} }} - which should go to /{_locale}/reset-password/{token}, the queue will fail that the _locale parameter can not be found. This is because the parameters are not being passed down. (Note: If you would be using the sync queue, this will work given the information is available in the RequestContext of the router.
An easy fix for this would be to extend the RouterContextMiddleware.
Yet, it might be a better idea to (also?) have a new LocaleContextMiddleware and LocaleContextStamp.
(We currently pass down the locale information manually)
This stamp could contain the currently selected locale in HTTP request.
When running the handler, it could first register the correct locale inside the application and finally revert this information after the handler's execution (just like the router middleware does).
This would imply:
Setting the translator's locale
Setting intl default locale
(I might be missing something here? - feel free to append)
So my questions here are:
What do you think about both suggestions above? Is this something you would like to have in messenger?
Maybe you have a better idea to beat this issue?
Example implementations / Considerations
RouterContextMiddleware change
The router's context parameters might contain closures. For example for the expression language, an additional "_functions" key is added which contains a service locator. We could e.g. only detect scalar types for passing down to the stamp:
(The rest of the code will be in line with what is there.)
LocaleContextMiddleware
This middleware would be responsible for passing down the locale from the HTTP request as a stamp.
Before handling the message, it can change the locale on all required services to the one of the HTTP request.
After handling the message, it will reset to previous settings.
LocaleContextStamp
classLocaleContextStampimplementsStampInterface
{
publicfunction__construct(
public readonly string$locale,
) {
}
}
LocaleContextMiddleware
useSymfony\Component\DependencyInjection\Attribute\TaggedIterator;
classLocaleContextMiddlewareimplementsMiddlewareInterface
{
/** * @var iterable<int, LocaleAwareInterface> */privateiterable$localeAwareServices;
/** * @param iterable<int, LocaleAwareInterface> $localeAwareServices */publicfunction__construct(
#[TaggedIterator('kernel.locale_aware')]
iterable$localeAwareServices
){
$this->localeAwareServices = $localeAwareServices;
}
publicfunctionhandle(Envelope$envelope, StackInterface$stack): Envelope
{
if (!$envelope->last(ConsumedByWorkerStamp::class) || !$contextStamp = $envelope->last(LocaleContextStamp::class)) {
$envelope = $envelope->with(newLocaleContextStamp(
\Locale::getDefault()
));
return$stack->next()->handle($envelope, $stack);
}
$currentLocale = \Locale::getDefault();
$this->changeLocale($contextStamp->locale);
try {
return$stack->next()->handle($envelope, $stack);
} finally {
$this->changeLocale($currentLocale);
}
}
privatefunctionchangeLocale(string$locale): void
{
\Locale::setDefault($locale);
foreach ($this->localeAwareServicesas$service) {
$service->setLocale($locale);
}
// optionally: set the RouterContext _locale parameter if we decide to do it right here
}
}
(!) Note: It currently uses intl for detecting current locale. We might as well select it from the first iterable instead - since intl might be disabled?
The text was updated successfully, but these errors were encountered:
Description
When having a multi-locale website, a common task is to make sure the application has the correct locale to use.
We are currently using router_context for passing down the context of the router during the async rendering and sending of emails. This has one big limitatation:
Flow:
/{_locale}./{_locale}/forget-passwordwill trigger an email that will be handled by e.g. rabbitMQ.router_contextto pass down the HTTP router context to the messenger consumer{{ url('reset-password', {token: token} }}- which should go to/{_locale}/reset-password/{token}, the queue will fail that the_localeparameter can not be found. This is because the parameters are not being passed down. (Note: If you would be using the sync queue, this will work given the information is available in the RequestContext of the router.An easy fix for this would be to extend the RouterContextMiddleware.
Yet, it might be a better idea to (also?) have a new
LocaleContextMiddlewareandLocaleContextStamp.(We currently pass down the locale information manually)
This stamp could contain the currently selected locale in HTTP request.
When running the handler, it could first register the correct locale inside the application and finally revert this information after the handler's execution (just like the router middleware does).
This would imply:
So my questions here are:
What do you think about both suggestions above? Is this something you would like to have in messenger?
Maybe you have a better idea to beat this issue?
Example implementations / Considerations
RouterContextMiddleware change
The router's context parameters might contain closures. For example for the expression language, an additional "_functions" key is added which contains a service locator. We could e.g. only detect scalar types for passing down to the stamp:
array_filter( $context->getParameters(), static fn (mixed $value): bool => is_scalar($value) ),(The rest of the code will be in line with what is there.)
LocaleContextMiddleware
This middleware would be responsible for passing down the locale from the HTTP request as a stamp.
Before handling the message, it can change the locale on all required services to the one of the HTTP request.
After handling the message, it will reset to previous settings.
LocaleContextStamp
LocaleContextMiddleware
(!) Note: It currently uses intl for detecting current locale. We might as well select it from the first iterable instead - since intl might be disabled?
The text was updated successfully, but these errors were encountered: