feat(i18n): convert Settings hardware section to t() (Batch E)

This commit is contained in:
iamdoubz committed 2026-07-12 12:27:48 -05:00
1 parent c0b7587298
commit c98c14bbc7
1 file changed
+82 -68
+82 -68
View File
@@ -752,14 +752,18 @@
</section>
{:else if section === "hardware"}
<section>
<h3>Hardware</h3>
<h3>{t("settings.hardware.title")}</h3>
{#if settings.hardware}
<div class="row">
Active backend<code>{settings.hardware.active}</code>
<span class="muted">· model {settings.hardware.modelSize}</span>
{t("settings.hardware.active_backend")}<code>{settings.hardware.active}</code>
<span class="muted"
>{t("settings.hardware.model_meta", {
size: settings.hardware.modelSize,
})}</span
>
</div>
<label
>Preferred backend
>{t("settings.hardware.preferred_backend")}
<select
value={settings.settings.preferred_backend}
onchange={(e) =>
@@ -767,40 +771,34 @@
(e.target as HTMLSelectElement).value as BackendId | "auto",
)}
>
<option value="auto">Auto (best available)</option>
<option value="auto">{t("settings.hardware.auto_backend")}</option>
{#each settings.hardware.backends as b (b.id)}
<option value={b.id} disabled={!b.available}>
{b.name} ({b.id}){b.available ? "" : " — not available"}
{b.name} ({b.id}){b.available ? "" : ` — ${t("settings.hardware.not_available")}`}
</option>
{/each}
</select>
</label>
<p class="muted">
Falls back automatically (NPU → NVIDIA → AMD → Intel → CPU) if the chosen backend fails
to load.
</p>
<p class="muted">{t("settings.hardware.fallback_hint")}</p>
<h4>Audio Devices</h4>
<h4>{t("settings.hardware.audio_devices")}</h4>
<label
>Recording device
>{t("settings.hardware.recording_device")}
<select
value={settings.settings.audio_output_device ?? ""}
onchange={(e) =>
settings.setAudioOutputDevice((e.target as HTMLSelectElement).value || null)}
>
<option value="">Default system audio</option>
<option value="">{t("settings.hardware.default_system_audio")}</option>
{#each settings.audioDevices as d (d.id)}
<option value={d.id}>{d.name}</option>
{/each}
</select>
</label>
<p class="muted">
WhispAssist records whatever this device plays (loopback) — the other side of the call.
Pick a specific output if you don't want it following Windows' system default.
</p>
<p class="muted">{t("settings.hardware.recording_device_hint")}</p>
<label
>Microphone
>{t("settings.hardware.microphone")}
<select
value={!settings.settings.microphone_enabled
? "off"
@@ -811,18 +809,14 @@
else settings.setMicrophone(true, v || null);
}}
>
<option value="off">Off — don't capture my microphone</option>
<option value="">Default microphone</option>
<option value="off">{t("settings.hardware.mic_off")}</option>
<option value="">{t("settings.hardware.default_mic")}</option>
{#each settings.inputDevices as d (d.id)}
<option value={d.id}>{d.name}</option>
{/each}
</select>
</label>
<p class="muted">
Adds your own voice to the live transcript so both sides of the meeting are captured.
Stays on your device — nothing is uploaded. Choose “Off” to transcribe only the system
audio above.
</p>
<p class="muted">{t("settings.hardware.mic_hint")}</p>
{#if settings.hardware.npu?.present}
{@const npu = settings.hardware.npu}
@@ -830,24 +824,27 @@
<div class="npu-package">
<div class="row">
<Cpu size={14} aria-hidden="true" />
<strong>NPU accelerator detected</strong>
<strong>{t("settings.hardware.npu_detected")}</strong>
{#if ready}
<span class="badge ok"><Check size={12} aria-hidden="true" /> Ready</span>
<span class="badge ok"
><Check size={12} aria-hidden="true" /> {t("settings.hardware.ready")}</span
>
{:else if npuBusy}
<span class="badge busy">Downloading…</span>
<span class="badge busy">{t("settings.hardware.downloading")}</span>
{:else}
<span class="badge">Package needed</span>
<span class="badge">{t("settings.hardware.package_needed")}</span>
{/if}
</div>
{#if !ready}
<p class="muted">
Your NPU needs a one-time acceleration package (Whisper ONNX model{npu.runtimeReady
? ""
: " + OpenVINO runtime"}). It downloads in the background; you can also start it
now.
{t("settings.hardware.npu_hint", {
extra: npu.runtimeReady ? "" : t("settings.hardware.plus_openvino"),
})}
</p>
<button onclick={downloadNpuPackage} disabled={npuBusy}>
{npuBusy ? "Downloading…" : "Download NPU package"}
{npuBusy
? t("settings.hardware.downloading")
: t("settings.hardware.download_npu")}
</button>
{/if}
{#if npuMsg}<p class="muted npu-status">{npuMsg}</p>{/if}
@@ -861,29 +858,34 @@
<div class="npu-package">
<div class="row">
<Cpu size={14} aria-hidden="true" />
<strong>GPU acceleration (DirectML)</strong>
<strong>{t("settings.hardware.dml_title")}</strong>
{#if dmlReady}
<span class="badge ok"><Check size={12} aria-hidden="true" /> Ready</span>
<span class="badge ok"
><Check size={12} aria-hidden="true" /> {t("settings.hardware.ready")}</span
>
{:else if dmlBusy}
<span class="badge busy">Downloading…</span>
<span class="badge busy">{t("settings.hardware.downloading")}</span>
{:else}
<span class="badge">Package needed</span>
<span class="badge">{t("settings.hardware.package_needed")}</span>
{/if}
</div>
{#if !dmlReady}
<p class="muted">
Your GPU can be accelerated without Vulkan via DirectML — a one-time package
(Whisper ONNX model{dml.runtimeReady ? "" : " + DirectML runtime"}).
{t("settings.hardware.dml_hint", {
extra: dml.runtimeReady ? "" : t("settings.hardware.plus_directml"),
})}
</p>
<button onclick={downloadDirectmlPackage} disabled={dmlBusy}>
{dmlBusy ? "Downloading…" : "Download DirectML package"}
{dmlBusy
? t("settings.hardware.downloading")
: t("settings.hardware.download_dml")}
</button>
{/if}
{#if dmlMsg}<p class="muted npu-status">{dmlMsg}</p>{/if}
</div>
{/if}
{:else}
<p class="muted">Hardware detection unavailable.</p>
<p class="muted">{t("settings.hardware.detection_unavailable")}</p>
{/if}
<label class="row">
@@ -893,11 +895,12 @@
onchange={(e) => settings.setLowOverhead((e.target as HTMLInputElement).checked)}
/>
<span
>Low overhead preset <em>(CPU + smallest model, for battery/background use)</em></span
>{t("settings.hardware.low_overhead")}
<em>({t("settings.hardware.low_overhead_note")})</em></span
>
</label>
<h4>Models</h4>
<h4>{t("settings.hardware.models")}</h4>
<ul class="models">
{#each settings.models as m (m.id)}
{@const downloading = m.id in settings.downloadProgress}
@@ -908,16 +911,19 @@
<span class="meta">
{fmtBytes(m.size_mb)}
{#if m.active}
<span class="badge ok"><Check size={11} aria-hidden="true" /> Active</span>
<span class="badge ok"
><Check size={11} aria-hidden="true" />
{t("settings.hardware.active_badge")}</span
>
{:else if m.installed}
<span class="badge">Installed</span>
<span class="badge">{t("settings.hardware.installed")}</span>
{/if}
</span>
{#if downloading}
<div
class="progress"
role="progressbar"
aria-label="Downloading {m.label}"
aria-label={t("settings.hardware.downloading_model", { name: m.label })}
aria-valuenow={pct ?? undefined}
aria-valuemin={0}
aria-valuemax={100}
@@ -929,7 +935,7 @@
></div>
</div>
<span class="muted progress-label"
>Downloading… {pct !== null ? `${pct}%` : ""}</span
>{t("settings.hardware.downloading")} {pct !== null ? `${pct}%` : ""}</span
>
{/if}
</div>
@@ -942,19 +948,24 @@
disabled={m.active}
onclick={() => settings.setActiveModel(m.id)}
>
<Check size={13} aria-hidden="true" /> Use
<Check size={13} aria-hidden="true" />
{t("settings.hardware.use")}
</button>
<button
class="icon-btn danger"
disabled={m.active}
title={m.active ? "Can't remove the active model" : "Remove"}
title={m.active
? t("settings.hardware.cant_remove_active")
: t("settings.hardware.remove")}
onclick={() => settings.removeModel(m.id)}
>
<Trash2 size={13} aria-hidden="true" /> Remove
<Trash2 size={13} aria-hidden="true" />
{t("settings.hardware.remove")}
</button>
{:else}
<button class="icon-btn" onclick={() => settings.downloadModel(m.id)}>
<Download size={13} aria-hidden="true" /> Download
<Download size={13} aria-hidden="true" />
{t("settings.hardware.download")}
</button>
{/if}
</div>
@@ -962,12 +973,8 @@
{/each}
</ul>
<h4>Speaker diarization</h4>
<p class="muted">
Install both models to have finished recordings separated by speaker (Speaker 1, Speaker
2, …) instead of one running transcript. Runs fully offline, once per meeting after it
stops. Without them, every line is attributed to a single speaker.
</p>
<h4>{t("settings.hardware.diarization")}</h4>
<p class="muted">{t("settings.hardware.diarization_hint")}</p>
<ul class="models">
{#each settings.diarizationModels as m (m.id)}
{@const downloading = m.id in settings.downloadProgress}
@@ -978,14 +985,17 @@
<span class="meta">
{fmtBytes(m.size_mb)}
{#if m.installed}
<span class="badge ok"><Check size={11} aria-hidden="true" /> Installed</span>
<span class="badge ok"
><Check size={11} aria-hidden="true" />
{t("settings.hardware.installed")}</span
>
{/if}
</span>
{#if downloading}
<div
class="progress"
role="progressbar"
aria-label="Downloading {m.label}"
aria-label={t("settings.hardware.downloading_model", { name: m.label })}
aria-valuenow={pct ?? undefined}
aria-valuemin={0}
aria-valuemax={100}
@@ -997,7 +1007,7 @@
></div>
</div>
<span class="muted progress-label"
>Downloading… {pct !== null ? `${pct}%` : ""}</span
>{t("settings.hardware.downloading")} {pct !== null ? `${pct}%` : ""}</span
>
{/if}
</div>
@@ -1007,14 +1017,16 @@
{:else if m.installed}
<button
class="icon-btn danger"
title="Remove"
title={t("settings.hardware.remove")}
onclick={() => settings.removeDiarizationModel(m.id)}
>
<Trash2 size={13} aria-hidden="true" /> Remove
<Trash2 size={13} aria-hidden="true" />
{t("settings.hardware.remove")}
</button>
{:else}
<button class="icon-btn" onclick={() => settings.downloadDiarizationModel(m.id)}>
<Download size={13} aria-hidden="true" /> Download
<Download size={13} aria-hidden="true" />
{t("settings.hardware.download")}
</button>
{/if}
</div>
@@ -1042,14 +1054,16 @@
<p class="muted">{t("settings.transcription.applies_hint")}</p>
{:else}
<label
>Language
>{t("settings.transcription.label")}
<select disabled aria-describedby="language-disabled-hint">
<option>English only</option>
<option>{t("settings.transcription.english_only")}</option>
</select>
</label>
<p class="muted" id="language-disabled-hint">
{activeModel ? `"${activeModel.label}" is English-only.` : "No model selected."} Switch to
a multilingual model above to choose a language.
{activeModel
? t("settings.transcription.model_english_only", { model: activeModel.label })
: t("settings.transcription.no_model")}
{t("settings.transcription.switch_multilingual")}
</p>
{/if}
</section>