Fixed #6380 - Follow symlinks when examining source code and templates for translation strings.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@12443 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Jannis Leidel 2010-02-16 12:14:27 +00:00
parent 71da5f62da
commit fef575a7f9
6 changed files with 83 additions and 14 deletions

View File

@ -43,7 +43,31 @@ def _popen(cmd):
p = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE, close_fds=os.name != 'nt', universal_newlines=True) p = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE, close_fds=os.name != 'nt', universal_newlines=True)
return p.communicate() return p.communicate()
def make_messages(locale=None, domain='django', verbosity='1', all=False, extensions=None): def walk(root, topdown=True, onerror=None, followlinks=False):
"""
A version of os.walk that can follow symlinks for Python < 2.6
"""
for dirpath, dirnames, filenames in os.walk(root, topdown, onerror):
yield (dirpath, dirnames, filenames)
if followlinks:
for d in dirnames:
p = os.path.join(dirpath, d)
if os.path.islink(p):
for link_dirpath, link_dirnames, link_filenames in walk(p):
yield (link_dirpath, link_dirnames, link_filenames)
def find_files(root, symlinks=False):
"""
Helper function to get all files in the given root.
"""
all_files = []
for (dirpath, dirnames, filenames) in walk(".", followlinks=symlinks):
all_files.extend([(dirpath, f) for f in filenames])
all_files.sort()
return all_files
def make_messages(locale=None, domain='django', verbosity='1', all=False,
extensions=None, symlinks=False):
""" """
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
@ -103,11 +127,7 @@ def make_messages(locale=None, domain='django', verbosity='1', all=False, extens
if os.path.exists(potfile): if os.path.exists(potfile):
os.unlink(potfile) os.unlink(potfile)
all_files = [] for dirpath, file in find_files(".", symlinks=symlinks):
for (dirpath, dirnames, filenames) in os.walk("."):
all_files.extend([(dirpath, f) for f in filenames])
all_files.sort()
for dirpath, file in all_files:
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:
@ -184,6 +204,8 @@ 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'),
@ -202,6 +224,7 @@ class Command(BaseCommand):
verbosity = int(options.get('verbosity')) verbosity = int(options.get('verbosity'))
process_all = options.get('all') process_all = options.get('all')
extensions = options.get('extensions') extensions = options.get('extensions')
symlinks = options.get('symlinks')
if domain == 'djangojs': if domain == 'djangojs':
extensions = handle_extensions(extensions or ['js']) extensions = handle_extensions(extensions or ['js'])
@ -211,4 +234,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) make_messages(locale, domain, verbosity, process_all, extensions, symlinks)

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" "]" .BI "makemessages [" "\-\-locale=LOCALE" "] [" "\-\-domain=DOMAIN" "] [" "\-\-extension=EXTENSION" "] [" "\-\-all" "] [" "\-\-symlinks" "]"
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.
@ -155,6 +155,10 @@ The domain of the message files (default: "django") when using makemessages.
The file extension(s) to examine (default: ".html", separate multiple The file extension(s) to examine (default: ".html", separate multiple
extensions with commas, or use -e multiple times). extensions with commas, or use -e multiple times).
.TP .TP
.I \-e, \-\-symlinks
Follows symlinks to directories when examining source code and templates for
translation strings.
.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

@ -471,8 +471,17 @@ Example usage::
Use the ``--domain`` or ``-d`` option to change the domain of the messages files. Use the ``--domain`` or ``-d`` option to change the domain of the messages files.
Currently supported: Currently supported:
* ``django`` for all ``*.py`` and ``*.html`` files (default) * ``django`` for all ``*.py`` and ``*.html`` files (default)
* ``djangojs`` for ``*.js`` files * ``djangojs`` for ``*.js`` files
.. django-admin-option:: --symlinks
Use the ``--symlinks`` or ``-s`` option to follow symlinks to directories when
looking for new translation strings.
Example usage::
django-admin.py makemessages --locale=de --symlinks
reset <appname appname ...> reset <appname appname ...>
--------------------------- ---------------------------

View File

@ -78,10 +78,10 @@ The script should be run from one of two places:
* The root directory of your Django project. * The root directory of your Django project.
* The root directory of your Django app. * The root directory of your Django app.
Th script runs over your project source tree or your application source tree and The script runs over your project source tree or your application source tree
pulls out all strings marked for translation. It creates (or updates) a message and pulls out all strings marked for translation. It creates (or updates) a
file in the directory ``locale/LANG/LC_MESSAGES``. In the ``de`` example, the message file in the directory ``locale/LANG/LC_MESSAGES``. In the ``de``
file will be ``locale/de/LC_MESSAGES/django.po``. example, the file will be ``locale/de/LC_MESSAGES/django.po``.
By default ``django-admin.py makemessages`` examines every file that has the By default ``django-admin.py makemessages`` examines every file that has the
``.html`` file extension. In case you want to override that default, use the ``.html`` file extension. In case you want to override that default, use the

View File

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

View File

@ -40,3 +40,34 @@ class JavascriptExtractorTests(ExtractorTests):
po_contents = open(self.PO_FILE, 'r').read() po_contents = open(self.PO_FILE, 'r').read()
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 SymlinkExtractorTests(ExtractorTests):
PO_FILE='locale/%s/LC_MESSAGES/django.po' % LOCALE
def setUp(self):
self._cwd = os.getcwd()
self.test_dir = os.path.abspath(os.path.dirname(__file__))
self.symlinked_dir = os.path.join(self.test_dir, 'templates_symlinked')
def tearDown(self):
super(SymlinkExtractorTests, self).tearDown()
os.chdir(self.test_dir)
try:
os.remove(self.symlinked_dir)
except OSError:
pass
os.chdir(self._cwd)
def test_symlink(self):
if hasattr(os, 'symlink'):
if os.path.exists(self.symlinked_dir):
self.assert_(os.path.islink(self.symlinked_dir))
else:
os.symlink(os.path.join(self.test_dir, 'templates'), self.symlinked_dir)
os.chdir(self.test_dir)
management.call_command('makemessages', locale=LOCALE, verbosity=0, symlinks=True)
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.assert_('templates_symlinked/test.html' in po_contents)