|
@@ -1,4 +1,104 @@
|
|
|
+import codecs
|
|
|
+from hashlib import md5
|
|
|
+import os
|
|
|
+import re
|
|
|
+
|
|
|
+from path import Path
|
|
|
+
|
|
|
from django.core.management.commands.makemessages import Command as BaseCommand
|
|
|
+from django.utils.text import smart_split
|
|
|
+
|
|
|
+
|
|
|
+HBS_EXPRESSION = re.compile(r'({{{(.*?)}}})|({{(.*?)}})')
|
|
|
+
|
|
|
+HELPERS = {
|
|
|
+ 'gettext': 1,
|
|
|
+ 'ngettext': 3,
|
|
|
+ 'gettext_noop': 1,
|
|
|
+ 'pgettext': 2,
|
|
|
+ 'npgettext': 4
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+class HandlebarsTemplate(object):
|
|
|
+ def __init__(self, content):
|
|
|
+ self.content = content
|
|
|
+
|
|
|
+ def get_converted_content(self):
|
|
|
+ stripped_content = self.strip_expressions(self.content)
|
|
|
+ stripped_content = self.strip_non_expressions(stripped_content)
|
|
|
+ replaced_content = self.replace_expressions(stripped_content)
|
|
|
+ return replaced_content
|
|
|
+
|
|
|
+ def strip_expressions(self, content):
|
|
|
+ def replace_expression(matchobj):
|
|
|
+ trimmed_expression = matchobj.group(0).lstrip('{').rstrip('}')
|
|
|
+ trimmed_expression = trimmed_expression.strip()
|
|
|
+
|
|
|
+ expression_words = trimmed_expression.split()
|
|
|
+ if expression_words[0] in HELPERS:
|
|
|
+ return matchobj.group(0)
|
|
|
+ else:
|
|
|
+ return ' ' * len(matchobj.group(0))
|
|
|
+
|
|
|
+ return HBS_EXPRESSION.sub(replace_expression, self.content)
|
|
|
+
|
|
|
+ def strip_non_expressions(self, content):
|
|
|
+ stripped = u''
|
|
|
+
|
|
|
+ cursor = 0
|
|
|
+ for expression in HBS_EXPRESSION.finditer(content):
|
|
|
+ position = content.find(expression.group(0), cursor)
|
|
|
+
|
|
|
+ content_slice = content[cursor:position]
|
|
|
+ if content_slice:
|
|
|
+ slice_lines = len(content_slice.splitlines())
|
|
|
+ if slice_lines:
|
|
|
+ stripped += '\n' * (slice_lines - 1)
|
|
|
+
|
|
|
+ stripped += expression.group(0)
|
|
|
+ cursor = position + len(expression.group(0))
|
|
|
+
|
|
|
+ return stripped
|
|
|
+
|
|
|
+ def replace_expressions(self, content):
|
|
|
+ def replace_expression(matchobj):
|
|
|
+ trimmed_expression = matchobj.group(0).lstrip('{').rstrip('}')
|
|
|
+ trimmed_expression = trimmed_expression.strip()
|
|
|
+
|
|
|
+ expression_bits = [b for b in smart_split(trimmed_expression)]
|
|
|
+ function = expression_bits[0]
|
|
|
+ args = expression_bits[1:HELPERS[function] + 1]
|
|
|
+ return '%s(%s);' % (function, ', '.join(args))
|
|
|
+ return HBS_EXPRESSION.sub(replace_expression, content)
|
|
|
+
|
|
|
+
|
|
|
+class HandlebasFile(object):
|
|
|
+ def __init__(self, hbs_path):
|
|
|
+ self.hbs_path = hbs_path
|
|
|
+ self.path_suffix = self.make_js_path_suffix(hbs_path)
|
|
|
+ self.js_path = self.make_js_path(hbs_path, self.path_suffix)
|
|
|
+
|
|
|
+ self.make_js_file(self.hbs_path, self.js_path)
|
|
|
+
|
|
|
+ def make_js_path_suffix(self, hbs_path):
|
|
|
+ return '%s.tmp.js' % md5(hbs_path).hexdigest()[:8]
|
|
|
+
|
|
|
+ def make_js_path(self, hbs_path, path_suffix):
|
|
|
+ return Path('%s.%s' % (unicode(hbs_path), path_suffix))
|
|
|
+
|
|
|
+ def make_js_file(self, hbs_path, js_path):
|
|
|
+ file_content = u''
|
|
|
+ with codecs.open(hbs_path, encoding='utf-8', mode="r") as hbs_file:
|
|
|
+ file_content = hbs_file.read()
|
|
|
+
|
|
|
+ js_file = codecs.open(js_path, encoding='utf-8', mode='w')
|
|
|
+ js_file.write(HandlebarsTemplate(file_content).get_converted_content())
|
|
|
+ js_file.close()
|
|
|
+
|
|
|
+ def delete(self):
|
|
|
+ if self.js_path.exists() and self.js_path.isfile():
|
|
|
+ self.js_path.unlink()
|
|
|
|
|
|
|
|
|
class Command(BaseCommand):
|
|
@@ -12,30 +112,47 @@ class Command(BaseCommand):
|
|
|
JS_TEMPLATES = ('.hbs', '.handlebars')
|
|
|
|
|
|
def handle(self, *args, **options):
|
|
|
- locale = options.get('locale')
|
|
|
- exclude = options.get('exclude')
|
|
|
+ locales = options.get('locale')
|
|
|
self.domain = options.get('domain')
|
|
|
- self.verbosity = options.get('verbosity')
|
|
|
- process_all = options.get('all')
|
|
|
- extensions = options.get('extensions')
|
|
|
- self.symlinks = options.get('symlinks')
|
|
|
+
|
|
|
+ tmp_js_files = []
|
|
|
|
|
|
if self.domain == 'djangojs':
|
|
|
|
|
|
- self.prepare_tmp_js_templates();
|
|
|
+ tmp_js_files = self.prepare_tmp_js_files();
|
|
|
|
|
|
super(Command, self).handle(*args, **options)
|
|
|
|
|
|
if self.domain == 'djangojs':
|
|
|
|
|
|
- self.cleanup_po_files();
|
|
|
- self.cleanup_tmp_js_templates();
|
|
|
+ self.cleanup_tmp_js_templates(tmp_js_files);
|
|
|
+ self.cleanup_po_files(locales, tmp_js_files);
|
|
|
+
|
|
|
+ def prepare_tmp_js_files(self):
|
|
|
+ files = []
|
|
|
+ for hbs_file in Path(os.getcwd()).walkfiles('*.hbs'):
|
|
|
+ files.append(HandlebasFile(hbs_file))
|
|
|
+ return files
|
|
|
+
|
|
|
+ def cleanup_po_files(self, locales, tmp_js_files):
|
|
|
+ strip_tokens = [js_file.path_suffix for js_file in tmp_js_files]
|
|
|
+
|
|
|
+ for po_file in Path(os.getcwd()).walkfiles('djangojs.po'):
|
|
|
+ if not locales or po_file.splitall()[-3] in locales:
|
|
|
+ self.cleanup_po_file(po_file, strip_tokens)
|
|
|
+
|
|
|
+ def cleanup_po_file(self, po_path, strip_tokens):
|
|
|
+ file_content = u''
|
|
|
+ with codecs.open(po_path, encoding='utf-8', mode="r") as po_file:
|
|
|
+ file_content = po_file.read()
|
|
|
|
|
|
- def prepare_tmp_js_templates(self):
|
|
|
- pass
|
|
|
+ for token in strip_tokens:
|
|
|
+ file_content = file_content.replace(token, '')
|
|
|
|
|
|
- def cleanup_po_files(self):
|
|
|
- pass
|
|
|
+ po_file = codecs.open(po_path, encoding='utf-8', mode='w')
|
|
|
+ po_file.write(file_content)
|
|
|
+ po_file.close()
|
|
|
|
|
|
- def cleanup_tmp_js_templates(self):
|
|
|
- pass
|
|
|
+ def cleanup_tmp_js_templates(self, tmp_js_files):
|
|
|
+ for js_file in tmp_js_files:
|
|
|
+ js_file.delete()
|