feat: more subscription information fields (#3701)
Some checks failed
Release 3X-UI / build (386) (push) Has been cancelled
Release 3X-UI / build (amd64) (push) Has been cancelled
Release 3X-UI / build (arm64) (push) Has been cancelled
Release 3X-UI / build (armv5) (push) Has been cancelled
Release 3X-UI / build (armv6) (push) Has been cancelled
Release 3X-UI / build (armv7) (push) Has been cancelled
Release 3X-UI / build (s390x) (push) Has been cancelled
Release 3X-UI / Build for Windows (push) Has been cancelled

* feat: more subscription information fields

* fix: incorrect translation

* feat: implement field for Happ custom routing rules
This commit is contained in:
Danil S. 2026-01-27 05:06:01 +07:00 committed by GitHub
parent 8a4c9a98cb
commit fd5f591737
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 285 additions and 27 deletions

View file

@ -153,6 +153,31 @@ func (s *Server) initRouter() (*gin.Engine, error) {
SubTitle = ""
}
SubSupportUrl, err := s.settingService.GetSubSupportUrl()
if err != nil {
SubSupportUrl = ""
}
SubProfileUrl, err := s.settingService.GetSubProfileUrl()
if err != nil {
SubProfileUrl = ""
}
SubAnnounce, err := s.settingService.GetSubAnnounce()
if err != nil {
SubAnnounce = ""
}
SubEnableRouting, err := s.settingService.GetSubEnableRouting()
if err != nil {
return nil, err
}
SubRoutingRules, err := s.settingService.GetSubRoutingRules()
if err != nil {
SubRoutingRules = ""
}
// set per-request localizer from headers/cookies
engine.Use(locale.LocalizerMiddleware())
@ -231,7 +256,8 @@ func (s *Server) initRouter() (*gin.Engine, error) {
s.sub = NewSUBController(
g, LinksPath, JsonPath, subJsonEnable, Encrypt, ShowInfo, RemarkModel, SubUpdates,
SubJsonFragment, SubJsonNoises, SubJsonMux, SubJsonRules, SubTitle)
SubJsonFragment, SubJsonNoises, SubJsonMux, SubJsonRules, SubTitle, SubSupportUrl,
SubProfileUrl, SubAnnounce, SubEnableRouting, SubRoutingRules)
return engine, nil
}

View file

@ -4,6 +4,7 @@ import (
"encoding/base64"
"fmt"
"strings"
"strconv"
"github.com/mhsanaei/3x-ui/v2/config"
@ -12,12 +13,17 @@ import (
// SUBController handles HTTP requests for subscription links and JSON configurations.
type SUBController struct {
subTitle string
subPath string
subJsonPath string
jsonEnabled bool
subEncrypt bool
updateInterval string
subTitle string
subSupportUrl string
subProfileUrl string
subAnnounce string
subEnableRouting bool
subRoutingRules string
subPath string
subJsonPath string
jsonEnabled bool
subEncrypt bool
updateInterval string
subService *SubService
subJsonService *SubJsonService
@ -38,18 +44,28 @@ func NewSUBController(
jsonMux string,
jsonRules string,
subTitle string,
subSupportUrl string,
subProfileUrl string,
subAnnounce string,
subEnableRouting bool,
subRoutingRules string,
) *SUBController {
sub := NewSubService(showInfo, rModel)
a := &SUBController{
subTitle: subTitle,
subPath: subPath,
subJsonPath: jsonPath,
jsonEnabled: jsonEnabled,
subEncrypt: encrypt,
updateInterval: update,
subTitle: subTitle,
subSupportUrl: subSupportUrl,
subProfileUrl: subProfileUrl,
subAnnounce: subAnnounce,
subEnableRouting: subEnableRouting,
subRoutingRules: subRoutingRules,
subPath: subPath,
subJsonPath: jsonPath,
jsonEnabled: jsonEnabled,
subEncrypt: encrypt,
updateInterval: update,
subService: sub,
subJsonService: NewSubJsonService(jsonFragment, jsonNoise, jsonMux, jsonRules, sub),
subService: sub,
subJsonService: NewSubJsonService(jsonFragment, jsonNoise, jsonMux, jsonRules, sub),
}
a.initRouter(g)
return a
@ -127,7 +143,7 @@ func (a *SUBController) subs(c *gin.Context) {
// Add headers
header := fmt.Sprintf("upload=%d; download=%d; total=%d; expire=%d", traffic.Up, traffic.Down, traffic.Total, traffic.ExpiryTime/1000)
a.ApplyCommonHeaders(c, header, a.updateInterval, a.subTitle)
a.ApplyCommonHeaders(c, header, a.updateInterval, a.subTitle, a.subSupportUrl, a.subProfileUrl, a.subAnnounce, a.subEnableRouting, a.subRoutingRules)
if a.subEncrypt {
c.String(200, base64.StdEncoding.EncodeToString([]byte(result)))
@ -145,17 +161,31 @@ func (a *SUBController) subJsons(c *gin.Context) {
if err != nil || len(jsonSub) == 0 {
c.String(400, "Error!")
} else {
// Add headers
a.ApplyCommonHeaders(c, header, a.updateInterval, a.subTitle)
a.ApplyCommonHeaders(c, header, a.updateInterval, a.subTitle, a.subSupportUrl, a.subProfileUrl, a.subAnnounce, a.subEnableRouting, a.subRoutingRules)
c.String(200, jsonSub)
}
}
// ApplyCommonHeaders sets common HTTP headers for subscription responses including user info, update interval, and profile title.
func (a *SUBController) ApplyCommonHeaders(c *gin.Context, header, updateInterval, profileTitle string) {
func (a *SUBController) ApplyCommonHeaders(
c *gin.Context,
header,
updateInterval,
profileTitle string,
profileSupportUrl string,
profileUrl string,
profileAnnounce string,
profileEnableRouting bool,
profileRoutingRules string,
) {
c.Writer.Header().Set("Subscription-Userinfo", header)
c.Writer.Header().Set("Profile-Update-Interval", updateInterval)
c.Writer.Header().Set("Profile-Title", "base64:"+base64.StdEncoding.EncodeToString([]byte(profileTitle)))
c.Writer.Header().Set("Support-Url", profileSupportUrl)
c.Writer.Header().Set("Profile-Web-Page-Url", profileUrl)
c.Writer.Header().Set("Announce", "base64:"+base64.StdEncoding.EncodeToString([]byte(profileAnnounce)))
c.Writer.Header().Set("Routing-Enable", strconv.FormatBool(profileEnableRouting))
c.Writer.Header().Set("Routing", profileRoutingRules)
}

View file

@ -29,6 +29,11 @@ class AllSetting {
this.subEnable = true;
this.subJsonEnable = false;
this.subTitle = "";
this.subSupportUrl = "";
this.subProfileUrl = "";
this.subAnnounce = "";
this.subEnableRouting = true;
this.subRoutingRules = "";
this.subListen = "";
this.subPort = 2096;
this.subPath = "/sub/";

View file

@ -57,6 +57,11 @@ type AllSetting struct {
SubEnable bool `json:"subEnable" form:"subEnable"` // Enable subscription server
SubJsonEnable bool `json:"subJsonEnable" form:"subJsonEnable"` // Enable JSON subscription endpoint
SubTitle string `json:"subTitle" form:"subTitle"` // Subscription title
SubSupportUrl string `json:"subSupportUrl" form:"subSupportUrl"` // Subscription support URL
SubProfileUrl string `json:"subProfileUrl" form:"subProfileUrl"` // Subscription profile URL
SubAnnounce string `json:"subAnnounce" form:"subAnnounce"` // Subscription announce
SubEnableRouting bool `json:"subEnableRouting" form:"subEnableRouting"` // Enable routing for subscription
SubRoutingRules string `json:"subRoutingRules" form:"subRoutingRules"` // Subscription global routing rules (Only for Happ)
SubListen string `json:"subListen" form:"subListen"` // Subscription server listen IP
SubPort int `json:"subPort" form:"subPort"` // Subscription server port
SubPath string `json:"subPath" form:"subPath"` // Base path for subscription URLs

View file

@ -15,13 +15,6 @@
<a-switch v-model="allSetting.subJsonEnable"></a-switch>
</template>
</a-setting-list-item>
<a-setting-list-item paddings="small">
<template #title>{{ i18n "pages.settings.subTitle"}}</template>
<template #description>{{ i18n "pages.settings.subTitleDesc"}}</template>
<template #control>
<a-input type="text" v-model="allSetting.subTitle"></a-input>
</template>
</a-setting-list-item>
<a-setting-list-item paddings="small">
<template #title>{{ i18n "pages.settings.subListen"}}</template>
<template #description>{{ i18n "pages.settings.subListenDesc"}}</template>
@ -78,6 +71,50 @@
<a-switch v-model="allSetting.subShowInfo"></a-switch>
</template>
</a-setting-list-item>
<a-divider>{{ i18n "pages.xray.basicTemplate"}}</a-divider>
<a-setting-list-item paddings="small">
<template #title>{{ i18n "pages.settings.subTitle"}}</template>
<template #description>{{ i18n "pages.settings.subTitleDesc"}}</template>
<template #control>
<a-input type="text" v-model="allSetting.subTitle"></a-input>
</template>
</a-setting-list-item>
<a-setting-list-item paddings="small">
<template #title>{{ i18n "pages.settings.subSupportUrl"}}</template>
<template #description>{{ i18n "pages.settings.subSupportUrlDesc"}}</template>
<template #control>
<a-input type="text" v-model="allSetting.subSupportUrl" placeholder="https://example.com"></a-input>
</template>
</a-setting-list-item>
<a-setting-list-item paddings="small">
<template #title>{{ i18n "pages.settings.subProfileUrl"}}</template>
<template #description>{{ i18n "pages.settings.subProfileUrlDesc"}}</template>
<template #control>
<a-input type="text" v-model="allSetting.subProfileUrl" placeholder="https://example.com"></a-input>
</template>
</a-setting-list-item>
<a-setting-list-item paddings="small">
<template #title>{{ i18n "pages.settings.subAnnounce"}}</template>
<template #description>{{ i18n "pages.settings.subAnnounceDesc"}}</template>
<template #control>
<a-textarea v-model="allSetting.subAnnounce"></a-textarea>
</template>
</a-setting-list-item>
<a-divider>{{ i18n "pages.xray.advancedTemplate"}} (Happ)</a-divider>
<a-setting-list-item paddings="small">
<template #title>{{ i18n "pages.settings.subEnableRouting"}}</template>
<template #description>{{ i18n "pages.settings.subEnableRoutingDesc"}}</template>
<template #control>
<a-switch v-model="allSetting.subEnableRouting"></a-switch>
</template>
</a-setting-list-item>
<a-setting-list-item paddings="small">
<template #title>{{ i18n "pages.settings.subRoutingRules"}}</template>
<template #description>{{ i18n "pages.settings.subRoutingRulesDesc"}}</template>
<template #control>
<a-textarea v-model="allSetting.subRoutingRules" placeholder="happ://routing/add/..."></a-textarea>
</template>
</a-setting-list-item>
</a-collapse-panel>
<a-collapse-panel key="3" header='{{ i18n "pages.settings.certs" }}'>
<a-setting-list-item paddings="small">

View file

@ -53,6 +53,11 @@ var defaultValueMap = map[string]string{
"subEnable": "true",
"subJsonEnable": "false",
"subTitle": "",
"subSupportUrl": "",
"subProfileUrl": "",
"subAnnounce": "",
"subEnableRouting": "true",
"subRoutingRules": "",
"subListen": "",
"subPort": "2096",
"subPath": "/sub/",
@ -459,6 +464,26 @@ func (s *SettingService) GetSubTitle() (string, error) {
return s.getString("subTitle")
}
func (s *SettingService) GetSubSupportUrl() (string, error) {
return s.getString("subSupportUrl")
}
func (s *SettingService) GetSubProfileUrl() (string, error) {
return s.getString("subProfileUrl")
}
func (s *SettingService) GetSubAnnounce() (string, error) {
return s.getString("subAnnounce")
}
func (s *SettingService) GetSubEnableRouting() (bool, error) {
return s.getBool("subEnableRouting")
}
func (s *SettingService) GetSubRoutingRules() (string, error) {
return s.getString("subRoutingRules")
}
func (s *SettingService) GetSubListen() (string, error) {
return s.getString("subListen")
}

View file

@ -374,6 +374,16 @@
"subJsonEnable" = "تمكين/تعطيل نقطة نهاية اشتراك JSON بشكل مستقل."
"subTitle" = "عنوان الاشتراك"
"subTitleDesc" = "العنوان اللي هيظهر في عميل VPN"
"subSupportUrl" = "رابط الدعم"
"subSupportUrlDesc" = "رابط الدعم الفني المعروض في عميل VPN"
"subProfileUrl" = "رابط الملف الشخصي"
"subProfileUrlDesc" = "رابط لموقعك الإلكتروني يظهر في عميل VPN"
"subAnnounce" = "إعلان"
"subAnnounceDesc" = "نص الإعلان المعروض في عميل VPN"
"subEnableRouting" = "تفعيل التوجيه"
"subEnableRoutingDesc" = "إعداد عام لتمكين التوجيه (Routing) في عميل VPN. (فقط لـ Happ)"
"subRoutingRules" = "قواعد التوجيه"
"subRoutingRulesDesc" = "قواعد التوجيه العامة لعميل VPN. (فقط لـ Happ)"
"subListen" = "IP الاستماع"
"subListenDesc" = "عنوان IP لخدمة الاشتراك. (سيبه فاضي عشان يستمع على كل الـ IPs)"
"subPort" = "بورت الاستماع"

View file

@ -374,6 +374,16 @@
"subJsonEnable" = "Enable/Disable the JSON subscription endpoint independently."
"subTitle" = "Subscription Title"
"subTitleDesc" = "Title shown in VPN client"
"subSupportUrl" = "Support URL"
"subSupportUrlDesc" = "Technical support link shown in the VPN client"
"subProfileUrl" = "Profile URL"
"subProfileUrlDesc" = "A link to your website displayed in the VPN client"
"subAnnounce" = "Announce"
"subAnnounceDesc" = "The text of the announce displayed in the VPN client"
"subEnableRouting" = "Enable routing"
"subEnableRoutingDesc" = "Global setting to enable routing in the VPN client. (Only for Happ)"
"subRoutingRules" = "Routing rules"
"subRoutingRulesDesc" = "Global routing rules for the VPN client. (Only for Happ)"
"subListen" = "Listen IP"
"subListenDesc" = "The IP address for the subscription service. (leave blank to listen on all IPs)"
"subPort" = "Listen Port"

View file

@ -374,6 +374,16 @@
"subJsonEnable" = "Habilitar/Deshabilitar el endpoint de suscripción JSON de forma independiente."
"subTitle" = "Título de la Suscripción"
"subTitleDesc" = "Título mostrado en el cliente de VPN"
"subSupportUrl" = "URL de soporte"
"subSupportUrlDesc" = "Enlace de soporte técnico mostrado en el cliente VPN"
"subProfileUrl" = "URL del perfil"
"subProfileUrlDesc" = "Un enlace a tu sitio web mostrado en el cliente VPN"
"subAnnounce" = "Anuncio"
"subAnnounceDesc" = "El texto del anuncio mostrado en el cliente VPN"
"subEnableRouting" = "Habilitar enrutamiento"
"subEnableRoutingDesc" = "Configuración global para habilitar el enrutamiento en el cliente VPN. (Solo para Happ)"
"subRoutingRules" = "Reglas de enrutamiento"
"subRoutingRulesDesc" = "Reglas de enrutamiento globales para el cliente VPN. (Solo para Happ)"
"subListen" = "Listening IP"
"subListenDesc" = "Dejar en blanco por defecto para monitorear todas las IPs."
"subPort" = "Puerto de Suscripción"

View file

@ -374,6 +374,16 @@
"subJsonEnable" = "فعال/غیرفعال‌سازی مستقل نقطه دسترسی سابسکریپشن JSON."
"subTitle" = "عنوان اشتراک"
"subTitleDesc" = "عنوان نمایش داده شده در کلاینت VPN"
"subSupportUrl" = "آدرس پشتیبانی"
"subSupportUrlDesc" = "لینک پشتیبانی فنی که در کلاینت VPN نمایش داده می‌شود"
"subProfileUrl" = "آدرس پروفایل"
"subProfileUrlDesc" = "لینک وب‌سایت شما که در کلاینت VPN نمایش داده می‌شود"
"subAnnounce" = "اعلان"
"subAnnounceDesc" = "متن اعلانی که در کلاینت VPN نمایش داده می‌شود"
"subEnableRouting" = "فعال‌سازی مسیریابی"
"subEnableRoutingDesc" = "تنظیمات سراسری برای فعال‌سازی مسیریابی در کلاینت VPN. (فقط برای Happ)"
"subRoutingRules" = "قوانین مسیریابی"
"subRoutingRulesDesc" = "قوانین مسیریابی سراسری برای کلاینت VPN. (فقط برای Happ)"
"subListen" = "آدرس آی‌پی"
"subListenDesc" = "آدرس آی‌پی برای سرویس سابسکریپشن. برای گوش دادن به‌تمام آی‌پی‌ها خالی‌بگذارید"
"subPort" = "پورت"

View file

@ -374,6 +374,16 @@
"subJsonEnable" = "Aktifkan/Nonaktifkan endpoint langganan JSON secara mandiri."
"subTitle" = "Judul Langganan"
"subTitleDesc" = "Judul yang ditampilkan di klien VPN"
"subSupportUrl" = "URL Dukungan"
"subSupportUrlDesc" = "Tautan dukungan teknis yang ditampilkan di klien VPN"
"subProfileUrl" = "URL Profil"
"subProfileUrlDesc" = "Tautan ke situs web Anda yang ditampilkan di klien VPN"
"subAnnounce" = "Pengumuman"
"subAnnounceDesc" = "Teks pengumuman yang ditampilkan di klien VPN"
"subEnableRouting" = "Aktifkan perutean"
"subEnableRoutingDesc" = "Pengaturan global untuk mengaktifkan perutean (routing) di klien VPN. (Hanya untuk Happ)"
"subRoutingRules" = "Aturan routing"
"subRoutingRulesDesc" = "Aturan routing global untuk klien VPN. (Hanya untuk Happ)"
"subListen" = "IP Pendengar"
"subListenDesc" = "Alamat IP untuk layanan langganan. (biarkan kosong untuk mendengarkan semua IP)"
"subPort" = "Port Pendengar"

View file

@ -374,6 +374,16 @@
"subJsonEnable" = "JSON サブスクリプションのエンドポイントを個別に有効/無効にする。"
"subTitle" = "サブスクリプションタイトル"
"subTitleDesc" = "VPNクライアントに表示されるタイトル"
"subSupportUrl" = "サポートURL"
"subSupportUrlDesc" = "VPNクライアントに表示されるテクニカルサポートへのリンク"
"subProfileUrl" = "プロフィールURL"
"subProfileUrlDesc" = "VPNクライアントに表示されるWebサイトへのリンク"
"subAnnounce" = "お知らせ"
"subAnnounceDesc" = "VPNクライアントに表示されるお知らせのテキスト"
"subEnableRouting" = "ルーティングを有効化"
"subEnableRoutingDesc" = "VPNクライアントでルーティングを有効にするためのグローバル設定。(Happのみ)"
"subRoutingRules" = "ルーティングルール"
"subRoutingRulesDesc" = "VPNクライアントのグローバルルーティングルール。(Happのみ)"
"subListen" = "監視IP"
"subListenDesc" = "サブスクリプションサービスが監視するIPアドレス空白にするとすべてのIPを監視"
"subPort" = "監視ポート"

View file

@ -374,6 +374,16 @@
"subJsonEnable" = "Ativar/Desativar o endpoint de assinatura JSON de forma independente."
"subTitle" = "Título da Assinatura"
"subTitleDesc" = "Título exibido no cliente VPN"
"subSupportUrl" = "URL de Suporte"
"subSupportUrlDesc" = "Link de suporte técnico exibido no cliente VPN"
"subProfileUrl" = "URL de Perfil"
"subProfileUrlDesc" = "Um link para o seu site exibido no cliente VPN"
"subAnnounce" = "Anúncio"
"subAnnounceDesc" = "O texto do anúncio exibido no cliente VPN"
"subEnableRouting" = "Ativar roteamento"
"subEnableRoutingDesc" = "Configuração global para habilitar o roteamento no cliente VPN. (Apenas para Happ)"
"subRoutingRules" = "Regras de roteamento"
"subRoutingRulesDesc" = "Regras de roteamento globais para o cliente VPN. (Apenas para Happ)"
"subListen" = "IP de Escuta"
"subListenDesc" = "O endereço IP para o serviço de assinatura. (deixe em branco para escutar em todos os IPs)"
"subPort" = "Porta de Escuta"

View file

@ -373,7 +373,17 @@
"subEnableDesc" = "Функция подписки с отдельной конфигурацией"
"subJsonEnable" = "Включить/отключить JSON-эндпоинт подписки независимо."
"subTitle" = "Заголовок подписки"
"subTitleDesc" = "Название подписки, которое видит клиент в VPN клиенте"
"subTitleDesc" = "Название подписки, которое видит клиент в VPN-клиенте"
"subSupportUrl" = "URL поддержки"
"subSupportUrlDesc" = "Ссылка на техническую поддержку, отображаемая в VPN-клиенте"
"subProfileUrl" = "URL профиля"
"subProfileUrlDesc" = "Ссылка на ваш сайт, отображаемая в VPN-клиенте"
"subAnnounce" = "Объявление"
"subAnnounceDesc" = "Текст объявления, отображаемый в VPN-клиенте"
"subEnableRouting" = "Включить маршрутизацию"
"subEnableRoutingDesc" = "Глобальная настройка для включения маршрутизации в VPN-клиенте. (Только для Happ)"
"subRoutingRules" = "Правила маршрутизации"
"subRoutingRulesDesc" = "Глобальные правила маршрутизации для VPN-клиента. (Только для Happ)"
"subListen" = "Прослушивание IP"
"subListenDesc" = "Оставьте пустым по умолчанию, чтобы отслеживать все IP-адреса"
"subPort" = "Порт подписки"

View file

@ -374,6 +374,16 @@
"subJsonEnable" = "JSON abonelik uç noktasını bağımsız olarak Etkinleştir/Devre Dışı bırak."
"subTitle" = "Abonelik Başlığı"
"subTitleDesc" = "VPN istemcisinde gösterilen başlık"
"subSupportUrl" = "Destek URL'si"
"subSupportUrlDesc" = "VPN istemcisinde gösterilen teknik destek bağlantısı"
"subProfileUrl" = "Profil URL'si"
"subProfileUrlDesc" = "VPN istemcisinde görüntülenen web sitenize giden bağlantı"
"subAnnounce" = "Duyuru"
"subAnnounceDesc" = "VPN istemcisinde görüntülenen duyuru metni"
"subEnableRouting" = "Yönlendirmeyi etkinleştir"
"subEnableRoutingDesc" = "VPN istemcisinde yönlendirmeyi etkinleştirmek için genel ayar. (Yalnızca Happ için)"
"subRoutingRules" = "Yönlendirme kuralları"
"subRoutingRulesDesc" = "VPN istemcisi için genel yönlendirme kuralları. (Yalnızca Happ için)"
"subListen" = "Dinleme IP"
"subListenDesc" = "Abonelik hizmeti için IP adresi. (tüm IP'leri dinlemek için boş bırakın)"
"subPort" = "Dinleme Portu"

View file

@ -374,6 +374,16 @@
"subJsonEnable" = "Увімкнути/вимкнути JSON-кінець підписки незалежно."
"subTitle" = "Назва Підписки"
"subTitleDesc" = "Назва, яка відображається у VPN-клієнті"
"subSupportUrl" = "URL підтримки"
"subSupportUrlDesc" = "Посилання на технічну підтримку, що відображається у VPN-клієнті"
"subProfileUrl" = "URL профілю"
"subProfileUrlDesc" = "Посилання на ваш вебсайт, що відображається у VPN-клієнті"
"subAnnounce" = "Оголошення"
"subAnnounceDesc" = "Текст оголошення, що відображається у VPN-клієнті"
"subEnableRouting" = "Увімкнути маршрутизацію"
"subEnableRoutingDesc" = "Глобальне налаштування для увімкнення маршрутизації у VPN-клієнті. (Тільки для Happ)"
"subRoutingRules" = "Правила маршрутизації"
"subRoutingRulesDesc" = "Глобальні правила маршрутизації для VPN-клієнта. (Тільки для Happ)"
"subListen" = "Слухати IP"
"subListenDesc" = "IP-адреса для служби підписки. (залиште порожнім, щоб слухати всі IP-адреси)"
"subPort" = "Слухати порт"

View file

@ -374,6 +374,16 @@
"subJsonEnable" = "Bật/Tắt điểm cuối đăng ký JSON độc lập."
"subTitle" = "Tiêu đề Đăng ký"
"subTitleDesc" = "Tiêu đề hiển thị trong ứng dụng VPN"
"subSupportUrl" = "URL Hỗ trợ"
"subSupportUrlDesc" = "Liên kết hỗ trợ kỹ thuật hiển thị trong ứng dụng VPN"
"subProfileUrl" = "URL Hồ sơ"
"subProfileUrlDesc" = "Liên kết đến trang web của bạn hiển thị trong ứng dụng VPN"
"subAnnounce" = "Thông báo"
"subAnnounceDesc" = "Văn bản thông báo hiển thị trong ứng dụng VPN"
"subEnableRouting" = "Bật định tuyến"
"subEnableRoutingDesc" = "Cài đặt toàn cục để bật định tuyến trong ứng dụng khách VPN. (Chỉ dành cho Happ)"
"subRoutingRules" = "Quy tắc định tuyến"
"subRoutingRulesDesc" = "Quy tắc định tuyến toàn cầu cho client VPN. (Chỉ dành cho Happ)"
"subListen" = "Listening IP"
"subListenDesc" = "Mặc định để trống để nghe tất cả các IP"
"subPort" = "Cổng gói đăng ký"

View file

@ -374,6 +374,16 @@
"subJsonEnable" = "单独启用/禁用 JSON 订阅端点。"
"subTitle" = "订阅标题"
"subTitleDesc" = "在VPN客户端中显示的标题"
"subSupportUrl" = "支持链接"
"subSupportUrlDesc" = "VPN 客户端中显示的技术支持链接"
"subProfileUrl" = "个人资料链接"
"subProfileUrlDesc" = "VPN 客户端中显示的网站链接"
"subAnnounce" = "公告"
"subAnnounceDesc" = "VPN 客户端中显示的公告文本"
"subEnableRouting" = "启用路由"
"subEnableRoutingDesc" = "在 VPN 客户端中启用路由的全局设置。(僅限 Happ"
"subRoutingRules" = "路由規則"
"subRoutingRulesDesc" = "VPN 用戶端的全域路由規則。(僅限 Happ"
"subListen" = "监听 IP"
"subListenDesc" = "订阅服务监听的 IP 地址(留空表示监听所有 IP"
"subPort" = "监听端口"

View file

@ -374,6 +374,16 @@
"subJsonEnable" = "獨立啟用/停用 JSON 訂閱端點。"
"subTitle" = "訂閱標題"
"subTitleDesc" = "在VPN客戶端中顯示的標題"
"subSupportUrl" = "支援連結"
"subSupportUrlDesc" = "VPN 用戶端中顯示的技術支援連結"
"subProfileUrl" = "個人資料連結"
"subProfileUrlDesc" = "VPN 用戶端中顯示的網站連結"
"subAnnounce" = "公告"
"subAnnounceDesc" = "VPN 用戶端中顯示的公告文字"
"subEnableRouting" = "啟用路由"
"subEnableRoutingDesc" = "在 VPN 用戶端中啟用路由的全域設定。(僅限 Happ"
"subRoutingRules" = "路由規則"
"subRoutingRulesDesc" = "VPN 用戶端的全域路由規則。(僅限 Happ"
"subListen" = "監聽 IP"
"subListenDesc" = "訂閱服務監聽的 IP 地址(留空表示監聽所有 IP"
"subPort" = "監聽埠"