Laravel localization with url - php

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 :)

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 8 Auth middleware protected route failing

I am building my first Laravel app with the Metronic 8 Laravel theme. It uses Breeze for authentication. I changed a couple of things around - created a welcome page for non-logged-in users, and moved the main template that was the index to an auth protected "/dashboard". The problem is that it still tries to load the dashboard Blade template, regardless of authentication, resulting in an error.
Route
Route::get('/dashboard', function () {
return view('dashboard');
})->middleware(['auth'])->name('dashboard');
Here's Authenticate, where it should redirect non-authenticated users to the login page.
protected function redirectTo($request)
{
if (! $request->expectsJson()) {
return route('login');
}
}
When I'm not logged in and navigate to the dashboard URL, it attempts to load the dashboard Blade template, which calls a menu function that checks the user permissions for menu items. Unfortunately, since there is no user, the application blows up from passing a null value to a method expecting a user array/object.
Any ideas on where to look for the problem? It seems to me that the auth middleware should redirect to the login page before trying to load the Blade template when not logged in.
I would put the middleware at the beginning of the route like this, though I'm sure it's not causing the problem-
Route::middleware(['auth'])->get('/dashboard', function () {
return view('dashboard');
})->name('dashboard');
Aside from that, please provide some information on the error itself like what the error is about/what is says..etc...
First of all, make sure you have a login named route defined in your routes/web.php file. It should look something like:
Route::get('/login', '<controller>#<method>')->name('login');
The important bit is ->name('login') so that the Authenticate middleware can correctly identify the route to redirect to. Change <controller>#<method> appropriately to route to the login method of your app.
Wakil's answer is irrelevant and actually opposite of the documentation. Your syntax is correct.
I figured out the issue. Keen Themes put a call to a method to build an array of menu items in the web routes file. That was making the call to the offending code. After I wrapped that in an auth check the error was fixed, and everything works as expected.

laravel 6 when login go to previous url not working

I'm using Laravel framework my previous version of laravel is 5.8
and in my middleware login
public function handle($request, Closure $next)
{
if(Auth::check())
{
return $next($request);
}
else
{
Session::put('url.intended',URL::previous());
return redirect('/login');
}
}
and this is the controller login controller
if(Session::get('url.intended') <> '')
return Redirect::to(Session::get('url.intended'));
else
return redirect('/');
with this codes in laravel 5.8 everything was working great but when i upgrade to laravel 6 its not working any more i dont know why
any help here thanks
if i came from any link its always redirect me to / link
You should probably be letting the framework handle as much of this as possible. If you must use your own middleware and Controller method still let the framework handle this as it does best.
Dealing with the intended URL is already something the framework is capable of doing itself and checks multiple conditions to figure this out. You can use the guest method of the Redirector to have it do this for you:
return redirect()->guest('login');
This will take care of the redirect to 'login' and set the url.intended in the session as needed.
After login is successful you can redirect them to where they were trying to end up, 'intended', or a fallback url:
return redirect()->intended('/');
This will redirect to what it can find as the 'intended' and if not use a fallback. It will also remove the 'url.intended' key from the session as it is no longer of use. No need to set or check the session yourself.

Grouping all the laravel application routes using dynamic prefix

We have multiple client portal each one has a unique url like
xyz.com/ClientPotal123
xyz.com/ClientPotal234
xyz.com/ClientPotalXXX
We will be routing all these url's to
/var/www/html/Laravelapp/public
Laravelapp is our codebase which we use for all the clients.
Since ClientPotalXXX is dynamic and unique for all the clients, I need to get the value of ClientPotalXXX for loading client specific settings like url generation, database connection (We have different database for each client).
To achieve above I've done below changes..
My Web.php file is as below..
Route::pattern('ClientPortal','^ClientPortal([0-9]+)?');
Route::prefix('/{ClientPortal}')->group(function () {
Route::get('/user/list', 'UserController#list')->name('list');
Route::get('/user/edit/{id}', 'UserController#edit');
});
I've created Middleware with below code written in it..
public function handle($request, Closure $next)
{
$database_name = strtolower($request->ClientPortal).'_db';
config(['database.connections.mysql.database'=>$database_name]);
config(['app_settings.client'=>$request->ClientPortal]);
return $next($request);
}
And it's working fine but previously I used to access $id in edit function directly
public function edit($id){
echo $id; // 12
}
But now $id return the value of ClientPortalXX everytime.
If I access id from Request it works fine
public function edit(Request $request){
$id = $request->id; // 12
}
This is happening with all of the other routes where I'm using route parameters.
So I'm not sure if this happened because I'm using dynamic prefix for grouping all the routes?
And now for every route() method which I've used in blade files for url generation I have to pass the second parameter ie. Value of {ClientPortal}
{{route('register',['ClientPortal'=>config('app_settings.client')])}}
Is this right implementation? I know we can make any varibale accessible globally using service provider but will it be right to do so?
My Laravel Version is 5.5.xx.. I'm just a beginner so any Help/Suggestion/Advice will be appreciated Thanks :)
Update:
Nikola Gavric and Oluwafemi Sule had already clarified my doubt in comments below.
But since the group prefix is dynamic, How do I handle the route naming case?
If I had to generate user list url using list route name which is mentioned in above web.php file.
Now I've to change this line..
{{ route('list') }}
To
{{ route('list',['ClientPortal'=> 'ClientPortalXXX' ]) }}
Since prefix is also a route param.
Is this feasible option? Because I've to do this change everywhere where I've used route method for url generation.

Laravel; how make setLocale permanent?

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.

Categories