Files
3x-ui/web/translation/fa-IR.json
Sanaei 85e2ded0e1 Feat/multi inbound clients (#4469)
* feat(clients): add shadow tables for first-class client promotion

Introduces three new GORM-backed tables (clients, client_inbounds,
inbound_fallback_children) and a populate-only seeder that backfills
them from each inbound's existing settings.clients JSON. Duplicate
emails across inbounds auto-merge under one client row, with each
field conflict logged. Existing services are unchanged and continue
reading from settings.clients — this commit is groundwork only.

* feat(clients): make clients+client_inbounds the runtime source of truth

Adds ClientService.SyncInbound that reconciles the new tables from
each inbound's clients list whenever existing service paths mutate
settings.clients. Wires it into AddInbound, UpdateInbound,
AddInboundClient, UpdateInboundClient, DelInboundClient,
DelInboundClientByEmail, DelDepletedClients, autoRenewClients, and
the timestamp-backfill path in adjustTraffics, plus DetachInbound
on DelInbound.

GetXrayConfig now builds settings.clients from the new tables before
writing config.json, and getInboundsBySubId joins through them
instead of JSON_EACH on settings JSON. Live Xray config and
subscription endpoints are now driven by the relational view;
settings.clients JSON stays in step as a side effect of every write.

* feat(clients): add top-level Clients tab and CRUD API

Adds /panel/api/clients endpoints (list, get, add, update, del,
attach, detach) backed by ClientService methods that orchestrate
the per-inbound Add/Update/Del flows so a single client row is
created once and attached to many inbounds in one operation.

The frontend gains a dedicated Clients page (frontend/clients.html
+ src/pages/clients/) with an AntD table, multi-inbound attach
modal, and full CRUD. Axios interceptor learns to honour
Content-Type: application/json so the JSON endpoints work
alongside the legacy form-encoded ones.

The legacy per-inbound client modal stays untouched in this PR —
both flows now write to the same source of truth.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* feat(inbounds): add Port-with-Fallback inbound type

Adds a new "portfallback" protocol that emits as a VLESS-TLS inbound
under the hood but is paired with a sidecar table of child inbounds.
Panel auto-builds settings.fallbacks at Xray-config-gen time from the
sidecar — each child's listen+port becomes the fallback dest, with
SNI/ALPN/path/xver match criteria pulled from the row. No more typing
loopback ports by hand or keeping settings.fallbacks in sync.

Backend: new FallbackService (Get/SetChildren, BuildFallbacksJSON);
two new routes (GET/POST /panel/api/inbounds/:id/fallbackChildren);
xray.GetXrayConfig injects fallbacks for PortFallback inbounds; the
inbound model emits protocol="vless" so Xray accepts the config.

Frontend: PORTFALLBACK joins the protocol dropdown; selecting it
shows the standard VLESS controls plus a Fallback Children table
(inbound picker + per-row SNI/ALPN/path/xver). Children are loaded
on edit and replaced atomically on save.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* feat(clients): add Reset Traffic, QR Code, Info actions + Online/Remaining columns

The Clients page table gains:
- Online column — green/grey tag driven by /panel/api/inbounds/onlines,
  polled every 10s.
- Remaining column — bytes-remaining tag, coloured green/orange/red
  against quota, purple infinity when unlimited.
- Action icons per row: QR, Info, Reset traffic, Edit, Delete.

ClientInfoModal shows the full client detail (uuid/password/auth,
traffic ↑/↓ + remaining + all-time, expiry absolute + relative,
attached inbounds chip list, online + last-online).

ClientQrModal fetches links for the client's subId via
/panel/api/inbounds/getSubLinks/:subId and renders each one through
the existing QrPanel component.

Reset Traffic confirms then calls the existing per-inbound endpoint
on the client's first attached inbound (the traffic row is keyed on
email globally, so any attached inbound resets the shared counter).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(clients): expose Attached inbounds in edit mode

The multi-select was gated on add-only, so editing a client had no way
to change which inbounds it belonged to. The picker now shows in both
modes, and on submit the modal diffs the picked set against the
original attachedIds — additions go through the /attach endpoint,
removals through /detach, both after the field update lands so the
new attachments get the latest values.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(clients): unbreak template parsing + stale i18n keys

- InboundFormModal: split the multi-line help string in the
  PortFallback section onto one line — Vue's template parser was
  bailing on Unterminated string constant because a single-quoted
  literal spanned two lines inside a {{ }} interpolation.
- ClientInfoModal: t('disable') was missing at the root level, so
  vue-i18n returned the key path literally. Use t('disabled') which
  exists.
- Linter cleanup elsewhere: pages.client.* references renamed to
  pages.clients.* to match the merged i18n block; whitespace
  normalisation in a few unrelated Vue templates.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* 1

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* refactor(traffic): drop all-time traffic tracking

Removes the AllTime field from Inbound and ClientTraffic and migrates
existing DBs by dropping the all_time columns on startup. The counter
duplicated up+down without adding signal, and the per-event accumulator
ran on every traffic write.

Frontend: drop the All-time column from the inbound list and the
client-row table, the All-time row from the client info modal, and the
All-Time Total Usage tile from the inbounds summary card. The
allTimeTraffic/allTimeTrafficUsage i18n keys are removed across every
locale.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* feat(clients): mobile cards, multi-select, bulk add

Adds the same row-card layout the inbounds page uses on mobile: the
table is suppressed under the mobile breakpoint and each client renders
as a compact card with a status dot, email, Info button, Enable switch,
and overflow menu. All the per-client detail (traffic, remaining,
expiry, attached inbounds, flow, created/updated, URL, subscription)
opens through the existing info modal.

Multi-select with bulk delete wires AntD row-selection on desktop and
a per-card checkbox on mobile; a Delete (N) button appears in the
toolbar when anything is selected.

Bulk add reuses the five email-generation modes from the inbound bulk
modal but takes a multi-inbound picker so one bulk run can attach to
several inbounds at once. Submits client-by-client through the
existing /panel/api/clients/add endpoint.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* refactor(inbounds): remove legacy per-inbound client UI

Now that clients live as first-class rows attached to one or many
inbounds, the per-inbound client UI on the inbounds page is dead
weight — every client action either has a global equivalent on the
Clients page or makes no sense in a many-to-many world.

Deletes ClientFormModal, ClientBulkModal, CopyClientsModal, and
ClientRowTable from inbounds/. Strips the matching emits, refs,
handlers, and dropdown menu items from InboundList and InboundsPage,
and removes the dead mobile expand-chevron state and the desktop
expanded-row plumbing that drove the inline client table.

The InboundFormModal Clients tab still works in add-mode (one inline
client at inbound creation) — that flow goes through ClientService.
SyncInbound on save and remains useful.

Fixes a stray "</a-dropdown>" left over by an earlier toolbar edit
in ClientsPage that broke the template parser.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* feat(clients): add Delete depleted action

Mirrors the legacy delDepletedClients action that lived under the
inbounds page, but as a first-class /panel/api/clients/delDepleted
endpoint backed by ClientService. The new path goes through
ClientService.Delete for each depleted email, so the new clients +
client_inbounds + xray_client_traffic tables stay consistent.

Adds a danger-styled toolbar button on the Clients page (next to
Reset all client traffic) with a confirm dialog and a toast
reporting the deleted count.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* refactor(api): move every client-shaped endpoint off /inbounds onto /clients

After the multi-inbound client migration, client state belongs to the
client API surface, not the inbound one. Twelve routes that were
crammed under /panel/api/inbounds/* now live where they belong, under
/panel/api/clients/*.

Moved (route, handler, doc):
  POST  /clientIps/:email
  POST  /clearClientIps/:email
  POST  /onlines
  POST  /lastOnline
  POST  /updateClientTraffic/:email
  POST  /resetAllClientTraffics/:id
  POST  /delDepletedClients/:id
  POST  /:id/resetClientTraffic/:email
  GET   /getClientTraffics/:email
  GET   /getClientTrafficsById/:id
  GET   /getSubLinks/:subId
  GET   /getClientLinks/:id/:email

Their /clients/* counterparts are:
  POST  /clients/clientIps/:email
  POST  /clients/clearClientIps/:email
  POST  /clients/onlines
  POST  /clients/lastOnline
  POST  /clients/updateTraffic/:email
  POST  /clients/resetTraffic/:email          (email-only, fans out)
  GET   /clients/traffic/:email
  GET   /clients/traffic/byId/:id
  GET   /clients/subLinks/:subId
  GET   /clients/links/:id/:email

per-inbound resetAllClientTraffics and delDepletedClients are dropped
entirely — the Clients page already exposes global Reset All Traffic
and Delete depleted actions, and per-inbound resets are meaningless
once a client can be attached to many inbounds.

ClientService.ResetTrafficByEmail is the new email-only reset path:
it looks up every inbound the client is attached to and pushes the
counter reset + Xray re-add through inboundService.ResetClientTraffic
for each one, so depleted users come back online instantly.

Frontend callers (ClientsPage, useClients, ClientQrModal,
ClientInfoModal, InboundInfoModal, InboundsPage, useInbounds) all
switched to the new paths. The Inbounds page drops its per-inbound
"Reset client traffic" and "Delete depleted clients" dropdown items —
users do those at the client level now. api-docs is rebuilt to match.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* refactor(service): switch tgbot + ldap callers to ClientService

Adds two thin helpers to ClientService (CreateOne, DetachByEmail) and
rewrites tgbot.SubmitAddClient and ldap_sync_job to call ClientService
directly. Removes the JSON-blob payloads (BuildJSONForProtocol output for
add, clientsToJSON/clientToJSON helpers) that callers previously fed to
InboundService.AddInboundClient/DelInboundClient.

ldap_sync_job.batchSetEnable now loops InboundService.SetClientEnableByEmail
per email instead of trying to coerce AddInboundClient into doing the
update — the old path would have failed duplicate-email validation for
existing clients anyway.

The legacy InboundService.AddInboundClient/UpdateInboundClient/
DelInboundClient methods stay in place; they are now only used internally
by ClientService Create/Update/Delete/Attach. Inlining + deleting them
follows in a separate commit.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* refactor(service): move all client mutation methods to ClientService

Moves the client mutation surface out of InboundService and into
ClientService. These methods all operate on a single client (identity
fields, traffic limits, expiry, ip limit, enable state, telegram tg id)
and didn't belong on the inbound aggregate.

Moved (12 methods): AddInboundClient, UpdateInboundClient, DelInboundClient,
DelInboundClientByEmail, checkEmailsExistForClients, SetClientTelegramUserID,
checkIsEnabledByEmail, ToggleClientEnableByEmail, SetClientEnableByEmail,
ResetClientIpLimitByEmail, ResetClientExpiryTimeByEmail,
ResetClientTrafficLimitByEmail.

Each method now takes an explicit *InboundService for the helpers that
legitimately stay on InboundService (GetInbound, GetClients, runtimeFor,
AddClientStat / UpdateClientStat / DelClientStat, DelClientIPs /
UpdateClientIPs, emailUsedByOtherInbounds, getAllEmailSubIDs,
GetClientInboundByEmail / GetClientInboundByTrafficID,
GetClientTrafficByEmail).

Stays on InboundService: ResetClientTrafficByEmail and
ResetClientTraffic(id, email) — these mutate xray_client_traffic rows,
not client identity, so they're inbound-side bookkeeping.

Callers updated: tgbot (6 calls), ldap_sync_job (1 call),
InboundService internal (writeBackClientSubID, CopyInboundClients,
AddInbound's email-uniqueness check), ClientService Create/Update/
Delete/Attach/Detach.

Also removes a dead resetAllClientTraffics controller handler whose
route was already gone after the previous /clients API migration.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* refactor(clients): finish migrating to ClientService + tidy IP routes

Two related cleanups in the new /clients surface:

1. Move ResetAllClientTraffics (bulk-reset of xray_client_traffic +
   last_traffic_reset_time, with node-runtime propagation) from
   InboundService to ClientService. PeriodicTrafficResetJob now holds
   a clientService and calls
   j.clientService.ResetAllClientTraffics(&j.inboundService, id).
   The last client-mutation method on InboundService is gone.

2. Shorten redundantly-named routes/handlers under /panel/api/clients:
   - /clientIps/:email      -> /ips/:email      (handler getIps)
   - /clearClientIps/:email -> /clearIps/:email (handler clearIps)
   The "client" prefix was redundant inside the clients namespace.

Frontend (InboundInfoModal) and api-docs updated to match.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* feat(inbounds,clients): clean up inbound modal + enrich client modal

Inbound modal rework (InboundFormModal.vue + inbound.js):
- Drop the embedded Client subform in the Protocol tab. Multi-inbound
  clients are managed exclusively from the Clients page now; a fresh
  inbound is created with zero clients (settings constructors default
  to []) and the user attaches clients afterwards.
- Hide the Protocol tab entirely when it has nothing to render
  (VMESS, Trojan without fallbacks, Hysteria). Auto-switches active
  tab to Basic when the tab disappears while focused.
- Move the Security section (Security selector + TLS block with certs
  and ECH + Reality block) out of the Stream tab into its own
  Security tab, sharing the canEnableStream gate.

Client modal additions (ClientFormModal.vue + ClientBulkAddModal.vue):
- Flow select (xtls-rprx-vision / -udp443) appears only when the
  panel actually has a Vision-capable inbound (VLESS or PortFallback
  on TCP with TLS or Reality). Hidden otherwise, and cleared when
  it disappears.
- IP Limit input is disabled when the panel-level ipLimitEnable
  setting is off, fetched into useClients alongside subSettings and
  threaded through ClientsPage to both modals.
- Edit modal now shows an "IP Log" section listing IPs that have
  connected with the client's credentials, with refresh and clear
  buttons (calls the renamed /panel/api/clients/ips and /clearIps
  endpoints).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* refactor(inbounds): drop manual Fallbacks UI from inbound modal

The PortFallback protocol type now covers the common
VLESS-master-plus-children case with auto-wired dests, so the manual
Fallbacks editor (showFallbacks block in the Protocol tab) is mostly
redundant. Removed:

- the v-if="showFallbacks" template block (SNI/ALPN/Path/dest/PROXY rows)
- the showFallbacks computed
- the addFallback / delFallback helpers
- the .fallbacks-header / .fallbacks-title styles
- the showFallbacks gate from hasProtocolTabContent (so Trojan-over-TCP
  no longer shows an empty Protocol tab)

Power users who need a non-inbound fallback dest (nginx, static site)
can still author settings.fallbacks via the Advanced JSON tab.

* feat(clients,inbounds): move search/filter to Clients page + small fixes

Search/filter relocation:
- Remove the search/filter toolbar (search switch + filter radio +
  protocol/node selects + the visibleInbounds projection +
  inboundsFilterState localStorage + filter CSS + the SearchOutlined/
  FilterOutlined/ObjectUtil/Inbound imports it required) from
  InboundList. The filters were all client-oriented buckets bolted
  onto the inbound row.
- Add a search/filter toolbar to ClientsPage with the same shape:
  switch between deep-text search and bucket filter (active /
  deactive / depleted / expiring / online) + protocol filter that
  matches clients attached to at least one inbound with the chosen
  protocol. State persists in clientsFilterState localStorage.
  filteredClients drives both the desktop table and the mobile card
  list, and select-all / allSelected / someSelected only span the
  visible subset.
- useClients now also fetches expireDiff and trafficDiff from
  /panel/setting/defaultSettings (used to detect the expiring
  bucket); ClientsPage threads them into the client-bucket helper.

Loose fixes folded in:
- Add Client: email field is auto-filled with a random handle on
  open, matching uuid/subId/password/auth.
- Inbound clone: parse and reuse the source settings JSON (with
  clients reset to []) instead of building a fresh defaulted
  Settings, so VLESS Encryption/Decryption and other non-client
  fields survive the clone.
- en-US.json: add the ipLog string used by the edit-client modal.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* feat(clients): add Reverse tag field for VLESS-attached clients

Mirrors the Flow field's pattern: a Reverse tag input appears in the
Add/Edit Client modal whenever at least one selected inbound is VLESS
or PortFallback. The value rides over the wire as
client.reverse = { tag: '...' } so it lands directly in model.Client's
*ClientReverse field; an empty value omits the reverse key entirely.

On edit the field is hydrated from props.client.reverse?.tag, and the
showReverseTag watcher clears the field if the user drops the last
VLESS-like inbound from the selection.

* fix(xray): emit only protocol-relevant fields per client entry

The Xray config synthesizer was writing every identifier field (id,
password, flow, auth, security/method, reverse) on every client entry
regardless of the inbound's protocol. Xray ignores unknown fields, so
the config worked, but it diverged from the spec and leaked secrets
across protocols when one client was attached to multiple inbounds —
a VLESS inbound's generated config carried the same client's Trojan
password and Hysteria auth alongside its uuid.

Switch on inbound.Protocol when building each entry:
- VLESS / PortFallback: id, flow, reverse
- VMess: id, security
- Trojan: password, flow
- Shadowsocks: password, method
- Hysteria / Hysteria2: auth
email is emitted for every protocol.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(clients): restore auto-disable kick under new schema

disableInvalidClients still resolved (inbound_tag, email) pairs via
JSON_EACH(inbounds.settings.clients), which is empty after migrating
to the clients + client_inbounds tables. Result: xrayApi.RemoveUser
never ran for depleted clients, clients.enable stayed true so the UI
showed them as active, and only xray_client_traffic.enable got flipped
- making "Restart Xray After Auto Disable" only half-work.

Resolve the targets via a JOIN through the new schema, flip clients.enable
so the Clients page reflects the state, and drop the legacy JSON
write-back plus the subId cascade workaround (email is unique now).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* feat(clients): live WebSocket updates + Ended status surfacing

ClientsPage now subscribes to traffic / client_stats / invalidate
WebSocket events instead of polling /onlines every 10s. Per-row
traffic counters refresh in place, online state stays current, and
list-level mutations elsewhere trigger a refresh.

The client roll-up summary moves from InboundsPage to ClientsPage
where it belongs, restructured into six labeled stat tiles
(Total / Online / Ended / Expiring / Disabled / Active) with email
popovers on the ones with issues.

Auto-disabled clients (traffic exhausted or expiry passed) now
classify as 'depleted' even though clients.enable=false, so they
show up under the Ended filter and render a red Ended tag instead
of looking indistinguishable from an operator-disabled row.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* feat(nodes): per-node client roll-up and panel version

Added transient inboundCount / clientCount / onlineCount /
depletedCount fields to model.Node, populated by NodeService.GetAll
via aggregated queries (one join across inbounds + client_inbounds,
one over client_traffics intersected with the in-memory online
emails). The Nodes list renders these as colored chips on a new
"Clients" column so an operator can see at a glance how many users
each node carries and how many are currently online or depleted.

Also exposes the remote panel's version. The central panel adds
panelVersion to its /api/server/status payload (sourced from
config.GetVersion). Probe reads that field and persists it on the
node row, mirroring how xrayVersion already flows. NodesPage gets
a new column next to Xray Version, in both desktop and mobile
views, with English and Persian strings.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(clients): stop node sync from resurrecting deleted clients

Several related issues around node-managed clients:

- Remote runtime: drop the per-inbound resetAllClientTraffics path
  and point traffic/onlines/lastOnline fetches at the new
  /panel/api/clients/* routes.
- Delete from master: always push the updated inbound to the node
  even when the client was already disabled or depleted, so the
  node actually loses the user instead of silently keeping it.
- setRemoteTraffic: mirror remote clients into the central tables
  only on first discovery of a node inbound. Matched inbounds let
  the master own the join table, so a stale snap can no longer
  re-create a ClientRecord (and join row) for a client that was
  just deleted on the master.
- ClientService.Delete: route through submitTrafficWrite so deletes
  serialize with node traffic merges, and switch the final
  ClientRecord delete to an explicit Where("id = ?") clause.
- setRemoteTraffic UNIQUE-constraint fix: use clause.OnConflict on
  inserts and email-keyed UPDATEs for client_traffics, so mirroring
  a snap doesn't trip the unique email index.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* refactor(clients): switch client API endpoints from id to email

All client-scoped routes now use the unique email as the path key
(get, update, del, attach, detach, links). Email is the stable,
protocol-independent identifier — UUIDs don't exist for trojan or
shadowsocks, and internal numeric ids leaked panel implementation
detail into the public API.

Removed the redundant /traffic/byId/:id endpoint (covered by
/traffic/:email) and collapsed /links/:id/:email into /links/:email,
which now returns links across every attached inbound for the client.

Frontend selection, bulk delete, and toggle state are now keyed by
email as well, dropping the id→email lookup workaround.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* refactor(server): move cached state and helpers into ServerService

ServerController had grown to hold its own status cache, version-list
TTL cache, history-bucket whitelist, and the loop that drove all three
— concerns that belong in the service layer. Pull them out:

- lastStatus + the @2s refresh become ServerService.RefreshStatus and
  ServerService.LastStatus; the controller's cron now just orchestrates
  the cross-service side effects (xrayMetrics sample, websocket broadcast).
- The 15-minute Xray-versions cache (with stale-on-error fallback) moves
  into ServerService.GetXrayVersionsCached, collapsing the controller
  handler to a single call.
- The freedom/blackhole outbound-tag walk used by /xraylogs becomes
  ServerService.GetDefaultLogOutboundTags.
- The allowed-history-bucket whitelist moves to package-level
  service.IsAllowedHistoryBucket, so both NodeController and
  ServerController validate against the same list.

Net result: web/controller/server.go drops from 458 to 365 lines and
contains only HTTP wiring + presentation-y side effects.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* refactor(api): emit JSON-text columns as nested objects

Inbound, ClientRecord, and InboundClientIps store settings /
streamSettings / sniffing / reverse / ips as JSON-text in the DB. The
API was passing that text through verbatim, so every consumer had to
JSON.parse a string inside a string. Add MarshalJSON / UnmarshalJSON so
the wire format is a real nested object, while still accepting the
legacy escaped-string shape on write. Frontend dbinbound.js gets a
matching coerceInboundJsonField helper for the same dual-shape read
path, and inbound.js toJson stops emitting empty/placeholder fields
(externalProxy [], sniffing destOverride when disabled, etc.) so the
new normalised JSON stays terse. api-docs and the inbound-clone path
are updated to the new shape. Controller route lists are regrouped so
all GETs sit above POSTs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(clients): include inboundIds and traffic in /clients/list

ClientRecord got its own MarshalJSON in the previous commit, and
ClientWithAttachments embeds it to add inboundIds and traffic. Go
promotes the embedded MarshalJSON to the outer struct, so the encoder
was calling ClientRecord.MarshalJSON for the whole value and silently
dropping the extras. The frontend reads row.inboundIds / row.traffic
from /clients/list, so attached inbounds didn't render and newly added
clients looked like they hadn't saved. Add an explicit MarshalJSON on
ClientWithAttachments that splices the extras in.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(clients): gate IP Log on ipLimitEnable + clean access-log dropdown

Legacy panel hid the IP Log section when access logging was off; the
Vue 3 migration left it gated on isEdit only, so the section showed
even when xray's access log was 'none' and nothing was being recorded.
Restore the ipLimitEnable gate on the edit modal's IP Log form-item.

While here, clean up the Xray Settings access-log dropdown: previously
two 'none' entries appeared (an empty value labelled with t('none') and
the literal 'none' from the options array). Drop the empty option for
access log (the literal 'none' covers it) and relabel the empty option
for error log / mask address to t('empty') so they're distinguishable.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(nodes): route per-client ops through node clients API + orphan sweep

Adds Runtime methods AddClient, UpdateUser, and DeleteUser so master
mutates clients on a node via /panel/api/clients/{add,update,del} rather
than pushing the whole inbound. The previous rt.UpdateInbound path made
the node DelInbound+AddInbound on every single-client change, briefly
cycling every other user on the same inbound.

DelInbound no longer filters by enable=true, so a disabled node inbound
actually gets removed from the node instead of being resurrected by the
next snap.

setRemoteTrafficLocked now sweeps any ClientRecord with zero
ClientInbound rows after SyncInbound rebuilds the attachments, which is
how a node-side delete propagates back to master instead of leaving a
detached ghost. ClientService.Delete tombstones the email first so a
snap arriving mid-delete can't re-create the record.

WebSocket broadcasts an "invalidate(clients)" message on every client
mutation so the Clients page refreshes without manual reload.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* feat(balancers): allow fallback on all strategies + feed burstObservatory from random/roundRobin

Drops the random/roundRobin gate on the Fallback field in
BalancerFormModal so every strategy can pick a fallback outbound.

syncObservatories now feeds burstObservatory from leastLoad +
random + roundRobin balancers (was leastLoad only), matching how
leastPing feeds observatory.

Fix the JsonEditor "Unexpected end of JSON input" that appeared
when switching a balancer between leastPing and another strategy:
the obsView watcher was gated on showObsEditor (a boolean OR of
the two flags) and missed the case where one observatory
swapped for the other in the same tick. Watch the individual
flags instead so obsView flips to the surviving editor and the
getter stops pointing at a deleted key.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(inbounds): use sortedInbounds for mobile empty-state check

InboundList referenced an undefined visibleInbounds in the mobile
card list's empty-state guard, throwing "Cannot read properties of
undefined (reading 'length')" and breaking the entire mobile render.

* feat(clients): sortable table columns

Adds the same sortState / sortableCol / sortFns pattern InboundList
uses, wrapping filteredClients in sortedClients so sort composes with
the existing search/filter pipeline. Sortable: enable, email,
inboundIds (attachment count), traffic, remaining, expiryTime;
actions and online stay unsorted.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(shadowsocks): generate valid ss2022 keys and per-client method for legacy ciphers

The Add Client flow on shadowsocks inbounds was producing xray configs
that failed to start:

- 2022-blake3-* ciphers need a base64-encoded key of an exact byte
  length per cipher. fillProtocolDefaults was assigning a uuid-style
  string, which xray rejects as "bad key". Now the password is
  generated (or replaced if invalid) via random.Base64Bytes(n) sized
  to the chosen cipher.
- Legacy ciphers (aes-256-gcm, chacha20-*, xchacha20-*) require a
  per-client method field in multi-user mode; model.Client has no
  Method, so settings.clients was stored without one and xray failed
  with "unsupported cipher method:". applyShadowsocksClientMethod
  now injects the top-level method into each client on add/update,
  and healShadowsocksClientMethods backfills it at xray-config-build
  time so existing inbounds heal on the next start.
- xray/api.go ssCipherType switch was missing aes-256-gcm, which
  fell through to ss2022 path.
- SSMethods dropdown now offers aes-256-gcm.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(clients): preserve ClientRecord on inbound delete + filter Attached inbounds to multi-client protocols

Replace the global orphan sweep in setRemoteTrafficLocked with a
per-inbound diff cleanup: only delete a ClientRecord whose email
disappeared from a snap-tracked inbound (i.e. a node-side delete).
Inbounds that vanished entirely from the snap (e.g. admin deleted
the inbound on master) aren't iterated, so a client whose last
attachment came from that inbound is now left alone instead of
being deleted alongside the inbound.

ClientFormModal and ClientBulkAddModal now filter the Attached
inbounds dropdown to protocols that actually support multiple
clients: shadowsocks, vless, vmess, trojan, hysteria, hysteria2,
and portfallback (which routes through VLESS settings).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(clients): make empty-state text readable on dark/ultra themes

The "No clients yet" empty state had a hardcoded black color
(rgba(0,0,0,0.45)) that vanished against the dark backgrounds.
Drop the inline color, let it inherit from the AntD theme, and
fade with opacity like the mobile card empty state already does.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* feat(clients): client-first tgbot add flow, tgId field, lightweight inbound options

- tgbot: drop legacy per-protocol Add Client UI in favour of a client-first
  multi-inbound flow. New BuildClientDraftMessage / getInboundsAttachPicker
  let an admin pick one or more inbounds and submit a single client; per-
  protocol secrets are now generated server-side via fillProtocolDefaults.
  Drops awaiting_id/awaiting_password_tr/awaiting_password_sh state cases
  and add_client_ch_default_id/pass_tr/pass_sh/flow callbacks. Adds a
  setTGUser button + awaiting_tg_id state so the bot can set Client.TgID
  during Add.
- clients UI: add Telegram user ID input to ClientFormModal (0 = none).
  Hide IP Limit field entirely when ipLimitEnable is off — disabled fields
  still take layout space, this collapses Auth(Hysteria) to full width.
- inbounds API: new GET /panel/api/inbounds/options that returns just
  {id, remark, protocol, port, tlsFlowCapable}. Used by the clients page
  pickers so the dropdown payload stays small on panels with thousands of
  clients (drops settings JSON, clientStats, streamSettings). Server-side
  TlsFlowCapable mirrors Inbound.canEnableTlsFlow so the modal no longer
  needs to parse streamSettings client-side.
- clientInfoMsg now shows attached inbound remarks, and getInboundUsages
  reports the attached client count per inbound.
- api-docs: document the new /options endpoint and add tgId / flow to the
  clients add/update bodies.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(inbounds): keep Node column visible for node-attached inbounds

The Node column was bound to hasActiveNode, so disabling every node hid
the column even when inbounds were still attached to those nodes — the
admin lost the visual cue that those inbounds belonged to a node and
would come back when it was re-enabled. Combine hasActiveNode with a
new hasNodeAttachedInbound check (any dbInbound with nodeId != null) so
the column survives node-disable.

* fix(api-docs): accept functional-component icons in EndpointSection

AntD-Vue icons (SafetyCertificateOutlined, etc.) are functional
components, so the icon prop's type: Object validator was rejecting
them with a "Expected Object, got Function" warning at runtime.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* test: cover crypto, random, netsafe, sub helpers, xray equals, websocket hub, node service

Adds ~110 unit tests across previously untested packages. Focus on
pure-logic and concurrency surfaces where regressions would silently
affect users:

- util/crypto, util/random: password hashing round-trip, ss2022 key
  generation, alphabet/length invariants.
- util/netsafe: IsBlockedIP edge cases, NormalizeHost validation,
  SSRF guard with AllowPrivate context bypass.
- util/common, util/json_util: traffic formatter, Combine nil-skip,
  RawMessage empty-as-null and copy-on-unmarshal.
- sub: splitLinkLines, searchKey/searchHost, kcp share fields,
  finalmask normalization, buildVmessLink round-trip.
- xray: Config.Equals and InboundConfig.Equals field-by-field,
  getRequiredUserString/getOptionalUserString type checks.
- web/websocket: hub registration, throttling, slow-client eviction,
  nil-receiver safety, concurrent register/unregister.
- web/service: NodeService.normalize validation, normalizeBasePath,
  HeartbeatPatch.ToUI mapping.
- web/job: atomicBool concurrent set/takeAndReset semantics.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* i18n(clients): replace English fallbacks with proper translation keys

Pulls every hard-coded English label/title in the Clients page and its
four modals through the i18n layer so localized panels stop leaking
English. New keys live under pages.clients (auth, hysteriaAuth, uuid,
flow, flowNone, reverseTag, reverseTagPlaceholder, telegramId,
telegramIdPlaceholder, created, updated, ipLimit) plus refresh at the
root and toasts.bulkDeletedMixed / bulkCreatedMixed for partial-failure
toasts. Also switches the add-client modal's primary button from "Add"
to "Create" for consistency with other create flows.

The bulk-add Random/Random+Prefix/... email-method options stay
hard-coded by request - they're identifier-shaped strings.

* i18n: backfill 99 missing keys across all 12 non-English locales

Brings every translation file up to parity with en-US.json so the
Clients page, the fallback-children inbound section, the new refresh
verb, the Nodes panel-version label and a handful of older holes stop
falling through to the English fallback. New strings span:

- pages.clients.* (labels, confirmations, toasts, emailMethods)
- pages.inbounds.portFallback.* (Reality fallback inbound section)
- pages.nodes.panelVersion, menu.clients, refresh

Technical identifiers (Auth, UUID, Flow, Reverse tag) are intentionally
left untranslated since they correspond to xray-core field names.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* i18n: drop stale pages.client block duplicated in every non-English locale

Every non-English locale carried a pages.client (singular) section with
30 entries that duplicated pages.clients (plural). The plural namespace
is what the Vue code actually consumes; the singular one was dead
weight from an older rename that never got cleaned up in the
non-English files. Removing it brings every locale to exactly 984
keys, matching en-US.json.

* chore: apply modernize analyzer fixes across codebase

Mechanical replacements suggested by golang.org/x/tools/.../modernize:
strings.Cut/CutPrefix/SplitSeq, slices.Contains, maps.Copy, min(),
range-over-int, new(expr), strings.Builder for hot += loops,
reflect.TypeFor[T](), sync.WaitGroup.Go(), drop legacy //+build lines.

* feat(database): add PostgreSQL as an optional backend alongside SQLite

Lets operators with large client counts or multi-node setups pick PostgreSQL
at install time without breaking the existing SQLite default. Backend is
selected at runtime via XUI_DB_TYPE/XUI_DB_DSN, a small dialect layer keeps
the five JSON_EXTRACT/JSON_EACH queries portable, and a new `x-ui migrate-db`
subcommand copies SQLite data into PostgreSQL in FK-aware order.

* fix(inbounds): gate node selector to multi-node-capable protocols

Hide the Deploy-To selector and clear nodeId when switching to a
protocol that can't run on a remote node. Also:

- subs: return 404 (not 400) when subId matches no inbounds, so VPN
  clients distinguish "deleted/unknown" from a server error
- hysteria link gen: use the inbound's resolved address so node-managed
  inbounds advertise the node host instead of the central panel
- shadowsocks: default network to 'tcp' (udp was causing issues for some
  clients on first-create)
- vite dev proxy: rewrite migrated-route bypass against the live base
  path instead of a hardcoded single-segment regex

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(clients): bulk add/delete correctness + perf, working pagination, delayed-start in form

Bulk add/delete were serial on the frontend (one toast per call, N round-trips)
and the backend race exposed by parallelizing them lost client attachments and
hit UNIQUE constraint failed on client_inbounds. The single add/edit modal also
had no Start-After-First-Use option, and the table never showed the delayed
duration.

Backend (web/service/client.go):
- Per-inbound mutex on Add/Update/Del InboundClient so concurrent writers on
  the same inbound don't lose the read-modify-write of settings JSON.
- SyncInbound skips create+join when the email is tombstoned so a concurrent
  maintenance pass (adjustTraffics, autoRenewClients, markClientsDisabledIn-
  Settings) that did a stale RMW can't resurrect a just-deleted client with a
  fresh id.
- compactOrphans sweeps settings.clients entries whose ClientRecord no longer
  exists, applied in Add/DelInboundClient + DelInboundClientByEmail so each
  user-initiated mutation self-heals the inbound's settings.
- DelInboundClient uses Pluck instead of First for the stats lookup so a
  missing row doesn't abort the delete with a noisy ErrRecordNotFound log.

Frontend:
- HttpUtil.{get,post} accept a silent option that suppresses the auto-toast.
- ClientBulkAddModal fires creates in parallel + silent + one summary toast.
- useClients.removeMany runs deletes in parallel + silent and refreshes once;
  ClientsPage bulk delete uses it and shows one aggregate toast.
- useClients.applyInvalidate debounces 200 ms so the burst of N WebSocket
  invalidate events from the backend collapses into a single refresh.
- ClientsPage pagination is reactive (paginationState ref + tablePagination
  computed); onTableChange persists page-size and page changes.
- ClientFormModal gains a Start-After-First-Use switch + Duration days input
  alongside the existing Expiry Date picker; on edit-mode open a negative
  expiryTime is decoded back to delayed mode + days; on submit the payload
  sends -86400000 * days or the absolute timestamp.
- ClientsPage table shows the delayed-start duration (blue tag Nd, tooltip
  Start After First Use: Nd) instead of infinity.
- Telegram ID field in the form is hidden when /panel/setting/defaultSettings
  reports tgBotEnable=false; Comment then fills the row.
- Form row 3 collapses UUID (span 12) + Total GB (span 8) + Limit IP (span 4)
  when ipLimitEnable is on, else UUID + Total GB at 12/12.
- useInbounds.rollupClients counts only clients with a matching clientStats
  row, so orphans in settings.clients no longer inflate the inbound's count.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(windows): clean shutdown, working panel restart, harden kernel32 load

Three Windows-specific issues addressed:

1. Orphaned xray-windows-amd64 after VS Code debugger stop. Delve's
   "Stop" sends TerminateProcess to the Go binary, which is uncatchable
   — our signal handlers never run, so xrayService.StopXray() is skipped
   and xray is left dangling. Spawn xray as a child of a Job Object with
   JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE so the OS kills xray when our
   handle to the job is closed (which happens even on TerminateProcess).
   Also trap os.Interrupt in main so Ctrl+C in the terminal runs the
   graceful path.

2. /panel/setting/restartPanel logged "failed to send SIGHUP signal: not
   supported by windows" because Windows can't deliver arbitrary signals.
   Add a restart hook in web/global; main registers it to push SIGHUP
   into its own signal channel, and RestartPanel calls the hook before
   falling back to the (Unix-only) signal path. Same restart-loop code
   runs in both cases.

3. util/sys/sys_windows.go now uses windows.NewLazySystemDLL so the
   kernel32.dll resolve is pinned to %SystemRoot%\System32 (prevents
   DLL hijacking by a planted DLL next to the binary). Local filetime
   type replaced with windows.Filetime, and the unreliable
   syscall.GetLastError() fallback replaced with a type assertion on the
   errno captured at call time.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(sys): correct CPU/connection accounting on linux + darwin

util/sys/sys_linux.go:
- GetTCPCount/GetUDPCount were counting the column header row in
  /proc/net/{tcp,udp}[6] as a connection, inflating the reported total
  by 1 per non-empty file (so the panel status line always showed 2
  more connections than actually existed). Replace getLinesNum +
  safeGetLinesNum with a single bufio.Scanner-based countConnections
  that skips the header.
- CPUPercentRaw now opens HostProc("stat") instead of a hardcoded
  /proc/stat so HOST_PROC overrides apply, matching the connection
  counters in the same file.
- Simplify CPU field unpacking: pad nums to 8 once instead of guarding
  every assignment with a len check.

util/sys/sys_darwin.go:
- Fix swapped idle/intr indices on kern.cp_time. BSD CPUSTATES order
  is user, nice, sys, intr, idle (CP_INTR=3, CP_IDLE=4) — gopsutil's
  cpu_darwin_nocgo.go reads the same layout. The previous code used
  out[3] as idle and out[4] as intr, so busy = total - dIdle was
  actually subtracting interrupt time, making the panel report CPU
  usage close to 100% on macOS regardless of actual load.
- Collapse the per-field delta math into a single loop.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(xray): rotate crash reports into log folder, prevent overwrites

writeCrashReport had two flaws: it wrote to the bin folder (alongside the
xray binary) which conflates artifacts, and the second-precision timestamp
meant a tight restart-loop crash burst overwrote prior reports. Write to
the log folder with nanosecond precision and keep the last 10 reports.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* revert(inbounds): drop unreleased portfallback protocol

The Port-with-Fallback inbound (commit 62fd9f9d) was confusing as a
standalone protocol — fallbacks belong on a regular VLESS/Trojan TCP-TLS
inbound, the way Xray models them natively. Rip out the entire feature
cleanly (no migration needed since it was never released): protocol
constant, fallback children DB table, FallbackService, 2 API endpoints,
all UI rows, related translations and api-docs. A native fallback flow
attached to VLESS/Trojan TCP-TLS/Reality will land in a follow-up commit.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* feat(inbounds): native fallbacks on VLESS/Trojan TCP-TLS, with working child links

A VLESS or Trojan inbound on TCP with TLS or Reality can now act as a
fallback master: pick existing inbounds as children and the panel auto-
fills the SNI / ALPN / path / xver routing fields from each child's
transport, auto-builds settings.fallbacks at config-gen time, and
rewrites the child's client-share link so it advertises the master's
reachable endpoint and TLS state instead of the child's loopback listen.

Layout matches the Xray All-in-One Nginx example: master at :443 with
clients + TLS, each child on 127.0.0.1 with its own transport+clients.
Order matters (Xray walks fallbacks top-to-bottom) — reorder via the
per-row up/down arrows. Path / SNI / ALPN are exposed under a per-row
Edit toggle for the rare cases where the auto-derivation needs
overriding; otherwise just pick a child and you're done.

Backend: new InboundFallback table + FallbackService (GetByMaster /
SetByMaster / GetParentForChild / BuildFallbacksJSON); two routes
(GET / POST /panel/api/inbounds/:id/fallbacks); xray.GetXrayConfig
injects settings.fallbacks for any VLESS/Trojan TCP-TLS/Reality
inbound; GetInbounds annotates each child with FallbackParent so the
frontend can rewrite links without an extra round-trip.

Link projection covers every emission path — clients-page QR/links,
per-inbound Get URL, raw subscription, sub-JSON, sub-Clash, and the
inbounds-page link/info/QR — via a shared projectThroughFallbackMaster
on the backend and a shared projectChildThroughMaster on the frontend
that both handle the panel-tracked relationship and the legacy
unix-socket (@vless-ws) convention.

Strings translated into all 12 non-English locales.

* docs: rewrite CONTRIBUTING with full local-dev setup

The prior three-line CONTRIBUTING left newcomers guessing at every
non-trivial step: which Go / Node versions, where xray comes from, why
the panel goes blank when XUI_DEBUG=true is flipped on, how the Vue
multi-page setup is wired, what to do on Windows when go build trips
on the CGo SQLite driver.

Now covers prerequisites, MinGW-w64 install on Windows (niXman builds
or MSYS2), one-shot first-time setup, two frontend dev workflows with
the XUI_DEBUG asset-cache gotcha called out, the architecture and
conventions of the Vue side, a project-layout map, useful env vars,
and the PR checklist.

---------
2026-05-19 12:20:24 +02:00

1092 lines
71 KiB
JSON
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"username": "نام‌کاربری",
"password": "رمزعبور",
"login": "ورود",
"confirm": "تایید",
"cancel": "انصراف",
"close": "بستن",
"save": "ذخیره",
"logout": "خروج",
"create": "ایجاد",
"update": "به‌روزرسانی",
"copy": "کپی",
"copied": "کپی شد",
"download": "دانلود",
"remark": "نام",
"enable": "فعال",
"protocol": "پروتکل",
"search": "جستجو",
"filter": "فیلتر",
"loading": "...در حال بارگذاری",
"refresh": "تازه‌سازی",
"clear": "پاک کردن",
"second": "ثانیه",
"minute": "دقیقه",
"hour": "ساعت",
"day": "روز",
"check": "چک کردن",
"indefinite": "نامحدود",
"unlimited": "نامحدود",
"none": "هیچ",
"qrCode": "QRکد",
"info": "اطلاعات بیشتر",
"edit": "ویرایش",
"delete": "حذف",
"reset": "ریست",
"noData": "داده‌ای وجود ندارد.",
"copySuccess": "باموفقیت کپی‌شد",
"sure": "مطمئن",
"encryption": "رمزگذاری",
"useIPv4ForHost": "از IPv4 برای میزبان استفاده کنید",
"transmission": "راه‌اتصال",
"host": "آدرس",
"path": "مسیر",
"camouflage": "مبهم‌سازی",
"status": "وضعیت",
"enabled": "فعال",
"disabled": "غیرفعال",
"depleted": "منقضی",
"depletingSoon": "در‌حال‌انقضا",
"offline": "آفلاین",
"online": "آنلاین",
"domainName": "آدرس دامنه",
"monitor": "آی‌پی اتصال",
"certificate": "گواهی دیجیتال",
"fail": "ناموفق",
"comment": "توضیحات",
"success": "موفق",
"lastOnline": "آخرین فعالیت",
"getVersion": "دریافت نسخه",
"install": "نصب",
"clients": "کاربران",
"usage": "استفاده",
"twoFactorCode": "کد",
"remained": "باقی‌مانده",
"security": "امنیت",
"secAlertTitle": "هشدار‌امنیتی",
"secAlertSsl": "این‌اتصال‌امن نیست. لطفا‌ تازمانی‌که تی‌ال‌اس برای محافظت از‌ داده‌ها فعال نشده‌است، از وارد کردن اطلاعات حساس خودداری کنید",
"secAlertConf": "تنظیمات خاصی در برابر حملات آسیب پذیر هستند. توصیه می‌شود پروتکل‌های امنیتی را برای جلوگیری از نفوذ احتمالی تقویت کنید",
"secAlertSSL": "پنل فاقد ارتباط امن است. لطفاً یک گواهینامه تی‌ال‌اس برای محافظت از داده‌ها نصب کنید",
"secAlertPanelPort": "استفاده از پورت پیش‌فرض پنل ناامن است. لطفاً یک پورت تصادفی یا خاص تنظیم کنید",
"secAlertPanelURI": "مسیر پیش‌فرض لینک پنل ناامن است. لطفاً یک مسیر پیچیده تنظیم کنید",
"secAlertSubURI": "مسیر پیش‌فرض لینک سابسکریپشن ناامن است. لطفاً یک مسیر پیچیده تنظیم کنید",
"secAlertSubJsonURI": "مسیر پیش‌فرض لینک سابسکریپشن جیسون ناامن است. لطفاً یک مسیر پیچیده تنظیم کنید",
"emptyDnsDesc": "هیچ سرور DNS اضافه نشده است.",
"emptyFakeDnsDesc": "هیچ سرور Fake DNS اضافه نشده است.",
"emptyBalancersDesc": "هیچ بالانسر اضافه نشده است.",
"emptyReverseDesc": "هیچ پروکسی معکوس اضافه نشده است.",
"somethingWentWrong": "مشکلی پیش آمد",
"subscription": {
"title": "اطلاعات سابسکریپشن",
"subId": "شناسه اشتراک",
"status": "وضعیت",
"downloaded": "دانلود",
"uploaded": "آپلود",
"expiry": "تاریخ پایان",
"totalQuota": "حجم کلی",
"individualLinks": "لینک‌های تکی",
"active": "فعال",
"inactive": "غیرفعال",
"unlimited": "نامحدود",
"noExpiry": "بدون انقضا"
},
"menu": {
"theme": "تم",
"dark": "تیره",
"ultraDark": "فوق تیره",
"dashboard": "نمای کلی",
"inbounds": "ورودی‌ها",
"clients": "کلاینت‌ها",
"nodes": "نودها",
"settings": "تنظیمات پنل",
"xray": "پیکربندی ایکس‌ری",
"apiDocs": "مستندات API",
"logout": "خروج",
"link": "مدیریت"
},
"pages": {
"login": {
"hello": "سلام",
"title": "خوش‌آمدید",
"loginAgain": "مدت زمان استفاده به‌اتمام‌رسیده، لطفا دوباره وارد شوید",
"toasts": {
"invalidFormData": "اطلاعات به‌درستی وارد نشده‌است",
"emptyUsername": "لطفا یک نام‌کاربری وارد کنید‌",
"emptyPassword": "لطفا یک رمزعبور وارد کنید",
"wrongUsernameOrPassword": "نام کاربری، رمز عبور یا کد دو مرحله‌ای نامعتبر است.",
"successLogin": "شما با موفقیت به حساب کاربری خود وارد شدید."
}
},
"index": {
"title": "نمای کلی",
"cpu": "پردازنده",
"logicalProcessors": "پردازنده‌های منطقی",
"frequency": "فرکانس",
"swap": "سواپ",
"storage": "ذخیره‌سازی",
"memory": "حافظه رم",
"threads": "رشته‌ها",
"xrayStatus": "ایکس‌ری",
"stopXray": "توقف",
"restartXray": "شروع‌مجدد",
"xraySwitch": "‌نسخه",
"xrayUpdates": "به‌روزرسانی‌های Xray",
"xraySwitchClick": "نسخه مورد نظر را انتخاب کنید",
"xraySwitchClickDesk": "لطفا بادقت انتخاب کنید. درصورت انتخاب نسخه قدیمی‌تر، امکان ناهماهنگی با پیکربندی فعلی وجود دارد",
"updatePanel": "به‌روزرسانی پنل",
"panelUpdateDesc": "این عملیات 3X-UI را به آخرین نسخه به‌روزرسانی می‌کند و سرویس پنل را مجدداً راه‌اندازی می‌کند.",
"currentPanelVersion": "نسخه فعلی پنل",
"latestPanelVersion": "آخرین نسخه پنل",
"panelUpToDate": "پنل به‌روز است",
"upToDate": "به‌روز",
"xrayStatusUnknown": "ناشناخته",
"xrayStatusRunning": "در حال اجرا",
"xrayStatusStop": "متوقف",
"xrayStatusError": "خطا",
"xrayErrorPopoverTitle": "خطا در هنگام اجرای Xray رخ داد",
"operationHours": "مدت‌کارکرد",
"systemHistoryTitle": "تاریخچه سیستم",
"charts": "نمودارها",
"xrayMetricsTitle": "متریک‌های Xray",
"xrayMetricsDisabled": "نقطه پایانی متریک‌های Xray پیکربندی نشده",
"xrayMetricsHint": "یک بلاک metrics در سطح بالای پیکربندی xray با tag برابر metrics_out و listen برابر 127.0.0.1:11111 اضافه کنید، سپس xray را راه‌اندازی مجدد کنید.",
"xrayObservatoryEmpty": "هنوز داده‌ای از Observatory دریافت نشده",
"xrayObservatoryHint": "یک بلاک observatory در پیکربندی xray اضافه کنید و outbound tagهایی که می‌خواهید بررسی شوند را لیست کنید، سپس xray را راه‌اندازی مجدد کنید.",
"xrayObservatoryTagPlaceholder": "انتخاب outbound",
"xrayObservatoryAlive": "فعال",
"xrayObservatoryDead": "غیرفعال",
"xrayObservatoryLastSeen": "آخرین مشاهده",
"xrayObservatoryLastTry": "آخرین تلاش",
"trendLast2Min": "۲ دقیقه اخیر",
"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": "به‌روزرسانی پنل آغاز شد",
"geofileUpdateDialog": "آیا واقعاً می‌خواهید فایل جغرافیایی را به‌روز کنید؟",
"geofileUpdateDialogDesc": "این عمل فایل #filename# را به‌روز می‌کند.",
"geofilesUpdateDialogDesc": "با این کار همه فایل‌ها به‌روزرسانی می‌شوند.",
"geofilesUpdateAll": "همه را به‌روزرسانی کنید",
"geofileUpdatePopover": "فایل جغرافیایی با موفقیت به‌روز شد",
"customGeoTitle": "GeoSite / GeoIP سفارشی",
"customGeoAdd": "افزودن",
"customGeoType": "نوع",
"customGeoAlias": "نام مستعار",
"customGeoUrl": "URL",
"customGeoEnabled": "فعال",
"customGeoLastUpdated": "آخرین به‌روزرسانی",
"customGeoExtColumn": "مسیریابی (ext:…)",
"customGeoToastUpdateAll": "همه منابع سفارشی به‌روزرسانی شدند",
"customGeoActions": "اقدامات",
"customGeoEdit": "ویرایش",
"customGeoDelete": "حذف",
"customGeoDownload": "به‌روزرسانی اکنون",
"customGeoModalAdd": "افزودن geo سفارشی",
"customGeoModalEdit": "ویرایش geo سفارشی",
"customGeoModalSave": "ذخیره",
"customGeoDeleteConfirm": "این منبع geo سفارشی حذف شود؟",
"customGeoRoutingHint": "در قوانین مسیریابی مقدار را به صورت ext:file.dat:tag استفاده کنید (tag را جایگزین کنید).",
"customGeoInvalidId": "شناسه منبع نامعتبر است",
"customGeoAliasesError": "بارگذاری نام مستعارهای geo سفارشی ناموفق بود",
"customGeoValidationAlias": "نام مستعار فقط حروف کوچک، اعداد، - و _",
"customGeoValidationUrl": "URL باید با http:// یا https:// شروع شود",
"customGeoAliasPlaceholder": "a-z 0-9 _ -",
"customGeoAliasLabelSuffix": " (سفارشی)",
"customGeoToastList": "فهرست geo سفارشی",
"customGeoToastAdd": "افزودن geo سفارشی",
"customGeoToastUpdate": "به‌روزرسانی geo سفارشی",
"customGeoToastDelete": "geofile سفارشی «{{ .fileName }}» حذف شد",
"customGeoToastDownload": "geofile «{{ .fileName }}» به‌روزرسانی شد",
"customGeoErrInvalidType": "نوع باید geosite یا geoip باشد",
"customGeoErrAliasRequired": "نام مستعار لازم است",
"customGeoErrAliasPattern": "نام مستعار دارای نویسه نامجاز است",
"customGeoErrAliasReserved": "این نام مستعار رزرو است",
"customGeoErrUrlRequired": "URL لازم است",
"customGeoErrInvalidUrl": "URL نامعتبر است",
"customGeoErrUrlScheme": "URL باید http یا https باشد",
"customGeoErrUrlHost": "میزبان URL نامعتبر است",
"customGeoErrDuplicateAlias": "این نام مستعار برای این نوع قبلاً استفاده شده است",
"customGeoErrNotFound": "منبع geo سفارشی یافت نشد",
"customGeoErrDownload": "بارگیری ناموفق بود",
"customGeoErrUpdateAllIncomplete": "به‌روزرسانی یک یا چند منبع geo سفارشی ناموفق بود",
"customGeoEmpty": "هنوز منبع geo سفارشی‌ای ثبت نشده — برای ایجاد روی «افزودن» کلیک کنید",
"dontRefresh": "در حال نصب، لطفا صفحه را رفرش نکنید",
"logs": "گزارش‌ها",
"config": "پیکربندی",
"backup": "پشتیبان‌گیری",
"backupTitle": "پشتیبان‌گیری و بازیابی",
"exportDatabase": "پشتیبان‌گیری",
"exportDatabaseDesc": "برای دانلود یک فایل .db حاوی پشتیبان از پایگاه داده فعلی خود به دستگاهتان کلیک کنید.",
"importDatabase": "بازیابی",
"importDatabaseDesc": "برای انتخاب و آپلود یک فایل .db از دستگاهتان و بازیابی پایگاه داده از یک پشتیبان کلیک کنید.",
"importDatabaseSuccess": "پایگاه داده با موفقیت وارد شد",
"importDatabaseError": "خطا در وارد کردن پایگاه داده",
"readDatabaseError": "خطا در خواندن پایگاه داده",
"getDatabaseError": "خطا در دریافت پایگاه داده",
"getConfigError": "خطا در دریافت فایل پیکربندی"
},
"inbounds": {
"title": "کاربران",
"totalDownUp": "دریافت/ارسال کل",
"totalUsage": "‌‌‌مصرف کل",
"inboundCount": "کل ورودی‌ها",
"operate": "عملیات",
"enable": "فعال",
"remark": "نام",
"node": "نود",
"deployTo": "استقرار روی",
"localPanel": "پنل لوکال",
"fallbacks": {
"title": "فال‌بک‌ها",
"help": "وقتی اتصالی روی این اینباند با هیچ کلاینتی تطبیق پیدا نمی‌کند، به یک اینباند دیگر ارجاع داده می‌شود. یک فرزند انتخاب کنید، فیلدهای مسیریابی (SNI / ALPN / Path / xver) خودکار از روی transport آن پر می‌شود — برای بیشتر تنظیمات نیازی به ویرایش نیست. هر فرزند باید روی 127.0.0.1 با security=none گوش بدهد.",
"empty": "هنوز فال‌بکی اضافه نشده",
"add": "افزودن فال‌بک",
"pickInbound": "یک اینباند انتخاب کنید",
"matchAny": "همه",
"rederive": "پر کردن مجدد از فرزند",
"rederived": "از فرزند پر شد",
"editAdvanced": "ویرایش فیلدهای مسیریابی",
"hideAdvanced": "بستن پیشرفته",
"quickAddAll": "افزودن سریع همه‌ی موارد واجد شرایط",
"quickAdded": "{n} فال‌بک افزوده شد",
"quickAddedNone": "اینباند جدیدی برای افزودن وجود ندارد",
"routesWhen": "هدایت می‌شود وقتی",
"defaultCatchAll": "پیش‌فرض — همه‌ی موارد دیگر را می‌گیرد"
},
"protocol": "پروتکل",
"port": "پورت",
"portMap": "پورت‌های نظیر",
"traffic": "ترافیک",
"details": "توضیحات",
"transportConfig": "نحوه اتصال",
"expireDate": "مدت زمان",
"createdAt": "ایجاد",
"updatedAt": "به‌روزرسانی",
"resetTraffic": "ریست ترافیک",
"addInbound": "افزودن ورودی",
"generalActions": "عملیات کلی",
"modifyInbound": "ویرایش ورودی",
"deleteInbound": "حذف ورودی",
"deleteInboundContent": "آیا مطمئن به حذف ورودی هستید؟",
"deleteClient": "حذف کاربر",
"deleteClientContent": "آیا مطمئن به حذف کاربر هستید؟",
"resetTrafficContent": "آیا مطمئن به ریست ترافیک هستید؟",
"copyLink": "کپی لینک",
"address": "آدرس",
"network": "شبکه",
"destinationPort": "پورت مقصد",
"targetAddress": "آدرس مقصد",
"monitorDesc": "به‌طور پیش‌فرض خالی‌بگذارید",
"meansNoLimit": "0 = واحد: گیگابایت) نامحدود)",
"totalFlow": "ترافیک کل",
"leaveBlankToNeverExpire": "برای منقضی‌نشدن خالی‌بگذارید",
"noRecommendKeepDefault": "توصیه‌می‌شود به‌طور پیش‌فرض حفظ‌شود",
"certificatePath": "مسیر فایل",
"certificateContent": "محتوای فایل",
"publicKey": "کلید عمومی",
"privatekey": "کلید خصوصی",
"clickOnQRcode": "برای کپی بر روی کدتصویری کلیک کنید",
"client": "کاربر",
"export": "استخراج لینک‌ها",
"clone": "شبیه‌سازی",
"cloneInbound": "شبیه‌سازی ورودی",
"cloneInboundContent": "همه موارد این ورودی بجز پورت، آی‌پی و کاربر‌ها شبیه‌سازی خواهند شد",
"cloneInboundOk": "ساختن شبیه ساز",
"resetAllTraffic": "ریست ترافیک کل ورودی‌ها",
"resetAllTrafficTitle": "ریست ترافیک کل ورودی‌ها",
"resetAllTrafficContent": "آیا مطمئن به ریست ترافیک تمام ورودی‌ها هستید؟",
"resetInboundClientTraffics": "ریست ترافیک کاربران",
"resetInboundClientTrafficTitle": "ریست ترافیک کاربران",
"resetInboundClientTrafficContent": "آیا مطمئن به ریست ترافیک تمام کاربران این‌ ورودی هستید؟",
"resetAllClientTraffics": "ریست ترافیک کل کاربران",
"resetAllClientTrafficTitle": "ریست ترافیک کل کاربران",
"resetAllClientTrafficContent": "آیا مطمئن به ریست ترافیک تمام کاربران هستید؟",
"delDepletedClients": "حذف کاربران منقضی",
"delDepletedClientsTitle": "حذف کاربران منقضی",
"delDepletedClientsContent": "آیا مطمئن به حذف تمام کاربران منقضی‌شده ‌هستید؟",
"email": "ایمیل",
"emailDesc": "باید یک ایمیل یکتا باشد",
"IPLimit": "محدودیت آی‌پی",
"IPLimitDesc": "(اگر تعداد از مقدار تنظیم شده بیشتر شود، ورودی را غیرفعال می کند. (0 = غیرفعال",
"IPLimitlog": "گزارش‌ها",
"IPLimitlogDesc": "گزارش تاریخچه آی‌پی. برای فعال کردن ورودی پس از غیرفعال شدن، گزارش را پاک کنید",
"IPLimitlogclear": "پاک کردن گزارش‌ها",
"setDefaultCert": "استفاده از گواهی پنل",
"streamTab": "استریم",
"securityTab": "امنیت",
"sniffingTab": "اسنیفینگ",
"sniffingMetadataOnly": "فقط متادیتا",
"sniffingRouteOnly": "فقط مسیریابی",
"sniffingIpsExcluded": "IPهای مستثنا",
"sniffingDomainsExcluded": "دامنه‌های مستثنا",
"decryption": "رمزگشایی",
"encryption": "رمزنگاری",
"vlessAuthX25519": "احراز X25519",
"vlessAuthMlkem768": "احراز ML-KEM-768",
"vlessAuthCustom": "سفارشی",
"vlessAuthSelected": "انتخاب‌شده: {auth}",
"advanced": {
"title": "بخش‌های JSON اینباند",
"subtitle": "JSON کامل اینباند و ویرایشگرهای جداگانه برای settings، sniffing و streamSettings.",
"all": "همه",
"allHelp": "شیء کامل اینباند با همه فیلدها در یک ویرایشگر.",
"settings": "تنظیمات",
"settingsHelp": "ساختار بلوک settings در Xray:",
"sniffing": "اسنیفینگ",
"sniffingHelp": "ساختار بلوک sniffing در Xray:",
"stream": "استریم",
"streamHelp": "ساختار بلوک stream در Xray:",
"jsonErrorPrefix": "JSON پیشرفته"
},
"telegramDesc": "لطفا شناسه گفتگوی تلگرام را وارد کنید. (از دستور '/id' در ربات استفاده کنید) یا ({'@'}userinfobot)",
"subscriptionDesc": "شما می‌توانید لینک سابسکربپشن خودرا در 'جزئیات' پیدا کنید، همچنین می‌توانید از همین نام برای چندین کاربر استفاده‌کنید",
"info": "اطلاعات",
"same": "همسان",
"inboundData": "داده‌های ورودی",
"exportInbound": "استخراج ورودی",
"import": "افزودن",
"importInbound": "افزودن یک ورودی",
"periodicTrafficResetTitle": "بازنشانی ترافیک",
"periodicTrafficResetDesc": "بازنشانی خودکار شمارنده ترافیک در فواصل زمانی مشخص",
"lastReset": "آخرین بازنشانی",
"periodicTrafficReset": {
"never": "هرگز",
"daily": "روزانه",
"weekly": "هفتگی",
"monthly": "ماهانه",
"hourly": "هر ساعت"
},
"toasts": {
"obtain": "فراهم‌سازی",
"updateSuccess": "بروزرسانی با موفقیت انجام شد",
"logCleanSuccess": "لاگ پاکسازی شد",
"inboundsUpdateSuccess": "ورودی‌ها با موفقیت به‌روزرسانی شدند",
"inboundUpdateSuccess": "ورودی با موفقیت به‌روزرسانی شد",
"inboundCreateSuccess": "ورودی با موفقیت ایجاد شد",
"inboundDeleteSuccess": "ورودی با موفقیت حذف شد",
"inboundClientAddSuccess": "کلاینت(های) ورودی اضافه شدند",
"inboundClientDeleteSuccess": "کلاینت ورودی حذف شد",
"inboundClientUpdateSuccess": "کلاینت ورودی به‌روزرسانی شد",
"delDepletedClientsSuccess": "تمام کلاینت‌های مصرف شده حذف شدند",
"resetAllClientTrafficSuccess": "تمام ترافیک کلاینت بازنشانی شد",
"resetAllTrafficSuccess": "تمام ترافیک‌ها بازنشانی شدند",
"resetInboundClientTrafficSuccess": "ترافیک بازنشانی شد",
"resetInboundTrafficSuccess": "ترافیک ورودی بازنشانی شد",
"trafficGetError": "خطا در دریافت ترافیک‌ها",
"getNewX25519CertError": "خطا در دریافت گواهی X25519.",
"getNewmldsa65Error": "خطا در دریافت گواهی mldsa65.",
"getNewVlessEncError": "خطا در دریافت گواهی VlessEnc."
},
"stream": {
"general": {
"request": "درخواست",
"response": "پاسخ",
"name": "نام",
"value": "مقدار"
},
"tcp": {
"version": "نسخه",
"method": "متد",
"path": "مسیر",
"status": "وضعیت",
"statusDescription": "توضیحات وضعیت",
"requestHeader": "سربرگ درخواست",
"responseHeader": "سربرگ پاسخ"
}
}
},
"clients": {
"add": "افزودن کلاینت",
"edit": "ویرایش کلاینت",
"submitAdd": "افزودن کلاینت",
"submitEdit": "ذخیره تغییرات",
"clientCount": "تعداد کلاینت‌ها",
"bulk": "افزودن گروهی",
"copyFromInbound": "کپی کلاینت‌ها از اینباند",
"copyToInbound": "کپی کلاینت‌ها به",
"copySelected": "کپی انتخاب‌شده‌ها",
"copySource": "منبع",
"copyEmailPreview": "پیش‌نمایش ایمیل خروجی",
"copySelectSourceFirst": "ابتدا یک اینباند مبدأ انتخاب کنید.",
"copyResult": "نتیجه کپی",
"copyResultSuccess": "با موفقیت کپی شد",
"copyResultNone": "چیزی برای کپی نیست: کلاینتی انتخاب نشده یا منبع خالی است",
"copyResultErrors": "خطاهای کپی",
"copyFlowLabel": "Flow برای کلاینت‌های جدید (VLESS)",
"copyFlowHint": "روی همه کلاینت‌های کپی‌شده اعمال می‌شود. خالی بگذارید تا رد شود.",
"selectAll": "انتخاب همه",
"clearAll": "پاک کردن همه",
"method": "روش",
"first": "اول",
"last": "آخر",
"ipLog": "گزارش IP",
"prefix": "پیشوند",
"postfix": "پسوند",
"delayedStart": "شروع پس از اولین استفاده",
"expireDays": "مدت",
"days": "روز",
"renew": "تمدید خودکار",
"renewDesc": "تمدید خودکار پس از انقضا. (۰ = غیرفعال) (واحد: روز)",
"title": "کلاینت‌ها",
"actions": "عملیات",
"totalGB": "مجموع ارسال/دریافت (گیگابایت)",
"expiryTime": "انقضا",
"addClients": "افزودن کلاینت‌ها",
"limitIp": "محدودیت IP",
"password": "رمز عبور",
"subId": "شناسه اشتراک",
"online": "آنلاین",
"email": "ایمیل",
"comment": "توضیحات",
"traffic": "ترافیک",
"offline": "آفلاین",
"addTitle": "افزودن کلاینت",
"qrCode": "کد QR",
"moreInformation": "اطلاعات بیشتر",
"delete": "حذف",
"reset": "بازنشانی ترافیک",
"editTitle": "ویرایش کلاینت",
"client": "کلاینت",
"enabled": "فعال",
"remaining": "باقی‌مانده",
"duration": "مدت",
"attachedInbounds": "اینباندهای متصل",
"selectInbound": "یک یا چند اینباند انتخاب کنید",
"noSubId": "این کلاینت subId ندارد، لینک اشتراک‌گذاری وجود ندارد.",
"noLinks": "لینکی برای اشتراک‌گذاری نیست — ابتدا این کلاینت را به یک اینباند با پروتکل سازگار متصل کنید.",
"link": "لینک",
"resetNotPossible": "ابتدا این کلاینت را به یک اینباند متصل کنید.",
"general": "عمومی",
"resetAllTraffics": "بازنشانی ترافیک همه کلاینت‌ها",
"resetAllTrafficsTitle": "بازنشانی ترافیک همه کلاینت‌ها؟",
"resetAllTrafficsContent": "شمارنده ارسال/دریافت همه کلاینت‌ها به صفر می‌رسد. سهمیه و تاریخ انقضا تغییری نمی‌کند. این عمل غیرقابل بازگشت است.",
"empty": "هنوز کلاینتی نیست — برای شروع یکی اضافه کنید.",
"deleteConfirmTitle": "حذف کلاینت {email}؟",
"deleteConfirmContent": "این کلاینت از تمام اینباندهای متصل حذف و سابقه ترافیک آن پاک می‌شود. این عمل غیرقابل بازگشت است.",
"deleteSelected": "حذف ({count})",
"bulkDeleteConfirmTitle": "حذف {count} کلاینت؟",
"bulkDeleteConfirmContent": "هر کلاینت انتخاب‌شده از تمام اینباندهای متصل حذف و سابقه ترافیک آن پاک می‌شود. این عمل غیرقابل بازگشت است.",
"delDepleted": "حذف اتمام‌یافته‌ها",
"delDepletedConfirmTitle": "حذف کلاینت‌های اتمام‌یافته؟",
"delDepletedConfirmContent": "هر کلاینتی که سهمیه ترافیک‌اش تمام شده یا تاریخ انقضایش گذشته است حذف می‌شود. این عمل غیرقابل بازگشت است.",
"auth": "Auth",
"hysteriaAuth": "Auth (هیستریا)",
"uuid": "UUID",
"flow": "Flow",
"reverseTag": "Reverse tag",
"reverseTagPlaceholder": "Reverse tag اختیاری",
"telegramId": "شناسه کاربر تلگرام",
"telegramIdPlaceholder": "شناسه عددی کاربر تلگرام (۰ = هیچ)",
"created": "ساخته‌شده",
"updated": "به‌روزشده",
"ipLimit": "محدودیت IP",
"toasts": {
"deleted": "کلاینت حذف شد",
"trafficReset": "ترافیک بازنشانی شد",
"allTrafficsReset": "ترافیک همه کلاینت‌ها بازنشانی شد",
"bulkDeleted": "{count} کلاینت حذف شد",
"bulkDeletedMixed": "{ok} حذف، {failed} ناموفق",
"bulkCreated": "{count} کلاینت ساخته شد",
"bulkCreatedMixed": "{ok} ساخته شد، {failed} ناموفق",
"delDepleted": "{count} کلاینت اتمام‌یافته حذف شد"
}
},
"nodes": {
"title": "نودها",
"addNode": "افزودن نود",
"editNode": "ویرایش نود",
"totalNodes": "کل نودها",
"onlineNodes": "آنلاین",
"offlineNodes": "آفلاین",
"avgLatency": "میانگین تاخیر",
"name": "نام",
"namePlaceholder": "مثلاً de-frankfurt-1",
"addressPlaceholder": "panel.example.com یا 1.2.3.4",
"remark": "توضیحات",
"scheme": "پروتکل",
"address": "آدرس",
"port": "پورت",
"basePath": "مسیر پایه",
"apiToken": "توکن API",
"apiTokenPlaceholder": "توکن از صفحه تنظیمات پنل ریموت",
"apiTokenHint": "پنل ریموت توکن API خودش را در بخش تنظیمات → توکن API نمایش می‌دهد.",
"regenerate": "تولید مجدد توکن",
"regenerateConfirm": "تولید مجدد، توکن فعلی را باطل می‌کند. هر پنل مرکزی‌ای که از این توکن استفاده می‌کند تا زمان به‌روزرسانی، دسترسی‌اش قطع می‌شود. ادامه می‌دهید؟",
"allowPrivateAddress": "اجازه آدرس خصوصی",
"allowPrivateAddressHint": "فقط برای نودهای روی شبکه خصوصی یا VPN فعال شود.",
"enable": "فعال",
"status": "وضعیت",
"cpu": "پردازنده",
"mem": "حافظه",
"uptime": "زمان کارکرد",
"latency": "تاخیر",
"lastHeartbeat": "آخرین ضربان",
"xrayVersion": "نسخه Xray",
"panelVersion": "نسخه پنل",
"actions": "عملیات",
"probe": "بررسی فوری",
"testConnection": "تست اتصال",
"connectionOk": "اتصال موفق ({ms} میلی‌ثانیه)",
"connectionFailed": "اتصال ناموفق",
"never": "هرگز",
"justNow": "هم‌اکنون",
"deleteConfirmTitle": "نود «{name}» حذف شود؟",
"deleteConfirmContent": "نظارت روی این نود متوقف می‌شود. خود پنل ریموت تغییری نمی‌کند.",
"statusValues": {
"online": "آنلاین",
"offline": "آفلاین",
"unknown": "نامشخص"
},
"toasts": {
"list": "بارگذاری نودها ناموفق",
"obtain": "بارگذاری نود ناموفق",
"add": "افزودن نود",
"update": "به‌روزرسانی نود",
"delete": "حذف نود",
"deleted": "نود حذف شد",
"test": "تست اتصال",
"fillRequired": "نام، آدرس، پورت و توکن API الزامی است",
"probeFailed": "بررسی ناموفق"
}
},
"settings": {
"title": "تنظیمات پنل",
"save": "ذخیره",
"infoDesc": "برای اعمال تغییرات در این بخش باید پس از ذخیره کردن، پنل را ریستارت کنید",
"restartPanel": "ریستارت پنل",
"restartPanelDesc": "آیا مطمئن به ریستارت پنل هستید؟ اگر پس‌از ریستارت نمی‌توانید به پنل دسترسی پیدا کنید، لطفاً گزارش‌های موجود در اسکریپت پنل را بررسی کنید",
"restartPanelSuccess": "پنل با موفقیت راه‌اندازی مجدد شد",
"actions": "عملیات ها",
"resetDefaultConfig": "برگشت به پیش‌فرض",
"panelSettings": "پیکربندی",
"securitySettings": "احرازهویت",
"TGBotSettings": "ربات تلگرام",
"panelListeningIP": "آدرس آی‌پی",
"panelListeningIPDesc": "آدرس آی‌پی برای وب پنل. برای گوش‌دادن به‌تمام آی‌پی‌ها خالی‌بگذارید",
"panelListeningDomain": "نام دامنه",
"panelListeningDomainDesc": "آدرس دامنه برای وب پنل. برای گوش دادن به‌تمام دامنه‌ها و آی‌پی‌ها خالی‌بگذارید",
"panelPort": "پورت",
"panelPortDesc": "شماره پورت برای وب پنل. باید پورت استفاده نشده‌باشد",
"publicKeyPath": "مسیر کلید عمومی",
"publicKeyPathDesc": "مسیر فایل کلیدعمومی برای وب پنل. با '/' شروع‌می‌شود",
"privateKeyPath": "مسیر کلید خصوصی",
"privateKeyPathDesc": "مسیر فایل کلیدخصوصی برای وب پنل. با '/' شروع‌می‌شود",
"panelUrlPath": "URI مسیر",
"panelUrlPathDesc": "برای وب پنل. با '/' شروع‌ و با '/' خاتمه‌ می‌یابد URI مسیر",
"pageSize": "اندازه صفحه بندی جدول",
"pageSizeDesc": "(اندازه صفحه برای جدول ورودی‌ها.(0 = غیرفعال",
"remarkModel": "نام‌کانفیگ و جداکننده",
"datepicker": "نوع تقویم",
"datepickerPlaceholder": "انتخاب تاریخ",
"datepickerDescription": "وظایف برنامه ریزی شده بر اساس این تقویم اجرا می‌شود",
"sampleRemark": "نمونه‌نام",
"oldUsername": "نام‌کاربری فعلی",
"currentPassword": "رمز‌عبور فعلی",
"newUsername": "نام‌کاربری جدید",
"newPassword": "رمزعبور جدید",
"telegramBotEnable": "فعال‌سازی ربات تلگرام",
"telegramBotEnableDesc": "ربات تلگرام را فعال می‌کند",
"telegramToken": "توکن تلگرام",
"telegramTokenDesc": "دریافت کنید {'@'}botfather توکن را می‌توانید از",
"telegramProxy": "SOCKS پراکسی",
"telegramProxyDesc": "را برای اتصال به تلگرام فعال می کند SOCKS5 پراکسی",
"telegramAPIServer": "سرور API تلگرام",
"telegramAPIServerDesc": "API سرور تلگرام برای اتصال را تغییر میدهد. برای استفاده از سرور پیش فرض خالی بگذارید",
"telegramChatId": "آی‌دی چت مدیر",
"telegramChatIdDesc": "دریافت ‌کنید ('/id'یا (دستور ({'@'}userinfobot) آی‌دی(های) چت تلگرام مدیر، از",
"telegramNotifyTime": "زمان نوتیفیکیشن",
"telegramNotifyTimeDesc": "زمان‌اطلاع‌رسانی ربات تلگرام برای گزارش های دوره‌ای. از فرمت زمانبندی لینوکس استفاده‌کنید‌",
"tgNotifyBackup": "پشتیبان‌گیری از دیتابیس",
"tgNotifyBackupDesc": "فایل پشتیبان‌دیتابیس را به‌همراه گزارش ارسال می‌کند",
"tgNotifyLogin": "اعلان ورود",
"tgNotifyLoginDesc": "نام‌کاربری، آدرس آی‌پی، و زمان ورود، فردی که سعی می‌کند وارد پنل شود را نمایش می‌دهد",
"sessionMaxAge": "بیشینه زمان جلسه وب",
"sessionMaxAgeDesc": "(بیشینه زمانی که می‌توانید لاگین بمانید. (واحد: دقیقه",
"expireTimeDiff": "آستانه زمان باقی مانده",
"expireTimeDiffDesc": "(فاصله زمانی هشدار تا رسیدن به زمان انقضا. (واحد: روز",
"trafficDiff": "آستانه ترافیک باقی مانده",
"trafficDiffDesc": "(فاصله زمانی هشدار تا رسیدن به اتمام ترافیک. (واحد: گیگابایت",
"tgNotifyCpu": "آستانه هشدار بار پردازنده",
"tgNotifyCpuDesc": "(اگر بار روی پردازنده ازاین آستانه فراتر رفت، برای شما پیام ارسال می‌شود. (واحد: درصد",
"timeZone": "منطقه زمانی",
"timeZoneDesc": "وظایف برنامه ریزی شده بر اساس این منطقه‌زمانی اجرا می‌شود",
"subSettings": "سابسکریپشن",
"subEnable": "فعال‌سازی سرویس سابسکریپشن",
"subEnableDesc": "سرویس سابسکریپشن‌ را فعال‌می‌کند",
"subJsonEnable": "فعال/غیرفعال‌سازی مستقل نقطه دسترسی سابسکریپشن JSON.",
"subTitle": "عنوان اشتراک",
"subTitleDesc": "عنوان نمایش داده شده در کلاینت VPN",
"subSupportUrl": "آدرس پشتیبانی",
"subSupportUrlDesc": "لینک پشتیبانی فنی که در کلاینت VPN نمایش داده می‌شود",
"subProfileUrl": "آدرس پروفایل",
"subProfileUrlDesc": "لینک وب‌سایت شما که در کلاینت VPN نمایش داده می‌شود",
"subAnnounce": "اعلان",
"subAnnounceDesc": "متن اعلانی که در کلاینت VPN نمایش داده می‌شود",
"subEnableRouting": "فعال‌سازی مسیریابی",
"subEnableRoutingDesc": "تنظیمات سراسری برای فعال‌سازی مسیریابی در کلاینت VPN. (فقط برای Happ)",
"subRoutingRules": "قوانین مسیریابی",
"subRoutingRulesDesc": "قوانین مسیریابی سراسری برای کلاینت VPN. (فقط برای Happ)",
"subListen": "آدرس آی‌پی",
"subListenDesc": "آدرس آی‌پی برای سرویس سابسکریپشن. برای گوش دادن به‌تمام آی‌پی‌ها خالی‌بگذارید",
"subPort": "پورت",
"subPortDesc": "شماره پورت برای سرویس سابسکریپشن. باید پورت استفاده نشده‌باشد",
"subCertPath": "مسیر کلید عمومی",
"subCertPathDesc": "مسیر فایل کلیدعمومی برای سرویس سابیکریپشن. با '/' شروع‌می‌شود",
"subKeyPath": "مسیر کلید خصوصی",
"subKeyPathDesc": "مسیر فایل کلیدخصوصی برای سرویس سابسکریپشن. با '/' شروع‌می‌شود",
"subPath": "URI مسیر",
"subPathDesc": "برای سرویس سابسکریپشن. با '/' شروع‌ و با '/' خاتمه‌ می‌یابد URI مسیر",
"subDomain": "نام دامنه",
"subDomainDesc": "آدرس دامنه برای سرویس سابسکریپشن. برای گوش دادن به تمام دامنه‌ها و آی‌پی‌ها خالی‌بگذارید‌",
"subUpdates": "فاصله بروزرسانی‌ سابسکریپشن",
"subUpdatesDesc": "(فاصله مابین بروزرسانی در برنامه‌های کاربری. (واحد: ساعت",
"subEncrypt": "کدگذاری",
"subEncryptDesc": "کدگذاری خواهدشد Base64 محتوای برگشتی سرویس سابسکریپشن برپایه",
"subShowInfo": "نمایش اطلاعات مصرف",
"subShowInfoDesc": "ترافیک و زمان باقی‌مانده را در برنامه‌های کاربری نمایش می‌دهد",
"subEmailInRemark": "گنجاندن ایمیل در نام",
"subEmailInRemarkDesc": "ایمیل کاربر در نام پروفایل اشتراک گنجانده می‌شود.",
"subURI": "پروکسی معکوس URI مسیر",
"subURIDesc": "سابسکریپشن را برای استفاده در پشت پراکسی‌ها تغییر می‌دهد URI مسیر",
"externalTrafficInformEnable": "اطلاع رسانی خارجی مصرف ترافیک",
"externalTrafficInformEnableDesc": "مصرف ترافیک به سرویس خارجی ارسال می شود",
"externalTrafficInformURI": "لینک اطلاع رسانی خارجی مصرف ترافیک",
"externalTrafficInformURIDesc": "ترافیک های مصرفی به این لینک هم ارسال می شود",
"restartXrayOnClientDisable": "ری‌استارت Xray بعد از غیرفعال‌سازی خودکار",
"restartXrayOnClientDisableDesc": "وقتی کاربر به‌صورت خودکار به‌دلیل اتمام زمان یا ترافیک غیرفعال می‌شود، Xray ری‌استارت شود.",
"fragment": "فرگمنت",
"fragmentDesc": "فعال کردن فرگمنت برای بسته‌ی نخست تی‌ال‌اس",
"fragmentSett": "تنظیمات فرگمنت",
"noisesDesc": "فعال کردن Noises.",
"noisesSett": "تنظیمات Noises",
"mux": "ماکس",
"muxDesc": "چندین جریان داده مستقل را در یک جریان داده ثابت منتقل می کند",
"muxSett": "تنظیمات ماکس",
"direct": "اتصال مستقیم",
"directDesc": "به طور مستقیم با دامنه ها یا محدوده آی‌پی یک کشور خاص ارتباط برقرار می کند",
"notifications": "اعلان‌ها",
"certs": "گواهی‌ها",
"externalTraffic": "ترافیک خارجی",
"dateAndTime": "تاریخ و زمان",
"proxyAndServer": "پراکسی و سرور",
"intervals": "فواصل",
"information": "اطلاعات",
"language": "زبان",
"telegramBotLanguage": "زبان ربات تلگرام",
"security": {
"admin": "اعتبارنامه‌های ادمین",
"twoFactor": "احراز هویت دو مرحله‌ای",
"twoFactorEnable": "فعال‌سازی 2FA",
"twoFactorEnableDesc": "یک لایه اضافی امنیتی برای احراز هویت فراهم می‌کند.",
"twoFactorModalSetTitle": "فعال‌سازی احراز هویت دو مرحله‌ای",
"twoFactorModalDeleteTitle": "غیرفعال‌سازی احراز هویت دو مرحله‌ای",
"twoFactorModalSteps": "برای راه‌اندازی احراز هویت دو مرحله‌ای، مراحل زیر را انجام دهید:",
"twoFactorModalFirstStep": "1. این کد QR را در برنامه احراز هویت اسکن کنید یا توکن کنار کد QR را کپی کرده و در برنامه بچسبانید",
"twoFactorModalSecondStep": "2. کد را از برنامه وارد کنید",
"twoFactorModalRemoveStep": "برای حذف احراز هویت دو مرحله‌ای، کد را از برنامه وارد کنید.",
"twoFactorModalChangeCredentialsTitle": "تغییر اعتبارنامه‌ها",
"twoFactorModalChangeCredentialsStep": "برای تغییر اعتبارنامه‌های مدیر، کد را از برنامه وارد کنید.",
"twoFactorModalSetSuccess": "احراز هویت دو مرحله‌ای با موفقیت برقرار شد",
"twoFactorModalDeleteSuccess": "احراز هویت دو مرحله‌ای با موفقیت حذف شد",
"twoFactorModalError": "کد نادرست",
"show": "نمایش",
"hide": "پنهان",
"apiTokenNew": "توکن جدید",
"apiTokenName": "نام",
"apiTokenNamePlaceholder": "مثلاً central-panel-a",
"apiTokenNameRequired": "نام الزامی است",
"apiTokenEmpty": "هنوز توکنی وجود ندارد — برای احراز هویت ربات‌ها یا پنل‌های راه دور یکی بسازید.",
"apiTokenDeleteWarning": "هر کلاینتی که از این توکن استفاده می‌کند بلافاصله احراز هویتش قطع می‌شود."
},
"toasts": {
"modifySettings": "پارامترها تغییر کرده‌اند.",
"getSettings": "خطا در دریافت پارامترها",
"modifyUserError": "خطا در تغییر اعتبارنامه‌های مدیر سیستم.",
"modifyUser": "شما با موفقیت اعتبارنامه‌های مدیر سیستم را تغییر دادید.",
"originalUserPassIncorrect": "نام‌کاربری یا رمزعبور فعلی اشتباه‌است",
"userPassMustBeNotEmpty": "نام‌کاربری یا رمزعبور جدید خالی‌است",
"getOutboundTrafficError": "خطا در دریافت ترافیک خروجی",
"resetOutboundTrafficError": "خطا در بازنشانی ترافیک خروجی"
}
},
"xray": {
"title": "پیکربندی ایکس‌ری",
"save": "ذخیره",
"restart": "ریستارت ایکس‌ری",
"restartSuccess": "Xray با موفقیت راه‌اندازی مجدد شد",
"stopSuccess": "Xray با موفقیت متوقف شد",
"restartError": "خطا در راه‌اندازی مجدد Xray.",
"stopError": "خطا در توقف Xray.",
"basicTemplate": "پایه",
"advancedTemplate": "پیشرفته",
"generalConfigs": "استراتژی‌ کلی",
"generalConfigsDesc": "این گزینه‌ها استراتژی کلی ترافیک را تعیین می‌کنند",
"logConfigs": "گزارش",
"logConfigsDesc": "گزارش‌ها ممکن است بر کارایی سرور شما تأثیر بگذارد. توصیه می شود فقط در صورت نیاز آن را عاقلانه فعال کنید",
"blockConfigsDesc": "این گزینه‌ها ترافیک را بر اساس پروتکل‌های درخواستی خاص، و وب سایت‌ها مسدود می‌کند",
"basicRouting": "مسیریابی پایه",
"blockConnectionsConfigsDesc": "این گزینه‌ها ترافیک را بر اساس کشور درخواست‌شده خاص مسدود می‌کنند.",
"directConnectionsConfigsDesc": "یک اتصال مستقیم تضمین می‌کند که ترافیک خاص از طریق سرور دیگری مسیریابی نشود.",
"blockips": "مسدود کردن آی‌پی‌ها",
"blockdomains": "مسدود کردن دامنه‌ها",
"directips": "آی‌پی‌های مستقیم",
"directdomains": "دامنه‌های مستقیم",
"ipv4Routing": "IPv4 مسیریابی",
"ipv4RoutingDesc": "این گزینه‌ها ترافیک را از طریق آی‌پی نسخه4 سرور، به مقصد هدایت می‌کند",
"warpRouting": "WARP مسیریابی",
"warpRoutingDesc": "این گزینه‌ها ترافیک‌ را از طریق وارپ کلادفلر به مقصد هدایت می‌کند",
"nordRouting": "مسیریابی NordVPN",
"nordRoutingDesc": "این گزینه‌ها ترافیک را بر اساس مقصد خاص از طریق NordVPN مسیریابی می‌کنند.",
"Template": "‌پیکربندی پیشرفته الگو ایکس‌ری",
"TemplateDesc": "فایل پیکربندی نهایی ایکس‌ری بر اساس این الگو ایجاد می‌شود",
"FreedomStrategy": "Freedom استراتژی پروتکل",
"FreedomStrategyDesc": "تعیین می‌کند Freedom استراتژی خروجی شبکه را برای پروتکل",
"RoutingStrategy": "استراتژی کلی مسیریابی",
"RoutingStrategyDesc": "استراتژی کلی مسیریابی برای حل تمام درخواست‌ها را تعیین می‌کند",
"outboundTestUrl": "آدرس تست خروجی",
"outboundTestUrlDesc": "آدرسی که برای تست اتصال خروجی استفاده می‌شود.",
"Torrent": "مسدودسازی پروتکل بیت‌تورنت",
"Inbounds": "ورودی‌ها",
"InboundsDesc": "پذیرش کلاینت خاص",
"Outbounds": "خروجی‌ها",
"Balancers": "بالانسرها",
"OutboundsDesc": "مسیر ترافیک خروجی را تنظیم کنید",
"Routings": "قوانین مسیریابی",
"RoutingsDesc": "اولویت هر قانون مهم است",
"completeTemplate": "کامل",
"logLevel": "سطح گزارش",
"logLevelDesc": "سطح گزارش برای گزارش های خطا، نشان دهنده اطلاعاتی است که باید ثبت شوند.",
"accessLog": "مسیر گزارش",
"accessLogDesc": "مسیر فایل برای گزارش دسترسی. مقدار ویژه «هیچ» گزارش‌های دسترسی را غیرفعال میکند.",
"errorLog": "گزارش خطا",
"errorLogDesc": "مسیر فایل برای ورود به سیستم خطا. مقدار ویژه «هیچ» گزارش های خطا را غیرفعال میکند",
"dnsLog": "گزارش DNS",
"dnsLogDesc": "آیا ثبت‌های درخواست DNS را فعال کنید",
"maskAddress": "پنهان کردن آدرس",
"maskAddressDesc": "پوشش آدرس IP، هنگامی که فعال می‌شود، به طور خودکار آدرس IP که در لاگ ظاهر می‌شود را جایگزین می‌کند.",
"statistics": "آمار",
"statsInboundUplink": "آمار آپلود ورودی",
"statsInboundUplinkDesc": "جمع‌آوری آمار برای ترافیک بالارو (آپلود) تمام پروکسی‌های ورودی را فعال می‌کند.",
"statsInboundDownlink": "آمار دانلود ورودی",
"statsInboundDownlinkDesc": "جمع‌آوری آمار برای ترافیک پایین‌رو (دانلود) تمام پروکسی‌های ورودی را فعال می‌کند.",
"statsOutboundUplink": "آمار آپلود خروجی",
"statsOutboundUplinkDesc": "جمع‌آوری آمار برای ترافیک بالارو (آپلود) تمام پروکسی‌های خروجی را فعال می‌کند.",
"statsOutboundDownlink": "آمار دانلود خروجی",
"statsOutboundDownlinkDesc": "جمع‌آوری آمار برای ترافیک پایین‌رو (دانلود) تمام پروکسی‌های خروجی را فعال می‌کند.",
"rules": {
"first": "اولین",
"last": "آخرین",
"up": "بالا",
"down": "پایین",
"source": "مبدا",
"dest": "مقصد",
"inbound": "ورودی",
"outbound": "خروجی",
"balancer": "بالانسر",
"info": "اطلاعات",
"add": "افزودن قانون",
"edit": "ویرایش قانون",
"useComma": "موارد جدا شده با کاما"
},
"outbound": {
"addOutbound": "افزودن خروجی",
"addReverse": "افزودن معکوس",
"editOutbound": "ویرایش خروجی",
"editReverse": "ویرایش معکوس",
"reverseTag": "تگ معکوس",
"reverseTagDesc": "تگ خروجی پروکسی معکوس ساده VLESS. برای غیرفعال کردن خالی بگذارید. در صورت تنظیم، اتصالات این کلاینت می‌توانند به عنوان تونل پروکسی معکوس استفاده شوند.",
"reverseTagPlaceholder": "تگ خروجی (خالی = غیرفعال)",
"tag": "برچسب",
"tagDesc": "برچسب یگانه",
"address": "آدرس",
"reverse": "معکوس",
"domain": "دامنه",
"type": "نوع",
"bridge": "پل",
"portal": "پورتال",
"link": "لینک",
"intercon": "اتصال میانی",
"settings": "تنظیمات",
"accountInfo": "اطلاعات حساب",
"outboundStatus": "وضعیت خروجی",
"sendThrough": "ارسال با",
"test": "تست",
"testResult": "نتیجه تست",
"testing": "در حال تست اتصال...",
"testSuccess": "تست موفقیت‌آمیز",
"testFailed": "تست ناموفق",
"testError": "خطا در تست خروجی",
"nordvpn": "NordVPN",
"accessToken": "توکن دسترسی",
"country": "کشور",
"server": "سرور",
"city": "شهر",
"allCities": "همه شهرها",
"privateKey": "کلید خصوصی",
"load": "فشار سرور"
},
"balancer": {
"addBalancer": "افزودن بالانسر",
"editBalancer": "ویرایش بالانسر",
"balancerStrategy": "استراتژی",
"balancerSelectors": "انتخاب‌گرها",
"tag": "برچسب",
"tagDesc": "برچسب یگانه",
"balancerDesc": "امکان استفاده همزمان balancerTag و outboundTag باهم وجود ندارد. درصورت استفاده همزمان فقط outboundTag عمل خواهد کرد."
},
"wireguard": {
"secretKey": "کلید شخصی",
"publicKey": "کلید عمومی",
"allowedIPs": "آی‌پی‌های مجاز",
"endpoint": "نقطه پایانی",
"psk": "کلید مشترک",
"domainStrategy": "استراتژی حل دامنه"
},
"tun": {
"nameDesc": "نام رابط TUN. مقدار پیش‌فرض 'xray0' است",
"mtuDesc": "واحد انتقال حداکثر. بیشترین اندازه بسته‌های داده. مقدار پیش‌فرض 1500 است",
"userLevel": "سطح کاربر",
"userLevelDesc": "تمام اتصالات انجام‌شده از طریق این ورودی از این سطح کاربری استفاده خواهند کرد. مقدار پیش‌فرض 0 است"
},
"dns": {
"enable": "فعال کردن حل دامنه",
"enableDesc": "سرور حل دامنه داخلی را فعال کنید",
"tag": "برچسب",
"tagDesc": "این برچسب در قوانین مسیریابی به عنوان یک برچسب ورودی قابل استفاده خواهد بود",
"clientIp": "آی‌پی کلاینت",
"clientIpDesc": "برای اطلاع‌رسانی به سرور درباره مکان IP مشخص‌شده در طول درخواست‌های DNS استفاده می‌شود",
"disableCache": "غیرفعال‌سازی کش",
"disableCacheDesc": "کش DNS را غیرفعال می‌کند",
"disableFallback": "غیرفعال‌سازی Fallback",
"disableFallbackDesc": "درخواست‌های DNS Fallback را غیرفعال می‌کند",
"disableFallbackIfMatch": "غیرفعال‌سازی Fallback در صورت تطابق",
"disableFallbackIfMatchDesc": "درخواست‌های DNS Fallback را زمانی که لیست دامنه‌های مطابقت‌یافته سرور DNS فعال است، غیرفعال می‌کند",
"enableParallelQuery": "فعال‌سازی پرس‌وجوی موازی",
"enableParallelQueryDesc": "فعال‌سازی پرس‌وجوهای DNS موازی به چندین سرور برای وضوح سریع‌تر",
"strategy": "استراتژی پرس‌وجو",
"strategyDesc": "استراتژی کلی برای حل نام دامنه",
"add": "افزودن سرور",
"edit": "ویرایش سرور",
"domains": "دامنه‌ها",
"expectIPs": "آی‌پی‌های مورد انتظار",
"unexpectIPs": "آی‌پی‌های غیرمنتظره",
"useSystemHosts": "استفاده از Hosts سیستم",
"useSystemHostsDesc": "استفاده از فایل hosts یک سیستم نصب‌شده",
"serveStale": "ارائه نتایج منقضی",
"serveStaleDesc": "بازگرداندن نتایج منقضی کش هنگام بروزرسانی در پس‌زمینه",
"serveExpiredTTL": "TTL نتایج منقضی",
"serveExpiredTTLDesc": "مدت اعتبار نتایج منقضی به ثانیه؛ ۰ یعنی هرگز منقضی نمی‌شود",
"timeoutMs": "زمان انتظار (میلی‌ثانیه)",
"skipFallback": "رد کردن Fallback",
"finalQuery": "پرس‌وجوی نهایی",
"hosts": "Hosts",
"hostsAdd": "افزودن Host",
"hostsEmpty": "هیچ Host تعریف نشده",
"hostsDomain": "دامنه (مثلاً domain:example.com)",
"hostsValues": "آی‌پی یا دامنه — تایپ کنید و Enter بزنید",
"usePreset": "استفاده از پیش‌تنظیم",
"dnsPresetTitle": "پیش‌تنظیم‌های DNS",
"dnsPresetFamily": "خانوادگی",
"clearAll": "حذف همه",
"clearAllTitle": "حذف همه سرورهای DNS؟",
"clearAllConfirm": "این کار همه سرورهای DNS را از لیست حذف می‌کند و قابل بازگشت نیست."
},
"fakedns": {
"add": "افزودن دی‌ان‌اس جعلی",
"edit": "ویرایش دی‌ان‌اس جعلی",
"ipPool": "زیرشبکه استخر آی‌پی",
"poolSize": "اندازه استخر"
}
}
},
"tgbot": {
"keyboardClosed": "❌ صفحه کلید بسته شد!",
"noResult": "❗ نتیجه ای یافت نشد!",
"noQuery": "❌ درخواست یافت نشد! لطفا دوباره تلاش کنید!",
"wentWrong": "❌ مشکلی پیش آمد!",
"noIpRecord": "❗ رکورد آی پی وجود ندارد!",
"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": "🆔 شناسه شما: <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\nشناسه گفتگوی تلگرام:\r\n<code>/id</code>",
"helpClientCommands": "برای جستجوی آمار، از دستور زیر استفاده کنید:\r\n<code>/usage [ایمیل]</code>\r\n\r\nشناسه گفتگوی تلگرام:\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": "نمایش شناسه تلگرام شما"
},
"messages": {
"cpuThreshold": "🔴 بار ‌پردازنده {{ .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": "🚀 نسخه‌پنل: {{ .Version }}\r\n",
"xrayVersion": "📡 نسخه‌هسته: {{ .XrayVersion }}\r\n",
"ipv6": "🌐 IPv6: {{ .IPv6 }}\r\n",
"ipv4": "🌐 IPv4: {{ .IPv4 }}\r\n",
"ip": "🌐 آدرس‌آی‌پی: {{ .IP }}\r\n",
"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\r\n",
"expireIn": "📅 باقی‌ مانده‌ تا انقضا: {{ .Time }}\r\n\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": "🔑📥 شناسه به‌روزرسانی شد.",
"received_password": "🔑📥 رمز عبور به‌روزرسانی شد.",
"received_email": "📧📥 ایمیل به‌روزرسانی شد.",
"received_comment": "💬📥 نظر به‌روزرسانی شد.",
"id_prompt": "🔑 شناسه پیش‌فرض: {{ .ClientId }}\n\nشناسه خود را وارد کنید.",
"pass_prompt": "🔑 رمز عبور پیش‌فرض: {{ .ClientPassword }}\n\nرمز عبور خود را وارد کنید.",
"email_prompt": "📧 ایمیل پیش‌فرض: {{ .ClientEmail }}\n\nایمیل خود را وارد کنید.",
"comment_prompt": "💬 نظر پیش‌فرض: {{ .ClientComment }}\n\nنظر خود را وارد کنید.",
"inbound_client_data_id": "🔄 ورودی: {{ .InboundRemark }}\n\n🔑 شناسه: {{ .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": "🔚 فرآیند بازنشانی ترافیک برای همه مشتریان به پایان رسید."
},
"buttons": {
"closeKeyboard": "❌ بستن کیبورد",
"cancel": "❌ لغو",
"cancelReset": "❌ لغو تنظیم مجدد",
"cancelIpLimit": "❌ لغو محدودیت آی‌پی",
"confirmResetTraffic": "✅ تأیید تنظیم مجدد ترافیک؟",
"confirmClearIps": "✅ تأیید پاک‌سازی آدرس‌های آی‌پی؟",
"confirmRemoveTGUser": "✅ تأیید حذف کاربر تلگرام؟",
"confirmToggle": "✅ تایید فعال/غیرفعال کردن کاربر؟",
"dbBackup": "دریافت پشتیبان",
"serverUsage": "استفاده از سیستم",
"getInbounds": "دریافت ورودی‌ها",
"depleteSoon": "به‌زودی به پایان خواهد رسید",
"clientUsage": "دریافت آمار کاربر",
"onlines": "کاربران آنلاین",
"commands": "دستورات",
"refresh": "🔄 تازه‌سازی",
"clearIPs": "❌ پاک‌سازی آدرس‌ها",
"removeTGUser": "❌ حذف کاربر تلگرام",
"selectTGUser": "👤 انتخاب کاربر تلگرام",
"selectOneTGUser": "👤 یک کاربر تلگرام را انتخاب کنید:",
"resetTraffic": "📈 تنظیم مجدد ترافیک",
"resetExpire": "📅 تنظیم مجدد تاریخ انقضا",
"ipLog": "🔢 لاگ آدرس‌های IP",
"ipLimit": "🔢 محدودیت IP",
"setTGUser": "👤 تنظیم کاربر تلگرام",
"toggle": "🔘 فعال / غیرفعال",
"custom": "🔢 سفارشی",
"confirmNumber": "✅ تایید: {{ .Num }}",
"confirmNumberAdd": "✅ تایید اضافه کردن: {{ .Num }}",
"limitTraffic": "🚧 محدودیت ترافیک",
"getBanLogs": "گزارش های بلوک را دریافت کنید",
"allClients": "همه مشتریان",
"addClient": "افزودن مشتری",
"submitDisable": "ارسال به عنوان غیرفعال ☑️",
"submitEnable": "ارسال به عنوان فعال ✅",
"use_default": "🏷️ استفاده از پیش‌فرض",
"change_id": "⚙️🔑 شناسه",
"change_password": "⚙️🔑 گذرواژه",
"change_email": "⚙️📧 ایمیل",
"change_comment": "⚙️💬 نظر",
"change_flow": "⚙️🚦 جریان",
"ResetAllTraffics": "بازنشانی همه ترافیک‌ها",
"SortedTrafficUsageReport": "گزارش استفاده از ترافیک مرتب‌شده"
},
"answers": {
"successfulOperation": "✅ انجام شد!",
"errorOperation": "❗ خطا در عملیات.",
"getInboundsFailed": "❌ دریافت ورودی‌ها با خطا مواجه شد.",
"getClientsFailed": "❌ دریافت مشتریان با شکست مواجه شد.",
"canceled": "❌ {{ .Email }} : عملیات لغو شد.",
"clientRefreshSuccess": "✅ {{ .Email }} : کلاینت با موفقیت تازه‌سازی شد.",
"IpRefreshSuccess": "✅ {{ .Email }} : آدرس‌ها با موفقیت تازه‌سازی شدند.",
"TGIdRefreshSuccess": "✅ {{ .Email }} : کاربر تلگرام کلاینت با موفقیت تازه‌سازی شد.",
"resetTrafficSuccess": "✅ {{ .Email }} : ترافیک با موفقیت تنظیم مجدد شد.",
"setTrafficLimitSuccess": "✅ {{ .Email }} : محدودیت ترافیک با موفقیت ذخیره شد.",
"expireResetSuccess": "✅ {{ .Email }} : تاریخ انقضا با موفقیت تنظیم مجدد شد.",
"resetIpSuccess": "✅ {{ .Email }} : محدودیت آدرس IP {{ .Count }} با موفقیت ذخیره شد.",
"clearIpSuccess": "✅ {{ .Email }} : آدرس‌ها با موفقیت پاک‌سازی شدند.",
"getIpLog": "✅ {{ .Email }} : دریافت لاگ آدرس‌های IP.",
"getUserInfo": "✅ {{ .Email }} : دریافت اطلاعات کاربر تلگرام.",
"removedTGUserSuccess": "✅ {{ .Email }} : کاربر تلگرام با موفقیت حذف شد.",
"enableSuccess": "✅ {{ .Email }} : با موفقیت فعال شد.",
"disableSuccess": "✅ {{ .Email }} : با موفقیت غیرفعال شد.",
"askToAddUserId": "پیکربندی شما یافت نشد!\r\nلطفاً از مدیر خود بخواهید که شناسه کاربر تلگرام خود را در پیکربندی (های) خود استفاده کند.\r\n\r\nشناسه کاربری شما: <code>{{ .TgUserID }}</code>",
"chooseClient": "یک مشتری برای ورودی {{ .Inbound }} انتخاب کنید",
"chooseInbound": "یک ورودی انتخاب کنید"
}
}
}