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