Adding a language selector is crucial to any multilingual application. In this practical example, we'll add a language selector to our navigation bar:
In this first example, we will define the language from the URL segment, like /en/about
or /es/register
.
Here's our plan to set up a language selector:
Let's start with the configuration:
config/app.php
// ...'locale' => 'en', // <-- Locate this line and add `available_locales` below it 'available_locales' => [ 'en', 'es',],// ...
Next, we can create our middleware:
php artisan make:middleware SetLocale
app/Http/Middleware/SetLocale.php
use URL;use Carbon\Carbon; // ... public function handle(Request $request, Closure $next): Response{ app()->setLocale($request->segment(1)); // <-- Set the application locale Carbon::setLocale($request->segment(1)); // <-- Set the Carbon locale URL::defaults(['locale' => $request->segment(1)]); // <-- Set the URL defaults // (for named routes we won't have to specify the locale each time!) return $next($request);}
Now we need to modify Routes to use the new Middleware and add the locale segment to the URL:
routes/web.php
Route::get('/', function () { return redirect(app()->getLocale()); // <-- Handles redirect with no locale to the current locale}); Route::prefix('{locale}') // <-- Add the locale segment to the URL ->where(['locale' => '[a-zA-Z]{2}']) // <-- Add a regex to validate the locale ->middleware(\App\Http\Middleware\SetLocale::class) // <-- Add the middleware ->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';});
Now we can add the language selector to our views:
resources/views/layouts/navigation.blade.php
{{-- ... --}}@foreach(config('app.available_locales') as $locale) <x-nav-link :href="route(\Illuminate\Support\Facades\Route::currentRouteName(), array_merge(Route::current()->parameters(),['locale' => $locale]))" :active="app()->getLocale() == $locale"> {{ strtoupper($locale) }} </x-nav-link>@endforeach<x-dropdown align="right" width="48">{{-- ... --}}
And fix one issue with our Dashboard
link:
resources/views/welcome.blade.php
Replace: {{ url('/dashboard') }}
with {{ route('dashboard') }}
Finally, we need to modify our redirects for authentication:
Redirect after login:
app/Http/Controllers/Auth/AuthenticatedSessionController.php
public function store(LoginRequest $request): RedirectResponse{ $request->authenticate(); $request->session()->regenerate(); return redirect()->intended(route('dashboard', ['locale' => app()->getLocale()]));}
Redirect after the user session expired:
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->redirectGuestsTo(fn() => route('login', ['locale' => app()->getLocale()])); })
Lastly, there is an issue mentioned where registrations do not redirect correctly. For this, we need to modify the RegisteredUserController
:
app/Http/Controllers/Auth/RegisteredUserController.php
// ... public function store(Request $request): RedirectResponse{ // ... return redirect(route('dashboard', absolute: false)); return redirect(route('dashboard', ['locale' => app()->getLocale()], absolute: false)); }
That is it, we are done! Once the page is loaded - we should see that we were redirected from /
to /en
and once the user logs in - we should be redirected to /en/dashboard
:
And switching between languages should work as expected:
Repository: https://github.com/LaravelDaily/laravel11-localization-course/tree/lesson/ui-switching