feat(ui): 第22条 改名 L-UI + 第14/21条 + 第18/19/20条前端

- 第22条 L-UI:登录页品牌名、侧栏 brand-text(收起态 L)、抽屉品牌、
  usePageTitle 默认标题(HTML 标题)、13 个语言文件里用户可见串中的
  3X-UI 字样(更新说明×2、TG 版本行)一并改为 L-UI;仓库/二进制/
  服务名/路径/内部包名不动
- 第18条:formatPanelVersion 对 V/A 系显示版本原样返回(新增单测);
  PanelUpdateModal 与首页动作条改用 display* 字段判更新与显示
- 第14条:首页运行时间卡片删除 Xray 半边与分隔线,只留 OS
- 第21条:节点表列宽 操作190→150/已启用80→64/客户端180→150/
  延迟100→84/心跳120→96、地址列 330;agent 行 IPv4·IPv6 单行
  (浅点分隔、沿用可见性 class),传统行不变
- 第20条:agent 行云朵按钮与移动端菜单改用「更新 Agent」文案;
  NodesPage 对 agent 行用无渠道选择的简单确认(传统行不变);
  schemas 增 agentUpdateState/Error/Target
- 第19条:节点编辑页(agent)拉 /panel/api/agent/install/:id 展示
  完整安装命令(master 可编辑、含 token 时完整命令+复制按钮);
  无 token 时展示无 token 命令+agent.json 路径提示,不报错不空白
- i18n 新增 4 键(updateAgent/updateAgentConfirmContent/
  agentInstallCommand/agentTokenNotStored)补齐全部 13 个语言文件
  (zh-CN 中文、其余英文),tsc 干净、panel-version 测试全过、
  i18n 失败仍为既有 forwarding 键集问题(第10条)零新增
This commit is contained in:
Muse
2026-10-22 13:30:57 +00:00
parent 2596880327
commit d46035708e
25 changed files with 270 additions and 74 deletions
+1 -1
View File
@@ -20,7 +20,7 @@ export function usePageTitle() {
useEffect(() => { useEffect(() => {
const key = TITLE_KEYS[pathname]; const key = TITLE_KEYS[pathname];
const title = key ? t(key) : '3X-UI'; const title = key ? t(key) : 'L-UI';
const host = window.location.hostname; const host = window.location.hostname;
document.title = host ? `${host} - ${title}` : title; document.title = host ? `${host} - ${title}` : title;
}, [pathname, t]); }, [pathname, t]);
+2 -2
View File
@@ -356,7 +356,7 @@ export default function AppSidebar() {
> >
<div className="sider-brand"> <div className="sider-brand">
<div className="brand-block"> <div className="brand-block">
<span className="brand-text">{railCollapsed ? '3X' : '3X-UI'}</span> <span className="brand-text">{railCollapsed ? 'L' : 'L-UI'}</span>
</div> </div>
{!railCollapsed && ( {!railCollapsed && (
<div className="brand-actions"> <div className="brand-actions">
@@ -420,7 +420,7 @@ export default function AppSidebar() {
> >
<div className="drawer-header"> <div className="drawer-header">
<div className="brand-block"> <div className="brand-block">
<span className="drawer-brand">3X-UI</span> <span className="drawer-brand">L-UI</span>
</div> </div>
<div className="drawer-header-actions"> <div className="drawer-header-actions">
<DocsButton ariaLabel={t('menu.docs') || 'Documentation'} /> <DocsButton ariaLabel={t('menu.docs') || 'Documentation'} />
+3
View File
@@ -22,6 +22,9 @@ function parseVersionParts(version: string): [number, number, number] | null {
export function formatPanelVersion(version: string | undefined | null): string { export function formatPanelVersion(version: string | undefined | null): string {
const v = (version || '').trim(); const v = (version || '').trim();
if (!v) return ''; if (!v) return '';
// This fork's display versions (master "V1.0.0", agent "A1.0.0") are
// shown exactly as written — never re-prefixed or re-cased.
if (/^[VA]\d+\.\d+\.\d+$/.test(v)) return v;
const normalized = v.replace(/^v/i, ''); const normalized = v.replace(/^v/i, '');
return /^\d/.test(normalized) ? `v${normalized}` : v; return /^\d/.test(normalized) ? `v${normalized}` : v;
} }
+11 -2
View File
@@ -172,8 +172,17 @@ export default function IndexPage() {
<OverviewActionBar <OverviewActionBar
isMobile={isMobile} isMobile={isMobile}
panelVersion={displayVersion} panelVersion={displayVersion}
latestVersion={panelUpdateInfo.latestVersion} latestVersion={
updateAvailable={panelUpdateInfo.updateAvailable} panelUpdateInfo.channel === 'dev'
? panelUpdateInfo.latestVersion
: panelUpdateInfo.displayLatestVersion || panelUpdateInfo.latestVersion
}
updateAvailable={
panelUpdateInfo.channel === 'dev'
? panelUpdateInfo.updateAvailable
: (panelUpdateInfo.displayUpdateAvailable ??
panelUpdateInfo.updateAvailable)
}
onOpenConfig={openConfig} onOpenConfig={openConfig}
onOpenBackup={() => setBackupOpen(true)} onOpenBackup={() => setBackupOpen(true)}
onOpenPanelUpdate={() => setPanelUpdateOpen(true)} onOpenPanelUpdate={() => setPanelUpdateOpen(true)}
+21 -6
View File
@@ -17,6 +17,11 @@ export interface PanelUpdateInfo {
currentCommit?: string; currentCommit?: string;
latestCommit?: string; latestCommit?: string;
updateAvailable: boolean; updateAvailable: boolean;
// V-series display versions (items 18/20); the stable channel's update
// decision and labels use these when present.
displayCurrentVersion?: string;
displayLatestVersion?: string;
displayUpdateAvailable?: boolean;
} }
interface BusyEvent { interface BusyEvent {
@@ -47,6 +52,13 @@ export default function PanelUpdateModal({
const isDev = info.channel === 'dev'; const isDev = info.channel === 'dev';
// On the stable channel the V-series display comparison decides (item
// 20); the dev channel keeps its commit-based decision.
const masterUpdateAvailable = isDev
? info.updateAvailable
: (info.displayUpdateAvailable ?? info.updateAvailable);
const displayLatest = info.displayLatestVersion || info.latestVersion;
async function pollUpdateStatus(expectedRunId: string): Promise<UpdateOutcome> { async function pollUpdateStatus(expectedRunId: string): Promise<UpdateOutcome> {
await PromiseUtil.sleep(5000); await PromiseUtil.sleep(5000);
const deadline = Date.now() + 90_000; const deadline = Date.now() + 90_000;
@@ -85,13 +97,14 @@ export default function PanelUpdateModal({
title: t('pages.index.panelUpdateDialog'), title: t('pages.index.panelUpdateDialog'),
content: t('pages.index.panelUpdateDialogDesc').replace( content: t('pages.index.panelUpdateDialogDesc').replace(
'#version#', '#version#',
info.latestVersion || '', isDev ? info.latestVersion || '' : displayLatest || '',
), ),
okText: t('confirm'), okText: t('confirm'),
cancelText: t('cancel'), cancelText: t('cancel'),
onOk: async () => { onOk: async () => {
const baseTip = t('pages.index.dontRefresh'); const baseTip = t('pages.index.dontRefresh');
const tip = info.latestVersion ? `${baseTip} (${info.latestVersion})` : baseTip; const tipVersion = isDev ? info.latestVersion : displayLatest;
const tip = tipVersion ? `${baseTip} (${tipVersion})` : baseTip;
onClose(); onClose();
onBusy({ busy: true, tip }); onBusy({ busy: true, tip });
const result = await HttpUtil.post<{ runId: string }>('/panel/api/server/updatePanel'); const result = await HttpUtil.post<{ runId: string }>('/panel/api/server/updatePanel');
@@ -128,7 +141,7 @@ export default function PanelUpdateModal({
<> <>
{contextHolder} {contextHolder}
<Modal open={open} title={t('pages.index.updatePanel')} footer={null} onCancel={onClose}> <Modal open={open} title={t('pages.index.updatePanel')} footer={null} onCancel={onClose}>
{info.updateAvailable && ( {masterUpdateAvailable && (
<Alert <Alert
type="warning" type="warning"
className="mb-12" className="mb-12"
@@ -166,12 +179,14 @@ export default function PanelUpdateModal({
</Tag> </Tag>
)} )}
</div> </div>
{info.updateAvailable ? ( {masterUpdateAvailable ? (
<div className="version-list-item"> <div className="version-list-item">
<span> <span>
{isDev ? t('pages.index.latestCommit') : t('pages.index.latestPanelVersion')} {isDev ? t('pages.index.latestCommit') : t('pages.index.latestPanelVersion')}
</span> </span>
<Tag color="purple">{(isDev ? info.latestCommit : info.latestVersion) || '-'}</Tag> <Tag color="purple">
{(isDev ? info.latestCommit : formatPanelVersion(displayLatest)) || '-'}
</Tag>
</div> </div>
) : ( ) : (
<div className="version-list-item"> <div className="version-list-item">
@@ -184,7 +199,7 @@ export default function PanelUpdateModal({
<div className="actions-row"> <div className="actions-row">
<Button <Button
type="primary" type="primary"
disabled={!info.updateAvailable} disabled={!masterUpdateAvailable}
onClick={updatePanel} onClick={updatePanel}
icon={<CloudDownloadOutlined />} icon={<CloudDownloadOutlined />}
> >
+5 -12
View File
@@ -29,18 +29,11 @@ export default function SystemStrip({ status, showIp, onToggleIp }: SystemStripP
<ClockCircleOutlined /> <ClockCircleOutlined />
{t('pages.index.uptime')} {t('pages.index.uptime')}
</div> </div>
<div className="ov-strip-split"> {/* The lite master runs no local xray core, so the uptime card
<div> shows the OS uptime only (the Xray half always read 0s). */}
<div className="ov-strip-sub">Xray</div> <div>
<div className="ov-strip-value"> <div className="ov-strip-sub">OS</div>
{TimeFormatter.formatSecond(status.appStats.uptime)} <div className="ov-strip-value">{TimeFormatter.formatSecond(status.uptime)}</div>
</div>
</div>
<span className="ov-strip-split-sep" />
<div>
<div className="ov-strip-sub">OS</div>
<div className="ov-strip-value">{TimeFormatter.formatSecond(status.uptime)}</div>
</div>
</div> </div>
</div> </div>
+1 -1
View File
@@ -179,7 +179,7 @@ export default function LoginPage() {
) : ( ) : (
<div className="login-card"> <div className="login-card">
<div className="brand"> <div className="brand">
<span className="brand-name">3X-UI</span> <span className="brand-name">L-UI</span>
<span className="brand-accent" aria-hidden="true" /> <span className="brand-accent" aria-hidden="true" />
</div> </div>
<h2 className="welcome"> <h2 className="welcome">
+83 -2
View File
@@ -1,4 +1,4 @@
import { useMemo, useState } from 'react'; import { useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { import {
Alert, Alert,
@@ -16,7 +16,7 @@ import {
import { FormProvider, useForm, useWatch } from 'react-hook-form'; import { FormProvider, useForm, useWatch } from 'react-hook-form';
import type { NodeRecord } from '@/api/queries/useNodesQuery'; import type { NodeRecord } from '@/api/queries/useNodesQuery';
import type { RemoteInboundOption } from '@/api/queries/useNodeMutations'; import type { RemoteInboundOption } from '@/api/queries/useNodeMutations';
import type { Msg } from '@/utils'; import { HttpUtil, type Msg } from '@/utils';
import { NodeFormSchema, type NodeFormValues, type ProbeResult } from '@/schemas/node'; import { NodeFormSchema, type NodeFormValues, type ProbeResult } from '@/schemas/node';
import { FormField, rhfZodValidate } from '@/components/form/rhf'; import { FormField, rhfZodValidate } from '@/components/form/rhf';
import { useOutboundTagGroups } from '@/api/queries/useOutboundTags'; import { useOutboundTagGroups } from '@/api/queries/useOutboundTags';
@@ -81,6 +81,17 @@ export default function NodeFormModal({
const [agentToken, setAgentToken] = useState<string | null>(null); const [agentToken, setAgentToken] = useState<string | null>(null);
const [agentNodeName, setAgentNodeName] = useState(''); const [agentNodeName, setAgentNodeName] = useState('');
const [agentMasterUrl, setAgentMasterUrl] = useState(''); const [agentMasterUrl, setAgentMasterUrl] = useState('');
// Edit mode (item 19): the stored install material for an existing agent
// node, fetched from the master; null until loaded / for non-agent nodes.
// Keyed by node id so a stale result from a previously edited node is
// never shown (visibility is derived during render below).
const [editInstall, setEditInstall] = useState<{
nodeId: number;
name: string;
token: string;
hasToken: boolean;
} | null>(null);
const [editMasterUrl, setEditMasterUrl] = useState('');
const scheme = useWatch({ control: methods.control, name: 'scheme' }) ?? 'https'; const scheme = useWatch({ control: methods.control, name: 'scheme' }) ?? 'https';
const tlsVerifyMode = useWatch({ control: methods.control, name: 'tlsVerifyMode' }) ?? 'verify'; const tlsVerifyMode = useWatch({ control: methods.control, name: 'tlsVerifyMode' }) ?? 'verify';
const inboundSyncMode = useWatch({ control: methods.control, name: 'inboundSyncMode' }) ?? 'all'; const inboundSyncMode = useWatch({ control: methods.control, name: 'inboundSyncMode' }) ?? 'all';
@@ -136,6 +147,39 @@ export default function NodeFormModal({
setTestResult(null); setTestResult(null);
} }
// Load the stored install material when editing an agent node so the
// full install command can be re-displayed (item 19). Nodes created
// before tokens were stored answer hasToken=false until the agent's
// next authenticated request backfills the token.
const editNodeId = mode === 'edit' && isAgent ? (node?.id ?? 0) : 0;
useEffect(() => {
if (!open || !editNodeId) return;
let cancelled = false;
HttpUtil.get<{ name: string; token: string; hasToken: boolean }>(
`/panel/api/agent/install/${editNodeId}`,
).then((msg) => {
if (!cancelled && msg?.success && msg.obj) {
setEditInstall({ nodeId: editNodeId, ...msg.obj });
setEditMasterUrl(currentPanelMasterUrl());
}
});
return () => {
cancelled = true;
};
}, [open, editNodeId]);
const shownInstall = editInstall && editInstall.nodeId === editNodeId ? editInstall : null;
const editInstallCmd = useMemo(() => {
if (!shownInstall || !editMasterUrl) return '';
const base =
`bash <(curl -fL https://git.881218.xyz/rogue/3x-ui-agent/raw/branch/main/install-agent.sh)` +
` --master ${editMasterUrl}`;
return shownInstall.hasToken
? `${base} --token ${shownInstall.token} --name ${shownInstall.name}`
: `${base} --name ${shownInstall.name}`;
}, [shownInstall, editMasterUrl]);
const title = useMemo( const title = useMemo(
() => (mode === 'edit' ? t('pages.nodes.editNode') : t('pages.nodes.addNode')), () => (mode === 'edit' ? t('pages.nodes.editNode') : t('pages.nodes.addNode')),
[mode, t], [mode, t],
@@ -391,6 +435,43 @@ export default function NodeFormModal({
</Row> </Row>
)} )}
{mode === 'edit' && isAgent && shownInstall && (
<div style={{ marginBottom: 16 }}>
<div style={{ marginBottom: 8 }}>{t('pages.nodes.agentInstallCommand')}</div>
<p>{t('pages.nodes.agentMasterUrlHint')}</p>
<Input
value={editMasterUrl}
onChange={(e) => setEditMasterUrl(e.target.value.trim())}
style={{ marginBottom: 12, fontFamily: 'monospace' }}
/>
{!shownInstall.hasToken && (
<Alert
type="warning"
showIcon
style={{ marginBottom: 12 }}
title={t('pages.nodes.agentTokenNotStored')}
/>
)}
<Input.TextArea
value={editInstallCmd}
readOnly
rows={4}
style={{ fontFamily: 'monospace', marginBottom: 12 }}
/>
<Button
disabled={!editInstallCmd}
onClick={() => {
navigator.clipboard.writeText(editInstallCmd).then(
() => messageApi.success(t('pages.nodes.agentTokenCopied')),
() => messageApi.error(t('pages.nodes.agentTokenCopyFailed')),
);
}}
>
{t('pages.nodes.copyToken')}
</Button>
</div>
)}
{!isAgent && ( {!isAgent && (
<FormField <FormField
label={t('pages.nodes.allowPrivateAddress')} label={t('pages.nodes.allowPrivateAddress')}
+34 -15
View File
@@ -239,7 +239,7 @@ export default function NodeList({
{ {
title: t('pages.nodes.actions'), title: t('pages.nodes.actions'),
align: 'center', align: 'center',
width: 190, width: 150,
render: (_value, record) => render: (_value, record) =>
record.transitive ? ( record.transitive ? (
<Tooltip <Tooltip
@@ -264,13 +264,23 @@ export default function NodeList({
/> />
</Tooltip> </Tooltip>
{isUpdateEligible(record) && ( {isUpdateEligible(record) && (
<Tooltip title={t('pages.nodes.updatePanel')}> <Tooltip
title={t(
record.nodeType === 'agent'
? 'pages.nodes.updateAgent'
: 'pages.nodes.updatePanel',
)}
>
<Button <Button
type="text" type="text"
size="small" size="small"
style={{ fontSize: 16 }} style={{ fontSize: 16 }}
icon={<CloudDownloadOutlined />} icon={<CloudDownloadOutlined />}
aria-label={t('pages.nodes.updatePanel')} aria-label={t(
record.nodeType === 'agent'
? 'pages.nodes.updateAgent'
: 'pages.nodes.updatePanel',
)}
onClick={() => onUpdateNode(record)} onClick={() => onUpdateNode(record)}
/> />
</Tooltip> </Tooltip>
@@ -303,7 +313,7 @@ export default function NodeList({
title: t('pages.nodes.enable'), title: t('pages.nodes.enable'),
dataIndex: 'enable', dataIndex: 'enable',
align: 'center', align: 'center',
width: 80, width: 64,
render: (_value, record) => render: (_value, record) =>
record.transitive ? ( record.transitive ? (
<span style={{ opacity: 0.4 }}>—</span> <span style={{ opacity: 0.4 }}>—</span>
@@ -362,17 +372,20 @@ export default function NodeList({
</span> </span>
), ),
dataIndex: 'url', dataIndex: 'url',
width: 330,
ellipsis: true, ellipsis: true,
render: (_value, record) => { render: (_value, record) => {
if (record.nodeType === 'agent') { if (record.nodeType === 'agent') {
// Agent nodes have no panel to link to: show the host IPs the // Agent nodes have no panel to link to: show the host IPs the
// agent reports with its heartbeat as plain text (P13). // agent reports with its heartbeat as plain text on one line
// (P13, layout per item 21).
const ips = [record.ipv4, record.ipv6].filter(Boolean) as string[]; const ips = [record.ipv4, record.ipv6].filter(Boolean) as string[];
return ( return (
<span className={showAddress ? 'address-visible' : 'address-hidden'}> <span className={showAddress ? 'address-visible' : 'address-hidden'}>
{ips.length > 0 {ips.length > 0
? ips.map((ip) => ( ? ips.map((ip, i) => (
<span key={ip} style={{ display: 'block' }}> <span key={ip}>
{i > 0 && <span style={{ opacity: 0.45 }}> · </span>}
{ip} {ip}
</span> </span>
)) ))
@@ -436,10 +449,11 @@ export default function NodeList({
dataIndex: 'panelVersion', dataIndex: 'panelVersion',
align: 'center', align: 'center',
render: (_value, record) => { render: (_value, record) => {
// Agent rows carry an "agent <version>" label, not an upstream // Agent rows carry the A-series display version ("A1.0.0"), not
// panel version: the update badge must never light up for them // an upstream panel version: the update badge must never light
// (the version comparator falls back to string inequality for // up for them (the version comparator falls back to string
// unparseable versions, which would always differ) (P13). // inequality for unparseable versions, which would always
// differ) (P13, item 18).
const canUpdate = const canUpdate =
record.nodeType !== 'agent' && record.nodeType !== 'agent' &&
isUpdateEligible(record) && isUpdateEligible(record) &&
@@ -474,7 +488,7 @@ export default function NodeList({
{ {
title: t('clients'), title: t('clients'),
align: 'center', align: 'center',
width: 180, width: 150,
render: (_value, record) => ( render: (_value, record) => (
<Space size={2}> <Space size={2}>
<Tag className="client-count-tag" style={{ margin: 0, padding: '0 2px' }}> <Tag className="client-count-tag" style={{ margin: 0, padding: '0 2px' }}>
@@ -527,7 +541,7 @@ export default function NodeList({
title: t('pages.nodes.latency'), title: t('pages.nodes.latency'),
dataIndex: 'latencyMs', dataIndex: 'latencyMs',
align: 'center', align: 'center',
width: 100, width: 84,
render: (_value, record) => render: (_value, record) =>
record.latencyMs && record.latencyMs > 0 ? `${record.latencyMs} ms` : '-', record.latencyMs && record.latencyMs > 0 ? `${record.latencyMs} ms` : '-',
}, },
@@ -535,7 +549,7 @@ export default function NodeList({
title: t('pages.nodes.lastHeartbeat'), title: t('pages.nodes.lastHeartbeat'),
dataIndex: 'lastHeartbeat', dataIndex: 'lastHeartbeat',
align: 'center', align: 'center',
width: 120, width: 96,
render: (_value, record) => relativeTime(record.lastHeartbeat), render: (_value, record) => relativeTime(record.lastHeartbeat),
}, },
], ],
@@ -652,7 +666,12 @@ export default function NodeList({
key: 'update', key: 'update',
label: ( label: (
<> <>
<CloudDownloadOutlined /> {t('pages.nodes.updatePanel')} <CloudDownloadOutlined />{' '}
{t(
record.nodeType === 'agent'
? 'pages.nodes.updateAgent'
: 'pages.nodes.updatePanel',
)}
</> </>
), ),
onClick: () => onUpdateNode(record), onClick: () => onUpdateNode(record),
+12
View File
@@ -232,6 +232,18 @@ export default function NodesPage() {
const onUpdateNode = useCallback( const onUpdateNode = useCallback(
(node: NodeRecord) => { (node: NodeRecord) => {
// Agent nodes update through the master-recorded intent (item 20):
// there is no channel to pick, so the confirm is a plain message.
if (node.nodeType === 'agent') {
modal.confirm({
title: t('pages.nodes.updateConfirmTitle', { count: 1 }),
content: t('pages.nodes.updateAgentConfirmContent'),
okText: t('update'),
cancelText: t('cancel'),
onOk: () => runUpdate([node.id], false),
});
return;
}
devRef.current = false; devRef.current = false;
modal.confirm({ modal.confirm({
title: t('pages.nodes.updateConfirmTitle', { count: 1 }), title: t('pages.nodes.updateConfirmTitle', { count: 1 }),
+4
View File
@@ -51,6 +51,10 @@ export const NodeRecordSchema = z
// Rendered as plain text in the address column for agent rows. // Rendered as plain text in the address column for agent rows.
ipv4: z.string().optional(), ipv4: z.string().optional(),
ipv6: z.string().optional(), ipv6: z.string().optional(),
// Item 20: last one-click agent update outcome, agent rows only.
agentUpdateState: z.string().optional(),
agentUpdateError: z.string().optional(),
agentUpdateTarget: z.string().optional(),
}) })
.loose(); .loose();
+9 -1
View File
@@ -40,7 +40,9 @@ describe('formatPanelVersion', () => {
it('does not double up the v on already-prefixed tags', () => { it('does not double up the v on already-prefixed tags', () => {
expect(formatPanelVersion('v3.4.0')).toBe('v3.4.0'); expect(formatPanelVersion('v3.4.0')).toBe('v3.4.0');
expect(formatPanelVersion('V3.4.0')).toBe('v3.4.0'); // An uppercase-V three-part version is this fork's master display
// form and stays verbatim (see the V/A case below).
expect(formatPanelVersion('V3.4.0')).toBe('V3.4.0');
}); });
it('shows dev builds verbatim without a v prefix', () => { it('shows dev builds verbatim without a v prefix', () => {
@@ -53,4 +55,10 @@ describe('formatPanelVersion', () => {
expect(formatPanelVersion(undefined)).toBe(''); expect(formatPanelVersion(undefined)).toBe('');
expect(formatPanelVersion('?')).toBe('?'); expect(formatPanelVersion('?')).toBe('?');
}); });
it('shows this fork’s V/A display versions verbatim', () => {
expect(formatPanelVersion('V1.0.0')).toBe('V1.0.0');
expect(formatPanelVersion('A1.0.0')).toBe('A1.0.0');
expect(formatPanelVersion('A1.0.9')).toBe('A1.0.9');
});
}); });
+7 -3
View File
@@ -128,7 +128,7 @@
"storage": "تخزين", "storage": "تخزين",
"memory": "الذاكرة", "memory": "الذاكرة",
"updatePanel": "تحديث البانل", "updatePanel": "تحديث البانل",
"panelUpdateDesc": "ده هيحدث 3X-UI لآخر إصدار وهيعيد تشغيل خدمة البانل.", "panelUpdateDesc": "ده هيحدث L-UI لآخر إصدار وهيعيد تشغيل خدمة البانل.",
"currentPanelVersion": "إصدار البانل الحالي", "currentPanelVersion": "إصدار البانل الحالي",
"latestPanelVersion": "أحدث إصدار للبانل", "latestPanelVersion": "أحدث إصدار للبانل",
"panelUpToDate": "البانل محدث لآخر إصدار", "panelUpToDate": "البانل محدث لآخر إصدار",
@@ -146,7 +146,7 @@
"sent": "مرسل", "sent": "مرسل",
"received": "مستقبل", "received": "مستقبل",
"panelUpdateDialog": "هل فعلاً عايز تحدث البانل؟", "panelUpdateDialog": "هل فعلاً عايز تحدث البانل؟",
"panelUpdateDialogDesc": "ده هيحدث 3X-UI للإصدار #version# وهيعيد تشغيل البانل.", "panelUpdateDialogDesc": "ده هيحدث L-UI للإصدار #version# وهيعيد تشغيل البانل.",
"panelUpdateStartedPopover": "بدأ تحديث البانل", "panelUpdateStartedPopover": "بدأ تحديث البانل",
"panelUpdateFailedTitle": "فشل تحديث البانل", "panelUpdateFailedTitle": "فشل تحديث البانل",
"panelUpdateFailedDesc": "لم يكتمل التحديث بنجاح. تحقق من سجلات الخادم، أو نفّذ الأمر «x-ui update» من سطر الأوامر.", "panelUpdateFailedDesc": "لم يكتمل التحديث بنجاح. تحقق من سجلات الخادم، أو نفّذ الأمر «x-ui update» من سطر الأوامر.",
@@ -850,6 +850,10 @@
"updateAvailable": "تحديث متاح", "updateAvailable": "تحديث متاح",
"updateConfirmTitle": "تحديث {count} عقدة إلى أحدث إصدار؟", "updateConfirmTitle": "تحديث {count} عقدة إلى أحدث إصدار؟",
"updateConfirmContent": "كل عقدة محددة ستنزّل أحدث إصدار وتعيد التشغيل عليه. يتم تحديث العقد المفعّلة والمتصلة فقط.", "updateConfirmContent": "كل عقدة محددة ستنزّل أحدث إصدار وتعيد التشغيل عليه. يتم تحديث العقد المفعّلة والمتصلة فقط.",
"updateAgent": "Update Agent",
"updateAgentConfirmContent": "The agent on this node will download the latest release, verify it, and restart onto it. If the update fails, the node keeps running the current version.",
"agentInstallCommand": "Install Command",
"agentTokenNotStored": "This node's token is not stored on the master yet, so the command below has no token. The token is saved on the node itself in /etc/x-ui/agent.json; it will be filled in here automatically after the agent's next authenticated request.",
"updateDevChannel": "التحديث إلى قناة التطوير (أحدث كومِت)", "updateDevChannel": "التحديث إلى قناة التطوير (أحدث كومِت)",
"testConnection": "اختبار الاتصال", "testConnection": "اختبار الاتصال",
"connectionOk": "الاتصال شغال ({ms} ms)", "connectionOk": "الاتصال شغال ({ms} ms)",
@@ -1747,7 +1751,7 @@
"report": "🕰 التقارير المجدولة: {{ .RunTime }}\r\n", "report": "🕰 التقارير المجدولة: {{ .RunTime }}\r\n",
"datetime": "⏰ التاريخ والوقت: {{ .DateTime }}\r\n", "datetime": "⏰ التاريخ والوقت: {{ .DateTime }}\r\n",
"hostname": "💻 المضيف: {{ .Hostname }}\r\n", "hostname": "💻 المضيف: {{ .Hostname }}\r\n",
"version": "🚀 نسخة 3X-UI: {{ .Version }}\r\n", "version": "🚀 نسخة L-UI: {{ .Version }}\r\n",
"xrayVersion": "📡 نسخة Xray: {{ .XrayVersion }}\r\n", "xrayVersion": "📡 نسخة Xray: {{ .XrayVersion }}\r\n",
"ipv6": "🌐 IPv6: {{ .IPv6 }}\r\n", "ipv6": "🌐 IPv6: {{ .IPv6 }}\r\n",
"ipv4": "🌐 IPv4: {{ .IPv4 }}\r\n", "ipv4": "🌐 IPv4: {{ .IPv4 }}\r\n",
+7 -3
View File
@@ -128,7 +128,7 @@
"storage": "Storage", "storage": "Storage",
"memory": "RAM", "memory": "RAM",
"updatePanel": "Update Panel", "updatePanel": "Update Panel",
"panelUpdateDesc": "This will update 3X-UI itself to the latest release and restart the panel service.", "panelUpdateDesc": "This will update L-UI itself to the latest release and restart the panel service.",
"currentPanelVersion": "Current panel version", "currentPanelVersion": "Current panel version",
"latestPanelVersion": "Latest panel version", "latestPanelVersion": "Latest panel version",
"panelUpToDate": "Panel is up to date", "panelUpToDate": "Panel is up to date",
@@ -146,7 +146,7 @@
"sent": "Sent", "sent": "Sent",
"received": "Received", "received": "Received",
"panelUpdateDialog": "Do you really want to update the panel?", "panelUpdateDialog": "Do you really want to update the panel?",
"panelUpdateDialogDesc": "This will update 3X-UI to #version# and restart the panel service.", "panelUpdateDialogDesc": "This will update L-UI to #version# and restart the panel service.",
"panelUpdateStartedPopover": "Panel update started", "panelUpdateStartedPopover": "Panel update started",
"panelUpdateFailedTitle": "Panel update failed", "panelUpdateFailedTitle": "Panel update failed",
"panelUpdateFailedDesc": "The update did not finish successfully. Check the server logs, or run 'x-ui update' from the command line.", "panelUpdateFailedDesc": "The update did not finish successfully. Check the server logs, or run 'x-ui update' from the command line.",
@@ -990,6 +990,10 @@
"updateAvailable": "Update available", "updateAvailable": "Update available",
"updateConfirmTitle": "Update {count} node(s) to the latest version?", "updateConfirmTitle": "Update {count} node(s) to the latest version?",
"updateConfirmContent": "Each selected node downloads the latest release and restarts onto it. Only enabled, online nodes are updated.", "updateConfirmContent": "Each selected node downloads the latest release and restarts onto it. Only enabled, online nodes are updated.",
"updateAgent": "Update Agent",
"updateAgentConfirmContent": "The agent on this node will download the latest release, verify it, and restart onto it. If the update fails, the node keeps running the current version.",
"agentInstallCommand": "Install Command",
"agentTokenNotStored": "This node's token is not stored on the master yet, so the command below has no token. The token is saved on the node itself in /etc/x-ui/agent.json; it will be filled in here automatically after the agent's next authenticated request.",
"updateDevChannel": "Update to Dev channel (latest commit)", "updateDevChannel": "Update to Dev channel (latest commit)",
"testConnection": "Test Connection", "testConnection": "Test Connection",
"connectionOk": "Connection OK ({ms} ms)", "connectionOk": "Connection OK ({ms} ms)",
@@ -1769,7 +1773,7 @@
"report": "🕰 Scheduled Reports: {{ .RunTime }}\r\n", "report": "🕰 Scheduled Reports: {{ .RunTime }}\r\n",
"datetime": "⏰ Date&Time: {{ .DateTime }}\r\n", "datetime": "⏰ Date&Time: {{ .DateTime }}\r\n",
"hostname": "💻 Host: {{ .Hostname }}\r\n", "hostname": "💻 Host: {{ .Hostname }}\r\n",
"version": "🚀 3X-UI Version: {{ .Version }}\r\n", "version": "🚀 L-UI Version: {{ .Version }}\r\n",
"xrayVersion": "📡 Xray Version: {{ .XrayVersion }}\r\n", "xrayVersion": "📡 Xray Version: {{ .XrayVersion }}\r\n",
"ipv6": "🌐 IPv6: {{ .IPv6 }}\r\n", "ipv6": "🌐 IPv6: {{ .IPv6 }}\r\n",
"ipv4": "🌐 IPv4: {{ .IPv4 }}\r\n", "ipv4": "🌐 IPv4: {{ .IPv4 }}\r\n",
+6 -2
View File
@@ -128,7 +128,7 @@
"storage": "Almacenamiento", "storage": "Almacenamiento",
"memory": "Memoria", "memory": "Memoria",
"updatePanel": "Actualizar panel", "updatePanel": "Actualizar panel",
"panelUpdateDesc": "Esto actualizará 3X-UI a la última versión y reiniciará el servicio del panel.", "panelUpdateDesc": "Esto actualizará L-UI a la última versión y reiniciará el servicio del panel.",
"currentPanelVersion": "Versión actual del panel", "currentPanelVersion": "Versión actual del panel",
"latestPanelVersion": "Última versión del panel", "latestPanelVersion": "Última versión del panel",
"panelUpToDate": "El panel está actualizado", "panelUpToDate": "El panel está actualizado",
@@ -146,7 +146,7 @@
"sent": "Enviado", "sent": "Enviado",
"received": "Recibido", "received": "Recibido",
"panelUpdateDialog": "¿Deseas actualizar el panel?", "panelUpdateDialog": "¿Deseas actualizar el panel?",
"panelUpdateDialogDesc": "Esto actualizará 3X-UI a la versión #version# y reiniciará el servicio del panel.", "panelUpdateDialogDesc": "Esto actualizará L-UI a la versión #version# y reiniciará el servicio del panel.",
"panelUpdateStartedPopover": "Actualización del panel iniciada", "panelUpdateStartedPopover": "Actualización del panel iniciada",
"panelUpdateFailedTitle": "Error al actualizar el panel", "panelUpdateFailedTitle": "Error al actualizar el panel",
"panelUpdateFailedDesc": "La actualización no se completó correctamente. Revisa los registros del servidor o ejecuta 'x-ui update' desde la línea de comandos.", "panelUpdateFailedDesc": "La actualización no se completó correctamente. Revisa los registros del servidor o ejecuta 'x-ui update' desde la línea de comandos.",
@@ -850,6 +850,10 @@
"updateAvailable": "Actualización disponible", "updateAvailable": "Actualización disponible",
"updateConfirmTitle": "¿Actualizar {count} nodo(s) a la última versión?", "updateConfirmTitle": "¿Actualizar {count} nodo(s) a la última versión?",
"updateConfirmContent": "Cada nodo seleccionado descarga la última versión y se reinicia con ella. Solo se actualizan los nodos habilitados y en línea.", "updateConfirmContent": "Cada nodo seleccionado descarga la última versión y se reinicia con ella. Solo se actualizan los nodos habilitados y en línea.",
"updateAgent": "Update Agent",
"updateAgentConfirmContent": "The agent on this node will download the latest release, verify it, and restart onto it. If the update fails, the node keeps running the current version.",
"agentInstallCommand": "Install Command",
"agentTokenNotStored": "This node's token is not stored on the master yet, so the command below has no token. The token is saved on the node itself in /etc/x-ui/agent.json; it will be filled in here automatically after the agent's next authenticated request.",
"updateDevChannel": "Actualizar al canal de desarrollo (último commit)", "updateDevChannel": "Actualizar al canal de desarrollo (último commit)",
"testConnection": "Probar conexión", "testConnection": "Probar conexión",
"connectionOk": "Conexión correcta ({ms} ms)", "connectionOk": "Conexión correcta ({ms} ms)",
+6 -2
View File
@@ -128,7 +128,7 @@
"storage": "ذخیره‌سازی", "storage": "ذخیره‌سازی",
"memory": "حافظه", "memory": "حافظه",
"updatePanel": "به‌روزرسانی پنل", "updatePanel": "به‌روزرسانی پنل",
"panelUpdateDesc": "این عملیات 3X-UI را به آخرین نسخه به‌روزرسانی می‌کند و سرویس پنل را مجدداً راه‌اندازی می‌کند.", "panelUpdateDesc": "این عملیات L-UI را به آخرین نسخه به‌روزرسانی می‌کند و سرویس پنل را مجدداً راه‌اندازی می‌کند.",
"currentPanelVersion": "نسخه فعلی پنل", "currentPanelVersion": "نسخه فعلی پنل",
"latestPanelVersion": "آخرین نسخه پنل", "latestPanelVersion": "آخرین نسخه پنل",
"panelUpToDate": "پنل به‌روز است", "panelUpToDate": "پنل به‌روز است",
@@ -146,7 +146,7 @@
"sent": "ارسال شده", "sent": "ارسال شده",
"received": "دریافت شده", "received": "دریافت شده",
"panelUpdateDialog": "آیا مطمئن هستید که می‌خواهید پنل را به‌روزرسانی کنید؟", "panelUpdateDialog": "آیا مطمئن هستید که می‌خواهید پنل را به‌روزرسانی کنید؟",
"panelUpdateDialogDesc": "این 3X-UI را به نسخه #version# به‌روزرسانی کرده و سرویس پنل را مجدداً راه‌اندازی می‌کند.", "panelUpdateDialogDesc": "این L-UI را به نسخه #version# به‌روزرسانی کرده و سرویس پنل را مجدداً راه‌اندازی می‌کند.",
"panelUpdateStartedPopover": "به‌روزرسانی پنل آغاز شد", "panelUpdateStartedPopover": "به‌روزرسانی پنل آغاز شد",
"panelUpdateFailedTitle": "به‌روزرسانی پنل ناموفق بود", "panelUpdateFailedTitle": "به‌روزرسانی پنل ناموفق بود",
"panelUpdateFailedDesc": "به‌روزرسانی با موفقیت به پایان نرسید. گزارش‌های سرور را بررسی کنید یا دستور «x-ui update» را از خط فرمان اجرا کنید.", "panelUpdateFailedDesc": "به‌روزرسانی با موفقیت به پایان نرسید. گزارش‌های سرور را بررسی کنید یا دستور «x-ui update» را از خط فرمان اجرا کنید.",
@@ -850,6 +850,10 @@
"updateAvailable": "به‌روزرسانی موجود", "updateAvailable": "به‌روزرسانی موجود",
"updateConfirmTitle": "{count} نود به آخرین نسخه به‌روزرسانی شوند؟", "updateConfirmTitle": "{count} نود به آخرین نسخه به‌روزرسانی شوند؟",
"updateConfirmContent": "هر نود انتخاب‌شده آخرین نسخه را دانلود و روی آن ری‌استارت می‌شود. فقط نودهای فعال و آنلاین به‌روزرسانی می‌شوند.", "updateConfirmContent": "هر نود انتخاب‌شده آخرین نسخه را دانلود و روی آن ری‌استارت می‌شود. فقط نودهای فعال و آنلاین به‌روزرسانی می‌شوند.",
"updateAgent": "Update Agent",
"updateAgentConfirmContent": "The agent on this node will download the latest release, verify it, and restart onto it. If the update fails, the node keeps running the current version.",
"agentInstallCommand": "Install Command",
"agentTokenNotStored": "This node's token is not stored on the master yet, so the command below has no token. The token is saved on the node itself in /etc/x-ui/agent.json; it will be filled in here automatically after the agent's next authenticated request.",
"updateDevChannel": "به‌روزرسانی به کانال دِو (آخرین کامیت)", "updateDevChannel": "به‌روزرسانی به کانال دِو (آخرین کامیت)",
"testConnection": "تست اتصال", "testConnection": "تست اتصال",
"connectionOk": "اتصال موفق ({ms} میلی‌ثانیه)", "connectionOk": "اتصال موفق ({ms} میلی‌ثانیه)",
+7 -3
View File
@@ -128,7 +128,7 @@
"storage": "Penyimpanan", "storage": "Penyimpanan",
"memory": "Memori", "memory": "Memori",
"updatePanel": "Perbarui Panel", "updatePanel": "Perbarui Panel",
"panelUpdateDesc": "Ini akan memperbarui 3X-UI ke rilis terbaru dan me-restart layanan panel.", "panelUpdateDesc": "Ini akan memperbarui L-UI ke rilis terbaru dan me-restart layanan panel.",
"currentPanelVersion": "Versi panel saat ini", "currentPanelVersion": "Versi panel saat ini",
"latestPanelVersion": "Versi panel terbaru", "latestPanelVersion": "Versi panel terbaru",
"panelUpToDate": "Panel sudah terbaru", "panelUpToDate": "Panel sudah terbaru",
@@ -146,7 +146,7 @@
"sent": "Dikirim", "sent": "Dikirim",
"received": "Diterima", "received": "Diterima",
"panelUpdateDialog": "Apakah Anda benar-benar ingin memperbarui panel?", "panelUpdateDialog": "Apakah Anda benar-benar ingin memperbarui panel?",
"panelUpdateDialogDesc": "Ini akan memperbarui 3X-UI ke #version# dan me-restart layanan panel.", "panelUpdateDialogDesc": "Ini akan memperbarui L-UI ke #version# dan me-restart layanan panel.",
"panelUpdateStartedPopover": "Pembaruan panel dimulai", "panelUpdateStartedPopover": "Pembaruan panel dimulai",
"panelUpdateFailedTitle": "Pembaruan panel gagal", "panelUpdateFailedTitle": "Pembaruan panel gagal",
"panelUpdateFailedDesc": "Pembaruan tidak selesai dengan sukses. Periksa log server, atau jalankan 'x-ui update' dari baris perintah.", "panelUpdateFailedDesc": "Pembaruan tidak selesai dengan sukses. Periksa log server, atau jalankan 'x-ui update' dari baris perintah.",
@@ -850,6 +850,10 @@
"updateAvailable": "Pembaruan tersedia", "updateAvailable": "Pembaruan tersedia",
"updateConfirmTitle": "Perbarui {count} node ke versi terbaru?", "updateConfirmTitle": "Perbarui {count} node ke versi terbaru?",
"updateConfirmContent": "Setiap node terpilih mengunduh rilis terbaru dan memulai ulang. Hanya node aktif dan online yang diperbarui.", "updateConfirmContent": "Setiap node terpilih mengunduh rilis terbaru dan memulai ulang. Hanya node aktif dan online yang diperbarui.",
"updateAgent": "Update Agent",
"updateAgentConfirmContent": "The agent on this node will download the latest release, verify it, and restart onto it. If the update fails, the node keeps running the current version.",
"agentInstallCommand": "Install Command",
"agentTokenNotStored": "This node's token is not stored on the master yet, so the command below has no token. The token is saved on the node itself in /etc/x-ui/agent.json; it will be filled in here automatically after the agent's next authenticated request.",
"updateDevChannel": "Perbarui ke kanal dev (commit terbaru)", "updateDevChannel": "Perbarui ke kanal dev (commit terbaru)",
"testConnection": "Tes Koneksi", "testConnection": "Tes Koneksi",
"connectionOk": "Koneksi OK ({ms} ms)", "connectionOk": "Koneksi OK ({ms} ms)",
@@ -1747,7 +1751,7 @@
"report": "🕰 Laporan Terjadwal: {{ .RunTime }}\r\n", "report": "🕰 Laporan Terjadwal: {{ .RunTime }}\r\n",
"datetime": "⏰ Tanggal & Waktu: {{ .DateTime }}\r\n", "datetime": "⏰ Tanggal & Waktu: {{ .DateTime }}\r\n",
"hostname": "💻 Host: {{ .Hostname }}\r\n", "hostname": "💻 Host: {{ .Hostname }}\r\n",
"version": "🚀 Versi 3X-UI: {{ .Version }}\r\n", "version": "🚀 Versi L-UI: {{ .Version }}\r\n",
"xrayVersion": "📡 Versi Xray: {{ .XrayVersion }}\r\n", "xrayVersion": "📡 Versi Xray: {{ .XrayVersion }}\r\n",
"ipv6": "🌐 IPv6: {{ .IPv6 }}\r\n", "ipv6": "🌐 IPv6: {{ .IPv6 }}\r\n",
"ipv4": "🌐 IPv4: {{ .IPv4 }}\r\n", "ipv4": "🌐 IPv4: {{ .IPv4 }}\r\n",
+6 -2
View File
@@ -128,7 +128,7 @@
"storage": "ストレージ", "storage": "ストレージ",
"memory": "メモリ", "memory": "メモリ",
"updatePanel": "パネルを更新", "updatePanel": "パネルを更新",
"panelUpdateDesc": "これにより3X-UIが最新リリースに更新され、パネルサービスが再起動されます。", "panelUpdateDesc": "これによりL-UIが最新リリースに更新され、パネルサービスが再起動されます。",
"currentPanelVersion": "現在のパネルバージョン", "currentPanelVersion": "現在のパネルバージョン",
"latestPanelVersion": "最新のパネルバージョン", "latestPanelVersion": "最新のパネルバージョン",
"panelUpToDate": "パネルは最新です", "panelUpToDate": "パネルは最新です",
@@ -146,7 +146,7 @@
"sent": "送信", "sent": "送信",
"received": "受信", "received": "受信",
"panelUpdateDialog": "本当にパネルを更新しますか?", "panelUpdateDialog": "本当にパネルを更新しますか?",
"panelUpdateDialogDesc": "これにより3X-UIが#version#に更新され、パネルサービスが再起動されます。", "panelUpdateDialogDesc": "これによりL-UIが#version#に更新され、パネルサービスが再起動されます。",
"panelUpdateStartedPopover": "パネルの更新を開始しました", "panelUpdateStartedPopover": "パネルの更新を開始しました",
"panelUpdateFailedTitle": "パネルの更新に失敗しました", "panelUpdateFailedTitle": "パネルの更新に失敗しました",
"panelUpdateFailedDesc": "更新が正常に完了しませんでした。サーバーのログを確認するか、コマンドラインで「x-ui update」を実行してください。", "panelUpdateFailedDesc": "更新が正常に完了しませんでした。サーバーのログを確認するか、コマンドラインで「x-ui update」を実行してください。",
@@ -850,6 +850,10 @@
"updateAvailable": "更新あり", "updateAvailable": "更新あり",
"updateConfirmTitle": "{count} 個のノードを最新バージョンに更新しますか?", "updateConfirmTitle": "{count} 個のノードを最新バージョンに更新しますか?",
"updateConfirmContent": "選択した各ノードは最新リリースをダウンロードして再起動します。有効かつオンラインのノードのみが更新されます。", "updateConfirmContent": "選択した各ノードは最新リリースをダウンロードして再起動します。有効かつオンラインのノードのみが更新されます。",
"updateAgent": "Update Agent",
"updateAgentConfirmContent": "The agent on this node will download the latest release, verify it, and restart onto it. If the update fails, the node keeps running the current version.",
"agentInstallCommand": "Install Command",
"agentTokenNotStored": "This node's token is not stored on the master yet, so the command below has no token. The token is saved on the node itself in /etc/x-ui/agent.json; it will be filled in here automatically after the agent's next authenticated request.",
"updateDevChannel": "開発チャンネルに更新(最新コミット)", "updateDevChannel": "開発チャンネルに更新(最新コミット)",
"testConnection": "接続テスト", "testConnection": "接続テスト",
"connectionOk": "接続OK ({ms} ms)", "connectionOk": "接続OK ({ms} ms)",
+7 -3
View File
@@ -128,7 +128,7 @@
"storage": "Armazenamento", "storage": "Armazenamento",
"memory": "Memória", "memory": "Memória",
"updatePanel": "Atualizar painel", "updatePanel": "Atualizar painel",
"panelUpdateDesc": "Isso atualizará o 3X-UI para a versão mais recente e reiniciará o serviço do painel.", "panelUpdateDesc": "Isso atualizará o L-UI para a versão mais recente e reiniciará o serviço do painel.",
"currentPanelVersion": "Versão atual do painel", "currentPanelVersion": "Versão atual do painel",
"latestPanelVersion": "Última versão do painel", "latestPanelVersion": "Última versão do painel",
"panelUpToDate": "O painel está atualizado", "panelUpToDate": "O painel está atualizado",
@@ -146,7 +146,7 @@
"sent": "Enviado", "sent": "Enviado",
"received": "Recebido", "received": "Recebido",
"panelUpdateDialog": "Deseja realmente atualizar o painel?", "panelUpdateDialog": "Deseja realmente atualizar o painel?",
"panelUpdateDialogDesc": "Isso atualizará o 3X-UI para #version# e reiniciará o serviço do painel.", "panelUpdateDialogDesc": "Isso atualizará o L-UI para #version# e reiniciará o serviço do painel.",
"panelUpdateStartedPopover": "Atualização do painel iniciada", "panelUpdateStartedPopover": "Atualização do painel iniciada",
"panelUpdateFailedTitle": "Falha ao atualizar o painel", "panelUpdateFailedTitle": "Falha ao atualizar o painel",
"panelUpdateFailedDesc": "A atualização não foi concluída com sucesso. Verifique os logs do servidor ou execute 'x-ui update' na linha de comando.", "panelUpdateFailedDesc": "A atualização não foi concluída com sucesso. Verifique os logs do servidor ou execute 'x-ui update' na linha de comando.",
@@ -850,6 +850,10 @@
"updateAvailable": "Atualização disponível", "updateAvailable": "Atualização disponível",
"updateConfirmTitle": "Atualizar {count} nó(s) para a versão mais recente?", "updateConfirmTitle": "Atualizar {count} nó(s) para a versão mais recente?",
"updateConfirmContent": "Cada nó selecionado baixa a versão mais recente e reinicia nela. Apenas nós ativos e online são atualizados.", "updateConfirmContent": "Cada nó selecionado baixa a versão mais recente e reinicia nela. Apenas nós ativos e online são atualizados.",
"updateAgent": "Update Agent",
"updateAgentConfirmContent": "The agent on this node will download the latest release, verify it, and restart onto it. If the update fails, the node keeps running the current version.",
"agentInstallCommand": "Install Command",
"agentTokenNotStored": "This node's token is not stored on the master yet, so the command below has no token. The token is saved on the node itself in /etc/x-ui/agent.json; it will be filled in here automatically after the agent's next authenticated request.",
"updateDevChannel": "Atualizar para o canal de desenvolvimento (último commit)", "updateDevChannel": "Atualizar para o canal de desenvolvimento (último commit)",
"testConnection": "Testar conexão", "testConnection": "Testar conexão",
"connectionOk": "Conexão OK ({ms} ms)", "connectionOk": "Conexão OK ({ms} ms)",
@@ -1747,7 +1751,7 @@
"report": "🕰 Relatórios agendados: {{ .RunTime }}\r\n", "report": "🕰 Relatórios agendados: {{ .RunTime }}\r\n",
"datetime": "⏰ Data&Hora: {{ .DateTime }}\r\n", "datetime": "⏰ Data&Hora: {{ .DateTime }}\r\n",
"hostname": "💻 Host: {{ .Hostname }}\r\n", "hostname": "💻 Host: {{ .Hostname }}\r\n",
"version": "🚀 Versão 3X-UI: {{ .Version }}\r\n", "version": "🚀 Versão L-UI: {{ .Version }}\r\n",
"xrayVersion": "📡 Versão Xray: {{ .XrayVersion }}\r\n", "xrayVersion": "📡 Versão Xray: {{ .XrayVersion }}\r\n",
"ipv6": "🌐 IPv6: {{ .IPv6 }}\r\n", "ipv6": "🌐 IPv6: {{ .IPv6 }}\r\n",
"ipv4": "🌐 IPv4: {{ .IPv4 }}\r\n", "ipv4": "🌐 IPv4: {{ .IPv4 }}\r\n",
+6 -2
View File
@@ -128,7 +128,7 @@
"storage": "Диск", "storage": "Диск",
"memory": "Память", "memory": "Память",
"updatePanel": "Обновить панель", "updatePanel": "Обновить панель",
"panelUpdateDesc": "Это обновит 3X-UI до последнего релиза и перезапустит сервис панели.", "panelUpdateDesc": "Это обновит L-UI до последнего релиза и перезапустит сервис панели.",
"currentPanelVersion": "Текущая версия панели", "currentPanelVersion": "Текущая версия панели",
"latestPanelVersion": "Последняя версия панели", "latestPanelVersion": "Последняя версия панели",
"panelUpToDate": "Панель обновлена", "panelUpToDate": "Панель обновлена",
@@ -146,7 +146,7 @@
"sent": "Отправлено", "sent": "Отправлено",
"received": "Получено", "received": "Получено",
"panelUpdateDialog": "Вы действительно хотите обновить панель?", "panelUpdateDialog": "Вы действительно хотите обновить панель?",
"panelUpdateDialogDesc": "Это обновит 3X-UI до версии #version# и перезапустит сервис панели.", "panelUpdateDialogDesc": "Это обновит L-UI до версии #version# и перезапустит сервис панели.",
"panelUpdateStartedPopover": "Обновление панели началось", "panelUpdateStartedPopover": "Обновление панели началось",
"panelUpdateFailedTitle": "Не удалось обновить панель", "panelUpdateFailedTitle": "Не удалось обновить панель",
"panelUpdateFailedDesc": "Обновление не завершилось успешно. Проверьте журналы сервера или выполните 'x-ui update' в командной строке.", "panelUpdateFailedDesc": "Обновление не завершилось успешно. Проверьте журналы сервера или выполните 'x-ui update' в командной строке.",
@@ -850,6 +850,10 @@
"updateAvailable": "Доступно обновление", "updateAvailable": "Доступно обновление",
"updateConfirmTitle": "Обновить {count} узлов до последней версии?", "updateConfirmTitle": "Обновить {count} узлов до последней версии?",
"updateConfirmContent": "Каждый выбранный узел загрузит последний релиз и перезапустится. Обновляются только включённые узлы в сети.", "updateConfirmContent": "Каждый выбранный узел загрузит последний релиз и перезапустится. Обновляются только включённые узлы в сети.",
"updateAgent": "Update Agent",
"updateAgentConfirmContent": "The agent on this node will download the latest release, verify it, and restart onto it. If the update fails, the node keeps running the current version.",
"agentInstallCommand": "Install Command",
"agentTokenNotStored": "This node's token is not stored on the master yet, so the command below has no token. The token is saved on the node itself in /etc/x-ui/agent.json; it will be filled in here automatically after the agent's next authenticated request.",
"updateDevChannel": "Обновить до канала разработки (последний коммит)", "updateDevChannel": "Обновить до канала разработки (последний коммит)",
"testConnection": "Проверить соединение", "testConnection": "Проверить соединение",
"connectionOk": "Соединение в порядке ({ms} мс)", "connectionOk": "Соединение в порядке ({ms} мс)",
+7 -3
View File
@@ -128,7 +128,7 @@
"storage": "Depolama", "storage": "Depolama",
"memory": "RAM", "memory": "RAM",
"updatePanel": "Paneli Güncelle", "updatePanel": "Paneli Güncelle",
"panelUpdateDesc": "Bu işlem 3X-UI'yi en son sürüme güncelleyecek ve panel servisini yeniden başlatacaktır.", "panelUpdateDesc": "Bu işlem L-UI'yi en son sürüme güncelleyecek ve panel servisini yeniden başlatacaktır.",
"currentPanelVersion": "Mevcut panel sürümü", "currentPanelVersion": "Mevcut panel sürümü",
"latestPanelVersion": "Panelin en son sürümü", "latestPanelVersion": "Panelin en son sürümü",
"panelUpToDate": "Panel güncel", "panelUpToDate": "Panel güncel",
@@ -146,7 +146,7 @@
"sent": "Gönderilen", "sent": "Gönderilen",
"received": "Alınan", "received": "Alınan",
"panelUpdateDialog": "Gerçekten paneli güncellemek istiyor musunuz?", "panelUpdateDialog": "Gerçekten paneli güncellemek istiyor musunuz?",
"panelUpdateDialogDesc": "Bu işlem 3X-UI'yi #version# sürümüne güncelleyecek ve panel servisini yeniden başlatacaktır.", "panelUpdateDialogDesc": "Bu işlem L-UI'yi #version# sürümüne güncelleyecek ve panel servisini yeniden başlatacaktır.",
"panelUpdateStartedPopover": "Panel güncellemesi başlatıldı", "panelUpdateStartedPopover": "Panel güncellemesi başlatıldı",
"panelUpdateFailedTitle": "Panel güncellemesi başarısız oldu", "panelUpdateFailedTitle": "Panel güncellemesi başarısız oldu",
"panelUpdateFailedDesc": "Güncelleme başarıyla tamamlanamadı. Sunucu günlüklerini kontrol edin veya komut satırından 'x-ui update' çalıştırın.", "panelUpdateFailedDesc": "Güncelleme başarıyla tamamlanamadı. Sunucu günlüklerini kontrol edin veya komut satırından 'x-ui update' çalıştırın.",
@@ -850,6 +850,10 @@
"updateAvailable": "Güncelleme mevcut", "updateAvailable": "Güncelleme mevcut",
"updateConfirmTitle": "{count} düğüm en son sürüme güncellensin mi?", "updateConfirmTitle": "{count} düğüm en son sürüme güncellensin mi?",
"updateConfirmContent": "Seçilen her düğüm en son sürümü indirir ve yeniden başlatılır. Yalnızca etkin ve çevrimiçi düğümler güncellenir.", "updateConfirmContent": "Seçilen her düğüm en son sürümü indirir ve yeniden başlatılır. Yalnızca etkin ve çevrimiçi düğümler güncellenir.",
"updateAgent": "Update Agent",
"updateAgentConfirmContent": "The agent on this node will download the latest release, verify it, and restart onto it. If the update fails, the node keeps running the current version.",
"agentInstallCommand": "Install Command",
"agentTokenNotStored": "This node's token is not stored on the master yet, so the command below has no token. The token is saved on the node itself in /etc/x-ui/agent.json; it will be filled in here automatically after the agent's next authenticated request.",
"updateDevChannel": "Dev kanalına güncelle (son commit)", "updateDevChannel": "Dev kanalına güncelle (son commit)",
"testConnection": "Bağlantıyı Test Et", "testConnection": "Bağlantıyı Test Et",
"connectionOk": "Bağlantı tamam ({ms} ms)", "connectionOk": "Bağlantı tamam ({ms} ms)",
@@ -1747,7 +1751,7 @@
"report": "🕰 Planlanmış Raporlar: {{ .RunTime }}\r\n", "report": "🕰 Planlanmış Raporlar: {{ .RunTime }}\r\n",
"datetime": "⏰ Tarih ve Saat: {{ .DateTime }}\r\n", "datetime": "⏰ Tarih ve Saat: {{ .DateTime }}\r\n",
"hostname": "💻 Sunucu: {{ .Hostname }}", "hostname": "💻 Sunucu: {{ .Hostname }}",
"version": "🚀 3X-UI Sürümü: {{ .Version }}\r\n", "version": "🚀 L-UI Sürümü: {{ .Version }}\r\n",
"xrayVersion": "📡 Xray Sürümü: {{ .XrayVersion }}\r\n", "xrayVersion": "📡 Xray Sürümü: {{ .XrayVersion }}\r\n",
"ipv6": "🌐 IPv6: {{ .IPv6 }}", "ipv6": "🌐 IPv6: {{ .IPv6 }}",
"ipv4": "🌐 IPv4: {{ .IPv4 }}", "ipv4": "🌐 IPv4: {{ .IPv4 }}",
+7 -3
View File
@@ -128,7 +128,7 @@
"storage": "Сховище", "storage": "Сховище",
"memory": "Пам’ять", "memory": "Пам’ять",
"updatePanel": "Оновити панель", "updatePanel": "Оновити панель",
"panelUpdateDesc": "Це оновить 3X-UI до останнього релізу та перезапустить сервіс панелі.", "panelUpdateDesc": "Це оновить L-UI до останнього релізу та перезапустить сервіс панелі.",
"currentPanelVersion": "Поточна версія панелі", "currentPanelVersion": "Поточна версія панелі",
"latestPanelVersion": "Остання версія панелі", "latestPanelVersion": "Остання версія панелі",
"panelUpToDate": "Панель оновлено", "panelUpToDate": "Панель оновлено",
@@ -146,7 +146,7 @@
"sent": "Відправлено", "sent": "Відправлено",
"received": "Отримано", "received": "Отримано",
"panelUpdateDialog": "Ви дійсно хочете оновити панель?", "panelUpdateDialog": "Ви дійсно хочете оновити панель?",
"panelUpdateDialogDesc": "Це оновить 3X-UI до #version# та перезапустить сервіс панелі.", "panelUpdateDialogDesc": "Це оновить L-UI до #version# та перезапустить сервіс панелі.",
"panelUpdateStartedPopover": "Розпочато оновлення панелі", "panelUpdateStartedPopover": "Розпочато оновлення панелі",
"panelUpdateFailedTitle": "Не вдалося оновити панель", "panelUpdateFailedTitle": "Не вдалося оновити панель",
"panelUpdateFailedDesc": "Оновлення не завершилося успішно. Перевірте журнали сервера або виконайте 'x-ui update' у командному рядку.", "panelUpdateFailedDesc": "Оновлення не завершилося успішно. Перевірте журнали сервера або виконайте 'x-ui update' у командному рядку.",
@@ -850,6 +850,10 @@
"updateAvailable": "Доступне оновлення", "updateAvailable": "Доступне оновлення",
"updateConfirmTitle": "Оновити {count} вузлів до останньої версії?", "updateConfirmTitle": "Оновити {count} вузлів до останньої версії?",
"updateConfirmContent": "Кожен вибраний вузол завантажить останній реліз і перезапуститься. Оновлюються лише увімкнені вузли в мережі.", "updateConfirmContent": "Кожен вибраний вузол завантажить останній реліз і перезапуститься. Оновлюються лише увімкнені вузли в мережі.",
"updateAgent": "Update Agent",
"updateAgentConfirmContent": "The agent on this node will download the latest release, verify it, and restart onto it. If the update fails, the node keeps running the current version.",
"agentInstallCommand": "Install Command",
"agentTokenNotStored": "This node's token is not stored on the master yet, so the command below has no token. The token is saved on the node itself in /etc/x-ui/agent.json; it will be filled in here automatically after the agent's next authenticated request.",
"updateDevChannel": "Оновити до каналу розробки (останній коміт)", "updateDevChannel": "Оновити до каналу розробки (останній коміт)",
"testConnection": "Перевірити з'єднання", "testConnection": "Перевірити з'єднання",
"connectionOk": "З'єднання в порядку ({ms} мс)", "connectionOk": "З'єднання в порядку ({ms} мс)",
@@ -1747,7 +1751,7 @@
"report": "🕰 Заплановані звіти: {{ .RunTime }}\r\n", "report": "🕰 Заплановані звіти: {{ .RunTime }}\r\n",
"datetime": "⏰ Дата й час: {{ .DateTime }}\r\n", "datetime": "⏰ Дата й час: {{ .DateTime }}\r\n",
"hostname": "💻 Хост: {{ .Hostname }}\r\n", "hostname": "💻 Хост: {{ .Hostname }}\r\n",
"version": "🚀 3X-UI Версія: {{ .Version }}\r\n", "version": "🚀 L-UI Версія: {{ .Version }}\r\n",
"xrayVersion": "📡 Xray Версія: {{ .XrayVersion }}\r\n", "xrayVersion": "📡 Xray Версія: {{ .XrayVersion }}\r\n",
"ipv6": "🌐 IPv6: {{ .IPv6 }}\r\n", "ipv6": "🌐 IPv6: {{ .IPv6 }}\r\n",
"ipv4": "🌐 IPv4: {{ .IPv4 }}\r\n", "ipv4": "🌐 IPv4: {{ .IPv4 }}\r\n",
+6 -2
View File
@@ -128,7 +128,7 @@
"storage": "Lưu trữ", "storage": "Lưu trữ",
"memory": "Bộ nhớ", "memory": "Bộ nhớ",
"updatePanel": "Cập nhật Panel", "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.", "panelUpdateDesc": "Điều này sẽ cập nhật L-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", "currentPanelVersion": "Phiên bản panel hiện tại",
"latestPanelVersion": "Phiên bản panel mới nhất", "latestPanelVersion": "Phiên bản panel mới nhất",
"panelUpToDate": "Panel đã được cập nhật", "panelUpToDate": "Panel đã được cập nhật",
@@ -146,7 +146,7 @@
"sent": "Đã gửi", "sent": "Đã gửi",
"received": "Đã nhận", "received": "Đã nhận",
"panelUpdateDialog": "Bạn có chắc muốn cập nhật panel khô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.", "panelUpdateDialogDesc": "Điều này sẽ cập nhật L-UI lên #version# và khởi động lại dịch vụ panel.",
"panelUpdateStartedPopover": "Bắt đầu cập nhật panel", "panelUpdateStartedPopover": "Bắt đầu cập nhật panel",
"panelUpdateFailedTitle": "Cập nhật panel thất bại", "panelUpdateFailedTitle": "Cập nhật panel thất bại",
"panelUpdateFailedDesc": "Bản cập nhật không hoàn tất thành công. Hãy kiểm tra nhật ký máy chủ, hoặc chạy 'x-ui update' từ dòng lệnh.", "panelUpdateFailedDesc": "Bản cập nhật không hoàn tất thành công. Hãy kiểm tra nhật ký máy chủ, hoặc chạy 'x-ui update' từ dòng lệnh.",
@@ -850,6 +850,10 @@
"updateAvailable": "Có bản cập nhật", "updateAvailable": "Có bản cập nhật",
"updateConfirmTitle": "Cập nhật {count} node lên phiên bản mới nhất?", "updateConfirmTitle": "Cập nhật {count} node lên phiên bản mới nhất?",
"updateConfirmContent": "Mỗi node đã chọn sẽ tải bản phát hành mới nhất và khởi động lại. Chỉ các node đang bật và trực tuyến được cập nhật.", "updateConfirmContent": "Mỗi node đã chọn sẽ tải bản phát hành mới nhất và khởi động lại. Chỉ các node đang bật và trực tuyến được cập nhật.",
"updateAgent": "Update Agent",
"updateAgentConfirmContent": "The agent on this node will download the latest release, verify it, and restart onto it. If the update fails, the node keeps running the current version.",
"agentInstallCommand": "Install Command",
"agentTokenNotStored": "This node's token is not stored on the master yet, so the command below has no token. The token is saved on the node itself in /etc/x-ui/agent.json; it will be filled in here automatically after the agent's next authenticated request.",
"updateDevChannel": "Cập nhật lên kênh phát triển (commit mới nhất)", "updateDevChannel": "Cập nhật lên kênh phát triển (commit mới nhất)",
"testConnection": "Kiểm tra kết nối", "testConnection": "Kiểm tra kết nối",
"connectionOk": "Kết nối OK ({ms} ms)", "connectionOk": "Kết nối OK ({ms} ms)",
+6 -2
View File
@@ -128,7 +128,7 @@
"storage": "存储", "storage": "存储",
"memory": "内存", "memory": "内存",
"updatePanel": "更新面板", "updatePanel": "更新面板",
"panelUpdateDesc": "这将把 3X-UI 更新到最新版本并重启面板服务。", "panelUpdateDesc": "这将把 L-UI 更新到最新版本并重启面板服务。",
"currentPanelVersion": "当前面板版本", "currentPanelVersion": "当前面板版本",
"latestPanelVersion": "最新面板版本", "latestPanelVersion": "最新面板版本",
"panelUpToDate": "面板已是最新", "panelUpToDate": "面板已是最新",
@@ -146,7 +146,7 @@
"sent": "已发送", "sent": "已发送",
"received": "已接收", "received": "已接收",
"panelUpdateDialog": "您确定要更新面板吗?", "panelUpdateDialog": "您确定要更新面板吗?",
"panelUpdateDialogDesc": "这将把 3X-UI 更新到 #version# 并重启面板服务。", "panelUpdateDialogDesc": "这将把 L-UI 更新到 #version# 并重启面板服务。",
"panelUpdateStartedPopover": "已开始更新面板", "panelUpdateStartedPopover": "已开始更新面板",
"panelUpdateFailedTitle": "面板更新失败", "panelUpdateFailedTitle": "面板更新失败",
"panelUpdateFailedDesc": "更新未成功完成。请检查服务器日志,或在命令行运行「x-ui update」。", "panelUpdateFailedDesc": "更新未成功完成。请检查服务器日志,或在命令行运行「x-ui update」。",
@@ -872,6 +872,10 @@
"updateAvailable": "有可用更新", "updateAvailable": "有可用更新",
"updateConfirmTitle": "将 {count} 个节点更新到最新版本?", "updateConfirmTitle": "将 {count} 个节点更新到最新版本?",
"updateConfirmContent": "每个所选节点会下载最新版本并重启。仅更新已启用且在线的节点。", "updateConfirmContent": "每个所选节点会下载最新版本并重启。仅更新已启用且在线的节点。",
"updateAgent": "更新 Agent",
"updateAgentConfirmContent": "该节点上的 agent 将下载最新发行版、校验后重启切换;更新失败时节点继续运行当前版本。",
"agentInstallCommand": "安装命令",
"agentTokenNotStored": "该节点的 token 尚未存入主控,下面的命令不含 token。token 保存在节点本机的 /etc/x-ui/agent.json 中;agent 下次通过校验的请求后会自动回填到这里。",
"updateDevChannel": "更新到开发通道(最新提交)", "updateDevChannel": "更新到开发通道(最新提交)",
"testConnection": "测试连接", "testConnection": "测试连接",
"connectionOk": "连接正常 ({ms} ms)", "connectionOk": "连接正常 ({ms} ms)",
+6 -2
View File
@@ -128,7 +128,7 @@
"storage": "儲存", "storage": "儲存",
"memory": "記憶體", "memory": "記憶體",
"updatePanel": "更新面板", "updatePanel": "更新面板",
"panelUpdateDesc": "這將把 3X-UI 更新到最新版本並重新啟動面板服務。", "panelUpdateDesc": "這將把 L-UI 更新到最新版本並重新啟動面板服務。",
"currentPanelVersion": "目前面板版本", "currentPanelVersion": "目前面板版本",
"latestPanelVersion": "最新面板版本", "latestPanelVersion": "最新面板版本",
"panelUpToDate": "面板已是最新", "panelUpToDate": "面板已是最新",
@@ -146,7 +146,7 @@
"sent": "已發送", "sent": "已發送",
"received": "已接收", "received": "已接收",
"panelUpdateDialog": "您確定要更新面板嗎?", "panelUpdateDialog": "您確定要更新面板嗎?",
"panelUpdateDialogDesc": "這將把 3X-UI 更新到 #version# 並重新啟動面板服務。", "panelUpdateDialogDesc": "這將把 L-UI 更新到 #version# 並重新啟動面板服務。",
"panelUpdateStartedPopover": "面板更新已開始", "panelUpdateStartedPopover": "面板更新已開始",
"panelUpdateFailedTitle": "面板更新失敗", "panelUpdateFailedTitle": "面板更新失敗",
"panelUpdateFailedDesc": "更新未成功完成。請檢查伺服器日誌,或在命令列執行「x-ui update」。", "panelUpdateFailedDesc": "更新未成功完成。請檢查伺服器日誌,或在命令列執行「x-ui update」。",
@@ -850,6 +850,10 @@
"updateAvailable": "有可用更新", "updateAvailable": "有可用更新",
"updateConfirmTitle": "將 {count} 個節點更新到最新版本?", "updateConfirmTitle": "將 {count} 個節點更新到最新版本?",
"updateConfirmContent": "每個所選節點會下載最新版本並重新啟動。僅更新已啟用且在線的節點。", "updateConfirmContent": "每個所選節點會下載最新版本並重新啟動。僅更新已啟用且在線的節點。",
"updateAgent": "Update Agent",
"updateAgentConfirmContent": "The agent on this node will download the latest release, verify it, and restart onto it. If the update fails, the node keeps running the current version.",
"agentInstallCommand": "Install Command",
"agentTokenNotStored": "This node's token is not stored on the master yet, so the command below has no token. The token is saved on the node itself in /etc/x-ui/agent.json; it will be filled in here automatically after the agent's next authenticated request.",
"updateDevChannel": "更新到開發通道(最新提交)", "updateDevChannel": "更新到開發通道(最新提交)",
"testConnection": "測試連線", "testConnection": "測試連線",
"connectionOk": "連線正常 ({ms} ms)", "connectionOk": "連線正常 ({ms} ms)",