Git Product home page Git Product logo

zope.i18n's Introduction

zope.i18n

Latest release Supported Python versions https://coveralls.io/repos/github/zopefoundation/zope.i18n/badge.svg?branch=master Documentation Status

This package implements several APIs related to internationalization and localization.

  • Locale objects for all locales maintained by the ICU project.
  • Gettext-based message catalogs for message strings.
  • Locale discovery for Web-based requests.

zope.i18n's People

Contributors

agroszer avatar alga avatar baijum avatar cjw296 avatar dobe avatar faassen avatar freddrake avatar gotcha avatar hannosch avatar icemac avatar jamadden avatar jensens avatar kedder avatar malthe avatar mauritsvanrees avatar mcdonc avatar menesis avatar mgedmin avatar nadako avatar philikon avatar sidnei avatar slinkp avatar stevealexander avatar strichter avatar syzn avatar thefunny42 avatar trollfot avatar tseaver avatar warsaw avatar wichert avatar

Stargazers

 avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

zope.i18n's Issues

Add optional `ITranslationDomain` factory for `registerTranslations`

In https://bugs.launchpad.net/zope.i18n/+bug/428882, Ethan Jucovy ([email protected]) reported:

It is useful to be able to override the default zope.i18n.translationdomain.TranslationDomain -- for example I have one override that always injects a certain value into the translation mapping, and another that prepends all new catalogs rather than appending them.

This is currently difficult without monkeypatching zope.i18n.zcml.handler or forking its registerTranslations function.

The attached patch adds an optional factory argument to both registerTranslations and handler so that custom ZCML directives can invoke registerTranslations with their choice of ITranslationDomain.

It might also be worth checking that the object returned by the provided factory implements (or can be adapted to?) ITranslationDomain, and preventing startup if it does not.

The <registerTranslations/> directive could also be extended with an optional factory parameter whose default is zope.i18n.translationdomain.TranslationDomain. This isn't necessary, though, and it's arguably cleaner to write new directives for particular overrides.

with patch: https://bugs.launchpad.net/zope.i18n/+bug/428882/+attachment/714923/+files/add_factory.diff

Regression: 4.3.0 breaks ZopeTestCase

.../site-packages/Testing/ZopeTestCase/__init__.py:54: in <module>
    from . import placeless  # NOQA
.../site-packages/Testing/ZopeTestCase/placeless.py:31: in <module>
    ContainerPlacelessSetup):
E   TypeError: Error when calling the metaclass bases
E       Cannot create a consistent method resolution
E   order (MRO) for bases PlacelessSetup, PlacelessSetup, PlacelessSetup, CleanUp

Seems to be the same problem like #30.

`zope.i18n.translate` overrides mapping if passed a message

In https://bugs.launchpad.net/zope.i18n/+bug/592753, @ctheune reported:

When using the module-level translation function passing in a message ID like shown below the interpolation will not happen because the translate function overrides the passed-in mapping with the (empty) default of the message object.

from foo import MessageFactory as _
X = _('some ${data}')
zope.i18n.translate(X, mapping=dict(data=1))

A work around for users is to explicitly turn the message ID back into a unicode object:

zope.i18n.translate(unicode(X), mapping=dict(data=1))

@vincentfretin:

I usually do:

X = _('some ${data}', mapping=dict(data=1))
zope.i18n.translate(X, context=self.request)

But indeed when you use X as a constant, you don't have necessary the mapping right away. In this case, what I do is to create a new Message object:

from zope.i18nmessageid import Message
zope.i18n.translate(Message(X, mapping=dict(data=1)), context=self.request)

This is the preferred way to do it right now. You lose the domain and default message when you do unicode(X).

Indeed, it may be less verbose to write:

zope.i18n.translate(X, mapping=dict(data=1), context=self.request)

If somebody change the code of the translate function so you can override mapping like this, I think in this case you should be able to override domain and default as well.

@vincentfretin (later):

Christian: Do we replace or update the mapping that's on the message object?

When you create a Message object from a Message object, it replaces the mapping completely, so I'd say we should do the same here, replace the mapping.

@icemac:

Currently it is only possible to override the existing mapping but it might be helpful (in some cases) to update it. I see no need to remove keys from the mapping, so it would be always perfect to update the mapping.

@ctheune:

This needs more discussion. My analysis and discussion is here: https://mail.zope.org/pipermail/zope-dev/2010-October/041906.html

interpolate should not try to convert unicode object to unicode

This happened while testing a plone.app.contentrules based workflow transition for a document containing non-ascii characters in the title (Garapaöl). An error status message was generated by url which caused the Traceback below.

I was able to avoid the traceback and get a status message by copying safe_unicode from https://github.com/plone/Products.CMFPlone/blob/master/Products/CMFPlone/utils.py#L453

    def replace(match):
        whole, param1, param2 = match.groups()
        return safe_unicode(mapping.get(param1 or param2, whole))

Error Beim Wechsel des Status von Artikel Garapaöl im Rahmen einer Arbeitsablaufaktion ist ein Fehler aufgetreten: No workflow provides the '${action_id}' action.

Attempting to import safe_unicode results in an aborted server startup:

ZConfig.SchemaResourceError: could not load package ZServer: cannot import name translate
  Package name: 'ZServer'
  File name: 'component.xml'
  Package path: None
2017-02-28 13:33:07 ERROR Zope.SiteErrorLog 1488285187.130.516651919431 http://localhost:8585/mdb/de/produkte/garapaoel/@@edit
Traceback (innermost last):
  Module ZPublisher.Publish, line 138, in publish
  Module ZPublisher.mapply, line 77, in mapply
  Module ZPublisher.Publish, line 48, in call_object
  Module plone.z3cform.layout, line 66, in __call__
  Module plone.z3cform.layout, line 50, in update
  Module plone.dexterity.browser.edit, line 58, in update
  Module plone.z3cform.fieldsets.extensible, line 59, in update
  Module plone.z3cform.patch, line 30, in GroupForm_update
  Module z3c.form.group, line 145, in update
  Module plone.app.z3cform.csrf, line 21, in execute
  Module z3c.form.action, line 98, in execute
  Module z3c.form.button, line 315, in __call__
  Module z3c.form.button, line 170, in __call__
  Module plone.dexterity.browser.edit, line 30, in handleApply
  Module z3c.form.group, line 126, in applyChanges
  Module zope.event, line 31, in notify
  Module zope.component.event, line 24, in dispatch
  Module zope.component._api, line 136, in subscribers
  Module zope.component.registry, line 321, in subscribers
  Module zope.interface.adapter, line 585, in subscribers
  Module plone.app.contentrules.handlers, line 234, in modified
  Module plone.app.contentrules.handlers, line 162, in execute_rules
  Module plone.app.contentrules.handlers, line 130, in execute
  Module plone.contentrules.engine.executor, line 37, in __call__
  Module plone.contentrules.rule.rule, line 47, in __call__
  Module plone.app.contentrules.actions.workflow, line 65, in __call__
  Module plone.app.contentrules.actions.workflow, line 77, in error
  Module Products.statusmessages.adapter, line 34, in add
  Module zope.i18n, line 127, in translate
  Module zope.i18n.translationdomain, line 78, in translate
  Module zope.i18n.translationdomain, line 140, in _recursive_translate
  Module zope.i18n, line 165, in interpolate
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 15: ordinal not in range(128)

Incompatibilities with recent CLDR releases

In https://bugs.launchpad.net/zope.i18n/+bug/1073940, Murithi reported:

The versions of LDML files in locales/data are pretty old (released in 2004). Getting any new version from unicode.org: http://unicode.org/repos/cldr/trunk/common/main/ reveals a number of issues:

  • Parsing the generation in this format:
<generation date="$Date: 2012-10-11 23:11:48 +0300 (Thu, 11 Oct 2012) $"/>

fails:

  File ".../eggs/zope.i18n-3.7.4-py2.7.egg/zope/i18n/locales/xmlfactory.py", line 79, in _extractVersion
    generationDate = date(int(year), int(month), int(day))
ValueError: invalid literal for int() with base 10: '$Date: 2012'
  • There is an assumption that a date format e.g.:
      <dateFormat>
       <pattern>MMMM d, y</pattern>
      </dateFormat>

implies length for all the date parts - it does not and will fail when formatting dates.

  File ".../eggs/zope.i18n-3.7.4-py2.7.egg/zope/i18n/format.py", line 192, in format
    text += info.get(elem, elem)
TypeError: coercing to Unicode: need string or buffer, tuple found
<type 'exceptions.TypeError'>:
coercing to Unicode: need string or buffer, tuple found
> /home/undesa/bungeni_apps/bungeni/eggs/zope.i18n-3.7.4-py2.7.egg/zope/i18n/format.py(192)format()
-> text += info.get(elem, elem)

This likely never bombed before since a lookup of the info dictionary always returned a string.

  • getFormatter (zope/i18n/locales/__init__.py LINE 495)
    There are a number of issues with lookup here:
        formats = getattr(cal, category+'Formats')
        if length is None:
            length = getattr(
                cal,
                'default'+category[0].upper()+category[1:]+'Format',
                formats.keys()[0])

        # 'datetime' is always a bit special; we often do not have a length
        # specification, but we need it for looking up the date and time
        # formatters
        if category == 'dateTime':
            formatLength = formats.get(length, formats[None])

For instance:

length = getattr(cal, 'default'+category[0].upper()+category[1:]+'Format', formats.keys()[0])

Why should this fall back to looking up the format key from the calendar instance?
Also, formats[None] raises an AttributeError

testRegisterAndCompileTranslations fails

======================================================================
FAIL: testRegisterAndCompileTranslations (zope.i18n.tests.test_zcml.DirectivesTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/tmp/nix-build-python2.7-zope.i18n-4.1.0.drv-0/zope.i18n-4.1.0/src/zope/i18n/tests/test_zcml.py", line 153, in testRegisterAndCompileTranslations
    self.assertEqual(msg, _u("I'm a newer file translated"))
AssertionError: u"I'm a newer file" != u"I'm a newer file translated"
- I'm a newer file
+ I'm a newer file translated
?                 +++++++++++
> pip list
extras (0.0.3)
linecache2 (1.0.0)
lxml (3.7.0)
pbr (1.8.1)
pip (9.0.1)
python-mimeparse (0.1.4)
python-subunit (1.1.0)
pytz (2016.6.1)
setuptools (30.2.0)
six (1.10.0)
testscenarios (0.4)
testtools (1.8.0)
traceback2 (1.4.0)
unittest2 (1.1.0)
wheel (0.29.0)
zope.component (4.2.1)
zope.configuration (4.0.3)
zope.event (4.0.3)
zope.exceptions (4.0.8)
zope.i18nmessageid (4.0.3)
zope.interface (4.1.3)
zope.location (4.0.3)
zope.proxy (4.1.6)
zope.schema (4.4.2)
zope.security (4.0.3)
zope.testing (4.6.1)
zope.testrunner (4.4.10)

`parseGetText` can't parse zope.app catalogs (fr and zh_CN)

In https://bugs.launchpad.net/zope.i18n/+bug/356004, Devin ([email protected]) reported:

When I attempt to use GettextImportFilter to parse the gettext translation catalogs in zope.app for fr and zh_CN, I get the following tracebacks (the first is fr, the second is zh_CN):

Traceback (most recent call last):
  File "./generate-pillar-domain.py", line 68, in main
    filter.importMessages(language, fp)
  File "/usr/lib/python2.5/site-packages/zope/app/i18n/filters.py", line 95, in importMessages
    result = parseGetText(file.readlines())[3]
  File "/usr/lib/python2.5/site-packages/zope/app/i18n/filters.py", line 197, in parseGetText
    raise ParseError(3, pointer + 1)
ParseError: state 3, line 4382

Traceback (most recent call last):
  File "./generate-pillar-domain.py", line 68, in main
    filter.importMessages(language, fp)
  File "/usr/lib/python2.5/site-packages/zope/app/i18n/filters.py", line 95, in importMessages
    result = parseGetText(file.readlines())[3]
  File "/usr/lib/python2.5/site-packages/zope/app/i18n/filters.py", line 197, in parseGetText
    raise ParseError(3, pointer + 1)
ParseError: state 3, line 268

Both errors occur when a blank line is found at the beginning of a msgstr portion in a gettext file.

and later:

Just to clarify, when I say "blank line", I mean "quoted empty string".

Support i18n plural forms

In https://bugs.launchpad.net/zope.i18n/+bug/161985, @ccomb reported:

Some languages use the plural form for zero (English, German, Dutch, Italian, Spanish, Portuguese):

This is generated by the ISized adapter of containers :

  • "0 items"
  • "1 item"
  • "2 items"

Regardless of whether this is logical or not to have a plural form for something below 1 :), other languages like French use the plural form only for numbers greater than 1 :

  • "0 élément"
  • "1 élément"
  • "2 élements"

This should be taken into account where applicable (at least on some ISized adapters)

@ctheune follwed up:

zope.i18n does not support plural forms, unfortunately, although it should. The way this is done right now is very hacky.

@strichter:

Could someone do some research on this? What deos it look like and is there a Python implementation for it? I am willing to do the necessary coding, if I get the info I need.

@ccomb:

Actually someone made me realize that "zero" is just a typical plural-form, and it can be handled as such. It should be sufficient to use the plural form fonctionnality of gettext where applicable. The string to translate should just be forked into as many plural forms as necessary, and the translators have to translate all these strings separately.

More details here: http://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html

@tmassman:

I added the plural form support in a separate branch: https://code.launchpad.net/~thomas-massmann/zope.i18n/plural. This code was mainly implemented during the 2012 Plonekonf in Munich.

It is already in "production" in a project I'm developing right now. Please note that zope.i18nmessageid needs to be taken from this branch to work: https://code.launchpad.net/~thomas-massmann/zope.i18nmessageid/plural.

Extracting plural messages is supported by xgettext by default. Zope tools like i18nduder have to be adjusted (they don't support ungettext right now). I already adjusted lingua by Wichert Akkerman (https://github.com/tmassman/lingua) - the pull request is still open.

Update mapping when creating new message ID from existing one

In https://bugs.launchpad.net/zope.i18n/+bug/668189, @icemac reported:

Creating new message IDs from existing message IDs should behave the following way:

police_and_dog = _('${a} + ${b} = ${c}', mapping=dict(a='police', c='police dog'))
police_dog = _(police_and_dog, mapping=dict(b='dog'))

Currently the mapping for police_dog is ignored but I think it should update the mapping of police_and_dog in the new message ID.

Currently you have to do the following to achieve the same:

mapping = police_and_dog.mapping.copy()
mapping.update(dict(b='dog'))
police_dog = _(unicode(police_and_dog), mapping=mapping)

Translating (zope.i18n.translate) should behave the same way.

Regression: zope.i18n 4.3.0 breaks zope.app.testing

Something changed in zope.i18n 4.3.0 that breaks zope.app.testing:

Traceback (most recent call last):
  File "/home/travis/build/mgedmin/zodbbrowser/src/zodbbrowser/ftests/test_standalone.py", line 23, in <module>
    from zope.app.testing import setup
  File "/home/travis/virtualenv/python2.7.14/lib/python2.7/site-packages/zope/app/testing/setup.py", line 59, in <module>
    from zope.app.testing.placelesssetup import setUp as placelessSetUp
  File "/home/travis/virtualenv/python2.7.14/lib/python2.7/site-packages/zope/app/testing/placelesssetup.py", line 32, in <module>
    ContainerPlacelessSetup):
TypeError: Error when calling the metaclass bases
    Cannot create a consistent method resolution
order (MRO) for bases PlacelessSetup, PlacelessSetup, PlacelessSetup, CleanUp

Downgrading zope.i18n to 4.2.0 makes the problem go away.

Fall back to msgfmt(1) when python-gettext is unavailable

According to PyPI, python-gettext was last uploaded in February 2013. It's unclear whether the package is still supported. It doesn't --and isn't likely to-- exist in the Debian archive. But that's fine because its functionality can be reproduced well enough to pass the test suite with a replacement made of subprocess and msgfmt(1). We'll be using something like the following patch in Debian (it's not even worth writing a pull request ;)

--- a/src/zope/i18n/compile.py
+++ b/src/zope/i18n/compile.py
@@ -15,14 +15,17 @@

 def compile_mo_file(domain, lc_messages_path):
     """Creates or updates a mo file in the locales folder."""
-    if not HAS_PYTHON_GETTEXT:
-        logger.critical("Unable to compile messages: Python `gettext` library missing.")
-        return
-
     base = join(lc_messages_path, domain)
     pofile = str(base + '.po')
     mofile = str(base + '.mo')

+    if not HAS_PYTHON_GETTEXT:
+        #logger.critical("Unable to compile messages: Python `gettext` library missing.")
+        # 2015-06-22 [email protected]: Fall back to msgfmt(1).
+        from subprocess import check_call
+        check_call(['msgfmt', '-o', mofile, pofile])
+        return
+
     po_mtime = 0
     try:
         po_mtime = os.stat(pofile)[ST_MTIME]

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.