Fixed #7050 - Allow the makemessages command to optionally ignore paths when examining source code and templates for translation strings.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@12444 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Jannis Leidel 2010-02-16 12:15:04 +00:00
parent fef575a7f9
commit eb26c9686b
5 changed files with 79 additions and 11 deletions

View File

@ -1,7 +1,8 @@
import re import fnmatch
import os
import sys
import glob import glob
import os
import re
import sys
from itertools import dropwhile from itertools import dropwhile
from optparse import make_option from optparse import make_option
from subprocess import PIPE, Popen from subprocess import PIPE, Popen
@ -56,18 +57,33 @@ def walk(root, topdown=True, onerror=None, followlinks=False):
for link_dirpath, link_dirnames, link_filenames in walk(p): for link_dirpath, link_dirnames, link_filenames in walk(p):
yield (link_dirpath, link_dirnames, link_filenames) yield (link_dirpath, link_dirnames, link_filenames)
def find_files(root, symlinks=False): def is_ignored(path, ignore_patterns):
"""
Helper function to check if the given path should be ignored or not.
"""
for pattern in ignore_patterns:
if fnmatch.fnmatchcase(path, pattern):
return True
return False
def find_files(root, ignore_patterns, verbosity, symlinks=False):
""" """
Helper function to get all files in the given root. Helper function to get all files in the given root.
""" """
all_files = [] all_files = []
for (dirpath, dirnames, filenames) in walk(".", followlinks=symlinks): for (dirpath, dirnames, filenames) in walk(".", followlinks=symlinks):
all_files.extend([(dirpath, f) for f in filenames]) for f in filenames:
norm_filepath = os.path.normpath(os.path.join(dirpath, f))
if is_ignored(norm_filepath, ignore_patterns):
if verbosity > 1:
sys.stdout.write('ignoring file %s in %s\n' % (f, dirpath))
else:
all_files.extend([(dirpath, f)])
all_files.sort() all_files.sort()
return all_files return all_files
def make_messages(locale=None, domain='django', verbosity='1', all=False, def make_messages(locale=None, domain='django', verbosity='1', all=False,
extensions=None, symlinks=False): extensions=None, symlinks=False, ignore_patterns=[]):
""" """
Uses the locale directory from the Django SVN tree or an application/ Uses the locale directory from the Django SVN tree or an application/
project to process all project to process all
@ -127,7 +143,7 @@ def make_messages(locale=None, domain='django', verbosity='1', all=False,
if os.path.exists(potfile): if os.path.exists(potfile):
os.unlink(potfile) os.unlink(potfile)
for dirpath, file in find_files(".", symlinks=symlinks): for dirpath, file in find_files(".", ignore_patterns, verbosity, symlinks=symlinks):
file_base, file_ext = os.path.splitext(file) file_base, file_ext = os.path.splitext(file)
if domain == 'djangojs' and file_ext in extensions: if domain == 'djangojs' and file_ext in extensions:
if verbosity > 1: if verbosity > 1:
@ -204,11 +220,15 @@ class Command(BaseCommand):
help='The domain of the message files (default: "django").'), help='The domain of the message files (default: "django").'),
make_option('--all', '-a', action='store_true', dest='all', make_option('--all', '-a', action='store_true', dest='all',
default=False, help='Reexamines all source code and templates for new translation strings and updates all message files for all available languages.'), default=False, help='Reexamines all source code and templates for new translation strings and updates all message files for all available languages.'),
make_option('--symlinks', '-s', action='store_true', dest='symlinks',
default=False, help='Follows symlinks to directories when examining source code and templates for translation strings.'),
make_option('--extension', '-e', dest='extensions', make_option('--extension', '-e', dest='extensions',
help='The file extension(s) to examine (default: ".html", separate multiple extensions with commas, or use -e multiple times)', help='The file extension(s) to examine (default: ".html", separate multiple extensions with commas, or use -e multiple times)',
action='append'), action='append'),
make_option('--symlinks', '-s', action='store_true', dest='symlinks',
default=False, help='Follows symlinks to directories when examining source code and templates for translation strings.'),
make_option('--ignore', '-i', action='append', dest='ignore_patterns',
default=[], metavar='PATTERN', help='Ignore files or directories matching this glob-style pattern. Use multiple times to ignore more.'),
make_option('--no-default-ignore', action='store_false', dest='use_default_ignore_patterns',
default=True, help="Don't ignore the common glob-style patterns 'CVS', '.*' and '*~'."),
) )
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." 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."
@ -225,6 +245,10 @@ class Command(BaseCommand):
process_all = options.get('all') process_all = options.get('all')
extensions = options.get('extensions') extensions = options.get('extensions')
symlinks = options.get('symlinks') symlinks = options.get('symlinks')
ignore_patterns = options.get('ignore_patterns')
if options.get('use_default_ignore_patterns'):
ignore_patterns += ['CVS', '.*', '*~']
ignore_patterns = list(set(ignore_patterns))
if domain == 'djangojs': if domain == 'djangojs':
extensions = handle_extensions(extensions or ['js']) extensions = handle_extensions(extensions or ['js'])
@ -234,4 +258,4 @@ class Command(BaseCommand):
if verbosity > 1: if verbosity > 1:
sys.stdout.write('examining files with the extensions: %s\n' % get_text_list(list(extensions), 'and')) sys.stdout.write('examining files with the extensions: %s\n' % get_text_list(list(extensions), 'and'))
make_messages(locale, domain, verbosity, process_all, extensions, symlinks) make_messages(locale, domain, verbosity, process_all, extensions, symlinks, ignore_patterns)

View File

@ -46,7 +46,7 @@ Executes
.B sqlall .B sqlall
for the given app(s) in the current database. for the given app(s) in the current database.
.TP .TP
.BI "makemessages [" "\-\-locale=LOCALE" "] [" "\-\-domain=DOMAIN" "] [" "\-\-extension=EXTENSION" "] [" "\-\-all" "] [" "\-\-symlinks" "]" .BI "makemessages [" "\-\-locale=LOCALE" "] [" "\-\-domain=DOMAIN" "] [" "\-\-extension=EXTENSION" "] [" "\-\-all" "] [" "\-\-symlinks" "] [" "\-\-ignore=PATTERN" "] [" "\-\-no\-default\-ignore" "]"
Runs over the entire source tree of the current directory and pulls out all 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 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. conf/locale (in the django tree) or locale (for project and application) directory.
@ -159,6 +159,13 @@ extensions with commas, or use -e multiple times).
Follows symlinks to directories when examining source code and templates for Follows symlinks to directories when examining source code and templates for
translation strings. translation strings.
.TP .TP
.I \-e, \-\-ignore=PATTERN
Ignore files or directories matching this glob-style pattern. Use multiple
times to ignore more.
.TP
.I \-e, \-\-no\-default\-ignore
Don't ignore the common private glob-style patterns 'CVS', '.*' and '*~'.
.TP
.I \-a, \-\-all .I \-a, \-\-all
Process all available locales when using makemessages..SH "ENVIRONMENT" Process all available locales when using makemessages..SH "ENVIRONMENT"
.TP .TP

View File

@ -483,6 +483,24 @@ Example usage::
django-admin.py makemessages --locale=de --symlinks django-admin.py makemessages --locale=de --symlinks
.. django-admin-option:: --ignore
Use the ``--ignore`` or ``-i`` option to ignore files or directories matching
the given `glob-style pattern`_. Use multiple times to ignore more.
These patterns are used by default: ``'CVS'``, ``'.*'``, ``'*~'``
Example usage::
django-admin.py makemessages --locale=en_US --ignore=apps/* --ignore=secret/*.html
.. _`glob-style pattern`: http://docs.python.org/library/glob.html
.. django-admin-option:: --no-default-ignore
Use the ``--no-default-ignore`` option to disable the default values of
:djadminopt:`--ignore`.
reset <appname appname ...> reset <appname appname ...>
--------------------------- ---------------------------

View File

@ -0,0 +1,2 @@
{% load i18n %}
{% trans "This should be ignored." %}

View File

@ -28,6 +28,9 @@ class ExtractorTests(TestCase):
def assertMsgId(self, msgid, s): def assertMsgId(self, msgid, s):
return self.assert_(re.search('^msgid "%s"' % msgid, s, re.MULTILINE)) return self.assert_(re.search('^msgid "%s"' % msgid, s, re.MULTILINE))
def assertNotMsgId(self, msgid, s):
return self.assert_(not re.search('^msgid "%s"' % msgid, s, re.MULTILINE))
class JavascriptExtractorTests(ExtractorTests): class JavascriptExtractorTests(ExtractorTests):
@ -41,6 +44,20 @@ class JavascriptExtractorTests(ExtractorTests):
self.assertMsgId('This literal should be included.', po_contents) self.assertMsgId('This literal should be included.', po_contents)
self.assertMsgId('This one as well.', po_contents) self.assertMsgId('This one as well.', po_contents)
class IgnoredExtractorTests(ExtractorTests):
PO_FILE='locale/%s/LC_MESSAGES/django.po' % LOCALE
def test_ignore_option(self):
os.chdir(self.test_dir)
management.call_command('makemessages', locale=LOCALE, verbosity=0, ignore_patterns=['ignore_dir/*'])
self.assert_(os.path.exists(self.PO_FILE))
po_contents = open(self.PO_FILE, 'r').read()
self.assertMsgId('This literal should be included.', po_contents)
self.assertNotMsgId('This should be ignored.', po_contents)
class SymlinkExtractorTests(ExtractorTests): class SymlinkExtractorTests(ExtractorTests):
PO_FILE='locale/%s/LC_MESSAGES/django.po' % LOCALE PO_FILE='locale/%s/LC_MESSAGES/django.po' % LOCALE