Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Marwelln's avatar

Example on how to use multiple locales in your Laravel 5 website

The following will make domain.com/{locale} available to your website.

What you need to use multiple locales is three things.

  1. Add list of available locales to an array.
  2. Prefix all your routes with current locale.
  3. A language middleware that checks if user is using a valid locale.

Step 1: Add your locales

Open up config/app.php and add the following below 'locale' => 'xx'.

'locales' => ['en' => 'English', 'sv' => 'Swedish'],

Modify this array with your desired locales.

Example at Github

Step 2: Prefix your routes

To prefix our routes, we change the map method in app/Providers/RouteServiceProvider.php. Change the map method to the following:

public function map(Router $router, Request $request)
{
    $locale = $request->segment(1);
    $this->app->setLocale($locale);

    $router->group(['namespace' => $this->namespace, 'prefix' => $locale], function($router) {
        require app_path('Http/routes.php');
    });
}

Then add this to the top of the file:

use Illuminate\Routing\Router;
use Illuminate\Http\Request;

Example at Github

Step 3: Create a language middleware

Now create a file named Language.php in app/Http/Middleware with this content:

<?php namespace App\Http\Middleware;

use Closure;
use Illuminate\Routing\Redirector;
use Illuminate\Http\Request;
use Illuminate\Foundation\Application;
use Illuminate\Contracts\Routing\Middleware;

class Language implements Middleware {

    public function __construct(Application $app, Redirector $redirector, Request $request) {
        $this->app = $app;
        $this->redirector = $redirector;
        $this->request = $request;
    }

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        // Make sure current locale exists.
        $locale = $request->segment(1);

        if ( ! array_key_exists($locale, $this->app->config->get('app.locales'))) {
            $segments = $request->segments();
            $segments[0] = $this->app->config->get('app.fallback_locale');

            return $this->redirector->to(implode('/', $segments));
        }

        $this->app->setLocale($locale);

        return $next($request);
    }

}

Example at Github

Now make that middleware run on all requests by adding it to the $middleware property in app/Http/Kernel.php. It is recommended to add it to the top of the array.

protected $middleware = [
    'App\Http\Middleware\Language',
    'Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode',
    'Illuminate\Cookie\Middleware\EncryptCookies',
    'Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse',
    'Illuminate\Session\Middleware\StartSession',
    'Illuminate\View\Middleware\ShareErrorsFromSession',
    'Illuminate\Foundation\Http\Middleware\VerifyCsrfToken',
];

Example at Github

You are now set to go.

Example repo

I have an example repository available at https://github.com/Marwelln/laravel-multiple-locales – clone it to test it out or if you are unsure how it works.

0 likes
47 replies
rjsworking's avatar

Thank you very much.

Next step: translate the routes :)

pmall's avatar

I prefer when the middleware set the locale then remove it from the route parameters. This way no overhead with route prefix or extra action param.

1 like
igaster's avatar

Slight modification when the request has parameters in a query string: eg: http:\domain.com\xxx?yyy=zzz

change:

        return $this->redirector->to(implode('/', $segments));

to

$newUrl = implode('/', $segments);
if (array_key_exists('QUERY_STRING', $_SERVER))
    $newUrl .= '?'.$_SERVER['QUERY_STRING'];   
return $this->redirector->to($newUrl);
4 likes
Ncls's avatar

I get

NotFoundHttpException in compiled.php line 7618:

using the exact code, any ideas?

MarcoMdMj's avatar

Nice explanation.

I have a doubt about the middleware (Language.php). Why do you call each class (Application, Redirector, Request, etc.) and import them into the middleware instead of using their facades directly in the handdle method?

<?php namespace App\Http\Middleware;

use Closure, Config, App, Redirect; // ... and so on

class Language implements Middleware {

    public function __construct() {
        //
    }

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        // Make sure current locale exists.
        $locale = $request->segment(1);

        if ( ! array_key_exists($locale, Config::get('app.locales'))) {
            $segments = $request->segments();
            $segments[0] = Config::get('app.fallback_locale');

            return Redirect::to(implode('/', $segments));
        }

        App::setLocale($locale);

        return $next($request);

    }

}

Also, is it necessary to implement the Middleware object when definning the class? I've generated a middleware using artisan, and it just don't do it.

Thanks.

2 likes
MarcoMdMj's avatar

@Marwelln, you mention sometime ago that we could translate the routes using trans(). In your post, I've notice that you are editing the map method in the RouteServiceProvider to set the Locale of the app before the routes.php file is included.

Is it a good practice to edit those files? Wouldn't it difficult the process of upgrading Laravel? Also, the app locale is already being set in the middleware after some validation, which of course is skipped in the modification I've quoted. Is there another way to do it?

Thanks

Ncls's avatar

Did you set it in your config/app.php? (app.locales) refers to the $locales array in your app config file.

arbrix's avatar

I was stuck with implementation this solution with Lumen.

I can't find RouteServiceProvider in Lumen, so can't redeclare map method and define locale before routing. I added hardcore initiation in route.php.

@pmall can you provide link to example of such solutions?

I'm not found information about variables in translation. Can you advise anything? I found only vsprintf way as worked solution.

Thanks

dev0urer's avatar

I can't figure out how to access the public directory using this code. I know I can use the asset() function, but that doesn't work inside of my css.

andy's avatar

Is it possible to remove the default locale from the URL? Any code for that?

1 like
renky's avatar

@jberzins802: I had exactly the same problem and found this solution for me now:

First update your RouteServiceProviders map-function to add prefix as Variable {lang}

$router->group(['namespace' => $this->namespace, 'prefix' => '{lang}'], function($router) {
    require app_path('Http/routes.php');
});

After that you can use the route-Helper-Function to get routes to all different languages like this:

route('home', ['lang' => 'fr'])

The Middleware is still working, if you enter a route without language prefix. But now you MUST give the lang-Parameter to your routes. This is not a problem if you're just starting with your application, but I was already far away from that point.

So my next solution is to overwrite the route-Helper-Function of laravel and always give in a default lang-param. I did it this way:

Create a file: /app/Http/helpers.php with this content:

<?php
    /**
     * Generate a URL to a named route.
     *
     * @param  string  $name
     * @param  array   $parameters
     * @param  bool    $absolute
     * @param  \Illuminate\Routing\Route  $route
     * @return string
     */
    function route($name, $parameters = [], $absolute = true, $route = null)
   {
    if (!isset($parameters['lang'])) $parameters['lang'] = App::getLocale();
        
        return app('url')->route($name, $parameters, $absolute, $route);
    }

Now load this file before laravel helpers are loaded. Unfortunatelly there is no possibility to give composer an order for loading. So my solution is changing the file bootstrap/autoload.php and insert a line before vendor/autoload.php is included:

require __DIR__.'/../app/Http/helpers.php';
require __DIR__.'/../vendor/autoload.php';

Now you can switch between the languages over the parameter lang, but you are not forced to do it. To switch to the same page as is opened at the moment you can use this:

route(Route::currentRouteName(), ['lang' => 'de'])

I think the same would be possible with the other Url-Helpers like action() or url() if you don't use named routes.

iskubiy's avatar

what if I dont want to show locale in url if my current locale is the default one

1 like
kozusnik's avatar

Hello,

do you have any idea, why the exact code returns "NotFoundHttpException in compiled.php line 7693:"?

postitief's avatar

@igaster

One issue with your code. If you enter the URL without an localization, it will redirect you to the default locale. But it will also always add a question mark ? to the URL.

In your code:

if (array_key_exists('QUERY_STRING', $_SERVER))

But the array_key 'QUERY_STRING' might always exists. At least it is at my Homestead installation. So it is better to check if it exists and has a value. Like this:

if (!empty($_SERVER['QUERY_STRING'])) {
1 like
postitief's avatar

@renky, I'm getting a error.

Fatal error: Cannot redeclare route() (previously declared in /home/vagrant/Code/project/vendor/laravel/framework/src/Illuminate/Foundation/helpers.php:491) in /home/vagrant/Code/project/app/Http/Helpers.php on line 24
buro-buro's avatar

this is great but it doesnt work with my other route groups :(

heavycode's avatar

Hi, i have an issue when going to AuthController and PasswordController. In theese cases it tries to prefix with domain/en/login but NotFoundHttpException in RouteCollection. Any ideas?

robertm's avatar

When you use route:cache with this code, it doesn't work. In map() method:

public function map(Router $router, Request $request)
    {
        // Locale
        $locale = $request->segment(1);
        \Log::info('locale:' . $locale);

$locale is not set, it is empty value. When I remove route cache with cache:clear, everything works.

Is it possible to read $request->segment(1) when routes are read from cache?

icemanblas's avatar

Hi, this solution works perfectly, but I have a strange 'RuntimeException: Session store not set on request' when I try to login, for example. Could this be anyhow connected? I'm using basic auth in Laravel 5.1. This is the whole exception code:

RuntimeException in Request.php line 758: Session store not set on request.

    in Request.php line 758
    at Request->session() in VerifyCsrfToken.php line 87
    at VerifyCsrfToken->tokensMatch(object(Request)) in VerifyCsrfToken.php line 49
    at VerifyCsrfToken->handle(object(Request), object(Closure))
    at call_user_func_array(array(object(VerifyCsrfToken), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 124
    at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in Language.php line 38
    at Language->handle(object(Request), object(Closure))
    at call_user_func_array(array(object(Language), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 124
    at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in EncryptCookies.php line 59
    at EncryptCookies->handle(object(Request), object(Closure))
    at call_user_func_array(array(object(EncryptCookies), 'handle'), array(object(Request), object(Closure))) in Pipeline.php line 124
    at Pipeline->Illuminate\Pipeline\{closure}(object(Request))
    at call_user_func(object(Closure), object(Request)) in Pipeline.php line 103
    at Pipeline->then(object(Closure)) in Kernel.php line 122
    at Kernel->sendRequestThroughRouter(object(Request)) in Kernel.php line 87
    at Kernel->handle(object(Request)) in index.php line 54

What are the real causes for this exception? Any idea is appreciated.

1 like
goeroe's avatar

Everything works just fine but what's the best practice to ignore this all for specific routes? For example if you have an /admin route (that doesn't need a locale)

icemanblas's avatar

Hi, @goeroe , I figured out that the 'RuntimeException' is not related to languages and locales. While it's still a mystery to me, I created a fresh project and manually imported all my files and now it's working as expected.

RossTsachev's avatar

After implementing this kind of localization all my Laravel-specific tests are broken. Has anyone else encountered it or is it just me doing something wrong?

1 like
Pingvalue's avatar

Have the same issue here when using the visit() method in my unit tests. I think that it's caused by the visit() method expecting a status 200. The language middleware redirects if locale is missing.

Can anyone confirm?

Next

Please or to participate in this conversation.