vendredi 14 mars 2008

Symfonians en VF

Je viens de mettre en ligne la version française de Symfonians[1]. J'ai préféré utiliser un sous-domaine pour définir la langue courante plutôt qu'un paramètre supplémentaire dans la requête, car le routing de Symfony implique de le gérer pour chacune des route (ou si y'a une astuce, je suis preneur.)

Ici, je détecte le sous domaine et en fait la langue courante de l'utilisateur au moyen d'un filtre. Pour ceux que ça intéresse, en voici le code :

<?php
class i18nSubdomainFilter extends sfFilter
{
  public function execute($filterChain)
  {
    if ($this->isFirstCall())
    {
      $context = $this->getContext();
      $request = $context->getRequest();
      $host_parts = explode('.', $request->getHost());
      if (count($host_parts) > 2) // We have at least a subdomain
      {
        $subdomain = strtolower($host_parts[0]);
        $enabled_cultures = sfConfig::get('app_cultures_enabled', array());
        if (array_key_exists($subdomain, $enabled_cultures))
        {
          sfConfig::set('sf_current_culture', $subdomain);
          $context->getResponse()->addMeta('language', $subdomain, true);
          $context->getUser()->setCulture($subdomain);
        }
      }
    }
    $filterChain->execute();
  }
}

Notez que je définis la liste des langues disponibles dans le fichier app.yml, pour éviter les blagues et gérer les domaines pour chacun des environnements que j'ai configuré[2] :

prod:
  cultures:
    enabled:
      en:    http://symfonians.net/
      fr:    http://fr.symfonians.net/

L'activation du filtre se fait dans le fichier filters.yml :

i18nSubdomain:
  class:    i18nSubdomainFilter

Et roule ma poule, mon routing reste strictement intact :-)

Notes

[1] 690 chaînes à traduire en deux heures, doit sans doûte rester du débris :p

[2] J'ai dautre part une action qui me permet de rediriger l'utilisateur vers la version traduite de la page courante, mais je vous fais grâce du code.

jeudi 13 mars 2008

Symfony 1.1 beta, tour du propriétaire - L'internationalisation (i18n)

Dans la liste des tâches nouvellement ajoutées en Symfony 1.1, on remarque une section dédiée à l'internationalisation :

i18n
  :extract            Extracts i18n strings from php files
  :find               Finds non "i18n ready" strings in an application

Et oui, la fonctionnalité dont tous les gens qui ont un jour travaillé sur des applications internationalisées en Symfony 1.0 ont rêvé a enfin été ajoutée : une tâche d'extraction des chaînes de caractères à traduire, avec génération et mise à jour des fichiers de traductions XLIFF :)

Si vous avez suivi les précédents tutoriels, vous devez disposer d'un projet sf11test, d'une application main et d'un module contact.

On va activer la gestion de l'internationalisation dans l'application en éditant le fichier de configuration apps/main/config/settings.yml comme suit :

[...]
all:
  [...]
  .settings:
    [...]
    i18n:                   on
    [...]
    standard_helpers:       [Partial, Cache, Form, I18N]
    [...]
    default_culture:        en

On part du principe que la langue par défaut sera l'anglais (en). Ajoutons quelques chaînes internationalisées dans le template apps/main/modules/contact/templates/indexSuccess.php au moyen du helper __() :

<h2><?php echo __('Contact us') ?></h2>
<p><?php echo __('Drop us a message using the form below:') ?></p>
<form action="<?php echo url_for('contact/index') ?>" method="post">
  <table>
    <?php echo $form ?>
    <tr>
      <td></td>
      <td><input type="submit" value="<?php echo __('Send your message') ?>" /></td>
    </tr>
  </table>
</form>

Maintenant, lançons la commande d'extraction des chaînes à traduire pour notre future version française, en lui demandant poliment de générer automatiquement le fichier de traduction et de supprimer automatiquement les entrées orphelines :

 $ ./symfony i18n:extract --auto-save --auto-delete main fr
>> i18n      extracting i18n strings for the "main" application
>> i18n      found "3" new i18n strings
>> i18n      found "0" old i18n strings
>> i18n      saving new i18n strings
>> i18n      deleting old i18n strings

Le fichier apps/main/i18n/fr/messages.xml a été généré, examinons son contenu :

<?xml version="1.0"?>
<xliff version="1.0">
  <file source-language="EN" target-language="fr" datatype="plaintext"
    original="messages" date="2008-03-13T11:13:45Z"
    product-name="messages">
    <body>
      <trans-unit id="1">
        <source>Contact us</source>
        <target></target>
      </trans-unit>
      <trans-unit id="2">
        <source>Drop us a message using the form below:</source>
        <target></target>
      </trans-unit>
      <trans-unit id="3">
        <source>Send your message</source>
        <target></target>
      </trans-unit>
    </body>
  </file>
</xliff>

Il ne nous reste plus qu'à traduire nos chaînes en remplissant les balises <target></target> en conséquence pour traduire notre application en français. Si l'on venait à modifier notre template en supprimant, modifiant ou ajoutant de nouvelles chaînes, la tâche d'extraction se chargerait de mettre à jour nos fichiers de traduction en conséquence, tout en préservant le travail déjà effectué :)