diff --git a/app/routers/web.py b/app/routers/web.py index a65a6f6..d553838 100644 --- a/app/routers/web.py +++ b/app/routers/web.py @@ -815,6 +815,16 @@ def public_showcase(request: Request, username: str, db: Session = Depends(get_d user = db.query(User).filter(User.username == username).first() if not user: return HTMLResponse("用户不存在", status_code=404) + + # Language: query param > cookie > owner's default + from app.i18n import get_languages + _avail = get_languages() + visitor_lang = request.query_params.get("lang") + if not visitor_lang or visitor_lang not in _avail: + visitor_lang = request.cookies.get("showcase_lang") + if not visitor_lang or visitor_lang not in _avail: + visitor_lang = user.language + profiles = db.query(Profile).filter(Profile.user_id == user.id, Profile.showcase_enabled == True).all() sent_all, received_all, profile_groups = [], [], [] for p in profiles: @@ -837,11 +847,13 @@ def public_showcase(request: Request, username: str, db: Session = Depends(get_d profile_groups.append({"profile": p, "sent": p_sent, "received": p_received}) sent_all.sort(key=lambda c: c.send_time or c.created_at, reverse=True) received_all.sort(key=lambda c: c.receive_time or c.created_at, reverse=True) - return templates.TemplateResponse("showcase.html", { + resp = templates.TemplateResponse("showcase.html", { "request": request, "profile_user": user, "mode": user.showcase_mode, "profile_groups": profile_groups, "sent_all": sent_all, "received_all": received_all, - "lang": user.language, + "lang": visitor_lang, "available_languages": _avail, }) + resp.set_cookie("showcase_lang", visitor_lang, max_age=365 * 24 * 3600, httponly=True, samesite="lax") + return resp # ---------- API Keys ---------- diff --git a/app/static/style.css b/app/static/style.css index 5082f1b..c3a61ff 100644 --- a/app/static/style.css +++ b/app/static/style.css @@ -39,6 +39,7 @@ a:hover { text-decoration: underline; } .lang-option { display: block; width: 100%; padding: .35rem .75rem; border: none; background: none; text-align: left; font-size: .8rem; color: var(--text); cursor: pointer; white-space: nowrap; } .lang-option:hover { background: var(--bg); color: var(--primary); } .lang-option.active { color: var(--primary); font-weight: 600; } +.showcase-lang-bar { position: fixed; top: 1rem; right: 1.5rem; z-index: 100; } /* Container */ .container { max-width: 960px; margin: 2rem auto; padding: 0 1.5rem; } diff --git a/app/templates/showcase.html b/app/templates/showcase.html index ea1d786..660db96 100644 --- a/app/templates/showcase.html +++ b/app/templates/showcase.html @@ -2,6 +2,16 @@ {% block title %}{{ profile_user.username }} {{ 'showcase.title'|t(lang) }}{% endblock %} {% block nav %}{% endblock %} {% block content %} +
+
+ +
+ {% for code, name in available_languages.items() %} + {{ name }} + {% endfor %} +
+
+

📮 {{ profile_user.username }} {{ 'showcase.title'|t(lang) }}

@@ -184,5 +194,13 @@ document.addEventListener('keydown', function(e) { else if (e.key === 'ArrowLeft') navLightbox(-1); else if (e.key === 'ArrowRight') navLightbox(1); }); +// Close language dropdown when clicking outside +document.addEventListener('click', function(e) { + var sw = document.getElementById('langSwitcher'); + var dd = document.getElementById('langDropdown'); + if (sw && dd && !sw.contains(e.target)) { + dd.classList.remove('show'); + } +}); {% endblock %}