添加国际化支持:在多个组件中引入 vue-i18n,更新文本以实现多语言显示

This commit is contained in:
jxxghp
2025-04-27 18:06:15 +08:00
parent c46d556684
commit 733d74ac36
6 changed files with 102 additions and 27 deletions
+7 -2
View File
@@ -1,4 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import { useI18n } from 'vue-i18n'
// 国际化
const { t } = useI18n()
const props = defineProps<Props>() const props = defineProps<Props>()
interface Props { interface Props {
@@ -28,12 +33,12 @@ interface Props {
<!-- 标题 --> <!-- 标题 -->
<div class="error-title"> <div class="error-title">
{{ props.errorTitle || '暂无数据' }} {{ props.errorTitle || t('common.noData') }}
</div> </div>
<!-- 描述 --> <!-- 描述 -->
<div class="error-description"> <div class="error-description">
{{ props.errorDescription || '没有找到相关内容' }} {{ props.errorDescription || t('common.noContent') }}
</div> </div>
<!-- 按钮插槽 --> <!-- 按钮插槽 -->
+4
View File
@@ -1,5 +1,9 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { MediaServerPlayItem } from '@/api/types' import type { MediaServerPlayItem } from '@/api/types'
import { useI18n } from 'vue-i18n'
// 国际化
const { t } = useI18n()
// 输入参数 // 输入参数
const props = defineProps({ const props = defineProps({
+15 -11
View File
@@ -13,6 +13,10 @@ import { useUserStore } from '@/stores'
import SubscribeEditDialog from '../dialog/SubscribeEditDialog.vue' import SubscribeEditDialog from '../dialog/SubscribeEditDialog.vue'
import SearchSiteDialog from '@/components/dialog/SearchSiteDialog.vue' import SearchSiteDialog from '@/components/dialog/SearchSiteDialog.vue'
import SubscribeSeasonDialog from '../dialog/SubscribeSeasonDialog.vue' import SubscribeSeasonDialog from '../dialog/SubscribeSeasonDialog.vue'
import { useI18n } from 'vue-i18n'
// 国际化
const { t } = useI18n()
// 输入参数 // 输入参数
const props = defineProps({ const props = defineProps({
@@ -114,14 +118,14 @@ function getMediaId() {
// 角标颜色 // 角标颜色
function getChipColor(type: string) { function getChipColor(type: string) {
if (type === '电影') return 'border-blue-500 bg-blue-600' if (type === t('media.movie')) return 'border-blue-500 bg-blue-600'
else if (type === '电视剧') return ' bg-indigo-500 border-indigo-600' else if (type === t('media.tv')) return ' bg-indigo-500 border-indigo-600'
else return 'border-purple-600 bg-purple-600' else return 'border-purple-600 bg-purple-600'
} }
// 添加订阅处理 // 添加订阅处理
async function handleAddSubscribe() { async function handleAddSubscribe() {
if (props.media?.type === '电视剧') { if (props.media?.type === t('media.tv')) {
// 弹出季选择列表,支持多选 // 弹出季选择列表,支持多选
seasonsSelected.value = [] seasonsSelected.value = []
subscribeSeasonDialog.value = true subscribeSeasonDialog.value = true
@@ -137,7 +141,7 @@ async function addSubscribe(season: number = 0, best_version: number = 0) {
startNProgress() startNProgress()
try { try {
// 是否洗版 // 是否洗版
if (!best_version && props.media?.type == '电影') best_version = isExists.value ? 1 : 0 if (!best_version && props.media?.type == t('media.movie')) best_version = isExists.value ? 1 : 0
// 请求API // 请求API
const result: { [key: string]: any } = await api.post('subscribe/', { const result: { [key: string]: any } = await api.post('subscribe/', {
name: props.media?.title, name: props.media?.title,
@@ -180,11 +184,11 @@ async function addSubscribe(season: number = 0, best_version: number = 0) {
function showSubscribeAddToast(result: boolean, title: string, season: number, message: string, best_version: number) { function showSubscribeAddToast(result: boolean, title: string, season: number, message: string, best_version: number) {
if (season) title = `${title} ${formatSeason(season.toString())}` if (season) title = `${title} ${formatSeason(season.toString())}`
let subname = '订阅' let subname = t('subscribe.normalSub')
if (best_version > 0) subname = '洗版订阅' if (best_version > 0) subname = t('subscribe.versionSub')
if (result) $toast.success(`${title} 添加${subname}成功!`) if (result) $toast.success(`${title} ${t('subscribe.addSuccess', { name: subname })}`)
else if (!result) $toast.error(`${title} 添加${subname}失败:${message}`) else if (!result) $toast.error(`${title} ${t('subscribe.addFailed', { name: subname, message: message })}`)
} }
// 调用API取消订阅 // 调用API取消订阅
@@ -202,9 +206,9 @@ async function removeSubscribe() {
if (result.success) { if (result.success) {
isSubscribed.value = false isSubscribed.value = false
$toast.success(`${props.media?.title} 已取消订阅!`) $toast.success(`${props.media?.title} ${t('subscribe.cancelSuccess')}`)
} else { } else {
$toast.error(`${props.media?.title} 取消订阅失败:${result.message}`) $toast.error(`${props.media?.title} ${t('subscribe.cancelFailed', { message: result.message })}`)
} }
} catch (error) { } catch (error) {
console.error(error) console.error(error)
@@ -275,7 +279,7 @@ async function queryDefaultSubscribeConfig() {
if (!userStore.superUser) return false if (!userStore.superUser) return false
try { try {
let subscribe_config_url = '' let subscribe_config_url = ''
if (props.media?.type === '电影') subscribe_config_url = 'system/setting/DefaultMovieSubscribeConfig' if (props.media?.type === t('media.movie')) subscribe_config_url = 'system/setting/DefaultMovieSubscribeConfig'
else subscribe_config_url = 'system/setting/DefaultTvSubscribeConfig' else subscribe_config_url = 'system/setting/DefaultTvSubscribeConfig'
const result: { [key: string]: any } = await api.get(subscribe_config_url) const result: { [key: string]: any } = await api.get(subscribe_config_url)
if (result.data?.value) return result.data.value.show_edit_dialog if (result.data?.value) return result.data.value.show_edit_dialog
+29
View File
@@ -13,6 +13,8 @@ export default {
openInNewWindow: 'Open in New Window', openInNewWindow: 'Open in New Window',
inputMessage: 'Enter message or command', inputMessage: 'Enter message or command',
send: 'Send', send: 'Send',
noData: 'No Data',
noContent: 'No content found',
}, },
theme: { theme: {
light: 'Light', light: 'Light',
@@ -200,4 +202,31 @@ export default {
tapComponentHint: 'Tap component to add to canvas', tapComponentHint: 'Tap component to add to canvas',
dragComponentHint: 'Drag components to canvas', dragComponentHint: 'Drag components to canvas',
}, },
dashboard: {
storage: 'Storage Space',
mediaStatistic: 'Media Statistics',
weeklyOverview: 'Recent Additions',
speed: 'Real-time Speed',
scheduler: 'Background Tasks',
cpu: 'CPU',
memory: 'Memory',
library: 'My Media Library',
playing: 'Continue Watching',
latest: 'Recently Added',
settings: 'Dashboard Settings',
chooseContent: 'Choose content you want to display on the page',
adaptiveHeight: 'Adaptive Component Height',
},
media: {
movie: 'Movie',
tv: 'TV Show',
},
subscribe: {
normalSub: 'Subscription',
versionSub: 'Version Upgrade',
addSuccess: '{name} added successfully!',
addFailed: 'Failed to add {name}: {message}!',
cancelSuccess: 'Subscription cancelled!',
cancelFailed: 'Failed to cancel subscription: {message}!',
},
} }
+29
View File
@@ -13,6 +13,8 @@ export default {
openInNewWindow: '在新窗口中打开', openInNewWindow: '在新窗口中打开',
inputMessage: '输入消息或命令', inputMessage: '输入消息或命令',
send: '发送', send: '发送',
noData: '暂无数据',
noContent: '没有找到相关内容',
}, },
theme: { theme: {
light: '浅色', light: '浅色',
@@ -200,4 +202,31 @@ export default {
tapComponentHint: '点击组件添加到画布', tapComponentHint: '点击组件添加到画布',
dragComponentHint: '拖动组件到画布', dragComponentHint: '拖动组件到画布',
}, },
dashboard: {
storage: '存储空间',
mediaStatistic: '媒体统计',
weeklyOverview: '最近入库',
speed: '实时速率',
scheduler: '后台任务',
cpu: 'CPU',
memory: '内存',
library: '我的媒体库',
playing: '继续观看',
latest: '最近添加',
settings: '设置仪表板',
chooseContent: '选择您想在页面显示的内容',
adaptiveHeight: '自适应组件高度',
},
media: {
movie: '电影',
tv: '电视剧',
},
subscribe: {
normalSub: '订阅',
versionSub: '洗版订阅',
addSuccess: '添加{name}成功!',
addFailed: '添加{name}失败:{message}',
cancelSuccess: '已取消订阅!',
cancelFailed: '取消订阅失败:{message}',
},
} }
+18 -14
View File
@@ -7,6 +7,10 @@ import { useUserStore } from '@/stores'
import DashboardElement from '@/components/misc/DashboardElement.vue' import DashboardElement from '@/components/misc/DashboardElement.vue'
import { useDisplay } from 'vuetify' import { useDisplay } from 'vuetify'
import { useDynamicButton } from '@/composables/useDynamicButton' import { useDynamicButton } from '@/composables/useDynamicButton'
import { useI18n } from 'vue-i18n'
// 国际化
const { t } = useI18n()
// APP // APP
const display = useDisplay() const display = useDisplay()
@@ -53,7 +57,7 @@ const orderConfig = ref<{ id: string; key: string }[]>([])
const dashboardConfigs = ref<DashboardItem[]>([ const dashboardConfigs = ref<DashboardItem[]>([
{ {
id: 'storage', id: 'storage',
name: '存储空间', name: t('dashboard.storage'),
key: '', key: '',
attrs: {}, attrs: {},
cols: { cols: 12, md: 4 }, cols: { cols: 12, md: 4 },
@@ -61,7 +65,7 @@ const dashboardConfigs = ref<DashboardItem[]>([
}, },
{ {
id: 'mediaStatistic', id: 'mediaStatistic',
name: '媒体统计', name: t('dashboard.mediaStatistic'),
key: '', key: '',
attrs: {}, attrs: {},
cols: { cols: 12, md: 8 }, cols: { cols: 12, md: 8 },
@@ -69,7 +73,7 @@ const dashboardConfigs = ref<DashboardItem[]>([
}, },
{ {
id: 'weeklyOverview', id: 'weeklyOverview',
name: '最近入库', name: t('dashboard.weeklyOverview'),
key: '', key: '',
attrs: {}, attrs: {},
cols: { cols: 12, md: 4 }, cols: { cols: 12, md: 4 },
@@ -77,7 +81,7 @@ const dashboardConfigs = ref<DashboardItem[]>([
}, },
{ {
id: 'speed', id: 'speed',
name: '实时速率', name: t('dashboard.speed'),
key: '', key: '',
attrs: {}, attrs: {},
cols: { cols: 12, md: 4 }, cols: { cols: 12, md: 4 },
@@ -85,7 +89,7 @@ const dashboardConfigs = ref<DashboardItem[]>([
}, },
{ {
id: 'scheduler', id: 'scheduler',
name: '后台任务', name: t('dashboard.scheduler'),
key: '', key: '',
attrs: {}, attrs: {},
cols: { cols: 12, md: 4 }, cols: { cols: 12, md: 4 },
@@ -93,7 +97,7 @@ const dashboardConfigs = ref<DashboardItem[]>([
}, },
{ {
id: 'cpu', id: 'cpu',
name: 'CPU', name: t('dashboard.cpu'),
key: '', key: '',
attrs: {}, attrs: {},
cols: { cols: 12, md: 6 }, cols: { cols: 12, md: 6 },
@@ -101,7 +105,7 @@ const dashboardConfigs = ref<DashboardItem[]>([
}, },
{ {
id: 'memory', id: 'memory',
name: '内存', name: t('dashboard.memory'),
key: '', key: '',
attrs: {}, attrs: {},
cols: { cols: 12, md: 6 }, cols: { cols: 12, md: 6 },
@@ -109,7 +113,7 @@ const dashboardConfigs = ref<DashboardItem[]>([
}, },
{ {
id: 'library', id: 'library',
name: '我的媒体库', name: t('dashboard.library'),
key: '', key: '',
attrs: {}, attrs: {},
cols: { cols: 12 }, cols: { cols: 12 },
@@ -117,7 +121,7 @@ const dashboardConfigs = ref<DashboardItem[]>([
}, },
{ {
id: 'playing', id: 'playing',
name: '继续观看', name: t('dashboard.playing'),
key: '', key: '',
attrs: {}, attrs: {},
cols: { cols: 12 }, cols: { cols: 12 },
@@ -125,7 +129,7 @@ const dashboardConfigs = ref<DashboardItem[]>([
}, },
{ {
id: 'latest', id: 'latest',
name: '最近添加', name: t('dashboard.latest'),
key: '', key: '',
attrs: {}, attrs: {},
cols: { cols: 12 }, cols: { cols: 12 },
@@ -354,13 +358,13 @@ onDeactivated(() => {
<VCardItem> <VCardItem>
<VCardTitle> <VCardTitle>
<VIcon icon="mdi-tune" size="small" class="me-2" /> <VIcon icon="mdi-tune" size="small" class="me-2" />
设置仪表板 {{ t('dashboard.settings') }}
</VCardTitle> </VCardTitle>
<VDialogCloseBtn @click="dialog = false" /> <VDialogCloseBtn @click="dialog = false" />
</VCardItem> </VCardItem>
<VDivider /> <VDivider />
<VCardText> <VCardText>
<p class="settings-hint">选择您想在页面显示的内容</p> <p class="settings-hint">{{ t('dashboard.chooseContent') }}</p>
<div class="settings-grid"> <div class="settings-grid">
<div <div
v-for="item in dashboardConfigs" v-for="item in dashboardConfigs"
@@ -389,7 +393,7 @@ onDeactivated(() => {
</div> </div>
</div> </div>
<p class="mt-3"> <p class="mt-3">
<VSwitch v-model="isElevated" label="自适应组件高度" /> <VSwitch v-model="isElevated" :label="t('dashboard.adaptiveHeight')" />
</p> </p>
</VCardText> </VCardText>
<VDivider /> <VDivider />
@@ -399,7 +403,7 @@ onDeactivated(() => {
<template #prepend> <template #prepend>
<VIcon icon="mdi-content-save" /> <VIcon icon="mdi-content-save" />
</template> </template>
保存 {{ t('common.save') }}
</VBtn> </VBtn>
</VCardText> </VCardText>
</VCard> </VCard>