Weblog

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

Plone Gebruikersdag

published Nov 02, 2010

Samenvatting van de Nederlandse Plone Gebruikersdag 2010 in Rotterdam.

In september werd de Nederlandse Plone Gebruikersdag 2010 gehouden in de Euromast, met prachtig uitzicht op het schitterende Rotterdam. Er waren ruim vijftig deelnemers op afgekomen. De dag was gevuld met lezingen van zo'n drie kwartier en een aantal 'lightning talks': bliksemsnelle praatjes van vijf tot zeven minuten. Natuurlijk was er ook een lunch, borrel en voor de nablijvers een diner, dus voldoende tijd om met elkaar te praten en kennis te maken. Hier volgt een korte samenvatting van de lezingen, met links naar wat uitgebreidere samenvattingen.

Fabian Spaargaren (Exser): Naar web 2.0 met Plone

Exser is een samenwerkingsprogramma's van overheid, wetenschap en bedrijven met als doel diensteninnovatie. De website van Exser was statisch, maar Plone heeft daar dynamiek in gebracht. Op de website staat nu onder andere een nieuwsbrief, linked-in integratie, een twitter portlet, RSS feed.

Verder ging het praatje vooral communicatie tussen klant en webbouwer. Heb je aandacht voor je klant? Denk je mee? Doe je uurtje-factuurtje of spreek je vantevoren een vaste prijs af, misschien voor een deel van het werk?

Lees meer...

Geir Bækholt (Jarn): Wat is er nieuw in Plone 4

Geir Bækholt, directeur bij Jarn en president van de Plone Foundation, geeft een overzicht van de stand van zaken van Plone en toekomstplannen voor Plone 4.1 en 5.

Plone 4.0 is begin september uitgebracht. Het was de bedoeling dat dit een kleine release zou worden, maar het is de grootste ooit geworden. Er zijn 27 grotere verbeteringen en nieuwe functionaliteit ('PLIPs'). Wat is er nieuw?

  • Plone 4 is een stuk sneller. Plone 4 gebruikt Zope 2.12 en Python 2.6, wat helpt voor een kleiner geheugengebruik. Plone 4 is ongeveer 50 procent sneller dan Plone 3. Als je kijkt naar het aantal requests per seconde zijn we sneller dan Joomla, Drupal en Wordpress.
  • BLOBs: Binary Large OBjects. Grote bestanden worden apart opgeslagen, wat het geheugengebruik terugbrengt.
  • TinyMCE lost Kupu af als standaard visuele editor. Het is beter in het uploaden van afbeeldingen, bewerken van tabellen, invoegen van links, enzovoorts.
  • Nieuwe uitstraling. Plone 4 komt met een vernieuwd, moderner thema.
  • Beter gebruikersbeheer. Overal worden volledige namen gebruikt. Je kan inloggen met je e-mailadres, als je dit aanzet.
  • Waarschijnlijk de eenvoudigste upgrade ooit. Natuurlijk verandert er een hoop tijdens de upgrade, dus houd backups bij de hand, maar een upgrade vanaf Plone 3 is niet spannend.

Wat zijn de toekomstplannen?

  • Plone 4.1 komt waarschijnlijk begin 2011. Verwacht zijn onder andere:
    • rondleidingen door de gebruikersinterface met Amberjack
    • verbeterd plaatsen van reacties
    • verbeterde structuur van Verzamelingen (zoekmappen)
    • nieuwe SiteAdmin rol, laten we zeggen een Manager zonder toegang tot de Zope Management Interface
    • wachtwoordbeleid
  • Plone 4.2: nog niet duidelijk wanneer dit gaat komen. Mogelijke verbeteringen hier zijn:
    • gebruiken van Chameleon om pagina's sneller te tonen (ongeveer 20 procent verbetering)
    • voorbereiding architectuur voor Deco dat in Plone 5 komt
    • betere batch-editing, tegelijk wijzigen van een aantal items
  • Of Plone 4.3 er komt, weten we nog niet.
  • Ergens aan de horizon is het magische Plone 5. Het zal de gebruikersinterface voor het bewerken flink verbeteren. Daar komen we aan de top te staan, met behulp van Deco en 'tiles' (tegels), geünificeerde contenttypes en een nieuwe interface voor het bewerken.

Lees meer... (Engels)

Jean-Paul Ladage (Zest Software): Plone voor uw mobiel

De enorme toename in het gebruik van smartphones maakt mobiele diensten lonend met de inzet van Plone GoMobile. Houd rekening met je doelgroep: welke mobieltjes worden gebruikt, welke schermresoluties horen daarbij?

Voor Plone is er Plone Go Mobile. Dit is een verzameling tools om binnen Plone nieuwe content voor mobiel te beheren of bestaande content te optimaliseren. Ook automatische doorsturing van bijvoorbeeld http://zestsoftware.nl naar http://m.zestsoftware.nl, de website en mobiele site van Zest Software.

Lees meer...

Rob Gietema (Four Digits): Content bewerken in Plone met Deco

Met Deco wordt het onderhouden van een website echt leuk. Het geeft je alle vrijheid om pagina's op te maken. Deco zal standaard gebruikt worden in Plone 5 en je kan er in Plone 4 al mee experimenteren.

Deco werkt met een grid. Op dat grid kan je tiles (tegels) toevoegen met html; dat kan de weergave van de titel zijn, of een folder listing, of van alles en nog wat.

De tiles vervangen onder andere de viewlets en portlets, dus je hoeft weer wat minder technieken te weten.

Lees meer...

Jeroen Vloothuis (KNMP) en Jan Murre (Pareto): Plone skinning met XDV

Een case studie van KNMP waarbij met Plone 4 en XDV de huisstijl is geïmplementeerd.

Het skinnen van een Plone site bestaat uit het aanpakken van CSS ('decorating the tree'), viewlets, portlets, main template. XDV gebruikt XSLT om die boom die Plone heeft opgezet te kortwieken. Met regels kan je zeggen: verplaats een deel van de html, of kopieer het, voeg wat toe aan de voor- of achterkant, haal wat weg. Dit is dus een nieuwe manier van het themen van een site. Zeker voor niet-programmeurs is dit potentieel een stuk sneller.

Hoe doe je deployment? Gebruik collective.xdv (nieuwe naam: Diazo) voor Plone.

Lees meer...

Lightning Talks

Hierna volgden de 'lightning talks' of bliksempraatjes.

Vincent Pretre (Zest Software): jquery.pyproxy
Vervang KSS door jQuery voor Ajax requests. Zie http://pypi.python.org/pypi/jquery.pyproxy
Roel Bruggink (Four Digits): Living Statues Sprint
Met de Plone community een sprintje trekken voor de ontwikkeling van Deco. Zie http://blog.fourdigits.nl/living-statues-sprint-2010
Fred van Dijk (Zest Software): pakketten die je (misschien) nog niet kent
Kijk eens rond of je nog pakketten op de plank hebt liggen die je voor één klant hebt gemaakt maar die voor de Plone community ook interessant zijn. Voorbeelden van al dan niet gereleaste pakketten van Zest: collective.sendaspdf, zest.carouselitem, mr.inquisition, zest.portlet.contact, zest.teammember, zest.releaser. Zie de slides van Fred.
Kees Hink (Goldmund, Wyldebeast and Wunderliebe): deurmat
Binnen een jaar wilden twee van onze klanten een 'deurmat'. Een beetje zoals de homepage van http://plone.org. Maak linkjes aan, geef wat headers aan en je hebt een deurmat. Dat doet Products.Doormat.
Thijs Jonkman (Pareto): XDV skinning
Je kan XDV theming gebruiken om Collage in het Deco keurslijf te persen. De CSS positionering van Deco kan je namelijk ook al in Plone 3 of 4 gebruiken. De html code van Collage is lelijk, maar als je er een net zo lelijke xslt sheet tegenaan gooit, krijg je er wel wat schoons uit.
Maurits van Rees (Zest Software): collective.watcherlist
Ontwikkeld vanuit Products.Poi. Houd een lijstje bij van mensen die updates willen van een content item. Registreer een browser view. Stuur ze automatisch een mailtje. Zie http://plone.org/products/collective.watcherlist

Lees meer...

Lightning talks

published Nov 02, 2010

Bliksempraatjes tijdens de Nederlandse Plone Gebruikersdag 2010.

Snelle, vaak technische presentaties tijdens de Nederlandse Plone Gebruikersdag 2010 in de Euromast, Rotterdam.

Vincent Pretre (Zest Software): jquery.pyproxy

Ik ben de hoofdontwikkelaar van Zest Software voor http://prettigpersoneel.nl, een online personeelsadministratie voor MKB'ers. De site gebruikt Products.plonehrm, collective.sendaspdf en: jquery.pyproxy.

Het idee is om KSS te vervangen door jQuery voor Ajax requests. De DOM aanpassen vanuit Python. We wilden dat het makkelijk te gebruiken was aan de client-kant (browser) en aan de server-kant. De python-syntax zo dicht mogelijk op de jQuery-syntax. Het zou net zo uitbreidbaar moeten zijn als jQuery, dus bestaande plugins zouden moeten worken. Het kan zelf als jQuery plugin gebruikt worden.

pyproxy bind een call aan een event. Er is ook pyproxy_call. In python code definieert @jquery een view als aanroepbaar door jquery.pyproxy. JQueryProxy: een object gebruikt om de DOM aan te passen. extend_grammar: definieer de syntax van plugins.

Huidige beperkingen: je kan geen chained call doen, kan geen query opslaan, kan geen functies als parameters gebruiken (dus geen callbacks).

Het is stabiel: al maanden in productie. Werkt met Plone en Django en kan uitgebreid worden naar andere frameworks. Werkt met Firefox, Chrome, IE, WebKit.

Het product wordt gehost op github. Zie de README daar. Releases zijn beschikbaar op PyPI (0.2 gereleased op 22 oktober 2010).

Zie de slides.

Roel Bruggink (Four Digits): Living Statues Sprint

De Plone community gebruikt sprints voor het ontwikkelen van nieuwe functionaliteit. Het idee is dat je met een aantal ontwikkelaars bij elkaar gaat zitten en een sprintje maakt in de ontwikkeling van een product. Eind augustus hebben wij van Four Digits de Living Statues Sprint in Arnhem georganiseerd. Twee keer per dag een stand-up meeting: kort overleg over wat je tot dan toe gedaan hebt en nu gaat doen. In dit geval hebben we vooral aan Deco gewerkt, zie het praatje van Rob. Ook aan Hudson, een continue integratieserver voor automatisch testen, vergelijkbaar met buildbot.

Fred van Dijk (Zest Software): pakketten die je (misschien) nog niet kent

We hebben bij Zest Software een aantal pakketten gemaakt die je waarschijnlijk nog niet kent. Het basis CMS Plone is open source. Veel add-on modules zijn ook open source. Worden door integrators vaak in eerste instantie voor één klant gebouwd. Soms kom je erachter dat het vrij makkelijk is om het voor algemeen gebruik te maken, bijvoorbeeld PloneFormGen. Wat komt er dan zoal uit Nederland, en hier specifiek bij Zest Software. Verkapte oproep: laat wat van je eigen modules zien.

  • collective.sendaspdf: laat de server de pdf maken van een webpagina en email die. Heeft extra module nodig (wkhtmltopdf).
  • zest.carouselitem: toevoeging voor collective.carousel. Speciaal contentitempje met plaatje en wat extra instellingen, zoals een ander kleurtje.
  • mr.inquisition: voorafgaand aan migraties: toon onder andere overzicht van gebruikte content types.
  • zest.portlet.contact: speciaal portlet voor contactgegevens
  • zest.teammember: overzicht van teamleden/medewerkers, op een mooie manier vormgegeven met verschillende portretten.
  • zest.releaser: maakt releasen makkelijk

Verder heb je bijvoorbeeld:

Maar ja, releasen is soms iets teveel werk, dus niet alle genoemde pakketten hebben we al daadwerkelijk gereleased. Zet hem op! En maak reclame!

Zie de slides.

Kees Hink (Goldmund, Wyldebeast and Wunderliebe): deurmat

Binnen een jaar wilden twee van onze klanten een 'deurmat'. Een beetje zoals de homepage van http://plone.org. Maak linkjes aan, geef wat headers aan en je hebt een deurmat. Dat doet Products.Doormat.

Thijs Jonkman (Pareto): XDV skinning

Je kan XDV theming gebruiken om Collage in het Deco keurslijf te persen. De CSS positionering van Deco kan je namelijk ook al in Plone 3 of 4 gebruiken. De html code van Collage is lelijk, maar als je er een net zo lelijke xslt sheet tegenaan gooit, krijg je er wel wat schoons uit.

Maurits van Rees (Zest Software): collective.watcherlist

Poi is een issue tracker voor Plone. Hij wordt op plone.org gebruikt. Ik doe daar sinds een paar jaar de ontwikkeling van. In de loop der tijd heb ik daar een aantal problemen opgelost rond het versturen van e-mails met 'internationale' karakters, van Nederlandse accenten in de namen van ontvangers tot Japanse karakters in de tekst. Dat wilde ik het liefst maar één keer doen. Ik heb dus die code afgesplitst in een nieuw pakket collective.watcherlist. Poi 2.0 (voor Plone 4) gebruikt dit.

Met behulp van dit product kan je een lijstje bijhouden van mensen die geïnteresseerd zijn in updates van een item. In het geval van Poi zijn dat nieuwe issues of wijzigingen aan bestaande issues. Out-of-the-box doet watcherlist nog helemaal niets. Je moet zelf als programmeur dus integratiecode schrijven. Gelukkig is dat niet al te moeilijk naar mijn idee. De template die verstuurd wordt, registreer je gewoon als browser view. In de code van watcherlist zit een integratievoorbeeld.

Als ik ooit nog eens gek wordt van Singing & Dancing, maak ik een nieuwsbriefproduct met watcherlist als basis. :-)

Jeroen Vloothuis (KNMP) en Jan Murre (Pareto): Plone skinning met XDV

published Nov 02, 2010

Een case studie van KNMP waarbij met Plone 4 en XDV de huisstijl is geïmplementeerd.

Jeroen Vloothuis en Jan Murre presenteren tijdens de Nederlandse Plone Gebruikersdag 2010 in de Euromast, Rotterdam.

Jeroen Vloothuis: ik heb ooit bij Pareto gewerkt, maar zit nu bij KNMP als klant van Pareto, dus dat is wel een bijzondere situatie. De KNMP behartigt de belangen van de apothekers in Nederland. We hebben twee websites: http://knmp.nl en http://pw.nl (Pharmaceutisch Weekblad). Daartussen moest ook nog wat gesynchroniseerd worden. Het ontwerp is gemaakt door TamTam.

Jan Murre: we hebben Plone 4 gebruikt. Vanaf de eerste betas was dit eigenlijk al een heel stabiel product. Verder onder andere PloneFormGen, Ploneboard, Collage, Feedfeeder (haal pagina's via RSS of atom binnen in je eigen site), Schemaextender, XDV.

Met Collage kan je in de content een layout maken met rijen en kolommen. De user interface is wat 'clunky'. Op termijn komt Deco in zicht als vervanging. De maker heeft aangegeven misschien een migratiepad van Collage naar Deco te maken, maar dat is dus onder voorbehoud.

Met SchemaExtender (bedankt, Jarn!) kan je bestaande content types uitbreiden. Dat is handig als een bestaand type bijna heeft wat je nodig hebt maar net even een veldje mist. In ons geval hebben we de schema extender gebruikt om het agenda item nog een plaatje mee te geven.

XDV: startte als Deliverance, door Paul Everitt. Doel is om de afstand tussen front- en backend developers te verkleinen. Zope Page Templates (ZPT) waren hier ook voor bedoeld. Het idee van ZPT was dat een pure html developer zonder Zope kennis ook een page template zou kunnen editen; in de praktijk staat er toch vaak teveel logica in.

Het skinnen van een Plone site bestaat uit het aanpakken van CSS ('decorating the tree'), viewlets, portlets, main template. Maar: Plone is 'zwaar': heel veel html, er moet veel gerekend worden. XDV gebruikt XSLT om die Plone boom te kortwieken. Met regels kan je zeggen: verplaats een deel van de html, of kopieer het, voeg wat toe aan de voor- of achterkant, haal wat weg.

Het scheelt aan de Plone kant niet aan rekenkracht, want Plone moet nog steeds de hele pagina laden. Voor de browser wordt het natuurlijk wel iets eenvoudiger, als je tenminste XDV gebruikt om van alles en nog wat weg te halen. Je zou aan de Plone kant wel een licht theme kunnen maken dat al veel minder html laadt.

Hoe doe je deployment? Gebruik collective.xdv voor Plone. Gebruik plugins voor de Nginx of Apache web server. Je kan ook dv.xdvserver als WSGI pipeline gebruiken. (Noot van Maurits: collective.xdv is ondertussen bezig met een naamsverandering naar Diazo.)

Lennert Regebro: "XDV is a potential game changer!" Als je het eenmaal in je vingers hebt, kan je heel snel Plone sites skinnen. Met Banjo kan je via drag-and-drop een XDV ruleset maken; nog niet ideaal, maar een goed begin.

Vraag uit de zaal: waarom is dit nou een voordeel? Antwoord: je hoeft veel minder aan de Plone kant aan te passen. Als je na een jaar weer een nieuwe vormgeving wilt, hoef je alleen maar de rules aan te passen, zonder dat je weer een hoop in Plone hoeft te veranderen. Een upgrade naar een nieuwere Plone versie zal ook gemakkelijker gaan.

Er is wat onenigheid in de zaal of het echt sneller is dan zelf een nieuw theme maken; het scheelt of je al een design in html en css aangeleverd hebt gekregen door een designbureau of dat je een Photoshop bestand hebt waar je nog helemaal me aan de slag moet.

Zie de slides.

Rob Gietema (Four Digits): Content bewerken in Plone met Deco

published Nov 02, 2010

Met Deco wordt het onderhouden van een website echt leuk. Het geeft je alle vrijheid om pagina's op te maken.

Rob Gietema van Four Digits spreekt op de Nederlandse Plone Gebruikersdag 2010 in de Euromast, Rotterdam.

Deco zal standaard gebruikt worden in Plone 5 en je kan er in Plone 4 al mee experimenteren. Deco is de voorkant, Blocks de technische achterkant.

Deco werkt met een grid. Op dat grid kan je tiles (tegels) toevoegen met html; dat kan de weergave van de titel zijn, of een folder listing, of van alles en nog wat.

Op de Living Statues Sprint in augustus hebben we een voorbeeldwebsite gemaakt met Deco om alles te testen en te kijken wat er nog mist.

(Nu volgt een demonstratie.)

De tiles vervangen onder andere de viewlets en portlets, dus je hoeft weer wat minder technieken te weten.

Kan je het al gebruiken? Nog net niet, maar we zijn al een heel eind. Op dit moment is nog geen overerving mogelijk (zoals nu bij portlets). Je wilt nog een template op kunnen geven: gebruik standaard voor dit type deze layout, zodat het minder snel een zooitje wordt.

Om het te proberen, gebruik deze buildout: https://svn.plone.org/svn/plone/plone.app.deco/buildouts/dev

Zie de slides.

Internationalization in Plone 3.3 and 4.0

published Oct 15, 2010, last modified Mar 05, 2013

How to do translations of your package in Plone 3.3 and 4.0. (Update 1: some comments by Hanno Schlichting. Update 2: zest.pocompile.)

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

My article from 2007 about i18n, locales and Plone 3.0 is still one of the most popular articles on my website. By now it is three years old, so it is high time for an update. This time I will focus on Plone 3.3 and 4.0. Advice here should be valid for the complete Plone 4.x line as I do not expect changes in this area. The findings below are my conclusions from testing with some sample packages on Plone 3.3.5 and Plone 4.0.0.

i18n versus locales

When you create a new package with its own translation domain, should you create an i18n directory or a locales directory? Basically, it does not matter in Plone 3.3 and 4.0. They both work fine. But the i18n directory is old technology and may not work anymore in Plone 5 and later. I know no downsides to the newer locales directory. So if you have the choice, you should use a locales directory. Register it like this in your configure.zcml:



  
  


Note that there is nothing magical about the locales name. You could call it Quack and it would also work, as long as you register it:


Headers and name of po file

Within a locales directory it does not matter too much what the headers look like. Some headers that you may think are vital, have absolutely no influence in practice. For example, you may have these headers:

"Language-Code: en\n"
"Language-Name: English\n"
"Domain: non.existing\n"

When those headers are in the locales/nl/LC_MESSAGES/collective.ducks.po file, then the internationalization machinery will regard the language as Dutch (nl for NetherLands as directory name) and collective.ducks as the domain as that is the name of the file minus the .po at the end. For clarity it may still be better to let the information in the headers match the folder name and file name. Update: Hanno Schlichting notes that these headers are not actually part of the gettext standard, but have been invented for the PlacelessTranslationService, so it is best to remove them from the po files, instead of trying to keep them in sync with the file name. I myself will note that i18ndude (at least the most recent 3.2 version) adds these headers by default, making it hard to keep them removed. But at least in locales directories it neither hurts to keep them, nor to remove them.

So your po file must match the pattern locales/languagecode/LC_MESSAGES/domainname.po. Note that the domain name is case sensitive. In Products.Poi the domain name is Poi, so I had to name the file Poi.po; with poi.po my translations were not picked up.

Note that if you still use an i18n directory the headers are checked. But i18n is old-style so I have not checked this too rigourously. Update: Hanno confirms that this is indeed the case; you can call your file i18n/spam.po and it will still work, as long as the headers are correct.

Domains in GenericSetup xml files

In your GenericSetup profile you can have several xml files. In some of these it makes sense to do translations. In most of those cases it only helps to use the plone domain. Let's try out most of the xml files, at least the ones contained in CMFPlone itself. Note that you are always allowed to use the plone domain, but if the xml file supports a separate domain, it is best to use that.

  • actions.xml: use your own domain. Example:

    
    

    Note that when you go to the portal_actions tools in the ZMI, you will see an i18n domain specified for each action.

  • catalog.xml: no i18n needed

  • componentregistry.xml: no i18n needed

  • contenttyperegistry.xml: no i18n needed

  • controlpanel.xml: use your own domain. (Note that in Plone 3.1 you must use the plone domain.) Example:

    
    
    
  • cssregistry.xml: no i18n needed

  • diff_tool.xml: no i18n needed

  • factorytool.xml: no i18n needed

  • jsregistry.xml: no i18n needed

  • kssregistry.xml: no i18n needed

  • mailhost.xml: no i18n needed

  • memberdata_properties.xml: no i18n needed

  • metadata.xml: no i18n needed

  • portal_atct.xml: use the plone domain. Note that this has no influence on the Collections panel in Site Setup. It is only used on the edit and criteria pages of a Collection.

  • portlets.xml: use the plone domain.

  • properties.xml: no i18n needed

  • propertiestool.xml: no i18n needed

  • rolemap.xml: no i18n needed

  • skins.xml: no i18n needed

  • toolset.xml: no i18n needed

  • types: use your own domain

  • viewlets.xml: no i18n needed

  • workflows: use the plone domain

Combining i18n and locales in your own package

You could put some translations of your domain in an i18n directory and some in a locales directory. When you do that, in Plone 3 your i18n translations are ignored. In Plone 4 both are combined; I cannot imagine a sane use case for doing this though. So: for your own domain you should always use either an i18n or a locales directory.

If you want to put your own domain in a locales directory and some extra translations for the plone domain in an i18n directory, that is fine.

i18ndude

I always use i18ndude to find translations in my package and generate and update the po files. I usually copy a script with the name rebuild_i18n.sh from package A to the new package B, and adapt it to the needs of that package. It at least works on Linux and Mac and looks something like this:

#! /bin/sh

I18NDOMAIN="collective.ducks"

# Synchronise the templates and scripts with the .pot.
# All on one line normally:
i18ndude rebuild-pot --pot locales/${I18NDOMAIN}.pot \
    --merge locales/manual.pot \
    --create ${I18NDOMAIN} \
   .

# Synchronise the resulting .pot with all .po files
for po in locales/*/LC_MESSAGES/${I18NDOMAIN}.po; do
    i18ndude sync --pot locales/${I18NDOMAIN}.pot $po
done

Note the dot at the end of the rebuild-pot call to signal that i18ndude should start searching in the current directory. The merge is optional; adapt to your needs and look in the i18ndude documentation for hints.

Gotchas

If you use i18ndude to extract msgids (translatable strings) it looks for i18n:translate calls in templates and xml files; it looks for the corresponding i18n:domain specification to check if this msgid belongs to the domain you are interested in (specified in the --create option). In python files i18ndude simply looks for all strings wrapped in an underscore function: _('My translatable string'). This function is usually defined like this:

from zope.i18nmessageid import MessageFactory
_ = MessageFactory('collective.ducks')

The gotcha now is that i18ndude is not smart enough to know which domain the string belongs to. It will report all 'underscored' strings, whether you look for your own domain or the plone domain. Usually you are only interested in your own domain. If you still need to use the plone domain in a python file, it is best to make sure this is not done with an underscore. For example, when customizing the folder_copy.cpy script of standard Plone in an own skin layer, I usually change it from this:

from Products.CMFPlone import PloneMessageFactory as _
message = _(u'One or more items not copyable.') 

to this:

from Products.CMFPlone import PloneMessageFactory as PMF
message = PMF(u'One or more items not copyable.')

That way, i18ndude will not detect that the string 'One or more items not copyable.' is translatable, so it will not end up in your pot and po files, so the existing translation from plone.app.locales is used.

Special case: translate the profile title and description

Say you have a configure.zcml like this:



  
  
  

i18ndude will not pick up the title and description, so you will have to add it manually. Create a locales/manual.pot file with something like this:

# --- PLEASE EDIT THE LINES BELOW CORRECTLY ---
# SOME DESCRIPTIVE TITLE.
# FIRST AUTHOR , YEAR.
msgid ""
msgstr ""
"Project-Id-Version: collective.duck 1.0\n"
"POT-Creation-Date: 2010-09-01 09:58+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI +ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0\n"
"Language-Code: en\n"
"Language-Name: English\n"
"Preferred-Encodings: utf-8 latin1\n"
"Domain: collective.ducks\n"

#: Profile title in configure.zcml
msgid "Collect All Ducks"
msgstr ""

#: Profile description in configure.zcml
msgid "Ducks of all nations: unite!"
msgstr ""

Rebuild the pot file and merge the manual pot file in it, something like this:

i18ndude rebuild-pot --pot locales/collective.ducks.pot --merge locales/manual.pot --create collective.ducks .

Synchronize the pot file with the po files (we will just do the Dutch file here):

i18ndude sync --pot locales/collective.ducks.pot locales/nl/LC_MESSAGES/collective.ducks.po

Add the translations in your po file, restart your zope instance and the translations should be visible in the Add-ons panel in the Site Setup (and the portal_quickinstaller in the ZMI).

Extra translations for an existing domain

This section is true for adding extra translations (new msgids) to any domain, but the plone domain is of course the one for which this is most often needed.

In Plone 3, the standard plone domain translations are done in an i18n directory. If you create a locales directory with extra plone translations, these will cancel all existing i18n translations for plone, so this is not good. You should create an i18n directory for this.

In Plone 4 you should add extra plone domain translations in a locales dir.

In general, you should follow the lead of the standard translations for the domain you want to add msgids for. If they are in an i18n directory, you should add your's in an i18n directory. If they are in a locales directory, you should add your's in a locales directory.

Note that in Plone 4 it looks like first all locales are loaded for all packages, and then all i18n directories are loaded. This might depend on the order in which the zcml for the packages is loaded though.

Overriding translations

In Plone 3.3 you can override translations that are in the i18n directory of a package (for example plone.app.locales, which is the successor or Products.PloneTranslations). The best way to make sure your translations are picked over the default ones, is by creating an i18n directory within your zope instance. Easiest is to use collective.recipe.i18noverrides for this.

Note that you can not use an i18n directory in the instance to override translations from a locales directory.

In Plone 4 the i18n directory of the instance is completely and utterly ignored. What you can do is override some translations of a locales directory. You can create a new plone package and use that only to override some translations, or you add something to an existing package. Let's say you want to override the "You are here:" translation from the bread crumbs (path bar). In Dutch it says "U bent hier:". We now want it to say: "U bent hier naartoegevlogen:". You locate the plone.po file for your translation and copy it to your locales directory. In our case we have created a package called customer.translations so copy this file:

plone.app.locales-4.0.0-py2.6.egg/plone/app/locales/locales/nl/LC_MESSAGES/plone.po

to this file:

customer.translations/customer/translations/locales/nl/LC_MESSAGES/plone.po 

Then remove whatever translations you do not need to override, and do your change, so you end up with a po file with some headers and this translation:

#. Default: "You are here:"
#: plone.app.layout/plone/app/layout/viewlets/path_bar.pt:6
msgid "you_are_here"
msgstr "U bent hiernaartoe gevlogen:"

In your buildout.cfg make sure this package is added to the eggs. The tricky thing now is to make sure that the zcml for this package is loaded before the zcml of other packages; that way our translations win. The way to do this, is to list it as the first (and possibly only) item in the zcml option, so something like this:

[instance]
...
eggs =
    Zope2
    Plone
    ${buildout:eggs}
    customer.translations
zcml =
    customer.translations

Warning: this works in Plone 3 too, but it has a problem. In Plone 3 the translations for the plone domain are in an i18n directory. If we add a plone.po file in our locales directory, the effect is that all other translations from the plone domain are lost. In other words: if you override an i18n folder with your own locales folder, all translations for that domain that are not in your po file, are lost. So you would have to copy over the complete original po file. In that case it is probably easier to use the already mentioned collective.recipe.i18noverrides. To be clear: this is true when using Plone 3.

To summarize this part:

  • If you want to override translations from an i18n directory:
  • If you want to override translations from a locales directory it is the same on Plone 3.3 and 4: copy the relevant part of the po file to the locales directory of your own package. Copying the entire po file works as well of course, but is not needed. Also you need to make sure the zcml of your package is loaded first. On Plone 3.3 it seemed less reliable, but that may be because I was meanwhile also combining i18n and locales directories for the same domain, which is not a good idea.

Restrict the loaded languages

(Update: includes info from Hanno about zope_i18n_allowed_languages.)

To speed up zope startup time and use less memory, you can set an environment variable to restrict the languages for which po files are loaded. To restrict them to English, Dutch and German, give this a value of en, nl, de. The commas are optional. In buildout.cfg this would be something like this:

[instance]
...
environment-vars =
  PTS_LANGUAGES en nl de
  zope_i18n_allowed_languages en nl de
  zope_i18n_compile_mo_files true

The zope_i18n_compile_mo_files setting is optional, see the next section. But why do we specify the allowed languages twice? Some words from Hanno, who pointed me to zope_i18n_allowed_languages:

In Plone 3.3 there is only PTS_LANGUAGES and it affects both i18n and locales folders. In Plone 4 there is also zope_i18n_allowed_languages. The new one now affects locales folders and the old one only affects i18n folders. So to get the full memory saving affect of not loading too many translation files, you need to specify both on Plone 4. Specifying the new one in Plone 3.3 does not hurt, it just does not do anything.

Compiled translation files

.po files need to be compiled before Plone can do something with them. When you compile a domain.po file, you get a domain.mo file. This is the file that is read by the translation machinery when looking up a translation for a msgid. To compile a file manually, you need the msgfmt program:

msgfmt -o domain.mo domain.po

If your package contains po files, Plone 3.3 compiles them when starting up your instance. In Plone 4 this is optional. For example, you might want to skip this when you do not need any translations at all in your site. Actually, it is skipped by default. To enable the compile step, add the following to the instance or zeoclient part of your Plone 4 buildout.cfg:

environment-vars =
    zope_i18n_compile_mo_files true

Note that the value (true in this case) does not matter: the relevant code in zope.i18n simply looks for the existence of the variable and does not care what its value is.

In Plone 3, any existing mo files in an i18n directory of a package are ignored. Instead, when the Zope instance starts up, all po files are compiled automatically and put in a directory like var/instance/pts.

Also in Plone 3, any po files in a locales directory are compiled inside that same locales directory: locales/nl/LC_MESSAGES/domain.po is compiled to a file locales/nl/LC_MESSAGES/domain.mo.

In Plone 4, the var/instance/pts directory is not used at all. All po files in an i18n or locales directory are compiled inside that same directory.

On startup, Zope (actually the PlacelessTranslationService) may see that a po file already has an accompanying mo file in the correct directory. It then compares the last modification date of the two files. If the po file is more recent, then a new mo file is compiled.

Note that you should not put the compiled mo files in subversion (or another version control system) as they can just be automatically created. Once you release a package to the public, putting the mo files in the released source could be handy though: if your package without mo files is installed by for example the root user in a directory where user zope has read access but not write access, then user zope will get an error when starting Plone. plone.app.locales does this correctly. I have not done this myself yet (and some of my packages probably still contain mo files in subversion) so I will not further comment on how to do this. I do want to add support for this in zest.releaser or in an optional support package for that.

If you want to do it manually, this shell script does the trick (at least when you have proper bash, find and msgfmt commands available):

for po in $(find . -path '*/LC_MESSAGES/*.po'); do
    msgfmt -o ${po/%po/mo} $po;
done

Plus you will need to make sure mo files are included in the created source distribution by creating a MANIFEST.in file next to your setup.py file; this works for me:

recursive-include collective *
global-exclude *pyc

Update: Okay, I have just created and released http://pypi.python.org/pypi/zest.pocompile for this, for use in combination with zest.releaser or as stand-alone command line tool.

Conclusions

  • When you create a package with a new translation domain: use locales.
  • When extending existing translations, follow the lead of the package you are extending to determine whether you should use i18n or locales.
  • When overriding existing translations, also follow the lead of the package you are overriding. Make sure the zcml of your package is loaded before that of the other package. On Plone 3.3 with an i18n dir: use collective.recipe.i18noverrides.
  • When using locales, make sure your po file matches the pattern locales/languagecode/LC_MESSAGES/domainname.po and note that the domain name is case sensitive.
  • In GenericSetup files, use your own domain for:
    • actions.xml
    • controlpanel.xml
    • types
  • In GenericSetup files, use the plone domain for:
    • portal_atct.xml
    • portlets.xml
    • workflows

Have fun translating!