дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-09 11:15:40 +02:00
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]>
Цей коміт міститься в:
121 files changed
+854
-457
No files matched your search
@@ -225,7 +225,7 @@ export function ImportDialog({ id, schema, table }: { id: string; schema: string
|
||||
<T>Columns:</T>
|
||||
</span>
|
||||
<span className={styles.formHint}>
|
||||
{mapped.length ? mapped.join(", ") : "No column of the file matches the table"}
|
||||
{mapped.length ? mapped.join(", ") : tx("No column of the file matches the table")}
|
||||
</span>
|
||||
</div>
|
||||
{preview.length > 0 && (
|
||||
|
||||
@@ -148,7 +148,7 @@ export function DataView(props: DataViewProps) {
|
||||
/>
|
||||
{filter.size > 0 && (
|
||||
<div className={styles.filterPill} role="status">
|
||||
{shown} of {rowCount} rows
|
||||
{tx`${shown} of ${rowCount} rows`}
|
||||
<button type="button" className={styles.filterPillClear} onClick={() => setFilter(new Map())}>
|
||||
<T>Clear local filter</T>
|
||||
</button>
|
||||
@@ -219,7 +219,7 @@ function FilterPopup(props: {
|
||||
value={query}
|
||||
onChange={(e) => setQuery(e.target.value)}
|
||||
/>
|
||||
<div className={styles.filterValues} role="group" aria-label="Values">
|
||||
<div className={styles.filterValues} role="group" aria-label={tx("Values")}>
|
||||
{list.map(({ value: v, count }) => (
|
||||
<div key={v ?? "\u0000null"} className={styles.filterValue}>
|
||||
<Checkbox
|
||||
@@ -270,7 +270,7 @@ function SidePanel(props: {
|
||||
}) {
|
||||
const { range, value, columns } = props;
|
||||
return (
|
||||
<aside className={styles.sidePanel} aria-label="Value panel">
|
||||
<aside className={styles.sidePanel} aria-label={tx("Value panel")}>
|
||||
<div className={styles.sidePanelHead}>
|
||||
<Tabs
|
||||
variant="compact"
|
||||
|
||||
@@ -42,6 +42,7 @@ import {
|
||||
import { DB_VIEW_FOCUS, openTableData } from "./treeActions";
|
||||
import { newMenu, nodeMenu } from "./treeMenu";
|
||||
import styles from "./Database.module.css";
|
||||
import { tx } from "@/platform/i18n";
|
||||
|
||||
const GROUP_LABELS: Record<Group, string> = {
|
||||
columns: "columns",
|
||||
@@ -427,7 +428,7 @@ export function DatabaseView() {
|
||||
<span className={styles.nodeIcon}>
|
||||
<Icon name={i} size={16} />
|
||||
{/* IDEA: a green dot on the data source icon while connected. */}
|
||||
{live && <span className={styles.connectedDot} title="Connected" />}
|
||||
{live && <span className={styles.connectedDot} title={tx("Connected")} />}
|
||||
</span>
|
||||
)}
|
||||
<span className={labelClass}>{label(n)}</span>
|
||||
@@ -490,7 +491,7 @@ function DatabaseToolbar() {
|
||||
const active = !!target && [...connected].some((t) => splitTarget(t).id === splitTarget(target).id);
|
||||
const button = { size: "small", iconSize: 16 } as const;
|
||||
return (
|
||||
<div className={styles.dbToolbar} role="toolbar" aria-label="Database actions">
|
||||
<div className={styles.dbToolbar} role="toolbar" aria-label={tx("Database actions")}>
|
||||
<IconButton
|
||||
ref={plus}
|
||||
{...button}
|
||||
@@ -520,7 +521,7 @@ function DatabaseToolbar() {
|
||||
<button
|
||||
type="button"
|
||||
className={styles.textTool}
|
||||
aria-label="Go to DDL"
|
||||
aria-label={tx("Go to DDL")}
|
||||
disabled={!table}
|
||||
onClick={() => void executeAction("db.goToDdl")}
|
||||
{...tooltipAttrs("Go to DDL", shortcutLabel("db.goToDdl"))}
|
||||
|
||||
@@ -9,6 +9,7 @@ import clsx from "clsx";
|
||||
import { Icon, showContextMenu, type MenuItem } from "@/ui";
|
||||
import { toCsv, toTsv, type Cell } from "./model";
|
||||
import styles from "./Database.module.css";
|
||||
import { tx } from "@/platform/i18n";
|
||||
|
||||
export interface GridColumn {
|
||||
name: string;
|
||||
@@ -291,7 +292,7 @@ export function Grid(props: GridProps) {
|
||||
type="button"
|
||||
className={clsx(styles.headerFilter, props.filtered?.(ci) && styles.headerFilterOn)}
|
||||
aria-label={`Filter ${c.name}`}
|
||||
title="Local filter"
|
||||
title={tx("Local filter")}
|
||||
onMouseDown={(e) => e.stopPropagation()}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
|
||||
@@ -120,7 +120,7 @@ function RenameDialog({ id, object }: { id: string; object: DbObjectRef | null }
|
||||
>
|
||||
<div className={styles.dialogBody}>
|
||||
<label className={styles.formLabelLeft} htmlFor="db-rename">
|
||||
Rename {what} '{initial}' to:
|
||||
{tx`Rename ${what} '${initial}' to:`}
|
||||
</label>
|
||||
<Input
|
||||
id="db-rename"
|
||||
@@ -156,7 +156,8 @@ function DropDialog({ id, object }: { id: string; object: DbObjectRef }) {
|
||||
>
|
||||
<div className={styles.dialogBody}>
|
||||
<div className={styles.dialogLead}>
|
||||
Drop {KIND_LABEL[object.kind]} <strong>{reference(driver, object)}</strong>? This cannot be undone.
|
||||
{tx`Drop ${KIND_LABEL[object.kind]}`} <strong>{reference(driver, object)}</strong>
|
||||
{tx`? This cannot be undone.`}
|
||||
</div>
|
||||
<Checkbox
|
||||
checked={ifExists}
|
||||
@@ -387,7 +388,7 @@ function ModifyTableForm({
|
||||
onClick={remove}
|
||||
/>
|
||||
</div>
|
||||
<div role="listbox" aria-label="Columns" className={styles.modifyList}>
|
||||
<div role="listbox" aria-label={tx("Columns")} className={styles.modifyList}>
|
||||
{columns.map((c) => (
|
||||
<div
|
||||
key={c.key}
|
||||
@@ -521,7 +522,7 @@ function SourceUrlDialog() {
|
||||
/>
|
||||
<span className={styles.formHint}>
|
||||
{url.trim() && !parsed
|
||||
? "Not a URL of PostgreSQL, MySQL, SQLite or a compatible database"
|
||||
? tx("Not a URL of PostgreSQL, MySQL, SQLite or a compatible database")
|
||||
: "postgresql://, mysql://, mariadb://, redshift://, tidb://…, jdbc:…, sqlite:path"}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
type ResultTab,
|
||||
} from "./store";
|
||||
import styles from "./Database.module.css";
|
||||
import { tx } from "@/platform/i18n";
|
||||
|
||||
function time(t: number): string {
|
||||
const d = new Date(t);
|
||||
@@ -44,7 +45,7 @@ function Output() {
|
||||
<span className={styles.spacer} />
|
||||
<IconButton icon="trash" title="Clear All" disabled={!lines.length} onClick={clearOutput} />
|
||||
</div>
|
||||
<div ref={ref} className={styles.output} role="log" aria-label="Database output">
|
||||
<div ref={ref} className={styles.output} role="log" aria-label={tx("Database output")}>
|
||||
{lines.map((l: OutputLine) => (
|
||||
<div key={l.id} className={clsx(styles.outputLine, l.kind === "error" && styles.outputError)}>
|
||||
<span className={styles.outputTime}>[{time(l.time)}]</span>{" "}
|
||||
@@ -115,8 +116,8 @@ function Result({ tab }: { tab: ResultTab }) {
|
||||
aria-label={tab.title}
|
||||
/>
|
||||
<div className={styles.rowPill} role="status" title={outcomeSummary(tab.outcome)}>
|
||||
{r.rows.length} row{r.rows.length === 1 ? "" : "s"}
|
||||
{r.hasMore ? " (limit reached)" : ""}
|
||||
{r.rows.length === 1 ? tx`${r.rows.length} row` : tx`${r.rows.length} rows`}
|
||||
{r.hasMore ? ` ${tx("(limit reached)")}` : ""}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -208,7 +209,7 @@ function PlanResult({ tab }: { tab: ResultTab }) {
|
||||
<EmptyState title="Empty plan" />
|
||||
)}
|
||||
</div>
|
||||
<table className={styles.planProperties} aria-label="Plan node properties">
|
||||
<table className={styles.planProperties} aria-label={tx("Plan node properties")}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
|
||||
@@ -534,7 +534,7 @@ export function SourceDialog({
|
||||
{sshOn && (
|
||||
<>
|
||||
<span />
|
||||
<span className={styles.formHint}>Reached from the SSH host {sshLabel({ ssh: sshUsed })}.</span>
|
||||
<span className={styles.formHint}>{tx`Reached from the SSH host ${sshLabel({ ssh: sshUsed })}.`}</span>
|
||||
</>
|
||||
)}
|
||||
<label className={styles.formLabel} htmlFor="db-user">
|
||||
@@ -916,8 +916,10 @@ export function SourceDialog({
|
||||
</Button>
|
||||
<span className={styles.formHint}>
|
||||
{initial?.id
|
||||
? "The Database tree shows only the checked names and patterns (* and ?); the connected database always shows."
|
||||
: "Save the data source to pick from the server's names; patterns (* and ?) work any time."}
|
||||
? tx(
|
||||
"The Database tree shows only the checked names and patterns (* and ?); the connected database always shows.",
|
||||
)
|
||||
: tx("Save the data source to pick from the server's names; patterns (* and ?) work any time.")}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -297,7 +297,7 @@ export function TableEditor({ input }: { input: EditorInput }) {
|
||||
</div>
|
||||
{page && !editable && (
|
||||
<div className={styles.notice}>
|
||||
{pk.length ? "Read-only data source." : "Read-only: the table has no primary key to identify rows."}
|
||||
{pk.length ? tx("Read-only data source.") : tx("Read-only: the table has no primary key to identify rows.")}
|
||||
</div>
|
||||
)}
|
||||
{error ? (
|
||||
|
||||
Reference in new issue
Заблокувати користувача