laraveledge / laravel-locale
Elegant URL-based locale handler and middleware for Laravel.
Requires
- php: ^8.1
- illuminate/http: ^10.0|^11.0|^12.0
- illuminate/routing: ^10.0|^11.0|^12.0
- illuminate/session: ^10.0|^11.0|^12.0
- illuminate/support: ^10.0|^11.0|^12.0
Requires (Dev)
- phpunit/phpunit: ^10.0
README
Elegant URL-Based Localization for Laravel Applications
Laravel Locale is a simple yet powerful package for handling localization through URL segments in Laravel. It detects, validates, and manages locale slugs (e.g., /en, /tr) in the request path, with seamless support for session storage, normalization, and middleware-based behavior.
π Table of Contents
- π Installation
- βοΈ Configuration
- π§© Usage
- π Alias Usage
- π¦ Middleware Setup
- π§ Locale Detection Order
- β οΈ Edge Cases
- β What This Package Does
- π Folder Structure
- β Requirements
- π License
π Installation
Install via Composer:
composer require laraveledge/laravel-locale
βοΈ Configuration
Publish the configuration file:
php artisan vendor:publish --tag=laravel-locale-config
This will publish config/locale.php, where you can specify your supported locales:
return [ 'supported_locales' => ['en', 'tr', 'ur'], ];
π§© Usage
Wrap your localized routes using middleware and a {locale} prefix:
use Laraveledge\LaravelLocale\Middleware\SetLocale; use Laraveledge\LaravelLocale\Middleware\EnsureIsLocale; use Laraveledge\LaravelLocale\Middleware\SetDefaultLocaleForUrls; Route::group([ 'prefix' => '{locale}', 'middleware' => [ EnsureIsLocale::class, SetLocale::class, SetDefaultLocaleForUrls::class, 'web', ], ], function () { Route::get('/', fn () => 'Home Page')->name('home'); Route::get('/about', fn () => 'About Page'); Route::get('/test', fn () => 'Test Page')->name('test'); Route::fallback(function () { abort(404, 'Hm, why did you land here somehow?'); }); //Neccessary , why ? see Edge Cases below });
Now visit /, /about, or /test to be redirected to the localized versions.
π Alias Usage
You can also register aliases in bootstrap/app.php to avoid referencing class paths directly:
use Laraveledge\LaravelLocale\Middleware\SetLocale; use Laraveledge\LaravelLocale\Middleware\EnsureIsLocale; use Laraveledge\LaravelLocale\Middleware\SetDefaultLocaleForUrls; ->withMiddleware(function (Middleware $middleware): void { $middleware->alias([ 'ensureIsLocale' => EnsureIsLocale::class, 'redirectMissingLocale' => RedirectMissingLocale::class, 'setDefaultUrls' => SetDefaultLocaleForUrls::class, 'setLocale' => SetLocale::class, ]); });
π¦ Middleware Setup
To avoid conflicts with Laravelβs internal URL binding, make sure to set middleware priority properly:
use Illuminate\Routing\Middleware\SubstituteBindings; ->withMiddleware(function (Middleware $middleware) { $middleware->prependToPriorityList( before: SubstituteBindings::class, prepend: SetDefaultLocaleForUrls::class, ); });
π¦ Full Setup (Copy Paste) - Recommended:
bootstrap/app.php: use Illuminate\Routing\Middleware\SubstituteBindings; use Laraveledge\LaravelLocale\Middleware\SetLocale; use Laraveledge\LaravelLocale\Middleware\EnsureIsLocale; use Laraveledge\LaravelLocale\Middleware\SetDefaultLocaleForUrls; ->withMiddleware(function (Middleware $middleware): void { $middleware->prependToPriorityList( before: SubstituteBindings::class, prepend: SetDefaultLocaleForUrls::class, ); $middleware->alias([ 'ensureIsLocale' => EnsureIsLocale::class, 'setDefaultUrls' => SetDefaultLocaleForUrls::class, 'setLocale' => SetLocale::class, ]); }) web.php: Route::group([ 'prefix' => '{locale}', 'middleware' => ['web', 'ensureIsLocale', 'setLocale', 'setDefaultUrls'] // ensure this middleware order ], function () { Route::get('/', function () { return 'home'; }); Route::get('/about', function () { return 'products'; }); Route::get('/test', function(){ return 'test'; })->name('test'); //ensure a route named test is present in your routes so you can check/test the Locale::debug() mnethod Route::fallback(function () { abort(404, 'Hm, why did you land here somehow?'); }); //Neccessary , why ? see Edge Cases below });
π§ Locale Detection Order
The package detects locale using the following order:
- Session β If a locale exists in session, it is used.
- URL Segment β First segment of the path.
- Browser Preferred Language β Based on
Accept-Languageheader. - Fallback Locale β As defined in
app.fallback_locale.
β οΈ Edge Cases
- If your route is deeply nested like /products/1 and the locale is missing, Laravel may return a 404 before your middleware is ever triggered. This happens because Laravel tries to match the route as-is (e.g., /products/1), but it doesn't exist without a {locale} prefix, so it aborts with a 404 before even hitting the middleware stack.
- However, if you define a Route::fallback() inside your localized group, Laravel is then forced to execute the fallback when no route matches. This allows the middleware to still kick in and redirect appropriately.
- Without a fallback, shallow routes like /products will still work because Laravel can find a matching route and then the middleware handles it. But deep, parameterized routes like /products/1 will fail silently unless the fallback is present.
β Solution: Always define a Route::fallback() within your {locale} route group to ensure nested and parameterized routes also get redirected when the locale is missing.
Route::fallback(function () { abort(404, 'Hm, why did you land here somehow?'); }); ---
β What This Package Does
- β Detects and validates the locale segment in the URL
- π Normalizes casing (e.g.,
EN-usβen) - πΎ Stores the selected locale in session
- π Calls
App::setLocale(...) - π Redirects to localized URLs if missing or invalid
π Inspired by the Greats β Built with Simplicity
This package is inspired by:
These packages have served the Laravel ecosystem well and offer a wide range of features. However, as Laravel modernized its routing and middleware pipeline, we felt the need for a simpler, lighter, and middleware-first approach β without route macros or runtime route manipulation.
π― Why This Package Exists
In real-world projects:
mcamaradynamically registers routes at runtime, which can introduce unpredictable behavior and confusion.codezerouses route macros and abstractions which deviate from native Laravel patterns.
This package solves that by offering:
β
Clean, Laravel-native routing
β
No macros β just plain Route::get() and Route::group()
β
Middleware-first lifecycle control
β
SEO-optimized URL redirection and normalization
β
Works great with Livewire, Inertia, Blade, APIs, SPAs
β
Debug-friendly (Locale::debug())
β
Lightweight, transparent, and easy to extend
π¦ What This Package Is (and Isn't)
This package intentionally starts simple.
It currently does not offer some of the advanced features available in mcamara or codezero such as:
- Automatic route translation
- Locale-prefixed route generation
- URL version negotiation, etc.
We plan to add more features in future versions β while staying true to the Laravel philosophy of clarity over magic.
π§ Choose Based on Your Needs
|-----------------------------------|----------------------------------------| | You Should Use This Package If...| |-----------------------------------|----------------------------------------| | You want a lightweight, zero-config localization system | You prefer Laravel-native routes with no macros | You value predictable middleware-based flow | Youβre building something new and modern |-----------------------------------|----------------------------------------| | You Might Prefer Other Packages If... | |-----------------------------------|----------------------------------------| | You need automatic route translation | You donβt mind learning route macros | You need deeply integrated i18n features | Youβre maintaining legacy systems
π Just Use It β Youβll Feel the Difference
Install it, add middleware, define routes β and youβre done.
Route::group([ 'prefix' => '{locale}', 'middleware' => ['web', 'ensureIsLocale', 'setLocale', 'setDefaultUrls'] ], function () { Route::get('/', fn () => view('home'))->name('home'); });
π Folder Structure
src/
βββ Config/
β βββ locale.php
βββ Middleware/
β βββ EnsureIsLocale.php
β βββ SetLocale.php
β βββ SetDefaultLocaleForUrls.php
βββ Services/
β βββ LocaleService.php
βββ Facades/
β βββ Locale.php (optional)
βββ LaravelLocaleServiceProvider.php
β Requirements
- PHP 8.1+
- Laravel 10+
π License
This package is open-source and released under the MIT License.