summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDominik Huber <dominik.huber@ideell.ch>2005-05-02 07:44:19 +0000
committerDominik Huber <dominik.huber@ideell.ch>2005-05-02 07:44:19 +0000
commitc8817ab5055e929cf750ff28310b93d44fde8537 (patch)
treeba3769538742671218ea9d4218a4d3786237a4ba
downloadzope-i18n-monolithic-zope3-dominik-locatableadapters.tar.gz
merge trunk into branch (from 29979 to 30223)monolithic-zope3-dominik-locatableadapters
-rw-r--r--DEPENDENCIES.cfg5
-rw-r--r--__init__.py81
-rw-r--r--i18nobject.txt74
-rw-r--r--locales/tests/test_xmlfactory.py65
-rw-r--r--messageid.py16
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