Weblog

published Nov 03, 2021 , last modified Nov 04, 2021

i18n, locales and Plone 3.0

published Sep 25, 2007 , last modified Mar 05, 2013

More and more products are developed as python packages instead of Zope products. This means they should not be put in the Products directory anymore, but in the lib/python/ directory of your instance. How you handle translations has changed a bit because of that. Also with Zope 2.10 and higher the translation machinery has changed a bit. So how should you handle translations now?

For the most recent version focusing on Plone 4, see my talk at the Plone Conference 2012.

For a version from 2010 focusing on Plone 3.3 and 4, see a different article on my blog.

How should you handle translations now when dealing with locales, i18n, products, packages and Plone 3.0?

For clarity: I use the following terms here: a product is in the Products dir, a package is in the lib/python dir.

Please correct me if anything I write here is wrong.

locales

Most translations should now be put in the locales directory of your product or package. This directory must be registered in zcml before it is picked up on Zope startup. So in your configure.zcml add:



    


The locales directory differs a bit from the i18n directory. i18n has for example:

i18n/mydomain.pot
i18n/mydomain-nl.po
i18n/mydomain-de.po

In locales that should be:

locales/mydomain.pot
locales/nl/LC_MESSAGES/mydomain.po
locales/de/LC_MESSAGES/mydomain.po

You can rebuild the .pot file with:

i18ndude rebuild-pot --pot locales/mydomain.pot --create mydomain .

and you sync the .po files with:

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

Domain plone

If you want to add translations to the plone domain you could add locales/plone.pot and locales/nl/LC_MESSAGES/plone.po (or locales/plone-mydomain.pot and locales/nl/LC_MESSAGES/plone-mydomain.po if you want). That works: your translations for the plone domain are then available. But now the default translations for the plone domain (so those from PloneTranslations) are overridden. This is because your translations for the plone domain are picked up first by the zope translation machinery; the PlacelessTranslationService that normally loads the translations from PloneTranslations then gets ignored for the plone domain. So half your site is in English even though your browser is set to Dutch.

So extra translations for the plone domain should not be done in the locales directory. You can still put them in the i18n directory though. In Plone 3.5 this is likely to change.

As Hanno Schlichting tells me, the same is of course true for the other domains in PloneTranslations, like atcontenttypes, cmfeditions, plonelanguagetool, etcetera.

i18n

If you put an i18n dir in a package, it will be ignored. Doing i18n:registerTranslations for this directory does not work. You can only use an i18n dir in a product.

GenericSetup profiles

Several .xml files in the profiles can handle i18n as well. For instance in a types definition like types/JobPerformanceInterview.xml:



The i18n:domain should be plone and not for instance mydomain as these translations are used in templates of plone itself. In fact, I think that the only use for having these i18n commands in the .xml files is that they can then be extracted by i18ndude (version 3.0 I think, which is best installed in a workingenv).

Compiling .po files

.po files in i18n are compiled on zope startup time by the PlacelessTranslationService. With compiling I mean: turning them into .mo files so they are usable by zope. This automatic compiling does not happen .po files in packages. So it is better to compile those files yourself. You can do that like this:

# Compile po files
for lang in $(find locales -mindepth 1 -maxdepth 1 -type d); do
    if test -d $lang/LC_MESSAGES; then
        msgfmt -o $lang/LC_MESSAGES/${PRODUCTNAME}.mo $lang/LC_MESSAGES/${PRODUCTNAME}.po
    fi
done

Conclusions

  • For both products and packages: put the translations for your domain in the locales directory.
  • Put extra translations for the plone domain in an i18n directory in a product for the Products dir.

Plone en Single Sign On

published Sep 19, 2007 , last modified Sep 20, 2007

Door Duco Dokter van Goldmund, Wildebeast & Wunderliebe op de Nederlandse Plone gebruikersdag, 19 september 2007.

Door Duco Dokter van Goldmund, Wildebeast & Wunderliebe op de Nederlandse Plone gebruikersdag, 19 september 2007.

Existentiële zaken

Wat is het? Eenmalig authenticeren voor meerdere applicaties. 1 metasessie. Je hebt ook Web SSO, specifiek voor webapplicaties.

Waarom zou je het willen? Gebruikers willen het graag, al draagt het niets wezenlijks toe. Het is gewoon gemakkelijk. Wel heb je minder accounts nodig, net zoals bij bijvoorbeeld OpenID. Ook ligt de focus van het beveiligingsbeleid centraal, dus beleids- en beheersmatig is het handig.

Hoe gaat het in zijn werk? Er is 1 bron die de authenticatie regelt. Die bron wordt vertrouwd door andere applicaties. Een betrouwbaar protocol is opgesteld voor deze relatie.

Plone en SSO

Je kan regelen dat meerdere Plone sites dezelfde gebruikersgegevens hebben en inloggen bij de een je meteen authenticeert voor de ander. Plone kan je als front-end gebruiken voor andere sites, bijvoorbeeld middels atom of rss feeds. Je kan andere (non)webapplicaties in dezelfde sessies hebben. Plone kan ook net als anderen gebruik maken van LDAP, al hebben we het daar vanavond niet over.

CAS is een SSO server gebouwd aan de Yale universiteit. Het is een open protocol. Plone kan daarmee praten, middels PlonePAS en CAS4PAS en optioneel PloneCASLogin.

Sessie A

Je bezoekt (maakt een http request naar) Plone site A. Je krijgt een zogenoemde challenge (uitdaging) van CAS4PAS, die je redirect naar de CAS server over https. Daar log je in. Die CAS server zet een cookie en redirect je terug naar de callback service (dus Plone site A) met een ticket. Plone Site A gaat met dat ticket zelf weer terug naar de CAS server en vraagt of het ticket geldig is. Als het klopt, verwijdert de CAS server de ticket, zegt tegen Plone site A dat het in orde is en geeft het netID, de gebruikersnaam van de persoon die zich zojuist heeft aangemeld. Plone site A geeft vervolgens een response aan de gebruiker, met een Plone cookie.

Sessie B

Je bezoekt Plone Site B. Je kiest de inloglink naar de CAS server of krijgt automatisch een redirect naar de authenticatie. De CAS server herkent de sessie op basis van je cookie. CAS stuurt dus meteen een ticket terug, zonder dat je je gebruikersnaam en wachtwoord in hoeft te vullen. Daarna gaat het hetzelfde als bij sessie A.

Qua backend wordt vaak LDAP gebruikt of SQL.

Maurits van Rees, BICT

published Jul 19, 2007

I am now a Bachelor of ICT!

Today I got my diploma. I have finished my study of Informatics (specializing in Software Engineering) at the Rotterdam University. So I can now call myself Maurits van Rees, BICT (Bachelor of Information and Communication Technologies).

At the moment I am extremely happy, relieved, proud, joyful and very much in want of a short, well deserved, vacation. Tomorrow I am heading for a week to the Dutch New Wine Summer Conference.

Cheers!

Ing. Maurits van Rees

published Jul 19, 2007

Ik ben nu afgestudeerd ingenieur!

Vandaag heb ik mijn diploma gekregen. Ik heb dus mijn studie Informatica (afstudeerrichting Software Engineering) aan de Hogeschool Rotterdam afgerond. Ik mag mezelf dus ing. Maurits van Rees noemen. :-) Of op z'n Engels: Maurits van Rees, BICT (Bachelor of Information and Communication Technology).

Ik ben dus op het moment behoorlijk vrolijk, trots, blij, opgelucht, uitzinnig, gelukkig en hard toe aan een behoorlijk verdiende vakantie. Morgen vertrek ik voor een week naar de New Wine zomerconferentie.

Proost!

Discovering GenericSetup

published Jun 25, 2007 , last modified Jun 25, 2007

I looked at GenericSetup trunk recently and I discovered some things I was not yet aware of.

If you want to know more about the current state of the trunk of GenericSetup, this thread on the CMF list is a good start.

I had some things to say there too, including a patch.

Rob Miller gave me some helpful pointers, especially about import_various steps.

I learned some things from him and from rummaging around in the code myself.

Context

A GenericSetup handler gets passed a context when called. This context is not the Plone Site or some other content. It is a special GenericSetup context, as defined in GenericSetup/context.py. One of the things you can do with that context is passing it some text for its logger so you get some messages in your log files and in the GenericSetup log:

logger = context.getLogger('eXtremeManagement')
logger.info('eXtremeManagement_various step imported')

Various import steps

When you apply a GenericSetup profile (base or extension does not matter) all registered import steps are executed. So if you have an extension profile that only has a propertiestool.xml file, still all import steps (which can be a few dozen) are run. If all authors of those import steps have done their work correctly, all but one exit immediately as they realize they do not need to do anything.

I will quote Rob Miller here:

It is the responsibility of an import step's implementation to ensure that it is indeed appropriate to perform its actions during any given invocation of the step.

All of the XML-based import steps already do this; they check for the existence of a specific XML file, and if they find it they perform the action. If they do not find the file, no problem, they do nothing.

The so-called importVarious steps, i.e. any step that uses a plain old python function as its handler (as opposed to building on the existing XML parsing infrastructure), must perform this check explicitly. you could restrict it to only running when the intended profile is the one being imported, or you could check for the existence of a specific file within the profile. I like the latter choice.

The summary in my own words: if you want to be a good CMF citizen, you had better make sure that the importVarious step of your profile (or any other import step you define yourself) is only executed when your profile is applied and not when the profile of some unrelated product is applied.

So, taking some pointers from how CMFPlone and CMFEditions do it, I fixed eXtremeManagement. I added a file profiles/default/extrememanagement_various.txt. This can remain empty but it is clearer to add a comment, like this:

The eXtremeManagement_various step is run if this file is present in
the profile.

Then I changed setuphandlers.py:

def importVarious(context):
    # Only run step if a flag file is present
    if context.readDataFile('extrememanagement_various.txt') is None:
        return

For reference, this is the profiles/default/import_steps.xml file that tells GenericSetup about this handler:



  
    
    
    
    Import steps that couldn't be mapped to other handlers.
  

So if you have a CMF/Plone product which defines an own import step (like import various, but it can be a totally different step) please make sure that this step only runs when your own profile is applied.

Upgrade profiles

GenericSetup now has support for profiles that you can use to upgrade a product, instead of applying the complete profile again. I only looked at the code and have not actually tried this. But this is absolutely something I want to use in eXtremeManagement too. So I will probably write about that later.