Translate the whole site to English: English routes with 301 redirects from the Dutch paths, English UI, docs, seeds and captions, one-time live content migration

This commit is contained in:
2026-10-05 11:25:41 +02:00
parent bbdecdc95b
commit ff547e1677
153 changed files with 1095 additions and 774 deletions
+3 -3
View File
@@ -1,15 +1,15 @@
<!-- retoor <retoor@molodetz.nl> -->
{% extends "admin/base_admin.html" %}
{% block admin_content %}
<h1>Auditlog</h1>
<h1>Audit log</h1>
<div class="table-wrap">
<table class="admin-table">
<thead><tr><th>Tijd</th><th>Gebeurtenis</th><th>Categorie</th><th>Actor</th><th>Resultaat</th></tr></thead>
<thead><tr><th>Time</th><th>Event</th><th>Category</th><th>Actor</th><th>Result</th></tr></thead>
<tbody>
{% for row in rows %}
<tr><td>{{ local_dt(row.created_at) }}</td><td><code>{{ row.event_key }}</code></td><td><a href="?category={{ row.category }}">{{ row.category }}</a></td><td>{{ row.actor_kind }}</td><td><span class="status {{ 'failed' if row.result == 'denied' else 'done' }}">{{ row.result }}</span></td></tr>
{% else %}
<tr><td colspan="5" class="muted">Nog geen regels.</td></tr>
<tr><td colspan="5" class="muted">No rows yet.</td></tr>
{% endfor %}
</tbody>
</table>
+5 -5
View File
@@ -1,14 +1,14 @@
<!-- retoor <retoor@molodetz.nl> -->
{% extends "admin/base_admin.html" %}
{% block admin_content %}
<h1>Back-ups</h1>
<h1>Backups</h1>
<form class="actions" method="post" action="/admin/backups">
<select name="target" aria-label="Doel">{% for target in ['database', 'uploads', 'keys', 'full'] %}<option value="{{ target }}">{{ target }}</option>{% endfor %}</select>
<button class="button" type="submit">Back-up inplannen</button>
<select name="target" aria-label="Target">{% for target in ['database', 'uploads', 'keys', 'full'] %}<option value="{{ target }}">{{ target }}</option>{% endfor %}</select>
<button class="button" type="submit">Schedule backup</button>
</form>
<div class="table-wrap">
<table class="admin-table">
<thead><tr><th>Doel</th><th>Status</th><th>Grootte</th><th>Aangemaakt</th><th></th></tr></thead>
<thead><tr><th>Target</th><th>Status</th><th>Size</th><th>Created</th><th></th></tr></thead>
<tbody>
{% for row in backups %}
<tr>
@@ -19,7 +19,7 @@
<td>{% if can_download and row.status == 'done' %}<a class="button ghost small" href="/admin/backups/{{ row.uid }}/download">Download</a>{% endif %}</td>
</tr>
{% else %}
<tr><td colspan="5" class="muted">Nog geen back-ups.</td></tr>
<tr><td colspan="5" class="muted">No backups yet.</td></tr>
{% endfor %}
</tbody>
</table>
+11 -11
View File
@@ -4,19 +4,19 @@
{% block extra_head %}<link rel="stylesheet" href="{{ static_url('/static/css/admin.css') }}">{% block admin_head %}{% endblock %}{% endblock %}
{% block content %}
<div class="admin-layout">
<nav class="admin-nav" aria-label="Beheer">
<a href="/admin" class="{{ nav_active(request, '/admin', exact=True) }}">Overzicht</a>
<a href="/admin/posts" class="{{ nav_active(request, '/admin/posts') }}">Berichten</a>
<a href="/admin/joins" class="{{ nav_active(request, '/admin/joins') }}">Aanmeldingen</a>
<nav class="admin-nav" aria-label="Admin">
<a href="/admin" class="{{ nav_active(request, '/admin', exact=True) }}">Overview</a>
<a href="/admin/posts" class="{{ nav_active(request, '/admin/posts') }}">Posts</a>
<a href="/admin/joins" class="{{ nav_active(request, '/admin/joins') }}">Join requests</a>
<a href="/admin/services" class="{{ nav_active(request, '/admin/services') }}">Services</a>
<a href="/admin/backups" class="{{ nav_active(request, '/admin/backups') }}">Back-ups</a>
<a href="/admin/trash" class="{{ nav_active(request, '/admin/trash') }}">Prullenbak</a>
<a href="/admin/backups" class="{{ nav_active(request, '/admin/backups') }}">Backups</a>
<a href="/admin/trash" class="{{ nav_active(request, '/admin/trash') }}">Trash</a>
<a href="/admin/users" class="{{ nav_active(request, '/admin/users') }}">Accounts</a>
<a href="/admin/settings" class="{{ nav_active(request, '/admin/settings') }}">Instellingen</a>
<a href="/admin/audit" class="{{ nav_active(request, '/admin/audit') }}">Auditlog</a>
<a href="/admin/stats" class="{{ nav_active(request, '/admin/stats') }}">Statistieken</a>
<a href="/profile/api-key">API-sleutel</a>
<a href="/docs/beheer">Docs</a>
<a href="/admin/settings" class="{{ nav_active(request, '/admin/settings') }}">Settings</a>
<a href="/admin/audit" class="{{ nav_active(request, '/admin/audit') }}">Audit log</a>
<a href="/admin/stats" class="{{ nav_active(request, '/admin/stats') }}">Statistics</a>
<a href="/profile/api-key">API key</a>
<a href="/docs/admin">Docs</a>
</nav>
<div class="admin-main">
{% block admin_content %}{% endblock %}
+5 -5
View File
@@ -1,12 +1,12 @@
<!-- retoor <retoor@molodetz.nl> -->
{% extends "admin/base_admin.html" %}
{% block admin_content %}
<h1>Beheer</h1>
<h1>Admin</h1>
<div class="stat-cards">
<div class="stat-card"><span class="value">{{ post_count }}</span><span class="name">Berichten</span></div>
<div class="stat-card"><span class="value">{{ open_joins }}</span><span class="name">Open aanmeldingen</span></div>
<div class="stat-card"><span class="value">{{ post_count }}</span><span class="name">Posts</span></div>
<div class="stat-card"><span class="value">{{ open_joins }}</span><span class="name">Open join requests</span></div>
<div class="stat-card"><span class="value">{{ user_count }}</span><span class="name">Accounts</span></div>
<div class="stat-card"><span class="value">{{ deleted_count }}</span><span class="name">In prullenbak</span></div>
<div class="stat-card"><span class="value">{{ deleted_count }}</span><span class="name">In trash</span></div>
</div>
<div class="actions"><a class="button" href="/admin/posts/new">Nieuw bericht</a><a class="button ghost" href="/admin/joins">Aanmeldingen bekijken</a></div>
<div class="actions"><a class="button" href="/admin/posts/new">New post</a><a class="button ghost" href="/admin/joins">View join requests</a></div>
{% endblock %}
+6 -6
View File
@@ -1,29 +1,29 @@
<!-- retoor <retoor@molodetz.nl> -->
{% extends "admin/base_admin.html" %}
{% block admin_content %}
<h1>Aanmeldingen</h1>
<h1>Join requests</h1>
<div class="table-wrap">
<table class="admin-table">
<thead><tr><th>Wie</th><th>Contact</th><th>Werk</th><th>Bericht</th><th>Status</th><th>Ontvangen</th><th></th></tr></thead>
<thead><tr><th>Who</th><th>Contact</th><th>Work</th><th>Message</th><th>Status</th><th>Received</th><th></th></tr></thead>
<tbody>
{% for item in requests %}
<tr>
<td>{{ item.name }}</td>
<td>{{ item.contact }}</td>
<td>{% if item.repo_url %}<a href="{{ item.repo_url }}" rel="nofollow noopener" target="_blank">{{ item.repo_url }}</a>{% if item.link_status %}<br><span class="muted">{{ item.link_status }}{% if item.link_title %}: {{ item.link_title }}{% endif %}</span>{% endif %}{% else %}<span class="muted">geen</span>{% endif %}</td>
<td>{% if item.repo_url %}<a href="{{ item.repo_url }}" rel="nofollow noopener" target="_blank">{{ item.repo_url }}</a>{% if item.link_status %}<br><span class="muted">{{ item.link_status }}{% if item.link_title %}: {{ item.link_title }}{% endif %}</span>{% endif %}{% else %}<span class="muted">none</span>{% endif %}</td>
<td>{{ item.message }}</td>
<td><span class="status {{ item.status }}">{{ item.status }}</span></td>
<td>{{ local_dt(item.created_at) }}</td>
<td class="actions">
<form method="post" action="/admin/joins/{{ item.uid }}/status">
<select name="status" aria-label="Status">{% for value in ['open', 'contacted', 'accepted', 'declined'] %}<option value="{{ value }}" {% if item.status == value %}selected{% endif %}>{{ value }}</option>{% endfor %}</select>
<button class="button ghost small" type="submit">Zet</button>
<button class="button ghost small" type="submit">Set</button>
</form>
{% if item.repo_url %}<form method="post" action="/admin/joins/{{ item.uid }}/check"><button class="button ghost small" type="submit" data-loading>Link controleren</button></form>{% endif %}
{% if item.repo_url %}<form method="post" action="/admin/joins/{{ item.uid }}/check"><button class="button ghost small" type="submit" data-loading>Check link</button></form>{% endif %}
</td>
</tr>
{% else %}
<tr><td colspan="7" class="muted">Nog geen aanmeldingen.</td></tr>
<tr><td colspan="7" class="muted">No join requests yet.</td></tr>
{% endfor %}
</tbody>
</table>
+10 -10
View File
@@ -1,31 +1,31 @@
<!-- retoor <retoor@molodetz.nl> -->
{% extends "admin/base_admin.html" %}
{% block admin_content %}
<h1>{{ 'Bericht bewerken' if post else 'Nieuw bericht' }}</h1>
<h1>{{ 'Edit post' if post else 'New post' }}</h1>
<form class="form wide" method="post" action="{{ '/admin/posts/' ~ post.uid if post else '/admin/posts' }}" data-form>
<div class="field"><label for="title">Titel</label><input id="title" type="text" name="title" required minlength="3" maxlength="200" value="{{ post.title if post else '' }}"></div>
{% set _selected = post.topic if post else 'rol' %}
<div class="field"><label for="title">Title</label><input id="title" type="text" name="title" required minlength="3" maxlength="200" value="{{ post.title if post else '' }}"></div>
{% set _selected = post.topic if post else 'roll' %}
{% include "_topic_selector.html" %}
<div class="editor">
<div class="field">
<label for="body">Tekst (markdown)</label>
<label for="body">Text (markdown)</label>
<textarea id="body" name="body" required minlength="10" data-preview-source>{{ post.body if post else '' }}</textarea>
<span class="help">Markdown met GFM. Emoji via :shortcode:. Voorbeeld rechts is een live voorbeeld; de gepubliceerde versie wordt op de server gerenderd.</span>
<span class="help">Markdown with GFM. Emoji via :shortcode:. The preview on the right is live; the published version is rendered on the server.</span>
</div>
<div class="field">
<label>Voorbeeld</label>
<label>Preview</label>
<dp-content class="preview prose" data-preview-target></dp-content>
</div>
</div>
<div class="field">
<label for="status">Status</label>
<select id="status" name="status">
<option value="draft" {% if not post or post.status == 'draft' %}selected{% endif %}>Concept</option>
<option value="published" {% if post and post.status == 'published' %}selected{% endif %}>Gepubliceerd</option>
<option value="draft" {% if not post or post.status == 'draft' %}selected{% endif %}>Draft</option>
<option value="published" {% if post and post.status == 'published' %}selected{% endif %}>Published</option>
</select>
</div>
<label class="check"><input type="checkbox" name="is_placeholder" value="true" {% if post and post.is_placeholder %}checked{% endif %}> Markeer als placeholder</label>
<div class="actions"><button class="button" type="submit" data-loading>Opslaan</button><a class="button ghost" href="/admin/posts">Annuleren</a></div>
<label class="check"><input type="checkbox" name="is_placeholder" value="true" {% if post and post.is_placeholder %}checked{% endif %}> Mark as placeholder</label>
<div class="actions"><button class="button" type="submit" data-loading>Save</button><a class="button ghost" href="/admin/posts">Cancel</a></div>
</form>
{% endblock %}
{% block extra_js %}<script type="module" src="{{ static_url('/static/js/utils/EditorPreview.js') }}"></script>{% endblock %}
+7 -7
View File
@@ -1,11 +1,11 @@
<!-- retoor <retoor@molodetz.nl> -->
{% extends "admin/base_admin.html" %}
{% block admin_content %}
<h1>Berichten</h1>
<div class="actions"><a class="button" href="/admin/posts/new">Nieuw bericht</a></div>
<h1>Posts</h1>
<div class="actions"><a class="button" href="/admin/posts/new">New post</a></div>
<div class="table-wrap">
<table class="admin-table">
<thead><tr><th>Titel</th><th>Onderwerp</th><th>Status</th><th>Bijgewerkt</th><th></th></tr></thead>
<thead><tr><th>Title</th><th>Topic</th><th>Status</th><th>Updated</th><th></th></tr></thead>
<tbody>
{% for post in posts %}
<tr>
@@ -14,13 +14,13 @@
<td><span class="status {{ post.status }}">{{ post.status }}</span></td>
<td>{{ local_dt(post.updated_at) }}</td>
<td class="actions">
<a class="button ghost small" href="/admin/posts/{{ post.uid }}/edit">Bewerken</a>
<form method="post" action="/admin/posts/{{ post.uid }}/publish"><button class="button ghost small" type="submit">{{ 'Depubliceren' if post.status == 'published' else 'Publiceren' }}</button></form>
<form method="post" action="/admin/posts/{{ post.uid }}/delete" data-confirm="Bericht naar de prullenbak verplaatsen?"><button class="button danger small" type="submit">Verwijderen</button></form>
<a class="button ghost small" href="/admin/posts/{{ post.uid }}/edit">Edit</a>
<form method="post" action="/admin/posts/{{ post.uid }}/publish"><button class="button ghost small" type="submit">{{ 'Unpublish' if post.status == 'published' else 'Publish' }}</button></form>
<form method="post" action="/admin/posts/{{ post.uid }}/delete" data-confirm="Move this post to the trash?"><button class="button danger small" type="submit">Delete</button></form>
</td>
</tr>
{% else %}
<tr><td colspan="5" class="muted">Nog geen berichten.</td></tr>
<tr><td colspan="5" class="muted">No posts yet.</td></tr>
{% endfor %}
</tbody>
</table>
+5 -5
View File
@@ -5,8 +5,8 @@
<p class="muted">{{ service.description }}</p>
<div data-service-monitor="detail" data-service="{{ service.name }}">
<div class="tabs" role="tablist" data-tabs>
<button type="button" class="active" data-tab="overview">Overzicht</button>
<button type="button" data-tab="config">Configuratie</button>
<button type="button" class="active" data-tab="overview">Overview</button>
<button type="button" data-tab="config">Configuration</button>
<button type="button" data-tab="logs">Logs</button>
</div>
<section data-panel="overview">
@@ -16,8 +16,8 @@
</div>
<div class="actions">
<form method="post" action="/admin/services/{{ service.name }}/command"><input type="hidden" name="verb" value="{{ 'stop' if service.enabled else 'start' }}"><button class="button ghost small" type="submit">{{ 'Stop' if service.enabled else 'Start' }}</button></form>
<form method="post" action="/admin/services/{{ service.name }}/command"><input type="hidden" name="verb" value="run"><button class="button ghost small" type="submit">Nu draaien</button></form>
<form method="post" action="/admin/services/{{ service.name }}/command"><input type="hidden" name="verb" value="clear"><button class="button ghost small" type="submit">Logs wissen</button></form>
<form method="post" action="/admin/services/{{ service.name }}/command"><input type="hidden" name="verb" value="run"><button class="button ghost small" type="submit">Run now</button></form>
<form method="post" action="/admin/services/{{ service.name }}/command"><input type="hidden" name="verb" value="clear"><button class="button ghost small" type="submit">Clear logs</button></form>
</div>
</section>
<section data-panel="config" hidden>
@@ -42,7 +42,7 @@
</div>
{% endfor %}
{% endfor %}
<div class="actions"><button class="button" type="submit">Opslaan</button></div>
<div class="actions"><button class="button" type="submit">Save</button></div>
</form>
</section>
<section data-panel="logs" hidden>
+2 -2
View File
@@ -4,7 +4,7 @@
<h1>Services</h1>
<div class="table-wrap">
<table class="admin-table" data-service-monitor="index">
<thead><tr><th>Service</th><th>Status</th><th>Laatste run</th><th>Volgende run</th><th></th></tr></thead>
<thead><tr><th>Service</th><th>Status</th><th>Last run</th><th>Next run</th><th></th></tr></thead>
<tbody>
{% for service in services %}
<tr data-service="{{ service.name }}">
@@ -14,7 +14,7 @@
<td data-field="next_run">{{ local_dt(service.next_run) }}</td>
<td class="actions">
<form method="post" action="/admin/services/{{ service.name }}/command"><input type="hidden" name="verb" value="{{ 'stop' if service.enabled else 'start' }}"><button class="button ghost small" type="submit">{{ 'Stop' if service.enabled else 'Start' }}</button></form>
<form method="post" action="/admin/services/{{ service.name }}/command"><input type="hidden" name="verb" value="run"><button class="button ghost small" type="submit">Nu draaien</button></form>
<form method="post" action="/admin/services/{{ service.name }}/command"><input type="hidden" name="verb" value="run"><button class="button ghost small" type="submit">Run now</button></form>
</td>
</tr>
{% endfor %}
+3 -3
View File
@@ -1,14 +1,14 @@
<!-- retoor <retoor@molodetz.nl> -->
{% extends "admin/base_admin.html" %}
{% block admin_content %}
<h1>Instellingen</h1>
<h1>Settings</h1>
<form class="form" method="post" action="/admin/settings">
{% for key, value in settings.items() %}
<div class="field">
<label for="s-{{ key }}">{{ key }}</label>
{% if key == 'site_intro' %}
<textarea id="s-{{ key }}" name="{{ key }}" rows="24">{{ value }}</textarea>
<span class="help">Intro bovenaan de homepage. Markdown; elke regelovergang blijft staan, een lege regel begint een nieuwe alinea. De eerste alinea wordt groot gezet.</span>
<span class="help">Intro at the top of the home page. Markdown; every line break is kept, an empty line starts a new paragraph. The first paragraph is set large.</span>
{% elif key in ('maintenance_mode', 'friendly_404') %}
<select id="s-{{ key }}" name="{{ key }}"><option value="0" {% if value == '0' %}selected{% endif %}>0</option><option value="1" {% if value == '1' %}selected{% endif %}>1</option></select>
{% else %}
@@ -16,6 +16,6 @@
{% endif %}
</div>
{% endfor %}
<div class="actions"><button class="button" type="submit">Opslaan</button></div>
<div class="actions"><button class="button" type="submit">Save</button></div>
</form>
{% endblock %}
+7 -7
View File
@@ -1,19 +1,19 @@
<!-- retoor <retoor@molodetz.nl> -->
{% extends "admin/base_admin.html" %}
{% block admin_content %}
<h1>Statistieken</h1>
<h1>Statistics</h1>
<div class="tabs" role="tablist" data-tabs>
<button type="button" class="active" data-tab="paths">Paden</button>
<button type="button" data-tab="days">Per dag</button>
<button type="button" class="active" data-tab="paths">Paths</button>
<button type="button" data-tab="days">Per day</button>
</div>
<section data-panel="paths">
<table class="admin-table"><thead><tr><th>Pad</th><th>Hits</th></tr></thead><tbody>
{% for row in top_paths %}<tr><td>{{ row.path }}</td><td>{{ row.hits }}</td></tr>{% else %}<tr><td colspan="2" class="muted">Nog geen data.</td></tr>{% endfor %}
<table class="admin-table"><thead><tr><th>Path</th><th>Hits</th></tr></thead><tbody>
{% for row in top_paths %}<tr><td>{{ row.path }}</td><td>{{ row.hits }}</td></tr>{% else %}<tr><td colspan="2" class="muted">No data yet.</td></tr>{% endfor %}
</tbody></table>
</section>
<section data-panel="days" hidden>
<table class="admin-table"><thead><tr><th>Dag</th><th>Hits</th></tr></thead><tbody>
{% for row in daily %}<tr><td>{{ format_date(row.day) }}</td><td>{{ row.hits }}</td></tr>{% else %}<tr><td colspan="2" class="muted">Nog geen data.</td></tr>{% endfor %}
<table class="admin-table"><thead><tr><th>Day</th><th>Hits</th></tr></thead><tbody>
{% for row in daily %}<tr><td>{{ format_date(row.day) }}</td><td>{{ row.hits }}</td></tr>{% else %}<tr><td colspan="2" class="muted">No data yet.</td></tr>{% endfor %}
</tbody></table>
</section>
{% endblock %}
+5 -5
View File
@@ -1,10 +1,10 @@
<!-- retoor <retoor@molodetz.nl> -->
{% extends "admin/base_admin.html" %}
{% block admin_content %}
<h1>Prullenbak</h1>
<h1>Trash</h1>
<div class="table-wrap">
<table class="admin-table">
<thead><tr><th>Soort</th><th>Item</th><th>Verwijderd</th><th>Door</th><th></th></tr></thead>
<thead><tr><th>Kind</th><th>Item</th><th>Deleted</th><th>By</th><th></th></tr></thead>
<tbody>
{% for item in items %}
<tr>
@@ -13,12 +13,12 @@
<td>{{ local_dt(item.deleted_at) }}</td>
<td>{{ item.deleted_by }}</td>
<td class="actions">
<form method="post" action="/admin/trash/restore"><input type="hidden" name="stamp" value="{{ item.deleted_at }}"><button class="button ghost small" type="submit">Herstellen</button></form>
<form method="post" action="/admin/trash/purge" data-confirm="Definitief verwijderen? Dit kan niet ongedaan worden gemaakt."><input type="hidden" name="stamp" value="{{ item.deleted_at }}"><button class="button danger small" type="submit">Definitief</button></form>
<form method="post" action="/admin/trash/restore"><input type="hidden" name="stamp" value="{{ item.deleted_at }}"><button class="button ghost small" type="submit">Restore</button></form>
<form method="post" action="/admin/trash/purge" data-confirm="Delete permanently? This cannot be undone."><input type="hidden" name="stamp" value="{{ item.deleted_at }}"><button class="button danger small" type="submit">Purge</button></form>
</td>
</tr>
{% else %}
<tr><td colspan="5" class="muted">De prullenbak is leeg.</td></tr>
<tr><td colspan="5" class="muted">The trash is empty.</td></tr>
{% endfor %}
</tbody>
</table>
+4 -4
View File
@@ -4,17 +4,17 @@
<h1>Accounts</h1>
<div class="table-wrap">
<table class="admin-table">
<thead><tr><th>Naam</th><th>Rol</th><th>Sinds</th><th></th></tr></thead>
<thead><tr><th>Name</th><th>Role</th><th>Since</th><th></th></tr></thead>
<tbody>
{% for user in users %}
<tr>
<td>{{ user.username }}{% if is_primary_admin(user) %} <span class="muted">(primair)</span>{% endif %}</td>
<td>{{ user.username }}{% if is_primary_admin(user) %} <span class="muted">(primary)</span>{% endif %}</td>
<td>{{ user.role }}</td>
<td>{{ local_dt(user.created_at, 'date') }}</td>
<td>
<form class="actions" method="post" action="/admin/users/{{ user.uid }}/role">
<select name="role" aria-label="Rol"><option value="Admin" {% if user.role == 'Admin' %}selected{% endif %}>Admin</option><option value="Member" {% if user.role == 'Member' %}selected{% endif %}>Member</option></select>
<button class="button ghost small" type="submit">Zet</button>
<select name="role" aria-label="Role"><option value="Admin" {% if user.role == 'Admin' %}selected{% endif %}>Admin</option><option value="Member" {% if user.role == 'Member' %}selected{% endif %}>Member</option></select>
<button class="button ghost small" type="submit">Set</button>
</form>
</td>
</tr>