Compare commits

..

4 commits

Author SHA1 Message Date
DHR60
ab9603dac8
Merge 036aee564b into a2929c6086 2026-03-20 15:09:11 +08:00
DHR60
036aee564b Fix 2026-03-13 23:06:28 +08:00
DHR60
cc3b0a5eda Add NaiveProxy support 2026-03-13 23:06:28 +08:00
DHR60
3893ac847d Add UoT support 2026-03-13 23:06:24 +08:00
16 changed files with 120 additions and 329 deletions

View file

@ -1,7 +1,7 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<Version>7.19.5</Version> <Version>7.19.4</Version>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>

View file

@ -13,7 +13,7 @@
<PackageVersion Include="CliWrap" Version="3.10.0" /> <PackageVersion Include="CliWrap" Version="3.10.0" />
<PackageVersion Include="Downloader" Version="5.1.0" /> <PackageVersion Include="Downloader" Version="5.1.0" />
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.4.1" /> <PackageVersion Include="H.NotifyIcon.Wpf" Version="2.4.1" />
<PackageVersion Include="MaterialDesignThemes" Version="5.3.1" /> <PackageVersion Include="MaterialDesignThemes" Version="5.3.0" />
<PackageVersion Include="MessageBox.Avalonia" Version="3.3.1.1" /> <PackageVersion Include="MessageBox.Avalonia" Version="3.3.1.1" />
<PackageVersion Include="QRCoder" Version="1.7.0" /> <PackageVersion Include="QRCoder" Version="1.7.0" />
<PackageVersion Include="ReactiveUI" Version="23.1.8" /> <PackageVersion Include="ReactiveUI" Version="23.1.8" />

View file

@ -933,42 +933,6 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Copy 的本地化字符串。
/// </summary>
public static string menuEditCopy {
get {
return ResourceManager.GetString("menuEditCopy", resourceCulture);
}
}
/// <summary>
/// 查找类似 Format 的本地化字符串。
/// </summary>
public static string menuEditFormat {
get {
return ResourceManager.GetString("menuEditFormat", resourceCulture);
}
}
/// <summary>
/// 查找类似 Paste 的本地化字符串。
/// </summary>
public static string menuEditPaste {
get {
return ResourceManager.GetString("menuEditPaste", resourceCulture);
}
}
/// <summary>
/// 查找类似 Select all 的本地化字符串。
/// </summary>
public static string menuEditSelectAll {
get {
return ResourceManager.GetString("menuEditSelectAll", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Edit 的本地化字符串。 /// 查找类似 Edit 的本地化字符串。
/// </summary> /// </summary>

View file

@ -1668,18 +1668,6 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="menuGenRegionGroup" xml:space="preserve"> <data name="menuGenRegionGroup" xml:space="preserve">
<value>Group by Region</value> <value>Group by Region</value>
</data> </data>
<data name="menuEditCopy" xml:space="preserve">
<value>کپی</value>
</data>
<data name="menuEditSelectAll" xml:space="preserve">
<value>انتخاب همه</value>
</data>
<data name="menuEditPaste" xml:space="preserve">
<value>Paste</value>
</data>
<data name="menuEditFormat" xml:space="preserve">
<value>Format</value>
</data>
<data name="TbUot" xml:space="preserve"> <data name="TbUot" xml:space="preserve">
<value>UDP over TCP</value> <value>UDP over TCP</value>
</data> </data>

View file

@ -1665,18 +1665,6 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="menuGenRegionGroup" xml:space="preserve"> <data name="menuGenRegionGroup" xml:space="preserve">
<value>Group by Region</value> <value>Group by Region</value>
</data> </data>
<data name="menuEditCopy" xml:space="preserve">
<value>Copier</value>
</data>
<data name="menuEditSelectAll" xml:space="preserve">
<value>Tout sélect</value>
</data>
<data name="menuEditPaste" xml:space="preserve">
<value>Paste</value>
</data>
<data name="menuEditFormat" xml:space="preserve">
<value>Format</value>
</data>
<data name="TbUot" xml:space="preserve"> <data name="TbUot" xml:space="preserve">
<value>UDP over TCP</value> <value>UDP over TCP</value>
</data> </data>

View file

@ -1668,18 +1668,6 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="menuGenRegionGroup" xml:space="preserve"> <data name="menuGenRegionGroup" xml:space="preserve">
<value>Group by Region</value> <value>Group by Region</value>
</data> </data>
<data name="menuEditCopy" xml:space="preserve">
<value>Másolás</value>
</data>
<data name="menuEditSelectAll" xml:space="preserve">
<value>Összes kijelölése</value>
</data>
<data name="menuEditPaste" xml:space="preserve">
<value>Paste</value>
</data>
<data name="menuEditFormat" xml:space="preserve">
<value>Format</value>
</data>
<data name="TbUot" xml:space="preserve"> <data name="TbUot" xml:space="preserve">
<value>UDP over TCP</value> <value>UDP over TCP</value>
</data> </data>

View file

@ -1668,18 +1668,6 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="menuGenRegionGroup" xml:space="preserve"> <data name="menuGenRegionGroup" xml:space="preserve">
<value>Group by Region</value> <value>Group by Region</value>
</data> </data>
<data name="menuEditCopy" xml:space="preserve">
<value>Copy</value>
</data>
<data name="menuEditSelectAll" xml:space="preserve">
<value>Select all</value>
</data>
<data name="menuEditPaste" xml:space="preserve">
<value>Paste</value>
</data>
<data name="menuEditFormat" xml:space="preserve">
<value>Format</value>
</data>
<data name="TbUot" xml:space="preserve"> <data name="TbUot" xml:space="preserve">
<value>UDP over TCP</value> <value>UDP over TCP</value>
</data> </data>

View file

@ -1027,7 +1027,7 @@
<value>Протокол Mux для sing-box</value> <value>Протокол Mux для sing-box</value>
</data> </data>
<data name="TbRoutingRuleProcess" xml:space="preserve"> <data name="TbRoutingRuleProcess" xml:space="preserve">
<value>Процесс (Linux/Windows)</value> <value>Process (Linux/Windows)</value>
</data> </data>
<data name="TbRoutingRuleIP" xml:space="preserve"> <data name="TbRoutingRuleIP" xml:space="preserve">
<value>IP-адрес или сеть CIDR</value> <value>IP-адрес или сеть CIDR</value>
@ -1393,10 +1393,10 @@
<value>Внутренний DNS</value> <value>Внутренний DNS</value>
</data> </data>
<data name="TbDirectResolveStrategy" xml:space="preserve"> <data name="TbDirectResolveStrategy" xml:space="preserve">
<value>Стратегия разрешения прямых соединений</value> <value>Direct Target Resolution Strategy</value>
</data> </data>
<data name="TbRemoteResolveStrategy" xml:space="preserve"> <data name="TbRemoteResolveStrategy" xml:space="preserve">
<value>Стратегия разрешения прокси-соединений</value> <value>Proxy Target Resolution Strategy</value>
</data> </data>
<data name="TbAddCommonDNSHosts" xml:space="preserve"> <data name="TbAddCommonDNSHosts" xml:space="preserve">
<value>Добавить стандартные записи hosts (DNS)</value> <value>Добавить стандартные записи hosts (DNS)</value>
@ -1429,7 +1429,7 @@
<value>Включён пользовательский DNS — настройки на этой странице не применяются</value> <value>Включён пользовательский DNS — настройки на этой странице не применяются</value>
</data> </data>
<data name="TbBlockSVCBHTTPSQueriesTips" xml:space="preserve"> <data name="TbBlockSVCBHTTPSQueriesTips" xml:space="preserve">
<value>При включении блокирует проверки доступности ECH и HTTP/3</value> <value>Block ECH and HTTP/3 availability checks when enabled</value>
</data> </data>
<data name="FillCorrectConfigTemplateText" xml:space="preserve"> <data name="FillCorrectConfigTemplateText" xml:space="preserve">
<value>Пожалуйста, заполните корректный шаблон конфигурации</value> <value>Пожалуйста, заполните корректный шаблон конфигурации</value>
@ -1462,127 +1462,127 @@
<value>Эта функция предназначена для продвинутых пользователей и особых случаев. После включения игнорируются базовые настройки ядра, DNS и маршрутизации. Вы должны самостоятельно корректно задать порт системного прокси, учёт трафика и другие связанные параметры — всё настраивается вручную.</value> <value>Эта функция предназначена для продвинутых пользователей и особых случаев. После включения игнорируются базовые настройки ядра, DNS и маршрутизации. Вы должны самостоятельно корректно задать порт системного прокси, учёт трафика и другие связанные параметры — всё настраивается вручную.</value>
</data> </data>
<data name="MsgStartParsingSubscription" xml:space="preserve"> <data name="MsgStartParsingSubscription" xml:space="preserve">
<value>Начинается разбор и обработка содержимого подписки</value> <value>Start parsing and processing subscription content</value>
</data> </data>
<data name="TbSelectProfile" xml:space="preserve"> <data name="TbSelectProfile" xml:space="preserve">
<value>Выбрать профиль</value> <value>Select Profile</value>
</data> </data>
<data name="TbFakeIPTips" xml:space="preserve"> <data name="TbFakeIPTips" xml:space="preserve">
<value>По умолчанию применяется глобально, со встроенной фильтрацией FakeIP (только sing-box).</value> <value>Applies globally by default, with built-in FakeIP filtering (sing-box only).</value>
</data> </data>
<data name="PleaseAddAtLeastOneServer" xml:space="preserve"> <data name="PleaseAddAtLeastOneServer" xml:space="preserve">
<value>Добавьте хотя бы одну конфигурацию</value> <value>Please Add At Least One Configuration</value>
</data> </data>
<data name="TbConfigTypePolicyGroup" xml:space="preserve"> <data name="TbConfigTypePolicyGroup" xml:space="preserve">
<value>Группа политик</value> <value>Policy Group</value>
</data> </data>
<data name="TbConfigTypeProxyChain" xml:space="preserve"> <data name="TbConfigTypeProxyChain" xml:space="preserve">
<value>Цепочка прокси</value> <value>Proxy Chain</value>
</data> </data>
<data name="TbLeastPing" xml:space="preserve"> <data name="TbLeastPing" xml:space="preserve">
<value>Наименьшая задержка</value> <value>Lowest Latency</value>
</data> </data>
<data name="TbRandom" xml:space="preserve"> <data name="TbRandom" xml:space="preserve">
<value>Случайный</value> <value>Random</value>
</data> </data>
<data name="TbRoundRobin" xml:space="preserve"> <data name="TbRoundRobin" xml:space="preserve">
<value>Циклический (Round Robin)</value> <value>Round Robin</value>
</data> </data>
<data name="TbLeastLoad" xml:space="preserve"> <data name="TbLeastLoad" xml:space="preserve">
<value>Наиболее стабильный</value> <value>Most Stable</value>
</data> </data>
<data name="TbPolicyGroupType" xml:space="preserve"> <data name="TbPolicyGroupType" xml:space="preserve">
<value>Тип группы политик</value> <value>Policy Group Type</value>
</data> </data>
<data name="menuAddPolicyGroupServer" xml:space="preserve"> <data name="menuAddPolicyGroupServer" xml:space="preserve">
<value>Добавить группу политик </value> <value>Add Policy Group Configuration</value>
</data> </data>
<data name="menuAddProxyChainServer" xml:space="preserve"> <data name="menuAddProxyChainServer" xml:space="preserve">
<value>Добавить цепочку прокси</value> <value>Add Proxy Chain Configuration</value>
</data> </data>
<data name="menuAddChildServer" xml:space="preserve"> <data name="menuAddChildServer" xml:space="preserve">
<value>Добавить дочернюю конфигурацию </value> <value>Add Child Configuration</value>
</data> </data>
<data name="menuRemoveChildServer" xml:space="preserve"> <data name="menuRemoveChildServer" xml:space="preserve">
<value>Удалить дочернюю конфигурацию </value> <value>Remove Child Configuration</value>
</data> </data>
<data name="menuServerList" xml:space="preserve"> <data name="menuServerList" xml:space="preserve">
<value>Конфигурация 1: автодобавление из группы подписки</value> <value>Configuration item 1, Auto add from subscription group</value>
</data> </data>
<data name="TbFallback" xml:space="preserve"> <data name="TbFallback" xml:space="preserve">
<value>Резервный (Fallback)</value> <value>Fallback</value>
</data> </data>
<data name="MsgCoreNotSupportNetwork" xml:space="preserve"> <data name="MsgCoreNotSupportNetwork" xml:space="preserve">
<value>Ядро «{0}» не поддерживает тип сети «{1}»</value> <value>Core '{0}' does not support network type '{1}'</value>
</data> </data>
<data name="MsgCoreNotSupportProtocolTransport" xml:space="preserve"> <data name="MsgCoreNotSupportProtocolTransport" xml:space="preserve">
<value>Ядро «{0}» не поддерживает протокол «{1}» при транспорте «{2}»</value> <value>Core '{0}' does not support protocol '{1}' when using transport '{2}'</value>
</data> </data>
<data name="MsgCoreNotSupportProtocol" xml:space="preserve"> <data name="MsgCoreNotSupportProtocol" xml:space="preserve">
<value>Ядро «{0}» не поддерживает протокол «{1}»</value> <value>Core '{0}' does not support protocol '{1}'</value>
</data> </data>
<data name="MsgInvalidProperty" xml:space="preserve"> <data name="MsgInvalidProperty" xml:space="preserve">
<value>Свойство {0} недопустимо, проверьте его</value> <value>The {0} property is invalid, please check</value>
</data> </data>
<data name="MsgNotSupportProtocol" xml:space="preserve"> <data name="MsgNotSupportProtocol" xml:space="preserve">
<value>Протокол «{0}» не поддерживается</value> <value>Not support protocol '{0}'</value>
</data> </data>
<data name="TbSettingsHide2TrayWhenCloseTip" xml:space="preserve"> <data name="TbSettingsHide2TrayWhenCloseTip" xml:space="preserve">
<value>Если в системе нет функции трея, не включайте эту опцию</value> <value>If the system does not have a tray function, please do not enable it</value>
</data> </data>
<data name="TbRuleTypeTips" xml:space="preserve"> <data name="TbRuleTypeTips" xml:space="preserve">
<value>Можно задать отдельные правила для маршрутизации и DNS или выбрать «ALL» для применения к обоим</value> <value>You can set separate rules for Routing and DNS, or select "ALL" to apply to both</value>
</data> </data>
<data name="TbRuleType" xml:space="preserve"> <data name="TbRuleType" xml:space="preserve">
<value>Тип правила</value> <value>Rule Type</value>
</data> </data>
<data name="TbBootstrapDNS" xml:space="preserve"> <data name="TbBootstrapDNS" xml:space="preserve">
<value>Bootstrap DNS</value> <value>Bootstrap DNS</value>
</data> </data>
<data name="TbBootstrapDNSTips" xml:space="preserve"> <data name="TbBootstrapDNSTips" xml:space="preserve">
<value>Разрешает домены DNS-серверов, требуется IP-адрес</value> <value>Resolve DNS server domains, requires IP</value>
</data> </data>
<data name="menuFastRealPing" xml:space="preserve"> <data name="menuFastRealPing" xml:space="preserve">
<value>Тест реальной задержки</value> <value>Test real delay</value>
</data> </data>
<data name="TbPolicyGroupSubChildTip" xml:space="preserve"> <data name="TbPolicyGroupSubChildTip" xml:space="preserve">
<value>Автодобавление отфильтрованных конфигураций из групп подписки</value> <value>Auto add filtered configuration from subscription groups</value>
</data> </data>
<data name="TbCertPinning" xml:space="preserve"> <data name="TbCertPinning" xml:space="preserve">
<value>Привязка сертификата</value> <value>Certificate Pinning</value>
</data> </data>
<data name="TbCertPinningTips" xml:space="preserve"> <data name="TbCertPinningTips" xml:space="preserve">
<value>Привязанный сертификат (заполните любое из полей) <value>Pinned certificate (fill in either one)
При указании сертификат будет привязан, а «Разрешить небезопасные» отключится. When specified, the certificate will be pinned, and "Allow Insecure" will be disabled.
Получение сертификата может завершиться неудачей при использовании самоподписанного сертификата или при наличии ненадёжного / вредоносного ЦС в системе.</value> The "Get Certificate" action may fail if a self-signed certificate is used or if the system contains an untrusted or malicious CA.</value>
</data> </data>
<data name="TbFetchCert" xml:space="preserve"> <data name="TbFetchCert" xml:space="preserve">
<value>Получить сертификат</value> <value>Fetch Certificate</value>
</data> </data>
<data name="TbFetchCertChain" xml:space="preserve"> <data name="TbFetchCertChain" xml:space="preserve">
<value>Получить цепочку сертификатов</value> <value>Fetch Certificate Chain</value>
</data> </data>
<data name="ServerNameMustBeValidDomain" xml:space="preserve"> <data name="ServerNameMustBeValidDomain" xml:space="preserve">
<value>Укажите корректный домен</value> <value>Please set a valid domain</value>
</data> </data>
<data name="CertNotSet" xml:space="preserve"> <data name="CertNotSet" xml:space="preserve">
<value>Сертификат не задан</value> <value>Certificate not set</value>
</data> </data>
<data name="CertSet" xml:space="preserve"> <data name="CertSet" xml:space="preserve">
<value>Сертификат задан</value> <value>Certificate set</value>
</data> </data>
<data name="TbSettingsCustomSystemProxyPacPath" xml:space="preserve"> <data name="TbSettingsCustomSystemProxyPacPath" xml:space="preserve">
<value>Путь к пользовательскому PAC-файлу</value> <value>Custom PAC file path</value>
</data> </data>
<data name="TbSettingsCustomSystemProxyScriptPath" xml:space="preserve"> <data name="TbSettingsCustomSystemProxyScriptPath" xml:space="preserve">
<value>Путь к скрипту системного прокси</value> <value>Custom system proxy script file path</value>
</data> </data>
<data name="TbSettingsMacOSShowInDock" xml:space="preserve"> <data name="TbSettingsMacOSShowInDock" xml:space="preserve">
<value>Отображать в Dock на macOS (требуется перезапуск)</value> <value>macOS displays this in the Dock (requires restart)</value>
</data> </data>
<data name="menuServerList2" xml:space="preserve"> <data name="menuServerList2" xml:space="preserve">
<value>Конфигурация 2: выбор и добавление из собственных</value> <value>Configuration Item 2, Select and add from self-built</value>
</data> </data>
<data name="TbEchConfigList" xml:space="preserve"> <data name="TbEchConfigList" xml:space="preserve">
<value>EchConfigList</value> <value>EchConfigList</value>
@ -1591,94 +1591,82 @@
<value>EchForceQuery</value> <value>EchForceQuery</value>
</data> </data>
<data name="TbFullCertTips" xml:space="preserve"> <data name="TbFullCertTips" xml:space="preserve">
<value>Полный сертификат (цепочка) в формате PEM</value> <value>Full certificate (chain), PEM format</value>
</data> </data>
<data name="TbCertSha256Tips" xml:space="preserve"> <data name="TbCertSha256Tips" xml:space="preserve">
<value>Отпечаток сертификата (SHA-256)</value> <value>Certificate fingerprint (SHA-256)</value>
</data> </data>
<data name="TbServeStale" xml:space="preserve"> <data name="TbServeStale" xml:space="preserve">
<value>Отдавать устаревшие записи (Serve Stale)</value> <value>Serve Stale</value>
</data> </data>
<data name="TbParallelQuery" xml:space="preserve"> <data name="TbParallelQuery" xml:space="preserve">
<value>Параллельные запросы</value> <value>Parallel Query</value>
</data> </data>
<data name="TbDomesticDNSTips" xml:space="preserve"> <data name="TbDomesticDNSTips" xml:space="preserve">
<value>По умолчанию используется только при разрешении имён в процессе маршрутизации</value> <value>By default, invoked only during routing for resolution</value>
</data> </data>
<data name="TbRemoteDNSTips" xml:space="preserve"> <data name="TbRemoteDNSTips" xml:space="preserve">
<value>По умолчанию используется только при разрешении имён в процессе маршрутизации; убедитесь, что удалённый сервер может достичь этого DNS</value> <value>By default, invoked only during routing for resolution; ensure the remote server can reach this DNS</value>
</data> </data>
<data name="TbDirectResolveStrategyTips" xml:space="preserve"> <data name="TbDirectResolveStrategyTips" xml:space="preserve">
<value>Если не задано или «AsIs», используется системный DNS; иначе — встроенный DNS-модуль.</value> <value>If unset or "AsIs", DNS resolution uses the system DNS; otherwise, the internal DNS module is used.</value>
</data> </data>
<data name="TbRemoteResolveStrategyTips" xml:space="preserve"> <data name="TbRemoteResolveStrategyTips" xml:space="preserve">
<value>Если не задано или «AsIs», разрешение DNS выполняется DNS удалённого сервера; иначе — встроенный DNS-модуль.</value> <value>If unset or "AsIs", DNS resolution is performed by the remote server's DNS; otherwise, the internal DNS module is used.</value>
</data> </data>
<data name="TbHopInt7" xml:space="preserve"> <data name="TbHopInt7" xml:space="preserve">
<value>Интервал смены портов (Port Hopping)</value> <value>Port hopping interval</value>
</data> </data>
<data name="menuServerListPreview" xml:space="preserve"> <data name="menuServerListPreview" xml:space="preserve">
<value>Предпросмотр конфигурации</value> <value>Configuration item preview</value>
</data> </data>
<data name="TbFinalmask" xml:space="preserve"> <data name="TbFinalmask" xml:space="preserve">
<value>Finalmask</value> <value>Finalmask</value>
</data> </data>
<data name="MsgRoutingRuleOutboundNodeWarning" xml:space="preserve"> <data name="MsgRoutingRuleOutboundNodeWarning" xml:space="preserve">
<value>Правило маршрутизации {0}, исходящий узел {1}, предупреждение: {2}</value> <value>Routing rule {0} outbound node {1} warning: {2}</value>
</data> </data>
<data name="MsgRoutingRuleOutboundNodeError" xml:space="preserve"> <data name="MsgRoutingRuleOutboundNodeError" xml:space="preserve">
<value>Правило маршрутизации {0}, исходящий узел {1}, ошибка: {2}. Используется только прокси-узел.</value> <value>Routing rule {0} outbound node {1} error: {2}. Fallback to proxy node only.</value>
</data> </data>
<data name="MsgGroupCycleDependency" xml:space="preserve"> <data name="MsgGroupCycleDependency" xml:space="preserve">
<value>Группа {0} имеет циклическую зависимость на дочерний узел {1}. Узел пропущен.</value> <value>Group {0} has a cycle dependency on child node {1}. Skipping this node.</value>
</data> </data>
<data name="MsgGroupChildNodeWarning" xml:space="preserve"> <data name="MsgGroupChildNodeWarning" xml:space="preserve">
<value>Группа {0}: предупреждение дочернего узла {1}: {2}</value> <value>Group {0} child node {1} warning: {2}</value>
</data> </data>
<data name="MsgGroupChildNodeError" xml:space="preserve"> <data name="MsgGroupChildNodeError" xml:space="preserve">
<value>Группа {0}: ошибка дочернего узла {1}: {2}. Узел пропущен.</value> <value>Group {0} child node {1} error: {2}. Skipping this node.</value>
</data> </data>
<data name="MsgGroupChildGroupNodeWarning" xml:space="preserve"> <data name="MsgGroupChildGroupNodeWarning" xml:space="preserve">
<value>Группа {0}: предупреждение дочернего узла группы {1}: {2}</value> <value>Group {0} child group node {1} warning: {2}</value>
</data> </data>
<data name="MsgGroupChildGroupNodeError" xml:space="preserve"> <data name="MsgGroupChildGroupNodeError" xml:space="preserve">
<value>Группа {0}: ошибка дочернего узла группы {1}: {2}. Узел пропущен.</value> <value>Group {0} child group node {1} error: {2}. Skipping this node.</value>
</data> </data>
<data name="MsgGroupNoValidChildNode" xml:space="preserve"> <data name="MsgGroupNoValidChildNode" xml:space="preserve">
<value>У группы {0} нет допустимых дочерних узлов.</value> <value>Group {0} has no valid child node.</value>
</data> </data>
<data name="MsgRoutingRuleEmptyOutboundTag" xml:space="preserve"> <data name="MsgRoutingRuleEmptyOutboundTag" xml:space="preserve">
<value>У правила маршрутизации {0} пустой исходящий тег. Используется только прокси-узел.</value> <value>Routing rule {0} has an empty outbound tag. Fallback to proxy node only.</value>
</data> </data>
<data name="MsgRoutingRuleOutboundNodeNotFound" xml:space="preserve"> <data name="MsgRoutingRuleOutboundNodeNotFound" xml:space="preserve">
<value>Правило маршрутизации {0}, исходящий узел {1} не найден. Используется только прокси-узел.</value> <value>Routing rule {0} outbound node {1} not found. Fallback to proxy node only.</value>
</data> </data>
<data name="MsgSubscriptionPrevProfileNotFound" xml:space="preserve"> <data name="MsgSubscriptionPrevProfileNotFound" xml:space="preserve">
<value>Предыдущий прокси подписки {0} не найден. Пропущено.</value> <value>Subscription previous proxy {0} not found. Skipping.</value>
</data> </data>
<data name="MsgSubscriptionNextProfileNotFound" xml:space="preserve"> <data name="MsgSubscriptionNextProfileNotFound" xml:space="preserve">
<value>Следующий прокси подписки {0} не найден. Пропущено.</value> <value>Subscription next proxy {0} not found. Skipping.</value>
</data> </data>
<data name="menuGenGroupServer" xml:space="preserve"> <data name="menuGenGroupServer" xml:space="preserve">
<value>Сгенерировать группу политик</value> <value>Generate Policy Group</value>
</data> </data>
<data name="menuAllServers" xml:space="preserve"> <data name="menuAllServers" xml:space="preserve">
<value>Все конфигурации</value> <value>All configurations</value>
</data> </data>
<data name="menuGenRegionGroup" xml:space="preserve"> <data name="menuGenRegionGroup" xml:space="preserve">
<value>Группировка по регионам</value> <value>Group by Region</value>
</data>
<data name="menuEditCopy" xml:space="preserve">
<value>Скопировать</value>
</data>
<data name="menuEditSelectAll" xml:space="preserve">
<value>Выбрать все</value>
</data>
<data name="menuEditPaste" xml:space="preserve">
<value>Paste</value>
</data>
<data name="menuEditFormat" xml:space="preserve">
<value>Format</value>
</data> </data>
<data name="TbUot" xml:space="preserve"> <data name="TbUot" xml:space="preserve">
<value>UDP over TCP</value> <value>UDP over TCP</value>
@ -1692,4 +1680,4 @@
<data name="TbUsername" xml:space="preserve"> <data name="TbUsername" xml:space="preserve">
<value>Username</value> <value>Username</value>
</data> </data>
</root> </root>

View file

@ -1665,18 +1665,6 @@
<data name="menuGenRegionGroup" xml:space="preserve"> <data name="menuGenRegionGroup" xml:space="preserve">
<value>按地区分组</value> <value>按地区分组</value>
</data> </data>
<data name="menuEditCopy" xml:space="preserve">
<value>复制</value>
</data>
<data name="menuEditSelectAll" xml:space="preserve">
<value>全选</value>
</data>
<data name="menuEditPaste" xml:space="preserve">
<value>粘贴</value>
</data>
<data name="menuEditFormat" xml:space="preserve">
<value>格式化</value>
</data>
<data name="TbUot" xml:space="preserve"> <data name="TbUot" xml:space="preserve">
<value>UDP over TCP</value> <value>UDP over TCP</value>
</data> </data>

View file

@ -1665,18 +1665,6 @@
<data name="menuGenRegionGroup" xml:space="preserve"> <data name="menuGenRegionGroup" xml:space="preserve">
<value>按區域分組</value> <value>按區域分組</value>
</data> </data>
<data name="menuEditCopy" xml:space="preserve">
<value>複製</value>
</data>
<data name="menuEditSelectAll" xml:space="preserve">
<value>全選</value>
</data>
<data name="menuEditPaste" xml:space="preserve">
<value>Paste</value>
</data>
<data name="menuEditFormat" xml:space="preserve">
<value>Format</value>
</data>
<data name="TbUot" xml:space="preserve"> <data name="TbUot" xml:space="preserve">
<value>UDP over TCP</value> <value>UDP over TCP</value>
</data> </data>

View file

@ -5,7 +5,6 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib" xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
xmlns:views="clr-namespace:v2rayN.Desktop.Views"
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib" xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
Title="{x:Static resx:ResUI.menuServers}" Title="{x:Static resx:ResUI.menuServers}"
Width="900" Width="900"
@ -744,13 +743,16 @@
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TransportExtraTip}" /> Text="{x:Static resx:ResUI.TransportExtraTip}" />
<views:JsonEditor <TextBox
x:Name="txtExtra" x:Name="txtExtra"
Width="400" Width="400"
MinHeight="100" MinHeight="100"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalAlignment="Center" /> VerticalAlignment="Center"
Classes="TextArea"
MinLines="6"
TextWrapping="Wrap" />
</StackPanel> </StackPanel>
</Flyout> </Flyout>
</Button.Flyout> </Button.Flyout>
@ -832,13 +834,13 @@
<Button.Flyout> <Button.Flyout>
<Flyout> <Flyout>
<StackPanel> <StackPanel>
<views:JsonEditor <TextBox
x:Name="txtFinalmask" x:Name="txtFinalmask"
Width="400" Width="400"
MinHeight="100"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
HorizontalAlignment="Stretch" AcceptsReturn="True"
VerticalAlignment="Center" /> Classes="TextArea"
TextWrapping="NoWrap" />
</StackPanel> </StackPanel>
</Flyout> </Flyout>
</Button.Flyout> </Button.Flyout>

View file

@ -3,7 +3,6 @@
xmlns="https://github.com/avaloniaui" xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:v2rayN.Desktop.Views"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib" xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib" xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
@ -400,7 +399,12 @@
BorderBrush="Gray" BorderBrush="Gray"
BorderThickness="1" BorderThickness="1"
Header="HTTP/SOCKS"> Header="HTTP/SOCKS">
<local:JsonEditor Name="txtnormalDNSCompatible" VerticalAlignment="Stretch" /> <TextBox
Name="txtnormalDNSCompatible"
VerticalAlignment="Stretch"
Classes="TextArea"
MinLines="10"
TextWrapping="Wrap" />
</HeaderedContentControl> </HeaderedContentControl>
</DockPanel> </DockPanel>
</TabItem> </TabItem>
@ -469,7 +473,12 @@
BorderBrush="Gray" BorderBrush="Gray"
BorderThickness="1" BorderThickness="1"
Header="HTTP/SOCKS"> Header="HTTP/SOCKS">
<local:JsonEditor Name="txtnormalDNS2Compatible" VerticalAlignment="Stretch" /> <TextBox
Name="txtnormalDNS2Compatible"
VerticalAlignment="Stretch"
Classes="TextArea"
MinLines="10"
TextWrapping="Wrap" />
</HeaderedContentControl> </HeaderedContentControl>
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" /> <GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
@ -479,7 +488,12 @@
BorderBrush="Gray" BorderBrush="Gray"
BorderThickness="1" BorderThickness="1"
Header="{x:Static resx:ResUI.TbSettingsTunMode}"> Header="{x:Static resx:ResUI.TbSettingsTunMode}">
<local:JsonEditor Name="txttunDNS2Compatible" VerticalAlignment="Stretch" /> <TextBox
Name="txttunDNS2Compatible"
VerticalAlignment="Stretch"
Classes="TextArea"
MinLines="10"
TextWrapping="Wrap" />
</HeaderedContentControl> </HeaderedContentControl>
</Grid> </Grid>

View file

@ -5,7 +5,6 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib" xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
xmlns:views="clr-namespace:v2rayN.Desktop.Views"
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib" xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
Title="{x:Static resx:ResUI.menuFullConfigTemplate}" Title="{x:Static resx:ResUI.menuFullConfigTemplate}"
Width="900" Width="900"
@ -95,7 +94,12 @@
BorderBrush="Gray" BorderBrush="Gray"
BorderThickness="1" BorderThickness="1"
Header="xray config template json"> Header="xray config template json">
<views:JsonEditor x:Name="rayFullConfigTemplate" VerticalAlignment="Stretch" /> <TextBox
x:Name="rayFullConfigTemplate"
VerticalAlignment="Stretch"
Classes="TextArea"
MinLines="10"
TextWrapping="Wrap" />
</HeaderedContentControl> </HeaderedContentControl>
</DockPanel> </DockPanel>
</TabItem> </TabItem>
@ -162,7 +166,12 @@
BorderBrush="Gray" BorderBrush="Gray"
BorderThickness="1" BorderThickness="1"
Header="sing-box config template json"> Header="sing-box config template json">
<views:JsonEditor x:Name="sbFullConfigTemplate" VerticalAlignment="Stretch" /> <TextBox
x:Name="sbFullConfigTemplate"
VerticalAlignment="Stretch"
Classes="TextArea"
MinLines="10"
TextWrapping="Wrap" />
</HeaderedContentControl> </HeaderedContentControl>
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" /> <GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
@ -172,7 +181,12 @@
BorderBrush="Gray" BorderBrush="Gray"
BorderThickness="1" BorderThickness="1"
Header="sing-box tun config template json"> Header="sing-box tun config template json">
<views:JsonEditor x:Name="sbFullTunConfigTemplate" VerticalAlignment="Stretch" /> <TextBox
x:Name="sbFullTunConfigTemplate"
VerticalAlignment="Stretch"
Classes="TextArea"
MinLines="10"
TextWrapping="Wrap" />
</HeaderedContentControl> </HeaderedContentControl>
</Grid> </Grid>
</DockPanel> </DockPanel>

View file

@ -1,23 +0,0 @@
<UserControl
x:Class="v2rayN.Desktop.Views.JsonEditor"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ae="clr-namespace:AvaloniaEdit;assembly=AvaloniaEdit"
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib">
<ae:TextEditor
Name="Editor"
FontFamily="Cascadia Code,Consolas,Monospace"
FontSize="14"
ShowLineNumbers="True">
<ae:TextEditor.ContextMenu>
<ContextMenu>
<MenuItem Click="FormatJson_Click" Header="{x:Static resx:ResUI.menuEditFormat}" />
<Separator />
<MenuItem Click="Copy_Click" Header="{x:Static resx:ResUI.menuEditCopy}" />
<MenuItem Click="Paste_Click" Header="{x:Static resx:ResUI.menuEditPaste}" />
<MenuItem Click="SelectAll_Click" Header="{x:Static resx:ResUI.menuEditSelectAll}" />
</ContextMenu>
</ae:TextEditor.ContextMenu>
</ae:TextEditor>
</UserControl>

View file

@ -1,96 +0,0 @@
using System.Text.Json;
using System.Xml;
using AvaloniaEdit.Highlighting;
using AvaloniaEdit.Highlighting.Xshd;
namespace v2rayN.Desktop.Views;
public partial class JsonEditor : UserControl
{
private static readonly JsonSerializerOptions SIndentedOptions = new() { WriteIndented = true };
private static readonly Lazy<IHighlightingDefinition> SHighlightingDark =
new(() => BuildHighlighting(dark: true), isThreadSafe: true);
private static readonly Lazy<IHighlightingDefinition> SHighlightingLight =
new(() => BuildHighlighting(dark: false), isThreadSafe: true);
public static readonly StyledProperty<string> TextProperty =
AvaloniaProperty.Register<JsonEditor, string>(nameof(Text), defaultValue: string.Empty);
public string Text
{
get => GetValue(TextProperty);
set => SetValue(TextProperty, value);
}
public JsonEditor()
{
InitializeComponent();
var isDark = Application.Current?.ActualThemeVariant != ThemeVariant.Light;
Editor.SyntaxHighlighting = isDark ? SHighlightingDark.Value : SHighlightingLight.Value;
Editor.TextArea.TextView.Options.EnableHyperlinks = false;
Editor.TextChanged += (_, _) =>
{
if (Text != Editor.Text)
{
SetCurrentValue(TextProperty, Editor.Text);
}
};
this.GetObservable(TextProperty).Subscribe(text =>
{
if (Editor.Text != text)
{
Editor.Text = text ?? string.Empty;
}
});
}
private static IHighlightingDefinition BuildHighlighting(bool dark)
{
var keyColor = dark ? "#9CDCFE" : "#0451A5";
var strColor = dark ? "#CE9178" : "#A31515";
var numColor = dark ? "#B5CEA8" : "#098658";
var kwColor = dark ? "#569CD6" : "#0000FF";
var xshd = $"""
<?xml version="1.0"?>
<SyntaxDefinition name="JSON" xmlns="http://icsharpcode.net/sharpdevelop/syntaxdefinition/2008">
<Color name="Key" foreground="{keyColor}" />
<Color name="String" foreground="{strColor}" />
<Color name="Number" foreground="{numColor}" />
<Color name="Keyword" foreground="{kwColor}" fontWeight="bold" />
<RuleSet>
<Rule color="Key">"([^"\\]|\\.)*"(?=\s*:)</Rule>
<Rule color="String">"([^"\\]|\\.)*"</Rule>
<Rule color="Number">-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?</Rule>
<Keywords color="Keyword">
<Word>true</Word>
<Word>false</Word>
<Word>null</Word>
</Keywords>
</RuleSet>
</SyntaxDefinition>
""";
using var reader = XmlReader.Create(new StringReader(xshd));
return HighlightingLoader.Load(reader, HighlightingManager.Instance);
}
private void FormatJson_Click(object? sender, RoutedEventArgs e)
{
try
{
var obj = JsonUtils.ParseJson(Editor.Text);
Editor.Text = JsonUtils.Serialize(obj, SIndentedOptions);
}
catch
{
// ignored
}
}
private void Copy_Click(object? sender, RoutedEventArgs e) => Editor.Copy();
private void Paste_Click(object? sender, RoutedEventArgs e) => Editor.Paste();
private void SelectAll_Click(object? sender, RoutedEventArgs e) => Editor.SelectAll();
}

View file

@ -79,8 +79,8 @@
<MenuItem <MenuItem
x:Name="menuMsgViewSelectAll" x:Name="menuMsgViewSelectAll"
Click="menuMsgViewSelectAll_Click" Click="menuMsgViewSelectAll_Click"
Header="{x:Static resx:ResUI.menuMsgViewSelectAll}" InputGesture="Ctrl+A"
InputGesture="Ctrl+A" /> Header="{x:Static resx:ResUI.menuMsgViewSelectAll}" />
<MenuItem <MenuItem
x:Name="menuMsgViewCopy" x:Name="menuMsgViewCopy"
Click="menuMsgViewCopy_Click" Click="menuMsgViewCopy_Click"