Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Améliore l'affichage de l'estimation du temps de lecture #6401

Merged
merged 1 commit into from
Oct 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 4 additions & 8 deletions templates/tutorialv2/includes/tags_authors.part.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
{% load category_url %}
{% load set %}
{% load displayable_authors %}
{% load minute_to_duration %}
{% load humanize_duration %}
{% load captureas %}

<aside class="meta">
Expand Down Expand Up @@ -68,13 +68,9 @@
{% endfor %}
</p>

<p>
{% if online and reading_time and not is_part_or_chapter %}
{% trans "Temps de lecture estimé : " %}{{ reading_time|minute_to_duration }}
{% elif online and not is_part_or_chapter %}
{% trans "Temps de lecture estimé à moins d’une minute." %}
{% endif %}
</p>
{% if online and not is_part_or_chapter %}
<p>{% blocktrans with reading_time=reading_time|humanize_duration %}Temps de lecture estimé à {{ reading_time }}.{% endblocktrans %}</p>
{% endif %}

{% if online %}
{% set public_object.last_publication_date as update_date %}
Expand Down
62 changes: 62 additions & 0 deletions zds/utils/templatetags/humanize_duration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
from typing import Tuple, List, Iterator, Iterable

from django import template
from django.utils.translation import ngettext, gettext as _

register = template.Library()


@register.filter
def humanize_duration(duration_min: int) -> str:
"""
Display a human-readable duration.
The granularity gets larger as the value gets larger to avoid meaningless precision.

See the unit tests for examples of results.
"""
duration_min = max(duration_min, 0) # to avoid surprises with modulo operations
truncated_value = _truncate_duration(
duration_min,
bounds=[600, 120, 60, 30, 15],
precisions=[60, 30, 15, 10, 5],
)
hours, minutes = _minutes_to_hours_and_minutes(truncated_value)
return _display_hours_and_minutes(hours, minutes)


def _truncate_duration(duration: int, bounds: Iterable[int], precisions: Iterable[int]) -> int:
"""
Truncate a duration to lower its precision.
Precisions are given for a set of intervals delimited by the given lower bounds.
The duration, precisions and bounds are expressed in the same unit (e.g. minutes).
"""
for bound, precision in zip(bounds, precisions):
if duration >= bound:
return duration - (duration % precision)
return duration


def _minutes_to_hours_and_minutes(duration_min: int) -> Tuple[int, int]:
"""
Convert a duration expressed in minutes to a duration expressed in hours and minutes.
`duration_min` shall be positive to ensure a correct behavior.
"""
minutes_per_hour = 60
hours, minutes = divmod(duration_min, minutes_per_hour)
return hours, minutes


def _display_hours_and_minutes(hours: int, minutes: int) -> str:
"""Display a human-readable duration given in hours and minutes."""

minutes_fragment = ngettext("1 minute", "{minutes} minutes", minutes).format(minutes=minutes)
hours_fragment = ngettext("1 heure", "{hours} heures", hours).format(hours=hours)

if hours == 0 and minutes == 0:
return _("moins d'une minute")
elif hours == 0:
return minutes_fragment
elif minutes == 0:
return hours_fragment
else:
return _("{hours} et {minutes}").format(hours=hours_fragment, minutes=minutes_fragment)
24 changes: 0 additions & 24 deletions zds/utils/templatetags/minute_to_duration.py

This file was deleted.

26 changes: 26 additions & 0 deletions zds/utils/tests/tests_humanize_duration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from django.test import TestCase
from zds.utils.templatetags.humanize_duration import humanize_duration


class TemplateTagsTest(TestCase):
def test_main(self):
test_cases = [
{"input": -1, "expected": "moins d'une minute"},
{"input": 0, "expected": "moins d'une minute"},
{"input": 1, "expected": "1 minute"},
{"input": 2, "expected": "2 minutes"},
{"input": 59, "expected": "50 minutes"},
{"input": 60, "expected": "1 heure"},
{"input": 72, "expected": "1 heure"},
{"input": 90, "expected": "1 heure et 30 minutes"},
{"input": 105, "expected": "1 heure et 45 minutes"},
{"input": 110, "expected": "1 heure et 45 minutes"},
{"input": 125, "expected": "2 heures"},
{"input": 155, "expected": "2 heures et 30 minutes"},
{"input": 24 * 60, "expected": "24 heures"},
{"input": 48 * 60, "expected": "48 heures"},
]

for test_case in test_cases:
with self.subTest(f"case: {test_case['input']} min"):
self.assertEqual(humanize_duration(test_case["input"]), test_case["expected"])
16 changes: 0 additions & 16 deletions zds/utils/tests/tests_minute_to_duration.py

This file was deleted.