# -*- coding: utf-8 -*-
#
-# Copyright (C) 2007 Edgewall Software
+# Copyright (C) 2007-2008 Edgewall Software
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
"""Representation of a single message in a catalog."""
def __init__(self, id, string=u'', locations=(), flags=(), auto_comments=(),
- user_comments=(), previous_id=(), lineno=None):
+ user_comments=(), previous_id=(), lineno=None, context=None):
"""Create the message object.
:param id: the message ID, or a ``(singular, plural)`` tuple for
tuple for pluralizable messages
:param lineno: the line number on which the msgid line was found in the
PO file, if any
+ :param context: the message context
"""
self.id = id #: The message ID
if not string and self.pluralizable:
else:
self.previous_id = list(previous_id)
self.lineno = lineno
+ self.context = context
def __repr__(self):
return '<%s %r (flags: %r)>' % (type(self).__name__, self.id,
def clone(self):
return Message(self.id, self.string, self.locations, self.flags,
self.auto_comments, self.user_comments,
- self.previous_id, self.lineno)
+ self.previous_id, self.lineno, self.context)
def fuzzy(self):
return 'fuzzy' in self.flags
self._messages[key] = message
def add(self, id, string=None, locations=(), flags=(), auto_comments=(),
- user_comments=(), previous_id=(), lineno=None):
+ user_comments=(), previous_id=(), lineno=None, context=None):
"""Add or update the message with the specified ID.
>>> catalog = Catalog()
tuple for pluralizable messages
:param lineno: the line number on which the msgid line was found in the
PO file, if any
+ :param context: the message context
"""
self[id] = Message(id, string, list(locations), flags, auto_comments,
- user_comments, previous_id, lineno=lineno)
+ user_comments, previous_id, lineno=lineno,
+ context=context)
def check(self):
"""Run various validation checks on the translations in the catalog.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
-# Copyright (C) 2007 Edgewall Software
+# Copyright (C) 2007-2008 Edgewall Software
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# -*- coding: utf-8 -*-
#
-# Copyright (C) 2007 Edgewall Software
+# Copyright (C) 2007-2008 Edgewall Software
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
catalog = Catalog()
headers = {}
- unpack = struct.unpack
filename = getattr(fileobj, 'name', '')
charset = None
buf = fileobj.read()
buflen = len(buf)
+ unpack = struct.unpack
# Parse the .mo file header, which consists of 5 little endian 32
# bit words.
magic = unpack('<I', buf[:4])[0] # Are we big endian or little endian?
if magic == LE_MAGIC:
- version, msgcount, masteridx, transidx = unpack('<4I', buf[4:20])
+ version, msgcount, origidx, transidx = unpack('<4I', buf[4:20])
ii = '<II'
elif magic == BE_MAGIC:
- version, msgcount, masteridx, transidx = unpack('>4I', buf[4:20])
+ version, msgcount, origidx, transidx = unpack('>4I', buf[4:20])
ii = '>II'
else:
raise IOError(0, 'Bad magic number', filename)
# Now put all messages from the .mo file buffer into the catalog
# dictionary
for i in xrange(0, msgcount):
- mlen, moff = unpack(ii, buf[masteridx:masteridx + 8])
+ mlen, moff = unpack(ii, buf[origidx:origidx + 8])
mend = moff + mlen
tlen, toff = unpack(ii, buf[transidx:transidx + 8])
tend = toff + tlen
if ':' in item:
key, value = item.split(':', 1)
lastkey = key = key.strip().lower()
- value = value.strip()
- headers[key] = value
- if key == 'content-type':
- charset = value.split('charset=')[1]
+ headers[key] = value.strip()
elif lastkey:
- self._info[lastkey] += '\n' + item
-
- # Note: we unconditionally convert both msgids and msgstrs to
- # Unicode using the character encoding specified in the charset
- # parameter of the Content-Type header. The gettext documentation
- # strongly encourages msgids to be us-ascii, but some appliations
- # require alternative encodings (e.g. Zope's ZCML and ZPT). For
- # traditional gettext applications, the msgid conversion will
- # cause no problems since us-ascii should always be a subset of
- # the charset encoding. We may want to fall back to 8-bit msgids
- # if the Unicode conversion fails.
- if '\x00' in msg:
- # Plural forms
+ headers[lastkey] += '\n' + item
+
+ if '\x04' in msg: # context
+ ctxt, msg = msg.split('\x04')
+ else:
+ ctxt = None
+
+ if '\x00' in msg: # plural forms
msg = msg.split('\x00')
tmsg = tmsg.split('\x00')
- if charset:
- msg = [unicode(x, charset) for x in msg]
- tmsg = [unicode(x, charset) for x in tmsg]
+ if catalog.charset:
+ msg = [x.decode(catalog.charset) for x in msg]
+ tmsg = [x.decode(catalog.charset) for x in tmsg]
else:
- if charset:
- msg = unicode(msg, charset)
- tmsg = unicode(tmsg, charset)
- catalog[msg] = Message(msg, tmsg)
+ if catalog.charset:
+ msg = msg.decode(catalog.charset)
+ tmsg = tmsg.decode(catalog.charset)
+ catalog[msg] = Message(msg, tmsg, context=ctxt)
# advance to next entry in the seek tables
- masteridx += 8
+ origidx += 8
transidx += 8
catalog.mime_headers = headers.items()
msgstr = message.id.encode(catalog.charset)
else:
msgstr = message.string.encode(catalog.charset)
+ if message.context:
+ msgid = '\x04'.join(message.context.encode(catalog.charset), msgid)
offsets.append((len(ids), len(msgid), len(strs), len(msgstr)))
ids += msgid + '\x00'
strs += msgstr + '\x00'
# -*- coding: utf-8 -*-
#
-# Copyright (C) 2007 Edgewall Software
+# Copyright (C) 2007-2008 Edgewall Software
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# Chuvash
'cv': (1, '0'),
# Welsh
- 'cy': (5, 'n==1 ? 1 : n==2 ? 2 : n==3 ? 3 : n==6 ? 4 : 0'),
+ 'cy': (5, '(n==1 ? 1 : n==2 ? 2 : n==3 ? 3 : n==6 ? 4 : 0)'),
# Danish
'da': (2, '(n != 1)'),
# German
# Friulian - From Pootle's PO's
'fur': (2, '(n > 1)'),
# Irish
- 'ga': (3, 'n==1 ? 0 : n==2 ? 1 : 2'),
+ 'ga': (3, '(n==1 ? 0 : n==2 ? 1 : 2)'),
# Galician - From Pootle's PO's
'gl': (2, '(n != 1)'),
# Hausa - From Pootle's PO's
- 'ha': (2, '(n != 1)'),
+ 'ha': (2, '(n != 1)'),
# Hebrew
'he': (2, '(n != 1)'),
# Hindi - From Pootle's PO's
- 'hi': (2, '(n != 1)'),
+ 'hi': (2, '(n != 1)'),
# Croatian
'hr': (3, '(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)'),
# Hungarian
# -*- coding: utf-8 -*-
#
-# Copyright (C) 2007 Edgewall Software
+# Copyright (C) 2007-2008 Edgewall Software
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
user_comments = []
auto_comments = []
obsolete = [False]
+ context = []
in_msgid = [False]
in_msgstr = [False]
string = tuple([denormalize(t[1]) for t in translations])
else:
string = denormalize(translations[0][1])
+ if context:
+ msgctxt = denormalize('\n'.join(context))
+ else:
+ msgctxt = None
message = Message(msgid, string, list(locations), set(flags),
- auto_comments, user_comments, lineno=offset[0] + 1)
+ auto_comments, user_comments, lineno=offset[0] + 1,
+ context=msgctxt)
if obsolete[0]:
if not ignore_obsolete:
catalog.obsolete[msgid] = message
else:
catalog[msgid] = message
- del messages[:]; del translations[:]; del locations[:];
- del flags[:]; del auto_comments[:]; del user_comments[:]
+ del messages[:]; del translations[:]; del context[:]; del locations[:];
+ del flags[:]; del auto_comments[:]; del user_comments[:];
obsolete[0] = False
counter[0] += 1
translations.append([int(idx), msg.lstrip()])
else:
translations.append([0, msg])
+ elif line.startswith('msgctxt'):
+ in_msgid[0] = in_msgstr[0] = False
+ context.append(line[7:].lstrip())
elif line.startswith('"'):
if in_msgid[0]:
messages[-1] += u'\n' + line.rstrip()
elif in_msgstr[0]:
translations[-1][1] += u'\n' + line.rstrip()
+ elif in_msgctxt[0]:
+ context.append(line.rstrip())
for lineno, line in enumerate(fileobj.readlines()):
line = line.strip().decode(catalog.charset)
# -*- coding: utf-8 -*-
#
-# Copyright (C) 2007 Edgewall Software
+# Copyright (C) 2007-2008 Edgewall Software
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
import unittest
def suite():
- from babel.messages.tests import catalog, extract, frontend, mofile, pofile
+ from babel.messages.tests import catalog, extract, frontend, mofile, \
+ plurals, pofile
suite = unittest.TestSuite()
suite.addTest(catalog.suite())
suite.addTest(extract.suite())
suite.addTest(frontend.suite())
suite.addTest(mofile.suite())
+ suite.addTest(plurals.suite())
suite.addTest(pofile.suite())
return suite
# -*- coding: utf-8 -*-
#
-# Copyright (C) 2007 Edgewall Software
+# Copyright (C) 2007-2008 Edgewall Software
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# -*- coding: utf-8 -*-
#
-# Copyright (C) 2007 Edgewall Software
+# Copyright (C) 2007-2008 Edgewall Software
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
--- /dev/null
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2008 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/.
+
+import doctest
+import unittest
+
+from babel.messages import plurals
+
+def suite():
+ suite = unittest.TestSuite()
+ suite.addTest(doctest.DocTestSuite(plurals))
+ return suite
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='suite')
# -*- coding: utf-8 -*-
#
-# Copyright (C) 2007 Edgewall Software
+# Copyright (C) 2007-2008 Edgewall Software
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
self.assertEqual(1, len(catalog))
self.assertEqual(0, len(catalog.obsolete))
+ def test_with_context(self):
+ buf = StringIO(r'''# Some string in the menu
+#: main.py:1
+msgctxt "Menu"
+msgid "foo"
+msgstr "Voh"
+
+# Another string in the menu
+#: main.py:2
+msgctxt "Menu"
+msgid "bar"
+msgstr "Bahr"
+''')
+ catalog = pofile.read_po(buf, ignore_obsolete=True)
+ self.assertEqual(2, len(catalog))
+ message = catalog['foo']
+ self.assertEqual('Menu', message.context)
+ message = catalog['bar']
+ self.assertEqual('Menu', message.context)
+
class WritePoTestCase(unittest.TestCase):