From cecd3a1c5fbc6ed9ae8079c2ba7fbb9fd7dc86f1 Mon Sep 17 00:00:00 2001 From: bwarsaw Date: Wed, 28 Feb 2001 16:37:26 +0000 Subject: Big i18n changes. CATEGORIES: Move back to module scope, and mark as translatable, but fake out the translator so the strings don't get translated at import time (they will be passed through _() later). At global scope, set the language to the server's default, at least until we know which list the request is being made on. main(): Significant cleanups and code re-org. Don't lock the list until absolutely necessary. Use the new preferred route for setting the language (don't use os.environ['LANG'], instead use i18n.set_language()). Move as much out of the locking try/finally as possible, including the checks for authorization, logout, and varhelp. Also, set the language on the document (so the resulting html has the proper charset). FormatAdminOverview() -> admin_overview() admin_overview(): Code re-org. Set the document's language to the server's default (since the overview isn't list specific). Don't set os.environ['LANG'] anymore. FormatOptionHelp() -> option_help() option_help(): Similar changes as above. Also, allow get_item_characteristics() to do the unpacking of the item records. FormatConfiguration() -> show_results() show_results(): Be sure to send the category values through _() for translating. Mark a few more strings as translatable. FormatOptionsSection() -> show_variables() ColHeader() -> column_header() AddOptionsTableItem() -> add_options_table_item() GetItemCharacteristics() -> get_item_characteristics() GetItemGuiValue() -> get_item_gui_value() GetItemGuiDescr() -> get_item_gui_description() FormatMembershipOptions() -> membership_options() FormatSubmit() -> submit_button() GetValidValue() -> get_valid_value() ChangeOptions() -> change_options() AddErrorMessage() -> add_error_message() change_options(): Watch specifically for changes to `preferred_language' attribute, and do the appropriate i18n.set_language() call if found. --- Mailman/Cgi/admin.py | 698 +++++++++++++++++++++++++++------------------------ 1 file changed, 375 insertions(+), 323 deletions(-) (limited to 'Mailman/Cgi/admin.py') diff --git a/Mailman/Cgi/admin.py b/Mailman/Cgi/admin.py index 15179a994..9809940ee 100644 --- a/Mailman/Cgi/admin.py +++ b/Mailman/Cgi/admin.py @@ -30,201 +30,215 @@ from Mailman import Utils from Mailman import MailList from Mailman import Errors from Mailman import MailCommandHandler +from Mailman import i18n from Mailman.htmlformat import * from Mailman.Cgi import Auth from Mailman.Logging.Syslog import syslog -CATEGORIES = [] +# Mark, but don't translate yet +def _(s): return s + +CATEGORIES = [('general', _('General Options')), + ('members', _('Membership Management')), + ('privacy', _('Privacy Options')), + ('nondigest', _('Regular-member (non-digest) Options')), + ('digest', _('Digest-member Options')), + ('bounce', _('Bounce Options')), + ('archive', _('Archival Options')), + ('gateway', _('Mail-News and News-Mail gateways')), + ] + + +# Set up i18n +_ = i18n._ +i18n.set_language(mm_cfg.DEFAULT_SERVER_LANGUAGE) NL = '\n' def main(): - """Process and produce list options form. - - CGI input indicates that we're returning from submission of some new - settings, which is processed before producing the new version. - - """ global CATEGORIES - doc = Document() + + # Try to find out which list is being administered parts = Utils.GetPathPieces() if not parts: - FormatAdminOverview() + # None, so just do the admin overview and be done with it + admin_overview() return - # get the list object + # Get the list object listname = parts[0].lower() - try: - mlist = MailList.MailList(listname) + try: + mlist = MailList.MailList(listname, lock=0) except Errors.MMListError, e: - FormatAdminOverview(_('No such list %s') % listname) + admin_overview(_('No such list %(listname)s')) syslog('error', 'Someone tried to access the admin interface for a ' 'non-existent list: %s' % listname) return + # + # Now that we know what list has been requested, all subsequent admin + # pages are shown in that list's preferred language. + i18n.set_language(mlist.preferred_language) + # If the user is not authenticated, we're done. + cgidata = cgi.FieldStorage(keep_blank_values=1) try: - if len(parts) == 1: - category = 'general' - category_suffix = '' - else: - category = parts[1] - category_suffix = category - - # If the user is not authenticated, we're done. - cgidata = cgi.FieldStorage(keep_blank_values=1) - try: - Auth.authenticate(mlist, cgidata) - except Auth.NotLoggedInError, e: - Auth.loginpage(mlist, 'admin', e.message) - return - - # Is this a log-out request? - if category == 'logout': - print mlist.ZapCookie('admin') - Auth.loginpage(mlist, 'admin', frontpage=1) - return - - os.environ['LANG'] = mlist.preferred_language - - CATEGORIES = [('general', _("General Options")), - ('members', _("Membership Management")), - ('privacy', _("Privacy Options")), - ('nondigest', _("Regular-member (non-digest) Options")), - ('digest', _("Digest-member Options")), - ('bounce', _("Bounce Options")), - ('archive', _("Archival Options")), - ('gateway', _("Mail-News and News-Mail gateways")), - ] - - if category not in map(lambda x: x[0], CATEGORIES): - category = 'general' - - # is the request for variable details? - varhelp = None - if cgidata.has_key('VARHELP'): - varhelp = cgidata['VARHELP'].value - elif cgidata.has_key('request_login') and \ - os.environ.get('QUERY_STRING'): - # POST methods, even if their actions have a query string, don't - # get put into FieldStorage's keys :-( - qs = cgi.parse_qs(os.environ['QUERY_STRING']).get('VARHELP') - if qs and type(qs) == types.ListType: - varhelp = qs[0] - if varhelp: - FormatOptionHelp(doc, varhelp, mlist) - print doc.Format(bgcolor="#ffffff") - return - - # BAW: This doesn't appear to do anything. The pairs variable isn't - # used anywhere. Perhaps this was meant as some incomplete error - # checking on the value? - if cgidata.has_key('bounce_matching_headers'): - pairs = mlist.parse_matching_header_opt() - - if len(cgidata.keys()): - ChangeOptions(mlist, category, cgidata, doc) + Auth.authenticate(mlist, cgidata) + except Auth.NotLoggedInError, e: + Auth.loginpage(mlist, 'admin', e.message) + return + # Which subcategory was requested? Default is `general' + if len(parts) == 1: + category = 'general' + category_suffix = '' + else: + category = parts[1] + category_suffix = category + # Is this a log-out request? + if category == 'logout': + print mlist.ZapCookie('admin') + Auth.loginpage(mlist, 'admin', frontpage=1) + return + # Sanity check + if category not in [x[0] for x in CATEGORIES]: + category = 'general' + # Is the request for variable details? + varhelp = None + if cgidata.has_key('VARHELP'): + varhelp = cgidata['VARHELP'].value + elif cgidata.has_key('request_login') and os.environ.get('QUERY_STRING'): + # POST methods, even if their actions have a query string, don't get + # put into FieldStorage's keys :-( + qs = cgi.parse_qs(os.environ['QUERY_STRING']).get('VARHELP') + if qs and type(qs) == types.ListType: + varhelp = qs[0] + if varhelp: + option_help(mlist, varhelp) + return + # The html page document + doc = Document() + doc.set_language(mlist.preferred_language) + # Now we're ready to do normal form processing. For this, though we must + # lock the mailing list, and everything from here on out must be wrapped + # in a try/except. + # + # BAW: Currently we attempt to acquire the lock with no timeout, although + # this could get hit by a webserver or client timeout, if there's a long + # or stale lock on the list. Maybe we should have a configurable timeout + # setting after which we'll just inform the user that the operation + # couldn't be performed? + mlist.Lock() + try: + if cgidata.keys(): + # There are options to change + change_options(mlist, category, cgidata, doc) + # Let the list sanity check the changed values mlist.CheckValues() - - # Sanity checks + # Additional sanity checks if not mlist.digestable and not mlist.nondigestable: - AddErrorMessage(doc, _('''You have turned off delivery of - both digest and non-digest messages. This is an incompatible - state of affairs. You must turn on either digest delivery or - non-digest delivery or your mailing list will basically be - unusable.''')) + add_error_message( + doc, + _('''You have turned off delivery of both digest and + non-digest messages. This is an incompatible state of + affairs. You must turn on either digest delivery or + non-digest delivery or your mailing list will basically be + unusable.''')) + if not mlist.digestable and len(mlist.GetDigestMembers()): - AddErrorMessage(doc, _('''You have digest members, - but digests are turned off. Those people will not receive - mail.''')) + add_error_message( + doc, + _('''You have digest members, but digests are turned + off. Those people will not receive mail.''')) if not mlist.nondigestable and len(mlist.GetMembers()): - AddErrorMessage(doc, _('''You have regular list members - but non-digestified mail is turned off. They will receive mail - until you fix this problem.''')) - - FormatConfiguration(doc, mlist, category, category_suffix, cgidata) - print doc.Format(bgcolor="#ffffff") + add_error_message( + doc, + _('''You have regular list members but non-digestified mail is + turned off. They will receive mail until you fix this + problem.''')) + # Glom up the results page and print it out + show_results(mlist, doc, category, category_suffix, cgidata) + print doc.Format(bgcolor='#ffffff') finally: mlist.Save() mlist.Unlock() -# Form Production: -def FormatAdminOverview(error=None): - "Present a general welcome and itemize the (public) lists." - doc = Document() - default_hostname = mm_cfg.DEFAULT_HOST_NAME +def admin_overview(msg=''): + # Show the administrative overview page, with the list of all the lists on + # this host. msg is an optional error message to display at the top of + # the page. + # + # This page should be displayed in the server's default language, which + # should have already been set. + hostname = mm_cfg.DEFAULT_HOST_NAME legend = _('%(default_hostname)s mailing lists - Admin Links') + # The html `document' + doc = Document() + doc.set_language(mm_cfg.DEFAULT_SERVER_LANGUAGE) doc.SetTitle(legend) - + # The table that will hold everything table = Table(border=0, width="100%") table.AddRow([Center(Header(2, legend))]) table.AddCellInfo(max(table.GetCurrentRowIndex(), 0), 0, colspan=2, bgcolor="#99ccff") - + # Skip any mailing list that isn't advertised. advertised = [] - names = Utils.list_names() - names.sort() - for n in names: - l = MailList.MailList(n, lock=0) - if l.advertised: - advertised.append(l) - - os.environ['LANG'] = mm_cfg.DEFAULT_SERVER_LANGUAGE - - if error: - greeting = FontAttr(error, color="ff5060", size="+1") + listnames = Utils.list_names() + listnames.sort() + for name in listnames: + mlist = MailList.MailList(name, lock=0) + if mlist.advertised: + advertised.append(mlist) + # Greeting depends on whether there was an error or not + if msg: + greeting = FontAttr(msg, color="ff5060", size="+1") else: greeting = _("Welcome!") + welcome = [] if not advertised: - welcome_items = (greeting, - _("
" - " There currently are no publicly-advertised "), - Link(mm_cfg.MAILMAN_URL, "mailman"), - _(" mailing lists on %s.") % mm_cfg.DEFAULT_HOST_NAME, - ) + welcome.extend([ + greeting, + _('
There currently are no publicly-advertised '), + Link(mm_cfg.MAILMAN_URL, _('Mailman')), + _(' mailing lists on %(hostname)s.'), + ]) else: - welcome_items = ( + welcome.extend([ greeting, - _("
" - " Below is the collection of publicly-advertised "), - Link(mm_cfg.MAILMAN_URL, "mailman"), - _(" mailing lists on %(default_hostname)s."), - (_(' Click on a list name to visit the configuration pages' - ' for that list.') - ) - ) + _('
Below is the collection of publicly-advertised '), + Link(mm_cfg.MAILMAN_URL, _('Mailman')), + _(' mailing lists on %(hostname)s.'), + _(''' Click on a list name to visit the configuration pages for + that list.'''), + ]) mailman_owner = mm_cfg.MAILMAN_OWNER - extra = error and _('right ') or '' - welcome_items = (welcome_items + - (_(" To visit the administrators configuration page for" - " an unadvertised list, open a URL similar to this") - + - (_(" one, but with a '/' and the %(extra)slist name " - 'appended.
')) - + - _(" General list information can be found at "), - Link(Utils.ScriptURL('listinfo'), - _('the mailing list overview page')), - "." + - _("
(Send questions and comments to "), - Link('mailto:%(mailman_owner)s', mailman_owner), - ".)
" - ) - ) - - table.AddRow([apply(Container, welcome_items)]) + extra = msg and _('right ') or '' + welcome.extend([ + _('''To visit the administrators configuration page for an + unadvertised list, open a URL similar to this one, but with a '/' and + the %(extra)slist name appended. + +
General list information can be found at '''), + Link(Utils.ScriptURL('listinfo'), + _('the mailing list overview page')), + '.', + _('
(Send questions and comments to '), + Link('mailto:%(mailman_owner)s', mailman_owner), + '.)
',
+ ])
+
+ table.addRow([Container(*welcome)])
table.AddCellInfo(max(table.GetCurrentRowIndex(), 0), 0, colspan=2)
if advertised:
table.AddRow([' ', ' '])
- table.AddRow([Bold(_("List")), Bold(_("Description"))])
- for l in advertised:
+ table.AddRow([Bold(_('List')), Bold(_('Description'))])
+ for mlist in advertised:
table.AddRow(
- [Link(l.GetScriptURL('admin'), Bold(l.real_name)),
- l.description or Italic(_('[no description available]')),
+ [Link(mlist.GetScriptURL('admin'), Bold(mlist.real_name)),
+ mlist.description or Italic(_('[no description available]')),
])
doc.AddItem(table)
@@ -234,24 +248,91 @@ def FormatAdminOverview(error=None):
-def FormatConfiguration(doc, mlist, category, category_suffix, cgi_data):
- """Produce the overall doc, *except* any processing error messages."""
+def option_help(mlist, varhelp):
+ # The html page document
+ doc = Document()
+ doc.set_language(mlist.preferred_language)
+ # Find out which category and variable help is being requested for.
+ item = None
+ reflist = varref.split('/')
+ if len(reflist) == 2:
+ category, varname = reflist
+ options = get_config_options(mlist, category)
+ for i in options:
+ if i and i[0] == varname:
+ item = i
+ break
+ # Print an error message if we couldn't find a valid one
+ if not item:
+ path_info = os.environ.get('PATH_INFO')
+ bad = _('No valid variable details request not found: %(path_info)s')
+ add_error_message(doc, bad)
+ print doc.Format(bgcolor='#fffff')
+ return
+ # Get the details about the variable
+ varname, kind, params, dependancies, description, elaboration = \
+ get_item_characteristics(item)
+ if elaboration is None:
+ elaboration = desc
+ #
+ # Set up the document
+ realname = mlist.real_name
+ legend = _("""%(realname)s Mailing list Configuration Help
+
%(varname)s Option""")
+
+ header = Table(width='100%')
+ header.AddRow([Center(Header(3, legend))])
+ header.AddCellInfo(max(header.GetCurrentRowIndex(), 0), 0,
+ colspan=2, bgcolor="#99ccff")
+ doc.SetTitle(_("Mailman %(varname)s List Option Help"))
+ doc.AddItem(header)
+ doc.AddItem("%s (%s): %s
" % (varname, category, descr)) + doc.AddItem("%s
" % elaboration) + + form = Form("%s/%s" % (mlist.GetScriptURL('admin'), category)) + valtab = Table(cellspacing=3, cellpadding=4) + add_options_table_item(mlist, category, valtab, item, detailsp=0) + form.AddItem(valtab) + form.AddItem('
')
+ form.AddItem(Center(submit_button()))
+ doc.AddItem(Center(form))
+
+ doc.AddItem(_("""Warning: changing this option here
+ could cause other screens to be out-of-sync. Be sure to reload any other
+ pages that are displaying this option for this mailing list. You can also
+ """))
+
+ doc.AddItem(Link('%s/%s' % (mlist.GetScriptURL('admin'), category),
+ _('return to the %(category)s options page.')))
+ doc.AddItem('')
+ doc.AddItem(mlist.GetMailmanFooter())
+ print doc.Format(bgcolor="#ffffff")
+
+
+
+def show_results(mlist, doc, category, category_suffix, cgidata):
+ # Produce the results page
+ global CATEGORIES
+
+ adminurl = mlist.GetScriptURL('admin')
+
for k, v in CATEGORIES:
if k == category:
- label = v
+ label = _(v)
+ break
+ # Set up the document's headers
realname = mlist.real_name
doc.SetTitle(_('%(realname)s Administration (%(label)s)'))
doc.AddItem(Center(Header(2, _(
'%(realname)s mailing list administration
%(label)s Section'))))
doc.AddItem('
') + andpassmsg = '' + form.AddItem( + _('''Make your changes below, and then submit them + using the button at the bottom.''') + + andpassmsg + + '
') - form.AddItem(FormatOptionsSection(category, mlist, cgi_data)) + form.AddItem(show_variables(mlist, category, cgidata)) if category == 'general': form.AddItem(Center(FormatPasswordStuff())) form.AddItem("
") - form.AddItem(Center(FormatSubmit())) + form.AddItem(Center(submit_button())) form.AddItem(mlist.GetMailmanFooter()) + # main() formats and prints the document -def FormatOptionsSection(category, mlist, cgi_data): - """Produce the category-specific options table.""" +def show_variables(mlist, category, cgidata): + # Produce the category specific variable options table if category == 'members': # Special case for members section. - return FormatMembershipOptions(mlist, cgi_data) + return membership_options(mlist, cgidata) - options = GetConfigOptions(mlist, category) - - big_table = Table(cellspacing=3, cellpadding=4) + options = get_config_options(mlist, category) + # The table containing the results + table = Table(cellspacing=3, cellpadding=4) # Get and portray the text label for the category. for k, v in CATEGORIES: if k == category: - label = v - big_table.AddRow([Center(Header(2, label))]) - big_table.AddCellInfo(max(big_table.GetCurrentRowIndex(), 0), 0, + label = _(v) + break + + table.AddRow([Center(Header(2, label))]) + table.AddCellInfo(max(table.GetCurrentRowIndex(), 0), 0, colspan=2, bgcolor="#99ccff") - def ColHeader(big_table = big_table): - big_table.AddRow([Center(Bold(_('Description'))), Center(Bold(_('Value')))]) - big_table.AddCellInfo(max(big_table.GetCurrentRowIndex(), 0), 0, - width="15%") - big_table.AddCellInfo(max(big_table.GetCurrentRowIndex(), 0), 1, - width="85%") - did_col_header = 0 + # Convenience + def column_header(table=table): + table.AddRow([Center(Bold(_('Description'))), + Center(Bold(_('Value')))]) + table.AddCellInfo(max(table.GetCurrentRowIndex(), 0), 0, + width='15%') + table.AddCellInfo(max(table.GetCurrentRowIndex(), 0), 1, + width='85%') + did_col_header = 0 for item in options: if type(item) == types.StringType: # The very first banner option (string in an options list) is @@ -339,35 +440,33 @@ def FormatOptionsSection(category, mlist, cgi_data): # treated as section headers - centered and italicized... if did_col_header: item = "
" % (varname, category, descr)) - doc.AddItem("%s
" % elaboration) - - form = Form("%s/%s" % (mlist.GetScriptURL('admin'), category)) - valtab = Table(cellspacing=3, cellpadding=4) - AddOptionsTableItem(valtab, item, category, mlist, detailsp=0) - form.AddItem(valtab) - form.AddItem('
')
- form.AddItem(Center(FormatSubmit()))
- doc.AddItem(Center(form))
- doc.AddItem(_("""Warning: changing this option here
- could cause other screens to be out-of-sync. Be sure to reload any other
- pages that are displaying this option for this mailing list. You can
- also """))
- doc.AddItem(Link('%s/%s' % (mlist.GetScriptURL('admin'), category),
- _('return to the %(category)s options page.')))
- doc.AddItem('')
- doc.AddItem(mlist.GetMailmanFooter())
-
-
-
-def GetItemCharacteristics(table_entry):
- """Break out the components of an item description from its table entry:
- 0 option-var name
- 1 type
- 2 entry size
- 3 ?dependancies?
- 4 Brief description
- 5 Optional description elaboration"""
- if len(table_entry) == 5:
+def get_item_characteristics(record):
+ # Break out the components of an item description from its description
+ # record:
+ #
+ # 0 -- option-var name
+ # 1 -- type
+ # 2 -- entry size
+ # 3 -- ?dependancies?
+ # 4 -- Brief description
+ # 5 -- Optional description elaboration
+ if len(record) == 5:
elaboration = None
- varname, kind, params, dependancies, descr = table_entry
- elif len(table_entry) == 6:
- varname, kind, params, dependancies, descr, elaboration = table_entry
+ varname, kind, params, dependancies, descr = record
+ elif len(record) == 6:
+ varname, kind, params, dependancies, descr, elaboration = record
else:
- raise ValueError, (_("Badly formed options entry:\n %s")
- % table_entry)
- return (varname, kind, params, dependancies, descr, elaboration)
+ raise ValueError, _('Badly formed options entry:\n %(record)s')
+ return varname, kind, params, dependancies, descr, elaboration
-def GetItemGuiValue(mlist, kind, varname, params):
+def get_item_gui_value(mlist, kind, varname, params):
"""Return a representation of an item's settings."""
if kind == mm_cfg.Radio or kind == mm_cfg.Toggle:
#
@@ -502,30 +549,28 @@ def GetItemGuiValue(mlist, kind, varname, params):
container.AddItem(_('
...specify a file to upload
'))
container.AddItem(FileUpload(varname+'_upload', r, c))
return container
-
- # jcrey - new to deal with language
+ # jcrey - new to deal with language popup
elif kind == mm_cfg.Select:
if params:
values, legend, selected = params
else:
- values = mlist.GetAvailableLanguages()
- legend = map(_, map(Utils.GetLanguageDescr, values))
+ values = mlist.GetAvailableLanguages()
+ legend = map(_, map(Utils.GetLanguageDescr, values))
selected = values.index(mlist.preferred_language)
return SelectOptions(varname, values, legend, selected)
-def GetItemGuiDescr(mlist, category, varname, descr, detailsp):
- """Return the item's description, with link to details.
-
- Details are not included if this is a VARHELP page, because that /is/ the
- details page!
- """
+def get_item_gui_description(mlist, category, varname, descr, detailsp):
+ # Return the item's description, with link to details.
+ #
+ # Details are not included if this is a VARHELP page, because that /is/
+ # the details page!
if detailsp:
text = Container('
To View other sections, " - "click on the appropriate range listed below")) + + footer = _('''
To View other sections, click on the appropriate + range listed below''') + chunk_indices = range(len(chunks)) chunk_indices.remove(chunk) buttons = [] for ci in chunk_indices: start, end = chunks[ci][0], chunks[ci][-1] url = mlist.GetScriptURL('admin') - buttons.append("" + _("from %s to %s") + "" - % (url, ci, start, end)) + buttons.append("" + + _("from %(start)s to %(end)s") + "") buttons = apply(UnorderedList, tuple(buttons)) footer = footer + buttons.Format() + "
" else: @@ -631,22 +679,23 @@ def FormatMembershipOptions(mlist, cgi_data): container.AddItem(Center(user_table)) legend = UnorderedList() legend.AddItem(_('subscr -- Is the member subscribed?')) - legend.AddItem(_("hide -- Is the member's address " - "concealed on the list of subscribers?")) + legend.AddItem( + _("""hide -- Is the member's address concealed on + the list of subscribers?""")) legend.AddItem(_('nomail -- Is delivery to the member disabled?')) - legend.AddItem(_('ack -- ' - 'Does the member get acknowledgements of their posts?')) - legend.AddItem(_('not metoo -- ' - 'Does the member avoid copies of their own posts?')) - legend.AddItem(_('digest -- ' - 'Does the member get messages in digests? ' - '(otherwise, individual messages)')) legend.AddItem( - _('plain -- ' - 'If getting digests, does the member get plain text digests? ' - '(otherwise, MIME)')) - legend.AddItem(_("language --" - "Language preferred by the user")) + _('''ack -- Does the member get acknowledgements of their + posts?''')) + legend.AddItem( + _('''not metoo -- Does the member avoid copies of their own + posts?''')) + legend.AddItem( + _('''digest -- Does the member get messages in digests? + (otherwise, individual messages)''')) + legend.AddItem( + _('''plain -- If getting digests, does the member get plain + text digests? (otherwise, MIME)''')) + legend.AddItem(_("language -- Language preferred by the user")) container.AddItem(legend.Format()) container.AddItem(footer) t = Table(width="90%") @@ -684,7 +733,9 @@ def FormatPasswordStuff(): change_pw_table.AddCellInfo(0, 0, align="left", colspan=2) old = Table(bgcolor="#99cccc", border=1, cellspacing=0, cellpadding=2, valign="top") - old.AddRow(['
""")) continue + # Watch for changes to preferred_language. If found, make + # sure that the response is generated in the new language. + if property == 'preferred_language': + i18n.set_language(value) setattr(mlist, property, value) # # mass subscription processing for members category @@ -936,18 +988,18 @@ def ChangeOptions(mlist, category, cgi_info, document): mlist.SetUserOption(user, opt_code, 0, save_list=0) if errors: document.AddItem(Header(5, _("Error Unsubscribing:"))) - items = map(lambda x: "%s -- %s" % (x[0], x[1]), errors) + items = ['%s -- %s' % (x[0], x[1]) for x in errors] document.AddItem(apply(UnorderedList, tuple((items)))) document.AddItem("
") -def AddErrorMessage(doc, errmsg, tag='Warning: ', *args): +def add_error_message(doc, errmsg, tag='Warning: ', *args): doc.AddItem(Header(3, Bold(FontAttr( _(tag), color="#ff0000", size="+2")).Format() + Italic(errmsg % args).Format())) -def GetConfigOptions(mlist, category): +def get_config_options(mlist, category): return mlist.GetConfigInfo()[category] -- cgit v1.2.3-70-g09d2