Back to Course |
Multi-Language Laravel 11: All You Need to Know

Language Switcher with Sessions and DB

Another example of how we can add a language selector to our application is by using sessions and a DB table to store the user's preferred language.

This example will not use a URL to determine the language which will allow us to use the same URL for all languages.


Setup

Our setup process for Database stored language selection will touch these things:

  • Configuration: Adding a language list to our configuration - this will be used to display the language selector
  • DB Structure: Creating a new field on the users table called language
  • Controller: Create a controller that will handle the language change
  • Middleware: Add a middleware to handle language settings based on user's preferences
  • Views: Adding a language selector to our views
  • Routes: Adding a route that will allow us to change the language

Let's start with the configuration:

config/app.php

// ...
'locale' => 'en', // <-- Locate this line and add `available_locales` below it
 
'available_locales' => [
'en',
'es',
],
// ...

Now we need to add a new field to our users table:

php artisan make:migration add_language_to_users_table

Migration

Schema::table('users', function (Blueprint $table) {
$table->string('language')->default('en');
});

app/Models/User.php

protected $fillable = [
// ...
'language'
];

Let's make a Controller that will switch user's language and save it to remember it for the next time:

app/Http/Controllers/ChangeLanguageController.php

public function __invoke($locale)
{
// Check if the locale is available and valid
if (!in_array($locale, config('app.available_locales'))) {
return redirect()->back();
}
 
if (Auth::check()) {
// Update the user's language preference in the database
Auth::user()->update(['language' => $locale]);
} else {
// Set the language in the session for guests
session()->put('locale', $locale);
}
 
// Redirect back to the previous page
return redirect()->back();
}

Now we can create our Middleware:

php artisan make:middleware SetLocale

app/Http/Middleware/SetLocale.php

use Auth;
use Carbon\Carbon;
 
// ...
 
public function handle(Request $request, Closure $next): Response
{
// Logged-in users use their own language preference
if (Auth::check()) {
app()->setLocale(Auth::user()->language);
Carbon::setLocale(Auth::user()->language);
// Guests use the language set in the session
} else {
app()->setLocale(session('locale', 'en'));
Carbon::setLocale(session('locale', 'en'));
}
 
return $next($request);
}

Register our middleware in our bootstrap/app.php file:

bootstrap/app.php

return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
commands: __DIR__.'/../routes/console.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {
$middleware->append(\App\Http\Middleware\SetLocale::class);
})
->withExceptions(function (Exceptions $exceptions) {
//
})->create();

Display the language selector in our views:

resources/views/layouts/navigation.blade.php

{{-- ... --}}
@foreach(config('app.available_locales') as $locale)
<x-nav-link
:href="route('change-locale', $locale)"
:active="app()->getLocale() == $locale">
{{ strtoupper($locale) }}
</x-nav-link>
@endforeach
<x-dropdown align="right" width="48">
{{-- ... --}}

And lastly, we need to modify our routes to use our Middleware and contain an endpoint to change the language:

routes/web.php

use App\Http\Controllers\ChangeLanguageController;
// ...
 
// Our language change endpoint
Route::get('lang/{locale}', ChangeLanguageController::class)->name('change-locale');
 
Route::middleware(SetLocale::class) // <-- Our middleware to set the language
->group(function () {
Route::get('/', function () {
return view('welcome');
});
 
 
Route::get('/dashboard', function () {
return view('dashboard');
})->middleware(['auth', 'verified'])->name('dashboard');
 
Route::middleware('auth')->group(function () {
Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');
Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update');
Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy');
 
// ...
});
 
require __DIR__ . '/auth.php';
});

That's it! Now we can change the language by clicking on the language selector in the navigation bar and it will remember the language for our users indefinitely while guests will have their language set for the current session.


Transforming Guest Language to a User Language Preference

One additional step that we can take to improve the experience and avoid resetting the language for our new users is to take what they set in the session and transform it into a language preference in the database:

app/Http/Controllers/Auth/RegisteredUserController.php

// ...
public function store(Request $request): RedirectResponse
{
// ...
 
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
// Here we set the language preference to the language set in the session
'language' => session('locale', config('app.locale')),
]);
 
// ...
}
// ...

Repository: https://github.com/LaravelDaily/laravel11-localization-course/tree/lesson/session-language-switching