Browse Source

makemessages now support handlebars helpers

Rafał Pitoń 10 years ago
parent
commit
4a037567d5

+ 1 - 0
.gitignore

@@ -70,4 +70,5 @@ dev/
 dev-manage.py
 futuredep/
 future-manage.py
+misago-admin.py
 db.sqlite3

+ 132 - 15
misago/core/management/commands/makemessages.py

@@ -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':
             # fake js files from templates
-            self.prepare_tmp_js_templates();
+            tmp_js_files = self.prepare_tmp_js_files();
 
         super(Command, self).handle(*args, **options)
 
         if self.domain == 'djangojs':
             # cleanup everything
-            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()

+ 2 - 0
misago/static/misago/app/templates/index.hbs

@@ -1,4 +1,6 @@
 <div class="container">
   <h1>Welcome to Ember.js!</h1>
   <p class="lead">IndexController renders index.hbs template!</p>
+  <p>Si vis pacem {{gettext "para bellum"}}!</p>
+  <p>Si {{gettext "vis"}} pacem {{gettext "para %(bellum)s" bellum="Honey"}}!</p>
 </div>