fix: translate hardcoded toasts and drop em dashes from ui text

This commit is contained in:
LukeGus committed 2026-09-30 14:25:51 -05:00
1 parent 3c66931245
commit 1b342322dc
17 files changed
+89 -52

No files matched your search

+15 -9
View File
@@ -72,6 +72,7 @@
"rename": "Rename",
"uploading": "Uploading...",
"uploadingFile": "Uploading {{name}}...",
"uploadingChunk": "Uploading {{name}}: {{percent}}% (part {{chunk}} of {{total}})",
"fileName": "File Name",
"folderName": "Folder Name",
"fileUploadedSuccessfully": "File \"{{name}}\" uploaded successfully",
@@ -373,7 +374,12 @@
"dragMovedItems_one": "Moved {{count}} item to {{target}}",
"dragMovedItems_other": "Moved {{count}} items to {{target}}",
"moveBackFileFailed": "Could not move {{name}} back: {{error}}",
"terminal": "Terminal: {{host}} ({{path}})"
"terminal": "Terminal: {{host}} ({{path}})",
"dragToDesktop": "Dragging {{name}} to the desktop",
"dragFilesToDesktop": "Dragging {{count}} files to the desktop",
"folderDragUnsupported": "Dragging folders to the desktop is not supported yet",
"saveToDesktopFailed": "Save failed: {{error}}",
"dragFailedDetail": "Drag failed: {{error}}"
},
"sftpTransfer": {
"title": "SFTP",
@@ -454,7 +460,7 @@
"destinationPath": "Destination path",
"destMustBeDirectory": "Destination must be a directory for multi-item transfers",
"goUp": "Go up",
"hostAuthRequired": "Authentication required — open File Manager on this host first",
"hostAuthRequired": "Authentication required. Open File Manager on this host first",
"hostConnecting": "Connecting…",
"hostConnectionFailed": "Connection failed",
"hostDisconnected": "Not connected",
@@ -475,12 +481,12 @@
"methodReason": {
"user_item_sftp": "You chose per-file SFTP.",
"user_tar": "You chose tar archive.",
"tar_unavailable": "Tar is not available on one or both hosts — per-file SFTP will be used instead.",
"windows_host": "A Windows host is involved — tar is not used.",
"auto_multi_large": "Auto: multiple files including a large file ({{largestSize}}) with compressible data — tar bundles into one transfer.",
"auto_single_large_in_archive": "Auto: one large file ({{largestSize}}) in this set — per-file SFTP.",
"auto_many_incompressible": "Auto: mostly incompressible data — per-file SFTP.",
"auto_many_files": "Auto: many files ({{fileCount}}) — tar reduces per-file overhead.",
"tar_unavailable": "Tar is not available on one or both hosts, so per-file SFTP will be used instead.",
"windows_host": "A Windows host is involved, so tar is not used.",
"auto_multi_large": "Auto: multiple files including a large file ({{largestSize}}) with compressible data. Tar bundles them into one transfer.",
"auto_single_large_in_archive": "Auto: one large file ({{largestSize}}) in this set, so per-file SFTP.",
"auto_many_incompressible": "Auto: mostly incompressible data, so per-file SFTP.",
"auto_many_files": "Auto: many files ({{fileCount}}), tar cuts the per-file overhead.",
"auto_default": "Auto: per-file SFTP for this set."
},
"methodTar": "Tar archive",
@@ -488,7 +494,7 @@
"metricsCompress": "Compress on source: {{duration}}",
"metricsExtract": "Extract on destination: {{duration}}",
"metricsPrepare": "Prepare destination: {{duration}}",
"metricsRouteBenchmark": "Route probe — direct: {{direct}}, relay: {{relay}}",
"metricsRouteBenchmark": "Route probe: direct {{direct}}, relay {{relay}}",
"metricsSourceDelete": "Remove from source: {{duration}}",
"metricsTotal": "Total: {{duration}}",
"metricsTransfer": "End-to-end: {{throughput}} ({{duration}})",
@@ -12,7 +12,7 @@ export class TransferStalledError extends Error {
constructor(byteOffset?: number, segmentIndex?: number) {
const pos = byteOffset !== undefined ? ` at byte offset ${byteOffset}` : "";
const seg = segmentIndex !== undefined ? ` (segment ${segmentIndex})` : "";
super(`Transfer stalled — no data moved for 45 seconds${pos}${seg}`);
super(`Transfer stalled: no data moved for 45 seconds${pos}${seg}`);
this.name = "TransferStalledError";
this.byteOffset = byteOffset;
this.segmentIndex = segmentIndex;
@@ -1345,7 +1345,12 @@ function FileManagerContent({
Math.round((p.bytesSent / p.totalBytes) * 100),
);
toast.loading(
`Uploading ${file.name} — ${percent}% (chunk ${p.chunkIndex + 1}/${p.totalChunks})`,
t("fileManager.uploadingChunk", {
name: file.name,
percent,
chunk: p.chunkIndex + 1,
total: p.totalChunks,
}),
{ id: progressToast, duration: Infinity, cancel },
);
};
@@ -216,9 +216,12 @@ export function FileWindow({
};
const errorData = err?.response?.data;
if (errorData?.tooLarge) {
toast.error(`File too large: ${errorData.error}`, {
duration: 10000,
});
toast.error(
t("fileManager.fileTooLarge", { error: errorData.error }),
{
duration: 10000,
},
);
} else if (
err.message?.includes("connection") ||
err.message?.includes("established")
@@ -102,7 +102,7 @@ function formatByteSize(bytes: number): string {
function formatTruncatedDestination(hostLabel: string, path: string): string {
const normalized = path.replace(/\\/g, "/").replace(/\/+$/, "") || "/";
if (normalized === "/") {
return `${hostLabel} — /`;
return `${hostLabel}: /`;
}
const segments = normalized.split("/").filter(Boolean);
@@ -111,7 +111,7 @@ function formatTruncatedDestination(hostLabel: string, path: string): string {
? `/${segments.join("/")}`
: `.../${segments.slice(-2).join("/")}`;
return `${hostLabel} — ${pathPart}`;
return `${hostLabel}: ${pathPart}`;
}
function longestCommonPrefix(strings: string[]): string {
@@ -1,5 +1,6 @@
import { useState, useCallback } from "react";
import { toast } from "sonner";
import { useTranslation } from "@termix/plugin-sdk/frontend";
import { downloadSSHFile } from "../api/ssh-file-operations-api";
import type { FileItem, SSHHost } from "../host-types";
@@ -22,6 +23,7 @@ interface DragToDesktopOptions {
}
export function useDragToDesktop({ sshSessionId }: UseDragToDesktopProps) {
const { t } = useTranslation();
const [state, setState] = useState<DragToDesktopState>({
isDragging: false,
isDownloading: false,
@@ -98,7 +100,7 @@ export function useDragToDesktop({ sshSessionId }: UseDragToDesktopProps) {
setState((prev) => ({ ...prev, progress: 100 }));
if (enableToast) {
toast.success(`Dragging ${file.name} to desktop`);
toast.success(t("fileManager.dragToDesktop", { name: file.name }));
}
onSuccess?.();
@@ -128,7 +130,9 @@ export function useDragToDesktop({ sshSessionId }: UseDragToDesktopProps) {
}));
if (enableToast) {
toast.error(`Drag failed: ${errorMessage}`);
toast.error(
t("fileManager.dragFailedDetail", { error: errorMessage }),
);
}
onError?.(errorMessage);
@@ -209,7 +213,9 @@ export function useDragToDesktop({ sshSessionId }: UseDragToDesktopProps) {
setState((prev) => ({ ...prev, progress: 100 }));
if (enableToast) {
toast.success(`Dragging ${fileList.length} files to desktop`);
toast.success(
t("fileManager.dragFilesToDesktop", { count: fileList.length }),
);
}
onSuccess?.();
@@ -238,7 +244,9 @@ export function useDragToDesktop({ sshSessionId }: UseDragToDesktopProps) {
}));
if (enableToast) {
toast.error(`Batch drag failed: ${errorMessage}`);
toast.error(
t("fileManager.dragFailedDetail", { error: errorMessage }),
);
}
onError?.(errorMessage);
@@ -268,7 +276,7 @@ export function useDragToDesktop({ sshSessionId }: UseDragToDesktopProps) {
}
if (enableToast) {
toast.info("Folder drag functionality is under development...");
toast.info(t("fileManager.folderDragUnsupported"));
}
return false;
@@ -1,6 +1,7 @@
/* eslint-disable react-hooks/exhaustive-deps */
import { useState, useCallback, useRef } from "react";
import { toast } from "sonner";
import { useTranslation } from "@termix/plugin-sdk/frontend";
import { downloadSSHFile } from "../api/ssh-file-operations-api";
import type { FileItem, SSHHost } from "../host-types";
@@ -23,6 +24,7 @@ interface DragToSystemOptions {
}
export function useDragToSystemDesktop({ sshSessionId }: UseDragToSystemProps) {
const { t } = useTranslation();
const [state, setState] = useState<DragToSystemState>({
isDragging: false,
isDownloading: false,
@@ -250,7 +252,9 @@ export function useDragToSystemDesktop({ sshSessionId }: UseDragToSystemProps) {
}));
if (enableToast) {
toast.error(`Save failed: ${errorMessage}`);
toast.error(
t("fileManager.saveToDesktopFailed", { error: errorMessage }),
);
}
onError?.(errorMessage);
+2 -2
View File
@@ -110,8 +110,8 @@
"hostNotFound": "Host not found",
"loadingHost": "Loading host...",
"none": "None",
"proxmoxGuestsSelected_one": "{{count}} guest — {{selected}} selected",
"proxmoxGuestsSelected_other": "{{count}} guests — {{selected}} selected",
"proxmoxGuestsSelected_one": "{{count}} guest, {{selected}} selected",
"proxmoxGuestsSelected_other": "{{count}} guests, {{selected}} selected",
"proxmoxImportButton_one": "Import {{count}} host",
"proxmoxImportButton_other": "Import {{count}} hosts"
},
+5 -1
View File
@@ -81,7 +81,11 @@
"clipboardWriteFailed": "Failed to copy to clipboard. Make sure the page is served over HTTPS or localhost.",
"connected": "Connected",
"totpCodeLabel": "Verification Code",
"duplicateTab": "Duplicate tab"
"duplicateTab": "Duplicate tab",
"imageChooseFile": "Choose an image file",
"imageUploaded": "Image uploaded: {{path}}",
"imageClipboardUnavailable": "This browser cannot read images from the clipboard",
"imageClipboardEmpty": "No image found in the clipboard"
},
"terminalToolbar": {
"detachTmux": "Detach tmux",
@@ -3523,7 +3523,7 @@ const TerminalInner = forwardRef<TerminalHandle, SSHTerminalProps>(
source: TerminalImageUploadSource,
) {
if (file.type && !file.type.startsWith("image/")) {
toast.error("Choose an image file");
toast.error(t("terminal.imageChooseFile"));
return;
}
setIsImageUploading(true);
@@ -3548,7 +3548,7 @@ const TerminalInner = forwardRef<TerminalHandle, SSHTerminalProps>(
data: quoteTerminalImagePath(shellPath),
}),
);
toast.success(`Image uploaded: ${shellPath}`);
toast.success(t("terminal.imageUploaded", { path: shellPath }));
} else {
toast.warning(
`Image uploaded, but the terminal was not available to paste it: ${shellPath}`,
@@ -3567,7 +3567,7 @@ const TerminalInner = forwardRef<TerminalHandle, SSHTerminalProps>(
async function handleClipboardImage() {
if (!navigator.clipboard?.read) {
toast.error("Clipboard image access is not available in this browser");
toast.error(t("terminal.imageClipboardUnavailable"));
return;
}
setIsImageUploading(true);
@@ -3619,7 +3619,7 @@ const TerminalInner = forwardRef<TerminalHandle, SSHTerminalProps>(
await handleImageUpload(clipboardFile, "clipboard");
return;
}
toast.error("No image found in the clipboard");
toast.error(t("terminal.imageClipboardEmpty"));
} catch (error) {
toast.error(getErrorMessage(error, "Clipboard read failed"));
} finally {
+3 -3
View File
@@ -73,7 +73,7 @@
"sessionRenameFailed": "Failed to rename session",
"editTagsTitle": "Edit tags for \"{{name}}\"",
"killPane": "Kill pane",
"resizeTree": "Drag to resize — double-click to reset",
"resizeTree": "Drag to resize, double-click to reset",
"reattach": "Re-attach (fixes a garbled view)",
"killWindow": "Kill window",
"killWindowTitle": "Kill window {{index}} of \"{{session}}\"?",
@@ -93,14 +93,14 @@
"sessionKillFailed": "Failed to kill session",
"hostUnreachable": "Could not connect to the host. Check that it is online and reachable.",
"noServer": "No tmux server is running on this host.",
"searchTruncated": "Partial results — search covers the last {{lines}} lines of each pane and at most {{panes}} panes.",
"searchTruncated": "Partial results. Search covers the last {{lines}} lines of each pane and at most {{panes}} panes.",
"closeSearchResults": "Close search results",
"retry": "Retry",
"noHosts": "No SSH hosts available",
"noHostsHint": "Enable the Tmux Monitor option on an SSH host (Host Manager, Tmux Monitor tab) to monitor its tmux sessions.",
"tmuxInstallHint": "Install it on the host with:",
"attachTooltip": "Open a terminal to {{host}}",
"attachTooltipPane": "Open a terminal to {{host}} — tmux session {{session}}",
"attachTooltipPane": "Open a terminal to {{host}}, tmux session {{session}}",
"timeJustNow": "just now",
"timeMinutes": "{{count}}m ago",
"timeHours": "{{count}}h ago",