8b582e17e5a9d04edd47f726b38b5cacd0f93466
[odoo/odoo.git] / npybabel.py
1 #!/usr/bin/env python
2 # EASY-INSTALL-ENTRY-SCRIPT: 'Babel==0.9.6','console_scripts','pybabel'
3 __requires__ = 'Babel==0.9.6'
4 import sys
5 from pkg_resources import load_entry_point
6 import re
7 import json
8 from lxml import etree as elt
9 from babel.messages import extract
10
11 if __name__ == '__main__':
12     sys.exit(
13         load_entry_point('Babel==0.9.6', 'console_scripts', 'pybabel')()
14     )
15
16 XMLJS_EXPR = re.compile(r"""(?:\_t *\( *((?:"(?:[^"\\]|\\.)*")|(?:'(?:[^'\\]|\\.)*')) *\))""")
17
18 TRANSLATION_FLAG_COMMENT = "openerp-web"
19
20 def extract_xmljs(fileobj, keywords, comment_tags, options):
21     """Extract messages from Javascript code embedded into XML documents.
22     This complements the ``extract_javascript`` extractor which works
23     only on pure .js files, and the``extract_qweb`` extractor, which only
24     extracts XML text.
25
26     :param fileobj: the file-like object the messages should be extracted
27                     from
28     :param keywords: a list of keywords (i.e. function names) that should
29                      be recognized as translation functions
30     :param comment_tags: a list of translator tags to search for and
31                          include in the results
32     :param options: a dictionary of additional options (optional)
33     :return: an iterator over ``(lineno, funcname, message, comments)``
34              tuples
35     :rtype: ``iterator``
36     """
37     content = fileobj.read()
38     found = XMLJS_EXPR.finditer(content)
39     index = 0
40     line_nbr = 0
41     for f in found:
42         msg = f.group(1)
43         msg = json.loads(msg)
44         while index < f.start():
45             if content[index] == "\n":
46                 line_nbr += 1
47             index += 1
48         yield (line_nbr, None, msg, [TRANSLATION_FLAG_COMMENT])
49
50 def extract_qweb(fileobj, keywords, comment_tags, options):
51     """Extract messages from qweb template files.
52     :param fileobj: the file-like object the messages should be extracted
53                     from
54     :param keywords: a list of keywords (i.e. function names) that should
55                      be recognized as translation functions
56     :param comment_tags: a list of translator tags to search for and
57                          include in the results
58     :param options: a dictionary of additional options (optional)
59     :return: an iterator over ``(lineno, funcname, message, comments)``
60              tuples
61     :rtype: ``iterator``
62     """
63     result = []
64     def handle_text(text, lineno):
65         text = (text or "").strip()
66         if len(text) > 1: # Avoid mono-char tokens like ':' ',' etc.
67             result.append((lineno, None, text, [TRANSLATION_FLAG_COMMENT]))
68
69     # not using elementTree.iterparse because we need to skip sub-trees in case
70     # the ancestor element had a reason to be skipped
71     def iter_elements(current_element):
72         for el in current_element:
73             if "t-js" not in el.attrib and \
74                     not ("t-jquery" in el.attrib and "t-operation" not in el.attrib) and \
75                     not ("t-translation" in el.attrib and el.attrib["t-translation"].strip() == "off"):
76                 handle_text(el.text, el.sourceline)
77                 for att in ('title', 'alt', 'label'):
78                     if att in el.attrib:
79                         handle_text(el.attrib[att], el.sourceline)
80                 iter_elements(el)
81             handle_text(el.tail, el.sourceline)
82
83     tree = elt.parse(fileobj)
84     iter_elements(tree.getroot())
85
86     return result
87
88 def extract_javascript(fileobj, keywords, comment_tags, options):
89     """Extract messages from Javascript source files. This extractor delegates
90     to babel's buit-in javascript extractor, but adds a special comment
91     used as a flag to identify web translations. 
92
93     :param fileobj: the file-like object the messages should be extracted
94                     from
95     :param keywords: a list of keywords (i.e. function names) that should
96                      be recognized as translation functions
97     :param comment_tags: a list of translator tags to search for and
98                          include in the results
99     :param options: a dictionary of additional options (optional)
100     :return: an iterator over ``(lineno, funcname, message, comments)``
101              tuples
102     :rtype: ``iterator``
103     """
104     for (message_lineno, funcname, messages, comments) in \
105         extract.extract_javascript(fileobj, keywords, comment_tags, options):
106         comments.append(TRANSLATION_FLAG_COMMENT)
107         yield (message_lineno, funcname, messages, comments)