更新国际化支持:为存储、媒体类型、通知开关及操作步骤等组件添加多语言文本,提升用户体验

This commit is contained in:
jxxghp
2025-04-29 13:24:27 +08:00
parent b75c93231e
commit b772e2d9ef
21 changed files with 566 additions and 386 deletions

View File

@@ -1,85 +1,304 @@
import i18n from '@/plugins/i18n'
export const storageOptions = [
{
title: '本地',
title: i18n.global.t('storage.local'),
value: 'local',
icon: 'mdi-folder-multiple-outline',
remote: false,
},
{
title: '阿里云盘',
title: i18n.global.t('storage.alipan'),
value: 'alipan',
icon: 'mdi-cloud-outline',
remote: true,
},
{
title: '115网盘',
title: i18n.global.t('storage.u115'),
value: 'u115',
icon: 'mdi-cloud-outline',
remote: true,
},
{
title: 'RClone',
title: i18n.global.t('storage.rclone'),
value: 'rclone',
icon: 'mdi-server-network-outline',
remote: true,
},
{
title: 'AList',
title: i18n.global.t('storage.alist'),
value: 'alist',
icon: 'mdi-server-network-outline',
remote: true,
},
]
export const innerFilterRules = [
{ title: '特效字幕', value: ' SPECSUB ' },
{ title: '中文字幕', value: ' CNSUB ' },
{ title: '国语配音', value: ' CNVOI ' },
{ title: '官种', value: ' GZ ' },
{ title: '排除: 国语配音', value: ' !CNVOI ' },
{ title: '粤语配音', value: ' HKVOI ' },
{ title: '排除: 粤语配音', value: ' !HKVOI ' },
{ title: '促销: 免费', value: ' FREE ' },
{ title: '分辨率: 4K', value: ' 4K ' },
{ title: '分辨率: 1080P', value: ' 1080P ' },
{ title: '分辨率: 720P', value: ' 720P ' },
{ title: '排除: 720P', value: ' !720P ' },
{ title: '质量: 蓝光原盘', value: ' BLU ' },
{ title: '排除: 蓝光原盘', value: ' !BLU ' },
{ title: '质量: BLURAY', value: ' BLURAY ' },
{ title: '排除: BLURAY', value: ' !BLURAY ' },
{ title: '质量: UHD', value: ' UHD ' },
{ title: '排除: UHD', value: ' !UHD ' },
{ title: '质量: REMUX', value: ' REMUX ' },
{ title: '排除: REMUX', value: ' !REMUX ' },
{ title: '质量: WEB-DL', value: ' WEBDL ' },
{ title: '排除: WEB-DL', value: ' !WEBDL ' },
{ title: '质量: 60fps', value: ' 60FPS ' },
{ title: '排除: 60fps', value: ' !60FPS ' },
{ title: '编码: H265', value: ' H265 ' },
{ title: '排除: H265', value: ' !H265 ' },
{ title: '编码: H264', value: ' H264 ' },
{ title: '排除: H264', value: ' !H264 ' },
{ title: '效果: 杜比视界', value: ' DOLBY ' },
{ title: '排除: 杜比视界', value: ' !DOLBY ' },
{ title: '效果: 杜比全景声', value: ' ATMOS ' },
{ title: '排除: 杜比全景声', value: ' !ATMOS ' },
{ title: '效果: HDR', value: ' HDR ' },
{ title: '排除: HDR', value: ' !HDR ' },
{ title: '效果: SDR', value: ' SDR ' },
{ title: '排除: SDR', value: ' !SDR ' },
{ title: '效果: 3D', value: ' 3D ' },
{ title: '排除: 3D', value: ' !3D ' },
]
export const storageDict = storageOptions.reduce((dict, item) => {
dict[item.value] = item.title
return dict
}, {} as Record<string, string>)
export const transferTypeOptions = [
{ title: '复制', value: 'copy' },
{ title: '移动', value: 'move' },
{ title: '硬链接', value: 'link' },
{ title: '软链接', value: 'softlink' },
export const innerFilterRules = [
{ title: i18n.global.t('filterRules.specSub'), value: ' SPECSUB ' },
{ title: i18n.global.t('filterRules.cnSub'), value: ' CNSUB ' },
{ title: i18n.global.t('filterRules.cnVoi'), value: ' CNVOI ' },
{ title: i18n.global.t('filterRules.gz'), value: ' GZ ' },
{ title: i18n.global.t('filterRules.notCnVoi'), value: ' !CNVOI ' },
{ title: i18n.global.t('filterRules.hkVoi'), value: ' HKVOI ' },
{ title: i18n.global.t('filterRules.notHkVoi'), value: ' !HKVOI ' },
{ title: i18n.global.t('filterRules.free'), value: ' FREE ' },
{ title: i18n.global.t('filterRules.resolution4k'), value: ' 4K ' },
{ title: i18n.global.t('filterRules.resolution1080p'), value: ' 1080P ' },
{ title: i18n.global.t('filterRules.resolution720p'), value: ' 720P ' },
{ title: i18n.global.t('filterRules.not720p'), value: ' !720P ' },
{ title: i18n.global.t('filterRules.qualityBlu'), value: ' BLU ' },
{ title: i18n.global.t('filterRules.notBlu'), value: ' !BLU ' },
{ title: i18n.global.t('filterRules.qualityBluray'), value: ' BLURAY ' },
{ title: i18n.global.t('filterRules.notBluray'), value: ' !BLURAY ' },
{ title: i18n.global.t('filterRules.qualityUhd'), value: ' UHD ' },
{ title: i18n.global.t('filterRules.notUhd'), value: ' !UHD ' },
{ title: i18n.global.t('filterRules.qualityRemux'), value: ' REMUX ' },
{ title: i18n.global.t('filterRules.notRemux'), value: ' !REMUX ' },
{ title: i18n.global.t('filterRules.qualityWebdl'), value: ' WEBDL ' },
{ title: i18n.global.t('filterRules.notWebdl'), value: ' !WEBDL ' },
{ title: i18n.global.t('filterRules.quality60fps'), value: ' 60FPS ' },
{ title: i18n.global.t('filterRules.not60fps'), value: ' !60FPS ' },
{ title: i18n.global.t('filterRules.codecH265'), value: ' H265 ' },
{ title: i18n.global.t('filterRules.notH265'), value: ' !H265 ' },
{ title: i18n.global.t('filterRules.codecH264'), value: ' H264 ' },
{ title: i18n.global.t('filterRules.notH264'), value: ' !H264 ' },
{ title: i18n.global.t('filterRules.effectDolby'), value: ' DOLBY ' },
{ title: i18n.global.t('filterRules.notDolby'), value: ' !DOLBY ' },
{ title: i18n.global.t('filterRules.effectAtmos'), value: ' ATMOS ' },
{ title: i18n.global.t('filterRules.notAtmos'), value: ' !ATMOS ' },
{ title: i18n.global.t('filterRules.effectHdr'), value: ' HDR ' },
{ title: i18n.global.t('filterRules.notHdr'), value: ' !HDR ' },
{ title: i18n.global.t('filterRules.effectSdr'), value: ' SDR ' },
{ title: i18n.global.t('filterRules.notSdr'), value: ' !SDR ' },
{ title: i18n.global.t('filterRules.effect3d'), value: ' 3D ' },
{ title: i18n.global.t('filterRules.not3d'), value: ' !3D ' },
]
export const transferTypeOptions = [
{ title: i18n.global.t('transferType.copy'), value: 'copy' },
{ title: i18n.global.t('transferType.move'), value: 'move' },
{ title: i18n.global.t('transferType.link'), value: 'link' },
{ title: i18n.global.t('transferType.softlink'), value: 'softlink' },
]
export const qualityOptions = ref([
{
title: i18n.global.t('qualityOptions.all'),
value: '',
},
{
title: i18n.global.t('qualityOptions.blurayOriginal'),
value: 'Blu-?Ray.+VC-?1|Blu-?Ray.+AVC|UHD.+blu-?ray.+HEVC|MiniBD',
},
{
title: i18n.global.t('qualityOptions.remux'),
value: 'Remux',
},
{
title: i18n.global.t('qualityOptions.bluray'),
value: 'Blu-?Ray',
},
{
title: i18n.global.t('qualityOptions.uhd'),
value: 'UHD|UltraHD',
},
{
title: i18n.global.t('qualityOptions.webdl'),
value: 'WEB-?DL|WEB-?RIP',
},
{
title: i18n.global.t('qualityOptions.hdtv'),
value: 'HDTV',
},
{
title: i18n.global.t('qualityOptions.h265'),
value: '[Hx].?265|HEVC',
},
{
title: i18n.global.t('qualityOptions.h264'),
value: '[Hx].?264|AVC',
},
])
// 分辨率选择框数据
export const resolutionOptions = ref([
{
title: i18n.global.t('resolutionOptions.all'),
value: '',
},
{
title: i18n.global.t('resolutionOptions.4k'),
value: '4K|2160p|x2160',
},
{
title: i18n.global.t('resolutionOptions.1080p'),
value: '1080[pi]|x1080',
},
{
title: i18n.global.t('resolutionOptions.720p'),
value: '720[pi]|x720',
},
])
// 特效选择框数据
export const effectOptions = ref([
{
title: i18n.global.t('effectOptions.all'),
value: '',
},
{
title: i18n.global.t('effectOptions.dolbyVision'),
value: 'Dolby[\\s.]+Vision|DOVI|[\\s.]+DV[\\s.]+',
},
{
title: i18n.global.t('effectOptions.dolbyAtmos'),
value: 'Dolby[\\s.]*\\+?Atmos|Atmos',
},
{
title: i18n.global.t('effectOptions.hdr'),
value: '[\\s.]+HDR[\\s.]+|HDR10|HDR10\\+',
},
{
title: i18n.global.t('effectOptions.sdr'),
value: '[\\s.]+SDR[\\s.]+',
},
])
// 媒体类型选项
export const mediaTypeOptions = [
{
title: i18n.global.t('mediaType.movie'),
value: '电影',
},
{
title: i18n.global.t('mediaType.tv'),
value: '电视剧',
},
{
title: i18n.global.t('mediaType.anime'),
value: '动漫',
},
{
title: i18n.global.t('mediaType.collection'),
value: '合集',
},
{
title: i18n.global.t('mediaType.unknown'),
value: '未知',
},
]
// 媒体类型字典
export const mediaTypeDict = mediaTypeOptions.reduce((dict, item) => {
dict[item.value] = item.title
return dict
}, {} as Record<string, string>)
// 通知开关选项
export const notificationSwitchOptions = [
{
title: i18n.global.t('notificationSwitch.resourceDownload'),
value: '资源下载',
},
{
title: i18n.global.t('notificationSwitch.organize'),
value: '整理入库',
},
{
title: i18n.global.t('notificationSwitch.subscribe'),
value: '订阅',
},
{
title: i18n.global.t('notificationSwitch.site'),
value: '站点',
},
{
title: i18n.global.t('notificationSwitch.mediaServer'),
value: '媒体服务器',
},
{
title: i18n.global.t('notificationSwitch.manual'),
value: '手动处理',
},
{
title: i18n.global.t('notificationSwitch.plugin'),
value: '插件',
},
{
title: i18n.global.t('notificationSwitch.other'),
value: '其它',
},
]
// 通知开关字典
export const notificationSwitchDict = notificationSwitchOptions.reduce((dict, item) => {
dict[item.value] = item.title
return dict
}, {} as Record<string, string>)
// 操作步骤选项
export const actionStepOptions = [
{
title: i18n.global.t('actionStep.addDownload'),
value: '添加下载',
},
{
title: i18n.global.t('actionStep.addSubscribe'),
value: '添加订阅',
},
{
title: i18n.global.t('actionStep.fetchDownloads'),
value: '获取下载任务',
},
{
title: i18n.global.t('actionStep.fetchMedias'),
value: '获取媒体数据',
},
{
title: i18n.global.t('actionStep.fetchRss'),
value: '获取RSS资源',
},
{
title: i18n.global.t('actionStep.fetchTorrents'),
value: '搜索站点资源',
},
{
title: i18n.global.t('actionStep.filterMedias'),
value: '过滤媒体数据',
},
{
title: i18n.global.t('actionStep.filterTorrents'),
value: '过滤资源',
},
{
title: i18n.global.t('actionStep.scanFile'),
value: '扫描目录',
},
{
title: i18n.global.t('actionStep.scrapeFile'),
value: '刮削文件',
},
{
title: i18n.global.t('actionStep.sendEvent'),
value: '发送事件',
},
{
title: i18n.global.t('actionStep.sendMessage'),
value: '发送消息',
},
{
title: i18n.global.t('actionStep.transferFile'),
value: '整理文件',
},
]
// 操作步骤字典
export const actionStepDict = actionStepOptions.reduce((dict, item) => {
dict[item.value] = item.title
return dict
}, {} as Record<string, string>)

View File

@@ -106,7 +106,7 @@ function onClose() {
<VImg :src="filter_svg" cover class="mt-7" max-width="3rem" />
</VCardText>
</VCard>
<VDialog v-if="ruleInfoDialog" v-model="ruleInfoDialog" scrollable max-width="40rem" persistent>
<VDialog v-if="ruleInfoDialog" v-model="ruleInfoDialog" scrollable max-width="40rem">
<VCard :title="t('customRule.title', { id: props.rule.id })" class="rounded-t">
<VDialogCloseBtn v-model="ruleInfoDialog" />
<VDivider />

View File

@@ -219,7 +219,7 @@ function onClose() {
<VImg :src="filter_group_svg" cover class="mt-10" max-width="3rem" />
</VCardText>
</VCard>
<VDialog v-if="groupInfoDialog" v-model="groupInfoDialog" scrollable max-width="80rem" persistent>
<VDialog v-if="groupInfoDialog" v-model="groupInfoDialog" scrollable max-width="80rem">
<VCard :title="`${props.group.name} - ${t('filterRule.title')}`" class="rounded-t">
<VDialogCloseBtn v-model="groupInfoDialog" />
<VDivider />
@@ -228,9 +228,9 @@ function onClose() {
<VCol cols="12" md="6">
<VTextField
v-model="groupInfo.name"
:label="t('filterRule.name')"
:label="t('filterRule.groupName')"
:placeholder="t('filterRule.nameRequired')"
:hint="t('filterRule.name')"
:hint="t('filterRule.groupName')"
persistent-hint
active
/>

View File

@@ -14,7 +14,7 @@ import SubscribeEditDialog from '../dialog/SubscribeEditDialog.vue'
import SearchSiteDialog from '@/components/dialog/SearchSiteDialog.vue'
import SubscribeSeasonDialog from '../dialog/SubscribeSeasonDialog.vue'
import { useI18n } from 'vue-i18n'
import { getMediaTypeText } from '@/types/i18n-type'
import { mediaTypeDict } from '@/api/constants'
// 国际化
const { t } = useI18n()
@@ -402,15 +402,6 @@ function setupIntersectionObserver() {
}
}
onMounted(() => {
setupIntersectionObserver()
})
onBeforeUnmount(() => {
observer.value?.disconnect()
observer.value = null
})
// 计算图片地址
const getImgUrl: Ref<string> = computed(() => {
if (imageLoadError.value) return noImage
@@ -428,6 +419,21 @@ const getImgUrl: Ref<string> = computed(() => {
function onRemoveSubscribe() {
subscribeEditDialog.value = false
}
// 获取媒体类型文本
function getMediaTypeText(type: string | undefined) {
if (!type) return ''
return mediaTypeDict[type]
}
onMounted(() => {
setupIntersectionObserver()
})
onBeforeUnmount(() => {
observer.value?.disconnect()
observer.value = null
})
</script>
<template>

View File

@@ -192,7 +192,7 @@ onMounted(() => {
<VImg :src="getIcon" cover class="mt-7 me-3" max-width="3rem" min-width="3rem" />
</VCardText>
</VCard>
<VDialog v-if="mediaServerInfoDialog" v-model="mediaServerInfoDialog" scrollable max-width="40rem" persistent>
<VDialog v-if="mediaServerInfoDialog" v-model="mediaServerInfoDialog" scrollable max-width="40rem">
<VCard :title="`${props.mediaserver.name} - ${t('common.config')}`" class="rounded-t">
<VDialogCloseBtn v-model="mediaServerInfoDialog" />
<VDivider />

View File

@@ -134,7 +134,7 @@ function onClose() {
<VImg :src="getIcon" cover class="mt-7 me-3" max-width="3rem" />
</VCardText>
</VCard>
<VDialog v-if="notificationInfoDialog" v-model="notificationInfoDialog" scrollable max-width="40rem" persistent>
<VDialog v-if="notificationInfoDialog" v-model="notificationInfoDialog" scrollable max-width="40rem">
<VCard :title="`${props.notification.name} - ${t('notification.config')}`" class="rounded-t">
<VDialogCloseBtn v-model="notificationInfoDialog" />
<VDivider />

View File

@@ -14,6 +14,7 @@ import AlistConfigDialog from '../dialog/AlistConfigDialog.vue'
import { useToast } from 'vue-toast-notification'
import { isNullOrEmptyObject } from '@/@core/utils'
import { useI18n } from 'vue-i18n'
import { storageOptions } from '@/api/constants'
// 国际化
const { t } = useI18n()
@@ -127,6 +128,11 @@ function handleDone() {
emit('done')
}
// 根据存储类型获取文本
function getStorageTypeText(type: string) {
return storageOptions.find((option) => option.value === type)?.title
}
onMounted(() => {
queryStorage()
})
@@ -136,7 +142,7 @@ onMounted(() => {
<VCard variant="tonal" @click="openStorageDialog">
<VCardText class="flex justify-space-between align-center gap-3">
<div class="align-self-start flex-1">
<h5 class="text-h6 mb-1">{{ storage.name }}</h5>
<h5 class="text-h6 mb-1">{{ getStorageTypeText(storage.type) }}</h5>
<div class="mb-3 text-sm" v-if="total">{{ formatBytes(used, 1) }} / {{ formatBytes(total, 1) }}</div>
<div v-else-if="isNullOrEmptyObject(storage.config)">{{ t('storage.notConfigured') }}</div>
</div>

View File

@@ -24,7 +24,7 @@ function handleImport() {
</script>
<template>
<VDialog width="40rem" scrollable max-height="85vh" persistent>
<VDialog width="40rem" scrollable max-height="85vh">
<VCard :title="props.title" class="rounded-t">
<VDialogCloseBtn @click="emit('close')" />
<VCardText class="pt-2">

View File

@@ -335,7 +335,7 @@ onMounted(() => {
<VList lines="two" v-if="searchWord" class="search-list py-2">
<!-- 搜索结果分组标题 -->
<VListSubheader class="font-weight-medium text-uppercase py-2 px-4 px-sm-6">
{{ t('media.movie') }}
{{ t('common.media') }}
</VListSubheader>
<!-- 媒体搜索选项 -->

View File

@@ -6,7 +6,7 @@ import type { DownloaderConf, FilterRuleGroup, Site, Subscribe, TransferDirector
import { useDisplay } from 'vuetify'
import { useConfirm } from 'vuetify-use-dialog'
import { useI18n } from 'vue-i18n'
import { qualityOptions, resolutionOptions, effectOptions } from '@/api/constants'
// i18n
const { t } = useI18n()
@@ -269,90 +269,6 @@ const targetDirectories = computed(() => {
return downloadDirectories.value.map(item => item.download_path)
})
// 质量选择框数据
const qualityOptions = ref([
{
title: t('common.all'),
value: '',
},
{
title: '蓝光原盘',
value: 'Blu-?Ray.+VC-?1|Blu-?Ray.+AVC|UHD.+blu-?ray.+HEVC|MiniBD',
},
{
title: 'Remux',
value: 'Remux',
},
{
title: 'BluRay',
value: 'Blu-?Ray',
},
{
title: 'UHD',
value: 'UHD|UltraHD',
},
{
title: 'WEB-DL',
value: 'WEB-?DL|WEB-?RIP',
},
{
title: 'HDTV',
value: 'HDTV',
},
{
title: 'H265',
value: '[Hx].?265|HEVC',
},
{
title: 'H264',
value: '[Hx].?264|AVC',
},
])
// 分辨率选择框数据
const resolutionOptions = ref([
{
title: t('common.all'),
value: '',
},
{
title: '4k',
value: '4K|2160p|x2160',
},
{
title: '1080p',
value: '1080[pi]|x1080',
},
{
title: '720p',
value: '720[pi]|x720',
},
])
// 特效选择框数据
const effectOptions = ref([
{
title: t('common.all'),
value: '',
},
{
title: '杜比视界',
value: 'Dolby[\\s.]+Vision|DOVI|[\\s.]+DV[\\s.]+',
},
{
title: '杜比全景声',
value: 'Dolby[\\s.]*\\+?Atmos|Atmos',
},
{
title: 'HDR',
value: '[\\s.]+HDR[\\s.]+|HDR10|HDR10\\+',
},
{
title: 'SDR',
value: '[\\s.]+SDR[\\s.]+',
},
])
onMounted(() => {
queryFilterRuleGroups()
loadDownloadDirectories()

View File

@@ -5,7 +5,7 @@ import { formatDateDifference } from '@core/utils/formatters'
import { useDisplay } from 'vuetify'
import ProgressDialog from './ProgressDialog.vue'
import { useI18n } from 'vue-i18n'
import { getMediaTypeText } from '@/types/i18n-type'
import { mediaTypeDict } from '@/api/constants'
// 国际化
const { t } = useI18n()
@@ -137,6 +137,12 @@ const dropdownItems = ref([
},
},
])
// 获取媒体类型文本
function getMediaTypeText(type: string | undefined) {
if (!type) return ''
return mediaTypeDict[type]
}
</script>
<template>

View File

@@ -3,6 +3,7 @@ import api from '@/api'
import { FilterRuleGroup } from '@/api/types'
import { Handle, Position } from '@vue-flow/core'
import { useI18n } from 'vue-i18n'
import { qualityOptions, resolutionOptions, effectOptions } from '@/api/constants'
const { t } = useI18n()
@@ -17,90 +18,6 @@ defineProps({
},
})
// 质量选择框数据
const qualityOptions = ref([
{
title: t('workflow.filterTorrents.qualityOptions.all'),
value: '',
},
{
title: t('workflow.filterTorrents.qualityOptions.blurayOriginal'),
value: 'Blu-?Ray.+VC-?1|Blu-?Ray.+AVC|UHD.+blu-?ray.+HEVC|MiniBD',
},
{
title: t('workflow.filterTorrents.qualityOptions.remux'),
value: 'Remux',
},
{
title: t('workflow.filterTorrents.qualityOptions.bluray'),
value: 'Blu-?Ray',
},
{
title: t('workflow.filterTorrents.qualityOptions.uhd'),
value: 'UHD|UltraHD',
},
{
title: t('workflow.filterTorrents.qualityOptions.webdl'),
value: 'WEB-?DL|WEB-?RIP',
},
{
title: t('workflow.filterTorrents.qualityOptions.hdtv'),
value: 'HDTV',
},
{
title: t('workflow.filterTorrents.qualityOptions.h265'),
value: '[Hx].?265|HEVC',
},
{
title: t('workflow.filterTorrents.qualityOptions.h264'),
value: '[Hx].?264|AVC',
},
])
// 分辨率选择框数据
const resolutionOptions = ref([
{
title: t('workflow.filterTorrents.resolutionOptions.all'),
value: '',
},
{
title: t('workflow.filterTorrents.resolutionOptions.4k'),
value: '4K|2160p|x2160',
},
{
title: t('workflow.filterTorrents.resolutionOptions.1080p'),
value: '1080[pi]|x1080',
},
{
title: t('workflow.filterTorrents.resolutionOptions.720p'),
value: '720[pi]|x720',
},
])
// 特效选择框数据
const effectOptions = ref([
{
title: t('workflow.filterTorrents.effectOptions.all'),
value: '',
},
{
title: t('workflow.filterTorrents.effectOptions.dolbyVision'),
value: 'Dolby[\\s.]+Vision|DOVI|[\\s.]+DV[\\s.]+',
},
{
title: t('workflow.filterTorrents.effectOptions.dolbyAtmos'),
value: 'Dolby[\\s.]*\\+?Atmos|Atmos',
},
{
title: t('workflow.filterTorrents.effectOptions.hdr'),
value: '[\\s.]+HDR[\\s.]+|HDR10|HDR10\\+',
},
{
title: t('workflow.filterTorrents.effectOptions.sdr'),
value: '[\\s.]+SDR[\\s.]+',
},
])
// 所有规则组列表
const filterRuleGroups = ref<FilterRuleGroup[]>([])

View File

@@ -3,7 +3,7 @@ import api from '@/api'
import useDragAndDrop from '@core/utils/workflow'
import { useDisplay } from 'vuetify'
import { useI18n } from 'vue-i18n'
import { getActionStepText } from '@/types/i18n-type'
import { actionStepDict } from '@/api/constants'
interface ActionItem {
name: string
@@ -95,6 +95,12 @@ watch(
},
)
// 获取动作步骤文本
function getActionStepText(type: string | undefined) {
if (!type) return ''
return actionStepDict[type]
}
onMounted(() => {
load_actions()
})

View File

@@ -37,6 +37,7 @@ export default {
files: 'Files',
share: 'Share',
unsubscribe: 'Unsubscribe',
media: 'Media',
},
mediaType: {
movie: 'Movie',
@@ -70,6 +71,30 @@ export default {
sendMessage: 'Send Message',
transferFile: 'Transfer File',
},
qualityOptions: {
all: 'All',
blurayOriginal: 'Blu-ray Original',
remux: 'Remux',
bluray: 'BluRay',
uhd: 'UHD',
webdl: 'WEB-DL',
hdtv: 'HDTV',
h265: 'H265',
h264: 'H264',
},
resolutionOptions: {
all: 'All',
'4k': '4K',
'1080p': '1080p',
'720p': '720p',
},
effectOptions: {
all: 'All',
dolbyVision: 'Dolby Vision',
dolbyAtmos: 'Dolby Atmos',
hdr: 'HDR',
sdr: 'SDR',
},
theme: {
light: 'Light',
dark: 'Dark',
@@ -249,7 +274,9 @@ export default {
empty: 'No Notifications',
channel: 'Notification Channel',
name: 'Name',
nameHint: 'Name of notification channel',
type: 'Type',
typeHint: 'Type of notification channel',
enabled: 'Enabled',
config: 'Configuration',
wechat: {
@@ -496,32 +523,8 @@ export default {
title: 'Filter Resources',
subtitle: 'Filter resource list',
quality: 'Quality',
qualityOptions: {
all: 'All',
blurayOriginal: 'Blu-ray Original',
remux: 'Remux',
bluray: 'BluRay',
uhd: 'UHD',
webdl: 'WEB-DL',
hdtv: 'HDTV',
h265: 'H265',
h264: 'H264',
},
resolution: 'Resolution',
resolutionOptions: {
all: 'All',
'4k': '4K',
'1080p': '1080p',
'720p': '720p',
},
effect: 'Effect',
effectOptions: {
all: 'All',
dolbyVision: 'Dolby Vision',
dolbyAtmos: 'Dolby Atmos',
hdr: 'HDR',
sdr: 'SDR',
},
size: 'Size Range',
include: 'Include (Keywords, Regex)',
exclude: 'Exclude (Keywords, Regex)',
@@ -727,6 +730,57 @@ export default {
usedPercent: '{percent}% Used',
noConfigNeeded: 'This storage type does not require configuration, please configure the directory directly!',
notConfigured: 'Not Configured',
local: 'Local',
alipan: 'Aliyun Drive',
u115: '115 Cloud',
rclone: 'RClone',
alist: 'AList',
},
filterRules: {
specSub: 'Special Subtitle',
cnSub: 'Chinese Subtitle',
cnVoi: 'Chinese Dubbing',
gz: 'Official Seed',
notCnVoi: 'Exclude: Chinese Dubbing',
hkVoi: 'Cantonese Dubbing',
notHkVoi: 'Exclude: Cantonese Dubbing',
free: 'Promotion: Free',
resolution4k: 'Resolution: 4K',
resolution1080p: 'Resolution: 1080P',
resolution720p: 'Resolution: 720P',
not720p: 'Exclude: 720P',
qualityBlu: 'Quality: Blu-ray',
notBlu: 'Exclude: Blu-ray',
qualityBluray: 'Quality: BLURAY',
notBluray: 'Exclude: BLURAY',
qualityUhd: 'Quality: UHD',
notUhd: 'Exclude: UHD',
qualityRemux: 'Quality: REMUX',
notRemux: 'Exclude: REMUX',
qualityWebdl: 'Quality: WEB-DL',
notWebdl: 'Exclude: WEB-DL',
quality60fps: 'Quality: 60fps',
not60fps: 'Exclude: 60fps',
codecH265: 'Codec: H265',
notH265: 'Exclude: H265',
codecH264: 'Codec: H264',
notH264: 'Exclude: H264',
effectDolby: 'Effect: Dolby Vision',
notDolby: 'Exclude: Dolby Vision',
effectAtmos: 'Effect: Dolby Atmos',
notAtmos: 'Exclude: Dolby Atmos',
effectHdr: 'Effect: HDR',
notHdr: 'Exclude: HDR',
effectSdr: 'Effect: SDR',
notSdr: 'Exclude: SDR',
effect3d: 'Effect: 3D',
not3d: 'Exclude: 3D',
},
transferType: {
copy: 'Copy',
move: 'Move',
link: 'Hard Link',
softlink: 'Soft Link',
},
site: {
noSites: 'No Sites',
@@ -2043,7 +2097,7 @@ export default {
},
filterRule: {
title: 'Filter Rule',
name: 'Name',
groupName: 'Group Name',
priority: 'Priority',
rules: 'Rules',
add: 'Add Rule',

View File

@@ -37,6 +37,7 @@ export default {
files: '文件',
share: '分享',
unsubscribe: '取消订阅',
media: '媒体',
},
mediaType: {
movie: '电影',
@@ -70,6 +71,30 @@ export default {
sendMessage: '发送消息',
transferFile: '整理文件',
},
qualityOptions: {
all: '全部',
blurayOriginal: '蓝光原盘',
remux: 'Remux',
bluray: 'BluRay',
uhd: 'UHD',
webdl: 'WEB-DL',
hdtv: 'HDTV',
h265: 'H265',
h264: 'H264',
},
resolutionOptions: {
all: '全部',
'4k': '4k',
'1080p': '1080p',
'720p': '720p',
},
effectOptions: {
all: '全部',
dolbyVision: '杜比视界',
dolbyAtmos: '杜比全景声',
hdr: 'HDR',
sdr: 'SDR',
},
theme: {
light: '浅色',
dark: '深色',
@@ -248,7 +273,9 @@ export default {
empty: '暂无通知',
channel: '通知渠道',
name: '名称',
nameHint: '通知渠道名称',
type: '类型',
typeHint: '通知渠道类型',
enabled: '启用',
config: '配置',
wechat: {
@@ -494,32 +521,8 @@ export default {
title: '过滤资源',
subtitle: '对资源列表数据进行过滤',
quality: '质量',
qualityOptions: {
all: '全部',
blurayOriginal: '蓝光原盘',
remux: 'Remux',
bluray: 'BluRay',
uhd: 'UHD',
webdl: 'WEB-DL',
hdtv: 'HDTV',
h265: 'H265',
h264: 'H264',
},
resolution: '分辨率',
resolutionOptions: {
all: '全部',
'4k': '4k',
'1080p': '1080p',
'720p': '720p',
},
effect: '特效',
effectOptions: {
all: '全部',
dolbyVision: '杜比视界',
dolbyAtmos: '杜比全景声',
hdr: 'HDR',
sdr: 'SDR',
},
size: '大小范围',
include: '包含(关键字、正则式)',
exclude: '排除(关键字、正则式)',
@@ -724,6 +727,57 @@ export default {
usedPercent: '已使用 {percent}%',
noConfigNeeded: '此存储类型无需配置参数,请直接配置目录!',
notConfigured: '未配置',
local: '本地',
alipan: '阿里云盘',
u115: '115网盘',
rclone: 'RClone',
alist: 'AList',
},
filterRules: {
specSub: '特效字幕',
cnSub: '中文字幕',
cnVoi: '国语配音',
gz: '官种',
notCnVoi: '排除: 国语配音',
hkVoi: '粤语配音',
notHkVoi: '排除: 粤语配音',
free: '促销: 免费',
resolution4k: '分辨率: 4K',
resolution1080p: '分辨率: 1080P',
resolution720p: '分辨率: 720P',
not720p: '排除: 720P',
qualityBlu: '质量: 蓝光原盘',
notBlu: '排除: 蓝光原盘',
qualityBluray: '质量: BLURAY',
notBluray: '排除: BLURAY',
qualityUhd: '质量: UHD',
notUhd: '排除: UHD',
qualityRemux: '质量: REMUX',
notRemux: '排除: REMUX',
qualityWebdl: '质量: WEB-DL',
notWebdl: '排除: WEB-DL',
quality60fps: '质量: 60fps',
not60fps: '排除: 60fps',
codecH265: '编码: H265',
notH265: '排除: H265',
codecH264: '编码: H264',
notH264: '排除: H264',
effectDolby: '效果: 杜比视界',
notDolby: '排除: 杜比视界',
effectAtmos: '效果: 杜比全景声',
notAtmos: '排除: 杜比全景声',
effectHdr: '效果: HDR',
notHdr: '排除: HDR',
effectSdr: '效果: SDR',
notSdr: '排除: SDR',
effect3d: '效果: 3D',
not3d: '排除: 3D',
},
transferType: {
copy: '复制',
move: '移动',
link: '硬链接',
softlink: '软链接',
},
site: {
noSites: '没有站点',
@@ -2019,6 +2073,7 @@ export default {
},
filterRule: {
title: '过滤规则',
groupName: '规则组名称',
priority: '优先级',
rules: '规则',
add: '添加规则',

View File

@@ -37,6 +37,7 @@ export default {
files: '文件',
share: '分享',
unsubscribe: '取消訂閱',
media: '媒體',
},
mediaType: {
movie: '電影',
@@ -70,6 +71,30 @@ export default {
sendMessage: '發送消息',
transferFile: '整理文件',
},
qualityOptions: {
all: '全部',
blurayOriginal: '藍光原盤',
remux: 'Remux',
bluray: 'BluRay',
uhd: 'UHD',
webdl: 'WEB-DL',
hdtv: 'HDTV',
h265: 'H265',
h264: 'H264',
},
resolutionOptions: {
all: '全部',
'4k': '4k',
'1080p': '1080p',
'720p': '720p',
},
effectOptions: {
all: '全部',
dolbyVision: '杜比視界',
dolbyAtmos: '杜比全景聲',
hdr: 'HDR',
sdr: 'SDR',
},
theme: {
light: '淺色',
dark: '深色',
@@ -249,7 +274,9 @@ export default {
empty: '暫無通知',
channel: '通知渠道',
name: '名稱',
nameHint: '通知渠道名稱',
type: '類型',
typeHint: '通知渠道類型',
enabled: '啟用',
config: '配置',
wechat: {
@@ -495,32 +522,8 @@ export default {
title: '過濾資源',
subtitle: '對資源列表數據進行過濾',
quality: '質量',
qualityOptions: {
all: '全部',
blurayOriginal: '藍光原盤',
remux: 'Remux',
bluray: 'BluRay',
uhd: 'UHD',
webdl: 'WEB-DL',
hdtv: 'HDTV',
h265: 'H265',
h264: 'H264',
},
resolution: '分辨率',
resolutionOptions: {
all: '全部',
'4k': '4k',
'1080p': '1080p',
'720p': '720p',
},
effect: '特效',
effectOptions: {
all: '全部',
dolbyVision: '杜比視界',
dolbyAtmos: '杜比全景聲',
hdr: 'HDR',
sdr: 'SDR',
},
size: '大小範圍',
include: '包含(關鍵字、正則式)',
exclude: '排除(關鍵字、正則式)',
@@ -725,6 +728,58 @@ export default {
usedPercent: '已使用 {percent}%',
noConfigNeeded: '此存儲類型無需配置參數,請直接配置目錄!',
notConfigured: '未配置',
local: '本地',
alipan: '阿里雲盤',
u115: '115網盤',
rclone: 'RClone',
alist: 'AList',
},
filterRules: {
specSub: '特效字幕',
cnSub: '中文字幕',
cnVoi: '國語配音',
gz: '官種',
notCnVoi: '排除: 國語配音',
hkVoi: '粵語配音',
notHkVoi: '排除: 粵語配音',
free: '促銷: 免費',
resolution4k: '解析度: 4K',
resolution1080p: '解析度: 1080P',
resolution720p: '解析度: 720P',
not720p: '排除: 720P',
qualityBlu: '品質: 藍光原盤',
notBlu: '排除: 藍光原盤',
qualityBluray: '品質: BLURAY',
notBluray: '排除: BLURAY',
qualityUhd: '品質: UHD',
notUhd: '排除: UHD',
qualityRemux: '品質: REMUX',
notRemux: '排除: REMUX',
qualityWebdl: '品質: WEB-DL',
notWebdl: '排除: WEB-DL',
quality60fps: '品質: 60fps',
not60fps: '排除: 60fps',
codecH265: '編碼: H265',
notH265: '排除: H265',
codecH264: '編碼: H264',
notH264: '排除: H264',
effectDolby: '效果: 杜比視界',
notDolby: '排除: 杜比視界',
effectAtmos: '效果: 杜比全景聲',
notAtmos: '排除: 杜比全景聲',
effectHdr: '效果: HDR',
notHdr: '排除: HDR',
effectSdr: '效果: SDR',
notSdr: '排除: SDR',
effect3d: '效果: 3D',
not3d: '排除: 3D',
},
transferType: {
copy: '複製',
move: '移動',
link: '硬連結',
softlink: '軟連結',
},
site: {
noSites: '沒有站點',
@@ -2020,6 +2075,7 @@ export default {
},
filterRule: {
title: '過濾規則',
groupName: '規則組名稱',
priority: '優先級',
rules: '規則',
add: '添加規則',

View File

@@ -44,6 +44,7 @@ export default {
VDialog: {
elevation: 0,
rounded: 'lg',
maxHeight: '85vh',
},
VExpansionPanels: {
elevation: 0,

View File

@@ -1,70 +0,0 @@
// MediaType
export function getMediaTypeText(label: string | undefined) {
if (!label) return ''
const { t } = useI18n()
// 常见的媒体类型及其映射
const typeMap: Record<string, string> = {
'电影': 'mediaType.movie',
'电视剧': 'mediaType.tv',
'动漫': 'mediaType.anime',
'合集': 'mediaType.collection',
'未知': 'mediaType.unknown',
}
// 如果是已知类型使用i18n翻译
if (label in typeMap) {
return t(typeMap[label])
}
// 对于未知的类型,直接返回原始标签
return label
}
// notificationSwitch
export function getNotificationSwitchText(label: string | undefined) {
if (!label) return ''
const { t } = useI18n()
const switchMap: Record<string, string> = {
'资源下载': 'notificationSwitch.resourceDownload',
'整理入库': 'notificationSwitch.organize',
'订阅': 'notificationSwitch.subscribe',
'站点': 'notificationSwitch.site',
'媒体服务器': 'notificationSwitch.mediaServer',
'手动处理': 'notificationSwitch.manual',
'插件': 'notificationSwitch.plugin',
'其它': 'notificationSwitch.other',
}
if (label in switchMap) {
return t(switchMap[label])
}
}
// actionStep
export function getActionStepText(label: string | undefined) {
if (!label) return ''
const { t } = useI18n()
const stepMap: Record<string, string> = {
'添加下载': 'actionStep.addDownload',
'添加订阅': 'actionStep.addSubscribe',
'获取下载任务': 'actionStep.fetchDownloads',
'获取媒体数据': 'actionStep.fetchMedias',
'获取RSS资源': 'actionStep.fetchRss',
'搜索站点资源': 'actionStep.fetchTorrents',
'过滤媒体数据': 'actionStep.filterMedias',
'过滤资源': 'actionStep.filterTorrents',
'扫描目录': 'actionStep.scanFile',
'刮削文件': 'actionStep.scrapeFile',
'发送事件': 'actionStep.sendEvent',
'发送消息': 'actionStep.sendMessage',
'整理文件': 'actionStep.transferFile',
}
if (label in stepMap) {
return t(stepMap[label])
}
}

View File

@@ -6,7 +6,7 @@ import type { NotificationConf, NotificationSwitchConf } from '@/api/types'
import NotificationChannelCard from '@/components/cards/NotificationChannelCard.vue'
import ProgressDialog from '@/components/dialog/ProgressDialog.vue'
import { useI18n } from 'vue-i18n'
import { getNotificationSwitchText } from '@/types/i18n-type'
import { notificationSwitchDict } from '@/api/constants'
// 国际化
const { t } = useI18n()
@@ -171,6 +171,12 @@ async function saveNotificationSwitchs() {
}
}
// 获取通知开关文本
function getNotificationSwitchText(type: string | undefined) {
if (!type) return ''
return notificationSwitchDict[type]
}
// 加载数据
onMounted(() => {
loadNotificationSetting()

View File

@@ -147,6 +147,8 @@ function addFilterRuleGroup() {
}
filterRuleGroups.value.push({
name: name,
media_type: '',
category: '',
})
}

View File

@@ -610,7 +610,7 @@ onDeactivated(() => {
</VCol>
</VRow>
<!-- 高级系统设置 -->
<VDialog v-if="advancedDialog" v-model="advancedDialog" scrollable max-width="60rem" persistent>
<VDialog v-if="advancedDialog" v-model="advancedDialog" scrollable max-width="60rem">
<VCard>
<VCardItem>
<VDialogCloseBtn @click="advancedDialog = false" />