Manage your internationalization with i18ndude


Yet another post to manage automatically you po files…

We are using i18ndude to manage translation for the Plone bundle and helpers script are in PloneTranslations/utils. If we can do this for the whole bundle you can do it too for your products.

Here come an example of a script that manage translations for a Plone 2.5 product:


#!/bin/sh

##
## First we work on the 'plone' domain and then on the local domain to define below.
##

PLONEPRODUCTS="/path/to/plone/bundle/Products"
LOCALDOMAIN="product_name"
POPREFIX="product_name_in_lowercase"

##
## Domain: 'plone'
##

##
## Search all translations in 'plone' domain and rebiuld a new catalog
i18ndude rebuild-pot --exclude build --pot "./i18n/i18ndude-plone.pot" \
                     --create plone "./"

##
## Filter out all msgids that are already translated in PloneTranslations
i18ndude filter "./i18n/i18ndude-plone.pot" \
                "${PLONEPRODUCTS}/PloneTranslations/i18n/plone.pot" > "./i18n/filtered-plone.pot"

##
## Merge generated file with manual maintained pot file then with the current catalog
i18ndude merge --pot "./i18n/${POPREFIX}-plone.pot" \
               --merge "./i18n/filtered-plone.pot" \
               --merge2 "./i18n/manual-plone.pot"

##
## Cleaning
rm "./i18n/filtered-plone.pot" "./i18n/i18ndude-plone.pot"

##
## Refresh po files for 'plone' domain
i18ndude sync --pot "./i18n/${POPREFIX}-plone.pot" \
                    "./i18n/${POPREFIX}-plone-fr.po" "./i18n/${POPREFIX}-plone-en.po"


##
## Domain: LOCALDOMAIN
##

##
## Search all translations in ${LOCALDOMAIN} domain and rebiuld a new catalog
i18ndude rebuild-pot --exclude build --pot "./i18n/i18ndude.pot" \
                     --create ${LOCALDOMAIN} "./"
##
## generated.pot is given by ArchGenXML during product generation
i18ndude merge --pot "./i18n/${POPREFIX}.pot" \
               --merge "./i18n/i18ndude.pot" \
               --merge2 "./i18n/generated.pot"
##
## Cleaning
rm "./i18n/i18ndude.pot"

##
## Refresh po files for LOCALDOMAIN
i18ndude sync --pot "./i18n/${POPREFIX}.pot" \
                    "./i18n/${POPREFIX}-fr.po" "./i18n/${POPREFIX}-en.po"

##
## Check for missing translations in all page templates
echo
echo "#########################################################"
echo "##"
echo "## untranslated messages summary report"
echo
i18ndude find-untranslated -s `find skins -name "*.*p?"`

echo "To display the full report use:"
echo "i18ndude find-untranslated \`find skins -name \"*.*p?\"\`"

exit 0

You can repeat this for every domain you are using in your products.
You still have to manage a manual-domain.pot by hand to be able to i18n selectboxes or Archetype name for a content type for example, but your work is really easier to maintain you translations.

Thanks to Hanno for maintaining this tool.

portal_factory et acquisition


L’acquisition dans Zope et dans Plone est souvent utilisée pour attraper des attributs, ou des méthodes (CQFD), qui sont dans le chemin de l’objet.

Par exemple vous avez un chemin site / dossier1 / dossier2 / document.
Vous êtes dans document. Si la méthode getProduit n’existe pas dans cet objet, alors Zope va chercher dans dossier2 puis dans dossier1 si elle existe.
document.getProduit() renverra en fait dossier1.getProduit() de manière complètement transparente pour le programmeur. Mais…

portal_factory est un utilitaire qui permet de ne pas créer un document dans votre site Plone tant que tous les champs obligatoires ne sont pas remplis. Le document est créé en RAM dans portal_factory avant d’être déplacé dans le dossier parent d’origine.
Lors de la création d’un objet le chemin prend cette forme:
site / dossier1 / dossier2 / portal_factory / TypeName / id-temporaire

portal_factory qui est à la racine de votre instance Plone est virtuellement déplacé dans dossier2 pour bénéficier de l’acquisition de celui-ci.

Le problème est qu’il doit en même temps garder son contexte et le contexte du dossier d’origine. L’acquisition fonctionne de manière prévisible mais beaucoup moins transparente.
Du coup il est très difficile d’utiliser l’acquisition pour initialiser dans champs lors de la création des objets.
Pour être sur d’avoir une acquisition qui fonctionne il faut se placer dans le dossier d’origine en utilisant la méthode getFolderWhenPortalFactory.

Le code :

self.getProduit()

devient:

parent = self.getFolderWhenPortalFactory()

parent.getProduit()

N’oubliez pas que l’acquisition est un outil pratique et essentiel pour comprendre comment fonctionne Zope, mais qu’il ne faut pas l’utiliser à toute les sauces: les bogues d’acquisition font partis des bogues les plus pénibles à trouver et les plus simples à corriger à la source.

Ajouter un lecteur de mp3 à votre site Plone


Voici un lecteur simple à installer et à utiliser:
Dewplayer, lecteur mp3 pour page web
Dans les points importants à remarquer, le première est qu’il est vert, ce qui ne va pas avec toutes les chartes graphiques, et surtout qu’il ne lit pas les tags mp3. Pas moyen de savoir quel morceau est en court de lecture dans la version « multiple ».
Voici un exemple de macro metal pour l’intégrer dans votre site: mp3player.pt

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"
      i18n:domain=”plone”>
<body>
<div id=”portal-mp3-player”
     metal:define-macro=”player”
     i18n:domain=”plone”>
<object width=”240″ height=”20″ type=”application/x-shockwave-flash”
        data=”dewplayer-multi.swf?mp3=sound-theme/track1.mp3|sound-theme/track2.mp3″>
  <param name=”movie” value=”dewplayer-multi.swf?mp3=sound-theme/track1.mp3|sound-theme/track2.mp3″ />
</object>
</div>
</body>
</html>

À noter:

  • il faut au préalable télécharger le fichier swf à la racine de votre instance dans un ATFile ou un PloneExFile
  • les morceaux sont séparés par le caractère « | »
  • le chemin des morceaux est relatif par rapport à la racine de l’instance Plone: pas de « / » pour commencer le chemin

Voici le petit morceau de code à rajouter dans votre main_tempate.pt:

<metal:mp3player use-macro="here/mp3player/macros/player">
  MP3 Player in Flash
</metal:mp3player >