backport 3.5
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Thu, 17 Sep 2009 15:16:53 +0200
changeset 3293 69c0ba095536
parent 3230 1d25e928c299 (current diff)
parent 3292 70c0dd1c3b7d (diff)
child 3300 c7c4775a5619
backport 3.5
__pkginfo__.py
common/i18n.py
cwvreg.py
dbapi.py
devtools/devctl.py
devtools/fake.py
doc/book/en/development/devweb/views.rst
doc/book/en/intro/tutorial/create-cube.rst
entity.py
goa/goactl.py
hooks/email.py
schema.py
selectors.py
server/repository.py
server/rqlrewrite.py
server/session.py
server/test/unittest_extlite.py
server/test/unittest_migractions.py
server/test/unittest_msplanner.py
server/test/unittest_multisources.py
server/test/unittest_rqlannotation.py
server/test/unittest_rqlrewrite.py
server/test/unittest_security.py
server/test/unittest_ssplanner.py
sobjects/test/unittest_email.py
test/unittest_entity.py
test/unittest_utils.py
utils.py
web/action.py
web/request.py
web/test/unittest_application.py
web/uicfg.py
web/views/actions.py
web/views/autoform.py
web/views/basecontrollers.py
web/views/basetemplates.py
web/views/baseviews.py
web/views/editviews.py
web/views/formrenderers.py
web/views/forms.py
web/views/schema.py
web/views/treeview.py
web/views/workflow.py
--- a/.hgtags	Tue Sep 15 15:01:41 2009 +0200
+++ b/.hgtags	Thu Sep 17 15:16:53 2009 +0200
@@ -68,3 +68,5 @@
 97273eeaaead11c0f422dc5a4fe2d4f14fc6a2dd cubicweb-debian-version-3.4.8-1
 e916f1e856c83aced0fe73f7ae9068e37edcc38c cubicweb-version-3.4.9
 24ea70f19a48cce60248ab18695925755009bcb8 cubicweb-debian-version-3.4.9-1
+f3d2adf483320d7726136433a41c57b130cbdc15 cubicweb-version-3.4.11
+635a25031f4abdd89c44d17f5d2b0d0d43914511 cubicweb-debian-version-3.4.11-1
--- a/common/i18n.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/common/i18n.py	Thu Sep 17 15:16:53 2009 +0200
@@ -26,10 +26,14 @@
     output.close()
 
 
-def add_msg(w, msgid):
+def add_msg(w, msgid, msgctx=None):
     """write an empty pot msgid definition"""
     if isinstance(msgid, unicode):
         msgid = msgid.encode('utf-8')
+    if msgctx:
+        if isinstance(msgctx, unicode):
+            msgctx = msgctx.encode('utf-8')
+        w('msgctxt "%s"\n' % msgctx)
     msgid = msgid.replace('"', r'\"').splitlines()
     if len(msgid) > 1:
         w('msgid ""\n')
--- a/cwconfig.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/cwconfig.py	Thu Sep 17 15:16:53 2009 +0200
@@ -392,7 +392,11 @@
                         'server/serverctl.py', 'hercule.py',
                         'devtools/devctl.py', 'goa/goactl.py'):
             if exists(join(CW_SOFTWARE_ROOT, ctlfile)):
-                load_module_from_file(join(CW_SOFTWARE_ROOT, ctlfile))
+                try:
+                    load_module_from_file(join(CW_SOFTWARE_ROOT, ctlfile))
+                except ImportError, err:
+                    cls.critical('could not import the command provider %s (cause : %s)' %
+                                (ctlfile, err))
                 cls.info('loaded cubicweb-ctl plugin %s', ctlfile)
         for cube in cls.available_cubes():
             pluginfile = join(cls.cube_dir(cube), 'ecplugin.py')
@@ -808,7 +812,7 @@
             self.info("loading language %s", language)
             try:
                 tr = translation('cubicweb', path, languages=[language])
-                self.translations[language] = tr.ugettext
+                self.translations[language] = (tr.ugettext, tr.upgettext)
             except (ImportError, AttributeError, IOError):
                 self.exception('localisation support error for language %s',
                                language)
--- a/cwvreg.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/cwvreg.py	Thu Sep 17 15:16:53 2009 +0200
@@ -297,8 +297,7 @@
 
     def set_schema(self, schema):
         """set instance'schema and load application objects"""
-        self.schema = schema
-        clear_cache(self, 'rqlhelper')
+        self._set_schema(schema)
         # now we can load application's web objects
         searchpath = self.config.vregistry_path()
         self.reset(searchpath, force_reload=False)
@@ -309,6 +308,11 @@
             etype = str(etype)
             self.case_insensitive_etypes[etype.lower()] = etype
 
+    def _set_schema(self, schema):
+        """set instance'schema"""
+        self.schema = schema
+        clear_cache(self, 'rqlhelper')
+
     def update_schema(self, schema):
         """update .schema attribute on registered objects, necessary for some
         tests
@@ -394,16 +398,7 @@
         # objects on automatic reloading
         self._needs_iface.clear()
 
-    def parse(self, session, rql, args=None):
-        rqlst = self.rqlhelper.parse(rql)
-        def type_from_eid(eid, session=session):
-            return session.describe(eid)[0]
-        try:
-            self.rqlhelper.compute_solutions(rqlst, {'eid': type_from_eid}, args)
-        except UnknownEid:
-            for select in rqlst.children:
-                select.solutions = []
-        return rqlst
+    # rql parsing utilities ####################################################
 
     @property
     @cached
@@ -411,38 +406,19 @@
         return RQLHelper(self.schema,
                          special_relations={'eid': 'uid', 'has_text': 'fti'})
 
-
-    @deprecated('[3.4] use vreg["etypes"].etype_class(etype)')
-    def etype_class(self, etype):
-        return self["etypes"].etype_class(etype)
-
-    @deprecated('[3.4] use vreg["views"].main_template(*args, **kwargs)')
-    def main_template(self, req, oid='main-template', **context):
-        return self["views"].main_template(req, oid, **context)
-
-    @deprecated('[3.4] use vreg[registry].possible_vobjects(*args, **kwargs)')
-    def possible_vobjects(self, registry, *args, **kwargs):
-        return self[registry].possible_vobjects(*args, **kwargs)
+    def solutions(self, req, rqlst, args):
+        def type_from_eid(eid, req=req):
+            return req.describe(eid)[0]
+        self.rqlhelper.compute_solutions(rqlst, {'eid': type_from_eid}, args)
 
-    @deprecated('[3.4] use vreg["actions"].possible_actions(*args, **kwargs)')
-    def possible_actions(self, req, rset=None, **kwargs):
-        return self["actions"].possible_actions(req, rest=rset, **kwargs)
-
-    @deprecated("[3.4] use vreg['boxes'].select_or_none(...)")
-    def select_box(self, oid, *args, **kwargs):
-        return self['boxes'].select_or_none(oid, *args, **kwargs)
-
-    @deprecated("[3.4] use vreg['components'].select_or_none(...)")
-    def select_component(self, cid, *args, **kwargs):
-        return self['components'].select_or_none(cid, *args, **kwargs)
-
-    @deprecated("[3.4] use vreg['actions'].select_or_none(...)")
-    def select_action(self, oid, *args, **kwargs):
-        return self['actions'].select_or_none(oid, *args, **kwargs)
-
-    @deprecated("[3.4] use vreg['views'].select(...)")
-    def select_view(self, __vid, req, rset=None, **kwargs):
-        return self['views'].select(__vid, req, rset=rset, **kwargs)
+    def parse(self, req, rql, args=None):
+        rqlst = self.rqlhelper.parse(rql)
+        try:
+            self.solutions(req, rqlst, args)
+        except UnknownEid:
+            for select in rqlst.children:
+                select.solutions = []
+        return rqlst
 
     # properties handling #####################################################
 
@@ -515,6 +491,40 @@
                 self.warning('%s (you should probably delete that property '
                              'from the database)', ex)
 
+    # deprecated code ####################################################
+
+    @deprecated('[3.4] use vreg["etypes"].etype_class(etype)')
+    def etype_class(self, etype):
+        return self["etypes"].etype_class(etype)
+
+    @deprecated('[3.4] use vreg["views"].main_template(*args, **kwargs)')
+    def main_template(self, req, oid='main-template', **context):
+        return self["views"].main_template(req, oid, **context)
+
+    @deprecated('[3.4] use vreg[registry].possible_vobjects(*args, **kwargs)')
+    def possible_vobjects(self, registry, *args, **kwargs):
+        return self[registry].possible_vobjects(*args, **kwargs)
+
+    @deprecated('[3.4] use vreg["actions"].possible_actions(*args, **kwargs)')
+    def possible_actions(self, req, rset=None, **kwargs):
+        return self["actions"].possible_actions(req, rest=rset, **kwargs)
+
+    @deprecated('[3.4] use vreg["boxes"].select_object(...)')
+    def select_box(self, oid, *args, **kwargs):
+        return self['boxes'].select_object(oid, *args, **kwargs)
+
+    @deprecated('[3.4] use vreg["components"].select_object(...)')
+    def select_component(self, cid, *args, **kwargs):
+        return self['components'].select_object(cid, *args, **kwargs)
+
+    @deprecated('[3.4] use vreg["actions"].select_object(...)')
+    def select_action(self, oid, *args, **kwargs):
+        return self['actions'].select_object(oid, *args, **kwargs)
+
+    @deprecated('[3.4] use vreg["views"].select(...)')
+    def select_view(self, __vid, req, rset=None, **kwargs):
+        return self['views'].select(__vid, req, rset=rset, **kwargs)
+
 
 from datetime import datetime, date, time, timedelta
 
--- a/dbapi.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/dbapi.py	Thu Sep 17 15:16:53 2009 +0200
@@ -215,10 +215,13 @@
             self.lang = 'en'
         # use req.__ to translate a message without registering it to the catalog
         try:
-            self._ = self.__ = self.translations[self.lang]
+            gettext, pgettext = self.translations[self.lang]
+            self._ = self.__ = gettext
+            self.pgettext = pgettext
         except KeyError:
             # this occurs usually during test execution
             self._ = self.__ = unicode
+            self.pgettext = lambda x,y: y
         self.debug('request default language: %s', self.lang)
 
     def decorate_rset(self, rset):
@@ -361,7 +364,7 @@
 # connection object ###########################################################
 
 class Connection(object):
-    """DB-API 2.0 compatible Connection object for CubicWebt
+    """DB-API 2.0 compatible Connection object for CubicWeb
     """
     # make exceptions available through the connection object
     ProgrammingError = ProgrammingError
--- a/debian/changelog	Tue Sep 15 15:01:41 2009 +0200
+++ b/debian/changelog	Thu Sep 17 15:16:53 2009 +0200
@@ -1,3 +1,15 @@
+cubicweb (3.5.0-1) unstable; urgency=low
+
+  * new upstream release
+
+ -- Sylvain Thénault <sylvain.thenault@logilab.fr>  Wed, 16 Sep 2009 17:51:13 +0200
+
+cubicweb (3.4.11-1) unstable; urgency=low
+
+  * new upstream release
+
+ -- Aurélien Campéas <aurelien.campeas@logilab.fr>  Tue, 11 Sep 2009 12:20:00 +0200
+
 cubicweb (3.4.10-1) unstable; urgency=low
 
   * new upstream release
--- a/devtools/devctl.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/devtools/devctl.py	Thu Sep 17 15:16:53 2009 +0200
@@ -12,6 +12,7 @@
 from datetime import datetime
 from os import mkdir, chdir, getcwd
 from os.path import join, exists, abspath, basename, normpath, split, isdir
+from copy import deepcopy
 from warnings import warn
 
 from logilab.common import STD_BLACKLIST
@@ -112,93 +113,104 @@
 
 def _generate_schema_pot(w, vreg, schema, libconfig=None, cube=None):
     from cubicweb.common.i18n import add_msg
+    from cubicweb.web import uicfg
+    from cubicweb.schema import META_RTYPES, SYSTEM_RTYPES
+    no_context_rtypes = META_RTYPES | SYSTEM_RTYPES
     w('# schema pot file, generated on %s\n' % datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
     w('# \n')
     w('# singular and plural forms for each entity type\n')
     w('\n')
+    vregdone = set()
     if libconfig is not None:
+        from cubicweb.cwvreg import CubicWebVRegistry, clear_rtag_objects
         libschema = libconfig.load_schema(remove_unused_rtypes=False)
-        entities = [e for e in schema.entities() if not e in libschema]
+        rinlined = deepcopy(uicfg.autoform_is_inlined)
+        appearsin_addmenu = deepcopy(uicfg.actionbox_appearsin_addmenu)
+        clear_rtag_objects()
+        cleanup_sys_modules(libconfig)
+        libvreg = CubicWebVRegistry(libconfig)
+        libvreg.set_schema(libschema) # trigger objects registration
+        librinlined = uicfg.autoform_is_inlined
+        libappearsin_addmenu = uicfg.actionbox_appearsin_addmenu
+        # prefill vregdone set
+        list(_iter_vreg_objids(libvreg, vregdone))
     else:
-        libschema = None
-        entities = schema.entities()
+        libschema = {}
+        rinlined = uicfg.autoform_is_inlined
+        appearsin_addmenu = uicfg.actionbox_appearsin_addmenu
     done = set()
-    for eschema in sorted(entities):
+    for eschema in sorted(schema.entities()):
         etype = eschema.type
-        add_msg(w, etype)
-        add_msg(w, '%s_plural' % etype)
-        if not eschema.is_final():
-            add_msg(w, 'This %s' % etype)
-            add_msg(w, 'New %s' % etype)
-            add_msg(w, 'add a %s' % etype)
-            add_msg(w, 'remove this %s' % etype)
-        if eschema.description and not eschema.description in done:
-            done.add(eschema.description)
-            add_msg(w, eschema.description)
-    w('# subject and object forms for each relation type\n')
-    w('# (no object form for final relation types)\n')
-    w('\n')
-    if libconfig is not None:
-        relations = [r for r in schema.relations() if not r in libschema]
-    else:
-        relations = schema.relations()
-    for rschema in sorted(set(relations)):
-        rtype = rschema.type
-        add_msg(w, rtype)
-        done.add(rtype)
-        if not (schema.rschema(rtype).is_final() or rschema.symetric):
-            add_msg(w, '%s_object' % rtype)
-        if rschema.description and rschema.description not in done:
-            done.add(rschema.description)
-            add_msg(w, rschema.description)
-    w('# add related box generated message\n')
-    w('\n')
-    from cubicweb.web import uicfg
-    appearsin_addmenu = uicfg.actionbox_appearsin_addmenu
-    for eschema in schema.entities():
+        if etype not in libschema:
+            add_msg(w, etype)
+            add_msg(w, '%s_plural' % etype)
+            if not eschema.is_final():
+                add_msg(w, 'This %s' % etype)
+                add_msg(w, 'New %s' % etype)
+            if eschema.description and not eschema.description in done:
+                done.add(eschema.description)
+                add_msg(w, eschema.description)
         if eschema.is_final():
             continue
-        for role, rschemas in (('subject', eschema.subject_relations()),
-                            ('object', eschema.object_relations())):
-            for rschema in rschemas:
-                if rschema.is_final():
-                    continue
-                if libconfig is not None:
-                    librschema = libschema.get(rschema)
-                for teschema in rschema.targets(eschema, role):
-                    if libconfig is not None and librschema is not None:
-                        if role == 'subject':
-                            subjtype, objtype = eschema, teschema
-                        else:
-                            subjtype, objtype = teschema, eschema
-                        if librschema.has_rdef(subjtype, objtype):
-                            continue
-                    if appearsin_addmenu.etype_get(eschema, rschema, role,
-                                                   teschema):
-                        if role == 'subject':
-                            label = 'add %s %s %s %s' % (eschema, rschema,
-                                                         teschema, role)
-                            label2 = "creating %s (%s %%(linkto)s %s %s)" % (
-                                teschema, eschema, rschema, teschema)
-                        else:
-                            label = 'add %s %s %s %s' % (teschema, rschema,
-                                                         eschema, role)
-                            label2 = "creating %s (%s %s %s %%(linkto)s)" % (
-                                teschema, teschema, rschema, eschema)
-                        add_msg(w, label)
-                        add_msg(w, label2)
-    #cube = (cube and 'cubes.%s.' % cube or 'cubicweb.')
-    done = set()
-    if libconfig is not None:
-        from cubicweb.cwvreg import CubicWebVRegistry
-        libvreg = CubicWebVRegistry(libconfig)
-        libvreg.set_schema(libschema) # trigger objects registration
-        # prefill done set
-        list(_iter_vreg_objids(libvreg, done))
-    for objid in _iter_vreg_objids(vreg, done):
+        for rschema, targetschemas, role in eschema.relation_definitions(True):
+            for tschema in targetschemas:
+                if rinlined.etype_get(eschema, rschema, role, tschema) and \
+                       (libconfig is None or not
+                        librinlined.etype_get(eschema, rschema, role, tschema)):
+                    add_msg(w, 'add a %s' % tschema,
+                            'inlined:%s.%s.%s' % (etype, rschema, role))
+                    add_msg(w, 'remove this %s' % tschema,
+                            'inlined:%s:%s:%s' % (etype, rschema, role))
+                if appearsin_addmenu.etype_get(eschema, rschema, role, tschema) and \
+                       (libconfig is None or not
+                        libappearsin_addmenu.etype_get(eschema, rschema, role, tschema)):
+                    if role == 'subject':
+                        label = 'add %s %s %s %s' % (eschema, rschema,
+                                                     tschema, role)
+                        label2 = "creating %s (%s %%(linkto)s %s %s)" % (
+                            tschema, eschema, rschema, tschema)
+                    else:
+                        label = 'add %s %s %s %s' % (tschema, rschema,
+                                                     eschema, role)
+                        label2 = "creating %s (%s %s %s %%(linkto)s)" % (
+                            tschema, tschema, rschema, eschema)
+                    add_msg(w, label)
+                    add_msg(w, label2)
+    w('# subject and object forms for each relation type\n')
+    w('# (no object form for final or symetric relation types)\n')
+    w('\n')
+    for rschema in sorted(schema.relations()):
+        rtype = rschema.type
+        if rtype not in libschema:
+            # bw compat, necessary until all translation of relation are done properly...
+            add_msg(w, rtype)
+            if rschema.description and rschema.description not in done:
+                done.add(rschema.description)
+                add_msg(w, rschema.description)
+            done.add(rtype)
+            librschema = None
+        else:
+            librschema = libschema.rschema(rtype)
+        # add context information only for non-metadata rtypes
+        if rschema not in no_context_rtypes:
+            libsubjects = librschema and librschema.subjects() or ()
+            for subjschema in rschema.subjects():
+                if not subjschema in libsubjects:
+                    add_msg(w, rtype, subjschema.type)
+        if not (schema.rschema(rtype).is_final() or rschema.symetric):
+            if rschema not in no_context_rtypes:
+                libobjects = librschema and librschema.objects() or ()
+                for objschema in rschema.objects():
+                    if not objschema in libobjects:
+                        add_msg(w, '%s_object' % rtype, objschema.type)
+            if rtype not in libschema:
+                # bw compat, necessary until all translation of relation are done properly...
+                add_msg(w, '%s_object' % rtype)
+    for objid in _iter_vreg_objids(vreg, vregdone):
         add_msg(w, '%s_description' % objid)
         add_msg(w, objid)
 
+
 def _iter_vreg_objids(vreg, done, prefix=None):
     for reg, objdict in vreg.items():
         for objects in objdict.values():
--- a/devtools/fake.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/devtools/fake.py	Thu Sep 17 15:16:53 2009 +0200
@@ -12,6 +12,7 @@
 from indexer import get_indexer
 
 from cubicweb.req import RequestSessionBase
+from cubicweb.cwvreg import CubicWebVRegistry
 from cubicweb.web.request import CubicWebRequestBase
 from cubicweb.devtools import BASE_URL, BaseApptestConfiguration
 
@@ -34,39 +35,13 @@
     def sources(self):
         return {}
 
-class FakeVReg(dict):
-    def __init__(self, schema=None, config=None):
-        self.schema = schema
-        self.config = config or FakeConfig()
-        self.properties = {'ui.encoding': 'UTF8',
-                           'ui.language': 'en',
-                           }
-        self.update({
-            'controllers' : {'login': []},
-            'views' : {},
-            })
-
-    def property_value(self, key):
-        return self.properties[key]
-
-    def etype_class(self, etype):
-        class Entity(dict):
-            e_schema = self.schema[etype]
-            def __init__(self, session, eid, row=0, col=0):
-                self.req = session
-                self.eid = eid
-                self.row, self.col = row, col
-            def set_eid(self, eid):
-                self.eid = self['eid'] = eid
-        return Entity
-
 
 class FakeRequest(CubicWebRequestBase):
     """test implementation of an cubicweb request object"""
 
     def __init__(self, *args, **kwargs):
         if not (args or 'vreg' in kwargs):
-            kwargs['vreg'] = FakeVReg()
+            kwargs['vreg'] = CubicWebVRegistry(FakeConfig(), initlog=False)
         kwargs['https'] = False
         self._url = kwargs.pop('url', 'view?rql=Blop&vid=blop')
         super(FakeRequest, self).__init__(*args, **kwargs)
@@ -147,25 +122,6 @@
         return self.execute(*args, **kwargs)
 
 
-# class FakeRequestNoCnx(FakeRequest):
-#     def get_session_data(self, key, default=None, pop=False):
-#         """return value associated to `key` in session data"""
-#         if pop:
-#             return self._session_data.pop(key, default)
-#         else:
-#             return self._session_data.get(key, default)
-
-#     def set_session_data(self, key, value):
-#         """set value associated to `key` in session data"""
-#         self._session_data[key] = value
-
-#     def del_session_data(self, key):
-#         try:
-#             del self._session_data[key]
-#         except KeyError:
-#             pass
-
-
 class FakeUser(object):
     login = 'toto'
     eid = 0
@@ -176,7 +132,7 @@
 class FakeSession(RequestSessionBase):
     def __init__(self, repo=None, user=None):
         self.repo = repo
-        self.vreg = getattr(self.repo, 'vreg', FakeVReg())
+        self.vreg = getattr(self.repo, 'vreg', CubicWebVRegistry(FakeConfig(), initlog=False))
         self.pool = FakePool()
         self.user = user or FakeUser()
         self.is_internal_session = False
@@ -209,8 +165,9 @@
         self.eids = {}
         self._count = 0
         self.schema = schema
-        self.vreg = vreg or FakeVReg()
         self.config = config or FakeConfig()
+        self.vreg = vreg or CubicWebVRegistry(self.config, initlog=False)
+        self.vreg.schema = schema
 
     def internal_session(self):
         return FakeSession(self)
@@ -248,10 +205,3 @@
 class FakePool(object):
     def source(self, uri):
         return FakeSource(uri)
-
-# commented until proven to be useful
-## from logging import getLogger
-## from cubicweb import set_log_methods
-## for cls in (FakeConfig, FakeVReg, FakeRequest, FakeSession, FakeRepo,
-##             FakeSource, FakePool):
-##     set_log_methods(cls, getLogger('fake'))
--- a/devtools/repotest.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/devtools/repotest.py	Thu Sep 17 15:16:53 2009 +0200
@@ -108,9 +108,10 @@
     schema = None # set this in concret test
 
     def setUp(self):
+        self.repo = FakeRepo(self.schema)
         self.rqlhelper = RQLHelper(self.schema, special_relations={'eid': 'uid',
                                                                    'has_text': 'fti'})
-        self.qhelper = QuerierHelper(FakeRepo(self.schema), self.schema)
+        self.qhelper = QuerierHelper(self.repo, self.schema)
         ExecutionPlan._check_permissions = _dummy_check_permissions
         rqlannotation._select_principal = _select_principal
 
@@ -129,7 +130,7 @@
         #print '********* solutions', solutions
         self.rqlhelper.simplify(union)
         #print '********* simplified', union.as_string()
-        plan = self.qhelper.plan_factory(union, {}, FakeSession())
+        plan = self.qhelper.plan_factory(union, {}, FakeSession(self.repo))
         plan.preprocess(union)
         for select in union.children:
             select.solutions.sort()
@@ -167,7 +168,7 @@
         set_debug(debug)
 
     def _rqlhelper(self):
-        rqlhelper = self.o._rqlhelper
+        rqlhelper = self.repo.vreg.rqlhelper
         # reset uid_func so it don't try to get type from eids
         rqlhelper._analyser.uid_func = None
         rqlhelper._analyser.uid_func_mapping = {}
@@ -241,7 +242,7 @@
         rqlst = self.o.parse(rql, annotate=True)
         self.o.solutions(self.session, rqlst, kwargs)
         if rqlst.TYPE == 'select':
-            self.o._rqlhelper.annotate(rqlst)
+            self.repo.vreg.rqlhelper.annotate(rqlst)
             for select in rqlst.children:
                 select.solutions.sort()
         else:
@@ -251,7 +252,7 @@
 
 # monkey patch some methods to get predicatable results #######################
 
-from cubicweb.server.rqlrewrite import RQLRewriter
+from cubicweb.rqlrewrite import RQLRewriter
 _orig_insert_snippets = RQLRewriter.insert_snippets
 _orig_build_variantes = RQLRewriter.build_variantes
 
--- a/doc/book/en/development/datamodel/definition.rst	Tue Sep 15 15:01:41 2009 +0200
+++ b/doc/book/en/development/datamodel/definition.rst	Thu Sep 17 15:16:53 2009 +0200
@@ -89,7 +89,7 @@
     * `*`: 0..n
 
   - `meta` : boolean indicating that the relation is a meta-relation (false by
-    default)
+    default, will disappear in *CubicWeb* 3.5)
 
 * optional properties for attributes :
 
@@ -216,8 +216,8 @@
 of the cube (``migration/precreate.py``).
 
 
-Use of RQL expression for writing rights
-`````````````````````````````````````````
+Use of RQL expression for write permissions
+```````````````````````````````````````````
 It is possible to define RQL expression to provide update permission
 (`add`, `delete` and `update`) on relation and entity types.
 
@@ -249,7 +249,7 @@
 * we can also defined rights on attributes of an entity (non-final relation),
   knowing that :
 
-  - to defines RQL expression, we have to use the class `RQLExpression`
+  - to define RQL expression, we have to use the class `RQLExpression`
     in which X represents the entity the attribute belongs to
 
   - the permissions `add` and `delete` are equivalent. Only `add`/`read`
@@ -321,7 +321,7 @@
     attr_name = attr_type(properties*)
 
 where `attr_type` is one of the type listed above and `properties` is
-a list of  the attribute needs to statisfy (see :ref:`properties`
+a list of the attribute needs to statisfy (see :ref:`properties`
 for more details).
 
 
@@ -434,6 +434,6 @@
 * in such case, we have to protect both the entity type "Version" and the relation
   associating a version to a project ("version_of")
 
-* because of the genricity of the entity type `CWPermission`, we have to execute
+* because of the genericity of the entity type `CWPermission`, we have to execute
   a unification with the groups and/or the states if necessary in the expression
   ("U in_group G, P require_group G" in the above example)
--- a/doc/book/en/development/datamodel/inheritance.rst	Tue Sep 15 15:01:41 2009 +0200
+++ b/doc/book/en/development/datamodel/inheritance.rst	Thu Sep 17 15:16:53 2009 +0200
@@ -5,4 +5,14 @@
 When describing a data model, entities can inherit from other entities as is
 common in object-oriented programming.
 
+You have the possibility to adapt some entity attributes, as follow:
+
+.. sourcecode:: python
+
+    from cubes.OTHER_CUBE import entities
+    class EntityExample(entities.EntityExample):
+        def dc_long_title(self):
+            return '%s (%s)' % (self.name, self.description)
+
+
 XXX WRITME
--- a/doc/book/en/development/devcore/appobject.rst	Tue Sep 15 15:01:41 2009 +0200
+++ b/doc/book/en/development/devcore/appobject.rst	Thu Sep 17 15:16:53 2009 +0200
@@ -16,7 +16,7 @@
 We can find a certain number of attributes and methods defined in this class
 and common to all the application objects.
 
-At the recording, the following attributes are dynamically added to
+At recording time, the following attributes are dynamically added to
 the *subclasses*:
 
 * `vreg`, the `vregistry` of the instance
@@ -27,28 +27,15 @@
 
 * `req`, `Request` instance
 * `rset`, the *result set* associated to the object if necessary
-* `cursor`, rql cursor on the session
-
 
 :URL handling:
-  * `build_url(method=None, **kwargs)`, returns an absolute URL based on
-    the given arguments. The *controller* supposed to handle the response,
-    can be specified through the special parameter `method` (the connection
-    is theoretically done automatically :).
-
-  * `datadir_url()`, returns the directory of the instance data
-    (contains static files such as images, css, js...)
-
-  * `base_url()`, shortcut to `req.base_url()`
-
-  * `url_quote(value)`, version *unicode safe* of the function `urllib.quote`
+  * `build_url(*args, **kwargs)`, returns an absolute URL based on the
+    given arguments. The *controller* supposed to handle the response,
+    can be specified through the first positional parameter (the
+    connection is theoretically done automatically :).
 
 :Data manipulation:
 
-  * `etype_rset(etype, size=1)`, shortcut to `vreg.etype_rset()`
-
-  * `eid_rset(eid, rql=None, descr=True)`, returns a *result set* object for
-    the given eid
   * `entity(row, col=0)`, returns the entity corresponding to the data position
     in the *result set* associated to the object
 
@@ -57,15 +44,12 @@
 
 :Data formatting:
   * `format_date(date, date_format=None, time=False)` returns a string for a
-    mx date time according to instance's configuration
-  * `format_time(time)` returns a string for a mx date time according to
+    date time according to instance's configuration
+  * `format_time(time)` returns a string for a date time according to
     instance's configuration
 
 :And more...:
 
-  * `external_resource(rid, default=_MARKER)`, access to a value defined in the
-    configuration file `external_resource`
-
   * `tal_render(template, variables)`, renders a precompiled page template with
     variables in the given dictionary as context
 
@@ -73,13 +57,14 @@
   When we inherit from `AppObject` (even not directly), you *always* have to use
   **super()** to get the methods and attributes of the superclasses, and not
   use the class identifier.
+
   For example, instead of writting: ::
 
       class Truc(PrimaryView):
           def f(self, arg1):
               PrimaryView.f(self, arg1)
 
-  You'd better write: ::
+  You must write: ::
 
       class Truc(PrimaryView):
           def f(self, arg1):
--- a/doc/book/en/development/devcore/vreg.rst	Tue Sep 15 15:01:41 2009 +0200
+++ b/doc/book/en/development/devcore/vreg.rst	Thu Sep 17 15:16:53 2009 +0200
@@ -22,16 +22,15 @@
     Once the function `registration_callback(vreg)` is implemented, all the objects
     have to be explicitly registered as it disables the automatic object registering.
 
-* the old registration mechanism will be removed when there will be no reference
-  left to the registerers module in cubicweb and the library of cubes.
-
 Examples:
 
 .. sourcecode:: python
 
    # web/views/basecomponents.py
    def registration_callback(vreg):
+      # register everything in the module except SeeAlsoComponent
       vreg.register_all(globals().values(), __name__, (SeeAlsoVComponent,))
+      # conditionally register SeeAlsoVComponent
       if 'see_also' in vreg.schema:
           vreg.register(SeeAlsoVComponent)
 
@@ -66,7 +65,7 @@
 
 The object's selector is defined by its `__select__` class attribute.
 
-When two selectors are combined using the `&` operator (former `chainall`), it
+When two selectors are combined using the `&` operator (formerly `chainall`), it
 means that both should return a positive score. On success, the sum of scores is returned.
 
 When two selectors are combined using the `|` operator (former `chainfirst`), it
@@ -76,38 +75,38 @@
 Of course you can use paren to balance expressions.
 
 
-For instance, if you're selecting the primary (eg `id = 'primary'`) view (eg
+For instance, if you are selecting the primary (eg `id = 'primary'`) view (eg
 `__registry__ = 'view'`) for a result set containing a `Card` entity, 2 objects
 will probably be selectable:
 
-* the default primary view (`__select__ = implements('Any')`), meaning that the object is selectable for any kind of entity type
-
-* the specific `Card` primary view (`__select__ = implements('Card')`, meaning that the object is selectable for Card entities
+* the default primary view (`__select__ = implements('Any')`), meaning
+  that the object is selectable for any kind of entity type
 
-Other primary views specific to other entity types won't be selectable in this
-case. Among selectable objects, the implements selector will return a higher score
-to the second view since it's more specific, so it will be selected as expected.
+* the specific `Card` primary view (`__select__ = implements('Card')`,
+  meaning that the object is selectable for Card entities
+
+Other primary views specific to other entity types won't be selectable
+in this case. Among selectable objects, the implements selector will
+return a higher score than the second view since it's more specific,
+so it will be selected as expected.
 
 
 Example
 ````````
 
-XXX this part needs to be translated
-
-The goal : when on a Blog, one wants the RSS link to refer to blog
+The goal: when on a Blog, one wants the RSS link to refer to blog
 entries, not to the blog entity itself.
 
 To do that, one defines a method on entity classes that returns the
-RSS stream url for a given entity. With a default implementation on
-AnyEntity and a specific implementation on Blog, which will do what we
-want.
+RSS stream url for a given entity. The default implementation on
+AnyEntity and a specific implementation on Blog will do what we want.
 
-There's a limitation to this schema : when we have a result set
-containing several Blog entities (or different entities), we don't
-know on which entity to call the aforementioned method. In this case,
-we keep the current behaviour (e.g : call to limited_rql).
+But when we have a result set containing several Blog entities (or
+different entities), we don't know on which entity to call the
+aforementioned method. In this case, we keep the current behaviour
+(e.g : call to limited_rql).
 
-Hence we want two cases here, one for a single-entity rsets, the other
+Hence we have two cases here, one for a single-entity rsets, the other
 for multi-entities rsets.
 
 In web/views/boxes.py lies the RSSIconBox class. Look at its selector ::
@@ -116,7 +115,7 @@
     """just display the RSS icon on uniform result set"""
     __select__ = ExtResourcesBoxTemplate.__select__ & non_final_entity()
 
-It takes into account :
+It takes into account:
 
 * the inherited selection criteria (one has to look them up in the
   class hierarchy to know the details)
@@ -125,7 +124,7 @@
   entities (a 'final entity' being synonym for entity attribute)
 
 This matches our second case. Hence we have to provide a specific
-component for the first case ::
+component for the first case::
 
   class EntityRSSIconBox(RSSIconBox):
     """just display the RSS icon on uniform result set for a single entity"""
@@ -152,7 +151,7 @@
 ```````````````````````
 
 Selectors are to be used whenever arises the need of dispatching on
-the shape or content of a result set.
+the shape or content of a result set. That is, almost all the time.
 
 Debugging
 `````````
--- a/doc/book/en/development/devweb/internationalization.rst	Tue Sep 15 15:01:41 2009 +0200
+++ b/doc/book/en/development/devweb/internationalization.rst	Thu Sep 17 15:16:53 2009 +0200
@@ -45,7 +45,8 @@
 
 The goal of the *built-in* function `_` is only **to mark the
 translatable strings**, it will only return the string to translate
-it-self, but not its translation (it's actually refering to the `unicode` builtin).
+itself, but not its translation (it's actually another name for the
+`unicode` builtin).
 
 In the other hand the request's method `self.req._` is meant to retrieve the
 proper translation of translation strings in the requested language.
@@ -81,8 +82,8 @@
 
 
 * `i18ncubicweb` updates Cubicweb framework's translation
-  catalogs. Unless you work on the framework development, you don't
-  need to use this command.
+  catalogs. Unless you actually work on the framework itself, you
+  don't need to use this command.
 
 * `i18ncube` updates the translation catalogs of *one particular
   cube* (or of all cubes). After this command is
@@ -90,7 +91,7 @@
   directory of your template. This command will of course not remove
   existing translations still in use.
 
-* `i18ninstance` recompile the translation catalogs of *one particular
+* `i18ninstance` recompiles the translation catalogs of *one particular
   instance* (or of all instances) after the translation catalogs of
   its cubes have been updated. This command is automatically
   called every time you create or update your instance. The compiled
--- a/doc/book/en/development/devweb/js.rst	Tue Sep 15 15:01:41 2009 +0200
+++ b/doc/book/en/development/devweb/js.rst	Thu Sep 17 15:16:53 2009 +0200
@@ -3,16 +3,70 @@
 Javascript
 ----------
 
-XXX jquery...
+*CubicWeb* uses quite a bit of javascript in its user interface and
+ships with jquery (1.3.x) and parts of the jquery UI
+library, plus a number of homegrown files and also other thirparty
+libraries.
+
+All javascript files are stored in cubicweb/web/data/. There are
+around thirty js files there. In a cube it goes to data/.
+
+Obviously one does not want javascript pieces to be loaded all at
+once, hence the framework provides a number of mechanisms and
+conventions to deal with javascript resources.
 
 Conventions
 ~~~~~~~~~~~
 
-XXX external_resources variable
-    naming convention
-    request.add_js
+It is good practice to name cube specific js files after the name of
+the cube, like this : 'cube.mycube.js', so as to avoid name clashes.
 
+XXX external_resources variable (which needs love)
 
 CubicWeb javascrip api
 ~~~~~~~~~~~~~~~~~~~~~~
-XXX explain diffenrent files and main functions
+
+Javascript resources are typically loaded on demand, from views. The
+request object (available as self.req from most application objects,
+for instance views and entities objects) has a few methods to do that:
+
+* `add_js(self, jsfiles, localfile=True)` which takes a sequence of
+  javascript files and writes proper entries into the HTML header
+  section. The localfile parameter allows to declare resources which
+  are not from web/data (for instance, residing on a content delivery
+  network).
+
+* `add_onload(self, jscode)` which adds one raw javascript code
+  snippet inline in the html headers. This is quite useful for setting
+  up early jQuery(document).ready(...) initialisations.
+
+Overview of what's available
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+* jquery.* : jquery and jquery UI library
+
+* cubicweb.python.js : adds a number of practical extension to stdanrd
+  javascript objects (on Date, Array, String, some list and dictionary
+  operations), and a pythonesque way to build classes. Defines a
+  CubicWeb namespace.
+
+* cubicweb.htmlhelpers.js : a small bag of convenience functions used
+  in various other cubicweb javascript resources (baseuri, progress
+  cursor handling, popup login box, html2dom function, etc.)
+
+* cubicweb.ajax.js : concentrates all ajax related facilities (it
+  extends jQuery with the loahxhtml function, provides a handfull of
+  high-level ajaxy operations like asyncRemoteExec, reloadComponent,
+  replacePageChunk, getDomFromResponse)
+
+* cubicweb.widgets.js : provides a widget namespace and constructors
+  and helpers for various widgets (mainly facets and timeline)
+
+* cubicweb.edition.js : used by edition forms
+
+* cubicweb.preferences.js : used by the preference form
+
+* cubicweb.facets.js : used by the facets mechanism
+
+xxx massmailing, gmap, fckcwconfig, timeline-bundle, timeline-ext,
+calendar, goa, flotn tazy, tabs, bookmarks
--- a/doc/book/en/development/devweb/views.rst	Tue Sep 15 15:01:41 2009 +0200
+++ b/doc/book/en/development/devweb/views.rst	Thu Sep 17 15:16:53 2009 +0200
@@ -34,26 +34,32 @@
     * the `category` attribute may be used in the interface to regroup related
       objects together
 
-At instantiation time, the standard `req`, `rset`, and `cursor`
-attributes are added and the `w` attribute will be set at rendering
-time.
+At instantiation time, the standard `req` and `rset` attributes are
+added and the `w` attribute will be set at rendering time.
 
-A view writes to its output stream thanks to its attribute `w` (`UStreamIO`).
+A view writes to its output stream thanks to its attribute `w` (an
+`UStreamIO`).
 
 The basic interface for views is as follows (remember that the result set has a
 tabular structure with rows and columns, hence cells):
 
-* `dispatch(**context)`, render the view by calling `call` or
+* `render(**context)`, render the view by calling `call` or
   `cell_call` depending on the given parameters
-* `call(**kwargs)`, call the view for a complete result set or null (default
-  implementation calls `cell_call()` on each cell of the result set)
-* `cell_call(row, col, **kwargs)`, call the view for a given cell of a result set
+
+* `call(**kwargs)`, call the view for a complete result set or null
+  (the default implementation calls `cell_call()` on each cell of the
+  result set)
+
+* `cell_call(row, col, **kwargs)`, call the view for a given cell of a
+  result set
+
 * `url()`, returns the URL enabling us to get the view with the current
   result set
+
 * `view(__vid, rset, __fallback_vid=None, **kwargs)`, call the view of identifier
   `__vid` on the given result set. It is possible to give a view identifier
   of fallback that will be used if the view requested is not applicable to the
-  result set
+  result set. This is actually defined on the AppObject class.
 
 * `wview(__vid, rset, __fallback_vid=None, **kwargs)`, similar to `view` except
   the flow is automatically passed in the parameters
@@ -70,8 +76,8 @@
 
 * `EntityView`, view applying to lines or cell containing an entity (e.g. an eid)
 * `StartupView`, start view that does not require a result set to apply to
-* `AnyRsetView`, view applied to any result set
-* `EmptyRsetView`, view applied to an empty result set
+* `AnyRsetView`, view applicable to any result set
+* `EmptyRsetView`, view applicable to an empty result set
 
 
 Examples of views class
@@ -103,11 +109,8 @@
         __select__ = one_line_rset() & match_search_state('linksearch') & implements('Any')
 
 
-Example of a view customization
--------------------------------
-
-[FIXME] XXX Example needs to be rewritten as it shows how to modify cell_call which
-contredicts our advise of not modifying it.
+Example of view customization and creation
+------------------------------------------
 
 We'll show you now an example of a ``primary`` view and how to customize it.
 
@@ -116,32 +119,26 @@
 
 .. sourcecode:: python
 
-   from cubicweb.view import EntityView
-   from cubicweb.selectors import implements
+  from cubicweb.selectors import implements
+  from cubicweb.web.views.primary improt Primaryview
 
-   class BlogEntryPrimaryView(EntityView):
-       id = 'primary'
-       __select__ =implements('Blog')
+  class BlogEntryPrimaryView(PrimaryView):
+    __select__ = PrimaryView.__select__ & implements('BlogEntry')
 
-       def cell_call(self, row, col):
-           entity = self.rset.get_entity(row, col)
-           self.w(u'<h1>%s</h1>' % entity.title)
-           self.w(u'<p>published on %s in category %s</p>' % \
-                  (entity.publish_date.strftime('%Y-%m-%d'), entity.category))
-           self.w(u'<p>%s</p>' % entity.text)
+      def render_entity_attributes(self, entity):
+          self.w(u'<p>published on %s</p>' %
+                 entity.publish_date.strftime('%Y-%m-%d'))
+          super(BlogEntryPrimaryView, self).render_entity_attributes(entity)
 
-The above source code defines a new primary view (`line 03`) for
-``BlogEntry`` (`line 05`).
+The above source code defines a new primary view for
+``BlogEntry``. The `id` class attribute is not repeated there since it
+is inherited through the `primary.PrimaryView` class.
 
-Since views are applied to result sets which can be tables of
-data, we have to recover the entity from its (row,col)-coordinates (`line 08`).
-We will get to this in more detail later.
+The selector for this view chains the selector of the inherited class
+with its own specific criterion.
 
 The view method ``self.w()`` is used to output data. Here `lines
-09-12` output HTML tags and values of the entity's attributes.
-
-When displaying the same blog entry as before, you will notice that the
-page is now looking much nicer. [FIXME: it is not clear to what this refers.]
+08-09` output HTML for the publication date of the entry.
 
 .. image:: ../../images/lax-book.09-new-view-blogentry.en.png
    :alt: blog entries now look much nicer
@@ -150,34 +147,74 @@
 
 .. sourcecode:: python
 
- class BlogPrimaryView(EntityView):
+ from logilab.mtconverter import xml_escape
+ from cubicweb.selectors import implements, one_line_rset
+ from cubicweb.web.views.primary import Primaryview
+
+ class BlogPrimaryView(PrimaryView):
      id = 'primary'
-     __select__ =implements('Blog')
+     __select__ = PrimaryView.__select__ & implements('Blog')
+     rql = 'Any BE ORDERBY D DESC WHERE BE entry_of B, BE publish_date D, B eid %(b)s'
+
+     def render_entity_relations(self, entity):
+         rset = self.req.execute(self.rql, {'b' : entity.eid})
+         for entry in rset.entities():
+             self.w(u'<p>%s</p>' % entry.view('inblogcontext'))
+
+ class BlogEntryInBlogView(EntityView):
+     id = 'inblogcontext'
+     __select__ = implements('BlogEntry')
 
      def cell_call(self, row, col):
          entity = self.rset.get_entity(row, col)
-         self.w(u'<h1>%s</h1>' % entity.title)
-         self.w(u'<p>%s</p>' % entity.description)
-         rset = self.req.execute('Any E WHERE E entry_of B, B eid "%s"' % entity.eid)
-         self.wview('primary', rset)
+         self.w(u'<a href="%s" title="%s">%s</a>' %
+                entity.absolute_url(),
+                xml_escape(entity.content[:50]),
+                xml_escape(entity.description))
 
-In the above source code, `lines 01-08` are similar to the previous
-view we defined. [FIXME: defined where ?]
+This happens in two places. First we override the
+render_entity_relations method of a Blog's primary view. Here we want
+to display our blog entries in a custom way.
 
-At `line 09`, a simple request is made to build a result set with all
+At `line 10`, a simple request is made to build a result set with all
 the entities linked to the current ``Blog`` entity by the relationship
 ``entry_of``. The part of the framework handling the request knows
-about the schema and infer that such entities have to be of the
-``BlogEntry`` kind and retrieves them.
+about the schema and infers that such entities have to be of the
+``BlogEntry`` kind and retrieves them (in the prescribed publish_date
+order).
+
+The request returns a selection of data called a result set. Result
+set objects have an .entities() method returning a generator on
+requested entities (going transparently through the `ORM` layer).
+
+At `line 13` the view 'inblogcontext' is applied to each blog entry to
+output HTML. (Note that the 'inblogcontext' view is not defined
+whatsoever in *CubicWeb*. You are absolutely free to define whole view
+families.) We juste arrange to wrap each blogentry output in a 'p'
+html element.
 
-The request returns a selection of data called a result set. At
-`line 10` the view 'primary' is applied to this result set to output
-HTML.
+Next, we define the 'inblogcontext' view. This is NOT a primary view,
+with its well-defined sections (title, metadata, attribtues,
+relations/boxes). All a basic view has to define is cell_call.
+
+Since views are applied to result sets which can be tables of data, we
+have to recover the entity from its (row,col)-coordinates (`line
+20`). Then we can spit some HTML.
+
+But careful: all strings manipulated in *CubicWeb* are actually
+unicode strings. While web browsers are usually tolerant to incoherent
+encodings they are being served, we should not abuse it. Hence we have
+to properly escape our data. The xml_escape() function has to be used
+to safely fill (X)HTML elements from Python unicode strings.
+
 
 **This is to be compared to interfaces and protocols in object-oriented
 languages. Applying a given view called 'a_view' to all the entities
 of a result set only requires to have for each entity of this result set,
-an available view called 'a_view' which accepts the entity.**
+an available view called 'a_view' which accepts the entity.
+
+Instead of merely using type based dispatch, we do predicate dispatch
+which quite more powerful**
 
 Assuming we added entries to the blog titled `MyLife`, displaying it
 now allows to read its description and all its entries.
--- a/doc/book/en/development/entityclasses/data-as-objects.rst	Tue Sep 15 15:01:41 2009 +0200
+++ b/doc/book/en/development/entityclasses/data-as-objects.rst	Thu Sep 17 15:16:53 2009 +0200
@@ -1,7 +1,8 @@
 Access to persistent data
 --------------------------
 
-XXX is provided by the :class:`Entity <cubicweb.entity.entity>` class
+Python-level access to persistent data is provided by the
+:class:`Entity <cubicweb.entity>` class.
 
 An entity class is bound to a schema entity type.  Descriptors are added when
 classes are registered in order to initialize the class according to its schema:
@@ -22,8 +23,6 @@
 
   * `rest_path()`, returns a relative REST URL to get the entity
 
-  * `format(attr)`, returns the format (MIME type) of the field given un parameter
-
   * `printable_value(attr, value=_marker, attrtype=None, format='text/html')`,
     returns a string enabling the display of an attribute value in a given format
     (the value is automatically recovered if necessary)
@@ -33,7 +32,7 @@
   * `as_rset()`, converts the entity into an equivalent result set simulating the
      request `Any X WHERE X eid _eid_`
 
-  * `complete(skip_bytes=True)`, executes a request that recovers in one time
+  * `complete(skip_bytes=True)`, executes a request that recovers all at once
     all the missing attributes of an entity
 
   * `get_value(name)`, returns the value associated to the attribute name given
@@ -52,9 +51,6 @@
   * `copy_relations(ceid)`, copies the relations of the entities having the eid
     given in the parameters on the current entity
 
-  * `last_modified(view)`, returns the date the object has been modified
-    (used by HTTP cache handling)
-
   * `delete()` allows to delete the entity
 
 
@@ -66,24 +62,25 @@
 in `mycube.entities` module (or in a submodule if we want to split code among
 multiple files) so that it will be available on both server and client side.
 
-The class `AnyEntity` is loaded dynamically from the class `Entity`
-(`cubciweb.entity`). We define a sub-class to add methods or to
-specialize the handling of a given entity type
+The class `AnyEntity` is a sub-class of Entity that add methods to it,
+and helps specializing (by further subclassing) the handling of a
+given entity type.
 
-The methods defined for `AnyEntity` or `Entity` are the following ones:
+The methods defined for `AnyEntity`, in addition to `Entity`, are the
+following ones:
 
 :Standard meta-data (Dublin Core):
 
-  * `dc_title()`, returns a unicode string corresponding to the meta-data
-    `Title` (used by default the first attribute non-meta of the entity
-    schema)
+  * `dc_title()`, returns a unicode string corresponding to the
+    meta-data `Title` (used by default is the first non-meta attribute
+    of the entity schema)
 
   * `dc_long_title()`, same as dc_title but can return a more
-    detailled title
+    detailed title
 
   * `dc_description(format='text/plain')`, returns a unicode string
-    corresponding to the meta-data `Description` (look for a description
-    attribute by default)
+    corresponding to the meta-data `Description` (looks for a
+    description attribute by default)
 
   * `dc_authors()`, returns a unicode string corresponding to the meta-data
     `Authors` (owners by default)
--- a/doc/book/en/development/webstdlib/baseviews.rst	Tue Sep 15 15:01:41 2009 +0200
+++ b/doc/book/en/development/webstdlib/baseviews.rst	Thu Sep 17 15:16:53 2009 +0200
@@ -30,10 +30,11 @@
 Entity views
 ````````````
 *incontext, outofcontext*
-    Those are used to display a link to an entity, depending if the entity is
-    considered as displayed in or out of context (of another entity).  By default
-    it respectively returns the result of `textincontext` and `textoutofcontext`
-    wrapped in a link leading to the primary view of the entity.
+    Those are used to display a link to an entity, depending on the
+    entity having to be displayed in or out of context
+    (of another entity).  By default it respectively returns the
+    result of `textincontext` and `textoutofcontext` wrapped in a link
+    leading to the primary view of the entity.
 
 *oneline*
     This view is used when we can't tell if the entity should be considered as
@@ -56,6 +57,12 @@
 *adaptedlistitem*
     This view redirects by default to the `outofcontext` view.
 
+*csv*
+    This view applies to entity groups, which are individually
+    displayed using the `incontext` view. It displays each entity as a
+    coma separated list. It is NOT related to the well-known text file
+    format.
+
 Text entity views
 ~~~~~~~~~~~~~~~~~
 *text*
--- a/doc/book/en/development/webstdlib/primary.rst	Tue Sep 15 15:01:41 2009 +0200
+++ b/doc/book/en/development/webstdlib/primary.rst	Thu Sep 17 15:16:53 2009 +0200
@@ -9,8 +9,9 @@
 Rendering methods and attributes for ``PrimaryView``
 ----------------------------------------------------
 
-By default, *CubicWeb* provides a primary view for each new entity type
-you create. The first view you might be interested in modifying.
+By default, *CubicWeb* provides a primary view for every available
+entity type. This is the first view you might be interested in
+modifying.
 
 Let's have a quick look at the EntityView ``PrimaryView`` as well as
 its rendering method
@@ -24,55 +25,63 @@
         show_attr_label = True
         show_rel_label = True
         skip_none = True
-        skip_attrs = ('eid', 'creation_date', 'modification_date')
-        skip_rels = ()
+        rsection = uicfg.primaryview_section
+        display_ctrl = uicfg.primaryview_display_ctrl
         main_related_section = True
 
         ...
 
     def cell_call(self, row, col):
         self.row = row
-        self.render_entity(self.complete_entity(row, col))
+        self.maxrelated = self.req.property_value('navigation.related-limit')
+        entity = self.complete_entity(row, col)
+        self.render_entity(entity)
 
     def render_entity(self, entity):
-        """return html to display the given entity"""
-        siderelations = []
         self.render_entity_title(entity)
         self.render_entity_metadata(entity)
         # entity's attributes and relations, excluding meta data
         # if the entity isn't meta itself
-        self.w(u'<div>')
+        boxes = self._prepare_side_boxes(entity)
+        if boxes or hasattr(self, 'render_side_related'):
+            self.w(u'<table width="100%"><tr><td style="width: 75%">')
+        self.render_entity_summary(entity)
         self.w(u'<div class="mainInfo">')
-        self.render_entity_attributes(entity, siderelations)
-        self.w(u'</div>')
         self.content_navigation_components('navcontenttop')
+        self.render_entity_attributes(entity)
         if self.main_related_section:
-            self.render_entity_relations(entity, siderelations)
+            self.render_entity_relations(entity)
         self.w(u'</div>')
         # side boxes
-        self.w(u'<div class="primaryRight">')
-        self.render_side_related(entity, siderelations)
-        self.w(u'</div>')
-        self.w(u'<div class="clear"></div>')
+        if boxes or hasattr(self, 'render_side_related'):
+            self.w(u'</td><td>')
+            self.w(u'<div class="primaryRight">')
+            if hasattr(self, 'render_side_related'):
+                warn('render_side_related is deprecated')
+                self.render_side_related(entity, [])
+            self.render_side_boxes(boxes)
+            self.w(u'</div>')
+            self.w(u'</td></tr></table>')
         self.content_navigation_components('navcontentbottom')
 
     ...
 
-``cell_call`` is executed for each entity of a result set and apply ``render_entity``.
+``cell_call`` is executed for each entity of a result set.
 
 The methods you want to modify while customizing a ``PrimaryView`` are:
 
 *render_entity_title(self, entity)*
     Renders the entity title based on the assumption that the method
-    ``def content_title(self)`` is implemented for the given entity type.
+    ``def dc_title(self)`` is implemented for the given entity type.
 
 *render_entity_metadata(self, entity)*
-    Renders the entity metadata based on the assumption that the method
-    ``def summary(self)`` is implemented for the given entity type.
+    Renders the entity metadata by calling the 'metadata' view on the
+    entity. This generic view is in cubicweb.views.baseviews.
 
-*render_entity_attributes(self, entity, siderelations)*
-    Renders all the attribute of an entity with the exception of attribute
-    of type `Password` and `Bytes`.
+*render_entity_attributes(self, entity)*
+    Renders all the attribute of an entity with the exception of
+    attribute of type `Password` and `Bytes`. The skip_none class
+    attribute controls the display of None valued attributes.
 
 *content_navigation_components(self, context)*
     This method is applicable only for entity type implementing the interface
@@ -81,15 +90,15 @@
     entities of this type, either at the top or at the bottom of the page
     given the context (navcontent{top|bottom}).
 
-*render_entity_relations(self, entity, siderelations)*
+*render_entity_relations(self, entity)*
     Renders all the relations of the entity in the main section of the page.
 
-*render_side_related(self, entity, siderelations)*
+*render_side_boxes(self, entity, boxes)*
     Renders all the relations of the entity in a side box. This is equivalent
     to *render_entity_relations* in addition to render the relations
     in a box.
 
-Also, please note that by setting the following attributes in you class,
+Also, please note that by setting the following attributes in your class,
 you can already customize some of the rendering:
 
 *show_attr_label*
--- a/doc/book/en/intro/concepts/index.rst	Tue Sep 15 15:01:41 2009 +0200
+++ b/doc/book/en/intro/concepts/index.rst	Thu Sep 17 15:16:53 2009 +0200
@@ -59,15 +59,15 @@
 
 .. image:: ../../images/archi_globale.en.png
 
-The command ``cubicweb-ctl list`` displays the list of instances installed on
-your system.
+The command ``cubicweb-ctl list`` also displays the list of instances
+installed on your system.
 
 On a Unix system, the instances are usually stored in the directory
 :file:`/etc/cubicweb.d/`. During development, the :file:`~/etc/cubicweb.d/`
 directory is looked up, as well as the paths in :envvar:`CW_INSTANCES_DIR`
 environment variable.
 
-The term application is used to refer at "something that should do something as a
+The term application is used to refer to "something that should do something as a
 whole", eg more like a project and so can refer to an instance or to a cube,
 depending on the context. This book will try to use *application*, *cube* and
 *instance* as appropriate.
@@ -77,7 +77,7 @@
 
 The data repository [#]_ provides access to one or more data sources (including
 SQL databases, LDAP repositories, Mercurial or Subversion version control
-systems, other CubicWeb repositories, GAE's DataStore, etc).
+systems, other CubicWeb instance repositories, GAE's DataStore, etc).
 
 All interactions with the repository are done using the Relation Query Language
 (RQL). The repository federates the data sources and hides them from the
@@ -99,13 +99,13 @@
 Web Engine
 ----------
 
-The web engine replies to http requests and runs the user interface and most of
-the application logic.
+The web engine replies to http requests and runs the user interface
+and most of the application logic.
 
-By default the web engine provides a generated user interface based on the data
-model of the instance. Entities can be created, displayed, updated and
-deleted. As the default user interface is not very fancy, it is usually
-necessary to develop your own.
+By default the web engine provides a default user interface based on
+the data model of the instance. Entities can be created, displayed,
+updated and deleted. As the default user interface is not very fancy,
+it is usually necessary to develop your own.
 
 Schema (Data Model)
 -------------------
@@ -120,7 +120,7 @@
 `Date`, `Time`, `Datetime`, `Interval`, `Password`, `Bytes`, `RichString`. See
 :ref:`yams.BASE_TYPES` for details.
 
-A `relation type` is used to define a binary oriented relation between two
+A `relation type` is used to define an oriented binary relation between two
 entity types.  The left-hand part of a relation is named the `subject` and the
 right-hand part is named the `object`.
 
@@ -143,8 +143,6 @@
 Registries and Objects
 ----------------------
 
-XXX registry, register, registries, registers ???
-
 Application objects
 ~~~~~~~~~~~~~~~~~~~
 
@@ -159,15 +157,15 @@
 
   object's `__registry__` : object's `id` : [list of app objects]
 
-The base class of appobjects is `AppRsetObject` (module `cubicweb.appobject`).
+The base class of appobjects is `AppObject` (module `cubicweb.appobject`).
 
 The `vregistry`
 ~~~~~~~~~~~~~~~
 
-At startup, the `registry` or registers base, inspects a number of directories
-looking for compatible classes definition. After a recording process, the objects
-are assigned to registers so that they can be selected dynamically while the
-instance is running.
+At startup, the `registry` inspects a number of directories looking
+for compatible classes definition. After a recording process, the
+objects are assigned to registers so that they can be selected
+dynamically while the instance is running.
 
 Selectors
 ~~~~~~~~~
@@ -185,7 +183,7 @@
   that case, the object with the greatest score is selected. There should always
   be a single appobject with a greater score than others.
 
-* get all appobjects applying to a context by specifying a registry.In
+* get all appobjects applying to a context by specifying a registry. In
   that case, every object with the a postive score is selected.
 
 * get the object within a particular registry/identifier. In that case no
@@ -195,10 +193,9 @@
 Selector sets are the glue that tie views to the data model. Using them
 appropriately is an essential part of the construction of well behaved cubes.
 
-
 When no score is higher than the others, an exception is raised in development
 mode to let you know that the engine was not able to identify the view to
-apply. This error is silented in production mode and one of the objects with the
+apply. This error is silenced in production mode and one of the objects with the
 higher score is picked.
 
 If no object has a positive score, ``NoSelectableObject`` exception is raised.
@@ -231,7 +228,14 @@
 Result set
 ~~~~~~~~~~
 
-XXX feed me
+Every request made (using RQL) to the data repository returns an
+object we call a Result Set. It enables easy use of the retrieved
+data, providing a translation layer between the backend's native
+datatypes and *CubicWeb* schema's EntityTypes.
+
+Result sets provide access to the raw data, yielding either basic
+Python data types, or schema-defined high-level entities, in a
+straightforward way.
 
 
 Views
@@ -239,6 +243,10 @@
 
 ** *CubicWeb* is data driven **
 
+The view system is loosely coupled to data through a selection
+system. Views are, in essence, defined by an id, a selection predicate
+and an entry point (generaly producing html).
+
 XXX feed me.
 
 
@@ -246,4 +254,31 @@
 -----
 ** *CubicWeb* provides an extensible data repository **
 
-XXX feed me.
+The data model defined using Yams types allows to express the data
+model in a comfortable way. However several aspects of the data model
+can not be expressed there. For instance:
+
+* managing computed attributes
+
+* enforcing complicated structural invariants
+
+* real-world side-effects linked to data events (email notification
+  being a prime example)
+
+The hook system is much like the triggers of an SQL database engine,
+except that:
+
+* it is not limited to one specific SQL backend (every one of them
+  having an idiomatic way to encode triggers), nor to SQL backends at
+  all (think about LDAP or a Subversion repository)
+
+* it is well-coupled to the rest of the framework
+
+Hooks are basically functions that dispatch on both:
+
+* events : after/before add/update/delete on entities/relations
+
+* entity or relation types
+
+They are an essential building block of any moderately complicated
+cubicweb application.
--- a/doc/book/en/intro/tutorial/create-cube.rst	Tue Sep 15 15:01:41 2009 +0200
+++ b/doc/book/en/intro/tutorial/create-cube.rst	Thu Sep 17 15:16:53 2009 +0200
@@ -3,12 +3,12 @@
 Create your cube
 ----------------
 
-The packages ``cubicweb`` and ``cubicweb-dev`` installs a command line tool
-for *CubicWeb* called ``cubicweb-ctl``. This tool provides a wide range of
-commands described in details in :ref:`cubicweb-ctl`.
+The packages ``cubicweb`` and ``cubicweb-dev`` install a command line
+tool for *CubicWeb* called ``cubicweb-ctl``. This tool provides a wide
+range of commands described in details in :ref:`cubicweb-ctl`.
 
-Once your *CubicWeb* development environment is set up, you can create a new
-cube::
+Once your *CubicWeb* development environment is set up, you can create
+a new cube::
 
   cubicweb-ctl newcube blog
 
@@ -40,15 +40,15 @@
 
 
 A Blog has a title and a description. The title is a string that is
-required by the class EntityType and must be less than 50 characters.
-The description is a string that is not constrained.
+required and must be less than 50 characters.  The
+description is a string that is not constrained.
 
 A BlogEntry has a title, a publish_date and a content. The title is a
 string that is required and must be less than 100 characters. The
 publish_date is a Date with a default value of TODAY, meaning that
 when a BlogEntry is created, its publish_date will be the current day
 unless it is modified. The content is a string that will be indexed in
-the full-text index and has no constraint.
+the database full-text index and has no constraint.
 
 A BlogEntry also has a relationship ``entry_of`` that links it to a
 Blog. The cardinality ``?*`` means that a BlogEntry can be part of
@@ -172,9 +172,9 @@
 Define your entity views
 ------------------------
 
-Each entity defined in a model inherits default views allowing
-different rendering of the data. You can redefine each of them
-according to your needs and preferences. So let's see how the
+Each entity defined in a model is associated with default views
+allowing different rendering of the data. You can redefine each of
+them according to your needs and preferences. So let's see how the
 views are defined.
 
 
@@ -183,72 +183,74 @@
 
 A view is defined by a Python class which includes:
 
-  - an identifier (all objects in *CubicWeb* are entered in a registry
-    and this identifier will be used as a key)
+  - an identifier (all objects in *CubicWeb* are recorded in a
+    registry and this identifier will be used as a key)
 
   - a filter to select the result sets it can be applied to
 
-A view has a set of methods complying
-with the `View` class interface (`cubicweb.common.view`).
+A view has a set of methods complying with the `View` class interface
+(`cubicweb.common.view`).
 
 *CubicWeb* provides a lot of standard views for the type `EntityView`;
 for a complete list, read the code in directory ``cubicweb/web/views/``.
 
-A view is applied on a `result set` which contains a set of
-entities we are trying to display. *CubicWeb* uses a selector
-mechanism which computes for each available view a score:
-the view with the highest score is then used to display the given `result set`.
-The standard library of selectors is in
-``cubicweb.common.selector`` and a library of methods used to
-compute scores is available in ``cubicweb.vregistry.vreq``.
+A view is applied on a `result set` which contains a set of entities
+we are trying to display. *CubicWeb* uses a selector mechanism which
+computes for each available view a score: the view with the highest
+score is then used to display the given `result set`.  The standard
+library of selectors is in ``cubicweb.selector``.
 
 It is possible to define multiple views for the same identifier
 and to associate selectors and filters to allow the application
-to find the best way to render the data.
+to find the most appropriate way to render the data.
 
-For example, the view named ``primary`` is the one used to display
-a single entity. We will now show you how to customize this view.
+For example, the view named ``primary`` is the one used to display a
+single entity. We will now show you how to create a primary view for
+BlogEntry.
 
 
-View customization
-~~~~~~~~~~~~~~~~~~
+Primary view customization
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you wish to modify the way a `BlogEntry` is rendered, you will have
+to subclass the `primary` view, for instance in the module ``views``
+of the cube ``cubes/blog/views.py``.
+
+The standard primary view is the most sophisticated view of all. It
+has more than a call() method. It is a template. Actually the entry
+point calls the following sequence of (redefinable) methods:
+
+ * render_entity_title
 
-If you wish to modify the way a `BlogEntry` is rendered, you will have to
-overwrite the `primary` view defined in the module ``views`` of the cube
-``cubes/blog/views.py``.
+ * render_entity_metadata
+
+ * render_entity_attributes
+
+ * render_entity_relations
 
-We can for example add in front of the publication date a prefix specifying
-that the date we see is the publication date.
+ * render_side_boxes
+
+Excepted side boxes, we can see all of them already in action in the
+blog entry view. This is all described in more details in
+:ref:`primary`.
+
+We can for example add in front of the publication date a prefix
+specifying that the date we see is the publication date.
 
 To do so, please apply the following changes:
 
 .. sourcecode:: python
 
-  from cubicweb.web.views import baseviews
-
-
-  class BlogEntryPrimaryView(baseviews.PrimaryView):
-
-    accepts = ('BlogEntry',)
-
-    def render_entity_title(self, entity):
-        self.w(u'<h1>%s</h1>' % html_escape(entity.dc_title()))
-
-    def content_format(self, entity):
-        return entity.view('reledit', rtype='content_format')
+  from cubicweb.selectors import implements
+  from cubicweb.web.views import primary
 
-    def cell_call(self, row, col):
-        entity = self.rset.get_entity(row, col)
+  class BlogEntryPrimaryView(primary.PrimaryView):
+    __select__ = implements('BlogEntry')
 
-        # display entity attributes with prefixes
-        self.w(u'<h1>%s</h1>' % entity.title)
-        self.w(u'<p>published on %s</p>' % entity.publish_date.strftime('%Y-%m-%d'))
-        self.w(u'<p>%s</p>' % entity.content)
-
-        # display relations
-        siderelations = []
-        if self.main_related_section:
-            self.render_entity_relations(entity, siderelations)
+      def render_entity_attributes(self, entity):
+          self.w(u'<p>published on %s</p>' %
+                 entity.publish_date.strftime('%Y-%m-%d'))
+          super(BlogEntryPrimaryView, self).render_entity_attributes(entity)
 
 .. note::
   When a view is modified, it is not required to restart the instance
--- a/entity.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/entity.py	Thu Sep 17 15:16:53 2009 +0200
@@ -14,6 +14,7 @@
 from logilab.common.decorators import cached
 from logilab.mtconverter import TransformData, TransformError, xml_escape
 
+from rql import parse
 from rql.utils import rqlvar_maker
 
 from cubicweb import Unauthorized
@@ -21,6 +22,7 @@
 from cubicweb.selectors import yes
 from cubicweb.appobject import AppObject
 from cubicweb.schema import RQLVocabularyConstraint, RQLConstraint
+from cubicweb.rqlrewrite import RQLRewriter
 
 from cubicweb.common.uilib import printable_value, soup2xhtml
 from cubicweb.common.mixins import MI_REL_TRIGGERS
@@ -616,7 +618,10 @@
     def unrelated_rql(self, rtype, targettype, role, ordermethod=None,
                       vocabconstraints=True):
         """build a rql to fetch `targettype` entities unrelated to this entity
-        using (rtype, role) relation
+        using (rtype, role) relation.
+
+        Consider relation permissions so that returned entities may be actually
+        linked by `rtype`.
         """
         ordermethod = ordermethod or 'fetch_unrelated_order'
         if isinstance(rtype, basestring):
@@ -629,8 +634,17 @@
             objtype, subjtype = self.e_schema, targettype
         if self.has_eid():
             restriction = ['NOT S %s O' % rtype, '%s eid %%(x)s' % evar]
+            args = {'x': self.eid}
+            if role == 'subject':
+                securitycheck_args = {'fromeid': self.eid}
+            else:
+                securitycheck_args = {'toeid': self.eid}
         else:
             restriction = []
+            args = {}
+            securitycheck_args = {}
+        insertsecurity = (rtype.has_local_role('add') and not
+                          rtype.has_perm(self.req, 'add', **securitycheck_args))
         constraints = rtype.rproperty(subjtype, objtype, 'constraints')
         if vocabconstraints:
             # RQLConstraint is a subclass for RQLVocabularyConstraint, so they
@@ -647,20 +661,29 @@
         if not ' ORDERBY ' in rql:
             before, after = rql.split(' WHERE ', 1)
             rql = '%s ORDERBY %s WHERE %s' % (before, searchedvar, after)
-        return rql
+        if insertsecurity:
+            rqlexprs = rtype.get_rqlexprs('add')
+            rewriter = RQLRewriter(self.req)
+            rqlst = self.req.vreg.parse(self.req, rql, args)
+            for select in rqlst.children:
+                rewriter.rewrite(select, [((searchedvar, searchedvar), rqlexprs)],
+                                 select.solutions, args)
+            rql = rqlst.as_string()
+        return rql, args
 
     def unrelated(self, rtype, targettype, role='subject', limit=None,
                   ordermethod=None):
         """return a result set of target type objects that may be related
         by a given relation, with self as subject or object
         """
-        rql = self.unrelated_rql(rtype, targettype, role, ordermethod)
+        try:
+            rql, args = self.unrelated_rql(rtype, targettype, role, ordermethod)
+        except Unauthorized:
+            return self.req.empty_rset()
         if limit is not None:
             before, after = rql.split(' WHERE ', 1)
             rql = '%s LIMIT %s WHERE %s' % (before, limit, after)
-        if self.has_eid():
-            return self.req.execute(rql, {'x': self.eid})
-        return self.req.execute(rql)
+        return self.req.execute(rql, args, tuple(args))
 
     # relations cache handling ################################################
 
@@ -816,6 +839,20 @@
                     words += entity.get_words()
         return words
 
+    @deprecated('[3.2] see new form api')
+    def vocabulary(self, rtype, role='subject', limit=None):
+        """vocabulary functions must return a list of couples
+        (label, eid) that will typically be used to fill the
+        edition view's combobox.
+
+        If `eid` is None in one of these couples, it should be
+        interpreted as a separator in case vocabulary results are grouped
+        """
+        from logilab.common.testlib import mock_object
+        form = self.vreg.select('forms', 'edition', self.req, entity=self)
+        field = mock_object(name=rtype, role=role)
+        return form.form_field_vocabulary(field, limit)
+
 
 # attribute and relation descriptors ##########################################
 
--- a/gettext.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/gettext.py	Thu Sep 17 15:16:53 2009 +0200
@@ -8,7 +8,6 @@
 languages.  L10N refers to the adaptation of your program, once
 internationalized, to the local language and cultural habits.
 
-:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
 """
 
 # This module represents the integration of work, contributions, feedback, and
@@ -47,7 +46,7 @@
 #   find this format documented anywhere.
 
 
-import copy, os, re, struct, sys
+import locale, copy, os, re, struct, sys
 from errno import ENOENT
 
 
@@ -78,7 +77,10 @@
     Python lambda function that implements an equivalent expression.
     """
     # Security check, allow only the "n" identifier
-    from StringIO import StringIO
+    try:
+        from cStringIO import StringIO
+    except ImportError:
+        from StringIO import StringIO
     import token, tokenize
     tokens = tokenize.generate_tokens(StringIO(plural).readline)
     try:
@@ -172,6 +174,7 @@
     def __init__(self, fp=None):
         self._info = {}
         self._charset = None
+        self._output_charset = None
         self._fallback = None
         if fp is not None:
             self._parse(fp)
@@ -190,6 +193,21 @@
             return self._fallback.gettext(message)
         return message
 
+    def pgettext(self, context, message):
+        if self._fallback:
+            return self._fallback.pgettext(context, message)
+        return message
+
+    def lgettext(self, message):
+        if self._fallback:
+            return self._fallback.lgettext(message)
+        return message
+
+    def lpgettext(self, context, message):
+        if self._fallback:
+            return self._fallback.lpgettext(context, message)
+        return message
+
     def ngettext(self, msgid1, msgid2, n):
         if self._fallback:
             return self._fallback.ngettext(msgid1, msgid2, n)
@@ -198,11 +216,40 @@
         else:
             return msgid2
 
+    def npgettext(self, context, msgid1, msgid2, n):
+        if self._fallback:
+            return self._fallback.npgettext(context, msgid1, msgid2, n)
+        if n == 1:
+            return msgid1
+        else:
+            return msgid2
+
+    def lngettext(self, msgid1, msgid2, n):
+        if self._fallback:
+            return self._fallback.lngettext(msgid1, msgid2, n)
+        if n == 1:
+            return msgid1
+        else:
+            return msgid2
+
+    def lnpgettext(self, context, msgid1, msgid2, n):
+        if self._fallback:
+            return self._fallback.lnpgettext(context, msgid1, msgid2, n)
+        if n == 1:
+            return msgid1
+        else:
+            return msgid2
+
     def ugettext(self, message):
         if self._fallback:
             return self._fallback.ugettext(message)
         return unicode(message)
 
+    def upgettext(self, context, message):
+        if self._fallback:
+            return self._fallback.upgettext(context, message)
+        return unicode(message)
+
     def ungettext(self, msgid1, msgid2, n):
         if self._fallback:
             return self._fallback.ungettext(msgid1, msgid2, n)
@@ -211,15 +258,49 @@
         else:
             return unicode(msgid2)
 
+    def unpgettext(self, context, msgid1, msgid2, n):
+        if self._fallback:
+            return self._fallback.unpgettext(context, msgid1, msgid2, n)
+        if n == 1:
+            return unicode(msgid1)
+        else:
+            return unicode(msgid2)
+
     def info(self):
         return self._info
 
     def charset(self):
         return self._charset
 
-    def install(self, unicode=False):
+    def output_charset(self):
+        return self._output_charset
+
+    def set_output_charset(self, charset):
+        self._output_charset = charset
+
+    def install(self, unicode=False, names=None):
         import __builtin__
         __builtin__.__dict__['_'] = unicode and self.ugettext or self.gettext
+        if hasattr(names, "__contains__"):
+            if "gettext" in names:
+                __builtin__.__dict__['gettext'] = __builtin__.__dict__['_']
+            if "pgettext" in names:
+                __builtin__.__dict__['pgettext'] = (unicode and self.upgettext
+                                                    or self.pgettext)
+            if "ngettext" in names:
+                __builtin__.__dict__['ngettext'] = (unicode and self.ungettext
+                                                             or self.ngettext)
+            if "npgettext" in names:
+                __builtin__.__dict__['npgettext'] = \
+                    (unicode and self.unpgettext or self.npgettext)
+            if "lgettext" in names:
+                __builtin__.__dict__['lgettext'] = self.lgettext
+            if "lpgettext" in names:
+                __builtin__.__dict__['lpgettext'] = self.lpgettext
+            if "lngettext" in names:
+                __builtin__.__dict__['lngettext'] = self.lngettext
+            if "lnpgettext" in names:
+                __builtin__.__dict__['lnpgettext'] = self.lnpgettext
 
 
 class GNUTranslations(NullTranslations):
@@ -227,6 +308,10 @@
     LE_MAGIC = 0x950412deL
     BE_MAGIC = 0xde120495L
 
+    # The encoding of a msgctxt and a msgid in a .mo file is
+    # msgctxt + "\x04" + msgid (gettext version >= 0.15)
+    CONTEXT_ENCODING = "%s\x04%s"
+
     def _parse(self, fp):
         """Override this method to support alternative .mo formats."""
         unpack = struct.unpack
@@ -262,18 +347,19 @@
             # See if we're looking at GNU .mo conventions for metadata
             if mlen == 0:
                 # Catalog description
-                # don't handle multi-lines fields here, and skip
-                # lines which don't look like a header description
-                # (e.g. "header: value")
                 lastk = k = None
                 for item in tmsg.splitlines():
                     item = item.strip()
-                    if not item or not ':' in item:
+                    if not item:
                         continue
-                    k, v = item.split(':', 1)
-                    k = k.strip().lower()
-                    v = v.strip()
-                    self._info[k] = v
+                    if ':' in item:
+                        k, v = item.split(':', 1)
+                        k = k.strip().lower()
+                        v = v.strip()
+                        self._info[k] = v
+                        lastk = k
+                    elif lastk:
+                        self._info[lastk] += '\n' + item
                     if k == 'content-type':
                         self._charset = v.split('charset=')[1]
                     elif k == 'plural-forms':
@@ -289,7 +375,7 @@
             # cause no problems since us-ascii should always be a subset of
             # the charset encoding.  We may want to fall back to 8-bit msgids
             # if the Unicode conversion fails.
-            if msg.find('\x00') >= 0:
+            if '\x00' in msg:
                 # Plural forms
                 msgid1, msgid2 = msg.split('\x00')
                 tmsg = tmsg.split('\x00')
@@ -315,14 +401,56 @@
                 return self._fallback.gettext(message)
             return message
         # Encode the Unicode tmsg back to an 8-bit string, if possible
-        if self._charset:
+        if self._output_charset:
+            return tmsg.encode(self._output_charset)
+        elif self._charset:
+            return tmsg.encode(self._charset)
+        return tmsg
+
+    def pgettext(self, context, message):
+        ctxt_msg_id = self.CONTEXT_ENCODING % (context, message)
+        missing = object()
+        tmsg = self._catalog.get(ctxt_msg_id, missing)
+        if tmsg is missing:
+            if self._fallback:
+                return self._fallback.pgettext(context, message)
+            return message
+        # Encode the Unicode tmsg back to an 8-bit string, if possible
+        if self._output_charset:
+            return tmsg.encode(self._output_charset)
+        elif self._charset:
             return tmsg.encode(self._charset)
         return tmsg
 
+    def lgettext(self, message):
+        missing = object()
+        tmsg = self._catalog.get(message, missing)
+        if tmsg is missing:
+            if self._fallback:
+                return self._fallback.lgettext(message)
+            return message
+        if self._output_charset:
+            return tmsg.encode(self._output_charset)
+        return tmsg.encode(locale.getpreferredencoding())
+
+    def lpgettext(self, context, message):
+        ctxt_msg_id = self.CONTEXT_ENCODING % (context, message)
+        missing = object()
+        tmsg = self._catalog.get(ctxt_msg_id, missing)
+        if tmsg is missing:
+            if self._fallback:
+                return self._fallback.lpgettext(context, message)
+            return message
+        if self._output_charset:
+            return tmsg.encode(self._output_charset)
+        return tmsg.encode(locale.getpreferredencoding())
+
     def ngettext(self, msgid1, msgid2, n):
         try:
             tmsg = self._catalog[(msgid1, self.plural(n))]
-            if self._charset:
+            if self._output_charset:
+                return tmsg.encode(self._output_charset)
+            elif self._charset:
                 return tmsg.encode(self._charset)
             return tmsg
         except KeyError:
@@ -333,6 +461,52 @@
             else:
                 return msgid2
 
+    def npgettext(self, context, msgid1, msgid2, n):
+        ctxt_msg_id = self.CONTEXT_ENCODING % (context, msgid1)
+        try:
+            tmsg = self._catalog[(ctxt_msg_id, self.plural(n))]
+            if self._output_charset:
+                return tmsg.encode(self._output_charset)
+            elif self._charset:
+                return tmsg.encode(self._charset)
+            return tmsg
+        except KeyError:
+            if self._fallback:
+                return self._fallback.npgettext(context, msgid1, msgid2, n)
+            if n == 1:
+                return msgid1
+            else:
+                return msgid2        
+
+    def lngettext(self, msgid1, msgid2, n):
+        try:
+            tmsg = self._catalog[(msgid1, self.plural(n))]
+            if self._output_charset:
+                return tmsg.encode(self._output_charset)
+            return tmsg.encode(locale.getpreferredencoding())
+        except KeyError:
+            if self._fallback:
+                return self._fallback.lngettext(msgid1, msgid2, n)
+            if n == 1:
+                return msgid1
+            else:
+                return msgid2
+
+    def lnpgettext(self, context, msgid1, msgid2, n):
+        ctxt_msg_id = self.CONTEXT_ENCODING % (context, msgid1)
+        try:
+            tmsg = self._catalog[(ctxt_msg_id, self.plural(n))]
+            if self._output_charset:
+                return tmsg.encode(self._output_charset)
+            return tmsg.encode(locale.getpreferredencoding())
+        except KeyError:
+            if self._fallback:
+                return self._fallback.lnpgettext(context, msgid1, msgid2, n)
+            if n == 1:
+                return msgid1
+            else:
+                return msgid2
+
     def ugettext(self, message):
         missing = object()
         tmsg = self._catalog.get(message, missing)
@@ -342,6 +516,18 @@
             return unicode(message)
         return tmsg
 
+    def upgettext(self, context, message):
+        ctxt_message_id = self.CONTEXT_ENCODING % (context, message)
+        missing = object()
+        tmsg = self._catalog.get(ctxt_message_id, missing)
+        if tmsg is missing:
+            # XXX logilab patch for compat w/ catalog generated by cw < 3.5
+            return self.ugettext(message)
+            if self._fallback:
+                return self._fallback.upgettext(context, message)
+            return unicode(message)
+        return tmsg
+
     def ungettext(self, msgid1, msgid2, n):
         try:
             tmsg = self._catalog[(msgid1, self.plural(n))]
@@ -354,6 +540,19 @@
                 tmsg = unicode(msgid2)
         return tmsg
 
+    def unpgettext(self, context, msgid1, msgid2, n):
+        ctxt_message_id = self.CONTEXT_ENCODING % (context, msgid1)
+        try:
+            tmsg = self._catalog[(ctxt_message_id, self.plural(n))]
+        except KeyError:
+            if self._fallback:
+                return self._fallback.unpgettext(context, msgid1, msgid2, n)
+            if n == 1:
+                tmsg = unicode(msgid1)
+            else:
+                tmsg = unicode(msgid2)
+        return tmsg
+
 
 # Locate a .mo file using the gettext strategy
 def find(domain, localedir=None, languages=None, all=0):
@@ -397,7 +596,7 @@
 _translations = {}
 
 def translation(domain, localedir=None, languages=None,
-                class_=None, fallback=False):
+                class_=None, fallback=False, codeset=None):
     if class_ is None:
         class_ = GNUTranslations
     mofiles = find(domain, localedir, languages, all=1)
@@ -414,9 +613,12 @@
         t = _translations.get(key)
         if t is None:
             t = _translations.setdefault(key, class_(open(mofile, 'rb')))
-        # Copy the translation object to allow setting fallbacks.
-        # All other instance data is shared with the cached object.
+        # Copy the translation object to allow setting fallbacks and
+        # output charset. All other instance data is shared with the
+        # cached object.
         t = copy.copy(t)
+        if codeset:
+            t.set_output_charset(codeset)
         if result is None:
             result = t
         else:
@@ -424,13 +626,16 @@
     return result
 
 
-def install(domain, localedir=None, unicode=False):
-    translation(domain, localedir, fallback=True).install(unicode)
+def install(domain, localedir=None, unicode=False, codeset=None, names=None):
+    t = translation(domain, localedir, fallback=True, codeset=codeset)
+    t.install(unicode, names)
 
 
 
 # a mapping b/w domains and locale directories
 _localedirs = {}
+# a mapping b/w domains and codesets
+_localecodesets = {}
 # current global domain, `messages' used for compatibility w/ GNU gettext
 _current_domain = 'messages'
 
@@ -443,22 +648,55 @@
 
 
 def bindtextdomain(domain, localedir=None):
+    global _localedirs
     if localedir is not None:
         _localedirs[domain] = localedir
     return _localedirs.get(domain, _default_localedir)
 
 
+def bind_textdomain_codeset(domain, codeset=None):
+    global _localecodesets
+    if codeset is not None:
+        _localecodesets[domain] = codeset
+    return _localecodesets.get(domain)
+
+
 def dgettext(domain, message):
     try:
-        t = translation(domain, _localedirs.get(domain, None))
+        t = translation(domain, _localedirs.get(domain, None),
+                        codeset=_localecodesets.get(domain))
     except IOError:
         return message
     return t.gettext(message)
 
+def dpgettext(domain, context, message):
+    try:
+        t = translation(domain, _localedirs.get(domain, None),
+                        codeset=_localecodesets.get(domain))
+    except IOError:
+        return message
+    return t.pgettext(context, message)
+
+def ldgettext(domain, message):
+    try:
+        t = translation(domain, _localedirs.get(domain, None),
+                        codeset=_localecodesets.get(domain))
+    except IOError:
+        return message
+    return t.lgettext(message)
+
+def ldpgettext(domain, context, message):
+    try:
+        t = translation(domain, _localedirs.get(domain, None),
+                        codeset=_localecodesets.get(domain))
+    except IOError:
+        return message
+    return t.lpgettext(context, message)
 
 def dngettext(domain, msgid1, msgid2, n):
     try:
-        t = translation(domain, _localedirs.get(domain, None))
+        t = translation(domain, _localedirs.get(domain, None),
+                        codeset=_localecodesets.get(domain))
     except IOError:
         if n == 1:
             return msgid1
@@ -466,14 +704,62 @@
             return msgid2
     return t.ngettext(msgid1, msgid2, n)
 
+def dnpgettext(domain, context, msgid1, msgid2, n):
+    try:
+        t = translation(domain, _localedirs.get(domain, None),
+                        codeset=_localecodesets.get(domain))
+    except IOError:
+        if n == 1:
+            return msgid1
+        else:
+            return msgid2
+    return t.npgettext(context, msgid1, msgid2, n)
+
+def ldngettext(domain, msgid1, msgid2, n):
+    try:
+        t = translation(domain, _localedirs.get(domain, None),
+                        codeset=_localecodesets.get(domain))
+    except IOError:
+        if n == 1:
+            return msgid1
+        else:
+            return msgid2
+    return t.lngettext(msgid1, msgid2, n)
+
+def ldnpgettext(domain, context, msgid1, msgid2, n):
+    try:
+        t = translation(domain, _localedirs.get(domain, None),
+                        codeset=_localecodesets.get(domain))
+    except IOError:
+        if n == 1:
+            return msgid1
+        else:
+            return msgid2
+    return t.lnpgettext(context, msgid1, msgid2, n)
 
 def gettext(message):
     return dgettext(_current_domain, message)
 
+def pgettext(context, message):
+    return dpgettext(_current_domain, context, message)
+
+def lgettext(message):
+    return ldgettext(_current_domain, message)
+
+def lpgettext(context, message):
+    return ldpgettext(_current_domain, context, message)
 
 def ngettext(msgid1, msgid2, n):
     return dngettext(_current_domain, msgid1, msgid2, n)
 
+def npgettext(context, msgid1, msgid2, n):
+    return dnpgettext(_current_domain, context, msgid1, msgid2, n)
+
+def lngettext(msgid1, msgid2, n):
+    return ldngettext(_current_domain, msgid1, msgid2, n)
+
+def lnpgettext(context, msgid1, msgid2, n):
+    return ldnpgettext(_current_domain, context, msgid1, msgid2, n)
 
 # dcgettext() has been deemed unnecessary and is not implemented.
 
--- a/goa/gaesource.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/goa/gaesource.py	Thu Sep 17 15:16:53 2009 +0200
@@ -149,7 +149,7 @@
     # ISource interface #######################################################
 
     def compile_rql(self, rql):
-        rqlst = self.repo.querier._rqlhelper.parse(rql)
+        rqlst = self.repo.vreg.parse(rql)
         rqlst.restricted_vars = ()
         rqlst.children[0].solutions = self._sols
         return rqlst
--- a/goa/goactl.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/goa/goactl.py	Thu Sep 17 15:16:53 2009 +0200
@@ -8,7 +8,6 @@
 __docformat__ = "restructuredtext en"
 
 from os.path import exists, join, split, basename, normpath, abspath
-
 from logilab.common.clcommands import register_commands
 
 from cubicweb import CW_SOFTWARE_ROOT, BadCommandUsage
@@ -19,9 +18,9 @@
 from logilab import common as lgc
 from logilab import constraint as lgcstr
 from logilab import mtconverter as lgmtc
-import rql, yams, yapps, simplejson, dateutil, vobject, docutils, roman
+import rql, yams, yapps, simplejson, docutils, roman
 
-SLINK_DIRECTORIES = (
+SLINK_DIRECTORIES = [
     (lgc.__path__[0], 'logilab/common'),
     (lgmtc.__path__[0], 'logilab/mtconverter'),
     (lgcstr.__path__[0], 'logilab/constraint'),
@@ -29,8 +28,6 @@
     (simplejson.__path__[0], 'simplejson'),
     (yams.__path__[0], 'yams'),
     (yapps.__path__[0], 'yapps'),
-    (dateutil.__path__[0], 'dateutil'),
-    (vobject.__path__[0], 'vobject'),
     (docutils.__path__[0], 'docutils'),
     (roman.__file__.replace('.pyc', '.py'), 'roman.py'),
 
@@ -42,7 +39,15 @@
     (join(CW_SOFTWARE_ROOT, 'i18n'), join('cubes', 'shared', 'i18n')),
     (join(CW_SOFTWARE_ROOT, 'goa', 'tools'), 'tools'),
     (join(CW_SOFTWARE_ROOT, 'goa', 'bin'), 'bin'),
-    )
+    ]
+
+try:
+    import dateutil
+    import vobject
+    SLINK_DIRECTORIES.extend([ (dateutil.__path__[0], 'dateutil'),
+                               (vobject.__path__[0], 'vobject') ] )
+except ImportError:
+    pass
 
 COPY_CW_FILES = (
     '__init__.py',
@@ -54,6 +59,7 @@
     'cwconfig.py',
     'entity.py',
     'interfaces.py',
+    'rqlrewrite.py',
     'rset.py',
     'schema.py',
     'schemaviewer.py',
@@ -78,7 +84,6 @@
     'server/pool.py',
     'server/querier.py',
     'server/repository.py',
-    'server/rqlrewrite.py',
     'server/securityhooks.py',
     'server/session.py',
     'server/serverconfig.py',
--- a/hooks/email.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/hooks/email.py	Thu Sep 17 15:16:53 2009 +0200
@@ -8,6 +8,7 @@
 __docformat__ = "restructuredtext en"
 
 from cubicweb.server import hook
+from cubicweb.server.repository import ensure_card_respected
 
 class SetUseEmailRelationOp(hook.Operation):
     """delay this operation to commit to avoid conflict with a late rql query
@@ -23,7 +24,12 @@
 
     def precommit_event(self):
         if self.condition():
-            self.session.unsafe_execute(
+            # we've to handle cardinaly by ourselves since we're using unsafe_execute
+            # but use session.execute and not session.unsafe_execute to check we
+            # can change the relation
+            ensure_card_respected(session.execute, session,
+                                  self.fromeid, self.rtype, self.toeid)
+            session.unsafe_execute(
                 'SET X %s Y WHERE X eid %%(x)s, Y eid %%(y)s' % self.rtype,
                 {'x': self.entity.eid, 'y': self.email.eid}, 'x')
 
--- a/i18n/en.po	Tue Sep 15 15:01:41 2009 +0200
+++ b/i18n/en.po	Thu Sep 17 15:16:53 2009 +0200
@@ -5,7 +5,7 @@
 msgstr ""
 "Project-Id-Version: 2.0\n"
 "POT-Creation-Date: 2006-01-12 17:35+CET\n"
-"PO-Revision-Date: 2009-08-05 08:39+0200\n"
+"PO-Revision-Date: 2009-09-17 11:53+0200\n"
 "Last-Translator: Sylvain Thenault <sylvain.thenault@logilab.fr>\n"
 "Language-Team: English <devel@logilab.fr.org>\n"
 "MIME-Version: 1.0\n"
@@ -107,10 +107,6 @@
 msgstr ""
 
 #, python-format
-msgid "%s is not the initial state (%s) for this entity"
-msgstr ""
-
-#, python-format
 msgid "%s not estimated"
 msgstr ""
 
@@ -197,6 +193,15 @@
 msgid "Attributes"
 msgstr ""
 
+# schema pot file, generated on 2009-09-16 16:46:55
+#
+# singular and plural forms for each entity type
+msgid "BaseTransition"
+msgstr "Transition (abstract)"
+
+msgid "BaseTransition_plural"
+msgstr "Transitions (abstract)"
+
 msgid "Bookmark"
 msgstr "Bookmark"
 
@@ -351,6 +356,9 @@
 msgid "Interval_plural"
 msgstr "Intervals"
 
+msgid "New BaseTransition"
+msgstr "XXX"
+
 msgid "New Bookmark"
 msgstr "New bookmark"
 
@@ -358,7 +366,7 @@
 msgstr "New attribute"
 
 msgid "New CWCache"
-msgstr ""
+msgstr "New cache"
 
 msgid "New CWConstraint"
 msgstr "New constraint"
@@ -399,12 +407,21 @@
 msgid "New State"
 msgstr "New state"
 
+msgid "New SubWorkflowExitPoint"
+msgstr "New subworkflow exit-point"
+
 msgid "New TrInfo"
 msgstr "New transition information"
 
 msgid "New Transition"
 msgstr "New transition"
 
+msgid "New Workflow"
+msgstr "New workflow"
+
+msgid "New WorkflowTransition"
+msgstr "New workflow-transition"
+
 msgid "No query has been executed"
 msgstr ""
 
@@ -472,6 +489,12 @@
 msgid "String_plural"
 msgstr "Strings"
 
+msgid "SubWorkflowExitPoint"
+msgstr "Subworkflow exit-point"
+
+msgid "SubWorkflowExitPoint_plural"
+msgstr "subworkflow exit-points"
+
 msgid "Subject:"
 msgstr ""
 
@@ -492,12 +515,8 @@
 msgid "The view %s could not be found"
 msgstr ""
 
-msgid "There is no workflow defined for this entity."
-msgstr ""
-
-#, python-format
-msgid "This %s"
-msgstr ""
+msgid "This BaseTransition"
+msgstr "This abstract transition"
 
 msgid "This Bookmark"
 msgstr "This bookmark"
@@ -506,7 +525,7 @@
 msgstr "This attribute"
 
 msgid "This CWCache"
-msgstr ""
+msgstr "This cache"
 
 msgid "This CWConstraint"
 msgstr "This constraint"
@@ -547,12 +566,21 @@
 msgid "This State"
 msgstr "This state"
 
+msgid "This SubWorkflowExitPoint"
+msgstr "This subworkflow exit-point"
+
 msgid "This TrInfo"
 msgstr "This transition information"
 
 msgid "This Transition"
 msgstr "This transition"
 
+msgid "This Workflow"
+msgstr "This workflow"
+
+msgid "This WorkflowTransition"
+msgstr "This workflow-transition"
+
 msgid "Time"
 msgstr "Time"
 
@@ -584,9 +612,21 @@
 msgid "What's new?"
 msgstr ""
 
+msgid "Workflow"
+msgstr "Workflow"
+
 msgid "Workflow history"
 msgstr ""
 
+msgid "WorkflowTransition"
+msgstr "Workflow-transition"
+
+msgid "WorkflowTransition_plural"
+msgstr "Workflow-transitions"
+
+msgid "Workflow_plural"
+msgstr "Workflows"
+
 msgid "You are not connected to an instance !"
 msgstr ""
 
@@ -622,9 +662,6 @@
 msgid "[%s supervision] changes summary"
 msgstr ""
 
-msgid "__msg state changed"
-msgstr "state changed"
-
 msgid ""
 "a RQL expression which should return some results, else the transition won't "
 "be available. This query may use X and U variables that will respectivly "
@@ -644,12 +681,12 @@
 msgid "about this site"
 msgstr ""
 
+msgid "abstract base class for transitions"
+msgstr ""
+
 msgid "access type"
 msgstr ""
 
-msgid "account state"
-msgstr ""
-
 msgid "action(s) on this selection"
 msgstr ""
 
@@ -662,6 +699,12 @@
 msgid "actions_addentity_description"
 msgstr ""
 
+msgid "actions_addrelated"
+msgstr ""
+
+msgid "actions_addrelated_description"
+msgstr ""
+
 msgid "actions_cancel"
 msgstr "cancel the selection"
 
@@ -848,8 +891,8 @@
 msgid "add State allowed_transition Transition subject"
 msgstr "allowed transition"
 
-msgid "add State state_of CWEType object"
-msgstr "state"
+msgid "add State allowed_transition WorkflowTransition subject"
+msgstr "workflow-transition"
 
 msgid "add Transition condition RQLExpression subject"
 msgstr "condition"
@@ -860,63 +903,28 @@
 msgid "add Transition destination_state State subject"
 msgstr "destination state"
 
-msgid "add Transition transition_of CWEType object"
-msgstr "transition"
-
-msgid "add a Bookmark"
-msgstr "add a bookmark"
-
-msgid "add a CWAttribute"
-msgstr "add an attribute"
-
-msgid "add a CWCache"
-msgstr "add a cubicweb cache"
-
-msgid "add a CWConstraint"
-msgstr "add a constraint"
-
-msgid "add a CWConstraintType"
-msgstr "add a constraint type"
-
+msgid "add WorkflowTransition condition RQLExpression subject"
+msgstr "workflow-transition"
+
+msgid "add WorkflowTransition subworkflow_exit SubWorkflowExitPoint subject"
+msgstr "subworkflow exit-point"
+
+msgctxt "inlined:CWRelation.from_entity.subject"
 msgid "add a CWEType"
 msgstr "add an entity type"
 
-msgid "add a CWGroup"
-msgstr "add a group"
-
-msgid "add a CWPermission"
-msgstr "add a permission"
-
-msgid "add a CWProperty"
-msgstr "add a property"
-
+msgctxt "inlined:CWRelation.to_entity.subject"
+msgid "add a CWEType"
+msgstr "add an entity type"
+
+msgctxt "inlined:CWRelation.relation_type.subject"
 msgid "add a CWRType"
 msgstr "add a relation type"
 
-msgid "add a CWRelation"
-msgstr "add a relation"
-
-msgid "add a CWUser"
-msgstr "add a user"
-
+msgctxt "inlined:CWUser.use_email.subject"
 msgid "add a EmailAddress"
 msgstr "add an email address"
 
-msgid "add a ExternalUri"
-msgstr "and an external uri"
-
-msgid "add a RQLExpression"
-msgstr "add a rql expression"
-
-msgid "add a State"
-msgstr "add a state"
-
-msgid "add a TrInfo"
-msgstr "add a transition information"
-
-msgid "add a Transition"
-msgstr "add a transition"
-
 msgid "add a new permission"
 msgstr ""
 
@@ -931,6 +939,24 @@
 msgid "add_permission"
 msgstr "can be added by"
 
+# subject and object forms for each relation type
+# (no object form for final relation types)
+msgctxt "CWEType"
+msgid "add_permission"
+msgstr ""
+
+msgctxt "CWRType"
+msgid "add_permission"
+msgstr ""
+
+msgctxt "CWGroup"
+msgid "add_permission_object"
+msgstr ""
+
+msgctxt "RQLExpression"
+msgid "add_permission_object"
+msgstr ""
+
 msgid "add_permission_object"
 msgstr "has permission to add"
 
@@ -944,12 +970,26 @@
 "(toeid)s"
 msgstr ""
 
+msgid "addrelated"
+msgstr ""
+
+msgid "address"
+msgstr ""
+
+msgctxt "EmailAddress"
 msgid "address"
 msgstr ""
 
 msgid "alias"
 msgstr ""
 
+msgctxt "EmailAddress"
+msgid "alias"
+msgstr ""
+
+msgid "allow to set a specific workflow for an entity"
+msgstr ""
+
 msgid "allowed transition from this state"
 msgstr ""
 
@@ -959,6 +999,22 @@
 msgid "allowed_transition"
 msgstr "allowed transition"
 
+msgctxt "State"
+msgid "allowed_transition"
+msgstr ""
+
+msgctxt "BaseTransition"
+msgid "allowed_transition_object"
+msgstr ""
+
+msgctxt "Transition"
+msgid "allowed_transition_object"
+msgstr ""
+
+msgctxt "WorkflowTransition"
+msgid "allowed_transition_object"
+msgstr ""
+
 msgid "allowed_transition_object"
 msgstr "incoming states"
 
@@ -1038,6 +1094,14 @@
 msgid "bookmarked_by"
 msgstr "bookmarked by"
 
+msgctxt "Bookmark"
+msgid "bookmarked_by"
+msgstr "bookmarked by"
+
+msgctxt "CWUser"
+msgid "bookmarked_by_object"
+msgstr ""
+
 msgid "bookmarked_by_object"
 msgstr "has bookmarks"
 
@@ -1122,6 +1186,28 @@
 msgid "by relation"
 msgstr ""
 
+msgid "by_transition"
+msgstr ""
+
+msgctxt "TrInfo"
+msgid "by_transition"
+msgstr "by transition"
+
+msgctxt "BaseTransition"
+msgid "by_transition_object"
+msgstr ""
+
+msgctxt "Transition"
+msgid "by_transition_object"
+msgstr ""
+
+msgctxt "WorkflowTransition"
+msgid "by_transition_object"
+msgstr ""
+
+msgid "by_transition_object"
+msgstr "transition information"
+
 msgid "calendar"
 msgstr ""
 
@@ -1152,6 +1238,9 @@
 msgid "can't display data, unexpected error: %s"
 msgstr ""
 
+msgid "can't have multiple exits on the same state"
+msgstr ""
+
 #, python-format
 msgid ""
 "can't set inlined=%(inlined)s, %(stype)s %(rtype)s %(otype)s has cardinality="
@@ -1164,9 +1253,14 @@
 msgid "cancel this insert"
 msgstr ""
 
-msgid "canonical"
-msgstr ""
-
+msgid "cardinality"
+msgstr ""
+
+msgctxt "CWAttribute"
+msgid "cardinality"
+msgstr "cardinality"
+
+msgctxt "CWRelation"
 msgid "cardinality"
 msgstr ""
 
@@ -1192,9 +1286,14 @@
 msgid "comment"
 msgstr ""
 
-msgid "comment:"
-msgstr ""
-
+msgctxt "TrInfo"
+msgid "comment"
+msgstr ""
+
+msgid "comment_format"
+msgstr "format"
+
+msgctxt "TrInfo"
 msgid "comment_format"
 msgstr "format"
 
@@ -1246,6 +1345,12 @@
 msgid "components_navigation_description"
 msgstr "pagination component for large resultsets"
 
+msgid "components_pdfview"
+msgstr ""
+
+msgid "components_pdfview_description"
+msgstr ""
+
 msgid "components_rqlinput"
 msgstr "rql input box"
 
@@ -1255,12 +1360,32 @@
 msgid "composite"
 msgstr ""
 
+msgctxt "CWRelation"
+msgid "composite"
+msgstr ""
+
+msgid "condition"
+msgstr ""
+
+msgctxt "BaseTransition"
+msgid "condition"
+msgstr ""
+
+msgctxt "Transition"
+msgid "condition"
+msgstr ""
+
+msgctxt "WorkflowTransition"
 msgid "condition"
 msgstr ""
 
 msgid "condition:"
 msgstr ""
 
+msgctxt "RQLExpression"
+msgid "condition_object"
+msgstr ""
+
 msgid "condition_object"
 msgstr "condition of"
 
@@ -1270,6 +1395,18 @@
 msgid "constrained_by"
 msgstr "constrained by"
 
+msgctxt "CWAttribute"
+msgid "constrained_by"
+msgstr "constrained by"
+
+msgctxt "CWRelation"
+msgid "constrained_by"
+msgstr "constrained by"
+
+msgctxt "CWConstraint"
+msgid "constrained_by_object"
+msgstr ""
+
 msgid "constrained_by_object"
 msgstr "constraints"
 
@@ -1385,6 +1522,10 @@
 msgid "created_by"
 msgstr "created by"
 
+msgctxt "CWUser"
+msgid "created_by_object"
+msgstr ""
+
 msgid "created_by_object"
 msgstr "has created"
 
@@ -1445,23 +1586,32 @@
 msgid "creating RQLExpression (Transition %(linkto)s condition RQLExpression)"
 msgstr "creating rql expression for transition %(linkto)s"
 
+msgid ""
+"creating RQLExpression (WorkflowTransition %(linkto)s condition "
+"RQLExpression)"
+msgstr "creating rql expression for workflow-transition %(linkto)s"
+
 msgid "creating State (State allowed_transition Transition %(linkto)s)"
 msgstr "creating a state able to trigger transition %(linkto)s"
 
-msgid "creating State (State state_of CWEType %(linkto)s)"
-msgstr "creating state for the %(linkto)s entity type"
-
 msgid "creating State (Transition %(linkto)s destination_state State)"
 msgstr "creating destination state for transition %(linkto)s"
 
+msgid ""
+"creating SubWorkflowExitPoint (WorkflowTransition %(linkto)s "
+"subworkflow_exit SubWorkflowExitPoint)"
+msgstr "creating subworkflow exit-point for workflow-transition %(linkto)s"
+
 msgid "creating Transition (State %(linkto)s allowed_transition Transition)"
 msgstr "creating triggerable transition for state %(linkto)s"
 
 msgid "creating Transition (Transition destination_state State %(linkto)s)"
 msgstr "creating transition leading to state %(linkto)s"
 
-msgid "creating Transition (Transition transition_of CWEType %(linkto)s)"
-msgstr "creating transition for the %(linkto)s entity type"
+msgid ""
+"creating WorkflowTransition (State %(linkto)s allowed_transition "
+"WorkflowTransition)"
+msgstr "creating workflow-transition leading to state %(linkto)s"
 
 msgid "creation"
 msgstr ""
@@ -1475,6 +1625,14 @@
 msgid "cstrtype"
 msgstr "constraint's type"
 
+msgctxt "CWConstraint"
+msgid "cstrtype"
+msgstr ""
+
+msgctxt "CWConstraintType"
+msgid "cstrtype_object"
+msgstr ""
+
 msgid "cstrtype_object"
 msgstr "used by"
 
@@ -1488,6 +1646,20 @@
 msgid "currently attached file: %s"
 msgstr ""
 
+msgid "custom_workflow"
+msgstr "custom workflow"
+
+msgctxt "CWUser"
+msgid "custom_workflow"
+msgstr "custom workflow"
+
+msgctxt "Workflow"
+msgid "custom_workflow_object"
+msgstr ""
+
+msgid "custom_workflow_object"
+msgstr "custom workflow of"
+
 msgid "cwetype-schema-image"
 msgstr "schema"
 
@@ -1524,6 +1696,30 @@
 msgid "default text format for rich text fields."
 msgstr ""
 
+msgid "default user workflow"
+msgstr ""
+
+msgid "default workflow for an entity type"
+msgstr ""
+
+msgid "default_workflow"
+msgstr "default workflow"
+
+msgctxt "CWEType"
+msgid "default_workflow"
+msgstr "default workflow"
+
+msgctxt "Workflow"
+msgid "default_workflow_object"
+msgstr ""
+
+msgid "default_workflow_object"
+msgstr "default workflow of"
+
+msgid "defaultval"
+msgstr "default value"
+
+msgctxt "CWAttribute"
 msgid "defaultval"
 msgstr "default value"
 
@@ -1558,6 +1754,9 @@
 msgid "define an entity type, used to build the instance schema"
 msgstr ""
 
+msgid "define how we get out from a sub-workflow"
+msgstr ""
+
 msgid ""
 "defines what's the property is applied for. You must select this first to be "
 "able to set value"
@@ -1581,6 +1780,22 @@
 msgid "delete_permission"
 msgstr "can be deleted by"
 
+msgctxt "CWEType"
+msgid "delete_permission"
+msgstr "delete permission"
+
+msgctxt "CWRType"
+msgid "delete_permission"
+msgstr ""
+
+msgctxt "CWGroup"
+msgid "delete_permission_object"
+msgstr ""
+
+msgctxt "RQLExpression"
+msgid "delete_permission_object"
+msgstr ""
+
 msgid "delete_permission_object"
 msgstr "has permission to delete"
 
@@ -1600,9 +1815,84 @@
 msgid "description"
 msgstr ""
 
+msgctxt "CWEType"
+msgid "description"
+msgstr ""
+
+msgctxt "CWRelation"
+msgid "description"
+msgstr ""
+
+msgctxt "Workflow"
+msgid "description"
+msgstr ""
+
+msgctxt "CWAttribute"
+msgid "description"
+msgstr ""
+
+msgctxt "Transition"
+msgid "description"
+msgstr ""
+
+msgctxt "WorkflowTransition"
+msgid "description"
+msgstr ""
+
+msgctxt "State"
+msgid "description"
+msgstr ""
+
+msgctxt "CWRType"
+msgid "description"
+msgstr ""
+
+msgctxt "BaseTransition"
+msgid "description"
+msgstr ""
+
 msgid "description_format"
 msgstr "format"
 
+msgctxt "CWEType"
+msgid "description_format"
+msgstr ""
+
+msgctxt "CWRelation"
+msgid "description_format"
+msgstr ""
+
+msgctxt "Workflow"
+msgid "description_format"
+msgstr "format"
+
+msgctxt "CWAttribute"
+msgid "description_format"
+msgstr "format"
+
+msgctxt "Transition"
+msgid "description_format"
+msgstr "format"
+
+msgctxt "WorkflowTransition"
+msgid "description_format"
+msgstr "format"
+
+msgctxt "State"
+msgid "description_format"
+msgstr "format"
+
+msgctxt "CWRType"
+msgid "description_format"
+msgstr "format"
+
+msgctxt "BaseTransition"
+msgid "description_format"
+msgstr "format"
+
+msgid "destination state"
+msgstr ""
+
 msgid "destination state for this transition"
 msgstr ""
 
@@ -1612,6 +1902,18 @@
 msgid "destination_state"
 msgstr "destination state"
 
+msgctxt "Transition"
+msgid "destination_state"
+msgstr ""
+
+msgctxt "SubWorkflowExitPoint"
+msgid "destination_state"
+msgstr "destination state"
+
+msgctxt "State"
+msgid "destination_state_object"
+msgstr ""
+
 msgid "destination_state_object"
 msgstr "destination of"
 
@@ -1640,6 +1942,9 @@
 msgid "display the component or not"
 msgstr ""
 
+msgid "display the pdf icon or not"
+msgstr ""
+
 msgid ""
 "distinct label to distinguate between other permission entity of the same "
 "name"
@@ -1655,6 +1960,9 @@
 msgid "download icon"
 msgstr ""
 
+msgid "download page as pdf"
+msgstr ""
+
 msgid "download schema as owl"
 msgstr ""
 
@@ -1712,6 +2020,9 @@
 msgid "entity edited"
 msgstr ""
 
+msgid "entity has no workflow set"
+msgstr ""
+
 msgid "entity linked"
 msgstr ""
 
@@ -1723,10 +2034,7 @@
 "configuration"
 msgstr ""
 
-msgid "entity types which may use this state"
-msgstr ""
-
-msgid "entity types which may use this transition"
+msgid "entity types which may use this workflow"
 msgstr ""
 
 msgid "error while embedding page"
@@ -1746,15 +2054,33 @@
 msgid "eta_date"
 msgstr ""
 
+msgid "exit_point"
+msgstr ""
+
+msgid "exit_point_object"
+msgstr ""
+
+#, python-format
+msgid "exiting from subworkflow %s"
+msgstr ""
+
 msgid "expected:"
 msgstr ""
 
 msgid "expression"
 msgstr ""
 
+msgctxt "RQLExpression"
+msgid "expression"
+msgstr ""
+
 msgid "exprtype"
 msgstr "expression's type"
 
+msgctxt "RQLExpression"
+msgid "exprtype"
+msgstr ""
+
 msgid "external page"
 msgstr ""
 
@@ -1806,6 +2132,18 @@
 msgid "final"
 msgstr ""
 
+msgctxt "CWEType"
+msgid "final"
+msgstr ""
+
+msgctxt "CWRType"
+msgid "final"
+msgstr ""
+
+msgid "firstname"
+msgstr ""
+
+msgctxt "CWUser"
 msgid "firstname"
 msgstr ""
 
@@ -1818,6 +2156,14 @@
 msgid "for_user"
 msgstr "for user"
 
+msgctxt "CWProperty"
+msgid "for_user"
+msgstr ""
+
+msgctxt "CWUser"
+msgid "for_user_object"
+msgstr ""
+
 msgid "for_user_object"
 msgstr "use properties"
 
@@ -1834,6 +2180,18 @@
 msgid "from_entity"
 msgstr "from entity"
 
+msgctxt "CWAttribute"
+msgid "from_entity"
+msgstr "from entity"
+
+msgctxt "CWRelation"
+msgid "from_entity"
+msgstr "from entity"
+
+msgctxt "CWEType"
+msgid "from_entity_object"
+msgstr ""
+
 msgid "from_entity_object"
 msgstr "subjet relation"
 
@@ -1843,6 +2201,14 @@
 msgid "from_state"
 msgstr "from state"
 
+msgctxt "TrInfo"
+msgid "from_state"
+msgstr "from state"
+
+msgctxt "State"
+msgid "from_state_object"
+msgstr ""
+
 msgid "from_state_object"
 msgstr "transitions from this state"
 
@@ -1852,9 +2218,17 @@
 msgid "fulltext_container"
 msgstr ""
 
+msgctxt "CWRType"
+msgid "fulltext_container"
+msgstr "fulltext container"
+
 msgid "fulltextindexed"
 msgstr "fulltext indexed"
 
+msgctxt "CWAttribute"
+msgid "fulltextindexed"
+msgstr ""
+
 msgid "generic plot"
 msgstr ""
 
@@ -1873,6 +2247,10 @@
 msgid "granted to groups"
 msgstr ""
 
+#, python-format
+msgid "graphical representation of %s"
+msgstr ""
+
 msgid "graphical representation of the instance'schema"
 msgstr ""
 
@@ -1961,12 +2339,103 @@
 msgid "id of main template used to render pages"
 msgstr ""
 
+msgid "identical to"
+msgstr ""
+
 msgid "identical_to"
 msgstr "identical to"
 
 msgid "identity"
 msgstr ""
 
+msgctxt "CWRelation"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "Bookmark"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "CWAttribute"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "CWConstraintType"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "State"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "BaseTransition"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "CWEType"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "Workflow"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "CWGroup"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "TrInfo"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "CWConstraint"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "CWUser"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "Transition"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "CWRType"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "SubWorkflowExitPoint"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "ExternalUri"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "CWCache"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "WorkflowTransition"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "RQLExpression"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "CWPermission"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "EmailAddress"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "CWProperty"
+msgid "identity_object"
+msgstr ""
+
 msgid "identity_object"
 msgstr "identity"
 
@@ -1987,12 +2456,28 @@
 msgid "in_group"
 msgstr "in group"
 
+msgctxt "CWUser"
+msgid "in_group"
+msgstr "in group"
+
+msgctxt "CWGroup"
+msgid "in_group_object"
+msgstr ""
+
 msgid "in_group_object"
 msgstr "contains"
 
 msgid "in_state"
 msgstr "in state"
 
+msgctxt "CWUser"
+msgid "in_state"
+msgstr "in state"
+
+msgctxt "State"
+msgid "in_state_object"
+msgstr ""
+
 msgid "in_state_object"
 msgstr "state of"
 
@@ -2012,6 +2497,10 @@
 msgid "indexed"
 msgstr ""
 
+msgctxt "CWAttribute"
+msgid "indexed"
+msgstr ""
+
 msgid "indicate the current state of an entity"
 msgstr ""
 
@@ -2027,18 +2516,30 @@
 msgid "initial estimation %s"
 msgstr ""
 
-msgid "initial state for entities of this type"
+msgid "initial state for this workflow"
 msgstr ""
 
 msgid "initial_state"
 msgstr "initial state"
 
+msgctxt "Workflow"
+msgid "initial_state"
+msgstr "initial state"
+
+msgctxt "State"
+msgid "initial_state_object"
+msgstr ""
+
 msgid "initial_state_object"
 msgstr "initial state of"
 
 msgid "inlined"
 msgstr ""
 
+msgctxt "CWRType"
+msgid "inlined"
+msgstr ""
+
 msgid "instance schema"
 msgstr ""
 
@@ -2048,6 +2549,10 @@
 msgid "internationalizable"
 msgstr ""
 
+msgctxt "CWAttribute"
+msgid "internationalizable"
+msgstr ""
+
 #, python-format
 msgid "invalid action %r"
 msgstr ""
@@ -2083,9 +2588,17 @@
 msgid "is_instance_of"
 msgstr ""
 
+msgctxt "CWEType"
 msgid "is_instance_of_object"
 msgstr ""
 
+msgid "is_instance_of_object"
+msgstr "is instance of"
+
+msgctxt "CWEType"
+msgid "is_object"
+msgstr ""
+
 msgid "is_object"
 msgstr "has instances"
 
@@ -2101,6 +2614,10 @@
 msgid "label"
 msgstr ""
 
+msgctxt "CWPermission"
+msgid "label"
+msgstr ""
+
 msgid "language of the user interface"
 msgstr ""
 
@@ -2110,6 +2627,10 @@
 msgid "last_login_time"
 msgstr "last login time"
 
+msgctxt "CWUser"
+msgid "last_login_time"
+msgstr "last login time"
+
 msgid "latest modification time of an entity"
 msgstr ""
 
@@ -2138,13 +2659,16 @@
 msgid "link a relation definition to its subject entity type"
 msgstr ""
 
-msgid "link a state to one or more entity type"
+msgid "link a state to one or more workflow"
 msgstr ""
 
 msgid "link a transition information to its object"
 msgstr ""
 
-msgid "link a transition to one or more entity type"
+msgid "link a transition to one or more workflow"
+msgstr ""
+
+msgid "link a workflow to one or more entity type"
 msgstr ""
 
 msgid "link to each item in"
@@ -2162,6 +2686,10 @@
 msgid "login"
 msgstr ""
 
+msgctxt "CWUser"
+msgid "login"
+msgstr ""
+
 msgid "login or email"
 msgstr ""
 
@@ -2181,6 +2709,10 @@
 msgid "mainvars"
 msgstr ""
 
+msgctxt "RQLExpression"
+msgid "mainvars"
+msgstr ""
+
 msgid "manage"
 msgstr ""
 
@@ -2196,6 +2728,9 @@
 msgid "managers"
 msgstr ""
 
+msgid "mandatory relation"
+msgstr ""
+
 msgid "march"
 msgstr ""
 
@@ -2242,6 +2777,50 @@
 msgid "name"
 msgstr ""
 
+msgctxt "CWEType"
+msgid "name"
+msgstr ""
+
+msgctxt "Transition"
+msgid "name"
+msgstr ""
+
+msgctxt "Workflow"
+msgid "name"
+msgstr ""
+
+msgctxt "CWGroup"
+msgid "name"
+msgstr ""
+
+msgctxt "CWConstraintType"
+msgid "name"
+msgstr ""
+
+msgctxt "WorkflowTransition"
+msgid "name"
+msgstr ""
+
+msgctxt "State"
+msgid "name"
+msgstr ""
+
+msgctxt "CWPermission"
+msgid "name"
+msgstr ""
+
+msgctxt "CWRType"
+msgid "name"
+msgstr ""
+
+msgctxt "BaseTransition"
+msgid "name"
+msgstr ""
+
+msgctxt "CWCache"
+msgid "name"
+msgstr ""
+
 msgid "name of the cache"
 msgstr ""
 
@@ -2347,6 +2926,14 @@
 msgid "ordernum"
 msgstr "order"
 
+msgctxt "CWAttribute"
+msgid "ordernum"
+msgstr ""
+
+msgctxt "CWRelation"
+msgid "ordernum"
+msgstr ""
+
 msgid "owl"
 msgstr ""
 
@@ -2356,6 +2943,10 @@
 msgid "owned_by"
 msgstr "owned by"
 
+msgctxt "CWUser"
+msgid "owned_by_object"
+msgstr ""
+
 msgid "owned_by_object"
 msgstr "owns"
 
@@ -2381,6 +2972,10 @@
 msgid "path"
 msgstr ""
 
+msgctxt "Bookmark"
+msgid "path"
+msgstr ""
+
 msgid "permission"
 msgstr ""
 
@@ -2402,6 +2997,10 @@
 msgid "pkey"
 msgstr "key"
 
+msgctxt "CWProperty"
+msgid "pkey"
+msgstr ""
+
 msgid "please correct errors below"
 msgstr ""
 
@@ -2414,6 +3013,20 @@
 msgid "powered by CubicWeb"
 msgstr ""
 
+msgid "prefered_form"
+msgstr ""
+
+msgctxt "EmailAddress"
+msgid "prefered_form"
+msgstr ""
+
+msgctxt "EmailAddress"
+msgid "prefered_form_object"
+msgstr ""
+
+msgid "prefered_form_object"
+msgstr ""
+
 msgid "preferences"
 msgstr ""
 
@@ -2426,6 +3039,14 @@
 msgid "primary_email"
 msgstr "primary email"
 
+msgctxt "CWUser"
+msgid "primary_email"
+msgstr "primary email"
+
+msgctxt "EmailAddress"
+msgid "primary_email_object"
+msgstr ""
+
 msgid "primary_email_object"
 msgstr "primary email of"
 
@@ -2442,17 +3063,39 @@
 msgstr ""
 
 msgid "read_perm"
-msgstr ""
+msgstr "read perm"
 
 msgid "read_permission"
 msgstr "can be read by"
 
+msgctxt "CWEType"
+msgid "read_permission"
+msgstr "read permission"
+
+msgctxt "CWRType"
+msgid "read_permission"
+msgstr "read permission"
+
+msgctxt "CWGroup"
+msgid "read_permission_object"
+msgstr ""
+
+msgctxt "RQLExpression"
+msgid "read_permission_object"
+msgstr ""
+
 msgid "read_permission_object"
 msgstr "has permission to delete"
 
 msgid "registry"
 msgstr ""
 
+msgid "related entity has no state"
+msgstr ""
+
+msgid "related entity has no workflow set"
+msgstr ""
+
 #, python-format
 msgid "relation %(relname)s of %(ent)s"
 msgstr ""
@@ -2460,6 +3103,18 @@
 msgid "relation_type"
 msgstr "relation type"
 
+msgctxt "CWAttribute"
+msgid "relation_type"
+msgstr "relation type"
+
+msgctxt "CWRelation"
+msgid "relation_type"
+msgstr "relation type"
+
+msgctxt "CWRType"
+msgid "relation_type_object"
+msgstr ""
+
 msgid "relation_type_object"
 msgstr "relation definitions"
 
@@ -2472,71 +3127,53 @@
 msgid "relative url of the bookmarked page"
 msgstr ""
 
-msgid "remove this Bookmark"
-msgstr "remove this bookmark"
-
-msgid "remove this CWAttribute"
-msgstr "remove this attribute"
-
-msgid "remove this CWCache"
-msgstr "remove this cubicweb cache"
-
-msgid "remove this CWConstraint"
-msgstr "remove this constraint"
-
-msgid "remove this CWConstraintType"
-msgstr "remove this constraint type"
-
+msgctxt "inlined:CWRelation:from_entity:subject"
+msgid "remove this CWEType"
+msgstr "remove this entity type"
+
+msgctxt "inlined:CWRelation:to_entity:subject"
 msgid "remove this CWEType"
 msgstr "remove this entity type"
 
-msgid "remove this CWGroup"
-msgstr "remove this group"
-
-msgid "remove this CWPermission"
-msgstr "remove this permission"
-
-msgid "remove this CWProperty"
-msgstr "remove this property"
-
+msgctxt "inlined:CWRelation:relation_type:subject"
 msgid "remove this CWRType"
 msgstr "remove this relation type"
 
-msgid "remove this CWRelation"
-msgstr "remove this relation"
-
-msgid "remove this CWUser"
-msgstr "remove this user"
-
+msgctxt "inlined:CWUser:use_email:subject"
 msgid "remove this EmailAddress"
 msgstr "remove this email address"
 
-msgid "remove this ExternalUri"
-msgstr ""
-
-msgid "remove this RQLExpression"
-msgstr "remove this RQL expression"
-
-msgid "remove this State"
-msgstr "remove this state"
-
-msgid "remove this TrInfo"
-msgstr "remove this transition information"
-
-msgid "remove this Transition"
-msgstr "remove this transition"
-
 msgid "require_group"
 msgstr "require the group"
 
+msgctxt "BaseTransition"
+msgid "require_group"
+msgstr "require group"
+
+msgctxt "Transition"
+msgid "require_group"
+msgstr "require group"
+
+msgctxt "CWPermission"
+msgid "require_group"
+msgstr "require group"
+
+msgctxt "WorkflowTransition"
+msgid "require_group"
+msgstr "require group"
+
+msgctxt "CWGroup"
+msgid "require_group_object"
+msgstr ""
+
 msgid "require_group_object"
 msgstr "required by"
 
 msgid "require_permission"
-msgstr ""
+msgstr "require permission"
 
 msgid "require_permission_object"
-msgstr ""
+msgstr "required by"
 
 msgid "required attribute"
 msgstr ""
@@ -2653,6 +3290,9 @@
 msgid "semantic description of this transition"
 msgstr ""
 
+msgid "semantic description of this workflow"
+msgstr ""
+
 msgid "send email"
 msgstr ""
 
@@ -2705,11 +3345,22 @@
 msgid "sparql xml"
 msgstr ""
 
+msgid "special transition allowing to go through a sub-workflow"
+msgstr ""
+
 msgid "specializes"
 msgstr ""
 
+msgctxt "CWEType"
+msgid "specializes"
+msgstr ""
+
+msgctxt "CWEType"
+msgid "specializes_object"
+msgstr ""
+
 msgid "specializes_object"
-msgstr ""
+msgstr "specialized by"
 
 msgid "startup views"
 msgstr ""
@@ -2717,9 +3368,28 @@
 msgid "state"
 msgstr ""
 
+msgid "state doesn't belong to entity's current workflow"
+msgstr ""
+
+msgid "state doesn't belong to entity's workflow"
+msgstr ""
+
+msgid ""
+"state doesn't belong to entity's workflow. You may want to set a custom "
+"workflow for this entity first."
+msgstr ""
+
 msgid "state_of"
 msgstr "state of"
 
+msgctxt "State"
+msgid "state_of"
+msgstr ""
+
+msgctxt "Workflow"
+msgid "state_of_object"
+msgstr ""
+
 msgid "state_of_object"
 msgstr "use states"
 
@@ -2742,12 +3412,65 @@
 msgid "subject_plural:"
 msgstr "subjects:"
 
+msgid "subworkflow"
+msgstr ""
+
+msgctxt "WorkflowTransition"
+msgid "subworkflow"
+msgstr ""
+
+msgid "subworkflow state"
+msgstr ""
+
+msgid "subworkflow_exit"
+msgstr "subworkflow exit"
+
+msgctxt "WorkflowTransition"
+msgid "subworkflow_exit"
+msgstr ""
+
+msgctxt "SubWorkflowExitPoint"
+msgid "subworkflow_exit_object"
+msgstr ""
+
+msgid "subworkflow_exit_object"
+msgstr "subworkflow exit of"
+
+msgctxt "Workflow"
+msgid "subworkflow_object"
+msgstr ""
+
+msgid "subworkflow_object"
+msgstr "subworkflow of"
+
+msgid "subworkflow_state"
+msgstr "subworkflow state"
+
+msgctxt "SubWorkflowExitPoint"
+msgid "subworkflow_state"
+msgstr "subworkflow state"
+
+msgctxt "State"
+msgid "subworkflow_state_object"
+msgstr ""
+
+msgid "subworkflow_state_object"
+msgstr ""
+
 msgid "sunday"
 msgstr ""
 
 msgid "surname"
 msgstr ""
 
+msgctxt "CWUser"
+msgid "surname"
+msgstr ""
+
+msgid "symetric"
+msgstr ""
+
+msgctxt "CWRType"
 msgid "symetric"
 msgstr ""
 
@@ -2806,6 +3529,10 @@
 msgid "timestamp"
 msgstr ""
 
+msgctxt "CWCache"
+msgid "timestamp"
+msgstr ""
+
 msgid "timestamp of the latest source synchronization."
 msgstr ""
 
@@ -2815,6 +3542,10 @@
 msgid "title"
 msgstr ""
 
+msgctxt "Bookmark"
+msgid "title"
+msgstr ""
+
 msgid "to"
 msgstr ""
 
@@ -2828,6 +3559,18 @@
 msgid "to_entity"
 msgstr "to entity"
 
+msgctxt "CWAttribute"
+msgid "to_entity"
+msgstr "to entity"
+
+msgctxt "CWRelation"
+msgid "to_entity"
+msgstr "to entity"
+
+msgctxt "CWEType"
+msgid "to_entity_object"
+msgstr ""
+
 msgid "to_entity_object"
 msgstr "object relations"
 
@@ -2837,6 +3580,14 @@
 msgid "to_state"
 msgstr "to state"
 
+msgctxt "TrInfo"
+msgid "to_state"
+msgstr ""
+
+msgctxt "State"
+msgid "to_state_object"
+msgstr ""
+
 msgid "to_state_object"
 msgstr "transitions to this state"
 
@@ -2846,13 +3597,34 @@
 msgid "toggle check boxes"
 msgstr ""
 
-#, python-format
-msgid "transition from %s to %s does not exist or is not allowed"
+msgid "transition doesn't belong to entity's workflow"
+msgstr ""
+
+msgid "transition isn't allowed"
+msgstr ""
+
+msgid "transition may not be fired"
 msgstr ""
 
 msgid "transition_of"
 msgstr "transition of"
 
+msgctxt "BaseTransition"
+msgid "transition_of"
+msgstr "transition of"
+
+msgctxt "Transition"
+msgid "transition_of"
+msgstr "transition of"
+
+msgctxt "WorkflowTransition"
+msgid "transition_of"
+msgstr ""
+
+msgctxt "Workflow"
+msgid "transition_of_object"
+msgstr ""
+
 msgid "transition_of_object"
 msgstr "use transitions"
 
@@ -2925,6 +3697,10 @@
 msgid "upassword"
 msgstr "password"
 
+msgctxt "CWUser"
+msgid "upassword"
+msgstr ""
+
 msgid "update"
 msgstr ""
 
@@ -2934,6 +3710,18 @@
 msgid "update_permission"
 msgstr "can be updated by"
 
+msgctxt "CWEType"
+msgid "update_permission"
+msgstr ""
+
+msgctxt "CWGroup"
+msgid "update_permission_object"
+msgstr ""
+
+msgctxt "RQLExpression"
+msgid "update_permission_object"
+msgstr ""
+
 msgid "update_permission_object"
 msgstr "has permission to update"
 
@@ -2944,6 +3732,10 @@
 msgid "uri"
 msgstr ""
 
+msgctxt "ExternalUri"
+msgid "uri"
+msgstr ""
+
 msgid "use template languages"
 msgstr ""
 
@@ -2955,6 +3747,14 @@
 msgid "use_email"
 msgstr "use email"
 
+msgctxt "CWUser"
+msgid "use_email"
+msgstr ""
+
+msgctxt "EmailAddress"
+msgid "use_email_object"
+msgstr ""
+
 msgid "use_email_object"
 msgstr "used by"
 
@@ -3005,6 +3805,14 @@
 msgid "value"
 msgstr ""
 
+msgctxt "CWConstraint"
+msgid "value"
+msgstr ""
+
+msgctxt "CWProperty"
+msgid "value"
+msgstr ""
+
 msgid "value associated to this key is not editable manually"
 msgstr ""
 
@@ -3051,17 +3859,54 @@
 msgid "wf_info_for"
 msgstr "record for"
 
+msgctxt "TrInfo"
+msgid "wf_info_for"
+msgstr ""
+
+msgctxt "CWUser"
+msgid "wf_info_for_object"
+msgstr ""
+
 msgid "wf_info_for_object"
 msgstr "workflow history"
 
 msgid ""
 "when multiple addresses are equivalent (such as python-projects@logilab.org "
-"and python-projects@lists.logilab.org), set this to true on one of them "
-"which is the preferred form."
+"and python-projects@lists.logilab.org), set this to indicate which is the "
+"preferred form."
+msgstr ""
+
+msgid "workflow"
 msgstr ""
 
 #, python-format
-msgid "workflow for %s"
+msgid "workflow changed to \"%s\""
+msgstr ""
+
+msgid "workflow has no initial state"
+msgstr ""
+
+msgid "workflow history item"
+msgstr ""
+
+msgid "workflow to which this state belongs"
+msgstr ""
+
+msgid "workflow to which this transition belongs"
+msgstr ""
+
+msgid "workflow_of"
+msgstr ""
+
+msgctxt "Workflow"
+msgid "workflow_of"
+msgstr ""
+
+msgctxt "CWEType"
+msgid "workflow_of_object"
+msgstr ""
+
+msgid "workflow_of_object"
 msgstr ""
 
 msgid "xbel"
@@ -3081,3 +3926,132 @@
 
 msgid "you should probably delete that property"
 msgstr ""
+
+#~ msgid "add a BaseTransition"
+#~ msgstr "XXX"
+
+#~ msgid "add a Bookmark"
+#~ msgstr "add a bookmark"
+
+#~ msgid "add a CWAttribute"
+#~ msgstr "add an attribute"
+
+#~ msgid "add a CWCache"
+#~ msgstr "add a cubicweb cache"
+
+#~ msgid "add a CWConstraint"
+#~ msgstr "add a constraint"
+
+#~ msgid "add a CWConstraintType"
+#~ msgstr "add a constraint type"
+
+#~ msgid "add a CWEType"
+#~ msgstr "add an entity type"
+
+#~ msgid "add a CWGroup"
+#~ msgstr "add a group"
+
+#~ msgid "add a CWPermission"
+#~ msgstr "add a permission"
+
+#~ msgid "add a CWProperty"
+#~ msgstr "add a property"
+
+#~ msgid "add a CWRType"
+#~ msgstr "add a relation type"
+
+#~ msgid "add a CWRelation"
+#~ msgstr "add a relation"
+
+#~ msgid "add a CWUser"
+#~ msgstr "add a user"
+
+#~ msgid "add a EmailAddress"
+#~ msgstr "add an email address"
+
+#~ msgid "add a ExternalUri"
+#~ msgstr "and an external uri"
+
+#~ msgid "add a RQLExpression"
+#~ msgstr "add a rql expression"
+
+#~ msgid "add a State"
+#~ msgstr "add a state"
+
+#~ msgid "add a SubWorkflowExitPoint"
+#~ msgstr "add a subworkflow exit-point"
+
+#~ msgid "add a TrInfo"
+#~ msgstr "add a transition information"
+
+#~ msgid "add a Transition"
+#~ msgstr "add a transition"
+
+#~ msgid "add a Workflow"
+#~ msgstr "add a workflow"
+
+#~ msgid "add a WorkflowTransition"
+#~ msgstr "add a workflow-transition"
+
+#~ msgid "remove this Bookmark"
+#~ msgstr "remove this bookmark"
+
+#~ msgid "remove this CWAttribute"
+#~ msgstr "remove this attribute"
+
+#~ msgid "remove this CWCache"
+#~ msgstr "remove this cubicweb cache"
+
+#~ msgid "remove this CWConstraint"
+#~ msgstr "remove this constraint"
+
+#~ msgid "remove this CWConstraintType"
+#~ msgstr "remove this constraint type"
+
+#~ msgid "remove this CWEType"
+#~ msgstr "remove this entity type"
+
+#~ msgid "remove this CWGroup"
+#~ msgstr "remove this group"
+
+#~ msgid "remove this CWPermission"
+#~ msgstr "remove this permission"
+
+#~ msgid "remove this CWProperty"
+#~ msgstr "remove this property"
+
+#~ msgid "remove this CWRType"
+#~ msgstr "remove this relation type"
+
+#~ msgid "remove this CWRelation"
+#~ msgstr "remove this relation"
+
+#~ msgid "remove this CWUser"
+#~ msgstr "remove this user"
+
+#~ msgid "remove this EmailAddress"
+#~ msgstr "remove this email address"
+
+#~ msgid "remove this ExternalUri"
+#~ msgstr "remove this external uri"
+
+#~ msgid "remove this RQLExpression"
+#~ msgstr "remove this RQL expression"
+
+#~ msgid "remove this State"
+#~ msgstr "remove this state"
+
+#~ msgid "remove this SubWorkflowExitPoint"
+#~ msgstr "remove this subworkflow exit-point"
+
+#~ msgid "remove this TrInfo"
+#~ msgstr "remove this transition information"
+
+#~ msgid "remove this Transition"
+#~ msgstr "remove this transition"
+
+#~ msgid "remove this Workflow"
+#~ msgstr "remove this workflow"
+
+#~ msgid "remove this WorkflowTransition"
+#~ msgstr "remove this workflow-transition"
--- a/i18n/es.po	Tue Sep 15 15:01:41 2009 +0200
+++ b/i18n/es.po	Thu Sep 17 15:16:53 2009 +0200
@@ -112,10 +112,6 @@
 msgstr "%s reporte de errores"
 
 #, python-format
-msgid "%s is not the initial state (%s) for this entity"
-msgstr ""
-
-#, python-format
 msgid "%s not estimated"
 msgstr "%s no estimado(s)"
 
@@ -205,6 +201,15 @@
 msgid "Attributes"
 msgstr "Atributos"
 
+# schema pot file, generated on 2009-09-16 16:46:55
+#
+# singular and plural forms for each entity type
+msgid "BaseTransition"
+msgstr ""
+
+msgid "BaseTransition_plural"
+msgstr ""
+
 msgid "Bookmark"
 msgstr "Favorito"
 
@@ -359,6 +364,9 @@
 msgid "Interval_plural"
 msgstr "Duraciones"
 
+msgid "New BaseTransition"
+msgstr ""
+
 msgid "New Bookmark"
 msgstr "Agregar a Favoritos"
 
@@ -407,12 +415,21 @@
 msgid "New State"
 msgstr "Agregar Estado"
 
+msgid "New SubWorkflowExitPoint"
+msgstr ""
+
 msgid "New TrInfo"
 msgstr "Agregar Información de Transición"
 
 msgid "New Transition"
 msgstr "Agregar transición"
 
+msgid "New Workflow"
+msgstr ""
+
+msgid "New WorkflowTransition"
+msgstr ""
+
 msgid "No query has been executed"
 msgstr "Ninguna búsqueda ha sido ejecutada"
 
@@ -480,6 +497,12 @@
 msgid "String_plural"
 msgstr "Cadenas de caracteres"
 
+msgid "SubWorkflowExitPoint"
+msgstr ""
+
+msgid "SubWorkflowExitPoint_plural"
+msgstr ""
+
 msgid "Subject:"
 msgstr "Sujeto:"
 
@@ -500,12 +523,8 @@
 msgid "The view %s could not be found"
 msgstr "La vista %s no ha podido ser encontrada"
 
-msgid "There is no workflow defined for this entity."
-msgstr "No hay workflow para este entidad"
-
-#, python-format
-msgid "This %s"
-msgstr "Este %s"
+msgid "This BaseTransition"
+msgstr ""
 
 msgid "This Bookmark"
 msgstr "Este favorito"
@@ -555,12 +574,21 @@
 msgid "This State"
 msgstr "Este estado"
 
+msgid "This SubWorkflowExitPoint"
+msgstr ""
+
 msgid "This TrInfo"
 msgstr "Esta información de transición"
 
 msgid "This Transition"
 msgstr "Esta transición"
 
+msgid "This Workflow"
+msgstr ""
+
+msgid "This WorkflowTransition"
+msgstr ""
+
 msgid "Time"
 msgstr "Hora"
 
@@ -592,9 +620,21 @@
 msgid "What's new?"
 msgstr "Lo último en el sitio"
 
+msgid "Workflow"
+msgstr ""
+
 msgid "Workflow history"
 msgstr "Histórico del Workflow"
 
+msgid "WorkflowTransition"
+msgstr ""
+
+msgid "WorkflowTransition_plural"
+msgstr ""
+
+msgid "Workflow_plural"
+msgstr ""
+
 msgid "You are not connected to an instance !"
 msgstr ""
 
@@ -628,7 +668,8 @@
 msgid ""
 "You have no access to this view or it can not be used to display the current "
 "data."
-msgstr "No tiene acceso a esta vista o No se puede utilizare para los datos actuales."
+msgstr ""
+"No tiene acceso a esta vista o No se puede utilizare para los datos actuales."
 
 msgid ""
 "You're not authorized to access this page. If you think you should, please "
@@ -641,9 +682,6 @@
 msgid "[%s supervision] changes summary"
 msgstr "[%s supervision] descripción de cambios"
 
-msgid "__msg state changed"
-msgstr "El estado a cambiado"
-
 msgid ""
 "a RQL expression which should return some results, else the transition won't "
 "be available. This query may use X and U variables that will respectivly "
@@ -666,12 +704,12 @@
 msgid "about this site"
 msgstr "Sobre este Espacio"
 
+msgid "abstract base class for transitions"
+msgstr ""
+
 msgid "access type"
 msgstr "Tipo de Acceso"
 
-msgid "account state"
-msgstr "Estado de la Cuenta"
-
 msgid "action(s) on this selection"
 msgstr "acción(es) en esta selección"
 
@@ -684,6 +722,12 @@
 msgid "actions_addentity_description"
 msgstr ""
 
+msgid "actions_addrelated"
+msgstr ""
+
+msgid "actions_addrelated_description"
+msgstr ""
+
 msgid "actions_cancel"
 msgstr "Anular"
 
@@ -829,28 +873,28 @@
 msgstr "Definición de atributo"
 
 msgid "add CWEType add_permission RQLExpression subject"
-msgstr "Agregar una autorización"
+msgstr "Expresión RQL de agregación"
 
 msgid "add CWEType delete_permission RQLExpression subject"
-msgstr "Eliminar una autorización"
+msgstr "Expresión RQL de eliminación"
 
 msgid "add CWEType read_permission RQLExpression subject"
-msgstr "Definir una expresión RQL de lectura"
+msgstr "Expresión RQL de lectura"
 
 msgid "add CWEType update_permission RQLExpression subject"
 msgstr "Definir una expresión RQL de actualización"
 
 msgid "add CWProperty for_user CWUser object"
-msgstr "Agregar Propiedad"
+msgstr "Propiedad"
 
 msgid "add CWRType add_permission RQLExpression subject"
-msgstr "Agregar expresión RQL de agregación"
+msgstr "Expresión RQL de agregación"
 
 msgid "add CWRType delete_permission RQLExpression subject"
-msgstr "Agregar expresión RQL de eliminación"
+msgstr "Expresión RQL de eliminación"
 
 msgid "add CWRType read_permission RQLExpression subject"
-msgstr "Agregar expresión RQL de lectura"
+msgstr "Expresión RQL de lectura"
 
 msgid "add CWRelation constrained_by CWConstraint subject"
 msgstr "Restricción"
@@ -859,85 +903,50 @@
 msgstr "Definición de relación"
 
 msgid "add CWUser in_group CWGroup object"
-msgstr "Agregar usuario"
+msgstr "Usuario"
 
 msgid "add CWUser use_email EmailAddress subject"
-msgstr "Agregar email"
+msgstr "Email"
 
 msgid "add State allowed_transition Transition object"
-msgstr "Agregar un estado en entrada"
+msgstr "Estado en entrada"
 
 msgid "add State allowed_transition Transition subject"
-msgstr "Agregar una transición en salida"
-
-msgid "add State state_of CWEType object"
-msgstr "Agregar un estado"
+msgstr "Transición en salida"
+
+msgid "add State allowed_transition WorkflowTransition subject"
+msgstr ""
 
 msgid "add Transition condition RQLExpression subject"
-msgstr "Agregar una Restricción"
+msgstr "Restricción"
 
 msgid "add Transition destination_state State object"
-msgstr "Agregar una transición de entrada"
+msgstr "Transición de entrada"
 
 msgid "add Transition destination_state State subject"
-msgstr "Agregar el estado de salida"
-
-msgid "add Transition transition_of CWEType object"
-msgstr "Agregar una transición"
-
-msgid "add a Bookmark"
-msgstr "Agregar un Favorito"
-
-msgid "add a CWAttribute"
-msgstr "Agregar un tipo de relación"
-
-msgid "add a CWCache"
-msgstr "Agregar un cache"
-
-msgid "add a CWConstraint"
-msgstr "Agregar una Restricción"
-
-msgid "add a CWConstraintType"
-msgstr "Agregar un tipo de Restricción"
-
+msgstr "Estado de salida"
+
+msgid "add WorkflowTransition condition RQLExpression subject"
+msgstr ""
+
+msgid "add WorkflowTransition subworkflow_exit SubWorkflowExitPoint subject"
+msgstr ""
+
+msgctxt "inlined:CWRelation.from_entity.subject"
 msgid "add a CWEType"
-msgstr "Agregar un tipo de entidad"
-
-msgid "add a CWGroup"
-msgstr "Agregar un grupo de usuarios"
-
-msgid "add a CWPermission"
-msgstr "Agregar una autorización"
-
-msgid "add a CWProperty"
-msgstr "Agregar una propiedad"
-
+msgstr ""
+
+msgctxt "inlined:CWRelation.to_entity.subject"
+msgid "add a CWEType"
+msgstr ""
+
+msgctxt "inlined:CWRelation.relation_type.subject"
 msgid "add a CWRType"
-msgstr "Agregar un tipo de relación"
-
-msgid "add a CWRelation"
-msgstr "Agregar una relación"
-
-msgid "add a CWUser"
-msgstr "Agregar un usuario"
-
+msgstr ""
+
+msgctxt "inlined:CWUser.use_email.subject"
 msgid "add a EmailAddress"
-msgstr "Agregar un email"
-
-msgid "add a ExternalUri"
-msgstr ""
-
-msgid "add a RQLExpression"
-msgstr "Agregar una expresión rql"
-
-msgid "add a State"
-msgstr "Agregar un estado"
-
-msgid "add a TrInfo"
-msgstr "Agregar una información de transición"
-
-msgid "add a Transition"
-msgstr "Agregar una transición"
+msgstr ""
 
 msgid "add a new permission"
 msgstr "Agregar una autorización"
@@ -953,6 +962,24 @@
 msgid "add_permission"
 msgstr "Autorización para agregar"
 
+# subject and object forms for each relation type
+# (no object form for final relation types)
+msgctxt "CWEType"
+msgid "add_permission"
+msgstr ""
+
+msgctxt "CWRType"
+msgid "add_permission"
+msgstr ""
+
+msgctxt "CWGroup"
+msgid "add_permission_object"
+msgstr ""
+
+msgctxt "RQLExpression"
+msgid "add_permission_object"
+msgstr ""
+
 msgid "add_permission_object"
 msgstr "tiene la autorización para agregar"
 
@@ -968,12 +995,26 @@
 "Relación agregada %(rtype)s de %(frometype)s #%(fromeid)s hacia %(toetype)s #"
 "%(toeid)s"
 
+msgid "addrelated"
+msgstr ""
+
 msgid "address"
 msgstr "dirección"
 
+msgctxt "EmailAddress"
+msgid "address"
+msgstr ""
+
 msgid "alias"
 msgstr "alias"
 
+msgctxt "EmailAddress"
+msgid "alias"
+msgstr ""
+
+msgid "allow to set a specific workflow for an entity"
+msgstr ""
+
 msgid "allowed transition from this state"
 msgstr "transición autorizada desde este estado"
 
@@ -983,6 +1024,22 @@
 msgid "allowed_transition"
 msgstr "transición autorizada"
 
+msgctxt "State"
+msgid "allowed_transition"
+msgstr ""
+
+msgctxt "BaseTransition"
+msgid "allowed_transition_object"
+msgstr ""
+
+msgctxt "Transition"
+msgid "allowed_transition_object"
+msgstr ""
+
+msgctxt "WorkflowTransition"
+msgid "allowed_transition_object"
+msgstr ""
+
 msgid "allowed_transition_object"
 msgstr "Estados de entrada"
 
@@ -1064,6 +1121,14 @@
 msgid "bookmarked_by"
 msgstr "está en los favoritos de"
 
+msgctxt "Bookmark"
+msgid "bookmarked_by"
+msgstr ""
+
+msgctxt "CWUser"
+msgid "bookmarked_by_object"
+msgstr ""
+
 msgid "bookmarked_by_object"
 msgstr "selecciona en sus favoritos a"
 
@@ -1149,6 +1214,28 @@
 msgid "by relation"
 msgstr "por relación"
 
+msgid "by_transition"
+msgstr ""
+
+msgctxt "TrInfo"
+msgid "by_transition"
+msgstr ""
+
+msgctxt "BaseTransition"
+msgid "by_transition_object"
+msgstr ""
+
+msgctxt "Transition"
+msgid "by_transition_object"
+msgstr ""
+
+msgctxt "WorkflowTransition"
+msgid "by_transition_object"
+msgstr ""
+
+msgid "by_transition_object"
+msgstr ""
+
 msgid "calendar"
 msgstr "mostrar un calendario"
 
@@ -1179,6 +1266,9 @@
 msgid "can't display data, unexpected error: %s"
 msgstr "imposible de mostrar los datos, a causa del siguiente error: %s"
 
+msgid "can't have multiple exits on the same state"
+msgstr ""
+
 #, python-format
 msgid ""
 "can't set inlined=%(inlined)s, %(stype)s %(rtype)s %(otype)s has cardinality="
@@ -1193,12 +1283,17 @@
 msgid "cancel this insert"
 msgstr "Cancelar esta inserción"
 
-msgid "canonical"
-msgstr "canónico"
-
 msgid "cardinality"
 msgstr "cardinalidad"
 
+msgctxt "CWAttribute"
+msgid "cardinality"
+msgstr ""
+
+msgctxt "CWRelation"
+msgid "cardinality"
+msgstr ""
+
 msgid "category"
 msgstr "categoria"
 
@@ -1221,12 +1316,17 @@
 msgid "comment"
 msgstr "Comentario"
 
-msgid "comment:"
-msgstr "Comentario:"
+msgctxt "TrInfo"
+msgid "comment"
+msgstr ""
 
 msgid "comment_format"
 msgstr "Formato"
 
+msgctxt "TrInfo"
+msgid "comment_format"
+msgstr ""
+
 msgid "components"
 msgstr "Componentes"
 
@@ -1278,6 +1378,12 @@
 "Componente que permite distribuir sobre varias páginas las búsquedas que "
 "arrojan mayores resultados que un número previamente elegido"
 
+msgid "components_pdfview"
+msgstr ""
+
+msgid "components_pdfview_description"
+msgstr ""
+
 msgid "components_rqlinput"
 msgstr "Barra rql"
 
@@ -1287,12 +1393,32 @@
 msgid "composite"
 msgstr "composite"
 
+msgctxt "CWRelation"
+msgid "composite"
+msgstr ""
+
 msgid "condition"
 msgstr "condición"
 
+msgctxt "BaseTransition"
+msgid "condition"
+msgstr ""
+
+msgctxt "Transition"
+msgid "condition"
+msgstr ""
+
+msgctxt "WorkflowTransition"
+msgid "condition"
+msgstr ""
+
 msgid "condition:"
 msgstr "condición:"
 
+msgctxt "RQLExpression"
+msgid "condition_object"
+msgstr ""
+
 msgid "condition_object"
 msgstr "condición de"
 
@@ -1302,6 +1428,18 @@
 msgid "constrained_by"
 msgstr "Restricción hecha por"
 
+msgctxt "CWAttribute"
+msgid "constrained_by"
+msgstr ""
+
+msgctxt "CWRelation"
+msgid "constrained_by"
+msgstr ""
+
+msgctxt "CWConstraint"
+msgid "constrained_by_object"
+msgstr ""
+
 msgid "constrained_by_object"
 msgstr "ha restringido"
 
@@ -1433,6 +1571,10 @@
 msgid "created_by"
 msgstr "creado por"
 
+msgctxt "CWUser"
+msgid "created_by_object"
+msgstr ""
+
 msgid "created_by_object"
 msgstr "ha creado"
 
@@ -1501,23 +1643,32 @@
 msgid "creating RQLExpression (Transition %(linkto)s condition RQLExpression)"
 msgstr "Creación de una expresión RQL para la transición %(linkto)s"
 
+msgid ""
+"creating RQLExpression (WorkflowTransition %(linkto)s condition "
+"RQLExpression)"
+msgstr ""
+
 msgid "creating State (State allowed_transition Transition %(linkto)s)"
 msgstr "Creación de un estado que pueda ir hacia la transición %(linkto)s"
 
-msgid "creating State (State state_of CWEType %(linkto)s)"
-msgstr "Creación de un estado por el tipo %(linkto)s"
-
 msgid "creating State (Transition %(linkto)s destination_state State)"
 msgstr "Creación de un estado destinación de la transición %(linkto)s"
 
+msgid ""
+"creating SubWorkflowExitPoint (WorkflowTransition %(linkto)s "
+"subworkflow_exit SubWorkflowExitPoint)"
+msgstr ""
+
 msgid "creating Transition (State %(linkto)s allowed_transition Transition)"
 msgstr "Creación de una transición autorizada desde el estado %(linkto)s"
 
 msgid "creating Transition (Transition destination_state State %(linkto)s)"
 msgstr "Creación de un transición hacia el estado %(linkto)s"
 
-msgid "creating Transition (Transition transition_of CWEType %(linkto)s)"
-msgstr "Creación de una transición para el tipo %(linkto)s"
+msgid ""
+"creating WorkflowTransition (State %(linkto)s allowed_transition "
+"WorkflowTransition)"
+msgstr ""
 
 msgid "creation"
 msgstr "Creación"
@@ -1531,6 +1682,14 @@
 msgid "cstrtype"
 msgstr "Tipo de condición"
 
+msgctxt "CWConstraint"
+msgid "cstrtype"
+msgstr ""
+
+msgctxt "CWConstraintType"
+msgid "cstrtype_object"
+msgstr ""
+
 msgid "cstrtype_object"
 msgstr "utilizado por"
 
@@ -1544,6 +1703,20 @@
 msgid "currently attached file: %s"
 msgstr "archivo adjunto: %s"
 
+msgid "custom_workflow"
+msgstr ""
+
+msgctxt "CWUser"
+msgid "custom_workflow"
+msgstr ""
+
+msgctxt "Workflow"
+msgid "custom_workflow_object"
+msgstr ""
+
+msgid "custom_workflow_object"
+msgstr ""
+
 msgid "cwetype-schema-image"
 msgstr "Esquema"
 
@@ -1580,9 +1753,33 @@
 msgid "default text format for rich text fields."
 msgstr "Formato de texto como opción por defecto para los campos texto"
 
+msgid "default user workflow"
+msgstr ""
+
+msgid "default workflow for an entity type"
+msgstr ""
+
+msgid "default_workflow"
+msgstr ""
+
+msgctxt "CWEType"
+msgid "default_workflow"
+msgstr ""
+
+msgctxt "Workflow"
+msgid "default_workflow_object"
+msgstr ""
+
+msgid "default_workflow_object"
+msgstr ""
+
 msgid "defaultval"
 msgstr "Valor por defecto"
 
+msgctxt "CWAttribute"
+msgid "defaultval"
+msgstr ""
+
 msgid "define a CubicWeb user"
 msgstr "Define un usuario CubicWeb"
 
@@ -1614,6 +1811,9 @@
 msgid "define an entity type, used to build the instance schema"
 msgstr ""
 
+msgid "define how we get out from a sub-workflow"
+msgstr ""
+
 msgid ""
 "defines what's the property is applied for. You must select this first to be "
 "able to set value"
@@ -1639,6 +1839,22 @@
 msgid "delete_permission"
 msgstr "Autorización de eliminar"
 
+msgctxt "CWEType"
+msgid "delete_permission"
+msgstr ""
+
+msgctxt "CWRType"
+msgid "delete_permission"
+msgstr ""
+
+msgctxt "CWGroup"
+msgid "delete_permission_object"
+msgstr ""
+
+msgctxt "RQLExpression"
+msgid "delete_permission_object"
+msgstr ""
+
 msgid "delete_permission_object"
 msgstr "posee la autorización de eliminar"
 
@@ -1660,9 +1876,84 @@
 msgid "description"
 msgstr "Descripción"
 
+msgctxt "CWEType"
+msgid "description"
+msgstr ""
+
+msgctxt "CWRelation"
+msgid "description"
+msgstr ""
+
+msgctxt "Workflow"
+msgid "description"
+msgstr ""
+
+msgctxt "CWAttribute"
+msgid "description"
+msgstr ""
+
+msgctxt "Transition"
+msgid "description"
+msgstr ""
+
+msgctxt "WorkflowTransition"
+msgid "description"
+msgstr ""
+
+msgctxt "State"
+msgid "description"
+msgstr ""
+
+msgctxt "CWRType"
+msgid "description"
+msgstr ""
+
+msgctxt "BaseTransition"
+msgid "description"
+msgstr ""
+
 msgid "description_format"
 msgstr "Formato"
 
+msgctxt "CWEType"
+msgid "description_format"
+msgstr ""
+
+msgctxt "CWRelation"
+msgid "description_format"
+msgstr ""
+
+msgctxt "Workflow"
+msgid "description_format"
+msgstr ""
+
+msgctxt "CWAttribute"
+msgid "description_format"
+msgstr ""
+
+msgctxt "Transition"
+msgid "description_format"
+msgstr ""
+
+msgctxt "WorkflowTransition"
+msgid "description_format"
+msgstr ""
+
+msgctxt "State"
+msgid "description_format"
+msgstr ""
+
+msgctxt "CWRType"
+msgid "description_format"
+msgstr ""
+
+msgctxt "BaseTransition"
+msgid "description_format"
+msgstr ""
+
+msgid "destination state"
+msgstr ""
+
 msgid "destination state for this transition"
 msgstr "Estado destino para esta transición"
 
@@ -1672,6 +1963,18 @@
 msgid "destination_state"
 msgstr "Estado destino"
 
+msgctxt "Transition"
+msgid "destination_state"
+msgstr ""
+
+msgctxt "SubWorkflowExitPoint"
+msgid "destination_state"
+msgstr ""
+
+msgctxt "State"
+msgid "destination_state_object"
+msgstr ""
+
 msgid "destination_state_object"
 msgstr "Destino de"
 
@@ -1700,6 +2003,9 @@
 msgid "display the component or not"
 msgstr "Mostrar el componente o no"
 
+msgid "display the pdf icon or not"
+msgstr ""
+
 msgid ""
 "distinct label to distinguate between other permission entity of the same "
 "name"
@@ -1717,6 +2023,9 @@
 msgid "download icon"
 msgstr "ícono de descarga"
 
+msgid "download page as pdf"
+msgstr ""
+
 msgid "download schema as owl"
 msgstr "Descargar esquema en OWL"
 
@@ -1774,6 +2083,9 @@
 msgid "entity edited"
 msgstr "entidad modificada"
 
+msgid "entity has no workflow set"
+msgstr ""
+
 msgid "entity linked"
 msgstr "entidad asociada"
 
@@ -1787,11 +2099,8 @@
 "Tipo de entidad utilizada para definir una configuración de seguridad "
 "avanzada"
 
-msgid "entity types which may use this state"
-msgstr "Tipo de entidades que pueden utilizar este estado"
-
-msgid "entity types which may use this transition"
-msgstr "Entidades que pueden utilizar esta transición"
+msgid "entity types which may use this workflow"
+msgstr ""
 
 msgid "error while embedding page"
 msgstr "Error durante la inclusión de la página"
@@ -1813,15 +2122,33 @@
 msgid "eta_date"
 msgstr "fecha de fin"
 
+msgid "exit_point"
+msgstr ""
+
+msgid "exit_point_object"
+msgstr ""
+
+#, python-format
+msgid "exiting from subworkflow %s"
+msgstr ""
+
 msgid "expected:"
 msgstr "Previsto :"
 
 msgid "expression"
 msgstr "Expresión"
 
+msgctxt "RQLExpression"
+msgid "expression"
+msgstr ""
+
 msgid "exprtype"
 msgstr "Tipo de la expresión"
 
+msgctxt "RQLExpression"
+msgid "exprtype"
+msgstr ""
+
 msgid "external page"
 msgstr "Página externa"
 
@@ -1873,9 +2200,21 @@
 msgid "final"
 msgstr "Final"
 
+msgctxt "CWEType"
+msgid "final"
+msgstr ""
+
+msgctxt "CWRType"
+msgid "final"
+msgstr ""
+
 msgid "firstname"
 msgstr "Nombre"
 
+msgctxt "CWUser"
+msgid "firstname"
+msgstr ""
+
 msgid "foaf"
 msgstr "Amigo de un Amigo, FOAF"
 
@@ -1885,6 +2224,14 @@
 msgid "for_user"
 msgstr "Para el usuario"
 
+msgctxt "CWProperty"
+msgid "for_user"
+msgstr ""
+
+msgctxt "CWUser"
+msgid "for_user_object"
+msgstr ""
+
 msgid "for_user_object"
 msgstr "Utiliza las propiedades"
 
@@ -1901,6 +2248,18 @@
 msgid "from_entity"
 msgstr "De la entidad"
 
+msgctxt "CWAttribute"
+msgid "from_entity"
+msgstr ""
+
+msgctxt "CWRelation"
+msgid "from_entity"
+msgstr ""
+
+msgctxt "CWEType"
+msgid "from_entity_object"
+msgstr ""
+
 msgid "from_entity_object"
 msgstr "Relación sujeto"
 
@@ -1910,6 +2269,14 @@
 msgid "from_state"
 msgstr "De el estado"
 
+msgctxt "TrInfo"
+msgid "from_state"
+msgstr ""
+
+msgctxt "State"
+msgid "from_state_object"
+msgstr ""
+
 msgid "from_state_object"
 msgstr "Transiciones desde este estado"
 
@@ -1919,9 +2286,17 @@
 msgid "fulltext_container"
 msgstr "Contenedor de texto indexado"
 
+msgctxt "CWRType"
+msgid "fulltext_container"
+msgstr ""
+
 msgid "fulltextindexed"
 msgstr "Indexación de texto"
 
+msgctxt "CWAttribute"
+msgid "fulltextindexed"
+msgstr ""
+
 msgid "generic plot"
 msgstr "Trazado de curbas estándares"
 
@@ -1940,6 +2315,10 @@
 msgid "granted to groups"
 msgstr "Otorgado a los grupos"
 
+#, python-format
+msgid "graphical representation of %s"
+msgstr ""
+
 msgid "graphical representation of the instance'schema"
 msgstr ""
 
@@ -2034,12 +2413,103 @@
 msgid "id of main template used to render pages"
 msgstr "ID del template principal"
 
+msgid "identical to"
+msgstr ""
+
 msgid "identical_to"
 msgstr "idéntico a"
 
 msgid "identity"
 msgstr "es idéntico a"
 
+msgctxt "CWRelation"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "Bookmark"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "CWAttribute"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "CWConstraintType"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "State"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "BaseTransition"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "CWEType"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "Workflow"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "CWGroup"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "TrInfo"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "CWConstraint"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "CWUser"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "Transition"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "CWRType"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "SubWorkflowExitPoint"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "ExternalUri"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "CWCache"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "WorkflowTransition"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "RQLExpression"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "CWPermission"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "EmailAddress"
+msgid "identity_object"
+msgstr ""
+
+msgctxt "CWProperty"
+msgid "identity_object"
+msgstr ""
+
 msgid "identity_object"
 msgstr "es idéntico a"
 
@@ -2062,12 +2532,28 @@
 msgid "in_group"
 msgstr "En el grupo"
 
+msgctxt "CWUser"
+msgid "in_group"
+msgstr ""
+
+msgctxt "CWGroup"
+msgid "in_group_object"
+msgstr ""
+
 msgid "in_group_object"
 msgstr "Miembros"
 
 msgid "in_state"
 msgstr "estado"
 
+msgctxt "CWUser"
+msgid "in_state"
+msgstr ""
+
+msgctxt "State"
+msgid "in_state_object"
+msgstr ""
+
 msgid "in_state_object"
 msgstr "estado de"
 
@@ -2087,6 +2573,10 @@
 msgid "indexed"
 msgstr "Indexado"
 
+msgctxt "CWAttribute"
+msgid "indexed"
+msgstr ""
+
 msgid "indicate the current state of an entity"
 msgstr "Indica el estado actual de una entidad"
 
@@ -2103,18 +2593,30 @@
 msgid "initial estimation %s"
 msgstr "Estimación inicial %s"
 
-msgid "initial state for entities of this type"
-msgstr "Estado inicial para las entidades de este tipo"
+msgid "initial state for this workflow"
+msgstr ""
 
 msgid "initial_state"
 msgstr "estado inicial"
 
+msgctxt "Workflow"
+msgid "initial_state"
+msgstr ""
+
+msgctxt "State"
+msgid "initial_state_object"
+msgstr ""
+
 msgid "initial_state_object"
 msgstr "es el estado inicial de"
 
 msgid "inlined"
 msgstr "Puesto en línea"
 
+msgctxt "CWRType"
+msgid "inlined"
+msgstr ""
+
 msgid "instance schema"
 msgstr ""
 
@@ -2124,6 +2626,10 @@
 msgid "internationalizable"
 msgstr "Internacionalizable"
 
+msgctxt "CWAttribute"
+msgid "internationalizable"
+msgstr ""
+
 #, python-format
 msgid "invalid action %r"
 msgstr "Acción %r invalida"
@@ -2163,9 +2669,17 @@
 msgid "is_instance_of"
 msgstr "es una instancia de"
 
+msgctxt "CWEType"
+msgid "is_instance_of_object"
+msgstr ""
+
 msgid "is_instance_of_object"
 msgstr "tiene como instancias"
 
+msgctxt "CWEType"
+msgid "is_object"
+msgstr ""
+
 msgid "is_object"
 msgstr "tiene por instancia"
 
@@ -2181,6 +2695,10 @@
 msgid "label"
 msgstr "Etiqueta"
 
+msgctxt "CWPermission"
+msgid "label"
+msgstr ""
+
 msgid "language of the user interface"
 msgstr "Idioma para la interface del usuario"
 
@@ -2190,6 +2708,10 @@
 msgid "last_login_time"
 msgstr "Ultima fecha de conexión"
 
+msgctxt "CWUser"
+msgid "last_login_time"
+msgstr ""
+
 msgid "latest modification time of an entity"
 msgstr "Fecha de la última modificación de una entidad "
 
@@ -2223,14 +2745,17 @@
 msgid "link a relation definition to its subject entity type"
 msgstr "liga una definición de relación a su tipo de entidad"
 
-msgid "link a state to one or more entity type"
-msgstr "liga un estado a una o mas entidades"
+msgid "link a state to one or more workflow"
+msgstr ""
 
 msgid "link a transition information to its object"
 msgstr "liga una transcion de informacion a los objetos asociados"
 
-msgid "link a transition to one or more entity type"
-msgstr "liga una transición a una o mas tipos de entidad"
+msgid "link a transition to one or more workflow"
+msgstr ""
+
+msgid "link a workflow to one or more entity type"
+msgstr ""
 
 msgid "link to each item in"
 msgstr "ligar hacia cada elemento en"
@@ -2247,6 +2772,10 @@
 msgid "login"
 msgstr "Clave de acesso"
 
+msgctxt "CWUser"
+msgid "login"
+msgstr ""
+
 msgid "login or email"
 msgstr "Clave de acesso o dirección de correo"
 
@@ -2266,6 +2795,10 @@
 msgid "mainvars"
 msgstr "Principales variables"
 
+msgctxt "RQLExpression"
+msgid "mainvars"
+msgstr ""
+
 msgid "manage"
 msgstr "Administracion del Sitio"
 
@@ -2281,6 +2814,9 @@
 msgid "managers"
 msgstr "editores"
 
+msgid "mandatory relation"
+msgstr ""
+
 msgid "march"
 msgstr "Marzo"
 
@@ -2327,6 +2863,50 @@
 msgid "name"
 msgstr "Nombre"
 
+msgctxt "CWEType"
+msgid "name"
+msgstr ""
+
+msgctxt "Transition"
+msgid "name"
+msgstr ""
+
+msgctxt "Workflow"
+msgid "name"
+msgstr ""
+
+msgctxt "CWGroup"
+msgid "name"
+msgstr ""
+
+msgctxt "CWConstraintType"
+msgid "name"
+msgstr ""
+
+msgctxt "WorkflowTransition"
+msgid "name"
+msgstr ""
+
+msgctxt "State"
+msgid "name"
+msgstr ""
+
+msgctxt "CWPermission"
+msgid "name"
+msgstr ""
+
+msgctxt "CWRType"
+msgid "name"
+msgstr ""
+
+msgctxt "BaseTransition"
+msgid "name"
+msgstr ""
+
+msgctxt "CWCache"
+msgid "name"
+msgstr ""
+
 msgid "name of the cache"
 msgstr "Nombre del Cache"
 
@@ -2438,6 +3018,14 @@
 msgid "ordernum"
 msgstr "orden"
 
+msgctxt "CWAttribute"
+msgid "ordernum"
+msgstr ""
+
+msgctxt "CWRelation"
+msgid "ordernum"
+msgstr ""
+
 msgid "owl"
 msgstr "owl"
 
@@ -2447,6 +3035,10 @@
 msgid "owned_by"
 msgstr "pertenece a"
 
+msgctxt "CWUser"
+msgid "owned_by_object"
+msgstr ""
+
 msgid "owned_by_object"
 msgstr "pertenece al objeto"
 
@@ -2471,6 +3063,10 @@
 msgid "path"
 msgstr "Ruta"
 
+msgctxt "Bookmark"
+msgid "path"
+msgstr ""
+
 msgid "permission"
 msgstr "Permiso"
 
@@ -2492,6 +3088,10 @@
 msgid "pkey"
 msgstr "pkey"
 
+msgctxt "CWProperty"
+msgid "pkey"
+msgstr ""
+
 msgid "please correct errors below"
 msgstr "Favor de corregir errores"
 
@@ -2504,6 +3104,20 @@
 msgid "powered by CubicWeb"
 msgstr ""
 
+msgid "prefered_form"
+msgstr ""
+
+msgctxt "EmailAddress"
+msgid "prefered_form"
+msgstr ""
+
+msgctxt "EmailAddress"
+msgid "prefered_form_object"
+msgstr ""
+
+msgid "prefered_form_object"
+msgstr ""
+
 msgid "preferences"
 msgstr "Preferencias"
 
@@ -2516,6 +3130,14 @@
 msgid "primary_email"
 msgstr "Dirección de email principal"
 
+msgctxt "CWUser"
+msgid "primary_email"
+msgstr ""
+
+msgctxt "EmailAddress"
+msgid "primary_email_object"
+msgstr ""
+
 msgid "primary_email_object"
 msgstr "Dirección de email principal (objeto)"
 
@@ -2537,12 +3159,34 @@
 msgid "read_permission"
 msgstr "Permiso de lectura"
 
+msgctxt "CWEType"
+msgid "read_permission"
+msgstr ""
+
+msgctxt "CWRType"
+msgid "read_permission"
+msgstr ""
+
+msgctxt "CWGroup"
+msgid "read_permission_object"
+msgstr ""
+
+msgctxt "RQLExpression"
+msgid "read_permission_object"
+msgstr ""
+
 msgid "read_permission_object"
 msgstr "Objeto_permiso_lectura"
 
 msgid "registry"
 msgstr ""
 
+msgid "related entity has no state"
+msgstr ""
+
+msgid "related entity has no workflow set"
+msgstr ""
+
 #, python-format
 msgid "relation %(relname)s of %(ent)s"
 msgstr "relación %(relname)s de %(ent)s"
@@ -2550,6 +3194,18 @@
 msgid "relation_type"
 msgstr "tipo de relación"
 
+msgctxt "CWAttribute"
+msgid "relation_type"
+msgstr ""
+
+msgctxt "CWRelation"
+msgid "relation_type"
+msgstr ""
+
+msgctxt "CWRType"
+msgid "relation_type_object"
+msgstr ""
+
 msgid "relation_type_object"
 msgstr "Definición"
 
@@ -2562,63 +3218,45 @@
 msgid "relative url of the bookmarked page"
 msgstr "Url relativa de la pagina"
 
-msgid "remove this Bookmark"
-msgstr "Eliminar este Favorito"
-
-msgid "remove this CWAttribute"
-msgstr "Eliminar este atributo"
-
-msgid "remove this CWCache"
-msgstr "Eliminar esta cache de aplicación"
-
-msgid "remove this CWConstraint"
-msgstr "Eliminar esta restricción"
-
-msgid "remove this CWConstraintType"
-msgstr "Eliminar este tipo de restricción"
-
+msgctxt "inlined:CWRelation:from_entity:subject"
+msgid "remove this CWEType"
+msgstr ""
+
+msgctxt "inlined:CWRelation:to_entity:subject"
 msgid "remove this CWEType"
-msgstr "Eliminar este tipo de entidad"
-
-msgid "remove this CWGroup"
-msgstr "Eliminar este grupo"
-
-msgid "remove this CWPermission"
-msgstr "Eliminar este permiso"
-
-msgid "remove this CWProperty"
-msgstr "Eliminar esta propiedad"
-
+msgstr ""
+
+msgctxt "inlined:CWRelation:relation_type:subject"
 msgid "remove this CWRType"
-msgstr "Eliminar esta definición de relación"
-
-msgid "remove this CWRelation"
-msgstr "Eliminar esta relación"
-
-msgid "remove this CWUser"
-msgstr "Eliminar este usuario"
-
+msgstr ""
+
+msgctxt "inlined:CWUser:use_email:subject"
 msgid "remove this EmailAddress"
-msgstr "Eliminar este correo electronico"
-
-msgid "remove this ExternalUri"
-msgstr ""
-
-msgid "remove this RQLExpression"
-msgstr "Eliminar esta expresión RQL"
-
-msgid "remove this State"
-msgstr "Eliminar este estado"
-
-msgid "remove this TrInfo"
-msgstr "Eliminar información de esta transición"
-
-msgid "remove this Transition"
-msgstr "Eliminar esta transición"
+msgstr ""
 
 msgid "require_group"
 msgstr "Requiere grupo"
 
+msgctxt "BaseTransition"
+msgid "require_group"
+msgstr ""
+
+msgctxt "Transition"
+msgid "require_group"
+msgstr ""
+
+msgctxt "CWPermission"
+msgid "require_group"
+msgstr ""
+
+msgctxt "WorkflowTransition"
+msgid "require_group"
+msgstr ""
+
+msgctxt "CWGroup"
+msgid "require_group_object"
+msgstr ""
+
 msgid "require_group_object"
 msgstr "Requerido por grupo"
 
@@ -2747,6 +3385,9 @@
 msgid "semantic description of this transition"
 msgstr "descripcion semantica de esta transición"
 
+msgid "semantic description of this workflow"
+msgstr ""
+
 msgid "send email"
 msgstr "enviar email"
 
@@ -2803,9 +3444,20 @@
 msgid "sparql xml"
 msgstr ""
 
+msgid "special transition allowing to go through a sub-workflow"
+msgstr ""
+
 msgid "specializes"
 msgstr "derivado de"
 
+msgctxt "CWEType"
+msgid "specializes"
+msgstr ""
+
+msgctxt "CWEType"
+msgid "specializes_object"
+msgstr ""
+
 msgid "specializes_object"
 msgstr "objeto_derivado"
 
@@ -2815,9 +3467,28 @@
 msgid "state"
 msgstr "estado"
 
+msgid "state doesn't belong to entity's current workflow"
+msgstr ""
+
+msgid "state doesn't belong to entity's workflow"
+msgstr ""
+
+msgid ""
+"state doesn't belong to entity's workflow. You may want to set a custom "
+"workflow for this entity first."
+msgstr ""
+
 msgid "state_of"
 msgstr "estado_de"
 
+msgctxt "State"
+msgid "state_of"
+msgstr ""
+
+msgctxt "Workflow"
+msgid "state_of_object"
+msgstr ""
+
 msgid "state_of_object"
 msgstr "objeto_estado_de"
 
@@ -2840,15 +3511,68 @@
 msgid "subject_plural:"
 msgstr "sujetos:"
 
+msgid "subworkflow"
+msgstr ""
+
+msgctxt "WorkflowTransition"
+msgid "subworkflow"
+msgstr ""
+
+msgid "subworkflow state"
+msgstr ""
+
+msgid "subworkflow_exit"
+msgstr ""
+
+msgctxt "WorkflowTransition"
+msgid "subworkflow_exit"
+msgstr ""
+
+msgctxt "SubWorkflowExitPoint"
+msgid "subworkflow_exit_object"
+msgstr ""
+
+msgid "subworkflow_exit_object"
+msgstr ""
+
+msgctxt "Workflow"
+msgid "subworkflow_object"
+msgstr ""
+
+msgid "subworkflow_object"
+msgstr ""
+
+msgid "subworkflow_state"
+msgstr ""
+
+msgctxt "SubWorkflowExitPoint"
+msgid "subworkflow_state"
+msgstr ""
+
+msgctxt "State"
+msgid "subworkflow_state_object"
+msgstr ""
+
+msgid "subworkflow_state_object"
+msgstr ""
+
 msgid "sunday"
 msgstr "domingo"
 
 msgid "surname"
 msgstr "apellido"
 
+msgctxt "CWUser"
+msgid "surname"
+msgstr ""
+
 msgid "symetric"
 msgstr "simetrico"
 
+msgctxt "CWRType"
+msgid "symetric"
+msgstr ""
+
 msgid "system entities"
 msgstr "entidades de sistema"
 
@@ -2904,6 +3628,10 @@
 msgid "timestamp"
 msgstr "fecha"
 
+msgctxt "CWCache"
+msgid "timestamp"
+msgstr ""
+
 msgid "timestamp of the latest source synchronization."
 msgstr "fecha de la ultima sincronización de la fuente."
 
@@ -2913,6 +3641,10 @@
 msgid "title"
 msgstr "titulo"
 
+msgctxt "Bookmark"
+msgid "title"
+msgstr ""
+
 msgid "to"
 msgstr "a"
 
@@ -2926,6 +3658,18 @@
 msgid "to_entity"
 msgstr "hacia entidad"
 
+msgctxt "CWAttribute"
+msgid "to_entity"
+msgstr ""
+
+msgctxt "CWRelation"
+msgid "to_entity"
+msgstr ""
+
+msgctxt "CWEType"
+msgid "to_entity_object"
+msgstr ""
+
 msgid "to_entity_object"
 msgstr "hacia entidad objeto"
 
@@ -2935,6 +3679,14 @@
 msgid "to_state"
 msgstr "hacia el estado"
 
+msgctxt "TrInfo"
+msgid "to_state"
+msgstr ""
+
+msgctxt "State"
+msgid "to_state_object"
+msgstr ""
+
 msgid "to_state_object"
 msgstr "hacia objeto estado"
 
@@ -2944,13 +3696,34 @@
 msgid "toggle check boxes"
 msgstr "cambiar valor"
 
-#, python-format
-msgid "transition from %s to %s does not exist or is not allowed"
+msgid "transition doesn't belong to entity's workflow"
+msgstr ""
+
+msgid "transition isn't allowed"
+msgstr ""
+
+msgid "transition may not be fired"
 msgstr ""
 
 msgid "transition_of"
 msgstr "transicion de"
 
+msgctxt "BaseTransition"
+msgid "transition_of"
+msgstr ""
+
+msgctxt "Transition"
+msgid "transition_of"
+msgstr ""
+
+msgctxt "WorkflowTransition"
+msgid "transition_of"
+msgstr ""
+
+msgctxt "Workflow"
+msgid "transition_of_object"
+msgstr ""
+
 msgid "transition_of_object"
 msgstr "objeto de transición"
 
@@ -3023,6 +3796,10 @@
 msgid "upassword"
 msgstr "clave de acceso"
 
+msgctxt "CWUser"
+msgid "upassword"
+msgstr ""
+
 msgid "update"
 msgstr "modificación"
 
@@ -3032,6 +3809,18 @@
 msgid "update_permission"
 msgstr "Permiso de modificación"
 
+msgctxt "CWEType"
+msgid "update_permission"
+msgstr ""
+
+msgctxt "CWGroup"
+msgid "update_permission_object"
+msgstr ""
+
+msgctxt "RQLExpression"
+msgid "update_permission_object"
+msgstr ""
+
 msgid "update_permission_object"
 msgstr "objeto de autorización de modificaciones"
 
@@ -3042,6 +3831,10 @@
 msgid "uri"
 msgstr ""
 
+msgctxt "ExternalUri"
+msgid "uri"
+msgstr ""
+
 msgid "use template languages"
 msgstr "utilizar plantillas de lenguaje"
 
@@ -3055,6 +3848,14 @@
 msgid "use_email"
 msgstr "correo electrónico"
 
+msgctxt "CWUser"
+msgid "use_email"
+msgstr ""
+
+msgctxt "EmailAddress"
+msgid "use_email_object"
+msgstr ""
+
 msgid "use_email_object"
 msgstr "objeto email utilizado"
 
@@ -3113,6 +3914,14 @@
 msgid "value"
 msgstr "valor"
 
+msgctxt "CWConstraint"
+msgid "value"
+msgstr ""
+
+msgctxt "CWProperty"
+msgid "value"
+msgstr ""
+
 msgid "value associated to this key is not editable manually"
 msgstr "el valor asociado a este elemento no es editable manualmente"
 
@@ -3159,21 +3968,55 @@
 msgid "wf_info_for"
 msgstr "historial de"
 
+msgctxt "TrInfo"
+msgid "wf_info_for"
+msgstr ""
+
+msgctxt "CWUser"
+msgid "wf_info_for_object"
+msgstr ""
+
 msgid "wf_info_for_object"
 msgstr "historial de transiciones"
 
 msgid ""
 "when multiple addresses are equivalent (such as python-projects@logilab.org "
-"and python-projects@lists.logilab.org), set this to true on one of them "
-"which is the preferred form."
-msgstr ""
-"cuando multiples direcciones de correo son equivalentes (como python-"
-"projects@logilab.org y python-projects@lists.logilab.org), establecer esto "
-"como verdadero en una de ellas es la forma preferida "
+"and python-projects@lists.logilab.org), set this to indicate which is the "
+"preferred form."
+msgstr ""
+
+msgid "workflow"
+msgstr ""
 
 #, python-format
-msgid "workflow for %s"
-msgstr "workflow para %s"
+msgid "workflow changed to \"%s\""
+msgstr ""
+
+msgid "workflow has no initial state"
+msgstr ""
+
+msgid "workflow history item"
+msgstr ""
+
+msgid "workflow to which this state belongs"
+msgstr ""
+
+msgid "workflow to which this transition belongs"
+msgstr ""
+
+msgid "workflow_of"
+msgstr ""
+
+msgctxt "Workflow"
+msgid "workflow_of"
+msgstr ""
+
+msgctxt "CWEType"
+msgid "workflow_of_object"
+msgstr ""
+
+msgid "workflow_of_object"
+msgstr ""
 
 msgid "xbel"
 msgstr "xbel"
@@ -3193,6 +4036,165 @@
 msgid "you should probably delete that property"
 msgstr "deberia probablamente suprimir esta propriedad"
 
+#~ msgid "There is no workflow defined for this entity."
+#~ msgstr "No hay workflow para este entidad"
+
+#~ msgid "This %s"
+#~ msgstr "Este %s"
+
 #~ msgid ""
 #~ "You have no access to this view or it's not applyable to current data"
 #~ msgstr "No tiene acceso a esta vista o No es aplicable a los datos actuales"
+
+#~ msgid "__msg state changed"
+#~ msgstr "El estado a cambiado"
+
+#~ msgid "account state"
+#~ msgstr "Estado de la Cuenta"
+
+#~ msgid "add State state_of CWEType object"
+#~ msgstr "Estado"
+
+#~ msgid "add Transition transition_of CWEType object"
+#~ msgstr "Transición"
+
+#~ msgid "add a Bookmark"
+#~ msgstr "Agregar un Favorito"
+
+#~ msgid "add a CWAttribute"
+#~ msgstr "Agregar un tipo de relación"
+
+#~ msgid "add a CWCache"
+#~ msgstr "Agregar un cache"
+
+#~ msgid "add a CWConstraint"
+#~ msgstr "Agregar una Restricción"
+
+#~ msgid "add a CWConstraintType"
+#~ msgstr "Agregar un tipo de Restricción"
+
+#~ msgid "add a CWEType"
+#~ msgstr "Agregar un tipo de entidad"
+
+#~ msgid "add a CWGroup"
+#~ msgstr "Agregar un grupo de usuarios"
+
+#~ msgid "add a CWPermission"
+#~ msgstr "Agregar una autorización"
+
+#~ msgid "add a CWProperty"
+#~ msgstr "Agregar una propiedad"
+
+#~ msgid "add a CWRType"
+#~ msgstr "Agregar un tipo de relación"
+
+#~ msgid "add a CWRelation"
+#~ msgstr "Agregar una relación"
+
+#~ msgid "add a CWUser"
+#~ msgstr "Agregar un usuario"
+
+#~ msgid "add a EmailAddress"
+#~ msgstr "Agregar un email"
+
+#~ msgid "add a RQLExpression"
+#~ msgstr "Agregar una expresión rql"
+
+#~ msgid "add a State"
+#~ msgstr "Agregar un estado"
+
+#~ msgid "add a TrInfo"
+#~ msgstr "Agregar una información de transición"
+
+#~ msgid "add a Transition"
+#~ msgstr "Agregar una transición"
+
+#~ msgid "canonical"
+#~ msgstr "canónico"
+
+#~ msgid "comment:"
+#~ msgstr "Comentario:"
+
+#~ msgid "creating State (State state_of CWEType %(linkto)s)"
+#~ msgstr "Creación de un estado por el tipo %(linkto)s"
+
+#~ msgid "creating Transition (Transition transition_of CWEType %(linkto)s)"
+#~ msgstr "Creación de una transición para el tipo %(linkto)s"
+
+#~ msgid "entity types which may use this state"
+#~ msgstr "Tipo de entidades que pueden utilizar este estado"
+
+#~ msgid "entity types which may use this transition"
+#~ msgstr "Entidades que pueden utilizar esta transición"
+
+#~ msgid "initial state for entities of this type"
+#~ msgstr "Estado inicial para las entidades de este tipo"
+
+#~ msgid "link a state to one or more entity type"
+#~ msgstr "liga un estado a una o mas entidades"
+
+#~ msgid "link a transition to one or more entity type"
+#~ msgstr "liga una transición a una o mas tipos de entidad"
+
+#~ msgid "remove this Bookmark"
+#~ msgstr "Eliminar este Favorito"
+
+#~ msgid "remove this CWAttribute"
+#~ msgstr "Eliminar este atributo"
+
+#~ msgid "remove this CWCache"
+#~ msgstr "Eliminar esta cache de aplicación"
+
+#~ msgid "remove this CWConstraint"
+#~ msgstr "Eliminar esta restricción"
+
+#~ msgid "remove this CWConstraintType"
+#~ msgstr "Eliminar este tipo de restricción"
+
+#~ msgid "remove this CWEType"
+#~ msgstr "Eliminar este tipo de entidad"
+
+#~ msgid "remove this CWGroup"
+#~ msgstr "Eliminar este grupo"
+
+#~ msgid "remove this CWPermission"
+#~ msgstr "Eliminar este permiso"
+
+#~ msgid "remove this CWProperty"
+#~ msgstr "Eliminar esta propiedad"
+
+#~ msgid "remove this CWRType"
+#~ msgstr "Eliminar esta definición de relación"
+
+#~ msgid "remove this CWRelation"
+#~ msgstr "Eliminar esta relación"
+
+#~ msgid "remove this CWUser"
+#~ msgstr "Eliminar este usuario"
+
+#~ msgid "remove this EmailAddress"
+#~ msgstr "Eliminar este correo electronico"
+
+#~ msgid "remove this RQLExpression"
+#~ msgstr "Eliminar esta expresión RQL"
+
+#~ msgid "remove this State"
+#~ msgstr "Eliminar este estado"
+
+#~ msgid "remove this TrInfo"
+#~ msgstr "Eliminar información de esta transición"
+
+#~ msgid "remove this Transition"
+#~ msgstr "Eliminar esta transición"
+
+#~ msgid ""
+#~ "when multiple addresses are equivalent (such as python-projects@logilab."
+#~ "org and python-projects@lists.logilab.org), set this to true on one of "
+#~ "them which is the preferred form."
+#~ msgstr ""
+#~ "cuando multiples direcciones de correo son equivalentes (como python-"
+#~ "projects@logilab.org y python-projects@lists.logilab.org), establecer "
+#~ "esto como verdadero en una de ellas es la forma preferida "
+
+#~ msgid "workflow for %s"
+#~ msgstr "workflow para %s"
--- a/i18n/fr.po	Tue Sep 15 15:01:41 2009 +0200
+++ b/i18n/fr.po	Thu Sep 17 15:16:53 2009 +0200
@@ -4,7 +4,7 @@
 msgid ""
 msgstr ""
 "Project-Id-Version: cubicweb 2.46.0\n"
-"PO-Revision-Date: 2009-08-05 08:37+0200\n"
+"PO-Revision-Date: 2009-09-17 12:03+0200\n"
 "Last-Translator: Logilab Team <contact@logilab.fr>\n"
 "Language-Team: fr <contact@logilab.fr>\n"
 "MIME-Version: 1.0\n"
@@ -112,10 +112,6 @@
 msgstr "%s rapport d'erreur"
 
 #, python-format
-msgid "%s is not the initial state (%s) for this entity"
-msgstr "%s n'est pas l'état initial (%s) de cette entité"
-
-#, python-format
 msgid "%s not estimated"
 msgstr "%s non estimé(s)"
 
@@ -204,6 +200,15 @@
 msgid "Attributes"
 msgstr "Attributs"
 
+# schema pot file, generated on 2009-09-16 16:46:55
+#
+# singular and plural forms for each entity type
+msgid "BaseTransition"
+msgstr "Transition (abstraite)"
+
+msgid "BaseTransition_plural"
+msgstr "Transitions (abstraites)"
+
 msgid "Bookmark"
 msgstr "Signet"
 
@@ -358,6 +363,9 @@
 msgid "Interval_plural"
 msgstr "Durées"
 
+msgid "New BaseTransition"
+msgstr "XXX"
+
 msgid "New Bookmark"
 msgstr "Nouveau signet"
 
@@ -406,12 +414,21 @@
 msgid "New State"
 msgstr "Nouvel état"
 
+msgid "New SubWorkflowExitPoint"
+msgstr "Nouvelle sortie de sous-workflow"
+
 msgid "New TrInfo"
 msgstr "Nouvelle information de transition"
 
 msgid "New Transition"
 msgstr "Nouvelle transition"
 
+msgid "New Workflow"
+msgstr "Nouveau workflow"
+
+msgid "New WorkflowTransition"
+msgstr "Nouvelle transition workflow"
+
 msgid "No query has been executed"
 msgstr "Aucune requête n'a été éxécuté"
 
@@ -479,6 +496,12 @@
 msgid "String_plural"
 msgstr "Chaînes de caractères"
 
+msgid "SubWorkflowExitPoint"
+msgstr "Sortie de sous-workflow"
+
+msgid "SubWorkflowExitPoint_plural"
+msgstr "Sorties de sous-workflow"
+
 msgid "Subject:"
 msgstr "Sujet :"
 
@@ -499,12 +522,8 @@
 msgid "The view %s could not be found"
 msgstr "La vue %s est introuvable"
 
-msgid "There is no workflow defined for this entity."
-msgstr "Il n'y a pas de workflow défini pour ce type d'entité"
-
-#, python-format
-msgid "This %s"
-msgstr "Ce %s"
+msgid "This BaseTransition"
+msgstr "Cette transition abstraite"
 
 msgid "This Bookmark"
 msgstr "Ce signet"
@@ -554,12 +573,21 @@
 msgid "This State"
 msgstr "Cet état"
 
+msgid "This SubWorkflowExitPoint"
+msgstr "Cette sortie de sous-workflow"
+
 msgid "This TrInfo"
 msgstr "Cette information de transition"
 
 msgid "This Transition"
 msgstr "Cette transition"
 
+msgid "This Workflow"
+msgstr "Ce workflow"
+
+msgid "This WorkflowTransition"
+msgstr "Cette transition workflow"
+
 msgid "Time"
 msgstr "Heure"
 
@@ -591,9 +619,21 @@
 msgid "What's new?"
 msgstr "Nouveautés"
 
+msgid "Workflow"
+msgstr "Workflow"
+
 msgid "Workflow history"
 msgstr "Historique des changements d'état"
 
+msgid "WorkflowTransition"
+msgstr "Transition workflow"
+
+msgid "WorkflowTransition_plural"
+msgstr "Transitions workflow"
+
+msgid "Workflow_plural"
+msgstr "Workflows"
+
 msgid "You are not connected to an instance !"
 msgstr "Vous n'êtes pas connecté à une instance"
 
@@ -627,7 +667,8 @@
 msgid ""
 "You have no access to this view or it can not be used to display the current "
 "data."
-msgstr "Vous n'avez pas accès à cette vue ou elle ne peut pas afficher ces données."
+msgstr ""
+"Vous n'avez pas accès à cette vue ou elle ne peut pas afficher ces données."
 
 msgid ""
 "You're not authorized to access this page. If you think you should, please "
@@ -640,9 +681,6 @@
 msgid "[%s supervision] changes summary"
 msgstr "[%s supervision] description des changements"
 
-msgid "__msg state changed"
-msgstr "l'état a été changé"
-
 msgid ""
 "a RQL expression which should return some results, else the transition won't "
 "be available. This query may use X and U variables that will respectivly "
@@ -671,12 +709,12 @@
 msgid "about this site"
 msgstr "à propos de ce site"
 
+msgid "abstract base class for transitions"
+msgstr "classe de base abstraite pour les transitions"
+
 msgid "access type"
 msgstr "type d'accès"
 
-msgid "account state"
-msgstr "état du compte"
-
 msgid "action(s) on this selection"
 msgstr "action(s) sur cette sélection"
 
@@ -689,6 +727,12 @@
 msgid "actions_addentity_description"
 msgstr ""
 
+msgid "actions_addrelated"
+msgstr "menu ajouter"
+
+msgid "actions_addrelated_description"
+msgstr ""
+
 msgid "actions_cancel"
 msgstr "annuler la sélection"
 
@@ -867,82 +911,47 @@
 msgstr "utilisateur"
 
 msgid "add CWUser use_email EmailAddress subject"
-msgstr "ajouter une addresse email"
+msgstr "addresse email"
 
 msgid "add State allowed_transition Transition object"
-msgstr "ajouter un état en entrée"
+msgstr "état en entrée"
 
 msgid "add State allowed_transition Transition subject"
-msgstr "ajouter une transition en sortie"
-
-msgid "add State state_of CWEType object"
-msgstr "ajouter un état"
+msgstr "transition en sortie"
+
+msgid "add State allowed_transition WorkflowTransition subject"
+msgstr "transition workflow en sortie"
 
 msgid "add Transition condition RQLExpression subject"
-msgstr "ajouter une condition"
+msgstr "condition"
 
 msgid "add Transition destination_state State object"
-msgstr "ajouter une transition en entrée"
+msgstr "transition en entrée"
 
 msgid "add Transition destination_state State subject"
-msgstr "ajouter l'état de sortie"
-
-msgid "add Transition transition_of CWEType object"
-msgstr "ajouter une transition"
-
-msgid "add a Bookmark"
-msgstr "ajouter un signet"
-
-msgid "add a CWAttribute"
-msgstr "ajouter un type de relation"
-
-msgid "add a CWCache"
-msgstr "ajouter un cache applicatif"
-
-msgid "add a CWConstraint"
-msgstr "ajouter une contrainte"
-
-msgid "add a CWConstraintType"
-msgstr "ajouter un type de contrainte"
-
+msgstr "état de sortie"
+
+msgid "add WorkflowTransition condition RQLExpression subject"
+msgstr "condition"
+
+msgid "add WorkflowTransition subworkflow_exit SubWorkflowExitPoint subject"
+msgstr "sortie de sous-workflow"
+
+msgctxt "inlined:CWRelation.from_entity.subject"
 msgid "add a CWEType"
-msgstr "ajouter un type d'entité"
-
-msgid "add a CWGroup"
-msgstr "ajouter un groupe d'utilisateurs"
-
-msgid "add a CWPermission"
-msgstr "ajouter une permission"
-
-msgid "add a CWProperty"
-msgstr "ajouter une propriété"
-
+msgstr "ajouter un type d'entité sujet"
+
+msgctxt "inlined:CWRelation.to_entity.subject"
+msgid "add a CWEType"
+msgstr "ajouter un type d'entité objet"
+
+msgctxt "inlined:CWRelation.relation_type.subject"
 msgid "add a CWRType"
 msgstr "ajouter un type de relation"
 
-msgid "add a CWRelation"
-msgstr "ajouter une relation"
-
-msgid "add a CWUser"
-msgstr "ajouter un utilisateur"
-
+msgctxt "inlined:CWUser.use_email.subject"
 msgid "add a EmailAddress"
-msgstr "ajouter une adresse email"
-
-msgid "add a ExternalUri"
-msgstr "ajouter une Uri externe"
-
-msgid "add a RQLExpression"
-msgstr "ajouter une expression rql"
-
-msgid "add a State"
-msgstr "ajouter un état"
-
-msgid "add a TrInfo"
-msgstr "ajouter une information de transition"
-
-msgid "add a Transition"
-msgstr "ajouter une transition"
+msgstr "ajouter une adresse électronique"
 
 msgid "add a new permission"
 msgstr "ajouter une permission"
@@ -956,7 +965,25 @@
 # subject and object forms for each relation type
 # (no object form for final relation types)
 msgid "add_permission"
-msgstr "permission d'ajouter"
+msgstr "peut ajouter"
+
+# subject and object forms for each relation type
+# (no object form for final relation types)
+msgctxt "CWEType"
+msgid "add_permission"
+msgstr "permission d'ajout"
+
+msgctxt "CWRType"
+msgid "add_permission"
+msgstr "permission d'ajout"
+
+msgctxt "CWGroup"
+msgid "add_permission_object"
+msgstr "a la permission d'ajouter"
+
+msgctxt "RQLExpression"
+msgid "add_permission_object"
+msgstr "a la permission d'ajouter"
 
 msgid "add_permission_object"
 msgstr "a la permission d'ajouter"
@@ -973,12 +1000,26 @@
 "ajout de la relation %(rtype)s de %(frometype)s #%(fromeid)s vers %(toetype)"
 "s #%(toeid)s"
 
+msgid "addrelated"
+msgstr "ajouter"
+
+msgid "address"
+msgstr "adresse électronique"
+
+msgctxt "EmailAddress"
 msgid "address"
 msgstr "adresse électronique"
 
 msgid "alias"
 msgstr "alias"
 
+msgctxt "EmailAddress"
+msgid "alias"
+msgstr "alias"
+
+msgid "allow to set a specific workflow for an entity"
+msgstr "permet de spécifier un workflow donné pour une entité"
+
 msgid "allowed transition from this state"
 msgstr "transition autorisée depuis cet état"
 
@@ -988,6 +1029,22 @@
 msgid "allowed_transition"
 msgstr "transition autorisée"
 
+msgctxt "State"
+msgid "allowed_transition"
+msgstr "transitions autorisées"
+
+msgctxt "BaseTransition"
+msgid "allowed_transition_object"
+msgstr "transition autorisée de"
+
+msgctxt "Transition"
+msgid "allowed_transition_object"
+msgstr "transition autorisée de"
+
+msgctxt "WorkflowTransition"
+msgid "allowed_transition_object"
+msgstr "transition autorisée de"
+
 msgid "allowed_transition_object"
 msgstr "états en entrée"
 
@@ -1069,6 +1126,14 @@
 msgid "bookmarked_by"
 msgstr "utilisé par"
 
+msgctxt "Bookmark"
+msgid "bookmarked_by"
+msgstr "utilisé par"
+
+msgctxt "CWUser"
+msgid "bookmarked_by_object"
+msgstr "utilise le(s) signet(s)"
+
 msgid "bookmarked_by_object"
 msgstr "a pour signets"
 
@@ -1155,6 +1220,28 @@
 msgid "by relation"
 msgstr "via la relation"
 
+msgid "by_transition"
+msgstr "transition"
+
+msgctxt "TrInfo"
+msgid "by_transition"
+msgstr "transition"
+
+msgctxt "BaseTransition"
+msgid "by_transition_object"
+msgstr "a pour information"
+
+msgctxt "Transition"
+msgid "by_transition_object"
+msgstr "a pour information"
+
+msgctxt "WorkflowTransition"
+msgid "by_transition_object"
+msgstr "a pour information"
+
+msgid "by_transition_object"
+msgstr "changement d'états"
+
 msgid "calendar"
 msgstr "afficher un calendrier"
 
@@ -1185,6 +1272,9 @@
 msgid "can't display data, unexpected error: %s"
 msgstr "impossible d'afficher les données à cause de l'erreur suivante: %s"
 
+msgid "can't have multiple exits on the same state"
+msgstr "ne peut avoir plusieurs sorties sur le même état"
+
 #, python-format
 msgid ""
 "can't set inlined=%(inlined)s, %(stype)s %(rtype)s %(otype)s has cardinality="
@@ -1199,9 +1289,14 @@
 msgid "cancel this insert"
 msgstr "annuler cette insertion"
 
-msgid "canonical"
-msgstr "canonique"
-
+msgid "cardinality"
+msgstr "cardinalité"
+
+msgctxt "CWAttribute"
+msgid "cardinality"
+msgstr "cardinalité"
+
+msgctxt "CWRelation"
 msgid "cardinality"
 msgstr "cardinalité"
 
@@ -1227,9 +1322,14 @@
 msgid "comment"
 msgstr "commentaire"
 
-msgid "comment:"
-msgstr "commentaire :"
-
+msgctxt "TrInfo"
+msgid "comment"
+msgstr "commentaire"
+
+msgid "comment_format"
+msgstr "format"
+
+msgctxt "TrInfo"
 msgid "comment_format"
 msgstr "format"
 
@@ -1284,6 +1384,12 @@
 "composant permettant de présenter sur plusieurs pages les requêtes renvoyant "
 "plus d'un certain nombre de résultat"
 
+msgid "components_pdfview"
+msgstr "icône pdf"
+
+msgid "components_pdfview_description"
+msgstr "l'icône pdf pour obtenir la page courant au format PDF"
+
 msgid "components_rqlinput"
 msgstr "barre rql"
 
@@ -1293,12 +1399,32 @@
 msgid "composite"
 msgstr "composite"
 
+msgctxt "CWRelation"
+msgid "composite"
+msgstr "composite"
+
+msgid "condition"
+msgstr "condition"
+
+msgctxt "BaseTransition"
+msgid "condition"
+msgstr "condition"
+
+msgctxt "Transition"
+msgid "condition"
+msgstr "condition"
+
+msgctxt "WorkflowTransition"
 msgid "condition"
 msgstr "condition"
 
 msgid "condition:"
 msgstr "condition :"
 
+msgctxt "RQLExpression"
+msgid "condition_object"
+msgstr "condition de"
+
 msgid "condition_object"
 msgstr "condition de"
 
@@ -1308,6 +1434,18 @@
 msgid "constrained_by"
 msgstr "contraint par"
 
+msgctxt "CWAttribute"
+msgid "constrained_by"
+msgstr "contraint par"
+
+msgctxt "CWRelation"
+msgid "constrained_by"
+msgstr "contraint par"
+
+msgctxt "CWConstraint"
+msgid "constrained_by_object"
+msgstr "contrainte de"
+
 msgid "constrained_by_object"
 msgstr "contrainte de"
 
@@ -1440,6 +1578,10 @@
 msgid "created_by"
 msgstr "créé par"
 
+msgctxt "CWUser"
+msgid "created_by_object"
+msgstr "a créé"
+
 msgid "created_by_object"
 msgstr "a créé"
 
@@ -1508,23 +1650,32 @@
 msgid "creating RQLExpression (Transition %(linkto)s condition RQLExpression)"
 msgstr "création d'une expression RQL pour la transition %(linkto)s"
 
+msgid ""
+"creating RQLExpression (WorkflowTransition %(linkto)s condition "
+"RQLExpression)"
+msgstr "création d'une expression RQL pour la transition workflow %(linkto)s"
+
 msgid "creating State (State allowed_transition Transition %(linkto)s)"
 msgstr "création d'un état pouvant aller vers la transition %(linkto)s"
 
-msgid "creating State (State state_of CWEType %(linkto)s)"
-msgstr "création d'un état pour le type %(linkto)s"
-
 msgid "creating State (Transition %(linkto)s destination_state State)"
 msgstr "création d'un état destination de la transition %(linkto)s"
 
+msgid ""
+"creating SubWorkflowExitPoint (WorkflowTransition %(linkto)s "
+"subworkflow_exit SubWorkflowExitPoint)"
+msgstr "création d'un point de sortie de la transition workflow %(linkto)s"
+
 msgid "creating Transition (State %(linkto)s allowed_transition Transition)"
 msgstr "création d'une transition autorisée depuis l'état %(linkto)s"
 
 msgid "creating Transition (Transition destination_state State %(linkto)s)"
 msgstr "création d'une transition vers l'état %(linkto)s"
 
-msgid "creating Transition (Transition transition_of CWEType %(linkto)s)"
-msgstr "création d'une transition pour le type %(linkto)s"
+msgid ""
+"creating WorkflowTransition (State %(linkto)s allowed_transition "
+"WorkflowTransition)"
+msgstr "création d'une transition workflow autorisée depuis l'état %(linkto)s"
 
 msgid "creation"
 msgstr "création"
@@ -1538,6 +1689,14 @@
 msgid "cstrtype"
 msgstr "type de constrainte"
 
+msgctxt "CWConstraint"
+msgid "cstrtype"
+msgstr "type"
+
+msgctxt "CWConstraintType"
+msgid "cstrtype_object"
+msgstr "type des contraintes"
+
 msgid "cstrtype_object"
 msgstr "utilisé par"
 
@@ -1551,6 +1710,20 @@
 msgid "currently attached file: %s"
 msgstr "fichie actuellement attaché %s"
 
+msgid "custom_workflow"
+msgstr "workflow spécifique"
+
+msgctxt "CWUser"
+msgid "custom_workflow"
+msgstr "workflow spécifique"
+
+msgctxt "Workflow"
+msgid "custom_workflow_object"
+msgstr "workflow spécifique de"
+
+msgid "custom_workflow_object"
+msgstr "workflow de"
+
 msgid "cwetype-schema-image"
 msgstr "schéma"
 
@@ -1587,6 +1760,30 @@
 msgid "default text format for rich text fields."
 msgstr "format de texte par défaut pour les champs textes"
 
+msgid "default user workflow"
+msgstr "workflow par défaut des utilisateurs"
+
+msgid "default workflow for an entity type"
+msgstr "workflow par défaut pour un type d'entité"
+
+msgid "default_workflow"
+msgstr "workflow par défaut"
+
+msgctxt "CWEType"
+msgid "default_workflow"
+msgstr "workflow par défaut"
+
+msgctxt "Workflow"
+msgid "default_workflow_object"
+msgstr "workflow par défaut de"
+
+msgid "default_workflow_object"
+msgstr "workflow par défaut de"
+
+msgid "defaultval"
+msgstr "valeur par défaut"
+
+msgctxt "CWAttribute"
 msgid "defaultval"
 msgstr "valeur par défaut"
 
@@ -1626,6 +1823,9 @@
 msgid "define an entity type, used to build the instance schema"
 msgstr "définit un type d'entité"
 
+msgid "define how we get out from a sub-workflow"
+msgstr "définit comment sortir d'un sous-workflow"
+
 msgid ""
 "defines what's the property is applied for. You must select this first to be "
 "able to set value"
@@ -1651,6 +1851,22 @@
 msgid "delete_permission"
 msgstr "permission de supprimer"
 
+msgctxt "CWEType"
+msgid "delete_permission"
+msgstr "permission de supprimer"
+
+msgctxt "CWRType"
+msgid "delete_permission"
+msgstr "permission de supprimer"
+
+msgctxt "CWGroup"
+msgid "delete_permission_object"
+msgstr "peut supprimer"
+
+msgctxt "RQLExpression"
+msgid "delete_permission_object"
+msgstr "peut supprimer"
+
 msgid "delete_permission_object"
 msgstr "a la permission de supprimer"
 
@@ -1672,9 +1888,84 @@
 msgid "description"
 msgstr "description"
 
+msgctxt "CWEType"
+msgid "description"
+msgstr "description"
+
+msgctxt "CWRelation"
+msgid "description"
+msgstr "description"
+
+msgctxt "Workflow"
+msgid "description"
+msgstr "description"
+
+msgctxt "CWAttribute"
+msgid "description"
+msgstr "description"
+
+msgctxt "Transition"
+msgid "description"
+msgstr "description"
+
+msgctxt "WorkflowTransition"
+msgid "description"
+msgstr "description"
+
+msgctxt "State"
+msgid "description"
+msgstr "description"
+
+msgctxt "CWRType"
+msgid "description"
+msgstr "description"
+
+msgctxt "BaseTransition"
+msgid "description"
+msgstr "description"
+
 msgid "description_format"
 msgstr "format"
 
+msgctxt "CWEType"
+msgid "description_format"
+msgstr "format"
+
+msgctxt "CWRelation"
+msgid "description_format"
+msgstr "format"
+
+msgctxt "Workflow"
+msgid "description_format"
+msgstr "format"
+
+msgctxt "CWAttribute"
+msgid "description_format"
+msgstr "format"
+
+msgctxt "Transition"
+msgid "description_format"
+msgstr "format"
+
+msgctxt "WorkflowTransition"
+msgid "description_format"
+msgstr "format"
+
+msgctxt "State"
+msgid "description_format"
+msgstr "format"
+
+msgctxt "CWRType"
+msgid "description_format"
+msgstr "format"
+
+msgctxt "BaseTransition"
+msgid "description_format"
+msgstr "format"
+
+msgid "destination state"
+msgstr "état de destination"
+
 msgid "destination state for this transition"
 msgstr "états accessibles par cette transition"
 
@@ -1684,6 +1975,18 @@
 msgid "destination_state"
 msgstr "état de destination"
 
+msgctxt "Transition"
+msgid "destination_state"
+msgstr "état de destination"
+
+msgctxt "SubWorkflowExitPoint"
+msgid "destination_state"
+msgstr "état de destination"
+
+msgctxt "State"
+msgid "destination_state_object"
+msgstr "état final de"
+
 msgid "destination_state_object"
 msgstr "destination de"
 
@@ -1712,6 +2015,9 @@
 msgid "display the component or not"
 msgstr "afficher le composant ou non"
 
+msgid "display the pdf icon or not"
+msgstr "afficher l'icône pdf ou non"
+
 msgid ""
 "distinct label to distinguate between other permission entity of the same "
 "name"
@@ -1729,6 +2035,9 @@
 msgid "download icon"
 msgstr "icône de téléchargement"
 
+msgid "download page as pdf"
+msgstr "télécharger la page au format PDF"
+
 msgid "download schema as owl"
 msgstr "télécharger le schéma OWL"
 
@@ -1786,6 +2095,9 @@
 msgid "entity edited"
 msgstr "entité éditée"
 
+msgid "entity has no workflow set"
+msgstr "l'entité n'a pas de workflow"
+
 msgid "entity linked"
 msgstr "entité liée"
 
@@ -1798,11 +2110,8 @@
 msgstr ""
 "type d'entité à utiliser pour définir une configuration de sécurité avancée"
 
-msgid "entity types which may use this state"
-msgstr "type d'entités opuvant utiliser cet état"
-
-msgid "entity types which may use this transition"
-msgstr "entités qui peuvent utiliser cette transition"
+msgid "entity types which may use this workflow"
+msgstr "types d'entité pouvant utiliser ce workflow"
 
 msgid "error while embedding page"
 msgstr "erreur pendant l'inclusion de la page"
@@ -1824,15 +2133,33 @@
 msgid "eta_date"
 msgstr "date de fin"
 
+msgid "exit_point"
+msgstr "état de sortie"
+
+msgid "exit_point_object"
+msgstr "état de sortie de"
+
+#, python-format
+msgid "exiting from subworkflow %s"
+msgstr "sortie du sous-workflow %s"
+
 msgid "expected:"
 msgstr "attendu :"
 
 msgid "expression"
 msgstr "expression"
 
+msgctxt "RQLExpression"
+msgid "expression"
+msgstr "rql de l'expression"
+
 msgid "exprtype"
 msgstr "type de l'expression"
 
+msgctxt "RQLExpression"
+msgid "exprtype"
+msgstr "type"
+
 msgid "external page"
 msgstr "page externe"
 
@@ -1884,6 +2211,18 @@
 msgid "final"
 msgstr "final"
 
+msgctxt "CWEType"
+msgid "final"
+msgstr "final"
+
+msgctxt "CWRType"
+msgid "final"
+msgstr "final"
+
+msgid "firstname"
+msgstr "prénom"
+
+msgctxt "CWUser"
 msgid "firstname"
 msgstr "prénom"
 
@@ -1896,6 +2235,14 @@
 msgid "for_user"
 msgstr "pour l'utilisateur"
 
+msgctxt "CWProperty"
+msgid "for_user"
+msgstr "propriété de l'utilisateur"
+
+msgctxt "CWUser"
+msgid "for_user_object"
+msgstr "a pour préférence"
+
 msgid "for_user_object"
 msgstr "utilise les propriétés"
 
@@ -1912,6 +2259,18 @@
 msgid "from_entity"
 msgstr "de l'entité"
 
+msgctxt "CWAttribute"
+msgid "from_entity"
+msgstr "attribut de l'entité"
+
+msgctxt "CWRelation"
+msgid "from_entity"
+msgstr "relation de l'entité"
+
+msgctxt "CWEType"
+msgid "from_entity_object"
+msgstr "entité de"
+
 msgid "from_entity_object"
 msgstr "relation sujet"
 
@@ -1921,6 +2280,14 @@
 msgid "from_state"
 msgstr "de l'état"
 
+msgctxt "TrInfo"
+msgid "from_state"
+msgstr "état de départ"
+
+msgctxt "State"
+msgid "from_state_object"
+msgstr "état de départ de"
+
 msgid "from_state_object"
 msgstr "transitions depuis cet état"
 
@@ -1930,9 +2297,17 @@
 msgid "fulltext_container"
 msgstr "conteneur du texte indexé"
 
+msgctxt "CWRType"
+msgid "fulltext_container"
+msgstr "objet à indexer"
+
 msgid "fulltextindexed"
 msgstr "indexation du texte"
 
+msgctxt "CWAttribute"
+msgid "fulltextindexed"
+msgstr "texte indexé"
+
 msgid "generic plot"
 msgstr "tracé de courbes standard"
 
@@ -1951,6 +2326,10 @@
 msgid "granted to groups"
 msgstr "accordée aux groupes"
 
+#, python-format
+msgid "graphical representation of %s"
+msgstr "représentation graphique de %s"
+
 msgid "graphical representation of the instance'schema"
 msgstr "représentation graphique du schéma de l'instance"
 
@@ -2046,12 +2425,103 @@
 msgid "id of main template used to render pages"
 msgstr "id du template principal"
 
+msgid "identical to"
+msgstr "identique à"
+
 msgid "identical_to"
 msgstr "identique à"
 
 msgid "identity"
 msgstr "est identique à"
 
+msgctxt "CWRelation"
+msgid "identity_object"
+msgstr "est identique à"
+
+msgctxt "Bookmark"
+msgid "identity_object"
+msgstr "est identique à"
+
+msgctxt "CWAttribute"
+msgid "identity_object"
+msgstr "est indentique à"
+
+msgctxt "CWConstraintType"
+msgid "identity_object"
+msgstr "est identique à"
+
+msgctxt "State"
+msgid "identity_object"
+msgstr "est identique à"
+
+msgctxt "BaseTransition"
+msgid "identity_object"
+msgstr "est identique à"
+
+msgctxt "CWEType"
+msgid "identity_object"
+msgstr "est identique à"
+
+msgctxt "Workflow"
+msgid "identity_object"
+msgstr "est identique à"
+
+msgctxt "CWGroup"
+msgid "identity_object"
+msgstr "est identique à"
+
+msgctxt "TrInfo"
+msgid "identity_object"
+msgstr "est identique à"
+
+msgctxt "CWConstraint"
+msgid "identity_object"
+msgstr "est identique à"
+
+msgctxt "CWUser"
+msgid "identity_object"
+msgstr "est identique à"
+
+msgctxt "Transition"
+msgid "identity_object"
+msgstr "est identique à"
+
+msgctxt "CWRType"
+msgid "identity_object"
+msgstr "est identique à"
+
+msgctxt "SubWorkflowExitPoint"
+msgid "identity_object"
+msgstr "est identique à"
+
+msgctxt "ExternalUri"
+msgid "identity_object"
+msgstr "est identique à"
+
+msgctxt "CWCache"
+msgid "identity_object"
+msgstr "est identique à"
+
+msgctxt "WorkflowTransition"
+msgid "identity_object"
+msgstr "est identique à"
+
+msgctxt "RQLExpression"
+msgid "identity_object"
+msgstr "est identique à"
+
+msgctxt "CWPermission"
+msgid "identity_object"
+msgstr "est identique à"
+
+msgctxt "EmailAddress"
+msgid "identity_object"
+msgstr "est identique à"
+
+msgctxt "CWProperty"
+msgid "identity_object"
+msgstr "est identique à"
+
 msgid "identity_object"
 msgstr "est identique à"
 
@@ -2074,12 +2544,28 @@
 msgid "in_group"
 msgstr "dans le groupe"
 
+msgctxt "CWUser"
+msgid "in_group"
+msgstr "fait partie du groupe"
+
+msgctxt "CWGroup"
+msgid "in_group_object"
+msgstr "contient les utilisateurs"
+
 msgid "in_group_object"
 msgstr "membres"
 
 msgid "in_state"
 msgstr "état"
 
+msgctxt "CWUser"
+msgid "in_state"
+msgstr "dans l'état"
+
+msgctxt "State"
+msgid "in_state_object"
+msgstr "état des entités"
+
 msgid "in_state_object"
 msgstr "état de"
 
@@ -2099,6 +2585,10 @@
 msgid "indexed"
 msgstr "index"
 
+msgctxt "CWAttribute"
+msgid "indexed"
+msgstr "indexé"
+
 msgid "indicate the current state of an entity"
 msgstr "indique l'état courant d'une entité"
 
@@ -2115,15 +2605,27 @@
 msgid "initial estimation %s"
 msgstr "estimation initiale %s"
 
-msgid "initial state for entities of this type"
-msgstr "état initial pour les entités de ce type"
+msgid "initial state for this workflow"
+msgstr "état initial pour ce workflow"
 
 msgid "initial_state"
 msgstr "état initial"
 
+msgctxt "Workflow"
+msgid "initial_state"
+msgstr "état initial"
+
+msgctxt "State"
 msgid "initial_state_object"
 msgstr "état initial de"
 
+msgid "initial_state_object"
+msgstr "état initial de"
+
+msgid "inlined"
+msgstr "mise en ligne"
+
+msgctxt "CWRType"
 msgid "inlined"
 msgstr "mise en ligne"
 
@@ -2136,6 +2638,10 @@
 msgid "internationalizable"
 msgstr "internationalisable"
 
+msgctxt "CWAttribute"
+msgid "internationalizable"
+msgstr "internationalisable"
+
 #, python-format
 msgid "invalid action %r"
 msgstr "action %r invalide"
@@ -2176,7 +2682,15 @@
 msgid "is_instance_of"
 msgstr "est une instance de"
 
+msgctxt "CWEType"
 msgid "is_instance_of_object"
+msgstr "type de l'entité"
+
+msgid "is_instance_of_object"
+msgstr "type de"
+
+msgctxt "CWEType"
+msgid "is_object"
 msgstr "type de"
 
 msgid "is_object"
@@ -2194,6 +2708,10 @@
 msgid "label"
 msgstr "libellé"
 
+msgctxt "CWPermission"
+msgid "label"
+msgstr "libellé"
+
 msgid "language of the user interface"
 msgstr "langue pour l'interface utilisateur"
 
@@ -2203,6 +2721,10 @@
 msgid "last_login_time"
 msgstr "dernière date de connexion"
 
+msgctxt "CWUser"
+msgid "last_login_time"
+msgstr "dernière date de connexion"
+
 msgid "latest modification time of an entity"
 msgstr "date de dernière modification d'une entité"
 
@@ -2236,14 +2758,17 @@
 msgid "link a relation definition to its subject entity type"
 msgstr "lie une définition de relation à son type d'entité sujet"
 
-msgid "link a state to one or more entity type"
-msgstr "lier un état à une ou plusieurs entités"
+msgid "link a state to one or more workflow"
+msgstr "lie un état à un ou plusieurs workflow"
 
 msgid "link a transition information to its object"
 msgstr "lié une enregistrement de transition vers l'objet associé"
 
-msgid "link a transition to one or more entity type"
-msgstr "lie une transition à un ou plusieurs types d'entités"
+msgid "link a transition to one or more workflow"
+msgstr "lie une transition à un ou plusieurs workflow"
+
+msgid "link a workflow to one or more entity type"
+msgstr "lie un workflow à un ou plusieurs types d'entité"
 
 msgid "link to each item in"
 msgstr "lier vers chaque élément dans"
@@ -2260,6 +2785,10 @@
 msgid "login"
 msgstr "identifiant"
 
+msgctxt "CWUser"
+msgid "login"
+msgstr "identifiant"
+
 msgid "login or email"
 msgstr "identifiant ou email"
 
@@ -2279,6 +2808,10 @@
 msgid "mainvars"
 msgstr "variables principales"
 
+msgctxt "RQLExpression"
+msgid "mainvars"
+msgstr "variables principales"
+
 msgid "manage"
 msgstr "gestion du site"
 
@@ -2294,6 +2827,9 @@
 msgid "managers"
 msgstr "administrateurs"
 
+msgid "mandatory relation"
+msgstr "relation obligatoire"
+
 msgid "march"
 msgstr "mars"
 
@@ -2340,6 +2876,50 @@
 msgid "name"
 msgstr "nom"
 
+msgctxt "CWEType"
+msgid "name"
+msgstr "nom"
+
+msgctxt "Transition"
+msgid "name"
+msgstr "nom"
+
+msgctxt "Workflow"
+msgid "name"
+msgstr "nom"
+
+msgctxt "CWGroup"
+msgid "name"
+msgstr "nom"
+
+msgctxt "CWConstraintType"
+msgid "name"
+msgstr "nom"
+
+msgctxt "WorkflowTransition"
+msgid "name"
+msgstr "nom"
+
+msgctxt "State"
+msgid "name"
+msgstr "nom"
+
+msgctxt "CWPermission"
+msgid "name"
+msgstr "nom"
+
+msgctxt "CWRType"
+msgid "name"
+msgstr "nom"
+
+msgctxt "BaseTransition"
+msgid "name"
+msgstr "nom"
+
+msgctxt "CWCache"
+msgid "name"
+msgstr "nom"
+
 msgid "name of the cache"
 msgstr "nom du cache applicatif"
 
@@ -2447,6 +3027,14 @@
 msgid "ordernum"
 msgstr "ordre"
 
+msgctxt "CWAttribute"
+msgid "ordernum"
+msgstr "numéro d'ordre"
+
+msgctxt "CWRelation"
+msgid "ordernum"
+msgstr "numéro d'ordre"
+
 msgid "owl"
 msgstr "owl"
 
@@ -2456,6 +3044,10 @@
 msgid "owned_by"
 msgstr "appartient à"
 
+msgctxt "CWUser"
+msgid "owned_by_object"
+msgstr "propriétaire de"
+
 msgid "owned_by_object"
 msgstr "possède"
 
@@ -2482,6 +3074,10 @@
 msgid "path"
 msgstr "chemin"
 
+msgctxt "Bookmark"
+msgid "path"
+msgstr "chemin"
+
 msgid "permission"
 msgstr "permission"
 
@@ -2503,6 +3099,10 @@
 msgid "pkey"
 msgstr "clé"
 
+msgctxt "CWProperty"
+msgid "pkey"
+msgstr "code de la propriété"
+
 msgid "please correct errors below"
 msgstr "veuillez corriger les erreurs ci-dessous"
 
@@ -2513,7 +3113,21 @@
 msgstr "vues possibles"
 
 msgid "powered by CubicWeb"
-msgstr ""
+msgstr "utilise la technologie CubicWeb"
+
+msgid "prefered_form"
+msgstr "forme préférée"
+
+msgctxt "EmailAddress"
+msgid "prefered_form"
+msgstr "forme préférée"
+
+msgctxt "EmailAddress"
+msgid "prefered_form_object"
+msgstr "forme préférée de"
+
+msgid "prefered_form_object"
+msgstr "forme préférée à"
 
 msgid "preferences"
 msgstr "préférences"
@@ -2527,6 +3141,14 @@
 msgid "primary_email"
 msgstr "adresse email principale"
 
+msgctxt "CWUser"
+msgid "primary_email"
+msgstr "email principal"
+
+msgctxt "EmailAddress"
+msgid "primary_email_object"
+msgstr "adresse principale de"
+
 msgid "primary_email_object"
 msgstr "adresse email principale (object)"
 
@@ -2548,12 +3170,34 @@
 msgid "read_permission"
 msgstr "permission de lire"
 
+msgctxt "CWEType"
+msgid "read_permission"
+msgstr "permission d'ajouter"
+
+msgctxt "CWRType"
+msgid "read_permission"
+msgstr "permission d'ajouter"
+
+msgctxt "CWGroup"
+msgid "read_permission_object"
+msgstr "peut lire"
+
+msgctxt "RQLExpression"
+msgid "read_permission_object"
+msgstr "peut lire"
+
 msgid "read_permission_object"
 msgstr "a la permission de lire"
 
 msgid "registry"
 msgstr "registre"
 
+msgid "related entity has no state"
+msgstr "l'entité lié n'a pas d'état"
+
+msgid "related entity has no workflow set"
+msgstr "l'entité lié n'a pas de workflow"
+
 #, python-format
 msgid "relation %(relname)s of %(ent)s"
 msgstr "relation %(relname)s de %(ent)s"
@@ -2561,6 +3205,18 @@
 msgid "relation_type"
 msgstr "type de relation"
 
+msgctxt "CWAttribute"
+msgid "relation_type"
+msgstr "type de relation"
+
+msgctxt "CWRelation"
+msgid "relation_type"
+msgstr "type de relation"
+
+msgctxt "CWRType"
+msgid "relation_type_object"
+msgstr "définition"
+
 msgid "relation_type_object"
 msgstr "définition"
 
@@ -2573,63 +3229,45 @@
 msgid "relative url of the bookmarked page"
 msgstr "url relative de la page"
 
-msgid "remove this Bookmark"
-msgstr "supprimer ce signet"
-
-msgid "remove this CWAttribute"
-msgstr "supprimer cet attribut"
-
-msgid "remove this CWCache"
-msgstr "supprimer ce cache applicatif"
-
-msgid "remove this CWConstraint"
-msgstr "supprimer cette contrainte"
-
-msgid "remove this CWConstraintType"
-msgstr "supprimer ce type de contrainte"
-
+msgctxt "inlined:CWRelation:from_entity:subject"
+msgid "remove this CWEType"
+msgstr "supprimer ce type d'entité"
+
+msgctxt "inlined:CWRelation:to_entity:subject"
 msgid "remove this CWEType"
 msgstr "supprimer ce type d'entité"
 
-msgid "remove this CWGroup"
-msgstr "supprimer ce groupe"
-
-msgid "remove this CWPermission"
-msgstr "supprimer cette permission"
-
-msgid "remove this CWProperty"
-msgstr "supprimer cette propriété"
-
+msgctxt "inlined:CWRelation:relation_type:subject"
 msgid "remove this CWRType"
-msgstr "supprimer cette définition de relation"
-
-msgid "remove this CWRelation"
-msgstr "supprimer cette relation"
-
-msgid "remove this CWUser"
-msgstr "supprimer cet utilisateur"
-
+msgstr "supprimer ce type de relation"
+
+msgctxt "inlined:CWUser:use_email:subject"
 msgid "remove this EmailAddress"
-msgstr "supprimer cette adresse email"
-
-msgid "remove this ExternalUri"
-msgstr "supprimer cette Uri externe"
-
-msgid "remove this RQLExpression"
-msgstr "supprimer cette expression rql"
-
-msgid "remove this State"
-msgstr "supprimer cet état"
-
-msgid "remove this TrInfo"
-msgstr "retirer cette information de transition"
-
-msgid "remove this Transition"
-msgstr "supprimer cette transition"
+msgstr "supprimer cette adresse électronique"
 
 msgid "require_group"
 msgstr "nécessite le groupe"
 
+msgctxt "BaseTransition"
+msgid "require_group"
+msgstr "restreinte au groupe"
+
+msgctxt "Transition"
+msgid "require_group"
+msgstr "restreinte au groupe"
+
+msgctxt "CWPermission"
+msgid "require_group"
+msgstr "restreinte au groupe"
+
+msgctxt "WorkflowTransition"
+msgid "require_group"
+msgstr "restreinte au groupe"
+
+msgctxt "CWGroup"
+msgid "require_group_object"
+msgstr "dé"
+
 msgid "require_group_object"
 msgstr "à les droits"
 
@@ -2763,6 +3401,9 @@
 msgid "semantic description of this transition"
 msgstr "description sémantique de cette transition"
 
+msgid "semantic description of this workflow"
+msgstr "description sémantique de ce workflow"
+
 msgid "send email"
 msgstr "envoyer un courriel"
 
@@ -2818,9 +3459,20 @@
 msgid "sparql xml"
 msgstr "XML Sparql"
 
+msgid "special transition allowing to go through a sub-workflow"
+msgstr "transition spécial permettant d'aller dans un sous-workfow"
+
 msgid "specializes"
 msgstr "dérive de"
 
+msgctxt "CWEType"
+msgid "specializes"
+msgstr "spécialise"
+
+msgctxt "CWEType"
+msgid "specializes_object"
+msgstr "parent de"
+
 msgid "specializes_object"
 msgstr "parent de"
 
@@ -2830,9 +3482,30 @@
 msgid "state"
 msgstr "état"
 
+msgid "state doesn't belong to entity's current workflow"
+msgstr "l'état n'appartient pas au workflow courant de l'entité"
+
+msgid "state doesn't belong to entity's workflow"
+msgstr "l'état n'appartient pas au workflow de l'entité"
+
+msgid ""
+"state doesn't belong to entity's workflow. You may want to set a custom "
+"workflow for this entity first."
+msgstr ""
+"l'état n'appartient pas au workflow courant de l'entité. Vous désirez peut-"
+"être spécifier que cette entité doit utiliser ce workflow."
+
 msgid "state_of"
 msgstr "état de"
 
+msgctxt "State"
+msgid "state_of"
+msgstr "état de"
+
+msgctxt "Workflow"
+msgid "state_of_object"
+msgstr "contient les états"
+
 msgid "state_of_object"
 msgstr "a pour état"
 
@@ -2855,12 +3528,65 @@
 msgid "subject_plural:"
 msgstr "sujets :"
 
+msgid "subworkflow"
+msgstr "sous-workflow"
+
+msgctxt "WorkflowTransition"
+msgid "subworkflow"
+msgstr "sous-workflow"
+
+msgid "subworkflow state"
+msgstr "état de sous-workflow"
+
+msgid "subworkflow_exit"
+msgstr "sortie de sous-workflow"
+
+msgctxt "WorkflowTransition"
+msgid "subworkflow_exit"
+msgstr "sortie du sous-workflow"
+
+msgctxt "SubWorkflowExitPoint"
+msgid "subworkflow_exit_object"
+msgstr "états de sortie"
+
+msgid "subworkflow_exit_object"
+msgstr "états de sortie"
+
+msgctxt "Workflow"
+msgid "subworkflow_object"
+msgstr ""
+
+msgid "subworkflow_object"
+msgstr "utilisé par la transition"
+
+msgid "subworkflow_state"
+msgstr "état du sous-workflow"
+
+msgctxt "SubWorkflowExitPoint"
+msgid "subworkflow_state"
+msgstr "état"
+
+msgctxt "State"
+msgid "subworkflow_state_object"
+msgstr ""
+
+msgid "subworkflow_state_object"
+msgstr "état de sortie de"
+
 msgid "sunday"
 msgstr "dimanche"
 
 msgid "surname"
 msgstr "nom"
 
+msgctxt "CWUser"
+msgid "surname"
+msgstr "nom de famille"
+
+msgid "symetric"
+msgstr "symétrique"
+
+msgctxt "CWRType"
 msgid "symetric"
 msgstr "symétrique"
 
@@ -2920,6 +3646,10 @@
 msgid "timestamp"
 msgstr "date"
 
+msgctxt "CWCache"
+msgid "timestamp"
+msgstr "valide depuis"
+
 msgid "timestamp of the latest source synchronization."
 msgstr "date de la dernière synchronisation avec la source."
 
@@ -2929,6 +3659,10 @@
 msgid "title"
 msgstr "titre"
 
+msgctxt "Bookmark"
+msgid "title"
+msgstr "libellé"
+
 msgid "to"
 msgstr "à"
 
@@ -2942,6 +3676,18 @@
 msgid "to_entity"
 msgstr "vers l'entité"
 
+msgctxt "CWAttribute"
+msgid "to_entity"
+msgstr "pour l'entité"
+
+msgctxt "CWRelation"
+msgid "to_entity"
+msgstr "pour l'entité"
+
+msgctxt "CWEType"
+msgid "to_entity_object"
+msgstr "relation objet"
+
 msgid "to_entity_object"
 msgstr "relation objet"
 
@@ -2951,8 +3697,16 @@
 msgid "to_state"
 msgstr "vers l'état"
 
+msgctxt "TrInfo"
+msgid "to_state"
+msgstr "état de destination"
+
+msgctxt "State"
 msgid "to_state_object"
-msgstr "transitions vers cette état"
+msgstr "transition vers cet état"
+
+msgid "to_state_object"
+msgstr "transitions vers cet état"
 
 msgid "todo_by"
 msgstr "à faire par"
@@ -2960,13 +3714,34 @@
 msgid "toggle check boxes"
 msgstr "inverser les cases à cocher"
 
-#, python-format
-msgid "transition from %s to %s does not exist or is not allowed"
-msgstr "la transition de %s à %s n'existe pas ou n'est pas permise"
+msgid "transition doesn't belong to entity's workflow"
+msgstr "la transition n'appartient pas au workflow de l'entité"
+
+msgid "transition isn't allowed"
+msgstr "la transition n'est pas autorisée"
+
+msgid "transition may not be fired"
+msgstr "la transition ne peut-être déclenchée"
 
 msgid "transition_of"
 msgstr "transition de"
 
+msgctxt "BaseTransition"
+msgid "transition_of"
+msgstr "transition de"
+
+msgctxt "Transition"
+msgid "transition_of"
+msgstr "transition de"
+
+msgctxt "WorkflowTransition"
+msgid "transition_of"
+msgstr "transition de"
+
+msgctxt "Workflow"
+msgid "transition_of_object"
+msgstr "a pour transition"
+
 msgid "transition_of_object"
 msgstr "a pour transition"
 
@@ -3039,6 +3814,10 @@
 msgid "upassword"
 msgstr "mot de passe"
 
+msgctxt "CWUser"
+msgid "upassword"
+msgstr "mot de passe"
+
 msgid "update"
 msgstr "modification"
 
@@ -3048,6 +3827,18 @@
 msgid "update_permission"
 msgstr "permission de modification"
 
+msgctxt "CWEType"
+msgid "update_permission"
+msgstr "permission de modifier"
+
+msgctxt "CWGroup"
+msgid "update_permission_object"
+msgstr "peut modifier"
+
+msgctxt "RQLExpression"
+msgid "update_permission_object"
+msgstr "peut modifier"
+
 msgid "update_permission_object"
 msgstr "à la permission de modifier"
 
@@ -3058,6 +3849,10 @@
 msgid "uri"
 msgstr "uri"
 
+msgctxt "ExternalUri"
+msgid "uri"
+msgstr "uri"
+
 msgid "use template languages"
 msgstr "utiliser les langages de template"
 
@@ -3071,6 +3866,14 @@
 msgid "use_email"
 msgstr "adresse électronique"
 
+msgctxt "CWUser"
+msgid "use_email"
+msgstr "utilise l'adresse électronique"
+
+msgctxt "EmailAddress"
+msgid "use_email_object"
+msgstr "utilisée par"
+
 msgid "use_email_object"
 msgstr "adresse utilisée par"
 
@@ -3127,6 +3930,14 @@
 msgid "value"
 msgstr "valeur"
 
+msgctxt "CWConstraint"
+msgid "value"
+msgstr "contrainte"
+
+msgctxt "CWProperty"
+msgid "value"
+msgstr "valeur"
+
 msgid "value associated to this key is not editable manually"
 msgstr "la valeur associée à cette clé n'est pas éditable manuellement"
 
@@ -3174,21 +3985,55 @@
 msgid "wf_info_for"
 msgstr "historique de"
 
+msgctxt "TrInfo"
+msgid "wf_info_for"
+msgstr "information de transition"
+
+msgctxt "CWUser"
+msgid "wf_info_for_object"
+msgstr "historique des transitions"
+
 msgid "wf_info_for_object"
 msgstr "historique des transitions"
 
 msgid ""
 "when multiple addresses are equivalent (such as python-projects@logilab.org "
-"and python-projects@lists.logilab.org), set this to true on one of them "
-"which is the preferred form."
+"and python-projects@lists.logilab.org), set this to indicate which is the "
+"preferred form."
 msgstr ""
-"quand plusieurs adresses sont équivalentes (comme python-projects@logilab."
-"org et python-projects@lists.logilab.org), mettez cette propriété à vrai sur "
-"l'une d'entre-elle qui sera la forme canonique"
+
+msgid "workflow"
+msgstr "workflow"
 
 #, python-format
-msgid "workflow for %s"
-msgstr "workflow pour %s"
+msgid "workflow changed to \"%s\""
+msgstr "workflow changé à \"%s\""
+
+msgid "workflow has no initial state"
+msgstr "le workflow n'a pas d'état initial"
+
+msgid "workflow history item"
+msgstr "entrée de l'historique de workflow"
+
+msgid "workflow to which this state belongs"
+msgstr "workflow auquel cet état appartient"
+
+msgid "workflow to which this transition belongs"
+msgstr "workflow auquel cette transition appartient"
+
+msgid "workflow_of"
+msgstr "workflow de"
+
+msgctxt "Workflow"
+msgid "workflow_of"
+msgstr "workflow de"
+
+msgctxt "CWEType"
+msgid "workflow_of_object"
+msgstr "a pour workflow"
+
+msgid "workflow_of_object"
+msgstr "a pour workflow"
 
 msgid "xbel"
 msgstr "xbel"
@@ -3208,10 +4053,180 @@
 msgid "you should probably delete that property"
 msgstr "vous devriez probablement supprimer cette propriété"
 
-#~ msgid ""
-#~ "You have no access to this view or it's not applyable to current data"
-#~ msgstr ""
-#~ "Vous n'avez pas accès à cette vue ou elle ne s'applique pas aux données"
-
-#~ msgid "download image"
-#~ msgstr "image de téléchargement"
+#~ msgid "This %s"
+#~ msgstr "Ce %s"
+
+#~ msgid "add a BaseTransition"
+#~ msgstr "XXX"
+
+#~ msgid "add a Bookmark"
+#~ msgstr "ajouter un signet"
+
+#~ msgid "add a CWAttribute"
+#~ msgstr "ajouter un type de relation"
+
+#~ msgid "add a CWCache"
+#~ msgstr "ajouter un cache applicatif"
+
+#~ msgid "add a CWConstraint"
+#~ msgstr "ajouter une contrainte"
+
+#~ msgid "add a CWConstraintType"
+#~ msgstr "ajouter un type de contrainte"
+
+#~ msgid "add a CWEType"
+#~ msgstr "ajouter un type d'entité"
+
+#~ msgid "add a CWGroup"
+#~ msgstr "ajouter un groupe d'utilisateurs"
+
+#~ msgid "add a CWPermission"
+#~ msgstr "ajouter une permission"
+
+#~ msgid "add a CWProperty"
+#~ msgstr "ajouter une propriété"
+
+#~ msgid "add a CWRType"
+#~ msgstr "ajouter un type de relation"
+
+#~ msgid "add a CWRelation"
+#~ msgstr "ajouter une relation"
+
+#~ msgid "add a CWUser"
+#~ msgstr "ajouter un utilisateur"
+
+#~ msgid "add a EmailAddress"
+#~ msgstr "ajouter une adresse email"
+
+#~ msgid "add a ExternalUri"
+#~ msgstr "ajouter une Uri externe"
+
+#~ msgid "add a RQLExpression"
+#~ msgstr "ajouter une expression rql"
+
+#~ msgid "add a State"
+#~ msgstr "ajouter un état"
+
+#~ msgid "add a SubWorkflowExitPoint"
+#~ msgstr "ajouter une sortie de sous-workflow"
+
+#~ msgid "add a TrInfo"
+#~ msgstr "ajouter une information de transition"
+
+#~ msgid "add a Transition"
+#~ msgstr "ajouter une transition"
+
+#~ msgid "add a Workflow"
+#~ msgstr "ajouter un workflow"
+
+#~ msgid "add a WorkflowTransition"
+#~ msgstr "ajouter une transition workflow"
+
+#~ msgctxt "CWRelation"
+#~ msgid "created_by"
+#~ msgstr "créée par"
+
+#~ msgctxt "Bookmark"
+#~ msgid "created_by"
+#~ msgstr "créé par"
+
+#~ msgctxt "CWAttribute"
+#~ msgid "created_by"
+#~ msgstr "créé par"
+
+#~ msgctxt "CWConstraintType"
+#~ msgid "created_by"
+#~ msgstr "créé par"
+
+#~ msgctxt "RQLExpression"
+#~ msgid "created_by"
+#~ msgstr "créée par"
+
+#~ msgctxt "BaseTransition"
+#~ msgid "created_by"
+#~ msgstr "créée par"
+
+#~ msgctxt "CWEType"
+#~ msgid "created_by"
+#~ msgstr "créé par"
+
+#~ msgctxt "Workflow"
+#~ msgid "created_by"
+#~ msgstr "créé par"
+
+#~ msgctxt "CWGroup"
+#~ msgid "created_by"
+#~ msgstr "créé par"
+
+#~ msgctxt "TrInfo"
+#~ msgid "created_by"
+#~ msgstr "créée par"
+
+#~ msgid "default workflow for this entity type"
+#~ msgstr "workflow par défaut pour un type d'entité"
+
+#~ msgid "remove this BaseTransition"
+#~ msgstr "XXX"
+
+#~ msgid "remove this Bookmark"
+#~ msgstr "supprimer ce signet"
+
+#~ msgid "remove this CWAttribute"
+#~ msgstr "supprimer cet attribut"
+
+#~ msgid "remove this CWCache"
+#~ msgstr "supprimer ce cache applicatif"
+
+#~ msgid "remove this CWConstraint"
+#~ msgstr "supprimer cette contrainte"
+
+#~ msgid "remove this CWConstraintType"
+#~ msgstr "supprimer ce type de contrainte"
+
+#~ msgid "remove this CWEType"
+#~ msgstr "supprimer ce type d'entité"
+
+#~ msgid "remove this CWGroup"
+#~ msgstr "supprimer ce groupe"
+
+#~ msgid "remove this CWPermission"
+#~ msgstr "supprimer cette permission"
+
+#~ msgid "remove this CWProperty"
+#~ msgstr "supprimer cette propriété"
+
+#~ msgid "remove this CWRType"
+#~ msgstr "supprimer cette définition de relation"
+
+#~ msgid "remove this CWRelation"
+#~ msgstr "supprimer cette relation"
+
+#~ msgid "remove this CWUser"
+#~ msgstr "supprimer cet utilisateur"
+
+#~ msgid "remove this EmailAddress"
+#~ msgstr "supprimer cette adresse email"
+
+#~ msgid "remove this ExternalUri"
+#~ msgstr "supprimer cette Uri externe"
+
+#~ msgid "remove this RQLExpression"
+#~ msgstr "supprimer cette expression rql"
+
+#~ msgid "remove this State"
+#~ msgstr "supprimer cet état"
+
+#~ msgid "remove this SubWorkflowExitPoint"
+#~ msgstr "supprimer ce point de sortie"
+
+#~ msgid "remove this TrInfo"
+#~ msgstr "retirer cette information de transition"
+
+#~ msgid "remove this Transition"
+#~ msgstr "supprimer cette transition"
+
+#~ msgid "remove this Workflow"
+#~ msgstr "supprimer ce workflow"
+
+#~ msgid "remove this WorkflowTransition"
+#~ msgstr "supprimer cette transition workflow"
--- a/misc/migration/3.5.0_Any.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/misc/migration/3.5.0_Any.py	Thu Sep 17 15:16:53 2009 +0200
@@ -5,3 +5,6 @@
 
 drop_attribute('EmailAddress', 'canonical')
 drop_relation_definition('EmailAddress', 'identical_to', 'EmailAddress')
+
+if 'see_also' in schema:
+    sync_schema_props_perms('see_also', syncprops=False, syncrdefs=False)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rqlrewrite.py	Thu Sep 17 15:16:53 2009 +0200
@@ -0,0 +1,480 @@
+"""RQL rewriting utilities : insert rql expression snippets into rql syntax
+tree.
+
+This is used for instance for read security checking in the repository.
+
+:organization: Logilab
+:copyright: 2007-2009 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.
+:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
+:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
+"""
+__docformat__ = "restructuredtext en"
+
+from rql import nodes as n, stmts, TypeResolverException
+
+from logilab.common.compat import any
+
+from cubicweb import Unauthorized, server, typed_eid
+from cubicweb.server.ssplanner import add_types_restriction
+
+
+def remove_solutions(origsolutions, solutions, defined):
+    """when a rqlst has been generated from another by introducing security
+    assertions, this method returns solutions which are contained in orig
+    solutions
+    """
+    newsolutions = []
+    for origsol in origsolutions:
+        for newsol in solutions[:]:
+            for var, etype in origsol.items():
+                try:
+                    if newsol[var] != etype:
+                        try:
+                            defined[var].stinfo['possibletypes'].remove(newsol[var])
+                        except KeyError:
+                            pass
+                        break
+                except KeyError:
+                    # variable has been rewritten
+                    continue
+            else:
+                newsolutions.append(newsol)
+                solutions.remove(newsol)
+    return newsolutions
+
+
+class Unsupported(Exception): pass
+
+
+class RQLRewriter(object):
+    """insert some rql snippets into another rql syntax tree
+
+    this class *isn't thread safe*
+    """
+
+    def __init__(self, session):
+        self.session = session
+        vreg = session.vreg
+        self.schema = vreg.schema
+        self.annotate = vreg.rqlhelper.annotate
+        self._compute_solutions = vreg.solutions
+
+    def compute_solutions(self):
+        self.annotate(self.select)
+        try:
+            self._compute_solutions(self.session, self.select, self.kwargs)
+        except TypeResolverException:
+            raise Unsupported(str(self.select))
+        if len(self.select.solutions) < len(self.solutions):
+            raise Unsupported()
+
+    def rewrite(self, select, snippets, solutions, kwargs):
+        """
+        snippets: (varmap, list of rql expression)
+                  with varmap a *tuple* (select var, snippet var)
+        """
+        if server.DEBUG:
+            print '---- rewrite', select, snippets, solutions
+        self.select = self.insert_scope = select
+        self.solutions = solutions
+        self.kwargs = kwargs
+        self.u_varname = None
+        self.removing_ambiguity = False
+        self.exists_snippet = {}
+        self.pending_keys = []
+        # we have to annotate the rqlst before inserting snippets, even though
+        # we'll have to redo it latter
+        self.annotate(select)
+        self.insert_snippets(snippets)
+        if not self.exists_snippet and self.u_varname:
+            # U has been inserted than cancelled, cleanup
+            select.undefine_variable(select.defined_vars[self.u_varname])
+        # clean solutions according to initial solutions
+        newsolutions = remove_solutions(solutions, select.solutions,
+                                        select.defined_vars)
+        assert len(newsolutions) >= len(solutions), (
+            'rewritten rql %s has lost some solutions, there is probably '
+            'something wrong in your schema permission (for instance using a '
+            'RQLExpression which insert a relation which doesn\'t exists in '
+            'the schema)\nOrig solutions: %s\nnew solutions: %s' % (
+            select, solutions, newsolutions))
+        if len(newsolutions) > len(solutions):
+            newsolutions = self.remove_ambiguities(snippets, newsolutions)
+        select.solutions = newsolutions
+        add_types_restriction(self.schema, select)
+        if server.DEBUG:
+            print '---- rewriten', select
+
+    def insert_snippets(self, snippets, varexistsmap=None):
+        self.rewritten = {}
+        for varmap, rqlexprs in snippets:
+            if varexistsmap is not None and not varmap in varexistsmap:
+                continue
+            self.varmap = varmap
+            selectvar, snippetvar = varmap
+            assert snippetvar in 'SOX'
+            self.revvarmap = {snippetvar: selectvar}
+            self.varinfo = vi = {}
+            try:
+                vi['const'] = typed_eid(selectvar) # XXX gae
+                vi['rhs_rels'] = vi['lhs_rels'] = {}
+            except ValueError:
+                vi['stinfo'] = sti = self.select.defined_vars[selectvar].stinfo
+                if varexistsmap is None:
+                    vi['rhs_rels'] = dict( (r.r_type, r) for r in sti['rhsrelations'])
+                    vi['lhs_rels'] = dict( (r.r_type, r) for r in sti['relations']
+                                           if not r in sti['rhsrelations'])
+                else:
+                    vi['rhs_rels'] = vi['lhs_rels'] = {}
+            parent = None
+            inserted = False
+            for rqlexpr in rqlexprs:
+                self.current_expr = rqlexpr
+                if varexistsmap is None:
+                    try:
+                        new = self.insert_snippet(varmap, rqlexpr.snippet_rqlst, parent)
+                    except Unsupported:
+                        import traceback
+                        traceback.print_exc()
+                        continue
+                    inserted = True
+                    if new is not None:
+                        self.exists_snippet[rqlexpr] = new
+                    parent = parent or new
+                else:
+                    # called to reintroduce snippet due to ambiguity creation,
+                    # so skip snippets which are not introducing this ambiguity
+                    exists = varexistsmap[varmap]
+                    if self.exists_snippet[rqlexpr] is exists:
+                        self.insert_snippet(varmap, rqlexpr.snippet_rqlst, exists)
+            if varexistsmap is None and not inserted:
+                # no rql expression found matching rql solutions. User has no access right
+                raise Unauthorized()
+
+    def insert_snippet(self, varmap, snippetrqlst, parent=None):
+        new = snippetrqlst.where.accept(self)
+        if new is not None:
+            if self.varinfo.get('stinfo', {}).get('optrelations'):
+                assert parent is None
+                self.insert_scope = self.snippet_subquery(varmap, new)
+                self.insert_pending()
+                self.insert_scope = self.select
+                return
+            new = n.Exists(new)
+            if parent is None:
+                self.insert_scope.add_restriction(new)
+            else:
+                grandpa = parent.parent
+                or_ = n.Or(parent, new)
+                grandpa.replace(parent, or_)
+            if not self.removing_ambiguity:
+                try:
+                    self.compute_solutions()
+                except Unsupported:
+                    # some solutions have been lost, can't apply this rql expr
+                    if parent is None:
+                        self.select.remove_node(new, undefine=True)
+                    else:
+                        parent.parent.replace(or_, or_.children[0])
+                        self._cleanup_inserted(new)
+                    raise
+                else:
+                    self.insert_scope = new
+                    self.insert_pending()
+                    self.insert_scope = self.select
+            return new
+        self.insert_pending()
+
+    def insert_pending(self):
+        """pending_keys hold variable referenced by U has_<action>_permission X
+        relation.
+
+        Once the snippet introducing this has been inserted and solutions
+        recomputed, we have to insert snippet defined for <action> of entity
+        types taken by X
+        """
+        while self.pending_keys:
+            key, action = self.pending_keys.pop()
+            try:
+                varname = self.rewritten[key]
+            except KeyError:
+                try:
+                    varname = self.revvarmap[key[-1]]
+                except KeyError:
+                    # variable isn't used anywhere else, we can't insert security
+                    raise Unauthorized()
+            ptypes = self.select.defined_vars[varname].stinfo['possibletypes']
+            if len(ptypes) > 1:
+                # XXX dunno how to handle this
+                self.session.error(
+                    'cant check security of %s, ambigous type for %s in %s',
+                    self.select, varname, key[0]) # key[0] == the rql expression
+                raise Unauthorized()
+            etype = iter(ptypes).next()
+            eschema = self.schema.eschema(etype)
+            if not eschema.has_perm(self.session, action):
+                rqlexprs = eschema.get_rqlexprs(action)
+                if not rqlexprs:
+                    raise Unauthorised()
+                self.insert_snippets([((varname, 'X'), rqlexprs)])
+
+    def snippet_subquery(self, varmap, transformedsnippet):
+        """introduce the given snippet in a subquery"""
+        subselect = stmts.Select()
+        selectvar, snippetvar = varmap
+        subselect.append_selected(n.VariableRef(
+            subselect.get_variable(selectvar)))
+        aliases = [selectvar]
+        subselect.add_restriction(transformedsnippet.copy(subselect))
+        stinfo = self.varinfo['stinfo']
+        for rel in stinfo['relations']:
+            rschema = self.schema.rschema(rel.r_type)
+            if rschema.is_final() or (rschema.inlined and
+                                      not rel in stinfo['rhsrelations']):
+                self.select.remove_node(rel)
+                rel.children[0].name = selectvar
+                subselect.add_restriction(rel.copy(subselect))
+                for vref in rel.children[1].iget_nodes(n.VariableRef):
+                    subselect.append_selected(vref.copy(subselect))
+                    aliases.append(vref.name)
+        if self.u_varname:
+            # generate an identifier for the substitution
+            argname = subselect.allocate_varname()
+            while argname in self.kwargs:
+                argname = subselect.allocate_varname()
+            subselect.add_constant_restriction(subselect.get_variable(self.u_varname),
+                                               'eid', unicode(argname), 'Substitute')
+            self.kwargs[argname] = self.session.user.eid
+        add_types_restriction(self.schema, subselect, subselect,
+                              solutions=self.solutions)
+        myunion = stmts.Union()
+        myunion.append(subselect)
+        aliases = [n.VariableRef(self.select.get_variable(name, i))
+                   for i, name in enumerate(aliases)]
+        self.select.add_subquery(n.SubQuery(aliases, myunion), check=False)
+        self._cleanup_inserted(transformedsnippet)
+        try:
+            self.compute_solutions()
+        except Unsupported:
+            # some solutions have been lost, can't apply this rql expr
+            self.select.remove_subquery(new, undefine=True)
+            raise
+        return subselect
+
+    def remove_ambiguities(self, snippets, newsolutions):
+        # the snippet has introduced some ambiguities, we have to resolve them
+        # "manually"
+        variantes = self.build_variantes(newsolutions)
+        # insert "is" where necessary
+        varexistsmap = {}
+        self.removing_ambiguity = True
+        for (erqlexpr, varmap, oldvarname), etype in variantes[0].iteritems():
+            varname = self.rewritten[(erqlexpr, varmap, oldvarname)]
+            var = self.select.defined_vars[varname]
+            exists = var.references()[0].scope
+            exists.add_constant_restriction(var, 'is', etype, 'etype')
+            varexistsmap[varmap] = exists
+        # insert ORED exists where necessary
+        for variante in variantes[1:]:
+            self.insert_snippets(snippets, varexistsmap)
+            for key, etype in variante.iteritems():
+                varname = self.rewritten[key]
+                try:
+                    var = self.select.defined_vars[varname]
+                except KeyError:
+                    # not a newly inserted variable
+                    continue
+                exists = var.references()[0].scope
+                exists.add_constant_restriction(var, 'is', etype, 'etype')
+        # recompute solutions
+        #select.annotated = False # avoid assertion error
+        self.compute_solutions()
+        # clean solutions according to initial solutions
+        return remove_solutions(self.solutions, self.select.solutions,
+                                self.select.defined_vars)
+
+    def build_variantes(self, newsolutions):
+        variantes = set()
+        for sol in newsolutions:
+            variante = []
+            for key, newvar in self.rewritten.iteritems():
+                variante.append( (key, sol[newvar]) )
+            variantes.add(tuple(variante))
+        # rebuild variantes as dict
+        variantes = [dict(variante) for variante in variantes]
+        # remove variable which have always the same type
+        for key in self.rewritten:
+            it = iter(variantes)
+            etype = it.next()[key]
+            for variante in it:
+                if variante[key] != etype:
+                    break
+            else:
+                for variante in variantes:
+                    del variante[key]
+        return variantes
+
+    def _cleanup_inserted(self, node):
+        # cleanup inserted variable references
+        for vref in node.iget_nodes(n.VariableRef):
+            vref.unregister_reference()
+            if not vref.variable.stinfo['references']:
+                # no more references, undefine the variable
+                del self.select.defined_vars[vref.name]
+
+    def _may_be_shared(self, relation, target, searchedvarname):
+        """return True if the snippet relation can be skipped to use a relation
+        from the original query
+        """
+        # if cardinality is in '?1', we can ignore the relation and use variable
+        # from the original query
+        rschema = self.schema.rschema(relation.r_type)
+        if target == 'object':
+            cardindex = 0
+            ttypes_func = rschema.objects
+            rprop = rschema.rproperty
+        else: # target == 'subject':
+            cardindex = 1
+            ttypes_func = rschema.subjects
+            rprop = lambda x, y, z: rschema.rproperty(y, x, z)
+        for etype in self.varinfo['stinfo']['possibletypes']:
+            for ttype in ttypes_func(etype):
+                if rprop(etype, ttype, 'cardinality')[cardindex] in '+*':
+                    return False
+        return True
+
+    def _use_outer_term(self, snippet_varname, term):
+        key = (self.current_expr, self.varmap, snippet_varname)
+        if key in self.rewritten:
+            insertedvar = self.select.defined_vars.pop(self.rewritten[key])
+            for inserted_vref in insertedvar.references():
+                inserted_vref.parent.replace(inserted_vref, term.copy(self.select))
+        self.rewritten[key] = term.name
+
+    def _get_varname_or_term(self, vname):
+        if vname == 'U':
+            if self.u_varname is None:
+                select = self.select
+                self.u_varname = select.allocate_varname()
+                # generate an identifier for the substitution
+                argname = select.allocate_varname()
+                while argname in self.kwargs:
+                    argname = select.allocate_varname()
+                # insert "U eid %(u)s"
+                var = select.get_variable(self.u_varname)
+                select.add_constant_restriction(select.get_variable(self.u_varname),
+                                                'eid', unicode(argname), 'Substitute')
+                self.kwargs[argname] = self.session.user.eid
+            return self.u_varname
+        key = (self.current_expr, self.varmap, vname)
+        try:
+            return self.rewritten[key]
+        except KeyError:
+            self.rewritten[key] = newvname = self.select.allocate_varname()
+            return newvname
+
+    # visitor methods ##########################################################
+
+    def _visit_binary(self, node, cls):
+        newnode = cls()
+        for c in node.children:
+            new = c.accept(self)
+            if new is None:
+                continue
+            newnode.append(new)
+        if len(newnode.children) == 0:
+            return None
+        if len(newnode.children) == 1:
+            return newnode.children[0]
+        return newnode
+
+    def _visit_unary(self, node, cls):
+        newc = node.children[0].accept(self)
+        if newc is None:
+            return None
+        newnode = cls()
+        newnode.append(newc)
+        return newnode
+
+    def visit_and(self, node):
+        return self._visit_binary(node, n.And)
+
+    def visit_or(self, node):
+        return self._visit_binary(node, n.Or)
+
+    def visit_not(self, node):
+        return self._visit_unary(node, n.Not)
+
+    def visit_exists(self, node):
+        return self._visit_unary(node, n.Exists)
+
+    def visit_relation(self, node):
+        lhs, rhs = node.get_variable_parts()
+        if node.r_type in ('has_add_permission', 'has_update_permission',
+                           'has_delete_permission', 'has_read_permission'):
+            assert lhs.name == 'U'
+            action = node.r_type.split('_')[1]
+            key = (self.current_expr, self.varmap, rhs.name)
+            self.pending_keys.append( (key, action) )
+            return
+        if lhs.name in self.revvarmap:
+            # on lhs
+            # see if we can reuse this relation
+            rels = self.varinfo['lhs_rels']
+            if (node.r_type in rels and isinstance(rhs, n.VariableRef)
+                and rhs.name != 'U' and not rels[node.r_type].neged(strict=True)
+                and self._may_be_shared(node, 'object', lhs.name)):
+                # ok, can share variable
+                term = rels[node.r_type].children[1].children[0]
+                self._use_outer_term(rhs.name, term)
+                return
+        elif isinstance(rhs, n.VariableRef) and rhs.name in self.revvarmap and lhs.name != 'U':
+            # on rhs
+            # see if we can reuse this relation
+            rels = self.varinfo['rhs_rels']
+            if (node.r_type in rels and not rels[node.r_type].neged(strict=True)
+                and self._may_be_shared(node, 'subject', rhs.name)):
+                # ok, can share variable
+                term = rels[node.r_type].children[0]
+                self._use_outer_term(lhs.name, term)
+                return
+        rel = n.Relation(node.r_type, node.optional)
+        for c in node.children:
+            rel.append(c.accept(self))
+        return rel
+
+    def visit_comparison(self, node):
+        cmp_ = n.Comparison(node.operator)
+        for c in node.children:
+            cmp_.append(c.accept(self))
+        return cmp_
+
+    def visit_mathexpression(self, node):
+        cmp_ = n.MathExpression(node.operator)
+        for c in cmp.children:
+            cmp_.append(c.accept(self))
+        return cmp_
+
+    def visit_function(self, node):
+        """generate filter name for a function"""
+        function_ = n.Function(node.name)
+        for c in node.children:
+            function_.append(c.accept(self))
+        return function_
+
+    def visit_constant(self, node):
+        """generate filter name for a constant"""
+        return n.Constant(node.value, node.type)
+
+    def visit_variableref(self, node):
+        """get the sql name for a variable reference"""
+        if node.name in self.revvarmap:
+            if self.varinfo.get('const') is not None:
+                return n.Constant(self.varinfo['const'], 'Int') # XXX gae
+            return n.VariableRef(self.select.get_variable(
+                self.revvarmap[node.name]))
+        vname_or_term = self._get_varname_or_term(node.name)
+        if isinstance(vname_or_term, basestring):
+            return n.VariableRef(self.select.get_variable(vname_or_term))
+        # shared term
+        return vname_or_term.copy(self.select)
--- a/schema.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/schema.py	Thu Sep 17 15:16:53 2009 +0200
@@ -44,6 +44,7 @@
     'owned_by', 'created_by', 'is', 'is_instance_of', 'identity',
     'eid', 'creation_date', 'modification_date', 'has_text', 'cwuri',
     ))
+SYSTEM_RTYPES = set(('require_permission', 'custom_workflow', 'in_state', 'wf_info_for'))
 
 #  set of entity and relation types used to build the schema
 SCHEMA_TYPES = set((
@@ -100,7 +101,7 @@
         etype = ETYPE_NAME_MAP[etype]
     return etype
 
-def display_name(req, key, form=''):
+def display_name(req, key, form='', context=None):
     """return a internationalized string for the key (schema entity or relation
     name) in a given form
     """
@@ -110,8 +111,12 @@
     if form:
         key = key + '_' + form
     # ensure unicode
-    # added .lower() in case no translation are available
-    return unicode(req._(key)).lower()
+    # .lower() in case no translation are available XXX done whatever a translation is there or not!
+    if context is not None:
+        return unicode(req.pgettext(context, key)).lower()
+    else:
+        return unicode(req._(key)).lower()
+
 __builtins__['display_name'] = deprecated('[3.4] display_name should be imported from cubicweb.schema')(display_name)
 
 def ERSchema_display_name(self, req, form=''):
@@ -642,6 +647,8 @@
             if len(self.rqlst.defined_vars[mainvar].references()) <= 2:
                 _LOGGER.warn('You did not use the %s variable in your RQL '
                              'expression %s', mainvar, self)
+        # syntax tree used by read security (inserted in queries when necessary
+        self.snippet_rqlst = parse(self.minimal_rql, print_errors=False).children[0]
 
     def __str__(self):
         return self.full_rql
@@ -767,8 +774,6 @@
 class ERQLExpression(RQLExpression):
     def __init__(self, expression, mainvars=None, eid=None):
         RQLExpression.__init__(self, expression, mainvars or 'X', eid)
-        # syntax tree used by read security (inserted in queries when necessary
-        self.snippet_rqlst = parse(self.minimal_rql, print_errors=False).children[0]
 
     @property
     def full_rql(self):
--- a/schemas/base.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/schemas/base.py	Thu Sep 17 15:16:53 2009 +0200
@@ -269,3 +269,8 @@
 class see_also(RelationType):
     """generic relation to link one entity to another"""
     symetric = True
+    permissions = {
+        'read':   ('managers', 'users', 'guests',),
+        'add':    ('managers', RRQLExpression('U has_update_permission S'),),
+        'delete': ('managers', RRQLExpression('U has_update_permission S'),),
+        }
--- a/schemas/workflow.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/schemas/workflow.py	Thu Sep 17 15:16:53 2009 +0200
@@ -33,7 +33,7 @@
 
 
 class default_workflow(RelationType):
-    """default workflow for this entity types"""
+    """default workflow for an entity type"""
     permissions = META_RTYPE_PERMS
 
     subject = 'CWEType'
--- a/selectors.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/selectors.py	Thu Sep 17 15:16:53 2009 +0200
@@ -961,4 +961,11 @@
     """
     def __init__(self, scorefunc, once_is_enough=False):
         super(score_entity, self).__init__(once_is_enough)
-        self.score_entity = scorefunc
+        def intscore(*args, **kwargs):
+            score = scorefunc(*args, **kwargs)
+            if not score:
+                return 0
+            if isinstance(score, (int, long)):
+                return score
+            return 1
+        self.score_entity = intscore
--- a/server/msplanner.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/server/msplanner.py	Thu Sep 17 15:16:53 2009 +0200
@@ -344,7 +344,7 @@
                         # * at least one supported relation specified
                         if not varobj._q_invariant or \
                                any(imap(source.support_relation,
-                                        (r.r_type for r in rels if r.r_type != 'eid'))):
+                                        (r.r_type for r in rels if r.r_type not in ('identity', 'eid')))):
                             sourcesterms.setdefault(source, {}).setdefault(varobj, set()).add(i)
                         # if variable is not invariant and is used by a relation
                         # not supported by this source, we'll have to split the
--- a/server/querier.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/server/querier.py	Thu Sep 17 15:16:53 2009 +0200
@@ -138,8 +138,8 @@
         # various resource accesors
         self.querier = querier
         self.schema = querier.schema
-        self.rqlhelper = querier._rqlhelper
         self.sqlannotate = querier.sqlgen_annotate
+        self.rqlhelper = session.vreg.rqlhelper
 
     def annotate_rqlst(self):
         if not self.rqlst.annotated:
@@ -265,6 +265,8 @@
                     myrqlst = select.copy(solutions=lchecksolutions)
                     myunion.append(myrqlst)
                     # in-place rewrite + annotation / simplification
+                    lcheckdef = [((varmap, 'X'), rqlexprs)
+                                 for varmap, rqlexprs in lcheckdef]
                     rewrite(myrqlst, lcheckdef, lchecksolutions, self.args)
                     noinvariant.update(noinvariant_vars(restricted, myrqlst, nbtrees))
                 if () in localchecks:
@@ -524,37 +526,33 @@
 
     def set_schema(self, schema):
         self.schema = schema
+        repo = self._repo
         # rql parsing / analysing helper
-        self._rqlhelper = RQLHelper(schema, special_relations={'eid': 'uid',
-                                                               'has_text': 'fti'})
-        self._rql_cache = Cache(self._repo.config['rql-cache-size'])
+        self.solutions = repo.vreg.solutions
+        self._rql_cache = Cache(repo.config['rql-cache-size'])
         self.cache_hit, self.cache_miss = 0, 0
         # rql planner
         # note: don't use repo.sources, may not be built yet, and also "admin"
         #       isn't an actual source
-        if len([uri for uri in self._repo.config.sources() if uri != 'admin']) < 2:
+        rqlhelper = repo.vreg.rqlhelper
+        self._parse = rqlhelper.parse
+        self._annotate = rqlhelper.annotate
+        if len([uri for uri in repo.config.sources() if uri != 'admin']) < 2:
             from cubicweb.server.ssplanner import SSPlanner
-            self._planner = SSPlanner(schema, self._rqlhelper)
+            self._planner = SSPlanner(schema, rqlhelper)
         else:
             from cubicweb.server.msplanner import MSPlanner
-            self._planner = MSPlanner(schema, self._rqlhelper)
+            self._planner = MSPlanner(schema, rqlhelper)
         # sql generation annotator
         self.sqlgen_annotate = SQLGenAnnotator(schema).annotate
 
     def parse(self, rql, annotate=False):
         """return a rql syntax tree for the given rql"""
         try:
-            return self._rqlhelper.parse(unicode(rql), annotate=annotate)
+            return self._parse(unicode(rql), annotate=annotate)
         except UnicodeError:
             raise RQLSyntaxError(rql)
 
-    def solutions(self, session, rqlst, args):
-        assert session is not None
-        def type_from_eid(eid, type_from_eid=self._repo.type_from_eid,
-                          session=session):
-            return type_from_eid(eid, session)
-        self._rqlhelper.compute_solutions(rqlst, {'eid': type_from_eid}, args)
-
     def plan_factory(self, rqlst, args, session):
         """create an execution plan for an INSERT RQL query"""
         if rqlst.TYPE == 'insert':
@@ -642,7 +640,7 @@
             # bother modifying it. This is not necessary on write queries since
             # a new syntax tree is built from them.
             rqlst = rqlst.copy()
-            self._rqlhelper.annotate(rqlst)
+            self._annotate(rqlst)
         # make an execution plan
         plan = self.plan_factory(rqlst, args, session)
         plan.cache_key = cachekey
--- a/server/repository.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/server/repository.py	Thu Sep 17 15:16:53 2009 +0200
@@ -101,6 +101,9 @@
     # hooks responsability to ensure they do not violate relation's cardinality
     if session.is_super_session:
         return
+    ensure_card_respected(session.unsafe_execute, session, eidfrom, rtype, eidto)
+
+def ensure_card_respected(execute, session, eidfrom, rtype, eidto):
     card = session.schema_rproperty(rtype, eidfrom, eidto, 'cardinality')
     # one may be tented to check for neweids but this may cause more than one
     # relation even with '1?'  cardinality if thoses relations are added in the
@@ -111,14 +114,11 @@
     if card[0] in '1?':
         rschema = session.repo.schema.rschema(rtype)
         if not rschema.inlined:
-            session.unsafe_execute(
-                'DELETE X %s Y WHERE X eid %%(x)s, NOT Y eid %%(y)s' % rtype,
-                {'x': eidfrom, 'y': eidto}, 'x')
+            execute('DELETE X %s Y WHERE X eid %%(x)s,NOT Y eid %%(y)s' % rtype,
+                    {'x': eidfrom, 'y': eidto}, 'x')
     if card[1] in '1?':
-        session.unsafe_execute(
-            'DELETE X %s Y WHERE NOT X eid %%(x)s, Y eid %%(y)s' % rtype,
-            {'x': eidfrom, 'y': eidto}, 'y')
-
+        execute('DELETE X %s Y WHERE NOT X eid %%(x)s, Y eid %%(y)s' % rtype,
+                {'x': eidfrom, 'y': eidto}, 'y')
 
 class Repository(object):
     """a repository provides access to a set of persistent storages for
@@ -142,6 +142,7 @@
         self._running_threads = []
         # initial schema, should be build or replaced latter
         self.schema = schema.CubicWebSchema(config.appid)
+        self.vreg.schema = self.schema # until actual schema is loaded...
         # querier helper, need to be created after sources initialization
         self.querier = querier.QuerierHelper(self, self.schema)
         # should we reindex in changes?
@@ -183,7 +184,6 @@
             config.bootstrap_cubes()
             self.set_schema(config.load_schema(), resetvreg=False)
             # need to load the Any and CWUser entity types
-            self.vreg.schema = self.schema
             etdirectory = join(CW_SOFTWARE_ROOT, 'entities')
             self.vreg.init_registration([etdirectory])
             self.vreg.load_file(join(etdirectory, '__init__.py'),
@@ -237,17 +237,18 @@
         if rebuildinfered:
             schema.rebuild_infered_relations()
         self.info('set schema %s %#x', schema.name, id(schema))
-        self.debug(', '.join(sorted(str(e) for e in schema.entities())))
-        self.querier.set_schema(schema)
-        for source in self.sources:
-            source.set_schema(schema)
-        self.schema = schema
         if resetvreg:
             if self.config._cubes is None:
                 self.config.init_cubes(self.get_cubes())
             # full reload of all appobjects
             self.vreg.reset()
             self.vreg.set_schema(schema)
+        else:
+            self.vreg._set_schema(schema)
+        self.querier.set_schema(schema)
+        for source in self.sources:
+            source.set_schema(schema)
+        self.schema = schema
 
     def fill_schema(self):
         """lod schema from the repository"""
--- a/server/rqlannotation.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/server/rqlannotation.py	Thu Sep 17 15:16:53 2009 +0200
@@ -331,7 +331,7 @@
         if isinstance(term, VariableRef) and self.is_ambiguous(term.variable):
             var = term.variable
             if len(var.stinfo['relations'] - var.stinfo['typerels']) == 1 \
-                   or rel.sqlscope is var.sqlscope:
+                   or rel.sqlscope is var.sqlscope or rel.r_type == 'identity':
                 self.restrict(var, frozenset(etypes_func()))
                 try:
                     self.maydeambrels[var].add(rel)
--- a/server/rqlrewrite.py	Tue Sep 15 15:01:41 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,396 +0,0 @@
-"""RQL rewriting utilities, used for read security checking
-
-:organization: Logilab
-:copyright: 2007-2009 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.
-:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
-:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
-"""
-
-from rql import nodes, stmts, TypeResolverException
-from cubicweb import Unauthorized, server, typed_eid
-from cubicweb.server.ssplanner import add_types_restriction
-
-def remove_solutions(origsolutions, solutions, defined):
-    """when a rqlst has been generated from another by introducing security
-    assertions, this method returns solutions which are contained in orig
-    solutions
-    """
-    newsolutions = []
-    for origsol in origsolutions:
-        for newsol in solutions[:]:
-            for var, etype in origsol.items():
-                try:
-                    if newsol[var] != etype:
-                        try:
-                            defined[var].stinfo['possibletypes'].remove(newsol[var])
-                        except KeyError:
-                            pass
-                        break
-                except KeyError:
-                    # variable has been rewritten
-                    continue
-            else:
-                newsolutions.append(newsol)
-                solutions.remove(newsol)
-    return newsolutions
-
-class Unsupported(Exception): pass
-
-class RQLRewriter(object):
-    """insert some rql snippets into another rql syntax tree"""
-    def __init__(self, querier, session):
-        self.session = session
-        self.annotate = querier._rqlhelper.annotate
-        self._compute_solutions = querier.solutions
-        self.schema = querier.schema
-
-    def compute_solutions(self):
-        self.annotate(self.select)
-        try:
-            self._compute_solutions(self.session, self.select, self.kwargs)
-        except TypeResolverException:
-            raise Unsupported()
-        if len(self.select.solutions) < len(self.solutions):
-            raise Unsupported()
-
-    def rewrite(self, select, snippets, solutions, kwargs):
-        if server.DEBUG:
-            print '---- rewrite', select, snippets, solutions
-        self.select = select
-        self.solutions = solutions
-        self.kwargs = kwargs
-        self.u_varname = None
-        self.removing_ambiguity = False
-        self.exists_snippet = {}
-        # we have to annotate the rqlst before inserting snippets, even though
-        # we'll have to redo it latter
-        self.annotate(select)
-        self.insert_snippets(snippets)
-        if not self.exists_snippet and self.u_varname:
-            # U has been inserted than cancelled, cleanup
-            select.undefine_variable(select.defined_vars[self.u_varname])
-        # clean solutions according to initial solutions
-        newsolutions = remove_solutions(solutions, select.solutions,
-                                        select.defined_vars)
-        assert len(newsolutions) >= len(solutions), \
-               'rewritten rql %s has lost some solutions, there is probably something '\
-               'wrong in your schema permission (for instance using a '\
-              'RQLExpression which insert a relation which doesn\'t exists in '\
-               'the schema)\nOrig solutions: %s\nnew solutions: %s' % (
-            select, solutions, newsolutions)
-        if len(newsolutions) > len(solutions):
-            # the snippet has introduced some ambiguities, we have to resolve them
-            # "manually"
-            variantes = self.build_variantes(newsolutions)
-            # insert "is" where necessary
-            varexistsmap = {}
-            self.removing_ambiguity = True
-            for (erqlexpr, mainvar, oldvarname), etype in variantes[0].iteritems():
-                varname = self.rewritten[(erqlexpr, mainvar, oldvarname)]
-                var = select.defined_vars[varname]
-                exists = var.references()[0].scope
-                exists.add_constant_restriction(var, 'is', etype, 'etype')
-                varexistsmap[mainvar] = exists
-            # insert ORED exists where necessary
-            for variante in variantes[1:]:
-                self.insert_snippets(snippets, varexistsmap)
-                for (erqlexpr, mainvar, oldvarname), etype in variante.iteritems():
-                    varname = self.rewritten[(erqlexpr, mainvar, oldvarname)]
-                    try:
-                        var = select.defined_vars[varname]
-                    except KeyError:
-                        # not a newly inserted variable
-                        continue
-                    exists = var.references()[0].scope
-                    exists.add_constant_restriction(var, 'is', etype, 'etype')
-            # recompute solutions
-            #select.annotated = False # avoid assertion error
-            self.compute_solutions()
-            # clean solutions according to initial solutions
-            newsolutions = remove_solutions(solutions, select.solutions,
-                                            select.defined_vars)
-        select.solutions = newsolutions
-        add_types_restriction(self.schema, select)
-        if server.DEBUG:
-            print '---- rewriten', select
-
-    def build_variantes(self, newsolutions):
-        variantes = set()
-        for sol in newsolutions:
-            variante = []
-            for (erqlexpr, mainvar, oldvar), newvar in self.rewritten.iteritems():
-                variante.append( ((erqlexpr, mainvar, oldvar), sol[newvar]) )
-            variantes.add(tuple(variante))
-        # rebuild variantes as dict
-        variantes = [dict(variante) for variante in variantes]
-        # remove variable which have always the same type
-        for erqlexpr, mainvar, oldvar in self.rewritten:
-            it = iter(variantes)
-            etype = it.next()[(erqlexpr, mainvar, oldvar)]
-            for variante in it:
-                if variante[(erqlexpr, mainvar, oldvar)] != etype:
-                    break
-            else:
-                for variante in variantes:
-                    del variante[(erqlexpr, mainvar, oldvar)]
-        return variantes
-
-    def insert_snippets(self, snippets, varexistsmap=None):
-        self.rewritten = {}
-        for varname, erqlexprs in snippets:
-            if varexistsmap is not None and not varname in varexistsmap:
-                continue
-            try:
-                self.const = typed_eid(varname)
-                self.varname = self.const
-                self.rhs_rels = self.lhs_rels = {}
-            except ValueError:
-                self.varname = varname
-                self.const = None
-                self.varstinfo = stinfo = self.select.defined_vars[varname].stinfo
-                if varexistsmap is None:
-                    self.rhs_rels = dict( (rel.r_type, rel) for rel in stinfo['rhsrelations'])
-                    self.lhs_rels = dict( (rel.r_type, rel) for rel in stinfo['relations']
-                                                  if not rel in stinfo['rhsrelations'])
-                else:
-                    self.rhs_rels = self.lhs_rels = {}
-            parent = None
-            inserted = False
-            for erqlexpr in erqlexprs:
-                self.current_expr = erqlexpr
-                if varexistsmap is None:
-                    try:
-                        new = self.insert_snippet(varname, erqlexpr.snippet_rqlst, parent)
-                    except Unsupported:
-                        continue
-                    inserted = True
-                    if new is not None:
-                        self.exists_snippet[erqlexpr] = new
-                    parent = parent or new
-                else:
-                    # called to reintroduce snippet due to ambiguity creation,
-                    # so skip snippets which are not introducing this ambiguity
-                    exists = varexistsmap[varname]
-                    if self.exists_snippet[erqlexpr] is exists:
-                        self.insert_snippet(varname, erqlexpr.snippet_rqlst, exists)
-            if varexistsmap is None and not inserted:
-                # no rql expression found matching rql solutions. User has no access right
-                raise Unauthorized()
-
-    def insert_snippet(self, varname, snippetrqlst, parent=None):
-        new = snippetrqlst.where.accept(self)
-        if new is not None:
-            try:
-                var = self.select.defined_vars[varname]
-            except KeyError:
-                # not a variable
-                pass
-            else:
-                if var.stinfo['optrelations']:
-                    # use a subquery
-                    subselect = stmts.Select()
-                    subselect.append_selected(nodes.VariableRef(subselect.get_variable(varname)))
-                    subselect.add_restriction(new.copy(subselect))
-                    aliases = [varname]
-                    for rel in var.stinfo['relations']:
-                        rschema = self.schema.rschema(rel.r_type)
-                        if rschema.is_final() or (rschema.inlined and not rel in var.stinfo['rhsrelations']):
-                            self.select.remove_node(rel)
-                            rel.children[0].name = varname
-                            subselect.add_restriction(rel.copy(subselect))
-                            for vref in rel.children[1].iget_nodes(nodes.VariableRef):
-                                subselect.append_selected(vref.copy(subselect))
-                                aliases.append(vref.name)
-                    if self.u_varname:
-                        # generate an identifier for the substitution
-                        argname = subselect.allocate_varname()
-                        while argname in self.kwargs:
-                            argname = subselect.allocate_varname()
-                        subselect.add_constant_restriction(subselect.get_variable(self.u_varname),
-                                                        'eid', unicode(argname), 'Substitute')
-                        self.kwargs[argname] = self.session.user.eid
-                    add_types_restriction(self.schema, subselect, subselect, solutions=self.solutions)
-                    assert parent is None
-                    myunion = stmts.Union()
-                    myunion.append(subselect)
-                    aliases = [nodes.VariableRef(self.select.get_variable(name, i))
-                               for i, name in enumerate(aliases)]
-                    self.select.add_subquery(nodes.SubQuery(aliases, myunion), check=False)
-                    self._cleanup_inserted(new)
-                    try:
-                        self.compute_solutions()
-                    except Unsupported:
-                        # some solutions have been lost, can't apply this rql expr
-                        self.select.remove_subquery(new, undefine=True)
-                        raise
-                    return
-            new = nodes.Exists(new)
-            if parent is None:
-                self.select.add_restriction(new)
-            else:
-                grandpa = parent.parent
-                or_ = nodes.Or(parent, new)
-                grandpa.replace(parent, or_)
-            if not self.removing_ambiguity:
-                try:
-                    self.compute_solutions()
-                except Unsupported:
-                    # some solutions have been lost, can't apply this rql expr
-                    if parent is None:
-                        self.select.remove_node(new, undefine=True)
-                    else:
-                        parent.parent.replace(or_, or_.children[0])
-                        self._cleanup_inserted(new)
-                    raise
-            return new
-
-    def _cleanup_inserted(self, node):
-        # cleanup inserted variable references
-        for vref in node.iget_nodes(nodes.VariableRef):
-            vref.unregister_reference()
-            if not vref.variable.stinfo['references']:
-                # no more references, undefine the variable
-                del self.select.defined_vars[vref.name]
-
-    def _visit_binary(self, node, cls):
-        newnode = cls()
-        for c in node.children:
-            new = c.accept(self)
-            if new is None:
-                continue
-            newnode.append(new)
-        if len(newnode.children) == 0:
-            return None
-        if len(newnode.children) == 1:
-            return newnode.children[0]
-        return newnode
-
-    def _visit_unary(self, node, cls):
-        newc = node.children[0].accept(self)
-        if newc is None:
-            return None
-        newnode = cls()
-        newnode.append(newc)
-        return newnode
-
-    def visit_and(self, et):
-        return self._visit_binary(et, nodes.And)
-
-    def visit_or(self, ou):
-        return self._visit_binary(ou, nodes.Or)
-
-    def visit_not(self, node):
-        return self._visit_unary(node, nodes.Not)
-
-    def visit_exists(self, node):
-        return self._visit_unary(node, nodes.Exists)
-
-    def visit_relation(self, relation):
-        lhs, rhs = relation.get_variable_parts()
-        if lhs.name == 'X':
-            # on lhs
-            # see if we can reuse this relation
-            if relation.r_type in self.lhs_rels and isinstance(rhs, nodes.VariableRef) and rhs.name != 'U':
-                if self._may_be_shared(relation, 'object'):
-                    # ok, can share variable
-                    term = self.lhs_rels[relation.r_type].children[1].children[0]
-                    self._use_outer_term(rhs.name, term)
-                    return
-        elif isinstance(rhs, nodes.VariableRef) and rhs.name == 'X' and lhs.name != 'U':
-            # on rhs
-            # see if we can reuse this relation
-            if relation.r_type in self.rhs_rels and self._may_be_shared(relation, 'subject'):
-                # ok, can share variable
-                term = self.rhs_rels[relation.r_type].children[0]
-                self._use_outer_term(lhs.name, term)
-                return
-        rel = nodes.Relation(relation.r_type, relation.optional)
-        for c in relation.children:
-            rel.append(c.accept(self))
-        return rel
-
-    def visit_comparison(self, cmp):
-        cmp_ = nodes.Comparison(cmp.operator)
-        for c in cmp.children:
-            cmp_.append(c.accept(self))
-        return cmp_
-
-    def visit_mathexpression(self, mexpr):
-        cmp_ = nodes.MathExpression(mexpr.operator)
-        for c in cmp.children:
-            cmp_.append(c.accept(self))
-        return cmp_
-
-    def visit_function(self, function):
-        """generate filter name for a function"""
-        function_ = nodes.Function(function.name)
-        for c in function.children:
-            function_.append(c.accept(self))
-        return function_
-
-    def visit_constant(self, constant):
-        """generate filter name for a constant"""
-        return nodes.Constant(constant.value, constant.type)
-
-    def visit_variableref(self, vref):
-        """get the sql name for a variable reference"""
-        if vref.name == 'X':
-            if self.const is not None:
-                return nodes.Constant(self.const, 'Int')
-            return nodes.VariableRef(self.select.get_variable(self.varname))
-        vname_or_term = self._get_varname_or_term(vref.name)
-        if isinstance(vname_or_term, basestring):
-            return nodes.VariableRef(self.select.get_variable(vname_or_term))
-        # shared term
-        return vname_or_term.copy(self.select)
-
-    def _may_be_shared(self, relation, target):
-        """return True if the snippet relation can be skipped to use a relation
-        from the original query
-        """
-        # if cardinality is in '?1', we can ignore the relation and use variable
-        # from the original query
-        rschema = self.schema.rschema(relation.r_type)
-        if target == 'object':
-            cardindex = 0
-            ttypes_func = rschema.objects
-            rprop = rschema.rproperty
-        else: # target == 'subject':
-            cardindex = 1
-            ttypes_func = rschema.subjects
-            rprop = lambda x, y, z: rschema.rproperty(y, x, z)
-        for etype in self.varstinfo['possibletypes']:
-            for ttype in ttypes_func(etype):
-                if rprop(etype, ttype, 'cardinality')[cardindex] in '+*':
-                    return False
-        return True
-
-    def _use_outer_term(self, snippet_varname, term):
-        key = (self.current_expr, self.varname, snippet_varname)
-        if key in self.rewritten:
-            insertedvar = self.select.defined_vars.pop(self.rewritten[key])
-            for inserted_vref in insertedvar.references():
-                inserted_vref.parent.replace(inserted_vref, term.copy(self.select))
-        self.rewritten[key] = term
-
-    def _get_varname_or_term(self, vname):
-        if vname == 'U':
-            if self.u_varname is None:
-                select = self.select
-                self.u_varname = select.allocate_varname()
-                # generate an identifier for the substitution
-                argname = select.allocate_varname()
-                while argname in self.kwargs:
-                    argname = select.allocate_varname()
-                # insert "U eid %(u)s"
-                var = select.get_variable(self.u_varname)
-                select.add_constant_restriction(select.get_variable(self.u_varname),
-                                                'eid', unicode(argname), 'Substitute')
-                self.kwargs[argname] = self.session.user.eid
-            return self.u_varname
-        key = (self.current_expr, self.varname, vname)
-        try:
-            return self.rewritten[key]
-        except KeyError:
-            self.rewritten[key] = newvname = self.select.allocate_varname()
-            return newvname
--- a/server/session.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/server/session.py	Thu Sep 17 15:16:53 2009 +0200
@@ -19,7 +19,7 @@
 from cubicweb.req import RequestSessionBase
 from cubicweb.dbapi import ConnectionProperties
 from cubicweb.utils import make_uid
-from cubicweb.server.rqlrewrite import RQLRewriter
+from cubicweb.rqlrewrite import RQLRewriter
 
 ETYPE_PYOBJ_MAP[Binary] = 'Bytes'
 
@@ -207,13 +207,18 @@
         vreg = self.vreg
         language = language or self.user.property_value('ui.language')
         try:
-            self._ = self.__ = vreg.config.translations[language]
+            gettext, pgettext = vreg.config.translations[language]
+            self._ = self.__ = gettext
+            self.pgettext = pgettext
         except KeyError:
             language = vreg.property_value('ui.language')
             try:
-                self._ = self.__ = vreg.config.translations[language]
+                gettext, pgettext = 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):
@@ -551,7 +556,7 @@
         try:
             return self._threaddata._rewriter
         except AttributeError:
-            self._threaddata._rewriter = RQLRewriter(self.repo.querier, self)
+            self._threaddata._rewriter = RQLRewriter(self)
             return self._threaddata._rewriter
 
     def build_description(self, rqlst, args, result):
--- a/server/sources/ldapuser.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/server/sources/ldapuser.py	Thu Sep 17 15:16:53 2009 +0200
@@ -336,7 +336,7 @@
                 if sol[varname] == 'CWUser':
                     mainvars.append(varname)
                     break
-        assert mainvars
+        assert mainvars, rqlst
         columns, globtransforms = self.prepare_columns(mainvars, rqlst)
         eidfilters = []
         allresults = []
--- a/server/sources/native.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/server/sources/native.py	Thu Sep 17 15:16:53 2009 +0200
@@ -231,7 +231,7 @@
     # ISource interface #######################################################
 
     def compile_rql(self, rql):
-        rqlst = self.repo.querier._rqlhelper.parse(rql)
+        rqlst = self.repo.vreg.rqlhelper.parse(rql)
         rqlst.restricted_vars = ()
         rqlst.children[0].solutions = self._sols
         self.repo.querier.sqlgen_annotate(rqlst)
--- a/server/sources/rql2sql.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/server/sources/rql2sql.py	Thu Sep 17 15:16:53 2009 +0200
@@ -336,6 +336,7 @@
         self._varmap = varmap
         self._query_attrs = {}
         self._state = None
+        self._not_scope_offset = 0
         try:
             # union query for each rqlst / solution
             sql = self.union_sql(union)
@@ -553,7 +554,11 @@
 
     def visit_not(self, node):
         self._state.push_scope()
+        if isinstance(node.children[0], Relation):
+            self._not_scope_offset += 1
         csql = node.children[0].accept(self)
+        if isinstance(node.children[0], Relation):
+            self._not_scope_offset -= 1
         sqls, tables = self._state.pop_scope()
         if node in self._state.done or not csql:
             # already processed or no sql generated by children
@@ -651,10 +656,6 @@
                 sql = self._visit_outer_join_relation(relation, rschema)
             elif rschema.inlined:
                 sql = self._visit_inlined_relation(relation)
-#             elif isinstance(relation.parent, Not):
-#                 self._state.done.add(relation.parent)
-#                 # NOT relation
-#                 sql = self._visit_not_relation(relation, rschema)
             else:
                 # regular (non final) relation
                 sql = self._visit_relation(relation, rschema)
@@ -1080,12 +1081,16 @@
         # a EXISTS node
         if var.sqlscope is var.stmt:
             scope = 0
+        # don't consider not_scope_offset if the variable is only used in one
+        # relation
+        elif len(var.stinfo['relations']) > 1:
+            scope = -1 - self._not_scope_offset
         else:
             scope = -1
         try:
             sql = self._varmap[var.name]
             table = sql.split('.', 1)[0]
-            if scope == -1:
+            if scope < 0:
                 scope = self._varmap_table_scope(var.stmt, table)
             self.add_table(table, scope=scope)
         except KeyError:
@@ -1095,7 +1100,8 @@
                 raise BadRQLQuery(var.stmt.root)
             table = var.name
             sql = '%s.%seid' % (table, SQL_PREFIX)
-            self.add_table('%s%s AS %s' % (SQL_PREFIX, etype, table), table, scope=scope)
+            self.add_table('%s%s AS %s' % (SQL_PREFIX, etype, table), table,
+                           scope=scope)
         return sql, table
 
     def _inlined_var_sql(self, var, rtype):
@@ -1146,8 +1152,8 @@
             key = table
         if key in self._state.tables:
             return
-        if scope == -1:
-            scope = len(self._state.actual_tables) - 1
+        if scope < 0:
+            scope = len(self._state.actual_tables) + scope
         self._state.tables[key] = (scope, table)
         self._state.actual_tables[scope].append(table)
 
--- a/server/test/unittest_extlite.py	Tue Sep 15 15:01:41 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-import threading, os, time
-
-from logilab.common.testlib import TestCase, unittest_main
-from logilab.common.db import get_connection
-
-class SQLiteTC(TestCase):
-    sqlite_file = '_extlite_test.sqlite'
-
-    def _cleanup(self):
-        try:
-            os.remove(self.sqlite_file)
-        except:
-            pass
-
-    def setUp(self):
-        self._cleanup()
-        cnx1 = get_connection('sqlite', database=self.sqlite_file)
-        cu = cnx1.cursor()
-        cu.execute('CREATE TABLE toto(name integer);')
-        cnx1.commit()
-        cnx1.close()
-
-    def tearDown(self):
-        self._cleanup()
-
-    def test(self):
-        lock1 = threading.Lock()
-        lock2 = threading.Lock()
-        
-        def run_thread():
-            cnx2 = get_connection('sqlite', database=self.sqlite_file)
-            lock1.acquire()
-            cu = cnx2.cursor()
-            cu.execute('SELECT name FROM toto')
-            self.failIf(cu.fetchall())
-            cnx2.commit()
-            lock1.release()
-            lock2.acquire()
-            cu.execute('SELECT name FROM toto')
-            self.failUnless(cu.fetchall())
-            lock2.release()
-
-        cnx1 = get_connection('sqlite', database=self.sqlite_file)
-        lock1.acquire()
-        lock2.acquire()
-        thread = threading.Thread(target=run_thread)
-        thread.start()
-        cu = cnx1.cursor()
-        cu.execute('SELECT name FROM toto')
-        lock1.release()
-        cnx1.commit()
-        cu.execute("INSERT INTO toto(name) VALUES ('toto')")
-        cnx1.commit()
-        lock2.release()
-
-if __name__ == '__main__':
-    unittest_main()
--- a/server/test/unittest_migractions.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/server/test/unittest_migractions.py	Thu Sep 17 15:16:53 2009 +0200
@@ -52,6 +52,7 @@
         assert self.cnx is self.mh._cnx
         assert self.session is self.mh.session, (self.session.id, self.mh.session.id)
 
+
     def test_add_attribute_int(self):
         self.failIf('whatever' in self.schema)
         orderdict = dict(self.mh.rqlexec('Any RTN, O WHERE X name "Note", RDEF from_entity X, '
@@ -137,6 +138,7 @@
         self.failUnless(self.execute('CWEType X WHERE X name "Folder2"'))
         self.failUnless('filed_under2' in self.schema)
         self.failUnless(self.execute('CWRType X WHERE X name "filed_under2"'))
+        self.schema.rebuild_infered_relations()
         self.assertEquals(sorted(str(rs) for rs in self.schema['Folder2'].subject_relations()),
                           ['created_by', 'creation_date', 'cwuri',
                            'description', 'description_format',
@@ -155,10 +157,11 @@
 
     def test_add_drop_entity_type(self):
         self.mh.cmd_add_entity_type('Folder2')
-        todoeid = self.mh.cmd_add_state(u'todo', 'Folder2', initial=True)
-        doneeid = self.mh.cmd_add_state(u'done', 'Folder2')
-        self.mh.cmd_add_transition(u'redoit', 'Folder2', (doneeid,), todoeid)
-        self.mh.cmd_add_transition(u'markasdone', 'Folder2', (todoeid,), doneeid)
+        wf = self.mh.cmd_add_workflow(u'folder2 wf', 'Folder2')
+        todo = wf.add_state(u'todo', initial=True)
+        done = wf.add_state(u'done')
+        wf.add_transition(u'redoit', done, todo)
+        wf.add_transition(u'markasdone', todo, done)
         self.commit()
         eschema = self.schema.eschema('Folder2')
         self.mh.cmd_drop_entity_type('Folder2')
@@ -172,6 +175,7 @@
     def test_add_drop_relation_type(self):
         self.mh.cmd_add_entity_type('Folder2', auto=False)
         self.mh.cmd_add_relation_type('filed_under2')
+        self.schema.rebuild_infered_relations()
         self.failUnless('filed_under2' in self.schema)
         self.assertEquals(sorted(str(e) for e in self.schema['filed_under2'].subjects()),
                           sorted(str(e) for e in self.schema.entities() if not e.is_final()))
@@ -189,8 +193,8 @@
                           '1*')
         self.mh.cmd_add_relation_definition('Personne', 'concerne2', 'Note')
         self.assertEquals(sorted(self.schema['concerne2'].objects()), ['Affaire', 'Note'])
-        self.mh.add_entity('Personne', nom=u'tot')
-        self.mh.add_entity('Affaire')
+        self.mh.create_entity('Personne', nom=u'tot')
+        self.mh.create_entity('Affaire')
         self.mh.rqlexec('SET X concerne2 Y WHERE X is Personne, Y is Affaire')
         self.commit()
         self.mh.cmd_drop_relation_definition('Personne', 'concerne2', 'Affaire')
@@ -225,11 +229,17 @@
         self.assertEquals(sorted(str(e) for e in self.schema['concerne'].subjects()),
                           ['Affaire', 'Personne'])
         self.assertEquals(sorted(str(e) for e in self.schema['concerne'].objects()),
+                          ['Affaire', 'Division', 'Note', 'SubDivision'])
+        self.schema.rebuild_infered_relations() # need to be explicitly called once everything is in place
+        self.assertEquals(sorted(str(e) for e in self.schema['concerne'].objects()),
                           ['Affaire', 'Note'])
         self.mh.cmd_add_relation_definition('Affaire', 'concerne', 'Societe')
         self.assertEquals(sorted(str(e) for e in self.schema['concerne'].subjects()),
                           ['Affaire', 'Personne'])
         self.assertEquals(sorted(str(e) for e in self.schema['concerne'].objects()),
+                          ['Affaire', 'Note', 'Societe'])
+        self.schema.rebuild_infered_relations() # need to be explicitly called once everything is in place
+        self.assertEquals(sorted(str(e) for e in self.schema['concerne'].objects()),
                           ['Affaire', 'Division', 'Note', 'Societe', 'SubDivision'])
         # trick: overwrite self.maxeid to avoid deletion of just reintroduced types
         self.maxeid = self.execute('Any MAX(X)')[0][0]
@@ -461,12 +471,6 @@
         ex = self.assertRaises(ConfigurationError, self.mh.cmd_remove_cube, 'file')
         self.assertEquals(str(ex), "can't remove cube file, used as a dependency")
 
-    def test_set_state(self):
-        user = self.session.user
-        self.mh.set_state(user.eid, 'deactivated')
-        user.clear_related_cache('in_state', 'subject')
-        self.assertEquals(user.state, 'deactivated')
-
     def test_introduce_base_class(self):
         self.mh.cmd_add_entity_type('Para')
         self.mh.repo.schema.rebuild_infered_relations()
--- a/server/test/unittest_msplanner.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/server/test/unittest_msplanner.py	Thu Sep 17 15:16:53 2009 +0200
@@ -348,7 +348,7 @@
 
     def setUp(self):
         BaseMSPlannerTC.setUp(self)
-        self.planner = MSPlanner(self.o.schema, self.o._rqlhelper)
+        self.planner = MSPlanner(self.o.schema, self.repo.vreg.rqlhelper)
 
     _test = test_plan
 
@@ -1961,13 +1961,23 @@
                      None, None, [self.system], {}, [])],
                    {'x': 999998, 'u': 999999})
 
-    def test_nonregr_identity_no_source_access(self):
+    def test_nonregr_identity_no_source_access_1(self):
         repo._type_source_cache[999999] = ('CWUser', 'ldap', 999998)
         self._test('Any S WHERE S identity U, S eid %(s)s, U eid %(u)s',
                    [('OneFetchStep', [('Any 999999 WHERE 999999 identity 999999', [{}])],
                      None, None, [self.system], {}, [])],
                    {'s': 999999, 'u': 999999})
 
+    def test_nonregr_identity_no_source_access_2(self):
+        repo._type_source_cache[999999] = ('EmailAddress', 'system', 999999)
+        repo._type_source_cache[999998] = ('CWUser', 'ldap', 999998)
+        self._test('Any X WHERE O use_email X, ((EXISTS(O identity U)) OR (EXISTS(O in_group G, G name IN("managers", "staff")))) OR (EXISTS(O in_group G2, U in_group G2, NOT G2 name "users")), X eid %(x)s, U eid %(u)s',
+                   [('OneFetchStep', [('Any 999999 WHERE O use_email 999999, ((EXISTS(O identity 999998)) OR (EXISTS(O in_group G, G name IN("managers", "staff")))) OR (EXISTS(O in_group G2, 999998 in_group G2, NOT G2 name "users"))',
+                                       [{'G': 'CWGroup', 'G2': 'CWGroup', 'O': 'CWUser'}])],
+                     None, None, [self.system], {}, [])],
+                   {'x': 999999, 'u': 999998})
+
+
 class MSPlannerTwoSameExternalSourcesTC(BasePlannerTC):
     """test planner related feature on a 3-sources repository:
 
@@ -1979,7 +1989,7 @@
         self.setup()
         self.add_source(FakeCardSource, 'cards')
         self.add_source(FakeCardSource, 'cards2')
-        self.planner = MSPlanner(self.o.schema, self.o._rqlhelper)
+        self.planner = MSPlanner(self.o.schema, self.repo.vreg.rqlhelper)
         assert repo.sources_by_uri['cards2'].support_relation('multisource_crossed_rel')
         assert 'multisource_crossed_rel' in repo.sources_by_uri['cards2'].cross_relations
         assert repo.sources_by_uri['cards'].support_relation('multisource_crossed_rel')
@@ -2132,7 +2142,7 @@
     def setUp(self):
         self.setup()
         self.add_source(FakeVCSSource, 'vcs')
-        self.planner = MSPlanner(self.o.schema, self.o._rqlhelper)
+        self.planner = MSPlanner(self.o.schema, self.repo.vreg.rqlhelper)
     _test = test_plan
 
     def test_multisource_inlined_rel_skipped(self):
--- a/server/test/unittest_multisources.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/server/test/unittest_multisources.py	Thu Sep 17 15:16:53 2009 +0200
@@ -237,11 +237,12 @@
 
     def test_not_relation(self):
         states = set(tuple(x) for x in self.sexecute('Any S,SN WHERE S is State, S name SN'))
+        self.session.user.clear_all_caches()
         userstate = self.session.user.in_state[0]
         states.remove((userstate.eid, userstate.name))
         notstates = set(tuple(x) for x in self.sexecute('Any S,SN WHERE S is State, S name SN, NOT X in_state S, X eid %(x)s',
                                                        {'x': self.session.user.eid}, 'x'))
-        self.assertEquals(notstates, states)
+        self.assertSetEquals(notstates, states)
         aff1 = self.sexecute('Any X WHERE X is Affaire, X ref "AFFREF"')[0][0]
         aff1stateeid, aff1statename = self.sexecute('Any S,SN WHERE X eid %(x)s, X in_state S, S name SN', {'x': aff1}, 'x')[0]
         self.assertEquals(aff1statename, 'pitetre')
--- a/server/test/unittest_rql2sql.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/server/test/unittest_rql2sql.py	Thu Sep 17 15:16:53 2009 +0200
@@ -163,7 +163,6 @@
 ]
 
 ADVANCED= [
-
     ("Societe S WHERE S nom 'Logilab' OR S nom 'Caesium'",
      '''SELECT S.cw_eid
 FROM cw_Societe AS S
@@ -642,6 +641,13 @@
 WHERE X.cw_in_state=S.cw_eid
 ORDER BY 2) AS T1'''),
 
+    ('Any O,AA,AB,AC ORDERBY AC DESC '
+     'WHERE NOT S use_email O, S eid 1, O is EmailAddress, O address AA, O alias AB, O modification_date AC, '
+     'EXISTS(A use_email O, EXISTS(A identity B, NOT B in_group D, D name "guests", D is CWGroup), A is CWUser), B eid 2',
+     '''SELECT O.cw_eid, O.cw_address, O.cw_alias, O.cw_modification_date
+FROM cw_EmailAddress AS O
+WHERE NOT EXISTS(SELECT 1 FROM use_email_relation AS rel_use_email0 WHERE rel_use_email0.eid_from=1 AND rel_use_email0.eid_to=O.cw_eid) AND EXISTS(SELECT 1 FROM use_email_relation AS rel_use_email1 WHERE rel_use_email1.eid_to=O.cw_eid AND EXISTS(SELECT 1 FROM cw_CWGroup AS D WHERE rel_use_email1.eid_from=2 AND NOT EXISTS(SELECT 1 FROM in_group_relation AS rel_in_group2 WHERE rel_in_group2.eid_from=2 AND rel_in_group2.eid_to=D.cw_eid) AND D.cw_name=guests))
+ORDER BY 4 DESC'''),
     ]
 
 MULTIPLE_SEL = [
--- a/server/test/unittest_rqlannotation.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/server/test/unittest_rqlannotation.py	Thu Sep 17 15:16:53 2009 +0200
@@ -95,6 +95,11 @@
         self.assertEquals(rqlst.defined_vars['X']._q_invariant, False)
         self.assertEquals(rqlst.defined_vars['Y']._q_invariant, False)
 
+    def test_diff_scope_identity_deamb(self):
+        rqlst = self._prepare('Any X WHERE X concerne Y, Y is Note, EXISTS(Y identity Z, Z migrated_from N)')
+        self.assertEquals(rqlst.defined_vars['Z']._q_invariant, True)
+        self.assertEquals(rqlst.defined_vars['Y']._q_invariant, True)
+
     def test_optional_inlined(self):
         rqlst = self._prepare('Any X,S where X from_state S?')
         self.assertEquals(rqlst.defined_vars['X']._q_invariant, False)
--- a/server/test/unittest_rqlrewrite.py	Tue Sep 15 15:01:41 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,193 +0,0 @@
-"""
-
-:organization: Logilab
-:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.
-:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
-:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
-"""
-from logilab.common.testlib import unittest_main, TestCase
-from logilab.common.testlib import mock_object
-
-from rql import parse, nodes, RQLHelper
-
-from cubicweb import Unauthorized
-from cubicweb.server.rqlrewrite import RQLRewriter
-from cubicweb.devtools import repotest, TestServerConfiguration
-
-config = TestServerConfiguration('data')
-config.bootstrap_cubes()
-schema = config.load_schema()
-schema.add_relation_def(mock_object(subject='Card', name='in_state', object='State', cardinality='1*'))
-
-rqlhelper = RQLHelper(schema, special_relations={'eid': 'uid',
-                                                 'has_text': 'fti'})
-
-def setup_module(*args):
-    repotest.do_monkey_patch()
-
-def teardown_module(*args):
-    repotest.undo_monkey_patch()
-
-def eid_func_map(eid):
-    return {1: 'CWUser',
-            2: 'Card'}[eid]
-
-def rewrite(rqlst, snippets_map, kwargs):
-    class FakeQuerier:
-        schema = schema
-        @staticmethod
-        def solutions(sqlcursor, mainrqlst, kwargs):
-            rqlhelper.compute_solutions(rqlst, {'eid': eid_func_map}, kwargs=kwargs)
-        class _rqlhelper:
-            @staticmethod
-            def annotate(rqlst):
-                rqlhelper.annotate(rqlst)
-            @staticmethod
-            def simplify(mainrqlst, needcopy=False):
-                rqlhelper.simplify(rqlst, needcopy)
-    rewriter = RQLRewriter(FakeQuerier, mock_object(user=(mock_object(eid=1))))
-    for v, snippets in snippets_map.items():
-        snippets_map[v] = [mock_object(snippet_rqlst=parse('Any X WHERE '+snippet).children[0],
-                                       expression='Any X WHERE '+snippet)
-                           for snippet in snippets]
-    rqlhelper.compute_solutions(rqlst.children[0], {'eid': eid_func_map}, kwargs=kwargs)
-    solutions = rqlst.children[0].solutions
-    rewriter.rewrite(rqlst.children[0], snippets_map.items(), solutions, kwargs)
-    test_vrefs(rqlst.children[0])
-    return rewriter.rewritten
-
-def test_vrefs(node):
-    vrefmap = {}
-    for vref in node.iget_nodes(nodes.VariableRef):
-        vrefmap.setdefault(vref.name, set()).add(vref)
-    for var in node.defined_vars.itervalues():
-        assert not (var.stinfo['references'] ^ vrefmap[var.name])
-        assert (var.stinfo['references'])
-
-class RQLRewriteTC(TestCase):
-    """a faire:
-
-    * optimisation: detecter les relations utilisees dans les rqlexpressions qui
-      sont presentes dans la requete de depart pour les reutiliser si possible
-
-    * "has_<ACTION>_permission" ?
-    """
-
-    def test_base_var(self):
-        card_constraint = ('X in_state S, U in_group G, P require_state S,'
-                           'P name "read", P require_group G')
-        rqlst = parse('Card C')
-        rewrite(rqlst, {'C': (card_constraint,)}, {})
-        self.failUnlessEqual(rqlst.as_string(),
-                             u"Any C WHERE C is Card, B eid %(D)s, "
-                             "EXISTS(C in_state A, B in_group E, F require_state A, "
-                             "F name 'read', F require_group E, A is State, E is CWGroup, F is CWPermission)")
-
-    def test_multiple_var(self):
-        card_constraint = ('X in_state S, U in_group G, P require_state S,'
-                           'P name "read", P require_group G')
-        affaire_constraints = ('X ref LIKE "PUBLIC%"', 'U in_group G, G name "public"')
-        kwargs = {'u':2}
-        rqlst = parse('Any S WHERE S documented_by C, C eid %(u)s')
-        rewrite(rqlst, {'C': (card_constraint,), 'S': affaire_constraints},
-                kwargs)
-        self.assertTextEquals(rqlst.as_string(),
-                             "Any S WHERE S documented_by C, C eid %(u)s, B eid %(D)s, "
-                             "EXISTS(C in_state A, B in_group E, F require_state A, "
-                             "F name 'read', F require_group E, A is State, E is CWGroup, F is CWPermission), "
-                             "(EXISTS(S ref LIKE 'PUBLIC%')) OR (EXISTS(B in_group G, G name 'public', G is CWGroup)), "
-                             "S is Affaire")
-        self.failUnless('D' in kwargs)
-
-    def test_or(self):
-        constraint = '(X identity U) OR (X in_state ST, CL identity U, CL in_state ST, ST name "subscribed")'
-        rqlst = parse('Any S WHERE S owned_by C, C eid %(u)s, S is in (CWUser, CWGroup)')
-        rewrite(rqlst, {'C': (constraint,)}, {'u':1})
-        self.failUnlessEqual(rqlst.as_string(),
-                             "Any S WHERE S owned_by C, C eid %(u)s, S is IN(CWUser, CWGroup), A eid %(B)s, "
-                             "EXISTS((C identity A) OR (C in_state D, E identity A, "
-                             "E in_state D, D name 'subscribed'), D is State, E is CWUser)")
-
-    def test_simplified_rqlst(self):
-        card_constraint = ('X in_state S, U in_group G, P require_state S,'
-                           'P name "read", P require_group G')
-        rqlst = parse('Any 2') # this is the simplified rql st for Any X WHERE X eid 12
-        rewrite(rqlst, {'2': (card_constraint,)}, {})
-        self.failUnlessEqual(rqlst.as_string(),
-                             u"Any 2 WHERE B eid %(C)s, "
-                             "EXISTS(2 in_state A, B in_group D, E require_state A, "
-                             "E name 'read', E require_group D, A is State, D is CWGroup, E is CWPermission)")
-
-    def test_optional_var(self):
-        card_constraint = ('X in_state S, U in_group G, P require_state S,'
-                           'P name "read", P require_group G')
-        rqlst = parse('Any A,C WHERE A documented_by C?')
-        rewrite(rqlst, {'C': (card_constraint,)}, {})
-        self.failUnlessEqual(rqlst.as_string(),
-                             "Any A,C WHERE A documented_by C?, A is Affaire "
-                             "WITH C BEING "
-                             "(Any C WHERE C in_state B, D in_group F, G require_state B, G name 'read', "
-                             "G require_group F, D eid %(A)s, C is Card)")
-        rqlst = parse('Any A,C,T WHERE A documented_by C?, C title T')
-        rewrite(rqlst, {'C': (card_constraint,)}, {})
-        self.failUnlessEqual(rqlst.as_string(),
-                             "Any A,C,T WHERE A documented_by C?, A is Affaire "
-                             "WITH C,T BEING "
-                             "(Any C,T WHERE C in_state B, D in_group F, G require_state B, G name 'read', "
-                             "G require_group F, C title T, D eid %(A)s, C is Card)")
-
-    def test_relation_optimization(self):
-        # since Card in_state State as monovalued cardinality, the in_state
-        # relation used in the rql expression can be ignored and S replaced by
-        # the variable from the incoming query
-        card_constraint = ('X in_state S, U in_group G, P require_state S,'
-                           'P name "read", P require_group G')
-        rqlst = parse('Card C WHERE C in_state STATE')
-        rewrite(rqlst, {'C': (card_constraint,)}, {})
-        self.failUnlessEqual(rqlst.as_string(),
-                             u"Any C WHERE C in_state STATE, C is Card, A eid %(B)s, "
-                             "EXISTS(A in_group D, E require_state STATE, "
-                             "E name 'read', E require_group D, D is CWGroup, E is CWPermission), "
-                             "STATE is State")
-
-    def test_unsupported_constraint_1(self):
-        # CWUser doesn't have require_permission
-        trinfo_constraint = ('X wf_info_for Y, Y require_permission P, P name "read"')
-        rqlst = parse('Any U,T WHERE U is CWUser, T wf_info_for U')
-        self.assertRaises(Unauthorized, rewrite, rqlst, {'T': (trinfo_constraint,)}, {})
-
-    def test_unsupported_constraint_2(self):
-        trinfo_constraint = ('X wf_info_for Y, Y require_permission P, P name "read"')
-        rqlst = parse('Any U,T WHERE U is CWUser, T wf_info_for U')
-        rewrite(rqlst, {'T': (trinfo_constraint, 'X wf_info_for Y, Y in_group G, G name "managers"')}, {})
-        self.failUnlessEqual(rqlst.as_string(),
-                             u"Any U,T WHERE U is CWUser, T wf_info_for U, "
-                             "EXISTS(U in_group B, B name 'managers', B is CWGroup), T is TrInfo")
-
-    def test_unsupported_constraint_3(self):
-        self.skip('raise unauthorized for now')
-        trinfo_constraint = ('X wf_info_for Y, Y require_permission P, P name "read"')
-        rqlst = parse('Any T WHERE T wf_info_for X')
-        rewrite(rqlst, {'T': (trinfo_constraint, 'X in_group G, G name "managers"')}, {})
-        self.failUnlessEqual(rqlst.as_string(),
-                             u'XXX dunno what should be generated')
-
-    def test_add_ambiguity_exists(self):
-        constraint = ('X concerne Y')
-        rqlst = parse('Affaire X')
-        rewrite(rqlst, {'X': (constraint,)}, {})
-        self.failUnlessEqual(rqlst.as_string(),
-                             u"Any X WHERE X is Affaire, (((EXISTS(X concerne A, A is Division)) OR (EXISTS(X concerne D, D is SubDivision))) OR (EXISTS(X concerne C, C is Societe))) OR (EXISTS(X concerne B, B is Note))")
-
-    def test_add_ambiguity_outerjoin(self):
-        constraint = ('X concerne Y')
-        rqlst = parse('Any X,C WHERE X? documented_by C')
-        rewrite(rqlst, {'X': (constraint,)}, {})
-        # ambiguity are kept in the sub-query, no need to be resolved using OR
-        self.failUnlessEqual(rqlst.as_string(),
-                             u"Any X,C WHERE X? documented_by C, C is Card WITH X BEING (Any X WHERE X concerne A, X is Affaire)")
-
-
-
-if __name__ == '__main__':
-    unittest_main()
--- a/server/test/unittest_security.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/server/test/unittest_security.py	Thu Sep 17 15:16:53 2009 +0200
@@ -27,10 +27,10 @@
 
     def test_check_read_access(self):
         rql = u'Personne U where U nom "managers"'
-        rqlst = self.repo.querier._rqlhelper.parse(rql).children[0]
+        rqlst = self.repo.vreg.rqlhelper.parse(rql).children[0]
         origgroups = self.schema['Personne'].get_groups('read')
         self.schema['Personne'].set_groups('read', ('users', 'managers'))
-        self.repo.querier._rqlhelper.compute_solutions(rqlst)
+        self.repo.vreg.rqlhelper.compute_solutions(rqlst)
         solution = rqlst.solutions[0]
         check_read_access(self.schema, self.session.user, rqlst, solution)
         cnx = self.login('anon')
--- a/server/test/unittest_ssplanner.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/server/test/unittest_ssplanner.py	Thu Sep 17 15:16:53 2009 +0200
@@ -18,7 +18,7 @@
 
     def setUp(self):
         BasePlannerTC.setUp(self)
-        self.planner = SSPlanner(self.o.schema, self.o._rqlhelper)
+        self.planner = SSPlanner(self.o.schema, self.repo.vreg.rqlhelper)
         self.system = self.o._repo.system_source
 
     def tearDown(self):
--- a/sobjects/test/unittest_email.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/sobjects/test/unittest_email.py	Thu Sep 17 15:16:53 2009 +0200
@@ -5,6 +5,8 @@
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
 """
+
+from cubicweb import Unauthorized
 from cubicweb.devtools.testlib import CubicWebTC
 
 class EmailAddressHooksTC(CubicWebTC):
@@ -30,6 +32,24 @@
         self.assertEquals(self.execute('Any A WHERE U use_email X, U login "admin", X address A')[0][0],
                           'admin@logilab.fr')
 
+    def test_cardinality_check(self):
+        email1 = self.execute('INSERT EmailAddress E: E address "client@client.com", U use_email E WHERE U login "admin"')[0][0]
+        self.commit()
+        self.execute('SET U primary_email E WHERE U login "anon", E address "client@client.com"')
+        self.commit()
+        rset = self.execute('Any X WHERE X use_email E, E eid %(e)s', {'e': email1})
+        self.failIf(rset.rowcount != 1, rset)
+
+    def test_security_check(self):
+        self.create_user('toto')
+        email1 = self.execute('INSERT EmailAddress E: E address "client@client.com", U use_email E WHERE U login "admin"')[0][0]
+        self.commit()
+        cnx = self.login('toto')
+        cu = cnx.cursor()
+        cu.execute('SET U primary_email E WHERE E eid %(e)s, U login "toto"',
+                   {'e': email1})
+        self.assertRaises(Unauthorized, cnx.commit)
+
 
 if __name__ == '__main__':
     from logilab.common.testlib import unittest_main
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/data/rewrite/bootstrap_cubes	Thu Sep 17 15:16:53 2009 +0200
@@ -0,0 +1,1 @@
+card, person
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/data/rewrite/schema.py	Thu Sep 17 15:16:53 2009 +0200
@@ -0,0 +1,42 @@
+from yams.buildobjs import EntityType, RelationDefinition, String, SubjectRelation
+from cubicweb.schema import ERQLExpression
+
+class Affaire(EntityType):
+    permissions = {
+        'read':   ('managers',
+                   ERQLExpression('X owned_by U'), ERQLExpression('X concerne S?, S owned_by U')),
+        'add':    ('managers', ERQLExpression('X concerne S, S owned_by U')),
+        'update': ('managers', 'owners', ERQLExpression('X in_state S, S name in ("pitetre", "en cours")')),
+        'delete': ('managers', 'owners', ERQLExpression('X concerne S, S owned_by U')),
+        }
+    ref = String(fulltextindexed=True, indexed=True,
+                 constraints=[SizeConstraint(16)])
+    documented_by = SubjectRelation('Card')
+    concerne = SubjectRelation(('Societe', 'Note'))
+
+
+class Societe(EntityType):
+    permissions = {
+        'read': ('managers', 'users', 'guests'),
+        'update': ('managers', 'owners', ERQLExpression('U login L, X nom L')),
+        'delete': ('managers', 'owners', ERQLExpression('U login L, X nom L')),
+        'add': ('managers', 'users',)
+        }
+
+
+class Division(Societe):
+    __specializes_schema__ = True
+
+
+class Note(EntityType):
+    pass
+
+
+class require_permission(RelationDefinition):
+    subject = ('Card', 'Note', 'Person')
+    object = 'CWPermission'
+
+
+class require_state(RelationDefinition):
+    subject = 'CWPermission'
+    object = 'State'
--- a/test/unittest_entity.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/test/unittest_entity.py	Thu Sep 17 15:16:53 2009 +0200
@@ -9,19 +9,13 @@
 
 from datetime import datetime
 
-from cubicweb import Binary
+from cubicweb import Binary, Unauthorized
 from cubicweb.devtools.testlib import CubicWebTC
 from cubicweb.common.mttransforms import HAS_TAL
+from cubicweb.entities import fetch_config
 
 class EntityTC(CubicWebTC):
 
-##     def setup_database(self):
-##         self.add_entity('Personne', nom=u'di mascio', prenom=u'adrien')
-##         self.add_entity('Task', title=u'fait ca !', description=u'et plus vite', start=now())
-##         self.add_entity('Tag', name=u'x')
-##         self.add_entity('Link', title=u'perdu', url=u'http://www.perdu.com',
-##                         embed=False)
-
     def test_boolean_value(self):
         e = self.vreg['etypes'].etype_class('CWUser')(self.request())
         self.failUnless(e)
@@ -179,7 +173,6 @@
             Societe.fetch_attrs = sfetch_attrs
 
     def test_related_rql(self):
-        from cubicweb.entities import fetch_config
         Personne = self.vreg['etypes'].etype_class('Personne')
         Note = self.vreg['etypes'].etype_class('Note')
         self.failUnless(issubclass(self.vreg['etypes'].etype_class('SubNote'), Note))
@@ -194,7 +187,40 @@
         self.assertEquals(p.related_rql('evaluee'),
                           'Any X,AA ORDERBY Z DESC WHERE X modification_date Z, E eid %(x)s, E evaluee X, X modification_date AA')
 
-    def test_entity_unrelated(self):
+    def test_unrelated_rql_security_1(self):
+        user = self.request().user
+        rql = user.unrelated_rql('use_email', 'EmailAddress', 'subject')[0]
+        self.assertEquals(rql, 'Any O,AA,AB,AC ORDERBY AC DESC '
+                          'WHERE NOT S use_email O, S eid %(x)s, O is EmailAddress, O address AA, O alias AB, O modification_date AC')
+        self.create_user('toto')
+        self.login('toto')
+        user = self.request().user
+        rql = user.unrelated_rql('use_email', 'EmailAddress', 'subject')[0]
+        self.assertEquals(rql, 'Any O,AA,AB,AC ORDERBY AC DESC '
+                          'WHERE NOT S use_email O, S eid %(x)s, O is EmailAddress, O address AA, O alias AB, O modification_date AC')
+        user = self.execute('Any X WHERE X login "admin"').get_entity(0, 0)
+        self.assertRaises(Unauthorized, user.unrelated_rql, 'use_email', 'EmailAddress', 'subject')
+        self.login('anon')
+        user = self.request().user
+        self.assertRaises(Unauthorized, user.unrelated_rql, 'use_email', 'EmailAddress', 'subject')
+
+    def test_unrelated_rql_security_2(self):
+        email = self.execute('INSERT EmailAddress X: X address "hop"').get_entity(0, 0)
+        rql = email.unrelated_rql('use_email', 'CWUser', 'object')[0]
+        self.assertEquals(rql, 'Any S,AA,AB,AC,AD ORDERBY AA ASC '
+                          'WHERE NOT S use_email O, O eid %(x)s, S is CWUser, S login AA, S firstname AB, S surname AC, S modification_date AD')
+        #rql = email.unrelated_rql('use_email', 'Person', 'object')[0]
+        #self.assertEquals(rql, '')
+        self.login('anon')
+        email = self.execute('Any X WHERE X eid %(x)s', {'x': email.eid}, 'x').get_entity(0, 0)
+        rql = email.unrelated_rql('use_email', 'CWUser', 'object')[0]
+        self.assertEquals(rql, 'Any S,AA,AB,AC,AD ORDERBY AA '
+                          'WHERE NOT S use_email O, O eid %(x)s, S is CWUser, S login AA, S firstname AB, S surname AC, S modification_date AD, '
+                          'A eid %(B)s, EXISTS(S identity A, NOT A in_group C, C name "guests", C is CWGroup)')
+        #rql = email.unrelated_rql('use_email', 'Person', 'object')[0]
+        #self.assertEquals(rql, '')
+
+    def test_unrelated_base(self):
         p = self.add_entity('Personne', nom=u'di mascio', prenom=u'adrien')
         e = self.add_entity('Tag', name=u'x')
         related = [r.eid for r in e.tags]
@@ -206,14 +232,40 @@
         unrelated = [r[0] for r in e.unrelated('tags', 'Personne', 'subject')]
         self.failIf(p.eid in unrelated)
 
-    def test_entity_unrelated_limit(self):
+    def test_unrelated_limit(self):
         e = self.add_entity('Tag', name=u'x')
         self.add_entity('Personne', nom=u'di mascio', prenom=u'adrien')
-        self.add_entity('Personne', nom=u'di mascio', prenom=u'gwen')
+        self.add_entity('Personne', nom=u'thenault', prenom=u'sylvain')
         self.assertEquals(len(e.unrelated('tags', 'Personne', 'subject', limit=1)),
                           1)
 
-    def test_new_entity_unrelated(self):
+    def test_unrelated_security(self):
+        email = self.execute('INSERT EmailAddress X: X address "hop"').get_entity(0, 0)
+        rset = email.unrelated('use_email', 'CWUser', 'object')
+        self.assertEquals([x.login for x in rset.entities()], [u'admin', u'anon'])
+        user = self.request().user
+        rset = user.unrelated('use_email', 'EmailAddress', 'subject')
+        self.assertEquals([x.address for x in rset.entities()], [u'hop'])
+        self.create_user('toto')
+        self.login('toto')
+        email = self.execute('Any X WHERE X eid %(x)s', {'x': email.eid}, 'x').get_entity(0, 0)
+        rset = email.unrelated('use_email', 'CWUser', 'object')
+        self.assertEquals([x.login for x in rset.entities()], ['toto'])
+        user = self.request().user
+        rset = user.unrelated('use_email', 'EmailAddress', 'subject')
+        self.assertEquals([x.address for x in rset.entities()], ['hop'])
+        user = self.execute('Any X WHERE X login "admin"').get_entity(0, 0)
+        rset = user.unrelated('use_email', 'EmailAddress', 'subject')
+        self.assertEquals([x.address for x in rset.entities()], [])
+        self.login('anon')
+        email = self.execute('Any X WHERE X eid %(x)s', {'x': email.eid}, 'x').get_entity(0, 0)
+        rset = email.unrelated('use_email', 'CWUser', 'object')
+        self.assertEquals([x.login for x in rset.entities()], [])
+        user = self.request().user
+        rset = user.unrelated('use_email', 'EmailAddress', 'subject')
+        self.assertEquals([x.address for x in rset.entities()], [])
+
+    def test_unrelated_new_entity(self):
         e = self.vreg['etypes'].etype_class('CWUser')(self.request())
         unrelated = [r[0] for r in e.unrelated('in_group', 'CWGroup', 'subject')]
         # should be default groups but owners, i.e. managers, users, guests
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/unittest_rqlrewrite.py	Thu Sep 17 15:16:53 2009 +0200
@@ -0,0 +1,193 @@
+"""
+
+:organization: Logilab
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.
+:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
+:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
+"""
+from logilab.common.testlib import unittest_main, TestCase
+from logilab.common.testlib import mock_object
+
+from rql import parse, nodes, RQLHelper
+
+from cubicweb import Unauthorized
+from cubicweb.rqlrewrite import RQLRewriter
+from cubicweb.devtools import repotest, TestServerConfiguration
+
+config = TestServerConfiguration('data/rewrite')
+config.bootstrap_cubes()
+schema = config.load_schema()
+schema.add_relation_def(mock_object(subject='Card', name='in_state', object='State', cardinality='1*'))
+
+rqlhelper = RQLHelper(schema, special_relations={'eid': 'uid',
+                                                 'has_text': 'fti'})
+
+def setup_module(*args):
+    repotest.do_monkey_patch()
+
+def teardown_module(*args):
+    repotest.undo_monkey_patch()
+
+def eid_func_map(eid):
+    return {1: 'CWUser',
+            2: 'Card'}[eid]
+
+def rewrite(rqlst, snippets_map, kwargs):
+    class FakeVReg:
+        schema = schema
+        @staticmethod
+        def solutions(sqlcursor, mainrqlst, kwargs):
+            rqlhelper.compute_solutions(rqlst, {'eid': eid_func_map}, kwargs=kwargs)
+        class rqlhelper:
+            @staticmethod
+            def annotate(rqlst):
+                rqlhelper.annotate(rqlst)
+            @staticmethod
+            def simplify(mainrqlst, needcopy=False):
+                rqlhelper.simplify(rqlst, needcopy)
+    rewriter = RQLRewriter(mock_object(vreg=FakeVReg, user=(mock_object(eid=1))))
+    for v, snippets in snippets_map.items():
+        snippets_map[v] = [mock_object(snippet_rqlst=parse('Any X WHERE '+snippet).children[0],
+                                       expression='Any X WHERE '+snippet)
+                           for snippet in snippets]
+    rqlhelper.compute_solutions(rqlst.children[0], {'eid': eid_func_map}, kwargs=kwargs)
+    solutions = rqlst.children[0].solutions
+    rewriter.rewrite(rqlst.children[0], snippets_map.items(), solutions, kwargs)
+    test_vrefs(rqlst.children[0])
+    return rewriter.rewritten
+
+def test_vrefs(node):
+    vrefmap = {}
+    for vref in node.iget_nodes(nodes.VariableRef):
+        vrefmap.setdefault(vref.name, set()).add(vref)
+    for var in node.defined_vars.itervalues():
+        assert not (var.stinfo['references'] ^ vrefmap[var.name])
+        assert (var.stinfo['references'])
+
+class RQLRewriteTC(TestCase):
+    """a faire:
+
+    * optimisation: detecter les relations utilisees dans les rqlexpressions qui
+      sont presentes dans la requete de depart pour les reutiliser si possible
+
+    * "has_<ACTION>_permission" ?
+    """
+
+    def test_base_var(self):
+        card_constraint = ('X in_state S, U in_group G, P require_state S,'
+                           'P name "read", P require_group G')
+        rqlst = parse('Card C')
+        rewrite(rqlst, {('C', 'X'): (card_constraint,)}, {})
+        self.failUnlessEqual(rqlst.as_string(),
+                             u"Any C WHERE C is Card, B eid %(D)s, "
+                             "EXISTS(C in_state A, B in_group E, F require_state A, "
+                             "F name 'read', F require_group E, A is State, E is CWGroup, F is CWPermission)")
+
+    def test_multiple_var(self):
+        card_constraint = ('X in_state S, U in_group G, P require_state S,'
+                           'P name "read", P require_group G')
+        affaire_constraints = ('X ref LIKE "PUBLIC%"', 'U in_group G, G name "public"')
+        kwargs = {'u':2}
+        rqlst = parse('Any S WHERE S documented_by C, C eid %(u)s')
+        rewrite(rqlst, {('C', 'X'): (card_constraint,), ('S', 'X'): affaire_constraints},
+                kwargs)
+        self.assertTextEquals(rqlst.as_string(),
+                             "Any S WHERE S documented_by C, C eid %(u)s, B eid %(D)s, "
+                             "EXISTS(C in_state A, B in_group E, F require_state A, "
+                             "F name 'read', F require_group E, A is State, E is CWGroup, F is CWPermission), "
+                             "(EXISTS(S ref LIKE 'PUBLIC%')) OR (EXISTS(B in_group G, G name 'public', G is CWGroup)), "
+                             "S is Affaire")
+        self.failUnless('D' in kwargs)
+
+    def test_or(self):
+        constraint = '(X identity U) OR (X in_state ST, CL identity U, CL in_state ST, ST name "subscribed")'
+        rqlst = parse('Any S WHERE S owned_by C, C eid %(u)s, S is in (CWUser, CWGroup)')
+        rewrite(rqlst, {('C', 'X'): (constraint,)}, {'u':1})
+        self.failUnlessEqual(rqlst.as_string(),
+                             "Any S WHERE S owned_by C, C eid %(u)s, S is IN(CWUser, CWGroup), A eid %(B)s, "
+                             "EXISTS((C identity A) OR (C in_state D, E identity A, "
+                             "E in_state D, D name 'subscribed'), D is State, E is CWUser)")
+
+    def test_simplified_rqlst(self):
+        card_constraint = ('X in_state S, U in_group G, P require_state S,'
+                           'P name "read", P require_group G')
+        rqlst = parse('Any 2') # this is the simplified rql st for Any X WHERE X eid 12
+        rewrite(rqlst, {('2', 'X'): (card_constraint,)}, {})
+        self.failUnlessEqual(rqlst.as_string(),
+                             u"Any 2 WHERE B eid %(C)s, "
+                             "EXISTS(2 in_state A, B in_group D, E require_state A, "
+                             "E name 'read', E require_group D, A is State, D is CWGroup, E is CWPermission)")
+
+    def test_optional_var(self):
+        card_constraint = ('X in_state S, U in_group G, P require_state S,'
+                           'P name "read", P require_group G')
+        rqlst = parse('Any A,C WHERE A documented_by C?')
+        rewrite(rqlst, {('C', 'X'): (card_constraint,)}, {})
+        self.failUnlessEqual(rqlst.as_string(),
+                             "Any A,C WHERE A documented_by C?, A is Affaire "
+                             "WITH C BEING "
+                             "(Any C WHERE C in_state B, D in_group F, G require_state B, G name 'read', "
+                             "G require_group F, D eid %(A)s, C is Card)")
+        rqlst = parse('Any A,C,T WHERE A documented_by C?, C title T')
+        rewrite(rqlst, {('C', 'X'): (card_constraint,)}, {})
+        self.failUnlessEqual(rqlst.as_string(),
+                             "Any A,C,T WHERE A documented_by C?, A is Affaire "
+                             "WITH C,T BEING "
+                             "(Any C,T WHERE C in_state B, D in_group F, G require_state B, G name 'read', "
+                             "G require_group F, C title T, D eid %(A)s, C is Card)")
+
+    def test_relation_optimization(self):
+        # since Card in_state State as monovalued cardinality, the in_state
+        # relation used in the rql expression can be ignored and S replaced by
+        # the variable from the incoming query
+        card_constraint = ('X in_state S, U in_group G, P require_state S,'
+                           'P name "read", P require_group G')
+        rqlst = parse('Card C WHERE C in_state STATE')
+        rewrite(rqlst, {('C', 'X'): (card_constraint,)}, {})
+        self.failUnlessEqual(rqlst.as_string(),
+                             u"Any C WHERE C in_state STATE, C is Card, A eid %(B)s, "
+                             "EXISTS(A in_group D, E require_state STATE, "
+                             "E name 'read', E require_group D, D is CWGroup, E is CWPermission), "
+                             "STATE is State")
+
+    def test_unsupported_constraint_1(self):
+        # CWUser doesn't have require_permission
+        trinfo_constraint = ('X wf_info_for Y, Y require_permission P, P name "read"')
+        rqlst = parse('Any U,T WHERE U is CWUser, T wf_info_for U')
+        self.assertRaises(Unauthorized, rewrite, rqlst, {('T', 'X'): (trinfo_constraint,)}, {})
+
+    def test_unsupported_constraint_2(self):
+        trinfo_constraint = ('X wf_info_for Y, Y require_permission P, P name "read"')
+        rqlst = parse('Any U,T WHERE U is CWUser, T wf_info_for U')
+        rewrite(rqlst, {('T', 'X'): (trinfo_constraint, 'X wf_info_for Y, Y in_group G, G name "managers"')}, {})
+        self.failUnlessEqual(rqlst.as_string(),
+                             u"Any U,T WHERE U is CWUser, T wf_info_for U, "
+                             "EXISTS(U in_group B, B name 'managers', B is CWGroup), T is TrInfo")
+
+    def test_unsupported_constraint_3(self):
+        self.skip('raise unauthorized for now')
+        trinfo_constraint = ('X wf_info_for Y, Y require_permission P, P name "read"')
+        rqlst = parse('Any T WHERE T wf_info_for X')
+        rewrite(rqlst, {('T', 'X'): (trinfo_constraint, 'X in_group G, G name "managers"')}, {})
+        self.failUnlessEqual(rqlst.as_string(),
+                             u'XXX dunno what should be generated')
+
+    def test_add_ambiguity_exists(self):
+        constraint = ('X concerne Y')
+        rqlst = parse('Affaire X')
+        rewrite(rqlst, {('X', 'X'): (constraint,)}, {})
+        self.failUnlessEqual(rqlst.as_string(),
+                             u"Any X WHERE X is Affaire, ((EXISTS(X concerne A, A is Division)) OR (EXISTS(X concerne C, C is Societe))) OR (EXISTS(X concerne B, B is Note))")
+
+    def test_add_ambiguity_outerjoin(self):
+        constraint = ('X concerne Y')
+        rqlst = parse('Any X,C WHERE X? documented_by C')
+        rewrite(rqlst, {('X', 'X'): (constraint,)}, {})
+        # ambiguity are kept in the sub-query, no need to be resolved using OR
+        self.failUnlessEqual(rqlst.as_string(),
+                             u"Any X,C WHERE X? documented_by C, C is Card WITH X BEING (Any X WHERE X concerne A, X is Affaire)")
+
+
+
+if __name__ == '__main__':
+    unittest_main()
--- a/test/unittest_utils.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/test/unittest_utils.py	Thu Sep 17 15:16:53 2009 +0200
@@ -8,7 +8,11 @@
 
 from logilab.common.testlib import TestCase, unittest_main
 
-from cubicweb.utils import make_uid, UStringIO, SizeConstrainedList
+import simplejson
+import decimal
+import datetime
+
+from cubicweb.utils import make_uid, UStringIO, SizeConstrainedList, CubicWebJsonEncoder
 
 
 class MakeUidTC(TestCase):
@@ -48,6 +52,24 @@
             l.extend(extension)
             yield self.assertEquals, l, expected
 
+class JSONEncoerTests(TestCase):
+
+    def encode(self, value):
+        return simplejson.dumps(value, cls=CubicWebJsonEncoder)
+
+    def test_encoding_dates(self):
+        self.assertEquals(self.encode(datetime.datetime(2009, 9, 9, 20, 30)),
+                          '"2009/09/09 20:30:00"')
+        self.assertEquals(self.encode(datetime.date(2009, 9, 9)),
+                          '"2009/09/09"')
+        self.assertEquals(self.encode(datetime.time(20, 30)),
+                          '"20:30:00"')
+
+    def test_encoding_decimal(self):
+        self.assertEquals(self.encode(decimal.Decimal('1.2')), '1.2')
+
+    def test_encoding_unknown_stuff(self):
+        self.assertEquals(self.encode(TestCase), 'null')
 
 if __name__ == '__main__':
     unittest_main()
--- a/utils.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/utils.py	Thu Sep 17 15:16:53 2009 +0200
@@ -12,10 +12,12 @@
 import locale
 from md5 import md5
 import sys
+import datetime as pydatetime
 from datetime import datetime, timedelta, date
 from time import time, mktime
 from random import randint, seed
 from calendar import monthrange
+import decimal
 
 # initialize random seed from current time
 seed()
@@ -263,7 +265,6 @@
         w = self.write
         # 1/ variable declaration if any
         if self.jsvars:
-            from simplejson import dumps
             w(u'<script type="text/javascript"><!--//--><![CDATA[//><!--\n')
             for var, value in self.jsvars:
                 w(u'%s = %s;\n' % (var, dumps(value)))
@@ -355,3 +356,27 @@
         return False
     __answer[0] = True
     return True
+
+try:
+    # may not be there is cubicweb-web not there
+    from simplejson import JSONEncoder, dumps
+except ImportError:
+    pass
+else:
+    class CubicWebJsonEncoder(JSONEncoder):
+        """define a simplejson encoder to be able to encode yams std types"""
+        def default(self, obj):
+            if isinstance(obj, datetime):
+                return obj.strftime('%Y/%m/%d %H:%M:%S')
+            elif isinstance(obj, date):
+                return obj.strftime('%Y/%m/%d')
+            elif isinstance(obj, pydatetime.time):
+                return obj.strftime('%H:%M:%S')
+            elif isinstance(obj, decimal.Decimal):
+                return float(obj)
+            try:
+                return simplejson.JSONEncoder.default(self, obj)
+            except TypeError:
+                # we never ever want to fail because of an unknown type,
+                # just return None in those cases.
+                return None
--- a/web/action.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/web/action.py	Thu Sep 17 15:16:53 2009 +0200
@@ -91,8 +91,7 @@
     def url(self):
         current_entity = self.rset.get_entity(self.row or 0, self.col or 0)
         linkto = '%s:%s:%s' % (self.rtype, current_entity.eid, target(self))
-        return self.build_url(vid='creation', etype=self.etype,
-                              __linkto=linkto,
+        return self.build_url('add/%s' % self.etype, __linkto=linkto,
                               __redirectpath=current_entity.rest_path(), # should not be url quoted!
                               __redirectvid=self.req.form.get('__redirectvid', ''))
 
--- a/web/data/cubicweb.edition.js	Tue Sep 15 15:01:41 2009 +0200
+++ b/web/data/cubicweb.edition.js	Thu Sep 17 15:16:53 2009 +0200
@@ -354,7 +354,7 @@
     // Success
     if (result[0]) {
 	if (onsuccess) {
-             onsuccess(result[1], formid);
+             onsuccess(result, formid);
 	} else {
 	    document.location.href = result[1];
 	}
--- a/web/formfields.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/web/formfields.py	Thu Sep 17 15:16:53 2009 +0200
@@ -438,9 +438,16 @@
 
 
 class RelationField(Field):
-    def __init__(self, **kwargs):
-        kwargs.setdefault('sort', False)
-        super(RelationField, self).__init__(**kwargs)
+    # XXX (syt): iirc, we originaly don't sort relation vocabulary since we want
+    # to let entity.unrelated_rql control this, usually to get most recently
+    # modified entities in the select box instead of by alphabetical order. Now,
+    # we first use unrelated_rql to get the vocabulary, which may be limited
+    # (hence we get the latest modified entities) and we can sort here for
+    # better readability
+    #
+    # def __init__(self, **kwargs):
+    #     kwargs.setdefault('sort', False)
+    #     super(RelationField, self).__init__(**kwargs)
 
     @staticmethod
     def fromcardinality(card, **kwargs):
@@ -506,6 +513,7 @@
         help = rschema.rproperty(targetschema, eschema, 'description')
     kwargs['required'] = card in '1+'
     kwargs['name'] = rschema.type
+    kwargs['label'] = (eschema.type, rschema.type)
     kwargs.setdefault('help', help)
     if rschema.is_final():
         if skip_meta_attr and rschema in eschema.meta_attributes():
--- a/web/request.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/web/request.py	Thu Sep 17 15:16:53 2009 +0200
@@ -122,7 +122,8 @@
         self.set_default_language(vreg)
 
     def set_language(self, lang):
-        self._ = self.__ = self.translations[lang]
+        gettext, self.pgettext = self.translations[lang]
+        self._ = self.__ = gettext
         self.lang = lang
         self.cnx.set_session_props(lang=lang)
         self.debug('request language: %s', lang)
--- a/web/test/unittest_application.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/web/test/unittest_application.py	Thu Sep 17 15:16:53 2009 +0200
@@ -69,14 +69,17 @@
 
 
     def test_from_controller(self):
+        self.req.vreg['controllers'] = {'view': 1, 'login': 1}
         self.assertEquals(self.req.from_controller(), 'view')
         req = FakeRequest(url='project?vid=list')
+        req.vreg['controllers'] = {'view': 1, 'login': 1}
         # this assertion is just to make sure that relative_path can be
         # correctly computed as it is used in from_controller()
         self.assertEquals(req.relative_path(False), 'project')
         self.assertEquals(req.from_controller(), 'view')
         # test on a valid non-view controller
         req = FakeRequest(url='login?x=1&y=2')
+        req.vreg['controllers'] = {'view': 1, 'login': 1}
         self.assertEquals(req.relative_path(False), 'login')
         self.assertEquals(req.from_controller(), 'login')
 
--- a/web/test/unittest_pdf.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/web/test/unittest_pdf.py	Thu Sep 17 15:16:53 2009 +0200
@@ -31,4 +31,6 @@
         reference = open(osp.join(DATADIR, 'sample1.pdf'), 'r').read()
         output = pdftmp.read()
         # XXX almost equals due to ID, creation date, so it seems to fail
-        self.assertTextEquals(output, reference)
+        self.assertEquals( len(output), len(reference) )
+        # cut begin & end 'cause they contain variyng data
+        self.assertTextEquals(output[150:1500], reference[150:1500])
--- a/web/uicfg.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/web/uicfg.py	Thu Sep 17 15:16:53 2009 +0200
@@ -166,11 +166,11 @@
             else:
                 self.setdefault(eschema, 'application')
 
-
 indexview_etype_section = InitializableDict(EmailAddress='subobject',
                                             CWUser='system',
                                             CWGroup='system',
                                             CWPermission='system',
+                                            CWCache='system',
                                             BaseTransition='hidden',
                                             )
 
--- a/web/views/actions.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/web/views/actions.py	Thu Sep 17 15:16:53 2009 +0200
@@ -32,10 +32,10 @@
         # if user has no update right but it can modify some relation,
         # display action anyway
         for dummy in AutomaticEntityForm.esrelations_by_category(
-            entity, 'generic', 'add'):
+            entity, 'generic', 'add', strict=True):
             return 1
         for rschema, targetschemas, role in AutomaticEntityForm.erelations_by_category(
-            entity, ('primary', 'secondary'), 'add'):
+            entity, ('primary', 'secondary'), 'add', strict=True):
             if not rschema.is_final():
                 return 1
         return 0
@@ -284,7 +284,7 @@
                         yield rschema, teschema, role
 
     def linkto_url(self, entity, rtype, etype, target):
-        return self.build_url(vid='creation', etype=etype,
+        return self.build_url('add/%s' % etype,
                               __linkto='%s:%s:%s' % (rtype, entity.eid, target),
                               __redirectpath=entity.rest_path(), # should not be url quoted!
                               __redirectvid=self.req.form.get('vid', ''))
--- a/web/views/autoform.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/web/views/autoform.py	Thu Sep 17 15:16:53 2009 +0200
@@ -48,9 +48,12 @@
 
     @classmethod
     def erelations_by_category(cls, entity, categories=None, permission=None,
-                               rtags=None):
+                               rtags=None, strict=False):
         """return a list of (relation schema, target schemas, role) matching
         categories and permission
+
+        `strict`:
+          bool telling if having local role is enough (strict = False) or not
         """
         if categories is not None:
             if not isinstance(categories, (list, tuple, set, frozenset)):
@@ -65,6 +68,7 @@
             eid = entity.eid
         else:
             eid = None
+            strict = False
         for rschema, targetschemas, role in eschema.relation_definitions(True):
             # check category first, potentially lower cost than checking
             # permission which may imply rql queries
@@ -84,7 +88,7 @@
                     if not rschema.has_perm(entity.req, permission, eid):
                         continue
                 elif role == 'subject':
-                    if not ((eid is None and rschema.has_local_role(permission)) or
+                    if not ((not strict and rschema.has_local_role(permission)) or
                             rschema.has_perm(entity.req, permission, fromeid=eid)):
                         continue
                     # on relation with cardinality 1 or ?, we need delete perm as well
@@ -96,7 +100,7 @@
                                                  toeid=entity.related(rschema.type, role)[0][0])):
                         continue
                 elif role == 'object':
-                    if not ((eid is None and rschema.has_local_role(permission)) or
+                    if not ((not strict and rschema.has_local_role(permission)) or
                             rschema.has_perm(entity.req, permission, toeid=eid)):
                         continue
                     # on relation with cardinality 1 or ?, we need delete perm as well
@@ -110,7 +114,8 @@
             yield (rschema, targetschemas, role)
 
     @classmethod
-    def esrelations_by_category(cls, entity, categories=None, permission=None):
+    def esrelations_by_category(cls, entity, categories=None, permission=None,
+                                strict=False):
         """filter out result of relations_by_category(categories, permission) by
         removing final relations
 
@@ -118,7 +123,7 @@
         """
         result = []
         for rschema, ttypes, role in cls.erelations_by_category(
-            entity, categories, permission):
+            entity, categories, permission, strict=strict):
             if rschema.is_final():
                 continue
             result.append((rschema.display_name(entity.req, role), rschema, role))
@@ -196,14 +201,15 @@
         return self.erelations_by_category(self.edited_entity, True, 'add',
                                            self.rinlined)
 
-    def srelations_by_category(self, categories=None, permission=None):
+    def srelations_by_category(self, categories=None, permission=None,
+                               strict=False):
         """filter out result of relations_by_category(categories, permission) by
         removing final relations
 
         return a sorted list of (relation's label, relation'schema, role)
         """
         return self.esrelations_by_category(self.edited_entity, categories,
-                                           permission)
+                                           permission, strict=strict)
 
     def action(self):
         """return the form's action attribute. Default to validateform if not
@@ -235,7 +241,8 @@
         """
         entity = self.edited_entity
         pending_deletes = self.req.get_pending_deletes(entity.eid)
-        for label, rschema, role in self.srelations_by_category('generic', 'add'):
+        for label, rschema, role in self.srelations_by_category('generic', 'add',
+                                                                strict=True):
             relatedrset = entity.related(rschema, role, limit=self.related_limit)
             if rschema.has_perm(self.req, 'delete'):
                 toggleable_rel_link_func = editforms.toggleable_relation_link
--- a/web/views/basecontrollers.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/web/views/basecontrollers.py	Thu Sep 17 15:16:53 2009 +0200
@@ -17,9 +17,8 @@
 from logilab.common.decorators import cached
 
 from cubicweb import NoSelectableObject, ValidationError, ObjectNotFound, typed_eid
-from cubicweb.utils import strptime
+from cubicweb.utils import strptime, CubicWebJsonEncoder
 from cubicweb.selectors import yes, match_user_groups
-from cubicweb.view import STRICT_DOCTYPE, STRICT_DOCTYPE_NOEXT
 from cubicweb.common.mail import format_mail
 from cubicweb.web import ExplicitLogin, Redirect, RemoteCallFailed, json_dumps
 from cubicweb.web.controller import Controller
@@ -181,48 +180,54 @@
             break
     return (foreid, ex.errors)
 
+
 def _validate_form(req, vreg):
     # XXX should use the `RemoteCallFailed` mechanism
     try:
         ctrl = vreg['controllers'].select('edit', req=req)
     except NoSelectableObject:
-        return (False, {None: req._('not authorized')})
+        return (False, {None: req._('not authorized')}, None)
     try:
         ctrl.publish(None)
     except ValidationError, ex:
-        return (False, _validation_error(req, ex))
+        return (False, _validation_error(req, ex), ctrl._edited_entity)
     except Redirect, ex:
+        if ctrl._edited_entity:
+            ctrl._edited_entity.complete()
         try:
             req.cnx.commit() # ValidationError may be raise on commit
         except ValidationError, ex:
-            return (False, _validation_error(req, ex))
+            return (False, _validation_error(req, ex), ctrl._edited_entity)
         else:
-            return (True, ex.location)
+            return (True, ex.location, ctrl._edited_entity)
     except Exception, ex:
         req.cnx.rollback()
         req.exception('unexpected error while validating form')
-        return (False, req._(str(ex).decode('utf-8')))
-    return (False, '???')
+        return (False, req._(str(ex).decode('utf-8')), ctrl._edited_entity)
+    return (False, '???', None)
 
 
 class FormValidatorController(Controller):
     id = 'validateform'
 
-    def response(self, domid, status, args):
+    def response(self, domid, status, args, entity):
+        callback = str(self.req.form.get('__onsuccess', 'null'))
+        errback = str(self.req.form.get('__onfailure', 'null'))
         self.req.set_content_type('text/html')
-        jsargs = simplejson.dumps( (status, args) )
+        jsargs = simplejson.dumps((status, args, entity), cls=CubicWebJsonEncoder)
         return """<script type="text/javascript">
- window.parent.handleFormValidationResponse('%s', null, null, %s);
-</script>""" %  (domid, jsargs)
+ wp = window.parent;
+ window.parent.handleFormValidationResponse('%s', %s, %s, %s);
+</script>""" %  (domid, callback, errback, jsargs)
 
     def publish(self, rset=None):
         self.req.json_request = True
         # XXX unclear why we have a separated controller here vs
         # js_validate_form on the json controller
-        status, args = _validate_form(self.req, self.vreg)
+        status, args, entity = _validate_form(self.req, self.vreg)
         domid = self.req.form.get('__domid', 'entityForm').encode(
             self.req.encoding)
-        return self.response(domid, status, args)
+        return self.response(domid, status, args, entity)
 
 
 class JSonController(Controller):
@@ -388,7 +393,7 @@
 
     @jsonize
     def js_edit_field(self, action, names, values, rtype, eid, default):
-        success, args = self.validate_form(action, names, values)
+        success, args, _ = self.validate_form(action, names, values)
         if success:
             # Any X,N where we don't seem to use N is an optimisation
             # printable_value won't need to query N again
--- a/web/views/basetemplates.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/web/views/basetemplates.py	Thu Sep 17 15:16:53 2009 +0200
@@ -14,7 +14,7 @@
 from cubicweb.selectors import match_kwargs
 from cubicweb.view import View, MainTemplate, NOINDEX, NOFOLLOW
 from cubicweb.utils import make_uid, UStringIO, can_do_pdf_conversion
-
+from cubicweb.schema import display_name
 
 # main templates ##############################################################
 
--- a/web/views/baseviews.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/web/views/baseviews.py	Thu Sep 17 15:16:53 2009 +0200
@@ -15,6 +15,8 @@
 __docformat__ = "restructuredtext en"
 _ = unicode
 
+from datetime import timedelta
+
 from rql import nodes
 
 from logilab.mtconverter import TransformError, xml_escape, xml_escape
@@ -77,6 +79,13 @@
                 self.w(entity.printable_value(rtype, value, format=format))
                 return
         if etype in ('Time', 'Interval'):
+            if etype == 'Interval' and isinstance(value, (int, long)):
+                # `date - date`, unlike `datetime - datetime` gives an int
+                # (number of days), not a timedelta
+                # XXX should rql be fixed to return Int instead of Interval in
+                #     that case? that would be probably the proper fix but we
+                #     loose information on the way...
+                value = timedelta(days=value)
             # value is DateTimeDelta but we have no idea about what is the
             # reference date here, so we can only approximate years and months
             if format == 'text/html':
--- a/web/views/bookmark.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/web/views/bookmark.py	Thu Sep 17 15:16:53 2009 +0200
@@ -12,9 +12,12 @@
 from cubicweb import Unauthorized
 from cubicweb.selectors import implements
 from cubicweb.web.htmlwidgets import BoxWidget, BoxMenu, RawBoxItem
-from cubicweb.web import action, box
+from cubicweb.web import action, box, uicfg
 from cubicweb.web.views import primary
 
+_abaa = uicfg.actionbox_appearsin_addmenu
+_abaa.tag_subject_of(('*', 'bookmarked_by', '*'), False)
+_abaa.tag_object_of(('*', 'bookmarked_by', '*'), False)
 
 class FollowAction(action.Action):
     id = 'follow'
--- a/web/views/editviews.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/web/views/editviews.py	Thu Sep 17 15:16:53 2009 +0200
@@ -50,10 +50,10 @@
         # them. Use fetch_order and not fetch_unrelated_order as sort method
         # since the latter is mainly there to select relevant items in the combo
         # box, it doesn't give interesting result in this context
-        rql = entity.unrelated_rql(rtype, etype, role,
+        rql, args = entity.unrelated_rql(rtype, etype, role,
                                    ordermethod='fetch_order',
                                    vocabconstraints=False)
-        rset = self.req.execute(rql, {'x' : entity.eid}, 'x')
+        rset = self.req.execute(rql, args, tuple(args))
         return rset, 'list', "search-associate-content", True
 
 
--- a/web/views/formrenderers.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/web/views/formrenderers.py	Thu Sep 17 15:16:53 2009 +0200
@@ -92,7 +92,10 @@
     def render_label(self, form, field):
         if field.label is None:
             return u''
-        label = self.req._(field.label)
+        if isinstance(field.label, tuple): # i.e. needs contextual translation
+            label = self.req.pgettext(*field.label)
+        else:
+            label = self.req._(field.label)
         attrs = {'for': form.context[field]['id']}
         if field.required:
             attrs['class'] = 'required'
@@ -412,12 +415,13 @@
             super(EntityFormRenderer, self).render_buttons(w, form)
 
     def relations_form(self, w, form):
-        srels_by_cat = form.srelations_by_category('generic', 'add')
+        srels_by_cat = form.srelations_by_category('generic', 'add', strict=True)
         if not srels_by_cat:
             return u''
         req = self.req
         _ = req._
-        label = u'%s :' % _('This %s' % form.edited_entity.e_schema).capitalize()
+        __ = _
+        label = u'%s :' % __('This %s' % form.edited_entity.e_schema).capitalize()
         eid = form.edited_entity.eid
         w(u'<fieldset class="subentity">')
         w(u'<legend class="iformTitle">%s</legend>' % label)
@@ -489,7 +493,7 @@
 
     def inline_relation_form(self, w, form, rschema, targettype, role):
         entity = form.edited_entity
-        __ = self.req.__
+        __ = self.req.pgettext
         w(u'<div id="inline%sslot">' % rschema)
         existant = entity.has_eid() and entity.related(rschema)
         if existant:
@@ -506,6 +510,7 @@
             w(form.view('inline-creation', None, etype=targettype,
                         peid=entity.eid, ptype=entity.e_schema,
                         rtype=rschema, role=role))
+            existant = True
         # we can create more than one related entity, we thus display a link
         # to add new related entities
         if form.should_display_add_new_relation_link(rschema, existant, card):
@@ -516,8 +521,9 @@
                 entity.eid, targettype, rschema, role)
             if card in '1?':
                 js = "toggleVisibility('%s'); %s" % (divid, js)
+            ctx = 'inlined:%s.%s.%s' % (entity.e_schema, rschema, role)
             w(u'<a class="addEntity" id="add%s:%slink" href="javascript: %s" >+ %s.</a>'
-              % (rschema, entity.eid, js, __('add a %s' % targettype)))
+              % (rschema, entity.eid, js, __(ctx, 'add a %s' % targettype)))
             w(u'</div>')
             w(u'<div class="trame_grise">&#160;</div>')
         w(u'</div>')
--- a/web/views/forms.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/web/views/forms.py	Thu Sep 17 15:16:53 2009 +0200
@@ -486,6 +486,7 @@
         #       cases, it doesn't make sense to sort results afterwards.
         return vocabfunc(rtype, limit)
 
+    # XXX should be on the field, no?
     def subject_relation_vocabulary(self, rtype, limit=None):
         """defaut vocabulary method for the given relation, looking for
         relation's object entities (i.e. self is the subject)
@@ -529,25 +530,6 @@
                 break
         return result
 
-    # def subject_in_state_vocabulary(self, rtype, limit=None):
-    #     """vocabulary method for the in_state relation, looking for relation's
-    #     object entities (i.e. self is the subject) according to initial_state,
-    #     state_of and next_state relation
-    #     """
-    #     entity = self.edited_entity
-    #     if not entity.has_eid() or not entity.in_state:
-    #         # get the initial state
-    #         rql = 'Any S where S state_of ET, ET name %(etype)s, ET initial_state S'
-    #         rset = self.req.execute(rql, {'etype': str(entity.e_schema)})
-    #         if rset:
-    #             return [(rset.get_entity(0, 0).view('combobox'), rset[0][0])]
-    #         return []
-    #     results = []
-    #     for tr in entity.in_state[0].transitions(entity):
-    #         state = tr.destination_state[0]
-    #         results.append((state.view('combobox'), state.eid))
-    #     return sorted(results)
-
     def srelations_by_category(self, categories=None, permission=None):
         return ()
 
--- a/web/views/schema.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/web/views/schema.py	Thu Sep 17 15:16:53 2009 +0200
@@ -14,7 +14,7 @@
 
 from cubicweb.selectors import (implements, yes, match_user_groups,
                                 has_related_entities)
-from cubicweb.schema import META_RTYPES, SCHEMA_TYPES
+from cubicweb.schema import META_RTYPES, SCHEMA_TYPES, SYSTEM_RTYPES
 from cubicweb.schemaviewer import SchemaViewer
 from cubicweb.view import EntityView, StartupView
 from cubicweb.common import tags, uilib
@@ -23,7 +23,7 @@
 from cubicweb.web.views import primary, baseviews, tabs, management
 
 ALWAYS_SKIP_TYPES = BASE_TYPES | SCHEMA_TYPES
-SKIP_TYPES = ALWAYS_SKIP_TYPES | META_RTYPES
+SKIP_TYPES = ALWAYS_SKIP_TYPES | META_RTYPES | SYSTEM_RTYPES
 SKIP_TYPES.update(set(('Transition', 'State', 'TrInfo',
                        'CWUser', 'CWGroup',
                        'CWCache', 'CWProperty', 'CWPermission',
--- a/web/views/treeview.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/web/views/treeview.py	Thu Sep 17 15:16:53 2009 +0200
@@ -24,7 +24,7 @@
     css_classes = 'treeview widget'
     title = _('tree view')
 
-    def call(self, subvid=None, treeid=None, initial_load=True):
+    def call(self, subvid=None, treeid=None, initial_load=True, initial_thru_ajax=False):
         if subvid is None:
             subvid = self.req.form.pop('treesubvid', 'oneline') # consume it
         if treeid is None:
@@ -32,7 +32,7 @@
             if treeid is None:
                 self.warning('Tree state won\'t be properly restored after next reload')
                 treeid = make_uid('throw away uid')
-        toplevel_thru_ajax = self.req.form.pop('treeview_top', False)
+        toplevel_thru_ajax = self.req.form.pop('treeview_top', False) or initial_thru_ajax
         toplevel = toplevel_thru_ajax or (initial_load and not self.req.form.get('fname'))
         ulid = ' '
         if toplevel:
--- a/web/views/workflow.py	Tue Sep 15 15:01:41 2009 +0200
+++ b/web/views/workflow.py	Thu Sep 17 15:16:53 2009 +0200
@@ -20,10 +20,15 @@
 from cubicweb.interfaces import IWorkflowable
 from cubicweb.view import EntityView
 from cubicweb.schema import display_name
-from cubicweb.web import stdmsgs, action, component, form, action
+from cubicweb.web import uicfg, stdmsgs, action, component, form, action
 from cubicweb.web import formfields as ff, formwidgets as fwdgs
 from cubicweb.web.views import TmpFileViewMixin, forms, primary
 
+_abaa = uicfg.actionbox_appearsin_addmenu
+_abaa.tag_subject_of(('BaseTransition', 'condition', 'RQLExpression'), False)
+_abaa.tag_subject_of(('State', 'allowed_transition', 'BaseTransition'), False)
+_abaa.tag_object_of(('SubWorkflowExitPoint', 'destination_state', 'State'),
+                    False)
 
 # IWorkflowable views #########################################################