mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-05-13 13:58:22 +00:00
i18n: localize sidebar theme toggle, xray-status badge, and nodes menu
The sidebar theme submenu (Theme / Dark / Ultra dark) and the dashboard's
Xray status badge ("Xray is running" etc.) were hardcoded English strings.
Wire them through vue-i18n: ThemeSwitch.vue uses menu.theme/dark/ultraDark,
and XrayStatusCard.vue derives the badge text from the existing
pages.index.xrayStatus{Running,Stop,Error,Unknown} keys (status.js no
longer carries an English stateMsg field).
The "Nodes" menu item was already keyed as menu.nodes but only en-US and
fa-IR had a translation; add it to the other 11 languages, matching the
wording each file already uses for pages.nodes.title.
#4201
This commit is contained in:
parent
444b05cac9
commit
cf5767acd1
15 changed files with 33 additions and 20 deletions
|
|
@ -1,8 +1,11 @@
|
|||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { BulbFilled, BulbOutlined } from '@ant-design/icons-vue';
|
||||
import { theme, currentTheme, toggleTheme, toggleUltra, pauseAnimationsUntilLeave } from '@/composables/useTheme.js';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const BulbIcon = computed(() => (theme.isDark ? BulbFilled : BulbOutlined));
|
||||
|
||||
function onDarkChange() {
|
||||
|
|
@ -22,17 +25,17 @@ function onUltraClick() {
|
|||
<template #title>
|
||||
<span>
|
||||
<component :is="BulbIcon" />
|
||||
<span class="theme-label">Theme</span>
|
||||
<span class="theme-label">{{ t('menu.theme') }}</span>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<a-menu-item id="change-theme" class="ant-menu-theme-switch">
|
||||
<span>Dark</span>
|
||||
<span>{{ t('menu.dark') }}</span>
|
||||
<a-switch :style="{ marginLeft: '2px' }" size="small" :checked="theme.isDark" @change="onDarkChange" />
|
||||
</a-menu-item>
|
||||
|
||||
<a-menu-item v-if="theme.isDark" id="change-theme-ultra" class="ant-menu-theme-switch">
|
||||
<span>Ultra dark</span>
|
||||
<span>{{ t('menu.ultraDark') }}</span>
|
||||
<a-checkbox :style="{ marginLeft: '2px' }" :checked="theme.isUltra" @click="onUltraClick" />
|
||||
</a-menu-item>
|
||||
</a-sub-menu>
|
||||
|
|
|
|||
|
|
@ -27,12 +27,6 @@ const XRAY_STATE_COLORS = {
|
|||
error: 'red',
|
||||
};
|
||||
|
||||
const XRAY_STATE_MESSAGES = {
|
||||
running: 'Xray is running',
|
||||
stop: 'Xray is stopped',
|
||||
error: 'Xray error',
|
||||
};
|
||||
|
||||
export class Status {
|
||||
constructor(data) {
|
||||
this.cpu = new CurTotal(0, 0);
|
||||
|
|
@ -51,7 +45,7 @@ export class Status {
|
|||
this.uptime = 0;
|
||||
this.appUptime = 0;
|
||||
this.appStats = { threads: 0, mem: 0, uptime: 0 };
|
||||
this.xray = { state: 'stop', stateMsg: '', errorMsg: '', version: '', color: '' };
|
||||
this.xray = { state: 'stop', errorMsg: '', version: '', color: '' };
|
||||
|
||||
if (data == null) return;
|
||||
|
||||
|
|
@ -73,6 +67,5 @@ export class Status {
|
|||
this.appStats = data.appStats ?? this.appStats;
|
||||
this.xray = { ...this.xray, ...(data.xray || {}) };
|
||||
this.xray.color = XRAY_STATE_COLORS[this.xray.state] ?? 'gray';
|
||||
this.xray.stateMsg = XRAY_STATE_MESSAGES[this.xray.state] ?? 'Unknown';
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import {
|
||||
BarsOutlined,
|
||||
|
|
@ -9,7 +10,7 @@ import {
|
|||
|
||||
const { t } = useI18n();
|
||||
|
||||
defineProps({
|
||||
const props = defineProps({
|
||||
status: { type: Object, required: true },
|
||||
isMobile: { type: Boolean, default: false },
|
||||
ipLimitEnable: { type: Boolean, default: false },
|
||||
|
|
@ -17,10 +18,16 @@ defineProps({
|
|||
|
||||
defineEmits(['stop-xray', 'restart-xray', 'open-logs', 'open-xray-logs', 'open-version-switch']);
|
||||
|
||||
// Map xray.color → which animation class to apply on the badge dot.
|
||||
// The legacy .xray-*-animation classes only override the badge ring
|
||||
// color; the actual pulsing comes from .xray-processing-animation
|
||||
// (which animates .ant-badge-status-dot via @keyframes runningAnimation).
|
||||
const XRAY_STATE_KEYS = {
|
||||
running: 'pages.index.xrayStatusRunning',
|
||||
stop: 'pages.index.xrayStatusStop',
|
||||
error: 'pages.index.xrayStatusError',
|
||||
};
|
||||
|
||||
const stateText = computed(() =>
|
||||
t(XRAY_STATE_KEYS[props.status.xray.state] ?? 'pages.index.xrayStatusUnknown'),
|
||||
);
|
||||
|
||||
function badgeAnimationClass(color) {
|
||||
if (color === 'green') return 'xray-running-animation';
|
||||
if (color === 'orange') return 'xray-stop-animation';
|
||||
|
|
@ -43,7 +50,7 @@ function badgeAnimationClass(color) {
|
|||
<template #extra>
|
||||
<template v-if="status.xray.state !== 'error'">
|
||||
<a-badge status="processing" :class="['xray-processing-animation', badgeAnimationClass(status.xray.color)]"
|
||||
:text="status.xray.stateMsg" :color="status.xray.color" />
|
||||
:text="stateText" :color="status.xray.color" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<a-popover>
|
||||
|
|
@ -60,7 +67,7 @@ function badgeAnimationClass(color) {
|
|||
{{ line }}
|
||||
</span>
|
||||
</template>
|
||||
<a-badge status="processing" :text="status.xray.stateMsg" :color="status.xray.color"
|
||||
<a-badge status="processing" :text="stateText" :color="status.xray.color"
|
||||
:class="['xray-processing-animation', 'xray-error-animation']" />
|
||||
</a-popover>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@
|
|||
"ultraDark": "داكن جدًا",
|
||||
"dashboard": "نظرة عامة",
|
||||
"inbounds": "الإدخالات",
|
||||
"nodes": "النودز",
|
||||
"settings": "إعدادات البانل",
|
||||
"xray": "إعدادات Xray",
|
||||
"logout": "تسجيل خروج",
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@
|
|||
"ultraDark": "Ultra Oscuro",
|
||||
"dashboard": "Estado del Sistema",
|
||||
"inbounds": "Entradas",
|
||||
"nodes": "Nodos",
|
||||
"settings": "Configuraciones",
|
||||
"xray": "Ajustes Xray",
|
||||
"logout": "Cerrar Sesión",
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@
|
|||
"ultraDark": "Sangat Gelap",
|
||||
"dashboard": "Ikhtisar",
|
||||
"inbounds": "Masuk",
|
||||
"nodes": "Node",
|
||||
"settings": "Pengaturan Panel",
|
||||
"xray": "Konfigurasi Xray",
|
||||
"logout": "Keluar",
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@
|
|||
"ultraDark": "ウルトラダーク",
|
||||
"dashboard": "ダッシュボード",
|
||||
"inbounds": "インバウンド一覧",
|
||||
"nodes": "ノード",
|
||||
"settings": "パネル設定",
|
||||
"xray": "Xray設定",
|
||||
"logout": "ログアウト",
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@
|
|||
"ultraDark": "Ultra Escuro",
|
||||
"dashboard": "Visão Geral",
|
||||
"inbounds": "Inbounds",
|
||||
"nodes": "Nós",
|
||||
"settings": "Panel Settings",
|
||||
"xray": "Xray Configs",
|
||||
"logout": "Sair",
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@
|
|||
"ultraDark": "Очень темная",
|
||||
"dashboard": "Дашборд",
|
||||
"inbounds": "Подключения",
|
||||
"nodes": "Узлы",
|
||||
"settings": "Настройки",
|
||||
"xray": "Настройки Xray",
|
||||
"logout": "Выход",
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@
|
|||
"ultraDark": "Ultra Koyu",
|
||||
"dashboard": "Genel Bakış",
|
||||
"inbounds": "Gelenler",
|
||||
"nodes": "Düğümler",
|
||||
"settings": "Panel Ayarları",
|
||||
"xray": "Xray Yapılandırmaları",
|
||||
"logout": "Çıkış Yap",
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@
|
|||
"ultraDark": "Ультра темна",
|
||||
"dashboard": "Огляд",
|
||||
"inbounds": "Вхідні",
|
||||
"nodes": "Вузли",
|
||||
"settings": "Параметри панелі",
|
||||
"xray": "Конфігурації Xray",
|
||||
"logout": "Вийти",
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@
|
|||
"ultraDark": "Siêu tối",
|
||||
"dashboard": "Trạng thái hệ thống",
|
||||
"inbounds": "Đầu vào khách hàng",
|
||||
"nodes": "Nút",
|
||||
"settings": "Cài đặt bảng điều khiển",
|
||||
"logout": "Đăng xuất",
|
||||
"xray": "Cài đặt Xray",
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@
|
|||
"ultraDark": "超暗色",
|
||||
"dashboard": "系统状态",
|
||||
"inbounds": "入站列表",
|
||||
"nodes": "节点",
|
||||
"settings": "面板设置",
|
||||
"xray": "Xray 设置",
|
||||
"logout": "退出登录",
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@
|
|||
"ultraDark": "超深色",
|
||||
"dashboard": "系統狀態",
|
||||
"inbounds": "入站列表",
|
||||
"nodes": "節點",
|
||||
"settings": "面板設定",
|
||||
"xray": "Xray 設定",
|
||||
"logout": "退出登入",
|
||||
|
|
|
|||
|
|
@ -280,8 +280,7 @@ func (s *Server) startTask() {
|
|||
|
||||
go func() {
|
||||
time.Sleep(time.Second * 5)
|
||||
// Statistics every 10 seconds, start the delay for 5 seconds for the first time, and staggered with the time to restart xray
|
||||
s.cron.AddJob("@every 10s", job.NewXrayTrafficJob())
|
||||
s.cron.AddJob("@every 5s", job.NewXrayTrafficJob())
|
||||
}()
|
||||
|
||||
// check client ips from log file every 10 sec
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue