Laravel; how make setLocale permanent? - php

I've my home route
Route::get('/', 'HomeController#index')->name('home');
And a specific route to change language
Route::get('/setLocale/{locale}', 'HomeController#setLocale')->name('setLocale');
In HomeController->setLocale($locale) I check if $locale is a valid locale, then simply do
\App::setLocale($locale);
Then redirect to home.
Here, in HomeController->index() I verify locale using
$locale = \App::getLocale();
The problem is that after user CHANGES the locale, the app set the new locale, redirect, but the locale detected is still the DEFAULT locale, not the new one setup by the user.
How / where / when can I make persistent the change to app locale?
I thinked Laravel was setting a locale cookies or something when using setLocale and re-reading it when using getLocale but now I think it's not this the way Laravel works.
I ask, again: how can I set app locale so that is preserved after page change?

I did that by using a middleware. Here's my code:
LanguageMiddleware:
public function handle($request, Closure $next)
{
if(session()->has('locale'))
app()->setLocale(session('locale'));
else
app()->setLocale(config('app.locale'));
return $next($request);
}
remember to register your middleware :)
The users are able to change the language, with a simple GET-Route:
Route::get('/lang/{key}', function ($key) {
session()->put('locale', $key);
return redirect()->back();
});
Hopefully that helps you :)
Apparently, there are some changes in Laravel 7.0!
If you are using the code above, please change from a BeforeMiddleware to a AfterMiddleware! (see https://laravel.com/docs/7.x/middleware)
If you don't do this, the value of session('locale') will always be null!

setlocale only works for the current request. If you want the value to be remembered, you will have to set a cookie manualy.
I recommend using a middleware to do this.

Related

Laravel verify locale in url is same as user's locale from database

So in my LocaleMiddleware class (which is located in the web group of the middleware), I have the following:
if (Auth::check())
{
app()->setLocale($request->user()->getLocale()); // This just fetches the locale from the database for the given user
}
And then it just returns the next request. However, there is a slight issue for example when logging in. I need to use the return redirect()->intended(); option. This poses a problem when I have for example the following route that I point to:
https://www.example.com/es/cervezas/dos
The English variant of this url would be:
https://www.example.com/en/beers/two
My routes look like this for example:
Route::name('user.')->prefix(app()->getLocale())->group(function () {
Route::get(trans('routes.beers'), [BeersController::class, 'index'])->name('beers.index');
}
So in my routes I translate everything, and I also have slugs for each of my database models etc, which is why I always need to have the correct locale set but also I always need to have the correct locale in the url. If not I get not found exceptions when viewing specific model items or weird translations.
But one of the main problems is, when I go to the Spanish route for example (or any route for that matter in any language), after logging in, it will return the intended url/route, which will be the English one since en is the fallback locale.
So basically, what I was thinking is something along the lines of this, in my LocaleMiddleware class:
if (Auth::check())
{
app()->setLocale($request->user()->getLocale());
// Check if the segment locale is the same as the user locale
// IF NOT, redirect them
if(request()->segment(1) !== $request->user()->getLang())
{
return redirect()->route(request()->route()->getName()); // Not sure what to do here, doing this just creates an endless loop because the locale somehow was not updated yet it seems
}
}
Any ideas for a solution for this, in the LocaleMiddleware or anywhere else? Or am I going about this the wrong way entirely? Any pointers are appreciated!
Edit:
Now in my LoginController I have the following:
protected function authenticated(Request $request, $user)
{
app()->setlocale($user->getLocale());
dd(app()->getLocale()); // This is the correct locale, `es` or `nl`
dd(route('beers.index')); // This just always shows the English route
}
How come the app()->getLocale() shows the correct locale but the route is still always in the default locale? And of course, how to fix that?
Usually you have access to the user in the login function before redirecting.
In many of my projects there is an admin panel and I use the same default login endpoint. During the login process I check where the user is an admin or not and decide where to redirect him.
Here's an example of the store function in App\Http\Controllers\Auth\LoginController in a laravel 8 project:
/**
* Handle an incoming authentication request.
*
* #param \App\Http\Requests\Auth\LoginRequest $request
* #return \Illuminate\Http\RedirectResponse
*/
public function store(LoginRequest $request)
{
$request->authenticate();
$request->session()->regenerate();
if (Auth::user()->hasRole('admin')) {
return redirect()->intended(RouteServiceProvider::ADMIN_HOME);
}
return redirect()->intended(RouteServiceProvider::HOME);
}
So I believe that if you edit your redirection logic in the login controller it should work, because you have access the user, before you actually redirect him.

Laravel localization with url

I am developing a multi-language web app using Laravel framework. So in this app, I have a special condition to do multi-language feature as below.
a user can select from some flags and change the language manually.
It changes his URL to /{lang} .. so, for example, webapp.com/cs - so he will see everything that in Czech language. webapp.com/en - see everything in English.
Chosen localization should be persistent so would not disappear when user change page or something - it should always be in the URL.
I created Route to set locale in session as follows.
Route::get('/{locale}', function ($locale) {
session()->put('locale', $locale);
return back();
});
And created middleware and added it to $middlewareGroups in the http\Kernel as well.
Below is my middleware.
public function handle($request, Closure $next)
{
if (session()->has('locale')) {
app()->setLocale(session('locale'));
}
return $next($request);
}
Localization is going well and it gives correct translations and everything. But what I need is to show in the URL what is the language is. as example webapp.com/cs,webapp.com/en. It would be great if anyone can help me with this problem.
Thanks.
You can try this,
In your every route you can append current local language like this
Route::get('/home/'.app()->getLocale(),'HomeController#index');
and one more thing you should see this
Laravel app()->getLocale() inside routes always print the default "en"
Hope this helps :)

How to set locale by controller laravel

I want to set locale for change language but my project is not website but it is a Facebook bot which developed through base controller, I want Example thank.
The default language for your application is stored in the config/app.php configuration file. Of course, you may modify this value to suit the needs of your application. You may also change the active language at runtime using the setLocale method on the App facade:
Route::get('welcome/{locale}', function ($locale) {
App::setLocale($locale);
//
});
see more in https://laravel.com/docs/5.7/localization#introduction

How is Localization in Laravel implemented?

I want to implement localization on my website using Laravel 5.5.
However, I am not sure what the standard practice when using localization should be. I have used the LocalizationController module from the Laravel documentation. My goal is to have the localization option selected via a dropdown. Then the user's selection should be remember.
Do I store their selection in a database for future use?
Or, is this something to keep in a cookie?
Side note:
(I want to avoid having their selection in the url. I'll either pass the data in a request or get method.)
For registered and logged-in users i recommend to store the users language in the database. Everytime a user logs in the application should set the language for the current user. Maybe you take a closer look on middleware. Build a language middleware, register it as new middlewaregroup and assign it to every route (-group) you need. A middleware could look like this:
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class LanguageMiddleware
{
public function handle($request, Closure $next)
{
if(Auth::check()){
// user is logged in
App::setLocale(Auth::user()->language);
return $next($request);
}
App::setLocale(config('app.locale'));
return $next($request);
}
}
Now register the new middleware in app/Http/Kernel.php as new middleware-group under protected $middlwareGroups:
// other middleware-groups
'language' => [
\App\Http\Middleware\LanguageMiddleware::class
]
Finally assign middelware-group to route (-group):
Route::group(['middleware' => ['language']], function(){
// Routes...
});
Unfortunately there is no build-in function to show a dropdown-language-select. But you can simply build a blade-partial which you can integrate in your navbar or where-ever you want to show/use it. You could ask new users during registration for their preferred language.
Guests/unregistered users could use the dropdown. By default they should see the default language.
Hopefully this helps you.

symfony change locale in route during login

I'm stumbling upon an issue on changing the locale during the login event on a symfony (2.7) application. I was following the sticky locale symfony article http://symfony.com/doc/current/cookbook/session/locale_sticky_session.html, but not using the session at all.
I'm using the approach that every URI contains one representation only. Therefore all routes contain the {_locale} (and no need of a session variable for sticky locales).
I'm just using the UserLocaleListener part to get the users locale and tried to set it into the route like on this github issue https://github.com/FriendsOfSymfony/FOSUserBundle/issues/829.
My problem possibly is, that on login is already a URI locale set. During the login event, I need/want to overwrite this locale value. As mentioned by the github article, I added the router context.
UserLocaleListener InteractiveLoginEvent
/**
* #param InteractiveLoginEvent $event
*/
public function onInteractiveLogin(InteractiveLoginEvent $event)
{
$request = $event->getRequest();
$user = $event->getAuthenticationToken()->getUser();
$locale = $user->getLocale();
if (null !== $locale) {
$request->setLocale($locale);
$this->router->getContext()->setParameter('_locale', $locale);
//var_dump(); die;
}
}
Unfortunately, it doesn't work (at least on my symfony 2.7).
If I dump the requests locale or the router context locale, the correct user locale was applied to the context, but not changed/applied on redirecting to the default_target_path or any other path.
Is the onInteractiveLoginEvent already too late to change the locale in an URI? Or how do I best change the locale in the URI during a (form based) login?
Many thanks for any hint.
as i explained here
the locale is set on the request, and will not "stick" , so each request it will be the default again, unless you do something like this:
http://symfony.com/doc/current/cookbook/session/locale_sticky_session.html

Categories