Code

Ticket #17008: 17008.makemessages-keep-pot.2.diff

File 17008.makemessages-keep-pot.2.diff, 13.2 KB (added by ramiro, 2 years ago)

Patch from Julien updated to changes that happened in makemessages code

Line 
1diff --git a/django/core/management/commands/makemessages.py b/django/core/management/commands/makemessages.py
2--- a/django/core/management/commands/makemessages.py
3+++ b/django/core/management/commands/makemessages.py
4@@ -11,7 +11,8 @@
5 from django.utils.text import get_text_list
6 from django.utils.jslex import prepare_js_for_gettext
7 
8-plural_forms_re = re.compile(r'^(?P<value>"Plural-Forms.+?\\n")\s*$', re.MULTILINE | re.DOTALL)
9+plural_forms_re = re.compile(
10+    r'^(?P<value>"Plural-Forms.+?\\n")\s*$', re.MULTILINE | re.DOTALL)
11 
12 def handle_extensions(extensions=('html',), ignored=('py',)):
13     """
14@@ -41,7 +42,8 @@
15     """
16     Friendly wrapper around Popen for Windows
17     """
18-    p = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE, close_fds=os.name != 'nt', universal_newlines=True)
19+    p = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE,
20+              close_fds=os.name != 'nt', universal_newlines=True)
21     return p.communicate()
22 
23 def walk(root, topdown=True, onerror=None, followlinks=False):
24@@ -95,12 +97,14 @@
25     else:
26         domains = ('django',)
27     for domain in domains:
28-        django_po = os.path.join(django_dir, 'conf', 'locale', locale, 'LC_MESSAGES', '%s.po' % domain)
29+        django_po = os.path.join(django_dir, 'conf', 'locale', locale,
30+                                 'LC_MESSAGES', '%s.po' % domain)
31         if os.path.exists(django_po):
32             m = plural_forms_re.search(open(django_po, 'rU').read())
33             if m:
34                 if verbosity > 1:
35-                    sys.stderr.write("copying plural forms: %s\n" % m.group('value'))
36+                    sys.stderr.write(
37+                        "copying plural forms: %s\n" % m.group('value'))
38                 lines = []
39                 seen = False
40                 for line in msgs.split('\n'):
41@@ -133,7 +137,7 @@
42         f.close()
43 
44 def process_file(file, dirpath, potfile, domain, verbosity, extensions, wrap,
45-        location):
46+        location, keep_pot):
47     """
48     Extract translatable literals from :param file: for :param domain:
49     creating or updating the :param potfile: POT file.
50@@ -196,7 +200,7 @@
51     if errors:
52         if is_templatized:
53             os.unlink(work_file)
54-        if os.path.exists(potfile):
55+        if not keep_pot and os.path.exists(potfile):
56             os.unlink(potfile)
57         raise CommandError(
58             "errors happened while running xgettext on %s\n%s" %
59@@ -207,7 +211,7 @@
60         os.unlink(work_file)
61 
62 def write_po_file(pofile, potfile, domain, locale, verbosity,
63-        copy_pforms, wrap, location, no_obsolete):
64+        copy_pforms, wrap, location, no_obsolete, keep_pot):
65     """
66     Creates of updates the :param pofile: PO file for :param domain: and :param
67     locale:.  Uses contents of the existing :param potfile:.
68@@ -217,7 +221,8 @@
69     msgs, errors = _popen('msguniq %s %s --to-code=utf-8 "%s"' %
70                             (wrap, location, potfile))
71     if errors:
72-        os.unlink(potfile)
73+        if not keep_pot:
74+            os.unlink(potfile)
75         raise CommandError("errors happened while running msguniq\n%s" % errors)
76     if os.path.exists(pofile):
77         f = open(potfile, 'w')
78@@ -228,7 +233,8 @@
79         msgs, errors = _popen('msgmerge %s %s -q "%s" "%s"' %
80                                 (wrap, location, pofile, potfile))
81         if errors:
82-            os.unlink(potfile)
83+            if not keep_pot:
84+                os.unlink(potfile)
85             raise CommandError(
86                 "errors happened while running msgmerge\n%s" % errors)
87     elif copy_pforms:
88@@ -240,7 +246,8 @@
89         f.write(msgs)
90     finally:
91         f.close()
92-    os.unlink(potfile)
93+    if not keep_pot:
94+        os.unlink(potfile)
95     if no_obsolete:
96         msgs, errors = _popen('msgattrib %s %s -o "%s" --no-obsolete "%s"' %
97                                 (wrap, location, pofile, pofile))
98@@ -250,7 +257,7 @@
99 
100 def make_messages(locale=None, domain='django', verbosity=1, all=False,
101         extensions=None, symlinks=False, ignore_patterns=None, no_wrap=False,
102-        no_location=False, no_obsolete=False):
103+        no_location=False, no_obsolete=False, keep_pot=False):
104     """
105     Uses the ``locale/`` directory from the Django SVN tree or an
106     application/project to process all files with translatable literals for
107@@ -284,10 +291,12 @@
108                 "if you want to enable i18n for your project or application.")
109 
110     if domain not in ('django', 'djangojs'):
111-        raise CommandError("currently makemessages only supports domains 'django' and 'djangojs'")
112+        raise CommandError("currently makemessages only supports domains "
113+                           "'django' and 'djangojs'")
114 
115     if (locale is None and not all) or domain is None:
116-        message = "Type '%s help %s' for usage information." % (os.path.basename(sys.argv[0]), sys.argv[1])
117+        message = "Type '%s help %s' for usage information." % (
118+                  os.path.basename(sys.argv[0]), sys.argv[1])
119         raise CommandError(message)
120 
121     # We require gettext version 0.15 or newer.
122@@ -326,42 +335,56 @@
123         for dirpath, file in find_files(".", ignore_patterns, verbosity,
124                 symlinks=symlinks):
125             process_file(file, dirpath, potfile, domain, verbosity, extensions,
126-                    wrap, location)
127+                    wrap, location, keep_pot)
128 
129         if os.path.exists(potfile):
130             write_po_file(pofile, potfile, domain, locale, verbosity,
131-                    not invoked_for_django, wrap, location, no_obsolete)
132+                    not invoked_for_django, wrap, location, no_obsolete,
133+                    keep_pot)
134 
135 
136 class Command(NoArgsCommand):
137     option_list = NoArgsCommand.option_list + (
138         make_option('--locale', '-l', default=None, dest='locale',
139-            help='Creates or updates the message files for the given locale (e.g. pt_BR).'),
140+            help='Creates or updates the message files for the given locale '
141+                 '(e.g. pt_BR).'),
142         make_option('--domain', '-d', default='django', dest='domain',
143             help='The domain of the message files (default: "django").'),
144         make_option('--all', '-a', action='store_true', dest='all',
145-            default=False, help='Updates the message files for all existing locales.'),
146-        make_option('--extension', '-e', dest='extensions',
147-            help='The file extension(s) to examine (default: "html,txt", or "js" if the domain is "djangojs"). Separate multiple extensions with commas, or use -e multiple times.',
148-            action='append'),
149+            default=False, help='Updates the message files for all existing '
150+                                'locales.'),
151+        make_option('--extension', '-e', dest='extensions', action='append',
152+            help='The file extension(s) to examine (default: "html,txt", or '
153+                 '"js" if the domain is "djangojs"). Separate multiple '
154+                 'extensions with commas, or use -e multiple times.'),
155         make_option('--symlinks', '-s', action='store_true', dest='symlinks',
156-            default=False, help='Follows symlinks to directories when examining source code and templates for translation strings.'),
157+            default=False, help='Follows symlinks to directories when '
158+                                'examining source code and templates for '
159+                                'translation strings.'),
160         make_option('--ignore', '-i', action='append', dest='ignore_patterns',
161-            default=[], metavar='PATTERN', help='Ignore files or directories matching this glob-style pattern. Use multiple times to ignore more.'),
162-        make_option('--no-default-ignore', action='store_false', dest='use_default_ignore_patterns',
163-            default=True, help="Don't ignore the common glob-style patterns 'CVS', '.*' and '*~'."),
164+            default=[], metavar='PATTERN',
165+            help='Ignore files or directories matching this glob-style '
166+                 'pattern. Use multiple times to ignore more.'),
167+        make_option('--no-default-ignore', action='store_false',
168+            default=True, dest='use_default_ignore_patterns',
169+            help="Don't ignore the common glob-style patterns 'CVS', '.*' and "
170+                 "'*~'."),
171         make_option('--no-wrap', action='store_true', dest='no_wrap',
172-            default=False, help="Don't break long message lines into several lines"),
173+            default=False, help="Don't break long message lines into several "
174+                                "lines"),
175         make_option('--no-location', action='store_true', dest='no_location',
176             default=False, help="Don't write '#: filename:line' lines"),
177         make_option('--no-obsolete', action='store_true', dest='no_obsolete',
178             default=False, help="Remove obsolete message strings"),
179+        make_option('--keep-pot', action='store_true', dest='keep_pot',
180+            default=False, help="Keep .pot file after making messages. Useful "
181+                                "when debugging."),
182     )
183     help = ( "Runs over the entire source tree of the current directory and "
184-"pulls out all strings marked for translation. It creates (or updates) a message "
185-"file in the conf/locale (in the django tree) or locale (for projects and "
186-"applications) directory.\n\nYou must run this command with one of either the "
187-"--locale or --all options.")
188+"pulls out all strings marked for translation. It creates (or updates) a "
189+"message file in the conf/locale (in the django tree) or locale (for projects "
190+"and applications) directory.\n\nYou must run this command with one of either "
191+"the --locale or --all options.")
192 
193     requires_model_validation = False
194     can_import_settings = False
195@@ -380,6 +403,7 @@
196         no_wrap = options.get('no_wrap')
197         no_location = options.get('no_location')
198         no_obsolete = options.get('no_obsolete')
199+        keep_pot = options.get('keep_pot')
200         if domain == 'djangojs':
201             extensions = handle_extensions(extensions or ['js'])
202         else:
203@@ -389,4 +413,6 @@
204             sys.stdout.write('examining files with the extensions: %s\n'
205                              % get_text_list(list(extensions), 'and'))
206 
207-        make_messages(locale, domain, verbosity, process_all, extensions, symlinks, ignore_patterns, no_wrap, no_location, no_obsolete)
208+        make_messages(locale, domain, verbosity, process_all, extensions,
209+            symlinks, ignore_patterns, no_wrap, no_location, no_obsolete,
210+            keep_pot)
211diff --git a/docs/ref/django-admin.txt b/docs/ref/django-admin.txt
212--- a/docs/ref/django-admin.txt
213+++ b/docs/ref/django-admin.txt
214@@ -483,6 +483,14 @@
215 comment lines in language files. Note that using this option makes it harder
216 for technically skilled translators to understand each message's context.
217 
218+.. django-admin-option:: --keep-pot
219+
220+.. versionadded:: 1.4
221+
222+Use the ``--keep-pot`` option to prevent django from deleting the temporary
223+.pot file it generates before creating the .po file. This is useful for
224+debugging errors which may prevent the final language files from being created.
225+
226 reset <appname appname ...>
227 ---------------------------
228 
229diff --git a/tests/regressiontests/i18n/commands/extraction.py b/tests/regressiontests/i18n/commands/extraction.py
230--- a/tests/regressiontests/i18n/commands/extraction.py
231+++ b/tests/regressiontests/i18n/commands/extraction.py
232@@ -263,3 +263,36 @@
233         with open(self.PO_FILE, 'r') as fp:
234             po_contents = fp.read()
235             self.assertTrue('#: templates/test.html:55' in po_contents)
236+
237+
238+class KeepPotFileExtractorTests(ExtractorTests):
239+
240+    def setUp(self):
241+        self.POT_FILE = self.PO_FILE + 't'
242+        super(KeepPotFileExtractorTests, self).setUp()
243+
244+    def tearDown(self):
245+        super(KeepPotFileExtractorTests, self).tearDown()
246+        os.chdir(self.test_dir)
247+        try:
248+            os.unlink(self.POT_FILE)
249+        except OSError:
250+            pass
251+        os.chdir(self._cwd)
252+
253+    def test_keep_pot_disabled_by_default(self):
254+        os.chdir(self.test_dir)
255+        management.call_command('makemessages', locale=LOCALE, verbosity=0)
256+        self.assertFalse(os.path.exists(self.POT_FILE))
257+
258+    def test_keep_pot_explicitly_disabled(self):
259+        os.chdir(self.test_dir)
260+        management.call_command('makemessages', locale=LOCALE, verbosity=0,
261+            keep_pot=False)
262+        self.assertFalse(os.path.exists(self.POT_FILE))
263+
264+    def test_keep_pot_enabled(self):
265+        os.chdir(self.test_dir)
266+        management.call_command('makemessages', locale=LOCALE, verbosity=0,
267+            keep_pot=True)
268+        self.assertTrue(os.path.exists(self.POT_FILE))
269diff --git a/tests/regressiontests/i18n/tests.py b/tests/regressiontests/i18n/tests.py
270--- a/tests/regressiontests/i18n/tests.py
271+++ b/tests/regressiontests/i18n/tests.py
272@@ -29,7 +29,7 @@
273     from .commands.extraction import (ExtractorTests, BasicExtractorTests,
274         JavascriptExtractorTests, IgnoredExtractorTests, SymlinkExtractorTests,
275         CopyPluralFormsExtractorTests, NoWrapExtractorTests,
276-        NoLocationExtractorTests)
277+        NoLocationExtractorTests, KeepPotFileExtractorTests)
278 if can_run_compilation_tests:
279     from .commands.compilation import (PoFileTests, PoFileContentsTests,
280         PercentRenderingTests)