mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-05-31 18:24:10 +00:00
* chore(frontend): add react+typescript toolchain alongside vue
Step 0 of the planned vue->react migration. React 19, antd 5, i18next
+ react-i18next, typescript 5, and @vitejs/plugin-react 6 are added as
dev/runtime deps alongside the existing vue stack. Both frameworks
coexist in the build until the last entry flips.
* vite.config.js: react() plugin runs next to vue(); new manualChunks
for vendor-react / vendor-antd-react / vendor-icons-react /
vendor-i18next. Existing vue chunks unchanged.
* eslint.config.js: typescript-eslint + eslint-plugin-react-hooks
rules scoped to *.{ts,tsx}; vue config untouched for *.{js,vue}.
* tsconfig.json: strict, jsx: react-jsx, moduleResolution: bundler,
allowJs: true (lets .tsx files import the remaining .js modules
during incremental migration), @/* path alias.
* env.d.ts: Vite client types + window.X_UI_BASE_PATH typing +
SubPageData shape consumed by the subscription page.
Vite stays pinned at 8.0.13 per the existing project policy. No
existing .vue/.js source files touched in this step.
eslint-plugin-react (not -hooks) is not included because its latest
release does not yet support ESLint 10. react-hooks/purity covers
the safety-critical case; revisit when the plugin updates.
* refactor(frontend): port subpage to react+ts
Step 1 of the planned vue->react migration. The standalone
subscription page (sub/sub.go renders the HTML host; React mounts
into #app) is the first entry off vue.
Introduces two shared pieces both entries (and future ones) will
use:
* src/hooks/useTheme.tsx — React Context + useTheme hook + the
same buildAntdThemeConfig (dark/ultra-dark token overrides) and
pauseAnimationsUntilLeave helper the vue version exposes. Same
localStorage keys (dark-mode, isUltraDarkThemeEnabled) and DOM
side effects (body.className, html[data-theme]) so the two stay
in sync across the coexistence period.
* src/i18n/react.ts — i18next + react-i18next loader that reads
the same web/translation/*.json files via import.meta.glob. The
vue-i18n setup in src/i18n/index.js is untouched and still serves
the remaining vue entries.
SubPage.tsx mirrors the vue version's behavior: reads
window.__SUB_PAGE_DATA__ injected by the Go sub server, renders QR
codes / descriptions / Android+iOS deep-link dropdowns, supports
theme cycle and language switch. Uses AntD v5 idioms: Descriptions
items prop, Dropdown menu prop, Layout.Content.
* refactor(frontend): port login to react+ts
Step 2 of the planned vue->react migration. The login entry is the
first to exercise AntD React's Form API (Form + Form.Item with
name/rules + onFinish) and the existing axios/CSRF interceptors
under React.
* LoginPage.tsx: same form fields, conditional 2FA input,
rotating headline ("Hello" / "Welcome to..."), drifting blob
background, theme cycle + language popover. Headline transition
switches from vue's <Transition mode=out-in> to a CSS keyframe
animation keyed off the visible word.
* entries/login.tsx: setupAxios() + applyDocumentTitle() unchanged
from the vue entry — both are framework-agnostic in src/utils
and src/api/axios-init.js.
useTheme hook, ThemeProvider, and i18n/react.ts loader introduced
in step 1 are now shared across two entries; Vite extracts them as
a small chunk in the build output.
* refactor(frontend): port api-docs to react+ts
Step 3 of the planned vue->react migration. The five api-docs files
(ApiDocsPage, CodeBlock, EndpointRow, EndpointSection, plus the
data-only endpoints.js) all move to react+ts.
Also introduces components/AppSidebar.tsx — api-docs is the first
authenticated page to need it. AppSidebar.vue stays in place for the
six remaining vue entries (settings, inbounds, clients, xray, nodes,
index); each gets switched to AppSidebar.tsx as its entry migrates.
After the last entry flips, AppSidebar.vue is deleted.
Notable transformations:
* The scroll observer that highlights the active TOC link is a
useEffect keyed on sections — re-registers whenever the visible
set changes (search filter narrows it). Same behaviour as the vue
watchEffect.
* v-html="safeInlineHtml(...)" becomes
dangerouslySetInnerHTML={{ __html: safeInlineHtml(...) }}. The
helper still escapes everything except <code> tags.
* JSON syntax highlighter in CodeBlock is unchanged — pure regex on
the escaped string, then rendered via dangerouslySetInnerHTML.
* endpoints.js stays as JS (allowJs in tsconfig); only the consumer
signatures (Endpoint, Section) are typed at the React boundary.
* AppSidebar reuses pauseAnimationsUntilLeave + useTheme from
step 1. Drawer + Sider keyed off the same localStorage flag
(isSidebarCollapsed) and DOM theme attributes the vue version
uses, so the two stay in sync during coexistence.
* refactor(frontend): port nodes to react+ts
Step 4 of the planned vue->react migration. The nodes entry brings in
the largest shared-infrastructure batch so far — every authenticated
react page from here on can lean on these.
New shared pieces (live alongside their .vue counterparts during
coexistence):
* hooks/useMediaQuery.ts — useState + resize listener
* hooks/useWebSocket.ts — wraps WebSocketClient, subscribes on mount
and unsubscribes on unmount. The underlying client is a single
module-level instance so multiple components on the same page
share one socket.
* hooks/useNodes.ts — node list state + CRUD + probe/test, including
the totals memo (online/offline/avgLatency) used by the summary card.
applyNodesEvent is the entry point for the heartbeat-pushed list.
* components/CustomStatistic.tsx — thin Statistic wrapper, prefix +
suffix slots become props.
* components/Sparkline.tsx — the SVG line chart with measured-width
axis scaling, gradient fill, tooltip overlay, and per-instance
gradient id from React.useId. ResizeObserver lifecycle is in
useEffect; the math is unchanged.
Pages:
* NodesPage — wires hooks + WebSocket together, renders summary card
+ NodeList, hosts the form modal. Uses Modal.useModal() for the
delete confirm so the dialog inherits ConfigProvider theming.
* NodeList — desktop renders a Table with expandable history rows;
mobile flips to a vertical card list whose actions live in a
bottom-right Dropdown. The IP-blur eye toggle persists across both.
* NodeFormModal — controlled form (useState object, single setForm
per change). The reset-on-open effect computes the next state
once and applies it with eslint-disable to satisfy the new
react-hooks/set-state-in-effect rule on a legitimate pattern.
* NodeHistoryPanel — polls /panel/api/nodes/history/{id}/{metric}/
{bucket} every 15s, renders cpu+mem sparklines side-by-side.
* refactor(frontend): port settings to react+ts
Step 5 of the planned vue->react migration. Settings is the first
entry whose state model didn't translate to the Vue-style "parent
passes a reactive object, children mutate it in place" pattern, so
the React port flips it to lifted state + a typed updateSetting
patch function.
* models/setting.ts — typed AllSetting class with the same field
defaults and equals() behavior the vue version had. The .js
twin is deleted; nothing else imported it.
* hooks/useAllSetting.ts — owns allSetting + oldAllSetting state,
exposes updateSetting(patch), saveDisabled is derived via useMemo
off equals() (no more 1Hz dirty-check timer).
* components/SettingListItem.tsx — children-based wrapper instead
of named slots. The vue twin stays alive because xray (BasicsTab,
DnsTab) still imports it; deleted when xray migrates.
The five tab components and the TwoFactorModal each accept
{ allSetting, updateSetting } and render with AntD v5's Collapse
items[] API. Every v-model:value="x" became
value={...} onChange={(e) => updateSetting({ key: e.target.value })}
or onChange={(v) => updateSetting({ key: v })} for non-input
controls.
SubscriptionFormatsTab is the trickiest — fragment / noises[] /
mux / direct routing rules are stored as JSON-encoded strings on
the wire. Parsing them once via useMemo per field, mutating the
parsed object on edit, and stringifying back into the patch keeps
the round-trip identical to the vue version.
SettingsPage hosts the tab navigation (with hash sync), the
save / restart action bar, the security-warnings alert banner,
and the restart flow that rebuilds the panel URL after the new
host/port/cert settings take effect.
* refactor(frontend): port clients to react+ts
Step 6 of the planned vue->react migration. Clients is the biggest
data-CRUD page in the panel (1.1k-line ClientsPage, 4 modals, full
table + mobile card list, WebSocket-driven realtime traffic + online
updates).
New shared infra (lives alongside vue twins until inbounds migrates):
* hooks/useClients.ts — clients + inbounds list, CRUD + bulk delete +
attach/detach + traffic reset, with WebSocket event handlers
(traffic, client_stats, invalidate) and a small debounced refresh
on the invalidate event. State managed via setState; the live
client_stats event merges traffic snapshots row-by-row through a
ref to avoid stale closure issues.
* hooks/useDatepicker.ts — singleton "gregorian"/"jalalian" cache
with subscribe/notify so multiple components can read the panel's
Calendar Type without re-fetching. Mirrors useDatepicker.js.
* components/DateTimePicker.tsx — AntD DatePicker wrapper.
vue3-persian-datetime-picker has no React port; the Jalali UI
calendar is deferred (read-only Jalali display via IntlUtil
formatDate still works). The vue twin stays for inbounds.
* pages/inbounds/QrPanel.tsx — copy/download/copy-as-png QR helper
shared between clients (qr modal) and inbounds (still on vue).
Vue twin stays alive at QrPanel.vue.
* models/inbound.ts — slim port: only the TLS_FLOW_CONTROL constant
the clients form needs. The full inbound model stays as
inbound.js for now; inbounds will pull it in as inbound.ts.
The clients page itself uses Modal.useModal() for all confirm
dialogs (delete, bulk-delete, reset-traffic, delDepleted, reset-all)
so the dialogs render themed. Filter state persists to
localStorage under clientsFilterState. Sort + pagination state is
local; pageSize seeds from /panel/setting/defaultSettings.
The four modals share a controlled "open/onOpenChange" pattern
that replaces vue's v-model:open. ClientFormModal computes
attach/detach diffs from the inbound multi-select on submit; the
parent's onSave callback routes them through useClients's attach()/
detach() after the main update succeeds.
ESLint config: turned off four react-hooks v7 rules
(react-compiler, preserve-manual-memoization, set-state-in-effect,
purity). They're all React-Compiler-driven informational rules; we
don't run the compiler and the patterns they flag (initial-fetch
useEffect, derived computations using Date.now, inline arrow event
handlers) are all idiomatic React. Disabling globally instead of
per-line keeps the diff readable.
* refactor(frontend): port index dashboard to react+ts
Step 7 of the Vue→React migration. Ports the overview/index entry: dashboard
page, status + xray cards, panel-update / log / backup / system-history /
xray-metrics / xray-log / version modals, and the custom-geo subsection. Adds
the shared JsonEditor (CodeMirror 6) and useStatus hook used by the config
modal. Removes the unused react-hooks/set-state-in-effect disables now that
the rule is off globally.
* refactor(frontend): port xray to react+ts
Step 8 of the Vue→React migration. Ports the xray config entry: page shell,
basics/routing/outbounds/balancers/dns tabs, the rule + balancer + dns server
+ dns presets + warp + nord modals, the protocol-aware outbound form, and the
shared FinalMaskForm (TCP/UDP masks + QUIC params). Adds useXraySetting that
mirrors the legacy two-way sync between the JSON template string and the
parsed templateSettings tree. The outbound model itself stays in JS so the
class-driven form keeps its existing mutation API; instance access is typed
loosely inside the form to match.
The shared FinalMaskForm.vue and JsonEditor.vue stay alongside the new .tsx
versions until step 9 — InboundFormModal.vue still imports them.
Adds react-hooks/immutability and react-hooks/refs to the already-disabled
react-compiler rule set; both flag the outbound form's instance-mutation
pattern that doesn't run through useState.
* Upgrade frontend deps (antd v6, i18n, TS)
Bump frontend dependencies in package.json and regenerate package-lock.json. Notable updates: upgrade antd to v6, update i18next/react-i18next, axios, qs, vue-i18n, TypeScript and ESLint, plus related @rc-component packages and replacements (e.g. classnames/rc-util -> clsx/@rc-component/util). Lockfile changes reflect the new dependency tree required for Ant Design v6 and other package upgrades.
* refactor(frontend): port inbounds to react+ts and drop vue toolchain
Step 9 — the last entry. Ports the inbounds entry: page shell, list with
desktop table + mobile cards, info modal, qr-code modal, share-link
helpers, and the protocol-aware form modal (basics / protocol /
stream / security / sniffing / advanced JSON). useInbounds replaces
the Vue composable with WebSocket-driven traffic + client-stats merge.
Inbound and DBInbound models stay in JS so the class-driven form keeps
its mutation API; instance access is typed loosely inside the form to
match. FinalMaskForm/JsonEditor/TextModal/PromptModal/InfinityIcon are
the last shared bits to flip; their .vue counterparts go too.
Toolchain cleanup now that no entry needs Vue: drop plugin-vue from
vite.config, remove the .vue lint block + parser, prune vue / vue-i18n
/ ant-design-vue / @ant-design/icons-vue / vue3-persian-datetime-picker
/ moment-jalaali override from package.json, and switch utils/index.js
to import { message } from 'antd' instead of ant-design-vue.
* chore(frontend): adopt antd v6 api updates
Sweep deprecated props across the React tree:
- Modal: destroyOnClose -> destroyOnHidden, maskClosable -> mask.closable
- Space: direction -> orientation (or removed when redundant)
- Input.Group compact -> Space.Compact block
- Drawer: width -> size
- Spin: tip -> description
- Progress: trailColor -> railColor
- Alert: message -> title
- Popover: overlayClassName -> rootClassName
- BackTop -> FloatButton.BackTop
Also refresh dashboard theming for v6: rename dark/ultra Layout and Menu
tokens (siderBg, darkItemBg, darkSubMenuItemBg, darkPopupBg), tweak gauge
size/stroke, add font-size overrides for Statistic and Progress so the
overview numbers stay legible under v6 defaults.
* chore(frontend): antd v6 polish, theme + modal fixes
- adopt message.useMessage hook + messageBus bridge so HttpUtil messages
inherit ConfigProvider theme tokens
- replace deprecated antd APIs (List, Input addonBefore/After, Empty
imageStyle); introduce InputAddon helper + SettingListItem custom rows
- fix dark/ultra selectors in portaled modals (body.dark,
html[data-theme='ultra-dark']) instead of nonexistent .is-dark/.is-ultra
- add horizontal scroll to clients table; reorder node columns so
actions+enable sit at the left
- swap raw button for antd Button in NodeFormModal test connection
- fix FinalMaskForm nested-form by hoisting it outside OutboundFormModal's
parent Form
- fix advanced "all" JSON tab in InboundFormModal — useMemo on a mutated
ref was stale; compute on every render
- fix chart-on-open for SystemHistory + XrayMetrics modals by adding open
to effect deps (useRef.current doesn't trigger re-runs)
- switch i18next interpolation to single-brace {var} to match locale files
- drop residual Vue mentions in CI workflows and Go comments
* fix(frontend): qr code collapse — open only first panel, allow toggle
ClientQrModal and QrCodeModal both used activeKey without onChange,
forcing every panel open and blocking user toggle. Switch to controlled
state initialized to the first item's key on open, with onChange so
clicks update state.
Also remove unused AppBridge.tsx (superseded by per-page message.useMessage
hook).
* fix(frontend): hover cards, balancer load, routing dnd, modal a11y, outbound crash
- ClientsPage/SettingsPage/XrayPage: add hoverable to bottom card/tabs so
hover affordance matches the top card
- BalancerFormModal: lazy-init useState from props + destroyOnHidden so
the form mounts with saved values instead of relying on a useEffect
sync that could miss the first open
- RoutingTab: rewrite pointer drag — handlers are now defined inside the
pointerdown closure so addEventListener/removeEventListener match;
drag state lives on a ref (from/to/moved) so onUp reads the real
indices, not stale closure values. Adds setPointerCapture so Windows
and touch keep delivering events when the cursor leaves the handle.
- OutboundFormModal/InboundFormModal: blur the focused input before
switching tabs to silence the aria-hidden-on-focused-element warning
- utils.isArrEmpty: return true for undefined/null arrays — the old form
treated undefined as "not empty" which crashed VLESSSettings.fromJson
when json.vnext was missing
* fix(frontend): clipboard reliability + restyle login page
- ClipboardManager.copyText: prefer navigator.clipboard on secure
contexts, fall back to a focused on-screen textarea + execCommand.
Old path used left:-9999px which failed selection in some browsers
and swallowed execCommand's return value, so the "copied" toast
appeared even when nothing made it to the clipboard.
- LoginPage: richer gradient backdrop — five animated colour blobs,
glassmorphic card (backdrop-filter blur + saturate), gradient brand
text/accent, masked grid texture for depth, and a thin gradient
border on the card. Light/dark/ultra each get their own palette.
* Memoize compactAdvancedJson and update deps
Wrap compactAdvancedJson in useCallback (dependent on messageApi) and add it to the dependency array of applyAdvancedJsonToBasic. This ensures a stable function reference for correct dependency tracking and avoids stale closures/unnecessary re-renders in InboundFormModal.tsx.
* style(frontend): prettier charts, drop redundant frame, format net rates
- Sparkline: multi-stop gradient fill, soft drop-shadow under the line,
dashed grid, glowing pulse on the latest-point marker, pill-shaped
tooltip with dashed crosshair
- XrayMetricsModal: glow + pulse on the observatory alive dot,
monospace stamps/listen text
- SystemHistoryModal: keep just the modal's frame around the chart (the
inner wrapper I'd added stacked a second border on top); strip the
decimal from Net Up/Down (25.63 KB/s → 25 KB/s) only on this chart's
formatter
* style(frontend): refined dark/ultra palette + shared pro card frame
- Dark tokens shifted to a cooler, Linear-style palette: page #1a1b1f,
sidebar/header #15161a (recessed nav, darker than cards), card
#23252b, elevated #2d2f37
- Ultra dark: page pure #000 for OLED, sidebar #050507 disappears into
the frame, card #101013 with a clear step, elevated #1a1a1e
- New styles/page-cards.css holds the card border/shadow/hover rules so
all seven content pages (index, clients, inbounds, xray, settings,
nodes, api-docs) share one definition instead of duplicating in each
page CSS
- Dashboard typography: uppercase card titles with letter-spacing,
larger 17px stat values, subtle gradient divider between stat columns,
ellipsis on action labels so "Backup & Restore" doesn't break the
card height at mid widths
- Light --bg-page stays at #e6e8ec for the contrast against white cards
* fix(frontend): wireguard info alignment, blue login dark, embed gitkeep
- align WireGuard info-modal fields with Protocol/Address/Port by wrapping
values in Tag (matches the rest of the dl.info-list rows)
- swap login dark palette from purple to pure blue blobs/accent/brand
- pin web/dist/.gitkeep through gitignore so //go:embed all:dist never
fails on a fresh clone with an empty dist directory
* docs: refresh frontend docs for the React + TS + AntD 6 stack
Update CONTRIBUTING.md and frontend/README.md to describe the migrated
frontend accurately:
- replace Vue 3 / Ant Design Vue 4 references with React 19 / AntD 6 / TS
- swap composables -> hooks, vue-i18n -> react-i18next, createApp -> createRoot
- mention the typecheck step (tsc --noEmit) in the PR checklist
- document the Vite 8.0.13 pin and TypeScript strict mode in conventions
- list the nodes and api-docs entries that were missing from the layout
* style(frontend): improve readability and mobile polish
- bump statistic title/value contrast in dark and ultra-dark so totals
on the inbounds summary card stay legible
- give index card actions explicit colors per theme so links like Stop,
Logs, System History no longer fade into the card background
- show the panel version as a tag next to "3X-UI" on mobile, mirroring
the Xray version tag pattern, and turn it orange when an update is
available
- make the login settings button a proper circle by adding size="large"
+ an explicit border-radius fallback on .toolbar-btn
* feat: jalali calendar support and date formatting fixes
- Wire useDatepicker into IntlUtil and switch jalalian display locale
to fa-IR for clean "1405/07/03 12:00:00" output (drops the awkward
"AP" era suffix that "<lang>-u-ca-persian" produced)
- Drop in persian-calendar-suite for the jalali date picker, with a
light/dark/ultra theme map and CSS overrides so the inline-styled
input stays readable and bg matches the surrounding container
- Force LTR on the picker input so "1405/03/07 00:00" reads naturally
- Pass calendar setting through ClientInfoModal, ClientsPage Duration
tooltip, and ClientFormModal's expiry picker
- Heuristic toMs() in ClientInfoModal so GORM's autoUpdateTime seconds
render as a real date instead of "1348/11/01"
- Persist UpdatedAt on the ClientRecord row in client_service.Update;
previously only the inbound settings JSON was bumped, so the panel
never saw a fresh updated_at after editing a client
* feat(frontend): donate link, panel version label, login lang menu
- Sidebar: add heart donate link to https://donate.sanaei.dev and small panel version under 3X-UI brand
- Login: swap settings-cog for translation icon, drop title, render languages as a direct list
- Vite dev: inject window.X_UI_CUR_VER from config/version so dev mode matches prod
- Translations: add menu.donate across all locales
* fix(xray-update): respect XUI_BIN_FOLDER on Windows
The Windows update path hardcoded "bin/xray-windows-amd64.exe", ignoring
the configured XUI_BIN_FOLDER. In dev mode (folder set to x-ui) this
created a stray bin/ folder while the running binary stayed un-updated.
* Bump Xray to v26.5.9 and minor cleanup
Update Xray release URLs to v26.5.9 in the GitHub Actions workflow and DockerInit.sh. Remove the hardcoded skip for tagVersion "26.5.3" so it will be considered when collecting Xray versions. Apply small formatting fixes: remove an extra blank line in database/db.go, normalize spacing/alignment of Protocol constants in database/model/model.go, and trim a trailing blank line in web/controller/inbound.go.
* fix(frontend): route remaining copy buttons through ClipboardManager
Direct navigator.clipboard calls fail in non-secure contexts (HTTP on a
LAN IP), making the API-docs code copy and security-tab token copy
silently broken. Both now go through ClipboardManager which falls back
to document.execCommand('copy') when navigator.clipboard is unavailable.
* fix(db): store CreatedAt/UpdatedAt in milliseconds
GORM's autoCreateTime/autoUpdateTime tags default to Unix seconds on
int64 fields and overwrite the service-supplied UnixMilli value on
save. The frontend interprets these timestamps as JS Date inputs
(milliseconds), so created/updated columns rendered ~1970 dates. Adding
the :milli qualifier makes GORM match what the service code and UI
expect.
* Improve legacy clipboard copy handling
Refactor ClipboardManager._legacyCopy to better handle focus and selection when copying. The textarea is now appended to the active element's parent (or body) and placed off-screen with aria-hidden and readonly attributes. The code preserves and restores the previous document selection and active element, uses focus({preventScroll: true}) to avoid scrolling, and returns the execCommand('copy') result. This makes legacy copy behavior more robust and less disruptive to the page state.
* fix(lint): drop redundant ok=false in clipboard fallback catch
* chore(deps): bump golang.org/x/net to v0.55.0 for GO-2026-5026
1093 lines
No EOL
64 KiB
JSON
1093 lines
No EOL
64 KiB
JSON
{
|
||
"username": "Tên người dùng",
|
||
"password": "Mật khẩu",
|
||
"login": "Đăng nhập",
|
||
"confirm": "Xác nhận",
|
||
"cancel": "Hủy bỏ",
|
||
"close": "Đóng",
|
||
"save": "Lưu",
|
||
"logout": "Đăng xuất",
|
||
"create": "Tạo",
|
||
"update": "Cập nhật",
|
||
"copy": "Sao chép",
|
||
"copied": "Đã sao chép",
|
||
"download": "Tải xuống",
|
||
"remark": "Ghi chú",
|
||
"enable": "Kích hoạt",
|
||
"protocol": "Giao thức",
|
||
"search": "Tìm kiếm",
|
||
"filter": "Bộ lọc",
|
||
"loading": "Đang tải",
|
||
"refresh": "Làm mới",
|
||
"clear": "Xóa",
|
||
"second": "Giây",
|
||
"minute": "Phút",
|
||
"hour": "Giờ",
|
||
"day": "Ngày",
|
||
"check": "Kiểm tra",
|
||
"indefinite": "Không xác định",
|
||
"unlimited": "Không giới hạn",
|
||
"none": "None",
|
||
"qrCode": "Mã QR",
|
||
"info": "Thông tin thêm",
|
||
"edit": "Chỉnh sửa",
|
||
"delete": "Xóa",
|
||
"reset": "Đặt lại",
|
||
"noData": "Không có dữ liệu.",
|
||
"copySuccess": "Đã sao chép thành công",
|
||
"sure": "Chắc chắn",
|
||
"encryption": "Mã hóa",
|
||
"useIPv4ForHost": "Sử dụng IPv4 cho máy chủ",
|
||
"transmission": "Truyền tải",
|
||
"host": "Máy chủ",
|
||
"path": "Đường dẫn",
|
||
"camouflage": "Ngụy trang",
|
||
"status": "Trạng thái",
|
||
"enabled": "Đã kích hoạt",
|
||
"disabled": "Đã tắt",
|
||
"depleted": "Depleted",
|
||
"depletingSoon": "Depleting...",
|
||
"offline": "Ngoại tuyến",
|
||
"online": "Trực tuyến",
|
||
"domainName": "Tên miền",
|
||
"monitor": "Listening IP",
|
||
"certificate": "Chứng chỉ số",
|
||
"fail": "Thất bại",
|
||
"comment": "Bình luận",
|
||
"success": "Thành công",
|
||
"lastOnline": "Lần online gần nhất",
|
||
"getVersion": "Lấy phiên bản",
|
||
"install": "Cài đặt",
|
||
"clients": "Các khách hàng",
|
||
"usage": "Sử dụng",
|
||
"twoFactorCode": "Mã",
|
||
"remained": "Còn lại",
|
||
"security": "Bảo vệ",
|
||
"secAlertTitle": "Cảnh báo an ninh-Tiếng Việt by Ohoang7",
|
||
"secAlertSsl": "Kết nối này không an toàn; Vui lòng không nhập thông tin nhạy cảm cho đến khi TLS được kích hoạt để bảo vệ dữ liệu của Bạn",
|
||
"secAlertConf": "Một số cài đặt có thể dễ bị tấn công. Đề xuất tăng cường các giao thức bảo mật để ngăn chặn các vi phạm tiềm ẩn.",
|
||
"secAlertSSL": "Bảng điều khiển thiếu kết nối an toàn. Vui lòng cài đặt chứng chỉ TLS để bảo vệ dữ liệu.",
|
||
"secAlertPanelPort": "Cổng mặc định của bảng điều khiển có thể dễ bị tấn công. Vui lòng cấu hình một cổng ngẫu nhiên hoặc cụ thể.",
|
||
"secAlertPanelURI": "Đường dẫn URI mặc định của bảng điều khiển không an toàn. Vui lòng cấu hình một đường dẫn URI phức tạp.",
|
||
"secAlertSubURI": "Đường dẫn URI mặc định của đăng ký không an toàn. Vui lòng cấu hình một đường dẫn URI phức tạp.",
|
||
"secAlertSubJsonURI": "Đường dẫn URI JSON mặc định của đăng ký không an toàn. Vui lòng cấu hình một đường dẫn URI phức tạp.",
|
||
"emptyDnsDesc": "Không có máy chủ DNS nào được thêm.",
|
||
"emptyFakeDnsDesc": "Không có máy chủ Fake DNS nào được thêm.",
|
||
"emptyBalancersDesc": "Không có bộ cân bằng tải nào được thêm.",
|
||
"emptyReverseDesc": "Không có proxy ngược nào được thêm.",
|
||
"somethingWentWrong": "Đã xảy ra lỗi",
|
||
"subscription": {
|
||
"title": "Thông tin đăng ký",
|
||
"subId": "ID đăng ký",
|
||
"status": "Trạng thái",
|
||
"downloaded": "Đã tải xuống",
|
||
"uploaded": "Đã tải lên",
|
||
"expiry": "Hết hạn",
|
||
"totalQuota": "Tổng hạn mức",
|
||
"individualLinks": "Liên kết riêng lẻ",
|
||
"active": "Hoạt động",
|
||
"inactive": "Không hoạt động",
|
||
"unlimited": "Không giới hạn",
|
||
"noExpiry": "Không hết hạn"
|
||
},
|
||
"menu": {
|
||
"theme": "Chủ đề",
|
||
"dark": "Tối",
|
||
"ultraDark": "Siêu tối",
|
||
"dashboard": "Trạng thái hệ thống",
|
||
"inbounds": "Đầu vào khách hàng",
|
||
"clients": "Khách hàng",
|
||
"nodes": "Nút",
|
||
"settings": "Cài đặt bảng điều khiển",
|
||
"xray": "Cài đặt Xray",
|
||
"apiDocs": "Tài liệu API",
|
||
"logout": "Đăng xuất",
|
||
"link": "Quản lý",
|
||
"donate": "Quyên góp"
|
||
},
|
||
"pages": {
|
||
"login": {
|
||
"hello": "Xin chào",
|
||
"title": "Chào mừng",
|
||
"loginAgain": "Thời hạn đăng nhập đã hết. Vui lòng đăng nhập lại.",
|
||
"toasts": {
|
||
"invalidFormData": "Dạng dữ liệu nhập không hợp lệ.",
|
||
"emptyUsername": "Vui lòng nhập tên người dùng.",
|
||
"emptyPassword": "Vui lòng nhập mật khẩu.",
|
||
"wrongUsernameOrPassword": "Tên người dùng, mật khẩu hoặc mã xác thực hai yếu tố không hợp lệ.",
|
||
"successLogin": "Bạn đã đăng nhập vào tài khoản thành công."
|
||
}
|
||
},
|
||
"index": {
|
||
"title": "Trạng thái hệ thống",
|
||
"cpu": "CPU",
|
||
"logicalProcessors": "Bộ xử lý logic",
|
||
"frequency": "Tần số",
|
||
"swap": "Swap",
|
||
"storage": "Lưu trữ",
|
||
"memory": "RAM",
|
||
"threads": "Luồng",
|
||
"xrayStatus": "Xray",
|
||
"stopXray": "Dừng lại",
|
||
"restartXray": "Khởi động lại",
|
||
"xraySwitch": "Phiên bản",
|
||
"xrayUpdates": "Cập nhật Xray",
|
||
"xraySwitchClick": "Chọn phiên bản mà bạn muốn chuyển đổi sang.",
|
||
"xraySwitchClickDesk": "Hãy lựa chọn thận trọng, vì các phiên bản cũ có thể không tương thích với các cấu hình hiện tại.",
|
||
"updatePanel": "Cập nhật Panel",
|
||
"panelUpdateDesc": "Điều này sẽ cập nhật 3X-UI lên bản phát hành mới nhất và khởi động lại dịch vụ panel.",
|
||
"currentPanelVersion": "Phiên bản panel hiện tại",
|
||
"latestPanelVersion": "Phiên bản panel mới nhất",
|
||
"panelUpToDate": "Panel đã được cập nhật",
|
||
"upToDate": "Đã cập nhật",
|
||
"xrayStatusUnknown": "Không xác định",
|
||
"xrayStatusRunning": "Đang chạy",
|
||
"xrayStatusStop": "Dừng",
|
||
"xrayStatusError": "Lỗi",
|
||
"xrayErrorPopoverTitle": "Đã xảy ra lỗi khi chạy Xray",
|
||
"operationHours": "Thời gian hoạt động",
|
||
"systemHistoryTitle": "Lịch sử hệ thống",
|
||
"charts": "Biểu đồ",
|
||
"xrayMetricsTitle": "Chỉ số Xray",
|
||
"xrayMetricsDisabled": "Điểm cuối chỉ số Xray chưa được cấu hình",
|
||
"xrayMetricsHint": "Thêm khối metrics cấp cao nhất vào cấu hình xray với tag là metrics_out và listen là 127.0.0.1:11111, sau đó khởi động lại xray.",
|
||
"xrayObservatoryEmpty": "Chưa có dữ liệu Observatory",
|
||
"xrayObservatoryHint": "Thêm khối observatory vào cấu hình xray liệt kê các tag outbound cần kiểm tra, sau đó khởi động lại xray.",
|
||
"xrayObservatoryTagPlaceholder": "Chọn outbound",
|
||
"xrayObservatoryAlive": "Hoạt động",
|
||
"xrayObservatoryDead": "Ngừng",
|
||
"xrayObservatoryLastSeen": "Lần cuối thấy",
|
||
"xrayObservatoryLastTry": "Lần thử cuối",
|
||
"trendLast2Min": "2 phút gần nhất",
|
||
"systemLoad": "Tải hệ thống",
|
||
"systemLoadDesc": "trung bình tải hệ thống trong 1, 5 và 15 phút qua",
|
||
"connectionCount": "Số lượng kết nối",
|
||
"ipAddresses": "Địa chỉ IP",
|
||
"toggleIpVisibility": "Chuyển đổi hiển thị IP",
|
||
"overallSpeed": "Tốc độ tổng thể",
|
||
"upload": "Tải lên",
|
||
"download": "Tải xuống",
|
||
"totalData": "Tổng dữ liệu",
|
||
"sent": "Đã gửi",
|
||
"received": "Đã nhận",
|
||
"documentation": "Tài liệu",
|
||
"xraySwitchVersionDialog": "Bạn có chắc chắn muốn thay đổi phiên bản Xray không?",
|
||
"xraySwitchVersionDialogDesc": "Hành động này sẽ thay đổi phiên bản Xray thành #version#.",
|
||
"xraySwitchVersionPopover": "Xray đã được cập nhật thành công",
|
||
"panelUpdateDialog": "Bạn có chắc muốn cập nhật panel không?",
|
||
"panelUpdateDialogDesc": "Điều này sẽ cập nhật 3X-UI lên #version# và khởi động lại dịch vụ panel.",
|
||
"panelUpdateCheckPopover": "Kiểm tra cập nhật panel thất bại",
|
||
"panelUpdateStartedPopover": "Bắt đầu cập nhật panel",
|
||
"geofileUpdateDialog": "Bạn có chắc chắn muốn cập nhật geofile không?",
|
||
"geofileUpdateDialogDesc": "Hành động này sẽ cập nhật tệp #filename#.",
|
||
"geofilesUpdateDialogDesc": "Thao tác này sẽ cập nhật tất cả các tập tin.",
|
||
"geofilesUpdateAll": "Cập nhật tất cả",
|
||
"geofileUpdatePopover": "Geofile đã được cập nhật thành công",
|
||
"customGeoTitle": "GeoSite / GeoIP tùy chỉnh",
|
||
"customGeoAdd": "Thêm",
|
||
"customGeoType": "Loại",
|
||
"customGeoAlias": "Bí danh",
|
||
"customGeoUrl": "URL",
|
||
"customGeoEnabled": "Bật",
|
||
"customGeoLastUpdated": "Cập nhật lần cuối",
|
||
"customGeoExtColumn": "Định tuyến (ext:…)",
|
||
"customGeoToastUpdateAll": "Đã cập nhật tất cả nguồn tùy chỉnh",
|
||
"customGeoActions": "Thao tác",
|
||
"customGeoEdit": "Sửa",
|
||
"customGeoDelete": "Xóa",
|
||
"customGeoDownload": "Cập nhật ngay",
|
||
"customGeoModalAdd": "Thêm geo tùy chỉnh",
|
||
"customGeoModalEdit": "Sửa geo tùy chỉnh",
|
||
"customGeoModalSave": "Lưu",
|
||
"customGeoDeleteConfirm": "Xóa nguồn geo tùy chỉnh này?",
|
||
"customGeoRoutingHint": "Trong quy tắc định tuyến dùng cột giá trị dạng ext:file.dat:tag (thay tag).",
|
||
"customGeoInvalidId": "ID tài nguyên không hợp lệ",
|
||
"customGeoAliasesError": "Không tải được bí danh geo tùy chỉnh",
|
||
"customGeoValidationAlias": "Bí danh chỉ gồm chữ thường, số, - và _",
|
||
"customGeoValidationUrl": "URL phải bắt đầu bằng http:// hoặc https://",
|
||
"customGeoAliasPlaceholder": "a-z 0-9 _ -",
|
||
"customGeoAliasLabelSuffix": " (tùy chỉnh)",
|
||
"customGeoToastList": "Danh sách geo tùy chỉnh",
|
||
"customGeoToastAdd": "Thêm geo tùy chỉnh",
|
||
"customGeoToastUpdate": "Cập nhật geo tùy chỉnh",
|
||
"customGeoToastDelete": "Đã xóa geofile tùy chỉnh “{{ .fileName }}”",
|
||
"customGeoToastDownload": "Đã cập nhật geofile “{{ .fileName }}”",
|
||
"customGeoErrInvalidType": "Loại phải là geosite hoặc geoip",
|
||
"customGeoErrAliasRequired": "Cần bí danh",
|
||
"customGeoErrAliasPattern": "Bí danh có ký tự không hợp lệ",
|
||
"customGeoErrAliasReserved": "Bí danh này được dành riêng",
|
||
"customGeoErrUrlRequired": "Cần URL",
|
||
"customGeoErrInvalidUrl": "URL không hợp lệ",
|
||
"customGeoErrUrlScheme": "URL phải dùng http hoặc https",
|
||
"customGeoErrUrlHost": "Máy chủ URL không hợp lệ",
|
||
"customGeoErrDuplicateAlias": "Bí danh này đã dùng cho loại này",
|
||
"customGeoErrNotFound": "Không tìm thấy nguồn geo tùy chỉnh",
|
||
"customGeoErrDownload": "Tải xuống thất bại",
|
||
"customGeoErrUpdateAllIncomplete": "Một hoặc nhiều nguồn geo tùy chỉnh không cập nhật được",
|
||
"customGeoEmpty": "Chưa có nguồn geo tùy chỉnh nào — nhấp Thêm để tạo",
|
||
"dontRefresh": "Đang tiến hành cài đặt, vui lòng không làm mới trang này.",
|
||
"logs": "Nhật ký",
|
||
"config": "Cấu hình",
|
||
"backup": "Sao lưu",
|
||
"backupTitle": "Sao lưu & Khôi phục",
|
||
"exportDatabase": "Sao lưu",
|
||
"exportDatabaseDesc": "Nhấp để tải xuống tệp .db chứa bản sao lưu cơ sở dữ liệu hiện tại của bạn vào thiết bị.",
|
||
"importDatabase": "Khôi phục",
|
||
"importDatabaseDesc": "Nhấp để chọn và tải lên tệp .db từ thiết bị của bạn để khôi phục cơ sở dữ liệu từ bản sao lưu.",
|
||
"importDatabaseSuccess": "Đã nhập cơ sở dữ liệu thành công",
|
||
"importDatabaseError": "Lỗi xảy ra khi nhập cơ sở dữ liệu",
|
||
"readDatabaseError": "Lỗi xảy ra khi đọc cơ sở dữ liệu",
|
||
"getDatabaseError": "Lỗi xảy ra khi truy xuất cơ sở dữ liệu",
|
||
"getConfigError": "Lỗi xảy ra khi truy xuất tệp cấu hình"
|
||
},
|
||
"inbounds": {
|
||
"title": "Điểm vào (Inbounds)",
|
||
"totalDownUp": "Tổng tải lên/tải xuống",
|
||
"totalUsage": "Tổng sử dụng",
|
||
"inboundCount": "Số lượng điểm vào",
|
||
"operate": "Thao tác",
|
||
"enable": "Kích hoạt",
|
||
"remark": "Chú thích",
|
||
"node": "Nút",
|
||
"deployTo": "Triển khai tới",
|
||
"localPanel": "Panel cục bộ",
|
||
"fallbacks": {
|
||
"title": "Fallback",
|
||
"help": "Khi một kết nối trên inbound này không khớp với client nào, nó sẽ được chuyển hướng tới inbound khác. Chọn một child bên dưới và các trường định tuyến (SNI / ALPN / Path / xver) sẽ được tự động điền từ transport của child — hầu hết cấu hình không cần chỉnh thêm. Mỗi child nên lắng nghe trên 127.0.0.1 với security=none.",
|
||
"empty": "Chưa có fallback nào",
|
||
"add": "Thêm fallback",
|
||
"pickInbound": "Chọn một inbound",
|
||
"matchAny": "bất kỳ",
|
||
"rederive": "Điền lại từ child",
|
||
"rederived": "Đã điền lại từ child",
|
||
"editAdvanced": "Sửa trường định tuyến",
|
||
"hideAdvanced": "Ẩn nâng cao",
|
||
"quickAddAll": "Thêm nhanh tất cả các inbound đủ điều kiện",
|
||
"quickAdded": "Đã thêm {n} fallback",
|
||
"quickAddedNone": "Không có inbound mới nào đủ điều kiện",
|
||
"routesWhen": "Định tuyến khi",
|
||
"defaultCatchAll": "Mặc định — bắt mọi thứ khác"
|
||
},
|
||
"protocol": "Giao thức",
|
||
"port": "Cổng",
|
||
"portMap": "Cổng tạo",
|
||
"traffic": "Lưu lượng",
|
||
"details": "Chi tiết",
|
||
"transportConfig": "Giao vận",
|
||
"expireDate": "Ngày hết hạn",
|
||
"createdAt": "Tạo lúc",
|
||
"updatedAt": "Cập nhật",
|
||
"resetTraffic": "Đặt lại lưu lượng",
|
||
"addInbound": "Thêm điểm vào",
|
||
"generalActions": "Hành động chung",
|
||
"modifyInbound": "Chỉnh sửa điểm vào (Inbound)",
|
||
"deleteInbound": "Xóa điểm vào (Inbound)",
|
||
"deleteInboundContent": "Xác nhận xóa điểm vào? (Inbound)",
|
||
"deleteClient": "Xóa người dùng",
|
||
"deleteClientContent": "Bạn có chắc chắn muốn xóa người dùng không?",
|
||
"resetTrafficContent": "Xác nhận đặt lại lưu lượng?",
|
||
"copyLink": "Sao chép liên kết",
|
||
"address": "Địa chỉ",
|
||
"network": "Mạng",
|
||
"destinationPort": "Cổng đích",
|
||
"targetAddress": "Địa chỉ mục tiêu",
|
||
"monitorDesc": "Mặc định để trống",
|
||
"meansNoLimit": "= Không giới hạn (đơn vị: GB)",
|
||
"totalFlow": "Tổng lưu lượng",
|
||
"leaveBlankToNeverExpire": "Để trống để không bao giờ hết hạn",
|
||
"noRecommendKeepDefault": "Không yêu cầu đặc biệt để giữ nguyên cài đặt mặc định",
|
||
"certificatePath": "Đường dẫn tập",
|
||
"certificateContent": "Nội dung tập",
|
||
"publicKey": "Khóa công khai",
|
||
"privatekey": "Khóa cá nhân",
|
||
"clickOnQRcode": "Nhấn vào Mã QR để sao chép",
|
||
"client": "Người dùng",
|
||
"export": "Xuất liên kết",
|
||
"clone": "Sao chép",
|
||
"cloneInbound": "Sao chép điểm vào (Inbound)",
|
||
"cloneInboundContent": "Tất cả cài đặt của điểm vào này, trừ Cổng, IP nghe và máy khách, sẽ được áp dụng cho bản sao.",
|
||
"cloneInboundOk": "Sao chép",
|
||
"resetAllTraffic": "Đặt lại lưu lượng cho tất cả điểm vào",
|
||
"resetAllTrafficTitle": "Đặt lại lưu lượng cho tất cả điểm vào",
|
||
"resetAllTrafficContent": "Bạn có chắc chắn muốn đặt lại lưu lượng cho tất cả điểm vào không?",
|
||
"resetInboundClientTraffics": "Đặt lại lưu lượng toàn bộ người dùng của điểm vào",
|
||
"resetInboundClientTrafficTitle": "Đặt lại lưu lượng cho toàn bộ người dùng của điểm vào",
|
||
"resetInboundClientTrafficContent": "Bạn có chắc chắn muốn đặt lại tất cả lưu lượng cho các người dùng của điểm vào này không?",
|
||
"resetAllClientTraffics": "Đặt lại lưu lượng cho toàn bộ người dùng",
|
||
"resetAllClientTrafficTitle": "Đặt lại lưu lượng cho toàn bộ người dùng",
|
||
"resetAllClientTrafficContent": "Bạn có chắc chắn muốn đặt lại tất cả lưu lượng cho toàn bộ người dùng không?",
|
||
"delDepletedClients": "Xóa các người dùng đã cạn kiệt",
|
||
"delDepletedClientsTitle": "Xóa các người dùng đã cạn kiệt",
|
||
"delDepletedClientsContent": "Bạn có chắc chắn muốn xóa toàn bộ người dùng đã cạn kiệt không?",
|
||
"email": "Email",
|
||
"emailDesc": "Vui lòng cung cấp một địa chỉ email duy nhất.",
|
||
"IPLimit": "Giới hạn IP",
|
||
"IPLimitDesc": "Vô hiệu hóa điểm vào nếu số lượng vượt quá giá trị đã nhập (nhập 0 để vô hiệu hóa giới hạn IP).",
|
||
"IPLimitlog": "Lịch sử IP",
|
||
"IPLimitlogDesc": "Lịch sử đăng nhập IP (trước khi kích hoạt điểm vào sau khi bị vô hiệu hóa bởi giới hạn IP, bạn nên xóa lịch sử).",
|
||
"IPLimitlogclear": "Xóa Lịch sử",
|
||
"setDefaultCert": "Đặt chứng chỉ từ bảng điều khiển",
|
||
"streamTab": "Stream",
|
||
"securityTab": "Bảo mật",
|
||
"sniffingTab": "Sniffing",
|
||
"sniffingMetadataOnly": "Chỉ siêu dữ liệu",
|
||
"sniffingRouteOnly": "Chỉ định tuyến",
|
||
"sniffingIpsExcluded": "IP bị loại trừ",
|
||
"sniffingDomainsExcluded": "Tên miền bị loại trừ",
|
||
"decryption": "Giải mã",
|
||
"encryption": "Mã hóa",
|
||
"vlessAuthX25519": "Xác thực X25519",
|
||
"vlessAuthMlkem768": "Xác thực ML-KEM-768",
|
||
"vlessAuthCustom": "Tùy chỉnh",
|
||
"vlessAuthSelected": "Đã chọn: {auth}",
|
||
"advanced": {
|
||
"title": "Các phần JSON của inbound",
|
||
"subtitle": "JSON inbound đầy đủ và các trình chỉnh sửa riêng cho settings, sniffing và streamSettings.",
|
||
"all": "Tất cả",
|
||
"allHelp": "Đối tượng inbound đầy đủ với mọi trường trong một trình chỉnh sửa.",
|
||
"settings": "Cài đặt",
|
||
"settingsHelp": "Bao đóng khối settings của Xray:",
|
||
"sniffing": "Sniffing",
|
||
"sniffingHelp": "Bao đóng khối sniffing của Xray:",
|
||
"stream": "Stream",
|
||
"streamHelp": "Bao đóng khối stream của Xray:",
|
||
"jsonErrorPrefix": "JSON nâng cao"
|
||
},
|
||
"telegramDesc": "Vui lòng cung cấp ID Trò chuyện Telegram. (sử dụng lệnh '/id' trong bot) hoặc ({'@'}userinfobot)",
|
||
"subscriptionDesc": "Bạn có thể tìm liên kết gói đăng ký của mình trong Chi tiết, cũng như bạn có thể sử dụng cùng tên cho nhiều cấu hình khác nhau",
|
||
"info": "Thông tin",
|
||
"same": "Giống nhau",
|
||
"inboundData": "Dữ liệu gửi đến",
|
||
"exportInbound": "Xuất nhập khẩu",
|
||
"import": "Nhập",
|
||
"importInbound": "Nhập inbound",
|
||
"periodicTrafficResetTitle": "Đặt lại lưu lượng",
|
||
"periodicTrafficResetDesc": "Tự động đặt lại bộ đếm lưu lượng theo khoảng thời gian xác định",
|
||
"lastReset": "Đặt lại lần cuối",
|
||
"periodicTrafficReset": {
|
||
"never": "Không bao giờ",
|
||
"daily": "Hàng ngày",
|
||
"weekly": "Hàng tuần",
|
||
"monthly": "Hàng tháng",
|
||
"hourly": "Hàng giờ"
|
||
},
|
||
"toasts": {
|
||
"obtain": "Nhận",
|
||
"updateSuccess": "Cập nhật thành công",
|
||
"logCleanSuccess": "Đã xóa nhật ký",
|
||
"inboundsUpdateSuccess": "Đã cập nhật thành công các kết nối inbound",
|
||
"inboundUpdateSuccess": "Đã cập nhật thành công kết nối inbound",
|
||
"inboundCreateSuccess": "Đã tạo thành công kết nối inbound",
|
||
"inboundDeleteSuccess": "Đã xóa thành công kết nối inbound",
|
||
"inboundClientAddSuccess": "Đã thêm client inbound",
|
||
"inboundClientDeleteSuccess": "Đã xóa client inbound",
|
||
"inboundClientUpdateSuccess": "Đã cập nhật client inbound",
|
||
"delDepletedClientsSuccess": "Đã xóa tất cả client hết hạn",
|
||
"resetAllClientTrafficSuccess": "Đã đặt lại toàn bộ lưu lượng client",
|
||
"resetAllTrafficSuccess": "Đã đặt lại toàn bộ lưu lượng",
|
||
"resetInboundClientTrafficSuccess": "Đã đặt lại lưu lượng",
|
||
"resetInboundTrafficSuccess": "Đã đặt lại lưu lượng Inbound",
|
||
"trafficGetError": "Lỗi khi lấy thông tin lưu lượng",
|
||
"getNewX25519CertError": "Lỗi khi lấy chứng chỉ X25519.",
|
||
"getNewmldsa65Error": "Lỗi khi lấy chứng chỉ mldsa65.",
|
||
"getNewVlessEncError": "Lỗi khi lấy chứng chỉ VlessEnc."
|
||
},
|
||
"stream": {
|
||
"general": {
|
||
"request": "Lời yêu cầu",
|
||
"response": "Phản ứng",
|
||
"name": "Tên",
|
||
"value": "Giá trị"
|
||
},
|
||
"tcp": {
|
||
"version": "Phiên bản",
|
||
"method": "Phương pháp",
|
||
"path": "Đường dẫn",
|
||
"status": "Trạng thái",
|
||
"statusDescription": "Tình trạng Mô tả",
|
||
"requestHeader": "Header yêu cầu",
|
||
"responseHeader": "Header phản hồi"
|
||
}
|
||
}
|
||
},
|
||
"clients": {
|
||
"add": "Thêm khách hàng",
|
||
"edit": "Chỉnh sửa khách hàng",
|
||
"submitAdd": "Thêm khách hàng",
|
||
"submitEdit": "Lưu thay đổi",
|
||
"clientCount": "Số lượng khách hàng",
|
||
"bulk": "Thêm hàng loạt",
|
||
"copyFromInbound": "Sao chép khách hàng từ inbound",
|
||
"copyToInbound": "Sao chép khách hàng đến",
|
||
"copySelected": "Sao chép đã chọn",
|
||
"copySource": "Nguồn",
|
||
"copyEmailPreview": "Xem trước email kết quả",
|
||
"copySelectSourceFirst": "Hãy chọn inbound nguồn trước.",
|
||
"copyResult": "Kết quả sao chép",
|
||
"copyResultSuccess": "Đã sao chép thành công",
|
||
"copyResultNone": "Không có gì để sao chép: chưa chọn khách hàng hoặc nguồn rỗng",
|
||
"copyResultErrors": "Lỗi sao chép",
|
||
"copyFlowLabel": "Flow cho khách hàng mới (VLESS)",
|
||
"copyFlowHint": "Áp dụng cho tất cả khách hàng được sao chép. Để trống để bỏ qua.",
|
||
"selectAll": "Chọn tất cả",
|
||
"clearAll": "Xóa tất cả",
|
||
"method": "Phương thức",
|
||
"first": "Đầu",
|
||
"last": "Cuối",
|
||
"ipLog": "Nhật ký IP",
|
||
"prefix": "Tiền tố",
|
||
"postfix": "Hậu tố",
|
||
"delayedStart": "Bắt đầu sau lần dùng đầu",
|
||
"expireDays": "Thời hạn",
|
||
"days": "Ngày",
|
||
"renew": "Tự động gia hạn",
|
||
"renewDesc": "Tự động gia hạn sau khi hết hạn. (0 = tắt) (đơn vị: ngày)",
|
||
"title": "Khách hàng",
|
||
"actions": "Hành động",
|
||
"totalGB": "Tổng gửi/nhận (GB)",
|
||
"expiryTime": "Hết hạn",
|
||
"addClients": "Thêm khách hàng",
|
||
"limitIp": "Giới hạn IP",
|
||
"password": "Mật khẩu",
|
||
"subId": "ID đăng ký",
|
||
"online": "Trực tuyến",
|
||
"email": "Email",
|
||
"comment": "Ghi chú",
|
||
"traffic": "Lưu lượng",
|
||
"offline": "Ngoại tuyến",
|
||
"addTitle": "Thêm khách hàng",
|
||
"qrCode": "Mã QR",
|
||
"moreInformation": "Thông tin thêm",
|
||
"delete": "Xóa",
|
||
"reset": "Đặt lại lưu lượng",
|
||
"editTitle": "Chỉnh sửa khách hàng",
|
||
"client": "Khách hàng",
|
||
"enabled": "Đã bật",
|
||
"remaining": "Còn lại",
|
||
"duration": "Thời hạn",
|
||
"attachedInbounds": "Inbound đã gắn",
|
||
"selectInbound": "Chọn một hoặc nhiều inbound",
|
||
"noSubId": "Khách hàng này không có subId, không có liên kết chia sẻ.",
|
||
"noLinks": "Không có liên kết chia sẻ — hãy gắn khách hàng này vào một inbound có giao thức tương thích trước.",
|
||
"link": "Liên kết",
|
||
"resetNotPossible": "Hãy gắn khách hàng này vào một inbound trước.",
|
||
"general": "Chung",
|
||
"resetAllTraffics": "Đặt lại lưu lượng của tất cả khách hàng",
|
||
"resetAllTrafficsTitle": "Đặt lại lưu lượng của tất cả khách hàng?",
|
||
"resetAllTrafficsContent": "Bộ đếm gửi/nhận của mỗi khách hàng về 0. Hạn mức và thời hạn không bị ảnh hưởng. Không thể hoàn tác.",
|
||
"empty": "Chưa có khách hàng nào — thêm một để bắt đầu.",
|
||
"deleteConfirmTitle": "Xóa khách hàng {email}?",
|
||
"deleteConfirmContent": "Hành động này gỡ khách hàng khỏi mọi inbound đã gắn và xóa bản ghi lưu lượng. Không thể hoàn tác.",
|
||
"deleteSelected": "Xóa ({count})",
|
||
"bulkDeleteConfirmTitle": "Xóa {count} khách hàng?",
|
||
"bulkDeleteConfirmContent": "Mỗi khách hàng được chọn sẽ bị gỡ khỏi tất cả inbound đã gắn và bản ghi lưu lượng cũng bị xóa. Không thể hoàn tác.",
|
||
"delDepleted": "Xóa hết hạn mức",
|
||
"delDepletedConfirmTitle": "Xóa khách hàng hết hạn mức?",
|
||
"delDepletedConfirmContent": "Gỡ tất cả khách hàng đã dùng hết hạn mức lưu lượng hoặc đã quá hạn. Không thể hoàn tác.",
|
||
"auth": "Auth",
|
||
"hysteriaAuth": "Auth Hysteria",
|
||
"uuid": "UUID",
|
||
"flow": "Flow",
|
||
"reverseTag": "Reverse tag",
|
||
"reverseTagPlaceholder": "Reverse tag tùy chọn",
|
||
"telegramId": "ID người dùng Telegram",
|
||
"telegramIdPlaceholder": "ID người dùng Telegram dạng số (0 = không có)",
|
||
"created": "Tạo",
|
||
"updated": "Cập nhật",
|
||
"ipLimit": "Giới hạn IP",
|
||
"toasts": {
|
||
"deleted": "Đã xóa khách hàng",
|
||
"trafficReset": "Đã đặt lại lưu lượng",
|
||
"allTrafficsReset": "Đã đặt lại lưu lượng của tất cả khách hàng",
|
||
"bulkDeleted": "Đã xóa {count} khách hàng",
|
||
"bulkDeletedMixed": "Đã xóa {ok}, thất bại {failed}",
|
||
"bulkCreated": "Đã tạo {count} khách hàng",
|
||
"bulkCreatedMixed": "Đã tạo {ok}, thất bại {failed}",
|
||
"delDepleted": "Đã xóa {count} khách hàng hết hạn mức"
|
||
}
|
||
},
|
||
"nodes": {
|
||
"title": "Nút",
|
||
"addNode": "Thêm nút",
|
||
"editNode": "Chỉnh sửa nút",
|
||
"totalNodes": "Tổng số nút",
|
||
"onlineNodes": "Trực tuyến",
|
||
"offlineNodes": "Ngoại tuyến",
|
||
"avgLatency": "Độ trễ trung bình",
|
||
"name": "Tên",
|
||
"namePlaceholder": "vd: de-frankfurt-1",
|
||
"addressPlaceholder": "panel.example.com hoặc 1.2.3.4",
|
||
"remark": "Chú thích",
|
||
"scheme": "Giao thức",
|
||
"address": "Địa chỉ",
|
||
"port": "Cổng",
|
||
"basePath": "Đường dẫn cơ sở",
|
||
"apiToken": "Token API",
|
||
"apiTokenPlaceholder": "Token từ trang Cài đặt của panel từ xa",
|
||
"apiTokenHint": "Panel từ xa hiển thị token API tại Cài đặt → Token API.",
|
||
"regenerate": "Tạo lại token",
|
||
"regenerateConfirm": "Tạo lại sẽ vô hiệu hóa token hiện tại. Mọi panel trung tâm dùng nó sẽ mất quyền truy cập cho đến khi được cập nhật. Tiếp tục?",
|
||
"allowPrivateAddress": "Cho phép địa chỉ riêng",
|
||
"allowPrivateAddressHint": "Chỉ bật cho các nút trên mạng riêng hoặc VPN.",
|
||
"enable": "Kích hoạt",
|
||
"status": "Trạng thái",
|
||
"cpu": "CPU",
|
||
"mem": "Bộ nhớ",
|
||
"uptime": "Thời gian hoạt động",
|
||
"latency": "Độ trễ",
|
||
"lastHeartbeat": "Heartbeat gần nhất",
|
||
"xrayVersion": "Phiên bản Xray",
|
||
"panelVersion": "Phiên bản panel",
|
||
"actions": "Hành động",
|
||
"probe": "Kiểm tra ngay",
|
||
"testConnection": "Kiểm tra kết nối",
|
||
"connectionOk": "Kết nối OK ({ms} ms)",
|
||
"connectionFailed": "Kết nối thất bại",
|
||
"never": "chưa bao giờ",
|
||
"justNow": "vừa xong",
|
||
"deleteConfirmTitle": "Xóa nút \"{name}\"?",
|
||
"deleteConfirmContent": "Việc này dừng giám sát nút. Panel từ xa không bị ảnh hưởng.",
|
||
"statusValues": {
|
||
"online": "Trực tuyến",
|
||
"offline": "Ngoại tuyến",
|
||
"unknown": "Không xác định"
|
||
},
|
||
"toasts": {
|
||
"list": "Không tải được danh sách nút",
|
||
"obtain": "Không tải được nút",
|
||
"add": "Thêm nút",
|
||
"update": "Cập nhật nút",
|
||
"delete": "Xóa nút",
|
||
"deleted": "Đã xóa nút",
|
||
"test": "Kiểm tra kết nối",
|
||
"fillRequired": "Tên, địa chỉ, cổng và token API là bắt buộc",
|
||
"probeFailed": "Kiểm tra thất bại"
|
||
}
|
||
},
|
||
"settings": {
|
||
"title": "Cài đặt",
|
||
"save": "Lưu",
|
||
"infoDesc": "Mọi thay đổi được thực hiện ở đây cần phải được lưu. Vui lòng khởi động lại bảng điều khiển để áp dụng các thay đổi.",
|
||
"restartPanel": "Khởi động lại bảng điều khiển",
|
||
"restartPanelDesc": "Bạn có chắc chắn muốn khởi động lại bảng điều khiển? Nhấn OK để khởi động lại sau 3 giây. Nếu bạn không thể truy cập bảng điều khiển sau khi khởi động lại, vui lòng xem thông tin nhật ký của bảng điều khiển trên máy chủ.",
|
||
"restartPanelSuccess": "Đã khởi động lại bảng điều khiển thành công",
|
||
"actions": "Hành động",
|
||
"resetDefaultConfig": "Đặt lại cấu hình mặc định",
|
||
"panelSettings": "Bảng điều khiển",
|
||
"securitySettings": "Bảo mật",
|
||
"TGBotSettings": "Bot Telegram",
|
||
"panelListeningIP": "IP Nghe của bảng điều khiển",
|
||
"panelListeningIPDesc": "Mặc định để trống để nghe tất cả các IP.",
|
||
"panelListeningDomain": "Tên miền của nghe bảng điều khiển",
|
||
"panelListeningDomainDesc": "Mặc định để trống để nghe tất cả các tên miền và IP",
|
||
"panelPort": "Cổng bảng điều khiển",
|
||
"panelPortDesc": "Cổng được sử dụng để kết nối với bảng điều khiển này",
|
||
"publicKeyPath": "Đường dẫn file chứng chỉ bảng điều khiển",
|
||
"publicKeyPathDesc": "Điền vào đường dẫn đầy đủ (bắt đầu từ '/')",
|
||
"privateKeyPath": "Đường dẫn file khóa của chứng chỉ bảng điều khiển",
|
||
"privateKeyPathDesc": "Điền vào đường dẫn đầy đủ (bắt đầu từ '/')",
|
||
"panelUrlPath": "Đường dẫn gốc URL bảng điều khiển",
|
||
"panelUrlPathDesc": "Phải bắt đầu và kết thúc bằng '/'",
|
||
"pageSize": "Kích thước phân trang",
|
||
"pageSizeDesc": "Xác định kích thước trang cho bảng gửi đến. Đặt 0 để tắt",
|
||
"remarkModel": "Ghi chú mô hình và ký tự phân tách",
|
||
"datepicker": "Kiểu lịch",
|
||
"datepickerPlaceholder": "Chọn ngày",
|
||
"datepickerDescription": "Tác vụ chạy theo lịch trình sẽ chạy theo kiểu lịch này.",
|
||
"sampleRemark": "Nhận xét mẫu",
|
||
"oldUsername": "Tên người dùng hiện tại",
|
||
"currentPassword": "Mật khẩu hiện tại",
|
||
"newUsername": "Tên người dùng mới",
|
||
"newPassword": "Mật khẩu mới",
|
||
"telegramBotEnable": "Bật Bot Telegram",
|
||
"telegramBotEnableDesc": "Kết nối với các tính năng của bảng điều khiển này thông qua bot Telegram",
|
||
"telegramToken": "Token Telegram",
|
||
"telegramTokenDesc": "Bạn phải nhận token từ quản lý bot Telegram {'@'}botfather",
|
||
"telegramProxy": "Socks5 Proxy",
|
||
"telegramProxyDesc": "Nếu bạn cần socks5 proxy để kết nối với Telegram. Điều chỉnh cài đặt của nó theo hướng dẫn.",
|
||
"telegramAPIServer": "Telegram API Server",
|
||
"telegramAPIServerDesc": "Máy chủ API Telegram để sử dụng. Để trống để sử dụng máy chủ mặc định.",
|
||
"telegramChatId": "Chat ID Telegram của quản trị viên",
|
||
"telegramChatIdDesc": "Nhiều Chat ID phân tách bằng dấu phẩy. Sử dụng {'@'}userinfobot hoặc sử dụng lệnh '/id' trong bot để lấy Chat ID của bạn.",
|
||
"telegramNotifyTime": "Thời gian thông báo của bot Telegram",
|
||
"telegramNotifyTimeDesc": "Sử dụng định dạng thời gian Crontab.",
|
||
"tgNotifyBackup": "Sao lưu Cơ sở dữ liệu",
|
||
"tgNotifyBackupDesc": "Bao gồm tệp sao lưu cơ sở dữ liệu với thông báo báo cáo.",
|
||
"tgNotifyLogin": "Thông báo Đăng nhập",
|
||
"tgNotifyLoginDesc": "Hiển thị tên người dùng, địa chỉ IP và thời gian khi ai đó cố gắng đăng nhập vào bảng điều khiển của bạn.",
|
||
"sessionMaxAge": "Thời gian tối đa của phiên",
|
||
"sessionMaxAgeDesc": "Thời gian của phiên đăng nhập (đơn vị: phút)",
|
||
"expireTimeDiff": "Ngưỡng hết hạn cho thông báo",
|
||
"expireTimeDiffDesc": "Nhận thông báo về việc hết hạn tài khoản trước ngưỡng này (đơn vị: ngày)",
|
||
"trafficDiff": "Ngưỡng lưu lượng cho thông báo",
|
||
"trafficDiffDesc": "Nhận thông báo về việc cạn kiệt lưu lượng trước khi đạt đến ngưỡng này (đơn vị: GB)",
|
||
"tgNotifyCpu": "Ngưỡng cảnh báo tỷ lệ CPU",
|
||
"tgNotifyCpuDesc": "Nhận thông báo nếu tỷ lệ sử dụng CPU vượt quá ngưỡng này (đơn vị: %)",
|
||
"timeZone": "Múi giờ",
|
||
"timeZoneDesc": "Các tác vụ được lên lịch chạy theo thời gian trong múi giờ này.",
|
||
"subSettings": "Gói đăng ký",
|
||
"subEnable": "Bật dịch vụ",
|
||
"subEnableDesc": "Tính năng gói đăng ký với cấu hình riêng",
|
||
"subJsonEnable": "Bật/Tắt điểm cuối đăng ký JSON độc lập.",
|
||
"subTitle": "Tiêu đề Đăng ký",
|
||
"subTitleDesc": "Tiêu đề hiển thị trong ứng dụng VPN",
|
||
"subSupportUrl": "URL Hỗ trợ",
|
||
"subSupportUrlDesc": "Liên kết hỗ trợ kỹ thuật hiển thị trong ứng dụng VPN",
|
||
"subProfileUrl": "URL Hồ sơ",
|
||
"subProfileUrlDesc": "Liên kết đến trang web của bạn hiển thị trong ứng dụng VPN",
|
||
"subAnnounce": "Thông báo",
|
||
"subAnnounceDesc": "Văn bản thông báo hiển thị trong ứng dụng VPN",
|
||
"subEnableRouting": "Bật định tuyến",
|
||
"subEnableRoutingDesc": "Cài đặt toàn cục để bật định tuyến trong ứng dụng khách VPN. (Chỉ dành cho Happ)",
|
||
"subRoutingRules": "Quy tắc định tuyến",
|
||
"subRoutingRulesDesc": "Quy tắc định tuyến toàn cầu cho client VPN. (Chỉ dành cho Happ)",
|
||
"subListen": "Listening IP",
|
||
"subListenDesc": "Mặc định để trống để nghe tất cả các IP",
|
||
"subPort": "Cổng gói đăng ký",
|
||
"subPortDesc": "Số cổng dịch vụ đăng ký phải chưa được sử dụng trên máy chủ",
|
||
"subCertPath": "Đường dẫn file chứng chỉ gói đăng ký",
|
||
"subCertPathDesc": "Điền vào đường dẫn đầy đủ (bắt đầu với '/')",
|
||
"subKeyPath": "Đường dẫn file khóa của chứng chỉ gói đăng ký",
|
||
"subKeyPathDesc": "Điền vào đường dẫn đầy đủ (bắt đầu với '/')",
|
||
"subPath": "Đường dẫn gốc URL gói đăng ký",
|
||
"subPathDesc": "Phải bắt đầu và kết thúc bằng '/'",
|
||
"subDomain": "Tên miền con",
|
||
"subDomainDesc": "Mặc định để trống để nghe tất cả các tên miền và IP",
|
||
"subUpdates": "Khoảng thời gian cập nhật gói đăng ký",
|
||
"subUpdatesDesc": "Số giờ giữa các cập nhật trong ứng dụng khách",
|
||
"subEncrypt": "Mã hóa cấu hình",
|
||
"subEncryptDesc": "Mã hóa các cấu hình được trả về trong gói đăng ký",
|
||
"subShowInfo": "Hiển thị thông tin sử dụng",
|
||
"subShowInfoDesc": "Hiển thị lưu lượng truy cập còn lại và ngày sau tên cấu hình",
|
||
"subEmailInRemark": "Thêm Email vào tên",
|
||
"subEmailInRemarkDesc": "Thêm email của client vào tên hồ sơ đăng ký.",
|
||
"subURI": "URI proxy trung gian",
|
||
"subURIDesc": "Thay đổi URI cơ sở của URL gói đăng ký để sử dụng cho proxy trung gian",
|
||
"externalTrafficInformEnable": "Thông báo giao thông bên ngoài",
|
||
"externalTrafficInformEnableDesc": "Thông báo cho API bên ngoài về mọi cập nhật lưu lượng truy cập.",
|
||
"externalTrafficInformURI": "URI thông báo lưu lượng truy cập bên ngoài",
|
||
"externalTrafficInformURIDesc": "Cập nhật lưu lượng truy cập được gửi tới URI này.",
|
||
"restartXrayOnClientDisable": "Khởi Động Lại Xray Sau Khi Tự Động Vô Hiệu Hóa",
|
||
"restartXrayOnClientDisableDesc": "Khi người dùng bị vô hiệu hóa tự động do hết hạn hoặc chạm giới hạn lưu lượng, hãy khởi động lại Xray.",
|
||
"fragment": "Sự phân mảnh",
|
||
"fragmentDesc": "Kích hoạt phân mảnh cho gói TLS hello",
|
||
"fragmentSett": "Cài đặt phân mảnh",
|
||
"noisesDesc": "Bật Noises.",
|
||
"noisesSett": "Cài đặt Noises",
|
||
"mux": "Mux",
|
||
"muxDesc": "Truyền nhiều luồng dữ liệu độc lập trong luồng dữ liệu đã thiết lập.",
|
||
"muxSett": "Mux Cài đặt",
|
||
"direct": "Kết nối trực tiếp",
|
||
"directDesc": "Trực tiếp thiết lập kết nối với tên miền hoặc dải IP của một quốc gia cụ thể.",
|
||
"notifications": "Thông báo",
|
||
"certs": "Chứng chỉ",
|
||
"externalTraffic": "Lưu lượng bên ngoài",
|
||
"dateAndTime": "Ngày và giờ",
|
||
"proxyAndServer": "Proxy và máy chủ",
|
||
"intervals": "Khoảng thời gian",
|
||
"information": "Thông tin",
|
||
"language": "Ngôn ngữ",
|
||
"telegramBotLanguage": "Ngôn ngữ của Bot Telegram",
|
||
"security": {
|
||
"admin": "Thông tin đăng nhập quản trị viên",
|
||
"twoFactor": "Xác thực hai yếu tố",
|
||
"twoFactorEnable": "Bật 2FA",
|
||
"twoFactorEnableDesc": "Thêm một lớp bảo mật bổ sung để tăng cường an toàn.",
|
||
"twoFactorModalSetTitle": "Bật xác thực hai yếu tố",
|
||
"twoFactorModalDeleteTitle": "Tắt xác thực hai yếu tố",
|
||
"twoFactorModalSteps": "Để thiết lập xác thực hai yếu tố, hãy thực hiện các bước sau:",
|
||
"twoFactorModalFirstStep": "1. Quét mã QR này trong ứng dụng xác thực hoặc sao chép mã token gần mã QR và dán vào ứng dụng",
|
||
"twoFactorModalSecondStep": "2. Nhập mã từ ứng dụng",
|
||
"twoFactorModalRemoveStep": "Nhập mã từ ứng dụng để xóa xác thực hai yếu tố.",
|
||
"twoFactorModalChangeCredentialsTitle": "Thay đổi thông tin xác thực",
|
||
"twoFactorModalChangeCredentialsStep": "Nhập mã từ ứng dụng để thay đổi thông tin xác thực quản trị viên.",
|
||
"twoFactorModalSetSuccess": "Xác thực hai yếu tố đã được thiết lập thành công",
|
||
"twoFactorModalDeleteSuccess": "Xác thực hai yếu tố đã được xóa thành công",
|
||
"twoFactorModalError": "Mã sai",
|
||
"show": "Hiển thị",
|
||
"hide": "Ẩn",
|
||
"apiTokenNew": "Token mới",
|
||
"apiTokenName": "Tên",
|
||
"apiTokenNamePlaceholder": "ví dụ: central-panel-a",
|
||
"apiTokenNameRequired": "Tên là bắt buộc",
|
||
"apiTokenEmpty": "Chưa có token nào — tạo một token để xác thực bot hoặc panel từ xa.",
|
||
"apiTokenDeleteWarning": "Mọi client đang dùng token này sẽ ngừng xác thực ngay lập tức."
|
||
},
|
||
"toasts": {
|
||
"modifySettings": "Các tham số đã được thay đổi.",
|
||
"getSettings": "Lỗi xảy ra khi truy xuất tham số.",
|
||
"modifyUserError": "Đã xảy ra lỗi khi thay đổi thông tin đăng nhập quản trị viên.",
|
||
"modifyUser": "Bạn đã thay đổi thông tin đăng nhập quản trị viên thành công.",
|
||
"originalUserPassIncorrect": "Tên người dùng hoặc mật khẩu gốc không đúng",
|
||
"userPassMustBeNotEmpty": "Tên người dùng mới và mật khẩu mới không thể để trống",
|
||
"getOutboundTrafficError": "Lỗi khi lấy lưu lượng truy cập đi",
|
||
"resetOutboundTrafficError": "Lỗi khi đặt lại lưu lượng truy cập đi"
|
||
}
|
||
},
|
||
"xray": {
|
||
"title": "Cài đặt Xray",
|
||
"save": "Lưu cài đặt",
|
||
"restart": "Khởi động lại Xray",
|
||
"restartSuccess": "Đã khởi động lại Xray thành công",
|
||
"stopSuccess": "Xray đã được dừng thành công",
|
||
"restartError": "Đã xảy ra lỗi khi khởi động lại Xray.",
|
||
"stopError": "Đã xảy ra lỗi khi dừng Xray.",
|
||
"basicTemplate": "Mẫu Cơ bản",
|
||
"advancedTemplate": "Mẫu Nâng cao",
|
||
"generalConfigs": "Cấu hình Chung",
|
||
"generalConfigsDesc": "Những tùy chọn này sẽ cung cấp điều chỉnh tổng quát.",
|
||
"logConfigs": "Nhật ký",
|
||
"logConfigsDesc": "Nhật ký có thể ảnh hưởng đến hiệu suất máy chủ của bạn. Bạn chỉ nên kích hoạt nó một cách khôn ngoan trong trường hợp bạn cần",
|
||
"blockConfigsDesc": "Những tùy chọn này sẽ ngăn người dùng kết nối đến các giao thức và trang web cụ thể.",
|
||
"basicRouting": "Định tuyến Cơ bản",
|
||
"blockConnectionsConfigsDesc": "Các tùy chọn này sẽ chặn lưu lượng truy cập dựa trên quốc gia được yêu cầu cụ thể.",
|
||
"directConnectionsConfigsDesc": "Kết nối trực tiếp đảm bảo rằng lưu lượng truy cập cụ thể không được định tuyến qua máy chủ khác.",
|
||
"blockips": "Chặn IP",
|
||
"blockdomains": "Chặn Tên Miền",
|
||
"directips": "IP Trực Tiếp",
|
||
"directdomains": "Tên Miền Trực Tiếp",
|
||
"ipv4Routing": "Định tuyến IPv4",
|
||
"ipv4RoutingDesc": "Những tùy chọn này sẽ chỉ định kết nối đến các tên miền mục tiêu qua IPv4.",
|
||
"warpRouting": "Định tuyến WARP",
|
||
"warpRoutingDesc": "Cảnh báo: Trước khi sử dụng những tùy chọn này, hãy cài đặt WARP ở chế độ proxy socks5 trên máy chủ của bạn bằng cách làm theo các bước trên GitHub của bảng điều khiển. WARP sẽ định tuyến lưu lượng đến các trang web qua máy chủ Cloudflare.",
|
||
"nordRouting": "Định tuyến NordVPN",
|
||
"nordRoutingDesc": "Các tùy chọn này sẽ định tuyến lưu lượng dựa trên đích cụ thể qua NordVPN.",
|
||
"Template": "Mẫu Cấu hình Xray",
|
||
"TemplateDesc": "Tạo tệp cấu hình Xray cuối cùng dựa trên mẫu này.",
|
||
"FreedomStrategy": "Cấu hình Chiến lược cho Giao thức Freedom",
|
||
"FreedomStrategyDesc": "Đặt chiến lược đầu ra của mạng trong Giao thức Freedom.",
|
||
"RoutingStrategy": "Cấu hình Chiến lược Định tuyến Tên miền",
|
||
"RoutingStrategyDesc": "Đặt chiến lược định tuyến tổng thể cho việc giải quyết DNS.",
|
||
"outboundTestUrl": "URL kiểm tra outbound",
|
||
"outboundTestUrlDesc": "URL dùng khi kiểm tra kết nối outbound",
|
||
"Torrent": "Cấu hình sử dụng BitTorrent",
|
||
"Inbounds": "Đầu vào",
|
||
"InboundsDesc": "Thay đổi mẫu cấu hình để chấp nhận các máy khách cụ thể.",
|
||
"Outbounds": "Đầu ra",
|
||
"Balancers": "Cân bằng",
|
||
"OutboundsDesc": "Thay đổi mẫu cấu hình để xác định các cách ra đi cho máy chủ này.",
|
||
"Routings": "Quy tắc định tuyến",
|
||
"RoutingsDesc": "Mức độ ưu tiên của mỗi quy tắc đều quan trọng!",
|
||
"completeTemplate": "All",
|
||
"logLevel": "Mức đăng nhập",
|
||
"logLevelDesc": "Cấp độ nhật ký cho nhật ký lỗi, cho biết thông tin cần được ghi lại.",
|
||
"accessLog": "Nhật ký truy cập",
|
||
"accessLogDesc": "Đường dẫn tệp cho nhật ký truy cập. Nhật ký truy cập bị vô hiệu hóa có giá trị đặc biệt 'không'",
|
||
"errorLog": "Nhật ký lỗi",
|
||
"errorLogDesc": "Đường dẫn tệp cho nhật ký lỗi. Nhật ký lỗi bị vô hiệu hóa có giá trị đặc biệt 'không'",
|
||
"dnsLog": "Nhật ký DNS",
|
||
"dnsLogDesc": "Có bật nhật ký truy vấn DNS không",
|
||
"maskAddress": "Ẩn Địa Chỉ",
|
||
"maskAddressDesc": "Mặt nạ địa chỉ IP, khi được bật, sẽ tự động thay thế địa chỉ IP xuất hiện trong nhật ký.",
|
||
"statistics": "Thống kê",
|
||
"statsInboundUplink": "Thống kê tải lên đầu vào",
|
||
"statsInboundUplinkDesc": "Kích hoạt thu thập thống kê cho lưu lượng tải lên của tất cả các proxy đầu vào.",
|
||
"statsInboundDownlink": "Thống kê tải xuống đầu vào",
|
||
"statsInboundDownlinkDesc": "Kích hoạt thu thập thống kê cho lưu lượng tải xuống của tất cả các proxy đầu vào.",
|
||
"statsOutboundUplink": "Thống kê tải lên đầu ra",
|
||
"statsOutboundUplinkDesc": "Kích hoạt thu thập thống kê cho lưu lượng tải lên của tất cả các proxy đầu ra.",
|
||
"statsOutboundDownlink": "Thống kê tải xuống đầu ra",
|
||
"statsOutboundDownlinkDesc": "Kích hoạt thu thập thống kê cho lưu lượng tải xuống của tất cả các proxy đầu ra.",
|
||
"rules": {
|
||
"first": "Đầu tiên",
|
||
"last": "Cuối cùng",
|
||
"up": "Lên",
|
||
"down": "Xuống",
|
||
"source": "Nguồn",
|
||
"dest": "Đích",
|
||
"inbound": "Vào",
|
||
"outbound": "Ra",
|
||
"balancer": "Cân bằng",
|
||
"info": "Thông tin",
|
||
"add": "Thêm quy tắc",
|
||
"edit": "Chỉnh sửa quy tắc",
|
||
"useComma": "Các mục được phân tách bằng dấu phẩy"
|
||
},
|
||
"outbound": {
|
||
"addOutbound": "Thêm thư đi",
|
||
"addReverse": "Thêm đảo ngược",
|
||
"editOutbound": "Chỉnh sửa gửi đi",
|
||
"editReverse": "Chỉnh sửa ngược lại",
|
||
"reverseTag": "Thẻ Ngược",
|
||
"reverseTagDesc": "Thẻ outbound của proxy ngược đơn giản VLESS. Để trống để vô hiệu hóa.",
|
||
"reverseTagPlaceholder": "thẻ outbound (để trống để vô hiệu hóa)",
|
||
"tag": "Thẻ",
|
||
"tagDesc": "thẻ duy nhất",
|
||
"address": "Địa chỉ",
|
||
"reverse": "Đảo ngược",
|
||
"domain": "Miền",
|
||
"type": "Loại",
|
||
"bridge": "Cầu",
|
||
"portal": "Cổng thông tin",
|
||
"link": "Liên kết",
|
||
"intercon": "Kết nối",
|
||
"settings": "cài đặt",
|
||
"accountInfo": "Thông tin tài khoản",
|
||
"outboundStatus": "Trạng thái đầu ra",
|
||
"sendThrough": "Gửi qua",
|
||
"test": "Kiểm tra",
|
||
"testResult": "Kết quả kiểm tra",
|
||
"testing": "Đang kiểm tra kết nối...",
|
||
"testSuccess": "Kiểm tra thành công",
|
||
"testFailed": "Kiểm tra thất bại",
|
||
"testError": "Không thể kiểm tra đầu ra",
|
||
"nordvpn": "NordVPN",
|
||
"accessToken": "Mã truy cập",
|
||
"country": "Quốc gia",
|
||
"server": "Máy chủ",
|
||
"city": "Thành phố",
|
||
"allCities": "Tất cả thành phố",
|
||
"privateKey": "Khóa riêng",
|
||
"load": "Tải"
|
||
},
|
||
"balancer": {
|
||
"addBalancer": "Thêm cân bằng",
|
||
"editBalancer": "Chỉnh sửa cân bằng",
|
||
"balancerStrategy": "Chiến lược",
|
||
"balancerSelectors": "Bộ chọn",
|
||
"tag": "Thẻ",
|
||
"tagDesc": "thẻ duy nhất",
|
||
"balancerDesc": "Không thể sử dụng balancerTag và outboundTag cùng một lúc. Nếu sử dụng cùng lúc thì chỉ outboundTag mới hoạt động."
|
||
},
|
||
"wireguard": {
|
||
"secretKey": "Khoá bí mật",
|
||
"publicKey": "Khóa công khai",
|
||
"allowedIPs": "IP được phép",
|
||
"endpoint": "Điểm cuối",
|
||
"psk": "Khóa chia sẻ",
|
||
"domainStrategy": "Chiến lược tên miền"
|
||
},
|
||
"tun": {
|
||
"nameDesc": "Tên của giao diện TUN. Giá trị mặc định là 'xray0'",
|
||
"mtuDesc": "Đơn vị Truyền Tối đa. Kích thước tối đa của các gói dữ liệu. Giá trị mặc định là 1500",
|
||
"userLevel": "Mức Người Dùng",
|
||
"userLevelDesc": "Tất cả các kết nối được thực hiện thông qua inbound này sẽ sử dụng mức người dùng này. Giá trị mặc định là 0"
|
||
},
|
||
"dns": {
|
||
"enable": "Kích hoạt DNS",
|
||
"enableDesc": "Kích hoạt máy chủ DNS tích hợp",
|
||
"tag": "Thẻ gửi đến DNS",
|
||
"tagDesc": "Thẻ này sẽ có sẵn dưới dạng thẻ Gửi đến trong quy tắc định tuyến.",
|
||
"clientIp": "IP khách hàng",
|
||
"clientIpDesc": "Được sử dụng để thông báo cho máy chủ về vị trí IP được chỉ định trong các truy vấn DNS",
|
||
"disableCache": "Tắt bộ nhớ đệm",
|
||
"disableCacheDesc": "Tắt bộ nhớ đệm DNS",
|
||
"disableFallback": "Tắt Fallback",
|
||
"disableFallbackDesc": "Tắt các truy vấn DNS Fallback",
|
||
"disableFallbackIfMatch": "Tắt Fallback Nếu Khớp",
|
||
"disableFallbackIfMatchDesc": "Tắt các truy vấn DNS Fallback khi danh sách tên miền khớp của máy chủ DNS được kích hoạt",
|
||
"enableParallelQuery": "Bật Truy vấn Song song",
|
||
"enableParallelQueryDesc": "Bật truy vấn DNS song song đến nhiều máy chủ để phân giải nhanh hơn",
|
||
"strategy": "Chiến lược truy vấn",
|
||
"strategyDesc": "Chiến lược tổng thể để phân giải tên miền",
|
||
"add": "Thêm máy chủ",
|
||
"edit": "Chỉnh sửa máy chủ",
|
||
"domains": "Tên miền",
|
||
"expectIPs": "Các IP Dự Kiến",
|
||
"unexpectIPs": "IP không mong muốn",
|
||
"useSystemHosts": "Sử dụng Hosts hệ thống",
|
||
"useSystemHostsDesc": "Sử dụng file hosts từ hệ thống đã cài đặt",
|
||
"serveStale": "Phục vụ kết quả hết hạn",
|
||
"serveStaleDesc": "Trả về kết quả cache đã hết hạn trong khi làm mới ở chế độ nền",
|
||
"serveExpiredTTL": "TTL hết hạn",
|
||
"serveExpiredTTLDesc": "Thời gian hiệu lực (giây) của các mục cache hết hạn; 0 = không bao giờ hết hạn",
|
||
"timeoutMs": "Thời gian chờ (ms)",
|
||
"skipFallback": "Bỏ qua Fallback",
|
||
"finalQuery": "Truy vấn cuối",
|
||
"hosts": "Hosts",
|
||
"hostsAdd": "Thêm Host",
|
||
"hostsEmpty": "Chưa có Host nào",
|
||
"hostsDomain": "Tên miền (vd. domain:example.com)",
|
||
"hostsValues": "IP hoặc tên miền — nhập và nhấn Enter",
|
||
"usePreset": "Dùng mẫu",
|
||
"dnsPresetTitle": "Mẫu DNS",
|
||
"dnsPresetFamily": "Gia đình",
|
||
"clearAll": "Xóa tất cả",
|
||
"clearAllTitle": "Xóa tất cả máy chủ DNS?",
|
||
"clearAllConfirm": "Thao tác này sẽ xóa toàn bộ máy chủ DNS khỏi danh sách. Không thể hoàn tác."
|
||
},
|
||
"fakedns": {
|
||
"add": "Thêm DNS giả",
|
||
"edit": "Chỉnh sửa DNS giả",
|
||
"ipPool": "Mạng con nhóm IP",
|
||
"poolSize": "Kích thước bể bơi"
|
||
}
|
||
}
|
||
},
|
||
"tgbot": {
|
||
"keyboardClosed": "❌ Bàn phím đã đóng!",
|
||
"noResult": "❗ Không có kết quả!",
|
||
"noQuery": "❌ Không tìm thấy truy vấn! Vui lòng sử dụng lại lệnh!",
|
||
"wentWrong": "❌ Đã xảy ra lỗi!",
|
||
"noIpRecord": "❗ Không có bản ghi IP!",
|
||
"noInbounds": "❗ Không tìm thấy inbound!",
|
||
"unlimited": "♾ Không giới hạn (Đặt lại)",
|
||
"add": "Thêm",
|
||
"month": "Tháng",
|
||
"months": "Tháng",
|
||
"day": "Ngày",
|
||
"days": "Ngày",
|
||
"hours": "Giờ",
|
||
"minutes": "Phút",
|
||
"unknown": "Không xác định",
|
||
"inbounds": "Inbound",
|
||
"clients": "Client",
|
||
"offline": "🔴 Ngoại tuyến",
|
||
"online": "🟢 Trực tuyến",
|
||
"commands": {
|
||
"unknown": "❗ Lệnh không rõ",
|
||
"pleaseChoose": "👇 Vui lòng chọn:\r\n",
|
||
"help": "🤖 Chào mừng bạn đến với bot này! Bot được thiết kế để cung cấp cho bạn dữ liệu cụ thể từ máy chủ và cho phép bạn thực hiện các thay đổi cần thiết.\r\n\r\n",
|
||
"start": "👋 Xin chào <i>{{ .Firstname }}</i>.\r\n",
|
||
"welcome": "🤖 Chào mừng đến với bot quản lý của <b>{{ .Hostname }}</b>.\r\n",
|
||
"status": "✅ Bot hoạt động bình thường!",
|
||
"usage": "❗ Vui lòng cung cấp văn bản để tìm kiếm!",
|
||
"getID": "🆔 ID của bạn: <code>{{ .ID }}</code>",
|
||
"helpAdminCommands": "Để khởi động lại Xray Core:\r\n<code>/restart</code>\r\n\r\nĐể tìm kiếm email của khách hàng:\r\n<code>/usage [Email]</code>\r\n\r\nĐể tìm kiếm các nhập (với số liệu thống kê của khách hàng):\r\n<code>/inbound [Ghi chú]</code>\r\n\r\nID Trò chuyện Telegram:\r\n<code>/id</code>",
|
||
"helpClientCommands": "Để tìm kiếm thống kê, sử dụng lệnh sau:\r\n<code>/usage [Email]</code>\r\n\r\nID Trò chuyện Telegram:\r\n<code>/id</code>",
|
||
"restartUsage": "\r\n\r\n<code>/restart</code>",
|
||
"restartSuccess": "✅ Hoạt động thành công!",
|
||
"restartFailed": "❗ Lỗi trong quá trình hoạt động.\r\n\r\n<code>Lỗi: {{ .Error }}</code>.",
|
||
"xrayNotRunning": "❗ Xray Core không chạy.",
|
||
"startDesc": "Hiển thị menu chính",
|
||
"helpDesc": "Trợ giúp bot",
|
||
"statusDesc": "Kiểm tra trạng thái bot",
|
||
"idDesc": "Hiển thị ID Telegram của bạn"
|
||
},
|
||
"messages": {
|
||
"cpuThreshold": "🔴 Sử dụng CPU {{ .Percent }}% vượt quá ngưỡng {{ .Threshold }}%",
|
||
"selectUserFailed": "❌ Lỗi khi chọn người dùng!",
|
||
"userSaved": "✅ Người dùng Telegram đã được lưu.",
|
||
"loginSuccess": "✅ Đăng nhập thành công vào bảng điều khiển.\r\n",
|
||
"loginFailed": "❗️ Đăng nhập vào bảng điều khiển thất bại.\r\n",
|
||
"2faFailed": "Lỗi 2FA",
|
||
"report": "🕰 Báo cáo định kỳ: {{ .RunTime }}\r\n",
|
||
"datetime": "⏰ Ngày-Giờ: {{ .DateTime }}\r\n",
|
||
"hostname": "💻 Tên máy chủ: {{ .Hostname }}\r\n",
|
||
"version": "🚀 Phiên bản X-UI: {{ .Version }}\r\n",
|
||
"xrayVersion": "📡 Phiên bản Xray: {{ .XrayVersion }}\r\n",
|
||
"ipv6": "🌐 IPv6: {{ .IPv6 }}\r\n",
|
||
"ipv4": "🌐 IPv4: {{ .IPv4 }}\r\n",
|
||
"ip": "🌐 IP: {{ .IP }}\r\n",
|
||
"ips": "🔢 Các IP:\r\n{{ .IPs }}\r\n",
|
||
"serverUpTime": "⏳ Thời gian hoạt động của máy chủ: {{ .UpTime }} {{ .Unit }}\r\n",
|
||
"serverLoad": "📈 Tải máy chủ: {{ .Load1 }}, {{ .Load2 }}, {{ .Load3 }}\r\n",
|
||
"serverMemory": "📋 Bộ nhớ máy chủ: {{ .Current }}/{{ .Total }}\r\n",
|
||
"tcpCount": "🔹 Số lượng kết nối TCP: {{ .Count }}\r\n",
|
||
"udpCount": "🔸 Số lượng kết nối UDP: {{ .Count }}\r\n",
|
||
"traffic": "🚦 Lưu lượng: {{ .Total }} (↑{{ .Upload }},↓{{ .Download }})\r\n",
|
||
"xrayStatus": "ℹ️ Trạng thái Xray: {{ .State }}\r\n",
|
||
"username": "👤 Tên người dùng: {{ .Username }}\r\n",
|
||
"reason": "❗️ Lý do: {{ .Reason }}\r\n",
|
||
"time": "⏰ Thời gian: {{ .Time }}\r\n",
|
||
"inbound": "📍 Inbound: {{ .Remark }}\r\n",
|
||
"port": "🔌 Cổng: {{ .Port }}\r\n",
|
||
"expire": "📅 Ngày hết hạn: {{ .Time }}\r\n",
|
||
"expireIn": "📅 Hết hạn sau: {{ .Time }}\r\n",
|
||
"active": "💡 Đang hoạt động: {{ .Enable }}\r\n",
|
||
"enabled": "🚨 Đã bật: {{ .Enable }}\r\n",
|
||
"online": "🌐 Trạng thái kết nối: {{ .Status }}\r\n",
|
||
"lastOnline": "🔙 Lần online gần nhất: {{ .Time }}\r\n",
|
||
"email": "📧 Email: {{ .Email }}\r\n",
|
||
"upload": "🔼 Tải lên: ↑{{ .Upload }}\r\n",
|
||
"download": "🔽 Tải xuống: ↓{{ .Download }}\r\n",
|
||
"total": "📊 Tổng cộng: ↑↓{{ .UpDown }} / {{ .Total }}\r\n",
|
||
"TGUser": "👤 Người dùng Telegram: {{ .TelegramID }}\r\n",
|
||
"exhaustedMsg": "🚨 Sự cạn kiệt {{ .Type }}:\r\n",
|
||
"exhaustedCount": "🚨 Số lần cạn kiệt {{ .Type }}:\r\n",
|
||
"onlinesCount": "🌐 Khách hàng trực tuyến: {{ .Count }}\r\n",
|
||
"disabled": "🛑 Vô hiệu hóa: {{ .Disabled }}\r\n",
|
||
"depleteSoon": "🔜 Sắp cạn kiệt: {{ .Deplete }}\r\n\r\n",
|
||
"backupTime": "🗄 Thời gian sao lưu: {{ .Time }}\r\n",
|
||
"refreshedOn": "\r\n📋🔄 Đã cập nhật lần cuối vào: {{ .Time }}\r\n\r\n",
|
||
"yes": "✅ Có",
|
||
"no": "❌ Không",
|
||
"received_id": "🔑📥 ID đã được cập nhật.",
|
||
"received_password": "🔑📥 Mật khẩu đã được cập nhật.",
|
||
"received_email": "📧📥 Email đã được cập nhật.",
|
||
"received_comment": "💬📥 Bình luận đã được cập nhật.",
|
||
"id_prompt": "🔑 ID mặc định: {{ .ClientId }}\n\nVui lòng nhập ID của bạn.",
|
||
"pass_prompt": "🔑 Mật khẩu mặc định: {{ .ClientPassword }}\n\nVui lòng nhập mật khẩu của bạn.",
|
||
"email_prompt": "📧 Email mặc định: {{ .ClientEmail }}\n\nVui lòng nhập email của bạn.",
|
||
"comment_prompt": "💬 Bình luận mặc định: {{ .ClientComment }}\n\nVui lòng nhập bình luận của bạn.",
|
||
"inbound_client_data_id": "🔄 Kết nối vào: {{ .InboundRemark }}\n\n🔑 ID: {{ .ClientId }}\n📧 Email: {{ .ClientEmail }}\n📊 Dung lượng: {{ .ClientTraffic }}\n📅 Ngày hết hạn: {{ .ClientExp }}\n🌐 Giới hạn IP: {{ .IpLimit }}\n💬 Ghi chú: {{ .ClientComment }}\n\nBây giờ bạn có thể thêm khách hàng vào inbound!",
|
||
"inbound_client_data_pass": "🔄 Kết nối vào: {{ .InboundRemark }}\n\n🔑 Mật khẩu: {{ .ClientPass }}\n📧 Email: {{ .ClientEmail }}\n📊 Dung lượng: {{ .ClientTraffic }}\n📅 Ngày hết hạn: {{ .ClientExp }}\n🌐 Giới hạn IP: {{ .IpLimit }}\n💬 Ghi chú: {{ .ClientComment }}\n\nBây giờ bạn có thể thêm khách hàng vào inbound!",
|
||
"cancel": "❌ Quá trình đã bị hủy! \n\nBạn có thể bắt đầu lại bất cứ lúc nào bằng cách nhập /start. 🔄",
|
||
"error_add_client": "⚠️ Lỗi:\n\n {{ .error }}",
|
||
"using_default_value": "Được rồi, tôi sẽ sử dụng giá trị mặc định. 😊",
|
||
"incorrect_input": "Dữ liệu bạn nhập không hợp lệ.\nCác chuỗi phải liền mạch và không có dấu cách.\nVí dụ đúng: aaaaaa\nVí dụ sai: aaa aaa 🚫",
|
||
"AreYouSure": "Bạn có chắc không? 🤔",
|
||
"SuccessResetTraffic": "📧 Email: {{ .ClientEmail }}\n🏁 Kết quả: ✅ Thành công",
|
||
"FailedResetTraffic": "📧 Email: {{ .ClientEmail }}\n🏁 Kết quả: ❌ Thất bại \n\n🛠️ Lỗi: [ {{ .ErrorMessage }} ]",
|
||
"FinishProcess": "🔚 Quá trình đặt lại lưu lượng đã hoàn tất cho tất cả khách hàng."
|
||
},
|
||
"buttons": {
|
||
"closeKeyboard": "❌ Đóng Bàn Phím",
|
||
"cancel": "❌ Hủy",
|
||
"cancelReset": "❌ Hủy Đặt Lại",
|
||
"cancelIpLimit": "❌ Hủy Giới Hạn IP",
|
||
"confirmResetTraffic": "✅ Xác Nhận Đặt Lại Lưu Lượng?",
|
||
"confirmClearIps": "✅ Xác Nhận Xóa Các IP?",
|
||
"confirmRemoveTGUser": "✅ Xác Nhận Xóa Người Dùng Telegram?",
|
||
"confirmToggle": "✅ Xác nhận Bật/Tắt người dùng?",
|
||
"dbBackup": "Tải bản sao lưu cơ sở dữ liệu",
|
||
"serverUsage": "Sử Dụng Máy Chủ",
|
||
"getInbounds": "Lấy cổng vào",
|
||
"depleteSoon": "Depleted Soon",
|
||
"clientUsage": "Lấy Sử Dụng",
|
||
"onlines": "Khách hàng trực tuyến",
|
||
"commands": "Lệnh",
|
||
"refresh": "🔄 Cập Nhật",
|
||
"clearIPs": "❌ Xóa IP",
|
||
"removeTGUser": "❌ Xóa Người Dùng Telegram",
|
||
"selectTGUser": "👤 Chọn Người Dùng Telegram",
|
||
"selectOneTGUser": "👤 Chọn một người dùng telegram:",
|
||
"resetTraffic": "📈 Đặt Lại Lưu Lượng",
|
||
"resetExpire": "📅 Thay đổi ngày hết hạn",
|
||
"ipLog": "🔢 Nhật ký địa chỉ IP",
|
||
"ipLimit": "🔢 Giới Hạn địa chỉ IP",
|
||
"setTGUser": "👤 Đặt Người Dùng Telegram",
|
||
"toggle": "🔘 Bật / Tắt",
|
||
"custom": "🔢 Tùy chỉnh",
|
||
"confirmNumber": "✅ Xác nhận: {{ .Num }}",
|
||
"confirmNumberAdd": "✅ Xác nhận thêm: {{ .Num }}",
|
||
"limitTraffic": "🚧 Giới hạn lưu lượng",
|
||
"getBanLogs": "Cấm nhật ký",
|
||
"allClients": "Tất cả Khách hàng",
|
||
"addClient": "Thêm Khách Hàng",
|
||
"submitDisable": "Gửi Dưới Dạng Vô Hiệu ☑️",
|
||
"submitEnable": "Gửi Dưới Dạng Kích Hoạt ✅",
|
||
"use_default": "🏷️ Sử Dụng Mặc Định",
|
||
"change_id": "⚙️🔑 ID",
|
||
"change_password": "⚙️🔑 Mật Khẩu",
|
||
"change_email": "⚙️📧 Email",
|
||
"change_comment": "⚙️💬 Bình Luận",
|
||
"change_flow": "⚙️🚦 Flow",
|
||
"ResetAllTraffics": "Đặt lại tất cả lưu lượng",
|
||
"SortedTrafficUsageReport": "Báo cáo sử dụng lưu lượng đã sắp xếp"
|
||
},
|
||
"answers": {
|
||
"successfulOperation": "✅ Thành công!",
|
||
"errorOperation": "❗ Lỗi Trong Quá Trình Thực Hiện.",
|
||
"getInboundsFailed": "❌ Không Thể Lấy Được Inbounds",
|
||
"getClientsFailed": "❌ Không thể lấy khách hàng.",
|
||
"canceled": "❌ {{ .Email }} : Thao Tác Đã Bị Hủy.",
|
||
"clientRefreshSuccess": "✅ {{ .Email }} : Cập Nhật Thành Công Cho Khách Hàng.",
|
||
"IpRefreshSuccess": "✅ {{ .Email }} : Cập Nhật Thành Công Cho IPs.",
|
||
"TGIdRefreshSuccess": "✅ {{ .Email }} : Cập Nhật Thành Công Cho Người Dùng Telegram.",
|
||
"resetTrafficSuccess": "✅ {{ .Email }} : Đặt Lại Lưu Lượng Thành Công.",
|
||
"setTrafficLimitSuccess": "✅ {{ .Email }} : Đã lưu thành công giới hạn lưu lượng.",
|
||
"expireResetSuccess": "✅ {{ .Email }} : Đặt Lại Ngày Hết Hạn Thành Công.",
|
||
"resetIpSuccess": "✅ {{ .Email }} : Giới Hạn IP {{ .Count }} Đã Được Lưu Thành Công.",
|
||
"clearIpSuccess": "✅ {{ .Email }} : IP Đã Được Xóa Thành Công.",
|
||
"getIpLog": "✅ {{ .Email }} : Lấy nhật ký IP Thành Công.",
|
||
"getUserInfo": "✅ {{ .Email }} : Lấy Thông Tin Người Dùng Telegram Thành Công.",
|
||
"removedTGUserSuccess": "✅ {{ .Email }} : Người Dùng Telegram Đã Được Xóa Thành Công.",
|
||
"enableSuccess": "✅ {{ .Email }} : Đã Bật Thành Công.",
|
||
"disableSuccess": "✅ {{ .Email }} : Đã Tắt Thành Công.",
|
||
"askToAddUserId": "Cấu hình của bạn không được tìm thấy!\r\nVui lòng yêu cầu Quản trị viên sử dụng ID người dùng telegram của bạn trong cấu hình của bạn.\r\n\r\nID người dùng của bạn: <code>{{ .TgUserID }}</code>",
|
||
"chooseClient": "Chọn một Khách hàng cho Inbound {{ .Inbound }}",
|
||
"chooseInbound": "Chọn một Inbound"
|
||
}
|
||
}
|
||
} |