Multiple Language Route w/ Model Collection

Published 1 month ago by splendidkeen

While implementing multiple languages, I face some issues with my Routes. Logically, Users can adjust languages within the footer, which will trigger the following Route

Route::get('/lang/{lang?}', function($lang=NULL){
    App::setLocale($lang);
    return view('home');
})->name('lang');

But if I need to add a collection of Partners or something similar on the homepage, I normally structure my routes this way:

Route::get('/', '[email protected]')->name('home');

// HomeController

public function index()
    {
        $partners = Partner::orderBy('created_at', 'desc')->get(); 

        return view ('home', compact('partners'));
    }   

How can I add the partners Collection to the language route structure?

Could there be problems with a home redirect, because basically the home.blade.php Route is / and not /lang/{lang?}.

Best Answer (As Selected By splendidkeen)
lostdreamer_nl

Something like this should do :

namespace App\Http\Middleware;

use Closure;

class Translate
{
    protected $default = 'en';

    protected $languages = [
         'en',
         'nl',
         'fr',
    ];

    public function handle($request, Closure $next)
    {
        if($request->has('lang')) {
            $lang = $request->lang;
            if(array_search($lang, $this->languages) === false) {
                $lang = $this->default;
            }

            $request->session()->put('lang', $request->lang);
        }

        \App::setLocale( $request->session()->get('lang') );

        return $next($request);
    }

}

Dont forget to add it in app/Http/Kernel.php:


    protected $middleware = [
        \App\Http\Middleware\Translate::class,
    ];

Going to any URI with ?lang=fr will load french, lang=doesntexist wil load english

After that, going to a regular page should keep you in that same language

lostdreamer_nl

Do your translation in a piece of middleware. Check if there is a ?lang=... request variable, if so, put it in the session

If there is a lang variable in the session, use App::setLocale() in the same middleware to change language.

Now you can change language on any page by adding ?lang=nl to it. After the first change, it will memorize your setting.

splendidkeen

How would that look like? @lostdreamer_nl

Currently I am handling translations using localization, which works, but not for the case of adding collections of Models to my view.

lostdreamer_nl

Something like this should do :

namespace App\Http\Middleware;

use Closure;

class Translate
{
    protected $default = 'en';

    protected $languages = [
         'en',
         'nl',
         'fr',
    ];

    public function handle($request, Closure $next)
    {
        if($request->has('lang')) {
            $lang = $request->lang;
            if(array_search($lang, $this->languages) === false) {
                $lang = $this->default;
            }

            $request->session()->put('lang', $request->lang);
        }

        \App::setLocale( $request->session()->get('lang') );

        return $next($request);
    }

}

Dont forget to add it in app/Http/Kernel.php:


    protected $middleware = [
        \App\Http\Middleware\Translate::class,
    ];

Going to any URI with ?lang=fr will load french, lang=doesntexist wil load english

After that, going to a regular page should keep you in that same language

splendidkeen

Thank you. How do I add it to my routes, then? @lostdreamer_nl

Tray2
Tray2
1 month ago (97,280 XP)

I would set a parameter on the user as to which language to use and then check it inside the controller on which language to pull or view for that matter,

splendidkeen

@Tray2 How would that effect my routing structure?

Tray2
Tray2
1 month ago (97,280 XP)

It wouldn't and that is the beauty of it.

Route::get('/page', '[email protected]');
public function index()
{
    $view = '';
    switch(getUserLanguage()) {
    case 'EN':
        $view = 'somemodel.index_en';
    break;
    //Additional languages
    default:
        $view = 'somemodel.index_en;
    }
    
    return view($view);
}

Something like that should work.

lostdreamer_nl

@splendidkeen Using the middleware option does not require any setup in your routing, by adding the middleware to the provider it will be used on every request and setup the language. Simply add the code as instructed, and visit your website.

Then go to your website, but add "?lang=en" to any route, from that point on you're app will be put in the english locale for that user until they select another language or break the session.

Putting your logic for translation inside your controller is not a smart thing as you will have to repeat the logic in every controller.

splendidkeen

@lostdreamer_nl

My routes will remain in this structure, right?

Route::get('/', '[email protected]')->name('home');

Logically, I could implement a logic, that checks on a stored parameter with respect to the language a User chooses, e.g. at signup, within this middleware?

lostdreamer_nl

Yes, your routes remain unchanged, as long as the Middleware is setup in your Kernel.php it will work.

And yes, you could ofcourse refactor this code to see if the user is logged in, and grab some setting from their profile ti set the language. Simply use auth()->user() to get the logged in user object and access any saved attribute from there to set the language.

splendidkeen

Thank you @lostdreamer_nl

splendidkeen

Sorry for combing back @lostdreamer_nl

After adding the middleware to my Kernel.php, I get the error: Session store not set on request for every page, any recommendations?

lostdreamer_nl

@splendidkeen Aah yes, my bad:

Instead of this:

    protected $middleware = [
        \App\Http\Middleware\Translate::class,
    ];

Try adding it only to the web middleware group, below the SessionStart middleware


    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,  // <-- without this one, it wont work
            // \Illuminate\Session\Middleware\AuthenticateSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
            \App\Http\Middleware\Translate::class,   // <-- Add it here
        ],
        'api' => [
            'throttle:60,1',
            'bindings',
        ],
    ];
splendidkeen

Thank you for coming back. It works @lostdreamer_nl

splendidkeen

Sorry for coming back @lostdreamer_nl

I tried to check based on a language_id integer on the User/ Partner Model, which language to choose for this session. Right now it is not working.

class Language
{
    protected $default = 'en';

    protected $languages = [
         'en',
         'de', 
    ];

    public function handle($request, Closure $next)
    {
        if($request->has('lang')) {
            $lang = $request->lang;
            if(array_search($lang, $this->languages) === false) {
                $lang = $this->default;
            }
    
        // How can I check on the authenticated user (User.php or Partner.php, both with 'language_id' on their table, referring to Language.php)
    
           if(auth()->guard('partner')){
        
        if (auth()->user()->language_id == 1) {
                    $request->session()->put('lang', 'en');
                } elseif (auth()->user()->language_id == 2) {
                    $request->session()->put('lang', 'de');
                }
       } else{
        
        if (auth()->user()->language_id == 1) {
                    $request->session()->put('lang', 'en');
                } elseif (auth()->user()->language_id == 2) {
                    $request->session()->put('lang', 'de');
                }
       }

            $request->session()->put('lang', $request->lang);
        }

        \App::setLocale( $request->session()->get('lang') );

        return $next($request);
    }
}

Please sign in or create an account to participate in this conversation.