chore: add missing i18n strings and UI adjustments

This commit is contained in:
pompurin404 2025-02-04 13:27:25 +08:00
parent 4a48445043
commit f2a4049f6c
8 changed files with 64 additions and 57 deletions

View File

@ -38,13 +38,14 @@ import os from 'os'
import { createWriteStream, existsSync } from 'fs' import { createWriteStream, existsSync } from 'fs'
import { uploadRuntimeConfig } from '../resolve/gistApi' import { uploadRuntimeConfig } from '../resolve/gistApi'
import { startMonitor } from '../resolve/trafficMonitor' import { startMonitor } from '../resolve/trafficMonitor'
import i18next from '../../shared/i18n'
chokidar.watch(path.join(mihomoCoreDir(), 'meta-update'), {}).on('unlinkDir', async () => { chokidar.watch(path.join(mihomoCoreDir(), 'meta-update'), {}).on('unlinkDir', async () => {
try { try {
await stopCore(true) await stopCore(true)
await startCore() await startCore()
} catch (e) { } catch (e) {
dialog.showErrorBox('内核启动出错', `${e}`) dialog.showErrorBox(i18next.t('mihomo.error.coreStartFailed'), `${e}`)
} }
}) })
@ -130,7 +131,7 @@ export async function startCore(detached = false): Promise<Promise<void>[]> {
patchControledMihomoConfig({ tun: { enable: false } }) patchControledMihomoConfig({ tun: { enable: false } })
mainWindow?.webContents.send('controledMihomoConfigUpdated') mainWindow?.webContents.send('controledMihomoConfigUpdated')
ipcMain.emit('updateTrayMenu') ipcMain.emit('updateTrayMenu')
reject('虚拟网卡启动失败, 请尝试手动授予内核权限') reject(i18next.t('tun.error.tunPermissionDenied'))
} }
if ( if (
@ -189,7 +190,7 @@ export async function restartCore(): Promise<void> {
try { try {
await startCore() await startCore()
} catch (e) { } catch (e) {
dialog.showErrorBox('内核启动出错', `${e}`) dialog.showErrorBox(i18next.t('mihomo.error.coreStartFailed'), `${e}`)
} }
} }
@ -200,7 +201,7 @@ export async function keepCoreAlive(): Promise<void> {
await writeFile(path.join(dataDir(), 'core.pid'), child.pid.toString()) await writeFile(path.join(dataDir(), 'core.pid'), child.pid.toString())
} }
} catch (e) { } catch (e) {
dialog.showErrorBox('内核启动出错', `${e}`) dialog.showErrorBox(i18next.t('mihomo.error.coreStartFailed'), `${e}`)
} }
} }
@ -230,7 +231,7 @@ async function checkProfile(): Promise<void> {
.split('\n') .split('\n')
.filter((line) => line.includes('level=error')) .filter((line) => line.includes('level=error'))
.map((line) => line.split('level=error')[1]) .map((line) => line.split('level=error')[1])
throw new Error(`Profile Check Failed:\n${errorLines.join('\n')}`) throw new Error(`${i18next.t('mihomo.error.profileCheckFailed')}:\n${errorLines.join('\n')}`)
} else { } else {
throw error throw error
} }

View File

@ -50,8 +50,8 @@ if (process.platform === 'win32' && !is.dev && !process.argv.includes('noadmin')
// ignore // ignore
} }
dialog.showErrorBox( dialog.showErrorBox(
i18next.t('main.error.adminRequired'), i18next.t('common.error.adminRequired'),
`${i18next.t('main.error.adminRequired')}\n${createErrorStr}\n${eStr}` `${i18next.t('common.error.adminRequired')}\n${createErrorStr}\n${eStr}`
) )
} finally { } finally {
app.exit() app.exit()
@ -123,12 +123,13 @@ powerMonitor.on('shutdown', async () => {
app.whenReady().then(async () => { app.whenReady().then(async () => {
// Set app user model id for windows // Set app user model id for windows
electronApp.setAppUserModelId('party.mihomo.app') electronApp.setAppUserModelId('party.mihomo.app')
try { try {
const appConfig = await getAppConfig() const appConfig = await getAppConfig()
await initI18n({ lng: appConfig.language }) await initI18n({ lng: appConfig.language })
await initPromise await initPromise
} catch (e) { } catch (e) {
dialog.showErrorBox(i18next.t('main.error.initFailed'), `${e}`) dialog.showErrorBox(i18next.t('common.error.initFailed'), `${e}`)
app.quit() app.quit()
} }
try { try {
@ -137,7 +138,7 @@ app.whenReady().then(async () => {
await initProfileUpdater() await initProfileUpdater()
}) })
} catch (e) { } catch (e) {
dialog.showErrorBox(i18next.t('main.error.coreStartFailed'), `${e}`) dialog.showErrorBox(i18next.t('mihomo.error.coreStartFailed'), `${e}`)
} }
try { try {
await startMonitor() await startMonitor()
@ -178,7 +179,7 @@ async function handleDeepLink(url: string): Promise<void> {
const profileUrl = urlObj.searchParams.get('url') const profileUrl = urlObj.searchParams.get('url')
const profileName = urlObj.searchParams.get('name') const profileName = urlObj.searchParams.get('name')
if (!profileUrl) { if (!profileUrl) {
throw new Error(i18next.t('main.error.urlParamMissing')) throw new Error(i18next.t('profiles.error.urlParamMissing'))
} }
await addProfileItem({ await addProfileItem({
type: 'remote', type: 'remote',
@ -186,10 +187,10 @@ async function handleDeepLink(url: string): Promise<void> {
url: profileUrl url: profileUrl
}) })
mainWindow?.webContents.send('profileConfigUpdated') mainWindow?.webContents.send('profileConfigUpdated')
new Notification({ title: i18next.t('main.notification.importSuccess') }).show() new Notification({ title: i18next.t('profiles.notification.importSuccess') }).show()
break break
} catch (e) { } catch (e) {
dialog.showErrorBox(i18next.t('main.error.importFailed'), `${url}\n${e}`) dialog.showErrorBox(i18next.t('profiles.error.importFailed'), `${url}\n${e}`)
} }
} }
} }

View File

@ -10,6 +10,7 @@ import { triggerSysProxy } from '../sys/sysproxy'
import { patchMihomoConfig } from '../core/mihomoApi' import { patchMihomoConfig } from '../core/mihomoApi'
import { quitWithoutCore, restartCore } from '../core/manager' import { quitWithoutCore, restartCore } from '../core/manager'
import { floatingWindow, triggerFloatingWindow } from './floatingWindow' import { floatingWindow, triggerFloatingWindow } from './floatingWindow'
import i18next from '../../shared/i18n'
export async function registerShortcut( export async function registerShortcut(
oldShortcut: string, oldShortcut: string,
@ -42,7 +43,7 @@ export async function registerShortcut(
await triggerSysProxy(!enable) await triggerSysProxy(!enable)
await patchAppConfig({ sysProxy: { enable: !enable } }) await patchAppConfig({ sysProxy: { enable: !enable } })
new Notification({ new Notification({
title: `系统代理已${!enable ? '开启' : '关闭'}` title: i18next.t(!enable ? 'common.notification.systemProxyEnabled' : 'common.notification.systemProxyDisabled')
}).show() }).show()
mainWindow?.webContents.send('appConfigUpdated') mainWindow?.webContents.send('appConfigUpdated')
floatingWindow?.webContents.send('appConfigUpdated') floatingWindow?.webContents.send('appConfigUpdated')
@ -65,7 +66,7 @@ export async function registerShortcut(
} }
await restartCore() await restartCore()
new Notification({ new Notification({
title: `虚拟网卡已${!enable ? '开启' : '关闭'}` title: i18next.t(!enable ? 'common.notification.tunEnabled' : 'common.notification.tunDisabled')
}).show() }).show()
mainWindow?.webContents.send('controledMihomoConfigUpdated') mainWindow?.webContents.send('controledMihomoConfigUpdated')
floatingWindow?.webContents.send('appConfigUpdated') floatingWindow?.webContents.send('appConfigUpdated')
@ -81,7 +82,7 @@ export async function registerShortcut(
await patchControledMihomoConfig({ mode: 'rule' }) await patchControledMihomoConfig({ mode: 'rule' })
await patchMihomoConfig({ mode: 'rule' }) await patchMihomoConfig({ mode: 'rule' })
new Notification({ new Notification({
title: '已切换至规则模式' title: i18next.t('common.notification.ruleMode')
}).show() }).show()
mainWindow?.webContents.send('controledMihomoConfigUpdated') mainWindow?.webContents.send('controledMihomoConfigUpdated')
ipcMain.emit('updateTrayMenu') ipcMain.emit('updateTrayMenu')
@ -92,7 +93,7 @@ export async function registerShortcut(
await patchControledMihomoConfig({ mode: 'global' }) await patchControledMihomoConfig({ mode: 'global' })
await patchMihomoConfig({ mode: 'global' }) await patchMihomoConfig({ mode: 'global' })
new Notification({ new Notification({
title: '已切换至全局模式' title: i18next.t('common.notification.globalMode')
}).show() }).show()
mainWindow?.webContents.send('controledMihomoConfigUpdated') mainWindow?.webContents.send('controledMihomoConfigUpdated')
ipcMain.emit('updateTrayMenu') ipcMain.emit('updateTrayMenu')
@ -103,7 +104,7 @@ export async function registerShortcut(
await patchControledMihomoConfig({ mode: 'direct' }) await patchControledMihomoConfig({ mode: 'direct' })
await patchMihomoConfig({ mode: 'direct' }) await patchMihomoConfig({ mode: 'direct' })
new Notification({ new Notification({
title: '已切换至直连模式' title: i18next.t('common.notification.directMode')
}).show() }).show()
mainWindow?.webContents.send('controledMihomoConfigUpdated') mainWindow?.webContents.send('controledMihomoConfigUpdated')
ipcMain.emit('updateTrayMenu') ipcMain.emit('updateTrayMenu')

View File

@ -109,7 +109,7 @@ const WebdavConfig: React.FC = () => {
className="ml-1" className="ml-1"
onPress={handleRestore} onPress={handleRestore}
> >
{t('webdav.restore')} {t('webdav.restore.title')}
</Button> </Button>
</div> </div>
</SettingCard> </SettingCard>

View File

@ -31,7 +31,9 @@
"restoreFailed": "Failed to restore: {{error}}", "restoreFailed": "Failed to restore: {{error}}",
"deleteFailed": "Failed to delete: {{error}}", "deleteFailed": "Failed to delete: {{error}}",
"shortcutRegistrationFailed": "Failed to register shortcut", "shortcutRegistrationFailed": "Failed to register shortcut",
"shortcutRegistrationFailedWithError": "Failed to register shortcut: {{error}}" "shortcutRegistrationFailedWithError": "Failed to register shortcut: {{error}}",
"adminRequired": "Please run with administrator privileges for first launch",
"initFailed": "Application initialization failed"
}, },
"updater": { "updater": {
"versionReady": "v{{version}} Version Ready", "versionReady": "v{{version}} Version Ready",
@ -129,8 +131,8 @@
"coreUpgradeSuccess": "Core upgrade successful. If you want to use virtual network card (Tun), please go to the virtual network card page to manually authorize the Core again", "coreUpgradeSuccess": "Core upgrade successful. If you want to use virtual network card (Tun), please go to the virtual network card page to manually authorize the Core again",
"alreadyLatestVersion": "Already Latest Version", "alreadyLatestVersion": "Already Latest Version",
"selectCoreVersion": "Select Core Version", "selectCoreVersion": "Select Core Version",
"stableVersion": "Stable Version", "stableVersion": "Stable",
"alphaVersion": "Alpha Version", "alphaVersion": "Alpha",
"mixedPort": "Mixed Port", "mixedPort": "Mixed Port",
"confirm": "Confirm", "confirm": "Confirm",
"socksPort": "Socks Port", "socksPort": "Socks Port",
@ -152,7 +154,10 @@
"logLevel": "Log Level", "logLevel": "Log Level",
"selectLogLevel": "Select Log Level", "selectLogLevel": "Select Log Level",
"silent": "Silent", "silent": "Silent",
"error": "Error", "error": {
"coreStartFailed": "Core start failed",
"profileCheckFailed": "Profile Check Failed"
},
"warning": "Warning", "warning": "Warning",
"info": "Info", "info": "Info",
"debug": "Debug", "debug": "Debug",
@ -310,6 +315,7 @@
} }
}, },
"proxies": { "proxies": {
"title": "Proxy Groups & Nodes",
"card": { "card": {
"title": "ProxyGrp" "title": "ProxyGrp"
}, },
@ -418,6 +424,9 @@
"notifications": { "notifications": {
"coreAuthSuccess": "Core Authorization Successful", "coreAuthSuccess": "Core Authorization Successful",
"firewallResetSuccess": "Firewall Reset Successful" "firewallResetSuccess": "Firewall Reset Successful"
},
"error": {
"tunPermissionDenied": "TUN interface start failed, please try to manually grant core permissions"
} }
}, },
"dns": { "dns": {
@ -471,7 +480,9 @@
"visit": "Visit Sub-Store" "visit": "Visit Sub-Store"
}, },
"error": { "error": {
"unsupportedFileType": "Unsupported file type" "unsupportedFileType": "Unsupported file type",
"urlParamMissing": "Missing parameter: url",
"importFailed": "Subscription import failed"
}, },
"emptyProfile": "Empty Profile", "emptyProfile": "Empty Profile",
"viewRuntimeConfig": "View Current Runtime Config", "viewRuntimeConfig": "View Current Runtime Config",
@ -506,6 +517,9 @@
"expired": "Expired", "expired": "Expired",
"remainingDays": "{{days}} days", "remainingDays": "{{days}} days",
"lastUpdate": "Last updated: {{time}}" "lastUpdate": "Last updated: {{time}}"
},
"notification": {
"importSuccess": "Subscription imported successfully"
} }
}, },
"outbound": { "outbound": {
@ -575,10 +589,10 @@
"filter": "Filter", "filter": "Filter",
"orderBy": "Order By", "orderBy": "Order By",
"time": "Time", "time": "Time",
"uploadAmount": "Upload Amount", "uploadAmount": "Up Amount",
"downloadAmount": "Download Amount", "downloadAmount": "Down Amount",
"uploadSpeed": "Upload Speed", "uploadSpeed": "Up Speed",
"downloadSpeed": "Download Speed", "downloadSpeed": "Down Speed",
"detail": { "detail": {
"title": "Connection Details", "title": "Connection Details",
"establishTime": "Establish Time", "establishTime": "Establish Time",
@ -708,17 +722,5 @@
"title": "Tutorial Complete", "title": "Tutorial Complete",
"description": "Now that you understand the basic usage of the software, import your subscription and start using it. Enjoy!\nYou can also join our official <a href=\"https://t.me/mihomo_party_group\" target=\"_blank\">Telegram group</a> for the latest news." "description": "Now that you understand the basic usage of the software, import your subscription and start using it. Enjoy!\nYou can also join our official <a href=\"https://t.me/mihomo_party_group\" target=\"_blank\">Telegram group</a> for the latest news."
} }
},
"main": {
"error": {
"adminRequired": "Please run with administrator privileges for first launch",
"initFailed": "Application initialization failed",
"coreStartFailed": "Core startup error",
"importFailed": "Subscription import failed",
"urlParamMissing": "Missing parameter: url"
},
"notification": {
"importSuccess": "Subscription imported successfully"
}
} }
} }

View File

@ -31,7 +31,9 @@
"restoreFailed": "恢复失败:{{error}}", "restoreFailed": "恢复失败:{{error}}",
"deleteFailed": "删除失败:{{error}}", "deleteFailed": "删除失败:{{error}}",
"shortcutRegistrationFailed": "快捷键注册失败", "shortcutRegistrationFailed": "快捷键注册失败",
"shortcutRegistrationFailedWithError": "快捷键注册失败:{{error}}" "shortcutRegistrationFailedWithError": "快捷键注册失败:{{error}}",
"adminRequired": "首次启动请以管理员权限运行",
"initFailed": "应用初始化失败"
}, },
"updater": { "updater": {
"versionReady": "v{{version}} 版本就绪", "versionReady": "v{{version}} 版本就绪",
@ -152,7 +154,10 @@
"logLevel": "日志等级", "logLevel": "日志等级",
"selectLogLevel": "选择日志等级", "selectLogLevel": "选择日志等级",
"silent": "静默", "silent": "静默",
"error": "错误", "error": {
"coreStartFailed": "内核启动出错",
"profileCheckFailed": "配置检查失败"
},
"warning": "警告", "warning": "警告",
"info": "信息", "info": "信息",
"debug": "调试", "debug": "调试",
@ -310,6 +315,7 @@
} }
}, },
"proxies": { "proxies": {
"title": "代理组与节点",
"card": { "card": {
"title": "代理组" "title": "代理组"
}, },
@ -418,6 +424,9 @@
"notifications": { "notifications": {
"coreAuthSuccess": "内核授权成功", "coreAuthSuccess": "内核授权成功",
"firewallResetSuccess": "防火墙重设成功" "firewallResetSuccess": "防火墙重设成功"
},
"error": {
"tunPermissionDenied": "虚拟网卡启动失败,请尝试手动授予内核权限"
} }
}, },
"dns": { "dns": {
@ -471,7 +480,9 @@
"visit": "访问 Sub-Store" "visit": "访问 Sub-Store"
}, },
"error": { "error": {
"unsupportedFileType": "不支持的文件类型" "unsupportedFileType": "不支持的文件类型",
"urlParamMissing": "缺少参数 url",
"importFailed": "订阅导入失败"
}, },
"emptyProfile": "空白订阅", "emptyProfile": "空白订阅",
"viewRuntimeConfig": "查看当前运行时配置", "viewRuntimeConfig": "查看当前运行时配置",
@ -506,7 +517,10 @@
"feature": "功能" "feature": "功能"
}, },
"openFile": "打开文件", "openFile": "打开文件",
"home": "主页" "home": "主页",
"notification": {
"importSuccess": "订阅导入成功"
}
}, },
"outbound": { "outbound": {
"title": "出站模式", "title": "出站模式",
@ -708,17 +722,5 @@
"title": "教程结束", "title": "教程结束",
"description": "现在您已经了解了软件的基本用法,导入您的订阅开始使用吧,祝您使用愉快!\n您还可以加入我们的官方 <a href=\"https://t.me/mihomo_party_group\" target=\"_blank\">Telegram 群组</a> 获取最新资讯" "description": "现在您已经了解了软件的基本用法,导入您的订阅开始使用吧,祝您使用愉快!\n您还可以加入我们的官方 <a href=\"https://t.me/mihomo_party_group\" target=\"_blank\">Telegram 群组</a> 获取最新资讯"
} }
},
"main": {
"error": {
"adminRequired": "首次启动请以管理员权限运行",
"initFailed": "应用初始化失败",
"coreStartFailed": "内核启动出错",
"importFailed": "订阅导入失败",
"urlParamMissing": "缺少参数 url"
},
"notification": {
"importSuccess": "订阅导入成功"
}
} }
} }

View File

@ -233,7 +233,7 @@ const Connections: React.FC = () => {
<Select <Select
classNames={{ trigger: 'data-[hover=true]:bg-default-200' }} classNames={{ trigger: 'data-[hover=true]:bg-default-200' }}
size="sm" size="sm"
className="w-[180px] min-w-[120px]" className="w-[180px] min-w-[131px]"
aria-label={t('connections.orderBy')} aria-label={t('connections.orderBy')}
selectedKeys={new Set([connectionOrderBy])} selectedKeys={new Set([connectionOrderBy])}
onSelectionChange={async (v) => { onSelectionChange={async (v) => {

View File

@ -252,7 +252,7 @@ const Proxies: React.FC = () => {
return ( return (
<BasePage <BasePage
title={t('proxies.card.title')} title={t('proxies.title')}
header={ header={
<> <>
<Button <Button