Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

carrick's avatar

translate site content based on select menu click using package

I installed this package "https://github.com/mcamara/laravel-localization".

And then put all routes inside "Route::group(['prefix' => LaravelLocalization::setLocale()], function()... });".

But I want to translate the site based on a select menu, so when the user selects a language in the select menu the site content should translate to the selected language using the above package.

Do you know what is necessary to integrate the select menu with the package to achieve that goal?

<form method="post" action="" id="translate">
      {{csrf_field()}}
      <select name="language" id="language">
        <option value="en">English</option>
        <option value="de">German</option>
        <option value="es">Spanish</option>
      </select>
    </form>

0 likes
41 replies
lostdreamer_nl's avatar
Level 53

about a week ago I gave this answer to someone else as well for this package. Here is a small example of how to use this package but use your own logic to handle the change:

https://laracasts.com/discuss/channels/tips/is-there-a-good-package-for-subdomain-laravel-translations

But instead of using the ServiceProvider option to check the subdomain, you can use a middleware like my answer here to set it:

https://laracasts.com/discuss/channels/laravel/multiple-language-route-w-model-collection

If you need more help, let me know

1 like
carrick's avatar

Thanks but using that first link approach for example when the user is on the homepage and change to the "spanish" language on the select menu the user is redirected to "https://proj.test/es" and it appears "Sorry, the page you are looking for could not be found.

carrick's avatar

I just install the package and did the configuration as it is on the first link in the APPserviceProvider, like:

class AppServiceProvider extends ServiceProvider
{
  
    public function boot()
    {
        setlocale(LC_TIME, config('app.locale'));
        \LaravelLocalization::setLocale( $this->getSubDomain() );
        \URL::forceScheme('https');
        DB::listen(function ($query) {
            //var_dump($query->sql);
        });
    }

    private function getSubDomain()
    {
        $domain = preg_replace('#^https?://#', '', request()->root());
        return substr($domain, 0, strpos($domain, '.'));
    }
  
    public function register()
    {
        //
    }
}

Select menu html:

<form method="post">
  {{csrf_field()}}
  <select name="language" class="form-control font-weight-normal text-gray" id="language" onchange="localize">
    <option value="en">English</option>
    <option value="fr">French</option>
    <option value="es">Spanish</option>
    <option>5</option>
  </select>
</form>

jQuery:


$(document).ready(function() {

      $('#language').on('change',function(){
            let locale = document.getElementById('language').value;
            let path = window.location.pathname.split('/').slice(2).join('/');
            window.location = `//${window.location.hostname}/${locale}/${path}`;
      });

    });

lostdreamer_nl's avatar

Using the middleware option I gave in the second link you can change the language by a ?language=en parameter on any URL.

You can remove the code from the AppServiceProvider as the middleware will now be doing this part.

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('language')) {
            $lang = $request->language;
            if(array_search($lang, $this->languages) === false) {
                $lang = $this->default;
            }

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

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

        return $next($request);
    }

}

Add it to your web middlewares:


    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',
        ],
    ];

And change your dropdown to this:

// changed the form to GET instead of POST, no need for a csrf this way either
<form method="get">
  <select name="language" class="form-control font-weight-normal text-gray" id="language" onchange="localize">
    <option value="en">English</option>
    <option value="fr">French</option>
    <option value="es">Spanish</option>
    <option>5</option>
  </select>
</form>

And remember not to use the route group of the package (the middleware is handling the language selection now)

// do not use this part of the LaravelLocalization package
Route::group(['prefix' => LaravelLocalization::setLocale()], function() {
1 like
carrick's avatar

Thanks but so is necessary to create a Translate class? This class should be inside the app folder?

lostdreamer_nl's avatar

Check the namespace ;)

namespace App\Http\Middleware;

use Closure;

class Translate

The Translate class is a piece of middleware that will run on all requests, checks if there is a ?language={LANG} and if so, changes the language.

carrick's avatar

Thanks, so is necessary to create like "php artisan make:middleware Translate "?

1 like
lostdreamer_nl's avatar

you can do it that way, or just copy paste the code that I gave into a new file (app\Http\Middleware\Translate.php)

If you go for the artisan command method, dont forget to replace the newly created class with the code I gave ;)

1 like
carrick's avatar

Thanks, the $middelwareGroups property is in the Kernel.php?

carrick's avatar

With that configurations and with form and jQuery belowwhen the user change the language in the form it appears "Symfony\Component\HttpKernel\Exception\ MethodNotAllowedHttpException in RouteCollection.php.

<form method="post" id="translate">
{{csrf_field()}}
<select name="language" class="form-control font-weight-normal text-gray" id="language" onchange="localize">
    <option value="en">English</option>
    <option value="fr">French</option>
    <option value="es">Spanish</option>
    <option>5</option>
</select>
</form

jQuery:


$(document).ready(function() {

        var myFormName = "translate";

        $('#language').on('change', function() {
            $('#translate').submit();
        });
    });
    ```
lostdreamer_nl's avatar

MethodNotAllowedHttpException is was you get when you GET a route ment for POSTing to, or the other way around.

To fix, simply change your form from POST to GET:

<form method="get" id="translate">

Since most users will be changing their language on a GET page instead of right after submitting a form, this should do fine.

1 like
carrick's avatar

Thanks, but with "get" still appears when the user change the language in the form "Symfony\Component\HttpKernel\Exception\ MethodNotAllowedHttpException in RouteCollection.php." error.

lostdreamer_nl's avatar

for which route is that then? I'm guessing it's a POST route?

ps. code goes between

```

code goes here

```

carrick's avatar

Sorry, I didnt understand. The form is like:

<form method="post" id="translate">
{{csrf_field()}}
<select name="language" class="form-control font-weight-normal text-gray" id="language" onchange="localize">
    <option value="en">English</option>
    <option value="fr">French</option>
    <option value="es">Spanish</option>
    <option>5</option>
</select>
</form


lostdreamer_nl's avatar

So as I said before:

<form method="post" id="translate">

Should be:

<form method="get" id="translate">
carrick's avatar

Thanks, like that when the user clicks for example in the language "French" in the select menu the site is not translated and the url change from "proj.test" to "proj.test/?_token=o....&language=fr."

carrick's avatar

With code below if the user is in the "proj.test" homepage and change to "french" in the select menu the url change to "https://proj.test/?_token=o...&language=fr" and the content is not translated.

Class Translate:

<?php

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('language')) {
            $lang = $request->language;
            if(array_search($lang, $this->languages) === false) {
                $lang = $this->default;
            }

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

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

        return $next($request);
    }

}

Form:

 <form method="get" id="translate">
    {{csrf_field()}}
    <select name="language" class="form-control font-weight-normal text-gray" id="language" onchange="localize">
        <option value="en">English</option>
        <option value="fr">French</option>
        <option value="es">Spanish</option>
        <option>5</option>
    </select>
</form>

Kernel.php:

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
        ],
    ];


lostdreamer_nl's avatar

ok, last 2 checks then:

Put this in your view to debug (underneath the language form)

</form> // this is the old form close tag of the language selection

Current locale: {{ LaravelLocalization::getCurrentLocale() }}

And check if the language you are trying (french in the last case) is also setup in the config/laravellocalization.php file (if not, it wont switch to that language)

Then change the language again and check if the 'Current locale: ...' below the translate dropdown switched as well.

ps. You can remove the csrf_token from the form as we are not POSTing it anymore.

1 like
carrick's avatar

It shows always "current locale: en" even after the user select for example the language "french". And the config/laravellocalization.php seems that dont exist. Its in the config folder? That file its in the vendor folder.

lostdreamer_nl's avatar

"That file its in the vendor folder."

NEVER change a file in the vendor folder, when you do a composer update it might be gone.

As the installation guide for that package says to do:

php artisan vendor:publish --provider="Mcamara\LaravelLocalization\LaravelLocalizationServiceProvider"

That will 'publish' the config file for the package into your app's config folder so you can change it.

Can you try the following change in the Translate middleware? To make sure it is loading and checking if it picks up on the query parameter


    public function handle($request, Closure $next)
    {
        // add the following line:
        dd($request->has('language'), $request->language, $request->all());

        if($request->has('language')) {
            $lang = $request->language;
            if(array_search($lang, $this->languages) === false) {
                $lang = $this->default;
            }

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

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

        return $next($request);
    }

Just make sure you have your website loaded in the browser first, then you add that line into the middleware, and after that you change the language in the dropdown.

Just copy paste the output back here. (between the ` please ;) )

1 like
carrick's avatar

Thanks it appears if the user selects the french language in the select menu:



true

"fr"

array:1[
"language" => "fr"
]

lostdreamer_nl's avatar

That's weird, everything is working, but it's not....

And this one?


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

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

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

        // add the following line:
        dd($request->session()->get('lang'), \LaravelLocalization::getLocale() );

        return $next($request);
    }

carrick's avatar

Call to undefined method Mcamara\LaravelLocalization\LaravelLocalization::getLocale()

lostdreamer_nl's avatar

Sorry my bad, it seems they called it 'getCurrentLocale'


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

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

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

        // add the following line:
        dd($request->session()->get('lang'), \LaravelLocalization::getCurrentLocale() );

        return $next($request);
    }
1 like
lostdreamer_nl's avatar

ok, so it should have turned to FR, but it stayed on EN.....

A while back I asked if you published the config file:

php artisan vendor:publish --provider="Mcamara\LaravelLocalization\LaravelLocalizationServiceProvider"

Which would give you a config file in config/laravellocalization.php

This is the file that should be in there: https://github.com/mcamara/laravel-localization/blob/master/src/config/config.php

In this huge array, any language you want to be able to select should be uncommented.

I'm guessing 'fr' is still commented, so you can't switch to that language.

If you have the config file there, and 'fr' is not commented, then you should check the output of: dd( LaravelLocalization::getSupportedLocales() );to make sure it's in there.

1 like
carrick's avatar

Thanks it was commented I uncommented the " 'fr' => ['name' => 'French', 'script' => 'Latn', 'native' => 'français', 'regional' => 'fr_FR'], ". But when the user is in the homepage like "project.test" and select the french language in the footer in the select menu the url change to "http://project.test/?language=fr" but the site content is not translated.

Next

Please or to participate in this conversation.