[request/session] refactor language handling: don't attempt to sync web/repo languages
This decouple thing and make code easier to understand. Previous behaviour was fine
w/ validation error that were translated on the server side, but isn't satisfying for
notification and all. Now:
* translations should be done on the ui side (see previous validation error
refactoring)
* consistent behaviour: each side (web/repo) is responsible to deal with its
request/session of language, no weird interaction between them on this topic
* drop on the way the 'session properties' api, used only for that matter.
-> much simpler/cleaner/saner api
The thing missing being a way for user to tell "My favorite language is xxx but I also
want cw to consider my http language header)
--- a/dbapi.py Mon Sep 10 14:00:09 2012 +0200
+++ b/dbapi.py Mon Sep 10 13:53:59 2012 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -80,9 +80,8 @@
class ConnectionProperties(object):
- def __init__(self, cnxtype=None, lang=None, close=True, log=False):
+ def __init__(self, cnxtype=None, close=True, log=False):
self.cnxtype = cnxtype or 'pyro'
- self.lang = lang
self.log_queries = log
self.close_on_del = close
@@ -283,6 +282,8 @@
return '<DBAPISession %r>' % self.sessionid
class DBAPIRequest(RequestSessionBase):
+ #: Request language identifier eg: 'en'
+ lang = None
def __init__(self, vreg, session=None):
super(DBAPIRequest, self).__init__(vreg)
@@ -292,9 +293,6 @@
self.translations = vreg.config.translations
except AttributeError:
self.translations = {}
- #: Request language identifier eg: 'en'
- self.lang = None
- self.set_default_language(vreg)
#: cache entities built during the request
self._eid_cache = {}
if session is not None:
@@ -304,6 +302,7 @@
# established
self.session = None
self.cnx = self.user = _NeedAuthAccessMock()
+ self.set_default_language(vreg)
def from_controller(self):
return 'view'
@@ -317,7 +316,7 @@
self.cnx = session.cnx
self.execute = session.cnx.cursor(self).execute
if user is None:
- user = self.cnx.user(self, {'lang': self.lang})
+ user = self.cnx.user(self)
if user is not None:
self.user = user
self.set_entity_cache(user)
@@ -330,19 +329,15 @@
def set_default_language(self, vreg):
try:
- self.lang = vreg.property_value('ui.language')
+ lang = vreg.property_value('ui.language')
except Exception: # property may not be registered
- self.lang = 'en'
- # use req.__ to translate a message without registering it to the catalog
+ lang = 'en'
try:
- gettext, pgettext = self.translations[self.lang]
- self._ = self.__ = gettext
- self.pgettext = pgettext
+ self.set_language(lang)
except KeyError:
# this occurs usually during test execution
self._ = self.__ = unicode
self.pgettext = lambda x, y: unicode(y)
- self.debug('request default language: %s', self.lang)
# server-side service call #################################################
@@ -670,11 +665,6 @@
# session data methods #####################################################
@check_not_closed
- def set_session_props(self, **props):
- """raise `BadConnectionId` if the connection is no more valid"""
- self._repo.set_session_props(self.sessionid, props)
-
- @check_not_closed
def get_shared_data(self, key, default=None, pop=False, txdata=False):
"""return value associated to key in the session's data dictionary or
session's transaction's data if `txdata` is true.
--- a/entities/authobjs.py Mon Sep 10 14:00:09 2012 +0200
+++ b/entities/authobjs.py Mon Sep 10 13:53:59 2012 +0200
@@ -77,6 +77,19 @@
self._properties = dict((p.pkey, p.value) for p in self.reverse_for_user)
return self._properties
+ def prefered_language(self, language=None):
+ """return language used by this user, if explicitly defined (eg not
+ using http negociation)
+ """
+ language = language or self.property_value('ui.language')
+ vreg = self._cw.vreg
+ try:
+ vreg.config.translations[language]
+ except KeyError:
+ language = vreg.property_value('ui.language')
+ assert language in vreg.config.translations[language], language
+ return language
+
def property_value(self, key):
try:
# properties stored on the user aren't correctly typed
--- a/req.py Mon Sep 10 14:00:09 2012 +0200
+++ b/req.py Mon Sep 10 13:53:59 2012 +0200
@@ -77,6 +77,17 @@
self.local_perm_cache = {}
self._ = unicode
+ def set_language(self, lang):
+ """install i18n configuration for `lang` translation.
+
+ Raises :exc:`KeyError` if translation doesn't exist.
+ """
+ self.lang = lang
+ gettext, pgettext = self.vreg.config.translations[lang]
+ # use _cw.__ to translate a message without registering it to the catalog
+ self._ = self.__ = gettext
+ self.pgettext = pgettext
+
def property_value(self, key):
"""return value of the property with the given key, giving priority to
user specific value if any, else using site value
--- a/server/repository.py Mon Sep 10 14:00:09 2012 +0200
+++ b/server/repository.py Mon Sep 10 13:53:59 2012 +0200
@@ -747,10 +747,10 @@
raise `AuthenticationError` if the authentication failed
raise `ConnectionError` if we can't open a connection
"""
+ cnxprops = kwargs.pop('cnxprops', None)
# use an internal connection
with self.internal_session() as session:
# try to get a user object
- cnxprops = kwargs.pop('cnxprops', None)
user = self.authenticate_user(session, login, **kwargs)
session = Session(user, self, cnxprops)
user._cw = user.cw_rset.req = session
@@ -901,22 +901,9 @@
* update user information on each user's request (i.e. groups and
custom properties)
"""
- session = self._get_session(sessionid, setcnxset=False)
- if props is not None:
- self.set_session_props(sessionid, props)
- user = session.user
+ user = self._get_session(sessionid, setcnxset=False).user
return user.eid, user.login, user.groups, user.properties
- def set_session_props(self, sessionid, props):
- """this method should be used by client to:
- * check session id validity
- * update user information on each user's request (i.e. groups and
- custom properties)
- """
- session = self._get_session(sessionid, setcnxset=False)
- for prop, value in props.items():
- session.change_property(prop, value)
-
def undoable_transactions(self, sessionid, ueid=None, txid=None,
**actionfilters):
"""See :class:`cubicweb.dbapi.Connection.undoable_transactions`"""
--- a/server/session.py Mon Sep 10 14:00:09 2012 +0200
+++ b/server/session.py Mon Sep 10 13:53:59 2012 +0200
@@ -265,7 +265,7 @@
# and the rql server
self.data = {}
# i18n initialization
- self.set_language(cnxprops.lang)
+ self.set_language(user.prefered_language())
# internals
self._tx_data = {}
self.__threaddata = threading.local()
@@ -463,28 +463,6 @@
self.cnxset.reconnect(source)
return source.doexec(self, sql, args, rollback=rollback_on_failure)
- def set_language(self, language):
- """i18n configuration for translation"""
- language = language or self.user.property_value('ui.language')
- try:
- gettext, pgettext = self.vreg.config.translations[language]
- self._ = self.__ = gettext
- self.pgettext = pgettext
- except KeyError:
- language = self.vreg.property_value('ui.language')
- try:
- gettext, pgettext = self.vreg.config.translations[language]
- self._ = self.__ = gettext
- self.pgettext = pgettext
- except KeyError:
- self._ = self.__ = unicode
- self.pgettext = lambda x, y: y
- self.lang = language
-
- def change_property(self, prop, value):
- assert prop == 'lang' # this is the only one changeable property for now
- self.set_language(value)
-
def deleted_in_transaction(self, eid):
"""return True if the entity of the given eid is being deleted in the
current transaction
--- a/web/request.py Mon Sep 10 14:00:09 2012 +0200
+++ b/web/request.py Mon Sep 10 13:53:59 2012 +0200
@@ -226,14 +226,6 @@
# 3. default language
self.set_default_language(vreg)
- def set_language(self, lang):
- gettext, self.pgettext = self.translations[lang]
- self._ = self.__ = gettext
- self.lang = lang
- self.debug('request language: %s', lang)
- if self.cnx:
- self.cnx.set_session_props(lang=lang)
-
# input form parameters management ########################################
# common form parameters which should be protected against html values