Maurits van Rees:
http://maurits.vanrees.org/
Zest Software, The Netherlands:
http://zestsoftware.nl/
Sample code, including this talk:
https://github.com/mauritsvanrees/maurits.i18ntalk
- What is internationalization?
- Defining strings in templates,
Python,GenericSetup,XML. - Extracting strings with
i18ndude. - Making Plone aware of the translations.
- Overriding translations.
- Future.
internationalization i...18 characters..n
i18n means making the web interface appear translated in your
local language instead of the default English.
No localization (l10n).
No multilingual sites.
Plone 4.0-4.3
- Make strings translatable.
- Extract those strings with i18ndude into a po file (portable object).
- Translate the strings in the .po file.
<html ...
xmlns:i18n="http://xml.zope.org/namespaces/i18n"
i18n:domain="maurits.i18ntalk">
<span i18n:translate="">A simple message</span>
<p i18n:translate="msg_string">This is a message.</p>
<span i18n:translate="">Label:</span>
<tal:block tal:content="some_content" />
<p i18n:domain="plone" i18n:translate="">
A message in the plone domain.
</p>
</html>
In the .pot/.po file it becomes this:
#: browser/test.pt:3 msgid "A simple message" msgstr "Een eenvoudige boodschap" #. Default: "This is a message string." #: ./browser/bookview.pt:14 msgid "msg_string" msgstr "Dit is een boodschap."
These are not used:
#. Default: "This is a message." #: ./browser/bookview.pt:15 #, fuzzy msgid "msg_string" msgstr "Dit is een boodschap."
<p i18n:translate="">
This book has
<tal:block i18n:name="stars"
tal:content="context/getStars" />
stars.
</p>
msgid "This book has ${stars} stars."
msgstr "Dit boek heeft ${stars} sterren."
If you forget the i18n:name you get this in your .po file:
msgid "This book has ${DYNAMIC_CONTENT} stars."
msgstr "Dit boek heeft ${DYNAMIC_CONTENT} sterren."
And this translation does not show up.
__init__.py:
from zope.i18nmessageid import MessageFactory
i18ntalkMF = MessageFactory('maurits.i18ntalk')
In your python file:
from maurits.i18ntalk import i18ntalkMF as _
...
def title(self):
return _(u"My latest books")
In a template:
<span tal:content="view/title" />
def book_message(self):
number = 42
return _(u"There are ${books} books in total.",
mapping={'books': number})
logger = ...
from zope.i18n import translate
msg = _("My books portlet is displayed.")
translation = translate(msg, context=self.request)
logger.info(translation)
# def translate(msgid, domain=None, mapping=None,
# context=None, target_language=None, default=None):
profiles/default/types/Book.xml:
<?xml version="1.0"?>
<object name="Book"
meta_type="Factory-based Type Information
with dynamic views"
i18n:domain="maurits.i18ntalk"
xmlns:i18n="http://xml.zope.org/namespaces/i18n">
<property name="title" i18n:translate="">Book</property>
<property name="description"
i18n:translate="">Information about a book</property>
Use your own domain for:
actions.xml controlpanel.xml types/YourType.xml
Use the plone domain for:
portal_atct.xml portlets.xml workflows/your_workflow/definition.xml
When in doubt, use the plone domain.
http://maurits.vanrees.org/weblog/archive/2010/10/i18n-plone-4
<configure
xmlns:gs="http://namespaces.zope.org/genericsetup"
i18n_domain="maurits.i18ntalk">
<gs:registerProfile
name="default"
title="Maurits' i18n talk"
directory="profiles/default"
description="Demo package by Maurits"
provides="Products.GenericSetup.interfaces.EXTENSION"
/>
</configure>
- How to extract?
i18ndudedoes not support this (yet).
<configure xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser"
i18n_domain="maurits.i18ntalk">
<include package="plone.app.contentmenu" />
<browser:page
for="maurits.i18ntalk.interfaces.IBook"
name="book_view"
... />
<browser:menuItem
for="maurits.i18ntalk.interfaces.IBook"
menu="plone_displayviews"
title="Book View"
action="@@book_view" />
</configure>
msgid "Book View"
atapi.IntegerField(
'stars',
widget=...,
schemata='starschema',
),
Put your translations manually in the plone domain:
#: content/book.py msgid "label_schema_starschema" msgstr "Sterrenschema"
Thanks, Reinout.
locales locales/yourdomain.pot locales/manual.pot locales/plone.pot locales/nl locales/nl/LC_MESSAGES locales/nl/LC_MESSAGES/yourdomain.po locales/nl/LC_MESSAGES/plone.po
buildout.cfg:
[i18ndude] recipe = zc.recipe.egg eggs = i18ndude
update_locales.sh:
#! /bin/sh
i18ndude rebuild-pot \
--pot locales/maurits.i18ntalk.pot \
--create maurits.i18ntalk \
--merge locales/manual.pot \
.
for po in locales/*/LC_MESSAGES/maurits.i18ntalk.po; do
i18ndude sync --pot locales/maurits.i18ntalk.pot $po
done
# Maurits van Rees <maurits@vanrees.org>, 2012. msgid "" msgstr "" "Project-Id-Version: maurits.i18ntalk 1.0\n" "POT-Creation-Date: 2012-10-03 14:36+0000\n" "PO-Revision-Date: 2012-10-03 16:39 +0200\n" "Last-Translator: Maurits <maurits@vanrees.org>\n" "Language-Team: Plone NL <plone-nl@lists.plone.org>\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: nl\n" "Language-Name: Nederlands\n" "Preferred-Encodings: utf-8 latin1\n" "Domain: maurits.i18ntalk\n"
msgfmt -c locales/nl/LC_MESSAGES/maurits.i18ntalk.po rm messages.mo
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:i18n="http://namespaces.zope.org/i18n">
<i18n:registerTranslations directory="locales" />
</configure>
Note:
- zcml:
http://namespaces.zope.org/i18n - html:
http://xml.zope.org/namespaces/i18n
[instance]
recipe = plone.recipe.zope2instance
locales = ${buildout:directory}/locales
environment-vars =
PTS_LANGUAGES en nl
zope_i18n_allowed_languages en nl
zope_i18n_compile_mo_files true
- in version control: no
- released on PyPI: yes
MANIFEST.in:
recursive-include collective * recursive-include docs * include * global-exclude *.pyc
easy_install or pip:
easy_install zest.releaser zest.pocompile
buildout:
[release]
recipe = zc.recipe.egg
eggs =
zest.releaser
zest.pocompile
Command:
fullrelease
Be the first! Order of loading:
$ cat parts/instance/etc/site.zcml <configure ... <!-- Load the configuration --> <include files="package-includes/*-configure.zcml" /> <five:loadProducts />
locales = ${buildout:directory}/localeszcml = your.package- Products alphabetically until and including
Products.CMFPlone - packages registered with
z3c.autoinclude - rest of the Products
i18nfolders (done byPlacelessTranslationService)
- No more
i18n:translate="some_message_id". - Babel instead of i18ndude?
[babelpy]
recipe = zc.recipe.egg
eggs =
babel
lingua
interpreter = babelpy
extract.ini:
[lingua_python: **.py] [lingua_xml: **pt] [lingua_xml: **.xml] [lingua_zcml: **.zcml]
bin/babelpy setup.py extract_messages
command line options or setup.cfg:
[extract_messages] mapping_file = extract.ini output_file = ...../locales/maurits.i18ntalk.pot sort_output = true
- Good: has zcml support
- Bad: currently extracts all domains
- support extracting zcml in i18ndude Code: https://github.com/collective/i18ndude
- improve babel or lingua
msgstr "Het einde" msgstr "Schluss" msgstr "La fin" msgstr "Los endos"
This talk plus the code:
https://github.com/mauritsvanrees/maurits.i18ntalk
An occasional blog entry about this Plone conference:


