mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-05-27 19:29:52 +08:00
更新国际化支持:为存储、媒体类型、通知开关及操作步骤等组件添加多语言文本,提升用户体验
This commit is contained in:
@@ -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 />
|
||||
|
||||
@@ -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
|
||||
/>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 />
|
||||
|
||||
@@ -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 />
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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>
|
||||
|
||||
<!-- 媒体搜索选项 -->
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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[]>([])
|
||||
|
||||
|
||||
Reference in New Issue
Block a user