source: python/trunk/Tools/i18n/msgfmt.py@ 6

Last change on this file since 6 was 2, checked in by Yuri Dario, 15 years ago

Initial import for vendor code.

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