[gen] Allow to use class Group as parameter of Search.group (soon, we will be able to get groups of groups of groups... of searches, to produce a tree of searches); refactored i18n-related code.
This commit is contained in:
parent
fcb1d36da0
commit
0dd870c042
6 changed files with 324 additions and 560 deletions
288
gen/generator.py
288
gen/generator.py
|
@ -3,9 +3,9 @@ import os, os.path, re, sys, parser, symbol, token, types
|
|||
import appy.pod, appy.pod.renderer
|
||||
from appy.shared.utils import FolderDeleter
|
||||
import appy.gen as gen
|
||||
from po import PoMessage, PoFile, PoParser
|
||||
import po
|
||||
from descriptors import *
|
||||
from utils import produceNiceMessage, getClassName
|
||||
from utils import getClassName
|
||||
from model import ModelClass, User, Group, Tool, Translation, Page
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
|
@ -365,9 +365,13 @@ class ZopeGenerator(Generator):
|
|||
self.translation = TranslationClassDescriptor(Translation, self)
|
||||
self.page = PageClassDescriptor(Page, self)
|
||||
# i18n labels to generate
|
||||
self.labels = [] # i18n labels
|
||||
self.labels = po.PoMessages()
|
||||
self.referers = {}
|
||||
|
||||
def i18n(self, id, default, nice=True):
|
||||
'''Shorthand for adding a new message into self.labels.'''
|
||||
self.labels.append(id, default, nice=nice)
|
||||
|
||||
versionRex = re.compile('(.*?\s+build)\s+(\d+)')
|
||||
def initialize(self):
|
||||
# Determine version number
|
||||
|
@ -387,175 +391,20 @@ class ZopeGenerator(Generator):
|
|||
for fileName in os.listdir(i18nFolder):
|
||||
name, ext = os.path.splitext(fileName)
|
||||
if ext in self.poExtensions:
|
||||
poParser = PoParser(os.path.join(i18nFolder, fileName))
|
||||
poParser = po.PoParser(os.path.join(i18nFolder, fileName))
|
||||
self.i18nFiles[fileName] = poParser.parse()
|
||||
|
||||
def finalize(self):
|
||||
# Some useful aliases
|
||||
msg = PoMessage
|
||||
app = self.applicationName
|
||||
# Some global i18n messages
|
||||
poMsg = msg(app, '', app); poMsg.produceNiceDefault()
|
||||
self.labels += [poMsg,
|
||||
msg('app_name', '', msg.APP_NAME),
|
||||
msg('workflow_state', '', msg.WORKFLOW_STATE),
|
||||
msg('appy_title', '', msg.APPY_TITLE),
|
||||
msg('data_change', '', msg.DATA_CHANGE),
|
||||
msg('modified_field', '', msg.MODIFIED_FIELD),
|
||||
msg('previous_value', '', msg.PREVIOUS_VALUE),
|
||||
msg('phase', '', msg.PHASE),
|
||||
msg('workflow_comment', '', msg.WORKFLOW_COMMENT),
|
||||
msg('choose_a_value', '', msg.CHOOSE_A_VALUE),
|
||||
msg('choose_a_doc', '', msg.CHOOSE_A_DOC),
|
||||
msg('min_ref_violated', '', msg.MIN_REF_VIOLATED),
|
||||
msg('max_ref_violated', '', msg.MAX_REF_VIOLATED),
|
||||
msg('no_ref', '', msg.REF_NO),
|
||||
msg('add_ref', '', msg.REF_ADD),
|
||||
msg('action_ok', '', msg.ACTION_OK),
|
||||
msg('action_ko', '', msg.ACTION_KO),
|
||||
msg('move_up', '', msg.REF_MOVE_UP),
|
||||
msg('move_down', '', msg.REF_MOVE_DOWN),
|
||||
msg('query_create', '', msg.QUERY_CREATE),
|
||||
msg('query_import', '', msg.QUERY_IMPORT),
|
||||
msg('query_no_result', '', msg.QUERY_NO_RESULT),
|
||||
msg('query_consult_all', '', msg.QUERY_CONSULT_ALL),
|
||||
msg('import_title', '', msg.IMPORT_TITLE),
|
||||
msg('import_show_hide', '', msg.IMPORT_SHOW_HIDE),
|
||||
msg('import_already', '', msg.IMPORT_ALREADY),
|
||||
msg('import_many', '', msg.IMPORT_MANY),
|
||||
msg('import_done', '', msg.IMPORT_DONE),
|
||||
msg('search_title', '', msg.SEARCH_TITLE),
|
||||
msg('search_button', '', msg.SEARCH_BUTTON),
|
||||
msg('search_objects', '', msg.SEARCH_OBJECTS),
|
||||
msg('search_results', '', msg.SEARCH_RESULTS),
|
||||
msg('search_results_descr', '', ' '),
|
||||
msg('search_new', '', msg.SEARCH_NEW),
|
||||
msg('search_from', '', msg.SEARCH_FROM),
|
||||
msg('search_to', '', msg.SEARCH_TO),
|
||||
msg('search_or', '', msg.SEARCH_OR),
|
||||
msg('search_and', '', msg.SEARCH_AND),
|
||||
msg('ref_invalid_index', '', msg.REF_INVALID_INDEX),
|
||||
msg('bad_long', '', msg.BAD_LONG),
|
||||
msg('bad_float', '', msg.BAD_FLOAT),
|
||||
msg('bad_date', '', msg.BAD_DATE),
|
||||
msg('bad_email', '', msg.BAD_EMAIL),
|
||||
msg('bad_url', '', msg.BAD_URL),
|
||||
msg('bad_alphanumeric', '', msg.BAD_ALPHANUMERIC),
|
||||
msg('bad_select_value', '', msg.BAD_SELECT_VALUE),
|
||||
msg('select_delesect', '', msg.SELECT_DESELECT),
|
||||
msg('no_elem_selected', '', msg.NO_SELECTION),
|
||||
msg('object_edit', '', msg.EDIT),
|
||||
msg('object_delete', '', msg.DELETE),
|
||||
msg('object_unlink', '', msg.UNLINK),
|
||||
msg('delete_confirm', '', msg.DELETE_CONFIRM),
|
||||
msg('unlink_confirm', '', msg.UNLINK_CONFIRM),
|
||||
msg('delete_done', '', msg.DELETE_DONE),
|
||||
msg('unlink_done', '', msg.UNLINK_DONE),
|
||||
msg('goto_first', '', msg.GOTO_FIRST),
|
||||
msg('goto_previous', '', msg.GOTO_PREVIOUS),
|
||||
msg('goto_next', '', msg.GOTO_NEXT),
|
||||
msg('goto_last', '', msg.GOTO_LAST),
|
||||
msg('goto_source', '', msg.GOTO_SOURCE),
|
||||
msg('whatever', '', msg.WHATEVER),
|
||||
msg('yes', '', msg.YES),
|
||||
msg('no', '', msg.NO),
|
||||
msg('field_required', '', msg.FIELD_REQUIRED),
|
||||
msg('field_invalid', '', msg.FIELD_INVALID),
|
||||
msg('file_required', '', msg.FILE_REQUIRED),
|
||||
msg('image_required', '', msg.IMAGE_REQUIRED),
|
||||
msg('odt', '', msg.FORMAT_ODT),
|
||||
msg('pdf', '', msg.FORMAT_PDF),
|
||||
msg('doc', '', msg.FORMAT_DOC),
|
||||
msg('rtf', '', msg.FORMAT_RTF),
|
||||
msg('front_page_text', '', msg.FRONT_PAGE_TEXT),
|
||||
msg('captcha_text', '', msg.CAPTCHA_TEXT),
|
||||
msg('bad_captcha', '', msg.BAD_CAPTCHA),
|
||||
msg('app_login', '', msg.LOGIN),
|
||||
msg('app_connect', '', msg.CONNECT),
|
||||
msg('app_logout', '', msg.LOGOUT),
|
||||
msg('app_password', '', msg.PASSWORD),
|
||||
msg('app_home', '', msg.HOME),
|
||||
msg('login_reserved', '', msg.LOGIN_RESERVED),
|
||||
msg('login_in_use', '', msg.LOGIN_IN_USE),
|
||||
msg('login_ko', '', msg.LOGIN_KO),
|
||||
msg('login_ok', '', msg.LOGIN_OK),
|
||||
msg('password_too_short', '', msg.PASSWORD_TOO_SHORT),
|
||||
msg('passwords_mismatch', '', msg.PASSWORDS_MISMATCH),
|
||||
msg('object_save', '', msg.SAVE),
|
||||
msg('object_saved', '', msg.SAVED),
|
||||
msg('validation_error', '', msg.ERROR),
|
||||
msg('object_cancel', '', msg.CANCEL),
|
||||
msg('object_canceled', '', msg.CANCELED),
|
||||
msg('enable_cookies', '', msg.ENABLE_COOKIES),
|
||||
msg('page_previous', '', msg.PAGE_PREVIOUS),
|
||||
msg('page_next', '', msg.PAGE_NEXT),
|
||||
msg('forgot_password', '', msg.FORGOT_PASSWORD),
|
||||
msg('ask_password_reinit', '', msg.ASK_PASSWORD_REINIT),
|
||||
msg('wrong_password_reinit','', msg.WRONG_PASSWORD_REINIT),
|
||||
msg('reinit_mail_sent', '', msg.REINIT_MAIL_SENT),
|
||||
msg('reinit_password', '', msg.REINIT_PASSWORD),
|
||||
msg('reinit_password_body', '', msg.REINIT_PASSWORD_BODY),
|
||||
msg('new_password', '', msg.NEW_PASSWORD),
|
||||
msg('new_password_body', '', msg.NEW_PASSWORD_BODY),
|
||||
msg('new_password_sent', '', msg.NEW_PASSWORD_SENT),
|
||||
msg('last_user_access', '', msg.LAST_USER_ACCESS),
|
||||
msg('object_history', '', msg.OBJECT_HISTORY),
|
||||
msg('object_created_by', '', msg.OBJECT_CREATED_BY),
|
||||
msg('object_created_on', '', msg.OBJECT_CREATED_ON),
|
||||
msg('object_modified_on', '', msg.OBJECT_MODIFIED_ON),
|
||||
msg('object_action', '', msg.OBJECT_ACTION),
|
||||
msg('object_author', '', msg.OBJECT_AUTHOR),
|
||||
msg('action_date', '', msg.ACTION_DATE),
|
||||
msg('action_comment', '', msg.ACTION_COMMENT),
|
||||
msg('day_Mon_short', '', msg.DAY_MON_SHORT),
|
||||
msg('day_Tue_short', '', msg.DAY_TUE_SHORT),
|
||||
msg('day_Wed_short', '', msg.DAY_WED_SHORT),
|
||||
msg('day_Thu_short', '', msg.DAY_THU_SHORT),
|
||||
msg('day_Fri_short', '', msg.DAY_FRI_SHORT),
|
||||
msg('day_Sat_short', '', msg.DAY_SAT_SHORT),
|
||||
msg('day_Sun_short', '', msg.DAY_SUN_SHORT),
|
||||
msg('day_Mon', '', msg.DAY_MON),
|
||||
msg('day_Tue', '', msg.DAY_TUE),
|
||||
msg('day_Wed', '', msg.DAY_WED),
|
||||
msg('day_Thu', '', msg.DAY_THU),
|
||||
msg('day_Fri', '', msg.DAY_FRI),
|
||||
msg('day_Sat', '', msg.DAY_SAT),
|
||||
msg('day_Sun', '', msg.DAY_SUN),
|
||||
msg('ampm_am', '', msg.AMPM_AM),
|
||||
msg('ampm_pm', '', msg.AMPM_PM),
|
||||
msg('month_Jan_short', '', msg.MONTH_JAN_SHORT),
|
||||
msg('month_Feb_short', '', msg.MONTH_FEB_SHORT),
|
||||
msg('month_Mar_short', '', msg.MONTH_MAR_SHORT),
|
||||
msg('month_Apr_short', '', msg.MONTH_APR_SHORT),
|
||||
msg('month_May_short', '', msg.MONTH_MAY_SHORT),
|
||||
msg('month_Jun_short', '', msg.MONTH_JUN_SHORT),
|
||||
msg('month_Jul_short', '', msg.MONTH_JUL_SHORT),
|
||||
msg('month_Aug_short', '', msg.MONTH_AUG_SHORT),
|
||||
msg('month_Sep_short', '', msg.MONTH_SEP_SHORT),
|
||||
msg('month_Oct_short', '', msg.MONTH_OCT_SHORT),
|
||||
msg('month_Nov_short', '', msg.MONTH_NOV_SHORT),
|
||||
msg('month_Dec_short', '', msg.MONTH_DEC_SHORT),
|
||||
msg('month_Jan', '', msg.MONTH_JAN),
|
||||
msg('month_Feb', '', msg.MONTH_FEB),
|
||||
msg('month_Mar', '', msg.MONTH_MAR),
|
||||
msg('month_Apr', '', msg.MONTH_APR),
|
||||
msg('month_May', '', msg.MONTH_MAY),
|
||||
msg('month_Jun', '', msg.MONTH_JUN),
|
||||
msg('month_Jul', '', msg.MONTH_JUL),
|
||||
msg('month_Aug', '', msg.MONTH_AUG),
|
||||
msg('month_Sep', '', msg.MONTH_SEP),
|
||||
msg('month_Oct', '', msg.MONTH_OCT),
|
||||
msg('month_Nov', '', msg.MONTH_NOV),
|
||||
msg('month_Dec', '', msg.MONTH_DEC),
|
||||
msg('today', '', msg.TODAY),
|
||||
msg('which_event', '', msg.WHICH_EVENT),
|
||||
msg('event_span', '', msg.EVENT_SPAN),
|
||||
msg('del_next_events', '', msg.DEL_NEXT_EVENTS),
|
||||
]
|
||||
# Create a label for every role added by this application
|
||||
# Add a label for the application name
|
||||
self.i18n(self.applicationName, self.applicationName)
|
||||
# Add default Appy i18n messages
|
||||
for id, default in po.appyLabels:
|
||||
self.i18n(id, default, nice=False)
|
||||
# Add a label for every role added by this application (we ensure role
|
||||
# 'Manager' was added even if not mentioned anywhere).
|
||||
self.i18n('role_Manager', 'Manager')
|
||||
for role in self.getAllUsedRoles():
|
||||
self.labels.append(msg('role_%s' % role.name,'', role.name,
|
||||
niceDefault=True))
|
||||
self.i18n('role_%s' % role.name, role.name)
|
||||
# Create basic files (config.py, etc)
|
||||
self.generateTool()
|
||||
self.generateInit()
|
||||
|
@ -570,23 +419,16 @@ class ZopeGenerator(Generator):
|
|||
f = open(initFile, 'w')
|
||||
f.write('')
|
||||
f.close()
|
||||
# Decline i18n labels into versions for child classes
|
||||
for classDescr in self.classes:
|
||||
for poMsg in classDescr.labelsToPropagate:
|
||||
for childDescr in classDescr.getChildren():
|
||||
childMsg = poMsg.clone(classDescr.name, childDescr.name)
|
||||
if childMsg not in self.labels:
|
||||
self.labels.append(childMsg)
|
||||
# Generate i18n pot file
|
||||
potFileName = '%s.pot' % self.applicationName
|
||||
if self.i18nFiles.has_key(potFileName):
|
||||
potFile = self.i18nFiles[potFileName]
|
||||
else:
|
||||
fullName = os.path.join(self.application, 'tr', potFileName)
|
||||
potFile = PoFile(fullName)
|
||||
potFile = po.PoFile(fullName)
|
||||
self.i18nFiles[potFileName] = potFile
|
||||
# We update the POT file with our list of automatically managed labels.
|
||||
removedLabels = potFile.update(self.labels, self.options.i18nClean,
|
||||
removedLabels = potFile.update(self.labels.get(),self.options.i18nClean,
|
||||
not self.options.i18nSort)
|
||||
if removedLabels:
|
||||
print 'Warning: %d messages were removed from translation ' \
|
||||
|
@ -599,7 +441,7 @@ class ZopeGenerator(Generator):
|
|||
nbOfPages = int(len(potFile.messages)/self.config.translationsPerPage)+1
|
||||
for i in range(nbOfPages):
|
||||
msgId = '%s_page_%d' % (self.translation.name, i+2)
|
||||
pageLabels.append(msg(msgId, '', 'Page %d' % (i+2)))
|
||||
pageLabels.append(po.PoMessage(msgId, '', 'Page %d' % (i+2)))
|
||||
potFile.update(pageLabels, keepExistingOrder=False)
|
||||
potFile.generate()
|
||||
# Generate i18n po files
|
||||
|
@ -611,7 +453,7 @@ class ZopeGenerator(Generator):
|
|||
poFile = self.i18nFiles[poFileName]
|
||||
else:
|
||||
fullName = os.path.join(self.application, 'tr', poFileName)
|
||||
poFile = PoFile(fullName)
|
||||
poFile = po.PoFile(fullName)
|
||||
self.i18nFiles[poFileName] = poFile
|
||||
poFile.update(potFile.messages, self.options.i18nClean,
|
||||
not self.options.i18nSort)
|
||||
|
@ -874,11 +716,8 @@ class ZopeGenerator(Generator):
|
|||
|
||||
def generateTool(self):
|
||||
'''Generates the tool that corresponds to this application.'''
|
||||
Msg = PoMessage
|
||||
# Create Tool-related i18n-related messages
|
||||
msg = Msg(self.tool.name, '', Msg.CONFIG % self.applicationName)
|
||||
self.labels.append(msg)
|
||||
|
||||
self.i18n(self.tool.name, po.CONFIG % self.applicationName, nice=False)
|
||||
# Tune the Ref field between Tool->User and Group->User
|
||||
Tool.users.klass = User
|
||||
if self.user.customized:
|
||||
|
@ -889,8 +728,8 @@ class ZopeGenerator(Generator):
|
|||
for klass in (self.user, self.group, self.translation, self.page):
|
||||
klassType = klass.name[len(self.applicationName):]
|
||||
klass.generateSchema()
|
||||
self.labels += [ Msg(klass.name, '', klassType),
|
||||
Msg('%s_plural' % klass.name,'', klass.name+'s')]
|
||||
self.i18n(klass.name, klassType, nice=False)
|
||||
self.i18n('%s_plural' % klass.name, klass.name+'s', nice=False)
|
||||
repls = self.repls.copy()
|
||||
if klass.isFolder():
|
||||
parents = 'BaseMixin, Folder'
|
||||
|
@ -904,21 +743,16 @@ class ZopeGenerator(Generator):
|
|||
self.copyFile('Class.pyt', repls, destName='%s.py' % klass.name)
|
||||
|
||||
# Before generating the Tool class, finalize it with query result
|
||||
# columns, with fields to propagate, workflow-related fields.
|
||||
# columns, search-related and import-related fields.
|
||||
for classDescr in self.getClasses(include='allButTool'):
|
||||
for fieldName, fieldType in classDescr.toolFieldsToPropagate:
|
||||
for childDescr in classDescr.getChildren():
|
||||
childFieldName = fieldName % childDescr.name
|
||||
fieldType.group = childDescr.klass.__name__
|
||||
self.tool.addField(childFieldName, fieldType)
|
||||
if classDescr.isRoot():
|
||||
# We must be able to configure query results from the tool.
|
||||
self.tool.addQueryResultColumns(classDescr)
|
||||
# Add the search-related fields.
|
||||
self.tool.addSearchRelatedFields(classDescr)
|
||||
importMean = classDescr.getCreateMean('Import')
|
||||
if importMean:
|
||||
self.tool.addImportRelatedFields(classDescr)
|
||||
if not classDescr.isRoot(): continue
|
||||
# We must be able to configure query results from the tool.
|
||||
self.tool.addQueryResultColumns(classDescr)
|
||||
# Add the search-related fields.
|
||||
self.tool.addSearchRelatedFields(classDescr)
|
||||
importMean = classDescr.getCreateMean('Import')
|
||||
if importMean:
|
||||
self.tool.addImportRelatedFields(classDescr)
|
||||
self.tool.generateSchema()
|
||||
|
||||
# Generate the Tool class
|
||||
|
@ -939,37 +773,27 @@ class ZopeGenerator(Generator):
|
|||
baseClass = isFolder and 'Folder' or 'SimpleItem'
|
||||
icon = isFolder and 'folder.gif' or 'object.gif'
|
||||
parents = 'BaseMixin, %s' % baseClass
|
||||
classDoc = classDescr.klass.__doc__ or 'Appy class.'
|
||||
classDoc = k.__doc__ or 'Appy class.'
|
||||
repls = self.repls.copy()
|
||||
classDescr.generateSchema()
|
||||
repls.update({
|
||||
'parents': parents, 'className': classDescr.klass.__name__,
|
||||
'parents': parents, 'className': k.__name__,
|
||||
'genClassName': classDescr.name, 'baseMixin':'BaseMixin',
|
||||
'classDoc': classDoc, 'applicationName': self.applicationName,
|
||||
'methods': classDescr.methods, 'icon':icon})
|
||||
fileName = '%s.py' % classDescr.name
|
||||
# Create i18n labels (class name and plural form)
|
||||
poMsg = PoMessage(classDescr.name, '', classDescr.klass.__name__)
|
||||
poMsg.produceNiceDefault()
|
||||
self.labels.append(poMsg)
|
||||
poMsgPl = PoMessage('%s_plural' % classDescr.name, '',
|
||||
classDescr.klass.__name__+'s')
|
||||
poMsgPl.produceNiceDefault()
|
||||
self.labels.append(poMsgPl)
|
||||
self.i18n(classDescr.name, k.__name__)
|
||||
self.i18n('%s_plural' % classDescr.name, k.__name__+'s')
|
||||
# Create i18n labels for searches
|
||||
for search in classDescr.getSearches(classDescr.klass):
|
||||
searchLabel = '%s_search_%s' % (classDescr.name, search.name)
|
||||
labels = [searchLabel, '%s_descr' % searchLabel]
|
||||
if search.group:
|
||||
grpLabel = '%s_searchgroup_%s' % (classDescr.name, search.group)
|
||||
labels += [grpLabel, '%s_descr' % grpLabel]
|
||||
for label in labels:
|
||||
default = ' '
|
||||
if label == searchLabel: default = search.name
|
||||
poMsg = PoMessage(label, '', default)
|
||||
poMsg.produceNiceDefault()
|
||||
if poMsg not in self.labels:
|
||||
self.labels.append(poMsg)
|
||||
for search in classDescr.getSearches(k):
|
||||
label = '%s_search_%s' % (classDescr.name, search.name)
|
||||
self.i18n(label, search.name)
|
||||
self.i18n('%s_descr' % label, ' ', nice=False)
|
||||
# Generate labels for groups of searches
|
||||
if search.group and not search.group.label:
|
||||
search.group.generateLabels(self.labels, classDescr, set(),
|
||||
forSearch=True)
|
||||
# Generate the resulting Zope class.
|
||||
self.copyFile('Class.pyt', repls, destName=fileName)
|
||||
|
||||
|
@ -983,31 +807,23 @@ class ZopeGenerator(Generator):
|
|||
# Add i18n messages for states
|
||||
for name in dir(wfDescr.klass):
|
||||
if not isinstance(getattr(wfDescr.klass, name), gen.State): continue
|
||||
poMsg = PoMessage('%s_%s' % (wfName, name), '', name)
|
||||
poMsg.produceNiceDefault()
|
||||
self.labels.append(poMsg)
|
||||
self.i18n('%s_%s' % (wfName, name), name)
|
||||
# Add i18n messages for transitions
|
||||
for name in dir(wfDescr.klass):
|
||||
transition = getattr(wfDescr.klass, name)
|
||||
if not isinstance(transition, gen.Transition): continue
|
||||
if transition.show:
|
||||
poMsg = PoMessage('%s_%s' % (wfName, name), '', name)
|
||||
poMsg.produceNiceDefault()
|
||||
self.labels.append(poMsg)
|
||||
self.i18n('%s_%s' % (wfName, name), name)
|
||||
if transition.show and transition.confirm:
|
||||
# We need to generate a label for the message that will be shown
|
||||
# in the confirm popup.
|
||||
label = '%s_%s_confirm' % (wfName, name)
|
||||
poMsg = PoMessage(label, '', PoMessage.CONFIRM)
|
||||
self.labels.append(poMsg)
|
||||
self.i18n('%s_%s_confirm'%(wfName, name),po.CONFIRM, nice=False)
|
||||
if transition.notify:
|
||||
# Appy will send a mail when this transition is triggered.
|
||||
# So we need 2 i18n labels: one for the mail subject and one for
|
||||
# the mail body.
|
||||
subjectLabel = '%s_%s_mail_subject' % (wfName, name)
|
||||
poMsg = PoMessage(subjectLabel, '', PoMessage.EMAIL_SUBJECT)
|
||||
self.labels.append(poMsg)
|
||||
bodyLabel = '%s_%s_mail_body' % (wfName, name)
|
||||
poMsg = PoMessage(bodyLabel, '', PoMessage.EMAIL_BODY)
|
||||
self.labels.append(poMsg)
|
||||
self.i18n('%s_%s_mail_subject' % (wfName, name),
|
||||
po.EMAIL_SUBJECT, nice=False)
|
||||
self.i18n('%s_%s_mail_body' % (wfName, name),
|
||||
po.EMAIL_BODY, nice=False)
|
||||
# ------------------------------------------------------------------------------
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue