Laravel: Detect Language & Set Locale

Do you want to detect the language of the user visiting your website? This is a really useful function for automatically setting the locale of your Laravel application.

Add the following to your base controller's public function __construct(). This will make sure that it loads for every page. However, please be aware that if you overwrite the __construct() in your own controllers that you will have to refer to the base controller's function by using parent::__construct().

App\Http\Controllers\Controller

public function __construct()
{
    if(Session::has('locale'))
    {
        Config::set('app.locale', Session::get('locale', 'en'));
    }
    else
    {
        Config::set('app.locale', getBrowserLocale());
    }
}

You will need to add a helper function to get the user's locale. Please note that you can add the locales that your website accepts in the array $websiteLanguages

helpers.php

function getBrowserLocale()
{
   // Credit: https://gist.github.com/Xeoncross/dc2ebf017676ae946082
   $websiteLanguages = ['EN', 'JA', 'NL'];
   // Parse the Accept-Language according to:
   // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
   preg_match_all(
      '/([a-z]{1,8})' .       // M1 - First part of language e.g en
      '(-[a-z]{1,8})*\s*' .   // M2 -other parts of language e.g -us
      // Optional quality factor M3 ;q=, M4 - Quality Factor
      '(;\s*q\s*=\s*((1(\.0{0,3}))|(0(\.[0-9]{0,3}))))?/i',
      $_SERVER['HTTP_ACCEPT_LANGUAGE'],
      $langParse);

   $langs = $langParse[1]; // M1 - First part of language
   $quals = $langParse[4]; // M4 - Quality Factor

   $numLanguages = count($langs);
   $langArr = array();

   for ($num = 0; $num < $numLanguages; $num++)
   {
      $newLang = strtoupper($langs[$num]);
      $newQual = isset($quals[$num]) ?
         (empty($quals[$num]) ? 1.0 : floatval($quals[$num])) : 0.0;

      // Choose whether to upgrade or set the quality factor for the
      // primary language.
      $langArr[$newLang] = (isset($langArr[$newLang])) ?
         max($langArr[$newLang], $newQual) : $newQual;
   }

   // sort list based on value
   // langArr will now be an array like: array('EN' => 1, 'ES' => 0.5)
   arsort($langArr, SORT_NUMERIC);

   // The languages the client accepts in order of preference.
   $acceptedLanguages = array_keys($langArr);

   // Set the most preferred language that we have a translation for.
   foreach ($acceptedLanguages as $preferredLanguage)
   {
       if (in_array($preferredLanguage, $websiteLanguages))
       {
          $_SESSION['lang'] = $preferredLanguage;
          return strtolower($preferredLanguage);
       }
   }
}

You can create a controller to manage the switching of languages.

App\Http\Controllers\Controller\LocaleController

namespace App\Http\Controllers;

use Redirect;
use Session;

use App\Http\Controllers\Controller;

class LocaleController extends Controller
{
    /**
     * Switch the locale of the website into English.
     *
     * @return Redirect
     */
    public function english()
    {
        Session::put('locale', 'en');
        return Redirect::back();
    }

    /**
     * Switch the locale of the website into Japanese.
     *
     * @return Redirect
     */
    public function japanese()
    {
        Session::put('locale', 'ja');
        return Redirect::back();
    }

    /**
     * Switch the locale of the website into Dutch.
     *
     * @return Redirect
     */
    public function dutch()
    {
        Session::put('locale', 'nl');
        return Redirect::back();
    }
}

Don't forget to add the routes to handle the switching.

routes.php

Route::get('en', ['as' => 'locale.english', 'uses' => 'LocaleController@english']);
Route::get('ja', ['as' => 'locale.japanese', 'uses' => 'LocaleController@japanese']);
Route::get('nl', ['as' => 'locale.dutch', 'uses' => 'LocaleController@dutch']);

Some ideas may be to pass the $websiteLanguages to the function as an arguement and store the acceptable languages in a config variable. You could also have the function scan which locale folders exist in your application.

Now that was easy! This code has been tested on Laravel 5.1


Posted: Wednesday, July 08, 2015

Comments

Christian Weiske 2018-07-23 13:29:20

The symfony http-foundation class "Symfony\Component\HttpFoundation\Request" used by Laravel has a "getPreferredLanguage()" method that implements your "getBrowserLocale()" code already.


Leave a Comment