How can I force the language for a particular template rendering?
Hi All, What I want to do is best shown in pseudocode: something.setLanguage('fr') text = my_page_template() something.restoreLanguage() ...the reason I want to do this is that the results of that template will not be in the language negotiated for the current user, as the result is then emailed to someone who may not be speaking the same language as them. I can't find a way to specify a target_language that overrides the negotiated language into the ZPT rendering process. Is there such a way? Suggestions welcomed! Chris -- Simplistix - Content Management, Zope & Python Consulting - http://www.simplistix.co.uk
How about just monkeypatching the active negotiator? {{{ negotiator = getUtility(zope.i18n.interfaces.INegotiator) orig = negotiator.getLanguage negotiator.getLanguage = lambda foo, bar: 'fr' text = my_page_template() negotiator.getLanguage = orig }}} Haven't tested it, but in my (limited) understanding of the I18N system something like that ought to work.. egj On Fri, Apr 17, 2009 at 3:14 PM, Chris Withers <chris@simplistix.co.uk>wrote:
Hi All,
What I want to do is best shown in pseudocode:
something.setLanguage('fr') text = my_page_template() something.restoreLanguage()
...the reason I want to do this is that the results of that template will not be in the language negotiated for the current user, as the result is then emailed to someone who may not be speaking the same language as them.
I can't find a way to specify a target_language that overrides the negotiated language into the ZPT rendering process. Is there such a way?
Suggestions welcomed!
Chris
Ethan Jucovy wrote:
How about just monkeypatching the active negotiator?
{{{ negotiator = getUtility(zope.i18n.interfaces.INegotiator) orig = negotiator.getLanguage negotiator.getLanguage = lambda foo, bar: 'fr' text = my_page_template() negotiator.getLanguage = orig }}}
Haven't tested it, but in my (limited) understanding of the I18N system something like that ought to work..
As the default negotiator is based on the request, it might be possible to forge a different request object for the template. Or attach a marker interface to the request and register a different IUserPreferredLanguages adapter for it. A more specialized version should take precedence over the normal adapter based on the HTTP header. Hanno
Hanno Schlichting wrote:
Or attach a marker interface to the request and register a different IUserPreferredLanguages adapter for it.
This won't quite work as I still need to get the language I'm forcing from somewhere. However, I realised I already had a custom IUserPreferredLanguages adapter on this project (to get the language from the user object, not the browser) so I added a bit of code in there. The simplest version of this would be: from zope.publisher.browser import BrowserLanguages class Languages(BrowserLanguages): def getPreferredLanguages(self): force = getattr(self.request,'_force_language',None) if force: return [force] return super(Languages, self).getPreferredLanguages() Then this zcml: <adapter for="zope.publisher.interfaces.http.IHTTPRequest" provides="zope.i18n.interfaces.IUserPreferredLanguages" factory=".languages.Languages" /> ...and then you can do the following in a view: def __call__(self): def1 = self.template(self) self.request._force_language = 'de' de = self.template(self) del self.request._force_language def2 = self.template(self) return def1+de+def2 Hope someone else finds this useful some day :-) Chris -- Simplistix - Content Management, Zope & Python Consulting - http://www.simplistix.co.uk
On Sat, Apr 18, 2009 at 12:34:19AM +0100, Chris Withers wrote:
Hanno Schlichting wrote:
Or attach a marker interface to the request and register a different IUserPreferredLanguages adapter for it.
This won't quite work as I still need to get the language I'm forcing from somewhere.
However, I realised I already had a custom IUserPreferredLanguages adapter on this project (to get the language from the user object, not the browser) so I added a bit of code in there. The simplest version of this would be:
from zope.publisher.browser import BrowserLanguages
class Languages(BrowserLanguages):
def getPreferredLanguages(self): force = getattr(self.request,'_force_language',None) if force: return [force] return super(Languages, self).getPreferredLanguages()
Then this zcml:
<adapter for="zope.publisher.interfaces.http.IHTTPRequest" provides="zope.i18n.interfaces.IUserPreferredLanguages" factory=".languages.Languages" />
...and then you can do the following in a view:
def __call__(self): def1 = self.template(self) self.request._force_language = 'de'
Does this work? IIRC Zope 3 request objects use __slots__ and therefore cannot have any extra attributes imposed upon them from the outside. Marius Gedminas -- http://pov.lt/ -- Zope 3 consulting and development
Marius Gedminas wrote:
Does this work? IIRC Zope 3 request objects use __slots__ and therefore cannot have any extra attributes imposed upon them from the outside.
Good thing I'm using Zope 2 request objects then ;-) Does a Zope 3 request still haev an 'other' dictionary? If so, you could stick it in there... Chris -- Simplistix - Content Management, Zope & Python Consulting - http://www.simplistix.co.uk
Actually -- for a more proper solution -- I believe zope.i18n.interfaces.IUserPreferredLanguages is expected to adapt a request (rather than being a contextless utility) so I bet you could register a custom IUserPreferredLanguages whose getPreferredLanguages returns ['fr'] on an IForceLanguage interface, and mark the current request with IForceLanguage before rendering the template. egj On Fri, Apr 17, 2009 at 3:35 PM, Ethan Jucovy <ethan.jucovy@gmail.com>wrote:
How about just monkeypatching the active negotiator?
{{{ negotiator = getUtility(zope.i18n.interfaces.INegotiator) orig = negotiator.getLanguage negotiator.getLanguage = lambda foo, bar: 'fr' text = my_page_template() negotiator.getLanguage = orig }}}
Haven't tested it, but in my (limited) understanding of the I18N system something like that ought to work..
egj
On Fri, Apr 17, 2009 at 3:14 PM, Chris Withers <chris@simplistix.co.uk>wrote:
Hi All,
What I want to do is best shown in pseudocode:
something.setLanguage('fr') text = my_page_template() something.restoreLanguage()
...the reason I want to do this is that the results of that template will not be in the language negotiated for the current user, as the result is then emailed to someone who may not be speaking the same language as them.
I can't find a way to specify a target_language that overrides the negotiated language into the ZPT rendering process. Is there such a way?
Suggestions welcomed!
Chris
Actually -- for a more proper solution -- I believe zope.i18n.interfaces.IUserPreferredLanguages is expected to adapt a request (rather than being a contextless utility) so I bet you could register a custom IUserPreferredLanguages whose getPreferredLanguages returns ['fr'] on an IForceLanguage interface, and mark the current request with IForceLanguage before rendering the template. egj On Fri, Apr 17, 2009 at 3:35 PM, Ethan Jucovy <ethan.jucovy@gmail.com>wrote:
How about just monkeypatching the active negotiator?
{{{ negotiator = getUtility(zope.i18n.interfaces.INegotiator) orig = negotiator.getLanguage negotiator.getLanguage = lambda foo, bar: 'fr' text = my_page_template() negotiator.getLanguage = orig }}}
Haven't tested it, but in my (limited) understanding of the I18N system something like that ought to work..
egj
On Fri, Apr 17, 2009 at 3:14 PM, Chris Withers <chris@simplistix.co.uk>wrote:
Hi All,
What I want to do is best shown in pseudocode:
something.setLanguage('fr') text = my_page_template() something.restoreLanguage()
...the reason I want to do this is that the results of that template will not be in the language negotiated for the current user, as the result is then emailed to someone who may not be speaking the same language as them.
I can't find a way to specify a target_language that overrides the negotiated language into the ZPT rendering process. Is there such a way?
Suggestions welcomed!
Chris
On Fri, Apr 17, 2009 at 03:35:58PM -0400, Ethan Jucovy wrote:
How about just monkeypatching the active negotiator?
{{{ negotiator = getUtility(zope.i18n.interfaces.INegotiator) orig = negotiator.getLanguage negotiator.getLanguage = lambda foo, bar: 'fr' text = my_page_template() negotiator.getLanguage = orig }}}
Haven't tested it, but in my (limited) understanding of the I18N system something like that ought to work..
Two words: "thread safety". Zope 3 utilities are global, not thread-local. Unless you have a persistent utility (theoretically; the default INegotiator isn't), which would be thread-local. (And in which case your example code would try to pickle a bound method---I wonder if that'd work? I think it might, but just consider the conflict errors you'd get if every request did this.) "Monkey-patching outside unit tests is evil and will explode when you don't expect" is a good rule of thumb. Marius Gedminas -- http://pov.lt/ -- Zope 3 consulting and development
participants (4)
-
Chris Withers -
Ethan Jucovy -
Hanno Schlichting -
Marius Gedminas