i18n improvements

git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@2238 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2007-12-12 10:26:57 +00:00
parent eddbdb63a9
commit 43e775c895
4 changed files with 100 additions and 40 deletions

View file

@ -171,14 +171,16 @@ class Concept(Contained, Persistent):
def getChildren(self, predicates=None, sort='default'):
return [r.second for r in self.getChildRelations(predicates, sort=sort)]
def getParentRelations (self, predicates=None, parent=None):
def getParentRelations (self, predicates=None, parent=None, sort='default'):
predicates = predicates is None and ['*'] or predicates
relationships = [ConceptRelation(None, self, p) for p in predicates]
# TODO: sort...
return getRelations(first=parent, second=self, relationships=relationships)
if sort == 'default':
sort = lambda x: (x.order, x.first.title.lower())
return sorted(getRelations(first=parent, second=self, relationships=relationships),
key=sort)
def getParents(self, predicates=None):
return [r.first for r in self.getParentRelations(predicates)]
def getParents(self, predicates=None, sort='default'):
return [r.first for r in self.getParentRelations(predicates, sort=sort)]
def assignChild(self, concept, predicate=None, order=0, relevance=1.0):
if predicate is None:

View file

@ -108,14 +108,41 @@ languages on the type object.
Now we are ready to enter a language-specific title.
>>> from loops.browser.concept import ConceptEditForm
>>> from loops.browser.concept import ConceptEditForm, ConceptView
>>> input = {'form.title': 'loops per Zope 3', 'loops.language': 'it',
... 'form.actions.apply': 'Change'}
>>> form = ConceptEditForm(topic01, TestRequest(form=input))
>>> form.update()
>>> topic01.title
{'it': u'loops per Zope 3'}
{'en': u'loops for Zope 3', 'it': u'loops per Zope 3'}
If we access an i18n attribute via a view that is i18n-aware we get the
value corresponding to the language preferences that appear in the request.
>>> input = {'loops.language': 'it'}
>>> view = ConceptView(topic01, TestRequest(form=input))
>>> view.title
u'loops per Zope 3'
If there is no entry for the language given we get back the entry for
the default language.
>>> input = {'loops.language': 'de'}
>>> view = ConceptView(topic01, TestRequest(form=input))
>>> view.title
u'loops for Zope 3'
There are also fallbacks - mainly for being able to access the title
attribute in not i18n-aware contexts - that retrieve the value corresponding
to the default language at the time of the attribute creation.
>>> topic01.title.getDefault()
u'loops for Zope 3'
>>> str(topic01.title)
'loops for Zope 3'
>>> topic01.title.lower()
u'loops for zope 3'
Fin de partie

View file

@ -33,40 +33,65 @@ from cybertools.typology.interfaces import IType
from loops.common import adapted, AdapterBase
_not_found = object()
# support for i18n content
class I18NValue(PersistentMapping):
""" A dictionary to be used for storing values for different languages.
"""
default = None
def lower(self):
return str(self).lower()
# this should only be used as a fallback for the title attribute
return self.getDefault().lower()
def getDefault(self):
if self.default is None:
return self.values()[0]
return self.default
def __str__(self):
return self.values()[0]
return str(self.getDefault())
def getI18nValue(obj, attr, langInfo=None):
obj = removeSecurityProxy(obj)
value = getattr(obj, attr, None)
lang = None
if isinstance(value, I18NValue):
lang = langInfo and langInfo.language or value.keys()[0]
value = value.get(lang)
#print '*** getI18nValue', attr, langInfo, lang, getattr(obj, attr, None), value
if langInfo:
result = value.get(langInfo.language, _not_found)
if result is _not_found:
result = value.get(langInfo.defaultLanguage, _not_found)
if result is _not_found:
result = value.getDefault()
return result
else:
return value.getDefault()
return value
def setI18nValue(obj, attr, value, langInfo=None):
obj = removeSecurityProxy(obj)
old = getattr(obj, attr, None)
if langInfo is None:
setattr(obj, attr, value)
return
if isinstance(old, I18NValue):
raise ValueError('Attribute %s on object %s is an I18NValue (%s) '
'and no langInfo given.' % (attr, obj, value))
else:
setattr(obj, attr, value)
return
lang = langInfo.language
if isinstance(old, I18NValue):
old[lang] = value
else:
setattr(obj, attr, I18NValue(((lang, value),)))
i18nValue = I18NValue(((lang, value),))
defaultLang = langInfo.defaultLanguage
if lang != defaultLang:
# keep existing value
i18nValue[defaultLang] = old
i18nValue.default = i18nValue[defaultLang]
setattr(obj, attr, i18nValue)
#print '*** setI18nValue', attr, langInfo, lang, value, getattr(obj, attr, None)

View file

@ -34,11 +34,13 @@ from zope.security.proxy import removeSecurityProxy
from zope.cachedescriptors.property import Lazy
from cybertools.typology.interfaces import IType
from loops.common import adapted
from loops.concept import Concept
from loops.i18n.browser import I18NView
from loops.util import getUidForObject, getObjectForUid, toUnicode
class LoopsMethods(MethodPublisher):
class LoopsMethods(MethodPublisher, I18NView):
""" XML-RPC methods for the loops root object.
"""
@ -77,40 +79,44 @@ class LoopsMethods(MethodPublisher):
tc = self.concepts.getTypeConcept()
types = tc.getChildren((self.typePredicate,))
#types = [t for t in types if ITypeConcept(t).typeInterface ... ]
return [objectAsDict(t) for t in types]
return [objectAsDict(t, self.languageInfo) for t in types]
def getPredicates(self):
pt = self.concepts.getDefaultPredicate().conceptType
preds = pt.getChildren((self.concepts.getTypePredicate(),))
return [objectAsDict(p) for p in preds if p is not self.typePredicate]
return [objectAsDict(p, self.languageInfo)
for p in preds if p is not self.typePredicate]
def getChildren(self, id, predicates=[], child=''):
obj = getObjectForUid(id)
preds = [getObjectForUid(p) for p in predicates]
child = child and getObjectForUid(child) or None
rels = obj.getChildRelations(preds or None, child)
return formatRelations(rels)
return formatRelations(rels, langInfo=self.languageInfo)
def getParents(self, id, predicates=[], parent=''):
obj = getObjectForUid(id)
preds = [getObjectForUid(p) for p in predicates]
parent = parent and getObjectForUid(parent) or None
rels = obj.getParentRelations(preds or None, parent)
return formatRelations(rels, useSecond=False)
return formatRelations(rels, useSecond=False, langInfo=self.languageInfo)
def getResources(self, id, predicates=[], resource=''):
obj = getObjectForUid(id)
preds = [getObjectForUid(p) for p in predicates]
resource = resource and getObjectForUid(child) or None
rels = obj.getResourceRelations(preds or None, resource)
return formatRelations(rels)
return formatRelations(rels, langInfo=self.languageInfo)
def getObjectWithChildren(self, obj):
mapping = objectAsDict(obj)
mapping['children'] = formatRelations(obj.getChildRelations())
mapping['parents'] = formatRelations(
obj.getParentRelations(), useSecond=False)
mapping['resources'] = formatRelations(obj.getResourceRelations())
mapping = objectAsDict(obj, self.languageInfo)
mapping['children'] = formatRelations(obj.getChildRelations(sort=None),
langInfo=self.languageInfo)
mapping['parents'] = formatRelations(obj.getParentRelations(sort=None),
useSecond=False,
langInfo=self.languageInfo)
mapping['resources'] = formatRelations(obj.getResourceRelations(sort=None),
langInfo=self.languageInfo)
return mapping
def assignChild(self, objId, predicateId, childId):
@ -134,36 +140,36 @@ class LoopsMethods(MethodPublisher):
name = INameChooser(self.concepts).chooseName(name, c)
self.concepts[name] = c
c.conceptType = type
adapted(c, self.languageInfo).title = title
notify(ObjectCreatedEvent(c))
notify(ObjectModifiedEvent(c))
return objectAsDict(c)
return objectAsDict(c, self.languageInfo)
def editConcept(self, objId, attr, value):
obj = getObjectForUid(objId)
ti = IType(obj).typeInterface
if ti is not None:
obj = ti(obj)
# TODO: provide conversion if necessary
adapter = adapted(obj, self.languageInfo)
# TODO: provide conversion if necessary - use cybertools.composer.schema
value = value.strip() # remove spaces appended by Flash
setattr(obj, attr, toUnicode(value))
setattr(adapter, attr, toUnicode(value))
notify(ObjectModifiedEvent(obj))
return 'OK'
def objectAsDict(obj):
def objectAsDict(obj, langInfo=None):
objType = IType(obj)
adapter = adapted(obj, langInfo)
mapping = {'id': getUidForObject(obj), 'name': getName(obj),
'title': obj.title, 'description': obj.description,
'title': adapter.title, 'description': adapter.description,
'type': getUidForObject(objType.typeProvider)}
ti = objType.typeInterface
if ti is not None:
adapter = ti(obj)
#for attr in (list(adapter._adapterAttributes) + list(ti)):
for attr in list(ti):
if attr not in ('__parent__', 'context', 'id', 'name',
'title', 'description', 'type', 'data'):
value = getattr(adapter, attr)
# TODO: provide conversion and schema information
# TODO: provide conversion and schema information -
# use cybertools.composer.schema
#if value is None or type(value) in (str, unicode):
if ITextLine.providedBy(ti[attr]):
mapping[attr] = value or u''
@ -171,7 +177,7 @@ def objectAsDict(obj):
# mapping[attr] = ' | '.join(value)
return mapping
def formatRelations(rels, useSecond=True):
def formatRelations(rels, useSecond=True, langInfo=None):
predIds = {}
result = []
for rel in rels:
@ -185,6 +191,6 @@ def formatRelations(rels, useSecond=True):
other = rel.second
else:
other = rel.first
result[predIds[predId]]['objects'].append(objectAsDict(other))
return result
result[predIds[predId]]['objects'].append(objectAsDict(other, langInfo))
return sorted(result, key=lambda x: x['title'])