diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json index 88e6bd6f..cca6c3e9 100644 --- a/public/locales/en/translation.json +++ b/public/locales/en/translation.json @@ -280,6 +280,25 @@ }, "tunnels": { "title": "SSH Tunnels", + "connected": "Connected", + "disconnected": "Disconnected", + "connecting": "Connecting...", + "disconnecting": "Disconnecting...", + "unknown": "Unknown", + "error": "Error", + "failed": "Failed", + "retrying": "Retrying", + "waiting": "Waiting", + "waitingForRetry": "Waiting for retry", + "retryingConnection": "Retrying connection", + "canceling": "Canceling...", + "connect": "Connect", + "disconnect": "Disconnect", + "cancel": "Cancel", + "port": "Port", + "attempt": "Attempt {{current}} of {{max}}", + "nextRetryIn": "Next retry in {{seconds}} seconds", + "checkDockerLogs": "Check your Docker logs for the error reason, join the", "addTunnel": "Add Tunnel", "editTunnel": "Edit Tunnel", "deleteTunnel": "Delete Tunnel", diff --git a/public/locales/zh/translation.json b/public/locales/zh/translation.json index f056d253..6502e255 100644 --- a/public/locales/zh/translation.json +++ b/public/locales/zh/translation.json @@ -280,6 +280,25 @@ }, "tunnels": { "title": "SSH 隧道", + "connected": "已连接", + "disconnected": "已断开", + "connecting": "连接中...", + "disconnecting": "断开中...", + "unknown": "未知", + "error": "错误", + "failed": "失败", + "retrying": "重试中", + "waiting": "等待中", + "waitingForRetry": "等待重试", + "retryingConnection": "重试连接", + "canceling": "取消中...", + "connect": "连接", + "disconnect": "断开连接", + "cancel": "取消", + "port": "端口", + "attempt": "第 {{current}} 次尝试,共 {{max}} 次", + "nextRetryIn": "{{seconds}} 秒后重试", + "checkDockerLogs": "查看 Docker 日志以了解错误原因,加入", "addTunnel": "添加隧道", "editTunnel": "编辑隧道", "deleteTunnel": "删除隧道", diff --git a/src/ui/Apps/Tunnel/TunnelObject.tsx b/src/ui/Apps/Tunnel/TunnelObject.tsx index 8daf97b9..13c5f4d4 100644 --- a/src/ui/Apps/Tunnel/TunnelObject.tsx +++ b/src/ui/Apps/Tunnel/TunnelObject.tsx @@ -2,6 +2,7 @@ import React from "react"; import {Button} from "@/components/ui/button.tsx"; import {Card, CardContent, CardHeader, CardTitle} from "@/components/ui/card.tsx"; import {Separator} from "@/components/ui/separator.tsx"; +import {useTranslation} from 'react-i18next'; import { Loader2, Pin, @@ -87,6 +88,7 @@ export function TunnelObject({ compact = false, bare = false }: SSHTunnelObjectProps): React.ReactElement { + const {t} = useTranslation(); const getTunnelStatus = (tunnelIndex: number): TunnelStatus | undefined => { const tunnel = host.tunnelConnections[tunnelIndex]; @@ -97,7 +99,7 @@ export function TunnelObject({ const getTunnelStatusDisplay = (status: TunnelStatus | undefined) => { if (!status) return { icon: , - text: 'Unknown', + text: t('tunnels.unknown'), color: 'text-muted-foreground', bgColor: 'bg-muted/50', borderColor: 'border-border' @@ -109,7 +111,7 @@ export function TunnelObject({ case 'CONNECTED': return { icon: , - text: 'Connected', + text: t('tunnels.connected'), color: 'text-green-600 dark:text-green-400', bgColor: 'bg-green-500/10 dark:bg-green-400/10', borderColor: 'border-green-500/20 dark:border-green-400/20' @@ -117,7 +119,7 @@ export function TunnelObject({ case 'CONNECTING': return { icon: , - text: 'Connecting...', + text: t('tunnels.connecting'), color: 'text-blue-600 dark:text-blue-400', bgColor: 'bg-blue-500/10 dark:bg-blue-400/10', borderColor: 'border-blue-500/20 dark:border-blue-400/20' @@ -125,7 +127,7 @@ export function TunnelObject({ case 'DISCONNECTING': return { icon: , - text: 'Disconnecting...', + text: t('tunnels.disconnecting'), color: 'text-orange-600 dark:text-orange-400', bgColor: 'bg-orange-500/10 dark:bg-orange-400/10', borderColor: 'border-orange-500/20 dark:border-orange-400/20' @@ -133,7 +135,7 @@ export function TunnelObject({ case 'DISCONNECTED': return { icon: , - text: 'Disconnected', + text: t('tunnels.disconnected'), color: 'text-muted-foreground', bgColor: 'bg-muted/30', borderColor: 'border-border' @@ -149,7 +151,7 @@ export function TunnelObject({ case 'FAILED': return { icon: , - text: status.reason || 'Error', + text: status.reason || t('tunnels.error'), color: 'text-red-600 dark:text-red-400', bgColor: 'bg-red-500/10 dark:bg-red-400/10', borderColor: 'border-red-500/20 dark:border-red-400/20' @@ -193,7 +195,7 @@ export function TunnelObject({
- Port {tunnel.sourcePort} → {tunnel.endpointHost}:{tunnel.endpointPort} + {t('tunnels.port')} {tunnel.sourcePort} → {tunnel.endpointHost}:{tunnel.endpointPort}
{statusDisplay.text} @@ -212,7 +214,7 @@ export function TunnelObject({ className="h-7 px-2 text-red-600 dark:text-red-400 border-red-500/30 dark:border-red-400/30 hover:bg-red-500/10 dark:hover:bg-red-400/10 hover:border-red-500/50 dark:hover:border-red-400/50 text-xs" > - Disconnect + {t('tunnels.disconnect')} ) : isRetrying || isWaiting ? ( @@ -223,7 +225,7 @@ export function TunnelObject({ className="h-7 px-2 text-orange-600 dark:text-orange-400 border-orange-500/30 dark:border-orange-400/30 hover:bg-orange-500/10 dark:hover:bg-orange-400/10 hover:border-orange-500/50 dark:hover:border-orange-400/50 text-xs" > - Cancel + {t('tunnels.cancel')} ) : ( )}
@@ -255,13 +257,13 @@ export function TunnelObject({ {(statusValue === 'ERROR' || statusValue === 'FAILED') && status?.reason && (
-
Error:
+
{t('tunnels.error')}:
{status.reason} {status.reason && status.reason.includes('Max retries exhausted') && ( <>
- Check your Docker logs for the error reason, join the Discord or @@ -280,12 +282,12 @@ export function TunnelObject({
- {statusValue === 'WAITING' ? 'Waiting for retry' : 'Retrying connection'} + {statusValue === 'WAITING' ? t('tunnels.waitingForRetry') : t('tunnels.retryingConnection')}
- Attempt {status.retryCount} of {status.maxRetries} + {t('tunnels.attempt', { current: status.retryCount, max: status.maxRetries })} {status.nextRetryIn && ( - • Next retry in {status.nextRetryIn} seconds + • {t('tunnels.nextRetryIn', { seconds: status.nextRetryIn })} )}
@@ -373,7 +375,7 @@ export function TunnelObject({
- Port {tunnel.sourcePort} → {tunnel.endpointHost}:{tunnel.endpointPort} + {t('tunnels.port')} {tunnel.sourcePort} → {tunnel.endpointHost}:{tunnel.endpointPort}
{statusDisplay.text} @@ -392,7 +394,7 @@ export function TunnelObject({ className="h-7 px-2 text-red-600 dark:text-red-400 border-red-500/30 dark:border-red-400/30 hover:bg-red-500/10 dark:hover:bg-red-400/10 hover:border-red-500/50 dark:hover:border-red-400/50 text-xs" > - Disconnect + {t('tunnels.disconnect')} ) : isRetrying || isWaiting ? ( @@ -403,7 +405,7 @@ export function TunnelObject({ className="h-7 px-2 text-orange-600 dark:text-orange-400 border-orange-500/30 dark:border-orange-400/30 hover:bg-orange-500/10 dark:hover:bg-orange-400/10 hover:border-orange-500/50 dark:hover:border-orange-400/50 text-xs" > - Cancel + {t('tunnels.cancel')} ) : ( )}
@@ -436,13 +438,13 @@ export function TunnelObject({ {(statusValue === 'ERROR' || statusValue === 'FAILED') && status?.reason && (
-
Error:
+
{t('tunnels.error')}:
{status.reason} {status.reason && status.reason.includes('Max retries exhausted') && ( <>
- Check your Docker logs for the error reason, join the Discord or @@ -461,12 +463,12 @@ export function TunnelObject({
- {statusValue === 'WAITING' ? 'Waiting for retry' : 'Retrying connection'} + {statusValue === 'WAITING' ? t('tunnels.waitingForRetry') : t('tunnels.retryingConnection')}
- Attempt {status.retryCount} of {status.maxRetries} + {t('tunnels.attempt', { current: status.retryCount, max: status.maxRetries })} {status.nextRetryIn && ( - • Next retry in {status.nextRetryIn} seconds + • {t('tunnels.nextRetryIn', { seconds: status.nextRetryIn })} )}