162
|
1 # -*- coding: utf-8 -*-
|
|
2 #
|
|
3 # Copyright (C) 2007 Edgewall Software
|
|
4 # All rights reserved.
|
|
5 #
|
|
6 # This software is licensed as described in the file COPYING, which
|
|
7 # you should have received as part of this distribution. The terms
|
|
8 # are also available at http://babel.edgewall.org/wiki/License.
|
|
9 #
|
|
10 # This software consists of voluntary contributions made by many
|
|
11 # individuals. For the exact contribution history, see the revision
|
|
12 # history and logs, available at http://babel.edgewall.org/log/.
|
|
13
|
|
14 """Writing of files in the ``gettext`` MO (machine object) format.
|
|
15
|
|
16 :see: `The Format of MO Files
|
|
17 <http://www.gnu.org/software/gettext/manual/gettext.html#MO-Files>`_
|
|
18 """
|
|
19
|
|
20 import array
|
|
21 import struct
|
|
22
|
163
|
23 __all__ = ['write_mo']
|
|
24 __docformat__ = 'restructuredtext en'
|
|
25
|
162
|
26 def write_mo(fileobj, catalog, use_fuzzy=False):
|
|
27 """Write a catalog to the specified file-like object using the GNU MO file
|
|
28 format.
|
|
29
|
|
30 >>> from babel.messages import Catalog
|
|
31 >>> from gettext import GNUTranslations
|
|
32 >>> from StringIO import StringIO
|
|
33
|
|
34 >>> catalog = Catalog(locale='en_US')
|
|
35 >>> catalog.add('foo', 'Voh')
|
|
36 >>> catalog.add((u'bar', u'baz'), (u'Bahr', u'Batz'))
|
|
37 >>> catalog.add('fuz', 'Futz', flags=['fuzzy'])
|
174
|
38 >>> catalog.add('Fizz', '')
|
162
|
39 >>> buf = StringIO()
|
|
40
|
|
41 >>> write_mo(buf, catalog)
|
|
42 >>> buf.seek(0)
|
|
43 >>> translations = GNUTranslations(fp=buf)
|
|
44 >>> translations.ugettext('foo')
|
|
45 u'Voh'
|
|
46 >>> translations.ungettext('bar', 'baz', 1)
|
|
47 u'Bahr'
|
|
48 >>> translations.ungettext('bar', 'baz', 2)
|
|
49 u'Batz'
|
|
50 >>> translations.ugettext('fuz')
|
|
51 u'fuz'
|
174
|
52 >>> translations.ugettext('Fizz')
|
|
53 u'Fizz'
|
162
|
54
|
|
55 :param fileobj: the file-like object to write to
|
|
56 :param catalog: the `Catalog` instance
|
|
57 :param use_fuzzy: whether translations marked as "fuzzy" should be included
|
|
58 in the output
|
|
59 """
|
|
60 messages = list(catalog)
|
|
61 if not use_fuzzy:
|
|
62 messages[1:] = [m for m in messages[1:] if not m.fuzzy]
|
|
63 messages.sort(lambda x,y: cmp(x.id, y.id))
|
|
64
|
|
65 ids = strs = ''
|
|
66 offsets = []
|
|
67
|
|
68 for message in messages:
|
|
69 # For each string, we need size and file offset. Each string is NUL
|
|
70 # terminated; the NUL does not count into the size.
|
|
71 if message.pluralizable:
|
|
72 msgid = '\x00'.join([
|
|
73 msgid.encode(catalog.charset) for msgid in message.id
|
|
74 ])
|
|
75 msgstr = '\x00'.join([
|
|
76 msgstr.encode(catalog.charset) for msgstr in message.string
|
|
77 ])
|
|
78 else:
|
|
79 msgid = message.id.encode(catalog.charset)
|
174
|
80 if not message.string:
|
|
81 msgstr = message.id.encode(catalog.charset)
|
|
82 else:
|
|
83 msgstr = message.string.encode(catalog.charset)
|
162
|
84 offsets.append((len(ids), len(msgid), len(strs), len(msgstr)))
|
|
85 ids += msgid + '\x00'
|
|
86 strs += msgstr + '\x00'
|
|
87
|
|
88 # The header is 7 32-bit unsigned integers. We don't use hash tables, so
|
|
89 # the keys start right after the index tables.
|
|
90 keystart = 7 * 4 + 16 * len(messages)
|
|
91 valuestart = keystart + len(ids)
|
|
92
|
|
93 # The string table first has the list of keys, then the list of values.
|
|
94 # Each entry has first the size of the string, then the file offset.
|
|
95 koffsets = []
|
|
96 voffsets = []
|
|
97 for o1, l1, o2, l2 in offsets:
|
|
98 koffsets += [l1, o1 + keystart]
|
|
99 voffsets += [l2, o2 + valuestart]
|
|
100 offsets = koffsets + voffsets
|
|
101
|
|
102 fileobj.write(struct.pack('Iiiiiii',
|
|
103 0x950412deL, # magic
|
|
104 0, # version
|
|
105 len(messages), # number of entries
|
|
106 7 * 4, # start of key index
|
|
107 7 * 4 + len(messages) * 8, # start of value index
|
|
108 0, 0 # size and offset of hash table
|
|
109 ) + array.array("i", offsets).tostring() + ids + strs)
|