Skip to content
Open
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
build
clones
venv
__pycache__
*.pyc
6 changes: 6 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,11 @@ repos:
- id: deptry
args: [".", "--per-rule-ignores", "DEP002=python-docs-theme", "--package-module-name-map", "gitpython=git,sphinx-lint=sphinxlint"]

- repo: https://github.com/djlint/djLint
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a dead project, no releases since 2024, are there no alternatives? It seems to work alright currently.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My quick research implied it is mature and stable, and there's no better alternative. It looks stagnant on PyPI, but the repo still receives commits. The GitHub project had updates as recently as Nov 2025, and the docs were updated in 2026, which indicates some ongoing maintenance.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fact they have Renovate set up to do updates multiple times a day, and automerge them without human review, is a bit odd:

https://github.com/djlint/djLint/commits/master/

Also no cooldown, so a very good way to be among the very first to be exposed to a new vulnerability...

https://blog.yossarian.net/2025/11/21/We-should-all-be-using-dependency-cooldowns

We're on a pinned tag not on master, which helps, but tags are immutable and a vuln could rewrite the tags.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've opened an issue with a suggestion to add the cooldown: djlint/djLint#1783.

It's only library like that that offers an autoformatter.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seeing as the whole litellm thing happened the day after Hugo’s message, I think we should wait with this PR till they make such changes.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They've added cooldowns recently and pinned dependencies.

rev: v1.36.4
hooks:
- id: djlint-reformat-jinja
- id: djlint-jinja

ci:
autoupdate_schedule: quarterly
2 changes: 2 additions & 0 deletions djlint.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ignore="J018"
indent=2
264 changes: 149 additions & 115 deletions templates/base.html.jinja
Original file line number Diff line number Diff line change
@@ -1,120 +1,154 @@
<!doctype html>
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="Python Documentation Translation Dashboard">

<title>Python Docs Translation Dashboard</title>

<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet" integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB"
crossorigin="anonymous">
<link href="style.css?version=1" rel="stylesheet">
</head>

<body>
<script>
function applyTheme(t) {
document.documentElement.setAttribute('data-bs-theme', t);
document.documentElement.classList.toggle('dark', t === 'dark');
}
applyTheme(localStorage.getItem('theme') || (matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'));
</script>
<header>
<nav class="navbar navbar-expand-md fixed-top">
<div class="container-fluid">
<div class="navbar-brand">
<a href="./">
<img src="logo.png" style="height: 2rem;" alt="Python logo">
<span class="navbar-title-text">Translation Dashboard</span>
</a>
</div>

<div>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
</div>

<div class="collapse navbar-collapse" id="navbarNavDropdown">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" href="build-details.html">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-card-text" viewBox="0 0 16 16">
<path d="M14.5 3a.5.5 0 0 1 .5.5v9a.5.5 0 0 1-.5.5h-13a.5.5 0 0 1-.5-.5v-9a.5.5 0 0 1 .5-.5zm-13-1A1.5 1.5 0 0 0 0 3.5v9A1.5 1.5 0 0 0 1.5 14h13a1.5 1.5 0 0 0 1.5-1.5v-9A1.5 1.5 0 0 0 14.5 2z"></path>
<path d="M3 5.5a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5M3 8a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9A.5.5 0 0 1 3 8m0 2.5a.5.5 0 0 1 .5-.5h6a.5.5 0 0 1 0 1h-6a.5.5 0 0 1-.5-.5"></path>
</svg>
Build details
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="https://devguide.python.org/documentation/translations/translating/" target="_blank">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-box-arrow-up-right" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M8.636 3.5a.5.5 0 0 0-.5-.5H1.5A1.5 1.5 0 0 0 0 4.5v10A1.5 1.5 0 0 0 1.5 16h10a1.5 1.5 0 0 0 1.5-1.5V7.864a.5.5 0 0 0-1 0V14.5a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h6.636a.5.5 0 0 0 .5-.5"></path>
<path fill-rule="evenodd" d="M16 .5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0 0 1h3.793L6.146 9.146a.5.5 0 1 0 .708.708L15 1.707V5.5a.5.5 0 0 0 1 0z"></path>
</svg>
Translating
<head>
<meta charset="utf-8">
<meta name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description"
content="Python Documentation Translation Dashboard">
<meta name="keywords" content="python,docs,translations,progress,status">
<title>Python Docs Translation Dashboard</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB"
crossorigin="anonymous">
<link href="style.css?version=3" rel="stylesheet">
</head>
<body>
<script>
function applyTheme(t) {
document.documentElement.setAttribute('data-bs-theme', t);
document.documentElement.classList.toggle('dark', t === 'dark');
}
applyTheme(localStorage.getItem('theme') || (matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'));
</script>
<header>
<nav class="navbar navbar-expand-md fixed-top">
<div class="container-fluid">
<div class="navbar-brand">
<a href="./">
<img src="logo.png" alt="Python logo" width="31.07" height="32">
<span class="navbar-title-text">Translation Dashboard</span>
</a>
</li>
</ul>
<div class="d-flex justify-content-center justify-content-md-end ms-md-auto">
<a href="https://github.com/python-docs-translations/dashboard" class="btn btn-sm theme-toggle-btn" aria-label="GitHub repository" target="_blank" rel="noopener noreferrer">
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" fill="currentColor" class="bi bi-github" viewBox="0 0 16 16">
<path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27s1.36.09 2 .27c1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8"/>
</svg>
</a>
<button id="theme-toggle" class="btn btn-sm theme-toggle-btn" type="button" aria-label="Toggle dark mode">
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" fill="currentColor" class="bi bi-brightness-high theme-icon-light" viewBox="0 0 16 16">
<path d="M8 11a3 3 0 1 1 0-6 3 3 0 0 1 0 6m0 1a4 4 0 1 0 0-8 4 4 0 0 0 0 8M8 0a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 0m0 13a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 13m8-5a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2a.5.5 0 0 1 .5.5M3 8a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2A.5.5 0 0 1 3 8m10.657-5.657a.5.5 0 0 1 0 .707l-1.414 1.415a.5.5 0 1 1-.707-.708l1.414-1.414a.5.5 0 0 1 .707 0m-9.193 9.193a.5.5 0 0 1 0 .707L3.05 13.657a.5.5 0 0 1-.707-.707l1.414-1.414a.5.5 0 0 1 .707 0m9.193 2.121a.5.5 0 0 1-.707 0l-1.414-1.414a.5.5 0 0 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .707M4.464 4.465a.5.5 0 0 1-.707 0L2.343 3.05a.5.5 0 1 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .708"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" fill="currentColor" class="bi bi-moon-fill theme-icon-dark" viewBox="0 0 16 16">
<path d="M6 .278a.77.77 0 0 1 .08.858 7.2 7.2 0 0 0-.878 3.46c0 4.021 3.278 7.277 7.318 7.277q.792-.001 1.533-.16a.79.79 0 0 1 .81.316.73.73 0 0 1-.031.893A8.35 8.35 0 0 1 8.344 16C3.734 16 0 12.286 0 7.71 0 4.266 2.114 1.312 5.124.06A.75.75 0 0 1 6 .278"/>
</svg>
</button>
</div>
<div>
<button class="navbar-toggler"
type="button"
data-bs-toggle="collapse"
data-bs-target="#navbarNavDropdown"
aria-controls="navbarNavDropdown"
aria-expanded="false"
aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
</div>
<div class="collapse navbar-collapse" id="navbarNavDropdown">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" href="build-details.html">
<svg xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
fill="currentColor"
class="bi bi-card-text"
viewBox="0 0 16 16">
<path d="M14.5 3a.5.5 0 0 1 .5.5v9a.5.5 0 0 1-.5.5h-13a.5.5 0 0 1-.5-.5v-9a.5.5 0 0 1 .5-.5zm-13-1A1.5 1.5 0 0 0 0 3.5v9A1.5 1.5 0 0 0 1.5 14h13a1.5 1.5 0 0 0 1.5-1.5v-9A1.5 1.5 0 0 0 14.5 2z">
</path>
<path d="M3 5.5a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5M3 8a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9A.5.5 0 0 1 3 8m0 2.5a.5.5 0 0 1 .5-.5h6a.5.5 0 0 1 0 1h-6a.5.5 0 0 1-.5-.5">
</path>
</svg>
Build details
</a>
</li>
<li class="nav-item">
<a class="nav-link"
href="https://devguide.python.org/documentation/translations/translating/"
target="_blank">
<svg xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
fill="currentColor"
class="bi bi-box-arrow-up-right"
viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M8.636 3.5a.5.5 0 0 0-.5-.5H1.5A1.5 1.5 0 0 0 0 4.5v10A1.5 1.5 0 0 0 1.5 16h10a1.5 1.5 0 0 0 1.5-1.5V7.864a.5.5 0 0 0-1 0V14.5a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h6.636a.5.5 0 0 0 .5-.5">
</path>
<path fill-rule="evenodd" d="M16 .5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0 0 1h3.793L6.146 9.146a.5.5 0 1 0 .708.708L15 1.707V5.5a.5.5 0 0 0 1 0z">
</path>
</svg>
Translating
</a>
</li>
</ul>
<div class="d-flex justify-content-center justify-content-md-end ms-md-auto">
<a href="https://github.com/python-docs-translations/dashboard"
class="btn btn-sm theme-toggle-btn"
aria-label="GitHub repository"
target="_blank"
rel="noopener noreferrer">
<svg xmlns="http://www.w3.org/2000/svg"
width="22"
height="22"
fill="currentColor"
class="bi bi-github"
viewBox="0 0 16 16">
<path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27s1.36.09 2 .27c1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8" />
</svg>
</a>
<button id="theme-toggle"
class="btn btn-sm theme-toggle-btn"
type="button"
aria-label="Toggle dark mode">
<svg xmlns="http://www.w3.org/2000/svg"
width="22"
height="22"
fill="currentColor"
class="bi bi-brightness-high theme-icon-light"
viewBox="0 0 16 16">
<path d="M8 11a3 3 0 1 1 0-6 3 3 0 0 1 0 6m0 1a4 4 0 1 0 0-8 4 4 0 0 0 0 8M8 0a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 0m0 13a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 13m8-5a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2a.5.5 0 0 1 .5.5M3 8a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2A.5.5 0 0 1 3 8m10.657-5.657a.5.5 0 0 1 0 .707l-1.414 1.415a.5.5 0 1 1-.707-.708l1.414-1.414a.5.5 0 0 1 .707 0m-9.193 9.193a.5.5 0 0 1 0 .707L3.05 13.657a.5.5 0 0 1-.707-.707l1.414-1.414a.5.5 0 0 1 .707 0m9.193 2.121a.5.5 0 0 1-.707 0l-1.414-1.414a.5.5 0 0 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .707M4.464 4.465a.5.5 0 0 1-.707 0L2.343 3.05a.5.5 0 1 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .708" />
</svg>
<svg xmlns="http://www.w3.org/2000/svg"
width="22"
height="22"
fill="currentColor"
class="bi bi-moon-fill theme-icon-dark"
viewBox="0 0 16 16">
<path d="M6 .278a.77.77 0 0 1 .08.858 7.2 7.2 0 0 0-.878 3.46c0 4.021 3.278 7.277 7.318 7.277q.792-.001 1.533-.16a.79.79 0 0 1 .81.316.73.73 0 0 1-.031.893A8.35 8.35 0 0 1 8.344 16C3.734 16 0 12.286 0 7.71 0 4.266 2.114 1.312 5.124.06A.75.75 0 0 1 6 .278" />
</svg>
</button>
</div>
</div>
</div>
</div>
</div>
</nav>
</header>

<main role="main">
{% block main %}
{% endblock %}
</main>

</body>

<script>
function padnavbar() {
const navbar = document.querySelector('.navbar.fixed-top');
if (navbar) {
document.body.style.paddingTop = (navbar.offsetHeight + 10) + 'px';
</nav>
</header>
<main role="main">
{% block main %}
{% endblock main %}
</main>
</body>
<script>
function padnavbar() {
const navbar = document.querySelector('.navbar.fixed-top');
if (navbar) {
document.body.style.paddingTop = (navbar.offsetHeight + 10) + 'px';
}
}
}
window.addEventListener('load', padnavbar);
window.addEventListener('resize', padnavbar);

document.getElementById('theme-toggle').addEventListener('click', function() {
var next = document.documentElement.getAttribute('data-bs-theme') === 'dark' ? 'light' : 'dark';
localStorage.setItem('theme', next);
applyTheme(next);
});
</script>

<script src="https://code.jquery.com/jquery-4.0.0.slim.min.js"
integrity="sha256-8DGpv13HIm+5iDNWw1XqxgFB4mj+yOKFNb+tHBZOowc="
crossorigin="anonymous">
</script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"
integrity="sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI"
crossorigin="anonymous">
</script>

{# Plausible analytics #}
<script defer data-domain="translations.python.org" src="https://analytics.python.org/js/script.outbound-links.js"></script>
<script>window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }</script>
{% block extrascript %}
{% endblock %}
window.addEventListener('load', padnavbar);
window.addEventListener('resize', padnavbar);
document.getElementById('theme-toggle').addEventListener('click', function() {
var next = document.documentElement.getAttribute('data-bs-theme') === 'dark' ? 'light' : 'dark';
localStorage.setItem('theme', next);
applyTheme(next);
});
</script>
<script src="https://code.jquery.com/jquery-4.0.0.slim.min.js" integrity="sha256-8DGpv13HIm+5iDNWw1XqxgFB4mj+yOKFNb+tHBZOowc=" crossorigin="anonymous">
</script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js" integrity="sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI" crossorigin="anonymous">
</script>
{# Plausible analytics #}
<script defer
data-domain="translations.python.org"
src="https://analytics.python.org/js/script.outbound-links.js"></script>
<script>window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }</script>
{% block extrascript %}
{% endblock extrascript %}
</html>
82 changes: 41 additions & 41 deletions templates/build-details.html.jinja
Original file line number Diff line number Diff line change
@@ -1,43 +1,43 @@
{% extends "base.html.jinja" %}

{% block main %}
<table>
<thead>
<tr>
<th>language</th>
<th>branch</th>
<th>last updated</th>
<th>build warnings*</th>
<th>lint failures</th>
</tr>
</thead>
<tbody>
{% for project, metadata in build_details | sort(attribute='0.completion') | reverse %}
{% if project.repository %}
<tr>
<td data-label="language">{{ project.language.name }} ({{ project.language.code }})</td>
<td data-label="branch">{{ project.branch }}</td>
<td data-label="updated">{{ metadata[2].strftime('%Y/%m/%d %T') if metadata[2] else '' }}</td>
<td data-label="warnings">
{% if project.completion %}
<a href="warnings-{{ project.language.code }}.txt">{{ metadata[0] }}</a>
{% else %}
{{ metadata[0] }}
{% endif %}
</td>
<td data-label="lint">
{% if project.completion %}
<a href="warnings-lint-{{ project.language.code }}.txt">{{ metadata[1] }}</a>
{% else %}
{{ metadata[1] }}
{% endif %}
</td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>

<p>* number of Sphinx build process warnings</p>
<p>Last updated at {{ generation_time.strftime('%A, %-d %B %Y, %-H:%M:%S %Z') }} (in {{ duration // 60 }}:{{ "{:02}".format(duration % 60) }} minutes).</p>
{% endblock %}
<table>
<thead>
<tr>
<th>language</th>
<th>branch</th>
<th>last updated</th>
<th>build warnings*</th>
<th>lint failures</th>
</tr>
</thead>
<tbody>
{% for project, metadata in build_details | sort(attribute='0.completion') | reverse %}
{% if project.repository %}
<tr>
<td data-label="language">{{ project.language.name }} ({{ project.language.code }})</td>
<td data-label="branch">{{ project.branch }}</td>
<td data-label="updated">{{ metadata[2].strftime("%Y/%m/%d %T") if metadata[2] else '' }}</td>
<td data-label="warnings">
{% if project.completion %}
<a href="warnings-{{ project.language.code }}.txt">{{ metadata[0] }}</a>
{% else %}
{{ metadata[0] }}
{% endif %}
</td>
<td data-label="lint">
{% if project.completion %}
<a href="warnings-lint-{{ project.language.code }}.txt">{{ metadata[1] }}</a>
{% else %}
{{ metadata[1] }}
{% endif %}
</td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
<p>* number of Sphinx build process warnings</p>
<p>
Last updated at {{ generation_time.strftime("%A, %-d %B %Y, %-H:%M:%S %Z") }} (in {{ duration // 60 }}:{{ "{:02}".format(duration % 60) }} minutes).
</p>
{% endblock main %}
Loading
Loading