[Erp5-report] r30269 - in /erp5/trunk/products/ERP5Type: ./ Accessor/ interfaces/ mixin/ pa...

nobody at svn.erp5.org nobody at svn.erp5.org
Wed Nov 4 08:19:45 CET 2009


Author: yusei
Date: Wed Nov  4 08:19:44 2009
New Revision: 30269

URL: http://svn.erp5.org?rev=30269&view=rev
Log:
Commit content translation feature.

Added:
    erp5/trunk/products/ERP5Type/interfaces/property_translatable.py
    erp5/trunk/products/ERP5Type/mixin/__init__.py
    erp5/trunk/products/ERP5Type/mixin/property_translatable.py
Modified:
    erp5/trunk/products/ERP5Type/Accessor/Translation.py
    erp5/trunk/products/ERP5Type/Base.py
    erp5/trunk/products/ERP5Type/TranslationProviderBase.py
    erp5/trunk/products/ERP5Type/Utils.py
    erp5/trunk/products/ERP5Type/patches/Localizer.py

Modified: erp5/trunk/products/ERP5Type/Accessor/Translation.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/Accessor/Translation.py?rev=30269&r1=30268&r2=30269&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/Accessor/Translation.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/Accessor/Translation.py [utf8] Wed Nov  4 08:19:44 2009
@@ -26,15 +26,74 @@
 #
 ##############################################################################
 
-from Base import func_code, ATTRIBUTE_PREFIX, evaluateTales, Getter as BaseGetter
 from zLOG import LOG
 from Products.ERP5Type.PsycoWrapper import psyco
 from Acquisition import aq_base
 from Products.CMFCore.utils import getToolByName
 
+from Products.ERP5Type.Accessor.Base import func_code, ATTRIBUTE_PREFIX, evaluateTales, Getter as BaseGetter
+from Products.ERP5Type.Accessor import Accessor, AcquiredProperty
+from Products.ERP5Type.Accessor.TypeDefinition import type_definition
+
+
+TRANSLATION_DOMAIN_CONTENT_TRANSLATION = 'content_translation'
+
+
 class TranslatedPropertyGetter(BaseGetter):
   """
   Get the translated property
+  """
+  # This can be called from the Web
+  func_code = func_code()
+  func_code.co_varnames = ('self',)
+  func_code.co_argcount = 1
+  func_defaults = ()
+
+  def __init__(self, id, key, property_id, property_type, language, default=None, warning=0):
+    self._id = id
+    self.__name__ = id
+    self._property_id = property_id
+    self._null = type_definition[property_type]['null']
+    self._language = language
+    self._default = default
+    self._warning = warning
+
+  def __call__(self, instance, *args, **kw):
+    if self._warning:
+      LOG("ERP5Type Deprecated Getter Id:",0, self._id)
+    domain = instance.getProperty('%s_translation_domain' % self._property_id)
+
+    if domain==TRANSLATION_DOMAIN_CONTENT_TRANSLATION:
+      if len(args) > 0:
+        default = args[0]
+      else:
+        default = self._default
+
+      if self._language is None:
+        language = kw.get('language') or getToolByName(instance, 'Localizer').get_selected_language()
+      else:
+        language = self._language
+      try:
+        return instance.getPropertyTranslation(self._property_id, language)
+      except KeyError:
+        return default
+    else:
+      value = instance.getProperty(self._property_id)
+      if domain == '' or (value in ('', None)):
+        return value
+      localizer = getToolByName(instance, 'Localizer')
+      message_catalog = getattr(localizer, domain, None)
+      if message_catalog is not None:
+        return message_catalog.gettext(unicode(value, 'utf8'), lang=self._language).encode('utf8')
+      else:
+        return value
+
+  psyco.bind(__call__)
+
+
+class PropertyTranslationDomainGetter(BaseGetter):
+  """
+  Get the translation domain
   """
   _need__name__=1
 
@@ -44,45 +103,10 @@
   func_code.co_argcount = 1
   func_defaults = ()
 
-  def __init__(self, id, key, warning=0):
-    self._id = id
-    self.__name__ = id
-    self._key = key
-    self._original_key = key.replace('translated_', '')
-    self._warning = warning
-
-  def __call__(self, instance, *args, **kw):
-    if self._warning:
-      LOG("ERP5Type Deprecated Getter Id:",0, self._id)
-    domain = instance.getProperty('%s_translation_domain' %
-                                  self._original_key)
-    value = instance.getProperty(self._original_key)
-    if domain == '' or (value in ('', None)):
-      return value
-    localizer = getToolByName(instance, 'Localizer')
-    return localizer[domain].gettext(unicode(value, 'utf8')).encode('utf8')
-
-  psyco.bind(__call__)
-
-
-class PropertyTranslationDomainGetter(BaseGetter):
-  """
-  Get the translation domain
-  """
-  _need__name__=1
-
-  # This can be called from the Web
-  func_code = func_code()
-  func_code.co_varnames = ('self', )
-  func_code.co_argcount = 1
-  func_defaults = ()
-
   def __init__(self, id, key, property_type, default=None, storage_id=None):
     self._id = id
     self.__name__ = id
-    self._key = key
     self._original_key = key.replace('_translation_domain', '')
-    self._property_type = property_type
     self._default = default
     if storage_id is None:
       storage_id = "%s%s" % (ATTRIBUTE_PREFIX, key)
@@ -126,3 +150,68 @@
   psyco.bind(__call__)
 
 
+class TranslationPropertySetter(Accessor.Accessor):
+  """
+  Set a translation into language-property pair dict.
+  """
+  _need__name__=1
+
+  # Generic Definition of Method Object
+  # This is required to call the method form the Web
+  # More information at http://www.zope.org/Members/htrd/howto/FunctionTemplate
+  func_code = func_code()
+  func_code.co_varnames = ('self', 'value')
+  func_code.co_argcount = 2
+  func_defaults = ()
+
+  def __init__(self, id, key, property_id, property_type, language):
+    self._id = id
+    self.__name__ = id
+    self._property_id = property_id
+    self._language = language
+    self._cast = type_definition[property_type]['cast']
+    self._null = type_definition[property_type]['null']
+
+  def __call__(self, instance, *args, **kw):
+    value = args[0]
+    modified_object_list = []
+
+    domain = instance.getProperty('%s_translation_domain' % self._property_id)
+    if domain==TRANSLATION_DOMAIN_CONTENT_TRANSLATION:
+      if value in self._null:
+        instance.deletePropertyTranslation(self._property_id, self._language)
+      else:
+        original_property_value = instance.getProperty(self._property_id)
+        instance.setPropertyTranslation(self._property_id, self._language, original_property_value, self._cast(args[0]))
+        modified_object_list.append(instance)
+    else:
+      pass
+      #raise RuntimeError, 'The property %s.%s is not writable.' % (instance.portal_type, self._property_id)
+    return modified_object_list
+
+
+class AcquiredPropertyGetter(AcquiredProperty.Getter):
+
+    def __call__(self, instance, *args, **kw):
+      if len(args) > 0:
+        default = args[0]
+      else:
+        default = None
+      value = instance._getDefaultAcquiredProperty(self._key, None, self._null,
+            base_category=self._acquisition_base_category,
+            portal_type=self._acquisition_portal_type,
+            accessor_id=self._acquisition_accessor_id,
+            copy_value=self._acquisition_copy_value,
+            mask_value=self._acquisition_mask_value,
+            sync_value=self._acquisition_sync_value,
+            storage_id=self._storage_id,
+            alt_accessor_id=self._alt_accessor_id,
+            acquisition_object_id=self._acquisition_object_id,
+            is_list_type=self._is_list_type,
+            is_tales_type=self._is_tales_type,
+            checked_permission=kw.get('checked_permission', None)
+            )
+      if value is not None:
+        return value.getProperty(self._acquired_property, default, **kw)
+      else:
+        return default

Modified: erp5/trunk/products/ERP5Type/Base.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/Base.py?rev=30269&r1=30268&r2=30269&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/Base.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/Base.py [utf8] Wed Nov  4 08:19:44 2009
@@ -64,6 +64,7 @@
 from Products.ERP5Type.Accessor.Accessor import Accessor
 from Products.ERP5Type.Accessor.TypeDefinition import list_types
 from Products.ERP5Type.Accessor import Base as BaseAccessor
+from Products.ERP5Type.mixin.property_translatable import PropertyTranslatableBuiltInDictMixIn
 from Products.ERP5Type.XMLExportImport import Base_asXML
 from Products.ERP5Type.Cache import CachingMethod, clearCache, getReadOnlyTransactionCache
 from Accessor import WorkflowState
@@ -711,7 +712,9 @@
             PortalContent,
             ActiveObject,
             OFS.History.Historical,
-            ERP5PropertyManager ):
+            ERP5PropertyManager,
+            PropertyTranslatableBuiltInDictMixIn
+            ):
   """
     This is the base class for all ERP5 Zope objects.
     It defines object attributes which are necessary to implement

Modified: erp5/trunk/products/ERP5Type/TranslationProviderBase.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/TranslationProviderBase.py?rev=30269&r1=30268&r2=30269&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/TranslationProviderBase.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/TranslationProviderBase.py [utf8] Wed Nov  4 08:19:44 2009
@@ -24,6 +24,9 @@
 
 import Products
 
+from Products.ERP5Type.Accessor import Translation
+from Products.CMFCore.utils import getToolByName
+
 from zLOG import LOG
 
 _MARKER = {}
@@ -85,6 +88,23 @@
       self.updateInitialPropertyTranslationDomainDict()
     return dict((k, v.__of__(self))
                 for k, v in self._property_domain_dict.iteritems())
+
+  security.declarePublic('getContentTranslationDomainPropertyNameList')
+  def getContentTranslationDomainPropertyNameList(self):
+    result = []
+    for property_name, translation_information in self.getPropertyTranslationDomainDict().items():
+      if translation_information.getDomainName()==Translation.TRANSLATION_DOMAIN_CONTENT_TRANSLATION:
+        result.append(property_name)
+    return result
+
+  security.declarePublic('getTranslationDomainNameList')
+  def getTranslationDomainNameList(self):
+    return (['']+
+            [object_.id
+             for object_ in getToolByName(self, 'Localizer').objectValues()
+             if object_.meta_type=='MessageCatalog']+
+            [Translation.TRANSLATION_DOMAIN_CONTENT_TRANSLATION]
+            )
 
   #
   #   ZMI methods
@@ -105,13 +125,13 @@
       t['domain_name'] = prop.getDomainName()
       translation_list.append(t)
 
-    # get list of Localizer catalog, add 'empty' one for no traduction
-    catalog = self.getPortalObject().Localizer.objectIds() + ['']
-
+    # get a list of message catalogs and add empty one for no traduction and
+    # add another for content translation.
+    translation_domain_list = self.getTranslationDomainNameList()
     return self._translation_form( self
                                    , REQUEST
                                    , translations = translation_list
-                                   , possible_domain_names=catalog
+                                   , possible_domain_names=translation_domain_list
                                    , management_view='Translation'
                                    , manage_tabs_message=manage_tabs_message
                                    )

Modified: erp5/trunk/products/ERP5Type/Utils.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/Utils.py?rev=30269&r1=30268&r2=30269&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/Utils.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/Utils.py [utf8] Wed Nov  4 08:19:44 2009
@@ -210,6 +210,19 @@
     return _cached_convertToUpperCase[key]
 
 UpperCase = convertToUpperCase
+
+def convertToLowerCase(key):
+  tmp = []
+  assert(key[0].isupper())
+  for i in key:
+    if i.isupper():
+      tmp.append('_')
+      tmp.append(i.lower())
+    else:
+      tmp.append(i)
+  return ''.join(tmp)
+LowerCase = convertToLowerCase
+
 
 def convertToMixedCase(key):
   """
@@ -919,6 +932,7 @@
       if not m.has_key(name): m[name] = []
       m[name].append(method)
     m[name+'__roles__']=pr
+  return document_class, constructors
 
 def initializeLocalRegistry(directory_name, import_local_method,
                             path_arg_name='path'):
@@ -1317,7 +1331,8 @@
                         '%s_range_%s' % (prop['id'], value),
                         prop=range_prop,
                         read_permission=read_permission,
-                        write_permission=write_permission)
+                        write_permission=write_permission,
+                        portal=portal)
 
         # Create translation accesor, if translatable is set
         if prop.get('translatable', 0):
@@ -1325,8 +1340,15 @@
           createTranslationAccessors(
                     property_holder,
                     'translated_%s' % (prop['id']),
+                    prop,
                     read_permission=read_permission,
                     write_permission=write_permission)
+          createTranslationLanguageAccessors(
+                    property_holder,
+                    prop,
+                    read_permission=read_permission,
+                    write_permission=write_permission,
+                    portal=portal)
           # make accessor to translation_domain
           # first create default one as a normal property
           txn_prop = {}
@@ -1340,7 +1362,8 @@
                     '%s_%s' %(prop['id'], txn_prop['id']),
                     prop=txn_prop,
                     read_permission=read_permission,
-                    write_permission=write_permission)
+                    write_permission=write_permission,
+                    portal=portal)
           # then overload accesors getPropertyTranslationDomain
           if prop.has_key('translation_domain'):
             default = prop['translation_domain']
@@ -1349,6 +1372,7 @@
           createTranslationAccessors(
                           property_holder,
                           '%s_translation_domain' % (prop['id']),
+                          prop,
                           read_permission=read_permission,
                           write_permission=write_permission,
                           default=default)
@@ -1357,7 +1381,8 @@
                         prop['id'],
                         prop=prop,
                         read_permission=read_permission,
-                        write_permission=write_permission)
+                        write_permission=write_permission,
+                        portal=portal)
       else:
         raise TypeError, '"%s" is invalid type for propertysheet' % \
                                             prop['type']
@@ -1380,7 +1405,8 @@
                         prop['id'],
                         prop=prop,
                         read_permission=Permissions.AccessContentsInformation,
-                        write_permission=Permissions.ModifyPortalContent)
+                        write_permission=Permissions.ModifyPortalContent,
+                        portal=portal)
 
       # Get read and write permission
       if portal is not None:
@@ -1508,7 +1534,8 @@
 
 def createDefaultAccessors(property_holder, id, prop = None,
     read_permission=Permissions.AccessContentsInformation,
-    write_permission=Permissions.ModifyPortalContent):
+    write_permission=Permissions.ModifyPortalContent,
+    portal=None):
   """
     This function creates accessor and setter for a class
     and a property
@@ -1519,6 +1546,12 @@
 
     prop  -- the property definition of the property
   """
+  ######################################################
+  # Create Translation Acquired Accessors.
+  if prop.get('translation_acquired_property_id'):
+    createTranslationAcquiredPropertyAccessors(property_holder, prop,
+                                               portal=portal)
+
   ######################################################
   # Create Getters
   if prop.has_key('acquisition_base_category'):
@@ -2565,27 +2598,196 @@
           if accessor_name[0] != '_':
             BaseClass.security.declareProtected(read_permission, accessor_name)
 
-def createTranslationAccessors(property_holder, id,
+def createTranslationAcquiredPropertyAccessors(
+  property_holder,
+  property,
+  read_permission=Permissions.AccessContentsInformation,
+  write_permission=Permissions.ModifyPortalContent,
+  portal=None):
+  """Generate translation acquired property accessor to Base class"""
+  property = property.copy()
+  translation_acquired_property_id_list = []
+  accessor_dict_list = []
+
+  # Language Dependent Getter/Setter
+  for language in portal.Localizer.get_languages():
+    language_key = language.replace('-', '_')
+    for acquired_property_id in property['acquired_property_id']:
+      key = '%s_translated_%s' % (language_key, acquired_property_id)
+      capitalised_composed_id = UpperCase("%s_%s" % (property['id'], key))
+      accessor_args = (
+        property['type'],
+        property['portal_type'],
+        key,
+        property['acquisition_base_category'],
+        property['acquisition_portal_type'],
+        property['acquisition_accessor_id'],
+        property.get('acquisition_copy_value',0),
+        property.get('acquisition_mask_value',0),
+        property.get('acquisition_sync_value',0),
+        property.get('storage_id'),
+        property.get('alt_accessor_id'),
+        property.get('acquisition_object_id'),
+        (property['type'] in list_types or property.get('multivalued', 0)),
+        (property['type'] == 'tales'),
+        )
+
+      accessor_dict_list.append({'name':'get' + capitalised_composed_id,
+                                 'key': key,
+                                 'class':Translation.AcquiredPropertyGetter,
+                                 'argument':accessor_args,
+                                 'permission':read_permission})
+      accessor_dict_list.append({'name':'_baseGet' + capitalised_composed_id,
+                                 'key': key,
+                                 'class':Translation.AcquiredPropertyGetter,
+                                 'argument':accessor_args,
+                                 'permission':read_permission})
+      accessor_dict_list.append({'name': 'getDefault' + capitalised_composed_id,
+                                 'key': key,
+                                 'class': Translation.AcquiredPropertyGetter,
+                                 'argument': accessor_args,
+                                 'permission': read_permission})
+      accessor_dict_list.append({'name': 'set' + capitalised_composed_id,
+                                 'key': '_set' + capitalised_composed_id,
+                                 'class': Alias.Reindex,
+                                 'argument': (),
+                                 'permission': write_permission})
+      accessor_dict_list.append({'name': '_set' + capitalised_composed_id,
+                                 'key': key,
+                                 'class': AcquiredProperty.DefaultSetter,
+                                 'argument': accessor_args,
+                                 'permission': write_permission})
+      accessor_dict_list.append({'name': 'setDefault' + capitalised_composed_id,
+                                 'key': '_set' + capitalised_composed_id,
+                                 'class': Alias.Reindex,
+                                 'argument': (),
+                                 'permission': write_permission})
+
+  # Language Independent Getter
+  for acquired_property_id in property['acquired_property_id']:
+    if acquired_property_id in property.get('translation_acquired_property_id',()):
+      key = 'translated_%s' % acquired_property_id
+      capitalised_composed_id = UpperCase('%s_%s' % (property['id'], key))
+      accessor_args = (
+        property['type'],
+        property['portal_type'],
+        key,
+        property['acquisition_base_category'],
+        property['acquisition_portal_type'],
+        property['acquisition_accessor_id'],
+        property.get('acquisition_copy_value',0),
+        property.get('acquisition_mask_value',0),
+        property.get('acquisition_sync_value',0),
+        property.get('storage_id'),
+        property.get('alt_accessor_id'),
+        property.get('acquisition_object_id'),
+        (property['type'] in list_types or property.get('multivalued', 0)),
+        (property['type'] == 'tales'),
+        )
+
+      accessor_dict_list.append({'name': 'get' + capitalised_composed_id,
+                                 'key': key,
+                                 'class': Translation.AcquiredPropertyGetter,
+                                 'argument': accessor_args,
+                                 'permission': read_permission})
+      accessor_dict_list.append({'name': '_baseGet' + capitalised_composed_id,
+                                 'key': key,
+                                 'class': Translation.AcquiredPropertyGetter,
+                                 'argument': accessor_args,
+                                 'permission': read_permission})
+      accessor_dict_list.append({'name': 'getDefault' + capitalised_composed_id,
+                                 'key': key,
+                                 'class': Translation.AcquiredPropertyGetter,
+                                 'argument': accessor_args,
+                                 'permission': read_permission})
+
+  for accessor_dict in accessor_dict_list:
+    accessor_name = accessor_dict['name']
+    if getattr(property_holder, accessor_name, None) is None:
+      property_holder.registerAccessor(accessor_name, # id
+                                       accessor_dict['key'],
+                                       accessor_dict['class'],
+                                       accessor_dict['argument'])
+      property_holder.declareProtected(accessor_dict['permission'],
+                                       accessor_name)
+
+def createTranslationAccessors(property_holder, id, property,
     read_permission=Permissions.AccessContentsInformation,
     write_permission=Permissions.ModifyPortalContent, default=''):
   """
   Generate the translation accessor for a class and a property
   """
+  capitalised_id = UpperCase(id)
   if 'translated' in id:
-    accessor_name = 'get' + UpperCase(id)
+    accessor_name = 'get' + capitalised_id
+    private_accessor_name = '_baseGet' + capitalised_id
     if not hasattr(property_holder, accessor_name):
-      property_holder.registerAccessor(accessor_name, id, Translation.TranslatedPropertyGetter, ())
+      property_holder.registerAccessor(accessor_name,
+                                       id,
+                                       Translation.TranslatedPropertyGetter,
+                                       (property['id'], property['type'], None, default))
       property_holder.declareProtected(read_permission, accessor_name)
-    accessor_name = '_baseGet' + UpperCase(id)
-    if not hasattr(property_holder, accessor_name):
-      property_holder.registerAccessor(accessor_name, id, Translation.TranslatedPropertyGetter, ())
+    if not hasattr(property_holder, private_accessor_name):
+      property_holder.registerAccessor(private_accessor_name,
+                                       id,
+                                       Translation.TranslatedPropertyGetter,
+                                       (property['id'], property['type'], None, default))
 
   if 'translation_domain' in id:
     # Getter
-    accessor_name = 'get' + UpperCase(id)
-    property_holder.registerAccessor(accessor_name, id,
-        Translation.PropertyTranslationDomainGetter, ('string', default,))
-    property_holder.declareProtected(read_permission, accessor_name)
+    accessor_name = 'get' + capitalised_id
+    property_holder.registerAccessor(accessor_name,
+                                     id,
+                                     Translation.PropertyTranslationDomainGetter,
+                                     ('string', default,))
+    property_holder.declareProtected(read_permission, accessor_name)
+
+
+def createTranslationLanguageAccessors(property_holder, property,
+    read_permission=Permissions.AccessContentsInformation,
+    write_permission=Permissions.ModifyPortalContent, default='',
+    portal=None):
+  """
+  Generate translation language accessors
+  """
+  accessor_dict_list = []
+
+  for language in portal.Localizer.get_languages():
+    language_key = language.replace('-', '_')
+    composed_id = '%s_translated_%s' % (language_key, property['id'])
+    capitalised_compose_id = UpperCase(composed_id)
+
+    getter_accessor_args = (property['id'], property['type'], language, default)
+    accessor_dict_list.append({'name': 'get' + capitalised_compose_id,
+                               'class': Translation.TranslatedPropertyGetter,
+                               'argument': getter_accessor_args,
+                               'permission': read_permission})
+    accessor_dict_list.append({'name': '_baseGet' + capitalised_compose_id,
+                               'class': Translation.TranslatedPropertyGetter,
+                               'argument': getter_accessor_args,
+                               'permission': read_permission})
+
+    setter_accessor_args = (property['id'], property['type'], language)
+    accessor_dict_list.append({'name':'set' + capitalised_compose_id,
+                               'key': '_set' + capitalised_compose_id,
+                               'class': Alias.Reindex,
+                               'argument': (),
+                               'permission': write_permission})
+    setter_accessor_args = (property['id'], property['type'], language)
+    accessor_dict_list.append({'name': '_set' + capitalised_compose_id,
+                               'class': Translation.TranslationPropertySetter,
+                               'argument': setter_accessor_args,
+                               'permission': write_permission})
+
+  for accessor_dict in accessor_dict_list:
+    accessor_name = accessor_dict['name']
+    if getattr(property_holder, accessor_name, None) is None:
+      property_holder.registerAccessor(accessor_name,
+                                       accessor_dict.get('key', None),
+                                       accessor_dict['class'],
+                                       accessor_dict['argument'])
+      property_holder.declareProtected(accessor_dict['permission'],
+                                       accessor_name)
 
 
 #####################################################

Added: erp5/trunk/products/ERP5Type/interfaces/property_translatable.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/interfaces/property_translatable.py?rev=30269&view=auto
==============================================================================
--- erp5/trunk/products/ERP5Type/interfaces/property_translatable.py (added)
+++ erp5/trunk/products/ERP5Type/interfaces/property_translatable.py [utf8] Wed Nov  4 08:19:44 2009
@@ -1,0 +1,47 @@
+##############################################################################
+#
+# Copyright (c) 2009 Nexedi KK, Nexedi SA and Contributors. All Rights Reserved.
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# This program is Free Software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+##############################################################################
+from zope.interface import Interface
+
+
+class IPropertyTranslatable(Interface):
+  """
+  """
+
+  def getPropertyTranslation(property_id, language):
+    """Retrieve translation text."""
+
+  def setPropertyTranslation(property_id, language, original_text, translation):
+    """Store translation text."""
+
+  def deletePropertyTranslation(property_id, language):
+    """Delete translation text."""
+
+  def getPropertyTranslationOriginalText(property_id, language):
+    """Retrieve original text which is used for translation."""
+
+  def isPropertyTranslated(property_id, language):
+    """Return True if property is translated, else return False"""

Added: erp5/trunk/products/ERP5Type/mixin/__init__.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/mixin/__init__.py?rev=30269&view=auto
==============================================================================
    (empty)

Added: erp5/trunk/products/ERP5Type/mixin/property_translatable.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/mixin/property_translatable.py?rev=30269&view=auto
==============================================================================
--- erp5/trunk/products/ERP5Type/mixin/property_translatable.py (added)
+++ erp5/trunk/products/ERP5Type/mixin/property_translatable.py [utf8] Wed Nov  4 08:19:44 2009
@@ -1,0 +1,86 @@
+##############################################################################
+#
+# Copyright (c) 2009 Nexedi KK, Nexedi SA and Contributors. All Rights Reserved.
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# This program is Free Software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+##############################################################################
+
+import zope.interface
+from Products.ERP5Type.interfaces.property_translatable import IPropertyTranslatable
+from AccessControl import ClassSecurityInfo
+from Products.ERP5Type import Permissions
+from Globals import InitializeClass
+
+
+INTERNAL_TRANSLATION_DICT_NAME = '__translation_dict'
+
+class PropertyTranslatableBuiltInDictMixIn:
+  """An implementation of IPropertyTranslatable with built-in dict."""
+
+  zope.interface.implements(IPropertyTranslatable)
+
+  security = ClassSecurityInfo()
+
+  def _getTranslationDict(self):
+    try:
+      return getattr(self, INTERNAL_TRANSLATION_DICT_NAME)
+    except AttributeError:
+      dict_ = {}
+      setattr(self, INTERNAL_TRANSLATION_DICT_NAME, dict_)
+      self._p_changed = True
+      return dict_
+
+  security.declareProtected(Permissions.AccessContentsInformation,
+                            'getPropertyTranslation')
+  def getPropertyTranslation(self, property_id, language):
+    return self._getTranslationDict()[(property_id, language)][1]
+
+  security.declareProtected(Permissions.ModifyPortalContent,
+                            'setPropertyTranslation')
+  def setPropertyTranslation(self, property_id, language, original_text, translation):
+    self._getTranslationDict()[(property_id, language)] = (original_text, translation)
+    self._p_changed = True
+
+  security.declareProtected(Permissions.ModifyPortalContent,
+                            'deletePropertyTranslation')
+  def deletePropertyTranslation(self, property_id, language):
+    try:
+      del self._getTranslationDict()[(property_id, language)]
+    except KeyError:
+      pass
+
+  security.declareProtected(Permissions.AccessContentsInformation,
+                            'getPropertyTranslationOriginalText')
+  def getPropertyTranslationOriginalText(self, property_id, language):
+    return self._getTranslationDict()[(property_id, language)][0]
+
+  security.declareProtected(Permissions.AccessContentsInformation,
+                          'isPropertyTranslated')  
+  def isPropertyTranslated(self, property_id, language):
+    try:
+      self._getTranslationDict()[(property_id, language)]
+      return True
+    except KeyError:
+      return False
+
+InitializeClass(PropertyTranslatableBuiltInDictMixIn)

Modified: erp5/trunk/products/ERP5Type/patches/Localizer.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/patches/Localizer.py?rev=30269&r1=30268&r2=30269&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/patches/Localizer.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/patches/Localizer.py [utf8] Wed Nov  4 08:19:44 2009
@@ -126,3 +126,128 @@
   return original_manage_export(self, x, REQUEST=REQUEST, RESPONSE=RESPONSE)
 MessageCatalog.manage_export = cleanup_and_export
 
+
+# Add a feature which allows users to be able to add a new language.
+#
+# Patch to LanguageManager.py
+#
+def get_languages_mapping(self):
+    """
+    Returns a list of dictionary, one for each objects language. The
+    dictionary contains the language code, its name and a boolean
+    value that tells wether the language is the default one or not.
+    """
+    return [ {'code': x,
+              'name': self.get_language_name(x),
+              'default': x == self._default_language}
+             for x in self._languages ]
+
+def get_language_name(self, id=None):
+    """
+    Returns the name of the given language code.
+
+    XXX Kept here for backwards compatibility only
+    """
+    if id is None:
+        id = self.get_default_language()
+    language_name = LanguageManager.i18n.get_language_name(id)
+    if language_name=='???':
+        return self.get_user_defined_language_name(id) or language_name
+    else:
+        return language_name
+
+# New method
+def get_user_defined_language_name(self, id=None):
+    """
+    Returns the name of the given user defined language code.
+    """
+    for language_dict in self.get_user_defined_languages():
+        if language_dict['code']==id:
+            return language_dict['name']
+
+def get_all_languages(self):
+    """
+    Returns all ISO languages, used by 'manage_languages'.
+    """
+    return LanguageManager.i18n.get_languages() + self.get_user_defined_languages()
+
+# New method
+def get_user_defined_languages(self):
+    user_define_language_dict_list = []
+    localizer = getattr(self, 'Localizer', None)
+    if localizer is not None:
+        for value in getattr(self, 'user_defined_languages', ()):
+            splitted_value = value.split(' ', 1)
+            if len(splitted_value)==2:
+                user_define_language_dict_list.append(
+                    {'name':splitted_value[0].strip(),
+                     'code':splitted_value[1].strip(),})
+    return user_define_language_dict_list
+
+# New method
+def _add_user_defined_language(self, language_name, language_code):
+    self.user_defined_languages = (
+        getattr(self, 'user_defined_languages', ())+
+        ('%s %s' % (language_name, language_code),)
+        )
+    self._p_changed = True
+
+# New method
+def _del_user_defined_language(self, language_code):
+    user_defined_languages = []
+    for language_dict in self.get_user_defined_languages():
+        if language_dict['code']!=language_code:
+            user_defined_languages.append('%s %s' %
+                                          (language_dict['name'],
+                                           language_dict['code']))
+    self.user_defined_languages = tuple(user_defined_languages)
+    self._p_changed = True
+
+from Products.Localizer import LanguageManager
+LanguageManager.LanguageManager.get_languages_mapping = get_languages_mapping
+LanguageManager.LanguageManager.get_language_name = get_language_name
+LanguageManager.LanguageManager.get_all_languages = get_all_languages
+LanguageManager.LanguageManager.get_user_defined_language_name = get_user_defined_language_name
+LanguageManager.LanguageManager.get_user_defined_languages = get_user_defined_languages
+LanguageManager.LanguageManager._add_user_defined_language = _add_user_defined_language
+LanguageManager.LanguageManager._del_user_defined_language = _del_user_defined_language
+LanguageManager.InitializeClass(LanguageManager.LanguageManager)
+
+#
+# Patch to Localizer.py
+#
+_properties = ({'id': 'title', 'type': 'string'},
+               {'id': 'accept_methods', 'type': 'tokens'},
+               {'id': 'user_defined_languages', 'type': 'lines'},)
+
+user_defined_languages = ()
+
+def get_languages_map(self):
+    """
+    Return a list of dictionaries, each dictionary has the language
+    id, its title and a boolean value to indicate wether it's the
+    user preferred language, for example:
+       [{'id': 'en', 'title': 'English', 'selected': 1}]
+     Used in changeLanguageForm.
+    """
+    # For now only LPM instances are considered to be containers of
+    # multilingual data.
+    try:
+        ob = self.getLocalPropertyManager()
+    except AttributeError:
+        ob = self
+
+    ob_language = ob.get_selected_language()
+    ob_languages = ob.get_available_languages()
+
+    langs = []
+    for x in ob_languages:
+        langs.append({'id': x, 'title': self.get_language_name(x),
+                      'selected': x == ob_language})
+    return langs
+
+from Products.Localizer import Localizer
+Localizer.Localizer._properties = _properties
+Localizer.Localizer.user_defined_languages = user_defined_languages
+Localizer.Localizer.get_languages_map = get_languages_map
+Localizer.InitializeClass(Localizer.Localizer)




More information about the Erp5-report mailing list