@thesnakebite please format your code correctly by wrapping it within triple backticks
```
// your code
```
Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.
Hi everyone, I need to change the language of my app using a select. From my web.php file
Route::get('language/{locale}', [LanguageController::class, 'changeLanguage'])- >name('language.change');
In my LanguageController.php controller in the changeLanguage method...
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\App;
use Illuminate\Http\Request;
class LanguageController extends Controller
{
public function changeLanguage($locale)
{
if (array_key_exists($locale, config('app.available_locales'))) {
session()->put('locale', $locale);
app()->setLocale($locale);
}
return redirect()->back();
}
}
Now in my config/app.php file I added the variable available:locales ...
'locale' => env('APP_LOCALE', 'es'),
'fallback_locale' => env('APP_FALLBACK_LOCALE', 'en'),
'faker_locale' => env('APP_FAKER_LOCALE', 'en_US'),
'available_locales' => [
'Español (España)' => 'es',
'English' => 'en',
],
... Below I have created a new middleware...
public function handle(Request $request, Closure $next): Response
{
if (session()->has('locale')) {
app()->setLocale(session()->get('locale'));
} else {
app()->setLocale(config('app.locale'));
}
return $next($request);
}
... From my HandleInertiaRequest.php file I enter...
public function share(Request $request): array
{
$currentLocale = session('locale', config('app.locale'));
Log::info('Inertia sharing locale:', ['locale' => $currentLocale]);
return array_merge(parent::share($request), [
'locale' => $currentLocale,
'available_locales' => config('app.available_locales'),
'translation' => function() {
$locale = app()->getLocale();
$path = base_path("/lang/{$locale}.json");
$content = file_get_contents($path);
return json_decode($content);
},
]);
}
... Also registered the Localization middleware in the bootstrap/app.php file ...
->withMiddleware(function (Middleware $middleware) {
$middleware->web(append: [
\App\Http\Middleware\HandleInertiaRequests::class,
\Illuminate\Http\Middleware\AddLinkHeadersForPreloadedAssets::class,
\App\Http\Middleware\Localization::class,
]);
//
})
... And finally in my vue component in your script...
<script setup>
import { Link, usePage } from '@inertiajs/vue3'
const page = usePage()
const changeLanguage = (locale) => {
window.location.href = route('language.change', locale);
};
</script>
...and in your template...
<select
v-model="page.props.locale"
@change="changeLanguage(page.props.locale)"
class="appearance-none border-0 bg-transparent text-gray-600 text-xs cursor-pointer focus:outline-none focus:ring-0 hover:border-0 active:border-0"
aria-label="Change language"
>
<option v-for="(code, name) in page.props.available_locales" :key="code" :value="code">
{{name}}
</option>
</select>
The behavior I'm getting is that the selector doesn't change and the language change isn't added either, any suggestions?
@thesnakebite please format your code correctly by wrapping it within triple backticks
```
// your code
```
Sorry @tykus
@thesnakebite In your changeLanguage method, you are looking for the keys of available_locales array in your config. However, the condition never evaluates to true because the keys in available_locales are Español (España) and English, while you are passing es or en. Please update changeLanguage in your controller to the following:
public function changeLanguage($locale)
{
if (in_array($locale, config('app.available_locales'))) {
session()->put('locale', $locale);
app()->setLocale($locale);
}
return redirect()->back();
}
In the Footer component, the language change is not functional because the implementation is not properly updating the page.props.locale variable.
<script setup>
import { Link, usePage } from '@inertiajs/vue3'
const page = usePage()
const changeLanguage = (locale) => {
router.get(route('language.change', locale), {}, {
preserveScroll: true,
onSuccess: () => window.location.reload(),
});
};
</script>
<div class="flex flex-col xs:flex-row justify-center items-center static overflow-y-visible overflow-x-visible gap-1 xs:gap-4">
<!-- Idiomas -->
<select @change="changeLanguage(page.props.locale)"
class="appearance-none border-0 bg-transparent text-gray-600 text-xs cursor-pointer focus:outline-none focus:ring-0 hover:border-0 active:border-0"
aria-label="Cambiar idioma">
<option v-for="(name, code) in page.props.available_locales" :key="code" :value="code">
{{ name }}
</option>
</select>
<!-- Copyright -->
<span class="text-gray-600 text-xs block max-w-full break-all m-0 wrap min-w-0 overflow-y-visible overflow-x-visible relative">
@ 2024 Setupstagram from Álvaro dev
</span>
</div>
The problem is that the @change event does not update page.props.locale when the user selects a new language. This means that the app does not correctly reflect the language change. In another component of my app called SuggestionsPanel, the language change is functional because the implementation uses a modal with checkboxes that directly update the selected language. This allows the language change to be correctly reflected throughout the app.
<script setup>
import { ref } from 'vue'
import { Link, usePage } from '@inertiajs/vue3'
import Modal from './Modal.vue'
import Checkbox from './Checkbox.vue';
const showModal = ref(false);
const page = usePage();
const selectedLanguage = ref(page.props.locale)
const showLanguageModal = () => {
showModal.value = true;
};
const changeLanguage = (locale) => {
window.location.href = route('language.change', locale)
showModal.value = false
};
</script>
<li class="_ab8f">
<a href="#" class="hover:underline" @click.prevent="showLanguageModal" ref="languageLink">
<span class="max-w-full overflow-y-visible overflow-x-visible whitespace-pre-line break-words">Idioma</span>
</a>
</li>
<Modal :show="showModal" @close="showModal = false">
<div class="p-6">
<div class="flex flex-col mb-5">
<span class="text-custom-blue-500 font-robotobold text-lg">Idioma de la aplicación</span>
<span class="text-xs text-custom-hover-like font-robotoregular">Mira botones, títulos y otro texto de Instagram en tu idioma preferido.</span>
</div>
<div class="flex flex-col justify-between space-y-2">
<div class="flex justify-between items-center">
<span class="text-base text-black font-robotoregular">Español (España)</span>
<Checkbox
:checked="selectedLanguage === 'es'"
@update:checked="changeLanguage('es')"
/>
</div>
<div class="flex justify-between items-center">
<span class="text-base text-black font-robotoregular">English</span>
<Checkbox
:checked="selectedLanguage === 'en'"
@update:checked="changeLanguage('en')"
/>
</div>
</div>
</div>
</Modal>
Because I don't have the same consistency with the select_ element?
@thesnakebite For the select options, use v-model for two-way binding, and avoid passing page.props.locale to the changeLanguage.
Please ensure your code is well-organized and properly imports the required components. Wrap your HTML code within <template></template> in your Vue component.
After receiving your suggestions @rebwar, I have made several adjustments to my implementation of language switching in the Footer component of my app. Let me share the steps I have followed and the results I have obtained:
Verifying the language settings in the config/app.php file:
I have confirmed that the language codes ('es', 'en') and language names ('Español (España)', 'English') are defined correctly.
Debugging the language switching logic:
I have added several console.log in the changeLanguage function to verify that it is being called correctly and that it receives the expected language value. However, I have noticed that even when a different language is selected, the select in the Footer component still displays the default language.
Verifying the server response:
I added a console.log to inspect the server response after redirecting the user to the language change route. The response appears to be correct and the language change is being processed properly on the server.
After performing these tests, I am still unable to determine the cause of the problem. The language change is being processed correctly, but it is not being reflected in the Footer component.
<script setup>
import { ref } from 'vue';
import { usePage, router, Link } from '@inertiajs/vue3';
const page = usePage();
const selectedLanguage = ref(page.props.locale);
const changeLanguage = (locale) => {
console.log('Changing language to:', locale);
router.get(route('language.change', locale), {}, {
preserveScroll: true,
onSuccess: () => window.location.reload(),
});
};
</script>
<template #footer>
<footer class="flex flex-col items-stretch box-border shrink-0 m-0 py-0 px-4 relative align-baseline">
<div class="flex flex-col justify-center items-stretch self-auto box-border overflow-y-visible overflow-x-visible mb-[52px]">
<!-- Enlaces -->
<div class="flex flex-col justify-start items-stretch self-auto grow-0 mt-6 overflow-y-visible overflow-x-visible">
<div class="flex flex-row flex-wrap content-stretch justify-center box-border shrink-0 items-stretch self-auto grow-0 relative overflow-y-visible overflow-x-visible">
<div class="flex flex-col justify-start mb-1 tablet:mb-3 mx-2 grow-0 box-border shrink-0 self-auto overflow-y-visible overflow-x-visible relative">
<Link
class="text-gray-600 text-xs"
href=""
>
<span class="overflow-y-visible overflow-x-visible min-w-0 m-0 max-w-full break-words relative whitespace-pre-line hover:underline">
Meta
</span>
</Link>
</div>
<div class="flex flex-col justify-start mb-1 tablet:mb-3 mx-2 grow-0 box-border shrink-0 self-auto overflow-y-visible overflow-x-visible relative">
<Link
class="text-gray-600 text-xs"
href=""
>
<span class="overflow-y-visible overflow-x-visible min-w-0 m-0 max-w-full break-words relative whitespace-pre-line hover:underline">
Información
</span>
</Link>
</div>
<div class="flex flex-col justify-start mb-1 tablet:mb-3 mx-2 grow-0 box-border shrink-0 self-auto overflow-y-visible overflow-x-visible relative">
<Link
class="text-gray-600 text-xs"
href=""
>
<span class="overflow-y-visible overflow-x-visible min-w-0 m-0 max-w-full break-words relative whitespace-pre-line hover:underline">
Blog
</span>
</Link>
</div>
<div class="flex flex-col justify-start mb-1 tablet:mb-3 mx-2 grow-0 box-border shrink-0 self-auto overflow-y-visible overflow-x-visible relative">
<Link
class="text-gray-600 text-xs"
href=""
>
<span class="overflow-y-visible overflow-x-visible min-w-0 m-0 max-w-full break-words relative whitespace-pre-line hover:underline">
Empleo
</span>
</Link>
</div>
<div class="flex flex-col justify-start mb-1 tablet:mb-3 mx-2 grow-0 box-border shrink-0 self-auto overflow-y-visible overflow-x-visible relative">
<Link
class="text-gray-600 text-xs"
href=""
>
<span class="overflow-y-visible overflow-x-visible min-w-0 m-0 max-w-full break-words relative whitespace-pre-line hover:underline">
Ayuda
</span>
</Link>
</div>
<div class="flex flex-col justify-start mb-1 tablet:mb-3 mx-2 grow-0 box-border shrink-0 self-auto overflow-y-visible overflow-x-visible relative">
<Link
class="text-gray-600 text-xs"
href=""
>
<span class="overflow-y-visible overflow-x-visible min-w-0 m-0 max-w-full break-words relative whitespace-pre-line hover:underline">
API
</span>
</Link>
</div>
<div class="flex flex-col justify-start mb-1 tablet:mb-3 mx-2 grow-0 box-border shrink-0 self-auto overflow-y-visible overflow-x-visible relative">
<Link
class="text-gray-600 text-xs"
href=""
>
<span class="overflow-y-visible overflow-x-visible min-w-0 m-0 max-w-full break-words relative whitespace-pre-line hover:underline">
Privacidad
</span>
</Link>
</div>
<div class="flex flex-col justify-start mb-1 tablet:mb-3 mx-2 grow-0 box-border shrink-0 self-auto overflow-y-visible overflow-x-visible relative">
<Link
class="text-gray-600 text-xs"
href=""
>
<span class="overflow-y-visible overflow-x-visible min-w-0 m-0 max-w-full break-words relative whitespace-pre-line hover:underline">
Condiciones
</span>
</Link>
</div>
<div class="flex flex-col justify-start mb-1 tablet:mb-3 mx-2 grow-0 box-border shrink-0 self-auto overflow-y-visible overflow-x-visible relative">
<Link
class="text-gray-600 text-xs"
href=""
>
<span class="overflow-y-visible overflow-x-visible min-w-0 m-0 max-w-full break-words relative whitespace-pre-line hover:underline">
Ubicaciones
</span>
</Link>
</div>
<div class="flex flex-col justify-start mb-1 tablet:mb-3 mx-2 grow-0 box-border shrink-0 self-auto overflow-y-visible overflow-x-visible relative">
<Link
class="text-gray-600 text-xs"
href=""
>
<span class="overflow-y-visible overflow-x-visible min-w-0 m-0 max-w-full break-words relative whitespace-pre-line hover:underline">
Setupstagram Lite
</span>
</Link>
</div>
<div class="flex flex-col justify-start mb-1 tablet:mb-3 mx-2 grow-0 box-border shrink-0 self-auto overflow-y-visible overflow-x-visible relative">
<Link
class="text-gray-600 text-xs"
href=""
>
<span class="overflow-y-visible overflow-x-visible min-w-0 m-0 max-w-full break-words relative whitespace-pre-line hover:underline">
Threads
</span>
</Link>
</div>
<div class="flex flex-col justify-start mb-1 tablet:mb-3 mx-2 grow-0 box-border shrink-0 self-auto overflow-y-visible overflow-x-visible relative">
<Link
class="text-gray-600 text-xs"
href=""
>
<span class="overflow-y-visible overflow-x-visible min-w-0 m-0 max-w-full break-words relative whitespace-pre-line hover:underline">
Subir contactos y personas no usuarias
</span>
</Link>
</div>
<div class="flex flex-col justify-start mb-1 tablet:mb-3 mx-2 grow-0 box-border shrink-0 self-auto overflow-y-visible overflow-x-visible relative">
<Link
class="text-gray-600 text-xs"
href=""
>
<span class="overflow-y-visible overflow-x-visible min-w-0 m-0 max-w-full break-words relative whitespace-pre-line hover:underline">
Meta Verified
</span>
</Link>
</div>
</div>
</div>
<div class="flex justify-center items-stretch self-auto grow-0 mt-4 lg:my-0 overflow-y-visible overflow-x-visible">
<span class="inline-block relative align-top">
<div class="flex flex-col xs:flex-row justify-center items-center static overflow-y-visible overflow-x-visible gap-1 xs:gap-4">
<!-- Idiomas -->
<div>
<select
v-model="selectedLanguage"
@change="changeLanguage(selectedLanguage)"
class="appearance-none border-0 bg-transparent text-gray-600 text-xs cursor-pointer focus:outline-none focus:ring-0 hover:border-0 active:border-0"
aria-label="Cambiar idioma"
>
<option v-for="(name, code) in page.props.available_locales" :key="code" :value="code">
{{ name }}
</option>
</select>
</div>
<!-- Copyright -->
<span class="text-gray-600 text-xs block max-w-full break-all m-0 wrap min-w-0 overflow-y-visible overflow-x-visible relative">
@ 2024 Setupstagram from Álvaro devode
</span>
</div>
</span>
</div>
</div>
</footer>
</template>
change:
<option v-for="(name, code) in page.props.available_locales" :key="code" :value="code"> {{ name }}</option>
to:
<option v-for="(code, name) in page.props.available_locales" :key="code" :value="code"> {{ name }}</option>
Thanks for the feedback but this change only shows the config/app.php options in the front-end. The behavior I get is when I select the language from the home page using the select element, it automatically returns to the app's default language.
@thesnakebite Ensure that your frontend sends the correct locale and verify in your controller that you are receiving and setting the locale correctly. If you'd like to share your code, please provide only the portion responsible for handling the locale change, without including any unrelated code.
The problem is that although the language change seems to work correctly in the backend, the Footer component of my application does not reflect the language change selected by the user.
public function changeLanguage($locale)
{
logger()->info('Changing language to:' , ['locale' => $locale]);
if(in_array($locale, config('app.available_locales'))) {
logger()->info('Valid locale, updating session and app...');
session()->put('locale', $locale);
app()->setLocale($locale);
} else {
logger()->warning('Invalid locale received:', ['locale' => $locale]);
}
return redirect()->back();
}
The Localization middleware created ...
class Localization
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
if (session()->has('locale')) {
app()->setLocale(session()->get('locale'));
} else {
app()->setLocale(config('app.locale'));
}
return $next($request);
}
}
And my config/app.php file ...
/*
|--------------------------------------------------------------------------
| Application Locale Configuration
|--------------------------------------------------------------------------
|
| The application locale determines the default locale that will be used
| by Laravel's translation / localization methods. This option can be
| set to any locale for which you plan to have translation strings.
|
*/
'locale' => env('APP_LOCALE', 'en'),
'fallback_locale' => env('APP_FALLBACK_LOCALE', 'en'),
'faker_locale' => env('APP_FAKER_LOCALE', 'en_US'),
'available_locales' => [
'Español (España)' => 'es',
'English' => 'en',
],
356 / 5.000 The problem persists in the select element, because...
1 - On the home page, when you change the language in the Footer component's select to "English", the select automatically reverts to displaying the "Spanish" language. 2 - However, once you log in and enter the application, the menus and other elements are displayed correctly translated.
@thesnakebite What does dd($locale) output in the changeLanguage method of your controller?
It is very strange that nothing is being received in the dd($locale) of the LanguageController controller. I have checked the route and controller but I cannot figure out why I am not receiving the dd value on the screen.
// Idioma
Route::get('/language/{locale}', [LanguageController::class, 'changeLanguage'])->name('language.change');
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class LanguageController extends Controller
{
public function changeLanguage($locale)
{
dd($locale);
if(in_array($locale, config('app.available_locales'))) {
session()->put('locale', $locale);
app()->setLocale($locale);
}
return redirect()->back();
}
}
@thesnakebite This means your controller is not being reached when selecting a locale from the frontend. Check the language select field, the function used to send the request to the controller, and ensure there are no typos. Additionally, inspect your browser's console for any errors when selecting the locale.
@thesnakebite Hi. See link Let me know if you need help. I speak spanish(Hablo español) https://es.stackoverflow.com/questions/623013/selecci%c3%b3n-de-idioma-en-laravel-11-de-manera-persistente/623032#623032
Hi, thanks @juanjota for the link and for a more concise look at the problem I'm facing with my app's language change.
When implementing the changes in my app I realized that the routes file is within the group of routes protected by authentication, which shouldn't be the case, since the language change should be available for both authenticated and unauthenticated users.
Once the route was moved out of the group it is now functional in my app, but I have implemented the language change in two different components of my app: one on the home page (where unauthenticated users can access) and another in an options panel (which only authenticated users can access).
The problem I'm getting is that, when an authenticated user makes the language change in the options panel and then logs out, the application returns to the default language on the home page, even though the user had selected a different language.
class Localization
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
if (session()->has('locale')) {
app()->setLocale(session()->get('locale'));
} else {
app()->setLocale(config('app.locale'));
}
return $next($request);
}
}
You should ensure that the selected language value is being updated correctly in the user session, and that the Localization middleware is setting the application language appropriately.
Please or to participate in this conversation.