Friday, August 9, 2013

Managing Laravel 4 Localization (Language)

Here is a quick tutorial on how to set and manage session localization in Laravel 4.

The Laravel documentation explains that you create a directory in app/lang representing each language you wish to support. For example, for the English language you may have app/lang/en directory and for the Spanish language you may have app/lang/es

I use controllers because I like how it organizes my code. Therefore, this article will be using controllers.

First, I set the applications default locale (i.e. language) and add a list of supported locales to the app/config/app.php file.
NOTE: the locales parameter is not in the default Laravel distribution. You will need to add this parameter.

....
      /*
      |--------------------------------------------------------------------------
      | Application Locale Configuration
      |--------------------------------------------------------------------------
      |
      | The application locale determines the default locale that will be used
      | by the translation service provider. You are free to set this value
      | to any of the locales which will be supported by the application.
      |
     */
    'locale' => 'en',
    /*

      |--------------------------------------------------------------------------
      | Application Supported Locales
      |--------------------------------------------------------------------------
      |
      | Locales supported by this application.
      |
     */
    'locales' => array(
        'en', // English
        'es', // Spanish
    ),
....


Next, I use the app/controller/BaseController.php for my locale logic because this controller is usually extended from my other controllers.

class BaseController extends Controller
{
    public function __construct()
    {
        $this -> configureLocale();
    }

    /**
     * Action used to set the application locale.
     * 
     */
    public function setLocale()
    {
        $mLocale = Request::segment( 2, Config::get( 'app.locale' ) ); // Get parameter from URL.
        if ( in_array( $mLocale , Config::get( 'app.locales' ) ) )
        {
           App::setLocale( $mLocale );
           Session::put( 'locale', $mLocale );
           Cookie::forever( 'locale', $mLocale );
        }
        return Redirect::back();
    }

    /**
     * Detect and set application localization environment (language).
     * NOTE: Don't foreget to ADD/SET/UPDATE the locales array in app/config/app.php!
     *
     */
    private function configureLocale()
    {
        // Set default locale.
        $mLocale = Config::get( 'app.locale' );

        // Has a session locale already been set?
        if ( !Session::has( 'locale' ) )
        {
            // No, a session locale hasn't been set.
            // Was there a cookie set from a previous visit?
            $mFromCookie = Cookie::get( 'locale', null );
            if ( $mFromCookie != null && in_array( $mFromCookie, Config::get( 'app.locales' ) ) )
            {
                // Cookie was previously set and it's a supported locale.
                $mLocale = $mFromCookie;
            }
            else
            {
                // No cookie was set.
                // Attempt to get local from current URI.
                $mFromURI = Request::segment( 1 );
                if ( $mFromURI != null && in_array( $mFromURI, Config::get( 'app.locales' ) ) )
                {
                    // supported locale
                    $mLocale = $mFromURI;
                }
                else
                {
                    // attempt to detect locale from browser.
                    $mFromBrowser = substr( Request::server( 'http_accept_language' ), 0, 2 );
                    if ( $mFromBrowser != null && in_array( $mFromBrowser, Config::get( 'app.locales' ) ) )
                    {
                        // browser lang is supported, use it.
                        $mLocale = $mFromBrowser;
                    } // $mFromBrowser
                } // $mFromURI
            } // $mFromCookie

            Session::put( 'locale', $mLocale );
            Cookie::forever( 'locale', $mLocale );
        } // Session?
        else
        {
            // session locale is available, use it.
            $mLocale = Session::get( 'locale' );
        } // Session?

        // set application locale for current session.
        App::setLocale( $mLocale );

    }
}


Now that my controller is configured to detected and set the application's locale, I now need to provide an action for the user to change their locale. I typically do it via a menu option like so.

app/view/plugin/navbar.blade.php
NOTE: I'm using twitter bootstrap for my navbar.

....
  <li class="dropdown">
   <a href="#" class="dropdown-toggle" data-toggle="dropdown">{{ Lang::get( 'navbar.locale.label' ) }} <b class="caret"></b></a>
    <ul class="dropdown-menu">
     @foreach( Lang::get( 'navbar.locale.option' ) as $mKey => $mLanguage )
      <li>{{ HTML::linkAction( 'BaseController@setLocale', $mLanguage, $mKey ) }}</li>
     @endforeach
    </ul>
   </li>
....


Next, we need to make sure our app/routes.php can handle the routing

....
Route::get( '/locale/{locale}', 'BaseController@setLocale' );
....

And finally, we need to update composer

$ composer dump-autoload


You can test it directly my entering into your browser the URL to your site like this:

http://mysite/locale/en
or
http://mysite/locale/es


5 comments:

  1. Thanks for this, its going to come in really useful, plus I picked up on some other ideas such as checking for a cookie or falling back to the browser language.

    ReplyDelete
  2. Sorry, meant to ask. Will you be doing anything on timezones? This really worries me as I am building an app that has time sensitive elements. Should I map everything to UTC and then back again, or just store everything in local time? (local to the user).

    ReplyDelete
    Replies
    1. You could use any time zone however, I would recommend always storing (in a database) the SAME time zone. Either the time zone of the business or UTC. That's because if you do any additional development outside the website (i.e. SQL queries for reports, routines, etc) all of the date/time zones will be the same. Allow the user to chose what zone they want displayed or attempt to discover it.

      Delete
  3. How to set
    ADD/SET/UPDATE the locales array in app/config/app.php

    ReplyDelete
  4. Hi! If you're interested in online tools that can help you with software localization projects, I would warmly recommend you this translation management app: https://poeditor.com/ It's suitable for collaborative translation work and crowdsourcing translations, and it can be integrated with other software through its API. I hope this info will be useful to you! Good luck!

    ReplyDelete