Mastering multilingual Laravel/PHP applications

Few years ago i wrote an article named Multilingual Laravel applications The Right Way and i was so sure, that this is it. I was right only 50%. In 2017 i have much better solution. A MUCH better!

If you do not want to waste your time reading this article you can grab the package linked below and get on with your life.

https://github.com/keevitaja/linguist

Multilingual application design in Laravel has still the same issues it had in 2015. And still the best option to start with, is to remove the locale slug from the REUQEST_URI before it hits the router. There are many options for doing that, but one approach works with any PHP application.

Remove the locale slug in your applications index.php file.

$default = 'en';
$enabled = ['en', 'et'];
$uri = $_SERVER['REQUEST_URI'];
$pattern = '/^\/('.implode('|', $enabled).')(\/|(?:$)|(?=\?))/';

if (preg_match($pattern, $uri, $matches)) {
    $_SERVER['REQUEST_URI'] = preg_replace($pattern, '/', $uri);

    define('INTERCEPTED_LOCALE', $matches[1]);
} else {
	define('INTERCEPTED_LOCALE', $default);
}

$_SERVER['ORIGINAL_REQUEST_URI'] = $uri;

And now you can use this INTERCEPTED_LOCALE constant in your application configuration and append it to the URI-s when needed. Works with any PHP application!

In Laravel we have to use the Application::setLocale() method if we want to use config::cache.

So do not apply this constant in config/app.php

Application::setLocale(INTERCEPTED_LOCALE);
// or
app()->setLocale(INTERCEPTED_LOCALE);

And to retrieve the current locale always use app()->getLocale().

Another step would be to tell the UrlGenerator to append the locale to the URI. Luckily this is easy as Laravels UrlGenerator is singleton and it has a dedicated method forceRootUrl() for this.

So what we actually do is prepending the locale slug to domain. End result pattern would be http://site.com/en/people.

You can do all this in your applications service provider.

public function boot(
    \Illuminate\Http\Request $request,
    \Illuminate\Contracts\Routing\UrlGenerator $url
) {
    $this->app->setLocale(INTERCEPTED_LOCALE);
    $url->forceRootUrl($request->root().'/'.INTERCEPTED_LOCALE);
}

In real world you need some additional checking when to add this locale slug. But the basics are here. If you're interested you can follow the linguist package on GitHub.