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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Notable transformations:

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

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

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

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

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

Pages:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

* chore(frontend): adopt antd v6 api updates

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

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

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

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

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

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

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

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

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

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

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

* Memoize compactAdvancedJson and update deps

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

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

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

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

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

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

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

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

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

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

* style(frontend): improve readability and mobile polish

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

* feat: jalali calendar support and date formatting fixes

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

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

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

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

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

* Bump Xray to v26.5.9 and minor cleanup

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

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

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

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

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

* Improve legacy clipboard copy handling

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

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

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

1093 lines
No EOL
59 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": "Nombre de Usuario",
"password": "Contraseña",
"login": "Acceder",
"confirm": "Confirmar",
"cancel": "Cancelar",
"close": "Cerrar",
"save": "Guardar",
"logout": "Cerrar Sesión",
"create": "Crear",
"update": "Actualizar",
"copy": "Copiar",
"copied": "Copiado",
"download": "Descargar",
"remark": "Notas",
"enable": "Habilitar",
"protocol": "Protocolo",
"search": "Buscar",
"filter": "Filtrar",
"loading": "Cargando...",
"refresh": "Actualizar",
"clear": "Borrar",
"second": "Segundo",
"minute": "Minuto",
"hour": "Hora",
"day": "Día",
"check": "Verificar",
"indefinite": "Indefinido",
"unlimited": "Ilimitado",
"none": "None",
"qrCode": "Código QR",
"info": "Más Información",
"edit": "Editar",
"delete": "Eliminar",
"reset": "Restablecer",
"noData": "Sin datos",
"copySuccess": "Copiado exitosamente",
"sure": "Seguro",
"encryption": "Encriptación",
"useIPv4ForHost": "Usar IPv4 para el host",
"transmission": "Transmisión",
"host": "Host",
"path": "Path",
"camouflage": "Camuflaje",
"status": "Estado",
"enabled": "Habilitado",
"disabled": "Deshabilitado",
"depleted": "Agotado",
"depletingSoon": "Agotándose",
"offline": "fuera de línea",
"online": "en línea",
"domainName": "Nombre de dominio",
"monitor": "Listening IP",
"certificate": "Certificado Digital",
"fail": "Falló",
"comment": "Comentario",
"success": "Éxito",
"lastOnline": "Última conexión",
"getVersion": "Obtener versión",
"install": "Instalar",
"clients": "Clientes",
"usage": "Uso",
"twoFactorCode": "Código",
"remained": "Restante",
"security": "Seguridad",
"secAlertTitle": "Alerta de Seguridad",
"secAlertSsl": "Esta conexión no es segura. Por favor, evite ingresar información sensible hasta que se active TLS para la protección de datos.",
"secAlertConf": "Ciertas configuraciones son vulnerables a ataques. Se recomienda reforzar los protocolos de seguridad para prevenir posibles violaciones.",
"secAlertSSL": "El panel carece de una conexión segura. Por favor, instale un certificado TLS para la protección de datos.",
"secAlertPanelPort": "El puerto predeterminado del panel es vulnerable. Por favor, configure un puerto aleatorio o específico.",
"secAlertPanelURI": "La ruta URI predeterminada del panel no es segura. Por favor, configure una ruta URI compleja.",
"secAlertSubURI": "La ruta URI predeterminada de la suscripción no es segura. Por favor, configure una ruta URI compleja.",
"secAlertSubJsonURI": "La ruta URI JSON predeterminada de la suscripción no es segura. Por favor, configure una ruta URI compleja.",
"emptyDnsDesc": "No hay servidores DNS añadidos.",
"emptyFakeDnsDesc": "No hay servidores Fake DNS añadidos.",
"emptyBalancersDesc": "No hay balanceadores añadidos.",
"emptyReverseDesc": "No hay proxies inversos añadidos.",
"somethingWentWrong": "Algo salió mal",
"subscription": {
"title": "Información de suscripción",
"subId": "ID de suscripción",
"status": "Estado",
"downloaded": "Descargado",
"uploaded": "Subido",
"expiry": "Caducidad",
"totalQuota": "Cuota total",
"individualLinks": "Enlaces individuales",
"active": "Activo",
"inactive": "Inactivo",
"unlimited": "Ilimitado",
"noExpiry": "Sin caducidad"
},
"menu": {
"theme": "Tema",
"dark": "Oscuro",
"ultraDark": "Ultra Oscuro",
"dashboard": "Estado del Sistema",
"inbounds": "Entradas",
"clients": "Clientes",
"nodes": "Nodos",
"settings": "Configuraciones",
"xray": "Ajustes Xray",
"apiDocs": "Documentación de la API",
"logout": "Cerrar Sesión",
"link": "Gestionar",
"donate": "Donar"
},
"pages": {
"login": {
"hello": "Hola",
"title": "Bienvenido",
"loginAgain": "El límite de tiempo de inicio de sesión ha expirado. Por favor, inicia sesión nuevamente.",
"toasts": {
"invalidFormData": "El formato de los datos de entrada es inválido.",
"emptyUsername": "Por favor ingresa el nombre de usuario.",
"emptyPassword": "Por favor ingresa la contraseña.",
"wrongUsernameOrPassword": "Nombre de usuario, contraseña o código de dos factores incorrecto.",
"successLogin": "Has iniciado sesión en tu cuenta correctamente."
}
},
"index": {
"title": "Estado del Sistema",
"cpu": "CPU",
"logicalProcessors": "Procesadores lógicos",
"frequency": "Frecuencia",
"swap": "Memoria Virtual",
"storage": "Almacenamiento",
"memory": "RAM",
"threads": "Hilos",
"xrayStatus": "Xray",
"stopXray": "Detener",
"restartXray": "Reiniciar",
"xraySwitch": "Versión",
"xrayUpdates": "Actualizaciones de Xray",
"xraySwitchClick": "Elige la versión a la que deseas cambiar.",
"xraySwitchClickDesk": "Elige sabiamente, ya que las versiones anteriores pueden no ser compatibles con las configuraciones actuales.",
"updatePanel": "Actualizar panel",
"panelUpdateDesc": "Esto actualizará 3X-UI a la última versión y reiniciará el servicio del panel.",
"currentPanelVersion": "Versión actual del panel",
"latestPanelVersion": "Última versión del panel",
"panelUpToDate": "El panel está actualizado",
"upToDate": "Actualizado",
"xrayStatusUnknown": "Desconocido",
"xrayStatusRunning": "En ejecución",
"xrayStatusStop": "Detenido",
"xrayStatusError": "Error",
"xrayErrorPopoverTitle": "Se produjo un error al ejecutar Xray",
"operationHours": "Tiempo de Funcionamiento",
"systemHistoryTitle": "Historial del Sistema",
"charts": "Gráficos",
"xrayMetricsTitle": "Métricas de Xray",
"xrayMetricsDisabled": "Endpoint de métricas de Xray no configurado",
"xrayMetricsHint": "Añade un bloque metrics de nivel superior a la configuración de xray con tag metrics_out y listen 127.0.0.1:11111, luego reinicia xray.",
"xrayObservatoryEmpty": "Aún no hay datos de Observatory",
"xrayObservatoryHint": "Añade un bloque observatory a la configuración de xray listando los tags de outbound a sondear, luego reinicia xray.",
"xrayObservatoryTagPlaceholder": "Seleccionar outbound",
"xrayObservatoryAlive": "Activo",
"xrayObservatoryDead": "Caído",
"xrayObservatoryLastSeen": "Visto por última vez",
"xrayObservatoryLastTry": "Último intento",
"trendLast2Min": "Últimos 2 minutos",
"systemLoad": "Carga del Sistema",
"systemLoadDesc": "promedio de carga del sistema en los últimos 1, 5 y 15 minutos",
"connectionCount": "Número de Conexiones",
"ipAddresses": "Direcciones IP",
"toggleIpVisibility": "Alternar visibilidad de la IP",
"overallSpeed": "Velocidad general",
"upload": "Subida",
"download": "Descarga",
"totalData": "Datos totales",
"sent": "Enviado",
"received": "Recibido",
"documentation": "Documentación",
"xraySwitchVersionDialog": "¿Realmente deseas cambiar la versión de Xray?",
"xraySwitchVersionDialogDesc": "Esto cambiará la versión de Xray a #version#.",
"xraySwitchVersionPopover": "Xray se actualizó correctamente",
"panelUpdateDialog": "¿Deseas actualizar el panel?",
"panelUpdateDialogDesc": "Esto actualizará 3X-UI a la versión #version# y reiniciará el servicio del panel.",
"panelUpdateCheckPopover": "Fallo al comprobar actualización del panel",
"panelUpdateStartedPopover": "Actualización del panel iniciada",
"geofileUpdateDialog": "¿Realmente deseas actualizar el geofichero?",
"geofileUpdateDialogDesc": "Esto actualizará el archivo #filename#.",
"geofilesUpdateDialogDesc": "Esto actualizará todos los archivos.",
"geofilesUpdateAll": "Actualizar todo",
"geofileUpdatePopover": "Geofichero actualizado correctamente",
"customGeoTitle": "GeoSite / GeoIP personalizados",
"customGeoAdd": "Añadir",
"customGeoType": "Tipo",
"customGeoAlias": "Alias",
"customGeoUrl": "URL",
"customGeoEnabled": "Activado",
"customGeoLastUpdated": "Última actualización",
"customGeoExtColumn": "Enrutamiento (ext:…)",
"customGeoToastUpdateAll": "Todas las fuentes personalizadas se actualizaron",
"customGeoActions": "Acciones",
"customGeoEdit": "Editar",
"customGeoDelete": "Eliminar",
"customGeoDownload": "Actualizar ahora",
"customGeoModalAdd": "Añadir geo personalizado",
"customGeoModalEdit": "Editar geo personalizado",
"customGeoModalSave": "Guardar",
"customGeoDeleteConfirm": "¿Eliminar esta fuente geo personalizada?",
"customGeoRoutingHint": "En reglas de enrutamiento use la columna de valor como ext:archivo.dat:etiqueta (sustituya la etiqueta).",
"customGeoInvalidId": "Id de recurso no válido",
"customGeoAliasesError": "No se pudieron cargar los alias geo personalizados",
"customGeoValidationAlias": "El alias solo puede contener letras minúsculas, dígitos, - y _",
"customGeoValidationUrl": "La URL debe comenzar con http:// o https://",
"customGeoAliasPlaceholder": "a-z 0-9 _ -",
"customGeoAliasLabelSuffix": " (personalizado)",
"customGeoToastList": "Lista de geo personalizado",
"customGeoToastAdd": "Añadir geo personalizado",
"customGeoToastUpdate": "Actualizar geo personalizado",
"customGeoToastDelete": "Geofile personalizado «{{ .fileName }}» eliminado",
"customGeoToastDownload": "Geofile «{{ .fileName }}» actualizado",
"customGeoErrInvalidType": "El tipo debe ser geosite o geoip",
"customGeoErrAliasRequired": "El alias es obligatorio",
"customGeoErrAliasPattern": "El alias contiene caracteres no permitidos",
"customGeoErrAliasReserved": "Este alias está reservado",
"customGeoErrUrlRequired": "La URL es obligatoria",
"customGeoErrInvalidUrl": "La URL no es válida",
"customGeoErrUrlScheme": "La URL debe usar http o https",
"customGeoErrUrlHost": "El host de la URL no es válido",
"customGeoErrDuplicateAlias": "Este alias ya se usa para este tipo",
"customGeoErrNotFound": "Fuente geo personalizada no encontrada",
"customGeoErrDownload": "Error de descarga",
"customGeoErrUpdateAllIncomplete": "No se pudieron actualizar una o más fuentes geo personalizadas",
"customGeoEmpty": "Aún no hay fuentes geo personalizadas — haz clic en Añadir para crear una",
"dontRefresh": "La instalación está en progreso, por favor no actualices esta página.",
"logs": "Registros",
"config": "Configuración",
"backup": "Сopia de Seguridad",
"backupTitle": "Copia & Restauración",
"exportDatabase": "Copia de seguridad",
"exportDatabaseDesc": "Haz clic para descargar un archivo .db que contiene una copia de seguridad de tu base de datos actual en tu dispositivo.",
"importDatabase": "Restaurar",
"importDatabaseDesc": "Haz clic para seleccionar y cargar un archivo .db desde tu dispositivo para restaurar tu base de datos desde una copia de seguridad.",
"importDatabaseSuccess": "La base de datos se ha importado correctamente",
"importDatabaseError": "Ocurrió un error al importar la base de datos",
"readDatabaseError": "Ocurrió un error al leer la base de datos",
"getDatabaseError": "Ocurrió un error al obtener la base de datos",
"getConfigError": "Ocurrió un error al obtener el archivo de configuración"
},
"inbounds": {
"title": "Entradas",
"totalDownUp": "Subidas/Descargas Totales",
"totalUsage": "Uso Total",
"inboundCount": "Número de Entradas",
"operate": "Menú",
"enable": "Habilitar",
"remark": "Notas",
"node": "Nodo",
"deployTo": "Desplegar en",
"localPanel": "Panel local",
"fallbacks": {
"title": "Fallbacks",
"help": "Cuando una conexión en este inbound no coincide con ningún cliente, redirígela a otro inbound. Elige un hijo abajo y los campos de enrutamiento (SNI / ALPN / Path / xver) se rellenan automáticamente desde su transporte; la mayoría de las configuraciones no necesitan más ajustes. Cada hijo debe escuchar en 127.0.0.1 con security=none.",
"empty": "Aún no hay fallbacks",
"add": "Añadir fallback",
"pickInbound": "Selecciona un inbound",
"matchAny": "cualquiera",
"rederive": "Rellenar desde el hijo",
"rederived": "Rellenado desde el hijo",
"editAdvanced": "Editar campos de enrutamiento",
"hideAdvanced": "Ocultar avanzado",
"quickAddAll": "Añadir todos los elegibles",
"quickAdded": "Se añadieron {n} fallback(s)",
"quickAddedNone": "No hay nuevos inbounds elegibles",
"routesWhen": "Enruta cuando",
"defaultCatchAll": "Por defecto — captura cualquier otra cosa"
},
"protocol": "Protocolo",
"port": "Puerto",
"portMap": "Puertos de Destino",
"traffic": "Tráfico",
"details": "Detalles",
"transportConfig": "Transporte",
"expireDate": "Fecha de Expiración",
"createdAt": "Creado",
"updatedAt": "Actualizado",
"resetTraffic": "Restablecer Tráfico",
"addInbound": "Agregar Entrada",
"generalActions": "Acciones Generales",
"modifyInbound": "Modificar Entrada",
"deleteInbound": "Eliminar Entrada",
"deleteInboundContent": "¿Confirmar eliminación de entrada?",
"deleteClient": "Eliminar cliente",
"deleteClientContent": "¿Está seguro de que desea eliminar el cliente?",
"resetTrafficContent": "¿Confirmar restablecimiento de tráfico?",
"copyLink": "Copiar Enlace",
"address": "Dirección",
"network": "Red",
"destinationPort": "Puerto de Destino",
"targetAddress": "Dirección de Destino",
"monitorDesc": "Dejar en blanco por defecto",
"meansNoLimit": " = illimitata. (unidad: GB)",
"totalFlow": "Flujo Total",
"leaveBlankToNeverExpire": "Dejar en Blanco para Nunca Expirar",
"noRecommendKeepDefault": "No hay requisitos especiales para mantener la configuración predeterminada",
"certificatePath": "Ruta Cert",
"certificateContent": "Datos Cert",
"publicKey": "Clave Pública",
"privatekey": "Clave Privada",
"clickOnQRcode": "Haz clic en el Código QR para Copiar",
"client": "Cliente",
"export": "Exportar Enlaces",
"clone": "Clonar",
"cloneInbound": "Clonar Entradas",
"cloneInboundContent": "Se aplicarán todas las configuraciones de esta entrada, excepto el Puerto, la IP de Escucha y los Clientes, al clon.",
"cloneInboundOk": "Clonar",
"resetAllTraffic": "Restablecer Tráfico de Todas las Entradas",
"resetAllTrafficTitle": "Restablecer tráfico de todas las entradas",
"resetAllTrafficContent": "¿Estás seguro de que deseas restablecer el tráfico de todas las entradas?",
"resetInboundClientTraffics": "Restablecer Tráfico de Clientes",
"resetInboundClientTrafficTitle": "Restablecer todo el tráfico de clientes",
"resetInboundClientTrafficContent": "¿Estás seguro de que deseas restablecer todo el tráfico para los clientes de esta entrada?",
"resetAllClientTraffics": "Restablecer Tráfico de Todos los Clientes",
"resetAllClientTrafficTitle": "Restablecer todo el tráfico de clientes",
"resetAllClientTrafficContent": "¿Estás seguro de que deseas restablecer todo el tráfico para todos los clientes?",
"delDepletedClients": "Eliminar Clientes Agotados",
"delDepletedClientsTitle": "Eliminar clientes agotados",
"delDepletedClientsContent": "¿Estás seguro de que deseas eliminar todos los clientes agotados?",
"email": "Email",
"emailDesc": "Por favor proporciona una dirección de correo electrónico única.",
"IPLimit": "Límite de IP",
"IPLimitDesc": "Desactiva la entrada si la cantidad supera el valor ingresado (ingresa 0 para desactivar el límite de IP).",
"IPLimitlog": "Registro de IP",
"IPLimitlogDesc": "Registro de historial de IPs (antes de habilitar la entrada después de que haya sido desactivada por el límite de IP, debes borrar el registro).",
"IPLimitlogclear": "Limpiar el Registro",
"setDefaultCert": "Establecer certificado desde el panel",
"streamTab": "Stream",
"securityTab": "Seguridad",
"sniffingTab": "Sniffing",
"sniffingMetadataOnly": "Solo metadatos",
"sniffingRouteOnly": "Solo enrutamiento",
"sniffingIpsExcluded": "IPs excluidas",
"sniffingDomainsExcluded": "Dominios excluidos",
"decryption": "Descifrado",
"encryption": "Cifrado",
"vlessAuthX25519": "Autenticación X25519",
"vlessAuthMlkem768": "Autenticación ML-KEM-768",
"vlessAuthCustom": "Personalizado",
"vlessAuthSelected": "Seleccionado: {auth}",
"advanced": {
"title": "Secciones JSON del inbound",
"subtitle": "JSON completo del inbound y editores específicos para settings, sniffing y streamSettings.",
"all": "Todo",
"allHelp": "Objeto inbound completo con todos los campos en un solo editor.",
"settings": "Ajustes",
"settingsHelp": "Envoltorio del bloque settings de Xray:",
"sniffing": "Sniffing",
"sniffingHelp": "Envoltorio del bloque sniffing de Xray:",
"stream": "Stream",
"streamHelp": "Envoltorio del bloque stream de Xray:",
"jsonErrorPrefix": "JSON avanzado"
},
"telegramDesc": "Por favor, proporciona el ID de Chat de Telegram. (usa el comando '/id' en el bot) o ({'@'}userinfobot)",
"subscriptionDesc": "Puedes encontrar tu enlace de suscripción en Detalles, también puedes usar el mismo nombre para varias configuraciones.",
"info": "Info",
"same": "misma",
"inboundData": "Datos de entrada",
"exportInbound": "Exportación entrante",
"import": "Importar",
"importInbound": "Importar un entrante",
"periodicTrafficResetTitle": "Reset de Tráfico",
"periodicTrafficResetDesc": "Reiniciar automáticamente el contador de tráfico en intervalos especificados",
"lastReset": "Último reinicio",
"periodicTrafficReset": {
"never": "Nunca",
"daily": "Diariamente",
"weekly": "Semanalmente",
"monthly": "Mensualmente",
"hourly": "Cada hora"
},
"toasts": {
"obtain": "Recibir",
"updateSuccess": "La actualización fue exitosa",
"logCleanSuccess": "El registro ha sido limpiado",
"inboundsUpdateSuccess": "Entradas actualizadas correctamente",
"inboundUpdateSuccess": "Entrada actualizada correctamente",
"inboundCreateSuccess": "Entrada creada correctamente",
"inboundDeleteSuccess": "Entrada eliminada correctamente",
"inboundClientAddSuccess": "Cliente(s) de entrada añadido(s)",
"inboundClientDeleteSuccess": "Cliente de entrada eliminado",
"inboundClientUpdateSuccess": "Cliente de entrada actualizado",
"delDepletedClientsSuccess": "Todos los clientes con tráfico agotado fueron eliminados",
"resetAllClientTrafficSuccess": "Todo el tráfico del cliente ha sido reiniciado",
"resetAllTrafficSuccess": "Todo el tráfico ha sido reiniciado",
"resetInboundClientTrafficSuccess": "El tráfico ha sido reiniciado",
"resetInboundTrafficSuccess": "El tráfico de entrada ha sido reiniciado",
"trafficGetError": "Error al obtener los tráficos",
"getNewX25519CertError": "Error al obtener el certificado X25519.",
"getNewmldsa65Error": "Error al obtener el certificado mldsa65.",
"getNewVlessEncError": "Error al obtener el certificado VlessEnc."
},
"stream": {
"general": {
"request": "Pedido",
"response": "Respuesta",
"name": "Nombre",
"value": "Valor"
},
"tcp": {
"version": "Versión",
"method": "Método",
"path": "Camino",
"status": "Estado",
"statusDescription": "Descripción de la Situación",
"requestHeader": "Encabezado de solicitud",
"responseHeader": "Encabezado de respuesta"
}
}
},
"clients": {
"add": "Añadir cliente",
"edit": "Editar cliente",
"submitAdd": "Añadir cliente",
"submitEdit": "Guardar cambios",
"clientCount": "Número de clientes",
"bulk": "Añadir en lote",
"copyFromInbound": "Copiar clientes desde inbound",
"copyToInbound": "Copiar clientes a",
"copySelected": "Copiar selección",
"copySource": "Origen",
"copyEmailPreview": "Vista previa del correo resultante",
"copySelectSourceFirst": "Selecciona primero un inbound de origen.",
"copyResult": "Resultado de la copia",
"copyResultSuccess": "Copiado correctamente",
"copyResultNone": "Nada que copiar: no hay clientes seleccionados o el origen está vacío",
"copyResultErrors": "Errores de copia",
"copyFlowLabel": "Flow para clientes nuevos (VLESS)",
"copyFlowHint": "Se aplica a todos los clientes copiados. Déjalo vacío para omitir.",
"selectAll": "Seleccionar todo",
"clearAll": "Limpiar todo",
"method": "Método",
"first": "Primero",
"last": "Último",
"ipLog": "Registro de IP",
"prefix": "Prefijo",
"postfix": "Sufijo",
"delayedStart": "Iniciar tras el primer uso",
"expireDays": "Duración",
"days": "Día(s)",
"renew": "Renovación automática",
"renewDesc": "Renovación automática tras la expiración. (0 = desactivado) (unidad: día)",
"title": "Clientes",
"actions": "Acciones",
"totalGB": "Total enviado/recibido (GB)",
"expiryTime": "Expiración",
"addClients": "Añadir clientes",
"limitIp": "Límite de IP",
"password": "Contraseña",
"subId": "ID de suscripción",
"online": "En línea",
"email": "Correo",
"comment": "Comentario",
"traffic": "Tráfico",
"offline": "Desconectado",
"addTitle": "Añadir cliente",
"qrCode": "Código QR",
"moreInformation": "Más información",
"delete": "Eliminar",
"reset": "Restablecer tráfico",
"editTitle": "Editar cliente",
"client": "Cliente",
"enabled": "Habilitado",
"remaining": "Restante",
"duration": "Duración",
"attachedInbounds": "Inbounds asociados",
"selectInbound": "Selecciona uno o más inbounds",
"noSubId": "Este cliente no tiene subId, no hay enlace compartible.",
"noLinks": "No hay enlaces compartibles — asocia primero este cliente a un inbound con protocolo válido.",
"link": "Enlace",
"resetNotPossible": "Asocia primero este cliente a un inbound.",
"general": "General",
"resetAllTraffics": "Restablecer tráfico de todos los clientes",
"resetAllTrafficsTitle": "¿Restablecer tráfico de todos los clientes?",
"resetAllTrafficsContent": "El contador de subida/bajada de cada cliente vuelve a cero. Las cuotas y la expiración no se modifican. Esta acción no se puede deshacer.",
"empty": "Aún no hay clientes — añade uno para empezar.",
"deleteConfirmTitle": "¿Eliminar al cliente {email}?",
"deleteConfirmContent": "Esto elimina al cliente de cada inbound asociado y descarta su registro de tráfico. No se puede deshacer.",
"deleteSelected": "Eliminar ({count})",
"bulkDeleteConfirmTitle": "¿Eliminar {count} clientes?",
"bulkDeleteConfirmContent": "Cada cliente seleccionado se elimina de los inbounds asociados y se descarta su registro de tráfico. No se puede deshacer.",
"delDepleted": "Eliminar agotados",
"delDepletedConfirmTitle": "¿Eliminar clientes agotados?",
"delDepletedConfirmContent": "Elimina todos los clientes con cuota agotada o expirados. No se puede deshacer.",
"auth": "Auth",
"hysteriaAuth": "Auth de Hysteria",
"uuid": "UUID",
"flow": "Flow",
"reverseTag": "Reverse tag",
"reverseTagPlaceholder": "Reverse tag opcional",
"telegramId": "ID de usuario de Telegram",
"telegramIdPlaceholder": "ID numérico de usuario de Telegram (0 = ninguno)",
"created": "Creado",
"updated": "Actualizado",
"ipLimit": "Límite de IP",
"toasts": {
"deleted": "Cliente eliminado",
"trafficReset": "Tráfico restablecido",
"allTrafficsReset": "Tráfico de todos los clientes restablecido",
"bulkDeleted": "{count} clientes eliminados",
"bulkDeletedMixed": "{ok} eliminados, {failed} fallidos",
"bulkCreated": "{count} clientes creados",
"bulkCreatedMixed": "{ok} creados, {failed} fallidos",
"delDepleted": "{count} clientes agotados eliminados"
}
},
"nodes": {
"title": "Nodos",
"addNode": "Agregar nodo",
"editNode": "Editar nodo",
"totalNodes": "Total de nodos",
"onlineNodes": "En línea",
"offlineNodes": "Desconectado",
"avgLatency": "Latencia media",
"name": "Nombre",
"namePlaceholder": "p. ej. de-frankfurt-1",
"addressPlaceholder": "panel.example.com o 1.2.3.4",
"remark": "Notas",
"scheme": "Esquema",
"address": "Dirección",
"port": "Puerto",
"basePath": "Ruta base",
"apiToken": "Token de API",
"apiTokenPlaceholder": "Token desde la página de Configuración del panel remoto",
"apiTokenHint": "El panel remoto expone su token de API en Configuración → Token de API.",
"regenerate": "Regenerar token",
"regenerateConfirm": "Regenerar invalida el token actual. Cualquier panel central que lo use perderá el acceso hasta que se actualice. ¿Continuar?",
"allowPrivateAddress": "Permitir dirección privada",
"allowPrivateAddressHint": "Habilitar solo para nodos en una red privada o VPN.",
"enable": "Habilitado",
"status": "Estado",
"cpu": "CPU",
"mem": "Memoria",
"uptime": "Tiempo activo",
"latency": "Latencia",
"lastHeartbeat": "Último latido",
"xrayVersion": "Versión de Xray",
"panelVersion": "Versión del panel",
"actions": "Acciones",
"probe": "Sondear ahora",
"testConnection": "Probar conexión",
"connectionOk": "Conexión correcta ({ms} ms)",
"connectionFailed": "Conexión fallida",
"never": "nunca",
"justNow": "ahora mismo",
"deleteConfirmTitle": "¿Eliminar el nodo \"{name}\"?",
"deleteConfirmContent": "Esto detiene la monitorización del nodo. El panel remoto en sí no se ve afectado.",
"statusValues": {
"online": "En línea",
"offline": "Desconectado",
"unknown": "Desconocido"
},
"toasts": {
"list": "Error al cargar los nodos",
"obtain": "Error al cargar el nodo",
"add": "Agregar nodo",
"update": "Actualizar nodo",
"delete": "Eliminar nodo",
"deleted": "Nodo eliminado",
"test": "Probar conexión",
"fillRequired": "El nombre, la dirección, el puerto y el token de API son obligatorios",
"probeFailed": "Sondeo fallido"
}
},
"settings": {
"title": "Configuraciones",
"save": "Guardar",
"infoDesc": "Cada cambio realizado aquí debe ser guardado. Por favor, reinicie el panel para aplicar los cambios.",
"restartPanel": "Reiniciar Panel",
"restartPanelDesc": "¿Está seguro de que desea reiniciar el panel? Haga clic en Aceptar para reiniciar después de 3 segundos. Si no puede acceder al panel después de reiniciar, por favor, consulte la información de registro del panel en el servidor.",
"restartPanelSuccess": "El panel se reinició correctamente",
"actions": "Acciones",
"resetDefaultConfig": "Restablecer a Configuración Predeterminada",
"panelSettings": "Configuraciones del Panel",
"securitySettings": "Configuraciones de Seguridad",
"TGBotSettings": "Configuraciones de Bot de Telegram",
"panelListeningIP": "IP de Escucha del Panel",
"panelListeningIPDesc": "Dejar en blanco por defecto para monitorear todas las IPs.",
"panelListeningDomain": "Dominio de Escucha del Panel",
"panelListeningDomainDesc": "Dejar en blanco por defecto para monitorear todos los dominios e IPs.",
"panelPort": "Puerto del Panel",
"panelPortDesc": "El puerto utilizado para mostrar este panel.",
"publicKeyPath": "Ruta del Archivo de Clave Pública del Certificado del Panel",
"publicKeyPathDesc": "Complete con una ruta absoluta que comience con.",
"privateKeyPath": "Ruta del Archivo de Clave Privada del Certificado del Panel",
"privateKeyPathDesc": "Complete con una ruta absoluta que comience con.",
"panelUrlPath": "Ruta Raíz de la URL del Panel",
"panelUrlPathDesc": "Debe empezar con '/' y terminar con.",
"pageSize": "Tamaño de paginación",
"pageSizeDesc": "Defina el tamaño de página para la tabla de entradas. Establezca 0 para desactivar",
"remarkModel": "Modelo de observación y carácter de separación",
"datepicker": "selector de fechas",
"datepickerPlaceholder": "Seleccionar fecha",
"datepickerDescription": "El tipo de calendario selector especifica la fecha de vencimiento",
"sampleRemark": "Observación de muestra",
"oldUsername": "Nombre de Usuario Actual",
"currentPassword": "Contraseña Actual",
"newUsername": "Nuevo Nombre de Usuario",
"newPassword": "Nueva Contraseña",
"telegramBotEnable": "Habilitar bot de Telegram",
"telegramBotEnableDesc": "Conéctese a las funciones de este panel a través del bot de Telegram.",
"telegramToken": "Token de Telegram",
"telegramTokenDesc": "Debe obtener el token del administrador de bots de Telegram {'@'}botfather.",
"telegramProxy": "Socks5 Proxy",
"telegramProxyDesc": "Si necesita el proxy Socks5 para conectarse a Telegram. Ajuste su configuración según la guía.",
"telegramAPIServer": "API Server de Telegram",
"telegramAPIServerDesc": "El servidor API de Telegram a utilizar. Déjelo en blanco para utilizar el servidor predeterminado.",
"telegramChatId": "IDs de Chat de Telegram para Administradores",
"telegramChatIdDesc": "IDs de Chat múltiples separados por comas. Use {'@'}userinfobot o use el comando '/id' en el bot para obtener sus IDs de Chat.",
"telegramNotifyTime": "Hora de Notificación del Bot de Telegram",
"telegramNotifyTimeDesc": "Usar el formato de tiempo de Crontab.",
"tgNotifyBackup": "Respaldo de Base de Datos",
"tgNotifyBackupDesc": "Incluir archivo de respaldo de base de datos con notificación de informe.",
"tgNotifyLogin": "Notificación de Inicio de Sesión",
"tgNotifyLoginDesc": "Muestra el nombre de usuario, dirección IP y hora cuando alguien intenta iniciar sesión en su panel.",
"sessionMaxAge": "Edad Máxima de Sesión",
"sessionMaxAgeDesc": "La duración de una sesión de inicio de sesión (unidad: minutos).",
"expireTimeDiff": "Umbral de Expiración para Notificación",
"expireTimeDiffDesc": "Reciba notificaciones sobre la expiración de la cuenta antes del umbral (unidad: días).",
"trafficDiff": "Umbral de Tráfico para Notificación",
"trafficDiffDesc": "Reciba notificaciones sobre el agotamiento del tráfico antes de alcanzar el umbral (unidad: GB).",
"tgNotifyCpu": "Umbral de Alerta de Porcentaje de CPU",
"tgNotifyCpuDesc": "Reciba notificaciones si el uso de la CPU supera este umbral (unidad: %).",
"timeZone": "Zona Horaria",
"timeZoneDesc": "Las tareas programadas se ejecutan de acuerdo con la hora en esta zona horaria.",
"subSettings": "Suscripción",
"subEnable": "Habilitar Servicio",
"subEnableDesc": "Función de suscripción con configuración separada.",
"subJsonEnable": "Habilitar/Deshabilitar el endpoint de suscripción JSON de forma independiente.",
"subTitle": "Título de la Suscripción",
"subTitleDesc": "Título mostrado en el cliente VPN",
"subSupportUrl": "URL de soporte",
"subSupportUrlDesc": "Enlace de soporte técnico mostrado en el cliente VPN",
"subProfileUrl": "URL del perfil",
"subProfileUrlDesc": "Un enlace a tu sitio web mostrado en el cliente VPN",
"subAnnounce": "Anuncio",
"subAnnounceDesc": "El texto del anuncio mostrado en el cliente VPN",
"subEnableRouting": "Habilitar enrutamiento",
"subEnableRoutingDesc": "Configuración global para habilitar el enrutamiento en el cliente VPN. (Solo para Happ)",
"subRoutingRules": "Reglas de enrutamiento",
"subRoutingRulesDesc": "Reglas de enrutamiento globales para el cliente VPN. (Solo para Happ)",
"subListen": "Listening IP",
"subListenDesc": "Dejar en blanco por defecto para monitorear todas las IPs.",
"subPort": "Puerto de Suscripción",
"subPortDesc": "El número de puerto para el servicio de suscripción debe estar sin usar en el servidor.",
"subCertPath": "Ruta del Archivo de Clave Pública del Certificado de Suscripción",
"subCertPathDesc": "Complete con una ruta absoluta que comience con '/'",
"subKeyPath": "Ruta del Archivo de Clave Privada del Certificado de Suscripción",
"subKeyPathDesc": "Complete con una ruta absoluta que comience con '/'",
"subPath": "Ruta Raíz de la URL de Suscripción",
"subPathDesc": "Debe empezar con '/' y terminar con '/'",
"subDomain": "Dominio de Escucha",
"subDomainDesc": "Dejar en blanco por defecto para monitorear todos los dominios e IPs.",
"subUpdates": "Intervalos de Actualización de Suscripción",
"subUpdatesDesc": "Horas de intervalo entre actualizaciones en la aplicación del cliente.",
"subEncrypt": "Encriptar configuraciones",
"subEncryptDesc": "Encriptar las configuraciones devueltas en la suscripción.",
"subShowInfo": "Mostrar información de uso",
"subShowInfoDesc": "Mostrar tráfico restante y fecha después del nombre de configuración.",
"subEmailInRemark": "Incluir Email en el nombre",
"subEmailInRemarkDesc": "Incluir el correo del cliente en el nombre del perfil de suscripción.",
"subURI": "URI de proxy inverso",
"subURIDesc": "Cambiar el URI base de la URL de suscripción para usar detrás de los servidores proxy",
"externalTrafficInformEnable": "Informe de tráfico externo",
"externalTrafficInformEnableDesc": "Informar a la API externa sobre cada actualización de tráfico.",
"externalTrafficInformURI": "URI de información de tráfico externo",
"externalTrafficInformURIDesc": "Las actualizaciones de tráfico se envían a este URI.",
"restartXrayOnClientDisable": "Reiniciar Xray tras desactivación automática",
"restartXrayOnClientDisableDesc": "Cuando un cliente se desactive automáticamente por vencimiento o límite de tráfico, reiniciar Xray.",
"fragment": "Fragmentación",
"fragmentDesc": "Habilitar la fragmentación para el paquete de saludo de TLS",
"fragmentSett": "Configuración de Fragmentación",
"noisesDesc": "Activar Sonidos",
"noisesSett": "Configuración de Sonidos",
"mux": "Mux",
"muxDesc": "Transmite múltiples flujos de datos independientes dentro de un flujo de datos establecido.",
"muxSett": "Configuración Mux",
"direct": "Conexión Directa",
"directDesc": "Establece conexiones directas con dominios o rangos de IP de un país específico.",
"notifications": "Notificaciones",
"certs": "Certificados",
"externalTraffic": "Tráfico Externo",
"dateAndTime": "Fecha y Hora",
"proxyAndServer": "Proxy y Servidor",
"intervals": "Intervalos",
"information": "Información",
"language": "Idioma",
"telegramBotLanguage": "Idioma del Bot de Telegram",
"security": {
"admin": "Credenciales de administrador",
"twoFactor": "Autenticación de dos factores",
"twoFactorEnable": "Habilitar 2FA",
"twoFactorEnableDesc": "Añade una capa adicional de autenticación para mayor seguridad.",
"twoFactorModalSetTitle": "Activar autenticación de dos factores",
"twoFactorModalDeleteTitle": "Desactivar autenticación de dos factores",
"twoFactorModalSteps": "Para configurar la autenticación de dos factores, sigue estos pasos:",
"twoFactorModalFirstStep": "1. Escanea este código QR en la aplicación de autenticación o copia el token cerca del código QR y pégalo en la aplicación",
"twoFactorModalSecondStep": "2. Ingresa el código de la aplicación",
"twoFactorModalRemoveStep": "Ingresa el código de la aplicación para eliminar la autenticación de dos factores.",
"twoFactorModalChangeCredentialsTitle": "Cambiar credenciales",
"twoFactorModalChangeCredentialsStep": "Ingrese el código de la aplicación para cambiar las credenciales del administrador.",
"twoFactorModalSetSuccess": "La autenticación de dos factores se ha establecido con éxito",
"twoFactorModalDeleteSuccess": "La autenticación de dos factores se ha eliminado con éxito",
"twoFactorModalError": "Código incorrecto",
"show": "Mostrar",
"hide": "Ocultar",
"apiTokenNew": "Nuevo token",
"apiTokenName": "Nombre",
"apiTokenNamePlaceholder": "por ejemplo central-panel-a",
"apiTokenNameRequired": "El nombre es obligatorio",
"apiTokenEmpty": "Aún no hay tokens — crea uno para autenticar bots o paneles remotos.",
"apiTokenDeleteWarning": "Cualquier cliente que use este token dejará de autenticarse inmediatamente."
},
"toasts": {
"modifySettings": "Los parámetros han sido modificados.",
"getSettings": "Ocurrió un error al obtener los parámetros.",
"modifyUserError": "Ocurrió un error al cambiar las credenciales del administrador.",
"modifyUser": "Has cambiado exitosamente las credenciales del administrador.",
"originalUserPassIncorrect": "Nombre de usuario o contraseña original incorrectos",
"userPassMustBeNotEmpty": "El nuevo nombre de usuario y la nueva contraseña no pueden estar vacíos",
"getOutboundTrafficError": "Error al obtener el tráfico saliente",
"resetOutboundTrafficError": "Error al reiniciar el tráfico saliente"
}
},
"xray": {
"title": "Xray Configuración",
"save": "Guardar configuración",
"restart": "Reiniciar Xray",
"restartSuccess": "Xray se ha reiniciado correctamente",
"stopSuccess": "Xray se ha detenido correctamente",
"restartError": "Ocurrió un error al reiniciar Xray.",
"stopError": "Ocurrió un error al detener Xray.",
"basicTemplate": "Perfil Básico",
"advancedTemplate": "Perfil Avanzado",
"generalConfigs": "Configuraciones Generales",
"generalConfigsDesc": "Estas opciones proporcionarán ajustes generales.",
"logConfigs": "Registro",
"logConfigsDesc": "Los registros pueden afectar la eficiencia de su servidor. Se recomienda habilitarlos sabiamente solo en caso de sus necesidades.",
"blockConfigsDesc": "Estas opciones evitarán que los usuarios se conecten a protocolos y sitios web específicos.",
"basicRouting": "Enrutamiento Básico",
"blockConnectionsConfigsDesc": "Estas opciones bloquearán el tráfico según el país solicitado específico.",
"directConnectionsConfigsDesc": "Una conexión directa asegura que el tráfico específico no sea enrutado a través de otro servidor.",
"blockips": "Bloquear IPs",
"blockdomains": "Bloquear Dominios",
"directips": "IPs Directas",
"directdomains": "Dominios Directos",
"ipv4Routing": "Enrutamiento IPv4",
"ipv4RoutingDesc": "Estas opciones solo enrutarán a los dominios objetivo a través de IPv4.",
"warpRouting": "Enrutamiento WARP",
"warpRoutingDesc": "Precaución: Antes de usar estas opciones, instale WARP en modo de proxy socks5 en su servidor siguiendo los pasos en el GitHub del panel. WARP enrutará el tráfico a los sitios web a través de los servidores de Cloudflare.",
"nordRouting": "Enrutamiento NordVPN",
"nordRoutingDesc": "Estas opciones enrutarán el tráfico basado en un destino específico a través de NordVPN.",
"Template": "Plantilla de Configuración de Xray",
"TemplateDesc": "Genera el archivo de configuración final de Xray basado en esta plantilla.",
"FreedomStrategy": "Configurar Estrategia para el Protocolo Freedom",
"FreedomStrategyDesc": "Establece la estrategia de salida de la red en el Protocolo Freedom.",
"RoutingStrategy": "Configurar Estrategia de Enrutamiento de Dominios",
"RoutingStrategyDesc": "Establece la estrategia general de enrutamiento para la resolución de DNS.",
"outboundTestUrl": "URL de prueba de outbound",
"outboundTestUrlDesc": "URL usada al probar la conectividad del outbound",
"Torrent": "Prohibir Uso de BitTorrent",
"Inbounds": "Entrante",
"InboundsDesc": "Cambia la plantilla de configuración para aceptar clientes específicos.",
"Outbounds": "Salidas",
"Balancers": "Equilibradores",
"OutboundsDesc": "Cambia la plantilla de configuración para definir formas de salida para este servidor.",
"Routings": "Reglas de enrutamiento",
"RoutingsDesc": "¡La prioridad de cada regla es importante!",
"completeTemplate": "Todos",
"logLevel": "Nivel de registro",
"logLevelDesc": "El nivel de registro para registros de errores, que indica la información que debe registrarse.",
"accessLog": "Registro de acceso",
"accessLogDesc": "La ruta del archivo para el registro de acceso. El valor especial 'ninguno' deshabilita los registros de acceso",
"errorLog": "Registro de Errores",
"errorLogDesc": "La ruta del archivo para el registro de errores. El valor especial 'none' desactiva los registros de errores.",
"dnsLog": "Registro DNS",
"dnsLogDesc": "Si habilitar los registros de consulta DNS",
"maskAddress": "Enmascarar Dirección",
"maskAddressDesc": "Máscara de dirección IP, cuando se habilita, reemplazará automáticamente la dirección IP que aparece en el registro.",
"statistics": "Estadísticas",
"statsInboundUplink": "Estadísticas de Subida de Entrada",
"statsInboundUplinkDesc": "Habilita la recopilación de estadísticas para el tráfico ascendente de todos los proxies de entrada.",
"statsInboundDownlink": "Estadísticas de Bajada de Entrada",
"statsInboundDownlinkDesc": "Habilita la recopilación de estadísticas para el tráfico descendente de todos los proxies de entrada.",
"statsOutboundUplink": "Estadísticas de Subida de Salida",
"statsOutboundUplinkDesc": "Habilita la recopilación de estadísticas para el tráfico ascendente de todos los proxies de salida.",
"statsOutboundDownlink": "Estadísticas de Bajada de Salida",
"statsOutboundDownlinkDesc": "Habilita la recopilación de estadísticas para el tráfico descendente de todos los proxies de salida.",
"rules": {
"first": "Primero",
"last": "Último",
"up": "Arriba",
"down": "Abajo",
"source": "Fuente",
"dest": "Destino",
"inbound": "Entrante",
"outbound": "Saliente",
"balancer": "Equilibrador",
"info": "Información",
"add": "Agregar Regla",
"edit": "Editar Regla",
"useComma": "Elementos separados por comas"
},
"outbound": {
"addOutbound": "Agregar salida",
"addReverse": "Agregar reverso",
"editOutbound": "Editar salida",
"editReverse": "Editar reverso",
"reverseTag": "Etiqueta Reverso",
"reverseTagDesc": "Etiqueta de salida del proxy inverso simple VLESS. Dejar vacío para deshabilitar. Cuando se establece, las conexiones de este cliente pueden usarse como túnel de proxy inverso.",
"reverseTagPlaceholder": "etiqueta de salida (vacío para deshabilitar)",
"tag": "Etiqueta",
"tagDesc": "etiqueta única",
"address": "Dirección",
"reverse": "Reverso",
"domain": "Dominio",
"type": "Tipo",
"bridge": "puente",
"portal": "portal",
"link": "Enlace",
"intercon": "Interconexión",
"settings": "Configuración",
"accountInfo": "Información de la Cuenta",
"outboundStatus": "Estado de Salida",
"sendThrough": "Enviar a través de",
"test": "Probar",
"testResult": "Resultado de la prueba",
"testing": "Probando conexión...",
"testSuccess": "Prueba exitosa",
"testFailed": "Prueba fallida",
"testError": "Error al probar la salida",
"nordvpn": "NordVPN",
"accessToken": "Token de acceso",
"country": "País",
"server": "Servidor",
"city": "Ciudad",
"allCities": "Todas las ciudades",
"privateKey": "Clave privada",
"load": "Carga"
},
"balancer": {
"addBalancer": "Agregar equilibrador",
"editBalancer": "Editar balanceador",
"balancerStrategy": "Estrategia",
"balancerSelectors": "Selectores",
"tag": "Etiqueta",
"tagDesc": "etiqueta única",
"balancerDesc": "No es posible utilizar balancerTag y outboundTag al mismo tiempo. Si se utilizan al mismo tiempo, sólo funcionará outboundTag."
},
"wireguard": {
"secretKey": "Llave secreta",
"publicKey": "Llave pública",
"allowedIPs": "IP permitidas",
"endpoint": "Punto final",
"psk": "Clave precompartida",
"domainStrategy": "Estrategia de dominio"
},
"tun": {
"nameDesc": "El nombre de la interfaz TUN. El valor predeterminado es 'xray0'",
"mtuDesc": "Unidad Máxima de Transmisión. El tamaño máximo de los paquetes de datos. El valor predeterminado es 1500",
"userLevel": "Nivel de Usuario",
"userLevelDesc": "Todas las conexiones realizadas a través de este entrada utilizarán este nivel de usuario. El valor predeterminado es 0"
},
"dns": {
"enable": "Habilitar DNS",
"enableDesc": "Habilitar servidor DNS incorporado",
"tag": "Etiqueta de Entrada DNS",
"tagDesc": "Esta etiqueta estará disponible como una etiqueta de entrada en las reglas de enrutamiento.",
"clientIp": "IP del cliente",
"clientIpDesc": "Se utiliza para notificar al servidor la ubicación IP especificada durante las consultas DNS",
"disableCache": "Desactivar caché",
"disableCacheDesc": "Desactiva el almacenamiento en caché de DNS",
"disableFallback": "Desactivar respaldo",
"disableFallbackDesc": "Desactiva las consultas DNS de respaldo",
"disableFallbackIfMatch": "Desactivar respaldo si coincide",
"disableFallbackIfMatchDesc": "Desactiva las consultas DNS de respaldo cuando se acierta en la lista de dominios coincidentes del servidor DNS",
"enableParallelQuery": "Habilitar consulta paralela",
"enableParallelQueryDesc": "Habilitar consultas DNS paralelas a múltiples servidores para una resolución más rápida",
"strategy": "Estrategia de Consulta",
"strategyDesc": "Estrategia general para resolver nombres de dominio",
"add": "Agregar Servidor",
"edit": "Editar Servidor",
"domains": "Dominios",
"expectIPs": "IPs esperadas",
"unexpectIPs": "IPs inesperadas",
"useSystemHosts": "Usar Hosts del sistema",
"useSystemHostsDesc": "Usar el archivo hosts de un sistema instalado",
"serveStale": "Servir caducados",
"serveStaleDesc": "Devolver resultados caducados de la caché mientras se actualiza en segundo plano",
"serveExpiredTTL": "TTL de caducados",
"serveExpiredTTLDesc": "Validez (segundos) de las entradas caducadas en la caché; 0 = nunca caduca",
"timeoutMs": "Tiempo de espera (ms)",
"skipFallback": "Omitir respaldo",
"finalQuery": "Consulta final",
"hosts": "Hosts",
"hostsAdd": "Agregar Host",
"hostsEmpty": "No hay Hosts definidos",
"hostsDomain": "Dominio (ej. domain:example.com)",
"hostsValues": "IP o dominio — escribe y presiona Enter",
"usePreset": "Usar plantilla",
"dnsPresetTitle": "Plantillas DNS",
"dnsPresetFamily": "Familiar",
"clearAll": "Eliminar todos",
"clearAllTitle": "¿Eliminar todos los servidores DNS?",
"clearAllConfirm": "Esto eliminará todos los servidores DNS de la lista. No se puede deshacer."
},
"fakedns": {
"add": "Agregar DNS Falso",
"edit": "Editar DNS Falso",
"ipPool": "Subred del grupo de IP",
"poolSize": "Tamaño del grupo"
}
}
},
"tgbot": {
"keyboardClosed": "❌ Teclado cerrado!",
"noResult": "❗ ¡Sin resultados!",
"noQuery": "❌ ¡Consulta no encontrada! ¡Por favor, use el comando nuevamente!",
"wentWrong": "❌ ¡Algo salió mal!",
"noIpRecord": "❗ ¡No hay registro de IP!",
"noInbounds": "❗ ¡No se encontraron entradas!",
"unlimited": "♾ Ilimitado (Restablecer)",
"add": "Añadir",
"month": "Mes",
"months": "Meses",
"day": "Día",
"days": "Días",
"hours": "Horas",
"minutes": "Minutos",
"unknown": "Desconocido",
"inbounds": "Entradas",
"clients": "Clientes",
"offline": "🔴 Desconectado",
"online": "🟢 En línea",
"commands": {
"unknown": "❗ Comando desconocido",
"pleaseChoose": "👇 Por favor elige:\r\n",
"help": "🤖 ¡Bienvenido a este bot! Está diseñado para ofrecerte datos específicos del servidor y te permite hacer modificaciones según sea necesario.\r\n\r\n",
"start": "👋 Hola <i>{{ .Firstname }}</i>.\r\n",
"welcome": "🤖 Bienvenido al bot de gestión de <b>{{ .Hostname }}</b>.\r\n",
"status": "✅ ¡El bot está bien!",
"usage": "❗ ¡Por favor proporciona un texto para buscar!",
"getID": "🆔 Tu ID: <code>{{ .ID }}</code>",
"helpAdminCommands": "Para reiniciar Xray Core:\r\n<code>/restart</code>\r\n\r\nPara buscar un correo electrónico de cliente:\r\n<code>/usage [Correo electrónico]</code>\r\n\r\nPara buscar entradas (con estadísticas de cliente):\r\n<code>/inbound [Observación]</code>\r\n\r\nID de Chat de Telegram:\r\n<code>/id</code>",
"helpClientCommands": "Para buscar estadísticas, utiliza el siguiente comando:\r\n<code>/usage [Correo electrónico]</code>\r\n\r\nID de Chat de Telegram:\r\n<code>/id</code>",
"restartUsage": "\r\n\r\n<code>/restart</code>",
"restartSuccess": "✅ ¡Operación exitosa!",
"restartFailed": "❗ Error en la operación.\r\n\r\n<code>Error: {{ .Error }}</code>.",
"xrayNotRunning": "❗ Xray Core no está en ejecución.",
"startDesc": "Mostrar el menú principal",
"helpDesc": "Ayuda del bot",
"statusDesc": "Comprobar el estado del bot",
"idDesc": "Mostrar tu ID de Telegram"
},
"messages": {
"cpuThreshold": "🔴 El uso de CPU {{ .Percent }}% es mayor que el umbral {{ .Threshold }}%",
"selectUserFailed": "❌ ¡Error al seleccionar usuario!",
"userSaved": "✅ Usuario de Telegram guardado.",
"loginSuccess": "✅ Has iniciado sesión en el panel con éxito.\r\n",
"loginFailed": "❗️ Falló el inicio de sesión en el panel.\r\n",
"2faFailed": "Error de 2FA",
"report": "🕰 Informes programados: {{ .RunTime }}\r\n",
"datetime": "⏰ Fecha y Hora: {{ .DateTime }}\r\n",
"hostname": "💻 Nombre del Host: {{ .Hostname }}\r\n",
"version": "🚀 Versión de X-UI: {{ .Version }}\r\n",
"xrayVersion": "📡 Versión de Xray: {{ .XrayVersion }}\r\n",
"ipv6": "🌐 IPv6: {{ .IPv6 }}\r\n",
"ipv4": "🌐 IPv4: {{ .IPv4 }}\r\n",
"ip": "🌐 IP: {{ .IP }}\r\n",
"ips": "🔢 IPs:\r\n{{ .IPs }}\r\n",
"serverUpTime": "⏳ Tiempo de actividad del servidor: {{ .UpTime }} {{ .Unit }}\r\n",
"serverLoad": "📈 Carga del servidor: {{ .Load1 }}, {{ .Load2 }}, {{ .Load3 }}\r\n",
"serverMemory": "📋 Memoria del servidor: {{ .Current }}/{{ .Total }}\r\n",
"tcpCount": "🔹 Conteo de TCP: {{ .Count }}\r\n",
"udpCount": "🔸 Conteo de UDP: {{ .Count }}\r\n",
"traffic": "🚦 Tráfico: {{ .Total }} (↑{{ .Upload }},↓{{ .Download }})\r\n",
"xrayStatus": " Estado de Xray: {{ .State }}\r\n",
"username": "👤 Nombre de usuario: {{ .Username }}\r\n",
"reason": "❗️ Motivo: {{ .Reason }}\r\n",
"time": "⏰ Hora: {{ .Time }}\r\n",
"inbound": "📍 Inbound: {{ .Remark }}\r\n",
"port": "🔌 Puerto: {{ .Port }}\r\n",
"expire": "📅 Fecha de Vencimiento: {{ .Time }}\r\n",
"expireIn": "📅 Vence en: {{ .Time }}\r\n",
"active": "💡 Activo: {{ .Enable }}\r\n",
"enabled": "🚨 Habilitado: {{ .Enable }}\r\n",
"online": "🌐 Estado de conexión: {{ .Status }}\r\n",
"lastOnline": "🔙 Última conexión: {{ .Time }}\r\n",
"email": "📧 Email: {{ .Email }}\r\n",
"upload": "🔼 Subida: ↑{{ .Upload }}\r\n",
"download": "🔽 Bajada: ↓{{ .Download }}\r\n",
"total": "📊 Total: ↑↓{{ .UpDown }} / {{ .Total }}\r\n",
"TGUser": "👤 Usuario de Telegram: {{ .TelegramID }}\r\n",
"exhaustedMsg": "🚨 Agotado {{ .Type }}:\r\n",
"exhaustedCount": "🚨 Cantidad de Agotados {{ .Type }}:\r\n",
"onlinesCount": "🌐 Clientes en línea: {{ .Count }}\r\n",
"disabled": "🛑 Desactivado: {{ .Disabled }}\r\n",
"depleteSoon": "🔜 Se agotará pronto: {{ .Deplete }}\r\n\r\n",
"backupTime": "🗄 Hora de la Copia de Seguridad: {{ .Time }}\r\n",
"refreshedOn": "\r\n📋🔄 Actualizado en: {{ .Time }}\r\n\r\n",
"yes": "✅ Sí",
"no": "❌ No",
"received_id": "🔑📥 ID actualizado.",
"received_password": "🔑📥 Contraseña actualizada.",
"received_email": "📧📥 Correo electrónico actualizado.",
"received_comment": "💬📥 Comentario actualizado.",
"id_prompt": "🔑 ID predeterminado: {{ .ClientId }}\n\nIntroduce tu ID.",
"pass_prompt": "🔑 Contraseña predeterminada: {{ .ClientPassword }}\n\nIntroduce tu contraseña.",
"email_prompt": "📧 Correo electrónico predeterminado: {{ .ClientEmail }}\n\nIntroduce tu correo electrónico.",
"comment_prompt": "💬 Comentario predeterminado: {{ .ClientComment }}\n\nIntroduce tu comentario.",
"inbound_client_data_id": "🔄 Entrada: {{ .InboundRemark }}\n\n🔑 ID: {{ .ClientId }}\n📧 Correo: {{ .ClientEmail }}\n📊 Tráfico: {{ .ClientTraffic }}\n📅 Fecha de expiración: {{ .ClientExp }}\n🌐 Límite de IP: {{ .IpLimit }}\n💬 Comentario: {{ .ClientComment }}\n\n¡Ahora puedes agregar al cliente a la entrada!",
"inbound_client_data_pass": "🔄 Entrada: {{ .InboundRemark }}\n\n🔑 Contraseña: {{ .ClientPass }}\n📧 Correo: {{ .ClientEmail }}\n📊 Tráfico: {{ .ClientTraffic }}\n📅 Fecha de expiración: {{ .ClientExp }}\n🌐 Límite de IP: {{ .IpLimit }}\n💬 Comentario: {{ .ClientComment }}\n\n¡Ahora puedes agregar al cliente a la entrada!",
"cancel": "❌ ¡Proceso cancelado! \n\nPuedes /start de nuevo en cualquier momento. 🔄",
"error_add_client": "⚠️ Error:\n\n {{ .error }}",
"using_default_value": "Está bien, me quedaré con el valor predeterminado. 😊",
"incorrect_input": "Tu entrada no es válida.\nLas frases deben ser continuas sin espacios.\nEjemplo correcto: aaaaaa\nEjemplo incorrecto: aaa aaa 🚫",
"AreYouSure": "¿Estás seguro? 🤔",
"SuccessResetTraffic": "📧 Correo: {{ .ClientEmail }}\n🏁 Resultado: ✅ Éxito",
"FailedResetTraffic": "📧 Correo: {{ .ClientEmail }}\n🏁 Resultado: ❌ Fallido \n\n🛠 Error: [ {{ .ErrorMessage }} ]",
"FinishProcess": "🔚 Proceso de reinicio de tráfico finalizado para todos los clientes."
},
"buttons": {
"closeKeyboard": "❌ Cerrar Teclado",
"cancel": "❌ Cancelar",
"cancelReset": "❌ Cancelar Reinicio",
"cancelIpLimit": "❌ Cancelar Límite de IP",
"confirmResetTraffic": "✅ ¿Confirmar Reinicio de Tráfico?",
"confirmClearIps": "✅ ¿Confirmar Limpiar IPs?",
"confirmRemoveTGUser": "✅ ¿Confirmar Eliminar Usuario de Telegram?",
"confirmToggle": "✅ ¿Confirmar habilitar/deshabilitar usuario?",
"dbBackup": "Obtener Copia de Seguridad de BD",
"serverUsage": "Uso del Servidor",
"getInbounds": "Obtener Entradas",
"depleteSoon": "Pronto se Agotará",
"clientUsage": "Obtener Uso",
"onlines": "Clientes en línea",
"commands": "Comandos",
"refresh": "🔄 Actualizar",
"clearIPs": "❌ Limpiar IPs",
"removeTGUser": "❌ Eliminar Usuario de Telegram",
"selectTGUser": "👤 Seleccionar Usuario de Telegram",
"selectOneTGUser": "👤 Selecciona un usuario de telegram:",
"resetTraffic": "📈 Reiniciar Tráfico",
"resetExpire": "📅 Cambiar fecha de Vencimiento",
"ipLog": "🔢 Registro de IP",
"ipLimit": "🔢 Límite de IP",
"setTGUser": "👤 Establecer Usuario de Telegram",
"toggle": "🔘 Habilitar / Deshabilitar",
"custom": "🔢 Costumbre",
"confirmNumber": "✅ Confirmar: {{ .Num }}",
"confirmNumberAdd": "✅ Confirmar agregando: {{ .Num }}",
"limitTraffic": "🚧 Límite de tráfico",
"getBanLogs": "Registros de prohibición",
"allClients": "Todos los Clientes",
"addClient": "Añadir cliente",
"submitDisable": "Enviar como deshabilitado ☑️",
"submitEnable": "Enviar como habilitado ✅",
"use_default": "🏷️ Usar por defecto",
"change_id": "⚙️🔑 ID",
"change_password": "⚙️🔑 Contraseña",
"change_email": "⚙️📧 Correo electrónico",
"change_comment": "⚙️💬 Comentario",
"change_flow": "⚙️🚦 Flujo",
"ResetAllTraffics": "Reiniciar todo el tráfico",
"SortedTrafficUsageReport": "Informe de uso de tráfico ordenado"
},
"answers": {
"successfulOperation": "✅ ¡Exitosa!",
"errorOperation": "❗ Error en la Operación.",
"getInboundsFailed": "❌ Error al obtener las entradas",
"getClientsFailed": "❌ No se pudo obtener los clientes.",
"canceled": "❌ {{ .Email }} : Operación cancelada.",
"clientRefreshSuccess": "✅ {{ .Email }} : Cliente actualizado exitosamente.",
"IpRefreshSuccess": "✅ {{ .Email }} : IPs actualizadas exitosamente.",
"TGIdRefreshSuccess": "✅ {{ .Email }} : Usuario de Telegram del cliente actualizado exitosamente.",
"resetTrafficSuccess": "✅ {{ .Email }} : Tráfico reiniciado exitosamente.",
"setTrafficLimitSuccess": "✅ {{ .Email }} : Límite de Tráfico guardado exitosamente.",
"expireResetSuccess": "✅ {{ .Email }} : Días de vencimiento reiniciados exitosamente.",
"resetIpSuccess": "✅ {{ .Email }} : Límite de IP {{ .Count }} guardado exitosamente.",
"clearIpSuccess": "✅ {{ .Email }} : IPs limpiadas exitosamente.",
"getIpLog": "✅ {{ .Email }} : Obtener Registro de IP.",
"getUserInfo": "✅ {{ .Email }} : Obtener Información de Usuario de Telegram.",
"removedTGUserSuccess": "✅ {{ .Email }} : Usuario de Telegram eliminado exitosamente.",
"enableSuccess": "✅ {{ .Email }} : Habilitado exitosamente.",
"disableSuccess": "✅ {{ .Email }} : Deshabilitado exitosamente.",
"askToAddUserId": "¡No se encuentra su configuración!\r\nPor favor, pídale a su administrador que use su ChatID de usuario de Telegram en su(s) configuración(es).\r\n\r\nSu ChatID de usuario: <code>{{ .TgUserID }}</code>",
"chooseClient": "Elige un Cliente para Inbound {{ .Inbound }}",
"chooseInbound": "Elige un Inbound"
}
}
}