i18n and plone 3, a little cookbook

History & summury

As you know, with plone3 outcoming, there was a lot of efforts around eggs packaging toward plone products.

The problem is that the way to handle i18n can not be the same for a lot of reasons.

Plone i18n is handled now in a more gettextish way with a classical locales gettext directory.

What were we used to do:

  • overwrite things in plone’s Domain
  • Write po’s with arbitrary names in the i18n/ top directory
  • Never use msgfmt.

What we will have to do:

  • Discipline ourselves not to have to write into plone Domain.
  • Write pos and pots called Domain.*
  • Use msgfmt if we want.

I18n aware product

To make zope know your locales directory, Add this zcml directive:

<i18n:registerTranslations directory="locales"/>

Layouts

Old

i18n/
    foo.bar.fr.po
    foo.bar.en.po
    foo.bar.pot
    foo.bar-plone.fr.po
    foo.bar-plone.en.po
    foo.bar-plone.pot

New

locales/
    en/LC_MESSAGES/foo.bar.mo
    fr/LC_MESSAGES/foo.bar.mo

locales.build/
    en/LC_MESSAGES/foo.bar.po
    fr/LC_MESSAGES/foo.bar.po
    foo.bar.pot

i18ndude

i18ndude can help you to maintain your translation files by grabbing msgids from templates code and browser views. Be aware, this tool is limited and pretty buggy :) . for example, it does not handle archetypes schemas

The two main things i needed to know about it were:

  • To generate a pot:

    i18ndude rebuild-pot --pot locales/mydomain.pot --create mydomain .
  • To sync a domain:

    i18ndude sync --pot locales.build/mydomain.pot locales.build/*/LC_MESSAGES/mydomain.po

Pitfalls

  • The current placelessTranslationService has a mecanism to refresh automaticly pos in locales/ when they are updated but i had odds sometime. So i use now a separated locales.build/ directory where i put the po/pot and i generate the mo compiled files with a small shell script:

    #!/usr/bin/env bash
    
    # Copyright (C) 2008, Mathieu PASQUET <Mathieu PASQUET mpa@makina-corpus.com>
    #
    # This program is free software; you can redistribute it and/or modify
    # it under the terms of the GNU General Public License as published by
    # the Free Software Foundation; either version 2 of the License, or
    # (at your option) any later version.
    #
    # This program is distributed in the hope that it will be useful,
    # but WITHOUT ANY WARRANTY; without even the implied warranty of
    # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    # GNU General Public License for more details.
    
    # Compile po files
    LOCALESSRCDIR=${1:-"$(pwd)/locales.build"}
    LOCALESDIR=${2:-"$(pwd)/locales"}
    
    
    pushd $LOCALESSRCDIR
    for pot in $(find -mindepth 1 -maxdepth 1 -type f -name "*pot");do
        filep=$(basename $pot .pot)
        for lang in $(find -mindepth 1 -maxdepth 1 -type d); do
            lang=$(basename $lang)
            echo $lang
            if test -d "$lang/LC_MESSAGES"; then
                if [[ -f "$lang/LC_MESSAGES/$filep.po" ]];then
                    output="$LOCALESDIR/$lang/LC_MESSAGES"
                    if [[ ! -d "$output" ]];then
                        mkdir -p "$output"
                    fi
                    msgfmt -c -o "$output/$filep.mo" "$lang/LC_MESSAGES/$filep.po"
                fi
            fi
        done
    done
    popd
    
    # vim:set et sts=4 ts=4 tw=80:

You can grab it via svn:

svn export https://svn.plone.org/svn/collective/Quaestrio/trunk/quizz/Quaestrio/compile-mo.sh

Na: in the current state, i do not need it anymore but if you want to control the mo generation, it can be useful not to allow automatic generation. So the way is to put the po outside from the locales/ directory.

  • I used false namespaces in templates wiping away my translations:

    xmlns="http://namespaces.zope.org/i18n" ->  xmlns:i18n="http://xml.zope.org/namespaces/i18n"
  • Some traductions can be now done in the specific domain too using profiles (for the add menu and the title):

    <?xml version="1.0"?>
    <object name="JobPerformanceInterview"
       meta_type="Factory-based Type Information with dynamic views"
       xmlns:i18n="http://xml.zope.org/namespaces/i18n"
       i18n:domain="plone">
     <property name="title"
               i18n:translate="">Job performance interview</property>
    </object>

What next?

The incoming releases of zope.i18n and plone PlacelessTranslationService are promising.

As a spoil, it seems that:

  • The machinery to generate automaticly pos will be a lot improved and will use the standard python gettext module.
  • They will be a merging mecanism to overwrite strings in the plone Domain as we were used to.