-1

I am developing a localization in Laravel 10. When I triggered to change the flag of Localization Then Error Show in Page.

Can anyone tell Just where is the problem ?


Error Message

Call to undefined method App\Http\Middleware\LocalizationMiddleware::setLanguage() in Localization


Here is my LocalizationController Controller

    {
        App::setLocale($locale);
        Session::put('locale', $locale);

        return redirect()->back();
    }

Here is my LocalizationMiddleware

    public function handle(Request $request, Closure $next): Response
    {
        // Set Locale in this Middleware
        App::setLocale(session()->get('selected_language') ?? 'en');

        return $next($request);
    }

Here is my route

Route::get('locale/{locale}',[LocalizationMiddleware::class, 'setLanguage'])->name('locale');

And here is my Blade code

<div class="dropdown ms-1 topbar-head-dropdown header-item">
                    <button type="button" class="btn btn-icon btn-topbar btn-ghost-secondary rounded-circle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                        <img id="header-lang-img" src="{{ asset('/') }}els/images/flags/us.svg" alt="Header Language" height="20" class="rounded">
                    </button>
                    <div class="dropdown-menu dropdown-menu-end">
                        <!-- English language -->
                        <a href="locale/en" class="dropdown-item notify-item language py-2" data-lang="en" title="English">
                            <img src="{{ asset('/') }}els/images/flags/us.svg" alt="user-image" class="me-2 rounded" height="18">
                            <span class="align-middle">English</span>
                        </a>
                        <!-- German Language -->
                        <a href="{{ url('locale/de') }}" class="dropdown-item notify-item language" data-lang="gr" title="German">
                            <img src="{{ asset('/') }}els/images/flags/germany.svg" alt="user-image" class="me-2 rounded" height="18"> <span class="align-middle">Deutsche</span>
                        </a>
                    </div>
                </div>

I don't understand why is this happening.

rozsazoltan
  • 2,831
  • 2
  • 7
  • 20
Mahe Karim
  • 49
  • 1
  • 10

2 Answers2

1

In your route, it should be LocalizationController instead. Try:

Route::get('locale/{locale}',[LocalizationController::class, 'setLanguage'])->name('locale');
Khang Tran
  • 2,015
  • 3
  • 7
  • 10
  • I think it's same with my route – Mahe Karim Apr 16 '23 at 20:15
  • Not entirely. I also inserted the path mentioned by @KhangTran. I suggest checking whether you modified it correctly! In short, we usually call a function of a controller from a route. However, in your original example, you called "Localization**Middleware**". This needs to be modified to "Localization**Controller**". – rozsazoltan Apr 16 '23 at 20:33
  • Oh I See, It was mistaken when i paste here. Thanks! – Mahe Karim Apr 17 '23 at 17:18
1

I see some confusion regarding the use of different modules: Middleware, Controller

Middleware

The Middleware runs before the task associated with the route is executed.. This includes starting a Session or checking authentication for an /admin route.

Controller

The Controller is the last thing that runs when a route is called. For example, displaying a blade, saving a record in the database, querying some data, etc.

enter image description here

Setting the Language

Now, let's focus on the original problem: you want to set the language so that the appropriate language content is loaded on the website.

You want the page to switch to English when a link like /locale/en is called. So, you want to do this after the link is called: using a Controller is recommended.

You can pass variables to the Controller, so you can also pass the language.

app/Http/Controllers/LocalizationController.php

// ...

class LocalizationController extends Controller
{
    public function setLanguage (Request $request)
    {
         // Save selected Locale to current "Session"
         $locale = $request->locale ?? 'en';
         // App::setLocale($locale); --> There is no need for this here, as the middleware will run after the redirect() where it has already been set.
         $request->session()->put('locale', $locale);

         return redirect()->back();
     }
}

Then in the route, you need to call the setLanguage function of LocalizationController::class and pass the language.

routes/web.php

Route::get(
    'locale/{locale}',
    [LocalizationController::class, 'setLanguage']
)->name('locale');

If you want to solve it with middleware, you won't have the opportunity to pass such variables. You need to know that the set language is en from somewhere. It's a good idea to save the set language in the session because you can access the stored values in the middleware. However, be careful in the future not to look for the selected language as selected_language if you saved it as locale before.

app/Http/Middlewares/LocalizationMiddleware.php

// ...

class LocalizationMiddleware
{
    public function handle(Request $request, Closure $next): Response
    {
        // Set Locale in this "Request"
        $locale = $request->session()->get('locale') ?? 'en';
        app()->setLocale($locale);

        return $next($request);
    }
}

How can you set a middleware to run for a specific route in Laravel?

By default, all middleware specified in the web middleware group declared in app/Http/Kernel.php will run for every route. (Why? See boot() function in app/Providers/RouteServiceProvider.php, where we load routes/web.php) So, you need to add your own LocalizationMiddleware to the web group as follows:

app/Http/Kernel.php

protected $middlewareGroups = [
    'web' => [
        // ...
        \App\Http\Middleware\LocalizationMiddleware::class,
    ],
    // ...
];

Summary

How will the code run?

  1. By default, there is no language set, so every route where LocalizationMiddleware is set will prioritize English language (see code).
  2. I choose the German language: de, in reality, I called the /locale/de route, which triggered the LocalizationController setLanguage function. In my session, the value of the locale key was set to de, and at the end of the function, I was redirected back to the previous link. So, as a user, I didn't notice anything.
  3. Due to the redirection, the previous link (from where I called the language change) is reloaded, but now the LocalizationMiddleware runs again where the value associated with the locale key is de, so the middleware overrides the default language to German, and finally, the content is loaded in German from the /lang folder.

Extra

If you store the language in a cookie instead of a session, the next time you visit the page, it will be loaded based on the selected language.
The session is deleted after X time of inactivity. (It is configured in config/session.php in lifetime and deleted by default after 2 hours)

rozsazoltan
  • 2,831
  • 2
  • 7
  • 20
  • 1
    Thanks @rozsazoltan , From your explained, I learned a lot. Though It's not working. I am checking where is issues. – Mahe Karim Apr 16 '23 at 20:21
  • The first phase of your testing should be to check the value of session.locale by printing it out on the blade! This way, when you switch languages, you can verify whether the Session correctly modifies the configuration. It is also good to print out the value corresponding to the locale key stored in the Session itself. – rozsazoltan Apr 16 '23 at 20:30
  • For example: {{ config("session.locale") }} for the currently modified value by Middleware; {{ Session::get("locale", "no set yet") }} for the value stored by the Controller (which does not exist until the first modification, so you can handle the default value in the Middleware: ?? "en", which I set to English). – rozsazoltan Apr 17 '23 at 05:12
  • 1
    I just get the locale value from controller like this `$request->session()->put('locale', $locale); ` Now It's Working fine. Anyway Thanks! – Mahe Karim Apr 17 '23 at 17:19
  • @MaheKarim, Happy to help, and welcome to Stack Overflow. If this answer or any other one solved your issue, please mark it as accepted. – rozsazoltan Aug 17 '23 at 13:43