Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

allow multiple domains and languages for makemessages command; add op…

…tion to pass in multiple language to the compilemessages command
  • Loading branch information...
commit 4fbb940bdbc26976d021791b21c4271fa229655c 1 parent c28e700
Craig Blaszczyk authored June 07, 2012
50  django/core/management/commands/compilemessages.py
@@ -24,34 +24,38 @@ def compile_messages(stderr, locale=None):
24 24
         raise CommandError("This script should be run from the Django Git checkout or your project or app tree, or with the settings module specified.")
25 25
 
26 26
     for basedir in basedirs:
  27
+        dirs = [basedir]
27 28
         if locale:
28  
-            basedir = os.path.join(basedir, locale, 'LC_MESSAGES')
29  
-        for dirpath, dirnames, filenames in os.walk(basedir):
30  
-            for f in filenames:
31  
-                if f.endswith('.po'):
32  
-                    stderr.write('processing file %s in %s\n' % (f, dirpath))
33  
-                    fn = os.path.join(dirpath, f)
34  
-                    if has_bom(fn):
35  
-                        raise CommandError("The %s file has a BOM (Byte Order Mark). Django only supports .po files encoded in UTF-8 and without any BOM." % fn)
36  
-                    pf = os.path.splitext(fn)[0]
37  
-                    # Store the names of the .mo and .po files in an environment
38  
-                    # variable, rather than doing a string replacement into the
39  
-                    # command, so that we can take advantage of shell quoting, to
40  
-                    # quote any malicious characters/escaping.
41  
-                    # See http://cyberelk.net/tim/articles/cmdline/ar01s02.html
42  
-                    os.environ['djangocompilemo'] = pf + '.mo'
43  
-                    os.environ['djangocompilepo'] = pf + '.po'
44  
-                    if sys.platform == 'win32': # Different shell-variable syntax
45  
-                        cmd = 'msgfmt --check-format -o "%djangocompilemo%" "%djangocompilepo%"'
46  
-                    else:
47  
-                        cmd = 'msgfmt --check-format -o "$djangocompilemo" "$djangocompilepo"'
48  
-                    os.system(cmd)
  29
+            dirs = [os.path.join(basedir, l, 'LC_MESSAGES') for l in (locale if isinstance(locale, list) else [locale])]
  30
+            
  31
+        
  32
+        for dir in dirs:
  33
+            for dirpath, dirnames, filenames in os.walk(dir):
  34
+                for f in filenames:
  35
+                    if f.endswith('.po'):
  36
+                        stderr.write('processing file %s in %s\n' % (f, dirpath))
  37
+                        fn = os.path.join(dirpath, f)
  38
+                        if has_bom(fn):
  39
+                            raise CommandError("The %s file has a BOM (Byte Order Mark). Django only supports .po files encoded in UTF-8 and without any BOM." % fn)
  40
+                        pf = os.path.splitext(fn)[0]
  41
+                        # Store the names of the .mo and .po files in an environment
  42
+                        # variable, rather than doing a string replacement into the
  43
+                        # command, so that we can take advantage of shell quoting, to
  44
+                        # quote any malicious characters/escaping.
  45
+                        # See http://cyberelk.net/tim/articles/cmdline/ar01s02.html
  46
+                        os.environ['djangocompilemo'] = pf + '.mo'
  47
+                        os.environ['djangocompilepo'] = pf + '.po'
  48
+                        if sys.platform == 'win32': # Different shell-variable syntax
  49
+                            cmd = 'msgfmt --check-format -o "%djangocompilemo%" "%djangocompilepo%"'
  50
+                        else:
  51
+                            cmd = 'msgfmt --check-format -o "$djangocompilemo" "$djangocompilepo"'
  52
+                        os.system(cmd)
49 53
 
50 54
 
51 55
 class Command(BaseCommand):
52 56
     option_list = BaseCommand.option_list + (
53  
-        make_option('--locale', '-l', dest='locale',
54  
-            help='The locale to process. Default is to process all.'),
  57
+        make_option('--locale', '-l', dest='locale', action="append",
  58
+            help='A locale to process. Default is to process all.'),
55 59
     )
56 60
     help = 'Compiles .po files to .mo files for use with builtin gettext support.'
57 61
 
52  django/core/management/commands/makemessages.py
@@ -248,7 +248,7 @@ def write_po_file(pofile, potfile, domain, locale, verbosity, stdout,
248 248
             raise CommandError(
249 249
                 "errors happened while running msgattrib\n%s" % errors)
250 250
 
251  
-def make_messages(locale=None, domain='django', verbosity=1, all=False,
  251
+def make_messages(locale=None, domain=None, verbosity=1, all=False,
252 252
         extensions=None, symlinks=False, ignore_patterns=None, no_wrap=False,
253 253
         no_location=False, no_obsolete=False, stdout=sys.stdout):
254 254
     """
@@ -283,10 +283,15 @@ def make_messages(locale=None, domain='django', verbosity=1, all=False,
283 283
                 "is not created automatically, you have to create it by hand "
284 284
                 "if you want to enable i18n for your project or application.")
285 285
 
286  
-    if domain not in ('django', 'djangojs'):
  286
+    if domain is None:
  287
+        domains = ['django']
  288
+    else:
  289
+        domains = [domain] if not isinstance(domain, list) else domain
  290
+
  291
+    if any(d not in ('django', 'djangojs') for d in domains):
287 292
         raise CommandError("currently makemessages only supports domains 'django' and 'djangojs'")
288 293
 
289  
-    if (locale is None and not all) or domain is None:
  294
+    if (locale is None and not all) or not domains:
290 295
         message = "Type '%s help %s' for usage information." % (os.path.basename(sys.argv[0]), sys.argv[1])
291 296
         raise CommandError(message)
292 297
 
@@ -302,7 +307,7 @@ def make_messages(locale=None, domain='django', verbosity=1, all=False,
302 307
 
303 308
     locales = []
304 309
     if locale is not None:
305  
-        locales.append(locale)
  310
+        locales += locale.split(',') if not isinstance(locale, list) else locale
306 311
     elif all:
307 312
         locale_dirs = filter(os.path.isdir, glob.glob('%s/*' % localedir))
308 313
         locales = [os.path.basename(l) for l in locale_dirs]
@@ -317,28 +322,31 @@ def make_messages(locale=None, domain='django', verbosity=1, all=False,
317 322
         if not os.path.isdir(basedir):
318 323
             os.makedirs(basedir)
319 324
 
320  
-        pofile = os.path.join(basedir, '%s.po' % domain)
321  
-        potfile = os.path.join(basedir, '%s.pot' % domain)
322  
-
323  
-        if os.path.exists(potfile):
324  
-            os.unlink(potfile)
325  
-
326  
-        for dirpath, file in find_files(".", ignore_patterns, verbosity,
327  
-                stdout, symlinks=symlinks):
328  
-            process_file(file, dirpath, potfile, domain, verbosity, extensions,
329  
-                    wrap, location, stdout)
330  
-
331  
-        if os.path.exists(potfile):
332  
-            write_po_file(pofile, potfile, domain, locale, verbosity, stdout,
333  
-                    not invoked_for_django, wrap, location, no_obsolete)
  325
+        for domain in domains:
  326
+            if verbosity > 1:
  327
+                stdout.write("processing domain %s\n" % domain)
  328
+            pofile = os.path.join(basedir, '%s.po' % domain)
  329
+            potfile = os.path.join(basedir, '%s.pot' % domain)
  330
+    
  331
+            if os.path.exists(potfile):
  332
+                os.unlink(potfile)
  333
+    
  334
+            for dirpath, file in find_files(".", ignore_patterns, verbosity,
  335
+                    stdout, symlinks=symlinks):
  336
+                process_file(file, dirpath, potfile, domain, verbosity, extensions,
  337
+                        wrap, location, stdout)
  338
+    
  339
+            if os.path.exists(potfile):
  340
+                write_po_file(pofile, potfile, domain, locale, verbosity, stdout,
  341
+                        not invoked_for_django, wrap, location, no_obsolete)
334 342
 
335 343
 
336 344
 class Command(NoArgsCommand):
337 345
     option_list = NoArgsCommand.option_list + (
338  
-        make_option('--locale', '-l', default=None, dest='locale',
339  
-            help='Creates or updates the message files for the given locale (e.g. pt_BR).'),
340  
-        make_option('--domain', '-d', default='django', dest='domain',
341  
-            help='The domain of the message files (default: "django").'),
  346
+        make_option('--locale', '-l', default=None, dest='locale', action='append',
  347
+            help='Creates or updates the message files for the given locale(s) (e.g. pt_BR).'),
  348
+        make_option('--domain', '-d', default=None, dest='domain', action='append',
  349
+            help='The domain(s) of the message files (default: "django").'),
342 350
         make_option('--all', '-a', action='store_true', dest='all',
343 351
             default=False, help='Updates the message files for all existing locales.'),
344 352
         make_option('--extension', '-e', dest='extensions',
19  docs/ref/django-admin.txt
@@ -104,12 +104,12 @@ compilemessages
104 104
 Compiles .po files created with ``makemessages`` to .mo files for use with
105 105
 the builtin gettext support. See :doc:`/topics/i18n/index`.
106 106
 
107  
-Use the :djadminopt:`--locale` option to specify the locale to process.
  107
+Use the :djadminopt:`--locale` option to specify the locale(s) to process.
108 108
 If not provided, all locales are processed.
109 109
 
110 110
 Example usage::
111 111
 
112  
-    django-admin.py compilemessages --locale=br_PT
  112
+    django-admin.py compilemessages --locale=pt_BR --locale=fr
113 113
 
114 114
 createcachetable
115 115
 ----------------
@@ -422,11 +422,16 @@ Separate multiple extensions with commas or use -e or --extension multiple times
422 422
 
423 423
     django-admin.py makemessages --locale=de --extension=html,txt --extension xml
424 424
 
425  
-Use the :djadminopt:`--locale` option to specify the locale to process.
  425
+Use the :djadminopt:`--locale` option to specify the locale(s) to process.
426 426
 
427 427
 Example usage::
428 428
 
429  
-    django-admin.py makemessages --locale=br_PT
  429
+    django-admin.py makemessages --locale=pt_BR --locale=fr
  430
+    
  431
+You can also use commas to separate multiple locales::
  432
+
  433
+    django-admin.py makemessages --locale=de,fr,pt_BR
  434
+
430 435
 
431 436
 .. django-admin-option:: --domain
432 437
 
@@ -436,6 +441,12 @@ Currently supported:
436 441
 * ``django`` for all ``*.py``, ``*.html`` and ``*.txt`` files (default)
437 442
 * ``djangojs`` for ``*.js`` files
438 443
 
  444
+
  445
+Example usage::
  446
+
  447
+    django-admin.py makemessages --domain=django --domain=djangojs
  448
+    
  449
+    
439 450
 .. django-admin-option:: --symlinks
440 451
 
441 452
 Use the ``--symlinks`` or ``-s`` option to follow symlinks to directories when
42  tests/regressiontests/i18n/commands/compilemessages.py
... ...
@@ -0,0 +1,42 @@
  1
+from StringIO import StringIO
  2
+from django.test import TestCase
  3
+import os
  4
+from django.core.management.commands import compilemessages
  5
+from django.conf import settings
  6
+
  7
+class CompileMessagesFunctionTestCase(TestCase):
  8
+    MO_FILE_DE = None
  9
+    MO_FILE_FR = None
  10
+    
  11
+    def setUp(self):
  12
+        self._old_locale_paths = settings.LOCALE_PATHS
  13
+        self.stderr = StringIO()
  14
+        self.localedir = os.path.join(
  15
+            os.path.dirname(os.path.abspath(__file__)), 'locale'
  16
+        )
  17
+        settings.LOCALE_PATHS = [self.localedir]
  18
+        self.MO_FILE_DE = os.path.join(self.localedir, 'de/LC_MESSAGES/django.mo')
  19
+        self.MO_FILE_FR = os.path.join(self.localedir, 'fr/LC_MESSAGES/django.mo')
  20
+        
  21
+    def tearDown(self):
  22
+        settings.LOCALE_PATHS = self._old_locale_paths
  23
+        self.stderr.close()
  24
+        self._rmfile(os.path.join(self.localedir, self.MO_FILE_DE))
  25
+        self._rmfile(os.path.join(self.localedir, self.MO_FILE_FR))
  26
+        
  27
+    def _rmfile(self, filepath):
  28
+        if os.path.exists(filepath):
  29
+            os.remove(filepath)
  30
+            
  31
+    def test_one_locale(self):
  32
+        command = compilemessages.Command()
  33
+        command.execute(locale='de', stderr=self.stderr)
  34
+        
  35
+        self.assertTrue(os.path.exists(self.MO_FILE_DE))
  36
+        
  37
+    def test_multiple_locales(self):
  38
+        command = compilemessages.Command()
  39
+        command.execute(locale=['de', 'fr'], stderr=self.stderr)
  40
+        
  41
+        self.assertTrue(os.path.exists(self.MO_FILE_DE))
  42
+        self.assertTrue(os.path.exists(self.MO_FILE_FR))
30  tests/regressiontests/i18n/commands/makemessages.py
... ...
@@ -0,0 +1,30 @@
  1
+import os
  2
+from .extraction import ExtractorTests
  3
+from django.core import management
  4
+
  5
+class MakeMessagesFunctionTestCase(ExtractorTests):
  6
+    PO_FILE_PT = 'locale/pt/LC_MESSAGES/django.po'
  7
+    PO_FILE_DE = 'locale/de/LC_MESSAGES/django.po'
  8
+    LOCALES = ['pt', 'de', 'ch']
  9
+    
  10
+    
  11
+    def tearDown(self):
  12
+        os.chdir(self.test_dir)
  13
+        for locale in self.LOCALES:
  14
+            try:
  15
+                self._rmrf('locale/%s' % locale)
  16
+            except OSError:
  17
+                pass
  18
+        os.chdir(self._cwd)
  19
+    
  20
+    def test_multiple_locales(self):
  21
+        os.chdir(self.test_dir)
  22
+        management.call_command('makemessages', locale=['pt','de'], verbosity=0)
  23
+        self.assertTrue(os.path.exists(self.PO_FILE_PT))
  24
+        self.assertTrue(os.path.exists(self.PO_FILE_DE))
  25
+    
  26
+    def test_comma_separated_locales(self):
  27
+        os.chdir(self.test_dir)
  28
+        management.call_command('makemessages', locale='pt,de,ch', verbosity=0)
  29
+        self.assertTrue(os.path.exists(self.PO_FILE_PT))
  30
+        self.assertTrue(os.path.exists(self.PO_FILE_DE))
2  tests/regressiontests/i18n/tests.py
@@ -30,9 +30,11 @@
30 30
         JavascriptExtractorTests, IgnoredExtractorTests, SymlinkExtractorTests,
31 31
         CopyPluralFormsExtractorTests, NoWrapExtractorTests,
32 32
         NoLocationExtractorTests)
  33
+    from .commands.makemessages import MakeMessagesFunctionTestCase
33 34
 if can_run_compilation_tests:
34 35
     from .commands.compilation import (PoFileTests, PoFileContentsTests,
35 36
         PercentRenderingTests)
  37
+    from .commands.compilemessages import CompileMessagesFunctionTestCase
36 38
 from .contenttypes.tests import ContentTypeTests
37 39
 from .forms import I18nForm, SelectDateForm, SelectDateWidget, CompanyForm
38 40
 from .models import Company, TestModel

0 notes on commit 4fbb940

Please sign in to comment.
Something went wrong with that request. Please try again.