diff --git a/src/components/fm.tsx b/src/components/fm.tsx index 35c7035..cfc0bb4 100644 --- a/src/components/fm.tsx +++ b/src/components/fm.tsx @@ -210,7 +210,7 @@ const FMComponent: React.FC = ({ wsUrl, if (uOpen) setuOpen(false); listFile(); } else { - throw new Error("Unknown identifier"); + throw new Error(t("Results.UnknownIdentifier")); } } else { await waitForHandleReady(); diff --git a/src/components/header.tsx b/src/components/header.tsx index ea89d38..32c54ab 100644 --- a/src/components/header.tsx +++ b/src/components/header.tsx @@ -117,7 +117,7 @@ export default function Header() { {profile.username} - + {profile.username} @@ -125,14 +125,12 @@ export default function Header() { {t('Profile')} - ⇧⌘P { setDropdownOpen(false) }}> {t('Settings')} - ⇧⌘S @@ -140,7 +138,6 @@ export default function Header() { {t('Logout')} - ⇧⌘Q diff --git a/src/components/install-commands.tsx b/src/components/install-commands.tsx index a618f1b..59fc8d3 100644 --- a/src/components/install-commands.tsx +++ b/src/components/install-commands.tsx @@ -10,9 +10,10 @@ import useSettings from "@/hooks/useSetting" import { ModelConfig } from "@/types" import { Check, Clipboard } from "lucide-react" import { toast } from "sonner" +import { copyToClipboard } from "@/lib/utils" import { useTranslation } from "react-i18next" -import { copyToClipboard } from "@/lib/utils" +import i18next from "i18next" enum OSTypes { Linux = 1, @@ -61,22 +62,23 @@ export const InstallCommandsMenu = forwardRef((p ); }) -const generateCommand = (type: number, { agent_secret_key, install_host, listen_port, tls }: ModelConfig) => { +const generateCommand = (type: number, { agent_secret_key, install_host, tls }: ModelConfig) => { + if (!install_host) - throw new Error("You have not specify the installed host.") + throw new Error(i18next.t("Results.InstallHostRequired")); - const env = `NZ_SERVER=${install_host}:${listen_port} NZ_TLS=${tls || false} NZ_CLIENT_SECRET=${agent_secret_key}`; + const env = `NZ_SERVER=${install_host} NZ_TLS=${tls || false} NZ_CLIENT_SECRET=${agent_secret_key}`; switch (type) { - case OSTypes.Linux: - case OSTypes.macOS: { - return `curl -L https://raw.githubusercontent.com/nezhahq/scripts/main/agent/install.sh -o nezha.sh && chmod +x nezha.sh && env ${env} ./nezha.sh` - } - case OSTypes.Windows: { - return `${env} [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Ssl3 -bor [Net.SecurityProtocolType]::Tls -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls12;set-ExecutionPolicy RemoteSigned;Invoke-WebRequest https://raw.githubusercontent.com/nezhahq/scripts/main/agent/install.ps1 -OutFile C:\install.ps1;powershell.exe C:\install.ps1` - } - default: { - throw new Error(`Unknown OS: ${type}`); - } + case OSTypes.Linux: + case OSTypes.macOS: { + return `curl -L https://raw.githubusercontent.com/nezhahq/scripts/main/agent/install.sh -o nezha.sh && chmod +x nezha.sh && env ${env} ./nezha.sh` + } + case OSTypes.Windows: { + return `${env} [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Ssl3 -bor [Net.SecurityProtocolType]::Tls -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls12;set-ExecutionPolicy RemoteSigned;Invoke-WebRequest https://raw.githubusercontent.com/nezhahq/scripts/main/agent/install.ps1 -OutFile C:\install.ps1;powershell.exe C:\install.ps1` + } + default: { + throw new Error(`Unknown OS: ${type}`); + } } } diff --git a/src/lib/i18n.ts b/src/lib/i18n.ts index 861a04f..a84aaa4 100644 --- a/src/lib/i18n.ts +++ b/src/lib/i18n.ts @@ -1,6 +1,5 @@ import i18n from "i18next"; import { initReactI18next } from "react-i18next"; -import LanguageDetector from "i18next-browser-languagedetector"; import enTranslation from "../locales/en/translation.json"; import itTranslation from "../locales/it/translation.json"; @@ -22,16 +21,22 @@ const resources = { }, }; +const getStoredLanguage = () => { + return localStorage.getItem("language") || "zh-CN"; +}; i18n.use(initReactI18next) - .use(LanguageDetector) .init({ resources, + lng: getStoredLanguage(), // 使用localStorage中存储的语言或默认值 fallbackLng: "en", // 当前语言的翻译没有找到时,使用的备选语言 interpolation: { escapeValue: false, // react已经安全地转义 }, }); +i18n.on("languageChanged", (lng) => { + localStorage.setItem("language", lng); +}); export default i18n; \ No newline at end of file diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index d01163f..9ecddf2 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -17,7 +17,9 @@ "NoRowsAreSelected": "No rows are selected", "ThisOperationIsUnrecoverable": "This operation cannot be undone!", "TaskTriggeredSuccessfully": "The task triggered successfully", - "TheServerDoesNotOnline": "The server does not exist or has not been connected yet" + "TheServerDoesNotOnline": "The server does not exist or has not been connected yet", + "InstallHostRequired": "The Agent docking address has not been filled in in the settings.", + "UnknownIdentifier": "Unknown identifier" }, "Login": "Log in", "Server": "Server", @@ -101,7 +103,7 @@ "Domains": "domain name", "MaximumRetryAttempts": "Maximum number of retries", "Refresh": "Refresh", - "CopyPath": "copy path", + "CopyPath": "Copy path", "Goto": "Go to", "UpdateProfile": "Update profile", "NewUsername": "New username", @@ -117,19 +119,18 @@ "Uploading": "Uploading", "EditNAT": "Edit intranet penetration", "CreateNAT": "Create intranet penetration", - "LocalService": "local service", + "LocalService": "Local service", "BindHostname": "Bind domain name", "EditServerGroup": "Edit server group", "CreateServerGroup": "Create server group", "User": "User", "WAF": "Web application firewall", "SiteName": "Site name", - "DashboardOriginalHost": "Dashboard Server Domain/IP without CDN", - "Auto": "Automatic", + "DashboardOriginalHost": "Agent docking address [domain name/IP:port]", "LoginFailed": "Login failed", "BruteForceAttackingToken": "Brute Force Attacking Token", "BruteForceAttackingAgentSecret": "Brute Force Attacking Agent Secret", - "Language": "language", + "Language": "Language", "CustomCodes": "Custom Codes (Style and Script)", "CustomCodesDashboard": "Custom Codes for Dashboard", "CustomPublicDNSNameserversforDDNS": "Custom Public DNS Nameservers for DDNS", @@ -137,7 +138,7 @@ "UseDirectConnectingIP": "Use direct connection IP", "IPChangeNotification": "IP Change notification", "FullIPNotification": "Show Full IP Address in Notification Messages", - "EditService": "Editing services", + "EditService": "Edit service", "CreateService": "Create service", "EditTask": "Edit task", "CreateTask": "Create task", @@ -147,8 +148,8 @@ "CreateAlertRule": "Create alert rules", "EditNotifierGroup": "Edit notification group", "CreateNotifierGroup": "Create notification group", - "NewUser": "new user", + "NewUser": "New user", "Count": "Count", "LastBlockReason": "Last Block Reason", "LastBlockTime": "Last ban time" -} \ No newline at end of file +} diff --git a/src/locales/it/translation.json b/src/locales/it/translation.json index d7349fa..ab9bf41 100644 --- a/src/locales/it/translation.json +++ b/src/locales/it/translation.json @@ -17,7 +17,9 @@ "NoRowsAreSelected": "Nessuna riga selezionata", "ThisOperationIsUnrecoverable": "Questa operazione non può essere annullata!", "TaskTriggeredSuccessfully": "Attività avviata correttamente", - "TheServerDoesNotOnline": "Il server non esiste o non è stato ancora connesso" + "TheServerDoesNotOnline": "Il server non esiste o non è stato ancora connesso", + "InstallHostRequired": "L'indirizzo di aggancio dell'Agent non è stato inserito nelle impostazioni.", + "UnknownIdentifier": "identificatore sconosciuto" }, "Login": "Accedi", "Server": "Server", @@ -45,23 +47,23 @@ "Done": "Fine", "Offline": "Non in linea", "Failure": "Fallire", - "Loading": "caricamento", - "NoResults": "nessun contenuto", + "Loading": "Caricamento", + "NoResults": "Nessun contenuto", "Actions": "Azione", "EditServer": "Modifica server", "Weight": "Peso (più grande è il numero, più alto sarà visualizzato)", "DDNSProfiles": "ID profilo DDNS", "SeparateWithComma": "(separati da virgole)", "Public": "Pubblico", - "Private": "privato", - "Submit": "invia", + "Private": "Privato", + "Submit": "Invia", "Target": "Bersaglio", "Coverage": "Copertura", "CoverAll": "Copri tutto", "IgnoreAll": "Ignorare tutto", "SpecificServers": "Server specifico", "Type": "Tipo", - "Interval": "intervallo", + "Interval": "Intervallo", "NotifierGroupID": "ID del gruppo di notifiche", "Trigger": "Grilletto", "TasksToTriggerOnAlert": "L'attività che ha attivato l'avviso", @@ -82,7 +84,7 @@ "EnableTriggerTask": "Abilita attività di attivazione", "CronExpression": "Espressione cron", "Command": "Ordine", - "NotifierGroup": "gruppo di notifica", + "NotifierGroup": "Gruppo di notifica", "SendSuccessNotification": "Invia notifica di successo", "LastExecution": "Ultimo giustiziato", "Result": "Risultato", @@ -96,16 +98,16 @@ "RequestHeader": "Intestazione della richiesta", "DoNotSendTestMessage": "Non inviare messaggi di prova", "Always": "Sempre", - "Once": "solo una volta", - "Provider": "fornitore", - "Domains": "nome di dominio", + "Once": "Solo una volta", + "Provider": "Fornitore", + "Domains": "Nome di dominio", "MaximumRetryAttempts": "Numero massimo di tentativi", "Refresh": "aggiornare", - "CopyPath": "percorso di copia", + "CopyPath": "Percorso di copia", "Goto": "Vai a", "UpdateProfile": "Aggiorna il profilo", "NewUsername": "Nuovo nome utente", - "OriginalPassword": "password originale", + "OriginalPassword": "Password originale", "NewPassword": "Nuova parola d'ordine", "EditDDNS": "Modifica DDNS", "CreateDDNS": "Crea DDNS", @@ -125,7 +127,6 @@ "CreateService": "Crea servizio", "EditTask": "Modifica attività", "CreateTask": "Crea attività", - "Auto": "automatico", "CreateNotifier": "Crea notifica", "EditNotifier": "Modifica notifica", "EditAlertRule": "Modifica le regole degli allarmi", @@ -135,10 +136,10 @@ "User": "Utente", "WAF": "Firewall dell'applicazione Web", "SiteName": "Nome del sito", - "Language": "lingua", + "Language": "Lingua", "CustomCodes": "Codice personalizzato (stili e script)", "CustomCodesDashboard": "Codice personalizzato per dashboard", - "DashboardOriginalHost": "Nome di dominio/IP del server Dashboard (no CDN)", + "DashboardOriginalHost": "Indirizzo di ancoraggio dell'agente [nome dominio/IP:porta]", "CustomPublicDNSNameserversforDDNS": "Server dei nomi DNS pubblici personalizzati per DDNS", "RealIPHeader": "Intestazione della richiesta IP reale", "UseDirectConnectingIP": "Utilizzare l'IP di connessione diretta", @@ -147,8 +148,8 @@ "LoginFailed": "Accesso non riuscito", "BruteForceAttackingToken": "Segnalino di attacco di forza bruta", "BruteForceAttackingAgentSecret": "Segreti proxy dell'attacco di forza bruta", - "NewUser": "nuovo utente", - "Count": "contare", + "NewUser": "Nuovo utente", + "Count": "Contare", "LastBlockReason": "Motivo dell'ultimo divieto", "LastBlockTime": "L'ultima volta che è stato vietato" -} \ No newline at end of file +} diff --git a/src/locales/zh-CN/translation.json b/src/locales/zh-CN/translation.json index 45582af..ea2b575 100644 --- a/src/locales/zh-CN/translation.json +++ b/src/locales/zh-CN/translation.json @@ -17,7 +17,9 @@ "NoRowsAreSelected": "未选择任何行", "ThisOperationIsUnrecoverable": "这个操作将无法恢复!", "TaskTriggeredSuccessfully": "任务触发成功", - "TheServerDoesNotOnline": "服务器不存在或者还未连接" + "TheServerDoesNotOnline": "服务器不存在或者还未连接", + "InstallHostRequired": "设置中尚未填写Agent对接地址", + "UnknownIdentifier": "未知标识符" }, "Login": "登录", "Server": "服务器", @@ -137,7 +139,7 @@ "Language": "语言", "CustomCodes": "自定义代码(样式和脚本)", "CustomCodesDashboard": "仪表板的自定义代码", - "DashboardOriginalHost": "仪表板服务器域名/IP(无 CDN)", + "DashboardOriginalHost": "Agent对接地址【域名/IP:端口】", "CustomPublicDNSNameserversforDDNS": "DDNS 的自定义公共 DNS 名称服务器", "RealIPHeader": "真实IP请求头", "UseDirectConnectingIP": "使用直连 IP", @@ -149,6 +151,5 @@ "NewUser": "新用户", "Count": "计数", "LastBlockReason": "最后封禁原因", - "LastBlockTime": "最后封禁时间", - "Auto": "自动" -} \ No newline at end of file + "LastBlockTime": "最后封禁时间" +} diff --git a/src/locales/zh-TW/translation.json b/src/locales/zh-TW/translation.json index eef24fb..34fcc7d 100644 --- a/src/locales/zh-TW/translation.json +++ b/src/locales/zh-TW/translation.json @@ -17,7 +17,9 @@ "NoRowsAreSelected": "未選擇任何行", "ThisOperationIsUnrecoverable": "這個操作將無法恢復!", "TaskTriggeredSuccessfully": "任務觸發成功", - "TheServerDoesNotOnline": "伺服器不存在或尚未連接" + "TheServerDoesNotOnline": "伺服器不存在或尚未連接", + "InstallHostRequired": "設定中尚未填寫Agent對接位址", + "UnknownIdentifier": "未知標識符" }, "Login": "登入", "Server": "伺服器", @@ -137,7 +139,7 @@ "Language": "語言", "CustomCodes": "自訂程式碼(樣式和腳本)", "CustomCodesDashboard": "儀表板的自訂程式碼", - "DashboardOriginalHost": "儀表板伺服器網域/IP(無 CDN)", + "DashboardOriginalHost": "Agent對接位址【網域名稱/IP:連接埠】", "CustomPublicDNSNameserversforDDNS": "DDNS 的自訂公共 DNS 名稱伺服器", "RealIPHeader": "真實IP請求頭", "UseDirectConnectingIP": "使用直連 IP", @@ -149,6 +151,5 @@ "NewUser": "新用戶", "Count": "計數", "LastBlockReason": "最後封鎖原因", - "LastBlockTime": "最後封鎖時間", - "Auto": "自動" -} \ No newline at end of file + "LastBlockTime": "最後封鎖時間" +} diff --git a/src/routes/settings.tsx b/src/routes/settings.tsx index d1f1eeb..4855f38 100644 --- a/src/routes/settings.tsx +++ b/src/routes/settings.tsx @@ -105,11 +105,9 @@ export default function SettingsPage() { if (e instanceof Error) setError(e); return; } finally { - if (values.language != "auto") { + if (values.language != i18n.language) { i18n.changeLanguage(values.language); - } else { - i18n.changeLanguage(i18n.services.languageDetector.detect()); - } + } toast(t("Success")); } }; diff --git a/src/types/settings.ts b/src/types/settings.ts index 6273054..4ae4766 100644 --- a/src/types/settings.ts +++ b/src/types/settings.ts @@ -5,7 +5,6 @@ export const settingCoverageTypes: Record = { } export const nezhaLang: Record = { - "auto": i18next.t("Auto"), "zh-CN": "简体中文(中国大陆)", "zh-TW": "正體中文(台灣)", "en-US": "English",