feat(i18n): improve Lao (lo) language support (#13313)

This commit is contained in:
2026-07-20 18:38:42 +08:00
committed by GitHub
parent e8f35e4e06
commit 092b57413b
30 changed files with 3333 additions and 2341 deletions

View File

@@ -34,6 +34,7 @@
<a href="/docs/README.ru.md"><img alt="Русский" src="https://img.shields.io/badge/Русский-d9d9d9"></a> <a href="/docs/README.ru.md"><img alt="Русский" src="https://img.shields.io/badge/Русский-d9d9d9"></a>
<a href="/docs/README.ms.md"><img alt="Bahasa Melayu" src="https://img.shields.io/badge/Bahasa Melayu-d9d9d9"></a> <a href="/docs/README.ms.md"><img alt="Bahasa Melayu" src="https://img.shields.io/badge/Bahasa Melayu-d9d9d9"></a>
<a href="/docs/README.fa.md"><img alt="Persian" src="https://img.shields.io/badge/%D9%81%D8%A7%D8%B1%D8%B3%DB%8C-d9d9d9"></a> <a href="/docs/README.fa.md"><img alt="Persian" src="https://img.shields.io/badge/%D9%81%D8%A7%D8%B1%D8%B3%DB%8C-d9d9d9"></a>
<a href="/docs/README.lo.md"><img alt="ພາສາລາວ" src="https://img.shields.io/badge/%E0%BA%9E%E0%BA%B2%E0%BA%AA%E0%BA%B2%E0%BA%A5%E0%BA%B2%E0%BA%A7-d9d9d9"></a>
</p> </p>
--- ---

View File

@@ -2,6 +2,7 @@ package dto
import ( import (
"context" "context"
"github.com/1Panel-dev/1Panel/agent/app/model" "github.com/1Panel-dev/1Panel/agent/app/model"
"github.com/1Panel-dev/1Panel/agent/app/task" "github.com/1Panel-dev/1Panel/agent/app/task"
) )
@@ -133,6 +134,7 @@ type Locale struct {
Tr string `json:"tr"` Tr string `json:"tr"`
Es string `json:"es-es" yaml:"es-es"` Es string `json:"es-es" yaml:"es-es"`
Fa string `json:"fa"` Fa string `json:"fa"`
Lo string `json:"lo"`
} }
type AppForm struct { type AppForm struct {

View File

@@ -1,4 +1,6 @@
ErrInvalidParams: 'ຄຳຮ້ອງຂໍບໍ່ຖືກຕ້ອງ: {{ .detail }}' ErrInvalidParams: 'ຄຳຮ້ອງຂໍບໍ່ຖືກຕ້ອງ: {{ .detail }}'
ErrMcpGatewayArgsParse: 'ຮູບແບບອາກິວເມັນ MCP ກຳນົດເອງບໍ່ຖືກຕ້ອງ'
ErrMcpGatewayArgsConflict: 'ອາກິວເມັນ {{ .name }} ຖືກຈັດການໂດຍ 1Panel ແລະ ບໍ່ສາມາດຕັ້ງຄ່າໃນອາກິວເມັນກຳນົດເອງໄດ້'
ErrTokenParse: 'ໂທເຄັນຜິດພາດ: {{ .detail }}' ErrTokenParse: 'ໂທເຄັນຜິດພາດ: {{ .detail }}'
ErrInitialPassword: 'ລະຫັດຜ່ານເດີມບໍ່ຖືກຕ້ອງ' ErrInitialPassword: 'ລະຫັດຜ່ານເດີມບໍ່ຖືກຕ້ອງ'
ErrInternalServer: 'ລະບົບພາຍໃນຜິດພາດ: {{ .detail }}' ErrInternalServer: 'ລະບົບພາຍໃນຜິດພາດ: {{ .detail }}'
@@ -10,6 +12,11 @@ ErrWgetProxyNotConfigured: 'ກະລຸນາກຳນົດຄ່າເຊີ
ErrWgetProxyInvalid: 'ທີ່ຢູ່ເຊີເວີພຣັອກຊີບໍ່ຖືກຕ້ອງ: {{ .detail }}' ErrWgetProxyInvalid: 'ທີ່ຢູ່ເຊີເວີພຣັອກຊີບໍ່ຖືກຕ້ອງ: {{ .detail }}'
ErrRecordExist: 'ຂໍ້ມູນນີ້ມີຢູ່ໃນລະບົບແລ້ວ' ErrRecordExist: 'ຂໍ້ມູນນີ້ມີຢູ່ໃນລະບົບແລ້ວ'
ErrRecordNotFound: 'ບໍ່ພົບຂໍ້ມູນ' ErrRecordNotFound: 'ບໍ່ພົບຂໍ້ມູນ'
WafLogExport: 'ສົ່ງອອກລັອກ WAF'
MonitorLogExport: 'ສົ່ງອອກລັອກການຕິດຕາມເວັບໄຊ'
LogExportNoData: 'ບໍ່ມີລັອກທີ່ກົງກັບເງື່ອນໄຂການກັ່ນຕອງ'
LogExportDiskSpace: 'ພື້ນທີ່ດິສກ໌ທີ່ໃຊ້ໄດ້ໜ້ອຍກວ່າ 1 GiB; ການສົ່ງອອກຖືກຢຸດແລ້ວ'
LogExportRetentionInvalid: 'ໄລຍະເກັບບັນທຶກການສົ່ງອອກຕ້ອງຢູ່ລະຫວ່າງ 1 ຫາ 30 ມື້'
ErrStructTransform: 'ການແປງປະເພດຂໍ້ມູນລົ້ມເຫຼວ: {{ .err }}' ErrStructTransform: 'ການແປງປະເພດຂໍ້ມູນລົ້ມເຫຼວ: {{ .err }}'
ErrNotLogin: 'ຍັງບໍ່ໄດ້ເຂົ້າສູ່ລະບົບ: {{ .detail }}' ErrNotLogin: 'ຍັງບໍ່ໄດ້ເຂົ້າສູ່ລະບົບ: {{ .detail }}'
ErrPasswordExpired: 'ລະຫັດຜ່ານໝົດອາຍຸ: {{ .detail }}' ErrPasswordExpired: 'ລະຫັດຜ່ານໝົດອາຍຸ: {{ .detail }}'
@@ -48,6 +55,7 @@ Decrypt: "ຖອດລະຫັດ"
#agent #agent
ErrAgentAccountBound: 'ບັນຊີຖືກຜູກມັດກັບຕົວແທນ (Agent) ແລະບໍ່ສາມາດລຶບໄດ້' ErrAgentAccountBound: 'ບັນຊີຖືກຜູກມັດກັບຕົວແທນ (Agent) ແລະບໍ່ສາມາດລຶບໄດ້'
ErrTerminalAIAccountInUse: 'ບັນຊີໂມເດລນີ້ກຳລັງຖືກໃຊ້ໂດຍ Terminal AI. ກະລຸນາປ່ຽນບັນຊີໃນການຕັ້ງຄ່າ Terminal AI ຫຼື ປິດໃຊ້ງານ Terminal AI ແລ້ວລອງໃໝ່.' ErrTerminalAIAccountInUse: 'ບັນຊີໂມເດລນີ້ກຳລັງຖືກໃຊ້ໂດຍ Terminal AI. ກະລຸນາປ່ຽນບັນຊີໃນການຕັ້ງຄ່າ Terminal AI ຫຼື ປິດໃຊ້ງານ Terminal AI ແລ້ວລອງໃໝ່.'
ErrFileAIAccountInUse: 'ບັນຊີໂມເດລນີ້ກຳລັງຖືກໃຊ້ໂດຍ AI ຈັດການໄຟລ໌. ກະລຸນາປ່ຽນບັນຊີໃນການຕັ້ງຄ່າ AI ຈັດການໄຟລ໌ ຫຼື ປິດໃຊ້ງານແລ້ວລອງໃໝ່.'
ErrAgentAccountUnavailable: 'ການເຊື່ອມຕໍ່ບັນຊີບໍ່ສາມາດໃຊ້ງານໄດ້: {{ .err }}' ErrAgentAccountUnavailable: 'ການເຊື່ອມຕໍ່ບັນຊີບໍ່ສາມາດໃຊ້ງານໄດ້: {{ .err }}'
ErrAgentProviderNotSupported: 'ບໍ່ຮອງຮັບຜູ້ໃຫ້ບໍລິການຕົວແທນນີ້' ErrAgentProviderNotSupported: 'ບໍ່ຮອງຮັບຜູ້ໃຫ້ບໍລິການຕົວແທນນີ້'
ErrAgentAccountRequired: 'ກະລຸນາເລືອກບັນຊີຕົວແທນກ່ອນ' ErrAgentAccountRequired: 'ກະລຸນາເລືອກບັນຊີຕົວແທນກ່ອນ'
@@ -55,6 +63,7 @@ ErrAgentAccountNotVerified: 'ບັນຊີຕົວແທນຍັງບໍ່
ErrAgentAccountModelsRequired: 'ກະລຸນາກຳນົດຄ່າໂມເດລຢ່າງໜ້ອຍໜຶ່ງຕົວ' ErrAgentAccountModelsRequired: 'ກະລຸນາກຳນົດຄ່າໂມເດລຢ່າງໜ້ອຍໜຶ່ງຕົວ'
ErrAgentAccountSingleInitialModel: 'ສາມາດກຳນົດຄ່າໂມເດລເລີ່ມຕົ້ນໄດ້ພຽງຕົວດຽວໃນລະຫວ່າງການສ້າງບັນຊີ' ErrAgentAccountSingleInitialModel: 'ສາມາດກຳນົດຄ່າໂມເດລເລີ່ມຕົ້ນໄດ້ພຽງຕົວດຽວໃນລະຫວ່າງການສ້າງບັນຊີ'
ErrAgentModelNotInAccount: 'ໂມເດລບໍ່ໄດ້ຖືກກຳນົດຄ່າໃນບັນຊີທີ່ເລືອກ' ErrAgentModelNotInAccount: 'ໂມເດລບໍ່ໄດ້ຖືກກຳນົດຄ່າໃນບັນຊີທີ່ເລືອກ'
ErrAgentVerifyModelInUse: 'ໂມເດລນີ້ຖືກໃຊ້ສຳລັບກວດສອບບັນຊີ. ກະລຸນາເລືອກໂມເດລກວດສອບອື່ນກ່ອນລຶບ.'
ErrAgentFallbackModelDuplicate: 'ໂມເດລສຳຮອງ (Fallback) ບໍ່ສາມາດຊ້ຳກັນໄດ້' ErrAgentFallbackModelDuplicate: 'ໂມເດລສຳຮອງ (Fallback) ບໍ່ສາມາດຊ້ຳກັນໄດ້'
ErrAgentFallbackModelPrimary: 'ໂມເດລສຳຮອງບໍ່ສາມາດຄືກັນກັບໂມເດລຫຼັກ' ErrAgentFallbackModelPrimary: 'ໂມເດລສຳຮອງບໍ່ສາມາດຄືກັນກັບໂມເດລຫຼັກ'
ErrAgentModelInUse: 'ຕົວແທນທີ່ຜູກມັດກຳລັງໃຊ້ໂມເດລນີ້ຢູ່: {{ .name }}' ErrAgentModelInUse: 'ຕົວແທນທີ່ຜູກມັດກຳລັງໃຊ້ໂມເດລນີ້ຢູ່: {{ .name }}'
@@ -362,6 +371,9 @@ ErrParseIP: 'ຮູບແບບ IP ບໍ່ຖືກຕ້ອງ'
ErrDefaultIP: 'ຊື່ default ຖືກສະຫງວນໄວ້; ກະລຸນາໃຊ້ຊື່ອື່ນ' ErrDefaultIP: 'ຊື່ default ຖືກສະຫງວນໄວ້; ກະລຸນາໃຊ້ຊື່ອື່ນ'
ErrGroupInUse: 'ກຸ່ມ IP ກຳລັງຖືກໃຊ້ງານໂດຍກົດລະບຽບ Blacklist/Whitelist' ErrGroupInUse: 'ກຸ່ມ IP ກຳລັງຖືກໃຊ້ງານໂດຍກົດລະບຽບ Blacklist/Whitelist'
ErrIPGroupAclUse: 'ກຸ່ມ IP ກຳລັງຖືກໃຊ້ງານໂດຍກົດລະບຽບປັບແຕ່ງເອງຂອງເວັບໄຊ {{ .name }}' ErrIPGroupAclUse: 'ກຸ່ມ IP ກຳລັງຖືກໃຊ້ງານໂດຍກົດລະບຽບປັບແຕ່ງເອງຂອງເວັບໄຊ {{ .name }}'
ErrIPGroupOriginProtectionUse: 'ກຸ່ມ IP ຖືກໃຊ້ໂດຍການປ້ອງກັນ CDN Origin ຂອງເວັບໄຊ {{ .name }}'
ErrOriginProtectionIPGroupRequired: 'ກະລຸນາເລືອກຢ່າງໜ້ອຍໜຶ່ງກຸ່ມ IP ທີ່ບໍ່ຫວ່າງກ່ອນເປີດການປ້ອງກັນ Origin'
ErrOriginProtectionIPGroupInvalid: 'ກຸ່ມ IP {{ .name }} ບໍ່ມີຢູ່ ຫຼື ຫວ່າງເປົ່າ'
ErrGroupExist: 'ຊື່ກຸ່ມ IP ມີຢູ່ໃນລະບົບແລ້ວ' ErrGroupExist: 'ຊື່ກຸ່ມ IP ມີຢູ່ໃນລະບົບແລ້ວ'
ErrIPRange: 'ຊ່ວງ IP ບໍ່ຖືກຕ້ອງ' ErrIPRange: 'ຊ່ວງ IP ບໍ່ຖືກຕ້ອງ'
ErrIPExist: 'IP ມີຢູ່ໃນລະບົບແລ້ວ' ErrIPExist: 'IP ມີຢູ່ໃນລະບົບແລ້ວ'

View File

@@ -23,7 +23,7 @@ type Login struct {
Password string `json:"password" validate:"required"` Password string `json:"password" validate:"required"`
Captcha string `json:"captcha"` Captcha string `json:"captcha"`
CaptchaID string `json:"captchaID"` CaptchaID string `json:"captchaID"`
Language string `json:"language" validate:"required,oneof=zh en 'zh-Hant' ko ja ru ms 'pt-BR' tr 'es-ES' fa"` Language string `json:"language" validate:"required,oneof=zh en 'zh-Hant' ko ja ru ms 'pt-BR' tr 'es-ES' fa lo"`
} }
type SystemSetting struct { type SystemSetting struct {

View File

@@ -29,6 +29,7 @@ var langFiles = map[string]string{
"tr": "lang/tr.yaml", "tr": "lang/tr.yaml",
"es-ES": "lang/es-ES.yaml", "es-ES": "lang/es-ES.yaml",
"fa": "lang/fa.yaml", "fa": "lang/fa.yaml",
"lo": "lang/lo.yaml",
} }
func GetMsgWithMap(key string, maps map[string]interface{}) string { func GetMsgWithMap(key string, maps map[string]interface{}) string {

409
core/i18n/lang/lo.yaml Normal file
View File

@@ -0,0 +1,409 @@
# base errors
ErrInvalidParams: "ພາລາມິເຕີຄຳຮ້ອງຂໍບໍ່ຖືກຕ້ອງ: {{ .detail }}"
ErrTokenParse: "ເກີດຂໍ້ຜິດພາດໃນການສ້າງໂທເຄັນ: {{ .detail }}"
ErrInitialPassword: "ລະຫັດຜ່ານເລີ່ມຕົ້ນບໍ່ຖືກຕ້ອງ"
ErrInternalServer: "ຂໍ້ຜິດພາດພາຍໃນເຊີບເວີ: {{ .detail }}"
ErrInternalServerKey: "ຂໍ້ຜິດພາດພາຍໃນເຊີບເວີ:"
ErrRecordExist: "ມີບັນທຶກນີ້ຢູ່ແລ້ວ"
ErrRecordNotFound: "ບໍ່ພົບບັນທຶກ"
ErrStructTransform: "ການແປງຊະນິດຂໍ້ມູນລົ້ມເຫຼວ: {{ .detail }}"
ErrNotSupportType: "ບໍ່ຮອງຮັບຊະນິດ: {{ .name }}"
ErrDemoEnvironment: "ນີ້ແມ່ນເຊີບເວີສາທິດ, ຫ້າມດຳເນີນການນີ້!"
ErrCmdTimeout: "ການປະຕິບັດຄຳສັ່ງໝົດເວລາ!"
ErrPortInUsed: "ພອດ {{ .name }} ກຳລັງຖືກໃຊ້ງານຢູ່!"
ErrFileNotFound: "ບໍ່ມີໄຟລ໌ {{ .name }}"
ErrReqFailed: "ຄຳຮ້ອງຂໍ {{.name}} ລົ້ມເຫຼວ: {{ .err }}"
# request and entrance
ErrNoSuchHost: "ການແປງຊື່ໂຮສລົ້ມເຫຼວ: {{ .err }}"
ErrHttpReqNotFound: "ບໍ່ພົບຊັບພະຍາກອນທີ່ຮ້ອງຂໍ: {{ .err }}"
ErrHttpReqFailed: "ຄຳຮ້ອງຂໍລົ້ມເຫຼວ {{ .err }}"
ErrHttpReqTimeOut: "ຄຳຮ້ອງຂໍໝົດເວລາ {{ .err }}"
ErrCreateHttpClient: "ສ້າງຄຳຮ້ອງຂໍບໍ່ສຳເລັດ {{ .err }}"
ErrProxy: "ຄຳຮ້ອງຂໍລົ້ມເຫຼວ; ກະລຸນາກວດສອບສະຖານະຂອງໂນດນີ້: {{ .detail }}"
ErrProxySetting: "ບໍ່ມີຂໍ້ມູນເຊີບເວີພຣັອກຊີ {{ .err }}, ກະລຸນາກວດສອບແລ້ວລອງໃໝ່!"
ErrEntrance: "ຂໍ້ມູນທາງເຂົ້າຄວາມປອດໄພຜິດພາດ, ກະລຸນາກວດສອບແລ້ວລອງໃໝ່!"
ErrEntranceFormat: "ບໍ່ຮອງຮັບທາງເຂົ້າຄວາມປອດໄພ {{ .name }}. ກະລຸນາກວດສອບແລ້ວລອງໃໝ່."
# login and security
ErrNotLogin: "ຜູ້ໃຊ້ຍັງບໍ່ໄດ້ເຂົ້າລະບົບ: {{ .detail }}"
ErrSessionDataNotFound: "ເຊດຊັນໝົດອາຍຸແລ້ວ"
ErrSessionDataFormat: "ຮູບແບບຂໍ້ມູນເຊດຊັນບໍ່ຖືກຕ້ອງ"
ErrPasswordExpired: "ລະຫັດຜ່ານໝົດອາຍຸແລ້ວ: {{ .detail }}"
ErrLoginLocked: "ພະຍາຍາມລົ້ມເຫຼວຫຼາຍຄັ້ງເກີນໄປ. ການເຂົ້າລະບົບຖືກລັອກຊົ່ວຄາວ 5 ນາທີ."
ErrApiConfigStatusInvalid: "ການເຂົ້າເຖິງ API ຖືກປິດໃຊ້ງານ: {{ .detail }}"
ErrApiConfigKeyInvalid: "ຄີ API ບໍ່ຖືກຕ້ອງ: {{ .detail }}"
ErrApiConfigIPInvalid: "IP ຂອງຄຳຮ້ອງຂໍ API ບໍ່ຢູ່ໃນລາຍຊື່ອະນຸຍາດ: {{ .detail }}"
ErrApiConfigDisable: "ອິນເຕີເຟດນີ້ຫ້າມການເອີ້ນໃຊ້ API: {{ .detail }}"
ErrApiConfigKeyTimeInvalid: "ເວລາປະທັບ API ບໍ່ຖືກຕ້ອງ: {{ .detail }}"
ErrPasskeyDisabled: "Passkey ຕ້ອງເປີດໃຊ້ງານ HTTPS"
ErrPasskeyNotConfigured: "ຍັງບໍ່ໄດ້ຕັ້ງຄ່າ Passkey"
ErrPasskeyLimit: "ຈຳນວນ Passkey ຮອດຂີດຈຳກັດແລ້ວ (ສູງສຸດ 5)"
ErrPasskeySession: "ເຊດຊັນ Passkey ໝົດອາຍຸ ຫຼື ບໍ່ຖືກຕ້ອງ"
ErrPasskeyDuplicate: "ມີ Passkey ນີ້ຢູ່ແລ້ວ"
ErrPasskeyVerify: "ການຢືນຢັນ Passkey ລົ້ມເຫຼວ"
# user and permission
ErrNoSuchUser: "ບໍ່ພົບຂໍ້ມູນຜູ້ໃຊ້, ກະລຸນາກວດສອບແລ້ວລອງໃໝ່!"
ErrToMaster: "ຜູ້ໃຊ້ນີ້ບໍ່ມີສິດດຳເນີນການນີ້ໃນໂນດຫຼັກ. ກະລຸນາກວດສອບແລ້ວລອງໃໝ່!"
ErrToNode: "ຜູ້ໃຊ້ນີ້ບໍ່ມີສິດດຳເນີນການນີ້ໃນໂນດນີ້. ກະລຸນາກວດສອບແລ້ວລອງໃໝ່!"
ErrRBAC: "ສິດຂອງຜູ້ໃຊ້ບໍ່ພຽງພໍ. ບໍ່ສາມາດດຳເນີນການນີ້ໄດ້. ກະລຸນາກວດສອບແລ້ວລອງໃໝ່!"
ErrNoneNode: "ຜູ້ໃຊ້ນີ້ບໍ່ມີສິດໃຊ້ງານໂນດ. ກະລຸນາຕິດຕໍ່ຜູ້ບໍລິຫານ ຫຼື ກວດສອບແລ້ວລອງໃໝ່!"
ErrOnlySuperAdmin: "ມີພຽງຜູ້ບໍລິຫານສູງສຸດເທົ່ານັ້ນທີ່ໃຊ້ຟັງຊັນນີ້ໄດ້!"
ErrRolePresetCannotDelete: "ບໍ່ສາມາດລຶບບົດບາດທີ່ລະບົບກຳນົດໄວ້ລ່ວງໜ້າ"
ErrRolePresetCannotUpdate: "ບໍ່ສາມາດອັບເດດບົດບາດທີ່ລະບົບກຳນົດໄວ້ລ່ວງໜ້າ"
ErrRoleBoundToUser: "ບົດບາດນີ້ຖືກຜູກກັບຜູ້ໃຊ້ແລ້ວ ແລະ ບໍ່ສາມາດລຶບໄດ້"
ErrRolePresetCannotBind: "ບໍ່ສາມາດມອບໝາຍບົດບາດທີ່ລະບົບກຳນົດໄວ້ລ່ວງໜ້າໃຫ້ຜູ້ໃຊ້"
ErrNodeAdminMasterForbidden: "ບໍ່ສາມາດເພີ່ມສິດຜູ້ບໍລິຫານໂນດໃຫ້ກັບໂນດຫຼັກ"
ErrSuperAdminCannotDelete: "ບໍ່ສາມາດລຶບຜູ້ໃຊ້ທີ່ເປັນຜູ້ບໍລິຫານສູງສຸດ"
ErrGroupIsDefault: "ເປັນກຸ່ມເລີ່ມຕົ້ນ, ບໍ່ສາມາດລຶບໄດ້"
ErrGroupIsInUse: "ກຸ່ມນີ້ກຳລັງຖືກໃຊ້ງານ ແລະ ບໍ່ສາມາດລຶບໄດ້."
# license
LicenseCheck: 'ກວດສອບວ່າໃບອະນຸຍາດພ້ອມໃຊ້ງານຫຼືບໍ່'
ErrLicenseInUsed: 'ໃບອະນຸຍາດຖືກຜູກໄວ້ແລ້ວ. ກະລຸນາກວດສອບແລ້ວລອງໃໝ່!'
ErrLicenseExpired: 'ໃບອະນຸຍາດໝົດອາຍຸແລ້ວ. ກະລຸນາກວດສອບແລ້ວລອງໃໝ່!'
ErrLicense: "ຮູບແບບໃບອະນຸຍາດຜິດພາດ, ກະລຸນາກວດສອບແລ້ວລອງໃໝ່!"
ErrLicenseCheck: "ການກວດສອບໃບອະນຸຍາດລົ້ມເຫຼວ, ກະລຸນາກວດສອບແລ້ວລອງໃໝ່!"
ErrXpackVersion: "ການກວດສອບໃບອະນຸຍາດລົ້ມເຫຼວ, ໃບອະນຸຍາດນີ້ຈຳກັດເວີຊັນ ແລະ ບໍ່ສາມາດນຳເຂົ້າໄດ້, ກະລຸນາກວດສອບແລ້ວລອງໃໝ່!"
ErrLicenseSave: "ບັນທຶກຂໍ້ມູນໃບອະນຸຍາດບໍ່ສຳເລັດ, ຂໍ້ຜິດພາດ {{ .err }}, ກະລຸນາລອງໃໝ່!"
ErrLicenseSync: "ການຊິງໃບອະນຸຍາດລົ້ມເຫຼວ, ບໍ່ພົບຂໍ້ມູນໃບອະນຸຍາດໃນຖານຂໍ້ມູນ!"
ErrLicenseExist: "ມີບັນທຶກໃບອະນຸຍາດນີ້ຢູ່ແລ້ວ. ທ່ານສາມາດໄປທີ່ໜ້າໃບອະນຸຍາດເພື່ອຜູກໂນດໄດ້ໂດຍກົງ."
ErrXpackNotFound: "ສ່ວນນີ້ຕ້ອງໃຊ້ຮຸ່ນທຸລະກິດ. ກະລຸນານຳເຂົ້າໃບອະນຸຍາດໃນ ການຕັ້ງຄ່າແຜງ > ໃບອະນຸຍາດ."
ErrXpackExceptional: "ສ່ວນນີ້ຕ້ອງໃຊ້ຮຸ່ນທຸລະກິດ. ກະລຸນາຊິງສະຖານະໃບອະນຸຍາດໃນ ການຕັ້ງຄ່າແຜງ > ໃບອະນຸຍາດ."
ErrXpackLost: "ການລອງໃບອະນຸຍາດໃໝ່ຮອດຂີດຈຳກັດແລ້ວ. ໄປທີ່ ການຕັ້ງຄ່າແຜງ > ໃບອະນຸຍາດ ແລະ ຊິງດ້ວຍຕົນເອງ."
ErrEnterpriseLicenseRequired: "ຍັງບໍ່ໄດ້ນຳເຂົ້າໃບອະນຸຍາດຮຸ່ນວິສາຫະກິດ. ກະລຸນານຳເຂົ້າໃບອະນຸຍາດກ່ອນ."
ErrDeviceLost: "ໄຟລ໌ທີ່ຈຳເປັນສຳລັບກວດສອບໃບອະນຸຍາດຫາຍໄປ, ກະລຸນາກວດສອບແລ້ວລອງໃໝ່!"
ErrDeviceErr: "ສະພາບແວດລ້ອມປັດຈຸບັນບໍ່ກົງກັບສະພາບແວດລ້ອມທີ່ນຳເຂົ້າໃບອະນຸຍາດ. ກະລຸນາແກ້ໄຂໃບອະນຸຍາດແລ້ວນຳເຂົ້າໃໝ່."
ErrXpackTimeout: "ຄຳຮ້ອງຂໍໝົດເວລາ, ການເຊື່ອມຕໍ່ເຄືອຂ່າຍອາດບໍ່ສະຖຽນ, ກະລຸນາລອງໃໝ່ພາຍຫຼັງ!"
ErrUnbindMaster: "ຍັງມີໂນດຢູ່ໃນການຈັດການໂນດ. ກະລຸນາລຶບໂນດກ່ອນ ແລ້ວຈຶ່ງຍົກເລີກການຜູກໃບອະນຸຍາດປັດຈຸບັນ."
ErrFreeNodeLimit: "ຈຳນວນໂນດທີ່ສາມາດເພີ່ມໄດ້ຮອດຂີດຈຳກັດແລ້ວ. ກະລຸນາຊື້ແລ້ວລອງໃໝ່."
ErrNodeBound: "ໃບອະນຸຍາດນີ້ຖືກຜູກກັບໂນດອື່ນແລ້ວ, ກະລຸນາກວດສອບແລ້ວລອງໃໝ່!"
ErrNodeBoundDelete: "ໃບອະນຸຍາດນີ້ຖືກຜູກແລ້ວ ແລະ ບໍ່ຮອງຮັບການລຶບ. ກະລຸນາກວດສອບແລ້ວລອງໃໝ່!"
ErrNodeBoundLimit: "ໂນດຟຣີປັດຈຸບັນຮອດຂີດຈຳກັດແລ້ວ, ກະລຸນາກວດສອບແລ້ວລອງໃໝ່!"
ErrLicenseFree: "ໂນດຟຣີຈະໃຊ້ງານໄດ້ເມື່ອໃບອະນຸຍາດຖືກຜູກກັບໂນດຢ່າງຖືກຕ້ອງເທົ່ານັ້ນ. ກະລຸນາກວດສອບແລ້ວລອງໃໝ່."
ErrLicenseUnbind: "ຍັງມີໂນດຮຸ່ນຊຸມຊົນທີ່ຜູກກັບໃບອະນຸຍາດນີ້. ກະລຸນາຍົກເລີກການຜູກໃນ ການຕັ້ງຄ່າແຜງ > ໃບອະນຸຍາດ ແລ້ວລອງໃໝ່."
ErrLicenseBindCount: "ຈຳນວນໂນດຟຣີຂອງໃບອະນຸຍາດໃໝ່ນ້ອຍກວ່າຈຳນວນໂນດຮຸ່ນຊຸມຊົນທີ່ຜູກຢູ່ປັດຈຸບັນ. ກະລຸນາກວດສອບແລ້ວລອງໃໝ່."
ErrNoSuchNode: "ບໍ່ພົບຂໍ້ມູນໂນດ, ກະລຸນາກວດສອບແລ້ວລອງໃໝ່!"
ErrNodeUnbind: "ໂນດນີ້ບໍ່ຢູ່ໃນຂອບເຂດການຜູກຂອງໃບອະນຸຍາດ, ກະລຸນາກວດສອບແລ້ວລອງໃໝ່!"
ErrNodeBind: "ໂນດນີ້ຖືກຜູກກັບໃບອະນຸຍາດແລ້ວ, ກະລຸນາກວດສອບແລ້ວລອງໃໝ່!"
ErrNodeLocalRollback: "ໂນດຫຼັກບໍ່ຮອງຮັບການຍ້ອນກັບໂດຍກົງ. ກະລຸນາໃຊ້ຄຳສັ່ງ '1pctl restore' ດ້ວຍຕົນເອງເພື່ອຍ້ອນກັບ."
ErrIntlLicense: "ເວີຊັນປັດຈຸບັນຍັງບໍ່ຮອງຮັບການນຳເຂົ້າໃບອະນຸຍາດສາກົນ. ກະລຸນາລໍຖ້າ!"
InvalidRequestBodyType: "ຮູບແບບເນື້ອຫາຄຳຮ້ອງຂໍບໍ່ຖືກຕ້ອງ. ກະລຸນາກວດວ່າເນື້ອຫາກົງກັບຮູບແບບທີ່ກຳນົດແລ້ວລອງໃໝ່."
InvalidLicenseCodeType: "ຮູບແບບລະຫັດໃບອະນຸຍາດທີ່ໃຫ້ມາບໍ່ຖືກຕ້ອງ, ກະລຸນາກວດສອບແລ້ວລອງໃໝ່!"
LicenseNotFoundType: "ບໍ່ພົບໃບອະນຸຍາດ, ບໍ່ມີບັນທຶກທີ່ກົງກັບໃບອະນຸຍາດທີ່ໃຫ້ມາໃນລະບົບ. ກະລຸນາກວດສອບແລ້ວລອງໃໝ່!"
LicenseRevokedType: "ໃບອະນຸຍາດທີ່ຮ້ອງຂໍຖືກຖອນແລ້ວ ແລະ ບໍ່ສາມາດໃຊ້ງານໄດ້ອີກ. ກະລຸນາກວດສອບແລ້ວລອງໃໝ່!"
LicenseExpiredType: "ໃບອະນຸຍາດໝົດອາຍຸແລ້ວ. ກະລຸນາຕໍ່ອາຍຸ ຫຼື ນຳເຂົ້າໃໝ່ໃນ ການຕັ້ງຄ່າແຜງ - ໃບອະນຸຍາດ ກ່ອນລອງໃໝ່."
LicenseProductMismatchType: "ໃບອະນຸຍາດບໍ່ກົງກັບຜະລິດຕະພັນ ຫຼື ບໍລິການທີ່ຮ້ອງຂໍ!"
InvalidAssigneeType: "ຂໍ້ມູນຜູ້ໃຊ້ ຫຼື ອຸປະກອນເປົ້າໝາຍສຳລັບການມອບໝາຍໃບອະນຸຍາດບໍ່ຖືກຕ້ອງ. ກະລຸນາກວດສອບແລ້ວລອງໃໝ່!"
LicenseUsageNotFoundType: "ບໍ່ພົບບັນທຶກການໃຊ້ງານ. ໃບອະນຸຍາດນີ້ຍັງບໍ່ໄດ້ເປີດໃຊ້ງານ ຫຼື ໃຊ້ງານເທື່ອ. ກະລຸນາກວດສອບແລ້ວລອງໃໝ່!"
LicenseUsageLimitExceededType: "ໃບອະນຸຍາດນີ້ຖືກຜູກກັບໂນດອື່ນແລ້ວ. ກະລຸນາກວດສອບແລ້ວລອງໃໝ່!"
# node and cluster
MasterNode: "ໂນດຫຼັກ"
Node: "ໂນດ"
ErrLocalDelete: "ບໍ່ສາມາດລຶບໂນດພາຍໃນເຄື່ອງໄດ້!"
ErrMasterDelete: "ບໍ່ສາມາດລຶບໂນດຫຼັກໄດ້. ກະລຸນາລຶບໂນດຍ່ອຍກ່ອນ."
ClusterNameIsExist: "ມີຊື່ຄລັສເຕີນີ້ຢູ່ແລ້ວ."
AppStatusUnHealthy: "ດຶງສະຖານະແອັບບໍ່ສຳເລັດ. ກະລຸນາກວດສອບສະຖານະໂນດທີ່ຕິດຕັ້ງໃນລາຍຊື່ໂນດ."
MasterNodePortNotAvailable: "ການກວດສອບການເຊື່ອມຕໍ່ຂອງໂນດ {{ .name }} ຜ່ານພອດ {{ .port }} ລົ້ມເຫຼວ. ກະລຸນາກວດສອບການຕັ້ງຄ່າໄຟຣ໌ວໍ/ກຸ່ມຄວາມປອດໄພ ແລະ ສະຖານະໂນດຫຼັກ."
ClusterMasterNotExist: "ໂນດຫຼັກຂອງຄລັສເຕີຖືກຕັດການເຊື່ອມຕໍ່. ກະລຸນາລຶບໂນດຍ່ອຍ."
# virtual machine
ErrVMNotFound: "ບໍ່ມີເຄື່ອງສະເໝືອນ"
ErrVMAlreadyExists: "ມີເຄື່ອງສະເໝືອນຢູ່ແລ້ວ"
ErrVMImageAlreadyExists: "ມີອິມເມຈເຄື່ອງສະເໝືອນຢູ່ແລ້ວ: {{ .detail }}"
ErrVMStoragePathInUse: "ເສັ້ນທາງພູນຈັດເກັບຖືກໃຊ້ໂດຍ [{{ .name }}] ແລ້ວ"
ErrVMHelperNotFound: "ບໍ່ພົບ 1panel-kvm"
ErrVMBridgeManaged: "ຊື່ບຣິດຈ໌ຖືກຈັດການໂດຍ libvirt ຫຼື Docker ແລ້ວ"
ErrVMNetworkInUse: "ເຄືອຂ່າຍກຳລັງຖືກໃຊ້ງານ ແລະ ບໍ່ສາມາດລຶບໄດ້"
ErrVMStorageInUse: "ພູນຈັດເກັບກຳລັງຖືກໃຊ້ງານ ແລະ ບໍ່ສາມາດລຶບໄດ້"
ErrVMStorageNameCannotChange: "ບໍ່ສາມາດປ່ຽນຊື່ພູນຈັດເກັບໄດ້"
ErrVMStoragePathCannotChange: "ບໍ່ສາມາດປ່ຽນເສັ້ນທາງພູນຈັດເກັບໄດ້"
ErrVMRunning: "ເຄື່ອງສະເໝືອນກຳລັງເຮັດວຽກ"
ErrVMLibvirtConnect: "ເຊື່ອມຕໍ່ກັບ libvirt ບໍ່ສຳເລັດ"
ErrVMPermission: "ບໍ່ມີສິດດຳເນີນການກັບເຄື່ອງສະເໝືອນ: {{ .detail }}"
ErrVMNetworkNotFound: "ບໍ່ມີເຄືອຂ່າຍເຄື່ອງສະເໝືອນ"
ErrVMInvalidPath: "ເສັ້ນທາງເຄື່ອງສະເໝືອນບໍ່ຖືກຕ້ອງ"
ErrVMInvalidInput: "ພາລາມິເຕີເຄື່ອງສະເໝືອນບໍ່ຖືກຕ້ອງ"
ErrVMCommandFailed: "ຄຳສັ່ງເຄື່ອງສະເໝືອນລົ້ມເຫຼວ: {{ .err }}"
VMCreateTask: "ສ້າງເຄື່ອງສະເໝືອນ [{{ .name }}]"
VMCreateFromTemplateTask: "ສ້າງເຄື່ອງສະເໝືອນ [{{ .name }}] ຈາກແມ່ແບບ"
VMUpdateTask: "ອັບເດດເຄື່ອງສະເໝືອນ [{{ .name }}]"
VMRenameTask: "ປ່ຽນຊື່ເຄື່ອງສະເໝືອນ [{{ .name }}] ເປັນ [{{ .newName }}]"
VMDeleteTask: "ລຶບເຄື່ອງສະເໝືອນ [{{ .name }}]"
VMTemplateCreateTask: "ບັນທຶກເຄື່ອງສະເໝືອນ [{{ .name }}] ເປັນແມ່ແບບ [{{ .template }}]"
VMTemplateDeleteTask: "ລຶບແມ່ແບບເຄື່ອງສະເໝືອນ [{{ .name }}]"
VMForceDeleteMetadataOnly: "ບໍ່ພົບ 1panel-kvm, ຈະບັງຄັບລຶບສະເພາະເມຕາດາຕາຂອງເຄື່ອງສະເໝືອນ [{{ .name }}]"
VMForceDeleteMetadataAfterLibvirtFailed: "ລຶບເຄື່ອງສະເໝືອນ [{{ .name }}] ຈາກ libvirt ບໍ່ສຳເລັດ, ຈະບັງຄັບລຶບເມຕາດາຕາ: {{ .err }}"
VMForceDeleteDiskFailed: "ບັງຄັບລຶບໄຟລ໌ດິສກ໌ເຄື່ອງສະເໝືອນ [{{ .path }}] ບໍ່ສຳເລັດ: {{ .err }}"
VMForceDeleteDiskSuccess: "ບັງຄັບລຶບໄຟລ໌ດິສກ໌ເຄື່ອງສະເໝືອນ [{{ .path }}] ສຳເລັດແລ້ວ"
VMSnapshotCreateTask: "ສ້າງສະແນັບຊັອດ [{{ .snapshot }}] ໃຫ້ເຄື່ອງສະເໝືອນ [{{ .vm }}]"
VMSnapshotCreateStep: "ສ້າງສະແນັບຊັອດເຄື່ອງສະເໝືອນ [{{ .snapshot }}]"
VMSnapshotRecoverTask: "ກູ້ຄືນສະແນັບຊັອດ [{{ .snapshot }}] ໃຫ້ເຄື່ອງສະເໝືອນ [{{ .vm }}]"
VMSnapshotRecoverStep: "ກູ້ຄືນສະແນັບຊັອດເຄື່ອງສະເໝືອນ [{{ .snapshot }}]"
VMSnapshotDeleteTask: "ລຶບສະແນັບຊັອດ [{{ .snapshot }}] ຂອງເຄື່ອງສະເໝືອນ [{{ .vm }}]"
VMSnapshotDeleteStep: "ລຶບສະແນັບຊັອດເຄື່ອງສະເໝືອນ [{{ .snapshot }}]"
# app
CustomAppStoreFileValid: "ແພັກເກດຮ້ານຄ້າແອັບຕ້ອງເປັນຮູບແບບ .tar.gz"
AppBackup: 'ສຳຮອງແອັບ'
AppBackupPush: 'ໂອນໄຟລ໌ສຳຮອງແອັບ {{.file}} ໄປຫາໂນດ {{ .name }}'
ErrSourceTargetSame: 'ໂນດຕົ້ນທາງ ແລະ ໂນດປາຍທາງຈະເປັນໂນດດຽວກັນບໍ່ໄດ້!'
AppInstall: 'ຕິດຕັ້ງແອັບ {{ .name }} ໃນໂນດ {{ .targetNode }}'
AppInstallCheck: 'ກວດສອບສະພາບແວດລ້ອມສຳລັບຕິດຕັ້ງແອັບ'
# backup
ErrBackupInUsed: "ບັນຊີສຳຮອງນີ້ຖືກໃຊ້ໃນວຽກຕາມກຳນົດເວລາ ແລະ ບໍ່ສາມາດລຶບໄດ້"
ErrBackupCheck: "ການທົດສອບການເຊື່ອມຕໍ່ບັນຊີສຳຮອງລົ້ມເຫຼວ {{ .err }}"
ErrBackupLocal: "ບັນຊີສຳຮອງເຊີບເວີພາຍໃນເຄື່ອງບໍ່ຮອງຮັບການດຳເນີນການນີ້!"
ErrBackupPublic: "ກວດພົບວ່າບັນຊີສຳຮອງນີ້ບໍ່ແມ່ນບັນຊີສາທາລະນະ, ກະລຸນາກວດສອບແລ້ວລອງໃໝ່!"
ErrOSSConn: "ບໍ່ສາມາດຮັບເວີຊັນລ່າສຸດໄດ້. ກະລຸນາກວດສອບການເຊື່ອມຕໍ່ອິນເຕີເນັດຂອງເຊີບເວີ."
MvBackup: "ຍ້າຍຂໍ້ມູນໄປຫາໄດເຣັກທໍຣີສຳຮອງ"
# alert
ErrAlertSync: "ການຊິງຂໍ້ມູນແຈ້ງເຕືອນຜິດພາດ, ກະລຸນາກວດສອບແລ້ວລອງໃໝ່!"
# AI gateway
ErrAIProxyUserGroupIsDefault: "ບໍ່ສາມາດລຶບກຸ່ມຜູ້ໃຊ້ເລີ່ມຕົ້ນໄດ້."
ErrAIProxyUserGroupInUse: "ກຸ່ມຜູ້ໃຊ້ກຳລັງຖືກໃຊ້ງານ ແລະ ບໍ່ສາມາດລຶບໄດ້."
ErrAIProxyUserGroupExists: "ມີຊື່ກຸ່ມຜູ້ໃຊ້ນີ້ຢູ່ແລ້ວ."
ErrAIProxyBackendAccountExists: "ບັນຊີໂມເດວນີ້ຖືກນຳເຂົ້າໃນພູນບັນຊີ AI Gateway ແລ້ວ."
ErrAIProxyModelGroupInUse: "ກຸ່ມໂມເດວກຳລັງຖືກໃຊ້ງານ ແລະ ບໍ່ສາມາດລຶບໄດ້."
ErrAIProxyModelGroupExists: "ມີຊື່ກຸ່ມໂມເດວນີ້ຢູ່ແລ້ວ."
ErrAIProxySensitiveGroupInUse: "ກຸ່ມຄຳທີ່ລະອຽດອ່ອນກຳລັງຖືກໃຊ້ງານ ແລະ ບໍ່ສາມາດລຶບໄດ້."
ErrAIProxySensitiveGroupExists: "ມີຊື່ກຸ່ມຄຳທີ່ລະອຽດອ່ອນນີ້ຢູ່ແລ້ວ."
AIBenchmarkRun: "ດຳເນີນການທົດສອບປະສິດທິພາບ AI"
# task
TaskStart: "ວຽກ {{ .name }} ເລີ່ມແລ້ວ [START]"
TaskEnd: "ວຽກ {{ .name }} ສິ້ນສຸດແລ້ວ [COMPLETED]"
TaskFailed: "ວຽກ {{ .name }} ລົ້ມເຫຼວ"
TaskTimeout: "ວຽກ {{ .name }} ໝົດເວລາ"
TaskSuccess: "ວຽກ {{ .name }} ສຳເລັດ"
TaskRetry: "ລອງວຽກ {{ .name }} ໃໝ່"
SubTaskSuccess: "{{ .name }} ສຳເລັດ"
SubTaskFailed: "{{ .name }} ລົ້ມເຫຼວ: {{ .err }}"
TaskInstall: "ຕິດຕັ້ງ"
TaskUpgrade: "ອັບເກຣດ"
TaskSync: 'ຊິງຂໍ້ມູນ'
TaskSyncForNode: "ຊິງຂໍ້ມູນໂນດ"
TaskBackup: "ສຳຮອງ"
TaskPush: "ສົ່ງ"
TaskRsync: "ຊິງຂໍ້ມູນ"
SuccessStatus: "{{ .name }} ສຳເລັດ"
FailedStatus: "{{ .name }} ລົ້ມເຫຼວ {{ .err }}"
Start: "ເລີ່ມ"
SubTask: "ວຽກຍ່ອຍ"
Skip: "ບໍ່ສົນໃຈຂໍ້ຜິດພາດ ແລະ ສືບຕໍ່"
Success: "ສຳເລັດ"
# agent batch task
BatchInstallAgent: "ຕິດຕັ້ງເອເຈນແບບກຸ່ມ"
DispatchAgentInstallTasks: "ຈັດສົ່ງວຽກຕິດຕັ້ງເອເຈນ"
BatchUpgradeAgent: "ອັບເກຣດເອເຈນແບບກຸ່ມ"
DispatchAgentUpgradeTasks: "ຈັດສົ່ງວຽກອັບເກຣດເອເຈນ"
BatchAgentInstallDispatchFailed: "ໂນດ {{ .node }} ຈັດສົ່ງວຽກຕິດຕັ້ງ {{ .agentType }} ບໍ່ສຳເລັດ ຂໍ້ຄວາມ: {{ .err }}"
BatchAgentInstallSubmitted: "ໂນດ {{ .node }} ຈັດສົ່ງວຽກຕິດຕັ້ງ {{ .agentType }} ສຳເລັດແລ້ວ!"
BatchAgentUpgradeDispatchFailed: "ໂນດ {{ .node }} ຈັດສົ່ງວຽກອັບເກຣດ {{ .agentType }} ບໍ່ສຳເລັດ ຂໍ້ຄວາມ: {{ .err }}"
BatchAgentUpgradeAlreadyLatest: "ໂນດ {{ .node }} ມີເອເຈນ {{ .agent }} ຢູ່ທີ່ເວີຊັນເປົ້າໝາຍແລ້ວ, ຂ້າມ"
BatchAgentUpgradeSubmitted: "ໂນດ {{ .node }} ຈັດສົ່ງວຽກອັບເກຣດ {{ .agent }} ສຳເລັດແລ້ວ!"
BatchAgentUpgradeFailed: "ໂນດ {{ .node }} ຈັດສົ່ງວຽກອັບເກຣດ {{ .agent }} ບໍ່ສຳເລັດ ຂໍ້ຄວາມ: {{ .err }}"
BatchInstallAgentSkill: "ແຈກຢາຍ Skill ແບບກຸ່ມ"
DispatchAgentSkillInstallTasks: "ຈັດສົ່ງວຽກຕິດຕັ້ງ Skill"
BatchAgentSkillDispatchFailed: "ໂນດ {{ .node }} ຈັດສົ່ງ {{ .skill }} ໄປຫາ {{ .target }} ບໍ່ສຳເລັດ ຂໍ້ຄວາມ: {{ .err }}"
BatchAgentNoAgentsFound: "ໂນດ {{ .node }} ບໍ່ພົບເອເຈນ {{ .agentType }}, ຂ້າມ"
BatchAgentSkillSkipped: "ໂນດ {{ .node }} {{ .agent }} ຖືກຂ້າມ ຂໍ້ຄວາມ: {{ .msg }}"
BatchAgentSkillInstallSubmitted: "ໂນດ {{ .node }} ຈັດສົ່ງວຽກຕິດຕັ້ງ {{ .skill }} ໄປຫາ {{ .agent }} ສຳເລັດແລ້ວ!"
BatchAgentSkillInstallFailed: "ໂນດ {{ .node }} ຈັດສົ່ງວຽກຕິດຕັ້ງ {{ .skill }} ໄປຫາ {{ .agent }} ບໍ່ສຳເລັດ ຂໍ້ຄວາມ: {{ .err }}"
BatchAgentOperateDispatchFailed: "ໂນດ {{ .node }} ຈັດສົ່ງວຽກຂອງ {{ .agentType }} ສຳລັບການດຳເນີນການ {{ .operate }} ບໍ່ສຳເລັດ ຂໍ້ຄວາມ: {{ .err }}"
BatchAgentOperateSkipped: "ໂນດ {{ .node }} {{ .agent }} ຖືກຂ້າມ ຂໍ້ຄວາມ: {{ .msg }}"
BatchAgentOperateSubmitted: "ໂນດ {{ .node }} ຈັດສົ່ງວຽກຂອງ {{ .agent }} ສຳລັບການດຳເນີນການ {{ .operate }} ສຳເລັດແລ້ວ!"
BatchAgentOperateFailed: "ໂນດ {{ .node }} ຈັດສົ່ງວຽກຂອງ {{ .agent }} ສຳລັບການດຳເນີນການ {{ .operate }} ບໍ່ສຳເລັດ ຂໍ້ຄວາມ: {{ .err }}"
BatchStartAgent: "ເລີ່ມເອເຈນແບບກຸ່ມ"
DispatchAgentStartTasks: "ຈັດສົ່ງວຽກເລີ່ມເອເຈນ"
BatchStopAgent: "ຢຸດເອເຈນແບບກຸ່ມ"
DispatchAgentStopTasks: "ຈັດສົ່ງວຽກຢຸດເອເຈນ"
BatchRestartAgent: "ເລີ່ມເອເຈນຄືນໃໝ່ແບບກຸ່ມ"
DispatchAgentRestartTasks: "ຈັດສົ່ງວຽກເລີ່ມເອເຈນຄືນໃໝ່"
BatchDeleteAgent: "ລຶບເອເຈນແບບກຸ່ມ"
DispatchAgentDeleteTasks: "ຈັດສົ່ງວຽກລຶບເອເຈນ"
AgentOperateStart: "ເລີ່ມ"
AgentOperateStop: "ຢຸດ"
AgentOperateRestart: "ເລີ່ມຄືນໃໝ່"
AgentOperateDelete: "ລຶບ"
# app and skill task
PushAppInstallTaskToNode: "ສົ່ງວຽກຕິດຕັ້ງແອັບໄປຫາໂນດ [{{ .name }}]"
AppInstallTask: "ວຽກຕິດຕັ້ງແອັບ"
PushAppFailed: "ສົ່ງວຽກຕິດຕັ້ງແອັບບໍ່ສຳເລັດ"
SkillHubInstallTask: "ຕິດຕັ້ງ Skill [{{ .name }}]"
SkillHubInstallToTarget: "ຕິດຕັ້ງ Skill ໄປຍັງເປົ້າໝາຍ [{{ .name }}]"
# script library
ScriptLibrary: "ຄັງສະຄຣິບ"
RemoteScriptLibrary: "ຄັງສະຄຣິບໄລຍະໄກ"
ScriptSyncSkip: "ຄັງສະຄຣິບເປັນເວີຊັນລ່າສຸດແລ້ວ"
DownloadData: "ກຳລັງດາວໂຫຼດໄຟລ໌ຄັງສະຄຣິບ data.yaml"
DownloadPackage: "ກຳລັງດາວໂຫຼດແພັກເກດຄັງສະຄຣິບ"
AnalyticCompletion: "ວິເຄາະສຳເລັດແລ້ວ, ກຳລັງຊິງໄປຫາຖານຂໍ້ມູນ..."
# node sync
SyncNode: "ຊິງຂໍ້ມູນໄປຫາໂນດ {{ .name }}"
LocalName: "ຊື່ 'local' ໃຊ້ສະເພາະສຳລັບການລະບຸເຄື່ອງພາຍໃນຂອງລະບົບ"
SyncPackageData: "ຈັດແພັກເກດຂໍ້ມູນສຳລັບຊິງ"
SyncPackageEncrypt: "ເຂົ້າລະຫັດແພັກເກດຂໍ້ມູນ"
SyncRequest: "ຮ້ອງຂໍ API ຊິງໂນດ"
SyncFailedRetry: "ການຊິງຂໍ້ມູນໂນດໝົດເວລາ (ຄັ້ງທີ {{ .index }}), ກຳລັງລອງໃໝ່..."
SyncFailed: "ການຊິງລົ້ມເຫຼວ, ກະລຸນາຊິງດ້ວຍຕົນເອງໃນລາຍຊື່ໂນດ!"
SyncSystemProxy: "ການຕັ້ງຄ່າພຣັອກຊີລະບົບ"
SyncScripts: "ຄັງສະຄຣິບ"
SyncBackupAccounts: "ບັນຊີສຳຮອງ"
SyncAlertSetting: "ການຕັ້ງຄ່າແຈ້ງເຕືອນ"
SyncCustomApp: "ແອັບກຳນົດເອງ"
SyncLanguage: "ພາສາລະບົບ"
SyncEdition: "ພາກພື້ນ"
# node upgrade
NodeUpgrade: "ອັບເກຣດໂນດ {{ .name }}"
UpgradeCheck: "ກວດສອບອັບເດດຂອງໂນດ"
UpgradeCheckLocal: "ໂນດພາຍໃນເຄື່ອງບໍ່ຮອງຮັບການອັບເກຣດແບບກຸ່ມ, ຂ້າມ..."
UpgradeCheckLatest: "ໂນດເປັນເວີຊັນລ່າສຸດແລ້ວ, ຂ້າມ..."
NewSSHClient: "ກຳລັງເລີ່ມຕົ້ນການເຊື່ອມຕໍ່ SSH"
BackupBeforeUpgrade: "ສຳຮອງຂໍ້ມູນກ່ອນອັບເກຣດ"
UploadUpgradeFile: "ແຈກຢາຍໄຟລ໌ອັບເກຣດ"
RestartAfterUpgrade: "ເລີ່ມບໍລິການຫຼັງການອັບເກຣດ"
LoadAutoUpgradeNodesFailed: "ໂຫຼດໂນດທີ່ອັບເກຣດອັດຕະໂນມັດບໍ່ສຳເລັດ, ຂໍ້ຜິດພາດ: {{ .err }}"
AutoUpgradeNodes: "ໂນດທີ່ອັບເກຣດອັດຕະໂນມັດ: {{ .nodes }}"
UpdateAutoUpgradeNodesStatusFailed: "ອັບເດດສະຖານະໂນດທີ່ອັບເກຣດອັດຕະໂນມັດບໍ່ສຳເລັດ, ຂໍ້ຜິດພາດ: {{ .err }}"
# node add
MasterData: "ຂໍ້ມູນໂນດຫຼັກ"
LoadSftpClient: "ໂຫຼດໄຄລເອນ SFTP"
PackageMasterData: "ສ້າງແພັກເກດສຳຮອງໂນດຫຼັກ"
UploadBackup: "ອັບໂຫຼດຂໍ້ມູນສຳຮອງ"
TaskAddNode: "ເພີ່ມໂນດ"
LoadNodeArch: "ຮັບຂໍ້ມູນສະຖາປັດຕະຍະກຳຂອງໂນດ"
LoadNodeArchDetail: "ກວດພົບສະຖາປັດຕະຍະກຳໂນດຫຼັກ: {{ .local }}, ສະຖາປັດຕະຍະກຳໂນດຍ່ອຍ: {{ .node }}"
LoadNodeUpgradeDetail: "ກຳລັງໃຊ້ໄດເຣັກທໍຣີການຕິດຕັ້ງເກົ່າຂອງເວີຊັນ v1: {{ .baseDir }}, ພອດຮັບຟັງຂອງບໍລິການ: {{ .port }}"
SyncAgentBaseInfo: "ຊິງຂໍ້ມູນພື້ນຖານຂອງໂນດ"
GenerateSSLInfo: "ສ້າງຂໍ້ມູນ SSL ຂອງໂນດ"
ConnInfoNotMatch: "ຂໍ້ມູນການເຊື່ອມຕໍ່ບໍ່ກົງກັນ"
MakeAgentPackage: "ສ້າງແພັກເກດຕິດຕັ້ງໂນດ"
SendAgent: "ແຈກຢາຍແພັກເກດຕິດຕັ້ງໂນດ"
StartService: "ເລີ່ມບໍລິການ"
NoBackupNode: "ໂນດສຳຮອງຫວ່າງເປົ່າ. ກະລຸນາເລືອກແລ້ວບັນທຶກກ່ອນ"
# node file and image sync
LocalNodeIpFailed: "ຮັບ IP ຂອງໂນດຫຼັກບໍ່ສຳເລັດ. ກະລຸນາແກ້ໄຂໂນດຫຼັກ ແລະ ເພີ່ມທີ່ຢູ່ IP ພ້ອມຂໍ້ມູນການຢືນຢັນ SSH."
HandlePrivateKey: "ປະມວນຜົນກະແຈສ່ວນຕົວຂອງໂນດ"
HandlePublicKey: "ປະມວນຜົນກະແຈສາທາລະນະຂອງໂນດ"
ExchangeFile: "ເລີ່ມຊິງ {{ .sourcePath }} ຈາກໂນດ {{ .source }} ໄປຫາໂນດ {{ .dest }}:{{ .destPath }}"
NodeFile: "ໄຟລ໌ໂນດ"
ImageSyncTaskName: "ຊິງອິມເມຈ {{ .count }} ລາຍການ"
SSLSyncTaskName: "ຊິງໃບຮັບຮອງ {{ .count }} ລາຍການ"
AppSyncTaskName: "ຊິງແອັບ {{ .name }}"
SSLSyncToNode: "ສົ່ງໃບຮັບຮອງ [{{ .cert }}] ໄປຫາໂນດ [{{ .node }}]"
ImageSyncSave: "ບັນທຶກອິມເມຈ {{ .image }}"
ImageSyncSaveTags: "ບັນທຶກແທັກອິມເມຈ {{ .tags }}"
ImageSyncToNode: "ຊິງອິມເມຈ {{ .image }} ໄປຫາໂນດ {{ .node }}"
ImageSyncLoad: "ໂຫຼດອິມເມຈ {{ .image }} ໃນໂນດ {{ .node }}"
ImageSyncClean: "ລ້າງໄຟລ໌ຊົ່ວຄາວຂອງອິມເມຈ {{ .image }}"
ImageSyncNoTag: "ອິມເມຈ {{ .image }} ບໍ່ມີແທັກ ແລະ ຈະຖືກບັນທຶກດ້ວຍ ID ອິມເມຈ"
ImageSyncFrontendTagsIgnored: "ບໍ່ພົບແທັກຂອງອິມເມຈ {{ .image }} ໃນໂນດຕົ້ນທາງ. ແທັກຈາກສ່ວນໜ້າຖືກຂ້າມ."
ImageSyncHandlePrivateKey: "ປະມວນຜົນກະແຈສ່ວນຕົວຂອງໂນດສຳລັບຊິງອິມເມຈ"
ImageSyncHandlePublicKey: "ປະມວນຜົນກະແຈສາທາລະນະຂອງໂນດສຳລັບຊິງອິມເມຈ"
ImageSyncTransfer: "ເລີ່ມໂອນໄຟລ໌ຊົ່ວຄາວຂອງອິມເມຈ: {{ .source }}:{{ .sourcePath }} -> {{ .dest }}:{{ .destPath }}"
# command line
SudoHelper: "ໃຊ້ {{ .cmd }} ຫຼື ປ່ຽນໄປໃຊ້ຜູ້ໃຊ້ root"
UsernameNeed: "ຮຸ່ນວິສາຫະກິດຕ້ອງລະບຸ --username"
DBConnErr: "ຂໍ້ຜິດພາດ: ເລີ່ມຕົ້ນການເຊື່ອມຕໍ່ຖານຂໍ້ມູນບໍ່ສຳເລັດ, {{ .err }}"
SystemVersion: "ເວີຊັນ: "
SystemMode: "ໂໝດ: "
# command line - app
AppVersion: "ເວີຊັນແອັບ"
AppCommands: "ຄຳສັ່ງທີ່ກ່ຽວກັບແອັບ"
AppInit: "ເລີ່ມຕົ້ນແອັບ"
AppKeyVal: "ຄີແອັບ (ຮອງຮັບສະເພາະພາສາອັງກິດ)"
AppCreateFileErr: "ສ້າງໄຟລ໌ {{ .name }} ບໍ່ສຳເລັດ {{ .err }}"
AppCreateDirErr: "ສ້າງໂຟນເດີ {{ .name }} ບໍ່ສຳເລັດ {{ .err }}"
AppMissKey: "ບໍ່ມີຄີແອັບ, ໃຊ້ -k ເພື່ອລະບຸ"
AppMissVersion: "ບໍ່ມີເວີຊັນແອັບ, ໃຊ້ -v ເພື່ອລະບຸ"
AppVersionExist: "ມີເວີຊັນນີ້ຢູ່ແລ້ວ!"
AppCreateSuccessful: "ສ້າງສຳເລັດແລ້ວ!"
AppWriteErr: "ຂຽນໄຟລ໌ {{ .name }} ບໍ່ສຳເລັດ {{ .err }}"
# command line - listen IP
ListenIPCommands: "ປ່ຽນ IP ທີ່ຮັບຟັງ"
ListenIPv4: "ຮັບຟັງຜ່ານ IPv4"
ListenIPv6: "ຮັບຟັງຜ່ານ IPv6"
ListenChangeSuccessful: "ປ່ຽນສຳເລັດແລ້ວ! ຕອນນີ້ກຳລັງຮັບຟັງຢູ່ {{ .value }}"
# command line - reset
ResetCommands: "ຕັ້ງຄ່າຂໍ້ມູນລະບົບຄືນໃໝ່"
ResetMFA: "ຍົກເລີກການຢືນຢັນສອງຂັ້ນຕອນຂອງ 1Panel"
ResetHttps: "ຍົກເລີກການເຂົ້າລະບົບ 1Panel ຜ່ານ HTTPS"
ResetEntrance: "ຍົກເລີກທາງເຂົ້າຄວາມປອດໄພຂອງ 1Panel"
ResetIPs: "ຍົກເລີກຂໍ້ຈຳກັດ IP ທີ່ອະນຸຍາດຂອງ 1Panel"
ResetDomain: "ຍົກເລີກການຜູກໂດເມນຂອງ 1Panel"
ResetPasskey: "ລ້າງ Passkey ຂອງ 1Panel"
# command line - user
UserList: "ຮັບລາຍຊື່ຜູ້ໃຊ້ 1Panel"
UserTableName: "ຊື່"
UserTableMFAStatus: "ສະຖານະ MFA"
UserTableSuperAdmin: "ຜູ້ບໍລິຫານສູງສຸດ"
UserTableCreatedAt: "ສ້າງເມື່ອ"
UserEmptyList: "ບໍ່ພົບຜູ້ໃຊ້"
UserInfo: "ຮັບຂໍ້ມູນແຜງ"
UserInfoAddr: "ທີ່ຢູ່ແຜງ: "
UserInfoPassHelp: "ຄຳແນະນຳ: ເພື່ອປ່ຽນລະຫັດຜ່ານ ທ່ານສາມາດໃຊ້ຄຳສັ່ງ: "
# command line - restore
RestoreCommands: "ຍ້ອນບໍລິການ ແລະ ຂໍ້ມູນ 1Panel ກັບຄືນ"
RestoreNoSuchFile: "ບໍ່ພົບໄຟລ໌ສຳລັບຍ້ອນກັບ"
RestoreStep1: "(1/5) ກຳລັງເລີ່ມຍ້ອນບໍລິການ ແລະ ຂໍ້ມູນ 1Panel ຈາກໄດເຣັກທໍຣີ {{ .name }}..."
RestoreStep2: "(2/5) ຍ້ອນໄບນາຣີ 1Panel ສຳເລັດແລ້ວ"
RestoreStep3: "(3/5) ຍ້ອນສະຄຣິບ 1Panel ສຳເລັດແລ້ວ"
RestoreStep4: "(4/5) ຍ້ອນບໍລິການ 1Panel ສຳເລັດແລ້ວ"
RestoreStep5: "(5/5) ຍ້ອນຂໍ້ມູນ 1Panel ສຳເລັດແລ້ວ"
RestoreSuccessful: "ການຍ້ອນກັບສຳເລັດແລ້ວ. ກັບໄປຫາເວີຊັນ {{ .version }}. ກຳລັງເລີ່ມບໍລິການຄືນໃໝ່..."
# command line - update
UpdateCommands: "ອັບເດດຂໍ້ມູນແຜງ"
UpdateUser: "ອັບເດດຂໍ້ມູນຜູ້ໃຊ້"
UpdatePassword: "ອັບເດດລະຫັດຜ່ານຜູ້ໃຊ້"
UpdatePort: "ອັບເດດພອດແຜງ"
UpdateUserNull: "ຂໍ້ຜິດພາດ: ຊື່ຜູ້ໃຊ້ຫວ່າງເປົ່າ!"
UpdateUserBlank: "ຂໍ້ຜິດພາດ: ຊື່ຜູ້ໃຊ້ມີຊ່ອງຫວ່າງ!"
UpdateUserFormat: "ຂໍ້ຜິດພາດ: ຮູບແບບຊື່ຜູ້ໃຊ້ບໍ່ຖືກຕ້ອງ! ຮອງຮັບສະເພາະຕົວອັກສອນອັງກິດ, ຈີນ, ຕົວເລກ ແລະ _, ຄວາມຍາວ 3-30 ຕົວ"
UpdateUserErr: "ຂໍ້ຜິດພາດ: ອັບເດດຜູ້ໃຊ້ບໍ່ສຳເລັດ, {{ .err }}"
UpdateSuccessful: "ອັບເດດສຳເລັດແລ້ວ!"
UpdateUserResult: "ຜູ້ໃຊ້: {{ .name }}"
UpdatePasswordRead: "ຂໍ້ຜິດພາດ: ອ່ານຂໍ້ມູນລະຫັດຜ່ານຜູ້ໃຊ້ບໍ່ສຳເລັດ, {{ .err }}"
UpdatePasswordNull: "ຂໍ້ຜິດພາດ: ລະຫັດຜ່ານຜູ້ໃຊ້ຫວ່າງເປົ່າ!"
UpdateUPasswordBlank: "ຂໍ້ຜິດພາດ: ລະຫັດຜ່ານຜູ້ໃຊ້ມີຊ່ອງຫວ່າງ!"
UpdatePasswordFormat: "ຂໍ້ຜິດພາດ: ລະຫັດຜ່ານຜູ້ໃຊ້ຮອງຮັບສະເພາະຕົວອັກສອນ, ຕົວເລກ ແລະ ອັກຂະລະພິເສດ (!@#$%*_,.?), ຄວາມຍາວ 8-30 ຕົວ."
UpdatePasswordLen: "ຂໍ້ຜິດພາດ: ກະລຸນາປ້ອນລະຫັດຜ່ານທີ່ຍາວກວ່າ 6 ຕົວ"
UpdatePasswordRe: "ຢືນຢັນລະຫັດຜ່ານ:"
UpdatePasswordErr: "ຂໍ້ຜິດພາດ: ອັບເດດລະຫັດຜ່ານຜູ້ໃຊ້ບໍ່ສຳເລັດ, {{ .err }}"
UpdatePasswordSame: "ຂໍ້ຜິດພາດ: ລະຫັດຜ່ານສອງຄັ້ງບໍ່ກົງກັນ, ກະລຸນາກວດສອບແລ້ວລອງໃໝ່!"
UpdatePasswordResult: "ລະຫັດຜ່ານຜູ້ໃຊ້: {{ .name }}"
UpdatePortFormat: "ຂໍ້ຜິດພາດ: ໝາຍເລກພອດທີ່ປ້ອນຕ້ອງຢູ່ລະຫວ່າງ 1 ຫາ 65535!"
UpdatePortUsed: "ຂໍ້ຜິດພາດ: ໝາຍເລກພອດກຳລັງຖືກໃຊ້ງານ, ກະລຸນາກວດສອບແລ້ວລອງໃໝ່!"
UpdatePortErr: "ຂໍ້ຜິດພາດ: ອັບເດດພອດແຜງບໍ່ສຳເລັດ, {{ .err }}"
UpdatePortResult: "ພອດແຜງ: {{ .name }}"
UpdatePortFirewallAdd: "ເພີ່ມກົດພອດໄຟຣ໌ວໍບໍ່ສຳເລັດ, {{ .err }}, ກະລຸນາເພີ່ມພອດ {{ .name }} ເຂົ້າໃນກົດໄຟຣ໌ວໍດ້ວຍຕົນເອງ."
UpdatePortFirewallDel: "ຂໍ້ຜິດພາດ: ລຶບພອດໄຟຣ໌ວໍບໍ່ສຳເລັດ, {{ .err }}"
UpdatePortFirewallReload: "ໂຫຼດໄຟຣ໌ວໍຄືນໃໝ່ບໍ່ສຳເລັດ, {{ .err }}, ກະລຸນາໂຫຼດໄຟຣ໌ວໍຄືນໃໝ່ດ້ວຍຕົນເອງ."
# mobile app
ErrVerifyToken: 'ການກວດສອບໂທເຄັນລົ້ມເຫຼວ. ກະລຸນາຕັ້ງຄ່າຄືນໃໝ່ແລ້ວສະແກນອີກຄັ້ງ.'
ErrInvalidToken: 'ໂທເຄັນບໍ່ຖືກຕ້ອງ. ກະລຸນາຕັ້ງຄ່າຄືນໃໝ່ແລ້ວສະແກນອີກຄັ້ງ.'
ErrExpiredToken: 'ໂທເຄັນໝົດອາຍຸແລ້ວ. ກະລຸນາຕັ້ງຄ່າຄືນໃໝ່ແລ້ວສະແກນອີກຄັ້ງ.'
# command export
Name: "ຊື່"
Command: "ຄຳສັ່ງ"

View File

@@ -29,6 +29,7 @@
<a href="/docs/README.ru.md"><img alt="Русский" src="https://img.shields.io/badge/%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9-d9d9d9"></a> <a href="/docs/README.ru.md"><img alt="Русский" src="https://img.shields.io/badge/%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9-d9d9d9"></a>
<a href="/docs/README.ms.md"><img alt="Bahasa Melayu" src="https://img.shields.io/badge/Bahasa Melayu-d9d9d9"></a> <a href="/docs/README.ms.md"><img alt="Bahasa Melayu" src="https://img.shields.io/badge/Bahasa Melayu-d9d9d9"></a>
<a href="/docs/README.fa.md"><img alt="Persian" src="https://img.shields.io/badge/%D9%81%D8%A7%D8%B1%D8%B3%DB%8C-d9d9d9"></a> <a href="/docs/README.fa.md"><img alt="Persian" src="https://img.shields.io/badge/%D9%81%D8%A7%D8%B1%D8%B3%DB%8C-d9d9d9"></a>
<a href="/docs/README.lo.md"><img alt="ພາສາລາວ" src="https://img.shields.io/badge/%E0%BA%9E%E0%BA%B2%E0%BA%AA%E0%BA%B2%E0%BA%A5%E0%BA%B2%E0%BA%A7-d9d9d9"></a>
</p> </p>
------------------------------ ------------------------------

View File

@@ -29,6 +29,7 @@
<a href="/docs/README.ru.md"><img alt="Русский" src="https://img.shields.io/badge/%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9-d9d9d9"></a> <a href="/docs/README.ru.md"><img alt="Русский" src="https://img.shields.io/badge/%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9-d9d9d9"></a>
<a href="/docs/README.ms.md"><img alt="Bahasa Melayu" src="https://img.shields.io/badge/Bahasa Melayu-d9d9d9"></a> <a href="/docs/README.ms.md"><img alt="Bahasa Melayu" src="https://img.shields.io/badge/Bahasa Melayu-d9d9d9"></a>
<a href="/docs/README.fa.md"><img alt="Persian" src="https://img.shields.io/badge/%D9%81%D8%A7%D8%B1%D8%B3%DB%8C-d9d9d9"></a> <a href="/docs/README.fa.md"><img alt="Persian" src="https://img.shields.io/badge/%D9%81%D8%A7%D8%B1%D8%B3%DB%8C-d9d9d9"></a>
<a href="/docs/README.lo.md"><img alt="ພາສາລາວ" src="https://img.shields.io/badge/%E0%BA%9E%E0%BA%B2%E0%BA%AA%E0%BA%B2%E0%BA%A5%E0%BA%B2%E0%BA%A7-d9d9d9"></a>
</p> </p>
------------------------------ ------------------------------

View File

@@ -29,6 +29,7 @@
<a href="/docs/README.ru.md"><img alt="Русский" src="https://img.shields.io/badge/%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9-d9d9d9"></a> <a href="/docs/README.ru.md"><img alt="Русский" src="https://img.shields.io/badge/%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9-d9d9d9"></a>
<a href="/docs/README.ms.md"><img alt="Bahasa Melayu" src="https://img.shields.io/badge/Bahasa Melayu-d9d9d9"></a> <a href="/docs/README.ms.md"><img alt="Bahasa Melayu" src="https://img.shields.io/badge/Bahasa Melayu-d9d9d9"></a>
<a href="/docs/README.fa.md"><img alt="Persian" src="https://img.shields.io/badge/%D9%81%D8%A7%D8%B1%D8%B3%DB%8C-d9d9d9"></a> <a href="/docs/README.fa.md"><img alt="Persian" src="https://img.shields.io/badge/%D9%81%D8%A7%D8%B1%D8%B3%DB%8C-d9d9d9"></a>
<a href="/docs/README.lo.md"><img alt="ພາສາລາວ" src="https://img.shields.io/badge/%E0%BA%9E%E0%BA%B2%E0%BA%AA%E0%BA%B2%E0%BA%A5%E0%BA%B2%E0%BA%A7-d9d9d9"></a>
</p> </p>
------------------------------ ------------------------------

View File

@@ -34,6 +34,7 @@
<a href="/docs/README.ru.md"><img alt="Русский" src="https://img.shields.io/badge/Русский-d9d9d9"></a> <a href="/docs/README.ru.md"><img alt="Русский" src="https://img.shields.io/badge/Русский-d9d9d9"></a>
<a href="/docs/README.ms.md"><img alt="Bahasa Melayu" src="https://img.shields.io/badge/Bahasa Melayu-d9d9d9"></a> <a href="/docs/README.ms.md"><img alt="Bahasa Melayu" src="https://img.shields.io/badge/Bahasa Melayu-d9d9d9"></a>
<a href="/docs/README.fa.md"><img alt="Persian" src="https://img.shields.io/badge/%D9%81%D8%A7%D8%B1%D8%B3%DB%8C-d9d9d9"></a> <a href="/docs/README.fa.md"><img alt="Persian" src="https://img.shields.io/badge/%D9%81%D8%A7%D8%B1%D8%B3%DB%8C-d9d9d9"></a>
<a href="/docs/README.lo.md"><img alt="ພາສາລາວ" src="https://img.shields.io/badge/%E0%BA%9E%E0%BA%B2%E0%BA%AA%E0%BA%B2%E0%BA%A5%E0%BA%B2%E0%BA%A7-d9d9d9"></a>
</p> </p>
--- ---

View File

@@ -29,6 +29,7 @@
<a href="/docs/README.ru.md"><img alt="Русский" src="https://img.shields.io/badge/%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9-d9d9d9"></a> <a href="/docs/README.ru.md"><img alt="Русский" src="https://img.shields.io/badge/%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9-d9d9d9"></a>
<a href="/docs/README.ms.md"><img alt="Bahasa Melayu" src="https://img.shields.io/badge/Bahasa Melayu-d9d9d9"></a> <a href="/docs/README.ms.md"><img alt="Bahasa Melayu" src="https://img.shields.io/badge/Bahasa Melayu-d9d9d9"></a>
<a href="/docs/README.fa.md"><img alt="Persian" src="https://img.shields.io/badge/%D9%81%D8%A7%D8%B1%D8%B3%DB%8C-d9d9d9"></a> <a href="/docs/README.fa.md"><img alt="Persian" src="https://img.shields.io/badge/%D9%81%D8%A7%D8%B1%D8%B3%DB%8C-d9d9d9"></a>
<a href="/docs/README.lo.md"><img alt="ພາສາລາວ" src="https://img.shields.io/badge/%E0%BA%9E%E0%BA%B2%E0%BA%AA%E0%BA%B2%E0%BA%A5%E0%BA%B2%E0%BA%A7-d9d9d9"></a>
</p> </p>
------------------------------ ------------------------------

View File

@@ -29,6 +29,7 @@
<a href="/docs/README.ru.md"><img alt="Русский" src="https://img.shields.io/badge/%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9-d9d9d9"></a> <a href="/docs/README.ru.md"><img alt="Русский" src="https://img.shields.io/badge/%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9-d9d9d9"></a>
<a href="/docs/README.ms.md"><img alt="Bahasa Melayu" src="https://img.shields.io/badge/Bahasa Melayu-d9d9d9"></a> <a href="/docs/README.ms.md"><img alt="Bahasa Melayu" src="https://img.shields.io/badge/Bahasa Melayu-d9d9d9"></a>
<a href="/docs/README.fa.md"><img alt="Persian" src="https://img.shields.io/badge/%D9%81%D8%A7%D8%B1%D8%B3%DB%8C-d9d9d9"></a> <a href="/docs/README.fa.md"><img alt="Persian" src="https://img.shields.io/badge/%D9%81%D8%A7%D8%B1%D8%B3%DB%8C-d9d9d9"></a>
<a href="/docs/README.lo.md"><img alt="ພາສາລາວ" src="https://img.shields.io/badge/%E0%BA%9E%E0%BA%B2%E0%BA%AA%E0%BA%B2%E0%BA%A5%E0%BA%B2%E0%BA%A7-d9d9d9"></a>
</p> </p>
------------------------------ ------------------------------

View File

@@ -29,6 +29,7 @@
<a href="/docs/README.ru.md"><img alt="Русский" src="https://img.shields.io/badge/%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9-d9d9d9"></a> <a href="/docs/README.ru.md"><img alt="Русский" src="https://img.shields.io/badge/%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9-d9d9d9"></a>
<a href="/docs/README.ms.md"><img alt="Bahasa Melayu" src="https://img.shields.io/badge/Bahasa Melayu-d9d9d9"></a> <a href="/docs/README.ms.md"><img alt="Bahasa Melayu" src="https://img.shields.io/badge/Bahasa Melayu-d9d9d9"></a>
<a href="/docs/README.fa.md"><img alt="Persian" src="https://img.shields.io/badge/%D9%81%D8%A7%D8%B1%D8%B3%DB%8C-d9d9d9"></a> <a href="/docs/README.fa.md"><img alt="Persian" src="https://img.shields.io/badge/%D9%81%D8%A7%D8%B1%D8%B3%DB%8C-d9d9d9"></a>
<a href="/docs/README.lo.md"><img alt="ພາສາລາວ" src="https://img.shields.io/badge/%E0%BA%9E%E0%BA%B2%E0%BA%AA%E0%BA%B2%E0%BA%A5%E0%BA%B2%E0%BA%A7-d9d9d9"></a>
</p> </p>
------------------------------ ------------------------------

View File

@@ -29,6 +29,7 @@
<a href="/docs/README.ru.md"><img alt="Русский" src="https://img.shields.io/badge/%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9-d9d9d9"></a> <a href="/docs/README.ru.md"><img alt="Русский" src="https://img.shields.io/badge/%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9-d9d9d9"></a>
<a href="/docs/README.ms.md"><img alt="Bahasa Melayu" src="https://img.shields.io/badge/Bahasa Melayu-d9d9d9"></a> <a href="/docs/README.ms.md"><img alt="Bahasa Melayu" src="https://img.shields.io/badge/Bahasa Melayu-d9d9d9"></a>
<a href="/docs/README.fa.md"><img alt="Persian" src="https://img.shields.io/badge/%D9%81%D8%A7%D8%B1%D8%B3%DB%8C-d9d9d9"></a> <a href="/docs/README.fa.md"><img alt="Persian" src="https://img.shields.io/badge/%D9%81%D8%A7%D8%B1%D8%B3%DB%8C-d9d9d9"></a>
<a href="/docs/README.lo.md"><img alt="ພາສາລາວ" src="https://img.shields.io/badge/%E0%BA%9E%E0%BA%B2%E0%BA%AA%E0%BA%B2%E0%BA%A5%E0%BA%B2%E0%BA%A7-d9d9d9"></a>
</p> </p>
------------------------------ ------------------------------

117
docs/README.lo.md Normal file
View File

@@ -0,0 +1,117 @@
<p align="center"><a href="https://1panel.pro"><img src="https://resource.1panel.pro/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
<h3 align="center">ແຜງຄວບຄຸມ VPS ແບບໂອເພນຊອດ ພ້ອມການຮອງຮັບເອເຈນ AI ໃນຕົວ</h3>
<p align="center">
ໄດ້ຮັບຄວາມໄວ້ວາງໃຈຈາກຜູ້ໃຊ້ໂຮສເອງຫຼາຍກວ່າ <strong>2,000,000</strong> ຄົນທົ່ວໂລກ
</p>
<p align="center">
<a href="https://trendshift.io/repositories/2462" target="_blank"><img src="https://trendshift.io/api/badge/repositories/2462" alt="1Panel-dev%2F1Panel | Trendshift" style="width: 240px; height: auto;" /></a>
</p>
<p align="center">
<a href="https://www.gnu.org/licenses/gpl-3.0.html"><img src="https://shields.io/github/license/1Panel-dev/1Panel?color=%231890FF" alt="ໃບອະນຸຍາດ: GPL v3"></a>
<a href="https://app.codacy.com/gh/1Panel-dev/1Panel"><img src="https://app.codacy.com/project/badge/Grade/da67574fd82b473992781d1386b937ef" alt="Codacy"></a>
<a href="https://discord.gg/bUpUqWqdRr"><img src="https://img.shields.io/discord/1318846410149335080?logo=discord&labelColor=%20%235462eb&logoColor=%20%23f5f5f5&color=%20%235462eb" alt="Discord"></a>
<a href="https://github.com/1Panel-dev/1Panel/releases"><img src="https://img.shields.io/github/v/release/1Panel-dev/1Panel" alt="ລຸ້ນທີ່ເຜີຍແຜ່ໃນ GitHub"></a>
<a href="https://github.com/1Panel-dev/1Panel"><img src="https://img.shields.io/github/stars/1Panel-dev/1Panel?color=%231890FF&style=flat-square" alt="ດາວ"></a>
</p>
<p align="center">
<a href="/README.md"><img alt="English" src="https://img.shields.io/badge/English-d9d9d9"></a>
<a href="/docs/README.zh-Hans.md"><img alt="中文(简体)" src="https://img.shields.io/badge/中文(简体)-d9d9d9"></a>
<a href="/docs/README.ja.md"><img alt="日本語" src="https://img.shields.io/badge/日本語-d9d9d9"></a>
<a href="/docs/README.pt-br.md"><img alt="Português (Brasil)" src="https://img.shields.io/badge/Português (Brasil)-d9d9d9"></a>
<a href="/docs/README.ar.md"><img alt="العربية" src="https://img.shields.io/badge/العربية-d9d9d9"></a>
<a href="/docs/README.de.md"><img alt="Deutsch" src="https://img.shields.io/badge/Deutsch-d9d9d9"></a>
<a href="/docs/README.es-es.md"><img alt="Español" src="https://img.shields.io/badge/Español-d9d9d9"></a>
<a href="/docs/README.fr.md"><img alt="français" src="https://img.shields.io/badge/français-d9d9d9"></a>
<a href="/docs/README.ko.md"><img alt="한국어" src="https://img.shields.io/badge/한국어-d9d9d9"></a>
<a href="/docs/README.id.md"><img alt="Bahasa Indonesia" src="https://img.shields.io/badge/Bahasa Indonesia-d9d9d9"></a>
<a href="/docs/README.zh-Hant.md"><img alt="中文(繁體)" src="https://img.shields.io/badge/中文(繁體)-d9d9d9"></a>
<a href="/docs/README.tr.md"><img alt="Türkçe" src="https://img.shields.io/badge/Türkçe-d9d9d9"></a>
<a href="/docs/README.ru.md"><img alt="Русский" src="https://img.shields.io/badge/Русский-d9d9d9"></a>
<a href="/docs/README.ms.md"><img alt="Bahasa Melayu" src="https://img.shields.io/badge/Bahasa Melayu-d9d9d9"></a>
<a href="/docs/README.fa.md"><img alt="Persian" src="https://img.shields.io/badge/%D9%81%D8%A7%D8%B1%D8%B3%DB%8C-d9d9d9"></a>
<a href="/docs/README.lo.md"><img alt="ພາສາລາວ" src="https://img.shields.io/badge/%E0%BA%9E%E0%BA%B2%E0%BA%AA%E0%BA%B2%E0%BA%A5%E0%BA%B2%E0%BA%A7-d9d9d9"></a>
</p>
---
## 1Panel ແມ່ນຫຍັງ?
1Panel ແມ່ນແຜງຄວບຄຸມ VPS ທີ່ທັນສະໄໝ ແລະ ເປັນໂອເພນຊອດ — ພ້ອມທັງເປັນແຜງດຽວທີ່ມີ **ການຮອງຮັບເອເຈນ AI ໃນຕົວ**. ທ່ານສາມາດໃຊ້ງານໂມເດວ Ollama, ນຳໃຊ້ເອເຈນສ່ວນຕົວ OpenClaw ແລະ ຈັດການລະບົບເຊີບເວີທັງໝົດຜ່ານໜ້າເວັບທີ່ສະອາດຕາ. ບໍ່ຕ້ອງຈື່ຄຳສັ່ງ CLI.
👉 ເບິ່ງ [ວິດີໂອແນະນຳ 2 ນາທີ](https://www.youtube.com/watch?v=Jl_wqp-XA08)
## ເປັນຫຍັງຕ້ອງເລືອກ 1Panel?
| | 1Panel | cPanel / Plesk | aaPanel | Webmin |
|--|--------|----------------|---------|--------|
| ຟຣີ ແລະ ເປັນໂອເພນຊອດ | ✅ | ❌ | ບາງສ່ວນ | ✅ |
| ຮັນໄທມ໌ເອເຈນ AI ໃນຕົວ | ✅ | ❌ | ❌ | ❌ |
| ຕະຫຼາດແອັບແບບຄລິກດຽວ | ✅ 165+ ແອັບ | ❌ | ✅ | ❌ |
| UI ທັນສະໄໝ (ຫຼັງປີ 2020) | ✅ | ❌ | ບາງສ່ວນ | ❌ |
| ການຈັດການ Docker / ຄອນເທນເນີ | ✅ | ❌ | ❌ | ❌ |
| ພັດທະນາຢ່າງຕໍ່ເນື່ອງ | ✅ | ✅ | ✅ | ຊ້າ |
## ຄຸນສົມບັດຫຼັກ
- **ຮັນໄທມ໌ເອເຈນ AI**: ນຳໃຊ້ໂມເດວ LLM ຂອງ Ollama, ເປີດໃຊ້ເອເຈນສ່ວນຕົວ OpenClaw ແລະ ຕິດຕາມການໃຊ້ GPU — ທັງໝົດເຮັດໄດ້ຈາກແດຊບອດ. ບໍ່ຕ້ອງຈັດການສະແຕັກ AI ແຍກຕ່າງຫາກ.
- **ນຳໃຊ້ເວັບໄຊດ້ວຍຄລິກດຽວ**: ເປີດໃຊ້ເວັບໄຊທີ່ພ້ອມສຳລັບການຜະລິດ ພ້ອມການຜູກໂດເມນອັດຕະໂນມັດ, ການອອກໃບຮັບຮອງ SSL ແລະ ການຕັ້ງຄ່າ Nginx — ບໍ່ຕ້ອງຕັ້ງຄ່າດ້ວຍຕົນເອງ.
- **ຕະຫຼາດແອັບ**: ມີແອັບໂອເພນຊອດທີ່ໜ້າເຊື່ອຖືຫຼາຍກວ່າ 165 ແອັບ (Nextcloud, Bitwarden, Umami, NocoBase ແລະ ອື່ນໆ) ທີ່ສາມາດຕິດຕັ້ງ ແລະ ອັບເດດໄດ້ດ້ວຍຄລິກດຽວ.
- **ການຈັດການ Docker ແລະ ຄອນເທນເນີ**: ສ້າງ, ເລີ່ມ, ຢຸດ ແລະ ກວດສອບຄອນເທນເນີ, ອິມເມຈ, ເຄືອຂ່າຍ ແລະ ໂວລຸມ ຜ່ານ UI ແບບກຣາຟິກ — ບໍ່ຕ້ອງສະຫຼັບໄປມາໃນ CLI.
- **ຄວາມປອດໄພພ້ອມໃຊ້ງານ**: ກົດໄຟຣ໌ວໍ, fail2ban, ການແຍກຄອນເທນເນີ, WAF ແລະ ບັນທຶກການກວດສອບ — ທຸກຢ່າງຖືກຕັ້ງຄ່າ ແລະ ເຮັດວຽກຕັ້ງແຕ່ມື້ທຳອິດ.
- **ສຳຮອງ ແລະ ກູ້ຄືນ**: ກຳນົດເວລາສຳຮອງອັດຕະໂນມັດໄປຫາ AWS S3, Cloudflare R2 ຫຼື ບ່ອນຈັດເກັບພາຍໃນເຄື່ອງ. ກູ້ຄືນສະແນັບຊັອດໃດກໍໄດ້ດ້ວຍຄລິກດຽວ.
## ເລີ່ມຕົ້ນຢ່າງໄວ
> **ຄວາມຕ້ອງການ:** Linux VPS (Debian / Ubuntu / CentOS / Rocky), RAM 1 GB ແລະ ການເຊື່ອມຕໍ່ອິນເຕີເນັດ.
> ໃຊ້ເວລາປະມານ 60 ວິນາທີ.
```bash
bash -c "$(curl -sSL https://resource.1panel.pro/v2/quick_start.sh)"
```
ຫຼັງຈາກຕິດຕັ້ງແລ້ວ, ເປີດ `http://<your-server-ip>:<port>/<security-path>` ໃນເບຣົາເຊີ.
ໃຊ້ຄຳສັ່ງ `1pctl user-info` ຜ່ານ SSH ຫາກຕ້ອງການເບິ່ງຂໍ້ມູນສຳລັບເຂົ້າລະບົບ.
## ພາບໜ້າຈໍ
![UI ຂອງ 1Panel](https://resource.1panel.pro/img/overview_en_v2.png)
## ຮຸ່ນ Pro
1Panel OSS ໃຊ້ງານໄດ້ຟຣີຕະຫຼອດໄປ. ຮຸ່ນ Pro ເພີ່ມຄຸນສົມບັດທີ່ອອກແບບສຳລັບທີມ ແລະ ວຽກລະດັບການຜະລິດ:
| ຄຸນສົມບັດ | OSS | Pro |
|---------|:---:|:---:|
| ຕິດຕັ້ງແອັບດ້ວຍຄລິກດຽວ | ✅ | ✅ |
| ເອເຈນ AI (OpenClaw) | 1 ເອເຈນ | ບໍ່ຈຳກັດ |
| WAF ແລະ ຄວາມປອດໄພຂັ້ນສູງ | ພື້ນຖານ | ✅ |
| ປ້ອງກັນການດັດແປງເວັບໄຊ | ❌ | ✅ |
| ຕິດຕາມເວລາພ້ອມໃຊ້ງານຂອງເວັບໄຊ | ❌ | ✅ |
| ການຈັດການຫຼາຍໂນດ | ❌ | ✅ |
| ໂລໂກ້ ແລະ ຮູບແບບການສະແດງຜົນກຳນົດເອງ | ❌ | ✅ |
| ການຊ່ວຍເຫຼືອລຳດັບຕົ້ນ | ❌ | ✅ |
**ເລີ່ມຕົ້ນທີ່ $80/ປີ.** [ປຽບທຽບແຜນ ແລະ ເລີ່ມທົດລອງຟຣີ 30 ມື້ →](https://1panel.pro/pricing)
## ປະຫວັດດາວ
[![ກຣາຟປະຫວັດດາວ](https://api.star-history.com/svg?repos=1Panel-dev/1Panel&type=Date)](https://star-history.com/#1Panel-dev/1Panel&Date)
## ຊຸມຊົນ ແລະ ການຊ່ວຍເຫຼືອ
- **Discord** — [ເຂົ້າຮ່ວມຊຸມຊົນ](https://discord.gg/bUpUqWqdRr) ເພື່ອຂໍຄວາມຊ່ວຍເຫຼືອ, ສະເໜີຄຸນສົມບັດ ແລະ ແບ່ງປັນຜົນງານ
- **ເອກະສານ** — [1panel.pro/docs](https://1panel.pro/docs)
- **ບັນຫາ** — [GitHub Issues](https://github.com/1Panel-dev/1Panel/issues) ສຳລັບລາຍງານບັກ
## ຄວາມປອດໄພ
ພົບຊ່ອງໂຫວ່ບໍ? ກະລຸນາອ່ານ [SECURITY.md](/SECURITY.md) ກ່ອນເຜີຍແຜ່ຂໍ້ມູນ.
## ໃບອະນຸຍາດ
ໂຄງການນີ້ໃຊ້ [GNU General Public License v3.0](https://www.gnu.org/licenses/gpl-3.0.html).

View File

@@ -29,6 +29,7 @@
<a href="/docs/README.ru.md"><img alt="Русский" src="https://img.shields.io/badge/%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9-d9d9d9"></a> <a href="/docs/README.ru.md"><img alt="Русский" src="https://img.shields.io/badge/%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9-d9d9d9"></a>
<a href="/docs/README.ms.md"><img alt="Bahasa Melayu" src="https://img.shields.io/badge/Bahasa Melayu-d9d9d9"></a> <a href="/docs/README.ms.md"><img alt="Bahasa Melayu" src="https://img.shields.io/badge/Bahasa Melayu-d9d9d9"></a>
<a href="/docs/README.fa.md"><img alt="Persian" src="https://img.shields.io/badge/%D9%81%D8%A7%D8%B1%D8%B3%DB%8C-d9d9d9"></a> <a href="/docs/README.fa.md"><img alt="Persian" src="https://img.shields.io/badge/%D9%81%D8%A7%D8%B1%D8%B3%DB%8C-d9d9d9"></a>
<a href="/docs/README.lo.md"><img alt="ພາສາລາວ" src="https://img.shields.io/badge/%E0%BA%9E%E0%BA%B2%E0%BA%AA%E0%BA%B2%E0%BA%A5%E0%BA%B2%E0%BA%A7-d9d9d9"></a>
</p> </p>
------------------------------ ------------------------------

View File

@@ -29,6 +29,7 @@
<a href="/docs/README.ru.md"><img alt="Русский" src="https://img.shields.io/badge/%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9-d9d9d9"></a> <a href="/docs/README.ru.md"><img alt="Русский" src="https://img.shields.io/badge/%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9-d9d9d9"></a>
<a href="/docs/README.ms.md"><img alt="Bahasa Melayu" src="https://img.shields.io/badge/Bahasa Melayu-d9d9d9"></a> <a href="/docs/README.ms.md"><img alt="Bahasa Melayu" src="https://img.shields.io/badge/Bahasa Melayu-d9d9d9"></a>
<a href="/docs/README.fa.md"><img alt="Persian" src="https://img.shields.io/badge/%D9%81%D8%A7%D8%B1%D8%B3%DB%8C-d9d9d9"></a> <a href="/docs/README.fa.md"><img alt="Persian" src="https://img.shields.io/badge/%D9%81%D8%A7%D8%B1%D8%B3%DB%8C-d9d9d9"></a>
<a href="/docs/README.lo.md"><img alt="ພາສາລາວ" src="https://img.shields.io/badge/%E0%BA%9E%E0%BA%B2%E0%BA%AA%E0%BA%B2%E0%BA%A5%E0%BA%B2%E0%BA%A7-d9d9d9"></a>
</p> </p>
------------------------------ ------------------------------

View File

@@ -29,6 +29,7 @@
<a href="/docs/README.ru.md"><img alt="Русский" src="https://img.shields.io/badge/%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9-d9d9d9"></a> <a href="/docs/README.ru.md"><img alt="Русский" src="https://img.shields.io/badge/%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9-d9d9d9"></a>
<a href="/docs/README.ms.md"><img alt="Bahasa Melayu" src="https://img.shields.io/badge/Bahasa Melayu-d9d9d9"></a> <a href="/docs/README.ms.md"><img alt="Bahasa Melayu" src="https://img.shields.io/badge/Bahasa Melayu-d9d9d9"></a>
<a href="/docs/README.fa.md"><img alt="Persian" src="https://img.shields.io/badge/%D9%81%D8%A7%D8%B1%D8%B3%DB%8C-d9d9d9"></a> <a href="/docs/README.fa.md"><img alt="Persian" src="https://img.shields.io/badge/%D9%81%D8%A7%D8%B1%D8%B3%DB%8C-d9d9d9"></a>
<a href="/docs/README.lo.md"><img alt="ພາສາລາວ" src="https://img.shields.io/badge/%E0%BA%9E%E0%BA%B2%E0%BA%AA%E0%BA%B2%E0%BA%A5%E0%BA%B2%E0%BA%A7-d9d9d9"></a>
</p> </p>
------------------------------ ------------------------------

View File

@@ -29,6 +29,7 @@
<a href="/docs/README.ru.md"><img alt="Русский" src="https://img.shields.io/badge/%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9-d9d9d9"></a> <a href="/docs/README.ru.md"><img alt="Русский" src="https://img.shields.io/badge/%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9-d9d9d9"></a>
<a href="/docs/README.ms.md"><img alt="Bahasa Melayu" src="https://img.shields.io/badge/Bahasa Melayu-d9d9d9"></a> <a href="/docs/README.ms.md"><img alt="Bahasa Melayu" src="https://img.shields.io/badge/Bahasa Melayu-d9d9d9"></a>
<a href="/docs/README.fa.md"><img alt="Persian" src="https://img.shields.io/badge/%D9%81%D8%A7%D8%B1%D8%B3%DB%8C-d9d9d9"></a> <a href="/docs/README.fa.md"><img alt="Persian" src="https://img.shields.io/badge/%D9%81%D8%A7%D8%B1%D8%B3%DB%8C-d9d9d9"></a>
<a href="/docs/README.lo.md"><img alt="ພາສາລາວ" src="https://img.shields.io/badge/%E0%BA%9E%E0%BA%B2%E0%BA%AA%E0%BA%B2%E0%BA%A5%E0%BA%B2%E0%BA%A7-d9d9d9"></a>
</p> </p>
------------------------------ ------------------------------

View File

@@ -29,6 +29,7 @@
<a href="/docs/README.ru.md"><img alt="Русский" src="https://img.shields.io/badge/%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9-d9d9d9"></a> <a href="/docs/README.ru.md"><img alt="Русский" src="https://img.shields.io/badge/%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9-d9d9d9"></a>
<a href="/docs/README.ms.md"><img alt="Bahasa Melayu" src="https://img.shields.io/badge/Bahasa Melayu-d9d9d9"></a> <a href="/docs/README.ms.md"><img alt="Bahasa Melayu" src="https://img.shields.io/badge/Bahasa Melayu-d9d9d9"></a>
<a href="/docs/README.fa.md"><img alt="Persian" src="https://img.shields.io/badge/%D9%81%D8%A7%D8%B1%D8%B3%DB%8C-d9d9d9"></a> <a href="/docs/README.fa.md"><img alt="Persian" src="https://img.shields.io/badge/%D9%81%D8%A7%D8%B1%D8%B3%DB%8C-d9d9d9"></a>
<a href="/docs/README.lo.md"><img alt="ພາສາລາວ" src="https://img.shields.io/badge/%E0%BA%9E%E0%BA%B2%E0%BA%AA%E0%BA%B2%E0%BA%A5%E0%BA%B2%E0%BA%A7-d9d9d9"></a>
</p> </p>
[![Watch the video](https://resource.fit2cloud.com/1panel/img/overview_video.png)](https://www.bilibili.com/video/BV1Mt421n7LZ/) [![Watch the video](https://resource.fit2cloud.com/1panel/img/overview_video.png)](https://www.bilibili.com/video/BV1Mt421n7LZ/)

View File

@@ -29,6 +29,7 @@
<a href="/docs/README.ru.md"><img alt="Русский" src="https://img.shields.io/badge/%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9-d9d9d9"></a> <a href="/docs/README.ru.md"><img alt="Русский" src="https://img.shields.io/badge/%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9-d9d9d9"></a>
<a href="/docs/README.ms.md"><img alt="Bahasa Melayu" src="https://img.shields.io/badge/Bahasa Melayu-d9d9d9"></a> <a href="/docs/README.ms.md"><img alt="Bahasa Melayu" src="https://img.shields.io/badge/Bahasa Melayu-d9d9d9"></a>
<a href="/docs/README.fa.md"><img alt="Persian" src="https://img.shields.io/badge/%D9%81%D8%A7%D8%B1%D8%B3%DB%8C-d9d9d9"></a> <a href="/docs/README.fa.md"><img alt="Persian" src="https://img.shields.io/badge/%D9%81%D8%A7%D8%B1%D8%B3%DB%8C-d9d9d9"></a>
<a href="/docs/README.lo.md"><img alt="ພາສາລາວ" src="https://img.shields.io/badge/%E0%BA%9E%E0%BA%B2%E0%BA%AA%E0%BA%B2%E0%BA%A5%E0%BA%B2%E0%BA%A7-d9d9d9"></a>
</p> </p>
[![Watch the video](https://resource.fit2cloud.com/1panel/img/overview_video.png)](https://www.bilibili.com/video/BV1Mt421n7LZ/) [![Watch the video](https://resource.fit2cloud.com/1panel/img/overview_video.png)](https://www.bilibili.com/video/BV1Mt421n7LZ/)

View File

@@ -1,78 +1,120 @@
# Translation Contribution Guide # Translation Contribution Guide
Thank you for your interest in helping translate 1Panel into a new language! This guide walks through every file you need to create or modify to add full language support across the frontend and backend. Thank you for helping translate 1Panel! A complete locale touches the frontend,
the Core service, the Agent service, application-store metadata, and the project
README files. This guide lists the repository changes and validation required
before opening a pull request.
> **Reference PR:** [WIP: Dev v2 spanish (#10352)](https://github.com/1Panel-dev/1Panel/pull/10352) — a merged, real-world example of adding a brand-new locale (Spanish `es-ES`). > **Reference pull requests**
>
> - [WIP: Dev v2 spanish (#10352)](https://github.com/1Panel-dev/1Panel/pull/10352)
> is a full-locale example for Spanish (`es-ES`).
> - [docs: add Persian README (#13132)](https://github.com/1Panel-dev/1Panel/pull/13132)
> is a localized-README example.
--- ---
## Overview ## Scope
1Panel's i18n system spans two layers: 1Panel has several independent translation surfaces:
| Layer | Technology | Translation format | | Surface | Technology | Repository format |
|---|---|---| |---|---|---|
| **Frontend** (Vue 3) | `vue-i18n` + Element Plus | TypeScript (`.ts`) | | Frontend | Vue 3, `vue-i18n`, Element Plus | TypeScript (`.ts`) |
| **Backend** (Go) | `go-i18n` / `nicksnyder/go-i18n` | YAML (`.yaml`) | | Core service | Go i18n | YAML (`.yaml`) |
| Agent service | Go i18n | YAML (`.yaml`) |
| Application store | API models and frontend types | Go and TypeScript |
| Project introduction | GitHub README files | Markdown (`.md`) |
Adding a new language requires changes in **both** layers, as well as registering the locale in a few selector components. Adding only a frontend module does not provide complete locale support. Follow
all applicable steps below and state explicitly in the pull request if a surface
is intentionally out of scope.
--- ## Step 0 Define locale identifiers
## Step 1 Frontend translation file Choose the canonical runtime locale first. Use a
[BCP 47](https://www.ietf.org/rfc/bcp/bcp47.txt) language tag and preserve its
casing wherever the runtime locale is used. File names and third-party locale
packs do not always use the same casing.
Copy the reference English file and translate all values. | Language | Runtime locale | Frontend module | Element Plus pack | Backend YAML | App-store key | README |
|---|---|---|---|---|---|---|
| Simplified Chinese | `zh` | `zh.ts` | `zh-cn` | `zh.yaml` | `zh` | `README.zh-Hans.md` |
| Traditional Chinese | `zh-Hant` | `zh-Hant.ts` | `zh-tw` | `zh-Hant.yaml` | `zh-hant` | `README.zh-Hant.md` |
| English | `en` | `en.ts` | `en` | `en.yaml` | `en` | `README.md` |
| Brazilian Portuguese | `pt-BR` | `pt-br.ts` | `pt-br` | `pt-BR.yaml` | `pt-br` | `README.pt-br.md` |
| Spanish (Spain) | `es-ES` | `es-es.ts` | `es` | `es-ES.yaml` | `es-es` | `README.es-es.md` |
| Lao | `lo` | `lo.ts` | `lo` | `lo.yaml` | `lo` | `README.lo.md` |
``` Use lowercase for simple runtime codes (`ja`, `ko`, `lo`) and standard BCP 47
frontend/src/lang/modules/en.ts → frontend/src/lang/modules/<locale>.ts casing for variants (`pt-BR`, `es-ES`, `zh-Hant`). Do not infer a file name from
the runtime locale: add an explicit mapping when the casing or code differs.
Before editing, search for hard-coded locale collections so a newly introduced
selector, whitelist, or compatibility map is not missed:
```bash
rg "zh-Hant|pt-BR|es-ES" frontend core agent
``` ```
Replace every English string with its translation. Keep all keys, nested objects, and the `getFuLocaleMessage` call at the bottom unchanged: ## Step 1 Add the frontend translation module
Copy the English module and translate its values:
```text
frontend/src/lang/modules/en.ts -> frontend/src/lang/modules/<module-name>.ts
```
Keep the following unchanged unless the English source changed structurally:
- object keys, nesting, and TypeScript syntax;
- interpolation placeholders such as `{0}`, `${name}`, and `{{ .detail }}`;
- HTML tags, Markdown, URLs, product names, commands, and configuration keys;
- the `getFuLocaleMessage` merge at the end of the file.
Pass the canonical runtime locale to `getFuLocaleMessage`, even when the module
file name uses different casing:
```ts ```ts
// frontend/src/lang/modules/<locale>.ts
import { getFuLocaleMessage } from '@/lang/fu'; import { getFuLocaleMessage } from '@/lang/fu';
const message = { const message = {
commons: { commons: {
// ... translated strings // Translated values.
}, },
// ...
}; };
export default { export default {
...getFuLocaleMessage('<locale>'), ...getFuLocaleMessage('<runtime-locale>'),
...message, ...message,
}; };
``` ```
> **Tip:** The file is ~4 400 lines. Using a translation tool for a first pass is fine, but please review the output for accuracy and context. The English module evolves continuously. Copy it from the same branch as your
change instead of relying on a fixed key count or line count. Machine
translation can be used for a first pass, but every string must be reviewed in
its UI context.
--- ## Step 2 Register the frontend loader and FU messages
## Step 2 Register the locale loader Add the canonical runtime locale and its module file to `LOCALE_LOADERS` in
`frontend/src/lang/index.ts`:
Open `frontend/src/lang/index.ts` and add your locale to `LOCALE_LOADERS`:
```ts ```ts
// frontend/src/lang/index.ts
const LOCALE_LOADERS: Record<string, LocaleLoader> = { const LOCALE_LOADERS: Record<string, LocaleLoader> = {
// existing entries // Existing entries.
'<locale>': () => import('./modules/<locale>'), '<runtime-locale>': () => import('./modules/<module-name>'),
}; };
``` ```
--- Then add the locale to `fuLocales` in `frontend/src/lang/fu.ts`. These messages
belong to the shared FU table and steps components and are not supplied by the
## Step 3 FU component translations main module:
`frontend/src/lang/fu.ts` contains translations for custom FU table/steps components. Add a new entry for your locale:
```ts ```ts
// frontend/src/lang/fu.ts
const fuLocales: Record<string, FuLocaleMessage> = { const fuLocales: Record<string, FuLocaleMessage> = {
// existing entries // Existing entries.
'<locale>': { '<runtime-locale>': {
fu: { fu: {
table: { table: {
more: '...', more: '...',
@@ -89,123 +131,326 @@ const fuLocales: Record<string, FuLocaleMessage> = {
}; };
``` ```
--- ## Step 3 Register the Element Plus locale
## Step 4 Element Plus component locale Element Plus provides its own translations for date pickers, pagination,
popovers, and other components. Import the matching pack in
Element Plus ships its own locale strings (used in date pickers, pagination, etc.). Import the matching locale pack and wire it into `frontend/src/App.vue`: `frontend/src/App.vue`:
```ts ```ts
// frontend/src/App.vue — import section import localePack from 'element-plus/es/locale/lang/<element-plus-code>';
import <varName> from 'element-plus/es/locale/lang/<ep-locale-code>';
``` ```
Then add a branch in the `i18nLocale` computed property: Map the canonical runtime locale in the `i18nLocale` computed property:
```ts ```ts
const i18nLocale = computed(() => { const i18nLocale = computed(() => {
// existing branches … // Existing mappings.
if (globalStore.language === '<locale>') return <varName>; if (globalStore.language === '<runtime-locale>') return localePack;
return zhCn; // fallback unchanged return zhCn;
}); });
``` ```
You can find all available Element Plus locale codes in `node_modules/element-plus/es/locale/lang/`. Confirm the pack exists in
`frontend/node_modules/element-plus/es/locale/lang/`. If Element Plus does not
provide the language, document the chosen fallback in the pull request rather
than importing a nonexistent module.
--- ## Step 4 Expose the locale in every frontend entry point
## Step 5 Login page language selector ### Login page
Open `frontend/src/views/login/components/login-form.vue` and add your locale label to `languageLabelMap`: `frontend/src/views/login/components/login-form.vue` currently renders two
language menus for different login layouts. Add the new locale to **both menu
blocks**, then add its native display name to `languageLabelMap`:
```ts ```ts
const languageLabelMap: Record<string, string> = { const languageLabelMap: Record<string, string> = {
// existing entries // Existing entries.
'<locale>': '<Native language name>', '<runtime-locale>': '<Native language name>',
}; };
``` ```
--- Verify both login layouts manually. Updating only `languageLabelMap` changes the
selected label but does not add a selectable menu item.
## Step 6 Panel settings language selector ### Panel settings
Open `frontend/src/views/setting/panel/index.vue` and add an option to `languageOptions`: Add the locale to `languageOptions` in
`frontend/src/views/setting/panel/index.vue`:
```ts ```ts
const languageOptions = ref([ const languageOptions = ref([
// existing entries // Existing entries.
{ value: '<locale>', label: '<Native language name>' }, { value: '<runtime-locale>', label: '<Native language name>' },
]); ]);
``` ```
--- ### Public share page
## Step 7 Backend translation files (core & agent) Add the locale to `supportedLocales` in `frontend/src/views/share/index.vue`.
This list controls browser-language recognition and the `Accept-Language`
header used by public share requests.
The backend has **two** independent Go modules, each with its own YAML translation file. Copy the English reference and translate: ```ts
const supportedLocales = [
``` // Existing entries.
core/i18n/lang/en.yaml → core/i18n/lang/<locale>.yaml (~264 lines) '<runtime-locale>',
agent/i18n/lang/en.yaml → agent/i18n/lang/<locale>.yaml (~592 lines) ];
``` ```
YAML format example: ### Locale-sensitive fallbacks
Review locale comparisons that select language-specific API fields. For
example, operation records currently provide Chinese and English detail fields
in `frontend/src/views/log/operation/index.vue`. Chinese runtime locales should
use `detailZH`; every other locale should retain a visible `detailEN` fallback.
Prefer one shared fallback branch instead of adding every non-Chinese locale to
another hard-coded list.
## Step 5 Allow the locale in the login API
The backend validates the language sent by the login request. Add the canonical
runtime locale to the `Language` field's `oneof` validation tag in
`core/app/dto/auth.go`:
```go
Language string `json:"language" validate:"oneof=zh en ... <runtime-locale>"`
```
Without this change, the new language can appear on the login page but the
login request will be rejected as an invalid parameter.
Run `gofmt` on the Go file after editing it.
## Step 6 Add and register Core translations
Copy the current English catalog and translate only its values:
```text
core/i18n/lang/en.yaml -> core/i18n/lang/<runtime-locale>.yaml
```
Preserve every YAML key and placeholder:
```yaml ```yaml
ErrInvalidParams: "Invalid request parameters: {{ .detail }}" ErrInvalidParams: "Translated text: {{ .detail }}"
ErrRecordExist: "Record already exists" ErrRecordExist: "Translated text"
# …
``` ```
--- Register the catalog in `core/i18n/i18n.go`:
## Step 8 Register backend locale in Go
Add your locale key and file path in both i18n registries:
**`core/i18n/i18n.go`**
```go ```go
var langFiles = map[string]string{ var langFiles = map[string]string{
// existing entries // Existing entries.
"<locale>": "lang/<locale>.yaml", "<runtime-locale>": "lang/<runtime-locale>.yaml",
} }
``` ```
**`agent/i18n/i18n.go`** ## Step 7 Add and register Agent translations
Core and Agent are independent Go modules and have independent catalogs. Copy
and translate the Agent catalog separately:
```text
agent/i18n/lang/en.yaml -> agent/i18n/lang/<runtime-locale>.yaml
```
Register it in `agent/i18n/i18n.go`:
```go ```go
var langFiles = map[string]string{ var langFiles = map[string]string{
// existing entries // Existing entries.
"<locale>": "lang/<locale>.yaml", "<runtime-locale>": "lang/<runtime-locale>.yaml",
} }
``` ```
--- Do not copy the Core YAML file into Agent: their key sets are different.
## Checklist ## Step 8 Extend application-store locale models
Before opening a PR, verify the following: Application-store names and descriptions use their own locale fields. Add the
new field to both repository-side schemas.
- [ ] `frontend/src/lang/modules/<locale>.ts` created and all strings translated In `agent/app/dto/app.go`, extend `Locale`:
- [ ] Locale registered in `frontend/src/lang/index.ts` (`LOCALE_LOADERS`)
- [ ] Locale entry added to `frontend/src/lang/fu.ts`
- [ ] Element Plus locale imported and mapped in `frontend/src/App.vue`
- [ ] Locale label added to `languageLabelMap` in `frontend/src/views/login/components/login-form.vue`
- [ ] Locale option added to `languageOptions` in `frontend/src/views/setting/panel/index.vue`
- [ ] `core/i18n/lang/<locale>.yaml` created
- [ ] `agent/i18n/lang/<locale>.yaml` created
- [ ] Locale registered in `core/i18n/i18n.go` (`langFiles`)
- [ ] Locale registered in `agent/i18n/i18n.go` (`langFiles`)
- [ ] Manually verified: new locale appears in the login language dropdown
- [ ] Manually verified: new locale appears in **Settings → Panel → Language**
- [ ] Manually verified: UI renders correctly after switching to the new locale
--- ```go
type Locale struct {
// Existing fields.
NewLanguage string `json:"<app-store-key>"`
}
```
## Locale code conventions In `frontend/src/api/interface/app.ts`, extend `Locale` with the same JSON key:
Use [BCP 47](https://www.ietf.org/rfc/bcp/bcp47.txt) locale codes. Examples used in this project: ```ts
interface Locale {
// Existing fields.
'<app-store-key>': string;
}
```
| Language | Locale code | Add the app-store key to the `description` example in
`core/cmd/server/app/app_config.yml` as well. This embedded template is written
when the server command scaffolds a new local application configuration.
Review `frontend/src/utils/app-store.ts` as well. Simple codes that lowercase to
the same value normally need no special handling; regional or script variants
may need an explicit runtime-locale-to-app-store-key mapping.
These schema changes make the repository capable of reading the locale. The
translated application names and descriptions are maintained in the external
application-store data source and must be coordinated separately. Until that
data exists, the application store falls back to English.
## Step 9 Add a localized README
Copy the root README to the documentation directory:
```text
README.md -> docs/README.<readme-code>.md
```
Translate prose while preserving Markdown structure, HTML, images, links,
commands, badges, and code samples. Check every relative link from its new
location under `docs/`; a link that works from the repository root may need a
different relative path in the localized file.
Then keep the language navigation synchronized:
1. Add the new README link to the language badge row in `README.md`.
2. Add the same link to every existing `docs/README.*.md` language badge row.
3. Add the locale to the table in this guide's
[Locale code reference](#locale-code-reference).
Use the native language name for the badge label. The README locale suffix may
follow an existing documentation convention (`zh-Hans`, `pt-br`, `es-es`) and
does not have to match the runtime locale casing.
## Step 10 Format code and regenerate API documentation
Format every changed Go source file:
```bash
gofmt -w core/app/dto/auth.go core/i18n/i18n.go
gofmt -w agent/app/dto/app.go agent/i18n/i18n.go
```
The login-language enum and application-store locale model are represented in
generated Swagger files. Install the repository-compatible `swag` command, then
run the generator test from the Core module:
```bash
cd core
go test ./cmd/server/docs -run TestGenerateSwaggerDoc
```
This updates generated files under `core/cmd/server/docs/`. Do not edit the
generated Swagger output by hand. If the generator is unavailable, call that
out explicitly in the pull request instead of committing stale manual changes.
## Step 11 Validate the locale
### Automated checks
Run checks from the repository root unless a command changes directory:
```bash
# Frontend type checking.
cd frontend
npm run type-check
# Lint only the frontend files changed by the locale contribution.
./node_modules/.bin/eslint \
src/lang/modules/<module-name>.ts \
src/lang/index.ts \
src/lang/fu.ts \
src/App.vue \
src/views/login/components/login-form.vue \
src/views/setting/panel/index.vue \
src/views/share/index.vue \
src/views/log/operation/index.vue \
src/api/interface/app.ts \
src/utils/app-store.ts
# Compile and test the directly affected Go packages.
cd ../core
go test ./i18n ./app/dto
cd ../agent
go test ./i18n ./app/dto
# Check whitespace errors in all changed files.
cd ..
git diff --check
```
Also compare each translated catalog with its English source:
- the frontend module has the same translation keys and nesting;
- each Core and Agent YAML file has exactly the same keys as its corresponding
English file;
- placeholders, formatting tokens, HTML tags, URLs, and commands are preserved;
- YAML files parse successfully, with no duplicate keys;
- all README links and badges resolve to the intended files.
### Manual checks
- [ ] Both login layouts show the native language name and can select it.
- [ ] Login succeeds with the locale in the request; validation does not reject it.
- [ ] **Settings -> Panel -> Language** can switch to the locale and retains it after reload.
- [ ] Element Plus date, pagination, select, and confirmation components use the expected language.
- [ ] A representative Core API error is translated.
- [ ] A representative Agent task/error message is translated.
- [ ] A public share page recognizes the browser locale and sends the expected `Accept-Language` value.
- [ ] Operation-log details remain visible through the correct Chinese or English fallback.
- [ ] Application-store metadata uses the locale when available and falls back to English when absent.
- [ ] The localized README renders correctly and every README language badge links to it.
- [ ] Layout, punctuation, truncation, and text direction are correct at common screen sizes.
For right-to-left languages, verify the login page, navigation, forms, tables,
dialogs, and mixed-direction values such as IP addresses. RTL layout support may
require a separate frontend change beyond translating strings.
## External translation resources
Some runtime assets are not maintained in this repository:
- application-store names and descriptions come from the external
application-store data source;
- the language shell resources downloaded as `language/lang.tar.gz` are
published through the 1Panel resource service.
Repository locale support does not automatically update either resource. If the
new language needs them, coordinate publication with the relevant maintainer and
record the status in the pull request. Do not add generated or downloaded
archives to this repository unless a maintainer requests it.
## Complete pull-request checklist
- [ ] Canonical runtime, module, Element Plus, app-store, and README codes are documented.
- [ ] `frontend/src/lang/modules/<module-name>.ts` is complete and reviewed.
- [ ] `frontend/src/lang/index.ts` contains the locale loader.
- [ ] `frontend/src/lang/fu.ts` contains the FU messages.
- [ ] `frontend/src/App.vue` maps an existing Element Plus locale pack or documents a fallback.
- [ ] Both language menus and `languageLabelMap` are updated in `frontend/src/views/login/components/login-form.vue`.
- [ ] `languageOptions` is updated in `frontend/src/views/setting/panel/index.vue`.
- [ ] `supportedLocales` is updated in `frontend/src/views/share/index.vue`.
- [ ] Locale-sensitive API-field fallbacks, including operation-log details, remain visible.
- [ ] The login validator is updated in `core/app/dto/auth.go`.
- [ ] `core/i18n/lang/<runtime-locale>.yaml` exists and is registered in `core/i18n/i18n.go`.
- [ ] `agent/i18n/lang/<runtime-locale>.yaml` exists and is registered in `agent/i18n/i18n.go`.
- [ ] Application-store locale fields are updated in `agent/app/dto/app.go`, `frontend/src/api/interface/app.ts`, and `core/cmd/server/app/app_config.yml`.
- [ ] Regional or script variants are normalized in `frontend/src/utils/app-store.ts` when needed.
- [ ] `docs/README.<readme-code>.md` exists and every README language badge is synchronized.
- [ ] Changed Go files are formatted and Swagger output is regenerated.
- [ ] Frontend, Core, Agent, catalog-parity, placeholder, and Markdown checks pass.
- [ ] All applicable manual checks pass.
- [ ] External application-store and language-resource work is completed or clearly tracked.
## Locale code reference
| Language | Runtime locale |
|---|---| |---|---|
| Simplified Chinese | `zh` | | Simplified Chinese | `zh` |
| Traditional Chinese | `zh-Hant` | | Traditional Chinese | `zh-Hant` |
@@ -218,19 +463,12 @@ Use [BCP 47](https://www.ietf.org/rfc/bcp/bcp47.txt) locale codes. Examples used
| Brazilian Portuguese | `pt-BR` | | Brazilian Portuguese | `pt-BR` |
| Spanish (Spain) | `es-ES` | | Spanish (Spain) | `es-ES` |
| Persian | `fa` | | Persian | `fa` |
| Lao | `lo` |
Use lowercase for simple codes (`ja`, `ko`) and the standard BCP 47 casing for regional variants (`pt-BR`, `es-ES`, `zh-Hant`). ## Pull-request title convention
**Frontend TypeScript file names** use all-lowercase with hyphens preserved exactly as they appear in the existing `frontend/src/lang/modules/` directory (e.g. `pt-br.ts`, `es-es.ts`, `zh-hant.ts`). ```text
feat(i18n): add <language name> (<runtime-locale>) locale support
**Backend YAML file names** mirror the locale code exactly, preserving the original casing (e.g. `pt-BR.yaml`, `es-ES.yaml`, `zh-Hant.yaml`).
---
## PR title convention
```
feat(i18n): add <language name> (<locale>) locale support
``` ```
Example: `feat(i18n): add German (de-DE) locale support` Example: `feat(i18n): add German (de-DE) locale support`

View File

@@ -18,6 +18,7 @@ import ko from 'element-plus/es/locale/lang/ko';
import tr from 'element-plus/es/locale/lang/tr'; import tr from 'element-plus/es/locale/lang/tr';
import esES from 'element-plus/es/locale/lang/es'; import esES from 'element-plus/es/locale/lang/es';
import fa from 'element-plus/es/locale/lang/fa'; import fa from 'element-plus/es/locale/lang/fa';
import lo from 'element-plus/es/locale/lang/lo';
import { useTheme } from '@/global/use-theme'; import { useTheme } from '@/global/use-theme';
useTheme(); useTheme();
@@ -38,6 +39,7 @@ const i18nLocale = computed(() => {
if (language.value === 'tr') return tr; if (language.value === 'tr') return tr;
if (language.value === 'es-ES') return esES; if (language.value === 'es-ES') return esES;
if (language.value === 'fa') return fa; if (language.value === 'fa') return fa;
if (language.value === 'lo') return lo;
return zhCn; return zhCn;
}); });

View File

@@ -31,6 +31,8 @@ export namespace App {
ko: string; ko: string;
tr: string; tr: string;
'es-es': string; 'es-es': string;
fa: string;
lo: string;
} }
export interface AppDTO extends App { export interface AppDTO extends App {

View File

@@ -95,8 +95,7 @@
<pre <pre
v-if="showScriptPreview" v-if="showScriptPreview"
class="vscode-open__script max-h-[430px] overflow-auto p-3 text-xs leading-6" class="vscode-open__script max-h-[430px] overflow-auto p-3 text-xs leading-6"
>{{ scriptText }}</pre >{{ scriptText }}</pre>
>
</div> </div>
<div v-else class="flex h-full min-h-[320px] flex-col justify-between gap-4"> <div v-else class="flex h-full min-h-[320px] flex-col justify-between gap-4">

View File

@@ -70,7 +70,7 @@ const fuLocales: Record<string, FuLocaleMessage> = {
finish: 'ສຳເລັດ', finish: 'ສຳເລັດ',
}, },
}, },
}, },
ms: { ms: {
fu: { fu: {
table: { table: {

File diff suppressed because it is too large Load Diff

View File

@@ -63,6 +63,7 @@
<el-dropdown-item command="ms">Bahasa Melayu</el-dropdown-item> <el-dropdown-item command="ms">Bahasa Melayu</el-dropdown-item>
<el-dropdown-item command="tr">Turkish</el-dropdown-item> <el-dropdown-item command="tr">Turkish</el-dropdown-item>
<el-dropdown-item command="fa">فارسی</el-dropdown-item> <el-dropdown-item command="fa">فارسی</el-dropdown-item>
<el-dropdown-item command="lo">ພາສາລາວ</el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</template> </template>
</el-dropdown> </el-dropdown>
@@ -122,6 +123,7 @@
<el-dropdown-item command="ms">Bahasa Melayu</el-dropdown-item> <el-dropdown-item command="ms">Bahasa Melayu</el-dropdown-item>
<el-dropdown-item command="tr">Turkish</el-dropdown-item> <el-dropdown-item command="tr">Turkish</el-dropdown-item>
<el-dropdown-item command="fa">فارسی</el-dropdown-item> <el-dropdown-item command="fa">فارسی</el-dropdown-item>
<el-dropdown-item command="lo">ພາສາລາວ</el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</template> </template>
</el-dropdown> </el-dropdown>
@@ -389,6 +391,7 @@ const languageLabelMap: Record<string, string> = {
tr: 'Turkish', tr: 'Turkish',
'es-ES': 'España - Español', 'es-ES': 'España - Español',
fa: 'فارسی', fa: 'فارسی',
lo: 'ພາສາລາວ',
}; };
const handleCommand = async (command: string) => { const handleCommand = async (command: string) => {

View File

@@ -289,6 +289,7 @@ const languageOptions = ref([
{ value: 'tr', label: 'Turkish' }, { value: 'tr', label: 'Turkish' },
{ value: 'es-ES', label: 'España - Español' }, { value: 'es-ES', label: 'España - Español' },
{ value: 'fa', label: 'فارسی' }, { value: 'fa', label: 'فارسی' },
{ value: 'lo', label: 'ພາສາລາວ' },
]); ]);
if (isIntl.value) { if (isIntl.value) {

View File

@@ -54,7 +54,7 @@ const initializing = ref(true);
const errorMessage = ref(''); const errorMessage = ref('');
const shareInfo = ref<File.FileSharePublicInfo | null>(null); const shareInfo = ref<File.FileSharePublicInfo | null>(null);
const shareLocale = ref('en'); const shareLocale = ref('en');
const supportedLocales = ['zh', 'zh-Hant', 'en', 'pt-BR', 'ja', 'ru', 'ms', 'ko', 'tr', 'es-ES']; const supportedLocales = ['zh', 'zh-Hant', 'en', 'pt-BR', 'ja', 'ru', 'ms', 'ko', 'tr', 'es-ES', 'lo'];
const code = computed(() => String(route.params.code || '').trim()); const code = computed(() => String(route.params.code || '').trim());
const currentNode = computed(() => String(route.query.operateNode || 'local')); const currentNode = computed(() => String(route.query.operateNode || 'local'));