Phase 28 (Steps 6+9): mail active view + i18n keys
Step 6 — mail active view + subcomponents. - `lib/active-view/mail.svelte` replaces the Phase 10 stub with the list / detail layout: two-pane on desktop, one-pane stack on mobile (CSS media query, no separate route). - `lib/active-view/mail/thread-list.svelte` renders per-race threads collapsed to their last message plus stand-alone system / admin / outgoing-broadcast items, with unread badges. - `lib/active-view/mail/thread-pane.svelte` is the chat-style transcript for one race; bodies render through `textContent`, per-message Show original / translation toggles flip the rendering when a translated body is present, and a persistent reply box at the bottom calls `mailStore.composePersonal`. - `lib/active-view/mail/system-item-pane.svelte` renders one stand-alone item read-only with the same translation toggle. - `lib/active-view/mail/compose.svelte` is the compose dialog: recipient race picker fed from `report.races[]`, kind toggle (personal / broadcast / admin), admin sub-toggle for target user / all and recipient-scope picker. Server-side enforces paid-tier and owner gating; the UI surfaces 403 inline. - `lib/active-view/mail/system-titles.ts` keeps the keyword → i18n-title mapping for lifecycle-hook system mail so both the list and the detail pane pick the same canonical title. Step 9 — i18n strings (en + ru). `game.mail.*`, `game.view.mail.badge`, `game.events.mail_new.*`, `game.mail.system.*` keys added in lockstep across both locales covering compose labels / validation copy / per-system titles / translation toggle / reply / delete affordances. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
// Maps a system-mail message (lifecycle hook) to its i18n title key.
|
||||
// Kept as a typed helper so the thread-list and detail panes pick the
|
||||
// same title even when the body templates evolve.
|
||||
|
||||
import type { TranslationKey } from "$lib/i18n/index.svelte";
|
||||
import type { MailMessage } from "../../../api/diplomail";
|
||||
|
||||
const KEYWORDS: Array<{ test: RegExp; key: TranslationKey }> = [
|
||||
{ test: /game[._ ]paused/i, key: "game.mail.system.game_paused.title" },
|
||||
{ test: /game[._ ]cancelled|cancelled/i, key: "game.mail.system.game_cancelled.title" },
|
||||
{ test: /membership[._ ]removed|kicked/i, key: "game.mail.system.membership_removed.title" },
|
||||
{ test: /membership[._ ]blocked|blocked/i, key: "game.mail.system.membership_blocked.title" },
|
||||
];
|
||||
|
||||
/**
|
||||
* systemTitleKey returns the localised title key for a system mail
|
||||
* row. The lobby renders these messages through templated subjects;
|
||||
* the UI matches on the subject to pick a canonical title regardless
|
||||
* of language. Falls back to a generic system-mail title when no
|
||||
* pattern matches.
|
||||
*/
|
||||
export function systemTitleKey(message: MailMessage): TranslationKey {
|
||||
const subject = message.subject ?? "";
|
||||
for (const { test, key } of KEYWORDS) {
|
||||
if (test.test(subject)) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
return "game.mail.system.generic.title";
|
||||
}
|
||||
Reference in New Issue
Block a user