Created
January 17, 2013 21:31
-
-
Save claudep/4559957 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/django/core/management/commands/makemessages.py b/django/core/management/commands/makemessages.py | |
--- a/django/core/management/commands/makemessages.py | |
+++ b/django/core/management/commands/makemessages.py | |
@@ -112,75 +112,56 @@ | |
break | |
return msgs | |
-def write_pot_file(potfile, msgs, file, work_file, is_templatized): | |
- """ | |
- Write the :param potfile: POT file with the :param msgs: contents, | |
- previously making sure its format is valid. | |
- """ | |
- if is_templatized: | |
- old = '#: ' + work_file[2:] | |
- new = '#: ' + file[2:] | |
- msgs = msgs.replace(old, new) | |
- if os.path.exists(potfile): | |
- # Strip the header | |
- msgs = '\n'.join(dropwhile(len, msgs.split('\n'))) | |
- else: | |
- msgs = msgs.replace('charset=CHARSET', 'charset=UTF-8') | |
- f = open(potfile, 'ab') | |
- try: | |
- f.write(msgs) | |
- finally: | |
- f.close() | |
-def process_file(file, dirpath, potfile, domain, verbosity, extensions, wrap, | |
- location): | |
- """ | |
- Extract translatable literals from :param file: for :param domain: | |
- creating or updating the :param potfile: POT file. | |
+class Domain(object): | |
- Uses the xgettext GNU gettext utility. | |
- """ | |
+ def __init__(self, extensions): | |
+ self.extensions = extensions | |
- from django.utils.translation import templatize | |
+ def process_file(self, file_obj, verbosity, wrap, location): | |
+ if verbosity > 1: | |
+ sys.stdout.write('processing file %s in %s\n' % (file_obj.file, file_obj.dirpath)) | |
+ cmd = self.work(file_obj, verbosity, wrap, location) | |
+ msgs, errors = _popen(cmd) | |
+ if errors: | |
+ raise CommandError( | |
+ "errors happened while running xgettext on %s\n%s" % | |
+ (file_obj.file, errors)) | |
+ return msgs | |
- if verbosity > 1: | |
- sys.stdout.write('processing file %s in %s\n' % (file, dirpath)) | |
- _, file_ext = os.path.splitext(file) | |
- if domain == 'djangojs' and file_ext in extensions: | |
- is_templatized = True | |
- orig_file = os.path.join(dirpath, file) | |
- src_data = open(orig_file).read() | |
- src_data = prepare_js_for_gettext(src_data) | |
- thefile = '%s.c' % file | |
- work_file = os.path.join(dirpath, thefile) | |
- f = open(work_file, "w") | |
- try: | |
- f.write(src_data) | |
- finally: | |
- f.close() | |
- 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, wrap, location, work_file | |
- ) | |
- ) | |
- elif domain == 'django' and (file_ext == '.py' or file_ext in extensions): | |
- thefile = file | |
- orig_file = os.path.join(dirpath, file) | |
- is_templatized = file_ext in extensions | |
- if is_templatized: | |
+ | |
+class DjangoDomain(Domain): | |
+ name = 'django' | |
+ xgettext_cmd = 'xgettext -d %(domain)s -L Python %(wrap)s %(location)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 - "%(work_file)s"' | |
+ templatize_format = '%s.py' | |
+ | |
+ def is_mine(self, domain, file): | |
+ _, file_ext = os.path.splitext(file) | |
+ return domain == self.name and (file_ext == '.py' or file_ext in self.extensions) | |
+ | |
+ def work(self, file_obj, verbosity, wrap, location): | |
+ from django.utils.translation import templatize | |
+ | |
+ _, file_ext = os.path.splitext(file_obj.file) | |
+ thefile = file_obj.file | |
+ orig_file = os.path.join(file_obj.dirpath, file_obj.file) | |
+ file_obj.is_templatized = file_ext in self.extensions | |
+ if file_obj.is_templatized: | |
src_data = open(orig_file, "rU").read() | |
- thefile = '%s.py' % file | |
- content = templatize(src_data, orig_file[2:]) | |
- f = open(os.path.join(dirpath, thefile), "w") | |
+ thefile = self.templatize_format % file_obj.file | |
+ f = open(os.path.join(file_obj.dirpath, thefile), "w") | |
try: | |
- f.write(content) | |
+ f.write(templatize(src_data, orig_file[2:])) | |
finally: | |
f.close() | |
- work_file = os.path.join(dirpath, thefile) | |
- cmd = ( | |
+ file_obj.work_file = os.path.join(file_obj.dirpath, thefile) | |
+ return ( | |
'xgettext -d %s -L Python %s %s --keyword=gettext_noop ' | |
'--keyword=gettext_lazy --keyword=ngettext_lazy:1,2 ' | |
'--keyword=ugettext_noop --keyword=ugettext_lazy ' | |
@@ -188,73 +169,146 @@ | |
'--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, wrap, location, work_file) | |
+ self.name, wrap, location, file_obj.work_file) | |
) | |
- else: | |
- return | |
- msgs, errors = _popen(cmd) | |
- if errors: | |
- if is_templatized: | |
- os.unlink(work_file) | |
- if os.path.exists(potfile): | |
- os.unlink(potfile) | |
- raise CommandError( | |
- "errors happened while running xgettext on %s\n%s" % | |
- (file, errors)) | |
- if msgs: | |
- write_pot_file(potfile, msgs, orig_file, work_file, is_templatized) | |
- if is_templatized: | |
- os.unlink(work_file) | |
-def write_po_file(pofile, potfile, domain, locale, verbosity, | |
- copy_pforms, wrap, location, no_obsolete): | |
- """ | |
- Creates of updates the :param pofile: PO file for :param domain: and :param | |
- locale:. Uses contents of the existing :param potfile:. | |
- Uses mguniq, msgmerge, and msgattrib GNU gettext utilities. | |
- """ | |
- msgs, errors = _popen('msguniq %s %s --to-code=utf-8 "%s"' % | |
- (wrap, location, potfile)) | |
- if errors: | |
- os.unlink(potfile) | |
- raise CommandError("errors happened while running msguniq\n%s" % errors) | |
- if os.path.exists(pofile): | |
- f = open(potfile, 'w') | |
+class DjangoJsDomain(Domain): | |
+ name = 'djangojs' | |
+ xgettext_cmd = 'xgettext -d %(domain)s -L C %(wrap)s %(location)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 - "%(work_file)s"' | |
+ templatize_format = '%s.c' | |
+ | |
+ def is_mine(self, domain, file): | |
+ _, file_ext = os.path.splitext(file) | |
+ return domain == self.name and file_ext in self.extensions | |
+ | |
+ def work(self, file_obj, verbosity, wrap, location): | |
+ file_obj.is_templatized = True | |
+ orig_file = os.path.join(file_obj.dirpath, file_obj.file) | |
+ src_data = open(orig_file).read() | |
+ src_data = prepare_js_for_gettext(src_data) | |
+ thefile = self.templatize_format % file_obj.file | |
+ file_obj.work_file = os.path.join(file_obj.dirpath, thefile) | |
+ f = open(file_obj.work_file, "w") | |
+ try: | |
+ f.write(src_data) | |
+ finally: | |
+ f.close() | |
+ return ( | |
+ '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"' % ( | |
+ self.name, wrap, location, file_obj.work_file | |
+ ) | |
+ ) | |
+ | |
+ | |
+class Locale(object): | |
+ def __init__(self, domain, localedir, locale_name): | |
+ basedir = os.path.join(localedir, locale_name, 'LC_MESSAGES') | |
+ if not os.path.isdir(basedir): | |
+ os.makedirs(basedir) | |
+ | |
+ self.domain = domain | |
+ self.locale_name = locale_name | |
+ self.pofile = os.path.join(basedir, '%s.po' % domain) | |
+ self.potfile = os.path.join(basedir, '%s.pot' % domain) | |
+ | |
+ self.remove_potfile() | |
+ | |
+ def write_pot_file(self, msgs, file_obj): | |
+ """ | |
+ Write the POT file with the :param msgs: contents, previously making | |
+ sure its format is valid. | |
+ """ | |
+ if file_obj.is_templatized: | |
+ old = '#: ' + file_obj.work_file[2:] | |
+ new = '#: ' + file_obj.file[2:] | |
+ msgs = msgs.replace(old, new) | |
+ if os.path.exists(self.potfile): | |
+ # Strip the header | |
+ msgs = '\n'.join(dropwhile(len, msgs.split('\n'))) | |
+ else: | |
+ msgs = msgs.replace('charset=CHARSET', 'charset=UTF-8') | |
+ f = open(self.potfile, 'ab') | |
try: | |
f.write(msgs) | |
finally: | |
f.close() | |
- msgs, errors = _popen('msgmerge %s %s -q "%s" "%s"' % | |
- (wrap, location, pofile, potfile)) | |
+ | |
+ def write_po_file(self, verbosity, copy_pforms, wrap, location, | |
+ no_obsolete): | |
+ """ | |
+ Write the PO file for this locale by creating or updating it. Uses | |
+ contents of the existing POT file. | |
+ | |
+ Uses mguniq, msgmerge, and msgattrib GNU gettext utilities. | |
+ """ | |
+ if not os.path.exists(self.potfile): | |
+ return | |
+ msgs, errors = _popen('msguniq %s %s --to-code=utf-8 "%s"' % | |
+ (wrap, location, self.potfile)) | |
if errors: | |
- os.unlink(potfile) | |
- raise CommandError( | |
- "errors happened while running msgmerge\n%s" % errors) | |
- elif copy_pforms: | |
- msgs = copy_plural_forms(msgs, locale, domain, verbosity) | |
- msgs = msgs.replace( | |
- "#. #-#-#-#-# %s.pot (PACKAGE VERSION) #-#-#-#-#\n" % domain, "") | |
- f = open(pofile, 'wb') | |
- try: | |
- f.write(msgs) | |
- finally: | |
- f.close() | |
- os.unlink(potfile) | |
- if no_obsolete: | |
- msgs, errors = _popen('msgattrib %s %s -o "%s" --no-obsolete "%s"' % | |
- (wrap, location, pofile, pofile)) | |
- if errors: | |
- raise CommandError( | |
- "errors happened while running msgattrib\n%s" % errors) | |
+ os.unlink(self.potfile) | |
+ raise CommandError("errors happened while running msguniq\n%s" % errors) | |
+ if os.path.exists(self.pofile): | |
+ f = open(self.potfile, 'w') | |
+ try: | |
+ f.write(msgs) | |
+ finally: | |
+ f.close() | |
+ msgs, errors = _popen('msgmerge %s %s -q "%s" "%s"' % | |
+ (wrap, location, self.pofile,self.potfile)) | |
+ if errors: | |
+ os.unlink(self.potfile) | |
+ raise CommandError( | |
+ "errors happened while running msgmerge\n%s" % errors) | |
+ elif copy_pforms: | |
+ msgs = copy_plural_forms(msgs, self.locale_name, self.domain, verbosity) | |
+ msgs = msgs.replace( | |
+ "#. #-#-#-#-# %s.pot (PACKAGE VERSION) #-#-#-#-#\n" % self.domain, "") | |
+ f = open(self.pofile, 'wb') | |
+ try: | |
+ f.write(msgs) | |
+ finally: | |
+ f.close() | |
+ os.unlink(self.potfile) | |
+ if no_obsolete: | |
+ msgs, errors = _popen('msgattrib %s %s -o "%s" --no-obsolete "%s"' % | |
+ (wrap, location, self.pofile, self.pofile)) | |
+ if errors: | |
+ raise CommandError( | |
+ "errors happened while running msgattrib\n%s" % errors) | |
-def make_messages(locale=None, domain='django', verbosity=1, all=False, | |
+ def remove_potfile(self): | |
+ if os.path.exists(self.potfile): | |
+ os.unlink(self.potfile) | |
+ | |
+ | |
+class TranslatableFile(object): | |
+ def __init__(self, file, dirpath, domain, locale): | |
+ self.file = file | |
+ self.dirpath = dirpath | |
+ self.domain = domain | |
+ self.locale = locale | |
+ self.is_templatized = False | |
+ | |
+ def cleanup(self): | |
+ if self.is_templatized: | |
+ os.unlink(self.work_file) | |
+ | |
+ | |
+def make_messages(locale=None, domain_name='django', verbosity=1, all=False, | |
extensions=None, symlinks=False, ignore_patterns=None, no_wrap=False, | |
no_location=False, no_obsolete=False): | |
""" | |
Uses the ``locale/`` directory from the Django SVN tree or an | |
- application/project to process all files with translatable literals for | |
- the :param domain: domain and :param locale: locale. | |
+ application/project to process all the files with translatable literals for | |
+ the :param domain_name: domain and :param locale: locale. | |
""" | |
# Need to ensure that the i18n framework is enabled | |
from django.conf import settings | |
@@ -266,7 +320,6 @@ | |
if ignore_patterns is None: | |
ignore_patterns = [] | |
- invoked_for_django = False | |
if os.path.isdir(os.path.join('conf', 'locale')): | |
localedir = os.path.abspath(os.path.join('conf', 'locale')) | |
invoked_for_django = True | |
@@ -274,6 +327,7 @@ | |
ignore_patterns += ['contrib/*'] | |
elif os.path.isdir('locale'): | |
localedir = os.path.abspath('locale') | |
+ invoked_for_django = False | |
else: | |
raise CommandError("This script should be run from the Django SVN " | |
"tree or your project or app tree. If you did indeed run it " | |
@@ -283,10 +337,10 @@ | |
"is not created automatically, you have to create it by hand " | |
"if you want to enable i18n for your project or application.") | |
- if domain not in ('django', 'djangojs'): | |
+ if domain_name not in ('django', 'djangojs'): | |
raise CommandError("currently makemessages only supports domains 'django' and 'djangojs'") | |
- if (locale is None and not all) or domain is None: | |
+ if (locale is None and not all) or domain_name is None: | |
message = "Type '%s help %s' for usage information." % (os.path.basename(sys.argv[0]), sys.argv[1]) | |
raise CommandError(message) | |
@@ -310,27 +364,33 @@ | |
wrap = '--no-wrap' if no_wrap else '' | |
location = '--no-location' if no_location else '' | |
- for locale in locales: | |
+ domains = ( | |
+ DjangoJsDomain(extensions), | |
+ DjangoDomain(extensions), | |
+ ) | |
+ for locale_name in locales: | |
if verbosity > 0: | |
- print "processing language", locale | |
- basedir = os.path.join(localedir, locale, 'LC_MESSAGES') | |
- if not os.path.isdir(basedir): | |
- os.makedirs(basedir) | |
- | |
- pofile = os.path.join(basedir, '%s.po' % domain) | |
- potfile = os.path.join(basedir, '%s.pot' % domain) | |
- | |
- if os.path.exists(potfile): | |
- os.unlink(potfile) | |
+ print "processing language", locale_name | |
+ locale = Locale(domain_name, localedir, locale_name) | |
for dirpath, file in find_files(".", ignore_patterns, verbosity, | |
symlinks=symlinks): | |
- process_file(file, dirpath, potfile, domain, verbosity, extensions, | |
- wrap, location) | |
+ for domain in domains: | |
+ if domain.is_mine(domain_name, file): | |
+ f = TranslatableFile(file, dirpath, domain, locale) | |
+ try: | |
+ msgs = domain.process_file(f, verbosity, wrap, location) | |
+ except CommandError: | |
+ locale.remove_potfile() | |
+ raise | |
+ else: | |
+ if msgs: | |
+ locale.write_pot_file(msgs, f) | |
+ finally: | |
+ f.cleanup() | |
- if os.path.exists(potfile): | |
- write_po_file(pofile, potfile, domain, locale, verbosity, | |
- not invoked_for_django, wrap, location, no_obsolete) | |
+ locale.write_po_file(verbosity, not invoked_for_django, wrap, location, | |
+ no_obsolete) | |
class Command(NoArgsCommand): |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment