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.
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!