laraveledge/laravel-locale

Elegant URL-based locale handler and middleware for Laravel.

Maintainers

Package info

github.com/laravelEdge/laravel-locale

pkg:composer/laraveledge/laravel-locale

Statistics

Installs: 8

Dependents: 0

Suggesters: 0

Stars: 2

Open Issues: 0

v1.9.0 2025-07-03 13:14 UTC

This package is auto-updated.

Last update: 2026-03-31 15:23:51 UTC


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

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:

  1. Session – If a locale exists in session, it is used.
  2. URL Segment – First segment of the path.
  3. Browser Preferred Language – Based on Accept-Language header.
  4. 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:

  • mcamara dynamically registers routes at runtime, which can introduce unpredictable behavior and confusion.
  • codezero uses 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.