feat(ui): localize commit AI and git error messages to English
Translate commit AI prompts, model labels, and git/keychain errors to English so the app and generated messages are consistent. Also add a discard confirmation dialog and update the UI text/styles to match the new flow. - src-tauri/crates/commit_ai/src/cloud.rs - Translate HTTP and API error messages to English. - Keep request timeout and token sizing behavior unchanged. - src-tauri/crates/commit_ai/src/lib.rs - Translate model labels, prompt text, and validation errors. - Keep diff truncation and message sanitization logic intact. - src-tauri/src/git.rs - Translate git, credential, merge, and history errors. - Update AI provider validation messages to English. - src/lib/components/* - Update AI settings, commit panel, credential, and loading UI text. - Add discard confirmation dialog for destructive actions. - src/App.svelte, src/app.css - Adjust app layout and styling for the new dialog and text changes.
This commit is contained in:
@@ -153,9 +153,9 @@
|
||||
<div class="cred-token-hint">
|
||||
<AlertCircle size={13} aria-hidden="true" />
|
||||
<span>
|
||||
Beim Wechsel wird das Modell{selectedLocalModel ? ` (${formatSize(selectedLocalModel.approx_size_mb)})` : ""}
|
||||
im Hintergrund heruntergeladen — je nach Internetverbindung kann das mehrere Minuten dauern.
|
||||
Danach bleibt es lokal zwischengespeichert und lädt beim nächsten Start sofort.
|
||||
Switching downloads the model{selectedLocalModel ? ` (${formatSize(selectedLocalModel.approx_size_mb)})` : ""}
|
||||
in the background — depending on your internet connection this can take several minutes.
|
||||
After that it stays cached locally and loads instantly on the next start.
|
||||
</span>
|
||||
</div>
|
||||
{:else if provider === "openai"}
|
||||
@@ -230,7 +230,7 @@
|
||||
</div>
|
||||
<div class="cred-token-hint">
|
||||
<Globe size={13} aria-hidden="true" />
|
||||
<span>Für lokale OpenAI-kompatible Server wie Ollama oder LM Studio. Die Basis-URL sollte auf /v1 enden.</span>
|
||||
<span>For local OpenAI-compatible servers like Ollama or LM Studio. The base URL should end in /v1.</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
);
|
||||
</script>
|
||||
|
||||
<section class="panel flex flex-col" aria-label="Commit">
|
||||
<section class="panel commit-panel" aria-label="Commit">
|
||||
<div class="section-head">
|
||||
<div>
|
||||
<span class="eyebrow">Commit</span>
|
||||
|
||||
@@ -44,10 +44,10 @@
|
||||
(mode === "token" || username.trim().length > 0),
|
||||
);
|
||||
let actionLabel = $derived(action === "push" ? "Push" : "Pull");
|
||||
let actionTitle = $derived(action === "push" ? "Push authentifizieren" : "Pull authentifizieren");
|
||||
let actionTitle = $derived(action === "push" ? "Authenticate push" : "Authenticate pull");
|
||||
let actionHint = $derived(action === "push"
|
||||
? "Der Remote braucht Schreibrechte. Nutze ein Passwort oder einen Token mit passenden Repository-Rechten."
|
||||
: "Der Remote braucht Zugriff auf das Repository. Nutze deine Git-Zugangsdaten oder einen Personal Access Token.");
|
||||
? "The remote needs write access. Use a password or a token with the appropriate repository permissions."
|
||||
: "The remote needs access to the repository. Use your Git credentials or a personal access token.");
|
||||
|
||||
function handleSubmit(e: SubmitEvent) {
|
||||
e.preventDefault();
|
||||
@@ -66,7 +66,7 @@
|
||||
role="presentation"
|
||||
onclick={(e) => { if (e.target === e.currentTarget) onCancel(); }}
|
||||
>
|
||||
<div class="cred-card" role="dialog" aria-modal="true" aria-label="Git-Zugangsdaten" tabindex="-1">
|
||||
<div class="cred-card" role="dialog" aria-modal="true" aria-label="Git credentials" tabindex="-1">
|
||||
<div class="cred-hero">
|
||||
<div class="cred-hero-top">
|
||||
<div class="cred-hero-icon">
|
||||
@@ -80,7 +80,7 @@
|
||||
<p class="cred-hero-label">{actionLabel} Remote</p>
|
||||
<h2 class="cred-hero-title">{actionTitle}</h2>
|
||||
</div>
|
||||
<button class="cred-close" type="button" onclick={onCancel} title="Abbrechen" aria-label="Abbrechen">
|
||||
<button class="cred-close" type="button" onclick={onCancel} title="Cancel" aria-label="Cancel">
|
||||
<X size={16} aria-hidden="true" />
|
||||
</button>
|
||||
</div>
|
||||
@@ -89,12 +89,12 @@
|
||||
|
||||
<div class="cred-security-note">
|
||||
<ShieldCheck size={14} aria-hidden="true" />
|
||||
<span>Beim Speichern landet der Token verschluesselt im Schluesselbund des Betriebssystems – nie im Klartext.</span>
|
||||
<span>When saved, the token is stored encrypted in the operating system's keychain — never in plain text.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form class="cred-body" onsubmit={handleSubmit}>
|
||||
<div class="cred-segment" role="group" aria-label="Authentifizierungsart">
|
||||
<div class="cred-segment" role="group" aria-label="Authentication method">
|
||||
<button
|
||||
type="button"
|
||||
class="cred-seg-btn"
|
||||
@@ -103,7 +103,7 @@
|
||||
aria-pressed={mode === "credentials"}
|
||||
>
|
||||
<User size={13} aria-hidden="true" />
|
||||
Username + Passwort
|
||||
Username + password
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@@ -127,7 +127,7 @@
|
||||
id="cred-username"
|
||||
type="text"
|
||||
bind:value={username}
|
||||
placeholder="z. B. mein-github-username"
|
||||
placeholder="e.g. my-github-username"
|
||||
autocomplete="username"
|
||||
disabled={isBusy}
|
||||
/>
|
||||
@@ -137,7 +137,7 @@
|
||||
|
||||
<div class="cred-field">
|
||||
<label class="cred-field-label" for="cred-password">
|
||||
{mode === "token" ? "Token" : "Passwort"}
|
||||
{mode === "token" ? "Token" : "Password"}
|
||||
</label>
|
||||
<div class="cred-input">
|
||||
<Lock size={15} class="cred-field-icon" aria-hidden="true" />
|
||||
@@ -146,8 +146,8 @@
|
||||
type={showPassword ? "text" : "password"}
|
||||
bind:value={password}
|
||||
placeholder={mode === "token"
|
||||
? "ghp_... oder anderer Zugangstoken"
|
||||
: "Passwort oder Personal Access Token"}
|
||||
? "ghp_... or another access token"
|
||||
: "Password or personal access token"}
|
||||
autocomplete="current-password"
|
||||
disabled={isBusy}
|
||||
/>
|
||||
@@ -156,7 +156,7 @@
|
||||
class="cred-reveal"
|
||||
onclick={() => { showPassword = !showPassword; }}
|
||||
tabindex="-1"
|
||||
aria-label={showPassword ? "Verbergen" : "Anzeigen"}
|
||||
aria-label={showPassword ? "Hide" : "Show"}
|
||||
>
|
||||
{#if showPassword}
|
||||
<EyeOff size={14} aria-hidden="true" />
|
||||
@@ -171,7 +171,7 @@
|
||||
{#if mode === "token"}
|
||||
<div class="cred-token-hint">
|
||||
<Key size={13} aria-hidden="true" />
|
||||
<span>Username wird automatisch auf <code>oauth2</code> gesetzt. Das funktioniert mit GitHub, GitLab und Bitbucket.</span>
|
||||
<span>Username is automatically set to <code>oauth2</code>. This works with GitHub, GitLab, and Bitbucket.</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -184,26 +184,26 @@
|
||||
|
||||
{#if saveSession}
|
||||
<div class="cred-expiry">
|
||||
<label class="cred-field-label" for="cred-expiry">Ablaufdatum (optional)</label>
|
||||
<label class="cred-field-label" for="cred-expiry">Expiration date (optional)</label>
|
||||
<input
|
||||
id="cred-expiry"
|
||||
type="date"
|
||||
bind:value={expiresAt}
|
||||
disabled={isBusy}
|
||||
/>
|
||||
<span class="cred-expiry-hint">Nach diesem Datum wird automatisch erneut nach dem Login gefragt.</span>
|
||||
<span class="cred-expiry-hint">After this date you'll automatically be asked to log in again.</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="cred-footer">
|
||||
<label class="cred-save">
|
||||
<input type="checkbox" bind:checked={saveSession} disabled={isBusy} />
|
||||
<span>Im Schluesselbund speichern</span>
|
||||
<span>Save in keychain</span>
|
||||
</label>
|
||||
|
||||
<div class="cred-btns">
|
||||
<button type="button" class="cred-cancel" onclick={onCancel} disabled={isBusy}>
|
||||
Abbrechen
|
||||
Cancel
|
||||
</button>
|
||||
<button class="cred-submit" type="submit" disabled={!canSubmit}>
|
||||
{#if isBusy}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
<script lang="ts">
|
||||
import { AlertTriangle, LoaderCircle, RotateCcw, X } from "@lucide/svelte";
|
||||
import type { GitFileStatus } from "../types";
|
||||
|
||||
interface Props {
|
||||
file: GitFileStatus;
|
||||
staged: boolean;
|
||||
scope: "file" | "hunk";
|
||||
isBusy: boolean;
|
||||
onConfirm: () => void | Promise<void>;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
let {
|
||||
file,
|
||||
staged = false,
|
||||
scope = "file",
|
||||
isBusy = false,
|
||||
onConfirm = () => {},
|
||||
onClose = () => {},
|
||||
}: Props = $props();
|
||||
|
||||
let targetPath = $derived(file.old_path ? `${file.old_path} -> ${file.path}` : file.path);
|
||||
let title = $derived(scope === "hunk" ? "Discard hunk?" : "Discard file changes?");
|
||||
let scopeLabel = $derived(scope === "hunk" ? "Selected hunk" : "File changes");
|
||||
let sourceLabel = $derived(staged ? "staged changes" : "unstaged changes");
|
||||
|
||||
function closeFromBackdrop(event: MouseEvent) {
|
||||
if (isBusy || event.target !== event.currentTarget) return;
|
||||
onClose();
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="dialog-backdrop" role="presentation" onclick={closeFromBackdrop}>
|
||||
<div class="dialog discard-confirm-dialog" role="dialog" aria-modal="true" aria-label={title}>
|
||||
<header class="dialog-header">
|
||||
<div>
|
||||
<span class="eyebrow">Confirm discard</span>
|
||||
<p class="dialog-title">{title}</p>
|
||||
</div>
|
||||
<button class="btn-sm dialog-close" type="button" onclick={onClose} disabled={isBusy} aria-label="Close">
|
||||
<X size={16} aria-hidden="true" />
|
||||
</button>
|
||||
</header>
|
||||
|
||||
<div class="discard-confirm-body">
|
||||
<div class="discard-warning-icon" aria-hidden="true">
|
||||
<AlertTriangle size={22} />
|
||||
</div>
|
||||
|
||||
<div class="discard-confirm-copy">
|
||||
<p>
|
||||
This will reset the {sourceLabel} for the {scopeLabel.toLowerCase()} below.
|
||||
</p>
|
||||
<code class="discard-target" title={targetPath}>{targetPath}</code>
|
||||
<p class="discard-warning-text">
|
||||
This cannot be undone. If the file only exists in your working tree, it can be deleted entirely.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer class="discard-confirm-actions">
|
||||
<button class="btn-secondary" type="button" onclick={onClose} disabled={isBusy}>Cancel</button>
|
||||
<button class="btn-danger" type="button" onclick={onConfirm} disabled={isBusy}>
|
||||
{#if isBusy}
|
||||
<LoaderCircle class="spin" size={15} aria-hidden="true" />
|
||||
{:else}
|
||||
<RotateCcw size={15} aria-hidden="true" />
|
||||
{/if}
|
||||
Discard
|
||||
</button>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
export let label = "Repository wird geöffnet";
|
||||
export let label = "Opening repository";
|
||||
export let repoName = "";
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user