[Zope3-checkins]
SVN: Zope3/branches/hdima-language-namespace/src/zope/
Added IModifiableUserPreferredLanguages adapter
Dmitry Vasiliev
dima at hlabs.spb.ru
Sun Aug 7 08:49:55 EDT 2005
Log message for revision 37767:
Added IModifiableUserPreferredLanguages adapter
Changed:
U Zope3/branches/hdima-language-namespace/src/zope/app/i18n/configure.zcml
U Zope3/branches/hdima-language-namespace/src/zope/app/publisher/browser/__init__.py
A Zope3/branches/hdima-language-namespace/src/zope/app/publisher/browser/tests/test_browserlanguages.py
U Zope3/branches/hdima-language-namespace/src/zope/app/traversing/configure.zcml
U Zope3/branches/hdima-language-namespace/src/zope/app/traversing/namespace.py
U Zope3/branches/hdima-language-namespace/src/zope/i18n/interfaces/__init__.py
U Zope3/branches/hdima-language-namespace/src/zope/publisher/browser.py
U Zope3/branches/hdima-language-namespace/src/zope/publisher/http.py
UU Zope3/branches/hdima-language-namespace/src/zope/publisher/tests/test_browserlanguages.py
-=-
Modified: Zope3/branches/hdima-language-namespace/src/zope/app/i18n/configure.zcml
===================================================================
--- Zope3/branches/hdima-language-namespace/src/zope/app/i18n/configure.zcml 2005-08-07 12:40:19 UTC (rev 37766)
+++ Zope3/branches/hdima-language-namespace/src/zope/app/i18n/configure.zcml 2005-08-07 12:49:54 UTC (rev 37767)
@@ -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/branches/hdima-language-namespace/src/zope/app/publisher/browser/__init__.py
===================================================================
--- Zope3/branches/hdima-language-namespace/src/zope/app/publisher/browser/__init__.py 2005-08-07 12:40:19 UTC (rev 37766)
+++ Zope3/branches/hdima-language-namespace/src/zope/app/publisher/browser/__init__.py 2005-08-07 12:49:54 UTC (rev 37767)
@@ -20,10 +20,17 @@
import zope.interface
from zope.interface import implements, directlyProvidedBy, directlyProvides
+from zope.publisher.browser import BrowserLanguages
+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"
+
# TODO: needs testing of __parent__ property
class BrowserView(Location):
implements(IBrowserView)
@@ -33,7 +40,7 @@
self.request = request
def __getParent(self):
- return hasattr(self, '_parent') and self._parent or self.context
+ return getattr(self, '_parent', self.context)
def __setParent(self, parent):
self._parent = parent
@@ -90,10 +97,10 @@
>>> class SkinB(Interface): pass
>>> directlyProvides(SkinB, ISkin)
>>> class IRequest(Interface): pass
-
+
>>> class Request(object):
... implements(IRequest)
-
+
>>> req = Request()
>>> applySkin(req, SkinA)
@@ -113,3 +120,27 @@
# Add the new skin.
ifaces.append(skin)
directlyProvides(request, *ifaces)
+
+class ModifiableBrowserLanguages(BrowserLanguages):
+
+ implements(IModifiableUserPreferredLanguages)
+
+ def setPreferredLanguages(self, languages):
+ languages_data = self._getLanguagesData()
+ languages_data["overridden"] = languages
+
+ 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(ModifiableBrowserLanguages,
+ 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
Added: Zope3/branches/hdima-language-namespace/src/zope/app/publisher/browser/tests/test_browserlanguages.py
===================================================================
--- Zope3/branches/hdima-language-namespace/src/zope/app/publisher/browser/tests/test_browserlanguages.py 2005-08-07 12:40:19 UTC (rev 37766)
+++ Zope3/branches/hdima-language-namespace/src/zope/app/publisher/browser/tests/test_browserlanguages.py 2005-08-07 12:49:54 UTC (rev 37767)
@@ -0,0 +1,65 @@
+##############################################################################
+#
+# 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.1 (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.
+#
+##############################################################################
+"""Test Modifiable Browser Languages detector
+
+$Id$
+"""
+import unittest
+
+from zope.interface import directlyProvides
+from zope.publisher.tests.test_browserlanguages import BrowserLanguagesTest
+from zope.publisher.tests.test_browserlanguages import TestRequest
+
+from zope.app.testing import ztapi
+from zope.app.testing.placelesssetup import PlacelessSetup
+from zope.app.annotation import IAttributeAnnotatable, IAnnotations
+from zope.app.annotation.attribute import AttributeAnnotations
+from zope.app.publisher.browser import ModifiableBrowserLanguages
+
+
+class ModifiableBrowserLanguagesTests(PlacelessSetup, BrowserLanguagesTest):
+
+ def setUp(self):
+ super(ModifiableBrowserLanguagesTests, self).setUp()
+ ztapi.provideAdapter(IAttributeAnnotatable, IAnnotations,
+ AttributeAnnotations)
+
+ def factory(self, request):
+ directlyProvides(request, IAttributeAnnotatable)
+ return ModifiableBrowserLanguages(request)
+
+ def test_setPreferredLanguages(self):
+ browser_languages = self.factory(TestRequest("da, en, pt"))
+ self.assertEqual(list(browser_languages.getPreferredLanguages()),
+ ["da", "en", "pt"])
+ browser_languages.setPreferredLanguages(["ru", "en"])
+ self.assertEqual(list(browser_languages.getPreferredLanguages()),
+ ["ru", "en"])
+
+ def test_cached_languages(self):
+ request = TestRequest("da, en, pt")
+ browser_languages = self.factory(request)
+ self.assertEqual(list(browser_languages.getPreferredLanguages()),
+ ["da", "en", "pt"])
+ request["HTTP_ACCEPT_LANGUAGE"] = "ru, en"
+ self.assertEqual(list(browser_languages.getPreferredLanguages()),
+ ["da", "en", "pt"])
+
+
+def test_suite():
+ loader=unittest.TestLoader()
+ return loader.loadTestsFromTestCase(ModifiableBrowserLanguagesTests)
+
+if __name__=='__main__':
+ unittest.TextTestRunner().run(test_suite())
Property changes on: Zope3/branches/hdima-language-namespace/src/zope/app/publisher/browser/tests/test_browserlanguages.py
___________________________________________________________________
Name: svn:keywords
+ Id
Modified: Zope3/branches/hdima-language-namespace/src/zope/app/traversing/configure.zcml
===================================================================
--- Zope3/branches/hdima-language-namespace/src/zope/app/traversing/configure.zcml 2005-08-07 12:40:19 UTC (rev 37766)
+++ Zope3/branches/hdima-language-namespace/src/zope/app/traversing/configure.zcml 2005-08-07 12:49:54 UTC (rev 37767)
@@ -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="language"
+ provides="zope.app.traversing.interfaces.ITraversable" for="*"
+ factory="zope.app.traversing.namespace.language"
+ />
<view
+ name="language" type="*"
+ provides="zope.app.traversing.interfaces.ITraversable" for="*"
+ factory="zope.app.traversing.namespace.language"
+ />
+
+<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/branches/hdima-language-namespace/src/zope/app/traversing/namespace.py
===================================================================
--- Zope3/branches/hdima-language-namespace/src/zope/app/traversing/namespace.py 2005-08-07 12:40:19 UTC (rev 37766)
+++ Zope3/branches/hdima-language-namespace/src/zope/app/traversing/namespace.py 2005-08-07 12:49:54 UTC (rev 37767)
@@ -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 language(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
"""
-
-
Modified: Zope3/branches/hdima-language-namespace/src/zope/i18n/interfaces/__init__.py
===================================================================
--- Zope3/branches/hdima-language-namespace/src/zope/i18n/interfaces/__init__.py 2005-08-07 12:40:19 UTC (rev 37766)
+++ Zope3/branches/hdima-language-namespace/src/zope/i18n/interfaces/__init__.py 2005-08-07 12:49:54 UTC (rev 37767)
@@ -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/branches/hdima-language-namespace/src/zope/publisher/browser.py
===================================================================
--- Zope3/branches/hdima-language-namespace/src/zope/publisher/browser.py 2005-08-07 12:40:19 UTC (rev 37766)
+++ Zope3/branches/hdima-language-namespace/src/zope/publisher/browser.py 2005-08-07 12:49:54 UTC (rev 37767)
@@ -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/branches/hdima-language-namespace/src/zope/publisher/http.py
===================================================================
--- Zope3/branches/hdima-language-namespace/src/zope/publisher/http.py 2005-08-07 12:40:19 UTC (rev 37766)
+++ Zope3/branches/hdima-language-namespace/src/zope/publisher/http.py 2005-08-07 12:49:54 UTC (rev 37767)
@@ -230,6 +230,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
@@ -809,7 +810,7 @@
status=302
else:
status=303
-
+
self.setStatus(status)
self.setHeader('Location', location)
return location
@@ -897,7 +898,7 @@
def output(self, data):
"""Output the data to the world.
-
+
There are a couple of steps we have to do:
1. Check that there is a character encoding for the data. If not,
@@ -921,7 +922,7 @@
if self.getHeader('content-type', '').startswith('text'):
data = self._encode(data)
self._updateContentLength(data)
-
+
if (not ('content-length' in self._headers)
and not ('transfer-encoding' in self._headers)):
self._updateContentLength()
Modified: Zope3/branches/hdima-language-namespace/src/zope/publisher/tests/test_browserlanguages.py
===================================================================
--- Zope3/branches/hdima-language-namespace/src/zope/publisher/tests/test_browserlanguages.py 2005-08-07 12:40:19 UTC (rev 37766)
+++ Zope3/branches/hdima-language-namespace/src/zope/publisher/tests/test_browserlanguages.py 2005-08-07 12:49:54 UTC (rev 37767)
@@ -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,24 @@
('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["HTTP_ACCEPT_LANGUAGE"] = languages
+
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/branches/hdima-language-namespace/src/zope/publisher/tests/test_browserlanguages.py
___________________________________________________________________
Name: svn:keywords
+ Id
More information about the Zope3-Checkins
mailing list