Code

Ticket #5522: django-admin.5.diff

File django-admin.5.diff, 38.7 KB (added by jezdez, 6 years ago)

As with Jacob discussed this patch moves the i18n helper functions to their appropriate subcommands and also includes [7473].

Line 
1Index: django/core/management/commands/makemessages.py
2===================================================================
3--- django/core/management/commands/makemessages.py     (Revision 0)
4+++ django/core/management/commands/makemessages.py     (Revision 0)
5@@ -0,0 +1,168 @@
6+import re
7+import os
8+import sys
9+from itertools import dropwhile
10+from optparse import make_option
11+from django.core.management.base import CommandError, BaseCommand
12+
13+pythonize_re = re.compile(r'\n\s*//')
14+
15+def make_messages(locale=None, domain='django', verbosity='1', all=False):
16+    """
17+    Uses the locale directory from the Django SVN tree or an application/
18+    project to process all
19+    """
20+    # Need to ensure that the i18n framework is enabled
21+    from django.conf import settings
22+    settings.configure(USE_I18N = True)
23+   
24+    from django.utils.translation import templatize
25+
26+    if os.path.isdir(os.path.join('conf', 'locale')):
27+        localedir = os.path.abspath(os.path.join('conf', 'locale'))
28+    elif os.path.isdir('locale'):
29+        localedir = os.path.abspath('locale')
30+    else:
31+        raise CommandError("This script should be run from the Django SVN tree or your project or app tree. If you did indeed run it from the SVN checkout or your project or application, maybe you are just missing the conf/locale (in the django tree) or locale (for project and application) directory? It is not created automatically, you have to create it by hand if you want to enable i18n for your project or application.")
32+   
33+    if domain not in ('django', 'djangojs'):
34+        raise CommandError("currently makemessages only supports domains 'django' and 'djangojs'")
35+
36+    if (locale is None and not all) or domain is None:
37+        # backwards compatible error message
38+        if not sys.argv[0].endswith("make-messages.py"):
39+            message = "Type '%s help %s' for usage.\n" % (os.path.basename(sys.argv[0]), sys.argv[1])
40+        else:
41+            message = "usage: make-messages.py -l <language>\n   or: make-messages.py -a\n"
42+        sys.stderr.write(message)
43+        sys.exit(1)
44+
45+    languages = []
46+    if locale is not None:
47+        languages.append(locale)
48+    elif all:
49+        languages = [el for el in os.listdir(localedir) if not el.startswith('.')]
50+
51+    for locale in languages:
52+        if verbosity > 0:
53+            print "processing language", locale
54+        basedir = os.path.join(localedir, locale, 'LC_MESSAGES')
55+        if not os.path.isdir(basedir):
56+            os.makedirs(basedir)
57+
58+        pofile = os.path.join(basedir, '%s.po' % domain)
59+        potfile = os.path.join(basedir, '%s.pot' % domain)
60+
61+        if os.path.exists(potfile):
62+            os.unlink(potfile)
63+
64+        all_files = []
65+        for (dirpath, dirnames, filenames) in os.walk("."):
66+            all_files.extend([(dirpath, f) for f in filenames])
67+        all_files.sort()
68+        for dirpath, file in all_files:
69+            if domain == 'djangojs' and file.endswith('.js'):
70+                if verbosity > 1:
71+                    sys.stdout.write('processing file %s in %s\n' % (file, dirpath))
72+                src = open(os.path.join(dirpath, file), "rb").read()
73+                src = pythonize_re.sub('\n#', src)
74+                open(os.path.join(dirpath, '%s.py' % file), "wb").write(src)
75+                thefile = '%s.py' % file
76+                cmd = 'xgettext -d %s -L Perl --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy:1,2 --from-code UTF-8 -o - "%s"' % (domain, os.path.join(dirpath, thefile))
77+                (stdin, stdout, stderr) = os.popen3(cmd, 't')
78+                msgs = stdout.read()
79+                errors = stderr.read()
80+                if errors:
81+                    print "errors happened while running xgettext on %s" % file
82+                    print errors
83+                    sys.exit(8)
84+                old = '#: '+os.path.join(dirpath, thefile)[2:]
85+                new = '#: '+os.path.join(dirpath, file)[2:]
86+                msgs = msgs.replace(old, new)
87+                if os.path.exists(potfile):
88+                    # Strip the header
89+                    msgs = '\n'.join(dropwhile(len, msgs.split('\n')))
90+                else:
91+                    msgs = msgs.replace('charset=CHARSET', 'charset=UTF-8')
92+                if msgs:
93+                    open(potfile, 'ab').write(msgs)
94+                os.unlink(os.path.join(dirpath, thefile))
95+            elif domain == 'django' and (file.endswith('.py') or file.endswith('.html')):
96+                thefile = file
97+                if file.endswith('.html'):
98+                    src = open(os.path.join(dirpath, file), "rb").read()
99+                    thefile = '%s.py' % file
100+                    open(os.path.join(dirpath, thefile), "wb").write(templatize(src))
101+                if verbosity > 1:
102+                    sys.stdout.write('processing file %s in %s\n' % (file, dirpath))
103+                cmd = 'xgettext -d %s -L Python --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy:1,2 --keyword=ugettext_noop --keyword=ugettext_lazy --keyword=ungettext_lazy:1,2 --from-code UTF-8 -o - "%s"' % (
104+                    domain, os.path.join(dirpath, thefile))
105+                (stdin, stdout, stderr) = os.popen3(cmd, 't')
106+                msgs = stdout.read()
107+                errors = stderr.read()
108+                if errors:
109+                    print "errors happened while running xgettext on %s" % file
110+                    print errors
111+                    sys.exit(8)
112+                if thefile != file:
113+                    old = '#: '+os.path.join(dirpath, thefile)[2:]
114+                    new = '#: '+os.path.join(dirpath, file)[2:]
115+                    msgs = msgs.replace(old, new)
116+                if os.path.exists(potfile):
117+                    # Strip the header
118+                    msgs = '\n'.join(dropwhile(len, msgs.split('\n')))
119+                else:
120+                    msgs = msgs.replace('charset=CHARSET', 'charset=UTF-8')
121+                if msgs:
122+                    open(potfile, 'ab').write(msgs)
123+                if thefile != file:
124+                    os.unlink(os.path.join(dirpath, thefile))
125+
126+        if os.path.exists(potfile):
127+            (stdin, stdout, stderr) = os.popen3('msguniq --to-code=utf-8 "%s"' % potfile, 'b')
128+            msgs = stdout.read()
129+            errors = stderr.read()
130+            if errors:
131+                print "errors happened while running msguniq"
132+                print errors
133+                sys.exit(8)
134+            open(potfile, 'w').write(msgs)
135+            if os.path.exists(pofile):
136+                (stdin, stdout, stderr) = os.popen3('msgmerge -q "%s" "%s"' % (pofile, potfile), 'b')
137+                msgs = stdout.read()
138+                errors = stderr.read()
139+                if errors:
140+                    print "errors happened while running msgmerge"
141+                    print errors
142+                    sys.exit(8)
143+            open(pofile, 'wb').write(msgs)
144+            os.unlink(potfile)
145+
146+
147+class Command(BaseCommand):
148+    option_list = BaseCommand.option_list + (
149+        make_option('--locale', '-l', default=None, dest='locale',
150+            help='Creates or updates the message files only for the given locale (e.g. pt_BR).'),
151+        make_option('--domain', '-d', default='django', dest='domain',
152+            help='The domain of the message files (default: "django").'),
153+        make_option('--verbosity', '-v', action='store', dest='verbosity',
154+            default='1', type='choice', choices=['0', '1', '2'],
155+            help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'),
156+        make_option('--all', '-a', action='store_true', dest='all',
157+            default=False, help='Reexamines all source code and templates for new translation strings and updates all message files for all available languages.'),
158+    )
159+    help = "Runs over the entire source tree of the current directory and pulls out all strings marked for translation. It creates (or updates) a message file in the conf/locale (in the django tree) or locale (for project and application) directory."
160+
161+    requires_model_validation = False
162+    can_import_settings = False
163+
164+    def handle(self, *args, **options):
165+        if len(args) != 0:
166+            raise CommandError("Command doesn't accept any arguments")
167+
168+        locale = options.get('locale')
169+        domain = options.get('domain')
170+        verbosity = int(options.get('verbosity'))
171+        process_all = options.get('all')
172+
173+        make_messages(locale, domain, verbosity, process_all)
174Index: django/core/management/commands/compilemessages.py
175===================================================================
176--- django/core/management/commands/compilemessages.py  (Revision 0)
177+++ django/core/management/commands/compilemessages.py  (Revision 0)
178@@ -0,0 +1,58 @@
179+import os
180+import sys
181+from optparse import make_option
182+from django.core.management.base import BaseCommand
183+from django.core.management.color import no_style
184+
185+try:
186+    set
187+except NameError:
188+    from sets import Set as set     # For Python 2.3
189+
190+def compile_messages(locale=None):
191+    basedirs = (os.path.join('conf', 'locale'), 'locale')
192+    if os.environ.get('DJANGO_SETTINGS_MODULE'):
193+        from django.conf import settings
194+        basedirs += settings.LOCALE_PATHS
195+
196+    # Gather existing directories.
197+    basedirs = set(map(os.path.abspath, filter(os.path.isdir, basedirs)))
198+
199+    if not basedirs:
200+        raise CommandError("This script should be run from the Django SVN tree or your project or app tree, or with the settings module specified.")
201+
202+    for basedir in basedirs:
203+        if locale:
204+            basedir = os.path.join(basedir, locale, 'LC_MESSAGES')
205+        for dirpath, dirnames, filenames in os.walk(basedir):
206+            for f in filenames:
207+                if f.endswith('.po'):
208+                    sys.stderr.write('processing file %s in %s\n' % (f, dirpath))
209+                    pf = os.path.splitext(os.path.join(dirpath, f))[0]
210+                    # Store the names of the .mo and .po files in an environment
211+                    # variable, rather than doing a string replacement into the
212+                    # command, so that we can take advantage of shell quoting, to
213+                    # quote any malicious characters/escaping.
214+                    # See http://cyberelk.net/tim/articles/cmdline/ar01s02.html
215+                    os.environ['djangocompilemo'] = pf + '.mo'
216+                    os.environ['djangocompilepo'] = pf + '.po'
217+                    if sys.platform == 'win32': # Different shell-variable syntax
218+                        cmd = 'msgfmt --check-format -o "%djangocompilemo%" "%djangocompilepo%"'
219+                    else:
220+                        cmd = 'msgfmt --check-format -o "$djangocompilemo" "$djangocompilepo"'
221+                    os.system(cmd)
222+
223+
224+class Command(BaseCommand):
225+    option_list = BaseCommand.option_list + (
226+        make_option('--locale', '-l', dest='locale',
227+            help='The locale to process. Default is to process all.'),
228+    )
229+    help = 'Compiles .po files to .mo files for use with builtin gettext support.'
230+
231+    requires_model_validation = False
232+    can_import_settings = False
233+
234+    def handle(self, **options):
235+        locale = options.get('locale')
236+        compile_messages(locale)
237Index: django/core/management/commands/cleanup.py
238===================================================================
239--- django/core/management/commands/cleanup.py  (Revision 0)
240+++ django/core/management/commands/cleanup.py  (Revision 0)
241@@ -0,0 +1,11 @@
242+import datetime
243+from django.core.management.base import NoArgsCommand
244+
245+class Command(NoArgsCommand):
246+    help = "Can be run as a cronjob or directly to clean out old data from the database (only expired sessions at the moment)."
247+
248+    def handle_noargs(self, **options):
249+        from django.db import transaction
250+        from django.contrib.sessions.models import Session
251+        Session.objects.filter(expire_date__lt=datetime.datetime.now()).delete()
252+        transaction.commit_unless_managed()
253Index: django/core/management/base.py
254===================================================================
255--- django/core/management/base.py      (Revision 7599)
256+++ django/core/management/base.py      (Arbeitskopie)
257@@ -6,6 +6,11 @@
258 from django.core.exceptions import ImproperlyConfigured
259 from django.core.management.color import color_style
260 
261+try:
262+    set
263+except NameError:
264+    from sets import Set as set     # For Python 2.3
265+
266 class CommandError(Exception):
267     pass
268 
269Index: django/bin/daily_cleanup.py
270===================================================================
271--- django/bin/daily_cleanup.py (Revision 7599)
272+++ django/bin/daily_cleanup.py (Arbeitskopie)
273@@ -7,14 +7,7 @@
274 sessions at the moment).
275 """
276 
277-import datetime
278-from django.db import transaction
279-from django.contrib.sessions.models import Session
280+from django.core import management
281 
282-def clean_up():
283-    """Clean up expired sessions."""
284-    Session.objects.filter(expire_date__lt=datetime.datetime.now()).delete()
285-    transaction.commit_unless_managed()
286-
287 if __name__ == "__main__":
288-    clean_up()
289+    management.call_command('cleanup')
290Index: django/bin/compile-messages.py
291===================================================================
292--- django/bin/compile-messages.py      (Revision 7599)
293+++ django/bin/compile-messages.py      (Arbeitskopie)
294@@ -1,52 +1,9 @@
295 #!/usr/bin/env python
296 
297-import optparse
298 import os
299-import sys
300+import optparse
301+from django.core.management.commands.compilemessages import compile_messages
302 
303-try:
304-    set
305-except NameError:
306-    from sets import Set as set     # For Python 2.3
307-
308-
309-def compile_messages(locale=None):
310-    basedirs = (os.path.join('conf', 'locale'), 'locale')
311-    if os.environ.get('DJANGO_SETTINGS_MODULE'):
312-        from django.conf import settings
313-        basedirs += settings.LOCALE_PATHS
314-
315-    # Gather existing directories.
316-    basedirs = set(map(os.path.abspath, filter(os.path.isdir, basedirs)))
317-
318-    if not basedirs:
319-        print "This script should be run from the Django SVN tree or your project or app tree, or with the settings module specified."
320-        sys.exit(1)
321-
322-    for basedir in basedirs:
323-        if locale:
324-            basedir = os.path.join(basedir, locale, 'LC_MESSAGES')
325-        compile_messages_in_dir(basedir)
326-
327-def compile_messages_in_dir(basedir):
328-    for dirpath, dirnames, filenames in os.walk(basedir):
329-        for f in filenames:
330-            if f.endswith('.po'):
331-                sys.stderr.write('processing file %s in %s\n' % (f, dirpath))
332-                pf = os.path.splitext(os.path.join(dirpath, f))[0]
333-                # Store the names of the .mo and .po files in an environment
334-                # variable, rather than doing a string replacement into the
335-                # command, so that we can take advantage of shell quoting, to
336-                # quote any malicious characters/escaping.
337-                # See http://cyberelk.net/tim/articles/cmdline/ar01s02.html
338-                os.environ['djangocompilemo'] = pf + '.mo'
339-                os.environ['djangocompilepo'] = pf + '.po'
340-                if sys.platform == 'win32': # Different shell-variable syntax
341-                    cmd = 'msgfmt --check-format -o "%djangocompilemo%" "%djangocompilepo%"'
342-                else:
343-                    cmd = 'msgfmt --check-format -o "$djangocompilemo" "$djangocompilepo"'
344-                os.system(cmd)
345-
346 def main():
347     parser = optparse.OptionParser()
348     parser.add_option('-l', '--locale', dest='locale',
349Index: django/bin/make-messages.py
350===================================================================
351--- django/bin/make-messages.py (Revision 7599)
352+++ django/bin/make-messages.py (Arbeitskopie)
353@@ -1,159 +1,33 @@
354 #!/usr/bin/env python
355 
356-# Need to ensure that the i18n framework is enabled
357-from django.conf import settings
358-settings.configure(USE_I18N = True)
359-
360-from django.utils.translation import templatize
361-import re
362 import os
363-import sys
364-import getopt
365-from itertools import dropwhile
366+import optparse
367+from django.core.management.commands.makemessages import make_messages
368 
369-pythonize_re = re.compile(r'\n\s*//')
370+def main():
371+    parser = optparse.OptionParser()
372+    parser.add_option('-l', '--locale', dest='locale',
373+        help='Creates or updates the message files only for the \
374+            given locale (e.g. pt_BR).')
375+    parser.add_option('-d', '--domain', dest='domain', default='django',
376+        help='The domain of the message files (default: "django").')
377+    parser.add_option('-v', '--verbose', action='store_true', dest='verbose',
378+        default=False, help='Verbosity output')
379+    parser.add_option('-a', '--all', action='store_true', dest='all',
380+        default=False, help='Reexamines all source code and templates for \
381+            new translation strings and updates all message files for all \
382+            available languages.')
383 
384-def make_messages():
385-    localedir = None
386-
387-    if os.path.isdir(os.path.join('conf', 'locale')):
388-        localedir = os.path.abspath(os.path.join('conf', 'locale'))
389-    elif os.path.isdir('locale'):
390-        localedir = os.path.abspath('locale')
391+    options, args = parser.parse_args()
392+    if len(args):
393+        parser.error("This program takes no arguments")
394+    if options.verbose:
395+        verbosity = 2
396     else:
397-        print "This script should be run from the django svn tree or your project or app tree."
398-        print "If you did indeed run it from the svn checkout or your project or application,"
399-        print "maybe you are just missing the conf/locale (in the django tree) or locale (for project"
400-        print "and application) directory?"
401-        print "make-messages.py doesn't create it automatically, you have to create it by hand if"
402-        print "you want to enable i18n for your project or application."
403-        sys.exit(1)
404+        verbosity = 1
405+   
406+    make_messages(locale=options.locale, domain=options.domain,
407+        verbosity=verbosity, all=options.all)
408 
409-    (opts, args) = getopt.getopt(sys.argv[1:], 'l:d:va')
410-
411-    lang = None
412-    domain = 'django'
413-    verbose = False
414-    all = False
415-
416-    for o, v in opts:
417-        if o == '-l':
418-            lang = v
419-        elif o == '-d':
420-            domain = v
421-        elif o == '-v':
422-            verbose = True
423-        elif o == '-a':
424-            all = True
425-
426-    if domain not in ('django', 'djangojs'):
427-        print "currently make-messages.py only supports domains 'django' and 'djangojs'"
428-        sys.exit(1)
429-    if (lang is None and not all) or domain is None:
430-        print "usage: make-messages.py -l <language>"
431-        print "   or: make-messages.py -a"
432-        sys.exit(1)
433-
434-    languages = []
435-
436-    if lang is not None:
437-        languages.append(lang)
438-    elif all:
439-        languages = [el for el in os.listdir(localedir) if not el.startswith('.')]
440-
441-    for lang in languages:
442-
443-        print "processing language", lang
444-        basedir = os.path.join(localedir, lang, 'LC_MESSAGES')
445-        if not os.path.isdir(basedir):
446-            os.makedirs(basedir)
447-
448-        pofile = os.path.join(basedir, '%s.po' % domain)
449-        potfile = os.path.join(basedir, '%s.pot' % domain)
450-
451-        if os.path.exists(potfile):
452-            os.unlink(potfile)
453-
454-        all_files = []
455-        for (dirpath, dirnames, filenames) in os.walk("."):
456-            all_files.extend([(dirpath, f) for f in filenames])
457-        all_files.sort()
458-        for dirpath, file in all_files:
459-            if domain == 'djangojs' and file.endswith('.js'):
460-                if verbose: sys.stdout.write('processing file %s in %s\n' % (file, dirpath))
461-                src = open(os.path.join(dirpath, file), "rb").read()
462-                src = pythonize_re.sub('\n#', src)
463-                open(os.path.join(dirpath, '%s.py' % file), "wb").write(src)
464-                thefile = '%s.py' % file
465-                cmd = 'xgettext -d %s -L Perl --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy:1,2 --from-code UTF-8 -o - "%s"' % (domain, os.path.join(dirpath, thefile))
466-                (stdin, stdout, stderr) = os.popen3(cmd, 't')
467-                msgs = stdout.read()
468-                errors = stderr.read()
469-                if errors:
470-                    print "errors happened while running xgettext on %s" % file
471-                    print errors
472-                    sys.exit(8)
473-                old = '#: '+os.path.join(dirpath, thefile)[2:]
474-                new = '#: '+os.path.join(dirpath, file)[2:]
475-                msgs = msgs.replace(old, new)
476-                if os.path.exists(potfile):
477-                    # Strip the header
478-                    msgs = '\n'.join(dropwhile(len, msgs.split('\n')))
479-                else:
480-                    msgs = msgs.replace('charset=CHARSET', 'charset=UTF-8')
481-                if msgs:
482-                    open(potfile, 'ab').write(msgs)
483-                os.unlink(os.path.join(dirpath, thefile))
484-            elif domain == 'django' and (file.endswith('.py') or file.endswith('.html')):
485-                thefile = file
486-                if file.endswith('.html'):
487-                    src = open(os.path.join(dirpath, file), "rb").read()
488-                    thefile = '%s.py' % file
489-                    open(os.path.join(dirpath, thefile), "wb").write(templatize(src))
490-                if verbose:
491-                    sys.stdout.write('processing file %s in %s\n' % (file, dirpath))
492-                cmd = 'xgettext -d %s -L Python --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy:1,2 --keyword=ugettext_noop --keyword=ugettext_lazy --keyword=ungettext_lazy:1,2 --from-code UTF-8 -o - "%s"' % (
493-                    domain, os.path.join(dirpath, thefile))
494-                (stdin, stdout, stderr) = os.popen3(cmd, 't')
495-                msgs = stdout.read()
496-                errors = stderr.read()
497-                if errors:
498-                    print "errors happened while running xgettext on %s" % file
499-                    print errors
500-                    sys.exit(8)
501-                if thefile != file:
502-                    old = '#: '+os.path.join(dirpath, thefile)[2:]
503-                    new = '#: '+os.path.join(dirpath, file)[2:]
504-                    msgs = msgs.replace(old, new)
505-                if os.path.exists(potfile):
506-                    # Strip the header
507-                    msgs = '\n'.join(dropwhile(len, msgs.split('\n')))
508-                else:
509-                    msgs = msgs.replace('charset=CHARSET', 'charset=UTF-8')
510-                if msgs:
511-                    open(potfile, 'ab').write(msgs)
512-                if thefile != file:
513-                    os.unlink(os.path.join(dirpath, thefile))
514-
515-        if os.path.exists(potfile):
516-            (stdin, stdout, stderr) = os.popen3('msguniq --to-code=utf-8 "%s"' % potfile, 'b')
517-            msgs = stdout.read()
518-            errors = stderr.read()
519-            if errors:
520-                print "errors happened while running msguniq"
521-                print errors
522-                sys.exit(8)
523-            open(potfile, 'w').write(msgs)
524-            if os.path.exists(pofile):
525-                (stdin, stdout, stderr) = os.popen3('msgmerge -q "%s" "%s"' % (pofile, potfile), 'b')
526-                msgs = stdout.read()
527-                errors = stderr.read()
528-                if errors:
529-                    print "errors happened while running msgmerge"
530-                    print errors
531-                    sys.exit(8)
532-            open(pofile, 'wb').write(msgs)
533-            os.unlink(potfile)
534-
535 if __name__ == "__main__":
536-    make_messages()
537+    main()
538Index: extras/django_bash_completion
539===================================================================
540--- extras/django_bash_completion       (Revision 7599)
541+++ extras/django_bash_completion       (Arbeitskopie)
542@@ -42,13 +42,15 @@
543     prev="${COMP_WORDS[COMP_CWORD-1]}"
544 
545     # Standalone options
546-    opts="--help --settings --pythonpath --noinput --noreload --format --indent --verbosity --adminmedia --version"
547+    opts="--help --settings --pythonpath --noinput --noreload --locale --all --domain --format --indent --verbosity --adminmedia --version"
548+
549     # Actions
550-    actions="adminindex createcachetable dbshell diffsettings \
551-             dumpdata flush inspectdb loaddata reset runfcgi runserver \
552-             shell sql sqlall sqlclear sqlcustom sqlflush sqlindexes \
553-             sqlreset sqlsequencereset startapp startproject \
554-             syncdb test validate"
555+    actions="adminindex createcachetable cleanup compilemessages dbshell \
556+             diffsettings dumpdata flush inspectdb loaddata makemessages \
557+             reset runfcgi runserver shell sql sqlall sqlclear sqlcustom \
558+             sqlflush sqlindexes sqlreset sqlsequencereset startapp \
559+             startproject syncdb test validate"
560+
561     # Action's options
562     action_shell_opts="--plain"
563     action_runfcgi_opts="host port socket method maxspare minspare maxchildren daemonize pidfile workdir"
564@@ -112,8 +114,9 @@
565                 return 0
566                 ;;
567 
568-            createcachetable|dbshell|diffsettings| \
569-            inspectdb|runserver|startapp|startproject|syncdb| \
570+            createcachetable|cleanup|compilemessages|dbshell| \
571+            diffsettings|inspectdb|makemessages| \
572+            runserver|startapp|startproject|syncdb| \
573             validate)
574                 COMPREPLY=()
575                 return 0
576Index: docs/man/django-admin.1
577===================================================================
578--- docs/man/django-admin.1     (Revision 7599)
579+++ docs/man/django-admin.1     (Arbeitskopie)
580@@ -1,4 +1,4 @@
581-.TH "django-admin.py" "1" "June 2007" "Django Project" ""
582+.TH "django-admin.py" "1" "March 2008" "Django Project" ""
583 .SH "NAME"
584 django\-admin.py \- Utility script for the Django web framework
585 .SH "SYNOPSIS"
586@@ -21,6 +21,12 @@
587 .BI "adminindex [" "appname ..." "]"
588 Prints the admin\-index template snippet for the given app name(s).
589 .TP
590+.BI cleanup
591+Cleans out old data from the database (only expired sessions at the moment).
592+.TP
593+.BI "compilemessages [" "\-\-locale=LOCALE" "]"
594+Compiles .po files to .mo files for use with builtin gettext support.
595+.TP
596 .BI "createcachetable [" "tablename" "]"
597 Creates the table needed to use the SQL cache backend
598 .TP
599@@ -43,6 +49,11 @@
600 .B sqlall
601 for the given app(s) in the current database.
602 .TP
603+.BI "makemessages [" "\-\-locale=LOCALE" "] [" "\-\-domain=DOMAIN" "] [" "\-\-all" "]"
604+Runs over the entire source tree of the current directory and pulls out all
605+strings marked for translation. It creates (or updates) a message file in the
606+conf/locale (in the django tree) or locale (for project and application) directory.
607+.TP
608 .BI "reset [" "appname ..." "]"
609 Executes
610 .B sqlreset
611@@ -136,7 +147,15 @@
612 .TP
613 .I \-\-adminmedia=ADMIN_MEDIA_PATH
614 Specifies the directory from which to serve admin media when using the development server.
615-
616+.TP
617+.I \-l, \-\-locale=LOCALE
618+The locale to process when using makemessages or compilemessages.
619+.TP
620+.I \-d, \-\-domain=DOMAIN
621+The domain of the message files (default: "django") when using makemessages.
622+.TP
623+.I \-a, \-\-all
624+Process all available locales when using makemessages.
625 .SH "ENVIRONMENT"
626 .TP
627 .I DJANGO_SETTINGS_MODULE
628Index: docs/i18n.txt
629===================================================================
630--- docs/i18n.txt       (Revision 7599)
631+++ docs/i18n.txt       (Arbeitskopie)
632@@ -122,8 +122,8 @@
633 
634 (The caveat with using variables or computed values, as in the previous two
635 examples, is that Django's translation-string-detecting utility,
636-``make-messages.py``, won't be able to find these strings. More on
637-``make-messages`` later.)
638+``django-admin.py makemessages``, won't be able to find these strings. More on
639+``makemessages`` later.)
640 
641 The strings you pass to ``_()`` or ``ugettext()`` can take placeholders,
642 specified with Python's standard named-string interpolation syntax. Example::
643@@ -392,12 +392,12 @@
644 available translation strings and how they should be represented in the given
645 language. Message files have a ``.po`` file extension.
646 
647-Django comes with a tool, ``bin/make-messages.py``, that automates the creation
648-and upkeep of these files.
649+Django comes with a tool, ``django-admin.py makemessages``, that automates the
650+creation and upkeep of these files.
651 
652 To create or update a message file, run this command::
653 
654-    bin/make-messages.py -l de
655+    django-admin.py makemessages -l de
656 
657 ...where ``de`` is the language code for the message file you want to create.
658 The language code, in this case, is in locale format. For example, it's
659@@ -422,11 +422,11 @@
660 
661 .. admonition:: No gettext?
662 
663-    If you don't have the ``gettext`` utilities installed, ``make-messages.py``
664-    will create empty files. If that's the case, either install the ``gettext``
665-    utilities or just copy the English message file
666-    (``conf/locale/en/LC_MESSAGES/django.po``) and use it as a starting point;
667-    it's just an empty translation file.
668+    If you don't have the ``gettext`` utilities installed,
669+    ``django-admin.py makemessages`` will create empty files. If that's the
670+    case, either install the ``gettext`` utilities or just copy the English
671+    message file (``conf/locale/en/LC_MESSAGES/django.po``) and use it as a
672+    starting point; it's just an empty translation file.
673 
674 The format of ``.po`` files is straightforward. Each ``.po`` file contains a
675 small bit of metadata, such as the translation maintainer's contact
676@@ -439,8 +439,8 @@
677 
678     _("Welcome to my site.")
679 
680-...then ``make-messages.py`` will have created a ``.po`` file containing the
681-following snippet -- a message::
682+...then ``django-admin.py makemessages`` will have created a ``.po`` file
683+containing the following snippet -- a message::
684 
685     #: path/to/python/module.py:23
686     msgid "Welcome to my site."
687@@ -475,21 +475,21 @@
688 To reexamine all source code and templates for new translation strings and
689 update all message files for **all** languages, run this::
690 
691-    make-messages.py -a
692+    django-admin.py makemessages -a
693 
694 Compiling message files
695 -----------------------
696 
697 After you create your message file -- and each time you make changes to it --
698 you'll need to compile it into a more efficient form, for use by ``gettext``.
699-Do this with the ``bin/compile-messages.py`` utility.
700+Do this with the ``django-admin.py compilemessages`` utility.
701 
702 This tool runs over all available ``.po`` files and creates ``.mo`` files,
703 which are binary files optimized for use by ``gettext``. In the same directory
704-from which you ran ``make-messages.py``, run ``compile-messages.py`` like
705-this::
706+from which you ran ``django-admin.py makemessages``, run
707+``django-admin.py compilemessages`` like this::
708 
709-   bin/compile-messages.py
710+   django-admin.py compilemessages
711 
712 That's it. Your translations are ready for use.
713 
714@@ -597,9 +597,9 @@
715               ('en', ugettext('English')),
716           )
717 
718-      With this arrangement, ``make-messages.py`` will still find and mark
719-      these strings for translation, but the translation won't happen at
720-      runtime -- so you'll have to remember to wrap the languages in the *real*
721+      With this arrangement, ``django-admin.py makemessages`` will still find
722+      and mark these strings for translation, but the translation won't happen
723+      at runtime -- so you'll have to remember to wrap the languages in the *real*
724       ``ugettext()`` in any code that uses ``LANGUAGES`` at runtime.
725 
726     * The ``LocaleMiddleware`` can only select languages for which there is a
727@@ -676,12 +676,12 @@
728       searched in that order for ``<language>/LC_MESSAGES/django.(po|mo)``
729     * ``$PYTHONPATH/django/conf/locale/<language>/LC_MESSAGES/django.(po|mo)``
730 
731-To create message files, you use the same ``make-messages.py`` tool as with the
732-Django message files. You only need to be in the right place -- in the directory
733-where either the ``conf/locale`` (in case of the source tree) or the ``locale/``
734-(in case of app messages or project messages) directory are located. And you
735-use the same ``compile-messages.py`` to produce the binary ``django.mo`` files
736-that are used by ``gettext``.
737+To create message files, you use the same ``django-admin.py makemessages``
738+tool as with the Django message files. You only need to be in the right place
739+-- in the directory where either the ``conf/locale`` (in case of the source
740+tree) or the ``locale/`` (in case of app messages or project messages)
741+directory are located. And you use the same ``django-admin.py compilemessages``
742+to produce the binary ``django.mo`` files that are used by ``gettext``.
743 
744 You can also run ``compile-message.py --settings=path.to.settings`` to make
745 the compiler process all the directories in your ``LOCALE_PATHS`` setting.
746@@ -694,15 +694,15 @@
747 files. If your applications need to be delivered to other users and will
748 be used in other projects, you might want to use app-specific translations.
749 But using app-specific translations and project translations could produce
750-weird problems with ``make-messages``: ``make-messages`` will traverse all
751+weird problems with ``makemessages``: ``makemessages`` will traverse all
752 directories below the current path and so might put message IDs into the
753 project message file that are already in application message files.
754 
755 The easiest way out is to store applications that are not part of the project
756 (and so carry their own translations) outside the project tree. That way,
757-``make-messages`` on the project level will only translate strings that are
758-connected to your explicit project and not strings that are distributed
759-independently.
760+``django-admin.py makemessages`` on the project level will only translate
761+strings that are connected to your explicit project and not strings that are
762+distributed independently.
763 
764 The ``set_language`` redirect view
765 ==================================
766@@ -857,14 +857,14 @@
767 ----------------------------------------
768 
769 You create and update the translation catalogs the same way as the other
770-Django translation catalogs -- with the make-messages.py tool. The only
771-difference is you need to provide a ``-d djangojs`` parameter, like this::
772+Django translation catalogs -- with the django-admin.py makemessages tool. The
773+only difference is you need to provide a ``-d djangojs`` parameter, like this::
774 
775-    make-messages.py -d djangojs -l de
776+    django-admin.py makemessages -d djangojs -l de
777 
778 This would create or update the translation catalog for JavaScript for German.
779-After updating translation catalogs, just run ``compile-messages.py`` the same
780-way as you do with normal Django translation catalogs.
781+After updating translation catalogs, just run ``django-admin.py compilemessages``
782+the same way as you do with normal Django translation catalogs.
783 
784 Specialties of Django translation
785 ==================================
786Index: docs/contributing.txt
787===================================================================
788--- docs/contributing.txt       (Revision 7599)
789+++ docs/contributing.txt       (Arbeitskopie)
790@@ -331,7 +331,7 @@
791     * Create translations using the methods described in the
792       `i18n documentation`_.
793     * Create a diff of the ``.po`` file against the current Subversion trunk.
794-    * Make sure that `` bin/compile-messages.py -l <lang>`` runs without
795+    * Make sure that `` django-admin.py compilemessages -l <lang>`` runs without
796       producing any warnings.
797     * Attach the patch to a ticket in Django's ticket system.
798 
799Index: docs/settings.txt
800===================================================================
801--- docs/settings.txt   (Revision 7599)
802+++ docs/settings.txt   (Arbeitskopie)
803@@ -638,10 +638,10 @@
804         ('en', gettext('English')),
805     )
806 
807-With this arrangement, ``make-messages.py`` will still find and mark these
808-strings for translation, but the translation won't happen at runtime -- so
809-you'll have to remember to wrap the languages in the *real* ``gettext()`` in
810-any code that uses ``LANGUAGES`` at runtime.
811+With this arrangement, ``django-admin.py makemessages`` will still find and
812+mark these strings for translation, but the translation won't happen at
813+runtime -- so you'll have to remember to wrap the languages in the *real*
814+``gettext()`` in any code that uses ``LANGUAGES`` at runtime.
815 
816 LOCALE_PATHS
817 ------------
818Index: docs/sessions.txt
819===================================================================
820--- docs/sessions.txt   (Revision 7599)
821+++ docs/sessions.txt   (Arbeitskopie)
822@@ -349,7 +349,7 @@
823 logs out manually, Django deletes the row. But if the user does *not* log out,
824 the row never gets deleted.
825 
826-Django provides a sample clean-up script in ``django/bin/daily_cleanup.py``.
827+Django provides a sample clean-up script in ``django-admin.py cleanup``.
828 That script deletes any session in the session table whose ``expire_date`` is
829 in the past -- but your application may have different requirements.
830 
831Index: docs/django-admin.txt
832===================================================================
833--- docs/django-admin.txt       (Revision 7599)
834+++ docs/django-admin.txt       (Arbeitskopie)
835@@ -85,6 +85,28 @@
836 
837 .. _Tutorial 2: ../tutorial02/
838 
839+cleanup
840+-------
841+
842+Can be run as a cronjob or directly to clean out old data from the database
843+(only expired sessions at the moment).
844+
845+compilemessages
846+---------------
847+
848+Compiles .po files created with ``makemessages`` to .mo files for use with
849+the builtin gettext support. See the `i18n documentation`_ for details.
850+
851+--locale
852+~~~~~~~~
853+
854+Use the ``--locale`` or ``-l`` option to specify the locale to process.
855+If not provided all locales are processed.
856+
857+Example usage::
858+
859+    django-admin.py compilemessages --locale=br_PT
860+
861 createcachetable <tablename>
862 ----------------------------
863 
864@@ -346,6 +368,60 @@
865 
866     django-admin.py loaddata --verbosity=2
867 
868+makemessages
869+------------
870+
871+Runs over the entire source tree of the current directory and pulls out all
872+strings marked for translation. It creates (or updates) a message file in the
873+conf/locale (in the django tree) or locale (for project and application)
874+directory. After making changes to the messages files you need to compile them
875+with ``compilemessages`` for use with the builtin gettext support. See the
876+`i18n documentation`_ for details.
877+
878+.. _i18n documentation: ../i18n/#how-to-create-language-files
879+
880+--all
881+~~~~~
882+
883+Use the ``--all`` or ``-a`` option to update the message files for all
884+available languages.
885+
886+Example usage::
887+
888+    django-admin.py makemessages --all
889+
890+--locale
891+~~~~~~~~
892+
893+Use the ``--locale`` or ``-l`` option to specify the locale to process.
894+
895+Example usage::
896+
897+    django-admin.py makemessages --locale=br_PT
898+
899+--domain
900+~~~~~~~~
901+
902+Use the ``--domain`` or ``-d`` option to change the domain of the messages files.
903+Currently supported:
904+
905+       * ``django`` for all ``*.py`` and ``*.html`` files (default)
906+       * ``djangojs`` for ``*.js`` files
907+
908+--verbosity
909+~~~~~~~~~~~
910+
911+Use ``--verbosity`` or ``-v`` to specify the amount of notification and debug
912+information that ``django-admin.py`` should print to the console.
913+
914+       * ``0`` means no input.
915+       * ``1`` means normal input (default).
916+       * ``2`` means verbose input.
917+
918+Example usage::
919+
920+    django-admin.py makemessages --verbosity=2
921+
922 reset <appname appname ...>
923 ---------------------------
924