Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Revert "Patch by Claude for #16084."

This reverts commit 2babab0.
  • Loading branch information...
commit ce27fb198dcce5dad47de83fc81119d3bb6567ce 1 parent 5b99d5a
Ramiro Morales authored January 25, 2013
139  django/core/management/commands/makemessages.py
@@ -19,28 +19,25 @@
19 19
 
20 20
 @total_ordering
21 21
 class TranslatableFile(object):
22  
-    def __init__(self, dirpath, file_name, locale_dir):
  22
+    def __init__(self, dirpath, file_name):
23 23
         self.file = file_name
24 24
         self.dirpath = dirpath
25  
-        self.locale_dir = locale_dir
26 25
 
27 26
     def __repr__(self):
28 27
         return "<TranslatableFile: %s>" % os.sep.join([self.dirpath, self.file])
29 28
 
30 29
     def __eq__(self, other):
31  
-        return self.path == other.path
  30
+        return self.dirpath == other.dirpath and self.file == other.file
32 31
 
33 32
     def __lt__(self, other):
34  
-        return self.path < other.path
  33
+        if self.dirpath == other.dirpath:
  34
+            return self.file < other.file
  35
+        return self.dirpath < other.dirpath
35 36
 
36  
-    @property
37  
-    def path(self):
38  
-        return os.path.join(self.dirpath, self.file)
39  
-
40  
-    def process(self, command, domain):
  37
+    def process(self, command, potfile, domain, keep_pot=False):
41 38
         """
42  
-        Extract translatable literals from self.file for :param domain:,
43  
-        creating or updating the POT file.
  39
+        Extract translatable literals from self.file for :param domain:
  40
+        creating or updating the :param potfile: POT file.
44 41
 
45 42
         Uses the xgettext GNU gettext utility.
46 43
         """
@@ -94,6 +91,8 @@ def process(self, command, domain):
94 91
             if status != STATUS_OK:
95 92
                 if is_templatized:
96 93
                     os.unlink(work_file)
  94
+                if not keep_pot and os.path.exists(potfile):
  95
+                    os.unlink(potfile)
97 96
                 raise CommandError(
98 97
                     "errors happened while running xgettext on %s\n%s" %
99 98
                     (self.file, errors))
@@ -101,14 +100,11 @@ def process(self, command, domain):
101 100
                 # Print warnings
102 101
                 command.stdout.write(errors)
103 102
         if msgs:
104  
-            # Write/append messages to pot file
105  
-            potfile = os.path.join(self.locale_dir, '%s.pot' % str(domain))
106 103
             if is_templatized:
107 104
                 old = '#: ' + work_file[2:]
108 105
                 new = '#: ' + orig_file[2:]
109 106
                 msgs = msgs.replace(old, new)
110 107
             write_pot_file(potfile, msgs)
111  
-
112 108
         if is_templatized:
113 109
             os.unlink(work_file)
114 110
 
@@ -236,21 +232,21 @@ def handle_noargs(self, *args, **options):
236 232
             settings.configure(USE_I18N = True)
237 233
 
238 234
         self.invoked_for_django = False
239  
-        self.locale_paths = []
240  
-        self.default_locale_path = None
241 235
         if os.path.isdir(os.path.join('conf', 'locale')):
242  
-            self.locale_paths = [os.path.abspath(os.path.join('conf', 'locale'))]
243  
-            self.default_locale_path = self.locale_paths[0]
  236
+            localedir = os.path.abspath(os.path.join('conf', 'locale'))
244 237
             self.invoked_for_django = True
245 238
             # Ignoring all contrib apps
246 239
             self.ignore_patterns += ['contrib/*']
  240
+        elif os.path.isdir('locale'):
  241
+            localedir = os.path.abspath('locale')
247 242
         else:
248  
-            self.locale_paths.extend(list(settings.LOCALE_PATHS))
249  
-            # Allow to run makemessages inside an app dir
250  
-            if os.path.isdir('locale'):
251  
-                self.locale_paths.append(os.path.abspath('locale'))
252  
-            if self.locale_paths:
253  
-                self.default_locale_path = self.locale_paths[0]
  243
+            raise CommandError("This script should be run from the Django Git "
  244
+                    "tree or your project or app tree. If you did indeed run it "
  245
+                    "from the Git checkout or your project or application, "
  246
+                    "maybe you are just missing the conf/locale (in the django "
  247
+                    "tree) or locale (for project and application) directory? It "
  248
+                    "is not created automatically, you have to create it by hand "
  249
+                    "if you want to enable i18n for your project or application.")
254 250
 
255 251
         # We require gettext version 0.15 or newer.
256 252
         output, errors, status = _popen('xgettext --version')
@@ -265,25 +261,24 @@ def handle_noargs(self, *args, **options):
265 261
                         "gettext 0.15 or newer. You are using version %s, please "
266 262
                         "upgrade your gettext toolset." % match.group())
267 263
 
268  
-        try:
269  
-            potfiles = self.build_potfiles()
  264
+        potfile = self.build_pot_file(localedir)
270 265
 
271  
-            # Build po files for each selected locale
272  
-            locales = []
273  
-            if locale is not None:
274  
-                locales = locale.split(',') if not isinstance(locale, list) else locale
275  
-            elif process_all:
276  
-                locale_dirs = filter(os.path.isdir, glob.glob('%s/*' % self.default_locale_path))
277  
-                locales = [os.path.basename(l) for l in locale_dirs]
  266
+        # Build po files for each selected locale
  267
+        locales = []
  268
+        if locale is not None:
  269
+            locales += locale.split(',') if not isinstance(locale, list) else locale
  270
+        elif process_all:
  271
+            locale_dirs = filter(os.path.isdir, glob.glob('%s/*' % localedir))
  272
+            locales = [os.path.basename(l) for l in locale_dirs]
278 273
 
  274
+        try:
279 275
             for locale in locales:
280 276
                 if self.verbosity > 0:
281 277
                     self.stdout.write("processing locale %s\n" % locale)
282  
-                for potfile in potfiles:
283  
-                    self.write_po_file(potfile, locale)
  278
+                self.write_po_file(potfile, locale)
284 279
         finally:
285  
-            if not self.keep_pot:
286  
-                self.remove_potfiles()
  280
+            if not self.keep_pot and os.path.exists(potfile):
  281
+                os.unlink(potfile)
287 282
 
288 283
     def build_pot_file(self, localedir):
289 284
         file_list = self.find_files(".")
@@ -297,41 +292,9 @@ def build_pot_file(self, localedir):
297 292
             f.process(self, potfile, self.domain, self.keep_pot)
298 293
         return potfile
299 294
 
300  
-    def build_potfiles(self):
301  
-        """Build pot files and apply msguniq to them"""
302  
-        file_list = self.find_files(".")
303  
-        self.remove_potfiles()
304  
-        for f in file_list:
305  
-            f.process(self, self.domain)
306  
-
307  
-        potfiles = []
308  
-        for path in self.locale_paths:
309  
-            potfile = os.path.join(path, '%s.pot' % str(self.domain))
310  
-            if not os.path.exists(potfile):
311  
-                continue
312  
-            msgs, errors, status = _popen('msguniq %s %s --to-code=utf-8 "%s"' %
313  
-                                    (self.wrap, self.location, potfile))
314  
-            if errors:
315  
-                if status != STATUS_OK:
316  
-                    raise CommandError(
317  
-                        "errors happened while running msguniq\n%s" % errors)
318  
-                elif self.verbosity > 0:
319  
-                    self.stdout.write(errors)
320  
-            with open(potfile, 'w') as fp:
321  
-                fp.write(msgs)
322  
-            potfiles.append(potfile)
323  
-        return potfiles
324  
-
325  
-    def remove_potfiles(self):
326  
-        for path in self.locale_paths:
327  
-            pot_path = os.path.join(path, '%s.pot' % str(self.domain))
328  
-            if os.path.exists(pot_path):
329  
-                os.unlink(pot_path)
330  
-
331 295
     def find_files(self, root):
332 296
         """
333  
-        Helper function to get all files in the given root. Also check that there
334  
-        is a matching locale dir for each file.
  297
+        Helper method to get all files in the given root.
335 298
         """
336 299
 
337 300
         def is_ignored(path, ignore_patterns):
@@ -352,26 +315,12 @@ def is_ignored(path, ignore_patterns):
352 315
                     dirnames.remove(dirname)
353 316
                     if self.verbosity > 1:
354 317
                         self.stdout.write('ignoring directory %s\n' % dirname)
355  
-                elif dirname == 'locale':
356  
-                    dirnames.remove(dirname)
357  
-                    self.locale_paths.insert(0, os.path.join(os.path.abspath(dirpath), dirname))
358 318
             for filename in filenames:
359  
-                file_path = os.path.normpath(os.path.join(dirpath, filename))
360  
-                if is_ignored(file_path, self.ignore_patterns):
  319
+                if is_ignored(os.path.normpath(os.path.join(dirpath, filename)), self.ignore_patterns):
361 320
                     if self.verbosity > 1:
362 321
                         self.stdout.write('ignoring file %s in %s\n' % (filename, dirpath))
363 322
                 else:
364  
-                    locale_dir = None
365  
-                    for path in self.locale_paths:
366  
-                        if os.path.abspath(dirpath).startswith(os.path.dirname(path)):
367  
-                            locale_dir = path
368  
-                            break
369  
-                    if not locale_dir:
370  
-                        locale_dir = self.default_locale_path
371  
-                    if not locale_dir:
372  
-                        raise CommandError(
373  
-                            "Unable to find a locale path to store translations for file %s" % file_path)
374  
-                    all_files.append(TranslatableFile(dirpath, filename, locale_dir))
  323
+                    all_files.append(TranslatableFile(dirpath, filename))
375 324
         return sorted(all_files)
376 325
 
377 326
     def write_po_file(self, potfile, locale):
@@ -379,8 +328,16 @@ def write_po_file(self, potfile, locale):
379 328
         Creates or updates the PO file for self.domain and :param locale:.
380 329
         Uses contents of the existing :param potfile:.
381 330
 
382  
-        Uses msgmerge, and msgattrib GNU gettext utilities.
  331
+        Uses mguniq, msgmerge, and msgattrib GNU gettext utilities.
383 332
         """
  333
+        msgs, errors, status = _popen('msguniq %s %s --to-code=utf-8 "%s"' %
  334
+                                        (self.wrap, self.location, potfile))
  335
+        if errors:
  336
+            if status != STATUS_OK:
  337
+                raise CommandError(
  338
+                    "errors happened while running msguniq\n%s" % errors)
  339
+            elif self.verbosity > 0:
  340
+                self.stdout.write(errors)
384 341
 
385 342
         basedir = os.path.join(os.path.dirname(potfile), locale, 'LC_MESSAGES')
386 343
         if not os.path.isdir(basedir):
@@ -388,6 +345,8 @@ def write_po_file(self, potfile, locale):
388 345
         pofile = os.path.join(basedir, '%s.po' % str(self.domain))
389 346
 
390 347
         if os.path.exists(pofile):
  348
+            with open(potfile, 'w') as fp:
  349
+                fp.write(msgs)
391 350
             msgs, errors, status = _popen('msgmerge %s %s -q "%s" "%s"' %
392 351
                                             (self.wrap, self.location, pofile, potfile))
393 352
             if errors:
@@ -396,10 +355,8 @@ def write_po_file(self, potfile, locale):
396 355
                         "errors happened while running msgmerge\n%s" % errors)
397 356
                 elif self.verbosity > 0:
398 357
                     self.stdout.write(errors)
399  
-        else:
400  
-            msgs = open(potfile, 'r').read()
401  
-            if not self.invoked_for_django:
402  
-                msgs = self.copy_plural_forms(msgs, locale)
  358
+        elif not self.invoked_for_django:
  359
+            msgs = self.copy_plural_forms(msgs, locale)
403 360
         msgs = msgs.replace(
404 361
             "#. #-#-#-#-#  %s.pot (PACKAGE VERSION)  #-#-#-#-#\n" % self.domain, "")
405 362
         with open(pofile, 'w') as fp:
3  docs/man/django-admin.1
@@ -193,8 +193,7 @@ Ignore files or directories matching this glob-style pattern. Use multiple
193 193
 times to ignore more (makemessages command).
194 194
 .TP
195 195
 .I \-\-no\-default\-ignore
196  
-Don't ignore the common private glob-style patterns 'CVS', '.*', '*~' and '*.pyc'
197  
-(makemessages command).
  196
+Don't ignore the common private glob-style patterns 'CVS', '.*' and '*~' (makemessages command).
198 197
 .TP
199 198
 .I \-\-no\-wrap
200 199
 Don't break long message lines into several lines (makemessages command).
4  docs/ref/django-admin.txt
@@ -472,7 +472,7 @@ Example usage::
472 472
 Use the ``--ignore`` or ``-i`` option to ignore files or directories matching
473 473
 the given :mod:`glob`-style pattern. Use multiple times to ignore more.
474 474
 
475  
-These patterns are used by default: ``'CVS'``, ``'.*'``, ``'*~'``, ``'*.pyc'``
  475
+These patterns are used by default: ``'CVS'``, ``'.*'``, ``'*~'``
476 476
 
477 477
 Example usage::
478 478
 
@@ -499,7 +499,7 @@ for technically skilled translators to understand each message's context.
499 499
 .. versionadded:: 1.6
500 500
 
501 501
 Use the ``--keep-pot`` option to prevent django from deleting the temporary
502  
-.pot files it generates before creating the .po file. This is useful for
  502
+.pot file it generates before creating the .po file. This is useful for
503 503
 debugging errors which may prevent the final language files from being created.
504 504
 
505 505
 runfcgi [options]
17  docs/topics/i18n/translation.txt
@@ -1543,9 +1543,24 @@ All message file repositories are structured the same way. They are:
1543 1543
 * ``$PYTHONPATH/django/conf/locale/<language>/LC_MESSAGES/django.(po|mo)``
1544 1544
 
1545 1545
 To create message files, you use the :djadmin:`django-admin.py makemessages <makemessages>`
1546  
-tool. And you use :djadmin:`django-admin.py compilemessages <compilemessages>`
  1546
+tool. You only need to be in the same directory where the ``locale/`` directory
  1547
+is located. And you use :djadmin:`django-admin.py compilemessages <compilemessages>`
1547 1548
 to produce the binary ``.mo`` files that are used by ``gettext``.
1548 1549
 
1549 1550
 You can also run :djadmin:`django-admin.py compilemessages
1550 1551
 --settings=path.to.settings <compilemessages>` to make the compiler process all
1551 1552
 the directories in your :setting:`LOCALE_PATHS` setting.
  1553
+
  1554
+Finally, you should give some thought to the structure of your translation
  1555
+files. If your applications need to be delivered to other users and will be used
  1556
+in other projects, you might want to use app-specific translations. But using
  1557
+app-specific translations and project-specific translations could produce weird
  1558
+problems with :djadmin:`makemessages`: it will traverse all directories below
  1559
+the current path and so might put message IDs into a unified, common message
  1560
+file for the current project that are already in application message files.
  1561
+
  1562
+The easiest way out is to store applications that are not part of the project
  1563
+(and so carry their own translations) outside the project tree. That way,
  1564
+:djadmin:`django-admin.py makemessages <makemessages>`, when ran on a project
  1565
+level will only extract strings that are connected to your explicit project and
  1566
+not strings that are distributed independently.
44  tests/regressiontests/i18n/commands/extraction.py
@@ -5,13 +5,10 @@
5 5
 import re
6 6
 import shutil
7 7
 
8  
-from django.conf import settings
9 8
 from django.core import management
10 9
 from django.test import SimpleTestCase
11  
-from django.test.utils import override_settings
12 10
 from django.utils.encoding import force_text
13 11
 from django.utils._os import upath
14  
-from django.utils import six
15 12
 from django.utils.six import StringIO
16 13
 
17 14
 
@@ -355,44 +352,3 @@ def test_comma_separated_locales(self):
355 352
         management.call_command('makemessages', locale='pt,de,ch', verbosity=0)
356 353
         self.assertTrue(os.path.exists(self.PO_FILE_PT))
357 354
         self.assertTrue(os.path.exists(self.PO_FILE_DE))
358  
-
359  
-
360  
-class CustomLayoutExtractionTests(ExtractorTests):
361  
-    def setUp(self):
362  
-        self._cwd = os.getcwd()
363  
-        self.test_dir = os.path.join(os.path.dirname(upath(__file__)), 'project_dir')
364  
-
365  
-    def test_no_locale_raises(self):
366  
-        os.chdir(self.test_dir)
367  
-        with six.assertRaisesRegex(self, management.CommandError,
368  
-                "Unable to find a locale path to store translations for file"):
369  
-            management.call_command('makemessages', locale=LOCALE, verbosity=0)
370  
-
371  
-    @override_settings(
372  
-        LOCALE_PATHS=(os.path.join(os.path.dirname(upath(__file__)), 'project_dir/project_locale'),)
373  
-    )
374  
-    def test_project_locale_paths(self):
375  
-        """
376  
-        Test that:
377  
-          * translations for app containing locale folder are stored in that folder
378  
-          * translations outside of that app are in LOCALE_PATHS[0]
379  
-        """
380  
-        os.chdir(self.test_dir)
381  
-        self.addCleanup(shutil.rmtree, os.path.join(settings.LOCALE_PATHS[0], LOCALE))
382  
-        self.addCleanup(shutil.rmtree, os.path.join(self.test_dir, 'app_with_locale/locale', LOCALE))
383  
-
384  
-        management.call_command('makemessages', locale=LOCALE, verbosity=0)
385  
-        project_de_locale = os.path.join(
386  
-            self.test_dir, 'project_locale/de/LC_MESSAGES/django.po',)
387  
-        app_de_locale = os.path.join(
388  
-            self.test_dir, 'app_with_locale/locale/de/LC_MESSAGES/django.po',)
389  
-        self.assertTrue(os.path.exists(project_de_locale))
390  
-        self.assertTrue(os.path.exists(app_de_locale))
391  
-
392  
-        with open(project_de_locale, 'r') as fp:
393  
-            po_contents = force_text(fp.read())
394  
-            self.assertMsgId('This app has no locale directory', po_contents)
395  
-            self.assertMsgId('This is a project-level string', po_contents)
396  
-        with open(app_de_locale, 'r') as fp:
397  
-            po_contents = force_text(fp.read())
398  
-            self.assertMsgId('This app has a locale directory', po_contents)
3  tests/regressiontests/i18n/commands/project_dir/__init__.py
... ...
@@ -1,3 +0,0 @@
1  
-from django.utils.translation import ugettext as _
2  
-
3  
-string = _("This is a project-level string")
4  tests/regressiontests/i18n/commands/project_dir/app_no_locale/models.py
... ...
@@ -1,4 +0,0 @@
1  
-from django.utils.translation import ugettext as _
2  
-
3  
-string = _("This app has no locale directory")
4  
-
4  tests/regressiontests/i18n/commands/project_dir/app_with_locale/models.py
... ...
@@ -1,4 +0,0 @@
1  
-from django.utils.translation import ugettext as _
2  
-
3  
-string = _("This app has a locale directory")
4  
-
2  tests/regressiontests/i18n/tests.py
@@ -33,7 +33,7 @@
33 33
         JavascriptExtractorTests, IgnoredExtractorTests, SymlinkExtractorTests,
34 34
         CopyPluralFormsExtractorTests, NoWrapExtractorTests,
35 35
         NoLocationExtractorTests, KeepPotFileExtractorTests,
36  
-        MultipleLocaleExtractionTests, CustomLayoutExtractionTests)
  36
+        MultipleLocaleExtractionTests)
37 37
 if can_run_compilation_tests:
38 38
     from .commands.compilation import (PoFileTests, PoFileContentsTests,
39 39
         PercentRenderingTests, MultipleLocaleCompilationTests)

0 notes on commit ce27fb1

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