Browse Source

feat: add EAB supports for ACME user register #1255

0xJacky 2 tuần trước cách đây
mục cha
commit
38ee12f587

+ 1 - 1
.air.toml

@@ -7,7 +7,7 @@ tmp_dir = "tmp"
 
 [build]
 # Just plain old shell command. You could use `make` as well.
-cmd = "CGO_ENABLED=1 go build -trimpath -tags=jsoniter,unembed -ldflags=\"-X 'github.com/0xJacky/Nginx-UI/settings.buildTime=$(date +%s)'\" -v -o ./tmp/main ."
+cmd = "CGO_ENABLED=1 go build -tags=jsoniter,unembed -ldflags=\"-X 'github.com/0xJacky/Nginx-UI/settings.buildTime=$(date +%s)'\" -v -o ./tmp/main ."
 # Binary file yields from `cmd`.
 bin = "tmp/main"
 # Customize binary.

+ 4 - 0
api/certificate/acme_user.go

@@ -29,6 +29,8 @@ func CreateAcmeUser(c *gin.Context) {
 		"ca_dir":              "omitempty",
 		"proxy":               "omitempty",
 		"register_on_startup": "omitempty",
+		"eab_key_id":          "omitempty",
+		"eab_hmac_key":        "omitempty",
 	}).BeforeExecuteHook(func(ctx *cosy.Ctx[model.AcmeUser]) {
 		if ctx.Model.CADir == "" {
 			ctx.Model.CADir = settings.CertSettings.GetCADir()
@@ -48,6 +50,8 @@ func ModifyAcmeUser(c *gin.Context) {
 		"ca_dir":              "omitempty",
 		"proxy":               "omitempty",
 		"register_on_startup": "omitempty",
+		"eab_key_id":          "omitempty",
+		"eab_hmac_key":        "omitempty",
 	}).BeforeExecuteHook(func(ctx *cosy.Ctx[model.AcmeUser]) {
 		if ctx.Model.CADir == "" {
 			ctx.Model.CADir = settings.CertSettings.GetCADir()

+ 1 - 1
app/package.json

@@ -18,7 +18,7 @@
     "@fingerprintjs/fingerprintjs": "^4.6.2",
     "@formkit/auto-animate": "^0.8.2",
     "@simplewebauthn/browser": "^13.1.2",
-    "@uozi-admin/curd": "^4.5.12",
+    "@uozi-admin/curd": "^4.6.0",
     "@uozi-admin/request": "^2.8.4",
     "@vue/reactivity": "^3.5.18",
     "@vue/shared": "^3.5.18",

+ 6 - 6
app/pnpm-lock.yaml

@@ -24,8 +24,8 @@ importers:
         specifier: ^13.1.2
         version: 13.1.2
       '@uozi-admin/curd':
-        specifier: ^4.5.12
-        version: 4.5.12(@ant-design/icons-vue@7.0.1(vue@3.5.18(typescript@5.8.3)))(ant-design-vue@4.2.6(vue@3.5.18(typescript@5.8.3)))(dayjs@1.11.13)(lodash-es@4.17.21)(vue-router@4.5.1(vue@3.5.18(typescript@5.8.3)))(vue@3.5.18(typescript@5.8.3))
+        specifier: ^4.6.0
+        version: 4.6.0(@ant-design/icons-vue@7.0.1(vue@3.5.18(typescript@5.8.3)))(ant-design-vue@4.2.6(vue@3.5.18(typescript@5.8.3)))(dayjs@1.11.13)(lodash-es@4.17.21)(vue-router@4.5.1(vue@3.5.18(typescript@5.8.3)))(vue@3.5.18(typescript@5.8.3))
       '@uozi-admin/request':
         specifier: ^2.8.4
         version: 2.8.4(lodash-es@4.17.21)
@@ -1250,15 +1250,15 @@ packages:
     peerDependencies:
       vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0
 
-  '@uozi-admin/curd@4.5.12':
-    resolution: {integrity: sha512-eLibmyPcbsJtcsou6/BQrNQmJVhJJ6h/3/OqX2oB5g7srDWqIvdmhTnCrFLzTQST3ZR+XgVdFWzCJ/eWzWH7jQ==}
+  '@uozi-admin/curd@4.6.0':
+    resolution: {integrity: sha512-nWsU4oHVgQSBuYd+ht9GLHwFmCxi1cRuOQBHh3oKkodZjZJtwuZ+IF+xD3LsytzAbMbvcSkJWkFd3LxGZt/FUg==}
     hasBin: true
     peerDependencies:
       '@ant-design/icons-vue': '>=7.0.1'
       ant-design-vue: '>=4.2.6'
       dayjs: '>=1.11.13'
       lodash-es: '>=4.17.21'
-      vue: '>=3.5.17'
+      vue: '>=3.5.18'
       vue-router: '>=4.5.1'
 
   '@uozi-admin/request@2.8.4':
@@ -5154,7 +5154,7 @@ snapshots:
     transitivePeerDependencies:
       - vue
 
-  '@uozi-admin/curd@4.5.12(@ant-design/icons-vue@7.0.1(vue@3.5.18(typescript@5.8.3)))(ant-design-vue@4.2.6(vue@3.5.18(typescript@5.8.3)))(dayjs@1.11.13)(lodash-es@4.17.21)(vue-router@4.5.1(vue@3.5.18(typescript@5.8.3)))(vue@3.5.18(typescript@5.8.3))':
+  '@uozi-admin/curd@4.6.0(@ant-design/icons-vue@7.0.1(vue@3.5.18(typescript@5.8.3)))(ant-design-vue@4.2.6(vue@3.5.18(typescript@5.8.3)))(dayjs@1.11.13)(lodash-es@4.17.21)(vue-router@4.5.1(vue@3.5.18(typescript@5.8.3)))(vue@3.5.18(typescript@5.8.3))':
     dependencies:
       '@ant-design/icons-vue': 7.0.1(vue@3.5.18(typescript@5.8.3))
       '@vueuse/core': 13.6.0(vue@3.5.18(typescript@5.8.3))

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

@@ -6,6 +6,8 @@ export interface AcmeUser extends ModelBase {
   email: string
   ca_dir: string
   registration: { body?: { status: string } }
+  eab_key_id?: string
+  eab_hmac_key?: string
 }
 
 const baseUrl = '/acme_users'

+ 219 - 168
app/src/language/ar/app.po

@@ -5,10 +5,10 @@ msgid ""
 msgstr ""
 "PO-Revision-Date: 2025-07-14 07:37+0000\n"
 "Last-Translator: mosaati <mohammed.saati@gmail.com>\n"
-"Language-Team: Arabic "
-"<https://weblate.nginxui.com/projects/nginx-ui/frontend/ar/>\n"
+"Language-Team: Arabic <https://weblate.nginxui.com/projects/nginx-ui/"
+"frontend/ar/>\n"
 "Language: ar\n"
-"Content-Type: text/plain; charset=utf-8\n"
+"Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
 "&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n"
@@ -33,7 +33,8 @@ msgid "[Nginx UI] Certificate successfully revoked"
 msgstr "[Nginx UI] تم إلغاء الشهادة بنجاح"
 
 #: src/language/generate.ts:37
-msgid "[Nginx UI] Certificate was used for server, reloading server TLS certificate"
+msgid ""
+"[Nginx UI] Certificate was used for server, reloading server TLS certificate"
 msgstr "[Nginx UI] تم استخدام الشهادة للخادم، إعادة تحميل شهادة TLS للخادم"
 
 #: src/language/generate.ts:38
@@ -129,7 +130,7 @@ msgstr "مسار سجل الوصول غير موجود"
 msgid "Access Logs"
 msgstr "سجلات الدخول"
 
-#: src/routes/modules/certificates.ts:20 src/views/certificate/ACMEUser.vue:108
+#: src/routes/modules/certificates.ts:20 src/views/certificate/ACMEUser.vue:148
 #: src/views/certificate/components/ACMEUserSelector.vue:52
 msgid "ACME User"
 msgstr "مستخدم ACME"
@@ -139,7 +140,7 @@ msgid "Action"
 msgstr "إجراء"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:273
-#: src/views/certificate/ACMEUser.vue:90
+#: src/views/certificate/ACMEUser.vue:130
 #: src/views/certificate/CertificateList/certColumns.tsx:92
 #: src/views/certificate/DNSCredential.vue:71
 #: src/views/config/configColumns.tsx:50
@@ -310,7 +311,7 @@ msgstr "هل أنت متأكد أنك تريد الحذف؟"
 msgid "Are you sure you want to reload Nginx on the following sync nodes?"
 msgstr "هل أنت متأكد أنك تريد إعادة تحميل Nginx على عقد المزامنة التالية؟"
 
-#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:97
+#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:100
 msgid "Are you sure you want to remove this directive?"
 msgstr "هل أنت متأكد أنك تريد إزالة هذا التوجيه؟"
 
@@ -490,13 +491,14 @@ msgstr "جدول النسخ الاحتياطي"
 
 #: src/components/Notification/notifications.ts:38
 msgid "Backup task %{backup_name} completed successfully, file: %{file_path}"
-msgstr "تم إنجاز مهمة النسخ الاحتياطي %{backup_name} بنجاح، الملف: %{file_path}"
+msgstr ""
+"تم إنجاز مهمة النسخ الاحتياطي %{backup_name} بنجاح، الملف: %{file_path}"
 
 #: src/components/Notification/notifications.ts:34
-msgid "Backup task %{backup_name} failed during storage upload, error: %{error}"
+msgid ""
+"Backup task %{backup_name} failed during storage upload, error: %{error}"
 msgstr ""
-"فشلت مهمة النسخ الاحتياطي %{backup_name} أثناء تحميل التخزين، الخطأ: "
-"%{error}"
+"فشلت مهمة النسخ الاحتياطي %{backup_name} أثناء تحميل التخزين، الخطأ: %{error}"
 
 #: src/components/Notification/notifications.ts:30
 msgid "Backup task %{backup_name} failed to execute, error: %{error}"
@@ -575,7 +577,8 @@ msgstr "الذاكرة المؤقتة"
 
 #: src/views/dashboard/components/ParamsOpt/ProxyCacheConfig.vue:178
 msgid "Cache items not accessed within this time will be removed"
-msgstr "سيتم إزالة عناصر الذاكرة المؤقتة التي لم يتم الوصول إليها خلال هذا الوقت"
+msgstr ""
+"سيتم إزالة عناصر الذاكرة المؤقتة التي لم يتم الوصول إليها خلال هذا الوقت"
 
 #: src/views/dashboard/components/ParamsOpt/ProxyCacheConfig.vue:350
 msgid "Cache loader processing time threshold"
@@ -825,23 +828,23 @@ msgstr "تحقق مرة أخرى"
 #: src/language/generate.ts:6
 msgid ""
 "Check if /var/run/docker.sock exists. If you are using Nginx UI Official "
-"Docker Image, please make sure the docker socket is mounted like this: `-v "
-"/var/run/docker.sock:/var/run/docker.sock`. Nginx UI official image uses "
-"/var/run/docker.sock to communicate with the host Docker Engine via Docker "
-"Client API. This feature is used to control Nginx in another container and "
-"perform container replacement rather than binary replacement during OTA "
-"upgrades of Nginx UI to ensure container dependencies are also upgraded. If "
-"you don't need this feature, please add the environment variable "
+"Docker Image, please make sure the docker socket is mounted like this: `-v /"
+"var/run/docker.sock:/var/run/docker.sock`. Nginx UI official image uses /var/"
+"run/docker.sock to communicate with the host Docker Engine via Docker Client "
+"API. This feature is used to control Nginx in another container and perform "
+"container replacement rather than binary replacement during OTA upgrades of "
+"Nginx UI to ensure container dependencies are also upgraded. If you don't "
+"need this feature, please add the environment variable "
 "NGINX_UI_IGNORE_DOCKER_SOCKET=true to the container."
 msgstr ""
 "تحقق مما إذا كان /var/run/docker.sock موجودًا. إذا كنت تستخدم صورة Docker "
-"الرسمية لـ Nginx UI، يرجى التأكد من توصيل مقبس Docker بهذه الطريقة: `-v "
-"/var/run/docker.sock:/var/run/docker.sock`. تستخدم صورة Nginx UI الرسمية "
-"/var/run/docker.sock للتواصل مع محرك Docker المضيف عبر واجهة برمجة تطبيقات "
-"Docker Client. تُستخدم هذه الميزة للتحكم في Nginx في حاوية أخرى وإجراء "
-"استبدال الحاوية بدلاً من استبدال الثنائي أثناء التحديثات OTA لـ Nginx UI "
-"لضمان تحديث تبعيات الحاوية أيضًا. إذا كنت لا تحتاج إلى هذه الميزة، يرجى "
-"إضافة متغير البيئة NGINX_UI_IGNORE_DOCKER_SOCKET=true إلى الحاوية."
+"الرسمية لـ Nginx UI، يرجى التأكد من توصيل مقبس Docker بهذه الطريقة: `-v /var/"
+"run/docker.sock:/var/run/docker.sock`. تستخدم صورة Nginx UI الرسمية /var/run/"
+"docker.sock للتواصل مع محرك Docker المضيف عبر واجهة برمجة تطبيقات Docker "
+"Client. تُستخدم هذه الميزة للتحكم في Nginx في حاوية أخرى وإجراء استبدال "
+"الحاوية بدلاً من استبدال الثنائي أثناء التحديثات OTA لـ Nginx UI لضمان تحديث "
+"تبعيات الحاوية أيضًا. إذا كنت لا تحتاج إلى هذه الميزة، يرجى إضافة متغير "
+"البيئة NGINX_UI_IGNORE_DOCKER_SOCKET=true إلى الحاوية."
 
 #: src/components/SelfCheck/tasks/frontend/https-check.ts:14
 msgid ""
@@ -853,19 +856,19 @@ msgstr ""
 
 #: src/language/generate.ts:8
 msgid ""
-"Check if the nginx access log path exists. By default, this path is "
-"obtained from 'nginx -V'. If it cannot be obtained or the obtained path "
-"does not point to a valid, existing file, an error will be reported. In "
-"this case, you need to modify the configuration file to specify the access "
-"log path.Refer to the docs for more details: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#accesslogpath"
+"Check if the nginx access log path exists. By default, this path is obtained "
+"from 'nginx -V'. If it cannot be obtained or the obtained path does not "
+"point to a valid, existing file, an error will be reported. In this case, "
+"you need to modify the configuration file to specify the access log path."
+"Refer to the docs for more details: https://nginxui.com/zh_CN/guide/config-"
+"nginx.html#accesslogpath"
 msgstr ""
-"تحقق مما إذا كان مسار سجل الوصول إلى nginx موجودًا. بشكل افتراضي، يتم "
-"الحصول على هذا المسار من 'nginx -V'. إذا لم يتم الحصول عليه أو إذا كان "
-"المسار الذي تم الحصول عليه لا يشير إلى ملف صالح موجود، فسيتم الإبلاغ عن "
-"خطأ. في هذه الحالة، تحتاج إلى تعديل ملف التكوين لتحديد مسار سجل الوصول. "
-"راجع الوثائق لمزيد من التفاصيل: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#accesslogpath"
+"تحقق مما إذا كان مسار سجل الوصول إلى nginx موجودًا. بشكل افتراضي، يتم الحصول "
+"على هذا المسار من 'nginx -V'. إذا لم يتم الحصول عليه أو إذا كان المسار الذي "
+"تم الحصول عليه لا يشير إلى ملف صالح موجود، فسيتم الإبلاغ عن خطأ. في هذه "
+"الحالة، تحتاج إلى تعديل ملف التكوين لتحديد مسار سجل الوصول. راجع الوثائق "
+"لمزيد من التفاصيل: https://nginxui.com/zh_CN/guide/config-nginx."
+"html#accesslogpath"
 
 #: src/language/generate.ts:9
 msgid "Check if the nginx configuration directory exists"
@@ -881,29 +884,28 @@ msgid ""
 "from 'nginx -V'. If it cannot be obtained or the obtained path does not "
 "point to a valid, existing file, an error will be reported. In this case, "
 "you need to modify the configuration file to specify the error log path. "
-"Refer to the docs for more details: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#errorlogpath"
+"Refer to the docs for more details: https://nginxui.com/zh_CN/guide/config-"
+"nginx.html#errorlogpath"
 msgstr ""
 "تحقق مما إذا كان مسار سجل أخطاء nginx موجودًا. بشكل افتراضي، يتم الحصول على "
 "هذا المسار من 'nginx -V'. إذا تعذر الحصول عليه أو إذا كان المسار الذي تم "
-"الحصول عليه لا يشير إلى ملف صالح موجود، فسيتم الإبلاغ عن خطأ. في هذه "
-"الحالة، تحتاج إلى تعديل ملف التكوين لتحديد مسار سجل الأخطاء. راجع الوثائق "
-"لمزيد من التفاصيل: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#errorlogpath"
+"الحصول عليه لا يشير إلى ملف صالح موجود، فسيتم الإبلاغ عن خطأ. في هذه الحالة، "
+"تحتاج إلى تعديل ملف التكوين لتحديد مسار سجل الأخطاء. راجع الوثائق لمزيد من "
+"التفاصيل: https://nginxui.com/zh_CN/guide/config-nginx.html#errorlogpath"
 
 #: src/language/generate.ts:7
 msgid ""
 "Check if the nginx PID path exists. By default, this path is obtained from "
 "'nginx -V'. If it cannot be obtained, an error will be reported. In this "
 "case, you need to modify the configuration file to specify the Nginx PID "
-"path.Refer to the docs for more details: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#pidpath"
+"path.Refer to the docs for more details: https://nginxui.com/zh_CN/guide/"
+"config-nginx.html#pidpath"
 msgstr ""
-"تحقق مما إذا كان مسار معرف عملية Nginx موجودًا. بشكل افتراضي، يتم الحصول "
-"على هذا المسار من الأمر 'nginx -V'. إذا تعذر الحصول عليه، سيتم الإبلاغ عن "
-"خطأ. في هذه الحالة، تحتاج إلى تعديل ملف التكوين لتحديد مسار معرف عملية "
-"Nginx. راجع الوثائق لمزيد من التفاصيل: "
-"https://nginxui.com/zh_CN/guide/config-nginx.html#pidpath"
+"تحقق مما إذا كان مسار معرف عملية Nginx موجودًا. بشكل افتراضي، يتم الحصول على "
+"هذا المسار من الأمر 'nginx -V'. إذا تعذر الحصول عليه، سيتم الإبلاغ عن خطأ. "
+"في هذه الحالة، تحتاج إلى تعديل ملف التكوين لتحديد مسار معرف عملية Nginx. "
+"راجع الوثائق لمزيد من التفاصيل: https://nginxui.com/zh_CN/guide/config-nginx."
+"html#pidpath"
 
 #: src/language/generate.ts:12
 msgid "Check if the nginx sbin path exists"
@@ -931,8 +933,8 @@ msgstr ""
 
 #: src/language/generate.ts:17
 msgid ""
-"Check if the streams-available and streams-enabled directories are under "
-"the nginx configuration directory"
+"Check if the streams-available and streams-enabled directories are under the "
+"nginx configuration directory"
 msgstr ""
 "تحقق مما إذا كانت الدلائل streams-available و streams-enabled موجودة ضمن "
 "دليل تكوين nginx"
@@ -1017,7 +1019,7 @@ msgstr "أمر"
 msgid "Command exited with unexpected exit code: {0}, error: {1}"
 msgstr "انتهت الأمر برمز خروج غير متوقع: {0}، خطأ: {1}"
 
-#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
+#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:118
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
 #: src/components/NgxConfigEditor/NgxServer.vue:123
@@ -1116,7 +1118,7 @@ msgstr "فترة مهلة الاتصال"
 msgid "Container status unknown"
 msgstr "حالة الحاوية غير معروفة"
 
-#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
+#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:123
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
 msgid "Content"
@@ -1643,8 +1645,8 @@ msgid ""
 "Due to the security policies of some browsers, you cannot use passkeys on "
 "non-HTTPS websites, except when running on localhost."
 msgstr ""
-"نظرًا لسياسات الأمان لبعض المتصفحات، لا يمكنك استخدام مفاتيح المرور على "
-"مواقع الويب غير HTTPS، إلا عند التشغيل على localhost."
+"نظرًا لسياسات الأمان لبعض المتصفحات، لا يمكنك استخدام مفاتيح المرور على مواقع "
+"الويب غير HTTPS، إلا عند التشغيل على localhost."
 
 #: src/views/site/site_list/SiteDuplicate.vue:72
 #: src/views/site/site_list/SiteList.vue:108
@@ -1667,6 +1669,14 @@ msgstr "ديناميكي"
 msgid "e.g., 0 0 * * * (daily at midnight)"
 msgstr "على سبيل المثال، 0 0 * * * (يوميًا عند منتصف الليل)"
 
+#: src/views/certificate/ACMEUser.vue:98
+msgid "EAB HMAC Key"
+msgstr "مفتاح HMAC EAB"
+
+#: src/views/certificate/ACMEUser.vue:85
+msgid "EAB Key ID"
+msgstr "معرف مفتاح EAB"
+
 #: src/language/curd.ts:8
 msgid "Edit"
 msgstr "تعديل"
@@ -1912,6 +1922,20 @@ msgstr "تنتهي في: %{date}"
 msgid "Export Excel"
 msgstr "تصدير إكسل"
 
+#: src/views/certificate/ACMEUser.vue:103
+msgid ""
+"External Account Binding HMAC Key (optional). Should be in Base64 URL "
+"encoding format."
+msgstr ""
+"مفتاح HMAC لربط الحساب الخارجي (اختياري). يجب أن يكون بتنسيق Base64 URL."
+
+#: src/views/certificate/ACMEUser.vue:90
+msgid ""
+"External Account Binding Key ID (optional). Required for some ACME providers "
+"like ZeroSSL."
+msgstr ""
+"معرف مفتاح الربط الحساب الخارجي (اختياري). مطلوب لبعض موفري ACME مثل ZeroSSL."
+
 #: src/views/preference/tabs/NginxSettings.vue:49
 msgid "External Docker Container"
 msgstr "حاوية Docker خارجية"
@@ -2495,10 +2519,6 @@ msgstr "بروتوكول HTTPS"
 msgid "ICP Number"
 msgstr "رقم ICP"
 
-#: src/views/certificate/ACMEUser.vue:43
-msgid "If left blank, the default CA Dir will be used."
-msgstr "إذا تُرك فارغًا، سيتم استخدام دليل CA الافتراضي."
-
 #: src/views/preference/tabs/AuthSettings.vue:113
 msgid ""
 "If the number of login failed attempts from a ip reach the max attempts in "
@@ -2609,7 +2629,7 @@ msgstr ""
 msgid "Interval"
 msgstr "فترة"
 
-#: src/views/certificate/ACMEUser.vue:125
+#: src/views/certificate/ACMEUser.vue:165
 msgid "Invalid"
 msgstr "غير صالح"
 
@@ -2777,7 +2797,11 @@ msgstr "اتركه فارغًا للإعداد الافتراضي: /https://api.
 msgid "Leave blank if do not want to modify"
 msgstr "اتركه فارغًا إذا كنت لا تريد التعديل"
 
-#: src/views/certificate/ACMEUser.vue:55
+#: src/views/certificate/ACMEUser.vue:105 src/views/certificate/ACMEUser.vue:92
+msgid "Leave blank if not required by your ACME provider"
+msgstr "اتركه فارغًا إذا لم يكن مطلوبًا من قبل موفر ACME الخاص بك"
+
+#: src/views/certificate/ACMEUser.vue:68
 msgid "Leave blank if you don't need this."
 msgstr "اتركه فارغًا إذا لم تكن بحاجة إلى ذلك."
 
@@ -2878,12 +2902,12 @@ msgstr "سجل"
 #: src/language/generate.ts:21
 msgid ""
 "Log file %{log_path} is not a regular file. If you are using nginx-ui in "
-"docker container, please refer to "
-"https://nginxui.com/zh_CN/guide/config-nginx-log.html for more information."
+"docker container, please refer to https://nginxui.com/zh_CN/guide/config-"
+"nginx-log.html for more information."
 msgstr ""
 "ملف السجل %{log_path} ليس ملفًا عاديًا. إذا كنت تستخدم nginx-ui في حاوية "
-"Docker، يرجى الرجوع إلى "
-"https://nginxui.com/zh_CN/guide/config-nginx-log.html لمزيد من المعلومات."
+"Docker، يرجى الرجوع إلى https://nginxui.com/zh_CN/guide/config-nginx-log."
+"html لمزيد من المعلومات."
 
 #: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:88
 msgid "Log List"
@@ -2907,22 +2931,22 @@ msgstr "تدوير السجلات"
 
 #: src/views/preference/tabs/LogrotateSettings.vue:13
 msgid ""
-"Logrotate, by default, is enabled in most mainstream Linux distributions "
-"for users who install Nginx UI on the host machine, so you don't need to "
-"modify the parameters on this page. For users who install Nginx UI using "
-"Docker containers, you can manually enable this option. The crontab task "
-"scheduler of Nginx UI will execute the logrotate command at the interval "
-"you set in minutes."
+"Logrotate, by default, is enabled in most mainstream Linux distributions for "
+"users who install Nginx UI on the host machine, so you don't need to modify "
+"the parameters on this page. For users who install Nginx UI using Docker "
+"containers, you can manually enable this option. The crontab task scheduler "
+"of Nginx UI will execute the logrotate command at the interval you set in "
+"minutes."
 msgstr ""
 "بشكل افتراضي، يتم تفعيل تدوير السجلات في معظم توزيعات لينكس الرئيسية "
 "للمستخدمين الذين يقومون بتثبيت واجهة Nginx UI على الجهاز المضيف، لذا لا "
-"تحتاج إلى تعديل معايير في هذه الصفحة. بالنسبة للمستخدمين الذين يقومون "
-"بتثبيت واجهة Nginx UI باستخدام حاويات Docker، يمكنك تمكين هذا الخيار "
-"يدويًا. سيقوم مجدول المهام crontab الخاص بواجهة Nginx UI بتنفيذ أمر تدوير "
-"السجلات في الفاصل الزمني الذي تحدده بالدقائق."
+"تحتاج إلى تعديل معايير في هذه الصفحة. بالنسبة للمستخدمين الذين يقومون بتثبيت "
+"واجهة Nginx UI باستخدام حاويات Docker، يمكنك تمكين هذا الخيار يدويًا. سيقوم "
+"مجدول المهام crontab الخاص بواجهة Nginx UI بتنفيذ أمر تدوير السجلات في "
+"الفاصل الزمني الذي تحدده بالدقائق."
 
 #: src/components/UpstreamDetailModal/UpstreamDetailModal.vue:51
-#: src/composables/useUpstreamStatus.ts:139
+#: src/composables/useUpstreamStatus.ts:156
 msgid "Main Node"
 msgstr "العقدة الرئيسية"
 
@@ -3402,8 +3426,8 @@ msgstr "تمت استعادة تكوين Nginx UI"
 
 #: src/components/SystemRestore/SystemRestoreContent.vue:336
 msgid ""
-"Nginx UI configuration has been restored and will restart automatically in "
-"a few seconds."
+"Nginx UI configuration has been restored and will restart automatically in a "
+"few seconds."
 msgstr "تمت استعادة تكوين Nginx UI وسيتم إعادة التشغيل تلقائيًا خلال بضع ثوانٍ."
 
 #: src/language/generate.ts:28
@@ -3421,7 +3445,7 @@ msgstr "يتضمن Nginx.conf دليل streams-enabled"
 #: src/components/ChatGPT/ChatMessageInput.vue:17
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:111
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:99
-#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:99
+#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:102
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
 #: src/components/Notification/Notification.vue:108 src/language/curd.ts:40
 #: src/views/notification/Notification.vue:38
@@ -3538,11 +3562,13 @@ msgstr "عدد عمليات العامل المتزامنة، يتم الضبط
 
 #: src/views/dashboard/components/ParamsOpt/ProxyCacheConfig.vue:315
 msgid "Number of files processed by cache loader at once"
-msgstr "عدد الملفات التي تتم معالجتها بواسطة محمل ذاكرة التخزين المؤقت في وقت واحد"
+msgstr ""
+"عدد الملفات التي تتم معالجتها بواسطة محمل ذاكرة التخزين المؤقت في وقت واحد"
 
 #: src/views/dashboard/components/ParamsOpt/ProxyCacheConfig.vue:253
 msgid "Number of files processed by cache manager at once"
-msgstr "عدد الملفات التي تتم معالجتها بواسطة مدير ذاكرة التخزين المؤقت في وقت واحد"
+msgstr ""
+"عدد الملفات التي تتم معالجتها بواسطة مدير ذاكرة التخزين المؤقت في وقت واحد"
 
 #: src/composables/usePerformanceMetrics.ts:129
 #: src/composables/usePerformanceMetrics.ts:169
@@ -3819,7 +3845,8 @@ msgstr ""
 msgid ""
 "Please enter a name for the passkey you wish to create and click the OK "
 "button below."
-msgstr "يرجى إدخال اسم لمفتاح المرور الذي ترغب في إنشائه ثم انقر على زر موافق أدناه."
+msgstr ""
+"يرجى إدخال اسم لمفتاح المرور الذي ترغب في إنشائه ثم انقر على زر موافق أدناه."
 
 #: src/components/PortScanner/PortScannerCompact.vue:85
 msgid "Please enter a valid port range"
@@ -3867,8 +3894,8 @@ msgstr ""
 #: src/components/Notification/notifications.ts:194
 #: src/language/constants.ts:59
 msgid ""
-"Please generate new recovery codes in the preferences immediately to "
-"prevent lockout."
+"Please generate new recovery codes in the preferences immediately to prevent "
+"lockout."
 msgstr "يرجى إنشاء رموز استرداد جديدة في التفضيلات على الفور لمنع الإغلاق."
 
 #: src/views/config/components/ConfigRightPanel/Basic.vue:27
@@ -3910,7 +3937,8 @@ msgid "Please log in."
 msgstr "الرجاء تسجيل الدخول."
 
 #: src/views/certificate/DNSCredential.vue:102
-msgid "Please note that the unit of time configurations below are all in seconds."
+msgid ""
+"Please note that the unit of time configurations below are all in seconds."
 msgstr "يرجى ملاحظة أن تكوين وحدات الوقت أدناه كلها بالثواني."
 
 #: src/views/install/components/InstallView.vue:102
@@ -4028,8 +4056,7 @@ msgstr "دليل محمي"
 #: src/views/preference/tabs/ServerSettings.vue:47
 msgid ""
 "Protocol configuration only takes effect when directly connecting. If using "
-"reverse proxy, please configure the protocol separately in the reverse "
-"proxy."
+"reverse proxy, please configure the protocol separately in the reverse proxy."
 msgstr ""
 "إعدادات البروتوكول تتأثر فقط عند الاتصال المباشر. إذا كنت تستخدم خادم وكيل "
 "عكسي، يرجى تكوين البروتوكول بشكل منفصل في خادم الوكيل العكسي."
@@ -4042,11 +4069,11 @@ msgstr "مزود"
 msgid "Provider not found: {0}"
 msgstr "لم يتم العثور على المزود: {0}"
 
-#: src/views/certificate/ACMEUser.vue:48
+#: src/views/certificate/ACMEUser.vue:61
 msgid "Proxy"
 msgstr "وكيل"
 
-#: src/composables/useUpstreamStatus.ts:115
+#: src/composables/useUpstreamStatus.ts:132
 msgid "Proxy Pass"
 msgstr "مرور الوكيل"
 
@@ -4105,21 +4132,21 @@ msgstr "خوادم الأسماء التكرارية"
 msgid "Regenerate response"
 msgstr "إعادة توليد الاستجابة"
 
-#: src/views/certificate/ACMEUser.vue:133
+#: src/views/certificate/ACMEUser.vue:173
 msgid "Register"
 msgstr "تسجيل"
 
-#: src/views/certificate/ACMEUser.vue:53
+#: src/views/certificate/ACMEUser.vue:66
 msgid ""
 "Register a user or use this account to issue a certificate through an HTTP "
 "proxy."
 msgstr "تسجيل مستخدم أو استخدام هذا الحساب لإصدار شهادة عبر وكيل HTTP."
 
-#: src/views/certificate/ACMEUser.vue:101
+#: src/views/certificate/ACMEUser.vue:141
 msgid "Register failed"
 msgstr "فشل التسجيل"
 
-#: src/views/certificate/ACMEUser.vue:72
+#: src/views/certificate/ACMEUser.vue:112
 msgid "Register On Startup"
 msgstr "التسجيل عند بدء التشغيل"
 
@@ -4127,7 +4154,7 @@ msgstr "التسجيل عند بدء التشغيل"
 msgid "Register passkey successfully"
 msgstr "تم تسجيل مفتاح المرور بنجاح"
 
-#: src/views/certificate/ACMEUser.vue:99
+#: src/views/certificate/ACMEUser.vue:139
 msgid "Register successfully"
 msgstr "تم التسجيل بنجاح"
 
@@ -4135,7 +4162,7 @@ msgstr "تم التسجيل بنجاح"
 msgid "Registering user"
 msgstr "تسجيل المستخدم"
 
-#: src/views/certificate/ACMEUser.vue:116
+#: src/views/certificate/ACMEUser.vue:156
 msgid "Registration Status"
 msgstr "حالة التسجيل"
 
@@ -4557,7 +4584,7 @@ msgid "Saturday"
 msgstr "السبت"
 
 #: src/components/ChatGPT/ChatMessage.vue:215
-#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:129
+#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:132
 #: src/language/curd.ts:18
 #: src/views/certificate/components/CertificateActions.vue:29
 #: src/views/config/components/ConfigLeftPanel.vue:282
@@ -4575,10 +4602,6 @@ msgstr "حفظ"
 msgid "Save Directive"
 msgstr "حفظ التوجيه"
 
-#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:45
-msgid "Save error %{msg}"
-msgstr "خطأ في الحفظ %{msg}"
-
 #: src/components/Notification/notifications.ts:145
 #: src/language/constants.ts:48
 msgid "Save Remote Site Error"
@@ -4622,7 +4645,7 @@ msgstr "تم الحفظ بنجاح"
 msgid "Save successfully"
 msgstr "تم الحفظ بنجاح"
 
-#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:43
+#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:48
 #: src/language/curd.ts:28 src/views/config/components/ConfigLeftPanel.vue:198
 #: src/views/site/site_add/SiteAdd.vue:36
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:46
@@ -4697,10 +4720,20 @@ msgstr "رمز الأمان"
 msgid "Security Token Information"
 msgstr "معلومات رمز الأمان"
 
+#: src/views/certificate/ACMEUser.vue:57
+msgid ""
+"Select a predefined CA directory or enter a custom one. Leave blank to use "
+"the default CA directory."
+msgstr ""
+
 #: src/language/curd.ts:31
 msgid "Select all"
 msgstr "تحديد الكل"
 
+#: src/views/certificate/ACMEUser.vue:43
+msgid "Select or enter a CA directory URL"
+msgstr ""
+
 #: src/language/curd.ts:59
 msgid "Selected {count} files"
 msgstr "تم تحديد {count} ملفات"
@@ -4793,19 +4826,19 @@ msgstr "تعيين موفر تحدي HTTP01"
 
 #: src/constants/errors/nginx_log.ts:8
 msgid ""
-"Settings.NginxLogSettings.AccessLogPath is empty, refer to "
-"https://nginxui.com/guide/config-nginx.html for more information"
+"Settings.NginxLogSettings.AccessLogPath is empty, refer to https://nginxui."
+"com/guide/config-nginx.html for more information"
 msgstr ""
-"إعدادات.Settings.NginxLogSettings.AccessLogPath فارغة، راجع "
-"https://nginxui.com/guide/config-nginx.html لمزيد من المعلومات"
+"إعدادات.Settings.NginxLogSettings.AccessLogPath فارغة، راجع https://nginxui."
+"com/guide/config-nginx.html لمزيد من المعلومات"
 
 #: src/constants/errors/nginx_log.ts:7
 msgid ""
-"Settings.NginxLogSettings.ErrorLogPath is empty, refer to "
-"https://nginxui.com/guide/config-nginx.html for more information"
+"Settings.NginxLogSettings.ErrorLogPath is empty, refer to https://nginxui."
+"com/guide/config-nginx.html for more information"
 msgstr ""
-"إعدادات.Settings.NginxLogSettings.ErrorLogPath فارغة، راجع "
-"https://nginxui.com/guide/config-nginx.html لمزيد من المعلومات"
+"إعدادات.Settings.NginxLogSettings.ErrorLogPath فارغة، راجع https://nginxui."
+"com/guide/config-nginx.html لمزيد من المعلومات"
 
 #: src/views/install/components/InstallView.vue:65
 msgid "Setup your Nginx UI"
@@ -4954,7 +4987,7 @@ msgstr "ثابت"
 
 #: src/components/PortScanner/PortScannerCompact.vue:37
 #: src/views/backup/AutoBackup/AutoBackup.vue:160
-#: src/views/certificate/ACMEUser.vue:60
+#: src/views/certificate/ACMEUser.vue:73
 #: src/views/certificate/CertificateList/certColumns.tsx:63
 #: src/views/dashboard/components/ModulesTable.vue:96
 #: src/views/environments/list/envColumns.tsx:43
@@ -5046,19 +5079,19 @@ msgstr "الأحد"
 msgid ""
 "Support communication with the backend through the Server-Sent Events "
 "protocol. If your Nginx UI is being used via an Nginx reverse proxy, please "
-"refer to this link to write the corresponding configuration file: "
-"https://nginxui.com/guide/nginx-proxy-example.html"
+"refer to this link to write the corresponding configuration file: https://"
+"nginxui.com/guide/nginx-proxy-example.html"
 msgstr ""
 "دعم الاتصال مع الخلفية من خلال بروتوكول Server-Sent Events. إذا كنت تستخدم "
-"واجهة Nginx UI عبر وكيل عكسي لـ Nginx، يرجى الرجوع إلى هذا الرابط لكتابة "
-"ملف التكوين المقابل: https://nginxui.com/guide/nginx-proxy-example.html"
+"واجهة Nginx UI عبر وكيل عكسي لـ Nginx، يرجى الرجوع إلى هذا الرابط لكتابة ملف "
+"التكوين المقابل: https://nginxui.com/guide/nginx-proxy-example.html"
 
 #: src/components/SelfCheck/tasks/frontend/websocket.ts:13
 msgid ""
 "Support communication with the backend through the WebSocket protocol. If "
-"your Nginx UI is being used via an Nginx reverse proxy, please refer to "
-"this link to write the corresponding configuration file: "
-"https://nginxui.com/guide/nginx-proxy-example.html"
+"your Nginx UI is being used via an Nginx reverse proxy, please refer to this "
+"link to write the corresponding configuration file: https://nginxui.com/"
+"guide/nginx-proxy-example.html"
 msgstr ""
 "دعم الاتصال مع الخلفية من خلال بروتوكول WebSocket. إذا كنت تستخدم واجهة "
 "Nginx عبر وكيل عكسي لـ Nginx، يرجى الرجوع إلى هذا الرابط لكتابة ملف التكوين "
@@ -5229,7 +5262,8 @@ msgstr ""
 msgid ""
 "The ICP Number should only contain letters, unicode, numbers, hyphens, "
 "dashes, colons, and dots."
-msgstr "يجب أن يحتوي رقم ICP على أحرف، يونيكود، أرقام، شرطات، نقاط، ونقطتين فقط."
+msgstr ""
+"يجب أن يحتوي رقم ICP على أحرف، يونيكود، أرقام، شرطات، نقاط، ونقطتين فقط."
 
 #: src/views/certificate/components/CertificateContentEditor.vue:96
 msgid "The input is not a SSL Certificate"
@@ -5241,11 +5275,10 @@ msgstr "المدخل ليس مفتاح شهادة SSL"
 
 #: src/constants/errors/nginx_log.ts:2
 msgid ""
-"The log path is not under the paths in "
-"settings.NginxSettings.LogDirWhiteList"
+"The log path is not under the paths in settings.NginxSettings.LogDirWhiteList"
 msgstr ""
-"مسار السجل ليس ضمن المسارات الموجودة في "
-"settings.NginxSettings.LogDirWhiteList"
+"مسار السجل ليس ضمن المسارات الموجودة في settings.NginxSettings."
+"LogDirWhiteList"
 
 #: src/views/preference/tabs/OpenAISettings.vue:23
 #: src/views/preference/tabs/OpenAISettings.vue:89
@@ -5257,7 +5290,8 @@ msgstr ""
 "فقط."
 
 #: src/views/preference/tabs/OpenAISettings.vue:90
-msgid "The model used for code completion, if not set, the chat model will be used."
+msgid ""
+"The model used for code completion, if not set, the chat model will be used."
 msgstr ""
 "النموذج المستخدم لإكمال التعليمات البرمجية، إذا لم يتم تعيينه، سيتم استخدام "
 "نموذج الدردشة."
@@ -5266,7 +5300,8 @@ msgstr ""
 msgid ""
 "The node name should only contain letters, unicode, numbers, hyphens, "
 "dashes, colons, and dots."
-msgstr "يجب أن يحتوي اسم العقدة على أحرف، يونيكود، أرقام، شرطات، نقاط، ونقطتين فقط."
+msgstr ""
+"يجب أن يحتوي اسم العقدة على أحرف، يونيكود، أرقام، شرطات، نقاط، ونقطتين فقط."
 
 #: src/views/site/site_add/SiteAdd.vue:96
 msgid "The parameter of server_name is required"
@@ -5368,13 +5403,14 @@ msgid "This field should not be empty"
 msgstr "يجب ألا يكون هذا الحقل فارغًا"
 
 #: src/constants/form_errors.ts:6
-msgid "This field should only contain letters, unicode characters, numbers, and -_."
+msgid ""
+"This field should only contain letters, unicode characters, numbers, and -_."
 msgstr "يجب أن يحتوي هذا الحقل على حروف وأحرف يونيكود وأرقام و-_. فقط."
 
 #: src/language/curd.ts:46
 msgid ""
-"This field should only contain letters, unicode characters, numbers, and "
-"-_./:"
+"This field should only contain letters, unicode characters, numbers, and -"
+"_./:"
 msgstr "يجب أن يحتوي هذا الحقل فقط على أحرف وأحرف يونيكود وأرقام و -_./:"
 
 #: src/components/Notification/notifications.ts:94
@@ -5386,8 +5422,8 @@ msgid ""
 "This module provides Nginx request statistics, connection count, etc. data. "
 "After enabling it, you can view performance statistics"
 msgstr ""
-"توفر هذه الوحدة إحصائيات طلبات Nginx وعدد الاتصالات وما إلى ذلك من "
-"البيانات. بعد تمكينها، يمكنك عرض إحصائيات الأداء"
+"توفر هذه الوحدة إحصائيات طلبات Nginx وعدد الاتصالات وما إلى ذلك من البيانات. "
+"بعد تمكينها، يمكنك عرض إحصائيات الأداء"
 
 #: src/views/certificate/components/RemoveCert.vue:106
 msgid ""
@@ -5428,11 +5464,12 @@ msgid ""
 "This will restore configuration files and database. Nginx UI will restart "
 "after the restoration is complete."
 msgstr ""
-"سيؤدي هذا إلى استعادة ملفات التكوين وقاعدة البيانات. سيعاد تشغيل واجهة "
-"Nginx بعد اكتمال الاستعادة."
+"سيؤدي هذا إلى استعادة ملفات التكوين وقاعدة البيانات. سيعاد تشغيل واجهة Nginx "
+"بعد اكتمال الاستعادة."
 
 #: src/views/environments/list/BatchUpgrader.vue:186
-msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
+msgid ""
+"This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
 msgstr "سيتم ترقية أو إعادة تثبيت Nginx UI على %{nodeNames} إلى %{version}."
 
 #: src/views/preference/tabs/AuthSettings.vue:92
@@ -5486,8 +5523,8 @@ msgstr ""
 #: src/views/site/site_edit/components/EnableTLS/EnableTLS.vue:15
 msgid ""
 "To make sure the certification auto-renewal can work normally, we need to "
-"add a location which can proxy the request from authority to backend, and "
-"we need to save this file and reload the Nginx. Are you sure you want to "
+"add a location which can proxy the request from authority to backend, and we "
+"need to save this file and reload the Nginx. Are you sure you want to "
 "continue?"
 msgstr ""
 "لضمان عمل تجديد الشهادة التلقائي بشكل طبيعي، نحتاج إلى إضافة موقع يمكنه "
@@ -5500,9 +5537,9 @@ msgid ""
 "provide an OpenAI-compatible API endpoint, so just set the baseUrl to your "
 "local API."
 msgstr ""
-"لاستخدام نموذج كبير محلي، قم بنشره باستخدام ollama أو vllm أو lmdeploy. "
-"توفر هذه الأدوات نقطة نهاية API متوافقة مع OpenAI، لذا ما عليك سوى تعيين "
-"baseUrl إلى API المحلي الخاص بك."
+"لاستخدام نموذج كبير محلي، قم بنشره باستخدام ollama أو vllm أو lmdeploy. توفر "
+"هذه الأدوات نقطة نهاية API متوافقة مع OpenAI، لذا ما عليك سوى تعيين baseUrl "
+"إلى API المحلي الخاص بك."
 
 #: src/views/dashboard/NginxDashBoard.vue:57
 msgid "Toggle failed"
@@ -5579,7 +5616,7 @@ msgstr "الثلاثاء"
 msgid "Two-factor authentication required"
 msgstr "يتطلب المصادقة الثنائية"
 
-#: src/composables/useUpstreamStatus.ts:115
+#: src/composables/useUpstreamStatus.ts:132
 #: src/views/certificate/CertificateList/certColumns.tsx:24
 #: src/views/config/components/Delete.vue:122
 #: src/views/dashboard/components/ModulesTable.vue:83
@@ -5615,7 +5652,7 @@ msgid "Update successfully"
 msgstr "تم التحديث بنجاح"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:236
-#: src/views/certificate/ACMEUser.vue:83
+#: src/views/certificate/ACMEUser.vue:123
 #: src/views/certificate/DNSCredential.vue:65
 #: src/views/config/components/ConfigRightPanel/Basic.vue:54
 #: src/views/config/configColumns.tsx:43
@@ -5660,7 +5697,7 @@ msgstr "تحميل الملفات"
 msgid "Upload Folders"
 msgstr "تحميل المجلدات"
 
-#: src/composables/useUpstreamStatus.ts:115
+#: src/composables/useUpstreamStatus.ts:132
 msgid "Upstream"
 msgstr "أعلى التيار"
 
@@ -5726,7 +5763,7 @@ msgid "Username length cannot exceed 255 characters"
 msgstr "يجب ألا يتجاوز طول اسم المستخدم 255 حرفًا"
 
 #: src/components/CertInfo/CertInfo.vue:24
-#: src/views/certificate/ACMEUser.vue:120
+#: src/views/certificate/ACMEUser.vue:160
 #: src/views/certificate/CertificateList/certColumns.tsx:76
 msgid "Valid"
 msgstr "صالح"
@@ -5789,8 +5826,8 @@ msgid ""
 "you have a valid backup file and security token, and carefully select what "
 "to restore."
 msgstr ""
-"تحذير: ستقوم عملية الاستعادة بالكتابة فوق التكوينات الحالية. تأكد من أن "
-"لديك ملف نسخ احتياطي صالحًا ورمزًا أمنيًا، واختر بعناية ما تريد استعادته."
+"تحذير: ستقوم عملية الاستعادة بالكتابة فوق التكوينات الحالية. تأكد من أن لديك "
+"ملف نسخ احتياطي صالحًا ورمزًا أمنيًا، واختر بعناية ما تريد استعادته."
 
 #: src/views/certificate/DNSCredential.vue:96
 msgid ""
@@ -5800,8 +5837,8 @@ msgstr "سنضيف سجل أو أكثر من سجلات TXT إلى سجلات DN
 
 #: src/views/site/site_edit/components/Cert/ObtainCert.vue:140
 msgid ""
-"We will remove the HTTPChallenge configuration from this file and reload "
-"the Nginx. Are you sure you want to continue?"
+"We will remove the HTTPChallenge configuration from this file and reload the "
+"Nginx. Are you sure you want to continue?"
 msgstr ""
 "سنقوم بإزالة تكوين HTTPChallenge من هذا الملف وإعادة تحميل Nginx. هل أنت "
 "متأكد أنك تريد المتابعة؟"
@@ -5830,7 +5867,7 @@ msgstr "أسبوعي"
 msgid "Weekly on %{day} at %{time}"
 msgstr "أسبوعيًا يوم %{day} الساعة %{time}"
 
-#: src/views/certificate/ACMEUser.vue:78
+#: src/views/certificate/ACMEUser.vue:118
 msgid ""
 "When Enabled, Nginx UI will automatically re-register users upon startup. "
 "Generally, do not enable this unless you are in a dev environment and using "
@@ -5906,7 +5943,7 @@ msgstr "كتابة الشهادة إلى القرص"
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:110
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:98
-#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:98
+#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:101
 #: src/components/NgxConfigEditor/LocationEditor.vue:88
 #: src/views/preference/tabs/AuthSettings.vue:131
 #: src/views/preference/tabs/CertSettings.vue:72
@@ -5915,11 +5952,11 @@ msgstr "نعم"
 
 #: src/views/terminal/Terminal.vue:132
 msgid ""
-"You are accessing this terminal over an insecure HTTP connection on a "
-"non-localhost domain. This may expose sensitive information."
+"You are accessing this terminal over an insecure HTTP connection on a non-"
+"localhost domain. This may expose sensitive information."
 msgstr ""
-"أنت تتصل بهذا الطرف عبر اتصال HTTP غير آمن في نطاق غير محلي. قد يؤدي هذا "
-"إلى كشف معلومات حساسة."
+"أنت تتصل بهذا الطرف عبر اتصال HTTP غير آمن في نطاق غير محلي. قد يؤدي هذا إلى "
+"كشف معلومات حساسة."
 
 #: src/constants/errors/config.ts:8
 msgid "You are not allowed to delete a file outside of the nginx config path"
@@ -5948,7 +5985,8 @@ msgid ""
 msgstr "لم تقم بتكوين إعدادات Webauthn، لذا لا يمكنك إضافة مفتاح مرور."
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:81
-msgid "You have not enabled 2FA yet. Please enable 2FA to generate recovery codes."
+msgid ""
+"You have not enabled 2FA yet. Please enable 2FA to generate recovery codes."
 msgstr ""
 "لم تقم بتمكين المصادقة الثنائية بعد. يرجى تمكين المصادقة الثنائية لإنشاء "
 "رموز الاسترداد."
@@ -5974,6 +6012,12 @@ msgstr "رموزك القديمة لن تعمل بعد الآن."
 msgid "Your passkeys"
 msgstr "مفاتيح المرور الخاصة بك"
 
+#~ msgid "If left blank, the default CA Dir will be used."
+#~ msgstr "إذا تُرك فارغًا، سيتم استخدام دليل CA الافتراضي."
+
+#~ msgid "Save error %{msg}"
+#~ msgstr "خطأ في الحفظ %{msg}"
+
 #~ msgid "Main"
 #~ msgstr "رئيسي"
 
@@ -6064,12 +6108,12 @@ msgstr "مفاتيح المرور الخاصة بك"
 
 #~ msgid ""
 #~ "Check if /var/run/docker.sock exists. If you are using Nginx UI Official "
-#~ "Docker Image, please make sure the docker socket is mounted like this: `-v "
-#~ "/var/run/docker.sock:/var/run/docker.sock`."
+#~ "Docker Image, please make sure the docker socket is mounted like this: `-"
+#~ "v /var/run/docker.sock:/var/run/docker.sock`."
 #~ msgstr ""
 #~ "تحقق مما إذا كان /var/run/docker.sock موجودًا. إذا كنت تستخدم صورة Docker "
-#~ "الرسمية لـ Nginx UI، يرجى التأكد من أن مقبس Docker مثبت بهذه الطريقة: `-v "
-#~ "/var/run/docker.sock:/var/run/docker.sock`."
+#~ "الرسمية لـ Nginx UI، يرجى التأكد من أن مقبس Docker مثبت بهذه الطريقة: `-"
+#~ "v /var/run/docker.sock:/var/run/docker.sock`."
 
 #~ msgid "Check if the nginx access log path exists"
 #~ msgstr "تحقق مما إذا كان مسار سجل الوصول لـ nginx موجودًا"
@@ -6108,8 +6152,8 @@ msgstr "مفاتيح المرور الخاصة بك"
 
 #, fuzzy
 #~ msgid ""
-#~ "When you enable/disable, delete, or save this stream, the nodes set in the "
-#~ "Node Group and the nodes selected below will be synchronized."
+#~ "When you enable/disable, delete, or save this stream, the nodes set in "
+#~ "the Node Group and the nodes selected below will be synchronized."
 #~ msgstr ""
 #~ "عند تفعيل/تعطيل، حذف، أو حفظ هذا الموقع، سيتم مزامنة العقد المحددة في فئة "
 #~ "الموقع والعقد المحددة أدناه."
@@ -6176,12 +6220,15 @@ msgstr "مفاتيح المرور الخاصة بك"
 #~ msgid "Please upgrade the remote Nginx UI to the latest version"
 #~ msgstr "يرجى ترقية واجهة Nginx البعيدة إلى أحدث إصدار"
 
-#~ msgid "Rename %{orig_path} to %{new_path} on %{env_name} failed, response: %{resp}"
+#~ msgid ""
+#~ "Rename %{orig_path} to %{new_path} on %{env_name} failed, response: "
+#~ "%{resp}"
 #~ msgstr ""
 #~ "فشل إعادة تسمية %{orig_path} إلى %{new_path} على %{env_name}، الاستجابة: "
 #~ "%{resp}"
 
-#~ msgid "Rename Site %{site} to %{new_site} on %{node} error, response: %{resp}"
+#~ msgid ""
+#~ "Rename Site %{site} to %{new_site} on %{node} error, response: %{resp}"
 #~ msgstr ""
 #~ "خطأ في إعادة تسمية الموقع %{site} إلى %{new_site} على %{node}، الاستجابة: "
 #~ "%{resp}"
@@ -6196,15 +6243,17 @@ msgstr "مفاتيح المرور الخاصة بك"
 #~ "فشل مزامنة الشهادة %{cert_name} إلى %{env_name}، يرجى ترقية واجهة Nginx "
 #~ "البعيدة إلى أحدث إصدار"
 
-#~ msgid "Sync Certificate %{cert_name} to %{env_name} failed, response: %{resp}"
+#~ msgid ""
+#~ "Sync Certificate %{cert_name} to %{env_name} failed, response: %{resp}"
 #~ msgstr "فشل مزامنة الشهادة %{cert_name} إلى %{env_name}، الاستجابة: %{resp}"
 
 #~ msgid "Sync config %{config_name} to %{env_name} failed, response: %{resp}"
-#~ msgstr "فشل مزامنة التكوين %{config_name} إلى %{env_name}، الاستجابة: %{resp}"
+#~ msgstr ""
+#~ "فشل مزامنة التكوين %{config_name} إلى %{env_name}، الاستجابة: %{resp}"
 
 #~ msgid ""
-#~ "If you lose your mobile phone, you can use the recovery code to reset your "
-#~ "2FA."
+#~ "If you lose your mobile phone, you can use the recovery code to reset "
+#~ "your 2FA."
 #~ msgstr ""
 #~ "إذا فقدت هاتفك المحمول، يمكنك استخدام رمز الاسترداد لإعادة تعيين المصادقة "
 #~ "الثنائية."
@@ -6212,7 +6261,8 @@ msgstr "مفاتيح المرور الخاصة بك"
 #~ msgid "Recovery Code:"
 #~ msgstr "رمز الاسترداد:"
 
-#~ msgid "The recovery code is only displayed once, please save it in a safe place."
+#~ msgid ""
+#~ "The recovery code is only displayed once, please save it in a safe place."
 #~ msgstr "رمز الاسترداد يُعرض مرة واحدة فقط، يرجى حفظه في مكان آمن."
 
 #~ msgid "Can't scan? Use text key binding"
@@ -6222,4 +6272,5 @@ msgstr "مفاتيح المرور الخاصة بك"
 #~ msgstr "اسم المستخدم أو كلمة المرور غير صحيحة"
 
 #~ msgid "Too many login failed attempts, please try again later"
-#~ msgstr "عدد كبير جدًا من محاولات تسجيل الدخول الفاشلة، يرجى المحاولة مرة أخرى لاحقًا"
+#~ msgstr ""
+#~ "عدد كبير جدًا من محاولات تسجيل الدخول الفاشلة، يرجى المحاولة مرة أخرى لاحقًا"

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 231 - 173
app/src/language/de_DE/app.po


+ 60 - 34
app/src/language/en/app.po

@@ -112,7 +112,7 @@ msgstr ""
 msgid "Access Logs"
 msgstr ""
 
-#: src/routes/modules/certificates.ts:20 src/views/certificate/ACMEUser.vue:108
+#: src/routes/modules/certificates.ts:20 src/views/certificate/ACMEUser.vue:148
 #: src/views/certificate/components/ACMEUserSelector.vue:52
 msgid "ACME User"
 msgstr ""
@@ -122,7 +122,7 @@ msgid "Action"
 msgstr ""
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:273
-#: src/views/certificate/ACMEUser.vue:90
+#: src/views/certificate/ACMEUser.vue:130
 #: src/views/certificate/CertificateList/certColumns.tsx:92
 #: src/views/certificate/DNSCredential.vue:71
 #: src/views/config/configColumns.tsx:50
@@ -291,7 +291,7 @@ msgstr ""
 msgid "Are you sure you want to reload Nginx on the following sync nodes?"
 msgstr ""
 
-#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:97
+#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:100
 msgid "Are you sure you want to remove this directive?"
 msgstr ""
 
@@ -956,7 +956,7 @@ msgstr ""
 msgid "Command exited with unexpected exit code: {0}, error: {1}"
 msgstr ""
 
-#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
+#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:118
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
 #: src/components/NgxConfigEditor/NgxServer.vue:123
@@ -1055,7 +1055,7 @@ msgstr ""
 msgid "Container status unknown"
 msgstr ""
 
-#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
+#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:123
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
 msgid "Content"
@@ -1598,6 +1598,14 @@ msgstr ""
 msgid "e.g., 0 0 * * * (daily at midnight)"
 msgstr ""
 
+#: src/views/certificate/ACMEUser.vue:98
+msgid "EAB HMAC Key"
+msgstr ""
+
+#: src/views/certificate/ACMEUser.vue:85
+msgid "EAB Key ID"
+msgstr ""
+
 #: src/language/curd.ts:8
 msgid "Edit"
 msgstr ""
@@ -1843,6 +1851,18 @@ msgstr ""
 msgid "Export Excel"
 msgstr ""
 
+#: src/views/certificate/ACMEUser.vue:103
+msgid ""
+"External Account Binding HMAC Key (optional). Should be in Base64 URL "
+"encoding format."
+msgstr ""
+
+#: src/views/certificate/ACMEUser.vue:90
+msgid ""
+"External Account Binding Key ID (optional). Required for some ACME providers "
+"like ZeroSSL."
+msgstr ""
+
 #: src/views/preference/tabs/NginxSettings.vue:49
 msgid "External Docker Container"
 msgstr ""
@@ -2426,10 +2446,6 @@ msgstr ""
 msgid "ICP Number"
 msgstr ""
 
-#: src/views/certificate/ACMEUser.vue:43
-msgid "If left blank, the default CA Dir will be used."
-msgstr ""
-
 #: src/views/preference/tabs/AuthSettings.vue:113
 msgid ""
 "If the number of login failed attempts from a ip reach the max attempts in "
@@ -2532,7 +2548,7 @@ msgstr ""
 msgid "Interval"
 msgstr ""
 
-#: src/views/certificate/ACMEUser.vue:125
+#: src/views/certificate/ACMEUser.vue:165
 msgid "Invalid"
 msgstr ""
 
@@ -2698,7 +2714,11 @@ msgstr ""
 msgid "Leave blank if do not want to modify"
 msgstr ""
 
-#: src/views/certificate/ACMEUser.vue:55
+#: src/views/certificate/ACMEUser.vue:105 src/views/certificate/ACMEUser.vue:92
+msgid "Leave blank if not required by your ACME provider"
+msgstr ""
+
+#: src/views/certificate/ACMEUser.vue:68
 msgid "Leave blank if you don't need this."
 msgstr ""
 
@@ -2834,7 +2854,7 @@ msgid ""
 msgstr ""
 
 #: src/components/UpstreamDetailModal/UpstreamDetailModal.vue:51
-#: src/composables/useUpstreamStatus.ts:139
+#: src/composables/useUpstreamStatus.ts:156
 msgid "Main Node"
 msgstr ""
 
@@ -3331,7 +3351,7 @@ msgstr ""
 #: src/components/ChatGPT/ChatMessageInput.vue:17
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:111
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:99
-#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:99
+#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:102
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
 #: src/components/Notification/Notification.vue:108 src/language/curd.ts:40
 #: src/views/notification/Notification.vue:38
@@ -3939,11 +3959,11 @@ msgstr ""
 msgid "Provider not found: {0}"
 msgstr ""
 
-#: src/views/certificate/ACMEUser.vue:48
+#: src/views/certificate/ACMEUser.vue:61
 msgid "Proxy"
 msgstr ""
 
-#: src/composables/useUpstreamStatus.ts:115
+#: src/composables/useUpstreamStatus.ts:132
 msgid "Proxy Pass"
 msgstr ""
 
@@ -4000,21 +4020,21 @@ msgstr ""
 msgid "Regenerate response"
 msgstr ""
 
-#: src/views/certificate/ACMEUser.vue:133
+#: src/views/certificate/ACMEUser.vue:173
 msgid "Register"
 msgstr ""
 
-#: src/views/certificate/ACMEUser.vue:53
+#: src/views/certificate/ACMEUser.vue:66
 msgid ""
 "Register a user or use this account to issue a certificate through an HTTP "
 "proxy."
 msgstr ""
 
-#: src/views/certificate/ACMEUser.vue:101
+#: src/views/certificate/ACMEUser.vue:141
 msgid "Register failed"
 msgstr ""
 
-#: src/views/certificate/ACMEUser.vue:72
+#: src/views/certificate/ACMEUser.vue:112
 msgid "Register On Startup"
 msgstr ""
 
@@ -4022,7 +4042,7 @@ msgstr ""
 msgid "Register passkey successfully"
 msgstr ""
 
-#: src/views/certificate/ACMEUser.vue:99
+#: src/views/certificate/ACMEUser.vue:139
 msgid "Register successfully"
 msgstr ""
 
@@ -4030,7 +4050,7 @@ msgstr ""
 msgid "Registering user"
 msgstr ""
 
-#: src/views/certificate/ACMEUser.vue:116
+#: src/views/certificate/ACMEUser.vue:156
 msgid "Registration Status"
 msgstr ""
 
@@ -4448,7 +4468,7 @@ msgid "Saturday"
 msgstr ""
 
 #: src/components/ChatGPT/ChatMessage.vue:215
-#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:129
+#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:132
 #: src/language/curd.ts:18
 #: src/views/certificate/components/CertificateActions.vue:29
 #: src/views/config/components/ConfigLeftPanel.vue:282
@@ -4466,10 +4486,6 @@ msgstr ""
 msgid "Save Directive"
 msgstr ""
 
-#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:45
-msgid "Save error %{msg}"
-msgstr ""
-
 #: src/components/Notification/notifications.ts:145
 #: src/language/constants.ts:48
 msgid "Save Remote Site Error"
@@ -4513,7 +4529,7 @@ msgstr ""
 msgid "Save successfully"
 msgstr ""
 
-#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:43
+#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:48
 #: src/language/curd.ts:28 src/views/config/components/ConfigLeftPanel.vue:198
 #: src/views/site/site_add/SiteAdd.vue:36
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:46
@@ -4588,10 +4604,20 @@ msgstr ""
 msgid "Security Token Information"
 msgstr ""
 
+#: src/views/certificate/ACMEUser.vue:57
+msgid ""
+"Select a predefined CA directory or enter a custom one. Leave blank to use "
+"the default CA directory."
+msgstr ""
+
 #: src/language/curd.ts:31
 msgid "Select all"
 msgstr ""
 
+#: src/views/certificate/ACMEUser.vue:43
+msgid "Select or enter a CA directory URL"
+msgstr ""
+
 #: src/language/curd.ts:59
 msgid "Selected {count} files"
 msgstr ""
@@ -4839,7 +4865,7 @@ msgstr ""
 
 #: src/components/PortScanner/PortScannerCompact.vue:37
 #: src/views/backup/AutoBackup/AutoBackup.vue:160
-#: src/views/certificate/ACMEUser.vue:60
+#: src/views/certificate/ACMEUser.vue:73
 #: src/views/certificate/CertificateList/certColumns.tsx:63
 #: src/views/dashboard/components/ModulesTable.vue:96
 #: src/views/environments/list/envColumns.tsx:43
@@ -5417,7 +5443,7 @@ msgstr ""
 msgid "Two-factor authentication required"
 msgstr ""
 
-#: src/composables/useUpstreamStatus.ts:115
+#: src/composables/useUpstreamStatus.ts:132
 #: src/views/certificate/CertificateList/certColumns.tsx:24
 #: src/views/config/components/Delete.vue:122
 #: src/views/dashboard/components/ModulesTable.vue:83
@@ -5453,7 +5479,7 @@ msgid "Update successfully"
 msgstr ""
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:236
-#: src/views/certificate/ACMEUser.vue:83
+#: src/views/certificate/ACMEUser.vue:123
 #: src/views/certificate/DNSCredential.vue:65
 #: src/views/config/components/ConfigRightPanel/Basic.vue:54
 #: src/views/config/configColumns.tsx:43
@@ -5498,7 +5524,7 @@ msgstr ""
 msgid "Upload Folders"
 msgstr ""
 
-#: src/composables/useUpstreamStatus.ts:115
+#: src/composables/useUpstreamStatus.ts:132
 msgid "Upstream"
 msgstr ""
 
@@ -5564,7 +5590,7 @@ msgid "Username length cannot exceed 255 characters"
 msgstr ""
 
 #: src/components/CertInfo/CertInfo.vue:24
-#: src/views/certificate/ACMEUser.vue:120
+#: src/views/certificate/ACMEUser.vue:160
 #: src/views/certificate/CertificateList/certColumns.tsx:76
 msgid "Valid"
 msgstr ""
@@ -5664,7 +5690,7 @@ msgstr ""
 msgid "Weekly on %{day} at %{time}"
 msgstr ""
 
-#: src/views/certificate/ACMEUser.vue:78
+#: src/views/certificate/ACMEUser.vue:118
 msgid ""
 "When Enabled, Nginx UI will automatically re-register users upon startup. "
 "Generally, do not enable this unless you are in a dev environment and using "
@@ -5735,7 +5761,7 @@ msgstr ""
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:110
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:98
-#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:98
+#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:101
 #: src/components/NgxConfigEditor/LocationEditor.vue:88
 #: src/views/preference/tabs/AuthSettings.vue:131
 #: src/views/preference/tabs/CertSettings.vue:72

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 224 - 173
app/src/language/es/app.po


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 235 - 184
app/src/language/fr_FR/app.po


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 291 - 168
app/src/language/ja_JP/app.po


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 280 - 165
app/src/language/ko_KR/app.po


+ 55 - 34
app/src/language/messages.pot

@@ -116,7 +116,7 @@ msgid "Access Logs"
 msgstr ""
 
 #: src/routes/modules/certificates.ts:20
-#: src/views/certificate/ACMEUser.vue:108
+#: src/views/certificate/ACMEUser.vue:148
 #: src/views/certificate/components/ACMEUserSelector.vue:52
 msgid "ACME User"
 msgstr ""
@@ -126,7 +126,7 @@ msgid "Action"
 msgstr ""
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:273
-#: src/views/certificate/ACMEUser.vue:90
+#: src/views/certificate/ACMEUser.vue:130
 #: src/views/certificate/CertificateList/certColumns.tsx:92
 #: src/views/certificate/DNSCredential.vue:71
 #: src/views/config/configColumns.tsx:50
@@ -298,7 +298,7 @@ msgstr ""
 msgid "Are you sure you want to reload Nginx on the following sync nodes?"
 msgstr ""
 
-#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:97
+#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:100
 msgid "Are you sure you want to remove this directive?"
 msgstr ""
 
@@ -934,7 +934,7 @@ msgstr ""
 msgid "Command exited with unexpected exit code: {0}, error: {1}"
 msgstr ""
 
-#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
+#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:118
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
 #: src/components/NgxConfigEditor/NgxServer.vue:123
@@ -1033,7 +1033,7 @@ msgstr ""
 msgid "Container status unknown"
 msgstr ""
 
-#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
+#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:123
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
 msgid "Content"
@@ -1576,6 +1576,14 @@ msgstr ""
 msgid "e.g., 0 0 * * * (daily at midnight)"
 msgstr ""
 
+#: src/views/certificate/ACMEUser.vue:98
+msgid "EAB HMAC Key"
+msgstr ""
+
+#: src/views/certificate/ACMEUser.vue:85
+msgid "EAB Key ID"
+msgstr ""
+
 #: src/language/curd.ts:8
 msgid "Edit"
 msgstr ""
@@ -1823,6 +1831,14 @@ msgstr ""
 msgid "Export Excel"
 msgstr ""
 
+#: src/views/certificate/ACMEUser.vue:103
+msgid "External Account Binding HMAC Key (optional). Should be in Base64 URL encoding format."
+msgstr ""
+
+#: src/views/certificate/ACMEUser.vue:90
+msgid "External Account Binding Key ID (optional). Required for some ACME providers like ZeroSSL."
+msgstr ""
+
 #: src/views/preference/tabs/NginxSettings.vue:49
 msgid "External Docker Container"
 msgstr ""
@@ -2405,10 +2421,6 @@ msgstr ""
 msgid "ICP Number"
 msgstr ""
 
-#: src/views/certificate/ACMEUser.vue:43
-msgid "If left blank, the default CA Dir will be used."
-msgstr ""
-
 #: src/views/preference/tabs/AuthSettings.vue:113
 msgid "If the number of login failed attempts from a ip reach the max attempts in ban threshold minutes, the ip will be banned for a period of time."
 msgstr ""
@@ -2502,7 +2514,7 @@ msgstr ""
 msgid "Interval"
 msgstr ""
 
-#: src/views/certificate/ACMEUser.vue:125
+#: src/views/certificate/ACMEUser.vue:165
 msgid "Invalid"
 msgstr ""
 
@@ -2666,7 +2678,12 @@ msgstr ""
 msgid "Leave blank if do not want to modify"
 msgstr ""
 
-#: src/views/certificate/ACMEUser.vue:55
+#: src/views/certificate/ACMEUser.vue:105
+#: src/views/certificate/ACMEUser.vue:92
+msgid "Leave blank if not required by your ACME provider"
+msgstr ""
+
+#: src/views/certificate/ACMEUser.vue:68
 msgid "Leave blank if you don't need this."
 msgstr ""
 
@@ -2796,7 +2813,7 @@ msgid "Logrotate, by default, is enabled in most mainstream Linux distributions
 msgstr ""
 
 #: src/components/UpstreamDetailModal/UpstreamDetailModal.vue:51
-#: src/composables/useUpstreamStatus.ts:139
+#: src/composables/useUpstreamStatus.ts:156
 msgid "Main Node"
 msgstr ""
 
@@ -3297,7 +3314,7 @@ msgstr ""
 #: src/components/ChatGPT/ChatMessageInput.vue:17
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:111
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:99
-#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:99
+#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:102
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
 #: src/components/Notification/Notification.vue:108
 #: src/language/curd.ts:40
@@ -3891,11 +3908,11 @@ msgstr ""
 msgid "Provider not found: {0}"
 msgstr ""
 
-#: src/views/certificate/ACMEUser.vue:48
+#: src/views/certificate/ACMEUser.vue:61
 msgid "Proxy"
 msgstr ""
 
-#: src/composables/useUpstreamStatus.ts:115
+#: src/composables/useUpstreamStatus.ts:132
 msgid "Proxy Pass"
 msgstr ""
 
@@ -3952,19 +3969,19 @@ msgstr ""
 msgid "Regenerate response"
 msgstr ""
 
-#: src/views/certificate/ACMEUser.vue:133
+#: src/views/certificate/ACMEUser.vue:173
 msgid "Register"
 msgstr ""
 
-#: src/views/certificate/ACMEUser.vue:53
+#: src/views/certificate/ACMEUser.vue:66
 msgid "Register a user or use this account to issue a certificate through an HTTP proxy."
 msgstr ""
 
-#: src/views/certificate/ACMEUser.vue:101
+#: src/views/certificate/ACMEUser.vue:141
 msgid "Register failed"
 msgstr ""
 
-#: src/views/certificate/ACMEUser.vue:72
+#: src/views/certificate/ACMEUser.vue:112
 msgid "Register On Startup"
 msgstr ""
 
@@ -3972,7 +3989,7 @@ msgstr ""
 msgid "Register passkey successfully"
 msgstr ""
 
-#: src/views/certificate/ACMEUser.vue:99
+#: src/views/certificate/ACMEUser.vue:139
 msgid "Register successfully"
 msgstr ""
 
@@ -3980,7 +3997,7 @@ msgstr ""
 msgid "Registering user"
 msgstr ""
 
-#: src/views/certificate/ACMEUser.vue:116
+#: src/views/certificate/ACMEUser.vue:156
 msgid "Registration Status"
 msgstr ""
 
@@ -4397,7 +4414,7 @@ msgid "Saturday"
 msgstr ""
 
 #: src/components/ChatGPT/ChatMessage.vue:215
-#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:129
+#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:132
 #: src/language/curd.ts:18
 #: src/views/certificate/components/CertificateActions.vue:29
 #: src/views/config/components/ConfigLeftPanel.vue:282
@@ -4415,10 +4432,6 @@ msgstr ""
 msgid "Save Directive"
 msgstr ""
 
-#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:45
-msgid "Save error %{msg}"
-msgstr ""
-
 #: src/components/Notification/notifications.ts:145
 #: src/language/constants.ts:48
 msgid "Save Remote Site Error"
@@ -4463,7 +4476,7 @@ msgstr ""
 msgid "Save successfully"
 msgstr ""
 
-#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:43
+#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:48
 #: src/language/curd.ts:28
 #: src/views/config/components/ConfigLeftPanel.vue:198
 #: src/views/site/site_add/SiteAdd.vue:36
@@ -4541,10 +4554,18 @@ msgstr ""
 msgid "Security Token Information"
 msgstr ""
 
+#: src/views/certificate/ACMEUser.vue:57
+msgid "Select a predefined CA directory or enter a custom one. Leave blank to use the default CA directory."
+msgstr ""
+
 #: src/language/curd.ts:31
 msgid "Select all"
 msgstr ""
 
+#: src/views/certificate/ACMEUser.vue:43
+msgid "Select or enter a CA directory URL"
+msgstr ""
+
 #: src/language/curd.ts:59
 msgid "Selected {count} files"
 msgstr ""
@@ -4789,7 +4810,7 @@ msgstr ""
 
 #: src/components/PortScanner/PortScannerCompact.vue:37
 #: src/views/backup/AutoBackup/AutoBackup.vue:160
-#: src/views/certificate/ACMEUser.vue:60
+#: src/views/certificate/ACMEUser.vue:73
 #: src/views/certificate/CertificateList/certColumns.tsx:63
 #: src/views/dashboard/components/ModulesTable.vue:96
 #: src/views/environments/list/envColumns.tsx:43
@@ -5319,7 +5340,7 @@ msgstr ""
 msgid "Two-factor authentication required"
 msgstr ""
 
-#: src/composables/useUpstreamStatus.ts:115
+#: src/composables/useUpstreamStatus.ts:132
 #: src/views/certificate/CertificateList/certColumns.tsx:24
 #: src/views/config/components/Delete.vue:122
 #: src/views/dashboard/components/ModulesTable.vue:83
@@ -5355,7 +5376,7 @@ msgid "Update successfully"
 msgstr ""
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:236
-#: src/views/certificate/ACMEUser.vue:83
+#: src/views/certificate/ACMEUser.vue:123
 #: src/views/certificate/DNSCredential.vue:65
 #: src/views/config/components/ConfigRightPanel/Basic.vue:54
 #: src/views/config/configColumns.tsx:43
@@ -5402,7 +5423,7 @@ msgstr ""
 msgid "Upload Folders"
 msgstr ""
 
-#: src/composables/useUpstreamStatus.ts:115
+#: src/composables/useUpstreamStatus.ts:132
 msgid "Upstream"
 msgstr ""
 
@@ -5470,7 +5491,7 @@ msgid "Username length cannot exceed 255 characters"
 msgstr ""
 
 #: src/components/CertInfo/CertInfo.vue:24
-#: src/views/certificate/ACMEUser.vue:120
+#: src/views/certificate/ACMEUser.vue:160
 #: src/views/certificate/CertificateList/certColumns.tsx:76
 msgid "Valid"
 msgstr ""
@@ -5565,7 +5586,7 @@ msgstr ""
 msgid "Weekly on %{day} at %{time}"
 msgstr ""
 
-#: src/views/certificate/ACMEUser.vue:78
+#: src/views/certificate/ACMEUser.vue:118
 msgid "When Enabled, Nginx UI will automatically re-register users upon startup. Generally, do not enable this unless you are in a dev environment and using Pebble as CA."
 msgstr ""
 
@@ -5630,7 +5651,7 @@ msgstr ""
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:110
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:98
-#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:98
+#: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:101
 #: src/components/NgxConfigEditor/LocationEditor.vue:88
 #: src/views/preference/tabs/AuthSettings.vue:131
 #: src/views/preference/tabs/CertSettings.vue:72

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 224 - 172
app/src/language/pt_PT/app.po


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 225 - 177
app/src/language/ru_RU/app.po


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 232 - 176
app/src/language/tr_TR/app.po


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 237 - 186
app/src/language/uk_UA/app.po


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 234 - 190
app/src/language/vi_VN/app.po


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 261 - 164
app/src/language/zh_CN/app.po


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 265 - 169
app/src/language/zh_TW/app.po


+ 43 - 3
app/src/views/certificate/ACMEUser.vue

@@ -38,10 +38,23 @@ const columns: StdTableColumn[] = [
     sorter: true,
     pure: true,
     edit: {
-      type: 'input',
-      input: {
-        placeholder: () => $gettext('If left blank, the default CA Dir will be used.'),
+      type: 'autoComplete',
+      autoComplete: {
+        placeholder: () => $gettext('Select or enter a CA directory URL'),
+        allowClear: true,
+        options: [
+          {
+            value: 'https://acme-v02.api.letsencrypt.org/directory',
+          },
+          {
+            value: 'https://acme-staging-v02.api.letsencrypt.org/directory',
+          },
+          {
+            value: 'https://acme.zerossl.com/v2/DV90',
+          },
+        ],
       },
+      hint: $gettext('Select a predefined CA directory or enter a custom one. Leave blank to use the default CA directory.'),
     },
   },
   {
@@ -68,6 +81,33 @@ const columns: StdTableColumn[] = [
     sorter: true,
     pure: true,
   },
+  {
+    title: () => $gettext('EAB Key ID'),
+    dataIndex: 'eab_key_id',
+    hiddenInTable: true,
+    edit: {
+      type: 'input',
+      hint: $gettext('External Account Binding Key ID (optional). Required for some ACME providers like ZeroSSL.'),
+      input: {
+        placeholder: $gettext('Leave blank if not required by your ACME provider'),
+      },
+    },
+    hiddenInDetail: true,
+  },
+  {
+    title: () => $gettext('EAB HMAC Key'),
+    dataIndex: 'eab_hmac_key',
+    hiddenInTable: true,
+    edit: {
+      type: 'input',
+      hint: $gettext('External Account Binding HMAC Key (optional). Should be in Base64 URL encoding format.'),
+      input: {
+        placeholder: $gettext('Leave blank if not required by your ACME provider'),
+        type: 'password',
+      },
+    },
+    hiddenInDetail: true,
+  },
   {
     title: () => $gettext('Register On Startup'),
     dataIndex: 'register_on_startup',

+ 4 - 4
internal/cache/search.go

@@ -608,8 +608,8 @@ func (si *SearchIndexer) updateMemoryUsage(documentID string, contentSize int64,
 	if isAddition {
 		si.totalContentSize += contentSize
 		si.documentCount++
-		logger.Debugf("Added document %s: size=%d, total_size=%d, count=%d",
-			documentID, contentSize, si.totalContentSize, si.documentCount)
+		// logger.Debugf("Added document %s: size=%d, total_size=%d, count=%d",
+		// 	documentID, contentSize, si.totalContentSize, si.documentCount)
 	} else {
 		si.totalContentSize -= contentSize
 		si.documentCount--
@@ -619,8 +619,8 @@ func (si *SearchIndexer) updateMemoryUsage(documentID string, contentSize int64,
 		if si.documentCount < 0 {
 			si.documentCount = 0
 		}
-		logger.Debugf("Removed document %s: size=%d, total_size=%d, count=%d",
-			documentID, contentSize, si.totalContentSize, si.documentCount)
+		// logger.Debugf("Removed document %s: size=%d, total_size=%d, count=%d",
+		// 	documentID, contentSize, si.totalContentSize, si.documentCount)
 	}
 }
 

+ 1 - 1
internal/upstream/service.go

@@ -82,7 +82,7 @@ func init() {
 
 // scanForProxyTargets is the callback function for cache scanner
 func scanForProxyTargets(configPath string, content []byte) error {
-	logger.Debug("scanForProxyTargets", configPath)
+	// logger.Debug("scanForProxyTargets", configPath)
 	// Parse proxy targets and upstream definitions from config content
 	result := ParseProxyTargetsAndUpstreamsFromRawContent(string(content))
 

+ 19 - 2
model/acme_user.go

@@ -5,10 +5,11 @@ import (
 	"crypto/ecdsa"
 	"crypto/elliptic"
 	"crypto/rand"
+	"math/big"
+
 	"github.com/0xJacky/Nginx-UI/internal/transport"
 	"github.com/go-acme/lego/v4/lego"
 	"github.com/go-acme/lego/v4/registration"
-	"math/big"
 )
 
 type PrivateKey struct {
@@ -25,6 +26,8 @@ type AcmeUser struct {
 	Key               PrivateKey            `json:"-" gorm:"serializer:json"`
 	Proxy             string                `json:"proxy"`
 	RegisterOnStartup bool                  `json:"register_on_startup"`
+	EABKeyID          string                `json:"eab_key_id"`
+	EABHMACKey        string                `json:"eab_hmac_key"`
 }
 
 func (u *AcmeUser) GetEmail() string {
@@ -77,7 +80,21 @@ func (u *AcmeUser) Register() error {
 	}
 
 	// New users will need to register
-	reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
+	var reg *registration.Resource
+
+	// Check if EAB credentials are provided
+	if u.EABKeyID != "" && u.EABHMACKey != "" {
+		// Register with External Account Binding
+		reg, err = client.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{
+			TermsOfServiceAgreed: true,
+			Kid:                  u.EABKeyID,
+			HmacEncoded:          u.EABHMACKey,
+		})
+	} else {
+		// Register without EAB
+		reg, err = client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
+	}
+
 	if err != nil {
 		return err
 	}

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác