更新国际化支持:在多个组件中引入 vue-i18n,优化文本翻译和结构

This commit is contained in:
jxxghp
2025-04-27 22:19:57 +08:00
parent 7a3d566875
commit 71787ece64
10 changed files with 298 additions and 244 deletions

View File

@@ -140,7 +140,9 @@ onMounted(() => {
<div class="max-w-6xl py-4 sm:grid sm:grid-cols-3 sm:gap-4">
<dt class="block text-sm font-bold">{{ t('setting.about.dataDir') }}</dt>
<dd class="flex text-sm sm:col-span-2 sm:mt-0">
<span class="flex-grow undefined"><code>/moviepilot</code></span>
<span class="flex-grow undefined"
><code>{{ t('setting.about.dataDirectory') }}</code></span
>
</dd>
</div>
</div>

View File

@@ -8,6 +8,9 @@ import { TransferDirectoryConf, StorageConf } from '@/api/types'
import DirectoryCard from '@/components/cards/DirectoryCard.vue'
import StorageCard from '@/components/cards/StorageCard.vue'
import ProgressDialog from '@/components/dialog/ProgressDialog.vue'
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
// 所有下载目录
const directories = ref<TransferDirectoryConf[]>([])
@@ -195,8 +198,8 @@ onMounted(() => {
<VCol cols="12">
<VCard>
<VCardItem>
<VCardTitle>存储</VCardTitle>
<VCardSubtitle>设置本地或网盘存储</VCardSubtitle>
<VCardTitle>{{ t('setting.directory.storage') }}</VCardTitle>
<VCardSubtitle>{{ t('setting.directory.storageDesc') }}</VCardSubtitle>
</VCardItem>
<VCardText>
<draggable
@@ -214,7 +217,7 @@ onMounted(() => {
<VCardText>
<VForm @submit.prevent="() => {}">
<div class="d-flex flex-wrap gap-4 mt-4">
<VBtn type="submit" class="me-2" @click="saveStorages"> 保存 </VBtn>
<VBtn type="submit" class="me-2" @click="saveStorages"> {{ t('common.save') }} </VBtn>
</div>
</VForm>
</VCardText>
@@ -225,8 +228,8 @@ onMounted(() => {
<VCol cols="12">
<VCard>
<VCardItem>
<VCardTitle>目录</VCardTitle>
<VCardSubtitle>设置媒体文件整理目录结构按先后顺序依次匹配</VCardSubtitle>
<VCardTitle>{{ t('setting.directory.directory') }}</VCardTitle>
<VCardSubtitle>{{ t('setting.directory.directoryDesc') }}</VCardSubtitle>
</VCardItem>
<VCardText>
<draggable
@@ -250,7 +253,7 @@ onMounted(() => {
<VCardText>
<VForm @submit.prevent="() => {}">
<div class="d-flex flex-wrap gap-4 mt-4">
<VBtn type="submit" @click="saveDirectories"> 保存 </VBtn>
<VBtn type="submit" @click="saveDirectories"> {{ t('common.save') }} </VBtn>
<VBtn color="success" variant="tonal" @click="addDirectory">
<VIcon icon="mdi-plus" />
</VBtn>
@@ -264,8 +267,8 @@ onMounted(() => {
<VCol cols="12">
<VCard>
<VCardItem>
<VCardTitle>整理 & 刮削</VCardTitle>
<VCardSubtitle>设置重命名格式刮削选项等</VCardSubtitle>
<VCardTitle>{{ t('setting.directory.organizeAndScrap') }}</VCardTitle>
<VCardSubtitle>{{ t('setting.directory.organizeAndScrapDesc') }}</VCardSubtitle>
</VCardItem>
<VCardText>
<VRow>
@@ -273,16 +276,16 @@ onMounted(() => {
<VSelect
v-model="SystemSettings.Basic.SCRAP_SOURCE"
:items="sourceItems"
label="刮削数据源"
hint="刮削时的元数据来源"
:label="t('setting.directory.scrapSource')"
:hint="t('setting.directory.scrapSourceHint')"
persistent-hint
/>
</VCol>
<VCol cols="12">
<VTextarea
v-model="SystemSettings.Basic.MOVIE_RENAME_FORMAT"
label="电影重命名格式"
hint="使用Jinja2语法格式参考https://jinja.palletsprojects.com/en/3.0.x/templates"
:label="t('setting.directory.movieRenameFormat')"
:hint="t('setting.directory.movieRenameFormatHint')"
persistent-hint
clearable
active
@@ -291,8 +294,8 @@ onMounted(() => {
<VCol cols="12">
<VTextarea
v-model="SystemSettings.Basic.TV_RENAME_FORMAT"
label="电视剧重命名格式"
hint="使用Jinja2语法格式参考https://jinja.palletsprojects.com/en/3.0.x/templates"
:label="t('setting.directory.tvRenameFormat')"
:hint="t('setting.directory.tvRenameFormatHint')"
persistent-hint
clearable
active
@@ -303,7 +306,7 @@ onMounted(() => {
<VCardText>
<VForm @submit.prevent="() => {}">
<div class="d-flex flex-wrap gap-4 mt-4">
<VBtn type="submit" @click="saveSystemSettings(SystemSettings.Basic)"> 保存</VBtn>
<VBtn type="submit" @click="saveSystemSettings(SystemSettings.Basic)"> {{ t('common.save') }}</VBtn>
</div>
</VForm>
</VCardText>
@@ -311,5 +314,5 @@ onMounted(() => {
</VCol>
</VRow>
<!-- 进度框 -->
<ProgressDialog v-if="progressDialog" v-model="progressDialog" text="正在应用配置..." />
<ProgressDialog v-if="progressDialog" v-model="progressDialog" :text="t('setting.system.reloading')" />
</template>

View File

@@ -216,19 +216,19 @@ onMounted(() => {
<VListItemTitle>{{ t('setting.notification.wechat') }}</VListItemTitle>
</VListItem>
<VListItem @click="addNotification('telegram')">
<VListItemTitle>Telegram</VListItemTitle>
<VListItemTitle>{{ t('setting.notification.telegram') }}</VListItemTitle>
</VListItem>
<VListItem @click="addNotification('slack')">
<VListItemTitle>Slack</VListItemTitle>
<VListItemTitle>{{ t('setting.notification.slack') }}</VListItemTitle>
</VListItem>
<VListItem @click="addNotification('synologychat')">
<VListItemTitle>SynologyChat</VListItemTitle>
<VListItemTitle>{{ t('setting.notification.synologyChat') }}</VListItemTitle>
</VListItem>
<VListItem @click="addNotification('vocechat')">
<VListItemTitle>VoceChat</VListItemTitle>
<VListItemTitle>{{ t('setting.notification.voceChat') }}</VListItemTitle>
</VListItem>
<VListItem @click="addNotification('webpush')">
<VListItemTitle>WebPush</VListItemTitle>
<VListItemTitle>{{ t('setting.notification.webPush') }}</VListItemTitle>
</VListItem>
</VList>
</VMenu>

View File

@@ -8,6 +8,10 @@ import { CustomRule, FilterRuleGroup } from '@/api/types'
import CustomerRuleCard from '@/components/cards/CustomRuleCard.vue'
import FilterRuleGroupCard from '@/components/cards/FilterRuleGroupCard.vue'
import ImportCodeDialog from '@/components/dialog/ImportCodeDialog.vue'
import { useI18n } from 'vue-i18n'
// 国际化
const { t } = useI18n()
// 自定义规则列表
const customRules = ref<CustomRule[]>([])
@@ -32,10 +36,10 @@ const $toast = useToast()
// 种子优先规则下拉框
const TorrentPriorityItems = [
{ title: '资源优先级', value: 'torrent' },
{ title: '站点优先级', value: 'site' },
{ title: '站点上传量', value: 'upload' },
{ title: '资源做种数', value: 'seeder' },
{ title: t('setting.rule.resourcePriority'), value: 'torrent' },
{ title: t('setting.rule.sitePriority'), value: 'site' },
{ title: t('setting.rule.siteUpload'), value: 'upload' },
{ title: t('setting.rule.resourceSeeder'), value: 'seeder' },
]
// 调用API查询自动分类配置
@@ -51,12 +55,12 @@ async function loadMediaCategories() {
async function saveCustomRules() {
// 检查是否存在空id规则
if (customRules.value.some(item => !item.id)) {
$toast.error('存在空ID的规则无法保存请修改')
$toast.error(t('setting.rule.emptyIdError'))
return
}
// 检查是否存在空的规则名称
if (customRules.value.some(item => !item.name)) {
$toast.error('存在空名字的规则,无法保存,请修改!')
$toast.error(t('setting.rule.emptyNameError'))
return
}
// 获取所有规则ID和名称
@@ -64,18 +68,18 @@ async function saveCustomRules() {
const names = customRules.value.map(item => item.name)
// 检查是否存在重名的规则ID
if (new Set(ids).size !== ids.length) {
$toast.error('存在重复规则ID无法保存请修改')
$toast.error(t('setting.rule.duplicateIdError'))
return
}
// 检查是否存在重名规则名称
if (new Set(names).size !== names.length) {
$toast.error('存在重复规则名称!无法保存,请修改!')
$toast.error(t('setting.rule.duplicateNameError'))
return
}
try {
const result: { [key: string]: any } = await api.post('system/setting/CustomFilterRules', customRules.value)
if (result.success) $toast.success('自定义规则保存成功')
else $toast.error('自定义规则保存失败!')
if (result.success) $toast.success(t('setting.rule.customRuleSaveSuccess'))
else $toast.error(t('setting.rule.customRuleSaveFailed'))
} catch (error) {
console.log(error)
}
@@ -117,19 +121,19 @@ async function queryFilterRuleGroups() {
async function saveFilterRuleGroups() {
// 检查是否存在空的规则组名称
if (filterRuleGroups.value.some(item => !item.name)) {
$toast.error('存在空名字的规则组!无法保存,请修改!')
$toast.error(t('setting.rule.emptyGroupNameError'))
return
}
// 检查是否存在重名规则组
const names = filterRuleGroups.value.map(item => item.name)
if (new Set(names).size !== names.length) {
$toast.error('存在重复规则组名称!无法保存,请修改!')
$toast.error(t('setting.rule.duplicateGroupNameError'))
return
}
try {
const result: { [key: string]: any } = await api.post('system/setting/UserFilterRuleGroups', filterRuleGroups.value)
if (result.success) $toast.success('优先级规则组保存成功')
else $toast.error('优先级规则组保存失败!')
if (result.success) $toast.success(t('setting.rule.ruleGroupSaveSuccess'))
else $toast.error(t('setting.rule.ruleGroupSaveFailed'))
} catch (error) {
console.log(error)
}
@@ -157,10 +161,14 @@ async function shareRules(rules: CustomRule[] | FilterRuleGroup[], type: string)
try {
let success
success = copyToClipboard(value)
if (await success) $toast.success(`${type === 'custom' ? '自定义规则' : '优先级规则组'}已复制到剪贴板!`)
else $toast.error(`${type === 'custom' ? '自定义规则' : '优先级规则组'}复制失败:可能是浏览器不支持或被用户阻止!`)
if (await success)
$toast.success(
type === 'custom' ? t('setting.rule.customRuleCopySuccess') : t('setting.rule.ruleGroupCopySuccess'),
)
else
$toast.error(type === 'custom' ? t('setting.rule.customRuleCopyFailed') : t('setting.rule.ruleGroupCopyFailed'))
} catch (e) {
$toast.error(`${type === 'custom' ? '自定义规则' : '优先级规则组'}复制失败!`)
$toast.error(type === 'custom' ? t('setting.rule.customRuleCopyError') : t('setting.rule.ruleGroupCopyError'))
console.error(e)
}
}
@@ -178,7 +186,7 @@ function saveCodeString(type: string, codeString: any) {
try {
parsedCode = JSON.parse(codeString.value)
} catch (e) {
$toast.error('导入规则失败!无法解析输入的数据!')
$toast.error(t('setting.rule.importFailed'))
console.error(e)
return
}
@@ -194,10 +202,10 @@ function saveCodeString(type: string, codeString: any) {
const newFilterRuleGroups = extractFilterRuleGroups(parsedCode) || []
filterRuleGroups.value = [...filterRuleGroups.value, ...newFilterRuleGroups]
} else {
$toast.error('导入规则失败!未知的数据类型!')
$toast.error(t('setting.rule.importUnknownType'))
}
} catch (e) {
$toast.error('导入规则失败!')
$toast.error(t('setting.rule.importFailed'))
console.error(e)
}
}
@@ -272,8 +280,8 @@ function isValidValue(value: any, type: string): boolean {
function validateCustomRule(hasName: boolean, hasId: boolean, noDuplicates: boolean): boolean {
if (!hasName || !hasId || !noDuplicates) {
if (!noDuplicates) $toast.warning(`存在重名值`)
if (!hasId) $toast.error(`导入失败发现有规则不存在ID可能属于优先级规则组`)
if (!noDuplicates) $toast.warning(t('setting.rule.duplicateValue'))
if (!hasId) $toast.error(t('setting.rule.importNoId'))
return false
}
return true
@@ -281,8 +289,8 @@ function validateCustomRule(hasName: boolean, hasId: boolean, noDuplicates: bool
function validateGroupRule(hasName: boolean, hasId: boolean, noDuplicates: boolean): boolean {
if (!hasName || hasId || !noDuplicates) {
if (!noDuplicates) $toast.warning(`存在重名值`)
if (hasId) $toast.error(`导入失败发现有规则存在相同ID可能属于自定义规则`)
if (!noDuplicates) $toast.warning(t('setting.rule.duplicateValue'))
if (hasId) $toast.error(t('setting.rule.importHasId'))
return false
}
return true
@@ -367,8 +375,8 @@ onMounted(() => {
<VCol cols="12">
<VCard>
<VCardItem>
<VCardTitle>自定义规则</VCardTitle>
<VCardSubtitle>自定义优先级规则项</VCardSubtitle>
<VCardTitle>{{ t('setting.rule.customRules') }}</VCardTitle>
<VCardSubtitle>{{ t('setting.rule.customRulesDesc') }}</VCardSubtitle>
</VCardItem>
<VCardText>
<draggable
@@ -391,7 +399,7 @@ onMounted(() => {
<VCardText>
<VForm @submit.prevent="() => {}">
<div class="d-flex flex-wrap gap-4 mt-4">
<VBtn type="submit" class="me-2" @click="saveCustomRules"> 保存 </VBtn>
<VBtn type="submit" class="me-2" @click="saveCustomRules"> {{ t('common.save') }} </VBtn>
<VBtnGroup density="comfortable">
<VBtn color="success" variant="tonal" @click="addCustomRule">
<VIcon icon="mdi-plus" />
@@ -416,8 +424,8 @@ onMounted(() => {
<VCol cols="12">
<VCard>
<VCardItem>
<VCardTitle>优先级规则组</VCardTitle>
<VCardSubtitle>预设优先级规则组以便在搜索和订阅中使用</VCardSubtitle>
<VCardTitle>{{ t('setting.rule.priorityRuleGroups') }}</VCardTitle>
<VCardSubtitle>{{ t('setting.rule.priorityRuleGroupsDesc') }}</VCardSubtitle>
</VCardItem>
<VCardText>
<draggable
@@ -442,7 +450,7 @@ onMounted(() => {
<VCardText>
<VForm @submit.prevent="() => {}">
<div class="d-flex flex-wrap gap-4 mt-4">
<VBtn type="submit" class="me-2" @click="saveFilterRuleGroups"> 保存 </VBtn>
<VBtn type="submit" class="me-2" @click="saveFilterRuleGroups"> {{ t('common.save') }} </VBtn>
<VBtnGroup density="comfortable">
<VBtn color="success" variant="tonal" @click="addFilterRuleGroup">
<VIcon icon="mdi-plus" />
@@ -466,7 +474,7 @@ onMounted(() => {
<ImportCodeDialog
v-if="importCodeDialog"
v-model="importCodeDialog"
:title="`导入${importCodeType === 'custom' ? '自定义规则' : '优先级规则组'}`"
:title="importCodeType === 'custom' ? t('setting.rule.importCustomRules') : t('setting.rule.importRuleGroups')"
:dataType="importCodeType"
@close="importCodeDialog = false"
@save="saveCodeString"
@@ -475,8 +483,8 @@ onMounted(() => {
<VCol cols="12">
<VCard>
<VCardItem>
<VCardTitle>下载规则</VCardTitle>
<VCardSubtitle>同时命中多个资源时择优下载</VCardSubtitle>
<VCardTitle>{{ t('setting.rule.downloadRules') }}</VCardTitle>
<VCardSubtitle>{{ t('setting.rule.downloadRulesDesc') }}</VCardSubtitle>
</VCardItem>
<VCardText>
<VForm>
@@ -488,8 +496,8 @@ onMounted(() => {
multiple
clearable
chips
label="当前使用下载优先规则"
hint="排在前面的优先级越高,未选择的项不纳入排序"
:label="t('setting.rule.currentPriorityRules')"
:hint="t('setting.rule.currentPriorityRulesHint')"
persistent-hint
/>
</VCol>
@@ -499,7 +507,7 @@ onMounted(() => {
<VCardText>
<VForm @submit.prevent="() => {}">
<div class="d-flex flex-wrap gap-4 mt-4">
<VBtn type="submit" @click="saveTorrentPriority"> 保存 </VBtn>
<VBtn type="submit" @click="saveTorrentPriority"> {{ t('common.save') }} </VBtn>
</div>
</VForm>
</VCardText>

View File

@@ -2,6 +2,10 @@
import { useToast } from 'vue-toast-notification'
import api from '@/api'
import type { ScheduleInfo } from '@/api/types'
import { useI18n } from 'vue-i18n'
// 国际化
const { t } = useI18n()
// 提示框
const $toast = useToast()
@@ -26,11 +30,11 @@ async function loadSchedulerList() {
// 任务状态颜色
function getSchedulerColor(status: string) {
switch (status) {
case '正在运行':
case t('setting.scheduler.running'):
return 'success'
case '已停止':
case t('setting.scheduler.stopped'):
return 'error'
case '等待':
case t('setting.scheduler.waiting'):
return ''
default:
return ''
@@ -46,7 +50,7 @@ function runCommand(id: string) {
jobid: id,
},
})
$toast.success('定时作业执行请求提交成功!')
$toast.success(t('setting.scheduler.executeSuccess'))
// 1秒后刷新数据
setTimeout(() => {
loadSchedulerList()
@@ -77,16 +81,16 @@ onUnmounted(() => {
<template>
<VCard>
<VCardItem>
<VCardTitle>定时作业</VCardTitle>
<VCardSubtitle>包含系统内置服务以及插件提供的服务手动执行不会影响作业正常的时间表</VCardSubtitle>
<VCardTitle>{{ t('setting.scheduler.title') }}</VCardTitle>
<VCardSubtitle>{{ t('setting.scheduler.subtitle') }}</VCardSubtitle>
</VCardItem>
<VTable class="text-no-wrap">
<thead>
<tr>
<th scope="col">提供者</th>
<th scope="col">任务名称</th>
<th scope="col">任务状态</th>
<th scope="col">下一次执行时间</th>
<th scope="col">{{ t('setting.scheduler.provider') }}</th>
<th scope="col">{{ t('setting.scheduler.taskName') }}</th>
<th scope="col">{{ t('setting.scheduler.taskStatus') }}</th>
<th scope="col">{{ t('setting.scheduler.nextRunTime') }}</th>
<th scope="col" />
</tr>
</thead>
@@ -107,16 +111,20 @@ onUnmounted(() => {
{{ scheduler.next_run }}
</td>
<td>
<VBtn size="small" :disabled="scheduler.status === '正在运行'" @click="runCommand(scheduler.id)">
<VBtn
size="small"
:disabled="scheduler.status === t('setting.scheduler.running')"
@click="runCommand(scheduler.id)"
>
<template #prepend>
<VIcon>mdi-play</VIcon>
</template>
执行
{{ t('setting.scheduler.execute') }}
</VBtn>
</td>
</tr>
<tr v-if="schedulerList.length === 0">
<td colspan="4" class="text-center">没有后台服务</td>
<td colspan="4" class="text-center">{{ t('setting.scheduler.noService') }}</td>
</tr>
</tbody>
</VTable>

View File

@@ -2,6 +2,7 @@
import { useToast } from 'vue-toast-notification'
import api from '@/api'
import type { FilterRuleGroup, Site } from '@/api/types'
import { useI18n } from 'vue-i18n'
// 提示框
const $toast = useToast()
@@ -172,6 +173,8 @@ async function loadSystemSettings() {
}
}
const { t } = useI18n()
onMounted(() => {
querySites()
queryFilterRuleGroups()
@@ -186,8 +189,8 @@ onMounted(() => {
<VCol cols="12">
<VCard>
<VCardItem>
<VCardTitle>基础设置</VCardTitle>
<VCardSubtitle>设定数据源规则组等基础信息</VCardSubtitle>
<VCardTitle>{{ t('setting.search.basicSettings') }}</VCardTitle>
<VCardSubtitle>{{ t('setting.search.basicSettingsDesc') }}</VCardSubtitle>
</VCardItem>
<VCardText>
<VRow>
@@ -198,8 +201,8 @@ onMounted(() => {
clearable
chips
:items="mediaSourcesDict"
label="媒体搜索数据源"
hint="搜索媒体信息时使用的数据源以及排序"
:label="t('setting.search.mediaSource')"
:hint="t('setting.search.mediaSourceHint')"
persistent-hint
/>
</VCol>
@@ -210,8 +213,8 @@ onMounted(() => {
clearable
chips
:items="filterRuleGroupOptions"
label="优先级规则组"
hint="搜索媒体信息时按选定的过滤规则组对结果进行过滤"
:label="t('setting.search.filterRuleGroup')"
:hint="t('setting.search.filterRuleGroupHint')"
persistent-hint
/>
</VCol>
@@ -220,34 +223,34 @@ onMounted(() => {
<VCol cols="12" md="6">
<VTextField
v-model="SystemSettings.Basic.TORRENT_TAG"
label="下载任务标签"
:label="t('setting.search.downloadLabel')"
placeholder="MOVIEPILOT"
hint="MoviePilot添加的下载任务标签"
:hint="t('setting.search.downloadLabelHint')"
persistent-hint
/>
</VCol>
<VCol cols="12" md="6">
<VCombobox
v-model="SystemSettings.Basic.AUTO_DOWNLOAD_USER"
label="远程搜索自动下载用户名单"
placeholder="用户ID1,用户ID2"
hint="使用Telegram、微信等搜索时是否自动下载使用逗号分割设置为 all 代表所有用户自动择优下载"
:label="t('setting.search.downloadUser')"
:placeholder="t('setting.search.downloadUserPlaceholder')"
:hint="t('setting.search.downloadUserHint')"
persistent-hint
/>
</VCol>
<VCol cols="12" md="6">
<VSwitch
v-model="SystemSettings.Basic.SEARCH_MULTIPLE_NAME"
label="多名称资源搜索"
hint="使用中英文等多个名称搜索站点资源并合并搜索结果,将会增加站点访问频率"
:label="t('setting.search.multipleNameSearch')"
:hint="t('setting.search.multipleNameSearchHint')"
persistent-hint
/>
</VCol>
<VCol cols="12" md="6">
<VSwitch
v-model="SystemSettings.Basic.DOWNLOAD_SUBTITLE"
label="下载站点字幕"
hint="检查站点资源是否有独立的字幕文件,有则自动下载"
:label="t('setting.search.downloadSubtitle')"
:hint="t('setting.search.downloadSubtitleHint')"
persistent-hint
/>
</VCol>
@@ -256,7 +259,7 @@ onMounted(() => {
<VCardText>
<VForm @submit.prevent="() => {}">
<div class="d-flex flex-wrap gap-4 mt-4">
<VBtn type="submit" @click="saveSearchSetting"> 保存 </VBtn>
<VBtn type="submit" @click="saveSearchSetting"> {{ t('common.save') }} </VBtn>
</div>
</VForm>
</VCardText>
@@ -267,8 +270,8 @@ onMounted(() => {
<VCol cols="12">
<VCard>
<VCardItem>
<VCardTitle>搜索站点</VCardTitle>
<VCardSubtitle> 只有选中的站点才会在搜索中使用</VCardSubtitle>
<VCardTitle>{{ t('setting.search.downloadSite') }}</VCardTitle>
<VCardSubtitle>{{ t('setting.search.downloadSiteDesc') }}</VCardSubtitle>
</VCardItem>
<VCardText>
<VChipGroup v-model="selectedSites" column multiple>
@@ -287,7 +290,7 @@ onMounted(() => {
<VCardText>
<VForm @submit.prevent="() => {}">
<div class="d-flex flex-wrap gap-4 mt-4">
<VBtn type="submit" @click="saveSelectedSites"> 保存 </VBtn>
<VBtn type="submit" @click="saveSelectedSites"> {{ t('common.save') }} </VBtn>
</div>
</VForm>
</VCardText>

View File

@@ -3,6 +3,7 @@ import { useToast } from 'vue-toast-notification'
import api from '@/api'
import type { FilterRuleGroup, Site } from '@/api/types'
import ProgressDialog from '@/components/dialog/ProgressDialog.vue'
import { useI18n } from 'vue-i18n'
// 提示框
const $toast = useToast()
@@ -24,8 +25,8 @@ const selectedBestVersionRuleGroup = ref([])
// 订阅模式选择项
const subscribeModeItems = [
{ title: '自动', value: 'spider' },
{ title: '站点RSS', value: 'rss' },
{ title: t('setting.subscribe.modes.auto'), value: 'spider' },
{ title: t('setting.subscribe.modes.rss'), value: 'rss' },
]
// 所有规则组列表
@@ -41,13 +42,13 @@ const filterRuleGroupOptions = computed(() => {
// RSS运行周期选择项
const rssIntervalItems = [
{ title: '5分钟', value: 5 },
{ title: '10分钟', value: 10 },
{ title: '20分钟', value: 20 },
{ title: '半小时', value: 30 },
{ title: '1小时', value: 60 },
{ title: '12小时', value: 720 },
{ title: '1天', value: 1440 },
{ title: t('setting.subscribe.intervals.min5'), value: 5 },
{ title: t('setting.subscribe.intervals.min10'), value: 10 },
{ title: t('setting.subscribe.intervals.min20'), value: 20 },
{ title: t('setting.subscribe.intervals.min30'), value: 30 },
{ title: t('setting.subscribe.intervals.hour1'), value: 60 },
{ title: t('setting.subscribe.intervals.hour12'), value: 720 },
{ title: t('setting.subscribe.intervals.day1'), value: 1440 },
]
// 系统设置项
@@ -99,8 +100,8 @@ async function saveSelectedRssSites() {
try {
const result1: { [key: string]: any } = await api.post('system/setting/RssSites', selectedRssSites.value)
if (result1.success) $toast.success('订阅站点保存成功')
else $toast.error('订阅站点保存失败!')
if (result1.success) $toast.success(t('setting.subscribe.saveSuccess'))
else $toast.error(t('setting.subscribe.saveFailed'))
} catch (error) {
console.log(error)
}
@@ -154,8 +155,8 @@ async function reloadSystem() {
progressDialog.value = true
try {
const result: { [key: string]: any } = await api.get('system/reload')
if (result.success) $toast.success('系统配置已生效')
else $toast.error('重载系统失败!')
if (result.success) $toast.success(t('setting.system.reloadSuccess'))
else $toast.error(t('setting.system.reloadFailed'))
} catch (error) {
console.log(error)
}
@@ -178,14 +179,16 @@ async function saveSubscribeSetting() {
const result3 = await saveSystemSetting(SystemSettings.value.Basic)
if (result1.success && result2.success && result3) {
$toast.success('订阅基础设置保存成功')
$toast.success(t('setting.subscribe.settingsSaveSuccess'))
await reloadSystem()
} else $toast.error('订阅基础设置保存失败!')
} else $toast.error(t('setting.subscribe.settingsSaveFailed'))
} catch (error) {
console.log(error)
}
}
const { t } = useI18n()
onMounted(() => {
querySites()
queryFilterRuleGroups()
@@ -200,8 +203,8 @@ onMounted(() => {
<VCol cols="12">
<VCard>
<VCardItem>
<VCardTitle>基础设置</VCardTitle>
<VCardSubtitle>设定订阅模式周期等基础设置</VCardSubtitle>
<VCardTitle>{{ t('setting.subscribe.basicSettings') }}</VCardTitle>
<VCardSubtitle>{{ t('setting.subscribe.basicSettingsDesc') }}</VCardSubtitle>
</VCardItem>
<VCardText>
<VForm>
@@ -210,8 +213,8 @@ onMounted(() => {
<VSelect
v-model="SystemSettings.Basic.SUBSCRIBE_MODE"
:items="subscribeModeItems"
label="订阅模式"
hint="自动自动爬取站点首页站点RSS通过站点RSS链接订阅"
:label="t('setting.subscribe.mode')"
:hint="t('setting.subscribe.modeHint')"
persistent-hint
/>
</VCol>
@@ -219,8 +222,8 @@ onMounted(() => {
<VSelect
v-model="SystemSettings.Basic.SUBSCRIBE_RSS_INTERVAL"
:items="rssIntervalItems"
label="站点RSS周期"
hint="设置站点RSS运行周期在订阅模式为`站点RSS`时生效"
:label="t('setting.subscribe.rssInterval')"
:hint="t('setting.subscribe.rssIntervalHint')"
persistent-hint
/>
</VCol>
@@ -231,8 +234,8 @@ onMounted(() => {
chips
multiple
clearable
label="订阅优先级规则组"
hint="按选定的过滤规则组对订阅进行过滤"
:label="t('setting.subscribe.filterRuleGroup')"
:hint="t('setting.subscribe.filterRuleGroupHint')"
persistent-hint
/>
</VCol>
@@ -243,8 +246,8 @@ onMounted(() => {
chips
multiple
clearable
label="洗版优先级规则组"
hint="按选定的过滤规则组对洗版订阅进行过滤"
:label="t('setting.subscribe.bestVersionRuleGroup')"
:hint="t('setting.subscribe.bestVersionRuleGroupHint')"
persistent-hint
/>
</VCol>
@@ -253,16 +256,16 @@ onMounted(() => {
<VCol cols="12" md="6">
<VSwitch
v-model="SystemSettings.Basic.SUBSCRIBE_SEARCH"
label="订阅定时搜索"
hint="每隔24小时全站搜索以补全订阅可能漏掉的资源"
:label="t('setting.subscribe.timedSearch')"
:hint="t('setting.subscribe.timedSearchHint')"
persistent-hint
/>
</VCol>
<VCol cols="12" md="6">
<VSwitch
v-model="SystemSettings.Basic.LOCAL_EXISTS_SEARCH"
label="检查本地媒体库资源"
hint="检查存储盘是否存在资源,以避免重复下载"
:label="t('setting.subscribe.checkLocalMedia')"
:hint="t('setting.subscribe.checkLocalMediaHint')"
persistent-hint
/>
</VCol>
@@ -272,7 +275,7 @@ onMounted(() => {
<VCardText>
<VForm @submit.prevent="() => {}">
<div class="d-flex flex-wrap gap-4 mt-4">
<VBtn type="submit" @click="saveSubscribeSetting"> 保存 </VBtn>
<VBtn type="submit" @click="saveSubscribeSetting"> {{ t('common.save') }} </VBtn>
</div>
</VForm>
</VCardText>
@@ -283,8 +286,8 @@ onMounted(() => {
<VCol cols="12">
<VCard>
<VCardItem>
<VCardTitle>订阅站点</VCardTitle>
<VCardSubtitle>只有选中的站点才会在订阅中使用</VCardSubtitle>
<VCardTitle>{{ t('setting.subscribe.subscribeSites') }}</VCardTitle>
<VCardSubtitle>{{ t('setting.subscribe.subscribeSitesDesc') }}</VCardSubtitle>
</VCardItem>
<VCardText>
<VChipGroup v-model="selectedRssSites" column multiple>
@@ -303,7 +306,7 @@ onMounted(() => {
<VCardText>
<VForm @submit.prevent="() => {}">
<div class="d-flex flex-wrap gap-4 mt-4">
<VBtn type="submit" @click="saveSelectedRssSites"> 保存 </VBtn>
<VBtn type="submit" @click="saveSelectedRssSites"> {{ t('common.save') }} </VBtn>
</div>
</VForm>
</VCardText>
@@ -311,5 +314,5 @@ onMounted(() => {
</VCol>
</VRow>
<!-- 进度框 -->
<ProgressDialog v-if="progressDialog" v-model="progressDialog" text="正在应用配置..." />
<ProgressDialog v-if="progressDialog" v-model="progressDialog" :text="t('setting.system.reloading')" />
</template>

View File

@@ -532,10 +532,10 @@ onDeactivated(() => {
<VMenu activator="parent" close-on-content-click>
<VList>
<VListItem @click="addDownloader('qbittorrent')">
<VListItemTitle>Qbittorrent</VListItemTitle>
<VListItemTitle>{{ t('setting.system.qbittorrent') }}</VListItemTitle>
</VListItem>
<VListItem @click="addDownloader('transmission')">
<VListItemTitle>Transmission</VListItemTitle>
<VListItemTitle>{{ t('setting.system.transmission') }}</VListItemTitle>
</VListItem>
</VList>
</VMenu>
@@ -580,13 +580,13 @@ onDeactivated(() => {
<VMenu activator="parent" close-on-content-click>
<VList>
<VListItem @click="addMediaServer('emby')">
<VListItemTitle>Emby</VListItemTitle>
<VListItemTitle>{{ t('setting.system.emby') }}</VListItemTitle>
</VListItem>
<VListItem @click="addMediaServer('jellyfin')">
<VListItemTitle>Jellyfin</VListItemTitle>
<VListItemTitle>{{ t('setting.system.jellyfin') }}</VListItemTitle>
</VListItem>
<VListItem @click="addMediaServer('plex')">
<VListItemTitle>Plex</VListItemTitle>
<VListItemTitle>{{ t('setting.system.plex') }}</VListItemTitle>
</VListItem>
<VListItem @click="addMediaServer('trimemedia')">
<VListItemTitle>{{ t('setting.system.trimeMedia') }}</VListItemTitle>