diff --git a/web/controller/setting.go b/web/controller/setting.go index 32eccefe..96223c28 100644 --- a/web/controller/setting.go +++ b/web/controller/setting.go @@ -41,7 +41,7 @@ func (a *SettingController) initRouter(g *gin.RouterGroup) { g.POST("/update", a.updateSetting) g.POST("/updateUser", a.updateUser) g.POST("/restartPanel", a.restartPanel) - g.GET("/getDefaultJsonConfig", a.getDefaultJsonConfig) + g.GET("/getDefaultJsonConfig", a.getDefaultXrayConfig) g.POST("/updateUserSecret", a.updateSecret) g.POST("/getUserSecret", a.getUserSecret) } @@ -55,15 +55,6 @@ func (a *SettingController) getAllSetting(c *gin.Context) { jsonObj(c, allSetting, nil) } -func (a *SettingController) getDefaultJsonConfig(c *gin.Context) { - defaultJsonConfig, err := a.settingService.GetDefaultJsonConfig() - if err != nil { - jsonMsg(c, I18nWeb(c, "pages.settings.toasts.getSettings"), err) - return - } - jsonObj(c, defaultJsonConfig, nil) -} - func (a *SettingController) getDefaultSettings(c *gin.Context) { type settingFunc func() (interface{}, error) @@ -169,3 +160,12 @@ func (a *SettingController) getUserSecret(c *gin.Context) { jsonObj(c, user, nil) } } + +func (a *SettingController) getDefaultXrayConfig(c *gin.Context) { + defaultJsonConfig, err := a.settingService.GetDefaultXrayConfig() + if err != nil { + jsonMsg(c, I18nWeb(c, "pages.settings.toasts.getSettings"), err) + return + } + jsonObj(c, defaultJsonConfig, nil) +} diff --git a/web/controller/xraySetting.go b/web/controller/xraySetting.go new file mode 100644 index 00000000..d244d030 --- /dev/null +++ b/web/controller/xraySetting.go @@ -0,0 +1,50 @@ +package controller + +import ( + "x-ui/web/service" + + "github.com/gin-gonic/gin" +) + +type XraySettingController struct { + XraySettingService service.XraySettingService + SettingService service.SettingService +} + +func NewXraySettingController(g *gin.RouterGroup) *XraySettingController { + a := &XraySettingController{} + a.initRouter(g) + return a +} + +func (a *XraySettingController) initRouter(g *gin.RouterGroup) { + g = g.Group("/xray") + + g.POST("/", a.getXraySetting) + g.POST("/update", a.updateSetting) + g.GET("/getDefaultJsonConfig", a.getDefaultXrayConfig) +} + +func (a *XraySettingController) getXraySetting(c *gin.Context) { + xraySetting, err := a.SettingService.GetXrayConfigTemplate() + if err != nil { + jsonMsg(c, I18nWeb(c, "pages.settings.toasts.getSettings"), err) + return + } + jsonObj(c, xraySetting, nil) +} + +func (a *XraySettingController) updateSetting(c *gin.Context) { + xraySetting := c.PostForm("xraySetting") + err := a.XraySettingService.SaveXraySetting(xraySetting) + jsonMsg(c, I18nWeb(c, "pages.settings.toasts.modifySettings"), err) +} + +func (a *XraySettingController) getDefaultXrayConfig(c *gin.Context) { + defaultJsonConfig, err := a.SettingService.GetDefaultXrayConfig() + if err != nil { + jsonMsg(c, I18nWeb(c, "pages.settings.toasts.getSettings"), err) + return + } + jsonObj(c, defaultJsonConfig, nil) +} diff --git a/web/controller/xui.go b/web/controller/xui.go index 700bd52c..5b4c0a18 100644 --- a/web/controller/xui.go +++ b/web/controller/xui.go @@ -7,8 +7,9 @@ import ( type XUIController struct { BaseController - inboundController *InboundController - settingController *SettingController + inboundController *InboundController + settingController *SettingController + xraySettingController *XraySettingController } func NewXUIController(g *gin.RouterGroup) *XUIController { @@ -24,9 +25,11 @@ func (a *XUIController) initRouter(g *gin.RouterGroup) { g.GET("/", a.index) g.GET("/inbounds", a.inbounds) g.GET("/settings", a.settings) + g.GET("/xray", a.xraySettings) a.inboundController = NewInboundController(g) a.settingController = NewSettingController(g) + a.xraySettingController = NewXraySettingController(g) } func (a *XUIController) index(c *gin.Context) { @@ -40,3 +43,7 @@ func (a *XUIController) inbounds(c *gin.Context) { func (a *XUIController) settings(c *gin.Context) { html(c, "settings.html", "pages.settings.title", nil) } + +func (a *XUIController) xraySettings(c *gin.Context) { + html(c, "xray.html", "pages.xray.title", nil) +} diff --git a/web/entity/entity.go b/web/entity/entity.go index 1428abe0..1c90305e 100644 --- a/web/entity/entity.go +++ b/web/entity/entity.go @@ -2,12 +2,10 @@ package entity import ( "crypto/tls" - "encoding/json" "net" "strings" "time" "x-ui/util/common" - "x-ui/xray" ) type Msg struct { @@ -27,36 +25,35 @@ type Pager struct { } type AllSetting struct { - WebListen string `json:"webListen" form:"webListen"` - WebDomain string `json:"webDomain" form:"webDomain"` - WebPort int `json:"webPort" form:"webPort"` - WebCertFile string `json:"webCertFile" form:"webCertFile"` - WebKeyFile string `json:"webKeyFile" form:"webKeyFile"` - WebBasePath string `json:"webBasePath" form:"webBasePath"` - SessionMaxAge int `json:"sessionMaxAge" form:"sessionMaxAge"` - ExpireDiff int `json:"expireDiff" form:"expireDiff"` - TrafficDiff int `json:"trafficDiff" form:"trafficDiff"` - TgBotEnable bool `json:"tgBotEnable" form:"tgBotEnable"` - TgBotToken string `json:"tgBotToken" form:"tgBotToken"` - TgBotChatId string `json:"tgBotChatId" form:"tgBotChatId"` - TgRunTime string `json:"tgRunTime" form:"tgRunTime"` - TgBotBackup bool `json:"tgBotBackup" form:"tgBotBackup"` - TgBotLoginNotify bool `json:"tgBotLoginNotify" form:"tgBotLoginNotify"` - TgCpu int `json:"tgCpu" form:"tgCpu"` - TgLang string `json:"tgLang" form:"tgLang"` - XrayTemplateConfig string `json:"xrayTemplateConfig" form:"xrayTemplateConfig"` - TimeLocation string `json:"timeLocation" form:"timeLocation"` - SecretEnable bool `json:"secretEnable" form:"secretEnable"` - SubEnable bool `json:"subEnable" form:"subEnable"` - SubListen string `json:"subListen" form:"subListen"` - SubPort int `json:"subPort" form:"subPort"` - SubPath string `json:"subPath" form:"subPath"` - SubDomain string `json:"subDomain" form:"subDomain"` - SubCertFile string `json:"subCertFile" form:"subCertFile"` - SubKeyFile string `json:"subKeyFile" form:"subKeyFile"` - SubUpdates int `json:"subUpdates" form:"subUpdates"` - SubEncrypt bool `json:"subEncrypt" form:"subEncrypt"` - SubShowInfo bool `json:"subShowInfo" form:"subShowInfo"` + WebListen string `json:"webListen" form:"webListen"` + WebDomain string `json:"webDomain" form:"webDomain"` + WebPort int `json:"webPort" form:"webPort"` + WebCertFile string `json:"webCertFile" form:"webCertFile"` + WebKeyFile string `json:"webKeyFile" form:"webKeyFile"` + WebBasePath string `json:"webBasePath" form:"webBasePath"` + SessionMaxAge int `json:"sessionMaxAge" form:"sessionMaxAge"` + ExpireDiff int `json:"expireDiff" form:"expireDiff"` + TrafficDiff int `json:"trafficDiff" form:"trafficDiff"` + TgBotEnable bool `json:"tgBotEnable" form:"tgBotEnable"` + TgBotToken string `json:"tgBotToken" form:"tgBotToken"` + TgBotChatId string `json:"tgBotChatId" form:"tgBotChatId"` + TgRunTime string `json:"tgRunTime" form:"tgRunTime"` + TgBotBackup bool `json:"tgBotBackup" form:"tgBotBackup"` + TgBotLoginNotify bool `json:"tgBotLoginNotify" form:"tgBotLoginNotify"` + TgCpu int `json:"tgCpu" form:"tgCpu"` + TgLang string `json:"tgLang" form:"tgLang"` + TimeLocation string `json:"timeLocation" form:"timeLocation"` + SecretEnable bool `json:"secretEnable" form:"secretEnable"` + SubEnable bool `json:"subEnable" form:"subEnable"` + SubListen string `json:"subListen" form:"subListen"` + SubPort int `json:"subPort" form:"subPort"` + SubPath string `json:"subPath" form:"subPath"` + SubDomain string `json:"subDomain" form:"subDomain"` + SubCertFile string `json:"subCertFile" form:"subCertFile"` + SubKeyFile string `json:"subKeyFile" form:"subKeyFile"` + SubUpdates int `json:"subUpdates" form:"subUpdates"` + SubEncrypt bool `json:"subEncrypt" form:"subEncrypt"` + SubShowInfo bool `json:"subShowInfo" form:"subShowInfo"` } func (s *AllSetting) CheckValid() error { @@ -107,13 +104,7 @@ func (s *AllSetting) CheckValid() error { s.WebBasePath += "/" } - xrayConfig := &xray.Config{} - err := json.Unmarshal([]byte(s.XrayTemplateConfig), xrayConfig) - if err != nil { - return common.NewError("xray template config invalid:", err) - } - - _, err = time.LoadLocation(s.TimeLocation) + _, err := time.LoadLocation(s.TimeLocation) if err != nil { return common.NewError("time location not exist:", s.TimeLocation) } diff --git a/web/service/setting.go b/web/service/setting.go index b1565e1f..933fff1b 100644 --- a/web/service/setting.go +++ b/web/service/setting.go @@ -70,7 +70,7 @@ func (s *SettingService) GetDefaultJsonConfig() (interface{}, error) { func (s *SettingService) GetAllSetting() (*entity.AllSetting, error) { db := database.GetDB() settings := make([]*model.Setting, 0) - err := db.Model(model.Setting{}).Find(&settings).Error + err := db.Model(model.Setting{}).Not("key = ?", "xrayTemplateConfig").Find(&settings).Error if err != nil { return nil, err } @@ -426,3 +426,12 @@ func (s *SettingService) UpdateAllSetting(allSetting *entity.AllSetting) error { } return common.Combine(errs...) } + +func (s *SettingService) GetDefaultXrayConfig() (interface{}, error) { + var jsonData interface{} + err := json.Unmarshal([]byte(xrayTemplateConfig), &jsonData) + if err != nil { + return nil, err + } + return jsonData, nil +} diff --git a/web/service/xraySettings.go b/web/service/xraySettings.go new file mode 100644 index 00000000..4550bde2 --- /dev/null +++ b/web/service/xraySettings.go @@ -0,0 +1,28 @@ +package service + +import ( + _ "embed" + "encoding/json" + "x-ui/util/common" + "x-ui/xray" +) + +type XraySettingService struct { + SettingService +} + +func (s *XraySettingService) SaveXraySetting(newXraySettings string) error { + if err := s.CheckXrayConfig(newXraySettings); err != nil { + return err + } + return s.SettingService.saveSetting("xrayTemplateConfig", newXraySettings) +} + +func (s *XraySettingService) CheckXrayConfig(XrayTemplateConfig string) error { + xrayConfig := &xray.Config{} + err := json.Unmarshal([]byte(XrayTemplateConfig), xrayConfig) + if err != nil { + return common.NewError("xray template config invalid:", err) + } + return nil +} diff --git a/web/translation/translate.en_US.toml b/web/translation/translate.en_US.toml index 88ae4067..8790beee 100644 --- a/web/translation/translate.en_US.toml +++ b/web/translation/translate.en_US.toml @@ -12,7 +12,7 @@ "protocol" = "Protocol" "search" = "Search" "filter" = "Filter" -"loading" = "Loading" +"loading" = "Loading..." "second" = "Second" "minute" = "Minute" "hour" = "Hour" @@ -37,7 +37,9 @@ "enabled" = "Enabled" "disabled" = "Disabled" "depleted" = "Depleted" -"depletingSoon" = "Depleting soon" +"depletingSoon" = "Depleting" +"offline" = "Offline" +"online" = "Online" "domainName" = "Domain name" "monitor" = "Listening IP" "certificate" = "Certificate" @@ -54,6 +56,7 @@ "dashboard" = "System Status" "inbounds" = "Inbounds" "settings" = "Panel Settings" +"xray" = "Xray Settings" "logout" = "Logout" "link" = "Other" @@ -121,6 +124,8 @@ "modifyInbound" = "Modify Inbound" "deleteInbound" = "Delete Inbound" "deleteInboundContent" = "Confirm deletion of inbound?" +"deleteClient" = "Delete Client" +"deleteClientContent" = "Are you sure you want to delete client?" "resetTrafficContent" = "Confirm traffic reset?" "copyLink" = "Copy Link" "address" = "Address" @@ -132,8 +137,8 @@ "totalFlow" = "Total Flow" "leaveBlankToNeverExpire" = "Leave Blank to Never Expire" "noRecommendKeepDefault" = "No special requirements to maintain default settings" -"certificatePath" = "Certificate File Path" -"certificateContent" = "Certificate File Content" +"certificatePath" = "File Path" +"certificateContent" = "File Content" "publicKeyPath" = "Public Key Path" "publicKeyContent" = "Public Key Content" "keyPath" = "Private Key Path" @@ -169,6 +174,7 @@ "realityDesc" = "Xray core needs to be 1.8.0 or higher." "telegramDesc" = "use Telegram ID without @ or chat IDs ( you can get it here @userinfobot or use '/id' command in bot )" "subscriptionDesc" = "you can find your sub link on Details, also you can use the same name for several configurations" +"info" = "Info" [pages.client] "add" = "Add Client" @@ -185,6 +191,8 @@ "delayedStart" = "Start after first use" "expireDays" = "Expire days" "days" = "day(s)" +"renew" = "Auto renew" +"renewDesc" = "Auto renew days after expiration. 0 = disable" [pages.inbounds.toasts] "obtain" = "Obtain" @@ -216,7 +224,6 @@ "resetDefaultConfig" = "Reset to Default Configuration" "panelSettings" = "Panel Settings" "securitySettings" = "Security Settings" -"xrayConfiguration" = "Xray Configuration" "TGBotSettings" = "Telegram Bot Settings" "panelListeningIP" = "Panel Listening IP" "panelListeningIPDesc" = "Leave blank by default to monitor all IPs." @@ -278,8 +285,8 @@ "subShowInfo" = "Show usage info" "subShowInfoDesc" = "Show remianed traffic and date after config name" -[pages.settings.templates] -"title" = "Templates" +[pages.xray] +"title" = "Xray Settings" "basicTemplate" = "Basic Template" "advancedTemplate" = "Advanced Template" "completeTemplate" = "Complete Template" diff --git a/web/translation/translate.es_ES.toml b/web/translation/translate.es_ES.toml index 31cd2aff..36e21d42 100644 --- a/web/translation/translate.es_ES.toml +++ b/web/translation/translate.es_ES.toml @@ -12,7 +12,7 @@ "protocol" = "Protocolo" "search" = "Buscar" "filter" = "Filtrar" -"loading" = "Cargando" +"loading" = "Cargando..." "second" = "Segundo" "minute" = "Minuto" "hour" = "Hora" @@ -37,7 +37,9 @@ "enabled" = "Habilitado" "disabled" = "Deshabilitado" "depleted" = "Agotado" -"depletingSoon" = "Agotándose pronto" +"depletingSoon" = "Agotándose" +"offline" = "fuera de línea" +"online" = "en línea" "domainName" = "Nombre de dominio" "monitor" = "Listening IP" "certificate" = "Certificado" @@ -54,6 +56,7 @@ "dashboard" = "Estado del Sistema" "inbounds" = "Entradas" "settings" = "Configuraciones" +"xray" = "Configuración Xray" "logout" = "Cerrar Sesión" "link" = "Otro" @@ -121,6 +124,8 @@ "modifyInbound" = "Modificar Entrada" "deleteInbound" = "Eliminar Entrada" "deleteInboundContent" = "¿Confirmar eliminación de entrada?" +"deleteClient" = "Eliminar cliente" +"deleteClientContent" = "¿Está seguro de que desea eliminar el cliente?" "resetTrafficContent" = "¿Confirmar restablecimiento de tráfico?" "copyLink" = "Copiar Enlace" "address" = "Dirección" @@ -132,8 +137,8 @@ "totalFlow" = "Flujo Total" "leaveBlankToNeverExpire" = "Dejar en Blanco para Nunca Expirar" "noRecommendKeepDefault" = "No hay requisitos especiales para mantener la configuración predeterminada" -"certificatePath" = "Ruta del Archivo de Certificado" -"certificateContent" = "Contenido del Archivo de Certificado" +"certificatePath" = "Ruta del Archivo" +"certificateContent" = "Contenido del Archivo" "publicKeyPath" = "Ruta de la Clave Pública" "publicKeyContent" = "Contenido de la Clave Pública" "keyPath" = "Ruta de la Clave Privada" @@ -169,6 +174,7 @@ "realityDesc" = "La versión del núcleo de Xray debe ser 1.8.0 o superior." "telegramDesc" = "Utiliza el ID de Telegram sin @ o los IDs de chat (puedes obtenerlo aquí @userinfobot o usando el comando '/id' en el bot)." "subscriptionDesc" = "Puedes encontrar tu enlace de suscripción en Detalles, también puedes usar el mismo nombre para varias configuraciones." +"info" = "Info" [pages.client] "add" = "Agregar Cliente" @@ -185,6 +191,8 @@ "delayedStart" = "Iniciar después del primer uso" "expireDays" = "Días de Expiración" "days" = "día(s)" +"renew" = "Renovación automática" +"renewDesc" = "Renovación automática días después del vencimiento. 0 = deshabilitar" [pages.inbounds.toasts] "obtain" = "Recibir" @@ -216,7 +224,6 @@ "resetDefaultConfig" = "Restablecer a Configuración Predeterminada" "panelSettings" = "Configuraciones del Panel" "securitySettings" = "Configuraciones de Seguridad" -"xrayConfiguration" = "Configuración de Xray" "TGBotSettings" = "Configuraciones de Bot de Telegram" "panelListeningIP" = "IP de Escucha del Panel" "panelListeningIPDesc" = "Dejar en blanco por defecto para monitorear todas las IPs." @@ -278,8 +285,8 @@ "subShowInfo" = "Mostrar información de uso" "subShowInfoDesc" = "Mostrar tráfico restante y fecha después del nombre de configuración." -[pages.settings.templates] -"title" = "Plantillas" +[pages.xray] +"title" = "Xray Configuración" "basicTemplate" = "Plantilla Básica" "advancedTemplate" = "Plantilla Avanzada" "completeTemplate" = "Plantilla Completa" diff --git a/web/translation/translate.fa_IR.toml b/web/translation/translate.fa_IR.toml index c95d135e..6d73fd7b 100644 --- a/web/translation/translate.fa_IR.toml +++ b/web/translation/translate.fa_IR.toml @@ -38,6 +38,8 @@ "disabled" = "غیرفعال" "depleted" = "منقضی" "depletingSoon" = "در حال انقضا" +"offline" = "آفلاین" +"online" = "آنلاین" "domainName" = "آدرس دامنه" "monitor" = "آی پی اتصال" "certificate" = "گواهی دیجیتال" @@ -54,6 +56,7 @@ "dashboard" = "وضعیت سیستم" "inbounds" = "سرویس ها" "settings" = "تنظیمات پنل" +"xray" = "الگوی ایکس‌ری" "logout" = "خروج" "link" = "دیگر" @@ -121,6 +124,8 @@ "modifyInbound" = "ویرایش سرویس" "deleteInbound" = "حذف سرویس" "deleteInboundContent" = "آیا مطمئن به حذف سرویس هستید ؟" +"deleteClient" = "حذف کاربر" +"deleteClientContent" = "آیا مطمئن به حذف کاربر هستید ؟" "resetTrafficContent" = "آیا مطمئن به ریست ترافیک هستید ؟" "copyLink" = "کپی لینک" "address" = "آدرس" @@ -169,6 +174,7 @@ "realityDesc" = "هسته Xray باید 1.8.0 و بالاتر باشد" "telegramDesc" = "از آیدی تلگرام بدون @ یا آیدی چت استفاده کنید (می توانید آن را از اینجا دریافت کنید @userinfobot یا در ربات دستور '/id' را وارد کنید)" "subscriptionDesc" = "می توانید ساب لینک خود را در جزئیات پیدا کنید، همچنین می توانید از همین نام برای چندین کانفیگ استفاده کنید" +"info" = "اطلاعات" [pages.client] "add" = "کاربر جدید" @@ -185,6 +191,8 @@ "delayedStart" = "شروع بعد از اولین استفاده" "expireDays" = "روزهای اعتبار" "days" = "(روز)" +"renew" = "تمدید خودکار" +"renewDesc" = "روزهای تمدید خودکار پس از انقضا. 0 = غیرفعال" [pages.inbounds.toasts] "obtain" = "Obtain" @@ -216,7 +224,6 @@ "resetDefaultConfig" = "برگشت به تنظیمات پیشفرض" "panelSettings" = "تنظیمات پنل" "securitySettings" = "تنظیمات امنیتی" -"xrayConfiguration" = "تنظیمات Xray" "TGBotSettings" = "تنظیمات ربات تلگرام" "panelListeningIP" = "محدودیت آی پی پنل" "panelListeningIPDesc" = "برای استفاده از تمام آی‌پیها به طور پیش فرض خالی بگذارید" diff --git a/web/translation/translate.ru_RU.toml b/web/translation/translate.ru_RU.toml index 5cb89a17..242ed665 100644 --- a/web/translation/translate.ru_RU.toml +++ b/web/translation/translate.ru_RU.toml @@ -12,7 +12,7 @@ "protocol" = "Протокол" "search" = "Поиск" "filter" = "Фильтр" -"loading" = "Загрузка" +"loading" = "Загрузка..." "second" = "Секунда" "minute" = "Минута" "hour" = "Час" @@ -38,6 +38,8 @@ "disabled" = "Отключено" "depleted" = "Исчерпано" "depletingSoon" = "Почти исчерпано" +"offline" = "Офлайн" +"online" = "Онлайн" "domainName" = "Домен" "monitor" = "Порт IP" "certificate" = "Сертификат" @@ -54,6 +56,7 @@ "dashboard" = "Статус системы" "inbounds" = "Подключения" "settings" = "Настройки панели" +"xray" = "Xray Настройки" "logout" = "Выход" "link" = "Прочее" @@ -132,8 +135,8 @@ "totalFlow" = "Общий расход" "leaveBlankToNeverExpire" = "Оставьте пустым, чтобы не истекало" "noRecommendKeepDefault" = "Нет требований для сохранения настроек по умолчанию" -"certificatePath" = "Путь файла сертификата" -"certificateContent" = "Содержимое файла сертификата" +"certificatePath" = "Путь файла" +"certificateContent" = "Содержимое файла" "publicKeyPath" = "Путь к публичному ключу" "publicKeyContent" = "Содержимое публичного ключа" "keyPath" = "Путь к приватному ключу" @@ -169,6 +172,7 @@ "realityDesc" = "Версия Xray должна быть не ниже 1.8.0" "telegramDesc" = "Используйте идентификатор Telegram без символа @ или идентификатора чата (можно получить его здесь @userinfobot или использовать команду '/id' в боте)" "subscriptionDesc" = "Вы можете найти свою ссылку подписки в разделе 'Подробнее', также вы можете использовать одно и то же имя для нескольких конфигураций" +"info" = "Информация" [pages.client] "add" = "Добавить пользователя" @@ -185,6 +189,8 @@ "delayedStart" = "Начать с момента первого подключения" "expireDays" = "Срок действия" "days" = "дней" +"renew" = "Автопродление" +"renewDesc" = "Автоматическое продление через несколько дней после истечения срока действия. 0 = отключить" [pages.inbounds.toasts] "obtain" = "Получить" @@ -278,8 +284,8 @@ "subShowInfo" = "Показать информацию об использовании" "subShowInfoDesc" = "Показывать восстановленный трафик и дату после имени конфигурации" -[pages.settings.templates] -"title" = "Шаблоны" +[pages.xray] +"title" = "Xray Настройки" "basicTemplate" = "Базовый шаблон" "advancedTemplate" = "Расширенный шаблон" "completeTemplate" = "Полный шаблон" diff --git a/web/translation/translate.vi_VN.toml b/web/translation/translate.vi_VN.toml index c71e0053..27b0cca7 100644 --- a/web/translation/translate.vi_VN.toml +++ b/web/translation/translate.vi_VN.toml @@ -1,6 +1,6 @@ "username" = "Tên người dùng" "password" = "Mật khẩu" -"login" = "Đăng nhập" +"login" = "Đăng nhập..." "confirm" = "Xác nhận" "cancel" = "Hủy bỏ" "close" = "Đóng" @@ -37,7 +37,9 @@ "enabled" = "Đã kích hoạt" "disabled" = "Đã tắt" "depleted" = "Đã cạn kiệt" -"depletingSoon" = "Sắp cạn kiệt" +"depletingSoon" = "Đang cạn kiệt" +"offline" = "Ngoại tuyến" +"online" = "Ngoại tuyến" "domainName" = "Tên miền" "monitor" = "Listening IP" "certificate" = "Chứng chỉ" @@ -55,6 +57,7 @@ "inbounds" = "Inbounds" "settings" = "Cài đặt bảng điều khiển" "logout" = "Đăng xuất" +"xray" = "Xray Cài đặt" "link" = "Khác" [pages.login] @@ -121,6 +124,8 @@ "modifyInbound" = "Chỉnh sửa điểm vào (Inbound)" "deleteInbound" = "Xóa điểm vào (Inbound)" "deleteInboundContent" = "Xác nhận xóa điểm vào? (Inbound)" +"deleteClient" = "Xóa khách hàng" +"deleteClientContent" = "Bạn có chắc chắn muốn xóa ứng dụng khách không?" "resetTrafficContent" = "Xác nhận đặt lại lưu lượng?" "copyLink" = "Sao chép liên kết" "address" = "Địa chỉ" @@ -132,8 +137,8 @@ "totalFlow" = "Tổng lưu lượng" "leaveBlankToNeverExpire" = "Để trống để không bao giờ hết hạn" "noRecommendKeepDefault" = "Không yêu cầu đặc biệt để giữ nguyên cài đặt mặc định" -"certificatePath" = "Đường dẫn tập tin chứng chỉ" -"certificateContent" = "Nội dung tập tin chứng chỉ" +"certificatePath" = "Đường dẫn tập" +"certificateContent" = "Nội dung tập" "publicKeyPath" = "Đường dẫn khóa công khai" "publicKeyContent" = "Nội dung khóa công khai" "keyPath" = "Đường dẫn khóa riêng tư" @@ -169,6 +174,7 @@ "realityDesc" = "Xray core cần phiên bản 1.8.0 hoặc cao hơn." "telegramDesc" = "Sử dụng Telegram ID mà không cần ký hiệu @ hoặc chat IDs (bạn có thể nhận được nó ở đây @userinfobot hoặc sử dụng lệnh '/id' trong bot)" "subscriptionDesc" = "Bạn có thể tìm liên kết đăng ký của mình trong Chi tiết, cũng như bạn có thể sử dụng cùng tên cho nhiều cấu hình khác nhau" +"info" = "Thông tin" [pages.client] "add" = "Thêm Client" @@ -185,6 +191,8 @@ "delayedStart" = "Bắt đầu sau khi sử dụng lần đầu" "expireDays" = "Số ngày hết hạn" "days" = "ngày" +"renew" = "Tự động gia hạn" +"renewDesc" = "Tự động gia hạn những ngày sau khi hết hạn. 0 = tắt" [pages.inbounds.toasts] "obtain" = "Nhận" @@ -278,8 +286,8 @@ "subShowInfo" = "Hiển thị thông tin sử dụng" "subShowInfoDesc" = "Hiển thị lưu lượng truy cập còn lại và ngày sau tên cấu hình" -[pages.settings.templates] -"title" = "Mẫu" +[pages.xray] +"title" = "Xray Cài đặt" "basicTemplate" = "Mẫu Cơ bản" "advancedTemplate" = "Mẫu Nâng cao" "completeTemplate" = "Mẫu Đầy đủ" diff --git a/web/translation/translate.zh_Hans.toml b/web/translation/translate.zh_Hans.toml index 1483b556..d982b939 100644 --- a/web/translation/translate.zh_Hans.toml +++ b/web/translation/translate.zh_Hans.toml @@ -12,7 +12,7 @@ "protocol" = "协议" "search" = "搜尋" "filter" = "过滤器" -"loading" = "加载中" +"loading" = "加载中..." "second" = "秒" "minute" = "分钟" "hour" = "小时" @@ -38,6 +38,8 @@ "disabled" = "关闭" "depleted" = "耗尽" "depletingSoon" = "即将耗尽" +"offline" = "离线" +"online" = "在线" "domainName" = "域名" "monitor" = "监听" "certificate" = "证书" @@ -54,6 +56,7 @@ "dashboard" = "系统状态" "inbounds" = "入站列表" "settings" = "面板设置" +"xray" = "Xray 设置" "logout" = "退出登录" "link" = "其他" @@ -121,6 +124,8 @@ "modifyInbound" = "修改入站" "deleteInbound" = "删除入站" "deleteInboundContent" = "确定要删除入站吗?" +"deleteClient" = "删除客户端" +"deleteClientContent" = "您确定要删除客户端吗?" "resetTrafficContent" = "确定要重置流量吗?" "copyLink" = "复制链接" "address" = "地址" @@ -132,8 +137,8 @@ "totalFlow" = "总流量" "leaveBlankToNeverExpire" = "留空则永不到期" "noRecommendKeepDefault" = "没有特殊需求保持默认即可" -"certificatePath" = "证书文件路径" -"certificateContent" = "证书文件内容" +"certificatePath" = "文件路径" +"certificateContent" = "文件内容" "publicKeyPath" = "公钥文件路径" "publicKeyContent" = "公钥内容" "keyPath" = "密钥文件路径" @@ -169,6 +174,7 @@ "realityDesc" = "Xray核心需要1.8.0及以上版本" "telegramDesc" = "使用 Telegram ID,不包含 @ 符号或聊天 ID(可以在 @userinfobot 处获取,或在机器人中使用'/id'命令)" "subscriptionDesc" = "您可以在详细信息上找到您的子链接,也可以对多个配置使用相同的名称" +"info" = "信息" [pages.client] "add" = "添加客户端" @@ -185,6 +191,8 @@ "delayedStart" = "首次使用后开始" "expireDays" = "过期天数" "days" = "天" +"renew" = "自动续订" +"renewDesc" = "过期后自动续订。0 = 禁用" [pages.inbounds.toasts] "obtain" = "获取" @@ -216,7 +224,6 @@ "resetDefaultConfig" = "重置为默认配置" "panelSettings" = "面板配置" "securitySettings" = "安全设定" -"xrayConfiguration" = "xray 相关设置" "TGBotSettings" = "TG提醒相关设置" "panelListeningIP" = "面板监听 IP" "panelListeningIPDesc" = "默认留空监听所有 IP" @@ -278,8 +285,8 @@ "subShowInfo" = "显示使用信息" "subShowInfoDesc" = "在配置名称后显示剩余流量和日期" -[pages.settings.templates] -"title" = "模板" +[pages.xray] +"title" = "Xray 设置" "basicTemplate" = "基本模板" "advancedTemplate" = "高级模板部件" "completeTemplate" = "Xray 配置的完整模板"