Skip to content

Commit

Permalink
Fixed #7050 - Allow the makemessages command to optionally ignore pat…
Browse files Browse the repository at this point in the history
…hs 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
  • Loading branch information
jezdez committed Feb 16, 2010
1 parent fef575a commit eb26c96
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 10 deletions.
42 changes: 33 additions & 9 deletions django/core/management/commands/makemessages.py
@@ -1,7 +1,8 @@
import re import fnmatch
import glob
import os import os
import re
import sys import sys
import glob
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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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."


Expand All @@ -225,6 +245,10 @@ def handle(self, *args, **options):
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'])
Expand All @@ -234,4 +258,4 @@ def handle(self, *args, **options):
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)
9 changes: 8 additions & 1 deletion docs/man/django-admin.1
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
18 changes: 18 additions & 0 deletions docs/ref/django-admin.txt
Expand Up @@ -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 ...>
--------------------------- ---------------------------


Expand Down
2 changes: 2 additions & 0 deletions tests/regressiontests/makemessages/ignore_dir/ignored.html
@@ -0,0 +1,2 @@
{% load i18n %}
{% trans "This should be ignored." %}
17 changes: 17 additions & 0 deletions tests/regressiontests/makemessages/tests.py
Expand Up @@ -28,6 +28,9 @@ def tearDown(self):
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):


Expand All @@ -41,6 +44,20 @@ def test_javascript_literals(self):
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
Expand Down

0 comments on commit eb26c96

Please sign in to comment.