Using zope.i18nmessageid
Rationale
To translate any text, we must be able to discover the source domain of the text. A source domain is an identifier that identifies a project that produces program source strings. Source strings occur as literals in python programs, text in templates, and some text in XML data. The project implies a source language and an application context.
Messages and Domains
We can think of a source domain as a collection of messages and
associated translation strings. The domain helps to disambiguate messages
based on context: for instance, the message whose source string is draw
means one thing in a first-person shooter game, and quite another in a
graphics package: in the first case, the domain for the message might
be ok_corral
, while in the second it might be gimp
.
We often need to create unicode strings that will be displayed by
separate views. The view cannot translate the string without knowing
its source domain. A string or unicode literal carries no domain
information, therefore we use instances of the
Message
class. Messages are unicode
strings which carry a translation source domain and possibly a default
translation.
Message Factories
Messages are created by a message factory belonging to a given translation
domain. Each message factory is created by instantiating a
MessageFactory
, passing the domain
corresponding to the project which manages the corrresponding translations.
>>> from zope.i18nmessageid import MessageFactory
>>> factory = MessageFactory('myproject')
>>> foo = factory('foo')
>>> foo.domain
'myproject'
The Zope project uses the zope
domain for its messages. This package
exports an already-created factory for that domain:
>>> from zope.i18nmessageid import ZopeMessageFactory as _z_
>>> foo = _z_('foo')
>>> foo.domain
'zope'
Example Usage
In this example, we create a message factory and assign it to _. By convention, we use _ as the name of our factory to be compatible with translatable string extraction tools such as xgettext. We then call _ with a string that needs to be translatable:
>>> from zope.i18nmessageid import MessageFactory, Message
>>> _ = MessageFactory("futurama")
>>> robot = _(u"robot-message", u"${name} is a robot.")
Messages at first seem like they are text strings:
>>> robot == 'robot-message'
True
>>> isinstance(robot, str)
True
The additional domain, default and mapping information is available through attributes:
>>> robot.default == '${name} is a robot.'
True
>>> robot.mapping
>>> robot.domain
'futurama'
The message’s attributes are considered part of the immutable message object. They cannot be changed once the message id is created:
>>> robot.domain = "planetexpress"
Traceback (most recent call last):
...
AttributeError: readonly attribute
>>> robot.default = u"${name} is not a robot."
Traceback (most recent call last):
...
AttributeError: readonly attribute
>>> robot.mapping = {'name': 'Bender'}
Traceback (most recent call last):
...
AttributeError: readonly attribute
If you need to change their information, yo’ll have to make a new message id object:
>>> new_robot = Message(robot, mapping={'name': 'Bender'})
>>> new_robot == 'robot-message'
True
>>> new_robot.domain
'futurama'
>>> new_robot.default == '${name} is a robot.'
True
>>> new_robot.mapping == {'name': 'Bender'}
True
Last but not least, messages are reduceable for pickling:
>>> callable, args = new_robot.__reduce__()
>>> callable is Message
True
>>> args == ('robot-message',
... 'futurama',
... '${name} is a robot.',
... {'name': 'Bender'},
... None,
... None,
... None)
True
>>> fembot = Message('fembot')
>>> callable, args = fembot.__reduce__()
>>> callable is Message
True
>>> args == ('fembot', None, None, None, None, None, None)
True
Pickling and unpickling works, which means we can store message IDs in a database:
>>> from pickle import dumps, loads
>>> pystate = dumps(new_robot)
>>> pickle_bot = loads(pystate)
>>> (pickle_bot,
... pickle_bot.domain,
... pickle_bot.default,
... pickle_bot.mapping) == ('robot-message',
... 'futurama',
... '${name} is a robot.',
... {'name': 'Bender'})
True
>>> pickle_bot.__reduce__()[0] is Message
True