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