New translation system, that generates screens for updating translations through the web, within the configuration.

This commit is contained in:
Gaetan Delannay 2011-01-14 09:06:25 +01:00
parent f3604624de
commit ead9f7c2de
22 changed files with 525 additions and 278 deletions

View file

@ -105,4 +105,8 @@ class ToolWrapper(AbstractWrapper):
res = '%sFor%s' % (attributeType, fullClassName)
if attrName: res += '_%s' % attrName
return res
def getAvailableLanguages(self):
'''Returns the list of available languages for this application.'''
return [(t.id, t.title) for t in self.translations]
# ------------------------------------------------------------------------------

View file

@ -0,0 +1,76 @@
# ------------------------------------------------------------------------------
import os.path
from appy.gen.plone25.wrappers import AbstractWrapper
from appy.gen.po import PoFile, PoMessage
from appy.shared.utils import getOsTempFolder
# ------------------------------------------------------------------------------
class TranslationWrapper(AbstractWrapper):
def computeLabel(self, field):
'''The label for a text to translate displays the text of the
corresponding message in the source translation.'''
tool = self.tool
sourceLanguage = self.o.getProductConfig().sourceLanguage
sourceTranslation = getattr(tool.o, sourceLanguage).appy()
# p_field is the Computed field. We need to get the name of the
# corresponding field holding the translation message.
fieldName = field.name[:-6]
# If we are showing the source translation, we do not repeat the message
# in the label.
if self.id == sourceLanguage:
sourceMsg = ''
else:
sourceMsg = getattr(sourceTranslation,fieldName)
# When editing the value, we don't want HTML code to be interpreted.
# This way, the translator sees the HTML tags and can reproduce them in
# the translation.
if self.request['URL'].endswith('/skyn/edit'):
sourceMsg = sourceMsg.replace('<','&lt;').replace('>','&gt;')
sourceMsg = sourceMsg.replace('\n', '<br/>')
return '<div class="translationLabel"><acronym title="%s">' \
'<img src="help.png"/></acronym>%s</div>' % \
(fieldName, sourceMsg)
def showField(self, field):
'''We show a field (or its label) only if the corresponding source
message is not empty.'''
tool = self.tool
if field.type == 'Computed': name = field.name[:-6]
else: name = field.name
# Get the source message
sourceLanguage = self.o.getProductConfig().sourceLanguage
sourceTranslation = getattr(tool.o, sourceLanguage).appy()
sourceMsg = getattr(sourceTranslation, name)
if field.isEmptyValue(sourceMsg): return False
return True
poReplacements = ( ('\r\n', '<br/>'), ('\n', '<br/>'), ('"', '\\"') )
def getPoFile(self):
'''Computes and returns the PO file corresponding to this
translation.'''
tool = self.tool
fileName = os.path.join(getOsTempFolder(),
'%s-%s.po' % (tool.o.getAppName(), self.id))
poFile = PoFile(fileName)
for field in self.fields:
if (field.name == 'title') or (field.type != 'String'): continue
# Adds the PO message corresponding to this field
msg = field.getValue(self.o) or ''
for old, new in self.poReplacements:
msg = msg.replace(old, new)
poFile.addMessage(PoMessage(field.name, msg, ''))
poFile.generate()
return True, file(fileName)
def validate(self, new, errors):
# Call a custom "validate" if any.
self._callCustom('validate', new, errors)
def onEdit(self, created):
# Call a custom "onEdit" if any.
self._callCustom('onEdit', created)
def onDelete(self):
# Call a custom "onDelete" if any.
self._callCustom('onDelete')
# ------------------------------------------------------------------------------

View file

@ -4,17 +4,6 @@ from appy.gen.plone25.wrappers import AbstractWrapper
# ------------------------------------------------------------------------------
class UserWrapper(AbstractWrapper):
def _callCustom(self, methodName, *args, **kwargs):
'''This wrapper implements some methods like "validate" and "onEdit".
If the user has defined its own wrapper, its methods will not be
called. So this method allows, from the methods here, to call the
user versions.'''
if len(self.__class__.__bases__) > 1:
# There is a custom user class
customUser = self.__class__.__bases__[-1]
if customUser.__dict__.has_key(methodName):
customUser.__dict__[methodName](self, *args, **kwargs)
def showLogin(self):
'''When must we show the login field?'''
if self.o.isTemporary(): return 'edit'

View file

@ -33,6 +33,17 @@ class AbstractWrapper:
if other: return cmp(self.o, other.o)
else: return 1
def _callCustom(self, methodName, *args, **kwargs):
'''This wrapper implements some methods like "validate" and "onEdit".
If the user has defined its own wrapper, its methods will not be
called. So this method allows, from the methods here, to call the
user versions.'''
if len(self.__class__.__bases__) > 1:
# There is a custom user class
customUser = self.__class__.__bases__[-1]
if customUser.__dict__.has_key(methodName):
customUser.__dict__[methodName](self, *args, **kwargs)
def get_tool(self): return self.o.getTool().appy()
tool = property(get_tool)