Преглед изворни кода

feat(sub): add Happ client integration, routing presets, and app management (#6434)

* feat(sub): add Happ client integration, routing presets, and app management

Implement comprehensive Happ proxy client integration according to official developer specifications.

- Fix header emission on disabled routing and hidden settings to send explicit '0' headers rather than omitting, allowing Happ clients to reset cached settings.
- Add support for 'happ://routing/off' deeplink in routing validation.
- Preserve '?serverDescription=' query parameters in link fragments without escaping to support Happ server subtitles across VMess, VLESS, Trojan and SS.
- Add Happ application management headers: ProviderID, New-Url, Fallback-Url, Sub-Info banners, Sub-Expire notifications, No-Limit mode, hardware ID enforcement, TUN modes/types, route exclusions, APNS exclusions, and per-app proxy settings.
- Add curated routing presets (Iran Bypass, China Direct, AdBlock, Global) and interactive visual rule generator in frontend settings.
- Synchronize all 13 translation locales with native Persian, Russian, and Chinese translations.

* fix(sub): keep Happ header overrides behind the auto-detect opt-in

The Routing-Enable/Hide-Settings off values were emitted on the
User-Agent alone, so every panel that upgraded would push
"Routing-Enable: 0" — documented by happ.su as disabling routing
globally — to every Happ client without the operator enabling anything.
They now ride subHappAutoDetect like every other Happ header.

Two further mismatches against the vendor spec:

- serverDescription was written as a key of the VMess base64 JSON
  object. happ.su documents it as a "#Title?serverDescription=<base64>"
  link parameter or a JSON "meta" entry, so the caption never reached
  Happ while every other VMess consumer received an unknown key.
  Dropped rather than moved: emitting the documented form is unsafe
  here because our own parser base64-decodes the whole VMess body
  (internal/util/link/outbound.go).

- The TUN Mode dropdown stored the literal "default", forwarded as
  "Tun-Mode: default", where happ.su documents system|gvisor only. It
  now stores the unset value so no header is sent. TUN Type "default"
  is a documented value and is unchanged.

Each fix carries a test that fails without it.
Pejman Yousefi пре 10 часа
родитељ
комит
1456658028
35 измењених фајлова са 3460 додато и 51 уклоњено
  1. 186 0
      docs/public/openapi.json
  2. 186 0
      frontend/public/openapi.json
  3. 46 0
      frontend/src/generated/examples.ts
  4. 186 0
      frontend/src/generated/schemas.ts
  5. 46 0
      frontend/src/generated/types.ts
  6. 46 0
      frontend/src/generated/zod.ts
  7. 23 0
      frontend/src/models/setting.ts
  8. 637 0
      frontend/src/pages/settings/HappSettingsContent.tsx
  9. 7 34
      frontend/src/pages/settings/SubscriptionGeneralTab.tsx
  10. 118 0
      frontend/src/pages/settings/happPresets.ts
  11. 23 0
      frontend/src/schemas/setting.ts
  12. 85 0
      frontend/src/test/happ-presets.test.ts
  13. 72 0
      frontend/src/test/happ-settings-tun-mode.test.tsx
  14. 16 2
      internal/sub/controller.go
  15. 26 0
      internal/sub/endpoint_test.go
  16. 141 0
      internal/sub/happ.go
  17. 227 0
      internal/sub/happ_test.go
  18. 3 0
      internal/sub/remote_routing.go
  19. 1 2
      internal/sub/service.go
  20. 26 0
      internal/sub/sub.go
  21. 25 0
      internal/web/entity/entity.go
  22. 125 0
      internal/web/service/setting.go
  23. 93 1
      internal/web/translation/ar-EG.json
  24. 93 1
      internal/web/translation/en-US.json
  25. 93 1
      internal/web/translation/es-ES.json
  26. 93 1
      internal/web/translation/fa-IR.json
  27. 93 1
      internal/web/translation/id-ID.json
  28. 93 1
      internal/web/translation/ja-JP.json
  29. 93 1
      internal/web/translation/pt-BR.json
  30. 93 1
      internal/web/translation/ru-RU.json
  31. 93 1
      internal/web/translation/tr-TR.json
  32. 93 1
      internal/web/translation/uk-UA.json
  33. 93 1
      internal/web/translation/vi-VN.json
  34. 93 1
      internal/web/translation/zh-CN.json
  35. 93 1
      internal/web/translation/zh-TW.json

+ 186 - 0
docs/public/openapi.json

@@ -220,6 +220,76 @@
           "subExpiredTemplate": {
             "type": "string"
           },
+          "subHappAlwaysHwid": {
+            "type": "boolean"
+          },
+          "subHappAutoConnect": {
+            "type": "boolean"
+          },
+          "subHappAutoConnectType": {
+            "type": "string"
+          },
+          "subHappAutoDetect": {
+            "description": "Happ client customization settings (app-management / routing / UX).",
+            "type": "boolean"
+          },
+          "subHappColorProfile": {
+            "type": "string"
+          },
+          "subHappExcludeApns": {
+            "type": "boolean"
+          },
+          "subHappExcludeRoutes": {
+            "type": "string"
+          },
+          "subHappFallbackUrl": {
+            "type": "string"
+          },
+          "subHappNewUrl": {
+            "type": "string"
+          },
+          "subHappNoLimit": {
+            "type": "boolean"
+          },
+          "subHappNotificationExpire": {
+            "type": "boolean"
+          },
+          "subHappPerAppList": {
+            "type": "string"
+          },
+          "subHappPerAppMode": {
+            "type": "string"
+          },
+          "subHappPingType": {
+            "type": "string"
+          },
+          "subHappProviderId": {
+            "type": "string"
+          },
+          "subHappSubExpire": {
+            "type": "boolean"
+          },
+          "subHappSubExpireButtonLink": {
+            "type": "string"
+          },
+          "subHappSubInfoButtonLink": {
+            "type": "string"
+          },
+          "subHappSubInfoButtonText": {
+            "type": "string"
+          },
+          "subHappSubInfoColor": {
+            "type": "string"
+          },
+          "subHappSubInfoText": {
+            "type": "string"
+          },
+          "subHappTunMode": {
+            "type": "string"
+          },
+          "subHappTunType": {
+            "type": "string"
+          },
           "subHideSettings": {
             "type": "boolean"
           },
@@ -443,6 +513,29 @@
           "subEnableRouting",
           "subEncrypt",
           "subExpiredTemplate",
+          "subHappAlwaysHwid",
+          "subHappAutoConnect",
+          "subHappAutoConnectType",
+          "subHappAutoDetect",
+          "subHappColorProfile",
+          "subHappExcludeApns",
+          "subHappExcludeRoutes",
+          "subHappFallbackUrl",
+          "subHappNewUrl",
+          "subHappNoLimit",
+          "subHappNotificationExpire",
+          "subHappPerAppList",
+          "subHappPerAppMode",
+          "subHappPingType",
+          "subHappProviderId",
+          "subHappSubExpire",
+          "subHappSubExpireButtonLink",
+          "subHappSubInfoButtonLink",
+          "subHappSubInfoButtonText",
+          "subHappSubInfoColor",
+          "subHappSubInfoText",
+          "subHappTunMode",
+          "subHappTunType",
           "subHideSettings",
           "subIncyEnableRouting",
           "subIncyRoutingRules",
@@ -711,6 +804,76 @@
           "subExpiredTemplate": {
             "type": "string"
           },
+          "subHappAlwaysHwid": {
+            "type": "boolean"
+          },
+          "subHappAutoConnect": {
+            "type": "boolean"
+          },
+          "subHappAutoConnectType": {
+            "type": "string"
+          },
+          "subHappAutoDetect": {
+            "description": "Happ client customization settings (app-management / routing / UX).",
+            "type": "boolean"
+          },
+          "subHappColorProfile": {
+            "type": "string"
+          },
+          "subHappExcludeApns": {
+            "type": "boolean"
+          },
+          "subHappExcludeRoutes": {
+            "type": "string"
+          },
+          "subHappFallbackUrl": {
+            "type": "string"
+          },
+          "subHappNewUrl": {
+            "type": "string"
+          },
+          "subHappNoLimit": {
+            "type": "boolean"
+          },
+          "subHappNotificationExpire": {
+            "type": "boolean"
+          },
+          "subHappPerAppList": {
+            "type": "string"
+          },
+          "subHappPerAppMode": {
+            "type": "string"
+          },
+          "subHappPingType": {
+            "type": "string"
+          },
+          "subHappProviderId": {
+            "type": "string"
+          },
+          "subHappSubExpire": {
+            "type": "boolean"
+          },
+          "subHappSubExpireButtonLink": {
+            "type": "string"
+          },
+          "subHappSubInfoButtonLink": {
+            "type": "string"
+          },
+          "subHappSubInfoButtonText": {
+            "type": "string"
+          },
+          "subHappSubInfoColor": {
+            "type": "string"
+          },
+          "subHappSubInfoText": {
+            "type": "string"
+          },
+          "subHappTunMode": {
+            "type": "string"
+          },
+          "subHappTunType": {
+            "type": "string"
+          },
           "subHideSettings": {
             "type": "boolean"
           },
@@ -941,6 +1104,29 @@
           "subEnableRouting",
           "subEncrypt",
           "subExpiredTemplate",
+          "subHappAlwaysHwid",
+          "subHappAutoConnect",
+          "subHappAutoConnectType",
+          "subHappAutoDetect",
+          "subHappColorProfile",
+          "subHappExcludeApns",
+          "subHappExcludeRoutes",
+          "subHappFallbackUrl",
+          "subHappNewUrl",
+          "subHappNoLimit",
+          "subHappNotificationExpire",
+          "subHappPerAppList",
+          "subHappPerAppMode",
+          "subHappPingType",
+          "subHappProviderId",
+          "subHappSubExpire",
+          "subHappSubExpireButtonLink",
+          "subHappSubInfoButtonLink",
+          "subHappSubInfoButtonText",
+          "subHappSubInfoColor",
+          "subHappSubInfoText",
+          "subHappTunMode",
+          "subHappTunType",
           "subHideSettings",
           "subIncyEnableRouting",
           "subIncyRoutingRules",

+ 186 - 0
frontend/public/openapi.json

@@ -220,6 +220,76 @@
           "subExpiredTemplate": {
             "type": "string"
           },
+          "subHappAlwaysHwid": {
+            "type": "boolean"
+          },
+          "subHappAutoConnect": {
+            "type": "boolean"
+          },
+          "subHappAutoConnectType": {
+            "type": "string"
+          },
+          "subHappAutoDetect": {
+            "description": "Happ client customization settings (app-management / routing / UX).",
+            "type": "boolean"
+          },
+          "subHappColorProfile": {
+            "type": "string"
+          },
+          "subHappExcludeApns": {
+            "type": "boolean"
+          },
+          "subHappExcludeRoutes": {
+            "type": "string"
+          },
+          "subHappFallbackUrl": {
+            "type": "string"
+          },
+          "subHappNewUrl": {
+            "type": "string"
+          },
+          "subHappNoLimit": {
+            "type": "boolean"
+          },
+          "subHappNotificationExpire": {
+            "type": "boolean"
+          },
+          "subHappPerAppList": {
+            "type": "string"
+          },
+          "subHappPerAppMode": {
+            "type": "string"
+          },
+          "subHappPingType": {
+            "type": "string"
+          },
+          "subHappProviderId": {
+            "type": "string"
+          },
+          "subHappSubExpire": {
+            "type": "boolean"
+          },
+          "subHappSubExpireButtonLink": {
+            "type": "string"
+          },
+          "subHappSubInfoButtonLink": {
+            "type": "string"
+          },
+          "subHappSubInfoButtonText": {
+            "type": "string"
+          },
+          "subHappSubInfoColor": {
+            "type": "string"
+          },
+          "subHappSubInfoText": {
+            "type": "string"
+          },
+          "subHappTunMode": {
+            "type": "string"
+          },
+          "subHappTunType": {
+            "type": "string"
+          },
           "subHideSettings": {
             "type": "boolean"
           },
@@ -443,6 +513,29 @@
           "subEnableRouting",
           "subEncrypt",
           "subExpiredTemplate",
+          "subHappAlwaysHwid",
+          "subHappAutoConnect",
+          "subHappAutoConnectType",
+          "subHappAutoDetect",
+          "subHappColorProfile",
+          "subHappExcludeApns",
+          "subHappExcludeRoutes",
+          "subHappFallbackUrl",
+          "subHappNewUrl",
+          "subHappNoLimit",
+          "subHappNotificationExpire",
+          "subHappPerAppList",
+          "subHappPerAppMode",
+          "subHappPingType",
+          "subHappProviderId",
+          "subHappSubExpire",
+          "subHappSubExpireButtonLink",
+          "subHappSubInfoButtonLink",
+          "subHappSubInfoButtonText",
+          "subHappSubInfoColor",
+          "subHappSubInfoText",
+          "subHappTunMode",
+          "subHappTunType",
           "subHideSettings",
           "subIncyEnableRouting",
           "subIncyRoutingRules",
@@ -711,6 +804,76 @@
           "subExpiredTemplate": {
             "type": "string"
           },
+          "subHappAlwaysHwid": {
+            "type": "boolean"
+          },
+          "subHappAutoConnect": {
+            "type": "boolean"
+          },
+          "subHappAutoConnectType": {
+            "type": "string"
+          },
+          "subHappAutoDetect": {
+            "description": "Happ client customization settings (app-management / routing / UX).",
+            "type": "boolean"
+          },
+          "subHappColorProfile": {
+            "type": "string"
+          },
+          "subHappExcludeApns": {
+            "type": "boolean"
+          },
+          "subHappExcludeRoutes": {
+            "type": "string"
+          },
+          "subHappFallbackUrl": {
+            "type": "string"
+          },
+          "subHappNewUrl": {
+            "type": "string"
+          },
+          "subHappNoLimit": {
+            "type": "boolean"
+          },
+          "subHappNotificationExpire": {
+            "type": "boolean"
+          },
+          "subHappPerAppList": {
+            "type": "string"
+          },
+          "subHappPerAppMode": {
+            "type": "string"
+          },
+          "subHappPingType": {
+            "type": "string"
+          },
+          "subHappProviderId": {
+            "type": "string"
+          },
+          "subHappSubExpire": {
+            "type": "boolean"
+          },
+          "subHappSubExpireButtonLink": {
+            "type": "string"
+          },
+          "subHappSubInfoButtonLink": {
+            "type": "string"
+          },
+          "subHappSubInfoButtonText": {
+            "type": "string"
+          },
+          "subHappSubInfoColor": {
+            "type": "string"
+          },
+          "subHappSubInfoText": {
+            "type": "string"
+          },
+          "subHappTunMode": {
+            "type": "string"
+          },
+          "subHappTunType": {
+            "type": "string"
+          },
           "subHideSettings": {
             "type": "boolean"
           },
@@ -941,6 +1104,29 @@
           "subEnableRouting",
           "subEncrypt",
           "subExpiredTemplate",
+          "subHappAlwaysHwid",
+          "subHappAutoConnect",
+          "subHappAutoConnectType",
+          "subHappAutoDetect",
+          "subHappColorProfile",
+          "subHappExcludeApns",
+          "subHappExcludeRoutes",
+          "subHappFallbackUrl",
+          "subHappNewUrl",
+          "subHappNoLimit",
+          "subHappNotificationExpire",
+          "subHappPerAppList",
+          "subHappPerAppMode",
+          "subHappPingType",
+          "subHappProviderId",
+          "subHappSubExpire",
+          "subHappSubExpireButtonLink",
+          "subHappSubInfoButtonLink",
+          "subHappSubInfoButtonText",
+          "subHappSubInfoColor",
+          "subHappSubInfoText",
+          "subHappTunMode",
+          "subHappTunType",
           "subHideSettings",
           "subIncyEnableRouting",
           "subIncyRoutingRules",

+ 46 - 0
frontend/src/generated/examples.ts

@@ -59,6 +59,29 @@ export const EXAMPLES: Record<string, unknown> = {
     "subEnableRouting": false,
     "subEncrypt": false,
     "subExpiredTemplate": "",
+    "subHappAlwaysHwid": false,
+    "subHappAutoConnect": false,
+    "subHappAutoConnectType": "",
+    "subHappAutoDetect": false,
+    "subHappColorProfile": "",
+    "subHappExcludeApns": false,
+    "subHappExcludeRoutes": "",
+    "subHappFallbackUrl": "",
+    "subHappNewUrl": "",
+    "subHappNoLimit": false,
+    "subHappNotificationExpire": false,
+    "subHappPerAppList": "",
+    "subHappPerAppMode": "",
+    "subHappPingType": "",
+    "subHappProviderId": "",
+    "subHappSubExpire": false,
+    "subHappSubExpireButtonLink": "",
+    "subHappSubInfoButtonLink": "",
+    "subHappSubInfoButtonText": "",
+    "subHappSubInfoColor": "",
+    "subHappSubInfoText": "",
+    "subHappTunMode": "",
+    "subHappTunType": "",
     "subHideSettings": false,
     "subIncyEnableRouting": false,
     "subIncyRoutingRules": "",
@@ -176,6 +199,29 @@ export const EXAMPLES: Record<string, unknown> = {
     "subEnableRouting": false,
     "subEncrypt": false,
     "subExpiredTemplate": "",
+    "subHappAlwaysHwid": false,
+    "subHappAutoConnect": false,
+    "subHappAutoConnectType": "",
+    "subHappAutoDetect": false,
+    "subHappColorProfile": "",
+    "subHappExcludeApns": false,
+    "subHappExcludeRoutes": "",
+    "subHappFallbackUrl": "",
+    "subHappNewUrl": "",
+    "subHappNoLimit": false,
+    "subHappNotificationExpire": false,
+    "subHappPerAppList": "",
+    "subHappPerAppMode": "",
+    "subHappPingType": "",
+    "subHappProviderId": "",
+    "subHappSubExpire": false,
+    "subHappSubExpireButtonLink": "",
+    "subHappSubInfoButtonLink": "",
+    "subHappSubInfoButtonText": "",
+    "subHappSubInfoColor": "",
+    "subHappSubInfoText": "",
+    "subHappTunMode": "",
+    "subHappTunType": "",
     "subHideSettings": false,
     "subIncyEnableRouting": false,
     "subIncyRoutingRules": "",

+ 186 - 0
frontend/src/generated/schemas.ts

@@ -194,6 +194,76 @@ export const SCHEMAS: Record<string, unknown> = {
       "subExpiredTemplate": {
         "type": "string"
       },
+      "subHappAlwaysHwid": {
+        "type": "boolean"
+      },
+      "subHappAutoConnect": {
+        "type": "boolean"
+      },
+      "subHappAutoConnectType": {
+        "type": "string"
+      },
+      "subHappAutoDetect": {
+        "description": "Happ client customization settings (app-management / routing / UX).",
+        "type": "boolean"
+      },
+      "subHappColorProfile": {
+        "type": "string"
+      },
+      "subHappExcludeApns": {
+        "type": "boolean"
+      },
+      "subHappExcludeRoutes": {
+        "type": "string"
+      },
+      "subHappFallbackUrl": {
+        "type": "string"
+      },
+      "subHappNewUrl": {
+        "type": "string"
+      },
+      "subHappNoLimit": {
+        "type": "boolean"
+      },
+      "subHappNotificationExpire": {
+        "type": "boolean"
+      },
+      "subHappPerAppList": {
+        "type": "string"
+      },
+      "subHappPerAppMode": {
+        "type": "string"
+      },
+      "subHappPingType": {
+        "type": "string"
+      },
+      "subHappProviderId": {
+        "type": "string"
+      },
+      "subHappSubExpire": {
+        "type": "boolean"
+      },
+      "subHappSubExpireButtonLink": {
+        "type": "string"
+      },
+      "subHappSubInfoButtonLink": {
+        "type": "string"
+      },
+      "subHappSubInfoButtonText": {
+        "type": "string"
+      },
+      "subHappSubInfoColor": {
+        "type": "string"
+      },
+      "subHappSubInfoText": {
+        "type": "string"
+      },
+      "subHappTunMode": {
+        "type": "string"
+      },
+      "subHappTunType": {
+        "type": "string"
+      },
       "subHideSettings": {
         "type": "boolean"
       },
@@ -417,6 +487,29 @@ export const SCHEMAS: Record<string, unknown> = {
       "subEnableRouting",
       "subEncrypt",
       "subExpiredTemplate",
+      "subHappAlwaysHwid",
+      "subHappAutoConnect",
+      "subHappAutoConnectType",
+      "subHappAutoDetect",
+      "subHappColorProfile",
+      "subHappExcludeApns",
+      "subHappExcludeRoutes",
+      "subHappFallbackUrl",
+      "subHappNewUrl",
+      "subHappNoLimit",
+      "subHappNotificationExpire",
+      "subHappPerAppList",
+      "subHappPerAppMode",
+      "subHappPingType",
+      "subHappProviderId",
+      "subHappSubExpire",
+      "subHappSubExpireButtonLink",
+      "subHappSubInfoButtonLink",
+      "subHappSubInfoButtonText",
+      "subHappSubInfoColor",
+      "subHappSubInfoText",
+      "subHappTunMode",
+      "subHappTunType",
       "subHideSettings",
       "subIncyEnableRouting",
       "subIncyRoutingRules",
@@ -685,6 +778,76 @@ export const SCHEMAS: Record<string, unknown> = {
       "subExpiredTemplate": {
         "type": "string"
       },
+      "subHappAlwaysHwid": {
+        "type": "boolean"
+      },
+      "subHappAutoConnect": {
+        "type": "boolean"
+      },
+      "subHappAutoConnectType": {
+        "type": "string"
+      },
+      "subHappAutoDetect": {
+        "description": "Happ client customization settings (app-management / routing / UX).",
+        "type": "boolean"
+      },
+      "subHappColorProfile": {
+        "type": "string"
+      },
+      "subHappExcludeApns": {
+        "type": "boolean"
+      },
+      "subHappExcludeRoutes": {
+        "type": "string"
+      },
+      "subHappFallbackUrl": {
+        "type": "string"
+      },
+      "subHappNewUrl": {
+        "type": "string"
+      },
+      "subHappNoLimit": {
+        "type": "boolean"
+      },
+      "subHappNotificationExpire": {
+        "type": "boolean"
+      },
+      "subHappPerAppList": {
+        "type": "string"
+      },
+      "subHappPerAppMode": {
+        "type": "string"
+      },
+      "subHappPingType": {
+        "type": "string"
+      },
+      "subHappProviderId": {
+        "type": "string"
+      },
+      "subHappSubExpire": {
+        "type": "boolean"
+      },
+      "subHappSubExpireButtonLink": {
+        "type": "string"
+      },
+      "subHappSubInfoButtonLink": {
+        "type": "string"
+      },
+      "subHappSubInfoButtonText": {
+        "type": "string"
+      },
+      "subHappSubInfoColor": {
+        "type": "string"
+      },
+      "subHappSubInfoText": {
+        "type": "string"
+      },
+      "subHappTunMode": {
+        "type": "string"
+      },
+      "subHappTunType": {
+        "type": "string"
+      },
       "subHideSettings": {
         "type": "boolean"
       },
@@ -915,6 +1078,29 @@ export const SCHEMAS: Record<string, unknown> = {
       "subEnableRouting",
       "subEncrypt",
       "subExpiredTemplate",
+      "subHappAlwaysHwid",
+      "subHappAutoConnect",
+      "subHappAutoConnectType",
+      "subHappAutoDetect",
+      "subHappColorProfile",
+      "subHappExcludeApns",
+      "subHappExcludeRoutes",
+      "subHappFallbackUrl",
+      "subHappNewUrl",
+      "subHappNoLimit",
+      "subHappNotificationExpire",
+      "subHappPerAppList",
+      "subHappPerAppMode",
+      "subHappPingType",
+      "subHappProviderId",
+      "subHappSubExpire",
+      "subHappSubExpireButtonLink",
+      "subHappSubInfoButtonLink",
+      "subHappSubInfoButtonText",
+      "subHappSubInfoColor",
+      "subHappSubInfoText",
+      "subHappTunMode",
+      "subHappTunType",
       "subHideSettings",
       "subIncyEnableRouting",
       "subIncyRoutingRules",

+ 46 - 0
frontend/src/generated/types.ts

@@ -67,6 +67,29 @@ export interface AllSetting {
   subEnableRouting: boolean;
   subEncrypt: boolean;
   subExpiredTemplate: string;
+  subHappAlwaysHwid: boolean;
+  subHappAutoConnect: boolean;
+  subHappAutoConnectType: string;
+  subHappAutoDetect: boolean;
+  subHappColorProfile: string;
+  subHappExcludeApns: boolean;
+  subHappExcludeRoutes: string;
+  subHappFallbackUrl: string;
+  subHappNewUrl: string;
+  subHappNoLimit: boolean;
+  subHappNotificationExpire: boolean;
+  subHappPerAppList: string;
+  subHappPerAppMode: string;
+  subHappPingType: string;
+  subHappProviderId: string;
+  subHappSubExpire: boolean;
+  subHappSubExpireButtonLink: string;
+  subHappSubInfoButtonLink: string;
+  subHappSubInfoButtonText: string;
+  subHappSubInfoColor: string;
+  subHappSubInfoText: string;
+  subHappTunMode: string;
+  subHappTunType: string;
   subHideSettings: boolean;
   subIncyEnableRouting: boolean;
   subIncyRoutingRules: string;
@@ -185,6 +208,29 @@ export interface AllSettingView {
   subEnableRouting: boolean;
   subEncrypt: boolean;
   subExpiredTemplate: string;
+  subHappAlwaysHwid: boolean;
+  subHappAutoConnect: boolean;
+  subHappAutoConnectType: string;
+  subHappAutoDetect: boolean;
+  subHappColorProfile: string;
+  subHappExcludeApns: boolean;
+  subHappExcludeRoutes: string;
+  subHappFallbackUrl: string;
+  subHappNewUrl: string;
+  subHappNoLimit: boolean;
+  subHappNotificationExpire: boolean;
+  subHappPerAppList: string;
+  subHappPerAppMode: string;
+  subHappPingType: string;
+  subHappProviderId: string;
+  subHappSubExpire: boolean;
+  subHappSubExpireButtonLink: string;
+  subHappSubInfoButtonLink: string;
+  subHappSubInfoButtonText: string;
+  subHappSubInfoColor: string;
+  subHappSubInfoText: string;
+  subHappTunMode: string;
+  subHappTunType: string;
   subHideSettings: boolean;
   subIncyEnableRouting: boolean;
   subIncyRoutingRules: string;

+ 46 - 0
frontend/src/generated/zod.ts

@@ -83,6 +83,29 @@ export const AllSettingSchema = z.object({
   subEnableRouting: z.boolean(),
   subEncrypt: z.boolean(),
   subExpiredTemplate: z.string(),
+  subHappAlwaysHwid: z.boolean(),
+  subHappAutoConnect: z.boolean(),
+  subHappAutoConnectType: z.string(),
+  subHappAutoDetect: z.boolean(),
+  subHappColorProfile: z.string(),
+  subHappExcludeApns: z.boolean(),
+  subHappExcludeRoutes: z.string(),
+  subHappFallbackUrl: z.string(),
+  subHappNewUrl: z.string(),
+  subHappNoLimit: z.boolean(),
+  subHappNotificationExpire: z.boolean(),
+  subHappPerAppList: z.string(),
+  subHappPerAppMode: z.string(),
+  subHappPingType: z.string(),
+  subHappProviderId: z.string(),
+  subHappSubExpire: z.boolean(),
+  subHappSubExpireButtonLink: z.string(),
+  subHappSubInfoButtonLink: z.string(),
+  subHappSubInfoButtonText: z.string(),
+  subHappSubInfoColor: z.string(),
+  subHappSubInfoText: z.string(),
+  subHappTunMode: z.string(),
+  subHappTunType: z.string(),
   subHideSettings: z.boolean(),
   subIncyEnableRouting: z.boolean(),
   subIncyRoutingRules: z.string(),
@@ -202,6 +225,29 @@ export const AllSettingViewSchema = z.object({
   subEnableRouting: z.boolean(),
   subEncrypt: z.boolean(),
   subExpiredTemplate: z.string(),
+  subHappAlwaysHwid: z.boolean(),
+  subHappAutoConnect: z.boolean(),
+  subHappAutoConnectType: z.string(),
+  subHappAutoDetect: z.boolean(),
+  subHappColorProfile: z.string(),
+  subHappExcludeApns: z.boolean(),
+  subHappExcludeRoutes: z.string(),
+  subHappFallbackUrl: z.string(),
+  subHappNewUrl: z.string(),
+  subHappNoLimit: z.boolean(),
+  subHappNotificationExpire: z.boolean(),
+  subHappPerAppList: z.string(),
+  subHappPerAppMode: z.string(),
+  subHappPingType: z.string(),
+  subHappProviderId: z.string(),
+  subHappSubExpire: z.boolean(),
+  subHappSubExpireButtonLink: z.string(),
+  subHappSubInfoButtonLink: z.string(),
+  subHappSubInfoButtonText: z.string(),
+  subHappSubInfoColor: z.string(),
+  subHappSubInfoText: z.string(),
+  subHappTunMode: z.string(),
+  subHappTunType: z.string(),
   subHideSettings: z.boolean(),
   subIncyEnableRouting: z.boolean(),
   subIncyRoutingRules: z.string(),

+ 23 - 0
frontend/src/models/setting.ts

@@ -73,6 +73,29 @@ export class AllSetting {
   subJsonObservatory = '';
   subThemeDir = '';
   subHideSettings = false;
+  subHappAutoDetect = false;
+  subHappProviderId = '';
+  subHappNewUrl = '';
+  subHappFallbackUrl = '';
+  subHappSubInfoColor = 'blue';
+  subHappSubInfoText = '';
+  subHappSubInfoButtonText = '';
+  subHappSubInfoButtonLink = '';
+  subHappSubExpire = false;
+  subHappSubExpireButtonLink = '';
+  subHappNotificationExpire = false;
+  subHappNoLimit = false;
+  subHappAlwaysHwid = false;
+  subHappTunMode = '';
+  subHappTunType = '';
+  subHappExcludeRoutes = '';
+  subHappExcludeApns = false;
+  subHappColorProfile = '';
+  subHappPingType = '';
+  subHappAutoConnect = false;
+  subHappAutoConnectType = 'lowestdelay';
+  subHappPerAppMode = 'off';
+  subHappPerAppList = '';
 
   timeLocation = 'Local';
 

+ 637 - 0
frontend/src/pages/settings/HappSettingsContent.tsx

@@ -0,0 +1,637 @@
+import { useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import { Button, Input, Modal, Select, Space, Switch, Tabs, message } from 'antd';
+import {
+  BranchesOutlined,
+  BuildOutlined,
+  CloudSyncOutlined,
+  DesktopOutlined,
+  MobileOutlined,
+  NotificationOutlined,
+  ThunderboltOutlined,
+} from '@ant-design/icons';
+import type { AllSetting } from '@/models/setting';
+import { SettingListItem } from '@/components/ui';
+import { buildHappPresetDeeplink, parseList, toBase64Utf8 } from './happPresets';
+
+interface HappSettingsContentProps {
+  allSetting: AllSetting;
+  updateSetting: (patch: Partial<AllSetting>) => void;
+  isMobile: boolean;
+  remoteSourceBadge: (val: string) => React.ReactNode;
+}
+
+export default function HappSettingsContent({
+  allSetting,
+  updateSetting,
+  isMobile,
+  remoteSourceBadge,
+}: HappSettingsContentProps) {
+  const { t } = useTranslation();
+  const [selectedPreset, setSelectedPreset] = useState<string>('iran-bypass');
+  const [isModalOpen, setIsModalOpen] = useState(false);
+
+  const [directDomains, setDirectDomains] = useState('');
+  const [proxyDomains, setProxyDomains] = useState('');
+  const [blockDomains, setBlockDomains] = useState('');
+  const [directIPs, setDirectIPs] = useState('');
+  const [proxyIPs, setProxyIPs] = useState('');
+  const [blockIPs, setBlockIPs] = useState('');
+
+  const applyPreset = () => {
+    const payload = buildHappPresetDeeplink(selectedPreset);
+    if (payload) {
+      updateSetting({ subRoutingRules: payload });
+      message.success(t('pages.settings.subHappPresetApplied'));
+    }
+  };
+
+  const handleBuildDeeplink = () => {
+    interface FieldRule {
+      type: string;
+      outboundTag: string;
+      domain?: string[];
+      ip?: string[];
+      network?: string;
+    }
+    const rules: FieldRule[] = [];
+
+    const bDom = parseList(blockDomains);
+    const bIp = parseList(blockIPs);
+    if (bDom.length > 0 || bIp.length > 0) {
+      rules.push({
+        type: 'field',
+        outboundTag: 'block',
+        ...(bDom.length > 0 ? { domain: bDom } : {}),
+        ...(bIp.length > 0 ? { ip: bIp } : {}),
+      });
+    }
+
+    const dDom = parseList(directDomains);
+    const dIp = parseList(directIPs);
+    if (dDom.length > 0 || dIp.length > 0) {
+      rules.push({
+        type: 'field',
+        outboundTag: 'direct',
+        ...(dDom.length > 0 ? { domain: dDom } : {}),
+        ...(dIp.length > 0 ? { ip: dIp } : {}),
+      });
+    }
+
+    const pDom = parseList(proxyDomains);
+    const pIp = parseList(proxyIPs);
+    if (pDom.length > 0 || pIp.length > 0) {
+      rules.push({
+        type: 'field',
+        outboundTag: 'proxy',
+        ...(pDom.length > 0 ? { domain: pDom } : {}),
+        ...(pIp.length > 0 ? { ip: pIp } : {}),
+      });
+    }
+
+    rules.push({
+      type: 'field',
+      outboundTag: 'proxy',
+      network: 'tcp,udp',
+    });
+
+    const deeplink = 'happ://routing/onadd/' + toBase64Utf8(JSON.stringify({ rules }));
+    updateSetting({ subRoutingRules: deeplink });
+    setIsModalOpen(false);
+    message.success(t('pages.settings.subHappDeeplinkGenerated'));
+  };
+
+  return (
+    <>
+      <Tabs
+        type="card"
+        size="small"
+        items={[
+          {
+            key: 'routing',
+            label: (
+              <span>
+                <BranchesOutlined /> {!isMobile && t('pages.settings.subHappGroupRouting')}
+              </span>
+            ),
+            children: (
+              <>
+                <SettingListItem
+                  paddings="small"
+                  title={t('pages.settings.subEnableRouting')}
+                  description={t('pages.settings.subEnableRoutingDesc')}
+                >
+                  <Switch
+                    checked={allSetting.subEnableRouting}
+                    onChange={(v) => updateSetting({ subEnableRouting: v })}
+                  />
+                </SettingListItem>
+
+                <SettingListItem
+                  paddings="small"
+                  title={t('pages.settings.subHappPresets')}
+                  description={t('pages.settings.subHappPresetsDesc')}
+                >
+                  <Space orientation="horizontal" style={{ width: '100%' }}>
+                    <Select
+                      value={selectedPreset}
+                      style={{ minWidth: 170 }}
+                      onChange={setSelectedPreset}
+                      options={[
+                        { value: 'iran-bypass', label: t('pages.settings.subHappPresetIran') },
+                        { value: 'china-direct', label: t('pages.settings.subHappPresetChina') },
+                        { value: 'adblock', label: t('pages.settings.subHappPresetAdblock') },
+                        { value: 'global', label: t('pages.settings.subHappPresetGlobal') },
+                        { value: 'off', label: t('pages.settings.subHappPresetOff') },
+                      ]}
+                    />
+                    <Button type="primary" onClick={applyPreset}>
+                      {t('pages.settings.subHappPresets')}
+                    </Button>
+                  </Space>
+                </SettingListItem>
+
+                <SettingListItem
+                  paddings="small"
+                  title={t('pages.settings.subHappVisualBuilder')}
+                  description={t('pages.settings.subHappVisualBuilderDesc')}
+                >
+                  <Button icon={<BuildOutlined />} onClick={() => setIsModalOpen(true)}>
+                    {t('pages.settings.subHappVisualBuilder')}
+                  </Button>
+                </SettingListItem>
+
+                <SettingListItem
+                  paddings="small"
+                  title={t('pages.settings.subRoutingRules')}
+                  badge={remoteSourceBadge(allSetting.subRoutingRules)}
+                  description={t('pages.settings.subRoutingRulesDesc')}
+                >
+                  <Input.TextArea
+                    value={allSetting.subRoutingRules}
+                    rows={4}
+                    placeholder="happ://routing/onadd/... or https://.../DEFAULT.DEEPLINK"
+                    onChange={(e) => updateSetting({ subRoutingRules: e.target.value })}
+                  />
+                </SettingListItem>
+
+                <SettingListItem
+                  paddings="small"
+                  title={t('pages.settings.subHappNoLimit')}
+                  description={t('pages.settings.subHappNoLimitDesc')}
+                >
+                  <Switch
+                    checked={allSetting.subHappNoLimit}
+                    onChange={(v) => updateSetting({ subHappNoLimit: v })}
+                  />
+                </SettingListItem>
+
+                <SettingListItem
+                  paddings="small"
+                  title={t('pages.settings.subHideSettings')}
+                  description={t('pages.settings.subHideSettingsDesc')}
+                >
+                  <Switch
+                    checked={allSetting.subHideSettings}
+                    onChange={(v) => updateSetting({ subHideSettings: v })}
+                  />
+                </SettingListItem>
+              </>
+            ),
+          },
+          {
+            key: 'banners',
+            label: (
+              <span>
+                <NotificationOutlined /> {!isMobile && t('pages.settings.subHappGroupBanners')}
+              </span>
+            ),
+            children: (
+              <>
+                <SettingListItem
+                  paddings="small"
+                  title={t('pages.settings.subHappSubInfoText')}
+                  description={t('pages.settings.subHappSubInfoTextDesc')}
+                >
+                  <Input
+                    value={allSetting.subHappSubInfoText}
+                    maxLength={200}
+                    placeholder="Welcome to our high-speed network!"
+                    onChange={(e) => updateSetting({ subHappSubInfoText: e.target.value })}
+                  />
+                </SettingListItem>
+
+                <SettingListItem
+                  paddings="small"
+                  title={t('pages.settings.subHappSubInfoColor')}
+                  description={t('pages.settings.subHappSubInfoColorDesc')}
+                >
+                  <Select
+                    value={allSetting.subHappSubInfoColor || 'blue'}
+                    style={{ width: '100%' }}
+                    onChange={(v) => updateSetting({ subHappSubInfoColor: v })}
+                    options={[
+                      { value: 'blue', label: t('pages.settings.subHappColorBlue') },
+                      { value: 'green', label: t('pages.settings.subHappColorGreen') },
+                      { value: 'red', label: t('pages.settings.subHappColorRed') },
+                    ]}
+                  />
+                </SettingListItem>
+
+                <SettingListItem
+                  paddings="small"
+                  title={t('pages.settings.subHappSubInfoButtonText')}
+                  description={t('pages.settings.subHappSubInfoButtonTextDesc')}
+                >
+                  <Input
+                    value={allSetting.subHappSubInfoButtonText}
+                    maxLength={25}
+                    placeholder="Support Channel"
+                    onChange={(e) => updateSetting({ subHappSubInfoButtonText: e.target.value })}
+                  />
+                </SettingListItem>
+
+                <SettingListItem
+                  paddings="small"
+                  title={t('pages.settings.subHappSubInfoButtonLink')}
+                  description={t('pages.settings.subHappSubInfoButtonLinkDesc')}
+                >
+                  <Input
+                    value={allSetting.subHappSubInfoButtonLink}
+                    placeholder="https://t.me/your_channel"
+                    onChange={(e) => updateSetting({ subHappSubInfoButtonLink: e.target.value })}
+                  />
+                </SettingListItem>
+
+                <SettingListItem
+                  paddings="small"
+                  title={t('pages.settings.subHappSubExpire')}
+                  description={t('pages.settings.subHappSubExpireDesc')}
+                >
+                  <Switch
+                    checked={allSetting.subHappSubExpire}
+                    onChange={(v) => updateSetting({ subHappSubExpire: v })}
+                  />
+                </SettingListItem>
+
+                <SettingListItem
+                  paddings="small"
+                  title={t('pages.settings.subHappSubExpireButtonLink')}
+                  description={t('pages.settings.subHappSubExpireButtonLinkDesc')}
+                >
+                  <Input
+                    value={allSetting.subHappSubExpireButtonLink}
+                    placeholder="https://example.com/renew"
+                    onChange={(e) => updateSetting({ subHappSubExpireButtonLink: e.target.value })}
+                  />
+                </SettingListItem>
+
+                <SettingListItem
+                  paddings="small"
+                  title={t('pages.settings.subHappNotificationExpire')}
+                  description={t('pages.settings.subHappNotificationExpireDesc')}
+                >
+                  <Switch
+                    checked={allSetting.subHappNotificationExpire}
+                    onChange={(v) => updateSetting({ subHappNotificationExpire: v })}
+                  />
+                </SettingListItem>
+              </>
+            ),
+          },
+          {
+            key: 'network',
+            label: (
+              <span>
+                <ThunderboltOutlined /> {!isMobile && t('pages.settings.subHappGroupNetwork')}
+              </span>
+            ),
+            children: (
+              <>
+                <SettingListItem
+                  paddings="small"
+                  title={t('pages.settings.subHappTunMode')}
+                  description={t('pages.settings.subHappTunModeDesc')}
+                >
+                  <Select
+                    value={allSetting.subHappTunMode}
+                    style={{ width: '100%' }}
+                    onChange={(v) => updateSetting({ subHappTunMode: v })}
+                    options={[
+                      // happ.su documents tun-mode as system|gvisor only, so
+                      // Default is the unset state rather than a third value.
+                      { value: '', label: t('pages.settings.subHappTunModeDefault') },
+                      { value: 'system', label: t('pages.settings.subHappTunModeSystem') },
+                      { value: 'gvisor', label: t('pages.settings.subHappTunModeGvisor') },
+                    ]}
+                  />
+                </SettingListItem>
+
+                <SettingListItem
+                  paddings="small"
+                  title={t('pages.settings.subHappTunType')}
+                  description={t('pages.settings.subHappTunTypeDesc')}
+                >
+                  <Select
+                    value={allSetting.subHappTunType || 'default'}
+                    style={{ width: '100%' }}
+                    onChange={(v) => updateSetting({ subHappTunType: v })}
+                    options={[
+                      { value: 'singbox', label: t('pages.settings.subHappTunTypeSingbox') },
+                      { value: 'tun2proxy', label: t('pages.settings.subHappTunTypeTun2proxy') },
+                      { value: 'default', label: t('pages.settings.subHappTunTypeDefault') },
+                      { value: 'xray', label: t('pages.settings.subHappTunTypeXray') },
+                    ]}
+                  />
+                </SettingListItem>
+
+                <SettingListItem
+                  paddings="small"
+                  title={t('pages.settings.subHappExcludeRoutes')}
+                  description={t('pages.settings.subHappExcludeRoutesDesc')}
+                >
+                  <Input
+                    value={allSetting.subHappExcludeRoutes}
+                    placeholder="192.168.0.0/16, 10.0.0.0/8"
+                    onChange={(e) => updateSetting({ subHappExcludeRoutes: e.target.value })}
+                  />
+                </SettingListItem>
+
+                <SettingListItem
+                  paddings="small"
+                  title={t('pages.settings.subHappExcludeApns')}
+                  description={t('pages.settings.subHappExcludeApnsDesc')}
+                >
+                  <Switch
+                    checked={allSetting.subHappExcludeApns}
+                    onChange={(v) => updateSetting({ subHappExcludeApns: v })}
+                  />
+                </SettingListItem>
+
+                <SettingListItem
+                  paddings="small"
+                  title={t('pages.settings.subHappPingType')}
+                  description={t('pages.settings.subHappPingTypeDesc')}
+                >
+                  <Select
+                    value={allSetting.subHappPingType || 'proxy'}
+                    style={{ width: '100%' }}
+                    onChange={(v) => updateSetting({ subHappPingType: v })}
+                    options={[
+                      { value: 'proxy', label: t('pages.settings.subHappPingProxy') },
+                      { value: 'proxy-head', label: t('pages.settings.subHappPingProxyHead') },
+                      { value: 'tcp', label: t('pages.settings.subHappPingTcp') },
+                      { value: 'icmp', label: t('pages.settings.subHappPingIcmp') },
+                    ]}
+                  />
+                </SettingListItem>
+
+                <SettingListItem
+                  paddings="small"
+                  title={t('pages.settings.subHappAutoConnect')}
+                  description={t('pages.settings.subHappAutoConnectDesc')}
+                >
+                  <Switch
+                    checked={allSetting.subHappAutoConnect}
+                    onChange={(v) => updateSetting({ subHappAutoConnect: v })}
+                  />
+                </SettingListItem>
+
+                <SettingListItem
+                  paddings="small"
+                  title={t('pages.settings.subHappAutoConnectType')}
+                  description={t('pages.settings.subHappAutoConnectTypeDesc')}
+                >
+                  <Select
+                    value={allSetting.subHappAutoConnectType || 'lowestdelay'}
+                    style={{ width: '100%' }}
+                    onChange={(v) => updateSetting({ subHappAutoConnectType: v })}
+                    options={[
+                      {
+                        value: 'lowestdelay',
+                        label: t('pages.settings.subHappAutoConnectLowestDelay'),
+                      },
+                      { value: 'lastused', label: t('pages.settings.subHappAutoConnectLastUsed') },
+                      { value: 'random', label: t('pages.settings.subHappAutoConnectRandom') },
+                    ]}
+                  />
+                </SettingListItem>
+              </>
+            ),
+          },
+          {
+            key: 'themes',
+            label: (
+              <span>
+                <DesktopOutlined /> {!isMobile && t('pages.settings.subHappGroupThemes')}
+              </span>
+            ),
+            children: (
+              <>
+                <SettingListItem
+                  paddings="small"
+                  title={t('pages.settings.subHappColorProfile')}
+                  description={t('pages.settings.subHappColorProfileDesc')}
+                >
+                  <Input
+                    value={allSetting.subHappColorProfile}
+                    placeholder="default, violet, turquoise, cyberpunk, or custom JSON"
+                    onChange={(e) => updateSetting({ subHappColorProfile: e.target.value })}
+                  />
+                </SettingListItem>
+              </>
+            ),
+          },
+          {
+            key: 'failover',
+            label: (
+              <span>
+                <CloudSyncOutlined /> {!isMobile && t('pages.settings.subHappGroupFailover')}
+              </span>
+            ),
+            children: (
+              <>
+                <SettingListItem
+                  paddings="small"
+                  title={t('pages.settings.subHappAutoDetect')}
+                  description={t('pages.settings.subHappAutoDetectDesc')}
+                >
+                  <Switch
+                    checked={allSetting.subHappAutoDetect}
+                    onChange={(v) => updateSetting({ subHappAutoDetect: v })}
+                  />
+                </SettingListItem>
+
+                <SettingListItem
+                  paddings="small"
+                  title={t('pages.settings.subHappProviderId')}
+                  description={t('pages.settings.subHappProviderIdDesc')}
+                >
+                  <Input
+                    value={allSetting.subHappProviderId}
+                    placeholder="my-happ-provider"
+                    onChange={(e) => updateSetting({ subHappProviderId: e.target.value })}
+                  />
+                </SettingListItem>
+
+                <SettingListItem
+                  paddings="small"
+                  title={t('pages.settings.subHappNewUrl')}
+                  description={t('pages.settings.subHappNewUrlDesc')}
+                >
+                  <Input
+                    value={allSetting.subHappNewUrl}
+                    placeholder="https://new-domain.com/sub/..."
+                    onChange={(e) => updateSetting({ subHappNewUrl: e.target.value })}
+                  />
+                </SettingListItem>
+
+                <SettingListItem
+                  paddings="small"
+                  title={t('pages.settings.subHappFallbackUrl')}
+                  description={t('pages.settings.subHappFallbackUrlDesc')}
+                >
+                  <Input
+                    value={allSetting.subHappFallbackUrl}
+                    placeholder="https://backup-domain.com/sub/..."
+                    onChange={(e) => updateSetting({ subHappFallbackUrl: e.target.value })}
+                  />
+                </SettingListItem>
+
+                <SettingListItem
+                  paddings="small"
+                  title={t('pages.settings.subHappAlwaysHwid')}
+                  description={t('pages.settings.subHappAlwaysHwidDesc')}
+                >
+                  <Switch
+                    checked={allSetting.subHappAlwaysHwid}
+                    onChange={(v) => updateSetting({ subHappAlwaysHwid: v })}
+                  />
+                </SettingListItem>
+              </>
+            ),
+          },
+          {
+            key: 'android',
+            label: (
+              <span>
+                <MobileOutlined /> {!isMobile && t('pages.settings.subHappGroupAndroid')}
+              </span>
+            ),
+            children: (
+              <>
+                <SettingListItem
+                  paddings="small"
+                  title={t('pages.settings.subHappPerAppMode')}
+                  description={t('pages.settings.subHappPerAppModeDesc')}
+                >
+                  <Select
+                    value={allSetting.subHappPerAppMode || 'off'}
+                    style={{ width: '100%' }}
+                    onChange={(v) => updateSetting({ subHappPerAppMode: v })}
+                    options={[
+                      { value: 'off', label: t('pages.settings.subHappPerAppOff') },
+                      { value: 'on', label: t('pages.settings.subHappPerAppOn') },
+                      { value: 'bypass', label: t('pages.settings.subHappPerAppBypass') },
+                    ]}
+                  />
+                </SettingListItem>
+
+                <SettingListItem
+                  paddings="small"
+                  title={t('pages.settings.subHappPerAppList')}
+                  description={t('pages.settings.subHappPerAppListDesc')}
+                >
+                  <Input.TextArea
+                    value={allSetting.subHappPerAppList}
+                    rows={4}
+                    placeholder="org.telegram.messenger, com.google.android.youtube"
+                    onChange={(e) => updateSetting({ subHappPerAppList: e.target.value })}
+                  />
+                </SettingListItem>
+              </>
+            ),
+          },
+        ]}
+      />
+
+      <Modal
+        title={t('pages.settings.subHappModalTitle')}
+        open={isModalOpen}
+        onCancel={() => setIsModalOpen(false)}
+        onOk={handleBuildDeeplink}
+        okText={t('pages.settings.subHappBuildDeeplink')}
+        width={650}
+      >
+        <Space direction="vertical" style={{ width: '100%', marginTop: 12 }} size="middle">
+          <div>
+            <div style={{ fontWeight: 600, marginBottom: 4 }}>
+              {t('pages.settings.subHappDirectDomains')}
+            </div>
+            <Input.TextArea
+              rows={2}
+              value={directDomains}
+              placeholder="domain:ir, domain:cn, example.local"
+              onChange={(e) => setDirectDomains(e.target.value)}
+            />
+          </div>
+          <div>
+            <div style={{ fontWeight: 600, marginBottom: 4 }}>
+              {t('pages.settings.subHappProxyDomains')}
+            </div>
+            <Input.TextArea
+              rows={2}
+              value={proxyDomains}
+              placeholder="geosite:google, youtube.com"
+              onChange={(e) => setProxyDomains(e.target.value)}
+            />
+          </div>
+          <div>
+            <div style={{ fontWeight: 600, marginBottom: 4 }}>
+              {t('pages.settings.subHappBlockDomains')}
+            </div>
+            <Input.TextArea
+              rows={2}
+              value={blockDomains}
+              placeholder="geosite:category-ads-all, analytics.google.com"
+              onChange={(e) => setBlockDomains(e.target.value)}
+            />
+          </div>
+          <div>
+            <div style={{ fontWeight: 600, marginBottom: 4 }}>
+              {t('pages.settings.subHappDirectIPs')}
+            </div>
+            <Input.TextArea
+              rows={2}
+              value={directIPs}
+              placeholder="geoip:ir, 192.168.0.0/16, 10.0.0.0/8"
+              onChange={(e) => setDirectIPs(e.target.value)}
+            />
+          </div>
+          <div>
+            <div style={{ fontWeight: 600, marginBottom: 4 }}>
+              {t('pages.settings.subHappProxyIPs')}
+            </div>
+            <Input.TextArea
+              rows={2}
+              value={proxyIPs}
+              placeholder="1.1.1.1/32, 8.8.8.8/32"
+              onChange={(e) => setProxyIPs(e.target.value)}
+            />
+          </div>
+          <div>
+            <div style={{ fontWeight: 600, marginBottom: 4 }}>
+              {t('pages.settings.subHappBlockIPs')}
+            </div>
+            <Input.TextArea
+              rows={2}
+              value={blockIPs}
+              placeholder="geoip:phishing, 0.0.0.0/8"
+              onChange={(e) => setBlockIPs(e.target.value)}
+            />
+          </div>
+        </Space>
+      </Modal>
+    </>
+  );
+}

+ 7 - 34
frontend/src/pages/settings/SubscriptionGeneralTab.tsx

@@ -17,6 +17,7 @@ import { RemarkTemplateField } from '@/components/form';
 import { useMediaQuery } from '@/hooks/useMediaQuery';
 import { catTabLabel } from './catTabLabel';
 import { sanitizePath, normalizePath } from './uriPath';
+import HappSettingsContent from './HappSettingsContent';
 
 interface SubscriptionGeneralTabProps {
   allSetting: AllSetting;
@@ -344,40 +345,12 @@ export default function SubscriptionGeneralTab({
           key: '5',
           label: catTabLabel(<BranchesOutlined />, 'Happ', isMobile),
           children: (
-            <>
-              <SettingListItem
-                paddings="small"
-                title={t('pages.settings.subEnableRouting')}
-                description={t('pages.settings.subEnableRoutingDesc')}
-              >
-                <Switch
-                  checked={allSetting.subEnableRouting}
-                  onChange={(v) => updateSetting({ subEnableRouting: v })}
-                />
-              </SettingListItem>
-              <SettingListItem
-                paddings="small"
-                title={t('pages.settings.subRoutingRules')}
-                badge={remoteSourceBadge(allSetting.subRoutingRules)}
-                description={t('pages.settings.subRoutingRulesDesc')}
-              >
-                <Input.TextArea
-                  value={allSetting.subRoutingRules}
-                  placeholder="happ://routing/onadd/... or https://.../DEFAULT.DEEPLINK"
-                  onChange={(e) => updateSetting({ subRoutingRules: e.target.value })}
-                />
-              </SettingListItem>
-              <SettingListItem
-                paddings="small"
-                title={t('pages.settings.subHideSettings')}
-                description={t('pages.settings.subHideSettingsDesc')}
-              >
-                <Switch
-                  checked={allSetting.subHideSettings}
-                  onChange={(v) => updateSetting({ subHideSettings: v })}
-                />
-              </SettingListItem>
-            </>
+            <HappSettingsContent
+              allSetting={allSetting}
+              updateSetting={updateSetting}
+              isMobile={isMobile}
+              remoteSourceBadge={remoteSourceBadge}
+            />
           ),
         },
         {

+ 118 - 0
frontend/src/pages/settings/happPresets.ts

@@ -0,0 +1,118 @@
+// Encode UTF-8 string to standard Base64 safe for browser environments.
+export function toBase64Utf8(str: string): string {
+  return btoa(
+    encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, (_, p1) =>
+      String.fromCharCode(Number(`0x${p1}`)),
+    ),
+  );
+}
+
+// Splits multiline or comma-separated string into clean unique token arrays.
+export function parseList(input: string): string[] {
+  return input
+    .split(/[\n,]+/)
+    .map((s) => s.trim())
+    .filter(Boolean);
+}
+
+// Build standard Happ routing deeplink or special state for curated presets.
+export function buildHappPresetDeeplink(preset: string): string {
+  switch (preset) {
+    case 'off':
+      return 'happ://routing/off';
+    case 'iran-bypass':
+      return (
+        'happ://routing/onadd/' +
+        toBase64Utf8(
+          JSON.stringify({
+            rules: [
+              {
+                type: 'field',
+                outboundTag: 'direct',
+                domain: ['domain:ir', 'regexp:.*\\.ir$'],
+                ip: ['geoip:ir', 'geoip:private'],
+              },
+              {
+                type: 'field',
+                outboundTag: 'block',
+                domain: ['geosite:category-ads-all'],
+              },
+              {
+                type: 'field',
+                outboundTag: 'proxy',
+                network: 'tcp,udp',
+              },
+            ],
+          }),
+        )
+      );
+    case 'china-direct':
+      return (
+        'happ://routing/onadd/' +
+        toBase64Utf8(
+          JSON.stringify({
+            rules: [
+              {
+                type: 'field',
+                outboundTag: 'direct',
+                domain: ['domain:cn', 'geosite:cn'],
+                ip: ['geoip:cn', 'geoip:private'],
+              },
+              {
+                type: 'field',
+                outboundTag: 'block',
+                domain: ['geosite:category-ads-all'],
+              },
+              {
+                type: 'field',
+                outboundTag: 'proxy',
+                network: 'tcp,udp',
+              },
+            ],
+          }),
+        )
+      );
+    case 'adblock':
+      return (
+        'happ://routing/onadd/' +
+        toBase64Utf8(
+          JSON.stringify({
+            rules: [
+              {
+                type: 'field',
+                outboundTag: 'block',
+                domain: ['geosite:category-ads-all'],
+              },
+              {
+                type: 'field',
+                outboundTag: 'direct',
+                ip: ['geoip:private'],
+              },
+              {
+                type: 'field',
+                outboundTag: 'proxy',
+                network: 'tcp,udp',
+              },
+            ],
+          }),
+        )
+      );
+    case 'global':
+      return (
+        'happ://routing/onadd/' +
+        toBase64Utf8(
+          JSON.stringify({
+            rules: [
+              {
+                type: 'field',
+                outboundTag: 'proxy',
+                network: 'tcp,udp',
+              },
+            ],
+          }),
+        )
+      );
+    default:
+      return '';
+  }
+}

+ 23 - 0
frontend/src/schemas/setting.ts

@@ -77,6 +77,29 @@ export const AllSettingSchema = z
     subJsonFinalMask: z.string().optional(),
     subJsonObservatory: z.string().optional(),
     subHideSettings: z.boolean().optional(),
+    subHappAutoDetect: z.boolean().optional(),
+    subHappProviderId: z.string().optional(),
+    subHappNewUrl: z.string().optional(),
+    subHappFallbackUrl: z.string().optional(),
+    subHappSubInfoColor: z.string().optional(),
+    subHappSubInfoText: z.string().optional(),
+    subHappSubInfoButtonText: z.string().optional(),
+    subHappSubInfoButtonLink: z.string().optional(),
+    subHappSubExpire: z.boolean().optional(),
+    subHappSubExpireButtonLink: z.string().optional(),
+    subHappNotificationExpire: z.boolean().optional(),
+    subHappNoLimit: z.boolean().optional(),
+    subHappAlwaysHwid: z.boolean().optional(),
+    subHappTunMode: z.string().optional(),
+    subHappTunType: z.string().optional(),
+    subHappExcludeRoutes: z.string().optional(),
+    subHappExcludeApns: z.boolean().optional(),
+    subHappColorProfile: z.string().optional(),
+    subHappPingType: z.string().optional(),
+    subHappAutoConnect: z.boolean().optional(),
+    subHappAutoConnectType: z.string().optional(),
+    subHappPerAppMode: z.string().optional(),
+    subHappPerAppList: z.string().optional(),
     timeLocation: z.string().optional(),
     ldapEnable: z.boolean().optional(),
     ldapHost: z.string().optional(),

+ 85 - 0
frontend/src/test/happ-presets.test.ts

@@ -0,0 +1,85 @@
+import { describe, expect, it } from 'vitest';
+
+import { buildHappPresetDeeplink, parseList, toBase64Utf8 } from '@/pages/settings/happPresets';
+
+describe('Happ presets and helpers', () => {
+  it('correctly parses comma and newline separated lists', () => {
+    const raw = 'domain:ir\nregexp:.*\\.ir$\n, example.com, , google.com';
+    const parsed = parseList(raw);
+    expect(parsed).toEqual(['domain:ir', 'regexp:.*\\.ir$', 'example.com', 'google.com']);
+  });
+
+  it('generates valid happ://routing/off for off preset', () => {
+    const link = buildHappPresetDeeplink('off');
+    expect(link).toBe('happ://routing/off');
+  });
+
+  it('generates valid base64 payload for iran-bypass preset', () => {
+    const link = buildHappPresetDeeplink('iran-bypass');
+    expect(link.startsWith('happ://routing/onadd/')).toBe(true);
+
+    const b64 = link.replace('happ://routing/onadd/', '');
+    const jsonStr = atob(b64);
+    const parsed = JSON.parse(jsonStr);
+
+    expect(parsed).toHaveProperty('rules');
+    expect(Array.isArray(parsed.rules)).toBe(true);
+
+    const directRule = parsed.rules.find(
+      (r: { outboundTag: string }) => r.outboundTag === 'direct',
+    );
+    expect(directRule).toBeDefined();
+    expect(directRule.domain).toContain('domain:ir');
+    expect(directRule.ip).toContain('geoip:ir');
+
+    const blockRule = parsed.rules.find((r: { outboundTag: string }) => r.outboundTag === 'block');
+    expect(blockRule).toBeDefined();
+    expect(blockRule.domain).toContain('geosite:category-ads-all');
+  });
+
+  it('generates valid base64 payload for china-direct preset', () => {
+    const link = buildHappPresetDeeplink('china-direct');
+    expect(link.startsWith('happ://routing/onadd/')).toBe(true);
+
+    const b64 = link.replace('happ://routing/onadd/', '');
+    const jsonStr = atob(b64);
+    const parsed = JSON.parse(jsonStr);
+
+    const directRule = parsed.rules.find(
+      (r: { outboundTag: string }) => r.outboundTag === 'direct',
+    );
+    expect(directRule.domain).toContain('domain:cn');
+    expect(directRule.ip).toContain('geoip:cn');
+  });
+
+  it('generates valid base64 payload for adblock preset', () => {
+    const link = buildHappPresetDeeplink('adblock');
+    const b64 = link.replace('happ://routing/onadd/', '');
+    const jsonStr = atob(b64);
+    const parsed = JSON.parse(jsonStr);
+
+    const blockRule = parsed.rules.find((r: { outboundTag: string }) => r.outboundTag === 'block');
+    expect(blockRule.domain).toContain('geosite:category-ads-all');
+  });
+
+  it('generates valid base64 payload for global preset', () => {
+    const link = buildHappPresetDeeplink('global');
+    const b64 = link.replace('happ://routing/onadd/', '');
+    const jsonStr = atob(b64);
+    const parsed = JSON.parse(jsonStr);
+
+    expect(parsed.rules[0].outboundTag).toBe('proxy');
+    expect(parsed.rules[0].network).toBe('tcp,udp');
+  });
+
+  it('encodes unicode properly via toBase64Utf8', () => {
+    const text = 'فیلترشکن و روتینگ';
+    const b64 = toBase64Utf8(text);
+    const decoded = decodeURIComponent(
+      Array.prototype.map
+        .call(atob(b64), (c: string) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))
+        .join(''),
+    );
+    expect(decoded).toBe(text);
+  });
+});

+ 72 - 0
frontend/src/test/happ-settings-tun-mode.test.tsx

@@ -0,0 +1,72 @@
+import { describe, expect, it, vi } from 'vitest';
+import { fireEvent } from '@testing-library/react';
+
+import HappSettingsContent from '@/pages/settings/HappSettingsContent';
+import { AllSetting } from '@/models/setting';
+
+import { renderWithProviders } from './test-utils';
+
+function openTab(name: string) {
+  const tab = Array.from(document.querySelectorAll('.ant-tabs-tab')).find((t) =>
+    (t.textContent ?? '').includes(name),
+  );
+  if (!tab) throw new Error(`tab '${name}' not found`);
+  fireEvent.click(tab);
+}
+
+function selectFor(title: string): HTMLElement {
+  const row = Array.from(document.querySelectorAll('.ant-select')).find((s) =>
+    (s.closest('li,div[class*="setting"]')?.textContent ?? '').includes(title),
+  );
+  if (!row) throw new Error(`select for '${title}' not found`);
+  return row as HTMLElement;
+}
+
+function clickOption(text: string) {
+  const option = Array.from(document.querySelectorAll('.ant-select-item-option')).find(
+    (o) => (o.textContent ?? '').trim() === text,
+  );
+  if (!option) throw new Error(`option '${text}' not found`);
+  fireEvent.click(option);
+}
+
+describe('Happ TUN Mode select', () => {
+  // happ.su documents tun-mode as system|gvisor only, so the Default entry has
+  // to mean "send no header", the same state a fresh panel ships with.
+  it('stores the empty value for Default so no Tun-Mode header is emitted', () => {
+    const updateSetting = vi.fn();
+    const allSetting = new AllSetting();
+    allSetting.subHappTunMode = 'gvisor';
+
+    renderWithProviders(
+      <HappSettingsContent
+        allSetting={allSetting}
+        updateSetting={updateSetting}
+        isMobile={false}
+        remoteSourceBadge={() => null}
+      />,
+    );
+
+    openTab('Network');
+    const select = selectFor('TUN Mode');
+    fireEvent.mouseDown(select.querySelector('.ant-select-selector') ?? select);
+    clickOption('Default');
+
+    expect(updateSetting).toHaveBeenCalledWith({ subHappTunMode: '' });
+  });
+
+  it('labels the unset state Default rather than leaving the control blank', () => {
+    renderWithProviders(
+      <HappSettingsContent
+        allSetting={new AllSetting()}
+        updateSetting={vi.fn()}
+        isMobile={false}
+        remoteSourceBadge={() => null}
+      />,
+    );
+
+    openTab('Network');
+    const select = selectFor('TUN Mode');
+    expect(select.querySelector('.ant-select-content')?.textContent).toBe('Default');
+  });
+});

+ 16 - 2
internal/sub/controller.go

@@ -52,6 +52,7 @@ type SUBController struct {
 	subEnableRouting bool
 	subRoutingRules  string
 	subHideSettings  bool
+	happConfig       HappConfig
 
 	subIncyEnableRouting bool
 	subIncyRoutingRules  string
@@ -110,6 +111,7 @@ type subControllerConfig struct {
 	subEnableRouting bool
 	subRoutingRules  string
 	subHideSettings  bool
+	happConfig       HappConfig
 
 	subIncyEnableRouting bool
 	subIncyRoutingRules  string
@@ -229,6 +231,10 @@ func WithSUBIncyRoutingRules(value string) SUBControllerOption {
 	return func(config *subControllerConfig) { config.subIncyRoutingRules = value }
 }
 
+func WithSUBHappConfig(value HappConfig) SUBControllerOption {
+	return func(config *subControllerConfig) { config.happConfig = value }
+}
+
 func defaultSUBControllerConfig() subControllerConfig {
 	return subControllerConfig{
 		subPath:        "/sub/",
@@ -258,6 +264,7 @@ func NewSUBController(g *gin.RouterGroup, options ...SUBControllerOption) *SUBCo
 		subEnableRouting: config.subEnableRouting,
 		subRoutingRules:  config.subRoutingRules,
 		subHideSettings:  config.subHideSettings,
+		happConfig:       config.happConfig,
 
 		subIncyEnableRouting: config.subIncyEnableRouting,
 		subIncyRoutingRules:  config.subIncyRoutingRules,
@@ -845,16 +852,23 @@ func (a *SUBController) ApplyCommonHeaders(
 		c.Writer.Header().Set("Announce", "base64:"+base64.StdEncoding.EncodeToString([]byte(profileAnnounce)))
 	}
 
-	// Advanced (Happ). Routing stays independent of the enable flag; remote
-	// values come only from the validated cache and never delay this response.
 	rules, remote, routingErr := resolveRoutingSource(remoteRoutingHapp, profileRoutingRules)
+	// The off values undo a previously pushed setting, so they ride the same
+	// opt-in as every other Happ header rather than reaching every Happ client.
+	happManaged := a.happConfig.AutoDetect && c.Request != nil && IsHappClient(c.GetHeader("User-Agent"))
 	if profileEnableRouting {
 		c.Writer.Header().Set("Routing-Enable", "true")
+	} else if happManaged {
+		c.Writer.Header().Set("Routing-Enable", "0")
 	}
 	if (routingErr == nil || !remote) && strings.TrimSpace(rules) != "" {
 		c.Writer.Header().Set("Routing", rules)
 	}
 	if profileHideSettings {
 		c.Writer.Header().Set("Hide-Settings", "1")
+	} else if happManaged {
+		c.Writer.Header().Set("Hide-Settings", "0")
 	}
+
+	ApplyHappHeaders(c, a.happConfig, happManaged)
 }

+ 26 - 0
internal/sub/endpoint_test.go

@@ -116,6 +116,32 @@ func TestBuildEndpointVmessLinks(t *testing.T) {
 	}
 }
 
+// happ.su documents serverDescription as a "#title?serverDescription=<base64>"
+// link parameter, never a key of the VMess object, so nothing may leak into it.
+func TestBuildEndpointVmessLinks_HostServerDescription(t *testing.T) {
+	s := &SubService{}
+	in := &model.Inbound{Remark: "ib"}
+	baseObj := map[string]any{"v": "2", "add": "base.example.com", "port": 443, "type": "none", "id": "uid", "scy": "auto", "net": "tcp", "tls": "none"}
+	host := &model.Host{Address: "a.example.com", Port: 8443, ServerDescription: "Berlin premium"}
+	eps := []ShareEndpoint{externalProxyToEndpoint(hostToExternalProxyMap(host, "a.example.com", 8443))}
+
+	got := s.buildEndpointVmessLinks(eps, baseObj, in, "user", "tcp")
+	raw, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(got, "vmess://"))
+	if err != nil {
+		t.Fatalf("decode vmess link: %v", err)
+	}
+	var obj map[string]any
+	if err := json.Unmarshal(raw, &obj); err != nil {
+		t.Fatalf("unmarshal vmess object: %v", err)
+	}
+	if obj["add"] != "a.example.com" {
+		t.Fatalf("host endpoint not applied: add = %v", obj["add"])
+	}
+	if value, ok := obj["serverDescription"]; ok {
+		t.Fatalf("VMess object carries serverDescription = %v; it is not a VMess object key", value)
+	}
+}
+
 // N5 — a host's Final Mask is appended to the inbound's own fm param (#5831).
 func TestBuildEndpointLinks_HostFinalMaskMerge(t *testing.T) {
 	s := &SubService{}

+ 141 - 0
internal/sub/happ.go

@@ -0,0 +1,141 @@
+package sub
+
+import (
+	"regexp"
+	"strings"
+
+	"github.com/gin-gonic/gin"
+)
+
+var happUserAgentRegex = regexp.MustCompile(`(?i)\bhapp\b`)
+
+// HappConfig holds all Happ client customization parameters.
+type HappConfig struct {
+	AutoDetect          bool
+	ProviderId          string
+	NewUrl              string
+	FallbackUrl         string
+	SubInfoColor        string
+	SubInfoText         string
+	SubInfoButtonText   string
+	SubInfoButtonLink   string
+	SubExpire           bool
+	SubExpireButtonLink string
+	NotificationExpire  bool
+	NoLimit             bool
+	AlwaysHwid          bool
+	TunMode             string
+	TunType             string
+	ExcludeRoutes       string
+	ExcludeApns         bool
+	ColorProfile        string
+	PingType            string
+	AutoConnect         bool
+	AutoConnectType     string
+	PerAppMode          string
+	PerAppList          string
+}
+
+// IsHappClient checks if the client user-agent identifies as Happ.
+func IsHappClient(userAgent string) bool {
+	return happUserAgentRegex.MatchString(userAgent)
+}
+
+// ApplyHappHeaders sets standard and advanced Happ subscription headers.
+func ApplyHappHeaders(c *gin.Context, cfg HappConfig, isHapp bool) {
+	if c == nil || c.Writer == nil || !cfg.AutoDetect || !isHapp {
+		return
+	}
+	if cfg.ProviderId != "" {
+		c.Writer.Header().Set("ProviderID", cfg.ProviderId)
+	}
+	if cfg.NewUrl != "" {
+		c.Writer.Header().Set("New-Url", cfg.NewUrl)
+	}
+	if cfg.FallbackUrl != "" {
+		c.Writer.Header().Set("Fallback-Url", cfg.FallbackUrl)
+	}
+	if text := strings.TrimSpace(cfg.SubInfoText); text != "" {
+		color := strings.TrimSpace(cfg.SubInfoColor)
+		switch strings.ToLower(color) {
+		case "primary", "info":
+			color = "blue"
+		case "success":
+			color = "green"
+		case "warning", "danger":
+			color = "red"
+		case "":
+			color = "blue"
+		}
+		c.Writer.Header().Set("Sub-Info-Color", color)
+		c.Writer.Header().Set("Sub-Info-Text", text)
+		if btnText := strings.TrimSpace(cfg.SubInfoButtonText); btnText != "" {
+			c.Writer.Header().Set("Sub-Info-Button-Text", btnText)
+		}
+		if btnLink := strings.TrimSpace(cfg.SubInfoButtonLink); btnLink != "" {
+			c.Writer.Header().Set("Sub-Info-Button-Link", btnLink)
+		}
+	}
+	if cfg.SubExpire {
+		c.Writer.Header().Set("Sub-Expire", "1")
+		if link := strings.TrimSpace(cfg.SubExpireButtonLink); link != "" {
+			c.Writer.Header().Set("Sub-Expire-Button-Link", link)
+		}
+	}
+	if cfg.NotificationExpire {
+		c.Writer.Header().Set("Notification-Subs-Expire", "1")
+	}
+	if cfg.NoLimit {
+		c.Writer.Header().Set("No-Limit-Enabled", "1")
+	}
+	if cfg.AlwaysHwid {
+		c.Writer.Header().Set("Subscription-Always-Hwid-Enable", "1")
+	}
+	if cfg.TunMode != "" {
+		c.Writer.Header().Set("Tun-Mode", cfg.TunMode)
+	}
+	if cfg.TunType != "" {
+		c.Writer.Header().Set("Tun-Type", cfg.TunType)
+	}
+	if routes := strings.TrimSpace(cfg.ExcludeRoutes); routes != "" {
+		c.Writer.Header().Set("Exclude-Routes", routes)
+	}
+	if cfg.ExcludeApns {
+		c.Writer.Header().Set("Exclude-Apns-Enable", "true")
+	}
+	if profile := strings.TrimSpace(cfg.ColorProfile); profile != "" {
+		profile = strings.ReplaceAll(strings.ReplaceAll(profile, "\r", ""), "\n", "")
+		c.Writer.Header().Set("Color-Profile", profile)
+	}
+	if ping := strings.TrimSpace(cfg.PingType); ping != "" {
+		if strings.EqualFold(ping, "http") {
+			ping = "proxy"
+		}
+		c.Writer.Header().Set("Ping-Type", ping)
+	}
+	if cfg.AutoConnect {
+		c.Writer.Header().Set("Subscription-Autoconnect", "1")
+		autoType := strings.TrimSpace(cfg.AutoConnectType)
+		switch strings.ToLower(autoType) {
+		case "fastest":
+			autoType = "lowestdelay"
+		case "last":
+			autoType = "lastused"
+		}
+		if autoType != "" {
+			c.Writer.Header().Set("Subscription-Autoconnect-Type", autoType)
+		}
+	}
+	if mode := strings.TrimSpace(cfg.PerAppMode); mode != "" && mode != "off" {
+		switch strings.ToLower(mode) {
+		case "include":
+			mode = "on"
+		case "exclude":
+			mode = "bypass"
+		}
+		c.Writer.Header().Set("Per-App-Proxy-Mode", mode)
+		if list := strings.TrimSpace(cfg.PerAppList); list != "" {
+			c.Writer.Header().Set("Per-App-Proxy-List", list)
+		}
+	}
+}

+ 227 - 0
internal/sub/happ_test.go

@@ -0,0 +1,227 @@
+package sub
+
+import (
+	"net/http"
+	"net/http/httptest"
+	"testing"
+
+	"github.com/gin-gonic/gin"
+)
+
+func TestNormalizeHappRouting_Off(t *testing.T) {
+	got, err := normalizeHappRouting([]byte("happ://routing/off"))
+	if err != nil {
+		t.Fatalf("normalizeHappRouting(off) error: %v", err)
+	}
+	if got != "happ://routing/off" {
+		t.Fatalf("normalizeHappRouting(off) = %q, want happ://routing/off", got)
+	}
+}
+
+func TestApplyCommonHeaders_HappClientHeaders(t *testing.T) {
+	gin.SetMode(gin.TestMode)
+
+	cfg := HappConfig{
+		AutoDetect:          true,
+		ProviderId:          "pid-test-123",
+		NewUrl:              "https://new.example.com/sub",
+		FallbackUrl:         "https://backup.example.com/sub",
+		SubInfoColor:        "primary",
+		SubInfoText:         "Welcome to VIP Network",
+		SubInfoButtonText:   "Telegram",
+		SubInfoButtonLink:   "https://t.me/example",
+		SubExpire:           true,
+		SubExpireButtonLink: "https://renew.example.com",
+		NotificationExpire:  true,
+		NoLimit:             true,
+		AlwaysHwid:          true,
+		TunMode:             "gvisor",
+		TunType:             "singbox",
+		ExcludeRoutes:       "192.168.1.0/24, 10.0.0.0/8",
+		ExcludeApns:         true,
+		ColorProfile:        "{\"serverRowBackgroundColor\":\n\"#21003D67\"}",
+		PingType:            "http",
+		AutoConnect:         true,
+		AutoConnectType:     "fastest",
+		PerAppMode:          "include",
+		PerAppList:          "com.google.chrome,com.meta.instagram",
+	}
+
+	controller := &SUBController{happConfig: cfg}
+	recorder := httptest.NewRecorder()
+	ctx, _ := gin.CreateTestContext(recorder)
+	ctx.Request = httptest.NewRequest(http.MethodGet, "/sub/test", nil)
+	ctx.Request.Header.Set("User-Agent", "Happ/1.2.0 (iPhone; iOS 17.5)")
+
+	controller.ApplyCommonHeaders(ctx, "upload=0; download=100; total=1000; expire=1800000000", "12", "MyTitle", "", "", "", false, "", false)
+
+	h := recorder.Header()
+	if h.Get("Routing-Enable") != "0" {
+		t.Fatalf("Routing-Enable = %q, want 0 for Happ with disabled routing", h.Get("Routing-Enable"))
+	}
+	if h.Get("Hide-Settings") != "0" {
+		t.Fatalf("Hide-Settings = %q, want 0 for Happ with disabled hideSettings", h.Get("Hide-Settings"))
+	}
+	if h.Get("ProviderID") != "pid-test-123" {
+		t.Fatalf("ProviderID = %q, want pid-test-123", h.Get("ProviderID"))
+	}
+	if h.Get("New-Url") != "https://new.example.com/sub" {
+		t.Fatalf("New-Url = %q", h.Get("New-Url"))
+	}
+	if h.Get("Fallback-Url") != "https://backup.example.com/sub" {
+		t.Fatalf("Fallback-Url = %q", h.Get("Fallback-Url"))
+	}
+	if h.Get("Sub-Info-Color") != "blue" || h.Get("Sub-Info-Text") != "Welcome to VIP Network" {
+		t.Fatalf("Sub-Info = %s / %s, want blue / Welcome to VIP Network", h.Get("Sub-Info-Color"), h.Get("Sub-Info-Text"))
+	}
+	if h.Get("Sub-Info-Button-Text") != "Telegram" || h.Get("Sub-Info-Button-Link") != "https://t.me/example" {
+		t.Fatalf("Sub-Info button = %s / %s", h.Get("Sub-Info-Button-Text"), h.Get("Sub-Info-Button-Link"))
+	}
+	if h.Get("Sub-Expire") != "1" || h.Get("Sub-Expire-Button-Link") != "https://renew.example.com" {
+		t.Fatalf("Sub-Expire = %s / %s", h.Get("Sub-Expire"), h.Get("Sub-Expire-Button-Link"))
+	}
+	if h.Get("Notification-Subs-Expire") != "1" {
+		t.Fatalf("Notification-Subs-Expire = %q", h.Get("Notification-Subs-Expire"))
+	}
+	if h.Get("No-Limit-Enabled") != "1" {
+		t.Fatalf("No-Limit-Enabled = %q", h.Get("No-Limit-Enabled"))
+	}
+	if h.Get("Subscription-Always-Hwid-Enable") != "1" {
+		t.Fatalf("Subscription-Always-Hwid-Enable = %q", h.Get("Subscription-Always-Hwid-Enable"))
+	}
+	if h.Get("Tun-Mode") != "gvisor" || h.Get("Tun-Type") != "singbox" {
+		t.Fatalf("Tun mode/type = %s / %s", h.Get("Tun-Mode"), h.Get("Tun-Type"))
+	}
+	if h.Get("Exclude-Routes") != "192.168.1.0/24, 10.0.0.0/8" || h.Get("Exclude-Apns-Enable") != "true" {
+		t.Fatalf("Exclude routes/apns = %s / %s", h.Get("Exclude-Routes"), h.Get("Exclude-Apns-Enable"))
+	}
+	if wantProfile := "{\"serverRowBackgroundColor\":\"#21003D67\"}"; h.Get("Color-Profile") != wantProfile {
+		t.Fatalf("Color-Profile = %q, want %q", h.Get("Color-Profile"), wantProfile)
+	}
+	if h.Get("Ping-Type") != "proxy" {
+		t.Fatalf("Ping-Type = %q, want proxy for http alias", h.Get("Ping-Type"))
+	}
+	if h.Get("Subscription-Autoconnect") != "1" || h.Get("Subscription-Autoconnect-Type") != "lowestdelay" {
+		t.Fatalf("Autoconnect = %s / %s, want 1 / lowestdelay for fastest alias", h.Get("Subscription-Autoconnect"), h.Get("Subscription-Autoconnect-Type"))
+	}
+	if h.Get("Per-App-Proxy-Mode") != "on" || h.Get("Per-App-Proxy-List") != "com.google.chrome,com.meta.instagram" {
+		t.Fatalf("Per-App = %s / %s, want on / com.google.chrome,com.meta.instagram", h.Get("Per-App-Proxy-Mode"), h.Get("Per-App-Proxy-List"))
+	}
+}
+
+func TestApplyHappHeaders_Gating(t *testing.T) {
+	gin.SetMode(gin.TestMode)
+
+	cfg := HappConfig{
+		AutoDetect:  true,
+		ProviderId:  "pid-secret",
+		SubInfoText: "Banner",
+		TunMode:     "system",
+	}
+
+	t.Run("non-Happ User-Agent receives no headers", func(t *testing.T) {
+		recorder := httptest.NewRecorder()
+		ctx, _ := gin.CreateTestContext(recorder)
+		ctx.Request = httptest.NewRequest(http.MethodGet, "/sub/test", nil)
+		ctx.Request.Header.Set("User-Agent", "v2rayNG/1.8.5")
+
+		controller := &SUBController{happConfig: cfg}
+		controller.ApplyCommonHeaders(ctx, "", "", "Title", "", "", "", false, "", false)
+
+		if got := recorder.Header().Get("ProviderID"); got != "" {
+			t.Fatalf("ProviderID emitted to non-Happ client: %q", got)
+		}
+		if got := recorder.Header().Get("Sub-Info-Text"); got != "" {
+			t.Fatalf("Sub-Info-Text emitted to non-Happ client: %q", got)
+		}
+		if got := recorder.Header().Get("Tun-Mode"); got != "" {
+			t.Fatalf("Tun-Mode emitted to non-Happ client: %q", got)
+		}
+	})
+
+	t.Run("AutoDetect disabled suppresses Happ headers", func(t *testing.T) {
+		recorder := httptest.NewRecorder()
+		ctx, _ := gin.CreateTestContext(recorder)
+		ctx.Request = httptest.NewRequest(http.MethodGet, "/sub/test", nil)
+		ctx.Request.Header.Set("User-Agent", "Happ/1.2.0 (Android)")
+
+		disabledCfg := cfg
+		disabledCfg.AutoDetect = false
+
+		controller := &SUBController{happConfig: disabledCfg}
+		controller.ApplyCommonHeaders(ctx, "", "", "Title", "", "", "", false, "", false)
+
+		if got := recorder.Header().Get("ProviderID"); got != "" {
+			t.Fatalf("ProviderID emitted when AutoDetect is false: %q", got)
+		}
+		if got := recorder.Header().Get("Sub-Info-Text"); got != "" {
+			t.Fatalf("Sub-Info-Text emitted when AutoDetect is false: %q", got)
+		}
+		// happ.su documents routing-enable 0/false as "disables routing
+		// globally", so it must stay behind the same opt-in as the rest.
+		if got := recorder.Header().Get("Routing-Enable"); got != "" {
+			t.Fatalf("Routing-Enable emitted when AutoDetect is false: %q", got)
+		}
+		if got := recorder.Header().Get("Hide-Settings"); got != "" {
+			t.Fatalf("Hide-Settings emitted when AutoDetect is false: %q", got)
+		}
+	})
+}
+
+func TestApplyHappHeaders_Aliases(t *testing.T) {
+	gin.SetMode(gin.TestMode)
+
+	tests := []struct {
+		name       string
+		cfg        HappConfig
+		wantHeader string
+		wantValue  string
+	}{
+		{
+			name:       "color warning maps to red",
+			cfg:        HappConfig{AutoDetect: true, SubInfoText: "Alert", SubInfoColor: "warning"},
+			wantHeader: "Sub-Info-Color",
+			wantValue:  "red",
+		},
+		{
+			name:       "color danger maps to red",
+			cfg:        HappConfig{AutoDetect: true, SubInfoText: "Alert", SubInfoColor: "danger"},
+			wantHeader: "Sub-Info-Color",
+			wantValue:  "red",
+		},
+		{
+			name:       "color success maps to green",
+			cfg:        HappConfig{AutoDetect: true, SubInfoText: "Ok", SubInfoColor: "success"},
+			wantHeader: "Sub-Info-Color",
+			wantValue:  "green",
+		},
+		{
+			name:       "autoconnect last maps to lastused",
+			cfg:        HappConfig{AutoDetect: true, AutoConnect: true, AutoConnectType: "last"},
+			wantHeader: "Subscription-Autoconnect-Type",
+			wantValue:  "lastused",
+		},
+		{
+			name:       "per-app exclude maps to bypass",
+			cfg:        HappConfig{AutoDetect: true, PerAppMode: "exclude", PerAppList: "app.id"},
+			wantHeader: "Per-App-Proxy-Mode",
+			wantValue:  "bypass",
+		},
+	}
+
+	for _, tc := range tests {
+		t.Run(tc.name, func(t *testing.T) {
+			recorder := httptest.NewRecorder()
+			ctx, _ := gin.CreateTestContext(recorder)
+			ctx.Request = httptest.NewRequest(http.MethodGet, "/sub/test", nil)
+			ctx.Request.Header.Set("User-Agent", "Happ/1.2.0 (iOS)")
+
+			controller := &SUBController{happConfig: tc.cfg}
+			controller.ApplyCommonHeaders(ctx, "", "", "Title", "", "", "", false, "", false)
+
+			if got := recorder.Header().Get(tc.wantHeader); got != tc.wantValue {
+				t.Fatalf("%s = %q, want %q", tc.wantHeader, got, tc.wantValue)
+			}
+		})
+	}
+}

+ 3 - 0
internal/sub/remote_routing.go

@@ -369,6 +369,9 @@ func normalizeHappRouting(body []byte) (string, error) {
 		}
 		return "happ://routing/onadd/" + base64.StdEncoding.EncodeToString(compact), nil
 	}
+	if text == "happ://routing/off" {
+		return text, nil
+	}
 	if strings.ContainsAny(text, "\r\n") {
 		return "", errors.New("Happ deeplink must be a single line")
 	}

+ 1 - 2
internal/sub/service.go

@@ -2166,8 +2166,7 @@ func appendQueryAndFragment(link string, params map[string]string, fragment, sec
 
 	if fragment != "" {
 		sb.WriteByte('#')
-		// Match the frontend's encodeURIComponent(remark): spaces become
-		// %20 (not + as in query strings).
+		// Match the frontend's encodeURIComponent(remark): spaces become %20.
 		sb.WriteString(strings.ReplaceAll(url.QueryEscape(fragment), "+", "%20"))
 	}
 	return sb.String()

+ 26 - 0
internal/sub/sub.go

@@ -215,6 +215,31 @@ func (s *Server) initRouter() (*gin.Engine, error) {
 		SubIncyRoutingRules = ""
 	}
 
+	happCfg := HappConfig{}
+	happCfg.AutoDetect, _ = s.settingService.GetSubHappAutoDetect()
+	happCfg.ProviderId, _ = s.settingService.GetSubHappProviderId()
+	happCfg.NewUrl, _ = s.settingService.GetSubHappNewUrl()
+	happCfg.FallbackUrl, _ = s.settingService.GetSubHappFallbackUrl()
+	happCfg.SubInfoColor, _ = s.settingService.GetSubHappSubInfoColor()
+	happCfg.SubInfoText, _ = s.settingService.GetSubHappSubInfoText()
+	happCfg.SubInfoButtonText, _ = s.settingService.GetSubHappSubInfoButtonText()
+	happCfg.SubInfoButtonLink, _ = s.settingService.GetSubHappSubInfoButtonLink()
+	happCfg.SubExpire, _ = s.settingService.GetSubHappSubExpire()
+	happCfg.SubExpireButtonLink, _ = s.settingService.GetSubHappSubExpireButtonLink()
+	happCfg.NotificationExpire, _ = s.settingService.GetSubHappNotificationExpire()
+	happCfg.NoLimit, _ = s.settingService.GetSubHappNoLimit()
+	happCfg.AlwaysHwid, _ = s.settingService.GetSubHappAlwaysHwid()
+	happCfg.TunMode, _ = s.settingService.GetSubHappTunMode()
+	happCfg.TunType, _ = s.settingService.GetSubHappTunType()
+	happCfg.ExcludeRoutes, _ = s.settingService.GetSubHappExcludeRoutes()
+	happCfg.ExcludeApns, _ = s.settingService.GetSubHappExcludeApns()
+	happCfg.ColorProfile, _ = s.settingService.GetSubHappColorProfile()
+	happCfg.PingType, _ = s.settingService.GetSubHappPingType()
+	happCfg.AutoConnect, _ = s.settingService.GetSubHappAutoConnect()
+	happCfg.AutoConnectType, _ = s.settingService.GetSubHappAutoConnectType()
+	happCfg.PerAppMode, _ = s.settingService.GetSubHappPerAppMode()
+	happCfg.PerAppList, _ = s.settingService.GetSubHappPerAppList()
+
 	// set per-request localizer from headers/cookies
 	engine.Use(locale.LocalizerMiddleware())
 
@@ -296,6 +321,7 @@ func (s *Server) initRouter() (*gin.Engine, error) {
 		WithSUBEnableRouting(SubEnableRouting),
 		WithSUBRoutingRules(SubRoutingRules),
 		WithSUBHideSettings(SubHideSettings),
+		WithSUBHappConfig(happCfg),
 		WithSUBIncyEnableRouting(SubIncyEnableRouting),
 		WithSUBIncyRoutingRules(SubIncyRoutingRules),
 	)

+ 25 - 0
internal/web/entity/entity.go

@@ -112,6 +112,31 @@ type AllSetting struct {
 	SubThemeDir                 string `json:"subThemeDir" form:"subThemeDir"`
 	SubHideSettings             bool   `json:"subHideSettings" form:"subHideSettings"`
 
+	// Happ client customization settings (app-management / routing / UX).
+	SubHappAutoDetect          bool   `json:"subHappAutoDetect" form:"subHappAutoDetect"`
+	SubHappProviderId          string `json:"subHappProviderId" form:"subHappProviderId"`
+	SubHappNewUrl              string `json:"subHappNewUrl" form:"subHappNewUrl"`
+	SubHappFallbackUrl         string `json:"subHappFallbackUrl" form:"subHappFallbackUrl"`
+	SubHappSubInfoColor        string `json:"subHappSubInfoColor" form:"subHappSubInfoColor"`
+	SubHappSubInfoText         string `json:"subHappSubInfoText" form:"subHappSubInfoText"`
+	SubHappSubInfoButtonText   string `json:"subHappSubInfoButtonText" form:"subHappSubInfoButtonText"`
+	SubHappSubInfoButtonLink   string `json:"subHappSubInfoButtonLink" form:"subHappSubInfoButtonLink"`
+	SubHappSubExpire           bool   `json:"subHappSubExpire" form:"subHappSubExpire"`
+	SubHappSubExpireButtonLink string `json:"subHappSubExpireButtonLink" form:"subHappSubExpireButtonLink"`
+	SubHappNotificationExpire  bool   `json:"subHappNotificationExpire" form:"subHappNotificationExpire"`
+	SubHappNoLimit             bool   `json:"subHappNoLimit" form:"subHappNoLimit"`
+	SubHappAlwaysHwid          bool   `json:"subHappAlwaysHwid" form:"subHappAlwaysHwid"`
+	SubHappTunMode             string `json:"subHappTunMode" form:"subHappTunMode"`
+	SubHappTunType             string `json:"subHappTunType" form:"subHappTunType"`
+	SubHappExcludeRoutes       string `json:"subHappExcludeRoutes" form:"subHappExcludeRoutes"`
+	SubHappExcludeApns         bool   `json:"subHappExcludeApns" form:"subHappExcludeApns"`
+	SubHappColorProfile        string `json:"subHappColorProfile" form:"subHappColorProfile"`
+	SubHappPingType            string `json:"subHappPingType" form:"subHappPingType"`
+	SubHappAutoConnect         bool   `json:"subHappAutoConnect" form:"subHappAutoConnect"`
+	SubHappAutoConnectType     string `json:"subHappAutoConnectType" form:"subHappAutoConnectType"`
+	SubHappPerAppMode          string `json:"subHappPerAppMode" form:"subHappPerAppMode"`
+	SubHappPerAppList          string `json:"subHappPerAppList" form:"subHappPerAppList"`
+
 	LdapEnable             bool   `json:"ldapEnable" form:"ldapEnable"`
 	LdapHost               string `json:"ldapHost" form:"ldapHost"`
 	LdapPort               int    `json:"ldapPort" form:"ldapPort" validate:"gte=0,lte=65535"`

+ 125 - 0
internal/web/service/setting.go

@@ -102,6 +102,29 @@ var defaultValueMap = map[string]string{
 	"subEnableRouting":            "false",
 	"subRoutingRules":             "",
 	"subHideSettings":             "false",
+	"subHappAutoDetect":           "false",
+	"subHappProviderId":           "",
+	"subHappNewUrl":               "",
+	"subHappFallbackUrl":          "",
+	"subHappSubInfoColor":         "blue",
+	"subHappSubInfoText":          "",
+	"subHappSubInfoButtonText":    "",
+	"subHappSubInfoButtonLink":    "",
+	"subHappSubExpire":            "false",
+	"subHappSubExpireButtonLink":  "",
+	"subHappNotificationExpire":   "false",
+	"subHappNoLimit":              "false",
+	"subHappAlwaysHwid":           "false",
+	"subHappTunMode":              "",
+	"subHappTunType":              "",
+	"subHappExcludeRoutes":        "",
+	"subHappExcludeApns":          "false",
+	"subHappColorProfile":         "",
+	"subHappPingType":             "",
+	"subHappAutoConnect":          "false",
+	"subHappAutoConnectType":      "lowestdelay",
+	"subHappPerAppMode":           "off",
+	"subHappPerAppList":           "",
 	"subIncyEnableRouting":        "false",
 	"subIncyRoutingRules":         "",
 	"subListen":                   "",
@@ -820,6 +843,98 @@ func (s *SettingService) GetSubHideSettings() (bool, error) {
 	return s.getBool("subHideSettings")
 }
 
+func (s *SettingService) GetSubHappAutoDetect() (bool, error) {
+	return s.getBool("subHappAutoDetect")
+}
+
+func (s *SettingService) GetSubHappProviderId() (string, error) {
+	return s.getString("subHappProviderId")
+}
+
+func (s *SettingService) GetSubHappNewUrl() (string, error) {
+	return s.getString("subHappNewUrl")
+}
+
+func (s *SettingService) GetSubHappFallbackUrl() (string, error) {
+	return s.getString("subHappFallbackUrl")
+}
+
+func (s *SettingService) GetSubHappSubInfoColor() (string, error) {
+	return s.getString("subHappSubInfoColor")
+}
+
+func (s *SettingService) GetSubHappSubInfoText() (string, error) {
+	return s.getString("subHappSubInfoText")
+}
+
+func (s *SettingService) GetSubHappSubInfoButtonText() (string, error) {
+	return s.getString("subHappSubInfoButtonText")
+}
+
+func (s *SettingService) GetSubHappSubInfoButtonLink() (string, error) {
+	return s.getString("subHappSubInfoButtonLink")
+}
+
+func (s *SettingService) GetSubHappSubExpire() (bool, error) {
+	return s.getBool("subHappSubExpire")
+}
+
+func (s *SettingService) GetSubHappSubExpireButtonLink() (string, error) {
+	return s.getString("subHappSubExpireButtonLink")
+}
+
+func (s *SettingService) GetSubHappNotificationExpire() (bool, error) {
+	return s.getBool("subHappNotificationExpire")
+}
+
+func (s *SettingService) GetSubHappNoLimit() (bool, error) {
+	return s.getBool("subHappNoLimit")
+}
+
+func (s *SettingService) GetSubHappAlwaysHwid() (bool, error) {
+	return s.getBool("subHappAlwaysHwid")
+}
+
+func (s *SettingService) GetSubHappTunMode() (string, error) {
+	return s.getString("subHappTunMode")
+}
+
+func (s *SettingService) GetSubHappTunType() (string, error) {
+	return s.getString("subHappTunType")
+}
+
+func (s *SettingService) GetSubHappExcludeRoutes() (string, error) {
+	return s.getString("subHappExcludeRoutes")
+}
+
+func (s *SettingService) GetSubHappExcludeApns() (bool, error) {
+	return s.getBool("subHappExcludeApns")
+}
+
+func (s *SettingService) GetSubHappColorProfile() (string, error) {
+	return s.getString("subHappColorProfile")
+}
+
+func (s *SettingService) GetSubHappPingType() (string, error) {
+	return s.getString("subHappPingType")
+}
+
+func (s *SettingService) GetSubHappAutoConnect() (bool, error) {
+	return s.getBool("subHappAutoConnect")
+}
+
+func (s *SettingService) GetSubHappAutoConnectType() (string, error) {
+	return s.getString("subHappAutoConnectType")
+}
+
+func (s *SettingService) GetSubHappPerAppMode() (string, error) {
+	return s.getString("subHappPerAppMode")
+}
+
+func (s *SettingService) GetSubHappPerAppList() (string, error) {
+	return s.getString("subHappPerAppList")
+}
+
 func (s *SettingService) GetSubIncyEnableRouting() (bool, error) {
 	return s.getBool("subIncyEnableRouting")
 }
@@ -1363,6 +1478,16 @@ func validateSettingsURLs(allSetting *entity.AllSetting) error {
 	// the scheme instead of forcing SanitizeHTTPURL's http(s)-only rule.
 	allSetting.SubSupportUrl = common.EnsureURLScheme(allSetting.SubSupportUrl)
 	allSetting.SubProfileUrl = common.EnsureURLScheme(allSetting.SubProfileUrl)
+	for _, ptr := range []*string{
+		&allSetting.SubHappNewUrl,
+		&allSetting.SubHappFallbackUrl,
+		&allSetting.SubHappSubInfoButtonLink,
+		&allSetting.SubHappSubExpireButtonLink,
+	} {
+		if strings.TrimSpace(*ptr) != "" {
+			*ptr = common.EnsureURLScheme(strings.TrimSpace(*ptr))
+		}
+	}
 	for name, value := range map[string]*string{
 		"Happ routing source":         &allSetting.SubRoutingRules,
 		"Clash/Mihomo routing source": &allSetting.SubClashRules,

+ 93 - 1
internal/web/translation/ar-EG.json

@@ -1466,7 +1466,99 @@
       "subExpiredTemplate": "قالب انتهاء الصلاحية",
       "subExpiredTemplateDesc": "قالب التكوين الوهمي عند انتهاء صلاحية اشتراك المستخدم.",
       "subTrafficDepletedTemplate": "قالب نفاد البيانات",
-      "subTrafficDepletedTemplateDesc": "قالب التكوين الوهمي عند استهلاك حصة بيانات المستخدم بالكامل."
+      "subTrafficDepletedTemplateDesc": "قالب التكوين الوهمي عند استهلاك حصة بيانات المستخدم بالكامل.",
+      "subHappAutoDetect": "Happ Header Auto-Detection",
+      "subHappAutoDetectDesc": "Automatically inject Happ routing and headers when client User-Agent indicates Happ.",
+      "subHappProviderId": "Provider ID",
+      "subHappProviderIdDesc": "Unique provider identifier for Happ client management, remote configuration binding, and migration.",
+      "subHappNewUrl": "New Subscription URL",
+      "subHappNewUrlDesc": "Target URL for automatic client migration. When set, Happ clients will migrate to this subscription link.",
+      "subHappFallbackUrl": "Fallback Subscription URL",
+      "subHappFallbackUrlDesc": "Backup subscription address used by Happ if the primary subscription URL becomes unreachable.",
+      "subHappSubInfoText": "Banner Announcement Text",
+      "subHappSubInfoTextDesc": "Custom announcement banner displayed at the top of the Happ client (max 200 characters).",
+      "subHappSubInfoColor": "Banner Accent Color",
+      "subHappSubInfoColorDesc": "Color theme style for the announcement banner.",
+      "subHappSubInfoButtonText": "Banner Button Text",
+      "subHappSubInfoButtonTextDesc": "Button label displayed inside the announcement banner (max 25 characters).",
+      "subHappSubInfoButtonLink": "Banner Button Link",
+      "subHappSubInfoButtonLinkDesc": "Target URL opened when the user clicks the banner action button.",
+      "subHappSubExpire": "Expired Subscription Banner",
+      "subHappSubExpireDesc": "Show an expired subscription banner in Happ when the user's traffic or validity has ended.",
+      "subHappSubExpireButtonLink": "Renewal Link",
+      "subHappSubExpireButtonLinkDesc": "Target URL opened when the user clicks the renewal button on an expired subscription.",
+      "subHappNotificationExpire": "Expiration Notifications",
+      "subHappNotificationExpireDesc": "Instruct Happ to alert the user in advance before their subscription expires.",
+      "subHappNoLimit": "Bypass Rule Limit",
+      "subHappNoLimitDesc": "Allow routing rule count to exceed default mobile platform limits without truncation.",
+      "subHappAlwaysHwid": "Enforce Hardware ID (HWID)",
+      "subHappAlwaysHwidDesc": "Bind subscription sessions to client device hardware identifier for enhanced security.",
+      "subHappTunMode": "TUN Mode",
+      "subHappTunModeDesc": "TUN virtual network interface routing mode: default, system, or strict.",
+      "subHappTunType": "TUN Engine",
+      "subHappTunTypeDesc": "Underlying network stack implementation for TUN: system, gVisor, or mixed.",
+      "subHappExcludeRoutes": "Exclude CIDR Routes",
+      "subHappExcludeRoutesDesc": "Comma-separated IP CIDRs (e.g. 192.168.0.0/16, 10.0.0.0/8) to bypass the VPN tunnel.",
+      "subHappExcludeApns": "Exclude Apple APNs",
+      "subHappExcludeApnsDesc": "Bypass Apple Push Notification services to maintain reliable background notifications on iOS.",
+      "subHappColorProfile": "Client Color Theme",
+      "subHappColorProfileDesc": "Client color theme profile: default, violet, turquoise, cyberpunk, or custom JSON theme.",
+      "subHappPingType": "Latency Ping Method",
+      "subHappPingTypeDesc": "Measurement protocol used by Happ for node latency testing: icmp, tcp, or http.",
+      "subHappAutoConnect": "Auto-Connect on Launch",
+      "subHappAutoConnectDesc": "Instruct Happ to automatically connect to VPN when the application starts.",
+      "subHappAutoConnectType": "Auto-Connect Target",
+      "subHappAutoConnectTypeDesc": "Connection target strategy for auto-connect: fastest node or last used node.",
+      "subHappPerAppMode": "Android Per-App Proxy Mode",
+      "subHappPerAppModeDesc": "Control Android application routing: off, include (proxy only listed apps), or exclude (bypass listed apps).",
+      "subHappPerAppList": "Android Package Names",
+      "subHappPerAppListDesc": "Comma-separated package names of Android applications to include or exclude (e.g. com.telegram.messenger).",
+      "subHappPresetIran": "Iran Bypass",
+      "subHappPresetChina": "China Direct",
+      "subHappPresetAdblock": "AdBlock",
+      "subHappPresetGlobal": "Full Proxy",
+      "subHappPresetOff": "تعطيل التوجيه (happ://routing/off)",
+      "subHappColorBlue": "أزرق (قياسي / افتراضي)",
+      "subHappColorGreen": "أخضر (نجاح)",
+      "subHappColorRed": "أحمر (تحذير / خطر)",
+      "subHappTunModeDefault": "افتراضي",
+      "subHappTunModeSystem": "النظام (حزمة نظام التشغيل القياسية)",
+      "subHappTunModeGvisor": "gVisor (حزمة مساحة المستخدم)",
+      "subHappTunTypeSingbox": "sing-box",
+      "subHappTunTypeTun2proxy": "tun2proxy",
+      "subHappTunTypeDefault": "افتراضي (Happ TUN)",
+      "subHappTunTypeXray": "Xray TUN",
+      "subHappPingProxy": "عبر البروكسي (زمن استجابة GET)",
+      "subHappPingProxyHead": "عبر البروكسي (زمن استجابة HEAD)",
+      "subHappPingTcp": "بينج مصافحة TCP",
+      "subHappPingIcmp": "بينج ICMP",
+      "subHappAutoConnectLowestDelay": "أقل تأخير (العقدة الأسرع)",
+      "subHappAutoConnectLastUsed": "آخر عقدة تم استخدامها",
+      "subHappAutoConnectRandom": "عقدة عشوائية",
+      "subHappPerAppOff": "إيقاف",
+      "subHappPerAppOn": "تشغيل (بروكسي للتطبيقات المحددة فقط)",
+      "subHappPerAppBypass": "تجاوز (استثناء التطبيقات المحددة)",
+      "subHappPresetApplied": "Happ preset applied to routing rules",
+      "subHappPresets": "Routing Presets",
+      "subHappPresetsDesc": "Pre-configured routing rule presets tailored for Happ clients.",
+      "subHappVisualBuilder": "Visual Rule Generator",
+      "subHappVisualBuilderDesc": "Create custom routing deeplink from domain and IP lists.",
+      "subHappBuildDeeplink": "Generate Deeplink",
+      "subHappModalTitle": "Happ Visual Routing Rule Generator",
+      "subHappDirectDomains": "Direct Domains (Bypass)",
+      "subHappProxyDomains": "Proxy Domains (Tunnel)",
+      "subHappBlockDomains": "Blocked Domains (Ad/Malware)",
+      "subHappDirectIPs": "Direct IPs / CIDRs",
+      "subHappProxyIPs": "Proxy IPs / CIDRs",
+      "subHappBlockIPs": "Blocked IPs / CIDRs",
+      "subHappDeeplinkGenerated": "Deeplink generated and applied to routing rules",
+      "subHappGroupRouting": "Routing & Rules",
+      "subHappGroupBanners": "Banners & Announcements",
+      "subHappGroupNetwork": "Network & TUN Engine",
+      "subHappGroupThemes": "Appearance & Theme",
+      "subHappGroupFailover": "Migration & App Management",
+      "subHappGroupAndroid": "Android Per-App Proxy"
+
     },
     "xray": {
       "save": "احفظ",

+ 93 - 1
internal/web/translation/en-US.json

@@ -1584,7 +1584,99 @@
       "subExpiredTemplate": "Expired Template",
       "subExpiredTemplateDesc": "Template for the dummy config when the subscriber account has expired.",
       "subTrafficDepletedTemplate": "Traffic Depleted Template",
-      "subTrafficDepletedTemplateDesc": "Template for the dummy config when subscriber traffic quota is exhausted."
+      "subTrafficDepletedTemplateDesc": "Template for the dummy config when subscriber traffic quota is exhausted.",
+      "subHappAutoDetect": "Happ Header Auto-Detection",
+      "subHappAutoDetectDesc": "Automatically inject Happ routing and headers when client User-Agent indicates Happ.",
+      "subHappProviderId": "Provider ID",
+      "subHappProviderIdDesc": "Unique provider identifier for Happ client management, remote configuration binding, and migration.",
+      "subHappNewUrl": "New Subscription URL",
+      "subHappNewUrlDesc": "Target URL for automatic client migration. When set, Happ clients will migrate to this subscription link.",
+      "subHappFallbackUrl": "Fallback Subscription URL",
+      "subHappFallbackUrlDesc": "Backup subscription address used by Happ if the primary subscription URL becomes unreachable.",
+      "subHappSubInfoText": "Banner Announcement Text",
+      "subHappSubInfoTextDesc": "Custom announcement banner displayed at the top of the Happ client (max 200 characters).",
+      "subHappSubInfoColor": "Banner Accent Color",
+      "subHappSubInfoColorDesc": "Color theme style for the announcement banner.",
+      "subHappSubInfoButtonText": "Banner Button Text",
+      "subHappSubInfoButtonTextDesc": "Button label displayed inside the announcement banner (max 25 characters).",
+      "subHappSubInfoButtonLink": "Banner Button Link",
+      "subHappSubInfoButtonLinkDesc": "Target URL opened when the user clicks the banner action button.",
+      "subHappSubExpire": "Expired Subscription Banner",
+      "subHappSubExpireDesc": "Show an expired subscription banner in Happ when the user's traffic or validity has ended.",
+      "subHappSubExpireButtonLink": "Renewal Link",
+      "subHappSubExpireButtonLinkDesc": "Target URL opened when the user clicks the renewal button on an expired subscription.",
+      "subHappNotificationExpire": "Expiration Notifications",
+      "subHappNotificationExpireDesc": "Instruct Happ to alert the user in advance before their subscription expires.",
+      "subHappNoLimit": "Bypass Rule Limit",
+      "subHappNoLimitDesc": "Allow routing rule count to exceed default mobile platform limits without truncation.",
+      "subHappAlwaysHwid": "Enforce Hardware ID (HWID)",
+      "subHappAlwaysHwidDesc": "Bind subscription sessions to client device hardware identifier for enhanced security.",
+      "subHappTunMode": "TUN Mode",
+      "subHappTunModeDesc": "TUN virtual network interface routing mode: default, system, or strict.",
+      "subHappTunType": "TUN Engine",
+      "subHappTunTypeDesc": "Underlying network stack implementation for TUN: system, gVisor, or mixed.",
+      "subHappExcludeRoutes": "Exclude CIDR Routes",
+      "subHappExcludeRoutesDesc": "Comma-separated IP CIDRs (e.g. 192.168.0.0/16, 10.0.0.0/8) to bypass the VPN tunnel.",
+      "subHappExcludeApns": "Exclude Apple APNs",
+      "subHappExcludeApnsDesc": "Bypass Apple Push Notification services to maintain reliable background notifications on iOS.",
+      "subHappColorProfile": "Client Color Theme",
+      "subHappColorProfileDesc": "Client color theme profile: default, violet, turquoise, cyberpunk, or custom JSON theme.",
+      "subHappPingType": "Latency Ping Method",
+      "subHappPingTypeDesc": "Measurement protocol used by Happ for node latency testing: icmp, tcp, or http.",
+      "subHappAutoConnect": "Auto-Connect on Launch",
+      "subHappAutoConnectDesc": "Instruct Happ to automatically connect to VPN when the application starts.",
+      "subHappAutoConnectType": "Auto-Connect Target",
+      "subHappAutoConnectTypeDesc": "Connection target strategy for auto-connect: fastest node or last used node.",
+      "subHappPerAppMode": "Android Per-App Proxy Mode",
+      "subHappPerAppModeDesc": "Control Android application routing: off, include (proxy only listed apps), or exclude (bypass listed apps).",
+      "subHappPerAppList": "Android Package Names",
+      "subHappPerAppListDesc": "Comma-separated package names of Android applications to include or exclude (e.g. com.telegram.messenger).",
+      "subHappPresetIran": "Iran Bypass",
+      "subHappPresetChina": "China Direct",
+      "subHappPresetAdblock": "AdBlock",
+      "subHappPresetGlobal": "Full Proxy",
+      "subHappPresetOff": "Disable Routing (happ://routing/off)",
+      "subHappColorBlue": "Blue (Standard / Default)",
+      "subHappColorGreen": "Green (Success)",
+      "subHappColorRed": "Red (Warning / Danger)",
+      "subHappTunModeDefault": "Default",
+      "subHappTunModeSystem": "System (Standard OS Stack)",
+      "subHappTunModeGvisor": "gVisor (Userspace Stack)",
+      "subHappTunTypeSingbox": "sing-box",
+      "subHappTunTypeTun2proxy": "tun2proxy",
+      "subHappTunTypeDefault": "Default (Happ TUN)",
+      "subHappTunTypeXray": "Xray TUN",
+      "subHappPingProxy": "via Proxy (GET Latency)",
+      "subHappPingProxyHead": "via Proxy (HEAD Latency)",
+      "subHappPingTcp": "TCP Handshake Ping",
+      "subHappPingIcmp": "ICMP Ping",
+      "subHappAutoConnectLowestDelay": "Lowest Delay (Fastest Node)",
+      "subHappAutoConnectLastUsed": "Last Used Node",
+      "subHappAutoConnectRandom": "Random Node",
+      "subHappPerAppOff": "Off",
+      "subHappPerAppOn": "On (Proxy Only Listed Apps)",
+      "subHappPerAppBypass": "Bypass (Exclude Listed Apps)",
+      "subHappPresetApplied": "Happ preset applied to routing rules",
+      "subHappPresets": "Routing Presets",
+      "subHappPresetsDesc": "Pre-configured routing rule presets tailored for Happ clients.",
+      "subHappVisualBuilder": "Visual Rule Generator",
+      "subHappVisualBuilderDesc": "Create custom routing deeplink from domain and IP lists.",
+      "subHappBuildDeeplink": "Generate Deeplink",
+      "subHappModalTitle": "Happ Visual Routing Rule Generator",
+      "subHappDirectDomains": "Direct Domains (Bypass)",
+      "subHappProxyDomains": "Proxy Domains (Tunnel)",
+      "subHappBlockDomains": "Blocked Domains (Ad/Malware)",
+      "subHappDirectIPs": "Direct IPs / CIDRs",
+      "subHappProxyIPs": "Proxy IPs / CIDRs",
+      "subHappBlockIPs": "Blocked IPs / CIDRs",
+      "subHappDeeplinkGenerated": "Deeplink generated and applied to routing rules",
+      "subHappGroupRouting": "Routing & Rules",
+      "subHappGroupBanners": "Banners & Announcements",
+      "subHappGroupNetwork": "Network & TUN Engine",
+      "subHappGroupThemes": "Appearance & Theme",
+      "subHappGroupFailover": "Migration & App Management",
+      "subHappGroupAndroid": "Android Per-App Proxy"
+
     },
     "xray": {
       "save": "Save",

+ 93 - 1
internal/web/translation/es-ES.json

@@ -1466,7 +1466,99 @@
       "subExpiredTemplate": "Plantilla de expirado",
       "subExpiredTemplateDesc": "Plantilla para el nodo ficticio cuando la suscripción ha expirado.",
       "subTrafficDepletedTemplate": "Plantilla de tráfico agotado",
-      "subTrafficDepletedTemplateDesc": "Plantilla para el nodo ficticio cuando el límite de tráfico se ha agotado."
+      "subTrafficDepletedTemplateDesc": "Plantilla para el nodo ficticio cuando el límite de tráfico se ha agotado.",
+      "subHappAutoDetect": "Happ Header Auto-Detection",
+      "subHappAutoDetectDesc": "Automatically inject Happ routing and headers when client User-Agent indicates Happ.",
+      "subHappProviderId": "Provider ID",
+      "subHappProviderIdDesc": "Unique provider identifier for Happ client management, remote configuration binding, and migration.",
+      "subHappNewUrl": "New Subscription URL",
+      "subHappNewUrlDesc": "Target URL for automatic client migration. When set, Happ clients will migrate to this subscription link.",
+      "subHappFallbackUrl": "Fallback Subscription URL",
+      "subHappFallbackUrlDesc": "Backup subscription address used by Happ if the primary subscription URL becomes unreachable.",
+      "subHappSubInfoText": "Banner Announcement Text",
+      "subHappSubInfoTextDesc": "Custom announcement banner displayed at the top of the Happ client (max 200 characters).",
+      "subHappSubInfoColor": "Banner Accent Color",
+      "subHappSubInfoColorDesc": "Color theme style for the announcement banner.",
+      "subHappSubInfoButtonText": "Banner Button Text",
+      "subHappSubInfoButtonTextDesc": "Button label displayed inside the announcement banner (max 25 characters).",
+      "subHappSubInfoButtonLink": "Banner Button Link",
+      "subHappSubInfoButtonLinkDesc": "Target URL opened when the user clicks the banner action button.",
+      "subHappSubExpire": "Expired Subscription Banner",
+      "subHappSubExpireDesc": "Show an expired subscription banner in Happ when the user's traffic or validity has ended.",
+      "subHappSubExpireButtonLink": "Renewal Link",
+      "subHappSubExpireButtonLinkDesc": "Target URL opened when the user clicks the renewal button on an expired subscription.",
+      "subHappNotificationExpire": "Expiration Notifications",
+      "subHappNotificationExpireDesc": "Instruct Happ to alert the user in advance before their subscription expires.",
+      "subHappNoLimit": "Bypass Rule Limit",
+      "subHappNoLimitDesc": "Allow routing rule count to exceed default mobile platform limits without truncation.",
+      "subHappAlwaysHwid": "Enforce Hardware ID (HWID)",
+      "subHappAlwaysHwidDesc": "Bind subscription sessions to client device hardware identifier for enhanced security.",
+      "subHappTunMode": "TUN Mode",
+      "subHappTunModeDesc": "TUN virtual network interface routing mode: default, system, or strict.",
+      "subHappTunType": "TUN Engine",
+      "subHappTunTypeDesc": "Underlying network stack implementation for TUN: system, gVisor, or mixed.",
+      "subHappExcludeRoutes": "Exclude CIDR Routes",
+      "subHappExcludeRoutesDesc": "Comma-separated IP CIDRs (e.g. 192.168.0.0/16, 10.0.0.0/8) to bypass the VPN tunnel.",
+      "subHappExcludeApns": "Exclude Apple APNs",
+      "subHappExcludeApnsDesc": "Bypass Apple Push Notification services to maintain reliable background notifications on iOS.",
+      "subHappColorProfile": "Client Color Theme",
+      "subHappColorProfileDesc": "Client color theme profile: default, violet, turquoise, cyberpunk, or custom JSON theme.",
+      "subHappPingType": "Latency Ping Method",
+      "subHappPingTypeDesc": "Measurement protocol used by Happ for node latency testing: icmp, tcp, or http.",
+      "subHappAutoConnect": "Auto-Connect on Launch",
+      "subHappAutoConnectDesc": "Instruct Happ to automatically connect to VPN when the application starts.",
+      "subHappAutoConnectType": "Auto-Connect Target",
+      "subHappAutoConnectTypeDesc": "Connection target strategy for auto-connect: fastest node or last used node.",
+      "subHappPerAppMode": "Android Per-App Proxy Mode",
+      "subHappPerAppModeDesc": "Control Android application routing: off, include (proxy only listed apps), or exclude (bypass listed apps).",
+      "subHappPerAppList": "Android Package Names",
+      "subHappPerAppListDesc": "Comma-separated package names of Android applications to include or exclude (e.g. com.telegram.messenger).",
+      "subHappPresetIran": "Iran Bypass",
+      "subHappPresetChina": "China Direct",
+      "subHappPresetAdblock": "AdBlock",
+      "subHappPresetGlobal": "Full Proxy",
+      "subHappPresetOff": "Desactivar enrutamiento (happ://routing/off)",
+      "subHappColorBlue": "Azul (estándar / predeterminado)",
+      "subHappColorGreen": "Verde (éxito)",
+      "subHappColorRed": "Rojo (advertencia / peligro)",
+      "subHappTunModeDefault": "Predeterminado",
+      "subHappTunModeSystem": "Sistema (pila estándar del SO)",
+      "subHappTunModeGvisor": "gVisor (pila de espacio de usuario)",
+      "subHappTunTypeSingbox": "sing-box",
+      "subHappTunTypeTun2proxy": "tun2proxy",
+      "subHappTunTypeDefault": "Predeterminado (Happ TUN)",
+      "subHappTunTypeXray": "Xray TUN",
+      "subHappPingProxy": "Vía proxy (latencia GET)",
+      "subHappPingProxyHead": "Vía proxy (latencia HEAD)",
+      "subHappPingTcp": "Ping de saludo TCP",
+      "subHappPingIcmp": "Ping ICMP",
+      "subHappAutoConnectLowestDelay": "Menor latencia (nodo más rápido)",
+      "subHappAutoConnectLastUsed": "Último nodo utilizado",
+      "subHappAutoConnectRandom": "Nodo aleatorio",
+      "subHappPerAppOff": "Desactivado",
+      "subHappPerAppOn": "Activado (solo apps de la lista)",
+      "subHappPerAppBypass": "Omitir (excluir apps de la lista)",
+      "subHappPresetApplied": "Happ preset applied to routing rules",
+      "subHappPresets": "Routing Presets",
+      "subHappPresetsDesc": "Pre-configured routing rule presets tailored for Happ clients.",
+      "subHappVisualBuilder": "Visual Rule Generator",
+      "subHappVisualBuilderDesc": "Create custom routing deeplink from domain and IP lists.",
+      "subHappBuildDeeplink": "Generate Deeplink",
+      "subHappModalTitle": "Happ Visual Routing Rule Generator",
+      "subHappDirectDomains": "Direct Domains (Bypass)",
+      "subHappProxyDomains": "Proxy Domains (Tunnel)",
+      "subHappBlockDomains": "Blocked Domains (Ad/Malware)",
+      "subHappDirectIPs": "Direct IPs / CIDRs",
+      "subHappProxyIPs": "Proxy IPs / CIDRs",
+      "subHappBlockIPs": "Blocked IPs / CIDRs",
+      "subHappDeeplinkGenerated": "Deeplink generated and applied to routing rules",
+      "subHappGroupRouting": "Routing & Rules",
+      "subHappGroupBanners": "Banners & Announcements",
+      "subHappGroupNetwork": "Network & TUN Engine",
+      "subHappGroupThemes": "Appearance & Theme",
+      "subHappGroupFailover": "Migration & App Management",
+      "subHappGroupAndroid": "Android Per-App Proxy"
+
     },
     "xray": {
       "save": "Guardar configuración",

+ 93 - 1
internal/web/translation/fa-IR.json

@@ -1466,7 +1466,99 @@
       "subExpiredTemplate": "قالب پیام انقضا",
       "subExpiredTemplateDesc": "قالب کانفیگ نمایشی زمانی که اشتراک کاربر منقضی شده است.",
       "subTrafficDepletedTemplate": "قالب پیام اتمام حجم",
-      "subTrafficDepletedTemplateDesc": "قالب کانفیگ نمایشی زمانی که حجم اشتراک کاربر به پایان رسیده است."
+      "subTrafficDepletedTemplateDesc": "قالب کانفیگ نمایشی زمانی که حجم اشتراک کاربر به پایان رسیده است.",
+      "subHappAutoDetect": "تشخیص خودکار کلاینت Happ",
+      "subHappAutoDetectDesc": "تزریق خودکار هدرها و روتینگ Happ هنگامی که User-Agent کلاینت مربوط به برنامه Happ باشد.",
+      "subHappProviderId": "شناسه ارائه‌دهنده (Provider ID)",
+      "subHappProviderIdDesc": "شناسه یکتا جهت مدیریت کلاینت Happ، اتصال به کانفیگ ریموت و مهاجرت کاربران.",
+      "subHappNewUrl": "لینک اشتراک جدید (مهاجرت)",
+      "subHappNewUrlDesc": "آدرس اشتراک جدید جهت انتقال خودکار؛ برنامه Happ پس از دریافت، آدرس اشتراک را به این لینک تغییر می‌دهد.",
+      "subHappFallbackUrl": "لینک اشتراک پشتیبان (Fallback)",
+      "subHappFallbackUrlDesc": "آدرس اشتراک جایگزین در صورت در دسترس نبودن سرور اصلی اشتراک.",
+      "subHappSubInfoText": "متن بنر اعلانات",
+      "subHappSubInfoTextDesc": "پیام اعلان سفارشی در بالای صفحه برنامه Happ (حداکثر ۲۰۰ نویسه).",
+      "subHappSubInfoColor": "رنگ بنر اعلانات",
+      "subHappSubInfoColorDesc": "تم رنگی بنر اعلان (پیش‌فرض، اطلاع‌رسانی، موفقیت، هشدار یا اخطار).",
+      "subHappSubInfoButtonText": "متن دکمه بنر",
+      "subHappSubInfoButtonTextDesc": "عنوان دکمه اقدام در بنر اعلان (حداکثر ۲۵ نویسه).",
+      "subHappSubInfoButtonLink": "لینک دکمه بنر",
+      "subHappSubInfoButtonLinkDesc": "آدرسی که با کلیک روی دکمه بنر باز می‌شود.",
+      "subHappSubExpire": "بنر اشتراک منقضی‌شده",
+      "subHappSubExpireDesc": "نمایش بنر تمدید در برنامه Happ در صورت اتمام ترافیک یا زمان اشتراک کاربر.",
+      "subHappSubExpireButtonLink": "لینک تمدید اشتراک",
+      "subHappSubExpireButtonLinkDesc": "آدرس صفحه خرید یا تمدید اشتراک منقضی‌شده.",
+      "subHappNotificationExpire": "اعلان انقضای اشتراک",
+      "subHappNotificationExpireDesc": "نمایش هشدار انقضای اشتراک به کاربر پیش از پایان اعتبار در برنامه Happ.",
+      "subHappNoLimit": "حذف محدودیت تعداد قوانین",
+      "subHappNoLimitDesc": "اجازه اعمال تعداد نامحدود قوانین روتینگ بدون برش خوردن روی سیستم‌های تلفن همراه.",
+      "subHappAlwaysHwid": "الزام شناسه سخت‌افزاری (HWID)",
+      "subHappAlwaysHwidDesc": "قفل کردن درخواست‌های اشتراک به شناسه سخت‌افزاری دستگاه جهت جلوگیری از اشتراک‌گذاری اکانت.",
+      "subHappTunMode": "حالت تونل (TUN Mode)",
+      "subHappTunModeDesc": "حالت رابط شبکه مجازی TUN در برنامه Happ (پیش‌فرض، سیستمی یا سخت‌گیرانه).",
+      "subHappTunType": "موتور شبکه TUN",
+      "subHappTunTypeDesc": "پشته شبکه مورد استفاده برای TUN (سیستمی، gVisor یا ترکیبی).",
+      "subHappExcludeRoutes": "مستثنی کردن مسیرهای CIDR",
+      "subHappExcludeRoutesDesc": "رنج‌های IP جدا شده با کاما جهت دور زدن تونل VPN (مانند 192.168.0.0/16, 10.0.0.0/8).",
+      "subHappExcludeApns": "مستثنی کردن سرویس‌های اعلان اپل (APNs)",
+      "subHappExcludeApnsDesc": "دور زدن سرویس‌های اعلان اپل برای اطمینان از دریافت پایدار ناتیفیکیشن‌ها در iOS.",
+      "subHappColorProfile": "پروفایل رنگ و پوسته",
+      "subHappColorProfileDesc": "پوسته ظاهری برنامه Happ (بنفش، فیروزه‌ای، سایبرپانک یا JSON سفارشی).",
+      "subHappPingType": "روش تست پینگ",
+      "subHappPingTypeDesc": "پروتکل اندازه‌گیری تأخیر گره‌ها در برنامه Happ (icmp، tcp یا http).",
+      "subHappAutoConnect": "اتصال خودکار هنگام اجرا",
+      "subHappAutoConnectDesc": "اتصال خودکار به وی‌پی‌ان با باز شدن برنامه Happ.",
+      "subHappAutoConnectType": "راهبرد اتصال خودکار",
+      "subHappAutoConnectTypeDesc": "هدف اتصال خودکار: سریع‌ترین سرور یا آخرین سرور استفاده‌شده.",
+      "subHappPerAppMode": "پراکسی انتخابی برنامه‌ها در اندروید",
+      "subHappPerAppModeDesc": "مدیریت عبور ترافیک برنامه‌های اندروید: خاموش، عبور فقط برنامه‌های منتخب یا مستثنی کردن آن‌ها.",
+      "subHappPerAppList": "نام بسته‌های برنامه‌های اندروید",
+      "subHappPerAppListDesc": "نام بسته‌های اپلیکیشن‌های اندروید جدا شده با کاما (مانند com.telegram.messenger).",
+      "subHappPresetIran": "دور زدن سایت‌های ایران (Iran Bypass)",
+      "subHappPresetChina": "دور زدن چین (China Direct)",
+      "subHappPresetAdblock": "مسدودسازی تبلیغات (AdBlock)",
+      "subHappPresetGlobal": "پراکسی کل ترافیک (Global)",
+      "subHappPresetOff": "غیرفعال‌سازی روتینگ (happ://routing/off)",
+      "subHappColorBlue": "آبی (استاندارد / پیش‌فرض)",
+      "subHappColorGreen": "سبز (موفقیت)",
+      "subHappColorRed": "قرمز (هشدار / خطر)",
+      "subHappTunModeDefault": "پیش‌فرض",
+      "subHappTunModeSystem": "سیستم (استک استاندارد سیستم‌عامل)",
+      "subHappTunModeGvisor": "gVisor (استک فضای کاربری)",
+      "subHappTunTypeSingbox": "sing-box",
+      "subHappTunTypeTun2proxy": "tun2proxy",
+      "subHappTunTypeDefault": "پیش‌فرض (Happ TUN)",
+      "subHappTunTypeXray": "Xray TUN",
+      "subHappPingProxy": "از طریق پروکسی (تأخیر GET)",
+      "subHappPingProxyHead": "از طریق پروکسی (تأخیر HEAD)",
+      "subHappPingTcp": "پینگ دست‌دادن TCP",
+      "subHappPingIcmp": "پینگ ICMP",
+      "subHappAutoConnectLowestDelay": "کمترین تأخیر (سریع‌ترین نود)",
+      "subHappAutoConnectLastUsed": "آخرین نود استفاده‌شده",
+      "subHappAutoConnectRandom": "نود تصادفی",
+      "subHappPerAppOff": "خاموش",
+      "subHappPerAppOn": "روشن (فقط برنامه‌های فهرست‌شده)",
+      "subHappPerAppBypass": "بای‌پس (مستثنی‌کردن برنامه‌های فهرست‌شده)",
+      "subHappPresetApplied": "الگوی روتینگ Happ اعمال شد",
+      "subHappPresets": "الگوهای آماده روتینگ",
+      "subHappPresetsDesc": "الگوهای آماده و بهینه‌سازی‌شده برای روتینگ در برنامه Happ.",
+      "subHappVisualBuilder": "سازنده بصری قوانین",
+      "subHappVisualBuilderDesc": "ایجاد آسان دیپ‌لینک روتینگ سفارشی بر اساس دامنه‌ها و آی‌پی‌ها.",
+      "subHappBuildDeeplink": "تولید دیپ‌لینک",
+      "subHappModalTitle": "سازنده بصری قوانین روتینگ Happ",
+      "subHappDirectDomains": "دامنه‌های مستقیم (Direct)",
+      "subHappProxyDomains": "دامنه‌های پراکسی (Proxy)",
+      "subHappBlockDomains": "دامنه‌های مسدود (Block)",
+      "subHappDirectIPs": "آی‌پی‌های مستقیم (Direct CIDRs)",
+      "subHappProxyIPs": "آی‌پی‌های پراکسی (Proxy CIDRs)",
+      "subHappBlockIPs": "آی‌پی‌های مسدود (Block CIDRs)",
+      "subHappDeeplinkGenerated": "دیپ‌لینک تولید و در قوانین روتینگ اعمال شد",
+      "subHappGroupRouting": "قوانین و روتینگ",
+      "subHappGroupBanners": "اعلانات و بنرهای هوشمند",
+      "subHappGroupNetwork": "تنظیمات شبکه و TUN",
+      "subHappGroupThemes": "ظاهر و پوسته برنامه",
+      "subHappGroupFailover": "مهاجرت و مدیریت کلاینت",
+      "subHappGroupAndroid": "پراکسی برنامه‌های اندروید"
+
     },
     "xray": {
       "save": "ذخیره",

+ 93 - 1
internal/web/translation/id-ID.json

@@ -1466,7 +1466,99 @@
       "subExpiredTemplate": "Templat Kedaluwarsa",
       "subExpiredTemplateDesc": "Templat untuk konfigurasi dummy saat akun langganan telah kedaluwarsa.",
       "subTrafficDepletedTemplate": "Templat Kuota Habis",
-      "subTrafficDepletedTemplateDesc": "Templat untuk konfigurasi dummy saat kuota data langganan telah habis."
+      "subTrafficDepletedTemplateDesc": "Templat untuk konfigurasi dummy saat kuota data langganan telah habis.",
+      "subHappAutoDetect": "Happ Header Auto-Detection",
+      "subHappAutoDetectDesc": "Automatically inject Happ routing and headers when client User-Agent indicates Happ.",
+      "subHappProviderId": "Provider ID",
+      "subHappProviderIdDesc": "Unique provider identifier for Happ client management, remote configuration binding, and migration.",
+      "subHappNewUrl": "New Subscription URL",
+      "subHappNewUrlDesc": "Target URL for automatic client migration. When set, Happ clients will migrate to this subscription link.",
+      "subHappFallbackUrl": "Fallback Subscription URL",
+      "subHappFallbackUrlDesc": "Backup subscription address used by Happ if the primary subscription URL becomes unreachable.",
+      "subHappSubInfoText": "Banner Announcement Text",
+      "subHappSubInfoTextDesc": "Custom announcement banner displayed at the top of the Happ client (max 200 characters).",
+      "subHappSubInfoColor": "Banner Accent Color",
+      "subHappSubInfoColorDesc": "Color theme style for the announcement banner.",
+      "subHappSubInfoButtonText": "Banner Button Text",
+      "subHappSubInfoButtonTextDesc": "Button label displayed inside the announcement banner (max 25 characters).",
+      "subHappSubInfoButtonLink": "Banner Button Link",
+      "subHappSubInfoButtonLinkDesc": "Target URL opened when the user clicks the banner action button.",
+      "subHappSubExpire": "Expired Subscription Banner",
+      "subHappSubExpireDesc": "Show an expired subscription banner in Happ when the user's traffic or validity has ended.",
+      "subHappSubExpireButtonLink": "Renewal Link",
+      "subHappSubExpireButtonLinkDesc": "Target URL opened when the user clicks the renewal button on an expired subscription.",
+      "subHappNotificationExpire": "Expiration Notifications",
+      "subHappNotificationExpireDesc": "Instruct Happ to alert the user in advance before their subscription expires.",
+      "subHappNoLimit": "Bypass Rule Limit",
+      "subHappNoLimitDesc": "Allow routing rule count to exceed default mobile platform limits without truncation.",
+      "subHappAlwaysHwid": "Enforce Hardware ID (HWID)",
+      "subHappAlwaysHwidDesc": "Bind subscription sessions to client device hardware identifier for enhanced security.",
+      "subHappTunMode": "TUN Mode",
+      "subHappTunModeDesc": "TUN virtual network interface routing mode: default, system, or strict.",
+      "subHappTunType": "TUN Engine",
+      "subHappTunTypeDesc": "Underlying network stack implementation for TUN: system, gVisor, or mixed.",
+      "subHappExcludeRoutes": "Exclude CIDR Routes",
+      "subHappExcludeRoutesDesc": "Comma-separated IP CIDRs (e.g. 192.168.0.0/16, 10.0.0.0/8) to bypass the VPN tunnel.",
+      "subHappExcludeApns": "Exclude Apple APNs",
+      "subHappExcludeApnsDesc": "Bypass Apple Push Notification services to maintain reliable background notifications on iOS.",
+      "subHappColorProfile": "Client Color Theme",
+      "subHappColorProfileDesc": "Client color theme profile: default, violet, turquoise, cyberpunk, or custom JSON theme.",
+      "subHappPingType": "Latency Ping Method",
+      "subHappPingTypeDesc": "Measurement protocol used by Happ for node latency testing: icmp, tcp, or http.",
+      "subHappAutoConnect": "Auto-Connect on Launch",
+      "subHappAutoConnectDesc": "Instruct Happ to automatically connect to VPN when the application starts.",
+      "subHappAutoConnectType": "Auto-Connect Target",
+      "subHappAutoConnectTypeDesc": "Connection target strategy for auto-connect: fastest node or last used node.",
+      "subHappPerAppMode": "Android Per-App Proxy Mode",
+      "subHappPerAppModeDesc": "Control Android application routing: off, include (proxy only listed apps), or exclude (bypass listed apps).",
+      "subHappPerAppList": "Android Package Names",
+      "subHappPerAppListDesc": "Comma-separated package names of Android applications to include or exclude (e.g. com.telegram.messenger).",
+      "subHappPresetIran": "Iran Bypass",
+      "subHappPresetChina": "China Direct",
+      "subHappPresetAdblock": "AdBlock",
+      "subHappPresetGlobal": "Full Proxy",
+      "subHappPresetOff": "Nonaktifkan Perutean (happ://routing/off)",
+      "subHappColorBlue": "Biru (Standar / Default)",
+      "subHappColorGreen": "Hijau (Sukses)",
+      "subHappColorRed": "Merah (Peringatan / Bahaya)",
+      "subHappTunModeDefault": "Default",
+      "subHappTunModeSystem": "Sistem (Stack OS Standar)",
+      "subHappTunModeGvisor": "gVisor (Stack Userspace)",
+      "subHappTunTypeSingbox": "sing-box",
+      "subHappTunTypeTun2proxy": "tun2proxy",
+      "subHappTunTypeDefault": "Default (Happ TUN)",
+      "subHappTunTypeXray": "Xray TUN",
+      "subHappPingProxy": "Melalui Proxy (Latensi GET)",
+      "subHappPingProxyHead": "Melalui Proxy (Latensi HEAD)",
+      "subHappPingTcp": "Ping Handshake TCP",
+      "subHappPingIcmp": "Ping ICMP",
+      "subHappAutoConnectLowestDelay": "Latensi Terendah (Node Tercepat)",
+      "subHappAutoConnectLastUsed": "Node Terakhir Digunakan",
+      "subHappAutoConnectRandom": "Node Acak",
+      "subHappPerAppOff": "Mati",
+      "subHappPerAppOn": "Nyala (Hanya Proksikan Aplikasi Terdaftar)",
+      "subHappPerAppBypass": "Bypass (Kecualikan Aplikasi Terdaftar)",
+      "subHappPresetApplied": "Happ preset applied to routing rules",
+      "subHappPresets": "Routing Presets",
+      "subHappPresetsDesc": "Pre-configured routing rule presets tailored for Happ clients.",
+      "subHappVisualBuilder": "Visual Rule Generator",
+      "subHappVisualBuilderDesc": "Create custom routing deeplink from domain and IP lists.",
+      "subHappBuildDeeplink": "Generate Deeplink",
+      "subHappModalTitle": "Happ Visual Routing Rule Generator",
+      "subHappDirectDomains": "Direct Domains (Bypass)",
+      "subHappProxyDomains": "Proxy Domains (Tunnel)",
+      "subHappBlockDomains": "Blocked Domains (Ad/Malware)",
+      "subHappDirectIPs": "Direct IPs / CIDRs",
+      "subHappProxyIPs": "Proxy IPs / CIDRs",
+      "subHappBlockIPs": "Blocked IPs / CIDRs",
+      "subHappDeeplinkGenerated": "Deeplink generated and applied to routing rules",
+      "subHappGroupRouting": "Routing & Rules",
+      "subHappGroupBanners": "Banners & Announcements",
+      "subHappGroupNetwork": "Network & TUN Engine",
+      "subHappGroupThemes": "Appearance & Theme",
+      "subHappGroupFailover": "Migration & App Management",
+      "subHappGroupAndroid": "Android Per-App Proxy"
+
     },
     "xray": {
       "save": "Simpan",

+ 93 - 1
internal/web/translation/ja-JP.json

@@ -1466,7 +1466,99 @@
       "subExpiredTemplate": "期限切れテンプレート",
       "subExpiredTemplateDesc": "サブスクリプションの有効期限が切れた際のダミー構成用テンプレート。",
       "subTrafficDepletedTemplate": "通信量超過テンプレート",
-      "subTrafficDepletedTemplateDesc": "サブスクリプションの通信量が上限に達した際のダミー構成用テンプレート。"
+      "subTrafficDepletedTemplateDesc": "サブスクリプションの通信量が上限に達した際のダミー構成用テンプレート。",
+      "subHappAutoDetect": "Happ Header Auto-Detection",
+      "subHappAutoDetectDesc": "Automatically inject Happ routing and headers when client User-Agent indicates Happ.",
+      "subHappProviderId": "Provider ID",
+      "subHappProviderIdDesc": "Unique provider identifier for Happ client management, remote configuration binding, and migration.",
+      "subHappNewUrl": "New Subscription URL",
+      "subHappNewUrlDesc": "Target URL for automatic client migration. When set, Happ clients will migrate to this subscription link.",
+      "subHappFallbackUrl": "Fallback Subscription URL",
+      "subHappFallbackUrlDesc": "Backup subscription address used by Happ if the primary subscription URL becomes unreachable.",
+      "subHappSubInfoText": "Banner Announcement Text",
+      "subHappSubInfoTextDesc": "Custom announcement banner displayed at the top of the Happ client (max 200 characters).",
+      "subHappSubInfoColor": "Banner Accent Color",
+      "subHappSubInfoColorDesc": "Color theme style for the announcement banner.",
+      "subHappSubInfoButtonText": "Banner Button Text",
+      "subHappSubInfoButtonTextDesc": "Button label displayed inside the announcement banner (max 25 characters).",
+      "subHappSubInfoButtonLink": "Banner Button Link",
+      "subHappSubInfoButtonLinkDesc": "Target URL opened when the user clicks the banner action button.",
+      "subHappSubExpire": "Expired Subscription Banner",
+      "subHappSubExpireDesc": "Show an expired subscription banner in Happ when the user's traffic or validity has ended.",
+      "subHappSubExpireButtonLink": "Renewal Link",
+      "subHappSubExpireButtonLinkDesc": "Target URL opened when the user clicks the renewal button on an expired subscription.",
+      "subHappNotificationExpire": "Expiration Notifications",
+      "subHappNotificationExpireDesc": "Instruct Happ to alert the user in advance before their subscription expires.",
+      "subHappNoLimit": "Bypass Rule Limit",
+      "subHappNoLimitDesc": "Allow routing rule count to exceed default mobile platform limits without truncation.",
+      "subHappAlwaysHwid": "Enforce Hardware ID (HWID)",
+      "subHappAlwaysHwidDesc": "Bind subscription sessions to client device hardware identifier for enhanced security.",
+      "subHappTunMode": "TUN Mode",
+      "subHappTunModeDesc": "TUN virtual network interface routing mode: default, system, or strict.",
+      "subHappTunType": "TUN Engine",
+      "subHappTunTypeDesc": "Underlying network stack implementation for TUN: system, gVisor, or mixed.",
+      "subHappExcludeRoutes": "Exclude CIDR Routes",
+      "subHappExcludeRoutesDesc": "Comma-separated IP CIDRs (e.g. 192.168.0.0/16, 10.0.0.0/8) to bypass the VPN tunnel.",
+      "subHappExcludeApns": "Exclude Apple APNs",
+      "subHappExcludeApnsDesc": "Bypass Apple Push Notification services to maintain reliable background notifications on iOS.",
+      "subHappColorProfile": "Client Color Theme",
+      "subHappColorProfileDesc": "Client color theme profile: default, violet, turquoise, cyberpunk, or custom JSON theme.",
+      "subHappPingType": "Latency Ping Method",
+      "subHappPingTypeDesc": "Measurement protocol used by Happ for node latency testing: icmp, tcp, or http.",
+      "subHappAutoConnect": "Auto-Connect on Launch",
+      "subHappAutoConnectDesc": "Instruct Happ to automatically connect to VPN when the application starts.",
+      "subHappAutoConnectType": "Auto-Connect Target",
+      "subHappAutoConnectTypeDesc": "Connection target strategy for auto-connect: fastest node or last used node.",
+      "subHappPerAppMode": "Android Per-App Proxy Mode",
+      "subHappPerAppModeDesc": "Control Android application routing: off, include (proxy only listed apps), or exclude (bypass listed apps).",
+      "subHappPerAppList": "Android Package Names",
+      "subHappPerAppListDesc": "Comma-separated package names of Android applications to include or exclude (e.g. com.telegram.messenger).",
+      "subHappPresetIran": "Iran Bypass",
+      "subHappPresetChina": "China Direct",
+      "subHappPresetAdblock": "AdBlock",
+      "subHappPresetGlobal": "Full Proxy",
+      "subHappPresetOff": "ルーティングを無効化 (happ://routing/off)",
+      "subHappColorBlue": "ブルー (標準 / デフォルト)",
+      "subHappColorGreen": "グリーン (成功)",
+      "subHappColorRed": "レッド (警告 / 危険)",
+      "subHappTunModeDefault": "デフォルト",
+      "subHappTunModeSystem": "システム (標準OSスタック)",
+      "subHappTunModeGvisor": "gVisor (ユーザー空間スタック)",
+      "subHappTunTypeSingbox": "sing-box",
+      "subHappTunTypeTun2proxy": "tun2proxy",
+      "subHappTunTypeDefault": "デフォルト (Happ TUN)",
+      "subHappTunTypeXray": "Xray TUN",
+      "subHappPingProxy": "プロキシ経由 (GET遅延)",
+      "subHappPingProxyHead": "プロキシ経由 (HEAD遅延)",
+      "subHappPingTcp": "TCPハンドシェイク Ping",
+      "subHappPingIcmp": "ICMP Ping",
+      "subHappAutoConnectLowestDelay": "最小遅延 (最速ノード)",
+      "subHappAutoConnectLastUsed": "最後に使用したノード",
+      "subHappAutoConnectRandom": "ランダムノード",
+      "subHappPerAppOff": "オフ",
+      "subHappPerAppOn": "オン (リストされたアプリのみプロキシ)",
+      "subHappPerAppBypass": "バイパス (リストされたアプリを除外)",
+      "subHappPresetApplied": "Happ preset applied to routing rules",
+      "subHappPresets": "Routing Presets",
+      "subHappPresetsDesc": "Pre-configured routing rule presets tailored for Happ clients.",
+      "subHappVisualBuilder": "Visual Rule Generator",
+      "subHappVisualBuilderDesc": "Create custom routing deeplink from domain and IP lists.",
+      "subHappBuildDeeplink": "Generate Deeplink",
+      "subHappModalTitle": "Happ Visual Routing Rule Generator",
+      "subHappDirectDomains": "Direct Domains (Bypass)",
+      "subHappProxyDomains": "Proxy Domains (Tunnel)",
+      "subHappBlockDomains": "Blocked Domains (Ad/Malware)",
+      "subHappDirectIPs": "Direct IPs / CIDRs",
+      "subHappProxyIPs": "Proxy IPs / CIDRs",
+      "subHappBlockIPs": "Blocked IPs / CIDRs",
+      "subHappDeeplinkGenerated": "Deeplink generated and applied to routing rules",
+      "subHappGroupRouting": "Routing & Rules",
+      "subHappGroupBanners": "Banners & Announcements",
+      "subHappGroupNetwork": "Network & TUN Engine",
+      "subHappGroupThemes": "Appearance & Theme",
+      "subHappGroupFailover": "Migration & App Management",
+      "subHappGroupAndroid": "Android Per-App Proxy"
+
     },
     "xray": {
       "importRules": "ルールをインポート",

+ 93 - 1
internal/web/translation/pt-BR.json

@@ -1466,7 +1466,99 @@
       "subExpiredTemplate": "Modelo expirado",
       "subExpiredTemplateDesc": "Modelo para a configuração fictícia quando a assinatura expirou.",
       "subTrafficDepletedTemplate": "Modelo de tráfego esgotado",
-      "subTrafficDepletedTemplateDesc": "Modelo para a configuração fictícia quando a cota de tráfego foi esgotada."
+      "subTrafficDepletedTemplateDesc": "Modelo para a configuração fictícia quando a cota de tráfego foi esgotada.",
+      "subHappAutoDetect": "Happ Header Auto-Detection",
+      "subHappAutoDetectDesc": "Automatically inject Happ routing and headers when client User-Agent indicates Happ.",
+      "subHappProviderId": "Provider ID",
+      "subHappProviderIdDesc": "Unique provider identifier for Happ client management, remote configuration binding, and migration.",
+      "subHappNewUrl": "New Subscription URL",
+      "subHappNewUrlDesc": "Target URL for automatic client migration. When set, Happ clients will migrate to this subscription link.",
+      "subHappFallbackUrl": "Fallback Subscription URL",
+      "subHappFallbackUrlDesc": "Backup subscription address used by Happ if the primary subscription URL becomes unreachable.",
+      "subHappSubInfoText": "Banner Announcement Text",
+      "subHappSubInfoTextDesc": "Custom announcement banner displayed at the top of the Happ client (max 200 characters).",
+      "subHappSubInfoColor": "Banner Accent Color",
+      "subHappSubInfoColorDesc": "Color theme style for the announcement banner.",
+      "subHappSubInfoButtonText": "Banner Button Text",
+      "subHappSubInfoButtonTextDesc": "Button label displayed inside the announcement banner (max 25 characters).",
+      "subHappSubInfoButtonLink": "Banner Button Link",
+      "subHappSubInfoButtonLinkDesc": "Target URL opened when the user clicks the banner action button.",
+      "subHappSubExpire": "Expired Subscription Banner",
+      "subHappSubExpireDesc": "Show an expired subscription banner in Happ when the user's traffic or validity has ended.",
+      "subHappSubExpireButtonLink": "Renewal Link",
+      "subHappSubExpireButtonLinkDesc": "Target URL opened when the user clicks the renewal button on an expired subscription.",
+      "subHappNotificationExpire": "Expiration Notifications",
+      "subHappNotificationExpireDesc": "Instruct Happ to alert the user in advance before their subscription expires.",
+      "subHappNoLimit": "Bypass Rule Limit",
+      "subHappNoLimitDesc": "Allow routing rule count to exceed default mobile platform limits without truncation.",
+      "subHappAlwaysHwid": "Enforce Hardware ID (HWID)",
+      "subHappAlwaysHwidDesc": "Bind subscription sessions to client device hardware identifier for enhanced security.",
+      "subHappTunMode": "TUN Mode",
+      "subHappTunModeDesc": "TUN virtual network interface routing mode: default, system, or strict.",
+      "subHappTunType": "TUN Engine",
+      "subHappTunTypeDesc": "Underlying network stack implementation for TUN: system, gVisor, or mixed.",
+      "subHappExcludeRoutes": "Exclude CIDR Routes",
+      "subHappExcludeRoutesDesc": "Comma-separated IP CIDRs (e.g. 192.168.0.0/16, 10.0.0.0/8) to bypass the VPN tunnel.",
+      "subHappExcludeApns": "Exclude Apple APNs",
+      "subHappExcludeApnsDesc": "Bypass Apple Push Notification services to maintain reliable background notifications on iOS.",
+      "subHappColorProfile": "Client Color Theme",
+      "subHappColorProfileDesc": "Client color theme profile: default, violet, turquoise, cyberpunk, or custom JSON theme.",
+      "subHappPingType": "Latency Ping Method",
+      "subHappPingTypeDesc": "Measurement protocol used by Happ for node latency testing: icmp, tcp, or http.",
+      "subHappAutoConnect": "Auto-Connect on Launch",
+      "subHappAutoConnectDesc": "Instruct Happ to automatically connect to VPN when the application starts.",
+      "subHappAutoConnectType": "Auto-Connect Target",
+      "subHappAutoConnectTypeDesc": "Connection target strategy for auto-connect: fastest node or last used node.",
+      "subHappPerAppMode": "Android Per-App Proxy Mode",
+      "subHappPerAppModeDesc": "Control Android application routing: off, include (proxy only listed apps), or exclude (bypass listed apps).",
+      "subHappPerAppList": "Android Package Names",
+      "subHappPerAppListDesc": "Comma-separated package names of Android applications to include or exclude (e.g. com.telegram.messenger).",
+      "subHappPresetIran": "Iran Bypass",
+      "subHappPresetChina": "China Direct",
+      "subHappPresetAdblock": "AdBlock",
+      "subHappPresetGlobal": "Full Proxy",
+      "subHappPresetOff": "Desativar roteamento (happ://routing/off)",
+      "subHappColorBlue": "Azul (padrão)",
+      "subHappColorGreen": "Verde (sucesso)",
+      "subHappColorRed": "Vermelho (aviso / perigo)",
+      "subHappTunModeDefault": "Padrão",
+      "subHappTunModeSystem": "Sistema (pilha padrão do SO)",
+      "subHappTunModeGvisor": "gVisor (pilha de espaço do usuário)",
+      "subHappTunTypeSingbox": "sing-box",
+      "subHappTunTypeTun2proxy": "tun2proxy",
+      "subHappTunTypeDefault": "Padrão (Happ TUN)",
+      "subHappTunTypeXray": "Xray TUN",
+      "subHappPingProxy": "Via proxy (latência GET)",
+      "subHappPingProxyHead": "Via proxy (latência HEAD)",
+      "subHappPingTcp": "Ping de handshake TCP",
+      "subHappPingIcmp": "Ping ICMP",
+      "subHappAutoConnectLowestDelay": "Menor latência (nó mais rápido)",
+      "subHappAutoConnectLastUsed": "Último nó usado",
+      "subHappAutoConnectRandom": "Nó aleatório",
+      "subHappPerAppOff": "Desativado",
+      "subHappPerAppOn": "Ativado (apenas apps listados)",
+      "subHappPerAppBypass": "Desviar (excluir apps listados)",
+      "subHappPresetApplied": "Happ preset applied to routing rules",
+      "subHappPresets": "Routing Presets",
+      "subHappPresetsDesc": "Pre-configured routing rule presets tailored for Happ clients.",
+      "subHappVisualBuilder": "Visual Rule Generator",
+      "subHappVisualBuilderDesc": "Create custom routing deeplink from domain and IP lists.",
+      "subHappBuildDeeplink": "Generate Deeplink",
+      "subHappModalTitle": "Happ Visual Routing Rule Generator",
+      "subHappDirectDomains": "Direct Domains (Bypass)",
+      "subHappProxyDomains": "Proxy Domains (Tunnel)",
+      "subHappBlockDomains": "Blocked Domains (Ad/Malware)",
+      "subHappDirectIPs": "Direct IPs / CIDRs",
+      "subHappProxyIPs": "Proxy IPs / CIDRs",
+      "subHappBlockIPs": "Blocked IPs / CIDRs",
+      "subHappDeeplinkGenerated": "Deeplink generated and applied to routing rules",
+      "subHappGroupRouting": "Routing & Rules",
+      "subHappGroupBanners": "Banners & Announcements",
+      "subHappGroupNetwork": "Network & TUN Engine",
+      "subHappGroupThemes": "Appearance & Theme",
+      "subHappGroupFailover": "Migration & App Management",
+      "subHappGroupAndroid": "Android Per-App Proxy"
+
     },
     "xray": {
       "importRules": "Importar regras",

+ 93 - 1
internal/web/translation/ru-RU.json

@@ -1466,7 +1466,99 @@
       "subExpiredTemplate": "Шаблон истекшей подписки",
       "subExpiredTemplateDesc": "Шаблон для фиктивного узла, когда срок действия подписки истек.",
       "subTrafficDepletedTemplate": "Шаблон исчерпания трафика",
-      "subTrafficDepletedTemplateDesc": "Шаблон для фиктивного узла, когда лимит трафика исчерпан."
+      "subTrafficDepletedTemplateDesc": "Шаблон для фиктивного узла, когда лимит трафика исчерпан.",
+      "subHappAutoDetect": "Автоопределение заголовков Happ",
+      "subHappAutoDetectDesc": "Автоматически добавлять заголовки и маршрутизацию для клиентов с User-Agent Happ.",
+      "subHappProviderId": "Идентификатор провайдера (Provider ID)",
+      "subHappProviderIdDesc": "Уникальный идентификатор для управления приложением, удаленной конфигурации и миграции.",
+      "subHappNewUrl": "Новый URL подписки (Миграция)",
+      "subHappNewUrlDesc": "Новый адрес подписки. При получении клиент Happ автоматически переключится на данный URL.",
+      "subHappFallbackUrl": "Резервный URL подписки (Fallback)",
+      "subHappFallbackUrlDesc": "Резервный адрес подписки на случай недоступности основного сервера.",
+      "subHappSubInfoText": "Текст информационного баннера",
+      "subHappSubInfoTextDesc": "Пользовательский баннер в верхней части приложения Happ (до 200 символов).",
+      "subHappSubInfoColor": "Цвет баннера",
+      "subHappSubInfoColorDesc": "Цветовая тема информационного блока: blue (синий), green (зеленый), red (красный).",
+      "subHappSubInfoButtonText": "Текст кнопки баннера",
+      "subHappSubInfoButtonTextDesc": "Название кнопки действия в информационном блоке (до 25 символов).",
+      "subHappSubInfoButtonLink": "Ссылка кнопки баннера",
+      "subHappSubInfoButtonLinkDesc": "URL-адрес, открывающийся при нажатии на кнопку баннера.",
+      "subHappSubExpire": "Баннер об окончании подписки",
+      "subHappSubExpireDesc": "Отображать баннер о скором окончании или истечении срока действия подписки.",
+      "subHappSubExpireButtonLink": "Ссылка для продления подписки",
+      "subHappSubExpireButtonLinkDesc": "URL для кнопки «Продлить» при истечении срока подписки.",
+      "subHappNotificationExpire": "Уведомление об окончании подписки",
+      "subHappNotificationExpireDesc": "Отправлять напоминания пользователю за 3 дня до окончания подписки.",
+      "subHappNoLimit": "Режим без ограничений (No Limit)",
+      "subHappNoLimitDesc": "Увеличивает лимит оперативной памяти и снимает ограничения на количество правил.",
+      "subHappAlwaysHwid": "Обязательный HWID",
+      "subHappAlwaysHwidDesc": "Запрещает пользователю отключать передачу идентификатора устройства (HWID).",
+      "subHappTunMode": "Режим TUN",
+      "subHappTunModeDesc": "Сетевой стек для TUN: system (системный) или gvisor (пользовательский стек).",
+      "subHappTunType": "Ядро туنнеля (TUN Type)",
+      "subHappTunTypeDesc": "Выбор ядра туннеля: singbox, tun2proxy, default (Happ TUN) или xray.",
+      "subHappExcludeRoutes": "Исключения маршрутов (CIDR)",
+      "subHappExcludeRoutesDesc": "Список подсетей и IP-адресов через запятую, трафик которых идет мимо туннеля.",
+      "subHappExcludeApns": "Исключить push-уведомления Apple (APNS)",
+      "subHappExcludeApnsDesc": "Трафик уведомлений Apple направляется напрямую для надежной доставки на iOS.",
+      "subHappColorProfile": "Цветовая тема клиента",
+      "subHappColorProfileDesc": "Тема оформления интерфейса Happ: violet, turquoise, cyberpunk или свой JSON.",
+      "subHappPingType": "Метод проверки пинга",
+      "subHappPingTypeDesc": "Тип проверки задержки: via Proxy (GET), via Proxy (HEAD), TCP или ICMP.",
+      "subHappAutoConnect": "Автоподключение при запуске",
+      "subHappAutoConnectDesc": "Автоматически подключаться к серверу при запуске приложения.",
+      "subHappAutoConnectType": "Критерий автоподключения",
+      "subHappAutoConnectTypeDesc": "Сервер для автоподключения: lowestdelay (наименьший пинг), lastused (последний) или random.",
+      "subHappPerAppMode": "Прокси для приложений (Android)",
+      "subHappPerAppModeDesc": "Режим раздельного туннелирования: off (выкл), on (только выбранные) или bypass (все кроме выбранных).",
+      "subHappPerAppList": "Пакеты приложений Android",
+      "subHappPerAppListDesc": "Список идентификаторов пакетов через запятую (например, org.telegram.messenger).",
+      "subHappPresetIran": "Обход сайтов Ирана (Iran Bypass)",
+      "subHappPresetChina": "Обход сайтов Китая (China Direct)",
+      "subHappPresetAdblock": "Блокировка рекламы (AdBlock)",
+      "subHappPresetGlobal": "Полный прокси (Global)",
+      "subHappPresetOff": "Отключить маршрутизацию (happ://routing/off)",
+      "subHappColorBlue": "Синий (стандартный / по умолчанию)",
+      "subHappColorGreen": "Зеленый (успех)",
+      "subHappColorRed": "Красный (предупреждение / опасность)",
+      "subHappTunModeDefault": "По умолчанию",
+      "subHappTunModeSystem": "Системный (стандартный стек ОС)",
+      "subHappTunModeGvisor": "gVisor (пользовательский стек)",
+      "subHappTunTypeSingbox": "sing-box",
+      "subHappTunTypeTun2proxy": "tun2proxy",
+      "subHappTunTypeDefault": "По умолчанию (Happ TUN)",
+      "subHappTunTypeXray": "Xray TUN",
+      "subHappPingProxy": "Через прокси (задержка GET)",
+      "subHappPingProxyHead": "Через прокси (задержка HEAD)",
+      "subHappPingTcp": "TCP-рукопожатие (пинг)",
+      "subHappPingIcmp": "ICMP-пинг",
+      "subHappAutoConnectLowestDelay": "Минимальная задержка (быстрый узел)",
+      "subHappAutoConnectLastUsed": "Последний использованный узел",
+      "subHappAutoConnectRandom": "Случайный узел",
+      "subHappPerAppOff": "Выкл",
+      "subHappPerAppOn": "Вкл (только выбранные приложения)",
+      "subHappPerAppBypass": "Обход (исключить выбранные приложения)",
+      "subHappPresetApplied": "Пресет маршрутизации Happ успешно применен",
+      "subHappPresets": "Пресеты маршрутизации",
+      "subHappPresetsDesc": "Готовые конфигурации маршрутизации для клиентов Happ.",
+      "subHappVisualBuilder": "Визуальный конструктор правил",
+      "subHappVisualBuilderDesc": "Генератор диплинков маршрутизации на основе списков доменов и IP.",
+      "subHappBuildDeeplink": "Сгенерировать диплинк",
+      "subHappModalTitle": "Визуальный конструктор правил маршрутизации Happ",
+      "subHappDirectDomains": "Прямые домены (Direct)",
+      "subHappProxyDomains": "Проксируемые домены (Proxy)",
+      "subHappBlockDomains": "Заблокированные домены (Block)",
+      "subHappDirectIPs": "Прямые IP / CIDR",
+      "subHappProxyIPs": "Проксируемые IP / CIDR",
+      "subHappBlockIPs": "Заблокированные IP / CIDR",
+      "subHappDeeplinkGenerated": "Диплинк сгенерирован и применен к правилам маршрутизации",
+      "subHappGroupRouting": "Маршрутизация и правила",
+      "subHappGroupBanners": "Баннеры и уведомления",
+      "subHappGroupNetwork": "Сетевые настройки и TUN",
+      "subHappGroupThemes": "Внешний вид и темы",
+      "subHappGroupFailover": "Миграция и управление",
+      "subHappGroupAndroid": "Прокси приложений Android"
+
     },
     "xray": {
       "importRules": "Импорт правил",

+ 93 - 1
internal/web/translation/tr-TR.json

@@ -1466,7 +1466,99 @@
       "subExpiredTemplate": "Süresi Dolmuş Şablonu",
       "subExpiredTemplateDesc": "Abonelik süresi dolduğunda sahte yapılandırma için kullanılacak şablon.",
       "subTrafficDepletedTemplate": "Trafik Tükendi Şablonu",
-      "subTrafficDepletedTemplateDesc": "Abonelik trafik kotası bittiğinde sahte yapılandırma için kullanılacak şablon."
+      "subTrafficDepletedTemplateDesc": "Abonelik trafik kotası bittiğinde sahte yapılandırma için kullanılacak şablon.",
+      "subHappAutoDetect": "Happ Header Auto-Detection",
+      "subHappAutoDetectDesc": "Automatically inject Happ routing and headers when client User-Agent indicates Happ.",
+      "subHappProviderId": "Provider ID",
+      "subHappProviderIdDesc": "Unique provider identifier for Happ client management, remote configuration binding, and migration.",
+      "subHappNewUrl": "New Subscription URL",
+      "subHappNewUrlDesc": "Target URL for automatic client migration. When set, Happ clients will migrate to this subscription link.",
+      "subHappFallbackUrl": "Fallback Subscription URL",
+      "subHappFallbackUrlDesc": "Backup subscription address used by Happ if the primary subscription URL becomes unreachable.",
+      "subHappSubInfoText": "Banner Announcement Text",
+      "subHappSubInfoTextDesc": "Custom announcement banner displayed at the top of the Happ client (max 200 characters).",
+      "subHappSubInfoColor": "Banner Accent Color",
+      "subHappSubInfoColorDesc": "Color theme style for the announcement banner.",
+      "subHappSubInfoButtonText": "Banner Button Text",
+      "subHappSubInfoButtonTextDesc": "Button label displayed inside the announcement banner (max 25 characters).",
+      "subHappSubInfoButtonLink": "Banner Button Link",
+      "subHappSubInfoButtonLinkDesc": "Target URL opened when the user clicks the banner action button.",
+      "subHappSubExpire": "Expired Subscription Banner",
+      "subHappSubExpireDesc": "Show an expired subscription banner in Happ when the user's traffic or validity has ended.",
+      "subHappSubExpireButtonLink": "Renewal Link",
+      "subHappSubExpireButtonLinkDesc": "Target URL opened when the user clicks the renewal button on an expired subscription.",
+      "subHappNotificationExpire": "Expiration Notifications",
+      "subHappNotificationExpireDesc": "Instruct Happ to alert the user in advance before their subscription expires.",
+      "subHappNoLimit": "Bypass Rule Limit",
+      "subHappNoLimitDesc": "Allow routing rule count to exceed default mobile platform limits without truncation.",
+      "subHappAlwaysHwid": "Enforce Hardware ID (HWID)",
+      "subHappAlwaysHwidDesc": "Bind subscription sessions to client device hardware identifier for enhanced security.",
+      "subHappTunMode": "TUN Mode",
+      "subHappTunModeDesc": "TUN virtual network interface routing mode: default, system, or strict.",
+      "subHappTunType": "TUN Engine",
+      "subHappTunTypeDesc": "Underlying network stack implementation for TUN: system, gVisor, or mixed.",
+      "subHappExcludeRoutes": "Exclude CIDR Routes",
+      "subHappExcludeRoutesDesc": "Comma-separated IP CIDRs (e.g. 192.168.0.0/16, 10.0.0.0/8) to bypass the VPN tunnel.",
+      "subHappExcludeApns": "Exclude Apple APNs",
+      "subHappExcludeApnsDesc": "Bypass Apple Push Notification services to maintain reliable background notifications on iOS.",
+      "subHappColorProfile": "Client Color Theme",
+      "subHappColorProfileDesc": "Client color theme profile: default, violet, turquoise, cyberpunk, or custom JSON theme.",
+      "subHappPingType": "Latency Ping Method",
+      "subHappPingTypeDesc": "Measurement protocol used by Happ for node latency testing: icmp, tcp, or http.",
+      "subHappAutoConnect": "Auto-Connect on Launch",
+      "subHappAutoConnectDesc": "Instruct Happ to automatically connect to VPN when the application starts.",
+      "subHappAutoConnectType": "Auto-Connect Target",
+      "subHappAutoConnectTypeDesc": "Connection target strategy for auto-connect: fastest node or last used node.",
+      "subHappPerAppMode": "Android Per-App Proxy Mode",
+      "subHappPerAppModeDesc": "Control Android application routing: off, include (proxy only listed apps), or exclude (bypass listed apps).",
+      "subHappPerAppList": "Android Package Names",
+      "subHappPerAppListDesc": "Comma-separated package names of Android applications to include or exclude (e.g. com.telegram.messenger).",
+      "subHappPresetIran": "Iran Bypass",
+      "subHappPresetChina": "China Direct",
+      "subHappPresetAdblock": "AdBlock",
+      "subHappPresetGlobal": "Full Proxy",
+      "subHappPresetOff": "Yönlendirmeyi Devre Dışı Bırak (happ://routing/off)",
+      "subHappColorBlue": "Mavi (Standart / Varsayılan)",
+      "subHappColorGreen": "Yeşil (Başarılı)",
+      "subHappColorRed": "Kırmızı (Uyarı / Tehlike)",
+      "subHappTunModeDefault": "Varsayılan",
+      "subHappTunModeSystem": "Sistem (Standart İşletim Sistemi Yığını)",
+      "subHappTunModeGvisor": "gVisor (Kullanıcı Alanı Yığını)",
+      "subHappTunTypeSingbox": "sing-box",
+      "subHappTunTypeTun2proxy": "tun2proxy",
+      "subHappTunTypeDefault": "Varsayılan (Happ TUN)",
+      "subHappTunTypeXray": "Xray TUN",
+      "subHappPingProxy": "Proxy Üzerinden (GET Gecikmesi)",
+      "subHappPingProxyHead": "Proxy Üzerinden (HEAD Gecikmesi)",
+      "subHappPingTcp": "TCP El Sıkışma Pingi",
+      "subHappPingIcmp": "ICMP Ping",
+      "subHappAutoConnectLowestDelay": "En Düşük Gecikme (En Hızlı Düğüm)",
+      "subHappAutoConnectLastUsed": "Son Kullanılan Düğüm",
+      "subHappAutoConnectRandom": "Rastgele Düğüm",
+      "subHappPerAppOff": "Kapalı",
+      "subHappPerAppOn": "Açık (Yalnızca Listelenen Uygulamalar)",
+      "subHappPerAppBypass": "Atla (Listelenen Uygulamaları Hariç Tut)",
+      "subHappPresetApplied": "Happ preset applied to routing rules",
+      "subHappPresets": "Routing Presets",
+      "subHappPresetsDesc": "Pre-configured routing rule presets tailored for Happ clients.",
+      "subHappVisualBuilder": "Visual Rule Generator",
+      "subHappVisualBuilderDesc": "Create custom routing deeplink from domain and IP lists.",
+      "subHappBuildDeeplink": "Generate Deeplink",
+      "subHappModalTitle": "Happ Visual Routing Rule Generator",
+      "subHappDirectDomains": "Direct Domains (Bypass)",
+      "subHappProxyDomains": "Proxy Domains (Tunnel)",
+      "subHappBlockDomains": "Blocked Domains (Ad/Malware)",
+      "subHappDirectIPs": "Direct IPs / CIDRs",
+      "subHappProxyIPs": "Proxy IPs / CIDRs",
+      "subHappBlockIPs": "Blocked IPs / CIDRs",
+      "subHappDeeplinkGenerated": "Deeplink generated and applied to routing rules",
+      "subHappGroupRouting": "Routing & Rules",
+      "subHappGroupBanners": "Banners & Announcements",
+      "subHappGroupNetwork": "Network & TUN Engine",
+      "subHappGroupThemes": "Appearance & Theme",
+      "subHappGroupFailover": "Migration & App Management",
+      "subHappGroupAndroid": "Android Per-App Proxy"
+
     },
     "xray": {
       "save": "Kaydet",

+ 93 - 1
internal/web/translation/uk-UA.json

@@ -1466,7 +1466,99 @@
       "subExpiredTemplate": "Шаблон закінчення терміну",
       "subExpiredTemplateDesc": "Шаблон для фіктивного вузла, коли термін дії підписки закінчився.",
       "subTrafficDepletedTemplate": "Шаблон вичерпання трафіку",
-      "subTrafficDepletedTemplateDesc": "Шаблон для фіктивного вузла, коли ліміт трафіку вичерпано."
+      "subTrafficDepletedTemplateDesc": "Шаблон для фіктивного вузла, коли ліміт трафіку вичерпано.",
+      "subHappAutoDetect": "Happ Header Auto-Detection",
+      "subHappAutoDetectDesc": "Automatically inject Happ routing and headers when client User-Agent indicates Happ.",
+      "subHappProviderId": "Provider ID",
+      "subHappProviderIdDesc": "Unique provider identifier for Happ client management, remote configuration binding, and migration.",
+      "subHappNewUrl": "New Subscription URL",
+      "subHappNewUrlDesc": "Target URL for automatic client migration. When set, Happ clients will migrate to this subscription link.",
+      "subHappFallbackUrl": "Fallback Subscription URL",
+      "subHappFallbackUrlDesc": "Backup subscription address used by Happ if the primary subscription URL becomes unreachable.",
+      "subHappSubInfoText": "Banner Announcement Text",
+      "subHappSubInfoTextDesc": "Custom announcement banner displayed at the top of the Happ client (max 200 characters).",
+      "subHappSubInfoColor": "Banner Accent Color",
+      "subHappSubInfoColorDesc": "Color theme style for the announcement banner.",
+      "subHappSubInfoButtonText": "Banner Button Text",
+      "subHappSubInfoButtonTextDesc": "Button label displayed inside the announcement banner (max 25 characters).",
+      "subHappSubInfoButtonLink": "Banner Button Link",
+      "subHappSubInfoButtonLinkDesc": "Target URL opened when the user clicks the banner action button.",
+      "subHappSubExpire": "Expired Subscription Banner",
+      "subHappSubExpireDesc": "Show an expired subscription banner in Happ when the user's traffic or validity has ended.",
+      "subHappSubExpireButtonLink": "Renewal Link",
+      "subHappSubExpireButtonLinkDesc": "Target URL opened when the user clicks the renewal button on an expired subscription.",
+      "subHappNotificationExpire": "Expiration Notifications",
+      "subHappNotificationExpireDesc": "Instruct Happ to alert the user in advance before their subscription expires.",
+      "subHappNoLimit": "Bypass Rule Limit",
+      "subHappNoLimitDesc": "Allow routing rule count to exceed default mobile platform limits without truncation.",
+      "subHappAlwaysHwid": "Enforce Hardware ID (HWID)",
+      "subHappAlwaysHwidDesc": "Bind subscription sessions to client device hardware identifier for enhanced security.",
+      "subHappTunMode": "TUN Mode",
+      "subHappTunModeDesc": "TUN virtual network interface routing mode: default, system, or strict.",
+      "subHappTunType": "TUN Engine",
+      "subHappTunTypeDesc": "Underlying network stack implementation for TUN: system, gVisor, or mixed.",
+      "subHappExcludeRoutes": "Exclude CIDR Routes",
+      "subHappExcludeRoutesDesc": "Comma-separated IP CIDRs (e.g. 192.168.0.0/16, 10.0.0.0/8) to bypass the VPN tunnel.",
+      "subHappExcludeApns": "Exclude Apple APNs",
+      "subHappExcludeApnsDesc": "Bypass Apple Push Notification services to maintain reliable background notifications on iOS.",
+      "subHappColorProfile": "Client Color Theme",
+      "subHappColorProfileDesc": "Client color theme profile: default, violet, turquoise, cyberpunk, or custom JSON theme.",
+      "subHappPingType": "Latency Ping Method",
+      "subHappPingTypeDesc": "Measurement protocol used by Happ for node latency testing: icmp, tcp, or http.",
+      "subHappAutoConnect": "Auto-Connect on Launch",
+      "subHappAutoConnectDesc": "Instruct Happ to automatically connect to VPN when the application starts.",
+      "subHappAutoConnectType": "Auto-Connect Target",
+      "subHappAutoConnectTypeDesc": "Connection target strategy for auto-connect: fastest node or last used node.",
+      "subHappPerAppMode": "Android Per-App Proxy Mode",
+      "subHappPerAppModeDesc": "Control Android application routing: off, include (proxy only listed apps), or exclude (bypass listed apps).",
+      "subHappPerAppList": "Android Package Names",
+      "subHappPerAppListDesc": "Comma-separated package names of Android applications to include or exclude (e.g. com.telegram.messenger).",
+      "subHappPresetIran": "Iran Bypass",
+      "subHappPresetChina": "China Direct",
+      "subHappPresetAdblock": "AdBlock",
+      "subHappPresetGlobal": "Full Proxy",
+      "subHappPresetOff": "Вимкнути маршрутизацію (happ://routing/off)",
+      "subHappColorBlue": "Синій (стандартний / за замовчуванням)",
+      "subHappColorGreen": "Зелений (успіх)",
+      "subHappColorRed": "Червоний (попередження / небезпека)",
+      "subHappTunModeDefault": "За замовчуванням",
+      "subHappTunModeSystem": "Системний (стандартний стек ОС)",
+      "subHappTunModeGvisor": "gVisor (користувацький стек)",
+      "subHappTunTypeSingbox": "sing-box",
+      "subHappTunTypeTun2proxy": "tun2proxy",
+      "subHappTunTypeDefault": "За замовчуванням (Happ TUN)",
+      "subHappTunTypeXray": "Xray TUN",
+      "subHappPingProxy": "Через проксі (затримка GET)",
+      "subHappPingProxyHead": "Через проксі (затримка HEAD)",
+      "subHappPingTcp": "TCP-рукостискання (пінг)",
+      "subHappPingIcmp": "ICMP-пінг",
+      "subHappAutoConnectLowestDelay": "Найменша затримка (найшвидший вузол)",
+      "subHappAutoConnectLastUsed": "Останній використаний вузол",
+      "subHappAutoConnectRandom": "Випадковий вузол",
+      "subHappPerAppOff": "Вимк",
+      "subHappPerAppOn": "Увімк (тільки обрані програми)",
+      "subHappPerAppBypass": "Обхід (виключити обрані програми)",
+      "subHappPresetApplied": "Happ preset applied to routing rules",
+      "subHappPresets": "Routing Presets",
+      "subHappPresetsDesc": "Pre-configured routing rule presets tailored for Happ clients.",
+      "subHappVisualBuilder": "Visual Rule Generator",
+      "subHappVisualBuilderDesc": "Create custom routing deeplink from domain and IP lists.",
+      "subHappBuildDeeplink": "Generate Deeplink",
+      "subHappModalTitle": "Happ Visual Routing Rule Generator",
+      "subHappDirectDomains": "Direct Domains (Bypass)",
+      "subHappProxyDomains": "Proxy Domains (Tunnel)",
+      "subHappBlockDomains": "Blocked Domains (Ad/Malware)",
+      "subHappDirectIPs": "Direct IPs / CIDRs",
+      "subHappProxyIPs": "Proxy IPs / CIDRs",
+      "subHappBlockIPs": "Blocked IPs / CIDRs",
+      "subHappDeeplinkGenerated": "Deeplink generated and applied to routing rules",
+      "subHappGroupRouting": "Routing & Rules",
+      "subHappGroupBanners": "Banners & Announcements",
+      "subHappGroupNetwork": "Network & TUN Engine",
+      "subHappGroupThemes": "Appearance & Theme",
+      "subHappGroupFailover": "Migration & App Management",
+      "subHappGroupAndroid": "Android Per-App Proxy"
+
     },
     "xray": {
       "save": "Зберегти",

+ 93 - 1
internal/web/translation/vi-VN.json

@@ -1466,7 +1466,99 @@
       "subExpiredTemplate": "Mẫu hết hạn",
       "subExpiredTemplateDesc": "Mẫu cho cấu hình ảo khi tài khoản đăng ký đã hết hạn.",
       "subTrafficDepletedTemplate": "Mẫu hết dung lượng",
-      "subTrafficDepletedTemplateDesc": "Mẫu cho cấu hình ảo khi tài khoản đăng ký đã dùng hết dung lượng."
+      "subTrafficDepletedTemplateDesc": "Mẫu cho cấu hình ảo khi tài khoản đăng ký đã dùng hết dung lượng.",
+      "subHappAutoDetect": "Happ Header Auto-Detection",
+      "subHappAutoDetectDesc": "Automatically inject Happ routing and headers when client User-Agent indicates Happ.",
+      "subHappProviderId": "Provider ID",
+      "subHappProviderIdDesc": "Unique provider identifier for Happ client management, remote configuration binding, and migration.",
+      "subHappNewUrl": "New Subscription URL",
+      "subHappNewUrlDesc": "Target URL for automatic client migration. When set, Happ clients will migrate to this subscription link.",
+      "subHappFallbackUrl": "Fallback Subscription URL",
+      "subHappFallbackUrlDesc": "Backup subscription address used by Happ if the primary subscription URL becomes unreachable.",
+      "subHappSubInfoText": "Banner Announcement Text",
+      "subHappSubInfoTextDesc": "Custom announcement banner displayed at the top of the Happ client (max 200 characters).",
+      "subHappSubInfoColor": "Banner Accent Color",
+      "subHappSubInfoColorDesc": "Color theme style for the announcement banner.",
+      "subHappSubInfoButtonText": "Banner Button Text",
+      "subHappSubInfoButtonTextDesc": "Button label displayed inside the announcement banner (max 25 characters).",
+      "subHappSubInfoButtonLink": "Banner Button Link",
+      "subHappSubInfoButtonLinkDesc": "Target URL opened when the user clicks the banner action button.",
+      "subHappSubExpire": "Expired Subscription Banner",
+      "subHappSubExpireDesc": "Show an expired subscription banner in Happ when the user's traffic or validity has ended.",
+      "subHappSubExpireButtonLink": "Renewal Link",
+      "subHappSubExpireButtonLinkDesc": "Target URL opened when the user clicks the renewal button on an expired subscription.",
+      "subHappNotificationExpire": "Expiration Notifications",
+      "subHappNotificationExpireDesc": "Instruct Happ to alert the user in advance before their subscription expires.",
+      "subHappNoLimit": "Bypass Rule Limit",
+      "subHappNoLimitDesc": "Allow routing rule count to exceed default mobile platform limits without truncation.",
+      "subHappAlwaysHwid": "Enforce Hardware ID (HWID)",
+      "subHappAlwaysHwidDesc": "Bind subscription sessions to client device hardware identifier for enhanced security.",
+      "subHappTunMode": "TUN Mode",
+      "subHappTunModeDesc": "TUN virtual network interface routing mode: default, system, or strict.",
+      "subHappTunType": "TUN Engine",
+      "subHappTunTypeDesc": "Underlying network stack implementation for TUN: system, gVisor, or mixed.",
+      "subHappExcludeRoutes": "Exclude CIDR Routes",
+      "subHappExcludeRoutesDesc": "Comma-separated IP CIDRs (e.g. 192.168.0.0/16, 10.0.0.0/8) to bypass the VPN tunnel.",
+      "subHappExcludeApns": "Exclude Apple APNs",
+      "subHappExcludeApnsDesc": "Bypass Apple Push Notification services to maintain reliable background notifications on iOS.",
+      "subHappColorProfile": "Client Color Theme",
+      "subHappColorProfileDesc": "Client color theme profile: default, violet, turquoise, cyberpunk, or custom JSON theme.",
+      "subHappPingType": "Latency Ping Method",
+      "subHappPingTypeDesc": "Measurement protocol used by Happ for node latency testing: icmp, tcp, or http.",
+      "subHappAutoConnect": "Auto-Connect on Launch",
+      "subHappAutoConnectDesc": "Instruct Happ to automatically connect to VPN when the application starts.",
+      "subHappAutoConnectType": "Auto-Connect Target",
+      "subHappAutoConnectTypeDesc": "Connection target strategy for auto-connect: fastest node or last used node.",
+      "subHappPerAppMode": "Android Per-App Proxy Mode",
+      "subHappPerAppModeDesc": "Control Android application routing: off, include (proxy only listed apps), or exclude (bypass listed apps).",
+      "subHappPerAppList": "Android Package Names",
+      "subHappPerAppListDesc": "Comma-separated package names of Android applications to include or exclude (e.g. com.telegram.messenger).",
+      "subHappPresetIran": "Iran Bypass",
+      "subHappPresetChina": "China Direct",
+      "subHappPresetAdblock": "AdBlock",
+      "subHappPresetGlobal": "Full Proxy",
+      "subHappPresetOff": "Tắt định tuyến (happ://routing/off)",
+      "subHappColorBlue": "Xanh dương (Tiêu chuẩn / Mặc định)",
+      "subHappColorGreen": "Xanh lá (Thành công)",
+      "subHappColorRed": "Đỏ (Cảnh báo / Nguy hiểm)",
+      "subHappTunModeDefault": "Mặc định",
+      "subHappTunModeSystem": "Hệ thống (Ngăn xếp hệ điều hành tiêu chuẩn)",
+      "subHappTunModeGvisor": "gVisor (Ngăn xếp không gian người dùng)",
+      "subHappTunTypeSingbox": "sing-box",
+      "subHappTunTypeTun2proxy": "tun2proxy",
+      "subHappTunTypeDefault": "Mặc định (Happ TUN)",
+      "subHappTunTypeXray": "Xray TUN",
+      "subHappPingProxy": "Qua Proxy (Độ trễ GET)",
+      "subHappPingProxyHead": "Qua Proxy (Độ trễ HEAD)",
+      "subHappPingTcp": "Ping bắt tay TCP",
+      "subHappPingIcmp": "Ping ICMP",
+      "subHappAutoConnectLowestDelay": "Độ trễ thấp nhất (Nút nhanh nhất)",
+      "subHappAutoConnectLastUsed": "Nút sử dụng gần nhất",
+      "subHappAutoConnectRandom": "Nút ngẫu nhiên",
+      "subHappPerAppOff": "Tắt",
+      "subHappPerAppOn": "Bật (Chỉ proxy ứng dụng trong danh sách)",
+      "subHappPerAppBypass": "Bỏ qua (Loại trừ ứng dụng trong danh sách)",
+      "subHappPresetApplied": "Happ preset applied to routing rules",
+      "subHappPresets": "Routing Presets",
+      "subHappPresetsDesc": "Pre-configured routing rule presets tailored for Happ clients.",
+      "subHappVisualBuilder": "Visual Rule Generator",
+      "subHappVisualBuilderDesc": "Create custom routing deeplink from domain and IP lists.",
+      "subHappBuildDeeplink": "Generate Deeplink",
+      "subHappModalTitle": "Happ Visual Routing Rule Generator",
+      "subHappDirectDomains": "Direct Domains (Bypass)",
+      "subHappProxyDomains": "Proxy Domains (Tunnel)",
+      "subHappBlockDomains": "Blocked Domains (Ad/Malware)",
+      "subHappDirectIPs": "Direct IPs / CIDRs",
+      "subHappProxyIPs": "Proxy IPs / CIDRs",
+      "subHappBlockIPs": "Blocked IPs / CIDRs",
+      "subHappDeeplinkGenerated": "Deeplink generated and applied to routing rules",
+      "subHappGroupRouting": "Routing & Rules",
+      "subHappGroupBanners": "Banners & Announcements",
+      "subHappGroupNetwork": "Network & TUN Engine",
+      "subHappGroupThemes": "Appearance & Theme",
+      "subHappGroupFailover": "Migration & App Management",
+      "subHappGroupAndroid": "Android Per-App Proxy"
+
     },
     "xray": {
       "importRules": "Nhập quy tắc",

+ 93 - 1
internal/web/translation/zh-CN.json

@@ -1466,7 +1466,99 @@
       "subExpiredTemplate": "过期提示模板",
       "subExpiredTemplateDesc": "用户订阅过期时提示配置的备注模板。",
       "subTrafficDepletedTemplate": "流量耗尽模板",
-      "subTrafficDepletedTemplateDesc": "用户订阅流量用尽时提示配置的备注模板。"
+      "subTrafficDepletedTemplateDesc": "用户订阅流量用尽时提示配置的备注模板。",
+      "subHappAutoDetect": "Happ 客户端请求头自动识别",
+      "subHappAutoDetectDesc": "当客户端 User-Agent 包含 Happ 时自动注入专属路由规则与响应头。",
+      "subHappProviderId": "服务提供商标识 (Provider ID)",
+      "subHappProviderIdDesc": "Happ 客户端管理、远程配置绑定与订阅迁移所需的唯一标识符。",
+      "subHappNewUrl": "新订阅地址 (迁移)",
+      "subHappNewUrlDesc": "自动迁移的新订阅 URL。客户端收到后会自动将订阅地址切换为此链接。",
+      "subHappFallbackUrl": "备用订阅地址 (Fallback)",
+      "subHappFallbackUrlDesc": "主订阅服务器不可用时 Happ 自动切换的备份订阅链接。",
+      "subHappSubInfoText": "横幅公告文本",
+      "subHappSubInfoTextDesc": "显示在 Happ 客户端顶部的自定义通知横幅(最多 200 字符)。",
+      "subHappSubInfoColor": "横幅配色主题",
+      "subHappSubInfoColorDesc": "横幅主题颜色:blue (默认蓝色)、green (绿色)、red (红色警告)。",
+      "subHappSubInfoButtonText": "横幅按钮文字",
+      "subHappSubInfoButtonTextDesc": "通知横幅内的操作按钮标题(最多 25 字符)。",
+      "subHappSubInfoButtonLink": "横幅按钮链接",
+      "subHappSubInfoButtonLinkDesc": "点击横幅按钮时打开的目标网址或 DeepLink。",
+      "subHappSubExpire": "订阅到期提醒横幅",
+      "subHappSubExpireDesc": "当用户订阅即将到期或已过期时在 Happ 中显示续费提示横幅。",
+      "subHappSubExpireButtonLink": "续费链接",
+      "subHappSubExpireButtonLinkDesc": "到期横幅中点击「续费」按钮时跳转的支付或购买页面。",
+      "subHappNotificationExpire": "订阅到期推送提醒",
+      "subHappNotificationExpireDesc": "在订阅到期前 3 天向用户发送每日一次的客户端到期提醒。",
+      "subHappNoLimit": "解除规则数量限制 (No Limit)",
+      "subHappNoLimitDesc": "提升内核内存上限,允许应用超出移动端默认数量的复杂路由规则。",
+      "subHappAlwaysHwid": "强制绑定硬件标识 (HWID)",
+      "subHappAlwaysHwidDesc": "禁止客户端关闭硬件标识符上报,强化多设备防盗刷安全。",
+      "subHappTunMode": "TUN 运行模式",
+      "subHappTunModeDesc": "TUN 网络接口栈:system (系统网络栈) 或 gvisor (用户态协议栈)。",
+      "subHappTunType": "TUN 隧道内核 (TUN Type)",
+      "subHappTunTypeDesc": "隧道实现引擎:singbox、tun2proxy、default (Happ 原生) 或 xray。",
+      "subHappExcludeRoutes": "排除直连网段 (CIDR)",
+      "subHappExcludeRoutesDesc": "逗号分隔的 IP/CIDR 地址段,此网段流量不走 VPN 隧道直连。",
+      "subHappExcludeApns": "排除苹果推送服务 (APNs)",
+      "subHappExcludeApnsDesc": "让 Apple APNs 流量直连,保障 iOS 设备在后台稳定接收推送通知。",
+      "subHappColorProfile": "客户端外观主题",
+      "subHappColorProfileDesc": "Happ 界面配色主题:violet、turquoise、cyberpunk 或自定义 JSON 调色板。",
+      "subHappPingType": "延迟测速协议",
+      "subHappPingTypeDesc": "节点测速协议:via Proxy (GET)、via Proxy (HEAD)、TCP 握手或 ICMP。",
+      "subHappAutoConnect": "启动时自动连接",
+      "subHappAutoConnectDesc": "Happ 客户端打开时自动连接代理节点。",
+      "subHappAutoConnectType": "自动连接策略",
+      "subHappAutoConnectTypeDesc": "连接目标选择:lowestdelay (最低延迟)、lastused (上次使用) 或 random。",
+      "subHappPerAppMode": "Android 分应用代理",
+      "subHappPerAppModeDesc": "分应用代理模式:off (关闭)、on (仅代理选定应用) 或 bypass (绕过选定应用)。",
+      "subHappPerAppList": "Android 应用包名列表",
+      "subHappPerAppListDesc": "以逗号分隔的应用包名(例如 org.telegram.messenger, com.google.android.youtube)。",
+      "subHappPresetIran": "伊朗直连规则 (Iran Bypass)",
+      "subHappPresetChina": "大陆直连规则 (China Direct)",
+      "subHappPresetAdblock": "广告拦截规则 (AdBlock)",
+      "subHappPresetGlobal": "全局代理规则 (Global)",
+      "subHappPresetOff": "禁用路由 (happ://routing/off)",
+      "subHappColorBlue": "蓝色 (标准 / 默认)",
+      "subHappColorGreen": "绿色 (成功)",
+      "subHappColorRed": "红色 (警告 / 危险)",
+      "subHappTunModeDefault": "默认",
+      "subHappTunModeSystem": "系统 (标准操作系统协议栈)",
+      "subHappTunModeGvisor": "gVisor (用户空间协议栈)",
+      "subHappTunTypeSingbox": "sing-box",
+      "subHappTunTypeTun2proxy": "tun2proxy",
+      "subHappTunTypeDefault": "默认 (Happ TUN)",
+      "subHappTunTypeXray": "Xray TUN",
+      "subHappPingProxy": "经由代理 (GET 延迟)",
+      "subHappPingProxyHead": "经由代理 (HEAD 延迟)",
+      "subHappPingTcp": "TCP 握手 Ping",
+      "subHappPingIcmp": "ICMP Ping",
+      "subHappAutoConnectLowestDelay": "最低延迟 (最快节点)",
+      "subHappAutoConnectLastUsed": "最后使用的节点",
+      "subHappAutoConnectRandom": "随机节点",
+      "subHappPerAppOff": "关闭",
+      "subHappPerAppOn": "开启 (仅代理列表中的应用)",
+      "subHappPerAppBypass": "绕过 (排除列表中的应用)",
+      "subHappPresetApplied": "Happ 预设规则已应用",
+      "subHappPresets": "预设路由规则",
+      "subHappPresetsDesc": "专为 Happ 客户端预设调优的常用分流规则。",
+      "subHappVisualBuilder": "可视化规则生成器",
+      "subHappVisualBuilderDesc": "通过域名与 IP 列表快速生成自定义 Happ 路由 DeepLink。",
+      "subHappBuildDeeplink": "生成 DeepLink",
+      "subHappModalTitle": "Happ 路由规则可视化生成器",
+      "subHappDirectDomains": "直连域名 (Direct)",
+      "subHappProxyDomains": "代理域名 (Proxy)",
+      "subHappBlockDomains": "阻止域名 (Block)",
+      "subHappDirectIPs": "直连 IP / CIDR",
+      "subHappProxyIPs": "代理 IP / CIDR",
+      "subHappBlockIPs": "阻止 IP / CIDR",
+      "subHappDeeplinkGenerated": "DeepLink 已生成并填入路由规则",
+      "subHappGroupRouting": "路由分流与规则",
+      "subHappGroupBanners": "横幅公告与通知",
+      "subHappGroupNetwork": "网络与 TUN 引擎",
+      "subHappGroupThemes": "界面与主题外观",
+      "subHappGroupFailover": "迁移与客户端管理",
+      "subHappGroupAndroid": "Android 分应用代理"
+
     },
     "xray": {
       "importRules": "导入规则",

+ 93 - 1
internal/web/translation/zh-TW.json

@@ -1466,7 +1466,99 @@
       "subExpiredTemplate": "過期提示範本",
       "subExpiredTemplateDesc": "使用者訂閱過期時提示配置的備註範本。",
       "subTrafficDepletedTemplate": "流量耗盡範本",
-      "subTrafficDepletedTemplateDesc": "使用者訂閱流量用盡時提示配置的備註範本。"
+      "subTrafficDepletedTemplateDesc": "使用者訂閱流量用盡時提示配置的備註範本。",
+      "subHappAutoDetect": "Happ 客户端请求头自动识别",
+      "subHappAutoDetectDesc": "当客户端 User-Agent 包含 Happ 时自动注入专属路由规则与响应头。",
+      "subHappProviderId": "服务提供商标识 (Provider ID)",
+      "subHappProviderIdDesc": "Happ 客户端管理、远程配置绑定与订阅迁移所需的唯一标识符。",
+      "subHappNewUrl": "新订阅地址 (迁移)",
+      "subHappNewUrlDesc": "自动迁移的新订阅 URL。客户端收到后会自动将订阅地址切换为此链接。",
+      "subHappFallbackUrl": "备用订阅地址 (Fallback)",
+      "subHappFallbackUrlDesc": "主订阅服务器不可用时 Happ 自动切换的备份订阅链接。",
+      "subHappSubInfoText": "横幅公告文本",
+      "subHappSubInfoTextDesc": "显示在 Happ 客户端顶部的自定义通知横幅(最多 200 字符)。",
+      "subHappSubInfoColor": "横幅配色主题",
+      "subHappSubInfoColorDesc": "横幅主题颜色:blue (默认蓝色)、green (绿色)、red (红色警告)。",
+      "subHappSubInfoButtonText": "横幅按钮文字",
+      "subHappSubInfoButtonTextDesc": "通知横幅内的操作按钮标题(最多 25 字符)。",
+      "subHappSubInfoButtonLink": "横幅按钮链接",
+      "subHappSubInfoButtonLinkDesc": "点击横幅按钮时打开的目标网址或 DeepLink。",
+      "subHappSubExpire": "订阅到期提醒横幅",
+      "subHappSubExpireDesc": "当用户订阅即将到期或已过期时在 Happ 中显示续费提示横幅。",
+      "subHappSubExpireButtonLink": "续费链接",
+      "subHappSubExpireButtonLinkDesc": "到期横幅中点击「续费」按钮时跳转的支付或购买页面。",
+      "subHappNotificationExpire": "订阅到期推送提醒",
+      "subHappNotificationExpireDesc": "在订阅到期前 3 天向用户发送每日一次的客户端到期提醒。",
+      "subHappNoLimit": "解除规则数量限制 (No Limit)",
+      "subHappNoLimitDesc": "提升内核内存上限,允许应用超出移动端默认数量的复杂路由规则。",
+      "subHappAlwaysHwid": "强制绑定硬件标识 (HWID)",
+      "subHappAlwaysHwidDesc": "禁止客户端关闭硬件标识符上报,强化多设备防盗刷安全。",
+      "subHappTunMode": "TUN 运行模式",
+      "subHappTunModeDesc": "TUN 网络接口栈:system (系统网络栈) 或 gvisor (用户态协议栈)。",
+      "subHappTunType": "TUN 隧道内核 (TUN Type)",
+      "subHappTunTypeDesc": "隧道实现引擎:singbox、tun2proxy、default (Happ 原生) 或 xray。",
+      "subHappExcludeRoutes": "排除直连网段 (CIDR)",
+      "subHappExcludeRoutesDesc": "逗号分隔的 IP/CIDR 地址段,此网段流量不走 VPN 隧道直连。",
+      "subHappExcludeApns": "排除苹果推送服务 (APNs)",
+      "subHappExcludeApnsDesc": "让 Apple APNs 流量直连,保障 iOS 设备在后台稳定接收推送通知。",
+      "subHappColorProfile": "客户端外观主题",
+      "subHappColorProfileDesc": "Happ 界面配色主题:violet、turquoise、cyberpunk 或自定义 JSON 调色板。",
+      "subHappPingType": "延迟测速协议",
+      "subHappPingTypeDesc": "节点测速协议:via Proxy (GET)、via Proxy (HEAD)、TCP 握手或 ICMP。",
+      "subHappAutoConnect": "启动时自动连接",
+      "subHappAutoConnectDesc": "Happ 客户端打开时自动连接代理节点。",
+      "subHappAutoConnectType": "自动连接策略",
+      "subHappAutoConnectTypeDesc": "连接目标选择:lowestdelay (最低延迟)、lastused (上次使用) 或 random。",
+      "subHappPerAppMode": "Android 分应用代理",
+      "subHappPerAppModeDesc": "分应用代理模式:off (关闭)、on (仅代理选定应用) 或 bypass (绕过选定应用)。",
+      "subHappPerAppList": "Android 应用包名列表",
+      "subHappPerAppListDesc": "以逗号分隔的应用包名(例如 org.telegram.messenger, com.google.android.youtube)。",
+      "subHappPresetIran": "伊朗直连规则 (Iran Bypass)",
+      "subHappPresetChina": "大陆直连规则 (China Direct)",
+      "subHappPresetAdblock": "广告拦截规则 (AdBlock)",
+      "subHappPresetGlobal": "全局代理规则 (Global)",
+      "subHappPresetOff": "停用路由 (happ://routing/off)",
+      "subHappColorBlue": "藍色 (標準 / 預設)",
+      "subHappColorGreen": "綠色 (成功)",
+      "subHappColorRed": "紅色 (警告 / 危險)",
+      "subHappTunModeDefault": "預設",
+      "subHappTunModeSystem": "系統 (標準作業系統協議棧)",
+      "subHappTunModeGvisor": "gVisor (使用者空間協議棧)",
+      "subHappTunTypeSingbox": "sing-box",
+      "subHappTunTypeTun2proxy": "tun2proxy",
+      "subHappTunTypeDefault": "預設 (Happ TUN)",
+      "subHappTunTypeXray": "Xray TUN",
+      "subHappPingProxy": "經由代理 (GET 延遲)",
+      "subHappPingProxyHead": "經由代理 (HEAD 延遲)",
+      "subHappPingTcp": "TCP 握手 Ping",
+      "subHappPingIcmp": "ICMP Ping",
+      "subHappAutoConnectLowestDelay": "最低延遲 (最快節點)",
+      "subHappAutoConnectLastUsed": "最後使用的節點",
+      "subHappAutoConnectRandom": "隨機節點",
+      "subHappPerAppOff": "關閉",
+      "subHappPerAppOn": "開啟 (僅代理列表中的應用)",
+      "subHappPerAppBypass": "繞過 (排除列表中的應用)",
+      "subHappPresetApplied": "Happ 预设规则已应用",
+      "subHappPresets": "预设路由规则",
+      "subHappPresetsDesc": "专为 Happ 客户端预设调优的常用分流规则。",
+      "subHappVisualBuilder": "可视化规则生成器",
+      "subHappVisualBuilderDesc": "通过域名与 IP 列表快速生成自定义 Happ 路由 DeepLink。",
+      "subHappBuildDeeplink": "生成 DeepLink",
+      "subHappModalTitle": "Happ 路由规则可视化生成器",
+      "subHappDirectDomains": "直连域名 (Direct)",
+      "subHappProxyDomains": "代理域名 (Proxy)",
+      "subHappBlockDomains": "阻止域名 (Block)",
+      "subHappDirectIPs": "直连 IP / CIDR",
+      "subHappProxyIPs": "代理 IP / CIDR",
+      "subHappBlockIPs": "阻止 IP / CIDR",
+      "subHappDeeplinkGenerated": "DeepLink 已生成并填入路由规则",
+      "subHappGroupRouting": "路由分流与规则",
+      "subHappGroupBanners": "横幅公告与通知",
+      "subHappGroupNetwork": "网络与 TUN 引擎",
+      "subHappGroupThemes": "界面与主题外观",
+      "subHappGroupFailover": "迁移与客户端管理",
+      "subHappGroupAndroid": "Android 分应用代理"
+
     },
     "xray": {
       "save": "儲存",