diff --git a/django/core/management/commands/makemessages.py b/django/core/management/commands/makemessages.py index 6e8ec3da40..a44c10c250 100644 --- a/django/core/management/commands/makemessages.py +++ b/django/core/management/commands/makemessages.py @@ -43,7 +43,31 @@ def _popen(cmd): p = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE, close_fds=os.name != 'nt', universal_newlines=True) 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/ 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): os.unlink(potfile) - all_files = [] - 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: + for dirpath, file in find_files(".", symlinks=symlinks): file_base, file_ext = os.path.splitext(file) if domain == 'djangojs' and file_ext in extensions: if verbosity > 1: @@ -184,6 +204,8 @@ class Command(BaseCommand): help='The domain of the message files (default: "django").'), 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.'), + 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', help='The file extension(s) to examine (default: ".html", separate multiple extensions with commas, or use -e multiple times)', action='append'), @@ -202,6 +224,7 @@ class Command(BaseCommand): verbosity = int(options.get('verbosity')) process_all = options.get('all') extensions = options.get('extensions') + symlinks = options.get('symlinks') if domain == 'djangojs': extensions = handle_extensions(extensions or ['js']) @@ -211,4 +234,4 @@ class Command(BaseCommand): if verbosity > 1: 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) diff --git a/docs/man/django-admin.1 b/docs/man/django-admin.1 index dff7d0d3da..473809279b 100644 --- a/docs/man/django-admin.1 +++ b/docs/man/django-admin.1 @@ -46,7 +46,7 @@ Executes .B sqlall for the given app(s) in the current database. .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 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. @@ -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 extensions with commas, or use -e multiple times). .TP +.I \-e, \-\-symlinks +Follows symlinks to directories when examining source code and templates for +translation strings. +.TP .I \-a, \-\-all Process all available locales when using makemessages..SH "ENVIRONMENT" .TP diff --git a/docs/ref/django-admin.txt b/docs/ref/django-admin.txt index 8a4a9bcc2b..641e619fa6 100644 --- a/docs/ref/django-admin.txt +++ b/docs/ref/django-admin.txt @@ -471,8 +471,17 @@ Example usage:: Use the ``--domain`` or ``-d`` option to change the domain of the messages files. Currently supported: - * ``django`` for all ``*.py`` and ``*.html`` files (default) - * ``djangojs`` for ``*.js`` files + * ``django`` for all ``*.py`` and ``*.html`` files (default) + * ``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 --------------------------- diff --git a/docs/topics/i18n/localization.txt b/docs/topics/i18n/localization.txt index 5e909d5fa6..2cd3eb1af3 100644 --- a/docs/topics/i18n/localization.txt +++ b/docs/topics/i18n/localization.txt @@ -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 app. -Th script runs over your project source tree or your application source tree and -pulls out all strings marked for translation. It creates (or updates) a message -file in the directory ``locale/LANG/LC_MESSAGES``. In the ``de`` example, the -file will be ``locale/de/LC_MESSAGES/django.po``. +The script runs over your project source tree or your application source tree +and pulls out all strings marked for translation. It creates (or updates) a +message file in the directory ``locale/LANG/LC_MESSAGES``. In the ``de`` +example, the file will be ``locale/de/LC_MESSAGES/django.po``. 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 diff --git a/tests/regressiontests/makemessages/templates/test.html b/tests/regressiontests/makemessages/templates/test.html new file mode 100644 index 0000000000..2c38b3e4e6 --- /dev/null +++ b/tests/regressiontests/makemessages/templates/test.html @@ -0,0 +1,2 @@ +{% load i18n %} +{% trans "This literal should be included." %} \ No newline at end of file diff --git a/tests/regressiontests/makemessages/tests.py b/tests/regressiontests/makemessages/tests.py index 954daf6a41..84eed2edeb 100644 --- a/tests/regressiontests/makemessages/tests.py +++ b/tests/regressiontests/makemessages/tests.py @@ -40,3 +40,34 @@ class JavascriptExtractorTests(ExtractorTests): po_contents = open(self.PO_FILE, 'r').read() self.assertMsgId('This literal should be included.', 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)