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

Scenario №2 - Lang based on URL path Create 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 example.com or example.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


When user selects language from dropdown, call below route to save language in session

Using Vue.js

LocalizationComponent.vue change language

<template>
<ul>
    <li @click="changeLanguage('en')">
        <a href="javascript:void(0);">
            <img src="/images/flag-1.png"  alt="image description">
            <span>ENG</span>
        </a>
    </li>
    <li @click="changeLanguage('vn')">
        <a href="javascript:void(0);">
            <img src="/images/flag-2.png"  alt="image description">
            <span>Việt</span>
        </a>
    </li>
</ul>

<script>
    export default{
        data(){
            return {
                selected_language:'en',
            }
        },
         methods:{
            changeLanguage(language){
                this.axios.post('/change-locale',{language:language}).then( 
                (response) => {window.location.reload();
            }).catch((error) => {
                console.log(error.response.data.errors)
            });
            localStorage.setItem('selected_language',language);
        }
    }
}
</script>

routes/web.php

Route::post('/change-locale', 'HomeController@changeLocale');

//save locale to session

public function changeLocale(Request $request)
{
    $language = $request->language ?? 'en';
    session(['selected_language' =>$language]);
}

//create middleware to set locale

class Localization
{
    public function handle($request, Closure $next)
    {
        App::setLocale(session()->get('selected_language') ?? 'en');
        return $next($request);
    }
}

In app/Http/Kernel.php

 protected $middlewareGroups = [
    'web' => [
        ...other middelwares
        Localization::class,  //add your localization middleware here
    ],
    //...
];

Done...


App::setLocale() is not persistent. I had a similar problem before so I created a middleware:

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

  • http://fr.example.org/a-propos
  • http://example.org/about

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.


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'