Skip to content

internationalisation

Larix Kortbeek edited this page Feb 2, 2016 · 7 revisions

How to internationalise a Garp app

  • In core.ini, change resources.router.locale.enabled to true.
  • In core.ini, make sure resources.locale.force is set to true.
  • Make sure resources.frontController.params.locales is an array with a couple of locales.
  • Make sure resources.locale.default is set to something.
  • Configure snippet model to have i18n fields (look at Melkweg for an example) and run a g spawn.
  • Configure resources.locale.translate.adapter as "Garp_I18n_Translate_Adapter_Snippet".
  • Run g snippet storeI18nStrings. This takes all the strings from the file-based i18n store (e.g. garp/application/data/i18n/nl.php) and stores them as snippets. You might want to pass --editable=0 if you don't want to burden the admins with these snippets in the CMS. They're mostly system messages and CMS strings so it's not entirely crazy to leave them out. (note: this does not populate snippets.ini. Harmen is sorta working on that)
  • Start adding snippets to snippets.ini and replace ALL hard-coded strings with __('identifier') (remember to escape the output!).
  • Add multilingual: true to any existing model column that you wish to be internationalised. Remember this for new models. Spawn again.

Querying models

When fetching from models, make sure you're fetching from the derived, localised version. Instead of using

$eventModel = new Model_Event();
$event = $eventModel->fetchBySlug('foobar');

You will need to use Garp_I18n_ModelFactory:

$modelFactory = new Garp_I18n_ModelFactory();
$eventModel = $modelFactory->getModel('Event');
$event = $eventModel->fetchBySlug('foobar');

On binding models

Binding internationalized models is a little more work, because you need to let Garp know it should use a root table's relation rule for another model (the localized one).

This requires changing its referenceMap property at runtime. Use the Garp_Model_ReferenceMapLocalizer for this. An example:

<?php
$modelFactory = new Garp_I18n_ModelFactory();
$tagModel = $modelFactory->getModel('Tag');

$localizer = new Garp_Model_ReferenceMapLocalizer($tagModel);
$localizer->populate('Model_Article');

$tagModel->bindModel('Model_Article', array(
  'modelClass' => $modelFactory->getModel('Article')
));
?>

Internationalised routes

If you want to use translated routes, you need to configure a routes file per locale. Configure this like so:

resources.router.routesFile.generic = APPLICATION_PATH "/configs/routes.ini"
resources.router.routesFile.nl = APPLICATION_PATH "/configs/routes_nl.ini"
resources.router.routesFile.en = APPLICATION_PATH "/configs/routes_en.ini"

Linking to the same page in a different language

In other words, how to make a language switch?

foreach ($this->config()->resources->frontController->params->locales as $i => $altLang):
  $urlParams = isset($this->alternateUrlParams[$altLang]) ?
    $this->alternateUrlParams[$altLang] : array();

  $alternateUrl = $this->fullUrl(
    $this->i18n()->getAlternateUrl($altLang, $urlParams), false, true);

  echo $this->htmlLink($alternateUrl, $altLang, array(
    'rel' => 'alternate',
    'hreflang' => $altLang
  ));
endforeach;

Let's break it up to see what this all means:

foreach ($this->config()->resources->frontController->params->locales as $i => $altLang):

Loops over all available languages.

$urlParams = isset($this->alternateUrlParams[$altLang]) ?
    $this->alternateUrlParams[$altLang] : array();

Checks to see if $this->alternateUrlParams is provided and wether the current language has an index in there. More on this later.

$alternateUrl = $this->fullUrl(
  $this->i18n()->getAlternateUrl($altLang, $urlParams), false, true);

Get the current route in a different language.

echo $this->htmlLink($alternateUrl, $altLang, array(
  'rel' => 'alternate',
  'hreflang' => $altLang
));

Echo the link with some sensible attributes.

Route params

Some alternate routes are easy. /nl/over-ons might become /en/about-us. We can just parse that from the routes file.
Other routes are more complicated, because the need params. These are the routes that are configured like this: /blog/:slug. That :slug bit is determined at runtime and it's therefore the responsibility of the developer to make sure to pass it from the controller to the view. In Dutch you might have /nl/blog/hallo-wereld, in English it would become /en/blog/hello-world.

To grab these alternate parameters you can use the controller helper Garp_Controller_Helper_I18nAlternative:

// from controller
$this->view->alternateUrlParams =
  $this->_helper->I18nAlternative('BlogPost', 'blog_post_id', $row);

This expects three parameters:

  1. The model name
  2. The foreign key from the i18n table to the base table
  3. The row that's viewed at the moment

Warning: right now this helper only concerns itself with the slug column. If you need other parameters in your alternate route, this might need refactoring.

The result of that call looks something like:

Array
(
    [nl] => Array
        (
            [slug] => ff-c-blog
        )

    [en] => Array
        (
            [slug] => free-charging-for-fastned-founders-forever
        )

    [de] => Array
        (
            [slug] => ff-c-blog
        )

)```
Clone this wiki locally