Add bilingual UI and improve event actions layout

Add persistent German/English switching, translated UI messages and English 12-hour times. Align desktop event actions while preserving mobile layouts and record bilingual project guidance.

Include pending diary deletion exclusions. Validate both languages with nine tests.
This commit is contained in:
kai
2026-09-14 15:31:56 +02:00
parent b2af6c6857
commit b2af866cf0
28 changed files with 1339 additions and 506 deletions
+18 -16
View File
@@ -1,9 +1,9 @@
<!DOCTYPE html>
<html lang="de">
<html lang="{{ language() }}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Nachrichten · MetalCircle</title>
<title>{{ _('Nachrichten · MetalCircle') }}</title>
<link rel="icon" type="image/png" href="/static/images/metalcircle-circle.png">
<link rel="stylesheet" href="/static/css/style.css">
<style>
@@ -38,9 +38,11 @@
.conversation-heading { margin-top: 20px; }
@media (max-width: 600px) { .chat-form { grid-template-columns: 1fr; } .chat-bubble { max-width: 90%; } }
</style>
<link rel="stylesheet" href="/static/css/language.css">
</head>
<body>
<header><div class="header-inner"><a href="/" class="logo"><img class="brand-logo" src="/static/images/metalcircle-full.png" alt="MetalCircle"></a>{% include '_user_menu.html' %}</div></header>
<header><div class="header-inner"><a href="/" class="logo"><img class="brand-logo" src="/static/images/metalcircle-full.png" alt="MetalCircle"></a>{% include '_user_menu.html' %}</div> {% include '_language_switch.html' %}
</header>
<main>
{% if partner %}
<div class="chat-header">
@@ -49,43 +51,43 @@
</div>
<div class="chat-log">
{% for message in messages %}<div class="chat-bubble{% if message.from_me %} mine{% endif %}"{% if loop.last %} id="latest"{% endif %}>{{ message.body }}<span class="chat-time">{{ message.created_at }}</span></div>
{% else %}<p class="empty-chat">Noch keine Nachrichten. Schreib die erste!</p>{% endfor %}
{% else %}<p class="empty-chat">{{ _('Noch keine Nachrichten. Schreib die erste!') }}</p>{% endfor %}
</div>
<form class="chat-form" method="post" action="/messages/{{ partner.username }}">
<textarea name="body" maxlength="2000" required placeholder="Nachricht schreiben …" aria-label="Nachricht"></textarea>
<button class="button" type="submit">Senden</button>
<textarea name="body" maxlength="2000" required placeholder="{{ _('Nachricht schreiben …') }}" aria-label="{{ _('Nachricht') }}"></textarea>
<button class="button" type="submit">{{ _('Senden') }}</button>
</form>
<p><a class="button button-secondary" href="/messages">← Alle Nachrichten</a></p>
<p><a class="button button-secondary" href="/messages">{{ _('← Alle Nachrichten') }}</a></p>
{% else %}
<div class="page-title"><h1>🤘 Nachrichten</h1><p>Private Chats mit deinen Freunden.</p></div>
<div class="page-title"><h1>{{ _('🤘 Nachrichten') }}</h1><p>{{ _('Private Chats mit deinen Freunden.') }}</p></div>
{% if friend_requests or event_invitations %}
<section class="message-notifications">
<h2>Neue Anfragen</h2>
<h2>{{ _('Neue Anfragen') }}</h2>
{% for request in friend_requests %}
<div class="notification-row">
<span class="notification-icon">🤝</span>
<span><strong>{{ request.display_name }}</strong> möchte sich mit dir befreunden.<small>{{ request.created_at }}</small></span>
<span class="notification-actions"><form method="post" action="/friendships/{{ request.id }}/accept"><input type="hidden" name="return_to" value="/messages"><button class="button" type="submit">Annehmen</button></form><form method="post" action="/friendships/{{ request.id }}/decline"><input type="hidden" name="return_to" value="/messages"><button class="button button-secondary" type="submit">Ablehnen</button></form></span>
<span><strong>{{ request.display_name }}</strong> {{ _('möchte sich mit dir befreunden.') }}<small>{{ request.created_at }}</small></span>
<span class="notification-actions"><form method="post" action="/friendships/{{ request.id }}/accept"><input type="hidden" name="return_to" value="/messages"><button class="button" type="submit">{{ _('Annehmen') }}</button></form><form method="post" action="/friendships/{{ request.id }}/decline"><input type="hidden" name="return_to" value="/messages"><button class="button button-secondary" type="submit">{{ _('Ablehnen') }}</button></form></span>
</div>
{% endfor %}
{% for invitation in event_invitations %}
<a class="notification-row" href="/concerts/{{ invitation.concert_id }}">
<span class="notification-icon">✉️</span>
<span><strong>{{ invitation.artist }}</strong> Einladung von {{ invitation.invited_by }}<small>{{ invitation.date }}</small></span>
<span class="notification-link">Ansehen →</span>
<span><strong>{{ invitation.artist }}</strong> {{ _(' Einladung von') }} {{ invitation.invited_by }}<small>{{ invitation.date }}</small></span>
<span class="notification-link">{{ _('Ansehen →') }}</span>
</a>
{% endfor %}
</section>
{% endif %}
<h2 class="conversation-heading">Unterhaltungen</h2>
<h2 class="conversation-heading">{{ _('Unterhaltungen') }}</h2>
<div class="conversation-list">
{% for conversation in conversations %}
<a class="conversation-card" href="/messages/{{ conversation.username }}">
{% if conversation.avatar_path %}<img class="chat-avatar" src="{{ conversation.avatar_path }}" alt="">{% else %}<span class="chat-avatar">{{ conversation.display_name[:1] }}</span>{% endif %}
<span class="conversation-copy"><strong>{{ conversation.display_name }}</strong><span>{% if conversation.last_message %}{% if conversation.last_from_me %}Du: {% endif %}{{ conversation.last_message }} · {{ conversation.last_at }}{% else %}Chat beginnen{% endif %}</span></span>
<span class="conversation-copy"><strong>{{ conversation.display_name }}</strong><span>{% if conversation.last_message %}{% if conversation.last_from_me %}{{ _('Du:') }} {% endif %}{{ conversation.last_message }} · {{ conversation.last_at }}{% else %}{{ _('Chat beginnen') }}{% endif %}</span></span>
{% if conversation.unread_count %}<span class="unread-badge">{{ conversation.unread_count }}</span>{% endif %}
</a>
{% else %}<div class="empty"><h2>Noch keine Chats</h2><p>Chats sind mit bestätigten Freunden und mit Admins verfügbar.</p></div>{% endfor %}
{% else %}<div class="empty"><h2>{{ _('Noch keine Chats') }}</h2><p>{{ _('Chats sind mit bestätigten Freunden und mit Admins verfügbar.') }}</p></div>{% endfor %}
</div>
{% endif %}
</main>