{config.APP_NAME} · - The padel business planning platform + {tagline}
- © {year} {config.APP_NAME}. You received this email because you have an account or submitted a request. + {copyright_text}
@@ -174,6 +187,7 @@ async def handle_send_email(payload: dict) -> None: @task("send_magic_link") async def handle_send_magic_link(payload: dict) -> None: """Send magic link email.""" + lang = payload.get("lang", "en") link = f"{config.BASE_URL}/auth/verify?token={payload['token']}" if config.DEBUG: @@ -183,19 +197,18 @@ async def handle_send_magic_link(payload: dict) -> None: print(f"{'='*60}\n") body = ( - f'Click the button below to sign in. This link expires in " - f"{config.MAGIC_LINK_EXPIRY_MINUTES} minutes.
" - f"{_email_button(link, 'Sign In')}" - f'If the button doesn\'t work, copy and paste this URL into your browser:
' + f'{_t("email_magic_link_body", lang, expiry_minutes=config.MAGIC_LINK_EXPIRY_MINUTES)}
' + f'{_email_button(link, _t("email_magic_link_btn", lang))}' + f'{_t("email_magic_link_fallback", lang)}
' f'{link}
' - f'If you didn\'t request this, you can safely ignore this email.
' + f'{_t("email_magic_link_ignore", lang)}
' ) await send_email( to=payload["email"], - subject=f"Sign in to {config.APP_NAME}", - html=_email_wrap(body), + subject=_t("email_magic_link_subject", lang, app_name=config.APP_NAME), + html=_email_wrap(body, lang), from_addr=EMAIL_ADDRESSES["transactional"], ) @@ -228,22 +241,20 @@ async def handle_send_quote_verification(payload: dict) -> None: project_desc = f" for your {' '.join(parts)} project" body = ( - f'Hi {first_name},
" - f"Thanks for requesting quotes{project_desc}. " - f"Click the button below to verify your email and activate your quote request. " - f"This will also create your {config.APP_NAME} account so you can track your project.
" - f"{_email_button(link, 'Verify & Activate Quote')}" - f'This link expires in 60 minutes.
' - f'If the button doesn\'t work, copy and paste this URL into your browser:
' + f'{_t("email_quote_verify_greeting", lang, first_name=first_name)}
' + f'{_t("email_quote_verify_body", lang, project_desc=project_desc, app_name=config.APP_NAME)}
' + f'{_email_button(link, _t("email_quote_verify_btn", lang))}' + f'{_t("email_quote_verify_expires", lang)}
' + f'{_t("email_quote_verify_fallback", lang)}
' f'{link}
' - f'If you didn\'t request this, you can safely ignore this email.
' + f'{_t("email_quote_verify_ignore", lang)}
' ) await send_email( to=payload["email"], - subject="Verify your email to get supplier quotes", - html=_email_wrap(body), + subject=_t("email_quote_verify_subject", lang), + html=_email_wrap(body, lang), from_addr=EMAIL_ADDRESSES["transactional"], ) @@ -251,16 +262,17 @@ async def handle_send_quote_verification(payload: dict) -> None: @task("send_welcome") async def handle_send_welcome(payload: dict) -> None: """Send welcome email to new user.""" + lang = payload.get("lang", "en") body = ( - f'Thanks for signing up. You're all set to start planning your padel business.
" - f'{_email_button(f"{config.BASE_URL}/dashboard", "Go to Dashboard")}' + f'{_t("email_welcome_body", lang)}
' + f'{_email_button(f"{config.BASE_URL}/dashboard", _t("email_welcome_btn", lang))}' ) await send_email( to=payload["email"], - subject=f"Welcome to {config.APP_NAME}", - html=_email_wrap(body), + subject=_t("email_welcome_subject", lang, app_name=config.APP_NAME), + html=_email_wrap(body, lang), from_addr=EMAIL_ADDRESSES["transactional"], ) @@ -269,45 +281,40 @@ async def handle_send_welcome(payload: dict) -> None: async def handle_send_waitlist_confirmation(payload: dict) -> None: """Send waitlist confirmation email.""" intent = payload.get("intent", "signup") + lang = payload.get("lang", "en") email = payload["email"] if intent.startswith("supplier_"): - # Supplier waitlist plan_name = intent.replace("supplier_", "").title() - subject = f"You're on the list — {config.APP_NAME} {plan_name} is launching soon" + subject = _t("email_waitlist_supplier_subject", lang, app_name=config.APP_NAME, plan_name=plan_name) body = ( - f'Thanks for your interest in the {plan_name} plan. ' - f'We\'re building the ultimate supplier platform for padel entrepreneurs.
' - f'You\'ll be among the first to know when we launch. ' - f'We\'ll send you early access, exclusive launch pricing, and onboarding support.
' - f'In the meantime, explore our free resources:
' + f'{_t("email_waitlist_supplier_body", lang, plan_name=plan_name)}
' + f'{_t("email_waitlist_supplier_perks", lang)}
' + f'{_t("email_waitlist_supplier_meanwhile", lang)}
' f'Thanks for joining the waitlist. We\'re preparing to launch the ultimate planning platform ' - 'for padel entrepreneurs.
' - 'You\'ll be among the first to get access when we open. ' - 'We\'ll send you:
' - 'We\'ll be in touch soon.
' + f'{_t("email_waitlist_general_body", lang)}
' + f'{_t("email_waitlist_general_perks_intro", lang)}
' + f'{_t("email_waitlist_general_outro", lang)}
' ) await send_email( to=email, subject=subject, - html=_email_wrap(body), + html=_email_wrap(body, lang), from_addr=EMAIL_ADDRESSES["transactional"], ) @@ -331,6 +338,7 @@ async def handle_cleanup_rate_limits(payload: dict) -> None: @task("send_lead_forward_email") async def handle_send_lead_forward_email(payload: dict) -> None: """Send full project brief to supplier who unlocked/was forwarded a lead.""" + lang = payload.get("lang", "en") lead_id = payload["lead_id"] supplier_id = payload["supplier_id"] @@ -346,14 +354,16 @@ async def handle_send_lead_forward_email(payload: dict) -> None: subject = f"[{heat}] New padel project in {country} — {courts} courts, €{budget}" + t = lambda key: _t(key, lang) # noqa: E731 + brief_rows = [ - ("Facility", f"{lead['facility_type'] or '-'} ({lead['build_context'] or '-'})"), - ("Courts", f"{courts} | Glass: {lead['glass_type'] or '-'} | Lighting: {lead['lighting_type'] or '-'}"), - ("Location", f"{lead['location'] or '-'}, {country}"), - ("Timeline", f"{lead['timeline'] or '-'} | Budget: €{budget}"), - ("Phase", f"{lead['location_status'] or '-'} | Financing: {lead['financing_status'] or '-'}"), - ("Services", lead["services_needed"] or "-"), - ("Additional", lead["additional_info"] or "-"), + (t("email_lead_forward_lbl_facility"), f"{lead['facility_type'] or '-'} ({lead['build_context'] or '-'})"), + (t("email_lead_forward_lbl_courts"), f"{courts} | Glass: {lead['glass_type'] or '-'} | Lighting: {lead['lighting_type'] or '-'}"), + (t("email_lead_forward_lbl_location"), f"{lead['location'] or '-'}, {country}"), + (t("email_lead_forward_lbl_timeline"), f"{lead['timeline'] or '-'} | Budget: €{budget}"), + (t("email_lead_forward_lbl_phase"), f"{lead['location_status'] or '-'} | Financing: {lead['financing_status'] or '-'}"), + (t("email_lead_forward_lbl_services"), lead["services_needed"] or "-"), + (t("email_lead_forward_lbl_additional"), lead["additional_info"] or "-"), ] brief_html = "" @@ -364,11 +374,11 @@ async def handle_send_lead_forward_email(payload: dict) -> None: ) contact_rows = [ - ("Name", lead["contact_name"] or "-"), - ("Email", lead["contact_email"] or "-"), - ("Phone", lead["contact_phone"] or "-"), - ("Company", lead["contact_company"] or "-"), - ("Role", lead["stakeholder_type"] or "-"), + (t("email_lead_forward_lbl_name"), lead["contact_name"] or "-"), + (t("email_lead_forward_lbl_email"), lead["contact_email"] or "-"), + (t("email_lead_forward_lbl_phone"), lead["contact_phone"] or "-"), + (t("email_lead_forward_lbl_company"), lead["contact_company"] or "-"), + (t("email_lead_forward_lbl_role"), lead["stakeholder_type"] or "-"), ] contact_html = "" @@ -379,13 +389,13 @@ async def handle_send_lead_forward_email(payload: dict) -> None: ) body = ( - f'A new padel project matches your services.
' - f'{t("email_lead_forward_subheading")}
' + f'Hi {first_name},
' - f'Great news — a verified supplier has been matched with your padel project. ' - f'They have your project brief and will reach out to you directly.
' - f'You submitted a quote request for a ' - f'{lead["facility_type"] or "padel"} facility with {lead["court_count"] or "?"} courts ' - f'in {lead["country"] or "your area"}.
' - f'{_email_button(f"{config.BASE_URL}/dashboard", "View Your Dashboard")}' - f'You\'ll receive this notification each time ' - f'a new supplier unlocks your project details.
' + f'{_t("email_lead_matched_greeting", lang, first_name=first_name)}
' + f'{_t("email_lead_matched_body", lang)}
' + f'{_t("email_lead_matched_context", lang, facility_type=lead["facility_type"] or "padel", court_count=lead["court_count"] or "?", country=lead["country"] or "your area")}
' + f'{_email_button(f"{config.BASE_URL}/dashboard", _t("email_lead_matched_btn", lang))}' + f'{_t("email_lead_matched_note", lang)}
' ) await send_email( to=lead["contact_email"], - subject="A supplier is reviewing your padel project", - html=_email_wrap(body), + subject=_t("email_lead_matched_subject", lang), + html=_email_wrap(body, lang), from_addr=EMAIL_ADDRESSES["leads"], ) @@ -444,6 +450,7 @@ async def handle_send_lead_matched_notification(payload: dict) -> None: @task("send_supplier_enquiry_email") async def handle_send_supplier_enquiry_email(payload: dict) -> None: """Relay a directory enquiry form submission to the supplier's contact email.""" + lang = payload.get("lang", "en") supplier_email = payload.get("supplier_email", "") if not supplier_email: return @@ -455,22 +462,21 @@ async def handle_send_supplier_enquiry_email(payload: dict) -> None: body = ( f'You have a new directory enquiry for {supplier_name}.
' + f'{_t("email_enquiry_heading", lang, app_name=config.APP_NAME)}' + f'{_t("email_enquiry_body", lang, supplier_name=supplier_name)}
' f'| From | ' + f'|
| {_t("email_enquiry_lbl_from", lang)} | ' f'{contact_name} <{contact_email}> |
| Message | ' + f'|
| {_t("email_enquiry_lbl_message", lang)} | ' f'{message} |
Reply directly to ' - f'{contact_email} to respond.
' + f'{_t("email_enquiry_reply", lang, contact_email=contact_email)}
' ) await send_email( to=supplier_email, - subject=f"New enquiry via {config.APP_NAME}: {contact_name}", - html=_email_wrap(body), + subject=_t("email_enquiry_subject", lang, app_name=config.APP_NAME, contact_name=contact_name), + html=_email_wrap(body, lang), from_addr=EMAIL_ADDRESSES["transactional"], ) @@ -533,14 +539,14 @@ async def handle_generate_business_plan(payload: dict) -> None: user = await fetch_one("SELECT email FROM users WHERE id = ?", (user_id,)) if user: body = ( - f'Your padel business plan PDF has been generated and is ready for download.
" - f'{_email_button(f"{config.BASE_URL}/planner/export/{export_token}", "Download PDF")}' + f'{_t("email_business_plan_body", language)}
' + f'{_email_button(f"{config.BASE_URL}/planner/export/{export_token}", _t("email_business_plan_btn", language))}' ) await send_email( to=user["email"], - subject="Your Padel Business Plan PDF is Ready", - html=_email_wrap(body), + subject=_t("email_business_plan_subject", language), + html=_email_wrap(body, language), from_addr=EMAIL_ADDRESSES["transactional"], )