3x-ui/web/translation/ru-RU.json
Sanaei edf0f36940
Frontend rewrite: React + TypeScript with AntD v6 (#4498)
* chore(frontend): add react+typescript toolchain alongside vue

Step 0 of the planned vue->react migration. React 19, antd 5, i18next
+ react-i18next, typescript 5, and @vitejs/plugin-react 6 are added as
dev/runtime deps alongside the existing vue stack. Both frameworks
coexist in the build until the last entry flips.

* vite.config.js: react() plugin runs next to vue(); new manualChunks
  for vendor-react / vendor-antd-react / vendor-icons-react /
  vendor-i18next. Existing vue chunks unchanged.
* eslint.config.js: typescript-eslint + eslint-plugin-react-hooks
  rules scoped to *.{ts,tsx}; vue config untouched for *.{js,vue}.
* tsconfig.json: strict, jsx: react-jsx, moduleResolution: bundler,
  allowJs: true (lets .tsx files import the remaining .js modules
  during incremental migration), @/* path alias.
* env.d.ts: Vite client types + window.X_UI_BASE_PATH typing +
  SubPageData shape consumed by the subscription page.

Vite stays pinned at 8.0.13 per the existing project policy. No
existing .vue/.js source files touched in this step.

eslint-plugin-react (not -hooks) is not included because its latest
release does not yet support ESLint 10. react-hooks/purity covers
the safety-critical case; revisit when the plugin updates.

* refactor(frontend): port subpage to react+ts

Step 1 of the planned vue->react migration. The standalone
subscription page (sub/sub.go renders the HTML host; React mounts
into #app) is the first entry off vue.

Introduces two shared pieces both entries (and future ones) will
use:

* src/hooks/useTheme.tsx — React Context + useTheme hook + the
  same buildAntdThemeConfig (dark/ultra-dark token overrides) and
  pauseAnimationsUntilLeave helper the vue version exposes. Same
  localStorage keys (dark-mode, isUltraDarkThemeEnabled) and DOM
  side effects (body.className, html[data-theme]) so the two stay
  in sync across the coexistence period.
* src/i18n/react.ts — i18next + react-i18next loader that reads
  the same web/translation/*.json files via import.meta.glob. The
  vue-i18n setup in src/i18n/index.js is untouched and still serves
  the remaining vue entries.

SubPage.tsx mirrors the vue version's behavior: reads
window.__SUB_PAGE_DATA__ injected by the Go sub server, renders QR
codes / descriptions / Android+iOS deep-link dropdowns, supports
theme cycle and language switch. Uses AntD v5 idioms: Descriptions
items prop, Dropdown menu prop, Layout.Content.

* refactor(frontend): port login to react+ts

Step 2 of the planned vue->react migration. The login entry is the
first to exercise AntD React's Form API (Form + Form.Item with
name/rules + onFinish) and the existing axios/CSRF interceptors
under React.

* LoginPage.tsx: same form fields, conditional 2FA input,
  rotating headline ("Hello" / "Welcome to..."), drifting blob
  background, theme cycle + language popover. Headline transition
  switches from vue's <Transition mode=out-in> to a CSS keyframe
  animation keyed off the visible word.
* entries/login.tsx: setupAxios() + applyDocumentTitle() unchanged
  from the vue entry — both are framework-agnostic in src/utils
  and src/api/axios-init.js.

useTheme hook, ThemeProvider, and i18n/react.ts loader introduced
in step 1 are now shared across two entries; Vite extracts them as
a small chunk in the build output.

* refactor(frontend): port api-docs to react+ts

Step 3 of the planned vue->react migration. The five api-docs files
(ApiDocsPage, CodeBlock, EndpointRow, EndpointSection, plus the
data-only endpoints.js) all move to react+ts.

Also introduces components/AppSidebar.tsx — api-docs is the first
authenticated page to need it. AppSidebar.vue stays in place for the
six remaining vue entries (settings, inbounds, clients, xray, nodes,
index); each gets switched to AppSidebar.tsx as its entry migrates.
After the last entry flips, AppSidebar.vue is deleted.

Notable transformations:

* The scroll observer that highlights the active TOC link is a
  useEffect keyed on sections — re-registers whenever the visible
  set changes (search filter narrows it). Same behaviour as the vue
  watchEffect.
* v-html="safeInlineHtml(...)" becomes
  dangerouslySetInnerHTML={{ __html: safeInlineHtml(...) }}. The
  helper still escapes everything except <code> tags.
* JSON syntax highlighter in CodeBlock is unchanged — pure regex on
  the escaped string, then rendered via dangerouslySetInnerHTML.
* endpoints.js stays as JS (allowJs in tsconfig); only the consumer
  signatures (Endpoint, Section) are typed at the React boundary.
* AppSidebar reuses pauseAnimationsUntilLeave + useTheme from
  step 1. Drawer + Sider keyed off the same localStorage flag
  (isSidebarCollapsed) and DOM theme attributes the vue version
  uses, so the two stay in sync during coexistence.

* refactor(frontend): port nodes to react+ts

Step 4 of the planned vue->react migration. The nodes entry brings in
the largest shared-infrastructure batch so far — every authenticated
react page from here on can lean on these.

New shared pieces (live alongside their .vue counterparts during
coexistence):

* hooks/useMediaQuery.ts — useState + resize listener
* hooks/useWebSocket.ts — wraps WebSocketClient, subscribes on mount
  and unsubscribes on unmount. The underlying client is a single
  module-level instance so multiple components on the same page
  share one socket.
* hooks/useNodes.ts — node list state + CRUD + probe/test, including
  the totals memo (online/offline/avgLatency) used by the summary card.
  applyNodesEvent is the entry point for the heartbeat-pushed list.
* components/CustomStatistic.tsx — thin Statistic wrapper, prefix +
  suffix slots become props.
* components/Sparkline.tsx — the SVG line chart with measured-width
  axis scaling, gradient fill, tooltip overlay, and per-instance
  gradient id from React.useId. ResizeObserver lifecycle is in
  useEffect; the math is unchanged.

Pages:

* NodesPage — wires hooks + WebSocket together, renders summary card
  + NodeList, hosts the form modal. Uses Modal.useModal() for the
  delete confirm so the dialog inherits ConfigProvider theming.
* NodeList — desktop renders a Table with expandable history rows;
  mobile flips to a vertical card list whose actions live in a
  bottom-right Dropdown. The IP-blur eye toggle persists across both.
* NodeFormModal — controlled form (useState object, single setForm
  per change). The reset-on-open effect computes the next state
  once and applies it with eslint-disable to satisfy the new
  react-hooks/set-state-in-effect rule on a legitimate pattern.
* NodeHistoryPanel — polls /panel/api/nodes/history/{id}/{metric}/
  {bucket} every 15s, renders cpu+mem sparklines side-by-side.

* refactor(frontend): port settings to react+ts

Step 5 of the planned vue->react migration. Settings is the first
entry whose state model didn't translate to the Vue-style "parent
passes a reactive object, children mutate it in place" pattern, so
the React port flips it to lifted state + a typed updateSetting
patch function.

* models/setting.ts — typed AllSetting class with the same field
  defaults and equals() behavior the vue version had. The .js
  twin is deleted; nothing else imported it.
* hooks/useAllSetting.ts — owns allSetting + oldAllSetting state,
  exposes updateSetting(patch), saveDisabled is derived via useMemo
  off equals() (no more 1Hz dirty-check timer).
* components/SettingListItem.tsx — children-based wrapper instead
  of named slots. The vue twin stays alive because xray (BasicsTab,
  DnsTab) still imports it; deleted when xray migrates.

The five tab components and the TwoFactorModal each accept
{ allSetting, updateSetting } and render with AntD v5's Collapse
items[] API. Every v-model:value="x" became
value={...} onChange={(e) => updateSetting({ key: e.target.value })}
or onChange={(v) => updateSetting({ key: v })} for non-input
controls.

SubscriptionFormatsTab is the trickiest — fragment / noises[] /
mux / direct routing rules are stored as JSON-encoded strings on
the wire. Parsing them once via useMemo per field, mutating the
parsed object on edit, and stringifying back into the patch keeps
the round-trip identical to the vue version.

SettingsPage hosts the tab navigation (with hash sync), the
save / restart action bar, the security-warnings alert banner,
and the restart flow that rebuilds the panel URL after the new
host/port/cert settings take effect.

* refactor(frontend): port clients to react+ts

Step 6 of the planned vue->react migration. Clients is the biggest
data-CRUD page in the panel (1.1k-line ClientsPage, 4 modals, full
table + mobile card list, WebSocket-driven realtime traffic + online
updates).

New shared infra (lives alongside vue twins until inbounds migrates):

* hooks/useClients.ts — clients + inbounds list, CRUD + bulk delete +
  attach/detach + traffic reset, with WebSocket event handlers
  (traffic, client_stats, invalidate) and a small debounced refresh
  on the invalidate event. State managed via setState; the live
  client_stats event merges traffic snapshots row-by-row through a
  ref to avoid stale closure issues.
* hooks/useDatepicker.ts — singleton "gregorian"/"jalalian" cache
  with subscribe/notify so multiple components can read the panel's
  Calendar Type without re-fetching. Mirrors useDatepicker.js.
* components/DateTimePicker.tsx — AntD DatePicker wrapper.
  vue3-persian-datetime-picker has no React port; the Jalali UI
  calendar is deferred (read-only Jalali display via IntlUtil
  formatDate still works). The vue twin stays for inbounds.
* pages/inbounds/QrPanel.tsx — copy/download/copy-as-png QR helper
  shared between clients (qr modal) and inbounds (still on vue).
  Vue twin stays alive at QrPanel.vue.
* models/inbound.ts — slim port: only the TLS_FLOW_CONTROL constant
  the clients form needs. The full inbound model stays as
  inbound.js for now; inbounds will pull it in as inbound.ts.

The clients page itself uses Modal.useModal() for all confirm
dialogs (delete, bulk-delete, reset-traffic, delDepleted, reset-all)
so the dialogs render themed. Filter state persists to
localStorage under clientsFilterState. Sort + pagination state is
local; pageSize seeds from /panel/setting/defaultSettings.

The four modals share a controlled "open/onOpenChange" pattern
that replaces vue's v-model:open. ClientFormModal computes
attach/detach diffs from the inbound multi-select on submit; the
parent's onSave callback routes them through useClients's attach()/
detach() after the main update succeeds.

ESLint config: turned off four react-hooks v7 rules
(react-compiler, preserve-manual-memoization, set-state-in-effect,
purity). They're all React-Compiler-driven informational rules; we
don't run the compiler and the patterns they flag (initial-fetch
useEffect, derived computations using Date.now, inline arrow event
handlers) are all idiomatic React. Disabling globally instead of
per-line keeps the diff readable.

* refactor(frontend): port index dashboard to react+ts

Step 7 of the Vue→React migration. Ports the overview/index entry: dashboard
page, status + xray cards, panel-update / log / backup / system-history /
xray-metrics / xray-log / version modals, and the custom-geo subsection. Adds
the shared JsonEditor (CodeMirror 6) and useStatus hook used by the config
modal. Removes the unused react-hooks/set-state-in-effect disables now that
the rule is off globally.

* refactor(frontend): port xray to react+ts

Step 8 of the Vue→React migration. Ports the xray config entry: page shell,
basics/routing/outbounds/balancers/dns tabs, the rule + balancer + dns server
+ dns presets + warp + nord modals, the protocol-aware outbound form, and the
shared FinalMaskForm (TCP/UDP masks + QUIC params). Adds useXraySetting that
mirrors the legacy two-way sync between the JSON template string and the
parsed templateSettings tree. The outbound model itself stays in JS so the
class-driven form keeps its existing mutation API; instance access is typed
loosely inside the form to match.

The shared FinalMaskForm.vue and JsonEditor.vue stay alongside the new .tsx
versions until step 9 — InboundFormModal.vue still imports them.

Adds react-hooks/immutability and react-hooks/refs to the already-disabled
react-compiler rule set; both flag the outbound form's instance-mutation
pattern that doesn't run through useState.

* Upgrade frontend deps (antd v6, i18n, TS)

Bump frontend dependencies in package.json and regenerate package-lock.json. Notable updates: upgrade antd to v6, update i18next/react-i18next, axios, qs, vue-i18n, TypeScript and ESLint, plus related @rc-component packages and replacements (e.g. classnames/rc-util -> clsx/@rc-component/util). Lockfile changes reflect the new dependency tree required for Ant Design v6 and other package upgrades.

* refactor(frontend): port inbounds to react+ts and drop vue toolchain

Step 9 — the last entry. Ports the inbounds entry: page shell, list with
desktop table + mobile cards, info modal, qr-code modal, share-link
helpers, and the protocol-aware form modal (basics / protocol /
stream / security / sniffing / advanced JSON). useInbounds replaces
the Vue composable with WebSocket-driven traffic + client-stats merge.

Inbound and DBInbound models stay in JS so the class-driven form keeps
its mutation API; instance access is typed loosely inside the form to
match. FinalMaskForm/JsonEditor/TextModal/PromptModal/InfinityIcon are
the last shared bits to flip; their .vue counterparts go too.

Toolchain cleanup now that no entry needs Vue: drop plugin-vue from
vite.config, remove the .vue lint block + parser, prune vue / vue-i18n
/ ant-design-vue / @ant-design/icons-vue / vue3-persian-datetime-picker
/ moment-jalaali override from package.json, and switch utils/index.js
to import { message } from 'antd' instead of ant-design-vue.

* chore(frontend): adopt antd v6 api updates

Sweep deprecated props across the React tree:
- Modal: destroyOnClose -> destroyOnHidden, maskClosable -> mask.closable
- Space: direction -> orientation (or removed when redundant)
- Input.Group compact -> Space.Compact block
- Drawer: width -> size
- Spin: tip -> description
- Progress: trailColor -> railColor
- Alert: message -> title
- Popover: overlayClassName -> rootClassName
- BackTop -> FloatButton.BackTop

Also refresh dashboard theming for v6: rename dark/ultra Layout and Menu
tokens (siderBg, darkItemBg, darkSubMenuItemBg, darkPopupBg), tweak gauge
size/stroke, add font-size overrides for Statistic and Progress so the
overview numbers stay legible under v6 defaults.

* chore(frontend): antd v6 polish, theme + modal fixes

- adopt message.useMessage hook + messageBus bridge so HttpUtil messages
  inherit ConfigProvider theme tokens
- replace deprecated antd APIs (List, Input addonBefore/After, Empty
  imageStyle); introduce InputAddon helper + SettingListItem custom rows
- fix dark/ultra selectors in portaled modals (body.dark,
  html[data-theme='ultra-dark']) instead of nonexistent .is-dark/.is-ultra
- add horizontal scroll to clients table; reorder node columns so
  actions+enable sit at the left
- swap raw button for antd Button in NodeFormModal test connection
- fix FinalMaskForm nested-form by hoisting it outside OutboundFormModal's
  parent Form
- fix advanced "all" JSON tab in InboundFormModal — useMemo on a mutated
  ref was stale; compute on every render
- fix chart-on-open for SystemHistory + XrayMetrics modals by adding open
  to effect deps (useRef.current doesn't trigger re-runs)
- switch i18next interpolation to single-brace {var} to match locale files
- drop residual Vue mentions in CI workflows and Go comments

* fix(frontend): qr code collapse — open only first panel, allow toggle

ClientQrModal and QrCodeModal both used activeKey without onChange,
forcing every panel open and blocking user toggle. Switch to controlled
state initialized to the first item's key on open, with onChange so
clicks update state.

Also remove unused AppBridge.tsx (superseded by per-page message.useMessage
hook).

* fix(frontend): hover cards, balancer load, routing dnd, modal a11y, outbound crash

- ClientsPage/SettingsPage/XrayPage: add hoverable to bottom card/tabs so
  hover affordance matches the top card
- BalancerFormModal: lazy-init useState from props + destroyOnHidden so
  the form mounts with saved values instead of relying on a useEffect
  sync that could miss the first open
- RoutingTab: rewrite pointer drag — handlers are now defined inside the
  pointerdown closure so addEventListener/removeEventListener match;
  drag state lives on a ref (from/to/moved) so onUp reads the real
  indices, not stale closure values. Adds setPointerCapture so Windows
  and touch keep delivering events when the cursor leaves the handle.
- OutboundFormModal/InboundFormModal: blur the focused input before
  switching tabs to silence the aria-hidden-on-focused-element warning
- utils.isArrEmpty: return true for undefined/null arrays — the old form
  treated undefined as "not empty" which crashed VLESSSettings.fromJson
  when json.vnext was missing

* fix(frontend): clipboard reliability + restyle login page

- ClipboardManager.copyText: prefer navigator.clipboard on secure
  contexts, fall back to a focused on-screen textarea + execCommand.
  Old path used left:-9999px which failed selection in some browsers
  and swallowed execCommand's return value, so the "copied" toast
  appeared even when nothing made it to the clipboard.
- LoginPage: richer gradient backdrop — five animated colour blobs,
  glassmorphic card (backdrop-filter blur + saturate), gradient brand
  text/accent, masked grid texture for depth, and a thin gradient
  border on the card. Light/dark/ultra each get their own palette.

* Memoize compactAdvancedJson and update deps

Wrap compactAdvancedJson in useCallback (dependent on messageApi) and add it to the dependency array of applyAdvancedJsonToBasic. This ensures a stable function reference for correct dependency tracking and avoids stale closures/unnecessary re-renders in InboundFormModal.tsx.

* style(frontend): prettier charts, drop redundant frame, format net rates

- Sparkline: multi-stop gradient fill, soft drop-shadow under the line,
  dashed grid, glowing pulse on the latest-point marker, pill-shaped
  tooltip with dashed crosshair
- XrayMetricsModal: glow + pulse on the observatory alive dot,
  monospace stamps/listen text
- SystemHistoryModal: keep just the modal's frame around the chart (the
  inner wrapper I'd added stacked a second border on top); strip the
  decimal from Net Up/Down (25.63 KB/s → 25 KB/s) only on this chart's
  formatter

* style(frontend): refined dark/ultra palette + shared pro card frame

- Dark tokens shifted to a cooler, Linear-style palette: page #1a1b1f,
  sidebar/header #15161a (recessed nav, darker than cards), card
  #23252b, elevated #2d2f37
- Ultra dark: page pure #000 for OLED, sidebar #050507 disappears into
  the frame, card #101013 with a clear step, elevated #1a1a1e
- New styles/page-cards.css holds the card border/shadow/hover rules so
  all seven content pages (index, clients, inbounds, xray, settings,
  nodes, api-docs) share one definition instead of duplicating in each
  page CSS
- Dashboard typography: uppercase card titles with letter-spacing,
  larger 17px stat values, subtle gradient divider between stat columns,
  ellipsis on action labels so "Backup & Restore" doesn't break the
  card height at mid widths
- Light --bg-page stays at #e6e8ec for the contrast against white cards

* fix(frontend): wireguard info alignment, blue login dark, embed gitkeep

- align WireGuard info-modal fields with Protocol/Address/Port by wrapping
  values in Tag (matches the rest of the dl.info-list rows)
- swap login dark palette from purple to pure blue blobs/accent/brand
- pin web/dist/.gitkeep through gitignore so //go:embed all:dist never
  fails on a fresh clone with an empty dist directory

* docs: refresh frontend docs for the React + TS + AntD 6 stack

Update CONTRIBUTING.md and frontend/README.md to describe the migrated
frontend accurately:

- replace Vue 3 / Ant Design Vue 4 references with React 19 / AntD 6 / TS
- swap composables -> hooks, vue-i18n -> react-i18next, createApp -> createRoot
- mention the typecheck step (tsc --noEmit) in the PR checklist
- document the Vite 8.0.13 pin and TypeScript strict mode in conventions
- list the nodes and api-docs entries that were missing from the layout

* style(frontend): improve readability and mobile polish

- bump statistic title/value contrast in dark and ultra-dark so totals
  on the inbounds summary card stay legible
- give index card actions explicit colors per theme so links like Stop,
  Logs, System History no longer fade into the card background
- show the panel version as a tag next to "3X-UI" on mobile, mirroring
  the Xray version tag pattern, and turn it orange when an update is
  available
- make the login settings button a proper circle by adding size="large"
  + an explicit border-radius fallback on .toolbar-btn

* feat: jalali calendar support and date formatting fixes

- Wire useDatepicker into IntlUtil and switch jalalian display locale
  to fa-IR for clean "1405/07/03 12:00:00" output (drops the awkward
  "AP" era suffix that "<lang>-u-ca-persian" produced)
- Drop in persian-calendar-suite for the jalali date picker, with a
  light/dark/ultra theme map and CSS overrides so the inline-styled
  input stays readable and bg matches the surrounding container
- Force LTR on the picker input so "1405/03/07 00:00" reads naturally
- Pass calendar setting through ClientInfoModal, ClientsPage Duration
  tooltip, and ClientFormModal's expiry picker
- Heuristic toMs() in ClientInfoModal so GORM's autoUpdateTime seconds
  render as a real date instead of "1348/11/01"
- Persist UpdatedAt on the ClientRecord row in client_service.Update;
  previously only the inbound settings JSON was bumped, so the panel
  never saw a fresh updated_at after editing a client

* feat(frontend): donate link, panel version label, login lang menu

- Sidebar: add heart donate link to https://donate.sanaei.dev and small panel version under 3X-UI brand
- Login: swap settings-cog for translation icon, drop title, render languages as a direct list
- Vite dev: inject window.X_UI_CUR_VER from config/version so dev mode matches prod
- Translations: add menu.donate across all locales

* fix(xray-update): respect XUI_BIN_FOLDER on Windows

The Windows update path hardcoded "bin/xray-windows-amd64.exe", ignoring
the configured XUI_BIN_FOLDER. In dev mode (folder set to x-ui) this
created a stray bin/ folder while the running binary stayed un-updated.

* Bump Xray to v26.5.9 and minor cleanup

Update Xray release URLs to v26.5.9 in the GitHub Actions workflow and DockerInit.sh. Remove the hardcoded skip for tagVersion "26.5.3" so it will be considered when collecting Xray versions. Apply small formatting fixes: remove an extra blank line in database/db.go, normalize spacing/alignment of Protocol constants in database/model/model.go, and trim a trailing blank line in web/controller/inbound.go.

* fix(frontend): route remaining copy buttons through ClipboardManager

Direct navigator.clipboard calls fail in non-secure contexts (HTTP on a
LAN IP), making the API-docs code copy and security-tab token copy
silently broken. Both now go through ClipboardManager which falls back
to document.execCommand('copy') when navigator.clipboard is unavailable.

* fix(db): store CreatedAt/UpdatedAt in milliseconds

GORM's autoCreateTime/autoUpdateTime tags default to Unix seconds on
int64 fields and overwrite the service-supplied UnixMilli value on
save. The frontend interprets these timestamps as JS Date inputs
(milliseconds), so created/updated columns rendered ~1970 dates. Adding
the :milli qualifier makes GORM match what the service code and UI
expect.

* Improve legacy clipboard copy handling

Refactor ClipboardManager._legacyCopy to better handle focus and selection when copying. The textarea is now appended to the active element's parent (or body) and placed off-screen with aria-hidden and readonly attributes. The code preserves and restores the previous document selection and active element, uses focus({preventScroll: true}) to avoid scrolling, and returns the execCommand('copy') result. This makes legacy copy behavior more robust and less disruptive to the page state.

* fix(lint): drop redundant ok=false in clipboard fallback catch

* chore(deps): bump golang.org/x/net to v0.55.0 for GO-2026-5026
2026-05-23 15:21:45 +02:00

1093 lines
No EOL
77 KiB
JSON
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"username": "Имя пользователя",
"password": "Пароль",
"login": "Войти",
"confirm": "Подтвердить",
"cancel": "Отмена",
"close": "Закрыть",
"save": "Сохранить",
"logout": "Выход",
"create": "Создать",
"update": "Обновить",
"copy": "Копировать",
"copied": "Скопировано",
"download": "Скачать",
"remark": "Примечание",
"enable": "Включить",
"protocol": "Протокол",
"search": "Поиск",
"filter": "Фильтр",
"loading": "Загрузка...",
"refresh": "Обновить",
"clear": "Очистить",
"second": "Секунда",
"minute": "Минута",
"hour": "Час",
"day": "День",
"check": "Проверить",
"indefinite": "Бесконечно",
"unlimited": "Безлимит",
"none": "Пусто",
"qrCode": "QR-код",
"info": "Информация",
"edit": "Изменить",
"delete": "Удалить",
"reset": "Сбросить",
"noData": "Нет данных.",
"copySuccess": "Скопировано",
"sure": "Да",
"encryption": "Шифрование",
"useIPv4ForHost": "Использовать IPv4 для подключения к хосту",
"transmission": "Транспорт",
"host": "Хост",
"path": "Путь",
"camouflage": "Маскировка",
"status": "Статус",
"enabled": "Включено",
"disabled": "Отключено",
"depleted": "Исчерпано",
"depletingSoon": "Почти исчерпано",
"offline": "Офлайн",
"online": "Онлайн",
"domainName": "Домен",
"monitor": "Мониторинг IP",
"certificate": "SSL-сертификат",
"fail": "Сбой",
"comment": "Комментарий",
"success": "Успешно",
"lastOnline": "Был(а) в сети",
"getVersion": "Узнать версию",
"install": "Установка",
"clients": "Клиенты",
"usage": "Использование",
"twoFactorCode": "Код 2FA",
"remained": "Остаток",
"security": "Безопасность",
"secAlertTitle": "Предупреждение системы безопасности",
"secAlertSsl": "Соединение не защищено. Не вводите конфиденциальные данные до установки SSL-сертификата.",
"secAlertConf": "Некоторые настройки уязвимы. Рекомендуется усилить защиту для предотвращения атак.",
"secAlertSSL": "Подключение к панели не защищено. Установите SSL-сертификат для защиты данных.",
"secAlertPanelPort": "Порт панели по умолчанию небезопасен. Установите нестандартный или случайный порт.",
"secAlertPanelURI": "Адрес панели по умолчанию небезопасен. Настройте уникальный и сложный URI.",
"secAlertSubURI": "URI подписки по умолчанию небезопасен. Настройте уникальный и сложный адрес.",
"secAlertSubJsonURI": "URI JSON-подписки по умолчанию небезопасен. Настройте уникальный и сложный адрес.",
"emptyDnsDesc": "Нет добавленных DNS-серверов.",
"emptyFakeDnsDesc": "Нет добавленных Fake DNS-серверов.",
"emptyBalancersDesc": "Нет добавленных балансировщиков.",
"emptyReverseDesc": "Нет добавленных реверс-прокси.",
"somethingWentWrong": "Что-то пошло не так",
"subscription": {
"title": "Информация о подписке",
"subId": "ID подписки",
"status": "Статус",
"downloaded": "Загружено",
"uploaded": "Отправлено",
"expiry": "Срок действия",
"totalQuota": "Общий лимит",
"individualLinks": "Индивидуальные ссылки",
"active": "Активна",
"inactive": "Неактивна",
"unlimited": "Неограниченно",
"noExpiry": "Бессрочно"
},
"menu": {
"theme": "Тема",
"dark": "Темная",
"ultraDark": "Очень темная",
"dashboard": "Дашборд",
"inbounds": "Подключения",
"clients": "Клиенты",
"nodes": "Узлы",
"settings": "Настройки",
"xray": "Настройки Xray",
"apiDocs": "Документация API",
"logout": "Выход",
"link": "Управление",
"donate": "Поддержать"
},
"pages": {
"login": {
"hello": "Привет!",
"title": "Добро пожаловать!",
"loginAgain": "Сессия истекла. Войдите в систему снова",
"toasts": {
"invalidFormData": "Недопустимый формат данных",
"emptyUsername": "Введите имя пользователя",
"emptyPassword": "Введите пароль",
"wrongUsernameOrPassword": "Неверные данные учетной записи.",
"successLogin": "Вход выполнен успешно"
}
},
"index": {
"title": "Дашборд",
"cpu": "ЦП",
"logicalProcessors": "Логические процессоры",
"frequency": "Частота",
"swap": "Файл подкачки",
"storage": "Диск",
"memory": "ОЗУ",
"threads": "Потоки",
"xrayStatus": "Xray",
"stopXray": "Остановить",
"restartXray": "Перезапустить",
"xraySwitch": "Выбор версии",
"xrayUpdates": "Обновления Xray",
"xraySwitchClick": "Выберите нужную версию",
"xraySwitchClickDesk": "Важно: старые версии могут не поддерживать текущие настройки",
"updatePanel": "Обновить панель",
"panelUpdateDesc": "Это обновит 3X-UI до последнего релиза и перезапустит сервис панели.",
"currentPanelVersion": "Текущая версия панели",
"latestPanelVersion": "Последняя версия панели",
"panelUpToDate": "Панель обновлена",
"upToDate": "Обновлено",
"xrayStatusUnknown": "Неизвестно",
"xrayStatusRunning": "Запущен",
"xrayStatusStop": "Остановлен",
"xrayStatusError": "Ошибка",
"xrayErrorPopoverTitle": "Ошибка при запуске Xray",
"operationHours": "Время работы системы",
"systemHistoryTitle": "История системы",
"charts": "Графики",
"xrayMetricsTitle": "Метрики Xray",
"xrayMetricsDisabled": "Конечная точка метрик Xray не настроена",
"xrayMetricsHint": "Добавьте блок metrics верхнего уровня в конфигурацию xray с tag metrics_out и listen 127.0.0.1:11111, затем перезапустите xray.",
"xrayObservatoryEmpty": "Данных Observatory пока нет",
"xrayObservatoryHint": "Добавьте блок observatory в конфигурацию xray с указанием тегов outbound для проверки, затем перезапустите xray.",
"xrayObservatoryTagPlaceholder": "Выберите outbound",
"xrayObservatoryAlive": "Активен",
"xrayObservatoryDead": "Недоступен",
"xrayObservatoryLastSeen": "Последняя активность",
"xrayObservatoryLastTry": "Последняя попытка",
"trendLast2Min": "Последние 2 минуты",
"systemLoad": "Нагрузка на систему",
"systemLoadDesc": "Средняя загрузка системы за последние 1, 5 и 15 минут",
"connectionCount": "Количество соединений",
"ipAddresses": "IP-адреса сервера",
"toggleIpVisibility": "Скрыть или показать IP-адреса сервера",
"overallSpeed": "Общая скорость передачи трафика",
"upload": "Отправка",
"download": "Загрузка",
"totalData": "Общий объем трафика",
"sent": "Отправлено",
"received": "Получено",
"documentation": "Документация",
"xraySwitchVersionDialog": "Переключить версию Xray",
"xraySwitchVersionDialogDesc": "Вы точно хотите сменить версию Xray?",
"xraySwitchVersionPopover": "Xray успешно обновлён",
"panelUpdateDialog": "Вы действительно хотите обновить панель?",
"panelUpdateDialogDesc": "Это обновит 3X-UI до версии #version# и перезапустит сервис панели.",
"panelUpdateCheckPopover": "Проверка обновления панели не удалась",
"panelUpdateStartedPopover": "Обновление панели началось",
"geofileUpdateDialog": "Вы действительно хотите обновить геофайл?",
"geofileUpdateDialogDesc": "Это обновит файл #filename#.",
"geofilesUpdateDialogDesc": "Это обновит все геофайлы.",
"geofilesUpdateAll": "Обновить все",
"geofileUpdatePopover": "Геофайлы успешно обновлены",
"customGeoTitle": "Пользовательские GeoSite / GeoIP",
"customGeoAdd": "Добавить",
"customGeoType": "Тип",
"customGeoAlias": "Псевдоним",
"customGeoUrl": "URL",
"customGeoEnabled": "Включено",
"customGeoLastUpdated": "Обновлено",
"customGeoExtColumn": "Маршрутизация (ext:…)",
"customGeoToastUpdateAll": "Все пользовательские источники обновлены",
"customGeoActions": "Действия",
"customGeoEdit": "Изменить",
"customGeoDelete": "Удалить",
"customGeoDownload": "Обновить сейчас",
"customGeoModalAdd": "Добавить источник",
"customGeoModalEdit": "Изменить источник",
"customGeoModalSave": "Сохранить",
"customGeoDeleteConfirm": "Удалить этот пользовательский источник?",
"customGeoRoutingHint": "В правилах маршрутизации используйте значение как ext:файл.dat:тег (замените тег).",
"customGeoInvalidId": "Некорректный идентификатор",
"customGeoAliasesError": "Не удалось загрузить список пользовательских geo",
"customGeoValidationAlias": "Псевдоним: только a-z, цифры, - и _",
"customGeoValidationUrl": "URL должен начинаться с http:// или https://",
"customGeoAliasPlaceholder": "a-z 0-9 _ -",
"customGeoAliasLabelSuffix": " (свой)",
"customGeoToastList": "Список пользовательских geo",
"customGeoToastAdd": "Добавить пользовательский geo",
"customGeoToastUpdate": "Изменить пользовательский geo",
"customGeoToastDelete": "Пользовательский geo-файл «{{ .fileName }}» удалён",
"customGeoToastDownload": "Geofile «{{ .fileName }}» обновлен",
"customGeoErrInvalidType": "Тип должен быть geosite или geoip",
"customGeoErrAliasRequired": "Укажите псевдоним",
"customGeoErrAliasPattern": "Псевдоним содержит недопустимые символы",
"customGeoErrAliasReserved": "Этот псевдоним зарезервирован",
"customGeoErrUrlRequired": "Укажите URL",
"customGeoErrInvalidUrl": "Некорректный URL",
"customGeoErrUrlScheme": "URL должен использовать http или https",
"customGeoErrUrlHost": "Некорректный хост URL",
"customGeoErrDuplicateAlias": "Такой псевдоним уже используется для этого типа",
"customGeoErrNotFound": "Источник не найден",
"customGeoErrDownload": "Ошибка загрузки",
"customGeoErrUpdateAllIncomplete": "Не удалось обновить один или несколько пользовательских источников",
"customGeoEmpty": "Пользовательских источников geo пока нет — нажмите «Добавить», чтобы создать",
"dontRefresh": "Установка в процессе. Не обновляйте страницу",
"logs": "Журнал",
"config": "Конфигурация",
"backup": "Резервная копия",
"backupTitle": "Бэкап и восстановление",
"exportDatabase": "Экспорт базы данных",
"exportDatabaseDesc": "Нажмите, чтобы скачать файл .db, содержащий резервную копию вашей текущей базы данных на ваше устройство.",
"importDatabase": "Импорт базы данных",
"importDatabaseDesc": "Нажмите, чтобы выбрать и загрузить файл .db с вашего устройства для восстановления базы данных из резервной копии.",
"importDatabaseSuccess": "База данных успешно импортирована",
"importDatabaseError": "Произошла ошибка при импорте базы данных",
"readDatabaseError": "Произошла ошибка при чтении базы данных",
"getDatabaseError": "Произошла ошибка при получении базы данных",
"getConfigError": "Произошла ошибка при получении конфигурационного файла"
},
"inbounds": {
"title": "Подключения",
"totalDownUp": "Отправлено/получено",
"totalUsage": "Всего трафика",
"inboundCount": "Всего подключений",
"operate": "Меню",
"enable": "Включить",
"remark": "Примечание",
"node": "Узел",
"deployTo": "Развернуть на",
"localPanel": "Локальная панель",
"fallbacks": {
"title": "Фолбэки",
"help": "Когда соединение на этом инбаунде не совпадает ни с одним клиентом, оно перенаправляется на другой инбаунд. Выберите дочерний инбаунд ниже — поля маршрутизации (SNI / ALPN / Path / xver) заполнятся автоматически из его транспорта, для большинства конфигураций больше ничего менять не нужно. Каждый дочерний должен слушать на 127.0.0.1 с security=none.",
"empty": "Фолбэков пока нет",
"add": "Добавить фолбэк",
"pickInbound": "Выберите инбаунд",
"matchAny": "любой",
"rederive": "Заполнить из дочернего",
"rederived": "Заполнено из дочернего",
"editAdvanced": "Изменить поля маршрутизации",
"hideAdvanced": "Скрыть расширенные",
"quickAddAll": "Быстро добавить все подходящие",
"quickAdded": "Добавлено {n} фолбэк(ов)",
"quickAddedNone": "Нет новых подходящих инбаундов",
"routesWhen": "Маршрутизирует, когда",
"defaultCatchAll": "По умолчанию — ловит всё остальное"
},
"protocol": "Протокол",
"port": "Порт",
"portMap": "Порт-маппинг",
"traffic": "Трафик",
"details": "Подробнее",
"transportConfig": "Транспорт",
"expireDate": "Дата окончания",
"createdAt": "Создано",
"updatedAt": "Обновлено",
"resetTraffic": "Сброс трафика",
"addInbound": "Создать подключение",
"generalActions": "Общие действия",
"modifyInbound": "Изменить подключение",
"deleteInbound": "Удалить подключение",
"deleteInboundContent": "Вы уверены, что хотите удалить подключение?",
"deleteClient": "Удалить клиента",
"deleteClientContent": "Вы уверены, что хотите удалить клиента?",
"resetTrafficContent": "Вы уверены, что хотите сбросить трафик?",
"copyLink": "Копировать ссылку",
"address": "Адрес",
"network": "Сеть",
"destinationPort": "Порт назначения",
"targetAddress": "Целевой адрес",
"monitorDesc": "Оставьте пустым для прослушивания всех IP-адресов",
"meansNoLimit": "= Без ограничений (значение: ГБ)",
"totalFlow": "Общий расход",
"leaveBlankToNeverExpire": "Оставьте пустым, чтобы было бесконечным",
"noRecommendKeepDefault": "Рекомендуется оставить настройки по умолчанию",
"certificatePath": "Путь к сертификату",
"certificateContent": "Содержимое сертификата",
"publicKey": "Публичный ключ",
"privatekey": "Приватный ключ",
"clickOnQRcode": "Нажмите на QR-код, чтобы скопировать",
"client": "Клиент",
"export": "Экспорт ссылок",
"clone": "Клонировать",
"cloneInbound": "Клонировать",
"cloneInboundContent": "Будут клонированы все настройки подключений, кроме списка клиентов, порта и IP-адреса прослушивания",
"cloneInboundOk": "Клонировано",
"resetAllTraffic": "Сброс трафика всех подключений",
"resetAllTrafficTitle": "Сброс трафика всех подключений",
"resetAllTrafficContent": "Вы уверены, что хотите сбросить трафик всех подключений?",
"resetInboundClientTraffics": "Сброс трафика клиента",
"resetInboundClientTrafficTitle": "Сброс трафика клиентов",
"resetInboundClientTrafficContent": "Вы уверены, что хотите сбросить трафик для этих клиентов?",
"resetAllClientTraffics": "Сброс трафика всех клиентов",
"resetAllClientTrafficTitle": "Сброс трафика всех клиентов",
"resetAllClientTrafficContent": "Вы уверены, что хотите сбросить трафик всех клиентов?",
"delDepletedClients": "Удалить отключенных клиентов",
"delDepletedClientsTitle": "Удаление отключенных клиентов",
"delDepletedClientsContent": "Вы уверены, что хотите удалить всех отключенных клиентов?",
"email": "Email",
"emailDesc": "Пожалуйста, укажите уникальный Email",
"IPLimit": "Лимит по количеству IP",
"IPLimitDesc": "Ограничение числа одновременных подключений с разных IP (0 отключить)",
"IPLimitlog": "Лог IP-адресов",
"IPLimitlogDesc": "Лог IP-адресов (перед включением лога IP-адресов, вы должны очистить лог)",
"IPLimitlogclear": "Очистить лог",
"setDefaultCert": "Установить сертификат панели",
"streamTab": "Поток",
"securityTab": "Безопасность",
"sniffingTab": "Сниффинг",
"sniffingMetadataOnly": "Только метаданные",
"sniffingRouteOnly": "Только маршрутизация",
"sniffingIpsExcluded": "Исключённые IP",
"sniffingDomainsExcluded": "Исключённые домены",
"decryption": "Расшифрование",
"encryption": "Шифрование",
"vlessAuthX25519": "Аутентификация X25519",
"vlessAuthMlkem768": "Аутентификация ML-KEM-768",
"vlessAuthCustom": "Свой",
"vlessAuthSelected": "Выбрано: {auth}",
"advanced": {
"title": "Разделы JSON входящего",
"subtitle": "Полный JSON входящего и отдельные редакторы для settings, sniffing и streamSettings.",
"all": "Всё",
"allHelp": "Полный объект входящего со всеми полями в одном редакторе.",
"settings": "Настройки",
"settingsHelp": "Обёртка блока settings Xray:",
"sniffing": "Сниффинг",
"sniffingHelp": "Обёртка блока sniffing Xray:",
"stream": "Поток",
"streamHelp": "Обёртка блока stream Xray:",
"jsonErrorPrefix": "Расширенный JSON"
},
"telegramDesc": "Пожалуйста, укажите Chat ID Telegram. (используйте команду '/id' в боте) или ({'@'}userinfobot)",
"subscriptionDesc": "Вы можете найти свою ссылку подписки в разделе 'Подробнее'",
"info": "Информация",
"same": "Тот же",
"inboundData": "Данные подключений",
"exportInbound": "Экспорт подключений",
"import": "Импортировать",
"importInbound": "Импорт подключений",
"periodicTrafficResetTitle": "Сброс трафика",
"periodicTrafficResetDesc": "Автоматический сброс счетчика трафика через указанные интервалы",
"lastReset": "Последний сброс",
"periodicTrafficReset": {
"never": "Никогда",
"daily": "Ежедневно",
"weekly": "Еженедельно",
"monthly": "Ежемесячно",
"hourly": "Ежечасно"
},
"toasts": {
"obtain": "Получить",
"updateSuccess": "Обновление прошло успешно",
"logCleanSuccess": "Лог был очищен",
"inboundsUpdateSuccess": "Подключения успешно обновлены",
"inboundUpdateSuccess": "Подключение успешно обновлено",
"inboundCreateSuccess": "Подключение успешно создано",
"inboundDeleteSuccess": "Подключение успешно удалено",
"inboundClientAddSuccess": "Клиент(ы) подключения добавлен(ы)",
"inboundClientDeleteSuccess": "Клиент подключения удалён",
"inboundClientUpdateSuccess": "Клиент подключения обновлён",
"delDepletedClientsSuccess": "Все исчерпанные клиенты удалены",
"resetAllClientTrafficSuccess": "Весь трафик клиента сброшен",
"resetAllTrafficSuccess": "Весь трафик сброшен",
"resetInboundClientTrafficSuccess": "Трафик сброшен",
"resetInboundTrafficSuccess": "Входящий трафик сброшен",
"trafficGetError": "Ошибка получения данных о трафике",
"getNewX25519CertError": "Ошибка при получении сертификата X25519.",
"getNewmldsa65Error": "Ошибка при получении сертификата mldsa65.",
"getNewVlessEncError": "Ошибка при получении сертификата VlessEnc."
},
"stream": {
"general": {
"request": "Запрос",
"response": "Ответ",
"name": "Имя",
"value": "Значение"
},
"tcp": {
"version": "Версия",
"method": "Метод",
"path": "Путь",
"status": "Статус",
"statusDescription": "Описание статуса",
"requestHeader": "Заголовок запроса",
"responseHeader": "Заголовок ответа"
}
}
},
"clients": {
"add": "Добавить клиента",
"edit": "Изменить клиента",
"submitAdd": "Добавить клиента",
"submitEdit": "Сохранить изменения",
"clientCount": "Количество клиентов",
"bulk": "Массовое добавление",
"copyFromInbound": "Скопировать клиентов из входящего",
"copyToInbound": "Скопировать клиентов в",
"copySelected": "Скопировать выбранное",
"copySource": "Источник",
"copyEmailPreview": "Предпросмотр результирующего email",
"copySelectSourceFirst": "Сначала выберите исходный входящий.",
"copyResult": "Результат копирования",
"copyResultSuccess": "Скопировано успешно",
"copyResultNone": "Нечего копировать: клиенты не выбраны или источник пуст",
"copyResultErrors": "Ошибки копирования",
"copyFlowLabel": "Flow для новых клиентов (VLESS)",
"copyFlowHint": "Применяется ко всем скопированным клиентам. Оставьте пустым, чтобы пропустить.",
"selectAll": "Выбрать всё",
"clearAll": "Очистить всё",
"method": "Метод",
"first": "Первый",
"last": "Последний",
"ipLog": "Журнал IP",
"prefix": "Префикс",
"postfix": "Постфикс",
"delayedStart": "Старт после первого использования",
"expireDays": "Длительность",
"days": "Дни",
"renew": "Автопродление",
"renewDesc": "Автоматическое продление после окончания. (0 = отключено) (единица: день)",
"title": "Клиенты",
"actions": "Действия",
"totalGB": "Всего отправлено/получено (ГБ)",
"expiryTime": "Срок действия",
"addClients": "Добавить клиентов",
"limitIp": "Лимит IP",
"password": "Пароль",
"subId": "ID подписки",
"online": "В сети",
"email": "Email",
"comment": "Комментарий",
"traffic": "Трафик",
"offline": "Не в сети",
"addTitle": "Добавить клиента",
"qrCode": "QR-код",
"moreInformation": "Подробнее",
"delete": "Удалить",
"reset": "Сбросить трафик",
"editTitle": "Изменить клиента",
"client": "Клиент",
"enabled": "Включён",
"remaining": "Остаток",
"duration": "Длительность",
"attachedInbounds": "Привязанные входящие",
"selectInbound": "Выберите один или несколько входящих",
"noSubId": "У этого клиента нет subId, ссылка для общего доступа недоступна.",
"noLinks": "Нет ссылок для общего доступа — сначала привяжите клиента к входящему с поддерживаемым протоколом.",
"link": "Ссылка",
"resetNotPossible": "Сначала привяжите этого клиента к входящему.",
"general": "Общее",
"resetAllTraffics": "Сбросить трафик всех клиентов",
"resetAllTrafficsTitle": "Сбросить трафик всех клиентов?",
"resetAllTrafficsContent": "Счётчики отправки/приёма всех клиентов сбрасываются в ноль. Квоты и срок действия не затрагиваются. Это действие нельзя отменить.",
"empty": "Клиентов пока нет — добавьте первого, чтобы начать.",
"deleteConfirmTitle": "Удалить клиента {email}?",
"deleteConfirmContent": "Клиент будет удалён из всех привязанных входящих, а его запись трафика будет уничтожена. Это действие нельзя отменить.",
"deleteSelected": "Удалить ({count})",
"bulkDeleteConfirmTitle": "Удалить {count} клиентов?",
"bulkDeleteConfirmContent": "Каждый выбранный клиент удаляется из всех привязанных входящих, его запись трафика уничтожается. Это действие нельзя отменить.",
"delDepleted": "Удалить исчерпанных",
"delDepletedConfirmTitle": "Удалить исчерпанных клиентов?",
"delDepletedConfirmContent": "Удаляются все клиенты, у которых исчерпана квота трафика или истёк срок. Это действие нельзя отменить.",
"auth": "Auth",
"hysteriaAuth": "Auth для Hysteria",
"uuid": "UUID",
"flow": "Flow",
"reverseTag": "Reverse tag",
"reverseTagPlaceholder": "Необязательный Reverse tag",
"telegramId": "ID пользователя Telegram",
"telegramIdPlaceholder": "Числовой ID пользователя Telegram (0 = нет)",
"created": "Создан",
"updated": "Обновлён",
"ipLimit": "Лимит IP",
"toasts": {
"deleted": "Клиент удалён",
"trafficReset": "Трафик сброшен",
"allTrafficsReset": "Трафик всех клиентов сброшен",
"bulkDeleted": "Удалено клиентов: {count}",
"bulkDeletedMixed": "Удалено: {ok}, не удалось: {failed}",
"bulkCreated": "Создано клиентов: {count}",
"bulkCreatedMixed": "Создано: {ok}, не удалось: {failed}",
"delDepleted": "Удалено исчерпанных клиентов: {count}"
}
},
"nodes": {
"title": "Узлы",
"addNode": "Добавить узел",
"editNode": "Редактировать узел",
"totalNodes": "Всего узлов",
"onlineNodes": "Онлайн",
"offlineNodes": "Офлайн",
"avgLatency": "Средняя задержка",
"name": "Имя",
"namePlaceholder": "напр. de-frankfurt-1",
"addressPlaceholder": "panel.example.com или 1.2.3.4",
"remark": "Примечание",
"scheme": "Схема",
"address": "Адрес",
"port": "Порт",
"basePath": "Базовый путь",
"apiToken": "Токен API",
"apiTokenPlaceholder": "Токен со страницы Настроек удалённой панели",
"apiTokenHint": "Удалённая панель показывает свой токен API в разделе Настройки → Токен API.",
"regenerate": "Сгенерировать токен заново",
"regenerateConfirm": "Повторная генерация аннулирует текущий токен. Любая центральная панель, использующая его, потеряет доступ до обновления. Продолжить?",
"allowPrivateAddress": "Разрешить частный адрес",
"allowPrivateAddressHint": "Включить только для узлов в частной сети или VPN.",
"enable": "Включён",
"status": "Статус",
"cpu": "CPU",
"mem": "Память",
"uptime": "Время работы",
"latency": "Задержка",
"lastHeartbeat": "Последний пинг",
"xrayVersion": "Версия Xray",
"panelVersion": "Версия панели",
"actions": "Действия",
"probe": "Проверить сейчас",
"testConnection": "Проверить соединение",
"connectionOk": "Соединение в порядке ({ms} мс)",
"connectionFailed": "Не удалось подключиться",
"never": "никогда",
"justNow": "только что",
"deleteConfirmTitle": "Удалить узел \"{name}\"?",
"deleteConfirmContent": "Это остановит мониторинг узла. Сама удалённая панель не будет затронута.",
"statusValues": {
"online": "Онлайн",
"offline": "Офлайн",
"unknown": "Неизвестно"
},
"toasts": {
"list": "Не удалось загрузить узлы",
"obtain": "Не удалось загрузить узел",
"add": "Добавить узел",
"update": "Обновить узел",
"delete": "Удалить узел",
"deleted": "Узел удалён",
"test": "Проверить соединение",
"fillRequired": "Имя, адрес, порт и токен API обязательны",
"probeFailed": "Проверка не удалась"
}
},
"settings": {
"title": "Настройки",
"save": "Сохранить",
"infoDesc": "Сохраните изменения и перезапустите панель для их применения.",
"restartPanel": "Перезапуск панели",
"restartPanelDesc": "Вы уверены, что хотите перезапустить панель? Подтвердите, и перезапуск произойдёт через 3 секунды. Если панель будет недоступна, проверьте лог сервера",
"restartPanelSuccess": "Панель успешно перезапущена",
"actions": "Действия",
"resetDefaultConfig": "Восстановить настройки по умолчанию",
"panelSettings": "Панель",
"securitySettings": "Учетная запись",
"TGBotSettings": "Telegram-Бот",
"panelListeningIP": "IP-адрес для управления панелью",
"panelListeningIPDesc": "Оставьте пустым для подключения с любого IP",
"panelListeningDomain": "Домен панели",
"panelListeningDomainDesc": "Оставьте пустым для подключения с любых доменов и IP.",
"panelPort": "Порт панели",
"panelPortDesc": "Порт, на котором работает панель",
"publicKeyPath": "Путь к файлу публичного ключа сертификата панели",
"publicKeyPathDesc": "Введите полный путь, начинающийся с '/'",
"privateKeyPath": "Путь к файлу приватного ключа сертификата панели",
"privateKeyPathDesc": "Введите полный путь, начинающийся с '/'",
"panelUrlPath": "Корневой путь URL адреса панели",
"panelUrlPathDesc": "Должен начинаться с '/' и заканчиваться '/'",
"pageSize": "Размер нумерации страниц",
"pageSizeDesc": "Определить размер страницы для таблицы подключений. Установите 0, чтобы отключить",
"remarkModel": "Модель примечания и символ разделения",
"datepicker": "Тип календаря",
"datepickerPlaceholder": "Выберите дату",
"datepickerDescription": "Запланированные задачи будут выполняться в соответствии с этим календарем.",
"sampleRemark": "Пример примечания",
"oldUsername": "Текущий логин",
"currentPassword": "Текущий пароль",
"newUsername": "Новый логин",
"newPassword": "Новый пароль",
"telegramBotEnable": "Включить Telegram бота",
"telegramBotEnableDesc": "Доступ к функциям панели через Telegram-бота",
"telegramToken": "Токен Telegram бота",
"telegramTokenDesc": "Необходимо получить токен у менеджера ботов Telegram {'@'}botfather",
"telegramProxy": "Прокси-сервер Socks5",
"telegramProxyDesc": "Если для подключения к Telegram вам нужен прокси Socks5, настройте его параметры согласно руководству.",
"telegramAPIServer": "API-сервер Telegram",
"telegramAPIServerDesc": "Используемый API-сервер Telegram. Оставьте пустым, чтобы использовать сервер по умолчанию.",
"telegramChatId": "User ID администратора бота",
"telegramChatIdDesc": "Один или несколько User ID администратора(-ов) Telegram-бота. Для получения User ID используйте {'@'}userinfobot или команду '/id' в боте.",
"telegramNotifyTime": "Частота уведомлений для администраторов от бота",
"telegramNotifyTimeDesc": "Укажите интервал уведомлений в формате Crontab",
"tgNotifyBackup": "Резервное копирование базы данных",
"tgNotifyBackupDesc": "Отправлять уведомление с файлом резервной копии базы данных",
"tgNotifyLogin": "Уведомление о входе",
"tgNotifyLoginDesc": "Отображает имя пользователя, IP-адрес и время, когда кто-то пытается войти в вашу панель.",
"sessionMaxAge": "Продолжительность сессии",
"sessionMaxAgeDesc": "Продолжительность сессии в системе (значение: минута)",
"expireTimeDiff": "Задержка уведомления об истечении сессии",
"expireTimeDiffDesc": "Получение уведомления об истечении срока действия сессии до достижения порогового значения (значение: день)",
"trafficDiff": "Порог трафика для уведомления",
"trafficDiffDesc": "Получение уведомления об исчерпании трафика до достижения порога (значение: ГБ)",
"tgNotifyCpu": "Порог нагрузки на ЦП для уведомления",
"tgNotifyCpuDesc": "Уведомление администраторов в Telegram, если нагрузка на ЦП превышает этот порог (значение: %)",
"timeZone": "Часовой пояс",
"timeZoneDesc": "Запланированные задачи выполняются в соответствии со временем в этом часовом поясе",
"subSettings": "Подписка",
"subEnable": "Включить подписку",
"subEnableDesc": "Функция подписки с отдельной конфигурацией",
"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-адреса",
"subPort": "Порт подписки",
"subPortDesc": "Номер порта для обслуживания службы подписки не должен использоваться на сервере",
"subCertPath": "Путь к файлу публичного ключа сертификата подписки",
"subCertPathDesc": "Введите полный путь, начинающийся с '/'",
"subKeyPath": "Путь к файлу приватного ключа сертификата подписки",
"subKeyPathDesc": "Введите полный путь, начинающийся с '/'",
"subPath": "Корневой путь URL-адреса подписки",
"subPathDesc": "Должен начинаться с '/' и заканчиваться на '/'",
"subDomain": "Домен прослушивания",
"subDomainDesc": "Оставьте пустым по умолчанию, чтобы слушать все домены и IP-адреса",
"subUpdates": "Интервалы обновления подписки",
"subUpdatesDesc": "Интервал между обновлениями в клиентском приложении (в часах)",
"subEncrypt": "Шифровать конфиги",
"subEncryptDesc": "Шифровать возвращенные конфиги в подписке",
"subShowInfo": "Показать информацию об использовании",
"subShowInfoDesc": "Отображать остаток трафика и дату окончания после имени конфигурации",
"subEmailInRemark": "Включать Email в название",
"subEmailInRemarkDesc": "Включать email клиента в название профиля подписки.",
"subURI": "URI обратного прокси",
"subURIDesc": "Изменить базовый URI URL-адреса подписки для использования за прокси-серверами",
"externalTrafficInformEnable": "Информация о внешнем трафике",
"externalTrafficInformEnableDesc": "Информировать внешний API о каждом обновлении трафика",
"externalTrafficInformURI": "URI информации о внешнем трафике",
"externalTrafficInformURIDesc": "Обновления трафика отправляются на этот URI",
"restartXrayOnClientDisable": "Перезапускать Xray после автоотключения",
"restartXrayOnClientDisableDesc": "Когда клиент автоматически отключается из-за окончания срока действия или лимита трафика, перезапускать Xray.",
"fragment": "Фрагментация",
"fragmentDesc": "Включить фрагментацию TLS-хэндшейка",
"fragmentSett": "Настройки фрагментации",
"noisesDesc": "Включить Noises.",
"noisesSett": "Настройки Noises",
"mux": "Mux",
"muxDesc": "Передача нескольких независимых потоков данных в одном соединении.",
"muxSett": "Настройки Mux",
"direct": "Прямое подключение",
"directDesc": "Устанавливает прямые соединения с доменами или IP-адресами определённой страны.",
"notifications": "Уведомления",
"certs": "Сертификаты",
"externalTraffic": "Внешний трафик",
"dateAndTime": "Дата и время",
"proxyAndServer": "Прокси и сервер",
"intervals": "Интервалы",
"information": "Информация",
"language": "Язык интерфейса",
"telegramBotLanguage": "Язык Telegram-бота",
"security": {
"admin": "Учетные данные администратора",
"twoFactor": "Двухфакторная аутентификация",
"twoFactorEnable": "Включить 2FA",
"twoFactorEnableDesc": "Добавляет дополнительный уровень аутентификации для повышения безопасности.",
"twoFactorModalSetTitle": "Включить двухфакторную аутентификацию",
"twoFactorModalDeleteTitle": "Отключить двухфакторную аутентификацию",
"twoFactorModalSteps": "Для настройки двухфакторной аутентификации выполните несколько шагов:",
"twoFactorModalFirstStep": "1. Отсканируйте этот QR-код в приложении для аутентификации или скопируйте токен рядом с QR-кодом и вставьте его в приложение",
"twoFactorModalSecondStep": "2. Введите код из приложения",
"twoFactorModalRemoveStep": "Введите код из приложения, чтобы отключить двухфакторную аутентификацию.",
"twoFactorModalChangeCredentialsTitle": "Изменить учетные данные",
"twoFactorModalChangeCredentialsStep": "Введите код из приложения, чтобы изменить учетные данные администратора.",
"twoFactorModalSetSuccess": "Двухфакторная аутентификация была успешно установлена",
"twoFactorModalDeleteSuccess": "Двухфакторная аутентификация была успешно удалена",
"twoFactorModalError": "Неверный код",
"show": "Показать",
"hide": "Скрыть",
"apiTokenNew": "Новый токен",
"apiTokenName": "Имя",
"apiTokenNamePlaceholder": "например, central-panel-a",
"apiTokenNameRequired": "Имя обязательно",
"apiTokenEmpty": "Токенов пока нет — создайте один для аутентификации ботов или удалённых панелей.",
"apiTokenDeleteWarning": "Любой клиент, использующий этот токен, немедленно потеряет аутентификацию."
},
"toasts": {
"modifySettings": "Настройки изменены",
"getSettings": "Произошла ошибка при получении параметров.",
"modifyUserError": "Произошла ошибка при изменении учетных данных администратора.",
"modifyUser": "Вы успешно изменили учетные данные администратора.",
"originalUserPassIncorrect": "Неверное имя пользователя или пароль",
"userPassMustBeNotEmpty": "Новое имя пользователя и новый пароль должны быть заполнены",
"getOutboundTrafficError": "Ошибка получения трафика исходящего подключения",
"resetOutboundTrafficError": "Ошибка сброса трафика исходящего подключения"
}
},
"xray": {
"title": "Настройки Xray",
"save": "Сохранить",
"restart": "Перезапуск Xray",
"restartSuccess": "Xray успешно перезапущен",
"stopSuccess": "Xray успешно остановлен",
"restartError": "Произошла ошибка при перезапуске Xray.",
"stopError": "Произошла ошибка при остановке Xray.",
"basicTemplate": "Основное",
"advancedTemplate": "Расширенный шаблон",
"generalConfigs": "Основные настройки",
"generalConfigsDesc": "Эти параметры описывают общие настройки",
"logConfigs": "Логи",
"logConfigsDesc": "Логи могут замедлять работу сервера. Включайте только нужные вам виды логов при необходимости!",
"blockConfigsDesc": "Настройте, чтобы клиенты не имели доступа к определенным протоколам",
"basicRouting": "Базовые соединения",
"blockConnectionsConfigsDesc": "Эти параметры будут блокировать трафик в зависимости от страны назначения.",
"directConnectionsConfigsDesc": "Прямое соединение означает, что определенный трафик не будет перенаправлен через другой сервер.",
"blockips": "Заблокированные IP-адреса",
"blockdomains": "Заблокированные домены",
"directips": "Прямые IP-адреса",
"directdomains": "Прямые домены",
"ipv4Routing": "Правила IPv4",
"ipv4RoutingDesc": "Эти параметры позволят клиентам маршрутизироваться к целевым доменам только через IPv4",
"warpRouting": "Правила WARP",
"warpRoutingDesc": " Эти опции будут направлять трафик в зависимости от конкретного пункта назначения через WARP.",
"nordRouting": "Маршрутизация NordVPN",
"nordRoutingDesc": "Эти опции будут направлять трафик в зависимости от конкретного пункта назначения через NordVPN.",
"Template": "Шаблон конфигурации Xray",
"TemplateDesc": "На основе шаблона создаётся конфигурационный файл Xray.",
"FreedomStrategy": "Настройка стратегии протокола Freedom",
"FreedomStrategyDesc": "Установка стратегии вывода сети в протоколе Freedom",
"RoutingStrategy": "Настройка маршрутизации доменов",
"RoutingStrategyDesc": "Установка общей стратегии маршрутизации разрешения DNS",
"outboundTestUrl": "URL для теста исходящего",
"outboundTestUrlDesc": "URL для проверки подключения исходящего",
"Torrent": "Заблокировать BitTorrent",
"Inbounds": "Входящие подключения",
"InboundsDesc": "Изменение шаблона конфигурации для подключения определенных клиентов",
"Outbounds": "Исходящие подключения",
"Balancers": "Балансировщик",
"OutboundsDesc": "Изменение шаблона конфигурации, чтобы определить исходящие подключения для этого сервера",
"Routings": "Маршрутизация",
"RoutingsDesc": "Важен приоритет каждого правила!",
"completeTemplate": "Все",
"logLevel": "Уровень логов",
"logLevelDesc": "Уровень журнала для журналов ошибок, указывающий информацию, которую необходимо записать.",
"accessLog": "Логи доступа",
"accessLogDesc": "Путь к файлу журнала доступа. Специальное значение «none» отключает логи доступа.",
"errorLog": "Логи ошибок",
"errorLogDesc": "Путь к файлу логов ошибок. Специальное значение «none» отключает логи ошибок.",
"dnsLog": "Логи DNS",
"dnsLogDesc": "Включить логи запросов DNS",
"maskAddress": "Маскировка адреса",
"maskAddressDesc": "При активации реальный IP-адрес заменяется на маскировочный в логах.",
"statistics": "Статистика",
"statsInboundUplink": "Статистика входящего аплинка",
"statsInboundUplinkDesc": "Включает сбор статистики для исходящего трафика всех входящих прокси.",
"statsInboundDownlink": "Статистика входящего даунлинка",
"statsInboundDownlinkDesc": "Включает сбор статистики для входящего трафика всех входящих прокси.",
"statsOutboundUplink": "Статистика исходящего аплинка",
"statsOutboundUplinkDesc": "Включает сбор статистики для исходящего трафика всех исходящих прокси.",
"statsOutboundDownlink": "Статистика исходящего даунлинка",
"statsOutboundDownlinkDesc": "Включает сбор статистики для входящего трафика всех исходящих прокси.",
"rules": {
"first": "Первый",
"last": "Последний",
"up": "Поднять вверх",
"down": "Опустить вниз",
"source": "Источник",
"dest": "Пункт назначения",
"inbound": "Входящее подключение",
"outbound": "Исходящее подключение",
"balancer": "Балансировщик",
"info": "Информация",
"add": "Создать правило",
"edit": "Редактировать правило",
"useComma": "Элементы, разделённые запятыми"
},
"outbound": {
"addOutbound": "Создать исходящее подключение",
"addReverse": "Создать реверс-прокси",
"editOutbound": "Изменить исходящее подключение",
"editReverse": "Редактировать реверс-прокси",
"reverseTag": "Тег реверс-прокси",
"reverseTagDesc": "Тег исходящего подключения для простого реверс-прокси VLESS. Оставьте пустым для отключения.",
"reverseTagPlaceholder": "тег исходящего (пусто = отключено)",
"tag": "Тег",
"tagDesc": "Уникальный тег",
"address": "Адрес",
"reverse": "Реверс-прокси",
"domain": "Домен",
"type": "Тип",
"bridge": "Мост",
"portal": "Портал",
"link": "Ссылка",
"intercon": "Соединение",
"settings": "Настройки",
"accountInfo": "Информация об учетной записи",
"outboundStatus": "Статус исходящего подключения",
"sendThrough": "Отправить через",
"test": "Тест",
"testResult": "Результат теста",
"testing": "Тестирование соединения...",
"testSuccess": "Тест успешен",
"testFailed": "Тест не пройден",
"testError": "Не удалось протестировать исходящее подключение",
"nordvpn": "NordVPN",
"accessToken": "Токен доступа",
"country": "Страна",
"server": "Сервер",
"city": "Город",
"allCities": "Все города",
"privateKey": "Приватный ключ",
"load": "Нагрузка"
},
"balancer": {
"addBalancer": "Создать балансировщик",
"editBalancer": "Редактировать балансировщик",
"balancerStrategy": "Стратегия",
"balancerSelectors": "Селекторы",
"tag": "Тег",
"tagDesc": "Уникальный тег",
"balancerDesc": "Невозможно одновременно использовать balancerTag и outboundTag. При одновременном использовании будет работать только outboundTag."
},
"wireguard": {
"secretKey": "Секретный ключ",
"publicKey": "Публичный ключ",
"allowedIPs": "Разрешенные IP-адреса",
"endpoint": "Конечная точка",
"psk": "Общий ключ",
"domainStrategy": "Стратегия домена"
},
"tun": {
"nameDesc": "Имя интерфейса TUN. Значение по умолчанию - 'xray0'",
"mtuDesc": "Максимальная единица передачи. Максимальный размер пакетов данных. Значение по умолчанию - 1500",
"userLevel": "Уровень пользователя",
"userLevelDesc": "Все соединения, установленные через этот входящий поток, будут использовать этот уровень пользователя. Значение по умолчанию - 0"
},
"dns": {
"enable": "Включить DNS",
"enableDesc": "Включить встроенный DNS-сервер",
"tag": "Название тега DNS",
"tagDesc": "Этот тег будет доступен как входящий тег в правилах маршрутизации.",
"clientIp": "IP клиента",
"clientIpDesc": "Используется для уведомления сервера о указанном местоположении IP во время DNS-запросов",
"disableCache": "Отключить кэш",
"disableCacheDesc": "Отключает кэширование DNS",
"disableFallback": "Отключить резервный DNS",
"disableFallbackDesc": "Отключает резервные DNS-запросы",
"disableFallbackIfMatch": "Отключить резервный DNS при совпадении",
"disableFallbackIfMatchDesc": "Отключает резервные DNS-запросы при совпадении списка доменов DNS-сервера",
"enableParallelQuery": "Включить параллельные запросы",
"enableParallelQueryDesc": "Включить параллельные DNS-запросы к нескольким серверам для более быстрого разрешения",
"strategy": "Стратегия запроса",
"strategyDesc": "Общая стратегия разрешения доменных имен",
"add": "Создать DNS",
"edit": "Редактировать DNS",
"domains": "Домены",
"expectIPs": "Ожидаемые IP",
"unexpectIPs": "Неожидаемые IP",
"useSystemHosts": "Использовать системные Hosts",
"useSystemHostsDesc": "Использовать файл hosts из установленной системы",
"serveStale": "Использовать устаревшие",
"serveStaleDesc": "Возвращать устаревшие результаты из кэша во время обновления в фоне",
"serveExpiredTTL": "TTL устаревших",
"serveExpiredTTLDesc": "Срок действия (секунды) устаревших записей кэша; 0 = бессрочно",
"timeoutMs": "Тайм-аут (мс)",
"skipFallback": "Пропустить Fallback",
"finalQuery": "Финальный запрос",
"hosts": "Hosts",
"hostsAdd": "Добавить Host",
"hostsEmpty": "Host не определены",
"hostsDomain": "Домен (напр. domain:example.com)",
"hostsValues": "IP или домен — введите и нажмите Enter",
"usePreset": "Использовать шаблон",
"dnsPresetTitle": "Шаблоны DNS",
"dnsPresetFamily": "Семейный",
"clearAll": "Удалить все",
"clearAllTitle": "Удалить все DNS-серверы?",
"clearAllConfirm": "Все DNS-серверы будут удалены из списка. Это действие нельзя отменить."
},
"fakedns": {
"add": "Создать Fake DNS",
"edit": "Редактировать Fake DNS",
"ipPool": "Подсеть пула IP",
"poolSize": "Размер пула"
}
}
},
"tgbot": {
"keyboardClosed": "❌ Клавиатура закрыта.",
"noResult": "❗ Нет результатов.",
"noQuery": "❌ Запрос не найден. Пожалуйста, повторите команду.",
"wentWrong": "❌ Что-то пошло не так...",
"noIpRecord": "❗ Нет записей об IP-адресе.",
"noInbounds": "❗ У вас не настроено ни одного входящего подключения.",
"unlimited": "♾ Безлимит",
"add": "Добавить",
"month": "Месяц",
"months": "Месяцев",
"day": "День",
"days": "Дней",
"hours": "Часов",
"minutes": "Минуты",
"unknown": "Неизвестно",
"inbounds": "Входящие подключения",
"clients": "Клиенты",
"offline": "🔴 Офлайн",
"online": "🟢 Онлайн",
"commands": {
"unknown": "❗ Неизвестная команда",
"pleaseChoose": "👇 Пожалуйста, выберите:\r\n",
"help": "🤖 Добро пожаловать! Этот бот предназначен для предоставления вам данных с сервера и позволяет вносить изменения на него.\r\n\r\n",
"start": "👋 Привет, <i>{{ .Firstname }}</i>.\r\n",
"welcome": "🤖 Добро пожаловать в бота управления <b>{{ .Hostname }}</b>!\r\n",
"status": "✅ Бот функционирует нормально.",
"usage": "❗ Пожалуйста, укажите email для поиска.",
"getID": "🆔 Ваш User ID: <code>{{ .ID }}</code>",
"helpAdminCommands": "🔃 Для перезапуска Xray Core:\r\n<code>/restart</code>\r\n\r\n🔎 Для поиска клиента по email:\r\n<code>/usage [Email]</code>\r\n\r\n📊 Для поиска входящих подключений (со статистикой клиентов):\r\n<code>/inbound [имя подключения]</code>\r\n\r\n🆔 Ваш Telegram User ID:\r\n<code>/id</code>",
"helpClientCommands": "💲 Для просмотра информации о вашей подписке используйте команду:\r\n<code>/usage [Email]</code>\r\n\r\n🆔 Ваш Telegram User ID:\r\n<code>/id</code>",
"restartUsage": "\r\n\r\n<code>/restart</code>",
"restartSuccess": "✅ Ядро Xray успешно перезапущено.",
"restartFailed": "❗ Ошибка при перезапуске Xray-core.\r\n\r\n<code>Ошибка: {{ .Error }}</code>.",
"xrayNotRunning": "❗ Xray Core не запущен.",
"startDesc": "Показать главное меню",
"helpDesc": "Справка по боту",
"statusDesc": "Проверить статус бота",
"idDesc": "Показать ваш Telegram ID"
},
"messages": {
"cpuThreshold": "🔴 Загрузка процессора составляет {{ .Percent }}%, что превышает пороговое значение {{ .Threshold }}%",
"selectUserFailed": "❌ Ошибка при выборе пользователя.",
"userSaved": "✅ Пользователь Telegram сохранен.",
"loginSuccess": "✅ Успешный вход в панель.\r\n",
"loginFailed": "❗️ Ошибка входа в панель.\r\n",
"2faFailed": "Ошибка 2FA",
"report": "🕰 Запланированные отчеты: {{ .RunTime }}\r\n",
"datetime": "⏰ Дата и время: {{ .DateTime }}\r\n",
"hostname": "💻 Имя хоста: {{ .Hostname }}\r\n",
"version": "🚀 Версия X-UI: {{ .Version }}\r\n",
"xrayVersion": "📡 Версия Xray: {{ .XrayVersion }}\r\n",
"ipv6": "🌐 IPv6: {{ .IPv6 }}\r\n",
"ipv4": "🌐 IPv4: {{ .IPv4 }}\r\n",
"ip": "🌐 IP: {{ .IP }}\r\n",
"ips": "🔢 IP-адреса:\r\n{{ .IPs }}\r\n",
"serverUpTime": "⏳ Время работы сервера: {{ .UpTime }} {{ .Unit }}\r\n",
"serverLoad": "📈 Нагрузка сервера: {{ .Load1 }}, {{ .Load2 }}, {{ .Load3 }}\r\n",
"serverMemory": "📋 ОЗУ сервера: {{ .Current }}/{{ .Total }}\r\n",
"tcpCount": "🔹 Количество TCP-соединений: {{ .Count }}\r\n",
"udpCount": "🔸 Количество UDP-соединений: {{ .Count }}\r\n",
"traffic": "🚦 Трафик: {{ .Total }} (↑{{ .Upload }},↓{{ .Download }})\r\n",
"xrayStatus": " Состояние Xray: {{ .State }}\r\n",
"username": "👤 Имя пользователя: {{ .Username }}\r\n",
"reason": "❗️ Причина: {{ .Reason }}\r\n",
"time": "⏰ Время: {{ .Time }}\r\n",
"inbound": "📍 Входящее подключение: {{ .Remark }}\r\n",
"port": "🔌 Порт: {{ .Port }}\r\n",
"expire": "📅 Дата окончания: {{ .Time }}\r\n",
"expireIn": "📅 Окончание через: {{ .Time }}\r\n",
"active": "💡 Активен: {{ .Enable }}\r\n",
"enabled": "🚨 Активен: {{ .Enable }}\r\n",
"online": "🌐 Статус соединения: {{ .Status }}\r\n",
"lastOnline": "🔙 Был(а) в сети: {{ .Time }}\r\n",
"email": "📧 Email: {{ .Email }}\r\n",
"upload": "🔼 Исходящий трафик: ↑{{ .Upload }}\r\n",
"download": "🔽 Входящий трафик: ↓{{ .Download }}\r\n",
"total": "📊 Всего: ↑↓{{ .UpDown }} из {{ .Total }}\r\n",
"TGUser": "👤 Telegram User ID: {{ .TelegramID }}\r\n",
"exhaustedMsg": "🚨 Исчерпаны {{ .Type }}:\r\n",
"exhaustedCount": "🚨 Количество исчерпанных {{ .Type }}:\r\n",
"onlinesCount": "🌐 Клиентов онлайн: {{ .Count }}\r\n",
"disabled": "🛑 Отключено: {{ .Disabled }}\r\n",
"depleteSoon": "🔜 Клиенты, у которых скоро исчерпание: {{ .Deplete }}\r\n\r\n",
"backupTime": "🗄 Время резервного копирования: {{ .Time }}\r\n",
"refreshedOn": "\r\n📋🔄 Обновлено: {{ .Time }}\r\n\r\n",
"yes": "✅ Да",
"no": "❌ Нет",
"received_id": "🔑📥 ID обновлён.",
"received_password": "🔑📥 Пароль обновлён.",
"received_email": "📧📥 Email обновлен.",
"received_comment": "💬📥 Комментарий обновлён.",
"id_prompt": "🔑 Стандартный ID: {{ .ClientId }}\n\nВведите ваш ID.",
"pass_prompt": "🔑 Стандартный пароль: {{ .ClientPassword }}\n\nВведите ваш пароль.",
"email_prompt": "📧 Стандартный email: {{ .ClientEmail }}\n\nВведите ваш email.",
"comment_prompt": "💬 Стандартный комментарий: {{ .ClientComment }}\n\nВведите ваш комментарий.",
"inbound_client_data_id": "🔄 Входящие подключения: {{ .InboundRemark }}\n\n🔑 ID: {{ .ClientId }}\n📧 Email: {{ .ClientEmail }}\n📊 Трафик: {{ .ClientTraffic }}\n📅 Срок действия: {{ .ClientExp }}\n💬 Комментарий: {{ .ClientComment }}\n\nТеперь вы можете добавить клиента в входящее подключение!",
"inbound_client_data_pass": "🔄 Входящие подключения: {{ .InboundRemark }}\n\n🔑 Пароль: {{ .ClientPass }}\n📧 Email: {{ .ClientEmail }}\n📊 Трафик: {{ .ClientTraffic }}\n📅 Срок действия: {{ .ClientExp }}\n💬 Комментарий: {{ .ClientComment }}\n\nТеперь вы можете добавить клиента в входящее подключение!",
"cancel": "❌ Процесс отменён! \n\nВы можете снова начать с /start в любое время. 🔄",
"error_add_client": "⚠️ Ошибка:\n\n {{ .error }}",
"using_default_value": "Используется значение по умолчанию👌",
"incorrect_input": "Ваш ввод недействителен.\nФразы должны быть непрерывными без пробелов.\nПравильный пример: aaaaaa\nНеправильный пример: aaa aaa 🚫",
"AreYouSure": "Вы уверены? 🤔",
"SuccessResetTraffic": "📧 Почта: {{ .ClientEmail }}\n🏁 Результат: ✅ Успешно",
"FailedResetTraffic": "📧 Почта: {{ .ClientEmail }}\n🏁 Результат: ❌ Неудача \n\n🛠 Ошибка: [ {{ .ErrorMessage }} ]",
"FinishProcess": "🔚 Сброс трафика завершён для всех клиентов."
},
"buttons": {
"closeKeyboard": "❌ Закрыть клавиатуру",
"cancel": "❌ Отмена",
"cancelReset": "❌ Отменить сброс",
"cancelIpLimit": "❌ Отменить лимит IP",
"confirmResetTraffic": "✅ Подтвердить сброс трафика?",
"confirmClearIps": "✅ Подтвердить очистку IP?",
"confirmRemoveTGUser": "✅ Подтвердить удаление пользователя Telegram?",
"confirmToggle": "✅ Подтвердить вкл/выкл пользователя?",
"dbBackup": "📂 Бэкап БД",
"serverUsage": "💻 Состояние сервера",
"getInbounds": "🔌 Входящие подключения",
"depleteSoon": "⚠️ Скоро конец",
"clientUsage": "Статистика клиента",
"onlines": "🟢 Онлайн",
"commands": "🖱️ Команды",
"refresh": "🔄 Обновить",
"clearIPs": "❌ Очистить IP",
"removeTGUser": "❌ Удалить пользователя Telegram",
"selectTGUser": "👤 Выбрать пользователя Telegram",
"selectOneTGUser": "👤 Выберите пользователя Telegram:",
"resetTraffic": "📈 Сбросить трафик",
"resetExpire": "📅 Изменить дату окончания",
"ipLog": "🔢 Лог IP",
"ipLimit": "🔢 Лимит IP",
"setTGUser": "👤 Установить пользователя Telegram",
"toggle": "🔘 Вкл./Выкл.",
"custom": "🔢 Свой",
"confirmNumber": "✅ Подтвердить: {{ .Num }}",
"confirmNumberAdd": "✅ Подтвердить добавление: {{ .Num }}",
"limitTraffic": "🚧 Лимит трафика",
"getBanLogs": "📄 Лог банов",
"allClients": "👥 Все клиенты",
"addClient": " Новый клиент",
"submitDisable": "Добавить отключенным ☑️",
"submitEnable": "Добавить включенным ✅",
"use_default": "🏷️ Использовать по умолчанию",
"change_id": "⚙️🔑 ID",
"change_password": "⚙️🔑 Пароль",
"change_email": "⚙️📧 Email",
"change_comment": "⚙️💬 Комментарий",
"change_flow": "⚙️🚦 Поток",
"ResetAllTraffics": "Сбросить весь трафик",
"SortedTrafficUsageReport": "Отсортированный отчет об использовании трафика"
},
"answers": {
"successfulOperation": "✅ Успешно!",
"errorOperation": "❗ Ошибка в операции.",
"getInboundsFailed": "❌ Не удалось получить входящие подключения.",
"getClientsFailed": "❌ Не удалось получить клиентов.",
"canceled": "❌ {{ .Email }}: Операция отменена.",
"clientRefreshSuccess": "✅ {{ .Email }}: Клиент успешно обновлен.",
"IpRefreshSuccess": "✅ {{ .Email }}: IP-адреса успешно обновлены.",
"TGIdRefreshSuccess": "✅ {{ .Email }}: Пользователь Telegram клиента успешно обновлен.",
"resetTrafficSuccess": "✅ {{ .Email }}: Трафик успешно сброшен.",
"setTrafficLimitSuccess": "✅ {{ .Email }}: Лимит трафика успешно установлен.",
"expireResetSuccess": "✅ {{ .Email }}: Срок действия успешно сброшен.",
"resetIpSuccess": "✅ {{ .Email }}: Лимит IP ({{ .Count }}) успешно сохранен.",
"clearIpSuccess": "✅ {{ .Email }}: IP-адреса успешно очищены.",
"getIpLog": "✅ {{ .Email }}: Получен лог IP.",
"getUserInfo": "✅ {{ .Email }}: Получена информация о пользователе Telegram.",
"removedTGUserSuccess": "✅ {{ .Email }}: Пользователь Telegram успешно удален.",
"enableSuccess": "✅ {{ .Email }}: Включено успешно.",
"disableSuccess": "✅ {{ .Email }}: Отключено успешно.",
"askToAddUserId": "❌ Ваша конфигурация не найдена!\r\n💭 Пожалуйста, попросите администратора использовать ваш Telegram User ID в конфигурации.\r\n\r\n🆔 Ваш User ID: <code>{{ .TgUserID }}</code>",
"chooseClient": "Выберите клиента для входящего подключения {{ .Inbound }}",
"chooseInbound": "Выберите входящее подключение"
}
}
}