from django.utils.translation import ungettext, ugettext as _ from django.utils.encoding import force_unicode from django import template from django.template import defaultfilters from datetime import date import re register = template.Library() def ordinal(value): """ Converts an integer to its ordinal as a string. 1 is '1st', 2 is '2nd', 3 is '3rd', etc. Works for any integer. """ try: value = int(value) except (TypeError, ValueError): return value t = (_('th'), _('st'), _('nd'), _('rd'), _('th'), _('th'), _('th'), _('th'), _('th'), _('th')) if value % 100 in (11, 12, 13): # special case return u"%d%s" % (value, t[0]) return u'%d%s' % (value, t[value % 10]) ordinal.is_safe = True register.filter(ordinal) def intcomma(value): """ Converts an integer to a string containing commas every three digits. For example, 3000 becomes '3,000' and 45000 becomes '45,000'. """ orig = force_unicode(value) new = re.sub("^(-?\d+)(\d{3})", '\g<1>,\g<2>', orig) if orig == new: return new else: return intcomma(new) intcomma.is_safe = True register.filter(intcomma) def intword(value): """ Converts a large integer to a friendly text representation. Works best for numbers over 1 million. For example, 1000000 becomes '1.0 million', 1200000 becomes '1.2 million' and '1200000000' becomes '1.2 billion'. """ try: value = int(value) except (TypeError, ValueError): return value if value < 1000000: return value if value < 1000000000: new_value = value / 1000000.0 return ungettext('%(value).1f million', '%(value).1f million', new_value) % {'value': new_value} if value < 1000000000000: new_value = value / 1000000000.0 return ungettext('%(value).1f billion', '%(value).1f billion', new_value) % {'value': new_value} if value < 1000000000000000: new_value = value / 1000000000000.0 return ungettext('%(value).1f trillion', '%(value).1f trillion', new_value) % {'value': new_value} return value intword.is_safe = False register.filter(intword) def apnumber(value): """ For numbers 1-9, returns the number spelled out. Otherwise, returns the number. This follows Associated Press style. """ try: value = int(value) except (TypeError, ValueError): return value if not 0 < value < 10: return value return (_('one'), _('two'), _('three'), _('four'), _('five'), _('six'), _('seven'), _('eight'), _('nine'))[value-1] apnumber.is_safe = True register.filter(apnumber) def naturalday(value, arg=None): """ For date values that are tomorrow, today or yesterday compared to present day returns representing string. Otherwise, returns a string formatted according to settings.DATE_FORMAT. """ try: value = date(value.year, value.month, value.day) except AttributeError: # Passed value wasn't a date object return value except ValueError: # Date arguments out of range return value delta = value - date.today() if delta.days == 0: return _(u'today') elif delta.days == 1: return _(u'tomorrow') elif delta.days == -1: return _(u'yesterday') return defaultfilters.date(value, arg) register.filter(naturalday)