feat(i18n): translate the log levels, access events and calendar labels (#6226)

* feat(i18n): translate the log levels, access events and calendar labels

The log-level selector, the access-log event tags, the Sub Formats sidebar
entry and the calendar choices were hardcoded English, so a fully translated
locale still showed them in English on core screens.

Add eleven keys across the 13 locales and reference them. Russian and
Ukrainian are translated; the remaining locales carry the English string, the
same convention the existing files already use for untranslated entries.

Two module-level constants had to move: the calendar list and the access-event
map were built outside the component, where t is not in scope. The event map
now stores keys and resolves them at render.

* fix(i18n): keep the log export language-independent and fit the translations

Three follow-ups from review. The downloaded x-ui.log had started carrying the
translated event text, so its contents depended on the panel language and the
Russian value for PROXY contains a space in a field format whose other values
are single tokens. The export keeps DIRECT/BLOCKED/PROXY; only the on-screen
tag is translated.

The log-level select had a fixed 95px width sized for "Warning", which clips
"Предупреждение"; it now grows with its content.

The three access filters stayed English while the tags they filter became
translated, so they use the same keys.

---------

Co-authored-by: n0ctal <n0ctal@users.noreply.github.com>
This commit is contained in:
n0ctal
2026-08-18 14:43:59 +05:00
committed by GitHub
parent 2b1fe1fd02
commit 5c9268c431
19 changed files with 234 additions and 66 deletions
+21 -9
View File
@@ -7,8 +7,8 @@
* - Please do NOT modify this file. * - Please do NOT modify this file.
*/ */
const PACKAGE_VERSION = '2.14.7' const PACKAGE_VERSION = '2.15.0'
const INTEGRITY_CHECKSUM = '4db4a41e972cec1b64cc569c66952d82' const INTEGRITY_CHECKSUM = '03cb67ac84128e63d7cd722a6e5b7f1e'
const IS_MOCKED_RESPONSE = Symbol('isMockedResponse') const IS_MOCKED_RESPONSE = Symbol('isMockedResponse')
const activeClientIds = new Set() const activeClientIds = new Set()
@@ -137,8 +137,18 @@ async function handleRequest(event, requestId, requestInterceptedAt) {
if (client && activeClientIds.has(client.id)) { if (client && activeClientIds.has(client.id)) {
const serializedRequest = await serializeRequest(requestCloneForEvents) const serializedRequest = await serializeRequest(requestCloneForEvents)
// Omit the body of server-sent event stream responses.
// Cloning such responses would prevent client-side stream cancelations
// from reaching the original stream (a teed stream only cancels its
// source once both of its branches cancel) and would buffer the
// entire stream into the unconsumed clone indefinitely.
const isEventStreamResponse = response.headers
.get('content-type')
?.toLowerCase()
.startsWith('text/event-stream')
// Clone the response so both the client and the library could consume it. // Clone the response so both the client and the library could consume it.
const responseClone = response.clone() const responseClone = isEventStreamResponse ? null : response.clone()
sendToClient( sendToClient(
client, client,
@@ -151,15 +161,17 @@ async function handleRequest(event, requestId, requestInterceptedAt) {
...serializedRequest, ...serializedRequest,
}, },
response: { response: {
type: responseClone.type, type: response.type,
status: responseClone.status, status: response.status,
statusText: responseClone.statusText, statusText: response.statusText,
headers: Object.fromEntries(responseClone.headers.entries()), headers: Object.fromEntries(response.headers.entries()),
body: responseClone.body, body: responseClone ? responseClone.body : null,
}, },
}, },
}, },
responseClone.body ? [serializedRequest.body, responseClone.body] : [], responseClone && responseClone.body
? [serializedRequest.body, responseClone.body]
: [],
) )
} }
+1 -1
View File
@@ -219,7 +219,7 @@ export default function AppSidebar() {
{ key: '/settings#subscription', icon: <CloudServerOutlined />, label: t('pages.settings.subSettings') }, { key: '/settings#subscription', icon: <CloudServerOutlined />, label: t('pages.settings.subSettings') },
]; ];
if (showSubFormats) { if (showSubFormats) {
children.push({ key: '/settings#subscription-formats', icon: <CodeOutlined />, label: 'Sub Formats' }); children.push({ key: '/settings#subscription-formats', icon: <CodeOutlined />, label: t('menu.subFormats') });
} }
return children; return children;
}, [t, showSubFormats]); }, [t, showSubFormats]);
+1 -1
View File
@@ -127,7 +127,7 @@ export default function IndexPage() {
async function copyConfig() { async function copyConfig() {
const ok = await ClipboardManager.copyText(configText || ''); const ok = await ClipboardManager.copyText(configText || '');
if (ok) messageApi.success('Copied'); if (ok) messageApi.success(t('copied'));
} }
function downloadConfig() { function downloadConfig() {
+6 -6
View File
@@ -105,14 +105,14 @@ export default function LogModal({ open, onClose }: LogModalProps) {
<Select <Select
value={level} value={level}
size="small" size="small"
style={{ width: 95 }} style={{ minWidth: 95 }}
onChange={setLevel} onChange={setLevel}
options={[ options={[
{ value: 'debug', label: 'Debug' }, { value: 'debug', label: t('pages.index.logLevelDebug') },
{ value: 'info', label: 'Info' }, { value: 'info', label: t('pages.index.logLevelInfo') },
{ value: 'notice', label: 'Notice' }, { value: 'notice', label: t('pages.index.logLevelNotice') },
{ value: 'warning', label: 'Warning' }, { value: 'warning', label: t('pages.index.logLevelWarning') },
{ value: 'err', label: 'Error' }, { value: 'err', label: t('pages.index.logLevelError') },
]} ]}
/> />
</Space.Compact> </Space.Compact>
+19 -5
View File
@@ -1,4 +1,5 @@
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import type { TFunction } from 'i18next';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Button, Checkbox, Form, Input, Modal, Select, Tag } from 'antd'; import { Button, Checkbox, Form, Input, Modal, Select, Tag } from 'antd';
import { DownloadOutlined, SyncOutlined } from '@ant-design/icons'; import { DownloadOutlined, SyncOutlined } from '@ant-design/icons';
@@ -24,11 +25,24 @@ interface XrayLogEntry {
Event?: number; Event?: number;
} }
const EVENT_LABELS: Record<number, string> = { 0: 'DIRECT', 1: 'BLOCKED', 2: 'PROXY' }; // The downloaded log is a data format people grep, so it keeps the stable
// tokens; only what is rendered on screen follows the panel language.
const EVENT_TOKENS: Record<number, string> = { 0: 'DIRECT', 1: 'BLOCKED', 2: 'PROXY' };
const EVENT_KEYS: Record<number, string> = {
0: 'pages.index.accessDirect',
1: 'pages.index.accessBlocked',
2: 'pages.index.accessProxy',
};
const EVENT_COLORS: Record<number, string> = { 0: 'green', 1: 'red', 2: 'blue' }; const EVENT_COLORS: Record<number, string> = { 0: 'green', 1: 'red', 2: 'blue' };
function eventLabel(ev?: number): string { function eventToken(ev?: number): string {
return EVENT_LABELS[ev ?? -1] ?? String(ev ?? ''); return EVENT_TOKENS[ev ?? -1] ?? String(ev ?? '');
}
function eventLabel(t: TFunction, ev?: number): string {
const key = EVENT_KEYS[ev ?? -1];
return key ? t(key) : String(ev ?? '');
} }
function eventColor(ev?: number): string { function eventColor(ev?: number): string {
@@ -112,7 +126,7 @@ export default function XrayLogModal({ open, onClose }: XrayLogModalProps) {
try { try {
const dt = l.DateTime ? new Date(l.DateTime) : null; const dt = l.DateTime ? new Date(l.DateTime) : null;
const dateStr = dt && !isNaN(dt.getTime()) ? dt.toISOString() : ''; const dateStr = dt && !isNaN(dt.getTime()) ? dt.toISOString() : '';
const eventText = eventLabel(l.Event); const eventText = eventToken(l.Event);
const emailPart = l.Email ? ` Email=${l.Email}` : ''; const emailPart = l.Email ? ` Email=${l.Email}` : '';
return `${dateStr} FROM=${l.FromAddress || ''} TO=${l.ToAddress || ''} INBOUND=${l.Inbound || ''} OUTBOUND=${l.Outbound || ''}${emailPart} EVENT=${eventText}`.trim(); return `${dateStr} FROM=${l.FromAddress || ''} TO=${l.ToAddress || ''} INBOUND=${l.Inbound || ''} OUTBOUND=${l.Outbound || ''}${emailPart} EVENT=${eventText}`.trim();
} catch { } catch {
@@ -193,7 +207,7 @@ export default function XrayLogModal({ open, onClose }: XrayLogModalProps) {
{shortTime(log.DateTime)} {shortTime(log.DateTime)}
</span> </span>
<Tag color={eventColor(log.Event)} className="log-event-tag"> <Tag color={eventColor(log.Event)} className="log-event-tag">
{eventLabel(log.Event)} {eventLabel(t, log.Event)}
</Tag> </Tag>
</div> </div>
<div className="log-route"> <div className="log-route">
+4 -5
View File
@@ -34,10 +34,6 @@ interface GeneralTabProps {
updateSetting: (patch: Partial<AllSetting>) => void; updateSetting: (patch: Partial<AllSetting>) => void;
} }
const DATEPICKER_LIST: { name: string; value: 'gregorian' | 'jalalian' }[] = [
{ name: 'Gregorian (Standard)', value: 'gregorian' },
{ name: 'Jalalian (شمسی)', value: 'jalalian' },
];
export default function GeneralTab({ allSetting, updateSetting }: GeneralTabProps) { export default function GeneralTab({ allSetting, updateSetting }: GeneralTabProps) {
const { t } = useTranslation(); const { t } = useTranslation();
@@ -290,7 +286,10 @@ export default function GeneralTab({ allSetting, updateSetting }: GeneralTabProp
value={allSetting.datepicker || 'gregorian'} value={allSetting.datepicker || 'gregorian'}
onChange={(v) => updateSetting({ datepicker: v as 'gregorian' | 'jalalian' })} onChange={(v) => updateSetting({ datepicker: v as 'gregorian' | 'jalalian' })}
style={{ width: '100%' }} style={{ width: '100%' }}
options={DATEPICKER_LIST.map((d) => ({ value: d.value, label: d.name }))} options={[
{ value: 'gregorian', label: t('pages.settings.calendarGregorian') },
{ value: 'jalalian', label: t('pages.settings.calendarJalalian') },
]}
/> />
</SettingListItem> </SettingListItem>
</> </>
+14 -3
View File
@@ -112,7 +112,8 @@
"docs": "التوثيق", "docs": "التوثيق",
"openMenu": "فتح القائمة", "openMenu": "فتح القائمة",
"pinSidebar": "تثبيت الشريط الجانبي", "pinSidebar": "تثبيت الشريط الجانبي",
"unpinSidebar": "إلغاء تثبيت الشريط الجانبي" "unpinSidebar": "إلغاء تثبيت الشريط الجانبي",
"subFormats": "Sub Formats"
}, },
"pages": { "pages": {
"login": { "login": {
@@ -257,7 +258,15 @@
"healthCritical": "{list} — حرج", "healthCritical": "{list} — حرج",
"panel": "اللوحة", "panel": "اللوحة",
"threads": "الخيوط", "threads": "الخيوط",
"uptime": "مدة التشغيل" "uptime": "مدة التشغيل",
"logLevelDebug": "Debug",
"logLevelInfo": "Info",
"logLevelNotice": "Notice",
"logLevelWarning": "Warning",
"logLevelError": "Error",
"accessDirect": "DIRECT",
"accessBlocked": "BLOCKED",
"accessProxy": "PROXY"
}, },
"inbounds": { "inbounds": {
"totalDownUp": "إجمالي المرسل/المستقبل", "totalDownUp": "إجمالي المرسل/المستقبل",
@@ -1352,7 +1361,9 @@
"pathLeadingSlash": "يجب أن يبدأ المسار بالرمز /" "pathLeadingSlash": "يجب أن يبدأ المسار بالرمز /"
}, },
"secretClear": "مسح", "secretClear": "مسح",
"secretClearUndo": "تراجع عن المسح" "secretClearUndo": "تراجع عن المسح",
"calendarGregorian": "Gregorian (Standard)",
"calendarJalalian": "Jalalian (شمسی)"
}, },
"xray": { "xray": {
"save": "احفظ", "save": "احفظ",
+14 -3
View File
@@ -112,7 +112,8 @@
"docs": "Documentation", "docs": "Documentation",
"openMenu": "Open menu", "openMenu": "Open menu",
"pinSidebar": "Pin sidebar", "pinSidebar": "Pin sidebar",
"unpinSidebar": "Unpin sidebar" "unpinSidebar": "Unpin sidebar",
"subFormats": "Sub Formats"
}, },
"pages": { "pages": {
"login": { "login": {
@@ -257,7 +258,15 @@
"healthCritical": "{list} — critical", "healthCritical": "{list} — critical",
"panel": "Panel", "panel": "Panel",
"threads": "Threads", "threads": "Threads",
"uptime": "Uptime" "uptime": "Uptime",
"logLevelDebug": "Debug",
"logLevelInfo": "Info",
"logLevelNotice": "Notice",
"logLevelWarning": "Warning",
"logLevelError": "Error",
"accessDirect": "DIRECT",
"accessBlocked": "BLOCKED",
"accessProxy": "PROXY"
}, },
"inbounds": { "inbounds": {
"totalDownUp": "Total Sent/Received", "totalDownUp": "Total Sent/Received",
@@ -1469,7 +1478,9 @@
"pathLeadingSlash": "Path must start with /" "pathLeadingSlash": "Path must start with /"
}, },
"secretClear": "Clear", "secretClear": "Clear",
"secretClearUndo": "Undo clear" "secretClearUndo": "Undo clear",
"calendarGregorian": "Gregorian (Standard)",
"calendarJalalian": "Jalalian (شمسی)"
}, },
"xray": { "xray": {
"save": "Save", "save": "Save",
+14 -3
View File
@@ -112,7 +112,8 @@
"docs": "Documentación", "docs": "Documentación",
"openMenu": "Abrir menú", "openMenu": "Abrir menú",
"pinSidebar": "Fijar barra lateral", "pinSidebar": "Fijar barra lateral",
"unpinSidebar": "Desfijar barra lateral" "unpinSidebar": "Desfijar barra lateral",
"subFormats": "Sub Formats"
}, },
"pages": { "pages": {
"login": { "login": {
@@ -257,7 +258,15 @@
"healthCritical": "{list} — crítico", "healthCritical": "{list} — crítico",
"panel": "Panel", "panel": "Panel",
"threads": "Hilos", "threads": "Hilos",
"uptime": "Tiempo activo" "uptime": "Tiempo activo",
"logLevelDebug": "Debug",
"logLevelInfo": "Info",
"logLevelNotice": "Notice",
"logLevelWarning": "Warning",
"logLevelError": "Error",
"accessDirect": "DIRECT",
"accessBlocked": "BLOCKED",
"accessProxy": "PROXY"
}, },
"inbounds": { "inbounds": {
"totalDownUp": "Subidas/Descargas Totales", "totalDownUp": "Subidas/Descargas Totales",
@@ -1352,7 +1361,9 @@
"pathLeadingSlash": "La ruta debe comenzar con /" "pathLeadingSlash": "La ruta debe comenzar con /"
}, },
"secretClear": "Borrar", "secretClear": "Borrar",
"secretClearUndo": "Deshacer borrado" "secretClearUndo": "Deshacer borrado",
"calendarGregorian": "Gregorian (Standard)",
"calendarJalalian": "Jalalian (شمسی)"
}, },
"xray": { "xray": {
"save": "Guardar configuración", "save": "Guardar configuración",
+14 -3
View File
@@ -112,7 +112,8 @@
"docs": "مستندات", "docs": "مستندات",
"openMenu": "باز کردن منو", "openMenu": "باز کردن منو",
"pinSidebar": "ثابت کردن نوار کناری", "pinSidebar": "ثابت کردن نوار کناری",
"unpinSidebar": "برداشتن تثبیت نوار کناری" "unpinSidebar": "برداشتن تثبیت نوار کناری",
"subFormats": "Sub Formats"
}, },
"pages": { "pages": {
"login": { "login": {
@@ -257,7 +258,15 @@
"healthCritical": "{list} — بحرانی", "healthCritical": "{list} — بحرانی",
"panel": "پنل", "panel": "پنل",
"threads": "نخ‌ها", "threads": "نخ‌ها",
"uptime": "مدت کارکرد" "uptime": "مدت کارکرد",
"logLevelDebug": "Debug",
"logLevelInfo": "Info",
"logLevelNotice": "Notice",
"logLevelWarning": "Warning",
"logLevelError": "Error",
"accessDirect": "DIRECT",
"accessBlocked": "BLOCKED",
"accessProxy": "PROXY"
}, },
"inbounds": { "inbounds": {
"totalDownUp": "دریافت/ارسال کل", "totalDownUp": "دریافت/ارسال کل",
@@ -1352,7 +1361,9 @@
"pathLeadingSlash": "مسیر باید با / شروع شود" "pathLeadingSlash": "مسیر باید با / شروع شود"
}, },
"secretClear": "پاک کردن", "secretClear": "پاک کردن",
"secretClearUndo": "لغو پاک کردن" "secretClearUndo": "لغو پاک کردن",
"calendarGregorian": "Gregorian (Standard)",
"calendarJalalian": "Jalalian (شمسی)"
}, },
"xray": { "xray": {
"save": "ذخیره", "save": "ذخیره",
+14 -3
View File
@@ -112,7 +112,8 @@
"docs": "Dokumentasi", "docs": "Dokumentasi",
"openMenu": "Buka menu", "openMenu": "Buka menu",
"pinSidebar": "Sematkan bilah sisi", "pinSidebar": "Sematkan bilah sisi",
"unpinSidebar": "Lepas sematan bilah sisi" "unpinSidebar": "Lepas sematan bilah sisi",
"subFormats": "Sub Formats"
}, },
"pages": { "pages": {
"login": { "login": {
@@ -257,7 +258,15 @@
"healthCritical": "{list} — kritis", "healthCritical": "{list} — kritis",
"panel": "Panel", "panel": "Panel",
"threads": "Thread", "threads": "Thread",
"uptime": "Waktu aktif" "uptime": "Waktu aktif",
"logLevelDebug": "Debug",
"logLevelInfo": "Info",
"logLevelNotice": "Notice",
"logLevelWarning": "Warning",
"logLevelError": "Error",
"accessDirect": "DIRECT",
"accessBlocked": "BLOCKED",
"accessProxy": "PROXY"
}, },
"inbounds": { "inbounds": {
"totalDownUp": "Total Terkirim/Diterima", "totalDownUp": "Total Terkirim/Diterima",
@@ -1352,7 +1361,9 @@
"pathLeadingSlash": "Path harus diawali dengan /" "pathLeadingSlash": "Path harus diawali dengan /"
}, },
"secretClear": "Hapus", "secretClear": "Hapus",
"secretClearUndo": "Batalkan hapus" "secretClearUndo": "Batalkan hapus",
"calendarGregorian": "Gregorian (Standard)",
"calendarJalalian": "Jalalian (شمسی)"
}, },
"xray": { "xray": {
"save": "Simpan", "save": "Simpan",
+14 -3
View File
@@ -112,7 +112,8 @@
"docs": "ドキュメント", "docs": "ドキュメント",
"openMenu": "メニューを開く", "openMenu": "メニューを開く",
"pinSidebar": "サイドバーを固定", "pinSidebar": "サイドバーを固定",
"unpinSidebar": "サイドバーの固定を解除" "unpinSidebar": "サイドバーの固定を解除",
"subFormats": "Sub Formats"
}, },
"pages": { "pages": {
"login": { "login": {
@@ -257,7 +258,15 @@
"healthCritical": "{list} — 危険水準", "healthCritical": "{list} — 危険水準",
"panel": "パネル", "panel": "パネル",
"threads": "スレッド", "threads": "スレッド",
"uptime": "稼働時間" "uptime": "稼働時間",
"logLevelDebug": "Debug",
"logLevelInfo": "Info",
"logLevelNotice": "Notice",
"logLevelWarning": "Warning",
"logLevelError": "Error",
"accessDirect": "DIRECT",
"accessBlocked": "BLOCKED",
"accessProxy": "PROXY"
}, },
"inbounds": { "inbounds": {
"totalDownUp": "総アップロード / ダウンロード", "totalDownUp": "総アップロード / ダウンロード",
@@ -1352,7 +1361,9 @@
"pathLeadingSlash": "パスは / で始まる必要があります" "pathLeadingSlash": "パスは / で始まる必要があります"
}, },
"secretClear": "クリア", "secretClear": "クリア",
"secretClearUndo": "クリアを取り消す" "secretClearUndo": "クリアを取り消す",
"calendarGregorian": "Gregorian (Standard)",
"calendarJalalian": "Jalalian (شمسی)"
}, },
"xray": { "xray": {
"importRules": "ルールをインポート", "importRules": "ルールをインポート",
+14 -3
View File
@@ -112,7 +112,8 @@
"docs": "Documentação", "docs": "Documentação",
"openMenu": "Abrir menu", "openMenu": "Abrir menu",
"pinSidebar": "Fixar barra lateral", "pinSidebar": "Fixar barra lateral",
"unpinSidebar": "Desafixar barra lateral" "unpinSidebar": "Desafixar barra lateral",
"subFormats": "Sub Formats"
}, },
"pages": { "pages": {
"login": { "login": {
@@ -257,7 +258,15 @@
"healthCritical": "{list} — crítico", "healthCritical": "{list} — crítico",
"panel": "Painel", "panel": "Painel",
"threads": "Threads", "threads": "Threads",
"uptime": "Tempo ativo" "uptime": "Tempo ativo",
"logLevelDebug": "Debug",
"logLevelInfo": "Info",
"logLevelNotice": "Notice",
"logLevelWarning": "Warning",
"logLevelError": "Error",
"accessDirect": "DIRECT",
"accessBlocked": "BLOCKED",
"accessProxy": "PROXY"
}, },
"inbounds": { "inbounds": {
"totalDownUp": "Total Enviado/Recebido", "totalDownUp": "Total Enviado/Recebido",
@@ -1352,7 +1361,9 @@
"pathLeadingSlash": "O caminho deve começar com /" "pathLeadingSlash": "O caminho deve começar com /"
}, },
"secretClear": "Limpar", "secretClear": "Limpar",
"secretClearUndo": "Desfazer limpeza" "secretClearUndo": "Desfazer limpeza",
"calendarGregorian": "Gregorian (Standard)",
"calendarJalalian": "Jalalian (شمسی)"
}, },
"xray": { "xray": {
"importRules": "Importar regras", "importRules": "Importar regras",
+14 -3
View File
@@ -112,7 +112,8 @@
"docs": "Документация", "docs": "Документация",
"openMenu": "Открыть меню", "openMenu": "Открыть меню",
"pinSidebar": "Закрепить боковую панель", "pinSidebar": "Закрепить боковую панель",
"unpinSidebar": "Открепить боковую панель" "unpinSidebar": "Открепить боковую панель",
"subFormats": "Форматы подписки"
}, },
"pages": { "pages": {
"login": { "login": {
@@ -257,7 +258,15 @@
"healthCritical": "{list} — критический уровень", "healthCritical": "{list} — критический уровень",
"panel": "Панель", "panel": "Панель",
"threads": "Потоки", "threads": "Потоки",
"uptime": "Время работы" "uptime": "Время работы",
"logLevelDebug": "Отладка",
"logLevelInfo": "Информация",
"logLevelNotice": "Уведомление",
"logLevelWarning": "Предупреждение",
"logLevelError": "Ошибка",
"accessDirect": "НАПРЯМУЮ",
"accessBlocked": "ЗАБЛОКИРОВАНО",
"accessProxy": "ЧЕРЕЗ ПРОКСИ"
}, },
"inbounds": { "inbounds": {
"totalDownUp": "Отправлено/получено", "totalDownUp": "Отправлено/получено",
@@ -1352,7 +1361,9 @@
"pathLeadingSlash": "Путь должен начинаться с /" "pathLeadingSlash": "Путь должен начинаться с /"
}, },
"secretClear": "Очистить", "secretClear": "Очистить",
"secretClearUndo": "Отменить очистку" "secretClearUndo": "Отменить очистку",
"calendarGregorian": "Григорианский (обычный)",
"calendarJalalian": "Джалали (شمسی)"
}, },
"xray": { "xray": {
"importRules": "Импорт правил", "importRules": "Импорт правил",
+14 -3
View File
@@ -112,7 +112,8 @@
"docs": "Belgeler", "docs": "Belgeler",
"openMenu": "Menüyü aç", "openMenu": "Menüyü aç",
"pinSidebar": "Kenar çubuğunu sabitle", "pinSidebar": "Kenar çubuğunu sabitle",
"unpinSidebar": "Kenar çubuğu sabitlemesini kaldır" "unpinSidebar": "Kenar çubuğu sabitlemesini kaldır",
"subFormats": "Sub Formats"
}, },
"pages": { "pages": {
"login": { "login": {
@@ -257,7 +258,15 @@
"healthCritical": "{list} — kritik", "healthCritical": "{list} — kritik",
"panel": "Panel", "panel": "Panel",
"threads": "İş parçacıkları", "threads": "İş parçacıkları",
"uptime": "Çalışma süresi" "uptime": "Çalışma süresi",
"logLevelDebug": "Debug",
"logLevelInfo": "Info",
"logLevelNotice": "Notice",
"logLevelWarning": "Warning",
"logLevelError": "Error",
"accessDirect": "DIRECT",
"accessBlocked": "BLOCKED",
"accessProxy": "PROXY"
}, },
"inbounds": { "inbounds": {
"totalDownUp": "Toplam Gönderilen/Alınan", "totalDownUp": "Toplam Gönderilen/Alınan",
@@ -1352,7 +1361,9 @@
"pathLeadingSlash": "Yol / ile başlamalıdır" "pathLeadingSlash": "Yol / ile başlamalıdır"
}, },
"secretClear": "Temizle", "secretClear": "Temizle",
"secretClearUndo": "Temizlemeyi geri al" "secretClearUndo": "Temizlemeyi geri al",
"calendarGregorian": "Gregorian (Standard)",
"calendarJalalian": "Jalalian (شمسی)"
}, },
"xray": { "xray": {
"save": "Kaydet", "save": "Kaydet",
+14 -3
View File
@@ -112,7 +112,8 @@
"docs": "Документація", "docs": "Документація",
"openMenu": "Відкрити меню", "openMenu": "Відкрити меню",
"pinSidebar": "Закріпити бічну панель", "pinSidebar": "Закріпити бічну панель",
"unpinSidebar": "Відкріпити бічну панель" "unpinSidebar": "Відкріпити бічну панель",
"subFormats": "Формати підписки"
}, },
"pages": { "pages": {
"login": { "login": {
@@ -257,7 +258,15 @@
"healthCritical": "{list} — критичний рівень", "healthCritical": "{list} — критичний рівень",
"panel": "Панель", "panel": "Панель",
"threads": "Потоки", "threads": "Потоки",
"uptime": "Час роботи" "uptime": "Час роботи",
"logLevelDebug": "Налагодження",
"logLevelInfo": "Інформація",
"logLevelNotice": "Сповіщення",
"logLevelWarning": "Попередження",
"logLevelError": "Помилка",
"accessDirect": "НАПРЯМУ",
"accessBlocked": "ЗАБЛОКОВАНО",
"accessProxy": "ЧЕРЕЗ ПРОКСІ"
}, },
"inbounds": { "inbounds": {
"totalDownUp": "Всього надісланих/отриманих", "totalDownUp": "Всього надісланих/отриманих",
@@ -1352,7 +1361,9 @@
"pathLeadingSlash": "Шлях має починатися з /" "pathLeadingSlash": "Шлях має починатися з /"
}, },
"secretClear": "Очистити", "secretClear": "Очистити",
"secretClearUndo": "Скасувати очищення" "secretClearUndo": "Скасувати очищення",
"calendarGregorian": "Григоріанський (звичайний)",
"calendarJalalian": "Джалалі (شمسی)"
}, },
"xray": { "xray": {
"save": "Зберегти", "save": "Зберегти",
+14 -3
View File
@@ -112,7 +112,8 @@
"docs": "Tài liệu", "docs": "Tài liệu",
"openMenu": "Mở menu", "openMenu": "Mở menu",
"pinSidebar": "Ghim thanh bên", "pinSidebar": "Ghim thanh bên",
"unpinSidebar": "Bỏ ghim thanh bên" "unpinSidebar": "Bỏ ghim thanh bên",
"subFormats": "Sub Formats"
}, },
"pages": { "pages": {
"login": { "login": {
@@ -257,7 +258,15 @@
"healthCritical": "{list} — nguy cấp", "healthCritical": "{list} — nguy cấp",
"panel": "Panel", "panel": "Panel",
"threads": "Luồng", "threads": "Luồng",
"uptime": "Thời gian chạy" "uptime": "Thời gian chạy",
"logLevelDebug": "Debug",
"logLevelInfo": "Info",
"logLevelNotice": "Notice",
"logLevelWarning": "Warning",
"logLevelError": "Error",
"accessDirect": "DIRECT",
"accessBlocked": "BLOCKED",
"accessProxy": "PROXY"
}, },
"inbounds": { "inbounds": {
"totalDownUp": "Tổng tải lên/tải xuống", "totalDownUp": "Tổng tải lên/tải xuống",
@@ -1352,7 +1361,9 @@
"pathLeadingSlash": "Đường dẫn phải bắt đầu bằng /" "pathLeadingSlash": "Đường dẫn phải bắt đầu bằng /"
}, },
"secretClear": "Xóa", "secretClear": "Xóa",
"secretClearUndo": "Hoàn tác xóa" "secretClearUndo": "Hoàn tác xóa",
"calendarGregorian": "Gregorian (Standard)",
"calendarJalalian": "Jalalian (شمسی)"
}, },
"xray": { "xray": {
"importRules": "Nhập quy tắc", "importRules": "Nhập quy tắc",
+14 -3
View File
@@ -112,7 +112,8 @@
"docs": "文档", "docs": "文档",
"openMenu": "打开菜单", "openMenu": "打开菜单",
"pinSidebar": "固定侧边栏", "pinSidebar": "固定侧边栏",
"unpinSidebar": "取消固定侧边栏" "unpinSidebar": "取消固定侧边栏",
"subFormats": "Sub Formats"
}, },
"pages": { "pages": {
"login": { "login": {
@@ -257,7 +258,15 @@
"healthCritical": "{list} — 危险", "healthCritical": "{list} — 危险",
"panel": "面板", "panel": "面板",
"threads": "线程", "threads": "线程",
"uptime": "运行时间" "uptime": "运行时间",
"logLevelDebug": "Debug",
"logLevelInfo": "Info",
"logLevelNotice": "Notice",
"logLevelWarning": "Warning",
"logLevelError": "Error",
"accessDirect": "DIRECT",
"accessBlocked": "BLOCKED",
"accessProxy": "PROXY"
}, },
"inbounds": { "inbounds": {
"totalDownUp": "总上传 / 下载", "totalDownUp": "总上传 / 下载",
@@ -1352,7 +1361,9 @@
"pathLeadingSlash": "路径必须以 / 开头" "pathLeadingSlash": "路径必须以 / 开头"
}, },
"secretClear": "清除", "secretClear": "清除",
"secretClearUndo": "撤销清除" "secretClearUndo": "撤销清除",
"calendarGregorian": "Gregorian (Standard)",
"calendarJalalian": "Jalalian (شمسی)"
}, },
"xray": { "xray": {
"importRules": "导入规则", "importRules": "导入规则",
+14 -3
View File
@@ -112,7 +112,8 @@
"docs": "文件", "docs": "文件",
"openMenu": "開啟選單", "openMenu": "開啟選單",
"pinSidebar": "固定側邊欄", "pinSidebar": "固定側邊欄",
"unpinSidebar": "取消固定側邊欄" "unpinSidebar": "取消固定側邊欄",
"subFormats": "Sub Formats"
}, },
"pages": { "pages": {
"login": { "login": {
@@ -257,7 +258,15 @@
"healthCritical": "{list} — 危險", "healthCritical": "{list} — 危險",
"panel": "面板", "panel": "面板",
"threads": "執行緒", "threads": "執行緒",
"uptime": "執行時間" "uptime": "執行時間",
"logLevelDebug": "Debug",
"logLevelInfo": "Info",
"logLevelNotice": "Notice",
"logLevelWarning": "Warning",
"logLevelError": "Error",
"accessDirect": "DIRECT",
"accessBlocked": "BLOCKED",
"accessProxy": "PROXY"
}, },
"inbounds": { "inbounds": {
"totalDownUp": "總上傳 / 下載", "totalDownUp": "總上傳 / 下載",
@@ -1352,7 +1361,9 @@
"pathLeadingSlash": "路徑必須以 / 開頭" "pathLeadingSlash": "路徑必須以 / 開頭"
}, },
"secretClear": "清除", "secretClear": "清除",
"secretClearUndo": "復原清除" "secretClearUndo": "復原清除",
"calendarGregorian": "Gregorian (Standard)",
"calendarJalalian": "Jalalian (شمسی)"
}, },
"xray": { "xray": {
"save": "儲存", "save": "儲存",