Browse Source

refactor: remove ChatGPTMessages from config structure and update URL unescaping logic

Jacky 3 weeks ago
parent
commit
0275f011a8
59 changed files with 4303 additions and 3135 deletions
  1. 7 19
      api/config/add.go
  2. 9 35
      api/config/get.go
  3. 2 15
      api/config/list.go
  4. 3 12
      api/config/mkdir.go
  5. 8 35
      api/config/modify.go
  6. 2 10
      api/config/rename.go
  7. 31 0
      api/openai/record.go
  8. 2 0
      api/openai/router.go
  9. 2 1
      api/sites/advance.go
  10. 24 37
      api/sites/site.go
  11. 2 1
      api/streams/advance.go
  12. 1 1
      api/streams/duplicate.go
  13. 37 53
      api/streams/streams.go
  14. 3 0
      app/components.d.ts
  15. 3 0
      app/src/api/openai.ts
  16. 0 2
      app/src/api/site.ts
  17. 20 426
      app/src/components/ChatGPT/ChatGPT.vue
  18. 292 0
      app/src/components/ChatGPT/ChatMessage.vue
  19. 82 0
      app/src/components/ChatGPT/ChatMessageInput.vue
  20. 131 0
      app/src/components/ChatGPT/ChatMessageList.vue
  21. 114 0
      app/src/components/ChatGPT/chatService.ts
  22. 275 0
      app/src/components/ChatGPT/chatgpt.ts
  23. 110 0
      app/src/components/ChatGPT/composables/useTypewriter.ts
  24. 7 0
      app/src/components/ChatGPT/index.ts
  25. 26 0
      app/src/components/ChatGPT/markdown.ts
  26. 9 0
      app/src/components/ChatGPT/types.ts
  27. 86 0
      app/src/components/ChatGPT/utils.ts
  28. 2 1
      app/src/components/CodeEditor/CodeEditor.vue
  29. 1 1
      app/src/components/PageHeader/PageHeader.vue
  30. 1 1
      app/src/components/PortScanner/PortScannerCompact.vue
  31. 177 161
      app/src/language/ar/app.po
  32. 208 181
      app/src/language/de_DE/app.po
  33. 30 30
      app/src/language/en/app.po
  34. 208 184
      app/src/language/es/app.po
  35. 217 189
      app/src/language/fr_FR/app.po
  36. 262 169
      app/src/language/ja_JP/app.po
  37. 254 169
      app/src/language/ko_KR/app.po
  38. 30 30
      app/src/language/messages.pot
  39. 207 181
      app/src/language/pt_PT/app.po
  40. 197 179
      app/src/language/ru_RU/app.po
  41. 207 180
      app/src/language/tr_TR/app.po
  42. 195 181
      app/src/language/uk_UA/app.po
  43. 209 190
      app/src/language/vi_VN/app.po
  44. 242 171
      app/src/language/zh_CN/app.po
  45. 245 173
      app/src/language/zh_TW/app.po
  46. 0 6
      app/src/views/config/ConfigEditor.vue
  47. 4 5
      app/src/views/site/site_edit/SiteEdit.vue
  48. 1 1
      app/src/views/site/site_edit/components/RightPanel/Basic.vue
  49. 0 2
      app/src/views/site/site_edit/components/RightPanel/Chat.vue
  50. 1 1
      app/src/views/site/site_edit/components/RightPanel/ConfigTemplate.vue
  51. 15 7
      app/src/views/site/site_edit/components/RightPanel/RightPanel.vue
  52. 49 41
      app/src/views/site/site_edit/components/SiteEditor/SiteEditor.vue
  53. 5 12
      app/src/views/site/site_edit/components/SiteEditor/store.ts
  54. 1 2
      app/src/views/stream/components/RightPanel/Chat.vue
  55. 6 12
      app/src/views/stream/store.ts
  56. 1 1
      app/src/views/terminal/Terminal.vue
  57. 14 16
      internal/config/config.go
  58. 17 0
      internal/helper/unescape_url.go
  59. 9 11
      internal/site/type.go

+ 7 - 19
api/config/add.go

@@ -2,7 +2,6 @@ package config
 
 import (
 	"net/http"
-	"net/url"
 	"os"
 	"path/filepath"
 	"time"
@@ -13,7 +12,6 @@ import (
 	"github.com/0xJacky/Nginx-UI/model"
 	"github.com/0xJacky/Nginx-UI/query"
 	"github.com/gin-gonic/gin"
-	"github.com/sashabaranov/go-openai"
 	"github.com/uozi-tech/cosy"
 )
 
@@ -31,17 +29,8 @@ func AddConfig(c *gin.Context) {
 	content := json.Content
 
 	// Decode paths from URL encoding
-	decodedBaseDir, err := url.QueryUnescape(json.BaseDir)
-	if err != nil {
-		cosy.ErrHandler(c, err)
-		return
-	}
-
-	decodedName, err := url.QueryUnescape(name)
-	if err != nil {
-		cosy.ErrHandler(c, err)
-		return
-	}
+	decodedBaseDir := helper.UnescapeURL(json.BaseDir)
+	decodedName := helper.UnescapeURL(name)
 
 	dir := nginx.GetConfPath(decodedBaseDir)
 	path := filepath.Join(dir, decodedName)
@@ -68,7 +57,7 @@ func AddConfig(c *gin.Context) {
 		}
 	}
 
-	err = os.WriteFile(path, []byte(content), 0644)
+	err := os.WriteFile(path, []byte(content), 0644)
 	if err != nil {
 		cosy.ErrHandler(c, err)
 		return
@@ -107,10 +96,9 @@ func AddConfig(c *gin.Context) {
 	}
 
 	c.JSON(http.StatusOK, config.Config{
-		Name:            name,
-		Content:         content,
-		ChatGPTMessages: make([]openai.ChatCompletionMessage, 0),
-		FilePath:        path,
-		ModifiedAt:      time.Now(),
+		Name:       name,
+		Content:    content,
+		FilePath:   path,
+		ModifiedAt: time.Now(),
 	})
 }

+ 9 - 35
api/config/get.go

@@ -2,7 +2,6 @@ package config
 
 import (
 	"net/http"
-	"net/url"
 	"os"
 	"path/filepath"
 
@@ -11,25 +10,11 @@ import (
 	"github.com/0xJacky/Nginx-UI/internal/nginx"
 	"github.com/0xJacky/Nginx-UI/query"
 	"github.com/gin-gonic/gin"
-	"github.com/sashabaranov/go-openai"
 	"github.com/uozi-tech/cosy"
 )
 
 func GetConfig(c *gin.Context) {
-	relativePath := c.Param("path")
-
-	// Ensure the path is correctly decoded - handle cases where it might be encoded multiple times
-	decodedPath := relativePath
-	var err error
-	// Try decoding until the path no longer changes
-	for {
-		newDecodedPath, decodeErr := url.PathUnescape(decodedPath)
-		if decodeErr != nil || newDecodedPath == decodedPath {
-			break
-		}
-		decodedPath = newDecodedPath
-	}
-	relativePath = decodedPath
+	relativePath := helper.UnescapeURL(c.Param("path"))
 
 	absPath := nginx.GetConfPath(relativePath)
 	if !helper.IsUnderDirectory(absPath, nginx.GetConfPath()) {
@@ -50,18 +35,8 @@ func GetConfig(c *gin.Context) {
 		cosy.ErrHandler(c, err)
 		return
 	}
-	q := query.Config
-	g := query.ChatGPTLog
-	chatgpt, err := g.Where(g.Name.Eq(absPath)).FirstOrCreate()
-	if err != nil {
-		cosy.ErrHandler(c, err)
-		return
-	}
-
-	if chatgpt.Content == nil {
-		chatgpt.Content = make([]openai.ChatCompletionMessage, 0)
-	}
 
+	q := query.Config
 	cfg, err := q.Where(q.Filepath.Eq(absPath)).FirstOrInit()
 	if err != nil {
 		cosy.ErrHandler(c, err)
@@ -69,13 +44,12 @@ func GetConfig(c *gin.Context) {
 	}
 
 	c.JSON(http.StatusOK, config.Config{
-		Name:            stat.Name(),
-		Content:         string(content),
-		ChatGPTMessages: chatgpt.Content,
-		FilePath:        absPath,
-		ModifiedAt:      stat.ModTime(),
-		Dir:             filepath.Dir(relativePath),
-		SyncNodeIds:     cfg.SyncNodeIds,
-		SyncOverwrite:   cfg.SyncOverwrite,
+		Name:          stat.Name(),
+		Content:       string(content),
+		FilePath:      absPath,
+		ModifiedAt:    stat.ModTime(),
+		Dir:           filepath.Dir(relativePath),
+		SyncNodeIds:   cfg.SyncNodeIds,
+		SyncOverwrite: cfg.SyncOverwrite,
 	})
 }

+ 2 - 15
api/config/list.go

@@ -2,11 +2,11 @@ package config
 
 import (
 	"net/http"
-	"net/url"
 	"os"
 	"strings"
 
 	"github.com/0xJacky/Nginx-UI/internal/config"
+	"github.com/0xJacky/Nginx-UI/internal/helper"
 	"github.com/gin-gonic/gin"
 	"github.com/uozi-tech/cosy"
 )
@@ -20,20 +20,7 @@ func GetConfigs(c *gin.Context) {
 	encodedDir := c.DefaultQuery("dir", "/")
 
 	// Handle cases where the path might be encoded multiple times
-	dir := encodedDir
-	// Try decoding until the path no longer changes
-	for {
-		newDecodedDir, decodeErr := url.QueryUnescape(dir)
-		if decodeErr != nil {
-			cosy.ErrHandler(c, decodeErr)
-			return
-		}
-
-		if newDecodedDir == dir {
-			break
-		}
-		dir = newDecodedDir
-	}
+	dir := helper.UnescapeURL(encodedDir)
 
 	// Ensure the directory path format is correct
 	dir = strings.TrimSpace(dir)

+ 3 - 12
api/config/mkdir.go

@@ -2,7 +2,6 @@ package config
 
 import (
 	"net/http"
-	"net/url"
 	"os"
 
 	"github.com/0xJacky/Nginx-UI/internal/helper"
@@ -21,17 +20,9 @@ func Mkdir(c *gin.Context) {
 	}
 
 	// Ensure paths are properly URL unescaped
-	decodedBasePath, err := url.QueryUnescape(json.BasePath)
-	if err != nil {
-		cosy.ErrHandler(c, err)
-		return
-	}
+	decodedBasePath := helper.UnescapeURL(json.BasePath)
 
-	decodedFolderName, err := url.QueryUnescape(json.FolderName)
-	if err != nil {
-		cosy.ErrHandler(c, err)
-		return
-	}
+	decodedFolderName := helper.UnescapeURL(json.FolderName)
 
 	fullPath := nginx.GetConfPath(decodedBasePath, decodedFolderName)
 	if !helper.IsUnderDirectory(fullPath, nginx.GetConfPath()) {
@@ -41,7 +32,7 @@ func Mkdir(c *gin.Context) {
 		})
 		return
 	}
-	err = os.Mkdir(fullPath, 0755)
+	err := os.Mkdir(fullPath, 0755)
 	if err != nil {
 		cosy.ErrHandler(c, err)
 		return

+ 8 - 35
api/config/modify.go

@@ -2,7 +2,6 @@ package config
 
 import (
 	"net/http"
-	"net/url"
 	"path/filepath"
 	"time"
 
@@ -12,7 +11,6 @@ import (
 	"github.com/0xJacky/Nginx-UI/model"
 	"github.com/0xJacky/Nginx-UI/query"
 	"github.com/gin-gonic/gin"
-	"github.com/sashabaranov/go-openai"
 	"github.com/uozi-tech/cosy"
 	"gorm.io/gen/field"
 )
@@ -22,20 +20,7 @@ type EditConfigJson struct {
 }
 
 func EditConfig(c *gin.Context) {
-	relativePath := c.Param("path")
-
-	// Ensure the path is correctly decoded - handle cases where it might be encoded multiple times
-	decodedPath := relativePath
-	var err error
-	// Try decoding until the path no longer changes
-	for {
-		newDecodedPath, decodeErr := url.PathUnescape(decodedPath)
-		if decodeErr != nil || newDecodedPath == decodedPath {
-			break
-		}
-		decodedPath = newDecodedPath
-	}
-	relativePath = decodedPath
+	relativePath := helper.UnescapeURL(c.Param("path"))
 
 	var json struct {
 		Content       string   `json:"content"`
@@ -83,25 +68,13 @@ func EditConfig(c *gin.Context) {
 		return
 	}
 
-	g := query.ChatGPTLog
-	chatgpt, err := g.Where(g.Name.Eq(absPath)).FirstOrCreate()
-	if err != nil {
-		cosy.ErrHandler(c, err)
-		return
-	}
-
-	if chatgpt.Content == nil {
-		chatgpt.Content = make([]openai.ChatCompletionMessage, 0)
-	}
-
 	c.JSON(http.StatusOK, config.Config{
-		Name:            filepath.Base(absPath),
-		Content:         content,
-		ChatGPTMessages: chatgpt.Content,
-		FilePath:        absPath,
-		ModifiedAt:      time.Now(),
-		Dir:             filepath.Dir(relativePath),
-		SyncNodeIds:     cfg.SyncNodeIds,
-		SyncOverwrite:   cfg.SyncOverwrite,
+		Name:          filepath.Base(absPath),
+		Content:       content,
+		FilePath:      absPath,
+		ModifiedAt:    time.Now(),
+		Dir:           filepath.Dir(relativePath),
+		SyncNodeIds:   cfg.SyncNodeIds,
+		SyncOverwrite: cfg.SyncOverwrite,
 	})
 }

+ 2 - 10
api/config/rename.go

@@ -35,17 +35,9 @@ func Rename(c *gin.Context) {
 	}
 
 	// Decode paths from URL encoding
-	decodedBasePath, err := url.QueryUnescape(json.BasePath)
-	if err != nil {
-		cosy.ErrHandler(c, err)
-		return
-	}
+	decodedBasePath := helper.UnescapeURL(json.BasePath)
 
-	decodedOrigName, err := url.QueryUnescape(json.OrigName)
-	if err != nil {
-		cosy.ErrHandler(c, err)
-		return
-	}
+	decodedOrigName := helper.UnescapeURL(json.OrigName)
 
 	decodedNewName, err := url.QueryUnescape(json.NewName)
 	if err != nil {

+ 31 - 0
api/openai/record.go

@@ -0,0 +1,31 @@
+package openai
+
+import (
+	"net/http"
+
+	"github.com/0xJacky/Nginx-UI/internal/helper"
+	"github.com/0xJacky/Nginx-UI/internal/nginx"
+	"github.com/0xJacky/Nginx-UI/query"
+	"github.com/gin-gonic/gin"
+	"github.com/uozi-tech/cosy"
+)
+
+func GetChatGPTRecord(c *gin.Context) {
+	absPath := c.Query("path")
+
+	if !helper.IsUnderDirectory(absPath, nginx.GetConfPath()) {
+		c.JSON(http.StatusForbidden, gin.H{
+			"message": "path is not under the nginx conf path",
+		})
+		return
+	}
+
+	g := query.ChatGPTLog
+	chatgpt, err := g.Where(g.Name.Eq(absPath)).FirstOrCreate()
+	if err != nil {
+		cosy.ErrHandler(c, err)
+		return
+	}
+
+	c.JSON(http.StatusOK, chatgpt)
+}

+ 2 - 0
api/openai/router.go

@@ -2,9 +2,11 @@ package openai
 
 import "github.com/gin-gonic/gin"
 
+
 func InitRouter(r *gin.RouterGroup) {
 	// ChatGPT
 	r.POST("chatgpt", MakeChatCompletionRequest)
+	r.GET("chatgpt/history", GetChatGPTRecord)
 	r.POST("chatgpt_record", StoreChatGPTRecord)
 	// Code Completion
 	r.GET("code_completion", CodeCompletion)

+ 2 - 1
api/sites/advance.go

@@ -3,6 +3,7 @@ package sites
 import (
 	"net/http"
 
+	"github.com/0xJacky/Nginx-UI/internal/helper"
 	"github.com/0xJacky/Nginx-UI/internal/nginx"
 	"github.com/0xJacky/Nginx-UI/query"
 	"github.com/gin-gonic/gin"
@@ -18,7 +19,7 @@ func DomainEditByAdvancedMode(c *gin.Context) {
 		return
 	}
 
-	name := c.Param("name")
+	name := helper.UnescapeURL(c.Param("name"))
 	path := nginx.GetConfPath("sites-available", name)
 
 	s := query.Site

+ 24 - 37
api/sites/site.go

@@ -5,19 +5,19 @@ import (
 	"os"
 
 	"github.com/0xJacky/Nginx-UI/internal/cert"
+	"github.com/0xJacky/Nginx-UI/internal/helper"
 	"github.com/0xJacky/Nginx-UI/internal/nginx"
 	"github.com/0xJacky/Nginx-UI/internal/site"
 	"github.com/0xJacky/Nginx-UI/model"
 	"github.com/0xJacky/Nginx-UI/query"
 	"github.com/gin-gonic/gin"
-	"github.com/sashabaranov/go-openai"
 	"github.com/uozi-tech/cosy"
 	"github.com/uozi-tech/cosy/logger"
 	"gorm.io/gorm/clause"
 )
 
 func GetSite(c *gin.Context) {
-	name := c.Param("name")
+	name := helper.UnescapeURL(c.Param("name"))
 
 	path := nginx.GetConfPath("sites-available", name)
 	file, err := os.Stat(path)
@@ -28,17 +28,6 @@ func GetSite(c *gin.Context) {
 		return
 	}
 
-	g := query.ChatGPTLog
-	chatgpt, err := g.Where(g.Name.Eq(path)).FirstOrCreate()
-	if err != nil {
-		cosy.ErrHandler(c, err)
-		return
-	}
-
-	if chatgpt.Content == nil {
-		chatgpt.Content = make([]openai.ChatCompletionMessage, 0)
-	}
-
 	s := query.Site
 	siteModel, err := s.Where(s.Path.Eq(path)).FirstOrCreate()
 	if err != nil {
@@ -59,14 +48,13 @@ func GetSite(c *gin.Context) {
 		}
 
 		c.JSON(http.StatusOK, site.Site{
-			ModifiedAt:      file.ModTime(),
-			Site:            siteModel,
-			Name:            name,
-			Config:          string(origContent),
-			AutoCert:        certModel.AutoCert == model.AutoCertEnabled,
-			ChatGPTMessages: chatgpt.Content,
-			Filepath:        path,
-			Status:          site.GetSiteStatus(name),
+			ModifiedAt: file.ModTime(),
+			Site:       siteModel,
+			Name:       name,
+			Config:     string(origContent),
+			AutoCert:   certModel.AutoCert == model.AutoCertEnabled,
+			Filepath:   path,
+			Status:     site.GetSiteStatus(name),
 		})
 		return
 	}
@@ -92,21 +80,20 @@ func GetSite(c *gin.Context) {
 	}
 
 	c.JSON(http.StatusOK, site.Site{
-		Site:            siteModel,
-		ModifiedAt:      file.ModTime(),
-		Name:            name,
-		Config:          nginxConfig.FmtCode(),
-		Tokenized:       nginxConfig,
-		AutoCert:        certModel.AutoCert == model.AutoCertEnabled,
-		CertInfo:        certInfoMap,
-		ChatGPTMessages: chatgpt.Content,
-		Filepath:        path,
-		Status:          site.GetSiteStatus(name),
+		Site:       siteModel,
+		ModifiedAt: file.ModTime(),
+		Name:       name,
+		Config:     nginxConfig.FmtCode(),
+		Tokenized:  nginxConfig,
+		AutoCert:   certModel.AutoCert == model.AutoCertEnabled,
+		CertInfo:   certInfoMap,
+		Filepath:   path,
+		Status:     site.GetSiteStatus(name),
 	})
 }
 
 func SaveSite(c *gin.Context) {
-	name := c.Param("name")
+	name := helper.UnescapeURL(c.Param("name"))
 
 	var json struct {
 		Content     string   `json:"content" binding:"required"`
@@ -130,7 +117,7 @@ func SaveSite(c *gin.Context) {
 }
 
 func RenameSite(c *gin.Context) {
-	oldName := c.Param("name")
+	oldName := helper.UnescapeURL(c.Param("name"))
 	var json struct {
 		NewName string `json:"new_name"`
 	}
@@ -150,7 +137,7 @@ func RenameSite(c *gin.Context) {
 }
 
 func EnableSite(c *gin.Context) {
-	name := c.Param("name")
+	name := helper.UnescapeURL(c.Param("name"))
 
 	// Check if the site is in maintenance mode, if yes, disable maintenance mode first
 	maintenanceConfigPath := nginx.GetConfPath("sites-enabled", name+site.MaintenanceSuffix)
@@ -176,7 +163,7 @@ func EnableSite(c *gin.Context) {
 }
 
 func DisableSite(c *gin.Context) {
-	name := c.Param("name")
+	name := helper.UnescapeURL(c.Param("name"))
 
 	// Check if the site is in maintenance mode, if yes, disable maintenance mode first
 	maintenanceConfigPath := nginx.GetConfPath("sites-enabled", name+site.MaintenanceSuffix)
@@ -202,7 +189,7 @@ func DisableSite(c *gin.Context) {
 }
 
 func DeleteSite(c *gin.Context) {
-	err := site.Delete(c.Param("name"))
+	err := site.Delete(helper.UnescapeURL(c.Param("name")))
 	if err != nil {
 		cosy.ErrHandler(c, err)
 		return
@@ -240,7 +227,7 @@ func BatchUpdateSites(c *gin.Context) {
 }
 
 func EnableMaintenanceSite(c *gin.Context) {
-	name := c.Param("name")
+	name := helper.UnescapeURL(c.Param("name"))
 
 	// If site is already enabled, disable the normal site first
 	enabledConfigPath := nginx.GetConfPath("sites-enabled", name)

+ 2 - 1
api/streams/advance.go

@@ -3,6 +3,7 @@ package streams
 import (
 	"net/http"
 
+	"github.com/0xJacky/Nginx-UI/internal/helper"
 	"github.com/0xJacky/Nginx-UI/internal/nginx"
 	"github.com/0xJacky/Nginx-UI/query"
 	"github.com/gin-gonic/gin"
@@ -18,7 +19,7 @@ func AdvancedEdit(c *gin.Context) {
 		return
 	}
 
-	name := c.Param("name")
+	name := helper.UnescapeURL(c.Param("name"))
 	path := nginx.GetConfPath("streams-available", name)
 
 	s := query.Stream

+ 1 - 1
api/streams/duplicate.go

@@ -11,7 +11,7 @@ import (
 
 func Duplicate(c *gin.Context) {
 	// Source name
-	name := c.Param("name")
+	name := helper.UnescapeURL(c.Param("name"))
 
 	// Destination name
 	var json struct {

+ 37 - 53
api/streams/streams.go

@@ -8,31 +8,30 @@ import (
 	"time"
 
 	"github.com/0xJacky/Nginx-UI/internal/config"
+	"github.com/0xJacky/Nginx-UI/internal/helper"
 	"github.com/0xJacky/Nginx-UI/internal/nginx"
 	"github.com/0xJacky/Nginx-UI/internal/stream"
 	"github.com/0xJacky/Nginx-UI/model"
 	"github.com/0xJacky/Nginx-UI/query"
 	"github.com/gin-gonic/gin"
 	"github.com/samber/lo"
-	"github.com/sashabaranov/go-openai"
 	"github.com/spf13/cast"
 	"github.com/uozi-tech/cosy"
 	"gorm.io/gorm/clause"
 )
 
 type Stream struct {
-	ModifiedAt      time.Time                      `json:"modified_at"`
-	Advanced        bool                           `json:"advanced"`
-	Status          config.ConfigStatus            `json:"status"`
-	Name            string                         `json:"name"`
-	Config          string                         `json:"config"`
-	ChatGPTMessages []openai.ChatCompletionMessage `json:"chatgpt_messages,omitempty"`
-	Tokenized       *nginx.NgxConfig               `json:"tokenized,omitempty"`
-	Filepath        string                         `json:"filepath"`
-	EnvGroupID      uint64                         `json:"env_group_id"`
-	EnvGroup        *model.EnvGroup                `json:"env_group,omitempty"`
-	SyncNodeIDs     []uint64                       `json:"sync_node_ids" gorm:"serializer:json"`
-	ProxyTargets    []config.ProxyTarget           `json:"proxy_targets,omitempty"`
+	ModifiedAt   time.Time            `json:"modified_at"`
+	Advanced     bool                 `json:"advanced"`
+	Status       config.ConfigStatus  `json:"status"`
+	Name         string               `json:"name"`
+	Config       string               `json:"config"`
+	Tokenized    *nginx.NgxConfig     `json:"tokenized,omitempty"`
+	Filepath     string               `json:"filepath"`
+	EnvGroupID   uint64               `json:"env_group_id"`
+	EnvGroup     *model.EnvGroup      `json:"env_group,omitempty"`
+	SyncNodeIDs  []uint64             `json:"sync_node_ids" gorm:"serializer:json"`
+	ProxyTargets []config.ProxyTarget `json:"proxy_targets,omitempty"`
 }
 
 func GetStreams(c *gin.Context) {
@@ -166,7 +165,7 @@ func GetStreams(c *gin.Context) {
 }
 
 func GetStream(c *gin.Context) {
-	name := c.Param("name")
+	name := helper.UnescapeURL(c.Param("name"))
 
 	// Get the absolute path to the stream configuration file
 	path := nginx.GetConfPath("streams-available", name)
@@ -184,19 +183,6 @@ func GetStream(c *gin.Context) {
 		status = config.StatusDisabled
 	}
 
-	// Retrieve or create ChatGPT log for this stream
-	g := query.ChatGPTLog
-	chatgpt, err := g.Where(g.Name.Eq(path)).FirstOrCreate()
-	if err != nil {
-		cosy.ErrHandler(c, err)
-		return
-	}
-
-	// Initialize empty content if nil
-	if chatgpt.Content == nil {
-		chatgpt.Content = make([]openai.ChatCompletionMessage, 0)
-	}
-
 	// Retrieve or create stream model from database
 	s := query.Stream
 	streamModel, err := s.Where(s.Path.Eq(path)).FirstOrCreate()
@@ -214,16 +200,15 @@ func GetStream(c *gin.Context) {
 		}
 
 		c.JSON(http.StatusOK, Stream{
-			ModifiedAt:      file.ModTime(),
-			Advanced:        streamModel.Advanced,
-			Status:          status,
-			Name:            name,
-			Config:          string(origContent),
-			ChatGPTMessages: chatgpt.Content,
-			Filepath:        path,
-			EnvGroupID:      streamModel.EnvGroupID,
-			EnvGroup:        streamModel.EnvGroup,
-			SyncNodeIDs:     streamModel.SyncNodeIDs,
+			ModifiedAt:  file.ModTime(),
+			Advanced:    streamModel.Advanced,
+			Status:      status,
+			Name:        name,
+			Config:      string(origContent),
+			Filepath:    path,
+			EnvGroupID:  streamModel.EnvGroupID,
+			EnvGroup:    streamModel.EnvGroup,
+			SyncNodeIDs: streamModel.SyncNodeIDs,
 		})
 		return
 	}
@@ -236,22 +221,21 @@ func GetStream(c *gin.Context) {
 	}
 
 	c.JSON(http.StatusOK, Stream{
-		ModifiedAt:      file.ModTime(),
-		Advanced:        streamModel.Advanced,
-		Status:          status,
-		Name:            name,
-		Config:          nginxConfig.FmtCode(),
-		Tokenized:       nginxConfig,
-		ChatGPTMessages: chatgpt.Content,
-		Filepath:        path,
-		EnvGroupID:      streamModel.EnvGroupID,
-		EnvGroup:        streamModel.EnvGroup,
-		SyncNodeIDs:     streamModel.SyncNodeIDs,
+		ModifiedAt:  file.ModTime(),
+		Advanced:    streamModel.Advanced,
+		Status:      status,
+		Name:        name,
+		Config:      nginxConfig.FmtCode(),
+		Tokenized:   nginxConfig,
+		Filepath:    path,
+		EnvGroupID:  streamModel.EnvGroupID,
+		EnvGroup:    streamModel.EnvGroup,
+		SyncNodeIDs: streamModel.SyncNodeIDs,
 	})
 }
 
 func SaveStream(c *gin.Context) {
-	name := c.Param("name")
+	name := helper.UnescapeURL(c.Param("name"))
 
 	var json struct {
 		Content     string   `json:"content" binding:"required"`
@@ -305,7 +289,7 @@ func SaveStream(c *gin.Context) {
 
 func EnableStream(c *gin.Context) {
 	// Enable the stream by creating a symlink in streams-enabled directory
-	err := stream.Enable(c.Param("name"))
+	err := stream.Enable(helper.UnescapeURL(c.Param("name")))
 	if err != nil {
 		cosy.ErrHandler(c, err)
 		return
@@ -318,7 +302,7 @@ func EnableStream(c *gin.Context) {
 
 func DisableStream(c *gin.Context) {
 	// Disable the stream by removing the symlink from streams-enabled directory
-	err := stream.Disable(c.Param("name"))
+	err := stream.Disable(helper.UnescapeURL(c.Param("name")))
 	if err != nil {
 		cosy.ErrHandler(c, err)
 		return
@@ -331,7 +315,7 @@ func DisableStream(c *gin.Context) {
 
 func DeleteStream(c *gin.Context) {
 	// Delete the stream configuration file and its symbolic link if exists
-	err := stream.Delete(c.Param("name"))
+	err := stream.Delete(helper.UnescapeURL(c.Param("name")))
 	if err != nil {
 		cosy.ErrHandler(c, err)
 		return
@@ -343,7 +327,7 @@ func DeleteStream(c *gin.Context) {
 }
 
 func RenameStream(c *gin.Context) {
-	oldName := c.Param("name")
+	oldName := helper.UnescapeURL(c.Param("name"))
 	var json struct {
 		NewName string `json:"new_name"`
 	}

+ 3 - 0
app/components.d.ts

@@ -74,6 +74,9 @@ declare module 'vue' {
     ChartRadialBarChart: typeof import('./src/components/Chart/RadialBarChart.vue')['default']
     ChartUsageProgressLine: typeof import('./src/components/Chart/UsageProgressLine.vue')['default']
     ChatGPTChatGPT: typeof import('./src/components/ChatGPT/ChatGPT.vue')['default']
+    ChatGPTChatMessage: typeof import('./src/components/ChatGPT/ChatMessage.vue')['default']
+    ChatGPTChatMessageInput: typeof import('./src/components/ChatGPT/ChatMessageInput.vue')['default']
+    ChatGPTChatMessageList: typeof import('./src/components/ChatGPT/ChatMessageList.vue')['default']
     CodeEditorCodeEditor: typeof import('./src/components/CodeEditor/CodeEditor.vue')['default']
     ConfigHistoryConfigHistory: typeof import('./src/components/ConfigHistory/ConfigHistory.vue')['default']
     ConfigHistoryDiffViewer: typeof import('./src/components/ConfigHistory/DiffViewer.vue')['default']

+ 3 - 0
app/src/api/openai.ts

@@ -24,6 +24,9 @@ export interface CodeCompletionResponse {
 }
 
 const openai = {
+  get_record(path: string) {
+    return http.get(`/chatgpt/history`, { params: { path } })
+  },
   store_record(data: { file_name?: string, messages?: ChatComplicationMessage[] }) {
     return http.post('/chatgpt_record', data)
   },

+ 0 - 2
app/src/api/site.ts

@@ -2,7 +2,6 @@ import type { CertificateInfo } from '@/api/cert'
 import type { ModelBase } from '@/api/curd'
 import type { EnvGroup } from '@/api/env_group'
 import type { NgxConfig } from '@/api/ngx'
-import type { ChatComplicationMessage } from '@/api/openai'
 import type { ConfigStatus, PrivateKeyType } from '@/constants'
 import { extendCurdApi, http, useCurdApi } from '@uozi-admin/request'
 
@@ -22,7 +21,6 @@ export interface Site extends ModelBase {
   filepath: string
   config: string
   auto_cert: boolean
-  chatgpt_messages: ChatComplicationMessage[]
   tokenized?: NgxConfig
   cert_info?: Record<number, CertificateInfo[]>
   env_group_id: number

+ 20 - 426
app/src/components/ChatGPT/ChatGPT.vue

@@ -1,315 +1,43 @@
 <script setup lang="ts">
-import type { ChatComplicationMessage } from '@/api/openai'
-import Icon, { SendOutlined } from '@ant-design/icons-vue'
-import hljs from 'highlight.js'
-import nginx from 'highlight.js/lib/languages/nginx'
-import { Marked } from 'marked'
-import { markedHighlight } from 'marked-highlight'
+import Icon from '@ant-design/icons-vue'
 import { storeToRefs } from 'pinia'
-import openai from '@/api/openai'
-
 import ChatGPT_logo from '@/assets/svg/ChatGPT_logo.svg?component'
-import { urlJoin } from '@/lib/helper'
-import { useSettingsStore, useUserStore } from '@/pinia'
-import 'highlight.js/styles/vs2015.css'
+import { useSettingsStore } from '@/pinia'
+import { useChatGPTStore } from './chatgpt'
+import ChatMessageInput from './ChatMessageInput.vue'
+import ChatMessageList from './ChatMessageList.vue'
 
 const props = defineProps<{
   content: string
   path?: string
 }>()
 
-hljs.registerLanguage('nginx', nginx)
-
 const { language: current } = storeToRefs(useSettingsStore())
 
-const messages = defineModel<ChatComplicationMessage[]>('historyMessages', {
-  type: Array,
-  default: reactive([]),
-})
-
-const loading = ref(false)
-const askBuffer = ref('')
-
-// Global buffer for accumulation
-let buffer = ''
-
-// Track last chunk to avoid immediate repeated content
-let lastChunkStr = ''
-
-// define a type for tracking code block state
-interface CodeBlockState {
-  isInCodeBlock: boolean
-  backtickCount: number
-}
-
-const codeBlockState: CodeBlockState = reactive({
-  isInCodeBlock: false, // if in ``` code block
-  backtickCount: 0, // count of ```
-})
-
-/**
- * transformReasonerThink: if <think> appears but is not paired with </think>, it will be automatically supplemented, and the entire text will be converted to a Markdown quote
- */
-function transformReasonerThink(rawText: string): string {
-  // 1. Count number of <think> vs </think>
-  const openThinkRegex = /<think>/gi
-  const closeThinkRegex = /<\/think>/gi
-
-  const openCount = (rawText.match(openThinkRegex) || []).length
-  const closeCount = (rawText.match(closeThinkRegex) || []).length
-
-  // 2. If open tags exceed close tags, append missing </think> at the end
-  if (openCount > closeCount) {
-    const diff = openCount - closeCount
-    rawText += '</think>'.repeat(diff)
-  }
-
-  // 3. Replace <think>...</think> blocks with Markdown blockquote ("> ...")
-  return rawText.replace(/<think>([\s\S]*?)<\/think>/g, (match, p1) => {
-    // Split the inner text by line, prefix each with "> "
-    const lines = p1.trim().split('\n')
-    const blockquoted = lines.map(line => `> ${line}`).join('\n')
-    // Return the replaced Markdown quote
-    return `\n${blockquoted}\n`
-  })
-}
-
-/**
- * transformText: transform the text
- */
-function transformText(rawText: string): string {
-  return transformReasonerThink(rawText)
-}
-
-/**
- * scrollToBottom: Scroll container to bottom
- */
-function scrollToBottom() {
-  const container = document.querySelector('.right-settings .ant-card-body')
-  if (container)
-    container.scrollTop = container.scrollHeight
-}
-
-/**
- * updateCodeBlockState: The number of unnecessary scans is reduced by changing the scanning method of incremental content
- */
-function updateCodeBlockState(chunk: string) {
-  // count all ``` in chunk
-  // note to distinguish how many "backticks" are not paired
-
-  const regex = /```/g
-
-  while (regex.exec(chunk) !== null) {
-    codeBlockState.backtickCount++
-    // if backtickCount is even -> closed
-    codeBlockState.isInCodeBlock = codeBlockState.backtickCount % 2 !== 0
-  }
-}
-
-/**
- * applyChunk: Process one SSE chunk and type out content character by character
- * @param input   A chunk of data (Uint8Array) from SSE
- * @param targetMsg  The assistant-type message object being updated
- */
-
-async function applyChunk(input: Uint8Array, targetMsg: ChatComplicationMessage) {
-  const decoder = new TextDecoder('utf-8')
-  const raw = decoder.decode(input)
-  // SSE default split by segment
-  const lines = raw.split('\n\n')
-
-  for (const line of lines) {
-    if (!line.startsWith('event:message\ndata:'))
-      continue
-
-    const dataStr = line.slice('event:message\ndata:'.length)
-    if (!dataStr)
-      continue
-
-    const content = JSON.parse(dataStr).content as string
-    if (!content || content.trim() === '')
-      continue
-    if (content === lastChunkStr)
-      continue
-
-    lastChunkStr = content
-
-    // Only detect substrings
-    // 1. This can be processed in batches according to actual needs, reducing the number of character processing times
-    updateCodeBlockState(content)
-
-    for (const c of content) {
-      buffer += c
-      // codeBlockState.isInCodeBlock check if in code block
-      targetMsg.content = buffer
-      await nextTick()
-      await new Promise(resolve => setTimeout(resolve, 20))
-      scrollToBottom()
-    }
-  }
-}
-
-/**
- * request: Send messages to server, receive SSE, and process by typing out chunk by chunk
- */
-async function request() {
-  loading.value = true
-
-  // Add an "assistant" message object
-  const t = ref<ChatComplicationMessage>({
-    role: 'assistant',
-    content: '',
-  })
-
-  messages.value.push(t.value)
-
-  // Reset buffer flags each time
-  buffer = ''
-  lastChunkStr = ''
+// Use ChatGPT store
+const chatGPTStore = useChatGPTStore()
+const { messageListRef, loading, shouldShowStartButton } = storeToRefs(chatGPTStore)
 
+// Initialize messages when path changes
+watch(() => props.path, async () => {
+  await chatGPTStore.initMessages(props.path)
   await nextTick()
-  scrollToBottom()
-
-  const user = useUserStore()
-  const { token } = storeToRefs(user)
+}, { immediate: true })
 
-  const res = await fetch(urlJoin(window.location.pathname, '/api/chatgpt'), {
-    method: 'POST',
-    headers: {
-      Accept: 'text/event-stream',
-      Authorization: token.value,
-    },
-    body: JSON.stringify({
-      filepath: props.path,
-      messages: messages.value.slice(0, messages.value.length - 1),
-    }),
-  })
-
-  if (!res.body) {
-    loading.value = false
-    return
-  }
-
-  const reader = res.body.getReader()
-
-  while (true) {
-    try {
-      const { done, value } = await reader.read()
-      if (done) {
-        // SSE stream ended
-        setTimeout(() => {
-          scrollToBottom()
-        }, 300)
-        break
-      }
-      if (value) {
-        // Process each chunk
-        await applyChunk(value, t.value)
-      }
-    }
-    catch {
-      // In case of error
-      break
-    }
-  }
-
-  loading.value = false
-  storeRecord()
-}
-
-/**
- * send: Add user message into messages then call request
- */
-async function send() {
-  if (!messages.value)
-    messages.value = []
-
-  if (messages.value.length === 0) {
-    // The first message
-    messages.value = [{
-      role: 'user',
-      content: `${props.content}\n\nCurrent Language Code: ${current.value}`,
-    }]
-  }
-  else {
-    // Append user's new message
-    messages.value.push({
-      role: 'user',
-      content: askBuffer.value,
-    })
-    askBuffer.value = ''
-  }
-
-  await nextTick()
-  await request()
-}
-
-// Markdown renderer
-const marked = new Marked(
-  markedHighlight({
-    langPrefix: 'hljs language-',
-    highlight(code, lang) {
-      const language = hljs.getLanguage(lang) ? lang : 'nginx'
-      return hljs.highlight(code, { language }).value
-    },
-  }),
-)
-
-// Basic marked options
-marked.setOptions({
-  pedantic: false,
-  gfm: true,
-  breaks: false,
-})
-
-/**
- * storeRecord: Save chat history
- */
-function storeRecord() {
-  openai.store_record({
-    file_name: props.path,
-    messages: messages.value,
-  })
-}
-
-/**
- * clearRecord: Clears all messages
- */
-function clearRecord() {
-  openai.store_record({
-    file_name: props.path,
-    messages: [],
-  })
-  messages.value = []
-}
-
-// Manage editing
-const editingIdx = ref(-1)
-
-/**
- * regenerate: Removes messages after index and re-request the answer
- */
-async function regenerate(index: number) {
-  editingIdx.value = -1
-  messages.value = messages.value.slice(0, index)
-  await nextTick()
-  await request()
+// Send message handler
+async function handleSend() {
+  await chatGPTStore.send(props.content, current.value)
 }
-
-/**
- * show: If empty, display start button
- */
-const show = computed(() => !messages.value || messages.value.length === 0)
 </script>
 
 <template>
   <div
-    v-if="show"
-    class="chat-start mt-4"
+    v-if="shouldShowStartButton"
+    class="chat-start m-4"
   >
     <AButton
       :loading="loading"
-      @click="send"
+      @click="handleSend"
     >
       <Icon
         v-if="!loading"
@@ -323,86 +51,9 @@ const show = computed(() => !messages.value || messages.value.length === 0)
     v-else
     class="chatgpt-container"
   >
-    <AList
-      class="chatgpt-log"
-      item-layout="horizontal"
-      :data-source="messages"
-    >
-      <template #renderItem="{ item, index }">
-        <AListItem>
-          <AComment :author="item.role === 'assistant' ? $gettext('Assistant') : $gettext('User')">
-            <template #content>
-              <div
-                v-if="item.role === 'assistant' || editingIdx !== index"
-                v-dompurify-html="marked.parse(transformText(item.content))"
-                class="content"
-              />
-              <AInput
-                v-else
-                v-model:value="item.content"
-                class="pa-0"
-                :bordered="false"
-              />
-            </template>
-            <template #actions>
-              <span
-                v-if="item.role === 'user' && editingIdx !== index"
-                @click="editingIdx = index"
-              >
-                {{ $gettext('Modify') }}
-              </span>
-              <template v-else-if="editingIdx === index">
-                <span @click="regenerate(index + 1)">{{ $gettext('Save') }}</span>
-                <span @click="editingIdx = -1">{{ $gettext('Cancel') }}</span>
-              </template>
-              <span
-                v-else-if="!loading"
-                @click="regenerate(index)"
-              >
-                {{ $gettext('Reload') }}
-              </span>
-            </template>
-          </AComment>
-        </AListItem>
-      </template>
-    </AList>
+    <ChatMessageList ref="messageListRef" />
 
-    <div class="input-msg">
-      <div class="control-btn">
-        <ASpace v-show="!loading">
-          <APopconfirm
-            :cancel-text="$gettext('No')"
-            :ok-text="$gettext('OK')"
-            :title="$gettext('Are you sure you want to clear the record of chat?')"
-            @confirm="clearRecord"
-          >
-            <AButton type="text">
-              {{ $gettext('Clear') }}
-            </AButton>
-          </APopconfirm>
-          <AButton
-            type="text"
-            @click="regenerate((messages?.length ?? 1) - 1)"
-          >
-            {{ $gettext('Regenerate response') }}
-          </AButton>
-        </ASpace>
-      </div>
-      <ATextarea
-        v-model:value="askBuffer"
-        auto-size
-      />
-      <div class="send-btn">
-        <AButton
-          size="small"
-          type="text"
-          :loading="loading"
-          @click="send"
-        >
-          <SendOutlined />
-        </AButton>
-      </div>
-    </div>
+    <ChatMessageInput />
   </div>
 </template>
 
@@ -410,62 +61,5 @@ const show = computed(() => !messages.value || messages.value.length === 0)
 .chatgpt-container {
   margin: 0 auto;
   max-width: 800px;
-
-  .chatgpt-log {
-    .content {
-      width: 100%;
-
-      :deep(.hljs) {
-        border-radius: 5px;
-      }
-
-      :deep(blockquote) {
-        display: block;
-        opacity: 0.6;
-        margin: 0.5em 0;
-        padding-left: 1em;
-        border-left: 3px solid #ccc;
-      }
-    }
-
-    :deep(.ant-list-item) {
-      padding: 0;
-    }
-
-    :deep(.ant-comment-content) {
-      width: 100%;
-    }
-
-    :deep(.ant-comment) {
-      width: 100%;
-    }
-
-    :deep(.ant-comment-content-detail) {
-      width: 100%;
-
-      p {
-        margin-bottom: 10px;
-      }
-    }
-
-    :deep(.ant-list-item:first-child) {
-      display: none;
-    }
-  }
-
-  .input-msg {
-    position: relative;
-
-    .control-btn {
-      display: flex;
-      justify-content: center;
-    }
-
-    .send-btn {
-      position: absolute;
-      right: 0;
-      bottom: 3px;
-    }
-  }
 }
 </style>

+ 292 - 0
app/src/components/ChatGPT/ChatMessage.vue

@@ -0,0 +1,292 @@
+<script setup lang="ts">
+import type { ChatComplicationMessage } from '@/api/openai'
+import { useChatGPTStore } from './chatgpt'
+import { marked } from './markdown'
+import { transformText } from './utils'
+
+interface Props {
+  message: ChatComplicationMessage
+  index: number
+  isEditing: boolean
+  loading: boolean
+  editValue: string
+}
+
+const props = defineProps<Props>()
+
+defineEmits<{
+  edit: [index: number]
+  save: [index: number]
+  cancel: []
+  regenerate: [index: number]
+}>()
+
+const chatGPTStore = useChatGPTStore()
+const { streamingMessageIndex } = storeToRefs(chatGPTStore)
+
+function updateEditValue(value: string) {
+  chatGPTStore.editValue = value
+}
+
+// Typewriter effect state
+const displayText = ref('')
+const isTyping = ref(false)
+const animationFrame = ref<number | null>(null)
+
+// Cache for transformed content to avoid re-processing
+let lastRawContent = ''
+let lastTransformedContent = ''
+
+// Get transformed content with caching
+function getTransformedContent(content: string): string {
+  if (content === lastRawContent) {
+    return lastTransformedContent
+  }
+  lastRawContent = content
+  lastTransformedContent = transformText(content)
+  return lastTransformedContent
+}
+
+// Check if current message should use typewriter effect
+const shouldUseTypewriter = computed(() => {
+  return props.message.role === 'assistant'
+    && !props.isEditing
+    && streamingMessageIndex.value === props.index
+})
+
+// High-performance typewriter animation using RAF
+function startTypewriterAnimation(targetContent: string) {
+  if (animationFrame.value) {
+    cancelAnimationFrame(animationFrame.value)
+  }
+
+  const transformedContent = getTransformedContent(targetContent)
+
+  // Skip if content hasn't changed
+  if (displayText.value === transformedContent) {
+    isTyping.value = false
+    return
+  }
+
+  // Start from current display text length
+  const startLength = displayText.value.length
+  const targetLength = transformedContent.length
+
+  // If content is shorter (like editing), immediately set to target
+  if (targetLength < startLength) {
+    displayText.value = transformedContent
+    isTyping.value = false
+    return
+  }
+
+  isTyping.value = true
+  let currentIndex = startLength
+  let lastTime = performance.now()
+
+  // Characters per second (adjustable for speed)
+  const charactersPerSecond = 120 // Similar to VScode speed
+  const msPerCharacter = 1000 / charactersPerSecond
+
+  function animate(currentTime: number) {
+    const deltaTime = currentTime - lastTime
+
+    // Check if enough time has passed to show next character(s)
+    if (deltaTime >= msPerCharacter) {
+      // Calculate how many characters to show based on elapsed time
+      const charactersToAdd = Math.floor(deltaTime / msPerCharacter)
+      currentIndex = Math.min(currentIndex + charactersToAdd, targetLength)
+
+      displayText.value = transformedContent.substring(0, currentIndex)
+      lastTime = currentTime
+
+      // Check if we've reached the end
+      if (currentIndex >= targetLength) {
+        isTyping.value = false
+        animationFrame.value = null
+        return
+      }
+    }
+
+    // Continue animation
+    animationFrame.value = requestAnimationFrame(animate)
+  }
+
+  // Start the animation
+  animationFrame.value = requestAnimationFrame(animate)
+}
+
+// Stop animation when component unmounts
+onUnmounted(() => {
+  if (animationFrame.value) {
+    cancelAnimationFrame(animationFrame.value)
+  }
+})
+
+// Watch for content changes
+watch(
+  () => props.message.content,
+  newContent => {
+    if (shouldUseTypewriter.value) {
+      // Only use typewriter effect for streaming messages
+      startTypewriterAnimation(newContent)
+    }
+    else {
+      // For user messages, non-streaming messages, or when editing, show immediately
+      displayText.value = getTransformedContent(newContent)
+      isTyping.value = false
+    }
+  },
+  { immediate: true },
+)
+
+// Watch for streaming state changes
+watch(
+  shouldUseTypewriter,
+  newValue => {
+    if (!newValue) {
+      // If no longer streaming, immediately show full content
+      displayText.value = getTransformedContent(props.message.content)
+      isTyping.value = false
+      if (animationFrame.value) {
+        cancelAnimationFrame(animationFrame.value)
+        animationFrame.value = null
+      }
+    }
+  },
+)
+
+// Reset when switching between messages
+watch(
+  () => [props.index, props.isEditing],
+  () => {
+    if (!shouldUseTypewriter.value) {
+      displayText.value = getTransformedContent(props.message.content)
+      isTyping.value = false
+      if (animationFrame.value) {
+        cancelAnimationFrame(animationFrame.value)
+        animationFrame.value = null
+      }
+    }
+  },
+)
+
+// Initialize display text
+onMounted(() => {
+  if (shouldUseTypewriter.value) {
+    displayText.value = ''
+    startTypewriterAnimation(props.message.content)
+  }
+  else {
+    displayText.value = getTransformedContent(props.message.content)
+  }
+})
+</script>
+
+<template>
+  <AListItem>
+    <AComment :author="message.role === 'assistant' ? $gettext('Assistant') : $gettext('User')">
+      <template #content>
+        <div
+          v-if="message.role === 'assistant' || !isEditing"
+          class="content"
+          :class="{ typing: isTyping }"
+        >
+          <div
+            v-dompurify-html="marked.parse(displayText)"
+            class="message-content"
+          />
+        </div>
+        <AInput
+          v-else
+          :value="editValue"
+          class="pa-0"
+          :bordered="false"
+          @update:value="updateEditValue"
+        />
+      </template>
+      <template #actions>
+        <span
+          v-if="message.role === 'user' && !isEditing"
+          @click="$emit('edit', index)"
+        >
+          {{ $gettext('Modify') }}
+        </span>
+        <template v-else-if="isEditing">
+          <span @click="$emit('save', index + 1)">{{ $gettext('Save') }}</span>
+          <span @click="$emit('cancel')">{{ $gettext('Cancel') }}</span>
+        </template>
+        <span
+          v-else-if="!loading"
+          @click="$emit('regenerate', index)"
+        >
+          {{ $gettext('Reload') }}
+        </span>
+      </template>
+    </AComment>
+  </AListItem>
+</template>
+
+<style lang="less" scoped>
+.content {
+  width: 100%;
+  position: relative;
+
+  .message-content {
+    width: 100%;
+  }
+
+  &.typing {
+    .message-content {
+      // Very subtle glow during typing
+      animation: typing-glow 3s ease-in-out infinite;
+    }
+  }
+
+  :deep(code) {
+    font-size: 12px;
+  }
+
+  :deep(.hljs) {
+    border-radius: 5px;
+  }
+
+  :deep(blockquote) {
+    display: block;
+    opacity: 0.6;
+    margin: 0.5em 0;
+    padding-left: 1em;
+    border-left: 3px solid #ccc;
+  }
+}
+
+@keyframes typing-glow {
+  0%, 100% {
+    filter: brightness(1) contrast(1);
+  }
+  50% {
+    filter: brightness(1.01) contrast(1.01);
+  }
+}
+
+// Dark mode adjustments (if applicable)
+@media (prefers-color-scheme: dark) {
+  .content {
+    .typing-indicator {
+      background-color: #40a9ff;
+    }
+
+    &.typing .message-content {
+      animation: typing-glow-dark 3s ease-in-out infinite;
+    }
+  }
+}
+
+@keyframes typing-glow-dark {
+  0%, 100% {
+    filter: brightness(1) contrast(1);
+  }
+  50% {
+    filter: brightness(1.05) contrast(1.02);
+  }
+}
+</style>

+ 82 - 0
app/src/components/ChatGPT/ChatMessageInput.vue

@@ -0,0 +1,82 @@
+<script setup lang="ts">
+import { SendOutlined } from '@ant-design/icons-vue'
+import { storeToRefs } from 'pinia'
+import { useChatGPTStore } from './chatgpt'
+
+const chatGPTStore = useChatGPTStore()
+const { loading, askBuffer, messages } = storeToRefs(chatGPTStore)
+
+const messagesLength = computed(() => messages.value?.length ?? 0)
+</script>
+
+<template>
+  <div class="input-msg">
+    <div class="control-btn">
+      <ASpace v-show="!loading">
+        <APopconfirm
+          :cancel-text="$gettext('No')"
+          :ok-text="$gettext('OK')"
+          :title="$gettext('Are you sure you want to clear the record of chat?')"
+          @confirm="chatGPTStore.clearRecord()"
+        >
+          <AButton type="text">
+            {{ $gettext('Clear') }}
+          </AButton>
+        </APopconfirm>
+        <AButton
+          type="text"
+          @click="chatGPTStore.regenerate(messagesLength - 1)"
+        >
+          {{ $gettext('Regenerate response') }}
+        </AButton>
+      </ASpace>
+    </div>
+    <ATextarea
+      v-model:value="askBuffer"
+      auto-size
+      @press-enter="chatGPTStore.send(askBuffer)"
+    />
+    <div class="send-btn">
+      <AButton
+        size="small"
+        type="text"
+        :loading="loading"
+        @click="chatGPTStore.send(askBuffer)"
+      >
+        <SendOutlined />
+      </AButton>
+    </div>
+  </div>
+</template>
+
+<style lang="less" scoped>
+.input-msg {
+  position: sticky;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  background: rgba(255, 255, 255, 0.8);
+  backdrop-filter: blur(10px);
+  -webkit-backdrop-filter: blur(10px);
+  padding: 16px;
+  border-top: 1px solid rgba(255, 255, 255, 0.2);
+
+  .control-btn {
+    display: flex;
+    justify-content: center;
+  }
+
+  .send-btn {
+    position: absolute;
+    right: 16px;
+    bottom: 19px;
+  }
+}
+
+.dark {
+  .input-msg {
+    background: rgba(30, 30, 30, 0.8);
+    border-top: 1px solid rgba(255, 255, 255, 0.1);
+  }
+}
+</style>

+ 131 - 0
app/src/components/ChatGPT/ChatMessageList.vue

@@ -0,0 +1,131 @@
+<script setup lang="ts">
+import { useChatGPTStore } from './chatgpt'
+import ChatMessage from './ChatMessage.vue'
+
+// Use ChatGPT store
+const chatGPTStore = useChatGPTStore()
+const { messages, editingIdx, editValue, loading } = storeToRefs(chatGPTStore)
+
+const messageListRef = useTemplateRef('messageList')
+let scrollTimeoutId: number | null = null
+
+function scrollToBottom() {
+  // Debounce scroll operations for better performance
+  if (scrollTimeoutId) {
+    clearTimeout(scrollTimeoutId)
+  }
+
+  scrollTimeoutId = window.setTimeout(() => {
+    requestAnimationFrame(() => {
+      if (messageListRef.value) {
+        let element = messageListRef.value.parentElement
+        while (element) {
+          const style = window.getComputedStyle(element)
+          if (style.overflowY === 'auto' || style.overflowY === 'scroll') {
+            element.scrollTo({
+              top: element.scrollHeight,
+              behavior: 'smooth',
+            })
+            return
+          }
+          element = element.parentElement
+        }
+      }
+    })
+  }, 50) // 50ms debounce
+}
+
+// Watch for messages changes and auto scroll - with debouncing
+watch(() => messages.value, () => {
+  scrollToBottom()
+}, { deep: true, flush: 'post' })
+
+// Auto scroll when messages are loaded
+onMounted(() => {
+  scrollToBottom()
+})
+
+// Clean up on unmount
+onUnmounted(() => {
+  if (scrollTimeoutId) {
+    clearTimeout(scrollTimeoutId)
+  }
+})
+
+// Expose scroll function for parent component
+defineExpose({
+  scrollToBottom,
+})
+
+function handleEdit(index: number) {
+  chatGPTStore.startEdit(index)
+}
+
+async function handleSave() {
+  chatGPTStore.saveEdit()
+  await nextTick()
+  chatGPTStore.request()
+}
+
+function handleCancel() {
+  chatGPTStore.cancelEdit()
+}
+
+async function handleRegenerate(index: number) {
+  chatGPTStore.regenerate(index)
+}
+</script>
+
+<template>
+  <div ref="messageList" class="message-list-container">
+    <AList
+      class="chatgpt-log"
+      item-layout="horizontal"
+      :data-source="messages"
+    >
+      <template #renderItem="{ item, index }">
+        <ChatMessage
+          :edit-value="editValue"
+          :message="item"
+          :index="index"
+          :is-editing="editingIdx === index"
+          :loading="loading"
+          @edit="handleEdit"
+          @save="handleSave"
+          @cancel="handleCancel"
+          @regenerate="handleRegenerate"
+        />
+      </template>
+    </AList>
+  </div>
+</template>
+
+<style lang="less" scoped>
+.message-list-container {
+  .chatgpt-log {
+    :deep(.ant-list-item) {
+      padding: 0 12px;
+    }
+
+    :deep(.ant-comment-content) {
+      width: 100%;
+    }
+
+    :deep(.ant-comment) {
+      width: 100%;
+    }
+
+    :deep(.ant-comment-content-detail) {
+      width: 100%;
+
+      p {
+        margin-bottom: 10px;
+      }
+    }
+
+    :deep(.ant-list-item:first-child) {
+      display: none;
+    }
+  }
+}
+</style>

+ 114 - 0
app/src/components/ChatGPT/chatService.ts

@@ -0,0 +1,114 @@
+import type { CodeBlockState } from './types'
+import type { ChatComplicationMessage } from '@/api/openai'
+import { storeToRefs } from 'pinia'
+import { urlJoin } from '@/lib/helper'
+import { useUserStore } from '@/pinia'
+import { updateCodeBlockState } from './utils'
+
+export class ChatService {
+  private buffer = ''
+  private lastChunkStr = ''
+  private codeBlockState: CodeBlockState = reactive({
+    isInCodeBlock: false,
+    backtickCount: 0,
+  })
+
+  // applyChunk: Process one SSE chunk and update content directly
+  private applyChunk(input: Uint8Array, targetMsg: ChatComplicationMessage) {
+    const decoder = new TextDecoder('utf-8')
+    const raw = decoder.decode(input)
+    // SSE default split by segment
+    const lines = raw.split('\n\n')
+
+    for (const line of lines) {
+      if (!line.startsWith('event:message\ndata:'))
+        continue
+
+      const dataStr = line.slice('event:message\ndata:'.length)
+      if (!dataStr)
+        continue
+
+      const content = JSON.parse(dataStr).content as string
+      if (!content || content.trim() === '')
+        continue
+      if (content === this.lastChunkStr)
+        continue
+
+      this.lastChunkStr = content
+
+      // Only detect substrings
+      updateCodeBlockState(content, this.codeBlockState)
+
+      // Directly append content to buffer
+      this.buffer += content
+
+      // Update message content immediately - typewriter effect is handled in ChatMessage.vue
+      targetMsg.content = this.buffer
+    }
+  }
+
+  // request: Send messages to server, receive SSE, and process chunks
+  async request(
+    path: string | undefined,
+    messages: ChatComplicationMessage[],
+    onProgress?: (message: ChatComplicationMessage) => void,
+  ): Promise<ChatComplicationMessage> {
+    // Reset buffer flags each time
+    this.buffer = ''
+    this.lastChunkStr = ''
+    this.codeBlockState.isInCodeBlock = false
+    this.codeBlockState.backtickCount = 0
+
+    const user = useUserStore()
+    const { token } = storeToRefs(user)
+
+    // Filter out empty assistant messages for the request
+    const requestMessages = messages.filter(msg =>
+      msg.role === 'user' || (msg.role === 'assistant' && msg.content.trim() !== ''),
+    )
+
+    const res = await fetch(urlJoin(window.location.pathname, '/api/chatgpt'), {
+      method: 'POST',
+      headers: {
+        Accept: 'text/event-stream',
+        Authorization: token.value,
+      },
+      body: JSON.stringify({
+        filepath: path,
+        messages: requestMessages,
+      }),
+    })
+
+    if (!res.body) {
+      throw new Error('No response body')
+    }
+
+    const reader = res.body.getReader()
+
+    // Create assistant message for streaming updates
+    const assistantMessage: ChatComplicationMessage = {
+      role: 'assistant',
+      content: '',
+    }
+
+    while (true) {
+      try {
+        const { done, value } = await reader.read()
+        if (done) {
+          break
+        }
+        if (value) {
+          // Process each chunk
+          this.applyChunk(value, assistantMessage)
+          onProgress?.(assistantMessage)
+        }
+      }
+      catch {
+        // In case of error
+        break
+      }
+    }
+
+    return assistantMessage
+  }
+}

+ 275 - 0
app/src/components/ChatGPT/chatgpt.ts

@@ -0,0 +1,275 @@
+import type { ChatMessageList } from '.'
+import type { ChatComplicationMessage } from '@/api/openai'
+import { defineStore } from 'pinia'
+import { computed, nextTick, ref } from 'vue'
+import openai from '@/api/openai'
+import { ChatService } from './chatService'
+
+export const useChatGPTStore = defineStore('chatgpt', () => {
+  // State
+  const path = ref<string>('') // Path to the chat record file
+  const messages = ref<ChatComplicationMessage[]>([])
+  const messageListRef = ref<InstanceType<typeof ChatMessageList>>()
+  const loading = ref(false)
+  const editingIdx = ref(-1)
+  const editValue = ref('')
+  const askBuffer = ref('')
+  const streamingMessageIndex = ref(-1) // Track which message is currently streaming
+
+  // Getters
+  const isEditing = computed(() => editingIdx.value !== -1)
+  const currentEditingMessage = computed(() => {
+    if (editingIdx.value !== -1 && messages.value[editingIdx.value]) {
+      return messages.value[editingIdx.value]
+    }
+    return null
+  })
+  const hasMessages = computed(() => messages.value.length > 0)
+  const shouldShowStartButton = computed(() => messages.value.length === 0)
+
+  // Actions
+  // Initialize messages for a specific file path
+  async function initMessages(filePath?: string) {
+    messages.value = []
+    if (filePath) {
+      try {
+        const record = await openai.get_record(filePath)
+        messages.value = record.content || []
+      }
+      catch (error) {
+        console.error('Failed to load chat record:', error)
+      }
+      path.value = filePath
+    }
+  }
+
+  // Start editing a message at the specified index
+  function startEdit(index: number) {
+    if (index >= 0 && index < messages.value.length) {
+      editingIdx.value = index
+      editValue.value = messages.value[index].content
+    }
+  }
+
+  // Save the edited message
+  function saveEdit() {
+    if (editingIdx.value !== -1 && messages.value[editingIdx.value]) {
+      messages.value[editingIdx.value].content = editValue.value
+      editingIdx.value = -1
+      editValue.value = ''
+    }
+  }
+
+  // Cancel editing and reset state
+  function cancelEdit() {
+    editingIdx.value = -1
+    editValue.value = ''
+  }
+
+  // Add a new user message
+  function addUserMessage(content: string) {
+    messages.value.push({
+      role: 'user',
+      content,
+    })
+  }
+
+  // Add a new assistant message
+  function addAssistantMessage(content: string = '') {
+    messages.value.push({
+      role: 'assistant',
+      content,
+    })
+  }
+
+  // Update the last assistant message content (for streaming)
+  function updateLastAssistantMessage(content: string) {
+    const lastMessage = messages.value[messages.value.length - 1]
+    if (lastMessage && lastMessage.role === 'assistant') {
+      lastMessage.content = content
+    }
+  }
+
+  // Remove messages after the specified index for regeneration
+  function prepareRegenerate(index: number) {
+    messages.value = messages.value.slice(0, index)
+    cancelEdit()
+  }
+
+  // Clear all messages
+  function clearMessages() {
+    messages.value = []
+    cancelEdit()
+  }
+
+  // Store chat record to server
+  async function storeRecord() {
+    if (!path.value)
+      return
+
+    try {
+      // Filter out empty messages before storing
+      const validMessages = messages.value.filter(msg => msg.content.trim() !== '')
+      await openai.store_record({
+        file_name: path.value,
+        messages: validMessages,
+      })
+    }
+    catch (error) {
+      console.error('Failed to store chat record:', error)
+    }
+  }
+
+  // Clear chat record on server
+  async function clearRecord() {
+    if (!path.value)
+      return
+
+    try {
+      await openai.store_record({
+        file_name: path.value,
+        messages: [],
+      })
+      clearMessages()
+    }
+    catch (error) {
+      console.error('Failed to clear chat record:', error)
+    }
+  }
+
+  // Set loading state
+  function setLoading(loadingState: boolean) {
+    loading.value = loadingState
+  }
+
+  // Set ask buffer
+  function setAskBuffer(buffer: string) {
+    askBuffer.value = buffer
+  }
+
+  // Clear ask buffer
+  function clearAskBuffer() {
+    askBuffer.value = ''
+  }
+
+  // scroll to bottom
+  function scrollToBottom() {
+    messageListRef.value?.scrollToBottom()
+  }
+
+  // Set streaming message index
+  function setStreamingMessageIndex(index: number) {
+    streamingMessageIndex.value = index
+  }
+
+  // Clear streaming message index
+  function clearStreamingMessageIndex() {
+    streamingMessageIndex.value = -1
+  }
+
+  // Request: Send messages to server using chat service
+  async function request() {
+    setLoading(true)
+
+    // Set the streaming message index to the last message (assistant message)
+    setStreamingMessageIndex(messages.value.length - 1)
+
+    try {
+      const chatService = new ChatService()
+      const assistantMessage = await chatService.request(
+        path.value,
+        messages.value.slice(0, -1), // Exclude the empty assistant message
+        message => {
+          // Update the current assistant message in real-time
+          updateLastAssistantMessage(message.content)
+        },
+      )
+
+      // Update the final content
+      updateLastAssistantMessage(assistantMessage.content)
+
+      // Auto scroll to bottom after response
+      await nextTick()
+      scrollToBottom()
+    }
+    catch (error) {
+      console.error('Chat request failed:', error)
+      // Remove the empty assistant message on error
+      if (messages.value.length > 0 && messages.value[messages.value.length - 1].content === '') {
+        messages.value.pop()
+      }
+    }
+    finally {
+      setLoading(false)
+      clearStreamingMessageIndex() // Clear streaming state
+      await storeRecord()
+    }
+  }
+
+  // Send: Add user message into messages then call request
+  async function send(content: string, currentLanguage?: string) {
+    if (messages.value.length === 0) {
+      // The first message
+      addUserMessage(`${content}\n\nCurrent Language Code: ${currentLanguage}`)
+    }
+    else {
+      // Append user's new message
+      addUserMessage(askBuffer.value)
+      clearAskBuffer()
+    }
+
+    // Add empty assistant message for real-time updates
+    addAssistantMessage('')
+
+    await request()
+  }
+
+  // Regenerate: Removes messages after index and re-request the answer
+  async function regenerate(index: number) {
+    prepareRegenerate(index)
+
+    // Add empty assistant message for real-time updates
+    addAssistantMessage('')
+
+    await request()
+  }
+
+  // Return all state, getters, and actions
+  return {
+    // State
+    messages,
+    loading,
+    editingIdx,
+    editValue,
+    askBuffer,
+    messageListRef,
+    streamingMessageIndex,
+
+    // Getters
+    isEditing,
+    currentEditingMessage,
+    hasMessages,
+    shouldShowStartButton,
+
+    // Actions
+    initMessages,
+    startEdit,
+    saveEdit,
+    cancelEdit,
+    addUserMessage,
+    addAssistantMessage,
+    updateLastAssistantMessage,
+    prepareRegenerate,
+    clearMessages,
+    storeRecord,
+    clearRecord,
+    setLoading,
+    setAskBuffer,
+    clearAskBuffer,
+    setStreamingMessageIndex,
+    clearStreamingMessageIndex,
+    request,
+    send,
+    regenerate,
+  }
+})

+ 110 - 0
app/src/components/ChatGPT/composables/useTypewriter.ts

@@ -0,0 +1,110 @@
+import type { Ref } from 'vue'
+
+interface TypewriterOptions {
+  baseSpeed?: number
+  fastSpeed?: number
+  scrollInterval?: number
+}
+
+export function useTypewriter(options: TypewriterOptions = {}) {
+  const {
+    baseSpeed = 35,
+    fastSpeed = 25,
+    scrollInterval = 150,
+  } = options
+
+  let isTyping = false
+  let typeQueue: string[] = []
+  let scrollTimer: number | null = null
+  let rafId: number | null = null
+
+  const typeText = async (
+    content: string,
+    targetRef: Ref<string>,
+    onScroll?: () => void,
+    isFastMode = false,
+  ): Promise<void> => {
+    return new Promise(resolve => {
+      if (isTyping) {
+        typeQueue.push(content)
+        resolve()
+        return
+      }
+
+      isTyping = true
+      const chars = content.split('')
+      let charIndex = 0
+
+      const typeNextChars = () => {
+        if (charIndex >= chars.length) {
+          isTyping = false
+
+          // Process queued content
+          if (typeQueue.length > 0) {
+            const nextContent = typeQueue.shift()!
+            typeText(nextContent, targetRef, onScroll, isFastMode).then(resolve)
+          }
+          else {
+            resolve()
+          }
+          return
+        }
+
+        // 一个字符一个字符地添加
+        targetRef.value += chars[charIndex]
+        charIndex++
+
+        // Throttled scrolling - 减少滚动频率
+        if (onScroll && !scrollTimer) {
+          scrollTimer = window.setTimeout(() => {
+            onScroll()
+            scrollTimer = null
+          }, scrollInterval)
+        }
+
+        // Dynamic speed based on mode
+        const delay = isFastMode ? fastSpeed : baseSpeed
+
+        rafId = requestAnimationFrame(() => {
+          setTimeout(typeNextChars, delay)
+        })
+      }
+
+      typeNextChars()
+    })
+  }
+
+  const resetTypewriter = () => {
+    isTyping = false
+    typeQueue = []
+
+    if (scrollTimer) {
+      clearTimeout(scrollTimer)
+      scrollTimer = null
+    }
+
+    if (rafId) {
+      cancelAnimationFrame(rafId)
+      rafId = null
+    }
+  }
+
+  const pauseTypewriter = () => {
+    if (rafId) {
+      cancelAnimationFrame(rafId)
+      rafId = null
+    }
+  }
+
+  const resumeTypewriter = () => {
+    // Typewriter will resume automatically when next content is queued
+  }
+
+  return {
+    typeText,
+    resetTypewriter,
+    pauseTypewriter,
+    resumeTypewriter,
+    isTyping: readonly(ref(isTyping)),
+  }
+}

+ 7 - 0
app/src/components/ChatGPT/index.ts

@@ -1,3 +1,10 @@
 import ChatGPT from './ChatGPT.vue'
 
+export { default as ChatMessage } from './ChatMessage.vue'
+export { default as ChatMessageInput } from './ChatMessageInput.vue'
+export { default as ChatMessageList } from './ChatMessageList.vue'
+export { ChatService } from './chatService'
+export { marked } from './markdown'
+export * from './types'
+export * from './utils'
 export default ChatGPT

+ 26 - 0
app/src/components/ChatGPT/markdown.ts

@@ -0,0 +1,26 @@
+import hljs from 'highlight.js'
+import nginx from 'highlight.js/lib/languages/nginx'
+import { Marked } from 'marked'
+import { markedHighlight } from 'marked-highlight'
+import 'highlight.js/styles/vs2015.css'
+
+// Register nginx language for highlight.js
+hljs.registerLanguage('nginx', nginx)
+
+// Markdown renderer
+export const marked = new Marked(
+  markedHighlight({
+    langPrefix: 'hljs language-',
+    highlight(code, lang) {
+      const language = hljs.getLanguage(lang) ? lang : 'nginx'
+      return hljs.highlight(code, { language }).value
+    },
+  }),
+)
+
+// Basic marked options
+marked.setOptions({
+  pedantic: false,
+  gfm: true,
+  breaks: false,
+})

+ 9 - 0
app/src/components/ChatGPT/types.ts

@@ -0,0 +1,9 @@
+export interface CodeBlockState {
+  isInCodeBlock: boolean
+  backtickCount: number
+}
+
+export interface ChatGPTProps {
+  content: string
+  path?: string
+}

+ 86 - 0
app/src/components/ChatGPT/utils.ts

@@ -0,0 +1,86 @@
+import type { CodeBlockState } from './types'
+
+/**
+ * transformReasonerThink: if <think> appears but is not paired with </think>, it will be automatically supplemented, and the entire text will be converted to a Markdown quote
+ */
+export function transformReasonerThink(rawText: string): string {
+  // 1. Count number of <think> vs </think>
+  const openThinkRegex = /<think>/gi
+  const closeThinkRegex = /<\/think>/gi
+
+  const openCount = (rawText.match(openThinkRegex) || []).length
+  const closeCount = (rawText.match(closeThinkRegex) || []).length
+
+  // 2. If open tags exceed close tags, append missing </think> at the end
+  if (openCount > closeCount) {
+    const diff = openCount - closeCount
+    rawText += '</think>'.repeat(diff)
+  }
+
+  // 3. Replace <think>...</think> blocks with Markdown blockquote ("> ...")
+  return rawText.replace(/<think>([\s\S]*?)<\/think>/g, (match, p1) => {
+    // Split the inner text by line, prefix each with "> "
+    const lines = p1.trim().split('\n')
+    const blockquoted = lines.map(line => `> ${line}`).join('\n')
+    // Return the replaced Markdown quote
+    return `\n${blockquoted}\n`
+  })
+}
+
+/**
+ * transformText: transform the text
+ */
+export function transformText(rawText: string): string {
+  return transformReasonerThink(rawText)
+}
+
+/**
+ * updateCodeBlockState: The number of unnecessary scans is reduced by changing the scanning method of incremental content
+ */
+export function updateCodeBlockState(chunk: string, codeBlockState: CodeBlockState) {
+  // count all ``` in chunk
+  // note to distinguish how many "backticks" are not paired
+
+  const regex = /```/g
+
+  while (regex.exec(chunk) !== null) {
+    codeBlockState.backtickCount++
+    // if backtickCount is even -> closed
+    codeBlockState.isInCodeBlock = codeBlockState.backtickCount % 2 !== 0
+  }
+}
+
+// Global scroll debouncing
+let scrollTimeoutId: number | null = null
+
+/**
+ * scrollToBottom: Scroll container to bottom with optimized performance
+ */
+export function scrollToBottom() {
+  // 更简单的防抖,避免过度优化导致的卡顿
+  if (scrollTimeoutId) {
+    return
+  }
+
+  scrollTimeoutId = window.setTimeout(() => {
+    const container = document.querySelector('.right-settings .ant-card-body')
+    if (container) {
+      // 直接设置scrollTop,避免动画导致的卡顿
+      container.scrollTop = container.scrollHeight
+    }
+    scrollTimeoutId = null
+  }, 50) // 减少到50ms,提高响应性
+}
+
+/**
+ * scrollToBottomSmooth: Smooth scroll version for manual interactions
+ */
+export function scrollToBottomSmooth() {
+  const container = document.querySelector('.right-settings .ant-card-body')
+  if (container) {
+    container.scrollTo({
+      top: container.scrollHeight,
+      behavior: 'smooth',
+    })
+  }
+}

+ 2 - 1
app/src/components/CodeEditor/CodeEditor.vue

@@ -12,6 +12,7 @@ const props = defineProps<{
   readonly?: boolean
   placeholder?: string
   disableCodeCompletion?: boolean
+  noBorderRadius?: boolean
 }>()
 
 const content = defineModel<string>('content', { default: '' })
@@ -46,7 +47,7 @@ onUnmounted(() => {
     theme="monokai"
     :style="{
       minHeight: defaultHeight || '100vh',
-      borderRadius: '5px',
+      borderRadius: props.noBorderRadius ? '0' : '5px',
     }"
     :readonly
     :placeholder

+ 1 - 1
app/src/components/PageHeader/PageHeader.vue

@@ -56,7 +56,7 @@ const name = computed(() => {
     margin-bottom: 16px;
   }
 
-  @media (max-height: 768px) {
+  @media (max-height: 800px) {
     display: none;
   }
 

+ 1 - 1
app/src/components/PortScanner/PortScannerCompact.vue

@@ -139,7 +139,7 @@ function quickScan(start: number, end: number) {
 </script>
 
 <template>
-  <div class="port-scanner-compact">
+  <div class="port-scanner-compact px-6 mb-6">
     <div class="scan-form">
       <ASpace direction="vertical" size="small" style="width: 100%">
         <ARow :gutter="8">

+ 177 - 161
app/src/language/ar/app.po

@@ -4,10 +4,10 @@ msgid ""
 msgstr ""
 "PO-Revision-Date: 2024-10-29 14:39+0000\n"
 "Last-Translator: mosaati <mohammed.saati@gmail.com>\n"
-"Language-Team: Arabic "
-"<https://weblate.nginxui.com/projects/nginx-ui/frontend/ar/>\n"
+"Language-Team: Arabic <https://weblate.nginxui.com/projects/nginx-ui/"
+"frontend/ar/>\n"
 "Language: ar\n"
-"Content-Type: text/plain; charset=utf-8\n"
+"Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
 "&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n"
@@ -32,7 +32,8 @@ msgid "[Nginx UI] Certificate successfully revoked"
 msgstr "[Nginx UI] تم إلغاء الشهادة بنجاح"
 
 #: src/language/generate.ts:35
-msgid "[Nginx UI] Certificate was used for server, reloading server TLS certificate"
+msgid ""
+"[Nginx UI] Certificate was used for server, reloading server TLS certificate"
 msgstr "[Nginx UI] تم استخدام الشهادة للخادم، إعادة تحميل شهادة TLS للخادم"
 
 #: src/language/generate.ts:36
@@ -158,10 +159,10 @@ msgid "Actual worker to configured ratio"
 msgstr "النسبة الفعلية للعامل إلى المُهيأ"
 
 #: src/components/NgxConfigEditor/NgxServer.vue:112
-#: src/components/NgxConfigEditor/NgxUpstream.vue:159 src/language/curd.ts:19
+#: src/components/NgxConfigEditor/NgxUpstream.vue:166 src/language/curd.ts:19
 #: src/views/preference/tabs/CertSettings.vue:45
 #: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:94
-#: src/views/stream/StreamList.vue:101
+#: src/views/stream/StreamList.vue:102
 msgid "Add"
 msgstr "إضافة"
 
@@ -188,7 +189,7 @@ msgstr "أضف مكان"
 msgid "Add Site"
 msgstr "أضف موقع"
 
-#: src/views/stream/StreamList.vue:138
+#: src/views/stream/StreamList.vue:139
 msgid "Add Stream"
 msgstr "أضف Stream"
 
@@ -276,7 +277,7 @@ msgid "Are you sure you want to delete permanently?"
 msgstr "هل أنت متأكد أنك تريد الحذف نهائيًا؟"
 
 #: src/language/curd.ts:25 src/views/site/site_list/SiteList.vue:100
-#: src/views/stream/StreamList.vue:121
+#: src/views/stream/StreamList.vue:122
 msgid "Are you sure you want to delete?"
 msgstr "هل أنت متأكد أنك تريد الحذف؟"
 
@@ -450,13 +451,14 @@ msgstr "جدول النسخ الاحتياطي"
 
 #: src/components/Notification/notifications.ts:38
 msgid "Backup task %{backup_name} completed successfully, file: %{file_path}"
-msgstr "تم إنجاز مهمة النسخ الاحتياطي %{backup_name} بنجاح، الملف: %{file_path}"
+msgstr ""
+"تم إنجاز مهمة النسخ الاحتياطي %{backup_name} بنجاح، الملف: %{file_path}"
 
 #: src/components/Notification/notifications.ts:34
-msgid "Backup task %{backup_name} failed during storage upload, error: %{error}"
+msgid ""
+"Backup task %{backup_name} failed during storage upload, error: %{error}"
 msgstr ""
-"فشلت مهمة النسخ الاحتياطي %{backup_name} أثناء تحميل التخزين، الخطأ: "
-"%{error}"
+"فشلت مهمة النسخ الاحتياطي %{backup_name} أثناء تحميل التخزين، الخطأ: %{error}"
 
 #: src/components/Notification/notifications.ts:30
 msgid "Backup task %{backup_name} failed to execute, error: %{error}"
@@ -487,7 +489,7 @@ msgid "Base information"
 msgstr "المعلومات الأساسية"
 
 #: src/views/config/ConfigEditor.vue:300
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:31
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:32
 #: src/views/stream/components/RightPanel/RightPanel.vue:20
 msgid "Basic"
 msgstr "أساسي"
@@ -535,7 +537,8 @@ msgstr "ذاكرة التخزين المؤقت"
 
 #: src/views/dashboard/components/ParamsOpt/ProxyCacheConfig.vue:178
 msgid "Cache items not accessed within this time will be removed"
-msgstr "سيتم إزالة عناصر الذاكرة المؤقتة التي لم يتم الوصول إليها خلال هذا الوقت"
+msgstr ""
+"سيتم إزالة عناصر الذاكرة المؤقتة التي لم يتم الوصول إليها خلال هذا الوقت"
 
 #: src/views/dashboard/components/ParamsOpt/ProxyCacheConfig.vue:350
 msgid "Cache loader processing time threshold"
@@ -739,7 +742,7 @@ msgstr "المسار المتغير"
 msgid "Channel"
 msgstr "القناة"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:41
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:42
 #: src/views/stream/components/RightPanel/RightPanel.vue:23
 msgid "Chat"
 msgstr "محادثة"
@@ -756,23 +759,23 @@ msgstr "تحقق مرة أخرى"
 #: src/language/generate.ts:6
 msgid ""
 "Check if /var/run/docker.sock exists. If you are using Nginx UI Official "
-"Docker Image, please make sure the docker socket is mounted like this: `-v "
-"/var/run/docker.sock:/var/run/docker.sock`. Nginx UI official image uses "
-"/var/run/docker.sock to communicate with the host Docker Engine via Docker "
-"Client API. This feature is used to control Nginx in another container and "
-"perform container replacement rather than binary replacement during OTA "
-"upgrades of Nginx UI to ensure container dependencies are also upgraded. If "
-"you don't need this feature, please add the environment variable "
+"Docker Image, please make sure the docker socket is mounted like this: `-v /"
+"var/run/docker.sock:/var/run/docker.sock`. Nginx UI official image uses /var/"
+"run/docker.sock to communicate with the host Docker Engine via Docker Client "
+"API. This feature is used to control Nginx in another container and perform "
+"container replacement rather than binary replacement during OTA upgrades of "
+"Nginx UI to ensure container dependencies are also upgraded. If you don't "
+"need this feature, please add the environment variable "
 "NGINX_UI_IGNORE_DOCKER_SOCKET=true to the container."
 msgstr ""
 "تحقق مما إذا كان /var/run/docker.sock موجودًا. إذا كنت تستخدم صورة Docker "
-"الرسمية لـ Nginx UI، يرجى التأكد من توصيل مقبس Docker بهذه الطريقة: `-v "
-"/var/run/docker.sock:/var/run/docker.sock`. تستخدم صورة Nginx UI الرسمية "
-"/var/run/docker.sock للتواصل مع محرك Docker المضيف عبر واجهة برمجة تطبيقات "
-"Docker Client. تُستخدم هذه الميزة للتحكم في Nginx في حاوية أخرى وإجراء "
-"استبدال الحاوية بدلاً من استبدال الثنائي أثناء التحديثات OTA لـ Nginx UI "
-"لضمان تحديث تبعيات الحاوية أيضًا. إذا كنت لا تحتاج إلى هذه الميزة، يرجى "
-"إضافة متغير البيئة NGINX_UI_IGNORE_DOCKER_SOCKET=true إلى الحاوية."
+"الرسمية لـ Nginx UI، يرجى التأكد من توصيل مقبس Docker بهذه الطريقة: `-v /var/"
+"run/docker.sock:/var/run/docker.sock`. تستخدم صورة Nginx UI الرسمية /var/run/"
+"docker.sock للتواصل مع محرك Docker المضيف عبر واجهة برمجة تطبيقات Docker "
+"Client. تُستخدم هذه الميزة للتحكم في Nginx في حاوية أخرى وإجراء استبدال "
+"الحاوية بدلاً من استبدال الثنائي أثناء التحديثات OTA لـ Nginx UI لضمان تحديث "
+"تبعيات الحاوية أيضًا. إذا كنت لا تحتاج إلى هذه الميزة، يرجى إضافة متغير "
+"البيئة NGINX_UI_IGNORE_DOCKER_SOCKET=true إلى الحاوية."
 
 #: src/components/SelfCheck/tasks/frontend/https-check.ts:14
 msgid ""
@@ -784,19 +787,19 @@ msgstr ""
 
 #: src/language/generate.ts:8
 msgid ""
-"Check if the nginx access log path exists. By default, this path is "
-"obtained from 'nginx -V'. If it cannot be obtained or the obtained path "
-"does not point to a valid, existing file, an error will be reported. In "
-"this case, you need to modify the configuration file to specify the access "
-"log path.Refer to the docs for more details: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#accesslogpath"
+"Check if the nginx access log path exists. By default, this path is obtained "
+"from 'nginx -V'. If it cannot be obtained or the obtained path does not "
+"point to a valid, existing file, an error will be reported. In this case, "
+"you need to modify the configuration file to specify the access log path."
+"Refer to the docs for more details: https://nginxui.com/zh_CN/guide/config-"
+"nginx.html#accesslogpath"
 msgstr ""
-"تحقق مما إذا كان مسار سجل الوصول إلى nginx موجودًا. بشكل افتراضي، يتم "
-"الحصول على هذا المسار من 'nginx -V'. إذا لم يتم الحصول عليه أو إذا كان "
-"المسار الذي تم الحصول عليه لا يشير إلى ملف صالح موجود، فسيتم الإبلاغ عن "
-"خطأ. في هذه الحالة، تحتاج إلى تعديل ملف التكوين لتحديد مسار سجل الوصول. "
-"راجع الوثائق لمزيد من التفاصيل: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#accesslogpath"
+"تحقق مما إذا كان مسار سجل الوصول إلى nginx موجودًا. بشكل افتراضي، يتم الحصول "
+"على هذا المسار من 'nginx -V'. إذا لم يتم الحصول عليه أو إذا كان المسار الذي "
+"تم الحصول عليه لا يشير إلى ملف صالح موجود، فسيتم الإبلاغ عن خطأ. في هذه "
+"الحالة، تحتاج إلى تعديل ملف التكوين لتحديد مسار سجل الوصول. راجع الوثائق "
+"لمزيد من التفاصيل: https://nginxui.com/zh_CN/guide/config-nginx."
+"html#accesslogpath"
 
 #: src/language/generate.ts:9
 msgid "Check if the nginx configuration directory exists"
@@ -811,30 +814,29 @@ msgid ""
 "Check if the nginx error log path exists. By default, this path is obtained "
 "from 'nginx -V'. If it cannot be obtained or the obtained path does not "
 "point to a valid, existing file, an error will be reported. In this case, "
-"you need to modify the configuration file to specify the error log "
-"path.Refer to the docs for more details: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#errorlogpath"
+"you need to modify the configuration file to specify the error log path."
+"Refer to the docs for more details: https://nginxui.com/zh_CN/guide/config-"
+"nginx.html#errorlogpath"
 msgstr ""
 "تحقق مما إذا كان مسار سجل أخطاء nginx موجودًا. بشكل افتراضي، يتم الحصول على "
 "هذا المسار من 'nginx -V'. إذا تعذر الحصول عليه أو إذا كان المسار الذي تم "
-"الحصول عليه لا يشير إلى ملف صالح موجود، فسيتم الإبلاغ عن خطأ. في هذه "
-"الحالة، تحتاج إلى تعديل ملف التكوين لتحديد مسار سجل الأخطاء. راجع الوثائق "
-"لمزيد من التفاصيل: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#errorlogpath"
+"الحصول عليه لا يشير إلى ملف صالح موجود، فسيتم الإبلاغ عن خطأ. في هذه الحالة، "
+"تحتاج إلى تعديل ملف التكوين لتحديد مسار سجل الأخطاء. راجع الوثائق لمزيد من "
+"التفاصيل: https://nginxui.com/zh_CN/guide/config-nginx.html#errorlogpath"
 
 #: src/language/generate.ts:7
 msgid ""
 "Check if the nginx PID path exists. By default, this path is obtained from "
 "'nginx -V'. If it cannot be obtained, an error will be reported. In this "
 "case, you need to modify the configuration file to specify the Nginx PID "
-"path.Refer to the docs for more details: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#pidpath"
+"path.Refer to the docs for more details: https://nginxui.com/zh_CN/guide/"
+"config-nginx.html#pidpath"
 msgstr ""
-"تحقق مما إذا كان مسار معرف عملية Nginx موجودًا. بشكل افتراضي، يتم الحصول "
-"على هذا المسار من الأمر 'nginx -V'. إذا تعذر الحصول عليه، سيتم الإبلاغ عن "
-"خطأ. في هذه الحالة، تحتاج إلى تعديل ملف التكوين لتحديد مسار معرف عملية "
-"Nginx. راجع الوثائق لمزيد من التفاصيل: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#pidpath"
+"تحقق مما إذا كان مسار معرف عملية Nginx موجودًا. بشكل افتراضي، يتم الحصول على "
+"هذا المسار من الأمر 'nginx -V'. إذا تعذر الحصول عليه، سيتم الإبلاغ عن خطأ. "
+"في هذه الحالة، تحتاج إلى تعديل ملف التكوين لتحديد مسار معرف عملية Nginx. "
+"راجع الوثائق لمزيد من التفاصيل: https://nginxui.com/zh_CN/guide/config-nginx."
+"html#pidpath"
 
 #: src/language/generate.ts:12
 msgid "Check if the nginx.conf includes the conf.d directory"
@@ -858,8 +860,8 @@ msgstr ""
 
 #: src/language/generate.ts:16
 msgid ""
-"Check if the streams-available and streams-enabled directories are under "
-"the nginx configuration directory"
+"Check if the streams-available and streams-enabled directories are under the "
+"nginx configuration directory"
 msgstr ""
 "تحقق مما إذا كانت الدلائل streams-available و streams-enabled موجودة ضمن "
 "دليل تكوين nginx"
@@ -988,7 +990,7 @@ msgstr "ملف إدخال التكوين غير موجود"
 msgid "Config path is empty"
 msgstr "مسار التكوين فارغ"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:37
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:38
 msgid "Config Template"
 msgstr "قالب التكوين"
 
@@ -1084,7 +1086,7 @@ msgstr "استخدام وحدة المعالجة المركزية مرتفع ن
 msgid "CPU:"
 msgstr "CPU:"
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:170
+#: src/components/NgxConfigEditor/NgxUpstream.vue:177
 msgid "Create"
 msgstr "إنشاء"
 
@@ -1223,10 +1225,10 @@ msgid "Define shared memory zone name and size, e.g. proxy_cache:10m"
 msgstr "حدد اسم منطقة الذاكرة المشتركة والحجم، على سبيل المثال proxy_cache:10m"
 
 #: src/components/NgxConfigEditor/NgxServer.vue:78
-#: src/components/NgxConfigEditor/NgxUpstream.vue:129 src/language/curd.ts:9
+#: src/components/NgxConfigEditor/NgxUpstream.vue:134 src/language/curd.ts:9
 #: src/views/certificate/components/RemoveCert.vue:88
 #: src/views/site/site_list/SiteList.vue:109
-#: src/views/stream/StreamList.vue:130
+#: src/views/stream/StreamList.vue:131
 msgid "Delete"
 msgstr "حذف"
 
@@ -1524,13 +1526,13 @@ msgid ""
 "Due to the security policies of some browsers, you cannot use passkeys on "
 "non-HTTPS websites, except when running on localhost."
 msgstr ""
-"نظرًا لسياسات الأمان لبعض المتصفحات، لا يمكنك استخدام مفاتيح المرور على "
-"مواقع الويب غير HTTPS، إلا عند التشغيل على localhost."
+"نظرًا لسياسات الأمان لبعض المتصفحات، لا يمكنك استخدام مفاتيح المرور على مواقع "
+"الويب غير HTTPS، إلا عند التشغيل على localhost."
 
 #: src/views/site/site_list/SiteDuplicate.vue:72
 #: src/views/site/site_list/SiteList.vue:95
 #: src/views/stream/components/StreamDuplicate.vue:64
-#: src/views/stream/StreamList.vue:116
+#: src/views/stream/StreamList.vue:117
 msgid "Duplicate"
 msgstr "مكرر"
 
@@ -1711,7 +1713,7 @@ msgstr "تم تنظيف متغيرات البيئة"
 
 #: src/routes/modules/environments.ts:11
 #: src/views/dashboard/Environments.vue:83
-#: src/views/environments/list/Environment.vue:81
+#: src/views/environments/list/Environment.vue:82
 msgid "Environments"
 msgstr "البيئات"
 
@@ -2573,7 +2575,7 @@ msgstr "يستمع"
 msgid "Load Average:"
 msgstr "متوسط التحميل:"
 
-#: src/views/environments/list/Environment.vue:88
+#: src/views/environments/list/Environment.vue:89
 msgid "Load from settings"
 msgstr "تحميل من الإعدادات"
 
@@ -2634,12 +2636,12 @@ msgstr "سجل"
 #: src/language/generate.ts:20
 msgid ""
 "Log file %{log_path} is not a regular file. If you are using nginx-ui in "
-"docker container, please refer to "
-"https://nginxui.com/zh_CN/guide/config-nginx-log.html for more information."
+"docker container, please refer to https://nginxui.com/zh_CN/guide/config-"
+"nginx-log.html for more information."
 msgstr ""
 "ملف السجل %{log_path} ليس ملفًا عاديًا. إذا كنت تستخدم nginx-ui في حاوية "
-"Docker، يرجى الرجوع إلى "
-"https://nginxui.com/zh_CN/guide/config-nginx-log.html لمزيد من المعلومات."
+"Docker، يرجى الرجوع إلى https://nginxui.com/zh_CN/guide/config-nginx-log."
+"html لمزيد من المعلومات."
 
 #: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:72
 msgid "Log List"
@@ -2663,19 +2665,19 @@ msgstr "تدوير السجلات"
 
 #: src/views/preference/tabs/LogrotateSettings.vue:13
 msgid ""
-"Logrotate, by default, is enabled in most mainstream Linux distributions "
-"for users who install Nginx UI on the host machine, so you don't need to "
-"modify the parameters on this page. For users who install Nginx UI using "
-"Docker containers, you can manually enable this option. The crontab task "
-"scheduler of Nginx UI will execute the logrotate command at the interval "
-"you set in minutes."
+"Logrotate, by default, is enabled in most mainstream Linux distributions for "
+"users who install Nginx UI on the host machine, so you don't need to modify "
+"the parameters on this page. For users who install Nginx UI using Docker "
+"containers, you can manually enable this option. The crontab task scheduler "
+"of Nginx UI will execute the logrotate command at the interval you set in "
+"minutes."
 msgstr ""
 "بشكل افتراضي، يتم تفعيل تدوير السجلات في معظم توزيعات لينكس الرئيسية "
 "للمستخدمين الذين يقومون بتثبيت واجهة Nginx UI على الجهاز المضيف، لذا لا "
-"تحتاج إلى تعديل معايير في هذه الصفحة. بالنسبة للمستخدمين الذين يقومون "
-"بتثبيت واجهة Nginx UI باستخدام حاويات Docker، يمكنك تمكين هذا الخيار "
-"يدويًا. سيقوم مجدول المهام crontab الخاص بواجهة Nginx UI بتنفيذ أمر تدوير "
-"السجلات في الفاصل الزمني الذي تحدده بالدقائق."
+"تحتاج إلى تعديل معايير في هذه الصفحة. بالنسبة للمستخدمين الذين يقومون بتثبيت "
+"واجهة Nginx UI باستخدام حاويات Docker، يمكنك تمكين هذا الخيار يدويًا. سيقوم "
+"مجدول المهام crontab الخاص بواجهة Nginx UI بتنفيذ أمر تدوير السجلات في "
+"الفاصل الزمني الذي تحدده بالدقائق."
 
 #: src/views/site/components/SiteStatusSelect.vue:165
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:68
@@ -2869,7 +2871,7 @@ msgstr "يوميًا في اليوم %{day} الساعة %{time}"
 msgid "Multi-line Directive"
 msgstr "توجيه متعدد الأسطر"
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:182
+#: src/components/NgxConfigEditor/NgxUpstream.vue:189
 #: src/views/backup/AutoBackup/AutoBackup.vue:11
 #: src/views/certificate/ACMEUser.vue:11
 #: src/views/certificate/CertificateEditor.vue:162
@@ -2887,7 +2889,7 @@ msgstr "توجيه متعدد الأسطر"
 #: src/views/stream/columns.tsx:12
 #: src/views/stream/components/RightPanel/Basic.vue:72
 #: src/views/stream/components/StreamDuplicate.vue:71
-#: src/views/stream/StreamList.vue:143
+#: src/views/stream/StreamList.vue:144
 msgid "Name"
 msgstr "اسم"
 
@@ -3118,8 +3120,8 @@ msgstr "تمت استعادة تكوين Nginx UI"
 
 #: src/components/SystemRestore/SystemRestoreContent.vue:336
 msgid ""
-"Nginx UI configuration has been restored and will restart automatically in "
-"a few seconds."
+"Nginx UI configuration has been restored and will restart automatically in a "
+"few seconds."
 msgstr "تمت استعادة تكوين Nginx UI وسيتم إعادة التشغيل تلقائيًا خلال بضع ثوانٍ."
 
 #: src/language/generate.ts:26
@@ -3143,7 +3145,7 @@ msgstr "يتضمن Nginx.conf دليل streams-enabled"
 #: src/views/notification/Notification.vue:38
 #: src/views/preference/tabs/AuthSettings.vue:132
 #: src/views/preference/tabs/CertSettings.vue:73
-#: src/views/site/site_list/SiteList.vue:98 src/views/stream/StreamList.vue:119
+#: src/views/site/site_list/SiteList.vue:98 src/views/stream/StreamList.vue:120
 msgid "No"
 msgstr "لا"
 
@@ -3237,11 +3239,13 @@ msgstr "عدد عمليات العامل المتزامنة، يتم الضبط
 
 #: src/views/dashboard/components/ParamsOpt/ProxyCacheConfig.vue:315
 msgid "Number of files processed by cache loader at once"
-msgstr "عدد الملفات التي تتم معالجتها بواسطة محمل ذاكرة التخزين المؤقت في وقت واحد"
+msgstr ""
+"عدد الملفات التي تتم معالجتها بواسطة محمل ذاكرة التخزين المؤقت في وقت واحد"
 
 #: src/views/dashboard/components/ParamsOpt/ProxyCacheConfig.vue:253
 msgid "Number of files processed by cache manager at once"
-msgstr "عدد الملفات التي تتم معالجتها بواسطة مدير ذاكرة التخزين المؤقت في وقت واحد"
+msgstr ""
+"عدد الملفات التي تتم معالجتها بواسطة مدير ذاكرة التخزين المؤقت في وقت واحد"
 
 #: src/composables/usePerformanceMetrics.ts:129
 #: src/composables/usePerformanceMetrics.ts:169
@@ -3276,7 +3280,7 @@ msgid "Off"
 msgstr "إيقاف"
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:159
-#: src/components/NgxConfigEditor/NgxUpstream.vue:145
+#: src/components/NgxConfigEditor/NgxUpstream.vue:151
 #: src/components/NodeSelector/NodeSelector.vue:109
 #: src/components/ProxyTargets/ProxyTargets.vue:43
 #: src/views/dashboard/Environments.vue:107
@@ -3297,7 +3301,7 @@ msgstr "غير متصل"
 #: src/views/site/site_list/SiteList.vue:99
 #: src/views/stream/components/RightPanel/Basic.vue:48
 #: src/views/stream/components/StreamStatusSelect.vue:60
-#: src/views/stream/StreamList.vue:120
+#: src/views/stream/StreamList.vue:121
 msgid "OK"
 msgstr "حسنًا"
 
@@ -3499,7 +3503,8 @@ msgstr ""
 msgid ""
 "Please enter a name for the passkey you wish to create and click the OK "
 "button below."
-msgstr "يرجى إدخال اسم لمفتاح المرور الذي ترغب في إنشائه ثم انقر على زر موافق أدناه."
+msgstr ""
+"يرجى إدخال اسم لمفتاح المرور الذي ترغب في إنشائه ثم انقر على زر موافق أدناه."
 
 #: src/components/PortScanner/PortScannerCompact.vue:85
 msgid "Please enter a valid port range"
@@ -3543,8 +3548,8 @@ msgstr ""
 #: src/components/Notification/notifications.ts:182
 #: src/language/constants.ts:59
 msgid ""
-"Please generate new recovery codes in the preferences immediately to "
-"prevent lockout."
+"Please generate new recovery codes in the preferences immediately to prevent "
+"lockout."
 msgstr "يرجى إنشاء رموز استرداد جديدة في التفضيلات على الفور لمنع الإغلاق."
 
 #: src/views/config/components/Rename.vue:65
@@ -3586,7 +3591,8 @@ msgid "Please log in."
 msgstr "الرجاء تسجيل الدخول."
 
 #: src/views/certificate/DNSCredential.vue:61
-msgid "Please note that the unit of time configurations below are all in seconds."
+msgid ""
+"Please note that the unit of time configurations below are all in seconds."
 msgstr "يرجى ملاحظة أن تكوين وحدات الوقت أدناه كلها بالثواني."
 
 #: src/views/install/components/InstallView.vue:102
@@ -3605,17 +3611,17 @@ msgstr "الرجاء تحديد ملف النسخ الاحتياطي"
 msgid "Please select at least one item"
 msgstr "الرجاء تحديد عنصر واحد على الأقل"
 
-#: src/views/environments/list/Environment.vue:120
+#: src/views/environments/list/Environment.vue:121
 #: src/views/environments/list/Environment.vue:35
 msgid "Please select at least one node to reload Nginx"
 msgstr "الرجاء تحديد عقدة واحدة على الأقل لإعادة تحميل Nginx"
 
-#: src/views/environments/list/Environment.vue:141
+#: src/views/environments/list/Environment.vue:142
 #: src/views/environments/list/Environment.vue:49
 msgid "Please select at least one node to restart Nginx"
 msgstr "الرجاء تحديد عقدة واحدة على الأقل لإعادة تشغيل Nginx"
 
-#: src/views/environments/list/Environment.vue:99
+#: src/views/environments/list/Environment.vue:100
 msgid "Please select at least one node to upgrade"
 msgstr "يرجى اختيار عقدة واحدة على الأقل للترقية"
 
@@ -3628,7 +3634,7 @@ msgstr "يرجى كتابة \"إلغاء\" للتأكيد"
 msgid "Port"
 msgstr "المنفذ"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:44
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:45
 #: src/views/stream/components/RightPanel/RightPanel.vue:26
 msgid "Port Scanner"
 msgstr "ماسح المنافذ"
@@ -3797,8 +3803,8 @@ msgstr "إعادة تحميل"
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:136
 #: src/views/environments/group/columns.ts:22
 #: src/views/environments/group/EnvGroup.vue:50
-#: src/views/environments/list/Environment.vue:128
-#: src/views/environments/list/Environment.vue:136
+#: src/views/environments/list/Environment.vue:129
+#: src/views/environments/list/Environment.vue:137
 msgid "Reload Nginx"
 msgstr "إعادة تحميل Nginx"
 
@@ -3847,7 +3853,7 @@ msgstr "إزالة بنجاح"
 msgid "Removed successfully"
 msgstr "تمت الإزالة بنجاح"
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:126
+#: src/components/NgxConfigEditor/NgxUpstream.vue:131
 #: src/views/config/components/ConfigName.vue:51
 #: src/views/config/components/Rename.vue:56
 #: src/views/config/ConfigList.vue:181
@@ -3977,8 +3983,8 @@ msgid "Restart"
 msgstr "إعادة تشغيل"
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:148
-#: src/views/environments/list/Environment.vue:149
-#: src/views/environments/list/Environment.vue:157
+#: src/views/environments/list/Environment.vue:150
+#: src/views/environments/list/Environment.vue:158
 msgid "Restart Nginx"
 msgstr "إعادة تشغيل Nginx"
 
@@ -4400,19 +4406,19 @@ msgstr "تعيين موفر تحدي HTTP01"
 
 #: src/constants/errors/nginx_log.ts:8
 msgid ""
-"Settings.NginxLogSettings.AccessLogPath is empty, refer to "
-"https://nginxui.com/guide/config-nginx.html for more information"
+"Settings.NginxLogSettings.AccessLogPath is empty, refer to https://nginxui."
+"com/guide/config-nginx.html for more information"
 msgstr ""
-"إعدادات.Settings.NginxLogSettings.AccessLogPath فارغة، راجع "
-"https://nginxui.com/guide/config-nginx.html لمزيد من المعلومات"
+"إعدادات.Settings.NginxLogSettings.AccessLogPath فارغة، راجع https://nginxui."
+"com/guide/config-nginx.html لمزيد من المعلومات"
 
 #: src/constants/errors/nginx_log.ts:7
 msgid ""
-"Settings.NginxLogSettings.ErrorLogPath is empty, refer to "
-"https://nginxui.com/guide/config-nginx.html for more information"
+"Settings.NginxLogSettings.ErrorLogPath is empty, refer to https://nginxui."
+"com/guide/config-nginx.html for more information"
 msgstr ""
-"إعدادات.Settings.NginxLogSettings.ErrorLogPath فارغة، راجع "
-"https://nginxui.com/guide/config-nginx.html لمزيد من المعلومات"
+"إعدادات.Settings.NginxLogSettings.ErrorLogPath فارغة، راجع https://nginxui."
+"com/guide/config-nginx.html لمزيد من المعلومات"
 
 #: src/views/install/components/InstallView.vue:65
 msgid "Setup your Nginx UI"
@@ -4645,19 +4651,19 @@ msgstr "الأحد"
 msgid ""
 "Support communication with the backend through the Server-Sent Events "
 "protocol. If your Nginx UI is being used via an Nginx reverse proxy, please "
-"refer to this link to write the corresponding configuration file: "
-"https://nginxui.com/guide/nginx-proxy-example.html"
+"refer to this link to write the corresponding configuration file: https://"
+"nginxui.com/guide/nginx-proxy-example.html"
 msgstr ""
 "دعم الاتصال مع الخلفية من خلال بروتوكول Server-Sent Events. إذا كنت تستخدم "
-"واجهة Nginx UI عبر وكيل عكسي لـ Nginx، يرجى الرجوع إلى هذا الرابط لكتابة "
-"ملف التكوين المقابل: https://nginxui.com/guide/nginx-proxy-example.html"
+"واجهة Nginx UI عبر وكيل عكسي لـ Nginx، يرجى الرجوع إلى هذا الرابط لكتابة ملف "
+"التكوين المقابل: https://nginxui.com/guide/nginx-proxy-example.html"
 
 #: src/components/SelfCheck/tasks/frontend/websocket.ts:13
 msgid ""
 "Support communication with the backend through the WebSocket protocol. If "
-"your Nginx UI is being used via an Nginx reverse proxy, please refer to "
-"this link to write the corresponding configuration file: "
-"https://nginxui.com/guide/nginx-proxy-example.html"
+"your Nginx UI is being used via an Nginx reverse proxy, please refer to this "
+"link to write the corresponding configuration file: https://nginxui.com/"
+"guide/nginx-proxy-example.html"
 msgstr ""
 "دعم الاتصال مع الخلفية من خلال بروتوكول WebSocket. إذا كنت تستخدم واجهة "
 "Nginx عبر وكيل عكسي لـ Nginx، يرجى الرجوع إلى هذا الرابط لكتابة ملف التكوين "
@@ -4826,11 +4832,10 @@ msgstr "المدخل ليس مفتاح شهادة SSL"
 
 #: src/constants/errors/nginx_log.ts:2
 msgid ""
-"The log path is not under the paths in "
-"settings.NginxSettings.LogDirWhiteList"
+"The log path is not under the paths in settings.NginxSettings.LogDirWhiteList"
 msgstr ""
-"مسار السجل ليس ضمن المسارات الموجودة في "
-"settings.NginxSettings.LogDirWhiteList"
+"مسار السجل ليس ضمن المسارات الموجودة في settings.NginxSettings."
+"LogDirWhiteList"
 
 #: src/views/preference/tabs/OpenAISettings.vue:23
 #: src/views/preference/tabs/OpenAISettings.vue:89
@@ -4842,7 +4847,8 @@ msgstr ""
 "فقط."
 
 #: src/views/preference/tabs/OpenAISettings.vue:90
-msgid "The model used for code completion, if not set, the chat model will be used."
+msgid ""
+"The model used for code completion, if not set, the chat model will be used."
 msgstr ""
 "النموذج المستخدم لإكمال التعليمات البرمجية، إذا لم يتم تعيينه، سيتم استخدام "
 "نموذج الدردشة."
@@ -4951,13 +4957,14 @@ msgid "This field should not be empty"
 msgstr "يجب ألا يكون هذا الحقل فارغًا"
 
 #: src/constants/form_errors.ts:6
-msgid "This field should only contain letters, unicode characters, numbers, and -_."
+msgid ""
+"This field should only contain letters, unicode characters, numbers, and -_."
 msgstr "يجب أن يحتوي هذا الحقل على حروف وأحرف يونيكود وأرقام و-_. فقط."
 
 #: src/language/curd.ts:44
 msgid ""
-"This field should only contain letters, unicode characters, numbers, and "
-"-_./:"
+"This field should only contain letters, unicode characters, numbers, and -"
+"_./:"
 msgstr "يجب أن يحتوي هذا الحقل على أحرف وأحرف يونيكود وأرقام و -_./: فقط"
 
 #: src/views/dashboard/NginxDashBoard.vue:150
@@ -4965,8 +4972,8 @@ msgid ""
 "This module provides Nginx request statistics, connection count, etc. data. "
 "After enabling it, you can view performance statistics"
 msgstr ""
-"توفر هذه الوحدة إحصائيات طلبات Nginx وعدد الاتصالات وما إلى ذلك من "
-"البيانات. بعد تمكينها، يمكنك عرض إحصائيات الأداء"
+"توفر هذه الوحدة إحصائيات طلبات Nginx وعدد الاتصالات وما إلى ذلك من البيانات. "
+"بعد تمكينها، يمكنك عرض إحصائيات الأداء"
 
 #: src/views/certificate/components/RemoveCert.vue:104
 msgid ""
@@ -5003,11 +5010,12 @@ msgid ""
 "This will restore configuration files and database. Nginx UI will restart "
 "after the restoration is complete."
 msgstr ""
-"سيؤدي هذا إلى استعادة ملفات التكوين وقاعدة البيانات. سيعاد تشغيل واجهة "
-"Nginx بعد اكتمال الاستعادة."
+"سيؤدي هذا إلى استعادة ملفات التكوين وقاعدة البيانات. سيعاد تشغيل واجهة Nginx "
+"بعد اكتمال الاستعادة."
 
 #: src/views/environments/list/BatchUpgrader.vue:182
-msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
+msgid ""
+"This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
 msgstr "سيتم ترقية أو إعادة تثبيت Nginx UI على %{nodeNames} إلى %{version}."
 
 #: src/views/preference/tabs/AuthSettings.vue:92
@@ -5061,8 +5069,8 @@ msgstr ""
 #: src/views/site/site_edit/components/EnableTLS/EnableTLS.vue:15
 msgid ""
 "To make sure the certification auto-renewal can work normally, we need to "
-"add a location which can proxy the request from authority to backend, and "
-"we need to save this file and reload the Nginx. Are you sure you want to "
+"add a location which can proxy the request from authority to backend, and we "
+"need to save this file and reload the Nginx. Are you sure you want to "
 "continue?"
 msgstr ""
 "لضمان عمل تجديد الشهادة التلقائي بشكل طبيعي، نحتاج إلى إضافة موقع يمكنه "
@@ -5075,9 +5083,9 @@ msgid ""
 "provide an OpenAI-compatible API endpoint, so just set the baseUrl to your "
 "local API."
 msgstr ""
-"لاستخدام نموذج كبير محلي، قم بنشره باستخدام ollama أو vllm أو lmdeploy. "
-"توفر هذه الأدوات نقطة نهاية API متوافقة مع OpenAI، لذا ما عليك سوى تعيين "
-"baseUrl إلى API المحلي الخاص بك."
+"لاستخدام نموذج كبير محلي، قم بنشره باستخدام ollama أو vllm أو lmdeploy. توفر "
+"هذه الأدوات نقطة نهاية API متوافقة مع OpenAI، لذا ما عليك سوى تعيين baseUrl "
+"إلى API المحلي الخاص بك."
 
 #: src/views/dashboard/NginxDashBoard.vue:55
 msgid "Toggle failed"
@@ -5186,8 +5194,8 @@ msgid "Updated at"
 msgstr "محدث في"
 
 #: src/routes/modules/system.ts:26
-#: src/views/environments/list/Environment.vue:107
-#: src/views/environments/list/Environment.vue:115
+#: src/views/environments/list/Environment.vue:108
+#: src/views/environments/list/Environment.vue:116
 #: src/views/system/Upgrade.vue:154 src/views/system/Upgrade.vue:159
 msgid "Upgrade"
 msgstr "ترقية"
@@ -5217,7 +5225,7 @@ msgstr "تحميل المجلدات"
 msgid "Upstream"
 msgstr "أعلى التيار"
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:177
+#: src/components/NgxConfigEditor/NgxUpstream.vue:184
 msgid "Upstream Name"
 msgstr "اسم المنبع"
 
@@ -5333,8 +5341,8 @@ msgid ""
 "you have a valid backup file and security token, and carefully select what "
 "to restore."
 msgstr ""
-"تحذير: ستقوم عملية الاستعادة بالكتابة فوق التكوينات الحالية. تأكد من أن "
-"لديك ملف نسخ احتياطي صالحًا ورمزًا أمنيًا، واختر بعناية ما تريد استعادته."
+"تحذير: ستقوم عملية الاستعادة بالكتابة فوق التكوينات الحالية. تأكد من أن لديك "
+"ملف نسخ احتياطي صالحًا ورمزًا أمنيًا، واختر بعناية ما تريد استعادته."
 
 #: src/views/certificate/DNSCredential.vue:55
 msgid ""
@@ -5344,8 +5352,8 @@ msgstr "سنضيف سجل أو أكثر من سجلات TXT إلى سجلات DN
 
 #: src/views/site/site_edit/components/Cert/ObtainCert.vue:140
 msgid ""
-"We will remove the HTTPChallenge configuration from this file and reload "
-"the Nginx. Are you sure you want to continue?"
+"We will remove the HTTPChallenge configuration from this file and reload the "
+"Nginx. Are you sure you want to continue?"
 msgstr ""
 "سنقوم بإزالة تكوين HTTPChallenge من هذا الملف وإعادة تحميل Nginx. هل أنت "
 "متأكد أنك تريد المتابعة؟"
@@ -5447,11 +5455,11 @@ msgstr "نعم"
 
 #: src/views/terminal/Terminal.vue:132
 msgid ""
-"You are accessing this terminal over an insecure HTTP connection on a "
-"non-localhost domain. This may expose sensitive information."
+"You are accessing this terminal over an insecure HTTP connection on a non-"
+"localhost domain. This may expose sensitive information."
 msgstr ""
-"أنت تتصل بهذا الطرف عبر اتصال HTTP غير آمن في نطاق غير محلي. قد يؤدي هذا "
-"إلى كشف معلومات حساسة."
+"أنت تتصل بهذا الطرف عبر اتصال HTTP غير آمن في نطاق غير محلي. قد يؤدي هذا إلى "
+"كشف معلومات حساسة."
 
 #: src/views/system/Upgrade.vue:224
 msgid "You are using the latest version"
@@ -5476,7 +5484,8 @@ msgid ""
 msgstr "لم تقم بتكوين إعدادات Webauthn، لذا لا يمكنك إضافة مفتاح مرور."
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:81
-msgid "You have not enabled 2FA yet. Please enable 2FA to generate recovery codes."
+msgid ""
+"You have not enabled 2FA yet. Please enable 2FA to generate recovery codes."
 msgstr ""
 "لم تقم بتمكين المصادقة الثنائية بعد. يرجى تمكين المصادقة الثنائية لإنشاء "
 "رموز الاسترداد."
@@ -5571,12 +5580,12 @@ msgstr "مفاتيح المرور الخاصة بك"
 
 #~ msgid ""
 #~ "Check if /var/run/docker.sock exists. If you are using Nginx UI Official "
-#~ "Docker Image, please make sure the docker socket is mounted like this: `-v "
-#~ "/var/run/docker.sock:/var/run/docker.sock`."
+#~ "Docker Image, please make sure the docker socket is mounted like this: `-"
+#~ "v /var/run/docker.sock:/var/run/docker.sock`."
 #~ msgstr ""
 #~ "تحقق مما إذا كان /var/run/docker.sock موجودًا. إذا كنت تستخدم صورة Docker "
-#~ "الرسمية لـ Nginx UI، يرجى التأكد من أن مقبس Docker مثبت بهذه الطريقة: `-v "
-#~ "/var/run/docker.sock:/var/run/docker.sock`."
+#~ "الرسمية لـ Nginx UI، يرجى التأكد من أن مقبس Docker مثبت بهذه الطريقة: `-"
+#~ "v /var/run/docker.sock:/var/run/docker.sock`."
 
 #~ msgid "Check if the nginx access log path exists"
 #~ msgstr "تحقق مما إذا كان مسار سجل الوصول لـ nginx موجودًا"
@@ -5622,8 +5631,8 @@ msgstr "مفاتيح المرور الخاصة بك"
 
 #, fuzzy
 #~ msgid ""
-#~ "When you enable/disable, delete, or save this stream, the nodes set in the "
-#~ "Node Group and the nodes selected below will be synchronized."
+#~ "When you enable/disable, delete, or save this stream, the nodes set in "
+#~ "the Node Group and the nodes selected below will be synchronized."
 #~ msgstr ""
 #~ "عند تفعيل/تعطيل، حذف، أو حفظ هذا الموقع، سيتم مزامنة العقد المحددة في فئة "
 #~ "الموقع والعقد المحددة أدناه."
@@ -5690,12 +5699,15 @@ msgstr "مفاتيح المرور الخاصة بك"
 #~ msgid "Please upgrade the remote Nginx UI to the latest version"
 #~ msgstr "يرجى ترقية واجهة Nginx البعيدة إلى أحدث إصدار"
 
-#~ msgid "Rename %{orig_path} to %{new_path} on %{env_name} failed, response: %{resp}"
+#~ msgid ""
+#~ "Rename %{orig_path} to %{new_path} on %{env_name} failed, response: "
+#~ "%{resp}"
 #~ msgstr ""
 #~ "فشل إعادة تسمية %{orig_path} إلى %{new_path} على %{env_name}، الاستجابة: "
 #~ "%{resp}"
 
-#~ msgid "Rename Site %{site} to %{new_site} on %{node} error, response: %{resp}"
+#~ msgid ""
+#~ "Rename Site %{site} to %{new_site} on %{node} error, response: %{resp}"
 #~ msgstr ""
 #~ "خطأ في إعادة تسمية الموقع %{site} إلى %{new_site} على %{node}، الاستجابة: "
 #~ "%{resp}"
@@ -5710,15 +5722,17 @@ msgstr "مفاتيح المرور الخاصة بك"
 #~ "فشل مزامنة الشهادة %{cert_name} إلى %{env_name}، يرجى ترقية واجهة Nginx "
 #~ "البعيدة إلى أحدث إصدار"
 
-#~ msgid "Sync Certificate %{cert_name} to %{env_name} failed, response: %{resp}"
+#~ msgid ""
+#~ "Sync Certificate %{cert_name} to %{env_name} failed, response: %{resp}"
 #~ msgstr "فشل مزامنة الشهادة %{cert_name} إلى %{env_name}، الاستجابة: %{resp}"
 
 #~ msgid "Sync config %{config_name} to %{env_name} failed, response: %{resp}"
-#~ msgstr "فشل مزامنة التكوين %{config_name} إلى %{env_name}، الاستجابة: %{resp}"
+#~ msgstr ""
+#~ "فشل مزامنة التكوين %{config_name} إلى %{env_name}، الاستجابة: %{resp}"
 
 #~ msgid ""
-#~ "If you lose your mobile phone, you can use the recovery code to reset your "
-#~ "2FA."
+#~ "If you lose your mobile phone, you can use the recovery code to reset "
+#~ "your 2FA."
 #~ msgstr ""
 #~ "إذا فقدت هاتفك المحمول، يمكنك استخدام رمز الاسترداد لإعادة تعيين المصادقة "
 #~ "الثنائية."
@@ -5726,7 +5740,8 @@ msgstr "مفاتيح المرور الخاصة بك"
 #~ msgid "Recovery Code:"
 #~ msgstr "رمز الاسترداد:"
 
-#~ msgid "The recovery code is only displayed once, please save it in a safe place."
+#~ msgid ""
+#~ "The recovery code is only displayed once, please save it in a safe place."
 #~ msgstr "رمز الاسترداد يُعرض مرة واحدة فقط، يرجى حفظه في مكان آمن."
 
 #~ msgid "Can't scan? Use text key binding"
@@ -5742,4 +5757,5 @@ msgstr "مفاتيح المرور الخاصة بك"
 #~ msgstr "اسم المستخدم أو كلمة المرور غير صحيحة"
 
 #~ msgid "Too many login failed attempts, please try again later"
-#~ msgstr "عدد كبير جدًا من محاولات تسجيل الدخول الفاشلة، يرجى المحاولة مرة أخرى لاحقًا"
+#~ msgstr ""
+#~ "عدد كبير جدًا من محاولات تسجيل الدخول الفاشلة، يرجى المحاولة مرة أخرى لاحقًا"

File diff suppressed because it is too large
+ 208 - 181
app/src/language/de_DE/app.po


+ 30 - 30
app/src/language/en/app.po

@@ -142,10 +142,10 @@ msgid "Actual worker to configured ratio"
 msgstr ""
 
 #: src/components/NgxConfigEditor/NgxServer.vue:112
-#: src/components/NgxConfigEditor/NgxUpstream.vue:159 src/language/curd.ts:19
+#: src/components/NgxConfigEditor/NgxUpstream.vue:166 src/language/curd.ts:19
 #: src/views/preference/tabs/CertSettings.vue:45
 #: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:94
-#: src/views/stream/StreamList.vue:101
+#: src/views/stream/StreamList.vue:102
 msgid "Add"
 msgstr ""
 
@@ -172,7 +172,7 @@ msgstr ""
 msgid "Add Site"
 msgstr ""
 
-#: src/views/stream/StreamList.vue:138
+#: src/views/stream/StreamList.vue:139
 msgid "Add Stream"
 msgstr ""
 
@@ -260,7 +260,7 @@ msgid "Are you sure you want to delete permanently?"
 msgstr ""
 
 #: src/language/curd.ts:25 src/views/site/site_list/SiteList.vue:100
-#: src/views/stream/StreamList.vue:121
+#: src/views/stream/StreamList.vue:122
 msgid "Are you sure you want to delete?"
 msgstr ""
 
@@ -470,7 +470,7 @@ msgid "Base information"
 msgstr ""
 
 #: src/views/config/ConfigEditor.vue:300
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:31
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:32
 #: src/views/stream/components/RightPanel/RightPanel.vue:20
 msgid "Basic"
 msgstr ""
@@ -712,7 +712,7 @@ msgstr ""
 msgid "Channel"
 msgstr ""
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:41
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:42
 #: src/views/stream/components/RightPanel/RightPanel.vue:23
 msgid "Chat"
 msgstr ""
@@ -930,7 +930,7 @@ msgstr ""
 msgid "Config path is empty"
 msgstr ""
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:37
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:38
 msgid "Config Template"
 msgstr ""
 
@@ -1026,7 +1026,7 @@ msgstr ""
 msgid "CPU:"
 msgstr ""
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:170
+#: src/components/NgxConfigEditor/NgxUpstream.vue:177
 msgid "Create"
 msgstr ""
 
@@ -1163,10 +1163,10 @@ msgid "Define shared memory zone name and size, e.g. proxy_cache:10m"
 msgstr ""
 
 #: src/components/NgxConfigEditor/NgxServer.vue:78
-#: src/components/NgxConfigEditor/NgxUpstream.vue:129 src/language/curd.ts:9
+#: src/components/NgxConfigEditor/NgxUpstream.vue:134 src/language/curd.ts:9
 #: src/views/certificate/components/RemoveCert.vue:88
 #: src/views/site/site_list/SiteList.vue:109
-#: src/views/stream/StreamList.vue:130
+#: src/views/stream/StreamList.vue:131
 msgid "Delete"
 msgstr ""
 
@@ -1469,7 +1469,7 @@ msgstr ""
 #: src/views/site/site_list/SiteDuplicate.vue:72
 #: src/views/site/site_list/SiteList.vue:95
 #: src/views/stream/components/StreamDuplicate.vue:64
-#: src/views/stream/StreamList.vue:116
+#: src/views/stream/StreamList.vue:117
 msgid "Duplicate"
 msgstr ""
 
@@ -1650,7 +1650,7 @@ msgstr ""
 
 #: src/routes/modules/environments.ts:11
 #: src/views/dashboard/Environments.vue:83
-#: src/views/environments/list/Environment.vue:81
+#: src/views/environments/list/Environment.vue:82
 msgid "Environments"
 msgstr ""
 
@@ -2502,7 +2502,7 @@ msgstr ""
 msgid "Load Average:"
 msgstr ""
 
-#: src/views/environments/list/Environment.vue:88
+#: src/views/environments/list/Environment.vue:89
 msgid "Load from settings"
 msgstr ""
 
@@ -2787,7 +2787,7 @@ msgstr ""
 msgid "Multi-line Directive"
 msgstr ""
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:182
+#: src/components/NgxConfigEditor/NgxUpstream.vue:189
 #: src/views/backup/AutoBackup/AutoBackup.vue:11
 #: src/views/certificate/ACMEUser.vue:11
 #: src/views/certificate/CertificateEditor.vue:162
@@ -2805,7 +2805,7 @@ msgstr ""
 #: src/views/stream/columns.tsx:12
 #: src/views/stream/components/RightPanel/Basic.vue:72
 #: src/views/stream/components/StreamDuplicate.vue:71
-#: src/views/stream/StreamList.vue:143
+#: src/views/stream/StreamList.vue:144
 msgid "Name"
 msgstr ""
 
@@ -3061,7 +3061,7 @@ msgstr ""
 #: src/views/notification/Notification.vue:38
 #: src/views/preference/tabs/AuthSettings.vue:132
 #: src/views/preference/tabs/CertSettings.vue:73
-#: src/views/site/site_list/SiteList.vue:98 src/views/stream/StreamList.vue:119
+#: src/views/site/site_list/SiteList.vue:98 src/views/stream/StreamList.vue:120
 msgid "No"
 msgstr ""
 
@@ -3190,7 +3190,7 @@ msgid "Off"
 msgstr ""
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:159
-#: src/components/NgxConfigEditor/NgxUpstream.vue:145
+#: src/components/NgxConfigEditor/NgxUpstream.vue:151
 #: src/components/NodeSelector/NodeSelector.vue:109
 #: src/components/ProxyTargets/ProxyTargets.vue:43
 #: src/views/dashboard/Environments.vue:107
@@ -3211,7 +3211,7 @@ msgstr ""
 #: src/views/site/site_list/SiteList.vue:99
 #: src/views/stream/components/RightPanel/Basic.vue:48
 #: src/views/stream/components/StreamStatusSelect.vue:60
-#: src/views/stream/StreamList.vue:120
+#: src/views/stream/StreamList.vue:121
 msgid "OK"
 msgstr ""
 
@@ -3513,17 +3513,17 @@ msgstr ""
 msgid "Please select at least one item"
 msgstr ""
 
-#: src/views/environments/list/Environment.vue:120
+#: src/views/environments/list/Environment.vue:121
 #: src/views/environments/list/Environment.vue:35
 msgid "Please select at least one node to reload Nginx"
 msgstr ""
 
-#: src/views/environments/list/Environment.vue:141
+#: src/views/environments/list/Environment.vue:142
 #: src/views/environments/list/Environment.vue:49
 msgid "Please select at least one node to restart Nginx"
 msgstr ""
 
-#: src/views/environments/list/Environment.vue:99
+#: src/views/environments/list/Environment.vue:100
 msgid "Please select at least one node to upgrade"
 msgstr ""
 
@@ -3536,7 +3536,7 @@ msgstr ""
 msgid "Port"
 msgstr ""
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:44
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:45
 #: src/views/stream/components/RightPanel/RightPanel.vue:26
 msgid "Port Scanner"
 msgstr ""
@@ -3703,8 +3703,8 @@ msgstr ""
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:136
 #: src/views/environments/group/columns.ts:22
 #: src/views/environments/group/EnvGroup.vue:50
-#: src/views/environments/list/Environment.vue:128
-#: src/views/environments/list/Environment.vue:136
+#: src/views/environments/list/Environment.vue:129
+#: src/views/environments/list/Environment.vue:137
 msgid "Reload Nginx"
 msgstr ""
 
@@ -3753,7 +3753,7 @@ msgstr ""
 msgid "Removed successfully"
 msgstr ""
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:126
+#: src/components/NgxConfigEditor/NgxUpstream.vue:131
 #: src/views/config/components/ConfigName.vue:51
 #: src/views/config/components/Rename.vue:56
 #: src/views/config/ConfigList.vue:181
@@ -3881,8 +3881,8 @@ msgid "Restart"
 msgstr ""
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:148
-#: src/views/environments/list/Environment.vue:149
-#: src/views/environments/list/Environment.vue:157
+#: src/views/environments/list/Environment.vue:150
+#: src/views/environments/list/Environment.vue:158
 msgid "Restart Nginx"
 msgstr ""
 
@@ -5031,8 +5031,8 @@ msgid "Updated at"
 msgstr ""
 
 #: src/routes/modules/system.ts:26
-#: src/views/environments/list/Environment.vue:107
-#: src/views/environments/list/Environment.vue:115
+#: src/views/environments/list/Environment.vue:108
+#: src/views/environments/list/Environment.vue:116
 #: src/views/system/Upgrade.vue:154 src/views/system/Upgrade.vue:159
 msgid "Upgrade"
 msgstr ""
@@ -5062,7 +5062,7 @@ msgstr ""
 msgid "Upstream"
 msgstr ""
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:177
+#: src/components/NgxConfigEditor/NgxUpstream.vue:184
 msgid "Upstream Name"
 msgstr ""
 

File diff suppressed because it is too large
+ 208 - 184
app/src/language/es/app.po


File diff suppressed because it is too large
+ 217 - 189
app/src/language/fr_FR/app.po


File diff suppressed because it is too large
+ 262 - 169
app/src/language/ja_JP/app.po


File diff suppressed because it is too large
+ 254 - 169
app/src/language/ko_KR/app.po


+ 30 - 30
app/src/language/messages.pot

@@ -147,11 +147,11 @@ msgid "Actual worker to configured ratio"
 msgstr ""
 
 #: src/components/NgxConfigEditor/NgxServer.vue:112
-#: src/components/NgxConfigEditor/NgxUpstream.vue:159
+#: src/components/NgxConfigEditor/NgxUpstream.vue:166
 #: src/language/curd.ts:19
 #: src/views/preference/tabs/CertSettings.vue:45
 #: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:94
-#: src/views/stream/StreamList.vue:101
+#: src/views/stream/StreamList.vue:102
 msgid "Add"
 msgstr ""
 
@@ -180,7 +180,7 @@ msgstr ""
 msgid "Add Site"
 msgstr ""
 
-#: src/views/stream/StreamList.vue:138
+#: src/views/stream/StreamList.vue:139
 msgid "Add Stream"
 msgstr ""
 
@@ -269,7 +269,7 @@ msgstr ""
 
 #: src/language/curd.ts:25
 #: src/views/site/site_list/SiteList.vue:100
-#: src/views/stream/StreamList.vue:121
+#: src/views/stream/StreamList.vue:122
 msgid "Are you sure you want to delete?"
 msgstr ""
 
@@ -481,7 +481,7 @@ msgid "Base information"
 msgstr ""
 
 #: src/views/config/ConfigEditor.vue:300
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:31
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:32
 #: src/views/stream/components/RightPanel/RightPanel.vue:20
 msgid "Basic"
 msgstr ""
@@ -721,7 +721,7 @@ msgstr ""
 msgid "Channel"
 msgstr ""
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:41
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:42
 #: src/views/stream/components/RightPanel/RightPanel.vue:23
 msgid "Chat"
 msgstr ""
@@ -910,7 +910,7 @@ msgstr ""
 msgid "Config path is empty"
 msgstr ""
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:37
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:38
 msgid "Config Template"
 msgstr ""
 
@@ -1006,7 +1006,7 @@ msgstr ""
 msgid "CPU:"
 msgstr ""
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:170
+#: src/components/NgxConfigEditor/NgxUpstream.vue:177
 msgid "Create"
 msgstr ""
 
@@ -1142,11 +1142,11 @@ msgid "Define shared memory zone name and size, e.g. proxy_cache:10m"
 msgstr ""
 
 #: src/components/NgxConfigEditor/NgxServer.vue:78
-#: src/components/NgxConfigEditor/NgxUpstream.vue:129
+#: src/components/NgxConfigEditor/NgxUpstream.vue:134
 #: src/language/curd.ts:9
 #: src/views/certificate/components/RemoveCert.vue:88
 #: src/views/site/site_list/SiteList.vue:109
-#: src/views/stream/StreamList.vue:130
+#: src/views/stream/StreamList.vue:131
 msgid "Delete"
 msgstr ""
 
@@ -1453,7 +1453,7 @@ msgstr ""
 #: src/views/site/site_list/SiteDuplicate.vue:72
 #: src/views/site/site_list/SiteList.vue:95
 #: src/views/stream/components/StreamDuplicate.vue:64
-#: src/views/stream/StreamList.vue:116
+#: src/views/stream/StreamList.vue:117
 msgid "Duplicate"
 msgstr ""
 
@@ -1636,7 +1636,7 @@ msgstr ""
 
 #: src/routes/modules/environments.ts:11
 #: src/views/dashboard/Environments.vue:83
-#: src/views/environments/list/Environment.vue:81
+#: src/views/environments/list/Environment.vue:82
 msgid "Environments"
 msgstr ""
 
@@ -2477,7 +2477,7 @@ msgstr ""
 msgid "Load Average:"
 msgstr ""
 
-#: src/views/environments/list/Environment.vue:88
+#: src/views/environments/list/Environment.vue:89
 msgid "Load from settings"
 msgstr ""
 
@@ -2760,7 +2760,7 @@ msgstr ""
 msgid "Multi-line Directive"
 msgstr ""
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:182
+#: src/components/NgxConfigEditor/NgxUpstream.vue:189
 #: src/views/backup/AutoBackup/AutoBackup.vue:11
 #: src/views/certificate/ACMEUser.vue:11
 #: src/views/certificate/CertificateEditor.vue:162
@@ -2779,7 +2779,7 @@ msgstr ""
 #: src/views/stream/columns.tsx:12
 #: src/views/stream/components/RightPanel/Basic.vue:72
 #: src/views/stream/components/StreamDuplicate.vue:71
-#: src/views/stream/StreamList.vue:143
+#: src/views/stream/StreamList.vue:144
 msgid "Name"
 msgstr ""
 
@@ -3039,7 +3039,7 @@ msgstr ""
 #: src/views/preference/tabs/AuthSettings.vue:132
 #: src/views/preference/tabs/CertSettings.vue:73
 #: src/views/site/site_list/SiteList.vue:98
-#: src/views/stream/StreamList.vue:119
+#: src/views/stream/StreamList.vue:120
 msgid "No"
 msgstr ""
 
@@ -3165,7 +3165,7 @@ msgid "Off"
 msgstr ""
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:159
-#: src/components/NgxConfigEditor/NgxUpstream.vue:145
+#: src/components/NgxConfigEditor/NgxUpstream.vue:151
 #: src/components/NodeSelector/NodeSelector.vue:109
 #: src/components/ProxyTargets/ProxyTargets.vue:43
 #: src/views/dashboard/Environments.vue:107
@@ -3187,7 +3187,7 @@ msgstr ""
 #: src/views/site/site_list/SiteList.vue:99
 #: src/views/stream/components/RightPanel/Basic.vue:48
 #: src/views/stream/components/StreamStatusSelect.vue:60
-#: src/views/stream/StreamList.vue:120
+#: src/views/stream/StreamList.vue:121
 msgid "OK"
 msgstr ""
 
@@ -3477,17 +3477,17 @@ msgstr ""
 msgid "Please select at least one item"
 msgstr ""
 
-#: src/views/environments/list/Environment.vue:120
+#: src/views/environments/list/Environment.vue:121
 #: src/views/environments/list/Environment.vue:35
 msgid "Please select at least one node to reload Nginx"
 msgstr ""
 
-#: src/views/environments/list/Environment.vue:141
+#: src/views/environments/list/Environment.vue:142
 #: src/views/environments/list/Environment.vue:49
 msgid "Please select at least one node to restart Nginx"
 msgstr ""
 
-#: src/views/environments/list/Environment.vue:99
+#: src/views/environments/list/Environment.vue:100
 msgid "Please select at least one node to upgrade"
 msgstr ""
 
@@ -3500,7 +3500,7 @@ msgstr ""
 msgid "Port"
 msgstr ""
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:44
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:45
 #: src/views/stream/components/RightPanel/RightPanel.vue:26
 msgid "Port Scanner"
 msgstr ""
@@ -3667,8 +3667,8 @@ msgstr ""
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:136
 #: src/views/environments/group/columns.ts:22
 #: src/views/environments/group/EnvGroup.vue:50
-#: src/views/environments/list/Environment.vue:128
-#: src/views/environments/list/Environment.vue:136
+#: src/views/environments/list/Environment.vue:129
+#: src/views/environments/list/Environment.vue:137
 msgid "Reload Nginx"
 msgstr ""
 
@@ -3717,7 +3717,7 @@ msgstr ""
 msgid "Removed successfully"
 msgstr ""
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:126
+#: src/components/NgxConfigEditor/NgxUpstream.vue:131
 #: src/views/config/components/ConfigName.vue:51
 #: src/views/config/components/Rename.vue:56
 #: src/views/config/ConfigList.vue:181
@@ -3845,8 +3845,8 @@ msgid "Restart"
 msgstr ""
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:148
-#: src/views/environments/list/Environment.vue:149
-#: src/views/environments/list/Environment.vue:157
+#: src/views/environments/list/Environment.vue:150
+#: src/views/environments/list/Environment.vue:158
 msgid "Restart Nginx"
 msgstr ""
 
@@ -4948,8 +4948,8 @@ msgid "Updated at"
 msgstr ""
 
 #: src/routes/modules/system.ts:26
-#: src/views/environments/list/Environment.vue:107
-#: src/views/environments/list/Environment.vue:115
+#: src/views/environments/list/Environment.vue:108
+#: src/views/environments/list/Environment.vue:116
 #: src/views/system/Upgrade.vue:154
 #: src/views/system/Upgrade.vue:159
 msgid "Upgrade"
@@ -4980,7 +4980,7 @@ msgstr ""
 msgid "Upstream"
 msgstr ""
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:177
+#: src/components/NgxConfigEditor/NgxUpstream.vue:184
 msgid "Upstream Name"
 msgstr ""
 

+ 207 - 181
app/src/language/pt_PT/app.po

@@ -4,17 +4,18 @@ msgid ""
 msgstr ""
 "PO-Revision-Date: 2024-08-12 17:09+0000\n"
 "Last-Translator: Kleiser Sarifo <kleiser.sarifo@gmail.com>\n"
-"Language-Team: Portuguese (Portugal) "
-"<https://weblate.nginxui.com/projects/nginx-ui/frontend/pt_PT/>\n"
+"Language-Team: Portuguese (Portugal) <https://weblate.nginxui.com/projects/"
+"nginx-ui/frontend/pt_PT/>\n"
 "Language: pt_PT\n"
-"Content-Type: text/plain; charset=utf-8\n"
+"Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=n > 1;\n"
 "X-Generator: Weblate 5.6.2\n"
 
 #: src/language/generate.ts:31
 msgid "[Nginx UI] ACME User: %{name}, Email: %{email}, CA Dir: %{caDir}"
-msgstr "[Nginx UI] Utilizador ACME: %{name}, Email: %{email}, Diretório CA: %{caDir}"
+msgstr ""
+"[Nginx UI] Utilizador ACME: %{name}, Email: %{email}, Diretório CA: %{caDir}"
 
 #: src/language/generate.ts:32
 msgid "[Nginx UI] Backing up current certificate for later revocation"
@@ -31,14 +32,16 @@ msgid "[Nginx UI] Certificate successfully revoked"
 msgstr "[Nginx UI] Certificado revogado com sucesso"
 
 #: src/language/generate.ts:35
-msgid "[Nginx UI] Certificate was used for server, reloading server TLS certificate"
+msgid ""
+"[Nginx UI] Certificate was used for server, reloading server TLS certificate"
 msgstr ""
 "[Nginx UI] O certificado foi usado para o servidor, a recarregar o "
 "certificado TLS do servidor"
 
 #: src/language/generate.ts:36
 msgid "[Nginx UI] Creating client facilitates communication with the CA server"
-msgstr "[Nginx UI] Criando cliente para facilitar a comunicação com o servidor CA"
+msgstr ""
+"[Nginx UI] Criando cliente para facilitar a comunicação com o servidor CA"
 
 #: src/language/generate.ts:37
 msgid "[Nginx UI] Environment variables cleaned"
@@ -159,10 +162,10 @@ msgid "Actual worker to configured ratio"
 msgstr "Rácio real de workers para configurado"
 
 #: src/components/NgxConfigEditor/NgxServer.vue:112
-#: src/components/NgxConfigEditor/NgxUpstream.vue:159 src/language/curd.ts:19
+#: src/components/NgxConfigEditor/NgxUpstream.vue:166 src/language/curd.ts:19
 #: src/views/preference/tabs/CertSettings.vue:45
 #: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:94
-#: src/views/stream/StreamList.vue:101
+#: src/views/stream/StreamList.vue:102
 msgid "Add"
 msgstr "Adicionar"
 
@@ -189,7 +192,7 @@ msgstr "Adicionar Local"
 msgid "Add Site"
 msgstr "Adicionar Site"
 
-#: src/views/stream/StreamList.vue:138
+#: src/views/stream/StreamList.vue:139
 msgid "Add Stream"
 msgstr "Adicionar Stream"
 
@@ -209,8 +212,7 @@ msgstr "Modo Avançado"
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:99
 msgid "Afterwards, refresh this page and click add passkey again."
 msgstr ""
-"Depois, atualize esta página e clique em adicionar chave de acesso "
-"novamente."
+"Depois, atualize esta página e clique em adicionar chave de acesso novamente."
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:115
 msgid "All"
@@ -255,7 +257,8 @@ msgstr "Tem certeza que pretende eliminar este IP banido imediatamente?"
 
 #: src/views/preference/components/AuthSettings/Passkey.vue:113
 msgid "Are you sure to delete this passkey immediately?"
-msgstr "Tem a certeza de que deseja eliminar imediatamente esta chave de acesso?"
+msgstr ""
+"Tem a certeza de que deseja eliminar imediatamente esta chave de acesso?"
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:154
 msgid "Are you sure to generate new recovery codes?"
@@ -279,7 +282,7 @@ msgid "Are you sure you want to delete permanently?"
 msgstr "Tem a certeza de que pretende eliminar permanentemente?"
 
 #: src/language/curd.ts:25 src/views/site/site_list/SiteList.vue:100
-#: src/views/stream/StreamList.vue:121
+#: src/views/stream/StreamList.vue:122
 msgid "Are you sure you want to delete?"
 msgstr "Tem certeza que pretende eliminar?"
 
@@ -447,7 +450,8 @@ msgstr "O caminho de backup não é um diretório: {0}"
 
 #: src/constants/errors/backup.ts:62
 msgid "Backup path is required for custom directory backup"
-msgstr "O caminho de backup é necessário para o backup de diretório personalizado"
+msgstr ""
+"O caminho de backup é necessário para o backup de diretório personalizado"
 
 #: src/constants/errors/backup.ts:60
 msgid "Backup path not in granted access paths: {0}"
@@ -460,11 +464,11 @@ msgstr "Agendamento de backup"
 #: src/components/Notification/notifications.ts:38
 msgid "Backup task %{backup_name} completed successfully, file: %{file_path}"
 msgstr ""
-"Tarefa de backup %{backup_name} concluída com sucesso, ficheiro: "
-"%{file_path}"
+"Tarefa de backup %{backup_name} concluída com sucesso, ficheiro: %{file_path}"
 
 #: src/components/Notification/notifications.ts:34
-msgid "Backup task %{backup_name} failed during storage upload, error: %{error}"
+msgid ""
+"Backup task %{backup_name} failed during storage upload, error: %{error}"
 msgstr ""
 "A tarefa de backup %{backup_name} falhou durante o upload para o "
 "armazenamento, erro: %{error}"
@@ -498,7 +502,7 @@ msgid "Base information"
 msgstr "Informação base"
 
 #: src/views/config/ConfigEditor.vue:300
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:31
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:32
 #: src/views/stream/components/RightPanel/RightPanel.vue:20
 msgid "Basic"
 msgstr "Básico"
@@ -614,7 +618,8 @@ msgstr "Não é possível aceder ao caminho de armazenamento {0}: {1}"
 
 #: src/constants/errors/user.ts:11
 msgid "Cannot change initial user password in demo mode"
-msgstr "Não é possível alterar a senha do usuário inicial no modo de demonstração"
+msgstr ""
+"Não é possível alterar a senha do usuário inicial no modo de demonstração"
 
 #: src/components/ConfigHistory/DiffViewer.vue:67
 #: src/components/ConfigHistory/DiffViewer.vue:84
@@ -744,7 +749,7 @@ msgstr "Caminho Alterado"
 msgid "Channel"
 msgstr "Canal"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:41
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:42
 #: src/views/stream/components/RightPanel/RightPanel.vue:23
 msgid "Chat"
 msgstr "Chat"
@@ -761,26 +766,26 @@ msgstr "Verificar de novo"
 #: src/language/generate.ts:6
 msgid ""
 "Check if /var/run/docker.sock exists. If you are using Nginx UI Official "
-"Docker Image, please make sure the docker socket is mounted like this: `-v "
-"/var/run/docker.sock:/var/run/docker.sock`. Nginx UI official image uses "
-"/var/run/docker.sock to communicate with the host Docker Engine via Docker "
-"Client API. This feature is used to control Nginx in another container and "
-"perform container replacement rather than binary replacement during OTA "
-"upgrades of Nginx UI to ensure container dependencies are also upgraded. If "
-"you don't need this feature, please add the environment variable "
+"Docker Image, please make sure the docker socket is mounted like this: `-v /"
+"var/run/docker.sock:/var/run/docker.sock`. Nginx UI official image uses /var/"
+"run/docker.sock to communicate with the host Docker Engine via Docker Client "
+"API. This feature is used to control Nginx in another container and perform "
+"container replacement rather than binary replacement during OTA upgrades of "
+"Nginx UI to ensure container dependencies are also upgraded. If you don't "
+"need this feature, please add the environment variable "
 "NGINX_UI_IGNORE_DOCKER_SOCKET=true to the container."
 msgstr ""
 "Verifique se /var/run/docker.sock existe. Se estiver a utilizar a imagem "
 "Docker oficial do Nginx UI, certifique-se de que o socket Docker está "
 "montado desta forma: `-v /var/run/docker.sock:/var/run/docker.sock`. A "
-"imagem oficial do Nginx UI utiliza /var/run/docker.sock para comunicar com "
-"o Docker Engine do anfitrião através da API do Docker Client. Esta "
+"imagem oficial do Nginx UI utiliza /var/run/docker.sock para comunicar com o "
+"Docker Engine do anfitrião através da API do Docker Client. Esta "
 "funcionalidade é utilizada para controlar o Nginx noutro contentor e "
 "realizar a substituição de contentores em vez da substituição binária "
-"durante as atualizações OTA do Nginx UI para garantir que as dependências "
-"do contentor também são atualizadas. Se não necessitar desta "
-"funcionalidade, adicione a variável de ambiente "
-"NGINX_UI_IGNORE_DOCKER_SOCKET=true ao contentor."
+"durante as atualizações OTA do Nginx UI para garantir que as dependências do "
+"contentor também são atualizadas. Se não necessitar desta funcionalidade, "
+"adicione a variável de ambiente NGINX_UI_IGNORE_DOCKER_SOCKET=true ao "
+"contentor."
 
 #: src/components/SelfCheck/tasks/frontend/https-check.ts:14
 msgid ""
@@ -792,20 +797,20 @@ msgstr ""
 
 #: src/language/generate.ts:8
 msgid ""
-"Check if the nginx access log path exists. By default, this path is "
-"obtained from 'nginx -V'. If it cannot be obtained or the obtained path "
-"does not point to a valid, existing file, an error will be reported. In "
-"this case, you need to modify the configuration file to specify the access "
-"log path.Refer to the docs for more details: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#accesslogpath"
+"Check if the nginx access log path exists. By default, this path is obtained "
+"from 'nginx -V'. If it cannot be obtained or the obtained path does not "
+"point to a valid, existing file, an error will be reported. In this case, "
+"you need to modify the configuration file to specify the access log path."
+"Refer to the docs for more details: https://nginxui.com/zh_CN/guide/config-"
+"nginx.html#accesslogpath"
 msgstr ""
 "Verifique se o caminho do registo de acesso do nginx existe. Por "
 "predefinição, este caminho é obtido a partir de 'nginx -V'. Se não for "
 "possível obtê-lo ou se o caminho obtido não apontar para um ficheiro válido "
 "existente, será reportado um erro. Neste caso, terá de modificar o ficheiro "
 "de configuração para especificar o caminho do registo de acesso. Consulte a "
-"documentação para mais detalhes: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#accesslogpath"
+"documentação para mais detalhes: https://nginxui.com/zh_CN/guide/config-"
+"nginx.html#accesslogpath"
 
 #: src/language/generate.ts:9
 msgid "Check if the nginx configuration directory exists"
@@ -820,25 +825,25 @@ msgid ""
 "Check if the nginx error log path exists. By default, this path is obtained "
 "from 'nginx -V'. If it cannot be obtained or the obtained path does not "
 "point to a valid, existing file, an error will be reported. In this case, "
-"you need to modify the configuration file to specify the error log "
-"path.Refer to the docs for more details: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#errorlogpath"
+"you need to modify the configuration file to specify the error log path."
+"Refer to the docs for more details: https://nginxui.com/zh_CN/guide/config-"
+"nginx.html#errorlogpath"
 msgstr ""
 "Verifique se o caminho do registo de erros do nginx existe. Por "
-"predefinição, este caminho é obtido a partir de 'nginx -V'. Se não puder "
-"ser obtido ou se o caminho obtido não apontar para um ficheiro válido "
-"existente, será reportado um erro. Neste caso, terá de modificar o ficheiro "
-"de configuração para especificar o caminho do registo de erros. Consulte a "
-"documentação para mais detalhes: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#errorlogpath"
+"predefinição, este caminho é obtido a partir de 'nginx -V'. Se não puder ser "
+"obtido ou se o caminho obtido não apontar para um ficheiro válido existente, "
+"será reportado um erro. Neste caso, terá de modificar o ficheiro de "
+"configuração para especificar o caminho do registo de erros. Consulte a "
+"documentação para mais detalhes: https://nginxui.com/zh_CN/guide/config-"
+"nginx.html#errorlogpath"
 
 #: src/language/generate.ts:7
 msgid ""
 "Check if the nginx PID path exists. By default, this path is obtained from "
 "'nginx -V'. If it cannot be obtained, an error will be reported. In this "
 "case, you need to modify the configuration file to specify the Nginx PID "
-"path.Refer to the docs for more details: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#pidpath"
+"path.Refer to the docs for more details: https://nginxui.com/zh_CN/guide/"
+"config-nginx.html#pidpath"
 msgstr ""
 "Verifique se o caminho do PID do Nginx existe. Por padrão, este caminho é "
 "obtido a partir de 'nginx -V'. Se não puder ser obtido, será relatado um "
@@ -868,8 +873,8 @@ msgstr ""
 
 #: src/language/generate.ts:16
 msgid ""
-"Check if the streams-available and streams-enabled directories are under "
-"the nginx configuration directory"
+"Check if the streams-available and streams-enabled directories are under the "
+"nginx configuration directory"
 msgstr ""
 "Verifique se os diretórios streams-available e streams-enabled estão no "
 "diretório de configuração do nginx"
@@ -896,7 +901,8 @@ msgstr "Limpo com sucesso"
 #: src/components/SystemRestore/SystemRestoreContent.vue:194
 #: src/components/SystemRestore/SystemRestoreContent.vue:271
 msgid "Click or drag backup file to this area to upload"
-msgstr "Clique ou arraste o arquivo de backup para esta área para fazer o upload"
+msgstr ""
+"Clique ou arraste o arquivo de backup para esta área para fazer o upload"
 
 #: src/language/curd.ts:49 src/language/curd.ts:53
 msgid "Click or drag files to this area to upload"
@@ -998,7 +1004,7 @@ msgstr "O ficheiro de entrada de configuração não existe"
 msgid "Config path is empty"
 msgstr "O caminho de configuração está vazio"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:37
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:38
 msgid "Config Template"
 msgstr "Modelo de Configuração"
 
@@ -1096,7 +1102,7 @@ msgstr ""
 msgid "CPU:"
 msgstr "CPU:"
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:170
+#: src/components/NgxConfigEditor/NgxUpstream.vue:177
 msgid "Create"
 msgstr "Criar"
 
@@ -1238,10 +1244,10 @@ msgstr ""
 "proxy_cache:10m"
 
 #: src/components/NgxConfigEditor/NgxServer.vue:78
-#: src/components/NgxConfigEditor/NgxUpstream.vue:129 src/language/curd.ts:9
+#: src/components/NgxConfigEditor/NgxUpstream.vue:134 src/language/curd.ts:9
 #: src/views/certificate/components/RemoveCert.vue:88
 #: src/views/site/site_list/SiteList.vue:109
-#: src/views/stream/StreamList.vue:130
+#: src/views/stream/StreamList.vue:131
 msgid "Delete"
 msgstr "Eliminar"
 
@@ -1519,7 +1525,8 @@ msgstr "Domínio"
 
 #: src/views/certificate/CertificateEditor.vue:112
 msgid "Domains list is empty, try to reopen Auto Cert for %{config}"
-msgstr "A lista de domínios está vazia, tente reabrir o Auto Cert para %{config}"
+msgstr ""
+"A lista de domínios está vazia, tente reabrir o Auto Cert para %{config}"
 
 #: src/language/constants.ts:27
 msgid "Download latest release error"
@@ -1540,13 +1547,12 @@ msgid ""
 "non-HTTPS websites, except when running on localhost."
 msgstr ""
 "Devido às políticas de segurança de alguns navegadores, não é possível "
-"utilizar passkeys em sites não HTTPS, exceto quando em execução no "
-"localhost."
+"utilizar passkeys em sites não HTTPS, exceto quando em execução no localhost."
 
 #: src/views/site/site_list/SiteDuplicate.vue:72
 #: src/views/site/site_list/SiteList.vue:95
 #: src/views/stream/components/StreamDuplicate.vue:64
-#: src/views/stream/StreamList.vue:116
+#: src/views/stream/StreamList.vue:117
 msgid "Duplicate"
 msgstr "Duplicado"
 
@@ -1727,7 +1733,7 @@ msgstr "Variáveis de ambiente limpas"
 
 #: src/routes/modules/environments.ts:11
 #: src/views/dashboard/Environments.vue:83
-#: src/views/environments/list/Environment.vue:81
+#: src/views/environments/list/Environment.vue:82
 msgid "Environments"
 msgstr "Ambientes"
 
@@ -2078,7 +2084,8 @@ msgstr "Falha ao restaurar as configurações do Nginx: {0}"
 
 #: src/constants/errors/backup.ts:40
 msgid "Failed to restore Nginx UI files: {0}"
-msgstr "Falha ao restaurar os ficheiros da interface de utilizador do Nginx: {0}"
+msgstr ""
+"Falha ao restaurar os ficheiros da interface de utilizador do Nginx: {0}"
 
 #: src/views/certificate/components/RemoveCert.vue:48
 msgid "Failed to revoke certificate"
@@ -2299,14 +2306,15 @@ msgid ""
 "ban threshold minutes, the ip will be banned for a period of time."
 msgstr ""
 "Se o número de tentativas de início de sessão falhadas de um IP atingir o "
-"máximo de tentativas em minutos de limite de banimento, o IP será banido "
-"por um período de tempo."
+"máximo de tentativas em minutos de limite de banimento, o IP será banido por "
+"um período de tempo."
 
 #: src/components/AutoCertForm/AutoCertForm.vue:116
 msgid ""
 "If you want to automatically revoke the old certificate, please enable this "
 "option."
-msgstr "Se desejar revogar automaticamente o certificado antigo, ative esta opção."
+msgstr ""
+"Se desejar revogar automaticamente o certificado antigo, ative esta opção."
 
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:70
 msgid "If your browser supports WebAuthn Passkey, a dialog box will appear."
@@ -2392,7 +2400,8 @@ msgstr "Instalação"
 
 #: src/constants/errors/system.ts:3
 msgid "Installation is not allowed after 10 minutes of system startup"
-msgstr "A instalação não é permitida após 10 minutos de inicialização do sistema"
+msgstr ""
+"A instalação não é permitida após 10 minutos de inicialização do sistema"
 
 #: src/views/install/components/TimeoutAlert.vue:11
 msgid ""
@@ -2500,8 +2509,8 @@ msgid ""
 "Keep your recovery codes as safe as your password. We recommend saving them "
 "with a password manager."
 msgstr ""
-"Mantenha os seus códigos de recuperação tão seguros como a sua "
-"palavra-passe. Recomendamos guardá-los com um gestor de palavras-passe."
+"Mantenha os seus códigos de recuperação tão seguros como a sua palavra-"
+"passe. Recomendamos guardá-los com um gestor de palavras-passe."
 
 #: src/views/dashboard/components/ParamsOpt/PerformanceConfig.vue:60
 msgid "Keepalive Timeout"
@@ -2567,7 +2576,8 @@ msgstr "Deixar em branco não vai mudar nada"
 
 #: src/constants/errors/user.ts:6
 msgid "Legacy recovery code not allowed since totp is not enabled"
-msgstr "Código de recuperação antigo não permitido porque o TOTP não está ativado"
+msgstr ""
+"Código de recuperação antigo não permitido porque o TOTP não está ativado"
 
 #: src/components/AutoCertForm/AutoCertForm.vue:104
 msgid "Lego disable CNAME Support"
@@ -2594,7 +2604,7 @@ msgstr "A escutar"
 msgid "Load Average:"
 msgstr "Média de Carga:"
 
-#: src/views/environments/list/Environment.vue:88
+#: src/views/environments/list/Environment.vue:89
 msgid "Load from settings"
 msgstr "Carregar a partir das configurações"
 
@@ -2655,13 +2665,12 @@ msgstr "Log"
 #: src/language/generate.ts:20
 msgid ""
 "Log file %{log_path} is not a regular file. If you are using nginx-ui in "
-"docker container, please refer to "
-"https://nginxui.com/zh_CN/guide/config-nginx-log.html for more information."
+"docker container, please refer to https://nginxui.com/zh_CN/guide/config-"
+"nginx-log.html for more information."
 msgstr ""
 "O ficheiro de registo %{log_path} não é um ficheiro regular. Se estiver a "
-"utilizar o nginx-ui num contentor Docker, consulte "
-"https://nginxui.com/zh_CN/guide/config-nginx-log.html para obter mais "
-"informações."
+"utilizar o nginx-ui num contentor Docker, consulte https://nginxui.com/zh_CN/"
+"guide/config-nginx-log.html para obter mais informações."
 
 #: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:72
 msgid "Log List"
@@ -2685,12 +2694,12 @@ msgstr "Logrotate"
 
 #: src/views/preference/tabs/LogrotateSettings.vue:13
 msgid ""
-"Logrotate, by default, is enabled in most mainstream Linux distributions "
-"for users who install Nginx UI on the host machine, so you don't need to "
-"modify the parameters on this page. For users who install Nginx UI using "
-"Docker containers, you can manually enable this option. The crontab task "
-"scheduler of Nginx UI will execute the logrotate command at the interval "
-"you set in minutes."
+"Logrotate, by default, is enabled in most mainstream Linux distributions for "
+"users who install Nginx UI on the host machine, so you don't need to modify "
+"the parameters on this page. For users who install Nginx UI using Docker "
+"containers, you can manually enable this option. The crontab task scheduler "
+"of Nginx UI will execute the logrotate command at the interval you set in "
+"minutes."
 msgstr ""
 "O Logrotate, por defeito, está activado na maioria das distribuições Linux "
 "convencionais para utilizadores que instalam o Nginx UI na máquina host, "
@@ -2891,7 +2900,7 @@ msgstr "Mensalmente no dia %{day} às %{time}"
 msgid "Multi-line Directive"
 msgstr "Diretiva Multilinha"
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:182
+#: src/components/NgxConfigEditor/NgxUpstream.vue:189
 #: src/views/backup/AutoBackup/AutoBackup.vue:11
 #: src/views/certificate/ACMEUser.vue:11
 #: src/views/certificate/CertificateEditor.vue:162
@@ -2909,7 +2918,7 @@ msgstr "Diretiva Multilinha"
 #: src/views/stream/columns.tsx:12
 #: src/views/stream/components/RightPanel/Basic.vue:72
 #: src/views/stream/components/StreamDuplicate.vue:71
-#: src/views/stream/StreamList.vue:143
+#: src/views/stream/StreamList.vue:144
 msgid "Name"
 msgstr "Nome"
 
@@ -3099,7 +3108,8 @@ msgstr "Recarga do Nginx falhou: {0}"
 
 #: src/views/environments/list/Environment.vue:41
 msgid "Nginx reload operations have been dispatched to remote nodes"
-msgstr "As operações de recarregamento do Nginx foram enviadas para os nós remotos"
+msgstr ""
+"As operações de recarregamento do Nginx foram enviadas para os nós remotos"
 
 #: src/components/NginxControl/NginxControl.vue:26
 msgid "Nginx reloaded successfully"
@@ -3140,11 +3150,11 @@ msgstr "A configuração do Nginx UI foi restaurada"
 
 #: src/components/SystemRestore/SystemRestoreContent.vue:336
 msgid ""
-"Nginx UI configuration has been restored and will restart automatically in "
-"a few seconds."
+"Nginx UI configuration has been restored and will restart automatically in a "
+"few seconds."
 msgstr ""
-"A configuração do Nginx UI foi restaurada e irá reiniciar automaticamente "
-"em alguns segundos."
+"A configuração do Nginx UI foi restaurada e irá reiniciar automaticamente em "
+"alguns segundos."
 
 #: src/language/generate.ts:26
 msgid "Nginx.conf includes conf.d directory"
@@ -3167,7 +3177,7 @@ msgstr "Nginx.conf inclui o diretório streams-enabled"
 #: src/views/notification/Notification.vue:38
 #: src/views/preference/tabs/AuthSettings.vue:132
 #: src/views/preference/tabs/CertSettings.vue:73
-#: src/views/site/site_list/SiteList.vue:98 src/views/stream/StreamList.vue:119
+#: src/views/site/site_list/SiteList.vue:98 src/views/stream/StreamList.vue:120
 msgid "No"
 msgstr "Não"
 
@@ -3302,7 +3312,7 @@ msgid "Off"
 msgstr "Desligado"
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:159
-#: src/components/NgxConfigEditor/NgxUpstream.vue:145
+#: src/components/NgxConfigEditor/NgxUpstream.vue:151
 #: src/components/NodeSelector/NodeSelector.vue:109
 #: src/components/ProxyTargets/ProxyTargets.vue:43
 #: src/views/dashboard/Environments.vue:107
@@ -3323,7 +3333,7 @@ msgstr "Off-line"
 #: src/views/site/site_list/SiteList.vue:99
 #: src/views/stream/components/RightPanel/Basic.vue:48
 #: src/views/stream/components/StreamStatusSelect.vue:60
-#: src/views/stream/StreamList.vue:120
+#: src/views/stream/StreamList.vue:121
 msgid "OK"
 msgstr "OK"
 
@@ -3334,7 +3344,8 @@ msgstr "Ligado"
 
 #: src/views/certificate/DNSCredential.vue:58
 msgid "Once the verification is complete, the records will be removed."
-msgstr "Assim que a verificação estiver concluída, os registos serão removidos."
+msgstr ""
+"Assim que a verificação estiver concluída, os registos serão removidos."
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:159
 #: src/components/NodeSelector/NodeSelector.vue:103
@@ -3425,10 +3436,10 @@ msgid ""
 "facial recognition, a device password, or a PIN. They can be used as a "
 "password replacement or as a 2FA method."
 msgstr ""
-"As passkeys são credenciais WebAuthn que validam a sua identidade "
-"utilizando toque, reconhecimento facial, uma palavra-passe do dispositivo "
-"ou um PIN. Podem ser usadas como substituto de palavra-passe ou como método "
-"de autenticação de dois fatores (2FA)."
+"As passkeys são credenciais WebAuthn que validam a sua identidade utilizando "
+"toque, reconhecimento facial, uma palavra-passe do dispositivo ou um PIN. "
+"Podem ser usadas como substituto de palavra-passe ou como método de "
+"autenticação de dois fatores (2FA)."
 
 #: src/views/other/Login.vue:183 src/views/user/userColumns.tsx:16
 msgid "Password"
@@ -3545,7 +3556,8 @@ msgstr "Por favor, insira o token de segurança"
 #: src/components/SystemRestore/SystemRestoreContent.vue:210
 #: src/components/SystemRestore/SystemRestoreContent.vue:287
 msgid "Please enter the security token received during backup"
-msgstr "Por favor, insira o token de segurança recebido durante a cópia de segurança"
+msgstr ""
+"Por favor, insira o token de segurança recebido durante a cópia de segurança"
 
 #: src/language/curd.ts:24
 msgid "Please fill all fields correctly"
@@ -3574,8 +3586,8 @@ msgstr ""
 #: src/components/Notification/notifications.ts:182
 #: src/language/constants.ts:59
 msgid ""
-"Please generate new recovery codes in the preferences immediately to "
-"prevent lockout."
+"Please generate new recovery codes in the preferences immediately to prevent "
+"lockout."
 msgstr ""
 "Por favor, gere novos códigos de recuperação nas preferências imediatamente "
 "para evitar bloqueio."
@@ -3623,12 +3635,15 @@ msgid "Please log in."
 msgstr "Por favor, faça login."
 
 #: src/views/certificate/DNSCredential.vue:61
-msgid "Please note that the unit of time configurations below are all in seconds."
-msgstr "Note que as definições da unidade de tempo abaixo estão todas em segundos."
+msgid ""
+"Please note that the unit of time configurations below are all in seconds."
+msgstr ""
+"Note que as definições da unidade de tempo abaixo estão todas em segundos."
 
 #: src/views/install/components/InstallView.vue:102
 msgid "Please resolve all issues before proceeding with installation"
-msgstr "Por favor, resolva todos os problemas antes de prosseguir com a instalação"
+msgstr ""
+"Por favor, resolva todos os problemas antes de prosseguir com a instalação"
 
 #: src/views/backup/components/BackupCreator.vue:107
 msgid "Please save this security token, you will need it for restoration:"
@@ -3644,17 +3659,17 @@ msgstr "Por favor, selecione um ficheiro de cópia de segurança"
 msgid "Please select at least one item"
 msgstr "Por favor, selecione pelo menos um item"
 
-#: src/views/environments/list/Environment.vue:120
+#: src/views/environments/list/Environment.vue:121
 #: src/views/environments/list/Environment.vue:35
 msgid "Please select at least one node to reload Nginx"
 msgstr "Por favor, selecione pelo menos um nó para recarregar o Nginx"
 
-#: src/views/environments/list/Environment.vue:141
+#: src/views/environments/list/Environment.vue:142
 #: src/views/environments/list/Environment.vue:49
 msgid "Please select at least one node to restart Nginx"
 msgstr "Por favor, selecione pelo menos um nó para reiniciar o Nginx"
 
-#: src/views/environments/list/Environment.vue:99
+#: src/views/environments/list/Environment.vue:100
 msgid "Please select at least one node to upgrade"
 msgstr "Por favor, selecione pelo menos um nó para atualizar"
 
@@ -3667,7 +3682,7 @@ msgstr "Por favor, digite \"Revogar\" para confirmar"
 msgid "Port"
 msgstr "Porta"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:44
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:45
 #: src/views/stream/components/RightPanel/RightPanel.vue:26
 msgid "Port Scanner"
 msgstr "Scanner de portas"
@@ -3838,8 +3853,8 @@ msgstr "Recarregar"
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:136
 #: src/views/environments/group/columns.ts:22
 #: src/views/environments/group/EnvGroup.vue:50
-#: src/views/environments/list/Environment.vue:128
-#: src/views/environments/list/Environment.vue:136
+#: src/views/environments/list/Environment.vue:129
+#: src/views/environments/list/Environment.vue:137
 msgid "Reload Nginx"
 msgstr "Recarregar Nginx"
 
@@ -3865,7 +3880,8 @@ msgstr "Recarregamento remoto do Nginx bem-sucedido"
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:84
 msgid "Reload request failed, please check your network connection"
-msgstr "O pedido de recarregamento falhou, por favor verifique a sua ligação à rede"
+msgstr ""
+"O pedido de recarregamento falhou, por favor verifique a sua ligação à rede"
 
 #: src/components/NginxControl/NginxControl.vue:73
 msgid "Reloading"
@@ -3888,7 +3904,7 @@ msgstr "Removido com sucesso"
 msgid "Removed successfully"
 msgstr "Removido com sucesso"
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:126
+#: src/components/NgxConfigEditor/NgxUpstream.vue:131
 #: src/views/config/components/ConfigName.vue:51
 #: src/views/config/components/Rename.vue:56
 #: src/views/config/ConfigList.vue:181
@@ -4021,8 +4037,8 @@ msgid "Restart"
 msgstr "Reiniciar"
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:148
-#: src/views/environments/list/Environment.vue:149
-#: src/views/environments/list/Environment.vue:157
+#: src/views/environments/list/Environment.vue:150
+#: src/views/environments/list/Environment.vue:158
 msgid "Restart Nginx"
 msgstr "Reiniciar Nginx"
 
@@ -4448,19 +4464,19 @@ msgstr "Definindo provedor de HTTP01 challenge"
 
 #: src/constants/errors/nginx_log.ts:8
 msgid ""
-"Settings.NginxLogSettings.AccessLogPath is empty, refer to "
-"https://nginxui.com/guide/config-nginx.html for more information"
+"Settings.NginxLogSettings.AccessLogPath is empty, refer to https://nginxui."
+"com/guide/config-nginx.html for more information"
 msgstr ""
-"Settings.NginxLogSettings.AccessLogPath está vazio, consulte "
-"https://nginxui.com/guide/config-nginx.html para mais informações"
+"Settings.NginxLogSettings.AccessLogPath está vazio, consulte https://nginxui."
+"com/guide/config-nginx.html para mais informações"
 
 #: src/constants/errors/nginx_log.ts:7
 msgid ""
-"Settings.NginxLogSettings.ErrorLogPath is empty, refer to "
-"https://nginxui.com/guide/config-nginx.html for more information"
+"Settings.NginxLogSettings.ErrorLogPath is empty, refer to https://nginxui."
+"com/guide/config-nginx.html for more information"
 msgstr ""
-"Settings.NginxLogSettings.ErrorLogPath está vazio, consulte "
-"https://nginxui.com/guide/config-nginx.html para mais informações"
+"Settings.NginxLogSettings.ErrorLogPath está vazio, consulte https://nginxui."
+"com/guide/config-nginx.html para mais informações"
 
 #: src/views/install/components/InstallView.vue:65
 msgid "Setup your Nginx UI"
@@ -4568,8 +4584,7 @@ msgstr "O caminho do certificado SSL é necessário quando o HTTPS está ativado
 #: src/constants/errors/system.ts:9
 msgid "SSL key file must be under Nginx configuration directory: {0}"
 msgstr ""
-"O ficheiro de chave SSL deve estar no diretório de configuração do Nginx: "
-"{0}"
+"O ficheiro de chave SSL deve estar no diretório de configuração do Nginx: {0}"
 
 #: src/constants/errors/system.ts:7
 msgid "SSL key file not found"
@@ -4651,7 +4666,8 @@ msgstr "O caminho de armazenamento é obrigatório"
 
 #: src/constants/errors/backup.ts:61
 msgid "Storage path not in granted access paths: {0}"
-msgstr "Caminho de armazenamento não está nos caminhos de acesso concedidos: {0}"
+msgstr ""
+"Caminho de armazenamento não está nos caminhos de acesso concedidos: {0}"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:70
 #: src/views/backup/AutoBackup/components/StorageConfigEditor.vue:45
@@ -4697,23 +4713,23 @@ msgstr "Domingo"
 msgid ""
 "Support communication with the backend through the Server-Sent Events "
 "protocol. If your Nginx UI is being used via an Nginx reverse proxy, please "
-"refer to this link to write the corresponding configuration file: "
-"https://nginxui.com/guide/nginx-proxy-example.html"
+"refer to this link to write the corresponding configuration file: https://"
+"nginxui.com/guide/nginx-proxy-example.html"
 msgstr ""
-"Suporte à comunicação com o backend através do protocolo Server-Sent "
-"Events. Se a sua Nginx UI estiver a ser utilizada através de um proxy "
-"inverso Nginx, consulte este link para escrever o ficheiro de configuração "
-"correspondente: https://nginxui.com/guide/nginx-proxy-example.html"
+"Suporte à comunicação com o backend através do protocolo Server-Sent Events. "
+"Se a sua Nginx UI estiver a ser utilizada através de um proxy inverso Nginx, "
+"consulte este link para escrever o ficheiro de configuração correspondente: "
+"https://nginxui.com/guide/nginx-proxy-example.html"
 
 #: src/components/SelfCheck/tasks/frontend/websocket.ts:13
 msgid ""
 "Support communication with the backend through the WebSocket protocol. If "
-"your Nginx UI is being used via an Nginx reverse proxy, please refer to "
-"this link to write the corresponding configuration file: "
-"https://nginxui.com/guide/nginx-proxy-example.html"
+"your Nginx UI is being used via an Nginx reverse proxy, please refer to this "
+"link to write the corresponding configuration file: https://nginxui.com/"
+"guide/nginx-proxy-example.html"
 msgstr ""
-"Suporta a comunicação com o backend através do protocolo WebSocket. Se a "
-"sua interface Nginx está a ser utilizada através de um proxy inverso Nginx, "
+"Suporta a comunicação com o backend através do protocolo WebSocket. Se a sua "
+"interface Nginx está a ser utilizada através de um proxy inverso Nginx, "
 "consulte este link para escrever o ficheiro de configuração correspondente: "
 "https://nginxui.com/guide/nginx-proxy-example.html"
 
@@ -4757,7 +4773,8 @@ msgstr "Falha ao sincronizar o certificado %{cert_name} para %{env_name}"
 
 #: src/components/Notification/notifications.ts:66
 msgid "Sync Certificate %{cert_name} to %{env_name} successfully"
-msgstr "Sincronização do Certificado %{cert_name} para %{env_name} feito com sucesso"
+msgstr ""
+"Sincronização do Certificado %{cert_name} para %{env_name} feito com sucesso"
 
 #: src/components/Notification/notifications.ts:61 src/language/constants.ts:39
 msgid "Sync Certificate Error"
@@ -4860,8 +4877,8 @@ msgid ""
 "since it was last issued."
 msgstr ""
 "O certificado do domínio será verificado 30 minutos e será renovado se já "
-"tiver passado mais de 1 semana ou o período que definiu nas definições "
-"desde a última emissão."
+"tiver passado mais de 1 semana ou o período que definiu nas definições desde "
+"a última emissão."
 
 #: src/views/preference/tabs/NodeSettings.vue:37
 msgid ""
@@ -4881,11 +4898,10 @@ msgstr "O valor introduzido não é uma Chave de Certificado SSL"
 
 #: src/constants/errors/nginx_log.ts:2
 msgid ""
-"The log path is not under the paths in "
-"settings.NginxSettings.LogDirWhiteList"
+"The log path is not under the paths in settings.NginxSettings.LogDirWhiteList"
 msgstr ""
-"O caminho do registo não está sob os caminhos em "
-"settings.NginxSettings.LogDirWhiteList"
+"O caminho do registo não está sob os caminhos em settings.NginxSettings."
+"LogDirWhiteList"
 
 #: src/views/preference/tabs/OpenAISettings.vue:23
 #: src/views/preference/tabs/OpenAISettings.vue:89
@@ -4897,10 +4913,11 @@ msgstr ""
 "traços, dois pontos e pontos."
 
 #: src/views/preference/tabs/OpenAISettings.vue:90
-msgid "The model used for code completion, if not set, the chat model will be used."
+msgid ""
+"The model used for code completion, if not set, the chat model will be used."
 msgstr ""
-"O modelo utilizado para a conclusão de código, se não estiver definido, "
-"será utilizado o modelo de chat."
+"O modelo utilizado para a conclusão de código, se não estiver definido, será "
+"utilizado o modelo de chat."
 
 #: src/views/preference/tabs/NodeSettings.vue:18
 msgid ""
@@ -4936,8 +4953,8 @@ msgid ""
 "version. To avoid potential errors, please upgrade the remote Nginx UI to "
 "match the local version."
 msgstr ""
-"A versão remota do Nginx UI não é compatível com a versão local do Nginx "
-"UI. Para evitar possíveis erros, atualize a versão remota do Nginx UI para "
+"A versão remota do Nginx UI não é compatível com a versão local do Nginx UI. "
+"Para evitar possíveis erros, atualize a versão remota do Nginx UI para "
 "corresponder à versão local."
 
 #: src/components/AutoCertForm/AutoCertForm.vue:43
@@ -5007,14 +5024,17 @@ msgid "This field should not be empty"
 msgstr "Este campo não pode estar vazio"
 
 #: src/constants/form_errors.ts:6
-msgid "This field should only contain letters, unicode characters, numbers, and -_."
-msgstr "Este campo deve conter apenas letras, caracteres Unicode, números e -_."
+msgid ""
+"This field should only contain letters, unicode characters, numbers, and -_."
+msgstr ""
+"Este campo deve conter apenas letras, caracteres Unicode, números e -_."
 
 #: src/language/curd.ts:44
 msgid ""
-"This field should only contain letters, unicode characters, numbers, and "
-"-_./:"
-msgstr "Este campo deve conter apenas letras, caracteres Unicode, números e -_./:"
+"This field should only contain letters, unicode characters, numbers, and -"
+"_./:"
+msgstr ""
+"Este campo deve conter apenas letras, caracteres Unicode, números e -_./:"
 
 #: src/views/dashboard/NginxDashBoard.vue:150
 msgid ""
@@ -5063,10 +5083,10 @@ msgstr ""
 "UI irá reiniciar após a conclusão da restauração."
 
 #: src/views/environments/list/BatchUpgrader.vue:182
-msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
+msgid ""
+"This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
 msgstr ""
-"Isto vai actualizar ou reinstalar o Nginx UI em %{nodeNames} para "
-"%{version}."
+"Isto vai actualizar ou reinstalar o Nginx UI em %{nodeNames} para %{version}."
 
 #: src/views/preference/tabs/AuthSettings.vue:92
 msgid "Throttle"
@@ -5120,8 +5140,8 @@ msgstr ""
 #: src/views/site/site_edit/components/EnableTLS/EnableTLS.vue:15
 msgid ""
 "To make sure the certification auto-renewal can work normally, we need to "
-"add a location which can proxy the request from authority to backend, and "
-"we need to save this file and reload the Nginx. Are you sure you want to "
+"add a location which can proxy the request from authority to backend, and we "
+"need to save this file and reload the Nginx. Are you sure you want to "
 "continue?"
 msgstr ""
 "Para garantir que a renovação automática da certificação funciona "
@@ -5246,8 +5266,8 @@ msgid "Updated at"
 msgstr "Actualizado em"
 
 #: src/routes/modules/system.ts:26
-#: src/views/environments/list/Environment.vue:107
-#: src/views/environments/list/Environment.vue:115
+#: src/views/environments/list/Environment.vue:108
+#: src/views/environments/list/Environment.vue:116
 #: src/views/system/Upgrade.vue:154 src/views/system/Upgrade.vue:159
 msgid "Upgrade"
 msgstr "Actualizar"
@@ -5277,7 +5297,7 @@ msgstr "Carregar pastas"
 msgid "Upstream"
 msgstr "A montante"
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:177
+#: src/components/NgxConfigEditor/NgxUpstream.vue:184
 msgid "Upstream Name"
 msgstr "Nome do Upstream"
 
@@ -5394,8 +5414,8 @@ msgid ""
 "to restore."
 msgstr ""
 "Aviso: A operação de restauro irá substituir as configurações atuais. "
-"Certifique-se de que tem um ficheiro de cópia de segurança válido e um "
-"token de segurança, e selecione cuidadosamente o que restaurar."
+"Certifique-se de que tem um ficheiro de cópia de segurança válido e um token "
+"de segurança, e selecione cuidadosamente o que restaurar."
 
 #: src/views/certificate/DNSCredential.vue:55
 msgid ""
@@ -5407,8 +5427,8 @@ msgstr ""
 
 #: src/views/site/site_edit/components/Cert/ObtainCert.vue:140
 msgid ""
-"We will remove the HTTPChallenge configuration from this file and reload "
-"the Nginx. Are you sure you want to continue?"
+"We will remove the HTTPChallenge configuration from this file and reload the "
+"Nginx. Are you sure you want to continue?"
 msgstr ""
 "Removeremos a configuração HTTPChallenge deste ficheiro e reiniciaremos o "
 "Nginx. Tem a certeza de que quer continuar?"
@@ -5512,8 +5532,8 @@ msgstr "Sim"
 
 #: src/views/terminal/Terminal.vue:132
 msgid ""
-"You are accessing this terminal over an insecure HTTP connection on a "
-"non-localhost domain. This may expose sensitive information."
+"You are accessing this terminal over an insecure HTTP connection on a non-"
+"localhost domain. This may expose sensitive information."
 msgstr ""
 "Está a aceder a este terminal através de uma ligação HTTP insegura num "
 "domínio que não é localhost. Isto pode expor informações sensíveis."
@@ -5539,11 +5559,12 @@ msgid ""
 "You have not configured the settings of Webauthn, so you cannot add a "
 "passkey."
 msgstr ""
-"Não configuraste as definições do WebAuthn, por isso não podes adicionar "
-"uma chave de acesso."
+"Não configuraste as definições do WebAuthn, por isso não podes adicionar uma "
+"chave de acesso."
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:81
-msgid "You have not enabled 2FA yet. Please enable 2FA to generate recovery codes."
+msgid ""
+"You have not enabled 2FA yet. Please enable 2FA to generate recovery codes."
 msgstr ""
 "Ainda não ativou a autenticação de dois fatores. Por favor, ative-a para "
 "gerar códigos de recuperação."
@@ -5630,8 +5651,8 @@ msgstr "As suas chaves de acesso"
 
 #~ msgid ""
 #~ "Check if /var/run/docker.sock exists. If you are using Nginx UI Official "
-#~ "Docker Image, please make sure the docker socket is mounted like this: `-v "
-#~ "/var/run/docker.sock:/var/run/docker.sock`."
+#~ "Docker Image, please make sure the docker socket is mounted like this: `-"
+#~ "v /var/run/docker.sock:/var/run/docker.sock`."
 #~ msgstr ""
 #~ "Verifique se /var/run/docker.sock existe. Se estiver a utilizar a imagem "
 #~ "Docker oficial do Nginx UI, certifique-se de que o socket Docker está "
@@ -5667,7 +5688,8 @@ msgstr "As suas chaves de acesso"
 #~ msgstr "Este item Auto Cert é inválido, por favor remova-o."
 
 #~ msgid "Automatically indexed from site and stream configurations."
-#~ msgstr "Indexado automaticamente a partir das configurações de site e stream."
+#~ msgstr ""
+#~ "Indexado automaticamente a partir das configurações de site e stream."
 
 #~ msgid "Deploy successfully"
 #~ msgstr "Deploy sucedido"
@@ -5690,7 +5712,9 @@ msgstr "As suas chaves de acesso"
 #~ msgstr "Ambiente"
 
 #~ msgid "Failed to save, syntax error(s) was detected in the configuration."
-#~ msgstr "Falha ao salvar, erro(s) de sintaxe detectados no ficheiro de configuração."
+#~ msgstr ""
+#~ "Falha ao salvar, erro(s) de sintaxe detectados no ficheiro de "
+#~ "configuração."
 
 #~ msgid "File"
 #~ msgstr "Ficheiro"
@@ -5699,11 +5723,11 @@ msgstr "As suas chaves de acesso"
 #~ msgstr "Erro de Formato %{msg}"
 
 #~ msgid ""
-#~ "If you lose your mobile phone, you can use the recovery code to reset your "
-#~ "2FA."
+#~ "If you lose your mobile phone, you can use the recovery code to reset "
+#~ "your 2FA."
 #~ msgstr ""
-#~ "Se perder o seu telemóvel, pode utilizar o código de recuperação para repor "
-#~ "o seu 2FA."
+#~ "Se perder o seu telemóvel, pode utilizar o código de recuperação para "
+#~ "repor o seu 2FA."
 
 #~ msgid "Incorrect username or password"
 #~ msgstr "Utilizador ou senha incorrectos"
@@ -5731,7 +5755,8 @@ msgstr "As suas chaves de acesso"
 #~ "Sincronização do Certificado %{cert_name} para %{env_name} falhou, por "
 #~ "favor actualize a versão remota do Nginx UI para a última versão"
 
-#~ msgid "Sync Certificate %{cert_name} to %{env_name} failed, response: %{resp}"
+#~ msgid ""
+#~ "Sync Certificate %{cert_name} to %{env_name} failed, response: %{resp}"
 #~ msgstr ""
 #~ "Sincronização do Certificado %{cert_name} para %{env_name} falhou, "
 #~ "resposta: %{resp}"
@@ -5748,7 +5773,8 @@ msgstr "As suas chaves de acesso"
 #~ "Sincronização de configuração %{config_name} para %{env_name} falhou, "
 #~ "resposta: %{resp}"
 
-#~ msgid "The recovery code is only displayed once, please save it in a safe place."
+#~ msgid ""
+#~ "The recovery code is only displayed once, please save it in a safe place."
 #~ msgstr ""
 #~ "O código de recuperação é apresentado apenas uma vez, guarde-o num local "
 #~ "seguro."

+ 197 - 179
app/src/language/ru_RU/app.po

@@ -7,24 +7,24 @@ msgstr ""
 "POT-Creation-Date: \n"
 "PO-Revision-Date: 2025-03-28 02:45+0300\n"
 "Last-Translator: Artyom Isrofilov <artyom@isrofilov.ru>\n"
-"Language-Team: Russian "
-"<https://weblate.nginxui.com/projects/nginx-ui/frontend/ru/>\n"
+"Language-Team: Russian <https://weblate.nginxui.com/projects/nginx-ui/"
+"frontend/ru/>\n"
 "Language: ru_RU\n"
 "MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=utf-8\n"
+"Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 "X-Generator: Poedit 3.5\n"
 
 #: src/language/generate.ts:31
 msgid "[Nginx UI] ACME User: %{name}, Email: %{email}, CA Dir: %{caDir}"
-msgstr "[Nginx UI] Пользователь ACME: %{name}, Email: %{email}, Каталог CA: %{caDir}"
+msgstr ""
+"[Nginx UI] Пользователь ACME: %{name}, Email: %{email}, Каталог CA: %{caDir}"
 
 #: src/language/generate.ts:32
 msgid "[Nginx UI] Backing up current certificate for later revocation"
 msgstr ""
-"[Nginx UI] Резервное копирование текущего сертификата для последующего "
-"отзыва"
+"[Nginx UI] Резервное копирование текущего сертификата для последующего отзыва"
 
 #: src/language/generate.ts:33
 msgid "[Nginx UI] Certificate renewed successfully"
@@ -35,10 +35,11 @@ msgid "[Nginx UI] Certificate successfully revoked"
 msgstr "[Nginx UI] Сертификат успешно отозван"
 
 #: src/language/generate.ts:35
-msgid "[Nginx UI] Certificate was used for server, reloading server TLS certificate"
+msgid ""
+"[Nginx UI] Certificate was used for server, reloading server TLS certificate"
 msgstr ""
-"[Nginx UI] Сертификат использовался для сервера, перезагрузка "
-"TLS-сертификата сервера"
+"[Nginx UI] Сертификат использовался для сервера, перезагрузка TLS-"
+"сертификата сервера"
 
 #: src/language/generate.ts:36
 msgid "[Nginx UI] Creating client facilitates communication with the CA server"
@@ -163,10 +164,10 @@ msgid "Actual worker to configured ratio"
 msgstr "Фактическое соотношение рабочих к настроенным"
 
 #: src/components/NgxConfigEditor/NgxServer.vue:112
-#: src/components/NgxConfigEditor/NgxUpstream.vue:159 src/language/curd.ts:19
+#: src/components/NgxConfigEditor/NgxUpstream.vue:166 src/language/curd.ts:19
 #: src/views/preference/tabs/CertSettings.vue:45
 #: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:94
-#: src/views/stream/StreamList.vue:101
+#: src/views/stream/StreamList.vue:102
 msgid "Add"
 msgstr "Добавить"
 
@@ -193,7 +194,7 @@ msgstr "Добавить Location"
 msgid "Add Site"
 msgstr "Добавить Сайт"
 
-#: src/views/stream/StreamList.vue:138
+#: src/views/stream/StreamList.vue:139
 msgid "Add Stream"
 msgstr "Добавить поток"
 
@@ -212,7 +213,8 @@ msgstr "Расширенный режим"
 
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:99
 msgid "Afterwards, refresh this page and click add passkey again."
-msgstr "После этого обновите эту страницу и снова нажмите «Добавить ключ доступа»."
+msgstr ""
+"После этого обновите эту страницу и снова нажмите «Добавить ключ доступа»."
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:115
 msgid "All"
@@ -281,7 +283,7 @@ msgid "Are you sure you want to delete permanently?"
 msgstr "Вы уверены, что хотите удалить безвозвратно?"
 
 #: src/language/curd.ts:25 src/views/site/site_list/SiteList.vue:100
-#: src/views/stream/StreamList.vue:121
+#: src/views/stream/StreamList.vue:122
 msgid "Are you sure you want to delete?"
 msgstr "Вы уверены, что хотите удалить?"
 
@@ -468,7 +470,8 @@ msgstr ""
 "%{file_path}"
 
 #: src/components/Notification/notifications.ts:34
-msgid "Backup task %{backup_name} failed during storage upload, error: %{error}"
+msgid ""
+"Backup task %{backup_name} failed during storage upload, error: %{error}"
 msgstr ""
 "Задача резервного копирования %{backup_name} не выполнена при загрузке в "
 "хранилище, ошибка: %{error}"
@@ -504,7 +507,7 @@ msgid "Base information"
 msgstr "Основная информация"
 
 #: src/views/config/ConfigEditor.vue:300
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:31
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:32
 #: src/views/stream/components/RightPanel/RightPanel.vue:20
 msgid "Basic"
 msgstr "Основные"
@@ -553,8 +556,7 @@ msgstr "Кэш"
 #: src/views/dashboard/components/ParamsOpt/ProxyCacheConfig.vue:178
 msgid "Cache items not accessed within this time will be removed"
 msgstr ""
-"Элементы кэша, к которым не обращались в течение этого времени, будут "
-"удалены"
+"Элементы кэша, к которым не обращались в течение этого времени, будут удалены"
 
 #: src/views/dashboard/components/ParamsOpt/ProxyCacheConfig.vue:350
 msgid "Cache loader processing time threshold"
@@ -750,7 +752,7 @@ msgstr "Путь изменён"
 msgid "Channel"
 msgstr "Канал"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:41
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:42
 #: src/views/stream/components/RightPanel/RightPanel.vue:23
 msgid "Chat"
 msgstr "Чат"
@@ -767,13 +769,13 @@ msgstr "Проверить повторно"
 #: src/language/generate.ts:6
 msgid ""
 "Check if /var/run/docker.sock exists. If you are using Nginx UI Official "
-"Docker Image, please make sure the docker socket is mounted like this: `-v "
-"/var/run/docker.sock:/var/run/docker.sock`. Nginx UI official image uses "
-"/var/run/docker.sock to communicate with the host Docker Engine via Docker "
-"Client API. This feature is used to control Nginx in another container and "
-"perform container replacement rather than binary replacement during OTA "
-"upgrades of Nginx UI to ensure container dependencies are also upgraded. If "
-"you don't need this feature, please add the environment variable "
+"Docker Image, please make sure the docker socket is mounted like this: `-v /"
+"var/run/docker.sock:/var/run/docker.sock`. Nginx UI official image uses /var/"
+"run/docker.sock to communicate with the host Docker Engine via Docker Client "
+"API. This feature is used to control Nginx in another container and perform "
+"container replacement rather than binary replacement during OTA upgrades of "
+"Nginx UI to ensure container dependencies are also upgraded. If you don't "
+"need this feature, please add the environment variable "
 "NGINX_UI_IGNORE_DOCKER_SOCKET=true to the container."
 msgstr ""
 "Проверьте, существует ли /var/run/docker.sock. Если вы используете "
@@ -797,19 +799,19 @@ msgstr ""
 
 #: src/language/generate.ts:8
 msgid ""
-"Check if the nginx access log path exists. By default, this path is "
-"obtained from 'nginx -V'. If it cannot be obtained or the obtained path "
-"does not point to a valid, existing file, an error will be reported. In "
-"this case, you need to modify the configuration file to specify the access "
-"log path.Refer to the docs for more details: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#accesslogpath"
+"Check if the nginx access log path exists. By default, this path is obtained "
+"from 'nginx -V'. If it cannot be obtained or the obtained path does not "
+"point to a valid, existing file, an error will be reported. In this case, "
+"you need to modify the configuration file to specify the access log path."
+"Refer to the docs for more details: https://nginxui.com/zh_CN/guide/config-"
+"nginx.html#accesslogpath"
 msgstr ""
 "Проверьте, существует ли путь к журналу доступа nginx. По умолчанию этот "
 "путь получается из 'nginx -V'. Если его невозможно получить или полученный "
 "путь не указывает на действительный существующий файл, будет сообщена "
 "ошибка. В этом случае вам необходимо изменить файл конфигурации, чтобы "
-"указать путь к журналу доступа. Подробнее см. в документации: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#accesslogpath"
+"указать путь к журналу доступа. Подробнее см. в документации: https://"
+"nginxui.com/zh_CN/guide/config-nginx.html#accesslogpath"
 
 #: src/language/generate.ts:9
 msgid "Check if the nginx configuration directory exists"
@@ -824,30 +826,30 @@ msgid ""
 "Check if the nginx error log path exists. By default, this path is obtained "
 "from 'nginx -V'. If it cannot be obtained or the obtained path does not "
 "point to a valid, existing file, an error will be reported. In this case, "
-"you need to modify the configuration file to specify the error log "
-"path.Refer to the docs for more details: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#errorlogpath"
+"you need to modify the configuration file to specify the error log path."
+"Refer to the docs for more details: https://nginxui.com/zh_CN/guide/config-"
+"nginx.html#errorlogpath"
 msgstr ""
-"Проверьте, существует ли путь к журналу ошибок nginx. По умолчанию этот "
-"путь получается из 'nginx -V'. Если его не удается получить или полученный "
-"путь не указывает на действительный существующий файл, будет сообщена "
-"ошибка. В этом случае вам необходимо изменить файл конфигурации, чтобы "
-"указать путь к журналу ошибок. Подробнее см. в документации: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#errorlogpath"
+"Проверьте, существует ли путь к журналу ошибок nginx. По умолчанию этот путь "
+"получается из 'nginx -V'. Если его не удается получить или полученный путь "
+"не указывает на действительный существующий файл, будет сообщена ошибка. В "
+"этом случае вам необходимо изменить файл конфигурации, чтобы указать путь к "
+"журналу ошибок. Подробнее см. в документации: https://nginxui.com/zh_CN/"
+"guide/config-nginx.html#errorlogpath"
 
 #: src/language/generate.ts:7
 msgid ""
 "Check if the nginx PID path exists. By default, this path is obtained from "
 "'nginx -V'. If it cannot be obtained, an error will be reported. In this "
 "case, you need to modify the configuration file to specify the Nginx PID "
-"path.Refer to the docs for more details: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#pidpath"
+"path.Refer to the docs for more details: https://nginxui.com/zh_CN/guide/"
+"config-nginx.html#pidpath"
 msgstr ""
-"Проверьте, существует ли путь к PID Nginx. По умолчанию этот путь "
-"получается из команды 'nginx -V'. Если его не удается получить, будет "
-"сообщена ошибка. В этом случае вам нужно изменить конфигурационный файл, "
-"чтобы указать путь к PID Nginx. Подробнее см. в документации: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#pidpath"
+"Проверьте, существует ли путь к PID Nginx. По умолчанию этот путь получается "
+"из команды 'nginx -V'. Если его не удается получить, будет сообщена ошибка. "
+"В этом случае вам нужно изменить конфигурационный файл, чтобы указать путь к "
+"PID Nginx. Подробнее см. в документации: https://nginxui.com/zh_CN/guide/"
+"config-nginx.html#pidpath"
 
 #: src/language/generate.ts:12
 msgid "Check if the nginx.conf includes the conf.d directory"
@@ -871,8 +873,8 @@ msgstr ""
 
 #: src/language/generate.ts:16
 msgid ""
-"Check if the streams-available and streams-enabled directories are under "
-"the nginx configuration directory"
+"Check if the streams-available and streams-enabled directories are under the "
+"nginx configuration directory"
 msgstr ""
 "Проверьте, находятся ли каталоги streams-available и streams-enabled в "
 "каталоге конфигурации nginx"
@@ -1003,7 +1005,7 @@ msgstr "Файл входа конфигурации не существует"
 msgid "Config path is empty"
 msgstr "Путь конфигурации пуст"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:37
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:38
 msgid "Config Template"
 msgstr "Шаблон конфигурации"
 
@@ -1101,7 +1103,7 @@ msgstr ""
 msgid "CPU:"
 msgstr "CPU:"
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:170
+#: src/components/NgxConfigEditor/NgxUpstream.vue:177
 msgid "Create"
 msgstr "Создать"
 
@@ -1241,10 +1243,10 @@ msgid "Define shared memory zone name and size, e.g. proxy_cache:10m"
 msgstr "Определите имя и размер зоны общей памяти, например proxy_cache:10m"
 
 #: src/components/NgxConfigEditor/NgxServer.vue:78
-#: src/components/NgxConfigEditor/NgxUpstream.vue:129 src/language/curd.ts:9
+#: src/components/NgxConfigEditor/NgxUpstream.vue:134 src/language/curd.ts:9
 #: src/views/certificate/components/RemoveCert.vue:88
 #: src/views/site/site_list/SiteList.vue:109
-#: src/views/stream/StreamList.vue:130
+#: src/views/stream/StreamList.vue:131
 msgid "Delete"
 msgstr "Удалить"
 
@@ -1522,7 +1524,8 @@ msgstr "Домен"
 
 #: src/views/certificate/CertificateEditor.vue:112
 msgid "Domains list is empty, try to reopen Auto Cert for %{config}"
-msgstr "Список доменов пуст, попробуйте заново создать авто-сертификат для %{config}"
+msgstr ""
+"Список доменов пуст, попробуйте заново создать авто-сертификат для %{config}"
 
 #: src/language/constants.ts:27
 msgid "Download latest release error"
@@ -1549,7 +1552,7 @@ msgstr ""
 #: src/views/site/site_list/SiteDuplicate.vue:72
 #: src/views/site/site_list/SiteList.vue:95
 #: src/views/stream/components/StreamDuplicate.vue:64
-#: src/views/stream/StreamList.vue:116
+#: src/views/stream/StreamList.vue:117
 msgid "Duplicate"
 msgstr "Дублировать"
 
@@ -1730,7 +1733,7 @@ msgstr "Переменные окружения очищены"
 
 #: src/routes/modules/environments.ts:11
 #: src/views/dashboard/Environments.vue:83
-#: src/views/environments/list/Environment.vue:81
+#: src/views/environments/list/Environment.vue:82
 msgid "Environments"
 msgstr "Окружения"
 
@@ -2152,8 +2155,8 @@ msgid ""
 "Follow the instructions in the dialog to complete the passkey registration "
 "process."
 msgstr ""
-"Следуйте инструкциям в всплывающем окне, чтобы завершить процесс "
-"регистрации ключа доступа."
+"Следуйте инструкциям в всплывающем окне, чтобы завершить процесс регистрации "
+"ключа доступа."
 
 #: src/views/preference/tabs/NodeSettings.vue:42
 #: src/views/preference/tabs/NodeSettings.vue:54
@@ -2252,7 +2255,8 @@ msgstr "Скрыть"
 
 #: src/views/dashboard/components/PerformanceStatisticsCard.vue:87
 msgid "Higher value means better connection reuse"
-msgstr "Более высокое значение означает лучшее повторное использование соединения"
+msgstr ""
+"Более высокое значение означает лучшее повторное использование соединения"
 
 #: src/views/config/ConfigEditor.vue:260
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
@@ -2309,11 +2313,13 @@ msgstr ""
 msgid ""
 "If you want to automatically revoke the old certificate, please enable this "
 "option."
-msgstr "Если вы хотите автоматически отозвать старый сертификат, включите эту опцию."
+msgstr ""
+"Если вы хотите автоматически отозвать старый сертификат, включите эту опцию."
 
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:70
 msgid "If your browser supports WebAuthn Passkey, a dialog box will appear."
-msgstr "Если ваш браузер поддерживает WebAuthn Passkey, появится диалоговое окно."
+msgstr ""
+"Если ваш браузер поддерживает WebAuthn Passkey, появится диалоговое окно."
 
 #: src/components/AutoCertForm/AutoCertForm.vue:107
 msgid ""
@@ -2501,8 +2507,8 @@ msgid ""
 "Keep your recovery codes as safe as your password. We recommend saving them "
 "with a password manager."
 msgstr ""
-"Храните ваши коды восстановления так же безопасно, как и пароль. "
-"Рекомендуем сохранить их в менеджере паролей."
+"Храните ваши коды восстановления так же безопасно, как и пароль. Рекомендуем "
+"сохранить их в менеджере паролей."
 
 #: src/views/dashboard/components/ParamsOpt/PerformanceConfig.vue:60
 msgid "Keepalive Timeout"
@@ -2595,7 +2601,7 @@ msgstr "Ожидает"
 msgid "Load Average:"
 msgstr "Средняя нагрузка:"
 
-#: src/views/environments/list/Environment.vue:88
+#: src/views/environments/list/Environment.vue:89
 msgid "Load from settings"
 msgstr "Загрузить из настроек"
 
@@ -2656,13 +2662,12 @@ msgstr "Журнал"
 #: src/language/generate.ts:20
 msgid ""
 "Log file %{log_path} is not a regular file. If you are using nginx-ui in "
-"docker container, please refer to "
-"https://nginxui.com/zh_CN/guide/config-nginx-log.html for more information."
+"docker container, please refer to https://nginxui.com/zh_CN/guide/config-"
+"nginx-log.html for more information."
 msgstr ""
 "Файл журнала %{log_path} не является обычным файлом. Если вы используете "
-"nginx-ui в контейнере Docker, обратитесь к "
-"https://nginxui.com/zh_CN/guide/config-nginx-log.html для получения "
-"дополнительной информации."
+"nginx-ui в контейнере Docker, обратитесь к https://nginxui.com/zh_CN/guide/"
+"config-nginx-log.html для получения дополнительной информации."
 
 #: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:72
 msgid "Log List"
@@ -2686,18 +2691,18 @@ msgstr "Прокрутка"
 
 #: src/views/preference/tabs/LogrotateSettings.vue:13
 msgid ""
-"Logrotate, by default, is enabled in most mainstream Linux distributions "
-"for users who install Nginx UI on the host machine, so you don't need to "
-"modify the parameters on this page. For users who install Nginx UI using "
-"Docker containers, you can manually enable this option. The crontab task "
-"scheduler of Nginx UI will execute the logrotate command at the interval "
-"you set in minutes."
+"Logrotate, by default, is enabled in most mainstream Linux distributions for "
+"users who install Nginx UI on the host machine, so you don't need to modify "
+"the parameters on this page. For users who install Nginx UI using Docker "
+"containers, you can manually enable this option. The crontab task scheduler "
+"of Nginx UI will execute the logrotate command at the interval you set in "
+"minutes."
 msgstr ""
 "Logrotate по умолчанию включен в большинстве основных дистрибутивов Linux "
 "для пользователей, которые устанавливают Nginx UI на хост-машину, поэтому "
-"вам не нужно изменять параметры на этой странице. Для пользователей, "
-"которые устанавливают Nginx UI с использованием Docker-контейнеров, вы "
-"можете вручную включить эту опцию. Планировщик задач crontab Nginx UI будет "
+"вам не нужно изменять параметры на этой странице. Для пользователей, которые "
+"устанавливают Nginx UI с использованием Docker-контейнеров, вы можете "
+"вручную включить эту опцию. Планировщик задач crontab Nginx UI будет "
 "выполнять команду logrotate с интервалом, который вы установите в минутах."
 
 #: src/views/site/components/SiteStatusSelect.vue:165
@@ -2892,7 +2897,7 @@ msgstr "Ежемесячно в день %{day} в %{time}"
 msgid "Multi-line Directive"
 msgstr "Многострочная директива"
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:182
+#: src/components/NgxConfigEditor/NgxUpstream.vue:189
 #: src/views/backup/AutoBackup/AutoBackup.vue:11
 #: src/views/certificate/ACMEUser.vue:11
 #: src/views/certificate/CertificateEditor.vue:162
@@ -2910,7 +2915,7 @@ msgstr "Многострочная директива"
 #: src/views/stream/columns.tsx:12
 #: src/views/stream/components/RightPanel/Basic.vue:72
 #: src/views/stream/components/StreamDuplicate.vue:71
-#: src/views/stream/StreamList.vue:143
+#: src/views/stream/StreamList.vue:144
 msgid "Name"
 msgstr "Имя"
 
@@ -3141,8 +3146,8 @@ msgstr "Конфигурация Nginx UI была восстановлена"
 
 #: src/components/SystemRestore/SystemRestoreContent.vue:336
 msgid ""
-"Nginx UI configuration has been restored and will restart automatically in "
-"a few seconds."
+"Nginx UI configuration has been restored and will restart automatically in a "
+"few seconds."
 msgstr ""
 "Конфигурация Nginx UI была восстановлена и автоматически перезапустится "
 "через несколько секунд."
@@ -3168,7 +3173,7 @@ msgstr "Nginx.conf включает каталог streams-enabled"
 #: src/views/notification/Notification.vue:38
 #: src/views/preference/tabs/AuthSettings.vue:132
 #: src/views/preference/tabs/CertSettings.vue:73
-#: src/views/site/site_list/SiteList.vue:98 src/views/stream/StreamList.vue:119
+#: src/views/site/site_list/SiteList.vue:98 src/views/stream/StreamList.vue:120
 msgid "No"
 msgstr "Нет"
 
@@ -3303,7 +3308,7 @@ msgid "Off"
 msgstr "Выкл"
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:159
-#: src/components/NgxConfigEditor/NgxUpstream.vue:145
+#: src/components/NgxConfigEditor/NgxUpstream.vue:151
 #: src/components/NodeSelector/NodeSelector.vue:109
 #: src/components/ProxyTargets/ProxyTargets.vue:43
 #: src/views/dashboard/Environments.vue:107
@@ -3324,7 +3329,7 @@ msgstr "Оффлайн"
 #: src/views/site/site_list/SiteList.vue:99
 #: src/views/stream/components/RightPanel/Basic.vue:48
 #: src/views/stream/components/StreamStatusSelect.vue:60
-#: src/views/stream/StreamList.vue:120
+#: src/views/stream/StreamList.vue:121
 msgid "OK"
 msgstr "ОК"
 
@@ -3520,8 +3525,8 @@ msgid ""
 "Please enable the stub_status module to get request statistics, connection "
 "count, etc."
 msgstr ""
-"Пожалуйста, включите модуль stub_status, чтобы получать статистику "
-"запросов, количество соединений и т. д."
+"Пожалуйста, включите модуль stub_status, чтобы получать статистику запросов, "
+"количество соединений и т. д."
 
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:69
 msgid ""
@@ -3563,8 +3568,8 @@ msgid ""
 "Please fill in the API authentication credentials provided by your DNS "
 "provider."
 msgstr ""
-"Пожалуйста, заполните учетные данные API, предоставленные вашим "
-"DNS-провайдером."
+"Пожалуйста, заполните учетные данные API, предоставленные вашим DNS-"
+"провайдером."
 
 #: src/components/AutoCertForm/AutoCertForm.vue:56
 msgid ""
@@ -3578,8 +3583,8 @@ msgstr ""
 #: src/components/Notification/notifications.ts:182
 #: src/language/constants.ts:59
 msgid ""
-"Please generate new recovery codes in the preferences immediately to "
-"prevent lockout."
+"Please generate new recovery codes in the preferences immediately to prevent "
+"lockout."
 msgstr ""
 "Пожалуйста, немедленно сгенерируйте новые коды восстановления в настройках, "
 "чтобы избежать блокировки."
@@ -3627,7 +3632,8 @@ msgid "Please log in."
 msgstr "Пожалуйста, войдите в систему."
 
 #: src/views/certificate/DNSCredential.vue:61
-msgid "Please note that the unit of time configurations below are all in seconds."
+msgid ""
+"Please note that the unit of time configurations below are all in seconds."
 msgstr ""
 "Обратите внимание, что единица измерения времени в конфигурациях ниже "
 "указана в секундах."
@@ -3650,17 +3656,17 @@ msgstr "Пожалуйста, выберите файл резервной ко
 msgid "Please select at least one item"
 msgstr "Пожалуйста, выберите хотя бы один элемент"
 
-#: src/views/environments/list/Environment.vue:120
+#: src/views/environments/list/Environment.vue:121
 #: src/views/environments/list/Environment.vue:35
 msgid "Please select at least one node to reload Nginx"
 msgstr "Пожалуйста, выберите хотя бы один узел для перезагрузки Nginx"
 
-#: src/views/environments/list/Environment.vue:141
+#: src/views/environments/list/Environment.vue:142
 #: src/views/environments/list/Environment.vue:49
 msgid "Please select at least one node to restart Nginx"
 msgstr "Пожалуйста, выберите хотя бы один узел для перезапуска Nginx"
 
-#: src/views/environments/list/Environment.vue:99
+#: src/views/environments/list/Environment.vue:100
 msgid "Please select at least one node to upgrade"
 msgstr "Пожалуйста, выберите хотя бы один узел"
 
@@ -3673,7 +3679,7 @@ msgstr "Пожалуйста, введите \"Отозвать\" для под
 msgid "Port"
 msgstr "Порт"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:44
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:45
 #: src/views/stream/components/RightPanel/RightPanel.vue:26
 msgid "Port Scanner"
 msgstr "Сканер портов"
@@ -3781,8 +3787,8 @@ msgid ""
 "Recovery codes are used to access your account when you lose access to your "
 "2FA device. Each code can only be used once."
 msgstr ""
-"Коды восстановления используются для доступа к аккаунту при утере "
-"2FA-устройства. Каждый код можно использовать только один раз."
+"Коды восстановления используются для доступа к аккаунту при утере 2FA-"
+"устройства. Каждый код можно использовать только один раз."
 
 #: src/views/preference/tabs/CertSettings.vue:40
 msgid "Recursive Nameservers"
@@ -3844,8 +3850,8 @@ msgstr "Перегрузить"
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:136
 #: src/views/environments/group/columns.ts:22
 #: src/views/environments/group/EnvGroup.vue:50
-#: src/views/environments/list/Environment.vue:128
-#: src/views/environments/list/Environment.vue:136
+#: src/views/environments/list/Environment.vue:129
+#: src/views/environments/list/Environment.vue:137
 msgid "Reload Nginx"
 msgstr "Перезагрузить Nginx"
 
@@ -3871,7 +3877,8 @@ msgstr "Удаленная перезагрузка Nginx успешно вып
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:84
 msgid "Reload request failed, please check your network connection"
-msgstr "Не удалось выполнить запрос на перезагрузку, проверьте подключение к сети"
+msgstr ""
+"Не удалось выполнить запрос на перезагрузку, проверьте подключение к сети"
 
 #: src/components/NginxControl/NginxControl.vue:73
 msgid "Reloading"
@@ -3894,7 +3901,7 @@ msgstr "Удалено успешно"
 msgid "Removed successfully"
 msgstr "Успешно удалено"
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:126
+#: src/components/NgxConfigEditor/NgxUpstream.vue:131
 #: src/views/config/components/ConfigName.vue:51
 #: src/views/config/components/Rename.vue:56
 #: src/views/config/ConfigList.vue:181
@@ -4025,8 +4032,8 @@ msgid "Restart"
 msgstr "Перезапуск"
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:148
-#: src/views/environments/list/Environment.vue:149
-#: src/views/environments/list/Environment.vue:157
+#: src/views/environments/list/Environment.vue:150
+#: src/views/environments/list/Environment.vue:158
 msgid "Restart Nginx"
 msgstr "Перезапустить Nginx"
 
@@ -4450,16 +4457,16 @@ msgstr "Настройка провайдера проверки HTTP01"
 
 #: src/constants/errors/nginx_log.ts:8
 msgid ""
-"Settings.NginxLogSettings.AccessLogPath is empty, refer to "
-"https://nginxui.com/guide/config-nginx.html for more information"
+"Settings.NginxLogSettings.AccessLogPath is empty, refer to https://nginxui."
+"com/guide/config-nginx.html for more information"
 msgstr ""
 "Settings.NginxLogSettings.AccessLogPath пуст, дополнительную информацию см. "
 "на https://nginxui.com/guide/config-nginx.html"
 
 #: src/constants/errors/nginx_log.ts:7
 msgid ""
-"Settings.NginxLogSettings.ErrorLogPath is empty, refer to "
-"https://nginxui.com/guide/config-nginx.html for more information"
+"Settings.NginxLogSettings.ErrorLogPath is empty, refer to https://nginxui."
+"com/guide/config-nginx.html for more information"
 msgstr ""
 "Settings.NginxLogSettings.ErrorLogPath пуст, дополнительную информацию см. "
 "на https://nginxui.com/guide/config-nginx.html"
@@ -4542,7 +4549,8 @@ msgstr "Содержимое SSL-сертификата"
 
 #: src/constants/errors/system.ts:8
 msgid "SSL certificate file must be under Nginx configuration directory: {0}"
-msgstr "Файл SSL-сертификата должен находиться в каталоге конфигурации Nginx: {0}"
+msgstr ""
+"Файл SSL-сертификата должен находиться в каталоге конфигурации Nginx: {0}"
 
 #: src/constants/errors/system.ts:6
 msgid "SSL certificate file not found"
@@ -4695,25 +4703,25 @@ msgstr "Воскресенье"
 msgid ""
 "Support communication with the backend through the Server-Sent Events "
 "protocol. If your Nginx UI is being used via an Nginx reverse proxy, please "
-"refer to this link to write the corresponding configuration file: "
-"https://nginxui.com/guide/nginx-proxy-example.html"
+"refer to this link to write the corresponding configuration file: https://"
+"nginxui.com/guide/nginx-proxy-example.html"
 msgstr ""
-"Поддержка связи с бэкендом через протокол Server-Sent Events. Если ваш "
-"Nginx UI используется через обратный прокси Nginx, обратитесь к этой "
-"ссылке, чтобы написать соответствующий конфигурационный файл: "
-"https://nginxui.com/guide/nginx-proxy-example.html"
+"Поддержка связи с бэкендом через протокол Server-Sent Events. Если ваш Nginx "
+"UI используется через обратный прокси Nginx, обратитесь к этой ссылке, чтобы "
+"написать соответствующий конфигурационный файл: https://nginxui.com/guide/"
+"nginx-proxy-example.html"
 
 #: src/components/SelfCheck/tasks/frontend/websocket.ts:13
 msgid ""
 "Support communication with the backend through the WebSocket protocol. If "
-"your Nginx UI is being used via an Nginx reverse proxy, please refer to "
-"this link to write the corresponding configuration file: "
-"https://nginxui.com/guide/nginx-proxy-example.html"
+"your Nginx UI is being used via an Nginx reverse proxy, please refer to this "
+"link to write the corresponding configuration file: https://nginxui.com/"
+"guide/nginx-proxy-example.html"
 msgstr ""
 "Поддерживает связь с бэкендом через протокол WebSocket. Если ваш Nginx UI "
 "используется через обратный прокси Nginx, обратитесь к этой ссылке, чтобы "
-"написать соответствующий конфигурационный файл: "
-"https://nginxui.com/guide/nginx-proxy-example.html"
+"написать соответствующий конфигурационный файл: https://nginxui.com/guide/"
+"nginx-proxy-example.html"
 
 #: src/language/curd.ts:51 src/language/curd.ts:55
 msgid "Support single or batch upload of files"
@@ -4879,11 +4887,10 @@ msgstr "Введенные данные не являются ключом SSL 
 
 #: src/constants/errors/nginx_log.ts:2
 msgid ""
-"The log path is not under the paths in "
-"settings.NginxSettings.LogDirWhiteList"
+"The log path is not under the paths in settings.NginxSettings.LogDirWhiteList"
 msgstr ""
-"Путь к журналу не находится под путями в "
-"settings.NginxSettings.LogDirWhiteList"
+"Путь к журналу не находится под путями в settings.NginxSettings."
+"LogDirWhiteList"
 
 #: src/views/preference/tabs/OpenAISettings.vue:23
 #: src/views/preference/tabs/OpenAISettings.vue:89
@@ -4895,7 +4902,8 @@ msgstr ""
 "двоеточия и точки."
 
 #: src/views/preference/tabs/OpenAISettings.vue:90
-msgid "The model used for code completion, if not set, the chat model will be used."
+msgid ""
+"The model used for code completion, if not set, the chat model will be used."
 msgstr ""
 "Модель, используемая для завершения кода. Если не задана, будет "
 "использоваться чат-модель."
@@ -4943,8 +4951,8 @@ msgid ""
 "The server_name in the current configuration must be the domain name you "
 "need to get the certificate, supportmultiple domains."
 msgstr ""
-"server_name в текущей конфигурации должен быть доменным именем, для "
-"которого вам нужно получить сертификат, поддержка нескольких доменов."
+"server_name в текущей конфигурации должен быть доменным именем, для которого "
+"вам нужно получить сертификат, поддержка нескольких доменов."
 
 #: src/views/preference/tabs/CertSettings.vue:22
 #: src/views/preference/tabs/HTTPSettings.vue:14
@@ -4974,8 +4982,8 @@ msgid ""
 "your password and second factors. If you cannot find these codes, you will "
 "lose access to your account."
 msgstr ""
-"Эти коды являются последним средством для доступа к вашему аккаунту, если "
-"вы потеряете пароль и вторые факторы. Если вы не сможете найти эти коды, вы "
+"Эти коды являются последним средством для доступа к вашему аккаунту, если вы "
+"потеряете пароль и вторые факторы. Если вы не сможете найти эти коды, вы "
 "потеряете доступ к своему аккаунту."
 
 #: src/views/certificate/CertificateEditor.vue:102
@@ -5005,13 +5013,14 @@ msgid "This field should not be empty"
 msgstr "Это поле обязательно к заполнению"
 
 #: src/constants/form_errors.ts:6
-msgid "This field should only contain letters, unicode characters, numbers, and -_."
+msgid ""
+"This field should only contain letters, unicode characters, numbers, and -_."
 msgstr "Это поле должно содержать только буквы, символы Юникода, цифры и -_."
 
 #: src/language/curd.ts:44
 msgid ""
-"This field should only contain letters, unicode characters, numbers, and "
-"-_./:"
+"This field should only contain letters, unicode characters, numbers, and -"
+"_./:"
 msgstr "Это поле должно содержать только буквы, символы Unicode, цифры и -_./:"
 
 #: src/views/dashboard/NginxDashBoard.vue:150
@@ -5019,8 +5028,8 @@ msgid ""
 "This module provides Nginx request statistics, connection count, etc. data. "
 "After enabling it, you can view performance statistics"
 msgstr ""
-"Этот модуль предоставляет статистику запросов Nginx, количество соединений "
-"и другие данные. После включения вы сможете просматривать статистику "
+"Этот модуль предоставляет статистику запросов Nginx, количество соединений и "
+"другие данные. После включения вы сможете просматривать статистику "
 "производительности."
 
 #: src/views/certificate/components/RemoveCert.vue:104
@@ -5036,8 +5045,8 @@ msgid ""
 "This token will only be shown once and cannot be retrieved later. Please "
 "make sure to save it in a secure location."
 msgstr ""
-"Этот токен будет показан только один раз и не может быть восстановлен "
-"позже. Пожалуйста, сохраните его в надежном месте."
+"Этот токен будет показан только один раз и не может быть восстановлен позже. "
+"Пожалуйста, сохраните его в надежном месте."
 
 #: src/constants/form_errors.ts:4 src/language/curd.ts:42
 msgid "This value is already taken"
@@ -5049,8 +5058,8 @@ msgid ""
 "This will restore all Nginx configuration files. Nginx will restart after "
 "the restoration is complete."
 msgstr ""
-"Это восстановит все конфигурационные файлы Nginx. Nginx перезапустится "
-"после завершения восстановления."
+"Это восстановит все конфигурационные файлы Nginx. Nginx перезапустится после "
+"завершения восстановления."
 
 #: src/components/SystemRestore/SystemRestoreContent.vue:238
 #: src/components/SystemRestore/SystemRestoreContent.vue:315
@@ -5062,7 +5071,8 @@ msgstr ""
 "после завершения восстановления."
 
 #: src/views/environments/list/BatchUpgrader.vue:182
-msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
+msgid ""
+"This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
 msgstr ""
 "Это обновит или переустановит интерфейс Nginx на %{nodeNames} до версии "
 "%{version}."
@@ -5112,15 +5122,15 @@ msgid ""
 "and restart Nginx UI."
 msgstr ""
 "Для обеспечения безопасности конфигурацию WebAuthn нельзя добавить через "
-"интерфейс. Пожалуйста, вручную настройте следующее в файле конфигурации "
-"app.ini и перезапустите Nginx UI."
+"интерфейс. Пожалуйста, вручную настройте следующее в файле конфигурации app."
+"ini и перезапустите Nginx UI."
 
 #: src/views/site/site_edit/components/Cert/IssueCert.vue:34
 #: src/views/site/site_edit/components/EnableTLS/EnableTLS.vue:15
 msgid ""
 "To make sure the certification auto-renewal can work normally, we need to "
-"add a location which can proxy the request from authority to backend, and "
-"we need to save this file and reload the Nginx. Are you sure you want to "
+"add a location which can proxy the request from authority to backend, and we "
+"need to save this file and reload the Nginx. Are you sure you want to "
 "continue?"
 msgstr ""
 "Чтобы убедиться, что автоматическое обновление сертификата может работать "
@@ -5134,9 +5144,9 @@ msgid ""
 "provide an OpenAI-compatible API endpoint, so just set the baseUrl to your "
 "local API."
 msgstr ""
-"Чтобы использовать локальную большую модель, разверните её с помощью "
-"ollama, vllm или lmdeploy. Они предоставляют API-эндпоинт, совместимый с "
-"OpenAI, поэтому просто установите baseUrl на ваш локальный API."
+"Чтобы использовать локальную большую модель, разверните её с помощью ollama, "
+"vllm или lmdeploy. Они предоставляют API-эндпоинт, совместимый с OpenAI, "
+"поэтому просто установите baseUrl на ваш локальный API."
 
 #: src/views/dashboard/NginxDashBoard.vue:55
 msgid "Toggle failed"
@@ -5245,8 +5255,8 @@ msgid "Updated at"
 msgstr "Обновлено в"
 
 #: src/routes/modules/system.ts:26
-#: src/views/environments/list/Environment.vue:107
-#: src/views/environments/list/Environment.vue:115
+#: src/views/environments/list/Environment.vue:108
+#: src/views/environments/list/Environment.vue:116
 #: src/views/system/Upgrade.vue:154 src/views/system/Upgrade.vue:159
 msgid "Upgrade"
 msgstr "Обновление"
@@ -5276,7 +5286,7 @@ msgstr "Загрузить папки"
 msgid "Upstream"
 msgstr "Восходящий поток"
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:177
+#: src/components/NgxConfigEditor/NgxUpstream.vue:184
 msgid "Upstream Name"
 msgstr "Имя Upstream"
 
@@ -5406,11 +5416,11 @@ msgstr ""
 
 #: src/views/site/site_edit/components/Cert/ObtainCert.vue:140
 msgid ""
-"We will remove the HTTPChallenge configuration from this file and reload "
-"the Nginx. Are you sure you want to continue?"
+"We will remove the HTTPChallenge configuration from this file and reload the "
+"Nginx. Are you sure you want to continue?"
 msgstr ""
-"Мы удалим конфигурацию HTTPChallenge из этого файла и перезагрузим Nginx. "
-"Вы уверены, что хотите продолжить?"
+"Мы удалим конфигурацию HTTPChallenge из этого файла и перезагрузим Nginx. Вы "
+"уверены, что хотите продолжить?"
 
 #: src/views/preference/tabs/AuthSettings.vue:65
 msgid "Webauthn"
@@ -5443,8 +5453,8 @@ msgid ""
 "Pebble as CA."
 msgstr ""
 "При включении Nginx UI будет автоматически перерегистрировать пользователей "
-"при запуске. Обычно не включайте эту функцию, если только вы не находитесь "
-"в среде разработки и используете Pebble в качестве CA."
+"при запуске. Обычно не включайте эту функцию, если только вы не находитесь в "
+"среде разработки и используете Pebble в качестве CA."
 
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:61
 #: src/views/stream/components/RightPanel/Basic.vue:98
@@ -5452,8 +5462,8 @@ msgid ""
 "When you enable/disable, delete, or save this site, the nodes set in the "
 "Node Group and the nodes selected below will be synchronized."
 msgstr ""
-"При включении/отключении, удалении или сохранении этого сайта узлы, "
-"заданные в Группе узлов, и узлы, выбранные ниже, будут синхронизированы."
+"При включении/отключении, удалении или сохранении этого сайта узлы, заданные "
+"в Группе узлов, и узлы, выбранные ниже, будут синхронизированы."
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:140
 msgid ""
@@ -5511,8 +5521,8 @@ msgstr "Да"
 
 #: src/views/terminal/Terminal.vue:132
 msgid ""
-"You are accessing this terminal over an insecure HTTP connection on a "
-"non-localhost domain. This may expose sensitive information."
+"You are accessing this terminal over an insecure HTTP connection on a non-"
+"localhost domain. This may expose sensitive information."
 msgstr ""
 "Вы обращаетесь к этому терминалу через небезопасное HTTP-соединение в "
 "домене, отличном от localhost. Это может раскрыть конфиденциальную "
@@ -5538,10 +5548,12 @@ msgstr "Теперь вы можете закрыть это диалогово
 msgid ""
 "You have not configured the settings of Webauthn, so you cannot add a "
 "passkey."
-msgstr "Вы не настроили параметры WebAuthn, поэтому не можете добавить ключ доступа."
+msgstr ""
+"Вы не настроили параметры WebAuthn, поэтому не можете добавить ключ доступа."
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:81
-msgid "You have not enabled 2FA yet. Please enable 2FA to generate recovery codes."
+msgid ""
+"You have not enabled 2FA yet. Please enable 2FA to generate recovery codes."
 msgstr ""
 "Вы еще не включили двухфакторную аутентификацию. Пожалуйста, включите её, "
 "чтобы сгенерировать коды восстановления."
@@ -5628,8 +5640,8 @@ msgstr "Ваши ключи доступа"
 
 #~ msgid ""
 #~ "Check if /var/run/docker.sock exists. If you are using Nginx UI Official "
-#~ "Docker Image, please make sure the docker socket is mounted like this: `-v "
-#~ "/var/run/docker.sock:/var/run/docker.sock`."
+#~ "Docker Image, please make sure the docker socket is mounted like this: `-"
+#~ "v /var/run/docker.sock:/var/run/docker.sock`."
 #~ msgstr ""
 #~ "Проверьте, существует ли /var/run/docker.sock. Если вы используете "
 #~ "официальный образ Docker Nginx UI, убедитесь, что сокет Docker подключен "
@@ -5675,7 +5687,8 @@ msgstr "Ваши ключи доступа"
 #~ msgstr "Ошибка формата %{msg}"
 
 #~ msgid "Failed to save, syntax error(s) was detected in the configuration."
-#~ msgstr "Не удалось сохранить, обнаружены синтаксические ошибки в конфигурации."
+#~ msgstr ""
+#~ "Не удалось сохранить, обнаружены синтаксические ошибки в конфигурации."
 
 #, fuzzy
 #~ msgid "Access Token"
@@ -5738,13 +5751,16 @@ msgstr "Ваши ключи доступа"
 #~ "Синхронизация конфигурации %{cert_name} с %{env_name} не удалась, "
 #~ "пожалуйста, обновите удаленный Nginx UI до последней версии"
 
-#~ msgid "Rename %{orig_path} to %{new_path} on %{env_name} failed, response: %{resp}"
-#~ msgstr ""
-#~ "Переименование %{orig_path} в %{new_path} на %{env_name} не удалось, ответ: "
+#~ msgid ""
+#~ "Rename %{orig_path} to %{new_path} on %{env_name} failed, response: "
 #~ "%{resp}"
+#~ msgstr ""
+#~ "Переименование %{orig_path} в %{new_path} на %{env_name} не удалось, "
+#~ "ответ: %{resp}"
 
 #, fuzzy
-#~ msgid "Rename Site %{site} to %{new_site} on %{node} error, response: %{resp}"
+#~ msgid ""
+#~ "Rename Site %{site} to %{new_site} on %{node} error, response: %{resp}"
 #~ msgstr "Переименование %{orig_path} в %{new_path} на %{env_name} успешно"
 
 #, fuzzy
@@ -5760,22 +5776,23 @@ msgstr "Ваши ключи доступа"
 #~ "Синхронизация сертификата %{cert_name} с %{env_name} не удалась, "
 #~ "пожалуйста, обновите удаленный интерфейс Nginx до последней версии"
 
-#~ msgid "Sync Certificate %{cert_name} to %{env_name} failed, response: %{resp}"
+#~ msgid ""
+#~ "Sync Certificate %{cert_name} to %{env_name} failed, response: %{resp}"
 #~ msgstr ""
 #~ "Синхронизация сертификата %{cert_name} с %{env_name} не удалась, ответ: "
 #~ "%{resp}"
 
 #~ msgid "Sync config %{config_name} to %{env_name} failed, response: %{resp}"
 #~ msgstr ""
-#~ "Синхронизация конфигурации %{config_name} с %{env_name} не удалась, ответ: "
-#~ "%{resp}"
+#~ "Синхронизация конфигурации %{config_name} с %{env_name} не удалась, "
+#~ "ответ: %{resp}"
 
 #~ msgid "File"
 #~ msgstr "Файл"
 
 #~ msgid ""
-#~ "If you lose your mobile phone, you can use the recovery code to reset your "
-#~ "2FA."
+#~ "If you lose your mobile phone, you can use the recovery code to reset "
+#~ "your 2FA."
 #~ msgstr ""
 #~ "Если вы потеряете свой мобильный телефон, вы можете использовать код "
 #~ "восстановления для сброса 2FA."
@@ -5789,10 +5806,11 @@ msgstr "Ваши ключи доступа"
 #~ msgid "Server error"
 #~ msgstr "Ошибка сервера"
 
-#~ msgid "The recovery code is only displayed once, please save it in a safe place."
+#~ msgid ""
+#~ "The recovery code is only displayed once, please save it in a safe place."
 #~ msgstr ""
-#~ "Код восстановления отображается только один раз, пожалуйста, сохраните его "
-#~ "в безопасном месте."
+#~ "Код восстановления отображается только один раз, пожалуйста, сохраните "
+#~ "его в безопасном месте."
 
 #~ msgid "Too many login failed attempts, please try again later"
 #~ msgstr "Слишком много неудачных попыток входа, попробуйте позже"

+ 207 - 180
app/src/language/tr_TR/app.po

@@ -5,22 +5,24 @@ msgstr ""
 "POT-Creation-Date: \n"
 "PO-Revision-Date: 2025-04-08 18:26+0000\n"
 "Last-Translator: Ulaş <ozturkmuratulas@hotmail.com>\n"
-"Language-Team: Turkish "
-"<https://weblate.nginxui.com/projects/nginx-ui/frontend/tr/>\n"
+"Language-Team: Turkish <https://weblate.nginxui.com/projects/nginx-ui/"
+"frontend/tr/>\n"
 "Language: tr_TR\n"
 "MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=utf-8\n"
+"Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=n != 1;\n"
 "X-Generator: Weblate 5.10.4\n"
 
 #: src/language/generate.ts:31
 msgid "[Nginx UI] ACME User: %{name}, Email: %{email}, CA Dir: %{caDir}"
-msgstr "[Nginx UI] ACME Kullanıcısı: %{name}, E-posta: %{email}, CA Dizini: %{caDir}"
+msgstr ""
+"[Nginx UI] ACME Kullanıcısı: %{name}, E-posta: %{email}, CA Dizini: %{caDir}"
 
 #: src/language/generate.ts:32
 msgid "[Nginx UI] Backing up current certificate for later revocation"
-msgstr "[Nginx UI] Geçerli sertifika daha sonra iptal edilmek üzere yedekleniyor"
+msgstr ""
+"[Nginx UI] Geçerli sertifika daha sonra iptal edilmek üzere yedekleniyor"
 
 #: src/language/generate.ts:33
 msgid "[Nginx UI] Certificate renewed successfully"
@@ -31,14 +33,16 @@ msgid "[Nginx UI] Certificate successfully revoked"
 msgstr "[Nginx UI] Sertifika başarıyla iptal edildi"
 
 #: src/language/generate.ts:35
-msgid "[Nginx UI] Certificate was used for server, reloading server TLS certificate"
+msgid ""
+"[Nginx UI] Certificate was used for server, reloading server TLS certificate"
 msgstr ""
 "[Nginx UI] Sertifika sunucu için kullanıldı, sunucu TLS sertifikası yeniden "
 "yükleniyor"
 
 #: src/language/generate.ts:36
 msgid "[Nginx UI] Creating client facilitates communication with the CA server"
-msgstr "[Nginx UI] CA sunucusu ile iletişimi kolaylaştırmak için istemci oluşturma"
+msgstr ""
+"[Nginx UI] CA sunucusu ile iletişimi kolaylaştırmak için istemci oluşturma"
 
 #: src/language/generate.ts:37
 msgid "[Nginx UI] Environment variables cleaned"
@@ -159,10 +163,10 @@ msgid "Actual worker to configured ratio"
 msgstr "Gerçek çalışanın yapılandırılmışa oranı"
 
 #: src/components/NgxConfigEditor/NgxServer.vue:112
-#: src/components/NgxConfigEditor/NgxUpstream.vue:159 src/language/curd.ts:19
+#: src/components/NgxConfigEditor/NgxUpstream.vue:166 src/language/curd.ts:19
 #: src/views/preference/tabs/CertSettings.vue:45
 #: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:94
-#: src/views/stream/StreamList.vue:101
+#: src/views/stream/StreamList.vue:102
 msgid "Add"
 msgstr "Ekle"
 
@@ -189,7 +193,7 @@ msgstr "Konum ekle"
 msgid "Add Site"
 msgstr "Site Ekle"
 
-#: src/views/stream/StreamList.vue:138
+#: src/views/stream/StreamList.vue:139
 msgid "Add Stream"
 msgstr "Akış Ekle"
 
@@ -208,7 +212,8 @@ msgstr "Gelişmiş Mod"
 
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:99
 msgid "Afterwards, refresh this page and click add passkey again."
-msgstr "Daha sonra bu sayfayı yenileyin ve tekrar parola anahtarı ekle'ye tıklayın."
+msgstr ""
+"Daha sonra bu sayfayı yenileyin ve tekrar parola anahtarı ekle'ye tıklayın."
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:115
 msgid "All"
@@ -277,7 +282,7 @@ msgid "Are you sure you want to delete permanently?"
 msgstr "Kalıcı olarak silmek istediğinizden emin misiniz?"
 
 #: src/language/curd.ts:25 src/views/site/site_list/SiteList.vue:100
-#: src/views/stream/StreamList.vue:121
+#: src/views/stream/StreamList.vue:122
 msgid "Are you sure you want to delete?"
 msgstr "Silmek istediğine emin misin?"
 
@@ -419,7 +424,8 @@ msgstr "Yedekleme"
 
 #: src/components/SystemRestore/SystemRestoreContent.vue:155
 msgid "Backup file integrity check failed, it may have been tampered with"
-msgstr "Yedek dosya bütünlük kontrolü başarısız oldu, dosya değiştirilmiş olabilir"
+msgstr ""
+"Yedek dosya bütünlük kontrolü başarısız oldu, dosya değiştirilmiş olabilir"
 
 #: src/constants/errors/backup.ts:41
 msgid "Backup file not found: {0}"
@@ -455,13 +461,15 @@ msgstr "Yedekleme Zamanlaması"
 
 #: src/components/Notification/notifications.ts:38
 msgid "Backup task %{backup_name} completed successfully, file: %{file_path}"
-msgstr "Yedekleme görevi %{backup_name} başarıyla tamamlandı, dosya: %{file_path}"
+msgstr ""
+"Yedekleme görevi %{backup_name} başarıyla tamamlandı, dosya: %{file_path}"
 
 #: src/components/Notification/notifications.ts:34
-msgid "Backup task %{backup_name} failed during storage upload, error: %{error}"
+msgid ""
+"Backup task %{backup_name} failed during storage upload, error: %{error}"
 msgstr ""
-"Yedekleme görevi %{backup_name} depolama yüklemesi sırasında başarısız "
-"oldu, hata: %{error}"
+"Yedekleme görevi %{backup_name} depolama yüklemesi sırasında başarısız oldu, "
+"hata: %{error}"
 
 #: src/components/Notification/notifications.ts:30
 msgid "Backup task %{backup_name} failed to execute, error: %{error}"
@@ -492,7 +500,7 @@ msgid "Base information"
 msgstr "Temel bilgiler"
 
 #: src/views/config/ConfigEditor.vue:300
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:31
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:32
 #: src/views/stream/components/RightPanel/RightPanel.vue:20
 msgid "Basic"
 msgstr "Temel"
@@ -520,7 +528,8 @@ msgstr "Toplu Yükseltme"
 
 #: src/language/curd.ts:36
 msgid "Belows are selected items that you want to batch modify"
-msgstr "Aşağıda toplu olarak değiştirmek istediğiniz seçili öğeler bulunmaktadır"
+msgstr ""
+"Aşağıda toplu olarak değiştirmek istediğiniz seçili öğeler bulunmaktadır"
 
 #: src/constants/errors/nginx.ts:3
 msgid "Block is nil"
@@ -736,7 +745,7 @@ msgstr "Değişen Dosya Yolu"
 msgid "Channel"
 msgstr "Kanal"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:41
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:42
 #: src/views/stream/components/RightPanel/RightPanel.vue:23
 msgid "Chat"
 msgstr "Sohbet"
@@ -753,25 +762,25 @@ msgstr "Tekrar kontrol et"
 #: src/language/generate.ts:6
 msgid ""
 "Check if /var/run/docker.sock exists. If you are using Nginx UI Official "
-"Docker Image, please make sure the docker socket is mounted like this: `-v "
-"/var/run/docker.sock:/var/run/docker.sock`. Nginx UI official image uses "
-"/var/run/docker.sock to communicate with the host Docker Engine via Docker "
-"Client API. This feature is used to control Nginx in another container and "
-"perform container replacement rather than binary replacement during OTA "
-"upgrades of Nginx UI to ensure container dependencies are also upgraded. If "
-"you don't need this feature, please add the environment variable "
+"Docker Image, please make sure the docker socket is mounted like this: `-v /"
+"var/run/docker.sock:/var/run/docker.sock`. Nginx UI official image uses /var/"
+"run/docker.sock to communicate with the host Docker Engine via Docker Client "
+"API. This feature is used to control Nginx in another container and perform "
+"container replacement rather than binary replacement during OTA upgrades of "
+"Nginx UI to ensure container dependencies are also upgraded. If you don't "
+"need this feature, please add the environment variable "
 "NGINX_UI_IGNORE_DOCKER_SOCKET=true to the container."
 msgstr ""
 "/var/run/docker.sock dosyasının var olup olmadığını kontrol edin. Nginx UI "
 "Resmi Docker Image'ını kullanıyorsanız, docker soketinin şu şekilde "
 "bağlandığından emin olun: `-v /var/run/docker.sock:/var/run/docker.sock`. "
 "Nginx UI resmi imajı, Docker Client API üzerinden ana bilgisayarın Docker "
-"Engine'i ile iletişim kurmak için /var/run/docker.sock kullanır. Bu "
-"özellik, Nginx UI'nin OTA güncellemeleri sırasında ikili dosya değişimi "
-"yerine konteyner değişimi yaparak Nginx'i başka bir konteynerde kontrol "
-"etmek ve konteyner bağımlılıklarının da güncellenmesini sağlamak için "
-"kullanılır. Bu özelliğe ihtiyacınız yoksa, konteynere "
-"NGINX_UI_IGNORE_DOCKER_SOCKET=true ortam değişkenini ekleyin."
+"Engine'i ile iletişim kurmak için /var/run/docker.sock kullanır. Bu özellik, "
+"Nginx UI'nin OTA güncellemeleri sırasında ikili dosya değişimi yerine "
+"konteyner değişimi yaparak Nginx'i başka bir konteynerde kontrol etmek ve "
+"konteyner bağımlılıklarının da güncellenmesini sağlamak için kullanılır. Bu "
+"özelliğe ihtiyacınız yoksa, konteynere NGINX_UI_IGNORE_DOCKER_SOCKET=true "
+"ortam değişkenini ekleyin."
 
 #: src/components/SelfCheck/tasks/frontend/https-check.ts:14
 msgid ""
@@ -784,19 +793,19 @@ msgstr ""
 
 #: src/language/generate.ts:8
 msgid ""
-"Check if the nginx access log path exists. By default, this path is "
-"obtained from 'nginx -V'. If it cannot be obtained or the obtained path "
-"does not point to a valid, existing file, an error will be reported. In "
-"this case, you need to modify the configuration file to specify the access "
-"log path.Refer to the docs for more details: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#accesslogpath"
+"Check if the nginx access log path exists. By default, this path is obtained "
+"from 'nginx -V'. If it cannot be obtained or the obtained path does not "
+"point to a valid, existing file, an error will be reported. In this case, "
+"you need to modify the configuration file to specify the access log path."
+"Refer to the docs for more details: https://nginxui.com/zh_CN/guide/config-"
+"nginx.html#accesslogpath"
 msgstr ""
 "Nginx erişim günlüğü yolunun var olup olmadığını kontrol edin. Varsayılan "
 "olarak bu yol 'nginx -V' komutu ile alınır. Eğer alınamazsa veya alınan yol "
 "geçerli, mevcut bir dosyayı işaret etmiyorsa bir hata bildirilecektir. Bu "
 "durumda, erişim günlüğü yolunu belirtmek için yapılandırma dosyasını "
-"değiştirmeniz gerekmektedir. Daha fazla bilgi için belgelere bakın: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#accesslogpath"
+"değiştirmeniz gerekmektedir. Daha fazla bilgi için belgelere bakın: https://"
+"nginxui.com/zh_CN/guide/config-nginx.html#accesslogpath"
 
 #: src/language/generate.ts:9
 msgid "Check if the nginx configuration directory exists"
@@ -811,30 +820,30 @@ msgid ""
 "Check if the nginx error log path exists. By default, this path is obtained "
 "from 'nginx -V'. If it cannot be obtained or the obtained path does not "
 "point to a valid, existing file, an error will be reported. In this case, "
-"you need to modify the configuration file to specify the error log "
-"path.Refer to the docs for more details: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#errorlogpath"
+"you need to modify the configuration file to specify the error log path."
+"Refer to the docs for more details: https://nginxui.com/zh_CN/guide/config-"
+"nginx.html#errorlogpath"
 msgstr ""
 "Nginx hata günlüğü yolunun var olup olmadığını kontrol edin. Varsayılan "
 "olarak bu yol 'nginx -V' komutuyla alınır. Eğer alınamazsa veya alınan yol "
 "geçerli, mevcut bir dosyayı işaret etmiyorsa, bir hata bildirilecektir. Bu "
-"durumda, yapılandırma dosyasını değiştirerek hata günlüğü yolunu "
-"belirtmeniz gerekir. Daha fazla ayrıntı için belgelere bakın: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#errorlogpath"
+"durumda, yapılandırma dosyasını değiştirerek hata günlüğü yolunu belirtmeniz "
+"gerekir. Daha fazla ayrıntı için belgelere bakın: https://nginxui.com/zh_CN/"
+"guide/config-nginx.html#errorlogpath"
 
 #: src/language/generate.ts:7
 msgid ""
 "Check if the nginx PID path exists. By default, this path is obtained from "
 "'nginx -V'. If it cannot be obtained, an error will be reported. In this "
 "case, you need to modify the configuration file to specify the Nginx PID "
-"path.Refer to the docs for more details: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#pidpath"
+"path.Refer to the docs for more details: https://nginxui.com/zh_CN/guide/"
+"config-nginx.html#pidpath"
 msgstr ""
-"Nginx PID yolunun var olup olmadığını kontrol edin. Varsayılan olarak bu "
-"yol 'nginx -V' komutuyla alınır. Alınamazsa bir hata bildirilir. Bu "
-"durumda, yapılandırma dosyasını değiştirerek Nginx PID yolunu belirtmeniz "
-"gerekir. Daha fazla ayrıntı için belgelere bakın: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#pidpath"
+"Nginx PID yolunun var olup olmadığını kontrol edin. Varsayılan olarak bu yol "
+"'nginx -V' komutuyla alınır. Alınamazsa bir hata bildirilir. Bu durumda, "
+"yapılandırma dosyasını değiştirerek Nginx PID yolunu belirtmeniz gerekir. "
+"Daha fazla ayrıntı için belgelere bakın: https://nginxui.com/zh_CN/guide/"
+"config-nginx.html#pidpath"
 
 #: src/language/generate.ts:12
 msgid "Check if the nginx.conf includes the conf.d directory"
@@ -843,8 +852,7 @@ msgstr "nginx.conf dosyasının conf.d dizinini içerip içermediğini kontrol e
 #: src/language/generate.ts:13
 msgid "Check if the nginx.conf includes the sites-enabled directory"
 msgstr ""
-"nginx.conf dosyasının sites-enabled dizinini içerip içermediğini kontrol "
-"edin"
+"nginx.conf dosyasının sites-enabled dizinini içerip içermediğini kontrol edin"
 
 #: src/language/generate.ts:14
 msgid "Check if the nginx.conf includes the streams-enabled directory"
@@ -862,8 +870,8 @@ msgstr ""
 
 #: src/language/generate.ts:16
 msgid ""
-"Check if the streams-available and streams-enabled directories are under "
-"the nginx configuration directory"
+"Check if the streams-available and streams-enabled directories are under the "
+"nginx configuration directory"
 msgstr ""
 "streams-available ve streams-enabled dizinlerinin nginx yapılandırma dizini "
 "altında olup olmadığını kontrol edin"
@@ -992,7 +1000,7 @@ msgstr "Yapılandırma giriş dosyası mevcut değil"
 msgid "Config path is empty"
 msgstr "Yapılandırma yolu boş"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:37
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:38
 msgid "Config Template"
 msgstr "Yapılandırma Şablonu"
 
@@ -1083,14 +1091,13 @@ msgstr "CPU Kullanımı"
 #: src/views/dashboard/components/ResourceUsageCard.vue:38
 msgid "CPU usage is relatively high, consider optimizing Nginx configuration"
 msgstr ""
-"CPU kullanımı nispeten yüksek, Nginx yapılandırmasını optimize etmeyi "
-"düşünün"
+"CPU kullanımı nispeten yüksek, Nginx yapılandırmasını optimize etmeyi düşünün"
 
 #: src/views/dashboard/ServerAnalytic.vue:195
 msgid "CPU:"
 msgstr "CPU:"
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:170
+#: src/components/NgxConfigEditor/NgxUpstream.vue:177
 msgid "Create"
 msgstr "Oluştur"
 
@@ -1231,10 +1238,10 @@ msgstr ""
 "proxy_cache:10m"
 
 #: src/components/NgxConfigEditor/NgxServer.vue:78
-#: src/components/NgxConfigEditor/NgxUpstream.vue:129 src/language/curd.ts:9
+#: src/components/NgxConfigEditor/NgxUpstream.vue:134 src/language/curd.ts:9
 #: src/views/certificate/components/RemoveCert.vue:88
 #: src/views/site/site_list/SiteList.vue:109
-#: src/views/stream/StreamList.vue:130
+#: src/views/stream/StreamList.vue:131
 msgid "Delete"
 msgstr "Sil"
 
@@ -1398,11 +1405,13 @@ msgstr "%{node} üzerindeki %{name} sitesi başarıyla devre dışı bırakıld
 
 #: src/components/Notification/notifications.ts:118
 msgid "Disable site %{name} maintenance on %{node} failed"
-msgstr "%{node} üzerindeki %{name} sitesi bakımını devre dışı bırakma başarısız oldu"
+msgstr ""
+"%{node} üzerindeki %{name} sitesi bakımını devre dışı bırakma başarısız oldu"
 
 #: src/components/Notification/notifications.ts:122
 msgid "Disable site %{name} maintenance on %{node} successfully"
-msgstr "%{name} sitesinin bakımı %{node} üzerinde başarıyla devre dışı bırakıldı"
+msgstr ""
+"%{name} sitesinin bakımı %{node} üzerinde başarıyla devre dışı bırakıldı"
 
 #: src/components/Notification/notifications.ts:150
 msgid "Disable stream %{name} from %{node} failed"
@@ -1541,7 +1550,7 @@ msgstr ""
 #: src/views/site/site_list/SiteDuplicate.vue:72
 #: src/views/site/site_list/SiteList.vue:95
 #: src/views/stream/components/StreamDuplicate.vue:64
-#: src/views/stream/StreamList.vue:116
+#: src/views/stream/StreamList.vue:117
 msgid "Duplicate"
 msgstr "Kopyala"
 
@@ -1722,7 +1731,7 @@ msgstr "Ortam değişkenleri temizlendi"
 
 #: src/routes/modules/environments.ts:11
 #: src/views/dashboard/Environments.vue:83
-#: src/views/environments/list/Environment.vue:81
+#: src/views/environments/list/Environment.vue:82
 msgid "Environments"
 msgstr "Ortamlar"
 
@@ -2244,7 +2253,8 @@ msgstr "Gizle"
 
 #: src/views/dashboard/components/PerformanceStatisticsCard.vue:87
 msgid "Higher value means better connection reuse"
-msgstr "Daha yüksek bir değer, daha iyi bağlantı yeniden kullanımı anlamına gelir"
+msgstr ""
+"Daha yüksek bir değer, daha iyi bağlantı yeniden kullanımı anlamına gelir"
 
 #: src/views/config/ConfigEditor.vue:260
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
@@ -2591,7 +2601,7 @@ msgstr "Dinliyor"
 msgid "Load Average:"
 msgstr "Yük Ortalaması:"
 
-#: src/views/environments/list/Environment.vue:88
+#: src/views/environments/list/Environment.vue:89
 msgid "Load from settings"
 msgstr "Ayarlar'dan yükle"
 
@@ -2652,12 +2662,12 @@ msgstr "Günlük"
 #: src/language/generate.ts:20
 msgid ""
 "Log file %{log_path} is not a regular file. If you are using nginx-ui in "
-"docker container, please refer to "
-"https://nginxui.com/zh_CN/guide/config-nginx-log.html for more information."
+"docker container, please refer to https://nginxui.com/zh_CN/guide/config-"
+"nginx-log.html for more information."
 msgstr ""
 "Günlük dosyası %{log_path} normal bir dosya değil. Docker konteynerinde "
-"nginx-ui kullanıyorsanız, daha fazla bilgi için "
-"https://nginxui.com/zh_CN/guide/config-nginx-log.html adresine bakın."
+"nginx-ui kullanıyorsanız, daha fazla bilgi için https://nginxui.com/zh_CN/"
+"guide/config-nginx-log.html adresine bakın."
 
 #: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:72
 msgid "Log List"
@@ -2681,19 +2691,19 @@ msgstr "Logrotate"
 
 #: src/views/preference/tabs/LogrotateSettings.vue:13
 msgid ""
-"Logrotate, by default, is enabled in most mainstream Linux distributions "
-"for users who install Nginx UI on the host machine, so you don't need to "
-"modify the parameters on this page. For users who install Nginx UI using "
-"Docker containers, you can manually enable this option. The crontab task "
-"scheduler of Nginx UI will execute the logrotate command at the interval "
-"you set in minutes."
+"Logrotate, by default, is enabled in most mainstream Linux distributions for "
+"users who install Nginx UI on the host machine, so you don't need to modify "
+"the parameters on this page. For users who install Nginx UI using Docker "
+"containers, you can manually enable this option. The crontab task scheduler "
+"of Nginx UI will execute the logrotate command at the interval you set in "
+"minutes."
 msgstr ""
-"Logrotate, varsayılan olarak, Nginx UI'yi ana makineye yükleyen "
-"kullanıcılar için çoğu ana akım Linux dağıtımında etkinleştirilmiştir, bu "
-"yüzden bu sayfadaki parametreleri değiştirmenize gerek yoktur. Nginx UI'yi "
-"Docker konteynerlerini kullanarak yükleyen kullanıcılar, bu seçeneği manuel "
-"olarak etkinleştirebilir. Nginx UI'nin crontab görev zamanlayıcısı, "
-"belirlediğiniz dakika aralığında logrotate komutunu çalıştıracaktır."
+"Logrotate, varsayılan olarak, Nginx UI'yi ana makineye yükleyen kullanıcılar "
+"için çoğu ana akım Linux dağıtımında etkinleştirilmiştir, bu yüzden bu "
+"sayfadaki parametreleri değiştirmenize gerek yoktur. Nginx UI'yi Docker "
+"konteynerlerini kullanarak yükleyen kullanıcılar, bu seçeneği manuel olarak "
+"etkinleştirebilir. Nginx UI'nin crontab görev zamanlayıcısı, belirlediğiniz "
+"dakika aralığında logrotate komutunu çalıştıracaktır."
 
 #: src/views/site/components/SiteStatusSelect.vue:165
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:68
@@ -2887,7 +2897,7 @@ msgstr "Her ayın %{day} günü %{time} saatinde"
 msgid "Multi-line Directive"
 msgstr "Çok Satırlı Yönergeler"
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:182
+#: src/components/NgxConfigEditor/NgxUpstream.vue:189
 #: src/views/backup/AutoBackup/AutoBackup.vue:11
 #: src/views/certificate/ACMEUser.vue:11
 #: src/views/certificate/CertificateEditor.vue:162
@@ -2905,7 +2915,7 @@ msgstr "Çok Satırlı Yönergeler"
 #: src/views/stream/columns.tsx:12
 #: src/views/stream/components/RightPanel/Basic.vue:72
 #: src/views/stream/components/StreamDuplicate.vue:71
-#: src/views/stream/StreamList.vue:143
+#: src/views/stream/StreamList.vue:144
 msgid "Name"
 msgstr "İsim"
 
@@ -3136,8 +3146,8 @@ msgstr "Nginx UI yapılandırması geri yüklendi"
 
 #: src/components/SystemRestore/SystemRestoreContent.vue:336
 msgid ""
-"Nginx UI configuration has been restored and will restart automatically in "
-"a few seconds."
+"Nginx UI configuration has been restored and will restart automatically in a "
+"few seconds."
 msgstr ""
 "Nginx UI yapılandırması geri yüklendi ve birkaç saniye içinde otomatik "
 "olarak yeniden başlatılacak."
@@ -3163,7 +3173,7 @@ msgstr "Nginx.conf, streams-enabled dizinini içerir"
 #: src/views/notification/Notification.vue:38
 #: src/views/preference/tabs/AuthSettings.vue:132
 #: src/views/preference/tabs/CertSettings.vue:73
-#: src/views/site/site_list/SiteList.vue:98 src/views/stream/StreamList.vue:119
+#: src/views/site/site_list/SiteList.vue:98 src/views/stream/StreamList.vue:120
 msgid "No"
 msgstr "Hayır"
 
@@ -3298,7 +3308,7 @@ msgid "Off"
 msgstr "Kapalı"
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:159
-#: src/components/NgxConfigEditor/NgxUpstream.vue:145
+#: src/components/NgxConfigEditor/NgxUpstream.vue:151
 #: src/components/NodeSelector/NodeSelector.vue:109
 #: src/components/ProxyTargets/ProxyTargets.vue:43
 #: src/views/dashboard/Environments.vue:107
@@ -3319,7 +3329,7 @@ msgstr "Çevrimdışı"
 #: src/views/site/site_list/SiteList.vue:99
 #: src/views/stream/components/RightPanel/Basic.vue:48
 #: src/views/stream/components/StreamStatusSelect.vue:60
-#: src/views/stream/StreamList.vue:120
+#: src/views/stream/StreamList.vue:121
 msgid "OK"
 msgstr "Tamam"
 
@@ -3522,8 +3532,8 @@ msgid ""
 "Please enter a name for the passkey you wish to create and click the OK "
 "button below."
 msgstr ""
-"Oluşturmak istediğiniz anahtar için bir ad girin ve aşağıdaki Tamam "
-"butonuna tıklayın."
+"Oluşturmak istediğiniz anahtar için bir ad girin ve aşağıdaki Tamam butonuna "
+"tıklayın."
 
 #: src/components/PortScanner/PortScannerCompact.vue:85
 msgid "Please enter a valid port range"
@@ -3554,7 +3564,8 @@ msgstr "Lütfen gerekli S3 yapılandırma alanlarını doldurun"
 msgid ""
 "Please fill in the API authentication credentials provided by your DNS "
 "provider."
-msgstr "Lütfen DNS sağlayıcınız tarafından sağlanan API kimlik bilgilerini doldurun."
+msgstr ""
+"Lütfen DNS sağlayıcınız tarafından sağlanan API kimlik bilgilerini doldurun."
 
 #: src/components/AutoCertForm/AutoCertForm.vue:56
 msgid ""
@@ -3568,11 +3579,10 @@ msgstr ""
 #: src/components/Notification/notifications.ts:182
 #: src/language/constants.ts:59
 msgid ""
-"Please generate new recovery codes in the preferences immediately to "
-"prevent lockout."
+"Please generate new recovery codes in the preferences immediately to prevent "
+"lockout."
 msgstr ""
-"Kilitlenmeyi önlemek için tercihlerden hemen yeni kurtarma kodları "
-"oluşturun."
+"Kilitlenmeyi önlemek için tercihlerden hemen yeni kurtarma kodları oluşturun."
 
 #: src/views/config/components/Rename.vue:65
 #: src/views/config/ConfigEditor.vue:308
@@ -3617,7 +3627,8 @@ msgid "Please log in."
 msgstr "Lütfen giriş yapın."
 
 #: src/views/certificate/DNSCredential.vue:61
-msgid "Please note that the unit of time configurations below are all in seconds."
+msgid ""
+"Please note that the unit of time configurations below are all in seconds."
 msgstr ""
 "Lütfen aşağıdaki zaman yapılandırmalarının birimlerinin saniye cinsinden "
 "olduğunu unutmayın."
@@ -3640,17 +3651,17 @@ msgstr "Lütfen bir yedekleme dosyası seçin"
 msgid "Please select at least one item"
 msgstr "Lütfen en az bir öğe seçin"
 
-#: src/views/environments/list/Environment.vue:120
+#: src/views/environments/list/Environment.vue:121
 #: src/views/environments/list/Environment.vue:35
 msgid "Please select at least one node to reload Nginx"
 msgstr "Lütfen Nginx'i yeniden yüklemek için en az bir düğüm seçin"
 
-#: src/views/environments/list/Environment.vue:141
+#: src/views/environments/list/Environment.vue:142
 #: src/views/environments/list/Environment.vue:49
 msgid "Please select at least one node to restart Nginx"
 msgstr "Lütfen Nginx'i yeniden başlatmak için en az bir düğüm seçin"
 
-#: src/views/environments/list/Environment.vue:99
+#: src/views/environments/list/Environment.vue:100
 msgid "Please select at least one node to upgrade"
 msgstr "Lütfen yükseltmek için en az bir düğüm seçin"
 
@@ -3663,7 +3674,7 @@ msgstr "Onaylamak için \"İptal Et\" yazın"
 msgid "Port"
 msgstr "Port"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:44
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:45
 #: src/views/stream/components/RightPanel/RightPanel.vue:26
 msgid "Port Scanner"
 msgstr "Port Tarayıcı"
@@ -3834,8 +3845,8 @@ msgstr "Yeniden Yükle"
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:136
 #: src/views/environments/group/columns.ts:22
 #: src/views/environments/group/EnvGroup.vue:50
-#: src/views/environments/list/Environment.vue:128
-#: src/views/environments/list/Environment.vue:136
+#: src/views/environments/list/Environment.vue:129
+#: src/views/environments/list/Environment.vue:137
 msgid "Reload Nginx"
 msgstr "Nginx'i Yeniden Yükle"
 
@@ -3861,7 +3872,8 @@ msgstr "Uzak Nginx Yeniden Yükleme Başarılı"
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:84
 msgid "Reload request failed, please check your network connection"
-msgstr "Yeniden yükleme isteği başarısız oldu, lütfen ağ bağlantınızı kontrol edin"
+msgstr ""
+"Yeniden yükleme isteği başarısız oldu, lütfen ağ bağlantınızı kontrol edin"
 
 #: src/components/NginxControl/NginxControl.vue:73
 msgid "Reloading"
@@ -3884,7 +3896,7 @@ msgstr "Başarıyla kaldırıldı"
 msgid "Removed successfully"
 msgstr "Başarıyla kaldırıldı"
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:126
+#: src/components/NgxConfigEditor/NgxUpstream.vue:131
 #: src/views/config/components/ConfigName.vue:51
 #: src/views/config/components/Rename.vue:56
 #: src/views/config/ConfigList.vue:181
@@ -3933,7 +3945,8 @@ msgstr "Uzak Akış Yeniden Adlandırma Başarılı"
 
 #: src/components/Notification/notifications.ts:126
 msgid "Rename site %{name} to %{new_name} on %{node} failed"
-msgstr "%{node} üzerinde %{name} sitesi %{new_name} olarak yeniden adlandırılamadı"
+msgstr ""
+"%{node} üzerinde %{name} sitesi %{new_name} olarak yeniden adlandırılamadı"
 
 #: src/components/Notification/notifications.ts:130
 msgid "Rename site %{name} to %{new_name} on %{node} successfully"
@@ -4011,8 +4024,8 @@ msgid ""
 "shared library memory, which will be repeated calculated for multiple "
 "processes"
 msgstr ""
-"Resident Set Size: Fiziksel bellekte gerçekte bulunan bellek, paylaşılan "
-"tüm kütüphane belleğini içerir ve birden fazla işlem için tekrar hesaplanır"
+"Resident Set Size: Fiziksel bellekte gerçekte bulunan bellek, paylaşılan tüm "
+"kütüphane belleğini içerir ve birden fazla işlem için tekrar hesaplanır"
 
 #: src/composables/usePerformanceMetrics.ts:109
 #: src/views/dashboard/components/PerformanceTablesCard.vue:69
@@ -4024,8 +4037,8 @@ msgid "Restart"
 msgstr "Yeniden Başlat"
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:148
-#: src/views/environments/list/Environment.vue:149
-#: src/views/environments/list/Environment.vue:157
+#: src/views/environments/list/Environment.vue:150
+#: src/views/environments/list/Environment.vue:158
 msgid "Restart Nginx"
 msgstr "Nginx'i Yeniden Başlat"
 
@@ -4047,7 +4060,8 @@ msgstr "Uzak Nginx Yeniden Başlatma Başarılı"
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:104
 msgid "Restart request failed, please check your network connection"
-msgstr "Yeniden başlatma isteği başarısız oldu, lütfen ağ bağlantınızı kontrol edin"
+msgstr ""
+"Yeniden başlatma isteği başarısız oldu, lütfen ağ bağlantınızı kontrol edin"
 
 #: src/components/NginxControl/NginxControl.vue:78
 msgid "Restarting"
@@ -4447,19 +4461,19 @@ msgstr "HTTP01 meydan okuma sağlayıcısı ayarlanıyor"
 
 #: src/constants/errors/nginx_log.ts:8
 msgid ""
-"Settings.NginxLogSettings.AccessLogPath is empty, refer to "
-"https://nginxui.com/guide/config-nginx.html for more information"
+"Settings.NginxLogSettings.AccessLogPath is empty, refer to https://nginxui."
+"com/guide/config-nginx.html for more information"
 msgstr ""
-"Settings.NginxLogSettings.AccessLogPath boş, daha fazla bilgi için "
-"https://nginxui.com/guide/config-nginx.html adresine bakın"
+"Settings.NginxLogSettings.AccessLogPath boş, daha fazla bilgi için https://"
+"nginxui.com/guide/config-nginx.html adresine bakın"
 
 #: src/constants/errors/nginx_log.ts:7
 msgid ""
-"Settings.NginxLogSettings.ErrorLogPath is empty, refer to "
-"https://nginxui.com/guide/config-nginx.html for more information"
+"Settings.NginxLogSettings.ErrorLogPath is empty, refer to https://nginxui."
+"com/guide/config-nginx.html for more information"
 msgstr ""
-"Settings.NginxLogSettings.ErrorLogPath boş, daha fazla bilgi için "
-"https://nginxui.com/guide/config-nginx.html adresine bakın"
+"Settings.NginxLogSettings.ErrorLogPath boş, daha fazla bilgi için https://"
+"nginxui.com/guide/config-nginx.html adresine bakın"
 
 #: src/views/install/components/InstallView.vue:65
 msgid "Setup your Nginx UI"
@@ -4692,25 +4706,25 @@ msgstr "Pazar"
 msgid ""
 "Support communication with the backend through the Server-Sent Events "
 "protocol. If your Nginx UI is being used via an Nginx reverse proxy, please "
-"refer to this link to write the corresponding configuration file: "
-"https://nginxui.com/guide/nginx-proxy-example.html"
+"refer to this link to write the corresponding configuration file: https://"
+"nginxui.com/guide/nginx-proxy-example.html"
 msgstr ""
 "Backend ile iletişimi Server-Sent Events protokolü üzerinden destekler. "
 "Nginx UI'nız bir Nginx ters proxy üzerinden kullanılıyorsa, ilgili "
-"yapılandırma dosyasını yazmak için bu bağlantıya bakın: "
-"https://nginxui.com/guide/nginx-proxy-example.html"
+"yapılandırma dosyasını yazmak için bu bağlantıya bakın: https://nginxui.com/"
+"guide/nginx-proxy-example.html"
 
 #: src/components/SelfCheck/tasks/frontend/websocket.ts:13
 msgid ""
 "Support communication with the backend through the WebSocket protocol. If "
-"your Nginx UI is being used via an Nginx reverse proxy, please refer to "
-"this link to write the corresponding configuration file: "
-"https://nginxui.com/guide/nginx-proxy-example.html"
+"your Nginx UI is being used via an Nginx reverse proxy, please refer to this "
+"link to write the corresponding configuration file: https://nginxui.com/"
+"guide/nginx-proxy-example.html"
 msgstr ""
 "WebSocket protokolü aracılığıyla backend ile iletişimi destekler. Nginx "
 "UI'nız bir Nginx ters proxy üzerinden kullanılıyorsa, ilgili yapılandırma "
-"dosyasını yazmak için bu bağlantıya bakın: "
-"https://nginxui.com/guide/nginx-proxy-example.html"
+"dosyasını yazmak için bu bağlantıya bakın: https://nginxui.com/guide/nginx-"
+"proxy-example.html"
 
 #: src/language/curd.ts:51 src/language/curd.ts:55
 msgid "Support single or batch upload of files"
@@ -4752,7 +4766,8 @@ msgstr "Sertifika %{cert_name}, %{env_name} ortamına senkronize edilemedi"
 
 #: src/components/Notification/notifications.ts:66
 msgid "Sync Certificate %{cert_name} to %{env_name} successfully"
-msgstr "Sertifika %{cert_name}, %{env_name} ortamına başarıyla senkronize edildi"
+msgstr ""
+"Sertifika %{cert_name}, %{env_name} ortamına başarıyla senkronize edildi"
 
 #: src/components/Notification/notifications.ts:61 src/language/constants.ts:39
 msgid "Sync Certificate Error"
@@ -4769,8 +4784,7 @@ msgstr "Yapılandırma %{config_name}, %{env_name} ortamına senkronize edilemed
 #: src/components/Notification/notifications.ts:74
 msgid "Sync config %{config_name} to %{env_name} successfully"
 msgstr ""
-"Yapılandırma %{config_name}, %{env_name} ortamına başarıyla senkronize "
-"edildi"
+"Yapılandırma %{config_name}, %{env_name} ortamına başarıyla senkronize edildi"
 
 #: src/components/Notification/notifications.ts:69 src/language/constants.ts:45
 msgid "Sync Config Error"
@@ -4878,8 +4892,7 @@ msgstr "Girdi bir SSL Sertifika Anahtarı değil"
 
 #: src/constants/errors/nginx_log.ts:2
 msgid ""
-"The log path is not under the paths in "
-"settings.NginxSettings.LogDirWhiteList"
+"The log path is not under the paths in settings.NginxSettings.LogDirWhiteList"
 msgstr ""
 "Günlük yolu, settings.NginxSettings.LogDirWhiteList içindeki yolların "
 "altında değil"
@@ -4894,7 +4907,8 @@ msgstr ""
 "iki nokta üst üste ve noktalar içermelidir."
 
 #: src/views/preference/tabs/OpenAISettings.vue:90
-msgid "The model used for code completion, if not set, the chat model will be used."
+msgid ""
+"The model used for code completion, if not set, the chat model will be used."
 msgstr ""
 "Kod tamamlama için kullanılan model. Ayarlanmamışsa sohbet modeli "
 "kullanılacaktır."
@@ -5004,14 +5018,17 @@ msgid "This field should not be empty"
 msgstr "Bu alan boş bırakılamaz"
 
 #: src/constants/form_errors.ts:6
-msgid "This field should only contain letters, unicode characters, numbers, and -_."
-msgstr "Bu alan yalnızca harfler, Unicode karakterler, sayılar ve -_ içermelidir."
+msgid ""
+"This field should only contain letters, unicode characters, numbers, and -_."
+msgstr ""
+"Bu alan yalnızca harfler, Unicode karakterler, sayılar ve -_ içermelidir."
 
 #: src/language/curd.ts:44
 msgid ""
-"This field should only contain letters, unicode characters, numbers, and "
-"-_./:"
-msgstr "Bu alan yalnızca harfler, Unicode karakterler, sayılar ve -_./: içermelidir"
+"This field should only contain letters, unicode characters, numbers, and -"
+"_./:"
+msgstr ""
+"Bu alan yalnızca harfler, Unicode karakterler, sayılar ve -_./: içermelidir"
 
 #: src/views/dashboard/NginxDashBoard.vue:150
 msgid ""
@@ -5034,8 +5051,8 @@ msgid ""
 "This token will only be shown once and cannot be retrieved later. Please "
 "make sure to save it in a secure location."
 msgstr ""
-"Bu token yalnızca bir kez gösterilecek ve daha sonra alınamayacaktır. "
-"Lütfen güvenli bir yerde sakladığınızdan emin olun."
+"Bu token yalnızca bir kez gösterilecek ve daha sonra alınamayacaktır. Lütfen "
+"güvenli bir yerde sakladığınızdan emin olun."
 
 #: src/constants/form_errors.ts:4 src/language/curd.ts:42
 msgid "This value is already taken"
@@ -5060,7 +5077,8 @@ msgstr ""
 "yükleme tamamlandıktan sonra Nginx UI yeniden başlatılacaktır."
 
 #: src/views/environments/list/BatchUpgrader.vue:182
-msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
+msgid ""
+"This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
 msgstr ""
 "Bu işlem, %{nodeNames} üzerindeki Nginx UI'yi %{version} sürümüne "
 "yükseltecek veya yeniden yükleyecektir."
@@ -5110,15 +5128,15 @@ msgid ""
 "and restart Nginx UI."
 msgstr ""
 "Güvenliği sağlamak için WebAuthn yapılandırması kullanıcı arayüzü üzerinden "
-"eklenemez. Lütfen app.ini yapılandırma dosyasına aşağıdakileri manuel "
-"olarak ekleyin ve Nginx UI'ı yeniden başlatın."
+"eklenemez. Lütfen app.ini yapılandırma dosyasına aşağıdakileri manuel olarak "
+"ekleyin ve Nginx UI'ı yeniden başlatın."
 
 #: src/views/site/site_edit/components/Cert/IssueCert.vue:34
 #: src/views/site/site_edit/components/EnableTLS/EnableTLS.vue:15
 msgid ""
 "To make sure the certification auto-renewal can work normally, we need to "
-"add a location which can proxy the request from authority to backend, and "
-"we need to save this file and reload the Nginx. Are you sure you want to "
+"add a location which can proxy the request from authority to backend, and we "
+"need to save this file and reload the Nginx. Are you sure you want to "
 "continue?"
 msgstr ""
 "Sertifikanın otomatik yenilenmesinin düzgün çalışmasını sağlamak için, "
@@ -5243,8 +5261,8 @@ msgid "Updated at"
 msgstr "Güncellenme Tarihi"
 
 #: src/routes/modules/system.ts:26
-#: src/views/environments/list/Environment.vue:107
-#: src/views/environments/list/Environment.vue:115
+#: src/views/environments/list/Environment.vue:108
+#: src/views/environments/list/Environment.vue:116
 #: src/views/system/Upgrade.vue:154 src/views/system/Upgrade.vue:159
 msgid "Upgrade"
 msgstr "Yükselt"
@@ -5274,7 +5292,7 @@ msgstr "Klasörleri Yükle"
 msgid "Upstream"
 msgstr "Yukarı Akış"
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:177
+#: src/components/NgxConfigEditor/NgxUpstream.vue:184
 msgid "Upstream Name"
 msgstr "Yukarı Akış Adı"
 
@@ -5404,8 +5422,8 @@ msgstr ""
 
 #: src/views/site/site_edit/components/Cert/ObtainCert.vue:140
 msgid ""
-"We will remove the HTTPChallenge configuration from this file and reload "
-"the Nginx. Are you sure you want to continue?"
+"We will remove the HTTPChallenge configuration from this file and reload the "
+"Nginx. Are you sure you want to continue?"
 msgstr ""
 "Bu dosyadan HTTPChallenge yapılandırmasını kaldıracağız ve Nginx'i yeniden "
 "yükleyeceğiz. Devam etmek istediğinizden emin misiniz?"
@@ -5510,8 +5528,8 @@ msgstr "Evet"
 
 #: src/views/terminal/Terminal.vue:132
 msgid ""
-"You are accessing this terminal over an insecure HTTP connection on a "
-"non-localhost domain. This may expose sensitive information."
+"You are accessing this terminal over an insecure HTTP connection on a non-"
+"localhost domain. This may expose sensitive information."
 msgstr ""
 "Bu terminale, localhost olmayan bir alan adında güvenli olmayan bir HTTP "
 "bağlantısı üzerinden erişiyorsunuz. Bu, hassas bilgilerin açığa çıkmasına "
@@ -5542,7 +5560,8 @@ msgstr ""
 "ekleyemezsiniz."
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:81
-msgid "You have not enabled 2FA yet. Please enable 2FA to generate recovery codes."
+msgid ""
+"You have not enabled 2FA yet. Please enable 2FA to generate recovery codes."
 msgstr ""
 "Henüz 2FA'yı etkinleştirmediniz. Kurtarma kodları oluşturmak için lütfen "
 "2FA'yı etkinleştirin."
@@ -5556,8 +5575,8 @@ msgid ""
 "Your current recovery code might be outdated and insecure. Please generate "
 "new recovery codes at your earliest convenience to ensure security."
 msgstr ""
-"Mevcut kurtarma kodunuz güncel olmayabilir ve güvenli olmayabilir. "
-"Güvenliği sağlamak için en kısa sürede yeni kurtarma kodları oluşturun."
+"Mevcut kurtarma kodunuz güncel olmayabilir ve güvenli olmayabilir. Güvenliği "
+"sağlamak için en kısa sürede yeni kurtarma kodları oluşturun."
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:142
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:155
@@ -5628,11 +5647,11 @@ msgstr "Geçiş Anahtarlarınız"
 
 #~ msgid ""
 #~ "Check if /var/run/docker.sock exists. If you are using Nginx UI Official "
-#~ "Docker Image, please make sure the docker socket is mounted like this: `-v "
-#~ "/var/run/docker.sock:/var/run/docker.sock`."
+#~ "Docker Image, please make sure the docker socket is mounted like this: `-"
+#~ "v /var/run/docker.sock:/var/run/docker.sock`."
 #~ msgstr ""
-#~ "/var/run/docker.sock dosyasının var olup olmadığını kontrol edin. Nginx UI "
-#~ "Resmi Docker Image'ını kullanıyorsanız, docker soketinin şu şekilde "
+#~ "/var/run/docker.sock dosyasının var olup olmadığını kontrol edin. Nginx "
+#~ "UI Resmi Docker Image'ını kullanıyorsanız, docker soketinin şu şekilde "
 #~ "bağlandığından emin olun: `-v /var/run/docker.sock:/var/run/docker.sock`."
 
 #~ msgid "Check if the nginx access log path exists"
@@ -5701,7 +5720,8 @@ msgstr "Geçiş Anahtarlarınız"
 #~ msgstr "Yeniden Başlatma"
 
 #~ msgid "Deploy %{conf_name} to %{node_name} successfully"
-#~ msgstr "%{conf_name} yapılandırması başarıyla %{node_name} düğümüne dağıtıldı"
+#~ msgstr ""
+#~ "%{conf_name} yapılandırması başarıyla %{node_name} düğümüne dağıtıldı"
 
 #~ msgid "Deploy successfully"
 #~ msgstr "Başarıyla Dağıtıldı"
@@ -5709,8 +5729,8 @@ msgstr "Geçiş Anahtarlarınız"
 #, fuzzy
 #~ msgid "Disable site %{site} on %{node} error, response: %{resp}"
 #~ msgstr ""
-#~ "%{conf_name} yapılandırmasını %{node_name} düğümünde etkinleştirme başarılı "
-#~ "oldu"
+#~ "%{conf_name} yapılandırmasını %{node_name} düğümünde etkinleştirme "
+#~ "başarılı oldu"
 
 #~ msgid "Do you want to deploy this file to remote server?"
 #~ msgid_plural "Do you want to deploy this file to remote servers?"
@@ -5725,8 +5745,8 @@ msgstr "Geçiş Anahtarlarınız"
 
 #~ msgid "Enable %{conf_name} in %{node_name} successfully"
 #~ msgstr ""
-#~ "%{conf_name} yapılandırmasını %{node_name} düğümünde etkinleştirme başarılı "
-#~ "oldu"
+#~ "%{conf_name} yapılandırmasını %{node_name} düğümünde etkinleştirme "
+#~ "başarılı oldu"
 
 #~ msgid "Enable successfully"
 #~ msgstr "Başarıyla etkinleştirildi"
@@ -5738,14 +5758,18 @@ msgstr "Geçiş Anahtarlarınız"
 #~ "Nginx kullanıcı arayüzünü en son sürüme yükseltin"
 
 #, fuzzy
-#~ msgid "Rename %{orig_path} to %{new_path} on %{env_name} failed, response: %{resp}"
+#~ msgid ""
+#~ "Rename %{orig_path} to %{new_path} on %{env_name} failed, response: "
+#~ "%{resp}"
 #~ msgstr ""
-#~ "2] üzerinde %{orig_path}'ı %{new_path} olarak yeniden adlandırma başarısız "
-#~ "oldu, yanıt: %{resp}"
+#~ "2] üzerinde %{orig_path}'ı %{new_path} olarak yeniden adlandırma "
+#~ "başarısız oldu, yanıt: %{resp}"
 
 #, fuzzy
-#~ msgid "Rename Site %{site} to %{new_site} on %{node} error, response: %{resp}"
-#~ msgstr "2] üzerinde %{orig_path}'ı %{new_path} olarak başarıyla yeniden adlandırın"
+#~ msgid ""
+#~ "Rename Site %{site} to %{new_site} on %{node} error, response: %{resp}"
+#~ msgstr ""
+#~ "2] üzerinde %{orig_path}'ı %{new_path} olarak başarıyla yeniden adlandırın"
 
 #, fuzzy
 #~ msgid "Save site %{site} to %{node} error, response: %{resp}"
@@ -5762,7 +5786,8 @@ msgstr "Geçiş Anahtarlarınız"
 #~ "lütfen uzak Nginx kullanıcı arayüzünü en son sürüme yükseltin"
 
 #, fuzzy
-#~ msgid "Sync Certificate %{cert_name} to %{env_name} failed, response: %{resp}"
+#~ msgid ""
+#~ "Sync Certificate %{cert_name} to %{env_name} failed, response: %{resp}"
 #~ msgstr ""
 #~ "Sertifika %{cert_name} ile %{env_name} arasında senkronizasyon başarısız "
 #~ "oldu, yanıt: %{resp}"
@@ -5780,8 +5805,8 @@ msgstr "Geçiş Anahtarlarınız"
 #~ msgstr "Dosya"
 
 #~ msgid ""
-#~ "If you lose your mobile phone, you can use the recovery code to reset your "
-#~ "2FA."
+#~ "If you lose your mobile phone, you can use the recovery code to reset "
+#~ "your 2FA."
 #~ msgstr ""
 #~ "Cep telefonunuzu kaybederseniz, 2FA'nızı sıfırlamak için kurtarma kodunu "
 #~ "kullanabilirsiniz."
@@ -5798,7 +5823,8 @@ msgstr "Geçiş Anahtarlarınız"
 #~ msgstr "Server hatası"
 
 #, fuzzy
-#~ msgid "The recovery code is only displayed once, please save it in a safe place."
+#~ msgid ""
+#~ "The recovery code is only displayed once, please save it in a safe place."
 #~ msgstr ""
 #~ "Kurtarma kodu yalnızca bir kez görüntülenir, lütfen güvenli bir yere "
 #~ "kaydedin."
@@ -5814,8 +5840,9 @@ msgstr "Geçiş Anahtarlarınız"
 #~ "Rename %{orig_path} to %{new_path} on %{env_name} failed, please upgrade "
 #~ "the remote Nginx UI to the latest version"
 #~ msgstr ""
-#~ "2] üzerinde %{orig_path}'ı %{new_path} olarak yeniden adlandırmak başarısız "
-#~ "oldu, lütfen uzak Nginx kullanıcı arayüzünü en son sürüme yükseltin"
+#~ "2] üzerinde %{orig_path}'ı %{new_path} olarak yeniden adlandırmak "
+#~ "başarısız oldu, lütfen uzak Nginx kullanıcı arayüzünü en son sürüme "
+#~ "yükseltin"
 
 #, fuzzy
 #~ msgid "Server Name"

+ 195 - 181
app/src/language/uk_UA/app.po

@@ -4,11 +4,11 @@ msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "PO-Revision-Date: 2025-04-16 15:12+0000\n"
 "Last-Translator: sergio_from_tauri <dedysobr@gmail.com>\n"
-"Language-Team: Ukrainian "
-"<https://weblate.nginxui.com/projects/nginx-ui/frontend/uk/>\n"
+"Language-Team: Ukrainian <https://weblate.nginxui.com/projects/nginx-ui/"
+"frontend/uk/>\n"
 "Language: uk_UA\n"
 "MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=utf-8\n"
+"Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
 "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
@@ -17,8 +17,8 @@ msgstr ""
 #: src/language/generate.ts:31
 msgid "[Nginx UI] ACME User: %{name}, Email: %{email}, CA Dir: %{caDir}"
 msgstr ""
-"[Nginx UI] Користувач ACME: %{name}, Електронна пошта: %{email}, Каталог "
-"CA: %{caDir}"
+"[Nginx UI] Користувач ACME: %{name}, Електронна пошта: %{email}, Каталог CA: "
+"%{caDir}"
 
 #: src/language/generate.ts:32
 msgid "[Nginx UI] Backing up current certificate for later revocation"
@@ -35,10 +35,11 @@ msgid "[Nginx UI] Certificate successfully revoked"
 msgstr "[Nginx UI] Сертифікат успішно відкликано"
 
 #: src/language/generate.ts:35
-msgid "[Nginx UI] Certificate was used for server, reloading server TLS certificate"
+msgid ""
+"[Nginx UI] Certificate was used for server, reloading server TLS certificate"
 msgstr ""
-"[Nginx UI] Сертифікат використовувався для сервера, перезавантаження "
-"TLS-сертифіката сервера"
+"[Nginx UI] Сертифікат використовувався для сервера, перезавантаження TLS-"
+"сертифіката сервера"
 
 #: src/language/generate.ts:36
 msgid "[Nginx UI] Creating client facilitates communication with the CA server"
@@ -163,10 +164,10 @@ msgid "Actual worker to configured ratio"
 msgstr "Фактичне співвідношення робочих до налаштованих"
 
 #: src/components/NgxConfigEditor/NgxServer.vue:112
-#: src/components/NgxConfigEditor/NgxUpstream.vue:159 src/language/curd.ts:19
+#: src/components/NgxConfigEditor/NgxUpstream.vue:166 src/language/curd.ts:19
 #: src/views/preference/tabs/CertSettings.vue:45
 #: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:94
-#: src/views/stream/StreamList.vue:101
+#: src/views/stream/StreamList.vue:102
 msgid "Add"
 msgstr "Додати"
 
@@ -193,7 +194,7 @@ msgstr "Додати локацію"
 msgid "Add Site"
 msgstr "Додати сайт"
 
-#: src/views/stream/StreamList.vue:138
+#: src/views/stream/StreamList.vue:139
 msgid "Add Stream"
 msgstr "Додати стрім"
 
@@ -212,7 +213,8 @@ msgstr "Розширений режим"
 
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:99
 msgid "Afterwards, refresh this page and click add passkey again."
-msgstr "Після цього оновіть цю сторінку та натисніть «Додати ключ доступу» знову."
+msgstr ""
+"Після цього оновіть цю сторінку та натисніть «Додати ключ доступу» знову."
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:115
 msgid "All"
@@ -281,7 +283,7 @@ msgid "Are you sure you want to delete permanently?"
 msgstr "Ви впевнені, що хочете видалити назавжди?"
 
 #: src/language/curd.ts:25 src/views/site/site_list/SiteList.vue:100
-#: src/views/stream/StreamList.vue:121
+#: src/views/stream/StreamList.vue:122
 msgid "Are you sure you want to delete?"
 msgstr "Ви впевнені, що хочете видалити?"
 
@@ -423,7 +425,8 @@ msgstr "Резервна копія"
 
 #: src/components/SystemRestore/SystemRestoreContent.vue:155
 msgid "Backup file integrity check failed, it may have been tampered with"
-msgstr "Перевірка цілісності резервного файлу не вдалася, можливо, його було змінено"
+msgstr ""
+"Перевірка цілісності резервного файлу не вдалася, можливо, його було змінено"
 
 #: src/constants/errors/backup.ts:41
 msgid "Backup file not found: {0}"
@@ -448,8 +451,8 @@ msgstr "Шлях резервного копіювання не є директ
 #: src/constants/errors/backup.ts:62
 msgid "Backup path is required for custom directory backup"
 msgstr ""
-"Шлях резервного копіювання необхідний для резервного копіювання "
-"спеціального каталогу"
+"Шлях резервного копіювання необхідний для резервного копіювання спеціального "
+"каталогу"
 
 #: src/constants/errors/backup.ts:60
 msgid "Backup path not in granted access paths: {0}"
@@ -466,7 +469,8 @@ msgstr ""
 "%{file_path}"
 
 #: src/components/Notification/notifications.ts:34
-msgid "Backup task %{backup_name} failed during storage upload, error: %{error}"
+msgid ""
+"Backup task %{backup_name} failed during storage upload, error: %{error}"
 msgstr ""
 "Завдання резервного копіювання %{backup_name} не вдалося під час "
 "завантаження в сховище, помилка: %{error}"
@@ -502,7 +506,7 @@ msgid "Base information"
 msgstr "Основна інформація"
 
 #: src/views/config/ConfigEditor.vue:300
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:31
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:32
 #: src/views/stream/components/RightPanel/RightPanel.vue:20
 msgid "Basic"
 msgstr "Базові"
@@ -550,7 +554,8 @@ msgstr "Кеш"
 
 #: src/views/dashboard/components/ParamsOpt/ProxyCacheConfig.vue:178
 msgid "Cache items not accessed within this time will be removed"
-msgstr "Елементи кешу, до яких не було звернень протягом цього часу, будуть видалені"
+msgstr ""
+"Елементи кешу, до яких не було звернень протягом цього часу, будуть видалені"
 
 #: src/views/dashboard/components/ParamsOpt/ProxyCacheConfig.vue:350
 msgid "Cache loader processing time threshold"
@@ -619,7 +624,8 @@ msgstr "Неможливо отримати доступ до шляху збе
 
 #: src/constants/errors/user.ts:11
 msgid "Cannot change initial user password in demo mode"
-msgstr "Не вдається змінити початковий пароль користувача в демонстраційному режимі"
+msgstr ""
+"Не вдається змінити початковий пароль користувача в демонстраційному режимі"
 
 #: src/components/ConfigHistory/DiffViewer.vue:67
 #: src/components/ConfigHistory/DiffViewer.vue:84
@@ -745,7 +751,7 @@ msgstr "Змінений шлях"
 msgid "Channel"
 msgstr "Канал"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:41
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:42
 #: src/views/stream/components/RightPanel/RightPanel.vue:23
 msgid "Chat"
 msgstr "Чат"
@@ -762,24 +768,24 @@ msgstr "Перевірте ще раз"
 #: src/language/generate.ts:6
 msgid ""
 "Check if /var/run/docker.sock exists. If you are using Nginx UI Official "
-"Docker Image, please make sure the docker socket is mounted like this: `-v "
-"/var/run/docker.sock:/var/run/docker.sock`. Nginx UI official image uses "
-"/var/run/docker.sock to communicate with the host Docker Engine via Docker "
-"Client API. This feature is used to control Nginx in another container and "
-"perform container replacement rather than binary replacement during OTA "
-"upgrades of Nginx UI to ensure container dependencies are also upgraded. If "
-"you don't need this feature, please add the environment variable "
+"Docker Image, please make sure the docker socket is mounted like this: `-v /"
+"var/run/docker.sock:/var/run/docker.sock`. Nginx UI official image uses /var/"
+"run/docker.sock to communicate with the host Docker Engine via Docker Client "
+"API. This feature is used to control Nginx in another container and perform "
+"container replacement rather than binary replacement during OTA upgrades of "
+"Nginx UI to ensure container dependencies are also upgraded. If you don't "
+"need this feature, please add the environment variable "
 "NGINX_UI_IGNORE_DOCKER_SOCKET=true to the container."
 msgstr ""
 "Перевірте, чи існує /var/run/docker.sock. Якщо ви використовуєте офіційний "
 "образ Docker Nginx UI, переконайтеся, що сокет Docker змонтовано таким "
-"чином: `-v /var/run/docker.sock:/var/run/docker.sock`. Офіційний образ "
-"Nginx UI використовує /var/run/docker.sock для зв’язку з Docker Engine "
-"хоста через API Docker Client. Ця функція використовується для керування "
-"Nginx в іншому контейнері та виконання заміни контейнера замість заміни "
-"бінарного файлу під час OTA-оновлень Nginx UI, щоб гарантувати, що "
-"залежності контейнера також оновлюються. Якщо вам не потрібна ця функція, "
-"додайте змінну середовища NGINX_UI_IGNORE_DOCKER_SOCKET=true до контейнера."
+"чином: `-v /var/run/docker.sock:/var/run/docker.sock`. Офіційний образ Nginx "
+"UI використовує /var/run/docker.sock для зв’язку з Docker Engine хоста через "
+"API Docker Client. Ця функція використовується для керування Nginx в іншому "
+"контейнері та виконання заміни контейнера замість заміни бінарного файлу під "
+"час OTA-оновлень Nginx UI, щоб гарантувати, що залежності контейнера також "
+"оновлюються. Якщо вам не потрібна ця функція, додайте змінну середовища "
+"NGINX_UI_IGNORE_DOCKER_SOCKET=true до контейнера."
 
 #: src/components/SelfCheck/tasks/frontend/https-check.ts:14
 msgid ""
@@ -791,19 +797,19 @@ msgstr ""
 
 #: src/language/generate.ts:8
 msgid ""
-"Check if the nginx access log path exists. By default, this path is "
-"obtained from 'nginx -V'. If it cannot be obtained or the obtained path "
-"does not point to a valid, existing file, an error will be reported. In "
-"this case, you need to modify the configuration file to specify the access "
-"log path.Refer to the docs for more details: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#accesslogpath"
+"Check if the nginx access log path exists. By default, this path is obtained "
+"from 'nginx -V'. If it cannot be obtained or the obtained path does not "
+"point to a valid, existing file, an error will be reported. In this case, "
+"you need to modify the configuration file to specify the access log path."
+"Refer to the docs for more details: https://nginxui.com/zh_CN/guide/config-"
+"nginx.html#accesslogpath"
 msgstr ""
-"Перевірте, чи існує шлях до журналу доступу nginx. За замовчуванням цей "
-"шлях отримується з 'nginx -V'. Якщо його не вдається отримати або отриманий "
-"шлях не вказує на дійсний існуючий файл, буде повідомлено про помилку. У "
-"цьому випадку вам потрібно змінити файл конфігурації, щоб вказати шлях до "
-"журналу доступу. Докладніше див. у документації: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#accesslogpath"
+"Перевірте, чи існує шлях до журналу доступу nginx. За замовчуванням цей шлях "
+"отримується з 'nginx -V'. Якщо його не вдається отримати або отриманий шлях "
+"не вказує на дійсний існуючий файл, буде повідомлено про помилку. У цьому "
+"випадку вам потрібно змінити файл конфігурації, щоб вказати шлях до журналу "
+"доступу. Докладніше див. у документації: https://nginxui.com/zh_CN/guide/"
+"config-nginx.html#accesslogpath"
 
 #: src/language/generate.ts:9
 msgid "Check if the nginx configuration directory exists"
@@ -818,30 +824,30 @@ msgid ""
 "Check if the nginx error log path exists. By default, this path is obtained "
 "from 'nginx -V'. If it cannot be obtained or the obtained path does not "
 "point to a valid, existing file, an error will be reported. In this case, "
-"you need to modify the configuration file to specify the error log "
-"path.Refer to the docs for more details: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#errorlogpath"
+"you need to modify the configuration file to specify the error log path."
+"Refer to the docs for more details: https://nginxui.com/zh_CN/guide/config-"
+"nginx.html#errorlogpath"
 msgstr ""
-"Перевірте, чи існує шлях до журналу помилок nginx. За замовчуванням цей "
-"шлях отримується з 'nginx -V'. Якщо його не вдається отримати або отриманий "
-"шлях не вказує на дійсний існуючий файл, буде повідомлено про помилку. У "
-"цьому випадку вам потрібно змінити файл конфігурації, щоб вказати шлях до "
-"журналу помилок. Докладніше див. у документації: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#errorlogpath"
+"Перевірте, чи існує шлях до журналу помилок nginx. За замовчуванням цей шлях "
+"отримується з 'nginx -V'. Якщо його не вдається отримати або отриманий шлях "
+"не вказує на дійсний існуючий файл, буде повідомлено про помилку. У цьому "
+"випадку вам потрібно змінити файл конфігурації, щоб вказати шлях до журналу "
+"помилок. Докладніше див. у документації: https://nginxui.com/zh_CN/guide/"
+"config-nginx.html#errorlogpath"
 
 #: src/language/generate.ts:7
 msgid ""
 "Check if the nginx PID path exists. By default, this path is obtained from "
 "'nginx -V'. If it cannot be obtained, an error will be reported. In this "
 "case, you need to modify the configuration file to specify the Nginx PID "
-"path.Refer to the docs for more details: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#pidpath"
+"path.Refer to the docs for more details: https://nginxui.com/zh_CN/guide/"
+"config-nginx.html#pidpath"
 msgstr ""
-"Перевірте, чи існує шлях до PID Nginx. За замовчуванням цей шлях "
-"отримується з команди 'nginx -V'. Якщо його не вдається отримати, буде "
-"повідомлено про помилку. У цьому випадку вам потрібно змінити "
-"конфігураційний файл, щоб вказати шлях до PID Nginx. Докладніше див. у "
-"документації: https://nginxui.com/zh_CN/guide/config-nginx.html#pidpath"
+"Перевірте, чи існує шлях до PID Nginx. За замовчуванням цей шлях отримується "
+"з команди 'nginx -V'. Якщо його не вдається отримати, буде повідомлено про "
+"помилку. У цьому випадку вам потрібно змінити конфігураційний файл, щоб "
+"вказати шлях до PID Nginx. Докладніше див. у документації: https://nginxui."
+"com/zh_CN/guide/config-nginx.html#pidpath"
 
 #: src/language/generate.ts:12
 msgid "Check if the nginx.conf includes the conf.d directory"
@@ -865,8 +871,8 @@ msgstr ""
 
 #: src/language/generate.ts:16
 msgid ""
-"Check if the streams-available and streams-enabled directories are under "
-"the nginx configuration directory"
+"Check if the streams-available and streams-enabled directories are under the "
+"nginx configuration directory"
 msgstr ""
 "Перевірте, чи каталоги streams-available та streams-enabled знаходяться в "
 "каталозі конфігурації nginx"
@@ -997,7 +1003,7 @@ msgstr "Вхідний файл конфігурації не існує"
 msgid "Config path is empty"
 msgstr "Конфігурація порожній"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:37
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:38
 msgid "Config Template"
 msgstr "Шаблон конфігурації"
 
@@ -1095,7 +1101,7 @@ msgstr ""
 msgid "CPU:"
 msgstr "CPU:"
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:170
+#: src/components/NgxConfigEditor/NgxUpstream.vue:177
 msgid "Create"
 msgstr "Створити"
 
@@ -1180,8 +1186,8 @@ msgstr ""
 "\"Вірність\" означає точність до змісту та наміру оригінального тексту;\n"
 "\"Плавність\" означає, що переклад має бути зрозумілим та легким для "
 "сприйняття;\n"
-"\"Витонченість\" означає прагнення до культурної естетики перекладу та "
-"краси мови.\n"
+"\"Витонченість\" означає прагнення до культурної естетики перекладу та краси "
+"мови.\n"
 "Мета полягає у створенні перекладу, який був би вірним духу оригіналу,\n"
 "а також відповідав цільовій мові, культурі та естетичним уподобанням "
 "читачів.\n"
@@ -1235,7 +1241,8 @@ msgstr "Спеціальний каталог"
 msgid ""
 "Customize the name of local node to be displayed in the environment "
 "indicator."
-msgstr "Налаштуйте назву локального вузла для відображення в індикаторі середовища."
+msgstr ""
+"Налаштуйте назву локального вузла для відображення в індикаторі середовища."
 
 #: src/views/backup/AutoBackup/components/CronEditor.vue:19
 msgid "Daily"
@@ -1268,13 +1275,14 @@ msgstr "Розшифрування не вдалося"
 
 #: src/views/dashboard/components/ParamsOpt/ProxyCacheConfig.vue:150
 msgid "Define shared memory zone name and size, e.g. proxy_cache:10m"
-msgstr "Вкажіть назву та розмір зони спільної пам'яті, наприклад proxy_cache:10m"
+msgstr ""
+"Вкажіть назву та розмір зони спільної пам'яті, наприклад proxy_cache:10m"
 
 #: src/components/NgxConfigEditor/NgxServer.vue:78
-#: src/components/NgxConfigEditor/NgxUpstream.vue:129 src/language/curd.ts:9
+#: src/components/NgxConfigEditor/NgxUpstream.vue:134 src/language/curd.ts:9
 #: src/views/certificate/components/RemoveCert.vue:88
 #: src/views/site/site_list/SiteList.vue:109
-#: src/views/stream/StreamList.vue:130
+#: src/views/stream/StreamList.vue:131
 msgid "Delete"
 msgstr "Видалити"
 
@@ -1588,7 +1596,8 @@ msgstr "Домен"
 
 #: src/views/certificate/CertificateEditor.vue:112
 msgid "Domains list is empty, try to reopen Auto Cert for %{config}"
-msgstr "Список доменів порожній, спробуйте знову відкрити Auto Cert для %{config}"
+msgstr ""
+"Список доменів порожній, спробуйте знову відкрити Auto Cert для %{config}"
 
 #: src/language/constants.ts:27
 msgid "Download latest release error"
@@ -1608,14 +1617,13 @@ msgid ""
 "Due to the security policies of some browsers, you cannot use passkeys on "
 "non-HTTPS websites, except when running on localhost."
 msgstr ""
-"Через політику безпеки деяких браузерів ви не можете використовувати "
-"пас-ключі на вебсайтах без HTTPS, окрім випадків, коли сайт працює на "
-"localhost."
+"Через політику безпеки деяких браузерів ви не можете використовувати пас-"
+"ключі на вебсайтах без HTTPS, окрім випадків, коли сайт працює на localhost."
 
 #: src/views/site/site_list/SiteDuplicate.vue:72
 #: src/views/site/site_list/SiteList.vue:95
 #: src/views/stream/components/StreamDuplicate.vue:64
-#: src/views/stream/StreamList.vue:116
+#: src/views/stream/StreamList.vue:117
 msgid "Duplicate"
 msgstr "Дублювати"
 
@@ -1796,7 +1804,7 @@ msgstr "Змінні середовища очищено"
 
 #: src/routes/modules/environments.ts:11
 #: src/views/dashboard/Environments.vue:83
-#: src/views/environments/list/Environment.vue:81
+#: src/views/environments/list/Environment.vue:82
 msgid "Environments"
 msgstr "Середовища"
 
@@ -2218,8 +2226,8 @@ msgid ""
 "Follow the instructions in the dialog to complete the passkey registration "
 "process."
 msgstr ""
-"Дотримуйтесь інструкцій у діалоговому вікні, щоб завершити процес "
-"реєстрації ключа доступу."
+"Дотримуйтесь інструкцій у діалоговому вікні, щоб завершити процес реєстрації "
+"ключа доступу."
 
 #: src/views/preference/tabs/NodeSettings.vue:42
 #: src/views/preference/tabs/NodeSettings.vue:54
@@ -2375,11 +2383,13 @@ msgstr ""
 msgid ""
 "If you want to automatically revoke the old certificate, please enable this "
 "option."
-msgstr "Якщо ви хочете автоматично відкликати старий сертифікат, увімкніть цю опцію."
+msgstr ""
+"Якщо ви хочете автоматично відкликати старий сертифікат, увімкніть цю опцію."
 
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:70
 msgid "If your browser supports WebAuthn Passkey, a dialog box will appear."
-msgstr "Якщо ваш браузер підтримує WebAuthn Passkey, з’явиться діалогове вікно."
+msgstr ""
+"Якщо ваш браузер підтримує WebAuthn Passkey, з’явиться діалогове вікно."
 
 #: src/components/AutoCertForm/AutoCertForm.vue:107
 msgid ""
@@ -2567,8 +2577,8 @@ msgid ""
 "Keep your recovery codes as safe as your password. We recommend saving them "
 "with a password manager."
 msgstr ""
-"Зберігайте ваші коди відновлення так само надійно, як і пароль. "
-"Рекомендуємо зберігати їх у менеджері паролів."
+"Зберігайте ваші коди відновлення так само надійно, як і пароль. Рекомендуємо "
+"зберігати їх у менеджері паролів."
 
 #: src/views/dashboard/components/ParamsOpt/PerformanceConfig.vue:60
 msgid "Keepalive Timeout"
@@ -2617,7 +2627,8 @@ msgstr "Залиште порожнім, щоб не змінювати"
 
 #: src/views/preference/tabs/OpenAISettings.vue:41
 msgid "Leave blank for the default: https://api.openai.com/"
-msgstr "Залиште порожнім для значення за замовчуванням: https://api.openai.com/"
+msgstr ""
+"Залиште порожнім для значення за замовчуванням: https://api.openai.com/"
 
 #: src/language/curd.ts:37
 msgid "Leave blank if do not want to modify"
@@ -2661,7 +2672,7 @@ msgstr "Прослуховує"
 msgid "Load Average:"
 msgstr "Середнє навантаження:"
 
-#: src/views/environments/list/Environment.vue:88
+#: src/views/environments/list/Environment.vue:89
 msgid "Load from settings"
 msgstr "Завантажити з налаштувань"
 
@@ -2722,13 +2733,12 @@ msgstr "Журнал"
 #: src/language/generate.ts:20
 msgid ""
 "Log file %{log_path} is not a regular file. If you are using nginx-ui in "
-"docker container, please refer to "
-"https://nginxui.com/zh_CN/guide/config-nginx-log.html for more information."
+"docker container, please refer to https://nginxui.com/zh_CN/guide/config-"
+"nginx-log.html for more information."
 msgstr ""
-"Файл журналу %{log_path} не є звичайним файлом. Якщо ви використовуєте "
-"nginx-ui у контейнері Docker, будь ласка, зверніться до "
-"https://nginxui.com/zh_CN/guide/config-nginx-log.html для отримання "
-"додаткової інформації."
+"Файл журналу %{log_path} не є звичайним файлом. Якщо ви використовуєте nginx-"
+"ui у контейнері Docker, будь ласка, зверніться до https://nginxui.com/zh_CN/"
+"guide/config-nginx-log.html для отримання додаткової інформації."
 
 #: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:72
 msgid "Log List"
@@ -2752,16 +2762,16 @@ msgstr "Logrotate"
 
 #: src/views/preference/tabs/LogrotateSettings.vue:13
 msgid ""
-"Logrotate, by default, is enabled in most mainstream Linux distributions "
-"for users who install Nginx UI on the host machine, so you don't need to "
-"modify the parameters on this page. For users who install Nginx UI using "
-"Docker containers, you can manually enable this option. The crontab task "
-"scheduler of Nginx UI will execute the logrotate command at the interval "
-"you set in minutes."
+"Logrotate, by default, is enabled in most mainstream Linux distributions for "
+"users who install Nginx UI on the host machine, so you don't need to modify "
+"the parameters on this page. For users who install Nginx UI using Docker "
+"containers, you can manually enable this option. The crontab task scheduler "
+"of Nginx UI will execute the logrotate command at the interval you set in "
+"minutes."
 msgstr ""
 "Logrotate за замовчуванням увімкнено у більшості популярних дистрибутивів "
-"Linux для користувачів, які встановлюють Nginx UI безпосередньо на "
-"хост-машині, тому вам не потрібно змінювати параметри на цій сторінці. Для "
+"Linux для користувачів, які встановлюють Nginx UI безпосередньо на хост-"
+"машині, тому вам не потрібно змінювати параметри на цій сторінці. Для "
 "користувачів, які встановлюють Nginx UI за допомогою контейнерів Docker, ви "
 "можете вручну активувати цю опцію. Планувальник завдань crontab у Nginx UI "
 "виконуватиме команду logrotate з інтервалом, який ви встановите у хвилинах."
@@ -2958,7 +2968,7 @@ msgstr "Щомісяця %{day} числа о %{time}"
 msgid "Multi-line Directive"
 msgstr "Багаторядкова директива"
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:182
+#: src/components/NgxConfigEditor/NgxUpstream.vue:189
 #: src/views/backup/AutoBackup/AutoBackup.vue:11
 #: src/views/certificate/ACMEUser.vue:11
 #: src/views/certificate/CertificateEditor.vue:162
@@ -2976,7 +2986,7 @@ msgstr "Багаторядкова директива"
 #: src/views/stream/columns.tsx:12
 #: src/views/stream/components/RightPanel/Basic.vue:72
 #: src/views/stream/components/StreamDuplicate.vue:71
-#: src/views/stream/StreamList.vue:143
+#: src/views/stream/StreamList.vue:144
 msgid "Name"
 msgstr "Ім'я"
 
@@ -3207,8 +3217,8 @@ msgstr "Конфігурацію Nginx UI відновлено"
 
 #: src/components/SystemRestore/SystemRestoreContent.vue:336
 msgid ""
-"Nginx UI configuration has been restored and will restart automatically in "
-"a few seconds."
+"Nginx UI configuration has been restored and will restart automatically in a "
+"few seconds."
 msgstr ""
 "Конфігурацію Nginx UI відновлено, і вона автоматично перезавантажиться за "
 "кілька секунд."
@@ -3234,7 +3244,7 @@ msgstr "Nginx.conf включає каталог streams-enabled"
 #: src/views/notification/Notification.vue:38
 #: src/views/preference/tabs/AuthSettings.vue:132
 #: src/views/preference/tabs/CertSettings.vue:73
-#: src/views/site/site_list/SiteList.vue:98 src/views/stream/StreamList.vue:119
+#: src/views/site/site_list/SiteList.vue:98 src/views/stream/StreamList.vue:120
 msgid "No"
 msgstr "Ні"
 
@@ -3369,7 +3379,7 @@ msgid "Off"
 msgstr "Вимкнено"
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:159
-#: src/components/NgxConfigEditor/NgxUpstream.vue:145
+#: src/components/NgxConfigEditor/NgxUpstream.vue:151
 #: src/components/NodeSelector/NodeSelector.vue:109
 #: src/components/ProxyTargets/ProxyTargets.vue:43
 #: src/views/dashboard/Environments.vue:107
@@ -3390,7 +3400,7 @@ msgstr "Офлайн"
 #: src/views/site/site_list/SiteList.vue:99
 #: src/views/stream/components/RightPanel/Basic.vue:48
 #: src/views/stream/components/StreamStatusSelect.vue:60
-#: src/views/stream/StreamList.vue:120
+#: src/views/stream/StreamList.vue:121
 msgid "OK"
 msgstr "Гаразд"
 
@@ -3612,7 +3622,8 @@ msgstr "Будь ласка, введіть токен безпеки"
 #: src/components/SystemRestore/SystemRestoreContent.vue:210
 #: src/components/SystemRestore/SystemRestoreContent.vue:287
 msgid "Please enter the security token received during backup"
-msgstr "Будь ласка, введіть токен безпеки, отриманий під час резервного копіювання"
+msgstr ""
+"Будь ласка, введіть токен безпеки, отриманий під час резервного копіювання"
 
 #: src/language/curd.ts:24
 msgid "Please fill all fields correctly"
@@ -3640,8 +3651,8 @@ msgstr ""
 #: src/components/Notification/notifications.ts:182
 #: src/language/constants.ts:59
 msgid ""
-"Please generate new recovery codes in the preferences immediately to "
-"prevent lockout."
+"Please generate new recovery codes in the preferences immediately to prevent "
+"lockout."
 msgstr ""
 "Будь ласка, негайно згенеруйте нові коди відновлення в налаштуваннях, щоб "
 "уникнути блокування."
@@ -3689,7 +3700,8 @@ msgid "Please log in."
 msgstr "Будь ласка, увійдіть."
 
 #: src/views/certificate/DNSCredential.vue:61
-msgid "Please note that the unit of time configurations below are all in seconds."
+msgid ""
+"Please note that the unit of time configurations below are all in seconds."
 msgstr ""
 "Будь ласка, зверніть увагу, що одиницею виміру часу в наведених нижче "
 "налаштуваннях є секунди."
@@ -3701,8 +3713,7 @@ msgstr "Будь ласка, усуньте всі проблеми перед 
 #: src/views/backup/components/BackupCreator.vue:107
 msgid "Please save this security token, you will need it for restoration:"
 msgstr ""
-"Будь ласка, збережіть цей токен безпеки, він знадобиться вам для "
-"відновлення:"
+"Будь ласка, збережіть цей токен безпеки, він знадобиться вам для відновлення:"
 
 #: src/components/SystemRestore/SystemRestoreContent.vue:107
 msgid "Please select a backup file"
@@ -3712,17 +3723,17 @@ msgstr "Будь ласка, виберіть файл резервної коп
 msgid "Please select at least one item"
 msgstr "Будь ласка, виберіть хоча б один елемент"
 
-#: src/views/environments/list/Environment.vue:120
+#: src/views/environments/list/Environment.vue:121
 #: src/views/environments/list/Environment.vue:35
 msgid "Please select at least one node to reload Nginx"
 msgstr "Будь ласка, виберіть принаймні один вузол для перезавантаження Nginx"
 
-#: src/views/environments/list/Environment.vue:141
+#: src/views/environments/list/Environment.vue:142
 #: src/views/environments/list/Environment.vue:49
 msgid "Please select at least one node to restart Nginx"
 msgstr "Будь ласка, виберіть принаймні один вузол для перезапуску Nginx"
 
-#: src/views/environments/list/Environment.vue:99
+#: src/views/environments/list/Environment.vue:100
 msgid "Please select at least one node to upgrade"
 msgstr "Будь ласка, виберіть принаймні один вузол для оновлення"
 
@@ -3735,7 +3746,7 @@ msgstr "Будь ласка, введіть \"Скасувати\" для під
 msgid "Port"
 msgstr "Порт"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:44
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:45
 #: src/views/stream/components/RightPanel/RightPanel.vue:26
 msgid "Port Scanner"
 msgstr "Сканер портів"
@@ -3907,8 +3918,8 @@ msgstr "Перезавантажити"
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:136
 #: src/views/environments/group/columns.ts:22
 #: src/views/environments/group/EnvGroup.vue:50
-#: src/views/environments/list/Environment.vue:128
-#: src/views/environments/list/Environment.vue:136
+#: src/views/environments/list/Environment.vue:129
+#: src/views/environments/list/Environment.vue:137
 msgid "Reload Nginx"
 msgstr "Перезавантажити Nginx"
 
@@ -3959,7 +3970,7 @@ msgstr "Успішно видалено"
 msgid "Removed successfully"
 msgstr "Успішно видалено"
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:126
+#: src/components/NgxConfigEditor/NgxUpstream.vue:131
 #: src/views/config/components/ConfigName.vue:51
 #: src/views/config/components/Rename.vue:56
 #: src/views/config/ConfigList.vue:181
@@ -4076,9 +4087,9 @@ msgid ""
 "shared library memory, which will be repeated calculated for multiple "
 "processes"
 msgstr ""
-"Розмір резидентного набору: Фактична пам'ять, резидентна у фізичній "
-"пам'яті, включаючи всю пам'ять спільних бібліотек, яка буде повторно "
-"обчислюватися для кількох процесів"
+"Розмір резидентного набору: Фактична пам'ять, резидентна у фізичній пам'яті, "
+"включаючи всю пам'ять спільних бібліотек, яка буде повторно обчислюватися "
+"для кількох процесів"
 
 #: src/composables/usePerformanceMetrics.ts:109
 #: src/views/dashboard/components/PerformanceTablesCard.vue:69
@@ -4090,8 +4101,8 @@ msgid "Restart"
 msgstr "Перезавантажити"
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:148
-#: src/views/environments/list/Environment.vue:149
-#: src/views/environments/list/Environment.vue:157
+#: src/views/environments/list/Environment.vue:150
+#: src/views/environments/list/Environment.vue:158
 msgid "Restart Nginx"
 msgstr "Перезапустити Nginx"
 
@@ -4517,21 +4528,19 @@ msgstr "Налаштування провайдера HTTP01-виклику"
 
 #: src/constants/errors/nginx_log.ts:8
 msgid ""
-"Settings.NginxLogSettings.AccessLogPath is empty, refer to "
-"https://nginxui.com/guide/config-nginx.html for more information"
+"Settings.NginxLogSettings.AccessLogPath is empty, refer to https://nginxui."
+"com/guide/config-nginx.html for more information"
 msgstr ""
-"Settings.NginxLogSettings.AccessLogPath порожній, див. "
-"https://nginxui.com/guide/config-nginx.html для отримання додаткової "
-"інформації"
+"Settings.NginxLogSettings.AccessLogPath порожній, див. https://nginxui.com/"
+"guide/config-nginx.html для отримання додаткової інформації"
 
 #: src/constants/errors/nginx_log.ts:7
 msgid ""
-"Settings.NginxLogSettings.ErrorLogPath is empty, refer to "
-"https://nginxui.com/guide/config-nginx.html for more information"
+"Settings.NginxLogSettings.ErrorLogPath is empty, refer to https://nginxui."
+"com/guide/config-nginx.html for more information"
 msgstr ""
-"Settings.NginxLogSettings.ErrorLogPath порожній, див. "
-"https://nginxui.com/guide/config-nginx.html для отримання додаткової "
-"інформації"
+"Settings.NginxLogSettings.ErrorLogPath порожній, див. https://nginxui.com/"
+"guide/config-nginx.html для отримання додаткової інформації"
 
 #: src/views/install/components/InstallView.vue:65
 msgid "Setup your Nginx UI"
@@ -4611,7 +4620,8 @@ msgstr "Вміст SSL-сертифіката"
 
 #: src/constants/errors/system.ts:8
 msgid "SSL certificate file must be under Nginx configuration directory: {0}"
-msgstr "Файл SSL-сертифіката повинен знаходитися в каталозі конфігурації Nginx: {0}"
+msgstr ""
+"Файл SSL-сертифіката повинен знаходитися в каталозі конфігурації Nginx: {0}"
 
 #: src/constants/errors/system.ts:6
 msgid "SSL certificate file not found"
@@ -4764,25 +4774,25 @@ msgstr "Неділя"
 msgid ""
 "Support communication with the backend through the Server-Sent Events "
 "protocol. If your Nginx UI is being used via an Nginx reverse proxy, please "
-"refer to this link to write the corresponding configuration file: "
-"https://nginxui.com/guide/nginx-proxy-example.html"
+"refer to this link to write the corresponding configuration file: https://"
+"nginxui.com/guide/nginx-proxy-example.html"
 msgstr ""
 "Підтримка зв’язку з бекендом через протокол Server-Sent Events. Якщо ваш "
 "Nginx UI використовується через зворотний проксі Nginx, перейдіть за цим "
-"посиланням, щоб написати відповідний конфігураційний файл: "
-"https://nginxui.com/guide/nginx-proxy-example.html"
+"посиланням, щоб написати відповідний конфігураційний файл: https://nginxui."
+"com/guide/nginx-proxy-example.html"
 
 #: src/components/SelfCheck/tasks/frontend/websocket.ts:13
 msgid ""
 "Support communication with the backend through the WebSocket protocol. If "
-"your Nginx UI is being used via an Nginx reverse proxy, please refer to "
-"this link to write the corresponding configuration file: "
-"https://nginxui.com/guide/nginx-proxy-example.html"
+"your Nginx UI is being used via an Nginx reverse proxy, please refer to this "
+"link to write the corresponding configuration file: https://nginxui.com/"
+"guide/nginx-proxy-example.html"
 msgstr ""
 "Підтримка зв'язку з бекендом через протокол WebSocket. Якщо ваш Nginx UI "
-"використовується через зворотний проксі Nginx, перегляньте це посилання, "
-"щоб написати відповідний конфігураційний файл: "
-"https://nginxui.com/guide/nginx-proxy-example.html"
+"використовується через зворотний проксі Nginx, перегляньте це посилання, щоб "
+"написати відповідний конфігураційний файл: https://nginxui.com/guide/nginx-"
+"proxy-example.html"
 
 #: src/language/curd.ts:51 src/language/curd.ts:55
 msgid "Support single or batch upload of files"
@@ -4948,11 +4958,10 @@ msgstr "Введений текст не є ключем SSL-сертифіка
 
 #: src/constants/errors/nginx_log.ts:2
 msgid ""
-"The log path is not under the paths in "
-"settings.NginxSettings.LogDirWhiteList"
+"The log path is not under the paths in settings.NginxSettings.LogDirWhiteList"
 msgstr ""
-"Шлях до журналу не знаходиться серед шляхів у "
-"settings.NginxSettings.LogDirWhiteList"
+"Шлях до журналу не знаходиться серед шляхів у settings.NginxSettings."
+"LogDirWhiteList"
 
 #: src/views/preference/tabs/OpenAISettings.vue:23
 #: src/views/preference/tabs/OpenAISettings.vue:89
@@ -4964,7 +4973,8 @@ msgstr ""
 "двокрапки та крапки."
 
 #: src/views/preference/tabs/OpenAISettings.vue:90
-msgid "The model used for code completion, if not set, the chat model will be used."
+msgid ""
+"The model used for code completion, if not set, the chat model will be used."
 msgstr ""
 "Модель, яка використовується для завершення коду. Якщо вона не встановлена, "
 "буде використовуватися модель чату."
@@ -5050,8 +5060,7 @@ msgstr ""
 #: src/views/certificate/CertificateEditor.vue:102
 msgid "This Auto Cert item is invalid, please remove it."
 msgstr ""
-"Цей елемент автоматичного сертифікату є недійсним, будь ласка, видаліть "
-"його."
+"Цей елемент автоматичного сертифікату є недійсним, будь ласка, видаліть його."
 
 #: src/views/certificate/CertificateEditor.vue:92
 msgid "This certificate is managed by Nginx UI"
@@ -5076,13 +5085,14 @@ msgid "This field should not be empty"
 msgstr "Це поле не повинно бути порожнім"
 
 #: src/constants/form_errors.ts:6
-msgid "This field should only contain letters, unicode characters, numbers, and -_."
+msgid ""
+"This field should only contain letters, unicode characters, numbers, and -_."
 msgstr "Це поле має містити лише літери, символи Unicode, цифри та -_."
 
 #: src/language/curd.ts:44
 msgid ""
-"This field should only contain letters, unicode characters, numbers, and "
-"-_./:"
+"This field should only contain letters, unicode characters, numbers, and -"
+"_./:"
 msgstr "Це поле має містити лише літери, символи Unicode, цифри та -_./:"
 
 #: src/views/dashboard/NginxDashBoard.vue:150
@@ -5132,8 +5142,10 @@ msgstr ""
 "після завершення відновлення."
 
 #: src/views/environments/list/BatchUpgrader.vue:182
-msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
-msgstr "Це оновить або перевстановить Nginx UI на %{nodeNames} до версії %{version}."
+msgid ""
+"This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
+msgstr ""
+"Це оновить або перевстановить Nginx UI на %{nodeNames} до версії %{version}."
 
 #: src/views/preference/tabs/AuthSettings.vue:92
 msgid "Throttle"
@@ -5170,8 +5182,8 @@ msgid ""
 "To enable it, you need to install the Google or Microsoft Authenticator app "
 "on your mobile phone."
 msgstr ""
-"Щоб увімкнути його, вам потрібно встановити додаток Google Authenticator "
-"або Microsoft Authenticator на свій мобільний телефон."
+"Щоб увімкнути його, вам потрібно встановити додаток Google Authenticator або "
+"Microsoft Authenticator на свій мобільний телефон."
 
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:89
 msgid ""
@@ -5180,15 +5192,15 @@ msgid ""
 "and restart Nginx UI."
 msgstr ""
 "Для забезпечення безпеки конфігурацію WebAuthn не можна додати через "
-"інтерфейс. Будь ласка, налаштуйте вручну наступне у файлі конфігурації "
-"app.ini та перезапустіть Nginx UI."
+"інтерфейс. Будь ласка, налаштуйте вручну наступне у файлі конфігурації app."
+"ini та перезапустіть Nginx UI."
 
 #: src/views/site/site_edit/components/Cert/IssueCert.vue:34
 #: src/views/site/site_edit/components/EnableTLS/EnableTLS.vue:15
 msgid ""
 "To make sure the certification auto-renewal can work normally, we need to "
-"add a location which can proxy the request from authority to backend, and "
-"we need to save this file and reload the Nginx. Are you sure you want to "
+"add a location which can proxy the request from authority to backend, and we "
+"need to save this file and reload the Nginx. Are you sure you want to "
 "continue?"
 msgstr ""
 "Щоб гарантувати нормальну роботу автоматичного поновлення сертифікатів, нам "
@@ -5313,8 +5325,8 @@ msgid "Updated at"
 msgstr "Оновлено"
 
 #: src/routes/modules/system.ts:26
-#: src/views/environments/list/Environment.vue:107
-#: src/views/environments/list/Environment.vue:115
+#: src/views/environments/list/Environment.vue:108
+#: src/views/environments/list/Environment.vue:116
 #: src/views/system/Upgrade.vue:154 src/views/system/Upgrade.vue:159
 msgid "Upgrade"
 msgstr "Оновити"
@@ -5344,7 +5356,7 @@ msgstr "Завантажити папки"
 msgid "Upstream"
 msgstr "Вгору за течією"
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:177
+#: src/components/NgxConfigEditor/NgxUpstream.vue:184
 msgid "Upstream Name"
 msgstr "Назва апстріму"
 
@@ -5474,8 +5486,8 @@ msgstr ""
 
 #: src/views/site/site_edit/components/Cert/ObtainCert.vue:140
 msgid ""
-"We will remove the HTTPChallenge configuration from this file and reload "
-"the Nginx. Are you sure you want to continue?"
+"We will remove the HTTPChallenge configuration from this file and reload the "
+"Nginx. Are you sure you want to continue?"
 msgstr ""
 "Ми видалимо конфігурацію HTTPChallenge з цього файлу та перезавантажимо "
 "Nginx. Ви впевнені, що хочете продовжити?"
@@ -5579,8 +5591,8 @@ msgstr "Так"
 
 #: src/views/terminal/Terminal.vue:132
 msgid ""
-"You are accessing this terminal over an insecure HTTP connection on a "
-"non-localhost domain. This may expose sensitive information."
+"You are accessing this terminal over an insecure HTTP connection on a non-"
+"localhost domain. This may expose sensitive information."
 msgstr ""
 "Ви отримуєте доступ до цього терміналу через незахищене HTTP-з’єднання в "
 "домені, який не є локальним. Це може призвести до витоку конфіденційної "
@@ -5606,13 +5618,15 @@ msgstr "Тепер ви можете закрити це діалогове ві
 msgid ""
 "You have not configured the settings of Webauthn, so you cannot add a "
 "passkey."
-msgstr "Ви не налаштували параметри WebAuthn, тому не можете додати ключ доступу."
+msgstr ""
+"Ви не налаштували параметри WebAuthn, тому не можете додати ключ доступу."
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:81
-msgid "You have not enabled 2FA yet. Please enable 2FA to generate recovery codes."
+msgid ""
+"You have not enabled 2FA yet. Please enable 2FA to generate recovery codes."
 msgstr ""
-"Ви ще не ввімкнули двофакторну аутентифікацію. Будь ласка, увімкніть її, "
-"щоб згенерувати коди відновлення."
+"Ви ще не ввімкнули двофакторну аутентифікацію. Будь ласка, увімкніть її, щоб "
+"згенерувати коди відновлення."
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:94
 msgid "You have not generated recovery codes yet."
@@ -5695,12 +5709,12 @@ msgstr "Ваші ключі доступу"
 
 #~ msgid ""
 #~ "Check if /var/run/docker.sock exists. If you are using Nginx UI Official "
-#~ "Docker Image, please make sure the docker socket is mounted like this: `-v "
-#~ "/var/run/docker.sock:/var/run/docker.sock`."
+#~ "Docker Image, please make sure the docker socket is mounted like this: `-"
+#~ "v /var/run/docker.sock:/var/run/docker.sock`."
 #~ msgstr ""
-#~ "Перевірте, чи існує /var/run/docker.sock. Якщо ви використовуєте офіційний "
-#~ "Docker-образ Nginx UI, переконайтеся, що сокет Docker підключено таким "
-#~ "чином: `-v /var/run/docker.sock:/var/run/docker.sock`."
+#~ "Перевірте, чи існує /var/run/docker.sock. Якщо ви використовуєте "
+#~ "офіційний Docker-образ Nginx UI, переконайтеся, що сокет Docker "
+#~ "підключено таким чином: `-v /var/run/docker.sock:/var/run/docker.sock`."
 
 #~ msgid "Check if the nginx access log path exists"
 #~ msgstr "Перевірити, чи існує шлях до журналу доступу nginx"

+ 209 - 190
app/src/language/vi_VN/app.po

@@ -5,13 +5,14 @@ msgstr ""
 "Language-Team: none\n"
 "Language: vi_VN\n"
 "MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=utf-8\n"
+"Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 
 #: src/language/generate.ts:31
 msgid "[Nginx UI] ACME User: %{name}, Email: %{email}, CA Dir: %{caDir}"
-msgstr "[Nginx UI] Người dùng ACME: %{name}, Email: %{email}, Thư mục CA: %{caDir}"
+msgstr ""
+"[Nginx UI] Người dùng ACME: %{name}, Email: %{email}, Thư mục CA: %{caDir}"
 
 #: src/language/generate.ts:32
 msgid "[Nginx UI] Backing up current certificate for later revocation"
@@ -26,10 +27,11 @@ msgid "[Nginx UI] Certificate successfully revoked"
 msgstr "[Nginx UI] Hủy chứng chỉ thành công"
 
 #: src/language/generate.ts:35
-msgid "[Nginx UI] Certificate was used for server, reloading server TLS certificate"
+msgid ""
+"[Nginx UI] Certificate was used for server, reloading server TLS certificate"
 msgstr ""
-"[Nginx UI] Chứng chỉ đã được sử dụng cho máy chủ, đang tải lại chứng chỉ "
-"TLS của máy chủ"
+"[Nginx UI] Chứng chỉ đã được sử dụng cho máy chủ, đang tải lại chứng chỉ TLS "
+"của máy chủ"
 
 #: src/language/generate.ts:36
 msgid "[Nginx UI] Creating client facilitates communication with the CA server"
@@ -154,10 +156,10 @@ msgid "Actual worker to configured ratio"
 msgstr "Tỷ lệ công nhân thực tế so với cấu hình"
 
 #: src/components/NgxConfigEditor/NgxServer.vue:112
-#: src/components/NgxConfigEditor/NgxUpstream.vue:159 src/language/curd.ts:19
+#: src/components/NgxConfigEditor/NgxUpstream.vue:166 src/language/curd.ts:19
 #: src/views/preference/tabs/CertSettings.vue:45
 #: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:94
-#: src/views/stream/StreamList.vue:101
+#: src/views/stream/StreamList.vue:102
 msgid "Add"
 msgstr "Thêm"
 
@@ -184,7 +186,7 @@ msgstr "Thêm Location"
 msgid "Add Site"
 msgstr "Thêm Website"
 
-#: src/views/stream/StreamList.vue:138
+#: src/views/stream/StreamList.vue:139
 msgid "Add Stream"
 msgstr "Thêm luồng"
 
@@ -272,7 +274,7 @@ msgid "Are you sure you want to delete permanently?"
 msgstr "Bạn có chắc chắn muốn xóa vĩnh viễn không?"
 
 #: src/language/curd.ts:25 src/views/site/site_list/SiteList.vue:100
-#: src/views/stream/StreamList.vue:121
+#: src/views/stream/StreamList.vue:122
 msgid "Are you sure you want to delete?"
 msgstr "Bạn có chắc chắn muốn xóa không?"
 
@@ -294,7 +296,8 @@ msgstr "Bạn có chắc chắn muốn xóa vị trí này không?"
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:141
 msgid "Are you sure you want to restart Nginx on the following sync nodes?"
-msgstr "Bạn có chắc chắn muốn khởi động lại Nginx trên các nút đồng bộ sau không?"
+msgstr ""
+"Bạn có chắc chắn muốn khởi động lại Nginx trên các nút đồng bộ sau không?"
 
 #: src/language/curd.ts:26
 msgid "Are you sure you want to restore?"
@@ -410,7 +413,8 @@ msgstr "Sao lưu"
 
 #: src/components/SystemRestore/SystemRestoreContent.vue:155
 msgid "Backup file integrity check failed, it may have been tampered with"
-msgstr "Kiểm tra tính toàn vẹn của tập tin sao lưu thất bại, có thể đã bị can thiệp"
+msgstr ""
+"Kiểm tra tính toàn vẹn của tập tin sao lưu thất bại, có thể đã bị can thiệp"
 
 #: src/constants/errors/backup.ts:41
 msgid "Backup file not found: {0}"
@@ -446,13 +450,15 @@ msgstr "Lịch trình sao lưu"
 
 #: src/components/Notification/notifications.ts:38
 msgid "Backup task %{backup_name} completed successfully, file: %{file_path}"
-msgstr "Tác vụ sao lưu %{backup_name} đã hoàn thành thành công, tệp: %{file_path}"
+msgstr ""
+"Tác vụ sao lưu %{backup_name} đã hoàn thành thành công, tệp: %{file_path}"
 
 #: src/components/Notification/notifications.ts:34
-msgid "Backup task %{backup_name} failed during storage upload, error: %{error}"
+msgid ""
+"Backup task %{backup_name} failed during storage upload, error: %{error}"
 msgstr ""
-"Tác vụ sao lưu %{backup_name} thất bại trong quá trình tải lên lưu trữ, "
-"lỗi: %{error}"
+"Tác vụ sao lưu %{backup_name} thất bại trong quá trình tải lên lưu trữ, lỗi: "
+"%{error}"
 
 #: src/components/Notification/notifications.ts:30
 msgid "Backup task %{backup_name} failed to execute, error: %{error}"
@@ -483,7 +489,7 @@ msgid "Base information"
 msgstr "Thông tin"
 
 #: src/views/config/ConfigEditor.vue:300
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:31
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:32
 #: src/views/stream/components/RightPanel/RightPanel.vue:20
 msgid "Basic"
 msgstr "Cơ bản"
@@ -725,7 +731,7 @@ msgstr "Đường dẫn đã thay đổi"
 msgid "Channel"
 msgstr "Kênh"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:41
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:42
 #: src/views/stream/components/RightPanel/RightPanel.vue:23
 msgid "Chat"
 msgstr "Trò chuyện"
@@ -742,13 +748,13 @@ msgstr "Kiểm tra lại"
 #: src/language/generate.ts:6
 msgid ""
 "Check if /var/run/docker.sock exists. If you are using Nginx UI Official "
-"Docker Image, please make sure the docker socket is mounted like this: `-v "
-"/var/run/docker.sock:/var/run/docker.sock`. Nginx UI official image uses "
-"/var/run/docker.sock to communicate with the host Docker Engine via Docker "
-"Client API. This feature is used to control Nginx in another container and "
-"perform container replacement rather than binary replacement during OTA "
-"upgrades of Nginx UI to ensure container dependencies are also upgraded. If "
-"you don't need this feature, please add the environment variable "
+"Docker Image, please make sure the docker socket is mounted like this: `-v /"
+"var/run/docker.sock:/var/run/docker.sock`. Nginx UI official image uses /var/"
+"run/docker.sock to communicate with the host Docker Engine via Docker Client "
+"API. This feature is used to control Nginx in another container and perform "
+"container replacement rather than binary replacement during OTA upgrades of "
+"Nginx UI to ensure container dependencies are also upgraded. If you don't "
+"need this feature, please add the environment variable "
 "NGINX_UI_IGNORE_DOCKER_SOCKET=true to the container."
 msgstr ""
 "Kiểm tra xem /var/run/docker.sock có tồn tại không. Nếu bạn đang sử dụng "
@@ -767,23 +773,23 @@ msgid ""
 "Check if HTTPS is enabled. Using HTTP outside localhost is insecure and "
 "prevents using Passkeys and clipboard features"
 msgstr ""
-"Kiểm tra xem HTTPS có được bật không. Sử dụng HTTP bên ngoài localhost "
-"không an toàn và ngăn chặn việc sử dụng tính năng Passkeys và clipboard"
+"Kiểm tra xem HTTPS có được bật không. Sử dụng HTTP bên ngoài localhost không "
+"an toàn và ngăn chặn việc sử dụng tính năng Passkeys và clipboard"
 
 #: src/language/generate.ts:8
 msgid ""
-"Check if the nginx access log path exists. By default, this path is "
-"obtained from 'nginx -V'. If it cannot be obtained or the obtained path "
-"does not point to a valid, existing file, an error will be reported. In "
-"this case, you need to modify the configuration file to specify the access "
-"log path.Refer to the docs for more details: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#accesslogpath"
+"Check if the nginx access log path exists. By default, this path is obtained "
+"from 'nginx -V'. If it cannot be obtained or the obtained path does not "
+"point to a valid, existing file, an error will be reported. In this case, "
+"you need to modify the configuration file to specify the access log path."
+"Refer to the docs for more details: https://nginxui.com/zh_CN/guide/config-"
+"nginx.html#accesslogpath"
 msgstr ""
 "Kiểm tra xem đường dẫn nhật ký truy cập nginx có tồn tại không. Theo mặc "
 "định, đường dẫn này được lấy từ 'nginx -V'. Nếu không thể lấy được hoặc "
 "đường dẫn lấy được không trỏ đến một tệp hợp lệ đang tồn tại, một lỗi sẽ "
-"được báo cáo. Trong trường hợp này, bạn cần sửa đổi tệp cấu hình để chỉ "
-"định đường dẫn nhật ký truy cập. Tham khảo tài liệu để biết thêm chi tiết: "
+"được báo cáo. Trong trường hợp này, bạn cần sửa đổi tệp cấu hình để chỉ định "
+"đường dẫn nhật ký truy cập. Tham khảo tài liệu để biết thêm chi tiết: "
 "https://nginxui.com/zh_CN/guide/config-nginx.html#accesslogpath"
 
 #: src/language/generate.ts:9
@@ -799,30 +805,30 @@ msgid ""
 "Check if the nginx error log path exists. By default, this path is obtained "
 "from 'nginx -V'. If it cannot be obtained or the obtained path does not "
 "point to a valid, existing file, an error will be reported. In this case, "
-"you need to modify the configuration file to specify the error log "
-"path.Refer to the docs for more details: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#errorlogpath"
+"you need to modify the configuration file to specify the error log path."
+"Refer to the docs for more details: https://nginxui.com/zh_CN/guide/config-"
+"nginx.html#errorlogpath"
 msgstr ""
 "Kiểm tra xem đường dẫn nhật ký lỗi của nginx có tồn tại không. Theo mặc "
 "định, đường dẫn này được lấy từ 'nginx -V'. Nếu không thể lấy được hoặc "
 "đường dẫn lấy được không trỏ đến một tệp hợp lệ đang tồn tại, một lỗi sẽ "
-"được báo cáo. Trong trường hợp này, bạn cần sửa đổi tệp cấu hình để chỉ "
-"định đường dẫn nhật ký lỗi. Tham khảo tài liệu để biết thêm chi tiết: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#errorlogpath"
+"được báo cáo. Trong trường hợp này, bạn cần sửa đổi tệp cấu hình để chỉ định "
+"đường dẫn nhật ký lỗi. Tham khảo tài liệu để biết thêm chi tiết: https://"
+"nginxui.com/zh_CN/guide/config-nginx.html#errorlogpath"
 
 #: src/language/generate.ts:7
 msgid ""
 "Check if the nginx PID path exists. By default, this path is obtained from "
 "'nginx -V'. If it cannot be obtained, an error will be reported. In this "
 "case, you need to modify the configuration file to specify the Nginx PID "
-"path.Refer to the docs for more details: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#pidpath"
+"path.Refer to the docs for more details: https://nginxui.com/zh_CN/guide/"
+"config-nginx.html#pidpath"
 msgstr ""
 "Kiểm tra xem đường dẫn PID của Nginx có tồn tại không. Theo mặc định, đường "
-"dẫn này được lấy từ lệnh 'nginx -V'. Nếu không thể lấy được, một lỗi sẽ "
-"được báo cáo. Trong trường hợp này, bạn cần sửa đổi tệp cấu hình để chỉ "
-"định đường dẫn PID của Nginx. Tham khảo tài liệu để biết thêm chi tiết: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#pidpath"
+"dẫn này được lấy từ lệnh 'nginx -V'. Nếu không thể lấy được, một lỗi sẽ được "
+"báo cáo. Trong trường hợp này, bạn cần sửa đổi tệp cấu hình để chỉ định "
+"đường dẫn PID của Nginx. Tham khảo tài liệu để biết thêm chi tiết: https://"
+"nginxui.com/zh_CN/guide/config-nginx.html#pidpath"
 
 #: src/language/generate.ts:12
 msgid "Check if the nginx.conf includes the conf.d directory"
@@ -846,8 +852,8 @@ msgstr ""
 
 #: src/language/generate.ts:16
 msgid ""
-"Check if the streams-available and streams-enabled directories are under "
-"the nginx configuration directory"
+"Check if the streams-available and streams-enabled directories are under the "
+"nginx configuration directory"
 msgstr ""
 "Kiểm tra xem các thư mục streams-available và streams-enabled có nằm trong "
 "thư mục cấu hình nginx không"
@@ -976,7 +982,7 @@ msgstr "Tệp nhập cấu hình không tồn tại"
 msgid "Config path is empty"
 msgstr "Đường dẫn cấu hình trống"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:37
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:38
 msgid "Config Template"
 msgstr "Mẫu cấu hình"
 
@@ -1072,7 +1078,7 @@ msgstr "Mức sử dụng CPU tương đối cao, hãy cân nhắc tối ưu c
 msgid "CPU:"
 msgstr "CPU:"
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:170
+#: src/components/NgxConfigEditor/NgxUpstream.vue:177
 msgid "Create"
 msgstr "Tạo"
 
@@ -1097,8 +1103,8 @@ msgid ""
 "Create system backups including Nginx configuration and Nginx UI settings. "
 "Backup files will be automatically downloaded to your computer."
 msgstr ""
-"Tạo bản sao lưu hệ thống bao gồm cấu hình Nginx và cài đặt Nginx UI. Các "
-"tệp sao lưu sẽ tự động được tải xuống máy tính của bạn."
+"Tạo bản sao lưu hệ thống bao gồm cấu hình Nginx và cài đặt Nginx UI. Các tệp "
+"sao lưu sẽ tự động được tải xuống máy tính của bạn."
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:229
 #: src/views/environments/group/columns.ts:29
@@ -1208,13 +1214,14 @@ msgstr "Giải mã thất bại"
 
 #: src/views/dashboard/components/ParamsOpt/ProxyCacheConfig.vue:150
 msgid "Define shared memory zone name and size, e.g. proxy_cache:10m"
-msgstr "Xác định tên và kích thước vùng bộ nhớ dùng chung, ví dụ proxy_cache:10m"
+msgstr ""
+"Xác định tên và kích thước vùng bộ nhớ dùng chung, ví dụ proxy_cache:10m"
 
 #: src/components/NgxConfigEditor/NgxServer.vue:78
-#: src/components/NgxConfigEditor/NgxUpstream.vue:129 src/language/curd.ts:9
+#: src/components/NgxConfigEditor/NgxUpstream.vue:134 src/language/curd.ts:9
 #: src/views/certificate/components/RemoveCert.vue:88
 #: src/views/site/site_list/SiteList.vue:109
-#: src/views/stream/StreamList.vue:130
+#: src/views/stream/StreamList.vue:131
 msgid "Delete"
 msgstr "Xoá"
 
@@ -1520,7 +1527,7 @@ msgstr ""
 #: src/views/site/site_list/SiteDuplicate.vue:72
 #: src/views/site/site_list/SiteList.vue:95
 #: src/views/stream/components/StreamDuplicate.vue:64
-#: src/views/stream/StreamList.vue:116
+#: src/views/stream/StreamList.vue:117
 msgid "Duplicate"
 msgstr "Nhân bản"
 
@@ -1701,7 +1708,7 @@ msgstr "Đã dọn dẹp biến môi trường"
 
 #: src/routes/modules/environments.ts:11
 #: src/views/dashboard/Environments.vue:83
-#: src/views/environments/list/Environment.vue:81
+#: src/views/environments/list/Environment.vue:82
 msgid "Environments"
 msgstr "Môi trường"
 
@@ -2283,7 +2290,8 @@ msgstr "Nếu bạn muốn tự động thu hồi chứng chỉ cũ, vui lòng b
 
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:70
 msgid "If your browser supports WebAuthn Passkey, a dialog box will appear."
-msgstr "Nếu trình duyệt của bạn hỗ trợ WebAuthn Passkey, một hộp thoại sẽ xuất hiện."
+msgstr ""
+"Nếu trình duyệt của bạn hỗ trợ WebAuthn Passkey, một hộp thoại sẽ xuất hiện."
 
 #: src/components/AutoCertForm/AutoCertForm.vue:107
 msgid ""
@@ -2565,7 +2573,7 @@ msgstr "Đang lắng nghe"
 msgid "Load Average:"
 msgstr "Tải trung bình:"
 
-#: src/views/environments/list/Environment.vue:88
+#: src/views/environments/list/Environment.vue:89
 msgid "Load from settings"
 msgstr "Tải từ cài đặt"
 
@@ -2626,13 +2634,12 @@ msgstr "Nhật ký"
 #: src/language/generate.ts:20
 msgid ""
 "Log file %{log_path} is not a regular file. If you are using nginx-ui in "
-"docker container, please refer to "
-"https://nginxui.com/zh_CN/guide/config-nginx-log.html for more information."
+"docker container, please refer to https://nginxui.com/zh_CN/guide/config-"
+"nginx-log.html for more information."
 msgstr ""
-"Tệp nhật ký %{log_path} không phải là tệp thông thường. Nếu bạn đang sử "
-"dụng nginx-ui trong container docker, vui lòng tham khảo "
-"https://nginxui.com/zh_CN/guide/config-nginx-log.html để biết thêm thông "
-"tin."
+"Tệp nhật ký %{log_path} không phải là tệp thông thường. Nếu bạn đang sử dụng "
+"nginx-ui trong container docker, vui lòng tham khảo https://nginxui.com/"
+"zh_CN/guide/config-nginx-log.html để biết thêm thông tin."
 
 #: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:72
 msgid "Log List"
@@ -2656,19 +2663,19 @@ msgstr "Logrotate"
 
 #: src/views/preference/tabs/LogrotateSettings.vue:13
 msgid ""
-"Logrotate, by default, is enabled in most mainstream Linux distributions "
-"for users who install Nginx UI on the host machine, so you don't need to "
-"modify the parameters on this page. For users who install Nginx UI using "
-"Docker containers, you can manually enable this option. The crontab task "
-"scheduler of Nginx UI will execute the logrotate command at the interval "
-"you set in minutes."
+"Logrotate, by default, is enabled in most mainstream Linux distributions for "
+"users who install Nginx UI on the host machine, so you don't need to modify "
+"the parameters on this page. For users who install Nginx UI using Docker "
+"containers, you can manually enable this option. The crontab task scheduler "
+"of Nginx UI will execute the logrotate command at the interval you set in "
+"minutes."
 msgstr ""
 "Logrotate được kích hoạt mặc định trong hầu hết các bản phân phối Linux phổ "
-"biến dành cho người dùng cài đặt Nginx UI trực tiếp trên máy chủ, vì vậy "
-"bạn không cần phải thay đổi các tham số trên trang này. Đối với người dùng "
-"cài đặt Nginx UI bằng container Docker, bạn có thể kích hoạt thủ công tùy "
-"chọn này. Bộ lập lịch tác vụ crontab của Nginx UI sẽ thực thi lệnh "
-"logrotate theo khoảng thời gian bạn đặt (tính bằng phút)."
+"biến dành cho người dùng cài đặt Nginx UI trực tiếp trên máy chủ, vì vậy bạn "
+"không cần phải thay đổi các tham số trên trang này. Đối với người dùng cài "
+"đặt Nginx UI bằng container Docker, bạn có thể kích hoạt thủ công tùy chọn "
+"này. Bộ lập lịch tác vụ crontab của Nginx UI sẽ thực thi lệnh logrotate theo "
+"khoảng thời gian bạn đặt (tính bằng phút)."
 
 #: src/views/site/components/SiteStatusSelect.vue:165
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:68
@@ -2862,7 +2869,7 @@ msgstr "Hàng tháng vào ngày %{day} lúc %{time}"
 msgid "Multi-line Directive"
 msgstr "Chỉ thị nhiều dòng"
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:182
+#: src/components/NgxConfigEditor/NgxUpstream.vue:189
 #: src/views/backup/AutoBackup/AutoBackup.vue:11
 #: src/views/certificate/ACMEUser.vue:11
 #: src/views/certificate/CertificateEditor.vue:162
@@ -2880,7 +2887,7 @@ msgstr "Chỉ thị nhiều dòng"
 #: src/views/stream/columns.tsx:12
 #: src/views/stream/components/RightPanel/Basic.vue:72
 #: src/views/stream/components/StreamDuplicate.vue:71
-#: src/views/stream/StreamList.vue:143
+#: src/views/stream/StreamList.vue:144
 msgid "Name"
 msgstr "Tên"
 
@@ -3111,11 +3118,10 @@ msgstr "Cấu hình Nginx UI đã được khôi phục"
 
 #: src/components/SystemRestore/SystemRestoreContent.vue:336
 msgid ""
-"Nginx UI configuration has been restored and will restart automatically in "
-"a few seconds."
+"Nginx UI configuration has been restored and will restart automatically in a "
+"few seconds."
 msgstr ""
-"Cấu hình Nginx UI đã được khôi phục và sẽ tự động khởi động lại sau vài "
-"giây."
+"Cấu hình Nginx UI đã được khôi phục và sẽ tự động khởi động lại sau vài giây."
 
 #: src/language/generate.ts:26
 msgid "Nginx.conf includes conf.d directory"
@@ -3138,7 +3144,7 @@ msgstr "Nginx.conf bao gồm thư mục streams-enabled"
 #: src/views/notification/Notification.vue:38
 #: src/views/preference/tabs/AuthSettings.vue:132
 #: src/views/preference/tabs/CertSettings.vue:73
-#: src/views/site/site_list/SiteList.vue:98 src/views/stream/StreamList.vue:119
+#: src/views/site/site_list/SiteList.vue:98 src/views/stream/StreamList.vue:120
 msgid "No"
 msgstr "Không"
 
@@ -3271,7 +3277,7 @@ msgid "Off"
 msgstr "Tắt"
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:159
-#: src/components/NgxConfigEditor/NgxUpstream.vue:145
+#: src/components/NgxConfigEditor/NgxUpstream.vue:151
 #: src/components/NodeSelector/NodeSelector.vue:109
 #: src/components/ProxyTargets/ProxyTargets.vue:43
 #: src/views/dashboard/Environments.vue:107
@@ -3292,7 +3298,7 @@ msgstr "Ngoại tuyến"
 #: src/views/site/site_list/SiteList.vue:99
 #: src/views/stream/components/RightPanel/Basic.vue:48
 #: src/views/stream/components/StreamStatusSelect.vue:60
-#: src/views/stream/StreamList.vue:120
+#: src/views/stream/StreamList.vue:121
 msgid "OK"
 msgstr "Đồng ý"
 
@@ -3395,9 +3401,9 @@ msgid ""
 "password replacement or as a 2FA method."
 msgstr ""
 "Passkey là thông tin xác thực WebAuthn dùng để xác minh danh tính của bạn "
-"thông qua chạm, nhận diện khuôn mặt, mật khẩu thiết bị hoặc mã PIN. Chúng "
-"thể được sử dụng để thay thế mật khẩu hoặc làm phương thức xác thực hai "
-"yếu tố (2FA)."
+"thông qua chạm, nhận diện khuôn mặt, mật khẩu thiết bị hoặc mã PIN. Chúng "
+"thể được sử dụng để thay thế mật khẩu hoặc làm phương thức xác thực hai yếu "
+"tố (2FA)."
 
 #: src/views/other/Login.vue:183 src/views/user/userColumns.tsx:16
 msgid "Password"
@@ -3496,8 +3502,7 @@ msgid ""
 "Please enter a name for the passkey you wish to create and click the OK "
 "button below."
 msgstr ""
-"Vui lòng nhập tên cho khóa truy cập bạn muốn tạo và nhấp vào nút OK bên "
-"dưới."
+"Vui lòng nhập tên cho khóa truy cập bạn muốn tạo và nhấp vào nút OK bên dưới."
 
 #: src/components/PortScanner/PortScannerCompact.vue:85
 msgid "Please enter a valid port range"
@@ -3528,21 +3533,22 @@ msgstr "Vui lòng điền vào các trường cấu hình S3 bắt buộc"
 msgid ""
 "Please fill in the API authentication credentials provided by your DNS "
 "provider."
-msgstr "Vui lòng điền thông tin xác thực API do nhà cung cấp DNS của bạn cung cấp"
+msgstr ""
+"Vui lòng điền thông tin xác thực API do nhà cung cấp DNS của bạn cung cấp"
 
 #: src/components/AutoCertForm/AutoCertForm.vue:56
 msgid ""
 "Please first add credentials in Certification > DNS Credentials, and then "
 "select one of the credentialsbelow to request the API of the DNS provider."
 msgstr ""
-"Trước tiên, vui lòng thêm thông tin xác thực trong Chứng chỉ > Thông tin "
-"xác thực DNS, sau đó chọn nhà cung cấp DNS"
+"Trước tiên, vui lòng thêm thông tin xác thực trong Chứng chỉ > Thông tin xác "
+"thực DNS, sau đó chọn nhà cung cấp DNS"
 
 #: src/components/Notification/notifications.ts:182
 #: src/language/constants.ts:59
 msgid ""
-"Please generate new recovery codes in the preferences immediately to "
-"prevent lockout."
+"Please generate new recovery codes in the preferences immediately to prevent "
+"lockout."
 msgstr ""
 "Vui lòng tạo mã khôi phục mới trong phần tùy chọn ngay lập tức để tránh bị "
 "khóa."
@@ -3560,13 +3566,15 @@ msgstr "Vui lòng nhập tên thư mục"
 msgid ""
 "Please input name, this will be used as the filename of the new "
 "configuration!"
-msgstr "Vui lòng nhập tên, tên này sẽ được sử dụng làm tên tệp của cấu hình mới!"
+msgstr ""
+"Vui lòng nhập tên, tên này sẽ được sử dụng làm tên tệp của cấu hình mới!"
 
 #: src/views/site/site_list/SiteDuplicate.vue:33
 msgid ""
 "Please input name, this will be used as the filename of the new "
 "configuration."
-msgstr "Vui lòng nhập tên, tên này sẽ được sử dụng làm tên tệp cho cấu hình mới."
+msgstr ""
+"Vui lòng nhập tên, tên này sẽ được sử dụng làm tên tệp cho cấu hình mới."
 
 #: src/views/install/components/InstallForm.vue:25
 msgid "Please input your E-mail!"
@@ -3586,7 +3594,8 @@ msgid "Please log in."
 msgstr "Vui lòng đăng nhập."
 
 #: src/views/certificate/DNSCredential.vue:61
-msgid "Please note that the unit of time configurations below are all in seconds."
+msgid ""
+"Please note that the unit of time configurations below are all in seconds."
 msgstr "Lưu ý đơn vị cấu hình thời gian bên dưới được tính bằng giây."
 
 #: src/views/install/components/InstallView.vue:102
@@ -3605,17 +3614,17 @@ msgstr "Vui lòng chọn tệp sao lưu"
 msgid "Please select at least one item"
 msgstr "Vui lòng chọn ít nhất một mục"
 
-#: src/views/environments/list/Environment.vue:120
+#: src/views/environments/list/Environment.vue:121
 #: src/views/environments/list/Environment.vue:35
 msgid "Please select at least one node to reload Nginx"
 msgstr "Vui lòng chọn ít nhất một nút để tải lại Nginx"
 
-#: src/views/environments/list/Environment.vue:141
+#: src/views/environments/list/Environment.vue:142
 #: src/views/environments/list/Environment.vue:49
 msgid "Please select at least one node to restart Nginx"
 msgstr "Vui lòng chọn ít nhất một nút để khởi động lại Nginx"
 
-#: src/views/environments/list/Environment.vue:99
+#: src/views/environments/list/Environment.vue:100
 msgid "Please select at least one node to upgrade"
 msgstr "Vui lòng chọn ít nhất một nút để nâng cấp"
 
@@ -3628,7 +3637,7 @@ msgstr "Vui lòng nhập \"Thu hồi\" để xác nhận"
 msgid "Port"
 msgstr "Cổng"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:44
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:45
 #: src/views/stream/components/RightPanel/RightPanel.vue:26
 msgid "Port Scanner"
 msgstr "Trình quét cổng"
@@ -3799,8 +3808,8 @@ msgstr "Tải lại"
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:136
 #: src/views/environments/group/columns.ts:22
 #: src/views/environments/group/EnvGroup.vue:50
-#: src/views/environments/list/Environment.vue:128
-#: src/views/environments/list/Environment.vue:136
+#: src/views/environments/list/Environment.vue:129
+#: src/views/environments/list/Environment.vue:137
 msgid "Reload Nginx"
 msgstr "Tải lại Nginx"
 
@@ -3849,7 +3858,7 @@ msgstr "Xóa thành công"
 msgid "Removed successfully"
 msgstr "Đã xóa thành công"
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:126
+#: src/components/NgxConfigEditor/NgxUpstream.vue:131
 #: src/views/config/components/ConfigName.vue:51
 #: src/views/config/components/Rename.vue:56
 #: src/views/config/ConfigList.vue:181
@@ -3967,8 +3976,8 @@ msgid ""
 "processes"
 msgstr ""
 "Kích thước tập hợp thường trú: Bộ nhớ thực tế thường trú trong bộ nhớ vật "
-"lý, bao gồm tất cả bộ nhớ thư viện dùng chung, sẽ được tính toán lặp lại "
-"cho nhiều tiến trình"
+"lý, bao gồm tất cả bộ nhớ thư viện dùng chung, sẽ được tính toán lặp lại cho "
+"nhiều tiến trình"
 
 #: src/composables/usePerformanceMetrics.ts:109
 #: src/views/dashboard/components/PerformanceTablesCard.vue:69
@@ -3980,8 +3989,8 @@ msgid "Restart"
 msgstr "Khởi động lại"
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:148
-#: src/views/environments/list/Environment.vue:149
-#: src/views/environments/list/Environment.vue:157
+#: src/views/environments/list/Environment.vue:150
+#: src/views/environments/list/Environment.vue:158
 msgid "Restart Nginx"
 msgstr "Khởi động lại Nginx"
 
@@ -4058,8 +4067,8 @@ msgid ""
 "Revoking a certificate will affect any services currently using it. This "
 "action cannot be undone."
 msgstr ""
-"Việc thu hồi chứng chỉ sẽ ảnh hưởng đến bất kỳ dịch vụ nào hiện đang sử "
-"dụng nó. Hành động này không thể hoàn tác."
+"Việc thu hồi chứng chỉ sẽ ảnh hưởng đến bất kỳ dịch vụ nào hiện đang sử dụng "
+"nó. Hành động này không thể hoàn tác."
 
 #: src/views/preference/tabs/AuthSettings.vue:75
 msgid "RP Display Name"
@@ -4280,7 +4289,8 @@ msgstr "Kết quả quét"
 
 #: src/views/preference/components/AuthSettings/TOTP.vue:69
 msgid "Scan the QR code with your mobile phone to add the account to the app."
-msgstr "Quét mã QR bằng điện thoại di động của bạn để thêm tài khoản vào ứng dụng."
+msgstr ""
+"Quét mã QR bằng điện thoại di động của bạn để thêm tài khoản vào ứng dụng."
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:113
 msgid "Schedule"
@@ -4342,7 +4352,8 @@ msgstr "Tự kiểm tra"
 #: src/components/SelfCheck/SelfCheckHeaderBanner.vue:37
 #: src/components/SelfCheck/SelfCheckHeaderBanner.vue:60
 msgid "Self check failed, Nginx UI may not work properly"
-msgstr "Tự kiểm tra thất bại, giao diện Nginx có thể không hoạt động bình thường"
+msgstr ""
+"Tự kiểm tra thất bại, giao diện Nginx có thể không hoạt động bình thường"
 
 #: src/views/dashboard/ServerAnalytic.vue:344
 #: src/views/dashboard/ServerAnalytic.vue:35
@@ -4382,8 +4393,8 @@ msgid ""
 "Set the recursive nameservers to override the systems nameservers for the "
 "step of DNS challenge."
 msgstr ""
-"Đặt các máy chủ tên đệ quy để ghi đè các máy chủ tên hệ thống trong bước "
-"thử thách DNS."
+"Đặt các máy chủ tên đệ quy để ghi đè các máy chủ tên hệ thống trong bước thử "
+"thách DNS."
 
 #: src/views/site/components/SiteStatusSelect.vue:116
 msgid "set to maintenance mode"
@@ -4403,19 +4414,19 @@ msgstr "Đang thiết lập nhà cung cấp thử thách HTTP01"
 
 #: src/constants/errors/nginx_log.ts:8
 msgid ""
-"Settings.NginxLogSettings.AccessLogPath is empty, refer to "
-"https://nginxui.com/guide/config-nginx.html for more information"
+"Settings.NginxLogSettings.AccessLogPath is empty, refer to https://nginxui."
+"com/guide/config-nginx.html for more information"
 msgstr ""
-"Settings.NginxLogSettings.AccessLogPath trống, tham khảo "
-"https://nginxui.com/guide/config-nginx.html để biết thêm thông tin"
+"Settings.NginxLogSettings.AccessLogPath trống, tham khảo https://nginxui.com/"
+"guide/config-nginx.html để biết thêm thông tin"
 
 #: src/constants/errors/nginx_log.ts:7
 msgid ""
-"Settings.NginxLogSettings.ErrorLogPath is empty, refer to "
-"https://nginxui.com/guide/config-nginx.html for more information"
+"Settings.NginxLogSettings.ErrorLogPath is empty, refer to https://nginxui."
+"com/guide/config-nginx.html for more information"
 msgstr ""
-"Settings.NginxLogSettings.ErrorLogPath trống, tham khảo "
-"https://nginxui.com/guide/config-nginx.html để biết thêm thông tin"
+"Settings.NginxLogSettings.ErrorLogPath trống, tham khảo https://nginxui.com/"
+"guide/config-nginx.html để biết thêm thông tin"
 
 #: src/views/install/components/InstallView.vue:65
 msgid "Setup your Nginx UI"
@@ -4648,25 +4659,25 @@ msgstr "Chủ nhật"
 msgid ""
 "Support communication with the backend through the Server-Sent Events "
 "protocol. If your Nginx UI is being used via an Nginx reverse proxy, please "
-"refer to this link to write the corresponding configuration file: "
-"https://nginxui.com/guide/nginx-proxy-example.html"
+"refer to this link to write the corresponding configuration file: https://"
+"nginxui.com/guide/nginx-proxy-example.html"
 msgstr ""
 "Hỗ trợ giao tiếp với backend thông qua giao thức Server-Sent Events. Nếu "
-"Nginx UI của bạn đang được sử dụng qua proxy ngược Nginx, vui lòng tham "
-"khảo liên kết này để viết tệp cấu hình tương ứng: "
-"https://nginxui.com/guide/nginx-proxy-example.html"
+"Nginx UI của bạn đang được sử dụng qua proxy ngược Nginx, vui lòng tham khảo "
+"liên kết này để viết tệp cấu hình tương ứng: https://nginxui.com/guide/nginx-"
+"proxy-example.html"
 
 #: src/components/SelfCheck/tasks/frontend/websocket.ts:13
 msgid ""
 "Support communication with the backend through the WebSocket protocol. If "
-"your Nginx UI is being used via an Nginx reverse proxy, please refer to "
-"this link to write the corresponding configuration file: "
-"https://nginxui.com/guide/nginx-proxy-example.html"
+"your Nginx UI is being used via an Nginx reverse proxy, please refer to this "
+"link to write the corresponding configuration file: https://nginxui.com/"
+"guide/nginx-proxy-example.html"
 msgstr ""
-"Hỗ trợ giao tiếp với backend thông qua giao thức WebSocket. Nếu Nginx UI "
-"của bạn đang được sử dụng thông qua proxy ngược Nginx, vui lòng tham khảo "
-"liên kết này để viết tệp cấu hình tương ứng: "
-"https://nginxui.com/guide/nginx-proxy-example.html"
+"Hỗ trợ giao tiếp với backend thông qua giao thức WebSocket. Nếu Nginx UI của "
+"bạn đang được sử dụng thông qua proxy ngược Nginx, vui lòng tham khảo liên "
+"kết này để viết tệp cấu hình tương ứng: https://nginxui.com/guide/nginx-"
+"proxy-example.html"
 
 #: src/language/curd.ts:51 src/language/curd.ts:55
 msgid "Support single or batch upload of files"
@@ -4811,16 +4822,16 @@ msgid ""
 "since it was last issued."
 msgstr ""
 "Chứng chỉ cho tên miền sẽ được kiểm tra sau mỗi 30 phút và sẽ được gia hạn "
-"nếu đã hơn 1 tuần hoặc khoảng thời gian bạn đặt trong cài đặt kể từ lần "
-"phát hành cuối cùng."
+"nếu đã hơn 1 tuần hoặc khoảng thời gian bạn đặt trong cài đặt kể từ lần phát "
+"hành cuối cùng."
 
 #: src/views/preference/tabs/NodeSettings.vue:37
 msgid ""
 "The ICP Number should only contain letters, unicode, numbers, hyphens, "
 "dashes, colons, and dots."
 msgstr ""
-"Số ICP chỉ được chứa chữ cái, unicode, số, dấu gạch ngang, dấu gạch dài, "
-"dấu hai chấm và dấu chấm."
+"Số ICP chỉ được chứa chữ cái, unicode, số, dấu gạch ngang, dấu gạch dài, dấu "
+"hai chấm và dấu chấm."
 
 #: src/views/certificate/CertificateEditor.vue:216
 msgid "The input is not a SSL Certificate"
@@ -4832,11 +4843,10 @@ msgstr "Đầu vào không phải là Khóa Chứng chỉ SSL"
 
 #: src/constants/errors/nginx_log.ts:2
 msgid ""
-"The log path is not under the paths in "
-"settings.NginxSettings.LogDirWhiteList"
+"The log path is not under the paths in settings.NginxSettings.LogDirWhiteList"
 msgstr ""
-"Đường dẫn nhật ký không nằm trong các đường dẫn trong "
-"settings.NginxSettings.LogDirWhiteList"
+"Đường dẫn nhật ký không nằm trong các đường dẫn trong settings.NginxSettings."
+"LogDirWhiteList"
 
 #: src/views/preference/tabs/OpenAISettings.vue:23
 #: src/views/preference/tabs/OpenAISettings.vue:89
@@ -4848,7 +4858,8 @@ msgstr ""
 "dài, dấu hai chấm và dấu chấm."
 
 #: src/views/preference/tabs/OpenAISettings.vue:90
-msgid "The model used for code completion, if not set, the chat model will be used."
+msgid ""
+"The model used for code completion, if not set, the chat model will be used."
 msgstr ""
 "Mô hình được sử dụng để hoàn thành mã, nếu không được đặt, mô hình trò "
 "chuyện sẽ được sử dụng."
@@ -4878,8 +4889,8 @@ msgid ""
 "The Public Security Number should only contain letters, unicode, numbers, "
 "hyphens, dashes, colons, and dots."
 msgstr ""
-"Số Công an chỉ được chứa chữ cái, unicode, số, dấu gạch ngang, dấu gạch "
-"dài, dấu hai chấm và dấu chấm."
+"Số Công an chỉ được chứa chữ cái, unicode, số, dấu gạch ngang, dấu gạch dài, "
+"dấu hai chấm và dấu chấm."
 
 #: src/views/dashboard/Environments.vue:148
 msgid ""
@@ -4887,9 +4898,9 @@ msgid ""
 "version. To avoid potential errors, please upgrade the remote Nginx UI to "
 "match the local version."
 msgstr ""
-"Phiên bản Nginx UI từ xa không tương thích với phiên bản Nginx UI cục bộ. "
-"Để tránh các lỗi tiềm ẩn, vui lòng nâng cấp phiên bản Nginx UI từ xa để "
-"khớp với phiên bản cục bộ."
+"Phiên bản Nginx UI từ xa không tương thích với phiên bản Nginx UI cục bộ. Để "
+"tránh các lỗi tiềm ẩn, vui lòng nâng cấp phiên bản Nginx UI từ xa để khớp "
+"với phiên bản cục bộ."
 
 #: src/components/AutoCertForm/AutoCertForm.vue:43
 msgid ""
@@ -4958,13 +4969,14 @@ msgid "This field should not be empty"
 msgstr "Trường này không được để trống"
 
 #: src/constants/form_errors.ts:6
-msgid "This field should only contain letters, unicode characters, numbers, and -_."
+msgid ""
+"This field should only contain letters, unicode characters, numbers, and -_."
 msgstr "Trường này chỉ được chứa chữ cái, ký tự Unicode, số và -_."
 
 #: src/language/curd.ts:44
 msgid ""
-"This field should only contain letters, unicode characters, numbers, and "
-"-_./:"
+"This field should only contain letters, unicode characters, numbers, and -"
+"_./:"
 msgstr "Trường này chỉ được chứa chữ cái, ký tự Unicode, số và -_./:"
 
 #: src/views/dashboard/NginxDashBoard.vue:150
@@ -4972,16 +4984,16 @@ msgid ""
 "This module provides Nginx request statistics, connection count, etc. data. "
 "After enabling it, you can view performance statistics"
 msgstr ""
-"Mô-đun này cung cấp dữ liệu như thống kê yêu cầu Nginx, số lượng kết nối, "
-"v.v. Sau khi bật, bạn có thể xem thống kê hiệu suất"
+"Mô-đun này cung cấp dữ liệu như thống kê yêu cầu Nginx, số lượng kết nối, v."
+"v. Sau khi bật, bạn có thể xem thống kê hiệu suất"
 
 #: src/views/certificate/components/RemoveCert.vue:104
 msgid ""
 "This operation will only remove the certificate from the database. The "
 "certificate files on the file system will not be deleted."
 msgstr ""
-"Thao tác này sẽ chỉ xóa chứng chỉ khỏi cơ sở dữ liệu. Các tệp chứng chỉ "
-"trên hệ thống tệp sẽ không bị xóa."
+"Thao tác này sẽ chỉ xóa chứng chỉ khỏi cơ sở dữ liệu. Các tệp chứng chỉ trên "
+"hệ thống tệp sẽ không bị xóa."
 
 #: src/views/backup/components/BackupCreator.vue:141
 msgid ""
@@ -5010,11 +5022,12 @@ msgid ""
 "This will restore configuration files and database. Nginx UI will restart "
 "after the restoration is complete."
 msgstr ""
-"Thao tác này sẽ khôi phục các tệp cấu hình và cơ sở dữ liệu. Giao diện "
-"Nginx sẽ khởi động lại sau khi quá trình khôi phục hoàn tất."
+"Thao tác này sẽ khôi phục các tệp cấu hình và cơ sở dữ liệu. Giao diện Nginx "
+"sẽ khởi động lại sau khi quá trình khôi phục hoàn tất."
 
 #: src/views/environments/list/BatchUpgrader.vue:182
-msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
+msgid ""
+"This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
 msgstr ""
 "Thao tác này sẽ nâng cấp hoặc cài đặt lại Nginx UI trên %{nodeNames} lên "
 "phiên bản %{version}."
@@ -5064,20 +5077,20 @@ msgid ""
 "and restart Nginx UI."
 msgstr ""
 "Để đảm bảo bảo mật, cấu hình WebAuthn không thể được thêm qua giao diện "
-"người dùng. Vui lòng cấu hình thủ công các mục sau trong tệp cấu hình "
-"app.ini và khởi động lại Nginx UI."
+"người dùng. Vui lòng cấu hình thủ công các mục sau trong tệp cấu hình app."
+"ini và khởi động lại Nginx UI."
 
 #: src/views/site/site_edit/components/Cert/IssueCert.vue:34
 #: src/views/site/site_edit/components/EnableTLS/EnableTLS.vue:15
 msgid ""
 "To make sure the certification auto-renewal can work normally, we need to "
-"add a location which can proxy the request from authority to backend, and "
-"we need to save this file and reload the Nginx. Are you sure you want to "
+"add a location which can proxy the request from authority to backend, and we "
+"need to save this file and reload the Nginx. Are you sure you want to "
 "continue?"
 msgstr ""
-"Để đảm bảo tính năng tự động gia hạn chứng chỉ có thể hoạt động bình "
-"thường, chúng tôi cần thêm một vị trí có thể ủy quyền yêu cầu từ cơ quan có "
-"thẩm quyền đến chương trình phụ trợ và chúng tôi cần lưu tệp này và tải lại "
+"Để đảm bảo tính năng tự động gia hạn chứng chỉ có thể hoạt động bình thường, "
+"chúng tôi cần thêm một vị trí có thể ủy quyền yêu cầu từ cơ quan có thẩm "
+"quyền đến chương trình phụ trợ và chúng tôi cần lưu tệp này và tải lại "
 "Nginx. Bạn có chắc chắn muốn Tiếp tục?"
 
 #: src/views/preference/tabs/OpenAISettings.vue:36
@@ -5197,8 +5210,8 @@ msgid "Updated at"
 msgstr "Ngày cập nhật"
 
 #: src/routes/modules/system.ts:26
-#: src/views/environments/list/Environment.vue:107
-#: src/views/environments/list/Environment.vue:115
+#: src/views/environments/list/Environment.vue:108
+#: src/views/environments/list/Environment.vue:116
 #: src/views/system/Upgrade.vue:154 src/views/system/Upgrade.vue:159
 msgid "Upgrade"
 msgstr "Cập nhật"
@@ -5228,7 +5241,7 @@ msgstr "Tải lên thư mục"
 msgid "Upstream"
 msgstr "Ngược dòng"
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:177
+#: src/components/NgxConfigEditor/NgxUpstream.vue:184
 msgid "Upstream Name"
 msgstr "Tên Upstream"
 
@@ -5344,9 +5357,9 @@ msgid ""
 "you have a valid backup file and security token, and carefully select what "
 "to restore."
 msgstr ""
-"Cảnh báo: Thao tác khôi phục sẽ ghi đè lên cấu hình hiện tại. Đảm bảo bạn "
-"tệp sao lưu hợp lệ và mã bảo mật, đồng thời cẩn thận chọn nội dung cần "
-"khôi phục."
+"Cảnh báo: Thao tác khôi phục sẽ ghi đè lên cấu hình hiện tại. Đảm bảo bạn "
+"tệp sao lưu hợp lệ và mã bảo mật, đồng thời cẩn thận chọn nội dung cần khôi "
+"phục."
 
 #: src/views/certificate/DNSCredential.vue:55
 msgid ""
@@ -5358,8 +5371,8 @@ msgstr ""
 
 #: src/views/site/site_edit/components/Cert/ObtainCert.vue:140
 msgid ""
-"We will remove the HTTPChallenge configuration from this file and reload "
-"the Nginx. Are you sure you want to continue?"
+"We will remove the HTTPChallenge configuration from this file and reload the "
+"Nginx. Are you sure you want to continue?"
 msgstr ""
 "Chúng tôi sẽ xóa cấu hình HTTPChallenge khỏi tệp này và tải lại Nginx. Bạn "
 "có muốn tiếp tục không?"
@@ -5404,8 +5417,8 @@ msgid ""
 "When you enable/disable, delete, or save this site, the nodes set in the "
 "Node Group and the nodes selected below will be synchronized."
 msgstr ""
-"Khi bạn bật/tắt, xóa hoặc lưu trang web này, các nút được đặt trong Nhóm "
-"Nút và các nút được chọn bên dưới sẽ được đồng bộ hóa."
+"Khi bạn bật/tắt, xóa hoặc lưu trang web này, các nút được đặt trong Nhóm Nút "
+"và các nút được chọn bên dưới sẽ được đồng bộ hóa."
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:140
 msgid ""
@@ -5461,12 +5474,12 @@ msgstr "Có"
 
 #: src/views/terminal/Terminal.vue:132
 msgid ""
-"You are accessing this terminal over an insecure HTTP connection on a "
-"non-localhost domain. This may expose sensitive information."
+"You are accessing this terminal over an insecure HTTP connection on a non-"
+"localhost domain. This may expose sensitive information."
 msgstr ""
-"Bạn đang truy cập thiết bị đầu cuối này thông qua kết nối HTTP không an "
-"toàn trên một miền không phải localhost. Điều này có thể làm lộ thông tin "
-"nhạy cảm."
+"Bạn đang truy cập thiết bị đầu cuối này thông qua kết nối HTTP không an toàn "
+"trên một miền không phải localhost. Điều này có thể làm lộ thông tin nhạy "
+"cảm."
 
 #: src/views/system/Upgrade.vue:224
 msgid "You are using the latest version"
@@ -5488,13 +5501,15 @@ msgstr "Bạn có thể đóng hộp thoại này ngay bây giờ"
 msgid ""
 "You have not configured the settings of Webauthn, so you cannot add a "
 "passkey."
-msgstr "Bạn chưa cấu hình cài đặt WebAuthn, vì vậy không thể thêm khóa truy cập."
+msgstr ""
+"Bạn chưa cấu hình cài đặt WebAuthn, vì vậy không thể thêm khóa truy cập."
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:81
-msgid "You have not enabled 2FA yet. Please enable 2FA to generate recovery codes."
+msgid ""
+"You have not enabled 2FA yet. Please enable 2FA to generate recovery codes."
 msgstr ""
-"Bạn chưa bật xác thực hai yếu tố. Vui lòng bật xác thực hai yếu tố để tạo "
-"khôi phục."
+"Bạn chưa bật xác thực hai yếu tố. Vui lòng bật xác thực hai yếu tố để tạo "
+"khôi phục."
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:94
 msgid "You have not generated recovery codes yet."
@@ -5577,8 +5592,8 @@ msgstr "Khóa truy cập của bạn"
 
 #~ msgid ""
 #~ "Check if /var/run/docker.sock exists. If you are using Nginx UI Official "
-#~ "Docker Image, please make sure the docker socket is mounted like this: `-v "
-#~ "/var/run/docker.sock:/var/run/docker.sock`."
+#~ "Docker Image, please make sure the docker socket is mounted like this: `-"
+#~ "v /var/run/docker.sock:/var/run/docker.sock`."
 #~ msgstr ""
 #~ "Kiểm tra xem /var/run/docker.sock có tồn tại không. Nếu bạn đang sử dụng "
 #~ "Docker Image chính thức của Nginx UI, hãy đảm bảo rằng ổ cắm Docker được "
@@ -5680,11 +5695,14 @@ msgstr "Khóa truy cập của bạn"
 #~ msgstr "Nhân bản %{conf_name} thành %{node_name} thành công"
 
 #, fuzzy
-#~ msgid "Rename %{orig_path} to %{new_path} on %{env_name} failed, response: %{resp}"
+#~ msgid ""
+#~ "Rename %{orig_path} to %{new_path} on %{env_name} failed, response: "
+#~ "%{resp}"
 #~ msgstr "Nhân bản %{conf_name} thành %{node_name} thành công"
 
 #, fuzzy
-#~ msgid "Rename Site %{site} to %{new_site} on %{node} error, response: %{resp}"
+#~ msgid ""
+#~ "Rename Site %{site} to %{new_site} on %{node} error, response: %{resp}"
 #~ msgstr "Nhân bản %{conf_name} thành %{node_name} thành công"
 
 #, fuzzy
@@ -5698,7 +5716,8 @@ msgstr "Khóa truy cập của bạn"
 #~ msgstr "Nhân bản %{conf_name} thành %{node_name} thành công"
 
 #, fuzzy
-#~ msgid "Sync Certificate %{cert_name} to %{env_name} failed, response: %{resp}"
+#~ msgid ""
+#~ "Sync Certificate %{cert_name} to %{env_name} failed, response: %{resp}"
 #~ msgstr "Nhân bản %{conf_name} thành %{node_name} thành công"
 
 #, fuzzy

+ 242 - 171
app/src/language/zh_CN/app.po

@@ -5,11 +5,11 @@ msgstr ""
 "POT-Creation-Date: \n"
 "PO-Revision-Date: 2025-05-09 21:33+0800\n"
 "Last-Translator: 0xJacky <me@jackyu.cn>\n"
-"Language-Team: Chinese (Simplified Han script) "
-"<https://weblate.nginxui.com/projects/nginx-ui/frontend/zh_Hans/>\n"
+"Language-Team: Chinese (Simplified Han script) <https://weblate.nginxui.com/"
+"projects/nginx-ui/frontend/zh_Hans/>\n"
 "Language: zh_CN\n"
 "MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=utf-8\n"
+"Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=1; plural=0;\n"
 "X-Generator: Poedit 3.6\n"
@@ -32,7 +32,8 @@ msgid "[Nginx UI] Certificate successfully revoked"
 msgstr "[Nginx UI] 证书成功撤销"
 
 #: src/language/generate.ts:35
-msgid "[Nginx UI] Certificate was used for server, reloading server TLS certificate"
+msgid ""
+"[Nginx UI] Certificate was used for server, reloading server TLS certificate"
 msgstr "[Nginx UI] 证书已用于服务器,正在重新加载服务器 TLS 证书"
 
 #: src/language/generate.ts:36
@@ -158,10 +159,10 @@ msgid "Actual worker to configured ratio"
 msgstr "实际工作进程与配置比例"
 
 #: src/components/NgxConfigEditor/NgxServer.vue:112
-#: src/components/NgxConfigEditor/NgxUpstream.vue:159 src/language/curd.ts:19
+#: src/components/NgxConfigEditor/NgxUpstream.vue:166 src/language/curd.ts:19
 #: src/views/preference/tabs/CertSettings.vue:45
 #: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:94
-#: src/views/stream/StreamList.vue:101
+#: src/views/stream/StreamList.vue:102
 msgid "Add"
 msgstr "添加"
 
@@ -188,7 +189,7 @@ msgstr "添加 Location"
 msgid "Add Site"
 msgstr "添加站点"
 
-#: src/views/stream/StreamList.vue:138
+#: src/views/stream/StreamList.vue:139
 msgid "Add Stream"
 msgstr "添加 Stream"
 
@@ -276,7 +277,7 @@ msgid "Are you sure you want to delete permanently?"
 msgstr "确定要永久删除吗?"
 
 #: src/language/curd.ts:25 src/views/site/site_list/SiteList.vue:100
-#: src/views/stream/StreamList.vue:121
+#: src/views/stream/StreamList.vue:122
 msgid "Are you sure you want to delete?"
 msgstr "您确定要删除吗?"
 
@@ -453,7 +454,8 @@ msgid "Backup task %{backup_name} completed successfully, file: %{file_path}"
 msgstr "备份任务 %{backup_name} 已完成,文件:%{file_path}"
 
 #: src/components/Notification/notifications.ts:34
-msgid "Backup task %{backup_name} failed during storage upload, error: %{error}"
+msgid ""
+"Backup task %{backup_name} failed during storage upload, error: %{error}"
 msgstr "备份任务 %{backup_name} 在存储上传过程中失败,错误:%{error}"
 
 #: src/components/Notification/notifications.ts:30
@@ -485,7 +487,7 @@ msgid "Base information"
 msgstr "基本信息"
 
 #: src/views/config/ConfigEditor.vue:300
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:31
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:32
 #: src/views/stream/components/RightPanel/RightPanel.vue:20
 msgid "Basic"
 msgstr "基本"
@@ -574,7 +576,9 @@ msgstr "CADir"
 msgid ""
 "Calculated based on worker_processes * worker_connections. Actual "
 "performance depends on hardware, configuration, and workload"
-msgstr "基于 worker_processes * worker_connections 计算得出。实际性能取决于硬件、配置和工作负载"
+msgstr ""
+"基于 worker_processes * worker_connections 计算得出。实际性能取决于硬件、配置"
+"和工作负载"
 
 #: src/components/ChatGPT/ChatGPT.vue:356
 #: src/components/NgxConfigEditor/NgxServer.vue:54
@@ -725,7 +729,7 @@ msgstr "变更后的路径"
 msgid "Channel"
 msgstr "通道"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:41
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:42
 #: src/views/stream/components/RightPanel/RightPanel.vue:23
 msgid "Chat"
 msgstr "聊天"
@@ -742,40 +746,44 @@ msgstr "重新检查"
 #: src/language/generate.ts:6
 msgid ""
 "Check if /var/run/docker.sock exists. If you are using Nginx UI Official "
-"Docker Image, please make sure the docker socket is mounted like this: `-v "
-"/var/run/docker.sock:/var/run/docker.sock`. Nginx UI official image uses "
-"/var/run/docker.sock to communicate with the host Docker Engine via Docker "
-"Client API. This feature is used to control Nginx in another container and "
-"perform container replacement rather than binary replacement during OTA "
-"upgrades of Nginx UI to ensure container dependencies are also upgraded. If "
-"you don't need this feature, please add the environment variable "
+"Docker Image, please make sure the docker socket is mounted like this: `-v /"
+"var/run/docker.sock:/var/run/docker.sock`. Nginx UI official image uses /var/"
+"run/docker.sock to communicate with the host Docker Engine via Docker Client "
+"API. This feature is used to control Nginx in another container and perform "
+"container replacement rather than binary replacement during OTA upgrades of "
+"Nginx UI to ensure container dependencies are also upgraded. If you don't "
+"need this feature, please add the environment variable "
 "NGINX_UI_IGNORE_DOCKER_SOCKET=true to the container."
 msgstr ""
-"检查 /var/run/docker.sock 是否存在。如果您使用的是 Nginx UI 官方 Docker 镜像,请确保以这种方式挂载 "
-"Docker 套接字:`-v /var/run/docker.sock:/var/run/docker.sock`。Nginx UI 官方镜像使用 "
-"/var/run/docker.sock 通过 Docker Client API 与主机 Docker Engine "
-"通信。此功能用于在另一个容器中控制 Nginx,并在 Nginx UI 的 OTA "
-"升级期间执行容器替换而非二进制替换,以确保容器依赖项也得到升级。如果您不需要此功能,请向容器添加环境变量 "
+"检查 /var/run/docker.sock 是否存在。如果您使用的是 Nginx UI 官方 Docker 镜"
+"像,请确保以这种方式挂载 Docker 套接字:`-v /var/run/docker.sock:/var/run/"
+"docker.sock`。Nginx UI 官方镜像使用 /var/run/docker.sock 通过 Docker Client "
+"API 与主机 Docker Engine 通信。此功能用于在另一个容器中控制 Nginx,并在 "
+"Nginx UI 的 OTA 升级期间执行容器替换而非二进制替换,以确保容器依赖项也得到升"
+"级。如果您不需要此功能,请向容器添加环境变量 "
 "NGINX_UI_IGNORE_DOCKER_SOCKET=true。"
 
 #: src/components/SelfCheck/tasks/frontend/https-check.ts:14
 msgid ""
 "Check if HTTPS is enabled. Using HTTP outside localhost is insecure and "
 "prevents using Passkeys and clipboard features"
-msgstr "检查是否启用了 HTTPS。在本地主机之外使用 HTTP 是不安全的,这也会导致无法使用 Passkey 和剪贴板功能"
+msgstr ""
+"检查是否启用了 HTTPS。在本地主机之外使用 HTTP 是不安全的,这也会导致无法使用 "
+"Passkey 和剪贴板功能"
 
 #: src/language/generate.ts:8
 msgid ""
-"Check if the nginx access log path exists. By default, this path is "
-"obtained from 'nginx -V'. If it cannot be obtained or the obtained path "
-"does not point to a valid, existing file, an error will be reported. In "
-"this case, you need to modify the configuration file to specify the access "
-"log path.Refer to the docs for more details: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#accesslogpath"
+"Check if the nginx access log path exists. By default, this path is obtained "
+"from 'nginx -V'. If it cannot be obtained or the obtained path does not "
+"point to a valid, existing file, an error will be reported. In this case, "
+"you need to modify the configuration file to specify the access log path."
+"Refer to the docs for more details: https://nginxui.com/zh_CN/guide/config-"
+"nginx.html#accesslogpath"
 msgstr ""
-"检查 nginx 访问日志路径是否存在。默认情况下,此路径从 'nginx -V' "
-"获取。如果无法获取或获取的路径未指向有效的现有文件,将报告错误。在这种情况下,您需要修改配置文件以指定访问日志路径。更多详情请参阅文档:https://"
-"nginxui.com/zh_CN/guide/config-nginx.html#accesslogpath"
+"检查 nginx 访问日志路径是否存在。默认情况下,此路径从 'nginx -V' 获取。如果无"
+"法获取或获取的路径未指向有效的现有文件,将报告错误。在这种情况下,您需要修改"
+"配置文件以指定访问日志路径。更多详情请参阅文档:https://nginxui.com/zh_CN/"
+"guide/config-nginx.html#accesslogpath"
 
 #: src/language/generate.ts:9
 msgid "Check if the nginx configuration directory exists"
@@ -790,25 +798,26 @@ msgid ""
 "Check if the nginx error log path exists. By default, this path is obtained "
 "from 'nginx -V'. If it cannot be obtained or the obtained path does not "
 "point to a valid, existing file, an error will be reported. In this case, "
-"you need to modify the configuration file to specify the error log "
-"path.Refer to the docs for more details: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#errorlogpath"
+"you need to modify the configuration file to specify the error log path."
+"Refer to the docs for more details: https://nginxui.com/zh_CN/guide/config-"
+"nginx.html#errorlogpath"
 msgstr ""
-"检查 nginx 错误日志路径是否存在。默认情况下,此路径从 'nginx -V' "
-"获取。如果无法获取或获取的路径未指向有效的现有文件,将报告错误。在这种情况下,您需要修改配置文件以指定错误日志路径。有关更多详细信息,请参阅文档:htt"
-"ps://nginxui.com/zh_CN/guide/config-nginx.html#errorlogpath"
+"检查 nginx 错误日志路径是否存在。默认情况下,此路径从 'nginx -V' 获取。如果无"
+"法获取或获取的路径未指向有效的现有文件,将报告错误。在这种情况下,您需要修改"
+"配置文件以指定错误日志路径。有关更多详细信息,请参阅文档:https://nginxui."
+"com/zh_CN/guide/config-nginx.html#errorlogpath"
 
 #: src/language/generate.ts:7
 msgid ""
 "Check if the nginx PID path exists. By default, this path is obtained from "
 "'nginx -V'. If it cannot be obtained, an error will be reported. In this "
 "case, you need to modify the configuration file to specify the Nginx PID "
-"path.Refer to the docs for more details: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#pidpath"
+"path.Refer to the docs for more details: https://nginxui.com/zh_CN/guide/"
+"config-nginx.html#pidpath"
 msgstr ""
-"检查 Nginx PID 路径是否存在。默认情况下,该路径是从 'nginx -V' "
-"获取的。如果无法获取,将会报错。在这种情况下,您需要修改配置文件以指定 Nginx PID "
-"路径。更多详情请参阅文档:https://nginxui.com/zh_CN/guide/config-nginx.html#pidpath"
+"检查 Nginx PID 路径是否存在。默认情况下,该路径是从 'nginx -V' 获取的。如果无"
+"法获取,将会报错。在这种情况下,您需要修改配置文件以指定 Nginx PID 路径。更多"
+"详情请参阅文档:https://nginxui.com/zh_CN/guide/config-nginx.html#pidpath"
 
 #: src/language/generate.ts:12
 msgid "Check if the nginx.conf includes the conf.d directory"
@@ -830,8 +839,8 @@ msgstr "检查 sites-available 和 sites-enabled 目录是否位于 Nginx 配置
 
 #: src/language/generate.ts:16
 msgid ""
-"Check if the streams-available and streams-enabled directories are under "
-"the nginx configuration directory"
+"Check if the streams-available and streams-enabled directories are under the "
+"nginx configuration directory"
 msgstr "检查 Nginx 配置目录下是否有 streams-available 和 streams-enabled 目录"
 
 #: src/constants/errors/crypto.ts:3
@@ -958,7 +967,7 @@ msgstr "配置入口文件不存在"
 msgid "Config path is empty"
 msgstr "配置路径为空"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:37
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:38
 msgid "Config Template"
 msgstr "配置模板"
 
@@ -1054,7 +1063,7 @@ msgstr "CPU 使用率相对较高,请考虑优化 Nginx 配置"
 msgid "CPU:"
 msgstr "CPU:"
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:170
+#: src/components/NgxConfigEditor/NgxUpstream.vue:177
 msgid "Create"
 msgstr "创建"
 
@@ -1078,7 +1087,8 @@ msgstr "创建文件夹"
 msgid ""
 "Create system backups including Nginx configuration and Nginx UI settings. "
 "Backup files will be automatically downloaded to your computer."
-msgstr "创建系统备份,包括 Nginx 配置和 Nginx UI 设置。备份文件将自动下载到你的电脑。"
+msgstr ""
+"创建系统备份,包括 Nginx 配置和 Nginx UI 设置。备份文件将自动下载到你的电脑。"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:229
 #: src/views/environments/group/columns.ts:29
@@ -1191,10 +1201,10 @@ msgid "Define shared memory zone name and size, e.g. proxy_cache:10m"
 msgstr "定义共享内存区名称和大小,例如 proxy_cache:10m"
 
 #: src/components/NgxConfigEditor/NgxServer.vue:78
-#: src/components/NgxConfigEditor/NgxUpstream.vue:129 src/language/curd.ts:9
+#: src/components/NgxConfigEditor/NgxUpstream.vue:134 src/language/curd.ts:9
 #: src/views/certificate/components/RemoveCert.vue:88
 #: src/views/site/site_list/SiteList.vue:109
-#: src/views/stream/StreamList.vue:130
+#: src/views/stream/StreamList.vue:131
 msgid "Delete"
 msgstr "删除"
 
@@ -1491,12 +1501,14 @@ msgstr "试运行模式已启动"
 msgid ""
 "Due to the security policies of some browsers, you cannot use passkeys on "
 "non-HTTPS websites, except when running on localhost."
-msgstr "由于某些浏览器的安全策略,除非在 localhost 上使用,否则不能在非 HTTPS 网站上使用 Passkey。"
+msgstr ""
+"由于某些浏览器的安全策略,除非在 localhost 上使用,否则不能在非 HTTPS 网站上"
+"使用 Passkey。"
 
 #: src/views/site/site_list/SiteDuplicate.vue:72
 #: src/views/site/site_list/SiteList.vue:95
 #: src/views/stream/components/StreamDuplicate.vue:64
-#: src/views/stream/StreamList.vue:116
+#: src/views/stream/StreamList.vue:117
 msgid "Duplicate"
 msgstr "复制"
 
@@ -1677,7 +1689,7 @@ msgstr "环境变量已清理"
 
 #: src/routes/modules/environments.ts:11
 #: src/views/dashboard/Environments.vue:83
-#: src/views/environments/list/Environment.vue:81
+#: src/views/environments/list/Environment.vue:82
 msgid "Environments"
 msgstr "环境"
 
@@ -2245,7 +2257,9 @@ msgstr "如果留空,则使用默认 CA Dir。"
 msgid ""
 "If the number of login failed attempts from a ip reach the max attempts in "
 "ban threshold minutes, the ip will be banned for a period of time."
-msgstr "如果某个 IP 的登录失败次数达到禁用阈值分钟内的最大尝试次数,该 IP 将被禁止登录一段时间。"
+msgstr ""
+"如果某个 IP 的登录失败次数达到禁用阈值分钟内的最大尝试次数,该 IP 将被禁止登"
+"录一段时间。"
 
 #: src/components/AutoCertForm/AutoCertForm.vue:116
 msgid ""
@@ -2436,7 +2450,8 @@ msgstr "Jwt 密钥"
 msgid ""
 "Keep your recovery codes as safe as your password. We recommend saving them "
 "with a password manager."
-msgstr "请像保护密码一样安全地保管您的恢复代码。我们建议使用密码管理器保存它们。"
+msgstr ""
+"请像保护密码一样安全地保管您的恢复代码。我们建议使用密码管理器保存它们。"
 
 #: src/views/dashboard/components/ParamsOpt/PerformanceConfig.vue:60
 msgid "Keepalive Timeout"
@@ -2529,7 +2544,7 @@ msgstr "监听中"
 msgid "Load Average:"
 msgstr "系统负载:"
 
-#: src/views/environments/list/Environment.vue:88
+#: src/views/environments/list/Environment.vue:89
 msgid "Load from settings"
 msgstr "从设置中加载"
 
@@ -2590,8 +2605,8 @@ msgstr "日志"
 #: src/language/generate.ts:20
 msgid ""
 "Log file %{log_path} is not a regular file. If you are using nginx-ui in "
-"docker container, please refer to "
-"https://nginxui.com/zh_CN/guide/config-nginx-log.html for more information."
+"docker container, please refer to https://nginxui.com/zh_CN/guide/config-"
+"nginx-log.html for more information."
 msgstr ""
 "日志文件 %{log_path} 不是常规文件。如果在 Docker 容器中使用 Nginx UI,请参阅 "
 "https://nginxui.com/zh_CN/guide/config-nginx-log.html 获取更多信息。"
@@ -2618,16 +2633,17 @@ msgstr "Logrotate"
 
 #: src/views/preference/tabs/LogrotateSettings.vue:13
 msgid ""
-"Logrotate, by default, is enabled in most mainstream Linux distributions "
-"for users who install Nginx UI on the host machine, so you don't need to "
-"modify the parameters on this page. For users who install Nginx UI using "
-"Docker containers, you can manually enable this option. The crontab task "
-"scheduler of Nginx UI will execute the logrotate command at the interval "
-"you set in minutes."
+"Logrotate, by default, is enabled in most mainstream Linux distributions for "
+"users who install Nginx UI on the host machine, so you don't need to modify "
+"the parameters on this page. For users who install Nginx UI using Docker "
+"containers, you can manually enable this option. The crontab task scheduler "
+"of Nginx UI will execute the logrotate command at the interval you set in "
+"minutes."
 msgstr ""
-"对于在宿主机上安装 Nginx UI 的用户,大多数主流 Linux 发行版都默认启用 logrotate "
-"定时任务,因此您无需修改本页面的参数。对于使用 Docker 容器安装 Nginx 用户界面的用户,您可以手动启用该选项。Nginx UI "
-"的定时任务任务调度器将按照您设置的时间间隔(以分钟为单位)执行 logrotate 命令。"
+"对于在宿主机上安装 Nginx UI 的用户,大多数主流 Linux 发行版都默认启用 "
+"logrotate 定时任务,因此您无需修改本页面的参数。对于使用 Docker 容器安装 "
+"Nginx 用户界面的用户,您可以手动启用该选项。Nginx UI 的定时任务任务调度器将按"
+"照您设置的时间间隔(以分钟为单位)执行 logrotate 命令。"
 
 #: src/views/site/components/SiteStatusSelect.vue:165
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:68
@@ -2647,7 +2663,9 @@ msgstr "成功启用维护模式"
 msgid ""
 "Make sure you have configured a reverse proxy for .well-known directory to "
 "HTTPChallengePort before obtaining the certificate."
-msgstr "在获取签发证书前,请确保配置文件中已将 .well-known 目录反向代理到 HTTPChallengePort。"
+msgstr ""
+"在获取签发证书前,请确保配置文件中已将 .well-known 目录反向代理到 "
+"HTTPChallengePort。"
 
 #: src/routes/modules/config.ts:10 src/views/config/ConfigEditor.vue:115
 #: src/views/config/ConfigEditor.vue:166 src/views/config/ConfigList.vue:72
@@ -2819,7 +2837,7 @@ msgstr "每月%{day}日%{time}"
 msgid "Multi-line Directive"
 msgstr "多行指令"
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:182
+#: src/components/NgxConfigEditor/NgxUpstream.vue:189
 #: src/views/backup/AutoBackup/AutoBackup.vue:11
 #: src/views/certificate/ACMEUser.vue:11
 #: src/views/certificate/CertificateEditor.vue:162
@@ -2837,7 +2855,7 @@ msgstr "多行指令"
 #: src/views/stream/columns.tsx:12
 #: src/views/stream/components/RightPanel/Basic.vue:72
 #: src/views/stream/components/StreamDuplicate.vue:71
-#: src/views/stream/StreamList.vue:143
+#: src/views/stream/StreamList.vue:144
 msgid "Name"
 msgstr "名称"
 
@@ -3068,8 +3086,8 @@ msgstr "Nginx 用户界面配置已恢复"
 
 #: src/components/SystemRestore/SystemRestoreContent.vue:336
 msgid ""
-"Nginx UI configuration has been restored and will restart automatically in "
-"a few seconds."
+"Nginx UI configuration has been restored and will restart automatically in a "
+"few seconds."
 msgstr "Nginx UI 配置已恢复,几秒钟后将自动重启。"
 
 #: src/language/generate.ts:26
@@ -3093,7 +3111,7 @@ msgstr "检查 nginx.conf 是否包含 streams-enabled 的目录"
 #: src/views/notification/Notification.vue:38
 #: src/views/preference/tabs/AuthSettings.vue:132
 #: src/views/preference/tabs/CertSettings.vue:73
-#: src/views/site/site_list/SiteList.vue:98 src/views/stream/StreamList.vue:119
+#: src/views/site/site_list/SiteList.vue:98 src/views/stream/StreamList.vue:120
 msgid "No"
 msgstr "取消"
 
@@ -3222,7 +3240,7 @@ msgid "Off"
 msgstr "关闭"
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:159
-#: src/components/NgxConfigEditor/NgxUpstream.vue:145
+#: src/components/NgxConfigEditor/NgxUpstream.vue:151
 #: src/components/NodeSelector/NodeSelector.vue:109
 #: src/components/ProxyTargets/ProxyTargets.vue:43
 #: src/views/dashboard/Environments.vue:107
@@ -3243,7 +3261,7 @@ msgstr "离线"
 #: src/views/site/site_list/SiteList.vue:99
 #: src/views/stream/components/RightPanel/Basic.vue:48
 #: src/views/stream/components/StreamStatusSelect.vue:60
-#: src/views/stream/StreamList.vue:120
+#: src/views/stream/StreamList.vue:121
 msgid "OK"
 msgstr "确定"
 
@@ -3344,7 +3362,9 @@ msgid ""
 "Passkeys are webauthn credentials that validate your identity using touch, "
 "facial recognition, a device password, or a PIN. They can be used as a "
 "password replacement or as a 2FA method."
-msgstr "Passkey 是一种网络认证凭据,可通过指纹、面部识别、设备密码或 PIN 码验证身份。它们可用作密码替代品或二步验证方法。"
+msgstr ""
+"Passkey 是一种网络认证凭据,可通过指纹、面部识别、设备密码或 PIN 码验证身份。"
+"它们可用作密码替代品或二步验证方法。"
 
 #: src/views/other/Login.vue:183 src/views/user/userColumns.tsx:16
 msgid "Password"
@@ -3477,13 +3497,15 @@ msgstr "请填写 DNS 提供商提供的 API 验证凭据。"
 msgid ""
 "Please first add credentials in Certification > DNS Credentials, and then "
 "select one of the credentialsbelow to request the API of the DNS provider."
-msgstr "请首先在 “证书”> “DNS 凭证” 中添加凭证,然后在下方选择一个凭证,请求 DNS 提供商的 API。"
+msgstr ""
+"请首先在 “证书”> “DNS 凭证” 中添加凭证,然后在下方选择一个凭证,请求 DNS 提供"
+"商的 API。"
 
 #: src/components/Notification/notifications.ts:182
 #: src/language/constants.ts:59
 msgid ""
-"Please generate new recovery codes in the preferences immediately to "
-"prevent lockout."
+"Please generate new recovery codes in the preferences immediately to prevent "
+"lockout."
 msgstr "请立即在偏好设置中生成新的恢复码,以防止无法访问您的账户。"
 
 #: src/views/config/components/Rename.vue:65
@@ -3525,7 +3547,8 @@ msgid "Please log in."
 msgstr "请登录。"
 
 #: src/views/certificate/DNSCredential.vue:61
-msgid "Please note that the unit of time configurations below are all in seconds."
+msgid ""
+"Please note that the unit of time configurations below are all in seconds."
 msgstr "请注意,下面的时间单位配置均以秒为单位。"
 
 #: src/views/install/components/InstallView.vue:102
@@ -3544,17 +3567,17 @@ msgstr "请选择备份文件"
 msgid "Please select at least one item"
 msgstr "请至少选择一项"
 
-#: src/views/environments/list/Environment.vue:120
+#: src/views/environments/list/Environment.vue:121
 #: src/views/environments/list/Environment.vue:35
 msgid "Please select at least one node to reload Nginx"
 msgstr "请至少选择一个节点重载 Nginx"
 
-#: src/views/environments/list/Environment.vue:141
+#: src/views/environments/list/Environment.vue:142
 #: src/views/environments/list/Environment.vue:49
 msgid "Please select at least one node to restart Nginx"
 msgstr "请至少选择一个节点重启 Nginx"
 
-#: src/views/environments/list/Environment.vue:99
+#: src/views/environments/list/Environment.vue:100
 msgid "Please select at least one node to upgrade"
 msgstr "请至少选择一个节点进行升级"
 
@@ -3567,7 +3590,7 @@ msgstr "请键入 \"撤销 \"确认"
 msgid "Port"
 msgstr "端口"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:44
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:45
 #: src/views/stream/components/RightPanel/RightPanel.vue:26
 msgid "Port Scanner"
 msgstr "端口检测"
@@ -3674,7 +3697,9 @@ msgstr "恢复代码"
 msgid ""
 "Recovery codes are used to access your account when you lose access to your "
 "2FA device. Each code can only be used once."
-msgstr "恢复代码用于在您无法访问双重身份验证设备时登录您的账户。每个代码只能使用一次。"
+msgstr ""
+"恢复代码用于在您无法访问双重身份验证设备时登录您的账户。每个代码只能使用一"
+"次。"
 
 #: src/views/preference/tabs/CertSettings.vue:40
 msgid "Recursive Nameservers"
@@ -3734,8 +3759,8 @@ msgstr "重载"
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:136
 #: src/views/environments/group/columns.ts:22
 #: src/views/environments/group/EnvGroup.vue:50
-#: src/views/environments/list/Environment.vue:128
-#: src/views/environments/list/Environment.vue:136
+#: src/views/environments/list/Environment.vue:129
+#: src/views/environments/list/Environment.vue:137
 msgid "Reload Nginx"
 msgstr "重载 Nginx"
 
@@ -3784,7 +3809,7 @@ msgstr "移除成功"
 msgid "Removed successfully"
 msgstr "删除成功"
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:126
+#: src/components/NgxConfigEditor/NgxUpstream.vue:131
 #: src/views/config/components/ConfigName.vue:51
 #: src/views/config/components/Rename.vue:56
 #: src/views/config/ConfigList.vue:181
@@ -3900,7 +3925,9 @@ msgid ""
 "Resident Set Size: Actual memory resident in physical memory, including all "
 "shared library memory, which will be repeated calculated for multiple "
 "processes"
-msgstr "驻留集大小:实际驻留在物理内存中的内存,包括所有共享库内存,将为多个进程重复计算"
+msgstr ""
+"驻留集大小:实际驻留在物理内存中的内存,包括所有共享库内存,将为多个进程重复"
+"计算"
 
 #: src/composables/usePerformanceMetrics.ts:109
 #: src/views/dashboard/components/PerformanceTablesCard.vue:69
@@ -3912,8 +3939,8 @@ msgid "Restart"
 msgstr "重启"
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:148
-#: src/views/environments/list/Environment.vue:149
-#: src/views/environments/list/Environment.vue:157
+#: src/views/environments/list/Environment.vue:150
+#: src/views/environments/list/Environment.vue:158
 msgid "Restart Nginx"
 msgstr "重启 Nginx"
 
@@ -4331,19 +4358,19 @@ msgstr "使用 HTTP01 challenge provider"
 
 #: src/constants/errors/nginx_log.ts:8
 msgid ""
-"Settings.NginxLogSettings.AccessLogPath is empty, refer to "
-"https://nginxui.com/guide/config-nginx.html for more information"
+"Settings.NginxLogSettings.AccessLogPath is empty, refer to https://nginxui."
+"com/guide/config-nginx.html for more information"
 msgstr ""
-"Settings.NginxLogSettings.AccessLogPath 为空,更多信息请参阅 "
-"https://nginxui.com/guide/config-nginx.html"
+"Settings.NginxLogSettings.AccessLogPath 为空,更多信息请参阅 https://nginxui."
+"com/guide/config-nginx.html"
 
 #: src/constants/errors/nginx_log.ts:7
 msgid ""
-"Settings.NginxLogSettings.ErrorLogPath is empty, refer to "
-"https://nginxui.com/guide/config-nginx.html for more information"
+"Settings.NginxLogSettings.ErrorLogPath is empty, refer to https://nginxui."
+"com/guide/config-nginx.html for more information"
 msgstr ""
-"Settings.NginxLogSettings.ErrorLogPath为空,更多信息请参阅 "
-"https://nginxui.com/guide/config-nginx.html"
+"Settings.NginxLogSettings.ErrorLogPath为空,更多信息请参阅 https://nginxui."
+"com/guide/config-nginx.html"
 
 #: src/views/install/components/InstallView.vue:65
 msgid "Setup your Nginx UI"
@@ -4574,18 +4601,19 @@ msgstr "星期日"
 msgid ""
 "Support communication with the backend through the Server-Sent Events "
 "protocol. If your Nginx UI is being used via an Nginx reverse proxy, please "
-"refer to this link to write the corresponding configuration file: "
-"https://nginxui.com/guide/nginx-proxy-example.html"
+"refer to this link to write the corresponding configuration file: https://"
+"nginxui.com/guide/nginx-proxy-example.html"
 msgstr ""
-"支持通过 Server-Sent Events 协议与后端通信。如果您的 Nginx UI 是通过 Nginx "
-"反向代理使用的,请参考此链接编写相应的配置文件:https://nginxui.com/guide/nginx-proxy-example.html"
+"支持通过 Server-Sent Events 协议与后端通信。如果您的 Nginx UI 是通过 Nginx 反"
+"向代理使用的,请参考此链接编写相应的配置文件:https://nginxui.com/guide/"
+"nginx-proxy-example.html"
 
 #: src/components/SelfCheck/tasks/frontend/websocket.ts:13
 msgid ""
 "Support communication with the backend through the WebSocket protocol. If "
-"your Nginx UI is being used via an Nginx reverse proxy, please refer to "
-"this link to write the corresponding configuration file: "
-"https://nginxui.com/guide/nginx-proxy-example.html"
+"your Nginx UI is being used via an Nginx reverse proxy, please refer to this "
+"link to write the corresponding configuration file: https://nginxui.com/"
+"guide/nginx-proxy-example.html"
 msgstr ""
 "支持通过 WebSocket 协议与后端通信,如果您正在使用 Nginx 反向代理了 Nginx UI "
 "请参考:https://nginxui.com/guide/nginx-proxy-example.html 编写配置文件"
@@ -4731,7 +4759,9 @@ msgid ""
 "The certificate for the domain will be checked 30 minutes, and will be "
 "renewed if it has been more than 1 week or the period you set in settings "
 "since it was last issued."
-msgstr "域名证书将在 30 分钟内接受检查,如果距离上次签发证书的时间超过 1 周或您在设置中设定的时间,证书将被更新。"
+msgstr ""
+"域名证书将在 30 分钟内接受检查,如果距离上次签发证书的时间超过 1 周或您在设置"
+"中设定的时间,证书将被更新。"
 
 #: src/views/preference/tabs/NodeSettings.vue:37
 msgid ""
@@ -4749,8 +4779,7 @@ msgstr "输入的内容不是 SSL 证书密钥"
 
 #: src/constants/errors/nginx_log.ts:2
 msgid ""
-"The log path is not under the paths in "
-"settings.NginxSettings.LogDirWhiteList"
+"The log path is not under the paths in settings.NginxSettings.LogDirWhiteList"
 msgstr "日志路径不在 settings.NginxSettings.LogDirWhiteList 中的路径之下"
 
 #: src/views/preference/tabs/OpenAISettings.vue:23
@@ -4761,7 +4790,8 @@ msgid ""
 msgstr "模型名称只能包含字母、单码、数字、连字符、破折号、冒号和点。"
 
 #: src/views/preference/tabs/OpenAISettings.vue:90
-msgid "The model used for code completion, if not set, the chat model will be used."
+msgid ""
+"The model used for code completion, if not set, the chat model will be used."
 msgstr "用于代码自动补全的模型,如果未设置,则使用聊天模型。"
 
 #: src/views/preference/tabs/NodeSettings.vue:18
@@ -4793,7 +4823,9 @@ msgid ""
 "The remote Nginx UI version is not compatible with the local Nginx UI "
 "version. To avoid potential errors, please upgrade the remote Nginx UI to "
 "match the local version."
-msgstr "远程 Nginx UI 版本与本地 Nginx UI版本不兼容。为避免意料之外的错误,请升级远程 Nginx UI,使其与本地版本一致。"
+msgstr ""
+"远程 Nginx UI 版本与本地 Nginx UI版本不兼容。为避免意料之外的错误,请升级远"
+"程 Nginx UI,使其与本地版本一致。"
 
 #: src/components/AutoCertForm/AutoCertForm.vue:43
 msgid ""
@@ -4828,7 +4860,9 @@ msgid ""
 "These codes are the last resort for accessing your account in case you lose "
 "your password and second factors. If you cannot find these codes, you will "
 "lose access to your account."
-msgstr "这些代码是在您丢失密码和双重身份验证方式时,访问账户的最后手段。如果找不到这些代码,您将无法再访问您的账户。"
+msgstr ""
+"这些代码是在您丢失密码和双重身份验证方式时,访问账户的最后手段。如果找不到这"
+"些代码,您将无法再访问您的账户。"
 
 #: src/views/certificate/CertificateEditor.vue:102
 msgid "This Auto Cert item is invalid, please remove it."
@@ -4857,13 +4891,14 @@ msgid "This field should not be empty"
 msgstr "该字段不能为空"
 
 #: src/constants/form_errors.ts:6
-msgid "This field should only contain letters, unicode characters, numbers, and -_."
+msgid ""
+"This field should only contain letters, unicode characters, numbers, and -_."
 msgstr "该字段只能包含字母、unicode 字符、数字和 -_。"
 
 #: src/language/curd.ts:44
 msgid ""
-"This field should only contain letters, unicode characters, numbers, and "
-"-_./:"
+"This field should only contain letters, unicode characters, numbers, and -"
+"_./:"
 msgstr "此字段应仅包含字母、Unicode字符、数字和 -_./:"
 
 #: src/views/dashboard/NginxDashBoard.vue:150
@@ -4903,7 +4938,8 @@ msgid ""
 msgstr "这将恢复配置文件和数据库。恢复完成后,Nginx UI 将重新启动。"
 
 #: src/views/environments/list/BatchUpgrader.vue:182
-msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
+msgid ""
+"This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
 msgstr "将 %{nodeNames} 上的 Nginx UI 升级或重新安装到 %{version} 版本。"
 
 #: src/views/preference/tabs/AuthSettings.vue:92
@@ -4924,7 +4960,8 @@ msgstr "提示"
 msgid ""
 "Tips: You can increase the concurrency processing capacity by increasing "
 "worker_processes or worker_connections"
-msgstr "提示您可以通过增加 worker_processes 或 worker_connections 来提高并发处理能力"
+msgstr ""
+"提示您可以通过增加 worker_processes 或 worker_connections 来提高并发处理能力"
 
 #: src/views/notification/notificationColumns.tsx:58
 msgid "Title"
@@ -4938,25 +4975,28 @@ msgstr "要确认撤销,请在下面的字段中输入 \"撤销\":"
 msgid ""
 "To enable it, you need to install the Google or Microsoft Authenticator app "
 "on your mobile phone."
-msgstr "要启用该功能,您需要在手机上安装 Google 或 Microsoft Authenticator 应用程序。"
+msgstr ""
+"要启用该功能,您需要在手机上安装 Google 或 Microsoft Authenticator 应用程序。"
 
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:89
 msgid ""
 "To ensure security, Webauthn configuration cannot be added through the UI. "
 "Please manually configure the following in the app.ini configuration file "
 "and restart Nginx UI."
-msgstr "为确保安全,Webauthn 配置不能通过用户界面添加。请在 app.ini 配置文件中手动配置以下内容,并重启 Nginx UI 服务。"
+msgstr ""
+"为确保安全,Webauthn 配置不能通过用户界面添加。请在 app.ini 配置文件中手动配"
+"置以下内容,并重启 Nginx UI 服务。"
 
 #: src/views/site/site_edit/components/Cert/IssueCert.vue:34
 #: src/views/site/site_edit/components/EnableTLS/EnableTLS.vue:15
 msgid ""
 "To make sure the certification auto-renewal can work normally, we need to "
-"add a location which can proxy the request from authority to backend, and "
-"we need to save this file and reload the Nginx. Are you sure you want to "
+"add a location which can proxy the request from authority to backend, and we "
+"need to save this file and reload the Nginx. Are you sure you want to "
 "continue?"
 msgstr ""
-"为了确保认证自动更新能够正常工作,我们需要添加一个能够代理从权威机构到后端的请求的 "
-"Location,并且我们需要保存这个文件并重新加载Nginx。你确定要继续吗?"
+"为了确保认证自动更新能够正常工作,我们需要添加一个能够代理从权威机构到后端的"
+"请求的 Location,并且我们需要保存这个文件并重新加载Nginx。你确定要继续吗?"
 
 #: src/views/preference/tabs/OpenAISettings.vue:36
 msgid ""
@@ -4964,8 +5004,8 @@ msgid ""
 "provide an OpenAI-compatible API endpoint, so just set the baseUrl to your "
 "local API."
 msgstr ""
-"要使用本地大型模型,可使用 ollama、vllm 或 lmdeploy 进行部署。它们提供了与 OpenAI 兼容的 API 端点,因此只需将 "
-"baseUrl 设置为本地 API 即可。"
+"要使用本地大型模型,可使用 ollama、vllm 或 lmdeploy 进行部署。它们提供了与 "
+"OpenAI 兼容的 API 端点,因此只需将 baseUrl 设置为本地 API 即可。"
 
 #: src/views/dashboard/NginxDashBoard.vue:55
 msgid "Toggle failed"
@@ -5072,8 +5112,8 @@ msgid "Updated at"
 msgstr "修改时间"
 
 #: src/routes/modules/system.ts:26
-#: src/views/environments/list/Environment.vue:107
-#: src/views/environments/list/Environment.vue:115
+#: src/views/environments/list/Environment.vue:108
+#: src/views/environments/list/Environment.vue:116
 #: src/views/system/Upgrade.vue:154 src/views/system/Upgrade.vue:159
 msgid "Upgrade"
 msgstr "升级"
@@ -5103,7 +5143,7 @@ msgstr "上传文件夹"
 msgid "Upstream"
 msgstr "上游"
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:177
+#: src/components/NgxConfigEditor/NgxUpstream.vue:184
 msgid "Upstream Name"
 msgstr "Upstream 名称"
 
@@ -5218,7 +5258,9 @@ msgid ""
 "Warning: Restore operation will overwrite current configurations. Make sure "
 "you have a valid backup file and security token, and carefully select what "
 "to restore."
-msgstr "警告:还原操作将覆盖当前配置。请确保您有有效的备份文件和安全令牌,并仔细选择要还原的内容。"
+msgstr ""
+"警告:还原操作将覆盖当前配置。请确保您有有效的备份文件和安全令牌,并仔细选择"
+"要还原的内容。"
 
 #: src/views/certificate/DNSCredential.vue:55
 msgid ""
@@ -5228,9 +5270,10 @@ msgstr "我们将在您域名的 DNS 记录中添加一个或多个 TXT 记录
 
 #: src/views/site/site_edit/components/Cert/ObtainCert.vue:140
 msgid ""
-"We will remove the HTTPChallenge configuration from this file and reload "
-"the Nginx. Are you sure you want to continue?"
-msgstr "我们将从这个文件中删除HTTPChallenge的配置,并重新加载Nginx。你确定要继续吗?"
+"We will remove the HTTPChallenge configuration from this file and reload the "
+"Nginx. Are you sure you want to continue?"
+msgstr ""
+"我们将从这个文件中删除HTTPChallenge的配置,并重新加载Nginx。你确定要继续吗?"
 
 #: src/views/preference/tabs/AuthSettings.vue:65
 msgid "Webauthn"
@@ -5261,14 +5304,18 @@ msgid ""
 "When Enabled, Nginx UI will automatically re-register users upon startup. "
 "Generally, do not enable this unless you are in a dev environment and using "
 "Pebble as CA."
-msgstr "启用后,Nginx UI 将在启动时自动重新注册用户。一般情况下,除非在开发环境中使用 Pebble 作为 CA,否则不要启用此功能。"
+msgstr ""
+"启用后,Nginx UI 将在启动时自动重新注册用户。一般情况下,除非在开发环境中使"
+"用 Pebble 作为 CA,否则不要启用此功能。"
 
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:61
 #: src/views/stream/components/RightPanel/Basic.vue:98
 msgid ""
 "When you enable/disable, delete, or save this site, the nodes set in the "
 "Node Group and the nodes selected below will be synchronized."
-msgstr "启用/禁用、删除或保存此站点时,环境组中设置的节点和下面选择的节点将同步执行操作。"
+msgstr ""
+"启用/禁用、删除或保存此站点时,环境组中设置的节点和下面选择的节点将同步执行操"
+"作。"
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:140
 msgid ""
@@ -5324,9 +5371,10 @@ msgstr "是的"
 
 #: src/views/terminal/Terminal.vue:132
 msgid ""
-"You are accessing this terminal over an insecure HTTP connection on a "
-"non-localhost domain. This may expose sensitive information."
-msgstr "您正在通过非本地主机域上的不安全 HTTP 连接访问此终端。这可能会暴露敏感信息。"
+"You are accessing this terminal over an insecure HTTP connection on a non-"
+"localhost domain. This may expose sensitive information."
+msgstr ""
+"您正在通过非本地主机域上的不安全 HTTP 连接访问此终端。这可能会暴露敏感信息。"
 
 #: src/views/system/Upgrade.vue:224
 msgid "You are using the latest version"
@@ -5351,7 +5399,8 @@ msgid ""
 msgstr "您尚未配置 Webauthn 的设置,因此无法添加 Passkey。"
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:81
-msgid "You have not enabled 2FA yet. Please enable 2FA to generate recovery codes."
+msgid ""
+"You have not enabled 2FA yet. Please enable 2FA to generate recovery codes."
 msgstr "您尚未启用双重身份验证。请启用双重身份验证以生成恢复代码。"
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:94
@@ -5433,11 +5482,12 @@ msgstr "你的 Passkeys"
 
 #~ msgid ""
 #~ "Check if /var/run/docker.sock exists. If you are using Nginx UI Official "
-#~ "Docker Image, please make sure the docker socket is mounted like this: `-v "
-#~ "/var/run/docker.sock:/var/run/docker.sock`."
+#~ "Docker Image, please make sure the docker socket is mounted like this: `-"
+#~ "v /var/run/docker.sock:/var/run/docker.sock`."
 #~ msgstr ""
-#~ "检查 /var/run/docker.sock 是否存在。如果你使用的是 Nginx UI 官方 Docker Image,请确保 Docker "
-#~ "Socket 像这样挂载:`-v /var/run/docker.sock:/var/run/docker.sock`."
+#~ "检查 /var/run/docker.sock 是否存在。如果你使用的是 Nginx UI 官方 Docker "
+#~ "Image,请确保 Docker Socket 像这样挂载:`-v /var/run/docker.sock:/var/run/"
+#~ "docker.sock`."
 
 #~ msgid "Check if the nginx access log path exists"
 #~ msgstr "检查 Nginx 访问日志路径是否存在"
@@ -5469,7 +5519,9 @@ msgstr "你的 Passkeys"
 #~ msgid ""
 #~ "If logs are not indexed, please check if the log file is under the "
 #~ "directory in Nginx.LogDirWhiteList."
-#~ msgstr "如果日志未被索引,请检查日志文件是否位于 Nginx.LogDirWhiteList 中的目录下。"
+#~ msgstr ""
+#~ "如果日志未被索引,请检查日志文件是否位于 Nginx.LogDirWhiteList 中的目录"
+#~ "下。"
 
 #~ msgid "Indexed"
 #~ msgstr "已索引"
@@ -5496,9 +5548,11 @@ msgstr "你的 Passkeys"
 #~ msgstr "保存失败,在配置中检测到语法错误。"
 
 #~ msgid ""
-#~ "When you enable/disable, delete, or save this stream, the nodes set in the "
-#~ "Node Group and the nodes selected below will be synchronized."
-#~ msgstr "启用/禁用、删除或保存此站点时,环境组中设置的节点和下面选择的节点将同步执行操作。"
+#~ "When you enable/disable, delete, or save this stream, the nodes set in "
+#~ "the Node Group and the nodes selected below will be synchronized."
+#~ msgstr ""
+#~ "启用/禁用、删除或保存此站点时,环境组中设置的节点和下面选择的节点将同步执"
+#~ "行操作。"
 
 #~ msgid "KB"
 #~ msgstr "KB"
@@ -5585,11 +5639,16 @@ msgstr "你的 Passkeys"
 #~ msgid "Please upgrade the remote Nginx UI to the latest version"
 #~ msgstr "请将远程 Nginx UI 升级到最新版本"
 
-#~ msgid "Rename %{orig_path} to %{new_path} on %{env_name} failed, response: %{resp}"
-#~ msgstr "将 %{env_name} 上的 %{orig_path} 重命名为 %{new_path} 失败,响应:%{resp}"
+#~ msgid ""
+#~ "Rename %{orig_path} to %{new_path} on %{env_name} failed, response: "
+#~ "%{resp}"
+#~ msgstr ""
+#~ "将 %{env_name} 上的 %{orig_path} 重命名为 %{new_path} 失败,响应:%{resp}"
 
-#~ msgid "Rename Site %{site} to %{new_site} on %{node} error, response: %{resp}"
-#~ msgstr "在 %{node} 上将站点 %{site} 重命名为 %{new_site} 失败,响应:%{resp}"
+#~ msgid ""
+#~ "Rename Site %{site} to %{new_site} on %{node} error, response: %{resp}"
+#~ msgstr ""
+#~ "在 %{node} 上将站点 %{site} 重命名为 %{new_site} 失败,响应:%{resp}"
 
 #~ msgid "Save site %{site} to %{node} error, response: %{resp}"
 #~ msgstr "保存站点 %{site} 到 %{node} 错误,响应: %{resp}"
@@ -5597,23 +5656,27 @@ msgstr "你的 Passkeys"
 #~ msgid ""
 #~ "Sync Certificate %{cert_name} to %{env_name} failed, please upgrade the "
 #~ "remote Nginx UI to the latest version"
-#~ msgstr "同步证书 %{cert_name} 到 %{env_name} 失败,请先将远程的 Nginx UI 升级到最新版本"
+#~ msgstr ""
+#~ "同步证书 %{cert_name} 到 %{env_name} 失败,请先将远程的 Nginx UI 升级到最"
+#~ "新版本"
 
-#~ msgid "Sync Certificate %{cert_name} to %{env_name} failed, response: %{resp}"
+#~ msgid ""
+#~ "Sync Certificate %{cert_name} to %{env_name} failed, response: %{resp}"
 #~ msgstr "同步证书 %{cert_name} 到 %{env_name} 失败,响应:%{resp}"
 
 #~ msgid "Sync config %{config_name} to %{env_name} failed, response: %{resp}"
 #~ msgstr "同步配置 %{config_name} 到 %{env_name} 失败,响应:%{resp}"
 
 #~ msgid ""
-#~ "If you lose your mobile phone, you can use the recovery code to reset your "
-#~ "2FA."
+#~ "If you lose your mobile phone, you can use the recovery code to reset "
+#~ "your 2FA."
 #~ msgstr "如果丢失了手机,可以使用恢复代码重置二步验证。"
 
 #~ msgid "Recovery Code:"
 #~ msgstr "恢复代码:"
 
-#~ msgid "The recovery code is only displayed once, please save it in a safe place."
+#~ msgid ""
+#~ "The recovery code is only displayed once, please save it in a safe place."
 #~ msgstr "恢复密码只会显示一次,请妥善保存。"
 
 #~ msgid "Can't scan? Use text key binding"
@@ -5634,7 +5697,9 @@ msgstr "你的 Passkeys"
 #~ msgid ""
 #~ "Rename %{orig_path} to %{new_path} on %{env_name} failed, please upgrade "
 #~ "the remote Nginx UI to the latest version"
-#~ msgstr "将 %{env_name} 上的 %{orig_path} 重命名为 %{new_path} 失败,请将远程 Nginx UI 升级到最新版本"
+#~ msgstr ""
+#~ "将 %{env_name} 上的 %{orig_path} 重命名为 %{new_path} 失败,请将远程 "
+#~ "Nginx UI 升级到最新版本"
 
 #~ msgid "Server Name"
 #~ msgstr "服务器名称"
@@ -5708,8 +5773,9 @@ msgstr "你的 Passkeys"
 #~ "Once the verification is complete, the records will be removed.\n"
 #~ "Please note that the unit of time configurations below are all in seconds."
 #~ msgstr ""
-#~ "请填写您的DNS提供商提供的API认证凭证。我们将在你的域名的DNS记录中添加一个或多个TXT记录,以进行所有权验证。一旦验证完成,这些记录将被删除。请"
-#~ "注意,下面的时间配置都是以秒为单位。"
+#~ "请填写您的DNS提供商提供的API认证凭证。我们将在你的域名的DNS记录中添加一个"
+#~ "或多个TXT记录,以进行所有权验证。一旦验证完成,这些记录将被删除。请注意,"
+#~ "下面的时间配置都是以秒为单位。"
 
 #~ msgid "Delete ID: %{id}"
 #~ msgstr "删除 ID: %{id}"
@@ -5730,11 +5796,11 @@ msgstr "你的 Passkeys"
 #~ msgstr "操作同步"
 
 #~ msgid ""
-#~ "Such as Reload and Configs, regex can configure as "
-#~ "`/api/nginx/reload|/api/nginx/test|/api/config/.+`, please see system api"
+#~ "Such as Reload and Configs, regex can configure as `/api/nginx/reload|/"
+#~ "api/nginx/test|/api/config/.+`, please see system api"
 #~ msgstr ""
-#~ "`重载`和`配置管理`的操作同步正则可以配置为`/api/nginx/reload|/api/nginx/test|/api/config/.+`"
-#~ ",详细请查看系统API"
+#~ "`重载`和`配置管理`的操作同步正则可以配置为`/api/nginx/reload|/api/nginx/"
+#~ "test|/api/config/.+`,详细请查看系统API"
 
 #~ msgid "SyncApiRegex"
 #~ msgstr "Api正则表达式"
@@ -5752,9 +5818,11 @@ msgstr "你的 Passkeys"
 #~ msgstr "你想启用自动更新证书吗?"
 
 #~ msgid ""
-#~ "We need to add the HTTPChallenge configuration to this file and reload the "
-#~ "Nginx. Are you sure you want to continue?"
-#~ msgstr "我们需要将 HTTPChallenge 的配置添加到这个文件中,并重新加载Nginx。你确定要继续吗?"
+#~ "We need to add the HTTPChallenge configuration to this file and reload "
+#~ "the Nginx. Are you sure you want to continue?"
+#~ msgstr ""
+#~ "我们需要将 HTTPChallenge 的配置添加到这个文件中,并重新加载Nginx。你确定要"
+#~ "继续吗?"
 
 #~ msgid "Chat with ChatGPT"
 #~ msgstr "与ChatGPT聊天"
@@ -5807,8 +5875,8 @@ msgstr "你的 Passkeys"
 #~ "you do not have a certificate before, please click \"Getting Certificate "
 #~ "from Let's Encrypt\" first."
 #~ msgstr ""
-#~ "系统将会每小时检测一次该域名证书,若距离上次签发已超过1个月,则将自动续签。<br/>如果您之前没有证书,请先点击 \"从 Let's Encrypt "
-#~ "获取证书\"。"
+#~ "系统将会每小时检测一次该域名证书,若距离上次签发已超过1个月,则将自动续"
+#~ "签。<br/>如果您之前没有证书,请先点击 \"从 Let's Encrypt 获取证书\"。"
 
 #~ msgid "Do you want to change the template to support the TLS?"
 #~ msgstr "你想要改变模板以支持 TLS 吗?"
@@ -5826,12 +5894,15 @@ msgstr "你的 Passkeys"
 #~ "The following values will only take effect if you have the corresponding "
 #~ "fields in your configuration file. The configuration filename cannot be "
 #~ "changed after it has been created."
-#~ msgstr "只有在您的配置文件中有相应字段时,下列的配置才能生效。配置文件名称创建后不可修改。"
+#~ msgstr ""
+#~ "只有在您的配置文件中有相应字段时,下列的配置才能生效。配置文件名称创建后不"
+#~ "可修改。"
 
 #~ msgid "This operation will lose the custom configuration."
 #~ msgstr "该操作将会丢失自定义配置。"
 
-#~ msgid "Add site here first, then you can configure TLS on the domain edit page."
+#~ msgid ""
+#~ "Add site here first, then you can configure TLS on the domain edit page."
 #~ msgstr "在这里添加站点,完成后可进入编辑页面配置 TLS。"
 
 #~ msgid "Server Status"

+ 245 - 173
app/src/language/zh_TW/app.po

@@ -9,11 +9,11 @@ msgstr ""
 "POT-Creation-Date: \n"
 "PO-Revision-Date: 2025-04-10 02:51+0000\n"
 "Last-Translator: 0xJacky <me@jackyu.cn>\n"
-"Language-Team: Chinese (Traditional Han script) "
-"<https://weblate.nginxui.com/projects/nginx-ui/frontend/zh_Hant/>\n"
+"Language-Team: Chinese (Traditional Han script) <https://weblate.nginxui.com/"
+"projects/nginx-ui/frontend/zh_Hant/>\n"
 "Language: zh_TW\n"
 "MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=utf-8\n"
+"Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=1; plural=0;\n"
 "X-Generator: Weblate 5.10.4\n"
@@ -36,7 +36,8 @@ msgid "[Nginx UI] Certificate successfully revoked"
 msgstr "[Nginx UI] 證書已成功撤銷"
 
 #: src/language/generate.ts:35
-msgid "[Nginx UI] Certificate was used for server, reloading server TLS certificate"
+msgid ""
+"[Nginx UI] Certificate was used for server, reloading server TLS certificate"
 msgstr "[Nginx UI] 憑證已用於伺服器,正在重新載入伺服器 TLS 憑證"
 
 #: src/language/generate.ts:36
@@ -162,10 +163,10 @@ msgid "Actual worker to configured ratio"
 msgstr "實際工作進程與配置比例"
 
 #: src/components/NgxConfigEditor/NgxServer.vue:112
-#: src/components/NgxConfigEditor/NgxUpstream.vue:159 src/language/curd.ts:19
+#: src/components/NgxConfigEditor/NgxUpstream.vue:166 src/language/curd.ts:19
 #: src/views/preference/tabs/CertSettings.vue:45
 #: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:94
-#: src/views/stream/StreamList.vue:101
+#: src/views/stream/StreamList.vue:102
 msgid "Add"
 msgstr "新增"
 
@@ -192,7 +193,7 @@ msgstr "新增 Location"
 msgid "Add Site"
 msgstr "新增網站"
 
-#: src/views/stream/StreamList.vue:138
+#: src/views/stream/StreamList.vue:139
 msgid "Add Stream"
 msgstr "新增 Stream"
 
@@ -280,7 +281,7 @@ msgid "Are you sure you want to delete permanently?"
 msgstr "確定要永久刪除嗎?"
 
 #: src/language/curd.ts:25 src/views/site/site_list/SiteList.vue:100
-#: src/views/stream/StreamList.vue:121
+#: src/views/stream/StreamList.vue:122
 msgid "Are you sure you want to delete?"
 msgstr "您確定要刪除嗎?"
 
@@ -457,7 +458,8 @@ msgid "Backup task %{backup_name} completed successfully, file: %{file_path}"
 msgstr "備份任務 %{backup_name} 已完成,檔案:%{file_path}"
 
 #: src/components/Notification/notifications.ts:34
-msgid "Backup task %{backup_name} failed during storage upload, error: %{error}"
+msgid ""
+"Backup task %{backup_name} failed during storage upload, error: %{error}"
 msgstr "備份任務 %{backup_name} 在儲存上傳過程中失敗,錯誤:%{error}"
 
 #: src/components/Notification/notifications.ts:30
@@ -489,7 +491,7 @@ msgid "Base information"
 msgstr "基本資訊"
 
 #: src/views/config/ConfigEditor.vue:300
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:31
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:32
 #: src/views/stream/components/RightPanel/RightPanel.vue:20
 msgid "Basic"
 msgstr "基本"
@@ -578,7 +580,9 @@ msgstr "CADir"
 msgid ""
 "Calculated based on worker_processes * worker_connections. Actual "
 "performance depends on hardware, configuration, and workload"
-msgstr "基於 worker_processes * worker_connections 計算得出。實際效能取決於硬體、配置和工作負載"
+msgstr ""
+"基於 worker_processes * worker_connections 計算得出。實際效能取決於硬體、配置"
+"和工作負載"
 
 #: src/components/ChatGPT/ChatGPT.vue:356
 #: src/components/NgxConfigEditor/NgxServer.vue:54
@@ -729,7 +733,7 @@ msgstr "變更後路徑"
 msgid "Channel"
 msgstr "通道"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:41
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:42
 #: src/views/stream/components/RightPanel/RightPanel.vue:23
 msgid "Chat"
 msgstr "聊天"
@@ -746,40 +750,44 @@ msgstr "再次檢查"
 #: src/language/generate.ts:6
 msgid ""
 "Check if /var/run/docker.sock exists. If you are using Nginx UI Official "
-"Docker Image, please make sure the docker socket is mounted like this: `-v "
-"/var/run/docker.sock:/var/run/docker.sock`. Nginx UI official image uses "
-"/var/run/docker.sock to communicate with the host Docker Engine via Docker "
-"Client API. This feature is used to control Nginx in another container and "
-"perform container replacement rather than binary replacement during OTA "
-"upgrades of Nginx UI to ensure container dependencies are also upgraded. If "
-"you don't need this feature, please add the environment variable "
+"Docker Image, please make sure the docker socket is mounted like this: `-v /"
+"var/run/docker.sock:/var/run/docker.sock`. Nginx UI official image uses /var/"
+"run/docker.sock to communicate with the host Docker Engine via Docker Client "
+"API. This feature is used to control Nginx in another container and perform "
+"container replacement rather than binary replacement during OTA upgrades of "
+"Nginx UI to ensure container dependencies are also upgraded. If you don't "
+"need this feature, please add the environment variable "
 "NGINX_UI_IGNORE_DOCKER_SOCKET=true to the container."
 msgstr ""
-"檢查 /var/run/docker.sock 是否存在。如果您使用的是 Nginx UI 官方 Docker 映像,請確保以這種方式掛載 "
-"Docker 通訊端:`-v /var/run/docker.sock:/var/run/docker.sock`。Nginx UI 官方映像使用 "
-"/var/run/docker.sock 通過 Docker Client API 與主機 Docker Engine "
-"通訊。此功能用於在另一個容器中控制 Nginx,並在 Nginx UI 的 OTA "
-"升級期間執行容器替換而非二進位替換,以確保容器依賴項也得到升級。如果您不需要此功能,請向容器新增環境變數 "
+"檢查 /var/run/docker.sock 是否存在。如果您使用的是 Nginx UI 官方 Docker 映"
+"像,請確保以這種方式掛載 Docker 通訊端:`-v /var/run/docker.sock:/var/run/"
+"docker.sock`。Nginx UI 官方映像使用 /var/run/docker.sock 通過 Docker Client "
+"API 與主機 Docker Engine 通訊。此功能用於在另一個容器中控制 Nginx,並在 "
+"Nginx UI 的 OTA 升級期間執行容器替換而非二進位替換,以確保容器依賴項也得到升"
+"級。如果您不需要此功能,請向容器新增環境變數 "
 "NGINX_UI_IGNORE_DOCKER_SOCKET=true。"
 
 #: src/components/SelfCheck/tasks/frontend/https-check.ts:14
 msgid ""
 "Check if HTTPS is enabled. Using HTTP outside localhost is insecure and "
 "prevents using Passkeys and clipboard features"
-msgstr "檢查是否啟用了 HTTPS。在 localhost 之外使用 HTTP 不安全,並且會阻止使用 Passkeys 和剪貼簿功能"
+msgstr ""
+"檢查是否啟用了 HTTPS。在 localhost 之外使用 HTTP 不安全,並且會阻止使用 "
+"Passkeys 和剪貼簿功能"
 
 #: src/language/generate.ts:8
 msgid ""
-"Check if the nginx access log path exists. By default, this path is "
-"obtained from 'nginx -V'. If it cannot be obtained or the obtained path "
-"does not point to a valid, existing file, an error will be reported. In "
-"this case, you need to modify the configuration file to specify the access "
-"log path.Refer to the docs for more details: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#accesslogpath"
+"Check if the nginx access log path exists. By default, this path is obtained "
+"from 'nginx -V'. If it cannot be obtained or the obtained path does not "
+"point to a valid, existing file, an error will be reported. In this case, "
+"you need to modify the configuration file to specify the access log path."
+"Refer to the docs for more details: https://nginxui.com/zh_CN/guide/config-"
+"nginx.html#accesslogpath"
 msgstr ""
-"檢查 nginx 訪問日誌路徑是否存在。預設情況下,此路徑從 'nginx -V' "
-"獲取。如果無法獲取或獲取的路徑未指向有效的現有文件,將報告錯誤。在這種情況下,您需要修改配置文件以指定訪問日誌路徑。更多詳情請參閱文檔:https://"
-"nginxui.com/zh_CN/guide/config-nginx.html#accesslogpath"
+"檢查 nginx 訪問日誌路徑是否存在。預設情況下,此路徑從 'nginx -V' 獲取。如果無"
+"法獲取或獲取的路徑未指向有效的現有文件,將報告錯誤。在這種情況下,您需要修改"
+"配置文件以指定訪問日誌路徑。更多詳情請參閱文檔:https://nginxui.com/zh_CN/"
+"guide/config-nginx.html#accesslogpath"
 
 #: src/language/generate.ts:9
 msgid "Check if the nginx configuration directory exists"
@@ -794,25 +802,26 @@ msgid ""
 "Check if the nginx error log path exists. By default, this path is obtained "
 "from 'nginx -V'. If it cannot be obtained or the obtained path does not "
 "point to a valid, existing file, an error will be reported. In this case, "
-"you need to modify the configuration file to specify the error log "
-"path.Refer to the docs for more details: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#errorlogpath"
+"you need to modify the configuration file to specify the error log path."
+"Refer to the docs for more details: https://nginxui.com/zh_CN/guide/config-"
+"nginx.html#errorlogpath"
 msgstr ""
-"檢查 nginx 錯誤日誌路徑是否存在。預設情況下,此路徑從 'nginx -V' "
-"獲取。如果無法獲取或獲取的路徑未指向有效的現有文件,將報告錯誤。在這種情況下,您需要修改配置文件以指定錯誤日誌路徑。有關更多詳細信息,請參閱文檔:htt"
-"ps://nginxui.com/zh_CN/guide/config-nginx.html#errorlogpath"
+"檢查 nginx 錯誤日誌路徑是否存在。預設情況下,此路徑從 'nginx -V' 獲取。如果無"
+"法獲取或獲取的路徑未指向有效的現有文件,將報告錯誤。在這種情況下,您需要修改"
+"配置文件以指定錯誤日誌路徑。有關更多詳細信息,請參閱文檔:https://nginxui."
+"com/zh_CN/guide/config-nginx.html#errorlogpath"
 
 #: src/language/generate.ts:7
 msgid ""
 "Check if the nginx PID path exists. By default, this path is obtained from "
 "'nginx -V'. If it cannot be obtained, an error will be reported. In this "
 "case, you need to modify the configuration file to specify the Nginx PID "
-"path.Refer to the docs for more details: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#pidpath"
+"path.Refer to the docs for more details: https://nginxui.com/zh_CN/guide/"
+"config-nginx.html#pidpath"
 msgstr ""
-"檢查 Nginx PID 路徑是否存在。預設情況下,該路徑是從 'nginx -V' "
-"獲取的。如果無法獲取,將會報錯。在這種情況下,您需要修改設定檔以指定 Nginx PID "
-"路徑。更多詳情請參閱文件:https://nginxui.com/zh_CN/guide/config-nginx.html#pidpath"
+"檢查 Nginx PID 路徑是否存在。預設情況下,該路徑是從 'nginx -V' 獲取的。如果無"
+"法獲取,將會報錯。在這種情況下,您需要修改設定檔以指定 Nginx PID 路徑。更多詳"
+"情請參閱文件:https://nginxui.com/zh_CN/guide/config-nginx.html#pidpath"
 
 #: src/language/generate.ts:12
 msgid "Check if the nginx.conf includes the conf.d directory"
@@ -834,9 +843,10 @@ msgstr "檢查 sites-available 和 sites-enabled 目錄是否位於 nginx 配置
 
 #: src/language/generate.ts:16
 msgid ""
-"Check if the streams-available and streams-enabled directories are under "
-"the nginx configuration directory"
-msgstr "檢查 streams-available 和 streams-enabled 目錄是否位於 nginx 配置目錄下"
+"Check if the streams-available and streams-enabled directories are under the "
+"nginx configuration directory"
+msgstr ""
+"檢查 streams-available 和 streams-enabled 目錄是否位於 nginx 配置目錄下"
 
 #: src/constants/errors/crypto.ts:3
 msgid "Cipher text is too short"
@@ -962,7 +972,7 @@ msgstr "配置入口文件不存在"
 msgid "Config path is empty"
 msgstr "設定路徑為空"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:37
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:38
 msgid "Config Template"
 msgstr "配置模板"
 
@@ -1058,7 +1068,7 @@ msgstr "CPU 使用率較高,建議優化 Nginx 配置"
 msgid "CPU:"
 msgstr "CPU:"
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:170
+#: src/components/NgxConfigEditor/NgxUpstream.vue:177
 msgid "Create"
 msgstr "建立"
 
@@ -1082,7 +1092,8 @@ msgstr "建立資料夾"
 msgid ""
 "Create system backups including Nginx configuration and Nginx UI settings. "
 "Backup files will be automatically downloaded to your computer."
-msgstr "建立系統備份,包括 Nginx 設定與 Nginx UI 設定。備份檔案將自動下載至您的電腦。"
+msgstr ""
+"建立系統備份,包括 Nginx 設定與 Nginx UI 設定。備份檔案將自動下載至您的電腦。"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:229
 #: src/views/environments/group/columns.ts:29
@@ -1195,10 +1206,10 @@ msgid "Define shared memory zone name and size, e.g. proxy_cache:10m"
 msgstr "定義共享記憶體區域名稱和大小,例如 proxy_cache:10m"
 
 #: src/components/NgxConfigEditor/NgxServer.vue:78
-#: src/components/NgxConfigEditor/NgxUpstream.vue:129 src/language/curd.ts:9
+#: src/components/NgxConfigEditor/NgxUpstream.vue:134 src/language/curd.ts:9
 #: src/views/certificate/components/RemoveCert.vue:88
 #: src/views/site/site_list/SiteList.vue:109
-#: src/views/stream/StreamList.vue:130
+#: src/views/stream/StreamList.vue:131
 msgid "Delete"
 msgstr "刪除"
 
@@ -1495,12 +1506,14 @@ msgstr "試運轉模式已啟用"
 msgid ""
 "Due to the security policies of some browsers, you cannot use passkeys on "
 "non-HTTPS websites, except when running on localhost."
-msgstr "基於部分瀏覽器的安全政策,您無法在未啟用 HTTPS 網站,特別是 localhost 上使用通行金鑰。"
+msgstr ""
+"基於部分瀏覽器的安全政策,您無法在未啟用 HTTPS 網站,特別是 localhost 上使用"
+"通行金鑰。"
 
 #: src/views/site/site_list/SiteDuplicate.vue:72
 #: src/views/site/site_list/SiteList.vue:95
 #: src/views/stream/components/StreamDuplicate.vue:64
-#: src/views/stream/StreamList.vue:116
+#: src/views/stream/StreamList.vue:117
 msgid "Duplicate"
 msgstr "複製"
 
@@ -1681,7 +1694,7 @@ msgstr "環境變數已清理"
 
 #: src/routes/modules/environments.ts:11
 #: src/views/dashboard/Environments.vue:83
-#: src/views/environments/list/Environment.vue:81
+#: src/views/environments/list/Environment.vue:82
 msgid "Environments"
 msgstr "環境"
 
@@ -2249,7 +2262,9 @@ msgstr "如果留空,將使用預設的 CA Dir。"
 msgid ""
 "If the number of login failed attempts from a ip reach the max attempts in "
 "ban threshold minutes, the ip will be banned for a period of time."
-msgstr "如果來自某個 IP 的登入失敗次數在禁止閾值分鐘內達到最大嘗試次數,該 IP 將被禁止一段時間。"
+msgstr ""
+"如果來自某個 IP 的登入失敗次數在禁止閾值分鐘內達到最大嘗試次數,該 IP 將被禁"
+"止一段時間。"
 
 #: src/components/AutoCertForm/AutoCertForm.vue:116
 msgid ""
@@ -2440,7 +2455,8 @@ msgstr "Jwt 金鑰"
 msgid ""
 "Keep your recovery codes as safe as your password. We recommend saving them "
 "with a password manager."
-msgstr "請將您的復原代碼與密碼一樣妥善保管。我們建議使用密碼管理工具來儲存這些代碼。"
+msgstr ""
+"請將您的復原代碼與密碼一樣妥善保管。我們建議使用密碼管理工具來儲存這些代碼。"
 
 #: src/views/dashboard/components/ParamsOpt/PerformanceConfig.vue:60
 msgid "Keepalive Timeout"
@@ -2533,7 +2549,7 @@ msgstr "監聽中"
 msgid "Load Average:"
 msgstr "負載平均值:"
 
-#: src/views/environments/list/Environment.vue:88
+#: src/views/environments/list/Environment.vue:89
 msgid "Load from settings"
 msgstr "從設定載入"
 
@@ -2594,11 +2610,11 @@ msgstr "日誌"
 #: src/language/generate.ts:20
 msgid ""
 "Log file %{log_path} is not a regular file. If you are using nginx-ui in "
-"docker container, please refer to "
-"https://nginxui.com/zh_CN/guide/config-nginx-log.html for more information."
+"docker container, please refer to https://nginxui.com/zh_CN/guide/config-"
+"nginx-log.html for more information."
 msgstr ""
-"日誌文件 %{log_path} 不是常規文件。如果您在 docker 容器中使用 nginx-ui,請參"
-"https://nginxui.com/zh_CN/guide/config-nginx-log.html 獲取更多信息。"
+"日誌文件 %{log_path} 不是常規文件。如果您在 docker 容器中使用 nginx-ui,請參"
+"https://nginxui.com/zh_CN/guide/config-nginx-log.html 獲取更多信息。"
 
 #: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:72
 msgid "Log List"
@@ -2622,16 +2638,17 @@ msgstr "Logrotate"
 
 #: src/views/preference/tabs/LogrotateSettings.vue:13
 msgid ""
-"Logrotate, by default, is enabled in most mainstream Linux distributions "
-"for users who install Nginx UI on the host machine, so you don't need to "
-"modify the parameters on this page. For users who install Nginx UI using "
-"Docker containers, you can manually enable this option. The crontab task "
-"scheduler of Nginx UI will execute the logrotate command at the interval "
-"you set in minutes."
+"Logrotate, by default, is enabled in most mainstream Linux distributions for "
+"users who install Nginx UI on the host machine, so you don't need to modify "
+"the parameters on this page. For users who install Nginx UI using Docker "
+"containers, you can manually enable this option. The crontab task scheduler "
+"of Nginx UI will execute the logrotate command at the interval you set in "
+"minutes."
 msgstr ""
-"預設情況下,對於在主機上安裝 Nginx UI 的使用者,大多數主流 Linux 發行版都啟用了 "
-"logrotate,因此您無需修改此頁面的參數。對於使用 Docker 容器安裝 Nginx UI 的使用者,您可以手動啟用此選項。Nginx UI "
-"的 crontab 任務排程器將按照您設定的分鐘間隔執行 logrotate 命令。"
+"預設情況下,對於在主機上安裝 Nginx UI 的使用者,大多數主流 Linux 發行版都啟用"
+"了 logrotate,因此您無需修改此頁面的參數。對於使用 Docker 容器安裝 Nginx UI "
+"的使用者,您可以手動啟用此選項。Nginx UI 的 crontab 任務排程器將按照您設定的"
+"分鐘間隔執行 logrotate 命令。"
 
 #: src/views/site/components/SiteStatusSelect.vue:165
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:68
@@ -2651,7 +2668,8 @@ msgstr "維護模式已成功啟用"
 msgid ""
 "Make sure you have configured a reverse proxy for .well-known directory to "
 "HTTPChallengePort before obtaining the certificate."
-msgstr "在取得憑證前,請確保您已將 .well-known 目錄反向代理到 HTTPChallengePort。"
+msgstr ""
+"在取得憑證前,請確保您已將 .well-known 目錄反向代理到 HTTPChallengePort。"
 
 #: src/routes/modules/config.ts:10 src/views/config/ConfigEditor.vue:115
 #: src/views/config/ConfigEditor.vue:166 src/views/config/ConfigList.vue:72
@@ -2823,7 +2841,7 @@ msgstr "每月%{day}日%{time}"
 msgid "Multi-line Directive"
 msgstr "多行指令"
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:182
+#: src/components/NgxConfigEditor/NgxUpstream.vue:189
 #: src/views/backup/AutoBackup/AutoBackup.vue:11
 #: src/views/certificate/ACMEUser.vue:11
 #: src/views/certificate/CertificateEditor.vue:162
@@ -2841,7 +2859,7 @@ msgstr "多行指令"
 #: src/views/stream/columns.tsx:12
 #: src/views/stream/components/RightPanel/Basic.vue:72
 #: src/views/stream/components/StreamDuplicate.vue:71
-#: src/views/stream/StreamList.vue:143
+#: src/views/stream/StreamList.vue:144
 msgid "Name"
 msgstr "名稱"
 
@@ -3072,8 +3090,8 @@ msgstr "Nginx UI 設定已恢復"
 
 #: src/components/SystemRestore/SystemRestoreContent.vue:336
 msgid ""
-"Nginx UI configuration has been restored and will restart automatically in "
-"a few seconds."
+"Nginx UI configuration has been restored and will restart automatically in a "
+"few seconds."
 msgstr "Nginx UI 設定已恢復,將在幾秒後自動重新啟動。"
 
 #: src/language/generate.ts:26
@@ -3097,7 +3115,7 @@ msgstr "Nginx.conf 包含 streams-enabled 目錄"
 #: src/views/notification/Notification.vue:38
 #: src/views/preference/tabs/AuthSettings.vue:132
 #: src/views/preference/tabs/CertSettings.vue:73
-#: src/views/site/site_list/SiteList.vue:98 src/views/stream/StreamList.vue:119
+#: src/views/site/site_list/SiteList.vue:98 src/views/stream/StreamList.vue:120
 msgid "No"
 msgstr "取消"
 
@@ -3226,7 +3244,7 @@ msgid "Off"
 msgstr "關"
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:159
-#: src/components/NgxConfigEditor/NgxUpstream.vue:145
+#: src/components/NgxConfigEditor/NgxUpstream.vue:151
 #: src/components/NodeSelector/NodeSelector.vue:109
 #: src/components/ProxyTargets/ProxyTargets.vue:43
 #: src/views/dashboard/Environments.vue:107
@@ -3247,7 +3265,7 @@ msgstr "離線"
 #: src/views/site/site_list/SiteList.vue:99
 #: src/views/stream/components/RightPanel/Basic.vue:48
 #: src/views/stream/components/StreamStatusSelect.vue:60
-#: src/views/stream/StreamList.vue:120
+#: src/views/stream/StreamList.vue:121
 msgid "OK"
 msgstr "確定"
 
@@ -3349,8 +3367,8 @@ msgid ""
 "facial recognition, a device password, or a PIN. They can be used as a "
 "password replacement or as a 2FA method."
 msgstr ""
-"通行金鑰是 WebAuthn 認證,透過觸控、面部辨識、裝置密碼或 PIN 碼來驗證您的身份。它們可以用作密碼替代品或作為雙重身份驗證 (2FA) "
-"方法。"
+"通行金鑰是 WebAuthn 認證,透過觸控、面部辨識、裝置密碼或 PIN 碼來驗證您的身"
+"份。它們可以用作密碼替代品或作為雙重身份驗證 (2FA) 方法。"
 
 #: src/views/other/Login.vue:183 src/views/user/userColumns.tsx:16
 msgid "Password"
@@ -3483,13 +3501,15 @@ msgstr "請填寫您的 DNS 供應商提供的 API 認證憑據。"
 msgid ""
 "Please first add credentials in Certification > DNS Credentials, and then "
 "select one of the credentialsbelow to request the API of the DNS provider."
-msgstr "請先在「憑證」 > 「DNS 認證」中新增認證,然後選擇以下認證之一以請求 DNS 供應商的 API。"
+msgstr ""
+"請先在「憑證」 > 「DNS 認證」中新增認證,然後選擇以下認證之一以請求 DNS 供應"
+"商的 API。"
 
 #: src/components/Notification/notifications.ts:182
 #: src/language/constants.ts:59
 msgid ""
-"Please generate new recovery codes in the preferences immediately to "
-"prevent lockout."
+"Please generate new recovery codes in the preferences immediately to prevent "
+"lockout."
 msgstr "請立即在偏好設定中產生新的恢復碼,以免無法存取您的賬戶。"
 
 #: src/views/config/components/Rename.vue:65
@@ -3531,7 +3551,8 @@ msgid "Please log in."
 msgstr "請登入。"
 
 #: src/views/certificate/DNSCredential.vue:61
-msgid "Please note that the unit of time configurations below are all in seconds."
+msgid ""
+"Please note that the unit of time configurations below are all in seconds."
 msgstr "請注意,以下時間設定單位均為秒。"
 
 #: src/views/install/components/InstallView.vue:102
@@ -3550,17 +3571,17 @@ msgstr "請選擇備份檔案"
 msgid "Please select at least one item"
 msgstr "請至少選擇一項"
 
-#: src/views/environments/list/Environment.vue:120
+#: src/views/environments/list/Environment.vue:121
 #: src/views/environments/list/Environment.vue:35
 msgid "Please select at least one node to reload Nginx"
 msgstr "請至少選擇一個節點以重新載入 Nginx"
 
-#: src/views/environments/list/Environment.vue:141
+#: src/views/environments/list/Environment.vue:142
 #: src/views/environments/list/Environment.vue:49
 msgid "Please select at least one node to restart Nginx"
 msgstr "請至少選擇一個節點以重啟 Nginx"
 
-#: src/views/environments/list/Environment.vue:99
+#: src/views/environments/list/Environment.vue:100
 msgid "Please select at least one node to upgrade"
 msgstr "請至少選擇一個節點進行升級"
 
@@ -3573,7 +3594,7 @@ msgstr "請輸入「撤銷」以確認"
 msgid "Port"
 msgstr "監聽埠"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:44
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:45
 #: src/views/stream/components/RightPanel/RightPanel.vue:26
 msgid "Port Scanner"
 msgstr "端口掃描器"
@@ -3680,7 +3701,8 @@ msgstr "復原代碼"
 msgid ""
 "Recovery codes are used to access your account when you lose access to your "
 "2FA device. Each code can only be used once."
-msgstr "復原代碼在您無法使用 2FA 裝置時,用於存取您的帳戶。每個代碼僅能使用一次。"
+msgstr ""
+"復原代碼在您無法使用 2FA 裝置時,用於存取您的帳戶。每個代碼僅能使用一次。"
 
 #: src/views/preference/tabs/CertSettings.vue:40
 msgid "Recursive Nameservers"
@@ -3740,8 +3762,8 @@ msgstr "重新載入"
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:136
 #: src/views/environments/group/columns.ts:22
 #: src/views/environments/group/EnvGroup.vue:50
-#: src/views/environments/list/Environment.vue:128
-#: src/views/environments/list/Environment.vue:136
+#: src/views/environments/list/Environment.vue:129
+#: src/views/environments/list/Environment.vue:137
 msgid "Reload Nginx"
 msgstr "重新載入 Nginx"
 
@@ -3790,7 +3812,7 @@ msgstr "移除成功"
 msgid "Removed successfully"
 msgstr "移除成功"
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:126
+#: src/components/NgxConfigEditor/NgxUpstream.vue:131
 #: src/views/config/components/ConfigName.vue:51
 #: src/views/config/components/Rename.vue:56
 #: src/views/config/ConfigList.vue:181
@@ -3906,7 +3928,9 @@ msgid ""
 "Resident Set Size: Actual memory resident in physical memory, including all "
 "shared library memory, which will be repeated calculated for multiple "
 "processes"
-msgstr "常駐集大小:實際存在於實體記憶體中的記憶體,包含所有共用函式庫記憶體,這些記憶體會在多個行程間重複計算"
+msgstr ""
+"常駐集大小:實際存在於實體記憶體中的記憶體,包含所有共用函式庫記憶體,這些記"
+"憶體會在多個行程間重複計算"
 
 #: src/composables/usePerformanceMetrics.ts:109
 #: src/views/dashboard/components/PerformanceTablesCard.vue:69
@@ -3918,8 +3942,8 @@ msgid "Restart"
 msgstr "重新啟動"
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:148
-#: src/views/environments/list/Environment.vue:149
-#: src/views/environments/list/Environment.vue:157
+#: src/views/environments/list/Environment.vue:150
+#: src/views/environments/list/Environment.vue:158
 msgid "Restart Nginx"
 msgstr "重新啟動 Nginx"
 
@@ -4337,19 +4361,19 @@ msgstr "使用 HTTP01 挑戰提供者"
 
 #: src/constants/errors/nginx_log.ts:8
 msgid ""
-"Settings.NginxLogSettings.AccessLogPath is empty, refer to "
-"https://nginxui.com/guide/config-nginx.html for more information"
+"Settings.NginxLogSettings.AccessLogPath is empty, refer to https://nginxui."
+"com/guide/config-nginx.html for more information"
 msgstr ""
-"Settings.NginxLogSettings.AccessLogPath 為空,請參考 "
-"https://nginxui.com/guide/config-nginx.html 了解更多資訊"
+"Settings.NginxLogSettings.AccessLogPath 為空,請參考 https://nginxui.com/"
+"guide/config-nginx.html 了解更多資訊"
 
 #: src/constants/errors/nginx_log.ts:7
 msgid ""
-"Settings.NginxLogSettings.ErrorLogPath is empty, refer to "
-"https://nginxui.com/guide/config-nginx.html for more information"
+"Settings.NginxLogSettings.ErrorLogPath is empty, refer to https://nginxui."
+"com/guide/config-nginx.html for more information"
 msgstr ""
-"Settings.NginxLogSettings.ErrorLogPath 為空,請參考 "
-"https://nginxui.com/guide/config-nginx.html 了解更多資訊"
+"Settings.NginxLogSettings.ErrorLogPath 為空,請參考 https://nginxui.com/"
+"guide/config-nginx.html 了解更多資訊"
 
 #: src/views/install/components/InstallView.vue:65
 msgid "Setup your Nginx UI"
@@ -4580,21 +4604,23 @@ msgstr "星期日"
 msgid ""
 "Support communication with the backend through the Server-Sent Events "
 "protocol. If your Nginx UI is being used via an Nginx reverse proxy, please "
-"refer to this link to write the corresponding configuration file: "
-"https://nginxui.com/guide/nginx-proxy-example.html"
+"refer to this link to write the corresponding configuration file: https://"
+"nginxui.com/guide/nginx-proxy-example.html"
 msgstr ""
-"支援透過 Server-Sent Events 協定與後端通訊。如果您的 Nginx UI 是透過 Nginx "
-"反向代理使用的,請參考此連結編寫相應的設定檔:https://nginxui.com/guide/nginx-proxy-example.html"
+"支援透過 Server-Sent Events 協定與後端通訊。如果您的 Nginx UI 是透過 Nginx 反"
+"向代理使用的,請參考此連結編寫相應的設定檔:https://nginxui.com/guide/nginx-"
+"proxy-example.html"
 
 #: src/components/SelfCheck/tasks/frontend/websocket.ts:13
 msgid ""
 "Support communication with the backend through the WebSocket protocol. If "
-"your Nginx UI is being used via an Nginx reverse proxy, please refer to "
-"this link to write the corresponding configuration file: "
-"https://nginxui.com/guide/nginx-proxy-example.html"
+"your Nginx UI is being used via an Nginx reverse proxy, please refer to this "
+"link to write the corresponding configuration file: https://nginxui.com/"
+"guide/nginx-proxy-example.html"
 msgstr ""
-"支援透過 WebSocket 協議與後端進行通訊。如果您的 Nginx UI 是透過 Nginx "
-"反向代理使用,請參考此連結編寫對應的設定文件:https://nginxui.com/guide/nginx-proxy-example.html"
+"支援透過 WebSocket 協議與後端進行通訊。如果您的 Nginx UI 是透過 Nginx 反向代"
+"理使用,請參考此連結編寫對應的設定文件:https://nginxui.com/guide/nginx-"
+"proxy-example.html"
 
 #: src/language/curd.ts:51 src/language/curd.ts:55
 msgid "Support single or batch upload of files"
@@ -4737,7 +4763,9 @@ msgid ""
 "The certificate for the domain will be checked 30 minutes, and will be "
 "renewed if it has been more than 1 week or the period you set in settings "
 "since it was last issued."
-msgstr "網域憑證將在 30 分鐘內接受檢查,如果自上次簽發以來已超過 1 週或您在設定中設定的時間,憑證將會自動更新。"
+msgstr ""
+"網域憑證將在 30 分鐘內接受檢查,如果自上次簽發以來已超過 1 週或您在設定中設定"
+"的時間,憑證將會自動更新。"
 
 #: src/views/preference/tabs/NodeSettings.vue:37
 msgid ""
@@ -4755,8 +4783,7 @@ msgstr "輸入的不是 SSL 憑證金鑰"
 
 #: src/constants/errors/nginx_log.ts:2
 msgid ""
-"The log path is not under the paths in "
-"settings.NginxSettings.LogDirWhiteList"
+"The log path is not under the paths in settings.NginxSettings.LogDirWhiteList"
 msgstr "日誌路徑不在 settings.NginxSettings.LogDirWhiteList 設定中的路徑範圍內"
 
 #: src/views/preference/tabs/OpenAISettings.vue:23
@@ -4767,7 +4794,8 @@ msgid ""
 msgstr "模型名稱僅能包含字母、Unicode 字元、數字、連字號、破折號、冒號和句點。"
 
 #: src/views/preference/tabs/OpenAISettings.vue:90
-msgid "The model used for code completion, if not set, the chat model will be used."
+msgid ""
+"The model used for code completion, if not set, the chat model will be used."
 msgstr "用於代碼補全的模型,如果未設置,將使用聊天模型。"
 
 #: src/views/preference/tabs/NodeSettings.vue:18
@@ -4799,7 +4827,9 @@ msgid ""
 "The remote Nginx UI version is not compatible with the local Nginx UI "
 "version. To avoid potential errors, please upgrade the remote Nginx UI to "
 "match the local version."
-msgstr "遠端 Nginx UI 版本與本機 Nginx UI 版本不相容。為避免潛在錯誤,請升級遠端 Nginx UI 以匹配本機版本。"
+msgstr ""
+"遠端 Nginx UI 版本與本機 Nginx UI 版本不相容。為避免潛在錯誤,請升級遠端 "
+"Nginx UI 以匹配本機版本。"
 
 #: src/components/AutoCertForm/AutoCertForm.vue:43
 msgid ""
@@ -4834,7 +4864,9 @@ msgid ""
 "These codes are the last resort for accessing your account in case you lose "
 "your password and second factors. If you cannot find these codes, you will "
 "lose access to your account."
-msgstr "這些代碼是您在遺失密碼和第二重驗證因素時,存取帳戶的最後手段。如果您找不到這些代碼,您將無法再存取您的帳戶。"
+msgstr ""
+"這些代碼是您在遺失密碼和第二重驗證因素時,存取帳戶的最後手段。如果您找不到這"
+"些代碼,您將無法再存取您的帳戶。"
 
 #: src/views/certificate/CertificateEditor.vue:102
 msgid "This Auto Cert item is invalid, please remove it."
@@ -4863,13 +4895,14 @@ msgid "This field should not be empty"
 msgstr "此欄位不應為空"
 
 #: src/constants/form_errors.ts:6
-msgid "This field should only contain letters, unicode characters, numbers, and -_."
+msgid ""
+"This field should only contain letters, unicode characters, numbers, and -_."
 msgstr "此欄位僅能包含字母、Unicode 字元、數字、連字號、破折號和底線。"
 
 #: src/language/curd.ts:44
 msgid ""
-"This field should only contain letters, unicode characters, numbers, and "
-"-_./:"
+"This field should only contain letters, unicode characters, numbers, and -"
+"_./:"
 msgstr "此欄位應僅包含字母、Unicode字符、數字和 -_./:"
 
 #: src/views/dashboard/NginxDashBoard.vue:150
@@ -4909,7 +4942,8 @@ msgid ""
 msgstr "這將恢復設定檔案和資料庫。恢復完成後,Nginx UI 將重新啟動。"
 
 #: src/views/environments/list/BatchUpgrader.vue:182
-msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
+msgid ""
+"This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
 msgstr "這將在 %{nodeNames} 上升級或重新安裝 Nginx UI 到 %{version}。"
 
 #: src/views/preference/tabs/AuthSettings.vue:92
@@ -4930,7 +4964,9 @@ msgstr "提示"
 msgid ""
 "Tips: You can increase the concurrency processing capacity by increasing "
 "worker_processes or worker_connections"
-msgstr "提示:您可以通過增加 worker_processes 或 worker_connections 來提高並行處理能力"
+msgstr ""
+"提示:您可以通過增加 worker_processes 或 worker_connections 來提高並行處理能"
+"力"
 
 #: src/views/notification/notificationColumns.tsx:58
 msgid "Title"
@@ -4944,25 +4980,28 @@ msgstr "若要確認撤銷,請在下方欄位中輸入「撤銷」:"
 msgid ""
 "To enable it, you need to install the Google or Microsoft Authenticator app "
 "on your mobile phone."
-msgstr "要啟用它,您需要在手機上安裝 Google 或 Microsoft Authenticator 應用程式。"
+msgstr ""
+"要啟用它,您需要在手機上安裝 Google 或 Microsoft Authenticator 應用程式。"
 
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:89
 msgid ""
 "To ensure security, Webauthn configuration cannot be added through the UI. "
 "Please manually configure the following in the app.ini configuration file "
 "and restart Nginx UI."
-msgstr "為確保安全性,Webauthn 設定無法透過 UI 新增。請在 app.ini 設定檔中手動設定以下內容,並重新啟動 Nginx UI。"
+msgstr ""
+"為確保安全性,Webauthn 設定無法透過 UI 新增。請在 app.ini 設定檔中手動設定以"
+"下內容,並重新啟動 Nginx UI。"
 
 #: src/views/site/site_edit/components/Cert/IssueCert.vue:34
 #: src/views/site/site_edit/components/EnableTLS/EnableTLS.vue:15
 msgid ""
 "To make sure the certification auto-renewal can work normally, we need to "
-"add a location which can proxy the request from authority to backend, and "
-"we need to save this file and reload the Nginx. Are you sure you want to "
+"add a location which can proxy the request from authority to backend, and we "
+"need to save this file and reload the Nginx. Are you sure you want to "
 "continue?"
 msgstr ""
-"為了確保憑證自動續期能夠正常運作,我們需要新增一個 Location 來代理從授權後端的請求,我們需要儲存這個檔案並重新載入 "
-"Nginx。你確定你要繼續嗎?"
+"為了確保憑證自動續期能夠正常運作,我們需要新增一個 Location 來代理從授權後端"
+"的請求,我們需要儲存這個檔案並重新載入 Nginx。你確定你要繼續嗎?"
 
 #: src/views/preference/tabs/OpenAISettings.vue:36
 msgid ""
@@ -4970,8 +5009,8 @@ msgid ""
 "provide an OpenAI-compatible API endpoint, so just set the baseUrl to your "
 "local API."
 msgstr ""
-"要使用本機大型語言模型,請使用 ollama、vllm 或 lmdeploy 部署。它們提供與 OpenAI 相容的 API 端點,因此只需將 "
-"baseUrl 設定為您的本機 API。"
+"要使用本機大型語言模型,請使用 ollama、vllm 或 lmdeploy 部署。它們提供與 "
+"OpenAI 相容的 API 端點,因此只需將 baseUrl 設定為您的本機 API。"
 
 #: src/views/dashboard/NginxDashBoard.vue:55
 msgid "Toggle failed"
@@ -5078,8 +5117,8 @@ msgid "Updated at"
 msgstr "更新時間"
 
 #: src/routes/modules/system.ts:26
-#: src/views/environments/list/Environment.vue:107
-#: src/views/environments/list/Environment.vue:115
+#: src/views/environments/list/Environment.vue:108
+#: src/views/environments/list/Environment.vue:116
 #: src/views/system/Upgrade.vue:154 src/views/system/Upgrade.vue:159
 msgid "Upgrade"
 msgstr "升級"
@@ -5109,7 +5148,7 @@ msgstr "上傳資料夾"
 msgid "Upstream"
 msgstr "上游"
 
-#: src/components/NgxConfigEditor/NgxUpstream.vue:177
+#: src/components/NgxConfigEditor/NgxUpstream.vue:184
 msgid "Upstream Name"
 msgstr "Upstream 名稱"
 
@@ -5224,7 +5263,9 @@ msgid ""
 "Warning: Restore operation will overwrite current configurations. Make sure "
 "you have a valid backup file and security token, and carefully select what "
 "to restore."
-msgstr "警告:恢復操作將覆蓋目前設定。請確保您擁有有效的備份檔案和安全令牌,並謹慎選擇要恢復的內容。"
+msgstr ""
+"警告:恢復操作將覆蓋目前設定。請確保您擁有有效的備份檔案和安全令牌,並謹慎選"
+"擇要恢復的內容。"
 
 #: src/views/certificate/DNSCredential.vue:55
 msgid ""
@@ -5234,9 +5275,11 @@ msgstr "我們將在您的網域的 DNS 記錄中新增一個或多個 TXT 記
 
 #: src/views/site/site_edit/components/Cert/ObtainCert.vue:140
 msgid ""
-"We will remove the HTTPChallenge configuration from this file and reload "
-"the Nginx. Are you sure you want to continue?"
-msgstr "我們將從該檔案中刪除 HTTPChallenge 設定並重新載入 Nginx 設定檔案。你確定你要繼續嗎?"
+"We will remove the HTTPChallenge configuration from this file and reload the "
+"Nginx. Are you sure you want to continue?"
+msgstr ""
+"我們將從該檔案中刪除 HTTPChallenge 設定並重新載入 Nginx 設定檔案。你確定你要"
+"繼續嗎?"
 
 #: src/views/preference/tabs/AuthSettings.vue:65
 msgid "Webauthn"
@@ -5267,14 +5310,18 @@ msgid ""
 "When Enabled, Nginx UI will automatically re-register users upon startup. "
 "Generally, do not enable this unless you are in a dev environment and using "
 "Pebble as CA."
-msgstr "啟用後,Nginx UI 將在啟動時自動重新註冊使用者。通常,除非您處於開發環境並使用 Pebble 作為 CA,否則不建議啟用此功能。"
+msgstr ""
+"啟用後,Nginx UI 將在啟動時自動重新註冊使用者。通常,除非您處於開發環境並使"
+"用 Pebble 作為 CA,否則不建議啟用此功能。"
 
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:61
 #: src/views/stream/components/RightPanel/Basic.vue:98
 msgid ""
 "When you enable/disable, delete, or save this site, the nodes set in the "
 "Node Group and the nodes selected below will be synchronized."
-msgstr "當您啟用/停用、刪除或儲存此網站時,在節點群組中設定的節點以及下方選擇的節點將會同步更新。"
+msgstr ""
+"當您啟用/停用、刪除或儲存此網站時,在節點群組中設定的節點以及下方選擇的節點將"
+"會同步更新。"
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:140
 msgid ""
@@ -5330,9 +5377,11 @@ msgstr "是的"
 
 #: src/views/terminal/Terminal.vue:132
 msgid ""
-"You are accessing this terminal over an insecure HTTP connection on a "
-"non-localhost domain. This may expose sensitive information."
-msgstr "您正在透過非本地主機域上的不安全 HTTP 連線存取此終端機。這可能會暴露敏感資訊。"
+"You are accessing this terminal over an insecure HTTP connection on a non-"
+"localhost domain. This may expose sensitive information."
+msgstr ""
+"您正在透過非本地主機域上的不安全 HTTP 連線存取此終端機。這可能會暴露敏感資"
+"訊。"
 
 #: src/views/system/Upgrade.vue:224
 msgid "You are using the latest version"
@@ -5357,7 +5406,8 @@ msgid ""
 msgstr "您尚未設定 Webauthn 設定,因此無法新增通行金鑰。"
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:81
-msgid "You have not enabled 2FA yet. Please enable 2FA to generate recovery codes."
+msgid ""
+"You have not enabled 2FA yet. Please enable 2FA to generate recovery codes."
 msgstr "您尚未啟用雙重身份驗證 (2FA)。請啟用 2FA 以生成復原代碼。"
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:94
@@ -5439,11 +5489,12 @@ msgstr "您的通行金鑰"
 
 #~ msgid ""
 #~ "Check if /var/run/docker.sock exists. If you are using Nginx UI Official "
-#~ "Docker Image, please make sure the docker socket is mounted like this: `-v "
-#~ "/var/run/docker.sock:/var/run/docker.sock`."
+#~ "Docker Image, please make sure the docker socket is mounted like this: `-"
+#~ "v /var/run/docker.sock:/var/run/docker.sock`."
 #~ msgstr ""
-#~ "檢查 /var/run/docker.sock 是否存在。如果您正在使用 Nginx UI 官方 Docker 映像,請確保 Docker "
-#~ "通訊端已掛載如下:`-v /var/run/docker.sock:/var/run/docker.sock`。"
+#~ "檢查 /var/run/docker.sock 是否存在。如果您正在使用 Nginx UI 官方 Docker 映"
+#~ "像,請確保 Docker 通訊端已掛載如下:`-v /var/run/docker.sock:/var/run/"
+#~ "docker.sock`。"
 
 #~ msgid "Check if the nginx access log path exists"
 #~ msgstr "檢查 Nginx 存取日誌路徑是否存在"
@@ -5480,7 +5531,8 @@ msgstr "您的通行金鑰"
 #~ msgid ""
 #~ "If logs are not indexed, please check if the log file is under the "
 #~ "directory in Nginx.LogDirWhiteList."
-#~ msgstr "如果日誌未被索引,請檢查日誌檔案是否位於 Nginx 的 LogDirWhiteList 目錄下。"
+#~ msgstr ""
+#~ "如果日誌未被索引,請檢查日誌檔案是否位於 Nginx 的 LogDirWhiteList 目錄下。"
 
 #~ msgid "Indexed"
 #~ msgstr "已建立索引"
@@ -5502,9 +5554,11 @@ msgstr "您的通行金鑰"
 #~ msgstr "儲存失敗,在設定中偵測到語法錯誤。"
 
 #~ msgid ""
-#~ "When you enable/disable, delete, or save this stream, the nodes set in the "
-#~ "Node Group and the nodes selected below will be synchronized."
-#~ msgstr "當您啟用/停用、刪除或儲存此串流時,在節點群組中設定的節點以及下方選擇的節點將會同步更新。"
+#~ "When you enable/disable, delete, or save this stream, the nodes set in "
+#~ "the Node Group and the nodes selected below will be synchronized."
+#~ msgstr ""
+#~ "當您啟用/停用、刪除或儲存此串流時,在節點群組中設定的節點以及下方選擇的節"
+#~ "點將會同步更新。"
 
 #, fuzzy
 #~ msgid "Access Token"
@@ -5563,11 +5617,17 @@ msgstr "您的通行金鑰"
 #~ msgid "Please upgrade the remote Nginx UI to the latest version"
 #~ msgstr "請將遠端 Nginx UI 升級至最新版本"
 
-#~ msgid "Rename %{orig_path} to %{new_path} on %{env_name} failed, response: %{resp}"
-#~ msgstr "在 %{env_name} 上將 %{orig_path} 重新命名為 %{new_path} 失敗,回應:%{resp}"
+#~ msgid ""
+#~ "Rename %{orig_path} to %{new_path} on %{env_name} failed, response: "
+#~ "%{resp}"
+#~ msgstr ""
+#~ "在 %{env_name} 上將 %{orig_path} 重新命名為 %{new_path} 失敗,回應:"
+#~ "%{resp}"
 
-#~ msgid "Rename Site %{site} to %{new_site} on %{node} error, response: %{resp}"
-#~ msgstr "將站點 %{site} 重新命名為 %{new_site} 於 %{node} 時發生錯誤,回應:%{resp}"
+#~ msgid ""
+#~ "Rename Site %{site} to %{new_site} on %{node} error, response: %{resp}"
+#~ msgstr ""
+#~ "將站點 %{site} 重新命名為 %{new_site} 於 %{node} 時發生錯誤,回應:%{resp}"
 
 #~ msgid "Save site %{site} to %{node} error, response: %{resp}"
 #~ msgstr "儲存站點 %{site} 至 %{node} 時發生錯誤,回應:%{resp}"
@@ -5575,23 +5635,27 @@ msgstr "您的通行金鑰"
 #~ msgid ""
 #~ "Sync Certificate %{cert_name} to %{env_name} failed, please upgrade the "
 #~ "remote Nginx UI to the latest version"
-#~ msgstr "同步憑證 %{cert_name} 到 %{env_name} 失敗,請將遠端 Nginx UI 升級到最新版本"
+#~ msgstr ""
+#~ "同步憑證 %{cert_name} 到 %{env_name} 失敗,請將遠端 Nginx UI 升級到最新版"
+#~ "本"
 
-#~ msgid "Sync Certificate %{cert_name} to %{env_name} failed, response: %{resp}"
+#~ msgid ""
+#~ "Sync Certificate %{cert_name} to %{env_name} failed, response: %{resp}"
 #~ msgstr "同步憑證 %{cert_name} 到 %{env_name} 失敗,回應:%{resp}"
 
 #~ msgid "Sync config %{config_name} to %{env_name} failed, response: %{resp}"
 #~ msgstr "同步設定 %{config_name} 到 %{env_name} 失敗,回應:%{resp}"
 
 #~ msgid ""
-#~ "If you lose your mobile phone, you can use the recovery code to reset your "
-#~ "2FA."
+#~ "If you lose your mobile phone, you can use the recovery code to reset "
+#~ "your 2FA."
 #~ msgstr "如果您遺失了手機,可以使用恢復碼重設您的多重因素驗證驗證。"
 
 #~ msgid "Recovery Code:"
 #~ msgstr "恢復碼:"
 
-#~ msgid "The recovery code is only displayed once, please save it in a safe place."
+#~ msgid ""
+#~ "The recovery code is only displayed once, please save it in a safe place."
 #~ msgstr "恢復碼僅顯示一次,請將其儲存在安全的地方。"
 
 #~ msgid "File"
@@ -5609,7 +5673,9 @@ msgstr "您的通行金鑰"
 #~ msgid ""
 #~ "Rename %{orig_path} to %{new_path} on %{env_name} failed, please upgrade "
 #~ "the remote Nginx UI to the latest version"
-#~ msgstr "將 %{orig_path} 重新命名為 %{new_path} 在 %{env_name} 失敗,請將遠端 Nginx UI 升級到最新版本"
+#~ msgstr ""
+#~ "將 %{orig_path} 重新命名為 %{new_path} 在 %{env_name} 失敗,請將遠端 "
+#~ "Nginx UI 升級到最新版本"
 
 #~ msgid "Server Name"
 #~ msgstr "伺服器名稱"
@@ -5672,8 +5738,9 @@ msgstr "您的通行金鑰"
 #~ "Once the verification is complete, the records will be removed.\n"
 #~ "Please note that the unit of time configurations below are all in seconds."
 #~ msgstr ""
-#~ "請填寫您的 DNS 供應商提供的 API 身份驗證認證。我們會將一個或多個 TXT 記錄新增到您網域的 DNS "
-#~ "記錄中以進行所有權驗證。驗證完成後,記錄將被刪除。請注意,以下時間設定均以秒為單位。"
+#~ "請填寫您的 DNS 供應商提供的 API 身份驗證認證。我們會將一個或多個 TXT 記錄"
+#~ "新增到您網域的 DNS 記錄中以進行所有權驗證。驗證完成後,記錄將被刪除。請注"
+#~ "意,以下時間設定均以秒為單位。"
 
 #~ msgid "Delete ID: %{id}"
 #~ msgstr "刪除 ID: %{id}"
@@ -5697,9 +5764,11 @@ msgstr "您的通行金鑰"
 #~ msgstr "您要啟用自動憑證更新嗎?"
 
 #~ msgid ""
-#~ "We need to add the HTTPChallenge configuration to this file and reload the "
-#~ "Nginx. Are you sure you want to continue?"
-#~ msgstr "我們需要將 HTTPChallenge 設定新增到此檔案並重新載入 Nginx。你確定你要繼續嗎?"
+#~ "We need to add the HTTPChallenge configuration to this file and reload "
+#~ "the Nginx. Are you sure you want to continue?"
+#~ msgstr ""
+#~ "我們需要將 HTTPChallenge 設定新增到此檔案並重新載入 Nginx。你確定你要繼續"
+#~ "嗎?"
 
 #~ msgid "Chat with ChatGPT"
 #~ msgstr "使用 ChatGPT 聊天"
@@ -5743,8 +5812,8 @@ msgstr "您的通行金鑰"
 #~ "you do not have a certificate before, please click \"Getting Certificate "
 #~ "from Let's Encrypt\" first."
 #~ msgstr ""
-#~ "系統將會每小時偵測一次該域名憑證,若距離上次簽發已超過 1 個月,則將自動續簽。<br/>如果您之前沒有憑證,請先點選「從 Let's Encrypt "
-#~ "取得憑證」。"
+#~ "系統將會每小時偵測一次該域名憑證,若距離上次簽發已超過 1 個月,則將自動續"
+#~ "簽。<br/>如果您之前沒有憑證,請先點選「從 Let's Encrypt 取得憑證」。"
 
 #~ msgid "Do you want to change the template to support the TLS?"
 #~ msgstr "你想要改變範本以支援 TLS 嗎?"
@@ -5762,12 +5831,15 @@ msgstr "您的通行金鑰"
 #~ "The following values will only take effect if you have the corresponding "
 #~ "fields in your configuration file. The configuration filename cannot be "
 #~ "changed after it has been created."
-#~ msgstr "只有在您的設定檔案中有相應欄位時,下列的設定才能生效。設定檔名稱建立後不可修改。"
+#~ msgstr ""
+#~ "只有在您的設定檔案中有相應欄位時,下列的設定才能生效。設定檔名稱建立後不可"
+#~ "修改。"
 
 #~ msgid "This operation will lose the custom configuration."
 #~ msgstr "該操作將會遺失自定義設定。"
 
-#~ msgid "Add site here first, then you can configure TLS on the domain edit page."
+#~ msgid ""
+#~ "Add site here first, then you can configure TLS on the domain edit page."
 #~ msgstr "在這裡新增網站,完成後可進入編輯頁面設定 TLS。"
 
 #~ msgid "Server Status"

+ 0 - 6
app/src/views/config/ConfigEditor.vue

@@ -1,7 +1,5 @@
 <script setup lang="ts">
-import type { Ref } from 'vue'
 import type { Config } from '@/api/config'
-import type { ChatComplicationMessage } from '@/api/openai'
 import { HistoryOutlined, InfoCircleOutlined } from '@ant-design/icons-vue'
 import { message } from 'ant-design-vue'
 import { trim, trimEnd } from 'lodash'
@@ -45,7 +43,6 @@ const data = ref({
   sync_overwrite: false,
 } as Config)
 
-const historyChatgptRecord = ref([]) as Ref<ChatComplicationMessage[]>
 const activeKey = ref(['basic', 'deploy', 'chatgpt'])
 const modifiedAt = ref('')
 const nginxConfigBase = ref('')
@@ -72,7 +69,6 @@ async function init() {
   if (!addMode.value) {
     config.getItem(relativePath.value).then(r => {
       data.value = r
-      historyChatgptRecord.value = r.chatgpt_messages
       modifiedAt.value = r.modified_at
 
       const filteredPath = trimEnd(data.value.filepath
@@ -124,7 +120,6 @@ async function init() {
   }
   else {
     data.value.content = ''
-    historyChatgptRecord.value = []
     data.value.filepath = ''
 
     const pathSegments = basePath.value
@@ -366,7 +361,6 @@ function openHistory() {
             header="ChatGPT"
           >
             <ChatGPT
-              v-model:history-messages="historyChatgptRecord"
               :content="data.content"
               :path="data.filepath"
             />

+ 4 - 5
app/src/views/site/site_edit/SiteEdit.vue

@@ -33,12 +33,11 @@ import SiteEditor from '@/views/site/site_edit/components/SiteEditor'
 </template>
 
 <style lang="less" scoped>
-.site-container {
-  max-height: calc(100vh - 267px);
-  overflow-y: auto;
-}
-
 :deep(.ant-card) {
   box-shadow: unset;
+
+  .card-body, .ant-tabs-content {
+    max-height: calc(100vh - 260px);
+  }
 }
 </style>

+ 1 - 1
app/src/views/site/site_edit/components/RightPanel/Basic.vue

@@ -22,7 +22,7 @@ function handleStatusChanged(event: { status: SiteStatus }) {
 </script>
 
 <template>
-  <div>
+  <div class="px-6">
     <div class="mb-6">
       <AForm layout="vertical">
         <AFormItem :label="$gettext('Status')">

+ 0 - 2
app/src/views/site/site_edit/components/RightPanel/Chat.vue

@@ -6,14 +6,12 @@ const editorStore = useSiteEditorStore()
 const {
   configText,
   filepath,
-  historyChatgptRecord,
 } = storeToRefs(editorStore)
 </script>
 
 <template>
   <div class="mt--4">
     <ChatGPT
-      v-model:history-messages="historyChatgptRecord"
       :content="configText"
       :path="filepath"
     />

+ 1 - 1
app/src/views/site/site_edit/components/RightPanel/ConfigTemplate.vue

@@ -3,7 +3,7 @@ import ConfigTemplate from '../ConfigTemplate'
 </script>
 
 <template>
-  <div>
+  <div class="px-6">
     <ConfigTemplate />
   </div>
 </template>

+ 15 - 7
app/src/views/site/site_edit/components/RightPanel/RightPanel.vue

@@ -54,13 +54,13 @@ watch(advanceMode, val => {
   position: relative;
 
   .right-settings {
-    max-height: calc(100vh - 323px);
-    overflow-y: scroll;
+    overflow-y: auto;
     position: relative;
   }
 
   :deep(.ant-card-body) {
-    padding: 19.5px 24px;
+    padding: 0;
+    position: relative;
   }
 
   :deep(.ant-tabs-nav) {
@@ -68,9 +68,17 @@ watch(advanceMode, val => {
   }
 }
 
-:deep(.ant-tabs-content) {
-  padding-top: 24px;
-  max-height: calc(100vh - 425px);
-  overflow-y: scroll;
+:deep(.ant-tabs) {
+  margin-bottom: 0;
+
+  .ant-tabs-nav-wrap {
+    height: 55px;
+    padding: 0 24px;
+  }
+
+  .ant-tabs-content {
+    padding-top: 24px;
+    overflow-y: auto;
+  }
 }
 </style>

+ 49 - 41
app/src/views/site/site_edit/components/SiteEditor/SiteEditor.vue

@@ -100,49 +100,54 @@ async function save() {
       </ASpace>
     </template>
 
-    <Transition name="slide-fade">
-      <div
-        v-if="advanceMode"
-        key="advance"
-      >
+    <div class="card-body">
+      <Transition name="slide-fade">
         <div
-          v-if="parseErrorStatus"
-          class="parse-error-alert-wrapper"
+          v-if="advanceMode"
+          key="advance"
         >
-          <AAlert
-            :message="$gettext('Nginx Configuration Parse Error')"
-            :description="parseErrorMessage"
-            type="error"
-            show-icon
-          />
-        </div>
-        <div>
-          <CodeEditor v-model:content="configText" />
+          <div
+            v-if="parseErrorStatus"
+            class="parse-error-alert-wrapper"
+          >
+            <AAlert
+              :message="$gettext('Nginx Configuration Parse Error')"
+              :description="parseErrorMessage"
+              type="error"
+              show-icon
+            />
+          </div>
+          <div>
+            <CodeEditor
+              v-model:content="configText"
+              no-border-radius
+            />
+          </div>
         </div>
-      </div>
 
-      <div
-        v-else
-        key="basic"
-        class="domain-edit-container"
-      >
-        <EnableTLS />
-        <NgxConfigEditor
-          :cert-info="certInfoMap"
-          :status="data.status"
+        <div
+          v-else
+          key="basic"
+          class="domain-edit-container"
         >
-          <template #tab-content="{ tabIdx }">
-            <Cert
-              v-if="curSupportSSL"
-              class="mb-4"
-              :site-status="data.status"
-              :config-name="name"
-              :cert-info="certInfoMap?.[tabIdx]"
-            />
-          </template>
-        </NgxConfigEditor>
-      </div>
-    </Transition>
+          <EnableTLS />
+          <NgxConfigEditor
+            :cert-info="certInfoMap"
+            :status="data.status"
+          >
+            <template #tab-content="{ tabIdx }">
+              <Cert
+                v-if="curSupportSSL"
+                class="mb-4"
+                :site-status="data.status"
+                :config-name="name"
+                :cert-info="certInfoMap?.[tabIdx]"
+              />
+            </template>
+          </NgxConfigEditor>
+        </div>
+      </Transition>
+    </div>
 
     <FooterToolBar>
       <ASpace>
@@ -179,8 +184,9 @@ async function save() {
 }
 
 .domain-edit-container {
-    max-width: 800px;
-    margin: 0 auto;
+  max-width: 800px;
+  margin: 0 auto;
+  padding: 24px 0;
 }
 
 .parse-error-alert-wrapper {
@@ -188,9 +194,11 @@ async function save() {
 }
 
 .site-edit-container {
+  height: 100%;
   :deep(.ant-card-body) {
-    max-height: calc(100vh - 375px);
+    max-height: 100%;
     overflow-y: scroll;
+    padding: 0;
   }
 }
 

+ 5 - 12
app/src/views/site/site_edit/components/SiteEditor/store.ts

@@ -1,5 +1,4 @@
 import type { CertificateInfo } from '@/api/cert'
-import type { ChatComplicationMessage } from '@/api/openai'
 import type { Site } from '@/api/site'
 import type { CheckedType } from '@/types'
 import config from '@/api/config'
@@ -12,7 +11,6 @@ export const useSiteEditorStore = defineStore('siteEditor', () => {
   const parseErrorStatus = ref(false)
   const parseErrorMessage = ref('')
   const data = ref({}) as Ref<Site>
-  const historyChatgptRecord = ref([]) as Ref<ChatComplicationMessage[]>
   const loading = ref(true)
   const saving = ref(false)
   const autoCert = ref(false)
@@ -40,16 +38,13 @@ export const useSiteEditorStore = defineStore('siteEditor', () => {
 
     if (name.value) {
       try {
-        const r = await site.getItem(name.value)
+        const r = await site.getItem(encodeURIComponent(name.value))
         handleResponse(r)
       }
       catch (error) {
         handleParseError(error as { error?: string, message: string })
       }
     }
-    else {
-      historyChatgptRecord.value = []
-    }
     loading.value = false
   }
 
@@ -67,7 +62,7 @@ export const useSiteEditorStore = defineStore('siteEditor', () => {
         await buildConfig()
       }
 
-      const response = await site.updateItem(name.value, {
+      const response = await site.updateItem(encodeURIComponent(name.value), {
         content: configText.value,
         overwrite: true,
         env_group_id: data.value.env_group_id,
@@ -89,7 +84,7 @@ export const useSiteEditorStore = defineStore('siteEditor', () => {
     console.error(e)
     parseErrorStatus.value = true
     parseErrorMessage.value = e.message
-    config.getItem(`sites-available/${name.value}`).then(r => {
+    config.getItem(`sites-available/${encodeURIComponent(name.value)}`).then(r => {
       configText.value = r.content
     })
   }
@@ -104,7 +99,6 @@ export const useSiteEditorStore = defineStore('siteEditor', () => {
     filepath.value = r.filepath
     configText.value = r.config
     autoCert.value = r.auto_cert
-    historyChatgptRecord.value = r.chatgpt_messages
     data.value = r
     autoCert.value = r.auto_cert
     certInfoMap.value = r.cert_info || {}
@@ -120,13 +114,13 @@ export const useSiteEditorStore = defineStore('siteEditor', () => {
     loading.value = true
 
     try {
-      await site.advance_mode(name.value, { advanced: advanced as boolean })
+      await site.advance_mode(encodeURIComponent(name.value), { advanced: advanced as boolean })
       advanceMode.value = advanced as boolean
       if (advanced) {
         await buildConfig()
       }
       else {
-        let r = await site.getItem(name.value)
+        let r = await site.getItem(encodeURIComponent(name.value))
         await handleResponse(r)
         r = await ngx.tokenize_config(configText.value)
         Object.assign(ngxConfig, {
@@ -160,7 +154,6 @@ export const useSiteEditorStore = defineStore('siteEditor', () => {
     parseErrorStatus,
     parseErrorMessage,
     data,
-    historyChatgptRecord,
     loading,
     saving,
     autoCert,

+ 1 - 2
app/src/views/stream/components/RightPanel/Chat.vue

@@ -3,13 +3,12 @@ import ChatGPT from '@/components/ChatGPT'
 import { useStreamEditorStore } from '../../store'
 
 const store = useStreamEditorStore()
-const { configText, filepath, historyChatgptRecord } = storeToRefs(store)
+const { configText, filepath } = storeToRefs(store)
 </script>
 
 <template>
   <div>
     <ChatGPT
-      v-model:history-messages="historyChatgptRecord"
       :content="configText"
       :path="filepath"
     />

+ 6 - 12
app/src/views/stream/store.ts

@@ -1,5 +1,4 @@
 import type { CertificateInfo } from '@/api/cert'
-import type { ChatComplicationMessage } from '@/api/openai'
 import type { Stream } from '@/api/stream'
 import type { CheckedType } from '@/types'
 import config from '@/api/config'
@@ -14,7 +13,6 @@ export const useStreamEditorStore = defineStore('streamEditor', () => {
   const parseErrorStatus = ref(false)
   const parseErrorMessage = ref('')
   const data = ref({}) as Ref<Stream>
-  const historyChatgptRecord = ref([]) as Ref<ChatComplicationMessage[]>
   const loading = ref(true)
   const saving = ref(false)
   const autoCert = ref(false)
@@ -33,16 +31,14 @@ export const useStreamEditorStore = defineStore('streamEditor', () => {
 
     if (name.value) {
       try {
-        const r = await stream.getItem(name.value)
+        const r = await stream.getItem(encodeURIComponent(name.value))
         handleResponse(r)
       }
       catch (error) {
         handleParseError(error as { error?: string, message: string })
       }
     }
-    else {
-      historyChatgptRecord.value = []
-    }
+
     loading.value = false
   }
 
@@ -60,7 +56,7 @@ export const useStreamEditorStore = defineStore('streamEditor', () => {
         await buildConfig()
       }
 
-      const response = await stream.updateItem(name.value, {
+      const response = await stream.updateItem(encodeURIComponent(name.value), {
         content: configText.value,
         overwrite: true,
         env_group_id: data.value.env_group_id,
@@ -82,7 +78,7 @@ export const useStreamEditorStore = defineStore('streamEditor', () => {
     console.error(e)
     parseErrorStatus.value = true
     parseErrorMessage.value = e.message
-    config.getItem(`streams-available/${name.value}`).then(r => {
+    config.getItem(`streams-available/${encodeURIComponent(name.value)}`).then(r => {
       configText.value = r.content
     })
   }
@@ -97,7 +93,6 @@ export const useStreamEditorStore = defineStore('streamEditor', () => {
     filename.value = r.name
     filepath.value = r.filepath
     configText.value = r.config
-    historyChatgptRecord.value = r.chatgpt_messages
     data.value = r
     Object.assign(ngxConfig, r.tokenized)
 
@@ -111,13 +106,13 @@ export const useStreamEditorStore = defineStore('streamEditor', () => {
     loading.value = true
 
     try {
-      await stream.advance_mode(name.value, { advanced: advanced as boolean })
+      await stream.advance_mode(encodeURIComponent(name.value), { advanced: advanced as boolean })
       advanceMode.value = advanced as boolean
       if (advanced) {
         await buildConfig()
       }
       else {
-        let r = await stream.getItem(name.value)
+        let r = await stream.getItem(encodeURIComponent(name.value))
         await handleResponse(r)
         r = await ngx.tokenize_config(configText.value)
         Object.assign(ngxConfig, {
@@ -140,7 +135,6 @@ export const useStreamEditorStore = defineStore('streamEditor', () => {
     parseErrorStatus,
     parseErrorMessage,
     data,
-    historyChatgptRecord,
     loading,
     saving,
     autoCert,

+ 1 - 1
app/src/views/terminal/Terminal.vue

@@ -147,7 +147,7 @@ onUnmounted(() => {
 
 <style lang="less" scoped>
 .console {
-  min-height: calc(100vh - 300px);
+  min-height: calc(100vh - 200px);
 
   :deep(.terminal) {
     padding: 10px;

+ 14 - 16
internal/config/config.go

@@ -5,7 +5,6 @@ import (
 
 	"github.com/0xJacky/Nginx-UI/internal/upstream"
 	"github.com/0xJacky/Nginx-UI/model"
-	"github.com/sashabaranov/go-openai"
 )
 
 type ConfigStatus string
@@ -20,19 +19,18 @@ const (
 type ProxyTarget = upstream.ProxyTarget
 
 type Config struct {
-	Name            string                         `json:"name"`
-	Content         string                         `json:"content"`
-	ChatGPTMessages []openai.ChatCompletionMessage `json:"chatgpt_messages,omitempty"`
-	FilePath        string                         `json:"filepath,omitempty"`
-	ModifiedAt      time.Time                      `json:"modified_at"`
-	Size            int64                          `json:"size,omitempty"`
-	IsDir           bool                           `json:"is_dir"`
-	EnvGroupID      uint64                         `json:"env_group_id"`
-	EnvGroup        *model.EnvGroup                `json:"env_group,omitempty"`
-	Status          ConfigStatus                   `json:"status"`
-	Dir             string                         `json:"dir"`
-	Urls            []string                       `json:"urls,omitempty"`
-	ProxyTargets    []ProxyTarget                  `json:"proxy_targets,omitempty"`
-	SyncNodeIds     []uint64                       `json:"sync_node_ids,omitempty"`
-	SyncOverwrite   bool                           `json:"sync_overwrite"`
+	Name          string          `json:"name"`
+	Content       string          `json:"content"`
+	FilePath      string          `json:"filepath,omitempty"`
+	ModifiedAt    time.Time       `json:"modified_at"`
+	Size          int64           `json:"size,omitempty"`
+	IsDir         bool            `json:"is_dir"`
+	EnvGroupID    uint64          `json:"env_group_id"`
+	EnvGroup      *model.EnvGroup `json:"env_group,omitempty"`
+	Status        ConfigStatus    `json:"status"`
+	Dir           string          `json:"dir"`
+	Urls          []string        `json:"urls,omitempty"`
+	ProxyTargets  []ProxyTarget   `json:"proxy_targets,omitempty"`
+	SyncNodeIds   []uint64        `json:"sync_node_ids,omitempty"`
+	SyncOverwrite bool            `json:"sync_overwrite"`
 }

+ 17 - 0
internal/helper/unescape_url.go

@@ -0,0 +1,17 @@
+package helper
+
+import (
+	"net/url"
+)
+
+func UnescapeURL(path string) (decodedPath string) {
+	decodedPath = path
+	for {
+		newDecodedPath, decodeErr := url.PathUnescape(decodedPath)
+		if decodeErr != nil || newDecodedPath == decodedPath {
+			break
+		}
+		decodedPath = newDecodedPath
+	}
+	return
+}

+ 9 - 11
internal/site/type.go

@@ -7,7 +7,6 @@ import (
 	"github.com/0xJacky/Nginx-UI/internal/nginx"
 	"github.com/0xJacky/Nginx-UI/internal/upstream"
 	"github.com/0xJacky/Nginx-UI/model"
-	"github.com/sashabaranov/go-openai"
 )
 
 type SiteStatus string
@@ -23,14 +22,13 @@ type ProxyTarget = upstream.ProxyTarget
 
 type Site struct {
 	*model.Site
-	Name            string                         `json:"name"`
-	ModifiedAt      time.Time                      `json:"modified_at"`
-	Status          SiteStatus                     `json:"status"`
-	Config          string                         `json:"config"`
-	AutoCert        bool                           `json:"auto_cert"`
-	ChatGPTMessages []openai.ChatCompletionMessage `json:"chatgpt_messages,omitempty"`
-	Tokenized       *nginx.NgxConfig               `json:"tokenized,omitempty"`
-	CertInfo        map[int][]*cert.Info           `json:"cert_info,omitempty"`
-	Filepath        string                         `json:"filepath"`
-	ProxyTargets    []ProxyTarget                  `json:"proxy_targets,omitempty"`
+	Name         string               `json:"name"`
+	ModifiedAt   time.Time            `json:"modified_at"`
+	Status       SiteStatus           `json:"status"`
+	Config       string               `json:"config"`
+	AutoCert     bool                 `json:"auto_cert"`
+	Tokenized    *nginx.NgxConfig     `json:"tokenized,omitempty"`
+	CertInfo     map[int][]*cert.Info `json:"cert_info,omitempty"`
+	Filepath     string               `json:"filepath"`
+	ProxyTargets []ProxyTarget        `json:"proxy_targets,omitempty"`
 }

Some files were not shown because too many files changed in this diff