# HG changeset patch # User Sylvain Thénault # Date 1347278039 -7200 # Node ID 00597256de1837cbbda2f47991df9a5bc3b6994b # Parent e30d0a7f00879216647ca44a346228041e927775 [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) diff -r e30d0a7f0087 -r 00597256de18 dbapi.py --- 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 '' % 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. diff -r e30d0a7f0087 -r 00597256de18 entities/authobjs.py --- 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 diff -r e30d0a7f0087 -r 00597256de18 req.py --- 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 diff -r e30d0a7f0087 -r 00597256de18 server/repository.py --- 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`""" diff -r e30d0a7f0087 -r 00597256de18 server/session.py --- 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 diff -r e30d0a7f0087 -r 00597256de18 web/request.py --- 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