Package platecom :: Package utils :: Package content :: Module multilingual
[hide private]
[frames] | no frames]

Source Code for Module icsemantic.core.content.multilingual

  1  """ 
  2  Utilities, adapters, markers... de todo un poco para 
  3  soportar contenido multi-lenguaje 
  4   
  5  @author: Juan Pablo Gimenez 
  6  @contact: jpg@rcom.com.ar 
  7  """ 
  8  __author__ = """Juan Pablo Gimenez <jpg@rcom.com.ar>""" 
  9  __docformat__ = 'plaintext' 
 10   
 11  import sys 
 12  from types import FunctionType as function 
 13   
 14  from zope.interface import implements, implementedBy, \ 
 15                             classProvides 
 16  from zope.app.component.hooks import getSite 
 17  from zope.component.interfaces import IFactory 
 18  from zope.component import queryUtility 
 19  from zope.i18n.interfaces import IUserPreferredLanguages 
 20   
 21  from Products.Archetypes.utils import capitalize 
 22  from Products.ATContentTypes.interfaces import IATContentType 
 23  from Products.CMFCore.utils import getToolByName 
 24  from Products.CMFPlone.utils import classImplements, \ 
 25                                      classDoesNotImplement 
 26   
 27  from platecom.utils.interfaces import IContentTypesMultilingualPatcher, \ 
 28                                        IMultilingualContentMarker, \ 
 29                                        IMultilingualGettersMarker, \ 
 30                                        IFieldEmptiness 
 31   
 32  NOT_FALLBACK_FIELDS = ['id', 
 33                         'language',] 
 34  FALLBACK_TYPES = ['string', 
 35                    'text', 
 36                    'lines',] 
 37   
38 -class ContentTypesMultilingualPatcher(object):
39 """ Utility para aplicar los parches de soporte multilenguaje 40 a un ContentType en particular 41 """ 42 implements(IContentTypesMultilingualPatcher) 43
44 - def patch(self, klass, replace_accessors=False):
45 """ Incorpora los metodos con fallback multi-lenguaje 46 47 >>> import string 48 >>> from Products.Archetypes.atapi import * 49 >>> from Products.ATContentTypes.content.base import ATCTContent 50 >>> from icsemantic.core.content.multilingual import ContentTypesMultilingualPatcher 51 >>> from icsemantic.core.interfaces import IMultilingualContentMarker, IMultilingualGettersMarker 52 53 >>> class MyContent(ATCTContent): 54 ... portal_type = meta_type = 'MyContent' 55 ... schema = Schema(( 56 ... StringField('some_field', storage=AnnotationStorage()), 57 ... StringField('_other_field'), 58 ... )) 59 60 >>> registerType(MyContent, 'Archetypes') 61 62 >>> hasattr(MyContent, 'getSome_field') 63 True 64 >>> hasattr(MyContent, 'getMultilingualSome_field') 65 False 66 67 >>> original_getter = getattr(MyContent, 'getSome_field') 68 >>> ccpatcher = ContentTypesMultilingualPatcher() 69 >>> ccpatcher.patch(MyContent) 70 71 >>> IMultilingualContentMarker.implementedBy(MyContent) 72 True 73 >>> IMultilingualGettersMarker.implementedBy(MyContent) 74 False 75 >>> hasattr(MyContent, 'getSome_field') 76 True 77 >>> hasattr(MyContent, 'getMultilingualSome_field') 78 True 79 >>> original_getter == getattr(MyContent, 'getSome_field') 80 True 81 82 >>> ccpatcher.unpatch(MyContent) 83 >>> IMultilingualContentMarker.implementedBy(MyContent) 84 False 85 >>> IMultilingualGettersMarker.implementedBy(MyContent) 86 False 87 >>> ccpatcher.patch(MyContent, replace_accessors=True) 88 89 >>> IMultilingualContentMarker.implementedBy(MyContent) 90 True 91 >>> IMultilingualGettersMarker.implementedBy(MyContent) 92 True 93 >>> hasattr(MyContent, 'getSome_field') 94 True 95 >>> hasattr(MyContent, 'getMultilingualSome_field') 96 True 97 >>> original_getter == getattr(MyContent, 'getSome_field') 98 False 99 >>> getattr(MyContent, 'getSome_field') == getattr(MyContent, 'getMultilingualSome_field') 100 True 101 >>> original_getter == getattr(MyContent, '_old_getSome_field') 102 True 103 104 Y ahora pruebo con basura... 105 >>> ccpatcher.patch('pepe') 106 Traceback (most recent call last): 107 ... 108 AttributeError... 109 110 """ 111 if not IATContentType.isImplementedByInstancesOf(klass): 112 # vamos a intentar conseguir el klass por el nombre 113 portal = getSite() 114 archetype_tool = getToolByName(portal, 'archetype_tool') 115 for type in archetype_tool.listRegisteredTypes(): 116 if type['meta_type'] == klass: 117 klass = type['klass'] 118 assert IATContentType.isImplementedByInstancesOf(klass) 119 120 if IMultilingualContentMarker.implementedBy(klass): 121 return 122 123 def getMultilingualField(self, field_name, fallback=True): 124 """ 125 """ 126 field = self.getField(field_name) 127 if field is None: 128 raise KeyError("Cannot find field with name %s" % field_name) 129 130 value = field.get(self) 131 if not IMultilingualContentMarker.providedBy(self) or \ 132 field.isLanguageIndependent(self) or \ 133 not fallback or \ 134 field_name in NOT_FALLBACK_FIELDS: 135 # si es independiente del lenguaje o pedimos que no haga 136 # fallback lo devolvemos sea cual sea el valor 137 # o las preferencias del usuario 138 # tampoco hacemos fallback para el campo language 139 return value 140 141 translations = self.getTranslations() 142 current_lang = self.getLanguage() 143 if fallback and current_lang and len(translations) > 1: 144 try: 145 platecom_lang_util = queryUtility(IUserPreferredLanguages, 146 name='platecom_preferred_languages') 147 request=getattr(self, 'REQUEST', None) 148 langs = platecom_lang_util.getPreferredLanguages(request=request) 149 langs += [current_lang] 150 for lang in langs: 151 if translations.has_key(lang): 152 inst = translations[lang][0] 153 field = inst.getField(field_name) 154 if field: 155 value = field.get(inst) 156 if not IFieldEmptiness(field)(inst): 157 break 158 except: 159 pass 160 return value
161 162 if not hasattr(klass, 'getMultilingualField'): 163 setattr(klass, 'getMultilingualField', getMultilingualField) 164 165 fields = klass.schema.fields() 166 for field in fields: 167 name = field.getName() 168 # if name is 'description': import pdb;pdb.set_trace() 169 if field.type in FALLBACK_TYPES and \ 170 name not in NOT_FALLBACK_FIELDS and \ 171 not field.isLanguageIndependent(field): 172 makeMethod(klass, field) 173 def getMultilingualAccessor(self, field): 174 """Return the accessor method for getting data out of this 175 field""" 176 if field.multilingual_accessor: 177 accessor = getattr(self, field.multilingual_accessor, None) 178 if not accessor and field.accessor: 179 accessor = getattr(self, field.accessor, None) 180 return accessor
181 setattr(klass, 'getMultilingualAccessor', getMultilingualAccessor) 182 if replace_accessors: 183 # replace fields accessors 184 getName = field.accessor 185 getMultilingualName = "getMultilingual%s" % capitalize(name) 186 if hasattr(klass, getName) and \ 187 hasattr(klass, getMultilingualName): 188 getMethod = getattr(klass, getName) 189 getMultilingualMethod = getattr(klass, getMultilingualName) 190 setattr(klass, '_old_%s' % getName, getMethod) 191 setattr(klass, getName, getMultilingualMethod) 192 classImplements(klass, IMultilingualGettersMarker) 193 classImplements(klass, IMultilingualContentMarker) 194
195 - def unpatch(self, klass):
196 """ Remueve los metodos con fallback multi-lenguaje 197 198 >>> import string 199 >>> from Products.Archetypes.atapi import * 200 >>> from Products.ATContentTypes.content.base import ATCTContent 201 >>> from icsemantic.core.content.multilingual import ContentTypesMultilingualPatcher 202 203 >>> class MyContent(ATCTContent): 204 ... portal_type = meta_type = 'MyContent' 205 ... schema = Schema(( 206 ... StringField('some_field', storage=AnnotationStorage()), 207 ... StringField('_other_field'), 208 ... )) 209 210 >>> registerType(MyContent, 'Archetypes') 211 212 >>> hasattr(MyContent, 'getSome_field') 213 True 214 >>> hasattr(MyContent, 'getMultilingualSome_field') 215 False 216 217 >>> ccpatcher = ContentTypesMultilingualPatcher() 218 >>> ccpatcher.patch(MyContent) 219 220 >>> hasattr(MyContent, 'getSome_field') 221 True 222 >>> hasattr(MyContent, 'getMultilingualSome_field') 223 True 224 225 >>> ccpatcher = ContentTypesMultilingualPatcher() 226 >>> ccpatcher.unpatch(MyContent) 227 228 >>> hasattr(MyContent, 'getSome_field') 229 True 230 >>> hasattr(MyContent, 'getMultilingualSome_field') 231 False 232 233 """ 234 if not IATContentType.isImplementedByInstancesOf(klass): 235 # vamos a intentar conseguir el klass por el nombre 236 portal = getSite() 237 archetype_tool = getToolByName(portal, 'archetype_tool') 238 for type in archetype_tool.listRegisteredTypes(): 239 if type['meta_type'] == klass: 240 klass = type['klass'] 241 assert IATContentType.isImplementedByInstancesOf(klass) 242 243 if IMultilingualContentMarker.implementedBy(klass): 244 fields = klass.schema.fields() 245 for field in fields: 246 methodName = "getMultilingual%s" % capitalize(field.getName()) 247 if hasattr(klass, methodName): 248 try: 249 delattr(klass, methodName) 250 except: 251 pass 252 if IMultilingualGettersMarker.implementedBy(klass): 253 name = field.getName() 254 getName = field.accessor 255 getOldName = "_old_%s" % getName 256 if hasattr(klass, getName) and hasattr(klass, getOldName): 257 getOldMethod = getattr(klass, getOldName) 258 setattr(klass, getName, getOldMethod) 259 try: 260 delattr(klass, getOldName) 261 except: 262 pass 263 264 if hasattr(klass, 'getMultilingualField'): 265 try: 266 delattr(klass, 'getMultilingualField') 267 except: 268 pass 269 270 classDoesNotImplement( klass, IMultilingualContentMarker) 271 classDoesNotImplement( klass, IMultilingualGettersMarker)
272
273 -def makeMethod(klass, field):
274 name = field.getName() 275 def generatedMultilingualAccessor(self, fallback = True): 276 def who_called_me(): 277 try: 278 1/0 279 except ZeroDivisionError: 280 return sys.exc_info()[2].tb_frame.f_back.f_back.f_code.co_name
281 # TODO: tratar de encontrar un mejor metodo que este... 282 who=who_called_me() 283 # import pdb;pdb.set_trace() 284 if who == '_get_object_datum': 285 fallback = False 286 287 value = self.getMultilingualField(name, fallback) 288 # if value == 'ATDocument de prueba.': 289 # import pdb;pdb.set_trace() 290 return value 291 method = generatedMultilingualAccessor 292 methodName = "getMultilingual%s" % capitalize(name) 293 method = function(method.func_code, 294 method.func_globals, 295 methodName, 296 method.func_defaults, 297 method.func_closure, 298 ) 299 if not hasattr(klass, methodName): 300 setattr(klass, methodName, method) 301 field.multilingual_accessor = methodName 302