[Zope-Checkins] CVS: Zope3/lib/python/Zope/I18n - Domain.py:1.1.2.1 IDomain.py:1.1.2.1 MessageCatalog.py:1.1.2.1 Translate.py:1.1.2.1 TranslationService.py:1.1.2.1 IMessageCatalog.py:1.1.2.9 INegotiator.py:1.1.2.4 ITranslationService.py:1.1.2.5 Negotiator.py:1.1.2.6 i18n.zcml:1.1.2.2 IInterpolationVariable.py:NONE

Stephan Richter srichter@cbu.edu
Wed, 5 Jun 2002 14:48:51 -0400


Update of /cvs-repository/Zope3/lib/python/Zope/I18n
In directory cvs.zope.org:/tmp/cvs-serv4962

Modified Files:
      Tag: Zope-3x-branch
	IMessageCatalog.py INegotiator.py ITranslationService.py 
	Negotiator.py i18n.zcml 
Added Files:
      Tag: Zope-3x-branch
	Domain.py IDomain.py MessageCatalog.py Translate.py 
	TranslationService.py 
Removed Files:
      Tag: Zope-3x-branch
	IInterpolationVariable.py 
Log Message:
First couple things for I18n. More coming soon. Not much is working, but
Fred and Barry would like to have the luxury to look at code. I will write
the real checkin message when it is done and working.


=== Added File Zope3/lib/python/Zope/I18n/Domain.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.
# 
##############################################################################
"""

$Id: Domain.py,v 1.1.2.1 2002/06/05 18:48:50 srichter Exp $
"""




=== Added File Zope3/lib/python/Zope/I18n/IDomain.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.
# 
##############################################################################
"""

$Id: IDomain.py,v 1.1.2.1 2002/06/05 18:48:50 srichter Exp $
"""

from Interface import Interface

class IDomain(Interface):
    """Since it is often tedious to always specify a domain and place for a
       particular translation, the idea of a Domain object was created, which
       allows to save the place and domain for a set of translations.

       Usage:

       domain = Domain(self, 'MyProduct')
       domain.translate('MyProductTitle', context)

       Constructor Arguments:

         place -- A location where the Domain should look for the translation
                  service.

         domain -- Secifies the domain to look up for the translation. See
                   ITranslationService for more details on domains."""


    def translate(source, mapping=None, context=None, target_language=None):
        """Translate the the source to its appropriate language. See
           ITranslationService for details."""


=== Added File Zope3/lib/python/Zope/I18n/MessageCatalog.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.
# 
##############################################################################
"""A simple implementation of a Message Catalog. 

$Id: MessageCatalog.py,v 1.1.2.1 2002/06/05 18:48:50 srichter Exp $
"""

from Zope.I18n.IMessageCatalog import IMessageCatalog


class MessageCatalog:

    __implements__ =  IMessageCatalog


    def __init__(self, language, domain="global"):
        """Initialize the message catalog"""
        self._language = language
        self._domain = domain
        self._messages = {}
    

    def setMessage(self, id, message):
        """Set a message to the catalog."""
        self._messages[id] = message
        

    ############################################################
    # Implementation methods for interface
    # Zope.I18n.IMessageCatalog.

    def getMessage(self, id):
        'See Zope.I18n.IMessageCatalog.IMessageCatalog'
        return self._messages[id]

    def queryMessage(self, id, default=None):
        'See Zope.I18n.IMessageCatalog.IMessageCatalog'
        if default is None:
            default = id
        return self._messages.get(id, default)

    def getLanguage(self):
        'See Zope.I18n.IMessageCatalog.IMessageCatalog'
        return self._language
        
    def getDomain(self):
        'See Zope.I18n.IMessageCatalog.IMessageCatalog'
        return self._domain

    def getIdentifier(self):
        'See Zope.I18n.IMessageCatalog.IMessageCatalog'
        return (self._language, self._domain)
        
    #
    ############################################################


=== Added File Zope3/lib/python/Zope/I18n/Translate.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.
# 
##############################################################################
"""

$Id: Translate.py,v 1.1.2.1 2002/06/05 18:48:50 srichter Exp $
"""


def translate(place, domain, source, mapping=None, context=None,
              target_language=None):
    """Translates a source text based on a location in the Zope architecture
       and a domain."""

    # Lookup service...
    service = None

    return service.translate(domain, source, mapping, context,
                             target_language):


=== Added File Zope3/lib/python/Zope/I18n/TranslationService.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.
# 
##############################################################################
"""

$Id: TranslationService.py,v 1.1.2.1 2002/06/05 18:48:50 srichter Exp $
"""
import re
from types import StringTypes, TupleType

import Persistence
from Persistence.BTrees.OOBTree import OOBTree

from Zope.App.OFS.Container.BTreeContainer import BTreeContainer

from IMessageCatalog import IMessageCatalog
from ITranslationService import ITranslationService
from Zope.App.OFS.Container.IContainer import IContainer


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}))


class ILocalTranslationService(ITranslationService, IContainer):
    """TTW manageable translation service"""


class TranslationService(BTreeContainer):
    ''' '''

    __implements__ =  ILocalTranslationService


    def __init__(self, default_domain='global'):
        ''' '''
        self.__data = OOBTree()
        self._catalogs = OOBTree()


    def _registerMessageCatalog(self, language, domain, catalog_name):
        ''' '''
        if (language, domain) not in self._catalogs.keys():
            self._catalogs[(language, domain)] = []

        mc = self._catalogs[(language, domain)]
        mc.append(catalog_name)


    def _unregisterMessageCatalog(self, language, domain, catalog_name):
        ''' '''
        mc = self._catalogs.get((language, domain), [])
        mc.append(catalog_name)


    ############################################################
    # Implementation methods for interface
    # Zope.App.OFS.Container.IContainer.IWriteContainer

    def setObject(self, name, object):
        'See Zope.App.OFS.Container.IContainer.IWriteContainer'
        if type(name) in StringTypes and len(name)==0:
            raise ValueError
        if not self.isAddable(getattr(object,'__implements__', None)):
            raise UnaddableError (self, object, name)
        self.__data[name] = object
        self._registerMessageCatalog(object.getLanguage(), object.getDomain(),
                                     name)

    def delObject(self, name):
        'See Zope.App.OFS.Container.IContainer.IWriteContainer'
        del self.__data[name]
        self._unregisterMessageCatalog(object.language, object.domain, name)
        

    def isAddable(self, interfaces):
        'See Zope.App.OFS.Container.IContainer.IWriteContainer'
        if type(interfaces) != TupleType:
            interfaces = (interfaces,)
        if IMessageCatalog in interfaces:
            return 1
        return 0

    #
    ############################################################


    ############################################################
    # Implementation methods for interface
    # Zope.I18n.ITranslationService.

    def translate(self, domain, source, mapping=None, context=None,  
                  target_language=None):
        '''See interface ITranslationService'''

        if domain is None:
            domain = self.default_domain

        if target_language is None:
            if context is None:
                raise TypeError, 'No destination language'
            else:
                target_language = context['language']

        # Get the translation. Default is the source text itself.
        text = self.__data.get((target_language, domain), {}
                               ).get(source, source)

        # Now we need to do the interpolation
        return self.interpolate(text, mapping)

    #
    ############################################################


    def interpolate(self, text, mapping):
        """Insert the data passed from mapping into the text"""

        to_replace = _interp_regex.findall(text)

        for string in to_replace:
            var = _get_var_regex.findall(string)[0]
            text = text.replace(string, mapping.get(var))

        return text


=== Zope3/lib/python/Zope/I18n/IMessageCatalog.py 1.1.2.8 => 1.1.2.9 ===
     """Translation Service
 
-    This interface provides a method for translating text, including
-    text with interpolation.
+    This interface provides a method for translating a message or message id,
+    including text with interpolation. The message catalog basically serves as
+    a fairly simple mapping object.
 
-    When we refer to text here, we mean text that follows the standard
-    Zope 3 text representation (tbd).
-    """
-
-    def translateSequence(source_sequence, object, context=None,
-                          destination_language_tag=None):
-        """Translate a source sequence that represents text with interpolation
-
-        The source sequence is translated for an object, which
-        provides a place setting language negotiation policies, and a
-        context, which represents a client, such as a web browser,
-        with which there are language preferences.
+    A single Message Catalog represents a particular language and
+    domain. Therefore you will have the following constructor arguments:
 
-        The source sequence is a sequence of text and IVariable
-        object. The IVariable objects define interpolation names for
-        data to be interpolated during or after translation.
+    language -- The language of the returning language. This is a read-only
+                attribute.
 
-        Optional arguments:
+    domain -- The translation domain for this messages. This is a read-only
+              attribute. See ITranslationService.
 
-        destination_language_tag -- The language tag of the langauge
-                                    to translate to.
-
-        context -- An object that provides contextual information for
-                   determining client language preferences. It must
-                   implement or have an adapter that implements
-                   IUserPreferedLanguages.
-
-        Note that one of destination_language or context must be
-        passed. Otherwise a TypeError will be raised.
-
-        Also note that languages tags are defined by RFC 1766.
+    When we refer to text here, we mean text that follows the standard
+    Zope 3 text representation.
+    """
 
-        A sequence is returned including translated text and IVariable
-        objects. 
+    def getMessage(id):
+        """Return the appropriate text for the given id. As all get methods,
+           this will raise an error, if the id is not found
         """
 
+    def queryMessage(id, default=None):
+        """Return the appropriate test for the given id, but if the id is not
+           found, it should not raise an error, instead returning default. If
+           default is None, then the id itself is returned.
+        """
+        
+    def getLanguage():
+        """Return the langauge this message catalog is representing.
+        """
+        
+    def getDomain():
+        """Return the domain this message catalog is serving.
+        """
 
-
-
-
+    def getIdentifier():
+        """Return a identifier for this message catalog. Note that this
+           identifier does not have to be unique as several message catalog
+           could serve the same domain and language.
+        """


=== Zope3/lib/python/Zope/I18n/INegotiator.py 1.1.2.3 => 1.1.2.4 ===
     """
   
-    def getLanguage(user_languages,  env):
-
+    def getLanguage(object_langs,  env):
         """getLanguage implements a decision making algorithm to decide
            what language should be used based on the available languages
            for an object and a list of user prefered languages.
 
         Arguments:
 
-        user_languages -- sequence of languages (not necessarily ordered)
+        object_langs -- sequence of languages (not necessarily ordered)
 
         env  -- environment passed to the service to determine a sequence
                 of user prefered languages


=== Zope3/lib/python/Zope/I18n/ITranslationService.py 1.1.2.4 => 1.1.2.5 ===
 
     When we refer to text here, we mean text that follows the standard
-    Zope 3 text representation (tbd).
+    Zope 3 text representation.
 
     Standard arguments:
 
-        destination_language_tag -- The language tag of the langauge
-                                    to translate to.
+        domain -- The domain is used to specify which translation to use.
+                  Different products will often use a specific domain naming
+                  translations supplied with the product.
+                  Stephan's (my) favorite example is: How do you translate
+                  "Sun"? Is it our star, the abbreviation of Sunday or the
+                  company? Specifying the domain, such as "Stars" will solve
+                  this problem for us.
+
+        source -- The source message or message id that should be translated.
+
+        mapping -- The object to get the interpolation data from.
+
+        target_language -- The language to translate to.
 
         context -- An object that provides contextual information for
                    determining client language preferences. It must
@@ -41,38 +52,26 @@
         Note that one of destination_language or context must be
         passed. Otherwise a TypeError will be raised.
 
-        Also note that languages tags are defined by RFC 1766.
-
-        domain -- The domain is used to specify which translation to use.
-                  Different products will often use a specific domain naming
-                  translations supplied with the product.
+        Also note that language tags are defined by RFC 1766.
     """
 
-    def translateSequence(source_sequence, domain,
-                          context=None,
-                          destination_language_tag=None,
-                          data=None):
-        """Translate a source sequence that represents text with interpolation
-
-        The source sequence is a sequence of text and IVariable
-        object. The IVariable objects define interpolation names for
-        data to be interpolated during or after translation.
-
-        A data mapping may be passed with keys for the values to be
-        interpolated. Extra keys are ignored. If any interpolation
-        names defined in the message don't have a key in the data
-        dictionary, then IVariable objects will be included in the
-        output for those names.
-
-        A sequence is returned including translated text and IVariable
-        objects for any interpolated names not supplied in the data
-        mapping. 
+
+    def translate(domain, source, mapping=None, 
+                  context=None, target_language=None):
+        """Translate source text. Translated text is returned.
+
+           However, the method does a little more than a vanilla
+           translation. The method also looks for a possible language to
+           translate to.
+           After a translation it also replaces any variables inside the 
+           
+           Note: The TranslationService interface does not support simplified
+                 translation methods, since it is totally hidden by ZPT and in
+                 Python you should use a Domain object, since it supports all
+                 the simplifications.
         """
 
-    def translate(source_text, domain,
-                  context=None,
-                  destination_language_tag=None):
-        """Translate source text
 
-        Translated text is returned.
-        """
+    def getDomain(domain):
+        """Get the domain for the passed domain name"""
+        


=== Zope3/lib/python/Zope/I18n/Negotiator.py 1.1.2.5 => 1.1.2.6 ===


=== Zope3/lib/python/Zope/I18n/i18n.zcml 1.1.2.1 => 1.1.2.2 ===
    xmlns:zmi='http://namespaces.zope.org/zmi'
    xmlns:browser='http://namespaces.zope.org/browser'
+   xmlns:service='http://namespaces.zope.org/service'
 >
 
   <serviceType name="LanguageNegotiation" 
@@ -16,5 +17,30 @@
          provides="Zope.I18n.IUserPreferedLanguages"
          />
 -->
+
+
+<security:protectClass class=".TranslationService.">
+   <security:protect interface="Zope.I18n.ITranslationService." 
+                     permission_id="Zope.I18n" />
+   <security:protect interface="Zope.App.OFS.Container.IContainer." 
+                     permission_id="Zope.ManageServices" />
+</security:protectClass>
+
+<security:protectClass class=".MessageCatalog.">
+   <security:protect interface="Zope.App.Security.IMessageCatalog." 
+                     permission_id="Zope.Security" />
+</security:protectClass>
+
+
+<service:factoryFromClass name="TranslationService"
+                          class=".TranslationService."
+                          permission_id="Zope.ManageServices"
+                          title="Translation Service" />
+
+<factory component=".MessageCatalog." />
+
+<include package=".Views" file="views.zcml" />
+
+
 
 </zopeConfigure>

=== Removed File Zope3/lib/python/Zope/I18n/IInterpolationVariable.py ===