ITEM6 B4: frontend reshaping — xray page retired, stats switches to settings, template read paths closed

- Delete the xray settings page (routes/menu/title), geodata UI/service,
  XraySettingController/Service and routing-sync write paths; the stored
  xrayTemplateConfig row loses its last readers (GetXrayConfigTemplate now
  returns the embedded factory template; B1 already deleted the row).
- Settings GeneralTab gains the four trafficStatsSwitches switches
  (settings.trafficStatsSwitches, B1) with the dual warning copy; entity
  AllSetting carries the key end to end (TestTrafficStatsSwitchesPlumbing).
- Tag-directory consumers (panelOutbound, mtproto egress, node/host
  outbound pickers) move from POST /xray/ to GET /server/outboundDirectory.
- Shared Mux/Sockopt forms and balancer helpers relocated to lib/xray;
  converter preserves sniffing ips/domains exclusions into the panel
  sidecar instead of dropping them (B2 gap closed by retention).
- Freedom final-rules DB fix seeders retired; getDefaultJsonConfig
  endpoint removed (no in-repo consumer); locales pruned to referenced
  keys (pages.xray 331 -> 68) plus the five new settings keys.
This commit is contained in:
Muse
2026-10-22 23:40:54 +00:00
parent 1762e54d5f
commit 277838d7ca
151 changed files with 780 additions and 22140 deletions
+10 -297
View File
@@ -98,9 +98,6 @@
"clients": "Клиенты",
"nodes": "Узлы",
"settings": "Настройки панели",
"xray": "Конфигурации Xray",
"routing": "Маршрутизация",
"outbounds": "Исходящие",
"donate": "Поддержать",
"hosts": "Хосты",
"docs": "Документация",
@@ -272,7 +269,6 @@
"clone": "Клонировать",
"resetAllTraffic": "Сброс трафика всех подключений",
"resetAllTrafficTitle": "Сброс трафика всех подключений",
"resetAllTrafficContent": "Вы уверены, что хотите сбросить трафик всех подключений?",
"email": "Email",
"IPLimit": "Лимит по количеству IP",
"IPLimitlog": "Лог IP-адресов",
@@ -1211,269 +1207,29 @@
"tgNotifyBackup": "Резервное копирование базы данных",
"tgNotifyBackupDesc": "Отправлять уведомление с файлом резервной копии базы данных",
"tgTestFailed": "Тест Telegram не удался",
"tgTestSuccess": "Тестовое сообщение отправлено в Telegram"
"tgTestSuccess": "Тестовое сообщение отправлено в Telegram",
"trafficStatsInboundUplink": "Inbound Upload Accounting",
"trafficStatsInboundDownlink": "Inbound Download Accounting",
"trafficStatsOutboundUplink": "Outbound Upload Accounting",
"trafficStatsOutboundDownlink": "Outbound Download Accounting",
"trafficStatsDesc": "Applies to the whole network. A direction pair (inbound or outbound) is counted only while both of its switches are on. While counting is off, that traffic is never recorded and the gap is permanent — it is not backfilled later — and expiry / over-quota auto-disable loses the data it relies on."
},
"xray": {
"importRules": "Импорт правил",
"exportRules": "Экспорт правил",
"importOutbounds": "Импорт исходящих",
"exportOutbounds": "Экспорт исходящих",
"importInvalidJson": "Некорректный JSON — ожидался массив или объект с подходящим ключом.",
"metricsListen": "Эндпоинт метрик",
"metricsListenDesc": "Публикует метрики Xray в стиле Prometheus по этому адресу:порту (например, 127.0.0.1:11111). Оставьте пустым, чтобы отключить. Привяжите к localhost и проксируйте через reverse-proxy — он без аутентификации.",
"metricsTag": "Тег метрик",
"save": "Сохранить",
"basicTemplate": "Основное",
"advancedTemplate": "Расширенный шаблон",
"generalConfigs": "Основные настройки",
"generalConfigsDesc": "Эти параметры описывают общие настройки",
"logConfigs": "Лог",
"logConfigsDesc": "Логи могут замедлять работу сервера. Включайте только нужные вам виды логов при необходимости!",
"basicRouting": "Базовые соединения",
"blockConnectionsConfigsDesc": "Эти параметры будут блокировать трафик в зависимости от страны назначения.",
"directConnectionsConfigsDesc": "Прямое соединение означает, что определенный трафик не будет перенаправлен через другой сервер.",
"blockips": "Заблокированные IP-адреса",
"blockdomains": "Заблокированные домены",
"directips": "Прямые IP-адреса",
"directdomains": "Прямые домены",
"ipv4Routing": "Правила IPv4",
"ipv4RoutingDesc": "Эти параметры позволят клиентам маршрутизироваться к целевым доменам только через IPv4",
"FreedomStrategy": "Настройка стратегии протокола Freedom",
"FreedomStrategyDesc": "Установка стратегии вывода сети в протоколе Freedom",
"FreedomHappyEyeballs": "Freedom Happy Eyeballs (IPv4/IPv6)",
"FreedomHappyEyeballsDesc": "Двухстековый набор для прямого (freedom) исходящего — полезно на выходных серверах с IPv4 и IPv6.",
"FreedomHappyEyeballsTryDelayDesc": "Миллисекунды перед попыткой другого семейства адресов. 150–250 мс — хорошая отправная точка.",
"RoutingStrategy": "Настройка маршрутизации доменов",
"RoutingStrategyDesc": "Установка общей стратегии маршрутизации разрешения DNS",
"Torrent": "Заблокировать BitTorrent",
"Inbounds": "Входящие",
"Outbounds": "Исходящие",
"Balancers": "Балансировщик",
"balancerTagRequired": "Тег обязателен",
"balancerSelectorRequired": "Выберите хотя бы одно исходящее",
"routeTester": "Тест маршрута",
"routeTesterDesc": "Спросите запущенный Xray, через какой исходящий будет обработано соединение. Трафик не отправляется — решение поступает напрямую от живого движка маршрутизации.",
"routeTesterDest": "Домен или IP",
"routeTesterPort": "Порт",
"routeTesterInbound": "Входящий",
"routeTesterProtocol": "Обнаруженный протокол",
"routeTesterTest": "Тест маршрута",
"routeTesterMatchedOutbound": "Совпавший исходящий",
"routeTesterViaBalancer": "через балансировщик",
"routeTesterDefaultOutbound": "Ни одно правило маршрутизации не совпало — трафик направляется в исходящий по умолчанию (первый).",
"Routings": "Маршрутизация",
"logLevel": "Уровень логов",
"logLevelDesc": "Уровень журнала для журналов ошибок, указывающий информацию, которую необходимо записать.",
"accessLog": "Логи доступа",
"accessLogDesc": "Путь к файлу журнала доступа. Специальное значение «none» отключает логи доступа.",
"errorLog": "Логи ошибок",
"errorLogDesc": "Путь к файлу логов ошибок. Специальное значение «none» отключает логи ошибок.",
"dnsLog": "Логи DNS",
"dnsLogDesc": "Включить логи запросов DNS",
"maskAddress": "Маскировка адреса",
"maskAddressDesc": "При активации реальный IP-адрес заменяется на маскировочный в логах.",
"statistics": "Статистика",
"statsInboundUplink": "Статистика входящего аплинка",
"statsInboundDownlink": "Статистика входящего даунлинка",
"statsOutboundUplink": "Статистика исходящего аплинка",
"statsOutboundDownlink": "Статистика исходящего даунлинка",
"connectionLimits": "Ограничения соединения",
"connectionLimitsDesc": "Политики уровня соединения для пользователей уровня 0. Оставьте поле пустым, чтобы использовать значение Xray по умолчанию.",
"connIdle": "Тайм-аут простоя",
"connIdleDesc": "Закрывает соединение после простоя в течение указанного числа секунд. Уменьшение значения быстрее освобождает память и файловые дескрипторы на нагруженных серверах (по умолчанию в Xray: 300).",
"bufferSize": "Размер буфера",
"bufferSizeDesc": "Размер внутреннего буфера на соединение в КБ. Установите 0, чтобы минимизировать использование памяти на серверах с малым объёмом ОЗУ (значение Xray по умолчанию зависит от платформы).",
"bufferSizePlaceholder": "авто",
"seconds": "секунд",
"rules": {
"source": "Источник",
"dest": "Пункт назначения",
"inbound": "Входящее подключение",
"useComma": "Элементы, разделённые запятыми"
},
"routing": {
"dragToReorder": "Перетащите для изменения порядка"
},
"geoBrowser": {
"title": "Категории geo-баз",
"openTooltip": "Открыть браузер geo-категорий",
"database": "База",
"searchCategory": "Поиск категории",
"searchEntries": "Фильтр внутри категории",
"selectFound": "Отметить найденные",
"selected": "Выбрано {count}",
"clearAll": "Снять всё",
"apply": "Применить",
"emptySelection": "Отметьте категории — они станут токенами правила",
"pickCategory": "Выберите категорию слева, чтобы посмотреть её содержимое",
"noMatches": "Ничего не найдено",
"noFiles": "В каталоге Xray нет geo-баз",
"noFilesHint": "Они появятся после того, как Xray скачает geosite.dat и geoip.dat",
"fileMeta": "{count} категорий · {size} · обновлено {date}",
"entriesCount": "{count} записей",
"subnetsCount": "{count} подсетей",
"shownRange": "Показано {from}–{to} из {total}",
"loadFailed": "Не удалось загрузить geo-базы",
"checkFailed": "Не удалось проверить эти значения по geo-базам",
"parseFailed": "Файл повреждён или это не база geosite/geoip",
"tooLarge": "Слишком большой файл для просмотра",
"unknownCategories": "Нет в базе: {tokens}",
"missingDatabase": "Файла базы нет: {tokens} — добавьте её в разделе Geodata",
"unknownAttribute": "Атрибут не найден, правило ничего не сматчит: {tokens}",
"invalidToken": "Xray не примет такую запись: {tokens}",
"wrongKind": "База не того типа для этого поля: {tokens}"
},
"ruleForm": {
"sourceIps": "IP источника",
"sourcePort": "Порт источника",
"vlessRoute": "VLESS route",
"attributes": "Атрибуты",
"value": "Значение",
"user": "Пользователь",
"userPlaceholder": "Выберите пользователей",
"userEmpty": "Нет доступных пользователей",
"userLoadError": "Не удалось загрузить пользователей",
"inboundTags": "Теги входящих",
"outboundTag": "Тег исходящего",
"balancerTag": "Тег балансировщика",
"balancerTagTooltip": "Направляет трафик через один из настроенных балансировщиков нагрузки"
"inbound": "Входящее подключение"
},
"outboundForm": {
"tagDuplicate": "Тег уже используется другим исходящим",
"tagRequired": "Тег обязателен",
"tagPlaceholder": "уникальный-тег",
"localIpPlaceholder": "локальный IP",
"dialerProxyPlaceholder": "Выберите исходящее для цепочки",
"dialerProxyHint": "Подключайте это исходящее через другое исходящее (по тегу), чтобы построить цепочку прокси. Оставьте пустым для прямого подключения.",
"targetStrategyHint": "Как разрешается домен назначения перед подключением: AsIs (по умолчанию) — отправляется как есть, UseIP… — разрешение с откатом, ForceIP… — требуется успешное разрешение.",
"addressRequired": "Адрес обязателен",
"portRequired": "Порт обязателен",
"optional": "опционально",
"udpOverTcp": "UDP over TCP",
"uotVersion": "Версия UoT",
"inboundTag": "Тег входящего",
"inboundTagPlaceholder": "тег входящего в правилах маршрутизации",
"responseType": "Тип ответа",
"rewriteNetwork": "Переписать сеть",
"unchanged": "(без изменений)",
"unchangedAddress": "(без изменений) напр. 1.1.1.1",
"rules": "Правила",
"ruleN": "Правило {n}",
"action": "Действие",
"redirect": "Redirect",
"finalRules": "Финальные правила",
"overrideXrayPrivateIp": "Переопределить дефолтный блок частных IP в Xray",
"blockDelay": "Задержка блока (мс)",
"reverseSniffing": "Обратный sniffing",
"reserved": "Зарезервировано",
"minUploadInterval": "Мин. интервал загрузки (мс)",
"maxUploadSizeBytes": "Макс. размер загрузки (байт)",
"uplinkChunkSize": "Размер chunk Uplink",
"noGrpcHeader": "Без gRPC-заголовка",
"maxConcurrency": "Макс. параллелизм",
"maxConnections": "Макс. соединений",
"maxReuseTimes": "Макс. повторных использований",
"maxRequestTimes": "Макс. запросов",
"maxReusableSecs": "Макс. секунд повторного использования",
"keepAlivePeriod": "Период keep alive",
"authPassword": "Пароль авторизации",
"visionTestpre": "Vision testpre",
"serverNamePlaceholder": "имя сервера",
"verifyPeerName": "Проверять имя peer",
"pinnedSha256": "Pinned SHA256",
"shortId": "Short ID",
"sockopts": "Sockopts",
"keepAliveInterval": "Интервал keep alive",
"markFwmark": "Mark (fwmark)",
"interface": "Интерфейс",
"proxyProtocol": "Proxy protocol",
"tcpUserTimeoutMs": "TCP user timeout (мс)",
"tcpKeepAliveIdleS": "TCP keep-alive idle (с)"
},
"outbound": {
"tag": "Тег",
"outboundStatus": "Статус исходящего подключения",
"sendThrough": "Отправить через",
"targetStrategy": "Стратегия назначения",
"country": "Страна",
"server": "Сервер",
"city": "Город",
"allCities": "Все города",
"moveToTop": "Переместить наверх"
},
"outboundSub": {
"manage": "Подписки",
"title": "Подписки исходящих",
"remark": "Примечание (необязательно)",
"remarkPlaceholder": "напр. узлы HK",
"url": "URL подписки",
"urlPlaceholder": "https://... (список ссылок в base64)",
"tagPrefix": "Префикс тега",
"tagPrefixPlaceholder": "hk-",
"interval": "Интервал обновления",
"hours": "ч",
"minutes": "мин",
"intervalHint": "По умолчанию 10 минут. Фоновая задача проверяет подписки часто, но каждая подписка обновляется только после того, как пройдёт её собственный интервал.",
"enabled": "Включено",
"allowPrivate": "Разрешить приватные адреса",
"allowPrivateHint": "Разрешить localhost, LAN и приватные IP-адреса для URL этой подписки. По умолчанию отключено в целях безопасности — включайте только для доверенного локального источника.",
"prepend": "Перед ручными исходящими",
"prependHint": "Размещать исходящие этой подписки перед вашими настроенными вручную, чтобы один из них мог стать исходящим по умолчанию.",
"preview": "Предпросмотр",
"previewEmpty": "По этому URL исходящих не найдено.",
"refreshAll": "Обновить все",
"statusOk": "OK",
"toastUpdated": "Подписка обновлена",
"addButton": "Добавить",
"active": "Активные подписки",
"empty": "Подписок пока нет. Добавьте одну выше.",
"colRemark": "Примечание",
"colLastFetch": "Последнее обновление",
"colEnabled": "Включено",
"auto": "авто",
"never": "никогда",
"refreshNow": "Обновить сейчас",
"deleteConfirm": "Удалить эту подписку?",
"restartHint": "После добавления или обновления перезапустите Xray (или дождитесь следующей автоперезагрузки), чтобы исходящие стали активными.",
"fromSubsTitle": "Из подписок исходящих (только для чтения)",
"fromSubsDesc": "Импортировано из ваших активных подписок. Управление ими доступно на панели «Подписки» выше.",
"toastLoadFailed": "Не удалось загрузить подписки",
"toastUrlRequired": "Укажите URL подписки",
"toastAdded": "Подписка добавлена",
"toastAddFailed": "Не удалось добавить подписку",
"toastRefreshed": "Обновлено",
"toastRefreshFailed": "Не удалось обновить",
"toastDeleted": "Удалено",
"toastDeleteFailed": "Не удалось удалить"
},
"pia": {
"menu": "PIA",
"username": "Имя пользователя PIA",
"password": "Пароль PIA",
"account": "Аккаунт",
"region": "Регион",
"allRegions": "Все регионы",
"noServers": "Для выбранной страны серверы не найдены",
"outboundAdded": "Исходящее соединение PIA добавлено",
"outboundUpdated": "Исходящее соединение PIA обновлено",
"addedServers": "Добавленные серверы",
"alreadyAdded": "Этот сервер уже в списке исходящих. Чтобы обновить ключ, нажмите {reset}.",
"provisionFailed": "Не удалось создать исходящее PIA. Попробуйте ещё раз."
},
"observatory": {
"deleteAlsoObservatory": "Это последний балансировщик, использующий Observatory, поэтому он тоже будет удалён.",
"deleteAlsoBurst": "Это последний балансировщик, использующий Burst Observatory, поэтому он тоже будет удалён."
},
"refCleanup": {
"header": "Удаление также обновит маршрутизацию:",
"ruleRemoved": "Правило {label} — удалено (не осталось назначения)",
"ruleModified": "Правило {label} — сохранено (теперь использует {keeps})",
"balancerRemoved": "Балансировщик {tag} — удалён (не осталось целей)"
},
"balancer": {
"balancerStrategy": "Стратегия",
"balancerFallbackCycle": "Невозможно назначить этот балансировщик запасным — это создаст циклическую зависимость.",
"reservedPrefix": "Префикс _bl_ зарезервирован для внутренних loopback-объектов балансеров"
"keepAlivePeriod": "Период keep alive"
},
"wireguard": {
"secretKey": "Секретный ключ",
@@ -1481,7 +1237,6 @@
"subnetIp": "Подсеть",
"subnetCidr": "Маска подсети (CIDR)",
"allowedIPs": "Разрешенные IP-адреса",
"endpoint": "Конечная точка",
"domainStrategy": "Стратегия домена"
},
"amneziawg": {
@@ -1537,48 +1292,7 @@
},
"tun": {
"userLevel": "Уровень пользователя"
},
"nord": {
"accessToken": "Access token",
"privateKey": "Приватный ключ",
"noServers": "Серверов для выбранной страны не найдено",
"noPublicKey": "Выбранный сервер не сообщает публичный ключ NordLynx.",
"outboundAdded": "Исходящий NordVPN добавлен",
"outboundUpdated": "Исходящий NordVPN обновлён"
},
"warp": {
"changeIp": "Сменить IP",
"changeIpSuccess": "IP-адрес WARP успешно изменён!",
"autoUpdateIp": "Автоматическое обновление IP-адреса",
"intervalDays": "Интервал (дни)",
"intervalDesc": "0 — отключить. Автоматически меняет IP-адрес.",
"licenseError": "Не удалось установить лицензию WARP.",
"fetchFirst": "Сначала получите WARP-конфиг.",
"createAccount": "Создать аккаунт WARP",
"accessToken": "Access token",
"deviceId": "ID устройства",
"licenseKey": "Лицензионный ключ",
"privateKey": "Приватный ключ",
"deleteAccount": "Удалить аккаунт",
"settings": "Настройки",
"licenseKeyLabel": "Лицензионный ключ WARP / WARP+",
"key": "Ключ",
"keyPlaceholder": "26-символьный ключ WARP+",
"accountInfo": "Информация об аккаунте",
"deviceName": "Имя устройства",
"deviceModel": "Модель устройства",
"deviceEnabled": "Устройство включено",
"accountType": "Тип аккаунта",
"role": "Роль",
"warpPlusData": "WARP+ data",
"quota": "Квота",
"usage": "Использование",
"addOutbound": "Добавить исходящий"
},
"dns": {},
"fakedns": {},
"defaultOutbound": "Исходящий по умолчанию",
"defaultOutboundDesc": "Трафик без совпадения с правилами маршрутизации идёт через этот исходящий (первый в списке)."
}
},
"hosts": {
"addHost": "Добавить хост",
@@ -1876,6 +1590,5 @@
"chooseClient": "Выберите клиента для входящего подключения {{ .Inbound }}",
"chooseInbound": "Выберите входящее подключение"
}
},
"email": {}
}
}