[Zope-Checkins] CVS: Zope3/lib/python/Zope/I18n - Domain.py:1.2 IDomain.py:1.2 ILanguageAvailability.py:1.2 IMessageCatalog.py:1.2 INegotiator.py:1.2 ITranslationService.py:1.2 IUserPreferedLanguages.py:1.2 MessageCatalog.py:1.2 Negotiator.py:1.2 Translate.py:1.2 TranslationService.py:1.2 __init__.py:1.2 i18n.zcml:1.2
Jim Fulton
jim@zope.com
Mon, 10 Jun 2002 19:29:59 -0400
Update of /cvs-repository/Zope3/lib/python/Zope/I18n
In directory cvs.zope.org:/tmp/cvs-serv20468/lib/python/Zope/I18n
Added Files:
Domain.py IDomain.py ILanguageAvailability.py
IMessageCatalog.py INegotiator.py ITranslationService.py
IUserPreferedLanguages.py MessageCatalog.py Negotiator.py
Translate.py TranslationService.py __init__.py i18n.zcml
Log Message:
Merged Zope-3x-branch into newly forked Zope3 CVS Tree.
=== Zope3/lib/python/Zope/I18n/Domain.py 1.1 => 1.2 ===
+#
+# 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$
+"""
+
+from Zope.I18n.IDomain import IDomain
+
+class Domain:
+
+ __implements__ = IDomain
+
+ def __init__(self, place, domain):
+ self._place = place
+ self.domain = domain
+
+
+ def getPlace(self):
+ """Return the place this domain was created for."""
+ return self._place
+
+
+ def getDomainName(self):
+ """Return the domain name"""
+ return self._domain
+
+
+ ############################################################
+ # Implementation methods for interface
+ # IDomain.py
+
+ def translate(self, source, mapping=None, context=None,
+ target_language=None):
+ 'See Zope.I18n.IDomain.IDomain'
+
+ # lookup the correct translation service
+ service_manager = getServiceManager(self.place)
+ service = service_manager.getBoundService('Translation Service')
+
+ return service.translate(self.domain, source, mapping, context,
+ target_language)
+
+ #
+ ############################################################
=== Zope3/lib/python/Zope/I18n/IDomain.py 1.1 => 1.2 ===
+#
+# 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$
+"""
+
+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(msgid, mapping=None, context=None, target_language=None):
+ """Translate the the source to its appropriate language.
+
+ See ITranslationService for details.
+ """
=== Zope3/lib/python/Zope/I18n/ILanguageAvailability.py 1.1 => 1.2 ===
+#
+# 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$
+"""
+
+from Interface import Interface
+
+class ILanguageAvailability(Interface):
+
+ def availableLanguages():
+ """Return a sequence of language tags for available languages
+ """
+
+
=== Zope3/lib/python/Zope/I18n/IMessageCatalog.py 1.1 => 1.2 ===
+#
+# 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$
+"""
+
+from Interface import Interface
+
+
+class IMessageCatalog(Interface):
+ """Translation Service
+
+ 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.
+
+ A single Message Catalog represents a particular language and
+ domain. Therefore you will have the following constructor arguments:
+
+ language -- The language of the returning language. This is a read-only
+ attribute.
+
+ domain -- The translation domain for this messages. This is a read-only
+ attribute. See ITranslationService.
+
+ When we refer to text here, we mean text that follows the standard
+ Zope 3 text representation.
+ """
+
+ 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 => 1.2 ===
+#
+# 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$
+"""
+
+from Interface import Interface
+
+class INegotiator(Interface):
+
+ """ The INegotiater defines an interface for a service for language
+ negotiation
+ """
+
+ 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:
+
+ 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 => 1.2 ===
+#
+# 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$
+"""
+
+from Interface import Interface
+
+
+class ITranslationService(Interface):
+ """Translation Service
+
+ This interface provides methods for translating text, including
+ text with interpolation.
+
+ When we refer to text here, we mean text that follows the standard
+ Zope 3 text representation.
+
+ Standard arguments:
+
+ 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
+ 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 language tags are defined by RFC 1766.
+ """
+
+
+ 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 getDomain(domain):
+ """Get the domain for the passed domain name"""
+
=== Zope3/lib/python/Zope/I18n/IUserPreferedLanguages.py 1.1 => 1.2 ===
+#
+# 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$
+"""
+
+from Interface import Interface
+
+class IUserPreferedLanguages(Interface):
+
+ """ This interfaces allows to obtain language negotiation dependant
+ informations about user prefered languages.
+ """
+
+ def getLanguages():
+
+ """getLanguages returns a sequence of user prefered languages
+
+ Arguments:
+
+ None
+
+ """
+
=== Zope3/lib/python/Zope/I18n/MessageCatalog.py 1.1 => 1.2 ===
+#
+# 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$
+"""
+
+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)
+
+ #
+ ############################################################
=== Zope3/lib/python/Zope/I18n/Negotiator.py 1.1 => 1.2 ===
+#
+# 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$
+"""
+
+from Zope.I18n.INegotiator import INegotiator
+from Zope.I18n.IUserPreferedLanguages import IUserPreferedLanguages
+from Zope.ComponentArchitecture import getAdapter
+
+class Negotiator:
+
+ __implements__ = INegotiator
+
+ def getLanguage(self, object_langs, env):
+
+ adapter = getAdapter(env, IUserPreferedLanguages)
+ user_langs = adapter.getLanguages()
+
+ for lang in user_langs:
+ if lang in object_langs:
+ return lang
+
+ return None
+
+
+negotiator = Negotiator()
=== Zope3/lib/python/Zope/I18n/Translate.py 1.1 => 1.2 ===
+#
+# 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$
+"""
+
+
+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):
=== Zope3/lib/python/Zope/I18n/TranslationService.py 1.1 => 1.2 ===
+#
+# 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$
+"""
+import re
+from types import StringTypes, TupleType
+
+import Persistence
+from Persistence.BTrees.OOBTree import OOBTree
+
+from Zope.App.OFS.Container.BTreeContainer import BTreeContainer
+from Zope.App.OFS.Container.IContainer import IContainer
+from Zope.App.OFS.Container.IContainer import IHomogenousContainer
+
+from Negotiator import negotiator
+from IMessageCatalog import IMessageCatalog
+from ITranslationService import ITranslationService
+
+
+# Setting up some regular expressions for finding interpolation variables in
+# the text.
+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, IHomogenousContainer):
+ """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)
+ return name
+
+ def __delitem__(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:
+ avail_langs = self.getAvailableLanguages(domain)
+ target_language = negotiator.getLanguage(avail_langs, context)
+
+ # Get the translation. Default is the source text itself.
+ catalog_names = self._catalogs.get((target_language, domain), {})
+
+ text = source
+ for name in catalog_names:
+ catalog = self.__data[name]
+ try:
+ text = catalog.getMessage(source)
+ break
+ except:
+ pass
+
+ # 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
+
+
+ def getAvailableLanguages(self, domain):
+ """Find all the languages that are available for this domain"""
+ identifiers = self._catalogs.keys()
+ identifiers = filter(lambda x, d=domain: x[1] == domain, identifiers)
+ languages = map(lambda x: x[0], identifiers)
+ return languages
=== Zope3/lib/python/Zope/I18n/__init__.py 1.1 => 1.2 ===
+#
+# 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.
+#
+##############################################################################
=== Zope3/lib/python/Zope/I18n/i18n.zcml 1.1 => 1.2 ===
+ xmlns='http://namespaces.zope.org/zope'
+ xmlns:security='http://namespaces.zope.org/security'
+ xmlns:zmi='http://namespaces.zope.org/zmi'
+ xmlns:browser='http://namespaces.zope.org/browser'
+ xmlns:service='http://namespaces.zope.org/service'
+>
+
+ <serviceType
+ id="LanguageNegotiation"
+ interface=".INegotiator." />
+ <service
+ serviceType="LanguageNegotiation"
+ component=".Negotiator.negotiator" />
+
+<!-- Language negotiation adapter
+<adapter factory="Zope.Publisher.Browser.BrowserLanguages."
+ for="Zope.Publisher.Browser.IHTTPRequest."
+ provides="Zope.I18n.IUserPreferedLanguages"
+ />
+-->
+
+<content class=".TranslationService.">
+ <security:require permission="Zope.I18n"
+ interface="Zope.I18n.ITranslationService."
+ />
+ <security:require permission="Zope.ManageServices"
+ interface="Zope.App.OFS.Container.IContainer."
+ />
+</content>
+
+<content class=".MessageCatalog.">
+ <security:require permission="Zope.Security"
+ interface=".IMessageCatalog."
+ />
+
+</content>
+
+ <service:factoryFromClass id="TranslationService"
+ class=".MessageCatalog."
+ permission="Zope.ManageServices"
+ title="Translation Service" />
+
+<!--factory component=".MessageCatalog." /-->
+
+<!--include package=".Views" file="views.zcml" /-->
+
+
+
+</zopeConfigure>