[Zope3-checkins] CVS: Zope3/src/zope/i18n -
simpletranslationdomain.py:1.1 translationdomain.py:1.1
__init__.py:1.4 gettextmessagecatalog.py:1.12
globaltranslationservice.py:NONE
simpletranslationservice.py:NONE translate.py:NONE
Stephan Richter
srichter at cosmos.phy.tufts.edu
Mon Mar 8 18:36:30 EST 2004
Update of /cvs-repository/Zope3/src/zope/i18n
In directory cvs.zope.org:/tmp/cvs-serv5256/src/zope/i18n
Modified Files:
__init__.py gettextmessagecatalog.py
Added Files:
simpletranslationdomain.py translationdomain.py
Removed Files:
globaltranslationservice.py simpletranslationservice.py
translate.py
Log Message:
Changed to use translation domains versus a translation
service. zope.i18n.__init__ provides a convenience translate() method.
=== Added File Zope3/src/zope/i18n/simpletranslationdomain.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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.
#
##############################################################################
"""This is a simple implementation of the ITranslationDomain interface.
$Id: simpletranslationdomain.py,v 1.1 2004/03/08 23:35:59 srichter Exp $
"""
from zope.interface import implements
from zope.component import getUtility
from zope.i18n.interfaces import ITranslationDomain, INegotiator
from zope.i18n import interpolate
class SimpleTranslationDomain:
"""This is the simplest implementation of the ITranslationDomain I
could come up with.
The constructor takes one optional argument 'messages', which will be
used to do the translation. The 'messages' attribute has to have the
following structure:
{('language', 'msg_id'): 'message', ...}
Note: This Translation Domain does not use message catalogs.
"""
implements(ITranslationDomain)
# See zope.i18n.interfaces.ITranslationDomain
domain = None
def __init__(self, domain, messages=None):
"""Initializes the object. No arguments are needed."""
self.domain = domain
if messages is None:
self.messages = {}
else:
assert isinstance(messages, dict)
self.messages = messages
def translate(self, msgid, mapping=None, context=None,
target_language=None, default=None):
'''See interface ITranslationDomain'''
# Find out what the target language should be
if target_language is None and context is not None:
langs = [m[0] for m in self.messages.keys()]
# Let's negotiate the language to translate to. :)
negotiator = getUtility(self, INegotiator)
target_language = negotiator.getLanguage(langs, context)
# Make a raw translation without interpolation
text = self.messages.get((target_language, msgid))
if text is None:
return default
# Now we need to do the interpolation
return interpolate(text, mapping)
=== Added File Zope3/src/zope/i18n/translationdomain.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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.
#
##############################################################################
"""Global Translation Service for providing I18n to file-based code.
$Id: translationdomain.py,v 1.1 2004/03/08 23:35:59 srichter Exp $
"""
from zope.i18n.negotiator import negotiator
from zope.i18n.simpletranslationdomain import SimpleTranslationDomain
from zope.i18n.messageid import MessageID
from zope.i18n import interpolate
# The configuration should specify a list of fallback languages for the
# site. If a particular catalog for a negotiated language is not available,
# then the zcml specified order should be tried. If that fails, then as a
# last resort the languages in the following list are tried. If these fail
# too, then the msgid is returned.
#
# Note that these fallbacks are used only to find a catalog. If a particular
# message in a catalog is not translated, tough luck, you get the msgid.
LANGUAGE_FALLBACKS = ['en']
class TranslationDomain(SimpleTranslationDomain):
def __init__(self, domain, fallbacks=None):
self.domain = domain
# _catalogs maps (language, domain) to IMessageCatalog instances
self._catalogs = {}
# _data maps IMessageCatalog.getIdentifier() to IMessageCatalog
self._data = {}
# What languages to fallback to, if there is no catalog for the
# requested language (no fallback on individual messages)
if fallbacks is None:
fallbacks = LANGUAGE_FALLBACKS
self._fallbacks = fallbacks
def _registerMessageCatalog(self, language, catalog_name):
key = language
mc = self._catalogs.setdefault(key, [])
mc.append(catalog_name)
def addCatalog(self, catalog):
self._data[catalog.getIdentifier()] = catalog
self._registerMessageCatalog(catalog.language,
catalog.getIdentifier())
def setLanguageFallbacks(self, fallbacks=None):
if fallbacks is None:
fallbacks = LANGUAGE_FALLBACKS
self._fallbacks = fallbacks
def translate(self, msgid, mapping=None, context=None,
target_language=None, default=None):
'''See interface ITranslationService'''
# if the msgid is empty, let's save a lot of calculations and return
# an empty string.
if msgid == u'':
return u''
if target_language is None and context is not None:
# Try to determine target language from context
langs = self._catalogs.keys()
target_language = negotiator.getLanguage(langs, context)
# MessageID attributes override arguments
if isinstance(msgid, MessageID):
if msgid.domain != self.domain:
util = getUtility(None, ITranslationDomain, msgid.domain)
return util.translate(msgid, mapping, context,
target_language, default)
else:
mapping = msgid.mapping
default = msgid.default
# Get the translation. Use the specified fallbacks if this fails
catalog_names = self._catalogs.get(target_language)
if catalog_names is None:
for language in self._fallbacks:
catalog_names = self._catalogs.get(language)
if catalog_names is not None:
break
# Did the fallback fail? Sigh, return None
text = default
if catalog_names:
for name in catalog_names:
catalog = self._data[name]
s = catalog.queryMessage(msgid)
if s is not None:
text = s
break
# Now we need to do the interpolation
if text is not None:
text = interpolate(text, mapping)
return text
def getCatalogsInfo(self):
return self._catalogs
def reloadCatalogs(self, catalogNames):
for catalogName in catalogNames:
self._data[catalogName].reload()
=== Zope3/src/zope/i18n/__init__.py 1.3 => 1.4 ===
--- Zope3/src/zope/i18n/__init__.py:1.3 Tue Mar 25 12:01:52 2003
+++ Zope3/src/zope/i18n/__init__.py Mon Mar 8 18:35:59 2004
@@ -13,8 +13,62 @@
##############################################################################
"""i18n support.
-
$Id$
"""
+import re
+from zope.i18n.messageid import MessageIDFactory, MessageID
+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(location, msgid, domain=None, mapping=None, context=None,
+ target_language=None, default=None):
+
+ # XXX: For some reason, I get a recursive import when placing this import
+ # outside the function. I have no clue how to fix this. SR
+ from zope.component import queryUtility
+
+ if isinstance(msgid, MessageID):
+ domain = msgid.domain
+ default = msgid.default
+ mapping = msgid.mapping
+
+ util = queryUtility(location, ITranslationDomain, name=domain)
+
+ if util is None:
+ return interpolate(default, mapping)
+
+ return util.translate(msgid, mapping, context, target_language, default)
+
+
+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
+
-from zope.i18n.messageid import MessageIDFactory
+
=== Zope3/src/zope/i18n/gettextmessagecatalog.py 1.11 => 1.12 ===
--- Zope3/src/zope/i18n/gettextmessagecatalog.py:1.11 Tue Nov 25 19:25:26 2003
+++ Zope3/src/zope/i18n/gettextmessagecatalog.py Mon Mar 8 18:35:59 2004
@@ -33,8 +33,8 @@
def __init__(self, language, domain, path_to_file):
"""Initialize the message catalog"""
- self._language = language
- self._domain = domain
+ self.language = language
+ self.domain = domain
self._path_to_file = path_to_file
self.reload()
self._catalog.add_fallback(_KeyErrorRaisingFallback())
@@ -57,14 +57,6 @@
return self._catalog.ugettext(id)
except KeyError:
return default
-
- def getLanguage(self):
- 'See IMessageCatalog'
- return self._language
-
- def getDomain(self):
- 'See IMessageCatalog'
- return self._domain
def getIdentifier(self):
'See IMessageCatalog'
=== Removed File Zope3/src/zope/i18n/globaltranslationservice.py ===
=== Removed File Zope3/src/zope/i18n/simpletranslationservice.py ===
=== Removed File Zope3/src/zope/i18n/translate.py ===
More information about the Zope3-Checkins
mailing list