53
48
def date(self, date=None, format='medium'):
54
49
"""Return a date formatted according to the given pattern.
51
>>> from datetime import date
56
52
>>> fmt = Format('en_US')
57
53
>>> fmt.date(date(2007, 4, 1))
60
:see: `babel.dates.format_date`
62
56
return format_date(date, format, locale=self.locale)
64
58
def datetime(self, datetime=None, format='medium'):
65
59
"""Return a date and time formatted according to the given pattern.
61
>>> from datetime import datetime
67
62
>>> from pytz import timezone
68
63
>>> fmt = Format('en_US', tzinfo=timezone('US/Eastern'))
69
64
>>> fmt.datetime(datetime(2007, 4, 1, 15, 30))
70
u'Apr 1, 2007 11:30:00 AM'
72
:see: `babel.dates.format_datetime`
65
u'Apr 1, 2007, 11:30:00 AM'
74
67
return format_datetime(datetime, format, tzinfo=self.tzinfo,
75
68
locale=self.locale)
77
70
def time(self, time=None, format='medium'):
78
71
"""Return a time formatted according to the given pattern.
73
>>> from datetime import datetime
80
74
>>> from pytz import timezone
81
75
>>> fmt = Format('en_US', tzinfo=timezone('US/Eastern'))
82
76
>>> fmt.time(datetime(2007, 4, 1, 15, 30))
85
:see: `babel.dates.format_time`
87
79
return format_time(time, format, tzinfo=self.tzinfo, locale=self.locale)
81
def timedelta(self, delta, granularity='second', threshold=.85,
82
format='medium', add_direction=False):
83
"""Return a time delta according to the rules of the given locale.
85
>>> from datetime import timedelta
86
>>> fmt = Format('en_US')
87
>>> fmt.timedelta(timedelta(weeks=11))
90
return format_timedelta(delta, granularity=granularity,
92
format=format, add_direction=add_direction,
89
95
def number(self, number):
90
96
"""Return an integer number formatted for the locale.
92
98
>>> fmt = Format('en_US')
93
99
>>> fmt.number(1099)
96
:see: `babel.numbers.format_number`
98
102
return format_number(number, locale=self.locale)
100
104
def decimal(self, number, format=None):
101
105
"""Return a decimal number formatted for the locale.
103
107
>>> fmt = Format('en_US')
104
108
>>> fmt.decimal(1.2345)
107
:see: `babel.numbers.format_decimal`
109
111
return format_decimal(number, format, locale=self.locale)
111
113
def currency(self, number, currency):
112
114
"""Return a number in the given currency formatted for the locale.
114
:see: `babel.numbers.format_currency`
116
116
return format_currency(number, currency, locale=self.locale)
118
118
def percent(self, number, format=None):
119
119
"""Return a number formatted as percentage for the locale.
121
121
>>> fmt = Format('en_US')
122
122
>>> fmt.percent(0.34)
125
:see: `babel.numbers.format_percent`
127
125
return format_percent(number, format, locale=self.locale)
129
127
def scientific(self, number):
130
128
"""Return a number formatted using scientific notation for the locale.
132
:see: `babel.numbers.format_scientific`
134
130
return format_scientific(number, locale=self.locale)
263
263
def __setitem__(self, key, value):
264
264
self.value[key] = value
267
class Translations(gettext.GNUTranslations, object):
267
class NullTranslations(gettext.NullTranslations, object):
269
DEFAULT_DOMAIN = None
271
def __init__(self, fp=None):
272
"""Initialize a simple translations class which is not backed by a
273
real catalog. Behaves similar to gettext.NullTranslations but also
274
offers Babel's on *gettext methods (e.g. 'dgettext()').
276
:param fp: a file-like object (ignored in this class)
278
# These attributes are set by gettext.NullTranslations when a catalog
279
# is parsed (fp != None). Ensure that they are always present because
280
# some *gettext methods (including '.gettext()') rely on the attributes.
282
self.plural = lambda n: int(n != 1)
283
super(NullTranslations, self).__init__(fp=fp)
284
self.files = filter(None, [getattr(fp, 'name', None)])
285
self.domain = self.DEFAULT_DOMAIN
288
def dgettext(self, domain, message):
289
"""Like ``gettext()``, but look the message up in the specified
292
return self._domains.get(domain, self).gettext(message)
294
def ldgettext(self, domain, message):
295
"""Like ``lgettext()``, but look the message up in the specified
298
return self._domains.get(domain, self).lgettext(message)
300
def udgettext(self, domain, message):
301
"""Like ``ugettext()``, but look the message up in the specified
304
return self._domains.get(domain, self).ugettext(message)
305
# backward compatibility with 0.9
306
dugettext = udgettext
308
def dngettext(self, domain, singular, plural, num):
309
"""Like ``ngettext()``, but look the message up in the specified
312
return self._domains.get(domain, self).ngettext(singular, plural, num)
314
def ldngettext(self, domain, singular, plural, num):
315
"""Like ``lngettext()``, but look the message up in the specified
318
return self._domains.get(domain, self).lngettext(singular, plural, num)
320
def udngettext(self, domain, singular, plural, num):
321
"""Like ``ungettext()`` but look the message up in the specified
324
return self._domains.get(domain, self).ungettext(singular, plural, num)
325
# backward compatibility with 0.9
326
dungettext = udngettext
328
# Most of the downwards code, until it get's included in stdlib, from:
329
# http://bugs.python.org/file10036/gettext-pgettext.patch
331
# The encoding of a msgctxt and a msgid in a .mo file is
332
# msgctxt + "\x04" + msgid (gettext version >= 0.15)
333
CONTEXT_ENCODING = '%s\x04%s'
335
def pgettext(self, context, message):
336
"""Look up the `context` and `message` id in the catalog and return the
337
corresponding message string, as an 8-bit string encoded with the
338
catalog's charset encoding, if known. If there is no entry in the
339
catalog for the `message` id and `context` , and a fallback has been
340
set, the look up is forwarded to the fallback's ``pgettext()``
341
method. Otherwise, the `message` id is returned.
343
ctxt_msg_id = self.CONTEXT_ENCODING % (context, message)
345
tmsg = self._catalog.get(ctxt_msg_id, missing)
348
return self._fallback.pgettext(context, message)
350
# Encode the Unicode tmsg back to an 8-bit string, if possible
351
if self._output_charset:
352
return text_to_native(tmsg, self._output_charset)
354
return text_to_native(tmsg, self._charset)
357
def lpgettext(self, context, message):
358
"""Equivalent to ``pgettext()``, but the translation is returned in the
359
preferred system encoding, if no other encoding was explicitly set with
360
``bind_textdomain_codeset()``.
362
ctxt_msg_id = self.CONTEXT_ENCODING % (context, message)
364
tmsg = self._catalog.get(ctxt_msg_id, missing)
367
return self._fallback.lpgettext(context, message)
369
if self._output_charset:
370
return tmsg.encode(self._output_charset)
371
return tmsg.encode(locale.getpreferredencoding())
373
def npgettext(self, context, singular, plural, num):
374
"""Do a plural-forms lookup of a message id. `singular` is used as the
375
message id for purposes of lookup in the catalog, while `num` is used to
376
determine which plural form to use. The returned message string is an
377
8-bit string encoded with the catalog's charset encoding, if known.
379
If the message id for `context` is not found in the catalog, and a
380
fallback is specified, the request is forwarded to the fallback's
381
``npgettext()`` method. Otherwise, when ``num`` is 1 ``singular`` is
382
returned, and ``plural`` is returned in all other cases.
384
ctxt_msg_id = self.CONTEXT_ENCODING % (context, singular)
386
tmsg = self._catalog[(ctxt_msg_id, self.plural(num))]
387
if self._output_charset:
388
return text_to_native(tmsg, self._output_charset)
390
return text_to_native(tmsg, self._charset)
394
return self._fallback.npgettext(context, singular, plural, num)
400
def lnpgettext(self, context, singular, plural, num):
401
"""Equivalent to ``npgettext()``, but the translation is returned in the
402
preferred system encoding, if no other encoding was explicitly set with
403
``bind_textdomain_codeset()``.
405
ctxt_msg_id = self.CONTEXT_ENCODING % (context, singular)
407
tmsg = self._catalog[(ctxt_msg_id, self.plural(num))]
408
if self._output_charset:
409
return tmsg.encode(self._output_charset)
410
return tmsg.encode(locale.getpreferredencoding())
413
return self._fallback.lnpgettext(context, singular, plural, num)
419
def upgettext(self, context, message):
420
"""Look up the `context` and `message` id in the catalog and return the
421
corresponding message string, as a Unicode string. If there is no entry
422
in the catalog for the `message` id and `context`, and a fallback has
423
been set, the look up is forwarded to the fallback's ``upgettext()``
424
method. Otherwise, the `message` id is returned.
426
ctxt_message_id = self.CONTEXT_ENCODING % (context, message)
428
tmsg = self._catalog.get(ctxt_message_id, missing)
431
return self._fallback.upgettext(context, message)
432
return text_type(message)
435
def unpgettext(self, context, singular, plural, num):
436
"""Do a plural-forms lookup of a message id. `singular` is used as the
437
message id for purposes of lookup in the catalog, while `num` is used to
438
determine which plural form to use. The returned message string is a
441
If the message id for `context` is not found in the catalog, and a
442
fallback is specified, the request is forwarded to the fallback's
443
``unpgettext()`` method. Otherwise, when `num` is 1 `singular` is
444
returned, and `plural` is returned in all other cases.
446
ctxt_message_id = self.CONTEXT_ENCODING % (context, singular)
448
tmsg = self._catalog[(ctxt_message_id, self.plural(num))]
451
return self._fallback.unpgettext(context, singular, plural, num)
453
tmsg = text_type(singular)
455
tmsg = text_type(plural)
458
def dpgettext(self, domain, context, message):
459
"""Like `pgettext()`, but look the message up in the specified
462
return self._domains.get(domain, self).pgettext(context, message)
464
def udpgettext(self, domain, context, message):
465
"""Like `upgettext()`, but look the message up in the specified
468
return self._domains.get(domain, self).upgettext(context, message)
469
# backward compatibility with 0.9
470
dupgettext = udpgettext
472
def ldpgettext(self, domain, context, message):
473
"""Equivalent to ``dpgettext()``, but the translation is returned in the
474
preferred system encoding, if no other encoding was explicitly set with
475
``bind_textdomain_codeset()``.
477
return self._domains.get(domain, self).lpgettext(context, message)
479
def dnpgettext(self, domain, context, singular, plural, num):
480
"""Like ``npgettext``, but look the message up in the specified
483
return self._domains.get(domain, self).npgettext(context, singular,
486
def udnpgettext(self, domain, context, singular, plural, num):
487
"""Like ``unpgettext``, but look the message up in the specified
490
return self._domains.get(domain, self).unpgettext(context, singular,
492
# backward compatibility with 0.9
493
dunpgettext = udnpgettext
495
def ldnpgettext(self, domain, context, singular, plural, num):
496
"""Equivalent to ``dnpgettext()``, but the translation is returned in
497
the preferred system encoding, if no other encoding was explicitly set
498
with ``bind_textdomain_codeset()``.
500
return self._domains.get(domain, self).lnpgettext(context, singular,
504
ugettext = gettext.NullTranslations.gettext
505
ungettext = gettext.NullTranslations.ngettext
508
class Translations(NullTranslations, gettext.GNUTranslations):
268
509
"""An extended translation catalog class."""
270
511
DEFAULT_DOMAIN = 'messages'
272
def __init__(self, fileobj=None, domain=DEFAULT_DOMAIN):
513
def __init__(self, fp=None, domain=None):
273
514
"""Initialize the translations catalog.
275
:param fileobj: the file-like object the translation should be read
516
:param fp: the file-like object the translation should be read from
517
:param domain: the message domain (default: 'messages')
278
gettext.GNUTranslations.__init__(self, fp=fileobj)
279
self.files = filter(None, [getattr(fileobj, 'name', None)])
283
def load(cls, dirname=None, locales=None, domain=DEFAULT_DOMAIN):
519
super(Translations, self).__init__(fp=fp)
520
self.domain = domain or self.DEFAULT_DOMAIN
523
ugettext = gettext.GNUTranslations.gettext
524
ungettext = gettext.GNUTranslations.ngettext
527
def load(cls, dirname=None, locales=None, domain=None):
284
528
"""Load translations from the given directory.
286
530
:param dirname: the directory containing the ``MO`` files
287
531
:param locales: the list of locales in order of preference (items in
288
532
this list can be either `Locale` objects or locale
290
:param domain: the message domain
291
:return: the loaded catalog, or a ``NullTranslations`` instance if no
292
matching translations were found
293
:rtype: `Translations`
534
:param domain: the message domain (default: 'messages')
295
536
if locales is not None:
296
537
if not isinstance(locales, (list, tuple)):