Package: collective.recipe.i18noverrides
Contentscollective.recipe.i18noverridesPlone/Zope versionsUse caseContents of .po fileDetailed DocumentationSupported optionsExample usageIntegration with plone.recipe.zope2instanceUsage with directory in eggContributorsChange historyHistory of collective.recipe.i18noverrides1.2 (2013-01-23)1.1 (2012-09-13)1.0 (2010-08-25)0.4 (2009-09-08)0.3 (2009-09-08)0.2 (2009-08-12)0.1 (2009-06-05)Downloadcollective.recipe.i18noverridesThis is a buildout recipe.  It creates an i18n directory within one or
more zope 2 instances in your buildout.  It copies some .po files to
those directories.  The translations in those .po files will override
any other translations.Plone/Zope versionsThis is tested for Plone 3 with Zope 2.10.  It should work for a plain
Zope site without Plone as well, as there is nothing Plone specific to
this recipe.  It should work fine for all previous versions as well.For Plone 4 and Zope 2.12 it has no effect: there is no code anymore
in those versions that looks for translations in an i18n folder of
your instance.  You should create an own package and register a
locales directory with translation in it.  For more info or questions,
see theplone-internationalization mailing list.Use caseAn example use case is:In the Dutch Plone translations the msgid ‘Manager’ is translated as
‘Beheerder’.A customer wanted it to be translated as ‘Site admin’ instead.Just putting this translation within the i18n directory of the
customer product is not guaranteed to work as it depends on the
order in which the i18n folders get read on Zope startup: is
CMFPlone/i18n or Customer/i18n read first.When you create an i18n directory within the zope 2 instance and add
a po file with that msgid there, this is guaranteed to get used.Note that this should work for overriding translations within i18n
directories.  Overriding translations in locales directories is not a
use case of this recipe.Contents of .po fileWhat should be in the .po file?  You need all the headers that are
normally in .po files.  So copy the headers of the current .po file
that has the translation that you want to override.  Then just add the
msgid and a new msgstr.  The name of the file does not really matter.
It should be meaningful to you and end with ‘.po’.  In the mentioned
use case it makes sense to call itplone-nl.poas that is the name
of the original file from the plone translations.  The contents would
be something like this (non-interesting header lines skipped for
clarity):msgid ""
msgstr ""
...
"Language-Code: nl\n"
"Language-Name: Nederlands\n"
"Domain: plone\n"

msgid "Manager"
msgstr "Site admin"Detailed DocumentationSupported optionsThe recipe supports the following options:sourceSource directory that contains the .po files that the recipe will
copy.  All*.pofiles will be copied.  This option is mandatory.eggEgg that contains thesourcedirectory. If this option is mentioned,
thesourcedirectory has to be a relative path.packageCan be mentioned whensourcecannot be found ineggfor one of the
following reasons :eggholds a version specification;eggis not
equal to the name of the installed package;sourceis in a subpackage.destinationsTarget directory or directories.  This should point to the
directory of the zope 2 instance.  The recipe will create an i18n
directory in each of the destinations and copy all*.pofiles
from the source directory to these i18n directories.  This option
is mandatory.Example usageWe’ll start by creating a buildout that uses the recipe.  Here is a
template where we only have to fill in the source and destinations:>>> buildout_config_template = """
... [buildout]
... index = http://pypi.python.org/simple
... parts = i18noverrides
... versions = versions
...
... [versions]
... zc.buildout = 1.4.3
... zc.recipe.egg = 1.2.2
... setuptools = 0.6c11
... distribute = 0.6.14
...
... [i18noverrides]
... recipe = collective.recipe.i18noverrides
... source = %(source)s
... destinations = %(dest)s
... """We will start with specifying some non existing source and destination
directories:>>> write('buildout.cfg', buildout_config_template % {
... 'source': '${buildout:directory}/translations',
... 'dest': '${buildout:directory}/instance'})Running the buildout gives us:>>> print system(buildout)
Installing i18noverrides.
While:
  Installing i18noverrides.
Error: path '/sample-buildout/translations' does not exist. You must list the i18noverrides part after all plone.recipe.zope2instance parts.
<BLANKLINE>The source must be a directory:>>> write('translations', 'This is a file.')
>>> print system(buildout)
Installing i18noverrides.
While:
  Installing i18noverrides.
Error: path '/sample-buildout/translations' must be a directory.
<BLANKLINE>Now we remove this file and try with a proper directory:>>> remove('translations')
>>> mkdir('translations')
>>> print system(buildout)
Installing i18noverrides.
While:
  Installing i18noverrides.
Error: path '/sample-buildout/instance' does not exist. You must list the i18noverrides part after all plone.recipe.zope2instance parts.
<BLANKLINE>So we set a destination too and first try with a file as well before
creating a directory:>>> write('instance', 'This is a file.')
>>> print system(buildout)
Installing i18noverrides.
While:
  Installing i18noverrides.
Error: path '/sample-buildout/instance' must be a directory.
<BLANKLINE>
>>> remove('instance')
>>> mkdir('instance')
>>> print system(buildout)
Installing i18noverrides.
collective.recipe.i18noverrides: Warning: source '/sample-buildout/translations' contains no .po files.
<BLANKLINE>Now the source and destination have been setup correctly, but we get a
warning as the source directory has no translation files.  We first
add a file that does not end with.po.  Since the previous
buildout run only had a warning and finished successfully, the recipe
now runs in update mode, which does the same as the install mode:>>> write('translations', 'not-a-po-file', 'I am not a po file')
>>> print system(buildout)
Updating i18noverrides.
collective.recipe.i18noverrides: Warning: source '/sample-buildout/translations' contains no .po files.
<BLANKLINE>
>>> write('translations', 'plone-nl.po', 'I am a Dutch plone po file')
>>> write('translations', 'plone-de.po', 'I am a German plone po file')
>>> print system(buildout)
Updating i18noverrides.
collective.recipe.i18noverrides: Creating directory /sample-buildout/instance/i18n
collective.recipe.i18noverrides: Copied 2 po files.
<BLANKLINE>No warnings, no errors, so let’s see what the end result is:>>> ls('translations')
-  not-a-po-file
-  plone-de.po
-  plone-nl.po
>>> ls('instance')
d  i18nA i18n directory has been created in the instance.  Inside that
directory we find our two po files:>>> ls('instance', 'i18n')
-  plone-de.po
-  plone-nl.po
>>> cat('instance', 'i18n', 'plone-de.po')
I am a German plone po file
>>> cat('instance', 'i18n', 'plone-nl.po')
I am a Dutch plone po fileIf the destination directory for some strange reason already contains
a i18n file instead of a directory, we fail:>>> remove('instance', 'i18n')
>>> write('instance', 'i18n', 'I am a file')
>>> print system(buildout)
Updating i18noverrides.
While:
  Updating i18noverrides.
Error: '/sample-buildout/instance/i18n' is not a directory.
<BLANKLINE>
>>> remove('instance', 'i18n')It should also be possible to have multiple destinations:>>> write('buildout.cfg', buildout_config_template % {
... 'source': '${buildout:directory}/translations',
... 'dest': """
...     ${buildout:directory}/instance
...     ${buildout:directory}/instance2"""})
>>> print system(buildout)
Installing i18noverrides.
While:
  Installing i18noverrides.
Error: path '/sample-buildout/instance2' does not exist. You must list the i18noverrides part after all plone.recipe.zope2instance parts.
<BLANKLINE>Right, right, we will create that directory too:>>> mkdir('instance2')
>>> print system(buildout)
Installing i18noverrides.
collective.recipe.i18noverrides: Creating directory /sample-buildout/instance/i18n
collective.recipe.i18noverrides: Creating directory /sample-buildout/instance2/i18n
collective.recipe.i18noverrides: Copied 2 po files.
<BLANKLINE>Let’s check the result:>>> ls('instance')
d  i18n
>>> ls('instance', 'i18n')
-  plone-de.po
-  plone-nl.po
>>> ls('instance2')
d  i18n
>>> ls('instance2', 'i18n')
-  plone-de.po
-  plone-nl.po
>>> cat('instance2', 'i18n', 'plone-de.po')
I am a German plone po file
>>> cat('instance2', 'i18n', 'plone-nl.po')
I am a Dutch plone po fileClean up:>>> remove('instance')
>>> remove('instance2')Integration with plone.recipe.zope2instanceAs the recipe is normally used to add translations to zope 2
instances, it makes sense to search for buildout parts that setup zope
instances and take those locations.>>> write('buildout.cfg', """
... [buildout]
... index = http://pypi.python.org/simple
... parts = instance instance2 zeoclient i18noverrides
... versions = versions
...
... [versions]
... zc.buildout = 1.4.3
... zc.recipe.egg = 1.2.2
... setuptools = 0.6c11
... distribute = 0.6.14
... plone.recipe.zope2instance = 3.9
... mailinglogger = 3.3
...
... [i18noverrides]
... recipe = collective.recipe.i18noverrides
... source = ${buildout:directory}/translations
...
... [instance]
... recipe = plone.recipe.zope2instance
... user = admin:admin
...
... [instance2]
... recipe = plone.recipe.zope2instance
... user = admin:admin
...
... [zeoclient]
... recipe = plone.recipe.zope2instance
... user = admin:admin
... """)We mock a mkzopeinstance script in the bin directory:>>> write('bin/mkzopeinstance', """
... import sys
... import os
... path = sys.argv[2]
... os.mkdir(path)
... os.mkdir(os.path.join(path, 'etc'))
... """)We do not want to install a complete zope2 instance in the tests, so
we do not add it to the buildout parts.  That does mean that running
buildout now fails:>>> print system(buildout)
Getting distribution for 'plone.recipe.zope2instance==3.9'.
...
Installing instance.
Generated script '.../bin/instance'.
...
Installing i18noverrides.
collective.recipe.i18noverrides: Creating directory .../i18n
collective.recipe.i18noverrides: Creating directory .../i18n
collective.recipe.i18noverrides: Creating directory .../i18n
collective.recipe.i18noverrides: Copied 2 po files.
<BLANKLINE>
>>> ls('parts', 'instance')
d etc
d i18n
>>> ls('parts', 'instance', 'i18n')
-  plone-de.po
-  plone-nl.po
>>> ls('parts', 'instance2', 'i18n')
-  plone-de.po
-  plone-nl.po
>>> ls('parts', 'zeoclient', 'i18n')
-  plone-de.po
-  plone-nl.poIf we explicitly specify destinations, the recipes are ignored.>>> write('buildout.cfg', """
... [buildout]
... index = http://pypi.python.org/simple
... parts = dummy i18noverrides
... versions = versions
...
... [versions]
... zc.buildout = 1.4.3
... zc.recipe.egg = 1.2.2
... setuptools = 0.6c11
... distribute = 0.6.14
... plone.recipe.zope2instance = 3.9
... mailinglogger = 3.3
...
... [i18noverrides]
... recipe = collective.recipe.i18noverrides
... source = ${buildout:directory}/translations
... destinations = ${buildout:directory}/dest
...
... [dummy]
... recipe = plone.recipe.zope2instance
... user = admin:admin
... """)
>>> mkdir('dest')
>>> print system(buildout)
Uninstalling ...
Installing i18noverrides.
collective.recipe.i18noverrides: Creating directory /.../dest/i18n
collective.recipe.i18noverrides: Copied 2 po files.
<BLANKLINE>
>>> ls('parts', 'dummy')
d etc
>>> ls('dest', 'i18n')
-  plone-de.po
-  plone-nl.poClean up:>>> remove('translations')Usage with directory in eggWe start by creating a buildout that uses the recipe.  Here is a
template where we only have to fill in the source, egg and
destinations:>>> buildout_config_template = """
... [buildout]
... index = http://pypi.python.org/simple
... parts = i18noverrides
... versions = versions
...
... [versions]
... zc.buildout = 1.4.3
... zc.recipe.egg = 1.2.2
... setuptools = 0.6c11
... distribute = 0.6.14
... # We need to pin this one because it still needs to be uninstalled.
... # If we do not pin, the uninstall code will get the latest version,
... # which depends on Zope2, which means we are hosed...
... plone.recipe.zope2instance = 3.9
... mailinglogger = 3.3
...
... [i18noverrides]
... recipe = collective.recipe.i18noverrides
... source = %(source)s
... egg = %(egg)s
... destinations = %(dest)s
... """We specifyeggandsource:>>> write('buildout.cfg', buildout_config_template % {
... 'source': 'tests/translations',
... 'egg': 'collective.recipe.i18noverrides',
... 'dest': 'translations'})We prepare target directory:>>> mkdir('translations')Running the buildout gives us:>>> print system(buildout)
Uninstalling ...
Installing i18noverrides.
collective.recipe.i18noverrides: Creating directory translations/i18n
collective.recipe.i18noverrides: Copied 2 po files.
<BLANKLINE>Let’s check the result:>>> ls('translations')
d  i18n
>>> ls('translations', 'i18n')
-  test-fr.po
-  test-nl.po
>>> cat('translations', 'i18n', 'test-fr.po')
Un fichier .po
>>> cat('translations', 'i18n', 'test-nl.po')
Een .po bestandWe specifyeggand an absolute path insource:>>> write('buildout.cfg', buildout_config_template % {
... 'source': '/translations',
... 'egg': 'testegg',
... 'dest': 'translations'})Running the buildout gives us:>>> print system(buildout)
Uninstalling i18noverrides.
Installing i18noverrides.
While:
  Installing i18noverrides.
Error: Because egg option is provided,
source '/translations' should be relative, not absolute.
<BLANKLINE>We specify anegg`that does not hold the configuredsource:>>> write('buildout.cfg', buildout_config_template % {
... 'source': 'translations',
... 'egg': 'zc.recipe.egg',
... 'dest': 'translations'})Running the buildout gives us:>>> print system(buildout)
Installing i18noverrides.
While:
  Installing i18noverrides.
Error: path '/sample-buildout/eggs/zc.recipe.egg.../zc/recipe/egg/translations' does not exist. You must list the i18noverrides part after all plone.recipe.zope2instance parts.
<BLANKLINE>ContributorsMaurits van Rees, AuthorChange historyHistory of collective.recipe.i18noverrides1.2 (2013-01-23)Raisezc.buildout.UserWarningin case of errors.  This is how it
should be done.  It is more noticeable than logging an error (which
may not be really visible as error) and quitting.
[maurits]1.1 (2012-09-13)Moved to github:https://github.com/collective/collective.recipe.i18noverrides[maurits]1.0 (2010-08-25)Added a note to warn that this recipe will have no effect in Plone 4
(Zope 2.12) or higher.  You should create an own package and
register a locales directory there.
[maurits]0.4 (2009-09-08)Only consider buildout parts for inclusion in the destinations when
they are actually in the parts section of buildout.  Otherwise you
can run into errors like this:
Error: Missing option: zptdebugger:__buildout_signature__
[maurits]0.3 (2009-09-08)If no destinations are specified, we automatically copy the po files
to all parts that use plone.recipe.zope2instance.
[maurits]0.2 (2009-08-12)Allow to specify an egg (with optional package)
where the source directory can be found.
[gotcha]Pin packages (at least zc.buildout) in both the main buildout.cfg
and the one in the tests, to avoid test failures simply because the
used zc.buildout is upgraded during the test run.
[maurits]0.1 (2009-06-05)Initial implementation moved over from a one-off script.  [maurits]Created recipe with ZopeSkel
[Maurits van Rees]Download