appy.gen: solved a tricky encoding problem.

This commit is contained in:
Gaetan Delannay 2011-12-08 16:01:57 +01:00
parent d5f26dd1df
commit c1174fac79
6 changed files with 60 additions and 67 deletions

View file

@ -1 +1 @@
0.7.1 0.8.0

View file

@ -2556,8 +2556,7 @@ class Transition:
notifier.sendMail(obj.appy(), self, transitionName, wf) notifier.sendMail(obj.appy(), self, transitionName, wf)
# Return a message to the user if needed # Return a message to the user if needed
if not doSay or (transitionName == '_init_'): return if not doSay or (transitionName == '_init_'): return
if not msg: if not msg: msg = 'Changes saved.' # XXX Translate
msg = obj.translate(u'Changes saved.')
obj.say(msg) obj.say(msg)
class Permission: class Permission:

View file

@ -370,15 +370,21 @@ class ToolMixin(BaseMixin):
maxWidth = appyType['width'] maxWidth = appyType['width']
if isinstance(value, str): value = value.decode('utf-8') if isinstance(value, str): value = value.decode('utf-8')
if len(value) > maxWidth: if len(value) > maxWidth:
return value[:maxWidth] + '...' return value[:maxWidth].encode('utf-8') + '...'
return value return value.encode('utf-8')
def truncateText(self, text, width=15): def truncateText(self, text, width=15):
'''Truncates p_text to max p_width chars. If the text is longer than '''Truncates p_text to max p_width chars. If the text is longer than
p_width, the truncated part is put in a "acronym" html tag.''' p_width, the truncated part is put in a "acronym" html tag.'''
if isinstance(text, str): text = text.decode('utf-8') # p_text has to be unicode-encoded for being truncated (else, one char
if len(text) <= width: return text # may be spread on 2 chars). But this method must return an encoded
return '<acronym title="%s">%s</acronym>' % (text, text[:width] + '...') # string, else, ZPT crashes. The same remark holds for m_truncateValue
# above.
uText = text # uText will store the unicode version
if isinstance(text, str): uText = text.decode('utf-8')
if len(uText) <= width: return text
return '<acronym title="%s">%s</acronym>' % \
(text, uText[:width].encode('utf-8') + '...')
def getPublishedObject(self): def getPublishedObject(self):
'''Gets the currently published object, if its meta_class is among '''Gets the currently published object, if its meta_class is among
@ -820,9 +826,8 @@ class ToolMixin(BaseMixin):
urlBack = rq['HTTP_REFERER'] urlBack = rq['HTTP_REFERER']
if jsEnabled and not cookiesEnabled: if jsEnabled and not cookiesEnabled:
msg = self.translate(u'You must enable cookies before you can ' \ msg = 'You must enable cookies before you can log in.' # XXX transl.
'log in.') return self.goto(urlBack, msg)
return self.goto(urlBack, msg.encode('utf-8'))
# Perform the Zope-level authentication # Perform the Zope-level authentication
login = rq.get('__ac_name', '') login = rq.get('__ac_name', '')
password = rq.get('__ac_password', '') password = rq.get('__ac_password', '')
@ -832,12 +837,11 @@ class ToolMixin(BaseMixin):
user = self.acl_users.validate(rq) user = self.acl_users.validate(rq)
if self.userIsAnon(): if self.userIsAnon():
rq.RESPONSE.expireCookie('__ac', path='/') rq.RESPONSE.expireCookie('__ac', path='/')
msg = self.translate(u'Login failed') msg = 'Login failed' # XXX to translate
logMsg = 'Authentication failed (tried with login "%s")' % login logMsg = 'Authentication failed (tried with login "%s")' % login
else: else:
msg = self.translate(u'Welcome! You are now logged in.') msg = 'Welcome! You are now logged in.' # XXX to translate
logMsg = 'User "%s" has been logged in.' % login logMsg = 'User "%s" has been logged in.' % login
msg = msg.encode('utf-8')
self.log(logMsg) self.log(logMsg)
# Bring Managers to the config, leave others on the main page. # Bring Managers to the config, leave others on the main page.
user = self.getUser() user = self.getUser()

View file

@ -184,7 +184,7 @@ class BaseMixin:
fields in the database.''' fields in the database.'''
rq = self.REQUEST rq = self.REQUEST
tool = self.getTool() tool = self.getTool()
errorMessage = self.translate('Please correct the indicated errors.') errorMessage = 'Please correct the indicated errors.' # XXX Translate
isNew = rq.get('is_new') == 'True' isNew = rq.get('is_new') == 'True'
# If this object is created from an initiator, get info about him. # If this object is created from an initiator, get info about him.
initiator = None initiator = None
@ -205,7 +205,7 @@ class BaseMixin:
urlBack = tool.getSiteUrl() urlBack = tool.getSiteUrl()
else: else:
urlBack = self.getUrl() urlBack = self.getUrl()
self.say(self.translate('Changes canceled.')) self.say('Changes canceled.') # XXX Translate
return self.goto(urlBack) return self.goto(urlBack)
# Object for storing validation errors # Object for storing validation errors
@ -241,7 +241,7 @@ class BaseMixin:
obj, msg = self.createOrUpdate(isNew, values, initiator, initiatorField) obj, msg = self.createOrUpdate(isNew, values, initiator, initiatorField)
# Redirect the user to the appropriate page # Redirect the user to the appropriate page
if not msg: msg = obj.translate('Changes saved.') if not msg: msg = 'Changes saved.' # XXX Translate
# If the object has already been deleted (ie, it is a kind of transient # If the object has already been deleted (ie, it is a kind of transient
# object like a one-shot form and has already been deleted in method # object like a one-shot form and has already been deleted in method
# onEdit), redirect to the main site page. # onEdit), redirect to the main site page.
@ -1058,7 +1058,7 @@ class BaseMixin:
instead of returning a list of string values, the result is a list instead of returning a list of string values, the result is a list
of tuples (s_value, s_translation). If p_withBlankValue is True, a of tuples (s_value, s_translation). If p_withBlankValue is True, a
blank value is prepended to the list. If no p_className is defined, blank value is prepended to the list. If no p_className is defined,
the field is supposed to belong to self's class''' the field is supposed to belong to self's class.'''
appyType = self.getAppyType(name, className=className) appyType = self.getAppyType(name, className=className)
if className: if className:
# We need an instance of className, but self can be an instance of # We need an instance of className, but self can be an instance of
@ -1333,51 +1333,40 @@ class BaseMixin:
p_mapping.''' p_mapping.'''
cfg = self.getProductConfig() cfg = self.getProductConfig()
if not domain: domain = cfg.PROJECTNAME if not domain: domain = cfg.PROJECTNAME
if domain != cfg.PROJECTNAME: # Get the label name, and the field-specific mapping if any.
# We need to translate something that is in a standard Zope catalog if field:
try: # p_field is the dict version of a appy type or group
res = self.Control_Panel.TranslationService.utranslate( if field['type'] != 'group':
domain, label, mapping, self, default=default, fieldMapping = field['mapping'][label]
target_language=language) if fieldMapping:
except AttributeError: if callable(fieldMapping):
# When run in test mode, Zope does not create the appyField = self.getAppyType(field['name'])
# TranslationService fieldMapping=appyField.callMethod(self,fieldMapping)
res = label mapping.update(fieldMapping)
else: label = field['%sId' % label]
# Get the label name, and the field-specific mapping if any. # We will get the translation from a Translation object.
if field: # In what language must we get the translation?
# p_field is the dict version of a appy type or group if not language: language = self.getUserLanguage()
if field['type'] != 'group': tool = self.getTool()
fieldMapping = field['mapping'][label] try:
if fieldMapping: translation = getattr(tool, language).appy()
if callable(fieldMapping): except AttributeError:
appyField = self.getAppyType(field['name']) # We have no translation for this language. Fallback to 'en'.
fieldMapping=appyField.callMethod(self,fieldMapping) translation = getattr(tool, 'en').appy()
mapping.update(fieldMapping) res = getattr(translation, label, '')
label = field['%sId' % label] if not res:
# We will get the translation from a Translation object. # Fallback to 'en'.
# In what language must we get the translation? translation = getattr(tool, 'en').appy()
if not language: language = self.getUserLanguage()
tool = self.getTool()
try:
translation = getattr(tool, language).appy()
except AttributeError:
# We have no translation for this language. Fallback to 'en'.
translation = getattr(tool, 'en').appy()
res = getattr(translation, label, '') res = getattr(translation, label, '')
if not res: # If still no result, put the label instead of a translated message
# Fallback to 'en'. if not res: res = label
translation = getattr(tool, 'en').appy() else:
res = getattr(translation, label, '') # Perform replacements, according to p_format.
# If still no result, put the label instead of a translated message res = self.formatText(res, format)
if not res: res = label # Perform variable replacements
else: for name, repl in mapping.iteritems():
# Perform replacements, according to p_format. if not isinstance(repl, basestring): repl = str(repl)
res = self.formatText(res, format) res = res.replace('${%s}' % name, repl)
# Perform variable replacements
for name, repl in mapping.iteritems():
if not isinstance(repl, basestring): repl = str(repl)
res = res.replace('${%s}' % name, repl)
return res return res
def getPageLayout(self, layoutType): def getPageLayout(self, layoutType):

View file

@ -8,7 +8,7 @@
_ python: tool.translate; _ python: tool.translate;
req python: request; req python: request;
resp req/RESPONSE; resp req/RESPONSE;
x python: resp.setHeader('Content-Type', 'text/html;;charset=utf-8'); x python: resp.setHeader('Content-Type', 'text/html;;charset=UTF-8');
x python: resp.setHeader('Expires', 'Thu, 11 Dec 1975 12:05:00 GMT+2'); x python: resp.setHeader('Expires', 'Thu, 11 Dec 1975 12:05:00 GMT+2');
x python: resp.setHeader('Content-Language', req.get('language', 'en'))"> x python: resp.setHeader('Content-Language', req.get('language', 'en'))">

View file

@ -13,17 +13,17 @@ class UserWrapper(AbstractWrapper):
'''Is this p_login valid?''' '''Is this p_login valid?'''
# The login can't be the id of the whole site or "admin" # The login can't be the id of the whole site or "admin"
if login == 'admin': if login == 'admin':
return self.translate('This username is reserved.') return 'This username is reserved.' # XXX Translate
# Check that no user or group already uses this login. # Check that no user or group already uses this login.
if self.count('User', login=login) or self.count('Group', login=login): if self.count('User', login=login) or self.count('Group', login=login):
return self.translate('This login is already in use.') return 'This login is already in use.' # XXX Translate
return True return True
def validatePassword(self, password): def validatePassword(self, password):
'''Is this p_password valid?''' '''Is this p_password valid?'''
# Password must be at least 5 chars length # Password must be at least 5 chars length
if len(password) < 5: if len(password) < 5:
return self.translate('Passwords must contain at least 5 letters.') return 'Passwords must contain at least 5 letters.' # XXX Translate
return True return True
def showPassword(self): def showPassword(self):
@ -43,7 +43,8 @@ class UserWrapper(AbstractWrapper):
page = self.request.get('page', 'main') page = self.request.get('page', 'main')
if page == 'main': if page == 'main':
if hasattr(new, 'password1') and (new.password1 != new.password2): if hasattr(new, 'password1') and (new.password1 != new.password2):
msg = self.translate('Passwords do not match.') # XXX Translate
msg = 'Passwords do not match.'
errors.password1 = msg errors.password1 = msg
errors.password2 = msg errors.password2 = msg
return self._callCustom('validate', new, errors) return self._callCustom('validate', new, errors)