cmlenz@162: # -*- coding: utf-8 -*- cmlenz@162: # cmlenz@162: # Copyright (C) 2007 Edgewall Software cmlenz@162: # All rights reserved. cmlenz@162: # cmlenz@162: # This software is licensed as described in the file COPYING, which cmlenz@162: # you should have received as part of this distribution. The terms cmlenz@162: # are also available at http://babel.edgewall.org/wiki/License. cmlenz@162: # cmlenz@162: # This software consists of voluntary contributions made by many cmlenz@162: # individuals. For the exact contribution history, see the revision cmlenz@162: # history and logs, available at http://babel.edgewall.org/log/. cmlenz@162: cmlenz@162: """Writing of files in the ``gettext`` MO (machine object) format. cmlenz@162: cmlenz@162: :see: `The Format of MO Files cmlenz@162: `_ cmlenz@162: """ cmlenz@162: cmlenz@162: import array cmlenz@162: import struct cmlenz@162: cmlenz@163: __all__ = ['write_mo'] cmlenz@163: __docformat__ = 'restructuredtext en' cmlenz@163: cmlenz@162: def write_mo(fileobj, catalog, use_fuzzy=False): cmlenz@162: """Write a catalog to the specified file-like object using the GNU MO file cmlenz@162: format. cmlenz@162: cmlenz@162: >>> from babel.messages import Catalog cmlenz@162: >>> from gettext import GNUTranslations cmlenz@162: >>> from StringIO import StringIO cmlenz@162: cmlenz@162: >>> catalog = Catalog(locale='en_US') cmlenz@162: >>> catalog.add('foo', 'Voh') cmlenz@162: >>> catalog.add((u'bar', u'baz'), (u'Bahr', u'Batz')) cmlenz@162: >>> catalog.add('fuz', 'Futz', flags=['fuzzy']) cmlenz@162: >>> buf = StringIO() cmlenz@162: cmlenz@162: >>> write_mo(buf, catalog) cmlenz@162: >>> buf.seek(0) cmlenz@162: >>> translations = GNUTranslations(fp=buf) cmlenz@162: >>> translations.ugettext('foo') cmlenz@162: u'Voh' cmlenz@162: >>> translations.ungettext('bar', 'baz', 1) cmlenz@162: u'Bahr' cmlenz@162: >>> translations.ungettext('bar', 'baz', 2) cmlenz@162: u'Batz' cmlenz@162: >>> translations.ugettext('fuz') cmlenz@162: u'fuz' cmlenz@162: cmlenz@162: :param fileobj: the file-like object to write to cmlenz@162: :param catalog: the `Catalog` instance cmlenz@162: :param use_fuzzy: whether translations marked as "fuzzy" should be included cmlenz@162: in the output cmlenz@162: """ cmlenz@162: messages = list(catalog) cmlenz@162: if not use_fuzzy: cmlenz@162: messages[1:] = [m for m in messages[1:] if not m.fuzzy] cmlenz@162: messages.sort(lambda x,y: cmp(x.id, y.id)) cmlenz@162: cmlenz@162: ids = strs = '' cmlenz@162: offsets = [] cmlenz@162: cmlenz@162: for message in messages: cmlenz@162: # For each string, we need size and file offset. Each string is NUL cmlenz@162: # terminated; the NUL does not count into the size. cmlenz@162: if message.pluralizable: cmlenz@162: msgid = '\x00'.join([ cmlenz@162: msgid.encode(catalog.charset) for msgid in message.id cmlenz@162: ]) cmlenz@162: msgstr = '\x00'.join([ cmlenz@162: msgstr.encode(catalog.charset) for msgstr in message.string cmlenz@162: ]) cmlenz@162: else: cmlenz@162: msgid = message.id.encode(catalog.charset) cmlenz@162: msgstr = message.string.encode(catalog.charset) cmlenz@162: offsets.append((len(ids), len(msgid), len(strs), len(msgstr))) cmlenz@162: ids += msgid + '\x00' cmlenz@162: strs += msgstr + '\x00' cmlenz@162: cmlenz@162: # The header is 7 32-bit unsigned integers. We don't use hash tables, so cmlenz@162: # the keys start right after the index tables. cmlenz@162: keystart = 7 * 4 + 16 * len(messages) cmlenz@162: valuestart = keystart + len(ids) cmlenz@162: cmlenz@162: # The string table first has the list of keys, then the list of values. cmlenz@162: # Each entry has first the size of the string, then the file offset. cmlenz@162: koffsets = [] cmlenz@162: voffsets = [] cmlenz@162: for o1, l1, o2, l2 in offsets: cmlenz@162: koffsets += [l1, o1 + keystart] cmlenz@162: voffsets += [l2, o2 + valuestart] cmlenz@162: offsets = koffsets + voffsets cmlenz@162: cmlenz@162: fileobj.write(struct.pack('Iiiiiii', cmlenz@162: 0x950412deL, # magic cmlenz@162: 0, # version cmlenz@162: len(messages), # number of entries cmlenz@162: 7 * 4, # start of key index cmlenz@162: 7 * 4 + len(messages) * 8, # start of value index cmlenz@162: 0, 0 # size and offset of hash table cmlenz@162: ) + array.array("i", offsets).tostring() + ids + strs)