Laravel change locale not working

后端 未结 5 1762
温柔的废话
温柔的废话 2020-12-09 10:00

I am using a dropdown lists for the languages, consisting of english and dutch.

相关标签:
5条回答
  • 2020-12-09 10:09

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

    0 讨论(0)
  • 2020-12-09 10:09

    setLocale will only change the language for the rest of the request from that point on.

    So to persist it, you could look into setting the selected language in a session (https://laravel.com/docs/session). Then you can create a middeware (https://laravel.com/docs/middleware) where you can check if a language is set in the session and then apply it for the request :)

    0 讨论(0)
  • 2020-12-09 10:11

    App::setLocale() is not persistent, it set locale only for current request(runtime). What you can do:

    Route::post('/locale', function(){
    
         session(['my_locale' => Request::Input('locale')]);
    
         return redirect()->back();
    });
    

    This will set session key for current user After we will need a Middleware to detect locale

    <?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 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 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)
        {
            if(in_array($request->segment(1), config('app.available_locale'))){
              $locale = $request->segment(1);
            }else{
              $locale = null;
            }
            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

    0 讨论(0)
  • 2020-12-09 10:14

    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'

    0 讨论(0)
  • 2020-12-09 10:24

    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.

    0 讨论(0)
提交回复
热议问题