-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmsgfmt.py
More file actions
126 lines (110 loc) · 3.69 KB
/
msgfmt.py
File metadata and controls
126 lines (110 loc) · 3.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
"""Tools for compiling gettext catalogs"""
import array
import os
import struct
def _add(messages, id_, str_, fuzzy):
"""Add a non-fuzzy translation to the dictionary"""
if not fuzzy and str_:
messages[id_] = str_
def _generate(messages):
"""Return the generated output"""
keys = messages.keys()
# the keys are sorted in the .mo file
keys.sort()
offsets = []
ids = ''
strs = ''
for id_ in keys:
# For each string, we need size and file offset. Each string is NUL
# terminated; the NUL does not count into the size.
offsets.append((len(ids), len(id_), len(strs), len(messages[id_])))
ids += id_ + '\0'
strs += messages[id_] + '\0'
output = ''
# The header is 7 32-bit unsigned integers. We don't use hash tables, so
# the keys start right after the index tables.
# translated string.
keystart = 7 * 4 + 16 * len(keys)
# and the values start after the keys
valuestart = keystart + len(ids)
koffsets = []
voffsets = []
# The string table first has the list of keys, then the list of values.
# Each entry has first the size of the string, then the file offset.
for offset1, line1, offset2, line2 in offsets:
koffsets += [line1, offset1 + keystart]
voffsets += [line2, offset2 + valuestart]
offsets = koffsets + voffsets
output = struct.pack("Iiiiiii",
0x950412deL, # Magic
0, # Version
len(keys), # # of entries
7 * 4, # start of key index
7 * 4 + len(keys) * 8, # start of value index
0, 0) # size and offset of hash table
output += array.array("i", offsets).tostring()
output += ids
output += strs
return output
def compile_catalog(path):
"""Builds a binary catalog for a given path to a gettext catalog"""
ID = 1
STR = 2
outpath = os.path.splitext(path)[0] + '.mo'
infile = open(path)
try:
lines = infile.readlines()
finally:
infile.close()
messages = {}
section = None
fuzzy = False
lno = 0
msgid = msgstr = ''
# Parse the catalog
for line in lines:
lno += 1
# If we get a comment line after a msgstr, this is a new entry
if line[0] == '#' and section == STR:
_add(messages, msgid, msgstr, fuzzy)
section = None
fuzzy = False
# Record a fuzzy mark
if line[:2] == '#,' and 'fuzzy' in line:
fuzzy = True
# Skip comments
if line[0] == '#':
continue
# Now we are in a msgid section, output previous section
if line.startswith('msgid'):
if section == STR:
_add(msgid, msgstr, fuzzy)
section = ID
line = line[5:]
msgid = msgstr = ''
# Now we are in a msgstr section
elif line.startswith('msgstr'):
section = STR
line = line[6:]
# Skip empty lines
line = line.strip()
if not line:
continue
# XXX: Does this always follow Python escape semantics?
line = eval(line)
if section == ID:
msgid += line
elif section == STR:
msgstr += line
else:
raise ValueError('Syntax error on %s:%d' % (path, lno))
# Add last entry
if section == STR:
_add(messages, msgid, msgstr, fuzzy)
# Compute output
output = _generate(messages)
outfile = open(outpath, 'wb')
try:
outfile.write(output)
finally:
outfile.close()