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

This commit is contained in:
iamdoubz
2026-07-12 12:32:54 -05:00
parent 698fb26b0a
commit 7796c5b62d
+82 -63
View File
@@ -706,16 +706,18 @@
{t("nav.about")}
</button>
</nav>
<button class="close" onclick={onClose} aria-label="Close" title="Close (Esc)">
<button
class="close"
onclick={onClose}
aria-label={t("settings.close")}
title={t("settings.close_title")}
>
<X size={18} aria-hidden="true" />
</button>
</header>
{#if settings.backendStub && section === "sync"}
<p class="stub">
Preview mode — the sync backend isn't implemented yet (Phase 9). Changes are kept in the UI
only.
</p>
<p class="stub">{t("settings.sync.stub")}</p>
{/if}
{#if section === "recording"}
@@ -1261,51 +1263,52 @@
</section>
{:else if section === "sync"}
<section>
<h3>Sync &amp; upload</h3>
<h3>{t("settings.sync.title")}</h3>
<label class="row">
<input
type="checkbox"
checked={settings.settings.sync_enabled}
onchange={(e) => settings.setSyncEnabled((e.target as HTMLInputElement).checked)}
/>
<span>Enable uploading meeting artifacts to configured targets</span>
<span>{t("settings.sync.enable_label")}</span>
</label>
<p class="muted">
Off by default. Nothing is uploaded unless this is on and a target is enabled. Self-hosted
targets keep data on your own server; third-party clouds are clearly labeled.
</p>
<p class="muted">{t("settings.sync.enable_hint")}</p>
<h4>Targets</h4>
<h4>{t("settings.sync.targets_title")}</h4>
{#if settings.targets.length === 0}
<p class="muted">No targets yet. Add one below.</p>
<p class="muted">{t("settings.sync.no_targets")}</p>
{:else}
<ul class="targets">
{#each settings.targets as t (t.id)}
{#each settings.targets as target (target.id)}
<li>
<label class="tg">
<input
type="checkbox"
checked={t.enabled}
onchange={() => settings.toggleTargetEnabled(t)}
checked={target.enabled}
onchange={() => settings.toggleTargetEnabled(target)}
/>
<span class="name">{t.name || t.kind}</span>
<span class="name">{target.name || target.kind}</span>
</label>
<span class="badge" class:third={t.third_party}
>{t.third_party ? "third-party" : "your server"}</span
<span class="badge" class:third={target.third_party}
>{target.third_party
? t("settings.sync.third_party")
: t("settings.sync.your_server")}</span
>
<span class="host">{t.host ?? t.kind}</span>
{#if !t.third_party}
<button class="link" onclick={() => startEdit(t)}>Edit</button>
<span class="host">{target.host ?? target.kind}</span>
{#if !target.third_party}
<button class="link" onclick={() => startEdit(target)}
>{t("settings.sync.edit")}</button
>
{/if}
<button class="link danger" onclick={() => settings.removeTarget(t.id)}
>Remove</button
<button class="link danger" onclick={() => settings.removeTarget(target.id)}
>{t("settings.sync.remove")}</button
>
</li>
{/each}
</ul>
{/if}
<h4>{editingId ? "Edit target" : "Add a target"}</h4>
<h4>{editingId ? t("settings.sync.edit_target") : t("settings.sync.add_target")}</h4>
{#if !editingId}
<div class="kinds">
{#each ["webdav", "onedrive", "dropbox", "box"] as k (k)}
@@ -1317,20 +1320,22 @@
{/if}
{#if form.kind === "webdav"}
<p class="muted">
WebDAV covers Nextcloud, ownCloud, Cloudreve, Seafile, and Synology. (Seafile: enable
SeafDAV server-side.)
</p>
<p class="muted">{t("settings.sync.webdav_hint")}</p>
<div class="grid">
<label>Name<input bind:value={form.name} placeholder="Home Nextcloud" /></label>
<label
>Provider
>{t("settings.sync.name")}<input
bind:value={form.name}
placeholder={t("settings.sync.name_placeholder")}
/></label
>
<label
>{t("settings.sync.provider")}
<select bind:value={form.provider_hint}>
{#each PROVIDERS as p (p)}<option value={p}>{p}</option>{/each}
</select>
</label>
<label class="wide"
>Server URL<input
>{t("settings.sync.server_url")}<input
bind:value={form.base_url}
placeholder={davAutoPath
? "https://cloud.example.com"
@@ -1338,36 +1343,46 @@
/>
{#if davAutoPath}
<small class="muted"
>Just your server URL — WhispAssist adds
<code>/remote.php/dav/files/&lt;username&gt;/</code> automatically.</small
>{t("settings.sync.server_url_note_1")}
<code>/remote.php/dav/files/&lt;username&gt;/</code>
{t("settings.sync.server_url_note_2")}</small
>
{/if}
</label>
<label>Remote folder<input bind:value={form.remote_base_path} /></label>
<label>Username<input bind:value={form.username} /></label>
<label
>App password<input
>{t("settings.sync.remote_folder")}<input bind:value={form.remote_base_path} /></label
>
<label>{t("settings.sync.username")}<input bind:value={form.username} /></label>
<label
>{t("settings.sync.app_password")}<input
type="password"
bind:value={form.secret}
placeholder={editingId
? "leave blank to keep current password"
: "stored in OS credential store"}
placeholder={editingId ? t("settings.sync.pw_keep") : t("settings.sync.pw_store")}
/></label
>
</div>
<fieldset class="artifacts">
<legend>Upload</legend>
<label><input type="checkbox" bind:checked={form.upload_transcript} /> transcript</label
>
<label><input type="checkbox" bind:checked={form.upload_notes} /> notes</label>
<label><input type="checkbox" bind:checked={form.upload_summary} /> summary</label>
<legend>{t("settings.sync.upload_legend")}</legend>
<label
><input type="checkbox" bind:checked={form.upload_recording} /> recording (.wav, if retained)</label
><input type="checkbox" bind:checked={form.upload_transcript} />
{t("settings.sync.artifact_transcript")}</label
>
<label
><input type="checkbox" bind:checked={form.upload_notes} />
{t("settings.sync.artifact_notes")}</label
>
<label
><input type="checkbox" bind:checked={form.upload_summary} />
{t("settings.sync.artifact_summary")}</label
>
<label
><input type="checkbox" bind:checked={form.upload_recording} />
{t("settings.sync.artifact_recording")}</label
>
</fieldset>
<label class="row small"
><input type="checkbox" bind:checked={form.allow_plaintext_lan} /> Allow plaintext http for
a LAN address (not recommended)</label
><input type="checkbox" bind:checked={form.allow_plaintext_lan} />
{t("settings.sync.allow_plaintext")}</label
>
<label class="row small">
<input
@@ -1375,16 +1390,19 @@
bind:checked={form.encrypt_before_upload}
disabled={!vault?.unlocked}
/>
Encrypt before upload (destination stores only ciphertext)
{#if !vault?.unlocked}<span class="muted">— requires an unlocked vault</span>{/if}
{t("settings.sync.encrypt_before")}
{#if !vault?.unlocked}<span class="muted">{t("settings.sync.requires_vault")}</span
>{/if}
</label>
<div class="actions">
<button onclick={testConnection}>Test connection</button>
<button onclick={testConnection}>{t("settings.sync.test_connection")}</button>
<button class="primary" onclick={saveTarget} disabled={!form.name || !form.base_url}
>{editingId ? "Save changes" : "Add target"}</button
>{editingId
? t("settings.sync.save_changes")
: t("settings.sync.add_target_btn")}</button
>
{#if editingId}
<button class="link" onclick={cancelEdit}>Cancel</button>
<button class="link" onclick={cancelEdit}>{t("settings.sync.cancel")}</button>
{/if}
{#if testResult}
<span class="test" class:ok={testResult.ok} class:fail={!testResult.ok}>
@@ -1399,27 +1417,28 @@
{:else}
<div class="banner">
<AlertTriangle size={14} aria-hidden="true" />
{form.kind} is a third-party cloud — uploading sends your data off your device to {form.kind}.
{t("settings.sync.third_party_banner", { kind: form.kind })}
</div>
<div class="grid">
<label class="wide">Name<input bind:value={form.name} placeholder={form.kind} /></label>
<label class="wide"
>{t("settings.sync.name")}<input
bind:value={form.name}
placeholder={form.kind}
/></label
>
</div>
<div class="actions">
<button class="primary" onclick={linkOAuth}>Link {form.kind} account…</button>
<span class="muted"
>Opens an OAuth sign-in (loopback redirect); the token is stored in your OS credential
store.</span
<button class="primary" onclick={linkOAuth}
>{t("settings.sync.link_account", { kind: form.kind })}</button
>
<span class="muted">{t("settings.sync.oauth_hint")}</span>
</div>
{#if settings.linkMessage}
<p class="muted">{settings.linkMessage}</p>
{/if}
{/if}
<p class="muted footnote">
Credentials are never written to settings or the database — only the OS credential store.
TLS is required for non-LAN targets.
</p>
<p class="muted footnote">{t("settings.sync.footnote")}</p>
</section>
{:else if section === "ai"}
<section>