Last Updated: September 09, 2019
·
21.3K
· marvinroger

Easy i18n with language prefix and language-related route in Laravel 4

I have seen a lot of snippets on how to get language prefixing in URL with Laravel 4. The problem is I was not able to find how to actually keep the prefix in the final URL and how to get a custom URL translated into each language.

So I worked on it and hey, it works pretty well !

I. Setting the available languages

In app/config/app.php, simply add a line with your available languages:

'available_locales' => array('de', 'en', 'es', 'fr', 'it')

II. Translating your URL routes

In app/lang/xx, create a file routes.php with your translated routes, and repeat it for each language. For example, in app/lang/fr/routes.php:

<?php

return array(

    /*
    |--------------------------------------------------------------------------
    | Routes
    |--------------------------------------------------------------------------
    |
    | The following language lines contain the routes of the website
    |
    */

    'about' => 'a-propos',
    'contact' => 'contact'

);

III. Connecting routes

It's time to connect your routes ! Firstly, we have to extract the language code (if it exists) from the URL, and to tell Laravel the language to be used. Then, we create a route prefixed group with the language, and we create our named routes. Why named ? Because this way, we will be able to retrieve the URL for the route we want with the prefix in the views. Simple !

<?php

/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| Here is where you can register all of the routes for an application.
| It's a breeze. Simply tell Laravel the URIs it should respond to
| and give it the Closure to execute when that URI is requested.
|
*/

$locale = Request::segment(1);

if (in_array($locale, Config::get('app.available_locales'))) {
    \App::setLocale($locale);
} else {
    $locale = null;
}

Route::group(array('prefix' => $locale), function()
{

    Route::get(Lang::get('routes.about'), array('as' => 'about', function()
    {
        return View::make('about');
    }));

    Route::get(Lang::get('routes.contact'), array('as' => 'contact', function()
    {
        return View::make('contact');
    }));

});

Here we are ! We can now access /fr/a-propos, or /en/about, and it will just work. Great, huh ?

IV. Setting up the links in the views

We have to setup the links so that if:

  • If we're on the french pages, the about link, for example, is /fr/a-propos
  • If we're on the english pages, the about link, for example, is /en/about

It is pretty easy since we used named routes. Let's create a link with that in mind, for example app/views/home.blade.php:

<a href="{{ URL::route('about') }}"></a>

V (optionnal, but recommended). One content, One URL

Be careful, having two URL for the same content is bad for SEO. Say your default language is english, then /en/about and /about will be the same. But it's up to you, maybe that is a behaviour you want. Anyway, if you want to avoid this, you can just remove the default language from available_locales in the app config. That is not a problem since the default language is already set in the locale variable.

9 Responses
Add your response

I run into an HttpNotFoundException when implementing as you described. The difference on my side is that I only wanted to throw in "de" and "en" as languages. In step 1 you declare "availablelanguages" but retrieve "app.availablelocales" in step 3. Is that a typo? And I assume you mean "app/lang/xx/routes.php" instead of "config/lang/xx/routes.php" in step 2, right? However, it works that way.

I needed to read the docs about localization again before I got an idea about what was wrong. A bumpy ride, but thanks anyway!

over 1 year ago ·

Actually yes, it was a typo. Thanks to you, I fixed them all and it should be alright now.
Pleased that you managed to get it working! :)

Thanks again.

over 1 year ago ·

Great pro tip, but how do you dynamically change language on website from /en to just / and backward while keeping the user on the same page?

Found the solution: https://coderwall.com/p/txyl3g

over 1 year ago ·

Thanks !

The problem with your approach is you lost the translated route for each language ("/en/home" -> "/fr/home" and not "/fr/accueil"). I will look into it.

over 1 year ago ·

Np, I have found a bug in my code, but that is not it.
By Google suggestions you should have only one URL for specific content and prefix that with a language tag, so I keep all of my routes in english and just change the language tag.

In that way if the "user" wants to see the same page on a different language he does not need to know the slug in the specific language, but only append the desired language to the slug.

This is the way I prefer to keep my URL schema for better SEO.

over 1 year ago ·

Good point, we are on the same wavelength! However, the goal of this protip is to provide a way to allow language related routes, as some people want it. :)

over 1 year ago ·

Hallo friend coders! :) I am just wondering how to obtain fully translated anchors in every supported language, and in an efficient way perhaps...

The problem is that you can only find the right url translation after a specific route has been recognized. Maybe add these translations to the response with a Middleware running after the request has been handled, fetching the variable part of the url (slug) from the DB and simply translating the rest with Lang::trans().

I doubt this is the most efficient pattern, yet can't think of a better one at the moment, I am still a beginner with Laravel.

Anyway: do you have any links supporting that statement about better SEO when the slug stays in the same language? This would completely void the effort to translate the slugs!

Thanks!

over 1 year ago ·

Hi,
How i can add language part in all url in blade
like example.com/ar/aboutus

I am using in blade file like this
<a href="aboutus">About us</a>

over 1 year ago ·

what about an area without language prefix? for example admin/ ?

over 1 year ago ·