diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json index 08267e20..88e6bd6f 100644 --- a/public/locales/en/translation.json +++ b/public/locales/en/translation.json @@ -100,6 +100,40 @@ }, "hosts": { "title": "Host Manager", + "sshHosts": "SSH Hosts", + "noHosts": "No SSH Hosts", + "noHostsMessage": "You haven't added any SSH hosts yet. Click \"Add Host\" to get started.", + "loadingHosts": "Loading hosts...", + "failedToLoadHosts": "Failed to load hosts", + "retry": "Retry", + "refresh": "Refresh", + "hostsCount": "{{count}} hosts", + "importJson": "Import JSON", + "importing": "Importing...", + "importJsonTitle": "Import SSH Hosts from JSON", + "importJsonDesc": "Upload a JSON file to bulk import multiple SSH hosts (max 100).", + "downloadSample": "Download Sample", + "formatGuide": "Format Guide", + "uncategorized": "Uncategorized", + "confirmDelete": "Are you sure you want to delete \"{{name}}\"?", + "failedToDeleteHost": "Failed to delete host", + "jsonMustContainHosts": "JSON must contain a \"hosts\" array or be an array of hosts", + "noHostsInJson": "No hosts found in JSON file", + "maxHostsAllowed": "Maximum 100 hosts allowed per import", + "importCompleted": "Import completed: {{success}} successful, {{failed}} failed", + "importFailed": "Import failed", + "importError": "Import error", + "failedToImportJson": "Failed to import JSON file", + "connectionDetails": "Connection Details", + "organization": "Organization", + "ipAddress": "IP Address", + "port": "Port", + "hostName": "Host Name", + "folder": "Folder", + "tags": "Tags", + "passwordRequired": "Password is required when using password authentication", + "sshKeyRequired": "SSH Private Key is required when using key authentication", + "keyTypeRequired": "Key Type is required when using key authentication", "addHost": "Add Host", "editHost": "Edit Host", "deleteHost": "Delete Host", diff --git a/public/locales/zh/translation.json b/public/locales/zh/translation.json index e58e8d6e..f056d253 100644 --- a/public/locales/zh/translation.json +++ b/public/locales/zh/translation.json @@ -100,6 +100,40 @@ }, "hosts": { "title": "主机管理", + "sshHosts": "SSH 主机", + "noHosts": "没有 SSH 主机", + "noHostsMessage": "您还没有添加任何 SSH 主机。点击\"添加主机\"开始使用。", + "loadingHosts": "加载主机中...", + "failedToLoadHosts": "加载主机失败", + "retry": "重试", + "refresh": "刷新", + "hostsCount": "{{count}} 个主机", + "importJson": "导入 JSON", + "importing": "导入中...", + "importJsonTitle": "从 JSON 导入 SSH 主机", + "importJsonDesc": "上传 JSON 文件以批量导入多个 SSH 主机(最多 100 个)。", + "downloadSample": "下载示例", + "formatGuide": "格式指南", + "uncategorized": "未分类", + "confirmDelete": "确定要删除 \"{{name}}\" 吗?", + "failedToDeleteHost": "删除主机失败", + "jsonMustContainHosts": "JSON 必须包含 \"hosts\" 数组或是一个主机数组", + "noHostsInJson": "JSON 文件中未找到主机", + "maxHostsAllowed": "每次导入最多允许 100 个主机", + "importCompleted": "导入完成:{{success}} 个成功,{{failed}} 个失败", + "importFailed": "导入失败", + "importError": "导入错误", + "failedToImportJson": "导入 JSON 文件失败", + "connectionDetails": "连接详情", + "organization": "组织", + "ipAddress": "IP 地址", + "port": "端口", + "hostName": "主机名", + "folder": "文件夹", + "tags": "标签", + "passwordRequired": "使用密码认证时需要密码", + "sshKeyRequired": "使用密钥认证时需要 SSH 私钥", + "keyTypeRequired": "使用密钥认证时需要密钥类型", "addHost": "添加主机", "editHost": "编辑主机", "deleteHost": "删除主机", diff --git a/src/ui/Apps/File Manager/FileManagerOperations.tsx b/src/ui/Apps/File Manager/FileManagerOperations.tsx index 7ee2c441..4d71fc02 100644 --- a/src/ui/Apps/File Manager/FileManagerOperations.tsx +++ b/src/ui/Apps/File Manager/FileManagerOperations.tsx @@ -282,7 +282,7 @@ export function FileManagerOperations({

- {t('fileManager.uploadFileTitle')}} + {t('fileManager.uploadFileTitle')}

{t('fileManager.maxFileSize')} diff --git a/src/ui/Apps/Host Manager/HostManagerHostEditor.tsx b/src/ui/Apps/Host Manager/HostManagerHostEditor.tsx index fc05ba61..593cba0d 100644 --- a/src/ui/Apps/Host Manager/HostManagerHostEditor.tsx +++ b/src/ui/Apps/Host Manager/HostManagerHostEditor.tsx @@ -129,7 +129,7 @@ export function HostManagerHostEditor({editingHost, onFormSubmit}: SSHManagerHos if (!data.password || data.password.trim() === '') { ctx.addIssue({ code: z.ZodIssueCode.custom, - message: "Password is required when using password authentication", + message: t('hosts.passwordRequired'), path: ['password'] }); } @@ -137,14 +137,14 @@ export function HostManagerHostEditor({editingHost, onFormSubmit}: SSHManagerHos if (!data.key) { ctx.addIssue({ code: z.ZodIssueCode.custom, - message: "SSH Private Key is required when using key authentication", + message: t('hosts.sshKeyRequired'), path: ['key'] }); } if (!data.keyType) { ctx.addIssue({ code: z.ZodIssueCode.custom, - message: "Key Type is required when using key authentication", + message: t('hosts.keyTypeRequired'), path: ['keyType'] }); } diff --git a/src/ui/Apps/Host Manager/HostManagerHostViewer.tsx b/src/ui/Apps/Host Manager/HostManagerHostViewer.tsx index 97cd1022..ae8d1281 100644 --- a/src/ui/Apps/Host Manager/HostManagerHostViewer.tsx +++ b/src/ui/Apps/Host Manager/HostManagerHostViewer.tsx @@ -7,6 +7,7 @@ import {Input} from "@/components/ui/input"; import {Accordion, AccordionContent, AccordionItem, AccordionTrigger} from "@/components/ui/accordion"; import {Tooltip, TooltipContent, TooltipProvider, TooltipTrigger} from "@/components/ui/tooltip"; import {getSSHHosts, deleteSSHHost, bulkImportSSHHosts} from "@/ui/main-axios.ts"; +import {useTranslation} from "react-i18next"; import { Edit, Trash2, @@ -47,6 +48,7 @@ interface SSHManagerHostViewerProps { } export function HostManagerHostViewer({onEditHost}: SSHManagerHostViewerProps) { + const {t} = useTranslation(); const [hosts, setHosts] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); @@ -64,20 +66,20 @@ export function HostManagerHostViewer({onEditHost}: SSHManagerHostViewerProps) { setHosts(data); setError(null); } catch (err) { - setError('Failed to load hosts'); + setError(t('hosts.failedToLoadHosts')); } finally { setLoading(false); } }; const handleDelete = async (hostId: number, hostName: string) => { - if (window.confirm(`Are you sure you want to delete "${hostName}"?`)) { + if (window.confirm(t('hosts.confirmDelete', { name: hostName }))) { try { await deleteSSHHost(hostId); await fetchHosts(); window.dispatchEvent(new CustomEvent('ssh-hosts:changed')); } catch (err) { - alert('Failed to delete host'); + alert(t('hosts.failedToDeleteHost')); } } }; @@ -98,32 +100,32 @@ export function HostManagerHostViewer({onEditHost}: SSHManagerHostViewerProps) { const data = JSON.parse(text); if (!Array.isArray(data.hosts) && !Array.isArray(data)) { - throw new Error('JSON must contain a "hosts" array or be an array of hosts'); + throw new Error(t('hosts.jsonMustContainHosts')); } const hostsArray = Array.isArray(data.hosts) ? data.hosts : data; if (hostsArray.length === 0) { - throw new Error('No hosts found in JSON file'); + throw new Error(t('hosts.noHostsInJson')); } if (hostsArray.length > 100) { - throw new Error('Maximum 100 hosts allowed per import'); + throw new Error(t('hosts.maxHostsAllowed')); } const result = await bulkImportSSHHosts(hostsArray); if (result.success > 0) { - alert(`Import completed: ${result.success} successful, ${result.failed} failed${result.errors.length > 0 ? '\n\nErrors:\n' + result.errors.join('\n') : ''}`); + alert(t('hosts.importCompleted', { success: result.success, failed: result.failed }) + (result.errors.length > 0 ? '\n\nErrors:\n' + result.errors.join('\n') : '')); await fetchHosts(); window.dispatchEvent(new CustomEvent('ssh-hosts:changed')); } else { - alert(`Import failed: ${result.errors.join('\n')}`); + alert(`${t('hosts.importFailed')}: ${result.errors.join('\n')}`); } } catch (err) { - const errorMessage = err instanceof Error ? err.message : 'Failed to import JSON file'; - alert(`Import error: ${errorMessage}`); + const errorMessage = err instanceof Error ? err.message : t('hosts.failedToImportJson'); + alert(`${t('hosts.importError')}: ${errorMessage}`); } finally { setImporting(false); event.target.value = ''; @@ -163,7 +165,7 @@ export function HostManagerHostViewer({onEditHost}: SSHManagerHostViewerProps) { const grouped: { [key: string]: SSHHost[] } = {}; filteredAndSortedHosts.forEach(host => { - const folder = host.folder || 'Uncategorized'; + const folder = host.folder || t('hosts.uncategorized'); if (!grouped[folder]) { grouped[folder] = []; } @@ -171,8 +173,9 @@ export function HostManagerHostViewer({onEditHost}: SSHManagerHostViewerProps) { }); const sortedFolders = Object.keys(grouped).sort((a, b) => { - if (a === 'Uncategorized') return -1; - if (b === 'Uncategorized') return 1; + const uncategorized = t('hosts.uncategorized'); + if (a === uncategorized) return -1; + if (b === uncategorized) return 1; return a.localeCompare(b); }); @@ -189,7 +192,7 @@ export function HostManagerHostViewer({onEditHost}: SSHManagerHostViewerProps) {

-

Loading hosts...

+

{t('hosts.loadingHosts')}

); @@ -201,7 +204,7 @@ export function HostManagerHostViewer({onEditHost}: SSHManagerHostViewerProps) {

{error}

@@ -213,9 +216,9 @@ export function HostManagerHostViewer({onEditHost}: SSHManagerHostViewerProps) {
-

No SSH Hosts

+

{t('hosts.noHosts')}

- You haven't added any SSH hosts yet. Click "Add Host" to get started. + {t('hosts.noHostsMessage')}

@@ -226,9 +229,9 @@ export function HostManagerHostViewer({onEditHost}: SSHManagerHostViewerProps) {
-

SSH Hosts

+

{t('hosts.sshHosts')}

- {filteredAndSortedHosts.length} hosts + {t('hosts.hostsCount', { count: filteredAndSortedHosts.length })}

@@ -242,15 +245,15 @@ export function HostManagerHostViewer({onEditHost}: SSHManagerHostViewerProps) { onClick={() => document.getElementById('json-import-input')?.click()} disabled={importing} > - {importing ? 'Importing...' : 'Import JSON'} + {importing ? t('hosts.importing') : t('hosts.importJson')}
-

Import SSH Hosts from JSON

+

{t('hosts.importJsonTitle')}

- Upload a JSON file to bulk import multiple SSH hosts (max 100). + {t('hosts.importJsonDesc')}

@@ -318,7 +321,7 @@ export function HostManagerHostViewer({onEditHost}: SSHManagerHostViewerProps) { URL.revokeObjectURL(url); }} > - Download Sample + {t('hosts.downloadSample')}