From f6832a4d2a0a51f7c6de8b5b90e8b156c3f0bed2 Mon Sep 17 00:00:00 2001 From: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> Date: Wed, 4 Nov 2026 10:56:47 +0800 Subject: [PATCH] fix(i18n): translate Git operation titles and their notifications MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Git operations run through runOp / runGitOperation took their title, success and failure text as plain strings, which the text catalog check doesn't see, so the notifications after a commit, merge, rebase, stash, shelve, tag, patch or rollback ("3 files committed: …", "Merged a into b", "Checkout x failed") stayed in English, and several spliced plural or English words into the sentence. The call sites now tag the text with tx, each count and variant has its own sentence, and a failure is titled "{title} failed" from the translated title. --- src/features/vcs/DiffEditor.tsx | 2 +- src/features/vcs/LocalHistory.tsx | 5 +-- src/features/vcs/MergeEditor.tsx | 4 +-- src/features/vcs/branchOps.ts | 38 +++++++++++--------- src/features/vcs/changeOps.tsx | 39 ++++++++++++++------- src/features/vcs/confirmations.tsx | 9 +++-- src/features/vcs/conflictsUi.tsx | 4 +-- src/features/vcs/gitMenuDialogs.tsx | 8 ++--- src/features/vcs/logChanges.ts | 4 +-- src/features/vcs/operations.tsx | 20 +++++------ src/features/vcs/ops.ts | 2 +- src/features/vcs/patches.tsx | 4 +-- src/features/vcs/rebase.tsx | 6 ++-- src/features/vcs/shelf.tsx | 10 +++--- src/platform/locales/text/zh.json | 54 ++++++++++++++++++++++++++++- 15 files changed, 143 insertions(+), 66 deletions(-) diff --git a/src/features/vcs/DiffEditor.tsx b/src/features/vcs/DiffEditor.tsx index ae46a3287..b00dd6e70 100644 --- a/src/features/vcs/DiffEditor.tsx +++ b/src/features/vcs/DiffEditor.tsx @@ -724,7 +724,7 @@ export function DiffEditor({ input, toolbarActions }: { input: EditorInput; tool logConsole("info", "Nothing to stage for this change"); return; } - await runOp(`Stage hunk of ${path}`, () => call(commands.vcsStageHunks(path, indices))); + await runOp(tx`Stage hunk of ${path}`, () => call(commands.vcsStageHunks(path, indices))); await refreshNow(); } finally { setBusy(false); diff --git a/src/features/vcs/LocalHistory.tsx b/src/features/vcs/LocalHistory.tsx index da3c35f9a..2c467bcf3 100644 --- a/src/features/vcs/LocalHistory.tsx +++ b/src/features/vcs/LocalHistory.tsx @@ -97,12 +97,13 @@ export function LocalHistoryEditor({ input }: { input: EditorInput }) { const ok = await confirmDialog({ title: "Revert", message: question, okLabel: "Revert" }); if (!ok) return; await runOp( - "Revert from Local History", + tx("Revert from Local History"), async () => { for (const e of targets) await call(commands.historyRestore(e.path, e.id)); }, { - success: targets.length === 1 ? `${baseName(targets[0]!.path)} reverted` : `${targets.length} files reverted`, + success: + targets.length === 1 ? tx`${baseName(targets[0]!.path)} reverted` : tx`${targets.length} files reverted`, refresh: true, }, ); diff --git a/src/features/vcs/MergeEditor.tsx b/src/features/vcs/MergeEditor.tsx index 0d5c77966..6244d82a8 100644 --- a/src/features/vcs/MergeEditor.tsx +++ b/src/features/vcs/MergeEditor.tsx @@ -259,14 +259,14 @@ export function MergeEditor({ input }: { input: EditorInput }) { /** Saves `text` as the resolved file and stages it; like IDEA, that closes the merge editor. */ const writeResolved = async (text: string | null) => { const ok = await runOp( - `Resolve ${baseName(path)}`, + tx`Resolve ${baseName(path)}`, async () => { if (text === null) await call(commands.fsDelete(path)); else await writeFileText(path, text, { save: true, exact: true }); await call(commands.vcsStage([path])); return true; }, - { success: `${baseName(path)}: conflicts resolved` }, + { success: tx`${baseName(path)}: conflicts resolved` }, ); if (ok) { setResolved(true); diff --git a/src/features/vcs/branchOps.ts b/src/features/vcs/branchOps.ts index b5f4adb09..6bd3f894c 100644 --- a/src/features/vcs/branchOps.ts +++ b/src/features/vcs/branchOps.ts @@ -79,7 +79,7 @@ async function performCheckout( let options: CheckoutOptions = { mode: "normal", diverged: null }; for (;;) { const opts = options; - const outcome = await runOp(`Checkout ${rev}`, () => call(commands.vcsCheckout(repo, rev, false, opts))); + const outcome = await runOp(tx`Checkout ${rev}`, () => call(commands.vcsCheckout(repo, rev, false, opts))); if (!outcome) return false; // `success` may name the branch now checked out. if (outcome.kind === "done" || outcome.kind === "conflicts") await refreshNow(); @@ -167,7 +167,7 @@ export async function newBranch(from?: string) { const previous = useVcs.getState().branch?.head; if (checkout) await saveAll(); const create = () => call(commands.vcsCreateBranch(repo, r.value, from ?? null, checkout)); - const ok = await runOp(`Create branch ${r.value}`, create, { + const ok = await runOp(tx`Create branch ${r.value}`, create, { success: checkout ? `Created and checked out ${r.value}` : `Created branch ${r.value}`, }); if (ok !== undefined && checkout) { @@ -208,8 +208,8 @@ export async function openConflictsInstead(): Promise { export async function mergeIntoCurrent(branch: string, repo: string | null = currentRepo()) { const current = (repo === currentRepo() ? useVcs.getState().branch?.head : null) ?? "HEAD"; await saveAll(); - await runOp(`Merge ${branch} into ${current}`, () => call(commands.vcsMerge(repo, branch)), { - success: `Merged ${branch} into ${current}`, + await runOp(tx`Merge ${branch} into ${current}`, () => call(commands.vcsMerge(repo, branch)), { + success: tx`Merged ${branch} into ${current}`, errorActions: conflictActions, onError: openConflictsInstead, }); @@ -219,8 +219,8 @@ export async function rebaseOnto(branch: string) { const repo = currentRepo(); const current = useVcs.getState().branch?.head ?? "HEAD"; await saveAll(); - await runOp(`Rebase ${current} onto ${branch}`, () => call(commands.vcsRebase(repo, branch)), { - success: `Rebased ${current} onto ${branch}`, + await runOp(tx`Rebase ${current} onto ${branch}`, () => call(commands.vcsRebase(repo, branch)), { + success: tx`Rebased ${current} onto ${branch}`, errorActions: conflictActions, onError: openConflictsInstead, }); @@ -238,8 +238,8 @@ export async function renameBranch(name: string) { }); if (!r) return; const to = r.value.trim(); - const ok = await runOp(`Rename branch ${name}`, () => call(commands.vcsRenameBranch(repo, name, to)), { - success: `Renamed branch ${name} to ${to}`, + const ok = await runOp(tx`Rename branch ${name}`, () => call(commands.vcsRenameBranch(repo, name, to)), { + success: tx`Renamed branch ${name} to ${to}`, }); if (ok !== undefined) { try { @@ -257,7 +257,7 @@ export async function renameBranch(name: string) { */ export async function deleteBranch(name: string) { const repo = currentRepo(); - const deleted = await runOp(`Delete branch ${name}`, () => call(commands.vcsDeleteBranch(repo, name))); + const deleted = await runOp(tx`Delete branch ${name}`, () => call(commands.vcsDeleteBranch(repo, name))); if (!deleted) return; const tracked = deleted.upstream; const otherTracking = useVcs.getState().branches.some((b) => !b.remote && b.name !== name && b.upstream === tracked); @@ -274,8 +274,8 @@ export async function deleteBranch(name: string) { label: "Restore", run: () => { done(); - void runOp(`Restore branch ${name}`, () => call(commands.vcsRestoreBranch(repo, deleted)), { - success: `Restored branch ${name}`, + void runOp(tx`Restore branch ${name}`, () => call(commands.vcsRestoreBranch(repo, deleted)), { + success: tx`Restored branch ${name}`, }); }, }, @@ -379,9 +379,13 @@ export async function newBranchInRepos(roots: readonly string[], from?: string) await eachRepo( roots, async (root) => - (await runOp(`Create branch ${name}`, () => call(commands.vcsCreateBranch(root, name, from ?? null, r.checked)), { - refresh: false, - })) !== undefined, + (await runOp( + tx`Create branch ${name}`, + () => call(commands.vcsCreateBranch(root, name, from ?? null, r.checked)), + { + refresh: false, + }, + )) !== undefined, r.checked ? `Created and checked out ${name}` : `Created branch ${name}`, ); } @@ -392,7 +396,7 @@ export async function mergeInRepos(branch: string, roots: readonly string[]) { await eachRepo( roots, async (root) => - (await runOp(`Merge ${branch} (${repoName(root)})`, () => call(commands.vcsMerge(root, branch)), { + (await runOp(tx`Merge ${branch} (${repoName(root)})`, () => call(commands.vcsMerge(root, branch)), { refresh: false, errorActions: conflictActions, onError: openConflictsInstead, @@ -407,7 +411,7 @@ export async function rebaseInRepos(branch: string, roots: readonly string[]) { await eachRepo( roots, async (root) => - (await runOp(`Rebase onto ${branch} (${repoName(root)})`, () => call(commands.vcsRebase(root, branch)), { + (await runOp(tx`Rebase onto ${branch} (${repoName(root)})`, () => call(commands.vcsRebase(root, branch)), { refresh: false, errorActions: conflictActions, onError: openConflictsInstead, @@ -428,7 +432,7 @@ export async function deleteInRepos(name: string, roots: readonly string[]) { await eachRepo( roots, async (root) => - (await runOp(`Delete branch ${name} (${repoName(root)})`, () => call(commands.vcsDeleteBranch(root, name)), { + (await runOp(tx`Delete branch ${name} (${repoName(root)})`, () => call(commands.vcsDeleteBranch(root, name)), { refresh: false, })) !== undefined, `Deleted branch ${name}`, diff --git a/src/features/vcs/changeOps.tsx b/src/features/vcs/changeOps.tsx index be93de050..a50adc30c 100644 --- a/src/features/vcs/changeOps.tsx +++ b/src/features/vcs/changeOps.tsx @@ -90,8 +90,23 @@ export async function commitChanges(): Promise { success: () => { const n = plan.included.length; const summary = firstLine(message); - const where = repos.length > 1 ? ` in ${repos.length} repositories` : ""; - return `${n} file${n === 1 ? "" : "s"} ${amend ? "amended" : "committed"}${where}${summary ? `: ${summary}` : ""}`; + const several = repos.length; + const done = amend + ? several > 1 + ? n === 1 + ? tx`1 file amended in ${several} repositories` + : tx`${n} files amended in ${several} repositories` + : n === 1 + ? tx("1 file amended") + : tx`${n} files amended` + : several > 1 + ? n === 1 + ? tx`1 file committed in ${several} repositories` + : tx`${n} files committed in ${several} repositories` + : n === 1 + ? tx("1 file committed") + : tx`${n} files committed`; + return summary ? `${done}: ${summary}` : done; }, }, ); @@ -199,12 +214,12 @@ function RollbackDialog({ files, onClose }: { files: FileStatus[]; onClose: () = await saveAll(); const { unstage, discard } = rollbackPlan(chosen, deleteAdded); await runOp( - "Rollback", + tx("Rollback"), async () => { if (unstage.length) await call(commands.vcsUnstage(unstage)); if (discard.length) await call(commands.vcsDiscard(discard)); }, - { success: `Rolled back ${chosen.length} file${chosen.length === 1 ? "" : "s"}` }, + { success: chosen.length === 1 ? tx("Rolled back 1 file") : tx`Rolled back ${chosen.length} files` }, ); }; return ( @@ -284,7 +299,7 @@ export async function addToVcs(paths: readonly string[]) { }); return; } - await runOp(`Add ${targets.length} file${targets.length === 1 ? "" : "s"} to Git`, () => + await runOp(targets.length === 1 ? tx("Add 1 file to Git") : tx`Add ${targets.length} files to Git`, () => call(commands.vcsStage(targets.map(stripSlash))), ); } @@ -299,9 +314,9 @@ export function stashChanges(repo = currentRepo()): Promise { if (r) { await saveAll(); await runOp( - "Stash changes", + tx("Stash changes"), () => call(commands.vcsStashPush(repo, r.message || null, r.includeUntracked, r.keepIndex)), - { success: "Changes stashed" }, + { success: tx("Changes stashed") }, ); void loadStashes().catch(() => undefined); } @@ -372,10 +387,10 @@ export interface UnstashOptions { export function unstashTitles(o: UnstashOptions): { title: string; success: string } { const ref = `stash@{${o.index}}`; if (o.branch) - return { title: tx`Unstash ${ref} as branch ${o.branch}`, success: `Unstashed ${ref} on branch ${o.branch}` }; + return { title: tx`Unstash ${ref} as branch ${o.branch}`, success: tx`Unstashed ${ref} on branch ${o.branch}` }; return o.pop - ? { title: tx`Pop ${ref}`, success: `Unstashed ${ref}` } - : { title: tx`Apply ${ref}`, success: `Applied ${ref}` }; + ? { title: tx`Pop ${ref}`, success: tx`Unstashed ${ref}` } + : { title: tx`Apply ${ref}`, success: tx`Applied ${ref}` }; } export async function unstash(o: UnstashOptions, repo = currentRepo()) { @@ -482,8 +497,8 @@ export async function dropStash(index: number, message: string, repo = currentRe danger: true, }); if (!ok) return; - await runOp(`Drop stash@{${index}}`, () => call(commands.vcsStashDrop(repo, index)), { - success: `Dropped stash@{${index}}`, + await runOp(tx`Drop ${`stash@{${index}}`}`, () => call(commands.vcsStashDrop(repo, index)), { + success: tx`Dropped ${`stash@{${index}}`}`, }); void loadStashes().catch((e) => logConsole("err", String(e))); } diff --git a/src/features/vcs/confirmations.tsx b/src/features/vcs/confirmations.tsx index e71a546c6..b0a0ab7cb 100644 --- a/src/features/vcs/confirmations.tsx +++ b/src/features/vcs/confirmations.tsx @@ -4,6 +4,7 @@ * the deletion staged (`git rm`), with the same three choices. */ import { onFileOperation, type FileOperation } from "@/platform/fileOps"; +import { tx } from "@/platform/i18n"; import { call, commands, isTauri } from "@/platform/ipc"; import { loadSettings } from "@/platform/project"; import { workflowSettings } from "@/platform/workflowSettings"; @@ -80,8 +81,12 @@ async function handle(op: FileOperation) { const n = files.length; await runOp( op.kind === "created" - ? `Add ${n} file${n === 1 ? "" : "s"} to Git` - : `Remove ${n} file${n === 1 ? "" : "s"} from Git`, + ? n === 1 + ? tx("Add 1 file to Git") + : tx`Add ${n} files to Git` + : n === 1 + ? tx("Remove 1 file from Git") + : tx`Remove ${n} files from Git`, () => call(commands.vcsStage(files)), ); } diff --git a/src/features/vcs/conflictsUi.tsx b/src/features/vcs/conflictsUi.tsx index c24969bdb..2777e3eab 100644 --- a/src/features/vcs/conflictsUi.tsx +++ b/src/features/vcs/conflictsUi.tsx @@ -31,7 +31,7 @@ export function openMergeEditor(path: string) { async function acceptSide(f: FileStatus, side: "ours" | "theirs") { const path = stripSlash(f.path); await runOp( - `Accept ${side === "ours" ? "yours" : "theirs"} for ${baseName(path)}`, + side === "ours" ? tx`Accept yours for ${baseName(path)}` : tx`Accept theirs for ${baseName(path)}`, async () => { const v = await call(commands.vcsConflictVersions(path)); const text = side === "ours" ? v.ours : v.theirs; @@ -43,7 +43,7 @@ async function acceptSide(f: FileStatus, side: "ours" | "theirs") { } await call(commands.vcsStage([path])); }, - { success: `${baseName(path)} resolved` }, + { success: tx`${baseName(path)} resolved` }, ); } diff --git a/src/features/vcs/gitMenuDialogs.tsx b/src/features/vcs/gitMenuDialogs.tsx index 12171251a..cc19fb228 100644 --- a/src/features/vcs/gitMenuDialogs.tsx +++ b/src/features/vcs/gitMenuDialogs.tsx @@ -238,9 +238,9 @@ function MergeDialog({ onClose }: { onClose: () => void }) { await saveAll(); const target = head ?? "HEAD"; await runOp( - `Merge ${branch} into ${target}`, + tx`Merge ${branch} into ${target}`, () => call(commands.vcsMergeWith(repo, [branch], mergeOptionsOf(flags, withMessage ? message : null))), - { success: `Merged ${branch} into ${target}`, errorActions: conflictActions, onError: openConflictsInstead }, + { success: tx`Merged ${branch} into ${target}`, errorActions: conflictActions, onError: openConflictsInstead }, ); await refreshNow(); }; @@ -313,7 +313,7 @@ function RebaseDialog({ onClose }: { onClose: () => void }) { const target = useOnto && onto ? onto : upstream; const current = head ?? "HEAD"; await runOp( - `Rebase ${current} onto ${target}`, + tx`Rebase ${current} onto ${target}`, () => call( commands.vcsRebaseWith(repo, upstream, { @@ -322,7 +322,7 @@ function RebaseDialog({ onClose }: { onClose: () => void }) { keepEmpty, }), ), - { success: `Rebased ${current} onto ${target}`, errorActions: conflictActions, onError: openConflictsInstead }, + { success: tx`Rebased ${current} onto ${target}`, errorActions: conflictActions, onError: openConflictsInstead }, ); await refreshNow(); }; diff --git a/src/features/vcs/logChanges.ts b/src/features/vcs/logChanges.ts index 87e1b0d27..c292d9450 100644 --- a/src/features/vcs/logChanges.ts +++ b/src/features/vcs/logChanges.ts @@ -184,7 +184,7 @@ export async function getFromRevision(changes: readonly LogChange[]) { if (!ok) return; await saveAll(); await runOp( - "Get from Revision", + tx("Get from Revision"), async () => { for (const c of changes) { const path = absolutePath(c.path, c.repo); @@ -211,7 +211,7 @@ export async function revertSelectedChanges(changes: readonly LogChange[], commi const ids = [...commits].reverse().map((c) => c.id); const paths = new Set(changes.flatMap((c) => (c.oldPath ? [c.path, c.oldPath] : [c.path]))); const outcome = await runOp( - "Revert selected changes", + tx("Revert selected changes"), async () => { const patch = filterPatch( await call( diff --git a/src/features/vcs/operations.tsx b/src/features/vcs/operations.tsx index d0a9bbe0b..51ac6ec42 100644 --- a/src/features/vcs/operations.tsx +++ b/src/features/vcs/operations.tsx @@ -165,7 +165,7 @@ export async function controlOperation(control: "continue" | "skip" | "abort", e { progress, success, - failure: `${controlLabel(op, control)} failed`, + failure: tx`${controlLabel(op, control)} failed`, onError: control === "abort" ? undefined : conflictsInstead, }, ); @@ -241,8 +241,8 @@ export async function cherryPick(commits: Commit[]) { { op: "cherryPick", commits: ordered.map((c) => c.id) }, { progress: "Cherry-picking", - success: `Cherry-picked ${label}`, - failure: "Cherry-pick failed", + success: tx`Cherry-picked ${label}`, + failure: tx("Cherry-pick failed"), onError: conflictsInstead, }, commitRepo(commits[0]!) ?? currentRepo(), @@ -256,7 +256,7 @@ export async function revertCommits(commits: Commit[]) { ordered.length === 1 ? `${short(ordered[0]!.id)} “${ordered[0]!.summary}”` : `${ordered.length} commits`; await runGitOperation( { op: "revert", commits: ordered.map((c) => c.id) }, - { progress: "Reverting", success: `Reverted ${label}`, failure: "Revert failed", onError: conflictsInstead }, + { progress: "Reverting", success: tx`Reverted ${label}`, failure: tx("Revert failed"), onError: conflictsInstead }, commitRepo(commits[0]!) ?? currentRepo(), ); } @@ -294,8 +294,8 @@ function ResetDialog({ commit, onClose }: { commit?: Commit; onClose: () => void { op: "reset", commit: rev, mode }, { progress: "Resetting", - success: `Reset ${head} to ${commit ? short(commit.id) : rev} (${mode})`, - failure: "Reset failed", + success: tx`Reset ${head} to ${commit ? short(commit.id) : rev} (${mode})`, + failure: tx("Reset failed"), }, repo, ); @@ -374,8 +374,8 @@ export async function newTagOn(commit: Commit) { }); if (!r) return; const create = () => call(commands.vcsCreateTag(repo, r.value, commit.id, null, false)); - const ok = await runOp(`Create tag ${r.value}`, create, { - success: `Created tag ${r.value} on ${short(commit.id)}`, + const ok = await runOp(tx`Create tag ${r.value}`, create, { + success: tx`Created tag ${r.value} on ${short(commit.id)}`, }); // Tags are not part of the refs signature that reloads the log. if (ok !== undefined) void reloadLog(); @@ -402,9 +402,9 @@ function TagDialog({ onClose }: { onClose: () => void }) { onClose(); const tag = name.trim(); const ok = await runOp( - `Create tag ${tag}`, + tx`Create tag ${tag}`, () => call(commands.vcsCreateTag(repo, tag, commit.trim() || "HEAD", message || null, force)), - { success: `Created tag ${tag}` }, + { success: tx`Created tag ${tag}` }, ); if (ok !== undefined && useGitLog.getState().commits.length) void reloadLog(); }; diff --git a/src/features/vcs/ops.ts b/src/features/vcs/ops.ts index db1344529..504dd3099 100644 --- a/src/features/vcs/ops.ts +++ b/src/features/vcs/ops.ts @@ -89,7 +89,7 @@ export async function runOp(title: string, fn: () => Promise, opts: OpOpti notifications().notify({ group: "vcs", level: "error", - title: `${title} failed`, + title: tx`${title} failed`, body: message, actions: opts.errorActions?.(message), }); diff --git a/src/features/vcs/patches.tsx b/src/features/vcs/patches.tsx index ab3a58830..0f4ee0820 100644 --- a/src/features/vcs/patches.tsx +++ b/src/features/vcs/patches.tsx @@ -116,7 +116,7 @@ function CreatePatchDialog({ origin, onClose }: { origin: PatchOrigin; onClose: reverse, }; const done = await runOp( - "Create patch", + tx("Create patch"), async () => { const patch = origin.kind === "shelf" @@ -250,7 +250,7 @@ function ApplyPatchDialog({ patch, source, onClose }: { patch: string; source: s const run = async () => { onClose(); await saveAll(); - const outcome = await runOp(`Apply patch (${source})`, () => call(commands.vcsApplyPatch(repo, patch)), { + const outcome = await runOp(tx`Apply patch (${source})`, () => call(commands.vcsApplyPatch(repo, patch)), { refresh: false, }); if (outcome) await reportApply(outcome, "Patch applied"); diff --git a/src/features/vcs/rebase.tsx b/src/features/vcs/rebase.tsx index 044b02189..a6a741556 100644 --- a/src/features/vcs/rebase.tsx +++ b/src/features/vcs/rebase.tsx @@ -62,8 +62,8 @@ export async function undoCommit(commit: Commit) { if (!ok) return; } const undo = () => call(commands.vcsUndoCommit(repo, commit.id)); - const message = await runOp(`Undo commit ${short(commit.id)}`, undo, { - success: `Undid commit ${short(commit.id)} “${commit.summary}”; its changes are staged`, + const message = await runOp(tx`Undo commit ${short(commit.id)}`, undo, { + success: tx`Undid commit ${short(commit.id)} “${commit.summary}”; its changes are staged`, }); // IDEA offers the undone message for the next commit. if (message !== undefined && !useCommit.getState().message.trim()) useCommit.setState({ message }); @@ -123,7 +123,7 @@ async function runRebase(base: string | null, entries: RebaseEntry[], done: stri { progress: "Rebasing", success: () => (inProgress() === "rebase" ? "Rebase stopped for editing; continue the rebase when done" : done), - failure: "Rebase failed", + failure: tx("Rebase failed"), onError: conflictsInstead, }, repo, diff --git a/src/features/vcs/shelf.tsx b/src/features/vcs/shelf.tsx index 9e808b91d..07d8bf592 100644 --- a/src/features/vcs/shelf.tsx +++ b/src/features/vcs/shelf.tsx @@ -144,7 +144,7 @@ function ShelveDialog({ if (!chosen.length || !name.trim()) return; onClose(); await saveAll(); - const entry = await runOp(`Shelve changes “${name.trim()}”`, () => call(commands.vcsShelve(name.trim(), chosen))); + const entry = await runOp(tx`Shelve changes “${name.trim()}”`, () => call(commands.vcsShelve(name.trim(), chosen))); if (!entry) return; void loadShelves().catch(() => undefined); notifications().notify({ @@ -218,7 +218,7 @@ function UnshelveDialog({ entry, path, onClose }: { entry: ShelvedChangeList; pa onClose(); await saveAll(); const outcome = await runOp( - `Unshelve “${entry.name}”`, + tx`Unshelve “${entry.name}”`, () => call(commands.vcsUnshelve(entry.id, remove, path ?? null)), { refresh: false, @@ -272,7 +272,7 @@ export async function deleteShelf(entry: ShelvedChangeList, path?: string) { danger: true, }); if (!ok) return; - await runOp(`Delete shelved changes “${entry.name}”`, () => call(commands.vcsShelfDelete(entry.id, path ?? null)), { + await runOp(tx`Delete shelved changes “${entry.name}”`, () => call(commands.vcsShelfDelete(entry.id, path ?? null)), { refresh: false, }); void loadShelves().catch(() => undefined); @@ -286,7 +286,7 @@ export async function renameShelf(entry: ShelvedChangeList) { okLabel: "Rename", }); if (!r || r.value === entry.name) return; - await runOp("Rename shelved changes", () => call(commands.vcsShelfRename(entry.id, r.value)), { refresh: false }); + await runOp(tx("Rename shelved changes"), () => call(commands.vcsShelfRename(entry.id, r.value)), { refresh: false }); void loadShelves().catch(() => undefined); } @@ -388,7 +388,7 @@ export async function importShelfPatches(paths?: string[]) { if (!picked) return; for (const path of typeof picked === "string" ? [picked] : picked) { await runOp( - "Import patches", + tx("Import patches"), async () => call(commands.vcsShelfImport(repo, baseName(path), await call(commands.fsReadText(path)))), { refresh: false }, ); diff --git a/src/platform/locales/text/zh.json b/src/platform/locales/text/zh.json index 9771374a8..9bd26e1dc 100644 --- a/src/platform/locales/text/zh.json +++ b/src/platform/locales/text/zh.json @@ -5858,5 +5858,57 @@ "Could not start Compose project {project}": "无法启动 Compose 项目 {project}", "Could not stop Compose project {project}": "无法停止 Compose 项目 {project}", "Could not restart Compose project {project}": "无法重启 Compose 项目 {project}", - "Could not take down Compose project {project}": "无法停止并移除 Compose 项目 {project}" + "Could not take down Compose project {project}": "无法停止并移除 Compose 项目 {project}", + "Stage hunk of {path}": "暂存 {path} 的块", + "{path} reverted": "已还原 {path}", + "{length} files reverted": "已还原 {length} 个文件", + "Resolve {path}": "解决 {path}", + "{path}: conflicts resolved": "{path}:冲突已解决", + "Create branch {value}": "创建分支 {value}", + "Merge {branch} into {current}": "将 {branch} 合并到 {current}", + "Merged {branch} into {current}": "已将 {branch} 合并到 {current}", + "Rebase {current} onto {branch}": "将 {current} 变基到 {branch}", + "Rebased {current} onto {branch}": "已将 {current} 变基到 {branch}", + "Rename branch {name}": "重命名分支 {name}", + "Renamed branch {name} to {to}": "已将分支 {name} 重命名为 {to}", + "Delete branch {name}": "删除分支 {name}", + "Restore branch {name}": "恢复分支 {name}", + "Merge {branch} ({root})": "合并 {branch}({root})", + "Rebase onto {branch} ({root})": "变基到 {branch}({root})", + "Delete branch {name} ({root})": "删除分支 {name}({root})", + "1 file amended in {several} repositories": "已在 {several} 个仓库中修改 1 个文件的提交", + "{n} files amended in {several} repositories": "已在 {several} 个仓库中修改 {n} 个文件的提交", + "1 file amended": "已修改 1 个文件的提交", + "{n} files amended": "已修改 {n} 个文件的提交", + "1 file committed in {several} repositories": "已在 {several} 个仓库中提交 1 个文件", + "{n} files committed in {several} repositories": "已在 {several} 个仓库中提交 {n} 个文件", + "1 file committed": "已提交 1 个文件", + "{n} files committed": "已提交 {n} 个文件", + "Rolled back 1 file": "已回滚 1 个文件", + "Rolled back {length} files": "已回滚 {length} 个文件", + "Add 1 file to Git": "将 1 个文件添加到 Git", + "Add {length} files to Git": "将 {length} 个文件添加到 Git", + "Stash changes": "储藏更改", + "Changes stashed": "已储藏更改", + "Unstashed {ref} on branch {branch}": "已在分支 {branch} 上取消储藏 {ref}", + "Unstashed {ref}": "已取消储藏 {ref}", + "Applied {ref}": "已应用 {ref}", + "Dropped {ref}": "已删除 {ref}", + "Remove 1 file from Git": "从 Git 中移除 1 个文件", + "Remove {n} files from Git": "从 Git 中移除 {n} 个文件", + "Accept yours for {path}": "对 {path} 接受你的版本", + "Accept theirs for {path}": "对 {path} 接受他们的版本", + "{path} resolved": "{path} 已解决", + "Revert selected changes": "还原所选更改", + "Create tag {value}": "创建标签 {value}", + "Created tag {value} on {id}": "已在 {id} 上创建标签 {value}", + "Created tag {tag}": "已创建标签 {tag}", + "Create patch": "创建补丁", + "Apply patch ({source})": "应用补丁({source})", + "Undo commit {id}": "撤销提交 {id}", + "Undid commit {id} “{summary}”; its changes are staged": "已撤销提交 {id}“{summary}”,其更改已暂存", + "Shelve changes “{trim}”": "搁置更改“{trim}”", + "Unshelve “{name}”": "取消搁置“{name}”", + "Delete shelved changes “{name}”": "删除搁置的更改“{name}”", + "Rename shelved changes": "重命名搁置的更改" }