[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