new feat übersetzer und faq
This commit is contained in:
155
backend/app.py
155
backend/app.py
@@ -53,6 +53,7 @@ ALLOWED_MIME_TYPES = {
|
||||
}
|
||||
|
||||
LOCATION_VIDEO_EXTENSIONS = {".mp4", ".webm", ".mov", ".m4v"}
|
||||
ONBOARDING_VERSION = 2
|
||||
|
||||
DEFAULT_INVITATION_GROUPS = [
|
||||
{
|
||||
@@ -330,8 +331,8 @@ TEXTS = {
|
||||
"hero_headline_with_group": "Willkommen zu unserer Hochzeit, {name}",
|
||||
"hero_text_single": "Wir freuen uns riesig, diesen besonderen Tag am 04.09.26 mit dir zu feiern.",
|
||||
"hero_text_group": "Wir freuen uns riesig, diesen besonderen Tag am 04.09.26 mit euch zu feiern.",
|
||||
"hero_app_hint_single": "In dieser Webapp kannst du zu- oder absagen, Fotos hochladen, die Galerie ansehen und alle wichtigen Infos rund um den Tag finden. Bitte gib deine Zu- oder Absage möglichst bald ab.",
|
||||
"hero_app_hint": "In dieser Webapp könnt ihr zu- oder absagen, Fotos hochladen, die Galerie ansehen und alle wichtigen Infos rund um den Tag finden. Bitte gebt eure Zu- oder Absage möglichst bald ab.",
|
||||
"hero_app_hint_single": "In dieser Webapp kannst du zu- oder absagen, Fotos hochladen, die Galerie ansehen und alle wichtigen Infos rund um den Tag finden. Im Header findest du außerdem unsere FAQ und eine Deutsch-Englisch-Übersetzungshilfe. Bitte gib deine Zu- oder Absage möglichst bald ab.",
|
||||
"hero_app_hint": "In dieser Webapp könnt ihr zu- oder absagen, Fotos hochladen, die Galerie ansehen und alle wichtigen Infos rund um den Tag finden. Im Header findet ihr außerdem unsere FAQ und eine Deutsch-Englisch-Übersetzungshilfe. Bitte gebt eure Zu- oder Absage möglichst bald ab.",
|
||||
"to_guest_area": "Zum Gästebereich",
|
||||
"schedule_text": "15:00 Trauung, 17:00 Empfang, 19:00 Dinner.",
|
||||
"schedule_intro": "Hier findet ihr den Ablauf für unseren Hochzeitstag.",
|
||||
@@ -373,6 +374,7 @@ TEXTS = {
|
||||
"gifts_teaser": "Wir würden uns über diese Geschenke sehr freuen...",
|
||||
"gifts_reveal_button": "Wunsch aufdecken",
|
||||
"gifts_image_alt": "Ein großer Haufen Geldscheine",
|
||||
"gifts_money_label": "Moneten",
|
||||
"gifts_caption": "Trommelwirbel... in unserer 70-Quadratmeter-Wohnung ist leider kein Platz mehr für Materielles.",
|
||||
"gifts_text": "Also: Money! Ein finanzieller Beitrag zu unserer Reise nach der Hochzeit ist herzlich willkommen.",
|
||||
"gallery_uploaded_by": "von {name}",
|
||||
@@ -409,6 +411,57 @@ TEXTS = {
|
||||
"flash_admin_only": "Dieser Bereich ist nur für Admins verfügbar.",
|
||||
"dashboard": "Dashboard",
|
||||
"back": "Zurück",
|
||||
"faq": "Häufig gestellte Fragen",
|
||||
"faq_intro": "Hier findet ihr Antworten auf die wichtigsten Fragen rund um unsere Hochzeit.",
|
||||
"faq_deadline_question": "Bis wann sollen wir zu- oder absagen?",
|
||||
"faq_deadline_answer": "Bitte gebt uns bis spätestens 4. August 2026 über den Bereich „Zu-/Absage“ Bescheid.",
|
||||
"faq_change_question": "Kann ich meine Antwort später noch ändern?",
|
||||
"faq_change_answer": "Ja, ihr könnt eure Zu- oder Absage jederzeit bis zum Ende der Rückmeldefrist anpassen.",
|
||||
"faq_when_where_question": "Wann und wo findet die Hochzeit statt?",
|
||||
"faq_when_where_answer": "Unsere Hochzeit beginnt um 15:30 Uhr auf der Hochheimer Terrasse. Weitere Informationen findet ihr auf der Location-Seite.",
|
||||
"faq_parking_question": "Gibt es Parkmöglichkeiten?",
|
||||
"faq_parking_answer": "In der Hochheimer Altstadt und in der näheren Umgebung gibt es viele Parkmöglichkeiten. Plant bitte etwas Zeit für die Parkplatzsuche und den anschließenden Fußweg ein.",
|
||||
"faq_hotel_question": "Wo können wir übernachten?",
|
||||
"faq_hotel_answer": "Für eine möglichst kurze Anreise empfehlen wir euch eine Unterkunft direkt in Hochheim oder in der näheren Umgebung. Eine Auswahl findet ihr auf unserer Hotel-Seite.",
|
||||
"faq_upload_question": "Wie funktioniert der Foto-Upload?",
|
||||
"faq_upload_answer": "Über den Bereich „Upload“ könnt ihr Fotos direkt von eurem Smartphone oder Computer hochladen.",
|
||||
"faq_visibility_question": "Wer kann die hochgeladenen Bilder sehen?",
|
||||
"faq_visibility_answer": "Die Bilder sind ausschließlich für eingeloggte Hochzeitsgäste sichtbar. Eure eigenen Uploads könnt ihr selbst wieder löschen.",
|
||||
"translator": "Übersetzungshilfe",
|
||||
"translator_kicker": "Deutsch & Englisch",
|
||||
"translator_close": "Übersetzungshilfe schließen",
|
||||
"translator_direction": "Übersetzungsrichtung",
|
||||
"translator_swap": "Übersetzungsrichtung wechseln",
|
||||
"translator_input_label": "Was möchtest du übersetzen?",
|
||||
"translator_placeholder": "Kurzen Text eingeben …",
|
||||
"translator_quick_phrases": "Schnelle Sätze",
|
||||
"translator_phrase_meet": "Kennenlernen",
|
||||
"translator_phrase_drink": "Getränk anbieten",
|
||||
"translator_phrase_restroom": "Toilette finden",
|
||||
"translator_privacy": "Der Text wird erst nach dem Klick an DeepL übertragen. Bitte keine Namen, Kontaktdaten oder vertraulichen Inhalte eingeben.",
|
||||
"translator_submit": "Mit DeepL übersetzen",
|
||||
"translator_policy": "Datenschutz bei DeepL",
|
||||
"language_german": "Deutsch",
|
||||
"language_english": "Englisch",
|
||||
"tour_title": "Willkommen in unserer Hochzeits-App",
|
||||
"tour_progress": "Schritt {current} von {total}",
|
||||
"tour_dashboard_title": "Alles auf einen Blick",
|
||||
"tour_dashboard_text": "Im Dashboard findet ihr alle wichtigen Bereiche und Informationen für unseren Hochzeitstag.",
|
||||
"tour_rsvp_title": "Zu- oder Absage",
|
||||
"tour_rsvp_text": "Gebt die Rückmeldung für jedes Mitglied eurer Einladung bequem über den Bereich „Zu-/Absage“ ab.",
|
||||
"tour_photos_title": "Fotos & Galerie",
|
||||
"tour_photos_text": "Ladet eure Fotos direkt vom Smartphone hoch, entdeckt die gemeinsame Galerie und ladet Erinnerungen herunter.",
|
||||
"tour_routes_title": "Hotels, Location & Routen",
|
||||
"tour_routes_text": "Bei den Hotels und der Location könnt ihr Routen mit Google Maps öffnen. Karten werden erst nach eurem Klick geladen.",
|
||||
"tour_translator_title": "Übersetzungshilfe",
|
||||
"tour_translator_text": "Über das Buch im Header könnt ihr kurze deutsche oder englische Texte für die Übersetzung mit DeepL vorbereiten.",
|
||||
"tour_faq_title": "Häufig gestellte Fragen",
|
||||
"tour_faq_text": "Das Fragezeichen im Header führt euch jederzeit zu den wichtigsten Antworten rund um die Hochzeit.",
|
||||
"tour_back": "Zurück",
|
||||
"tour_next": "Weiter",
|
||||
"tour_skip": "Überspringen",
|
||||
"tour_finish": "Los geht’s",
|
||||
"tour_restart": "Einführung erneut ansehen",
|
||||
"countdown_button_label": "Countdown bis zur Hochzeit",
|
||||
"countdown_until": "Noch",
|
||||
"countdown_started": "Die Feier hat begonnen",
|
||||
@@ -474,8 +527,8 @@ TEXTS = {
|
||||
"hero_headline_with_group": "Welcome to our wedding, {name}",
|
||||
"hero_text_single": "We are incredibly excited to celebrate this special day on 09/04/26 with you.",
|
||||
"hero_text_group": "We are incredibly excited to celebrate this special day on 09/04/26 with all of you.",
|
||||
"hero_app_hint_single": "In this web app, you can send your RSVP, upload photos, view the gallery, and find all important details for the day. Please submit your RSVP soon.",
|
||||
"hero_app_hint": "In this web app, you can send your RSVP, upload photos, view the gallery, and find all important details for the day. Please submit your RSVP soon.",
|
||||
"hero_app_hint_single": "In this web app, you can send your RSVP, upload photos, view the gallery, and find all important details for the day. The header also includes our FAQ and a German-English translation helper. Please submit your RSVP soon.",
|
||||
"hero_app_hint": "In this web app, you can send your RSVP, upload photos, view the gallery, and find all important details for the day. The header also includes our FAQ and a German-English translation helper. Please submit your RSVP soon.",
|
||||
"to_guest_area": "Open guest area",
|
||||
"schedule_text": "3:00 PM ceremony, 5:00 PM reception, 7:00 PM dinner.",
|
||||
"schedule_intro": "Here is the schedule for our wedding day.",
|
||||
@@ -517,6 +570,7 @@ TEXTS = {
|
||||
"gifts_teaser": "We would be very happy to receive these gifts...",
|
||||
"gifts_reveal_button": "Reveal wish",
|
||||
"gifts_image_alt": "A big pile of cash",
|
||||
"gifts_money_label": "Moolah",
|
||||
"gifts_caption": "Drum roll... in our 70-square-meter apartment, we sadly have no room left for material things.",
|
||||
"gifts_text": "So: Money! A financial contribution to our trip after the wedding is very welcome.",
|
||||
"gallery_uploaded_by": "by {name}",
|
||||
@@ -553,6 +607,57 @@ TEXTS = {
|
||||
"flash_admin_only": "This area is available to admins only.",
|
||||
"dashboard": "Dashboard",
|
||||
"back": "Back",
|
||||
"faq": "Frequently Asked Questions",
|
||||
"faq_intro": "Here you will find answers to the most important questions about our wedding.",
|
||||
"faq_deadline_question": "When do we need to RSVP by?",
|
||||
"faq_deadline_answer": "Please let us know whether you will be attending by 4 August 2026 in the “RSVP” section.",
|
||||
"faq_change_question": "Can I change my response later?",
|
||||
"faq_change_answer": "Yes, you can update your RSVP at any time before the response deadline.",
|
||||
"faq_when_where_question": "When and where is the wedding taking place?",
|
||||
"faq_when_where_answer": "Our wedding begins at 3:30 PM at Hochheimer Terrasse. You can find more information on the location page.",
|
||||
"faq_parking_question": "Is parking available?",
|
||||
"faq_parking_answer": "There are plenty of parking options in Hochheim's old town and the surrounding area. Please allow some extra time to find a space and walk to the venue.",
|
||||
"faq_hotel_question": "Where can we stay overnight?",
|
||||
"faq_hotel_answer": "For the shortest possible journey, we recommend staying in Hochheim or nearby. You can find a selection on our hotels page.",
|
||||
"faq_upload_question": "How does the photo upload work?",
|
||||
"faq_upload_answer": "You can upload photos directly from your smartphone or computer in the “Upload” section.",
|
||||
"faq_visibility_question": "Who can see the uploaded photos?",
|
||||
"faq_visibility_answer": "The photos are visible only to logged-in wedding guests. You can delete your own uploads at any time.",
|
||||
"translator": "Translation helper",
|
||||
"translator_kicker": "English & German",
|
||||
"translator_close": "Close translation helper",
|
||||
"translator_direction": "Translation direction",
|
||||
"translator_swap": "Switch translation direction",
|
||||
"translator_input_label": "What would you like to translate?",
|
||||
"translator_placeholder": "Enter a short text …",
|
||||
"translator_quick_phrases": "Quick phrases",
|
||||
"translator_phrase_meet": "Meeting someone",
|
||||
"translator_phrase_drink": "Offering a drink",
|
||||
"translator_phrase_restroom": "Finding the restroom",
|
||||
"translator_privacy": "Your text is sent to DeepL only after you click the button. Please do not enter names, contact details, or confidential information.",
|
||||
"translator_submit": "Translate with DeepL",
|
||||
"translator_policy": "DeepL privacy policy",
|
||||
"language_german": "German",
|
||||
"language_english": "English",
|
||||
"tour_title": "Welcome to our wedding app",
|
||||
"tour_progress": "Step {current} of {total}",
|
||||
"tour_dashboard_title": "Everything at a glance",
|
||||
"tour_dashboard_text": "The dashboard brings together all the important sections and information for our wedding day.",
|
||||
"tour_rsvp_title": "RSVP",
|
||||
"tour_rsvp_text": "Submit a response for every member of your invitation conveniently in the “RSVP” section.",
|
||||
"tour_photos_title": "Photos & gallery",
|
||||
"tour_photos_text": "Upload photos directly from your phone, explore the shared gallery, and download your favourite memories.",
|
||||
"tour_routes_title": "Hotels, location & routes",
|
||||
"tour_routes_text": "You can open Google Maps routes from the hotel and location pages. Maps load only after you click.",
|
||||
"tour_translator_title": "Translation helper",
|
||||
"tour_translator_text": "Use the book in the header to prepare short German or English texts for translation with DeepL.",
|
||||
"tour_faq_title": "Frequently asked questions",
|
||||
"tour_faq_text": "The question mark in the header takes you to the most important answers about the wedding at any time.",
|
||||
"tour_back": "Back",
|
||||
"tour_next": "Next",
|
||||
"tour_skip": "Skip",
|
||||
"tour_finish": "Let’s go",
|
||||
"tour_restart": "View introduction again",
|
||||
"countdown_button_label": "Wedding countdown",
|
||||
"countdown_until": "Countdown",
|
||||
"countdown_started": "The celebration has started",
|
||||
@@ -767,6 +872,7 @@ def init_db() -> None:
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
password_hash TEXT NOT NULL,
|
||||
role TEXT NOT NULL DEFAULT 'guest',
|
||||
onboarding_completed INTEGER NOT NULL DEFAULT 0,
|
||||
created_at TEXT NOT NULL
|
||||
)
|
||||
"""
|
||||
@@ -811,6 +917,8 @@ def init_db() -> None:
|
||||
group_cols = table_columns(conn, "groups")
|
||||
if "role" not in group_cols:
|
||||
conn.execute("ALTER TABLE groups ADD COLUMN role TEXT NOT NULL DEFAULT 'guest'")
|
||||
if "onboarding_completed" not in group_cols:
|
||||
conn.execute("ALTER TABLE groups ADD COLUMN onboarding_completed INTEGER NOT NULL DEFAULT 0")
|
||||
|
||||
conn.commit()
|
||||
|
||||
@@ -947,14 +1055,38 @@ def welcome():
|
||||
is_single_guest = member_count <= 1
|
||||
welcome_headline = t("hero_headline_with_group").format(name=session.get("group_name", ""))
|
||||
welcome_text = t("hero_text_single") if is_single_guest else t("hero_text_group")
|
||||
onboarding_row = db.execute(
|
||||
"SELECT onboarding_completed FROM groups WHERE id = ?",
|
||||
(int(session["group_id"]),),
|
||||
).fetchone()
|
||||
completed_onboarding_version = (
|
||||
int(onboarding_row["onboarding_completed"] or 0) if onboarding_row else 0
|
||||
)
|
||||
show_onboarding = (
|
||||
request.args.get("tour") == "1"
|
||||
or completed_onboarding_version < ONBOARDING_VERSION
|
||||
)
|
||||
return render_template(
|
||||
"welcome.html",
|
||||
welcome_headline=welcome_headline,
|
||||
welcome_text=welcome_text,
|
||||
welcome_hint=t("hero_app_hint_single") if is_single_guest else t("hero_app_hint"),
|
||||
show_onboarding=show_onboarding,
|
||||
)
|
||||
|
||||
|
||||
@app.post("/onboarding/complete")
|
||||
@login_required
|
||||
def complete_onboarding():
|
||||
db = get_db()
|
||||
db.execute(
|
||||
"UPDATE groups SET onboarding_completed = ? WHERE id = ?",
|
||||
(ONBOARDING_VERSION, int(session["group_id"])),
|
||||
)
|
||||
db.commit()
|
||||
return ("", 204)
|
||||
|
||||
|
||||
@app.get("/gaestebereich")
|
||||
@app.get("/gästebereich")
|
||||
@login_required
|
||||
@@ -1002,6 +1134,21 @@ def dashboard():
|
||||
return redirect(url_for("guest_area"))
|
||||
|
||||
|
||||
@app.get("/faq")
|
||||
@login_required
|
||||
def faq():
|
||||
faq_items = [
|
||||
("faq_deadline_question", "faq_deadline_answer"),
|
||||
("faq_change_question", "faq_change_answer"),
|
||||
("faq_when_where_question", "faq_when_where_answer"),
|
||||
("faq_parking_question", "faq_parking_answer"),
|
||||
("faq_hotel_question", "faq_hotel_answer"),
|
||||
("faq_upload_question", "faq_upload_answer"),
|
||||
("faq_visibility_question", "faq_visibility_answer"),
|
||||
]
|
||||
return render_template("faq.html", faq_items=faq_items)
|
||||
|
||||
|
||||
@app.route("/rsvp", methods=["GET", "POST"])
|
||||
@login_required
|
||||
def rsvp():
|
||||
|
||||
Reference in New Issue
Block a user