18
18
# with Python under the Python License, which is GPL compatible.
20
20
"""Extract docstrings from Bazaar commands.
22
This module only handles bzrlib objects that use strings not directly wrapped
23
by a gettext() call. To generate a complete translation template file, this
24
output needs to be combined with that of xgettext or a similar command for
25
extracting those strings, as is done in the bzr Makefile. Sorting the output
26
is also left to that stage of the process.
63
_FOUND_MSGID = None # set by entry function.
65
def _poentry(outf, path, lineno, s, comment=None):
72
comment = "# %s\n" % comment
73
mutter("Exporting msg %r at line %d in %r", s[:20], lineno, path)
74
print >>outf, ('#: %s:%d\n' % (path, lineno) +
76
'msgid %s\n' % _normalize(s) +
79
def _poentry_per_paragraph(outf, path, lineno, msgid, filter=lambda x: False):
80
# TODO: How to split long help?
81
paragraphs = msgid.split('\n\n')
85
_poentry(outf, path, lineno, p)
86
lineno += p.count('\n') + 2
71
class _PotExporter(object):
72
"""Write message details to output stream in .pot file format"""
74
def __init__(self, outf):
78
def poentry(self, path, lineno, s, comment=None):
85
comment = "# %s\n" % comment
86
mutter("Exporting msg %r at line %d in %r", s[:20], lineno, path)
88
"#: {path}:{lineno}\n"
93
path=path, lineno=lineno, comment=comment, msg=_normalize(s)))
95
def poentry_per_paragraph(self, path, lineno, msgid, include=None):
96
# TODO: How to split long help?
97
paragraphs = msgid.split('\n\n')
98
if include is not None:
99
paragraphs = filter(include, paragraphs)
101
self.poentry(path, lineno, p)
102
lineno += p.count('\n') + 2
88
105
_LAST_CACHE = _LAST_CACHED_SRC = None
104
121
_LAST_CACHE = offsets.copy()
107
def _standard_options(outf):
124
def _standard_options(exporter):
108
125
from bzrlib.option import Option
109
126
src = inspect.findsource(Option)[0]
110
127
src = ''.join(src)
118
135
if getattr(opt, 'title', None):
119
136
lineno = offsets.get(opt.title, 9999)
120
137
if lineno == 9999:
121
note("%r is not found in bzrlib/option.py" % opt.title)
122
_poentry(outf, path, lineno, opt.title,
138
note(gettext("%r is not found in bzrlib/option.py") % opt.title)
139
exporter.poentry(path, lineno, opt.title,
123
140
'title of %r option' % name)
124
141
if getattr(opt, 'help', None):
125
142
lineno = offsets.get(opt.help, 9999)
126
143
if lineno == 9999:
127
note("%r is not found in bzrlib/option.py" % opt.help)
128
_poentry(outf, path, lineno, opt.help,
144
note(gettext("%r is not found in bzrlib/option.py") % opt.help)
145
exporter.poentry(path, lineno, opt.help,
129
146
'help of %r option' % name)
131
def _command_options(outf, path, cmd):
148
def _command_options(exporter, path, cmd):
132
149
src, default_lineno = inspect.findsource(cmd.__class__)
133
150
offsets = _offsets_of_literal(''.join(src))
134
151
for opt in cmd.takes_options:
140
157
if getattr(opt, 'title', None):
141
158
lineno = offsets.get(opt.title, default_lineno)
142
_poentry(outf, path, lineno, opt.title,
159
exporter.poentry(path, lineno, opt.title,
143
160
'title of %r option of %r command' % (name, cmd.name()))
144
161
if getattr(opt, 'help', None):
145
162
lineno = offsets.get(opt.help, default_lineno)
146
_poentry(outf, path, lineno, opt.help,
163
exporter.poentry(path, lineno, opt.help,
147
164
'help of %r option of %r command' % (name, cmd.name()))
150
def _write_command_help(outf, cmd):
167
def _write_command_help(exporter, cmd):
151
168
path = inspect.getfile(cmd.__class__)
152
169
if path.endswith('.pyc'):
157
174
lineno = offsets[cmd.__doc__]
158
175
doc = inspect.getdoc(cmd)
177
def exclude_usage(p):
161
178
# ':Usage:' has special meaning in help topics.
162
179
# This is usage example of command and should not be translated.
163
if p.splitlines()[0] == ':Usage:':
180
if p.splitlines()[0] != ':Usage:':
166
_poentry_per_paragraph(outf, path, lineno, doc, filter)
167
_command_options(outf, path, cmd)
170
def _command_helps(outf):
183
exporter.poentry_per_paragraph(path, lineno, doc, exclude_usage)
184
_command_options(exporter, path, cmd)
187
def _command_helps(exporter, plugin_name=None):
171
188
"""Extract docstrings from path.
173
190
This respects the Bazaar cmdtable/table convention and will
180
197
command = _mod_commands.get_cmd_object(cmd_name, False)
181
198
if command.hidden:
183
note("Exporting messages from builtin command: %s", cmd_name)
184
_write_command_help(outf, command)
200
if plugin_name is not None:
201
# only export builtins if we are not exporting plugin commands
203
note(gettext("Exporting messages from builtin command: %s"), cmd_name)
204
_write_command_help(exporter, command)
186
206
plugin_path = plugin.get_core_plugin_path()
187
207
core_plugins = glob(plugin_path + '/*/__init__.py')
188
208
core_plugins = [os.path.basename(os.path.dirname(p))
189
209
for p in core_plugins]
191
211
for cmd_name in _mod_commands.plugin_command_names():
192
212
command = _mod_commands.get_cmd_object(cmd_name, False)
193
213
if command.hidden:
195
if command.plugin_name() not in core_plugins:
215
if plugin_name is not None and command.plugin_name() != plugin_name:
216
# if we are exporting plugin commands, skip plugins we have not specified.
218
if plugin_name is None and command.plugin_name() not in core_plugins:
196
219
# skip non-core plugins
197
220
# TODO: Support extracting from third party plugins.
199
note("Exporting messages from plugin command: %s in %s",
200
cmd_name, command.plugin_name())
201
_write_command_help(outf, command)
204
def _error_messages(outf):
222
note(gettext("Exporting messages from plugin command: {0} in {1}").format(
223
cmd_name, command.plugin_name() ))
224
_write_command_help(exporter, command)
227
def _error_messages(exporter):
205
228
"""Extract fmt string from bzrlib.errors."""
206
229
path = errors.__file__
207
230
if path.endswith('.pyc'):
222
245
fmt = getattr(klass, "_fmt", None)
224
note("Exporting message from error: %s", name)
225
_poentry(outf, 'bzrlib/errors.py',
247
note(gettext("Exporting message from error: %s"), name)
248
exporter.poentry('bzrlib/errors.py',
226
249
offsets.get(fmt, 9999), fmt)
228
def _help_topics(outf):
251
def _help_topics(exporter):
229
252
topic_registry = help_topics.topic_registry
230
253
for key in topic_registry.keys():
231
254
doc = topic_registry.get(key)
232
255
if isinstance(doc, str):
233
_poentry_per_paragraph(
256
exporter.poentry_per_paragraph(
235
257
'dummy/help_topics/'+key+'/detail.txt',
259
elif callable(doc): # help topics from files
260
exporter.poentry_per_paragraph(
261
'en/help_topics/'+key+'.txt',
238
263
summary = topic_registry.get_summary(key)
239
264
if summary is not None:
240
_poentry(outf, 'dummy/help_topics/'+key+'/summary.txt',
265
exporter.poentry('dummy/help_topics/'+key+'/summary.txt',
243
def export_pot(outf):
246
_standard_options(outf)
248
_error_messages(outf)
249
# disable exporting help topics until we decide how to translate it.
268
def export_pot(outf, plugin=None):
269
exporter = _PotExporter(outf)
271
_standard_options(exporter)
272
_command_helps(exporter)
273
_error_messages(exporter)
274
_help_topics(exporter)
276
_command_helps(exporter, plugin)