feat(i18n): display-language selector in Settings + t() on nav and transcription-language strings
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
import { settings } from "../stores/settings.svelte";
|
||||
import { calendar } from "../stores/calendar.svelte";
|
||||
import { meetings } from "../stores/meetings.svelte";
|
||||
import { t, i18n, LOCALES } from "../i18n/index.svelte";
|
||||
import ConsentNotice from "../components/ConsentNotice.svelte";
|
||||
import HostedAiBanner from "../components/HostedAiBanner.svelte";
|
||||
import { open } from "@tauri-apps/plugin-dialog";
|
||||
@@ -49,7 +50,16 @@
|
||||
let { onClose }: { onClose: () => void } = $props();
|
||||
|
||||
let section = $state<
|
||||
"recording" | "hardware" | "storage" | "calendar" | "sync" | "ai" | "mcp" | "privacy" | "about"
|
||||
| "recording"
|
||||
| "hardware"
|
||||
| "storage"
|
||||
| "calendar"
|
||||
| "sync"
|
||||
| "ai"
|
||||
| "mcp"
|
||||
| "privacy"
|
||||
| "language"
|
||||
| "about"
|
||||
>("recording");
|
||||
|
||||
// The currently active whisper model (T8.7, FR-TRX-4) — gates the
|
||||
@@ -650,31 +660,34 @@
|
||||
<strong>Settings</strong>
|
||||
<nav>
|
||||
<button class:active={section === "recording"} onclick={() => (section = "recording")}>
|
||||
<Mic size={14} aria-hidden="true" /> Recording
|
||||
<Mic size={14} aria-hidden="true" /> {t("nav.recording")}
|
||||
</button>
|
||||
<button class:active={section === "hardware"} onclick={() => (section = "hardware")}>
|
||||
<Cpu size={14} aria-hidden="true" /> Hardware
|
||||
<Cpu size={14} aria-hidden="true" /> {t("nav.hardware")}
|
||||
</button>
|
||||
<button class:active={section === "storage"} onclick={() => (section = "storage")}>
|
||||
<HardDrive size={14} aria-hidden="true" /> Storage
|
||||
<HardDrive size={14} aria-hidden="true" /> {t("nav.storage")}
|
||||
</button>
|
||||
<button class:active={section === "calendar"} onclick={() => (section = "calendar")}>
|
||||
<CalendarDays size={14} aria-hidden="true" /> Calendar
|
||||
<CalendarDays size={14} aria-hidden="true" /> {t("nav.calendar")}
|
||||
</button>
|
||||
<button class:active={section === "sync"} onclick={() => (section = "sync")}>
|
||||
<UploadCloud size={14} aria-hidden="true" /> Sync
|
||||
<UploadCloud size={14} aria-hidden="true" /> {t("nav.sync")}
|
||||
</button>
|
||||
<button class:active={section === "ai"} onclick={() => (section = "ai")}>
|
||||
<Sparkles size={14} aria-hidden="true" /> AI
|
||||
<Sparkles size={14} aria-hidden="true" /> {t("nav.ai")}
|
||||
</button>
|
||||
<button class:active={section === "mcp"} onclick={() => (section = "mcp")}>
|
||||
<Bot size={14} aria-hidden="true" /> MCP server
|
||||
<Bot size={14} aria-hidden="true" /> {t("nav.mcp")}
|
||||
</button>
|
||||
<button class:active={section === "privacy"} onclick={() => (section = "privacy")}>
|
||||
<ShieldCheck size={14} aria-hidden="true" /> Privacy
|
||||
<ShieldCheck size={14} aria-hidden="true" /> {t("nav.privacy")}
|
||||
</button>
|
||||
<button class:active={section === "language"} onclick={() => (section = "language")}>
|
||||
<Globe size={14} aria-hidden="true" /> {t("nav.language")}
|
||||
</button>
|
||||
<button class:active={section === "about"} onclick={() => (section = "about")}>
|
||||
<Info size={14} aria-hidden="true" /> About
|
||||
<Info size={14} aria-hidden="true" /> {t("nav.about")}
|
||||
</button>
|
||||
</nav>
|
||||
<button class="close" onclick={onClose} aria-label="Close" title="Close (Esc)">
|
||||
@@ -1002,10 +1015,10 @@
|
||||
{/each}
|
||||
</ul>
|
||||
|
||||
<h4>Transcription Language</h4>
|
||||
<h4>{t("settings.transcription.title")}</h4>
|
||||
{#if activeModel?.multilingual}
|
||||
<label
|
||||
>Language
|
||||
>{t("settings.transcription.label")}
|
||||
<select
|
||||
value={settings.settings.whisper_language ?? ""}
|
||||
onchange={(e) => {
|
||||
@@ -1013,16 +1026,13 @@
|
||||
settings.setWhisperLanguage(v || null);
|
||||
}}
|
||||
>
|
||||
<option value="">Auto-detect</option>
|
||||
<option value="">{t("settings.transcription.auto")}</option>
|
||||
{#each settings.languages as l (l.code)}
|
||||
<option value={l.code}>{l.label}</option>
|
||||
{/each}
|
||||
</select>
|
||||
</label>
|
||||
<p class="muted">
|
||||
Applies to the next recording. The language actually used is shown on each meeting
|
||||
afterward.
|
||||
</p>
|
||||
<p class="muted">{t("settings.transcription.applies_hint")}</p>
|
||||
{:else}
|
||||
<label
|
||||
>Language
|
||||
@@ -1890,6 +1900,22 @@
|
||||
{#if vaultMsg}<p class="muted">{vaultMsg}</p>{/if}
|
||||
{/if}
|
||||
</section>
|
||||
{:else if section === "language"}
|
||||
<section>
|
||||
<h3>{t("settings.language.title")}</h3>
|
||||
<label
|
||||
>{t("settings.language.display")}
|
||||
<select
|
||||
value={i18n.locale}
|
||||
onchange={(e) => i18n.setLocale((e.target as HTMLSelectElement).value)}
|
||||
>
|
||||
{#each LOCALES as l (l.code)}
|
||||
<option value={l.code}>{l.label}</option>
|
||||
{/each}
|
||||
</select>
|
||||
</label>
|
||||
<p class="muted">{t("settings.language.display_hint")}</p>
|
||||
</section>
|
||||
{:else if section === "about"}
|
||||
<section>
|
||||
<h3>About</h3>
|
||||
|
||||
Reference in New Issue
Block a user