[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