Welcome, guest | Sign In | My Account | Store | Cart

Notice! PyPM is being replaced with the ActiveState Platform, which enhances PyPM’s build and deploy capabilities. Create your free Platform account to download ActivePython or customize Python with the packages you require and get automatic updates.

Download
ActivePython
INSTALL>
pypm install collective.recipe.i18noverrides

How to install collective.recipe.i18noverrides

  1. Download and install ActivePython
  2. Open Command Prompt
  3. Type pypm install collective.recipe.i18noverrides
 Python 2.7Python 3.2Python 3.3
Windows (32-bit)
1.0
1.2Never BuiltWhy not?
1.0 Available View build log
Windows (64-bit)
1.0
1.2Never BuiltWhy not?
1.0 Available View build log
Mac OS X (10.5+)
1.0
1.2Never BuiltWhy not?
1.0 Available View build log
Linux (32-bit)
1.0
1.2Never BuiltWhy not?
1.0 Available View build log
Linux (64-bit)
1.2 Available View build log
1.0 Available View build log
 
License
GPL
Dependencies
Lastest release
version 1.2 on Jan 9th, 2014

collective.recipe.i18noverrides

This 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 versions

This 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 the plone-internationalization mailing list.

Use case

An 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 file

What 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 it plone-nl.po as 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"

Supported options

The recipe supports the following options:

source
Source directory that contains the .po files that the recipe will copy. All *.po files will be copied. This option is mandatory.
egg
Egg that contains the source directory. If this option is mentioned, the source directory has to be a relative path.
package
Can be mentioned when source cannot be found in egg for one of the following reasons : egg holds a version specification; egg is not equal to the name of the installed package; source is in a subpackage.
destinations
Target 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 *.po files from the source directory to these i18n directories. This option is mandatory.
Example usage

We'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  i18n

A 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 file

If 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 file

Clean up:

>>> remove('instance')
>>> remove('instance2')
Integration with plone.recipe.zope2instance

As 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.po

If 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.po

Clean up:

>>> remove('translations')
Usage with directory in egg

We 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 specify egg and source:

>>> 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 bestand

We specify egg and an absolute path in source:

>>> 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 an egg` that does not hold the configured source:

>>> 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>

Contributors

Maurits van Rees, Author

History of collective.recipe.i18noverrides

1.2 (2013-01-23)
  • Raise zc.buildout.UserWarning in 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.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]

Subscribe to package updates

Last updated Jan 9th, 2014

Download Stats

Last month:1

What does the lock icon mean?

Builds marked with a lock icon are only available via PyPM to users with a current ActivePython Business Edition subscription.

Need custom builds or support?

ActivePython Enterprise Edition guarantees priority access to technical support, indemnification, expert consulting and quality-assured language builds.

Plan on re-distributing ActivePython?

Get re-distribution rights and eliminate legal risks with ActivePython OEM Edition.