mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-05-28 19:59:52 +08:00
添加国际化支持:在多个组件中引入 vue-i18n,更新文本以支持多语言显示
This commit is contained in:
@@ -2,9 +2,11 @@
|
||||
import { getNavMenus } from '@/router/i18n-menu'
|
||||
import { useDisplay } from 'vuetify'
|
||||
import { NavMenu } from '@/@layouts/types'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const display = useDisplay()
|
||||
const appMode = inject('pwaMode') && display.mdAndDown.value
|
||||
const { t } = useI18n()
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
@@ -130,7 +132,7 @@ const showDynamicButton = computed(() => {
|
||||
>
|
||||
<div class="btn-content">
|
||||
<VIcon icon="mdi-dots-horizontal" size="24"></VIcon>
|
||||
<span class="btn-text">更多</span>
|
||||
<span class="btn-text">{{ t('nav.more') }}</span>
|
||||
</div>
|
||||
</VBtn>
|
||||
</VBtnToggle>
|
||||
|
||||
@@ -1,30 +1,33 @@
|
||||
<script setup lang="ts">
|
||||
import type { ThemeSwitcherTheme } from '@layouts/types'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const themes: ThemeSwitcherTheme[] = [
|
||||
{
|
||||
name: 'auto',
|
||||
title: '跟随系统',
|
||||
title: t('theme.auto'),
|
||||
icon: 'mdi-laptop',
|
||||
},
|
||||
{
|
||||
name: 'light',
|
||||
title: '明亮',
|
||||
title: t('theme.light'),
|
||||
icon: 'mdi-weather-sunny',
|
||||
},
|
||||
{
|
||||
name: 'dark',
|
||||
title: '暗黑',
|
||||
title: t('theme.dark'),
|
||||
icon: 'mdi-weather-night',
|
||||
},
|
||||
{
|
||||
name: 'purple',
|
||||
title: '幻紫',
|
||||
title: t('theme.purple'),
|
||||
icon: 'mdi-brightness-4',
|
||||
},
|
||||
{
|
||||
name: 'transparent',
|
||||
title: '透明',
|
||||
title: t('theme.transparent'),
|
||||
icon: 'mdi-gradient-horizontal',
|
||||
},
|
||||
]
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
import * as Mousetrap from 'mousetrap'
|
||||
import SearchBarDialog from '@/components/dialog/SearchBarDialog.vue'
|
||||
import { useDisplay } from 'vuetify'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const display = useDisplay()
|
||||
const { t } = useI18n()
|
||||
|
||||
const searchDialog = ref(false)
|
||||
|
||||
@@ -31,7 +33,7 @@ const metaKey = computed(() => (isMac() ? '⌘+K' : 'Ctrl+K'))
|
||||
<VIcon icon="ri-search-line" />
|
||||
</IconBtn>
|
||||
<span v-if="display.lgAndUp.value" class="flex align-center text-disabled ms-2" @click="openSearchDialog">
|
||||
<span class="me-3">搜索</span>
|
||||
<span class="me-3">{{ t('common.search') }}</span>
|
||||
<span class="meta-key">{{ metaKey }}</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -8,6 +8,10 @@ import MessageView from '@/views/system/MessageView.vue'
|
||||
import api from '@/api'
|
||||
import { useDisplay } from 'vuetify'
|
||||
import { getQueryValue } from '@/@core/utils'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
// 国际化
|
||||
const { t } = useI18n()
|
||||
|
||||
// 显示器宽度
|
||||
const display = useDisplay()
|
||||
@@ -48,43 +52,43 @@ const chatContainer = ref<HTMLElement>()
|
||||
// 定义捷径列表
|
||||
const shortcuts = [
|
||||
{
|
||||
title: '识别',
|
||||
subtitle: '名称识别测试',
|
||||
title: t('shortcut.recognition.title'),
|
||||
subtitle: t('shortcut.recognition.subtitle'),
|
||||
icon: 'mdi-text-recognition',
|
||||
dialog: 'nameTest',
|
||||
dialogRef: nameTestDialog,
|
||||
},
|
||||
{
|
||||
title: '规则',
|
||||
subtitle: '规则测试',
|
||||
title: t('shortcut.rule.title'),
|
||||
subtitle: t('shortcut.rule.subtitle'),
|
||||
icon: 'mdi-filter-cog',
|
||||
dialog: 'ruleTest',
|
||||
dialogRef: ruleTestDialog,
|
||||
},
|
||||
{
|
||||
title: '日志',
|
||||
subtitle: '实时日志',
|
||||
title: t('shortcut.log.title'),
|
||||
subtitle: t('shortcut.log.subtitle'),
|
||||
icon: 'mdi-file-document',
|
||||
dialog: 'logging',
|
||||
dialogRef: loggingDialog,
|
||||
},
|
||||
{
|
||||
title: '网络',
|
||||
subtitle: '网速连通性测试',
|
||||
title: t('shortcut.network.title'),
|
||||
subtitle: t('shortcut.network.subtitle'),
|
||||
icon: 'mdi-network',
|
||||
dialog: 'netTest',
|
||||
dialogRef: netTestDialog,
|
||||
},
|
||||
{
|
||||
title: '系统',
|
||||
subtitle: '健康检查',
|
||||
title: t('shortcut.system.title'),
|
||||
subtitle: t('shortcut.system.subtitle'),
|
||||
icon: 'mdi-cog',
|
||||
dialog: 'systemTest',
|
||||
dialogRef: systemTestDialog,
|
||||
},
|
||||
{
|
||||
title: '消息',
|
||||
subtitle: '消息中心',
|
||||
title: t('shortcut.message.title'),
|
||||
subtitle: t('shortcut.message.subtitle'),
|
||||
icon: 'mdi-message',
|
||||
dialog: 'message',
|
||||
dialogRef: messageDialog,
|
||||
@@ -158,7 +162,7 @@ onMounted(() => {
|
||||
<!-- Menu Content -->
|
||||
<VCard class="overflow-hidden">
|
||||
<VCardItem class="py-3">
|
||||
<VCardTitle>捷径</VCardTitle>
|
||||
<VCardTitle>{{ t('shortcut.title') }}</VCardTitle>
|
||||
<template #append>
|
||||
<IconBtn @click="appsMenu = false">
|
||||
<VIcon icon="mdi-close" />
|
||||
@@ -196,7 +200,7 @@ onMounted(() => {
|
||||
<VCardItem>
|
||||
<VCardTitle>
|
||||
<VIcon icon="mdi-text-recognition" class="me-2" />
|
||||
名称识别测试
|
||||
{{ t('shortcut.recognition.title') }}
|
||||
</VCardTitle>
|
||||
<VDialogCloseBtn @click="nameTestDialog = false" />
|
||||
</VCardItem>
|
||||
@@ -212,7 +216,7 @@ onMounted(() => {
|
||||
<VCardItem>
|
||||
<VCardTitle>
|
||||
<VIcon icon="mdi-network" class="me-2" />
|
||||
网速连通性测试
|
||||
{{ t('shortcut.network.subtitle') }}
|
||||
</VCardTitle>
|
||||
<VDialogCloseBtn @click="netTestDialog = false" />
|
||||
</VCardItem>
|
||||
@@ -235,11 +239,11 @@ onMounted(() => {
|
||||
<VCardItem>
|
||||
<VCardTitle class="d-inline-flex">
|
||||
<VIcon icon="mdi-file-document" class="me-2" />
|
||||
实时日志
|
||||
{{ t('shortcut.log.subtitle') }}
|
||||
<a class="mx-2 d-inline-flex align-center" :href="allLoggingUrl()" target="_blank">
|
||||
<VChip color="grey-darken-1" size="small" class="ml-2">
|
||||
<VIcon icon="mdi-open-in-new" size="small" start />
|
||||
在新窗口中打开
|
||||
{{ t('common.openInNewWindow') }}
|
||||
</VChip>
|
||||
</a>
|
||||
</VCardTitle>
|
||||
@@ -250,13 +254,13 @@ onMounted(() => {
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</VDialog>
|
||||
<!-- 规则测试弹窗 -->
|
||||
<VDialog v-if="ruleTestDialog" v-model="ruleTestDialog" max-width="40rem" scrollable>
|
||||
<!-- 过滤规则弹窗 -->
|
||||
<VDialog v-if="ruleTestDialog" v-model="ruleTestDialog" max-width="35rem" scrollable>
|
||||
<VCard>
|
||||
<VCardItem>
|
||||
<VCardTitle>
|
||||
<VIcon icon="mdi-filter-cog" class="me-2" />
|
||||
规则测试
|
||||
{{ t('shortcut.rule.subtitle') }}
|
||||
</VCardTitle>
|
||||
<VDialogCloseBtn @click="ruleTestDialog = false" />
|
||||
</VCardItem>
|
||||
@@ -267,12 +271,12 @@ onMounted(() => {
|
||||
</VCard>
|
||||
</VDialog>
|
||||
<!-- 系统健康检查弹窗 -->
|
||||
<VDialog v-if="systemTestDialog" v-model="systemTestDialog" max-width="35rem" max-height="85vh" scrollable>
|
||||
<VDialog v-if="systemTestDialog" v-model="systemTestDialog" max-width="35rem" scrollable>
|
||||
<VCard>
|
||||
<VCardItem>
|
||||
<VCardTitle>
|
||||
<VIcon icon="mdi-cog" class="me-2" />
|
||||
系统健康检查
|
||||
{{ t('shortcut.system.subtitle') }}
|
||||
</VCardTitle>
|
||||
<VDialogCloseBtn @click="systemTestDialog = false" />
|
||||
</VCardItem>
|
||||
@@ -283,39 +287,42 @@ onMounted(() => {
|
||||
</VCard>
|
||||
</VDialog>
|
||||
<!-- 消息中心弹窗 -->
|
||||
<VDialog
|
||||
v-if="messageDialog"
|
||||
v-model="messageDialog"
|
||||
max-width="45rem"
|
||||
scrollable
|
||||
:fullscreen="!display.mdAndUp.value"
|
||||
>
|
||||
<VDialog v-if="messageDialog" v-model="messageDialog" max-width="35rem" scrollable>
|
||||
<VCard>
|
||||
<VCardItem>
|
||||
<VCardTitle>
|
||||
<VIcon icon="mdi-message" class="me-2" />
|
||||
消息中心
|
||||
{{ t('shortcut.message.subtitle') }}
|
||||
</VCardTitle>
|
||||
<VDialogCloseBtn @click="messageDialog = false" />
|
||||
</VCardItem>
|
||||
<VDivider />
|
||||
<VCardText ref="chatContainer">
|
||||
<MessageView @scroll="scrollMessageToEnd" />
|
||||
<VCardText>
|
||||
<MessageView ref="chatContainer" />
|
||||
</VCardText>
|
||||
<VCardItem>
|
||||
<VTextField
|
||||
v-model="user_message"
|
||||
variant="solo"
|
||||
placeholder="输入消息或命令"
|
||||
clearable
|
||||
:disabled="sendButtonDisabled"
|
||||
@keydown.enter="sendMessage"
|
||||
>
|
||||
<template #append-inner>
|
||||
<VBtn color="primary" :disabled="sendButtonDisabled" @click="sendMessage"> 发送 </VBtn>
|
||||
</template>
|
||||
</VTextField>
|
||||
</VCardItem>
|
||||
<VDivider />
|
||||
<VCardActions class="pa-4">
|
||||
<div class="d-flex w-100 gap-2">
|
||||
<VTextField
|
||||
v-model="user_message"
|
||||
variant="outlined"
|
||||
hide-details
|
||||
density="compact"
|
||||
:placeholder="t('common.inputMessage')"
|
||||
@keyup.enter="sendMessage"
|
||||
/>
|
||||
<VBtn
|
||||
:disabled="sendButtonDisabled"
|
||||
@click="sendMessage"
|
||||
:loading="sendButtonDisabled"
|
||||
color="primary"
|
||||
min-width="auto"
|
||||
width="46"
|
||||
height="38"
|
||||
>{{ t('common.send') }}</VBtn
|
||||
>
|
||||
</div>
|
||||
</VCardActions>
|
||||
</VCard>
|
||||
</VDialog>
|
||||
</template>
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { formatDateDifference } from '@core/utils/formatters'
|
||||
import { SystemNotification } from '@/api/types'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
// 是否有新消息
|
||||
const hasNewMessage = ref(false)
|
||||
@@ -63,9 +66,9 @@ onBeforeUnmount(() => {
|
||||
<!-- Menu Content -->
|
||||
<VCard>
|
||||
<VCardItem class="py-3">
|
||||
<VCardTitle>通知中心</VCardTitle>
|
||||
<VCardTitle>{{ t('notification.center') }}</VCardTitle>
|
||||
<template #append>
|
||||
<VTooltip text="设为已读">
|
||||
<VTooltip :text="t('notification.markRead')">
|
||||
<template #activator="{ props }">
|
||||
<IconBtn
|
||||
v-bind="props"
|
||||
@@ -107,7 +110,7 @@ onBeforeUnmount(() => {
|
||||
</div>
|
||||
<div v-else class="py-8 text-center">
|
||||
<VIcon icon="mdi-bell-sleep-outline" size="40" class="mb-3" />
|
||||
<div>暂无通知</div>
|
||||
<div>{{ t('notification.empty') }}</div>
|
||||
</div>
|
||||
</VCard>
|
||||
</VMenu>
|
||||
|
||||
@@ -99,7 +99,7 @@ const userLevel = computed(() => userStore.level)
|
||||
</template>
|
||||
<div>
|
||||
<span class="text-primary text-sm font-medium d-block">
|
||||
{{ superUser ? '管理员' : '普通用户' }}
|
||||
{{ superUser ? t('user.admin') : t('user.normalUser') }}
|
||||
</span>
|
||||
<span class="text-high-emphasis text-lg font-weight-bold">
|
||||
{{ userName }}
|
||||
@@ -113,14 +113,14 @@ const userLevel = computed(() => userStore.level)
|
||||
<template #prepend>
|
||||
<VIcon icon="mdi-account-outline" />
|
||||
</template>
|
||||
<VListItemTitle>个人信息</VListItemTitle>
|
||||
<VListItemTitle>{{ t('user.profile') }}</VListItemTitle>
|
||||
</VListItem>
|
||||
|
||||
<VListItem link @click="router.push('/setting')" class="mb-1 rounded-lg" hover>
|
||||
<template #prepend>
|
||||
<VIcon icon="mdi-cog-outline" />
|
||||
</template>
|
||||
<VListItemTitle>系统设定</VListItemTitle>
|
||||
<VListItemTitle>{{ t('user.systemSettings') }}</VListItemTitle>
|
||||
</VListItem>
|
||||
|
||||
<!-- 👉 Site Auth -->
|
||||
@@ -128,7 +128,7 @@ const userLevel = computed(() => userStore.level)
|
||||
<template #prepend>
|
||||
<VIcon icon="mdi-lock-check-outline" />
|
||||
</template>
|
||||
<VListItemTitle>用户认证</VListItemTitle>
|
||||
<VListItemTitle>{{ t('user.siteAuth') }}</VListItemTitle>
|
||||
</VListItem>
|
||||
|
||||
<!-- 👉 FAQ -->
|
||||
@@ -136,7 +136,7 @@ const userLevel = computed(() => userStore.level)
|
||||
<template #prepend>
|
||||
<VIcon icon="mdi-help-circle-outline" />
|
||||
</template>
|
||||
<VListItemTitle>帮助文档</VListItemTitle>
|
||||
<VListItemTitle>{{ t('user.helpDocs') }}</VListItemTitle>
|
||||
</VListItem>
|
||||
|
||||
<!-- Divider -->
|
||||
@@ -147,7 +147,7 @@ const userLevel = computed(() => userStore.level)
|
||||
<template #prepend>
|
||||
<VIcon icon="mdi-restart" />
|
||||
</template>
|
||||
<VListItemTitle>重启</VListItemTitle>
|
||||
<VListItemTitle>{{ t('user.restart') }}</VListItemTitle>
|
||||
</VListItem>
|
||||
</div>
|
||||
<!-- 👉 Logout -->
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import api from '@/api'
|
||||
import useDragAndDrop from '@core/utils/workflow'
|
||||
import { useDisplay } from 'vuetify'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
interface ActionItem {
|
||||
name: string
|
||||
@@ -12,6 +13,7 @@ interface ActionItem {
|
||||
const display = useDisplay()
|
||||
// APP
|
||||
const appMode = inject('pwaMode') && display.mdAndDown.value
|
||||
const { t } = useI18n()
|
||||
|
||||
const { onDragStart } = useDragAndDrop()
|
||||
|
||||
@@ -119,7 +121,9 @@ onMounted(() => {
|
||||
<VAvatar size="36" class="workflow-logo">
|
||||
<VIcon icon="mdi-puzzle" />
|
||||
</VAvatar>
|
||||
<span v-if="!isSidebarCollapsed || display.smAndDown.value" class="header-title">动作组件</span>
|
||||
<span v-if="!isSidebarCollapsed || display.smAndDown.value" class="header-title">{{
|
||||
t('workflow.components')
|
||||
}}</span>
|
||||
<IconBtn v-if="!display.smAndDown.value" @click="toggleSidebar" class="collapse-btn">
|
||||
<VIcon :icon="isSidebarCollapsed ? 'mdi-chevron-right' : 'mdi-chevron-left'" />
|
||||
</IconBtn>
|
||||
@@ -142,7 +146,9 @@ onMounted(() => {
|
||||
</VAvatar>
|
||||
<div v-if="!isSidebarCollapsed || display.smAndDown.value" class="component-info">
|
||||
<div class="component-name">{{ action.name }}</div>
|
||||
<div class="component-desc">{{ display.smAndDown.value ? '点击添加' : '拖动到画布' }}</div>
|
||||
<div class="component-desc">
|
||||
{{ display.smAndDown.value ? t('workflow.clickToAdd') : t('workflow.dragToCanvas') }}
|
||||
</div>
|
||||
</div>
|
||||
</VCard>
|
||||
</div>
|
||||
@@ -155,7 +161,9 @@ onMounted(() => {
|
||||
<VIcon v-if="isSidebarCollapsed && !display.smAndDown.value" class="footer-icon" icon="mdi-gesture-swipe" />
|
||||
<template v-else>
|
||||
<VIcon :icon="display.smAndDown.value ? 'mdi-gesture-tap' : 'mdi-gesture-swipe'" class="me-2" />
|
||||
<span>{{ display.smAndDown.value ? '点击组件添加到画布' : '拖动组件到画布' }}</span>
|
||||
<span>{{
|
||||
display.smAndDown.value ? t('workflow.tapComponentHint') : t('workflow.dragComponentHint')
|
||||
}}</span>
|
||||
</template>
|
||||
</div>
|
||||
</VBtn>
|
||||
|
||||
@@ -10,6 +10,9 @@ export default {
|
||||
loading: 'Loading',
|
||||
success: 'Success',
|
||||
error: 'Error',
|
||||
openInNewWindow: 'Open in New Window',
|
||||
inputMessage: 'Enter message or command',
|
||||
send: 'Send',
|
||||
},
|
||||
theme: {
|
||||
light: 'Light',
|
||||
@@ -146,4 +149,55 @@ export default {
|
||||
douban: 'Douban',
|
||||
bangumi: 'Bangumi',
|
||||
},
|
||||
user: {
|
||||
admin: 'Administrator',
|
||||
normalUser: 'Normal User',
|
||||
profile: 'Profile',
|
||||
systemSettings: 'System Settings',
|
||||
siteAuth: 'User Authentication',
|
||||
helpDocs: 'Help Docs',
|
||||
restart: 'Restart',
|
||||
},
|
||||
nav: {
|
||||
more: 'More',
|
||||
},
|
||||
notification: {
|
||||
center: 'Notification Center',
|
||||
markRead: 'Mark as Read',
|
||||
empty: 'No Notifications',
|
||||
},
|
||||
shortcut: {
|
||||
title: 'Shortcuts',
|
||||
recognition: {
|
||||
title: 'Recognition',
|
||||
subtitle: 'Name Recognition Test',
|
||||
},
|
||||
rule: {
|
||||
title: 'Rules',
|
||||
subtitle: 'Rule Test',
|
||||
},
|
||||
log: {
|
||||
title: 'Logs',
|
||||
subtitle: 'Real-time Logs',
|
||||
},
|
||||
network: {
|
||||
title: 'Network',
|
||||
subtitle: 'Speed & Connectivity Test',
|
||||
},
|
||||
system: {
|
||||
title: 'System',
|
||||
subtitle: 'Health Check',
|
||||
},
|
||||
message: {
|
||||
title: 'Messages',
|
||||
subtitle: 'Message Center',
|
||||
},
|
||||
},
|
||||
workflow: {
|
||||
components: 'Action Components',
|
||||
clickToAdd: 'Click to Add',
|
||||
dragToCanvas: 'Drag to Canvas',
|
||||
tapComponentHint: 'Tap component to add to canvas',
|
||||
dragComponentHint: 'Drag components to canvas',
|
||||
},
|
||||
}
|
||||
|
||||
@@ -10,6 +10,9 @@ export default {
|
||||
loading: '加载中',
|
||||
success: '成功',
|
||||
error: '错误',
|
||||
openInNewWindow: '在新窗口中打开',
|
||||
inputMessage: '输入消息或命令',
|
||||
send: '发送',
|
||||
},
|
||||
theme: {
|
||||
light: '浅色',
|
||||
@@ -146,4 +149,55 @@ export default {
|
||||
douban: '豆瓣',
|
||||
bangumi: 'Bangumi',
|
||||
},
|
||||
user: {
|
||||
admin: '管理员',
|
||||
normalUser: '普通用户',
|
||||
profile: '个人信息',
|
||||
systemSettings: '系统设定',
|
||||
siteAuth: '用户认证',
|
||||
helpDocs: '帮助文档',
|
||||
restart: '重启',
|
||||
},
|
||||
nav: {
|
||||
more: '更多',
|
||||
},
|
||||
notification: {
|
||||
center: '通知中心',
|
||||
markRead: '设为已读',
|
||||
empty: '暂无通知',
|
||||
},
|
||||
shortcut: {
|
||||
title: '捷径',
|
||||
recognition: {
|
||||
title: '识别',
|
||||
subtitle: '名称识别测试',
|
||||
},
|
||||
rule: {
|
||||
title: '规则',
|
||||
subtitle: '规则测试',
|
||||
},
|
||||
log: {
|
||||
title: '日志',
|
||||
subtitle: '实时日志',
|
||||
},
|
||||
network: {
|
||||
title: '网络',
|
||||
subtitle: '网速连通性测试',
|
||||
},
|
||||
system: {
|
||||
title: '系统',
|
||||
subtitle: '健康检查',
|
||||
},
|
||||
message: {
|
||||
title: '消息',
|
||||
subtitle: '消息中心',
|
||||
},
|
||||
},
|
||||
workflow: {
|
||||
components: '动作组件',
|
||||
clickToAdd: '点击添加',
|
||||
dragToCanvas: '拖动到画布',
|
||||
tapComponentHint: '点击组件添加到画布',
|
||||
dragComponentHint: '拖动组件到画布',
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user