~bzr-pqm/bzr/bzr.dev

5830.2.1 by INADA Naoki
Add update-pot command to Makefile and tools/bzrgettext script that
1
#!/usr/bin/env python
2
#
3
# bzrgettext - extract docstrings for Bazaar commands
4
#
5
# Copyright 2009 Matt Mackall <mpm@selenic.com> and others
6
# Copyright 2011 Canonical Ltd
7
#
8
# This program is free software; you can redistribute it and/or modify
9
# it under the terms of the GNU General Public License as published by
10
# the Free Software Foundation; either version 2 of the License, or
11
# (at your option) any later version.
12
#
13
# This program is distributed in the hope that it will be useful,
14
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
# GNU General Public License for more details.
17
#
18
# You should have received a copy of the GNU General Public License
19
# along with this program; if not, write to the Free Software
20
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
22
# This script is copied from mercurial/i18n/hggettext and modified
23
# for Bazaar.
24
25
# The normalize function is taken from pygettext which is distributed
26
# with Python under the Python License, which is GPL compatible.
27
28
29
"""Extract docstrings from Bazaar commands.
30
"""
31
32
import os, sys, inspect
33
34
35
def escape(s):
36
    s = (s.replace('\\', '\\\\')
37
        .replace('\n', '\\n')
38
        .replace('\r', '\\r')
39
        .replace('\t', '\\t')
40
        .replace('"', '\\"')
41
        )
42
    return s
43
44
45
def normalize(s):
46
    # This converts the various Python string types into a format that
47
    # is appropriate for .po files, namely much closer to C style.
48
    lines = s.split('\n')
49
    if len(lines) == 1:
50
        s = '"' + escape(s) + '"'
51
    else:
52
        if not lines[-1]:
53
            del lines[-1]
54
            lines[-1] = lines[-1] + '\n'
55
        lines = map(escape, lines)
56
        lineterm = '\\n"\n"'
57
        s = '""\n"' + lineterm.join(lines) + '"'
58
    return s
59
60
61
def poentry(path, lineno, s):
62
    return ('#: %s:%d\n' % (path, lineno) +
63
            'msgid %s\n' % normalize(s) +
64
            'msgstr ""\n')
65
66
67
def offset(src, doc, name, default):
68
    """Compute offset or issue a warning on stdout."""
69
    # Backslashes in doc appear doubled in src.
70
    end = src.find(doc.replace('\\', '\\\\'))
71
    if end == -1:
72
        # This can happen if the docstring contains unnecessary escape
73
        # sequences such as \" in a triple-quoted string. The problem
74
        # is that \" is turned into " and so doc wont appear in src.
75
        sys.stderr.write("warning: unknown offset in %s, assuming %d lines\n"
76
                         % (name, default))
77
        return default
78
    else:
79
        return src.count('\n', 0, end)
80
81
82
def importpath(path):
83
    """Import a path like foo/bar/baz.py and return the baz module."""
84
    if path.endswith('.py'):
85
        path = path[:-3]
86
    if path.endswith('/__init__'):
87
        path = path[:-9]
88
    path = path.replace('/', '.')
89
    mod = __import__(path)
90
    for comp in path.split('.')[1:]:
91
        mod = getattr(mod, comp)
92
    return mod
93
94
95
def docstrings(path):
96
    """Extract docstrings from path.
97
98
    This respects the Bazaar cmdtable/table convention and will
99
    only extract docstrings from functions mentioned in these tables.
100
    """
101
    from bzrlib.commands import Command as cmd_klass
102
    mod = importpath(path)
103
    for name in dir(mod):
104
        if not name.startswith('cmd_'):
105
            continue
106
        obj = getattr(mod, name)
107
        try:
108
            doc = obj.__doc__
109
            if doc:
110
                doc = inspect.cleandoc(doc)
111
            else:
112
                continue
113
        except AttributeError:
114
            continue
115
        if (inspect.isclass(obj) and issubclass(obj, cmd_klass)
116
                and not obj is cmd_klass):
117
            print poentry(path, inspect.findsource(obj)[1], doc)
118
119
def bzrerrors():
120
    """Extract fmt string from bzrlib.errors."""
121
    from bzrlib import errors
122
    base_klass = errors.BzrError
123
    for name in dir(errors):
124
        klass = getattr(errors, name)
125
        if not inspect.isclass(klass):
126
            continue
127
        if not issubclass(klass, base_klass):
128
            continue
129
        if klass is base_klass:
130
            continue
131
        if klass.internal_error:
132
            continue
133
        fmt = getattr(klass, "_fmt", None)
134
        if fmt:
135
            print poentry('bzrlib/erros.py',
136
                    inspect.findsource(klass)[1], fmt)
137
138
139
def rawtext(path):
140
    src = open(path).read()
141
    print poentry(path, 1, src)
142
143
144
if __name__ == "__main__":
145
    # It is very important that we import the Bazaar modules from
146
    # the source tree where bzrgettext is executed. Otherwise we might
147
    # accidentally import and extract strings from a Bazaar
148
    # installation mentioned in PYTHONPATH.
149
    sys.path.insert(0, os.getcwd())
150
    import bzrlib.lazy_import
151
    for path in sys.argv[1:]:
152
        if path.endswith('.txt'):
153
            rawtext(path)
154
        else:
155
            docstrings(path)
156
    bzrerrors()