fix: Kill auto language (#21)

* fix: Kill auto language

Kill the background automatic recognition of language to prevent backend
Language file correction

* refactor(Aggregate): Ports and install hosts

Optimize multi-language

* fix(I18n): Kill spurious shortcuts

Fix wrong import
This commit is contained in:
GuGuGu
2024-12-02 13:57:03 +01:00
committed by GitHub
parent 51c0af6146
commit 22c53cf723
10 changed files with 68 additions and 63 deletions

View File

@@ -210,7 +210,7 @@ const FMComponent: React.FC<FMProps & JSX.IntrinsicElements["div"]> = ({ wsUrl,
if (uOpen) setuOpen(false); if (uOpen) setuOpen(false);
listFile(); listFile();
} else { } else {
throw new Error("Unknown identifier"); throw new Error(t("Results.UnknownIdentifier"));
} }
} else { } else {
await waitForHandleReady(); await waitForHandleReady();

View File

@@ -117,7 +117,7 @@ export default function Header() {
<AvatarFallback>{profile.username}</AvatarFallback> <AvatarFallback>{profile.username}</AvatarFallback>
</Avatar> </Avatar>
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent className="w-56"> <DropdownMenuContent className="w-32">
<DropdownMenuLabel>{profile.username}</DropdownMenuLabel> <DropdownMenuLabel>{profile.username}</DropdownMenuLabel>
<DropdownMenuSeparator /> <DropdownMenuSeparator />
<DropdownMenuGroup> <DropdownMenuGroup>
@@ -125,14 +125,12 @@ export default function Header() {
<Link to="/dashboard/profile" className="flex items-center gap-2 w-full"> <Link to="/dashboard/profile" className="flex items-center gap-2 w-full">
<User2 /> <User2 />
{t('Profile')} {t('Profile')}
<DropdownMenuShortcut>P</DropdownMenuShortcut>
</Link> </Link>
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem onClick={() => { setDropdownOpen(false) }}> <DropdownMenuItem onClick={() => { setDropdownOpen(false) }}>
<Link to="/dashboard/settings" className="flex items-center gap-2 w-full"> <Link to="/dashboard/settings" className="flex items-center gap-2 w-full">
<Settings /> <Settings />
{t('Settings')} {t('Settings')}
<DropdownMenuShortcut>S</DropdownMenuShortcut>
</Link> </Link>
</DropdownMenuItem> </DropdownMenuItem>
</DropdownMenuGroup> </DropdownMenuGroup>
@@ -140,7 +138,6 @@ export default function Header() {
<DropdownMenuItem onClick={logout} className="cursor-pointer"> <DropdownMenuItem onClick={logout} className="cursor-pointer">
<LogOut /> <LogOut />
{t('Logout')} {t('Logout')}
<DropdownMenuShortcut>Q</DropdownMenuShortcut>
</DropdownMenuItem> </DropdownMenuItem>
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu>

View File

@@ -10,9 +10,10 @@ import useSettings from "@/hooks/useSetting"
import { ModelConfig } from "@/types" import { ModelConfig } from "@/types"
import { Check, Clipboard } from "lucide-react" import { Check, Clipboard } from "lucide-react"
import { toast } from "sonner" import { toast } from "sonner"
import { copyToClipboard } from "@/lib/utils"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { copyToClipboard } from "@/lib/utils" import i18next from "i18next"
enum OSTypes { enum OSTypes {
Linux = 1, Linux = 1,
@@ -61,22 +62,23 @@ export const InstallCommandsMenu = forwardRef<HTMLButtonElement, ButtonProps>((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) 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) { switch (type) {
case OSTypes.Linux: case OSTypes.Linux:
case OSTypes.macOS: { 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` 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: { 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` 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: { default: {
throw new Error(`Unknown OS: ${type}`); throw new Error(`Unknown OS: ${type}`);
} }
} }
} }

View File

@@ -1,6 +1,5 @@
import i18n from "i18next"; import i18n from "i18next";
import { initReactI18next } from "react-i18next"; import { initReactI18next } from "react-i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import enTranslation from "../locales/en/translation.json"; import enTranslation from "../locales/en/translation.json";
import itTranslation from "../locales/it/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) i18n.use(initReactI18next)
.use(LanguageDetector)
.init({ .init({
resources, resources,
lng: getStoredLanguage(), // 使用localStorage中存储的语言或默认值
fallbackLng: "en", // 当前语言的翻译没有找到时,使用的备选语言 fallbackLng: "en", // 当前语言的翻译没有找到时,使用的备选语言
interpolation: { interpolation: {
escapeValue: false, // react已经安全地转义 escapeValue: false, // react已经安全地转义
}, },
}); });
i18n.on("languageChanged", (lng) => {
localStorage.setItem("language", lng);
});
export default i18n; export default i18n;

View File

@@ -17,7 +17,9 @@
"NoRowsAreSelected": "No rows are selected", "NoRowsAreSelected": "No rows are selected",
"ThisOperationIsUnrecoverable": "This operation cannot be undone!", "ThisOperationIsUnrecoverable": "This operation cannot be undone!",
"TaskTriggeredSuccessfully": "The task triggered successfully", "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", "Login": "Log in",
"Server": "Server", "Server": "Server",
@@ -101,7 +103,7 @@
"Domains": "domain name", "Domains": "domain name",
"MaximumRetryAttempts": "Maximum number of retries", "MaximumRetryAttempts": "Maximum number of retries",
"Refresh": "Refresh", "Refresh": "Refresh",
"CopyPath": "copy path", "CopyPath": "Copy path",
"Goto": "Go to", "Goto": "Go to",
"UpdateProfile": "Update profile", "UpdateProfile": "Update profile",
"NewUsername": "New username", "NewUsername": "New username",
@@ -117,19 +119,18 @@
"Uploading": "Uploading", "Uploading": "Uploading",
"EditNAT": "Edit intranet penetration", "EditNAT": "Edit intranet penetration",
"CreateNAT": "Create intranet penetration", "CreateNAT": "Create intranet penetration",
"LocalService": "local service", "LocalService": "Local service",
"BindHostname": "Bind domain name", "BindHostname": "Bind domain name",
"EditServerGroup": "Edit server group", "EditServerGroup": "Edit server group",
"CreateServerGroup": "Create server group", "CreateServerGroup": "Create server group",
"User": "User", "User": "User",
"WAF": "Web application firewall", "WAF": "Web application firewall",
"SiteName": "Site name", "SiteName": "Site name",
"DashboardOriginalHost": "Dashboard Server Domain/IP without CDN", "DashboardOriginalHost": "Agent docking address [domain name/IP:port]",
"Auto": "Automatic",
"LoginFailed": "Login failed", "LoginFailed": "Login failed",
"BruteForceAttackingToken": "Brute Force Attacking Token", "BruteForceAttackingToken": "Brute Force Attacking Token",
"BruteForceAttackingAgentSecret": "Brute Force Attacking Agent Secret", "BruteForceAttackingAgentSecret": "Brute Force Attacking Agent Secret",
"Language": "language", "Language": "Language",
"CustomCodes": "Custom Codes (Style and Script)", "CustomCodes": "Custom Codes (Style and Script)",
"CustomCodesDashboard": "Custom Codes for Dashboard", "CustomCodesDashboard": "Custom Codes for Dashboard",
"CustomPublicDNSNameserversforDDNS": "Custom Public DNS Nameservers for DDNS", "CustomPublicDNSNameserversforDDNS": "Custom Public DNS Nameservers for DDNS",
@@ -137,7 +138,7 @@
"UseDirectConnectingIP": "Use direct connection IP", "UseDirectConnectingIP": "Use direct connection IP",
"IPChangeNotification": "IP Change notification", "IPChangeNotification": "IP Change notification",
"FullIPNotification": "Show Full IP Address in Notification Messages", "FullIPNotification": "Show Full IP Address in Notification Messages",
"EditService": "Editing services", "EditService": "Edit service",
"CreateService": "Create service", "CreateService": "Create service",
"EditTask": "Edit task", "EditTask": "Edit task",
"CreateTask": "Create task", "CreateTask": "Create task",
@@ -147,8 +148,8 @@
"CreateAlertRule": "Create alert rules", "CreateAlertRule": "Create alert rules",
"EditNotifierGroup": "Edit notification group", "EditNotifierGroup": "Edit notification group",
"CreateNotifierGroup": "Create notification group", "CreateNotifierGroup": "Create notification group",
"NewUser": "new user", "NewUser": "New user",
"Count": "Count", "Count": "Count",
"LastBlockReason": "Last Block Reason", "LastBlockReason": "Last Block Reason",
"LastBlockTime": "Last ban time" "LastBlockTime": "Last ban time"
} }

View File

@@ -17,7 +17,9 @@
"NoRowsAreSelected": "Nessuna riga selezionata", "NoRowsAreSelected": "Nessuna riga selezionata",
"ThisOperationIsUnrecoverable": "Questa operazione non può essere annullata!", "ThisOperationIsUnrecoverable": "Questa operazione non può essere annullata!",
"TaskTriggeredSuccessfully": "Attività avviata correttamente", "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", "Login": "Accedi",
"Server": "Server", "Server": "Server",
@@ -45,23 +47,23 @@
"Done": "Fine", "Done": "Fine",
"Offline": "Non in linea", "Offline": "Non in linea",
"Failure": "Fallire", "Failure": "Fallire",
"Loading": "caricamento", "Loading": "Caricamento",
"NoResults": "nessun contenuto", "NoResults": "Nessun contenuto",
"Actions": "Azione", "Actions": "Azione",
"EditServer": "Modifica server", "EditServer": "Modifica server",
"Weight": "Peso (più grande è il numero, più alto sarà visualizzato)", "Weight": "Peso (più grande è il numero, più alto sarà visualizzato)",
"DDNSProfiles": "ID profilo DDNS", "DDNSProfiles": "ID profilo DDNS",
"SeparateWithComma": "(separati da virgole)", "SeparateWithComma": "(separati da virgole)",
"Public": "Pubblico", "Public": "Pubblico",
"Private": "privato", "Private": "Privato",
"Submit": "invia", "Submit": "Invia",
"Target": "Bersaglio", "Target": "Bersaglio",
"Coverage": "Copertura", "Coverage": "Copertura",
"CoverAll": "Copri tutto", "CoverAll": "Copri tutto",
"IgnoreAll": "Ignorare tutto", "IgnoreAll": "Ignorare tutto",
"SpecificServers": "Server specifico", "SpecificServers": "Server specifico",
"Type": "Tipo", "Type": "Tipo",
"Interval": "intervallo", "Interval": "Intervallo",
"NotifierGroupID": "ID del gruppo di notifiche", "NotifierGroupID": "ID del gruppo di notifiche",
"Trigger": "Grilletto", "Trigger": "Grilletto",
"TasksToTriggerOnAlert": "L'attività che ha attivato l'avviso", "TasksToTriggerOnAlert": "L'attività che ha attivato l'avviso",
@@ -82,7 +84,7 @@
"EnableTriggerTask": "Abilita attività di attivazione", "EnableTriggerTask": "Abilita attività di attivazione",
"CronExpression": "Espressione cron", "CronExpression": "Espressione cron",
"Command": "Ordine", "Command": "Ordine",
"NotifierGroup": "gruppo di notifica", "NotifierGroup": "Gruppo di notifica",
"SendSuccessNotification": "Invia notifica di successo", "SendSuccessNotification": "Invia notifica di successo",
"LastExecution": "Ultimo giustiziato", "LastExecution": "Ultimo giustiziato",
"Result": "Risultato", "Result": "Risultato",
@@ -96,16 +98,16 @@
"RequestHeader": "Intestazione della richiesta", "RequestHeader": "Intestazione della richiesta",
"DoNotSendTestMessage": "Non inviare messaggi di prova", "DoNotSendTestMessage": "Non inviare messaggi di prova",
"Always": "Sempre", "Always": "Sempre",
"Once": "solo una volta", "Once": "Solo una volta",
"Provider": "fornitore", "Provider": "Fornitore",
"Domains": "nome di dominio", "Domains": "Nome di dominio",
"MaximumRetryAttempts": "Numero massimo di tentativi", "MaximumRetryAttempts": "Numero massimo di tentativi",
"Refresh": "aggiornare", "Refresh": "aggiornare",
"CopyPath": "percorso di copia", "CopyPath": "Percorso di copia",
"Goto": "Vai a", "Goto": "Vai a",
"UpdateProfile": "Aggiorna il profilo", "UpdateProfile": "Aggiorna il profilo",
"NewUsername": "Nuovo nome utente", "NewUsername": "Nuovo nome utente",
"OriginalPassword": "password originale", "OriginalPassword": "Password originale",
"NewPassword": "Nuova parola d'ordine", "NewPassword": "Nuova parola d'ordine",
"EditDDNS": "Modifica DDNS", "EditDDNS": "Modifica DDNS",
"CreateDDNS": "Crea DDNS", "CreateDDNS": "Crea DDNS",
@@ -125,7 +127,6 @@
"CreateService": "Crea servizio", "CreateService": "Crea servizio",
"EditTask": "Modifica attività", "EditTask": "Modifica attività",
"CreateTask": "Crea attività", "CreateTask": "Crea attività",
"Auto": "automatico",
"CreateNotifier": "Crea notifica", "CreateNotifier": "Crea notifica",
"EditNotifier": "Modifica notifica", "EditNotifier": "Modifica notifica",
"EditAlertRule": "Modifica le regole degli allarmi", "EditAlertRule": "Modifica le regole degli allarmi",
@@ -135,10 +136,10 @@
"User": "Utente", "User": "Utente",
"WAF": "Firewall dell'applicazione Web", "WAF": "Firewall dell'applicazione Web",
"SiteName": "Nome del sito", "SiteName": "Nome del sito",
"Language": "lingua", "Language": "Lingua",
"CustomCodes": "Codice personalizzato (stili e script)", "CustomCodes": "Codice personalizzato (stili e script)",
"CustomCodesDashboard": "Codice personalizzato per dashboard", "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", "CustomPublicDNSNameserversforDDNS": "Server dei nomi DNS pubblici personalizzati per DDNS",
"RealIPHeader": "Intestazione della richiesta IP reale", "RealIPHeader": "Intestazione della richiesta IP reale",
"UseDirectConnectingIP": "Utilizzare l'IP di connessione diretta", "UseDirectConnectingIP": "Utilizzare l'IP di connessione diretta",
@@ -147,8 +148,8 @@
"LoginFailed": "Accesso non riuscito", "LoginFailed": "Accesso non riuscito",
"BruteForceAttackingToken": "Segnalino di attacco di forza bruta", "BruteForceAttackingToken": "Segnalino di attacco di forza bruta",
"BruteForceAttackingAgentSecret": "Segreti proxy dell'attacco di forza bruta", "BruteForceAttackingAgentSecret": "Segreti proxy dell'attacco di forza bruta",
"NewUser": "nuovo utente", "NewUser": "Nuovo utente",
"Count": "contare", "Count": "Contare",
"LastBlockReason": "Motivo dell'ultimo divieto", "LastBlockReason": "Motivo dell'ultimo divieto",
"LastBlockTime": "L'ultima volta che è stato vietato" "LastBlockTime": "L'ultima volta che è stato vietato"
} }

View File

@@ -17,7 +17,9 @@
"NoRowsAreSelected": "未选择任何行", "NoRowsAreSelected": "未选择任何行",
"ThisOperationIsUnrecoverable": "这个操作将无法恢复!", "ThisOperationIsUnrecoverable": "这个操作将无法恢复!",
"TaskTriggeredSuccessfully": "任务触发成功", "TaskTriggeredSuccessfully": "任务触发成功",
"TheServerDoesNotOnline": "服务器不存在或者还未连接" "TheServerDoesNotOnline": "服务器不存在或者还未连接",
"InstallHostRequired": "设置中尚未填写Agent对接地址",
"UnknownIdentifier": "未知标识符"
}, },
"Login": "登录", "Login": "登录",
"Server": "服务器", "Server": "服务器",
@@ -137,7 +139,7 @@
"Language": "语言", "Language": "语言",
"CustomCodes": "自定义代码(样式和脚本)", "CustomCodes": "自定义代码(样式和脚本)",
"CustomCodesDashboard": "仪表板的自定义代码", "CustomCodesDashboard": "仪表板的自定义代码",
"DashboardOriginalHost": "仪表板服务器域名/IP无 CDN", "DashboardOriginalHost": "Agent对接地址【域名/IP:端口】",
"CustomPublicDNSNameserversforDDNS": "DDNS 的自定义公共 DNS 名称服务器", "CustomPublicDNSNameserversforDDNS": "DDNS 的自定义公共 DNS 名称服务器",
"RealIPHeader": "真实IP请求头", "RealIPHeader": "真实IP请求头",
"UseDirectConnectingIP": "使用直连 IP", "UseDirectConnectingIP": "使用直连 IP",
@@ -149,6 +151,5 @@
"NewUser": "新用户", "NewUser": "新用户",
"Count": "计数", "Count": "计数",
"LastBlockReason": "最后封禁原因", "LastBlockReason": "最后封禁原因",
"LastBlockTime": "最后封禁时间", "LastBlockTime": "最后封禁时间"
"Auto": "自动" }
}

View File

@@ -17,7 +17,9 @@
"NoRowsAreSelected": "未選擇任何行", "NoRowsAreSelected": "未選擇任何行",
"ThisOperationIsUnrecoverable": "這個操作將無法恢復!", "ThisOperationIsUnrecoverable": "這個操作將無法恢復!",
"TaskTriggeredSuccessfully": "任務觸發成功", "TaskTriggeredSuccessfully": "任務觸發成功",
"TheServerDoesNotOnline": "伺服器不存在或尚未連接" "TheServerDoesNotOnline": "伺服器不存在或尚未連接",
"InstallHostRequired": "設定中尚未填寫Agent對接位址",
"UnknownIdentifier": "未知標識符"
}, },
"Login": "登入", "Login": "登入",
"Server": "伺服器", "Server": "伺服器",
@@ -137,7 +139,7 @@
"Language": "語言", "Language": "語言",
"CustomCodes": "自訂程式碼(樣式和腳本)", "CustomCodes": "自訂程式碼(樣式和腳本)",
"CustomCodesDashboard": "儀表板的自訂程式碼", "CustomCodesDashboard": "儀表板的自訂程式碼",
"DashboardOriginalHost": "儀表板伺服器網域/IP無 CDN", "DashboardOriginalHost": "Agent對接位址【網域名稱/IP:連接埠】",
"CustomPublicDNSNameserversforDDNS": "DDNS 的自訂公共 DNS 名稱伺服器", "CustomPublicDNSNameserversforDDNS": "DDNS 的自訂公共 DNS 名稱伺服器",
"RealIPHeader": "真實IP請求頭", "RealIPHeader": "真實IP請求頭",
"UseDirectConnectingIP": "使用直連 IP", "UseDirectConnectingIP": "使用直連 IP",
@@ -149,6 +151,5 @@
"NewUser": "新用戶", "NewUser": "新用戶",
"Count": "計數", "Count": "計數",
"LastBlockReason": "最後封鎖原因", "LastBlockReason": "最後封鎖原因",
"LastBlockTime": "最後封鎖時間", "LastBlockTime": "最後封鎖時間"
"Auto": "自動" }
}

View File

@@ -105,11 +105,9 @@ export default function SettingsPage() {
if (e instanceof Error) setError(e); if (e instanceof Error) setError(e);
return; return;
} finally { } finally {
if (values.language != "auto") { if (values.language != i18n.language) {
i18n.changeLanguage(values.language); i18n.changeLanguage(values.language);
} else { }
i18n.changeLanguage(i18n.services.languageDetector.detect());
}
toast(t("Success")); toast(t("Success"));
} }
}; };

View File

@@ -5,7 +5,6 @@ export const settingCoverageTypes: Record<number, string> = {
} }
export const nezhaLang: Record<string, string> = { export const nezhaLang: Record<string, string> = {
"auto": i18next.t("Auto"),
"zh-CN": "简体中文(中国大陆)", "zh-CN": "简体中文(中国大陆)",
"zh-TW": "正體中文(台灣)", "zh-TW": "正體中文(台灣)",
"en-US": "English", "en-US": "English",