fix(i18n): Translate the remaining UI text (Git, hierarchy, pull requests, dialogs, aria labels) (#114)

Hard-coded UI text, titles and aria-labels in about 110 components (Git panels, hierarchy, pull requests, dialogs, settings, welcome) now go through tx; spliced fragments became whole sentences (fileCount, noneFoundLabel, hierarchyTitle) and pull request states use keyed messages. 225 zh entries added, stale fragment entries removed.

Also: tx used as a tag without interpolations (tx`No checks`) now looks the text up exactly instead of as a template, so it is translated like tx("No checks"); the text-catalog test checks such tags as plain literals. Check and test counts reuse the existing "{count} passed" / "{failed} failing" entries.

Claude-Session: https://claude.ai/code/session_01VUYsdXA2nkF5v6zsC93dpn
Co-authored-by: jaw52 <[email protected]>
Цей коміт міститься в:
Jaw authored and GitHub committed 2026-10-28 12:18:46 +08:00
1 джерело faf666d125
коміт 70f10e741c
121 files changed
+854 -457

No files matched your search

+11 -9
Переглянути файл
@@ -152,8 +152,8 @@ export function DebugToolWindow() {
return (
<div className={styles.root}>
<div className={styles.toolbar} role="toolbar" aria-label="Debugger actions">
<div role="tablist" aria-label="Debug views" className={styles.tabs}>
<div className={styles.toolbar} role="toolbar" aria-label={tx("Debugger actions")}>
<div role="tablist" aria-label={tx("Debug views")} className={styles.tabs}>
{(
[
["variables", "Threads & Variables"],
@@ -262,7 +262,7 @@ function FramesPane({ session }: { session: DebugSession }) {
<div
className={styles.frameList}
role="listbox"
aria-label="Frames"
aria-label={tx("Frames")}
tabIndex={0}
onKeyDown={onKeyDown}
onFocus={() =>
@@ -276,7 +276,7 @@ function FramesPane({ session }: { session: DebugSession }) {
}
onBlur={() => blurDebugView("frames")}
>
{!paused && <div className={styles.note}>{session.status === "terminated" ? "Finished" : "Running…"}</div>}
{!paused && <div className={styles.note}>{session.status === "terminated" ? tx("Finished") : "Running…"}</div>}
{items.map((item) =>
item.kind === "hidden" ? (
<button
@@ -285,7 +285,7 @@ function FramesPane({ session }: { session: DebugSession }) {
className={clsx(styles.frame, styles.hiddenFrames)}
onClick={() => setShowAll(true)}
>
{item.count} library frames hidden
{tx`${item.count} library frames hidden`}
</button>
) : (
<button
@@ -496,7 +496,7 @@ function VariablesPane({ session }: { session: DebugSession }) {
}
}}
placeholder={frame != null ? "Evaluate expression (↩) or add a watch (⇧⌘↩)" : "Evaluate expression"}
aria-label="Evaluate expression"
aria-label={tx("Evaluate expression")}
spellCheck={false}
autoComplete="off"
disabled={frame == null}
@@ -516,7 +516,9 @@ function VariablesPane({ session }: { session: DebugSession }) {
</div>
{frame == null && !watches.length && !lastEval ? (
<div className={styles.note}>
{session.status === "terminated" ? "The session has finished." : "Variables are available while suspended."}
{session.status === "terminated"
? tx("The session has finished.")
: tx("Variables are available while suspended.")}
</div>
) : (
<VariablesView
@@ -589,7 +591,7 @@ function ConsoleView({ session }: { session: DebugSession }) {
showContextMenu(e, [{ label: "Clear All", icon: "trash", run: () => clearConsole(session.id) }]);
}}
role="log"
aria-label="Debug console"
aria-label={tx("Debug console")}
tabIndex={0}
>
{(lines ?? []).map((l) => (
@@ -609,7 +611,7 @@ function ConsoleView({ session }: { session: DebugSession }) {
onKeyDown={onKeyDown}
placeholder={isLive(session) ? "Evaluate in the debug console" : "Session finished"}
disabled={!isLive(session)}
aria-label="Debug console input"
aria-label={tx("Debug console input")}
spellCheck={false}
autoComplete="off"
/>
+21 -9
Переглянути файл
@@ -458,7 +458,11 @@ function BreakpointsDialog() {
{r.bp.line != null ? `:${r.bp.line + 1}` : ""}
</span>
)}
{st && !st.verified && isLive(activeSession()) && <span className={styles.bpCond}>unverified</span>}
{st && !st.verified && isLive(activeSession()) && (
<span className={styles.bpCond}>
<T>unverified</T>
</span>
)}
</div>
);
}
@@ -486,7 +490,11 @@ function BreakpointsDialog() {
</span>
<span className={styles.bpDir}>{relativePath(root, r.path)}</span>
{isConditional(r.bp) && <span className={styles.bpCond}>{suspends(r.bp) ? "if" : "log"}</span>}
{r.bp.temporary && <span className={styles.bpCond}>temp</span>}
{r.bp.temporary && (
<span className={styles.bpCond}>
<T>temp</T>
</span>
)}
</div>
);
}}
@@ -514,7 +522,7 @@ function ExceptionBreakpoints({ open }: { open: boolean }) {
if (open) void refreshExceptionFilters();
}, [open]);
return (
<section className={styles.exceptions} aria-label="Exception breakpoints">
<section className={styles.exceptions} aria-label={tx("Exception breakpoints")}>
<div className={styles.exceptionsTitle}>
<T>Exception Breakpoints</T>
</div>
@@ -564,7 +572,7 @@ function BreakpointDetail({ row, onGo }: { row: BpRow; onGo: () => void }) {
<T>Remove</T>
</Button>
</div>
{st && <div className={styles.statusLine}>{st.verified ? "Verified" : (st.message ?? "Not verified")}</div>}
{st && <div className={styles.statusLine}>{st.verified ? tx("Verified") : (st.message ?? "Not verified")}</div>}
<BreakpointFields path={path} bp={bp} />
<Checkbox
checked={!!bp.temporary}
@@ -595,7 +603,7 @@ function SpecialDetail({ bp, onGo }: { bp: SpecialBreakpoint; onGo: () => void }
<T>Remove</T>
</Button>
</div>
{st && <div className={styles.statusLine}>{st.verified ? "Verified" : (st.message ?? "Not verified")}</div>}
{st && <div className={styles.statusLine}>{st.verified ? tx("Verified") : (st.message ?? "Not verified")}</div>}
<Checkbox checked={bp.enabled} onChange={(enabled) => updateSpecial(bp.id, { enabled })} label="Enabled" />
{bp.kind === "method" ? (
<label className={styles.field}>
@@ -614,7 +622,7 @@ function SpecialDetail({ bp, onGo }: { bp: SpecialBreakpoint; onGo: () => void }
</label>
) : (
<>
<div className={styles.statusLine}>Watching {bp.dataId}</div>
<div className={styles.statusLine}>{tx`Watching ${bp.dataId}`}</div>
<label className={styles.field}>
<span className={styles.label}>
<T>Suspend on</T>
@@ -776,7 +784,7 @@ function EvaluateDialogInner({ initial }: { initial: string }) {
spellCheck={false}
autoComplete="off"
data-autofocus=""
aria-label="Expression"
aria-label={tx("Expression")}
placeholder={paused ? "Expression to evaluate in the selected frame" : "Pause the program to evaluate"}
/>
<span ref={historyButton}>
@@ -805,7 +813,7 @@ function EvaluateDialogInner({ initial }: { initial: string }) {
<VariablesView roots={[result]} session={session?.id ?? null} aria-label="Evaluation result" />
) : (
<div className={styles.empty}>
{paused ? "Press Enter to evaluate" : "Evaluation is available while the program is suspended"}
{paused ? tx("Press Enter to evaluate") : tx("Evaluation is available while the program is suspended")}
</div>
)}
</div>
@@ -938,7 +946,11 @@ function AttachPopup() {
focusable={false}
aria-label="Processes"
className={styles.attachList}
empty={<div className={styles.empty}>No attachable processes{filter ? " match the filter" : ""}.</div>}
empty={
<div className={styles.empty}>
{filter ? tx`No attachable processes match the filter.` : tx`No attachable processes.`}
</div>
}
renderItem={(r) =>
r.kind === "process" ? (
<div className={styles.chooserRow} title={r.process.commandLine}>