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

+6 -4
Переглянути файл
@@ -19,9 +19,11 @@ import { openLocation } from "./ipc";
import {
ROOT_ID,
directionLabel,
hierarchyTitle,
hierarchyTarget,
loadChildren,
refreshHierarchy,
noneFoundLabel,
setDirection,
useHierarchy,
type HierarchyNode,
@@ -56,7 +58,7 @@ export function HierarchyTabs() {
const direction = useHierarchy((s) => s.direction);
const root = useHierarchy((s) => s.root);
if (!root) return null;
const label = `${directionLabel(mode, direction)} of ${root.name}`;
const label = hierarchyTitle(mode, direction, root.name);
return (
<Tabs
variant="compact"
@@ -74,7 +76,7 @@ function HierarchyToolbar() {
const direction = useHierarchy((s) => s.direction);
const autoscroll = useHierarchyOptions((s) => s.autoscroll);
return (
<div className={styles.toolbar} role="toolbar" aria-label="Hierarchy actions">
<div className={styles.toolbar} role="toolbar" aria-label={tx("Hierarchy actions")}>
<IconButton
icon="arrow-up"
size="small"
@@ -165,7 +167,7 @@ export function HierarchyView() {
</span>
)}
{!loading && !failed.has(ROOT_ID) && children.get(ROOT_ID)?.length === 0 && (
<span className={styles.muted}>— no {directionLabel(mode, direction).toLowerCase()} found</span>
<span className={styles.muted}>{noneFoundLabel(mode, direction)}</span>
)}
</span>
);
@@ -180,7 +182,7 @@ export function HierarchyView() {
<span className={styles.muted}>
{basename(item.path)}:{item.selectionRange.start.line + 1}
</span>
{calls > 1 && <span className={styles.muted}>({calls} calls)</span>}
{calls > 1 && <span className={styles.muted}>{tx`(${calls} calls)`}</span>}
{failed.has(n.id) && (
<span className={styles.error}>
<T>failed to load</T>
+7 -5
Переглянути файл
@@ -16,6 +16,7 @@ import { openLocation, readFileLines } from "./ipc";
import { showUsageResults, usageCount, useUsagesPopup, type Usage, type UsageGroup } from "./usages";
import { UsagePreview } from "./UsagesView";
import styles from "./UsagesPopup.module.css";
import { tx } from "@/platform/i18n";
const close = () => useUsagesPopup.setState({ open: false });
@@ -118,8 +119,8 @@ function UsagesPopupInner() {
<div className={styles.focus} tabIndex={0} data-autofocus onKeyDown={onKeyDown}>
<div className={styles.header}>
<span className={styles.title}>
Usages{symbol ? ` of ${symbol}` : ""}{" "}
<span className={styles.count}>{filter ? `${items.length} of ${total}` : total} found</span>
{symbol ? tx`Usages of ${symbol}` : tx("Usages")}{" "}
<span className={styles.count}>{filter ? tx`${items.length} of ${total} found` : tx`${total} found`}</span>
</span>
{filter && (
<span className={clsx(styles.filter, !items.length && styles.noMatch)} role="status">
@@ -135,7 +136,8 @@ function UsagesPopupInner() {
onClick={() => setUsagesPopupPreview(!preview)}
/>
<button type="button" className={styles.link} onClick={openInFindWindow}>
Open in Find Window{keys ? ` ${keys}` : ""}
{tx("Open in Find Window")}
{keys ? ` ${keys}` : ""}
</button>
</div>
{note && <div className={styles.note}>{note}</div>}
@@ -150,7 +152,7 @@ function UsagesPopupInner() {
rowHeight={ROW}
aria-label="Usages"
onActivate={pick}
empty={<div className={styles.empty}>Nothing matches '{filter}'</div>}
empty={<div className={styles.empty}>{tx`Nothing matches '${filter}'`}</div>}
renderItem={(u) => (
<div className={styles.row}>
<Icon name={fileIconName(basename(u.path))} size={14} className={styles.icon} />
@@ -234,7 +236,7 @@ function UsageCodePreview({ usage }: { usage: Usage | null }) {
}, [usage, loaded]);
return (
<div className={styles.preview} role="region" aria-label="Preview">
<div className={styles.preview} role="region" aria-label={tx("Preview")}>
<div ref={host} className={clsx(styles.previewEditor, loaded !== path && styles.previewHidden)} />
</div>
);
+15 -2
Переглянути файл
@@ -5,6 +5,7 @@ import { IpcError, call, commands } from "@/platform/ipc";
import { toolWindowService } from "@/workbench/contributions";
import { basename } from "@/platform/project";
import { caretContext, hint, lspRequest, reportError, withDocument, type CaretContext } from "./ipc";
import { tx } from "@/platform/i18n";
export type HierarchyMode = "call" | "type";
@@ -56,9 +57,21 @@ export function resetHierarchy() {
}));
}
/** The empty-result line of the hierarchy tree. */
export function noneFoundLabel(mode: HierarchyMode, direction: HierarchyDirection): string {
if (mode === "call") return direction === "incoming" ? tx`— no callers found` : tx`— no callees found`;
return direction === "incoming" ? tx`— no supertypes found` : tx`— no subtypes found`;
}
export function directionLabel(mode: HierarchyMode, direction: HierarchyDirection): string {
if (mode === "call") return direction === "incoming" ? "Callers" : "Callees";
return direction === "incoming" ? "Supertypes" : "Subtypes";
if (mode === "call") return direction === "incoming" ? tx("Callers") : tx("Callees");
return direction === "incoming" ? tx("Supertypes") : tx("Subtypes");
}
/** The tab title of the hierarchy tree, e.g. "Callers of main". */
export function hierarchyTitle(mode: HierarchyMode, direction: HierarchyDirection, name: string): string {
if (mode === "call") return direction === "incoming" ? tx`Callers of ${name}` : tx`Callees of ${name}`;
return direction === "incoming" ? tx`Supertypes of ${name}` : tx`Subtypes of ${name}`;
}
function request(mode: HierarchyMode, doc: number, line: number, col: number, direction: HierarchyDirection) {