diff --git a/docs/HISTORY.txt b/docs/HISTORY.txt index ba7bdcc..6839a9c 100644 --- a/docs/HISTORY.txt +++ b/docs/HISTORY.txt @@ -4,8 +4,12 @@ Changelog 1.1b12 (unreleased) ------------------- -- Nothing changed yet. - +- Required fields are not dependent from language fallback anymore [sebasgo] +- Reset language after scaling images [pgrunewald] +- Make indices resilient [sebasgo] +- Fix Image Bobo traversing for fullscreen view [sebasgo] +- Allow language fallback for brains [pgrunewald] +- Fix lazy initialization with respect to plone.protect [sebasgo] 1.1b11 (2017-01-09) ------------------- @@ -16,7 +20,7 @@ Changelog 1.1b10 (2014-12-05) ------------------- -* Renamed protected TAL keyword 'translate' to 'multilanguage' +* Renamed protected TAL keyword 'translate' to 'multilanguage' [pgrunewald] 1.1b9 (2014-06-24) diff --git a/raptus/multilanguagefields/fields.py b/raptus/multilanguagefields/fields.py index 7d2c0e4..8c2ee85 100755 --- a/raptus/multilanguagefields/fields.py +++ b/raptus/multilanguagefields/fields.py @@ -70,13 +70,6 @@ def __init__(self, name=None, **kwargs): def _set_required(self, value): self._required = value def _get_required(self): - context = getSite() - if self.haveLanguageFallback(context): - current = self._v_lang - if current is None: - current = self._getCurrentLanguage(context) - default = self.getDefaultLang(context) - return default == current and getattr(self, '_required', False) return getattr(self, '_required', False) required = property(fget=_get_required, fset=_set_required) diff --git a/raptus/multilanguagefields/indexes/UnIndex.py b/raptus/multilanguagefields/indexes/UnIndex.py index 20bbf97..cbc1753 100644 --- a/raptus/multilanguagefields/indexes/UnIndex.py +++ b/raptus/multilanguagefields/indexes/UnIndex.py @@ -16,18 +16,28 @@ from Products.PluginIndexes.common import safe_callable from Products.PluginIndexes.common.UnIndex import UnIndex, _marker +try: + from plone.protect.utils import safeWrite +except ImportError: + def safeWrite(obj, request=None): + pass + + class MultilanguageUnIndex(UnIndex): """Multilanguage aware forward and reverse index. """ - + _v_lang = None _d_length = PersistentDict() _d_index = PersistentDict() _d_unindex = PersistentDict() - + def _getCurrentLanguage(self): - return getToolByName(getSite(), 'portal_languages').getPreferredLanguage() - + try: + return getToolByName(getSite(), 'portal_languages').getPreferredLanguage() + except AttributeError: + return 'en' + def _get_lang_length(self, lang): if not self._d_length.has_key(lang): self._d_length[lang] = BTrees.Length.Length() @@ -53,10 +63,13 @@ def _del_length(self): _length = property(fget=_get_length, fset=_set_length, fdel=_del_length) - + def _get_lang_index(self, lang): if not self._d_index.has_key(lang): self._d_index[lang] = OOBTree() + safeWrite(self) + safeWrite(self._d_index) + safeWrite(self._d_index[lang]) return self._d_index[lang] def _set_index(self, value): @@ -78,10 +91,13 @@ def _del_index(self): _index = property(fget=_get_index, fset=_set_index, fdel=_del_index) - + def _get_lang_unindex(self, lang): if not self._d_unindex.has_key(lang): self._d_unindex[lang] = IOBTree() + safeWrite(self) + safeWrite(self._d_unindex) + safeWrite(self._d_unindex[lang]) return self._d_unindex[lang] def _set_unindex(self, value): @@ -103,7 +119,7 @@ def _del_unindex(self): _unindex = property(fget=_get_unindex, fset=_set_unindex, fdel=_del_unindex) - + def clear(self): self._v_lang = None self._d_length = PersistentDict() @@ -136,7 +152,7 @@ def unindex_object(self, documentId): UnIndex.unindex_object(self, documentId) finally: self._v_lang = None - + def _get_object_datum(self, obj, attr): # self.id is the name of the index, which is also the name of the # attribute we're interested in. If the attribute is callable, diff --git a/raptus/multilanguagefields/indexes/ZCTextIndex.py b/raptus/multilanguagefields/indexes/ZCTextIndex.py index 53460b3..261d8d6 100644 --- a/raptus/multilanguagefields/indexes/ZCTextIndex.py +++ b/raptus/multilanguagefields/indexes/ZCTextIndex.py @@ -15,6 +15,13 @@ from Products.PluginIndexes.common import safe_callable from Products.CMFCore.utils import getToolByName +try: + from plone.protect.utils import safeWrite +except ImportError: + def safeWrite(obj, request=None): + pass + + class MultilanguageZCTextIndex(ZCTextIndex): """Multilanguage Persistent text index. """ @@ -24,7 +31,10 @@ class MultilanguageZCTextIndex(ZCTextIndex): _v_lang = None def _getCurrentLanguage(self): - return getToolByName(getSite(), 'portal_languages').getPreferredLanguage() + try: + return getToolByName(getSite(), 'portal_languages').getPreferredLanguage() + except AttributeError: + return 'en' @property def languages(self): @@ -32,10 +42,12 @@ def languages(self): if ltool is None: return [] return ltool.getSupportedLanguages() - + def _get_lang_index(self, lang): if not hasattr(self, '_index_%s' % lang): setattr(self, '_index_%s' % lang, self._index_factory(aq_base(self.getLexicon()))) + safeWrite(self) + safeWrite(self, getattr(self, '_index_%s' % lang)) return getattr(self, '_index_%s' % lang) def _set_index(self, value): @@ -71,6 +83,8 @@ def getLexicon(self): raise TypeError('Object "%s" is not a ZCTextIndex Lexicon' % repr(lexicon)) self._v_lexicon = lexicon + safeWrite(self) + safeWrite(lexicon) return lexicon ## Pluggable Index APIs ## @@ -79,7 +93,7 @@ def index_object(self, documentId, obj, threshold=None): try: fields = self._indexed_attrs except: fields = [ self._fieldname ] res = 0 - + for lang in self.languages: all_texts = [] for attr in fields: @@ -96,7 +110,7 @@ def index_object(self, documentId, obj, threshold=None): all_texts.extend(text) else: all_texts.append(text) - + # Check that we're sending only strings all_texts = filter(lambda text: isinstance(text, basestring), \ all_texts) diff --git a/raptus/multilanguagefields/patches/catalog.py b/raptus/multilanguagefields/patches/catalog.py index 297f351..b5ce438 100644 --- a/raptus/multilanguagefields/patches/catalog.py +++ b/raptus/multilanguagefields/patches/catalog.py @@ -25,7 +25,9 @@ # CatalogBrain monkey patch def __new_init__(self, data): ndata = [] - lang = getToolByName(getSite(), 'portal_languages').getPreferredLanguage() + portal_languages = getToolByName(getSite(), 'portal_languages') + lang = portal_languages.getPreferredLanguage() + default_lang = portal_languages.getDefaultLanguage() if portal_languages.allow_content_language_fallback else 'en' try: encoding = getToolByName(self, "portal_properties").site_properties.default_charset except AttributeError: @@ -34,7 +36,10 @@ def __new_init__(self, data): try: value = json.loads(v) value = value['___multilanguage___'] - v = value.get(lang, '') + if portal_languages.allow_content_language_fallback: + v = value.get(lang, value.get(default_lang, '')) + else: + v = value.get(lang, '') if isinstance(v, basestring): v = v.encode(encoding) except: diff --git a/raptus/multilanguagefields/patches/imaging.py b/raptus/multilanguagefields/patches/imaging.py index 2949f84..7122e21 100755 --- a/raptus/multilanguagefields/patches/imaging.py +++ b/raptus/multilanguagefields/patches/imaging.py @@ -46,11 +46,19 @@ def publishTraverse(self, request, name): ImageTraverser.publishTraverse = publishTraverse LOG.info("plone.app.imaging.traverse.ImageTraverser.publishTraverse patched") - def scale(self, fieldname=None, scale=None, **parameters): + def scale(self, fieldname=None, scale=None, height=None, width=None, **parameters): field = self.context.getField(fieldname) + + if IMultilanguageField.providedBy(field): + if not '___' in fieldname: # no language explicitly wished. So unset language preference. + field.resetLanguage() + fieldname = '%s___%s___' % (fieldname, field._v_lang or field._getCurrentLanguage(self.context)) + + image = self.__old_scale(fieldname, scale, height, width, **parameters) + if IMultilanguageField.providedBy(field): - fieldname = '%s___%s___' % (fieldname, field._v_lang or field._getCurrentLanguage(getSite())) - return self.__old_scale(fieldname, scale, **parameters) + field.resetLanguage() + return image from plone.app.imaging.scaling import ImageScaling ImageScaling.__old_scale = ImageScaling.scale ImageScaling.scale = scale diff --git a/raptus/multilanguagefields/patches/traverse.py b/raptus/multilanguagefields/patches/traverse.py index 7728ed5..c4cd9a4 100755 --- a/raptus/multilanguagefields/patches/traverse.py +++ b/raptus/multilanguagefields/patches/traverse.py @@ -4,16 +4,16 @@ from raptus.multilanguagefields import LOG from raptus.multilanguagefields.interfaces import IMultilanguageField from Products.Archetypes.BaseObject import BaseObject + def __bobo_traverse__(self, REQUEST, name): - """Transparent access to multilanguage image scales for - content types holding an multilanguage ImageField named - 'image' + """ helper to access multilanguage image scales the old way during + `unrestrictedTraverse` calls - NO BLOBS + the method to be patched is '__bobo_traverse__' """ if name.startswith('image_') or name == 'image': - field = self.getField('image') - if not IMultilanguageField.providedBy(field): + field = self.getField(name.split('_')[0]) + if not IMultilanguageField.providedBy(field) or not hasattr(REQUEST, 'get'): return BaseObject.__bobo_traverse__(self, REQUEST, name) last = REQUEST.get('ACTUAL_URL', '').endswith(name) fieldname, scale = name, None @@ -25,31 +25,32 @@ def __bobo_traverse__(self, REQUEST, name): if '_' in name: fieldname, scale = name.split('_', 1) if last and REQUEST.get('HTTP_USER_AGENT', False): - _scale = scale - if _scale is not None: - _scale = '_'+str(_scale) - else: - _scale = '' - REQUEST.RESPONSE.redirect(self.absolute_url()+'/'+fieldname+'___'+field._getCurrentLanguage(self)+'___'+_scale) + # begin own code + if scale in field.getAvailableSizes(self): + # end own code + _scale = scale + if _scale is not None: + _scale = '_'+str(_scale) + else: + _scale = '' + REQUEST.RESPONSE.redirect(self.absolute_url()+'/'+fieldname+'___'+field._getCurrentLanguage(self)+'___'+_scale) lang = field._getCurrentLanguage(self) lang_before = field._v_lang try: field.setLanguage(lang) + handler = IImageScaleHandler(field, None) image = None - if scale: - if scale in field.getAvailableSizes(self): - image = field.getScale(self, scale=scale) - else: - image = field.getScale(self) + if handler is not None: + try: + image = handler.getScale(self, scale) + except AttributeError: # no image available, do not raise as there might be one available as a fallback + pass if not image: # language fallback defaultLang = field.getDefaultLang(self) if defaultLang and not defaultLang == lang: field.setLanguage(defaultLang) - if scale: - if scale in field.getAvailableSizes(self): - image = field.getScale(self, scale=scale) - else: - image = field.getScale(self) + if handler is not None: + image = handler.getScale(self, scale) if image is not None: if last and REQUEST.get('HTTP_USER_AGENT', False): _scale = scale @@ -60,8 +61,7 @@ def __bobo_traverse__(self, REQUEST, name): REQUEST.RESPONSE.redirect(self.absolute_url()+'/'+fieldname+'___'+defaultLang+'___'+_scale) finally: field.setLanguage(lang_before) - if image is not None and not isinstance(image, basestring): - # image might be None or '' for empty images + if image is not None: return image return BaseObject.__bobo_traverse__(self, REQUEST, name)