diff --git a/agent/app/api/v2/php_extensions.go b/agent/app/api/v2/php_extensions.go index 842ea43a5..ea4f0c77a 100644 --- a/agent/app/api/v2/php_extensions.go +++ b/agent/app/api/v2/php_extensions.go @@ -103,3 +103,46 @@ func (b *BaseApi) DeletePHPExtensions(c *gin.Context) { } helper.Success(c) } + +// @Router /runtimes/php/extensions/detail [post] +func (b *BaseApi) GetPHPExtensions(c *gin.Context) { + var req request.PHPExtensionsDelete + if err := helper.CheckBindAndValidate(&req, c); err != nil { + return + } + item, err := phpExtensionsService.Get(req.ID) + if err != nil { + helper.InternalServer(c, err) + return + } + helper.SuccessWithData(c, item) +} + +// @Router /runtimes/php/extensions/import [post] +// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"同步 PHP 扩展模版 [name]","formatEN":"Sync PHP extension template [name]"} +func (b *BaseApi) ImportPHPExtensions(c *gin.Context) { + var req request.PHPExtensionsCreate + if err := helper.CheckBindAndValidate(&req, c); err != nil { + return + } + status, err := phpExtensionsService.Import(req) + if err != nil { + helper.InternalServer(c, err) + return + } + helper.SuccessWithData(c, status) +} + +// @Router /runtimes/php/extensions/push [post] +// @x-panel-log {"bodyKeys":["sourceNode","targetNodes"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"推送 PHP 扩展模版 [sourceNode] 至 [targetNodes]","formatEN":"Push PHP extension template from [sourceNode] to [targetNodes]"} +func (b *BaseApi) PushPHPExtensions(c *gin.Context) { + var req dto.PHPExtensionsPush + if err := helper.CheckBindAndValidate(&req, c); err != nil { + return + } + if err := phpExtensionsService.Push(req); err != nil { + helper.InternalServer(c, err) + return + } + helper.Success(c) +} diff --git a/agent/app/dto/php_extensions.go b/agent/app/dto/php_extensions.go new file mode 100644 index 000000000..6588d1318 --- /dev/null +++ b/agent/app/dto/php_extensions.go @@ -0,0 +1,9 @@ +package dto + +// PHPExtensionsPush is submitted to the master agent, with an explicit source node. +type PHPExtensionsPush struct { + SourceNode string `json:"sourceNode" validate:"required"` + TargetNodes []string `json:"targetNodes" validate:"required,min=1,dive,required"` + ID uint `json:"id" validate:"required"` + TaskID string `json:"taskID" validate:"required,uuid"` +} diff --git a/agent/app/dto/request/php_extensions.go b/agent/app/dto/request/php_extensions.go index 2046f2b08..f751369ac 100644 --- a/agent/app/dto/request/php_extensions.go +++ b/agent/app/dto/request/php_extensions.go @@ -4,7 +4,8 @@ import "github.com/1Panel-dev/1Panel/agent/app/dto" type PHPExtensionsSearch struct { dto.PageInfo - All bool `json:"all"` + All bool `json:"all"` + Name string `json:"name"` } type PHPExtensionsCreate struct { diff --git a/agent/app/service/php_extensions.go b/agent/app/service/php_extensions.go index 6698150aa..d890971fc 100644 --- a/agent/app/service/php_extensions.go +++ b/agent/app/service/php_extensions.go @@ -1,13 +1,22 @@ package service import ( + "errors" + "sync" + + "github.com/1Panel-dev/1Panel/agent/app/dto" "github.com/1Panel-dev/1Panel/agent/app/dto/request" "github.com/1Panel-dev/1Panel/agent/app/dto/response" "github.com/1Panel-dev/1Panel/agent/app/model" "github.com/1Panel-dev/1Panel/agent/app/repo" "github.com/1Panel-dev/1Panel/agent/buserr" + "github.com/1Panel-dev/1Panel/agent/global" + "github.com/1Panel-dev/1Panel/agent/utils/xpack" + "gorm.io/gorm" ) +var phpExtensionsMu sync.Mutex + type PHPExtensionsService struct { } @@ -17,6 +26,9 @@ type IPHPExtensionsService interface { Create(req request.PHPExtensionsCreate) error Update(req request.PHPExtensionsUpdate) error Delete(req request.PHPExtensionsDelete) error + Get(id uint) (model.PHPExtensions, error) + Import(req request.PHPExtensionsCreate) (string, error) + Push(req dto.PHPExtensionsPush) error } func NewIPHPExtensionsService() IPHPExtensionsService { @@ -30,7 +42,7 @@ func (p PHPExtensionsService) Page(req request.PHPExtensionsSearch) (int64, []re err error result []response.PHPExtensionsDTO ) - total, extensions, err = phpExtensionsRepo.Page(req.Page, req.PageSize) + total, extensions, err = phpExtensionsRepo.Page(req.Page, req.PageSize, repo.WithByLikeName(req.Name)) if err != nil { return 0, nil, err } @@ -61,6 +73,8 @@ func (p PHPExtensionsService) List() ([]response.PHPExtensionsDTO, error) { } func (p PHPExtensionsService) Create(req request.PHPExtensionsCreate) error { + phpExtensionsMu.Lock() + defer phpExtensionsMu.Unlock() exist, _ := phpExtensionsRepo.GetFirst(repo.WithByName(req.Name)) if exist.ID > 0 { return buserr.New("ErrNameIsExist") @@ -73,6 +87,8 @@ func (p PHPExtensionsService) Create(req request.PHPExtensionsCreate) error { } func (p PHPExtensionsService) Update(req request.PHPExtensionsUpdate) error { + phpExtensionsMu.Lock() + defer phpExtensionsMu.Unlock() exist, err := phpExtensionsRepo.GetFirst(repo.WithByID(req.ID)) if err != nil { return err @@ -82,5 +98,41 @@ func (p PHPExtensionsService) Update(req request.PHPExtensionsUpdate) error { } func (p PHPExtensionsService) Delete(req request.PHPExtensionsDelete) error { + phpExtensionsMu.Lock() + defer phpExtensionsMu.Unlock() return phpExtensionsRepo.DeleteBy(repo.WithByID(req.ID)) } + +func (p PHPExtensionsService) Get(id uint) (model.PHPExtensions, error) { + return phpExtensionsRepo.GetFirst(repo.WithByID(id)) +} + +func (p PHPExtensionsService) Import(req request.PHPExtensionsCreate) (string, error) { + phpExtensionsMu.Lock() + defer phpExtensionsMu.Unlock() + existing, err := phpExtensionsRepo.GetFirst(repo.WithByName(req.Name)) + if err == nil { + if existing.Extensions == req.Extensions { + return "skipped", nil + } + return "", buserr.New("ErrPHPExtensionsConflict") + } + if !errors.Is(err, gorm.ErrRecordNotFound) { + return "", err + } + item := model.PHPExtensions{Name: req.Name, Extensions: req.Extensions} + if err := phpExtensionsRepo.Create(&item); err != nil { + return "", err + } + return "created", nil +} + +func (p PHPExtensionsService) Push(req dto.PHPExtensionsPush) error { + if !global.IsMaster { + return errors.New("PHP extension template sync must be submitted to the master node") + } + if !xpack.MultiNodeProvider.IsXpack() { + return buserr.New("ErrXpackNotFound") + } + return xpack.MultiNodeProvider.PushPHPExtensionsToNode(req) +} diff --git a/agent/i18n/lang/en.yaml b/agent/i18n/lang/en.yaml index 38c9d8e51..3ce8acbe3 100644 --- a/agent/i18n/lang/en.yaml +++ b/agent/i18n/lang/en.yaml @@ -816,3 +816,5 @@ ContainerImageCheckSummary: "Check finished: {{ .checked }} checked, {{ .updates ContainerImageCheckFailures: "{{ .count }} container checks failed; see the task log" ErrImageCheckProxyRequired: "To check for image updates in the current runtime environment, please configure a proxy server first." + +ErrPHPExtensionsConflict: "A PHP extension template with this name exists with different content" diff --git a/agent/i18n/lang/es-ES.yaml b/agent/i18n/lang/es-ES.yaml index 33b3324c1..79504c928 100644 --- a/agent/i18n/lang/es-ES.yaml +++ b/agent/i18n/lang/es-ES.yaml @@ -816,3 +816,5 @@ ContainerImageCheckSummary: "Comprobación finalizada: comprobados {{ .checked } ContainerImageCheckFailures: "Falló la comprobación de {{ .count }} contenedores; consulte el registro de la tarea" ErrImageCheckProxyRequired: "Para comprobar actualizaciones de imágenes en el entorno actual, configura primero un servidor proxy." + +ErrPHPExtensionsConflict: "Ya existe una plantilla de extensiones PHP con este nombre y contenido diferente; no se ha sobrescrito" diff --git a/agent/i18n/lang/fa.yaml b/agent/i18n/lang/fa.yaml index 66c69006b..4da11c21b 100644 --- a/agent/i18n/lang/fa.yaml +++ b/agent/i18n/lang/fa.yaml @@ -817,3 +817,5 @@ ContainerImageCheckSummary: "بررسی پایان یافت: بررسی‌شده ContainerImageCheckFailures: "بررسی {{ .count }} کانتینر ناموفق بود؛ گزارش وظیفه را مشاهده کنید" ErrImageCheckProxyRequired: "برای بررسی به‌روزرسانی تصاویر در محیط فعلی، ابتدا یک سرور پروکسی پیکربندی کنید." + +ErrPHPExtensionsConflict: "قالب افزونه PHP با این نام و محتوای متفاوت از قبل وجود دارد؛ بازنویسی نشد" diff --git a/agent/i18n/lang/ja.yaml b/agent/i18n/lang/ja.yaml index ac717b02e..73a5a3ca6 100644 --- a/agent/i18n/lang/ja.yaml +++ b/agent/i18n/lang/ja.yaml @@ -816,3 +816,5 @@ ContainerImageCheckSummary: "確認終了:成功 {{ .checked }}、更新可能 ContainerImageCheckFailures: "{{ .count }} コンテナの確認に失敗しました。タスクログを確認してください" ErrImageCheckProxyRequired: "現在の実行環境でイメージの更新を確認するには、先にプロキシサーバーを設定してください。" + +ErrPHPExtensionsConflict: "同じ名前で内容が異なる PHP 拡張機能テンプレートが既に存在するため、上書きしませんでした" diff --git a/agent/i18n/lang/ko.yaml b/agent/i18n/lang/ko.yaml index 6678caef8..739aef06e 100644 --- a/agent/i18n/lang/ko.yaml +++ b/agent/i18n/lang/ko.yaml @@ -816,3 +816,5 @@ ContainerImageCheckSummary: "확인 종료: 성공 {{ .checked }}, 업데이트 ContainerImageCheckFailures: "컨테이너 {{ .count }}개 확인에 실패했습니다. 작업 로그를 확인하세요" ErrImageCheckProxyRequired: "현재 실행 환경에서 이미지 업데이트를 확인하려면 먼저 프록시 서버를 설정하세요." + +ErrPHPExtensionsConflict: "같은 이름에 내용이 다른 PHP 확장 템플릿이 이미 있어 덮어쓰지 않았습니다" diff --git a/agent/i18n/lang/lo.yaml b/agent/i18n/lang/lo.yaml index 6853fa41c..6b1ac4f6c 100644 --- a/agent/i18n/lang/lo.yaml +++ b/agent/i18n/lang/lo.yaml @@ -807,3 +807,5 @@ ContainerImageCheckSummary: "ກວດສອບສິ້ນສຸດ: ກວດ ContainerImageCheckFailures: "ກວດສອບ {{ .count }} ຄອນເທນເນີລົ້ມເຫຼວ; ກະລຸນາເບິ່ງບັນທຶກວຽກ" ErrImageCheckProxyRequired: "ເພື່ອກວດສອບການອັບເດດອິມເມຈໃນສະພາບແວດລ້ອມປັດຈຸບັນ ກະລຸນາຕັ້ງຄ່າພຣັອກຊີເຊີບເວີກ່ອນ." + +ErrPHPExtensionsConflict: "ມີແມ່ແບບສ່ວນຂະຫຍາຍ PHP ຊື່ນີ້ຢູ່ແລ້ວແຕ່ເນື້ອຫາຕ່າງກັນ; ບໍ່ໄດ້ຂຽນທັບ" diff --git a/agent/i18n/lang/ms.yaml b/agent/i18n/lang/ms.yaml index 38b335ada..923276a1e 100644 --- a/agent/i18n/lang/ms.yaml +++ b/agent/i18n/lang/ms.yaml @@ -816,3 +816,5 @@ ContainerImageCheckSummary: "Semakan selesai: disemak {{ .checked }}, boleh dike ContainerImageCheckFailures: "Semakan {{ .count }} kontena gagal; lihat log tugas" ErrImageCheckProxyRequired: "Untuk menyemak kemas kini imej dalam persekitaran semasa, sila konfigurasikan pelayan proksi terlebih dahulu." + +ErrPHPExtensionsConflict: "Templat sambungan PHP dengan nama ini sudah wujud tetapi kandungannya berbeza; tidak ditulis ganti" diff --git a/agent/i18n/lang/pt-BR.yaml b/agent/i18n/lang/pt-BR.yaml index 6fbded771..30fb22c92 100644 --- a/agent/i18n/lang/pt-BR.yaml +++ b/agent/i18n/lang/pt-BR.yaml @@ -816,3 +816,5 @@ ContainerImageCheckSummary: "Verificação concluída: verificados {{ .checked } ContainerImageCheckFailures: "Falha na verificação de {{ .count }} contêineres; consulte o log da tarefa" ErrImageCheckProxyRequired: "Para verificar atualizações de imagens no ambiente atual, configure primeiro um servidor proxy." + +ErrPHPExtensionsConflict: "Já existe um modelo de extensões PHP com este nome e conteúdo diferente; ele não foi sobrescrito" diff --git a/agent/i18n/lang/ru.yaml b/agent/i18n/lang/ru.yaml index 556a9f482..bf548a42a 100644 --- a/agent/i18n/lang/ru.yaml +++ b/agent/i18n/lang/ru.yaml @@ -816,3 +816,5 @@ ContainerImageCheckSummary: "Проверка завершена: провере ContainerImageCheckFailures: "Не удалось проверить контейнеры: {{ .count }}. Подробности в журнале задачи" ErrImageCheckProxyRequired: "Для проверки обновлений образов в текущей среде сначала настройте прокси-сервер." + +ErrPHPExtensionsConflict: "Шаблон расширений PHP с таким именем уже существует и имеет другое содержимое; перезапись не выполнена" diff --git a/agent/i18n/lang/tr.yaml b/agent/i18n/lang/tr.yaml index 11125cf30..212f971cf 100644 --- a/agent/i18n/lang/tr.yaml +++ b/agent/i18n/lang/tr.yaml @@ -816,3 +816,5 @@ ContainerImageCheckSummary: "Denetim tamamlandı: denetlenen {{ .checked }}, gü ContainerImageCheckFailures: "{{ .count }} konteyner denetlenemedi; görev günlüğünü inceleyin" ErrImageCheckProxyRequired: "Geçerli çalışma ortamında imaj güncellemelerini kontrol etmek için önce bir proxy sunucusu yapılandırın." + +ErrPHPExtensionsConflict: "Bu ada sahip ancak içeriği farklı bir PHP uzantı şablonu zaten mevcut; üzerine yazılmadı" diff --git a/agent/i18n/lang/zh-Hant.yaml b/agent/i18n/lang/zh-Hant.yaml index 124f13a42..55cdc8e33 100644 --- a/agent/i18n/lang/zh-Hant.yaml +++ b/agent/i18n/lang/zh-Hant.yaml @@ -816,3 +816,5 @@ ContainerImageCheckSummary: "檢查結束:成功 {{ .checked }},可升級 {{ ContainerImageCheckFailures: "{{ .count }} 個容器檢查失敗,請查看任務日誌" ErrImageCheckProxyRequired: "目前運行環境下,如需檢查映像是否更新,請先設定代理伺服器" + +ErrPHPExtensionsConflict: "同名 PHP 擴充模版已存在且內容不同,未覆蓋" diff --git a/agent/i18n/lang/zh.yaml b/agent/i18n/lang/zh.yaml index 6007b8d20..4579a3fdd 100644 --- a/agent/i18n/lang/zh.yaml +++ b/agent/i18n/lang/zh.yaml @@ -816,3 +816,5 @@ ContainerImageCheckSummary: "检查结束:成功 {{ .checked }},可升级 {{ ContainerImageCheckFailures: "{{ .count }} 个容器检查失败,请查看任务日志" ErrImageCheckProxyRequired: "当前运行环境下,如需检查镜像是否更新,请优先配置代理服务器" + +ErrPHPExtensionsConflict: "同名 PHP 扩展模版已存在且内容不同,未覆盖" diff --git a/agent/router/ro_runtime.go b/agent/router/ro_runtime.go index 7f03a8ad8..9f1568f3d 100644 --- a/agent/router/ro_runtime.go +++ b/agent/router/ro_runtime.go @@ -27,6 +27,9 @@ func (r *RuntimeRouter) InitRouter(Router *gin.RouterGroup) { groupRouter.POST("/node/modules/operate", baseApi.OperateNodeModules) groupRouter.POST("/php/extensions/search", baseApi.PagePHPExtensions) + groupRouter.POST("/php/extensions/detail", baseApi.GetPHPExtensions) + groupRouter.POST("/php/extensions/import", baseApi.ImportPHPExtensions) + groupRouter.POST("/php/extensions/push", baseApi.PushPHPExtensions) groupRouter.POST("/php/extensions", baseApi.CreatePHPExtensions) groupRouter.POST("/php/extensions/update", baseApi.UpdatePHPExtensions) groupRouter.POST("/php/extensions/del", baseApi.DeletePHPExtensions) diff --git a/agent/utils/xpack/helper/multi_node.go b/agent/utils/xpack/helper/multi_node.go index 1c4700711..849130751 100644 --- a/agent/utils/xpack/helper/multi_node.go +++ b/agent/utils/xpack/helper/multi_node.go @@ -72,3 +72,7 @@ func (m *multiNodeHelper) PushSSLToNode(websiteSSL *model.WebsiteSSL) error { func (m *multiNodeHelper) GetAgentInfo() (*dto.AgentInfo, error) { return nil, nil } + +func (m *multiNodeHelper) PushPHPExtensionsToNode(req dto.PHPExtensionsPush) error { + return buserr.New("ErrXpackNotFound") +} diff --git a/agent/utils/xpack/providers/multi_node.go b/agent/utils/xpack/providers/multi_node.go index 5defd2cc7..44f11cd6e 100644 --- a/agent/utils/xpack/providers/multi_node.go +++ b/agent/utils/xpack/providers/multi_node.go @@ -19,5 +19,6 @@ type MultiNodeProvider interface { LoadRequestTransport() *http.Transport ValidateCertificate(c *gin.Context) bool PushSSLToNode(websiteSSL *model.WebsiteSSL) error + PushPHPExtensionsToNode(req dto.PHPExtensionsPush) error GetAgentInfo() (*dto.AgentInfo, error) } diff --git a/core/constant/common.go b/core/constant/common.go index 4b7055d85..0e49ca5f2 100644 --- a/core/constant/common.go +++ b/core/constant/common.go @@ -189,21 +189,22 @@ var WebUrlMap = map[string]struct{}{ "/xpack/monitor/trend": {}, "/xpack/monitor/websites": {}, - "/xpack/tamper": {}, - "/xpack/gpu": {}, - "/xpack/alert/dashboard": {}, - "/xpack/alert/log": {}, - "/xpack/alert/setting": {}, - "/xpack/setting": {}, - "/xpack/node/dashboard": {}, - "/xpack/node": {}, - "/xpack/simple-node": {}, - "/xpack/sync/file": {}, - "/xpack/sync/image": {}, - "/xpack/sync/ssl": {}, - "/xpack/sync/app": {}, - "/xpack/app": {}, - "/xpack/app-upgrade": {}, + "/xpack/tamper": {}, + "/xpack/gpu": {}, + "/xpack/alert/dashboard": {}, + "/xpack/alert/log": {}, + "/xpack/alert/setting": {}, + "/xpack/setting": {}, + "/xpack/node/dashboard": {}, + "/xpack/node": {}, + "/xpack/simple-node": {}, + "/xpack/sync/file": {}, + "/xpack/sync/image": {}, + "/xpack/sync/php-extensions": {}, + "/xpack/sync/ssl": {}, + "/xpack/sync/app": {}, + "/xpack/app": {}, + "/xpack/app-upgrade": {}, "/xpack/cluster/mysql": {}, "/xpack/cluster/postgres": {}, diff --git a/core/i18n/lang/en.yaml b/core/i18n/lang/en.yaml index 8d998d760..a8477165f 100644 --- a/core/i18n/lang/en.yaml +++ b/core/i18n/lang/en.yaml @@ -587,6 +587,10 @@ MCPInstallRecoveryFailed: "Installation failed and service recovery is incomplet MCPInstallLocalImage: "The image exists locally; skip downloading" MCPInstallVerifyImage: "Validate the image version and managed service contract" MCPInstallVerifiedImage: "Image validation passed" + +PHPExtensionsNoTargets: "No target nodes remain after excluding the source node" +PHPExtensionsSyncTask: "Sync PHP extension template [{{ .name }}]" +PHPExtensionsSyncSkipped: "Node [{{ .node }}] already has an identical template; skipped" MCPInstallCleanup: "Clean up the previous container" MCPInstallOldContainerRemoved: "Previous container removed" MCPInstallOldImageRemoved: "Previous image removed" diff --git a/core/i18n/lang/es-ES.yaml b/core/i18n/lang/es-ES.yaml index 41299a538..6903d9e7e 100644 --- a/core/i18n/lang/es-ES.yaml +++ b/core/i18n/lang/es-ES.yaml @@ -587,6 +587,10 @@ MCPInstallRecoveryFailed: "Instalación fallida y recuperación incompleta. Veri MCPInstallLocalImage: "La imagen ya existe localmente; omitir la descarga" MCPInstallVerifyImage: "Validar la versión de la imagen y el contrato del servicio administrado" MCPInstallVerifiedImage: "La imagen superó la validación" + +PHPExtensionsNoTargets: "No quedan nodos de destino tras excluir el nodo de origen" +PHPExtensionsSyncTask: "Sincronizar plantilla de extensiones PHP [{{ .name }}]" +PHPExtensionsSyncSkipped: "El nodo [{{ .node }}] ya tiene una plantilla idéntica; se ha omitido" MCPInstallCleanup: "Limpiar el contenedor anterior" MCPInstallOldContainerRemoved: "Contenedor anterior eliminado" MCPInstallOldImageRemoved: "Imagen anterior eliminada" diff --git a/core/i18n/lang/fa.yaml b/core/i18n/lang/fa.yaml index d0f054a10..4e8b54989 100644 --- a/core/i18n/lang/fa.yaml +++ b/core/i18n/lang/fa.yaml @@ -587,6 +587,10 @@ MCPInstallRecoveryFailed: "نصب ناموفق و بازیابی سرویس نا MCPInstallLocalImage: "تصویر به‌صورت محلی موجود است؛ دریافت انجام نمی‌شود" MCPInstallVerifyImage: "اعتبارسنجی نسخه تصویر و قرارداد سرویس مدیریت‌شده" MCPInstallVerifiedImage: "اعتبارسنجی تصویر موفق بود" + +PHPExtensionsNoTargets: "پس از کنار گذاشتن گره مبدأ، هیچ گره مقصدی باقی نمانده است" +PHPExtensionsSyncTask: "همگام‌سازی قالب افزونه PHP [{{ .name }}]" +PHPExtensionsSyncSkipped: "گره [{{ .node }}] از قبل قالب یکسانی دارد؛ نادیده گرفته شد" MCPInstallCleanup: "پاک‌سازی کانتینر قبلی" MCPInstallOldContainerRemoved: "کانتینر قبلی حذف شد" MCPInstallOldImageRemoved: "ایمیج قبلی حذف شد" diff --git a/core/i18n/lang/ja.yaml b/core/i18n/lang/ja.yaml index b5048790d..d33460546 100644 --- a/core/i18n/lang/ja.yaml +++ b/core/i18n/lang/ja.yaml @@ -587,6 +587,10 @@ MCPInstallRecoveryFailed: "インストールに失敗し、サービスの復 MCPInstallLocalImage: "ローカルにイメージが存在するため、ダウンロードをスキップ" MCPInstallVerifyImage: "イメージのバージョンと管理対象サービスの契約を検証" MCPInstallVerifiedImage: "イメージの検証に成功しました" + +PHPExtensionsNoTargets: "ソースノードを除外すると、ターゲットノードが残りません" +PHPExtensionsSyncTask: "PHP 拡張機能テンプレート [{{ .name }}] を同期" +PHPExtensionsSyncSkipped: "ノード [{{ .node }}] には同一のテンプレートが既に存在するため、スキップしました" MCPInstallCleanup: "以前のコンテナーをクリーンアップ" MCPInstallOldContainerRemoved: "以前のコンテナーを削除しました" MCPInstallOldImageRemoved: "以前のイメージを削除しました" diff --git a/core/i18n/lang/ko.yaml b/core/i18n/lang/ko.yaml index 9a30c2399..fbd16211f 100644 --- a/core/i18n/lang/ko.yaml +++ b/core/i18n/lang/ko.yaml @@ -587,6 +587,10 @@ MCPInstallRecoveryFailed: "설치에 실패했고 서비스 복원이 불완전 MCPInstallLocalImage: "로컬 이미지가 있어 다운로드를 건너뜁니다" MCPInstallVerifyImage: "이미지 버전 및 관리형 서비스 계약 검증" MCPInstallVerifiedImage: "이미지 검증 통과" + +PHPExtensionsNoTargets: "원본 노드를 제외하면 대상 노드가 남지 않습니다" +PHPExtensionsSyncTask: "PHP 확장 템플릿 [{{ .name }}] 동기화" +PHPExtensionsSyncSkipped: "노드 [{{ .node }}]에 동일한 템플릿이 이미 있어 건너뛰었습니다" MCPInstallCleanup: "이전 컨테이너 정리" MCPInstallOldContainerRemoved: "이전 컨테이너가 삭제되었습니다" MCPInstallOldImageRemoved: "이전 이미지가 삭제되었습니다" diff --git a/core/i18n/lang/lo.yaml b/core/i18n/lang/lo.yaml index b6cbdde88..83def7a8d 100644 --- a/core/i18n/lang/lo.yaml +++ b/core/i18n/lang/lo.yaml @@ -587,6 +587,10 @@ MCPInstallRecoveryFailed: "ຕິດຕັ້ງບໍ່ສຳເລັດແ MCPInstallLocalImage: "ມີອິມເມດຢູ່ໃນເຄື່ອງແລ້ວ; ຂ້າມການດາວໂຫຼດ" MCPInstallVerifyImage: "ກວດສອບເວີຊັນອິມເມດ ແລະ ສັນຍາບໍລິການທີ່ຈັດການ" MCPInstallVerifiedImage: "ກວດສອບອິມເມດຜ່ານແລ້ວ" + +PHPExtensionsNoTargets: "ບໍ່ມີໂນດປາຍທາງເຫຼືອຫຼັງຈາກຍົກເວັ້ນໂນດຕົ້ນທາງ" +PHPExtensionsSyncTask: "ຊິງແມ່ແບບສ່ວນຂະຫຍາຍ PHP [{{ .name }}]" +PHPExtensionsSyncSkipped: "ໂນດ [{{ .node }}] ມີແມ່ແບບທີ່ຄືກັນແລ້ວ; ຂ້າມ" MCPInstallCleanup: "ກຳລັງລ້າງຄອນເທນເນີເກົ່າ" MCPInstallOldContainerRemoved: "ລຶບຄອນເທນເນີເກົ່າແລ້ວ" MCPInstallOldImageRemoved: "ລຶບອິມເມຈເກົ່າແລ້ວ" diff --git a/core/i18n/lang/ms.yaml b/core/i18n/lang/ms.yaml index ee945ddde..86c9fe067 100644 --- a/core/i18n/lang/ms.yaml +++ b/core/i18n/lang/ms.yaml @@ -587,6 +587,10 @@ MCPInstallRecoveryFailed: "Pemasangan gagal dan pemulihan tidak lengkap. Sahkan MCPInstallLocalImage: "Imej sudah tersedia secara setempat; langkau muat turun" MCPInstallVerifyImage: "Sahkan versi imej dan kontrak perkhidmatan terurus" MCPInstallVerifiedImage: "Pengesahan imej berjaya" + +PHPExtensionsNoTargets: "Tiada nod sasaran yang tinggal selepas mengecualikan nod sumber" +PHPExtensionsSyncTask: "Segerakkan templat sambungan PHP [{{ .name }}]" +PHPExtensionsSyncSkipped: "Nod [{{ .node }}] sudah mempunyai templat yang sama; dilangkau" MCPInstallCleanup: "Bersihkan bekas terdahulu" MCPInstallOldContainerRemoved: "Bekas terdahulu dipadam" MCPInstallOldImageRemoved: "Imej terdahulu dipadam" diff --git a/core/i18n/lang/pt-BR.yaml b/core/i18n/lang/pt-BR.yaml index 95433bb7a..5fc078eb1 100644 --- a/core/i18n/lang/pt-BR.yaml +++ b/core/i18n/lang/pt-BR.yaml @@ -587,6 +587,10 @@ MCPInstallRecoveryFailed: "Instalação falhou e a recuperação está incomplet MCPInstallLocalImage: "A imagem já existe localmente; ignorar o download" MCPInstallVerifyImage: "Validar a versão da imagem e o contrato do serviço gerenciado" MCPInstallVerifiedImage: "A imagem passou na validação" + +PHPExtensionsNoTargets: "Não restam nós de destino após excluir o nó de origem" +PHPExtensionsSyncTask: "Sincronizar modelo de extensões PHP [{{ .name }}]" +PHPExtensionsSyncSkipped: "O nó [{{ .node }}] já possui um modelo idêntico; ignorado" MCPInstallCleanup: "Limpar o contêiner anterior" MCPInstallOldContainerRemoved: "Contêiner anterior removido" MCPInstallOldImageRemoved: "Imagem anterior removida" diff --git a/core/i18n/lang/ru.yaml b/core/i18n/lang/ru.yaml index bd01408b7..072337313 100644 --- a/core/i18n/lang/ru.yaml +++ b/core/i18n/lang/ru.yaml @@ -587,6 +587,10 @@ MCPInstallRecoveryFailed: "Установка не удалась, служба MCPInstallLocalImage: "Образ уже есть локально; пропустить загрузку" MCPInstallVerifyImage: "Проверить версию образа и контракт управляемой службы" MCPInstallVerifiedImage: "Образ успешно проверен" + +PHPExtensionsNoTargets: "После исключения исходного узла не осталось целевых узлов" +PHPExtensionsSyncTask: "Синхронизация шаблона расширений PHP [{{ .name }}]" +PHPExtensionsSyncSkipped: "На узле [{{ .node }}] уже есть идентичный шаблон; пропущено" MCPInstallCleanup: "Очистка предыдущего контейнера" MCPInstallOldContainerRemoved: "Предыдущий контейнер удалён" MCPInstallOldImageRemoved: "Предыдущий образ удалён" diff --git a/core/i18n/lang/tr.yaml b/core/i18n/lang/tr.yaml index d51db0705..c1e22839c 100644 --- a/core/i18n/lang/tr.yaml +++ b/core/i18n/lang/tr.yaml @@ -587,6 +587,10 @@ MCPInstallRecoveryFailed: "Kurulum başarısız ve hizmet tam geri yüklenemedi. MCPInstallLocalImage: "İmaj yerel olarak mevcut; indirmeyi atla" MCPInstallVerifyImage: "İmaj sürümünü ve yönetilen hizmet sözleşmesini doğrula" MCPInstallVerifiedImage: "İmaj doğrulaması başarılı" + +PHPExtensionsNoTargets: "Kaynak düğüm hariç tutulduktan sonra hedef düğüm kalmadı" +PHPExtensionsSyncTask: "PHP uzantı şablonunu eşitle [{{ .name }}]" +PHPExtensionsSyncSkipped: "[{{ .node }}] düğümünde aynı şablon zaten mevcut; atlandı" MCPInstallCleanup: "Önceki konteyneri temizle" MCPInstallOldContainerRemoved: "Önceki konteyner silindi" MCPInstallOldImageRemoved: "Önceki imaj silindi" diff --git a/core/i18n/lang/zh-Hant.yaml b/core/i18n/lang/zh-Hant.yaml index 3a7a3afa6..6a49197ec 100644 --- a/core/i18n/lang/zh-Hant.yaml +++ b/core/i18n/lang/zh-Hant.yaml @@ -587,6 +587,10 @@ MCPInstallRecoveryFailed: "安裝失敗且原服務還原不完整,請核對 MCPInstallLocalImage: "本機映像已存在,略過下載" MCPInstallVerifyImage: "驗證映像版本及受管契約" MCPInstallVerifiedImage: "映像驗證通過" + +PHPExtensionsNoTargets: "排除來源節點後,沒有可同步的目標節點" +PHPExtensionsSyncTask: "同步 PHP 擴充模版 [{{ .name }}]" +PHPExtensionsSyncSkipped: "節點 [{{ .node }}] 已存在相同模版,略過" MCPInstallCleanup: "正在清理舊容器" MCPInstallOldContainerRemoved: "舊容器已刪除" MCPInstallOldImageRemoved: "舊映像已刪除" diff --git a/core/i18n/lang/zh.yaml b/core/i18n/lang/zh.yaml index d85af29c2..6771b32a4 100644 --- a/core/i18n/lang/zh.yaml +++ b/core/i18n/lang/zh.yaml @@ -587,6 +587,10 @@ MCPInstallRecoveryFailed: "安装失败且原服务恢复不完整,请核对 MCPInstallLocalImage: "本地镜像已存在,跳过下载" MCPInstallVerifyImage: "校验镜像版本和受管契约" MCPInstallVerifiedImage: "镜像校验通过" + +PHPExtensionsNoTargets: "排除源节点后,没有可同步的目标节点" +PHPExtensionsSyncTask: "同步 PHP 扩展模版 [{{ .name }}]" +PHPExtensionsSyncSkipped: "节点 [{{ .node }}] 已存在相同模版,跳过" MCPInstallCleanup: "正在清理旧容器" MCPInstallOldContainerRemoved: "旧容器已删除" MCPInstallOldImageRemoved: "旧镜像已删除" diff --git a/core/init/router/proxy.go b/core/init/router/proxy.go index 174fb1aa8..a21bfba5d 100644 --- a/core/init/router/proxy.go +++ b/core/init/router/proxy.go @@ -199,5 +199,7 @@ func checkSession(c *gin.Context, refresh bool) bool { } func isLocalAPI(urlPath string) bool { - return urlPath == "/api/v2/core/xpack/sync/ssl" || urlPath == "/api/v2/core/xpack/settings/search" + return urlPath == "/api/v2/core/xpack/sync/ssl" || + urlPath == "/api/v2/core/xpack/sync/php/extensions" || + urlPath == "/api/v2/core/xpack/settings/search" } diff --git a/core/middleware/ip_limit.go b/core/middleware/ip_limit.go index 782360987..808013e98 100644 --- a/core/middleware/ip_limit.go +++ b/core/middleware/ip_limit.go @@ -98,7 +98,7 @@ func isLocalSyncRequest(reqPath, clientIP, token string) bool { } switch reqPath { - case "/api/v2/core/xpack/sync/ssl": + case "/api/v2/core/xpack/sync/ssl", "/api/v2/core/xpack/sync/php/extensions": return token != "" case "/api/v2/core/settings/ssl/reload": return token != "" diff --git a/frontend/src/api/interface/runtime.ts b/frontend/src/api/interface/runtime.ts index e7d390fa4..4cda6457a 100644 --- a/frontend/src/api/interface/runtime.ts +++ b/frontend/src/api/interface/runtime.ts @@ -1,6 +1,13 @@ import { CommonModel, ReqPage } from '.'; import { App } from './app'; export namespace Runtime { + export interface PHPExtensionsPush { + sourceNode: string; + targetNodes: string[]; + id: number; + taskID: string; + } + export interface Runtime extends CommonModel { name: string; appDetailID: number; diff --git a/frontend/src/api/modules/runtime.ts b/frontend/src/api/modules/runtime.ts index 5f74b2c65..f8ffcb575 100644 --- a/frontend/src/api/modules/runtime.ts +++ b/frontend/src/api/modules/runtime.ts @@ -46,8 +46,13 @@ export const OperateNodeModule = (req: Runtime.NodeModuleReq) => { return http.post(`/runtimes/node/modules/operate`, req, TimeoutEnum.T_10M); }; -export const SearchPHPExtensions = (req: ReqPage) => { - return http.post>(`/runtimes/php/extensions/search`, req); +export const SearchPHPExtensions = (req: ReqPage & { name?: string }, currentNode?: string) => { + return http.post>( + `/runtimes/php/extensions/search`, + req, + undefined, + currentNode ? { CurrentNode: currentNode } : undefined, + ); }; export const ListPHPExtensions = (req: Runtime.PHPExtensionsList) => { @@ -137,3 +142,7 @@ export const updateRemark = (req: Runtime.RemarkUpdate) => { export const getFPMStatus = (id: number) => { return http.get(`/runtimes/php/fpm/status/${id}`); }; + +export const PushPHPExtensions = (req: Runtime.PHPExtensionsPush) => { + return http.post(`/runtimes/php/extensions/push`, req, undefined, { CurrentNode: 'local' }); +}; diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index 7f0892be4..f9505aea6 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -4011,6 +4011,13 @@ const message = { nodeApp: 'Upgrade to Commercial Edition to upgrade multi-node app versions without switching nodes manually.', nodeDashboard: 'Upgrade to Commercial Edition for centralized management of multi-node apps, websites, databases, and scheduled tasks.', + imageExchange: 'Upgrade to Commercial Edition to transfer container images between nodes in batches.', + appExchange: + 'Upgrade to Commercial Edition to migrate installed applications to target nodes and confirm their resource dependencies.', + sslSync: + 'Upgrade to Commercial Edition to synchronize certificates from a source node to one or more target nodes.', + phpExtensionsSync: + 'Upgrade to Commercial Edition to synchronize PHP extension templates to one or more target nodes.', fileExchange: 'Upgrade to Commercial Edition to transfer files quickly between servers.', app: 'Upgrade to Commercial Edition to view service details, anomaly monitoring, and more in the mobile app.', cluster: 'Upgrade to Commercial Edition to manage MySQL/Postgres/Redis primary-replica clusters.', @@ -7038,6 +7045,35 @@ const message = { nodeContent3: "Real-time monitoring of each node's operational status", nodeTitle4: 'Quick Remote Connection', nodeContent4: 'One-click direct connection to node remote terminals', + imageExchangeTitle1: 'Select source images', + imageExchangeContent1: 'Browse container images on the source node and select the images to transfer.', + imageExchangeTitle2: 'Distribute images', + imageExchangeContent2: 'Transfer selected images to one or more target nodes.', + imageExchangeTitle3: 'View transfer logs', + imageExchangeContent3: 'Track image transfer progress and results in task logs.', + appExchangeTitle1: 'Select an application', + appExchangeContent1: 'Browse installed applications on the source node and select one to migrate.', + appExchangeTitle2: 'Confirm dependencies', + appExchangeContent2: 'Confirm target nodes and required resources, such as databases, before migration.', + appExchangeTitle3: 'Migrate applications', + appExchangeContent3: + 'Transfer application backups to target nodes for restoration and view results in task logs.', + sslSyncTitle1: 'Select certificates', + sslSyncContent1: 'Browse certificate details on the source node and select certificates to synchronize.', + sslSyncTitle2: 'Synchronize across nodes', + sslSyncContent2: + 'Synchronize selected certificates to target nodes, automatically excluding the source node.', + sslSyncTitle3: 'Confirm sync tasks', + sslSyncContent3: 'Review target nodes and certificates before execution, then view results in task logs.', + phpExtensionsSyncTitle1: 'Select a template', + phpExtensionsSyncContent1: + 'Browse template names and extension lists on the source node and select a template to synchronize.', + phpExtensionsSyncTitle2: 'Synchronize templates', + phpExtensionsSyncContent2: + 'Synchronize the selected template to target nodes, automatically excluding the source node.', + phpExtensionsSyncTitle3: 'Check existing templates', + phpExtensionsSyncContent3: + 'Skip templates with identical names and content. Report conflicts without overwriting different content.', fileExchangeTitle1: 'Key Authentication Transmission', fileExchangeContent1: 'Authenticate via SSH keys to ensure transmission security.', fileExchangeTitle2: 'Efficient File Synchronization', @@ -7552,6 +7588,13 @@ const message = { imageBatchConfirmPrefix: 'About to transfer {0} images to {1} nodes, for a total of {2} tasks.', ssl: 'Certificate Sync', + phpExtensions: 'PHP Extension Template Sync', + phpExtensionsTitle: 'Extension Template Sync', + phpExtensionsDesc: 'Select a source node to sync its PHP extension template to target nodes.', + phpExtensionsList: 'PHP extensions', + phpExtensionsConfirm: 'Sync {0} PHP extension template(s) to {1} node(s).', + phpExtensionsConflictHint: + 'Identical templates are skipped. Same-name templates with different content are reported as conflicts and will not be overwritten.', sslBatchDesc: 'After selecting a source node, sync the specified certificate into the current panel environment.', sslBatchConfirmPrefix: 'About to sync {0} certificates to {1} nodes, for a total of {2} tasks.', diff --git a/frontend/src/lang/modules/es-es.ts b/frontend/src/lang/modules/es-es.ts index 20f4a10a6..0653e45f4 100644 --- a/frontend/src/lang/modules/es-es.ts +++ b/frontend/src/lang/modules/es-es.ts @@ -4088,6 +4088,14 @@ const message = { 'Actualizar a la edición comercial permite actualizar versiones de aplicaciones multinodo sin cambiar de nodo manualmente.', nodeDashboard: 'Actualizar a la edición comercial permite la gestión centralizada de aplicaciones, sitios web, bases de datos y tareas programadas multinodo.', + imageExchange: + 'Actualiza a la Edición Comercial para transferir imágenes de contenedores por lotes entre nodos.', + appExchange: + 'Actualiza a la Edición Comercial para migrar aplicaciones instaladas a nodos de destino y confirmar sus dependencias de recursos.', + sslSync: + 'Actualiza a la Edición Comercial para sincronizar certificados de un nodo de origen con uno o varios nodos de destino.', + phpExtensionsSync: + 'Actualiza a la Edición Comercial para sincronizar plantillas de extensiones PHP con uno o varios nodos de destino.', fileExchange: 'La edición comercial permite transferir archivos entre varios servidores.', app: 'La edición comercial permite ver información de servicio, monitoreo, etc. vía app móvil.', cluster: @@ -7151,6 +7159,41 @@ const message = { nodeContent3: 'Supervisa en tiempo real el estado operativo de cada nodo', nodeTitle4: 'Conexión Remota Rápida', nodeContent4: 'Conecta directamente a la terminal remota de un nodo con un clic', + imageExchangeTitle1: 'Seleccionar imágenes de origen', + imageExchangeContent1: + 'Consulta las imágenes de contenedores del nodo de origen y selecciona las que quieras transferir.', + imageExchangeTitle2: 'Distribuir imágenes', + imageExchangeContent2: 'Transfiere las imágenes seleccionadas a uno o varios nodos de destino.', + imageExchangeTitle3: 'Ver registros de transferencia', + imageExchangeContent3: + 'Consulta el progreso y los resultados de la transferencia de imágenes en los registros de tareas.', + appExchangeTitle1: 'Seleccionar una aplicación', + appExchangeContent1: + 'Consulta las aplicaciones instaladas en el nodo de origen y selecciona una para migrarla.', + appExchangeTitle2: 'Confirmar dependencias', + appExchangeContent2: + 'Antes de migrar, confirma los nodos de destino y los recursos necesarios, como las bases de datos.', + appExchangeTitle3: 'Migrar aplicaciones', + appExchangeContent3: + 'Transfiere las copias de seguridad de las aplicaciones a los nodos de destino para restaurarlas y consulta los resultados en los registros de tareas.', + sslSyncTitle1: 'Seleccionar certificados', + sslSyncContent1: + 'Consulta los detalles de los certificados del nodo de origen y selecciona los que quieras sincronizar.', + sslSyncTitle2: 'Sincronizar entre nodos', + sslSyncContent2: + 'Sincroniza los certificados seleccionados con los nodos de destino, excluyendo automáticamente el nodo de origen.', + sslSyncTitle3: 'Confirmar tareas de sincronización', + sslSyncContent3: + 'Revisa los nodos de destino y los certificados antes de ejecutar la tarea y consulta los resultados en los registros de tareas.', + phpExtensionsSyncTitle1: 'Seleccionar una plantilla', + phpExtensionsSyncContent1: + 'Consulta los nombres de las plantillas y sus listas de extensiones en el nodo de origen y selecciona una plantilla para sincronizarla.', + phpExtensionsSyncTitle2: 'Sincronizar plantillas', + phpExtensionsSyncContent2: + 'Sincroniza la plantilla seleccionada con los nodos de destino, excluyendo automáticamente el nodo de origen.', + phpExtensionsSyncTitle3: 'Comprobar plantillas existentes', + phpExtensionsSyncContent3: + 'Se omiten las plantillas con el mismo nombre y contenido. Si el contenido es diferente, se informa del conflicto sin sobrescribirlo.', fileExchangeTitle1: 'Transmisión con Autenticación por Claves', fileExchangeContent1: 'Autenticación vía claves SSH para garantizar seguridad en la transmisión.', fileExchangeTitle2: 'Sincronización de Archivos Eficiente', @@ -7669,6 +7712,14 @@ const message = { imageBatchConfirmPrefix: 'Se enviarán {0} imágenes a {1} nodos, creando {2} tareas.', ssl: 'Sincronización de certificados', + phpExtensions: 'Sincronización de plantillas de extensiones PHP', + phpExtensionsTitle: 'Sincronización de plantillas de extensiones', + phpExtensionsDesc: + 'Selecciona un nodo de origen para sincronizar su plantilla de extensiones PHP con los nodos de destino.', + phpExtensionsList: 'Extensiones PHP', + phpExtensionsConfirm: 'Se sincronizarán {0} plantillas de extensiones PHP con {1} nodos.', + phpExtensionsConflictHint: + 'Se omiten las plantillas idénticas. Las plantillas con el mismo nombre y contenido diferente se notifican como conflictos y no se sobrescriben.', sslBatchDesc: 'Después de seleccionar el nodo de origen, los certificados especificados pueden sincronizarse con el entorno actual del panel.', sslBatchConfirmPrefix: 'Se sincronizarán {0} certificados a {1} nodos, creando {2} tareas.', diff --git a/frontend/src/lang/modules/fa.ts b/frontend/src/lang/modules/fa.ts index b1e099c0a..918e13d4b 100644 --- a/frontend/src/lang/modules/fa.ts +++ b/frontend/src/lang/modules/fa.ts @@ -3975,6 +3975,11 @@ const message = { nodeApp: 'برای ارتقاء نسخه برنامه‌های چند گره بدون نیاز به جابجایی دستی بین گره‌ها به نسخه تجاری ارتقاء دهید.', nodeDashboard: 'برای مدیریت متمرکز برنامه‌ها، وب‌سایت‌ها، پایگاه‌های داده و وظایف زمان‌بندی شده چند گره به نسخه تجاری ارتقاء دهید.', + imageExchange: 'برای انتقال گروهی ایمیج‌های کانتینر بین گره‌ها به نسخه تجاری ارتقاء دهید.', + appExchange: + 'برای انتقال برنامه‌های نصب‌شده به گره‌های مقصد و تأیید منابع موردنیاز آن‌ها به نسخه تجاری ارتقاء دهید.', + sslSync: 'برای همگام‌سازی گواهی‌های گره مبدأ با یک یا چند گره مقصد به نسخه تجاری ارتقاء دهید.', + phpExtensionsSync: 'برای همگام‌سازی قالب‌های افزونه PHP با یک یا چند گره مقصد به نسخه تجاری ارتقاء دهید.', fileExchange: 'برای انتقال سریع فایل‌ها بین سرورها به نسخه تجاری ارتقاء دهید.', app: 'برای مشاهده جزئیات سرویس، نظارت بر ناهنجاری‌ها و موارد دیگر در برنامه موبایل به نسخه تجاری ارتقاء دهید.', cluster: 'برای مدیریت خوشه‌های اصلی-برده MySQL/Postgres/Redis به نسخه تجاری ارتقاء دهید.', @@ -6993,6 +6998,38 @@ const message = { nodeContent3: 'نظارت بر وضعیت عملیاتی هر گره به صورت بلادرنگ', nodeTitle4: 'اتصال سریع از راه دور', nodeContent4: 'اتصال مستقیم یک‌کلیکی به ترمینال‌های از راه دور گره', + imageExchangeTitle1: 'انتخاب ایمیج‌های مبدأ', + imageExchangeContent1: + 'ایمیج‌های کانتینر گره مبدأ را بررسی و ایمیج‌های موردنظر برای انتقال را انتخاب کنید.', + imageExchangeTitle2: 'توزیع ایمیج‌ها', + imageExchangeContent2: 'ایمیج‌های انتخاب‌شده را به یک یا چند گره مقصد انتقال دهید.', + imageExchangeTitle3: 'مشاهده گزارش‌های انتقال', + imageExchangeContent3: 'پیشرفت و نتایج انتقال ایمیج‌ها را در گزارش‌های وظیفه مشاهده کنید.', + appExchangeTitle1: 'انتخاب برنامه', + appExchangeContent1: + 'برنامه‌های نصب‌شده روی گره مبدأ را بررسی و برنامه موردنظر برای انتقال را انتخاب کنید.', + appExchangeTitle2: 'تأیید وابستگی‌ها', + appExchangeContent2: 'پیش از انتقال، گره‌های مقصد و منابع موردنیاز مانند پایگاه‌های داده را تأیید کنید.', + appExchangeTitle3: 'انتقال برنامه‌ها', + appExchangeContent3: + 'نسخه‌های پشتیبان برنامه‌ها را برای بازیابی به گره‌های مقصد انتقال دهید و نتایج را در گزارش‌های وظیفه مشاهده کنید.', + sslSyncTitle1: 'انتخاب گواهی‌ها', + sslSyncContent1: 'اطلاعات گواهی‌های گره مبدأ را بررسی و گواهی‌های موردنظر برای همگام‌سازی را انتخاب کنید.', + sslSyncTitle2: 'همگام‌سازی بین گره‌ها', + sslSyncContent2: + 'گواهی‌های انتخاب‌شده را با گره‌های مقصد همگام کنید؛ گره مبدأ به‌طور خودکار کنار گذاشته می‌شود.', + sslSyncTitle3: 'تأیید وظایف همگام‌سازی', + sslSyncContent3: + 'پیش از اجرا، گره‌های مقصد و گواهی‌ها را بررسی کنید و سپس نتایج را در گزارش‌های وظیفه مشاهده کنید.', + phpExtensionsSyncTitle1: 'انتخاب قالب', + phpExtensionsSyncContent1: + 'نام قالب‌ها و فهرست افزونه‌های گره مبدأ را بررسی و قالب موردنظر برای همگام‌سازی را انتخاب کنید.', + phpExtensionsSyncTitle2: 'همگام‌سازی قالب‌ها', + phpExtensionsSyncContent2: + 'قالب انتخاب‌شده را با گره‌های مقصد همگام کنید؛ گره مبدأ به‌طور خودکار کنار گذاشته می‌شود.', + phpExtensionsSyncTitle3: 'بررسی قالب‌های موجود', + phpExtensionsSyncContent3: + 'قالب‌هایی با نام و محتوای یکسان نادیده گرفته می‌شوند. اگر محتوا متفاوت باشد، تعارض بدون بازنویسی گزارش می‌شود.', fileExchangeTitle1: 'انتقال احراز هویت کلید', fileExchangeContent1: 'از طریق کلیدهای SSH احراز هویت کنید تا امنیت انتقال تضمین شود.', fileExchangeTitle2: 'همگام‌سازی کارآمد فایل', @@ -7510,6 +7547,13 @@ const message = { imageBatchConfirmPrefix: 'در حال انتقال {0} تصویر به {1} گره، مجموعاً {2} وظیفه.', ssl: 'همگام‌سازی گواهی', + phpExtensions: 'همگام‌سازی قالب‌های افزونه PHP', + phpExtensionsTitle: 'همگام‌سازی قالب‌های افزونه', + phpExtensionsDesc: 'یک گره مبدأ انتخاب کنید تا قالب افزونه PHP آن با گره‌های مقصد همگام شود.', + phpExtensionsList: 'افزونه‌های PHP', + phpExtensionsConfirm: '{0} قالب افزونه PHP با {1} گره همگام می‌شود.', + phpExtensionsConflictHint: + 'قالب‌های یکسان نادیده گرفته می‌شوند. قالب‌های هم‌نام با محتوای متفاوت به‌عنوان تعارض گزارش می‌شوند و بازنویسی نخواهند شد.', sslBatchDesc: 'پس از انتخاب یک گره منبع، گواهی مشخص شده را به محیط پنل فعلی همگام‌سازی کنید.', sslBatchConfirmPrefix: 'در حال همگام‌سازی {0} گواهی به {1} گره، مجموعاً {2} وظیفه.', diff --git a/frontend/src/lang/modules/ja.ts b/frontend/src/lang/modules/ja.ts index 938687147..3b1e1d76a 100644 --- a/frontend/src/lang/modules/ja.ts +++ b/frontend/src/lang/modules/ja.ts @@ -3992,6 +3992,12 @@ const message = { '商用版にアップグレードすると、ノードを手動で切り替えずにマルチノードアプリのバージョンを一括アップグレードできます。', nodeDashboard: '商用版にアップグレードすると、マルチノードのアプリ、Web サイト、データベース、スケジュールタスクを一元管理できます。', + imageExchange: '商用版にアップグレードすると、ノード間でコンテナイメージを一括転送できます。', + appExchange: + '商用版にアップグレードすると、インストール済みアプリケーションを移行先ノードに移行し、必要なリソースの依存関係を確認できます。', + sslSync: '商用版にアップグレードすると、ソースノードの証明書を1つ以上のターゲットノードに同期できます。', + phpExtensionsSync: + '商用版にアップグレードすると、PHP 拡張機能テンプレートを1つ以上のターゲットノードに同期できます。', fileExchange: '商用版にアップグレードすると、複数サーバー間でファイルをすばやく転送できます。', cluster: '商用版にアップグレードすると、MySQL/Postgres/Redis のプライマリ/レプリカ構成を管理できます。', vllm: '商用版にアップグレードすると、1Panel で vLLM サービスのデプロイ、設定、ライフサイクル操作、タスク追跡を一元管理できます。', @@ -7026,6 +7032,34 @@ const message = { nodeContent3: '各ノードの運用状況をリアルタイムで把握', nodeTitle4: '迅速なリモート接続', nodeContent4: 'ワンクリックでノードリモート端末に直接接続', + imageExchangeTitle1: '転送元のイメージを選択', + imageExchangeContent1: 'ソースノードのコンテナイメージを確認し、転送するイメージを選択します。', + imageExchangeTitle2: 'イメージを配布', + imageExchangeContent2: '選択したイメージを1つ以上のターゲットノードに転送します。', + imageExchangeTitle3: '転送ログを表示', + imageExchangeContent3: 'タスクログでイメージの転送状況と実行結果を確認します。', + appExchangeTitle1: 'アプリケーションを選択', + appExchangeContent1: 'ソースノードにインストールされたアプリケーションを確認し、移行するものを選択します。', + appExchangeTitle2: '依存関係を確認', + appExchangeContent2: '移行前に、移行先ノードとデータベースなどの必要なリソースを確認します。', + appExchangeTitle3: 'アプリケーションを移行', + appExchangeContent3: + 'アプリケーションのバックアップを移行先ノードに転送して復元し、タスクログで結果を確認します。', + sslSyncTitle1: '証明書を選択', + sslSyncContent1: 'ソースノードの証明書情報を確認し、同期する証明書を選択します。', + sslSyncTitle2: 'ノード間で同期', + sslSyncContent2: 'ソースノードを自動的に除外し、選択した証明書をターゲットノードに同期します。', + sslSyncTitle3: '同期タスクを確認', + sslSyncContent3: '実行前にターゲットノードと証明書を確認し、実行後にタスクログで結果を確認します。', + phpExtensionsSyncTitle1: 'テンプレートを選択', + phpExtensionsSyncContent1: + 'ソースノードのテンプレート名と拡張機能一覧を確認し、同期するテンプレートを選択します。', + phpExtensionsSyncTitle2: 'テンプレートを同期', + phpExtensionsSyncContent2: + 'ソースノードを自動的に除外し、選択したテンプレートをターゲットノードに同期します。', + phpExtensionsSyncTitle3: '既存のテンプレートを確認', + phpExtensionsSyncContent3: + '名前と内容が一致するテンプレートはスキップします。内容が異なる場合は上書きせず、競合を報告します。', fileExchangeTitle1: 'キー認証伝送', fileExchangeContent1: 'SSHキーを介して認証し、伝送のセキュリティを確保します。', fileExchangeTitle2: '効率的なファイル同期', @@ -7540,6 +7574,13 @@ const message = { '{0} 個のイメージを {1} 個のノードへ転送します。合計 {2} 件のタスクが作成されます。', ssl: '証明書同期', + phpExtensions: 'PHP 拡張機能テンプレートの同期', + phpExtensionsTitle: '拡張機能テンプレートの同期', + phpExtensionsDesc: 'ソースノードを選択し、その PHP 拡張機能テンプレートをターゲットノードに同期します。', + phpExtensionsList: 'PHP 拡張機能', + phpExtensionsConfirm: '{0} 件の PHP 拡張機能テンプレートを {1} 個のノードに同期します。', + phpExtensionsConflictHint: + '同一のテンプレートはスキップします。同じ名前で内容が異なるテンプレートは競合として報告し、上書きしません。', sslBatchDesc: 'ソースノードを選択すると、指定した証明書を現在のパネル環境へ同期できます。', sslBatchConfirmPrefix: '{0} 件の証明書を {1} 個のノードへ同期します。合計 {2} 件のタスクが作成されます。', diff --git a/frontend/src/lang/modules/ko.ts b/frontend/src/lang/modules/ko.ts index 1487b4a1e..7eb029d39 100644 --- a/frontend/src/lang/modules/ko.ts +++ b/frontend/src/lang/modules/ko.ts @@ -3922,6 +3922,12 @@ const message = { '상용 버전으로 업그레이드하면 노드를 수동으로 전환하지 않고도 다중 노드 애플리케이션 버전을 일괄 업그레이드할 수 있습니다.', nodeDashboard: '상용 버전으로 업그레이드하면 다중 노드 애플리케이션, 웹사이트, 데이터베이스, 예약 작업을 중앙에서 관리할 수 있습니다.', + imageExchange: '상용 버전으로 업그레이드하면 노드 간에 컨테이너 이미지를 일괄 전송할 수 있습니다.', + appExchange: + '상용 버전으로 업그레이드하면 설치된 애플리케이션을 대상 노드로 마이그레이션하고 필요한 리소스 의존성을 확인할 수 있습니다.', + sslSync: '상용 버전으로 업그레이드하면 원본 노드의 인증서를 하나 이상의 대상 노드에 동기화할 수 있습니다.', + phpExtensionsSync: + '상용 버전으로 업그레이드하면 PHP 확장 템플릿을 하나 이상의 대상 노드에 동기화할 수 있습니다.', fileExchange: '상용 버전으로 업그레이드하면 여러 서버 간에 파일을 빠르게 전송할 수 있습니다.', app: '상용 버전으로 업그레이드하면 모바일 앱에서 서비스 정보와 이상 모니터링을 확인할 수 있습니다.', cluster: '상용 버전으로 업그레이드하면 MySQL/Postgres/Redis 기본-복제 클러스터를 관리할 수 있습니다.', @@ -6885,6 +6891,31 @@ const message = { nodeContent3: '각 노드의 운영 상태를 실시간으로 파악', nodeTitle4: '빠른 원격 연결', nodeContent4: '원클릭으로 노드 원격 터미널에 직접 연결', + imageExchangeTitle1: '원본 이미지 선택', + imageExchangeContent1: '원본 노드의 컨테이너 이미지를 확인하고 전송할 이미지를 선택합니다.', + imageExchangeTitle2: '이미지 배포', + imageExchangeContent2: '선택한 이미지를 하나 이상의 대상 노드로 전송합니다.', + imageExchangeTitle3: '전송 로그 확인', + imageExchangeContent3: '작업 로그에서 이미지 전송 진행 상황과 결과를 확인합니다.', + appExchangeTitle1: '애플리케이션 선택', + appExchangeContent1: '원본 노드에 설치된 애플리케이션을 확인하고 마이그레이션할 항목을 선택합니다.', + appExchangeTitle2: '의존성 확인', + appExchangeContent2: '마이그레이션 전에 대상 노드와 데이터베이스 등 필요한 리소스를 확인합니다.', + appExchangeTitle3: '애플리케이션 마이그레이션', + appExchangeContent3: '애플리케이션 백업을 대상 노드로 전송하여 복원하고 작업 로그에서 결과를 확인합니다.', + sslSyncTitle1: '인증서 선택', + sslSyncContent1: '원본 노드의 인증서 정보를 확인하고 동기화할 인증서를 선택합니다.', + sslSyncTitle2: '노드 간 동기화', + sslSyncContent2: '원본 노드를 자동으로 제외하고 선택한 인증서를 대상 노드에 동기화합니다.', + sslSyncTitle3: '동기화 작업 확인', + sslSyncContent3: '실행 전에 대상 노드와 인증서를 확인하고 실행 후 작업 로그에서 결과를 확인합니다.', + phpExtensionsSyncTitle1: '템플릿 선택', + phpExtensionsSyncContent1: '원본 노드의 템플릿 이름과 확장 목록을 확인하고 동기화할 템플릿을 선택합니다.', + phpExtensionsSyncTitle2: '템플릿 동기화', + phpExtensionsSyncContent2: '원본 노드를 자동으로 제외하고 선택한 템플릿을 대상 노드에 동기화합니다.', + phpExtensionsSyncTitle3: '기존 템플릿 확인', + phpExtensionsSyncContent3: + '이름과 내용이 같은 템플릿은 건너뜁니다. 내용이 다르면 덮어쓰지 않고 충돌을 보고합니다.', fileExchangeTitle1: '키 인증 전송', fileExchangeContent1: 'SSH 키를 통해 인증하여 전송 보안을 보장합니다.', fileExchangeTitle2: '효율적인 파일 동기화', @@ -7392,6 +7423,13 @@ const message = { imageBatchConfirmPrefix: '{0}개의 이미지를 {1}개 노드로 전달합니다. 총 {2}개의 작업이 생성됩니다.', ssl: '인증서 동기화', + phpExtensions: 'PHP 확장 템플릿 동기화', + phpExtensionsTitle: '확장 템플릿 동기화', + phpExtensionsDesc: '원본 노드를 선택하여 PHP 확장 템플릿을 대상 노드에 동기화합니다.', + phpExtensionsList: 'PHP 확장', + phpExtensionsConfirm: 'PHP 확장 템플릿 {0}개를 노드 {1}개에 동기화합니다.', + phpExtensionsConflictHint: + '동일한 템플릿은 건너뜁니다. 이름은 같지만 내용이 다른 템플릿은 충돌로 보고되며 덮어쓰지 않습니다.', sslBatchDesc: '원본 노드를 선택한 후 지정된 인증서를 현재 패널 환경으로 동기화할 수 있습니다.', sslBatchConfirmPrefix: '{0}개의 인증서를 {1}개 노드로 동기화합니다. 총 {2}개의 작업이 생성됩니다.', diff --git a/frontend/src/lang/modules/lo.ts b/frontend/src/lang/modules/lo.ts index 9c5e7169f..967a7ba8a 100644 --- a/frontend/src/lang/modules/lo.ts +++ b/frontend/src/lang/modules/lo.ts @@ -3900,6 +3900,11 @@ const message = { nodeApp: 'ອັບເກຣດເປັນເວີຊັນ Commercial ເພື່ອອັບເກຣດເວີຊັນແອັບໃນຫຼາຍໂນດໂດຍບໍ່ຕ້ອງສະຫຼັບໂນດດ້ວຍຕົນເອງ.', nodeDashboard: 'ອັບເກຣດເປັນເວີຊັນ Commercial ເພື່ອຈັດການແອັບ, ເວັບໄຊ, ຖານຂໍ້ມູນ ແລະ ງານຕາມກຳນົດເວລາຂອງຫຼາຍໂນດຢູ່ບ່ອນດຽວ.', + imageExchange: 'ອັບເກຣດເປັນເວີຊັນ Commercial ເພື່ອໂອນອິມເມດຄອນເທນເນີເປັນຊຸດລະຫວ່າງໂນດ.', + appExchange: + 'ອັບເກຣດເປັນເວີຊັນ Commercial ເພື່ອຍ້າຍແອັບທີ່ຕິດຕັ້ງແລ້ວໄປຍັງໂນດປາຍທາງ ແລະ ຢືນຢັນຊັບພະຍາກອນທີ່ຈຳເປັນ.', + sslSync: 'ອັບເກຣດເປັນເວີຊັນ Commercial ເພື່ອຊິງໃບຢັ້ງຢືນຈາກໂນດຕົ້ນທາງໄປຍັງໂນດປາຍທາງໜຶ່ງ ຫຼື ຫຼາຍໂນດ.', + phpExtensionsSync: 'ອັບເກຣດເປັນເວີຊັນ Commercial ເພື່ອຊິງແມ່ແບບສ່ວນຂະຫຍາຍ PHP ໄປຍັງໂນດປາຍທາງໜຶ່ງ ຫຼື ຫຼາຍໂນດ.', fileExchange: 'ອັບເກຣດເປັນເວີຊັນ Commercial ເພື່ອໂອນຍ້າຍໄຟລ໌ລະຫວ່າງເຊີບເວີຢ່າງວ່ອງໄວ.', app: 'ອັບເກຣດເປັນເວີຊັນ Commercial ເພື່ອເບິ່ງລາຍລະອຽດບໍລິການ, ການຕິດຕາມສິ່ງຜິດປົກກະຕິ ແລະ ອື່ນໆໃນແອັບມືຖື.', cluster: 'ອັບເກຣດເປັນເວີຊັນ Commercial ເພື່ອຈັດການ MySQL/Postgres/Redis primary-replica clusters.', @@ -6827,6 +6832,31 @@ const message = { nodeContent3: 'ຕິດຕາມສະຖານະການທຳງານຂອງແຕ່ລະໂນດແບບທັນທີ', nodeTitle4: 'ເຊື່ອມຕໍ່ໄລຍະໄກວ່ອງໄວ', nodeContent4: 'ເຊື່ອມຕໍ່ຫາເທີມິນອລຂອງໂນດໄດ້ໂດຍກົງຄລິກດຽວ', + imageExchangeTitle1: 'ເລືອກອິມເມດຕົ້ນທາງ', + imageExchangeContent1: 'ເບິ່ງອິມເມດຄອນເທນເນີໃນໂນດຕົ້ນທາງ ແລະ ເລືອກອິມເມດທີ່ຕ້ອງການໂອນ.', + imageExchangeTitle2: 'ແຈກຢາຍອິມເມດ', + imageExchangeContent2: 'ໂອນອິມເມດທີ່ເລືອກໄປຍັງໂນດປາຍທາງໜຶ່ງ ຫຼື ຫຼາຍໂນດ.', + imageExchangeTitle3: 'ເບິ່ງບັນທຶກການໂອນ', + imageExchangeContent3: 'ຕິດຕາມຄວາມຄືບໜ້າ ແລະ ຜົນການໂອນອິມເມດໃນບັນທຶກວຽກ.', + appExchangeTitle1: 'ເລືອກແອັບ', + appExchangeContent1: 'ເບິ່ງແອັບທີ່ຕິດຕັ້ງໃນໂນດຕົ້ນທາງ ແລະ ເລືອກແອັບທີ່ຕ້ອງການຍ້າຍ.', + appExchangeTitle2: 'ຢືນຢັນຊັບພະຍາກອນທີ່ຈຳເປັນ', + appExchangeContent2: 'ກ່ອນຍ້າຍ ໃຫ້ຢືນຢັນໂນດປາຍທາງ ແລະ ຊັບພະຍາກອນທີ່ຈຳເປັນ ເຊັ່ນ ຖານຂໍ້ມູນ.', + appExchangeTitle3: 'ຍ້າຍແອັບ', + appExchangeContent3: 'ໂອນຂໍ້ມູນສຳຮອງຂອງແອັບໄປຍັງໂນດປາຍທາງເພື່ອກູ້ຄືນ ແລະ ເບິ່ງຜົນໃນບັນທຶກວຽກ.', + sslSyncTitle1: 'ເລືອກໃບຢັ້ງຢືນ', + sslSyncContent1: 'ເບິ່ງລາຍລະອຽດໃບຢັ້ງຢືນໃນໂນດຕົ້ນທາງ ແລະ ເລືອກໃບຢັ້ງຢືນທີ່ຕ້ອງການຊິງ.', + sslSyncTitle2: 'ຊິງລະຫວ່າງໂນດ', + sslSyncContent2: 'ຊິງໃບຢັ້ງຢືນທີ່ເລືອກໄປຍັງໂນດປາຍທາງ ໂດຍຍົກເວັ້ນໂນດຕົ້ນທາງອັດຕະໂນມັດ.', + sslSyncTitle3: 'ຢືນຢັນວຽກຊິງ', + sslSyncContent3: 'ກວດສອບໂນດປາຍທາງ ແລະ ໃບຢັ້ງຢືນກ່ອນດຳເນີນການ ແລ້ວເບິ່ງຜົນໃນບັນທຶກວຽກ.', + phpExtensionsSyncTitle1: 'ເລືອກແມ່ແບບ', + phpExtensionsSyncContent1: 'ເບິ່ງຊື່ແມ່ແບບ ແລະ ລາຍການສ່ວນຂະຫຍາຍໃນໂນດຕົ້ນທາງ ແລະ ເລືອກແມ່ແບບທີ່ຕ້ອງການຊິງ.', + phpExtensionsSyncTitle2: 'ຊິງແມ່ແບບ', + phpExtensionsSyncContent2: 'ຊິງແມ່ແບບທີ່ເລືອກໄປຍັງໂນດປາຍທາງ ໂດຍຍົກເວັ້ນໂນດຕົ້ນທາງອັດຕະໂນມັດ.', + phpExtensionsSyncTitle3: 'ກວດສອບແມ່ແບບທີ່ມີຢູ່', + phpExtensionsSyncContent3: + 'ຂ້າມແມ່ແບບທີ່ມີຊື່ ແລະ ເນື້ອຫາຄືກັນ. ຖ້າເນື້ອຫາຕ່າງກັນ ຈະແຈ້ງຂໍ້ຂັດແຍ່ງໂດຍບໍ່ຂຽນທັບ.', fileExchangeTitle1: 'ສົ່ງຂໍ້ມູນຜ່ານ Key Authentication', fileExchangeContent1: 'ຢືນຢັນຕົວຕົນຜ່ານ SSH keys ເພື່ອຄວາມປອດໄພໃນການສົ່ງຂໍ້ມູນ.', fileExchangeTitle2: 'ຊິງໂຄຣໄນໄຟລ໌ທີ່ມີປະສິດທິພາບ', @@ -7304,6 +7334,13 @@ const message = { imageBatchConfirmPrefix: 'ກຳລັງຈະໂອນ {0} images ໄປຫາ {1} ໂນດ, ລວມທັງໝົດ {2} ງານ.', ssl: 'ຊິງໂຄຣໄນໃບຢັ້ງຢືນ', + phpExtensions: 'ຊິງແມ່ແບບສ່ວນຂະຫຍາຍ PHP', + phpExtensionsTitle: 'ຊິງແມ່ແບບສ່ວນຂະຫຍາຍ', + phpExtensionsDesc: 'ເລືອກໂນດຕົ້ນທາງເພື່ອຊິງແມ່ແບບສ່ວນຂະຫຍາຍ PHP ໄປຍັງໂນດປາຍທາງ.', + phpExtensionsList: 'ສ່ວນຂະຫຍາຍ PHP', + phpExtensionsConfirm: 'ຈະຊິງແມ່ແບບສ່ວນຂະຫຍາຍ PHP {0} ແມ່ແບບ ໄປຍັງ {1} ໂນດ.', + phpExtensionsConflictHint: + 'ແມ່ແບບທີ່ຄືກັນຈະຖືກຂ້າມ. ແມ່ແບບທີ່ມີຊື່ຄືກັນແຕ່ເນື້ອຫາຕ່າງກັນຈະຖືກແຈ້ງເປັນຂໍ້ຂັດແຍ່ງ ແລະ ບໍ່ຖືກຂຽນທັບ.', sslBatchDesc: 'ເລືອກໂນດຕົ້ນທາງ ແລະ ຊິງໂຄຣໄນໃບຢັ້ງຢືນທີ່ກຳນົດເຂົ້າມາໃນພາແນລປັດຈຸບັນ.', sslBatchConfirmPrefix: 'ກຳລັງຈະຊິງໂຄຣໄນ {0} ໃບຢັ້ງຢືນ ໄປຫາ {1} ໂນດ, ລວມທັງໝົດ {2} ງານ.', diff --git a/frontend/src/lang/modules/ms.ts b/frontend/src/lang/modules/ms.ts index 158d5465a..3218dbf33 100644 --- a/frontend/src/lang/modules/ms.ts +++ b/frontend/src/lang/modules/ms.ts @@ -4078,6 +4078,13 @@ const message = { 'Naik taraf ke Edisi Komersial untuk menaik taraf versi aplikasi berbilang nod tanpa menukar nod secara manual.', nodeDashboard: 'Naik taraf ke Edisi Komersial untuk mengurus aplikasi, laman web, pangkalan data dan tugas berjadual berbilang nod secara berpusat.', + imageExchange: 'Naik taraf ke Edisi Komersial untuk memindahkan imej kontena secara kelompok antara nod.', + appExchange: + 'Naik taraf ke Edisi Komersial untuk memindahkan aplikasi yang dipasang ke nod sasaran dan mengesahkan kebergantungan sumbernya.', + sslSync: + 'Naik taraf ke Edisi Komersial untuk menyegerakkan sijil daripada nod sumber ke satu atau lebih nod sasaran.', + phpExtensionsSync: + 'Naik taraf ke Edisi Komersial untuk menyegerakkan templat sambungan PHP ke satu atau lebih nod sasaran.', fileExchange: 'Naik taraf ke Edisi Komersial untuk memindahkan fail dengan pantas antara pelayan.', app: 'Naik taraf ke Edisi Komersial untuk melihat maklumat perkhidmatan dan pemantauan anomali dalam aplikasi mudah alih.', cluster: 'Naik taraf ke Edisi Komersial untuk mengurus kelompok utama-replika MySQL/Postgres/Redis.', @@ -7139,6 +7146,38 @@ const message = { nodeContent3: 'Memantau status operasi setiap nod secara real-time', nodeTitle4: 'Sambungan Jauh Pantas', nodeContent4: 'Sambung terus ke terminal jauh nod dengan satu klik', + imageExchangeTitle1: 'Pilih imej sumber', + imageExchangeContent1: 'Lihat imej kontena pada nod sumber dan pilih imej yang hendak dipindahkan.', + imageExchangeTitle2: 'Edarkan imej', + imageExchangeContent2: 'Pindahkan imej yang dipilih ke satu atau lebih nod sasaran.', + imageExchangeTitle3: 'Lihat log pemindahan', + imageExchangeContent3: 'Pantau kemajuan dan hasil pemindahan imej dalam log tugas.', + appExchangeTitle1: 'Pilih aplikasi', + appExchangeContent1: + 'Lihat aplikasi yang dipasang pada nod sumber dan pilih aplikasi yang hendak dipindahkan.', + appExchangeTitle2: 'Sahkan kebergantungan', + appExchangeContent2: + 'Sebelum pemindahan, sahkan nod sasaran dan sumber yang diperlukan, seperti pangkalan data.', + appExchangeTitle3: 'Pindahkan aplikasi', + appExchangeContent3: + 'Pindahkan sandaran aplikasi ke nod sasaran untuk pemulihan dan lihat hasilnya dalam log tugas.', + sslSyncTitle1: 'Pilih sijil', + sslSyncContent1: 'Lihat butiran sijil pada nod sumber dan pilih sijil yang hendak disegerakkan.', + sslSyncTitle2: 'Segerakkan antara nod', + sslSyncContent2: + 'Segerakkan sijil yang dipilih ke nod sasaran dengan mengecualikan nod sumber secara automatik.', + sslSyncTitle3: 'Sahkan tugas penyegerakan', + sslSyncContent3: + 'Semak nod sasaran dan sijil sebelum pelaksanaan, kemudian lihat hasilnya dalam log tugas.', + phpExtensionsSyncTitle1: 'Pilih templat', + phpExtensionsSyncContent1: + 'Lihat nama templat dan senarai sambungan pada nod sumber, kemudian pilih templat yang hendak disegerakkan.', + phpExtensionsSyncTitle2: 'Segerakkan templat', + phpExtensionsSyncContent2: + 'Segerakkan templat yang dipilih ke nod sasaran dengan mengecualikan nod sumber secara automatik.', + phpExtensionsSyncTitle3: 'Semak templat sedia ada', + phpExtensionsSyncContent3: + 'Templat dengan nama dan kandungan yang sama akan dilangkau. Kandungan yang berbeza dilaporkan sebagai konflik tanpa ditulis ganti.', fileExchangeTitle1: 'Pengangkutan Pengesahan Kunci', fileExchangeContent1: 'Mengesahkan melalui kunci SSH untuk memastikan keselamatan pengangkutan.', fileExchangeTitle2: 'Segerakan Fail Cekap', @@ -7662,6 +7701,13 @@ const message = { imageBatchConfirmPrefix: 'Akan memindahkan {0} imej ke {1} nod, dengan jumlah {2} tugasan.', ssl: 'Penyegerakan Sijil', + phpExtensions: 'Penyegerakan Templat Sambungan PHP', + phpExtensionsTitle: 'Penyegerakan Templat Sambungan', + phpExtensionsDesc: 'Pilih nod sumber untuk menyegerakkan templat sambungan PHP ke nod sasaran.', + phpExtensionsList: 'Sambungan PHP', + phpExtensionsConfirm: 'Segerakkan {0} templat sambungan PHP ke {1} nod.', + phpExtensionsConflictHint: + 'Templat yang sama akan dilangkau. Templat dengan nama yang sama tetapi kandungan berbeza dilaporkan sebagai konflik dan tidak akan ditulis ganti.', sslBatchDesc: 'Selepas memilih nod sumber, sijil yang ditentukan boleh disegerakkan ke persekitaran panel semasa.', sslBatchConfirmPrefix: 'Akan menyegerakkan {0} sijil ke {1} nod, dengan jumlah {2} tugasan.', diff --git a/frontend/src/lang/modules/pt-br.ts b/frontend/src/lang/modules/pt-br.ts index 4897df75c..63414a361 100644 --- a/frontend/src/lang/modules/pt-br.ts +++ b/frontend/src/lang/modules/pt-br.ts @@ -4084,6 +4084,13 @@ const message = { 'Atualize para a edição comercial para atualizar versões de aplicativos multi-nó sem alternar manualmente entre os nós.', nodeDashboard: 'Atualize para a edição comercial para gerenciar aplicativos, sites, bancos de dados e tarefas agendadas multi-nó de forma centralizada.', + imageExchange: 'Atualize para a edição comercial para transferir imagens de contêineres em lote entre nós.', + appExchange: + 'Atualize para a edição comercial para migrar aplicativos instalados para nós de destino e confirmar suas dependências de recursos.', + sslSync: + 'Atualize para a edição comercial para sincronizar certificados de um nó de origem com um ou mais nós de destino.', + phpExtensionsSync: + 'Atualize para a edição comercial para sincronizar modelos de extensões PHP com um ou mais nós de destino.', fileExchange: 'Atualize para a edição comercial para transferir arquivos rapidamente entre vários servidores.', app: 'Faça upgrade para a edição comercial para visualizar informações do serviço e monitoramento de anomalias no aplicativo móvel.', cluster: 'Atualize para a edição comercial para gerenciar clusters primário-réplica de MySQL/Postgres/Redis.', @@ -7174,6 +7181,40 @@ const message = { nodeContent3: 'Acompanhe em tempo real o status operacional de cada nó', nodeTitle4: 'Conexão Remota Rápida', nodeContent4: 'Conecte-se diretamente a terminais remotos de nós com um clique', + imageExchangeTitle1: 'Selecionar imagens de origem', + imageExchangeContent1: + 'Consulte as imagens de contêineres do nó de origem e selecione as que deseja transferir.', + imageExchangeTitle2: 'Distribuir imagens', + imageExchangeContent2: 'Transfira as imagens selecionadas para um ou mais nós de destino.', + imageExchangeTitle3: 'Ver logs de transferência', + imageExchangeContent3: + 'Acompanhe o progresso e os resultados da transferência de imagens nos logs de tarefas.', + appExchangeTitle1: 'Selecionar um aplicativo', + appExchangeContent1: 'Consulte os aplicativos instalados no nó de origem e selecione um para migrar.', + appExchangeTitle2: 'Confirmar dependências', + appExchangeContent2: + 'Antes da migração, confirme os nós de destino e os recursos necessários, como bancos de dados.', + appExchangeTitle3: 'Migrar aplicativos', + appExchangeContent3: + 'Transfira os backups dos aplicativos para os nós de destino para restauração e consulte os resultados nos logs de tarefas.', + sslSyncTitle1: 'Selecionar certificados', + sslSyncContent1: + 'Consulte os detalhes dos certificados do nó de origem e selecione os que deseja sincronizar.', + sslSyncTitle2: 'Sincronizar entre nós', + sslSyncContent2: + 'Sincronize os certificados selecionados com os nós de destino, excluindo automaticamente o nó de origem.', + sslSyncTitle3: 'Confirmar tarefas de sincronização', + sslSyncContent3: + 'Revise os nós de destino e os certificados antes da execução e consulte os resultados nos logs de tarefas.', + phpExtensionsSyncTitle1: 'Selecionar um modelo', + phpExtensionsSyncContent1: + 'Consulte os nomes dos modelos e as listas de extensões do nó de origem e selecione um modelo para sincronizar.', + phpExtensionsSyncTitle2: 'Sincronizar modelos', + phpExtensionsSyncContent2: + 'Sincronize o modelo selecionado com os nós de destino, excluindo automaticamente o nó de origem.', + phpExtensionsSyncTitle3: 'Verificar modelos existentes', + phpExtensionsSyncContent3: + 'Modelos com nome e conteúdo idênticos são ignorados. Conteúdos diferentes são sinalizados como conflitos e não são sobrescritos.', fileExchangeTitle1: 'Transmissão de Autenticação por Chave', fileExchangeContent1: 'Autentique via chaves SSH para garantir a segurança da transmissão.', fileExchangeTitle2: 'Sincronização de Arquivos Eficiente', @@ -7699,6 +7740,14 @@ const message = { imageBatchConfirmPrefix: 'Serão encaminhadas {0} imagens para {1} nós, totalizando {2} tarefas.', ssl: 'Sincronização de Certificados', + phpExtensions: 'Sincronização de modelos de extensões PHP', + phpExtensionsTitle: 'Sincronização de modelos de extensões', + phpExtensionsDesc: + 'Selecione um nó de origem para sincronizar seu modelo de extensões PHP com os nós de destino.', + phpExtensionsList: 'Extensões PHP', + phpExtensionsConfirm: 'Serão sincronizados {0} modelos de extensões PHP com {1} nós.', + phpExtensionsConflictHint: + 'Modelos idênticos são ignorados. Modelos com o mesmo nome e conteúdo diferente são sinalizados como conflitos e não são sobrescritos.', sslBatchDesc: 'Após selecionar o nó de origem, os certificados especificados podem ser sincronizados com o ambiente atual do painel.', sslBatchConfirmPrefix: 'Serão sincronizados {0} certificados para {1} nós, totalizando {2} tarefas.', diff --git a/frontend/src/lang/modules/ru.ts b/frontend/src/lang/modules/ru.ts index 5bb0c535c..d10e492e2 100644 --- a/frontend/src/lang/modules/ru.ts +++ b/frontend/src/lang/modules/ru.ts @@ -4060,6 +4060,13 @@ const message = { 'Обновление до коммерческой редакции позволяет унифицированно обновлять версии приложений на нескольких узлах без необходимости ручного переключения узлов.', nodeDashboard: 'Обновление до коммерческой редакции позволяет централизованно управлять приложениями, веб-сайтами, базами данных и запланированными задачами на нескольких узлах.', + imageExchange: 'Обновите до Коммерческой версии, чтобы передавать образы контейнеров между узлами пакетами.', + appExchange: + 'Обновите до Коммерческой версии, чтобы переносить установленные приложения на целевые узлы и проверять необходимые ресурсы.', + sslSync: + 'Обновите до Коммерческой версии, чтобы синхронизировать сертификаты исходного узла с одним или несколькими целевыми узлами.', + phpExtensionsSync: + 'Обновите до Коммерческой версии, чтобы синхронизировать шаблоны расширений PHP с одним или несколькими целевыми узлами.', fileExchange: 'Обновите до Коммерческой версии, чтобы быстро передавать файлы между несколькими серверами.', app: 'Обновите до коммерческой версии, чтобы просматривать информацию о сервисах, мониторинг аномалий и т.д. через мобильное приложение.', cluster: 'Обновление до коммерческой версии позволяет управлять кластерами мастер-слейв MySQL/Postgres/Redis.', @@ -7148,6 +7155,38 @@ const message = { nodeContent3: 'Реальное наблюдение за рабочим статусом каждого узла', nodeTitle4: 'Быстрое удаленное подключение', nodeContent4: 'Одним кликом подключитесь к удаленным терминалам узлов', + imageExchangeTitle1: 'Выбор исходных образов', + imageExchangeContent1: 'Просмотрите образы контейнеров на исходном узле и выберите образы для передачи.', + imageExchangeTitle2: 'Распространение образов', + imageExchangeContent2: 'Передайте выбранные образы на один или несколько целевых узлов.', + imageExchangeTitle3: 'Просмотр журналов передачи', + imageExchangeContent3: 'Отслеживайте ход и результаты передачи образов в журналах задач.', + appExchangeTitle1: 'Выбор приложения', + appExchangeContent1: + 'Просмотрите установленные приложения на исходном узле и выберите приложение для переноса.', + appExchangeTitle2: 'Проверка зависимостей', + appExchangeContent2: 'Перед переносом проверьте целевые узлы и необходимые ресурсы, например базы данных.', + appExchangeTitle3: 'Перенос приложений', + appExchangeContent3: + 'Передайте резервные копии приложений на целевые узлы для восстановления и просмотрите результаты в журналах задач.', + sslSyncTitle1: 'Выбор сертификатов', + sslSyncContent1: + 'Просмотрите сведения о сертификатах исходного узла и выберите сертификаты для синхронизации.', + sslSyncTitle2: 'Синхронизация между узлами', + sslSyncContent2: + 'Синхронизируйте выбранные сертификаты с целевыми узлами, автоматически исключив исходный узел.', + sslSyncTitle3: 'Подтверждение задач синхронизации', + sslSyncContent3: + 'Перед выполнением проверьте целевые узлы и сертификаты, а затем просмотрите результаты в журналах задач.', + phpExtensionsSyncTitle1: 'Выбор шаблона', + phpExtensionsSyncContent1: + 'Просмотрите имена шаблонов и списки расширений на исходном узле и выберите шаблон для синхронизации.', + phpExtensionsSyncTitle2: 'Синхронизация шаблонов', + phpExtensionsSyncContent2: + 'Синхронизируйте выбранный шаблон с целевыми узлами, автоматически исключив исходный узел.', + phpExtensionsSyncTitle3: 'Проверка существующих шаблонов', + phpExtensionsSyncContent3: + 'Шаблоны с одинаковыми именами и содержимым пропускаются. При различии содержимого сообщается о конфликте без перезаписи.', fileExchangeTitle1: 'Передача с аутентификацией по ключу', fileExchangeContent1: 'Аутентифицируйтесь через SSH-ключи, чтобы обеспечить безопасность передачи.', fileExchangeTitle2: 'Эффективная синхронизация файлов', @@ -7678,6 +7717,14 @@ const message = { imageBatchConfirmPrefix: 'Будет передано {0} образов на {1} узлов, всего {2} задач.', ssl: 'Синхронизация сертификатов', + phpExtensions: 'Синхронизация шаблонов расширений PHP', + phpExtensionsTitle: 'Синхронизация шаблонов расширений', + phpExtensionsDesc: + 'Выберите исходный узел, чтобы синхронизировать его шаблон расширений PHP с целевыми узлами.', + phpExtensionsList: 'Расширения PHP', + phpExtensionsConfirm: 'Будет синхронизировано шаблонов расширений PHP: {0}; целевых узлов: {1}.', + phpExtensionsConflictHint: + 'Идентичные шаблоны пропускаются. Шаблоны с одинаковыми именами и разным содержимым отмечаются как конфликтующие и не перезаписываются.', sslBatchDesc: 'После выбора исходного узла указанные сертификаты можно синхронизировать с текущей средой панели.', sslBatchConfirmPrefix: 'Будет синхронизировано {0} сертификатов на {1} узлов, всего {2} задач.', diff --git a/frontend/src/lang/modules/tr.ts b/frontend/src/lang/modules/tr.ts index 638d4d556..1d257047f 100644 --- a/frontend/src/lang/modules/tr.ts +++ b/frontend/src/lang/modules/tr.ts @@ -4073,6 +4073,14 @@ const message = { 'Ticari sürüme yükselterek düğümleri manuel değiştirmeden çok düğümlü uygulama sürümlerini toplu olarak yükseltebilirsiniz.', nodeDashboard: 'Ticari sürüme yükselterek çok düğümlü uygulamaları, web sitelerini, veritabanlarını ve zamanlanmış görevleri merkezi olarak yönetebilirsiniz.', + imageExchange: + 'Ticari sürüme yükselterek konteyner imajlarını düğümler arasında toplu olarak aktarabilirsiniz.', + appExchange: + 'Ticari sürüme yükselterek yüklü uygulamaları hedef düğümlere taşıyabilir ve gerekli kaynak bağımlılıklarını doğrulayabilirsiniz.', + sslSync: + 'Ticari sürüme yükselterek kaynak düğümdeki sertifikaları bir veya daha fazla hedef düğümle eşitleyebilirsiniz.', + phpExtensionsSync: + 'Ticari sürüme yükselterek PHP uzantı şablonlarını bir veya daha fazla hedef düğümle eşitleyebilirsiniz.', fileExchange: 'Ticari sürüme yükselterek birden fazla sunucu arasında dosyaları hızlıca aktarabilirsiniz.', app: 'Ticari sürüme yükselterek mobil uygulamada hizmet bilgilerini ve anormallik izlemeyi görüntüleyebilirsiniz.', cluster: 'Ticari sürüme yükselterek MySQL/Postgres/Redis birincil-kopya kümelerini yönetebilirsiniz.', @@ -7151,6 +7159,37 @@ const message = { nodeContent3: 'Her düğümün çalışma durumunu gerçek zamanlı olarak izler', nodeTitle4: 'Hızlı Uzak Bağlantı', nodeContent4: 'Düğümlere tek tıkla doğrudan uzak terminal bağlantısı', + imageExchangeTitle1: 'Kaynak imajları seçin', + imageExchangeContent1: 'Kaynak düğümdeki konteyner imajlarını inceleyin ve aktarılacak imajları seçin.', + imageExchangeTitle2: 'İmajları dağıtın', + imageExchangeContent2: 'Seçilen imajları bir veya daha fazla hedef düğüme aktarın.', + imageExchangeTitle3: 'Aktarım günlüklerini görüntüleyin', + imageExchangeContent3: 'İmaj aktarımının ilerlemesini ve sonuçlarını görev günlüklerinden takip edin.', + appExchangeTitle1: 'Bir uygulama seçin', + appExchangeContent1: 'Kaynak düğümde yüklü uygulamaları inceleyin ve taşınacak uygulamayı seçin.', + appExchangeTitle2: 'Bağımlılıkları doğrulayın', + appExchangeContent2: + 'Taşıma işleminden önce hedef düğümleri ve veritabanları gibi gerekli kaynakları doğrulayın.', + appExchangeTitle3: 'Uygulamaları taşıyın', + appExchangeContent3: + 'Uygulama yedeklerini geri yüklemek için hedef düğümlere aktarın ve sonuçları görev günlüklerinde görüntüleyin.', + sslSyncTitle1: 'Sertifikaları seçin', + sslSyncContent1: 'Kaynak düğümdeki sertifika bilgilerini inceleyin ve eşitlenecek sertifikaları seçin.', + sslSyncTitle2: 'Düğümler arasında eşitleyin', + sslSyncContent2: + 'Kaynak düğüm otomatik olarak hariç tutularak seçilen sertifikaları hedef düğümlerle eşitleyin.', + sslSyncTitle3: 'Eşitleme görevlerini onaylayın', + sslSyncContent3: + 'İşlemden önce hedef düğümleri ve sertifikaları gözden geçirin, ardından sonuçları görev günlüklerinde görüntüleyin.', + phpExtensionsSyncTitle1: 'Bir şablon seçin', + phpExtensionsSyncContent1: + 'Kaynak düğümdeki şablon adlarını ve uzantı listelerini inceleyin ve eşitlenecek şablonu seçin.', + phpExtensionsSyncTitle2: 'Şablonları eşitleyin', + phpExtensionsSyncContent2: + 'Kaynak düğüm otomatik olarak hariç tutularak seçilen şablonu hedef düğümlerle eşitleyin.', + phpExtensionsSyncTitle3: 'Mevcut şablonları kontrol edin', + phpExtensionsSyncContent3: + 'Adı ve içeriği aynı olan şablonlar atlanır. İçerik farklıysa üzerine yazılmadan çakışma bildirilir.', fileExchangeTitle1: 'Anahtar Kimlik Doğrulama İletimi', fileExchangeContent1: 'İletim güvenliğini sağlamak için SSH anahtarları ile kimlik doğrulaması yapar.', fileExchangeTitle2: 'Verimli Dosya Senkronizasyonu', @@ -7675,6 +7714,13 @@ const message = { imageBatchConfirmPrefix: '{0} imaj {1} düğüme aktarılacak, toplam {2} görev oluşturulacak.', ssl: 'Sertifika Senkronizasyonu', + phpExtensions: 'PHP Uzantı Şablonu Eşitleme', + phpExtensionsTitle: 'Uzantı Şablonu Eşitleme', + phpExtensionsDesc: 'PHP uzantı şablonunu hedef düğümlerle eşitlemek için bir kaynak düğüm seçin.', + phpExtensionsList: 'PHP uzantıları', + phpExtensionsConfirm: '{0} PHP uzantı şablonu {1} düğümle eşitlenecek.', + phpExtensionsConflictHint: + 'Aynı şablonlar atlanır. Adı aynı ancak içeriği farklı olan şablonlar çakışma olarak bildirilir ve üzerlerine yazılmaz.', sslBatchDesc: 'Kaynak düğüm seçildikten sonra belirtilen sertifikalar mevcut panel ortamına senkronize edilebilir.', sslBatchConfirmPrefix: '{0} sertifika {1} düğüme senkronize edilecek, toplam {2} görev oluşturulacak.', diff --git a/frontend/src/lang/modules/zh-Hant.ts b/frontend/src/lang/modules/zh-Hant.ts index bfca41d00..0b1b999a1 100644 --- a/frontend/src/lang/modules/zh-Hant.ts +++ b/frontend/src/lang/modules/zh-Hant.ts @@ -3748,6 +3748,10 @@ const message = { node: '升級商業版可以使用 1Panel 管理多台 Linux 伺服器。', nodeApp: '升級商業版可以統一升級多節點應用版本,無需手動切換節點。', nodeDashboard: '升級商業版可以集中管理多節點應用、網站、資料庫和計劃任務。', + imageExchange: '升級商業版可以在多個節點之間批次傳輸容器映像。', + appExchange: '升級商業版可以將已安裝的應用程式遷移到目標節點,並確認所需的關聯資源。', + sslSync: '升級商業版可以將來源節點的憑證同步到一個或多個目標節點。', + phpExtensionsSync: '升級商業版可以將 PHP 擴充範本同步到一個或多個目標節點。', fileExchange: '升級商業版可以在多台伺服器之間快速傳輸檔案。', app: '升級商業版可透過手機APP,檢視服務資訊、異常監控等。', cluster: '升級商業版可以管理 MySQL/Postgres/Redis 主從叢集。', @@ -6540,6 +6544,30 @@ const message = { nodeContent3: '即時掌握各節點執行狀態', nodeTitle4: '快速遠端連接', nodeContent4: '一鍵直連節點遠端終端', + imageExchangeTitle1: '選擇來源映像', + imageExchangeContent1: '檢視來源節點的容器映像,選擇需要傳輸的映像。', + imageExchangeTitle2: '批次分發映像', + imageExchangeContent2: '將選取的映像傳輸到一個或多個目標節點。', + imageExchangeTitle3: '檢視傳輸日誌', + imageExchangeContent3: '透過任務日誌檢視映像傳輸進度和執行結果。', + appExchangeTitle1: '選擇來源應用程式', + appExchangeContent1: '檢視來源節點已安裝的應用程式,選擇需要遷移的應用程式。', + appExchangeTitle2: '確認資源相依性', + appExchangeContent2: '遷移前確認目標節點及應用程式所需的資料庫等關聯資源。', + appExchangeTitle3: '執行應用程式遷移', + appExchangeContent3: '將應用程式備份傳輸到目標節點進行還原,並透過任務日誌檢視結果。', + sslSyncTitle1: '選擇來源憑證', + sslSyncContent1: '檢視來源節點的憑證資訊,選擇需要同步的憑證。', + sslSyncTitle2: '多節點憑證同步', + sslSyncContent2: '將選取的憑證同步到目標節點,自動排除來源節點。', + sslSyncTitle3: '確認同步任務', + sslSyncContent3: '執行前確認目標節點和憑證,透過任務日誌檢視同步結果。', + phpExtensionsSyncTitle1: '選擇擴充範本', + phpExtensionsSyncContent1: '檢視來源節點的範本名稱和擴充清單,選擇需要同步的範本。', + phpExtensionsSyncTitle2: '多節點範本同步', + phpExtensionsSyncContent2: '將選取的擴充範本同步到目標節點,自動排除來源節點。', + phpExtensionsSyncTitle3: '同名範本檢查', + phpExtensionsSyncContent3: '同名且內容一致的範本會略過;內容不同則提示衝突,不會覆寫。', fileExchangeTitle1: '金鑰認證傳輸', fileExchangeContent1: '通過 SSH 金鑰進行身份驗證,確保傳輸的安全性。', fileExchangeTitle2: '高效檔案同步', @@ -7023,6 +7051,12 @@ const message = { imageBatchConfirmPrefix: '即將把 {0} 張映像轉發到 {1} 個節點,共 {2} 個任務。', ssl: '證書同步', + phpExtensions: 'PHP 擴充模版同步', + phpExtensionsTitle: '擴充模版同步', + phpExtensionsDesc: '選擇來源節點後,可將指定 PHP 擴充模版同步至目標節點。', + phpExtensionsList: '擴充清單', + phpExtensionsConfirm: '即將把 {0} 個 PHP 擴充模版同步至 {1} 個目標節點。', + phpExtensionsConflictHint: '同名且內容一致的模版將略過;同名但內容不同的模版將提示衝突,不會覆蓋。', sslBatchDesc: '選擇來源節點後,可將指定證書同步到目前面板環境。', sslBatchConfirmPrefix: '即將把 {0} 張證書同步到 {1} 個節點,共 {2} 個任務。', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index ecc45eb58..9f3f0d6c3 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -3778,6 +3778,10 @@ const message = { node: '升级商业版可以使用 1Panel 管理多台 linux 服务器。', nodeApp: '升级商业版可以统一升级多节点应用版本,无需手动切换节点。', nodeDashboard: '升级商业版可以集中管理多节点应用、网站、数据库和计划任务。', + imageExchange: '升级商业版可以在多个节点之间批量传输容器镜像。', + appExchange: '升级商业版可以将已安装的应用迁移到目标节点,并确认所需的关联资源。', + sslSync: '升级商业版可以将源节点的证书同步到一个或多个目标节点。', + phpExtensionsSync: '升级商业版可以将 PHP 扩展模版同步到一个或多个目标节点。', fileExchange: '升级商业版可以在多台服务器之间快速传输文件。', app: '升级商业版可通过手机 APP,查看服务信息、异常监控等。', cluster: '升级商业版可以管理 MySQL/Postgres/Redis 主从集群。', @@ -5495,6 +5499,30 @@ const message = { nodeTitle4: '快速远程连接', nodeContent4: '一键直连节点远程终端', + imageExchangeTitle1: '选择源镜像', + imageExchangeContent1: '查看源节点的容器镜像,选择需要传输的镜像。', + imageExchangeTitle2: '批量分发镜像', + imageExchangeContent2: '将选中的镜像传输到一个或多个目标节点。', + imageExchangeTitle3: '查看传输日志', + imageExchangeContent3: '通过任务日志查看镜像传输进度和执行结果。', + appExchangeTitle1: '选择源应用', + appExchangeContent1: '查看源节点已安装的应用,选择需要迁移的应用。', + appExchangeTitle2: '确认资源依赖', + appExchangeContent2: '迁移前确认目标节点及应用所需的数据库等关联资源。', + appExchangeTitle3: '执行应用迁移', + appExchangeContent3: '将应用备份传输到目标节点进行恢复,并通过任务日志查看结果。', + sslSyncTitle1: '选择源证书', + sslSyncContent1: '查看源节点的证书信息,选择需要同步的证书。', + sslSyncTitle2: '多节点证书同步', + sslSyncContent2: '将选中的证书同步到目标节点,自动排除源节点。', + sslSyncTitle3: '确认同步任务', + sslSyncContent3: '执行前确认目标节点和证书,通过任务日志查看同步结果。', + phpExtensionsSyncTitle1: '选择扩展模版', + phpExtensionsSyncContent1: '查看源节点的模版名称和扩展列表,选择需要同步的模版。', + phpExtensionsSyncTitle2: '多节点模版同步', + phpExtensionsSyncContent2: '将选中的扩展模版同步到目标节点,自动排除源节点。', + phpExtensionsSyncTitle3: '同名模版检查', + phpExtensionsSyncContent3: '同名且内容一致的模版会跳过;内容不同则提示冲突,不会覆盖。', fileExchangeTitle1: '密钥认证传输', fileExchangeContent1: '通过 SSH 密钥进行身份验证,确保传输的安全性。', fileExchangeTitle2: '高效文件同步', @@ -7080,6 +7108,12 @@ const message = { imageBatchConfirmPrefix: '即将把 {0} 张镜像转发到 {1} 个节点,共 {2} 个任务。', ssl: '证书同步', + phpExtensions: 'PHP 扩展模版同步', + phpExtensionsTitle: '扩展模版同步', + phpExtensionsDesc: '选择源节点后,可将指定 PHP 扩展模版同步到目标节点。', + phpExtensionsList: '扩展列表', + phpExtensionsConfirm: '即将把 {0} 个 PHP 扩展模版同步到 {1} 个目标节点。', + phpExtensionsConflictHint: '同名且内容一致的模版将跳过;同名但内容不同的模版将提示冲突,不会覆盖。', sslBatchDesc: '选择源节点后,可将指定证书同步到当前面板环境。', sslBatchConfirmPrefix: '即将把 {0} 张证书同步到 {1} 个节点,共 {2} 个任务。',