Giogiosw's avatar

Set Lang with Cookie

Hello

I have to set the language through the use of cookies but I have some problems

I created the following code to set the Cookie and it works

Route::get('setlocale/{lang}',function($lang){

  $durata= 15;

  Cookie::queue('lang', $lang, $durata);

  return redirect()->back();

});

if I insert the following code in the routes it works perfectly

 if (Cookie::get('lang') !== null){
     App::setLocale(Cookie::get('lang'));
    }

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

use Cookie;
use Carbon\Carbon;
class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
      if (Cookie::get('lang') !== null){
         App::setLocale(Cookie::get('lang'));
        }
    }
}


How can I make sure that it is automatically set in all the routes?

I used laravel 6.

0 likes
16 replies
fylzero's avatar

@giogiosw Maybe edit the config/app.php file with...

Top of file... Elvis operator saying if there is a cookie value for lang, use that... otherwise use en

<?php

$language = cookie('lang') ?: 'en';

return [

Change this mid-file... pass the cookie lang or en to the config.


    /*
    |--------------------------------------------------------------------------
    | Application Locale Configuration
    |--------------------------------------------------------------------------
    |
    | The application locale determines the default locale that will be used
    | by the translation service provider. You are free to set this value
    | to any of the locales which will be supported by the application.
    |
    */

    'locale' => $language,

1 like
Giogiosw's avatar

i have this error:

Fatal error: Uncaught RuntimeException: A facade root has not been set. in C:\xampp\htdocs\cv\vendor\laravel\framework\src\Illuminate\Support\Facades\Facade.php:258 Stack trace: #0 C:\xampp\htdocs\cv\vendor\laravel\framework\src\Illuminate\Foundation\Exceptions\Handler.php(424): Illuminate\Support\Facades\Facade::__callStatic('replaceNamespac...', Array) #1 C:\xampp\htdocs\cv\vendor\laravel\framework\src\Illuminate\Foundation\Exceptions\Handler.php(401): Illuminate\Foundation\Exceptions\Handler->registerErrorViewPaths() #2 C:\xampp\htdocs\cv\vendor\laravel\framework\src\Illuminate\Foundation\Exceptions\Handler.php(312): Illuminate\Foundation\Exceptions\Handler->renderHttpException(Object(Symfony\Component\HttpKernel\Exception\HttpException)) #3 C:\xampp\htdocs\cv\vendor\laravel\framework\src\Illuminate\Foundation\Exceptions\Handler.php(209): Illuminate\Foundation\Exceptions\Handler->prepareResponse(Object(Illuminate\Http\Request), Object(Symfony\Component\HttpKernel\Exception\HttpException)) #4 C:\xampp\htdocs\cv\app\Exce in C:\xampp\htdocs\cv\vendor\laravel\framework\src\Illuminate\Support\Facades\Facade.php on line 258

bugsysha's avatar

Having it in ServiceProvider should work. I'm not sure from your post if defining it in ServiceProvider is working for you or not?

fylzero's avatar

@giogiosw Actually, put it in the boot method of AppServiceProvider.

public function boot()
{
    // Set locale from cookie, otherwise use default app config setting...
    app()->setLocale( cookie('lang') ?: config('app.locale') );
}
1 like
Giogiosw's avatar

@fylzero I tried but it doesn't work.

It appears that the cookie is not read correctly in the file.

fylzero's avatar

@giogiosw

Set client cookie... 20 mins

Cookie::queue( Cookie::make('lang', 'es', 20) );

Set client cookie... forever

Cookie::queue( Cookie::forever('lang', 'es') );

Get cookie...

Cookie::get('lang');

The cookie() helper was returning weird for me as well. Make sure you explicitly use the facade use Illuminate\Support\Facades\Cookie;

I guess queue allows the cookie to be attached to the response headers so it can be set on the clients machine. I thought this happened implicitly, it doesn't seem to. I rarely reach for cookies for this. Usually I set these types of things in the session, which uses a cookie anyway, just seems easier to deal with.

In fact, you might just want to use that approach. Store the language preference in the database and then save that to the session on login. That would be more robust because then the setting would save across different machines the user may be using.

Just dropping a language cookie off... if the user goes on their phone or on a different computer, their language would revert to default. Something to consider.

2 likes
fylzero's avatar

@giogiosw Just figured out... in AppServiceProvier the cookie is still encrypted... still trying to figure this out for ya...

1 like
fylzero's avatar
fylzero
Best Answer
Level 67

@giogiosw I would just do this... it is a bit excessive... but...

Create middlewear to check for a language cookie.

php artisan make:middleware SetLocale

app/Http/Middleware/SetLocale.php

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Cookie;

class SetLocale
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        // You can optimize / cache this probably so you aren't actually checking for it on every request.
        // .Not sure if that is expensive really / probably not.  Depends on what scale you're working with.
        App::setLocale( Cookie::get('lang') ?: config('app.locale') );

        return $next($request);
    }
}

app/Http/Kernel.php

    protected $routeMiddleware = [
        // Everything else
        'set.locale' => \App\Http\Middleware\SetLocale::class,
    ];

app/Providers/RouteServiceProvider.php

protected function mapWebRoutes()
{
    Route::middleware(['web', 'set.locale'])
            ->namespace($this->namespace)
            ->group(base_path('routes/web.php'));
}

Just drop the cookie on the user machine like this..

Cookie::queue( Cookie::make('lang', 'es', 20) );

I just testing this... looks like it works fine. By editing the RouteServiceProvider and adding the middleware to web routes... that will automatically apply the middleware to anything in the web.php route file.

Again, I'd still reconsider using session for this purpose. Seems more robust / proper.

2 likes
bugsysha's avatar

Cookie encryption middleware is not active at that point in Service Providers so that is why you are getting encrypted values.

1 like
fylzero's avatar

@bugsysha Yeah, I still have a lot to learn about lifecycle stuff in Laravel.

1 like
bugsysha's avatar

I could not remember why but I guess this is the reason why I always used language as part of the URL.

louk116's avatar

Hello everybody , this is my solution that i'm using it works smoothly i hope this will help someone else:

// What you need in web.php
// life cycle of cookie 1440 minutes = 24 hours you may change it as you want 

Route::get('lang/{locale}', function ($locale) {
   if (! in_array($locale, ['en', 'ar', 'fr','es'])) {
       abort(400);
   }
	Cookie::queue( Cookie::make('lang', $locale,1440) ); 
	return back();
});

if (Request::hasCookie('lang')){
	App::setLocale(Crypt::decrypt(Cookie::get('lang'), false)); 
}



//--------------------in Blade buttons to set your language 

       <div>
           <a href="{{url('lang/en')}}"> English </a>
           <a href="{{url('lang/ar')}}"> Arabic </a>
           <a href="{{url('lang/fr')}}"> Français </a>
           <a href="{{url('lang/es')}}"> Spanish </a>
       </div>


1 like

Please or to participate in this conversation.