[Zope3-checkins] SVN: Zope3/trunk/ Merged the hdima-language-namespace branch.

Dmitry Vasiliev dima at hlabs.spb.ru
Wed Oct 26 04:10:39 EDT 2005


Log message for revision 39629:
  Merged the hdima-language-namespace branch.
  
  For details see doc/CHANGES.txt and
  http://www.zope.org/Wikis/DevSite/Projects/ComponentArchitecture/LanguageNamespace
  

Changed:
  U   Zope3/trunk/doc/CHANGES.txt
  U   Zope3/trunk/src/zope/app/i18n/configure.zcml
  U   Zope3/trunk/src/zope/app/publisher/browser/__init__.py
  A   Zope3/trunk/src/zope/app/publisher/browser/tests/test_browserlanguages.py
  U   Zope3/trunk/src/zope/app/traversing/configure.zcml
  U   Zope3/trunk/src/zope/app/traversing/namespace.py
  A   Zope3/trunk/src/zope/app/traversing/tests/test_lang.py
  U   Zope3/trunk/src/zope/i18n/interfaces/__init__.py
  U   Zope3/trunk/src/zope/publisher/browser.py
  U   Zope3/trunk/src/zope/publisher/http.py
  U   Zope3/trunk/src/zope/publisher/interfaces/http.py
  UU  Zope3/trunk/src/zope/publisher/tests/test_browserlanguages.py

-=-
Modified: Zope3/trunk/doc/CHANGES.txt
===================================================================
--- Zope3/trunk/doc/CHANGES.txt	2005-10-26 02:22:47 UTC (rev 39628)
+++ Zope3/trunk/doc/CHANGES.txt	2005-10-26 08:10:38 UTC (rev 39629)
@@ -10,6 +10,16 @@
 
     New features
 
+      - Implemented the language namespace proposal. Now you can override
+        the browser preferred language through the URL, like this:
+
+          http://site.org/++lang++ru/path
+
+        Note: If you want to use a custom IUserPreferredLanguages adapter and
+        the '++lang++' feature together you should use
+        zope.app.publisher.browser.CacheableBrowserLanguages adapter as a base
+        class or at least as example.
+
       - Implemented a new object introspector. Instead of just providing
         information of the object's class, the new introspector focuses on
         providing information that is specific to the instance, such as
@@ -41,11 +51,6 @@
 
       - addMenuItem directive supports a `layer` attribute.
 
-      - Fixed issue 390. Deprecated ``IBaseRequest.body`` and
-        ``IBaseRequest.bodyFile``. The latter was simply renamed to
-        ``IBaseRequest.bodyStream``. No code assumes anymore that the input
-        streams are seekable.
-
       - Formalized the Publisher Response API.
 
         + Until now the publisher made assumptions about the form of ouput of
@@ -122,6 +127,11 @@
 
     Bug Fixes
 
+      - Fixed issue #390: Deprecated ``IBaseRequest.body`` and
+        ``IBaseRequest.bodyFile``. The latter was simply renamed to
+        ``IBaseRequest.bodyStream``. No code assumes anymore that the input
+        streams are seekable.
+
       - Fixed issue #450: ignore python level CookieError and report them
         to the log file.
 
@@ -141,7 +151,7 @@
 
       Stephan Richter, Roger Ineichen, Marius Gedminas, Julien Anguenot, Benji
       York, Gary Poster, Jim Fulton, Michael Kerrin, Torsten Kurbad,
-      Philipp von Weitershausen, Tarek Ziadé, Andreas Jung
+      Philipp von Weitershausen, Tarek Ziadé, Andreas Jung, Dmitry Vasiliev
 
     Note: If you are not listed and contributed, please add yourself. This
           note will be deleted before the release.

Modified: Zope3/trunk/src/zope/app/i18n/configure.zcml
===================================================================
--- Zope3/trunk/src/zope/app/i18n/configure.zcml	2005-10-26 02:22:47 UTC (rev 39628)
+++ Zope3/trunk/src/zope/app/i18n/configure.zcml	2005-10-26 08:10:38 UTC (rev 39629)
@@ -2,40 +2,44 @@
    xmlns="http://namespaces.zope.org/zope">
 
   <!-- Setup language negotiation -->
-  <utility 
+  <utility
       provides="zope.i18n.interfaces.INegotiator"
-      component="zope.i18n.negotiator.negotiator" 
+      component="zope.i18n.negotiator.negotiator"
       />
-  
-  <adapter factory="zope.publisher.browser.BrowserLanguages"
+
+  <adapter factory="zope.app.publisher.browser.ModifiableBrowserLanguages"
       for="zope.publisher.interfaces.http.IHTTPRequest"
-      provides="zope.i18n.interfaces.IUserPreferredLanguages" 
+      provides="zope.i18n.interfaces.IModifiableUserPreferredLanguages"
       />
-  
+
+  <class class="zope.publisher.http.HTTPRequest">
+      <implements interface="zope.app.annotation.IAttributeAnnotatable" />
+  </class>
+
   <!-- Setup charset negotiation -->
   <adapter factory="zope.publisher.http.HTTPCharsets"
       for="zope.publisher.interfaces.http.IHTTPRequest"
-      provides="zope.i18n.interfaces.IUserPreferredCharsets" 
+      provides="zope.i18n.interfaces.IUserPreferredCharsets"
       />
-  
+
   <!-- Register the Translation Domain as a content object -->
   <localUtility class=".translationdomain.TranslationDomain">
     <factory 
-         id="zope.app.i18n.TranslationDomain" 
+         id="zope.app.i18n.TranslationDomain"
          />
-    <allow interface="zope.i18n.interfaces.ITranslationDomain" 
+    <allow interface="zope.i18n.interfaces.ITranslationDomain"
         />
     <require permission="zope.ManageSite"
-        interface="zope.app.container.interfaces.IContainer" 
+        interface="zope.app.container.interfaces.IContainer"
         />
     <require permission="zope.ManageSite"
-        interface=".interfaces.IWriteTranslationDomain" 
+        interface=".interfaces.IWriteTranslationDomain"
         />
     <require permission="zope.ManageSite"
-        interface=".interfaces.ISyncTranslationDomain" 
+        interface=".interfaces.ISyncTranslationDomain"
         />
   </localUtility>
-  
+
   <subscriber
        for=".interfaces.ILocalTranslationDomain
             ..component.interfaces.registration.IRegistrationActivatedEvent"
@@ -46,34 +50,34 @@
        for=".interfaces.ILocalTranslationDomain
             ..component.interfaces.registration.IRegistrationDeactivatedEvent"
        handler=".translationdomain.unsetDomainOnDeactivation"
-       />  
+       />
 
   <!-- Setup Message Catalogs -->
   <content class=".messagecatalog.MessageCatalog">
     <factory id="zope.app.MessageCatalog" />
     <implements 
         interface="zope.app.annotation.interfaces.IAttributeAnnotatable" />
-  
+
     <require permission="zope.View" 
         interface="zope.i18n.interfaces.IMessageCatalog" />
     <require permission="zope.ManageSite"
         attributes="setMessage getMessageIds" />
   </content>
-  
-  
+
+
   <!-- Setup Export and Import Filters -->
   <adapter 
       factory=".filters.GettextExportFilter"
       for=".interfaces.ILocalTranslationDomain"
-      provides="zope.i18n.interfaces.IMessageExportFilter" 
+      provides="zope.i18n.interfaces.IMessageExportFilter"
       />
-  
+
   <adapter 
       factory=".filters.GettextImportFilter"
       for=".interfaces.ILocalTranslationDomain"
-      provides="zope.i18n.interfaces.IMessageImportFilter" 
+      provides="zope.i18n.interfaces.IMessageImportFilter"
       />
-  
+
   <include file="locales.zcml" />
   <include package=".xmlrpc" />
   <include package=".browser" />

Modified: Zope3/trunk/src/zope/app/publisher/browser/__init__.py
===================================================================
--- Zope3/trunk/src/zope/app/publisher/browser/__init__.py	2005-10-26 02:22:47 UTC (rev 39628)
+++ Zope3/trunk/src/zope/app/publisher/browser/__init__.py	2005-10-26 08:10:38 UTC (rev 39629)
@@ -20,11 +20,18 @@
 
 import zope.interface
 from zope.interface import implements, directlyProvidedBy, directlyProvides
+from zope.publisher.browser import BrowserLanguages
+from zope.i18n.interfaces import IUserPreferredLanguages
+from zope.i18n.interfaces import IModifiableUserPreferredLanguages
+
+from zope.app.annotation import IAnnotations
 from zope.app.location import Location
 from zope.app.publisher.interfaces.browser import IBrowserView
 from zope.publisher.interfaces.browser import ISkin
 
 
+key = "zope.app.publisher.browser.IUserPreferredLanguages"
+
 class BrowserView(Location):
     """Browser View.
 
@@ -128,3 +135,45 @@
     # Add the new skin.
     ifaces.append(skin)
     directlyProvides(request, *ifaces)
+
+class NotCompatibleAdapterError(Exception):
+    """Adapter not compatible with
+       zope.i18n.interfaces.IModifiableBrowserLanguages has been used.
+    """
+
+class CacheableBrowserLanguages(BrowserLanguages):
+
+    implements(IUserPreferredLanguages)
+
+    def getPreferredLanguages(self):
+        languages_data = self._getLanguagesData()
+        if "overridden" in languages_data:
+            return languages_data["overridden"]
+        elif "cached" not in languages_data:
+            languages_data["cached"] = super(
+                CacheableBrowserLanguages, self).getPreferredLanguages()
+        return languages_data["cached"]
+
+    def _getLanguagesData(self):
+        annotations = IAnnotations(self.request)
+        languages_data = annotations.get(key)
+        if languages_data is None:
+            annotations[key] = languages_data = {}
+        return languages_data
+
+class ModifiableBrowserLanguages(CacheableBrowserLanguages):
+
+    implements(IModifiableUserPreferredLanguages)
+
+    def setPreferredLanguages(self, languages):
+        annotations = IAnnotations(self.request)
+        languages_data = annotations.get(key)
+        if languages_data is None:
+            # Better way to create a compatible with
+            # IModifiableUserPreferredLanguages adapter is to use
+            # CacheableBrowserLanguages as base class or as example.
+            raise NotCompatibleAdapterError("Adapter not compatible with "
+                "zope.i18n.interfaces.IModifiableBrowserLanguages "
+                "has been used.")
+        languages_data["overridden"] = languages
+        self.request.setupLocale()

Copied: Zope3/trunk/src/zope/app/publisher/browser/tests/test_browserlanguages.py (from rev 39612, Zope3/branches/hdima-language-namespace/src/zope/app/publisher/browser/tests/test_browserlanguages.py)

Modified: Zope3/trunk/src/zope/app/traversing/configure.zcml
===================================================================
--- Zope3/trunk/src/zope/app/traversing/configure.zcml	2005-10-26 02:22:47 UTC (rev 39628)
+++ Zope3/trunk/src/zope/app/traversing/configure.zcml	2005-10-26 08:10:38 UTC (rev 39629)
@@ -1,16 +1,16 @@
 <configure xmlns="http://namespaces.zope.org/zope">
 
-<adapter 
+<adapter
     for="*"
     factory="zope.app.traversing.adapters.Traverser"
     provides="zope.app.traversing.interfaces.ITraverser" />
 
-<adapter 
+<adapter
     for="*"
     factory="zope.app.traversing.adapters.DefaultTraversable"
     provides="zope.app.traversing.interfaces.ITraversable" />
 
-<adapter 
+<adapter
     provides="zope.app.traversing.interfaces.IPhysicallyLocatable"
     for="zope.app.traversing.interfaces.IContainmentRoot"
     factory="zope.app.traversing.adapters.RootPhysicallyLocatable" />
@@ -18,89 +18,100 @@
 <adapter
     name="etc"
     provides="zope.app.traversing.interfaces.ITraversable" for="*"
-    factory="zope.app.traversing.namespace.etc" 
+    factory="zope.app.traversing.namespace.etc"
     />
 <view
     name="etc"
     type="zope.interface.Interface"
     provides="zope.app.traversing.interfaces.ITraversable" for="*"
-    factory="zope.app.traversing.namespace.etc" 
+    factory="zope.app.traversing.namespace.etc"
     />
 
 <adapter
     name="attribute"
     provides="zope.app.traversing.interfaces.ITraversable" for="*"
-    factory="zope.app.traversing.namespace.attr" 
+    factory="zope.app.traversing.namespace.attr"
     />
 <view
     name="attribute"
     type="zope.interface.Interface"
     provides="zope.app.traversing.interfaces.ITraversable" for="*"
-    factory="zope.app.traversing.namespace.attr" 
+    factory="zope.app.traversing.namespace.attr"
     />
 
 <adapter
     name="adapter"
     provides="zope.app.traversing.interfaces.ITraversable" for="*"
-    factory="zope.app.traversing.namespace.adapter" 
+    factory="zope.app.traversing.namespace.adapter"
     />
 <view
     name="adapter"
     type="zope.interface.Interface"
     provides="zope.app.traversing.interfaces.ITraversable" for="*"
-    factory="zope.app.traversing.namespace.adapter" 
+    factory="zope.app.traversing.namespace.adapter"
     />
 
 <adapter
     name="item"
     provides="zope.app.traversing.interfaces.ITraversable" for="*"
-    factory="zope.app.traversing.namespace.item" 
+    factory="zope.app.traversing.namespace.item"
     />
 <view
     name="item" type="*"
     provides="zope.app.traversing.interfaces.ITraversable" for="*"
-    factory="zope.app.traversing.namespace.item" 
+    factory="zope.app.traversing.namespace.item"
     />
 
 <adapter
     name="acquire"
     provides="zope.app.traversing.interfaces.ITraversable" for="*"
-    factory="zope.app.traversing.namespace.acquire" 
+    factory="zope.app.traversing.namespace.acquire"
     />
 <view
     name="acquire" type="*"
     provides="zope.app.traversing.interfaces.ITraversable" for="*"
-    factory="zope.app.traversing.namespace.acquire" 
+    factory="zope.app.traversing.namespace.acquire"
     />
 
 <view
     name="view" type="*"
     provides="zope.app.traversing.interfaces.ITraversable" for="*"
-    factory="zope.app.traversing.namespace.view" 
+    factory="zope.app.traversing.namespace.view"
     />
 
 <view
     name="resource" type="*"
     provides="zope.app.traversing.interfaces.ITraversable" for="*"
-    factory="zope.app.traversing.namespace.resource" 
+    factory="zope.app.traversing.namespace.resource"
     />
 
+<adapter
+    name="lang"
+    provides="zope.app.traversing.interfaces.ITraversable" for="*"
+    factory="zope.app.traversing.namespace.lang"
+    />
 <view
+    name="lang" type="*"
+    provides="zope.app.traversing.interfaces.ITraversable" for="*"
+    factory="zope.app.traversing.namespace.lang"
+    />
+
+<view
     name="skin" type="*"
     provides="zope.app.traversing.interfaces.ITraversable" for="*"
-    factory="zope.app.traversing.namespace.skin" 
+    factory="zope.app.traversing.namespace.skin"
     />
 
 <view
     name="vh" type="*"
     provides="zope.app.traversing.interfaces.ITraversable" for="*"
-    factory="zope.app.traversing.namespace.vh" 
+    factory="zope.app.traversing.namespace.vh"
     />
 
 <view
     name="debug" type="*"
     provides="zope.app.traversing.interfaces.ITraversable" for="*"
-    factory="zope.app.traversing.namespace.debug" 
+    factory="zope.app.traversing.namespace.debug"
     />
 
 </configure>

Modified: Zope3/trunk/src/zope/app/traversing/namespace.py
===================================================================
--- Zope3/trunk/src/zope/app/traversing/namespace.py	2005-10-26 02:22:47 UTC (rev 39628)
+++ Zope3/trunk/src/zope/app/traversing/namespace.py	2005-10-26 08:10:38 UTC (rev 39629)
@@ -20,6 +20,7 @@
 import zope.deprecation
 import zope.component
 import zope.interface
+from zope.i18n.interfaces import IModifiableUserPreferredLanguages
 from zope.component.exceptions import ComponentLookupError
 from zope.interface import providedBy, directlyProvides, directlyProvidedBy
 from zope.publisher.interfaces.browser import ISkin
@@ -36,6 +37,7 @@
 
 import warnings
 
+
 class UnexpectedParameters(TraversalError):
     "Unexpected namespace parameters were provided."
 
@@ -346,8 +348,8 @@
             return method()
         except ComponentLookupError:
             raise TraversalError(ob, name)
-            
 
+
 class view(object):
 
     zope.interface.implements(ITraversable)
@@ -371,6 +373,14 @@
         # resource, which is needed to generate the absolute URL.
         return getResource(self.context, name, self.request)
 
+class lang(view):
+
+    def traverse(self, name, ignored):
+        self.request.shiftNameToApplication()
+        languages = IModifiableUserPreferredLanguages(self.request)
+        languages.setPreferredLanguages([name])
+        return self.context
+
 class skin(view):
 
     def traverse(self, name, ignored):
@@ -588,5 +598,3 @@
             ...
             ValueError: Debug flags only allowed in debug mode
         """
-
-        

Copied: Zope3/trunk/src/zope/app/traversing/tests/test_lang.py (from rev 39612, Zope3/branches/hdima-language-namespace/src/zope/app/traversing/tests/test_lang.py)

Modified: Zope3/trunk/src/zope/i18n/interfaces/__init__.py
===================================================================
--- Zope3/trunk/src/zope/i18n/interfaces/__init__.py	2005-10-26 02:22:47 UTC (rev 39628)
+++ Zope3/trunk/src/zope/i18n/interfaces/__init__.py	2005-10-26 08:10:38 UTC (rev 39629)
@@ -202,7 +202,16 @@
         languages first.
         """
 
+class IModifiableUserPreferredLanguages(IUserPreferredLanguages):
 
+    def setPreferredLanguages(languages):
+        """Set a sequence of user preferred languages.
+
+        The sequence should be sorted in order of quality, with the most
+        preferred languages first.
+        """
+
+
 class IMessageExportFilter(Interface):
     """The Export Filter for Translation Service Messages.
 
@@ -394,5 +403,3 @@
 
     calendar = Attribute("""This object must implement ILocaleCalendar. See
                             this interface's documentation for details.""")
-
-

Modified: Zope3/trunk/src/zope/publisher/browser.py
===================================================================
--- Zope3/trunk/src/zope/publisher/browser.py	2005-10-26 02:22:47 UTC (rev 39628)
+++ Zope3/trunk/src/zope/publisher/browser.py	2005-10-26 08:10:38 UTC (rev 39629)
@@ -202,12 +202,13 @@
     implements(IBrowserRequest, IBrowserApplicationRequest)
 
     __slots__ = (
-        '__provides__',      # Allow request to directly provide interfaces
-        'form',   # Form data
+        '__provides__', # Allow request to directly provide interfaces
+        'form', # Form data
         'charsets', # helper attribute
         '__meth',
         '__tuple_items',
         '__defaults',
+        '__annotations__',
         )
 
     # Set this to True in a subclass to redirect GET requests when the

Modified: Zope3/trunk/src/zope/publisher/http.py
===================================================================
--- Zope3/trunk/src/zope/publisher/http.py	2005-10-26 02:22:47 UTC (rev 39628)
+++ Zope3/trunk/src/zope/publisher/http.py	2005-10-26 08:10:38 UTC (rev 39629)
@@ -266,6 +266,7 @@
         'method',         # The upper-cased request method (REQUEST_METHOD)
         '_locale',        # The locale for the request
         '_vh_root',       # Object at the root of the virtual host
+        '__annotations__',
         )
 
     retry_max_count = 3    # How many times we're willing to retry
@@ -303,9 +304,9 @@
         self.__setupPath()
         self.__setupURLBase()
         self._vh_root = None
-        self.__setupLocale()
+        self.setupLocale()
 
-    def __setupLocale(self):
+    def setupLocale(self):
         envadapter = IUserPreferredLanguages(self, None)
         if envadapter is None:
             self._locale = None

Modified: Zope3/trunk/src/zope/publisher/interfaces/http.py
===================================================================
--- Zope3/trunk/src/zope/publisher/interfaces/http.py	2005-10-26 02:22:47 UTC (rev 39628)
+++ Zope3/trunk/src/zope/publisher/interfaces/http.py	2005-10-26 08:10:38 UTC (rev 39629)
@@ -203,7 +203,12 @@
     locale = Attribute(
         "Return the locale object associated with this request.")
 
+    def setupLocale():
+        """Setup the locale object based on languages returned by
+        IUserPreferredLanguages adapter.
+        """
 
+
 class IHTTPCredentials(Interface):
 
     # TODO: Eventially this will be a different method

Modified: Zope3/trunk/src/zope/publisher/tests/test_browserlanguages.py
===================================================================
--- Zope3/trunk/src/zope/publisher/tests/test_browserlanguages.py	2005-10-26 02:22:47 UTC (rev 39628)
+++ Zope3/trunk/src/zope/publisher/tests/test_browserlanguages.py	2005-10-26 08:10:38 UTC (rev 39629)
@@ -17,6 +17,9 @@
 """
 import unittest
 
+from zope.publisher.browser import BrowserLanguages
+
+
 # Note: The expected output is in order of preference,
 # empty 'q=' means 'q=1', and if theres more than one
 # empty, we assume they are in order of preference.
@@ -29,17 +32,28 @@
     ('ro,en-us;q=0,es;q=0.5,fr;q=0,ru;q=1,it', ['ro', 'ru', 'it', 'es'])
     ]
 
+class TestRequest(dict):
 
+    def __init__(self, languages):
+        self.localized = False
+        self["HTTP_ACCEPT_LANGUAGE"] = languages
+
+    def setupLocale(self):
+        self.localized = True
+
 class BrowserLanguagesTest(unittest.TestCase):
 
+    def factory(self, request):
+        return BrowserLanguages(request)
+
     def test_browser_language_handling(self):
-        from zope.publisher.browser import BrowserLanguages
         for req, expected in data:
-            request = {'HTTP_ACCEPT_LANGUAGE': req}
-            browser_languages = BrowserLanguages(request)
+            request = TestRequest(req)
+            browser_languages = self.factory(request)
             self.assertEqual(list(browser_languages.getPreferredLanguages()),
                              expected)
 
+
 def test_suite():
     loader=unittest.TestLoader()
     return loader.loadTestsFromTestCase(BrowserLanguagesTest)


Property changes on: Zope3/trunk/src/zope/publisher/tests/test_browserlanguages.py
___________________________________________________________________
Name: svn:keywords
   + Id



More information about the Zope3-Checkins mailing list