##// END OF EJS Templates
py3: make i18n/hggettext use absolute_import
Pulkit Goyal -
r29170:2516bba6 default
parent child Browse files
Show More
@@ -1,137 +1,141
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 #
2 #
3 # hggettext - carefully extract docstrings for Mercurial
3 # hggettext - carefully extract docstrings for Mercurial
4 #
4 #
5 # Copyright 2009 Matt Mackall <mpm@selenic.com> and others
5 # Copyright 2009 Matt Mackall <mpm@selenic.com> and others
6 #
6 #
7 # This software may be used and distributed according to the terms of the
7 # This software may be used and distributed according to the terms of the
8 # GNU General Public License version 2 or any later version.
8 # GNU General Public License version 2 or any later version.
9
9
10 # The normalize function is taken from pygettext which is distributed
10 # The normalize function is taken from pygettext which is distributed
11 # with Python under the Python License, which is GPL compatible.
11 # with Python under the Python License, which is GPL compatible.
12
12
13 """Extract docstrings from Mercurial commands.
13 """Extract docstrings from Mercurial commands.
14
14
15 Compared to pygettext, this script knows about the cmdtable and table
15 Compared to pygettext, this script knows about the cmdtable and table
16 dictionaries used by Mercurial, and will only extract docstrings from
16 dictionaries used by Mercurial, and will only extract docstrings from
17 functions mentioned therein.
17 functions mentioned therein.
18
18
19 Use xgettext like normal to extract strings marked as translatable and
19 Use xgettext like normal to extract strings marked as translatable and
20 join the message cataloges to get the final catalog.
20 join the message cataloges to get the final catalog.
21 """
21 """
22
22
23 import os, sys, inspect
23 from __future__ import absolute_import
24
25 import inspect
26 import os
27 import sys
24
28
25
29
26 def escape(s):
30 def escape(s):
27 # The order is important, the backslash must be escaped first
31 # The order is important, the backslash must be escaped first
28 # since the other replacements introduce new backslashes
32 # since the other replacements introduce new backslashes
29 # themselves.
33 # themselves.
30 s = s.replace('\\', '\\\\')
34 s = s.replace('\\', '\\\\')
31 s = s.replace('\n', '\\n')
35 s = s.replace('\n', '\\n')
32 s = s.replace('\r', '\\r')
36 s = s.replace('\r', '\\r')
33 s = s.replace('\t', '\\t')
37 s = s.replace('\t', '\\t')
34 s = s.replace('"', '\\"')
38 s = s.replace('"', '\\"')
35 return s
39 return s
36
40
37
41
38 def normalize(s):
42 def normalize(s):
39 # This converts the various Python string types into a format that
43 # This converts the various Python string types into a format that
40 # is appropriate for .po files, namely much closer to C style.
44 # is appropriate for .po files, namely much closer to C style.
41 lines = s.split('\n')
45 lines = s.split('\n')
42 if len(lines) == 1:
46 if len(lines) == 1:
43 s = '"' + escape(s) + '"'
47 s = '"' + escape(s) + '"'
44 else:
48 else:
45 if not lines[-1]:
49 if not lines[-1]:
46 del lines[-1]
50 del lines[-1]
47 lines[-1] = lines[-1] + '\n'
51 lines[-1] = lines[-1] + '\n'
48 lines = map(escape, lines)
52 lines = map(escape, lines)
49 lineterm = '\\n"\n"'
53 lineterm = '\\n"\n"'
50 s = '""\n"' + lineterm.join(lines) + '"'
54 s = '""\n"' + lineterm.join(lines) + '"'
51 return s
55 return s
52
56
53
57
54 def poentry(path, lineno, s):
58 def poentry(path, lineno, s):
55 return ('#: %s:%d\n' % (path, lineno) +
59 return ('#: %s:%d\n' % (path, lineno) +
56 'msgid %s\n' % normalize(s) +
60 'msgid %s\n' % normalize(s) +
57 'msgstr ""\n')
61 'msgstr ""\n')
58
62
59
63
60 def offset(src, doc, name, default):
64 def offset(src, doc, name, default):
61 """Compute offset or issue a warning on stdout."""
65 """Compute offset or issue a warning on stdout."""
62 # Backslashes in doc appear doubled in src.
66 # Backslashes in doc appear doubled in src.
63 end = src.find(doc.replace('\\', '\\\\'))
67 end = src.find(doc.replace('\\', '\\\\'))
64 if end == -1:
68 if end == -1:
65 # This can happen if the docstring contains unnecessary escape
69 # This can happen if the docstring contains unnecessary escape
66 # sequences such as \" in a triple-quoted string. The problem
70 # sequences such as \" in a triple-quoted string. The problem
67 # is that \" is turned into " and so doc wont appear in src.
71 # is that \" is turned into " and so doc wont appear in src.
68 sys.stderr.write("warning: unknown offset in %s, assuming %d lines\n"
72 sys.stderr.write("warning: unknown offset in %s, assuming %d lines\n"
69 % (name, default))
73 % (name, default))
70 return default
74 return default
71 else:
75 else:
72 return src.count('\n', 0, end)
76 return src.count('\n', 0, end)
73
77
74
78
75 def importpath(path):
79 def importpath(path):
76 """Import a path like foo/bar/baz.py and return the baz module."""
80 """Import a path like foo/bar/baz.py and return the baz module."""
77 if path.endswith('.py'):
81 if path.endswith('.py'):
78 path = path[:-3]
82 path = path[:-3]
79 if path.endswith('/__init__'):
83 if path.endswith('/__init__'):
80 path = path[:-9]
84 path = path[:-9]
81 path = path.replace('/', '.')
85 path = path.replace('/', '.')
82 mod = __import__(path)
86 mod = __import__(path)
83 for comp in path.split('.')[1:]:
87 for comp in path.split('.')[1:]:
84 mod = getattr(mod, comp)
88 mod = getattr(mod, comp)
85 return mod
89 return mod
86
90
87
91
88 def docstrings(path):
92 def docstrings(path):
89 """Extract docstrings from path.
93 """Extract docstrings from path.
90
94
91 This respects the Mercurial cmdtable/table convention and will
95 This respects the Mercurial cmdtable/table convention and will
92 only extract docstrings from functions mentioned in these tables.
96 only extract docstrings from functions mentioned in these tables.
93 """
97 """
94 mod = importpath(path)
98 mod = importpath(path)
95 if mod.__doc__:
99 if mod.__doc__:
96 src = open(path).read()
100 src = open(path).read()
97 lineno = 1 + offset(src, mod.__doc__, path, 7)
101 lineno = 1 + offset(src, mod.__doc__, path, 7)
98 print poentry(path, lineno, mod.__doc__)
102 print poentry(path, lineno, mod.__doc__)
99
103
100 functions = list(getattr(mod, 'i18nfunctions', []))
104 functions = list(getattr(mod, 'i18nfunctions', []))
101 functions = [(f, True) for f in functions]
105 functions = [(f, True) for f in functions]
102
106
103 cmdtable = getattr(mod, 'cmdtable', {})
107 cmdtable = getattr(mod, 'cmdtable', {})
104 if not cmdtable:
108 if not cmdtable:
105 # Maybe we are processing mercurial.commands?
109 # Maybe we are processing mercurial.commands?
106 cmdtable = getattr(mod, 'table', {})
110 cmdtable = getattr(mod, 'table', {})
107 functions.extend((c[0], False) for c in cmdtable.itervalues())
111 functions.extend((c[0], False) for c in cmdtable.itervalues())
108
112
109 for func, rstrip in functions:
113 for func, rstrip in functions:
110 if func.__doc__:
114 if func.__doc__:
111 src = inspect.getsource(func)
115 src = inspect.getsource(func)
112 name = "%s.%s" % (path, func.__name__)
116 name = "%s.%s" % (path, func.__name__)
113 lineno = func.func_code.co_firstlineno
117 lineno = func.func_code.co_firstlineno
114 doc = func.__doc__
118 doc = func.__doc__
115 if rstrip:
119 if rstrip:
116 doc = doc.rstrip()
120 doc = doc.rstrip()
117 lineno += offset(src, doc, name, 1)
121 lineno += offset(src, doc, name, 1)
118 print poentry(path, lineno, doc)
122 print poentry(path, lineno, doc)
119
123
120
124
121 def rawtext(path):
125 def rawtext(path):
122 src = open(path).read()
126 src = open(path).read()
123 print poentry(path, 1, src)
127 print poentry(path, 1, src)
124
128
125
129
126 if __name__ == "__main__":
130 if __name__ == "__main__":
127 # It is very important that we import the Mercurial modules from
131 # It is very important that we import the Mercurial modules from
128 # the source tree where hggettext is executed. Otherwise we might
132 # the source tree where hggettext is executed. Otherwise we might
129 # accidentally import and extract strings from a Mercurial
133 # accidentally import and extract strings from a Mercurial
130 # installation mentioned in PYTHONPATH.
134 # installation mentioned in PYTHONPATH.
131 sys.path.insert(0, os.getcwd())
135 sys.path.insert(0, os.getcwd())
132 from mercurial import demandimport; demandimport.enable()
136 from mercurial import demandimport; demandimport.enable()
133 for path in sys.argv[1:]:
137 for path in sys.argv[1:]:
134 if path.endswith('.txt'):
138 if path.endswith('.txt'):
135 rawtext(path)
139 rawtext(path)
136 else:
140 else:
137 docstrings(path)
141 docstrings(path)
General Comments 0
You need to be logged in to leave comments. Login now