Skip to content

Commit 0829823

Browse files
committed
feat(i18n): 添加多语言支持到确认模态框、手动复制模态框和API密钥编辑模态框
1 parent 5cf4cfc commit 0829823

13 files changed

Lines changed: 587 additions & 41 deletions

File tree

web/src/components/ui/confirmation-modal.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
ModalFooter,
88
Button,
99
} from "@heroui/react";
10+
import { useTranslation } from "react-i18next";
1011
import { Icon } from "@iconify/react";
1112

1213
interface ConfirmationModalProps {
@@ -29,13 +30,15 @@ export const ConfirmationModal: React.FC<ConfirmationModalProps> = ({
2930
onConfirm,
3031
title,
3132
message,
32-
confirmText = "确认",
33-
cancelText = "取消",
33+
confirmText,
34+
cancelText,
3435
confirmColor = "danger",
3536
isLoading = false,
3637
icon = "solar:danger-triangle-bold",
3738
iconColor = "text-warning",
3839
}) => {
40+
const { t } = useTranslation("modals");
41+
3942
return (
4043
<Modal isOpen={isOpen} onClose={onClose}>
4144
<ModalContent>
@@ -50,14 +53,14 @@ export const ConfirmationModal: React.FC<ConfirmationModalProps> = ({
5053
</ModalBody>
5154
<ModalFooter>
5255
<Button disabled={isLoading} variant="light" onPress={onClose}>
53-
{cancelText}
56+
{cancelText || t("confirmation.defaultCancel")}
5457
</Button>
5558
<Button
5659
color={confirmColor}
5760
isLoading={isLoading}
5861
onPress={onConfirm}
5962
>
60-
{confirmText}
63+
{confirmText || t("confirmation.defaultConfirm")}
6164
</Button>
6265
</ModalFooter>
6366
</ModalContent>

web/src/components/ui/manual-copy-modal.tsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
ModalFooter,
99
Button,
1010
} from "@heroui/react";
11+
import { useTranslation } from "react-i18next";
1112
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
1213
import { faCopy } from "@fortawesome/free-solid-svg-icons";
1314

@@ -22,8 +23,10 @@ export default function ManualCopyModal({
2223
isOpen,
2324
onOpenChange,
2425
text,
25-
title = "手动复制",
26+
title,
2627
}: ManualCopyModalProps) {
28+
const { t } = useTranslation("modals");
29+
2730
return (
2831
<Modal
2932
isOpen={isOpen}
@@ -37,26 +40,25 @@ export default function ManualCopyModal({
3740
<ModalHeader className="flex flex-col gap-1">
3841
<div className="flex items-center gap-2">
3942
<FontAwesomeIcon className="text-primary" icon={faCopy} />
40-
{title}
43+
{title || t("manualCopy.defaultTitle")}
4144
</div>
4245
</ModalHeader>
4346
<ModalBody>
4447
<p className="text-default-600 mb-3">
45-
自动复制失败,请手动选择并复制以下内容:
48+
{t("manualCopy.description")}
4649
</p>
4750
<div className="bg-default-100 p-3 rounded-lg">
4851
<pre className="text-small font-mono whitespace-pre-wrap break-all select-all">
4952
{text}
5053
</pre>
5154
</div>
5255
<p className="text-small text-default-500 mt-2">
53-
💡 提示:点击上方文本框可全选内容,然后使用 Ctrl+C (Windows) 或
54-
Cmd+C (Mac) 复制
56+
{t("manualCopy.hint")}
5557
</p>
5658
</ModalBody>
5759
<ModalFooter>
5860
<Button color="primary" onPress={onClose}>
59-
知道了
61+
{t("manualCopy.understood")}
6062
</Button>
6163
</ModalFooter>
6264
</>

web/src/locales/en-US/endpoints.json

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,5 +230,230 @@
230230
"refreshSuccessDesc": "Tunnel information has been refreshed",
231231
"refreshFailed": "Refresh Failed",
232232
"refreshFailedDesc": "Refresh request failed"
233+
},
234+
"editApiKeyModal": {
235+
"title": "Modify API Key",
236+
"endpoint": "Endpoint",
237+
"warningTitle": "⚠️ Important Reminder",
238+
"warningMessage": "After modifying the API key, the current connection will be disconnected and you need to reconnect to the endpoint with the new key.",
239+
"newApiKey": "New API Key",
240+
"newApiKeyPlaceholder": "Enter new API key",
241+
"cancel": "Cancel",
242+
"confirm": "Confirm Modification",
243+
"saving": "Saving..."
244+
},
245+
"renameModal": {
246+
"title": "Rename Endpoint",
247+
"label": "Endpoint Name",
248+
"placeholder": "Enter new endpoint name",
249+
"cancel": "Cancel",
250+
"save": "Save",
251+
"saving": "Saving..."
252+
},
253+
"details": {
254+
"pageTitle": "Endpoint Details",
255+
"refresh": "Refresh",
256+
"sseDebug": "SSE Debug",
257+
"tlsConfig": {
258+
"none": "No TLS",
259+
"selfSigned": "Self-signed Certificate",
260+
"custom": "Custom Certificate"
261+
},
262+
"uptimeUnit": {
263+
"days": "d",
264+
"hours": "h",
265+
"minutes": "m",
266+
"seconds": "s"
267+
},
268+
"instanceStatus": {
269+
"running": "Running",
270+
"stopped": "Stopped",
271+
"error": "Error",
272+
"starting": "Starting",
273+
"stopping": "Stopping",
274+
"unknown": "Unknown"
275+
},
276+
"stats": {
277+
"title": "Endpoint Statistics",
278+
"description": "Data statistics overview for current endpoint",
279+
"tunnelCount": "Total Instances",
280+
"activeTunnels": "Active Instances",
281+
"logFileCount": "Log File Count",
282+
"logFiles": "Log Files",
283+
"logFileSize": "Log File Size",
284+
"diskUsage": "Disk Usage",
285+
"totalTraffic": "Total Traffic",
286+
"noData": "Unable to fetch statistics data"
287+
},
288+
"actions": {
289+
"title": "Endpoint Actions",
290+
"addInstance": "Add Instance",
291+
"syncInstances": "Sync Instances",
292+
"networkDebug": "Network Debug",
293+
"disconnect": "Disconnect",
294+
"connect": "Connect",
295+
"copyConfig": "Copy Config",
296+
"editConfig": "Edit Config",
297+
"resetKey": "Reset Key",
298+
"delete": "Delete Endpoint"
299+
},
300+
"info": {
301+
"title": "Endpoint Information",
302+
"qrCodeTitle": "Show QR Code",
303+
"serverAddress": "Server Address",
304+
"apiKey": "API Key",
305+
"os": "Operating System",
306+
"arch": "Architecture",
307+
"logLevel": "Log Level",
308+
"tlsConfig": "TLS Configuration",
309+
"uptime": "Uptime",
310+
"certPath": "Certificate Path",
311+
"keyPath": "Key Path",
312+
"createdAt": "Created At: ",
313+
"updatedAt": "Updated At: ",
314+
"lastCheck": "Last Check: "
315+
},
316+
"instances": {
317+
"title": "Endpoint Instances",
318+
"noData": "No instance data",
319+
"server": "Server",
320+
"client": "Client",
321+
"unnamed": "Unnamed"
322+
},
323+
"modals": {
324+
"extractInstances": {
325+
"title": "Extract Instance URLs",
326+
"copyAll": "Copy All",
327+
"close": "Close",
328+
"copied": "Copied"
329+
},
330+
"addInstance": {
331+
"title": "Add Instance",
332+
"nameLabel": "Instance Name",
333+
"namePlaceholder": "Enter instance name (optional)",
334+
"urlLabel": "Tunnel URL",
335+
"urlPlaceholder": "Example: server://0.0.0.0:8080/127.0.0.1:3000",
336+
"formatHint": "Format: server://bind_addr:bind_port/target_host:target_port or client://server_host:server_port/local_host:local_port",
337+
"cancel": "Cancel",
338+
"add": "Add"
339+
},
340+
"editConfig": {
341+
"title": "Edit Endpoint Configuration",
342+
"warning": "⚠️ Modifying URL or API key will disconnect current connection and reconnect with new configuration",
343+
"nameLabel": "Endpoint Name",
344+
"namePlaceholder": "Enter endpoint name",
345+
"urlLabel": "URL Address",
346+
"urlPlaceholder": "http(s)://example.com:9090/api/v1",
347+
"apiKeyLabel": "API Key",
348+
"apiKeyPlaceholder": "Leave blank to keep current key",
349+
"apiKeyDescription": "Leave blank to keep current key",
350+
"hostnameLabel": "Connection IP",
351+
"hostnamePlaceholder": "Example: 192.168.1.1",
352+
"hostnameDescription": "Address for instance connection",
353+
"cancel": "Cancel",
354+
"confirm": "Confirm Modification"
355+
},
356+
"importUrl": {
357+
"title": "Import URLs",
358+
"placeholder": "Paste URLs here, one per line...",
359+
"confirm": "Confirm",
360+
"cancel": "Cancel"
361+
},
362+
"resetApiKey": {
363+
"title": "Reset API Key",
364+
"warningTitle": "⚠️ Important Reminder",
365+
"warningMessage": "After resetting the API key, the current connection will be disconnected and you need to reconnect with the new key.",
366+
"confirmMessage": "Are you sure you want to reset the API key for this endpoint? This action will:",
367+
"consequences": {
368+
"newKey": "Generate a new API key",
369+
"disconnect": "Disconnect current connection",
370+
"reconnect": "Require reconnection with new key"
371+
},
372+
"cancel": "Cancel",
373+
"confirm": "Confirm Reset"
374+
},
375+
"deleteEndpoint": {
376+
"title": "Delete Endpoint",
377+
"warningTitle": "⚠️ Dangerous Operation",
378+
"warningMessage": "After deleting the endpoint, all related instances and configuration information will be permanently lost and cannot be recovered.",
379+
"confirmMessage": "Are you sure you want to delete endpoint",
380+
"confirmMessageEnd": "? This action will:",
381+
"consequences": {
382+
"deleteConfig": "Permanently delete endpoint configuration",
383+
"deleteInstances": "Delete all associated instances",
384+
"clearHistory": "Clear all historical data",
385+
"irreversible": "This action cannot be undone"
386+
},
387+
"cancel": "Cancel",
388+
"confirm": "Confirm Delete"
389+
},
390+
"qrCode": {
391+
"title": "Endpoint Configuration QR Code",
392+
"description": "Scan this QR code to quickly configure endpoint connection",
393+
"downloadApp": "Download Mobile App",
394+
"iosVersion": "iOS Version",
395+
"androidVersion": "Android Version",
396+
"androidInDevelopment": "In Development",
397+
"androidDescription": "Android version is under development, stay tuned!"
398+
}
399+
},
400+
"toasts": {
401+
"fetchDetailFailed": "Failed to fetch endpoint details",
402+
"loadFailed": "Load failed",
403+
"fetchStatsFailed": "Failed to fetch statistics",
404+
"fetchInstancesFailed": "Failed to fetch instance list",
405+
"connectSuccess": "Connect successful",
406+
"connectSuccessDesc": "Endpoint connection request sent",
407+
"connectFailed": "Connect failed",
408+
"connectFailedDesc": "Connection request failed",
409+
"disconnectSuccess": "Disconnect successful",
410+
"disconnectSuccessDesc": "Endpoint connection has been disconnected",
411+
"disconnectFailed": "Disconnect failed",
412+
"disconnectFailedDesc": "Disconnect failed",
413+
"refreshSuccess": "Refresh successful",
414+
"refreshSuccessDesc": "Tunnel information has been refreshed",
415+
"refreshFailed": "Refresh failed",
416+
"refreshFailedDesc": "Refresh request failed",
417+
"configCopied": "Copied",
418+
"configCopiedDesc": "Configuration copied to clipboard",
419+
"resetKeyStart": "Starting key reset",
420+
"resetKeyDisconnecting": "Disconnecting current connection...",
421+
"resetKeySuccess": "Key reset successful",
422+
"resetKeySuccessDesc": "New key generated, reconnecting...",
423+
"resetKeyFailed": "Key reset failed",
424+
"resetKeyFailedDesc": "Reset failed",
425+
"deleteSuccess": "Delete successful",
426+
"deleteSuccessDesc": "Endpoint has been deleted",
427+
"deleteFailed": "Delete failed",
428+
"deleteFailedDesc": "Delete failed",
429+
"addInstanceUrlRequired": "Please enter URL",
430+
"addInstanceUrlRequiredDesc": "Tunnel URL cannot be empty",
431+
"addInstanceSuccess": "Create successful",
432+
"addInstanceSuccessDesc": "Tunnel has been created",
433+
"addInstanceFailed": "Create failed",
434+
"addInstanceFailedDesc": "Unable to create tunnel",
435+
"editConfigValidation": "Please fill in complete information",
436+
"editConfigValidationDesc": "Name and URL address cannot be empty",
437+
"editConfigNoChange": "No changes",
438+
"editConfigNoChangeDesc": "No configuration changes detected",
439+
"editConfigStartUpdate": "Starting configuration update",
440+
"editConfigStartUpdateDesc": "Processing configuration update...",
441+
"editConfigDisconnecting": "Disconnecting",
442+
"editConfigDisconnectingDesc": "Disconnecting current connection...",
443+
"editConfigUpdating": "Updating configuration",
444+
"editConfigUpdatingDesc": "Submitting configuration update...",
445+
"editConfigSuccess": "Configuration update successful",
446+
"editConfigSuccessDesc": "Configuration updated, refreshing data...",
447+
"editConfigReconnecting": "Reconnecting",
448+
"editConfigReconnectingDesc": "Attempting to reconnect...",
449+
"editConfigFailed": "Configuration update failed",
450+
"editConfigFailedDesc": "Update failed",
451+
"refreshAllSuccess": "Refresh successful",
452+
"refreshAllSuccessDesc": "All data has been refreshed",
453+
"refreshAllFailed": "Refresh failed",
454+
"refreshAllFailedDesc": "Refresh failed",
455+
"qrCodeFailed": "Failed to generate QR code",
456+
"qrCodeFailedDesc": "Unknown error"
457+
}
233458
}
234459
}

web/src/locales/en-US/modals.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"confirmation": {
3+
"defaultConfirm": "Confirm",
4+
"defaultCancel": "Cancel"
5+
},
6+
"manualCopy": {
7+
"defaultTitle": "Manual Copy",
8+
"description": "Auto-copy failed, please manually select and copy the following content:",
9+
"hint": "💡 Tip: Click the text box above to select all content, then use Ctrl+C (Windows) or Cmd+C (Mac) to copy",
10+
"understood": "Got it"
11+
}
12+
}

web/src/locales/en-US/settings.json

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,36 @@
9595
"resetSuccessDesc": "Settings have been restored to default values"
9696
}
9797
},
98+
"auth": {
99+
"title": "Authentication",
100+
"description": "Manage authentication and OAuth2 authorization configuration",
101+
"loginMethods": {
102+
"title": "Login Methods",
103+
"local": {
104+
"title": "Local Account Password",
105+
"description": "Login with username and password"
106+
},
107+
"github": {
108+
"title": "GitHub OAuth",
109+
"description": "Login with GitHub account"
110+
},
111+
"cloudflare": {
112+
"title": "Cloudflare OAuth",
113+
"description": "Login with Cloudflare account"
114+
}
115+
},
116+
"oauth2Config": {
117+
"title": "OAuth2 Configuration",
118+
"clientId": "Client ID",
119+
"clientIdPlaceholder": "Enter OAuth2 Client ID",
120+
"clientSecret": "Client Secret",
121+
"clientSecretPlaceholder": "Enter OAuth2 Client Secret"
122+
},
123+
"actions": {
124+
"reset": "Reset",
125+
"save": "Save Changes"
126+
}
127+
},
98128
"profile": {
99129
"title": "Personal Profile",
100130
"description": "Manage your personal information and account settings",

0 commit comments

Comments
 (0)