So I found out that I can put above code on every blade file, and it works that way, but that is obviously wrong way to do it. :(
Localisation from controller
Hi, I am trying to create multi language app for multi users (so that language is applied per user). I have translation in place already, and when I change locale in config it works as expected.
When user is logged in, in his/her settings he/she can set the language (en or de) and that is stored in database with that user id. After save I do:
$lang = Auth::user()->user_settings->language;
App::setLocale($lang);
and locale is set (checked in session), but only for current route, so language is not applied on whole app.
I tried to find online but without much success, how to set now the language for that user on the app level? That has to be done somehow on routes level, or? Also, it would be great, that next time user is on login page that the page is also in his/her language, but without logged in user, I assume I need to set it in the cookie, and get it from there?
So my problem is that this translation is not applied even if it is set in session.
So after searching online for solution, I found something that partially solves my problem. I used this how to: https://dev.to/fadilxcoder/adding-multi-language-functionality-in-a-website-developed-in-laravel-4ech
It works ok, but when I logout/login language is back to default. I need to go every time to settings and set language manually as in my controller this is executed after save button:
$lang = Auth::user()->user_settings->language;
return redirect (url('locale/' . $lang))->with('success','Settings saved successfully.');
After that everything is translated but when I login next time, language is not set, which is correct as I set it only here in settings.
How can I set it after login?
I think in your LoginController you can add this:
/**
* The user has been authenticated.
*
* @param \Illuminate\Http\Request $request
* @param mixed $user
* @return mixed
*/
protected function authenticated(Request $request, $user)
{
$lang = $user_settings->language;
App::setLocale($lang);
}
or inside authenticated method you can also add redirect.
Would middleware solve your issue?
<?php
namespace App\Http\Middleware;
use Closure;
class SetLocale
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$locale = \Auth::check()
? auth()->user()->user_settings->language
: config('app.locale');
app()->setLocale($locale);
return $next($request);
}
}
Add it to the web middleware group.
After login it complains:
TypeError Argument 1 passed to App\Http\Controllers\Auth\LoginController::authenticated() must be an instance of App\Http\Controllers\Auth\Request, instance of Illuminate\Http\Request given, called in /home/vagrant/code/value2.test/vendor/laravel/ui/auth-backend/AuthenticatesUsers.php on line 110
If you are open to use a package i found that this one works pretty good https://github.com/mcamara/laravel-localization
Import Request class in top of your LoginController:
use Illuminate\Http\Request;
Your solution worked, but I don't know why the one from the page I sent, didn't.
I had handle function like this:
public function handle($request, Closure $next)
{
if(Session::has('locale')) {
App::setlocale(Session::get('locale'));
}
return $next($request);
}
Thx!
So to summarize, the solution that @johncarmackfan95 wrote, is working, even if I already had "middleware solution" from the page above.
To repeat, I set the language per user like this:
$lang = Auth::user()->user_settings->language;
return redirect (url('locale/' . $lang))->with('success','Settings saved successfully.');
Here the only problem is that this part with the message is not working. Message is not shown. Anyone have idea why?
Do you have something in view where you show that message?
Like:
@if (Session::has('success'))
<div class="alert alert-success">
<ul>
<li>{{ Session::get('success') }}</li>
</ul>
</div>
@endif
No I don't have anything like that, but this is standard way, that I use and it is working everywhere else.
If I put:
return redirect ('/user-settings')->with('success','Settings saved successfully.');
that works. But this not:
return redirect (url('locale/' . $lang))->with('success','Settings saved successfully.');
and yes, the idea is to stay on settings page after saving changes.
On url for example locale/en you redirect again right?
There you need propably reflash it again, there is documentation for it.
$request->session()->keep('success');
Sry my bad. I do have in in app.blade file:
@if ($message = Session::get('success'))
<div class="alert alert-success alert-block">
<button type="button" class="close" data-dismiss="alert">×</button>
<strong>{{ $message }}</strong>
</div>
@endif
@if ($message = Session::get('error'))
<div class="alert alert-danger alert-block">
<button type="button" class="close" data-dismiss="alert">×</button>
<strong>{{ $message }}</strong>
</div>
@endif
and so on, for warning & info type of message
I'll try to reflash.
I will try your solution as well. Thx!
@boby What do you have in you controller where go route url('locale/' . $lang)?
It is a function to update user settings:
public function update(Request $request, UserSettings $userSettings)
{
$attributes['user_id'] = Auth::user()->id;
$attributes = $this->validateGeneralSettings();
UserSettings::where('user_id', Auth::user()->id)->update($attributes);
$lang = Auth::user()->user_settings->language;
return redirect (url('locale/' . $lang))->with('success','Settings saved successfully.');
//return redirect ('/user-settings')->with('success','Settings saved successfully.');
}
other then this there is a validation function and index, which shows existing data in settings. Nothing else.
No I mean what is for url 'locale/' . $lang?
In web.php:
Route::get('locale/{locale}', function ($locale){
Session::put('locale', $locale);
return redirect()->back();
});
Ok try it to change to this:
Route::get('locale/{locale}', function ($locale){
session(['locale' => $locale]);
session()->keep('success');
return redirect()->back();
});
Works that way and I see that the difference is the line:
session()->keep('success');
but how long this message will live? Documentation says: "If you need to keep your flash data around for several requests, you may use the reflash method, which will keep all of the flash data for an additional request."
Does this mean two? If it is longer, that can cause some other problem if that message is live long enough?
Should I "forget" the key success of maybe flush all session messages?
No, you don't have to, now it is ok, because it keeps just for next redirect and you do it there. So it should be everything good now.
So final thing that is left to do is translate non-authorized pages (like login page). I was thinking to do it this way:
- after settings are saved I check if cookie e.g. lang exists and that it has value
- if yes do nothing,
- if no, set it
On login page I set locale based on the cookie content.
What do you think?
Is there a way to set do this for all non-authorized pages at once? Like login, reset password, register, ... so I don't do it on one by one.
Through middleware is the best option for that.
But I am not sure that I know how :(
Probably I need one more middleware like for user settings, just not get the user_settings->language, but cookie value? Am I right?
Where do I put that middleware, and how to say "this middleware is for those pages like login, register, ..."
Hi again,
this solution with keeping session for one more request now created a new problem. I have added cookie creation after settings are saved like this:
return redirect (url('locale/' . $lang))->with('success', __('user_settings.settings_saved'))->cookie('language', $lang, 1440);
so I simply added only
->cookie('language', $lang, 1440)
and the cookie is saved.
Problem is, in order to have a new value (language), I need to press save on settings twice, otherwise I have old value in cookie.
Or I am having something else wrong here, not related to keeping request?
I don't think that problem is related to keeping session.
My problem is not the session :( somehow getting language from database is wrong:
$lang = Auth::user()->user_settings->language;
this is not updated if I don't press save twice. Have no idea why.
DB record is ok, I checked.
I can use request to get correct language, but I don't get it why above way is working from 2nd save and not from the 1st one. So strange...
So, to conclude, how I solved translation, in case someone finds it useful.
First, ofc, I have translation in place in 'lang' folder, so I will skip that part.
Then as @johncarmackfan95 suggested I created middleware, with little modification:
public function handle($request, Closure $next)
{
if(! Auth::check() && (Cookie::get('lang') !== null)) {
app()->setLocale(Cookie::get('lang'));
}
$locale = Auth::check()
? auth()->user()->user_settings->language
: config('app.locale');
app()->setLocale($locale);
return $next($request);
}
so I covered case when user is not logged in with the cookie, which is created in user settings page after clicking button Update:
public function update(Request $request, UserSettings $userSettings)
{
$attributes['user_id'] = Auth::user()->id;
$attributes = $this->validateGeneralSettings();
UserSettings::where('user_id', Auth::user()->id)->update($attributes);
$new_language = $attributes['language'];
return redirect (url('locale/' . $new_language))->with('success', __('user_settings.settings_saved'))->cookie('lang', $new_language, 525600);
}
in my routes I added:
Route::get('locale/{locale}', function ($locale) {
session(['locale' => $locale]);
session()->keep('success');
return redirect()->back();
});
and that is it!
Big thanks to everyone on this thread!
@boby You mentioned the middleware in your third post, that you used from that article.
That solution was different, and it didn't work until I change it to what @johncarmackfan95 suggested, and yesterday I "expanded" it to include non auth pages as well.
Anyhow I just wanted to summarize all in one message in case someone need it.
Thank you.
Please or to participate in this conversation.