chinleung/laravel-multilingual-routes
Register multilingual Laravel routes from a single definition. Automatically generates locale-prefixed URLs based on configured locales, with optional default-locale prefixing. Includes middleware to detect request locale and switch the app locale accordingly.
Installation:
composer require chinleung/laravel-multilingual-routes
Ensure compatibility with your Laravel version (check version matrix).
Middleware Setup:
Add DetectRequestLocale as the first middleware in bootstrap/app.php:
$middleware->web(prepend: [DetectRequestLocale::class]);
Configure Locales:
Publish the config and set app.locales (e.g., ['en', 'fr']):
php artisan vendor:publish --provider="ChinLeung\MultilingualRoutes\MultilingualRoutesServiceProvider" --tag="config"
Or use chinleung/laravel-locales for dynamic locale management.
First Route:
Replace manual locale-specific routes (e.g., Route::get('/fr', ...)) with:
Route::multilingual('/', 'HomeController')->name('home');
This auto-generates / (en) and /fr/ (fr) routes.
resources/lang/{locale}/routes.php for URI translations (e.g., 'test' => 'teste' for French).localized_route(), current_route(), and current_route_is() in Blade/views or controllers.Scenario: A bilingual blog with English (/posts) and French (/articles) URLs.
Solution:
resources/lang/fr/routes.php:
return ['posts' => 'articles'];
Route::multilingualResource('posts', 'PostController');
// English: /posts
localized_route('posts.index');
// French: /articles
localized_route('posts.index', [], 'fr');
Basic Route:
Route::multilingual('contact', 'ContactController')->name('contact');
Generates:
GET /contact (en.contact)GET /fr/contact (fr.contact) if translated in routes.php.Resource Routes:
Route::multilingualResource('products', 'ProductController')
->only(['index', 'show'])
->middleware('auth');
Supports all Laravel resource features (e.g., withTrashed, missing, parameters).
Route::multilingual('home')->names(['en' => 'home', 'fr' => 'accueil']);
Route::multilingual('admin')->only(['en']); // Only English
Route::multilingual('promo')->except(['fr']); // Exclude French
Route::multilingual('about'); // Loads `about.blade.php`
Route::multilingual('team')->view('members', ['active' => true]);
Route::multilingual('old-page')->redirect('new-page');
if (Request::localizedRouteIs('dashboard')) { ... }
chinleung/laravel-locales to dynamically manage locales (e.g., user-selected languages).// app/Providers/AppServiceProvider.php
public function boot()
{
$locales = Locale::getSupportedLocales(); // From laravel-locales
config(['app.locales' => $locales]);
}
/api and ensure locale detection works:
Route::prefix('api')->group(function () {
Route::multilingual('v1/users', 'UserController');
});
localized_route() in API responses for consistent URLs.public function handle(Request $request, Closure $next)
{
if ($request->routeIs('fr.*')) {
// French-specific logic
}
return $next($request);
}
actingAs() with locale switching:
$response = $this->actingAs($user)->withHeaders(['Accept-Language' => 'fr'])
->get(localized_route('home'));
routes.php.Route::multilingual('blog')->fallbackLocale('en'); // Fallback to English
php artisan route:cache) may not update multilingual routes.php artisan route:clear
php artisan route:cache
DetectRequestLocale may override other middleware (e.g., session-based locales).photos/{photo}).// resources/lang/fr/routes.php
return [
'photos/{photo}' => 'photos/{photo_id}'
];
signedLocalizedRoute() may break if the locale changes.URL::signedLocalizedRoute('unsubscribe', [], 'fr');
Route::get('/debug-routes', function () {
return response()->json(Route::getRoutes()->getByName());
});
public function handle($request, Closure $next)
{
\Log::info('Detected locale:', ['locale' => app()->getLocale()]);
return $next($request);
}
app()->setLocale('fr');
Route::multilingual('test')->translations(['test' => 'debug']);
use ChinLeung\MultilingualRoutes\RouteGenerator;
class CustomRouteGenerator extends RouteGenerator
{
public function generate($uri, $locale)
{
// Custom logic (e.g., add API version)
return parent::generate($uri, $locale) . '/v1';
}
}
Bind it in AppServiceProvider:
$this->app->bind(RouteGenerator::class, function () {
return new CustomRouteGenerator();
});
Route::get('/switch-locale/{locale}', function ($locale) {
app()->setLocale($locale);
return redirect()->back();
})->name('switch.locale');
Route::multilingual('fallback')->fallback(function ($request) {
return redirect()->route('home');
});
// Override the translation resolver
Route::multilingual('dynamic')->translations(function ($locale, $uri) {
return DB::table('route_translations')->where('uri', $uri)->where('locale', $locale)->first()->translated_uri
How can I help you explore Laravel packages today?