mirror of
https://github.com/perfect-panel/ppanel-web.git
synced 2026-04-19 10:09:55 -04:00
♻️ refactor: Refactor server management API endpoints and typings
This commit is contained in:
parent
217ddce60c
commit
4f7cc807af
@ -1,11 +1,13 @@
|
||||
'use client';
|
||||
|
||||
import { filterServerList } from '@/services/admin/server';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { Button } from '@workspace/ui/components/button';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
@ -38,82 +40,40 @@ export type ProtocolName =
|
||||
| 'tuic'
|
||||
| 'anytls';
|
||||
|
||||
type ServerProtocolItem = {
|
||||
protocol: ProtocolName;
|
||||
enabled: boolean;
|
||||
config?: { port?: number } & Record<string, unknown>;
|
||||
};
|
||||
|
||||
type ServerRow = {
|
||||
id: number;
|
||||
name: string;
|
||||
server_addr: string;
|
||||
protocols: ServerProtocolItem[];
|
||||
};
|
||||
type ServerRow = API.Server;
|
||||
|
||||
export type NodeFormValues = {
|
||||
name: string;
|
||||
server_id?: number;
|
||||
protocol: ProtocolName | '';
|
||||
server_addr: string;
|
||||
port?: number;
|
||||
address: string;
|
||||
port: number;
|
||||
tags: string[];
|
||||
};
|
||||
|
||||
async function getServerListMock(): Promise<{ data: { list: ServerRow[] } }> {
|
||||
return {
|
||||
data: {
|
||||
list: [
|
||||
{
|
||||
id: 101,
|
||||
name: 'Tokyo-1',
|
||||
server_addr: 'jp-1.example.com',
|
||||
protocols: [
|
||||
{ protocol: 'shadowsocks', enabled: true, config: { port: 443 } },
|
||||
{ protocol: 'vless', enabled: true, config: { port: 8443 } },
|
||||
{ protocol: 'trojan', enabled: false, config: { port: 443 } },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 102,
|
||||
name: 'HK-Edge',
|
||||
server_addr: 'hk-edge.example.com',
|
||||
protocols: [
|
||||
{ protocol: 'vmess', enabled: true, config: { port: 443 } },
|
||||
{ protocol: 'vless', enabled: true, config: { port: 443 } },
|
||||
{ protocol: 'hysteria2', enabled: true, config: { port: 60000 } },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 103,
|
||||
name: 'AnyTLS Lab',
|
||||
server_addr: 'lab.example.com',
|
||||
protocols: [
|
||||
{ protocol: 'anytls', enabled: true, config: { port: 443 } },
|
||||
{ protocol: 'tuic', enabled: false, config: { port: 4443 } },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
async function getServers(): Promise<ServerRow[]> {
|
||||
const { data } = await filterServerList({ page: 1, size: 1000 });
|
||||
return (data?.data?.list || []) as ServerRow[];
|
||||
}
|
||||
|
||||
const buildSchema = (t: ReturnType<typeof useTranslations>) =>
|
||||
z
|
||||
.object({
|
||||
name: z.string().min(1, t('errors.nameRequired')),
|
||||
server_id: z.number({ invalid_type_error: t('errors.serverRequired') }).optional(),
|
||||
protocol: z.string().min(1, t('errors.protocolRequired')),
|
||||
server_addr: z.string().min(1, t('errors.serverAddrRequired')),
|
||||
port: z
|
||||
.number()
|
||||
.int()
|
||||
.min(1, t('errors.portRange'))
|
||||
.max(65535, t('errors.portRange'))
|
||||
.optional(),
|
||||
tags: z.array(z.string()),
|
||||
})
|
||||
.refine((v) => !!v.server_id, { path: ['server_id'], message: t('errors.serverRequired') });
|
||||
const buildScheme = (t: ReturnType<typeof useTranslations>) =>
|
||||
z.object({
|
||||
name: z.string().trim().min(1, t('errors.nameRequired')),
|
||||
server_id: z.coerce
|
||||
.number({ invalid_type_error: t('errors.serverRequired') })
|
||||
.int()
|
||||
.gt(0, t('errors.serverRequired')),
|
||||
protocol: z.custom<ProtocolName>((v) => typeof v === 'string' && v.length > 0, {
|
||||
message: t('errors.protocolRequired'),
|
||||
}),
|
||||
address: z.string().trim().min(1, t('errors.serverAddrRequired')),
|
||||
port: z.coerce
|
||||
.number({ invalid_type_error: t('errors.portRange') })
|
||||
.int()
|
||||
.min(1, t('errors.portRange'))
|
||||
.max(65535, t('errors.portRange')),
|
||||
tags: z.array(z.string()).default([]),
|
||||
});
|
||||
|
||||
export default function NodeForm(props: {
|
||||
trigger: string;
|
||||
@ -124,16 +84,16 @@ export default function NodeForm(props: {
|
||||
}) {
|
||||
const { trigger, title, loading, initialValues, onSubmit } = props;
|
||||
const t = useTranslations('nodes');
|
||||
const schema = useMemo(() => buildSchema(t), [t]);
|
||||
const Scheme = useMemo(() => buildScheme(t), [t]);
|
||||
|
||||
const form = useForm<NodeFormValues>({
|
||||
resolver: zodResolver(schema),
|
||||
resolver: zodResolver(Scheme),
|
||||
defaultValues: {
|
||||
name: '',
|
||||
server_id: undefined,
|
||||
protocol: '',
|
||||
server_addr: '',
|
||||
port: undefined,
|
||||
address: '',
|
||||
port: 0,
|
||||
tags: [],
|
||||
...initialValues,
|
||||
},
|
||||
@ -141,22 +101,19 @@ export default function NodeForm(props: {
|
||||
|
||||
const serverId = form.watch('server_id');
|
||||
|
||||
const { data } = useQuery({ queryKey: ['getServerListMock'], queryFn: getServerListMock });
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const servers: ServerRow[] = data?.data?.list ?? [];
|
||||
const { data } = useQuery({ queryKey: ['filterServerListAll'], queryFn: getServers });
|
||||
const servers: ServerRow[] = data as ServerRow[];
|
||||
|
||||
const currentServer = useMemo(() => servers.find((s) => s.id === serverId), [servers, serverId]);
|
||||
const currentServer = useMemo(() => servers?.find((s) => s.id === serverId), [servers, serverId]);
|
||||
|
||||
const availableProtocols = useMemo(
|
||||
() =>
|
||||
(currentServer?.protocols || [])
|
||||
.filter((p) => p.enabled)
|
||||
.map((p) => ({
|
||||
protocol: p.protocol,
|
||||
port: p.config?.port,
|
||||
})),
|
||||
[currentServer],
|
||||
);
|
||||
const availableProtocols = useMemo(() => {
|
||||
return (currentServer?.protocols || [])
|
||||
.map((p) => ({
|
||||
protocol: (p as any).type as ProtocolName,
|
||||
port: (p as any).port as number | undefined,
|
||||
}))
|
||||
.filter((p) => !!p.protocol);
|
||||
}, [currentServer]);
|
||||
|
||||
useEffect(() => {
|
||||
if (initialValues) {
|
||||
@ -164,8 +121,8 @@ export default function NodeForm(props: {
|
||||
name: '',
|
||||
server_id: undefined,
|
||||
protocol: '',
|
||||
server_addr: '',
|
||||
port: undefined,
|
||||
address: '',
|
||||
port: 0,
|
||||
tags: [],
|
||||
...initialValues,
|
||||
});
|
||||
@ -178,26 +135,33 @@ export default function NodeForm(props: {
|
||||
form.setValue('server_id', id);
|
||||
|
||||
const sel = servers.find((s) => s.id === id);
|
||||
if (!form.getValues('server_addr') && sel?.server_addr) {
|
||||
form.setValue('server_addr', sel.server_addr);
|
||||
const dirty = form.formState.dirtyFields as Record<string, any>;
|
||||
if (!dirty.name) {
|
||||
form.setValue('name', (sel?.name as string) || '', { shouldDirty: false });
|
||||
}
|
||||
const allowed = (sel?.protocols || []).filter((p) => p.enabled).map((p) => p.protocol);
|
||||
if (!dirty.address) {
|
||||
form.setValue('address', (sel?.address as string) || '', { shouldDirty: false });
|
||||
}
|
||||
const allowed = (sel?.protocols || [])
|
||||
.map((p) => (p as any).type as ProtocolName)
|
||||
.filter(Boolean);
|
||||
if (!allowed.includes(form.getValues('protocol') as ProtocolName)) {
|
||||
form.setValue('protocol', '' as any);
|
||||
}
|
||||
// Do not auto-fill port here; handled in handleProtocolChange
|
||||
}
|
||||
|
||||
function handleProtocolChange(nextProto?: ProtocolName | null) {
|
||||
const p = (nextProto || '') as ProtocolName | '';
|
||||
form.setValue('protocol', p);
|
||||
if (!p || !currentServer) return;
|
||||
const curPort = Number(form.getValues('port') || 0);
|
||||
if (!curPort) {
|
||||
const hit = currentServer.protocols.find((x) => x.protocol === p);
|
||||
const port = hit?.config?.port;
|
||||
if (typeof port === 'number' && port > 0) {
|
||||
form.setValue('port', port);
|
||||
}
|
||||
const dirty = form.formState.dirtyFields as Record<string, any>;
|
||||
if (!dirty.port) {
|
||||
const hit = (currentServer.protocols as any[]).find((x) => (x as any).type === p);
|
||||
const port = (hit as any)?.port as number | undefined;
|
||||
form.setValue('port', typeof port === 'number' && port > 0 ? port : 0, {
|
||||
shouldDirty: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -220,40 +184,6 @@ export default function NodeForm(props: {
|
||||
<ScrollArea className='-mx-6 h-[calc(100dvh-48px-36px-36px-env(safe-area-inset-top))] px-6 pt-4'>
|
||||
<Form {...form}>
|
||||
<form className='grid grid-cols-1 gap-4'>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='name'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('name')}</FormLabel>
|
||||
<FormControl>
|
||||
<EnhancedInput
|
||||
{...field}
|
||||
onValueChange={(v) => form.setValue(field.name, v as string)}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='tags'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('tags')}</FormLabel>
|
||||
<FormControl>
|
||||
<TagInput
|
||||
placeholder={t('tags_placeholder')}
|
||||
value={field.value || []}
|
||||
onChange={(v) => form.setValue(field.name, v)}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='server_id'
|
||||
@ -266,7 +196,7 @@ export default function NodeForm(props: {
|
||||
value={field.value}
|
||||
options={servers.map((s) => ({
|
||||
value: s.id,
|
||||
label: `${s.name} (${s.server_addr})`,
|
||||
label: `${s.name} (${(s.address as any) || ''})`,
|
||||
}))}
|
||||
onChange={(v) => handleServerChange(v)}
|
||||
/>
|
||||
@ -287,7 +217,7 @@ export default function NodeForm(props: {
|
||||
value={field.value}
|
||||
options={availableProtocols.map((p) => ({
|
||||
value: p.protocol,
|
||||
label: `${p.protocol} (${p.port})`,
|
||||
label: `${p.protocol}${p.port ? ` (${p.port})` : ''}`,
|
||||
}))}
|
||||
onChange={(v) => handleProtocolChange((v as ProtocolName) || null)}
|
||||
/>
|
||||
@ -296,13 +226,29 @@ export default function NodeForm(props: {
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='name'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('name')}</FormLabel>
|
||||
<FormControl>
|
||||
<EnhancedInput
|
||||
{...field}
|
||||
onValueChange={(v) => form.setValue(field.name, v as string)}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='server_addr'
|
||||
name='address'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('server_addr')}</FormLabel>
|
||||
<FormLabel>{t('address')}</FormLabel>
|
||||
<FormControl>
|
||||
<EnhancedInput
|
||||
{...field}
|
||||
@ -326,7 +272,7 @@ export default function NodeForm(props: {
|
||||
type='number'
|
||||
min={1}
|
||||
max={65535}
|
||||
placeholder='1 - 65535'
|
||||
placeholder='1-65535'
|
||||
onValueChange={(v) => form.setValue(field.name, Number(v))}
|
||||
/>
|
||||
</FormControl>
|
||||
@ -334,6 +280,24 @@ export default function NodeForm(props: {
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='tags'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('tags')}</FormLabel>
|
||||
<FormControl>
|
||||
<TagInput
|
||||
placeholder={t('tags_placeholder')}
|
||||
value={field.value || []}
|
||||
onChange={(v) => form.setValue(field.name, v)}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormDescription>{t('tags_description')}</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</form>
|
||||
</Form>
|
||||
</ScrollArea>
|
||||
|
||||
@ -1,124 +1,50 @@
|
||||
'use client';
|
||||
|
||||
import { ProTable, ProTableActions } from '@/components/pro-table';
|
||||
import {
|
||||
createNode,
|
||||
deleteNode,
|
||||
filterNodeList,
|
||||
filterServerList,
|
||||
toggleNodeStatus,
|
||||
updateNode,
|
||||
} from '@/services/admin/server';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { Badge } from '@workspace/ui/components/badge';
|
||||
import { Button } from '@workspace/ui/components/button';
|
||||
import { Switch } from '@workspace/ui/components/switch';
|
||||
import { ConfirmButton } from '@workspace/ui/custom-components/confirm-button';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useMemo, useRef, useState } from 'react';
|
||||
import { useRef, useState } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import NodeForm, { type NodeFormValues } from './node-form';
|
||||
|
||||
type NodeItem = NodeFormValues & { id: number; enabled: boolean; sort: number };
|
||||
|
||||
let mock: NodeItem[] = [
|
||||
{
|
||||
id: 1,
|
||||
enabled: false,
|
||||
name: 'Node A',
|
||||
server_id: 101,
|
||||
protocol: 'shadowsocks',
|
||||
server_addr: 'jp-1.example.com',
|
||||
port: 443,
|
||||
tags: ['hk', 'premium'],
|
||||
sort: 1,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
enabled: true,
|
||||
name: 'Node B',
|
||||
server_id: 102,
|
||||
protocol: 'vless',
|
||||
server_addr: 'hk-edge.example.com',
|
||||
port: 8443,
|
||||
tags: ['jp'],
|
||||
sort: 2,
|
||||
},
|
||||
];
|
||||
|
||||
const list = async () => ({ list: mock, total: mock.length });
|
||||
const create = async (v: NodeFormValues) => {
|
||||
mock.push({
|
||||
id: Date.now(),
|
||||
enabled: false,
|
||||
sort: 0,
|
||||
...v,
|
||||
});
|
||||
return true;
|
||||
};
|
||||
const update = async (id: number, v: NodeFormValues) => {
|
||||
mock = mock.map((x) => (x.id === id ? { ...x, ...v } : x));
|
||||
return true;
|
||||
};
|
||||
const remove = async (id: number) => {
|
||||
mock = mock.filter((x) => x.id !== id);
|
||||
return true;
|
||||
};
|
||||
const setState = async (id: number, en: boolean) => {
|
||||
mock = mock.map((x) => (x.id === id ? { ...x, enabled: en } : x));
|
||||
return true;
|
||||
};
|
||||
|
||||
type ProtocolName = 'shadowsocks' | 'vmess' | 'vless' | 'trojan' | 'hysteria2' | 'tuic' | 'anytls';
|
||||
type ServerProtocolItem = { protocol: ProtocolName; enabled: boolean; config?: { port?: number } };
|
||||
type ServerRow = { id: number; name: string; server_addr: string; protocols: ServerProtocolItem[] };
|
||||
|
||||
async function getServerListMock(): Promise<{ data: { list: ServerRow[] } }> {
|
||||
return {
|
||||
data: {
|
||||
list: [
|
||||
{
|
||||
id: 101,
|
||||
name: 'Tokyo-1',
|
||||
server_addr: 'jp-1.example.com',
|
||||
protocols: [
|
||||
{ protocol: 'shadowsocks', enabled: true, config: { port: 443 } },
|
||||
{ protocol: 'vless', enabled: true, config: { port: 8443 } },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 102,
|
||||
name: 'HK-Edge',
|
||||
server_addr: 'hk-edge.example.com',
|
||||
protocols: [
|
||||
{ protocol: 'vmess', enabled: true, config: { port: 443 } },
|
||||
{ protocol: 'vless', enabled: true, config: { port: 443 } },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
import NodeForm from './node-form';
|
||||
|
||||
export default function NodesPage() {
|
||||
const t = useTranslations('nodes');
|
||||
const ref = useRef<ProTableActions>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const { data: serversResp } = useQuery({
|
||||
queryKey: ['getServerListMock'],
|
||||
queryFn: getServerListMock,
|
||||
const { data: servers = [] } = useQuery({
|
||||
queryKey: ['filterServerListAll', { page: 1, size: 1000 }],
|
||||
queryFn: async () => {
|
||||
const { data } = await filterServerList({ page: 1, size: 1000 });
|
||||
return data?.data?.list || [];
|
||||
},
|
||||
});
|
||||
const servers: ServerRow[] = serversResp?.data?.list ?? [];
|
||||
const serverMap = useMemo(() => {
|
||||
const m = new Map<number, ServerRow>();
|
||||
servers.forEach((s) => m.set(s.id, s));
|
||||
return m;
|
||||
}, [servers]);
|
||||
|
||||
const getServerName = (id?: number) => (id ? (serverMap.get(id)?.name ?? `#${id}`) : '—');
|
||||
const getServerOriginAddr = (id?: number) => (id ? (serverMap.get(id)?.server_addr ?? '—') : '—');
|
||||
const getServerName = (id?: number) =>
|
||||
id ? (servers.find((s) => s.id === id)?.name ?? `#${id}`) : '—';
|
||||
const getServerOriginAddr = (id?: number) =>
|
||||
id ? (servers.find((s) => s.id === id)?.address ?? '—') : '—';
|
||||
const getProtocolOriginPort = (id?: number, proto?: string) => {
|
||||
if (!id || !proto) return '—';
|
||||
const hit = serverMap.get(id)?.protocols?.find((p) => p.protocol === proto);
|
||||
const p = hit?.config?.port;
|
||||
const hit = servers.find((s) => s.id === id)?.protocols?.find((p) => (p as any).type === proto);
|
||||
const p = (hit as any)?.port as number | undefined;
|
||||
return typeof p === 'number' ? String(p) : '—';
|
||||
};
|
||||
|
||||
return (
|
||||
<ProTable<NodeItem, { search: string }>
|
||||
<ProTable<API.Node, { search: string }>
|
||||
action={ref}
|
||||
header={{
|
||||
title: t('pageTitle'),
|
||||
@ -129,11 +55,25 @@ export default function NodesPage() {
|
||||
loading={loading}
|
||||
onSubmit={async (values) => {
|
||||
setLoading(true);
|
||||
await create(values);
|
||||
toast.success(t('created'));
|
||||
ref.current?.refresh();
|
||||
setLoading(false);
|
||||
return true;
|
||||
try {
|
||||
const body: API.CreateNodeRequest = {
|
||||
name: values.name,
|
||||
server_id: Number(values.server_id!),
|
||||
protocol: values.protocol,
|
||||
address: values.address,
|
||||
port: Number(values.port!),
|
||||
tags: values.tags || [],
|
||||
enabled: false,
|
||||
};
|
||||
await createNode(body);
|
||||
toast.success(t('created'));
|
||||
ref.current?.refresh();
|
||||
setLoading(false);
|
||||
return true;
|
||||
} catch (e) {
|
||||
setLoading(false);
|
||||
return false;
|
||||
}
|
||||
}}
|
||||
/>
|
||||
),
|
||||
@ -146,7 +86,7 @@ export default function NodesPage() {
|
||||
<Switch
|
||||
checked={row.original.enabled}
|
||||
onCheckedChange={async (v) => {
|
||||
await setState(row.original.id, v);
|
||||
await toggleNodeStatus({ id: row.original.id, enable: v });
|
||||
toast.success(v ? t('enabled_on') : t('enabled_off'));
|
||||
ref.current?.refresh();
|
||||
}}
|
||||
@ -156,13 +96,9 @@ export default function NodesPage() {
|
||||
{ accessorKey: 'name', header: t('name') },
|
||||
|
||||
{
|
||||
id: 'server_addr_port',
|
||||
header: t('server_addr_port'),
|
||||
cell: ({ row }) => (
|
||||
<Badge variant='outline'>
|
||||
{(row.original.server_addr || '—') + ':' + (row.original.port ?? '—')}
|
||||
</Badge>
|
||||
),
|
||||
id: 'address_port',
|
||||
header: `${t('address')}:${t('port')}`,
|
||||
cell: ({ row }) => (row.original.address || '—') + ':' + (row.original.port ?? '—'),
|
||||
},
|
||||
|
||||
{
|
||||
@ -174,7 +110,7 @@ export default function NodesPage() {
|
||||
{getServerName(row.original.server_id)} ·{' '}
|
||||
{getServerOriginAddr(row.original.server_id)}
|
||||
</Badge>
|
||||
<Badge>
|
||||
<Badge variant='outline'>
|
||||
{row.original.protocol || '—'} ·{' '}
|
||||
{getProtocolOriginPort(row.original.server_id, row.original.protocol)}
|
||||
</Badge>
|
||||
@ -198,24 +134,15 @@ export default function NodesPage() {
|
||||
},
|
||||
]}
|
||||
params={[{ key: 'search' }]}
|
||||
request={async (_pagination, filter) => {
|
||||
const { list: items } = await list();
|
||||
const kw = (filter?.search || '').toLowerCase().trim();
|
||||
const filtered = kw
|
||||
? items.filter((i) =>
|
||||
[
|
||||
i.name,
|
||||
getServerName(i.server_id),
|
||||
getServerOriginAddr(i.server_id),
|
||||
`${i.server_addr}:${i.port ?? ''}`,
|
||||
`${i.protocol}:${getProtocolOriginPort(i.server_id, i.protocol)}`,
|
||||
...(i.tags || []),
|
||||
]
|
||||
.filter(Boolean)
|
||||
.some((v) => String(v).toLowerCase().includes(kw)),
|
||||
)
|
||||
: items;
|
||||
return { list: filtered, total: filtered.length };
|
||||
request={async (pagination, filter) => {
|
||||
const { data } = await filterNodeList({
|
||||
page: pagination.page,
|
||||
size: pagination.size,
|
||||
search: filter?.search || undefined,
|
||||
});
|
||||
const list = (data?.data?.list || []) as API.Node[];
|
||||
const total = Number(data?.data?.total || list.length);
|
||||
return { list, total };
|
||||
}}
|
||||
actions={{
|
||||
render: (row) => [
|
||||
@ -224,14 +151,36 @@ export default function NodesPage() {
|
||||
trigger={t('edit')}
|
||||
title={t('drawerEditTitle')}
|
||||
loading={loading}
|
||||
initialValues={row}
|
||||
initialValues={{
|
||||
name: row.name,
|
||||
server_id: row.server_id,
|
||||
protocol: row.protocol as any,
|
||||
address: row.address as any,
|
||||
port: row.port as any,
|
||||
tags: (row.tags as any) || [],
|
||||
}}
|
||||
onSubmit={async (values) => {
|
||||
setLoading(true);
|
||||
await update(row.id, values);
|
||||
toast.success(t('updated'));
|
||||
ref.current?.refresh();
|
||||
setLoading(false);
|
||||
return true;
|
||||
try {
|
||||
const body: API.UpdateNodeRequest = {
|
||||
id: row.id,
|
||||
name: values.name,
|
||||
server_id: Number(values.server_id!),
|
||||
protocol: values.protocol,
|
||||
address: values.address,
|
||||
port: Number(values.port!),
|
||||
tags: values.tags || [],
|
||||
enabled: row.enabled,
|
||||
} as any;
|
||||
await updateNode(body);
|
||||
toast.success(t('updated'));
|
||||
ref.current?.refresh();
|
||||
setLoading(false);
|
||||
return true;
|
||||
} catch (e) {
|
||||
setLoading(false);
|
||||
return false;
|
||||
}
|
||||
}}
|
||||
/>,
|
||||
<ConfirmButton
|
||||
@ -240,7 +189,7 @@ export default function NodesPage() {
|
||||
title={t('confirmDeleteTitle')}
|
||||
description={t('confirmDeleteDesc')}
|
||||
onConfirm={async () => {
|
||||
await remove(row.id);
|
||||
await deleteNode({ id: row.id } as any);
|
||||
toast.success(t('deleted'));
|
||||
ref.current?.refresh();
|
||||
}}
|
||||
@ -251,8 +200,16 @@ export default function NodesPage() {
|
||||
key='copy'
|
||||
variant='outline'
|
||||
onClick={async () => {
|
||||
const { id, enabled, ...rest } = row;
|
||||
await create(rest);
|
||||
const { id, enabled, created_at, updated_at, ...rest } = row as any;
|
||||
await createNode({
|
||||
name: rest.name,
|
||||
server_id: rest.server_id,
|
||||
protocol: rest.protocol,
|
||||
address: rest.address,
|
||||
port: rest.port,
|
||||
tags: rest.tags || [],
|
||||
enabled: false,
|
||||
} as any);
|
||||
toast.success(t('copied'));
|
||||
ref.current?.refresh();
|
||||
}}
|
||||
@ -268,6 +225,7 @@ export default function NodesPage() {
|
||||
title={t('confirmDeleteTitle')}
|
||||
description={t('confirmDeleteDesc')}
|
||||
onConfirm={async () => {
|
||||
await Promise.all(rows.map((r) => deleteNode({ id: r.id } as any)));
|
||||
toast.success(t('deleted'));
|
||||
ref.current?.refresh();
|
||||
}}
|
||||
@ -277,33 +235,6 @@ export default function NodesPage() {
|
||||
];
|
||||
},
|
||||
}}
|
||||
onSort={async (source, target, items) => {
|
||||
const sourceIndex = items.findIndex((item) => String(item.id) === source);
|
||||
const targetIndex = items.findIndex((item) => String(item.id) === target);
|
||||
|
||||
const originalSorts = items.map((item) => item.sort);
|
||||
|
||||
const [movedItem] = items.splice(sourceIndex, 1);
|
||||
items.splice(targetIndex, 0, movedItem!);
|
||||
|
||||
const updatedItems = items.map((item, index) => {
|
||||
const originalSort = originalSorts[index];
|
||||
const newSort = originalSort !== undefined ? originalSort : item.sort;
|
||||
return { ...item, sort: newSort };
|
||||
});
|
||||
|
||||
const changedItems = updatedItems.filter((item, index) => {
|
||||
return item.sort !== items[index]?.sort;
|
||||
});
|
||||
|
||||
if (changedItems.length > 0) {
|
||||
// nodeSort({
|
||||
// sort: changedItems.map((item) => ({ id: item.id, sort: item.sort })),
|
||||
// });
|
||||
}
|
||||
|
||||
return updatedItems;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { getNodeGroupList, getNodeList } from '@/services/admin/server';
|
||||
import { filterNodeList } from '@/services/admin/server';
|
||||
import { getSubscribeGroupList } from '@/services/admin/subscribe';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
@ -10,6 +10,7 @@ import {
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from '@workspace/ui/components/accordion';
|
||||
import { Badge } from '@workspace/ui/components/badge';
|
||||
import { Button } from '@workspace/ui/components/button';
|
||||
import { Checkbox } from '@workspace/ui/components/checkbox';
|
||||
import {
|
||||
@ -103,7 +104,11 @@ export default function SubscribeForm<T extends Record<string, any>>({
|
||||
traffic: z.number().optional().default(0),
|
||||
quota: z.number().optional().default(0),
|
||||
group_id: z.number().optional().nullish(),
|
||||
server_group: z.array(z.number()).optional().default([]),
|
||||
// Use tags as group identifiers; accept string (tag) or number (legacy id)
|
||||
server_group: z
|
||||
.array(z.union([z.number(), z.string()]) as any)
|
||||
.optional()
|
||||
.default([]),
|
||||
server: z.array(z.number()).optional().default([]),
|
||||
deduction_ratio: z.number().optional().default(0),
|
||||
allow_deduction: z.boolean().optional().default(false),
|
||||
@ -237,27 +242,22 @@ export default function SubscribeForm<T extends Record<string, any>>({
|
||||
},
|
||||
});
|
||||
|
||||
const { data: server } = useQuery({
|
||||
queryKey: ['getNodeList', 'all'],
|
||||
const { data: nodes } = useQuery({
|
||||
queryKey: ['filterNodeListAll'],
|
||||
queryFn: async () => {
|
||||
const { data } = await getNodeList({
|
||||
page: 1,
|
||||
size: 9999,
|
||||
});
|
||||
return data.data?.list;
|
||||
},
|
||||
});
|
||||
|
||||
const { data: server_groups } = useQuery({
|
||||
queryKey: ['getNodeGroupList'],
|
||||
queryFn: async () => {
|
||||
const { data } = await getNodeGroupList();
|
||||
return (data.data?.list || []) as API.ServerGroup[];
|
||||
const { data } = await filterNodeList({ page: 1, size: 9999 });
|
||||
return (data.data?.list || []) as API.Node[];
|
||||
},
|
||||
});
|
||||
const tagGroups = Array.from(
|
||||
new Set(
|
||||
((nodes as API.Node[]) || [])
|
||||
.flatMap((n) => (Array.isArray(n.tags) ? n.tags : []))
|
||||
.filter(Boolean),
|
||||
),
|
||||
) as string[];
|
||||
|
||||
const unit_time = form.watch('unit_time');
|
||||
const unit_price = form.watch('unit_price');
|
||||
|
||||
return (
|
||||
<Sheet open={open} onOpenChange={setOpen}>
|
||||
@ -290,7 +290,7 @@ export default function SubscribeForm<T extends Record<string, any>>({
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value='servers' className='flex items-center gap-2'>
|
||||
<Server className='h-4 w-4' />
|
||||
{t('form.servers')}
|
||||
{t('form.nodes')}
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
@ -798,50 +798,56 @@ export default function SubscribeForm<T extends Record<string, any>>({
|
||||
name='server_group'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('form.serverGroup')}</FormLabel>
|
||||
<FormLabel>{t('form.nodeGroup')}</FormLabel>
|
||||
<FormControl>
|
||||
<Accordion type='single' collapsible className='w-full'>
|
||||
{server_groups?.map((group: API.ServerGroup) => {
|
||||
{tagGroups.map((tag) => {
|
||||
const value = field.value || [];
|
||||
|
||||
// Use a synthetic ID for tag grouping selection by name
|
||||
const tagId = tag;
|
||||
return (
|
||||
<AccordionItem key={group.id} value={String(group.id)}>
|
||||
<AccordionItem key={tag} value={String(tag)}>
|
||||
<AccordionTrigger>
|
||||
<div className='flex items-center gap-2'>
|
||||
<Checkbox
|
||||
checked={value.includes(group.id!)}
|
||||
checked={value.includes(tagId as any)}
|
||||
onCheckedChange={(checked) => {
|
||||
return checked
|
||||
? form.setValue(field.name, [...value, group.id])
|
||||
? form.setValue(field.name, [...value, tagId] as any)
|
||||
: form.setValue(
|
||||
field.name,
|
||||
value.filter(
|
||||
(value: number) => value !== group.id,
|
||||
),
|
||||
value.filter((v: any) => v !== tagId),
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Label>{group.name}</Label>
|
||||
<Label>{tag}</Label>
|
||||
</div>
|
||||
</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
<ul className='list-disc [&>li]:mt-2'>
|
||||
{server
|
||||
?.filter(
|
||||
(server: API.Server) => server.group_id === group.id,
|
||||
)
|
||||
?.map((node: API.Server) => {
|
||||
return (
|
||||
<li
|
||||
key={node.id}
|
||||
className='flex items-center justify-between *:flex-1'
|
||||
>
|
||||
<span>{node.name}</span>
|
||||
<span>{node.server_addr}</span>
|
||||
<span className='text-right'>{node.protocol}</span>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
<ul className='space-y-1'>
|
||||
{(nodes as API.Node[])
|
||||
?.filter((n) => (n.tags || []).includes(tag))
|
||||
?.map((node) => (
|
||||
<li
|
||||
key={node.id}
|
||||
className='flex items-center justify-between gap-3'
|
||||
>
|
||||
<span className='font-medium'>{node.name}</span>
|
||||
<span className='text-muted-foreground'>
|
||||
{node.address}:{node.port ?? '—'}
|
||||
</span>
|
||||
<span className='font-mono text-xs uppercase'>
|
||||
{node.protocol || '—'}
|
||||
</span>
|
||||
<span className='flex flex-wrap justify-end gap-1'>
|
||||
{(node.tags || []).map((tg) => (
|
||||
<Badge key={tg} variant='outline'>
|
||||
{tg}
|
||||
</Badge>
|
||||
))}
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
@ -859,12 +865,12 @@ export default function SubscribeForm<T extends Record<string, any>>({
|
||||
name='server'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('form.server')}</FormLabel>
|
||||
<FormLabel>{t('form.node')}</FormLabel>
|
||||
<FormControl>
|
||||
<div className='flex flex-col gap-2'>
|
||||
{server
|
||||
?.filter((item: API.Server) => !item.group_id)
|
||||
?.map((item: API.Server) => {
|
||||
{(nodes as API.Node[])
|
||||
?.filter((item) => (item.tags || []).length === 0)
|
||||
?.map((item) => {
|
||||
const value = field.value || [];
|
||||
|
||||
return (
|
||||
@ -880,10 +886,12 @@ export default function SubscribeForm<T extends Record<string, any>>({
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Label className='flex w-full items-center justify-between *:flex-1'>
|
||||
<Label className='flex w-full items-center justify-between gap-3'>
|
||||
<span>{item.name}</span>
|
||||
<span>{item.server_addr}</span>
|
||||
<span className='text-right'>{item.protocol}</span>
|
||||
<span>
|
||||
{item.address}:{item.port}
|
||||
</span>
|
||||
<span>{item.protocol}</span>
|
||||
</Label>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -1,126 +0,0 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const protocols = ['shadowsocks', 'vmess', 'vless', 'trojan', 'hysteria2', 'tuic', 'anytls'];
|
||||
|
||||
const nullableString = z.string().nullish();
|
||||
const portSchema = z.number().max(65535).nullish();
|
||||
const securityConfigSchema = z
|
||||
.object({
|
||||
sni: nullableString,
|
||||
allow_insecure: z.boolean().nullable().default(false),
|
||||
fingerprint: nullableString,
|
||||
reality_private_key: nullableString,
|
||||
reality_public_key: nullableString,
|
||||
reality_short_id: nullableString,
|
||||
reality_server_addr: nullableString,
|
||||
reality_server_port: portSchema,
|
||||
})
|
||||
.nullish();
|
||||
|
||||
const transportConfigSchema = z
|
||||
.object({
|
||||
path: nullableString,
|
||||
host: nullableString,
|
||||
service_name: nullableString,
|
||||
})
|
||||
.nullish();
|
||||
|
||||
const baseProtocolSchema = z.object({
|
||||
port: portSchema,
|
||||
transport: z.string(),
|
||||
transport_config: transportConfigSchema,
|
||||
security: z.string(),
|
||||
security_config: securityConfigSchema,
|
||||
});
|
||||
|
||||
const shadowsocksSchema = z.object({
|
||||
method: z.string(),
|
||||
port: portSchema,
|
||||
server_key: nullableString,
|
||||
});
|
||||
|
||||
const vmessSchema = baseProtocolSchema;
|
||||
|
||||
const vlessSchema = baseProtocolSchema.extend({
|
||||
flow: nullableString,
|
||||
});
|
||||
|
||||
const trojanSchema = baseProtocolSchema;
|
||||
|
||||
const hysteria2Schema = z.object({
|
||||
port: portSchema,
|
||||
hop_ports: nullableString,
|
||||
hop_interval: z.number().nullish(),
|
||||
obfs_password: nullableString,
|
||||
security: z.string(),
|
||||
security_config: securityConfigSchema,
|
||||
});
|
||||
|
||||
const tuicSchema = z.object({
|
||||
port: portSchema,
|
||||
disable_sni: z.boolean().default(false),
|
||||
reduce_rtt: z.boolean().default(false),
|
||||
udp_relay_mode: z.string().default('native'),
|
||||
congestion_controller: z.string().default('bbr'),
|
||||
security_config: securityConfigSchema,
|
||||
});
|
||||
|
||||
const anytlsSchema = z.object({
|
||||
port: portSchema,
|
||||
security_config: securityConfigSchema,
|
||||
});
|
||||
|
||||
const protocolConfigSchema = z.discriminatedUnion('protocol', [
|
||||
z.object({
|
||||
protocol: z.literal('shadowsocks'),
|
||||
config: shadowsocksSchema,
|
||||
}),
|
||||
z.object({
|
||||
protocol: z.literal('vmess'),
|
||||
config: vmessSchema,
|
||||
}),
|
||||
z.object({
|
||||
protocol: z.literal('vless'),
|
||||
config: vlessSchema,
|
||||
}),
|
||||
z.object({
|
||||
protocol: z.literal('trojan'),
|
||||
config: trojanSchema,
|
||||
}),
|
||||
z.object({
|
||||
protocol: z.literal('hysteria2'),
|
||||
config: hysteria2Schema,
|
||||
}),
|
||||
z.object({
|
||||
protocol: z.literal('tuic'),
|
||||
config: tuicSchema,
|
||||
}),
|
||||
z.object({
|
||||
protocol: z.literal('anytls'),
|
||||
config: anytlsSchema,
|
||||
}),
|
||||
]);
|
||||
|
||||
const baseFormSchema = z.object({
|
||||
name: z.string(),
|
||||
tags: z.array(z.string()).nullish().default([]),
|
||||
country: z.string().nullish(),
|
||||
city: z.string().nullish(),
|
||||
server_addr: z.string(),
|
||||
speed_limit: z.number().nullish(),
|
||||
traffic_ratio: z.number().default(1),
|
||||
group_id: z.number().nullish(),
|
||||
relay_mode: z.string().nullish().default('none'),
|
||||
relay_node: z
|
||||
.array(
|
||||
z.object({
|
||||
host: z.string(),
|
||||
port: portSchema,
|
||||
prefix: z.string().nullish(),
|
||||
}),
|
||||
)
|
||||
.nullish()
|
||||
.default([]),
|
||||
});
|
||||
|
||||
export const formSchema = z.intersection(baseFormSchema, protocolConfigSchema);
|
||||
@ -1,145 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { Button } from '@workspace/ui/components/button';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@workspace/ui/components/form';
|
||||
import { ScrollArea } from '@workspace/ui/components/scroll-area';
|
||||
import {
|
||||
Sheet,
|
||||
SheetContent,
|
||||
SheetFooter,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
SheetTrigger,
|
||||
} from '@workspace/ui/components/sheet';
|
||||
import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input';
|
||||
import { Icon } from '@workspace/ui/custom-components/icon';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
|
||||
const formSchema = z.object({
|
||||
name: z.string(),
|
||||
description: z.string().optional(),
|
||||
});
|
||||
|
||||
interface GroupFormProps<T> {
|
||||
onSubmit: (data: T) => Promise<boolean> | boolean;
|
||||
initialValues?: T;
|
||||
loading?: boolean;
|
||||
trigger: string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
export default function GroupForm<T extends Record<string, any>>({
|
||||
onSubmit,
|
||||
initialValues,
|
||||
loading,
|
||||
trigger,
|
||||
title,
|
||||
}: GroupFormProps<T>) {
|
||||
const t = useTranslations('server');
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const form = useForm({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
...initialValues,
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
form?.reset(initialValues);
|
||||
}, [form, initialValues]);
|
||||
|
||||
async function handleSubmit(data: { [x: string]: any }) {
|
||||
const bool = await onSubmit(data as T);
|
||||
|
||||
if (bool) setOpen(false);
|
||||
}
|
||||
|
||||
return (
|
||||
<Sheet open={open} onOpenChange={setOpen}>
|
||||
<SheetTrigger asChild>
|
||||
<Button
|
||||
onClick={() => {
|
||||
form.reset();
|
||||
setOpen(true);
|
||||
}}
|
||||
>
|
||||
{trigger}
|
||||
</Button>
|
||||
</SheetTrigger>
|
||||
<SheetContent className='w-[500px] max-w-full md:max-w-screen-md'>
|
||||
<SheetHeader>
|
||||
<SheetTitle>{title}</SheetTitle>
|
||||
</SheetHeader>
|
||||
<ScrollArea className='-mx-6 h-[calc(100dvh-48px-36px-36px-env(safe-area-inset-top))]'>
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(handleSubmit)} className='space-y-4 px-6 pt-4'>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='name'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('groupForm.name')}</FormLabel>
|
||||
<FormControl>
|
||||
<EnhancedInput
|
||||
{...field}
|
||||
onValueChange={(value) => {
|
||||
form.setValue(field.name, value);
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='description'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('groupForm.description')}</FormLabel>
|
||||
<FormControl>
|
||||
<EnhancedInput
|
||||
{...field}
|
||||
onValueChange={(value) => {
|
||||
form.setValue(field.name, value);
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</form>
|
||||
</Form>
|
||||
</ScrollArea>
|
||||
<SheetFooter className='flex-row justify-end gap-2 pt-3'>
|
||||
<Button
|
||||
variant='outline'
|
||||
disabled={loading}
|
||||
onClick={() => {
|
||||
setOpen(false);
|
||||
}}
|
||||
>
|
||||
{t('groupForm.cancel')}
|
||||
</Button>
|
||||
<Button disabled={loading} onClick={form.handleSubmit(handleSubmit)}>
|
||||
{loading && <Icon icon='mdi:loading' className='mr-2 animate-spin' />}{' '}
|
||||
{t('groupForm.confirm')}
|
||||
</Button>
|
||||
</SheetFooter>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
);
|
||||
}
|
||||
@ -1,140 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import { ProTable, ProTableActions } from '@/components/pro-table';
|
||||
import {
|
||||
batchDeleteNodeGroup,
|
||||
createNodeGroup,
|
||||
deleteNodeGroup,
|
||||
getNodeGroupList,
|
||||
updateNodeGroup,
|
||||
} from '@/services/admin/server';
|
||||
import { Button } from '@workspace/ui/components/button';
|
||||
import { ConfirmButton } from '@workspace/ui/custom-components/confirm-button';
|
||||
import { formatDate } from '@workspace/ui/utils';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useRef, useState } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import GroupForm from './group-form';
|
||||
|
||||
export default function GroupTable() {
|
||||
const t = useTranslations('server');
|
||||
const [loading, setLoading] = useState(false);
|
||||
const ref = useRef<ProTableActions>(null);
|
||||
|
||||
return (
|
||||
<ProTable<API.ServerGroup, any>
|
||||
action={ref}
|
||||
header={{
|
||||
title: t('group.title'),
|
||||
toolbar: (
|
||||
<GroupForm<API.CreateNodeGroupRequest>
|
||||
trigger={t('group.create')}
|
||||
title={t('group.createNodeGroup')}
|
||||
loading={loading}
|
||||
onSubmit={async (values) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
await createNodeGroup(values);
|
||||
toast.success(t('group.createdSuccessfully'));
|
||||
ref.current?.refresh();
|
||||
setLoading(false);
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
|
||||
return false;
|
||||
}
|
||||
}}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
columns={[
|
||||
{
|
||||
accessorKey: 'name',
|
||||
header: t('group.name'),
|
||||
},
|
||||
{
|
||||
accessorKey: 'description',
|
||||
header: t('group.description'),
|
||||
cell: ({ row }) => <p className='line-clamp-3'>{row.getValue('description')}</p>,
|
||||
},
|
||||
{
|
||||
accessorKey: 'updated_at',
|
||||
header: t('group.updatedAt'),
|
||||
cell: ({ row }) => formatDate(row.getValue('updated_at')),
|
||||
},
|
||||
]}
|
||||
request={async () => {
|
||||
const { data } = await getNodeGroupList();
|
||||
return {
|
||||
list: data.data?.list || [],
|
||||
total: data.data?.total || 0,
|
||||
};
|
||||
}}
|
||||
actions={{
|
||||
render: (row) => [
|
||||
<GroupForm<API.ServerGroup>
|
||||
key='edit'
|
||||
trigger={t('group.edit')}
|
||||
title={t('group.editNodeGroup')}
|
||||
loading={loading}
|
||||
initialValues={row}
|
||||
onSubmit={async (values) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
await updateNodeGroup({
|
||||
...row,
|
||||
...values,
|
||||
});
|
||||
toast.success(t('group.createdSuccessfully'));
|
||||
ref.current?.refresh();
|
||||
setLoading(false);
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
|
||||
return false;
|
||||
}
|
||||
}}
|
||||
/>,
|
||||
<ConfirmButton
|
||||
key='delete'
|
||||
trigger={<Button variant='destructive'>{t('group.delete')}</Button>}
|
||||
title={t('group.confirmDelete')}
|
||||
description={t('group.deleteWarning')}
|
||||
onConfirm={async () => {
|
||||
await deleteNodeGroup({
|
||||
id: row.id!,
|
||||
});
|
||||
toast.success(t('group.deletedSuccessfully'));
|
||||
ref.current?.refresh();
|
||||
}}
|
||||
cancelText={t('group.cancel')}
|
||||
confirmText={t('group.confirm')}
|
||||
/>,
|
||||
],
|
||||
batchRender(rows) {
|
||||
return [
|
||||
<ConfirmButton
|
||||
key='delete'
|
||||
trigger={<Button variant='destructive'>{t('group.delete')}</Button>}
|
||||
title={t('group.confirmDelete')}
|
||||
description={t('group.deleteWarning')}
|
||||
onConfirm={async () => {
|
||||
await batchDeleteNodeGroup({
|
||||
ids: rows.map((item) => item.id),
|
||||
});
|
||||
toast.success(t('group.deleteSuccess'));
|
||||
ref.current?.refresh();
|
||||
}}
|
||||
cancelText={t('group.cancel')}
|
||||
confirmText={t('group.confirm')}
|
||||
/>,
|
||||
];
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -1,296 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import {
|
||||
getNodeConfig,
|
||||
getNodeMultiplier,
|
||||
setNodeMultiplier,
|
||||
updateNodeConfig,
|
||||
} from '@/services/admin/system';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { Button } from '@workspace/ui/components/button';
|
||||
import { ChartContainer, ChartTooltip } from '@workspace/ui/components/chart';
|
||||
import { Label } from '@workspace/ui/components/label';
|
||||
import { Table, TableBody, TableCell, TableRow } from '@workspace/ui/components/table';
|
||||
import { ArrayInput } from '@workspace/ui/custom-components/dynamic-Inputs';
|
||||
import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input';
|
||||
import { DicesIcon } from 'lucide-react';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { uid } from 'radash';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { Cell, Legend, Pie, PieChart } from 'recharts';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
const COLORS = [
|
||||
'hsl(var(--chart-1))',
|
||||
'hsl(var(--chart-2))',
|
||||
'hsl(var(--chart-3))',
|
||||
'hsl(var(--chart-4))',
|
||||
'hsl(var(--chart-5))',
|
||||
];
|
||||
|
||||
const MINUTES_IN_DAY = 1440; // 24 * 60
|
||||
|
||||
function getTimeRangeData(slots: API.TimePeriod[]) {
|
||||
const timePoints = slots
|
||||
.filter((slot) => slot.start_time && slot.end_time)
|
||||
.flatMap((slot) => {
|
||||
const [startH = 0, startM = 0] = slot.start_time.split(':').map(Number);
|
||||
const [endH = 0, endM = 0] = slot?.end_time.split(':').map(Number);
|
||||
const start = startH * 60 + startM;
|
||||
let end = endH * 60 + endM;
|
||||
if (end < start) end += MINUTES_IN_DAY;
|
||||
return { start, end, multiplier: slot.multiplier };
|
||||
})
|
||||
.sort((a, b) => a.start - b.start);
|
||||
|
||||
const result = [];
|
||||
let currentMinute = 0;
|
||||
|
||||
timePoints.forEach((point) => {
|
||||
if (point.start > currentMinute) {
|
||||
result.push({
|
||||
name: `${Math.floor(currentMinute / 60)}:${String(currentMinute % 60).padStart(2, '0')} - ${Math.floor(point.start / 60)}:${String(point.start % 60).padStart(2, '0')}`,
|
||||
value: point.start - currentMinute,
|
||||
multiplier: 1,
|
||||
});
|
||||
}
|
||||
result.push({
|
||||
name: `${Math.floor(point.start / 60)}:${String(point.start % 60).padStart(2, '0')} - ${Math.floor((point.end / 60) % 24)}:${String(point.end % 60).padStart(2, '0')}`,
|
||||
value: point.end - point.start,
|
||||
multiplier: point.multiplier,
|
||||
});
|
||||
currentMinute = point.end % MINUTES_IN_DAY;
|
||||
});
|
||||
|
||||
if (currentMinute < MINUTES_IN_DAY) {
|
||||
result.push({
|
||||
name: `${Math.floor(currentMinute / 60)}:${String(currentMinute % 60).padStart(2, '0')} - 24:00`,
|
||||
value: MINUTES_IN_DAY - currentMinute,
|
||||
multiplier: 1,
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export default function NodeConfig() {
|
||||
const t = useTranslations('server.config');
|
||||
|
||||
const { data, refetch } = useQuery({
|
||||
queryKey: ['getNodeConfig'],
|
||||
queryFn: async () => {
|
||||
const { data } = await getNodeConfig();
|
||||
|
||||
return data.data;
|
||||
},
|
||||
});
|
||||
|
||||
async function updateConfig(key: string, value: unknown) {
|
||||
if (data?.[key] === value) return;
|
||||
try {
|
||||
await updateNodeConfig({
|
||||
...data,
|
||||
[key]: value,
|
||||
} as API.NodeConfig);
|
||||
toast.success(t('saveSuccess'));
|
||||
refetch();
|
||||
} catch (error) {
|
||||
/* empty */
|
||||
}
|
||||
}
|
||||
|
||||
const [timeSlots, setTimeSlots] = useState<API.TimePeriod[]>([]);
|
||||
|
||||
const { data: NodeMultiplier, refetch: refetchNodeMultiplier } = useQuery({
|
||||
queryKey: ['getNodeMultiplier'],
|
||||
queryFn: async () => {
|
||||
const { data } = await getNodeMultiplier();
|
||||
if (timeSlots.length === 0) {
|
||||
setTimeSlots(data.data?.periods || []);
|
||||
}
|
||||
return data.data?.periods || [];
|
||||
},
|
||||
});
|
||||
|
||||
const chartTimeSlots = useMemo(() => {
|
||||
return getTimeRangeData(timeSlots);
|
||||
}, [timeSlots]);
|
||||
|
||||
const chartConfig = useMemo(() => {
|
||||
return chartTimeSlots?.reduce(
|
||||
(acc, item, index) => {
|
||||
acc[item.name] = {
|
||||
label: item.name,
|
||||
color: COLORS[index % COLORS.length] || 'hsl(var(--default-chart-color))',
|
||||
};
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, { label: string; color: string }>,
|
||||
);
|
||||
}, [data]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Table>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell>
|
||||
<Label>{t('communicationKey')}</Label>
|
||||
<p className='text-muted-foreground text-xs'>{t('communicationKeyDescription')}</p>
|
||||
</TableCell>
|
||||
<TableCell className='text-right'>
|
||||
<EnhancedInput
|
||||
placeholder={t('inputPlaceholder')}
|
||||
value={data?.node_secret}
|
||||
onValueBlur={(value) => updateConfig('node_secret', value)}
|
||||
suffix={
|
||||
<div className='bg-muted flex h-9 items-center text-nowrap px-3'>
|
||||
<DicesIcon
|
||||
onClick={() => {
|
||||
const id = uid(32).toLowerCase();
|
||||
const formatted = `${id.slice(0, 8)}-${id.slice(8, 12)}-${id.slice(12, 16)}-${id.slice(16, 20)}-${id.slice(20)}`;
|
||||
updateConfig('node_secret', formatted);
|
||||
}}
|
||||
className='cursor-pointer'
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>
|
||||
<Label>{t('nodePullInterval')}</Label>
|
||||
<p className='text-muted-foreground text-xs'>{t('nodePullIntervalDescription')}</p>
|
||||
</TableCell>
|
||||
<TableCell className='text-right'>
|
||||
<EnhancedInput
|
||||
type='number'
|
||||
min={0}
|
||||
onValueBlur={(value) => updateConfig('node_pull_interval', value)}
|
||||
suffix='S'
|
||||
value={data?.node_pull_interval}
|
||||
placeholder={t('inputPlaceholder')}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>
|
||||
<Label>{t('nodePushInterval')}</Label>
|
||||
<p className='text-muted-foreground text-xs'>{t('nodePushIntervalDescription')}</p>
|
||||
</TableCell>
|
||||
<TableCell className='text-right'>
|
||||
<EnhancedInput
|
||||
type='number'
|
||||
min={0}
|
||||
step={0.1}
|
||||
value={data?.node_push_interval}
|
||||
onValueBlur={(value) => updateConfig('node_push_interval', value)}
|
||||
placeholder={t('inputPlaceholder')}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>
|
||||
<Label>{t('dynamicMultiplier')}</Label>
|
||||
<p className='text-muted-foreground text-xs'>{t('dynamicMultiplierDescription')}</p>
|
||||
</TableCell>
|
||||
<TableCell className='flex justify-end gap-2'>
|
||||
<Button
|
||||
size='sm'
|
||||
variant='outline'
|
||||
onClick={() => {
|
||||
setTimeSlots(NodeMultiplier || []);
|
||||
}}
|
||||
>
|
||||
{t('reset')}
|
||||
</Button>
|
||||
<Button
|
||||
size='sm'
|
||||
onClick={() => {
|
||||
setNodeMultiplier({
|
||||
periods: timeSlots,
|
||||
}).then(async () => {
|
||||
const result = await refetchNodeMultiplier();
|
||||
if (result.data) setTimeSlots(result.data);
|
||||
toast.success(t('saveSuccess'));
|
||||
});
|
||||
}}
|
||||
>
|
||||
{t('save')}
|
||||
</Button>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
<div className='flex flex-col-reverse gap-8 px-4 pt-6 md:flex-row md:items-start'>
|
||||
<div className='w-full md:w-1/2'>
|
||||
<ChartContainer config={chartConfig} className='mx-auto aspect-[4/3] max-w-[400px]'>
|
||||
<PieChart>
|
||||
<Pie
|
||||
data={chartTimeSlots}
|
||||
cx='50%'
|
||||
cy='50%'
|
||||
labelLine={false}
|
||||
outerRadius='80%'
|
||||
fill='#8884d8'
|
||||
dataKey='value'
|
||||
label={({ name, percent, multiplier }) =>
|
||||
`${(multiplier || 0)?.toFixed(2)}x (${(percent * 100).toFixed(0)}%)`
|
||||
}
|
||||
>
|
||||
{chartTimeSlots.map((entry, index) => (
|
||||
<Cell key={`cell-${index}`} fill={COLORS[index % COLORS.length]} />
|
||||
))}
|
||||
</Pie>
|
||||
<ChartTooltip
|
||||
content={({ payload }) => {
|
||||
if (payload && payload.length) {
|
||||
const data = payload[0]?.payload;
|
||||
return (
|
||||
<div className='bg-background rounded-lg border p-2 shadow-sm'>
|
||||
<div className='grid grid-cols-2 gap-2'>
|
||||
<div className='flex flex-col'>
|
||||
<span className='text-muted-foreground text-[0.70rem] uppercase'>
|
||||
{t('timeSlot')}
|
||||
</span>
|
||||
<span className='text-muted-foreground font-bold'>
|
||||
{data.name || '其他'}
|
||||
</span>
|
||||
</div>
|
||||
<div className='flex flex-col'>
|
||||
<span className='text-muted-foreground text-[0.70rem] uppercase'>
|
||||
{t('multiplier')}
|
||||
</span>
|
||||
<span className='font-bold'>{data.multiplier.toFixed(2)}x</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}}
|
||||
/>
|
||||
<Legend />
|
||||
</PieChart>
|
||||
</ChartContainer>
|
||||
</div>
|
||||
<div className='w-full md:w-1/2'>
|
||||
<ArrayInput<API.TimePeriod>
|
||||
fields={[
|
||||
{
|
||||
name: 'start_time',
|
||||
prefix: t('startTime'),
|
||||
type: 'time',
|
||||
},
|
||||
{ name: 'end_time', prefix: t('endTime'), type: 'time' },
|
||||
{ name: 'multiplier', prefix: t('multiplier'), type: 'number', placeholder: '0' },
|
||||
]}
|
||||
value={timeSlots}
|
||||
onChange={setTimeSlots}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@ -1,251 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import { UserDetail } from '@/app/dashboard/user/user-detail';
|
||||
import { ProTable } from '@/components/pro-table';
|
||||
import { getUserSubscribeById } from '@/services/admin/user';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { Badge } from '@workspace/ui/components/badge';
|
||||
import { Button } from '@workspace/ui/components/button';
|
||||
import { Progress } from '@workspace/ui/components/progress';
|
||||
|
||||
import {
|
||||
Sheet,
|
||||
SheetContent,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
SheetTrigger,
|
||||
} from '@workspace/ui/components/sheet';
|
||||
import { formatBytes, formatDate } from '@workspace/ui/utils';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useState } from 'react';
|
||||
|
||||
interface NodeDetailDialogProps {
|
||||
node: API.Server;
|
||||
children?: React.ReactNode;
|
||||
trigger?: React.ReactNode;
|
||||
}
|
||||
|
||||
// 统一的用户订阅信息组件
|
||||
function UserSubscribeInfo({
|
||||
userId,
|
||||
type,
|
||||
}: {
|
||||
userId: number;
|
||||
type: 'account' | 'subscribeName' | 'subscribeId' | 'trafficUsage' | 'expireTime';
|
||||
}) {
|
||||
const { data } = useQuery({
|
||||
enabled: userId !== 0,
|
||||
queryKey: ['getUserSubscribeById', userId],
|
||||
queryFn: async () => {
|
||||
const { data } = await getUserSubscribeById({ id: userId });
|
||||
return data.data;
|
||||
},
|
||||
});
|
||||
|
||||
if (!data) return <span className='text-muted-foreground'>--</span>;
|
||||
|
||||
switch (type) {
|
||||
case 'account':
|
||||
if (!data.user_id) return <span className='text-muted-foreground'>--</span>;
|
||||
return <UserDetail id={data.user_id} />;
|
||||
|
||||
case 'subscribeName':
|
||||
if (!data.subscribe?.name) return <span className='text-muted-foreground'>--</span>;
|
||||
return <span className='text-sm'>{data.subscribe.name}</span>;
|
||||
|
||||
case 'subscribeId':
|
||||
if (!data.id) return <span className='text-muted-foreground'>--</span>;
|
||||
return <span className='font-mono text-sm'>{data.id}</span>;
|
||||
|
||||
case 'trafficUsage': {
|
||||
const usedTraffic = data.upload + data.download;
|
||||
const totalTraffic = data.traffic || 0;
|
||||
return (
|
||||
<div className='min-w-0 text-sm'>
|
||||
<div className='break-words'>
|
||||
{formatBytes(usedTraffic)} / {totalTraffic > 0 ? formatBytes(totalTraffic) : '无限制'}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
case 'expireTime': {
|
||||
if (!data.expire_time) return <span className='text-muted-foreground'>--</span>;
|
||||
const isExpired = data.expire_time < Date.now() / 1000;
|
||||
return (
|
||||
<div className='flex flex-col gap-1 sm:flex-row sm:items-center sm:gap-2'>
|
||||
<span className='text-sm'>{formatDate(data.expire_time)}</span>
|
||||
{isExpired && (
|
||||
<Badge variant='destructive' className='w-fit px-1 py-0 text-xs'>
|
||||
过期
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
default:
|
||||
return <span className='text-muted-foreground'>--</span>;
|
||||
}
|
||||
}
|
||||
|
||||
export function NodeDetailDialog({ node, children, trigger }: NodeDetailDialogProps) {
|
||||
const t = useTranslations('server.node');
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const { status } = node;
|
||||
const { online, cpu, mem, disk, updated_at } = status || {
|
||||
online: {},
|
||||
cpu: 0,
|
||||
mem: 0,
|
||||
disk: 0,
|
||||
updated_at: 0,
|
||||
};
|
||||
|
||||
const isOnline = updated_at > 0;
|
||||
const onlineCount = (online && Object.keys(online).length) || 0;
|
||||
|
||||
// 转换在线用户数据为ProTable需要的格式
|
||||
const onlineUsersData = Object.entries(online || {}).map(([uid, ips]) => ({
|
||||
uid,
|
||||
ips: ips as string[],
|
||||
primaryIp: ips[0] || '',
|
||||
allIps: (ips as string[]).join(', '),
|
||||
}));
|
||||
|
||||
return (
|
||||
<Sheet open={open} onOpenChange={setOpen}>
|
||||
<SheetTrigger asChild>
|
||||
{trigger || (
|
||||
<Button variant='outline' size='sm'>
|
||||
{t('detail')}
|
||||
</Button>
|
||||
)}
|
||||
</SheetTrigger>
|
||||
<SheetContent className='w-full max-w-full sm:w-[600px] sm:max-w-screen-md'>
|
||||
<SheetHeader>
|
||||
<SheetTitle>
|
||||
{t('nodeDetail')} - {node.name}
|
||||
</SheetTitle>
|
||||
</SheetHeader>
|
||||
<div className='-mx-6 h-[calc(100dvh-48px-16px-env(safe-area-inset-top))] space-y-2 overflow-y-auto px-6 py-4'>
|
||||
<h3 className='text-base font-medium'>{t('nodeStatus')}</h3>
|
||||
<div className='space-y-3'>
|
||||
<div className='flex w-full flex-col gap-2 text-sm sm:flex-row sm:items-center sm:gap-3'>
|
||||
<Badge variant={isOnline ? 'default' : 'destructive'} className='w-fit text-xs'>
|
||||
{isOnline ? t('normal') : t('abnormal')}
|
||||
</Badge>
|
||||
<span className='text-muted-foreground'>
|
||||
{t('onlineCount')}: {onlineCount}
|
||||
</span>
|
||||
{isOnline && (
|
||||
<span className='text-muted-foreground text-xs sm:text-sm'>
|
||||
{t('lastUpdated')}: {formatDate(updated_at)}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{isOnline && (
|
||||
<div className='grid grid-cols-1 gap-3 sm:grid-cols-3'>
|
||||
<div className='space-y-1'>
|
||||
<div className='flex justify-between text-xs'>
|
||||
<span>CPU</span>
|
||||
<span>{cpu?.toFixed(1)}%</span>
|
||||
</div>
|
||||
<Progress value={cpu ?? 0} className='h-1.5' max={100} />
|
||||
</div>
|
||||
<div className='space-y-1'>
|
||||
<div className='flex justify-between text-xs'>
|
||||
<span>{t('memory')}</span>
|
||||
<span>{mem?.toFixed(1)}%</span>
|
||||
</div>
|
||||
<Progress value={mem ?? 0} className='h-1.5' max={100} />
|
||||
</div>
|
||||
<div className='space-y-1'>
|
||||
<div className='flex justify-between text-xs'>
|
||||
<span>{t('disk')}</span>
|
||||
<span>{disk?.toFixed(1)}%</span>
|
||||
</div>
|
||||
<Progress value={disk ?? 0} className='h-1.5' max={100} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{isOnline && onlineCount > 0 && (
|
||||
<div>
|
||||
<h3 className='mb-3 text-lg font-medium'>{t('onlineUsers')}</h3>
|
||||
<div className='overflow-x-auto'>
|
||||
<ProTable
|
||||
header={{
|
||||
hidden: true,
|
||||
}}
|
||||
columns={[
|
||||
{
|
||||
accessorKey: 'allIps',
|
||||
header: t('ipAddresses'),
|
||||
cell: ({ row }) => {
|
||||
const ips = row.original.ips;
|
||||
return (
|
||||
<div className='flex min-w-0 flex-col gap-1'>
|
||||
{ips.map((ip: string, index: number) => (
|
||||
<div key={ip} className='whitespace-nowrap text-sm'>
|
||||
{index === 0 ? (
|
||||
<span className='font-medium'>{ip}</span>
|
||||
) : (
|
||||
<span className='text-muted-foreground'>{ip}</span>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: 'user',
|
||||
header: t('user'),
|
||||
cell: ({ row }) => (
|
||||
<UserSubscribeInfo userId={Number(row.original.uid)} type='account' />
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: 'subscribeName',
|
||||
header: t('subscribeName'),
|
||||
cell: ({ row }) => (
|
||||
<UserSubscribeInfo userId={Number(row.original.uid)} type='subscribeName' />
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: 'subscribeId',
|
||||
header: t('subscribeId'),
|
||||
cell: ({ row }) => (
|
||||
<UserSubscribeInfo userId={Number(row.original.uid)} type='subscribeId' />
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: 'trafficUsage',
|
||||
header: t('trafficUsage'),
|
||||
cell: ({ row }) => (
|
||||
<UserSubscribeInfo userId={Number(row.original.uid)} type='trafficUsage' />
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: 'expireTime',
|
||||
header: t('expireTime'),
|
||||
cell: ({ row }) => (
|
||||
<UserSubscribeInfo userId={Number(row.original.uid)} type='expireTime' />
|
||||
),
|
||||
},
|
||||
]}
|
||||
request={async () => ({
|
||||
list: onlineUsersData,
|
||||
total: onlineUsersData.length,
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,266 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import { UserDetail } from '@/app/dashboard/user/user-detail';
|
||||
import { IpLink } from '@/components/ip-link';
|
||||
import { ProTable } from '@/components/pro-table';
|
||||
import { getUserSubscribeById } from '@/services/admin/user';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { Badge } from '@workspace/ui/components/badge';
|
||||
import { Progress } from '@workspace/ui/components/progress';
|
||||
import {
|
||||
Sheet,
|
||||
SheetContent,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
SheetTrigger,
|
||||
} from '@workspace/ui/components/sheet';
|
||||
import { formatBytes, formatDate } from '@workspace/ui/utils';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useState } from 'react';
|
||||
|
||||
export function formatPercentage(value: number): string {
|
||||
return `${value.toFixed(1)}%`;
|
||||
}
|
||||
|
||||
// 统一的用户订阅信息组件
|
||||
function UserSubscribeInfo({
|
||||
userId,
|
||||
type,
|
||||
}: {
|
||||
userId: number;
|
||||
type: 'account' | 'subscribeName' | 'subscribeId' | 'trafficUsage' | 'expireTime';
|
||||
}) {
|
||||
const { data } = useQuery({
|
||||
enabled: userId !== 0,
|
||||
queryKey: ['getUserSubscribeById', userId],
|
||||
queryFn: async () => {
|
||||
const { data } = await getUserSubscribeById({ id: userId });
|
||||
return data.data;
|
||||
},
|
||||
});
|
||||
|
||||
if (!data) return <span className='text-muted-foreground'>--</span>;
|
||||
|
||||
switch (type) {
|
||||
case 'account':
|
||||
if (!data.user_id) return <span className='text-muted-foreground'>--</span>;
|
||||
return <UserDetail id={data.user_id} />;
|
||||
|
||||
case 'subscribeName':
|
||||
if (!data.subscribe?.name) return <span className='text-muted-foreground'>--</span>;
|
||||
return <span className='text-sm'>{data.subscribe.name}</span>;
|
||||
|
||||
case 'subscribeId':
|
||||
if (!data.id) return <span className='text-muted-foreground'>--</span>;
|
||||
return <span className='font-mono text-sm'>{data.id}</span>;
|
||||
|
||||
case 'trafficUsage': {
|
||||
const usedTraffic = data.upload + data.download;
|
||||
const totalTraffic = data.traffic || 0;
|
||||
return (
|
||||
<div className='min-w-0 text-sm'>
|
||||
<div className='break-words'>
|
||||
{formatBytes(usedTraffic)} / {totalTraffic > 0 ? formatBytes(totalTraffic) : '无限制'}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
case 'expireTime': {
|
||||
if (!data.expire_time) return <span className='text-muted-foreground'>--</span>;
|
||||
const isExpired = data.expire_time < Date.now() / 1000;
|
||||
return (
|
||||
<div className='flex flex-col gap-1 sm:flex-row sm:items-center sm:gap-2'>
|
||||
<span className='text-sm'>{formatDate(data.expire_time)}</span>
|
||||
{isExpired && (
|
||||
<Badge variant='destructive' className='w-fit px-1 py-0 text-xs'>
|
||||
过期
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
default:
|
||||
return <span className='text-muted-foreground'>--</span>;
|
||||
}
|
||||
}
|
||||
|
||||
export function NodeStatusCell({ status, node }: { status: API.NodeStatus; node?: API.Server }) {
|
||||
const t = useTranslations('server.node');
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const { online, cpu, mem, disk, updated_at } = status || {
|
||||
online: {},
|
||||
cpu: 0,
|
||||
mem: 0,
|
||||
disk: 0,
|
||||
updated_at: 0,
|
||||
};
|
||||
|
||||
const isOnline = updated_at > 0;
|
||||
const badgeVariant = isOnline ? 'default' : 'destructive';
|
||||
const badgeText = isOnline ? t('normal') : t('abnormal');
|
||||
const onlineCount = (online && Object.keys(online).length) || 0;
|
||||
|
||||
// 转换在线用户数据为ProTable需要的格式
|
||||
const onlineUsersData = Object.entries(online || {}).map(([uid, ips]) => ({
|
||||
uid,
|
||||
ips: ips as string[],
|
||||
primaryIp: ips[0] || '',
|
||||
allIps: (ips as string[]).join(', '),
|
||||
}));
|
||||
|
||||
return (
|
||||
<>
|
||||
<Sheet open={open} onOpenChange={setOpen}>
|
||||
<SheetTrigger asChild>
|
||||
<button className='hover:text-foreground flex cursor-pointer items-center gap-2 border-none bg-transparent p-0 text-left text-sm transition-colors'>
|
||||
<Badge variant={badgeVariant}>{badgeText}</Badge>
|
||||
<span className='text-muted-foreground'>
|
||||
{t('onlineCount')}: {onlineCount}
|
||||
</span>
|
||||
</button>
|
||||
</SheetTrigger>
|
||||
{node && (
|
||||
<SheetContent className='h-screen w-screen max-w-none sm:h-auto sm:w-[800px] sm:max-w-[90vw]'>
|
||||
<SheetHeader>
|
||||
<SheetTitle>
|
||||
{t('nodeDetail')} - {node.name}
|
||||
</SheetTitle>
|
||||
</SheetHeader>
|
||||
<div className='-mx-6 h-[calc(100vh-48px-16px)] space-y-2 overflow-y-auto px-6 py-4 sm:h-[calc(100dvh-48px-16px-env(safe-area-inset-top))]'>
|
||||
<h3 className='text-base font-medium'>{t('nodeStatus')}</h3>
|
||||
<div className='space-y-3'>
|
||||
<div className='flex w-full flex-col gap-2 text-sm sm:flex-row sm:items-center sm:gap-3'>
|
||||
<Badge variant={isOnline ? 'default' : 'destructive'} className='w-fit text-xs'>
|
||||
{isOnline ? t('normal') : t('abnormal')}
|
||||
</Badge>
|
||||
<span className='text-muted-foreground'>
|
||||
{t('onlineCount')}: {onlineCount}
|
||||
</span>
|
||||
{isOnline && (
|
||||
<span className='text-muted-foreground text-xs sm:text-sm'>
|
||||
{t('lastUpdated')}: {formatDate(updated_at)}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{isOnline && (
|
||||
<div className='grid grid-cols-1 gap-3 sm:grid-cols-3'>
|
||||
<div className='space-y-1'>
|
||||
<div className='flex justify-between text-xs'>
|
||||
<span>CPU</span>
|
||||
<span>{cpu?.toFixed(1)}%</span>
|
||||
</div>
|
||||
<Progress value={cpu ?? 0} className='h-1.5' max={100} />
|
||||
</div>
|
||||
<div className='space-y-1'>
|
||||
<div className='flex justify-between text-xs'>
|
||||
<span>{t('memory')}</span>
|
||||
<span>{mem?.toFixed(1)}%</span>
|
||||
</div>
|
||||
<Progress value={mem ?? 0} className='h-1.5' max={100} />
|
||||
</div>
|
||||
<div className='space-y-1'>
|
||||
<div className='flex justify-between text-xs'>
|
||||
<span>{t('disk')}</span>
|
||||
<span>{disk?.toFixed(1)}%</span>
|
||||
</div>
|
||||
<Progress value={disk ?? 0} className='h-1.5' max={100} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{isOnline && onlineCount > 0 && (
|
||||
<div>
|
||||
<h3 className='mb-3 text-lg font-medium'>{t('onlineUsers')}</h3>
|
||||
<div className='overflow-x-auto'>
|
||||
<ProTable
|
||||
header={{
|
||||
hidden: true,
|
||||
}}
|
||||
columns={[
|
||||
{
|
||||
accessorKey: 'allIps',
|
||||
header: t('ipAddresses'),
|
||||
cell: ({ row }) => {
|
||||
const ips = row.original.ips;
|
||||
return (
|
||||
<div className='flex min-w-0 flex-col gap-1'>
|
||||
{ips.map((ip: string, index: number) => (
|
||||
<div key={ip} className='whitespace-nowrap text-sm'>
|
||||
{index === 0 ? (
|
||||
<IpLink ip={ip} className='font-medium' />
|
||||
) : (
|
||||
<IpLink ip={ip} className='text-muted-foreground' />
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: 'user',
|
||||
header: t('user'),
|
||||
cell: ({ row }) => (
|
||||
<UserSubscribeInfo userId={Number(row.original.uid)} type='account' />
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: 'subscribeName',
|
||||
header: t('subscribeName'),
|
||||
cell: ({ row }) => (
|
||||
<UserSubscribeInfo
|
||||
userId={Number(row.original.uid)}
|
||||
type='subscribeName'
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: 'subscribeId',
|
||||
header: t('subscribeId'),
|
||||
cell: ({ row }) => (
|
||||
<UserSubscribeInfo
|
||||
userId={Number(row.original.uid)}
|
||||
type='subscribeId'
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: 'trafficUsage',
|
||||
header: t('trafficUsage'),
|
||||
cell: ({ row }) => (
|
||||
<UserSubscribeInfo
|
||||
userId={Number(row.original.uid)}
|
||||
type='trafficUsage'
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: 'expireTime',
|
||||
header: t('expireTime'),
|
||||
cell: ({ row }) => (
|
||||
<UserSubscribeInfo
|
||||
userId={Number(row.original.uid)}
|
||||
type='expireTime'
|
||||
/>
|
||||
),
|
||||
},
|
||||
]}
|
||||
request={async () => ({
|
||||
list: onlineUsersData,
|
||||
total: onlineUsersData.length,
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</SheetContent>
|
||||
)}
|
||||
</Sheet>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@ -1,320 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import { Display } from '@/components/display';
|
||||
import { ProTable, ProTableActions } from '@/components/pro-table';
|
||||
import {
|
||||
batchDeleteNode,
|
||||
createNode,
|
||||
deleteNode,
|
||||
getNodeGroupList,
|
||||
getNodeList,
|
||||
nodeSort,
|
||||
updateNode,
|
||||
} from '@/services/admin/server';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { Badge } from '@workspace/ui/components/badge';
|
||||
import { Button } from '@workspace/ui/components/button';
|
||||
import { Switch } from '@workspace/ui/components/switch';
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from '@workspace/ui/components/tooltip';
|
||||
import { ConfirmButton } from '@workspace/ui/custom-components/confirm-button';
|
||||
import { cn } from '@workspace/ui/lib/utils';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useRef, useState } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import NodeForm from './node-form';
|
||||
import { NodeStatusCell } from './node-status';
|
||||
|
||||
export default function NodeTable() {
|
||||
const t = useTranslations('server.node');
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const { data: groups } = useQuery({
|
||||
queryKey: ['getNodeGroupList'],
|
||||
queryFn: async () => {
|
||||
const { data } = await getNodeGroupList();
|
||||
return (data.data?.list || []) as API.ServerGroup[];
|
||||
},
|
||||
});
|
||||
|
||||
const ref = useRef<ProTableActions>(null);
|
||||
|
||||
return (
|
||||
<ProTable<API.Server, { groupId: number; search: string }>
|
||||
action={ref}
|
||||
header={{
|
||||
toolbar: (
|
||||
<NodeForm<API.CreateNodeRequest>
|
||||
trigger={t('create')}
|
||||
title={t('createNode')}
|
||||
loading={loading}
|
||||
onSubmit={async (values) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
await createNode({ ...values, enable: false });
|
||||
toast.success(t('createSuccess'));
|
||||
ref.current?.refresh();
|
||||
setLoading(false);
|
||||
return true;
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
|
||||
return false;
|
||||
}
|
||||
}}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
columns={[
|
||||
{
|
||||
accessorKey: 'id',
|
||||
header: t('id'),
|
||||
cell: ({ row }) => (
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<Badge
|
||||
variant='outline'
|
||||
className={cn('text-primary-foreground', {
|
||||
'bg-green-500': row.original.protocol === 'shadowsocks',
|
||||
'bg-rose-500': row.original.protocol === 'vmess',
|
||||
'bg-blue-500': row.original.protocol === 'vless',
|
||||
'bg-yellow-500': row.original.protocol === 'trojan',
|
||||
'bg-purple-500': row.original.protocol === 'hysteria2',
|
||||
'bg-cyan-500': row.original.protocol === 'tuic',
|
||||
'bg-gray-500': row.original.protocol === 'anytls',
|
||||
})}
|
||||
>
|
||||
{row.getValue('id')}
|
||||
</Badge>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>{row.original.protocol}</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: 'enable',
|
||||
header: t('enable'),
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<Switch
|
||||
checked={row.getValue('enable')}
|
||||
onCheckedChange={async (checked) => {
|
||||
await updateNode({
|
||||
...row.original,
|
||||
id: row.original.id!,
|
||||
enable: checked,
|
||||
} as API.UpdateNodeRequest);
|
||||
ref.current?.refresh();
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: 'name',
|
||||
header: t('name'),
|
||||
},
|
||||
{
|
||||
accessorKey: 'server_addr',
|
||||
header: t('serverAddr'),
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<div className='flex gap-1'>
|
||||
<Badge variant='outline'>
|
||||
{row.original.country} - {row.original.city}
|
||||
</Badge>
|
||||
<Badge variant='outline'>{row.getValue('server_addr')}</Badge>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: 'status',
|
||||
header: t('status'),
|
||||
cell: ({ row }) => {
|
||||
return <NodeStatusCell status={row.original?.status} node={row.original} />;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: 'speed_limit',
|
||||
header: t('speedLimit'),
|
||||
cell: ({ row }) => (
|
||||
<Display type='trafficSpeed' value={row.getValue('speed_limit')} unlimited />
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: 'traffic_ratio',
|
||||
header: t('trafficRatio'),
|
||||
cell: ({ row }) => <Badge variant='outline'>{row.getValue('traffic_ratio')} X</Badge>,
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: 'group_id',
|
||||
header: t('nodeGroup'),
|
||||
cell: ({ row }) => {
|
||||
const name = groups?.find((group) => group.id === row.getValue('group_id'))?.name;
|
||||
return name ? <Badge variant='outline'>{name}</Badge> : t('noData');
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: 'tags',
|
||||
header: t('tags'),
|
||||
cell: ({ row }) => {
|
||||
const tags = (row.getValue('tags') as string[]) || [];
|
||||
return tags.length > 0 ? (
|
||||
<div className='flex gap-1'>
|
||||
{tags.map((tag) => (
|
||||
<Badge key={tag} variant='outline'>
|
||||
{tag}
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
t('noData')
|
||||
);
|
||||
},
|
||||
},
|
||||
]}
|
||||
params={[
|
||||
{
|
||||
key: 'group_id',
|
||||
placeholder: t('nodeGroup'),
|
||||
options: groups?.map((item) => ({
|
||||
label: item.name,
|
||||
value: String(item.id),
|
||||
})),
|
||||
},
|
||||
{
|
||||
key: 'search',
|
||||
},
|
||||
]}
|
||||
request={async (pagination, filter) => {
|
||||
const { data } = await getNodeList({
|
||||
...pagination,
|
||||
...filter,
|
||||
});
|
||||
return {
|
||||
list: data.data?.list || [],
|
||||
total: data.data?.total || 0,
|
||||
};
|
||||
}}
|
||||
actions={{
|
||||
render: (row) => [
|
||||
<NodeForm<API.Server>
|
||||
key='edit'
|
||||
trigger={t('edit')}
|
||||
title={t('editNode')}
|
||||
loading={loading}
|
||||
initialValues={row}
|
||||
onSubmit={async (values) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
await updateNode({ ...row, ...values } as API.UpdateNodeRequest);
|
||||
toast.success(t('updateSuccess'));
|
||||
ref.current?.refresh();
|
||||
setLoading(false);
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
|
||||
return false;
|
||||
}
|
||||
}}
|
||||
/>,
|
||||
<ConfirmButton
|
||||
key='delete'
|
||||
trigger={<Button variant='destructive'>{t('delete')}</Button>}
|
||||
title={t('confirmDelete')}
|
||||
description={t('deleteWarning')}
|
||||
onConfirm={async () => {
|
||||
await deleteNode({
|
||||
id: row.id,
|
||||
});
|
||||
toast.success(t('deleteSuccess'));
|
||||
ref.current?.refresh();
|
||||
}}
|
||||
cancelText={t('cancel')}
|
||||
confirmText={t('confirm')}
|
||||
/>,
|
||||
<Button
|
||||
key='copy'
|
||||
variant='outline'
|
||||
onClick={async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const { id, sort, enable, updated_at, created_at, status, ...params } = row;
|
||||
await createNode({
|
||||
...params,
|
||||
enable: false,
|
||||
} as API.CreateNodeRequest);
|
||||
toast.success(t('copySuccess'));
|
||||
ref.current?.refresh();
|
||||
setLoading(false);
|
||||
return true;
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
return false;
|
||||
}
|
||||
}}
|
||||
>
|
||||
{t('copy')}
|
||||
</Button>,
|
||||
],
|
||||
batchRender(rows) {
|
||||
return [
|
||||
<ConfirmButton
|
||||
key='delete'
|
||||
trigger={<Button variant='destructive'>{t('delete')}</Button>}
|
||||
title={t('confirmDelete')}
|
||||
description={t('deleteWarning')}
|
||||
onConfirm={async () => {
|
||||
await batchDeleteNode({
|
||||
ids: rows.map((item) => item.id),
|
||||
});
|
||||
toast.success(t('deleteSuccess'));
|
||||
ref.current?.refresh();
|
||||
}}
|
||||
cancelText={t('cancel')}
|
||||
confirmText={t('confirm')}
|
||||
/>,
|
||||
];
|
||||
},
|
||||
}}
|
||||
onSort={async (source, target, items) => {
|
||||
const sourceIndex = items.findIndex((item) => String(item.id) === source);
|
||||
const targetIndex = items.findIndex((item) => String(item.id) === target);
|
||||
|
||||
const originalSorts = items.map((item) => item.sort);
|
||||
|
||||
const [movedItem] = items.splice(sourceIndex, 1);
|
||||
items.splice(targetIndex, 0, movedItem!);
|
||||
|
||||
const updatedItems = items.map((item, index) => {
|
||||
const originalSort = originalSorts[index];
|
||||
const newSort = originalSort !== undefined ? originalSort : item.sort;
|
||||
return { ...item, sort: newSort };
|
||||
});
|
||||
|
||||
const changedItems = updatedItems.filter((item, index) => {
|
||||
return item.sort !== items[index]?.sort;
|
||||
});
|
||||
|
||||
if (changedItems.length > 0) {
|
||||
nodeSort({
|
||||
sort: changedItems.map((item) => ({ id: item.id, sort: item.sort })),
|
||||
});
|
||||
}
|
||||
|
||||
return updatedItems;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@workspace/ui/components/tabs';
|
||||
import { getTranslations } from 'next-intl/server';
|
||||
|
||||
import GroupTable from './group-table';
|
||||
import NodeConfig from './node-config';
|
||||
import NodeTable from './node-table';
|
||||
|
||||
export default async function Page() {
|
||||
const t = await getTranslations('server');
|
||||
|
||||
return (
|
||||
<Tabs defaultValue='node'>
|
||||
<TabsList>
|
||||
<TabsTrigger value='node'>{t('tabs.node')}</TabsTrigger>
|
||||
<TabsTrigger value='group'>{t('tabs.nodeGroup')}</TabsTrigger>
|
||||
<TabsTrigger value='config'>{t('tabs.nodeConfig')}</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value='node'>
|
||||
<NodeTable />
|
||||
</TabsContent>
|
||||
<TabsContent value='group'>
|
||||
<GroupTable />
|
||||
</TabsContent>
|
||||
<TabsContent value='config'>
|
||||
<NodeConfig />
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
);
|
||||
}
|
||||
@ -10,179 +10,223 @@ export const protocols = [
|
||||
'anytls',
|
||||
] as const;
|
||||
|
||||
// Global label map for display; fallback to raw value if missing
|
||||
export const LABELS = {
|
||||
// transport
|
||||
'tcp': 'TCP',
|
||||
'websocket': 'WebSocket',
|
||||
'http2': 'HTTP/2',
|
||||
'httpupgrade': 'HTTP Upgrade',
|
||||
'grpc': 'gRPC',
|
||||
'xtls-rprx-vision': 'XTLS-RPRX-Vision',
|
||||
// security
|
||||
'none': 'NONE',
|
||||
'tls': 'TLS',
|
||||
'reality': 'Reality',
|
||||
// fingerprint
|
||||
'chrome': 'Chrome',
|
||||
'firefox': 'Firefox',
|
||||
'safari': 'Safari',
|
||||
'ios': 'IOS',
|
||||
'android': 'Android',
|
||||
'edge': 'edge',
|
||||
'360': '360',
|
||||
'qq': 'QQ',
|
||||
} as const;
|
||||
|
||||
// Flat arrays for enum-like sets
|
||||
export const SS_CIPHERS = [
|
||||
'aes-128-gcm',
|
||||
'aes-192-gcm',
|
||||
'aes-256-gcm',
|
||||
'chacha20-ietf-poly1305',
|
||||
'2022-blake3-aes-128-gcm',
|
||||
'2022-blake3-aes-256-gcm',
|
||||
'2022-blake3-chacha20-poly1305',
|
||||
] as const;
|
||||
|
||||
export const TRANSPORTS = {
|
||||
vmess: ['tcp', 'websocket', 'grpc', 'httpupgrade'] as const,
|
||||
vless: ['tcp', 'websocket', 'grpc', 'httpupgrade', 'http2'] as const,
|
||||
trojan: ['tcp', 'websocket', 'grpc'] as const,
|
||||
} as const;
|
||||
|
||||
export const SECURITY = {
|
||||
vmess: ['none', 'tls'] as const,
|
||||
vless: ['none', 'tls', 'reality'] as const,
|
||||
trojan: ['tls'] as const,
|
||||
hysteria2: ['tls'] as const,
|
||||
} as const;
|
||||
|
||||
export const FLOWS = {
|
||||
vless: ['none', 'xtls-rprx-vision'] as const,
|
||||
} as const;
|
||||
|
||||
export const TUIC_UDP_RELAY_MODES = ['native', 'quic', 'none'] as const;
|
||||
export const TUIC_CONGESTION = ['bbr', 'cubic', 'new_reno'] as const;
|
||||
export const FINGERPRINTS = [
|
||||
'chrome',
|
||||
'firefox',
|
||||
'safari',
|
||||
'ios',
|
||||
'android',
|
||||
'edge',
|
||||
'360',
|
||||
'qq',
|
||||
] as const;
|
||||
|
||||
export function getLabel(value: string): string {
|
||||
return (LABELS as Record<string, string>)[value] ?? value;
|
||||
}
|
||||
|
||||
const nullableString = z.string().nullish();
|
||||
const portScheme = z.number().max(65535).nullish();
|
||||
const nullableBool = z.boolean().nullish();
|
||||
const nullablePort = z.number().int().min(0).max(65535).nullish();
|
||||
|
||||
const securityConfigScheme = z
|
||||
.object({
|
||||
sni: nullableString,
|
||||
allow_insecure: z.boolean().nullable().default(false),
|
||||
fingerprint: nullableString,
|
||||
reality_private_key: nullableString,
|
||||
reality_public_key: nullableString,
|
||||
reality_short_id: nullableString,
|
||||
reality_server_addr: nullableString,
|
||||
reality_server_port: portScheme,
|
||||
})
|
||||
.nullish();
|
||||
|
||||
const transportConfigScheme = z
|
||||
.object({
|
||||
path: nullableString,
|
||||
host: nullableString,
|
||||
service_name: nullableString,
|
||||
})
|
||||
.nullish();
|
||||
|
||||
const shadowsocksScheme = z.object({
|
||||
method: z.string(),
|
||||
port: portScheme,
|
||||
const ss = z.object({
|
||||
type: z.literal('shadowsocks'),
|
||||
host: nullableString,
|
||||
port: nullablePort,
|
||||
cipher: z.enum(SS_CIPHERS as any).nullish(),
|
||||
server_key: nullableString,
|
||||
});
|
||||
|
||||
const vmessScheme = z.object({
|
||||
port: portScheme,
|
||||
transport: z.string(),
|
||||
transport_config: transportConfigScheme,
|
||||
security: z.string(),
|
||||
security_config: securityConfigScheme,
|
||||
const vmess = z.object({
|
||||
type: z.literal('vmess'),
|
||||
host: nullableString,
|
||||
port: nullablePort,
|
||||
transport: z.enum(TRANSPORTS.vmess as any).nullish(),
|
||||
security: z.enum(SECURITY.vmess as any).nullish(),
|
||||
path: nullableString,
|
||||
service_name: nullableString,
|
||||
sni: nullableString,
|
||||
allow_insecure: nullableBool,
|
||||
fingerprint: nullableString,
|
||||
});
|
||||
|
||||
const vlessScheme = z.object({
|
||||
port: portScheme,
|
||||
transport: z.string(),
|
||||
transport_config: transportConfigScheme,
|
||||
security: z.string(),
|
||||
security_config: securityConfigScheme,
|
||||
flow: nullableString,
|
||||
const vless = z.object({
|
||||
type: z.literal('vless'),
|
||||
host: nullableString,
|
||||
port: nullablePort,
|
||||
transport: z.enum(TRANSPORTS.vless as any).nullish(),
|
||||
security: z.enum(SECURITY.vless as any).nullish(),
|
||||
path: nullableString,
|
||||
service_name: nullableString,
|
||||
flow: z.enum(FLOWS.vless as any).nullish(),
|
||||
sni: nullableString,
|
||||
allow_insecure: nullableBool,
|
||||
fingerprint: nullableString,
|
||||
reality_server_addr: nullableString,
|
||||
reality_server_port: nullablePort,
|
||||
reality_private_key: nullableString,
|
||||
reality_public_key: nullableString,
|
||||
reality_short_id: nullableString,
|
||||
});
|
||||
|
||||
const trojanScheme = z.object({
|
||||
port: portScheme,
|
||||
transport: z.string(),
|
||||
transport_config: transportConfigScheme,
|
||||
security: z.string(),
|
||||
security_config: securityConfigScheme,
|
||||
const trojan = z.object({
|
||||
type: z.literal('trojan'),
|
||||
host: nullableString,
|
||||
port: nullablePort,
|
||||
transport: z.enum(TRANSPORTS.trojan as any).nullish(),
|
||||
security: z.enum(SECURITY.trojan as any).nullish(),
|
||||
path: nullableString,
|
||||
service_name: nullableString,
|
||||
sni: nullableString,
|
||||
allow_insecure: nullableBool,
|
||||
fingerprint: nullableString,
|
||||
});
|
||||
|
||||
const hysteria2Scheme = z.object({
|
||||
port: portScheme,
|
||||
const hysteria2 = z.object({
|
||||
type: z.literal('hysteria2'),
|
||||
hop_ports: nullableString,
|
||||
hop_interval: z.number().nullish(),
|
||||
obfs_password: nullableString,
|
||||
security: z.string(),
|
||||
security_config: securityConfigScheme,
|
||||
host: nullableString,
|
||||
port: nullablePort,
|
||||
security: z.enum(SECURITY.hysteria2 as any).nullish(),
|
||||
sni: nullableString,
|
||||
allow_insecure: nullableBool,
|
||||
fingerprint: nullableString,
|
||||
});
|
||||
|
||||
const tuicScheme = z.object({
|
||||
port: portScheme,
|
||||
disable_sni: z.boolean().default(false),
|
||||
reduce_rtt: z.boolean().default(false),
|
||||
udp_relay_mode: z.string().default('native'),
|
||||
congestion_controller: z.string().default('bbr'),
|
||||
security_config: securityConfigScheme,
|
||||
const tuic = z.object({
|
||||
type: z.literal('tuic'),
|
||||
host: nullableString,
|
||||
port: nullablePort,
|
||||
disable_sni: z.boolean().nullish(),
|
||||
reduce_rtt: z.boolean().nullish(),
|
||||
udp_relay_mode: z.enum(TUIC_UDP_RELAY_MODES as any).nullish(),
|
||||
congestion_controller: z.enum(TUIC_CONGESTION as any).nullish(),
|
||||
sni: nullableString,
|
||||
allow_insecure: nullableBool,
|
||||
fingerprint: nullableString,
|
||||
});
|
||||
|
||||
const anytlsScheme = z.object({
|
||||
port: portScheme,
|
||||
security_config: securityConfigScheme,
|
||||
const anytls = z.object({
|
||||
type: z.literal('anytls'),
|
||||
host: nullableString,
|
||||
port: nullablePort,
|
||||
sni: nullableString,
|
||||
allow_insecure: nullableBool,
|
||||
fingerprint: nullableString,
|
||||
});
|
||||
|
||||
export const protocolConfigScheme = z.discriminatedUnion('protocol', [
|
||||
z.object({
|
||||
protocol: z.literal('shadowsocks'),
|
||||
enabled: z.boolean().default(false),
|
||||
config: shadowsocksScheme,
|
||||
}),
|
||||
z.object({
|
||||
protocol: z.literal('vmess'),
|
||||
enabled: z.boolean().default(false),
|
||||
config: vmessScheme,
|
||||
}),
|
||||
z.object({
|
||||
protocol: z.literal('vless'),
|
||||
enabled: z.boolean().default(false),
|
||||
config: vlessScheme,
|
||||
}),
|
||||
z.object({
|
||||
protocol: z.literal('trojan'),
|
||||
enabled: z.boolean().default(false),
|
||||
config: trojanScheme,
|
||||
}),
|
||||
z.object({
|
||||
protocol: z.literal('hysteria2'),
|
||||
enabled: z.boolean().default(false),
|
||||
config: hysteria2Scheme,
|
||||
}),
|
||||
z.object({
|
||||
protocol: z.literal('tuic'),
|
||||
enabled: z.boolean().default(false),
|
||||
config: tuicScheme,
|
||||
}),
|
||||
z.object({
|
||||
protocol: z.literal('anytls'),
|
||||
enabled: z.boolean().default(false),
|
||||
config: anytlsScheme,
|
||||
}),
|
||||
export const protocolApiScheme = z.discriminatedUnion('type', [
|
||||
ss,
|
||||
vmess,
|
||||
vless,
|
||||
trojan,
|
||||
hysteria2,
|
||||
tuic,
|
||||
anytls,
|
||||
]);
|
||||
|
||||
export const formScheme = z.object({
|
||||
name: z.string(),
|
||||
server_addr: z.string(),
|
||||
name: z.string().min(1),
|
||||
address: z.string().min(1),
|
||||
country: z.string().optional(),
|
||||
city: z.string().optional(),
|
||||
protocols: z.array(protocolConfigScheme).min(1),
|
||||
ratio: z.number().default(1),
|
||||
protocols: z.array(protocolApiScheme),
|
||||
});
|
||||
|
||||
export function getProtocolDefaultConfig(proto: (typeof protocols)[number]) {
|
||||
export type ProtocolType = (typeof protocols)[number];
|
||||
|
||||
export function getProtocolDefaultConfig(proto: ProtocolType) {
|
||||
switch (proto) {
|
||||
case 'shadowsocks':
|
||||
return { method: 'chacha20-ietf-poly1305', port: null, server_key: null };
|
||||
return {
|
||||
type: 'shadowsocks',
|
||||
port: null,
|
||||
cipher: 'chacha20-ietf-poly1305',
|
||||
server_key: null,
|
||||
} as any;
|
||||
case 'vmess':
|
||||
return {
|
||||
port: null,
|
||||
transport: 'tcp',
|
||||
transport_config: null,
|
||||
security: 'none',
|
||||
security_config: null,
|
||||
};
|
||||
return { type: 'vmess', port: null, transport: 'tcp', security: 'none' } as any;
|
||||
case 'vless':
|
||||
return {
|
||||
port: null,
|
||||
transport: 'tcp',
|
||||
transport_config: null,
|
||||
security: 'none',
|
||||
security_config: null,
|
||||
flow: null,
|
||||
};
|
||||
return { type: 'vless', port: null, transport: 'tcp', security: 'none', flow: 'none' } as any;
|
||||
case 'trojan':
|
||||
return {
|
||||
port: null,
|
||||
transport: 'tcp',
|
||||
transport_config: null,
|
||||
security: 'tls',
|
||||
security_config: {},
|
||||
};
|
||||
return { type: 'trojan', port: null, transport: 'tcp', security: 'tls' } as any;
|
||||
case 'hysteria2':
|
||||
return {
|
||||
type: 'hysteria2',
|
||||
port: null,
|
||||
hop_ports: null,
|
||||
hop_interval: null,
|
||||
obfs_password: null,
|
||||
security: 'tls',
|
||||
security_config: {},
|
||||
};
|
||||
} as any;
|
||||
case 'tuic':
|
||||
return {
|
||||
type: 'tuic',
|
||||
port: null,
|
||||
disable_sni: false,
|
||||
reduce_rtt: false,
|
||||
udp_relay_mode: 'native',
|
||||
congestion_controller: 'bbr',
|
||||
security_config: {},
|
||||
};
|
||||
} as any;
|
||||
case 'anytls':
|
||||
return { port: null, security_config: {} };
|
||||
return { type: 'anytls', port: null } as any;
|
||||
default:
|
||||
return {} as any;
|
||||
}
|
||||
|
||||
162
apps/admin/app/dashboard/servers/online-users-cell.tsx
Normal file
162
apps/admin/app/dashboard/servers/online-users-cell.tsx
Normal file
@ -0,0 +1,162 @@
|
||||
'use client';
|
||||
|
||||
import { UserDetail } from '@/app/dashboard/user/user-detail';
|
||||
import { IpLink } from '@/components/ip-link';
|
||||
import { ProTable } from '@/components/pro-table';
|
||||
import { filterServerList } from '@/services/admin/server';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { Badge } from '@workspace/ui/components/badge';
|
||||
import {
|
||||
Sheet,
|
||||
SheetContent,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
SheetTrigger,
|
||||
} from '@workspace/ui/components/sheet';
|
||||
import type { useTranslations } from 'next-intl';
|
||||
import { useState } from 'react';
|
||||
|
||||
function mapOnlineUsers(online: API.ServerStatus['online'] = []): {
|
||||
uid: string;
|
||||
ips: string[];
|
||||
subscribe?: string;
|
||||
subscribe_id?: number;
|
||||
traffic?: number;
|
||||
expired_at?: number;
|
||||
}[] {
|
||||
return (online || []).map((u) => ({
|
||||
uid: String(u.user_id || ''),
|
||||
ips: Array.isArray(u.ip) ? u.ip.map(String) : [],
|
||||
subscribe: (u as any).subscribe,
|
||||
subscribe_id: (u as any).subscribe_id,
|
||||
traffic: (u as any).traffic,
|
||||
expired_at: (u as any).expired_at,
|
||||
}));
|
||||
}
|
||||
|
||||
export default function OnlineUsersCell({
|
||||
serverId,
|
||||
status,
|
||||
t,
|
||||
}: {
|
||||
serverId?: number;
|
||||
status?: API.ServerStatus;
|
||||
t: ReturnType<typeof useTranslations>;
|
||||
}) {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const { data: latest } = useQuery({
|
||||
queryKey: ['serverStatusById', serverId, open],
|
||||
enabled: !!serverId && open,
|
||||
queryFn: async () => {
|
||||
const { data } = await filterServerList({ page: 1, size: 1, search: String(serverId) });
|
||||
const list = (data?.data?.list || []) as API.Server[];
|
||||
return list[0]?.status as API.ServerStatus | undefined;
|
||||
},
|
||||
});
|
||||
|
||||
const rows = mapOnlineUsers((latest || status)?.online);
|
||||
const count = rows.length;
|
||||
return (
|
||||
<Sheet open={open} onOpenChange={setOpen}>
|
||||
<SheetTrigger asChild>
|
||||
<button className='hover:text-foreground text-muted-foreground flex items-center gap-2 bg-transparent p-0 text-sm'>
|
||||
<Badge variant='secondary'>{count}</Badge>
|
||||
<span>{t('onlineUsers')}</span>
|
||||
</button>
|
||||
</SheetTrigger>
|
||||
<SheetContent className='h-screen w-screen max-w-none sm:h-auto sm:w-[900px] sm:max-w-[90vw]'>
|
||||
<SheetHeader>
|
||||
<SheetTitle>{t('onlineUsers')}</SheetTitle>
|
||||
</SheetHeader>
|
||||
<div className='-mx-6 h-[calc(100vh-48px-16px)] overflow-y-auto px-6 py-4 sm:h-[calc(100dvh-48px-16px-env(safe-area-inset-top))]'>
|
||||
<ProTable<
|
||||
{
|
||||
uid: string;
|
||||
ips: string[];
|
||||
subscribe?: string;
|
||||
subscribe_id?: number;
|
||||
traffic?: number;
|
||||
expired_at?: number;
|
||||
},
|
||||
Record<string, unknown>
|
||||
>
|
||||
header={{ hidden: true }}
|
||||
columns={[
|
||||
{
|
||||
accessorKey: 'ips',
|
||||
header: t('ipAddresses'),
|
||||
cell: ({ row }) => {
|
||||
const ips = row.original.ips;
|
||||
return (
|
||||
<div className='flex min-w-0 flex-col gap-1'>
|
||||
{ips.map((ip, i) => (
|
||||
<div
|
||||
key={`${row.original.uid}-${ip}`}
|
||||
className='whitespace-nowrap text-sm'
|
||||
>
|
||||
{i === 0 ? (
|
||||
<IpLink ip={ip} className='font-medium' />
|
||||
) : (
|
||||
<IpLink ip={ip} className='text-muted-foreground' />
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: 'user',
|
||||
header: t('user'),
|
||||
cell: ({ row }) => <UserDetail id={Number(row.original.uid)} />,
|
||||
},
|
||||
{
|
||||
accessorKey: 'subscription',
|
||||
header: t('subscription'),
|
||||
cell: ({ row }) => (
|
||||
<span className='text-sm'>{row.original.subscribe || '--'}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: 'subscribeId',
|
||||
header: t('subscribeId'),
|
||||
cell: ({ row }) => (
|
||||
<span className='font-mono text-sm'>{row.original.subscribe_id || '--'}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: 'traffic',
|
||||
header: t('traffic'),
|
||||
cell: ({ row }) => {
|
||||
const v = Number(row.original.traffic || 0);
|
||||
return <span className='text-sm'>{(v / 1024 ** 3).toFixed(2)} GB</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: 'expireTime',
|
||||
header: t('expireTime'),
|
||||
cell: ({ row }) => {
|
||||
const ts = Number(row.original.expired_at || 0);
|
||||
if (!ts) return <span className='text-muted-foreground'>--</span>;
|
||||
const expired = ts < Date.now() / 1000;
|
||||
return (
|
||||
<div className='flex items-center gap-2'>
|
||||
<span className='text-sm'>{new Date(ts * 1000).toLocaleString()}</span>
|
||||
{expired && (
|
||||
<Badge variant='destructive' className='w-fit px-1 py-0 text-xs'>
|
||||
{t('expired')}
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
]}
|
||||
request={async () => ({ list: rows, total: rows.length })}
|
||||
/>
|
||||
</div>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
);
|
||||
}
|
||||
@ -1,156 +1,25 @@
|
||||
'use client';
|
||||
import { UserDetail } from '@/app/dashboard/user/user-detail';
|
||||
import { IpLink } from '@/components/ip-link';
|
||||
// Online users detail moved to separate component
|
||||
import { ProTable, ProTableActions } from '@/components/pro-table';
|
||||
import { getUserSubscribeById } from '@/services/admin/user';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import {
|
||||
createServer,
|
||||
deleteServer,
|
||||
filterServerList,
|
||||
updateServer,
|
||||
} from '@/services/admin/server';
|
||||
import { Badge } from '@workspace/ui/components/badge';
|
||||
import { Button } from '@workspace/ui/components/button';
|
||||
import { Card, CardContent } from '@workspace/ui/components/card';
|
||||
import {
|
||||
Sheet,
|
||||
SheetContent,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
SheetTrigger,
|
||||
} from '@workspace/ui/components/sheet';
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from '@workspace/ui/components/tooltip';
|
||||
import { ConfirmButton } from '@workspace/ui/custom-components/confirm-button';
|
||||
import { cn } from '@workspace/ui/lib/utils';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useRef, useState } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import OnlineUsersCell from './online-users-cell';
|
||||
import ServerConfig from './server-config';
|
||||
import ServerForm from './server-form';
|
||||
|
||||
type ProtocolName = 'shadowsocks' | 'vmess' | 'vless' | 'trojan' | 'hysteria2' | 'tuic' | 'anytls';
|
||||
type ProtocolEntry = { protocol: ProtocolName; enabled: boolean; config: Record<string, unknown> };
|
||||
|
||||
interface ServerFormFields {
|
||||
name: string;
|
||||
server_addr: string;
|
||||
country?: string;
|
||||
city?: string;
|
||||
protocols: ProtocolEntry[];
|
||||
}
|
||||
|
||||
type ServerStatus = {
|
||||
online?: unknown;
|
||||
cpu?: number;
|
||||
mem?: number;
|
||||
disk?: number;
|
||||
updated_at?: number;
|
||||
};
|
||||
|
||||
type ServerItem = ServerFormFields & { id: number; status?: ServerStatus; [key: string]: unknown };
|
||||
|
||||
const mockList: ServerItem[] = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Server A',
|
||||
server_addr: '1.1.1.1',
|
||||
country: 'US',
|
||||
city: 'SFO',
|
||||
protocols: [
|
||||
{
|
||||
protocol: 'shadowsocks',
|
||||
enabled: true,
|
||||
config: { method: 'aes-128-gcm', port: 443, server_key: null },
|
||||
},
|
||||
{
|
||||
protocol: 'trojan',
|
||||
enabled: true,
|
||||
config: { port: 8443, transport: 'tcp', security: 'tls' },
|
||||
},
|
||||
{
|
||||
protocol: 'vmess',
|
||||
enabled: false,
|
||||
config: {
|
||||
port: 1443,
|
||||
transport: 'websocket',
|
||||
transport_config: { path: '/ws', host: 'example.com' },
|
||||
security: 'tls',
|
||||
},
|
||||
},
|
||||
],
|
||||
status: {
|
||||
online: { 1001: ['1.2.3.4'], 1002: ['5.6.7.8', '9.9.9.9'] },
|
||||
cpu: 34,
|
||||
mem: 62,
|
||||
disk: 48,
|
||||
updated_at: Date.now() / 1000,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Server B',
|
||||
server_addr: '2.2.2.2',
|
||||
country: 'JP',
|
||||
city: 'Tokyo',
|
||||
protocols: [
|
||||
{
|
||||
protocol: 'vmess',
|
||||
enabled: true,
|
||||
config: { port: 2443, transport: 'tcp', security: 'none' },
|
||||
},
|
||||
{
|
||||
protocol: 'hysteria2',
|
||||
enabled: true,
|
||||
config: { port: 3443, hop_ports: '443,8443,10443', hop_interval: 15, security: 'tls' },
|
||||
},
|
||||
{ protocol: 'tuic', enabled: false, config: { port: 4443 } },
|
||||
],
|
||||
status: {
|
||||
online: { 2001: ['10.0.0.1'] },
|
||||
cpu: 72,
|
||||
mem: 81,
|
||||
disk: 67,
|
||||
updated_at: Date.now() / 1000,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Server C',
|
||||
server_addr: '3.3.3.3',
|
||||
country: 'DE',
|
||||
city: 'FRA',
|
||||
protocols: [
|
||||
{ protocol: 'anytls', enabled: true, config: { port: 80 } },
|
||||
{
|
||||
protocol: 'shadowsocks',
|
||||
enabled: false,
|
||||
config: { method: 'chacha20-ietf-poly1305', port: 8080 },
|
||||
},
|
||||
],
|
||||
status: { online: {}, cpu: 0, mem: 0, disk: 0, updated_at: 0 },
|
||||
},
|
||||
];
|
||||
|
||||
let mockData: ServerItem[] = [...mockList];
|
||||
const getServerList = async () => ({ list: mockData, total: mockData.length });
|
||||
const createServer = async (values: Omit<ServerItem, 'id'>) => {
|
||||
mockData.push({
|
||||
id: Date.now(),
|
||||
name: '',
|
||||
server_addr: '',
|
||||
protocols: [],
|
||||
...values,
|
||||
});
|
||||
return true;
|
||||
};
|
||||
const updateServer = async (id: number, values: Omit<ServerItem, 'id'>) => {
|
||||
mockData = mockData.map((i) => (i.id === id ? { ...i, ...values } : i));
|
||||
return true;
|
||||
};
|
||||
const deleteServer = async (id: number) => {
|
||||
mockData = mockData.filter((i) => i.id !== id);
|
||||
return true;
|
||||
};
|
||||
|
||||
const PROTOCOL_COLORS: Record<ProtocolName, string> = {
|
||||
shadowsocks: 'bg-green-500',
|
||||
@ -162,42 +31,8 @@ const PROTOCOL_COLORS: Record<ProtocolName, string> = {
|
||||
anytls: 'bg-gray-500',
|
||||
};
|
||||
|
||||
function getEnabledProtocols(p: ServerItem['protocols']) {
|
||||
return Array.isArray(p) ? p.filter((x) => x.enabled) : [];
|
||||
}
|
||||
|
||||
function ProtocolBadge({
|
||||
item,
|
||||
t,
|
||||
}: {
|
||||
item: ServerItem['protocols'][number];
|
||||
t: (key: string) => string;
|
||||
}) {
|
||||
const color = PROTOCOL_COLORS[item.protocol];
|
||||
const port = (item?.config as any)?.port as number | undefined;
|
||||
const extra: string[] = [];
|
||||
if ((item.config as any)?.transport) extra.push(String((item.config as any).transport));
|
||||
if ((item.config as any)?.security && (item.config as any).security !== 'none')
|
||||
extra.push(String((item.config as any).security));
|
||||
const label = `${item.protocol}${port ? ` (${port})` : ''}`;
|
||||
const tipParts = [label, extra.length ? `· ${extra.join(' / ')}` : ''].filter(Boolean);
|
||||
const tooltip = tipParts.join(' ');
|
||||
return (
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Badge variant='outline' className={cn('text-primary-foreground', color)}>
|
||||
{label}
|
||||
</Badge>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>{tooltip || t('notAvailable')}</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
);
|
||||
}
|
||||
|
||||
function PctBar({ value }: { value: number }) {
|
||||
const v = Math.max(0, Math.min(100, Math.round(value)));
|
||||
const v = value.toFixed(2);
|
||||
return (
|
||||
<div className='min-w-24'>
|
||||
<div className='text-xs leading-none'>{v}%</div>
|
||||
@ -216,183 +51,19 @@ function RegionIpCell({
|
||||
}: {
|
||||
country?: string;
|
||||
city?: string;
|
||||
ip: string;
|
||||
ip?: string;
|
||||
t: (key: string) => string;
|
||||
}) {
|
||||
const region = [country, city].filter(Boolean).join(' / ') || t('notAvailable');
|
||||
return (
|
||||
<div className='flex items-center gap-1'>
|
||||
<Badge variant='outline'>{region}</Badge>
|
||||
<Badge variant='outline'>{ip}</Badge>
|
||||
<Badge variant='outline'>{ip || t('notAvailable')}</Badge>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function UserSubscribeInfo({
|
||||
userId,
|
||||
type,
|
||||
t,
|
||||
}: {
|
||||
userId: number;
|
||||
type: 'account' | 'subscribeName' | 'subscribeId' | 'traffic' | 'expireTime';
|
||||
t: (key: string) => string;
|
||||
}) {
|
||||
const { data } = useQuery({
|
||||
enabled: userId !== 0,
|
||||
queryKey: ['getUserSubscribeById', userId],
|
||||
queryFn: async () => {
|
||||
const { data } = await getUserSubscribeById({ id: userId });
|
||||
return data.data;
|
||||
},
|
||||
});
|
||||
if (!data) return <span className='text-muted-foreground'>--</span>;
|
||||
if (type === 'account')
|
||||
return data.user_id ? (
|
||||
<UserDetail id={data.user_id} />
|
||||
) : (
|
||||
<span className='text-muted-foreground'>--</span>
|
||||
);
|
||||
if (type === 'subscribeName')
|
||||
return data.subscribe?.name ? (
|
||||
<span className='text-sm'>{data.subscribe.name}</span>
|
||||
) : (
|
||||
<span className='text-muted-foreground'>--</span>
|
||||
);
|
||||
if (type === 'subscribeId')
|
||||
return data.id ? (
|
||||
<span className='font-mono text-sm'>{data.id}</span>
|
||||
) : (
|
||||
<span className='text-muted-foreground'>--</span>
|
||||
);
|
||||
if (type === 'traffic') {
|
||||
const used = (data.upload || 0) + (data.download || 0);
|
||||
const total = data.traffic || 0;
|
||||
return (
|
||||
<div className='min-w-0 text-sm'>{`${(used / 1024 ** 3).toFixed(2)} GB / ${total > 0 ? (total / 1024 ** 3).toFixed(2) + ' GB' : t('unlimited')}`}</div>
|
||||
);
|
||||
}
|
||||
if (type === 'expireTime') {
|
||||
if (!data.expire_time) return <span className='text-muted-foreground'>--</span>;
|
||||
const expired = data.expire_time < Date.now() / 1000;
|
||||
return (
|
||||
<div className='flex items-center gap-2'>
|
||||
<span className='text-sm'>{new Date((data.expire_time || 0) * 1000).toLocaleString()}</span>
|
||||
{expired && (
|
||||
<Badge variant='destructive' className='w-fit px-1 py-0 text-xs'>
|
||||
{t('expired')}
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return <span className='text-muted-foreground'>--</span>;
|
||||
}
|
||||
|
||||
function normalizeOnlineMap(online: unknown): { uid: string; ips: string[] }[] {
|
||||
if (!online || typeof online !== 'object' || Array.isArray(online)) return [];
|
||||
const m = online as Record<string, unknown>;
|
||||
const rows = Object.entries(m).map(([uid, ips]) => {
|
||||
if (Array.isArray(ips)) return { uid, ips: (ips as unknown[]).map(String) };
|
||||
if (typeof ips === 'string') return { uid, ips: [ips] };
|
||||
const o = ips as Record<string, unknown>;
|
||||
if (Array.isArray(o?.ips)) return { uid, ips: (o.ips as unknown[]).map(String) };
|
||||
return { uid, ips: [] };
|
||||
});
|
||||
return rows.filter((r) => r.ips.length > 0);
|
||||
}
|
||||
|
||||
function OnlineUsersCell({ status, t }: { status?: ServerStatus; t: (key: string) => string }) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const rows = normalizeOnlineMap(status?.online);
|
||||
const count = rows.length;
|
||||
return (
|
||||
<Sheet open={open} onOpenChange={setOpen}>
|
||||
<SheetTrigger asChild>
|
||||
<button className='hover:text-foreground text-muted-foreground flex items-center gap-2 bg-transparent p-0 text-sm'>
|
||||
<Badge variant='secondary'>{count}</Badge>
|
||||
<span>{t('onlineUsers')}</span>
|
||||
</button>
|
||||
</SheetTrigger>
|
||||
<SheetContent className='sm:w=[900px] h-screen w-screen max-w-none sm:h-auto sm:max-w-[90vw]'>
|
||||
<SheetHeader>
|
||||
<SheetTitle>{t('onlineUsers')}</SheetTitle>
|
||||
</SheetHeader>
|
||||
<div className='-mx-6 h-[calc(100vh-48px-16px)] overflow-y-auto px-6 py-4 sm:h-[calc(100dvh-48px-16px-env(safe-area-inset-top))]'>
|
||||
<ProTable<
|
||||
{
|
||||
uid: string;
|
||||
ips: string[];
|
||||
},
|
||||
Record<string, unknown>
|
||||
>
|
||||
header={{ hidden: true }}
|
||||
columns={[
|
||||
{
|
||||
accessorKey: 'ips',
|
||||
header: t('ipAddresses'),
|
||||
cell: ({ row }) => {
|
||||
const ips = row.original.ips;
|
||||
return (
|
||||
<div className='flex min-w-0 flex-col gap-1'>
|
||||
{ips.map((ip, i) => (
|
||||
<div
|
||||
key={`${row.original.uid}-${ip}`}
|
||||
className='whitespace-nowrap text-sm'
|
||||
>
|
||||
{i === 0 ? (
|
||||
<IpLink ip={ip} className='font-medium' />
|
||||
) : (
|
||||
<IpLink ip={ip} className='text-muted-foreground' />
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: 'user',
|
||||
header: t('user'),
|
||||
cell: ({ row }) => (
|
||||
<UserSubscribeInfo userId={Number(row.original.uid)} type='account' t={t} />
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: 'subscription',
|
||||
header: t('subscription'),
|
||||
cell: ({ row }) => (
|
||||
<UserSubscribeInfo userId={Number(row.original.uid)} type='subscribeName' t={t} />
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: 'subscribeId',
|
||||
header: t('subscribeId'),
|
||||
cell: ({ row }) => (
|
||||
<UserSubscribeInfo userId={Number(row.original.uid)} type='subscribeId' t={t} />
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: 'traffic',
|
||||
header: t('traffic'),
|
||||
cell: ({ row }) => (
|
||||
<UserSubscribeInfo userId={Number(row.original.uid)} type='traffic' t={t} />
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: 'expireTime',
|
||||
header: t('expireTime'),
|
||||
cell: ({ row }) => (
|
||||
<UserSubscribeInfo userId={Number(row.original.uid)} type='expireTime' t={t} />
|
||||
),
|
||||
},
|
||||
]}
|
||||
request={async () => ({ list: rows, total: rows.length })}
|
||||
/>
|
||||
</div>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
);
|
||||
}
|
||||
// OnlineUsersCell is now a standalone component
|
||||
|
||||
export default function ServersPage() {
|
||||
const t = useTranslations('servers');
|
||||
@ -407,7 +78,7 @@ export default function ServersPage() {
|
||||
<ServerConfig />
|
||||
</CardContent>
|
||||
</Card>
|
||||
<ProTable<ServerItem, { search: string }>
|
||||
<ProTable<API.Server, { search: string }>
|
||||
action={ref}
|
||||
header={{
|
||||
title: t('pageTitle'),
|
||||
@ -418,11 +89,16 @@ export default function ServersPage() {
|
||||
loading={loading}
|
||||
onSubmit={async (values) => {
|
||||
setLoading(true);
|
||||
await createServer(values as any);
|
||||
toast.success(t('created'));
|
||||
ref.current?.refresh();
|
||||
setLoading(false);
|
||||
return true;
|
||||
try {
|
||||
await createServer(values as unknown as API.CreateServerRequest);
|
||||
toast.success(t('created'));
|
||||
ref.current?.refresh();
|
||||
setLoading(false);
|
||||
return true;
|
||||
} catch (e) {
|
||||
setLoading(false);
|
||||
return false;
|
||||
}
|
||||
}}
|
||||
/>
|
||||
),
|
||||
@ -436,12 +112,12 @@ export default function ServersPage() {
|
||||
{ accessorKey: 'name', header: t('name') },
|
||||
{
|
||||
id: 'region_ip',
|
||||
header: t('serverAddress'),
|
||||
header: t('address'),
|
||||
cell: ({ row }) => (
|
||||
<RegionIpCell
|
||||
country={row.original.country as string}
|
||||
city={row.original.city as string}
|
||||
ip={row.original.server_addr as string}
|
||||
country={row.original.country as unknown as string}
|
||||
city={row.original.city as unknown as string}
|
||||
ip={row.original.address as unknown as string}
|
||||
t={t}
|
||||
/>
|
||||
),
|
||||
@ -450,28 +126,37 @@ export default function ServersPage() {
|
||||
accessorKey: 'protocols',
|
||||
header: t('protocols'),
|
||||
cell: ({ row }) => {
|
||||
const enabled = getEnabledProtocols(row.original.protocols);
|
||||
if (!enabled.length) return t('noData');
|
||||
const list = (row.original.protocols || []) as API.Protocol[];
|
||||
if (!list.length) return t('noData');
|
||||
return (
|
||||
<div className='flex flex-wrap gap-1'>
|
||||
{enabled.map((p, idx) => (
|
||||
<ProtocolBadge key={idx} item={p} t={t} />
|
||||
))}
|
||||
{list.map((p, idx) => {
|
||||
const proto = ((p as any)?.type || '') as ProtocolName | '';
|
||||
if (!proto) return null;
|
||||
const color = PROTOCOL_COLORS[proto as ProtocolName];
|
||||
const port = (p as any)?.port as number | undefined;
|
||||
const label = `${proto}${port ? ` (${port})` : ''}`;
|
||||
return (
|
||||
<Badge
|
||||
key={idx}
|
||||
variant='outline'
|
||||
className={cn('text-primary-foreground', color)}
|
||||
>
|
||||
{label}
|
||||
</Badge>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
id: 'status',
|
||||
header: t('status'),
|
||||
cell: ({ row }) => {
|
||||
const s = (row.original.status ?? {}) as ServerStatus;
|
||||
const on = !!(
|
||||
s.online &&
|
||||
typeof s.online === 'object' &&
|
||||
!Array.isArray(s.online) &&
|
||||
Object.keys(s.online as Record<string, unknown>).length
|
||||
);
|
||||
const s = (row.original.status ?? {}) as API.ServerStatus;
|
||||
const on = !!(Array.isArray(s.online) && s.online.length > 0);
|
||||
return (
|
||||
<div className='flex items-center gap-2'>
|
||||
<span
|
||||
@ -488,38 +173,56 @@ export default function ServersPage() {
|
||||
{
|
||||
id: 'cpu',
|
||||
header: t('cpu'),
|
||||
cell: ({ row }) => <PctBar value={(row.original.status?.cpu as number) ?? 0} />,
|
||||
cell: ({ row }) => (
|
||||
<PctBar value={(row.original.status?.cpu as unknown as number) ?? 0} />
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'mem',
|
||||
header: t('memory'),
|
||||
cell: ({ row }) => <PctBar value={(row.original.status?.mem as number) ?? 0} />,
|
||||
cell: ({ row }) => (
|
||||
<PctBar value={(row.original.status?.mem as unknown as number) ?? 0} />
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'disk',
|
||||
header: t('disk'),
|
||||
cell: ({ row }) => <PctBar value={(row.original.status?.disk as number) ?? 0} />,
|
||||
cell: ({ row }) => (
|
||||
<PctBar value={(row.original.status?.disk as unknown as number) ?? 0} />
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
id: 'online_users',
|
||||
header: t('onlineUsers'),
|
||||
cell: ({ row }) => (
|
||||
<OnlineUsersCell status={row.original.status as ServerStatus} t={t} />
|
||||
<OnlineUsersCell
|
||||
serverId={row.original.id}
|
||||
status={row.original.status as API.ServerStatus}
|
||||
t={t}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'traffic_ratio',
|
||||
header: t('traffic_ratio'),
|
||||
cell: ({ row }) => {
|
||||
const raw = row.original.ratio as unknown;
|
||||
const ratio = Number(raw ?? 1) || 1;
|
||||
return <span className='text-sm'>{ratio.toFixed(2)}x</span>;
|
||||
},
|
||||
},
|
||||
]}
|
||||
params={[{ key: 'search' }]}
|
||||
request={async (_pagination, filter) => {
|
||||
const { list } = await getServerList();
|
||||
const keyword = (filter?.search || '').toLowerCase().trim();
|
||||
const filtered = keyword
|
||||
? list.filter((item) =>
|
||||
[item.name, item.server_addr, item.country, item.city]
|
||||
.filter(Boolean)
|
||||
.some((v) => String(v).toLowerCase().includes(keyword)),
|
||||
)
|
||||
: list;
|
||||
return { list: filtered, total: filtered.length };
|
||||
request={async (pagination, filter) => {
|
||||
const { data } = await filterServerList({
|
||||
page: pagination.page,
|
||||
size: pagination.size,
|
||||
search: filter?.search || undefined,
|
||||
});
|
||||
const list = (data?.data?.list || []) as API.Server[];
|
||||
const total = (data?.data?.total ?? list.length) as number;
|
||||
return { list, total };
|
||||
}}
|
||||
actions={{
|
||||
render: (row) => [
|
||||
@ -527,21 +230,24 @@ export default function ServersPage() {
|
||||
key='edit'
|
||||
trigger={t('edit')}
|
||||
title={t('drawerEditTitle')}
|
||||
initialValues={{
|
||||
name: row.name as string,
|
||||
server_addr: row.server_addr as string,
|
||||
country: (row as any).country,
|
||||
city: (row as any).city,
|
||||
protocols: (row as ServerItem).protocols,
|
||||
}}
|
||||
initialValues={row as any}
|
||||
loading={loading}
|
||||
onSubmit={async (values) => {
|
||||
setLoading(true);
|
||||
await updateServer(row.id as number, values as any);
|
||||
toast.success(t('updated'));
|
||||
ref.current?.refresh();
|
||||
setLoading(false);
|
||||
return true;
|
||||
try {
|
||||
// ServerForm already returns API-shaped body; add id for update
|
||||
await updateServer({
|
||||
id: row.id,
|
||||
...(values as unknown as Omit<API.UpdateServerRequest, 'id'>),
|
||||
});
|
||||
toast.success(t('updated'));
|
||||
ref.current?.refresh();
|
||||
setLoading(false);
|
||||
return true;
|
||||
} catch (e) {
|
||||
setLoading(false);
|
||||
return false;
|
||||
}
|
||||
}}
|
||||
/>,
|
||||
<ConfirmButton
|
||||
@ -550,7 +256,7 @@ export default function ServersPage() {
|
||||
title={t('confirmDeleteTitle')}
|
||||
description={t('confirmDeleteDesc')}
|
||||
onConfirm={async () => {
|
||||
await deleteServer(row.id as number);
|
||||
await deleteServer({ id: row.id } as any);
|
||||
toast.success(t('deleted'));
|
||||
ref.current?.refresh();
|
||||
}}
|
||||
@ -562,8 +268,17 @@ export default function ServersPage() {
|
||||
variant='outline'
|
||||
onClick={async () => {
|
||||
setLoading(true);
|
||||
const { id, ...others } = row as ServerItem;
|
||||
await createServer(others as any);
|
||||
const { id, created_at, updated_at, last_reported_at, status, ...others } =
|
||||
row as any;
|
||||
const body: API.CreateServerRequest = {
|
||||
name: others.name,
|
||||
country: others.country,
|
||||
city: others.city,
|
||||
ratio: others.ratio,
|
||||
address: others.address,
|
||||
protocols: others.protocols || [],
|
||||
};
|
||||
await createServer(body);
|
||||
toast.success(t('copied'));
|
||||
ref.current?.refresh();
|
||||
setLoading(false);
|
||||
|
||||
@ -188,7 +188,7 @@ export default function ServerConfig() {
|
||||
<div className='flex cursor-pointer items-center justify-between'>
|
||||
<div className='flex items-center gap-3'>
|
||||
<div className='bg-primary/10 flex h-10 w-10 items-center justify-center rounded-lg'>
|
||||
<Icon icon='mdi:server-cog' className='text-primary h-5 w-5' />
|
||||
<Icon icon='mdi:resistor-nodes' className='text-primary h-5 w-5' />
|
||||
</div>
|
||||
<div className='flex-1'>
|
||||
<p className='font-medium'>{t('config.title')}</p>
|
||||
@ -274,6 +274,7 @@ export default function ServerConfig() {
|
||||
<EnhancedInput
|
||||
type='number'
|
||||
min={0}
|
||||
suffix='S'
|
||||
step={0.1}
|
||||
value={field.value as any}
|
||||
onValueChange={field.onChange}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -82,19 +82,19 @@ export default function Statistics() {
|
||||
title: t('onlineIPCount'),
|
||||
value: ServerTotal?.online_user_ips || 0,
|
||||
icon: 'uil:users-alt',
|
||||
href: '/dashboard/server',
|
||||
href: '/dashboard/servers',
|
||||
},
|
||||
{
|
||||
title: t('onlineNodeCount'),
|
||||
value: ServerTotal?.online_servers || 0,
|
||||
icon: 'uil:server-network',
|
||||
href: '/dashboard/server',
|
||||
href: '/dashboard/servers',
|
||||
},
|
||||
{
|
||||
title: t('offlineNodeCount'),
|
||||
value: ServerTotal?.offline_servers || 0,
|
||||
icon: 'uil:server-network-alt',
|
||||
href: '/dashboard/server',
|
||||
href: '/dashboard/servers',
|
||||
},
|
||||
{
|
||||
title: t('pendingTickets'),
|
||||
|
||||
@ -9,11 +9,6 @@ export const navs = [
|
||||
title: 'Maintenance',
|
||||
icon: 'flat-color-icons:data-protection',
|
||||
items: [
|
||||
{
|
||||
title: 'Server Management',
|
||||
url: '/dashboard/server',
|
||||
icon: 'flat-color-icons:data-protection',
|
||||
},
|
||||
{
|
||||
title: 'Server Management',
|
||||
url: '/dashboard/servers',
|
||||
|
||||
@ -1,27 +1,36 @@
|
||||
{
|
||||
"ADS Config": "Konfigurace ADS",
|
||||
"Announcement Management": "Správa oznámení",
|
||||
"Application Management": "Správa aplikací",
|
||||
"Auth Control": "Řízení ověřování",
|
||||
"Balance": "Zůstatek",
|
||||
"Commerce": "Obchod",
|
||||
"Commission": "Provize",
|
||||
"Coupon Management": "Správa kupónů",
|
||||
"Dashboard": "Přístrojová deska",
|
||||
"Document Management": "Správa dokumentů",
|
||||
"Finance": "Finance",
|
||||
"Email": "E-mail",
|
||||
"Gift": "Dárek",
|
||||
"Login": "Přihlášení",
|
||||
"Logs & Analytics": "Protokoly a analýzy",
|
||||
"Maintenance": "Údržba",
|
||||
"Marketing Management": "Řízení marketingu",
|
||||
"Node Management": "Správa uzlů",
|
||||
"Order Management": "Správa objednávek",
|
||||
"Payment Config": "Konfigurace platby",
|
||||
"Product Management": "Správa produktů",
|
||||
"Protocol Management": "Správa protokolů",
|
||||
"Rule Management": "Správa pravidel",
|
||||
"Server": "Server",
|
||||
"Register": "Registrace",
|
||||
"Reset Subscribe": "Obnovit předplatné",
|
||||
"SMS": "SMS",
|
||||
"Server Management": "Správa serveru",
|
||||
"Settings": "Nastavení",
|
||||
"Server Traffic": "Serverový provoz",
|
||||
"Subscribe": "Předplatit",
|
||||
"Subscribe Config": "Nastavení odběru",
|
||||
"Subscribe Traffic": "Provoz předplatného",
|
||||
"System": "Systém",
|
||||
"System Config": "Systémová konfigurace",
|
||||
"System Management": "Správa systému",
|
||||
"System Tool": "Systémový nástroj",
|
||||
"Ticket Management": "Správa lístků",
|
||||
"User": "Uživatel",
|
||||
"User Detail": "Podrobnosti o uživateli",
|
||||
"User Management": "Správa uživatelů"
|
||||
"User Management": "Správa uživatelů",
|
||||
"Users & Support": "Uživatelé a podpora"
|
||||
}
|
||||
|
||||
37
apps/admin/locales/cs-CZ/nodes.json
Normal file
37
apps/admin/locales/cs-CZ/nodes.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"address": "Adresa",
|
||||
"cancel": "Zrušit",
|
||||
"confirm": "Potvrdit",
|
||||
"confirmDeleteDesc": "Tuto akci nelze vrátit zpět.",
|
||||
"confirmDeleteTitle": "Smazat tento uzel?",
|
||||
"copied": "Zkopírováno",
|
||||
"copy": "Kopírovat",
|
||||
"create": "Vytvořit",
|
||||
"created": "Vytvořeno",
|
||||
"delete": "Smazat",
|
||||
"deleted": "Smazáno",
|
||||
"drawerCreateTitle": "Vytvořit uzel",
|
||||
"drawerEditTitle": "Upravit uzel",
|
||||
"edit": "Upravit",
|
||||
"enabled": "Povoleno",
|
||||
"enabled_off": "Zakázáno",
|
||||
"enabled_on": "Povoleno",
|
||||
"errors": {
|
||||
"nameRequired": "Zadejte prosím název",
|
||||
"portRange": "Port musí být mezi 1 a 65535",
|
||||
"protocolRequired": "Vyberte prosím protokol",
|
||||
"serverAddrRequired": "Zadejte prosím adresu pro vstup",
|
||||
"serverRequired": "Vyberte prosím server"
|
||||
},
|
||||
"name": "Název",
|
||||
"pageTitle": "Uzel",
|
||||
"port": "Port",
|
||||
"protocol": "Protokol",
|
||||
"select_protocol": "Vyberte protokol…",
|
||||
"select_server": "Vyberte server…",
|
||||
"server": "Server",
|
||||
"tags": "Štítky",
|
||||
"tags_description": "Štítek pro skupinování oprávnění (včetně vazby na plán a dodací politiky).",
|
||||
"tags_placeholder": "Použijte Enter nebo čárku (,) pro přidání více štítků",
|
||||
"updated": "Aktualizováno"
|
||||
}
|
||||
@ -1,60 +1,6 @@
|
||||
{
|
||||
"actions": "akce",
|
||||
"app": {
|
||||
"appDownloadURL": "URL pro stažení aplikace",
|
||||
"appIcon": "Ikona aplikace",
|
||||
"appList": "Seznam aplikací",
|
||||
"appName": "Název aplikace",
|
||||
"backupDomains": "Seznam záložních domén",
|
||||
"backupDomainsDescription": "Seznam záložních domén pro řešení domén, jedna doména na řádek",
|
||||
"batchDelete": "Hromadné smazání",
|
||||
"cancel": "Zrušit",
|
||||
"communicationKey": "Komunikační klíč",
|
||||
"communicationKeyDescription": "Klíč používaný pro komunikaci klienta",
|
||||
"config": "Konfigurace",
|
||||
"configApp": "Konfigurace aplikace",
|
||||
"confirm": "Potvrdit",
|
||||
"confirmDelete": "Potvrdit smazání",
|
||||
"create": "Vytvořit",
|
||||
"createApp": "Vytvořit aplikaci",
|
||||
"createSuccess": "Úspěšně vytvořeno",
|
||||
"defaultVersion": "Výchozí",
|
||||
"delete": "Smazat",
|
||||
"deleteWarning": "Tuto akci nelze vrátit zpět",
|
||||
"describeDescription": "Používá se k popisu aplikace, zobrazuje se v seznamu aplikací",
|
||||
"description": "Popis",
|
||||
"downloadLink": "Odkaz ke stažení",
|
||||
"edit": "Upravit",
|
||||
"editApp": "Upravit aplikaci",
|
||||
"encryption": "Metoda šifrování",
|
||||
"encryptionDescription": "Vyberte metodu šifrování pro komunikaci klienta. Pokud je vybrána, klient použije tuto metodu ke komunikaci se serverem",
|
||||
"nameDescription": "Název aplikace, zobrazuje se v seznamu aplikací",
|
||||
"platform": "Platforma",
|
||||
"selectApp": "Vybrat aplikaci",
|
||||
"selectAppDescription": "Vyberte aplikaci k nastavení, všechna nastavení se použijí na vybranou aplikaci",
|
||||
"startupPicture": "Úvodní obrázek",
|
||||
"startupPictureDescription": "Úvodní obrázek, podporuje síťové a lokální obrázky. Pro síťové obrázky zadejte úplnou URL adresu obrázku",
|
||||
"startupPicturePreview": "Náhled úvodního obrázku",
|
||||
"startupPictureSkip": "Čas přeskočení úvodního obrázku",
|
||||
"startupPictureSkipDescription": "Doba zobrazení úvodního obrázku v sekundách, zadejte 0 pro nezobrazení",
|
||||
"subscriptionProtocol": "Protokol předplatného",
|
||||
"updateSuccess": "Úspěšně aktualizováno",
|
||||
"version": "Verze"
|
||||
},
|
||||
"cancel": "Zrušit",
|
||||
"config": {
|
||||
"singleSubscriptionMode": "Režim jednorázového předplatného",
|
||||
"singleSubscriptionModeDescription": "Když je povoleno, všechna uživatelská předplatná budou převedena na zůstatek",
|
||||
"subscriptionDomain": "Doména předplatného",
|
||||
"subscriptionDomainDescription": "Používá se pro předplatné; nechte prázdné pro použití domény webu",
|
||||
"subscriptionDomainPlaceholder": "Zadejte doménu předplatného, jednu na řádek",
|
||||
"subscriptionPath": "Cesta předplatného",
|
||||
"subscriptionPathDescription": "Používá se pro předplatné; po úpravě nezapomeňte restartovat systém pro optimální výkon",
|
||||
"subscriptionPathPlaceholder": "Zadejte",
|
||||
"updateSuccess": "Úspěšně aktualizováno",
|
||||
"wildcardResolution": "Řešení zástupných znaků",
|
||||
"wildcardResolutionDescription": "Používá se pro předplatné"
|
||||
},
|
||||
"confirm": "Potvrdit",
|
||||
"confirmDelete": "Opravdu chcete smazat?",
|
||||
"copy": "Kopírovat",
|
||||
@ -95,6 +41,9 @@
|
||||
"name": "Název",
|
||||
"noLimit": "Bez omezení",
|
||||
"noReset": "Žádný Reset",
|
||||
"node": "Uzlový prvek",
|
||||
"nodeGroup": "Skupina uzlů",
|
||||
"nodes": "Uzly",
|
||||
"pricing": "Cenotvorba",
|
||||
"purchaseWithDiscount": "Povolit Odpočet",
|
||||
"purchaseWithDiscountDescription": "Povolit nebo zakázat funkci odhlášení. Po aktivaci systém provede zpracování odpočtu podle nakonfigurovaných pravidel a poměrů a zbývající hodnota bude vrácena na zůstatek.",
|
||||
@ -107,9 +56,6 @@
|
||||
"selectResetCycle": "Vyberte prosím resetovací cyklus",
|
||||
"selectSubscribeGroup": "Vyberte prosím skupinu předplatného",
|
||||
"selectUnitTime": "Vyberte jednotku času",
|
||||
"server": "Server",
|
||||
"serverGroup": "Skupina serverů",
|
||||
"servers": "Servery",
|
||||
"speedLimit": "Omezení rychlosti ",
|
||||
"traffic": "Přenos dat",
|
||||
"unitPrice": "Jednotková cena",
|
||||
@ -151,8 +97,6 @@
|
||||
"subscribeGroup": "Přihlásit se ke skupině",
|
||||
"tabs": {
|
||||
"subscribe": "Předplatit",
|
||||
"subscribeApp": "Konfigurace aplikace",
|
||||
"subscribeConfig": "Konfigurace předplatného",
|
||||
"subscribeGroup": "Skupina předplatných"
|
||||
},
|
||||
"traffic": "provoz",
|
||||
|
||||
@ -1,183 +0,0 @@
|
||||
{
|
||||
"config": {
|
||||
"addTimeSlot": "Přidat časový úsek",
|
||||
"communicationKey": "Komunikační klíč",
|
||||
"communicationKeyDescription": "Klíč pro komunikaci uzlů k zajištění bezpečnosti dat",
|
||||
"delete": "Smazat",
|
||||
"dynamicMultiplier": "Dynamický multiplikátor",
|
||||
"dynamicMultiplierDescription": "Dynamický multiplikátor označuje zpracování posílaných dat s různými multiplikátory pro různé uzly během různých časových období.",
|
||||
"endTime": "Konec",
|
||||
"inputPlaceholder": "Zadejte",
|
||||
"multiplier": "Multiplikátor",
|
||||
"nodePullInterval": "Interval stahování uzlu",
|
||||
"nodePullIntervalDescription": "Frekvence (v sekundách) pro stahování dat uzly z panelu",
|
||||
"nodePushInterval": "Interval odesílání uzlu",
|
||||
"nodePushIntervalDescription": "Frekvence odesílání dat uzly do panelu",
|
||||
"reset": "Resetovat",
|
||||
"save": "Uložit",
|
||||
"saveSuccess": "Úspěšně uloženo",
|
||||
"startTime": "Začátek",
|
||||
"timeSlot": "Časový úsek"
|
||||
},
|
||||
"group": {
|
||||
"actions": "Akce",
|
||||
"cancel": "Zrušit",
|
||||
"confirm": "Potvrdit",
|
||||
"confirmDelete": "Opravdu chcete smazat?",
|
||||
"create": "Vytvořit",
|
||||
"createNodeGroup": "Vytvořit skupinu uzlů",
|
||||
"createdSuccessfully": "Úspěšně vytvořeno",
|
||||
"delete": "Smazat",
|
||||
"deleteWarning": "Po smazání nebude možné data obnovit, prosím, buďte opatrní.",
|
||||
"deletedSuccessfully": "Úspěšně smazáno",
|
||||
"description": "Popis",
|
||||
"edit": "Upravit",
|
||||
"editNodeGroup": "Upravit skupinu uzlů",
|
||||
"name": "Název",
|
||||
"title": "Seznam skupin uzlů",
|
||||
"updatedAt": "Aktualizováno"
|
||||
},
|
||||
"groupForm": {
|
||||
"cancel": "Zrušit",
|
||||
"confirm": "Potvrdit",
|
||||
"description": "Popis",
|
||||
"name": "Název"
|
||||
},
|
||||
"node": {
|
||||
"abnormal": "Abnormální",
|
||||
"actions": "Akce",
|
||||
"address": "Adresa",
|
||||
"all": "Vše",
|
||||
"basicInfo": "Základní informace",
|
||||
"cancel": "Zrušit",
|
||||
"confirm": "Potvrdit",
|
||||
"confirmDelete": "Opravdu chcete smazat?",
|
||||
"copy": "Kopírovat",
|
||||
"copySuccess": "Úspěšně zkopírováno",
|
||||
"create": "Vytvořit",
|
||||
"createNode": "Vytvořit uzel",
|
||||
"createSuccess": "Úspěšně vytvořeno",
|
||||
"delete": "Smazat",
|
||||
"deleteSuccess": "Úspěšně smazáno",
|
||||
"deleteWarning": "Po smazání nebude možné data obnovit. Prosím, buďte opatrní.",
|
||||
"detail": "Detail",
|
||||
"disabled": "Zakázáno",
|
||||
"disk": "Disk",
|
||||
"edit": "Upravit",
|
||||
"editNode": "Upravit uzel",
|
||||
"enable": "Povolit",
|
||||
"enabled": "Povoleno",
|
||||
"expireTime": "Čas vypršení",
|
||||
"hide": "Skrýt",
|
||||
"id": "ID",
|
||||
"ipAddresses": "IP adresy",
|
||||
"lastUpdated": "Poslední aktualizace",
|
||||
"location": "Umístění",
|
||||
"memory": "Paměť",
|
||||
"name": "Název",
|
||||
"noData": "--",
|
||||
"node": "Uzel",
|
||||
"nodeDetail": "Detail uzlu",
|
||||
"nodeGroup": "Skupina uzlů",
|
||||
"nodeStatus": "Stav uzlu",
|
||||
"normal": "Normální",
|
||||
"onlineCount": "Počet online",
|
||||
"onlineUsers": "Online uživatelé",
|
||||
"protocol": "Protokol",
|
||||
"rate": "Rychlost",
|
||||
"relay": "Přenos",
|
||||
"serverAddr": "Adresa serveru",
|
||||
"speedLimit": "Omezení rychlosti",
|
||||
"status": "Stav",
|
||||
"subscribeId": "ID předplatného",
|
||||
"subscribeName": "Název předplatného",
|
||||
"subscription": "Předplatné",
|
||||
"tags": "Štítky",
|
||||
"trafficRatio": "Poměr provozu",
|
||||
"trafficUsage": "Využití provozu",
|
||||
"type": "Typ",
|
||||
"updateSuccess": "Úspěšně aktualizováno",
|
||||
"updatedAt": "Čas aktualizace",
|
||||
"user": "Uživatel",
|
||||
"userDetail": "Detail uživatele",
|
||||
"userId": "ID uživatele"
|
||||
},
|
||||
"nodeForm": {
|
||||
"allowInsecure": "Povolit nezabezpečené",
|
||||
"cancel": "Zrušit",
|
||||
"city": "Město",
|
||||
"confirm": "Potvrdit",
|
||||
"congestionController": "Ovladač přetížení",
|
||||
"country": "Země",
|
||||
"disableSni": "Zakázat SNI",
|
||||
"edit": "Upravit",
|
||||
"editSecurity": "Upravit bezpečnostní konfiguraci",
|
||||
"enableTLS": "Povolit TLS",
|
||||
"encryptionMethod": "Metoda šifrování",
|
||||
"fingerprint": "Otisk",
|
||||
"flow": "Algoritmus řízení toku",
|
||||
"groupId": "Skupina uzlů",
|
||||
"hopInterval": "Interval skoků",
|
||||
"hopPorts": "Porty skoků",
|
||||
"hopPortsPlaceholder": "Oddělte více portů čárkami",
|
||||
"name": "Název",
|
||||
"obfsPassword": "Heslo pro obfuskování",
|
||||
"obfsPasswordPlaceholder": "Nechte prázdné pro žádné obfuskování",
|
||||
"path": "Cesta",
|
||||
"pleaseSelect": "Prosím vyberte",
|
||||
"port": "Port serveru",
|
||||
"protocol": "Protokol",
|
||||
"reduceRtt": "Snížit RTT",
|
||||
"relayHost": "Hostitel relé",
|
||||
"relayMode": "Režim relé",
|
||||
"relayPort": "Port relé",
|
||||
"relayPrefix": "Předpona relé",
|
||||
"remarks": "Poznámky",
|
||||
"security": "Bezpečnost",
|
||||
"securityConfig": "Bezpečnostní konfigurace",
|
||||
"selectEncryptionMethod": "Vyberte metodu šifrování",
|
||||
"selectNodeGroup": "Vyberte skupinu uzlů",
|
||||
"selectProtocol": "Vyberte protokol",
|
||||
"selectRelayMode": "Vyberte režim relé",
|
||||
"serverAddr": "Adresa serveru",
|
||||
"serverKey": "Klíč serveru",
|
||||
"serverName": "Název služby",
|
||||
"speedLimit": "Rychlostní limit",
|
||||
"speedLimitPlaceholder": "Neomezeno",
|
||||
"tags": "Štítky",
|
||||
"tagsPlaceholder": "Použijte Enter nebo čárku (,) pro zadání více štítků",
|
||||
"trafficRatio": "Poměr provozu",
|
||||
"transport": "Konfigurace transportního protokolu",
|
||||
"transportConfig": "Konfigurace transportního protokolu",
|
||||
"transportHost": "Adresa transportního serveru",
|
||||
"transportPath": "Transportní cesta",
|
||||
"transportServerName": "Název transportního serveru",
|
||||
"udpRelayMode": "Režim UDP relé"
|
||||
},
|
||||
"relayModeOptions": {
|
||||
"all": "Vše",
|
||||
"none": "Žádné",
|
||||
"random": "Náhodně"
|
||||
},
|
||||
"securityConfig": {
|
||||
"fingerprint": "Otisk",
|
||||
"privateKey": "Soukromý klíč",
|
||||
"privateKeyPlaceholder": "Nechte prázdné pro automatické vygenerování",
|
||||
"publicKey": "Veřejný klíč",
|
||||
"publicKeyPlaceholder": "Nechte prázdné pro automatické vygenerování",
|
||||
"serverAddress": "Adresa serveru",
|
||||
"serverAddressPlaceholder": "Cílová adresa REALITY, výchozí použití SNI",
|
||||
"serverName": "Název serveru (SNI)",
|
||||
"serverNamePlaceholder": "REALITY vyžaduje, konzistentní s backendem",
|
||||
"serverPort": "Port serveru",
|
||||
"serverPortPlaceholder": "Cílový port REALITY, výchozí 443",
|
||||
"shortId": "Krátké ID",
|
||||
"shortIdPlaceholder": "Nechte prázdné pro automatické vygenerování",
|
||||
"sni": "Indikace názvu serveru (SNI)"
|
||||
},
|
||||
"tabs": {
|
||||
"node": "Uzlu",
|
||||
"nodeConfig": "Konfigurace uzlu",
|
||||
"nodeGroup": "Skupina uzlů"
|
||||
}
|
||||
}
|
||||
101
apps/admin/locales/cs-CZ/servers.json
Normal file
101
apps/admin/locales/cs-CZ/servers.json
Normal file
@ -0,0 +1,101 @@
|
||||
{
|
||||
"address": "Adresa",
|
||||
"address_placeholder": "Adresa serveru",
|
||||
"cancel": "Zrušit",
|
||||
"city": "Město",
|
||||
"config": {
|
||||
"actions": {
|
||||
"cancel": "Zrušit",
|
||||
"save": "Uložit"
|
||||
},
|
||||
"communicationKey": "Komunikační klíč",
|
||||
"communicationKeyDescription": "Používá se pro autentizaci uzlu.",
|
||||
"description": "Spravujte klíče pro komunikaci uzlu, intervaly stahování/odesílání a dynamické multiplikátory.",
|
||||
"dynamicMultiplier": "Dynamický multiplikátor",
|
||||
"dynamicMultiplierDescription": "Definujte časové sloty a multiplikátory pro úpravu účtování provozu.",
|
||||
"endTime": "Čas konce",
|
||||
"inputPlaceholder": "Prosím zadejte",
|
||||
"multiplier": "Multiplikátor",
|
||||
"nodePullInterval": "Interval stahování uzlu",
|
||||
"nodePullIntervalDescription": "Jak často uzel stahuje konfiguraci (vteřiny).",
|
||||
"nodePushInterval": "Interval odesílání uzlu",
|
||||
"nodePushIntervalDescription": "Jak často uzel odesílá statistiky (vteřiny).",
|
||||
"reset": "Obnovit",
|
||||
"save": "Uložit",
|
||||
"saveSuccess": "Úspěšně uloženo",
|
||||
"startTime": "Čas začátku",
|
||||
"timeSlot": "Časový slot",
|
||||
"title": "Konfigurace uzlu"
|
||||
},
|
||||
"confirm": "Potvrdit",
|
||||
"confirmDeleteDesc": "Tuto akci nelze vrátit zpět.",
|
||||
"confirmDeleteTitle": "Smazat tento server?",
|
||||
"congestion_controller": "Ovladač přetížení",
|
||||
"copied": "Zkopírováno",
|
||||
"copy": "Kopírovat",
|
||||
"country": "Země",
|
||||
"cpu": "CPU",
|
||||
"create": "Vytvořit",
|
||||
"created": "Úspěšně vytvořeno",
|
||||
"delete": "Smazat",
|
||||
"deleted": "Úspěšně smazáno",
|
||||
"disable_sni": "Zakázat SNI",
|
||||
"disk": "Disk",
|
||||
"drawerCreateTitle": "Vytvořit server",
|
||||
"drawerEditTitle": "Upravit server",
|
||||
"edit": "Upravit",
|
||||
"enabled": "Povoleno",
|
||||
"encryption_method": "Metoda šifrování",
|
||||
"expireTime": "Čas vypršení",
|
||||
"expired": "Vypršelo",
|
||||
"flow": "Tok",
|
||||
"hop_interval": "Interval skoku",
|
||||
"hop_ports": "Porty skoku",
|
||||
"hop_ports_placeholder": "např. 1-65535",
|
||||
"host": "Hostitel",
|
||||
"id": "ID",
|
||||
"ipAddresses": "IP adresy",
|
||||
"memory": "Paměť",
|
||||
"name": "Název",
|
||||
"noData": "Žádná data",
|
||||
"notAvailable": "Není k dispozici",
|
||||
"obfs_password": "Heslo pro obfuskaci",
|
||||
"obfs_password_placeholder": "Zadejte heslo pro obfuskaci",
|
||||
"offline": "Offline",
|
||||
"online": "Online",
|
||||
"onlineUsers": "Online uživatelé",
|
||||
"pageTitle": "Servery",
|
||||
"path": "Cesta",
|
||||
"please_select": "Prosím vyberte",
|
||||
"port": "Port",
|
||||
"protocols": "Protokoly",
|
||||
"reduce_rtt": "Snížit RTT",
|
||||
"security_allow_insecure": "Povolit nezabezpečené",
|
||||
"security_fingerprint": "Otisk prstu",
|
||||
"security_private_key": "Soukromý klíč reality",
|
||||
"security_private_key_placeholder": "Zadejte soukromý klíč",
|
||||
"security_public_key": "Veřejný klíč reality",
|
||||
"security_public_key_placeholder": "Zadejte veřejný klíč",
|
||||
"security_server_address": "Adresa serveru reality",
|
||||
"security_server_address_placeholder": "např. 1.2.3.4 nebo doména",
|
||||
"security_server_port": "Port serveru reality",
|
||||
"security_short_id": "Krátké ID reality",
|
||||
"security_short_id_placeholder": "Hexadecimální řetězec (max. 16 znaků)",
|
||||
"security_sni": "SNI",
|
||||
"security_title": "Bezpečnost",
|
||||
"select_encryption_method": "Vyberte metodu šifrování",
|
||||
"server_key": "Klíč serveru",
|
||||
"service_name": "Název služby",
|
||||
"status": "Stav",
|
||||
"subscribeId": "ID předplatného",
|
||||
"subscription": "Předplatné",
|
||||
"traffic": "Provoz",
|
||||
"traffic_ratio": "Multiplikátor",
|
||||
"transport_title": "Transport",
|
||||
"udp_relay_mode": "Režim UDP relé",
|
||||
"unitSecondsShort": "S",
|
||||
"unlimited": "Neomezeno",
|
||||
"updated": "Úspěšně aktualizováno",
|
||||
"user": "Uživatel",
|
||||
"validation_failed": "Ověření selhalo. Zkontrolujte formulář."
|
||||
}
|
||||
@ -1,27 +1,36 @@
|
||||
{
|
||||
"ADS Config": "ADS-Konfiguration",
|
||||
"Announcement Management": "Ankündigungsverwaltung",
|
||||
"Application Management": "Anwendungsverwaltung",
|
||||
"Auth Control": "Authentifizierungskontrolle",
|
||||
"Balance": "Guthaben",
|
||||
"Commerce": "Handel",
|
||||
"Commission": "Provision",
|
||||
"Coupon Management": "Gutscheinverwaltung",
|
||||
"Dashboard": "Armaturenbrett",
|
||||
"Document Management": "Dokumentenverwaltung",
|
||||
"Finance": "Finanzen",
|
||||
"Email": "E-Mail",
|
||||
"Gift": "Geschenk",
|
||||
"Login": "Anmelden",
|
||||
"Logs & Analytics": "Protokolle & Analysen",
|
||||
"Maintenance": "Wartung",
|
||||
"Marketing Management": "Marketingmanagement",
|
||||
"Node Management": "Knotenverwaltung",
|
||||
"Order Management": "Bestellverwaltung",
|
||||
"Payment Config": "Zahlungskonfiguration",
|
||||
"Product Management": "Produktmanagement",
|
||||
"Protocol Management": "Protokollverwaltung",
|
||||
"Rule Management": "Regelverwaltung",
|
||||
"Server": "Dienst",
|
||||
"Register": "Registrieren",
|
||||
"Reset Subscribe": "Abonnement zurücksetzen",
|
||||
"SMS": "SMS",
|
||||
"Server Management": "Serververwaltung",
|
||||
"Settings": "Einstellungen",
|
||||
"Server Traffic": "Serververkehr",
|
||||
"Subscribe": "Abonnieren",
|
||||
"Subscribe Config": "Abonnieren-Konfiguration",
|
||||
"Subscribe Traffic": "Abonnieren Verkehr",
|
||||
"System": "System",
|
||||
"System Config": "Systemkonfiguration",
|
||||
"System Management": "Systemverwaltung",
|
||||
"System Tool": "Systemwerkzeug",
|
||||
"Ticket Management": "Ticketverwaltung",
|
||||
"User": "Benutzer",
|
||||
"User Detail": "Benutzerdetails",
|
||||
"User Management": "Benutzerverwaltung"
|
||||
"User Management": "Benutzerverwaltung",
|
||||
"Users & Support": "Benutzer & Unterstützung"
|
||||
}
|
||||
|
||||
37
apps/admin/locales/de-DE/nodes.json
Normal file
37
apps/admin/locales/de-DE/nodes.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"address": "Adresse",
|
||||
"cancel": "Abbrechen",
|
||||
"confirm": "Bestätigen",
|
||||
"confirmDeleteDesc": "Diese Aktion kann nicht rückgängig gemacht werden.",
|
||||
"confirmDeleteTitle": "Knoten löschen?",
|
||||
"copied": "Kopiert",
|
||||
"copy": "Kopieren",
|
||||
"create": "Erstellen",
|
||||
"created": "Erstellt",
|
||||
"delete": "Löschen",
|
||||
"deleted": "Gelöscht",
|
||||
"drawerCreateTitle": "Knoten erstellen",
|
||||
"drawerEditTitle": "Knoten bearbeiten",
|
||||
"edit": "Bearbeiten",
|
||||
"enabled": "Aktiviert",
|
||||
"enabled_off": "Deaktiviert",
|
||||
"enabled_on": "Aktiviert",
|
||||
"errors": {
|
||||
"nameRequired": "Bitte geben Sie einen Namen ein",
|
||||
"portRange": "Der Port muss zwischen 1 und 65535 liegen",
|
||||
"protocolRequired": "Bitte wählen Sie ein Protokoll aus",
|
||||
"serverAddrRequired": "Bitte geben Sie eine Eingangsadresse ein",
|
||||
"serverRequired": "Bitte wählen Sie einen Server aus"
|
||||
},
|
||||
"name": "Name",
|
||||
"pageTitle": "Knoten",
|
||||
"port": "Port",
|
||||
"protocol": "Protokoll",
|
||||
"select_protocol": "Protokoll auswählen…",
|
||||
"select_server": "Server auswählen…",
|
||||
"server": "Server",
|
||||
"tags": "Tags",
|
||||
"tags_description": "Berechtigungsgruppierungs-Tag (einschließlich Planbindung und Lieferrichtlinien).",
|
||||
"tags_placeholder": "Verwenden Sie Enter oder Komma (,) um mehrere Tags hinzuzufügen",
|
||||
"updated": "Aktualisiert"
|
||||
}
|
||||
@ -1,59 +1,6 @@
|
||||
{
|
||||
"actions": "Aktionen",
|
||||
"app": {
|
||||
"appDownloadURL": "App-Download-URL",
|
||||
"appIcon": "App-Symbol",
|
||||
"appList": "App-Liste",
|
||||
"appName": "App-Name",
|
||||
"backupDomains": "Liste der Backup-Domains",
|
||||
"backupDomainsDescription": "Liste der Backup-Domains für die Domain-Auflösung, eine Domain pro Zeile",
|
||||
"batchDelete": "Stapel löschen",
|
||||
"cancel": "Abbrechen",
|
||||
"communicationKey": "Kommunikationsschlüssel",
|
||||
"communicationKeyDescription": "Schlüssel, der für die Kommunikation mit dem Client verwendet wird",
|
||||
"config": "Konfiguration",
|
||||
"configApp": "App-Konfiguration",
|
||||
"confirm": "Bestätigen",
|
||||
"confirmDelete": "Löschen bestätigen",
|
||||
"create": "Erstellen",
|
||||
"createApp": "App erstellen",
|
||||
"createSuccess": "Erfolgreich erstellt",
|
||||
"defaultVersion": "Standard",
|
||||
"delete": "Löschen",
|
||||
"deleteWarning": "Diese Aktion kann nicht rückgängig gemacht werden",
|
||||
"describeDescription": "Wird verwendet, um die Anwendung zu beschreiben, wird in der App-Liste angezeigt",
|
||||
"description": "Beschreibung",
|
||||
"downloadLink": "Download-Link",
|
||||
"edit": "Bearbeiten",
|
||||
"editApp": "App bearbeiten",
|
||||
"encryption": "Verschlüsselungsmethode",
|
||||
"encryptionDescription": "Wählen Sie die Verschlüsselungsmethode für die Kommunikation mit dem Client. Wenn ausgewählt, wird der Client diese Methode verwenden, um mit dem Server zu kommunizieren.",
|
||||
"nameDescription": "Anwendungsname, wird in der App-Liste angezeigt",
|
||||
"platform": "Plattform",
|
||||
"selectApp": "App auswählen",
|
||||
"selectAppDescription": "Wählen Sie die App aus, die konfiguriert werden soll. Alle Einstellungen gelten für die ausgewählte App.",
|
||||
"startupPicture": "Startbild",
|
||||
"startupPictureDescription": "Startbild, unterstützt Netzwerk- und lokale Bilder. Für Netzwerkbilder bitte die vollständige Bild-URL eingeben",
|
||||
"startupPicturePreview": "Vorschau des Startbildes",
|
||||
"startupPictureSkip": "Überspringzeit des Startbildes",
|
||||
"startupPictureSkipDescription": "Anzeigedauer des Startbildes in Sekunden, 0 eingeben, um nicht anzuzeigen",
|
||||
"subscriptionProtocol": "Abonnementprotokoll",
|
||||
"updateSuccess": "Erfolgreich aktualisiert",
|
||||
"version": "Version"
|
||||
},
|
||||
"cancel": "Abbrechen",
|
||||
"config": {
|
||||
"singleSubscriptionMode": "Einzelabonnement-Modus",
|
||||
"subscriptionDomain": "Abonnement-Domain",
|
||||
"subscriptionDomainDescription": "Wird für Abonnements verwendet; leer lassen, um die Site-Domain zu verwenden",
|
||||
"subscriptionDomainPlaceholder": "Abonnement-Domain eingeben, eine pro Zeile",
|
||||
"subscriptionPath": "Abonnement-Pfad",
|
||||
"subscriptionPathDescription": "Wird für Abonnements verwendet; starten Sie das System nach der Änderung neu, um die optimale Leistung zu gewährleisten",
|
||||
"subscriptionPathPlaceholder": "Eingeben",
|
||||
"updateSuccess": "Erfolgreich aktualisiert",
|
||||
"wildcardResolution": "Wildcard-Auflösung",
|
||||
"wildcardResolutionDescription": "Wird für Abonnements verwendet"
|
||||
},
|
||||
"confirm": "Bestätigen",
|
||||
"confirmDelete": "Möchten Sie wirklich löschen?",
|
||||
"copy": "Kopieren",
|
||||
@ -94,6 +41,9 @@
|
||||
"name": "Name",
|
||||
"noLimit": "Keine Begrenzung",
|
||||
"noReset": "Kein Zurücksetzen",
|
||||
"node": "Knoten",
|
||||
"nodeGroup": "Knotengruppe",
|
||||
"nodes": "Knoten",
|
||||
"pricing": "Preisgestaltung",
|
||||
"purchaseWithDiscount": "Abzug erlauben",
|
||||
"purchaseWithDiscountDescription": "Aktivieren oder deaktivieren Sie die Abmeldefunktion. Nach der Aktivierung führt das System die Abzugsverarbeitung gemäß den konfigurierten Regeln und Anteilen durch, und der verbleibende Wert wird dem Guthaben gutgeschrieben.",
|
||||
@ -106,9 +56,6 @@
|
||||
"selectResetCycle": "Bitte wählen Sie einen Zurücksetzungszyklus",
|
||||
"selectSubscribeGroup": "Bitte Abonnementgruppe auswählen",
|
||||
"selectUnitTime": "Bitte wählen Sie eine Zeiteinheit",
|
||||
"server": "Dienst",
|
||||
"serverGroup": "Dienstgruppe",
|
||||
"servers": "Server",
|
||||
"speedLimit": "Geschwindigkeitsbegrenzung ",
|
||||
"traffic": "Datenvolumen",
|
||||
"unitPrice": "Einheitspreis",
|
||||
@ -150,8 +97,6 @@
|
||||
"subscribeGroup": "Gruppe abonnieren",
|
||||
"tabs": {
|
||||
"subscribe": "Abonnieren",
|
||||
"subscribeApp": "App-Konfiguration",
|
||||
"subscribeConfig": "Abonnement-Konfiguration",
|
||||
"subscribeGroup": "Abonnieren Gruppe"
|
||||
},
|
||||
"traffic": "Verkehr",
|
||||
|
||||
@ -1,183 +0,0 @@
|
||||
{
|
||||
"config": {
|
||||
"addTimeSlot": "Zeitfenster hinzufügen",
|
||||
"communicationKey": "Kommunikationsschlüssel",
|
||||
"communicationKeyDescription": "Schlüssel für die Knotenkommunikation zur Gewährleistung der Datensicherheit",
|
||||
"delete": "Löschen",
|
||||
"dynamicMultiplier": "Dynamischer Multiplikator",
|
||||
"dynamicMultiplierDescription": "Dynamischer Multiplikator bezieht sich auf die Verarbeitung von übertragenen Daten mit unterschiedlichen Multiplikatoren für verschiedene Knoten während unterschiedlicher Zeiträume.",
|
||||
"endTime": "Endzeit",
|
||||
"inputPlaceholder": "Eingeben",
|
||||
"multiplier": "Multiplikator",
|
||||
"nodePullInterval": "Knotenabfrageintervall",
|
||||
"nodePullIntervalDescription": "Häufigkeit (in Sekunden), mit der Knoten Daten vom Panel abrufen",
|
||||
"nodePushInterval": "Knotenübertragungsintervall",
|
||||
"nodePushIntervalDescription": "Häufigkeit, mit der Knoten Daten an das Panel übertragen",
|
||||
"reset": "Zurücksetzen",
|
||||
"save": "Speichern",
|
||||
"saveSuccess": "Erfolgreich gespeichert",
|
||||
"startTime": "Startzeit",
|
||||
"timeSlot": "Zeitfenster"
|
||||
},
|
||||
"group": {
|
||||
"actions": "Aktionen",
|
||||
"cancel": "Abbrechen",
|
||||
"confirm": "Bestätigen",
|
||||
"confirmDelete": "Möchten Sie wirklich löschen?",
|
||||
"create": "Erstellen",
|
||||
"createNodeGroup": "Knoten-Gruppe erstellen",
|
||||
"createdSuccessfully": "Erfolgreich erstellt",
|
||||
"delete": "Löschen",
|
||||
"deleteWarning": "Nach dem Löschen können die Daten nicht wiederhergestellt werden, bitte vorsichtig vorgehen.",
|
||||
"deletedSuccessfully": "Erfolgreich gelöscht",
|
||||
"description": "Beschreibung",
|
||||
"edit": "Bearbeiten",
|
||||
"editNodeGroup": "Knoten-Gruppe bearbeiten",
|
||||
"name": "Name",
|
||||
"title": "Liste der Knoten-Gruppen",
|
||||
"updatedAt": "Aktualisierungszeit"
|
||||
},
|
||||
"groupForm": {
|
||||
"cancel": "Abbrechen",
|
||||
"confirm": "Bestätigen",
|
||||
"description": "Beschreibung",
|
||||
"name": "Name"
|
||||
},
|
||||
"node": {
|
||||
"abnormal": "Abnormalität",
|
||||
"actions": "Aktionen",
|
||||
"address": "Adresse",
|
||||
"all": "Alle",
|
||||
"basicInfo": "Grundlegende Informationen",
|
||||
"cancel": "Abbrechen",
|
||||
"confirm": "Bestätigen",
|
||||
"confirmDelete": "Möchten Sie wirklich löschen?",
|
||||
"copy": "Kopieren",
|
||||
"copySuccess": "Erfolgreich kopiert",
|
||||
"create": "Erstellen",
|
||||
"createNode": "Knoten erstellen",
|
||||
"createSuccess": "Erfolgreich erstellt",
|
||||
"delete": "Löschen",
|
||||
"deleteSuccess": "Erfolgreich gelöscht",
|
||||
"deleteWarning": "Nach dem Löschen können die Daten nicht wiederhergestellt werden. Bitte vorsichtig vorgehen.",
|
||||
"detail": "Einzelheiten",
|
||||
"disabled": "Deaktiviert",
|
||||
"disk": "Festplatte",
|
||||
"edit": "Bearbeiten",
|
||||
"editNode": "Knoten bearbeiten",
|
||||
"enable": "Aktivieren",
|
||||
"enabled": "Aktiviert",
|
||||
"expireTime": "Ablaufzeit",
|
||||
"hide": "Ausblenden",
|
||||
"id": "ID",
|
||||
"ipAddresses": "IP-Adressen",
|
||||
"lastUpdated": "Zuletzt aktualisiert",
|
||||
"location": "Standort",
|
||||
"memory": "Speicher",
|
||||
"name": "Name",
|
||||
"noData": "--",
|
||||
"node": "Knoten",
|
||||
"nodeDetail": "Knotendetails",
|
||||
"nodeGroup": "Knotengruppe",
|
||||
"nodeStatus": "Knotenstatus",
|
||||
"normal": "Normal",
|
||||
"onlineCount": "Online-Anzahl",
|
||||
"onlineUsers": "Online-Benutzer",
|
||||
"protocol": "Protokoll",
|
||||
"rate": "Rate",
|
||||
"relay": "Relais",
|
||||
"serverAddr": "Serveradresse",
|
||||
"speedLimit": "Geschwindigkeitsbegrenzung",
|
||||
"status": "Status",
|
||||
"subscribeId": "Abonnieren ID",
|
||||
"subscribeName": "Abonnieren Name",
|
||||
"subscription": "Abonnement",
|
||||
"tags": "Stichwörter",
|
||||
"trafficRatio": "Verkehrsrate",
|
||||
"trafficUsage": "Datenverbrauch",
|
||||
"type": "Typ",
|
||||
"updateSuccess": "Erfolgreich aktualisiert",
|
||||
"updatedAt": "Aktualisierungszeit",
|
||||
"user": "Benutzer",
|
||||
"userDetail": "Benutzerdetails",
|
||||
"userId": "Benutzer-ID"
|
||||
},
|
||||
"nodeForm": {
|
||||
"allowInsecure": "Unsichere Verbindungen erlauben",
|
||||
"cancel": "Abbrechen",
|
||||
"city": "Stadt",
|
||||
"confirm": "Bestätigen",
|
||||
"congestionController": "Staukontrolle",
|
||||
"country": "Land",
|
||||
"disableSni": "SNI deaktivieren",
|
||||
"edit": "Bearbeiten",
|
||||
"editSecurity": "Sicherheitskonfiguration bearbeiten",
|
||||
"enableTLS": "TLS aktivieren",
|
||||
"encryptionMethod": "Verschlüsselungsmethode",
|
||||
"fingerprint": "Fingerprint",
|
||||
"flow": "Flusskontrollalgorithmus",
|
||||
"groupId": "Knotengruppe",
|
||||
"hopInterval": "Hop-Intervall",
|
||||
"hopPorts": "Hop-Ports",
|
||||
"hopPortsPlaceholder": "Mehrere Ports mit Kommas trennen",
|
||||
"name": "Name",
|
||||
"obfsPassword": "Obfuskationspasswort",
|
||||
"obfsPasswordPlaceholder": "Für keine Obfuskation leer lassen",
|
||||
"path": "Pfad",
|
||||
"pleaseSelect": "Bitte auswählen",
|
||||
"port": "Serverport",
|
||||
"protocol": "Protokoll",
|
||||
"reduceRtt": "RTT reduzieren",
|
||||
"relayHost": "Relay-Host",
|
||||
"relayMode": "Relay-Modus",
|
||||
"relayPort": "Relay-Port",
|
||||
"relayPrefix": "Relay-Präfix",
|
||||
"remarks": "Bemerkungen",
|
||||
"security": "Sicherheit",
|
||||
"securityConfig": "Sicherheitskonfiguration",
|
||||
"selectEncryptionMethod": "Verschlüsselungsmethode auswählen",
|
||||
"selectNodeGroup": "Knotengruppe auswählen",
|
||||
"selectProtocol": "Protokoll auswählen",
|
||||
"selectRelayMode": "Relay-Modus auswählen",
|
||||
"serverAddr": "Serveradresse",
|
||||
"serverKey": "Server-Schlüssel",
|
||||
"serverName": "Dienstname",
|
||||
"speedLimit": "Geschwindigkeitsbegrenzung",
|
||||
"speedLimitPlaceholder": "Unbegrenzt",
|
||||
"tags": "Tags",
|
||||
"tagsPlaceholder": "Verwenden Sie Enter oder Komma (,) um mehrere Tags einzugeben",
|
||||
"trafficRatio": "Verkehrsrate",
|
||||
"transport": "Transportprotokollkonfiguration",
|
||||
"transportConfig": "Transportprotokollkonfiguration",
|
||||
"transportHost": "Transport-Serveradresse",
|
||||
"transportPath": "Transportpfad",
|
||||
"transportServerName": "Transport-Servername",
|
||||
"udpRelayMode": "UDP-Relay-Modus"
|
||||
},
|
||||
"relayModeOptions": {
|
||||
"all": "Alle",
|
||||
"none": "Keine",
|
||||
"random": "Zufällig"
|
||||
},
|
||||
"securityConfig": {
|
||||
"fingerprint": "Fingerprint",
|
||||
"privateKey": "Privater Schlüssel",
|
||||
"privateKeyPlaceholder": "Für automatische Generierung leer lassen",
|
||||
"publicKey": "Öffentlicher Schlüssel",
|
||||
"publicKeyPlaceholder": "Für automatische Generierung leer lassen",
|
||||
"serverAddress": "Serveradresse",
|
||||
"serverAddressPlaceholder": "REALITY-Zieladresse, standardmäßig SNI verwenden",
|
||||
"serverName": "Servername (SNI)",
|
||||
"serverNamePlaceholder": "REALITY erforderlich, konsistent mit Backend",
|
||||
"serverPort": "Serverport",
|
||||
"serverPortPlaceholder": "REALITY-Zielport, standardmäßig 443",
|
||||
"shortId": "Kurze ID",
|
||||
"shortIdPlaceholder": "Für automatische Generierung leer lassen",
|
||||
"sni": "Server Name Indication (SNI)"
|
||||
},
|
||||
"tabs": {
|
||||
"node": "Knoten",
|
||||
"nodeConfig": "Knoten-Konfiguration",
|
||||
"nodeGroup": "Knotengruppe"
|
||||
}
|
||||
}
|
||||
101
apps/admin/locales/de-DE/servers.json
Normal file
101
apps/admin/locales/de-DE/servers.json
Normal file
@ -0,0 +1,101 @@
|
||||
{
|
||||
"address": "Adresse",
|
||||
"address_placeholder": "Serveradresse",
|
||||
"cancel": "Abbrechen",
|
||||
"city": "Stadt",
|
||||
"config": {
|
||||
"actions": {
|
||||
"cancel": "Abbrechen",
|
||||
"save": "Speichern"
|
||||
},
|
||||
"communicationKey": "Kommunikationsschlüssel",
|
||||
"communicationKeyDescription": "Wird zur Authentifizierung des Knotens verwendet.",
|
||||
"description": "Verwalten Sie die Kommunikationsschlüssel des Knotens, Pull/Push-Intervalle und dynamische Multiplikatoren.",
|
||||
"dynamicMultiplier": "Dynamischer Multiplikator",
|
||||
"dynamicMultiplierDescription": "Definieren Sie Zeitfenster und Multiplikatoren zur Anpassung der Verkehrsabrechnung.",
|
||||
"endTime": "Endzeit",
|
||||
"inputPlaceholder": "Bitte eingeben",
|
||||
"multiplier": "Multiplikator",
|
||||
"nodePullInterval": "Knoten-Pull-Intervall",
|
||||
"nodePullIntervalDescription": "Wie oft der Knoten die Konfiguration abruft (Sekunden).",
|
||||
"nodePushInterval": "Knoten-Push-Intervall",
|
||||
"nodePushIntervalDescription": "Wie oft der Knoten Statistiken sendet (Sekunden).",
|
||||
"reset": "Zurücksetzen",
|
||||
"save": "Speichern",
|
||||
"saveSuccess": "Erfolgreich gespeichert",
|
||||
"startTime": "Startzeit",
|
||||
"timeSlot": "Zeitfenster",
|
||||
"title": "Knoten-Konfiguration"
|
||||
},
|
||||
"confirm": "Bestätigen",
|
||||
"confirmDeleteDesc": "Diese Aktion kann nicht rückgängig gemacht werden.",
|
||||
"confirmDeleteTitle": "Diesen Server löschen?",
|
||||
"congestion_controller": "Staukontroller",
|
||||
"copied": "Kopiert",
|
||||
"copy": "Kopieren",
|
||||
"country": "Land",
|
||||
"cpu": "CPU",
|
||||
"create": "Erstellen",
|
||||
"created": "Erfolgreich erstellt",
|
||||
"delete": "Löschen",
|
||||
"deleted": "Erfolgreich gelöscht",
|
||||
"disable_sni": "SNI deaktivieren",
|
||||
"disk": "Festplatte",
|
||||
"drawerCreateTitle": "Server erstellen",
|
||||
"drawerEditTitle": "Server bearbeiten",
|
||||
"edit": "Bearbeiten",
|
||||
"enabled": "Aktiviert",
|
||||
"encryption_method": "Verschlüsselungsmethode",
|
||||
"expireTime": "Ablaufzeit",
|
||||
"expired": "Abgelaufen",
|
||||
"flow": "Fluss",
|
||||
"hop_interval": "Hop-Intervall",
|
||||
"hop_ports": "Hop-Ports",
|
||||
"hop_ports_placeholder": "z.B. 1-65535",
|
||||
"host": "Host",
|
||||
"id": "ID",
|
||||
"ipAddresses": "IP-Adressen",
|
||||
"memory": "Speicher",
|
||||
"name": "Name",
|
||||
"noData": "Keine Daten",
|
||||
"notAvailable": "Nicht verfügbar",
|
||||
"obfs_password": "Obfuskationspasswort",
|
||||
"obfs_password_placeholder": "Obfuskationspasswort eingeben",
|
||||
"offline": "Offline",
|
||||
"online": "Online",
|
||||
"onlineUsers": "Online-Benutzer",
|
||||
"pageTitle": "Server",
|
||||
"path": "Pfad",
|
||||
"please_select": "Bitte auswählen",
|
||||
"port": "Port",
|
||||
"protocols": "Protokolle",
|
||||
"reduce_rtt": "RTT reduzieren",
|
||||
"security_allow_insecure": "Unsichere Verbindungen zulassen",
|
||||
"security_fingerprint": "Fingerprint",
|
||||
"security_private_key": "Echter privater Schlüssel",
|
||||
"security_private_key_placeholder": "Privaten Schlüssel eingeben",
|
||||
"security_public_key": "Echter öffentlicher Schlüssel",
|
||||
"security_public_key_placeholder": "Öffentlichen Schlüssel eingeben",
|
||||
"security_server_address": "Echte Serveradresse",
|
||||
"security_server_address_placeholder": "z.B. 1.2.3.4 oder Domain",
|
||||
"security_server_port": "Echter Serverport",
|
||||
"security_short_id": "Echte kurze ID",
|
||||
"security_short_id_placeholder": "Hex-String (bis zu 16 Zeichen)",
|
||||
"security_sni": "SNI",
|
||||
"security_title": "Sicherheit",
|
||||
"select_encryption_method": "Verschlüsselungsmethode auswählen",
|
||||
"server_key": "Server-Schlüssel",
|
||||
"service_name": "Dienstname",
|
||||
"status": "Status",
|
||||
"subscribeId": "Abonnement-ID",
|
||||
"subscription": "Abonnement",
|
||||
"traffic": "Verkehr",
|
||||
"traffic_ratio": "Multiplikator",
|
||||
"transport_title": "Transport",
|
||||
"udp_relay_mode": "UDP-Relay-Modus",
|
||||
"unitSecondsShort": "S",
|
||||
"unlimited": "Unbegrenzt",
|
||||
"updated": "Erfolgreich aktualisiert",
|
||||
"user": "Benutzer",
|
||||
"validation_failed": "Validierung fehlgeschlagen. Bitte überprüfen Sie das Formular."
|
||||
}
|
||||
@ -1,14 +1,15 @@
|
||||
{
|
||||
"address": "Address",
|
||||
"cancel": "Cancel",
|
||||
"confirm": "Confirm",
|
||||
"confirmDeleteDesc": "This action cannot be undone.",
|
||||
"confirmDeleteTitle": "Delete this node?",
|
||||
"copied": "Copied successfully",
|
||||
"copied": "Copied",
|
||||
"copy": "Copy",
|
||||
"create": "Create",
|
||||
"created": "Created successfully",
|
||||
"created": "Created",
|
||||
"delete": "Delete",
|
||||
"deleted": "Deleted successfully",
|
||||
"deleted": "Deleted",
|
||||
"drawerCreateTitle": "Create Node",
|
||||
"drawerEditTitle": "Edit Node",
|
||||
"edit": "Edit",
|
||||
@ -16,22 +17,21 @@
|
||||
"enabled_off": "Disabled",
|
||||
"enabled_on": "Enabled",
|
||||
"errors": {
|
||||
"nameRequired": "Name is required",
|
||||
"nameRequired": "Please enter a name",
|
||||
"serverRequired": "Please select a server",
|
||||
"serverAddrRequired": "Entry address is required",
|
||||
"serverAddrRequired": "Please enter an entry address",
|
||||
"protocolRequired": "Please select a protocol",
|
||||
"portRange": "Port must be 1–65535"
|
||||
"portRange": "Port must be between 1 and 65535"
|
||||
},
|
||||
"name": "Name",
|
||||
"pageTitle": "Nodes",
|
||||
"port": "Port",
|
||||
"protocol": "Protocol",
|
||||
"select_protocol": "Search protocol…",
|
||||
"select_server": "Search server…",
|
||||
"select_protocol": "Select protocol…",
|
||||
"select_server": "Select server…",
|
||||
"server": "Server",
|
||||
"server_addr": "Entry address",
|
||||
"server_addr_port": "Address:Port",
|
||||
"tags": "Tags",
|
||||
"tags_placeholder": "Type and press Enter",
|
||||
"updated": "Updated successfully"
|
||||
"tags_description": "Permission grouping tag (incl. plan binding and delivery policies).",
|
||||
"tags_placeholder": "Use Enter or comma (,) to add multiple tags",
|
||||
"updated": "Updated"
|
||||
}
|
||||
|
||||
@ -53,9 +53,9 @@
|
||||
"selectResetCycle": "Please select a reset cycle",
|
||||
"selectSubscribeGroup": "Select Subscription Group",
|
||||
"selectUnitTime": "Please select a unit of time",
|
||||
"server": "Server",
|
||||
"serverGroup": "Server Group",
|
||||
"servers": "Servers",
|
||||
"node": "Node",
|
||||
"nodeGroup": "Node Group",
|
||||
"nodes": "Nodes",
|
||||
"speedLimit": "Speed Limit ",
|
||||
"traffic": "Traffic",
|
||||
"unitPrice": "Unit Price",
|
||||
|
||||
@ -1,183 +0,0 @@
|
||||
{
|
||||
"config": {
|
||||
"addTimeSlot": "Add Time Slot",
|
||||
"communicationKey": "Communication Key",
|
||||
"communicationKeyDescription": "Key for node communication to ensure data security",
|
||||
"delete": "Delete",
|
||||
"dynamicMultiplier": "Dynamic Multiplier",
|
||||
"dynamicMultiplierDescription": "Dynamic Multiplier refers to processing pushed data with different multipliers for different nodes during different time periods.",
|
||||
"endTime": "End Time",
|
||||
"inputPlaceholder": "Enter",
|
||||
"multiplier": "Multiplier",
|
||||
"nodePullInterval": "Node Pull Interval",
|
||||
"nodePullIntervalDescription": "Frequency (in seconds) for nodes to fetch data from the panel",
|
||||
"nodePushInterval": "Node Push Interval",
|
||||
"nodePushIntervalDescription": "Frequency for nodes to push data to the panel",
|
||||
"reset": "Reset",
|
||||
"save": "Save",
|
||||
"saveSuccess": "Save Successful",
|
||||
"startTime": "Start Time",
|
||||
"timeSlot": "Time Slot"
|
||||
},
|
||||
"group": {
|
||||
"actions": "Actions",
|
||||
"cancel": "Cancel",
|
||||
"confirm": "Confirm",
|
||||
"confirmDelete": "Are you sure you want to delete?",
|
||||
"create": "Create",
|
||||
"createNodeGroup": "Create Node Group",
|
||||
"createdSuccessfully": "Created successfully",
|
||||
"delete": "Delete",
|
||||
"deleteWarning": "Data will not be recoverable after deletion. Please proceed with caution.",
|
||||
"deletedSuccessfully": "Deleted successfully",
|
||||
"description": "Description",
|
||||
"edit": "Edit",
|
||||
"editNodeGroup": "Edit Node Group",
|
||||
"name": "Name",
|
||||
"title": "Node Group List",
|
||||
"updatedAt": "Updated At"
|
||||
},
|
||||
"groupForm": {
|
||||
"cancel": "Cancel",
|
||||
"confirm": "Confirm",
|
||||
"description": "Description",
|
||||
"name": "Name"
|
||||
},
|
||||
"node": {
|
||||
"abnormal": "Abnormal",
|
||||
"actions": "Actions",
|
||||
"address": "Address",
|
||||
"all": "All",
|
||||
"basicInfo": "Basic Info",
|
||||
"cancel": "Cancel",
|
||||
"confirm": "Confirm",
|
||||
"confirmDelete": "Are you sure you want to delete?",
|
||||
"copy": "Copy",
|
||||
"copySuccess": "Copied successfully",
|
||||
"create": "Create",
|
||||
"createNode": "Create Node",
|
||||
"createSuccess": "Created successfully",
|
||||
"delete": "Delete",
|
||||
"deleteSuccess": "Deleted successfully",
|
||||
"deleteWarning": "Data will not be recoverable after deletion. Please proceed with caution.",
|
||||
"detail": "Detail",
|
||||
"disabled": "Disabled",
|
||||
"disk": "Disk",
|
||||
"edit": "Edit",
|
||||
"editNode": "Edit Node",
|
||||
"enable": "Enable",
|
||||
"enabled": "Enabled",
|
||||
"hide": "Hide",
|
||||
"id": "ID",
|
||||
"ipAddresses": "IP Addresses",
|
||||
"lastUpdated": "Last Updated",
|
||||
"location": "Location",
|
||||
"memory": "Memory",
|
||||
"name": "Name",
|
||||
"node": "Node",
|
||||
"nodeDetail": "Node Detail",
|
||||
"nodeGroup": "Node Group",
|
||||
"nodeStatus": "Node Status",
|
||||
"noData": "--",
|
||||
"normal": "Normal",
|
||||
"onlineCount": "Online users",
|
||||
"onlineUsers": "Online Users",
|
||||
"protocol": "Protocol",
|
||||
"rate": "Rate",
|
||||
"relay": "Relay",
|
||||
"serverAddr": "Server Address",
|
||||
"speedLimit": "Speed Limit",
|
||||
"status": "Status",
|
||||
"subscription": "Subscription",
|
||||
"subscribeName": "Subscribe Name",
|
||||
"subscribeId": "Subscribe ID",
|
||||
"tags": "Tags",
|
||||
"trafficRatio": "Traffic Rate",
|
||||
"trafficUsage": "Traffic Usage",
|
||||
"type": "Type",
|
||||
"updateSuccess": "Update successful",
|
||||
"updatedAt": "Updated At",
|
||||
"user": "User",
|
||||
"userDetail": "User Detail",
|
||||
"userId": "User ID",
|
||||
"expireTime": "Expire Time"
|
||||
},
|
||||
"nodeForm": {
|
||||
"allowInsecure": "Allow Insecure",
|
||||
"cancel": "Cancel",
|
||||
"city": "City",
|
||||
"confirm": "Confirm",
|
||||
"congestionController": "Congestion Controller",
|
||||
"country": "Country",
|
||||
"disableSni": "Disable SNI",
|
||||
"edit": "Edit",
|
||||
"editSecurity": "Edit Security Configuration",
|
||||
"enableTLS": "Enable TLS",
|
||||
"encryptionMethod": "Encryption Method",
|
||||
"fingerprint": "Fingerprint",
|
||||
"flow": "Flow Control Algorithm",
|
||||
"groupId": "Node Group",
|
||||
"hopInterval": "Hop Interval",
|
||||
"hopPorts": "Hop Ports",
|
||||
"hopPortsPlaceholder": "Separate multiple ports with commas",
|
||||
"name": "Name",
|
||||
"obfsPassword": "Obfuscation Password",
|
||||
"obfsPasswordPlaceholder": "Leave blank for no obfuscation",
|
||||
"path": "Path",
|
||||
"pleaseSelect": "Please Select",
|
||||
"port": "Server Port",
|
||||
"protocol": "Protocol",
|
||||
"reduceRtt": "Reduce RTT",
|
||||
"relayHost": "Relay Host",
|
||||
"relayMode": "Relay Mode",
|
||||
"relayPort": "Relay Port",
|
||||
"relayPrefix": "Relay Prefix",
|
||||
"remarks": "Remarks",
|
||||
"security": "Security",
|
||||
"securityConfig": "Security Configuration",
|
||||
"selectEncryptionMethod": "Select Encryption Method",
|
||||
"selectNodeGroup": "Select Node Group",
|
||||
"selectProtocol": "Select Protocol",
|
||||
"selectRelayMode": "Select Relay Mode",
|
||||
"serverAddr": "Server Address",
|
||||
"serverKey": "Server Key",
|
||||
"serverName": "Service Name",
|
||||
"speedLimit": "Speed Limit",
|
||||
"speedLimitPlaceholder": "Unlimited",
|
||||
"tags": "Tags",
|
||||
"tagsPlaceholder": "Use Enter or comma (,) to enter multiple tags",
|
||||
"trafficRatio": "Traffic Rate",
|
||||
"transport": "Transport Protocol Configuration",
|
||||
"transportConfig": "Transport Protocol Configuration",
|
||||
"transportHost": "Transport Server Address",
|
||||
"udpRelayMode": "UDP Relay Mode",
|
||||
"transportPath": "Transport Path",
|
||||
"transportServerName": "Transport Server Name"
|
||||
},
|
||||
"relayModeOptions": {
|
||||
"all": "All",
|
||||
"none": "None",
|
||||
"random": "Random"
|
||||
},
|
||||
"securityConfig": {
|
||||
"fingerprint": "Fingerprint",
|
||||
"privateKey": "Private Key",
|
||||
"privateKeyPlaceholder": "Leave blank for auto-generation",
|
||||
"publicKey": "Public Key",
|
||||
"publicKeyPlaceholder": "Leave blank for auto-generation",
|
||||
"serverAddress": "Server Address",
|
||||
"serverAddressPlaceholder": "REALITY target address, default using SNI",
|
||||
"serverName": "Server Name (SNI)",
|
||||
"serverNamePlaceholder": "REALITY required, consistent with backend",
|
||||
"serverPort": "Server Port",
|
||||
"serverPortPlaceholder": "REALITY target port, default 443",
|
||||
"shortId": "Short ID",
|
||||
"shortIdPlaceholder": "Leave blank for auto-generation",
|
||||
"sni": "Server Name Indication (SNI)"
|
||||
},
|
||||
"tabs": {
|
||||
"node": "Node",
|
||||
"nodeConfig": "Node Configuration",
|
||||
"nodeGroup": "Node Group"
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,7 @@
|
||||
{
|
||||
"address": "Address",
|
||||
"address": "Address",
|
||||
"address_placeholder": "Server address",
|
||||
"cancel": "Cancel",
|
||||
"city": "City",
|
||||
"config": {
|
||||
@ -49,7 +52,7 @@
|
||||
"flow": "Flow",
|
||||
"hop_interval": "Hop interval",
|
||||
"hop_ports": "Hop ports",
|
||||
"hop_ports_placeholder": "e.g. 443,8443,10443",
|
||||
"hop_ports_placeholder": "e.g. 1-65535",
|
||||
"host": "Host",
|
||||
"id": "ID",
|
||||
"ipAddresses": "IP addresses",
|
||||
@ -66,7 +69,6 @@
|
||||
"path": "Path",
|
||||
"please_select": "Please select",
|
||||
"port": "Port",
|
||||
"port_placeholder": "Enter port",
|
||||
"protocols": "Protocols",
|
||||
"reduce_rtt": "Reduce RTT",
|
||||
"security_allow_insecure": "Allow insecure",
|
||||
@ -78,23 +80,21 @@
|
||||
"security_server_address": "Reality server address",
|
||||
"security_server_address_placeholder": "e.g. 1.2.3.4 or domain",
|
||||
"security_server_port": "Reality server port",
|
||||
"security_server_port_placeholder": "Enter port",
|
||||
"security_short_id": "Reality short ID",
|
||||
"security_short_id_placeholder": "Hex string (up to 16 chars)",
|
||||
"security_sni": "SNI",
|
||||
"security_title": "Security",
|
||||
"select_encryption_method": "Select encryption method",
|
||||
"serverAddress": "Server",
|
||||
"server_addr": "Server address",
|
||||
"server_key": "Server key",
|
||||
"service_name": "Service name",
|
||||
"status": "Status",
|
||||
"subscribeId": "Subscription ID",
|
||||
"subscription": "Subscription",
|
||||
"traffic": "Traffic",
|
||||
"traffic_ratio": "Multiplier",
|
||||
"transport_title": "Transport",
|
||||
"udp_relay_mode": "UDP relay mode",
|
||||
"unitSecondsShort": "s",
|
||||
"unitSecondsShort": "S",
|
||||
"unlimited": "Unlimited",
|
||||
"updated": "Updated successfully",
|
||||
"user": "User",
|
||||
|
||||
@ -1,27 +1,36 @@
|
||||
{
|
||||
"ADS Config": "Configuración de ADS",
|
||||
"Announcement Management": "Gestión de Anuncios",
|
||||
"Application Management": "Gestión de Aplicaciones",
|
||||
"Auth Control": "Control de Autenticación",
|
||||
"Balance": "Saldo",
|
||||
"Commerce": "Comercio",
|
||||
"Commission": "Comisión",
|
||||
"Coupon Management": "Gestión de Cupones",
|
||||
"Dashboard": "Tablero",
|
||||
"Document Management": "Gestión de Documentos",
|
||||
"Finance": "Finanzas",
|
||||
"Email": "Correo electrónico",
|
||||
"Gift": "Regalo",
|
||||
"Login": "Iniciar sesión",
|
||||
"Logs & Analytics": "Registros y análisis",
|
||||
"Maintenance": "Mantenimiento",
|
||||
"Marketing Management": "Gestión de Marketing",
|
||||
"Node Management": "Gestión de nodos",
|
||||
"Order Management": "Gestión de Pedidos",
|
||||
"Payment Config": "Configuración de Pago",
|
||||
"Product Management": "Gestión de Productos",
|
||||
"Protocol Management": "Gestión de Protocolos",
|
||||
"Rule Management": "Gestión de Reglas",
|
||||
"Server": "Servidor",
|
||||
"Register": "Registrarse",
|
||||
"Reset Subscribe": "Restablecer suscripción",
|
||||
"SMS": "SMS",
|
||||
"Server Management": "Gestión de Servidores",
|
||||
"Settings": "Configuración",
|
||||
"Server Traffic": "Tráfico del servidor",
|
||||
"Subscribe": "Suscribirse",
|
||||
"Subscribe Config": "Configuración de Suscripción",
|
||||
"Subscribe Traffic": "Tráfico de suscripción",
|
||||
"System": "Sistema",
|
||||
"System Config": "Configuración del sistema",
|
||||
"System Management": "Gestión del Sistema",
|
||||
"System Tool": "Herramienta del sistema",
|
||||
"Ticket Management": "Gestión de Tickets",
|
||||
"User": "Usuario",
|
||||
"User Detail": "Detalle del Usuario",
|
||||
"User Management": "Gestión de Usuarios"
|
||||
"User Management": "Gestión de Usuarios",
|
||||
"Users & Support": "Usuarios y soporte"
|
||||
}
|
||||
|
||||
37
apps/admin/locales/es-ES/nodes.json
Normal file
37
apps/admin/locales/es-ES/nodes.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"address": "Dirección",
|
||||
"cancel": "Cancelar",
|
||||
"confirm": "Confirmar",
|
||||
"confirmDeleteDesc": "Esta acción no se puede deshacer.",
|
||||
"confirmDeleteTitle": "¿Eliminar este nodo?",
|
||||
"copied": "Copiado",
|
||||
"copy": "Copiar",
|
||||
"create": "Crear",
|
||||
"created": "Creado",
|
||||
"delete": "Eliminar",
|
||||
"deleted": "Eliminado",
|
||||
"drawerCreateTitle": "Crear Nodo",
|
||||
"drawerEditTitle": "Editar Nodo",
|
||||
"edit": "Editar",
|
||||
"enabled": "Habilitado",
|
||||
"enabled_off": "Deshabilitado",
|
||||
"enabled_on": "Habilitado",
|
||||
"errors": {
|
||||
"nameRequired": "Por favor, introduce un nombre",
|
||||
"portRange": "El puerto debe estar entre 1 y 65535",
|
||||
"protocolRequired": "Por favor, selecciona un protocolo",
|
||||
"serverAddrRequired": "Por favor, introduce una dirección de entrada",
|
||||
"serverRequired": "Por favor, selecciona un servidor"
|
||||
},
|
||||
"name": "Nombre",
|
||||
"pageTitle": "Nodos",
|
||||
"port": "Puerto",
|
||||
"protocol": "Protocolo",
|
||||
"select_protocol": "Seleccionar protocolo…",
|
||||
"select_server": "Seleccionar servidor…",
|
||||
"server": "Servidor",
|
||||
"tags": "Etiquetas",
|
||||
"tags_description": "Etiqueta de agrupación de permisos (incl. vinculación de planes y políticas de entrega).",
|
||||
"tags_placeholder": "Usa Enter o coma (,) para añadir múltiples etiquetas",
|
||||
"updated": "Actualizado"
|
||||
}
|
||||
@ -1,60 +1,6 @@
|
||||
{
|
||||
"actions": "acciones",
|
||||
"app": {
|
||||
"appDownloadURL": "URL de Descarga de la App",
|
||||
"appIcon": "Icono de la App",
|
||||
"appList": "Lista de Aplicaciones",
|
||||
"appName": "Nombre de la App",
|
||||
"backupDomains": "Lista de Dominios de Respaldo",
|
||||
"backupDomainsDescription": "Lista de dominios de respaldo para la resolución de dominios, un dominio por línea",
|
||||
"batchDelete": "Eliminar en Lote",
|
||||
"cancel": "Cancelar",
|
||||
"communicationKey": "Clave de comunicación",
|
||||
"communicationKeyDescription": "Clave utilizada para la comunicación del cliente",
|
||||
"config": "Configuración",
|
||||
"configApp": "Configuración de la Aplicación",
|
||||
"confirm": "Confirmar",
|
||||
"confirmDelete": "Confirmar Eliminación",
|
||||
"create": "Crear",
|
||||
"createApp": "Crear App",
|
||||
"createSuccess": "Creado con éxito",
|
||||
"defaultVersion": "Versión Predeterminada",
|
||||
"delete": "Eliminar",
|
||||
"deleteWarning": "Esta acción no se puede deshacer",
|
||||
"describeDescription": "Se utiliza para describir la aplicación, se muestra en la lista de aplicaciones",
|
||||
"description": "Descripción",
|
||||
"downloadLink": "Enlace de Descarga",
|
||||
"edit": "Editar",
|
||||
"editApp": "Editar App",
|
||||
"encryption": "Método de encriptación",
|
||||
"encryptionDescription": "Elija el método de encriptación para la comunicación del cliente. Si se selecciona, el cliente utilizará este método para comunicarse con el servidor",
|
||||
"nameDescription": "Nombre de la aplicación, se muestra en la lista de aplicaciones",
|
||||
"platform": "Plataforma",
|
||||
"selectApp": "Seleccionar aplicación",
|
||||
"selectAppDescription": "Seleccione la aplicación para configurar, todos los ajustes se aplicarán a la aplicación seleccionada",
|
||||
"startupPicture": "Imagen de Inicio",
|
||||
"startupPictureDescription": "Imagen de inicio, admite imágenes de red y locales. Para imágenes de red, ingrese la URL completa de la imagen",
|
||||
"startupPicturePreview": "Vista Previa de la Imagen de Inicio",
|
||||
"startupPictureSkip": "Tiempo de Salto de la Imagen de Inicio",
|
||||
"startupPictureSkipDescription": "Tiempo de visualización de la imagen de inicio en segundos, ingrese 0 para no mostrar",
|
||||
"subscriptionProtocol": "Protocolo de Suscripción",
|
||||
"updateSuccess": "Actualizado con éxito",
|
||||
"version": "Versión"
|
||||
},
|
||||
"cancel": "Cancelar",
|
||||
"config": {
|
||||
"singleSubscriptionMode": "Modo de Suscripción Única",
|
||||
"singleSubscriptionModeDescription": "Cuando está habilitado, todas las suscripciones de usuario se convertirán en saldo",
|
||||
"subscriptionDomain": "Dominio de Suscripción",
|
||||
"subscriptionDomainDescription": "Usado para suscripción; dejar en blanco para usar el dominio del sitio",
|
||||
"subscriptionDomainPlaceholder": "Ingrese el dominio de suscripción, uno por línea",
|
||||
"subscriptionPath": "Ruta de Suscripción",
|
||||
"subscriptionPathDescription": "Usado para suscripción; asegúrese de reiniciar el sistema después de la modificación para un rendimiento óptimo",
|
||||
"subscriptionPathPlaceholder": "Ingrese",
|
||||
"updateSuccess": "Actualizado con éxito",
|
||||
"wildcardResolution": "Resolución de Comodín",
|
||||
"wildcardResolutionDescription": "Usado para suscripción"
|
||||
},
|
||||
"confirm": "Confirmar",
|
||||
"confirmDelete": "¿Estás seguro de que deseas eliminar?",
|
||||
"copy": "Copiar",
|
||||
@ -95,6 +41,9 @@
|
||||
"name": "Nombre",
|
||||
"noLimit": "Sin límite",
|
||||
"noReset": "Sin Reinicio",
|
||||
"node": "Nodo",
|
||||
"nodeGroup": "Grupo de Nodos",
|
||||
"nodes": "Nodos",
|
||||
"pricing": "Precios",
|
||||
"purchaseWithDiscount": "Permitir Deducción",
|
||||
"purchaseWithDiscountDescription": "Habilitar o deshabilitar la funcionalidad de cancelación de suscripción. Después de la activación, el sistema realizará el procesamiento de deducción según las reglas y proporciones configuradas, y el valor restante se devolverá al saldo",
|
||||
@ -107,9 +56,6 @@
|
||||
"selectResetCycle": "Por favor, seleccione un ciclo de reinicio",
|
||||
"selectSubscribeGroup": "Por favor, seleccione un grupo de suscripción",
|
||||
"selectUnitTime": "Por favor, seleccione la unidad de tiempo",
|
||||
"server": "Servidor",
|
||||
"serverGroup": "Grupo de servidores",
|
||||
"servers": "Servidores",
|
||||
"speedLimit": "Límite de velocidad ",
|
||||
"traffic": "Tráfico",
|
||||
"unitPrice": "Precio unitario",
|
||||
@ -151,8 +97,6 @@
|
||||
"subscribeGroup": "Suscribirse al grupo",
|
||||
"tabs": {
|
||||
"subscribe": "Suscribirse",
|
||||
"subscribeApp": "Configuración de la aplicación",
|
||||
"subscribeConfig": "Configuración de suscripción",
|
||||
"subscribeGroup": "Grupo de suscripción"
|
||||
},
|
||||
"traffic": "tráfico",
|
||||
|
||||
@ -1,183 +0,0 @@
|
||||
{
|
||||
"config": {
|
||||
"addTimeSlot": "Agregar Franja Horaria",
|
||||
"communicationKey": "Clave de Comunicación",
|
||||
"communicationKeyDescription": "Clave para la comunicación de nodos para garantizar la seguridad de los datos",
|
||||
"delete": "Eliminar",
|
||||
"dynamicMultiplier": "Multiplicador Dinámico",
|
||||
"dynamicMultiplierDescription": "El Multiplicador Dinámico se refiere al procesamiento de datos enviados con diferentes multiplicadores para diferentes nodos durante distintos períodos de tiempo.",
|
||||
"endTime": "Hora de Fin",
|
||||
"inputPlaceholder": "Ingresar",
|
||||
"multiplier": "Multiplicador",
|
||||
"nodePullInterval": "Intervalo de Extracción de Nodo",
|
||||
"nodePullIntervalDescription": "Frecuencia (en segundos) para que los nodos obtengan datos del panel",
|
||||
"nodePushInterval": "Intervalo de Envío de Nodo",
|
||||
"nodePushIntervalDescription": "Frecuencia para que los nodos envíen datos al panel",
|
||||
"reset": "Restablecer",
|
||||
"save": "Guardar",
|
||||
"saveSuccess": "Guardado Exitoso",
|
||||
"startTime": "Hora de Inicio",
|
||||
"timeSlot": "Franja Horaria"
|
||||
},
|
||||
"group": {
|
||||
"actions": "Acciones",
|
||||
"cancel": "Cancelar",
|
||||
"confirm": "Confirmar",
|
||||
"confirmDelete": "¿Está seguro de que desea eliminar?",
|
||||
"create": "Crear",
|
||||
"createNodeGroup": "Crear grupo de nodos",
|
||||
"createdSuccessfully": "Creado con éxito",
|
||||
"delete": "Eliminar",
|
||||
"deleteWarning": "Los datos no se podrán recuperar después de la eliminación, por favor opere con precaución.",
|
||||
"deletedSuccessfully": "Eliminado con éxito",
|
||||
"description": "Descripción",
|
||||
"edit": "Editar",
|
||||
"editNodeGroup": "Editar grupo de nodos",
|
||||
"name": "Nombre",
|
||||
"title": "Lista de grupos de nodos",
|
||||
"updatedAt": "Fecha de actualización"
|
||||
},
|
||||
"groupForm": {
|
||||
"cancel": "Cancelar",
|
||||
"confirm": "Confirmar",
|
||||
"description": "Descripción",
|
||||
"name": "Nombre"
|
||||
},
|
||||
"node": {
|
||||
"abnormal": "Anormal",
|
||||
"actions": "Acciones",
|
||||
"address": "Dirección",
|
||||
"all": "Todo",
|
||||
"basicInfo": "Información Básica",
|
||||
"cancel": "Cancelar",
|
||||
"confirm": "Confirmar",
|
||||
"confirmDelete": "¿Está seguro de que desea eliminar?",
|
||||
"copy": "Copiar",
|
||||
"copySuccess": "Copiado con éxito",
|
||||
"create": "Crear",
|
||||
"createNode": "Crear nodo",
|
||||
"createSuccess": "Creación exitosa",
|
||||
"delete": "Eliminar",
|
||||
"deleteSuccess": "Eliminación exitosa",
|
||||
"deleteWarning": "Después de eliminar, los datos no se podrán recuperar. Proceda con precaución.",
|
||||
"detail": "Detalle",
|
||||
"disabled": "Deshabilitado",
|
||||
"disk": "Disco",
|
||||
"edit": "Editar",
|
||||
"editNode": "Editar nodo",
|
||||
"enable": "Habilitar",
|
||||
"enabled": "Habilitado",
|
||||
"expireTime": "Tiempo de Expiración",
|
||||
"hide": "Ocultar",
|
||||
"id": "ID",
|
||||
"ipAddresses": "Direcciones IP",
|
||||
"lastUpdated": "Última actualización",
|
||||
"location": "Ubicación",
|
||||
"memory": "Memoria",
|
||||
"name": "Nombre",
|
||||
"noData": "--",
|
||||
"node": "Nodo",
|
||||
"nodeDetail": "Detalle del Nodo",
|
||||
"nodeGroup": "Grupo de nodos",
|
||||
"nodeStatus": "Estado del Nodo",
|
||||
"normal": "Normal",
|
||||
"onlineCount": "Número de usuarios en línea",
|
||||
"onlineUsers": "Usuarios en línea",
|
||||
"protocol": "Protocolo",
|
||||
"rate": "Tasa",
|
||||
"relay": "Retransmisión",
|
||||
"serverAddr": "Dirección del servidor",
|
||||
"speedLimit": "Límite de velocidad",
|
||||
"status": "Estado",
|
||||
"subscribeId": "ID de Suscripción",
|
||||
"subscribeName": "Nombre de Suscripción",
|
||||
"subscription": "Suscripción",
|
||||
"tags": "Etiquetas",
|
||||
"trafficRatio": "Tasa de tráfico",
|
||||
"trafficUsage": "Uso de Tráfico",
|
||||
"type": "Tipo",
|
||||
"updateSuccess": "Actualización exitosa",
|
||||
"updatedAt": "Fecha de actualización",
|
||||
"user": "Usuario",
|
||||
"userDetail": "Detalle del Usuario",
|
||||
"userId": "ID de Usuario"
|
||||
},
|
||||
"nodeForm": {
|
||||
"allowInsecure": "Permitir Inseguro",
|
||||
"cancel": "Cancelar",
|
||||
"city": "Ciudad",
|
||||
"confirm": "Confirmar",
|
||||
"congestionController": "Controlador de Congestión",
|
||||
"country": "País",
|
||||
"disableSni": "Deshabilitar SNI",
|
||||
"edit": "Editar",
|
||||
"editSecurity": "Editar Configuración de Seguridad",
|
||||
"enableTLS": "Habilitar TLS",
|
||||
"encryptionMethod": "Método de Cifrado",
|
||||
"fingerprint": "Huella Digital",
|
||||
"flow": "Algoritmo de Control de Flujo",
|
||||
"groupId": "Grupo de Nodos",
|
||||
"hopInterval": "Intervalo de Salto",
|
||||
"hopPorts": "Puertos de Salto",
|
||||
"hopPortsPlaceholder": "Separe múltiples puertos con comas",
|
||||
"name": "Nombre",
|
||||
"obfsPassword": "Contraseña de Ofuscación",
|
||||
"obfsPasswordPlaceholder": "Deje en blanco para no ofuscar",
|
||||
"path": "Ruta",
|
||||
"pleaseSelect": "Por Favor Seleccione",
|
||||
"port": "Puerto del Servidor",
|
||||
"protocol": "Protocolo",
|
||||
"reduceRtt": "Reducir RTT",
|
||||
"relayHost": "Host de Relevo",
|
||||
"relayMode": "Modo de Relevo",
|
||||
"relayPort": "Puerto de Relevo",
|
||||
"relayPrefix": "Prefijo de Relevo",
|
||||
"remarks": "Observaciones",
|
||||
"security": "Seguridad",
|
||||
"securityConfig": "Configuración de Seguridad",
|
||||
"selectEncryptionMethod": "Seleccionar Método de Cifrado",
|
||||
"selectNodeGroup": "Seleccionar Grupo de Nodos",
|
||||
"selectProtocol": "Seleccionar Protocolo",
|
||||
"selectRelayMode": "Seleccionar Modo de Relevo",
|
||||
"serverAddr": "Dirección del Servidor",
|
||||
"serverKey": "Clave del Servidor",
|
||||
"serverName": "Nombre del Servicio",
|
||||
"speedLimit": "Límite de Velocidad",
|
||||
"speedLimitPlaceholder": "Ilimitado",
|
||||
"tags": "Etiquetas",
|
||||
"tagsPlaceholder": "Use Enter o coma (,) para ingresar múltiples etiquetas",
|
||||
"trafficRatio": "Tasa de Tráfico",
|
||||
"transport": "Configuración del Protocolo de Transporte",
|
||||
"transportConfig": "Configuración del Protocolo de Transporte",
|
||||
"transportHost": "Dirección del Servidor de Transporte",
|
||||
"transportPath": "Ruta de Transporte",
|
||||
"transportServerName": "Nombre del Servidor de Transporte",
|
||||
"udpRelayMode": "Modo de Relevo UDP"
|
||||
},
|
||||
"relayModeOptions": {
|
||||
"all": "Todos",
|
||||
"none": "Ninguno",
|
||||
"random": "Aleatorio"
|
||||
},
|
||||
"securityConfig": {
|
||||
"fingerprint": "Huella Digital",
|
||||
"privateKey": "Clave Privada",
|
||||
"privateKeyPlaceholder": "Deje en blanco para auto-generación",
|
||||
"publicKey": "Clave Pública",
|
||||
"publicKeyPlaceholder": "Deje en blanco para auto-generación",
|
||||
"serverAddress": "Dirección del Servidor",
|
||||
"serverAddressPlaceholder": "Dirección de destino REALITY, por defecto usando SNI",
|
||||
"serverName": "Nombre del Servidor (SNI)",
|
||||
"serverNamePlaceholder": "REALITY requerido, consistente con el backend",
|
||||
"serverPort": "Puerto del Servidor",
|
||||
"serverPortPlaceholder": "Puerto de destino REALITY, por defecto 443",
|
||||
"shortId": "ID Corto",
|
||||
"shortIdPlaceholder": "Deje en blanco para auto-generación",
|
||||
"sni": "Indicación de Nombre del Servidor (SNI)"
|
||||
},
|
||||
"tabs": {
|
||||
"node": "Nodo",
|
||||
"nodeConfig": "Configuración del Nodo",
|
||||
"nodeGroup": "Grupo de nodos"
|
||||
}
|
||||
}
|
||||
101
apps/admin/locales/es-ES/servers.json
Normal file
101
apps/admin/locales/es-ES/servers.json
Normal file
@ -0,0 +1,101 @@
|
||||
{
|
||||
"address": "Dirección",
|
||||
"address_placeholder": "Dirección del servidor",
|
||||
"cancel": "Cancelar",
|
||||
"city": "Ciudad",
|
||||
"config": {
|
||||
"actions": {
|
||||
"cancel": "Cancelar",
|
||||
"save": "Guardar"
|
||||
},
|
||||
"communicationKey": "Clave de comunicación",
|
||||
"communicationKeyDescription": "Utilizado para la autenticación del nodo.",
|
||||
"description": "Gestionar las claves de comunicación del nodo, intervalos de extracción/empuje y multiplicadores dinámicos.",
|
||||
"dynamicMultiplier": "Multiplicador dinámico",
|
||||
"dynamicMultiplierDescription": "Definir intervalos de tiempo y multiplicadores para ajustar la contabilidad del tráfico.",
|
||||
"endTime": "Hora de finalización",
|
||||
"inputPlaceholder": "Por favor ingrese",
|
||||
"multiplier": "Multiplicador",
|
||||
"nodePullInterval": "Intervalo de extracción del nodo",
|
||||
"nodePullIntervalDescription": "Con qué frecuencia el nodo extrae la configuración (segundos).",
|
||||
"nodePushInterval": "Intervalo de empuje del nodo",
|
||||
"nodePushIntervalDescription": "Con qué frecuencia el nodo envía estadísticas (segundos).",
|
||||
"reset": "Restablecer",
|
||||
"save": "Guardar",
|
||||
"saveSuccess": "Guardado con éxito",
|
||||
"startTime": "Hora de inicio",
|
||||
"timeSlot": "Intervalo de tiempo",
|
||||
"title": "Configuración del nodo"
|
||||
},
|
||||
"confirm": "Confirmar",
|
||||
"confirmDeleteDesc": "Esta acción no se puede deshacer.",
|
||||
"confirmDeleteTitle": "¿Eliminar este servidor?",
|
||||
"congestion_controller": "Controlador de congestión",
|
||||
"copied": "Copiado",
|
||||
"copy": "Copiar",
|
||||
"country": "País",
|
||||
"cpu": "CPU",
|
||||
"create": "Crear",
|
||||
"created": "Creado con éxito",
|
||||
"delete": "Eliminar",
|
||||
"deleted": "Eliminado con éxito",
|
||||
"disable_sni": "Deshabilitar SNI",
|
||||
"disk": "Disco",
|
||||
"drawerCreateTitle": "Crear Servidor",
|
||||
"drawerEditTitle": "Editar Servidor",
|
||||
"edit": "Editar",
|
||||
"enabled": "Habilitado",
|
||||
"encryption_method": "Método de cifrado",
|
||||
"expireTime": "Tiempo de expiración",
|
||||
"expired": "Expirado",
|
||||
"flow": "Flujo",
|
||||
"hop_interval": "Intervalo de salto",
|
||||
"hop_ports": "Puertos de salto",
|
||||
"hop_ports_placeholder": "p. ej. 1-65535",
|
||||
"host": "Host",
|
||||
"id": "ID",
|
||||
"ipAddresses": "Direcciones IP",
|
||||
"memory": "Memoria",
|
||||
"name": "Nombre",
|
||||
"noData": "Sin datos",
|
||||
"notAvailable": "N/A",
|
||||
"obfs_password": "Contraseña de ofuscación",
|
||||
"obfs_password_placeholder": "Ingrese la contraseña de ofuscación",
|
||||
"offline": "Desconectado",
|
||||
"online": "Conectado",
|
||||
"onlineUsers": "Usuarios en línea",
|
||||
"pageTitle": "Servidores",
|
||||
"path": "Ruta",
|
||||
"please_select": "Por favor seleccione",
|
||||
"port": "Puerto",
|
||||
"protocols": "Protocolos",
|
||||
"reduce_rtt": "Reducir RTT",
|
||||
"security_allow_insecure": "Permitir inseguro",
|
||||
"security_fingerprint": "Huella digital",
|
||||
"security_private_key": "Clave privada de realidad",
|
||||
"security_private_key_placeholder": "Ingrese la clave privada",
|
||||
"security_public_key": "Clave pública de realidad",
|
||||
"security_public_key_placeholder": "Ingrese la clave pública",
|
||||
"security_server_address": "Dirección del servidor de realidad",
|
||||
"security_server_address_placeholder": "p. ej. 1.2.3.4 o dominio",
|
||||
"security_server_port": "Puerto del servidor de realidad",
|
||||
"security_short_id": "ID corta de realidad",
|
||||
"security_short_id_placeholder": "Cadena hexadecimal (hasta 16 caracteres)",
|
||||
"security_sni": "SNI",
|
||||
"security_title": "Seguridad",
|
||||
"select_encryption_method": "Seleccionar método de cifrado",
|
||||
"server_key": "Clave del servidor",
|
||||
"service_name": "Nombre del servicio",
|
||||
"status": "Estado",
|
||||
"subscribeId": "ID de suscripción",
|
||||
"subscription": "Suscripción",
|
||||
"traffic": "Tráfico",
|
||||
"traffic_ratio": "Multiplicador",
|
||||
"transport_title": "Transporte",
|
||||
"udp_relay_mode": "Modo de retransmisión UDP",
|
||||
"unitSecondsShort": "S",
|
||||
"unlimited": "Ilimitado",
|
||||
"updated": "Actualizado con éxito",
|
||||
"user": "Usuario",
|
||||
"validation_failed": "La validación falló. Por favor revise el formulario."
|
||||
}
|
||||
@ -1,27 +1,36 @@
|
||||
{
|
||||
"ADS Config": "Configuración de ADS",
|
||||
"Announcement Management": "Gestión de Anuncios",
|
||||
"Application Management": "Gestión de Aplicaciones",
|
||||
"Auth Control": "Control de Autenticación",
|
||||
"Balance": "Saldo",
|
||||
"Commerce": "Comercio",
|
||||
"Commission": "Comisión",
|
||||
"Coupon Management": "Gestión de Cupones",
|
||||
"Dashboard": "Tablero",
|
||||
"Document Management": "Gestión de Documentos",
|
||||
"Finance": "Finanzas",
|
||||
"Email": "Correo Electrónico",
|
||||
"Gift": "Regalo",
|
||||
"Login": "Iniciar Sesión",
|
||||
"Logs & Analytics": "Registros y Análisis",
|
||||
"Maintenance": "Mantenimiento",
|
||||
"Marketing Management": "Gestión de Marketing",
|
||||
"Node Management": "Gestión de Nodos",
|
||||
"Order Management": "Gestión de Pedidos",
|
||||
"Payment Config": "Configuración de Pago",
|
||||
"Product Management": "Gestión de Productos",
|
||||
"Protocol Management": "Gestión de Protocolos",
|
||||
"Rule Management": "Gestión de Reglas",
|
||||
"Server": "Servidor",
|
||||
"Register": "Registrar",
|
||||
"Reset Subscribe": "Restablecer Suscripción",
|
||||
"SMS": "SMS",
|
||||
"Server Management": "Gestión de Servidores",
|
||||
"Settings": "Configuración",
|
||||
"Server Traffic": "Tráfico del Servidor",
|
||||
"Subscribe": "Suscribirse",
|
||||
"Subscribe Config": "Configuración de Suscripción",
|
||||
"Subscribe Traffic": "Tráfico de Suscripción",
|
||||
"System": "Sistema",
|
||||
"System Config": "Configuración del Sistema",
|
||||
"System Management": "Gestión del Sistema",
|
||||
"System Tool": "Herramienta del sistema",
|
||||
"Ticket Management": "Gestión de Tickets",
|
||||
"User": "Usuario",
|
||||
"User Detail": "Detalle del Usuario",
|
||||
"User Management": "Gestión de Usuarios"
|
||||
"User Management": "Gestión de Usuarios",
|
||||
"Users & Support": "Usuarios y Soporte"
|
||||
}
|
||||
|
||||
37
apps/admin/locales/es-MX/nodes.json
Normal file
37
apps/admin/locales/es-MX/nodes.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"address": "Dirección",
|
||||
"cancel": "Cancelar",
|
||||
"confirm": "Confirmar",
|
||||
"confirmDeleteDesc": "Esta acción no se puede deshacer.",
|
||||
"confirmDeleteTitle": "¿Eliminar este nodo?",
|
||||
"copied": "Copiado",
|
||||
"copy": "Copiar",
|
||||
"create": "Crear",
|
||||
"created": "Creado",
|
||||
"delete": "Eliminar",
|
||||
"deleted": "Eliminado",
|
||||
"drawerCreateTitle": "Crear Nodo",
|
||||
"drawerEditTitle": "Editar Nodo",
|
||||
"edit": "Editar",
|
||||
"enabled": "Habilitado",
|
||||
"enabled_off": "Deshabilitado",
|
||||
"enabled_on": "Habilitado",
|
||||
"errors": {
|
||||
"nameRequired": "Por favor ingresa un nombre",
|
||||
"portRange": "El puerto debe estar entre 1 y 65535",
|
||||
"protocolRequired": "Por favor selecciona un protocolo",
|
||||
"serverAddrRequired": "Por favor ingresa una dirección de entrada",
|
||||
"serverRequired": "Por favor selecciona un servidor"
|
||||
},
|
||||
"name": "Nombre",
|
||||
"pageTitle": "Nodos",
|
||||
"port": "Puerto",
|
||||
"protocol": "Protocolo",
|
||||
"select_protocol": "Seleccionar protocolo…",
|
||||
"select_server": "Seleccionar servidor…",
|
||||
"server": "Servidor",
|
||||
"tags": "Etiquetas",
|
||||
"tags_description": "Etiqueta de agrupación de permisos (incl. vinculación de planes y políticas de entrega).",
|
||||
"tags_placeholder": "Usa Enter o coma (,) para agregar múltiples etiquetas",
|
||||
"updated": "Actualizado"
|
||||
}
|
||||
@ -1,59 +1,6 @@
|
||||
{
|
||||
"actions": "acciones",
|
||||
"app": {
|
||||
"appDownloadURL": "URL de Descarga de la App",
|
||||
"appIcon": "Ícono de la App",
|
||||
"appList": "Lista de Aplicaciones",
|
||||
"appName": "Nombre de la App",
|
||||
"backupDomains": "Lista de Dominios de Respaldo",
|
||||
"backupDomainsDescription": "Lista de dominios de respaldo para la resolución de dominios, un dominio por línea",
|
||||
"batchDelete": "Eliminar en Lote",
|
||||
"cancel": "Cancelar",
|
||||
"communicationKey": "Clave de Comunicación",
|
||||
"communicationKeyDescription": "Clave utilizada para la comunicación con el cliente",
|
||||
"config": "Configuración",
|
||||
"configApp": "Configuración de la Aplicación",
|
||||
"confirm": "Confirmar",
|
||||
"confirmDelete": "Confirmar Eliminación",
|
||||
"create": "Crear",
|
||||
"createApp": "Crear App",
|
||||
"createSuccess": "Creado exitosamente",
|
||||
"defaultVersion": "Versión Predeterminada",
|
||||
"delete": "Eliminar",
|
||||
"deleteWarning": "Esta acción no se puede deshacer",
|
||||
"describeDescription": "Se utiliza para describir la aplicación, se muestra en la lista de aplicaciones",
|
||||
"description": "Descripción",
|
||||
"downloadLink": "Enlace de Descarga",
|
||||
"edit": "Editar",
|
||||
"editApp": "Editar App",
|
||||
"encryption": "Método de Cifrado",
|
||||
"encryptionDescription": "Elige el método de cifrado para la comunicación con el cliente. Si se selecciona, el cliente usará este método para comunicarse con el servidor",
|
||||
"nameDescription": "Nombre de la aplicación, se muestra en la lista de aplicaciones",
|
||||
"platform": "Plataforma",
|
||||
"selectApp": "Seleccionar Aplicación",
|
||||
"selectAppDescription": "Selecciona la aplicación para configurar, todos los ajustes se aplicarán a la aplicación seleccionada",
|
||||
"startupPicture": "Imagen de Inicio",
|
||||
"startupPictureDescription": "Imagen de inicio, admite imágenes de red y locales. Para imágenes de red, ingrese la URL completa de la imagen",
|
||||
"startupPicturePreview": "Vista Previa de la Imagen de Inicio",
|
||||
"startupPictureSkip": "Tiempo de Salto de la Imagen de Inicio",
|
||||
"startupPictureSkipDescription": "Tiempo de visualización de la imagen de inicio en segundos, ingrese 0 para no mostrar",
|
||||
"subscriptionProtocol": "Protocolo de Suscripción",
|
||||
"updateSuccess": "Actualizado exitosamente",
|
||||
"version": "Versión"
|
||||
},
|
||||
"cancel": "Cancelar",
|
||||
"config": {
|
||||
"singleSubscriptionMode": "Modo de Suscripción Única",
|
||||
"subscriptionDomain": "Dominio de Suscripción",
|
||||
"subscriptionDomainDescription": "Usado para suscripción; deje en blanco para usar el dominio del sitio",
|
||||
"subscriptionDomainPlaceholder": "Ingrese el dominio de suscripción, uno por línea",
|
||||
"subscriptionPath": "Ruta de Suscripción",
|
||||
"subscriptionPathDescription": "Usado para suscripción; asegúrese de reiniciar el sistema después de la modificación para un rendimiento óptimo",
|
||||
"subscriptionPathPlaceholder": "Ingrese",
|
||||
"updateSuccess": "Actualizado con éxito",
|
||||
"wildcardResolution": "Resolución de Comodín",
|
||||
"wildcardResolutionDescription": "Usado para suscripción"
|
||||
},
|
||||
"confirm": "Confirmar",
|
||||
"confirmDelete": "¿Estás seguro de que deseas eliminar?",
|
||||
"copy": "Copiar",
|
||||
@ -94,6 +41,9 @@
|
||||
"name": "Nombre",
|
||||
"noLimit": "Sin límite",
|
||||
"noReset": "Sin Reinicio",
|
||||
"node": "Nodo",
|
||||
"nodeGroup": "Grupo de Nodos",
|
||||
"nodes": "Nodos",
|
||||
"pricing": "Precios",
|
||||
"purchaseWithDiscount": "Permitir Deducción",
|
||||
"purchaseWithDiscountDescription": "Habilitar o deshabilitar la funcionalidad de cancelación de suscripción. Después de la activación, el sistema realizará el procesamiento de deducción según las reglas y proporciones configuradas, y el valor restante se devolverá al saldo",
|
||||
@ -106,9 +56,6 @@
|
||||
"selectResetCycle": "Por favor, seleccione un ciclo de reinicio",
|
||||
"selectSubscribeGroup": "Por favor seleccione un grupo de suscripción",
|
||||
"selectUnitTime": "Por favor seleccione la unidad de tiempo",
|
||||
"server": "Servidor",
|
||||
"serverGroup": "Grupo de servidores",
|
||||
"servers": "Servidores",
|
||||
"speedLimit": "Límite de velocidad ",
|
||||
"traffic": "Tráfico",
|
||||
"unitPrice": "Precio unitario",
|
||||
@ -150,8 +97,6 @@
|
||||
"subscribeGroup": "Suscribirse al grupo",
|
||||
"tabs": {
|
||||
"subscribe": "Suscribirse",
|
||||
"subscribeApp": "Configuración de la App",
|
||||
"subscribeConfig": "Configuración de Suscripción",
|
||||
"subscribeGroup": "Grupo de suscripción"
|
||||
},
|
||||
"traffic": "tráfico",
|
||||
|
||||
@ -1,183 +0,0 @@
|
||||
{
|
||||
"config": {
|
||||
"addTimeSlot": "Agregar Franja Horaria",
|
||||
"communicationKey": "Clave de Comunicación",
|
||||
"communicationKeyDescription": "Clave para la comunicación de nodos para garantizar la seguridad de los datos",
|
||||
"delete": "Eliminar",
|
||||
"dynamicMultiplier": "Multiplicador Dinámico",
|
||||
"dynamicMultiplierDescription": "El Multiplicador Dinámico se refiere al procesamiento de datos enviados con diferentes multiplicadores para diferentes nodos durante distintos períodos de tiempo.",
|
||||
"endTime": "Hora de Fin",
|
||||
"inputPlaceholder": "Ingresar",
|
||||
"multiplier": "Multiplicador",
|
||||
"nodePullInterval": "Intervalo de Extracción de Nodo",
|
||||
"nodePullIntervalDescription": "Frecuencia (en segundos) para que los nodos obtengan datos del panel",
|
||||
"nodePushInterval": "Intervalo de Envío de Nodo",
|
||||
"nodePushIntervalDescription": "Frecuencia para que los nodos envíen datos al panel",
|
||||
"reset": "Restablecer",
|
||||
"save": "Guardar",
|
||||
"saveSuccess": "Guardado Exitoso",
|
||||
"startTime": "Hora de Inicio",
|
||||
"timeSlot": "Franja Horaria"
|
||||
},
|
||||
"group": {
|
||||
"actions": "Acciones",
|
||||
"cancel": "Cancelar",
|
||||
"confirm": "Confirmar",
|
||||
"confirmDelete": "¿Está seguro de que desea eliminar?",
|
||||
"create": "Crear",
|
||||
"createNodeGroup": "Crear grupo de nodos",
|
||||
"createdSuccessfully": "Creación exitosa",
|
||||
"delete": "Eliminar",
|
||||
"deleteWarning": "Los datos no se podrán recuperar después de la eliminación, proceda con precaución.",
|
||||
"deletedSuccessfully": "Eliminación exitosa",
|
||||
"description": "Descripción",
|
||||
"edit": "Editar",
|
||||
"editNodeGroup": "Editar grupo de nodos",
|
||||
"name": "Nombre",
|
||||
"title": "Lista de grupos de nodos",
|
||||
"updatedAt": "Fecha de actualización"
|
||||
},
|
||||
"groupForm": {
|
||||
"cancel": "Cancelar",
|
||||
"confirm": "Confirmar",
|
||||
"description": "Descripción",
|
||||
"name": "Nombre"
|
||||
},
|
||||
"node": {
|
||||
"abnormal": "Anormal",
|
||||
"actions": "Acciones",
|
||||
"address": "Dirección",
|
||||
"all": "Todo",
|
||||
"basicInfo": "Información Básica",
|
||||
"cancel": "Cancelar",
|
||||
"confirm": "Confirmar",
|
||||
"confirmDelete": "¿Estás seguro de que deseas eliminar?",
|
||||
"copy": "Copiar",
|
||||
"copySuccess": "Copiado exitosamente",
|
||||
"create": "Crear",
|
||||
"createNode": "Crear nodo",
|
||||
"createSuccess": "Creación exitosa",
|
||||
"delete": "Eliminar",
|
||||
"deleteSuccess": "Eliminación exitosa",
|
||||
"deleteWarning": "Después de eliminar, los datos no se podrán recuperar. Proceda con precaución.",
|
||||
"detail": "Detalle",
|
||||
"disabled": "Deshabilitado",
|
||||
"disk": "Disco",
|
||||
"edit": "Editar",
|
||||
"editNode": "Editar nodo",
|
||||
"enable": "Habilitar",
|
||||
"enabled": "Habilitado",
|
||||
"expireTime": "Tiempo de Expiración",
|
||||
"hide": "Ocultar",
|
||||
"id": "ID",
|
||||
"ipAddresses": "Direcciones IP",
|
||||
"lastUpdated": "Última actualización",
|
||||
"location": "Ubicación",
|
||||
"memory": "Memoria",
|
||||
"name": "Nombre",
|
||||
"noData": "--",
|
||||
"node": "Nodo",
|
||||
"nodeDetail": "Detalle del Nodo",
|
||||
"nodeGroup": "Grupo de nodos",
|
||||
"nodeStatus": "Estado del Nodo",
|
||||
"normal": "Normal",
|
||||
"onlineCount": "Número de personas en línea",
|
||||
"onlineUsers": "Usuarios en línea",
|
||||
"protocol": "Protocolo",
|
||||
"rate": "Tasa",
|
||||
"relay": "Retransmisión",
|
||||
"serverAddr": "Dirección del servidor",
|
||||
"speedLimit": "Límite de velocidad",
|
||||
"status": "Estado",
|
||||
"subscribeId": "ID de Suscripción",
|
||||
"subscribeName": "Nombre de Suscripción",
|
||||
"subscription": "Suscripción",
|
||||
"tags": "Etiquetas",
|
||||
"trafficRatio": "Tasa de tráfico",
|
||||
"trafficUsage": "Uso de Tráfico",
|
||||
"type": "Tipo",
|
||||
"updateSuccess": "Actualización exitosa",
|
||||
"updatedAt": "Fecha de actualización",
|
||||
"user": "Usuario",
|
||||
"userDetail": "Detalle del Usuario",
|
||||
"userId": "ID de Usuario"
|
||||
},
|
||||
"nodeForm": {
|
||||
"allowInsecure": "Permitir Inseguro",
|
||||
"cancel": "Cancelar",
|
||||
"city": "Ciudad",
|
||||
"confirm": "Confirmar",
|
||||
"congestionController": "Controlador de Congestión",
|
||||
"country": "País",
|
||||
"disableSni": "Deshabilitar SNI",
|
||||
"edit": "Editar",
|
||||
"editSecurity": "Editar Configuración de Seguridad",
|
||||
"enableTLS": "Habilitar TLS",
|
||||
"encryptionMethod": "Método de Cifrado",
|
||||
"fingerprint": "Huella Digital",
|
||||
"flow": "Algoritmo de Control de Flujo",
|
||||
"groupId": "Grupo de Nodos",
|
||||
"hopInterval": "Intervalo de Salto",
|
||||
"hopPorts": "Puertos de Salto",
|
||||
"hopPortsPlaceholder": "Separe múltiples puertos con comas",
|
||||
"name": "Nombre",
|
||||
"obfsPassword": "Contraseña de Ofuscación",
|
||||
"obfsPasswordPlaceholder": "Deje en blanco para no ofuscar",
|
||||
"path": "Ruta",
|
||||
"pleaseSelect": "Por Favor Seleccione",
|
||||
"port": "Puerto del Servidor",
|
||||
"protocol": "Protocolo",
|
||||
"reduceRtt": "Reducir RTT",
|
||||
"relayHost": "Host de Relevo",
|
||||
"relayMode": "Modo de Relevo",
|
||||
"relayPort": "Puerto de Relevo",
|
||||
"relayPrefix": "Prefijo de Relevo",
|
||||
"remarks": "Observaciones",
|
||||
"security": "Seguridad",
|
||||
"securityConfig": "Configuración de Seguridad",
|
||||
"selectEncryptionMethod": "Seleccionar Método de Cifrado",
|
||||
"selectNodeGroup": "Seleccionar Grupo de Nodos",
|
||||
"selectProtocol": "Seleccionar Protocolo",
|
||||
"selectRelayMode": "Seleccionar Modo de Relevo",
|
||||
"serverAddr": "Dirección del Servidor",
|
||||
"serverKey": "Clave del Servidor",
|
||||
"serverName": "Nombre del Servicio",
|
||||
"speedLimit": "Límite de Velocidad",
|
||||
"speedLimitPlaceholder": "Ilimitado",
|
||||
"tags": "Etiquetas",
|
||||
"tagsPlaceholder": "Use Enter o coma (,) para ingresar múltiples etiquetas",
|
||||
"trafficRatio": "Tasa de Tráfico",
|
||||
"transport": "Configuración del Protocolo de Transporte",
|
||||
"transportConfig": "Configuración del Protocolo de Transporte",
|
||||
"transportHost": "Dirección del Servidor de Transporte",
|
||||
"transportPath": "Ruta de Transporte",
|
||||
"transportServerName": "Nombre del Servidor de Transporte",
|
||||
"udpRelayMode": "Modo de Relevo UDP"
|
||||
},
|
||||
"relayModeOptions": {
|
||||
"all": "Todos",
|
||||
"none": "Ninguno",
|
||||
"random": "Aleatorio"
|
||||
},
|
||||
"securityConfig": {
|
||||
"fingerprint": "Huella Digital",
|
||||
"privateKey": "Clave Privada",
|
||||
"privateKeyPlaceholder": "Deje en blanco para auto-generación",
|
||||
"publicKey": "Clave Pública",
|
||||
"publicKeyPlaceholder": "Deje en blanco para auto-generación",
|
||||
"serverAddress": "Dirección del Servidor",
|
||||
"serverAddressPlaceholder": "Dirección de destino REALITY, por defecto usando SNI",
|
||||
"serverName": "Nombre del Servidor (SNI)",
|
||||
"serverNamePlaceholder": "REALITY requerido, consistente con el backend",
|
||||
"serverPort": "Puerto del Servidor",
|
||||
"serverPortPlaceholder": "Puerto de destino REALITY, por defecto 443",
|
||||
"shortId": "ID Corto",
|
||||
"shortIdPlaceholder": "Deje en blanco para auto-generación",
|
||||
"sni": "Indicación de Nombre del Servidor (SNI)"
|
||||
},
|
||||
"tabs": {
|
||||
"node": "Nodo",
|
||||
"nodeConfig": "Configuración del Nodo",
|
||||
"nodeGroup": "Grupo de nodos"
|
||||
}
|
||||
}
|
||||
101
apps/admin/locales/es-MX/servers.json
Normal file
101
apps/admin/locales/es-MX/servers.json
Normal file
@ -0,0 +1,101 @@
|
||||
{
|
||||
"address": "Dirección",
|
||||
"address_placeholder": "Dirección del servidor",
|
||||
"cancel": "Cancelar",
|
||||
"city": "Ciudad",
|
||||
"config": {
|
||||
"actions": {
|
||||
"cancel": "Cancelar",
|
||||
"save": "Guardar"
|
||||
},
|
||||
"communicationKey": "Clave de comunicación",
|
||||
"communicationKeyDescription": "Utilizado para la autenticación del nodo.",
|
||||
"description": "Gestiona las claves de comunicación del nodo, intervalos de extracción/empuje y multiplicadores dinámicos.",
|
||||
"dynamicMultiplier": "Multiplicador dinámico",
|
||||
"dynamicMultiplierDescription": "Define intervalos de tiempo y multiplicadores para ajustar la contabilidad del tráfico.",
|
||||
"endTime": "Hora de finalización",
|
||||
"inputPlaceholder": "Por favor ingresa",
|
||||
"multiplier": "Multiplicador",
|
||||
"nodePullInterval": "Intervalo de extracción del nodo",
|
||||
"nodePullIntervalDescription": "Con qué frecuencia el nodo extrae la configuración (segundos).",
|
||||
"nodePushInterval": "Intervalo de empuje del nodo",
|
||||
"nodePushIntervalDescription": "Con qué frecuencia el nodo envía estadísticas (segundos).",
|
||||
"reset": "Restablecer",
|
||||
"save": "Guardar",
|
||||
"saveSuccess": "Guardado con éxito",
|
||||
"startTime": "Hora de inicio",
|
||||
"timeSlot": "Intervalo de tiempo",
|
||||
"title": "Configuración del nodo"
|
||||
},
|
||||
"confirm": "Confirmar",
|
||||
"confirmDeleteDesc": "Esta acción no se puede deshacer.",
|
||||
"confirmDeleteTitle": "¿Eliminar este servidor?",
|
||||
"congestion_controller": "Controlador de congestión",
|
||||
"copied": "Copiado",
|
||||
"copy": "Copiar",
|
||||
"country": "País",
|
||||
"cpu": "CPU",
|
||||
"create": "Crear",
|
||||
"created": "Creado con éxito",
|
||||
"delete": "Eliminar",
|
||||
"deleted": "Eliminado con éxito",
|
||||
"disable_sni": "Deshabilitar SNI",
|
||||
"disk": "Disco",
|
||||
"drawerCreateTitle": "Crear Servidor",
|
||||
"drawerEditTitle": "Editar Servidor",
|
||||
"edit": "Editar",
|
||||
"enabled": "Habilitado",
|
||||
"encryption_method": "Método de encriptación",
|
||||
"expireTime": "Tiempo de expiración",
|
||||
"expired": "Expirado",
|
||||
"flow": "Flujo",
|
||||
"hop_interval": "Intervalo de salto",
|
||||
"hop_ports": "Puertos de salto",
|
||||
"hop_ports_placeholder": "p. ej. 1-65535",
|
||||
"host": "Host",
|
||||
"id": "ID",
|
||||
"ipAddresses": "Direcciones IP",
|
||||
"memory": "Memoria",
|
||||
"name": "Nombre",
|
||||
"noData": "Sin datos",
|
||||
"notAvailable": "N/A",
|
||||
"obfs_password": "Contraseña de ofuscación",
|
||||
"obfs_password_placeholder": "Ingresa la contraseña de ofuscación",
|
||||
"offline": "Desconectado",
|
||||
"online": "Conectado",
|
||||
"onlineUsers": "Usuarios en línea",
|
||||
"pageTitle": "Servidores",
|
||||
"path": "Ruta",
|
||||
"please_select": "Por favor selecciona",
|
||||
"port": "Puerto",
|
||||
"protocols": "Protocolos",
|
||||
"reduce_rtt": "Reducir RTT",
|
||||
"security_allow_insecure": "Permitir inseguro",
|
||||
"security_fingerprint": "Huella digital",
|
||||
"security_private_key": "Clave privada de realidad",
|
||||
"security_private_key_placeholder": "Ingresa la clave privada",
|
||||
"security_public_key": "Clave pública de realidad",
|
||||
"security_public_key_placeholder": "Ingresa la clave pública",
|
||||
"security_server_address": "Dirección del servidor de realidad",
|
||||
"security_server_address_placeholder": "p. ej. 1.2.3.4 o dominio",
|
||||
"security_server_port": "Puerto del servidor de realidad",
|
||||
"security_short_id": "ID corto de realidad",
|
||||
"security_short_id_placeholder": "Cadena hexadecimal (hasta 16 caracteres)",
|
||||
"security_sni": "SNI",
|
||||
"security_title": "Seguridad",
|
||||
"select_encryption_method": "Selecciona el método de encriptación",
|
||||
"server_key": "Clave del servidor",
|
||||
"service_name": "Nombre del servicio",
|
||||
"status": "Estado",
|
||||
"subscribeId": "ID de suscripción",
|
||||
"subscription": "Suscripción",
|
||||
"traffic": "Tráfico",
|
||||
"traffic_ratio": "Multiplicador",
|
||||
"transport_title": "Transporte",
|
||||
"udp_relay_mode": "Modo de retransmisión UDP",
|
||||
"unitSecondsShort": "S",
|
||||
"unlimited": "Ilimitado",
|
||||
"updated": "Actualizado con éxito",
|
||||
"user": "Usuario",
|
||||
"validation_failed": "La validación falló. Por favor verifica el formulario."
|
||||
}
|
||||
@ -1,27 +1,36 @@
|
||||
{
|
||||
"ADS Config": "تنظیمات ADS",
|
||||
"Announcement Management": "مدیریت اطلاعیهها",
|
||||
"Application Management": "مدیریت برنامه",
|
||||
"Auth Control": "کنترل احراز هویت",
|
||||
"Balance": "تعادل",
|
||||
"Commerce": "تجارت",
|
||||
"Commission": "کمیسیون",
|
||||
"Coupon Management": "مدیریت کوپن",
|
||||
"Dashboard": "داشبورد",
|
||||
"Document Management": "مدیریت اسناد",
|
||||
"Finance": "امور مالی",
|
||||
"Email": "ایمیل",
|
||||
"Gift": "هدیه",
|
||||
"Login": "ورود",
|
||||
"Logs & Analytics": "گزارشات و تجزیه و تحلیل",
|
||||
"Maintenance": "نگهداری",
|
||||
"Marketing Management": "مدیریت بازاریابی",
|
||||
"Node Management": "مدیریت نود",
|
||||
"Order Management": "مدیریت سفارش",
|
||||
"Payment Config": "پیکربندی پرداخت",
|
||||
"Product Management": "مدیریت محصول",
|
||||
"Protocol Management": "مدیریت پروتکل",
|
||||
"Rule Management": "مدیریت قوانین",
|
||||
"Server": "سرور",
|
||||
"Register": "ثبت نام",
|
||||
"Reset Subscribe": "بازنشانی اشتراک",
|
||||
"SMS": "پیامک",
|
||||
"Server Management": "مدیریت سرور",
|
||||
"Settings": "تنظیمات",
|
||||
"Server Traffic": "ترافیک سرور",
|
||||
"Subscribe": "اشتراک",
|
||||
"Subscribe Config": "تنظیمات اشتراک",
|
||||
"Subscribe Traffic": "ترافیک اشتراک",
|
||||
"System": "سیستم",
|
||||
"System Config": "پیکربندی سیستم",
|
||||
"System Management": "مدیریت سیستم",
|
||||
"System Tool": "ابزار سیستم",
|
||||
"Ticket Management": "مدیریت بلیط",
|
||||
"User": "کاربر",
|
||||
"User Detail": "جزئیات کاربر",
|
||||
"User Management": "مدیریت کاربران"
|
||||
"User Management": "مدیریت کاربران",
|
||||
"Users & Support": "کاربران و پشتیبانی"
|
||||
}
|
||||
|
||||
37
apps/admin/locales/fa-IR/nodes.json
Normal file
37
apps/admin/locales/fa-IR/nodes.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"address": "آدرس",
|
||||
"cancel": "لغو",
|
||||
"confirm": "تأیید",
|
||||
"confirmDeleteDesc": "این عمل قابل بازگشت نیست.",
|
||||
"confirmDeleteTitle": "آیا میخواهید این گره را حذف کنید؟",
|
||||
"copied": "کپی شد",
|
||||
"copy": "کپی",
|
||||
"create": "ایجاد",
|
||||
"created": "ایجاد شد",
|
||||
"delete": "حذف",
|
||||
"deleted": "حذف شد",
|
||||
"drawerCreateTitle": "ایجاد گره",
|
||||
"drawerEditTitle": "ویرایش گره",
|
||||
"edit": "ویرایش",
|
||||
"enabled": "فعال",
|
||||
"enabled_off": "غیرفعال",
|
||||
"enabled_on": "فعال",
|
||||
"errors": {
|
||||
"nameRequired": "لطفاً یک نام وارد کنید",
|
||||
"portRange": "پورت باید بین ۱ و ۶۵۵۳۵ باشد",
|
||||
"protocolRequired": "لطفاً یک پروتکل انتخاب کنید",
|
||||
"serverAddrRequired": "لطفاً یک آدرس ورودی وارد کنید",
|
||||
"serverRequired": "لطفاً یک سرور انتخاب کنید"
|
||||
},
|
||||
"name": "نام",
|
||||
"pageTitle": "گرهها",
|
||||
"port": "پورت",
|
||||
"protocol": "پروتکل",
|
||||
"select_protocol": "پروتکل را انتخاب کنید…",
|
||||
"select_server": "سرور را انتخاب کنید…",
|
||||
"server": "سرور",
|
||||
"tags": "برچسبها",
|
||||
"tags_description": "برچسب گروهبندی مجوز (شامل پیوند برنامه و سیاستهای تحویل).",
|
||||
"tags_placeholder": "برای افزودن چندین برچسب از Enter یا ویرگول (,) استفاده کنید",
|
||||
"updated": "بهروزرسانی شد"
|
||||
}
|
||||
@ -1,59 +1,6 @@
|
||||
{
|
||||
"actions": "اقدامات",
|
||||
"app": {
|
||||
"appDownloadURL": "آدرس دانلود اپلیکیشن",
|
||||
"appIcon": "آیکون اپلیکیشن",
|
||||
"appList": "لیست برنامهها",
|
||||
"appName": "نام اپلیکیشن",
|
||||
"backupDomains": "لیست دامنههای پشتیبان",
|
||||
"backupDomainsDescription": "لیست دامنههای پشتیبان برای حل دامنه، هر دامنه در یک خط",
|
||||
"batchDelete": "حذف گروهی",
|
||||
"cancel": "لغو",
|
||||
"communicationKey": "کلید ارتباطی",
|
||||
"communicationKeyDescription": "کلیدی که برای ارتباط با مشتری استفاده میشود",
|
||||
"config": "پیکربندی",
|
||||
"configApp": "پیکربندی برنامه",
|
||||
"confirm": "تأیید",
|
||||
"confirmDelete": "تأیید حذف",
|
||||
"create": "ایجاد",
|
||||
"createApp": "ایجاد اپلیکیشن",
|
||||
"createSuccess": "با موفقیت ایجاد شد",
|
||||
"defaultVersion": "پیشفرض",
|
||||
"delete": "حذف",
|
||||
"deleteWarning": "این عمل قابل بازگشت نیست",
|
||||
"describeDescription": "برای توصیف برنامه استفاده میشود، در لیست برنامهها نمایش داده میشود",
|
||||
"description": "توضیحات",
|
||||
"downloadLink": "لینک دانلود",
|
||||
"edit": "ویرایش",
|
||||
"editApp": "ویرایش اپلیکیشن",
|
||||
"encryption": "روش رمزنگاری",
|
||||
"encryptionDescription": "روش رمزنگاری برای ارتباط با مشتری را انتخاب کنید. در صورت انتخاب، مشتری از این روش برای ارتباط با سرور استفاده خواهد کرد",
|
||||
"nameDescription": "نام برنامه، در لیست برنامهها نمایش داده میشود",
|
||||
"platform": "پلتفرم",
|
||||
"selectApp": "انتخاب برنامه",
|
||||
"selectAppDescription": "برنامهای را برای پیکربندی انتخاب کنید، تمام تنظیمات به برنامه انتخاب شده اعمال خواهد شد",
|
||||
"startupPicture": "تصویر شروع",
|
||||
"startupPictureDescription": "تصویر شروع، از تصاویر شبکه و محلی پشتیبانی میکند. برای تصاویر شبکه، لطفاً آدرس کامل تصویر را وارد کنید",
|
||||
"startupPicturePreview": "پیشنمایش تصویر شروع",
|
||||
"startupPictureSkip": "زمان عبور از تصویر شروع",
|
||||
"startupPictureSkipDescription": "زمان نمایش تصویر شروع به ثانیه، برای عدم نمایش 0 وارد کنید",
|
||||
"subscriptionProtocol": "پروتکل اشتراک",
|
||||
"updateSuccess": "با موفقیت بهروزرسانی شد",
|
||||
"version": "نسخه"
|
||||
},
|
||||
"cancel": "لغو",
|
||||
"config": {
|
||||
"singleSubscriptionMode": "حالت اشتراک تکی",
|
||||
"subscriptionDomain": "دامنه اشتراک",
|
||||
"subscriptionDomainDescription": "برای اشتراک استفاده میشود؛ برای استفاده از دامنه سایت، خالی بگذارید",
|
||||
"subscriptionDomainPlaceholder": "دامنه اشتراک را وارد کنید، هر خط یک دامنه",
|
||||
"subscriptionPath": "مسیر اشتراک",
|
||||
"subscriptionPathDescription": "برای اشتراک استفاده میشود؛ حتماً پس از تغییر، سیستم را برای عملکرد بهینه راهاندازی مجدد کنید",
|
||||
"subscriptionPathPlaceholder": "وارد کنید",
|
||||
"updateSuccess": "بهروزرسانی با موفقیت انجام شد",
|
||||
"wildcardResolution": "حل و فصل کاراکترهای جایگزین",
|
||||
"wildcardResolutionDescription": "برای اشتراک استفاده میشود"
|
||||
},
|
||||
"confirm": "تأیید",
|
||||
"confirmDelete": "آیا مطمئن هستید که میخواهید حذف کنید؟",
|
||||
"copy": "کپی",
|
||||
@ -94,6 +41,9 @@
|
||||
"name": "نام",
|
||||
"noLimit": "بدون محدودیت",
|
||||
"noReset": "بدون بازنشانی",
|
||||
"node": "گره",
|
||||
"nodeGroup": "گروه گره",
|
||||
"nodes": "گرهها",
|
||||
"pricing": "قیمتگذاری",
|
||||
"purchaseWithDiscount": "اجازه کسر",
|
||||
"purchaseWithDiscountDescription": "فعال یا غیرفعال کردن قابلیت لغو اشتراک. پس از فعالسازی، سیستم بر اساس قوانین و نسبتهای تنظیمشده، پردازش کسر را انجام میدهد و مقدار باقیمانده به موجودی بازگردانده میشود.",
|
||||
@ -106,9 +56,6 @@
|
||||
"selectResetCycle": "لطفاً یک چرخه بازنشانی انتخاب کنید",
|
||||
"selectSubscribeGroup": "گروه اشتراک را انتخاب کنید",
|
||||
"selectUnitTime": "لطفاً واحد زمان را انتخاب کنید",
|
||||
"server": "سرور",
|
||||
"serverGroup": "گروه سرور",
|
||||
"servers": "سرورها",
|
||||
"speedLimit": "محدودیت سرعت (مگابیت بر ثانیه)",
|
||||
"traffic": "ترافیک",
|
||||
"unitPrice": "قیمت واحد",
|
||||
@ -150,8 +97,6 @@
|
||||
"subscribeGroup": "گروه اشتراک",
|
||||
"tabs": {
|
||||
"subscribe": "اشتراک",
|
||||
"subscribeApp": "پیکربندی اپلیکیشن",
|
||||
"subscribeConfig": "پیکربندی اشتراک",
|
||||
"subscribeGroup": "گروه اشتراک"
|
||||
},
|
||||
"traffic": "ترافیک",
|
||||
|
||||
@ -1,183 +0,0 @@
|
||||
{
|
||||
"config": {
|
||||
"addTimeSlot": "افزودن بازه زمانی",
|
||||
"communicationKey": "کلید ارتباطی",
|
||||
"communicationKeyDescription": "کلید برای ارتباط گرهها به منظور اطمینان از امنیت دادهها",
|
||||
"delete": "حذف",
|
||||
"dynamicMultiplier": "ضریب پویا",
|
||||
"dynamicMultiplierDescription": "ضریب پویا به پردازش دادههای ارسال شده با ضرایب مختلف برای گرههای مختلف در دورههای زمانی مختلف اشاره دارد.",
|
||||
"endTime": "زمان پایان",
|
||||
"inputPlaceholder": "وارد کنید",
|
||||
"multiplier": "ضریب",
|
||||
"nodePullInterval": "فاصله زمانی کشیدن گره",
|
||||
"nodePullIntervalDescription": "فرکانس (بر حسب ثانیه) برای گرهها جهت دریافت داده از پنل",
|
||||
"nodePushInterval": "فاصله زمانی ارسال گره",
|
||||
"nodePushIntervalDescription": "فرکانس برای گرهها جهت ارسال داده به پنل",
|
||||
"reset": "بازنشانی",
|
||||
"save": "ذخیره",
|
||||
"saveSuccess": "ذخیره با موفقیت انجام شد",
|
||||
"startTime": "زمان شروع",
|
||||
"timeSlot": "بازه زمانی"
|
||||
},
|
||||
"group": {
|
||||
"actions": "اقدامات",
|
||||
"cancel": "لغو",
|
||||
"confirm": "تأیید",
|
||||
"confirmDelete": "آیا مطمئن هستید که میخواهید حذف کنید؟",
|
||||
"create": "ایجاد",
|
||||
"createNodeGroup": "ایجاد گروه نود",
|
||||
"createdSuccessfully": "با موفقیت ایجاد شد",
|
||||
"delete": "حذف",
|
||||
"deleteWarning": "پس از حذف، دادهها قابل بازیابی نخواهند بود. لطفاً با احتیاط ادامه دهید.",
|
||||
"deletedSuccessfully": "با موفقیت حذف شد",
|
||||
"description": "توضیحات",
|
||||
"edit": "ویرایش",
|
||||
"editNodeGroup": "ویرایش گروه نود",
|
||||
"name": "نام",
|
||||
"title": "فهرست گروه نود",
|
||||
"updatedAt": "بهروزرسانی شده در"
|
||||
},
|
||||
"groupForm": {
|
||||
"cancel": "لغو",
|
||||
"confirm": "تأیید",
|
||||
"description": "توضیحات",
|
||||
"name": "نام"
|
||||
},
|
||||
"node": {
|
||||
"abnormal": "غیرعادی",
|
||||
"actions": "اقدامات",
|
||||
"address": "آدرس",
|
||||
"all": "همه",
|
||||
"basicInfo": "اطلاعات پایه",
|
||||
"cancel": "لغو",
|
||||
"confirm": "تأیید",
|
||||
"confirmDelete": "آیا مطمئن هستید که میخواهید حذف کنید؟",
|
||||
"copy": "کپی",
|
||||
"copySuccess": "با موفقیت کپی شد",
|
||||
"create": "ایجاد",
|
||||
"createNode": "ایجاد گره",
|
||||
"createSuccess": "با موفقیت ایجاد شد",
|
||||
"delete": "حذف",
|
||||
"deleteSuccess": "با موفقیت حذف شد",
|
||||
"deleteWarning": "پس از حذف، دادهها قابل بازیابی نخواهند بود. لطفاً با احتیاط ادامه دهید.",
|
||||
"detail": "جزئیات",
|
||||
"disabled": "غیرفعال",
|
||||
"disk": "دیسک",
|
||||
"edit": "ویرایش",
|
||||
"editNode": "ویرایش گره",
|
||||
"enable": "فعالسازی",
|
||||
"enabled": "فعال",
|
||||
"expireTime": "زمان انقضا",
|
||||
"hide": "پنهان کردن",
|
||||
"id": "شناسه",
|
||||
"ipAddresses": "آدرسهای IP",
|
||||
"lastUpdated": "آخرین بهروزرسانی",
|
||||
"location": "مکان",
|
||||
"memory": "حافظه",
|
||||
"name": "نام",
|
||||
"noData": "--",
|
||||
"node": "گره",
|
||||
"nodeDetail": "جزئیات گره",
|
||||
"nodeGroup": "گروه گره",
|
||||
"nodeStatus": "وضعیت گره",
|
||||
"normal": "عادی",
|
||||
"onlineCount": "کاربران آنلاین",
|
||||
"onlineUsers": "کاربران آنلاین",
|
||||
"protocol": "پروتکل",
|
||||
"rate": "نرخ",
|
||||
"relay": "رله",
|
||||
"serverAddr": "آدرس سرور",
|
||||
"speedLimit": "محدودیت سرعت",
|
||||
"status": "وضعیت",
|
||||
"subscribeId": "شناسه اشتراک",
|
||||
"subscribeName": "نام اشتراک",
|
||||
"subscription": "اشتراک",
|
||||
"tags": "برچسبها",
|
||||
"trafficRatio": "نرخ ترافیک",
|
||||
"trafficUsage": "استفاده از ترافیک",
|
||||
"type": "نوع",
|
||||
"updateSuccess": "بهروزرسانی موفقیتآمیز بود",
|
||||
"updatedAt": "بهروزرسانی در",
|
||||
"user": "کاربر",
|
||||
"userDetail": "جزئیات کاربر",
|
||||
"userId": "شناسه کاربر"
|
||||
},
|
||||
"nodeForm": {
|
||||
"allowInsecure": "اجازه به ناامن",
|
||||
"cancel": "لغو",
|
||||
"city": "شهر",
|
||||
"confirm": "تأیید",
|
||||
"congestionController": "کنترل ترافیک",
|
||||
"country": "کشور",
|
||||
"disableSni": "غیرفعال کردن SNI",
|
||||
"edit": "ویرایش",
|
||||
"editSecurity": "ویرایش تنظیمات امنیتی",
|
||||
"enableTLS": "فعال کردن TLS",
|
||||
"encryptionMethod": "روش رمزنگاری",
|
||||
"fingerprint": "اثر انگشت",
|
||||
"flow": "الگوریتم کنترل جریان",
|
||||
"groupId": "گروه گره",
|
||||
"hopInterval": "فاصله پرش",
|
||||
"hopPorts": "پورتهای پرش",
|
||||
"hopPortsPlaceholder": "پورتهای متعدد را با کاما جدا کنید",
|
||||
"name": "نام",
|
||||
"obfsPassword": "رمز عبور پنهانسازی",
|
||||
"obfsPasswordPlaceholder": "برای عدم پنهانسازی خالی بگذارید",
|
||||
"path": "مسیر",
|
||||
"pleaseSelect": "لطفاً انتخاب کنید",
|
||||
"port": "پورت سرور",
|
||||
"protocol": "پروتکل",
|
||||
"reduceRtt": "کاهش RTT",
|
||||
"relayHost": "میزبان رله",
|
||||
"relayMode": "حالت رله",
|
||||
"relayPort": "پورت رله",
|
||||
"relayPrefix": "پیشوند رله",
|
||||
"remarks": "یادداشتها",
|
||||
"security": "امنیت",
|
||||
"securityConfig": "تنظیمات امنیتی",
|
||||
"selectEncryptionMethod": "انتخاب روش رمزنگاری",
|
||||
"selectNodeGroup": "انتخاب گروه گره",
|
||||
"selectProtocol": "انتخاب پروتکل",
|
||||
"selectRelayMode": "انتخاب حالت رله",
|
||||
"serverAddr": "آدرس سرور",
|
||||
"serverKey": "کلید سرور",
|
||||
"serverName": "نام سرویس",
|
||||
"speedLimit": "محدودیت سرعت",
|
||||
"speedLimitPlaceholder": "نامحدود",
|
||||
"tags": "برچسبها",
|
||||
"tagsPlaceholder": "برای وارد کردن چندین برچسب از Enter یا کاما (,) استفاده کنید",
|
||||
"trafficRatio": "نسبت ترافیک",
|
||||
"transport": "تنظیمات پروتکل حمل و نقل",
|
||||
"transportConfig": "تنظیمات پروتکل حمل و نقل",
|
||||
"transportHost": "آدرس سرور حمل و نقل",
|
||||
"transportPath": "مسیر حمل و نقل",
|
||||
"transportServerName": "نام سرور حمل و نقل",
|
||||
"udpRelayMode": "حالت رله UDP"
|
||||
},
|
||||
"relayModeOptions": {
|
||||
"all": "همه",
|
||||
"none": "هیچکدام",
|
||||
"random": "تصادفی"
|
||||
},
|
||||
"securityConfig": {
|
||||
"fingerprint": "اثر انگشت",
|
||||
"privateKey": "کلید خصوصی",
|
||||
"privateKeyPlaceholder": "برای تولید خودکار خالی بگذارید",
|
||||
"publicKey": "کلید عمومی",
|
||||
"publicKeyPlaceholder": "برای تولید خودکار خالی بگذارید",
|
||||
"serverAddress": "آدرس سرور",
|
||||
"serverAddressPlaceholder": "آدرس هدف REALITY، بهطور پیشفرض از SNI استفاده میکند",
|
||||
"serverName": "نام سرور (SNI)",
|
||||
"serverNamePlaceholder": "نیاز به REALITY، با backend سازگار باشد",
|
||||
"serverPort": "پورت سرور",
|
||||
"serverPortPlaceholder": "پورت هدف REALITY، بهطور پیشفرض 443",
|
||||
"shortId": "شناسه کوتاه",
|
||||
"shortIdPlaceholder": "برای تولید خودکار خالی بگذارید",
|
||||
"sni": "نشاندهنده نام سرور (SNI)"
|
||||
},
|
||||
"tabs": {
|
||||
"node": "نود",
|
||||
"nodeConfig": "پیکربندی نود",
|
||||
"nodeGroup": "گروه نود"
|
||||
}
|
||||
}
|
||||
101
apps/admin/locales/fa-IR/servers.json
Normal file
101
apps/admin/locales/fa-IR/servers.json
Normal file
@ -0,0 +1,101 @@
|
||||
{
|
||||
"address": "آدرس",
|
||||
"address_placeholder": "آدرس سرور",
|
||||
"cancel": "لغو",
|
||||
"city": "شهر",
|
||||
"config": {
|
||||
"actions": {
|
||||
"cancel": "لغو",
|
||||
"save": "ذخیره"
|
||||
},
|
||||
"communicationKey": "کلید ارتباطی",
|
||||
"communicationKeyDescription": "برای احراز هویت نود استفاده میشود.",
|
||||
"description": "مدیریت کلیدهای ارتباطی نود، فواصل کشیدن/فشردن و ضریبهای دینامیک.",
|
||||
"dynamicMultiplier": "ضریب دینامیک",
|
||||
"dynamicMultiplierDescription": "تعریف زمانهای مشخص و ضریبها برای تنظیم حسابداری ترافیک.",
|
||||
"endTime": "زمان پایان",
|
||||
"inputPlaceholder": "لطفاً وارد کنید",
|
||||
"multiplier": "ضریب",
|
||||
"nodePullInterval": "فاصله کشیدن نود",
|
||||
"nodePullIntervalDescription": "چند وقت یکبار نود پیکربندی را میکشد (ثانیه).",
|
||||
"nodePushInterval": "فاصله فشردن نود",
|
||||
"nodePushIntervalDescription": "چند وقت یکبار نود آمار را فشرده میکند (ثانیه).",
|
||||
"reset": "بازنشانی",
|
||||
"save": "ذخیره",
|
||||
"saveSuccess": "با موفقیت ذخیره شد",
|
||||
"startTime": "زمان شروع",
|
||||
"timeSlot": "زمانبندی",
|
||||
"title": "پیکربندی نود"
|
||||
},
|
||||
"confirm": "تأیید",
|
||||
"confirmDeleteDesc": "این عمل قابل بازگشت نیست.",
|
||||
"confirmDeleteTitle": "آیا این سرور را حذف کنید؟",
|
||||
"congestion_controller": "کنترلکننده ترافیک",
|
||||
"copied": "کپی شد",
|
||||
"copy": "کپی",
|
||||
"country": "کشور",
|
||||
"cpu": "سیپییو",
|
||||
"create": "ایجاد",
|
||||
"created": "با موفقیت ایجاد شد",
|
||||
"delete": "حذف",
|
||||
"deleted": "با موفقیت حذف شد",
|
||||
"disable_sni": "غیرفعال کردن SNI",
|
||||
"disk": "دیسک",
|
||||
"drawerCreateTitle": "ایجاد سرور",
|
||||
"drawerEditTitle": "ویرایش سرور",
|
||||
"edit": "ویرایش",
|
||||
"enabled": "فعال",
|
||||
"encryption_method": "روش رمزنگاری",
|
||||
"expireTime": "زمان انقضا",
|
||||
"expired": "منقضی شده",
|
||||
"flow": "جریان",
|
||||
"hop_interval": "فاصله پرش",
|
||||
"hop_ports": "پورتهای پرش",
|
||||
"hop_ports_placeholder": "مثلاً 1-65535",
|
||||
"host": "میزبان",
|
||||
"id": "شناسه",
|
||||
"ipAddresses": "آدرسهای IP",
|
||||
"memory": "حافظه",
|
||||
"name": "نام",
|
||||
"noData": "هیچ دادهای",
|
||||
"notAvailable": "غیرقابل دسترسی",
|
||||
"obfs_password": "رمز عبور اختفا",
|
||||
"obfs_password_placeholder": "رمز عبور اختفا را وارد کنید",
|
||||
"offline": "آفلاین",
|
||||
"online": "آنلاین",
|
||||
"onlineUsers": "کاربران آنلاین",
|
||||
"pageTitle": "سرورها",
|
||||
"path": "مسیر",
|
||||
"please_select": "لطفاً انتخاب کنید",
|
||||
"port": "پورت",
|
||||
"protocols": "پروتکلها",
|
||||
"reduce_rtt": "کاهش RTT",
|
||||
"security_allow_insecure": "اجازه به ناامن",
|
||||
"security_fingerprint": "اثر انگشت",
|
||||
"security_private_key": "کلید خصوصی واقعیت",
|
||||
"security_private_key_placeholder": "کلید خصوصی را وارد کنید",
|
||||
"security_public_key": "کلید عمومی واقعیت",
|
||||
"security_public_key_placeholder": "کلید عمومی را وارد کنید",
|
||||
"security_server_address": "آدرس سرور واقعیت",
|
||||
"security_server_address_placeholder": "مثلاً 1.2.3.4 یا دامنه",
|
||||
"security_server_port": "پورت سرور واقعیت",
|
||||
"security_short_id": "شناسه کوتاه واقعیت",
|
||||
"security_short_id_placeholder": "رشته هگز (حداکثر 16 کاراکتر)",
|
||||
"security_sni": "SNI",
|
||||
"security_title": "امنیت",
|
||||
"select_encryption_method": "روش رمزنگاری را انتخاب کنید",
|
||||
"server_key": "کلید سرور",
|
||||
"service_name": "نام سرویس",
|
||||
"status": "وضعیت",
|
||||
"subscribeId": "شناسه اشتراک",
|
||||
"subscription": "اشتراک",
|
||||
"traffic": "ترافیک",
|
||||
"traffic_ratio": "ضریب",
|
||||
"transport_title": "حمل و نقل",
|
||||
"udp_relay_mode": "حالت رله UDP",
|
||||
"unitSecondsShort": "ث",
|
||||
"unlimited": "نامحدود",
|
||||
"updated": "با موفقیت بهروزرسانی شد",
|
||||
"user": "کاربر",
|
||||
"validation_failed": "اعتبارسنجی ناموفق بود. لطفاً فرم را بررسی کنید."
|
||||
}
|
||||
@ -1,27 +1,36 @@
|
||||
{
|
||||
"ADS Config": "ADS-asetukset",
|
||||
"Announcement Management": "Ilmoitusten hallinta",
|
||||
"Application Management": "Sovellushallinta",
|
||||
"Auth Control": "Todennuksen hallinta",
|
||||
"Balance": "Saldo",
|
||||
"Commerce": "Kauppa",
|
||||
"Commission": "Komissio",
|
||||
"Coupon Management": "Kuponkien hallinta",
|
||||
"Dashboard": "Kojelauta",
|
||||
"Document Management": "Asiakirjojen hallinta",
|
||||
"Finance": "Rahoitus",
|
||||
"Email": "Sähköposti",
|
||||
"Gift": "Lahja",
|
||||
"Login": "Kirjaudu sisään",
|
||||
"Logs & Analytics": "Lokit ja analytiikka",
|
||||
"Maintenance": "Ylläpito",
|
||||
"Marketing Management": "Markkinoinnin Hallinta",
|
||||
"Node Management": "Solmun hallinta",
|
||||
"Order Management": "Tilausten hallinta",
|
||||
"Payment Config": "Maksukonfiguraatio",
|
||||
"Product Management": "Tuotteen hallinta",
|
||||
"Protocol Management": "Protokollan hallinta",
|
||||
"Rule Management": "Sääntöhallinta",
|
||||
"Server": "Palvelu",
|
||||
"Register": "Rekisteröidy",
|
||||
"Reset Subscribe": "Nollaa tilaus",
|
||||
"SMS": "SMS",
|
||||
"Server Management": "Palvelimen hallinta",
|
||||
"Settings": "Asetukset",
|
||||
"Server Traffic": "Palvelimen liikenne",
|
||||
"Subscribe": "Tilaa",
|
||||
"Subscribe Config": "Tilauksen asetukset",
|
||||
"Subscribe Traffic": "Tilauksen liikenne",
|
||||
"System": "Järjestelmä",
|
||||
"System Config": "Järjestelmän asetukset",
|
||||
"System Management": "Järjestelmän hallinta",
|
||||
"System Tool": "Järjestelmätyökalu",
|
||||
"Ticket Management": "Lipputoiminta",
|
||||
"User": "Käyttäjä",
|
||||
"User Detail": "Käyttäjän tiedot",
|
||||
"User Management": "Käyttäjien hallinta"
|
||||
"User Management": "Käyttäjien hallinta",
|
||||
"Users & Support": "Käyttäjät ja tuki"
|
||||
}
|
||||
|
||||
37
apps/admin/locales/fi-FI/nodes.json
Normal file
37
apps/admin/locales/fi-FI/nodes.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"address": "Osoite",
|
||||
"cancel": "Peruuta",
|
||||
"confirm": "Vahvista",
|
||||
"confirmDeleteDesc": "Tätä toimintoa ei voi peruuttaa.",
|
||||
"confirmDeleteTitle": "Poista tämä solmu?",
|
||||
"copied": "Kopioitu",
|
||||
"copy": "Kopioi",
|
||||
"create": "Luo",
|
||||
"created": "Luotu",
|
||||
"delete": "Poista",
|
||||
"deleted": "Poistettu",
|
||||
"drawerCreateTitle": "Luo solmu",
|
||||
"drawerEditTitle": "Muokkaa solmua",
|
||||
"edit": "Muokkaa",
|
||||
"enabled": "Käytössä",
|
||||
"enabled_off": "Pois käytöstä",
|
||||
"enabled_on": "Käytössä",
|
||||
"errors": {
|
||||
"nameRequired": "Ole hyvä ja syötä nimi",
|
||||
"portRange": "Portin on oltava välillä 1 ja 65535",
|
||||
"protocolRequired": "Ole hyvä ja valitse protokolla",
|
||||
"serverAddrRequired": "Ole hyvä ja syötä osoite",
|
||||
"serverRequired": "Ole hyvä ja valitse palvelin"
|
||||
},
|
||||
"name": "Nimi",
|
||||
"pageTitle": "Solmut",
|
||||
"port": "Portti",
|
||||
"protocol": "Protokolla",
|
||||
"select_protocol": "Valitse protokolla…",
|
||||
"select_server": "Valitse palvelin…",
|
||||
"server": "Palvelin",
|
||||
"tags": "Tunnisteet",
|
||||
"tags_description": "Oikeuksien ryhmittelytunniste (mukaan lukien suunnitelman sitominen ja toimituskäytännöt).",
|
||||
"tags_placeholder": "Käytä Enteriä tai pilkkua (,) lisätäksesi useita tunnisteita",
|
||||
"updated": "Päivitetty"
|
||||
}
|
||||
@ -1,59 +1,6 @@
|
||||
{
|
||||
"actions": "toiminnot",
|
||||
"app": {
|
||||
"appDownloadURL": "Sovelluksen lataus-URL",
|
||||
"appIcon": "Sovelluksen kuvake",
|
||||
"appList": "Sovellusluettelo",
|
||||
"appName": "Sovelluksen nimi",
|
||||
"backupDomains": "Varmuuskopiodomainien luettelo",
|
||||
"backupDomainsDescription": "Varmuuskopiodomainien luettelo domainin resoluutiota varten, yksi domain per rivi",
|
||||
"batchDelete": "Poista erä",
|
||||
"cancel": "Peruuta",
|
||||
"communicationKey": "Viestintäavain",
|
||||
"communicationKeyDescription": "Avain, jota käytetään asiakasviestintään",
|
||||
"config": "Asetukset",
|
||||
"configApp": "Sovelluksen asetukset",
|
||||
"confirm": "Vahvista",
|
||||
"confirmDelete": "Vahvista poisto",
|
||||
"create": "Luo",
|
||||
"createApp": "Luo sovellus",
|
||||
"createSuccess": "Luotu onnistuneesti",
|
||||
"defaultVersion": "Oletus",
|
||||
"delete": "Poista",
|
||||
"deleteWarning": "Tätä toimintoa ei voi peruuttaa",
|
||||
"describeDescription": "Käytetään sovelluksen kuvaamiseen, näytetään sovellusluettelossa",
|
||||
"description": "Kuvaus",
|
||||
"downloadLink": "Latauslinkki",
|
||||
"edit": "Muokkaa",
|
||||
"editApp": "Muokkaa sovellusta",
|
||||
"encryption": "Salausmenetelmä",
|
||||
"encryptionDescription": "Valitse salausmenetelmä asiakasviestintään. Jos valittu, asiakas käyttää tätä menetelmää kommunikoidessaan palvelimen kanssa",
|
||||
"nameDescription": "Sovelluksen nimi, näytetään sovellusluettelossa",
|
||||
"platform": "Alusta",
|
||||
"selectApp": "Valitse Sovellus",
|
||||
"selectAppDescription": "Valitse sovellus, jota haluat konfiguroida. Kaikki asetukset koskevat valittua sovellusta",
|
||||
"startupPicture": "Käynnistyskuva",
|
||||
"startupPictureDescription": "Käynnistyskuva, tukee verkko- ja paikallisia kuvia. Verkkokuville, syötä täydellinen kuvan URL-osoite",
|
||||
"startupPicturePreview": "Käynnistyskuvan esikatselu",
|
||||
"startupPictureSkip": "Käynnistyskuvan ohitusaika",
|
||||
"startupPictureSkipDescription": "Käynnistyskuvan näyttöaika sekunteina, syötä 0, jos ei näytetä",
|
||||
"subscriptionProtocol": "Tilausprotokolla",
|
||||
"updateSuccess": "Päivitetty onnistuneesti",
|
||||
"version": "Versio"
|
||||
},
|
||||
"cancel": "Peruuta",
|
||||
"config": {
|
||||
"singleSubscriptionMode": "Yhden tilauksen tila",
|
||||
"subscriptionDomain": "Tilausalue",
|
||||
"subscriptionDomainDescription": "Käytetään tilaukseen; jätä tyhjäksi käyttääksesi sivuston verkkotunnusta",
|
||||
"subscriptionDomainPlaceholder": "Syötä tilausalue, yksi per rivi",
|
||||
"subscriptionPath": "Tilauspolku",
|
||||
"subscriptionPathDescription": "Käytetään tilaukseen; varmista, että käynnistät järjestelmän uudelleen muutoksen jälkeen parhaan suorituskyvyn saavuttamiseksi",
|
||||
"subscriptionPathPlaceholder": "Syötä",
|
||||
"updateSuccess": "Päivitys onnistui",
|
||||
"wildcardResolution": "Yleismerkkien ratkaisu",
|
||||
"wildcardResolutionDescription": "Käytetään tilaukseen"
|
||||
},
|
||||
"confirm": "Vahvista",
|
||||
"confirmDelete": "Haluatko varmasti poistaa?",
|
||||
"copy": "Kopioi",
|
||||
@ -94,6 +41,9 @@
|
||||
"name": "Nimi",
|
||||
"noLimit": "Ei rajoitusta",
|
||||
"noReset": "Ei Nollausta",
|
||||
"node": "Solmu",
|
||||
"nodeGroup": "Solmuryhmä",
|
||||
"nodes": "Solmut",
|
||||
"pricing": "Hinnoittelu",
|
||||
"purchaseWithDiscount": "Salli Vähennys",
|
||||
"purchaseWithDiscountDescription": "Ota käyttöön tai poista käytöstä peruutustoiminto. Aktivoinnin jälkeen järjestelmä suorittaa vähennyskäsittelyn määritettyjen sääntöjen ja osuuksien mukaisesti, ja jäljelle jäävä arvo palautetaan saldolle.",
|
||||
@ -106,9 +56,6 @@
|
||||
"selectResetCycle": "Valitse nollausjakso",
|
||||
"selectSubscribeGroup": "Valitse tilausryhmä",
|
||||
"selectUnitTime": "Valitse aikayksikkö",
|
||||
"server": "Palvelin",
|
||||
"serverGroup": "Palvelinryhmä",
|
||||
"servers": "Palvelimet",
|
||||
"speedLimit": "Nopeusrajoitus ",
|
||||
"traffic": "Liikenne",
|
||||
"unitPrice": "Yksikköhinta",
|
||||
@ -150,8 +97,6 @@
|
||||
"subscribeGroup": "Tilaa ryhmä",
|
||||
"tabs": {
|
||||
"subscribe": "Tilaa",
|
||||
"subscribeApp": "Sovelluksen asetukset",
|
||||
"subscribeConfig": "Tilausasetukset",
|
||||
"subscribeGroup": "Tilaa ryhmä"
|
||||
},
|
||||
"traffic": "liikenne",
|
||||
|
||||
@ -1,183 +0,0 @@
|
||||
{
|
||||
"config": {
|
||||
"addTimeSlot": "Lisää Aikaväli",
|
||||
"communicationKey": "Viestintäavain",
|
||||
"communicationKeyDescription": "Avain solmujen viestintään tietoturvan varmistamiseksi",
|
||||
"delete": "Poista",
|
||||
"dynamicMultiplier": "Dynaaminen Kerroin",
|
||||
"dynamicMultiplierDescription": "Dynaaminen kerroin tarkoittaa työnnetyn datan käsittelyä eri kertoimilla eri solmuille eri ajanjaksoina.",
|
||||
"endTime": "Lopetusaika",
|
||||
"inputPlaceholder": "Syötä",
|
||||
"multiplier": "Kerroin",
|
||||
"nodePullInterval": "Solmun Noutoväli",
|
||||
"nodePullIntervalDescription": "Taajuus (sekunteina), jolla solmut hakevat dataa paneelista",
|
||||
"nodePushInterval": "Solmun Työntövälit",
|
||||
"nodePushIntervalDescription": "Taajuus, jolla solmut työntävät dataa paneeliin",
|
||||
"reset": "Nollaa",
|
||||
"save": "Tallenna",
|
||||
"saveSuccess": "Tallennus Onnistui",
|
||||
"startTime": "Aloitusaika",
|
||||
"timeSlot": "Aikaväli"
|
||||
},
|
||||
"group": {
|
||||
"actions": "Toiminnot",
|
||||
"cancel": "Peruuta",
|
||||
"confirm": "Vahvista",
|
||||
"confirmDelete": "Haluatko varmasti poistaa?",
|
||||
"create": "Luo",
|
||||
"createNodeGroup": "Luo solmuryhmä",
|
||||
"createdSuccessfully": "Luotu onnistuneesti",
|
||||
"delete": "Poista",
|
||||
"deleteWarning": "Poiston jälkeen tietoja ei voi palauttaa, ole varovainen.",
|
||||
"deletedSuccessfully": "Poistettu onnistuneesti",
|
||||
"description": "Kuvaus",
|
||||
"edit": "Muokkaa",
|
||||
"editNodeGroup": "Muokkaa solmuryhmää",
|
||||
"name": "Nimi",
|
||||
"title": "Solmuryhmien lista",
|
||||
"updatedAt": "Päivitetty"
|
||||
},
|
||||
"groupForm": {
|
||||
"cancel": "Peruuta",
|
||||
"confirm": "Vahvista",
|
||||
"description": "Kuvaus",
|
||||
"name": "Nimi"
|
||||
},
|
||||
"node": {
|
||||
"abnormal": "Poikkeava",
|
||||
"actions": "Toiminnot",
|
||||
"address": "Osoite",
|
||||
"all": "Kaikki",
|
||||
"basicInfo": "Perustiedot",
|
||||
"cancel": "Peruuta",
|
||||
"confirm": "Vahvista",
|
||||
"confirmDelete": "Haluatko varmasti poistaa?",
|
||||
"copy": "Kopioi",
|
||||
"copySuccess": "Kopioitu onnistuneesti",
|
||||
"create": "Luo",
|
||||
"createNode": "Luo solmu",
|
||||
"createSuccess": "Luonti onnistui",
|
||||
"delete": "Poista",
|
||||
"deleteSuccess": "Poisto onnistui",
|
||||
"deleteWarning": "Poiston jälkeen tietoja ei voi palauttaa. Ole varovainen.",
|
||||
"detail": "Yksityiskohdat",
|
||||
"disabled": "Pois käytöstä",
|
||||
"disk": "Levy",
|
||||
"edit": "Muokkaa",
|
||||
"editNode": "Muokkaa solmua",
|
||||
"enable": "Ota käyttöön",
|
||||
"enabled": "Käytössä",
|
||||
"expireTime": "Voimassaoloaika",
|
||||
"hide": "Piilota",
|
||||
"id": "ID",
|
||||
"ipAddresses": "IP-osoitteet",
|
||||
"lastUpdated": "Viimeksi päivitetty",
|
||||
"location": "Sijainti",
|
||||
"memory": "Muisti",
|
||||
"name": "Nimi",
|
||||
"noData": "--",
|
||||
"node": "Solmu",
|
||||
"nodeDetail": "Solmun tiedot",
|
||||
"nodeGroup": "Solmuryhmä",
|
||||
"nodeStatus": "Solmun tila",
|
||||
"normal": "Normaali",
|
||||
"onlineCount": "Online-käyttäjien määrä",
|
||||
"onlineUsers": "Online-käyttäjät",
|
||||
"protocol": "Protokolla",
|
||||
"rate": "Nopeus",
|
||||
"relay": "Välitys",
|
||||
"serverAddr": "Palvelimen osoite",
|
||||
"speedLimit": "Nopeusrajoitus",
|
||||
"status": "Tila",
|
||||
"subscribeId": "Tilauksen ID",
|
||||
"subscribeName": "Tilauksen nimi",
|
||||
"subscription": "Tilauksen tiedot",
|
||||
"tags": "Tunnisteet",
|
||||
"trafficRatio": "Liikenteen nopeus",
|
||||
"trafficUsage": "Liikenteen käyttö",
|
||||
"type": "Tyyppi",
|
||||
"updateSuccess": "Päivitys onnistui",
|
||||
"updatedAt": "Päivitetty",
|
||||
"user": "Käyttäjä",
|
||||
"userDetail": "Käyttäjän tiedot",
|
||||
"userId": "Käyttäjän ID"
|
||||
},
|
||||
"nodeForm": {
|
||||
"allowInsecure": "Salli epävarma",
|
||||
"cancel": "Peruuta",
|
||||
"city": "Kaupunki",
|
||||
"confirm": "Vahvista",
|
||||
"congestionController": "Ruuhkansäätö",
|
||||
"country": "Maa",
|
||||
"disableSni": "Poista SNI käytöstä",
|
||||
"edit": "Muokkaa",
|
||||
"editSecurity": "Muokkaa turvallisuusasetuksia",
|
||||
"enableTLS": "Ota TLS käyttöön",
|
||||
"encryptionMethod": "Salausmenetelmä",
|
||||
"fingerprint": "Sormenjälki",
|
||||
"flow": "Virtaohjausalgoritmi",
|
||||
"groupId": "Solmuryhmä",
|
||||
"hopInterval": "Hyppäysväli",
|
||||
"hopPorts": "Hyppäysportit",
|
||||
"hopPortsPlaceholder": "Erota useat portit pilkuilla",
|
||||
"name": "Nimi",
|
||||
"obfsPassword": "Häilytys salasana",
|
||||
"obfsPasswordPlaceholder": "Jätä tyhjäksi, jos ei häilytystä",
|
||||
"path": "Polku",
|
||||
"pleaseSelect": "Valitse",
|
||||
"port": "Palvelimen portti",
|
||||
"protocol": "Protokolla",
|
||||
"reduceRtt": "Vähennä RTT",
|
||||
"relayHost": "Väyläisäntä",
|
||||
"relayMode": "Väylätila",
|
||||
"relayPort": "Väyläportti",
|
||||
"relayPrefix": "Väyläetuliite",
|
||||
"remarks": "Huomiot",
|
||||
"security": "Turvallisuus",
|
||||
"securityConfig": "Turvallisuusasetukset",
|
||||
"selectEncryptionMethod": "Valitse salausmenetelmä",
|
||||
"selectNodeGroup": "Valitse solmuryhmä",
|
||||
"selectProtocol": "Valitse protokolla",
|
||||
"selectRelayMode": "Valitse väylätila",
|
||||
"serverAddr": "Palvelimen osoite",
|
||||
"serverKey": "Palvelimen avain",
|
||||
"serverName": "Palvelun nimi",
|
||||
"speedLimit": "Nopeusrajoitus",
|
||||
"speedLimitPlaceholder": "Rajoittamaton",
|
||||
"tags": "Tunnisteet",
|
||||
"tagsPlaceholder": "Käytä Enteriä tai pilkkua (,) useiden tunnisteiden syöttämiseen",
|
||||
"trafficRatio": "Liikennesuhde",
|
||||
"transport": "Siirtoprotokollan asetukset",
|
||||
"transportConfig": "Siirtoprotokollan asetukset",
|
||||
"transportHost": "Siirtopalvelimen osoite",
|
||||
"transportPath": "Siirtopolku",
|
||||
"transportServerName": "Siirtopalvelimen nimi",
|
||||
"udpRelayMode": "UDP väylätila"
|
||||
},
|
||||
"relayModeOptions": {
|
||||
"all": "Kaikki",
|
||||
"none": "Ei mitään",
|
||||
"random": "Satunnainen"
|
||||
},
|
||||
"securityConfig": {
|
||||
"fingerprint": "Sormenjälki",
|
||||
"privateKey": "Yksityinen avain",
|
||||
"privateKeyPlaceholder": "Jätä tyhjäksi automaattista luontia varten",
|
||||
"publicKey": "Julkinen avain",
|
||||
"publicKeyPlaceholder": "Jätä tyhjäksi automaattista luontia varten",
|
||||
"serverAddress": "Palvelimen osoite",
|
||||
"serverAddressPlaceholder": "REALITY-kohdeosoite, oletuksena SNI",
|
||||
"serverName": "Palvelimen nimi (SNI)",
|
||||
"serverNamePlaceholder": "REALITY vaaditaan, yhteensopiva taustajärjestelmän kanssa",
|
||||
"serverPort": "Palvelimen portti",
|
||||
"serverPortPlaceholder": "REALITY-kohdeportti, oletus 443",
|
||||
"shortId": "Lyhyt ID",
|
||||
"shortIdPlaceholder": "Jätä tyhjäksi automaattista luontia varten",
|
||||
"sni": "Palvelimen nimen ilmoitus (SNI)"
|
||||
},
|
||||
"tabs": {
|
||||
"node": "Solmu",
|
||||
"nodeConfig": "Solmun asetukset",
|
||||
"nodeGroup": "Solmuryhmä"
|
||||
}
|
||||
}
|
||||
101
apps/admin/locales/fi-FI/servers.json
Normal file
101
apps/admin/locales/fi-FI/servers.json
Normal file
@ -0,0 +1,101 @@
|
||||
{
|
||||
"address": "Osoite",
|
||||
"address_placeholder": "Palvelimen osoite",
|
||||
"cancel": "Peruuta",
|
||||
"city": "Kaupunki",
|
||||
"config": {
|
||||
"actions": {
|
||||
"cancel": "Peruuta",
|
||||
"save": "Tallenna"
|
||||
},
|
||||
"communicationKey": "Viestintäavain",
|
||||
"communicationKeyDescription": "Käytetään solmun todennukseen.",
|
||||
"description": "Hallitse solmun viestintäavaimia, vetovälejä ja dynaamisia kertoimia.",
|
||||
"dynamicMultiplier": "Dynaaminen kerroin",
|
||||
"dynamicMultiplierDescription": "Määritä aikaväli ja kertoimet liikenteen laskentaa varten.",
|
||||
"endTime": "Lopetusaika",
|
||||
"inputPlaceholder": "Ole hyvä ja syötä",
|
||||
"multiplier": "Kerroin",
|
||||
"nodePullInterval": "Solmun vetoväli",
|
||||
"nodePullIntervalDescription": "Kuinka usein solmu vetää konfiguraation (sekunteina).",
|
||||
"nodePushInterval": "Solmun työntöväli",
|
||||
"nodePushIntervalDescription": "Kuinka usein solmu työntää tilastoja (sekunteina).",
|
||||
"reset": "Nollaa",
|
||||
"save": "Tallenna",
|
||||
"saveSuccess": "Tallennus onnistui",
|
||||
"startTime": "Aloitusaika",
|
||||
"timeSlot": "Aikaväli",
|
||||
"title": "Solmun konfigurointi"
|
||||
},
|
||||
"confirm": "Vahvista",
|
||||
"confirmDeleteDesc": "Tätä toimintoa ei voi peruuttaa.",
|
||||
"confirmDeleteTitle": "Poista tämä palvelin?",
|
||||
"congestion_controller": "Ruuhkansäätö",
|
||||
"copied": "Kopioitu",
|
||||
"copy": "Kopioi",
|
||||
"country": "Maa",
|
||||
"cpu": "CPU",
|
||||
"create": "Luo",
|
||||
"created": "Luotu onnistuneesti",
|
||||
"delete": "Poista",
|
||||
"deleted": "Poistettu onnistuneesti",
|
||||
"disable_sni": "Poista SNI käytöstä",
|
||||
"disk": "Levy",
|
||||
"drawerCreateTitle": "Luo palvelin",
|
||||
"drawerEditTitle": "Muokkaa palvelinta",
|
||||
"edit": "Muokkaa",
|
||||
"enabled": "Käytössä",
|
||||
"encryption_method": "Salausmenetelmä",
|
||||
"expireTime": "Voimassaoloaika",
|
||||
"expired": "Vanhentunut",
|
||||
"flow": "Virta",
|
||||
"hop_interval": "Hyppyvälit",
|
||||
"hop_ports": "Hyppysatamat",
|
||||
"hop_ports_placeholder": "esim. 1-65535",
|
||||
"host": "Isäntä",
|
||||
"id": "ID",
|
||||
"ipAddresses": "IP-osoitteet",
|
||||
"memory": "Muisti",
|
||||
"name": "Nimi",
|
||||
"noData": "Ei tietoja",
|
||||
"notAvailable": "Ei saatavilla",
|
||||
"obfs_password": "Häilytyssalasana",
|
||||
"obfs_password_placeholder": "Syötä häilytyssalasana",
|
||||
"offline": "Offline",
|
||||
"online": "Online",
|
||||
"onlineUsers": "Verkossa olevat käyttäjät",
|
||||
"pageTitle": "Palvelimet",
|
||||
"path": "Polku",
|
||||
"please_select": "Ole hyvä ja valitse",
|
||||
"port": "Portti",
|
||||
"protocols": "Protokollat",
|
||||
"reduce_rtt": "Vähennä RTT",
|
||||
"security_allow_insecure": "Salli epävarma",
|
||||
"security_fingerprint": "Sormenjälki",
|
||||
"security_private_key": "Todellinen yksityinen avain",
|
||||
"security_private_key_placeholder": "Syötä yksityinen avain",
|
||||
"security_public_key": "Todellinen julkinen avain",
|
||||
"security_public_key_placeholder": "Syötä julkinen avain",
|
||||
"security_server_address": "Todellinen palvelimen osoite",
|
||||
"security_server_address_placeholder": "esim. 1.2.3.4 tai verkkotunnus",
|
||||
"security_server_port": "Todellinen palvelimen portti",
|
||||
"security_short_id": "Todellinen lyhyt ID",
|
||||
"security_short_id_placeholder": "Hex-merkkijono (enintään 16 merkkiä)",
|
||||
"security_sni": "SNI",
|
||||
"security_title": "Turvallisuus",
|
||||
"select_encryption_method": "Valitse salausmenetelmä",
|
||||
"server_key": "Palvelimen avain",
|
||||
"service_name": "Palvelun nimi",
|
||||
"status": "Tila",
|
||||
"subscribeId": "Tilauksen ID",
|
||||
"subscription": "Tilauksen",
|
||||
"traffic": "Liikenne",
|
||||
"traffic_ratio": "Kerroin",
|
||||
"transport_title": "Kuljetus",
|
||||
"udp_relay_mode": "UDP-väylätila",
|
||||
"unitSecondsShort": "S",
|
||||
"unlimited": "Rajoittamaton",
|
||||
"updated": "Päivitetty onnistuneesti",
|
||||
"user": "Käyttäjä",
|
||||
"validation_failed": "Vahvistus epäonnistui. Tarkista lomake."
|
||||
}
|
||||
@ -1,27 +1,36 @@
|
||||
{
|
||||
"ADS Config": "Configuration ADS",
|
||||
"Announcement Management": "Gestion des annonces",
|
||||
"Application Management": "Gestion des applications",
|
||||
"Auth Control": "Contrôle d'authentification",
|
||||
"Balance": "Solde",
|
||||
"Commerce": "Commerce",
|
||||
"Commission": "Commission",
|
||||
"Coupon Management": "Gestion des coupons",
|
||||
"Dashboard": "Tableau de bord",
|
||||
"Document Management": "Gestion des documents",
|
||||
"Finance": "Finance",
|
||||
"Email": "Email",
|
||||
"Gift": "Cadeau",
|
||||
"Login": "Connexion",
|
||||
"Logs & Analytics": "Journaux et Analytique",
|
||||
"Maintenance": "Maintenance",
|
||||
"Marketing Management": "Gestion du marketing",
|
||||
"Node Management": "Gestion des Nœuds",
|
||||
"Order Management": "Gestion des commandes",
|
||||
"Payment Config": "Configuration de paiement",
|
||||
"Product Management": "Gestion de produit",
|
||||
"Protocol Management": "Gestion de protocole",
|
||||
"Rule Management": "Gestion des règles",
|
||||
"Server": "Serveur",
|
||||
"Register": "S'inscrire",
|
||||
"Reset Subscribe": "Réinitialiser l'Abonnement",
|
||||
"SMS": "SMS",
|
||||
"Server Management": "Gestion des services",
|
||||
"Settings": "Paramètres",
|
||||
"Server Traffic": "Trafic Serveur",
|
||||
"Subscribe": "S'abonner",
|
||||
"Subscribe Config": "Configuration d'abonnement",
|
||||
"Subscribe Traffic": "Trafic d'Abonnement",
|
||||
"System": "Système",
|
||||
"System Config": "Configuration du système",
|
||||
"System Management": "Gestion du système",
|
||||
"System Tool": "Outil Système",
|
||||
"Ticket Management": "Gestion des billets",
|
||||
"User": "Utilisateur",
|
||||
"User Detail": "Détail de l'utilisateur",
|
||||
"User Management": "Gestion des utilisateurs"
|
||||
"User Management": "Gestion des utilisateurs",
|
||||
"Users & Support": "Utilisateurs et Support"
|
||||
}
|
||||
|
||||
37
apps/admin/locales/fr-FR/nodes.json
Normal file
37
apps/admin/locales/fr-FR/nodes.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"address": "Adresse",
|
||||
"cancel": "Annuler",
|
||||
"confirm": "Confirmer",
|
||||
"confirmDeleteDesc": "Cette action ne peut pas être annulée.",
|
||||
"confirmDeleteTitle": "Supprimer ce nœud ?",
|
||||
"copied": "Copié",
|
||||
"copy": "Copier",
|
||||
"create": "Créer",
|
||||
"created": "Créé",
|
||||
"delete": "Supprimer",
|
||||
"deleted": "Supprimé",
|
||||
"drawerCreateTitle": "Créer un nœud",
|
||||
"drawerEditTitle": "Modifier le nœud",
|
||||
"edit": "Modifier",
|
||||
"enabled": "Activé",
|
||||
"enabled_off": "Désactivé",
|
||||
"enabled_on": "Activé",
|
||||
"errors": {
|
||||
"nameRequired": "Veuillez entrer un nom",
|
||||
"portRange": "Le port doit être compris entre 1 et 65535",
|
||||
"protocolRequired": "Veuillez sélectionner un protocole",
|
||||
"serverAddrRequired": "Veuillez entrer une adresse d'entrée",
|
||||
"serverRequired": "Veuillez sélectionner un serveur"
|
||||
},
|
||||
"name": "Nom",
|
||||
"pageTitle": "Nœuds",
|
||||
"port": "Port",
|
||||
"protocol": "Protocole",
|
||||
"select_protocol": "Sélectionner un protocole…",
|
||||
"select_server": "Sélectionner un serveur…",
|
||||
"server": "Serveur",
|
||||
"tags": "Étiquettes",
|
||||
"tags_description": "Étiquette de regroupement de permissions (y compris l'association de plan et les politiques de livraison).",
|
||||
"tags_placeholder": "Utilisez Entrée ou une virgule (,) pour ajouter plusieurs étiquettes",
|
||||
"updated": "Mis à jour"
|
||||
}
|
||||
@ -1,59 +1,6 @@
|
||||
{
|
||||
"actions": "actions",
|
||||
"app": {
|
||||
"appDownloadURL": "URL de téléchargement de l'application",
|
||||
"appIcon": "Icône de l'application",
|
||||
"appList": "Liste des applications",
|
||||
"appName": "Nom de l'application",
|
||||
"backupDomains": "Liste des domaines de sauvegarde",
|
||||
"backupDomainsDescription": "Liste des domaines de sauvegarde pour la résolution de domaine, un domaine par ligne",
|
||||
"batchDelete": "Suppression par lot",
|
||||
"cancel": "Annuler",
|
||||
"communicationKey": "Clé de communication",
|
||||
"communicationKeyDescription": "Clé utilisée pour la communication client",
|
||||
"config": "Configuration",
|
||||
"configApp": "Configuration de l'application",
|
||||
"confirm": "Confirmer",
|
||||
"confirmDelete": "Confirmer la suppression",
|
||||
"create": "Créer",
|
||||
"createApp": "Créer une application",
|
||||
"createSuccess": "Créé avec succès",
|
||||
"defaultVersion": "Par défaut",
|
||||
"delete": "Supprimer",
|
||||
"deleteWarning": "Cette action est irréversible",
|
||||
"describeDescription": "Utilisé pour décrire l'application, affiché dans la liste des applications",
|
||||
"description": "Description",
|
||||
"downloadLink": "Lien de téléchargement",
|
||||
"edit": "Modifier",
|
||||
"editApp": "Modifier l'application",
|
||||
"encryption": "Méthode de chiffrement",
|
||||
"encryptionDescription": "Choisissez la méthode de chiffrement pour la communication client. Si elle est sélectionnée, le client utilisera cette méthode pour communiquer avec le serveur",
|
||||
"nameDescription": "Nom de l'application, affiché dans la liste des applications",
|
||||
"platform": "Plateforme",
|
||||
"selectApp": "Sélectionner l'application",
|
||||
"selectAppDescription": "Sélectionnez l'application à configurer, tous les paramètres s'appliqueront à l'application sélectionnée",
|
||||
"startupPicture": "Image de démarrage",
|
||||
"startupPictureDescription": "Image de démarrage, prend en charge les images réseau et locales. Pour les images réseau, veuillez entrer l'URL complète de l'image",
|
||||
"startupPicturePreview": "Aperçu de l'image de démarrage",
|
||||
"startupPictureSkip": "Temps de saut de l'image de démarrage",
|
||||
"startupPictureSkipDescription": "Temps d'affichage de l'image de démarrage en secondes, entrez 0 pour ne pas afficher",
|
||||
"subscriptionProtocol": "Protocole d'abonnement",
|
||||
"updateSuccess": "Mis à jour avec succès",
|
||||
"version": "Version"
|
||||
},
|
||||
"cancel": "Annuler",
|
||||
"config": {
|
||||
"singleSubscriptionMode": "Mode d'abonnement unique",
|
||||
"subscriptionDomain": "Domaine d'abonnement",
|
||||
"subscriptionDomainDescription": "Utilisé pour l'abonnement ; laissez vide pour utiliser le domaine du site",
|
||||
"subscriptionDomainPlaceholder": "Entrez le domaine d'abonnement, un par ligne",
|
||||
"subscriptionPath": "Chemin d'abonnement",
|
||||
"subscriptionPathDescription": "Utilisé pour l'abonnement ; assurez-vous de redémarrer le système après modification pour des performances optimales",
|
||||
"subscriptionPathPlaceholder": "Entrez",
|
||||
"updateSuccess": "Mise à jour réussie",
|
||||
"wildcardResolution": "Résolution générique",
|
||||
"wildcardResolutionDescription": "Utilisé pour l'abonnement"
|
||||
},
|
||||
"confirm": "Confirmer",
|
||||
"confirmDelete": "Êtes-vous sûr de vouloir supprimer ?",
|
||||
"copy": "Copier",
|
||||
@ -94,6 +41,9 @@
|
||||
"name": "Nom",
|
||||
"noLimit": "Illimité",
|
||||
"noReset": "Pas de Réinitialisation",
|
||||
"node": "Nœud",
|
||||
"nodeGroup": "Groupe de Nœuds",
|
||||
"nodes": "Nœuds",
|
||||
"pricing": "Tarification",
|
||||
"purchaseWithDiscount": "Autoriser la Déduction",
|
||||
"purchaseWithDiscountDescription": "Activer ou désactiver la fonctionnalité de désabonnement. Après activation, le système effectuera un traitement de déduction selon les règles et proportions configurées, et la valeur restante sera retournée au solde.",
|
||||
@ -106,9 +56,6 @@
|
||||
"selectResetCycle": "Veuillez sélectionner un cycle de réinitialisation",
|
||||
"selectSubscribeGroup": "Veuillez sélectionner un groupe d'abonnement",
|
||||
"selectUnitTime": "Veuillez sélectionner l'unité de temps",
|
||||
"server": "Serveur",
|
||||
"serverGroup": "Groupe de serveurs",
|
||||
"servers": "Serveurs",
|
||||
"speedLimit": "Limite de vitesse ",
|
||||
"traffic": "Trafic",
|
||||
"unitPrice": "Prix unitaire",
|
||||
@ -150,8 +97,6 @@
|
||||
"subscribeGroup": "S'abonner au groupe",
|
||||
"tabs": {
|
||||
"subscribe": "S'abonner",
|
||||
"subscribeApp": "Configuration de l'application",
|
||||
"subscribeConfig": "Configuration de l'abonnement",
|
||||
"subscribeGroup": "Groupe d'abonnement"
|
||||
},
|
||||
"traffic": "trafic",
|
||||
|
||||
@ -1,183 +0,0 @@
|
||||
{
|
||||
"config": {
|
||||
"addTimeSlot": "Ajouter un créneau horaire",
|
||||
"communicationKey": "Clé de communication",
|
||||
"communicationKeyDescription": "Clé pour la communication des nœuds afin d'assurer la sécurité des données",
|
||||
"delete": "Supprimer",
|
||||
"dynamicMultiplier": "Multiplicateur dynamique",
|
||||
"dynamicMultiplierDescription": "Le multiplicateur dynamique fait référence au traitement des données poussées avec différents multiplicateurs pour différents nœuds pendant différentes périodes.",
|
||||
"endTime": "Heure de fin",
|
||||
"inputPlaceholder": "Entrer",
|
||||
"multiplier": "Multiplicateur",
|
||||
"nodePullInterval": "Intervalle de récupération des nœuds",
|
||||
"nodePullIntervalDescription": "Fréquence (en secondes) à laquelle les nœuds récupèrent les données du panneau",
|
||||
"nodePushInterval": "Intervalle de poussée des nœuds",
|
||||
"nodePushIntervalDescription": "Fréquence à laquelle les nœuds poussent les données vers le panneau",
|
||||
"reset": "Réinitialiser",
|
||||
"save": "Enregistrer",
|
||||
"saveSuccess": "Enregistrement réussi",
|
||||
"startTime": "Heure de début",
|
||||
"timeSlot": "Créneau horaire"
|
||||
},
|
||||
"group": {
|
||||
"actions": "Actions",
|
||||
"cancel": "Annuler",
|
||||
"confirm": "Confirmer",
|
||||
"confirmDelete": "Êtes-vous sûr de vouloir supprimer ?",
|
||||
"create": "Créer",
|
||||
"createNodeGroup": "Créer un groupe de nœuds",
|
||||
"createdSuccessfully": "Création réussie",
|
||||
"delete": "Supprimer",
|
||||
"deleteWarning": "Les données ne pourront pas être récupérées après suppression, veuillez procéder avec prudence.",
|
||||
"deletedSuccessfully": "Suppression réussie",
|
||||
"description": "Description",
|
||||
"edit": "Éditer",
|
||||
"editNodeGroup": "Éditer le groupe de nœuds",
|
||||
"name": "Nom",
|
||||
"title": "Liste des groupes de nœuds",
|
||||
"updatedAt": "Mis à jour à"
|
||||
},
|
||||
"groupForm": {
|
||||
"cancel": "Annuler",
|
||||
"confirm": "Confirmer",
|
||||
"description": "Description",
|
||||
"name": "Nom"
|
||||
},
|
||||
"node": {
|
||||
"abnormal": "Anormal",
|
||||
"actions": "Actions",
|
||||
"address": "Adresse",
|
||||
"all": "Tout",
|
||||
"basicInfo": "Informations de base",
|
||||
"cancel": "Annuler",
|
||||
"confirm": "Confirmer",
|
||||
"confirmDelete": "Êtes-vous sûr de vouloir supprimer ?",
|
||||
"copy": "Copier",
|
||||
"copySuccess": "Copié avec succès",
|
||||
"create": "Créer",
|
||||
"createNode": "Créer un nœud",
|
||||
"createSuccess": "Création réussie",
|
||||
"delete": "Supprimer",
|
||||
"deleteSuccess": "Suppression réussie",
|
||||
"deleteWarning": "Après suppression, les données ne pourront pas être récupérées. Veuillez procéder avec prudence.",
|
||||
"detail": "Détail",
|
||||
"disabled": "Désactivé",
|
||||
"disk": "Disque",
|
||||
"edit": "Éditer",
|
||||
"editNode": "Éditer le nœud",
|
||||
"enable": "Activer",
|
||||
"enabled": "Activé",
|
||||
"expireTime": "Temps d'expiration",
|
||||
"hide": "Cacher",
|
||||
"id": "ID",
|
||||
"ipAddresses": "Adresses IP",
|
||||
"lastUpdated": "Dernière mise à jour",
|
||||
"location": "Emplacement",
|
||||
"memory": "Mémoire",
|
||||
"name": "Nom",
|
||||
"noData": "--",
|
||||
"node": "Nœud",
|
||||
"nodeDetail": "Détails du nœud",
|
||||
"nodeGroup": "Groupe de nœuds",
|
||||
"nodeStatus": "État du nœud",
|
||||
"normal": "Normal",
|
||||
"onlineCount": "Nombre d'utilisateurs en ligne",
|
||||
"onlineUsers": "Utilisateurs en ligne",
|
||||
"protocol": "Protocole",
|
||||
"rate": "Taux",
|
||||
"relay": "Relais",
|
||||
"serverAddr": "Adresse du serveur",
|
||||
"speedLimit": "Limite de vitesse",
|
||||
"status": "Statut",
|
||||
"subscribeId": "ID de l'abonnement",
|
||||
"subscribeName": "Nom de l'abonnement",
|
||||
"subscription": "Abonnement",
|
||||
"tags": "Étiquettes",
|
||||
"trafficRatio": "Taux de trafic",
|
||||
"trafficUsage": "Utilisation du trafic",
|
||||
"type": "Type",
|
||||
"updateSuccess": "Mise à jour réussie",
|
||||
"updatedAt": "Date de mise à jour",
|
||||
"user": "Utilisateur",
|
||||
"userDetail": "Détails de l'utilisateur",
|
||||
"userId": "ID de l'utilisateur"
|
||||
},
|
||||
"nodeForm": {
|
||||
"allowInsecure": "Autoriser Insecure",
|
||||
"cancel": "Annuler",
|
||||
"city": "Ville",
|
||||
"confirm": "Confirmer",
|
||||
"congestionController": "Contrôleur de Congestion",
|
||||
"country": "Pays",
|
||||
"disableSni": "Désactiver SNI",
|
||||
"edit": "Modifier",
|
||||
"editSecurity": "Modifier la Configuration de Sécurité",
|
||||
"enableTLS": "Activer TLS",
|
||||
"encryptionMethod": "Méthode de Chiffrement",
|
||||
"fingerprint": "Empreinte",
|
||||
"flow": "Algorithme de Contrôle de Flux",
|
||||
"groupId": "Groupe de Nœuds",
|
||||
"hopInterval": "Intervalle de Saut",
|
||||
"hopPorts": "Ports de Saut",
|
||||
"hopPortsPlaceholder": "Séparez plusieurs ports par des virgules",
|
||||
"name": "Nom",
|
||||
"obfsPassword": "Mot de Passe d'Obfuscation",
|
||||
"obfsPasswordPlaceholder": "Laissez vide pour aucune obfuscation",
|
||||
"path": "Chemin",
|
||||
"pleaseSelect": "Veuillez Sélectionner",
|
||||
"port": "Port du Serveur",
|
||||
"protocol": "Protocole",
|
||||
"reduceRtt": "Réduire RTT",
|
||||
"relayHost": "Hôte de Relais",
|
||||
"relayMode": "Mode de Relais",
|
||||
"relayPort": "Port de Relais",
|
||||
"relayPrefix": "Préfixe de Relais",
|
||||
"remarks": "Remarques",
|
||||
"security": "Sécurité",
|
||||
"securityConfig": "Configuration de Sécurité",
|
||||
"selectEncryptionMethod": "Sélectionner la Méthode de Chiffrement",
|
||||
"selectNodeGroup": "Sélectionner le Groupe de Nœuds",
|
||||
"selectProtocol": "Sélectionner le Protocole",
|
||||
"selectRelayMode": "Sélectionner le Mode de Relais",
|
||||
"serverAddr": "Adresse du Serveur",
|
||||
"serverKey": "Clé du Serveur",
|
||||
"serverName": "Nom du Service",
|
||||
"speedLimit": "Limite de Vitesse",
|
||||
"speedLimitPlaceholder": "Illimité",
|
||||
"tags": "Étiquettes",
|
||||
"tagsPlaceholder": "Utilisez Entrée ou virgule (,) pour entrer plusieurs étiquettes",
|
||||
"trafficRatio": "Taux de Trafic",
|
||||
"transport": "Configuration du Protocole de Transport",
|
||||
"transportConfig": "Configuration du Protocole de Transport",
|
||||
"transportHost": "Adresse du Serveur de Transport",
|
||||
"transportPath": "Chemin de Transport",
|
||||
"transportServerName": "Nom du Serveur de Transport",
|
||||
"udpRelayMode": "Mode de Relais UDP"
|
||||
},
|
||||
"relayModeOptions": {
|
||||
"all": "Tous",
|
||||
"none": "Aucun",
|
||||
"random": "Aléatoire"
|
||||
},
|
||||
"securityConfig": {
|
||||
"fingerprint": "Empreinte",
|
||||
"privateKey": "Clé Privée",
|
||||
"privateKeyPlaceholder": "Laissez vide pour auto-génération",
|
||||
"publicKey": "Clé Publique",
|
||||
"publicKeyPlaceholder": "Laissez vide pour auto-génération",
|
||||
"serverAddress": "Adresse du Serveur",
|
||||
"serverAddressPlaceholder": "Adresse cible REALITY, par défaut utilisant SNI",
|
||||
"serverName": "Nom du Serveur (SNI)",
|
||||
"serverNamePlaceholder": "REQUIRED REALITY, cohérent avec le backend",
|
||||
"serverPort": "Port du Serveur",
|
||||
"serverPortPlaceholder": "Port cible REALITY, par défaut 443",
|
||||
"shortId": "ID Court",
|
||||
"shortIdPlaceholder": "Laissez vide pour auto-génération",
|
||||
"sni": "Indication de Nom de Serveur (SNI)"
|
||||
},
|
||||
"tabs": {
|
||||
"node": "Nœud",
|
||||
"nodeConfig": "Configuration du nœud",
|
||||
"nodeGroup": "Groupe de nœuds"
|
||||
}
|
||||
}
|
||||
101
apps/admin/locales/fr-FR/servers.json
Normal file
101
apps/admin/locales/fr-FR/servers.json
Normal file
@ -0,0 +1,101 @@
|
||||
{
|
||||
"address": "Adresse",
|
||||
"address_placeholder": "Adresse du serveur",
|
||||
"cancel": "Annuler",
|
||||
"city": "Ville",
|
||||
"config": {
|
||||
"actions": {
|
||||
"cancel": "Annuler",
|
||||
"save": "Enregistrer"
|
||||
},
|
||||
"communicationKey": "Clé de communication",
|
||||
"communicationKeyDescription": "Utilisé pour l'authentification du nœud.",
|
||||
"description": "Gérer les clés de communication du nœud, les intervalles de tirage/poussée et les multiplicateurs dynamiques.",
|
||||
"dynamicMultiplier": "Multiplicateur dynamique",
|
||||
"dynamicMultiplierDescription": "Définir des créneaux horaires et des multiplicateurs pour ajuster le comptage du trafic.",
|
||||
"endTime": "Heure de fin",
|
||||
"inputPlaceholder": "Veuillez entrer",
|
||||
"multiplier": "Multiplicateur",
|
||||
"nodePullInterval": "Intervalle de tirage du nœud",
|
||||
"nodePullIntervalDescription": "À quelle fréquence le nœud tire la configuration (secondes).",
|
||||
"nodePushInterval": "Intervalle de poussée du nœud",
|
||||
"nodePushIntervalDescription": "À quelle fréquence le nœud pousse les statistiques (secondes).",
|
||||
"reset": "Réinitialiser",
|
||||
"save": "Enregistrer",
|
||||
"saveSuccess": "Enregistré avec succès",
|
||||
"startTime": "Heure de début",
|
||||
"timeSlot": "Créneau horaire",
|
||||
"title": "Configuration du nœud"
|
||||
},
|
||||
"confirm": "Confirmer",
|
||||
"confirmDeleteDesc": "Cette action ne peut pas être annulée.",
|
||||
"confirmDeleteTitle": "Supprimer ce serveur ?",
|
||||
"congestion_controller": "Contrôleur de congestion",
|
||||
"copied": "Copié",
|
||||
"copy": "Copier",
|
||||
"country": "Pays",
|
||||
"cpu": "CPU",
|
||||
"create": "Créer",
|
||||
"created": "Créé avec succès",
|
||||
"delete": "Supprimer",
|
||||
"deleted": "Supprimé avec succès",
|
||||
"disable_sni": "Désactiver SNI",
|
||||
"disk": "Disque",
|
||||
"drawerCreateTitle": "Créer un serveur",
|
||||
"drawerEditTitle": "Modifier le serveur",
|
||||
"edit": "Modifier",
|
||||
"enabled": "Activé",
|
||||
"encryption_method": "Méthode de chiffrement",
|
||||
"expireTime": "Temps d'expiration",
|
||||
"expired": "Expiré",
|
||||
"flow": "Flux",
|
||||
"hop_interval": "Intervalle de saut",
|
||||
"hop_ports": "Ports de saut",
|
||||
"hop_ports_placeholder": "ex. 1-65535",
|
||||
"host": "Hôte",
|
||||
"id": "ID",
|
||||
"ipAddresses": "Adresses IP",
|
||||
"memory": "Mémoire",
|
||||
"name": "Nom",
|
||||
"noData": "Aucune donnée",
|
||||
"notAvailable": "N/A",
|
||||
"obfs_password": "Mot de passe d'obfuscation",
|
||||
"obfs_password_placeholder": "Entrez le mot de passe d'obfuscation",
|
||||
"offline": "Hors ligne",
|
||||
"online": "En ligne",
|
||||
"onlineUsers": "Utilisateurs en ligne",
|
||||
"pageTitle": "Serveurs",
|
||||
"path": "Chemin",
|
||||
"please_select": "Veuillez sélectionner",
|
||||
"port": "Port",
|
||||
"protocols": "Protocoles",
|
||||
"reduce_rtt": "Réduire le RTT",
|
||||
"security_allow_insecure": "Autoriser l'insecure",
|
||||
"security_fingerprint": "Empreinte digitale",
|
||||
"security_private_key": "Clé privée de réalité",
|
||||
"security_private_key_placeholder": "Entrez la clé privée",
|
||||
"security_public_key": "Clé publique de réalité",
|
||||
"security_public_key_placeholder": "Entrez la clé publique",
|
||||
"security_server_address": "Adresse du serveur de réalité",
|
||||
"security_server_address_placeholder": "ex. 1.2.3.4 ou domaine",
|
||||
"security_server_port": "Port du serveur de réalité",
|
||||
"security_short_id": "ID court de réalité",
|
||||
"security_short_id_placeholder": "Chaîne hexadécimale (jusqu'à 16 caractères)",
|
||||
"security_sni": "SNI",
|
||||
"security_title": "Sécurité",
|
||||
"select_encryption_method": "Sélectionner la méthode de chiffrement",
|
||||
"server_key": "Clé du serveur",
|
||||
"service_name": "Nom du service",
|
||||
"status": "Statut",
|
||||
"subscribeId": "ID d'abonnement",
|
||||
"subscription": "Abonnement",
|
||||
"traffic": "Trafic",
|
||||
"traffic_ratio": "Multiplicateur",
|
||||
"transport_title": "Transport",
|
||||
"udp_relay_mode": "Mode de relais UDP",
|
||||
"unitSecondsShort": "S",
|
||||
"unlimited": "Illimité",
|
||||
"updated": "Mis à jour avec succès",
|
||||
"user": "Utilisateur",
|
||||
"validation_failed": "Échec de la validation. Veuillez vérifier le formulaire."
|
||||
}
|
||||
@ -1,27 +1,36 @@
|
||||
{
|
||||
"ADS Config": "एडीएस कॉन्फ़िग",
|
||||
"Announcement Management": "घोषणा प्रबंधन",
|
||||
"Application Management": "ऐप्लिकेशन प्रबंधन",
|
||||
"Auth Control": "प्रमाणिकरण नियंत्रण",
|
||||
"Balance": "बैलेंस",
|
||||
"Commerce": "वाणिज्य",
|
||||
"Commission": "आयोग",
|
||||
"Coupon Management": "कूपन प्रबंधन",
|
||||
"Dashboard": "डैशबोर्ड",
|
||||
"Document Management": "दस्तावेज़ प्रबंधन",
|
||||
"Finance": "वित्त",
|
||||
"Email": "ईमेल",
|
||||
"Gift": "उपहार",
|
||||
"Login": "लॉगिन",
|
||||
"Logs & Analytics": "लॉग और विश्लेषण",
|
||||
"Maintenance": "रखरखाव",
|
||||
"Marketing Management": "मार्केटिंग प्रबंधन",
|
||||
"Node Management": "नोड प्रबंधन",
|
||||
"Order Management": "ऑर्डर प्रबंधन",
|
||||
"Payment Config": "भुगतान कॉन्फ़िगरेशन",
|
||||
"Product Management": "उत्पाद प्रबंधन",
|
||||
"Protocol Management": "प्रोटोकॉल प्रबंधन",
|
||||
"Rule Management": "नियम प्रबंधन",
|
||||
"Server": "सर्वर",
|
||||
"Register": "पंजीकरण",
|
||||
"Reset Subscribe": "सदस्यता रीसेट करें",
|
||||
"SMS": "एसएमएस",
|
||||
"Server Management": "सर्वर प्रबंधन",
|
||||
"Settings": "सेटिंग्स",
|
||||
"Server Traffic": "सर्वर ट्रैफ़िक",
|
||||
"Subscribe": "सदस्यता लें",
|
||||
"Subscribe Config": "सदस्यता कॉन्फ़िगरेशन",
|
||||
"Subscribe Traffic": "सदस्यता ट्रैफ़िक",
|
||||
"System": "सिस्टम",
|
||||
"System Config": "सिस्टम कॉन्फ़िगरेशन",
|
||||
"System Management": "सिस्टम प्रबंधन",
|
||||
"System Tool": "सिस्टम उपकरण",
|
||||
"Ticket Management": "टिकट प्रबंधन",
|
||||
"User": "उपयोगकर्ता",
|
||||
"User Detail": "उपयोगकर्ता विवरण",
|
||||
"User Management": "उपयोगकर्ता प्रबंधन"
|
||||
"User Management": "उपयोगकर्ता प्रबंधन",
|
||||
"Users & Support": "उपयोगकर्ता और समर्थन"
|
||||
}
|
||||
|
||||
37
apps/admin/locales/hi-IN/nodes.json
Normal file
37
apps/admin/locales/hi-IN/nodes.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"address": "पता",
|
||||
"cancel": "रद्द करें",
|
||||
"confirm": "पुष्टि करें",
|
||||
"confirmDeleteDesc": "यह क्रिया पूर्ववत नहीं की जा सकती।",
|
||||
"confirmDeleteTitle": "क्या इस नोड को हटाएं?",
|
||||
"copied": "कॉपी किया गया",
|
||||
"copy": "कॉपी करें",
|
||||
"create": "बनाएं",
|
||||
"created": "बनाया गया",
|
||||
"delete": "हटाएं",
|
||||
"deleted": "हटाया गया",
|
||||
"drawerCreateTitle": "नोड बनाएं",
|
||||
"drawerEditTitle": "नोड संपादित करें",
|
||||
"edit": "संपादित करें",
|
||||
"enabled": "सक्षम",
|
||||
"enabled_off": "अक्षम",
|
||||
"enabled_on": "सक्षम",
|
||||
"errors": {
|
||||
"nameRequired": "कृपया एक नाम दर्ज करें",
|
||||
"portRange": "पोर्ट 1 और 65535 के बीच होना चाहिए",
|
||||
"protocolRequired": "कृपया एक प्रोटोकॉल चुनें",
|
||||
"serverAddrRequired": "कृपया एक प्रविष्टि पता दर्ज करें",
|
||||
"serverRequired": "कृपया एक सर्वर चुनें"
|
||||
},
|
||||
"name": "नाम",
|
||||
"pageTitle": "नोड्स",
|
||||
"port": "पोर्ट",
|
||||
"protocol": "प्रोटोकॉल",
|
||||
"select_protocol": "प्रोटोकॉल चुनें…",
|
||||
"select_server": "सर्वर चुनें…",
|
||||
"server": "सर्वर",
|
||||
"tags": "टैग",
|
||||
"tags_description": "अनुमति समूह टैग (योजना बाइंडिंग और वितरण नीतियों सहित)।",
|
||||
"tags_placeholder": "एकाधिक टैग जोड़ने के लिए Enter या कॉमा (,) का उपयोग करें",
|
||||
"updated": "अपडेट किया गया"
|
||||
}
|
||||
@ -1,59 +1,6 @@
|
||||
{
|
||||
"actions": "क्रियाएँ",
|
||||
"app": {
|
||||
"appDownloadURL": "ऐप डाउनलोड URL",
|
||||
"appIcon": "ऐप आइकन",
|
||||
"appList": "ऐप सूची",
|
||||
"appName": "ऐप का नाम",
|
||||
"backupDomains": "बैकअप डोमेन सूची",
|
||||
"backupDomainsDescription": "डोमेन समाधान के लिए बैकअप डोमेन सूची, प्रत्येक पंक्ति में एक डोमेन",
|
||||
"batchDelete": "बैच हटाएं",
|
||||
"cancel": "रद्द करें",
|
||||
"communicationKey": "संचार कुंजी",
|
||||
"communicationKeyDescription": "क्लाइंट संचार के लिए उपयोग की जाने वाली कुंजी",
|
||||
"config": "कॉन्फ़िग",
|
||||
"configApp": "ऐप कॉन्फ़िगरेशन",
|
||||
"confirm": "पुष्टि करें",
|
||||
"confirmDelete": "हटाने की पुष्टि करें",
|
||||
"create": "बनाएं",
|
||||
"createApp": "ऐप बनाएं",
|
||||
"createSuccess": "सफलतापूर्वक बनाया गया",
|
||||
"defaultVersion": "डिफ़ॉल्ट",
|
||||
"delete": "हटाएं",
|
||||
"deleteWarning": "यह क्रिया पूर्ववत नहीं की जा सकती",
|
||||
"describeDescription": "एप्लिकेशन का वर्णन करने के लिए उपयोग किया जाता है, ऐप सूची में प्रदर्शित",
|
||||
"description": "विवरण",
|
||||
"downloadLink": "डाउनलोड लिंक",
|
||||
"edit": "संपादित करें",
|
||||
"editApp": "ऐप संपादित करें",
|
||||
"encryption": "एन्क्रिप्शन विधि",
|
||||
"encryptionDescription": "क्लाइंट संचार के लिए एन्क्रिप्शन विधि चुनें। यदि चुना गया, तो क्लाइंट इस विधि का उपयोग सर्वर के साथ संचार करने के लिए करेगा",
|
||||
"nameDescription": "एप्लिकेशन का नाम, ऐप सूची में प्रदर्शित",
|
||||
"platform": "प्लेटफ़ॉर्म",
|
||||
"selectApp": "ऐप चुनें",
|
||||
"selectAppDescription": "कॉन्फ़िगर करने के लिए ऐप चुनें, सभी सेटिंग्स चयनित ऐप पर लागू होंगी",
|
||||
"startupPicture": "स्टार्टअप चित्र",
|
||||
"startupPictureDescription": "स्टार्टअप चित्र, नेटवर्क और स्थानीय छवियों का समर्थन करता है। नेटवर्क छवियों के लिए, कृपया पूरी छवि URL दर्ज करें",
|
||||
"startupPicturePreview": "स्टार्टअप चित्र पूर्वावलोकन",
|
||||
"startupPictureSkip": "स्टार्टअप चित्र छोड़ने का समय",
|
||||
"startupPictureSkipDescription": "स्टार्टअप चित्र प्रदर्शन समय सेकंड में, प्रदर्शित न करने के लिए 0 दर्ज करें",
|
||||
"subscriptionProtocol": "सदस्यता प्रोटोकॉल",
|
||||
"updateSuccess": "सफलतापूर्वक अपडेट किया गया",
|
||||
"version": "संस्करण"
|
||||
},
|
||||
"cancel": "रद्द करें",
|
||||
"config": {
|
||||
"singleSubscriptionMode": "एकल सदस्यता मोड",
|
||||
"subscriptionDomain": "सदस्यता डोमेन",
|
||||
"subscriptionDomainDescription": "सदस्यता के लिए उपयोग किया जाता है; साइट डोमेन का उपयोग करने के लिए खाली छोड़ दें",
|
||||
"subscriptionDomainPlaceholder": "सदस्यता डोमेन दर्ज करें, एक प्रति पंक्ति",
|
||||
"subscriptionPath": "सदस्यता पथ",
|
||||
"subscriptionPathDescription": "सदस्यता के लिए उपयोग किया जाता है; इष्टतम प्रदर्शन के लिए संशोधन के बाद सिस्टम को पुनः आरंभ करना सुनिश्चित करें",
|
||||
"subscriptionPathPlaceholder": "दर्ज करें",
|
||||
"updateSuccess": "सफलता से अपडेट किया गया",
|
||||
"wildcardResolution": "वाइल्डकार्ड समाधान",
|
||||
"wildcardResolutionDescription": "सदस्यता के लिए उपयोग किया जाता है"
|
||||
},
|
||||
"confirm": "पुष्टि करें",
|
||||
"confirmDelete": "क्या आप वाकई हटाना चाहते हैं?",
|
||||
"copy": "कॉपी",
|
||||
@ -94,6 +41,9 @@
|
||||
"name": "नाम",
|
||||
"noLimit": "कोई सीमा नहीं",
|
||||
"noReset": "कोई रीसेट नहीं",
|
||||
"node": "नोड",
|
||||
"nodeGroup": "नोड समूह",
|
||||
"nodes": "नोड्स",
|
||||
"pricing": "मूल्य निर्धारण",
|
||||
"purchaseWithDiscount": "कटौती की अनुमति दें",
|
||||
"purchaseWithDiscountDescription": "अनसब्सक्राइब कार्यक्षमता को सक्षम या अक्षम करें। सक्रियण के बाद, सिस्टम कॉन्फ़िगर किए गए नियमों और अनुपातों के अनुसार कटौती प्रसंस्करण करेगा, और शेष मूल्य को बैलेंस में वापस कर दिया जाएगा।",
|
||||
@ -106,9 +56,6 @@
|
||||
"selectResetCycle": "कृपया एक रीसेट चक्र चुनें",
|
||||
"selectSubscribeGroup": "कृपया सदस्यता समूह चुनें",
|
||||
"selectUnitTime": "कृपया इकाई समय चुनें",
|
||||
"server": "सर्वर",
|
||||
"serverGroup": "सर्वर समूह",
|
||||
"servers": "सर्वर",
|
||||
"speedLimit": "गति सीमा ",
|
||||
"traffic": "ट्रैफिक",
|
||||
"unitPrice": "इकाई मूल्य",
|
||||
@ -150,8 +97,6 @@
|
||||
"subscribeGroup": "सदस्यता समूह",
|
||||
"tabs": {
|
||||
"subscribe": "सदस्यता लें",
|
||||
"subscribeApp": "ऐप कॉन्फ़िगरेशन",
|
||||
"subscribeConfig": "सदस्यता कॉन्फ़िगरेशन",
|
||||
"subscribeGroup": "समूह सदस्यता"
|
||||
},
|
||||
"traffic": "ट्रैफिक",
|
||||
|
||||
@ -1,183 +0,0 @@
|
||||
{
|
||||
"config": {
|
||||
"addTimeSlot": "समय स्लॉट जोड़ें",
|
||||
"communicationKey": "संचार कुंजी",
|
||||
"communicationKeyDescription": "डेटा सुरक्षा सुनिश्चित करने के लिए नोड संचार की कुंजी",
|
||||
"delete": "हटाएं",
|
||||
"dynamicMultiplier": "गतिशील गुणक",
|
||||
"dynamicMultiplierDescription": "गतिशील गुणक का अर्थ है विभिन्न समय अवधियों के दौरान विभिन्न नोड्स के लिए विभिन्न गुणकों के साथ धकेले गए डेटा को संसाधित करना।",
|
||||
"endTime": "समाप्ति समय",
|
||||
"inputPlaceholder": "दर्ज करें",
|
||||
"multiplier": "गुणक",
|
||||
"nodePullInterval": "नोड पुल अंतराल",
|
||||
"nodePullIntervalDescription": "पैनल से डेटा प्राप्त करने के लिए नोड्स की आवृत्ति (सेकंड में)",
|
||||
"nodePushInterval": "नोड पुश अंतराल",
|
||||
"nodePushIntervalDescription": "पैनल को डेटा धकेलने के लिए नोड्स की आवृत्ति",
|
||||
"reset": "रीसेट",
|
||||
"save": "सहेजें",
|
||||
"saveSuccess": "सहेजना सफल",
|
||||
"startTime": "प्रारंभ समय",
|
||||
"timeSlot": "समय स्लॉट"
|
||||
},
|
||||
"group": {
|
||||
"actions": "क्रियाएँ",
|
||||
"cancel": "रद्द करें",
|
||||
"confirm": "पुष्टि करें",
|
||||
"confirmDelete": "क्या आप वाकई हटाना चाहते हैं?",
|
||||
"create": "बनाएँ",
|
||||
"createNodeGroup": "नोड समूह बनाएं",
|
||||
"createdSuccessfully": "सफलतापूर्वक बनाया गया",
|
||||
"delete": "हटाएं",
|
||||
"deleteWarning": "हटाने के बाद डेटा पुनर्प्राप्त नहीं किया जा सकेगा, कृपया सावधानीपूर्वक कार्य करें।",
|
||||
"deletedSuccessfully": "सफलतापूर्वक हटाया गया",
|
||||
"description": "विवरण",
|
||||
"edit": "संपादित करें",
|
||||
"editNodeGroup": "नोड समूह संपादित करें",
|
||||
"name": "नाम",
|
||||
"title": "नोड समूह सूची",
|
||||
"updatedAt": "अद्यतन समय"
|
||||
},
|
||||
"groupForm": {
|
||||
"cancel": "रद्द करें",
|
||||
"confirm": "पुष्टि करें",
|
||||
"description": "विवरण",
|
||||
"name": "नाम"
|
||||
},
|
||||
"node": {
|
||||
"abnormal": "असामान्य",
|
||||
"actions": "क्रियाएँ",
|
||||
"address": "पता",
|
||||
"all": "सभी",
|
||||
"basicInfo": "बुनियादी जानकारी",
|
||||
"cancel": "रद्द करें",
|
||||
"confirm": "पुष्टि करें",
|
||||
"confirmDelete": "क्या आप वाकई हटाना चाहते हैं?",
|
||||
"copy": "कॉपी करें",
|
||||
"copySuccess": "सफलतापूर्वक कॉपी किया गया",
|
||||
"create": "बनाएँ",
|
||||
"createNode": "नोड बनाएं",
|
||||
"createSuccess": "सफलतापूर्वक बनाया गया",
|
||||
"delete": "हटाएं",
|
||||
"deleteSuccess": "सफलतापूर्वक हटाया गया",
|
||||
"deleteWarning": "हटाने के बाद, डेटा पुनर्प्राप्त नहीं किया जा सकेगा। कृपया सावधानी से कार्य करें।",
|
||||
"detail": "विवरण",
|
||||
"disabled": "अक्षम",
|
||||
"disk": "डिस्क",
|
||||
"edit": "संपादित करें",
|
||||
"editNode": "नोड संपादित करें",
|
||||
"enable": "सक्रिय करें",
|
||||
"enabled": "सक्षम",
|
||||
"expireTime": "समाप्ति समय",
|
||||
"hide": "छिपाएँ",
|
||||
"id": "आईडी",
|
||||
"ipAddresses": "आईपी पते",
|
||||
"lastUpdated": "अंतिम अपडेट",
|
||||
"location": "स्थान",
|
||||
"memory": "मेमोरी",
|
||||
"name": "नाम",
|
||||
"noData": "--",
|
||||
"node": "नोड",
|
||||
"nodeDetail": "नोड विवरण",
|
||||
"nodeGroup": "नोड समूह",
|
||||
"nodeStatus": "नोड स्थिति",
|
||||
"normal": "सामान्य",
|
||||
"onlineCount": "ऑनलाइन संख्या",
|
||||
"onlineUsers": "ऑनलाइन उपयोगकर्ता",
|
||||
"protocol": "प्रोटोकॉल",
|
||||
"rate": "दर",
|
||||
"relay": "रिले",
|
||||
"serverAddr": "सर्वर पता",
|
||||
"speedLimit": "गति सीमा",
|
||||
"status": "स्थिति",
|
||||
"subscribeId": "सदस्यता आईडी",
|
||||
"subscribeName": "सदस्यता नाम",
|
||||
"subscription": "सदस्यता",
|
||||
"tags": "टैग्स",
|
||||
"trafficRatio": "ट्रैफिक दर",
|
||||
"trafficUsage": "ट्रैफ़िक उपयोग",
|
||||
"type": "प्रकार",
|
||||
"updateSuccess": "सफलतापूर्वक अपडेट किया गया",
|
||||
"updatedAt": "अपडेट समय",
|
||||
"user": "उपयोगकर्ता",
|
||||
"userDetail": "उपयोगकर्ता विवरण",
|
||||
"userId": "उपयोगकर्ता आईडी"
|
||||
},
|
||||
"nodeForm": {
|
||||
"allowInsecure": "असुरक्षित की अनुमति दें",
|
||||
"cancel": "रद्द करें",
|
||||
"city": "शहर",
|
||||
"confirm": "पुष्टि करें",
|
||||
"congestionController": "भीड़ नियंत्रण",
|
||||
"country": "देश",
|
||||
"disableSni": "SNI बंद करें",
|
||||
"edit": "संपादित करें",
|
||||
"editSecurity": "सुरक्षा कॉन्फ़िगरेशन संपादित करें",
|
||||
"enableTLS": "TLS सक्षम करें",
|
||||
"encryptionMethod": "एन्क्रिप्शन विधि",
|
||||
"fingerprint": "फिंगरप्रिंट",
|
||||
"flow": "प्रवाह नियंत्रण एल्गोरिदम",
|
||||
"groupId": "नोड समूह",
|
||||
"hopInterval": "हॉप अंतराल",
|
||||
"hopPorts": "हॉप पोर्ट",
|
||||
"hopPortsPlaceholder": "कई पोर्ट को अल्पविराम से अलग करें",
|
||||
"name": "नाम",
|
||||
"obfsPassword": "ओबफस्केशन पासवर्ड",
|
||||
"obfsPasswordPlaceholder": "ओबफस्केशन के लिए खाली छोड़ें",
|
||||
"path": "पथ",
|
||||
"pleaseSelect": "कृपया चुनें",
|
||||
"port": "सर्वर पोर्ट",
|
||||
"protocol": "प्रोटोकॉल",
|
||||
"reduceRtt": "RTT कम करें",
|
||||
"relayHost": "रिले होस्ट",
|
||||
"relayMode": "रिले मोड",
|
||||
"relayPort": "रिले पोर्ट",
|
||||
"relayPrefix": "रिले उपसर्ग",
|
||||
"remarks": "टिप्पणियाँ",
|
||||
"security": "सुरक्षा",
|
||||
"securityConfig": "सुरक्षा कॉन्फ़िगरेशन",
|
||||
"selectEncryptionMethod": "एन्क्रिप्शन विधि चुनें",
|
||||
"selectNodeGroup": "नोड समूह चुनें",
|
||||
"selectProtocol": "प्रोटोकॉल चुनें",
|
||||
"selectRelayMode": "रिले मोड चुनें",
|
||||
"serverAddr": "सर्वर पता",
|
||||
"serverKey": "सर्वर कुंजी",
|
||||
"serverName": "सेवा नाम",
|
||||
"speedLimit": "गति सीमा",
|
||||
"speedLimitPlaceholder": "असीमित",
|
||||
"tags": "टैग",
|
||||
"tagsPlaceholder": "कई टैग दर्ज करने के लिए Enter या अल्पविराम (,) का उपयोग करें",
|
||||
"trafficRatio": "ट्रैफ़िक दर",
|
||||
"transport": "परिवहन प्रोटोकॉल कॉन्फ़िगरेशन",
|
||||
"transportConfig": "परिवहन प्रोटोकॉल कॉन्फ़िगरेशन",
|
||||
"transportHost": "परिवहन सर्वर पता",
|
||||
"transportPath": "परिवहन पथ",
|
||||
"transportServerName": "परिवहन सर्वर नाम",
|
||||
"udpRelayMode": "UDP रिले मोड"
|
||||
},
|
||||
"relayModeOptions": {
|
||||
"all": "सभी",
|
||||
"none": "कोई नहीं",
|
||||
"random": "यादृच्छिक"
|
||||
},
|
||||
"securityConfig": {
|
||||
"fingerprint": "फिंगरप्रिंट",
|
||||
"privateKey": "निजी कुंजी",
|
||||
"privateKeyPlaceholder": "स्वतः उत्पन्न करने के लिए खाली छोड़ें",
|
||||
"publicKey": "सार्वजनिक कुंजी",
|
||||
"publicKeyPlaceholder": "स्वतः उत्पन्न करने के लिए खाली छोड़ें",
|
||||
"serverAddress": "सर्वर पता",
|
||||
"serverAddressPlaceholder": "REALITY लक्ष्य पता, डिफ़ॉल्ट रूप से SNI का उपयोग करें",
|
||||
"serverName": "सर्वर नाम (SNI)",
|
||||
"serverNamePlaceholder": "REALITY आवश्यक, बैकएंड के साथ संगत",
|
||||
"serverPort": "सर्वर पोर्ट",
|
||||
"serverPortPlaceholder": "REALITY लक्ष्य पोर्ट, डिफ़ॉल्ट 443",
|
||||
"shortId": "संक्षिप्त आईडी",
|
||||
"shortIdPlaceholder": "स्वतः उत्पन्न करने के लिए खाली छोड़ें",
|
||||
"sni": "सर्वर नाम संकेत (SNI)"
|
||||
},
|
||||
"tabs": {
|
||||
"node": "नोड",
|
||||
"nodeConfig": "नोड कॉन्फ़िगरेशन",
|
||||
"nodeGroup": "नोड समूह"
|
||||
}
|
||||
}
|
||||
101
apps/admin/locales/hi-IN/servers.json
Normal file
101
apps/admin/locales/hi-IN/servers.json
Normal file
@ -0,0 +1,101 @@
|
||||
{
|
||||
"address": "पता",
|
||||
"address_placeholder": "सर्वर का पता",
|
||||
"cancel": "रद्द करें",
|
||||
"city": "शहर",
|
||||
"config": {
|
||||
"actions": {
|
||||
"cancel": "रद्द करें",
|
||||
"save": "सहेजें"
|
||||
},
|
||||
"communicationKey": "संचार कुंजी",
|
||||
"communicationKeyDescription": "नोड प्रमाणीकरण के लिए उपयोग किया जाता है।",
|
||||
"description": "नोड संचार कुंजी, पुल/धक्का अंतराल, और गतिशील गुणांक प्रबंधित करें।",
|
||||
"dynamicMultiplier": "गतिशील गुणांक",
|
||||
"dynamicMultiplierDescription": "यातायात लेखांकन को समायोजित करने के लिए समय स्लॉट और गुणांक परिभाषित करें।",
|
||||
"endTime": "समाप्ति का समय",
|
||||
"inputPlaceholder": "कृपया दर्ज करें",
|
||||
"multiplier": "गुणांक",
|
||||
"nodePullInterval": "नोड पुल अंतराल",
|
||||
"nodePullIntervalDescription": "नोड कितनी बार कॉन्फ़िगरेशन खींचता है (सेकंड में)।",
|
||||
"nodePushInterval": "नोड धक्का अंतराल",
|
||||
"nodePushIntervalDescription": "नोड कितनी बार आँकड़े धकेलता है (सेकंड में)।",
|
||||
"reset": "रीसेट करें",
|
||||
"save": "सहेजें",
|
||||
"saveSuccess": "सफलता से सहेजा गया",
|
||||
"startTime": "शुरुआत का समय",
|
||||
"timeSlot": "समय स्लॉट",
|
||||
"title": "नोड कॉन्फ़िगरेशन"
|
||||
},
|
||||
"confirm": "पुष्टि करें",
|
||||
"confirmDeleteDesc": "यह क्रिया पूर्ववत नहीं की जा सकती।",
|
||||
"confirmDeleteTitle": "क्या इस सर्वर को हटाएं?",
|
||||
"congestion_controller": "भीड़ नियंत्रण",
|
||||
"copied": "कॉपी किया गया",
|
||||
"copy": "कॉपी करें",
|
||||
"country": "देश",
|
||||
"cpu": "सीपीयू",
|
||||
"create": "बनाएँ",
|
||||
"created": "सफलता से बनाया गया",
|
||||
"delete": "हटाएं",
|
||||
"deleted": "सफलता से हटाया गया",
|
||||
"disable_sni": "SNI अक्षम करें",
|
||||
"disk": "डिस्क",
|
||||
"drawerCreateTitle": "सर्वर बनाएं",
|
||||
"drawerEditTitle": "सर्वर संपादित करें",
|
||||
"edit": "संपादित करें",
|
||||
"enabled": "सक्षम",
|
||||
"encryption_method": "एन्क्रिप्शन विधि",
|
||||
"expireTime": "समाप्ति समय",
|
||||
"expired": "समय समाप्त",
|
||||
"flow": "प्रवाह",
|
||||
"hop_interval": "हॉप अंतराल",
|
||||
"hop_ports": "हॉप पोर्ट",
|
||||
"hop_ports_placeholder": "जैसे 1-65535",
|
||||
"host": "होस्ट",
|
||||
"id": "आईडी",
|
||||
"ipAddresses": "आईपी पते",
|
||||
"memory": "मेमोरी",
|
||||
"name": "नाम",
|
||||
"noData": "कोई डेटा नहीं",
|
||||
"notAvailable": "उपलब्ध नहीं",
|
||||
"obfs_password": "अवशोषण पासवर्ड",
|
||||
"obfs_password_placeholder": "अवशोषण पासवर्ड दर्ज करें",
|
||||
"offline": "ऑफलाइन",
|
||||
"online": "ऑनलाइन",
|
||||
"onlineUsers": "ऑनलाइन उपयोगकर्ता",
|
||||
"pageTitle": "सर्वर",
|
||||
"path": "पथ",
|
||||
"please_select": "कृपया चुनें",
|
||||
"port": "पोर्ट",
|
||||
"protocols": "प्रोटोकॉल",
|
||||
"reduce_rtt": "RTT कम करें",
|
||||
"security_allow_insecure": "असुरक्षित की अनुमति दें",
|
||||
"security_fingerprint": "फिंगरप्रिंट",
|
||||
"security_private_key": "वास्तविक निजी कुंजी",
|
||||
"security_private_key_placeholder": "निजी कुंजी दर्ज करें",
|
||||
"security_public_key": "वास्तविक सार्वजनिक कुंजी",
|
||||
"security_public_key_placeholder": "सार्वजनिक कुंजी दर्ज करें",
|
||||
"security_server_address": "वास्तविक सर्वर पता",
|
||||
"security_server_address_placeholder": "जैसे 1.2.3.4 या डोमेन",
|
||||
"security_server_port": "वास्तविक सर्वर पोर्ट",
|
||||
"security_short_id": "वास्तविक शॉर्ट आईडी",
|
||||
"security_short_id_placeholder": "हेक्स स्ट्रिंग (16 अक्षरों तक)",
|
||||
"security_sni": "SNI",
|
||||
"security_title": "सुरक्षा",
|
||||
"select_encryption_method": "एन्क्रिप्शन विधि चुनें",
|
||||
"server_key": "सर्वर कुंजी",
|
||||
"service_name": "सेवा का नाम",
|
||||
"status": "स्थिति",
|
||||
"subscribeId": "सदस्यता आईडी",
|
||||
"subscription": "सदस्यता",
|
||||
"traffic": "यातायात",
|
||||
"traffic_ratio": "गुणांक",
|
||||
"transport_title": "परिवहन",
|
||||
"udp_relay_mode": "UDP रिले मोड",
|
||||
"unitSecondsShort": "सेकंड",
|
||||
"unlimited": "असीमित",
|
||||
"updated": "सफलता से अपडेट किया गया",
|
||||
"user": "उपयोगकर्ता",
|
||||
"validation_failed": "मान्यता विफल। कृपया फॉर्म की जांच करें।"
|
||||
}
|
||||
@ -1,27 +1,36 @@
|
||||
{
|
||||
"ADS Config": "ADS konfiguráció",
|
||||
"Announcement Management": "Hirdetménykezelés",
|
||||
"Application Management": "Alkalmazáskezelés",
|
||||
"Auth Control": "Hitelesítési vezérlés",
|
||||
"Balance": "Egyenleg",
|
||||
"Commerce": "Kereskedelem",
|
||||
"Commission": "Bizottság",
|
||||
"Coupon Management": "Kuponkezelés",
|
||||
"Dashboard": "Irányítópult",
|
||||
"Document Management": "Dokumentumkezelés",
|
||||
"Finance": "Pénzügy",
|
||||
"Email": "Email",
|
||||
"Gift": "Ajándék",
|
||||
"Login": "Bejelentkezés",
|
||||
"Logs & Analytics": "Naplók és Elemzések",
|
||||
"Maintenance": "Karbantartás",
|
||||
"Marketing Management": "Marketing Menedzsment",
|
||||
"Node Management": "Csomópont Kezelés",
|
||||
"Order Management": "Rendeléskezelés",
|
||||
"Payment Config": "Fizetési beállítások",
|
||||
"Product Management": "Termékmenedzsment",
|
||||
"Protocol Management": "Protokollkezelés",
|
||||
"Rule Management": "Szabálykezelés",
|
||||
"Server": "Szolgáltatás",
|
||||
"Register": "Regisztráció",
|
||||
"Reset Subscribe": "Feliratkozás Visszaállítása",
|
||||
"SMS": "SMS",
|
||||
"Server Management": "Szerverkezelés",
|
||||
"Settings": "Beállítások",
|
||||
"Server Traffic": "Szerver Forgalom",
|
||||
"Subscribe": "Feliratkozás",
|
||||
"Subscribe Config": "Előfizetés Beállítás",
|
||||
"Subscribe Traffic": "Feliratkozás Forgalom",
|
||||
"System": "Rendszer",
|
||||
"System Config": "Rendszerkonfiguráció",
|
||||
"System Management": "Rendszerkezelés",
|
||||
"System Tool": "Rendszereszköz",
|
||||
"Ticket Management": "Jegykezelés",
|
||||
"User": "Felhasználó",
|
||||
"User Detail": "Felhasználói részletek",
|
||||
"User Management": "Felhasználókezelés"
|
||||
"User Management": "Felhasználókezelés",
|
||||
"Users & Support": "Felhasználók és Támogatás"
|
||||
}
|
||||
|
||||
37
apps/admin/locales/hu-HU/nodes.json
Normal file
37
apps/admin/locales/hu-HU/nodes.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"address": "Cím",
|
||||
"cancel": "Mégse",
|
||||
"confirm": "Megerősít",
|
||||
"confirmDeleteDesc": "Ez a művelet nem vonható vissza.",
|
||||
"confirmDeleteTitle": "Törölni szeretné ezt a csomópontot?",
|
||||
"copied": "Másolva",
|
||||
"copy": "Másolás",
|
||||
"create": "Létrehozás",
|
||||
"created": "Létrehozva",
|
||||
"delete": "Törlés",
|
||||
"deleted": "Törölve",
|
||||
"drawerCreateTitle": "Csomópont létrehozása",
|
||||
"drawerEditTitle": "Csomópont szerkesztése",
|
||||
"edit": "Szerkesztés",
|
||||
"enabled": "Engedélyezve",
|
||||
"enabled_off": "Letiltva",
|
||||
"enabled_on": "Engedélyezve",
|
||||
"errors": {
|
||||
"nameRequired": "Kérjük, adjon meg egy nevet",
|
||||
"portRange": "A portnak 1 és 65535 között kell lennie",
|
||||
"protocolRequired": "Kérjük, válasszon egy protokollt",
|
||||
"serverAddrRequired": "Kérjük, adjon meg egy belépési címet",
|
||||
"serverRequired": "Kérjük, válasszon egy szervert"
|
||||
},
|
||||
"name": "Név",
|
||||
"pageTitle": "Csomópontok",
|
||||
"port": "Port",
|
||||
"protocol": "Protokoll",
|
||||
"select_protocol": "Válassza ki a protokollt…",
|
||||
"select_server": "Válassza ki a szervert…",
|
||||
"server": "Szerver",
|
||||
"tags": "Címkék",
|
||||
"tags_description": "Engedélyezési csoportosító címke (beleértve a tervkötést és a szállítási irányelveket).",
|
||||
"tags_placeholder": "Több címke hozzáadásához használja az Entert vagy a vesszőt (,)",
|
||||
"updated": "Frissítve"
|
||||
}
|
||||
@ -1,59 +1,6 @@
|
||||
{
|
||||
"actions": "műveletek",
|
||||
"app": {
|
||||
"appDownloadURL": "Alkalmazás letöltési URL",
|
||||
"appIcon": "Alkalmazás ikon",
|
||||
"appList": "Alkalmazáslista",
|
||||
"appName": "Alkalmazás neve",
|
||||
"backupDomains": "Biztonsági tartománylista",
|
||||
"backupDomainsDescription": "Biztonsági tartománylista a tartomány feloldásához, soronként egy tartomány",
|
||||
"batchDelete": "Csoportos törlés",
|
||||
"cancel": "Mégse",
|
||||
"communicationKey": "Kommunikációs kulcs",
|
||||
"communicationKeyDescription": "Kulcs az ügyfélkommunikációhoz",
|
||||
"config": "Beállítás",
|
||||
"configApp": "Alkalmazás beállítása",
|
||||
"confirm": "Megerősítés",
|
||||
"confirmDelete": "Törlés megerősítése",
|
||||
"create": "Létrehozás",
|
||||
"createApp": "Alkalmazás létrehozása",
|
||||
"createSuccess": "Sikeresen létrehozva",
|
||||
"defaultVersion": "Alapértelmezett",
|
||||
"delete": "Törlés",
|
||||
"deleteWarning": "Ez a művelet nem vonható vissza",
|
||||
"describeDescription": "Az alkalmazás leírására szolgál, megjelenik az alkalmazáslistában",
|
||||
"description": "Leírás",
|
||||
"downloadLink": "Letöltési hivatkozás",
|
||||
"edit": "Szerkesztés",
|
||||
"editApp": "Alkalmazás szerkesztése",
|
||||
"encryption": "Titkosítási módszer",
|
||||
"encryptionDescription": "Válassza ki az ügyfélkommunikáció titkosítási módszerét. Ha kiválasztja, az ügyfél ezt a módszert fogja használni a szerverrel való kommunikációhoz",
|
||||
"nameDescription": "Alkalmazás neve, megjelenik az alkalmazáslistában",
|
||||
"platform": "Platform",
|
||||
"selectApp": "Alkalmazás kiválasztása",
|
||||
"selectAppDescription": "Válassza ki a konfigurálandó alkalmazást, az összes beállítás az adott alkalmazásra vonatkozik",
|
||||
"startupPicture": "Indító kép",
|
||||
"startupPictureDescription": "Indító kép, támogatja a hálózati és helyi képeket. Hálózati képek esetén kérjük, adja meg a teljes kép URL-jét",
|
||||
"startupPicturePreview": "Indító kép előnézete",
|
||||
"startupPictureSkip": "Indító kép kihagyási ideje",
|
||||
"startupPictureSkipDescription": "Indító kép megjelenítési ideje másodpercben, 0 megadása esetén nem jelenik meg",
|
||||
"subscriptionProtocol": "Előfizetési protokoll",
|
||||
"updateSuccess": "Sikeresen frissítve",
|
||||
"version": "Verzió"
|
||||
},
|
||||
"cancel": "Mégse",
|
||||
"config": {
|
||||
"singleSubscriptionMode": "Egyszeri Előfizetési Mód",
|
||||
"subscriptionDomain": "Előfizetési Tartomány",
|
||||
"subscriptionDomainDescription": "Előfizetéshez használatos; hagyja üresen a webhely tartományának használatához",
|
||||
"subscriptionDomainPlaceholder": "Adja meg az előfizetési tartományt, soronként egyet",
|
||||
"subscriptionPath": "Előfizetési Útvonal",
|
||||
"subscriptionPathDescription": "Előfizetéshez használatos; a módosítás után feltétlenül indítsa újra a rendszert az optimális teljesítmény érdekében",
|
||||
"subscriptionPathPlaceholder": "Adja meg",
|
||||
"updateSuccess": "Sikeresen frissítve",
|
||||
"wildcardResolution": "Joker Feloldás",
|
||||
"wildcardResolutionDescription": "Előfizetéshez használatos"
|
||||
},
|
||||
"confirm": "Megerősítés",
|
||||
"confirmDelete": "Biztosan törölni szeretné?",
|
||||
"copy": "Másolás",
|
||||
@ -94,6 +41,9 @@
|
||||
"name": "Név",
|
||||
"noLimit": "Korlátlan",
|
||||
"noReset": "Nincs Visszaállítás",
|
||||
"node": "Csomópont",
|
||||
"nodeGroup": "Csomópont Csoport",
|
||||
"nodes": "Csomópontok",
|
||||
"pricing": "Árazás",
|
||||
"purchaseWithDiscount": "Levonás Engedélyezése",
|
||||
"purchaseWithDiscountDescription": "Leiratkozási funkció engedélyezése vagy letiltása. Aktiválás után a rendszer a beállított szabályok és arányok szerint végzi el a levonási feldolgozást, és a fennmaradó értéket visszatéríti az egyenlegre.",
|
||||
@ -106,9 +56,6 @@
|
||||
"selectResetCycle": "Kérjük, válasszon visszaállítási ciklust",
|
||||
"selectSubscribeGroup": "Kérjük, válassza ki az előfizetési csoportot",
|
||||
"selectUnitTime": "Kérjük, válassza ki az időegységet",
|
||||
"server": "Szolgáltatás",
|
||||
"serverGroup": "Szolgáltatáscsoport",
|
||||
"servers": "Szerverek",
|
||||
"speedLimit": "Sebességkorlát ",
|
||||
"traffic": "Forgalom",
|
||||
"unitPrice": "Egységár",
|
||||
@ -150,8 +97,6 @@
|
||||
"subscribeGroup": "Feliratkozási csoport",
|
||||
"tabs": {
|
||||
"subscribe": "Feliratkozás",
|
||||
"subscribeApp": "Alkalmazás konfiguráció",
|
||||
"subscribeConfig": "Előfizetés konfiguráció",
|
||||
"subscribeGroup": "Feliratkozási csoport"
|
||||
},
|
||||
"traffic": "forgalom",
|
||||
|
||||
@ -1,183 +0,0 @@
|
||||
{
|
||||
"config": {
|
||||
"addTimeSlot": "Idősáv hozzáadása",
|
||||
"communicationKey": "Kommunikációs kulcs",
|
||||
"communicationKeyDescription": "Kulcs a csomópontok közötti kommunikációhoz az adatok biztonságának biztosítása érdekében",
|
||||
"delete": "Törlés",
|
||||
"dynamicMultiplier": "Dinamikus szorzó",
|
||||
"dynamicMultiplierDescription": "A dinamikus szorzó azt jelenti, hogy a különböző csomópontok különböző időszakokban különböző szorzókkal dolgozzák fel a továbbított adatokat.",
|
||||
"endTime": "Befejezési idő",
|
||||
"inputPlaceholder": "Adja meg",
|
||||
"multiplier": "Szorzó",
|
||||
"nodePullInterval": "Csomópont lehívási intervallum",
|
||||
"nodePullIntervalDescription": "Gyakoriság (másodpercben), amellyel a csomópontok adatokat kérnek le a panelről",
|
||||
"nodePushInterval": "Csomópont feltöltési intervallum",
|
||||
"nodePushIntervalDescription": "Gyakoriság, amellyel a csomópontok adatokat küldenek a panelre",
|
||||
"reset": "Visszaállítás",
|
||||
"save": "Mentés",
|
||||
"saveSuccess": "Sikeres mentés",
|
||||
"startTime": "Kezdési idő",
|
||||
"timeSlot": "Idősáv"
|
||||
},
|
||||
"group": {
|
||||
"actions": "Műveletek",
|
||||
"cancel": "Mégse",
|
||||
"confirm": "Megerősít",
|
||||
"confirmDelete": "Biztosan törölni szeretné?",
|
||||
"create": "Létrehozás",
|
||||
"createNodeGroup": "Csomópontcsoport létrehozása",
|
||||
"createdSuccessfully": "Sikeres létrehozás",
|
||||
"delete": "Törlés",
|
||||
"deleteWarning": "A törlés után az adatok nem állíthatók vissza, kérjük, járjon el körültekintően.",
|
||||
"deletedSuccessfully": "Sikeres törlés",
|
||||
"description": "Leírás",
|
||||
"edit": "Szerkesztés",
|
||||
"editNodeGroup": "Csomópontcsoport szerkesztése",
|
||||
"name": "Név",
|
||||
"title": "Csomópontcsoportok listája",
|
||||
"updatedAt": "Frissítés ideje"
|
||||
},
|
||||
"groupForm": {
|
||||
"cancel": "Mégse",
|
||||
"confirm": "Megerősít",
|
||||
"description": "Leírás",
|
||||
"name": "Név"
|
||||
},
|
||||
"node": {
|
||||
"abnormal": "Rendellenes",
|
||||
"actions": "Műveletek",
|
||||
"address": "Cím",
|
||||
"all": "Összes",
|
||||
"basicInfo": "Alapinformáció",
|
||||
"cancel": "Mégse",
|
||||
"confirm": "Megerősít",
|
||||
"confirmDelete": "Biztosan törölni szeretné?",
|
||||
"copy": "Másolás",
|
||||
"copySuccess": "Sikeresen másolva",
|
||||
"create": "Létrehozás",
|
||||
"createNode": "Csomópont létrehozása",
|
||||
"createSuccess": "Sikeres létrehozás",
|
||||
"delete": "Törlés",
|
||||
"deleteSuccess": "Sikeres törlés",
|
||||
"deleteWarning": "Törlés után az adatok nem állíthatók vissza. Kérjük, járjon el körültekintően.",
|
||||
"detail": "Részletek",
|
||||
"disabled": "Letiltva",
|
||||
"disk": "Lemez",
|
||||
"edit": "Szerkesztés",
|
||||
"editNode": "Csomópont szerkesztése",
|
||||
"enable": "Engedélyezés",
|
||||
"enabled": "Engedélyezve",
|
||||
"expireTime": "Lejárati Idő",
|
||||
"hide": "Elrejtés",
|
||||
"id": "ID",
|
||||
"ipAddresses": "IP Címek",
|
||||
"lastUpdated": "Utoljára frissítve",
|
||||
"location": "Helyszín",
|
||||
"memory": "Memória",
|
||||
"name": "Név",
|
||||
"noData": "--",
|
||||
"node": "Csomópont",
|
||||
"nodeDetail": "Csomópont Részletei",
|
||||
"nodeGroup": "Csomópont csoport",
|
||||
"nodeStatus": "Csomópont Állapota",
|
||||
"normal": "Normál",
|
||||
"onlineCount": "Online felhasználók száma",
|
||||
"onlineUsers": "Online felhasználók",
|
||||
"protocol": "Protokoll",
|
||||
"rate": "Sebesség",
|
||||
"relay": "Átjátszás",
|
||||
"serverAddr": "Szerver cím",
|
||||
"speedLimit": "Sebességkorlátozás",
|
||||
"status": "Állapot",
|
||||
"subscribeId": "Előfizető Azonosító",
|
||||
"subscribeName": "Előfizető Neve",
|
||||
"subscription": "Előfizetés",
|
||||
"tags": "Címkék",
|
||||
"trafficRatio": "Forgalmi arány",
|
||||
"trafficUsage": "Forgalmi Használat",
|
||||
"type": "Típus",
|
||||
"updateSuccess": "Sikeres frissítés",
|
||||
"updatedAt": "Frissítés ideje",
|
||||
"user": "Felhasználó",
|
||||
"userDetail": "Felhasználói Részletek",
|
||||
"userId": "Felhasználói Azonosító"
|
||||
},
|
||||
"nodeForm": {
|
||||
"allowInsecure": "Biztonságos kapcsolat engedélyezése",
|
||||
"cancel": "Mégse",
|
||||
"city": "Város",
|
||||
"confirm": "Megerősít",
|
||||
"congestionController": "Forgalomirányító",
|
||||
"country": "Ország",
|
||||
"disableSni": "SNI letiltása",
|
||||
"edit": "Szerkesztés",
|
||||
"editSecurity": "Biztonsági beállítások szerkesztése",
|
||||
"enableTLS": "TLS engedélyezése",
|
||||
"encryptionMethod": "Titkosítási módszer",
|
||||
"fingerprint": "Ujjlenyomat",
|
||||
"flow": "Áramlásirányító algoritmus",
|
||||
"groupId": "Csoport azonosító",
|
||||
"hopInterval": "Ugrás intervallum",
|
||||
"hopPorts": "Ugrás portok",
|
||||
"hopPortsPlaceholder": "Több portot vesszen el vesszővel",
|
||||
"name": "Név",
|
||||
"obfsPassword": "Obfuszkálás jelszó",
|
||||
"obfsPasswordPlaceholder": "Hagyja üresen obfuszkálás nélkül",
|
||||
"path": "Útvonal",
|
||||
"pleaseSelect": "Kérem válasszon",
|
||||
"port": "Szerver port",
|
||||
"protocol": "Protokoll",
|
||||
"reduceRtt": "RTT csökkentése",
|
||||
"relayHost": "Átjáró gazda",
|
||||
"relayMode": "Átjáró mód",
|
||||
"relayPort": "Átjáró port",
|
||||
"relayPrefix": "Átjáró előtag",
|
||||
"remarks": "Megjegyzések",
|
||||
"security": "Biztonság",
|
||||
"securityConfig": "Biztonsági beállítások",
|
||||
"selectEncryptionMethod": "Titkosítási módszer kiválasztása",
|
||||
"selectNodeGroup": "Csoport kiválasztása",
|
||||
"selectProtocol": "Protokoll kiválasztása",
|
||||
"selectRelayMode": "Átjáró mód kiválasztása",
|
||||
"serverAddr": "Szerver cím",
|
||||
"serverKey": "Szerver kulcs",
|
||||
"serverName": "Szolgáltatás neve",
|
||||
"speedLimit": "Sebességkorlátozás",
|
||||
"speedLimitPlaceholder": "Korlátlan",
|
||||
"tags": "Címkék",
|
||||
"tagsPlaceholder": "Több címke megadásához használja az Entert vagy a vesszőt (,)",
|
||||
"trafficRatio": "Forgalmi arány",
|
||||
"transport": "Szállítási protokoll beállítások",
|
||||
"transportConfig": "Szállítási protokoll beállítások",
|
||||
"transportHost": "Szállító szerver címe",
|
||||
"transportPath": "Szállítási útvonal",
|
||||
"transportServerName": "Szállító szerver neve",
|
||||
"udpRelayMode": "UDP átjáró mód"
|
||||
},
|
||||
"relayModeOptions": {
|
||||
"all": "Mind",
|
||||
"none": "Egyik sem",
|
||||
"random": "Véletlenszerű"
|
||||
},
|
||||
"securityConfig": {
|
||||
"fingerprint": "Ujjlenyomat",
|
||||
"privateKey": "Privát kulcs",
|
||||
"privateKeyPlaceholder": "Hagyja üresen automatikus generáláshoz",
|
||||
"publicKey": "Nyilvános kulcs",
|
||||
"publicKeyPlaceholder": "Hagyja üresen automatikus generáláshoz",
|
||||
"serverAddress": "Szerver cím",
|
||||
"serverAddressPlaceholder": "REALITY célcím, alapértelmezett SNI használatával",
|
||||
"serverName": "Szerver név (SNI)",
|
||||
"serverNamePlaceholder": "REALITY szükséges, összhangban a háttérrel",
|
||||
"serverPort": "Szerver port",
|
||||
"serverPortPlaceholder": "REALITY célport, alapértelmezett 443",
|
||||
"shortId": "Rövid ID",
|
||||
"shortIdPlaceholder": "Hagyja üresen automatikus generáláshoz",
|
||||
"sni": "Szerver név jelzés (SNI)"
|
||||
},
|
||||
"tabs": {
|
||||
"node": "csomópont",
|
||||
"nodeConfig": "Csomópont konfiguráció",
|
||||
"nodeGroup": "csomópontcsoport"
|
||||
}
|
||||
}
|
||||
101
apps/admin/locales/hu-HU/servers.json
Normal file
101
apps/admin/locales/hu-HU/servers.json
Normal file
@ -0,0 +1,101 @@
|
||||
{
|
||||
"address": "Cím",
|
||||
"address_placeholder": "Szerver cím",
|
||||
"cancel": "Mégse",
|
||||
"city": "Város",
|
||||
"config": {
|
||||
"actions": {
|
||||
"cancel": "Mégse",
|
||||
"save": "Mentés"
|
||||
},
|
||||
"communicationKey": "Kommunikációs kulcs",
|
||||
"communicationKeyDescription": "A node hitelesítéséhez használatos.",
|
||||
"description": "A node kommunikációs kulcsainak, pull/push időközeinek és dinamikus szorzóinak kezelése.",
|
||||
"dynamicMultiplier": "Dinamikus szorzó",
|
||||
"dynamicMultiplierDescription": "Időszakok és szorzók meghatározása a forgalom elszámolásának módosításához.",
|
||||
"endTime": "Befejezési idő",
|
||||
"inputPlaceholder": "Kérjük, adja meg",
|
||||
"multiplier": "Szorzó",
|
||||
"nodePullInterval": "Node pull időköz",
|
||||
"nodePullIntervalDescription": "Milyen gyakran húzza a node a konfigurációt (másodperc).",
|
||||
"nodePushInterval": "Node push időköz",
|
||||
"nodePushIntervalDescription": "Milyen gyakran tolja a node a statisztikákat (másodperc).",
|
||||
"reset": "Visszaállítás",
|
||||
"save": "Mentés",
|
||||
"saveSuccess": "Sikeresen mentve",
|
||||
"startTime": "Kezdési idő",
|
||||
"timeSlot": "Időszak",
|
||||
"title": "Node konfiguráció"
|
||||
},
|
||||
"confirm": "Megerősítés",
|
||||
"confirmDeleteDesc": "Ez a művelet nem vonható vissza.",
|
||||
"confirmDeleteTitle": "Törölni szeretné ezt a szervert?",
|
||||
"congestion_controller": "Torlaszkezelő",
|
||||
"copied": "Másolva",
|
||||
"copy": "Másolás",
|
||||
"country": "Ország",
|
||||
"cpu": "CPU",
|
||||
"create": "Létrehozás",
|
||||
"created": "Sikeresen létrehozva",
|
||||
"delete": "Törlés",
|
||||
"deleted": "Sikeresen törölve",
|
||||
"disable_sni": "SNI letiltása",
|
||||
"disk": "Lemez",
|
||||
"drawerCreateTitle": "Szerver létrehozása",
|
||||
"drawerEditTitle": "Szerver szerkesztése",
|
||||
"edit": "Szerkesztés",
|
||||
"enabled": "Engedélyezve",
|
||||
"encryption_method": "Titkosítási módszer",
|
||||
"expireTime": "Lejárati idő",
|
||||
"expired": "Lejárt",
|
||||
"flow": "Forgalom",
|
||||
"hop_interval": "Ugrás időköz",
|
||||
"hop_ports": "Ugrás portok",
|
||||
"hop_ports_placeholder": "pl. 1-65535",
|
||||
"host": "Gazda",
|
||||
"id": "ID",
|
||||
"ipAddresses": "IP címek",
|
||||
"memory": "Memória",
|
||||
"name": "Név",
|
||||
"noData": "Nincs adat",
|
||||
"notAvailable": "N/A",
|
||||
"obfs_password": "Obfuszkálás jelszó",
|
||||
"obfs_password_placeholder": "Adja meg az obfuszkálás jelszót",
|
||||
"offline": "Offline",
|
||||
"online": "Online",
|
||||
"onlineUsers": "Online felhasználók",
|
||||
"pageTitle": "Szerverek",
|
||||
"path": "Útvonal",
|
||||
"please_select": "Kérjük, válasszon",
|
||||
"port": "Port",
|
||||
"protocols": "Protokollok",
|
||||
"reduce_rtt": "RTT csökkentése",
|
||||
"security_allow_insecure": "Biztonságos kapcsolat engedélyezése",
|
||||
"security_fingerprint": "Ujjlenyomat",
|
||||
"security_private_key": "Valóság privát kulcs",
|
||||
"security_private_key_placeholder": "Adja meg a privát kulcsot",
|
||||
"security_public_key": "Valóság nyilvános kulcs",
|
||||
"security_public_key_placeholder": "Adja meg a nyilvános kulcsot",
|
||||
"security_server_address": "Valóság szerver címe",
|
||||
"security_server_address_placeholder": "pl. 1.2.3.4 vagy domain",
|
||||
"security_server_port": "Valóság szerver port",
|
||||
"security_short_id": "Valóság rövid ID",
|
||||
"security_short_id_placeholder": "Hexadecimális karakterlánc (legfeljebb 16 karakter)",
|
||||
"security_sni": "SNI",
|
||||
"security_title": "Biztonság",
|
||||
"select_encryption_method": "Válassza ki a titkosítási módszert",
|
||||
"server_key": "Szerver kulcs",
|
||||
"service_name": "Szolgáltatás neve",
|
||||
"status": "Állapot",
|
||||
"subscribeId": "Előfizetési ID",
|
||||
"subscription": "Előfizetés",
|
||||
"traffic": "Forgalom",
|
||||
"traffic_ratio": "Szorzó",
|
||||
"transport_title": "Szállítás",
|
||||
"udp_relay_mode": "UDP átjáró mód",
|
||||
"unitSecondsShort": "S",
|
||||
"unlimited": "Korlátlan",
|
||||
"updated": "Sikeresen frissítve",
|
||||
"user": "Felhasználó",
|
||||
"validation_failed": "Érvényesítés sikertelen. Kérjük, ellenőrizze a űrlapot."
|
||||
}
|
||||
@ -1,27 +1,36 @@
|
||||
{
|
||||
"ADS Config": "ADS設定",
|
||||
"Announcement Management": "お知らせ管理",
|
||||
"Application Management": "アプリケーション管理",
|
||||
"Auth Control": "認証管理",
|
||||
"Balance": "残高",
|
||||
"Commerce": "商取引",
|
||||
"Commission": "手数料",
|
||||
"Coupon Management": "クーポン管理",
|
||||
"Dashboard": "ダッシュボード",
|
||||
"Document Management": "ドキュメント管理",
|
||||
"Finance": "財務",
|
||||
"Email": "メール",
|
||||
"Gift": "ギフト",
|
||||
"Login": "ログイン",
|
||||
"Logs & Analytics": "ログと分析",
|
||||
"Maintenance": "メンテナンス",
|
||||
"Marketing Management": "マーケティングマネジメント",
|
||||
"Node Management": "ノード管理",
|
||||
"Order Management": "注文管理",
|
||||
"Payment Config": "支払い設定",
|
||||
"Product Management": "プロダクトマネジメント",
|
||||
"Protocol Management": "プロトコル管理",
|
||||
"Rule Management": "ルール管理",
|
||||
"Server": "サーバー",
|
||||
"Register": "登録",
|
||||
"Reset Subscribe": "購読のリセット",
|
||||
"SMS": "SMS",
|
||||
"Server Management": "サーバー管理",
|
||||
"Settings": "設定",
|
||||
"Server Traffic": "サーバートラフィック",
|
||||
"Subscribe": "購読",
|
||||
"Subscribe Config": "サブスクリプション設定",
|
||||
"Subscribe Traffic": "購読トラフィック",
|
||||
"System": "システム",
|
||||
"System Config": "システム構成",
|
||||
"System Management": "システム管理",
|
||||
"System Tool": "システムツール",
|
||||
"Ticket Management": "チケット管理",
|
||||
"User": "ユーザー",
|
||||
"User Detail": "ユーザー詳細",
|
||||
"User Management": "ユーザー管理"
|
||||
"User Management": "ユーザー管理",
|
||||
"Users & Support": "ユーザーとサポート"
|
||||
}
|
||||
|
||||
37
apps/admin/locales/ja-JP/nodes.json
Normal file
37
apps/admin/locales/ja-JP/nodes.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"address": "アドレス",
|
||||
"cancel": "キャンセル",
|
||||
"confirm": "確認",
|
||||
"confirmDeleteDesc": "この操作は元に戻せません。",
|
||||
"confirmDeleteTitle": "このノードを削除しますか?",
|
||||
"copied": "コピーしました",
|
||||
"copy": "コピー",
|
||||
"create": "作成",
|
||||
"created": "作成されました",
|
||||
"delete": "削除",
|
||||
"deleted": "削除されました",
|
||||
"drawerCreateTitle": "ノードを作成",
|
||||
"drawerEditTitle": "ノードを編集",
|
||||
"edit": "編集",
|
||||
"enabled": "有効",
|
||||
"enabled_off": "無効",
|
||||
"enabled_on": "有効",
|
||||
"errors": {
|
||||
"nameRequired": "名前を入力してください",
|
||||
"portRange": "ポートは1から65535の間でなければなりません",
|
||||
"protocolRequired": "プロトコルを選択してください",
|
||||
"serverAddrRequired": "エントリーアドレスを入力してください",
|
||||
"serverRequired": "サーバーを選択してください"
|
||||
},
|
||||
"name": "名前",
|
||||
"pageTitle": "ノード",
|
||||
"port": "ポート",
|
||||
"protocol": "プロトコル",
|
||||
"select_protocol": "プロトコルを選択…",
|
||||
"select_server": "サーバーを選択…",
|
||||
"server": "サーバー",
|
||||
"tags": "タグ",
|
||||
"tags_description": "権限グループ化タグ(プランバインディングおよび配信ポリシーを含む)。",
|
||||
"tags_placeholder": "複数のタグを追加するにはEnterまたはカンマ(,)を使用してください",
|
||||
"updated": "更新されました"
|
||||
}
|
||||
@ -1,59 +1,6 @@
|
||||
{
|
||||
"actions": "アクション",
|
||||
"app": {
|
||||
"appDownloadURL": "アプリダウンロードURL",
|
||||
"appIcon": "アプリアイコン",
|
||||
"appList": "アプリリスト",
|
||||
"appName": "アプリ名",
|
||||
"backupDomains": "バックアップドメインリスト",
|
||||
"backupDomainsDescription": "ドメイン解決のためのバックアップドメインリスト、1行に1つのドメイン",
|
||||
"batchDelete": "一括削除",
|
||||
"cancel": "キャンセル",
|
||||
"communicationKey": "通信キー",
|
||||
"communicationKeyDescription": "クライアント通信に使用されるキー",
|
||||
"config": "設定",
|
||||
"configApp": "アプリ設定",
|
||||
"confirm": "確認",
|
||||
"confirmDelete": "削除を確認",
|
||||
"create": "作成",
|
||||
"createApp": "アプリ作成",
|
||||
"createSuccess": "作成に成功しました",
|
||||
"defaultVersion": "デフォルト",
|
||||
"delete": "削除",
|
||||
"deleteWarning": "この操作は元に戻せません",
|
||||
"describeDescription": "アプリケーションを説明するために使用され、アプリリストに表示されます",
|
||||
"description": "説明",
|
||||
"downloadLink": "ダウンロードリンク",
|
||||
"edit": "編集",
|
||||
"editApp": "アプリ編集",
|
||||
"encryption": "暗号化方式",
|
||||
"encryptionDescription": "クライアント通信の暗号化方式を選択してください。選択された場合、クライアントはこの方式を使用してサーバーと通信します",
|
||||
"nameDescription": "アプリケーション名、アプリリストに表示されます",
|
||||
"platform": "プラットフォーム",
|
||||
"selectApp": "アプリを選択",
|
||||
"selectAppDescription": "設定するアプリを選択してください。すべての設定は選択したアプリに適用されます",
|
||||
"startupPicture": "スタートアップ画像",
|
||||
"startupPictureDescription": "スタートアップ画像、ネットワークおよびローカル画像をサポートします。ネットワーク画像の場合は、完全な画像URLを入力してください",
|
||||
"startupPicturePreview": "スタートアップ画像プレビュー",
|
||||
"startupPictureSkip": "スタートアップ画像スキップ時間",
|
||||
"startupPictureSkipDescription": "スタートアップ画像の表示時間(秒)、表示しない場合は0を入力",
|
||||
"subscriptionProtocol": "サブスクリプションプロトコル",
|
||||
"updateSuccess": "更新に成功しました",
|
||||
"version": "バージョン"
|
||||
},
|
||||
"cancel": "キャンセル",
|
||||
"config": {
|
||||
"singleSubscriptionMode": "シングルサブスクリプションモード",
|
||||
"subscriptionDomain": "サブスクリプションドメイン",
|
||||
"subscriptionDomainDescription": "サブスクリプションに使用します。サイトドメインを使用する場合は空白のままにしてください",
|
||||
"subscriptionDomainPlaceholder": "サブスクリプションドメインを入力してください。1行に1つずつ",
|
||||
"subscriptionPath": "サブスクリプションパス",
|
||||
"subscriptionPathDescription": "サブスクリプションに使用します。最適なパフォーマンスのために、変更後は必ずシステムを再起動してください",
|
||||
"subscriptionPathPlaceholder": "入力してください",
|
||||
"updateSuccess": "更新が成功しました",
|
||||
"wildcardResolution": "ワイルドカード解決",
|
||||
"wildcardResolutionDescription": "サブスクリプションに使用します"
|
||||
},
|
||||
"confirm": "確認",
|
||||
"confirmDelete": "削除してもよろしいですか?",
|
||||
"copy": "コピー",
|
||||
@ -94,6 +41,9 @@
|
||||
"name": "名称",
|
||||
"noLimit": "無制限",
|
||||
"noReset": "リセットなし",
|
||||
"node": "ノード",
|
||||
"nodeGroup": "ノードグループ",
|
||||
"nodes": "ノード",
|
||||
"pricing": "価格設定",
|
||||
"purchaseWithDiscount": "控除を許可",
|
||||
"purchaseWithDiscountDescription": "購読解除機能を有効または無効にします。有効化後、システムは設定されたルールと割合に従って控除処理を行い、残りの金額を残高に返金します。",
|
||||
@ -106,9 +56,6 @@
|
||||
"selectResetCycle": "リセットサイクルを選択してください",
|
||||
"selectSubscribeGroup": "サブスクリプショングループを選択してください",
|
||||
"selectUnitTime": "単位時間を選択してください",
|
||||
"server": "サーバー",
|
||||
"serverGroup": "サーバーグループ",
|
||||
"servers": "サーバー",
|
||||
"speedLimit": "速度制限",
|
||||
"traffic": "トラフィック",
|
||||
"unitPrice": "単価",
|
||||
@ -150,8 +97,6 @@
|
||||
"subscribeGroup": "グループを購読する",
|
||||
"tabs": {
|
||||
"subscribe": "購読",
|
||||
"subscribeApp": "アプリ設定",
|
||||
"subscribeConfig": "サブスクリプション設定",
|
||||
"subscribeGroup": "購読グループ"
|
||||
},
|
||||
"traffic": "トラフィック",
|
||||
|
||||
@ -1,183 +0,0 @@
|
||||
{
|
||||
"config": {
|
||||
"addTimeSlot": "時間枠を追加",
|
||||
"communicationKey": "通信キー",
|
||||
"communicationKeyDescription": "データの安全性を確保するためのノード通信キー",
|
||||
"delete": "削除",
|
||||
"dynamicMultiplier": "動的乗数",
|
||||
"dynamicMultiplierDescription": "動的乗数は、異なるノードが異なる時間帯に異なる乗数でプッシュされたデータを処理することを指します。",
|
||||
"endTime": "終了時間",
|
||||
"inputPlaceholder": "入力してください",
|
||||
"multiplier": "乗数",
|
||||
"nodePullInterval": "ノードプル間隔",
|
||||
"nodePullIntervalDescription": "ノードがパネルからデータを取得する頻度(秒単位)",
|
||||
"nodePushInterval": "ノードプッシュ間隔",
|
||||
"nodePushIntervalDescription": "ノードがデータをパネルにプッシュする頻度",
|
||||
"reset": "リセット",
|
||||
"save": "保存",
|
||||
"saveSuccess": "保存に成功しました",
|
||||
"startTime": "開始時間",
|
||||
"timeSlot": "時間枠"
|
||||
},
|
||||
"group": {
|
||||
"actions": "操作",
|
||||
"cancel": "キャンセル",
|
||||
"confirm": "確認",
|
||||
"confirmDelete": "削除してもよろしいですか?",
|
||||
"create": "作成",
|
||||
"createNodeGroup": "ノードグループを作成",
|
||||
"createdSuccessfully": "作成に成功しました",
|
||||
"delete": "削除",
|
||||
"deleteWarning": "削除後、データは復元できませんので、慎重に操作してください。",
|
||||
"deletedSuccessfully": "削除に成功しました",
|
||||
"description": "説明",
|
||||
"edit": "編集",
|
||||
"editNodeGroup": "ノードグループを編集",
|
||||
"name": "名前",
|
||||
"title": "ノードグループ一覧",
|
||||
"updatedAt": "更新日時"
|
||||
},
|
||||
"groupForm": {
|
||||
"cancel": "キャンセル",
|
||||
"confirm": "確認",
|
||||
"description": "説明",
|
||||
"name": "名前"
|
||||
},
|
||||
"node": {
|
||||
"abnormal": "異常",
|
||||
"actions": "操作",
|
||||
"address": "住所",
|
||||
"all": "すべて",
|
||||
"basicInfo": "基本情報",
|
||||
"cancel": "キャンセル",
|
||||
"confirm": "確認",
|
||||
"confirmDelete": "削除してもよろしいですか?",
|
||||
"copy": "コピー",
|
||||
"copySuccess": "コピーしました",
|
||||
"create": "作成",
|
||||
"createNode": "ノードを作成",
|
||||
"createSuccess": "作成成功",
|
||||
"delete": "削除",
|
||||
"deleteSuccess": "削除成功",
|
||||
"deleteWarning": "削除後、データは復元できません。慎重に操作してください。",
|
||||
"detail": "詳細",
|
||||
"disabled": "無効",
|
||||
"disk": "ディスク",
|
||||
"edit": "編集",
|
||||
"editNode": "ノードを編集",
|
||||
"enable": "有効化",
|
||||
"enabled": "有効",
|
||||
"expireTime": "有効期限",
|
||||
"hide": "非表示",
|
||||
"id": "ID",
|
||||
"ipAddresses": "IPアドレス",
|
||||
"lastUpdated": "最終更新",
|
||||
"location": "場所",
|
||||
"memory": "メモリ",
|
||||
"name": "名前",
|
||||
"noData": "--",
|
||||
"node": "ノード",
|
||||
"nodeDetail": "ノードの詳細",
|
||||
"nodeGroup": "ノードグループ",
|
||||
"nodeStatus": "ノードの状態",
|
||||
"normal": "正常",
|
||||
"onlineCount": "オンライン人数",
|
||||
"onlineUsers": "オンラインユーザー",
|
||||
"protocol": "プロトコル",
|
||||
"rate": "レート",
|
||||
"relay": "リレー",
|
||||
"serverAddr": "サーバーアドレス",
|
||||
"speedLimit": "速度制限",
|
||||
"status": "ステータス",
|
||||
"subscribeId": "サブスクライブID",
|
||||
"subscribeName": "サブスクライブ名",
|
||||
"subscription": "サブスクリプション",
|
||||
"tags": "タグ",
|
||||
"trafficRatio": "トラフィックレート",
|
||||
"trafficUsage": "トラフィック使用量",
|
||||
"type": "タイプ",
|
||||
"updateSuccess": "更新成功",
|
||||
"updatedAt": "更新時間",
|
||||
"user": "ユーザー",
|
||||
"userDetail": "ユーザーの詳細",
|
||||
"userId": "ユーザーID"
|
||||
},
|
||||
"nodeForm": {
|
||||
"allowInsecure": "不正な接続を許可",
|
||||
"cancel": "キャンセル",
|
||||
"city": "市",
|
||||
"confirm": "確認",
|
||||
"congestionController": "混雑制御",
|
||||
"country": "国",
|
||||
"disableSni": "SNIを無効にする",
|
||||
"edit": "編集",
|
||||
"editSecurity": "セキュリティ設定の編集",
|
||||
"enableTLS": "TLSを有効にする",
|
||||
"encryptionMethod": "暗号化方式",
|
||||
"fingerprint": "フィンガープリント",
|
||||
"flow": "フロー制御アルゴリズム",
|
||||
"groupId": "ノードグループ",
|
||||
"hopInterval": "ホップ間隔",
|
||||
"hopPorts": "ホップポート",
|
||||
"hopPortsPlaceholder": "複数のポートをカンマで区切って入力",
|
||||
"name": "名前",
|
||||
"obfsPassword": "難読化パスワード",
|
||||
"obfsPasswordPlaceholder": "難読化しない場合は空白のままにしてください",
|
||||
"path": "パス",
|
||||
"pleaseSelect": "選択してください",
|
||||
"port": "サーバーポート",
|
||||
"protocol": "プロトコル",
|
||||
"reduceRtt": "RTTを削減",
|
||||
"relayHost": "リレーホスト",
|
||||
"relayMode": "リレーモード",
|
||||
"relayPort": "リレーポート",
|
||||
"relayPrefix": "リレープレフィックス",
|
||||
"remarks": "備考",
|
||||
"security": "セキュリティ",
|
||||
"securityConfig": "セキュリティ設定",
|
||||
"selectEncryptionMethod": "暗号化方式を選択",
|
||||
"selectNodeGroup": "ノードグループを選択",
|
||||
"selectProtocol": "プロトコルを選択",
|
||||
"selectRelayMode": "リレーモードを選択",
|
||||
"serverAddr": "サーバーアドレス",
|
||||
"serverKey": "サーバーキー",
|
||||
"serverName": "サービス名",
|
||||
"speedLimit": "速度制限",
|
||||
"speedLimitPlaceholder": "無制限",
|
||||
"tags": "タグ",
|
||||
"tagsPlaceholder": "複数のタグを入力するにはEnterまたはカンマ(,)を使用",
|
||||
"trafficRatio": "トラフィック比率",
|
||||
"transport": "トランスポートプロトコル設定",
|
||||
"transportConfig": "トランスポートプロトコル設定",
|
||||
"transportHost": "トランスポートサーバーアドレス",
|
||||
"transportPath": "トランスポートパス",
|
||||
"transportServerName": "トランスポートサーバー名",
|
||||
"udpRelayMode": "UDPリレーモード"
|
||||
},
|
||||
"relayModeOptions": {
|
||||
"all": "すべて",
|
||||
"none": "なし",
|
||||
"random": "ランダム"
|
||||
},
|
||||
"securityConfig": {
|
||||
"fingerprint": "フィンガープリント",
|
||||
"privateKey": "秘密鍵",
|
||||
"privateKeyPlaceholder": "自動生成する場合は空白のままにしてください",
|
||||
"publicKey": "公開鍵",
|
||||
"publicKeyPlaceholder": "自動生成する場合は空白のままにしてください",
|
||||
"serverAddress": "サーバーアドレス",
|
||||
"serverAddressPlaceholder": "REALITYターゲットアドレス、デフォルトはSNIを使用",
|
||||
"serverName": "サーバー名 (SNI)",
|
||||
"serverNamePlaceholder": "REALITY必須、バックエンドと一致",
|
||||
"serverPort": "サーバーポート",
|
||||
"serverPortPlaceholder": "REALITYターゲットポート、デフォルトは443",
|
||||
"shortId": "ショートID",
|
||||
"shortIdPlaceholder": "自動生成する場合は空白のままにしてください",
|
||||
"sni": "サーバー名表示 (SNI)"
|
||||
},
|
||||
"tabs": {
|
||||
"node": "ノード",
|
||||
"nodeConfig": "ノード構成",
|
||||
"nodeGroup": "ノードグループ"
|
||||
}
|
||||
}
|
||||
101
apps/admin/locales/ja-JP/servers.json
Normal file
101
apps/admin/locales/ja-JP/servers.json
Normal file
@ -0,0 +1,101 @@
|
||||
{
|
||||
"address": "アドレス",
|
||||
"address_placeholder": "サーバーアドレス",
|
||||
"cancel": "キャンセル",
|
||||
"city": "都市",
|
||||
"config": {
|
||||
"actions": {
|
||||
"cancel": "キャンセル",
|
||||
"save": "保存"
|
||||
},
|
||||
"communicationKey": "通信キー",
|
||||
"communicationKeyDescription": "ノード認証に使用されます。",
|
||||
"description": "ノードの通信キー、プル/プッシュ間隔、動的倍率を管理します。",
|
||||
"dynamicMultiplier": "動的倍率",
|
||||
"dynamicMultiplierDescription": "トラフィック計算を調整するための時間スロットと倍率を定義します。",
|
||||
"endTime": "終了時間",
|
||||
"inputPlaceholder": "入力してください",
|
||||
"multiplier": "倍率",
|
||||
"nodePullInterval": "ノードプル間隔",
|
||||
"nodePullIntervalDescription": "ノードが設定をプルする頻度(秒)。",
|
||||
"nodePushInterval": "ノードプッシュ間隔",
|
||||
"nodePushIntervalDescription": "ノードが統計をプッシュする頻度(秒)。",
|
||||
"reset": "リセット",
|
||||
"save": "保存",
|
||||
"saveSuccess": "保存に成功しました",
|
||||
"startTime": "開始時間",
|
||||
"timeSlot": "時間スロット",
|
||||
"title": "ノード設定"
|
||||
},
|
||||
"confirm": "確認",
|
||||
"confirmDeleteDesc": "この操作は元に戻せません。",
|
||||
"confirmDeleteTitle": "このサーバーを削除しますか?",
|
||||
"congestion_controller": "混雑制御",
|
||||
"copied": "コピーしました",
|
||||
"copy": "コピー",
|
||||
"country": "国",
|
||||
"cpu": "CPU",
|
||||
"create": "作成",
|
||||
"created": "作成に成功しました",
|
||||
"delete": "削除",
|
||||
"deleted": "削除に成功しました",
|
||||
"disable_sni": "SNIを無効にする",
|
||||
"disk": "ディスク",
|
||||
"drawerCreateTitle": "サーバーを作成",
|
||||
"drawerEditTitle": "サーバーを編集",
|
||||
"edit": "編集",
|
||||
"enabled": "有効",
|
||||
"encryption_method": "暗号化方式",
|
||||
"expireTime": "有効期限",
|
||||
"expired": "期限切れ",
|
||||
"flow": "フロー",
|
||||
"hop_interval": "ホップ間隔",
|
||||
"hop_ports": "ホップポート",
|
||||
"hop_ports_placeholder": "例: 1-65535",
|
||||
"host": "ホスト",
|
||||
"id": "ID",
|
||||
"ipAddresses": "IPアドレス",
|
||||
"memory": "メモリ",
|
||||
"name": "名前",
|
||||
"noData": "データなし",
|
||||
"notAvailable": "利用不可",
|
||||
"obfs_password": "難読化パスワード",
|
||||
"obfs_password_placeholder": "難読化パスワードを入力してください",
|
||||
"offline": "オフライン",
|
||||
"online": "オンライン",
|
||||
"onlineUsers": "オンラインユーザー",
|
||||
"pageTitle": "サーバー",
|
||||
"path": "パス",
|
||||
"please_select": "選択してください",
|
||||
"port": "ポート",
|
||||
"protocols": "プロトコル",
|
||||
"reduce_rtt": "RTTを減少させる",
|
||||
"security_allow_insecure": "不安全を許可",
|
||||
"security_fingerprint": "フィンガープリント",
|
||||
"security_private_key": "リアリティプライベートキー",
|
||||
"security_private_key_placeholder": "プライベートキーを入力してください",
|
||||
"security_public_key": "リアリティパブリックキー",
|
||||
"security_public_key_placeholder": "パブリックキーを入力してください",
|
||||
"security_server_address": "リアリティサーバーアドレス",
|
||||
"security_server_address_placeholder": "例: 1.2.3.4 または ドメイン",
|
||||
"security_server_port": "リアリティサーバーポート",
|
||||
"security_short_id": "リアリティショートID",
|
||||
"security_short_id_placeholder": "16文字以内の16進数文字列",
|
||||
"security_sni": "SNI",
|
||||
"security_title": "セキュリティ",
|
||||
"select_encryption_method": "暗号化方式を選択",
|
||||
"server_key": "サーバーキー",
|
||||
"service_name": "サービス名",
|
||||
"status": "ステータス",
|
||||
"subscribeId": "サブスクリプションID",
|
||||
"subscription": "サブスクリプション",
|
||||
"traffic": "トラフィック",
|
||||
"traffic_ratio": "倍率",
|
||||
"transport_title": "トランスポート",
|
||||
"udp_relay_mode": "UDPリレーモード",
|
||||
"unitSecondsShort": "秒",
|
||||
"unlimited": "無制限",
|
||||
"updated": "更新に成功しました",
|
||||
"user": "ユーザー",
|
||||
"validation_failed": "検証に失敗しました。フォームを確認してください。"
|
||||
}
|
||||
@ -1,27 +1,36 @@
|
||||
{
|
||||
"ADS Config": "ADS 구성",
|
||||
"Announcement Management": "공지 관리",
|
||||
"Application Management": "애플리케이션 관리",
|
||||
"Auth Control": "인증 제어",
|
||||
"Balance": "잔액",
|
||||
"Commerce": "상업",
|
||||
"Commission": "수수료",
|
||||
"Coupon Management": "쿠폰 관리",
|
||||
"Dashboard": "대시보드",
|
||||
"Document Management": "문서 관리",
|
||||
"Finance": "재무",
|
||||
"Email": "이메일",
|
||||
"Gift": "선물",
|
||||
"Login": "로그인",
|
||||
"Logs & Analytics": "로그 및 분석",
|
||||
"Maintenance": "유지보수",
|
||||
"Marketing Management": "마케팅 관리",
|
||||
"Node Management": "노드 관리",
|
||||
"Order Management": "주문 관리",
|
||||
"Payment Config": "결제 구성",
|
||||
"Product Management": "제품 관리",
|
||||
"Protocol Management": "프로토콜 관리",
|
||||
"Rule Management": "규칙 관리",
|
||||
"Server": "서버",
|
||||
"Register": "등록",
|
||||
"Reset Subscribe": "구독 초기화",
|
||||
"SMS": "문자 메시지",
|
||||
"Server Management": "서버 관리",
|
||||
"Settings": "설정",
|
||||
"Server Traffic": "서버 트래픽",
|
||||
"Subscribe": "구독",
|
||||
"Subscribe Config": "구독 설정",
|
||||
"Subscribe Traffic": "구독 트래픽",
|
||||
"System": "시스템",
|
||||
"System Config": "시스템 구성",
|
||||
"System Management": "시스템 관리",
|
||||
"System Tool": "시스템 도구",
|
||||
"Ticket Management": "티켓 관리",
|
||||
"User": "사용자",
|
||||
"User Detail": "사용자 세부 정보",
|
||||
"User Management": "사용자 관리"
|
||||
"User Management": "사용자 관리",
|
||||
"Users & Support": "사용자 및 지원"
|
||||
}
|
||||
|
||||
37
apps/admin/locales/ko-KR/nodes.json
Normal file
37
apps/admin/locales/ko-KR/nodes.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"address": "주소",
|
||||
"cancel": "취소",
|
||||
"confirm": "확인",
|
||||
"confirmDeleteDesc": "이 작업은 실행 취소할 수 없습니다.",
|
||||
"confirmDeleteTitle": "이 노드를 삭제하시겠습니까?",
|
||||
"copied": "복사됨",
|
||||
"copy": "복사",
|
||||
"create": "생성",
|
||||
"created": "생성됨",
|
||||
"delete": "삭제",
|
||||
"deleted": "삭제됨",
|
||||
"drawerCreateTitle": "노드 생성",
|
||||
"drawerEditTitle": "노드 편집",
|
||||
"edit": "편집",
|
||||
"enabled": "활성화됨",
|
||||
"enabled_off": "비활성화됨",
|
||||
"enabled_on": "활성화됨",
|
||||
"errors": {
|
||||
"nameRequired": "이름을 입력해 주세요",
|
||||
"portRange": "포트는 1과 65535 사이여야 합니다",
|
||||
"protocolRequired": "프로토콜을 선택해 주세요",
|
||||
"serverAddrRequired": "입력 주소를 입력해 주세요",
|
||||
"serverRequired": "서버를 선택해 주세요"
|
||||
},
|
||||
"name": "이름",
|
||||
"pageTitle": "노드",
|
||||
"port": "포트",
|
||||
"protocol": "프로토콜",
|
||||
"select_protocol": "프로토콜 선택…",
|
||||
"select_server": "서버 선택…",
|
||||
"server": "서버",
|
||||
"tags": "태그",
|
||||
"tags_description": "권한 그룹화 태그(계획 바인딩 및 배포 정책 포함).",
|
||||
"tags_placeholder": "여러 태그를 추가하려면 Enter 또는 쉼표(,)를 사용하세요",
|
||||
"updated": "업데이트됨"
|
||||
}
|
||||
@ -1,59 +1,6 @@
|
||||
{
|
||||
"actions": "작업",
|
||||
"app": {
|
||||
"appDownloadURL": "앱 다운로드 URL",
|
||||
"appIcon": "앱 아이콘",
|
||||
"appList": "앱 목록",
|
||||
"appName": "앱 이름",
|
||||
"backupDomains": "백업 도메인 목록",
|
||||
"backupDomainsDescription": "도메인 해석을 위한 백업 도메인 목록, 한 줄에 하나의 도메인",
|
||||
"batchDelete": "일괄 삭제",
|
||||
"cancel": "취소",
|
||||
"communicationKey": "통신 키",
|
||||
"communicationKeyDescription": "클라이언트 통신에 사용되는 키",
|
||||
"config": "설정",
|
||||
"configApp": "앱 설정",
|
||||
"confirm": "확인",
|
||||
"confirmDelete": "삭제 확인",
|
||||
"create": "생성",
|
||||
"createApp": "앱 생성",
|
||||
"createSuccess": "성공적으로 생성되었습니다",
|
||||
"defaultVersion": "기본",
|
||||
"delete": "삭제",
|
||||
"deleteWarning": "이 작업은 되돌릴 수 없습니다",
|
||||
"describeDescription": "애플리케이션을 설명하는 데 사용되며, 앱 목록에 표시됩니다",
|
||||
"description": "설명",
|
||||
"downloadLink": "다운로드 링크",
|
||||
"edit": "편집",
|
||||
"editApp": "앱 편집",
|
||||
"encryption": "암호화 방법",
|
||||
"encryptionDescription": "클라이언트 통신을 위한 암호화 방법을 선택하세요. 선택하면 클라이언트는 이 방법을 사용하여 서버와 통신합니다.",
|
||||
"nameDescription": "애플리케이션 이름, 앱 목록에 표시됩니다",
|
||||
"platform": "플랫폼",
|
||||
"selectApp": "앱 선택",
|
||||
"selectAppDescription": "구성할 앱을 선택하세요. 모든 설정은 선택한 앱에 적용됩니다.",
|
||||
"startupPicture": "시작 화면",
|
||||
"startupPictureDescription": "시작 화면, 네트워크 및 로컬 이미지를 지원합니다. 네트워크 이미지를 사용할 경우, 전체 이미지 URL을 입력하세요",
|
||||
"startupPicturePreview": "시작 화면 미리보기",
|
||||
"startupPictureSkip": "시작 화면 건너뛰기 시간",
|
||||
"startupPictureSkipDescription": "시작 화면 표시 시간(초), 0을 입력하면 표시되지 않습니다",
|
||||
"subscriptionProtocol": "구독 프로토콜",
|
||||
"updateSuccess": "성공적으로 업데이트되었습니다",
|
||||
"version": "버전"
|
||||
},
|
||||
"cancel": "취소",
|
||||
"config": {
|
||||
"singleSubscriptionMode": "단일 구독 모드",
|
||||
"subscriptionDomain": "구독 도메인",
|
||||
"subscriptionDomainDescription": "구독에 사용됩니다; 사이트 도메인을 사용하려면 비워 두세요",
|
||||
"subscriptionDomainPlaceholder": "구독 도메인을 입력하세요, 한 줄에 하나씩",
|
||||
"subscriptionPath": "구독 경로",
|
||||
"subscriptionPathDescription": "구독에 사용됩니다; 최적의 성능을 위해 수정 후 시스템을 재시작하세요",
|
||||
"subscriptionPathPlaceholder": "입력하세요",
|
||||
"updateSuccess": "성공적으로 업데이트되었습니다",
|
||||
"wildcardResolution": "와일드카드 해상도",
|
||||
"wildcardResolutionDescription": "구독에 사용됩니다"
|
||||
},
|
||||
"confirm": "확인",
|
||||
"confirmDelete": "삭제하시겠습니까?",
|
||||
"copy": "복사",
|
||||
@ -94,6 +41,9 @@
|
||||
"name": "이름",
|
||||
"noLimit": "무제한",
|
||||
"noReset": "초기화 없음",
|
||||
"node": "노드",
|
||||
"nodeGroup": "노드 그룹",
|
||||
"nodes": "노드들",
|
||||
"pricing": "가격",
|
||||
"purchaseWithDiscount": "공제 허용",
|
||||
"purchaseWithDiscountDescription": "구독 취소 기능을 활성화하거나 비활성화합니다. 활성화 후, 시스템은 설정된 규칙과 비율에 따라 공제 처리를 수행하며, 남은 가치는 잔액으로 반환됩니다.",
|
||||
@ -106,9 +56,6 @@
|
||||
"selectResetCycle": "초기화 주기를 선택하세요",
|
||||
"selectSubscribeGroup": "구독 그룹을 선택하세요",
|
||||
"selectUnitTime": "단위 시간을 선택하세요",
|
||||
"server": "서버",
|
||||
"serverGroup": "서버 그룹",
|
||||
"servers": "서버",
|
||||
"speedLimit": "속도 제한 ",
|
||||
"traffic": "트래픽",
|
||||
"unitPrice": "단가",
|
||||
@ -150,8 +97,6 @@
|
||||
"subscribeGroup": "구독 그룹",
|
||||
"tabs": {
|
||||
"subscribe": "구독",
|
||||
"subscribeApp": "앱 구성",
|
||||
"subscribeConfig": "구독 구성",
|
||||
"subscribeGroup": "구독 그룹"
|
||||
},
|
||||
"traffic": "트래픽",
|
||||
|
||||
@ -1,183 +0,0 @@
|
||||
{
|
||||
"config": {
|
||||
"addTimeSlot": "시간 슬롯 추가",
|
||||
"communicationKey": "통신 키",
|
||||
"communicationKeyDescription": "데이터 보안을 보장하기 위한 노드 통신 키",
|
||||
"delete": "삭제",
|
||||
"dynamicMultiplier": "동적 배수",
|
||||
"dynamicMultiplierDescription": "동적 배수는 서로 다른 시간대에 서로 다른 노드에 대해 서로 다른 배수로 푸시된 데이터를 처리하는 것을 의미합니다.",
|
||||
"endTime": "종료 시간",
|
||||
"inputPlaceholder": "입력",
|
||||
"multiplier": "배수",
|
||||
"nodePullInterval": "노드 풀 간격",
|
||||
"nodePullIntervalDescription": "노드가 패널에서 데이터를 가져오는 빈도(초 단위)",
|
||||
"nodePushInterval": "노드 푸시 간격",
|
||||
"nodePushIntervalDescription": "노드가 데이터를 패널로 푸시하는 빈도",
|
||||
"reset": "재설정",
|
||||
"save": "저장",
|
||||
"saveSuccess": "저장 성공",
|
||||
"startTime": "시작 시간",
|
||||
"timeSlot": "시간 슬롯"
|
||||
},
|
||||
"group": {
|
||||
"actions": "작업",
|
||||
"cancel": "취소",
|
||||
"confirm": "확인",
|
||||
"confirmDelete": "삭제하시겠습니까?",
|
||||
"create": "생성",
|
||||
"createNodeGroup": "노드 그룹 생성",
|
||||
"createdSuccessfully": "성공적으로 생성되었습니다",
|
||||
"delete": "삭제",
|
||||
"deleteWarning": "삭제 후 데이터는 복구할 수 없으니 신중히 진행하세요.",
|
||||
"deletedSuccessfully": "성공적으로 삭제되었습니다",
|
||||
"description": "설명",
|
||||
"edit": "편집",
|
||||
"editNodeGroup": "노드 그룹 편집",
|
||||
"name": "이름",
|
||||
"title": "노드 그룹 목록",
|
||||
"updatedAt": "업데이트 시간"
|
||||
},
|
||||
"groupForm": {
|
||||
"cancel": "취소",
|
||||
"confirm": "확인",
|
||||
"description": "설명",
|
||||
"name": "이름"
|
||||
},
|
||||
"node": {
|
||||
"abnormal": "비정상",
|
||||
"actions": "작업",
|
||||
"address": "주소",
|
||||
"all": "전체",
|
||||
"basicInfo": "기본 정보",
|
||||
"cancel": "취소",
|
||||
"confirm": "확인",
|
||||
"confirmDelete": "삭제하시겠습니까?",
|
||||
"copy": "복사",
|
||||
"copySuccess": "성공적으로 복사되었습니다",
|
||||
"create": "생성",
|
||||
"createNode": "노드 생성",
|
||||
"createSuccess": "생성 성공",
|
||||
"delete": "삭제",
|
||||
"deleteSuccess": "삭제 성공",
|
||||
"deleteWarning": "삭제 후 데이터는 복구할 수 없습니다. 신중히 진행하세요.",
|
||||
"detail": "상세 정보",
|
||||
"disabled": "비활성화",
|
||||
"disk": "디스크",
|
||||
"edit": "편집",
|
||||
"editNode": "노드 편집",
|
||||
"enable": "활성화",
|
||||
"enabled": "활성화",
|
||||
"expireTime": "만료 시간",
|
||||
"hide": "숨기기",
|
||||
"id": "ID",
|
||||
"ipAddresses": "IP 주소",
|
||||
"lastUpdated": "마지막 업데이트",
|
||||
"location": "위치",
|
||||
"memory": "메모리",
|
||||
"name": "이름",
|
||||
"noData": "--",
|
||||
"node": "노드",
|
||||
"nodeDetail": "노드 상세 정보",
|
||||
"nodeGroup": "노드 그룹",
|
||||
"nodeStatus": "노드 상태",
|
||||
"normal": "정상",
|
||||
"onlineCount": "온라인 인원",
|
||||
"onlineUsers": "온라인 사용자",
|
||||
"protocol": "프로토콜",
|
||||
"rate": "비율",
|
||||
"relay": "중계",
|
||||
"serverAddr": "서버 주소",
|
||||
"speedLimit": "속도 제한",
|
||||
"status": "상태",
|
||||
"subscribeId": "구독 ID",
|
||||
"subscribeName": "구독 이름",
|
||||
"subscription": "구독",
|
||||
"tags": "태그",
|
||||
"trafficRatio": "트래픽 비율",
|
||||
"trafficUsage": "트래픽 사용량",
|
||||
"type": "유형",
|
||||
"updateSuccess": "업데이트 성공",
|
||||
"updatedAt": "업데이트 시간",
|
||||
"user": "사용자",
|
||||
"userDetail": "사용자 상세 정보",
|
||||
"userId": "사용자 ID"
|
||||
},
|
||||
"nodeForm": {
|
||||
"allowInsecure": "불안전 허용",
|
||||
"cancel": "취소",
|
||||
"city": "도시",
|
||||
"confirm": "확인",
|
||||
"congestionController": "혼잡 제어기",
|
||||
"country": "국가",
|
||||
"disableSni": "SNI 비활성화",
|
||||
"edit": "편집",
|
||||
"editSecurity": "보안 구성 편집",
|
||||
"enableTLS": "TLS 활성화",
|
||||
"encryptionMethod": "암호화 방법",
|
||||
"fingerprint": "지문",
|
||||
"flow": "흐름 제어 알고리즘",
|
||||
"groupId": "노드 그룹",
|
||||
"hopInterval": "홉 간격",
|
||||
"hopPorts": "홉 포트",
|
||||
"hopPortsPlaceholder": "여러 포트를 쉼표로 구분",
|
||||
"name": "이름",
|
||||
"obfsPassword": "난독화 비밀번호",
|
||||
"obfsPasswordPlaceholder": "난독화 없음은 비워두세요",
|
||||
"path": "경로",
|
||||
"pleaseSelect": "선택하세요",
|
||||
"port": "서버 포트",
|
||||
"protocol": "프로토콜",
|
||||
"reduceRtt": "RTT 줄이기",
|
||||
"relayHost": "릴레이 호스트",
|
||||
"relayMode": "릴레이 모드",
|
||||
"relayPort": "릴레이 포트",
|
||||
"relayPrefix": "릴레이 접두사",
|
||||
"remarks": "비고",
|
||||
"security": "보안",
|
||||
"securityConfig": "보안 구성",
|
||||
"selectEncryptionMethod": "암호화 방법 선택",
|
||||
"selectNodeGroup": "노드 그룹 선택",
|
||||
"selectProtocol": "프로토콜 선택",
|
||||
"selectRelayMode": "릴레이 모드 선택",
|
||||
"serverAddr": "서버 주소",
|
||||
"serverKey": "서버 키",
|
||||
"serverName": "서비스 이름",
|
||||
"speedLimit": "속도 제한",
|
||||
"speedLimitPlaceholder": "무제한",
|
||||
"tags": "태그",
|
||||
"tagsPlaceholder": "여러 태그 입력은 Enter 또는 쉼표(,) 사용",
|
||||
"trafficRatio": "트래픽 비율",
|
||||
"transport": "전송 프로토콜 구성",
|
||||
"transportConfig": "전송 프로토콜 구성",
|
||||
"transportHost": "전송 서버 주소",
|
||||
"transportPath": "전송 경로",
|
||||
"transportServerName": "전송 서버 이름",
|
||||
"udpRelayMode": "UDP 릴레이 모드"
|
||||
},
|
||||
"relayModeOptions": {
|
||||
"all": "모두",
|
||||
"none": "없음",
|
||||
"random": "무작위"
|
||||
},
|
||||
"securityConfig": {
|
||||
"fingerprint": "지문",
|
||||
"privateKey": "개인 키",
|
||||
"privateKeyPlaceholder": "자동 생성은 비워두세요",
|
||||
"publicKey": "공개 키",
|
||||
"publicKeyPlaceholder": "자동 생성은 비워두세요",
|
||||
"serverAddress": "서버 주소",
|
||||
"serverAddressPlaceholder": "REALITY 대상 주소, 기본 SNI 사용",
|
||||
"serverName": "서버 이름 (SNI)",
|
||||
"serverNamePlaceholder": "REALITY 필수, 백엔드와 일치",
|
||||
"serverPort": "서버 포트",
|
||||
"serverPortPlaceholder": "REALITY 대상 포트, 기본 443",
|
||||
"shortId": "짧은 ID",
|
||||
"shortIdPlaceholder": "자동 생성은 비워두세요",
|
||||
"sni": "서버 이름 표시 (SNI)"
|
||||
},
|
||||
"tabs": {
|
||||
"node": "노드",
|
||||
"nodeConfig": "노드 구성",
|
||||
"nodeGroup": "노드 그룹"
|
||||
}
|
||||
}
|
||||
101
apps/admin/locales/ko-KR/servers.json
Normal file
101
apps/admin/locales/ko-KR/servers.json
Normal file
@ -0,0 +1,101 @@
|
||||
{
|
||||
"address": "주소",
|
||||
"address_placeholder": "서버 주소",
|
||||
"cancel": "취소",
|
||||
"city": "도시",
|
||||
"config": {
|
||||
"actions": {
|
||||
"cancel": "취소",
|
||||
"save": "저장"
|
||||
},
|
||||
"communicationKey": "통신 키",
|
||||
"communicationKeyDescription": "노드 인증에 사용됩니다.",
|
||||
"description": "노드 통신 키, 풀/푸시 간격 및 동적 배수를 관리합니다.",
|
||||
"dynamicMultiplier": "동적 배수",
|
||||
"dynamicMultiplierDescription": "트래픽 회계를 조정하기 위한 시간 슬롯 및 배수를 정의합니다.",
|
||||
"endTime": "종료 시간",
|
||||
"inputPlaceholder": "입력해 주세요",
|
||||
"multiplier": "배수",
|
||||
"nodePullInterval": "노드 풀 간격",
|
||||
"nodePullIntervalDescription": "노드가 구성을 가져오는 빈도(초 단위).",
|
||||
"nodePushInterval": "노드 푸시 간격",
|
||||
"nodePushIntervalDescription": "노드가 통계를 푸시하는 빈도(초 단위).",
|
||||
"reset": "초기화",
|
||||
"save": "저장",
|
||||
"saveSuccess": "저장 성공",
|
||||
"startTime": "시작 시간",
|
||||
"timeSlot": "시간 슬롯",
|
||||
"title": "노드 구성"
|
||||
},
|
||||
"confirm": "확인",
|
||||
"confirmDeleteDesc": "이 작업은 실행 취소할 수 없습니다.",
|
||||
"confirmDeleteTitle": "이 서버를 삭제하시겠습니까?",
|
||||
"congestion_controller": "혼잡 제어기",
|
||||
"copied": "복사됨",
|
||||
"copy": "복사",
|
||||
"country": "국가",
|
||||
"cpu": "CPU",
|
||||
"create": "생성",
|
||||
"created": "성공적으로 생성됨",
|
||||
"delete": "삭제",
|
||||
"deleted": "성공적으로 삭제됨",
|
||||
"disable_sni": "SNI 비활성화",
|
||||
"disk": "디스크",
|
||||
"drawerCreateTitle": "서버 생성",
|
||||
"drawerEditTitle": "서버 편집",
|
||||
"edit": "편집",
|
||||
"enabled": "활성화됨",
|
||||
"encryption_method": "암호화 방법",
|
||||
"expireTime": "만료 시간",
|
||||
"expired": "만료됨",
|
||||
"flow": "흐름",
|
||||
"hop_interval": "홉 간격",
|
||||
"hop_ports": "홉 포트",
|
||||
"hop_ports_placeholder": "예: 1-65535",
|
||||
"host": "호스트",
|
||||
"id": "ID",
|
||||
"ipAddresses": "IP 주소",
|
||||
"memory": "메모리",
|
||||
"name": "이름",
|
||||
"noData": "데이터 없음",
|
||||
"notAvailable": "사용 불가",
|
||||
"obfs_password": "난독화 비밀번호",
|
||||
"obfs_password_placeholder": "난독화 비밀번호를 입력하세요",
|
||||
"offline": "오프라인",
|
||||
"online": "온라인",
|
||||
"onlineUsers": "온라인 사용자",
|
||||
"pageTitle": "서버",
|
||||
"path": "경로",
|
||||
"please_select": "선택해 주세요",
|
||||
"port": "포트",
|
||||
"protocols": "프로토콜",
|
||||
"reduce_rtt": "RTT 감소",
|
||||
"security_allow_insecure": "불안전 허용",
|
||||
"security_fingerprint": "지문",
|
||||
"security_private_key": "실제 개인 키",
|
||||
"security_private_key_placeholder": "개인 키를 입력하세요",
|
||||
"security_public_key": "실제 공개 키",
|
||||
"security_public_key_placeholder": "공개 키를 입력하세요",
|
||||
"security_server_address": "실제 서버 주소",
|
||||
"security_server_address_placeholder": "예: 1.2.3.4 또는 도메인",
|
||||
"security_server_port": "실제 서버 포트",
|
||||
"security_short_id": "실제 짧은 ID",
|
||||
"security_short_id_placeholder": "16자 이내의 헥스 문자열",
|
||||
"security_sni": "SNI",
|
||||
"security_title": "보안",
|
||||
"select_encryption_method": "암호화 방법 선택",
|
||||
"server_key": "서버 키",
|
||||
"service_name": "서비스 이름",
|
||||
"status": "상태",
|
||||
"subscribeId": "구독 ID",
|
||||
"subscription": "구독",
|
||||
"traffic": "트래픽",
|
||||
"traffic_ratio": "배수",
|
||||
"transport_title": "전송",
|
||||
"udp_relay_mode": "UDP 릴레이 모드",
|
||||
"unitSecondsShort": "초",
|
||||
"unlimited": "무제한",
|
||||
"updated": "성공적으로 업데이트됨",
|
||||
"user": "사용자",
|
||||
"validation_failed": "유효성 검사 실패. 양식을 확인하세요."
|
||||
}
|
||||
@ -1,27 +1,36 @@
|
||||
{
|
||||
"ADS Config": "ADS-konfigurasjon",
|
||||
"Announcement Management": "Kunngjøringsadministrasjon",
|
||||
"Application Management": "Applikasjonsadministrasjon",
|
||||
"Auth Control": "Autentiseringskontroll",
|
||||
"Balance": "Balanse",
|
||||
"Commerce": "Handel",
|
||||
"Commission": "Kommisjon",
|
||||
"Coupon Management": "Kupongadministrasjon",
|
||||
"Dashboard": "Dashbord",
|
||||
"Document Management": "Dokumenthåndtering",
|
||||
"Finance": "Finans",
|
||||
"Email": "E-post",
|
||||
"Gift": "Gave",
|
||||
"Login": "Logg inn",
|
||||
"Logs & Analytics": "Logger og analyser",
|
||||
"Maintenance": "Vedlikehold",
|
||||
"Marketing Management": "Markedsføringsledelse",
|
||||
"Node Management": "Nodeadministrasjon",
|
||||
"Order Management": "Bestillingsadministrasjon",
|
||||
"Payment Config": "Betalingskonfigurasjon",
|
||||
"Product Management": "Produktledelse",
|
||||
"Protocol Management": "Protokolladministrasjon",
|
||||
"Rule Management": "Regeladministrasjon",
|
||||
"Server": "Tjeneste",
|
||||
"Register": "Registrer",
|
||||
"Reset Subscribe": "Tilbakestill abonnement",
|
||||
"SMS": "SMS",
|
||||
"Server Management": "Serveradministrasjon",
|
||||
"Settings": "Innstillinger",
|
||||
"Server Traffic": "Servertrafikk",
|
||||
"Subscribe": "Abonner",
|
||||
"Subscribe Config": "Abonnementsinnstillinger",
|
||||
"Subscribe Traffic": "Abonnenttrafikk",
|
||||
"System": "System",
|
||||
"System Config": "Systemkonfigurasjon",
|
||||
"System Management": "Systemadministrasjon",
|
||||
"System Tool": "Systemverktøy",
|
||||
"Ticket Management": "Billettadministrasjon",
|
||||
"User": "Bruker",
|
||||
"User Detail": "Brukerdetaljer",
|
||||
"User Management": "Brukeradministrasjon"
|
||||
"User Management": "Brukeradministrasjon",
|
||||
"Users & Support": "Brukere og støtte"
|
||||
}
|
||||
|
||||
37
apps/admin/locales/no-NO/nodes.json
Normal file
37
apps/admin/locales/no-NO/nodes.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"address": "Adresse",
|
||||
"cancel": "Avbryt",
|
||||
"confirm": "Bekreft",
|
||||
"confirmDeleteDesc": "Denne handlingen kan ikke angres.",
|
||||
"confirmDeleteTitle": "Slette denne noden?",
|
||||
"copied": "Kopiert",
|
||||
"copy": "Kopier",
|
||||
"create": "Opprett",
|
||||
"created": "Opprettet",
|
||||
"delete": "Slett",
|
||||
"deleted": "Slettet",
|
||||
"drawerCreateTitle": "Opprett Node",
|
||||
"drawerEditTitle": "Rediger Node",
|
||||
"edit": "Rediger",
|
||||
"enabled": "Aktivert",
|
||||
"enabled_off": "Deaktivert",
|
||||
"enabled_on": "Aktivert",
|
||||
"errors": {
|
||||
"nameRequired": "Vennligst skriv inn et navn",
|
||||
"portRange": "Porten må være mellom 1 og 65535",
|
||||
"protocolRequired": "Vennligst velg en protokoll",
|
||||
"serverAddrRequired": "Vennligst skriv inn en adresse",
|
||||
"serverRequired": "Vennligst velg en server"
|
||||
},
|
||||
"name": "Navn",
|
||||
"pageTitle": "Noder",
|
||||
"port": "Port",
|
||||
"protocol": "Protokoll",
|
||||
"select_protocol": "Velg protokoll…",
|
||||
"select_server": "Velg server…",
|
||||
"server": "Server",
|
||||
"tags": "Tagger",
|
||||
"tags_description": "Tillatelsesgrupperingstagg (inkl. planbinding og leveringspolicyer).",
|
||||
"tags_placeholder": "Bruk Enter eller komma (,) for å legge til flere tagger",
|
||||
"updated": "Oppdatert"
|
||||
}
|
||||
@ -1,59 +1,6 @@
|
||||
{
|
||||
"actions": "handlinger",
|
||||
"app": {
|
||||
"appDownloadURL": "App Nedlastings-URL",
|
||||
"appIcon": "App-ikon",
|
||||
"appList": "Appliste",
|
||||
"appName": "App-navn",
|
||||
"backupDomains": "Sikkerhetskopidomener",
|
||||
"backupDomainsDescription": "Liste over sikkerhetskopidomener for domeneresolusjon, ett domene per linje",
|
||||
"batchDelete": "Slett i gruppe",
|
||||
"cancel": "Avbryt",
|
||||
"communicationKey": "Kommunikasjonsnøkkel",
|
||||
"communicationKeyDescription": "Nøkkel brukt for klientkommunikasjon",
|
||||
"config": "Konfigurasjon",
|
||||
"configApp": "Appkonfigurasjon",
|
||||
"confirm": "Bekreft",
|
||||
"confirmDelete": "Bekreft sletting",
|
||||
"create": "Opprett",
|
||||
"createApp": "Opprett app",
|
||||
"createSuccess": "Opprettet vellykket",
|
||||
"defaultVersion": "Standard",
|
||||
"delete": "Slett",
|
||||
"deleteWarning": "Denne handlingen kan ikke angres",
|
||||
"describeDescription": "Brukes til å beskrive applikasjonen, vises i applisten",
|
||||
"description": "Beskrivelse",
|
||||
"downloadLink": "Nedlastingslenke",
|
||||
"edit": "Rediger",
|
||||
"editApp": "Rediger app",
|
||||
"encryption": "Krypteringsmetode",
|
||||
"encryptionDescription": "Velg krypteringsmetoden for klientkommunikasjon. Hvis valgt, vil klienten bruke denne metoden for å kommunisere med serveren",
|
||||
"nameDescription": "Applikasjonsnavn, vises i applisten",
|
||||
"platform": "Plattform",
|
||||
"selectApp": "Velg App",
|
||||
"selectAppDescription": "Velg appen du vil konfigurere, alle innstillinger vil gjelde for den valgte appen",
|
||||
"startupPicture": "Oppstartsbilde",
|
||||
"startupPictureDescription": "Oppstartsbilde, støtter nettverks- og lokale bilder. For nettverksbilder, vennligst skriv inn den fullstendige bilde-URLen",
|
||||
"startupPicturePreview": "Forhåndsvisning av oppstartsbilde",
|
||||
"startupPictureSkip": "Tid for å hoppe over oppstartsbilde",
|
||||
"startupPictureSkipDescription": "Visningstid for oppstartsbilde i sekunder, skriv inn 0 for å ikke vise",
|
||||
"subscriptionProtocol": "Abonnementsprotokoll",
|
||||
"updateSuccess": "Oppdatert vellykket",
|
||||
"version": "Versjon"
|
||||
},
|
||||
"cancel": "Avbryt",
|
||||
"config": {
|
||||
"singleSubscriptionMode": "Enkelt Abonnementsmodus",
|
||||
"subscriptionDomain": "Abonnementsdomene",
|
||||
"subscriptionDomainDescription": "Brukes for abonnement; la stå tomt for å bruke nettstedets domene",
|
||||
"subscriptionDomainPlaceholder": "Skriv inn abonnementsdomene, ett per linje",
|
||||
"subscriptionPath": "Abonnementssti",
|
||||
"subscriptionPathDescription": "Brukes for abonnement; sørg for å starte systemet på nytt etter endring for optimal ytelse",
|
||||
"subscriptionPathPlaceholder": "Skriv inn",
|
||||
"updateSuccess": "Oppdatering vellykket",
|
||||
"wildcardResolution": "Jokertegnoppløsning",
|
||||
"wildcardResolutionDescription": "Brukes for abonnement"
|
||||
},
|
||||
"confirm": "Bekreft",
|
||||
"confirmDelete": "Er du sikker på at du vil slette?",
|
||||
"copy": "Kopier",
|
||||
@ -94,6 +41,9 @@
|
||||
"name": "Navn",
|
||||
"noLimit": "Ubegrenset",
|
||||
"noReset": "Ingen Tilbakestilling",
|
||||
"node": "Nod",
|
||||
"nodeGroup": "Nodgruppe",
|
||||
"nodes": "Noder",
|
||||
"pricing": "Prissetting",
|
||||
"purchaseWithDiscount": "Tillat Fradrag",
|
||||
"purchaseWithDiscountDescription": "Aktiver eller deaktiver funksjonaliteten for avmelding. Etter aktivering vil systemet utføre fradragsbehandling i henhold til de konfigurerte reglene og proporsjonene, og den gjenværende verdien vil bli returnert til saldoen",
|
||||
@ -106,9 +56,6 @@
|
||||
"selectResetCycle": "Vennligst velg en tilbakestillingssyklus",
|
||||
"selectSubscribeGroup": "Vennligst velg abonnementsgruppe",
|
||||
"selectUnitTime": "Vennligst velg enhetstid",
|
||||
"server": "Tjeneste",
|
||||
"serverGroup": "Tjenestegruppe",
|
||||
"servers": "Servere",
|
||||
"speedLimit": "Hastighetsbegrensning ",
|
||||
"traffic": "Trafikk",
|
||||
"unitPrice": "Enhetspris",
|
||||
@ -150,8 +97,6 @@
|
||||
"subscribeGroup": "Abonner på gruppe",
|
||||
"tabs": {
|
||||
"subscribe": "Abonner",
|
||||
"subscribeApp": "App-konfigurasjon",
|
||||
"subscribeConfig": "Abonnementskonfigurasjon",
|
||||
"subscribeGroup": "Abonner gruppe"
|
||||
},
|
||||
"traffic": "trafikk",
|
||||
|
||||
@ -1,183 +0,0 @@
|
||||
{
|
||||
"config": {
|
||||
"addTimeSlot": "Legg til tidsluke",
|
||||
"communicationKey": "Kommunikasjonsnøkkel",
|
||||
"communicationKeyDescription": "Nøkkel for nodekommunikasjon for å sikre datasikkerhet",
|
||||
"delete": "Slett",
|
||||
"dynamicMultiplier": "Dynamisk multiplikator",
|
||||
"dynamicMultiplierDescription": "Dynamisk multiplikator refererer til behandling av dyttet data med forskjellige multiplikatorer for forskjellige noder i ulike tidsperioder.",
|
||||
"endTime": "Sluttid",
|
||||
"inputPlaceholder": "Skriv inn",
|
||||
"multiplier": "Multiplikator",
|
||||
"nodePullInterval": "Node hentingsintervall",
|
||||
"nodePullIntervalDescription": "Frekvens (i sekunder) for noder å hente data fra panelet",
|
||||
"nodePushInterval": "Node dyttingsintervall",
|
||||
"nodePushIntervalDescription": "Frekvens for noder å dytte data til panelet",
|
||||
"reset": "Tilbakestill",
|
||||
"save": "Lagre",
|
||||
"saveSuccess": "Lagret vellykket",
|
||||
"startTime": "Starttid",
|
||||
"timeSlot": "Tidsluke"
|
||||
},
|
||||
"group": {
|
||||
"actions": "Handlinger",
|
||||
"cancel": "Avbryt",
|
||||
"confirm": "Bekreft",
|
||||
"confirmDelete": "Er du sikker på at du vil slette?",
|
||||
"create": "Opprett",
|
||||
"createNodeGroup": "Opprett nodegruppe",
|
||||
"createdSuccessfully": "Opprettet vellykket",
|
||||
"delete": "Slett",
|
||||
"deleteWarning": "Data kan ikke gjenopprettes etter sletting, vær forsiktig.",
|
||||
"deletedSuccessfully": "Slettet vellykket",
|
||||
"description": "Beskrivelse",
|
||||
"edit": "Rediger",
|
||||
"editNodeGroup": "Rediger nodegruppe",
|
||||
"name": "Navn",
|
||||
"title": "Nodegruppeliste",
|
||||
"updatedAt": "Oppdatert"
|
||||
},
|
||||
"groupForm": {
|
||||
"cancel": "Avbryt",
|
||||
"confirm": "Bekreft",
|
||||
"description": "Beskrivelse",
|
||||
"name": "Navn"
|
||||
},
|
||||
"node": {
|
||||
"abnormal": "Unormal",
|
||||
"actions": "Handlinger",
|
||||
"address": "Adresse",
|
||||
"all": "Alle",
|
||||
"basicInfo": "Grunnleggende info",
|
||||
"cancel": "Avbryt",
|
||||
"confirm": "Bekreft",
|
||||
"confirmDelete": "Er du sikker på at du vil slette?",
|
||||
"copy": "Kopier",
|
||||
"copySuccess": "Kopiert med suksess",
|
||||
"create": "Opprett",
|
||||
"createNode": "Opprett node",
|
||||
"createSuccess": "Opprettelse vellykket",
|
||||
"delete": "Slett",
|
||||
"deleteSuccess": "Sletting vellykket",
|
||||
"deleteWarning": "Etter sletting kan data ikke gjenopprettes. Vennligst vær forsiktig.",
|
||||
"detail": "Detalj",
|
||||
"disabled": "Deaktivert",
|
||||
"disk": "Disk",
|
||||
"edit": "Rediger",
|
||||
"editNode": "Rediger node",
|
||||
"enable": "Aktiver",
|
||||
"enabled": "Aktivert",
|
||||
"expireTime": "Utløpstid",
|
||||
"hide": "Skjul",
|
||||
"id": "ID",
|
||||
"ipAddresses": "IP-adresser",
|
||||
"lastUpdated": "Sist oppdatert",
|
||||
"location": "Plassering",
|
||||
"memory": "Minne",
|
||||
"name": "Navn",
|
||||
"noData": "--",
|
||||
"node": "Node",
|
||||
"nodeDetail": "Node-detalj",
|
||||
"nodeGroup": "Nodegruppe",
|
||||
"nodeStatus": "Node-status",
|
||||
"normal": "Normal",
|
||||
"onlineCount": "Antall online",
|
||||
"onlineUsers": "Online brukere",
|
||||
"protocol": "Protokoll",
|
||||
"rate": "Hastighet",
|
||||
"relay": "Relé",
|
||||
"serverAddr": "Serveradresse",
|
||||
"speedLimit": "Hastighetsbegrensning",
|
||||
"status": "Status",
|
||||
"subscribeId": "Abonnements-ID",
|
||||
"subscribeName": "Abonnementsnavn",
|
||||
"subscription": "Abonnement",
|
||||
"tags": "Merker",
|
||||
"trafficRatio": "Trafikkhastighet",
|
||||
"trafficUsage": "Trafikkbruk",
|
||||
"type": "Type",
|
||||
"updateSuccess": "Oppdatering vellykket",
|
||||
"updatedAt": "Oppdatert kl",
|
||||
"user": "Bruker",
|
||||
"userDetail": "Brukerdetalj",
|
||||
"userId": "Bruker-ID"
|
||||
},
|
||||
"nodeForm": {
|
||||
"allowInsecure": "Tillat usikker",
|
||||
"cancel": "Avbryt",
|
||||
"city": "By",
|
||||
"confirm": "Bekreft",
|
||||
"congestionController": "Kongestion Controller",
|
||||
"country": "Land",
|
||||
"disableSni": "Deaktiver SNI",
|
||||
"edit": "Rediger",
|
||||
"editSecurity": "Rediger sikkerhetskonfigurasjon",
|
||||
"enableTLS": "Aktiver TLS",
|
||||
"encryptionMethod": "Krypteringsmetode",
|
||||
"fingerprint": "Fingeravtrykk",
|
||||
"flow": "Flytkontrollalgoritme",
|
||||
"groupId": "Nodegruppe",
|
||||
"hopInterval": "Hoppintervall",
|
||||
"hopPorts": "Hoppporter",
|
||||
"hopPortsPlaceholder": "Skille flere porter med komma",
|
||||
"name": "Navn",
|
||||
"obfsPassword": "Obfuskasjonspassord",
|
||||
"obfsPasswordPlaceholder": "La stå tomt for ingen obfuskasjon",
|
||||
"path": "Sti",
|
||||
"pleaseSelect": "Vennligst velg",
|
||||
"port": "Serverport",
|
||||
"protocol": "Protokoll",
|
||||
"reduceRtt": "Reduser RTT",
|
||||
"relayHost": "Relayvert",
|
||||
"relayMode": "Relay-modus",
|
||||
"relayPort": "Relay-port",
|
||||
"relayPrefix": "Relay-prefiks",
|
||||
"remarks": "Merknader",
|
||||
"security": "Sikkerhet",
|
||||
"securityConfig": "Sikkerhetskonfigurasjon",
|
||||
"selectEncryptionMethod": "Velg krypteringsmetode",
|
||||
"selectNodeGroup": "Velg nodegruppe",
|
||||
"selectProtocol": "Velg protokoll",
|
||||
"selectRelayMode": "Velg relay-modus",
|
||||
"serverAddr": "Serveradresse",
|
||||
"serverKey": "Servernøkkel",
|
||||
"serverName": "Tjenestenavn",
|
||||
"speedLimit": "Hastighetsgrense",
|
||||
"speedLimitPlaceholder": "Ubegrenset",
|
||||
"tags": "Tags",
|
||||
"tagsPlaceholder": "Bruk Enter eller komma (,) for å legge til flere tags",
|
||||
"trafficRatio": "Trafikkforhold",
|
||||
"transport": "Transportprotokollkonfigurasjon",
|
||||
"transportConfig": "Transportprotokollkonfigurasjon",
|
||||
"transportHost": "Transportserveradresse",
|
||||
"transportPath": "Transportsti",
|
||||
"transportServerName": "Transportservernavn",
|
||||
"udpRelayMode": "UDP Relay-modus"
|
||||
},
|
||||
"relayModeOptions": {
|
||||
"all": "Alle",
|
||||
"none": "Ingen",
|
||||
"random": "Tilfeldig"
|
||||
},
|
||||
"securityConfig": {
|
||||
"fingerprint": "Fingeravtrykk",
|
||||
"privateKey": "Privat nøkkel",
|
||||
"privateKeyPlaceholder": "La stå tomt for automatisk generering",
|
||||
"publicKey": "Offentlig nøkkel",
|
||||
"publicKeyPlaceholder": "La stå tomt for automatisk generering",
|
||||
"serverAddress": "Serveradresse",
|
||||
"serverAddressPlaceholder": "REALITY måladresse, standard bruker SNI",
|
||||
"serverName": "Servernavn (SNI)",
|
||||
"serverNamePlaceholder": "REALITY påkrevd, konsistent med backend",
|
||||
"serverPort": "Serverport",
|
||||
"serverPortPlaceholder": "REALITY målport, standard 443",
|
||||
"shortId": "Kort ID",
|
||||
"shortIdPlaceholder": "La stå tomt for automatisk generering",
|
||||
"sni": "Servernavnindikasjon (SNI)"
|
||||
},
|
||||
"tabs": {
|
||||
"node": "Node",
|
||||
"nodeConfig": "Node-konfigurasjon",
|
||||
"nodeGroup": "Nodegruppe"
|
||||
}
|
||||
}
|
||||
101
apps/admin/locales/no-NO/servers.json
Normal file
101
apps/admin/locales/no-NO/servers.json
Normal file
@ -0,0 +1,101 @@
|
||||
{
|
||||
"address": "Adresse",
|
||||
"address_placeholder": "Serveradresse",
|
||||
"cancel": "Avbryt",
|
||||
"city": "By",
|
||||
"config": {
|
||||
"actions": {
|
||||
"cancel": "Avbryt",
|
||||
"save": "Lagre"
|
||||
},
|
||||
"communicationKey": "Kommunikasjonsnøkkel",
|
||||
"communicationKeyDescription": "Brukes for nodeautentisering.",
|
||||
"description": "Administrer nodekommunikasjonsnøkler, pull/push-intervaller og dynamiske multiplikatorer.",
|
||||
"dynamicMultiplier": "Dynamisk multiplikator",
|
||||
"dynamicMultiplierDescription": "Definer tidsluker og multiplikatorer for å justere trafikkregnskap.",
|
||||
"endTime": "Sluttid",
|
||||
"inputPlaceholder": "Vennligst skriv inn",
|
||||
"multiplier": "Multiplikator",
|
||||
"nodePullInterval": "Node pull-intervall",
|
||||
"nodePullIntervalDescription": "Hvor ofte noden henter konfigurasjon (sekunder).",
|
||||
"nodePushInterval": "Node push-intervall",
|
||||
"nodePushIntervalDescription": "Hvor ofte noden sender statistikk (sekunder).",
|
||||
"reset": "Tilbakestill",
|
||||
"save": "Lagre",
|
||||
"saveSuccess": "Lagring vellykket",
|
||||
"startTime": "Starttid",
|
||||
"timeSlot": "Tidsluke",
|
||||
"title": "Nodekonfigurasjon"
|
||||
},
|
||||
"confirm": "Bekreft",
|
||||
"confirmDeleteDesc": "Denne handlingen kan ikke angres.",
|
||||
"confirmDeleteTitle": "Slette denne serveren?",
|
||||
"congestion_controller": "Kongestjonskontroller",
|
||||
"copied": "Kopiert",
|
||||
"copy": "Kopier",
|
||||
"country": "Land",
|
||||
"cpu": "CPU",
|
||||
"create": "Opprett",
|
||||
"created": "Opprettet vellykket",
|
||||
"delete": "Slett",
|
||||
"deleted": "Slettet vellykket",
|
||||
"disable_sni": "Deaktiver SNI",
|
||||
"disk": "Disk",
|
||||
"drawerCreateTitle": "Opprett server",
|
||||
"drawerEditTitle": "Rediger server",
|
||||
"edit": "Rediger",
|
||||
"enabled": "Aktivert",
|
||||
"encryption_method": "Krypteringsmetode",
|
||||
"expireTime": "Utløpstid",
|
||||
"expired": "Utløpt",
|
||||
"flow": "Flyt",
|
||||
"hop_interval": "Hoppintervall",
|
||||
"hop_ports": "Hoppporter",
|
||||
"hop_ports_placeholder": "f.eks. 1-65535",
|
||||
"host": "Vert",
|
||||
"id": "ID",
|
||||
"ipAddresses": "IP-adresser",
|
||||
"memory": "Minne",
|
||||
"name": "Navn",
|
||||
"noData": "Ingen data",
|
||||
"notAvailable": "Ikke tilgjengelig",
|
||||
"obfs_password": "Obfuskasjonspassord",
|
||||
"obfs_password_placeholder": "Skriv inn obfuskasjonspassord",
|
||||
"offline": "Frakoblet",
|
||||
"online": "På nett",
|
||||
"onlineUsers": "Brukere på nett",
|
||||
"pageTitle": "Servere",
|
||||
"path": "Sti",
|
||||
"please_select": "Vennligst velg",
|
||||
"port": "Port",
|
||||
"protocols": "Protokoller",
|
||||
"reduce_rtt": "Reduser RTT",
|
||||
"security_allow_insecure": "Tillat usikker",
|
||||
"security_fingerprint": "Fingeravtrykk",
|
||||
"security_private_key": "Privat nøkkel",
|
||||
"security_private_key_placeholder": "Skriv inn privat nøkkel",
|
||||
"security_public_key": "Offentlig nøkkel",
|
||||
"security_public_key_placeholder": "Skriv inn offentlig nøkkel",
|
||||
"security_server_address": "Serveradresse",
|
||||
"security_server_address_placeholder": "f.eks. 1.2.3.4 eller domene",
|
||||
"security_server_port": "Serverport",
|
||||
"security_short_id": "Kort ID",
|
||||
"security_short_id_placeholder": "Hex-streng (opptil 16 tegn)",
|
||||
"security_sni": "SNI",
|
||||
"security_title": "Sikkerhet",
|
||||
"select_encryption_method": "Velg krypteringsmetode",
|
||||
"server_key": "Servernøkkel",
|
||||
"service_name": "Tjenestenavn",
|
||||
"status": "Status",
|
||||
"subscribeId": "Abonnements-ID",
|
||||
"subscription": "Abonnement",
|
||||
"traffic": "Trafikk",
|
||||
"traffic_ratio": "Multiplikator",
|
||||
"transport_title": "Transport",
|
||||
"udp_relay_mode": "UDP relémodus",
|
||||
"unitSecondsShort": "S",
|
||||
"unlimited": "Ubegrenset",
|
||||
"updated": "Oppdatert vellykket",
|
||||
"user": "Bruker",
|
||||
"validation_failed": "Validering feilet. Vennligst sjekk skjemaet."
|
||||
}
|
||||
@ -1,27 +1,36 @@
|
||||
{
|
||||
"ADS Config": "Konfiguracja ADS",
|
||||
"Announcement Management": "Zarządzanie ogłoszeniami",
|
||||
"Application Management": "Zarządzanie aplikacjami",
|
||||
"Auth Control": "Kontrola autoryzacji",
|
||||
"Balance": "Saldo",
|
||||
"Commerce": "Handel",
|
||||
"Commission": "Prowizja",
|
||||
"Coupon Management": "Zarządzanie kuponami",
|
||||
"Dashboard": "Pulpit",
|
||||
"Document Management": "Zarządzanie dokumentami",
|
||||
"Finance": "Finanse",
|
||||
"Email": "Email",
|
||||
"Gift": "Prezent",
|
||||
"Login": "Zaloguj się",
|
||||
"Logs & Analytics": "Dzienniki i analityka",
|
||||
"Maintenance": "Utrzymanie",
|
||||
"Marketing Management": "Zarządzanie Marketingiem",
|
||||
"Node Management": "Zarządzanie węzłami",
|
||||
"Order Management": "Zarządzanie zamówieniami",
|
||||
"Payment Config": "Konfiguracja płatności",
|
||||
"Product Management": "Zarządzanie Produktem",
|
||||
"Protocol Management": "Zarządzanie Protokołem",
|
||||
"Rule Management": "Zarządzanie regułami",
|
||||
"Server": "Serwer",
|
||||
"Register": "Zarejestruj się",
|
||||
"Reset Subscribe": "Zresetuj subskrypcję",
|
||||
"SMS": "SMS",
|
||||
"Server Management": "Zarządzanie serwerem",
|
||||
"Settings": "Ustawienia",
|
||||
"Server Traffic": "Ruch serwera",
|
||||
"Subscribe": "Subskrybuj",
|
||||
"Subscribe Config": "Konfiguracja subskrypcji",
|
||||
"Subscribe Traffic": "Ruch subskrypcyjny",
|
||||
"System": "System",
|
||||
"System Config": "Konfiguracja systemu",
|
||||
"System Management": "Zarządzanie systemem",
|
||||
"System Tool": "Narzędzie systemowe",
|
||||
"Ticket Management": "Zarządzanie zgłoszeniami",
|
||||
"User": "Użytkownik",
|
||||
"User Detail": "Szczegóły użytkownika",
|
||||
"User Management": "Zarządzanie użytkownikami"
|
||||
"User Management": "Zarządzanie użytkownikami",
|
||||
"Users & Support": "Użytkownicy i wsparcie"
|
||||
}
|
||||
|
||||
37
apps/admin/locales/pl-PL/nodes.json
Normal file
37
apps/admin/locales/pl-PL/nodes.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"address": "Adres",
|
||||
"cancel": "Anuluj",
|
||||
"confirm": "Potwierdź",
|
||||
"confirmDeleteDesc": "Ta akcja nie może być cofnięta.",
|
||||
"confirmDeleteTitle": "Usunąć ten węzeł?",
|
||||
"copied": "Skopiowano",
|
||||
"copy": "Kopiuj",
|
||||
"create": "Utwórz",
|
||||
"created": "Utworzono",
|
||||
"delete": "Usuń",
|
||||
"deleted": "Usunięto",
|
||||
"drawerCreateTitle": "Utwórz węzeł",
|
||||
"drawerEditTitle": "Edytuj węzeł",
|
||||
"edit": "Edytuj",
|
||||
"enabled": "Włączony",
|
||||
"enabled_off": "Wyłączony",
|
||||
"enabled_on": "Włączony",
|
||||
"errors": {
|
||||
"nameRequired": "Proszę wpisać nazwę",
|
||||
"portRange": "Port musi być w zakresie od 1 do 65535",
|
||||
"protocolRequired": "Proszę wybrać protokół",
|
||||
"serverAddrRequired": "Proszę wpisać adres wejściowy",
|
||||
"serverRequired": "Proszę wybrać serwer"
|
||||
},
|
||||
"name": "Nazwa",
|
||||
"pageTitle": "Węzły",
|
||||
"port": "Port",
|
||||
"protocol": "Protokół",
|
||||
"select_protocol": "Wybierz protokół…",
|
||||
"select_server": "Wybierz serwer…",
|
||||
"server": "Serwer",
|
||||
"tags": "Tagi",
|
||||
"tags_description": "Tag grupujący uprawnienia (w tym powiązania planu i polityki dostarczania).",
|
||||
"tags_placeholder": "Użyj Enter lub przecinka (,) aby dodać wiele tagów",
|
||||
"updated": "Zaktualizowano"
|
||||
}
|
||||
@ -1,59 +1,6 @@
|
||||
{
|
||||
"actions": "działania",
|
||||
"app": {
|
||||
"appDownloadURL": "URL pobierania aplikacji",
|
||||
"appIcon": "Ikona aplikacji",
|
||||
"appList": "Lista aplikacji",
|
||||
"appName": "Nazwa aplikacji",
|
||||
"backupDomains": "Lista domen zapasowych",
|
||||
"backupDomainsDescription": "Lista domen zapasowych do rozwiązywania domen, jedna domena na linię",
|
||||
"batchDelete": "Usuń zbiorczo",
|
||||
"cancel": "Anuluj",
|
||||
"communicationKey": "Klucz komunikacyjny",
|
||||
"communicationKeyDescription": "Klucz używany do komunikacji z klientem",
|
||||
"config": "Konfiguracja",
|
||||
"configApp": "Konfiguracja aplikacji",
|
||||
"confirm": "Potwierdź",
|
||||
"confirmDelete": "Potwierdź usunięcie",
|
||||
"create": "Utwórz",
|
||||
"createApp": "Utwórz aplikację",
|
||||
"createSuccess": "Utworzono pomyślnie",
|
||||
"defaultVersion": "Domyślna",
|
||||
"delete": "Usuń",
|
||||
"deleteWarning": "Tej operacji nie można cofnąć",
|
||||
"describeDescription": "Służy do opisu aplikacji, wyświetlany na liście aplikacji",
|
||||
"description": "Opis",
|
||||
"downloadLink": "Link do pobrania",
|
||||
"edit": "Edytuj",
|
||||
"editApp": "Edytuj aplikację",
|
||||
"encryption": "Metoda szyfrowania",
|
||||
"encryptionDescription": "Wybierz metodę szyfrowania dla komunikacji z klientem. Jeśli zostanie wybrana, klient będzie używał tej metody do komunikacji z serwerem",
|
||||
"nameDescription": "Nazwa aplikacji, wyświetlana na liście aplikacji",
|
||||
"platform": "Platforma",
|
||||
"selectApp": "Wybierz aplikację",
|
||||
"selectAppDescription": "Wybierz aplikację do skonfigurowania, wszystkie ustawienia będą dotyczyć wybranej aplikacji",
|
||||
"startupPicture": "Obraz startowy",
|
||||
"startupPictureDescription": "Obraz startowy, obsługuje obrazy sieciowe i lokalne. Dla obrazów sieciowych, proszę wprowadzić pełny URL obrazu",
|
||||
"startupPicturePreview": "Podgląd obrazu startowego",
|
||||
"startupPictureSkip": "Czas pominięcia obrazu startowego",
|
||||
"startupPictureSkipDescription": "Czas wyświetlania obrazu startowego w sekundach, wprowadź 0, aby nie wyświetlać",
|
||||
"subscriptionProtocol": "Protokół subskrypcji",
|
||||
"updateSuccess": "Zaktualizowano pomyślnie",
|
||||
"version": "Wersja"
|
||||
},
|
||||
"cancel": "Anuluj",
|
||||
"config": {
|
||||
"singleSubscriptionMode": "Tryb pojedynczej subskrypcji",
|
||||
"subscriptionDomain": "Domena subskrypcji",
|
||||
"subscriptionDomainDescription": "Używane do subskrypcji; pozostaw puste, aby użyć domeny witryny",
|
||||
"subscriptionDomainPlaceholder": "Wprowadź domenę subskrypcji, jedna na linię",
|
||||
"subscriptionPath": "Ścieżka subskrypcji",
|
||||
"subscriptionPathDescription": "Używane do subskrypcji; upewnij się, że zrestartujesz system po modyfikacji dla optymalnej wydajności",
|
||||
"subscriptionPathPlaceholder": "Wprowadź",
|
||||
"updateSuccess": "Zaktualizowano pomyślnie",
|
||||
"wildcardResolution": "Rozwiązanie wieloznaczne",
|
||||
"wildcardResolutionDescription": "Używane do subskrypcji"
|
||||
},
|
||||
"confirm": "Potwierdź",
|
||||
"confirmDelete": "Czy na pewno chcesz usunąć?",
|
||||
"copy": "Kopiuj",
|
||||
@ -94,6 +41,9 @@
|
||||
"name": "Nazwa",
|
||||
"noLimit": "Bez ograniczeń",
|
||||
"noReset": "Brak Resetu",
|
||||
"node": "Węzeł",
|
||||
"nodeGroup": "Grupa węzłów",
|
||||
"nodes": "Węzły",
|
||||
"pricing": "Cennik",
|
||||
"purchaseWithDiscount": "Zezwól na Potrącenie",
|
||||
"purchaseWithDiscountDescription": "Włącz lub wyłącz funkcję rezygnacji z subskrypcji. Po aktywacji system przeprowadzi proces odliczenia zgodnie z skonfigurowanymi zasadami i proporcjami, a pozostała wartość zostanie zwrócona na saldo",
|
||||
@ -106,9 +56,6 @@
|
||||
"selectResetCycle": "Proszę wybrać cykl resetowania",
|
||||
"selectSubscribeGroup": "Wybierz grupę subskrypcji",
|
||||
"selectUnitTime": "Proszę wybrać jednostkę czasu",
|
||||
"server": "Serwer",
|
||||
"serverGroup": "Grupa serwerów",
|
||||
"servers": "Serwery",
|
||||
"speedLimit": "Limit prędkości ",
|
||||
"traffic": "Ruch",
|
||||
"unitPrice": "Cena jednostkowa",
|
||||
@ -150,8 +97,6 @@
|
||||
"subscribeGroup": "Subskrybuj grupę",
|
||||
"tabs": {
|
||||
"subscribe": "Subskrybuj",
|
||||
"subscribeApp": "Konfiguracja aplikacji",
|
||||
"subscribeConfig": "Konfiguracja subskrypcji",
|
||||
"subscribeGroup": "Grupa subskrypcji"
|
||||
},
|
||||
"traffic": "ruch",
|
||||
|
||||
@ -1,183 +0,0 @@
|
||||
{
|
||||
"config": {
|
||||
"addTimeSlot": "Dodaj przedział czasowy",
|
||||
"communicationKey": "Klucz komunikacyjny",
|
||||
"communicationKeyDescription": "Klucz do komunikacji węzłów w celu zapewnienia bezpieczeństwa danych",
|
||||
"delete": "Usuń",
|
||||
"dynamicMultiplier": "Mnożnik dynamiczny",
|
||||
"dynamicMultiplierDescription": "Mnożnik dynamiczny odnosi się do przetwarzania przesyłanych danych z różnymi mnożnikami dla różnych węzłów w różnych okresach czasu.",
|
||||
"endTime": "Czas zakończenia",
|
||||
"inputPlaceholder": "Wprowadź",
|
||||
"multiplier": "Mnożnik",
|
||||
"nodePullInterval": "Interwał pobierania węzła",
|
||||
"nodePullIntervalDescription": "Częstotliwość (w sekundach) pobierania danych przez węzły z panelu",
|
||||
"nodePushInterval": "Interwał przesyłania węzła",
|
||||
"nodePushIntervalDescription": "Częstotliwość przesyłania danych przez węzły do panelu",
|
||||
"reset": "Resetuj",
|
||||
"save": "Zapisz",
|
||||
"saveSuccess": "Zapisano pomyślnie",
|
||||
"startTime": "Czas rozpoczęcia",
|
||||
"timeSlot": "Przedział czasowy"
|
||||
},
|
||||
"group": {
|
||||
"actions": "Operacje",
|
||||
"cancel": "Anuluj",
|
||||
"confirm": "Potwierdź",
|
||||
"confirmDelete": "Czy na pewno chcesz usunąć?",
|
||||
"create": "Utwórz",
|
||||
"createNodeGroup": "Utwórz grupę węzłów",
|
||||
"createdSuccessfully": "Utworzono pomyślnie",
|
||||
"delete": "Usuń",
|
||||
"deleteWarning": "Po usunięciu dane nie będą mogły zostać odzyskane, proszę postępować ostrożnie.",
|
||||
"deletedSuccessfully": "Usunięto pomyślnie",
|
||||
"description": "Opis",
|
||||
"edit": "Edytuj",
|
||||
"editNodeGroup": "Edytuj grupę węzłów",
|
||||
"name": "Nazwa",
|
||||
"title": "Lista grup węzłów",
|
||||
"updatedAt": "Czas aktualizacji"
|
||||
},
|
||||
"groupForm": {
|
||||
"cancel": "Anuluj",
|
||||
"confirm": "Potwierdź",
|
||||
"description": "Opis",
|
||||
"name": "Nazwa"
|
||||
},
|
||||
"node": {
|
||||
"abnormal": "Nieprawidłowy",
|
||||
"actions": "Działania",
|
||||
"address": "Adres",
|
||||
"all": "Wszystko",
|
||||
"basicInfo": "Podstawowe informacje",
|
||||
"cancel": "Anuluj",
|
||||
"confirm": "Potwierdź",
|
||||
"confirmDelete": "Czy na pewno chcesz usunąć?",
|
||||
"copy": "Kopiuj",
|
||||
"copySuccess": "Skopiowano pomyślnie",
|
||||
"create": "Utwórz",
|
||||
"createNode": "Utwórz węzeł",
|
||||
"createSuccess": "Utworzono pomyślnie",
|
||||
"delete": "Usuń",
|
||||
"deleteSuccess": "Usunięto pomyślnie",
|
||||
"deleteWarning": "Po usunięciu dane nie będą mogły zostać odzyskane. Proszę postępować ostrożnie.",
|
||||
"detail": "Szczegóły",
|
||||
"disabled": "Wyłączone",
|
||||
"disk": "Dysk",
|
||||
"edit": "Edytuj",
|
||||
"editNode": "Edytuj węzeł",
|
||||
"enable": "Włącz",
|
||||
"enabled": "Włączone",
|
||||
"expireTime": "Czas wygaśnięcia",
|
||||
"hide": "Ukryj",
|
||||
"id": "ID",
|
||||
"ipAddresses": "Adresy IP",
|
||||
"lastUpdated": "Ostatnia aktualizacja",
|
||||
"location": "Lokalizacja",
|
||||
"memory": "Pamięć",
|
||||
"name": "Nazwa",
|
||||
"noData": "--",
|
||||
"node": "Węzeł",
|
||||
"nodeDetail": "Szczegóły węzła",
|
||||
"nodeGroup": "Grupa węzłów",
|
||||
"nodeStatus": "Status węzła",
|
||||
"normal": "Normalny",
|
||||
"onlineCount": "Liczba osób online",
|
||||
"onlineUsers": "Użytkownicy online",
|
||||
"protocol": "Protokół",
|
||||
"rate": "Stawka",
|
||||
"relay": "Przekaźnik",
|
||||
"serverAddr": "Adres serwera",
|
||||
"speedLimit": "Ograniczenie prędkości",
|
||||
"status": "Status",
|
||||
"subscribeId": "ID subskrypcji",
|
||||
"subscribeName": "Nazwa subskrypcji",
|
||||
"subscription": "Subskrypcja",
|
||||
"tags": "Tagi",
|
||||
"trafficRatio": "Wskaźnik ruchu",
|
||||
"trafficUsage": "Użycie ruchu",
|
||||
"type": "Typ",
|
||||
"updateSuccess": "Aktualizacja zakończona pomyślnie",
|
||||
"updatedAt": "Czas aktualizacji",
|
||||
"user": "Użytkownik",
|
||||
"userDetail": "Szczegóły użytkownika",
|
||||
"userId": "ID użytkownika"
|
||||
},
|
||||
"nodeForm": {
|
||||
"allowInsecure": "Zezwól na niebezpieczne połączenia",
|
||||
"cancel": "Anuluj",
|
||||
"city": "Miasto",
|
||||
"confirm": "Potwierdź",
|
||||
"congestionController": "Kontroler przeciążenia",
|
||||
"country": "Kraj",
|
||||
"disableSni": "Wyłącz SNI",
|
||||
"edit": "Edytuj",
|
||||
"editSecurity": "Edytuj konfigurację zabezpieczeń",
|
||||
"enableTLS": "Włącz TLS",
|
||||
"encryptionMethod": "Metoda szyfrowania",
|
||||
"fingerprint": "Odcisk palca",
|
||||
"flow": "Algorytm kontroli przepływu",
|
||||
"groupId": "Grupa węzłów",
|
||||
"hopInterval": "Interwał skoków",
|
||||
"hopPorts": "Porty skoków",
|
||||
"hopPortsPlaceholder": "Oddziel wiele portów przecinkami",
|
||||
"name": "Nazwa",
|
||||
"obfsPassword": "Hasło obfuskacji",
|
||||
"obfsPasswordPlaceholder": "Pozostaw puste, aby nie stosować obfuskacji",
|
||||
"path": "Ścieżka",
|
||||
"pleaseSelect": "Proszę wybrać",
|
||||
"port": "Port serwera",
|
||||
"protocol": "Protokół",
|
||||
"reduceRtt": "Zredukuj RTT",
|
||||
"relayHost": "Host przekaźnika",
|
||||
"relayMode": "Tryb przekaźnika",
|
||||
"relayPort": "Port przekaźnika",
|
||||
"relayPrefix": "Prefiks przekaźnika",
|
||||
"remarks": "Uwagi",
|
||||
"security": "Zabezpieczenia",
|
||||
"securityConfig": "Konfiguracja zabezpieczeń",
|
||||
"selectEncryptionMethod": "Wybierz metodę szyfrowania",
|
||||
"selectNodeGroup": "Wybierz grupę węzłów",
|
||||
"selectProtocol": "Wybierz protokół",
|
||||
"selectRelayMode": "Wybierz tryb przekaźnika",
|
||||
"serverAddr": "Adres serwera",
|
||||
"serverKey": "Klucz serwera",
|
||||
"serverName": "Nazwa usługi",
|
||||
"speedLimit": "Limit prędkości",
|
||||
"speedLimitPlaceholder": "Nieograniczony",
|
||||
"tags": "Tagi",
|
||||
"tagsPlaceholder": "Użyj Enter lub przecinka (,) aby wprowadzić wiele tagów",
|
||||
"trafficRatio": "Wskaźnik ruchu",
|
||||
"transport": "Konfiguracja protokołu transportowego",
|
||||
"transportConfig": "Konfiguracja protokołu transportowego",
|
||||
"transportHost": "Adres serwera transportowego",
|
||||
"transportPath": "Ścieżka transportu",
|
||||
"transportServerName": "Nazwa serwera transportowego",
|
||||
"udpRelayMode": "Tryb przekaźnika UDP"
|
||||
},
|
||||
"relayModeOptions": {
|
||||
"all": "Wszystkie",
|
||||
"none": "Brak",
|
||||
"random": "Losowo"
|
||||
},
|
||||
"securityConfig": {
|
||||
"fingerprint": "Odcisk palca",
|
||||
"privateKey": "Klucz prywatny",
|
||||
"privateKeyPlaceholder": "Pozostaw puste, aby automatycznie wygenerować",
|
||||
"publicKey": "Klucz publiczny",
|
||||
"publicKeyPlaceholder": "Pozostaw puste, aby automatycznie wygenerować",
|
||||
"serverAddress": "Adres serwera",
|
||||
"serverAddressPlaceholder": "Adres docelowy REALITY, domyślnie używa SNI",
|
||||
"serverName": "Nazwa serwera (SNI)",
|
||||
"serverNamePlaceholder": "REALITY wymagane, zgodne z backendem",
|
||||
"serverPort": "Port serwera",
|
||||
"serverPortPlaceholder": "Docelowy port REALITY, domyślnie 443",
|
||||
"shortId": "Krótki ID",
|
||||
"shortIdPlaceholder": "Pozostaw puste, aby automatycznie wygenerować",
|
||||
"sni": "Wskazanie nazwy serwera (SNI)"
|
||||
},
|
||||
"tabs": {
|
||||
"node": "Węzeł",
|
||||
"nodeConfig": "Konfiguracja Węzła",
|
||||
"nodeGroup": "Grupa węzłów"
|
||||
}
|
||||
}
|
||||
101
apps/admin/locales/pl-PL/servers.json
Normal file
101
apps/admin/locales/pl-PL/servers.json
Normal file
@ -0,0 +1,101 @@
|
||||
{
|
||||
"address": "Adres",
|
||||
"address_placeholder": "Adres serwera",
|
||||
"cancel": "Anuluj",
|
||||
"city": "Miasto",
|
||||
"config": {
|
||||
"actions": {
|
||||
"cancel": "Anuluj",
|
||||
"save": "Zapisz"
|
||||
},
|
||||
"communicationKey": "Klucz komunikacyjny",
|
||||
"communicationKeyDescription": "Używany do uwierzytelniania węzła.",
|
||||
"description": "Zarządzaj kluczami komunikacyjnymi węzła, interwałami pobierania/wysyłania oraz dynamicznymi mnożnikami.",
|
||||
"dynamicMultiplier": "Dynamiczny mnożnik",
|
||||
"dynamicMultiplierDescription": "Zdefiniuj przedziały czasowe i mnożniki, aby dostosować rozliczanie ruchu.",
|
||||
"endTime": "Czas zakończenia",
|
||||
"inputPlaceholder": "Proszę wpisać",
|
||||
"multiplier": "Mnożnik",
|
||||
"nodePullInterval": "Interwał pobierania węzła",
|
||||
"nodePullIntervalDescription": "Jak często węzeł pobiera konfigurację (sekundy).",
|
||||
"nodePushInterval": "Interwał wysyłania węzła",
|
||||
"nodePushIntervalDescription": "Jak często węzeł wysyła statystyki (sekundy).",
|
||||
"reset": "Resetuj",
|
||||
"save": "Zapisz",
|
||||
"saveSuccess": "Zapisano pomyślnie",
|
||||
"startTime": "Czas rozpoczęcia",
|
||||
"timeSlot": "Przedział czasowy",
|
||||
"title": "Konfiguracja węzła"
|
||||
},
|
||||
"confirm": "Potwierdź",
|
||||
"confirmDeleteDesc": "Ta akcja nie może być cofnięta.",
|
||||
"confirmDeleteTitle": "Usunąć ten serwer?",
|
||||
"congestion_controller": "Kontroler przeciążenia",
|
||||
"copied": "Skopiowano",
|
||||
"copy": "Kopiuj",
|
||||
"country": "Kraj",
|
||||
"cpu": "CPU",
|
||||
"create": "Utwórz",
|
||||
"created": "Utworzono pomyślnie",
|
||||
"delete": "Usuń",
|
||||
"deleted": "Usunięto pomyślnie",
|
||||
"disable_sni": "Wyłącz SNI",
|
||||
"disk": "Dysk",
|
||||
"drawerCreateTitle": "Utwórz serwer",
|
||||
"drawerEditTitle": "Edytuj serwer",
|
||||
"edit": "Edytuj",
|
||||
"enabled": "Włączony",
|
||||
"encryption_method": "Metoda szyfrowania",
|
||||
"expireTime": "Czas wygaśnięcia",
|
||||
"expired": "Wygasł",
|
||||
"flow": "Przepływ",
|
||||
"hop_interval": "Interwał skoku",
|
||||
"hop_ports": "Porty skoku",
|
||||
"hop_ports_placeholder": "np. 1-65535",
|
||||
"host": "Host",
|
||||
"id": "ID",
|
||||
"ipAddresses": "Adresy IP",
|
||||
"memory": "Pamięć",
|
||||
"name": "Nazwa",
|
||||
"noData": "Brak danych",
|
||||
"notAvailable": "N/D",
|
||||
"obfs_password": "Hasło obfuskacji",
|
||||
"obfs_password_placeholder": "Wprowadź hasło obfuskacji",
|
||||
"offline": "Offline",
|
||||
"online": "Online",
|
||||
"onlineUsers": "Użytkownicy online",
|
||||
"pageTitle": "Serwery",
|
||||
"path": "Ścieżka",
|
||||
"please_select": "Proszę wybrać",
|
||||
"port": "Port",
|
||||
"protocols": "Protokoły",
|
||||
"reduce_rtt": "Zredukuj RTT",
|
||||
"security_allow_insecure": "Zezwól na niebezpieczne",
|
||||
"security_fingerprint": "Odcisk palca",
|
||||
"security_private_key": "Prywatny klucz rzeczywistości",
|
||||
"security_private_key_placeholder": "Wprowadź klucz prywatny",
|
||||
"security_public_key": "Publiczny klucz rzeczywistości",
|
||||
"security_public_key_placeholder": "Wprowadź klucz publiczny",
|
||||
"security_server_address": "Adres serwera rzeczywistości",
|
||||
"security_server_address_placeholder": "np. 1.2.3.4 lub domena",
|
||||
"security_server_port": "Port serwera rzeczywistości",
|
||||
"security_short_id": "Krótki ID rzeczywistości",
|
||||
"security_short_id_placeholder": "Ciąg szesnastkowy (do 16 znaków)",
|
||||
"security_sni": "SNI",
|
||||
"security_title": "Bezpieczeństwo",
|
||||
"select_encryption_method": "Wybierz metodę szyfrowania",
|
||||
"server_key": "Klucz serwera",
|
||||
"service_name": "Nazwa usługi",
|
||||
"status": "Status",
|
||||
"subscribeId": "ID subskrypcji",
|
||||
"subscription": "Subskrypcja",
|
||||
"traffic": "Ruch",
|
||||
"traffic_ratio": "Mnożnik",
|
||||
"transport_title": "Transport",
|
||||
"udp_relay_mode": "Tryb przekazywania UDP",
|
||||
"unitSecondsShort": "S",
|
||||
"unlimited": "Nieograniczone",
|
||||
"updated": "Zaktualizowano pomyślnie",
|
||||
"user": "Użytkownik",
|
||||
"validation_failed": "Walidacja nie powiodła się. Proszę sprawdzić formularz."
|
||||
}
|
||||
@ -1,27 +1,36 @@
|
||||
{
|
||||
"ADS Config": "Configuração ADS",
|
||||
"Announcement Management": "Gerenciamento de Anúncios",
|
||||
"Application Management": "Gerenciamento de Aplicativos",
|
||||
"Auth Control": "Controle de Autenticação",
|
||||
"Balance": "Saldo",
|
||||
"Commerce": "Comércio",
|
||||
"Commission": "Comissão",
|
||||
"Coupon Management": "Gerenciamento de Cupons",
|
||||
"Dashboard": "Painel de Controle",
|
||||
"Document Management": "Gerenciamento de Documentos",
|
||||
"Finance": "Finanças",
|
||||
"Email": "Email",
|
||||
"Gift": "Presente",
|
||||
"Login": "Entrar",
|
||||
"Logs & Analytics": "Registros e Análises",
|
||||
"Maintenance": "Manutenção",
|
||||
"Marketing Management": "Gestão de Marketing",
|
||||
"Node Management": "Gerenciamento de Nós",
|
||||
"Order Management": "Gerenciamento de Pedidos",
|
||||
"Payment Config": "Configuração de Pagamento",
|
||||
"Product Management": "Gestão de Produtos",
|
||||
"Protocol Management": "Gestão de Protocolos",
|
||||
"Rule Management": "Gerenciamento de Regras",
|
||||
"Server": "Servidor",
|
||||
"Register": "Registrar",
|
||||
"Reset Subscribe": "Redefinir Inscrição",
|
||||
"SMS": "SMS",
|
||||
"Server Management": "Gerenciamento de Servidor",
|
||||
"Settings": "Configurações",
|
||||
"Server Traffic": "Tráfego do Servidor",
|
||||
"Subscribe": "Inscrever-se",
|
||||
"Subscribe Config": "Configuração de Assinatura",
|
||||
"Subscribe Traffic": "Tráfego de Inscrição",
|
||||
"System": "Sistema",
|
||||
"System Config": "Configuração do Sistema",
|
||||
"System Management": "Gerenciamento de Sistema",
|
||||
"System Tool": "Ferramenta do Sistema",
|
||||
"Ticket Management": "Gerenciamento de Chamados",
|
||||
"User": "Usuário",
|
||||
"User Detail": "Detalhes do Usuário",
|
||||
"User Management": "Gerenciamento de Usuários"
|
||||
"User Management": "Gerenciamento de Usuários",
|
||||
"Users & Support": "Usuários e Suporte"
|
||||
}
|
||||
|
||||
37
apps/admin/locales/pt-BR/nodes.json
Normal file
37
apps/admin/locales/pt-BR/nodes.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"address": "Endereço",
|
||||
"cancel": "Cancelar",
|
||||
"confirm": "Confirmar",
|
||||
"confirmDeleteDesc": "Esta ação não pode ser desfeita.",
|
||||
"confirmDeleteTitle": "Excluir este nó?",
|
||||
"copied": "Copiado",
|
||||
"copy": "Copiar",
|
||||
"create": "Criar",
|
||||
"created": "Criado",
|
||||
"delete": "Excluir",
|
||||
"deleted": "Excluído",
|
||||
"drawerCreateTitle": "Criar Nó",
|
||||
"drawerEditTitle": "Editar Nó",
|
||||
"edit": "Editar",
|
||||
"enabled": "Ativado",
|
||||
"enabled_off": "Desativado",
|
||||
"enabled_on": "Ativado",
|
||||
"errors": {
|
||||
"nameRequired": "Por favor, insira um nome",
|
||||
"portRange": "A porta deve estar entre 1 e 65535",
|
||||
"protocolRequired": "Por favor, selecione um protocolo",
|
||||
"serverAddrRequired": "Por favor, insira um endereço de entrada",
|
||||
"serverRequired": "Por favor, selecione um servidor"
|
||||
},
|
||||
"name": "Nome",
|
||||
"pageTitle": "Nós",
|
||||
"port": "Porta",
|
||||
"protocol": "Protocolo",
|
||||
"select_protocol": "Selecionar protocolo…",
|
||||
"select_server": "Selecionar servidor…",
|
||||
"server": "Servidor",
|
||||
"tags": "Tags",
|
||||
"tags_description": "Tag de agrupamento de permissões (incl. vinculação de plano e políticas de entrega).",
|
||||
"tags_placeholder": "Use Enter ou vírgula (,) para adicionar várias tags",
|
||||
"updated": "Atualizado"
|
||||
}
|
||||
@ -1,59 +1,6 @@
|
||||
{
|
||||
"actions": "ações",
|
||||
"app": {
|
||||
"appDownloadURL": "URL de Download do App",
|
||||
"appIcon": "Ícone do App",
|
||||
"appList": "Lista de Apps",
|
||||
"appName": "Nome do App",
|
||||
"backupDomains": "Lista de Domínios de Backup",
|
||||
"backupDomainsDescription": "Lista de domínios de backup para resolução de domínios, um domínio por linha",
|
||||
"batchDelete": "Excluir em Lote",
|
||||
"cancel": "Cancelar",
|
||||
"communicationKey": "Chave de Comunicação",
|
||||
"communicationKeyDescription": "Chave usada para comunicação com o cliente",
|
||||
"config": "Configuração",
|
||||
"configApp": "Configuração do App",
|
||||
"confirm": "Confirmar",
|
||||
"confirmDelete": "Confirmar Exclusão",
|
||||
"create": "Criar",
|
||||
"createApp": "Criar App",
|
||||
"createSuccess": "Criado com sucesso",
|
||||
"defaultVersion": "Padrão",
|
||||
"delete": "Excluir",
|
||||
"deleteWarning": "Esta ação não pode ser desfeita",
|
||||
"describeDescription": "Usado para descrever o aplicativo, exibido na lista de apps",
|
||||
"description": "Descrição",
|
||||
"downloadLink": "Link para Download",
|
||||
"edit": "Editar",
|
||||
"editApp": "Editar App",
|
||||
"encryption": "Método de Criptografia",
|
||||
"encryptionDescription": "Escolha o método de criptografia para comunicação com o cliente. Se selecionado, o cliente usará este método para se comunicar com o servidor",
|
||||
"nameDescription": "Nome do aplicativo, exibido na lista de apps",
|
||||
"platform": "Plataforma",
|
||||
"selectApp": "Selecionar Aplicativo",
|
||||
"selectAppDescription": "Selecione o aplicativo para configurar, todas as configurações serão aplicadas ao aplicativo selecionado",
|
||||
"startupPicture": "Imagem de Inicialização",
|
||||
"startupPictureDescription": "Imagem de inicialização, suporta imagens de rede e locais. Para imagens de rede, por favor insira a URL completa da imagem",
|
||||
"startupPicturePreview": "Pré-visualização da Imagem de Inicialização",
|
||||
"startupPictureSkip": "Tempo de Pular Imagem de Inicialização",
|
||||
"startupPictureSkipDescription": "Tempo de exibição da imagem de inicialização em segundos, insira 0 para não exibir",
|
||||
"subscriptionProtocol": "Protocolo de Assinatura",
|
||||
"updateSuccess": "Atualizado com sucesso",
|
||||
"version": "Versão"
|
||||
},
|
||||
"cancel": "Cancelar",
|
||||
"config": {
|
||||
"singleSubscriptionMode": "Modo de Assinatura Única",
|
||||
"subscriptionDomain": "Domínio de Assinatura",
|
||||
"subscriptionDomainDescription": "Usado para assinatura; deixe em branco para usar o domínio do site",
|
||||
"subscriptionDomainPlaceholder": "Insira o domínio de assinatura, um por linha",
|
||||
"subscriptionPath": "Caminho de Assinatura",
|
||||
"subscriptionPathDescription": "Usado para assinatura; certifique-se de reiniciar o sistema após a modificação para um desempenho ideal",
|
||||
"subscriptionPathPlaceholder": "Insira",
|
||||
"updateSuccess": "Atualizado com sucesso",
|
||||
"wildcardResolution": "Resolução de Curinga",
|
||||
"wildcardResolutionDescription": "Usado para assinatura"
|
||||
},
|
||||
"confirm": "confirmar",
|
||||
"confirmDelete": "Tem certeza de que deseja excluir?",
|
||||
"copy": "Copiar",
|
||||
@ -94,6 +41,9 @@
|
||||
"name": "Nome",
|
||||
"noLimit": "Sem limite",
|
||||
"noReset": "Sem Reinicialização",
|
||||
"node": "Nó",
|
||||
"nodeGroup": "Grupo de Nós",
|
||||
"nodes": "Nós",
|
||||
"pricing": "Preços",
|
||||
"purchaseWithDiscount": "Permitir Dedução",
|
||||
"purchaseWithDiscountDescription": "Ative ou desative a funcionalidade de cancelamento de inscrição. Após a ativação, o sistema realizará o processamento de dedução de acordo com as regras e proporções configuradas, e o valor restante será retornado ao saldo",
|
||||
@ -106,9 +56,6 @@
|
||||
"selectResetCycle": "Por favor, selecione um ciclo de reinicialização",
|
||||
"selectSubscribeGroup": "Por favor, selecione o grupo de assinatura",
|
||||
"selectUnitTime": "Por favor, selecione a unidade de tempo",
|
||||
"server": "Servidor",
|
||||
"serverGroup": "Grupo de servidores",
|
||||
"servers": "Servidores",
|
||||
"speedLimit": "Limite de velocidade ",
|
||||
"traffic": "Tráfego",
|
||||
"unitPrice": "Preço unitário",
|
||||
@ -150,8 +97,6 @@
|
||||
"subscribeGroup": "Inscrever-se no grupo",
|
||||
"tabs": {
|
||||
"subscribe": "Inscrever-se",
|
||||
"subscribeApp": "Configuração do Aplicativo",
|
||||
"subscribeConfig": "Configuração de Assinatura",
|
||||
"subscribeGroup": "Grupo de Inscrição"
|
||||
},
|
||||
"traffic": "tráfego",
|
||||
|
||||
@ -1,183 +0,0 @@
|
||||
{
|
||||
"config": {
|
||||
"addTimeSlot": "Adicionar Faixa de Horário",
|
||||
"communicationKey": "Chave de Comunicação",
|
||||
"communicationKeyDescription": "Chave para comunicação entre nós para garantir a segurança dos dados",
|
||||
"delete": "Excluir",
|
||||
"dynamicMultiplier": "Multiplicador Dinâmico",
|
||||
"dynamicMultiplierDescription": "Multiplicador Dinâmico refere-se ao processamento de dados enviados com diferentes multiplicadores para diferentes nós durante diferentes períodos de tempo.",
|
||||
"endTime": "Hora de Término",
|
||||
"inputPlaceholder": "Digite",
|
||||
"multiplier": "Multiplicador",
|
||||
"nodePullInterval": "Intervalo de Busca do Nó",
|
||||
"nodePullIntervalDescription": "Frequência (em segundos) para os nós buscarem dados do painel",
|
||||
"nodePushInterval": "Intervalo de Envio do Nó",
|
||||
"nodePushIntervalDescription": "Frequência para os nós enviarem dados ao painel",
|
||||
"reset": "Redefinir",
|
||||
"save": "Salvar",
|
||||
"saveSuccess": "Salvo com Sucesso",
|
||||
"startTime": "Hora de Início",
|
||||
"timeSlot": "Faixa de Horário"
|
||||
},
|
||||
"group": {
|
||||
"actions": "Ações",
|
||||
"cancel": "Cancelar",
|
||||
"confirm": "Confirmar",
|
||||
"confirmDelete": "Tem certeza de que deseja excluir?",
|
||||
"create": "Criar",
|
||||
"createNodeGroup": "Criar Grupo de Nós",
|
||||
"createdSuccessfully": "Criado com sucesso",
|
||||
"delete": "Excluir",
|
||||
"deleteWarning": "Após a exclusão, os dados não poderão ser recuperados. Proceda com cautela.",
|
||||
"deletedSuccessfully": "Excluído com sucesso",
|
||||
"description": "Descrição",
|
||||
"edit": "Editar",
|
||||
"editNodeGroup": "Editar Grupo de Nós",
|
||||
"name": "Nome",
|
||||
"title": "Lista de Grupos de Nós",
|
||||
"updatedAt": "Atualizado em"
|
||||
},
|
||||
"groupForm": {
|
||||
"cancel": "Cancelar",
|
||||
"confirm": "Confirmar",
|
||||
"description": "Descrição",
|
||||
"name": "Nome"
|
||||
},
|
||||
"node": {
|
||||
"abnormal": "Anormal",
|
||||
"actions": "Ações",
|
||||
"address": "Endereço",
|
||||
"all": "Todos",
|
||||
"basicInfo": "Informações Básicas",
|
||||
"cancel": "Cancelar",
|
||||
"confirm": "Confirmar",
|
||||
"confirmDelete": "Tem certeza de que deseja excluir?",
|
||||
"copy": "Copiar",
|
||||
"copySuccess": "Copiado com sucesso",
|
||||
"create": "Criar",
|
||||
"createNode": "Criar Nó",
|
||||
"createSuccess": "Criado com sucesso",
|
||||
"delete": "Excluir",
|
||||
"deleteSuccess": "Excluído com sucesso",
|
||||
"deleteWarning": "Após a exclusão, os dados não poderão ser recuperados. Por favor, proceda com cautela.",
|
||||
"detail": "Detalhe",
|
||||
"disabled": "Desativado",
|
||||
"disk": "Disco",
|
||||
"edit": "Editar",
|
||||
"editNode": "Editar Nó",
|
||||
"enable": "Habilitar",
|
||||
"enabled": "Ativado",
|
||||
"expireTime": "Tempo de Expiração",
|
||||
"hide": "Ocultar",
|
||||
"id": "ID",
|
||||
"ipAddresses": "Endereços IP",
|
||||
"lastUpdated": "Última Atualização",
|
||||
"location": "Localização",
|
||||
"memory": "Memória",
|
||||
"name": "Nome",
|
||||
"noData": "--",
|
||||
"node": "Nó",
|
||||
"nodeDetail": "Detalhes do Nó",
|
||||
"nodeGroup": "Grupo de Nós",
|
||||
"nodeStatus": "Status do Nó",
|
||||
"normal": "Normal",
|
||||
"onlineCount": "Contagem de Usuários Online",
|
||||
"onlineUsers": "Usuários Online",
|
||||
"protocol": "Protocolo",
|
||||
"rate": "Taxa",
|
||||
"relay": "Relay",
|
||||
"serverAddr": "Endereço do Servidor",
|
||||
"speedLimit": "Limite de Velocidade",
|
||||
"status": "Status",
|
||||
"subscribeId": "ID da Assinatura",
|
||||
"subscribeName": "Nome da Assinatura",
|
||||
"subscription": "Assinatura",
|
||||
"tags": "Etiquetas",
|
||||
"trafficRatio": "Taxa de Tráfego",
|
||||
"trafficUsage": "Uso de Tráfego",
|
||||
"type": "Tipo",
|
||||
"updateSuccess": "Atualizado com sucesso",
|
||||
"updatedAt": "Atualizado em",
|
||||
"user": "Usuário",
|
||||
"userDetail": "Detalhes do Usuário",
|
||||
"userId": "ID do Usuário"
|
||||
},
|
||||
"nodeForm": {
|
||||
"allowInsecure": "Permitir Inseguro",
|
||||
"cancel": "Cancelar",
|
||||
"city": "Cidade",
|
||||
"confirm": "Confirmar",
|
||||
"congestionController": "Controlador de Congestionamento",
|
||||
"country": "País",
|
||||
"disableSni": "Desativar SNI",
|
||||
"edit": "Editar",
|
||||
"editSecurity": "Editar Configuração de Segurança",
|
||||
"enableTLS": "Ativar TLS",
|
||||
"encryptionMethod": "Método de Criptografia",
|
||||
"fingerprint": "Impressão Digital",
|
||||
"flow": "Algoritmo de Controle de Fluxo",
|
||||
"groupId": "Grupo de Nós",
|
||||
"hopInterval": "Intervalo de Salto",
|
||||
"hopPorts": "Portas de Salto",
|
||||
"hopPortsPlaceholder": "Separe várias portas com vírgulas",
|
||||
"name": "Nome",
|
||||
"obfsPassword": "Senha de Ofuscação",
|
||||
"obfsPasswordPlaceholder": "Deixe em branco para nenhuma ofuscação",
|
||||
"path": "Caminho",
|
||||
"pleaseSelect": "Por Favor Selecione",
|
||||
"port": "Porta do Servidor",
|
||||
"protocol": "Protocolo",
|
||||
"reduceRtt": "Reduzir RTT",
|
||||
"relayHost": "Host de Revezamento",
|
||||
"relayMode": "Modo de Revezamento",
|
||||
"relayPort": "Porta de Revezamento",
|
||||
"relayPrefix": "Prefixo de Revezamento",
|
||||
"remarks": "Observações",
|
||||
"security": "Segurança",
|
||||
"securityConfig": "Configuração de Segurança",
|
||||
"selectEncryptionMethod": "Selecionar Método de Criptografia",
|
||||
"selectNodeGroup": "Selecionar Grupo de Nós",
|
||||
"selectProtocol": "Selecionar Protocolo",
|
||||
"selectRelayMode": "Selecionar Modo de Revezamento",
|
||||
"serverAddr": "Endereço do Servidor",
|
||||
"serverKey": "Chave do Servidor",
|
||||
"serverName": "Nome do Serviço",
|
||||
"speedLimit": "Limite de Velocidade",
|
||||
"speedLimitPlaceholder": "Ilimitado",
|
||||
"tags": "Tags",
|
||||
"tagsPlaceholder": "Use Enter ou vírgula (,) para inserir várias tags",
|
||||
"trafficRatio": "Taxa de Tráfego",
|
||||
"transport": "Configuração do Protocolo de Transporte",
|
||||
"transportConfig": "Configuração do Protocolo de Transporte",
|
||||
"transportHost": "Endereço do Servidor de Transporte",
|
||||
"transportPath": "Caminho de Transporte",
|
||||
"transportServerName": "Nome do Servidor de Transporte",
|
||||
"udpRelayMode": "Modo de Revezamento UDP"
|
||||
},
|
||||
"relayModeOptions": {
|
||||
"all": "Todos",
|
||||
"none": "Nenhum",
|
||||
"random": "Aleatório"
|
||||
},
|
||||
"securityConfig": {
|
||||
"fingerprint": "Impressão Digital",
|
||||
"privateKey": "Chave Privada",
|
||||
"privateKeyPlaceholder": "Deixe em branco para auto-geração",
|
||||
"publicKey": "Chave Pública",
|
||||
"publicKeyPlaceholder": "Deixe em branco para auto-geração",
|
||||
"serverAddress": "Endereço do Servidor",
|
||||
"serverAddressPlaceholder": "Endereço de destino REALITY, padrão usando SNI",
|
||||
"serverName": "Nome do Servidor (SNI)",
|
||||
"serverNamePlaceholder": "REALITY necessário, consistente com o backend",
|
||||
"serverPort": "Porta do Servidor",
|
||||
"serverPortPlaceholder": "Porta de destino REALITY, padrão 443",
|
||||
"shortId": "ID Curto",
|
||||
"shortIdPlaceholder": "Deixe em branco para auto-geração",
|
||||
"sni": "Indicação de Nome do Servidor (SNI)"
|
||||
},
|
||||
"tabs": {
|
||||
"node": "Nó",
|
||||
"nodeConfig": "Configuração do Nó",
|
||||
"nodeGroup": "Grupo de Nós"
|
||||
}
|
||||
}
|
||||
101
apps/admin/locales/pt-BR/servers.json
Normal file
101
apps/admin/locales/pt-BR/servers.json
Normal file
@ -0,0 +1,101 @@
|
||||
{
|
||||
"address": "Endereço",
|
||||
"address_placeholder": "Endereço do servidor",
|
||||
"cancel": "Cancelar",
|
||||
"city": "Cidade",
|
||||
"config": {
|
||||
"actions": {
|
||||
"cancel": "Cancelar",
|
||||
"save": "Salvar"
|
||||
},
|
||||
"communicationKey": "Chave de comunicação",
|
||||
"communicationKeyDescription": "Usado para autenticação do nó.",
|
||||
"description": "Gerenciar chaves de comunicação do nó, intervalos de pull/push e multiplicadores dinâmicos.",
|
||||
"dynamicMultiplier": "Multiplicador dinâmico",
|
||||
"dynamicMultiplierDescription": "Defina intervalos de tempo e multiplicadores para ajustar a contagem de tráfego.",
|
||||
"endTime": "Hora de término",
|
||||
"inputPlaceholder": "Por favor, insira",
|
||||
"multiplier": "Multiplicador",
|
||||
"nodePullInterval": "Intervalo de pull do nó",
|
||||
"nodePullIntervalDescription": "Com que frequência o nó puxa a configuração (segundos).",
|
||||
"nodePushInterval": "Intervalo de push do nó",
|
||||
"nodePushIntervalDescription": "Com que frequência o nó envia estatísticas (segundos).",
|
||||
"reset": "Redefinir",
|
||||
"save": "Salvar",
|
||||
"saveSuccess": "Salvo com sucesso",
|
||||
"startTime": "Hora de início",
|
||||
"timeSlot": "Intervalo de tempo",
|
||||
"title": "Configuração do nó"
|
||||
},
|
||||
"confirm": "Confirmar",
|
||||
"confirmDeleteDesc": "Esta ação não pode ser desfeita.",
|
||||
"confirmDeleteTitle": "Excluir este servidor?",
|
||||
"congestion_controller": "Controlador de congestionamento",
|
||||
"copied": "Copiado",
|
||||
"copy": "Copiar",
|
||||
"country": "País",
|
||||
"cpu": "CPU",
|
||||
"create": "Criar",
|
||||
"created": "Criado com sucesso",
|
||||
"delete": "Excluir",
|
||||
"deleted": "Excluído com sucesso",
|
||||
"disable_sni": "Desativar SNI",
|
||||
"disk": "Disco",
|
||||
"drawerCreateTitle": "Criar Servidor",
|
||||
"drawerEditTitle": "Editar Servidor",
|
||||
"edit": "Editar",
|
||||
"enabled": "Ativado",
|
||||
"encryption_method": "Método de criptografia",
|
||||
"expireTime": "Tempo de expiração",
|
||||
"expired": "Expirado",
|
||||
"flow": "Fluxo",
|
||||
"hop_interval": "Intervalo de salto",
|
||||
"hop_ports": "Portas de salto",
|
||||
"hop_ports_placeholder": "ex. 1-65535",
|
||||
"host": "Host",
|
||||
"id": "ID",
|
||||
"ipAddresses": "Endereços IP",
|
||||
"memory": "Memória",
|
||||
"name": "Nome",
|
||||
"noData": "Sem dados",
|
||||
"notAvailable": "N/D",
|
||||
"obfs_password": "Senha de ofuscação",
|
||||
"obfs_password_placeholder": "Insira a senha de ofuscação",
|
||||
"offline": "Offline",
|
||||
"online": "Online",
|
||||
"onlineUsers": "Usuários online",
|
||||
"pageTitle": "Servidores",
|
||||
"path": "Caminho",
|
||||
"please_select": "Por favor, selecione",
|
||||
"port": "Porta",
|
||||
"protocols": "Protocolos",
|
||||
"reduce_rtt": "Reduzir RTT",
|
||||
"security_allow_insecure": "Permitir inseguro",
|
||||
"security_fingerprint": "Impressão digital",
|
||||
"security_private_key": "Chave privada da realidade",
|
||||
"security_private_key_placeholder": "Insira a chave privada",
|
||||
"security_public_key": "Chave pública da realidade",
|
||||
"security_public_key_placeholder": "Insira a chave pública",
|
||||
"security_server_address": "Endereço do servidor da realidade",
|
||||
"security_server_address_placeholder": "ex. 1.2.3.4 ou domínio",
|
||||
"security_server_port": "Porta do servidor da realidade",
|
||||
"security_short_id": "ID curto da realidade",
|
||||
"security_short_id_placeholder": "String hexadecimal (até 16 caracteres)",
|
||||
"security_sni": "SNI",
|
||||
"security_title": "Segurança",
|
||||
"select_encryption_method": "Selecionar método de criptografia",
|
||||
"server_key": "Chave do servidor",
|
||||
"service_name": "Nome do serviço",
|
||||
"status": "Status",
|
||||
"subscribeId": "ID de assinatura",
|
||||
"subscription": "Assinatura",
|
||||
"traffic": "Tráfego",
|
||||
"traffic_ratio": "Multiplicador",
|
||||
"transport_title": "Transporte",
|
||||
"udp_relay_mode": "Modo de retransmissão UDP",
|
||||
"unitSecondsShort": "S",
|
||||
"unlimited": "Ilimitado",
|
||||
"updated": "Atualizado com sucesso",
|
||||
"user": "Usuário",
|
||||
"validation_failed": "Validação falhou. Por favor, verifique o formulário."
|
||||
}
|
||||
@ -17,7 +17,6 @@ export default getRequestConfig(async () => {
|
||||
'auth-control': (await import(`./${locale}/auth-control.json`)).default,
|
||||
'ads': (await import(`./${locale}/ads.json`)).default,
|
||||
'payment': (await import(`./${locale}/payment.json`)).default,
|
||||
'server': (await import(`./${locale}/server.json`)).default,
|
||||
'servers': (await import(`./${locale}/servers.json`)).default,
|
||||
'nodes': (await import(`./${locale}/nodes.json`)).default,
|
||||
'product': (await import(`./${locale}/product.json`)).default,
|
||||
|
||||
@ -1,27 +1,36 @@
|
||||
{
|
||||
"ADS Config": "Configurație ADS",
|
||||
"Announcement Management": "Managementul Anunțurilor",
|
||||
"Application Management": "Gestionarea aplicațiilor",
|
||||
"Auth Control": "Control Autentificare",
|
||||
"Balance": "Sold",
|
||||
"Commerce": "Comerț",
|
||||
"Commission": "Comision",
|
||||
"Coupon Management": "Managementul Cuponului",
|
||||
"Dashboard": "Tablou de bord",
|
||||
"Document Management": "Managementul documentelor",
|
||||
"Finance": "Finanțe",
|
||||
"Email": "Email",
|
||||
"Gift": "Cadou",
|
||||
"Login": "Autentificare",
|
||||
"Logs & Analytics": "Jurnale și Analitice",
|
||||
"Maintenance": "Întreținere",
|
||||
"Marketing Management": "Managementul Marketingului",
|
||||
"Node Management": "Gestionarea Nodurilor",
|
||||
"Order Management": "Gestionarea comenzilor",
|
||||
"Payment Config": "Configurație Plată",
|
||||
"Product Management": "Gestionarea Produselor",
|
||||
"Protocol Management": "Gestionarea Protocolului",
|
||||
"Rule Management": "Gestionarea regulilor",
|
||||
"Server": "Serviciu",
|
||||
"Register": "Înregistrare",
|
||||
"Reset Subscribe": "Resetează Abonamentul",
|
||||
"SMS": "SMS",
|
||||
"Server Management": "Managementul serverului",
|
||||
"Settings": "Setări",
|
||||
"Server Traffic": "Trafic Server",
|
||||
"Subscribe": "Abonează-te",
|
||||
"Subscribe Config": "Configurație Abonare",
|
||||
"Subscribe Traffic": "Trafic Abonament",
|
||||
"System": "Sistem",
|
||||
"System Config": "Configurația sistemului",
|
||||
"System Management": "Gestionarea sistemului",
|
||||
"System Tool": "Instrumente de sistem",
|
||||
"Ticket Management": "Gestionarea Biletelor",
|
||||
"User": "Utilizator",
|
||||
"User Detail": "Detalii Utilizator",
|
||||
"User Management": "Gestionarea Utilizatorilor"
|
||||
"User Management": "Gestionarea Utilizatorilor",
|
||||
"Users & Support": "Utilizatori și Suport"
|
||||
}
|
||||
|
||||
37
apps/admin/locales/ro-RO/nodes.json
Normal file
37
apps/admin/locales/ro-RO/nodes.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"address": "Adresă",
|
||||
"cancel": "Anulează",
|
||||
"confirm": "Confirmă",
|
||||
"confirmDeleteDesc": "Această acțiune nu poate fi anulată.",
|
||||
"confirmDeleteTitle": "Șterge acest nod?",
|
||||
"copied": "Copiat",
|
||||
"copy": "Copiază",
|
||||
"create": "Creează",
|
||||
"created": "Creat",
|
||||
"delete": "Șterge",
|
||||
"deleted": "Șters",
|
||||
"drawerCreateTitle": "Creează Nod",
|
||||
"drawerEditTitle": "Editează Nod",
|
||||
"edit": "Editează",
|
||||
"enabled": "Activat",
|
||||
"enabled_off": "Dezactivat",
|
||||
"enabled_on": "Activat",
|
||||
"errors": {
|
||||
"nameRequired": "Te rog introdu un nume",
|
||||
"portRange": "Portul trebuie să fie între 1 și 65535",
|
||||
"protocolRequired": "Te rog selectează un protocol",
|
||||
"serverAddrRequired": "Te rog introdu o adresă de intrare",
|
||||
"serverRequired": "Te rog selectează un server"
|
||||
},
|
||||
"name": "Nume",
|
||||
"pageTitle": "Noduri",
|
||||
"port": "Port",
|
||||
"protocol": "Protocol",
|
||||
"select_protocol": "Selectează protocolul…",
|
||||
"select_server": "Selectează serverul…",
|
||||
"server": "Server",
|
||||
"tags": "Etichete",
|
||||
"tags_description": "Etichetă de grupare a permisiunilor (incluzând legarea planului și politicile de livrare).",
|
||||
"tags_placeholder": "Folosește Enter sau virgulă (,) pentru a adăuga mai multe etichete",
|
||||
"updated": "Actualizat"
|
||||
}
|
||||
@ -1,59 +1,6 @@
|
||||
{
|
||||
"actions": "acțiuni",
|
||||
"app": {
|
||||
"appDownloadURL": "URL Descărcare Aplicație",
|
||||
"appIcon": "Iconiță Aplicație",
|
||||
"appList": "Listă de aplicații",
|
||||
"appName": "Nume Aplicație",
|
||||
"backupDomains": "Listă de domenii de rezervă",
|
||||
"backupDomainsDescription": "Listă de domenii de rezervă pentru rezolvarea domeniilor, un domeniu pe linie",
|
||||
"batchDelete": "Ștergere în Lot",
|
||||
"cancel": "Anulează",
|
||||
"communicationKey": "Cheie de comunicare",
|
||||
"communicationKeyDescription": "Cheie utilizată pentru comunicarea cu clientul",
|
||||
"config": "Configurație",
|
||||
"configApp": "Configurația aplicației",
|
||||
"confirm": "Confirmă",
|
||||
"confirmDelete": "Confirmă Ștergerea",
|
||||
"create": "Creează",
|
||||
"createApp": "Creează Aplicație",
|
||||
"createSuccess": "Creat cu succes",
|
||||
"defaultVersion": "Implicit",
|
||||
"delete": "Șterge",
|
||||
"deleteWarning": "Această acțiune nu poate fi anulată",
|
||||
"describeDescription": "Folosit pentru a descrie aplicația, afișat în lista de aplicații",
|
||||
"description": "Descriere",
|
||||
"downloadLink": "Link de descărcare",
|
||||
"edit": "Editează",
|
||||
"editApp": "Editează Aplicație",
|
||||
"encryption": "Metodă de criptare",
|
||||
"encryptionDescription": "Alegeți metoda de criptare pentru comunicarea cu clientul. Dacă este selectată, clientul va folosi această metodă pentru a comunica cu serverul",
|
||||
"nameDescription": "Numele aplicației, afișat în lista de aplicații",
|
||||
"platform": "Platformă",
|
||||
"selectApp": "Selectați aplicația",
|
||||
"selectAppDescription": "Selectați aplicația pentru configurare, toate setările se vor aplica aplicației selectate",
|
||||
"startupPicture": "Imagine de pornire",
|
||||
"startupPictureDescription": "Imagine de pornire, suportă imagini de rețea și locale. Pentru imagini de rețea, vă rugăm să introduceți URL-ul complet al imaginii",
|
||||
"startupPicturePreview": "Previzualizare imagine de pornire",
|
||||
"startupPictureSkip": "Timp de omitere imagine de pornire",
|
||||
"startupPictureSkipDescription": "Timpul de afișare a imaginii de pornire în secunde, introduceți 0 pentru a nu afișa",
|
||||
"subscriptionProtocol": "Protocol de Abonament",
|
||||
"updateSuccess": "Actualizat cu succes",
|
||||
"version": "Versiune"
|
||||
},
|
||||
"cancel": "Anulează",
|
||||
"config": {
|
||||
"singleSubscriptionMode": "Modul Abonament Unic",
|
||||
"subscriptionDomain": "Domeniu Abonament",
|
||||
"subscriptionDomainDescription": "Folosit pentru abonament; lăsați necompletat pentru a folosi domeniul site-ului",
|
||||
"subscriptionDomainPlaceholder": "Introduceți domeniul abonamentului, unul pe linie",
|
||||
"subscriptionPath": "Calea Abonamentului",
|
||||
"subscriptionPathDescription": "Folosit pentru abonament; asigurați-vă că reporniți sistemul după modificare pentru performanțe optime",
|
||||
"subscriptionPathPlaceholder": "Introduceți",
|
||||
"updateSuccess": "Actualizat cu succes",
|
||||
"wildcardResolution": "Rezoluție Wildcard",
|
||||
"wildcardResolutionDescription": "Folosit pentru abonament"
|
||||
},
|
||||
"confirm": "Confirmare",
|
||||
"confirmDelete": "Sigur doriți să ștergeți?",
|
||||
"copy": "Copiază",
|
||||
@ -94,6 +41,9 @@
|
||||
"name": "Nume",
|
||||
"noLimit": "Fără limită",
|
||||
"noReset": "Fără Resetare",
|
||||
"node": "Nod",
|
||||
"nodeGroup": "Grup de Noduri",
|
||||
"nodes": "Noduri",
|
||||
"pricing": "Prețuri",
|
||||
"purchaseWithDiscount": "Permite Deducerea",
|
||||
"purchaseWithDiscountDescription": "Activează sau dezactivează funcționalitatea de dezabonare. După activare, sistemul va efectua procesarea deducerilor conform regulilor și proporțiilor configurate, iar valoarea rămasă va fi returnată în sold.",
|
||||
@ -106,9 +56,6 @@
|
||||
"selectResetCycle": "Vă rugăm să selectați un ciclu de resetare",
|
||||
"selectSubscribeGroup": "Vă rugăm să selectați grupul de abonament",
|
||||
"selectUnitTime": "Vă rugăm să selectați unitatea de timp",
|
||||
"server": "Server",
|
||||
"serverGroup": "Grup server",
|
||||
"servers": "Servere",
|
||||
"speedLimit": "Limită de viteză ",
|
||||
"traffic": "Trafic",
|
||||
"unitPrice": "Preț unitar",
|
||||
@ -150,8 +97,6 @@
|
||||
"subscribeGroup": "Abonare grup",
|
||||
"tabs": {
|
||||
"subscribe": "Abonare",
|
||||
"subscribeApp": "Configurare Aplicație",
|
||||
"subscribeConfig": "Configurare Abonament",
|
||||
"subscribeGroup": "Grup de abonare"
|
||||
},
|
||||
"traffic": "trafic",
|
||||
|
||||
@ -1,183 +0,0 @@
|
||||
{
|
||||
"config": {
|
||||
"addTimeSlot": "Adaugă Interval de Timp",
|
||||
"communicationKey": "Cheie de Comunicare",
|
||||
"communicationKeyDescription": "Cheie pentru comunicarea nodului pentru a asigura securitatea datelor",
|
||||
"delete": "Șterge",
|
||||
"dynamicMultiplier": "Multiplicator Dinamic",
|
||||
"dynamicMultiplierDescription": "Multiplicatorul Dinamic se referă la procesarea datelor transmise cu multiplicatori diferiți pentru noduri diferite în perioade de timp diferite.",
|
||||
"endTime": "Ora de Sfârșit",
|
||||
"inputPlaceholder": "Introduceți",
|
||||
"multiplier": "Multiplicator",
|
||||
"nodePullInterval": "Interval de Extracție Nod",
|
||||
"nodePullIntervalDescription": "Frecvența (în secunde) cu care nodurile extrag date de la panou",
|
||||
"nodePushInterval": "Interval de Transmitere Nod",
|
||||
"nodePushIntervalDescription": "Frecvența cu care nodurile transmit date către panou",
|
||||
"reset": "Resetează",
|
||||
"save": "Salvează",
|
||||
"saveSuccess": "Salvare Reușită",
|
||||
"startTime": "Ora de Început",
|
||||
"timeSlot": "Interval de Timp"
|
||||
},
|
||||
"group": {
|
||||
"actions": "Acțiuni",
|
||||
"cancel": "Anulează",
|
||||
"confirm": "Confirmă",
|
||||
"confirmDelete": "Sigur doriți să ștergeți?",
|
||||
"create": "Creează",
|
||||
"createNodeGroup": "Creează grup de noduri",
|
||||
"createdSuccessfully": "Creat cu succes",
|
||||
"delete": "Șterge",
|
||||
"deleteWarning": "După ștergere, datele nu vor putea fi recuperate, vă rugăm să acționați cu prudență.",
|
||||
"deletedSuccessfully": "Șters cu succes",
|
||||
"description": "Descriere",
|
||||
"edit": "Editează",
|
||||
"editNodeGroup": "Editează grupul de noduri",
|
||||
"name": "Nume",
|
||||
"title": "Lista grupurilor de noduri",
|
||||
"updatedAt": "Actualizat la"
|
||||
},
|
||||
"groupForm": {
|
||||
"cancel": "Anulează",
|
||||
"confirm": "Confirmă",
|
||||
"description": "Descriere",
|
||||
"name": "Nume"
|
||||
},
|
||||
"node": {
|
||||
"abnormal": "Anormal",
|
||||
"actions": "Acțiuni",
|
||||
"address": "Adresă",
|
||||
"all": "Toate",
|
||||
"basicInfo": "Informații de bază",
|
||||
"cancel": "Anulează",
|
||||
"confirm": "Confirmă",
|
||||
"confirmDelete": "Sigur doriți să ștergeți?",
|
||||
"copy": "Copiază",
|
||||
"copySuccess": "Copiat cu succes",
|
||||
"create": "Creează",
|
||||
"createNode": "Creează nod",
|
||||
"createSuccess": "Creat cu succes",
|
||||
"delete": "Șterge",
|
||||
"deleteSuccess": "Șters cu succes",
|
||||
"deleteWarning": "După ștergere, datele nu vor putea fi recuperate. Vă rugăm să acționați cu prudență.",
|
||||
"detail": "Detaliu",
|
||||
"disabled": "Dezactivat",
|
||||
"disk": "Disc",
|
||||
"edit": "Editează",
|
||||
"editNode": "Editează nod",
|
||||
"enable": "Activează",
|
||||
"enabled": "Activat",
|
||||
"expireTime": "Timp de expirare",
|
||||
"hide": "Ascunde",
|
||||
"id": "ID",
|
||||
"ipAddresses": "Adrese IP",
|
||||
"lastUpdated": "Ultima actualizare",
|
||||
"location": "Locație",
|
||||
"memory": "Memorie",
|
||||
"name": "Nume",
|
||||
"noData": "--",
|
||||
"node": "Nod",
|
||||
"nodeDetail": "Detalii nod",
|
||||
"nodeGroup": "Grup de noduri",
|
||||
"nodeStatus": "Starea nodului",
|
||||
"normal": "Normal",
|
||||
"onlineCount": "Număr de utilizatori online",
|
||||
"onlineUsers": "Utilizatori online",
|
||||
"protocol": "Protocol",
|
||||
"rate": "Rată",
|
||||
"relay": "Retransmisie",
|
||||
"serverAddr": "Adresă server",
|
||||
"speedLimit": "Limită de viteză",
|
||||
"status": "Stare",
|
||||
"subscribeId": "ID abonament",
|
||||
"subscribeName": "Nume abonament",
|
||||
"subscription": "Abonament",
|
||||
"tags": "Etichete",
|
||||
"trafficRatio": "Rata de trafic",
|
||||
"trafficUsage": "Utilizare trafic",
|
||||
"type": "Tip",
|
||||
"updateSuccess": "Actualizat cu succes",
|
||||
"updatedAt": "Data actualizării",
|
||||
"user": "Utilizator",
|
||||
"userDetail": "Detalii utilizator",
|
||||
"userId": "ID utilizator"
|
||||
},
|
||||
"nodeForm": {
|
||||
"allowInsecure": "Permite Insecuritate",
|
||||
"cancel": "Anulează",
|
||||
"city": "Oraș",
|
||||
"confirm": "Confirmă",
|
||||
"congestionController": "Controler de Congestie",
|
||||
"country": "Țară",
|
||||
"disableSni": "Dezactivează SNI",
|
||||
"edit": "Editează",
|
||||
"editSecurity": "Editează Configurarea de Securitate",
|
||||
"enableTLS": "Activează TLS",
|
||||
"encryptionMethod": "Metodă de Criptare",
|
||||
"fingerprint": "Amprentă",
|
||||
"flow": "Algoritm de Control al Fluxului",
|
||||
"groupId": "Grup de Noduri",
|
||||
"hopInterval": "Interval de Salt",
|
||||
"hopPorts": "Porturi de Salt",
|
||||
"hopPortsPlaceholder": "Separă porturile multiple cu virgule",
|
||||
"name": "Nume",
|
||||
"obfsPassword": "Parolă de Obfuscatie",
|
||||
"obfsPasswordPlaceholder": "Lasă gol pentru fără obfuscatie",
|
||||
"path": "Cale",
|
||||
"pleaseSelect": "Te rugăm să Selectezi",
|
||||
"port": "Port Server",
|
||||
"protocol": "Protocol",
|
||||
"reduceRtt": "Reducere RTT",
|
||||
"relayHost": "Gazdă Relay",
|
||||
"relayMode": "Mod Relay",
|
||||
"relayPort": "Port Relay",
|
||||
"relayPrefix": "Prefix Relay",
|
||||
"remarks": "Observații",
|
||||
"security": "Securitate",
|
||||
"securityConfig": "Configurare Securitate",
|
||||
"selectEncryptionMethod": "Selectează Metoda de Criptare",
|
||||
"selectNodeGroup": "Selectează Grupul de Noduri",
|
||||
"selectProtocol": "Selectează Protocolul",
|
||||
"selectRelayMode": "Selectează Mod Relay",
|
||||
"serverAddr": "Adresă Server",
|
||||
"serverKey": "Cheie Server",
|
||||
"serverName": "Nume Serviciu",
|
||||
"speedLimit": "Limită de Viteză",
|
||||
"speedLimitPlaceholder": "Nelimitat",
|
||||
"tags": "Etichete",
|
||||
"tagsPlaceholder": "Folosește Enter sau virgulă (,) pentru a introduce etichete multiple",
|
||||
"trafficRatio": "Rată de Trafic",
|
||||
"transport": "Configurare Protocol de Transport",
|
||||
"transportConfig": "Configurare Protocol de Transport",
|
||||
"transportHost": "Adresă Server de Transport",
|
||||
"transportPath": "Cale de Transport",
|
||||
"transportServerName": "Nume Server de Transport",
|
||||
"udpRelayMode": "Mod Relay UDP"
|
||||
},
|
||||
"relayModeOptions": {
|
||||
"all": "Toate",
|
||||
"none": "Niciunul",
|
||||
"random": "Aleator"
|
||||
},
|
||||
"securityConfig": {
|
||||
"fingerprint": "Amprentă",
|
||||
"privateKey": "Cheie Privată",
|
||||
"privateKeyPlaceholder": "Lasă gol pentru generare automată",
|
||||
"publicKey": "Cheie Publică",
|
||||
"publicKeyPlaceholder": "Lasă gol pentru generare automată",
|
||||
"serverAddress": "Adresă Server",
|
||||
"serverAddressPlaceholder": "Adresă țintă REALITY, implicit folosind SNI",
|
||||
"serverName": "Nume Server (SNI)",
|
||||
"serverNamePlaceholder": "REALITY necesar, consistent cu backend-ul",
|
||||
"serverPort": "Port Server",
|
||||
"serverPortPlaceholder": "Port țintă REALITY, implicit 443",
|
||||
"shortId": "ID Scurt",
|
||||
"shortIdPlaceholder": "Lasă gol pentru generare automată",
|
||||
"sni": "Indicație Nume Server (SNI)"
|
||||
},
|
||||
"tabs": {
|
||||
"node": "Nod",
|
||||
"nodeConfig": "Configurare Nod",
|
||||
"nodeGroup": "Grup de noduri"
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user