root/trunk/umitCore/msgfmt.py @ 3174

Revision 3174, 6.0 kB (checked in by luis, 5 years ago)

- Fixed icons install (and in uninstall_umit)
- Added functions to build mo files 'on the fly'
- Remove mo files from sdist

(this changes it's necessary to debian package)

Line 
1#! /usr/bin/env python
2# -*- coding: iso-8859-1 -*-
3# Written by Martin v. L� <loewis@informatik.hu-berlin.de>
4#
5# Changelog: (Guilherme Polo)
6#   2008-04-11
7#    - Support for files with BOM UTF8 mark.
8#
9#   2008-04-10
10#    - Support for fuzzy strings in output.
11#    - Bumped to version 1.1.1
12
13"""Generate binary message catalog from textual translation description.
14
15This program converts a textual Uniforum-style message catalog (.po file) into
16a binary GNU catalog (.mo file).  This is essentially the same function as the
17GNU msgfmt program, however, it is a simpler implementation.
18
19Usage: msgfmt.py [OPTIONS] filename.po
20
21Options:
22    -o file
23    --output-file=file
24        Specify the output file to write to.  If omitted, output will go to a
25        file named filename.mo (based off the input file name).
26
27    -f
28    --use-fuzzy
29        Use fuzzy entries in output
30
31    -h
32    --help
33        Print this message and exit.
34
35    -V
36    --version
37        Display version information and exit.
38
39Before using the -f (fuzzy) option, read this:
40    http://www.finesheer.com:8457/cgi-bin/info2html?(gettext)Fuzzy%20Entries&lang=en
41"""
42
43import sys
44import os
45import getopt
46import struct
47import array
48import codecs
49
50__version__ = "1.1.1"
51
52MESSAGES = {}
53
54
55def usage(code, msg=''):
56    print >> sys.stderr, __doc__
57    if msg:
58        print >> sys.stderr, msg
59    sys.exit(code)
60
61
62def add(id, str, fuzzy, use_fuzzy):
63    "Add a translation to the dictionary."
64    global MESSAGES
65    if (not fuzzy or use_fuzzy) and str:
66        MESSAGES[id] = str
67
68
69def generate():
70    "Return the generated output."
71    global MESSAGES
72    keys = MESSAGES.keys()
73    # the keys are sorted in the .mo file
74    keys.sort()
75    offsets = []
76    ids = strs = ''
77    for id in keys:
78        # For each string, we need size and file offset.  Each string is NUL
79        # terminated; the NUL does not count into the size.
80        offsets.append((len(ids), len(id), len(strs), len(MESSAGES[id])))
81        ids += id + '\0'
82        strs += MESSAGES[id] + '\0'
83    output = ''
84    # The header is 7 32-bit unsigned integers.  We don't use hash tables, so
85    # the keys start right after the index tables.
86    # translated string.
87    keystart = 7*4+16*len(keys)
88    # and the values start after the keys
89    valuestart = keystart + len(ids)
90    koffsets = []
91    voffsets = []
92    # The string table first has the list of keys, then the list of values.
93    # Each entry has first the size of the string, then the file offset.
94    for o1, l1, o2, l2 in offsets:
95        koffsets += [l1, o1+keystart]
96        voffsets += [l2, o2+valuestart]
97    offsets = koffsets + voffsets
98    output = struct.pack("Iiiiiii",
99                         0x950412deL,       # Magic
100                         0,                 # Version
101                         len(keys),         # # of entries
102                         7*4,               # start of key index
103                         7*4+len(keys)*8,   # start of value index
104                         0, 0)              # size and offset of hash table
105    output += array.array("i", offsets).tostring()
106    output += ids
107    output += strs
108    return output
109
110
111def make(filename, outfile, use_fuzzy):
112    ID = 1
113    STR = 2
114
115    # Compute .mo name from .po name and arguments
116    if filename.endswith('.po'):
117        infile = filename
118    else:
119        infile = filename + '.po'
120    if outfile is None:
121        outfile = os.path.splitext(infile)[0] + '.mo'
122
123    try:
124        lines = open(infile).readlines()
125        if lines[0].startswith(codecs.BOM_UTF8):
126            lines[0] = lines[0][len(codecs.BOM_UTF8):]
127    except IOError, msg:
128        print >> sys.stderr, msg
129        sys.exit(1)
130
131    section = None
132    fuzzy = 0
133
134    # Parse the catalog
135    lno = 0
136    for l in lines:
137        lno += 1
138        # If we get a comment line after a msgstr, this is a new entry
139        if l[0] == '#' and section == STR:
140            add(msgid, msgstr, fuzzy, use_fuzzy)
141            section = None
142            fuzzy = 0
143        # Record a fuzzy mark
144        if l[:2] == '#,' and 'fuzzy' in l:
145            fuzzy = 1
146        # Skip comments
147        if l[0] == '#':
148            continue
149        # Now we are in a msgid section, output previous section
150        if l.startswith('msgid'):
151            if section == STR:
152                add(msgid, msgstr, fuzzy, use_fuzzy)
153            section = ID
154            l = l[5:]
155            msgid = msgstr = ''
156        # Now we are in a msgstr section
157        elif l.startswith('msgstr'):
158            section = STR
159            l = l[6:]
160        # Skip empty lines
161        l = l.strip()
162        if not l:
163            continue
164        # XXX: Does this always follow Python escape semantics?
165        l = eval(l)
166        if section == ID:
167            msgid += l
168        elif section == STR:
169            msgstr += l
170        else:
171            print >> sys.stderr, 'Syntax error on %s:%d' % (infile, lno), \
172                  'before:'
173            print >> sys.stderr, l
174            sys.exit(1)
175    # Add last entry
176    if section == STR:
177        add(msgid, msgstr, fuzzy, use_fuzzy)
178
179    # Compute output
180    output = generate()
181
182    try:
183        open(outfile,"wb").write(output)
184    except IOError,msg:
185        print >> sys.stderr, msg
186
187
188def main():
189    try:
190        opts, args = getopt.getopt(sys.argv[1:], 'hVo:f',
191            ['help', 'version', 'output-file=', 'use-fuzzy'])
192    except getopt.error, msg:
193        usage(1, msg)
194
195    outfile = None
196    use_fuzzy = False
197    # parse options
198    for opt, arg in opts:
199        if opt in ('-h', '--help'):
200            usage(0)
201        elif opt in ('-V', '--version'):
202            print >> sys.stderr, "msgfmt.py", __version__
203            sys.exit(0)
204        elif opt in ('-f', '--use-fuzzy'):
205            use_fuzzy = True
206        elif opt in ('-o', '--output-file'):
207            outfile = arg
208    # do it
209    if not args:
210        print >> sys.stderr, 'No input file given'
211        print >> sys.stderr, "Try `msgfmt --help' for more information."
212        return
213
214    for filename in args:
215        make(filename, outfile, use_fuzzy)
216
217
218if __name__ == '__main__':
219    main()
Note: See TracBrowser for help on using the browser.