feat(i18n): convert App shell chrome to t() (Batch A)

This commit is contained in:
iamdoubz committed 2026-07-12 11:03:42 -05:00
1 parent e5fdb2baea
commit aac88bfbc5
1 file changed
+49 -48
+49 -48
View File
@@ -18,6 +18,7 @@
import ThemeToggle from "./lib/components/ThemeToggle.svelte";
import Splitter from "./lib/components/Splitter.svelte";
import { layout, clamp } from "./lib/stores/layout.svelte";
import { t } from "./lib/i18n/index.svelte";
import {
Circle,
Square,
@@ -62,7 +63,7 @@
vaultLocked = false;
meetings.load(); // refresh now that encrypted content is readable
} catch {
vaultErr = "Incorrect password";
vaultErr = t("app.vault_incorrect");
}
}
@@ -134,7 +135,7 @@
checkVault();
api
.listNoteTemplates()
.then((t) => (noteTemplates = t))
.then((tpls) => (noteTemplates = tpls))
.catch(() => (noteTemplates = []));
const media = window.matchMedia("(prefers-color-scheme: dark)");
@@ -160,7 +161,7 @@
}
async function cancelRecording() {
if (!confirm("Discard this recording? Its audio and transcript will be deleted.")) return;
if (!confirm(t("app.discard_confirm"))) return;
await recording.cancel();
meetings.deselect();
}
@@ -186,9 +187,9 @@
$effect(() => {
const current = recording.state;
if (current !== previousRecordingState) {
if (current === "recording") recordingAnnouncement = "Recording started";
else if (current === "paused") recordingAnnouncement = "Recording paused";
else if (previousRecordingState !== "idle") recordingAnnouncement = "Recording stopped";
if (current === "recording") recordingAnnouncement = t("app.announce_started");
else if (current === "paused") recordingAnnouncement = t("app.announce_paused");
else if (previousRecordingState !== "idle") recordingAnnouncement = t("app.announce_stopped");
previousRecordingState = current;
}
});
@@ -232,58 +233,54 @@
<div class="sr-only" role="status" aria-live="polite">{recordingAnnouncement}</div>
<header class="bar">
<strong>WhispAssist</strong>
<span class="muted">local · private</span>
<span class="muted">{t("app.tagline")}</span>
<div class="spacer"></div>
{#if recording.state === "idle"}
<select
class="theme-select"
bind:value={selectedTemplateId}
aria-label="Note template"
title="Note template"
aria-label={t("app.note_template")}
title={t("app.note_template")}
>
<option value="">No template</option>
{#each noteTemplates as t (t.id)}
<option value={t.id}>{t.name}</option>
<option value="">{t("app.no_template")}</option>
{#each noteTemplates as tpl (tpl.id)}
<option value={tpl.id}>{tpl.name}</option>
{/each}
</select>
<button
class="import-btn"
onclick={() => (showImport = true)}
title="Add a meeting from a file or URL"
title={t("app.add_meeting_title")}
>
<FilePlus size={13} aria-hidden="true" />
Add meeting
{t("app.add_meeting")}
</button>
<button
class="record-btn"
onclick={startRecording}
title="Start recording (Ctrl+Shift+R)"
title={t("app.record_title")}
aria-keyshortcuts="Control+Shift+R"
>
<Circle size={11} fill="currentColor" aria-hidden="true" />
Record
{t("app.record")}
</button>
{:else}
<button
class="stop-btn"
onclick={() => recording.stop()}
title="Stop recording (Ctrl+Shift+R)"
title={t("app.stop_title")}
aria-keyshortcuts="Control+Shift+R"
>
<Square size={11} fill="currentColor" aria-hidden="true" />
Stop
{t("app.stop")}
</button>
<button
class="cancel-btn"
onclick={cancelRecording}
title="Discard this recording and delete it"
>
<button class="cancel-btn" onclick={cancelRecording} title={t("app.cancel_title")}>
<Trash2 size={12} aria-hidden="true" />
Cancel
{t("app.cancel")}
</button>
<span class="rec">
<span class="rec-dot" aria-hidden="true"></span>
Recording…
{t("app.recording")}
</span>
<LevelMeter
rms={recording.levelRms}
@@ -293,16 +290,16 @@
showMic={settings.settings.microphone_enabled}
/>
{#if settings.hardware}
<span class="backend" title="Active transcription backend">{settings.hardware.active}</span>
<span class="backend" title={t("app.backend_title")}>{settings.hardware.active}</span>
{/if}
<label class="retention" title="Save audio as .wav for this meeting">
<label class="retention" title={t("app.retention_title")}>
<input type="checkbox" checked={recording.retention} onchange={onToggleRetention} />
<span>{recording.retention ? "saving" : "not saved"}</span>
<span>{recording.retention ? t("app.saving") : t("app.not_saved")}</span>
</label>
{#if recording.deviceNotice}
<span class="device-notice" role="status" title={recording.deviceNotice}>
<AlertTriangle size={14} aria-hidden="true" />
reconnecting audio device…
{t("app.reconnecting")}
</span>
{/if}
{/if}
@@ -312,8 +309,8 @@
/>
<button
class="icon"
aria-label="Settings"
title="Settings (Ctrl+,)"
aria-label={t("app.settings")}
title={t("app.settings_title")}
aria-keyshortcuts="Control+,"
onclick={() => (showSettings = !showSettings)}
>
@@ -326,7 +323,7 @@
class="consent-overlay"
role="dialog"
aria-modal="true"
aria-label="Recording consent"
aria-label={t("app.consent_dialog")}
tabindex="-1"
use:trapFocus
>
@@ -347,23 +344,27 @@
class="vault-overlay"
role="dialog"
aria-modal="true"
aria-label="Unlock encryption vault"
aria-label={t("app.vault_dialog")}
tabindex="-1"
use:trapFocus
>
<div class="vault-card">
<h2>Unlock encryption vault</h2>
<p class="muted">Your meetings are encrypted at rest. Enter your password to read them.</p>
<h2>{t("app.vault_title")}</h2>
<p class="muted">{t("app.vault_desc")}</p>
<input
type="password"
placeholder="Vault password"
placeholder={t("app.vault_password")}
bind:value={vaultPw}
onkeydown={(e) => e.key === "Enter" && submitUnlock()}
/>
{#if vaultErr}<p class="vault-err">{vaultErr}</p>{/if}
<div class="vault-actions">
<button class="primary" onclick={submitUnlock} disabled={!vaultPw}>Unlock</button>
<button class="link" onclick={() => (vaultLocked = false)}>Continue locked</button>
<button class="primary" onclick={submitUnlock} disabled={!vaultPw}
>{t("app.unlock")}</button
>
<button class="link" onclick={() => (vaultLocked = false)}
>{t("app.continue_locked")}</button
>
</div>
</div>
</div>
@@ -385,8 +386,8 @@
layout.leftCollapsed = false;
layout.persist();
}}
title="Show meetings list"
aria-label="Show meetings list"
title={t("app.show_meetings")}
aria-label={t("app.show_meetings")}
>
<PanelLeftOpen size={16} aria-hidden="true" />
</button>
@@ -397,8 +398,8 @@
layout.leftCollapsed = true;
layout.persist();
}}
title="Hide meetings list"
aria-label="Hide meetings list"
title={t("app.hide_meetings")}
aria-label={t("app.hide_meetings")}
>
<PanelLeftClose size={14} aria-hidden="true" />
</button>
@@ -407,7 +408,7 @@
</aside>
{#if !layout.leftCollapsed}
<Splitter
label="Resize meetings list"
label={t("app.resize_meetings")}
onResize={(d) => (layout.leftWidth = clamp(layout.leftWidth + d, 200, 480))}
onResizeEnd={() => layout.persist()}
/>
@@ -417,7 +418,7 @@
<section class="center"><TranscriptNotes /></section>
{#if !layout.rightCollapsed}
<Splitter
label="Resize summary panel"
label={t("app.resize_summary")}
onResize={(d) => (layout.rightWidth = clamp(layout.rightWidth - d, 240, 560))}
onResizeEnd={() => layout.persist()}
/>
@@ -432,8 +433,8 @@
layout.rightCollapsed = false;
layout.persist();
}}
title="Show summary panel"
aria-label="Show summary panel"
title={t("app.show_summary")}
aria-label={t("app.show_summary")}
>
<PanelRightOpen size={16} aria-hidden="true" />
</button>
@@ -444,8 +445,8 @@
layout.rightCollapsed = true;
layout.persist();
}}
title="Hide summary panel"
aria-label="Hide summary panel"
title={t("app.hide_summary")}
aria-label={t("app.hide_summary")}
>
<PanelRightClose size={14} aria-hidden="true" />
</button>