feat(i18n): convert MeetingsList chrome to t() (Batch B, FR-*)

This commit is contained in:
iamdoubz committed 2026-07-12 11:03:41 -05:00
1 parent fc89f76ac8
commit e5fdb2baea
1 file changed
+48 -25
+48 -25
View File
@@ -5,6 +5,12 @@
import { api, type MeetingListItem, type SearchHit } from "../api";
import { open } from "@tauri-apps/plugin-dialog";
import { Search, Trash2, Download, RotateCcw } from "@lucide/svelte";
import { t } from "../i18n/index.svelte";
// Meeting status ("recording"/"transcribing"/"recovering"/"error") → its
// localized badge label. The status value itself is app vocabulary, not user
// content, so it gets keyed.
const statusLabel = (s: string) => t(`meetings.status.${s}`);
let query = $state("");
let searchTimer: ReturnType<typeof setTimeout> | undefined;
@@ -55,7 +61,10 @@
from: toUnix(fromFilter),
to: toUnix(toFilter),
});
bulkResult = `Exported ${count} meeting${count === 1 ? "" : "s"}.`;
bulkResult =
count === 1
? t("meetings.exported_one", { n: count })
: t("meetings.exported_many", { n: count });
} finally {
bulkExporting = false;
}
@@ -93,7 +102,7 @@
async function removeMeeting(e: Event, id: string) {
e.stopPropagation();
if (!confirm("Delete this meeting? This removes its recording, transcript, and notes.")) return;
if (!confirm(t("meetings.delete_confirm"))) return;
await meetings.remove(id);
}
@@ -107,24 +116,38 @@
<div class="search-box">
<Search size={15} aria-hidden="true" />
<input
placeholder="Search meetings…"
aria-label="Search meetings"
placeholder={t("meetings.search_placeholder")}
aria-label={t("meetings.search_aria")}
bind:value={query}
oninput={onSearchInput}
/>
</div>
<div class="filters">
<select aria-label="Filter by tag" bind:value={tagFilter} onchange={onFilterChange}>
<option value="">All tags</option>
{#each meetings.allTags as t (t)}
<option value={t}>{t}</option>
<select
aria-label={t("meetings.filter_tag_aria")}
bind:value={tagFilter}
onchange={onFilterChange}
>
<option value="">{t("meetings.all_tags")}</option>
{#each meetings.allTags as tag (tag)}
<option value={tag}>{tag}</option>
{/each}
</select>
<input type="date" aria-label="From date" bind:value={fromFilter} onchange={onFilterChange} />
<input type="date" aria-label="To date" bind:value={toFilter} onchange={onFilterChange} />
<input
type="date"
aria-label={t("meetings.from_date_aria")}
bind:value={fromFilter}
onchange={onFilterChange}
/>
<input
type="date"
aria-label={t("meetings.to_date_aria")}
bind:value={toFilter}
onchange={onFilterChange}
/>
</div>
<div class="filters">
<select aria-label="Bulk export format" bind:value={bulkFormat}>
<select aria-label={t("meetings.bulk_format_aria")} bind:value={bulkFormat}>
<option value="md">.md</option>
<option value="pdf">.pdf</option>
<option value="docx">.docx</option>
@@ -134,23 +157,23 @@
class="bulk-btn"
onclick={bulkExport}
disabled={bulkExporting}
title="Export every meeting matching the tag/date filters above"
title={t("meetings.bulk_export_title")}
>
<Download size={13} aria-hidden="true" />
{bulkExporting ? "Exporting…" : "Bulk export"}
{bulkExporting ? t("meetings.exporting") : t("meetings.bulk_export")}
</button>
</div>
{#if bulkResult}
<p class="muted small">{bulkResult}</p>
{/if}
{#if meetings.searching}
<p class="muted">Searching…</p>
<p class="muted">{t("meetings.searching")}</p>
{:else if displayItems.length === 0 && meetings.loading}
<p class="muted">Loading meetings…</p>
<p class="muted">{t("meetings.loading")}</p>
{:else if displayItems.length === 0 && meetings.searchResults !== null}
<p class="muted">No matches.</p>
<p class="muted">{t("meetings.no_matches")}</p>
{:else if displayItems.length === 0}
<p class="muted">No meetings yet — click Record above to start.</p>
<p class="muted">{t("meetings.empty")}</p>
{:else}
<ul>
{#each displayItems as m (m.id)}
@@ -159,11 +182,11 @@
<span class="row">
<span class="title">{m.title}</span>
{#if m.status === "recording" || m.status === "transcribing"}
<span class="badge live">{m.status}</span>
<span class="badge live">{statusLabel(m.status)}</span>
{:else if m.status === "recovering"}
<span class="badge recovering">recovering</span>
<span class="badge recovering">{statusLabel("recovering")}</span>
{:else if m.status === "error"}
<span class="badge error">error</span>
<span class="badge error">{statusLabel("error")}</span>
{/if}
</span>
<span class="row muted small">
@@ -175,8 +198,8 @@
{/if}
{#if m.tags.length > 0}
<span class="row tags">
{#each m.tags as t (t)}
<span class="chip">{t}</span>
{#each m.tags as tag (tag)}
<span class="chip">{tag}</span>
{/each}
</span>
{/if}
@@ -185,14 +208,14 @@
{#if m.status === "recovering"}
<button class="link" onclick={(e) => resumeMeeting(e, m.id)}>
<RotateCcw size={12} aria-hidden="true" />
Resume transcription
{t("meetings.resume")}
</button>
{/if}
<button
class="link danger"
onclick={(e) => removeMeeting(e, m.id)}
aria-label="Delete meeting"
title="Delete meeting"
aria-label={t("meetings.delete_aria")}
title={t("meetings.delete_aria")}
>
<Trash2 size={14} aria-hidden="true" />
</button>