Loading django/core/management/commands/compilemessages.py +5 −2 Original line number Diff line number Diff line Loading @@ -5,7 +5,7 @@ import os from optparse import make_option from django.core.management.base import BaseCommand, CommandError from django.core.management.utils import popen_wrapper from django.core.management.utils import find_command, popen_wrapper from django.utils._os import npath def has_bom(fn): Loading @@ -16,6 +16,10 @@ def has_bom(fn): sample.startswith(codecs.BOM_UTF16_BE) def compile_messages(stderr, locale=None): program = 'msgfmt' if find_command(program) is None: raise CommandError("Can't find %s. Make sure you have GNU gettext tools 0.15 or newer installed." % program) basedirs = [os.path.join('conf', 'locale'), 'locale'] if os.environ.get('DJANGO_SETTINGS_MODULE'): from django.conf import settings Loading @@ -42,7 +46,6 @@ def compile_messages(stderr, locale=None): if has_bom(fn): 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) pf = os.path.splitext(fn)[0] program = 'msgfmt' args = [program, '--check-format', '-o', npath(pf + '.mo'), npath(pf + '.po')] output, errors, status = popen_wrapper(args) if status: Loading django/core/management/commands/makemessages.py +77 −35 Original line number Diff line number Diff line Loading @@ -5,11 +5,11 @@ import re import sys from itertools import dropwhile from optparse import make_option from subprocess import PIPE, Popen import django from django.core.management.base import CommandError, NoArgsCommand from django.core.management.utils import handle_extensions from django.core.management.utils import (handle_extensions, find_command, popen_wrapper) from django.utils.functional import total_ordering from django.utils.text import get_text_list from django.utils.jslex import prepare_js_for_gettext Loading @@ -18,6 +18,13 @@ plural_forms_re = re.compile(r'^(?P<value>"Plural-Forms.+?\\n")\s*$', re.MULTILI STATUS_OK = 0 def check_programs(*programs): for program in programs: if find_command(program) is None: raise CommandError("Can't find %s. Make sure you have GNU " "gettext tools 0.15 or newer installed." % program) @total_ordering class TranslatableFile(object): def __init__(self, dirpath, file_name): Loading Loading @@ -58,12 +65,24 @@ class TranslatableFile(object): work_file = os.path.join(self.dirpath, thefile) with open(work_file, "w") as fp: fp.write(src_data) cmd = ( 'xgettext -d %s -L C %s %s --keyword=gettext_noop ' '--keyword=gettext_lazy --keyword=ngettext_lazy:1,2 ' '--keyword=pgettext:1c,2 --keyword=npgettext:1c,2,3 ' '--from-code UTF-8 --add-comments=Translators -o - "%s"' % (domain, command.wrap, command.location, work_file)) args = [ 'xgettext', '-d', domain, '--language=C', '--keyword=gettext_noop', '--keyword=gettext_lazy', '--keyword=ngettext_lazy:1,2', '--keyword=pgettext:1c,2', '--keyword=npgettext:1c,2,3', '--from-code=UTF-8', '--add-comments=Translators', '--output=-' ] if command.wrap: args.append(command.wrap) if command.location: args.append(command.location) args.append(work_file) elif domain == 'django' and (file_ext == '.py' or file_ext in command.extensions): thefile = self.file orig_file = os.path.join(self.dirpath, self.file) Loading @@ -76,18 +95,32 @@ class TranslatableFile(object): with open(os.path.join(self.dirpath, thefile), "w") as fp: fp.write(content) work_file = os.path.join(self.dirpath, thefile) cmd = ( 'xgettext -d %s -L Python %s %s --keyword=gettext_noop ' '--keyword=gettext_lazy --keyword=ngettext_lazy:1,2 ' '--keyword=ugettext_noop --keyword=ugettext_lazy ' '--keyword=ungettext_lazy:1,2 --keyword=pgettext:1c,2 ' '--keyword=npgettext:1c,2,3 --keyword=pgettext_lazy:1c,2 ' '--keyword=npgettext_lazy:1c,2,3 --from-code UTF-8 ' '--add-comments=Translators -o - "%s"' % (domain, command.wrap, command.location, work_file)) args = [ 'xgettext', '-d', domain, '--language=Python', '--keyword=gettext_noop', '--keyword=gettext_lazy', '--keyword=ngettext_lazy:1,2', '--keyword=ugettext_noop', '--keyword=ugettext_lazy', '--keyword=ungettext_lazy:1,2', '--keyword=pgettext:1c,2', '--keyword=npgettext:1c,2,3', '--keyword=pgettext_lazy:1c,2', '--keyword=npgettext_lazy:1c,2,3', '--from-code=UTF-8', '--add-comments=Translators', '--output=-' ] if command.wrap: args.append(command.wrap) if command.location: args.append(command.location) args.append(work_file) else: return msgs, errors, status = _popen(cmd) msgs, errors, status = popen_wrapper(args) if errors: if status != STATUS_OK: if is_templatized: Loading @@ -109,15 +142,6 @@ class TranslatableFile(object): if is_templatized: os.unlink(work_file) def _popen(cmd): """ Friendly wrapper around Popen for Windows """ p = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE, close_fds=os.name != 'nt', universal_newlines=True) output, errors = p.communicate() return output, errors, p.returncode def write_pot_file(potfile, msgs): """ Write the :param potfile: POT file with the :param msgs: contents, Loading Loading @@ -225,8 +249,9 @@ class Command(NoArgsCommand): "is not created automatically, you have to create it by hand " "if you want to enable i18n for your project or application.") check_programs('xgettext') # We require gettext version 0.15 or newer. output, errors, status = _popen('xgettext --version') output, errors, status = popen_wrapper(['xgettext', '--version']) if status != STATUS_OK: raise CommandError("Error running xgettext. Note that Django " "internationalization requires GNU gettext 0.15 or newer.") Loading @@ -248,6 +273,9 @@ class Command(NoArgsCommand): locale_dirs = filter(os.path.isdir, glob.glob('%s/*' % localedir)) locales = [os.path.basename(l) for l in locale_dirs] if locales: check_programs('msguniq', 'msgmerge', 'msgattrib') try: for locale in locales: if self.verbosity > 0: Loading Loading @@ -307,8 +335,13 @@ class Command(NoArgsCommand): Uses mguniq, msgmerge, and msgattrib GNU gettext utilities. """ msgs, errors, status = _popen('msguniq %s %s --to-code=utf-8 "%s"' % (self.wrap, self.location, potfile)) args = ['msguniq', '--to-code=utf-8'] if self.wrap: args.append(self.wrap) if self.location: args.append(self.location) args.append(potfile) msgs, errors, status = popen_wrapper(args) if errors: if status != STATUS_OK: raise CommandError( Loading @@ -324,8 +357,13 @@ class Command(NoArgsCommand): if os.path.exists(pofile): with open(potfile, 'w') as fp: fp.write(msgs) msgs, errors, status = _popen('msgmerge %s %s -q "%s" "%s"' % (self.wrap, self.location, pofile, potfile)) args = ['msgmerge', '-q'] if self.wrap: args.append(self.wrap) if self.location: args.append(self.location) args.extend([pofile, potfile]) msgs, errors, status = popen_wrapper(args) if errors: if status != STATUS_OK: raise CommandError( Loading @@ -340,9 +378,13 @@ class Command(NoArgsCommand): fp.write(msgs) if self.no_obsolete: msgs, errors, status = _popen( 'msgattrib %s %s -o "%s" --no-obsolete "%s"' % (self.wrap, self.location, pofile, pofile)) args = ['msgattrib', '-o', pofile, '--no-obsolete'] if self.wrap: args.append(self.wrap) if self.location: args.append(self.location) args.append(pofile) msgs, errors, status = popen_wrapper(args) if errors: if status != STATUS_OK: raise CommandError( Loading django/core/management/utils.py +37 −3 Original line number Diff line number Diff line from __future__ import absolute_import import os from subprocess import PIPE, Popen import sys from django.utils.encoding import force_text, DEFAULT_LOCALE_ENCODING from django.utils import six from .base import CommandError def popen_wrapper(args): def popen_wrapper(args, os_err_exc_type=CommandError): """ Friendly wrapper around Popen. Returns stdout output, stderr output and OS status code. """ try: p = Popen(args, shell=False, stdout=PIPE, stderr=PIPE, close_fds=os.name != 'nt', universal_newlines=True) except OSError as e: six.reraise(os_err_exc_type, os_err_exc_type('Error executing %s: %s' % (args[0], e.strerror)), sys.exc_info()[2]) output, errors = p.communicate() return ( output, Loading Loading @@ -43,3 +53,27 @@ def handle_extensions(extensions=('html',), ignored=('py',)): if not ext.startswith('.'): ext_list[i] = '.%s' % ext_list[i] return set([x for x in ext_list if x.strip('.') not in ignored]) def find_command(cmd, path=None, pathext=None): if path is None: path = os.environ.get('PATH', []).split(os.pathsep) if isinstance(path, six.string_types): path = [path] # check if there are funny path extensions for executables, e.g. Windows if pathext is None: pathext = os.environ.get('PATHEXT', '.COM;.EXE;.BAT;.CMD').split(os.pathsep) # don't use extensions if the command ends with one of them for ext in pathext: if cmd.endswith(ext): pathext = [''] break # check if we find the command on PATH for p in path: f = os.path.join(p, cmd) if os.path.isfile(f): return f for ext in pathext: fext = f + ext if os.path.isfile(fext): return fext return None tests/i18n/commands/extraction.py +7 −2 Original line number Diff line number Diff line Loading @@ -131,8 +131,13 @@ class BasicExtractorTests(ExtractorTests): os.chdir(self.test_dir) shutil.copyfile('./code.sample', './code_sample.py') stdout = StringIO() try: management.call_command('makemessages', locale=LOCALE, stdout=stdout) finally: try: os.remove('./code_sample.py') except OSError: pass self.assertIn("code_sample.py:4", force_text(stdout.getvalue())) def test_template_message_context_extractor(self): Loading tests/i18n/commands/tests.py +1 −25 Original line number Diff line number Diff line Loading @@ -2,35 +2,11 @@ import os import re from subprocess import Popen, PIPE from django.utils import six from django.core.management.utils import find_command can_run_extraction_tests = False can_run_compilation_tests = False def find_command(cmd, path=None, pathext=None): if path is None: path = os.environ.get('PATH', []).split(os.pathsep) if isinstance(path, six.string_types): path = [path] # check if there are funny path extensions for executables, e.g. Windows if pathext is None: pathext = os.environ.get('PATHEXT', '.COM;.EXE;.BAT;.CMD').split(os.pathsep) # don't use extensions if the command ends with one of them for ext in pathext: if cmd.endswith(ext): pathext = [''] break # check if we find the command on PATH for p in path: f = os.path.join(p, cmd) if os.path.isfile(f): return f for ext in pathext: fext = f + ext if os.path.isfile(fext): return fext return None # checks if it can find xgettext on the PATH and # imports the extraction tests if yes xgettext_cmd = find_command('xgettext') Loading Loading
django/core/management/commands/compilemessages.py +5 −2 Original line number Diff line number Diff line Loading @@ -5,7 +5,7 @@ import os from optparse import make_option from django.core.management.base import BaseCommand, CommandError from django.core.management.utils import popen_wrapper from django.core.management.utils import find_command, popen_wrapper from django.utils._os import npath def has_bom(fn): Loading @@ -16,6 +16,10 @@ def has_bom(fn): sample.startswith(codecs.BOM_UTF16_BE) def compile_messages(stderr, locale=None): program = 'msgfmt' if find_command(program) is None: raise CommandError("Can't find %s. Make sure you have GNU gettext tools 0.15 or newer installed." % program) basedirs = [os.path.join('conf', 'locale'), 'locale'] if os.environ.get('DJANGO_SETTINGS_MODULE'): from django.conf import settings Loading @@ -42,7 +46,6 @@ def compile_messages(stderr, locale=None): if has_bom(fn): 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) pf = os.path.splitext(fn)[0] program = 'msgfmt' args = [program, '--check-format', '-o', npath(pf + '.mo'), npath(pf + '.po')] output, errors, status = popen_wrapper(args) if status: Loading
django/core/management/commands/makemessages.py +77 −35 Original line number Diff line number Diff line Loading @@ -5,11 +5,11 @@ import re import sys from itertools import dropwhile from optparse import make_option from subprocess import PIPE, Popen import django from django.core.management.base import CommandError, NoArgsCommand from django.core.management.utils import handle_extensions from django.core.management.utils import (handle_extensions, find_command, popen_wrapper) from django.utils.functional import total_ordering from django.utils.text import get_text_list from django.utils.jslex import prepare_js_for_gettext Loading @@ -18,6 +18,13 @@ plural_forms_re = re.compile(r'^(?P<value>"Plural-Forms.+?\\n")\s*$', re.MULTILI STATUS_OK = 0 def check_programs(*programs): for program in programs: if find_command(program) is None: raise CommandError("Can't find %s. Make sure you have GNU " "gettext tools 0.15 or newer installed." % program) @total_ordering class TranslatableFile(object): def __init__(self, dirpath, file_name): Loading Loading @@ -58,12 +65,24 @@ class TranslatableFile(object): work_file = os.path.join(self.dirpath, thefile) with open(work_file, "w") as fp: fp.write(src_data) cmd = ( 'xgettext -d %s -L C %s %s --keyword=gettext_noop ' '--keyword=gettext_lazy --keyword=ngettext_lazy:1,2 ' '--keyword=pgettext:1c,2 --keyword=npgettext:1c,2,3 ' '--from-code UTF-8 --add-comments=Translators -o - "%s"' % (domain, command.wrap, command.location, work_file)) args = [ 'xgettext', '-d', domain, '--language=C', '--keyword=gettext_noop', '--keyword=gettext_lazy', '--keyword=ngettext_lazy:1,2', '--keyword=pgettext:1c,2', '--keyword=npgettext:1c,2,3', '--from-code=UTF-8', '--add-comments=Translators', '--output=-' ] if command.wrap: args.append(command.wrap) if command.location: args.append(command.location) args.append(work_file) elif domain == 'django' and (file_ext == '.py' or file_ext in command.extensions): thefile = self.file orig_file = os.path.join(self.dirpath, self.file) Loading @@ -76,18 +95,32 @@ class TranslatableFile(object): with open(os.path.join(self.dirpath, thefile), "w") as fp: fp.write(content) work_file = os.path.join(self.dirpath, thefile) cmd = ( 'xgettext -d %s -L Python %s %s --keyword=gettext_noop ' '--keyword=gettext_lazy --keyword=ngettext_lazy:1,2 ' '--keyword=ugettext_noop --keyword=ugettext_lazy ' '--keyword=ungettext_lazy:1,2 --keyword=pgettext:1c,2 ' '--keyword=npgettext:1c,2,3 --keyword=pgettext_lazy:1c,2 ' '--keyword=npgettext_lazy:1c,2,3 --from-code UTF-8 ' '--add-comments=Translators -o - "%s"' % (domain, command.wrap, command.location, work_file)) args = [ 'xgettext', '-d', domain, '--language=Python', '--keyword=gettext_noop', '--keyword=gettext_lazy', '--keyword=ngettext_lazy:1,2', '--keyword=ugettext_noop', '--keyword=ugettext_lazy', '--keyword=ungettext_lazy:1,2', '--keyword=pgettext:1c,2', '--keyword=npgettext:1c,2,3', '--keyword=pgettext_lazy:1c,2', '--keyword=npgettext_lazy:1c,2,3', '--from-code=UTF-8', '--add-comments=Translators', '--output=-' ] if command.wrap: args.append(command.wrap) if command.location: args.append(command.location) args.append(work_file) else: return msgs, errors, status = _popen(cmd) msgs, errors, status = popen_wrapper(args) if errors: if status != STATUS_OK: if is_templatized: Loading @@ -109,15 +142,6 @@ class TranslatableFile(object): if is_templatized: os.unlink(work_file) def _popen(cmd): """ Friendly wrapper around Popen for Windows """ p = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE, close_fds=os.name != 'nt', universal_newlines=True) output, errors = p.communicate() return output, errors, p.returncode def write_pot_file(potfile, msgs): """ Write the :param potfile: POT file with the :param msgs: contents, Loading Loading @@ -225,8 +249,9 @@ class Command(NoArgsCommand): "is not created automatically, you have to create it by hand " "if you want to enable i18n for your project or application.") check_programs('xgettext') # We require gettext version 0.15 or newer. output, errors, status = _popen('xgettext --version') output, errors, status = popen_wrapper(['xgettext', '--version']) if status != STATUS_OK: raise CommandError("Error running xgettext. Note that Django " "internationalization requires GNU gettext 0.15 or newer.") Loading @@ -248,6 +273,9 @@ class Command(NoArgsCommand): locale_dirs = filter(os.path.isdir, glob.glob('%s/*' % localedir)) locales = [os.path.basename(l) for l in locale_dirs] if locales: check_programs('msguniq', 'msgmerge', 'msgattrib') try: for locale in locales: if self.verbosity > 0: Loading Loading @@ -307,8 +335,13 @@ class Command(NoArgsCommand): Uses mguniq, msgmerge, and msgattrib GNU gettext utilities. """ msgs, errors, status = _popen('msguniq %s %s --to-code=utf-8 "%s"' % (self.wrap, self.location, potfile)) args = ['msguniq', '--to-code=utf-8'] if self.wrap: args.append(self.wrap) if self.location: args.append(self.location) args.append(potfile) msgs, errors, status = popen_wrapper(args) if errors: if status != STATUS_OK: raise CommandError( Loading @@ -324,8 +357,13 @@ class Command(NoArgsCommand): if os.path.exists(pofile): with open(potfile, 'w') as fp: fp.write(msgs) msgs, errors, status = _popen('msgmerge %s %s -q "%s" "%s"' % (self.wrap, self.location, pofile, potfile)) args = ['msgmerge', '-q'] if self.wrap: args.append(self.wrap) if self.location: args.append(self.location) args.extend([pofile, potfile]) msgs, errors, status = popen_wrapper(args) if errors: if status != STATUS_OK: raise CommandError( Loading @@ -340,9 +378,13 @@ class Command(NoArgsCommand): fp.write(msgs) if self.no_obsolete: msgs, errors, status = _popen( 'msgattrib %s %s -o "%s" --no-obsolete "%s"' % (self.wrap, self.location, pofile, pofile)) args = ['msgattrib', '-o', pofile, '--no-obsolete'] if self.wrap: args.append(self.wrap) if self.location: args.append(self.location) args.append(pofile) msgs, errors, status = popen_wrapper(args) if errors: if status != STATUS_OK: raise CommandError( Loading
django/core/management/utils.py +37 −3 Original line number Diff line number Diff line from __future__ import absolute_import import os from subprocess import PIPE, Popen import sys from django.utils.encoding import force_text, DEFAULT_LOCALE_ENCODING from django.utils import six from .base import CommandError def popen_wrapper(args): def popen_wrapper(args, os_err_exc_type=CommandError): """ Friendly wrapper around Popen. Returns stdout output, stderr output and OS status code. """ try: p = Popen(args, shell=False, stdout=PIPE, stderr=PIPE, close_fds=os.name != 'nt', universal_newlines=True) except OSError as e: six.reraise(os_err_exc_type, os_err_exc_type('Error executing %s: %s' % (args[0], e.strerror)), sys.exc_info()[2]) output, errors = p.communicate() return ( output, Loading Loading @@ -43,3 +53,27 @@ def handle_extensions(extensions=('html',), ignored=('py',)): if not ext.startswith('.'): ext_list[i] = '.%s' % ext_list[i] return set([x for x in ext_list if x.strip('.') not in ignored]) def find_command(cmd, path=None, pathext=None): if path is None: path = os.environ.get('PATH', []).split(os.pathsep) if isinstance(path, six.string_types): path = [path] # check if there are funny path extensions for executables, e.g. Windows if pathext is None: pathext = os.environ.get('PATHEXT', '.COM;.EXE;.BAT;.CMD').split(os.pathsep) # don't use extensions if the command ends with one of them for ext in pathext: if cmd.endswith(ext): pathext = [''] break # check if we find the command on PATH for p in path: f = os.path.join(p, cmd) if os.path.isfile(f): return f for ext in pathext: fext = f + ext if os.path.isfile(fext): return fext return None
tests/i18n/commands/extraction.py +7 −2 Original line number Diff line number Diff line Loading @@ -131,8 +131,13 @@ class BasicExtractorTests(ExtractorTests): os.chdir(self.test_dir) shutil.copyfile('./code.sample', './code_sample.py') stdout = StringIO() try: management.call_command('makemessages', locale=LOCALE, stdout=stdout) finally: try: os.remove('./code_sample.py') except OSError: pass self.assertIn("code_sample.py:4", force_text(stdout.getvalue())) def test_template_message_context_extractor(self): Loading
tests/i18n/commands/tests.py +1 −25 Original line number Diff line number Diff line Loading @@ -2,35 +2,11 @@ import os import re from subprocess import Popen, PIPE from django.utils import six from django.core.management.utils import find_command can_run_extraction_tests = False can_run_compilation_tests = False def find_command(cmd, path=None, pathext=None): if path is None: path = os.environ.get('PATH', []).split(os.pathsep) if isinstance(path, six.string_types): path = [path] # check if there are funny path extensions for executables, e.g. Windows if pathext is None: pathext = os.environ.get('PATHEXT', '.COM;.EXE;.BAT;.CMD').split(os.pathsep) # don't use extensions if the command ends with one of them for ext in pathext: if cmd.endswith(ext): pathext = [''] break # check if we find the command on PATH for p in path: f = os.path.join(p, cmd) if os.path.isfile(f): return f for ext in pathext: fext = f + ext if os.path.isfile(fext): return fext return None # checks if it can find xgettext on the PATH and # imports the extraction tests if yes xgettext_cmd = find_command('xgettext') Loading