Browse Source

separate xray page #1286

Alireza Ahmadi 1 year ago
parent
commit
2a8da2ba3c

+ 10 - 10
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)
+}

+ 50 - 0
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)
+}

+ 9 - 2
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)
+}

+ 30 - 39
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)
 	}

+ 10 - 1
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
+}

+ 28 - 0
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
+}

+ 14 - 7
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"

+ 14 - 7
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"

+ 8 - 1
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" = "برای استفاده از تمام آی‌پیها به طور پیش فرض خالی بگذارید"

+ 11 - 5
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" = "Полный шаблон"

+ 14 - 6
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 đủ"

+ 13 - 6
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 配置的完整模板"