diff --git a/AUTHORS b/AUTHORS index 91d572d78b..59420932d5 100644 --- a/AUTHORS +++ b/AUTHORS @@ -559,6 +559,7 @@ answer newbie questions, and generally made Django that much better: Max Derkachev Maxime Lorant Maxime Turcotte + Maximilian Merz Maximillian Dornseif mccutchen@gmail.com Meir Kriheli diff --git a/django/contrib/humanize/locale/de/LC_MESSAGES/django.mo b/django/contrib/humanize/locale/de/LC_MESSAGES/django.mo index 7a0f3fe0ae..6a933d80b8 100644 Binary files a/django/contrib/humanize/locale/de/LC_MESSAGES/django.mo and b/django/contrib/humanize/locale/de/LC_MESSAGES/django.mo differ diff --git a/django/contrib/humanize/locale/de/LC_MESSAGES/django.po b/django/contrib/humanize/locale/de/LC_MESSAGES/django.po index 305b57f326..ed6b213d47 100644 --- a/django/contrib/humanize/locale/de/LC_MESSAGES/django.po +++ b/django/contrib/humanize/locale/de/LC_MESSAGES/django.po @@ -4,12 +4,13 @@ # André Hagenbruch, 2011 # Claude Paroz , 2013 # Jannis Leidel , 2011,2013-2014 +# Maximilian Merz , 2018 msgid "" msgstr "" "Project-Id-Version: django\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2015-01-17 11:07+0100\n" -"PO-Revision-Date: 2017-09-23 18:54+0000\n" +"PO-Revision-Date: 2018-03-13 16:07+0100\n" "Last-Translator: Jannis Leidel \n" "Language-Team: German (http://www.transifex.com/django/django/language/de/)\n" "MIME-Version: 1.0\n" @@ -202,7 +203,6 @@ msgid "yesterday" msgstr "gestern" #, python-format -msgctxt "naturaltime" msgid "%(delta)s ago" msgstr "vor %(delta)s" @@ -234,10 +234,56 @@ msgstr[0] "vor einer Stunde" msgstr[1] "vor %(count)s Stunden" #, python-format -msgctxt "naturaltime" msgid "%(delta)s from now" msgstr "in %(delta)s" +#, python-format +msgctxt "naturaltime-future" +msgid "%(delta)s from now" +msgstr "in %(delta)s" + +#, python-format +msgctxt "naturaltime-past" +msgid "%d day" +msgid_plural "%d days" +msgstr[0] "%d Tag" +msgstr[1] "%d Tagen" + +#, python-format +msgctxt "naturaltime-past" +msgid "%d month" +msgid_plural "%d months" +msgstr[0] "%d Monat" +msgstr[1] "%d Monaten" + +#, python-format +msgctxt "naturaltime-past" +msgid "%d year" +msgid_plural "%d years" +msgstr[0] "%d Jahr" +msgstr[1] "%d Jahren" + +#, python-format +msgctxt "naturaltime-future" +msgid "%d day" +msgid_plural "%d days" +msgstr[0] "%d Tag" +msgstr[1] "%d Tagen" + +#, python-format +msgctxt "naturaltime-future" +msgid "%d month" +msgid_plural "%d months" +msgstr[0] "%d Monat" +msgstr[1] "%d Monaten" + +#, python-format +msgctxt "naturaltime-future" +msgid "%d year" +msgid_plural "%d years" +msgstr[0] "%d Jahr" +msgstr[1] "%d Jahren" + #. Translators: please keep a non-breaking space (U+00A0) #. between count and time unit. #, python-format diff --git a/django/contrib/humanize/templatetags/humanize.py b/django/contrib/humanize/templatetags/humanize.py index 482725c88c..838d669834 100644 --- a/django/contrib/humanize/templatetags/humanize.py +++ b/django/contrib/humanize/templatetags/humanize.py @@ -8,7 +8,9 @@ from django.template import defaultfilters 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, pgettext +from django.utils.translation import ( + gettext as _, ngettext, npgettext_lazy, pgettext, +) register = template.Library() @@ -220,7 +222,16 @@ def naturaltime(value): 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)} + 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: @@ -247,7 +258,16 @@ def naturaltime(value): 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)} + 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: diff --git a/django/utils/timesince.py b/django/utils/timesince.py index 1616c9a2ea..139fca28a1 100644 --- a/django/utils/timesince.py +++ b/django/utils/timesince.py @@ -5,17 +5,26 @@ from django.utils.html import avoid_wrapping from django.utils.timezone import is_aware, utc from django.utils.translation import gettext, ngettext_lazy +TIME_STRINGS = { + 'year': ngettext_lazy('%d year', '%d years'), + 'month': ngettext_lazy('%d month', '%d months'), + 'week': ngettext_lazy('%d week', '%d weeks'), + 'day': ngettext_lazy('%d day', '%d days'), + 'hour': ngettext_lazy('%d hour', '%d hours'), + 'minute': ngettext_lazy('%d minute', '%d minutes'), +} + TIMESINCE_CHUNKS = ( - (60 * 60 * 24 * 365, ngettext_lazy('%d year', '%d years')), - (60 * 60 * 24 * 30, ngettext_lazy('%d month', '%d months')), - (60 * 60 * 24 * 7, ngettext_lazy('%d week', '%d weeks')), - (60 * 60 * 24, ngettext_lazy('%d day', '%d days')), - (60 * 60, ngettext_lazy('%d hour', '%d hours')), - (60, ngettext_lazy('%d minute', '%d minutes')) + (60 * 60 * 24 * 365, 'year'), + (60 * 60 * 24 * 30, 'month'), + (60 * 60 * 24 * 7, 'week'), + (60 * 60 * 24, 'day'), + (60 * 60, 'hour'), + (60, 'minute'), ) -def timesince(d, now=None, reversed=False): +def timesince(d, now=None, reversed=False, time_strings=None): """ Take two datetime objects and return the time between d and now as a nicely formatted string, e.g. "10 minutes". If d occurs after now, return @@ -26,9 +35,15 @@ def timesince(d, now=None, reversed=False): displayed. For example, "2 weeks, 3 days" and "1 year, 3 months" are possible outputs, but "2 weeks, 3 hours" and "1 year, 5 days" are not. + `time_strings` is an optional dict of strings to replace the default + TIME_STRINGS dict. + Adapted from http://web.archive.org/web/20060617175230/http://blog.natbat.co.uk/archive/2003/Jun/14/time_since """ + if time_strings is None: + time_strings = TIME_STRINGS + # Convert datetime.date to datetime.datetime for comparison. if not isinstance(d, datetime.datetime): d = datetime.datetime(d.year, d.month, d.day) @@ -59,18 +74,18 @@ def timesince(d, now=None, reversed=False): count = since // seconds if count != 0: break - result = avoid_wrapping(name % count) + result = avoid_wrapping(time_strings[name] % count) if i + 1 < len(TIMESINCE_CHUNKS): # Now get the second item seconds2, name2 = TIMESINCE_CHUNKS[i + 1] count2 = (since - (seconds * count)) // seconds2 if count2 != 0: - result += gettext(', ') + avoid_wrapping(name2 % count2) + result += gettext(', ') + avoid_wrapping(time_strings[name2] % count2) return result -def timeuntil(d, now=None): +def timeuntil(d, now=None, time_strings=None): """ Like timesince, but return a string measuring the time until the given time. """ - return timesince(d, now, reversed=True) + return timesince(d, now, reversed=True, time_strings=time_strings) diff --git a/tests/humanize_tests/tests.py b/tests/humanize_tests/tests.py index df9ae4f35d..2414a55ed7 100644 --- a/tests/humanize_tests/tests.py +++ b/tests/humanize_tests/tests.py @@ -289,3 +289,29 @@ class HumanizeTests(SimpleTestCase): self.assertEqual(expected_natural_time, natural_time) finally: humanize.datetime = orig_humanize_datetime + + def test_dative_inflection_for_timedelta(self): + """Translation may differ depending on the string it is inserted in.""" + test_list = [ + now - datetime.timedelta(days=1), + now - datetime.timedelta(days=2), + now - datetime.timedelta(days=30), + now - datetime.timedelta(days=60), + now - datetime.timedelta(days=500), + now - datetime.timedelta(days=865), + ] + result_list = [ + 'vor 1\xa0Tag', + 'vor 2\xa0Tagen', + 'vor 1\xa0Monat', + 'vor 2\xa0Monaten', + 'vor 1\xa0Jahr, 4\xa0Monaten', + 'vor 2\xa0Jahren, 4\xa0Monaten', + ] + + orig_humanize_datetime, humanize.datetime = humanize.datetime, MockDateTime + try: + with translation.override('de'), self.settings(USE_L10N=True): + self.humanize_tester(test_list, result_list, 'naturaltime') + finally: + humanize.datetime = orig_humanize_datetime