[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