diff options
author | Dominik Huber <dominik.huber@ideell.ch> | 2005-05-02 07:44:19 +0000 |
---|---|---|
committer | Dominik Huber <dominik.huber@ideell.ch> | 2005-05-02 07:44:19 +0000 |
commit | c8817ab5055e929cf750ff28310b93d44fde8537 (patch) | |
tree | ba3769538742671218ea9d4218a4d3786237a4ba | |
download | zope-i18n-monolithic-zope3-dominik-locatableadapters.tar.gz |
merge trunk into branch (from 29979 to 30223)monolithic-zope3-dominik-locatableadapters
-rw-r--r-- | DEPENDENCIES.cfg | 5 | ||||
-rw-r--r-- | __init__.py | 81 | ||||
-rw-r--r-- | i18nobject.txt | 74 | ||||
-rw-r--r-- | locales/tests/test_xmlfactory.py | 65 | ||||
-rw-r--r-- | messageid.py | 16 |
5 files changed, 241 insertions, 0 deletions
diff --git a/DEPENDENCIES.cfg b/DEPENDENCIES.cfg new file mode 100644 index 0000000..c77f15b --- /dev/null +++ b/DEPENDENCIES.cfg @@ -0,0 +1,5 @@ +pytz +zope.component +zope.interface +zope.schema +zope.testing diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..1b0d330 --- /dev/null +++ b/__init__.py @@ -0,0 +1,81 @@ +############################################################################## +# +# Copyright (c) 2003 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +"""i18n support. + +$Id$ +""" +import re +import warnings +from zope.component import queryUtility +from zope.i18nmessageid import MessageIDFactory, MessageID +from zope.i18nmessageid import MessageFactory, Message +from zope.i18n.interfaces import ITranslationDomain + +# Set up regular expressions for finding interpolation variables in text. +# NAME_RE must exactly match the expression of the same name in the +# zope.tal.taldefs module: +NAME_RE = r"[a-zA-Z][-a-zA-Z0-9_]*" + +_interp_regex = re.compile(r'(?<!\$)(\$(?:%(n)s|{%(n)s}))' %({'n': NAME_RE})) +_get_var_regex = re.compile(r'%(n)s' %({'n': NAME_RE})) + + +def _translate(msgid, domain=None, mapping=None, context=None, + target_language=None, default=None): + + if isinstance(msgid, (MessageID, Message)): + domain = msgid.domain + default = msgid.default + if default is None: + default = msgid + mapping = msgid.mapping + + util = queryUtility(ITranslationDomain, domain) + + if util is None: + return interpolate(default, mapping) + + return util.translate(msgid, mapping, context, target_language, default) + +# BBB Backward compat +def translate(*args, **kw): + if args and not isinstance(args[0], basestring): + warnings.warn( + "translate no longer takes a location argument. " + "The argument was ignored.", + DeprecationWarning, 2) + args = args[1:] + return _translate(*args, **kw) + +def interpolate(text, mapping): + """Insert the data passed from mapping into the text""" + + # If no translation was found, there is nothing to do. + if text is None: + return None + + # If the mapping does not exist, make a "raw translation" without + # interpolation. + if mapping is None: + return text + + # Find all the spots we want to substitute + to_replace = _interp_regex.findall(text) + + # Now substitute with the variables in mapping + for string in to_replace: + var = _get_var_regex.findall(string)[0] + text = text.replace(string, unicode(mapping.get(var))) + + return text diff --git a/i18nobject.txt b/i18nobject.txt new file mode 100644 index 0000000..3ccf15e --- /dev/null +++ b/i18nobject.txt @@ -0,0 +1,74 @@ +============ +I18n Objects +============ + +The Problem +----------- + +I18n objects are used to internationalize content that cannot be +translated via messages. The problem is three fold: + +- Internationalize an object iteself. The best example is an Image. + Often people put text into an image that needs to be localized, but + since it is a picture the text cannot be retrieved as a string. You + therefore will need a mechanism to create a different version of the + object for every language. (Note: This behavior is the same as + currently implemented in the ZBabelObject.) + +- Internationalize fractions of the content. Let's say for example you + wanted to internationalize the DublinCore information of your + content object. In order for this to work out you need to have an + I18n-supportive `AttributeAnnotation`. Solving this use case would + be similar to some of the work David Juan did with + `InternationalizedContent` in Localizer. + +- Formatting Objects. This problem involves converting basic or + complex types into a localized format. Good examples for this are + decimal numbers and date/time objects. In this case you would like + to specify a format via a templating expression and then pass the + object to the formatter to apply the parsed template. Initial steps + for implementing the template parser have been already taken, + therefore we only need to develop some interfaces and unittests + here, so the parser developer (which will use the ICU C/C++ + libraries) will (choose?) what parts of the parser to wrap for + Python. + +The first two problems are very similar and can actually share the +same interface for the language negotiation and redirection of the +content request. I would therefore propose to have a `II18nContent` +interface that somehow specifies how to get to the translated content +and then redirect the call to the correct local content. + + +`I18nObject` +------------ + +There will be an interface called II18nObject (which inherits I18nContent +of course), which is a chameleon-like container, as it adapts to the +properties of the contained object type. In order to accomplish all this, +you will have to implement your own traverser which looks up the correct +subobject. + + +`I18nAttributeAnnotation` +------------------------- + +This object will basically provide an internationalized version of +zope.app.annotation.attribute.AttributeAnnotations, which will be +accomplished in a similar manner as the `I18nObject`. + + +Open Issues +----------- + +One issue left to solve is how to know the language when we need to +make the decision. These objects are **not** Views, therefore they do +not know about the request variable. + +One way to solve the issue would be that `I18nAttributeAnnotation`, +for example, would not actually implement the `IAnnotations` +interface, but that there would be an Adapter converting the +`II18nAnnotations` to `IAnnotations`. Since adapters are short-lived +(meaning they are initialized for a particular call), we can safely +store some language information in them in order to make the language +decision. diff --git a/locales/tests/test_xmlfactory.py b/locales/tests/test_xmlfactory.py new file mode 100644 index 0000000..3f7e114 --- /dev/null +++ b/locales/tests/test_xmlfactory.py @@ -0,0 +1,65 @@ +############################################################################## +# +# Copyright (c) 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTLAR PURPOSE. +# +############################################################################## +"""Testing all XML Locale functionality. + +$Id$ +""" +import os +from unittest import TestCase, TestSuite, makeSuite + +from zope.i18n.locales.xmlfactory import LocaleFactory +from zope.i18n.format import parseDateTimePattern, parseNumberPattern +import zope.i18n + +class LocaleXMLFileTestCase(TestCase): + """This test verifies that every locale XML file can be loaded.""" + + # only run when running tests of level 2 + level = 2 + + def __init__(self, path): + self.__path = path + TestCase.__init__(self) + + def runTest(self): + # Loading Locale object + locale = LocaleFactory(self.__path)() + + # Making sure all number format patterns parse + for category in (u'decimal', u'scientific', u'percent', u'currency'): + for length in getattr(locale.numbers, category+'Formats').values(): + for format in length.formats.values(): + self.assert_(parseNumberPattern(format.pattern) is not None) + + # Making sure all datetime patterns parse + for calendar in locale.dates.calendars.values(): + for category in ('date', 'time', 'dateTime'): + for length in getattr(calendar, category+'Formats').values(): + for format in length.formats.values(): + self.assert_( + parseDateTimePattern(format.pattern) is not None) + + + +def test_suite(): + suite = TestSuite() + locale_dir = os.path.join(os.path.dirname(zope.i18n.__file__), + 'locales', 'data') + for path in os.listdir(locale_dir): + if not path.endswith(".xml"): + continue + path = os.path.join(locale_dir, path) + case = LocaleXMLFileTestCase(path) + suite.addTest(case) + return suite diff --git a/messageid.py b/messageid.py new file mode 100644 index 0000000..3869cfd --- /dev/null +++ b/messageid.py @@ -0,0 +1,16 @@ +############################################################################## +# +# Copyright (c) 2004 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +"$Id$" +from zope.i18nmessageid import MessageID, MessageIDFactory +from zope.i18nmessageid import Message, MessageFactory |