summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBarry Warsaw2007-07-16 23:55:49 -0400
committerBarry Warsaw2007-07-16 23:55:49 -0400
commitb8e8aa0386c2ee0fc7e90bf22fbe8fe3f222964a (patch)
tree5893e3908f89d8dd988c7844827d83e60ab6c532
parent327865eaf118f40063366acad9c7d97487e010d6 (diff)
downloadmailman-b8e8aa0386c2ee0fc7e90bf22fbe8fe3f222964a.tar.gz
mailman-b8e8aa0386c2ee0fc7e90bf22fbe8fe3f222964a.tar.zst
mailman-b8e8aa0386c2ee0fc7e90bf22fbe8fe3f222964a.zip
Major surgery to get the setuptools based installation passing all the
existing unit tests. Here's a summary of the changes. - Removed all dependent third party packages, since the setup.py file now claims all package dependencies such that they can be automatically installed from the cheeseshop. - Moved the misc directory into the Mailman package as Mailman/data. Moved templates and messages to Mailman subpackages. - Added an ILanguageManager interface, plus an implementation, so that we don't use Defaults.LC_DESCRIPTIONS directly anymore. Added a doctest for this interface and implementation. Defaults.LANGUAGES is moved into mailman.cfg. Defaults.LANGUAGE_DICT is moved to _DEFAULT_LANGUAGE_DATA, and LC_DESCRIPTIONS is removed. The calculation of the available and enabled languages is moved to the Configuration class, but this will probably still need work. Utils.GetLanguageDescr() and Utils.IsLanguage() are removed. I'd like to remove GetCharSet() eventually too, but there are too many uses of this currently, so I'm deferring it. - Utils.findtext(): Hacks added so that templates can be retrieved from the language catalog. The hack is that the template contents are used to find the translation, but in the one test case where this is actually flexed, the trailing newline in the file contents has to be trimmed. This is probably not right. - No more Defaults.py.in or mm_cfg.py! Defaults.py.in is moved to Defaults.py and is no longer created from a template file. The script called make_instance is added which creates an etc/mailman.cfg file from mailman.cfg.in (previously, mailman.cfg.sample) and /that/ file now has the small number of calculated values. In general, make_instance will not touch mailman.cfg if it exists, unless the --force option is given. CGIEXT is made the empty string by default (i.e. not generated). make_instance grows a --var-dir option. Fleshed out the --languages opton. - Defaults.py grows a DEFAULT_VAR_DIRECTORY variable, which is the default location of the 'var' directory. The Configuration class uses this as one of the directories it searches for its landmark, i.e. etc/mailman.cfg. RUNTIME_DIR is gone, as is VAR_PREFIX. - testall needs to write MAILMAN_USER, MAILMAN_UID, MAILMAN_GROUP, MAILMAN_GID, and LANGUAGES run time variables. - bin/withlist no longer needs to add config.BIN_DIR to sys.path, because in fact that variable doesn't exist any more. - Tweak the French catalog to make a test work. This is needed because of the conversion from %-strings to $-strings. - The setup.py now generates the .mo files before it does its thing. This will have to be fixed, but for now we must generate these files on setup build time instead of installation time. - Removed an unused interface.
-rw-r--r--.bzrignore22
-rw-r--r--Mailman/Cgi/admin.py10
-rw-r--r--Mailman/Cgi/confirm.py4
-rw-r--r--Mailman/Cgi/create.py6
-rw-r--r--Mailman/Cgi/listinfo.py2
-rw-r--r--Mailman/Cgi/options.py4
-rw-r--r--Mailman/Cgi/rmlist.py2
-rw-r--r--Mailman/Cgi/roster.py2
-rw-r--r--Mailman/Cgi/subscribe.py2
-rw-r--r--Mailman/Defaults.py (renamed from Mailman/Defaults.py.in)29
-rw-r--r--Mailman/Gui/Language.py11
-rw-r--r--Mailman/HTMLFormatter.py6
-rw-r--r--Mailman/MailList.py15
-rw-r--r--Mailman/OldStyleMemberships.py2
-rw-r--r--Mailman/SafeDict.py2
-rw-r--r--Mailman/Utils.py54
-rw-r--r--Mailman/bin/make_instance.py98
-rw-r--r--Mailman/bin/newlist.py2
-rw-r--r--Mailman/bin/rmlist.py2
-rw-r--r--Mailman/bin/testall.py20
-rw-r--r--Mailman/bin/withlist.py4
-rw-r--r--Mailman/configuration.py121
-rw-r--r--Mailman/data/Elixir-0.3.0.tar.gz (renamed from misc/Elixir-0.3.0.tar.gz)bin99715 -> 99715 bytes
-rw-r--r--Mailman/data/PythonPowered.png (renamed from misc/PythonPowered.png)bin945 -> 945 bytes
-rw-r--r--Mailman/data/SQLAlchemy-0.3.3.tar.gz (renamed from misc/SQLAlchemy-0.3.3.tar.gz)bin737019 -> 737019 bytes
-rwxr-xr-xMailman/data/__init__.py0
-rw-r--r--Mailman/data/coverage.py (renamed from misc/coverage.py)0
-rw-r--r--Mailman/data/gnu-head-tiny.jpg (renamed from misc/gnu-head-tiny.jpg)bin3049 -> 3049 bytes
-rw-r--r--Mailman/data/mailman-large.jpg (renamed from misc/mailman-large.jpg)bin6150 -> 6150 bytes
-rw-r--r--Mailman/data/mailman.cfg.in (renamed from misc/mailman.cfg.sample)26
-rw-r--r--Mailman/data/mailman.in (renamed from misc/mailman.in)0
-rw-r--r--Mailman/data/mailman.jpg (renamed from misc/mailman.jpg)bin2022 -> 2022 bytes
-rw-r--r--Mailman/data/mm-icon.png (renamed from misc/mm-icon.png)bin281 -> 281 bytes
-rw-r--r--Mailman/data/munepy-1.1-py2.5.egg (renamed from misc/munepy-1.1-py2.5.egg)bin8192 -> 8192 bytes
-rw-r--r--Mailman/data/paths.py.in (renamed from misc/paths.py.in)0
-rw-r--r--Mailman/data/pysqlite-2.3.2.tar.gz (renamed from misc/pysqlite-2.3.2.tar.gz)bin79532 -> 79532 bytes
-rw-r--r--Mailman/data/setuptools-0.6c3.tar.gz (renamed from misc/setuptools-0.6c3.tar.gz)bin238544 -> 238544 bytes
-rw-r--r--Mailman/data/wsgiref-0.1.2-py2.4.egg (renamed from misc/wsgiref-0.1.2-py2.4.egg)bin39890 -> 39890 bytes
-rw-r--r--Mailman/data/zope.interface-3.3.0.1.tar.gz (renamed from misc/zope.interface-3.3.0.1.tar.gz)bin105075 -> 105075 bytes
-rw-r--r--Mailman/docs/acknowledge.txt1
-rw-r--r--Mailman/docs/digests.txt15
-rw-r--r--Mailman/docs/languages.txt94
-rw-r--r--Mailman/i18n.py9
-rw-r--r--Mailman/interfaces/languages.py65
-rw-r--r--Mailman/interfaces/manager.py57
-rw-r--r--Mailman/languages.py57
-rw-r--r--Mailman/messages/__init__.py0
-rw-r--r--Mailman/messages/ar/LC_MESSAGES/mailman.po (renamed from messages/ar/LC_MESSAGES/mailman.po)0
-rw-r--r--Mailman/messages/ca/LC_MESSAGES/mailman.po (renamed from messages/ca/LC_MESSAGES/mailman.po)0
-rw-r--r--Mailman/messages/cs/LC_MESSAGES/mailman.po (renamed from messages/cs/LC_MESSAGES/mailman.po)0
-rw-r--r--Mailman/messages/da/LC_MESSAGES/mailman.po (renamed from messages/da/LC_MESSAGES/mailman.po)0
-rw-r--r--Mailman/messages/de/LC_MESSAGES/mailman.po (renamed from messages/de/LC_MESSAGES/mailman.po)0
-rw-r--r--Mailman/messages/de/README.de (renamed from messages/de/README.de)0
-rw-r--r--Mailman/messages/docstring.files (renamed from messages/docstring.files)0
-rw-r--r--Mailman/messages/es/LC_MESSAGES/mailman.po (renamed from messages/es/LC_MESSAGES/mailman.po)0
-rw-r--r--Mailman/messages/es/README.es (renamed from messages/es/README.es)0
-rw-r--r--Mailman/messages/et/LC_MESSAGES/mailman.po (renamed from messages/et/LC_MESSAGES/mailman.po)0
-rw-r--r--Mailman/messages/eu/LC_MESSAGES/mailman.po (renamed from messages/eu/LC_MESSAGES/mailman.po)0
-rw-r--r--Mailman/messages/eu/README.eu (renamed from messages/eu/README.eu)0
-rw-r--r--Mailman/messages/fi/LC_MESSAGES/mailman.po (renamed from messages/fi/LC_MESSAGES/mailman.po)0
-rw-r--r--Mailman/messages/fi/README.fi (renamed from messages/fi/README.fi)0
-rw-r--r--Mailman/messages/fr/LC_MESSAGES/mailman.po (renamed from messages/fr/LC_MESSAGES/mailman.po)4
-rw-r--r--Mailman/messages/fr/README.fr (renamed from messages/fr/README.fr)0
-rw-r--r--Mailman/messages/hr/LC_MESSAGES/mailman.po (renamed from messages/hr/LC_MESSAGES/mailman.po)0
-rw-r--r--Mailman/messages/hu/FAQ.hu (renamed from messages/hu/FAQ.hu)0
-rw-r--r--Mailman/messages/hu/INSTALL.hu (renamed from messages/hu/INSTALL.hu)0
-rw-r--r--Mailman/messages/hu/LC_MESSAGES/mailman.po (renamed from messages/hu/LC_MESSAGES/mailman.po)0
-rw-r--r--Mailman/messages/hu/README.BSD.hu (renamed from messages/hu/README.BSD.hu)0
-rw-r--r--Mailman/messages/hu/README.CONTRIB.hu (renamed from messages/hu/README.CONTRIB.hu)0
-rw-r--r--Mailman/messages/hu/README.EXIM.hu (renamed from messages/hu/README.EXIM.hu)0
-rw-r--r--Mailman/messages/hu/README.LINUX.hu (renamed from messages/hu/README.LINUX.hu)0
-rw-r--r--Mailman/messages/hu/README.MACOSX.hu (renamed from messages/hu/README.MACOSX.hu)0
-rw-r--r--Mailman/messages/hu/README.NETSCAPE.hu (renamed from messages/hu/README.NETSCAPE.hu)0
-rw-r--r--Mailman/messages/hu/README.POSTFIX.hu (renamed from messages/hu/README.POSTFIX.hu)0
-rw-r--r--Mailman/messages/hu/README.QMAIL.hu (renamed from messages/hu/README.QMAIL.hu)0
-rw-r--r--Mailman/messages/hu/README.SENDMAIL.hu (renamed from messages/hu/README.SENDMAIL.hu)0
-rw-r--r--Mailman/messages/hu/README.USERAGENT.hu (renamed from messages/hu/README.USERAGENT.hu)0
-rw-r--r--Mailman/messages/hu/README.hu (renamed from messages/hu/README.hu)0
-rw-r--r--Mailman/messages/hu/UPGRADING.hu (renamed from messages/hu/UPGRADING.hu)0
-rw-r--r--Mailman/messages/ia/LC_MESSAGES/mailman.po (renamed from messages/ia/LC_MESSAGES/mailman.po)0
-rw-r--r--Mailman/messages/it/LC_MESSAGES/mailman.po (renamed from messages/it/LC_MESSAGES/mailman.po)0
-rw-r--r--Mailman/messages/it/README.it (renamed from messages/it/README.it)0
-rw-r--r--Mailman/messages/ja/INSTALL (renamed from messages/ja/INSTALL)0
-rw-r--r--Mailman/messages/ja/LC_MESSAGES/mailman.po (renamed from messages/ja/LC_MESSAGES/mailman.po)0
-rw-r--r--Mailman/messages/ja/README (renamed from messages/ja/README)0
-rw-r--r--Mailman/messages/ja/README.ja (renamed from messages/ja/README.ja)0
-rw-r--r--Mailman/messages/ja/UPGRADING (renamed from messages/ja/UPGRADING)0
-rw-r--r--Mailman/messages/ja/doc/Defaults.py.in (renamed from messages/ja/doc/Defaults.py.in)0
-rw-r--r--Mailman/messages/ja/doc/mailman-install.tex (renamed from messages/ja/doc/mailman-install.tex)0
-rw-r--r--Mailman/messages/ja/doc/mailman-member.tex (renamed from messages/ja/doc/mailman-member.tex)0
-rw-r--r--Mailman/messages/ko/LC_MESSAGES/mailman.po (renamed from messages/ko/LC_MESSAGES/mailman.po)0
-rw-r--r--Mailman/messages/ko/README.ko (renamed from messages/ko/README.ko)0
-rw-r--r--Mailman/messages/lt/LC_MESSAGES/mailman.po (renamed from messages/lt/LC_MESSAGES/mailman.po)0
-rw-r--r--Mailman/messages/mailman.pot (renamed from messages/mailman.pot)0
-rw-r--r--Mailman/messages/marked.files (renamed from messages/marked.files)0
-rw-r--r--Mailman/messages/nl/LC_MESSAGES/mailman.po (renamed from messages/nl/LC_MESSAGES/mailman.po)0
-rw-r--r--Mailman/messages/no/LC_MESSAGES/mailman.po (renamed from messages/no/LC_MESSAGES/mailman.po)0
-rw-r--r--Mailman/messages/pl/LC_MESSAGES/mailman.po (renamed from messages/pl/LC_MESSAGES/mailman.po)0
-rw-r--r--Mailman/messages/pl/README.pl (renamed from messages/pl/README.pl)0
-rw-r--r--Mailman/messages/pt/LC_MESSAGES/mailman.po (renamed from messages/pt/LC_MESSAGES/mailman.po)0
-rw-r--r--Mailman/messages/pt_BR/LC_MESSAGES/mailman.po (renamed from messages/pt_BR/LC_MESSAGES/mailman.po)0
-rw-r--r--Mailman/messages/ro/LC_MESSAGES/mailman.po (renamed from messages/ro/LC_MESSAGES/mailman.po)0
-rw-r--r--Mailman/messages/ru/LC_MESSAGES/mailman.po (renamed from messages/ru/LC_MESSAGES/mailman.po)0
-rw-r--r--Mailman/messages/ru/README.ru (renamed from messages/ru/README.ru)0
-rw-r--r--Mailman/messages/sl/LC_MESSAGES/mailman.po (renamed from messages/sl/LC_MESSAGES/mailman.po)0
-rw-r--r--Mailman/messages/sr/LC_MESSAGES/mailman.po (renamed from messages/sr/LC_MESSAGES/mailman.po)0
-rw-r--r--Mailman/messages/sr/readme.sr (renamed from messages/sr/readme.sr)0
-rw-r--r--Mailman/messages/sv/LC_MESSAGES/mailman.po (renamed from messages/sv/LC_MESSAGES/mailman.po)0
-rw-r--r--Mailman/messages/sv/README.sv (renamed from messages/sv/README.sv)0
-rw-r--r--Mailman/messages/tr/LC_MESSAGES/mailman.po (renamed from messages/tr/LC_MESSAGES/mailman.po)0
-rw-r--r--Mailman/messages/uk/LC_MESSAGES/mailman.po (renamed from messages/uk/LC_MESSAGES/mailman.po)0
-rw-r--r--Mailman/messages/vi/LC_MESSAGES/mailman.po (renamed from messages/vi/LC_MESSAGES/mailman.po)0
-rw-r--r--Mailman/messages/zh_CN/LC_MESSAGES/mailman.po (renamed from messages/zh_CN/LC_MESSAGES/mailman.po)0
-rw-r--r--Mailman/messages/zh_TW/LC_MESSAGES/mailman.po (renamed from messages/zh_TW/LC_MESSAGES/mailman.po)0
-rw-r--r--Mailman/templates/__init__.py0
-rw-r--r--Mailman/templates/en/adminaddrchgack.txt (renamed from templates/en/adminaddrchgack.txt)0
-rw-r--r--Mailman/templates/en/admindbdetails.html (renamed from templates/en/admindbdetails.html)0
-rw-r--r--Mailman/templates/en/admindbpreamble.html (renamed from templates/en/admindbpreamble.html)0
-rw-r--r--Mailman/templates/en/admindbsummary.html (renamed from templates/en/admindbsummary.html)0
-rw-r--r--Mailman/templates/en/adminsubscribeack.txt (renamed from templates/en/adminsubscribeack.txt)0
-rw-r--r--Mailman/templates/en/adminunsubscribeack.txt (renamed from templates/en/adminunsubscribeack.txt)0
-rw-r--r--Mailman/templates/en/admlogin.html (renamed from templates/en/admlogin.html)0
-rw-r--r--Mailman/templates/en/approve.txt (renamed from templates/en/approve.txt)0
-rw-r--r--Mailman/templates/en/archidxentry.html (renamed from templates/en/archidxentry.html)0
-rw-r--r--Mailman/templates/en/archidxfoot.html (renamed from templates/en/archidxfoot.html)0
-rw-r--r--Mailman/templates/en/archidxhead.html (renamed from templates/en/archidxhead.html)0
-rw-r--r--Mailman/templates/en/archlistend.html (renamed from templates/en/archlistend.html)0
-rw-r--r--Mailman/templates/en/archliststart.html (renamed from templates/en/archliststart.html)0
-rw-r--r--Mailman/templates/en/archtoc.html (renamed from templates/en/archtoc.html)0
-rw-r--r--Mailman/templates/en/archtocentry.html (renamed from templates/en/archtocentry.html)0
-rw-r--r--Mailman/templates/en/archtocnombox.html (renamed from templates/en/archtocnombox.html)0
-rw-r--r--Mailman/templates/en/article.html (renamed from templates/en/article.html)0
-rw-r--r--Mailman/templates/en/bounce.txt (renamed from templates/en/bounce.txt)0
-rw-r--r--Mailman/templates/en/checkdbs.txt (renamed from templates/en/checkdbs.txt)0
-rw-r--r--Mailman/templates/en/convert.txt (renamed from templates/en/convert.txt)0
-rw-r--r--Mailman/templates/en/cronpass.txt (renamed from templates/en/cronpass.txt)0
-rw-r--r--Mailman/templates/en/disabled.txt (renamed from templates/en/disabled.txt)0
-rw-r--r--Mailman/templates/en/emptyarchive.html (renamed from templates/en/emptyarchive.html)0
-rw-r--r--Mailman/templates/en/headfoot.html (renamed from templates/en/headfoot.html)0
-rw-r--r--Mailman/templates/en/help.txt (renamed from templates/en/help.txt)0
-rw-r--r--Mailman/templates/en/invite.txt (renamed from templates/en/invite.txt)0
-rw-r--r--Mailman/templates/en/listinfo.html (renamed from templates/en/listinfo.html)0
-rw-r--r--Mailman/templates/en/masthead.txt (renamed from templates/en/masthead.txt)0
-rw-r--r--Mailman/templates/en/newlist.txt (renamed from templates/en/newlist.txt)0
-rw-r--r--Mailman/templates/en/nomoretoday.txt (renamed from templates/en/nomoretoday.txt)0
-rw-r--r--Mailman/templates/en/options.html (renamed from templates/en/options.html)0
-rw-r--r--Mailman/templates/en/postack.txt (renamed from templates/en/postack.txt)0
-rw-r--r--Mailman/templates/en/postauth.txt (renamed from templates/en/postauth.txt)0
-rw-r--r--Mailman/templates/en/postheld.txt (renamed from templates/en/postheld.txt)0
-rw-r--r--Mailman/templates/en/private.html (renamed from templates/en/private.html)0
-rw-r--r--Mailman/templates/en/probe.txt (renamed from templates/en/probe.txt)0
-rw-r--r--Mailman/templates/en/refuse.txt (renamed from templates/en/refuse.txt)0
-rw-r--r--Mailman/templates/en/roster.html (renamed from templates/en/roster.html)0
-rw-r--r--Mailman/templates/en/subauth.txt (renamed from templates/en/subauth.txt)0
-rw-r--r--Mailman/templates/en/subscribe.html (renamed from templates/en/subscribe.html)0
-rw-r--r--Mailman/templates/en/subscribeack.txt (renamed from templates/en/subscribeack.txt)0
-rw-r--r--Mailman/templates/en/unsub.txt (renamed from templates/en/unsub.txt)0
-rw-r--r--Mailman/templates/en/unsubauth.txt (renamed from templates/en/unsubauth.txt)0
-rw-r--r--Mailman/templates/en/userpass.txt (renamed from templates/en/userpass.txt)0
-rw-r--r--Mailman/templates/en/verify.txt (renamed from templates/en/verify.txt)0
-rwxr-xr-xMailman/testing/bounces/__init__.py0
-rw-r--r--Mailman/testing/test_bounces.py22
-rw-r--r--Mailman/testing/testing.cfg.in2
-rw-r--r--setup.py17
164 files changed, 530 insertions, 259 deletions
diff --git a/.bzrignore b/.bzrignore
index e007ba8c3..9c3023bfa 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -1,28 +1,6 @@
*.mo
.bzrignore
-Mailman/Defaults.py
-Mailman/mm_cfg.py.dist
-Makefile
build/
-config.log
-config.status
cron/crontab.in
mailman.egg-info
-misc/Elixir-0.3.0/
-misc/SQLAlchemy-0.3.3/
misc/mailman
-misc/paths.py
-misc/setuptools-0.6c3/
-misc/zope.interface-3.3.0.1/
-src/admin
-src/admindb
-src/confirm
-src/create
-src/edithtml
-src/listinfo
-src/mailman
-src/options
-src/private
-src/rmlist
-src/roster
-src/subscribe
diff --git a/Mailman/Cgi/admin.py b/Mailman/Cgi/admin.py
index cb001317e..fb0ab1a56 100644
--- a/Mailman/Cgi/admin.py
+++ b/Mailman/Cgi/admin.py
@@ -625,7 +625,8 @@ def get_item_gui_value(mlist, category, kind, varname, params, extra):
values, legend, selected = params
else:
codes = mlist.language_codes
- legend = [Utils.GetLanguageDescr(code) for code in codes]
+ legend = [config.languages.get_language_data(code)[0]
+ for code in codes]
selected = codes.index(mlist.preferred_language)
return SelectOptions(varname, values, legend, selected)
elif kind == config.Topics:
@@ -986,7 +987,8 @@ def membership_options(mlist, subcat, cgidata, doc, form):
# User's preferred language
langpref = mlist.getMemberLanguage(addr)
langs = mlist.language_codes
- langdescs = [_(Utils.GetLanguageDescr(lang)) for lang in langs]
+ langdescs = [_(config.languges.get_language_data(code)[0])
+ for code in langs]
try:
selected = langs.index(langpref)
except ValueError:
@@ -1402,7 +1404,9 @@ def change_options(mlist, category, subcat, cgidata, doc):
newlang = cgidata.getvalue(user+'_language')
oldlang = mlist.getMemberLanguage(user)
- if Utils.IsLanguage(newlang) and newlang <> oldlang:
+ if (newlang not in config.languages.enabled_codes
+ and newlang <> oldlang):
+ # Then
mlist.setMemberLanguage(user, newlang)
moderate = not not cgidata.getvalue(user+'_mod')
diff --git a/Mailman/Cgi/confirm.py b/Mailman/Cgi/confirm.py
index d2bc3b0aa..aee6df46b 100644
--- a/Mailman/Cgi/confirm.py
+++ b/Mailman/Cgi/confirm.py
@@ -286,7 +286,7 @@ def subscription_prompt(mlist, doc, cookie, userdesc):
RadioButtonArray('digests', (_('No'), _('Yes')),
checked=digest, values=(0, 1))])
langs = mlist.language_codes
- values = [_(Utils.GetLanguageDescr(l)) for l in langs]
+ values = [_(config.languages.get_language_data(code)[0]) for code in langs]
try:
selected = langs.index(lang)
except ValueError:
@@ -332,7 +332,7 @@ def subscription_confirm(mlist, doc, cookie, cgidata):
# Some pending values may be overridden in the form. email of
# course is hardcoded. ;)
lang = cgidata.getvalue('language')
- if not Utils.IsLanguage(lang):
+ if lang not in config.languages.enabled_codes:
lang = mlist.preferred_language
i18n.set_language(lang)
doc.set_language(lang)
diff --git a/Mailman/Cgi/create.py b/Mailman/Cgi/create.py
index 0ca51bd65..978f1b9ac 100644
--- a/Mailman/Cgi/create.py
+++ b/Mailman/Cgi/create.py
@@ -361,13 +361,15 @@ def request_creation(doc, cgidata=dummy, errmsg=None):
# invocations.
checked = [0] * len(langs)
checked[langi] = 1
- deflang = _(Utils.GetLanguageDescr(config.DEFAULT_SERVER_LANGUAGE))
+ deflang = _(config.languages.get_language_data(
+ config.DEFAULT_SERVER_LANGUAGE)[0])
ftable.AddRow([Label(_(
"""Initial list of supported languages. <p>Note that if you do not
select at least one initial language, the list will use the server
default language of $deflang""")),
CheckBoxArray('langs',
- [_(Utils.GetLanguageDescr(L)) for L in langs],
+ [_(config.languges.get_language_data(code)[0])
+ for code in langs],
checked=checked,
values=langs)])
ftable.AddCellInfo(ftable.GetCurrentRowIndex(), 0, bgcolor=GREY)
diff --git a/Mailman/Cgi/listinfo.py b/Mailman/Cgi/listinfo.py
index 72ef6bfa9..9861e2496 100644
--- a/Mailman/Cgi/listinfo.py
+++ b/Mailman/Cgi/listinfo.py
@@ -57,7 +57,7 @@ def main():
# See if the user want to see this page in other language
cgidata = cgi.FieldStorage()
language = cgidata.getvalue('language')
- if not Utils.IsLanguage(language):
+ if language not in config.languages.enabled_codes:
language = mlist.preferred_language
i18n.set_language(language)
list_listinfo(mlist, language)
diff --git a/Mailman/Cgi/options.py b/Mailman/Cgi/options.py
index e7e7264a1..faa813489 100644
--- a/Mailman/Cgi/options.py
+++ b/Mailman/Cgi/options.py
@@ -88,7 +88,7 @@ def main():
# preference to view the page in, so we should honor that here. If that's
# not available, use the list's default language.
language = cgidata.getvalue('language')
- if not Utils.IsLanguage(language):
+ if language not in config.languages.enabled_codes:
language = mlist.preferred_language
i18n.set_language(language)
doc.set_language(language)
@@ -138,7 +138,7 @@ def main():
# user's stored preferred language, overridden by any form settings for
# their new language preference.
userlang = cgidata.getvalue('language')
- if not Utils.IsLanguage(userlang):
+ if userlang not in config.languages.enabled_codes:
userlang = mlist.getMemberLanguage(user)
doc.set_language(userlang)
i18n.set_language(userlang)
diff --git a/Mailman/Cgi/rmlist.py b/Mailman/Cgi/rmlist.py
index 080d3b492..534d06131 100644
--- a/Mailman/Cgi/rmlist.py
+++ b/Mailman/Cgi/rmlist.py
@@ -141,7 +141,7 @@ def process_request(doc, cgidata, mlist):
problems = 0
listname = mlist.internal_name()
for dirtmpl in REMOVABLES:
- dir = os.path.join(config.VAR_PREFIX, dirtmpl % listname)
+ dir = os.path.join(config.VAR_DIR, dirtmpl % listname)
if os.path.islink(dir):
try:
os.unlink(dir)
diff --git a/Mailman/Cgi/roster.py b/Mailman/Cgi/roster.py
index fdeb83d31..4eb3174cd 100644
--- a/Mailman/Cgi/roster.py
+++ b/Mailman/Cgi/roster.py
@@ -64,7 +64,7 @@ def main():
# messages in form should go in selected language (if any...)
lang = cgidata.getvalue('language')
- if not Utils.IsLanguage(lang):
+ if lang not in config.languages.enabled_codes:
lang = mlist.preferred_language
i18n.set_language(lang)
diff --git a/Mailman/Cgi/subscribe.py b/Mailman/Cgi/subscribe.py
index 3d66cac42..512cd3195 100644
--- a/Mailman/Cgi/subscribe.py
+++ b/Mailman/Cgi/subscribe.py
@@ -70,7 +70,7 @@ def main():
# for the results. If not, use the list's preferred language.
cgidata = cgi.FieldStorage()
language = cgidata.getvalue('language')
- if not Utils.IsLanguage(language):
+ if language not in config.languages.enabled_codes:
language = mlist.preferred_language
i18n.set_language(language)
doc.set_language(language)
diff --git a/Mailman/Defaults.py.in b/Mailman/Defaults.py
index 0bc552d26..3c06b709a 100644
--- a/Mailman/Defaults.py.in
+++ b/Mailman/Defaults.py
@@ -101,6 +101,9 @@ HTML_TO_PLAIN_TEXT_COMMAND = '/usr/bin/lynx -dump %(filename)s'
# available schemes.
PASSWORD_SCHEME = 'ssha'
+# Default run-time directory.
+DEFAULT_VAR_DIRECTORY = '/var/mailman'
+
#####
@@ -200,6 +203,9 @@ WEB_ALINK_COLOR = '' # If true, forces ALINK=
WEB_VLINK_COLOR = '' # If true, forces VLINK=
WEB_HIGHLIGHT_COLOR = '#dddddd' # If true, alternating rows
# in listinfo & admin display
+# CGI file extension.
+CGIEXT = ''
+
#####
@@ -804,8 +810,8 @@ MAX_RESTARTS = 10
#####
# The default language for this server. Whenever we can't figure out the list
-# context or user context, we'll fall back to using this language. See
-# LC_DESCRIPTIONS below for legal values.
+# context or user context, we'll fall back to using this language. This code
+# must be in the list of available language codes.
DEFAULT_SERVER_LANGUAGE = 'en'
# When allowing only members to post to a mailing list, how is the sender of
@@ -1240,14 +1246,6 @@ PENDINGDB_LOCK_DEBUGGING = Off
# any of them in your mailman.cfg file!
#####
-# This is the top-level run-time data directory. All other runtime data by
-# default lives under this directory.
-RUNTIME_DIR = '$runtime_dir'
-
-# Group id that group-owns the Mailman installation
-MAILMAN_USER = '$user_name'
-MAILMAN_GROUP = '$group_name'
-
# Enumeration for Mailman cgi widget types
Toggle = 1
Radio = 2
@@ -1365,8 +1363,7 @@ from Version import *
def _(s):
return s
-LANGUAGES = 'en ' + '@LANGUAGES@'
-LANGUAGE_DICT = {
+_DEFAULT_LANGUAGE_DATA = {
'ar': (_('Arabic'), 'utf-8'),
'ca': (_('Catalan'), 'iso-8859-1'),
'cs': (_('Czech'), 'iso-8859-2'),
@@ -1402,13 +1399,5 @@ LANGUAGE_DICT = {
'zh_TW': (_('Chinese (Taiwan)'), 'utf-8'),
}
-LC_DESCRIPTIONS = {}
-
-def add_language(code, description, charset):
- LC_DESCRIPTIONS[code] = (description, charset)
-
-for lang in LANGUAGES.split():
- if lang in LANGUAGE_DICT.keys():
- add_language(lang, LANGUAGE_DICT[lang][0], LANGUAGE_DICT[lang][1])
del _
diff --git a/Mailman/Gui/Language.py b/Mailman/Gui/Language.py
index 32029577d..bcd0ba93b 100644
--- a/Mailman/Gui/Language.py
+++ b/Mailman/Gui/Language.py
@@ -37,7 +37,7 @@ class Language(GUIBase):
return None
# Set things up for the language choices
langs = mlist.language_codes
- langnames = [_(Utils.GetLanguageDescr(L)) for L in langs]
+ langnames = [_(description) for description in config.enabled_names]
try:
langi = langs.index(mlist.preferred_language)
except ValueError:
@@ -53,12 +53,11 @@ class Language(GUIBase):
except LookupError:
return 0
- all = [key for key in config.LC_DESCRIPTIONS.keys()
- if checkcodec(Utils.GetCharSet(key))]
- all.sort()
+ all = sorted(code for code in config.languages.enabled_codes
+ if checkcodec(Utils.GetCharSet(code)))
checked = [L in langs for L in all]
- allnames = [_(Utils.GetLanguageDescr(L)) for L in all]
-
+ allnames = [_(config.languages.get_language_data(code)[0])
+ for code in all]
return [
_('Natural language (internationalization) options.'),
diff --git a/Mailman/HTMLFormatter.py b/Mailman/HTMLFormatter.py
index ab4c03a32..a5e69dbcd 100644
--- a/Mailman/HTMLFormatter.py
+++ b/Mailman/HTMLFormatter.py
@@ -377,7 +377,8 @@ class HTMLFormatter:
# If only one language is enabled for this mailing list, omit the
# language choice buttons.
if len(self.language_codes) == 1:
- listlangs = _(Utils.GetLanguageDescr(self.preferred_language))
+ listlangs = _(config.languages.get_language_data(
+ self.preferred_language))
else:
listlangs = self.GetLangSelectBox(lang).Format()
d = {
@@ -424,7 +425,8 @@ class HTMLFormatter:
lang = self.preferred_language
# Figure out the available languages
values = self.language_codes
- legend = [Utils.GetLanguageDescr(code) for code in values]
+ legend = [config.languages.get_language_data(code)[0]
+ for code in values]
try:
selected = values.index(lang)
except ValueError:
diff --git a/Mailman/MailList.py b/Mailman/MailList.py
index 9d784de51..76538e6c2 100644
--- a/Mailman/MailList.py
+++ b/Mailman/MailList.py
@@ -1410,8 +1410,10 @@ bad regexp in bounce_matching_header line: %s
# default server language. The effect would be that the default
# server language would never get added to the list's list of
# languages.
- self.available_languages = [Language(code) for code in language_codes
- if code in config.LC_DESCRIPTIONS]
+ requested_codes = set(language_codes)
+ enabled_codes = set(config.languages.enabled_codes)
+ self.available_languages = [
+ Language(code) for code in requested_codes & enabled_codes]
def add_language(self, language_code):
self.available_languages.append(Language(language_code))
@@ -1419,12 +1421,13 @@ bad regexp in bounce_matching_header line: %s
@property
def language_codes(self):
# Callers of this method expect a list of language codes
- codes = [lang.code for lang in self.available_languages
- if lang.code in config.LC_DESCRIPTIONS]
+ available_codes = set(self.available_languages)
+ enabled_codes = set(config.languages.enabled_codes)
+ codes = available_codes & enabled_codes
# If we don't add this, and the site admin has never added any
# language support to the list, then the general admin page may have a
# blank field where the list owner is supposed to chose the list's
# preferred language.
if config.DEFAULT_SERVER_LANGUAGE not in codes:
- codes.append(config.DEFAULT_SERVER_LANGUAGE)
- return codes
+ codes.add(config.DEFAULT_SERVER_LANGUAGE)
+ return list(codes)
diff --git a/Mailman/OldStyleMemberships.py b/Mailman/OldStyleMemberships.py
index 2a72b8928..594096d9e 100644
--- a/Mailman/OldStyleMemberships.py
+++ b/Mailman/OldStyleMemberships.py
@@ -29,8 +29,8 @@ import time
from Mailman import Errors
from Mailman import MemberAdaptor
from Mailman import Utils
-from Mailman import mm_cfg
from Mailman import passwords
+from Mailman.configuration import config
ISREGULAR = 1
ISDIGEST = 2
diff --git a/Mailman/SafeDict.py b/Mailman/SafeDict.py
index 876ab88e4..52f78c6a2 100644
--- a/Mailman/SafeDict.py
+++ b/Mailman/SafeDict.py
@@ -35,7 +35,7 @@ class SafeDict(dict):
if charset:
self.cset = charset
elif lang:
- self.cset = config.LC_DESCRIPTIONS[lang][1]
+ self.cset = config.languages.get_language_data(lang)[1]
else:
self.cset = 'us-ascii'
diff --git a/Mailman/Utils.py b/Mailman/Utils.py
index 064de570e..4121d3d75 100644
--- a/Mailman/Utils.py
+++ b/Mailman/Utils.py
@@ -39,6 +39,7 @@ import email.Iterators
from email.Errors import HeaderParseError
from string import ascii_letters, digits, whitespace
+import Mailman.templates
from Mailman import Errors
from Mailman import passwords
from Mailman.SafeDict import SafeDict
@@ -51,6 +52,7 @@ EMPTYSTRING = ''
IDENTCHARS = ascii_letters + digits + '_'
NL = '\n'
UEMPTYSTRING = u''
+TEMPLATE_DIR = os.path.dirname(Mailman.templates.__file__)
# Search for $(identifier)s strings, except that the trailing s is optional,
# since that's a common mistake
@@ -450,7 +452,9 @@ def findtext(templatefile, dict=None, raw=False, lang=None, mlist=None):
# language. After that, the server default language is used for
# <language>. If that still doesn't yield a template, then the standard
# distribution's English language template is used as an ultimate
- # fallback. If that's missing you've got big problems. ;)
+ # fallback, and when lang is not 'en', the resulting template is passed
+ # through the translation service. If this template is missing you've got
+ # big problems. ;)
#
# A word on backwards compatibility: Mailman versions prior to 2.1 stored
# templates in templates/*.{html,txt} and lists/<listname>/*.{html,txt}.
@@ -466,19 +470,19 @@ def findtext(templatefile, dict=None, raw=False, lang=None, mlist=None):
# item returned.
#
# Calculate the languages to scan
- languages = []
+ languages = set()
if lang is not None:
- languages.append(lang)
+ languages.add(lang)
if mlist is not None:
- languages.append(mlist.preferred_language)
- languages.append(config.DEFAULT_SERVER_LANGUAGE)
+ languages.add(mlist.preferred_language)
+ languages.add(config.DEFAULT_SERVER_LANGUAGE)
# Calculate the locations to scan
searchdirs = []
if mlist is not None:
searchdirs.append(mlist.full_path)
- searchdirs.append(os.path.join(config.TEMPLATE_DIR, mlist.host_name))
- searchdirs.append(os.path.join(config.TEMPLATE_DIR, 'site'))
- searchdirs.append(config.TEMPLATE_DIR)
+ searchdirs.append(os.path.join(TEMPLATE_DIR, mlist.host_name))
+ searchdirs.append(os.path.join(TEMPLATE_DIR, 'site'))
+ searchdirs.append(TEMPLATE_DIR)
# Start scanning
fp = None
try:
@@ -498,24 +502,31 @@ def findtext(templatefile, dict=None, raw=False, lang=None, mlist=None):
# Try one last time with the distro English template, which, unless
# you've got a really broken installation, must be there.
try:
- filename = os.path.join(config.TEMPLATE_DIR, 'en', templatefile)
+ filename = os.path.join(TEMPLATE_DIR, 'en', templatefile)
fp = open(filename)
except IOError, e:
- if e.errno <> errno.ENOENT: raise
+ if e.errno <> errno.ENOENT:
+ raise
# We never found the template. BAD!
raise IOError(errno.ENOENT, 'No template file found', templatefile)
- template = fp.read()
- fp.close()
- template = unicode(template, GetCharSet(lang), 'replace')
+ else:
+ from Mailman.i18n import get_translation
+ # XXX BROKEN HACK
+ data = fp.read()[:-1]
+ template = get_translation().ugettext(data)
+ fp.close()
+ else:
+ template = fp.read()
+ fp.close()
+ template = unicode(template, GetCharSet(lang), 'replace')
text = template
if dict is not None:
try:
sdict = SafeDict(dict, lang=lang)
text = sdict.interpolate(template)
- except (TypeError, ValueError), e:
+ except (TypeError, ValueError):
# The template is really screwed up
- log.error('broken template: %s\n%s', filename, e)
- pass
+ log.exception('broken template: %s', filename)
if raw:
return text, filename
return wrap(text), filename
@@ -646,15 +657,10 @@ def makedirs(path, mode=02775):
-def GetLanguageDescr(lang):
- return config.LC_DESCRIPTIONS[lang][0]
-
-
+# XXX Replace this with direct calls. For now, existing uses of GetCharSet()
+# are too numerous to change.
def GetCharSet(lang):
- return config.LC_DESCRIPTIONS[lang][1]
-
-def IsLanguage(lang):
- return config.LC_DESCRIPTIONS.has_key(lang)
+ return config.languages.get_language_data(lang)[1]
diff --git a/Mailman/bin/make_instance.py b/Mailman/bin/make_instance.py
index 435b0863a..14eed24ce 100644
--- a/Mailman/bin/make_instance.py
+++ b/Mailman/bin/make_instance.py
@@ -21,23 +21,21 @@ import os
import grp
import pwd
import sys
+import errno
+import shutil
import optparse
import setuptools
from string import Template
-import Mailman
-from Mailman.Version import MAILMAN_VERSION
+import Mailman.data
-# Until an instance is actually created, this module won't be importable
-# because the Defaults.py module won't have been created yet.
-try:
- from Mailman.i18n import _
-except ImportError:
- def _(s): return s
+from Mailman import Defaults
+from Mailman.Version import MAILMAN_VERSION
+from Mailman.i18n import _
__i18n_templates__ = True
SPACE = ' '
-DEFAULT_RUNTIME_DIR = '/var/mailman'
+DATA_DIR = os.path.dirname(Mailman.data.__file__)
@@ -49,11 +47,17 @@ def parseargs():
Create a Mailman instance by generating all the necessary basic configuration
support and intervening directories.
"""))
- parser.add_option('-r', '--runtime-dir',
- type='string', default=DEFAULT_RUNTIME_DIR, help=_("""\
+ parser.add_option('-d', '--var-dir',
+ type='string', default=Defaults.DEFAULT_VAR_DIRECTORY,
+ help=_("""\
The top-level runtime data directory. All supporting runtime data will be
placed in subdirectories of this directory. It will be created if necessary,
although this might require superuser privileges."""))
+ parser.add_option('-f', '--force',
+ default=False, action='store_true', help=_("""\
+Force overwriting of mailman.cfg file with new values. Ordinarily, Mailman
+will never overwrite this file because it would cause you to lose your
+configuration data."""))
parser.add_option('-p', '--permchecks',
default=False, action='store_true', help=_("""\
Perform permission checks on the runtime directory."""))
@@ -65,9 +69,13 @@ current user is used."""))
type='string', default=None, help=_("""\
The group id or name to use for the runtime environment. If not specified, the
current group is used."""))
- parser.add_option('-l', '--language',
- default=[], type='string', action='append', help=_("""\
-Enable the given language. Use 'all' to enable all supported languages."""))
+ parser.add_option('-l', '--languages',
+ default=Defaults.DEFAULT_SERVER_LANGUAGE, type='string',
+ help=_("""\
+Space separated list of language codes to enable. Use -L to print all
+available language codes and the name of the associated native language.
+Default is to enable just English. Use the special code 'all' to enable all
+available languages."""))
opts, args = parser.parse_args()
if args:
unexpected = SPACE.join(args)
@@ -76,13 +84,9 @@ Enable the given language. Use 'all' to enable all supported languages."""))
-def instantiate(user=None, group=None, runtime_dir=None):
- # Create the Defaults.py file using substitutions.
- in_file_path = os.path.join(os.path.dirname(Mailman.__file__),
- 'Defaults.py.in')
- out_file_path = os.path.splitext(in_file_path)[0]
- with open(in_file_path) as fp:
- raw = Template(fp.read())
+def instantiate(var_dir, user, group, languages, force):
+ # XXX This needs to be converted to use package resources.
+ etc_dir = os.path.join(var_dir, 'etc')
# Figure out which user name and group name to use.
if user is None:
uid = os.getuid()
@@ -112,20 +116,56 @@ def instantiate(user=None, group=None, runtime_dir=None):
group_name = grp.getgrgid(gid).gr_name
except KeyError:
parser.print_error(_('Unknown group: $group'))
- # Process the .in file and write it to Defaults.py.
- processed = raw.safe_substitute(runtime_dir=runtime_dir,
- user_name=user_name,
- group_name=group_name)
- with open(out_file_path, 'w') as fp:
- fp.write(processed)
+ # Make the runtime dir if it doesn't yet exist.
+ try:
+ omask = os.umask(0)
+ try:
+ os.makedirs(etc_dir, 02775)
+ finally:
+ os.umask(omask)
+ except OSError, e:
+ # Ignore the exceptions if the directory already exists
+ if e.errno <> errno.EEXIST:
+ raise
+ os.chown(etc_dir, uid, gid)
+ # Create an etc/mailman.cfg file which contains just a few configuration
+ # variables about the run-time environment that can't be calculated.
+ # Don't overwrite mailman.cfg unless the -f flag was given.
+ in_file_path = os.path.join(DATA_DIR, 'mailman.cfg.in')
+ out_file_path = os.path.join(etc_dir, 'mailman.cfg')
+ if os.path.exists(out_file_path) and not force:
+ # The logging subsystem isn't up yet, so just print this to stderr.
+ print >> sys.stderr, 'File exists:', out_file_path
+ print >> sys.stderr, 'Use --force to override.'
+ else:
+ with open(in_file_path) as fp:
+ raw = Template(fp.read())
+ processed = raw.safe_substitute(var_dir=var_dir,
+ user_id=uid,
+ user_name=user_name,
+ group_name=group_name,
+ group_id=gid,
+ languages=SPACE.join(languages),
+ )
+ with open(out_file_path, 'w') as fp:
+ fp.write(processed)
# XXX Do --permchecks
- # XXX Do --language
def main():
parser, opts, args = parseargs()
- instantiate(opts.user, opts.group, opts.runtime_dir)
+ available_languages = set(Defaults.LANGUAGE_DICT)
+ enable_languages = set(opts.languages.split())
+ if 'all' in enable_languages:
+ languages = available_languages
+ else:
+ unknown_language = enable_languages - available_languages
+ if unknown_language:
+ print >> sys.stderr, 'Ignoring unknown language codes:', \
+ SPACE.join(unknown_language)
+ languages = available_languages & enable_languages
+ instantiate(opts.var_dir, opts.user, opts.group, languages, opts.force)
diff --git a/Mailman/bin/newlist.py b/Mailman/bin/newlist.py
index 5ac2dc5a6..1bbe818ff 100644
--- a/Mailman/bin/newlist.py
+++ b/Mailman/bin/newlist.py
@@ -104,7 +104,7 @@ def main():
if opts.language is None:
opts.language = config.DEFAULT_SERVER_LANGUAGE
# Is the language known?
- if opts.language not in config.LC_DESCRIPTIONS:
+ if opts.language not in config.languages.enabled_codes:
parser.print_help()
print >> sys.stderr, _('Unknown language: $opts.language')
sys.exit(1)
diff --git a/Mailman/bin/rmlist.py b/Mailman/bin/rmlist.py
index 26dbd1df7..fcc47b3f0 100644
--- a/Mailman/bin/rmlist.py
+++ b/Mailman/bin/rmlist.py
@@ -83,7 +83,7 @@ def delete_list(listname, mlist=None, archives=True, quiet=False):
])
for dirtmpl, msg in removeables:
- path = os.path.join(config.VAR_PREFIX, dirtmpl)
+ path = os.path.join(config.VAR_DIR, dirtmpl)
remove_it(listname, path, msg, quiet)
diff --git a/Mailman/bin/testall.py b/Mailman/bin/testall.py
index 005808cfe..a5c9d02e6 100644
--- a/Mailman/bin/testall.py
+++ b/Mailman/bin/testall.py
@@ -167,7 +167,7 @@ def main():
# Set up the testing configuration file both for this process, and for all
# sub-processes testing will spawn (e.g. the qrunners).
#
- # Calculate a temporary VAR_PREFIX directory so that run-time artifacts of
+ # Calculate a temporary VAR_DIR directory so that run-time artifacts of
# the tests won't tread on the installation's data. This also makes it
# easier to clean up after the tests are done, and insures isolation of
# test suite runs.
@@ -177,14 +177,24 @@ def main():
os.close(fd)
shutil.copyfile(cfg_in, cfg_out)
- var_prefix = tempfile.mkdtemp()
+ var_dir = tempfile.mkdtemp()
if opts.verbosity > 2:
- print 'VAR_PREFIX :', var_prefix
+ print 'VAR_DIR :', var_dir
print 'config file:', cfg_out
+ user_id = os.getuid()
+ user_name = pwd.getpwuid(user_id).pw_name
+ group_id = os.getgid()
+ group_name = grp.getgrgid(group_id).gr_name
+
try:
with open(cfg_out, 'a') as fp:
- print >> fp, 'VAR_PREFIX = "%s"' % var_prefix
+ print >> fp, 'VAR_DIR = "%s"' % var_dir
+ print >> fp, 'MAILMAN_USER = "%s"' % user_name
+ print >> fp, 'MAILMAN_UID = %d' % user_id
+ print >> fp, 'MAILMAN_GROUP = "%s"' % group_name
+ print >> fp, 'MAILMAN_GID = %d' % group_id
+ print >> fp, "LANGUAGES = 'en'"
initialize_1(cfg_out, propagate_logs=opts.stderr)
mailman_uid = pwd.getpwnam(config.MAILMAN_USER).pw_uid
@@ -216,7 +226,7 @@ def main():
results = runner.run(suite(args))
finally:
os.remove(cfg_out)
- shutil.rmtree(var_prefix)
+ shutil.rmtree(var_dir)
# Turn off coverage and print a report
if opts.coverage:
diff --git a/Mailman/bin/withlist.py b/Mailman/bin/withlist.py
index ac1ab0aac..5e4655100 100644
--- a/Mailman/bin/withlist.py
+++ b/Mailman/bin/withlist.py
@@ -190,10 +190,6 @@ def main():
VERBOSE = not opts.quiet
LOCK = opts.lock
- # Append our bin directory to sys.path so that any withlist scripts living
- # their can be simply imported.
- sys.path.append(config.BIN_DIR)
-
# The default for interact is true unless -r was given
if opts.interactive is None:
if not opts.run:
diff --git a/Mailman/configuration.py b/Mailman/configuration.py
index a8ecdae84..dbb057a5f 100644
--- a/Mailman/configuration.py
+++ b/Mailman/configuration.py
@@ -18,10 +18,12 @@
"""Configuration file loading and management."""
import os
+import sys
import errno
from Mailman import Defaults
from Mailman import Errors
+from Mailman.languages import LanguageManager
_missing = object()
@@ -46,63 +48,80 @@ class Configuration(object):
def load(self, filename=None):
join = os.path.join
- # Load the configuration from the named file, or if not given, search
- # in the runtime data directory for an etc/mailman.cfg file. If that
- # file is missing, use Mailman/mm_cfg.py for backward compatibility.
- #
- # Whatever you find, create a namespace and execfile that file in it.
- # The values in that namespace are exposed as attributes on this
- # Configuration instance.
- original_filename = filename
- if filename is None:
- filename = join(Defaults.RUNTIME_DIR, 'etc', 'mailman.cfg')
# Set up the execfile namespace
ns = Defaults.__dict__.copy()
# Prune a few things, add a few things
del ns['__file__']
del ns['__name__']
del ns['__doc__']
- ns['add_domain'] = self.add_domain
+ ns['add_domain'] = self.add_domain
ns['add_qrunner'] = self.add_qrunner
ns['del_qrunner'] = self.del_qrunner
+ self._languages = LanguageManager()
+ ns['add_language'] = self._languages.add_language
+ ns['enable_language'] = self._languages.enable_language
+ # Add all known languages, but don't enable them.
+ for code, (desc, charset) in Defaults._DEFAULT_LANGUAGE_DATA.items():
+ self._languages.add_language(code, desc, charset, False)
# Set up the default list of qrunners so that the mailman.cfg file may
# add or delete them.
for name in DEFAULT_QRUNNERS:
self.add_qrunner(name)
- # Attempt our first choice
- path = os.path.abspath(os.path.expanduser(filename))
- print 'path:', path
- try:
- execfile(path, ns, ns)
- self.filename = path
- except EnvironmentError, e:
- if e.errno <> errno.ENOENT or original_filename:
- raise
- # The file didn't exist, so try mm_cfg.py
- from Mailman import mm_cfg
- ns.update(mm_cfg.__dict__)
- self.filename = None
- # Based on values possibly set in mailman.cfg, add additional qrunners
+ # Load the configuration from the named file, or if not given, search
+ # in the runtime data directory for an etc/mailman.cfg file. If there
+ # is an instance.cfg file in the same directory, load that first, then
+ # mailman.cfg.
+ #
+ # Whatever you find, create a namespace and execfile that file in it.
+ # The values in that namespace are exposed as attributes on this
+ # Configuration instance.
+ self.filename = None
+ paths = [
+ # Development directories.
+ join(os.getcwd(), 'etc', 'mailman.cfg'),
+ join(os.getcwd(), 'var', 'etc', 'mailman.cfg'),
+ # Standard installation directories.
+ join('/etc', 'mailman.cfg'),
+ join(Defaults.DEFAULT_VAR_DIRECTORY, 'etc', 'mailman.cfg'),
+ ]
+ if filename is not None:
+ paths.insert(0, filename)
+ for cfg_path in paths:
+ path = os.path.abspath(os.path.expanduser(cfg_path))
+ try:
+ execfile(path, ns, ns)
+ except EnvironmentError, e:
+ if e.errno <> errno.ENOENT:
+ # It's okay if the instance.cfg file does not exist. This
+ # can happen for example in the test suite.
+ raise
+ else:
+ self.filename = cfg_path
+ break
+ if self.filename is None:
+ # The logging subsystem isn't running yet, so use stderr.
+ print >> sys.stderr, 'No runtime configuration file file. Use -C'
+ sys.exit(-1)
+ # Based on values possibly set in mailman.cfg, add additional qrunners.
if ns['USE_MAILDIR']:
self.add_qrunner('Maildir')
if ns['USE_LMTP']:
self.add_qrunner('LMTP')
- # Pull out the defaults
- RUNTIME_DIR = ns['RUNTIME_DIR']
+ # Pull out the defaults.
+ VAR_DIR = ns['VAR_DIR']
# Now that we've loaded all the configuration files we're going to
# load, set up some useful directories.
- self.LIST_DATA_DIR = join(RUNTIME_DIR, 'lists')
- self.LOG_DIR = join(RUNTIME_DIR, 'logs')
- self.LOCK_DIR = lockdir = join(RUNTIME_DIR, 'locks')
- self.DATA_DIR = datadir = join(RUNTIME_DIR, 'data')
- self.ETC_DIR = etcdir = join(RUNTIME_DIR, 'etc')
- self.SPAM_DIR = join(RUNTIME_DIR, 'spam')
- self.EXT_DIR = join(RUNTIME_DIR, 'ext')
- self.PUBLIC_ARCHIVE_FILE_DIR = join(RUNTIME_DIR, 'archives', 'public')
- self.PRIVATE_ARCHIVE_FILE_DIR = join(
- RUNTIME_DIR, 'archives', 'private')
+ self.LIST_DATA_DIR = join(VAR_DIR, 'lists')
+ self.LOG_DIR = join(VAR_DIR, 'logs')
+ self.LOCK_DIR = lockdir = join(VAR_DIR, 'locks')
+ self.DATA_DIR = datadir = join(VAR_DIR, 'data')
+ self.ETC_DIR = etcdir = join(VAR_DIR, 'etc')
+ self.SPAM_DIR = join(VAR_DIR, 'spam')
+ self.EXT_DIR = join(VAR_DIR, 'ext')
+ self.PUBLIC_ARCHIVE_FILE_DIR = join(VAR_DIR, 'archives', 'public')
+ self.PRIVATE_ARCHIVE_FILE_DIR = join(VAR_DIR, 'archives', 'private')
# Directories used by the qrunner subsystem
- self.QUEUE_DIR = qdir = join(RUNTIME_DIR, 'qfiles')
+ self.QUEUE_DIR = qdir = join(VAR_DIR, 'qfiles')
self.INQUEUE_DIR = join(qdir, 'in')
self.OUTQUEUE_DIR = join(qdir, 'out')
self.CMDQUEUE_DIR = join(qdir, 'commands')
@@ -121,15 +140,33 @@ class Configuration(object):
self.CONFIG_FILE = join(etcdir, 'mailman.cfg')
self.LOCK_FILE = join(lockdir, 'master-qrunner')
# Now update our dict so attribute syntax just works
- if 'add_domain' in ns:
- del ns['add_domain']
- if 'add_runner' in ns:
- del ns['add_runner']
+ del ns['add_domain']
+ del ns['add_qrunner']
+ del ns['del_qrunner']
self.__dict__.update(ns)
# Add the default domain if there are no virtual domains currently
# defined.
if not self.domains:
self.add_domain(self.DEFAULT_EMAIL_HOST, self.DEFAULT_URL_HOST)
+ # Enable all specified languages, and promote the language manager to
+ # a public attribute.
+ self.languages = self._languages
+ del self._languages
+ available_languages = set(self._DEFAULT_LANGUAGE_DATA)
+ enabled_languages = set(self.LANGUAGES.split())
+ if 'all' in enabled_languages:
+ languages = available_languages
+ else:
+ unknown_language = enabled_languages - available_languages
+ if unknown_language:
+ print >> sys.stderr, 'Ignoring unknown language codes:', \
+ SPACE.join(unknown_language)
+ languages = available_languages & enabled_languages
+ for code in languages:
+ self.languages.enable_language(code)
+ # Always add and enable the default server language.
+ code = self.DEFAULT_SERVER_LANGUAGE
+ self.languages.enable_language(code)
def add_domain(self, email_host, url_host):
"""Add the definition of a virtual domain.
diff --git a/misc/Elixir-0.3.0.tar.gz b/Mailman/data/Elixir-0.3.0.tar.gz
index fd61be97e..fd61be97e 100644
--- a/misc/Elixir-0.3.0.tar.gz
+++ b/Mailman/data/Elixir-0.3.0.tar.gz
Binary files differ
diff --git a/misc/PythonPowered.png b/Mailman/data/PythonPowered.png
index 2e9d99c2d..2e9d99c2d 100644
--- a/misc/PythonPowered.png
+++ b/Mailman/data/PythonPowered.png
Binary files differ
diff --git a/misc/SQLAlchemy-0.3.3.tar.gz b/Mailman/data/SQLAlchemy-0.3.3.tar.gz
index 5732923fd..5732923fd 100644
--- a/misc/SQLAlchemy-0.3.3.tar.gz
+++ b/Mailman/data/SQLAlchemy-0.3.3.tar.gz
Binary files differ
diff --git a/Mailman/data/__init__.py b/Mailman/data/__init__.py
new file mode 100755
index 000000000..e69de29bb
--- /dev/null
+++ b/Mailman/data/__init__.py
diff --git a/misc/coverage.py b/Mailman/data/coverage.py
index 66e55e0c4..66e55e0c4 100644
--- a/misc/coverage.py
+++ b/Mailman/data/coverage.py
diff --git a/misc/gnu-head-tiny.jpg b/Mailman/data/gnu-head-tiny.jpg
index 441be50d6..441be50d6 100644
--- a/misc/gnu-head-tiny.jpg
+++ b/Mailman/data/gnu-head-tiny.jpg
Binary files differ
diff --git a/misc/mailman-large.jpg b/Mailman/data/mailman-large.jpg
index e184f3c6e..e184f3c6e 100644
--- a/misc/mailman-large.jpg
+++ b/Mailman/data/mailman-large.jpg
Binary files differ
diff --git a/misc/mailman.cfg.sample b/Mailman/data/mailman.cfg.in
index 3aab3d61e..3e24acc46 100644
--- a/misc/mailman.cfg.sample
+++ b/Mailman/data/mailman.cfg.in
@@ -19,15 +19,27 @@
"""This module contains your site-specific settings.
-Use this to override the default settings in Mailman/Defaults.py. You only
+Use this to override the default settings in `Mailman/Defaults.py`. You only
need to include those settings that you want to change, and unlike the old
-mm_cfg.py file, you do /not/ need to import Defaults. Its variables will
+`mm_cfg.py` file, you do /not/ need to `import Defaults`. Its variables will
automatically be available in this module's namespace.
-You should consult Defaults.py though for a complete listing of configuration
-variables that you can change.
+You should consult `Defaults.py` though for a complete listing of
+configuration variables that you can change.
-To use this, copy this file to $VAR_PREFIX/etc/mailman.cfg
-
-Mailman's installation procedure will never overwrite mailman.cfg.
+Mailman's installation procedure will never overwrite `mailman.cfg`.
"""
+
+# This is the top-level run-time data directory. All other runtime data by
+# default lives under this directory.
+VAR_DIR = '$var_dir'
+
+# User name and id that owns the Mailman process and files.
+MAILMAN_UID = '$user_id'
+MAILMAN_USER = '$user_name'
+
+# Group name and id that owns the Mailman process and files.
+MAILMAN_GID = '$group_id'
+MAILMAN_GROUP = '$group_name'
+
+LANGUAGES = '$languages'
diff --git a/misc/mailman.in b/Mailman/data/mailman.in
index 4fb0612f3..4fb0612f3 100644
--- a/misc/mailman.in
+++ b/Mailman/data/mailman.in
diff --git a/misc/mailman.jpg b/Mailman/data/mailman.jpg
index 94a4c0112..94a4c0112 100644
--- a/misc/mailman.jpg
+++ b/Mailman/data/mailman.jpg
Binary files differ
diff --git a/misc/mm-icon.png b/Mailman/data/mm-icon.png
index 42c3cf759..42c3cf759 100644
--- a/misc/mm-icon.png
+++ b/Mailman/data/mm-icon.png
Binary files differ
diff --git a/misc/munepy-1.1-py2.5.egg b/Mailman/data/munepy-1.1-py2.5.egg
index 00ed8ccfe..00ed8ccfe 100644
--- a/misc/munepy-1.1-py2.5.egg
+++ b/Mailman/data/munepy-1.1-py2.5.egg
Binary files differ
diff --git a/misc/paths.py.in b/Mailman/data/paths.py.in
index a840e3f14..a840e3f14 100644
--- a/misc/paths.py.in
+++ b/Mailman/data/paths.py.in
diff --git a/misc/pysqlite-2.3.2.tar.gz b/Mailman/data/pysqlite-2.3.2.tar.gz
index 52f5711e9..52f5711e9 100644
--- a/misc/pysqlite-2.3.2.tar.gz
+++ b/Mailman/data/pysqlite-2.3.2.tar.gz
Binary files differ
diff --git a/misc/setuptools-0.6c3.tar.gz b/Mailman/data/setuptools-0.6c3.tar.gz
index 30a4a464a..30a4a464a 100644
--- a/misc/setuptools-0.6c3.tar.gz
+++ b/Mailman/data/setuptools-0.6c3.tar.gz
Binary files differ
diff --git a/misc/wsgiref-0.1.2-py2.4.egg b/Mailman/data/wsgiref-0.1.2-py2.4.egg
index b38cb8321..b38cb8321 100644
--- a/misc/wsgiref-0.1.2-py2.4.egg
+++ b/Mailman/data/wsgiref-0.1.2-py2.4.egg
Binary files differ
diff --git a/misc/zope.interface-3.3.0.1.tar.gz b/Mailman/data/zope.interface-3.3.0.1.tar.gz
index c95bf0698..c95bf0698 100644
--- a/misc/zope.interface-3.3.0.1.tar.gz
+++ b/Mailman/data/zope.interface-3.3.0.1.tar.gz
Binary files differ
diff --git a/Mailman/docs/acknowledge.txt b/Mailman/docs/acknowledge.txt
index 82fdd3fd3..e22bf3d57 100644
--- a/Mailman/docs/acknowledge.txt
+++ b/Mailman/docs/acknowledge.txt
@@ -12,6 +12,7 @@ acknowledgment.
>>> from Mailman.database import flush
>>> mlist = config.list_manager.create('_xtest@example.com')
>>> mlist.real_name = 'XTest'
+ >>> mlist.preferred_language = 'en'
>>> # XXX This will almost certainly change once we've worked out the web
>>> # space layout for mailing lists now.
>>> mlist._data.web_page_url = 'http://lists.example.com/'
diff --git a/Mailman/docs/digests.txt b/Mailman/docs/digests.txt
index 3788651f9..8f2a60ebc 100644
--- a/Mailman/docs/digests.txt
+++ b/Mailman/docs/digests.txt
@@ -418,9 +418,16 @@ Internationalized digests
-------------------------
When messages come in with a content-type character set different than that of
-the list's preferred language, recipients wil get an internationalized digest.
+the list's preferred language, recipients wil get an internationalized
+digest. French is not enabled by default site-wide, so enable that now.
+XXX We also have to set the default server language to French, otherwise the
+English template will be found and the masthead won't be translated.
+
+ >>> config.languages.enable_language('fr')
+ >>> config.DEFAULT_SERVER_LANGUAGE = 'fr'
>>> mlist.preferred_language = 'fr'
+ >>> flush()
>>> msg = message_from_string("""\
... From: aperson@example.org
... To: _xtest@example.com
@@ -537,3 +544,9 @@ Set the digest threshold to zero so that the digests will be sent immediately.
('listname', '_xtest@example.com'),
('received_time', ...),
('recips', set([])), ('version', 3)]
+
+
+Clean up
+--------
+
+ >>> config.DEFAULT_SERVER_LANGUAGE = 'en'
diff --git a/Mailman/docs/languages.txt b/Mailman/docs/languages.txt
new file mode 100644
index 000000000..2c1664da3
--- /dev/null
+++ b/Mailman/docs/languages.txt
@@ -0,0 +1,94 @@
+Languages
+=========
+
+Mailman is multilingual. A language manager handles the known set of
+languages at run time, as well as enabling those languages for use in a
+running Mailman instance.
+
+ >>> from zope.interface.verify import verifyObject
+ >>> from Mailman.interfaces import ILanguageManager
+ >>> from Mailman.languages import LanguageManager
+ >>> mgr = LanguageManager()
+ >>> verifyObject(ILanguageManager, mgr)
+ True
+
+A language manager keeps track of the languages it knows about as well as the
+languages which are enabled. By default, none are known or enabled.
+
+ >>> sorted(mgr.known_codes)
+ []
+ >>> sorted(mgr.enabled_codes)
+ []
+
+The language manager also keeps track of information for each known language,
+but you obviously can't get information for an unknown language.
+
+ >>> mgr.get_language_data('en')
+ Traceback (most recent call last):
+ ...
+ KeyError: 'en'
+
+
+Adding languages
+----------------
+
+Adding a new language requires three pieces of information, the 2-character
+language code, the English description of the language, and the character set
+used by the language.
+
+ >>> mgr.add_language('en', 'English', 'us-ascii')
+ >>> mgr.add_language('it', 'Italian', 'iso-8859-1')
+
+By default, added languages are also enabled.
+
+ >>> sorted(mgr.known_codes)
+ ['en', 'it']
+ >>> sorted(mgr.enabled_codes)
+ ['en', 'it']
+
+And you can get information for all known languages.
+
+ >>> mgr.get_language_data('en')
+ ('English', 'us-ascii')
+ >>> mgr.get_language_data('it')
+ ('Italian', 'iso-8859-1')
+
+You can also add a language without enabling it.
+
+ >>> mgr.add_language('pl', 'Polish', 'iso-8859-2', enable=False)
+ >>> sorted(mgr.known_codes)
+ ['en', 'it', 'pl']
+ >>> sorted(mgr.enabled_codes)
+ ['en', 'it']
+
+You can get language data for disabled languages.
+
+ >>> mgr.get_language_data('pl')
+ ('Polish', 'iso-8859-2')
+
+And of course you can enable a known language.
+
+ >>> mgr.enable_language('pl')
+ >>> sorted(mgr.enabled_codes)
+ ['en', 'it', 'pl']
+
+But you cannot enable languages that the manager does not know about.
+
+ >>> mgr.enable_language('xx')
+ Traceback (most recent call last):
+ ...
+ KeyError: 'xx'
+
+
+Other iterations
+----------------
+
+You can iterate over the descriptions (names) of all enabled languages.
+
+ >>> sorted(mgr.enabled_names)
+ ['English', 'Italian', 'Polish']
+
+You can ask whether a particular language code is enabled.
+
+ >>> 'it' in mgr.enabled_codes
+ True
diff --git a/Mailman/i18n.py b/Mailman/i18n.py
index 66584e895..120e861ad 100644
--- a/Mailman/i18n.py
+++ b/Mailman/i18n.py
@@ -15,17 +15,23 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.
+import os
import sys
import time
import string
import gettext
+import Mailman.messages
from Mailman.SafeDict import SafeDict
from Mailman.configuration import config
_translation = None
_missing = object()
+MESSAGES_DIR = os.path.dirname(Mailman.messages.__file__)
+
+
+
class Template(string.Template):
idpattern = r'[_a-z][_a-z0-9.]*'
@@ -47,8 +53,7 @@ def set_language(language=None):
if language is not None:
language = [language]
try:
- _translation = gettext.translation('mailman', config.MESSAGES_DIR,
- language)
+ _translation = gettext.translation('mailman', MESSAGES_DIR, language)
except IOError:
# The selected language was not installed in messages, so fall back to
# untranslated English.
diff --git a/Mailman/interfaces/languages.py b/Mailman/interfaces/languages.py
new file mode 100644
index 000000000..44a284a5b
--- /dev/null
+++ b/Mailman/interfaces/languages.py
@@ -0,0 +1,65 @@
+# Copyright (C) 2007 by the Free Software Foundation, Inc.
+#
+# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+# USA.
+
+"""Interfaces for managing languages."""
+
+from zope.interface import Interface, Attribute
+
+
+
+class ILanguageManager(Interface):
+ """A language manager.
+
+ Current, disabling languages is not supported.
+ """
+
+ def add_language(code, description, charset, enable=True):
+ """Teach the language manager about a language.
+
+ :param code: The short two-character language code for the
+ language. If the language manager already knows about this code,
+ the old language binding is lost.
+ :param description: The English description of the language,
+ e.g. 'English' or 'French'.
+ :param charset: The character set that the language uses,
+ e.g. 'us-ascii', 'iso-8859-1', or 'utf-8'
+ :param enable: Enable the language at the same time.
+ """
+
+ def enable_language(code):
+ """Enable a language that the manager already knows about.
+
+ :raises KeyError: when the manager does not know about the given
+ language code.
+ """
+
+ def get_language_data(code):
+ """Return the description and charset for the given `code`.
+
+ :param code: The code to lookup.
+ :returns: A 2-tuple of the description and charset for the code.
+ :raises KeyError: when the code is unknown.
+ """
+
+ known_codes = Attribute(
+ """An iterator over all known codes.""")
+
+ enabled_codes = Attribute(
+ """An iterator over all enabled codes.""")
+
+ enabled_names = Attribute(
+ """An iterator over all enabled language names.""")
diff --git a/Mailman/interfaces/manager.py b/Mailman/interfaces/manager.py
deleted file mode 100644
index fe22ec74d..000000000
--- a/Mailman/interfaces/manager.py
+++ /dev/null
@@ -1,57 +0,0 @@
-# Copyright (C) 2007 by the Free Software Foundation, Inc.
-#
-# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
-# USA.
-
-"""Generic database object manager interface."""
-
-from zope.interface import Interface, Attribute
-
-
-
-class IManaged(Interface):
- """An object managed by an IManager."""
-
- name = Attribute("""The name of the managed object.""")
-
-
-
-class IManager(Interface):
- """Create and manage profiles."""
-
- def create(name):
- """Create and return a new IManaged object.
-
- name is the unique name for this object. Raises
- ExistingManagedObjectError if an IManaged object with the given name
- already exists.
- """
-
- def get(name):
- """Return the named IManaged object.
-
- Raises NoSuchManagedObjectError if the named IManaged object does not
- exist.
- """
-
- def delete(name):
- """Delete the named IManaged object.
-
- Raises NoSuchManagedObjectError if the named IManaged object does not
- exist.
- """
-
- iterator = Attribute(
- """Return an iterator over the all the IManaged objects.""")
diff --git a/Mailman/languages.py b/Mailman/languages.py
new file mode 100644
index 000000000..a6a457a20
--- /dev/null
+++ b/Mailman/languages.py
@@ -0,0 +1,57 @@
+# Copyright (C) 2007 by the Free Software Foundation, Inc.
+#
+# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+# USA.
+
+"""Language manager."""
+
+from zope.interface import implements
+from Mailman.interfaces import ILanguageManager
+
+
+
+class LanguageManager:
+ implements(ILanguageManager)
+
+ def __init__(self):
+ self._language_data = {}
+ self._enabled = set()
+
+ def add_language(self, code, description, charset, enable=True):
+ self._language_data[code] = (description, charset)
+ if enable:
+ self._enabled.add(code)
+
+ def enable_language(self, code):
+ # As per the interface, let KeyError percolate up.
+ self._language_data[code]
+ self._enabled.add(code)
+
+ def get_language_data(self, code):
+ return self._language_data[code]
+
+ @property
+ def known_codes(self):
+ return iter(self._language_data)
+
+ @property
+ def enabled_codes(self):
+ return iter(self._enabled)
+
+ @property
+ def enabled_names(self):
+ for code in self._enabled:
+ description, charset = self._language_data[code]
+ yield description
diff --git a/Mailman/messages/__init__.py b/Mailman/messages/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Mailman/messages/__init__.py
diff --git a/messages/ar/LC_MESSAGES/mailman.po b/Mailman/messages/ar/LC_MESSAGES/mailman.po
index 076a13434..076a13434 100644
--- a/messages/ar/LC_MESSAGES/mailman.po
+++ b/Mailman/messages/ar/LC_MESSAGES/mailman.po
diff --git a/messages/ca/LC_MESSAGES/mailman.po b/Mailman/messages/ca/LC_MESSAGES/mailman.po
index 3ec74f0fe..3ec74f0fe 100644
--- a/messages/ca/LC_MESSAGES/mailman.po
+++ b/Mailman/messages/ca/LC_MESSAGES/mailman.po
diff --git a/messages/cs/LC_MESSAGES/mailman.po b/Mailman/messages/cs/LC_MESSAGES/mailman.po
index 0b9fe96be..0b9fe96be 100644
--- a/messages/cs/LC_MESSAGES/mailman.po
+++ b/Mailman/messages/cs/LC_MESSAGES/mailman.po
diff --git a/messages/da/LC_MESSAGES/mailman.po b/Mailman/messages/da/LC_MESSAGES/mailman.po
index c4afab6f2..c4afab6f2 100644
--- a/messages/da/LC_MESSAGES/mailman.po
+++ b/Mailman/messages/da/LC_MESSAGES/mailman.po
diff --git a/messages/de/LC_MESSAGES/mailman.po b/Mailman/messages/de/LC_MESSAGES/mailman.po
index 9403a4f92..9403a4f92 100644
--- a/messages/de/LC_MESSAGES/mailman.po
+++ b/Mailman/messages/de/LC_MESSAGES/mailman.po
diff --git a/messages/de/README.de b/Mailman/messages/de/README.de
index 4ca818d31..4ca818d31 100644
--- a/messages/de/README.de
+++ b/Mailman/messages/de/README.de
diff --git a/messages/docstring.files b/Mailman/messages/docstring.files
index c65b0e949..c65b0e949 100644
--- a/messages/docstring.files
+++ b/Mailman/messages/docstring.files
diff --git a/messages/es/LC_MESSAGES/mailman.po b/Mailman/messages/es/LC_MESSAGES/mailman.po
index 7a2224010..7a2224010 100644
--- a/messages/es/LC_MESSAGES/mailman.po
+++ b/Mailman/messages/es/LC_MESSAGES/mailman.po
diff --git a/messages/es/README.es b/Mailman/messages/es/README.es
index 066e7d7dd..066e7d7dd 100644
--- a/messages/es/README.es
+++ b/Mailman/messages/es/README.es
diff --git a/messages/et/LC_MESSAGES/mailman.po b/Mailman/messages/et/LC_MESSAGES/mailman.po
index 2e404618f..2e404618f 100644
--- a/messages/et/LC_MESSAGES/mailman.po
+++ b/Mailman/messages/et/LC_MESSAGES/mailman.po
diff --git a/messages/eu/LC_MESSAGES/mailman.po b/Mailman/messages/eu/LC_MESSAGES/mailman.po
index 979221811..979221811 100644
--- a/messages/eu/LC_MESSAGES/mailman.po
+++ b/Mailman/messages/eu/LC_MESSAGES/mailman.po
diff --git a/messages/eu/README.eu b/Mailman/messages/eu/README.eu
index 8176d5288..8176d5288 100644
--- a/messages/eu/README.eu
+++ b/Mailman/messages/eu/README.eu
diff --git a/messages/fi/LC_MESSAGES/mailman.po b/Mailman/messages/fi/LC_MESSAGES/mailman.po
index eac01f0ca..eac01f0ca 100644
--- a/messages/fi/LC_MESSAGES/mailman.po
+++ b/Mailman/messages/fi/LC_MESSAGES/mailman.po
diff --git a/messages/fi/README.fi b/Mailman/messages/fi/README.fi
index 796275f0a..796275f0a 100644
--- a/messages/fi/README.fi
+++ b/Mailman/messages/fi/README.fi
diff --git a/messages/fr/LC_MESSAGES/mailman.po b/Mailman/messages/fr/LC_MESSAGES/mailman.po
index d6546b6dc..6bccf8d9c 100644
--- a/messages/fr/LC_MESSAGES/mailman.po
+++ b/Mailman/messages/fr/LC_MESSAGES/mailman.po
@@ -7958,8 +7958,8 @@ msgid "Message rejected by filter rule match"
msgstr "Message rejeté par correspondance avec une règle de filtrage"
#: Mailman/Handlers/ToDigest.py:159
-msgid "%(realname)s Digest, Vol %(volume)d, Issue %(issue)d"
-msgstr "Groupe %(realname)s, Vol. %(volume)d, Parution %(issue)d"
+msgid "$realname Digest, Vol $volume, Issue $issue"
+msgstr "Groupe $realname, Vol. $volume, Parution $issue"
#: Mailman/Handlers/ToDigest.py:205
msgid "digest header"
diff --git a/messages/fr/README.fr b/Mailman/messages/fr/README.fr
index 0ae05b224..0ae05b224 100644
--- a/messages/fr/README.fr
+++ b/Mailman/messages/fr/README.fr
diff --git a/messages/hr/LC_MESSAGES/mailman.po b/Mailman/messages/hr/LC_MESSAGES/mailman.po
index 243997947..243997947 100644
--- a/messages/hr/LC_MESSAGES/mailman.po
+++ b/Mailman/messages/hr/LC_MESSAGES/mailman.po
diff --git a/messages/hu/FAQ.hu b/Mailman/messages/hu/FAQ.hu
index 7430f1d22..7430f1d22 100644
--- a/messages/hu/FAQ.hu
+++ b/Mailman/messages/hu/FAQ.hu
diff --git a/messages/hu/INSTALL.hu b/Mailman/messages/hu/INSTALL.hu
index 0fc4aaf76..0fc4aaf76 100644
--- a/messages/hu/INSTALL.hu
+++ b/Mailman/messages/hu/INSTALL.hu
diff --git a/messages/hu/LC_MESSAGES/mailman.po b/Mailman/messages/hu/LC_MESSAGES/mailman.po
index 2d568d554..2d568d554 100644
--- a/messages/hu/LC_MESSAGES/mailman.po
+++ b/Mailman/messages/hu/LC_MESSAGES/mailman.po
diff --git a/messages/hu/README.BSD.hu b/Mailman/messages/hu/README.BSD.hu
index 6ff26c6d7..6ff26c6d7 100644
--- a/messages/hu/README.BSD.hu
+++ b/Mailman/messages/hu/README.BSD.hu
diff --git a/messages/hu/README.CONTRIB.hu b/Mailman/messages/hu/README.CONTRIB.hu
index 0b53cdc12..0b53cdc12 100644
--- a/messages/hu/README.CONTRIB.hu
+++ b/Mailman/messages/hu/README.CONTRIB.hu
diff --git a/messages/hu/README.EXIM.hu b/Mailman/messages/hu/README.EXIM.hu
index 107438b17..107438b17 100644
--- a/messages/hu/README.EXIM.hu
+++ b/Mailman/messages/hu/README.EXIM.hu
diff --git a/messages/hu/README.LINUX.hu b/Mailman/messages/hu/README.LINUX.hu
index 9646a6cee..9646a6cee 100644
--- a/messages/hu/README.LINUX.hu
+++ b/Mailman/messages/hu/README.LINUX.hu
diff --git a/messages/hu/README.MACOSX.hu b/Mailman/messages/hu/README.MACOSX.hu
index 3b9420c7c..3b9420c7c 100644
--- a/messages/hu/README.MACOSX.hu
+++ b/Mailman/messages/hu/README.MACOSX.hu
diff --git a/messages/hu/README.NETSCAPE.hu b/Mailman/messages/hu/README.NETSCAPE.hu
index efcda422e..efcda422e 100644
--- a/messages/hu/README.NETSCAPE.hu
+++ b/Mailman/messages/hu/README.NETSCAPE.hu
diff --git a/messages/hu/README.POSTFIX.hu b/Mailman/messages/hu/README.POSTFIX.hu
index f2a36c3f0..f2a36c3f0 100644
--- a/messages/hu/README.POSTFIX.hu
+++ b/Mailman/messages/hu/README.POSTFIX.hu
diff --git a/messages/hu/README.QMAIL.hu b/Mailman/messages/hu/README.QMAIL.hu
index 72ab96e31..72ab96e31 100644
--- a/messages/hu/README.QMAIL.hu
+++ b/Mailman/messages/hu/README.QMAIL.hu
diff --git a/messages/hu/README.SENDMAIL.hu b/Mailman/messages/hu/README.SENDMAIL.hu
index 028550952..028550952 100644
--- a/messages/hu/README.SENDMAIL.hu
+++ b/Mailman/messages/hu/README.SENDMAIL.hu
diff --git a/messages/hu/README.USERAGENT.hu b/Mailman/messages/hu/README.USERAGENT.hu
index d92dd1233..d92dd1233 100644
--- a/messages/hu/README.USERAGENT.hu
+++ b/Mailman/messages/hu/README.USERAGENT.hu
diff --git a/messages/hu/README.hu b/Mailman/messages/hu/README.hu
index 4638b78ea..4638b78ea 100644
--- a/messages/hu/README.hu
+++ b/Mailman/messages/hu/README.hu
diff --git a/messages/hu/UPGRADING.hu b/Mailman/messages/hu/UPGRADING.hu
index 1a070a27f..1a070a27f 100644
--- a/messages/hu/UPGRADING.hu
+++ b/Mailman/messages/hu/UPGRADING.hu
diff --git a/messages/ia/LC_MESSAGES/mailman.po b/Mailman/messages/ia/LC_MESSAGES/mailman.po
index 2cf4db675..2cf4db675 100644
--- a/messages/ia/LC_MESSAGES/mailman.po
+++ b/Mailman/messages/ia/LC_MESSAGES/mailman.po
diff --git a/messages/it/LC_MESSAGES/mailman.po b/Mailman/messages/it/LC_MESSAGES/mailman.po
index 598968457..598968457 100644
--- a/messages/it/LC_MESSAGES/mailman.po
+++ b/Mailman/messages/it/LC_MESSAGES/mailman.po
diff --git a/messages/it/README.it b/Mailman/messages/it/README.it
index 56fcc422d..56fcc422d 100644
--- a/messages/it/README.it
+++ b/Mailman/messages/it/README.it
diff --git a/messages/ja/INSTALL b/Mailman/messages/ja/INSTALL
index f8c4de6b4..f8c4de6b4 100644
--- a/messages/ja/INSTALL
+++ b/Mailman/messages/ja/INSTALL
diff --git a/messages/ja/LC_MESSAGES/mailman.po b/Mailman/messages/ja/LC_MESSAGES/mailman.po
index 611dba470..611dba470 100644
--- a/messages/ja/LC_MESSAGES/mailman.po
+++ b/Mailman/messages/ja/LC_MESSAGES/mailman.po
diff --git a/messages/ja/README b/Mailman/messages/ja/README
index a163742c1..a163742c1 100644
--- a/messages/ja/README
+++ b/Mailman/messages/ja/README
diff --git a/messages/ja/README.ja b/Mailman/messages/ja/README.ja
index a459d9daa..a459d9daa 100644
--- a/messages/ja/README.ja
+++ b/Mailman/messages/ja/README.ja
diff --git a/messages/ja/UPGRADING b/Mailman/messages/ja/UPGRADING
index 3afc8c5fe..3afc8c5fe 100644
--- a/messages/ja/UPGRADING
+++ b/Mailman/messages/ja/UPGRADING
diff --git a/messages/ja/doc/Defaults.py.in b/Mailman/messages/ja/doc/Defaults.py.in
index cfbcc9ed8..cfbcc9ed8 100644
--- a/messages/ja/doc/Defaults.py.in
+++ b/Mailman/messages/ja/doc/Defaults.py.in
diff --git a/messages/ja/doc/mailman-install.tex b/Mailman/messages/ja/doc/mailman-install.tex
index aa4297400..aa4297400 100644
--- a/messages/ja/doc/mailman-install.tex
+++ b/Mailman/messages/ja/doc/mailman-install.tex
diff --git a/messages/ja/doc/mailman-member.tex b/Mailman/messages/ja/doc/mailman-member.tex
index 8fe6e3543..8fe6e3543 100644
--- a/messages/ja/doc/mailman-member.tex
+++ b/Mailman/messages/ja/doc/mailman-member.tex
diff --git a/messages/ko/LC_MESSAGES/mailman.po b/Mailman/messages/ko/LC_MESSAGES/mailman.po
index 1654f4f2a..1654f4f2a 100644
--- a/messages/ko/LC_MESSAGES/mailman.po
+++ b/Mailman/messages/ko/LC_MESSAGES/mailman.po
diff --git a/messages/ko/README.ko b/Mailman/messages/ko/README.ko
index 268a96d01..268a96d01 100644
--- a/messages/ko/README.ko
+++ b/Mailman/messages/ko/README.ko
diff --git a/messages/lt/LC_MESSAGES/mailman.po b/Mailman/messages/lt/LC_MESSAGES/mailman.po
index 1e87b6eea..1e87b6eea 100644
--- a/messages/lt/LC_MESSAGES/mailman.po
+++ b/Mailman/messages/lt/LC_MESSAGES/mailman.po
diff --git a/messages/mailman.pot b/Mailman/messages/mailman.pot
index ae04e58f2..ae04e58f2 100644
--- a/messages/mailman.pot
+++ b/Mailman/messages/mailman.pot
diff --git a/messages/marked.files b/Mailman/messages/marked.files
index 375fb35a5..375fb35a5 100644
--- a/messages/marked.files
+++ b/Mailman/messages/marked.files
diff --git a/messages/nl/LC_MESSAGES/mailman.po b/Mailman/messages/nl/LC_MESSAGES/mailman.po
index 290808f90..290808f90 100644
--- a/messages/nl/LC_MESSAGES/mailman.po
+++ b/Mailman/messages/nl/LC_MESSAGES/mailman.po
diff --git a/messages/no/LC_MESSAGES/mailman.po b/Mailman/messages/no/LC_MESSAGES/mailman.po
index 5e4c53696..5e4c53696 100644
--- a/messages/no/LC_MESSAGES/mailman.po
+++ b/Mailman/messages/no/LC_MESSAGES/mailman.po
diff --git a/messages/pl/LC_MESSAGES/mailman.po b/Mailman/messages/pl/LC_MESSAGES/mailman.po
index de6273bd2..de6273bd2 100644
--- a/messages/pl/LC_MESSAGES/mailman.po
+++ b/Mailman/messages/pl/LC_MESSAGES/mailman.po
diff --git a/messages/pl/README.pl b/Mailman/messages/pl/README.pl
index 47f40998b..47f40998b 100644
--- a/messages/pl/README.pl
+++ b/Mailman/messages/pl/README.pl
diff --git a/messages/pt/LC_MESSAGES/mailman.po b/Mailman/messages/pt/LC_MESSAGES/mailman.po
index 1976c787f..1976c787f 100644
--- a/messages/pt/LC_MESSAGES/mailman.po
+++ b/Mailman/messages/pt/LC_MESSAGES/mailman.po
diff --git a/messages/pt_BR/LC_MESSAGES/mailman.po b/Mailman/messages/pt_BR/LC_MESSAGES/mailman.po
index 47c983be8..47c983be8 100644
--- a/messages/pt_BR/LC_MESSAGES/mailman.po
+++ b/Mailman/messages/pt_BR/LC_MESSAGES/mailman.po
diff --git a/messages/ro/LC_MESSAGES/mailman.po b/Mailman/messages/ro/LC_MESSAGES/mailman.po
index 05a80aca7..05a80aca7 100644
--- a/messages/ro/LC_MESSAGES/mailman.po
+++ b/Mailman/messages/ro/LC_MESSAGES/mailman.po
diff --git a/messages/ru/LC_MESSAGES/mailman.po b/Mailman/messages/ru/LC_MESSAGES/mailman.po
index 6a02aca15..6a02aca15 100644
--- a/messages/ru/LC_MESSAGES/mailman.po
+++ b/Mailman/messages/ru/LC_MESSAGES/mailman.po
diff --git a/messages/ru/README.ru b/Mailman/messages/ru/README.ru
index 027dbe878..027dbe878 100644
--- a/messages/ru/README.ru
+++ b/Mailman/messages/ru/README.ru
diff --git a/messages/sl/LC_MESSAGES/mailman.po b/Mailman/messages/sl/LC_MESSAGES/mailman.po
index ca1ed16d2..ca1ed16d2 100644
--- a/messages/sl/LC_MESSAGES/mailman.po
+++ b/Mailman/messages/sl/LC_MESSAGES/mailman.po
diff --git a/messages/sr/LC_MESSAGES/mailman.po b/Mailman/messages/sr/LC_MESSAGES/mailman.po
index 058a4939e..058a4939e 100644
--- a/messages/sr/LC_MESSAGES/mailman.po
+++ b/Mailman/messages/sr/LC_MESSAGES/mailman.po
diff --git a/messages/sr/readme.sr b/Mailman/messages/sr/readme.sr
index df7eef0e9..df7eef0e9 100644
--- a/messages/sr/readme.sr
+++ b/Mailman/messages/sr/readme.sr
diff --git a/messages/sv/LC_MESSAGES/mailman.po b/Mailman/messages/sv/LC_MESSAGES/mailman.po
index 724aefce3..724aefce3 100644
--- a/messages/sv/LC_MESSAGES/mailman.po
+++ b/Mailman/messages/sv/LC_MESSAGES/mailman.po
diff --git a/messages/sv/README.sv b/Mailman/messages/sv/README.sv
index f74eaec5b..f74eaec5b 100644
--- a/messages/sv/README.sv
+++ b/Mailman/messages/sv/README.sv
diff --git a/messages/tr/LC_MESSAGES/mailman.po b/Mailman/messages/tr/LC_MESSAGES/mailman.po
index 273880afe..273880afe 100644
--- a/messages/tr/LC_MESSAGES/mailman.po
+++ b/Mailman/messages/tr/LC_MESSAGES/mailman.po
diff --git a/messages/uk/LC_MESSAGES/mailman.po b/Mailman/messages/uk/LC_MESSAGES/mailman.po
index 296c0eecc..296c0eecc 100644
--- a/messages/uk/LC_MESSAGES/mailman.po
+++ b/Mailman/messages/uk/LC_MESSAGES/mailman.po
diff --git a/messages/vi/LC_MESSAGES/mailman.po b/Mailman/messages/vi/LC_MESSAGES/mailman.po
index 880df992c..880df992c 100644
--- a/messages/vi/LC_MESSAGES/mailman.po
+++ b/Mailman/messages/vi/LC_MESSAGES/mailman.po
diff --git a/messages/zh_CN/LC_MESSAGES/mailman.po b/Mailman/messages/zh_CN/LC_MESSAGES/mailman.po
index c5b2382d6..c5b2382d6 100644
--- a/messages/zh_CN/LC_MESSAGES/mailman.po
+++ b/Mailman/messages/zh_CN/LC_MESSAGES/mailman.po
diff --git a/messages/zh_TW/LC_MESSAGES/mailman.po b/Mailman/messages/zh_TW/LC_MESSAGES/mailman.po
index 6c82e3794..6c82e3794 100644
--- a/messages/zh_TW/LC_MESSAGES/mailman.po
+++ b/Mailman/messages/zh_TW/LC_MESSAGES/mailman.po
diff --git a/Mailman/templates/__init__.py b/Mailman/templates/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Mailman/templates/__init__.py
diff --git a/templates/en/adminaddrchgack.txt b/Mailman/templates/en/adminaddrchgack.txt
index a24dd3d91..a24dd3d91 100644
--- a/templates/en/adminaddrchgack.txt
+++ b/Mailman/templates/en/adminaddrchgack.txt
diff --git a/templates/en/admindbdetails.html b/Mailman/templates/en/admindbdetails.html
index d97fcec11..d97fcec11 100644
--- a/templates/en/admindbdetails.html
+++ b/Mailman/templates/en/admindbdetails.html
diff --git a/templates/en/admindbpreamble.html b/Mailman/templates/en/admindbpreamble.html
index 659b77e72..659b77e72 100644
--- a/templates/en/admindbpreamble.html
+++ b/Mailman/templates/en/admindbpreamble.html
diff --git a/templates/en/admindbsummary.html b/Mailman/templates/en/admindbsummary.html
index 20ffef584..20ffef584 100644
--- a/templates/en/admindbsummary.html
+++ b/Mailman/templates/en/admindbsummary.html
diff --git a/templates/en/adminsubscribeack.txt b/Mailman/templates/en/adminsubscribeack.txt
index 388a3a240..388a3a240 100644
--- a/templates/en/adminsubscribeack.txt
+++ b/Mailman/templates/en/adminsubscribeack.txt
diff --git a/templates/en/adminunsubscribeack.txt b/Mailman/templates/en/adminunsubscribeack.txt
index 2ebcfeb70..2ebcfeb70 100644
--- a/templates/en/adminunsubscribeack.txt
+++ b/Mailman/templates/en/adminunsubscribeack.txt
diff --git a/templates/en/admlogin.html b/Mailman/templates/en/admlogin.html
index 03f763b95..03f763b95 100644
--- a/templates/en/admlogin.html
+++ b/Mailman/templates/en/admlogin.html
diff --git a/templates/en/approve.txt b/Mailman/templates/en/approve.txt
index dfb0dfb1e..dfb0dfb1e 100644
--- a/templates/en/approve.txt
+++ b/Mailman/templates/en/approve.txt
diff --git a/templates/en/archidxentry.html b/Mailman/templates/en/archidxentry.html
index f9bb57aab..f9bb57aab 100644
--- a/templates/en/archidxentry.html
+++ b/Mailman/templates/en/archidxentry.html
diff --git a/templates/en/archidxfoot.html b/Mailman/templates/en/archidxfoot.html
index 0b0a42075..0b0a42075 100644
--- a/templates/en/archidxfoot.html
+++ b/Mailman/templates/en/archidxfoot.html
diff --git a/templates/en/archidxhead.html b/Mailman/templates/en/archidxhead.html
index 4fdf4731d..4fdf4731d 100644
--- a/templates/en/archidxhead.html
+++ b/Mailman/templates/en/archidxhead.html
diff --git a/templates/en/archlistend.html b/Mailman/templates/en/archlistend.html
index 9bc052ddb..9bc052ddb 100644
--- a/templates/en/archlistend.html
+++ b/Mailman/templates/en/archlistend.html
diff --git a/templates/en/archliststart.html b/Mailman/templates/en/archliststart.html
index cdf5d17c4..cdf5d17c4 100644
--- a/templates/en/archliststart.html
+++ b/Mailman/templates/en/archliststart.html
diff --git a/templates/en/archtoc.html b/Mailman/templates/en/archtoc.html
index 6969d5152..6969d5152 100644
--- a/templates/en/archtoc.html
+++ b/Mailman/templates/en/archtoc.html
diff --git a/templates/en/archtocentry.html b/Mailman/templates/en/archtocentry.html
index 00cf9c47d..00cf9c47d 100644
--- a/templates/en/archtocentry.html
+++ b/Mailman/templates/en/archtocentry.html
diff --git a/templates/en/archtocnombox.html b/Mailman/templates/en/archtocnombox.html
index 0b1239ec8..0b1239ec8 100644
--- a/templates/en/archtocnombox.html
+++ b/Mailman/templates/en/archtocnombox.html
diff --git a/templates/en/article.html b/Mailman/templates/en/article.html
index 38dbc5543..38dbc5543 100644
--- a/templates/en/article.html
+++ b/Mailman/templates/en/article.html
diff --git a/templates/en/bounce.txt b/Mailman/templates/en/bounce.txt
index 8e02cc7a5..8e02cc7a5 100644
--- a/templates/en/bounce.txt
+++ b/Mailman/templates/en/bounce.txt
diff --git a/templates/en/checkdbs.txt b/Mailman/templates/en/checkdbs.txt
index d53925a4d..d53925a4d 100644
--- a/templates/en/checkdbs.txt
+++ b/Mailman/templates/en/checkdbs.txt
diff --git a/templates/en/convert.txt b/Mailman/templates/en/convert.txt
index ae17a79e0..ae17a79e0 100644
--- a/templates/en/convert.txt
+++ b/Mailman/templates/en/convert.txt
diff --git a/templates/en/cronpass.txt b/Mailman/templates/en/cronpass.txt
index 52ce5ea6c..52ce5ea6c 100644
--- a/templates/en/cronpass.txt
+++ b/Mailman/templates/en/cronpass.txt
diff --git a/templates/en/disabled.txt b/Mailman/templates/en/disabled.txt
index 54998a83b..54998a83b 100644
--- a/templates/en/disabled.txt
+++ b/Mailman/templates/en/disabled.txt
diff --git a/templates/en/emptyarchive.html b/Mailman/templates/en/emptyarchive.html
index 2f10766ce..2f10766ce 100644
--- a/templates/en/emptyarchive.html
+++ b/Mailman/templates/en/emptyarchive.html
diff --git a/templates/en/headfoot.html b/Mailman/templates/en/headfoot.html
index b2caf10f6..b2caf10f6 100644
--- a/templates/en/headfoot.html
+++ b/Mailman/templates/en/headfoot.html
diff --git a/templates/en/help.txt b/Mailman/templates/en/help.txt
index 654eda315..654eda315 100644
--- a/templates/en/help.txt
+++ b/Mailman/templates/en/help.txt
diff --git a/templates/en/invite.txt b/Mailman/templates/en/invite.txt
index 920c84213..920c84213 100644
--- a/templates/en/invite.txt
+++ b/Mailman/templates/en/invite.txt
diff --git a/templates/en/listinfo.html b/Mailman/templates/en/listinfo.html
index 0f0b5e614..0f0b5e614 100644
--- a/templates/en/listinfo.html
+++ b/Mailman/templates/en/listinfo.html
diff --git a/templates/en/masthead.txt b/Mailman/templates/en/masthead.txt
index 30c526ac9..30c526ac9 100644
--- a/templates/en/masthead.txt
+++ b/Mailman/templates/en/masthead.txt
diff --git a/templates/en/newlist.txt b/Mailman/templates/en/newlist.txt
index 3362887d8..3362887d8 100644
--- a/templates/en/newlist.txt
+++ b/Mailman/templates/en/newlist.txt
diff --git a/templates/en/nomoretoday.txt b/Mailman/templates/en/nomoretoday.txt
index 1019dce34..1019dce34 100644
--- a/templates/en/nomoretoday.txt
+++ b/Mailman/templates/en/nomoretoday.txt
diff --git a/templates/en/options.html b/Mailman/templates/en/options.html
index 8213b1f4b..8213b1f4b 100644
--- a/templates/en/options.html
+++ b/Mailman/templates/en/options.html
diff --git a/templates/en/postack.txt b/Mailman/templates/en/postack.txt
index 7402e4c2a..7402e4c2a 100644
--- a/templates/en/postack.txt
+++ b/Mailman/templates/en/postack.txt
diff --git a/templates/en/postauth.txt b/Mailman/templates/en/postauth.txt
index a10727716..a10727716 100644
--- a/templates/en/postauth.txt
+++ b/Mailman/templates/en/postauth.txt
diff --git a/templates/en/postheld.txt b/Mailman/templates/en/postheld.txt
index 877bb4050..877bb4050 100644
--- a/templates/en/postheld.txt
+++ b/Mailman/templates/en/postheld.txt
diff --git a/templates/en/private.html b/Mailman/templates/en/private.html
index 28ac9bfc8..28ac9bfc8 100644
--- a/templates/en/private.html
+++ b/Mailman/templates/en/private.html
diff --git a/templates/en/probe.txt b/Mailman/templates/en/probe.txt
index e0ae4ff57..e0ae4ff57 100644
--- a/templates/en/probe.txt
+++ b/Mailman/templates/en/probe.txt
diff --git a/templates/en/refuse.txt b/Mailman/templates/en/refuse.txt
index 9b6d9bb9c..9b6d9bb9c 100644
--- a/templates/en/refuse.txt
+++ b/Mailman/templates/en/refuse.txt
diff --git a/templates/en/roster.html b/Mailman/templates/en/roster.html
index aa5392ae4..aa5392ae4 100644
--- a/templates/en/roster.html
+++ b/Mailman/templates/en/roster.html
diff --git a/templates/en/subauth.txt b/Mailman/templates/en/subauth.txt
index 9c20c3dac..9c20c3dac 100644
--- a/templates/en/subauth.txt
+++ b/Mailman/templates/en/subauth.txt
diff --git a/templates/en/subscribe.html b/Mailman/templates/en/subscribe.html
index 20373877b..20373877b 100644
--- a/templates/en/subscribe.html
+++ b/Mailman/templates/en/subscribe.html
diff --git a/templates/en/subscribeack.txt b/Mailman/templates/en/subscribeack.txt
index fad433f28..fad433f28 100644
--- a/templates/en/subscribeack.txt
+++ b/Mailman/templates/en/subscribeack.txt
diff --git a/templates/en/unsub.txt b/Mailman/templates/en/unsub.txt
index b08f65bae..b08f65bae 100644
--- a/templates/en/unsub.txt
+++ b/Mailman/templates/en/unsub.txt
diff --git a/templates/en/unsubauth.txt b/Mailman/templates/en/unsubauth.txt
index 920f6c1b6..920f6c1b6 100644
--- a/templates/en/unsubauth.txt
+++ b/Mailman/templates/en/unsubauth.txt
diff --git a/templates/en/userpass.txt b/Mailman/templates/en/userpass.txt
index 2a53a846e..2a53a846e 100644
--- a/templates/en/userpass.txt
+++ b/Mailman/templates/en/userpass.txt
diff --git a/templates/en/verify.txt b/Mailman/templates/en/verify.txt
index 8e767f072..8e767f072 100644
--- a/templates/en/verify.txt
+++ b/Mailman/templates/en/verify.txt
diff --git a/Mailman/testing/bounces/__init__.py b/Mailman/testing/bounces/__init__.py
new file mode 100755
index 000000000..e69de29bb
--- /dev/null
+++ b/Mailman/testing/bounces/__init__.py
diff --git a/Mailman/testing/test_bounces.py b/Mailman/testing/test_bounces.py
index 54c82ff68..f09c671f4 100644
--- a/Mailman/testing/test_bounces.py
+++ b/Mailman/testing/test_bounces.py
@@ -17,14 +17,18 @@
"""Test the bounce detection modules."""
+from __future__ import with_statement
+
import os
import sys
import email
import unittest
-from paths import prefix
+import Mailman.testing.bounces
from Mailman.Bouncers.BouncerAPI import Stop
+MSGDIR = os.path.dirname(Mailman.testing.bounces.__file__)
+
class BounceTest(unittest.TestCase):
@@ -157,15 +161,13 @@ class BounceTest(unittest.TestCase):
)
def test_bounce(self):
- for modname, file, addrs in self.DATA:
+ for modname, filename, addrs in self.DATA:
module = 'Mailman.Bouncers.' + modname
__import__(module)
- fp = open(os.path.join(prefix, 'Mailman', 'testing', 'bounces',
- file))
- try:
+ # XXX Convert this tousing package resources
+ path = os.path.join(MSGDIR, filename)
+ with open(path) as fp:
msg = email.message_from_file(fp)
- finally:
- fp.close()
foundaddrs = sys.modules[module].process(msg)
# Some modules return None instead of [] for failure
if foundaddrs is None:
@@ -181,12 +183,8 @@ class BounceTest(unittest.TestCase):
def test_SMTP32_failure(self):
from Mailman.Bouncers import SMTP32
# This file has no X-Mailer: header
- fp = open(os.path.join(prefix, 'Mailman', 'testing', 'bounces',
- 'postfix_01.txt'))
- try:
+ with open(os.path.join(MSGDIR, 'postfix_01.txt')) as fp:
msg = email.message_from_file(fp)
- finally:
- fp.close()
self.failIf(msg['x-mailer'] is not None)
self.failIf(SMTP32.process(msg))
diff --git a/Mailman/testing/testing.cfg.in b/Mailman/testing/testing.cfg.in
index 2609ef5cf..074806cb1 100644
--- a/Mailman/testing/testing.cfg.in
+++ b/Mailman/testing/testing.cfg.in
@@ -10,4 +10,4 @@ MTA = None
add_domain('example.com', 'www.example.com')
-# bin/testall will add a SQLALCHEMY_ENGINE_URL below
+# bin/testall will add additional runtime configuration variables here.
diff --git a/setup.py b/setup.py
index cfb83bcdc..975b808a1 100644
--- a/setup.py
+++ b/setup.py
@@ -30,6 +30,22 @@ if sys.hexversion < 0x20500f0:
+# Ensure that all the .mo files are generated from the corresponding .po file.
+# This procedure needs to be made sane, probably when the language packs are
+# properly split out.
+import os
+import Mailman.messages
+start_dir = os.path.dirname(Mailman.messages.__file__)
+for dirpath, dirnames, filenames in os.walk(start_dir):
+ for filename in filenames:
+ po_file = os.path.join(dirpath, filename)
+ basename, ext = os.path.splitext(po_file)
+ mo_file = basename + '.mo'
+ if ext == '.po' and not os.path.exists(mo_file):
+ os.system('bin/msgfmt.py -o %s %s' % (mo_file, po_file))
+
+
+
scripts = ['%(script)s = Mailman.bin.%(script)s:main' % dict(script=script)
for script in (
'make_instance',
@@ -55,6 +71,7 @@ Any other spelling is incorrect.""",
url = 'http://www.list.org',
keywords = 'email',
packages = find_packages(),
+ include_package_data = True,
# Executable scripts
entry_points = {
'console_scripts': scripts,