Refactored naturaltime to use a class-based formatter

This commit is contained in:
Claude Paroz 2018-06-03 10:33:38 +02:00
parent e0d0fc0b14
commit 56611a96df
1 changed files with 86 additions and 75 deletions

View File

@ -9,7 +9,8 @@ from django.utils.formats import number_format
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.timezone import is_aware, utc from django.utils.timezone import is_aware, utc
from django.utils.translation import ( from django.utils.translation import (
gettext as _, ngettext, npgettext_lazy, pgettext, gettext as _, gettext_lazy, ngettext, ngettext_lazy, npgettext_lazy,
pgettext,
) )
register = template.Library() register = template.Library()
@ -214,79 +215,89 @@ def naturaltime(value):
For date and time values show how many seconds, minutes, or hours ago For date and time values show how many seconds, minutes, or hours ago
compared to current timestamp return representing string. compared to current timestamp return representing string.
""" """
if not isinstance(value, date): # datetime is a subclass of date return NaturalTimeFormatter.string_for(value)
return value
now = datetime.now(utc if is_aware(value) else None)
if value < now: class NaturalTimeFormatter:
delta = now - value time_strings = {
if delta.days != 0: # Translators: delta will contain a string like '2 months' or '1 month, 2 weeks'
# Translators: delta will contain a string like '2 months' or '1 month, 2 weeks' 'past-day': gettext_lazy('%(delta)s ago'),
return _('%(delta)s ago') % {'delta': defaultfilters.timesince(value, now, time_strings={ # Translators: please keep a non-breaking space (U+00A0) between count
# Translators: 'naturaltime-past' strings will be included in # and time unit.
# '%(delta)s ago' 'past-hour': ngettext_lazy('an hour ago', '%(count)s hours ago', 'count'),
'year': npgettext_lazy('naturaltime-past', '%d year', '%d years'), # Translators: please keep a non-breaking space (U+00A0) between count
'month': npgettext_lazy('naturaltime-past', '%d month', '%d months'), # and time unit.
'week': npgettext_lazy('naturaltime-past', '%d week', '%d weeks'), 'past-minute': ngettext_lazy('a minute ago', '%(count)s minutes ago', 'count'),
'day': npgettext_lazy('naturaltime-past', '%d day', '%d days'), # Translators: please keep a non-breaking space (U+00A0) between count
'hour': npgettext_lazy('naturaltime-past', '%d hour', '%d hours'), # and time unit.
'minute': npgettext_lazy('naturaltime-past', '%d minute', '%d minutes') 'past-second': ngettext_lazy('a second ago', '%(count)s seconds ago', 'count'),
})} 'now': gettext_lazy('now'),
elif delta.seconds == 0: # Translators: please keep a non-breaking space (U+00A0) between count
return _('now') # and time unit.
elif delta.seconds < 60: 'future-second': ngettext_lazy('a second from now', '%(count)s seconds from now', 'count'),
return ngettext( # Translators: please keep a non-breaking space (U+00A0) between count
# Translators: please keep a non-breaking space (U+00A0) # and time unit.
# between count and time unit. 'future-minute': ngettext_lazy('a minute from now', '%(count)s minutes from now', 'count'),
'a second ago', '%(count)s seconds ago', delta.seconds # Translators: please keep a non-breaking space (U+00A0) between count
) % {'count': delta.seconds} # and time unit.
elif delta.seconds // 60 < 60: 'future-hour': ngettext_lazy('an hour from now', '%(count)s hours from now', 'count'),
count = delta.seconds // 60 # Translators: delta will contain a string like '2 months' or '1 month, 2 weeks'
return ngettext( 'future-day': gettext_lazy('%(delta)s from now'),
# Translators: please keep a non-breaking space (U+00A0) }
# between count and time unit. past_substrings = {
'a minute ago', '%(count)s minutes ago', count # Translators: 'naturaltime-past' strings will be included in '%(delta)s ago'
) % {'count': count} 'year': npgettext_lazy('naturaltime-past', '%d year', '%d years'),
'month': npgettext_lazy('naturaltime-past', '%d month', '%d months'),
'week': npgettext_lazy('naturaltime-past', '%d week', '%d weeks'),
'day': npgettext_lazy('naturaltime-past', '%d day', '%d days'),
'hour': npgettext_lazy('naturaltime-past', '%d hour', '%d hours'),
'minute': npgettext_lazy('naturaltime-past', '%d minute', '%d minutes'),
}
future_substrings = {
# Translators: 'naturaltime-future' strings will be included in '%(delta)s from now'
'year': npgettext_lazy('naturaltime-future', '%d year', '%d years'),
'month': npgettext_lazy('naturaltime-future', '%d month', '%d months'),
'week': npgettext_lazy('naturaltime-future', '%d week', '%d weeks'),
'day': npgettext_lazy('naturaltime-future', '%d day', '%d days'),
'hour': npgettext_lazy('naturaltime-future', '%d hour', '%d hours'),
'minute': npgettext_lazy('naturaltime-future', '%d minute', '%d minutes'),
}
@classmethod
def string_for(cls, value):
if not isinstance(value, date): # datetime is a subclass of date
return value
now = datetime.now(utc if is_aware(value) else None)
if value < now:
delta = now - value
if delta.days != 0:
return cls.time_strings['past-day'] % {
'delta': defaultfilters.timesince(value, now, time_strings=cls.past_substrings),
}
elif delta.seconds == 0:
return cls.time_strings['now']
elif delta.seconds < 60:
return cls.time_strings['past-second'] % {'count': delta.seconds}
elif delta.seconds // 60 < 60:
count = delta.seconds // 60
return cls.time_strings['past-minute'] % {'count': count}
else:
count = delta.seconds // 60 // 60
return cls.time_strings['past-hour'] % {'count': count}
else: else:
count = delta.seconds // 60 // 60 delta = value - now
return ngettext( if delta.days != 0:
# Translators: please keep a non-breaking space (U+00A0) return cls.time_strings['future-day'] % {
# between count and time unit. 'delta': defaultfilters.timeuntil(value, now, time_strings=cls.future_substrings),
'an hour ago', '%(count)s hours ago', count }
) % {'count': count} elif delta.seconds == 0:
else: return cls.time_strings['now']
delta = value - now elif delta.seconds < 60:
if delta.days != 0: return cls.time_strings['future-second'] % {'count': delta.seconds}
# Translators: delta will contain a string like '2 months' or '1 month, 2 weeks' elif delta.seconds // 60 < 60:
return _('%(delta)s from now') % {'delta': defaultfilters.timeuntil(value, now, time_strings={ count = delta.seconds // 60
# Translators: 'naturaltime-future' strings will be included in return cls.time_strings['future-minute'] % {'count': count}
# '%(delta)s from now' else:
'year': npgettext_lazy('naturaltime-future', '%d year', '%d years'), count = delta.seconds // 60 // 60
'month': npgettext_lazy('naturaltime-future', '%d month', '%d months'), return cls.time_strings['future-hour'] % {'count': count}
'week': npgettext_lazy('naturaltime-future', '%d week', '%d weeks'),
'day': npgettext_lazy('naturaltime-future', '%d day', '%d days'),
'hour': npgettext_lazy('naturaltime-future', '%d hour', '%d hours'),
'minute': npgettext_lazy('naturaltime-future', '%d minute', '%d minutes')
})}
elif delta.seconds == 0:
return _('now')
elif delta.seconds < 60:
return ngettext(
# Translators: please keep a non-breaking space (U+00A0)
# between count and time unit.
'a second from now', '%(count)s seconds from now', delta.seconds
) % {'count': delta.seconds}
elif delta.seconds // 60 < 60:
count = delta.seconds // 60
return ngettext(
# Translators: please keep a non-breaking space (U+00A0)
# between count and time unit.
'a minute from now', '%(count)s minutes from now', count
) % {'count': count}
else:
count = delta.seconds // 60 // 60
return ngettext(
# Translators: please keep a non-breaking space (U+00A0)
# between count and time unit.
'an hour from now', '%(count)s hours from now', count
) % {'count': count}