Complete client UI i18n migration

Adds client-side i18n support, language settings, translated UI copy, and locale parity coverage.
This commit is contained in:
chyendongnhanh338
2026-06-11 14:15:35 +08:00
committed by GitHub
parent 41cf070fd8
commit 08ebe5e7e1
199 changed files with 16426 additions and 1821 deletions
@@ -1,4 +1,5 @@
import { useCallback, useMemo } from "react";
import { useTranslation } from "react-i18next";
import { useSessionStore, type AgentFileExplorerState } from "@/stores/session-store";
import { explorerFileFromReadResult } from "@/file-explorer/read-result";
@@ -51,6 +52,7 @@ export function buildWorkspaceExplorerStateKey(scope: FileExplorerWorkspaceScope
}
export function useFileExplorerActions(params: { serverId: string } & FileExplorerWorkspaceScope) {
const { t } = useTranslation();
const { serverId, workspaceId, workspaceRoot } = params;
const client = useSessionStore((state) => state.sessions[serverId]?.client ?? null);
const setFileExplorer = useSessionStore((state) => state.setFileExplorer);
@@ -114,7 +116,7 @@ export function useFileExplorerActions(params: { serverId: string } & FileExplor
updateExplorerState((state) => ({
...state,
isLoading: false,
lastError: "Workspace is unavailable",
lastError: t("workspace.fileExplorer.states.unavailable"),
pendingRequest: null,
}));
return false;
@@ -124,7 +126,7 @@ export function useFileExplorerActions(params: { serverId: string } & FileExplor
updateExplorerState((state) => ({
...state,
isLoading: false,
lastError: "Host is not connected",
lastError: t("workspace.terminal.hostDisconnected"),
pendingRequest: null,
}));
return false;
@@ -153,13 +155,16 @@ export function useFileExplorerActions(params: { serverId: string } & FileExplor
updateExplorerState((state) => ({
...state,
isLoading: false,
lastError: error instanceof Error ? error.message : "Failed to list directory",
lastError:
error instanceof Error
? error.message
: t("workspace.fileExplorer.errors.failedToListDirectory"),
pendingRequest: null,
}));
return false;
}
},
[client, normalizedWorkspaceRoot, updateExplorerState, workspaceStateKey],
[client, normalizedWorkspaceRoot, t, updateExplorerState, workspaceStateKey],
);
const requestFilePreview = useCallback(
@@ -179,7 +184,7 @@ export function useFileExplorerActions(params: { serverId: string } & FileExplor
updateExplorerState((state) => ({
...state,
isLoading: false,
lastError: "Workspace is unavailable",
lastError: t("workspace.fileExplorer.states.unavailable"),
pendingRequest: null,
}));
return;
@@ -189,7 +194,7 @@ export function useFileExplorerActions(params: { serverId: string } & FileExplor
updateExplorerState((state) => ({
...state,
isLoading: false,
lastError: "Host is not connected",
lastError: t("workspace.terminal.hostDisconnected"),
pendingRequest: null,
}));
return;
@@ -218,21 +223,21 @@ export function useFileExplorerActions(params: { serverId: string } & FileExplor
updateExplorerState((state) => ({
...state,
isLoading: false,
lastError: error instanceof Error ? error.message : "Failed to load file preview",
lastError: error instanceof Error ? error.message : t("panels.file.failedToLoadPreview"),
pendingRequest: null,
}));
}
},
[client, normalizedWorkspaceRoot, updateExplorerState, workspaceStateKey],
[client, normalizedWorkspaceRoot, t, updateExplorerState, workspaceStateKey],
);
const requestFileDownloadToken = useCallback(
async (path: string) => {
if (!normalizedWorkspaceRoot) {
throw new Error("Workspace is unavailable");
throw new Error(t("workspace.fileExplorer.states.unavailable"));
}
if (!client) {
throw new Error("Host is not connected");
throw new Error(t("workspace.terminal.hostDisconnected"));
}
const payload = await client.requestDownloadToken(normalizedWorkspaceRoot, path);
if (payload.error) {
@@ -240,7 +245,7 @@ export function useFileExplorerActions(params: { serverId: string } & FileExplor
}
return payload;
},
[client, normalizedWorkspaceRoot],
[client, normalizedWorkspaceRoot, t],
);
const selectExplorerEntry = useCallback(