Files
3x-ui/internal/web/translation/zh-CN.json
T
Sanaei 5e1cb7693b Repo-wide self-correcting audit: 54 verified bug fixes (#5970)
* fix(email): resolve a name-addr smtpFrom into bare envelope address and display name

The save-time validator accepts any RFC 5322 address form, so a value
like '3x-ui Panel <panel(at)example.com>' passes validation, but Send and
TestConnection fed that raw string to MAIL FROM, which strict servers
reject with 501, and buildMessage mangled it into a quoted local part.
Parse the configured sender at the point of use: the envelope gets the
bare address and, when no explicit sender name is set, the display name
embedded in the setting is used for the From header.

* fix(email): report a missing sender address from the SMTP connection test

TestConnection skipped the empty-from guard that Send enforces, so with
no sender and no username configured the test issued the null reverse-path
and could report success against a lenient relay while every real
notification send kept failing with the missing-sender error. Guard the
test path the same way and surface a dedicated translated message.

* fix(sub): fall back to the raw subscription when an auto-detected format has no content

With format auto-detection enabled, a client whose User-Agent matched the
Clash or JSON regex was routed straight to that format handler. For a
subscription whose entries convert to neither format (an MTProto-only
subscription, for example) the handler returns an empty document and the
request ended as 404, breaking a URL that served the raw list before the
toggle. The auto-detect branches now serve the detected format only when
it produces content and otherwise continue to the raw response; the
explicit format endpoints keep answering 404 for empty documents.

* fix(node): match prefixed central tags when filtering a selected-mode node snapshot

FilterNodeSnapshot compared a node snapshot's inbound tags against the
raw selected-tag list with an exact match, while its two siblings
(SnapshotHasUnadoptedInbounds and the reconcile tagToCentral map) expand
each selected tag to both its bare node-side form and its n<id>- prefixed
central form. A panel-created node inbound is recorded in the selected
list under the central prefixed tag but reported by the node under the
bare tag, so the exact match dropped it from every snapshot and the
orphan sweep then deleted its central row one tick after creation. Expand
the allowed set with the same prefix flip the siblings use.

* fix(client): refuse a bulk quota reduction that would fall to or below zero

BulkAdjust clamped a client's new traffic limit with max(total+addBytes, 0).
Because 0 is the unlimited sentinel, reducing a client's quota by more than
it had left silently granted that client unlimited traffic. The sibling
expiry branch already refuses an over-reduction; mirror it for quota so the
adjustment is skipped with a clear reason instead of crossing the sentinel.

* fix(client): persist a bulk adjustment's applied field even when the sibling field is skipped

In a mixed BulkAdjust (both a days delta and a bytes delta), a per-field
planning skip such as "unlimited expiry" or "unlimited traffic" was recorded
in the same map that gated the client_traffics write. The applied field was
already written to the inbound JSON and the clients table, but the enforcement
row was left untouched, so the depletion job cut the client on the old limit
while the panel showed the new one. Gate the traffic-row write on an actual
inbound-processing failure rather than on any planning-phase skip note.

* fix(inbound): always create in AddInbound instead of overwriting a row whose id was posted

The add controller binds the inbound model's id form field and never clears
it, and AddInbound persisted with GORM Save, which updates in place when the
primary key is non-zero. A client that reused an existing id (for instance by
duplicating an inbound fetched from /get and changing the port) silently
overwrote that stored row instead of creating a new inbound. Zero the id at
the top of AddInbound, matching how it already zeroes the client-stat ids.

* fix(inbound): accept WireGuard clients when creating an inbound

AddInbound's per-client validation switch had cases for every protocol
except WireGuard, so a WireGuard client fell through to the default branch
that requires a non-empty id. WireGuard clients are keyed by their public
key and carry no id, so importing a WireGuard inbound or re-adding one to a
reconciling node was rejected with "empty client ID". Add a wireguard case
that validates the client key, mirroring addInboundClient.

* fix(client): stop holding the inbound-lock registry mutex while waiting on one inbound

lockInbound acquired the global registry mutex and then blocked on the
per-inbound mutex without releasing the registry first. A slow client
operation holding one inbound's mutex (for example a bulk delete pushing to
an unreachable node) made the next waiter park on that inbound while still
holding the registry mutex, which in turn blocked lockInbound for every
other inbound — freezing client mutations panel-wide. Release the registry
mutex before taking the per-inbound lock.

* fix(client): honor keepTraffic when deleting a client that is attached to inbounds

Delete, DeleteByEmail and BulkDelete all pass keepTraffic to their final
cleanup transaction, but each called the per-inbound delete helper with a
hardcoded false. That helper purges the client's traffic, IP and stat rows
before the gated cleanup runs, so keepTraffic=true still destroyed all
traffic history for any client actually attached to an inbound (the pinned
test only covered a record with no inbound mappings). Thread the caller's
keepTraffic through to the per-inbound helper at all three call sites.

* fix(inbound): defer a local MTProto inbound edit's sidecar push until after commit

UpdateInbound applied a local MTProto inbound change by calling the runtime
UpdateInbound (which stops/starts the mtg sidecar or talks to it) from inside
runSerializedTx. That runs process and network I/O on the single traffic-writer
goroutine while a DB transaction is open, so a slow sidecar stalls traffic
accounting and every concurrent client mutation, and a later step failing the
transaction leaves the sidecar ahead of the rolled-back row. Move the push into
the post-commit hook, matching the xray branch. Adds a SetLocalRuntimeOverride
test seam mirroring the existing node override so the deferral is regression
tested.

* fix(client): delete external-link rows when bulk-deleting clients

The single-client Delete path removes a client's client_external_links rows,
but BulkDelete (and the DelDepleted reaper that routes through it) deleted the
record, mappings and traffic while leaving the external-link rows keyed by the
now-dead client id, so they accumulated as orphans. Delete them in the same
cleanup transaction, keyed by client id like the single path.

* fix(inbound): request an xray restart when toggling a routed MTProto inbound

AddInbound, DelInbound and UpdateInbound all flag needRestart when an inbound
routes MTProto through xray, so the egress SOCKS bridge is regenerated. Only
SetInboundEnable's local path omitted it, so toggling a routed MTProto inbound
off then on left the bridge out of the running config while the sidecar dialed
its loopback port, blackholing that inbound until an unrelated restart. Flag the
restart on the local enable path too.

* fix(client): apply enable-by-email to every inbound a client is attached to

ToggleClientEnableByEmail (Telegram bot) and SetClientEnableByEmail (LDAP sync)
resolved a single inbound via the legacy client_traffics pointer and flipped
enable only there. A client attached to several inbounds kept connecting through
the siblings' running Xray after being disabled, and the next edit could
re-enable it everywhere from a stale sibling. Route both through the
applyClientFieldByEmail fan-out (the #5039 fix path) so the whole multi-inbound
identity is toggled at once, dropping the circular Set/Toggle dependency.

* fix(traffic): commit a traffic tick even when a best-effort maintenance helper fails

addTrafficLocked stages the inbound and client deltas, then runs three helpers
(auto-renew, disable depleted clients, disable depleted inbounds) that are meant
to log and continue. All three reused the function-scope err that the deferred
commit/rollback inspects, so the last helper's error decided the whole tick: a
failure in disableInvalidInbounds rolled back the already-staged traffic while
AddTraffic reported success, and because xray had already advanced its counter
baseline that traffic was lost for good. Give each best-effort helper its own
error variable so only a genuine staging failure rolls the tick back.

* fix(traffic): re-enable clients and serialize the write in Reset All Client Traffic

ClientService.ResetAllTraffics zeroed up/down but, unlike every sibling reset
path, never restored enable=true, so clients that had been auto-disabled for
exceeding their quota stayed cut with zero usage after a reset. It also wrote
client_traffics directly on the shared DB handle instead of through the serial
traffic writer, reintroducing the cross-transaction lock-order deadlock the
writer exists to prevent. Restore enable and run the reset inside
submitTrafficWrite within one transaction.

* fix(traffic): keep node reset propagation out of the serial traffic writer

ResetAllTraffics and ResetInboundTraffic performed their remote-node reset HTTP
calls inside submitTrafficWrite. Each call can block up to the remote timeout,
and Reset All Traffics loops every node serially, so the single traffic-writer
goroutine was held for seconds — long enough that the concurrent 5s traffic poll
timed out submitting its own write and dropped the deltas it had already drained
from xray. Do the DB reset inside the writer, then propagate to the nodes after
it returns, matching how the mtproto quota reset is already sequenced.

* fix(sub): stop the subscription from 500ing on valid-but-unusual stream settings

The raw share-link generators used unchecked type assertions and unguarded
array indexing: an empty Reality shortIds/serverNames array (random.Num(0)
panics), a tcp-http header with no request block or an empty request.path, a
grpc block missing its keys, empty stream settings, and a non-string Host
header all panicked mid-generation. Because getSubs loops every client's link
with no recover, one such client 500s the entire subscription for everyone. The
sibling JSON, Clash and frontend generators already guard these; make the raw
generators match with comma-ok assertions and length checks.

* fix(sub): tolerate a hysteria inbound without hysteriaSettings in the JSON subscription

genHy asserted stream["hysteriaSettings"].(map[string]any) without the comma-ok
form, so a hysteria inbound whose StreamSettings omit the hysteriaSettings key
(a valid, representable shape the raw generator renders fine) panicked and 500ed
the entire JSON subscription. Use comma-ok; the downstream reads already guard
each key, so a nil map degrades gracefully.

* fix(sub): emit the pinned peer cert sha256 in Clash subscriptions

The Clash stream builder computed tlsSettings["pin-sha256"] from the inbound's
pinnedPeerCertSha256, but applySecurity's tls case never copied it onto the
proxy, so it was written with no reader and silently dropped. Clash subscribers
lost certificate pinning while JSON subscribers kept it. Surface pin-sha256 on
the proxy in the tls case, matching the JSON emitter.

* fix(link): parse the snake_case and extra-blob xhttp fields when importing a share link

The panel's share-link emitters (Go and TS) carry advanced xhttp knobs as a
snake_case x_padding_bytes plus an extra=<json> payload, but the Go parser's
xhttp branch read only top-level camelCase params, so importing an xhttp link
via the outbound-subscription feature dropped xPaddingBytes, scMaxEachPostBytes
and the rest, silently reverting them to the stream defaults and producing a
non-working outbound. Mirror the TS parser: read the snake_case alias, merge the
extra JSON blob, then let explicit camelCase params win.

* fix(frontend): decode URL-safe base64 when parsing an imported share link

Base64.decode called window.atob directly, which rejects the base64url
alphabet (- and _) and unpadded input. But the panel's own share-link emitter
uses Base64.encode(x, true) (URL-safe, unpadded), and real SIP002 links do too,
so importing a Shadowsocks link whose method:password encodes with a - or _ threw,
fell back to the raw undecoded string, and produced a wrong method and garbage
password (the vmess parser shared the same limitation). Normalize base64url and
re-pad before atob so decode round-trips every emitted link.

* fix(link): honor the vmess ws path and hysteria2 vcn params on import

Two Go/TS parser parity gaps in the outbound share-link import path: parseVmess
only applied a ws link's path when the inner JSON also carried a host key, so a
generator that omits host dropped the path back to the default; and parseHysteria2
hardcoded verifyPeerCertByName to empty, ignoring the vcn param the panel emits,
so a hysteria2 outbound with a decoy SNI and a distinct cert name failed TLS
verification after import. The TS parser handles both; make the Go parser match.

* fix(ui): stop the sniffing form island from clobbering unrendered fields

antd's Form.useWatch only reports registered fields, so while the
sniffing toggle was off the island emitted { enabled: false } upward and
replaced the full Sniffing object in form state. Saving a VLESS reverse
outbound then crashed in sniffingToWire on the missing ipsExcluded
array; the loopback outbound and the inbound sniffing tab shared the
same hole. Watch the store with preserve: true so unrendered fields
keep their values, and seed a missing value from the schema defaults
instead of an empty cast.

* fix(sub): drop empty remark segments instead of leaving a stray separator

expandSegment dropped a "|" segment only when its tokens rendered the unlimited
mark, so a segment whose only token resolved to the empty string (a client with
no comment, an unlimited client's expiry date) was kept as bare decoration,
leaving a trailing "|" or a dangling emoji on every share link's remark. Drop a
token-bearing segment whenever none of its tokens produce a real value, while
still keeping pure-literal segments.

* fix(xray): keep source- and domains-scoped routing rules when an inbound is deleted

removeInboundTagFromRules drops a routing rule whose inboundTag list becomes
empty only if the rule has no other matcher, but routingMatcherKeys omitted
xray-core's canonical source and domains keys. A rule scoped by source or domains
(common in hand-authored or imported configs) therefore lost its whole body —
including a security-relevant block — when its single listed inbound was deleted,
instead of just having the tag trimmed. Recognize source and domains as live
matchers.

* fix(xray): guard RemoveUser against an uninitialized handler client

Every XrayAPI handler method returns an error when HandlerServiceClient is nil,
except RemoveUser, which dereferenced it directly. A depletion sweep runs Init
with the port ignored and, during a restart window where the fresh process's
api port is still 0, Init fails and leaves the client nil — so RemoveUser
panicked (recovered by the traffic writer, but re-thrown every poll) instead of
returning an error. Add the same nil guard the siblings have.

* fix(xray): do not revive a manually stopped Xray on a background restart

RestartXray cleared isManuallyStopped unconditionally at its top, so the @30s
pending-config cron (and warp/ldap/outbound reconcile jobs) that call
RestartXray(false) resurrected an Xray the admin had deliberately stopped —
unlike the crash-detector, which honors the manual-stop flag. Skip a non-forced
restart while the stop flag is set; only an explicit forced restart clears it.

* fix(xray): retry a failed pending-restart instead of dropping the config change

The 30s cron consumed the need-restart flag with IsNeedRestartAndSetFalse before
calling RestartXray and only logged a failure. If RestartXray failed early (a
transient GetXrayConfig DB error) the old process kept running the old config,
the crash detector saw a running process and never retried, and the flag stayed
cleared — so an admin's saved change silently never reached the core. Move the
consume/restart/retry into ApplyPendingRestart, which re-arms the flag on
failure so the next tick retries.

* fix(xray): synchronize the process version and apiPort fields

Start writes p.version and p.apiPort (via refreshVersion/refreshAPIPort) after
flipping the process to running, while GetXrayVersion and GetAPIPort read them
lock-free from the status and traffic poll goroutines. The struct mutex
deliberately excluded these fields, so a restart racing a poll was a real data
race — a torn read of the version string header can crash. Extend the mutex to
cover version and apiPort, doing the blocking version probe before taking the
lock.

* fix(settings): detect a wildcard listen collision between the web and sub ports

The web/sub same-port check compared the two listen addresses as raw strings, so
binding both on all interfaces with different spellings (webListen 0.0.0.0 vs an
empty subListen) slipped past validation and only failed at startup with an
opaque bind error. Treat any wildcard listen ('', 0.0.0.0, ::) as overlapping so
the clash is reported up front, while still allowing two distinct specific
addresses to share a port.

* fix(db): mark the IP-limit cleanup seeder done on a fresh install

ResetIpLimitNoFail2ban is a one-time migration that, on a host without fail2ban,
zeroes every existing client's limitIp because the limit can't be enforced. It
was missing from the fresh-install fast-path seeder list, so on a brand-new DB it
did not run on the first boot but fired on the second — wiping any IP limits the
admin had set in between. Add it to the fast-path so a truly fresh install marks
it done up front (there is nothing to clean), leaving later admin-set limits
intact.

* fix(security): dial outbound subscriptions through the SSRF guard

The outbound-subscription fetch validated the URL host once (resolving DNS and
rejecting private targets) but then fetched with a plain HTTP client that
re-resolves the host at dial time, so a subscription domain the attacker controls
could pass validation as a public IP and rebind to 127.0.0.1 / a cloud metadata
endpoint / an internal host for the actual dial — a blind SSRF into the panel's
network. Route the direct fetch (and its redirects) through
netsafe.SSRFGuardedDialContext, which resolves, checks and dials the same IP
atomically, carrying the subscription's AllowPrivate flag on the request context;
a configured egress proxy still dials its loopback bridge unguarded.

* fix(security): bound the login-limiter attempts map

The login rate limiter keys its records on the caller-supplied username and only
evicted a record when that exact key was revisited or the login succeeded. An
unauthenticated attacker replaying one CSRF token while rotating a fresh username
per request seeded a record that was never revisited, growing the map without
bound until the panel OOMs. Cap the map: before inserting a new record, reclaim
records whose block has lapsed and whose failures aged out, and if the map is
still at the ceiling under a broad flood, drop one so memory can never grow past
the cap.

* fix(tgbot): require admin for privileged callbacks, not just the first switch

answerCallback wraps only its first callback switch in an isAdmin guard; the
second switch (server usage, inbound/online enumeration, database backup export,
ban logs, mass traffic reset, client creation) ran for every caller. Telegram
delivers a callback with the tapping user's id, so a non-admin who can see an
admin's inline keyboard — as when the bot runs in a group — could tap Backup and
receive the full database and config, or reset all traffic. Default-deny before
the second switch: a non-admin may only run the per-user client_* callbacks that
resolve their own data from their Telegram id.

* fix(eventbus): dispatch each subscriber in its own goroutine

The fan-out loop called every subscriber's handler sequentially on the
single dispatch goroutine. The email and Telegram notifiers block on
network I/O for tens of seconds (or minutes when the remote is slow), so
one slow subscriber stalled the whole loop: the 256-slot channel then
filled and Publish silently dropped later events — including high-value
xray.crash and node.down notifications unrelated to the slow handler.

Hand each delivered event to every handler in its own goroutine so a
blocking subscriber can no longer stall delivery to the others. safeCall
already recovers panics, so a detached handler cannot take down the bus.

* fix(integration): cap WARP API response body size

doWarpRequest read the response with an unbounded io.ReadAll, unlike the
sibling NordVPN client which already caps every read at maxResponseSize.
A hostile panel egress proxy or a MITM on the Cloudflare WARP endpoint
could stream an arbitrarily large body and force the panel into an
unbounded allocation. Wrap the body in an io.LimitReader(maxResponseSize)
to match the NordVPN client.

* fix(email): bound every SMTP step with a connection deadline

The "starttls"/"none" transport delivered through net/smtp.SendMail, which
dials with an untimed net.Dial and never sets a socket deadline. When an
SMTP server accepted the TCP connection but then stalled (or was a
blackhole), the caller was released by Send's 30s select, but the sender
goroutine and its socket stayed blocked until the OS TCP timeout — minutes
per notification, leaking a goroutine and a connection each time.
sendWithTLS dialed with a timeout but likewise armed no deadline on the
protocol phase, and TestConnection (called synchronously from the settings
handler, with no select guard) could hang the request indefinitely.

Replace SendMail with sendPlain, which dials with smtpConnectTimeout and
arms conn.SetDeadline(smtpDeadline) before the greeting read, preserving
SendMail's opportunistic STARTTLS upgrade. Arm the same deadline in
sendWithTLS and TestConnection so every SMTP step is bounded.

* fix(server): guard access-log parser against malformed lines

GetXrayLogs split each Xray access-log line on whitespace and then read
fixed offsets — parts[1] for the timestamp and parts[i+1] after the "from",
"accepted" and "email:" markers — without checking the line had that many
fields. A truncated or malformed line (the logged destination is
attacker-influenced) indexed past the slice and panicked; the panel handler
returned a 500 via Gin's recovery.

Extract the per-line field parsing into parseAccessLogFields and length
guard every positional lookup so a short line yields a partial entry
instead of panicking.

* fix(server): guard xray key-generator output parsing

GetNewX25519Cert, GetNewmldsa65 and GetNewmlkem768 parsed xray's stdout by
reading lines[0], lines[1] and each line's second colon-separated field
without any length check — unlike GetNewEchCert, which already guards its
line count. If the xray binary printed fewer than two lines or reformatted
its labels (a version change, or a silent failure that emitted nothing),
the fixed slice index panicked and the handler 500'd.

Extract the shared parsing into parseXrayKeyPairOutput, which length guards
the line count and each label split and returns an error instead of
panicking, then route all three generators through it.

* fix(tgbot): stop auto-deleted messages from resetting wizard state

SendMsgToTgbotDeleteAfter spawns a goroutine that, after the display delay,
deleted the transient message and then unconditionally cleared the chat's
conversation state. Every caller that ends a wizard step already clears the
state synchronously, so that call was redundant — and harmful: if within
the delay the user advanced to the next step (a callback sets a fresh
awaiting_* state), the late goroutine wiped it, and the user's next message
fell through unrecognized, silently dropping their input.

Move the delayed deletion into deleteMessageAfterDelay, which only removes
the message and no longer touches the conversation state. Guard
deleteMessageTgBot against a nil bot so the deletion path is unit-testable.

* fix(frontend): refetch a fresh CSRF token on 403 instead of reusing the stale meta tag

On a 403 to an unsafe method the client cleared its cached CSRF token and
called ensureCsrfToken to retry. But ensureCsrfToken prefers the
<meta name="csrf-token"> tag baked into the page, which the production
panel always injects, so the "refresh" re-read the same stale token and the
/csrf-token refetch was never reached — the retry re-sent the token that had
just been rejected and the save failed with an error toast.

The token lives in the session and rotates when the session is regenerated
(for example re-login in another tab), leaving the tab's baked-in meta token
stale. Fetch the current token straight from /csrf-token in the 403 branch so
the retry uses the authoritative server value. The existing tests only passed
because they strip the meta tag; the new test keeps a stale tag present.

* fix(frontend): surface backend error text from failed requests

HttpUtil.get/post read the thrown HttpError body as response.data.message,
but the backend error envelope (entity.Msg) serializes its text as msg. On
any non-2xx JSON response the real reason was therefore dropped and the
operator saw only the generic "Request failed with status N" toast.

Read response.data.msg first (keeping message and the native error text as
fallbacks). The sibling test had pinned the wrong body shape ({ message });
correct it to the real backend shape ({ success:false, msg }) so it exercises
the actual envelope.

* fix(frontend): share one WebSocket connection across bridge and hooks

websocketBridge.ts and useWebSocket.ts each declared their own
module-scoped sharedClient plus an identical getSharedClient, so the
"shared" client was not shared between them: whenever a page using
useWebSocket (Clients/Inbounds) mounted alongside the always-mounted
bridge, the panel opened two sockets to /ws. The server then pushed every
traffic/stats/nodes/inbounds snapshot to both, doubling WebSocket bandwidth
and running two independent reconnect loops, and the hook's socket was never
disconnected on unmount.

Hoist a single getSharedWebSocketClient into api/websocket.ts and route both
the bridge and the hook through it, so exactly one connection is opened.

* fix(frontend): guard the outbounds WebSocket handler against non-array payloads

onOutbounds wrote the raw WebSocket payload straight into the
outboundsTraffic cache, unlike the sibling onNodes/onInbounds handlers which
first check Array.isArray. A malformed non-array push (for example an object)
would land in the cache with staleTime Infinity; consumers that call
.find()/.map() on the outbounds list would then throw and crash the Outbounds
tab. Add the same Array.isArray guard so a bad push is ignored.

* fix(frontend): key the node table by the computed row key, not id

The desktop node table used rowKey="id", but transitive sub-nodes (the
read-only rows surfaced from downstream nodes) all carry id 0, so a topology
with two or more transitive rows gave React duplicate keys. antd's rowKey
prop overrides the row object's own computed `key` (`t-${guid}` for
transitive rows, the numeric id otherwise), so the unique key the code
already builds was ignored — causing row-state/DOM mis-association on any
re-render (heartbeat refetch, address-eye toggle). The mobile card path
already keyed by record.key.

Key the table by "key" so transitive rows get their distinct t-${guid}
identity; direct nodes keep key === id, so row selection (filtered to numeric
keys) is unchanged.

* fix(frontend): map routing row actions through the rule's real index

The routing table hides balancer-loopback rules (`_bl_*`) but keeps each
visible row's original index in `key`, then handed antd's positional row
index straight to edit/delete/toggle/move/drag — all of which mutate the
full, unfiltered routing.rules array. Once a hidden loopback rule precedes a
visible one (e.g. a balancer whose fallback is another balancer, plus any
rule added afterwards), the positional index no longer matches the array
index, so deleting or editing a rule silently hit the wrong one — including
destroying the loopback rule that keeps the balancer alive.

Add originalRuleIndex to translate a positional row index back through the
row's `key`, and route every mutating handler (openEdit, confirmDelete,
toggleRule, moveUp/moveDown, drag) through it. When no loopback rows are
hidden the mapping is the identity, so ordinary configs are unaffected.

* fix(frontend): map outbound row actions through the outbound's real index

The outbounds table hides balancer-loopback outbounds (`_bl_*`) but keeps
each visible row's original index in `key`, then passed antd's positional
row index to edit/delete/move and to the per-row probe (onTest) and its
result lookup — all of which address the full, unfiltered outbounds array.
Once a hidden loopback outbound precedes a visible one, the positional index
diverges from the array index, so deleting or editing an outbound hit the
wrong one (its deletion-impact plan and removal targeting the wrong entry),
and the test button probed / showed results against the wrong outbound.

Add originalOutboundIndex and route the mutating handlers through it; key
the probe trigger and test-result columns by record.key. With no loopback
rows hidden the mapping is the identity, so ordinary configs are unaffected.

* fix(frontend): tolerate a malformed happyEyeballs value in the Xray Basics tab

BasicsTab derived directHappyEyeballs by calling HappyEyeballsSchema.parse
during render, guarding only against null/non-object. A wrong-typed field
(e.g. happyEyeballs.tryDelayMs as a string) or any other shape mismatch —
reachable via the Complete Template JSON editor or an imported config — threw
straight out of render, white-screening the default Xray landing tab.

Use safeParse and fall back to null so a bad value degrades to "no override"
instead of crashing the page.

* fix(frontend): preserve routing-rule fields the form does not surface

The rule form rebuilt the rule from a fixed literal of only the fields it
edits, and RoutingTab replaces the rule wholesale on confirm. Fields the
form never exposes — localPort, localIP, process, ruleTag, webhook — are in
the rule schema and can arrive via the advanced JSON editor or Import Rules;
opening such a rule in the form and saving silently dropped them.

Carry over every key of the original rule the form does not manage before
applying the form-derived fields, so an edit only touches what it surfaces.

* fix(frontend): re-sync the sniffing island when its value changes externally

The sniffing config editor froze its seed value at mount and only watched
its own inner AntD form, never reflecting a later change to the shared RHF
`sniffing` path. Because the inbound form mounts every tab with
forceRender, the friendly Sniffing tab and the Advanced JSON editor are live
at once: editing sniffing in the JSON editor updated the RHF value but not
the frozen island, so the next interaction with the friendly tab emitted the
stale value and silently discarded the JSON edit.

Add an effect that pushes an external value change into the inner form,
guarded by the same lastEmitted marker the emit path uses so the island
never re-seeds from its own echo and no update loop forms.

* fix(frontend): don't drift a client's byte quota on a no-op save

The quota field shows the total in GB rounded to two decimals; editing a
client and saving converted that display value straight back to bytes. A
byte total not aligned to 0.01 GB — one set via the API or an import — was
therefore rewritten to the rounded value on any save that never touched the
field, losing a few MB each time.

Add resolveTotalBytes: keep the original byte total when the displayed GB
still matches it, and only re-derive from GB when the user actually changed
the field.

* fix(eventbus): deliver events on a bounded per-subscriber worker

The previous fix dispatched each event to every subscriber with a bare
`go safeCall`. That unblocked the dispatch loop, but removed the bus's
backpressure: under a login-attempt flood (which both notifier subscribers
process without rate-limiting) with email/Telegram enabled, every attempt
spawned handler goroutines that each block on network I/O for up to ~30s,
with no bound — a goroutine and outbound-connection storm. It also let a
subscriber's handler run concurrently with itself, racing the Telegram
notifier's lazily-cached hostname.

Give each subscriber its own bounded queue drained by a single worker
goroutine. Dispatch does a non-blocking send per subscriber (dropping only
that subscriber's event when its queue is full), so a slow subscriber still
can't stall the others, concurrency is bounded to one in-flight handler per
subscriber, per-subscriber event order is preserved, and Stop again waits
for in-flight handlers to finish.

* fix(frontend): map outbound mobile-card actions through the real index too

The desktop outbounds table was keyed by the outbound's real index, but the
mobile card list was left keying the probe trigger and every test-state
lookup by the positional row index. With a hidden balancer-loopback outbound
present, tapping Check on a mobile card probed the wrong outbound and the
Test-All results landed on the wrong card. Key onTest and the
testResult/isTesting reads by record.key, matching the desktop columns.

* fix(frontend): meet WCAG AA contrast on the config-block link text

The Storybook accessibility test flagged the share-link <code> block: with no
explicit color it inherited a muted grey that renders as #888888 on the
#f8f8f8 tertiary-fill background in CI's Chromium — a 3.33:1 contrast, below
the 4.5:1 AA threshold. Set the text to the theme's primary text token so the
colour is explicit and high-contrast in both light and dark themes instead of
depending on an inherited value that varies by browser.

* style(sub): simplify a negated conjunction to satisfy staticcheck QF1001

golangci-lint (staticcheck QF1001) flagged the `!(a && b)` guard in
expandSegment. Rewrite it via De Morgan's law to the equivalent
`!a || !b` form so the linter passes; behavior is unchanged.

* fix: close panics and races the audit's own fixes left nearby

Second-pass review of the 54-commit self-correcting audit. Each item below
was confirmed by reading the surrounding source (and, where practical, the
pre-fix code) before being changed; regression tests are included for every
behavioral fix.

Concurrency:
- eventbus: Bus.Subscribe called wg.Add with no synchronization against a
  concurrent Bus.Stop's wg.Wait, a real "WaitGroup misuse" panic risk (e.g. a
  Telegram-bot settings save racing panel shutdown/restart). Stop now flips a
  mu-guarded `stopped` flag before waiting, and Subscribe checks it under the
  same lock, so Add and Wait can no longer race.

Security:
- login_limiter: evictForRoom's fallback eviction picked an arbitrary map
  key, including ones still under an active cooldown - an attacker flooding
  /login with fresh usernames could evict their own (or anyone's) blocked
  record and reset the lockout. The fallback now skips actively-blocked
  records, only falling back to an unconditional evict if the map is
  somehow entirely full of active blocks (preserves the hard memory cap).

Subscription-endpoint panics (reachable by any client hitting /sub):
- internal/sub/service.go: applyPathAndHostParams/Obj (ws/httpupgrade/xhttp
  with no path settings object) and the TLS alpn readers in three places
  used unchecked type assertions - exactly the bug class abab7cd0 patched
  elsewhere in the same switch statements, just not these call sites.
- internal/sub/json_service.go, clash_service.go: the externalProxy loops
  in the JSON and Clash generators used unchecked assertions on a
  legacy/admin-supplied field (missing "port", non-object entry, etc.).
- internal/sub/json_service.go: realityData's shortId/serverName selection
  could assert a non-string array element.

Other correctness:
- client_traffic.go: ResetAllTraffics (touched by 3eb214d0) still skipped
  clearing NodeClientTraffic node-sync baselines, unlike its sibling reset
  paths in the same file - a node's next sync would re-add pre-reset delta
  on top of the freshly-zeroed counter.
- inbound_traffic.go: the traffic-tick tx's Commit/Rollback errors were
  silently discarded; now logged so a backend-level commit failure (e.g. an
  aborted Postgres tx from a best-effort helper) doesn't masquerade as a
  successful tick.
- outbound_subscription.go: the new subscriptionFetchClient doc comment was
  wedged between fetchAndStore's existing comment and fetchAndStore itself,
  leaving fetchAndStore undocumented and the comment describing the wrong
  function.

Convention cleanup:
- Removed narrative // comments added by the audit that violate this repo's
  no-inline-comment rule (mostly narrating the specific bug/fix rather than
  a lasting contract, and mostly on new Test functions, which this repo's
  existing tests never comment) - calibrated against this exact codebase's
  own pre-existing comment style so legitimate godoc-style doc comments
  were left alone.

---------

Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
2026-07-17 00:33:06 +02:00

2241 lines
117 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
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": "创建",
"add": "添加",
"remove": "移除",
"update": "更新",
"copy": "复制",
"copied": "已复制",
"more": "更多",
"download": "下载",
"regenerate": "重新生成",
"jsonEditor": "JSON 编辑器",
"downloadImage": "下载图片",
"sort": "排序",
"remark": "备注",
"enable": "启用",
"protocol": "协议",
"search": "搜索",
"filter": "筛选",
"all": "全部",
"from": "从",
"to": "到",
"done": "完成",
"loading": "加载中...",
"refresh": "刷新",
"clear": "清除",
"second": "秒",
"minute": "分钟",
"hour": "小时",
"day": "天",
"check": "查看",
"indefinite": "无限期",
"unlimited": "无限制",
"none": "无",
"qrCode": "二维码",
"info": "更多信息",
"edit": "编辑",
"delete": "删除",
"reset": "重置",
"noData": "无数据。",
"copySuccess": "复制成功",
"sure": "确定",
"encryption": "加密",
"useIPv4ForHost": "使用 IPv4 连接主机",
"transmission": "传输",
"host": "主机",
"path": "路径",
"camouflage": "混淆",
"status": "状态",
"enabled": "开启",
"disabled": "关闭",
"depleted": "耗尽",
"depletingSoon": "即将耗尽",
"offline": "离线",
"online": "在线",
"domainName": "域名",
"monitor": "监听",
"certificate": "数字证书",
"fail": "失败",
"comment": "评论",
"success": "成功",
"lastOnline": "上次在线",
"getVersion": "获取版本",
"install": "安装",
"clients": "客户端",
"usage": "使用情况",
"twoFactorCode": "代码",
"remained": "剩余",
"security": "安全",
"secAlertTitle": "安全警报",
"secAlertSsl": "此连接不安全。在激活 TLS 进行数据保护之前,请勿输入敏感信息。",
"secAlertConf": "某些设置易受攻击。建议加强安全协议以防止潜在漏洞。",
"secAlertSSL": "面板缺少安全连接。请安装 TLS 证书以保护数据安全。",
"secAlertPanelPort": "面板默认端口存在安全风险。请配置随机端口或特定端口。",
"secAlertPanelURI": "面板默认 URI 路径不安全。请配置复杂的 URI 路径。",
"secAlertSubURI": "订阅默认 URI 路径不安全。请配置复杂的 URI 路径。",
"secAlertSubJsonURI": "订阅 JSON 默认 URI 路径不安全。请配置复杂的 URI 路径。",
"emptyDnsDesc": "未添加DNS服务器。",
"emptyFakeDnsDesc": "未添加Fake DNS服务器。",
"emptyBalancersDesc": "未添加负载均衡器。",
"emptyReverseDesc": "未添加反向代理。",
"somethingWentWrong": "出了点问题",
"subscription": {
"title": "订阅信息",
"subId": "订阅 ID",
"status": "状态",
"downloaded": "已下载",
"uploaded": "已上传",
"expiry": "到期",
"totalQuota": "总配额",
"individualLinks": "单独链接",
"active": "启用",
"inactive": "停用",
"unlimited": "无限制",
"noExpiry": "无到期",
"copyAllConfigs": "复制全部配置",
"copyAllConfigsCopied": "已复制全部配置",
"email": "邮箱"
},
"menu": {
"theme": "主题",
"dark": "暗色",
"ultraDark": "超暗色",
"dashboard": "系统状态",
"inbounds": "入站",
"clients": "客户端",
"groups": "分组",
"nodes": "节点",
"settings": "面板设置",
"xray": "Xray 配置",
"routing": "路由",
"outbounds": "出站",
"apiDocs": "API 文档",
"logout": "退出登录",
"link": "管理",
"donate": "捐赠",
"hosts": "主机",
"docs": "文档",
"openMenu": "打开菜单"
},
"pages": {
"login": {
"hello": "你好",
"title": "欢迎",
"loginAgain": "登录时效已过,请重新登录",
"toasts": {
"invalidFormData": "数据格式错误",
"emptyUsername": "请输入用户名",
"emptyPassword": "请输入密码",
"wrongUsernameOrPassword": "用户名、密码或双重验证码无效。",
"successLogin": "您已成功登录您的账户。"
}
},
"index": {
"title": "系统状态",
"cpu": "CPU",
"logicalProcessors": "逻辑处理器",
"frequency": "频率",
"swap": "交换空间",
"storage": "存储",
"memory": "内存",
"threads": "线程",
"xrayStatus": "Xray",
"stopXray": "停止",
"restartXray": "重启",
"xraySwitch": "版本",
"xrayUpdates": "Xray 更新",
"xraySwitchClick": "选择你要切换到的版本",
"xraySwitchClickDesk": "请谨慎选择,因为较旧版本可能与当前配置不兼容",
"updatePanel": "更新面板",
"panelUpdateDesc": "这将把 3X-UI 更新到最新版本并重启面板服务。",
"currentPanelVersion": "当前面板版本",
"latestPanelVersion": "最新面板版本",
"panelUpToDate": "面板已是最新",
"devChannel": "开发通道",
"devChannelWarning": "开发版会跟踪 main 的每次提交,并非稳定版本,且无法自动降级。",
"currentCommit": "当前提交",
"latestCommit": "最新提交",
"updateChannelChanged": "更新通道已切换",
"upToDate": "已是最新",
"xrayStatusUnknown": "未知",
"xrayStatusRunning": "运行中",
"xrayStatusStop": "停止",
"xrayStatusError": "错误",
"xrayErrorPopoverTitle": "运行Xray时发生错误",
"operationHours": "系统正常运行时间",
"systemHistoryTitle": "系统历史",
"historyTitleCpu": "CPU 使用率",
"historyTitleMem": "内存使用率",
"historyTitleNetwork": "网络带宽",
"historyTitlePackets": "网络数据包",
"historyTitleDisk": "磁盘 I/O",
"historyTitleOnline": "在线客户端",
"historyTitleLoad": "系统平均负载(1 分钟 / 5 分钟 / 15 分钟)",
"historyTitleConnections": "活动连接 (TCP / UDP)",
"historyTitleDiskUsage": "磁盘空间使用率",
"historyTabBandwidth": "带宽",
"historyTabPackets": "数据包",
"historyTabDisk": "磁盘 I/O",
"historyTabOnline": "在线",
"historyTabLoad": "负载",
"historyTabConnections": "连接数",
"historyTabDiskUsage": "磁盘使用量",
"charts": "图表",
"xrayMetricsTitle": "Xray 指标",
"xrayTitleHeap": "已分配的堆内存",
"xrayTitleSys": "向操作系统保留的内存",
"xrayTitleObjects": "存活的堆对象",
"xrayTitleGcCount": "已完成的 GC 周期",
"xrayTitleGcPause": "GC 暂停时间",
"xrayTitleObservatory": "出站连接健康状态",
"xrayTabHeap": "堆",
"xrayTabSys": "系统",
"xrayTabObjects": "对象",
"xrayTabGcCount": "GC 次数",
"xrayTabGcPause": "GC 暂停",
"xrayTabObservatory": "观测站",
"xrayMetricsDisabled": "未配置 Xray 指标端点",
"xrayMetricsHint": "在 xray 配置中添加顶级 metrics 块,tag 为 metrics_out,listen 为 127.0.0.1:11111,然后重启 xray。",
"xrayObservatoryEmpty": "暂无 Observatory 数据",
"xrayObservatoryHint": "在 xray 配置中添加 observatory 块,列出要探测的出站 tag,然后重启 xray。",
"xrayObservatoryTagPlaceholder": "选择出站",
"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版本更改为#version#。",
"xraySwitchVersionPopover": "Xray 更新成功",
"panelUpdateDialog": "您确定要更新面板吗?",
"panelUpdateDialogDesc": "这将把 3X-UI 更新到 #version# 并重启面板服务。",
"panelUpdateCheckPopover": "面板更新检查失败",
"panelUpdateStartedPopover": "已开始更新面板",
"panelUpdateFailedTitle": "面板更新失败",
"panelUpdateFailedDesc": "更新未成功完成。请检查服务器日志,或在命令行运行「x-ui update」。",
"panelUpdateUnknownTitle": "无法确认更新是否已完成",
"panelUpdateUnknownDesc": "面板未能及时返回结果。请刷新页面查看当前版本,或检查服务器日志。",
"geofileUpdateDialog": "您确定要更新地理文件吗?",
"geofileUpdateDialogDesc": "这将更新 #filename# 文件。",
"geofilesUpdateDialogDesc": "这将更新所有文件。",
"geofilesUpdateAll": "全部更新",
"geofileUpdatePopover": "地理文件更新成功",
"geodataTitle": "Geodata 自动更新",
"geodataHint": "Xray 会按计划下载这些文件并热重载,无需重启。URL 必须为 HTTPS。文件必须已存在于 bin 目录中,Xray 才能对其更新。",
"geodataCron": "更新计划 (cron)",
"geodataOutbound": "通过出站下载(可选)",
"geodataFile": "文件名",
"geodataAddFile": "添加文件",
"geodataSaveRestart": "保存并重启 Xray",
"geodataConfirmTitle": "保存 geodata 设置?",
"geodataConfirmContent": "将更新 Xray 配置模板并重启 Xray。",
"geodataInvalidUrl": "每个文件都需要 HTTPS 地址。",
"geodataInvalidFile": "文件名必须是纯文件名,例如 geosite_custom.dat(不能包含路径)。",
"geodataInvalidCron": "Cron 必须为 5 段,例如 0 4 * * *",
"geodataEmpty": "尚未配置文件。路由规则中可通过 ext:geosite_custom.dat:category 引用文件。",
"dontRefresh": "安装中,请勿刷新此页面",
"logs": "日志",
"accessLogs": "访问日志",
"autoUpdate": "自动更新",
"config": "配置",
"backup": "备份",
"backupTitle": "备份和恢复",
"exportDatabase": "备份",
"exportDatabaseDesc": "点击下载包含当前数据库备份的 .db 文件到您的设备。同一文件也可以恢复到运行 PostgreSQL 的面板中。",
"importDatabase": "恢复",
"importDatabaseDesc": "点击选择并上传设备中的 .db 备份或迁移导出文件(.dump)以恢复数据库。",
"importDatabaseSuccess": "数据库导入成功",
"importDatabaseError": "导入数据库时出错",
"readDatabaseError": "读取数据库时出错",
"getDatabaseError": "检索数据库时出错",
"getConfigError": "检索配置文件时出错",
"backupPostgresNote": "此面板运行在 PostgreSQL 上。「备份」会下载一个 pg_dump 归档(.dump),「恢复」会通过 pg_restore 重新载入。「恢复」也接受 SQLite 数据库(.db)或 SQLite 迁移导出文件,并将其数据导入 PostgreSQL。服务器需要安装 PostgreSQL 客户端工具(pg_dump 和 pg_restore)。",
"exportDatabasePgDesc": "点击将当前数据库的 PostgreSQL 转储(.dump)下载到您的设备。",
"importDatabasePgDesc": "点击选择并上传 PostgreSQL 备份(.dump)、SQLite 数据库(.db)或 SQLite 迁移导出文件以恢复您的数据库。此操作将替换所有当前数据。",
"migrationDownload": "下载迁移文件",
"migrationDownloadPgDesc": "点击下载由 PostgreSQL 数据构建的 .db SQLite 数据库,可用于在 SQLite 上运行本面板。"
},
"inbounds": {
"title": "入站",
"totalDownUp": "总上传 / 下载",
"totalUsage": "总用量",
"inboundCount": "入站数量",
"operate": "菜单",
"enable": "启用",
"remark": "备注",
"node": "节点",
"deployTo": "部署到",
"localPanel": "本地面板",
"fallbacks": {
"title": "Fallbacks",
"help": "当此入站的连接未匹配任何客户端时,将其路由到其他位置。在下方选择一个子入站,可从其传输方式自动填充路由字段(SNI / ALPN / Path / xver);或将选择框留空并直接设置 Dest(例如 8080 或 127.0.0.1:8080),以路由到 Nginx 等外部服务器。每个子入站应监听 127.0.0.1security=none。",
"empty": "暂无回落",
"add": "添加回落",
"pickInbound": "选择一个入站",
"matchAny": "任意",
"destPlaceholder": "自动(子入站 listen:port",
"rederive": "从子入站重新填充",
"rederived": "已从子入站重新填充",
"editAdvanced": "编辑路由字段",
"hideAdvanced": "隐藏高级",
"quickAddAll": "一键添加所有可用入站",
"quickAdded": "已添加 {n} 条回落",
"quickAddedNone": "没有可添加的新入站",
"routesWhen": "当满足条件时路由",
"defaultCatchAll": "默认 — 兜底匹配其他所有",
"needsTls": "在“安全”标签页选择 TLS 或 Reality 后即可配置回落(仅限 RAW 上的 VLESS/Trojan)。"
},
"protocol": "协议",
"port": "端口",
"portMap": "端口映射",
"traffic": "流量",
"speed": "速度",
"details": "详细信息",
"transportConfig": "传输",
"expireDate": "到期时间",
"createdAt": "创建时间",
"updatedAt": "更新时间",
"resetTraffic": "重置流量",
"addInbound": "添加入站",
"generalActions": "通用操作",
"modifyInbound": "修改入站",
"deleteInbound": "删除入站",
"deleteInboundContent": "确定要删除入站吗?",
"deleteConfirmTitle": "删除入站 \"{remark}\"",
"deleteConfirmContent": "将删除此入站及其所有客户端。该操作不可撤销。",
"resetConfirmTitle": "重置 \"{remark}\" 的流量?",
"resetConfirmContent": "将此入站的上/下行计数器清零。",
"selectedCount": "已选 {count} 项",
"selectAll": "全选",
"bulkDeleteConfirmTitle": "删除 {count} 个入站?",
"bulkDeleteConfirmContent": "将删除所选入站及其所有客户端。该操作不可撤销。",
"cloneConfirmTitle": "克隆入站 \"{remark}\"",
"cloneConfirmContent": "使用新端口和空客户端列表创建副本。",
"delAllClients": "删除所有客户端",
"delAllClientsConfirmTitle": "从 \"{remark}\" 中删除全部 {count} 个客户端?",
"delAllClientsConfirmContent": "从此入站中移除每个客户端并丢弃其流量记录。入站本身将保留。此操作无法撤销。",
"attachClients": "附加客户端到…",
"addClientsToGroup": "将客户端添加到分组…",
"attachClientsTitle": "从 “{remark}” 附加客户端",
"attachClientsDesc": "将相同的 {count} 个客户端(相同 UUID/密码和共享流量)附加到选定的入站。它们仍保留在此入站中。",
"attachClientsTargets": "目标入站",
"attachClientsNoTargets": "没有可附加的其他兼容入站。",
"attachClientsResult": "已附加 {attached},已跳过 {skipped}。",
"attachClientsResultMixed": "已附加 {attached},已跳过 {skipped},错误 {errors}。",
"attachClientsSelectLabel": "要附加的客户端",
"attachClientsSearchPlaceholder": "搜索邮箱或备注",
"attachClientsStatusDisabled": "已禁用",
"attachClientsSelectedCount": "已选 {selected}/{total}",
"attachExistingClients": "附加现有客户端…",
"attachExistingTitle": "将现有客户端附加到 “{remark}”",
"attachExistingDesc": "将现有客户端(可用 {count} 个)附加到此入站 — 相同 UUID/密码和共享流量。已在此入站的客户端将被跳过。",
"attachExistingNoClients": "尚无客户端。请先创建客户端,然后在此附加。",
"attachExistingStatusAttached": "已附加",
"detachClients": "分离客户端",
"detachClientsTitle": "从 “{remark}” 分离客户端",
"detachClientsDesc": "仅从此入站移除选中的客户端。客户端记录保留(使用 Delete 完全移除)。源共有 {count} 个客户端。",
"detachClientsResult": "已分离 {detached},已跳过 {skipped}。",
"detachClientsResultMixed": "已分离 {detached},已跳过 {skipped},错误 {errors}。",
"detachClientsSelectLabel": "要分离的客户端",
"exportLinksTitle": "导出入站链接",
"exportSubsTitle": "导出订阅链接",
"exportAllLinksTitle": "导出所有入站链接",
"exportAllSubsTitle": "导出所有订阅链接",
"exportAllLinksFileName": "所有入站",
"exportAllSubsFileName": "所有入站-Subs",
"inboundJsonTitle": "入站 JSON",
"deleteClient": "删除客户端",
"deleteClientContent": "确定要删除客户端吗?",
"resetTrafficContent": "确定要重置流量吗?",
"copyLink": "复制链接",
"address": "地址",
"network": "网络",
"destinationPort": "目标端口",
"targetAddress": "目标地址",
"monitorDesc": "留空表示监听所有 IP",
"meansNoLimit": "= 无限制。(单位: GB)",
"totalFlow": "总流量",
"leaveBlankToNeverExpire": "留空表示永不过期",
"noRecommendKeepDefault": "建议保留默认值",
"certificatePath": "文件路径",
"certificateContent": "文件内容",
"publicKey": "公钥",
"privatekey": "私钥",
"clickOnQRcode": "点击二维码复制",
"client": "客户",
"export": "导出链接",
"clone": "克隆",
"cloneInbound": "克隆",
"cloneInboundContent": "此入站规则除端口(Port)、监听 IP(Listening IP)和客户端(Clients)以外的所有配置都将应用于克隆",
"cloneInboundOk": "创建克隆",
"resetAllTraffic": "重置所有入站流量",
"resetAllTrafficTitle": "重置所有入站流量",
"resetAllTrafficContent": "确定要重置所有入站流量吗?",
"resetInboundClientTraffics": "重置客户端流量",
"resetInboundClientTrafficTitle": "重置所有客户端流量",
"resetInboundClientTrafficContent": "确定要重置此入站客户端的所有流量吗?",
"resetAllClientTraffics": "重置所有客户端流量",
"resetAllClientTrafficTitle": "重置所有客户端流量",
"resetAllClientTrafficContent": "确定要重置所有客户端的所有流量吗?",
"delDepletedClients": "删除流量耗尽的客户端",
"delDepletedClientsTitle": "删除流量耗尽的客户端",
"delDepletedClientsContent": "确定要删除所有流量耗尽的客户端吗?",
"email": "邮箱",
"emailDesc": "电子邮件必须完全唯一",
"IPLimit": "IP 限制",
"IPLimitDesc": "如果数量超过设置值,则禁用入站流量。(0 = 禁用)",
"IPLimitlog": "IP 日志",
"IPLimitlogDesc": "IP 历史日志(要启用被禁用的入站流量,请清除日志)",
"IPLimitlogclear": "清除日志",
"setDefaultCert": "从面板设置证书",
"setDefaultCertEmpty": "面板尚未配置证书。请先在“设置”中设置。",
"streamTab": "传输",
"securityTab": "安全",
"sniffingTab": "嗅探",
"sniffingMetadataOnly": "仅元数据",
"sniffingRouteOnly": "仅路由",
"sniffingIpsExcluded": "排除的 IP",
"sniffingDomainsExcluded": "排除的域名",
"decryption": "解密",
"encryption": "加密",
"vlessAuthX25519": "X25519 (native)",
"vlessAuthMlkem768": "ML-KEM-768 (native)",
"vlessAuthX25519Xorpub": "X25519 (xorpub)",
"vlessAuthX25519Random": "X25519 (random)",
"vlessAuthMlkem768Xorpub": "ML-KEM-768 (xorpub)",
"vlessAuthMlkem768Random": "ML-KEM-768 (random)",
"vlessAuthCustom": "自定义",
"vlessAuthSelected": "已选择:{auth}",
"vlessAuthGenerate": "生成密钥",
"vlessAuthGenerateButton": "生成",
"advanced": {
"title": "入站 JSON 部分",
"subtitle": "完整入站 JSON 以及针对 settings、sniffing 和 streamSettings 的专用编辑器。",
"all": "全部",
"allHelp": "在单个编辑器中编辑包含所有字段的完整入站对象。",
"settings": "设置",
"settingsHelp": "Xray settings 块包装:",
"sniffing": "Sniffing",
"sniffingHelp": "Xray sniffing 块包装:",
"stream": "Stream",
"streamHelp": "Xray stream 块包装:",
"jsonErrorPrefix": "高级 JSON"
},
"telegramDesc": "请提供Telegram聊天ID。(在机器人中使用'/id'命令)或({'@'}userinfobot",
"subscriptionDesc": "要找到你的订阅 URL,请导航到“详细信息”。此外,你可以为多个客户端使用相同的名称。",
"subSortIndex": "订阅排序",
"same": "相同",
"inboundInfo": "入站信息",
"exportInbound": "导出入站规则",
"import": "导入",
"importInbound": "导入入站规则",
"periodicTrafficResetTitle": "流量重置",
"periodicTrafficResetDesc": "按指定间隔自动重置流量计数器",
"lastReset": "上次重置",
"periodicTrafficReset": {
"never": "从不",
"daily": "每日",
"weekly": "每周",
"monthly": "每月",
"hourly": "每小时"
},
"toasts": {
"obtain": "获取",
"updateSuccess": "更新成功",
"logCleanSuccess": "日志已清除",
"inboundsUpdateSuccess": "入站连接已成功更新",
"inboundUpdateSuccess": "入站连接已成功更新",
"inboundCreateSuccess": "入站连接已成功创建",
"bulkDeleted": "已删除 {count} 个入站",
"bulkDeletedMixed": "已删除 {ok} 个,失败 {failed} 个",
"inboundDeleteSuccess": "入站连接已成功删除",
"inboundClientAddSuccess": "已添加入站客户端",
"inboundClientDeleteSuccess": "入站客户端已删除",
"inboundClientUpdateSuccess": "入站客户端已更新",
"savedNodeOfflineWillSync": "已在本地保存。某个支撑节点离线或已禁用——重新连接后将同步此更改。",
"delDepletedClientsSuccess": "所有耗尽客户端已删除",
"resetAllClientTrafficSuccess": "客户端所有流量已重置",
"resetAllTrafficSuccess": "所有流量已重置",
"resetInboundClientTrafficSuccess": "流量已重置",
"resetInboundTrafficSuccess": "入站流量已重置",
"trafficGetError": "获取流量数据时出错",
"getNewX25519CertError": "获取X25519证书时出错。",
"getNewmldsa65Error": "获取mldsa65证书时出错。",
"getNewVlessEncError": "获取VlessEnc证书时出错。",
"scanRealityTargetError": "扫描 REALITY 目标失败。",
"scanRealityTargetFeasible": "目标可用 — 已填入目标和 SNI。",
"scanRealityTargetNotFeasible": "目标可达,但不适用于 REALITY。",
"invalidClientField": "客户端 {client}:字段 {field} — {reason}",
"invalidField": "{field} — {reason}",
"moreIssues": "{message} (另有 {count} 项)"
},
"form": {
"echSockopt": "ECH Sockopt",
"echSockoptTip": "Xray 获取 ECH 配置列表时所用连接的 Socket 选项(例如让该查询通过 dialerProxy 出站)。保持禁用则使用默认值。",
"curvePreferences": "曲线偏好",
"curvePreferencesTip": "限制服务器提供的 TLS 密钥交换曲线,并按偏好顺序排列(例如 X25519MLKEM768、X25519)。留空则使用 Xray-core 默认值。",
"masterKeyLog": "主密钥日志",
"masterKeyLogTip": "写入 TLS 主密钥的路径(SSLKEYLOGFILE 格式),用于配合 Wireshark 调试。生产环境请留空——任何拥有该文件的人都能解密流量。",
"verifyPeerCertByNameTip": "让客户端以此名称(而非 SNI)验证服务器证书。多个名称用逗号分隔。仅面板使用——会包含在分享链接中(vcn)。这是 allowInsecure 的现代替代方案,Xray 已在 2026-06-01 之后将其移除。",
"pinFromCert": "从此入站的证书填充",
"pinFromRemote": "通过 ping SNI 获取哈希(xray tls ping",
"pinFromRemoteNoSni": "请先设置 SNIserverName)才能 ping 远端证书。",
"pinFromRemoteFailed": "无法获取远端证书哈希。",
"limitFallback": "限制 Fallback",
"limitFallbackUpload": "限制 Fallback 上传",
"limitFallbackDownload": "限制 Fallback 下载",
"afterBytes": "起始字节数",
"afterBytesTip": "允许 fallback 以全速运行此字节数,之后开始限速。0 = 从第一个字节起就限速。",
"bytesPerSec": "每秒字节数",
"bytesPerSecTip": "在达到阈值后对 fallback 流量施加的速度上限(字节/秒),以防探测者把你的服务器当作通往目标的免费带宽。0 = 无限制(禁用此方向)。",
"burstBytesPerSec": "突发每秒字节数",
"burstBytesPerSecTip": "允许在稳定速率之上的短时突发额度(token-bucket 容量)。若低于“每秒字节数”,则会被提升至与之相同。",
"moveUp": "上移",
"moveDown": "下移",
"addAll": "全部添加",
"addAllFallbackTooltip": "为尚未连接的每个符合条件的入站添加一个 fallback 行",
"peers": "Peers",
"addPeer": "添加 peer",
"keepAlive": "Keep-alive",
"autoSystemRoutesTooltip": "仅 Windows。CIDR 会自动添加到系统路由表,以便匹配的流量通过 TUN。",
"autoOutboundsInterface": "自动出站接口",
"autoOutboundsInterfaceTooltip": "出站流量的物理接口。使用 'auto' 进行检测;设置 Auto system routes 时自动启用。",
"rewriteAddress": "重写地址",
"rewritePort": "重写端口",
"allowedNetwork": "允许的网络",
"followRedirect": "跟随重定向",
"accounts": "账户",
"allowTransparent": "允许透明",
"encryptionMethod": "加密方法",
"fakeTlsDomain": "FakeTLS 域名 (SNI)",
"mtprotoSecret": "密钥",
"mtgDomainFrontingIp": "域前置 IP",
"mtgDomainFrontingPort": "域前置端口",
"mtgDomainFrontingProxyProtocol": "域前置 PROXY 协议",
"mtgDomainFrontingHint": "mtg 转发非 Telegram 流量的目标——例如你的 NGINX 伪装站点。留空 IP 则通过 DNS 解析 FakeTLS 域名;默认端口为 443。",
"mtgProxyProtocolListener": "接受 PROXY 协议(监听器)",
"mtgPreferIp": "IP 优先级",
"mtgDebug": "调试日志",
"mtgRouteThroughXray": "通过 Xray 路由",
"mtgRouteThroughXrayHint": "让此代理的 Telegram 流量经过 Xray,以应用您的路由规则。mtg 附属进程会通过带有此入站标签的本地 SOCKS 桥接出站;在路由选项卡中引用该标签即可设置高级规则。",
"mtgRouteOutbound": "出站",
"mtgRouteOutboundHint": "可选。强制 Telegram 流量经由此出站(或负载均衡器)发出。留空则由您的路由规则决定。",
"mtgRouteOutboundPlaceholder": "使用路由规则",
"mtprotoFakeTlsDomainHint": "生成新客户端密钥时使用的默认 FakeTLS 域名。每个客户端可使用各自的域名。",
"mtgThrottleMaxConnections": "最大连接数",
"mtgThrottleMaxConnectionsHint": "按公平分配限制所有用户的并发连接数。0 表示不限制。",
"mtgAdTagInvalid": "广告标签必须为 32 位十六进制字符。",
"mtgPublicIpv4": "公网 IPv4",
"mtgPublicIpv6": "公网 IPv6",
"mtgPublicIpHint": "本服务器可访问的公网地址,供广告标签的中间代理使用。留空则由 mtg 自动检测。",
"visionTestseed": "Vision testseed",
"version": "版本",
"udpIdleTimeout": "UDP 空闲超时 (s)",
"masquerade": "伪装",
"type": "类型",
"upstreamUrl": "Upstream URL",
"rewriteHost": "重写 Host",
"skipTlsVerify": "跳过 TLS 验证",
"directory": "目录",
"statusCode": "状态码",
"body": "Body",
"headers": "请求头",
"proxyProtocol": "Proxy Protocol",
"requestVersion": "请求版本",
"requestMethod": "请求方法",
"requestPath": "请求路径",
"requestHeaders": "请求头",
"responseVersion": "响应版本",
"responseStatus": "响应状态",
"responseReason": "响应原因",
"responseHeaders": "响应头",
"heartbeatPeriod": "心跳周期",
"serviceName": "服务名",
"authority": "Authority",
"multiMode": "多模式",
"maxBufferedUpload": "最大缓冲上传",
"maxUploadSize": "最大上传大小 (字节)",
"streamUpServer": "Stream-Up 服务器",
"serverMaxHeaderBytes": "服务器最大头字节",
"paddingBytes": "Padding 字节",
"uplinkHttpMethod": "Uplink HTTP 方法",
"paddingObfsMode": "Padding 混淆模式",
"paddingKey": "Padding Key",
"paddingHeader": "Padding Header",
"paddingPlacement": "Padding 位置",
"paddingMethod": "Padding 方法",
"sessionPlacement": "Session 位置",
"sessionKey": "Session Key",
"sessionIDTable": "会话 ID 字符表",
"sessionIDTableHint": "生成会话 ID 使用的字符集:预定义名称(ALPHABET、Base62、hex、number 等)或字面 ASCII 字符串。留空则使用 xray-core 默认值。",
"sessionIDLength": "会话 ID 长度",
"sessionIDLengthHint": "生成会话 ID 的长度或范围(如 8-16)。仅在设置了会话 ID 字符表时生效;最小值必须大于 0。",
"sequencePlacement": "Sequence 位置",
"sequenceKey": "Sequence Key",
"uplinkDataPlacement": "Uplink 数据位置",
"uplinkDataKey": "Uplink 数据 Key",
"noSseHeader": "无 SSE 头",
"ttiMs": "TTI (ms)",
"uplinkMbps": "上行 (MB/s)",
"downlinkMbps": "下行 (MB/s)",
"cwndMultiplier": "CWND 倍数",
"maxSendingWindow": "最大发送窗口",
"externalProxy": "外部代理",
"forceTls": "强制 TLS",
"fingerprint": "指纹",
"defaultOption": "默认",
"routeMark": "Route Mark",
"tcpKeepAliveInterval": "TCP Keep Alive 间隔",
"tcpKeepAliveIdle": "TCP Keep Alive Idle",
"tcpMaxSeg": "TCP Max Seg",
"tcpUserTimeout": "TCP User Timeout",
"tcpWindowClamp": "TCP Window Clamp",
"tcpWindowClampHint": "留 0 使用操作系统默认值。非零值会限制通告的 TCP 接收窗口;像 600 这样的值(来自 Xray 文档示例)在高延迟链路上可能导致吞吐量骤降。",
"tcpFastOpen": "TCP Fast Open",
"multipathTcp": "Multipath TCP",
"penetrate": "Penetrate",
"v6Only": "仅 V6",
"tcpCongestion": "TCP Congestion",
"dialerProxy": "Dialer Proxy",
"trustedXForwardedFor": "可信 X-Forwarded-For",
"trustedXForwardedForHint": "信任此请求头来获取真实客户端 IP(例如 Cloudflare CDN 后的 CF-Connecting-IP)。仅在 WebSocket、HTTPUpgrade、XHTTP 和 gRPC 传输上生效。留空则忽略转发头。",
"proxyProtocolHint": "接受 PROXY protocol 头,从上游 L4 隧道或中继(HAProxy、gost、nginx-stream、Xray dokodemo-door)或 Cloudflare Spectrum 获取真实客户端 IP。上游必须发送 PROXY protocol。适用于 TCP、WebSocket、HTTPUpgrade 和 gRPC;不适用于 mKCP。",
"realClientIp": "真实客户端 IP",
"realClientIpHint": "当流量通过 CDN 或中继到达此入站时,获取访客的真实 IP,而不是记录中间节点的地址。选择一个预设以自动填写下方对应的 sockopt 字段。这些字段绝不会在订阅中发送给客户端。",
"realClientIpPresetOff": "关闭 / 直连",
"realClientIpPresetCloudflare": "Cloudflare CDN",
"realClientIpPresetProxyProtocol": "L4 中继 / Spectrum (PROXY)",
"realClientIpTrustedHeaderTransportWarn": "Trusted X-Forwarded-For 仅在 WebSocket、HTTPUpgrade 和 XHTTP 上生效。在当前传输上此请求头将被忽略。",
"realClientIpProxyProtocolTransportWarn": "PROXY protocol 不支持此传输(mKCP)。请使用 TCP/RAW、WebSocket、HTTPUpgrade、gRPC 或 XHTTP。",
"addressPortStrategy": "地址+端口策略",
"tryDelayMs": "尝试延迟 (ms)",
"prioritizeIPv6": "IPv6 优先",
"interleave": "Interleave",
"maxConcurrentTry": "最大并发尝试",
"customSockopt": "自定义 sockopt",
"addCustomOption": "添加自定义选项",
"serverNameIndication": "SNI",
"cipherSuites": "Cipher Suites",
"autoOption": "自动",
"minMaxVersion": "最小/最大版本",
"rejectUnknownSni": "拒绝未知 SNI",
"disableSystemRoot": "禁用系统根",
"sessionResumption": "会话恢复",
"oneTimeLoading": "一次性加载",
"usageOption": "使用选项",
"buildChain": "构建证书链",
"echKey": "ECH key",
"echConfig": "ECH 配置",
"pinnedPeerCertSha256": "固定对端证书 SHA-256",
"pinnedPeerCertSha256Tip": "对端证书的 SHA-256 哈希(十六进制字符串,如 e8e2d3…),逗号分隔。仅面板使用 — 不写入服务器的 xray 配置,但会包含在分享链接中,以便客户端固定证书。",
"pinnedPeerCertSha256Placeholder": "十六进制哈希,逗号分隔",
"getNewEchCert": "获取新 ECH 证书",
"show": "显示",
"xver": "Xver",
"target": "目标",
"maxTimeDiff": "最大时间差 (ms)",
"minClientVer": "最小客户端版本",
"maxClientVer": "最大客户端版本",
"shortIds": "Short IDs",
"realityTargetHint": "必填。必须包含端口(例如 example.com:443)。没有端口时 Xray-core 将无法启动。",
"realityTargetRequired": "REALITY 目标为必填项",
"realityTargetNeedsPort": "REALITY 目标必须包含端口(例如 example.com:443",
"realityTargetInvalidPort": "REALITY 目标的端口无效",
"scan": "扫描",
"findTargets": "查找目标",
"scanModalTitle": "REALITY 目标扫描器",
"scanModalDesc": "验证某个域名,或扫描 IP / CIDR 范围,从证书中发现新的 REALITY 目标。留空则探测常用候选。",
"scanDiscoverPlaceholder": "IP、CIDR 或域名 — 留空使用常用候选",
"scanStatus": "状态",
"scanFeasible": "可用",
"scanNotFeasible": "不可用",
"scanCurve": "密钥交换",
"scanCert": "证书",
"scanCertInvalid": "不受信任",
"scanLatency": "延迟",
"scanUse": "使用",
"scanRescan": "重新扫描",
"spiderX": "SpiderX",
"spiderXHint": "按客户端的种子——面板据此为每个客户端派生唯一的 spx 路径;重新生成可轮换所有客户端的路径",
"getNewCert": "获取新证书",
"mldsa65Seed": "mldsa65 Seed",
"mldsa65Verify": "mldsa65 Verify",
"getNewSeed": "获取新 Seed",
"listenHelp": "也可以填写 Unix socket 路径(例如 /run/xray/in.sock),或以 @ 为前缀的抽象套接字名称(例如 @xray/in.sock),以使用套接字而非 TCP 端口监听——此时请将端口设为 0。",
"shareAddrStrategy": "分享地址策略",
"shareAddrStrategyHelp": "控制导出分享链接、二维码和订阅输出时写入哪个地址。",
"shareAddr": "自定义分享地址",
"shareAddrHelp": "仅在分享地址策略为自定义时使用。填写不带协议和端口的域名或 IP。",
"subSortIndex": "订阅排序",
"subSortIndexHelp": "此入站的链接在订阅输出(订阅页面和客户端应用)中的位置。数值越小越靠前;数值相同时保持创建顺序。不影响面板中的入站列表。",
"shareAddrStrategyOptions": {
"node": "节点地址",
"listen": "入站监听地址",
"custom": "自定义"
},
"verifyPeerCertByName": "按名称验证对端证书"
},
"info": {
"mode": "模式",
"grpcServiceName": "grpc serviceName",
"grpcMultiMode": "grpc multiMode",
"interfaceName": "接口名称",
"mtu": "MTU",
"gateway": "Gateway",
"dns": "DNS",
"outboundsInterface": "出站接口",
"autoSystemRoutes": "自动系统路由",
"followRedirect": "FollowRedirect",
"auth": "认证",
"noKernelTun": "非内核 TUN",
"keepAlive": "Keep alive",
"peerNumber": "Peer {n}",
"peerNumberConfig": "Peer {n} 配置"
},
"stream": {
"general": {
"request": "请求",
"response": "响应",
"name": "名称",
"value": "值"
},
"tcp": {
"version": "版本",
"method": "方法",
"path": "路径",
"status": "状态",
"statusDescription": "状态说明",
"requestHeader": "请求头",
"responseHeader": "响应头"
}
},
"sniffingDestOverride": "目标覆盖"
},
"clients": {
"tabBasics": "基本",
"tabCredentials": "凭据",
"tabLinks": "链接",
"wireguardConfig": "WireGuard 配置",
"config": "配置",
"linksHint": "添加第三方分享链接和远程订阅地址,将其包含在该客户端的订阅中。",
"addExternalLink": "添加外部链接",
"addExternalSubscription": "添加外部订阅",
"noExternalLinks": "暂无外部链接。",
"noExternalSubscriptions": "暂无外部订阅。",
"add": "添加客户端",
"edit": "编辑客户端",
"submitAdd": "添加客户端",
"submitEdit": "保存更改",
"clientCount": "客户端数量",
"bulk": "批量添加",
"copyFromInbound": "从入站复制客户端",
"copyToInbound": "复制客户端到",
"copySelected": "复制所选",
"copySource": "来源",
"copyEmailPreview": "生成的邮箱预览",
"copySelectSourceFirst": "请先选择一个来源入站。",
"copyResult": "复制结果",
"copyResultSuccess": "复制成功",
"copyResultNone": "没有内容可复制:未选中客户端或来源为空",
"copyResultErrors": "复制错误",
"copyFlowLabel": "新客户端的 Flow (VLESS)",
"copyFlowHint": "应用于所有被复制的客户端。留空则跳过。",
"selectAll": "全选",
"clearAll": "全部清除",
"method": "方式",
"first": "首个",
"last": "末位",
"ipLog": "IP 日志",
"prefix": "前缀",
"postfix": "后缀",
"delayedStart": "首次使用后开始",
"expireDays": "时长 (天)",
"days": "天",
"renew": "自动续期",
"renewDesc": "到期后自动续期。(0 = 禁用) (单位: 天)",
"renewDays": "自动续期 (天)",
"searchPlaceholder": "搜索邮箱、备注、sub ID、UUID、密码、auth、Telegram ID…",
"filterTitle": "筛选客户端",
"clearAllFilters": "清除全部",
"filters": {
"nodes": "节点",
"localPanel": "本机(此面板)"
},
"showingCount": "显示 {shown} / {total}",
"sortOldest": "最旧优先",
"sortNewest": "最新优先",
"sortRecentlyUpdated": "最近更新",
"sortRecentlyOnline": "最近在线",
"sortEmailAZ": "邮箱 A→Z",
"sortEmailZA": "邮箱 Z→A",
"sortMostTraffic": "流量最多",
"sortHighestRemaining": "剩余最多",
"sortExpiringSoonest": "即将过期",
"has": "拥有",
"hasNot": "不拥有",
"title": "客户端",
"actions": "操作",
"totalGB": "流量上限 (GB)",
"totalGBDesc": "该客户端的流量配额。0 = 不限制。",
"expiryTime": "过期时间",
"addClients": "添加客户端",
"limitIp": "IP 限制",
"limitIpDesc": "最大同时连接 IP 数。0 = 不限制。",
"limitIpFail2banMissing": "未安装 Fail2ban,无法实施 IP 限制。请从 x-ui 命令行菜单安装 Fail2ban 以启用此选项。",
"limitIpFail2banWindows": "Windows 上不支持 Fail2ban,无法实施 IP 限制。",
"limitIpDisabled": "此服务器已禁用 IP 限制功能。",
"password": "密码",
"passwordDesc": "仅 Trojan 和 Shadowsocks 客户端使用;VLESS、VMess、Hysteria 和 WireGuard 会忽略此项。",
"subId": "订阅 ID",
"online": "在线",
"email": "邮箱",
"emailInvalidChars": "邮箱不能包含空格、'/'、'\\' 或控制字符",
"subIdInvalidChars": "订阅ID不能包含空格、'/'、'\\' 或控制字符",
"group": "分组",
"groupDesc": "用于对相关客户端进行分桶的逻辑标签(如团队、客户、地区)。可从工具栏筛选。",
"groupPlaceholder": "如 customer-a",
"comment": "备注",
"traffic": "流量",
"speed": "速度",
"offline": "离线",
"addClient": "添加客户端",
"qrCode": "二维码",
"clientInfo": "客户端信息",
"delete": "删除",
"reset": "重置流量",
"editClient": "编辑客户端",
"client": "客户端",
"enabled": "已启用",
"remaining": "剩余",
"duration": "时长",
"attachedInbounds": "关联入站",
"selectInbound": "选择一个或多个入站",
"selectAllInbounds": "全选",
"clearAllInbounds": "全部清除",
"noSubId": "该客户端没有 subId,无法生成共享链接。",
"noLinks": "没有可共享的链接 — 请先将此客户端关联到支持协议的入站。",
"link": "链接",
"resetNotPossible": "请先将此客户端关联到入站。",
"general": "常规",
"resetAllTraffics": "重置所有客户端流量",
"resetAllTrafficsTitle": "重置所有客户端流量?",
"resetAllTrafficsContent": "所有客户端的上下行计数器将归零。配额与过期时间不受影响。该操作不可撤销。",
"deleteConfirmTitle": "删除客户端 {email}",
"deleteConfirmContent": "将从所有关联入站中移除该客户端并删除其流量记录。该操作不可撤销。",
"deleteSelected": "删除 ({count})",
"adjustSelected": "调整 ({count})",
"subLinksSelected": "订阅链接 ({count})",
"addToGroupTitle": "将 {count} 个客户端添加到分组",
"addToGroupTooltip": "选择现有分组或输入新名称。使用 Ungroup 操作从当前分组移除客户端。",
"groupName": "分组名称",
"addToGroupSuccessToast": "已将 {count} 个客户端添加到 {group}",
"ungroupSuccessToast": "已清除 {count} 个客户端的分组",
"ungroup": "取消分组",
"ungroupConfirmTitle": "将 {count} 个客户端从其分组中移除?",
"ungroupConfirmContent": "清除每个选中客户端的分组标签。客户端本身保留(使用 Delete 完全移除)。",
"addToGroup": "添加到分组",
"attach": "附加",
"adjust": "调整",
"subLinks": "订阅链接",
"enable": "启用",
"disable": "禁用",
"bulkEnableConfirmTitle": "启用 {count} 个客户端?",
"bulkEnableConfirmContent": "在每个已附加的入站上启用所选的客户端。配额已用尽或已过期的客户端将被自动重新禁用。",
"bulkDisableConfirmTitle": "禁用 {count} 个客户端?",
"bulkDisableConfirmContent": "在每个已附加的入站上禁用所选的客户端。他们将立即失去访问权限,但其记录和流量将被保留。",
"selectedCount": "已选 {count} 项",
"attachSelected": "附加 ({count})",
"attachToInboundsTitle": "将 {count} 个客户端附加到入站",
"attachToInboundsDesc": "将选中的 {count} 个客户端(相同 UUID/密码和共享流量)附加到选定的入站。它们保留现有的附加关系。",
"attachToInboundsTargets": "目标入站",
"attachToInboundsNoTargets": "没有可用于附加的多用户入站。",
"detachSelected": "分离 ({count})",
"detach": "分离",
"detachFromInboundsTitle": "从入站分离 {count} 个客户端",
"detachFromInboundsDesc": "从选定的入站中移除选中的 {count} 个客户端。客户端未附加的配对将被静默跳过。客户端记录保留(使用 Delete 完全移除)。",
"detachFromInboundsTargets": "要分离的入站",
"detachFromInboundsNoTargets": "没有可用的多用户入站。",
"detachFromInboundsResult": "已分离 {detached},已跳过 {skipped}。",
"detachFromInboundsResultMixed": "已分离 {detached},已跳过 {skipped},错误 {errors}。",
"subLinksTitle": "订阅链接 ({count})",
"subLinkColumn": "订阅 URL",
"subJsonLinkColumn": "订阅 JSON URL",
"subLinksCopyAll": "全部复制",
"subLinksCopiedAll": "已复制 {count} 条链接",
"subLinksEmpty": "选中的客户端均无订阅 ID。",
"subLinksDisabled": "订阅服务已禁用。",
"subLinksDisabledHint": "在面板设置 → 订阅中启用订阅以生成链接。",
"bulkDeleteConfirmTitle": "删除 {count} 个客户端?",
"bulkDeleteConfirmContent": "每个所选客户端都会从关联的入站中被移除,其流量记录也会被删除。该操作不可撤销。",
"bulkAdjustTitle": "调整 {count} 个客户端",
"bulkAdjustHint": "正值延长,负值减少。具有无限期限或流量的客户端将跳过该字段。",
"bulkAdjustNothing": "应用前请设置天数或流量。",
"addDays": "添加天数",
"addTrafficGB": "添加流量 (GB)",
"bulkFlow": "设置 flow",
"bulkFlowNoChange": "不更改",
"bulkFlowDisable": "禁用(清除 flow",
"delDepleted": "删除已耗尽",
"delDepletedConfirmTitle": "删除已耗尽的客户端?",
"delDepletedConfirmContent": "删除所有流量配额已用尽或已过期的客户端。该操作不可撤销。",
"exportClients": "导出客户端",
"importClients": "导入客户端",
"import": "导入",
"delOrphans": "删除未关联的客户端",
"delOrphansConfirmTitle": "删除没有入站的客户端?",
"delOrphansConfirmContent": "删除所有未关联到任何入站的客户端及其流量记录。该操作不可撤销。",
"auth": "认证",
"hysteriaAuth": "Hysteria 认证",
"hysteriaAuthDesc": "仅 Hysteria 客户端使用的凭据。Trojan 和 Shadowsocks 请改用上方的“密码”字段。",
"uuid": "UUID",
"flow": "Flow",
"vmessSecurity": "VMess 加密",
"wireguardPrivateKey": "WireGuard 私钥",
"wireguardPublicKey": "WireGuard 公钥",
"wireguardPreSharedKey": "WireGuard 预共享密钥",
"wireguardAllowedIPs": "WireGuard 允许的 IP",
"wireguardAllowedIPsHint": "留空则自动分配;多个条目用逗号分隔",
"mtprotoSecret": "MTProto 密钥",
"mtprotoSecretHint": "该客户端的 FakeTLS 密钥。重新生成即可更换。",
"mtprotoAdTag": "广告标签(赞助频道)",
"mtprotoAdTagHint": "可选的 32 位十六进制标签,从 Telegram 代理注册处获取。设置后,该客户端将通过 Telegram 中间代理路由,赞助频道会显示在其聊天列表顶部。",
"reverseTag": "反向标签",
"reverseTagPlaceholder": "可选 Reverse tag",
"telegramId": "Telegram 用户 ID",
"telegramIdPlaceholder": "数字形式的 Telegram 用户 ID (0 = 无)",
"created": "创建时间",
"updated": "更新时间",
"ipLimit": "IP 限制",
"toasts": {
"deleted": "客户端已删除",
"trafficReset": "流量已重置",
"allTrafficsReset": "所有客户端流量已重置",
"bulkDeleted": "已删除 {count} 个客户端",
"bulkDeletedMixed": "已删除 {ok} 个,失败 {failed} 个",
"bulkEnabled": "已启用 {count} 个客户端",
"bulkEnabledMixed": "已启用 {ok} 个,失败 {failed} 个",
"bulkDisabled": "已禁用 {count} 个客户端",
"bulkDisabledMixed": "已禁用 {ok} 个,失败 {failed} 个",
"bulkCreated": "已创建 {count} 个客户端",
"bulkCreatedMixed": "已创建 {ok} 个,失败 {failed} 个",
"bulkAdjusted": "已调整 {count} 个客户端",
"bulkAdjustedMixed": "已调整 {ok} 个,跳过 {skipped} 个",
"delDepleted": "已删除 {count} 个已耗尽的客户端",
"delOrphans": "已删除 {count} 个未关联的客户端",
"imported": "已导入 {count} 个客户端",
"importedMixed": "已导入 {ok} 个,跳过 {failed} 个"
}
},
"groups": {
"title": "分组",
"name": "名称",
"clientCount": "客户端",
"totalGroups": "分组总数",
"totalGroupedClients": "有分组的客户端",
"trafficUsed": "已用流量",
"upload": "上传",
"download": "下载",
"totalTraffic": "总流量",
"totalUpDown": "总上传 / 下载",
"addGroup": "添加分组",
"createSuccess": "已创建分组 “{name}”。",
"rename": "重命名",
"renameTitle": "重命名 {name}",
"renameCollision": "已存在名为 “{name}” 的分组。",
"renameSuccess": "已为 {count} 个客户端重命名分组。",
"deleteConfirmTitle": "删除分组 {name}?",
"deleteConfirmContent": "这将删除分组并清除 {count} 个客户端的标签。客户端本身不会被删除。",
"deleteSuccess": "已清除 {count} 个客户端的分组。",
"resetTraffic": "重置流量",
"resetConfirmTitle": "重置分组 {name} 的流量?",
"resetConfirmContent": "这只会清零该分组的流量计数器,不影响各个客户端的计数器。",
"resetSuccess": "已重置分组 {name} 的流量。",
"adjustSuccess": "已调整 {name} 中的 {count} 个客户端。",
"emptyForAction": "此分组尚无客户端。",
"deleteGroupOnly": "删除分组(保留客户端)",
"deleteClients": "删除分组中的客户端",
"deleteClientsConfirmTitle": "删除 {name} 中的所有客户端?",
"deleteClientsConfirmContent": "这将永久删除 {count} 个客户端及其流量记录。分组标签也会被清除。此操作无法撤销。",
"deleteClientsSuccess": "已删除 {count} 个客户端。",
"deleteClientsMixed": "已删除 {ok},已跳过 {failed}",
"addToGroup": "添加客户端…",
"addToGroupTitle": "添加客户端到分组 “{name}”",
"addToGroupDesc": "选择要添加到此分组的客户端。保留其现有入站附加;仅更改分组标签。已在此分组中的客户端不会列出。",
"addToGroupEmpty": "没有其他可添加的客户端。",
"addToGroupResult": "已将 {count} 个客户端添加到 {name}。",
"removeFromGroup": "移除客户端…",
"removeFromGroupTitle": "从分组 “{name}” 移除客户端",
"removeFromGroupDesc": "选择要从此分组中移除的成员。客户端本身保留(使用 “删除分组中的客户端” 完全移除)。",
"removeFromGroupResult": "已从 {name} 移除 {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上的节点启用。",
"outboundTag": "连接出站",
"outboundTagHint": "通过选定的 Xray 出站路由此节点的面板 API 流量。系统会自动将回环桥接入站添加到运行配置并实时应用。留空表示直接连接。",
"outboundTagPlaceholder": "直接连接",
"inboundSyncMode": "入站导入",
"inboundSyncModeHint": "选择要从此节点导入的入站。现有节点默认导入全部入站。",
"allInbounds": "全部入站",
"selectedInbounds": "选定的入站",
"inboundTags": "入站",
"inboundTagsHint": "按入站标签匹配。空选择不会导入任何入站。",
"inboundTagsPlaceholder": "加载并选择入站",
"loadInbounds": "从节点加载入站",
"inboundsLoaded": "已加载 {{count}} 个入站",
"inboundsLoadFailed": "加载入站失败",
"enable": "已启用",
"status": "状态",
"cpu": "CPU",
"mem": "内存",
"netUp": "网络上行 (KB/s)",
"netDown": "网络下行 (KB/s)",
"uptime": "运行时长",
"latency": "延迟",
"lastHeartbeat": "上次心跳",
"xrayVersion": "Xray 版本",
"panelVersion": "面板版本",
"actions": "操作",
"probe": "立即探测",
"updatePanel": "更新面板",
"updateSelected": "更新所选 ({count})",
"updateAvailable": "有可用更新",
"upToDate": "已是最新",
"updateConfirmTitle": "将 {count} 个节点更新到最新版本?",
"updateConfirmContent": "每个所选节点会下载最新版本并重启。仅更新已启用且在线的节点。",
"updateDevChannel": "更新到开发通道(最新提交)",
"testConnection": "测试连接",
"connectionOk": "连接正常 ({ms} ms)",
"connectionFailed": "连接失败",
"never": "从未",
"justNow": "刚刚",
"subNode": "子节点",
"subNodeTip": "只读:通过 {parent} 接入的下游节点。请在 {parent} 自己的面板中管理。",
"deleteConfirmTitle": "删除节点 \"{name}\"",
"deleteConfirmContent": "这将停止监控该节点。远程面板本身不受影响。",
"statusValues": {
"online": "在线",
"offline": "离线",
"unknown": "未知",
"xrayError": "Xray 错误",
"xrayStopped": "已停止"
},
"toasts": {
"list": "加载节点失败",
"obtain": "加载节点失败",
"add": "添加节点",
"update": "更新节点",
"delete": "删除节点",
"deleted": "节点已删除",
"test": "测试连接",
"fillRequired": "名称、地址、端口和 API 令牌为必填项",
"probeFailed": "探测失败",
"updateStarted": "已开始更新面板",
"updateResult": "已在 {ok} 个节点上触发更新,{failed} 个失败",
"updateNoneEligible": "请至少选择一个在线且已启用的节点",
"saveMtls": "保存节点 mTLS"
},
"tlsVerifyMode": "TLS 校验",
"tlsVerifyModeHint": "面板如何校验节点的 HTTPS 证书。固定或跳过用于自签名证书(仅 https 节点)。",
"tlsVerify": "校验(默认 CA",
"tlsPin": "固定证书(SHA-256",
"tlsSkip": "跳过校验",
"tlsMtls": "双向 TLS(客户端证书)",
"mtlsFormHint": "此节点使用客户端证书对面板进行认证。请从“节点 mTLS”区域复制本面板的 CA 到该节点,设置其受信任的 CA,然后重启该节点。",
"mtls": {
"title": "节点 mTLS",
"intro": "双向 TLS 在节点间调用的 API 令牌之上增加客户端证书认证。此为可选项:留空则仅使用令牌认证。",
"copyCa": "复制此面板的 CA",
"copyCaHint": "将此 CA 提供给本面板管理的节点,然后将它们的 TLS 校验设置为双向 TLS。",
"caCopied": "CA 证书已复制到剪贴板",
"caFailed": "获取 CA 证书失败",
"trustLabel": "受信任的上级 CA",
"trustHint": "当本面板自身作为节点时,将管理它的面板的 CA 粘贴到此处以要求其客户端证书。重启面板后生效。",
"trustPlaceholder": "-----BEGIN CERTIFICATE-----",
"save": "保存受信任的 CA",
"saved": "受信任的 CA 已保存 — 重启面板后生效"
},
"tlsSkipWarning": "跳过校验会失去对中间人攻击的防护,API 令牌可能被截获。建议改用固定证书。",
"pinnedCert": "固定证书的 SHA-256",
"pinnedCertHint": "节点证书的 SHA-256base64 或 hex)。点击“获取”可立即从节点读取。",
"pinnedCertPlaceholder": "base64 或 hex 的 SHA-256",
"fetchPin": "获取",
"pinFetched": "已获取节点当前证书",
"pinFetchFailed": "无法获取证书"
},
"settings": {
"title": "面板设置",
"save": "保存",
"infoDesc": "此处的所有更改都需要保存并重启面板才能生效",
"restartPanel": "重启面板",
"restartPanelDesc": "确定要重启面板吗?若重启后无法访问面板,请前往服务器查看面板日志信息",
"restartPanelSuccess": "面板已成功重启",
"actions": "操作",
"resetDefaultConfig": "重置为默认配置",
"panelSettings": "常规",
"securitySettings": "安全设定",
"securityWarnings": "安全警告",
"panelExposed": "您的面板可能已暴露:",
"warnHttp": "面板通过明文 HTTP 提供服务 — 生产环境请配置 TLS。",
"warnDefaultPort": "默认端口 2053 众所周知 — 请更改为随机端口。",
"warnDefaultBasePath": "默认根路径 \"/\" 众所周知 — 请更改为随机路径。",
"warnDefaultSubPath": "默认订阅路径 \"/sub/\" 众所周知 — 请更改。",
"warnDefaultJsonPath": "默认 JSON 订阅路径 \"/json/\" 众所周知 — 请更改。",
"TGBotSettings": "Telegram 机器人",
"panelListeningIP": "面板监听 IP",
"panelListeningIPDesc": "默认留空监听所有 IP",
"panelListeningDomain": "面板监听域名",
"panelListeningDomainDesc": "默认情况下留空以监视所有域名和 IP 地址",
"panelPort": "面板监听端口",
"panelPortDesc": "重启面板生效",
"publicKeyPath": "面板证书公钥文件路径",
"publicKeyPathDesc": "填写一个 '/' 开头的绝对路径",
"privateKeyPath": "面板证书密钥文件路径",
"privateKeyPathDesc": "填写一个 '/' 开头的绝对路径",
"panelUrlPath": "URI 路径",
"panelUrlPathDesc": "必须以 '/' 开头,以 '/' 结尾",
"pageSize": "分页大小",
"pageSizeDesc": "定义入站表的页面大小。设置 0 表示禁用",
"panelOutbound": "面板流量出站",
"panelOutboundDesc": "通过此 Xray 出站路由面板自身的请求(面板/Xray 版本检查与下载、Telegram、普通 geo 文件更新),以绕过服务端对 GitHub/Telegram 的过滤。本地桥接入站会自动添加到运行中的配置并实时生效。Xray 原生的 Geodata 自动更新不受影响,它有自己的下载出站。留空表示直连。",
"panelOutboundPh": "直连",
"datepicker": "日期选择器",
"datepickerPlaceholder": "选择日期",
"datepickerDescription": "选择器日历类型指定到期日期",
"oldUsername": "原用户名",
"currentPassword": "原密码",
"newUsername": "新用户名",
"newPassword": "新密码",
"telegramBotEnable": "启用 Telegram 机器人",
"telegramBotEnableDesc": "启用 Telegram 机器人功能",
"telegramToken": "Telegram Token",
"telegramTokenDesc": "从 '{'@'}BotFather' 获取的 Telegram 机器人令牌",
"telegramProxy": "SOCKS 代理",
"telegramProxyDesc": "启用 SOCKS5 代理连接到 Telegram(根据指南调整设置)",
"telegramAPIServer": "Telegram API 服务器",
"telegramAPIServerDesc": "要使用的 Telegram API 服务器。留空以使用默认服务器。",
"telegramChatId": "管理员聊天 ID",
"telegramChatIdDesc": "Telegram 管理员聊天 ID (多个以逗号分隔)(可通过 {'@'}userinfobot 获取,或在机器人中使用 '/id' 命令获取)",
"telegramNotifyTime": "通知时间",
"telegramNotifyTimeDesc": "Telegram 机器人发送周期性报告的频率。选择预设间隔,或选择“自定义”以输入 crontab 表达式。",
"notifyTime": {
"every": "@every — 按间隔重复",
"hourly": "@hourly — 每小时",
"daily": "@daily — 每天 00:00",
"weekly": "@weekly — 每周",
"monthly": "@monthly — 每月",
"custom": "自定义 (crontab)",
"seconds": "秒",
"minutes": "分钟",
"hours": "小时",
"interval": "间隔",
"unit": "单位"
},
"tgNotifyBackup": "数据库备份",
"tgNotifyBackupDesc": "发送带有报告的数据库备份文件",
"tgNotifyLogin": "登录通知",
"tgNotifyLoginDesc": "当有人试图登录你的面板时显示用户名、IP 地址和时间",
"sessionMaxAge": "会话时长",
"sessionMaxAgeDesc": "保持登录状态的时长(单位:分钟)",
"expireTimeDiff": "到期通知阈值",
"expireTimeDiffDesc": "达到此阈值时,将收到有关到期时间的通知(单位:天)",
"trafficDiff": "流量耗尽阈值",
"trafficDiffDesc": "达到此阈值时,将收到有关流量耗尽的通知(单位:GB)",
"tgNotifyCpu": "CPU 负载通知阈值",
"tgNotifyCpuDesc": "CPU 负载超过此阈值时,将收到通知(单位:%)",
"timeZone": "时区",
"timeZoneDesc": "定时任务将按照该时区的时间运行",
"subSettings": "订阅设置",
"subEnable": "启用订阅服务",
"subEnableDesc": "启用订阅服务功能",
"subJsonEnable": "单独启用/禁用 JSON 订阅端点。",
"subJsonEnableTitle": "JSON 订阅",
"subClashEnableTitle": "Clash / Mihomo 订阅",
"subFormatsTipTitle": "特定格式的订阅设置",
"subFormatsTipDesc": "分别配置 JSON 和 Clash / Mihomo 的 URL 路径、反向代理 URL 和客户端自动识别。",
"subFormatsTipAction": "打开订阅格式",
"subJsonAutoDetect": "自动识别 Xray JSON 客户端",
"subJsonAutoDetectDesc": "启用后,使用标准订阅 URL 的已识别兼容客户端将自动获得 Xray JSON 配置数组。其他客户端继续获得原始/Base64 响应。需要启用 JSON 订阅并重启面板才能生效。",
"subJsonAlwaysArray": "始终返回 JSON 数组",
"subJsonAlwaysArrayDesc": "即使只有一个配置,也将显式 JSON 订阅端点返回为数组,以符合 XTLS 订阅标准。自动识别的 JSON 响应始终使用数组。禁用时保留旧版单对象响应。",
"subJsonUserAgentRegex": "Xray JSON User-Agent 正则表达式",
"subJsonUserAgentRegexDesc": "用于与客户端 User-Agent 进行匹配,从而在标准订阅 URL 上自动选择 Xray JSON 格式的 Go RE2 正则表达式。默认留空,因此在为需要服务的客户端设置规则之前,自动识别保持关闭。其他客户端继续获得原始/Base64 响应。更改后请重启面板。",
"subClashAutoDetect": "自动识别 Clash/Mihomo 客户端",
"subClashAutoDetectDesc": "启用后,使用标准订阅 URL 的已识别 Clash/Mihomo 客户端将自动获得 Clash YAML。浏览器仍显示订阅页面,其他客户端继续获得原始/Base64 响应,独立的 JSON 和 Clash URL 仍然可用。需要启用 Clash/Mihomo 订阅并重启面板才能生效。",
"subClashUserAgentRegex": "Clash/Mihomo User-Agent 正则表达式",
"subClashUserAgentRegexDesc": "用于与客户端 User-Agent 进行匹配,从而在标准订阅 URL 上识别 Clash/Mihomo 客户端的 Go RE2 正则表达式。留空则使用默认规则。更改后请重启面板。",
"subTitle": "订阅标题",
"subTitleDesc": "在VPN客户端中显示的标题",
"subSupportUrl": "支持链接",
"subSupportUrlDesc": "VPN 客户端中显示的技术支持链接",
"subProfileUrl": "个人资料链接",
"subProfileUrlDesc": "VPN 客户端中显示的网站链接",
"subAnnounce": "公告",
"subAnnounceDesc": "VPN 客户端中显示的公告文本",
"subThemeDir": "订阅主题目录",
"subThemeDirDesc": "包含自定义订阅页面模板 (index.html/sub.html) 的文件夹的绝对路径(例如 /etc/3x-ui/sub_templates/my-theme/)。留空则使用默认页面。",
"subThemeDirDocs": "模板指南 ↗",
"subEnableRouting": "启用路由",
"subEnableRoutingDesc": "在 VPN 客户端中启用路由的全局设置。(仅限 Happ)",
"subRoutingRules": "路由规则",
"subRoutingRulesDesc": "VPN 用户端的全域路由规则。(仅限 Happ)",
"subHideSettings": "隐藏服务器设置",
"subHideSettingsDesc": "在 VPN 客户端中隐藏查看和编辑服务器配置的功能。(仅限 Happ)",
"subIncyEnableRouting": "启用路由",
"subIncyEnableRoutingDesc": "为 Incy 客户端将路由配置注入订阅内容中。(仅限 Incy)",
"subIncyRoutingRules": "路由规则",
"subIncyRoutingRulesDesc": "添加到订阅内容的 Incy 路由深层链接,例如 incy://routing/onadd/<base64>。(仅限 Incy",
"subClashEnableRouting": "启用路由",
"subClashEnableRoutingDesc": "在生成的 YAML 订阅中包含 Clash/Mihomo 全局路由规则。",
"subClashRoutingRules": "全局路由规则",
"subClashRoutingRulesDesc": "添加到每个 YAML 订阅开头、MATCH,PROXY 之前的 Clash/Mihomo 规则。",
"subListen": "监听 IP",
"subListenDesc": "订阅服务监听的 IP 地址(留空表示监听所有 IP)",
"subPort": "监听端口",
"subPortDesc": "订阅服务监听的端口号(必须是未使用的端口)。当下方「反向代理 URI」为空时,也会用来生成面板中显示的订阅链接/二维码——如果订阅是通过反向代理的其他端口访问的,请改为设置「反向代理 URI」。",
"subCertPath": "公钥路径",
"subCertPathDesc": "订阅服务使用的公钥文件路径(以 '/' 开头)",
"subKeyPath": "私钥路径",
"subKeyPathDesc": "订阅服务使用的私钥文件路径(以 '/' 开头)",
"subPath": "URI 路径",
"subPathDesc": "订阅服务使用的 URI 路径(以 '/' 开头,以 '/' 结尾)",
"subDomain": "监听域名",
"subDomainDesc": "订阅服务监听的域名(留空表示监听所有域名和 IP)。当「反向代理 URI」为空时,也会作为显示的订阅链接的回退域名——如果面板和订阅通过不同的域名访问(例如位于反向代理之后),请设置「反向代理 URI」。",
"subUpdates": "更新间隔",
"subUpdatesDesc": "客户端应用中订阅 URL 的更新间隔(单位:小时)",
"subEncrypt": "编码",
"subEncryptDesc": "订阅服务返回的内容将采用 Base64 编码",
"subURI": "反向代理 URI",
"subURIDesc": "用于订阅链接和二维码的完整基础 URL(scheme://域名[:端口]/路径/),会替代监听域名/监听端口使用。当订阅通过反向代理访问,或使用与上面不同的域名/端口访问时,请设置此项。",
"externalTrafficInformEnable": "外部交通通知",
"externalTrafficInformEnableDesc": "每次流量更新时通知外部 API。",
"externalTrafficInformURI": "外部流量通知 URI",
"externalTrafficInformURIDesc": "流量更新将发送到此 URI",
"restartXrayOnClientDisable": "客户端自动禁用后重启 Xray",
"restartXrayOnClientDisableDesc": "当客户端因到期或流量超限被自动禁用时,重启 Xray。",
"fragment": "分片",
"fragmentDesc": "启用 TLS hello 数据包分片",
"fragmentSett": "设置",
"noisesDesc": "启用 Noises.",
"noisesSett": "Noises 设置",
"trustedProxyCidrs": "可信代理 CIDR",
"trustedProxyCidrsDesc": "允许设置转发 host、proto 和客户端 IP 标头的 IP/CIDR(逗号分隔)。",
"ldap": {
"enable": "启用 LDAP 同步",
"host": "LDAP host",
"port": "LDAP 端口",
"useTls": "使用 TLS (LDAPS)",
"skipTlsVerify": "跳过 TLS 证书验证",
"skipTlsVerifyDesc": "不安全 — 禁用服务器证书验证。仅用于内部/不受信任的 CA。",
"bindDn": "Bind DN",
"passwordConfigured": "已配置;留空以保留当前密码。",
"passwordUnconfigured": "未配置。",
"passwordPlaceholder": "已配置 - 输入新值以替换",
"baseDn": "Base DN",
"userFilter": "用户筛选",
"userAttr": "用户属性 (username/email)",
"vlessField": "VLESS flag 属性",
"flagField": "通用 flag 属性 (可选)",
"flagFieldDesc": "如设置,将覆盖 VLESS flag — 如 shadowInactive。",
"truthyValues": "Truthy 值",
"truthyValuesDesc": "逗号分隔;默认: true,1,yes,on",
"invertFlag": "反转 flag",
"invertFlagDesc": "当属性表示已禁用时启用 (如 shadowInactive)。",
"syncSchedule": "同步计划",
"syncScheduleDesc": "类 cron 字符串,如 @every 1m",
"inboundTags": "入站标签",
"inboundTagsDesc": "允许 LDAP 同步自动创建或删除客户端的入站。",
"noInbounds": "未找到入站。请先在“入站”中创建。",
"autoCreate": "自动创建客户端",
"autoDelete": "自动删除客户端",
"defaultTotalGb": "默认总流量 (GB)",
"defaultExpiryDays": "默认到期 (天)",
"defaultIpLimit": "默认 IP 限制"
},
"subFormats": {
"finalMask": "Final Mask",
"finalMaskDesc": "将 Xray finalmask TCP/UDP 掩码和 QUIC 参数注入每个生成的 Xray JSON 配置。需要支持 Xray JSON 订阅的客户端应用和较新的 Xray 核心。",
"packets": "数据包",
"length": "长度",
"interval": "间隔",
"maxSplit": "最大分割",
"noises": "噪声",
"noiseItem": "噪声 №{n}",
"type": "类型",
"packet": "数据包",
"delayMs": "延迟 (ms)",
"applyTo": "应用于",
"addNoise": "+ 噪声",
"concurrency": "并发",
"xudpConcurrency": "xudp 并发",
"xudpUdp443": "xudp UDP 443"
},
"mux": "Mux",
"muxDesc": "在已建立的数据流内传输多个独立的数据流",
"muxSett": "复用器设置",
"direct": "直接连接",
"directDesc": "直接与特定国家的域或IP范围建立连接",
"notifications": "通知",
"certs": "证书",
"externalTraffic": "外部流量",
"dateAndTime": "日期和时间",
"proxyAndServer": "代理和服务器",
"intervals": "间隔",
"information": "信息",
"profile": "资料",
"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": "使用此令牌的任何调用方将立即无法认证。",
"apiTokenCreatedTitle": "令牌已创建",
"apiTokenCreatedNotice": "请立即复制此令牌。出于安全考虑,它不会以可读形式存储,也不会再次显示。"
},
"toasts": {
"modifySettings": "参数已更改。",
"getSettings": "获取参数时发生错误",
"modifyUserError": "更改管理员凭据时发生错误。",
"modifyUser": "您已成功更改管理员凭据。",
"originalUserPassIncorrect": "原用户名或原密码错误",
"userPassMustBeNotEmpty": "新用户名和新密码不能为空",
"getOutboundTrafficError": "获取出站流量错误",
"resetOutboundTrafficError": "重置出站流量错误"
},
"smtpSettings": "SMTP 设置",
"smtpEnable": "启用邮件通知",
"smtpEnableDesc": "通过 SMTP 启用邮件通知",
"smtpHost": "SMTP 主机",
"smtpHostDesc": "SMTP 服务器主机名(例如 smtp.gmail.com",
"smtpPort": "SMTP 端口",
"smtpPortDesc": "SMTP 服务器端口(默认:587",
"smtpUsername": "SMTP 用户名",
"smtpUsernameDesc": "SMTP 认证用户名",
"smtpFrom": "发件人地址 (From)",
"smtpFromDesc": "邮件 From 头使用的地址。留空则使用用户名。",
"smtpFromName": "发件人名称 (From)",
"smtpFromNameDesc": "From 头中显示在地址前的可选显示名称。",
"smtpPassword": "SMTP 密码",
"smtpPasswordDesc": "SMTP 认证密码",
"smtpTo": "收件人",
"smtpToDesc": "以逗号分隔的收件人邮箱地址",
"emailSettings": "邮件",
"emailNotifications": "通知",
"smtpEventBusNotify": "邮件事件通知",
"smtpEventBusNotifyDesc": "选择触发邮件通知的事件",
"tgEventBusNotify": "Telegram 事件通知",
"tgEventBusNotifyDesc": "选择触发 Telegram 通知的事件",
"testSmtp": "发送测试邮件",
"testTgBot": "发送测试消息",
"eventGroupOutbound": "出站",
"eventGroupXray": "Xray 核心",
"eventGroupSystem": "系统",
"eventGroupSecurity": "安全",
"eventGroupNode": "节点",
"eventOutboundDown": "断开",
"eventOutboundUp": "恢复",
"eventXrayCrash": "崩溃",
"eventNodeDown": "离线",
"eventNodeUp": "上线",
"eventCPUHigh": "CPU 占用过高(%",
"requestFailed": "请求失败",
"smtpEncryption": "加密",
"smtpEncryptionDesc": "SMTP 连接加密方式",
"smtpEncryptionNone": "无(明文)",
"smtpEncryptionStartTLS": "STARTTLS",
"smtpEncryptionTLS": "TLS(隐式)",
"smtpStageConnect": "连接",
"smtpStageAuth": "认证",
"smtpStageSend": "发送",
"smtpTestSuccess": "测试邮件发送成功",
"smtpHostNotConfigured": "尚未配置 SMTP 主机",
"smtpNoRecipients": "尚未配置收件人",
"smtpFromNotConfigured": "未配置 SMTP 发件人地址",
"eventLoginAttempt": "登录尝试",
"telegramTokenConfigured": "已配置;留空则保留当前令牌。",
"telegramTokenPlaceholder": "已配置——输入新令牌以替换",
"smtpPasswordConfigured": "已配置;留空则保留当前密码。",
"smtpPasswordPlaceholder": "已配置——输入新密码以替换",
"smtpNotInitialized": "SMTP 尚未初始化",
"tgBotNotEnabled": "Telegram 机器人未启用",
"tgTestFailed": "Telegram 测试失败",
"tgTestSuccess": "测试消息已发送至 Telegram",
"tgBotNotRunning": "Telegram 机器人未运行",
"smtpErrorAuth": "认证失败——请检查用户名和密码",
"smtpErrorStarttls": "服务器要求 STARTTLS——请更改加密类型",
"smtpErrorTls": "服务器要求 TLS——请更改加密类型",
"smtpErrorRefused": "连接被拒绝——请检查主机和端口",
"smtpErrorTimeout": "连接超时——主机无法访问",
"smtpErrorRelay": "服务器拒绝从此地址发送",
"smtpErrorEof": "连接被服务器关闭",
"smtpErrorUnknown": "SMTP 错误:{{ .Error }}",
"eventMemoryHigh": "内存使用率高 (%)",
"remarkTemplate": "备注模板",
"remarkTemplateDesc": "设置后,将替换每个订阅链接的备注模型 — 使用变量标记编写您自己的格式(用按钮插入它们)。留空则使用上方的模型。",
"validation": {
"pathLeadingSlash": "路径必须以 / 开头"
},
"secretClear": "清除",
"secretClearUndo": "撤销清除"
},
"xray": {
"importRules": "导入规则",
"exportRules": "导出规则",
"importOutbounds": "导入出站",
"exportOutbounds": "导出出站",
"importInvalidJson": "无效的 JSON——应为数组或包含匹配键的对象。",
"metricsListen": "指标端点",
"metricsListenDesc": "在此 address:port 上暴露 Xray 的 Prometheus 风格指标(例如 127.0.0.1:11111)。留空则禁用。请绑定到本地回环并通过反向代理转发——它没有身份验证。",
"metricsTag": "指标标签",
"title": "Xray 配置",
"save": "保存",
"restart": "重启 Xray",
"restartSuccess": "Xray 已成功重新启动",
"restartOutputTitle": "Xray 重启输出",
"restartConfirmTitle": "重启 xray?",
"restartConfirmContent": "使用已保存的配置重新加载 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": "注意:在使用这些选项之前,请按照面板 GitHub 上的步骤在你的服务器上以 socks5 代理模式安装 WARP。WARP 将通过 Cloudflare 服务器将流量路由到网站。",
"nordRouting": "NordVPN 路由",
"nordRoutingDesc": "这些选项将根据特定目的地通过 NordVPN 路由流量。",
"Template": "高级 Xray 配置模板",
"TemplateDesc": "最终的 Xray 配置文件将基于此模板生成",
"FreedomStrategy": "Freedom 协议策略",
"FreedomStrategyDesc": "设置 Freedom 协议中网络的输出策略",
"FreedomHappyEyeballs": "Freedom Happy Eyeballs (IPv4/IPv6)",
"FreedomHappyEyeballsDesc": "为直连(freedom)出站启用双栈拨号——在同时具备 IPv4 和 IPv6 的出口服务器上很有用。",
"FreedomHappyEyeballsTryDelayDesc": "尝试备用地址族之前等待的毫秒数。150–250 毫秒是不错的起点。",
"RoutingStrategy": "配置路由域策略",
"RoutingStrategyDesc": "设置 DNS 解析的整体路由策略",
"outboundTestUrl": "出站测试 URL",
"outboundTestUrlDesc": "测试出站连接时使用的 URL",
"Torrent": "屏蔽 BitTorrent 协议",
"Inbounds": "入站",
"InboundsDesc": "接受来自特定客户端的流量",
"Outbounds": "出站",
"OutboundSubscriptions": "出站订阅",
"OutboundSubscriptionsDesc": "从远程订阅 URLvmess/vless/trojan/ss/…)导入出站。标签保持稳定,可用于负载均衡器和路由规则。更新会自动进行。",
"Balancers": "负载均衡",
"balancerTagRequired": "标签为必填项",
"balancerSelectorRequired": "至少选择一个出站",
"balancerLive": "当前目标",
"balancerOverride": "强制指定",
"balancerOverridePh": "自动(策略)",
"balancerLiveRefresh": "刷新负载均衡器实时状态",
"balancerNotRunning": "此负载均衡器在运行中的 Xray 未激活 — 请先保存更改或启动 Xray",
"routeTester": "路由测试",
"routeTesterDesc": "向运行中的 Xray 查询某个连接将使用哪个出站。不会发送真实流量 — 结果直接来自实时路由引擎。",
"routeTesterDest": "域名或 IP",
"routeTesterPort": "端口",
"routeTesterInbound": "入站",
"routeTesterProtocol": "嗅探协议",
"routeTesterTest": "测试路由",
"routeTesterMatchedOutbound": "匹配出站",
"routeTesterViaBalancer": "经由负载均衡器",
"routeTesterDefaultOutbound": "无路由规则匹配 — 流量将发往默认(第一个)出站。",
"OutboundsDesc": "设置出站流量传出方式",
"Routings": "路由规则",
"RoutingsDesc": "每条规则的优先级都很重要",
"completeTemplate": "全部",
"logLevel": "日志级别",
"logLevelDesc": "错误日志的日志级别,用于指示需要记录的信息",
"accessLog": "访问日志",
"accessLogDesc": "访问日志的文件路径。特殊值 'none' 禁用访问日志",
"errorLog": "错误日志",
"errorLogDesc": "错误日志的文件路径。特殊值 'none' 禁用错误日志",
"dnsLog": "DNS 日志",
"dnsLogDesc": "是否启用 DNS 查询日志",
"maskAddress": "隐藏地址",
"maskAddressDesc": "IP 地址掩码,启用时会自动替换日志中出现的 IP 地址。",
"statistics": "统计",
"statsInboundUplink": "入站上传统计",
"statsInboundUplinkDesc": "启用所有入站代理的上行流量统计收集。",
"statsInboundDownlink": "入站下载统计",
"statsInboundDownlinkDesc": "启用所有入站代理的下行流量统计收集。",
"statsOutboundUplink": "出站上传统计",
"statsOutboundUplinkDesc": "启用所有出站代理的上行流量统计收集。",
"statsOutboundDownlink": "出站下载统计",
"statsOutboundDownlinkDesc": "启用所有出站代理的下行流量统计收集。",
"connectionLimits": "连接限制",
"connectionLimitsDesc": "用户等级 0 的连接级策略。留空则使用 Xray 的默认值。",
"connIdle": "空闲超时",
"connIdleDesc": "连接空闲达到该秒数后将被关闭。在繁忙的服务器上调低此值可更快释放内存和文件描述符(Xray 默认值:300)。",
"bufferSize": "缓冲区大小",
"bufferSizeDesc": "每个连接的内部缓冲区大小(KB)。在低内存服务器上设为 0 可最大限度减少内存占用(Xray 默认值取决于平台)。",
"bufferSizePlaceholder": "自动",
"seconds": "秒",
"rules": {
"first": "置顶",
"last": "置底",
"up": "向上",
"down": "向下",
"source": "来源",
"dest": "目的地址",
"inbound": "入站",
"outbound": "出站",
"balancer": "负载均衡",
"info": "信息",
"add": "添加规则",
"edit": "编辑规则",
"useComma": "逗号分隔的项目"
},
"routing": {
"dragToReorder": "拖动以重新排序"
},
"ruleForm": {
"sourceIps": "源 IP",
"sourcePort": "源端口",
"vlessRoute": "VLESS 路由",
"attributes": "属性",
"value": "值",
"user": "用户",
"inboundTags": "入站标签",
"outboundTag": "出站标签",
"balancerTag": "均衡器标签",
"balancerTagTooltip": "通过其中一个已配置的负载均衡器路由流量"
},
"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",
"fragment": "Fragment",
"finalRules": "最终规则",
"overrideXrayPrivateIp": "覆盖 Xray 默认的私有 IP 阻止",
"blockDelay": "阻塞延迟 (ms)",
"reverseSniffing": "反向 sniffing",
"reserved": "保留",
"minUploadInterval": "最小上传间隔 (ms)",
"maxUploadSizeBytes": "最大上传大小 (字节)",
"uplinkChunkSize": "Uplink chunk 大小",
"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": "接口",
"ipv6Only": "仅 IPv6",
"acceptProxyProtocol": "接受 proxy protocol",
"proxyProtocol": "Proxy protocol",
"tcpUserTimeoutMs": "TCP user timeout (ms)",
"tcpKeepAliveIdleS": "TCP keep-alive idle (s)"
},
"outbound": {
"addOutbound": "添加出站",
"addReverse": "添加反向",
"editOutbound": "编辑出站",
"editReverse": "编辑反向",
"reverseTag": "反向标签",
"reverseTagDesc": "VLESS 简易反向代理出站标签。留空则禁用。设置后,此客户端的连接可用作反向代理隧道。",
"reverseTagPlaceholder": "出站标签(留空则禁用)",
"tag": "标签",
"tagDesc": "唯一标签",
"address": "地址",
"egress": "Egress",
"egressHint": "Run an HTTP test to show egress IP and country.",
"reverse": "反向",
"domain": "域名",
"type": "类型",
"bridge": "Bridge",
"portal": "Portal",
"link": "链接",
"intercon": "互连",
"settings": "设置",
"accountInfo": "帐户信息",
"outboundStatus": "出站状态",
"sendThrough": "发送通过",
"targetStrategy": "目标解析策略",
"test": "测试",
"testResult": "测试结果",
"testing": "正在测试连接...",
"testSuccess": "测试成功",
"testFailed": "测试失败",
"testError": "测试出站失败",
"modeRealDelay": "真实延迟",
"testModeTooltip": "TCP: 快速 dial-only 探测。HTTP: 通过 xray 的完整请求。真实延迟: 含建立连接的总耗时。",
"testAll": "全部测试",
"httpStatus": "HTTP 状态",
"breakdownConnect": "代理连接",
"breakdownTls": "经由出站的 TLS",
"breakdownTtfb": "首字节",
"nordvpn": "NordVPN",
"accessToken": "访问令牌",
"country": "国家",
"server": "服务器",
"city": "城市",
"allCities": "所有城市",
"privateKey": "私钥",
"load": "负载",
"moveToTop": "移到顶部"
},
"outboundSub": {
"manage": "订阅",
"title": "出站订阅",
"remark": "备注(可选)",
"remarkPlaceholder": "如:香港节点",
"url": "订阅 URL",
"urlPlaceholder": "https://...base64 编码的链接列表)",
"tagPrefix": "标签前缀",
"tagPrefixPlaceholder": "hk-",
"interval": "更新间隔",
"hours": "时",
"minutes": "分",
"intervalHint": "默认 10 分钟。后台任务会频繁检查;每个订阅仅在自身间隔到期后才重新拉取。",
"enabled": "启用",
"allowPrivate": "允许私有地址",
"allowPrivateHint": "允许此订阅 URL 使用 localhost / 局域网(LAN)/ 私有 IP 地址。出于安全考虑默认关闭,仅在使用可信的本地来源时才开启。",
"prepend": "置于手动出站之前",
"prependHint": "将此订阅的出站排在手动配置的出站之前,使其中之一可成为默认出站。",
"preview": "预览",
"previewEmpty": "在该 URL 未找到任何出站。",
"refreshAll": "全部刷新",
"statusOk": "正常",
"toastUpdated": "订阅已更新",
"addButton": "添加",
"active": "已启用的订阅",
"empty": "暂无订阅。请在上方添加。",
"colRemark": "备注",
"colPrefix": "前缀",
"colInterval": "间隔",
"colLastFetch": "上次拉取",
"colEnabled": "启用",
"auto": "自动",
"never": "从未",
"yes": "是",
"no": "否",
"refreshNow": "立即刷新",
"lastError": "上次错误",
"deleteConfirm": "删除此订阅?",
"restartHint": "添加或刷新后,请重启 Xray(或等待下一次自动重载)以使出站生效。",
"fromSubsTitle": "来自出站订阅(只读)",
"fromSubsDesc": "从已启用的订阅中导入。请在上方的订阅面板中管理它们。",
"toastLoadFailed": "加载订阅失败",
"toastUrlRequired": "订阅 URL 为必填项",
"toastAdded": "订阅已添加",
"toastAddFailed": "添加订阅失败",
"toastRefreshed": "已刷新",
"toastRefreshFailed": "刷新失败",
"toastDeleted": "已删除",
"toastDeleteFailed": "删除失败"
},
"tabBalancerSettings": "负载均衡设置",
"tabObservatory": "观测器",
"observatory": {
"title": "观测器",
"burstTitle": "突发观测器",
"autoManaged": "观测器会根据你的负载均衡器自动管理。可在下方调整探测方式;被观测的出站会跟随负载均衡器的选择器。",
"emptyHint": "当前没有活动的连接观测器。当你创建 Least Ping 或 Least Load 负载均衡器,或带有 fallback 的 Random / Round-robin 负载均衡器时,会自动添加一个,以便依赖观测器的负载均衡器在选择目标前检查出站健康状态。",
"mixedLegacy": "此配置同时包含 Observatory 和 Burst Observatory。Xray 只使用一个全局观测器,因此不支持这种旧式混合状态;保存负载均衡器时会将其规范化为单个观测器。",
"subjectSelector": "被观测的出站",
"subjectSelectorDesc": "该观测器探测的出站标签。根据你的负载均衡器自动管理。",
"probeURL": "探测 URL",
"probeURLDesc": "用于测量每个出站而请求的 URL,应返回 HTTP 204。",
"probeInterval": "探测间隔",
"probeIntervalDesc": "每个出站的探测频率,例如 30s、1m、2h45m。",
"enableConcurrency": "并发探测",
"enableConcurrencyDesc": "一次性探测所有被观测的出站,而不是逐个探测。更快,但在网络上更明显。",
"destination": "探测目标",
"destinationDesc": "用于测量每个出站而请求的 URL,应返回 HTTP 204。",
"connectivity": "连通性检查",
"connectivityDesc": "可选的本地网络检查 URL,仅在目标失败后才尝试。留空则跳过。",
"interval": "探测间隔",
"intervalDesc": "每个出站两次探测之间的平均时间,例如 1m。最小 10s。",
"timeout": "探测超时",
"timeoutDesc": "判定探测失败前的等待时长,例如 5s。",
"sampling": "采样数量",
"samplingDesc": "为每个出站评分而保留的最近探测结果数量。",
"httpMethod": "HTTP 方法",
"httpMethodDesc": "探测所用的 HTTP 方法。",
"deleteAlsoObservatory": "这是最后一个使用 Observatory 的负载均衡器,因此它也会被一并移除。",
"deleteAlsoBurst": "这是最后一个使用 Burst Observatory 的负载均衡器,因此它也会被一并移除。"
},
"refCleanup": {
"header": "删除此项还会更新你的路由:",
"ruleRemoved": "规则 {label} — 已移除(没有剩余出口)",
"ruleModified": "规则 {label} — 已保留(现使用 {keeps}",
"balancerRemoved": "负载均衡器 {tag} — 已移除(没有剩余目标)"
},
"balancer": {
"addBalancer": "添加负载均衡",
"editBalancer": "编辑负载均衡",
"balancerStrategy": "策略",
"balancerSelectors": "选择器",
"tag": "标签",
"tagDesc": "唯一标签",
"tagDuplicate": "该标签已被其他均衡器使用",
"tagPlaceholder": "唯一均衡器标签",
"selector": "选择器",
"fallback": "Fallback",
"cycleTooltip": "循环: {path} → (回到 {start})",
"expected": "期望",
"expectedPlaceholder": "最佳节点数",
"maxRtt": "最大 RTT",
"tolerance": "容差",
"baselines": "Baselines",
"costs": "Costs",
"balancerDesc": "无法同时使用 balancerTag 和 outboundTag。如果同时使用,则只有 outboundTag 会生效。",
"costMatch": "标签匹配模式",
"costValue": "权重",
"costRegexp": "正则表达式匹配",
"balancerDeleteInUse": "无法删除此负载均衡器 — 它被用作以下负载均衡器的备用:{names}",
"balancerFallbackCycle": "无法将此负载均衡器设置为备用 — 这会创建循环依赖。",
"balancerFallbackInfo": "流量将通过以下路径路由:负载均衡器 → Loopback → 服务器 → 目标负载均衡器 → 出站连接。这会增加一个经过服务器的额外跳转,可能会引入轻微延迟。",
"fallbackBalancerHint": "选择另一个负载均衡器作为备用",
"reservedPrefix": "_bl_ 前缀保留给内部负载均衡器回环对象"
},
"wireguard": {
"secretKey": "密钥",
"publicKey": "公钥",
"allowedIPs": "允许的 IP",
"endpoint": "端点",
"psk": "共享密钥",
"domainStrategy": "域策略"
},
"tun": {
"nameDesc": "TUN 接口的名称。默认值为 'xray0'",
"mtuDesc": "最大传输单元。数据包的最大大小。默认值为 1500",
"userLevel": "用户级别",
"userLevelDesc": "通过此入站的所有连接都将使用此用户级别。默认值为 0"
},
"nord": {
"accessToken": "Access token",
"privateKey": "私钥",
"noServers": "未找到选定国家/地区的服务器",
"noPublicKey": "选定的服务器未公布 NordLynx 公钥。",
"outboundAdded": "NordVPN 出站已添加",
"outboundUpdated": "NordVPN 出站已更新"
},
"warp": {
"changeIp": "更换 IP",
"changeIpSuccess": "WARP IP 更换成功!",
"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+ 数据",
"quota": "配额",
"usage": "使用",
"addOutbound": "添加出站"
},
"dns": {
"enable": "启用 DNS",
"enableDesc": "启用内置 DNS 服务器",
"tag": "DNS 入站标签",
"tagDesc": "此标签将在路由规则中可用作入站标签",
"clientIp": "客户端IP",
"clientIpDesc": "用于在DNS查询期间通知服务器指定的IP位置",
"disableCache": "禁用缓存",
"disableCacheDesc": "禁用DNS缓存",
"disableFallback": "禁用回退",
"disableFallbackDesc": "禁用回退DNS查询",
"disableFallbackIfMatch": "匹配时禁用回退",
"disableFallbackIfMatchDesc": "当DNS服务器的匹配域名列表命中时,禁用回退DNS查询",
"enableParallelQuery": "启用并行查询",
"enableParallelQueryDesc": "启用并行DNS查询到多个服务器以实现更快的解析",
"strategy": "查询策略",
"strategyDesc": "解析域名的总体策略",
"add": "添加服务器",
"edit": "编辑服务器",
"domains": "域名",
"expectIPs": "预期 IP",
"unexpectIPs": "意外IP",
"useSystemHosts": "使用系统Hosts",
"useSystemHostsDesc": "使用已安装系统的hosts文件",
"serveStale": "提供过期结果",
"serveStaleDesc": "在后台刷新时返回过期的缓存结果",
"serveExpiredTTL": "过期TTL",
"serveExpiredTTLDesc": "过期缓存条目的有效期(秒);0 = 永不过期",
"timeoutMs": "超时 (毫秒)",
"skipFallback": "跳过回退",
"finalQuery": "最终查询",
"hosts": "Hosts",
"hostsAdd": "添加 Host",
"hostsEmpty": "未定义任何 Host",
"hostsDomain": "域名 (例如 domain:example.com)",
"hostsValues": "IP 或域名 — 输入后按 Enter",
"usePreset": "使用模板",
"dnsPresetTitle": "DNS模板",
"dnsPresetFamily": "家庭",
"clearAll": "删除全部",
"clearAllTitle": "删除所有 DNS 服务器?",
"clearAllConfirm": "此操作将从列表中删除所有 DNS 服务器,且无法撤销。",
"dnsLeakWarning": "DNS 可能通过 localhost、明文 UDP/TCP、本地模式 DoH/DoQ、回退查询或 EDNS client IP 泄漏。重视隐私时请使用经路由的 DoH、在 hosts 中固定解析器,并禁用回退。"
},
"fakedns": {
"add": "添加假 DNS",
"edit": "编辑假 DNS",
"ipPool": "IP 池子网",
"poolSize": "池大小"
},
"defaultOutbound": "默认出站",
"defaultOutboundDesc": "未匹配任何路由规则的流量走此出站(列表中的第一个出站)。"
},
"hosts": {
"addHost": "添加主机",
"editHost": "编辑主机",
"selectInbound": "选择一个入站",
"selectedCount": "已选 {count} 项",
"summary": {
"total": "总计",
"enabled": "已启用",
"disabled": "已禁用"
},
"moveUp": "上移",
"moveDown": "下移",
"bulkEnable": "启用",
"bulkDisable": "禁用",
"bulkDelete": "删除",
"bulkDeleteConfirm": "删除选中的 {count} 个主机?",
"deleteConfirmTitle": "删除主机 \"{name}\"",
"sections": {
"basic": "基本",
"security": "安全",
"advanced": "高级",
"general": "常规",
"clash": "Clash (mihomo)"
},
"fields": {
"remark": "备注",
"serverDescription": "描述",
"inbound": "入站",
"address": "地址",
"port": "端口",
"endpoint": "端点",
"enable": "启用",
"actions": "操作",
"security": "安全",
"sni": "SNI",
"overrideSniFromAddress": "使用地址作为 SNI",
"keepSniBlank": "保持 SNI 为空",
"hostHeader": "Host 头",
"path": "路径",
"alpn": "ALPN",
"fingerprint": "指纹",
"pins": "固定证书 SHA-256",
"verifyPeerCertByName": "按名称验证对端证书",
"allowInsecure": "允许不安全连接",
"echConfigList": "ECH 配置列表",
"muxParams": "Mux",
"sockoptParams": "Sockopt",
"finalMask": "Final Mask",
"vlessRoute": "VLESS 路由",
"mihomoIpVersion": "IP 版本",
"mihomoX25519": "Mihomo X25519",
"shuffleHost": "随机打乱 Host",
"tags": "标签",
"nodeGuids": "节点",
"excludeFromSubTypes": "从格式中排除",
"inheritAddress": "继承地址"
},
"hints": {
"address": "留空则继承入站自身的地址。",
"port": "填 0 则继承入站的端口。",
"tags": "对终端用户不可见;仅随 RAW 订阅发送。只能包含大写字母、数字、_ 和 :。",
"nodeGuids": "选择从此主机解析的节点。仅用于可视化关联。",
"serverDescription": "可选备注,显示在备注下方。",
"allowInsecure": "跳过 TLS 证书验证(allowInsecure / skip-cert-verify)。",
"vlessRoute": "嵌入 UUID 的单个 VLESS 路由值(0-65535),例如 443。留空表示不路由。",
"remark": "此主机的纯文本标签。仅当入站没有自己的备注时,才作为配置名称显示。"
},
"remarkVars": {
"title": "模板变量",
"intro": "点击变量即可添加。生成订阅时会按客户端逐一替换。",
"preview": "预览",
"groups": {
"client": "客户端",
"traffic": "流量",
"time": "时间与状态",
"connection": "连接"
},
"descEMAIL": "客户端邮箱",
"descINBOUND": "入站本身的备注(配置名称)",
"descHOST": "主机备注",
"descID": "客户端 UUID",
"descSHORT_ID": "UUID 的前 8 个字符",
"descTELEGRAM_ID": "客户端的 Telegram ID(未设置则为空)",
"descSUB_ID": "订阅 ID",
"descCOMMENT": "客户端备注",
"descTRAFFIC_USED": "已用流量(易读格式)",
"descTRAFFIC_LEFT": "剩余流量(无限制时隐藏)",
"descTRAFFIC_TOTAL": "总流量(无限制时隐藏)",
"descTRAFFIC_USED_BYTES": "已用流量(字节)",
"descTRAFFIC_LEFT_BYTES": "剩余流量(字节)",
"descTRAFFIC_TOTAL_BYTES": "总流量(字节)",
"descUP": "上传流量",
"descDOWN": "下载流量",
"descSTATUS": "active / expired / disabled / depleted",
"descSTATUS_EMOJI": "以表情符号显示状态(✅ ⏳ 🚫)",
"descDAYS_LEFT": "距到期天数(无限制时隐藏)",
"descTIME_LEFT": "剩余时间(例如 12d 4h 30m",
"descUSAGE_PERCENTAGE": "已用流量百分比(无限制时隐藏)",
"descEXPIRE_DATE": "到期日期(YYYY-MM-DD",
"descJALALI_EXPIRE_DATE": "Jalali(波斯)历的到期日期(YYYY/MM/DD",
"descEXPIRE_UNIX": "到期时间的 Unix 时间戳(秒)",
"descCREATED_UNIX": "创建时间的 Unix 时间戳(秒)",
"descRESET_DAYS": "流量重置周期(天)",
"descPROTOCOL": "入站协议(VLESS、VMess、Trojan……)",
"descTRANSPORT": "传输网络(tcp、ws、grpc……)",
"descSECURITY": "传输安全(TLS、REALITY、NONE"
},
"toasts": {
"list": "加载主机失败",
"obtain": "加载主机失败",
"add": "添加主机",
"update": "更新主机",
"delete": "删除主机",
"badTag": "无效的标签",
"badVlessRoute": "请输入 0 到 65535 之间的单个数字"
}
}
},
"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": "❗ 请输入要搜索的文本!",
"getID": "🆔 您的 ID 为:<code>{{ .ID }}</code>",
"helpAdminCommands": "要重新启动 Xray Core\r\n<code>/restart</code>\r\n\r\n要搜索客户电子邮件:\r\n<code>/usage [电子邮件]</code>\r\n\r\n要搜索入站(带有客户统计数据):\r\n<code>/inbound [备注]</code>\r\n\r\nTelegram聊天ID\r\n<code>/id</code>",
"helpClientCommands": "要搜索统计数据,请使用以下命令:\r\n<code>/usage [电子邮件]</code>\r\n\r\nTelegram聊天ID\r\n<code>/id</code>",
"restartUsage": "\r\n\r\n<code>/restart</code>",
"restartSuccess": "✅ 操作成功!",
"restartFailed": "❗ 操作错误。\r\n\r\n<code>错误: {{ .Error }}</code>.",
"xrayNotRunning": "❗ Xray Core 未运行。",
"startDesc": "显示主菜单",
"helpDesc": "机器人帮助",
"statusDesc": "检查机器人状态",
"idDesc": "显示您的 Telegram ID",
"usageDesc": "查看客户端用量:/usage 邮箱",
"inboundDesc": "搜索入站:/inbound 备注(管理员)",
"restartDesc": "重启 Xray 内核(管理员)",
"clearallDesc": "重置所有客户端流量(管理员)"
},
"messages": {
"cpuThreshold": "CPU 使用率为 {{ .Percent }}%,超过阈值 {{ .Threshold }}%",
"selectUserFailed": "❌ 用户选择错误!",
"userSaved": "✅ 电报用户已保存。",
"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": "🔢 IPs:\r\n{{ .IPs }}\r\n",
"serverUpTime": "⏳ 服务器运行时间:{{ .UpTime }} {{ .Unit }}\r\n",
"serverLoad": "📈 服务器负载:{{ .Load1 }}, {{ .Load2 }}, {{ .Load3 }}\r\n",
"serverMemory": "📋 RAM: {{ .Current }}/{{ .Total }}\r\n",
"tcpCount": "🔹 TCP: {{ .Count }}\r\n",
"udpCount": "🔸 UDP: {{ .Count }}\r\n",
"traffic": "🚦 流量:{{ .Total }} (↑{{ .Upload }},↓{{ .Download }})\r\n",
"xrayStatus": "️ 状态: {{ .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 }}\r\n",
"upload": "🔼 上传: ↑{{ .Upload }}\r\n",
"download": "🔽 下载: ↓{{ .Download }}\r\n",
"total": "📊 总计: ↑↓{{ .UpDown }} / {{ .Total }}\r\n",
"TGUser": "👤 电报用户:{{ .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": "📧📥 邮箱已更新。",
"received_comment": "💬📥 评论已更新。",
"id_prompt": "🔑 默认 ID: {{ .ClientId }}\n\n请输入您的 ID。",
"pass_prompt": "🔑 默认密码: {{ .ClientPassword }}\n\n请输入您的密码。",
"email_prompt": "📧 默认邮箱: {{ .ClientEmail }}\n\n请输入您的邮箱。",
"comment_prompt": "💬 默认评论: {{ .ClientComment }}\n\n请输入您的评论。",
"inbound_client_data_id": "🔄 入站: {{ .InboundRemark }}\n\n🔑 ID: {{ .ClientId }}\n📧 邮箱: {{ .ClientEmail }}\n📊 流量: {{ .ClientTraffic }}\n📅 到期日期: {{ .ClientExp }}\n🌐 IP 限制: {{ .IpLimit }}\n💬 备注: {{ .ClientComment }}\n\n你现在可以将客户添加到入站了!",
"inbound_client_data_pass": "🔄 入站: {{ .InboundRemark }}\n\n🔑 密码: {{ .ClientPass }}\n📧 邮箱: {{ .ClientEmail }}\n📊 流量: {{ .ClientTraffic }}\n📅 到期日期: {{ .ClientExp }}\n🌐 IP 限制: {{ .IpLimit }}\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": "🔚 所有客户的流量重置已完成。",
"eventOutboundDown": "出站 {{ .Tag }} 已断开",
"eventOutboundUp": "出站 {{ .Tag }} 已恢复",
"eventErrorDetail": "错误:{{ .Error }}",
"eventDelayDetail": "延迟:{{ .Delay }} 毫秒",
"eventXrayCrash": "Xray 已崩溃",
"eventXrayCrashError": "错误:{{ .Error }}",
"eventNodeDown": "节点 {{ .Name }} 已离线",
"eventNodeUp": "节点 {{ .Name }} 已上线",
"eventCPUHigh": "CPU 占用过高",
"eventCPUHighDetail": "CPU{{ .Detail }}",
"eventLoginFallback": "来自 {{ .Source }} 的登录失败",
"memoryThreshold": "内存使用率 {{ .Percent }}% 超过阈值 {{ .Threshold }}%"
},
"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": "⚙️📧 邮箱",
"change_comment": "⚙️💬 评论",
"change_flow": "⚙️🚦 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 用户 ChatID。\r\n\r\n您的用户 ChatID<code>{{ .TgUserID }}</code>",
"chooseClient": "为入站 {{ .Inbound }} 选择一个客户",
"chooseInbound": "选择一个入站"
}
},
"email": {
"subjectOutboundDown": "出站 {{ .Tag }} 已断开",
"subjectOutboundUp": "出站 {{ .Tag }} 已恢复",
"subjectXrayCrash": "Xray 已崩溃",
"subjectCPUHigh": "CPU 占用过高",
"subjectLoginSuccess": "登录成功",
"subjectLoginFailed": "登录失败",
"titleOutboundDown": "出站断开",
"titleOutboundUp": "出站恢复",
"titleXrayCrash": "Xray 已崩溃",
"titleCPUHigh": "CPU 占用过高",
"titleLoginSuccess": "登录成功",
"titleLoginFailed": "登录失败",
"labelStatus": "状态",
"labelOutbound": "出站",
"labelNode": "节点",
"labelError": "错误",
"labelDelay": "延迟",
"labelDetail": "详情",
"labelUsername": "用户名",
"labelIP": "IP",
"labelReason": "原因",
"labelSource": "来源",
"labelTime": "时间",
"statusCrashed": "已崩溃",
"statusRunning": "运行中",
"statusHigh": "过高",
"statusSuccess": "成功",
"statusFailed": "失败",
"statusDown": "断开",
"statusUp": "恢复"
}
}