Giovannetti, Mark wrote:
The key, as you've correctly identified, is write your own
IUserPreferredLanguages adapter (or a variant thereof). I would store
the user's preferences in a cookie or a session. This makes
things much easier. Simply adapt the request to
I'll end up having to do something like this, I suppose.
It really sucks, though, because I *want* to use the
preferences machinery. Why was it built if it can't be
used in certain places - and why aren't the places it can't
be used documented? Arrg.
Well, it's pretty simple, I've tried to outline it to you:
No matter whether you're going the route with sessions or the route with
the preferences machinery: Both need to store their information
persistently somewhere. That's why they employ local, persistent
utilities. Those are only available after certain things have happened:
the database has been opened and the publisher has successfully
traversed over the sites that contain registered versions of such
utilities. Then and only then the getUtility calls work.
The ComponentLookupError you were quoting in your original email is, I
bet my ass on this, due to the fact that the languages adapter is
invoked right when the request is instantiated, at which point none of
the steps I outlined above have happened.
Note that this might not always work, e.g. when the request is
instantiated and the request's locale is first created (because local
utilities to store the session data in aren't available at
How am I supposed to deal with what you say above? I don't
even understand most of it! ;-)
I'm sorry if I haven't been clear. I also suggest picking up a copy of
my 2nd edition and reading through the chapter on local sites. It
explains the concepts of local components.
It seems you're hitting that exact problem with the
preference stuff as well. The trick here is to stub this
out when the adapter is first called,
'stub this out ... ' - I don't understand, sorry.
and then later during traversal, when you know the local
components are there, you revisit it all again by calling
request.setUpLocale() or whatever it is.
I don't know what you mean. How is a noob supposed to
deal with this?
The ++lang++ implementation might give some pointers.
The ++lang++ implementation (and ensuing errors when I tested using
it) told me that I needed to change BrowserFormLanguages to
use IModifiableUserPreferredLanguages. Since I had to do that
in order to allow language preferences I decided to get the
UserPreferences machinery running for the app. Now I have
I'll try to be a bit clearer now:
* Your custom language adapter needs to gracefully deal with an absent
preference machinery. In other words, you should catch that
ComponentLookupError and fall back to whatever mechanism you want to
fallback (I suggest you simply fall back to the super class's
* If the preference stuff is correctly set up, normal views invoking the
translation machinery will get your adapter, there will be no
ComponentLookupError (because the local site with the persistent
utilities is active).
* The only problem lies in request.locale which has been initialized too
early, when the local site wasn't active and when we caught that
ComponentLookupError and simply ignored it. This should be revisited
now. I recommend to write an event handler for IBeforeTraverseEvent for
ISites that re-initializes request.locale. It would look something like
from zope.component import adapter
from zope.app.component.interfaces import ISite
from zope.app.publication.interfaces import IBeforeTraverseEvent
def reinitializeRequestLocale(site, event):
Register that using <subscriber handler=".reinitializeRequestLocale" />.
http://worldcookery.com -- Professional Zope documentation and training
Next Zope 3 training at Camp5: http://trizpug.org/boot-camp/camp5
Zope3-users mailing list