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

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