Laravel change locale not working
App::setLocale()
is not persistent, and sets locale only for current request(runtime). You can achieve persistent in multiple ways (example of 2):
Route::post('/locale', function(){ session(['my_locale' => app('request')->input('locale')]); return redirect()->back();});
This will set session key
with lang
value from request for current user. Next create a Middleware
to set locale based on user session language
<?php namespace App\Http\Middleware;use Closure;use Illuminate\Http\Request;use Illuminate\Foundation\Application;class Language { public function __construct(Application $app, Request $request) { $this->app = $app; $this->request = $request; } /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, Closure $next) { $this->app->setLocale(session('my_locale', config('app.locale'))); return $next($request); }}
This will get current session and if is empty will fallback to default locale, which is set in your app config.
In app\Http\Kernel.php
add previously created Language
middleware:
protected $middleware = [ \App\Http\Middleware\Language::class,];
As global middlware or just for web (based on your needs).I hope this helps, and gives an idea on how things are working.
Scenario №2 - Lang based on URL pathCreate an array
with all available locales on your app inside app config
'available_locale' => ['fr', 'gr', 'ja'],
Inside the Middleware we will check the URL first segment en, fr, gr, cy
if this segment is in available_locale
, set language
public function handle($request, Closure $next){ if(in_array($request->segment(1), config('app.available_locale'))){ $this->app->setLocale($request->segment(1)); }else{ $this->app->setLocale(config('app.locale')); } return $next($request);}
You will need to modify app\Providers\RouteServiceProvider
for setting prefix to all your routes. so you can access them domain.com
or domain.com/fr/
with French language
Find: mapWebRoutes
And add this to it: (before add use Illuminate\Http\Request;
)
public function map(Request $request) { $this->mapApiRoutes(); $this->mapWebRoutes($request); } protected function mapWebRoutes(Request $request) { $locale = null; if(in_array($request->segment(1), config('app.available_locale'))){ $locale = $request->segment(1); } Route::group([ 'middleware' => 'web', 'namespace' => $this->namespace, 'prefix' => $locale ], function ($router) { require base_path('routes/web.php'); }); }
This will prefix all your routes with country letter like 'fr gr cy' except en for non-duplicate content, so is better to not add into available_locales_array
I solved my problem from this article https://mydnic.be/post/laravel-5-and-his-fcking-non-persistent-app-setlocale
Thanks to the people who contributed the word 'non persistent'
App::setLocale()
is not persistent.I had a similar problem before so I created a middleware:
<?phpnamespace 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) { if (strpos($request->getHttpHost(), 'fr.') === 0) { \App::setLocale('fr'); } else { \App::setLocale('en'); } return $next($request); }}
And I registered this middleware in app\Http\Kernel
:
protected $middlewareGroups = [ 'web' => [ // ... \App\Http\Middleware\SetLocale::class, // ... ]];
This script works for two domains: http://example.org (en) and http://fr.example.org (fr). As a middleware, it's called on every request, so the locale is always set as the right locale according to the url.
My routes looked like:
Route::group(['domain' => 'fr.' . config('app.root-domain')], function () { Route::get('a-propos', 'HomeController@about'); // ...}Route::group(['domain' => config('app.root-domain')], function () { Route::get('about', 'HomeController@about'); // ...}
So it responds with the correct locale to:
And I use the same controller and same view, just 2 different routes + a global middleware.
Hope it will help, not sure it's the best solution BTW. This solution works without sessio, it matches with domain and/or routes. It has some advantages over session-based solutions:
- No possible bugs due to session usage ("magic" language switch)
- You can rewrite your routes. A french user may want to see "/mon-panier" and english user "/my-cart" in their url.
- Better indexing in google (SEO), because you can have a real index by country with relevant content.
- I use it in production!
It may have it's cons too.