Monday, April 1, 2013

Internationalization with FuelPHP


FuelPHP is a free open-source PHP framework, based on PHP 5.3+. It implements a HMVC architecture (Hierarchical Model–View–Controller) where the controller plays a central part in the architecture, the view and the model being completely separated (hence they can't communicate which each other). It also offers many other features like a RESTful implementation, template parsing, an Object Relational Mapper, an authentication package and a caching system among other things. We will focus here on the way it handles internationalization in its version 1.5.1 from January 2013. The new 2.0 codebase development has already started but it should treat i18n the same way.

Lightweight example


In this first approach, we are going to set up the code to display a template via a controller (we completely bypass the view layer here).

Let's start with our own controller Controller_Test which is placed in fuel/app/classes/controller/test.php. We set some data content, namely, the title and textual content of the template to display. The View class is an object wrapper for HTML pages with embedded PHP. Its forge method takes three parameters: the path to the view filename or template, relative to the app/views directory (here, test/template), an array of PHP variables and values ($data), and a boolean encoding parameter (optional, setting it to true, its default value, means you follow the encoding set in the app/config/config.php configuration file, which overwrites the core/config/config.php file). The internal string encoding charset value is UTF-8 by default.
class Controller_Test extends Controller
{
    public function action_index()
    {
        $data = array();
        $data['title']   = "Test Page";
        $data['content'] = "Test page content";

        return View::forge('test/template', $data, true);
    }
}
And the actual template lies is fuel/app/views/test/template.php:
<!DOCTYPE html>
<html>
<head>
    
    <?php echo $title ?>
</head>
<body>
    
<?= $content ?>
</body> </html>

Languages and locales


The default language is English (en), and it is set in the app/config/config.php configuration file, which overwrites the core/config/config.php file. If you want to change its value at runtime, you can do it with the following method call:
Config::set('language', 'fr');
Or you can directly set the languages and locales in the app/config/config.php file.
return array(
    'language'           => 'en', // Default language
    'language_fallback'  => 'en', // Fallback language when file isn't available for default language
    'locale'             => 'en_US', // PHP set_locale() setting, null to not set
    'locales'            => array(
        'en' => 'en_US',
        'fr' => 'fr_FR'
    ),
);
  • language is the default language of the application
  • language_fallback is the language that will be used in case the default one is not found
  • locale is the current locale, used for the set_locale() PHP function. It can be set to null
  • locales are the locales supported by the application, you can use every locale (language + region) you want and force them to use a specific language
In this example, we have set English (USA) by default, while having added a support for French (France).

Storing languages data


FuelPHP supports four different ways to store the language data:
  • a PHP array, the default type:
    return array('key' => 'value');
    
  • an INI configuration file:
    [group]
    key=value
    
  • a YAML configuration file:
    group:
       key: value
    
  • a JSON configuration file:
    {
    "group":
        {
            "key": "value"
        }
    }
    
Let's create the French language file app/lang/fr/test.php
return array(
    'test_page' => 'Page de test',
    'penguin' => 'Pingouin',
    'hello' => 'Salut !',
    'hello_name' => 'Salut, :name !',
    'test_group'=> array('hello' => 'Salut à toi, :name.')
);
And its matching English language file app/lang/en/test.php
return array(
    'test_page' => 'Test page',
    'penguin' => 'Penguin',
    'hello' => 'Hello!',
    'hello_name' => 'Hello, :name!',
    'test_group'=> array('hello' => 'Hello to you, :name.')
);
The controller fuel/app/classes/controller/test.php is now:
class Controller_Test extends Controller
{
    public function action_index()
    {
        Config::set('language', 'fr');
        Lang::load('test');

        $data = array();
        $data['title'] = Lang::get('test.test_page');
        $data['content1'] = Lang::get('hello');
        $data['content2'] = Lang::get('hello_name', array('name' => Lang::get('penguin')));
        $data['content3'] = Lang::get('test_group.hello', array('name' => Lang::get('penguin')));

        return View::forge('test/template', $data, 'UTF-8');
    }
}
And the template (fuel/app/views/test/template.php):
<!DOCTYPE html>
<html>
<head>
    
    <?= $title ?>
</head>
<body>
    
<?= $content1 ?> <?= $content2 ?> <?= $content3 ?>
</body> </html>
The French result is:
Salut !
Salut, Pingouin !
Salut à toi, Pingouin.
Whereas in English (commenting out the line Config::set('language', 'fr');):
Hello!
Hello, Penguin!
Hello to you, Penguin.
To load a language file, the Lang class offers the load method. In that example, we load the full language data, but we could have only loaded the test group using:
Lang::load('test', 'test_group');
As you can see, we can also use a named placeholder in the translated string, prefixed with a colon (here, :name).
On a side note, FuelPHP Lang class offers methods to set a specific line in the language file (set), to delete a specific line from the loaded language file (delete), and to save a language file into the system (save), enabling you to dynamically update a language file.


Internationalisation avec FuelPHP (in French)
Internacionalización con FuelPHP (in Spanish)
Internacionalização com FuelPHP (in Portuguese)

No comments:

Post a Comment