Laravel’s Multilingual Progression

If you’re building a multilingual site you may want to guess what the user’s language is in order to provide the correct content and still let him/her decide afterward which language to use.

Such solution is concealed within a two part problem:

Find a way to detect the user’s native language and then tell Laravel to use it WHILE still providing a way for the user to change it AND store that choice in session.

This simple tutorial will not cover how to make a multilingual Laravel application, as for that I’ll suggest you take a look at Laravel’s Translatable and this tutorial on Laravel News.

Moving forward;

1. Detecting the user’s native language:

There are multiple ways to detect a language from an HTTP Request but as I only need to check for English or for French users, I chose to check if any of those were present in the HTTP_ACCEPT_LANGUAGE HTTP directive and fall back to English if nothing matches French (or any other languages).

The best way to do this is to use a Middleware. By typing in the following command from the console to create a new middleware:

PHP artisan make:middleware SetLocale

<?php

namespace App\Http\Middleware;

use Closure;
use Session;
use App;
use Config;

class SetLocale
{
/**
*
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if (Session::has('locale'))
{
$locale = Session::get('locale', Config::get('app.locale'));
}
else
{
$locale = substr($request->server('HTTP_ACCEPT_LANGUAGE'), 0, 2);

if ($locale != 'fr' && $locale != 'en')
{
$locale = 'en';
}
}

App::setLocale($locale);

return $next($request);
}
}

After, you will need to register this middleware to be fired on each request within the $middleware attribute located inside: app/Http/Middleware/Kernel.php

Which will look something similar to this:

/**
* The application's global HTTP middleware stack.
*
* @var array
*/
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\App\Http\Middleware\SetLocale::class,
];

2. Allowing the user to change his/her locale whenever:

Below is a simple form using Laravel’s Collective Forms and Bootstrap 3 with a select input to let the user choose its language. This is not necessarily the best UX implementation that you should use but for now, on this tutorial, we’ll use it as an example. You should decide on your own what UX solution fits best for your setup.

{!! Form::open(['method' => 'POST', 'route' => 'changelocale', 'class' => 'form-inline navbar-select']) !!}

<div class="form-group @if($errors->first('locale')) has-error @endif">
<span aria-hidden="true"><i class="fa fa-flag"></i></span>
{!! Form::select(
'locale',
['en' => 'EN', 'fr' => 'FR'],
\App::getLocale(),
[
'id' => 'locale',
'class' => 'form-control',
'required' => 'required',
'onchange' => 'this.form.submit()',
]
) !!}
<small class="text-danger">{{ $errors->first('locale') }}</small>
</div>

<div class="btn-group pull-right sr-only">
{!! Form::submit("Change", ['class' => 'btn btn-success']) !!}
</div>

{!! Form::close() !!}

After, simply declare aPOST route to bind the form to the method located inside: app/Http/routes.php as shown in the example below:

route::post(‘changelocale’, [‘as’ => ‘changelocale’, ‘uses’ => ‘TranslationController@changeLocale’]);

And finally, the very last piece — adding the controller method! In this example below, we’ll append (add) it to: app/Http/Controllers/TranslationController.php

However, feel free to append it to any controller of your liking (don’t forget to also change the route though).

/**
* Change session locale
* @param Request $request
* @return Response
*/
public function changeLocale(Request $request)
{
$this->validate($request, ['locale' => 'required|in:fr,en']);

\Session::put('locale', $request->locale);

return redirect()->back();
}

And that’s all. #happycoding

Points of references: