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