1
1
# -*- coding: utf-8 -*-
3
# Copyright (C) 2007 Edgewall Software
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.
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/.
14
"""Writing of files in the ``gettext`` MO (machine object) format.
17
:see: `The Format of MO Files
18
<http://www.gnu.org/software/gettext/manual/gettext.html#MO-Files>`_
6
Writing of files in the ``gettext`` MO (machine object) format.
8
:copyright: (c) 2013 by the Babel Team.
9
:license: BSD, see LICENSE for more details.
24
__all__ = ['write_mo']
25
__docformat__ = 'restructuredtext en'
15
from babel.messages.catalog import Catalog, Message
16
from babel._compat import range_type
24
"""Read a binary MO file from the given file-like object and return a
25
corresponding `Catalog` object.
27
:param fileobj: the file-like object to read the MO file from
29
:note: The implementation of this function is heavily based on the
30
``GNUTranslations._parse`` method of the ``gettext`` module in the
36
filename = getattr(fileobj, 'name', '')
40
unpack = struct.unpack
42
# Parse the .mo file header, which consists of 5 little endian 32
44
magic = unpack('<I', buf[:4])[0] # Are we big endian or little endian?
46
version, msgcount, origidx, transidx = unpack('<4I', buf[4:20])
48
elif magic == BE_MAGIC:
49
version, msgcount, origidx, transidx = unpack('>4I', buf[4:20])
52
raise IOError(0, 'Bad magic number', filename)
54
# Now put all messages from the .mo file buffer into the catalog
56
for i in range_type(0, msgcount):
57
mlen, moff = unpack(ii, buf[origidx:origidx + 8])
59
tlen, toff = unpack(ii, buf[transidx:transidx + 8])
61
if mend < buflen and tend < buflen:
65
raise IOError(0, 'File is corrupt', filename)
67
# See if we're looking at GNU .mo conventions for metadata
71
for item in tmsg.splitlines():
76
key, value = item.split(b':', 1)
77
lastkey = key = key.strip().lower()
78
headers[key] = value.strip()
80
headers[lastkey] += b'\n' + item
82
if b'\x04' in msg: # context
83
ctxt, msg = msg.split(b'\x04')
87
if b'\x00' in msg: # plural forms
88
msg = msg.split(b'\x00')
89
tmsg = tmsg.split(b'\x00')
91
msg = [x.decode(catalog.charset) for x in msg]
92
tmsg = [x.decode(catalog.charset) for x in tmsg]
95
msg = msg.decode(catalog.charset)
96
tmsg = tmsg.decode(catalog.charset)
97
catalog[msg] = Message(msg, tmsg, context=ctxt)
99
# advance to next entry in the seek tables
103
catalog.mime_headers = headers.items()
27
107
def write_mo(fileobj, catalog, use_fuzzy=False):
28
108
"""Write a catalog to the specified file-like object using the GNU MO file
31
111
>>> from babel.messages import Catalog
32
112
>>> from gettext import GNUTranslations
33
113
>>> from StringIO import StringIO
35
115
>>> catalog = Catalog(locale='en_US')
36
116
>>> catalog.add('foo', 'Voh')
37
118
>>> catalog.add((u'bar', u'baz'), (u'Bahr', u'Batz'))
38
120
>>> catalog.add('fuz', 'Futz', flags=['fuzzy'])
39
122
>>> catalog.add('Fizz', '')
40
124
>>> catalog.add(('Fuzz', 'Fuzzes'), ('', ''))
41
126
>>> buf = StringIO()
43
128
>>> write_mo(buf, catalog)
45
130
>>> translations = GNUTranslations(fp=buf)