+
{operationTitle(op, branch?.head ?? null)}
{conflicts
- ? ` · ${conflicts} conflict${conflicts === 1 ? "" : "s"}`
+ ? ` · ${conflicts === 1 ? tx`${conflicts} conflict` : tx`${conflicts} conflicts`}`
: op === "merge"
? tx(" · commit to conclude")
: ""}
diff --git a/src/features/vcs/ops.ts b/src/features/vcs/ops.ts
index b3c34b77b..5b889a5b7 100644
--- a/src/features/vcs/ops.ts
+++ b/src/features/vcs/ops.ts
@@ -5,6 +5,7 @@
import { Channel } from "@tauri-apps/api/core";
import { create } from "zustand";
import type { GitOperation, RemoteOp } from "@/bindings";
+import { tx } from "@/platform/i18n";
import { call, commands, emitLocalIdeEvent, isCancelled, nextRequestId } from "@/platform/ipc";
import { editorsFor } from "@/editor/api";
import { maybeEditorService, notifications } from "@/workbench/contributions";
@@ -150,7 +151,8 @@ export async function runRemote(
notifications().notify({ group: "vcs", level: "warning", title: "Another remote operation is in progress" });
return false;
}
- const [progressTitle, doneTitle] = REMOTE_TITLE[op.op];
+ const [progressText, doneTitle] = REMOTE_TITLE[op.op];
+ const progressTitle = tx(progressText);
const request = nextRequestId();
const taskId = 900_000 + request;
activeRemote = request;
@@ -320,15 +322,16 @@ export async function runGitOperation(op: GitOperation, opts: GitOperationOption
const request = nextRequestId();
const taskId = 900_000 + request;
activeRemote = request;
- useVcs.setState({ remoteBusy: opts.progress });
+ const progress = tx(opts.progress);
+ useVcs.setState({ remoteBusy: progress });
const task = (message: string | null, done: boolean) =>
- emitLocalIdeEvent({ type: "task", id: taskId, title: opts.progress, message, fraction: done ? 1 : null, done });
+ emitLocalIdeEvent({ type: "task", id: taskId, title: progress, message, fraction: done ? 1 : null, done });
task(null, false);
notifications().notify({
group: "vcs",
level: "info",
key: "vcs.operation",
- title: `${opts.progress}…`,
+ title: `${progress}…`,
sticky: true,
actions: [{ label: "Cancel", run: cancelRemote }],
});
diff --git a/src/features/vcs/patches.tsx b/src/features/vcs/patches.tsx
index 3cc9f70c2..ea3d93ba9 100644
--- a/src/features/vcs/patches.tsx
+++ b/src/features/vcs/patches.tsx
@@ -257,7 +257,9 @@ function ApplyPatchDialog({ patch, source, onClose }: { patch: string; source: s
{baseName(f.path)}
- {f.oldPath ? `from ${f.oldPath}` : dirName(f.path)}
+ {f.oldPath ? tx`from ${f.oldPath}` : dirName(f.path)}
- {f.binary ? "binary" : `+${f.added} −${f.removed}`}
+ {f.binary ? tx("binary") : `+${f.added} −${f.removed}`}
{!f.applies && }
)}
diff --git a/src/features/vcs/remoteUi.tsx b/src/features/vcs/remoteUi.tsx
index b9be0f8ea..ac702f994 100644
--- a/src/features/vcs/remoteUi.tsx
+++ b/src/features/vcs/remoteUi.tsx
@@ -425,7 +425,7 @@ function PushDialog({ target: pushTarget, onClose }: { target: PushTarget; onClo
rowHeight={22}
aria-label="Outgoing commits"
className={styles.boxList}
- empty={{upstream ? tx("Everything is up to date") : "No commits"}}
+ empty={{upstream ? tx("Everything is up to date") : tx("No commits")}}
renderItem={(c) => (
{c.shortId}
diff --git a/src/features/vcs/repoBranches.ts b/src/features/vcs/repoBranches.ts
index dac9523ab..addd7b5c1 100644
--- a/src/features/vcs/repoBranches.ts
+++ b/src/features/vcs/repoBranches.ts
@@ -1,5 +1,6 @@
/** Branches popup model for a project with several repositories (pure). */
import type { Branch } from "@/bindings";
+import { tx } from "@/platform/i18n";
import { fuzzyMatch } from "@/ui/match";
import { rootOf } from "./model";
import { isFavoriteBranch, MAX_RECENT, sortLocal, sortRemote, type PopupAction } from "./branches";
@@ -23,7 +24,7 @@ export function repoColorIndex(index: number): number {
/** Display name of a repository's HEAD: its branch, else the short commit. */
export function repoHeadLabel(r: Pick): string {
if (r.head) return r.head;
- return r.headCommit ? r.headCommit.slice(0, 8) : "No commits";
+ return r.headCommit ? r.headCommit.slice(0, 8) : tx("No commits");
}
/**
@@ -167,7 +168,7 @@ export function buildMultiRepoRows({
const actionRows: RepoRow[] = [];
for (const a of actions) {
- const m = match(a.label);
+ const m = match(tx(a.label));
if (m !== false) actionRows.push({ type: "action", key: `action:${a.id}`, action: a, matches: m });
}
blocks.push(actionRows);
@@ -225,7 +226,7 @@ export function buildMultiRepoRows({
? []
: [{ type: "common", key: `common:${b.name}`, branch: b, label: b.name, depth: 1, matches: m }];
});
- group(groups, "common:local", "Common Local Branches", 0, local);
+ group(groups, "common:local", tx("Common Local Branches"), 0, local);
const byRemote = new Map();
for (const b of common.remote) {
const remote = b.name.slice(0, Math.max(0, b.name.indexOf("/")));
@@ -243,7 +244,7 @@ export function buildMultiRepoRows({
});
group(remote, `common:folder:${name}`, name, 1, leaves);
}
- group(groups, "common:remote", "Common Remote Branches", 0, remote);
+ group(groups, "common:remote", tx("Common Remote Branches"), 0, remote);
} else if (currentRepo) {
const list = branches[currentRepo.root] ?? [];
const local = sortLocal(list, favorites);
@@ -255,12 +256,12 @@ export function buildMultiRepoRows({
.filter((b): b is Branch => !!b && !b.current)
.slice(0, MAX_RECENT);
const name = currentRepo.name;
- group(groups, "repo:recent", `Recent Branches in ${name}`, 0, branchRows(currentRepo, recentList, "recent", 1));
- group(groups, "repo:local", `Local Branches in ${name}`, 0, branchRows(currentRepo, local, "local", 1));
+ group(groups, "repo:recent", tx`Recent Branches in ${name}`, 0, branchRows(currentRepo, recentList, "recent", 1));
+ group(groups, "repo:local", tx`Local Branches in ${name}`, 0, branchRows(currentRepo, local, "local", 1));
group(
groups,
"repo:remote",
- `Remote Branches in ${name}`,
+ tx`Remote Branches in ${name}`,
0,
branchRows(currentRepo, sortRemote(list, favorites), "remote", 1),
);
@@ -272,7 +273,7 @@ export function buildMultiRepoRows({
? []
: [{ type: "tag", key: `tag:${currentRepo.root}:${t}`, repo: currentRepo, tag: t, depth: 1, matches: m }];
});
- group(groups, "repo:tags", `Tags in ${name}`, 0, tagRows);
+ group(groups, "repo:tags", tx`Tags in ${name}`, 0, tagRows);
}
blocks.push(groups);
diff --git a/src/features/vcs/shelf.tsx b/src/features/vcs/shelf.tsx
index b211f29f1..b7fa3a676 100644
--- a/src/features/vcs/shelf.tsx
+++ b/src/features/vcs/shelf.tsx
@@ -355,7 +355,7 @@ export function ShelfPanel() {
}}
onContextMenu={(node, _sel, e: MouseEvent) => node && showContextMenu(e, shelfMenu(node.entry))}
aria-label="Shelved changes"
- empty={{loaded ? tx("No shelved changes") : "Loading…"}}
+ empty={{loaded ? tx("No shelved changes") : tx("Loading…")}}
renderNode={(n) =>
n.file ? (
<>
diff --git a/src/platform/dateFormat.ts b/src/platform/dateFormat.ts
index eaf497924..8552f135d 100644
--- a/src/platform/dateFormat.ts
+++ b/src/platform/dateFormat.ts
@@ -4,6 +4,7 @@
* "Use pretty formatting" (Today / Yesterday / N min ago). Used by the Git
* log, Local History, commit details and blame.
*/
+import { tx } from "./i18n";
import { useProject } from "./project";
export interface DateFormatOptions {
@@ -69,11 +70,11 @@ export function formatTimestamp(ms: number, now = Date.now(), o: DateFormatOptio
if (o.pretty) {
const diff = now - ms;
const min = 60_000;
- if (diff >= 0 && diff < min) return "Moments ago";
- if (diff >= 0 && diff < 60 * min) return `${Math.floor(diff / min)} min ago`;
+ if (diff >= 0 && diff < min) return tx("Moments ago");
+ if (diff >= 0 && diff < 60 * min) return tx`${Math.floor(diff / min)} min ago`;
const today = new Date(now);
- if (d.toDateString() === today.toDateString()) return `Today ${formatClock(d, o)}`;
- if (d.toDateString() === new Date(now - 86_400_000).toDateString()) return `Yesterday ${formatClock(d, o)}`;
+ if (d.toDateString() === today.toDateString()) return tx`Today ${formatClock(d, o)}`;
+ if (d.toDateString() === new Date(now - 86_400_000).toDateString()) return tx`Yesterday ${formatClock(d, o)}`;
return formatDay(d, o);
}
return `${formatDay(d, o)} ${formatClock(d, o)}`;
diff --git a/src/platform/locales/text/zh.json b/src/platform/locales/text/zh.json
index 994c2e993..e4adbc1a4 100644
--- a/src/platform/locales/text/zh.json
+++ b/src/platform/locales/text/zh.json
@@ -4383,5 +4383,94 @@
"{n} hours ago": "{n} 小时前",
"{n} minute ago": "{n} 分钟前",
"{n} minutes ago": "{n} 分钟前",
- "just now": "刚刚"
+ "just now": "刚刚",
+ "No symbols": "没有符号",
+ "{behind} incoming, {ahead} outgoing commits": "{behind} 个传入提交,{ahead} 个传出提交",
+ "{behind} incoming commits": "{behind} 个传入提交",
+ "{ahead} outgoing commits": "{ahead} 个传出提交",
+ "Repository: {repo}": "仓库:{repo}",
+ "Git branch: {head}": "Git 分支:{head}",
+ "Tracking {upstream}": "跟踪 {upstream}",
+ "In all {count} repositories": "在全部 {count} 个仓库中",
+ "{current} of {count} differences": "第 {current} 处差异,共 {count} 处",
+ "{count} difference": "{count} 处差异",
+ "{count} differences": "{count} 处差异",
+ "{left} conflict left": "剩余 {left} 个冲突",
+ "{left} conflicts left": "剩余 {left} 个冲突",
+ "Cloning…": "正在克隆…",
+ "locked": "已锁定",
+ "prunable": "可清理",
+ "Rebasing": "正在变基",
+ "Merging": "正在合并",
+ "Cherry-picking": "正在拣选",
+ "Reverting": "正在还原",
+ "Applying patches": "正在应用补丁",
+ "Rebasing {head}": "正在变基 {head}",
+ "Merging {head}": "正在合并到 {head}",
+ "Cherry-picking {head}": "正在拣选到 {head}",
+ "Reverting {head}": "正在 {head} 上还原",
+ "Applying patches to {head}": "正在向 {head} 应用补丁",
+ "Rebase in progress": "变基进行中",
+ "Merge in progress": "合并进行中",
+ "Cherry-pick in progress": "拣选进行中",
+ "Revert in progress": "还原进行中",
+ "Patch application in progress": "补丁应用进行中",
+ "{conflicts} conflict": "{conflicts} 个冲突",
+ "{conflicts} conflicts": "{conflicts} 个冲突",
+ "Continuing rebase": "正在继续变基",
+ "Continuing merge": "正在继续合并",
+ "Continuing cherry-pick": "正在继续拣选",
+ "Continuing revert": "正在继续还原",
+ "Continuing patch application": "正在继续应用补丁",
+ "Skipping commit": "正在跳过提交",
+ "Aborting rebase": "正在中止变基",
+ "Aborting merge": "正在中止合并",
+ "Aborting cherry-pick": "正在中止拣选",
+ "Aborting revert": "正在中止还原",
+ "Aborting patch application": "正在中止补丁应用",
+ "Rebase continued": "变基已继续",
+ "Merge continued": "合并已继续",
+ "Cherry-pick continued": "拣选已继续",
+ "Revert continued": "还原已继续",
+ "Patch application continued": "补丁应用已继续",
+ "Commit skipped": "已跳过提交",
+ "Rebase aborted": "变基已中止",
+ "Merge aborted": "合并已中止",
+ "Cherry-pick aborted": "拣选已中止",
+ "Revert aborted": "还原已中止",
+ "Patch application aborted": "补丁应用已中止",
+ "Rebase failed": "变基失败",
+ "Cherry-pick failed": "拣选失败",
+ "Revert failed": "还原失败",
+ "Reset failed": "重置失败",
+ "Rebase stopped for editing; continue the rebase when done": "变基已停止以便编辑;完成后请继续变基",
+ "Cherry-picked {label}": "已拣选 {label}",
+ "Reverted {label}": "已还原 {label}",
+ "Reset {head} to {rev} ({mode})": "已将 {head} 重置到 {rev}({mode})",
+ "Resetting": "正在重置",
+ "Fetching": "正在获取",
+ "Updating project": "正在更新项目",
+ "Pulling": "正在拉取",
+ "Pushing": "正在推送",
+ "Deleting remote branch": "正在删除远程分支",
+ "Updating branch": "正在更新分支",
+ "Delete remote branch": "删除远程分支",
+ "binary": "二进制",
+ "Common Local Branches": "公共本地分支",
+ "Common Remote Branches": "公共远程分支",
+ "Recent Branches in {name}": "{name} 中的最近分支",
+ "Local Branches in {name}": "{name} 中的本地分支",
+ "Remote Branches in {name}": "{name} 中的远程分支",
+ "Tags in {name}": "{name} 中的标签",
+ "Moments ago": "刚刚",
+ "{min} min ago": "{min} 分钟前",
+ "Today {time}": "今天 {time}",
+ "Yesterday {time}": "昨天 {time}",
+ "Added lines": "新增的行",
+ "Deleted lines": "删除的行",
+ "Added": "已添加",
+ "Renamed": "已重命名",
+ "Unversioned": "未跟踪",
+ "Merge conflict": "合并冲突",
+ "by {author}": "由 {author} 创建"
}
diff --git a/src/platform/locales/textCatalog.test.ts b/src/platform/locales/textCatalog.test.ts
index a31125dfd..3025e8dc6 100644
--- a/src/platform/locales/textCatalog.test.ts
+++ b/src/platform/locales/textCatalog.test.ts
@@ -196,7 +196,6 @@ const UNTRANSLATED = new Set([
"info",
"languageServer",
"process",
- "read-only",
"Running processes requires the desktop app.\n",
"text",
]);