mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-07-24 07:09:16 +08:00
更新国际化支持:将多个组件中的文本替换为国际化支持
This commit is contained in:
@@ -5,6 +5,10 @@ import { doneNProgress, startNProgress } from '@/api/nprogress'
|
||||
import { numberValidator, requiredValidator } from '@/@validators'
|
||||
import api from '@/api'
|
||||
import { useDisplay } from 'vuetify'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
// 国际化
|
||||
const { t } = useI18n()
|
||||
|
||||
// 显示器宽度
|
||||
const display = useDisplay()
|
||||
@@ -45,8 +49,8 @@ const isLimit = ref(false)
|
||||
|
||||
// 状态下拉项
|
||||
const statusItems = [
|
||||
{ title: '启用', value: true },
|
||||
{ title: '停用', value: false },
|
||||
{ title: t('site.status.enabled'), value: true },
|
||||
{ title: t('site.status.disabled'), value: false },
|
||||
]
|
||||
|
||||
// 生成1到50的优先级下拉框选项
|
||||
@@ -64,14 +68,14 @@ async function loadDownloaderSetting() {
|
||||
try {
|
||||
const downloaders: DownloaderConf[] = await api.get('download/clients')
|
||||
downloaderOptions.value = [
|
||||
{ title: '默认', value: '' },
|
||||
{ title: t('common.default'), value: '' },
|
||||
...downloaders.map((item: { name: any }) => ({
|
||||
title: item.name,
|
||||
value: item.name,
|
||||
})),
|
||||
]
|
||||
} catch (error) {
|
||||
console.error('加载下载器设置失败:', error)
|
||||
console.error(t('site.errors.loadDownloader'), error)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,10 +97,10 @@ async function addSite() {
|
||||
try {
|
||||
const result: { [key: string]: string } = await api.post('site/', siteForm.value)
|
||||
if (result.success) {
|
||||
$toast.success('新增站点成功')
|
||||
$toast.success(t('site.messages.addSuccess'))
|
||||
emit('save')
|
||||
} else {
|
||||
$toast.error(`新增站点失败:${result.message}`)
|
||||
$toast.error(`${t('site.messages.addFailed')}:${result.message}`)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
@@ -119,13 +123,13 @@ async function updateSiteInfo() {
|
||||
}
|
||||
const result: { [key: string]: any } = await api.put('site/', siteForm.value)
|
||||
if (result.success) {
|
||||
$toast.success(`${siteForm.value?.name} 更新成功!`)
|
||||
$toast.success(`${siteForm.value?.name} ${t('site.messages.updateSuccess')}`)
|
||||
emit('save')
|
||||
} else {
|
||||
$toast.error(`${siteForm.value?.name} 更新失败:${result.message}`)
|
||||
$toast.error(`${siteForm.value?.name} ${t('site.messages.updateFailed')}:${result.message}`)
|
||||
}
|
||||
} catch (error) {
|
||||
$toast.error(`${siteForm.value?.name} 更新失败!`)
|
||||
$toast.error(`${siteForm.value?.name} ${t('site.messages.updateFailed')}!`)
|
||||
console.error(error)
|
||||
}
|
||||
doneNProgress()
|
||||
@@ -145,7 +149,9 @@ onMounted(async () => {
|
||||
<template>
|
||||
<VDialog scrollable :close-on-back="false" eager max-width="45rem" :fullscreen="!display.mdAndUp.value">
|
||||
<VCard
|
||||
:title="`${props.oper === 'add' ? '新增' : '编辑'}站点${props.oper !== 'add' ? ` - ${siteForm.name}` : ''}`"
|
||||
:title="`${props.oper === 'add' ? t('site.actions.add') : t('site.actions.edit')}${t('site.title')}${
|
||||
props.oper !== 'add' ? ` - ${siteForm.name}` : ''
|
||||
}`"
|
||||
class="rounded-t"
|
||||
>
|
||||
<VDialogCloseBtn @click="emit('close')" />
|
||||
@@ -156,19 +162,19 @@ onMounted(async () => {
|
||||
<VCol cols="12" md="6">
|
||||
<VTextField
|
||||
v-model="siteForm.url"
|
||||
label="站点地址"
|
||||
:label="t('site.fields.url')"
|
||||
:rules="[requiredValidator]"
|
||||
hint="格式:http://www.example.com/"
|
||||
:hint="t('site.hints.url')"
|
||||
persistent-hint
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="6" md="3">
|
||||
<VSelect
|
||||
v-model="siteForm.pri"
|
||||
label="优先级"
|
||||
:label="t('site.fields.priority')"
|
||||
:items="priorityItems"
|
||||
:rules="[requiredValidator]"
|
||||
hint="优先级越小越优先"
|
||||
:hint="t('site.hints.priority')"
|
||||
persistent-hint
|
||||
/>
|
||||
</VCol>
|
||||
@@ -176,8 +182,8 @@ onMounted(async () => {
|
||||
<VSelect
|
||||
v-model="siteForm.is_active"
|
||||
:items="statusItems"
|
||||
label="状态"
|
||||
hint="站点启用/停用"
|
||||
:label="t('site.fields.status')"
|
||||
:hint="t('site.hints.status')"
|
||||
persistent-hint
|
||||
/>
|
||||
</VCol>
|
||||
@@ -186,25 +192,25 @@ onMounted(async () => {
|
||||
<VCol cols="12" md="6">
|
||||
<VTextField
|
||||
v-model="siteForm.rss"
|
||||
label="RSS地址"
|
||||
hint="订阅模式为`站点RSS`时使用的订阅链接,如未自动获取需手动补充"
|
||||
:label="t('site.fields.rss')"
|
||||
:hint="t('site.hints.rss')"
|
||||
persistent-hint
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="3">
|
||||
<VTextField
|
||||
v-model="siteForm.timeout"
|
||||
label="超时时间(秒)"
|
||||
hint="站点请求超时时间,为0时不限制"
|
||||
:label="t('site.fields.timeout')"
|
||||
:hint="t('site.hints.timeout')"
|
||||
persistent-hint
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="6" md="3">
|
||||
<VSelect
|
||||
v-model="siteForm.downloader"
|
||||
label="下载器"
|
||||
:label="t('site.fields.downloader')"
|
||||
:items="downloaderOptions"
|
||||
hint="此站点使用的下载器"
|
||||
:hint="t('site.hints.downloader')"
|
||||
persistent-hint
|
||||
/>
|
||||
</VCol>
|
||||
@@ -229,16 +235,16 @@ onMounted(async () => {
|
||||
<VCol cols="12">
|
||||
<VTextarea
|
||||
v-model="siteForm.cookie"
|
||||
label="站点Cookie"
|
||||
hint="站点请求头中的Cookie信息"
|
||||
:label="t('site.fields.cookie')"
|
||||
:hint="t('site.hints.cookie')"
|
||||
persistent-hint
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12">
|
||||
<VTextField
|
||||
v-model="siteForm.ua"
|
||||
label="站点User-Agent"
|
||||
hint="获取Cookie的浏览器对应的User-Agent"
|
||||
:label="t('site.fields.userAgent')"
|
||||
:hint="t('site.hints.userAgent')"
|
||||
persistent-hint
|
||||
/>
|
||||
</VCol>
|
||||
@@ -249,16 +255,16 @@ onMounted(async () => {
|
||||
<VCol cols="12" md="6">
|
||||
<VTextField
|
||||
v-model="siteForm.token"
|
||||
label="请求头(Authorization)"
|
||||
hint="站点请求头中的Authorization信息,特殊站点需要"
|
||||
:label="t('site.fields.authorization')"
|
||||
:hint="t('site.hints.authorization')"
|
||||
persistent-hint
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
<VTextField
|
||||
v-model="siteForm.apikey"
|
||||
label="令牌(API Key)"
|
||||
hint="站点的访问API Key,特殊站点需要"
|
||||
:label="t('site.fields.apiKey')"
|
||||
:hint="t('site.hints.apiKey')"
|
||||
persistent-hint
|
||||
/>
|
||||
</VCol>
|
||||
@@ -267,47 +273,52 @@ onMounted(async () => {
|
||||
</VWindow>
|
||||
<VRow>
|
||||
<VCol cols="12" md="4">
|
||||
<VSwitch v-model="isLimit" label="限制站点访问频率" />
|
||||
<VSwitch v-model="isLimit" :label="t('site.fields.limitAccess')" />
|
||||
</VCol>
|
||||
</VRow>
|
||||
<VRow v-if="isLimit">
|
||||
<VCol cols="12" md="4">
|
||||
<VTextField
|
||||
v-model="siteForm.limit_interval"
|
||||
label="单位周期(秒)"
|
||||
:label="t('site.fields.limitInterval')"
|
||||
:rules="[numberValidator]"
|
||||
hint="限流控制的单位周期时长"
|
||||
:hint="t('site.hints.limitInterval')"
|
||||
persistent-hint
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="4">
|
||||
<VTextField
|
||||
v-model="siteForm.limit_count"
|
||||
label="周期内访问次数"
|
||||
:label="t('site.fields.limitCount')"
|
||||
:rules="[numberValidator]"
|
||||
hint="单位周期内允许的访问次数"
|
||||
:hint="t('site.hints.limitCount')"
|
||||
persistent-hint
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="4">
|
||||
<VTextField
|
||||
v-model="siteForm.limit_seconds"
|
||||
label="访问间隔(秒)"
|
||||
:label="t('site.fields.limitSeconds')"
|
||||
:rules="[numberValidator]"
|
||||
hint="每次访问需要间隔的最小时间"
|
||||
:hint="t('site.hints.limitSeconds')"
|
||||
persistent-hint
|
||||
/>
|
||||
</VCol>
|
||||
</VRow>
|
||||
<VRow>
|
||||
<VCol cols="12" md="6">
|
||||
<VSwitch v-model="siteForm.proxy" label="使用代理访问" hint="使用代理服务器访问该站点" persistent-hint />
|
||||
<VSwitch
|
||||
v-model="siteForm.proxy"
|
||||
:label="t('site.fields.useProxy')"
|
||||
:hint="t('site.hints.useProxy')"
|
||||
persistent-hint
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12" md="6">
|
||||
<VSwitch
|
||||
v-model="siteForm.render"
|
||||
label="浏览器仿真"
|
||||
hint="使用浏览器模拟真实访问该站点"
|
||||
:label="t('site.fields.browserSimulation')"
|
||||
:hint="t('site.hints.browserSimulation')"
|
||||
persistent-hint
|
||||
/>
|
||||
</VCol>
|
||||
@@ -324,7 +335,7 @@ onMounted(async () => {
|
||||
prepend-icon="mdi-plus"
|
||||
class="px-5"
|
||||
>
|
||||
新增
|
||||
{{ t('site.actions.add') }}
|
||||
</VBtn>
|
||||
<VBtn
|
||||
v-else
|
||||
@@ -334,7 +345,7 @@ onMounted(async () => {
|
||||
prepend-icon="mdi-content-save"
|
||||
class="px-5"
|
||||
>
|
||||
保存
|
||||
{{ t('common.save') }}
|
||||
</VBtn>
|
||||
</VCardActions>
|
||||
</VCard>
|
||||
|
||||
@@ -67,7 +67,7 @@ const renameLoading = ref(false)
|
||||
const progressDialog = ref(false)
|
||||
|
||||
// 识别进度文本
|
||||
const progressText = ref('请稍候 ...')
|
||||
const progressText = ref(t('common.pleaseWait'))
|
||||
|
||||
// 识别进度
|
||||
const progressValue = ref(0)
|
||||
@@ -162,8 +162,11 @@ async function list_files() {
|
||||
async function deleteItem(item: FileItem, confirm: boolean = true) {
|
||||
if (confirm) {
|
||||
const confirmed = await createConfirm({
|
||||
title: '确认',
|
||||
content: `是否确认删除${item.type === 'dir' ? '目录' : '文件'} ${item.name}?`,
|
||||
title: t('common.confirm'),
|
||||
content: t('file.confirmFileDelete', {
|
||||
type: item.type === 'dir' ? t('file.directory') : t('file.file'),
|
||||
name: item.name,
|
||||
}),
|
||||
})
|
||||
if (!confirmed) return
|
||||
}
|
||||
@@ -191,8 +194,8 @@ async function deleteItem(item: FileItem, confirm: boolean = true) {
|
||||
// 批量删除
|
||||
async function batchDelete() {
|
||||
const confirmed = await createConfirm({
|
||||
title: '确认',
|
||||
content: `是否确认删除选中的 ${selected.value.length} 个项目?`,
|
||||
title: t('common.confirm'),
|
||||
content: t('file.confirmBatchDelete', { count: selected.value.length }),
|
||||
})
|
||||
|
||||
if (!confirmed) return
|
||||
@@ -203,7 +206,7 @@ async function batchDelete() {
|
||||
|
||||
// 删除选中的项目
|
||||
selected.value.every(async item => {
|
||||
progressText.value = `正在删除 ${item.name} ...`
|
||||
progressText.value = t('file.deleting', { name: item.name })
|
||||
await deleteItem(item, false)
|
||||
})
|
||||
|
||||
@@ -322,9 +325,9 @@ async function rename() {
|
||||
progressDialog.value = true
|
||||
progressValue.value = 0
|
||||
if (renameAll.value) {
|
||||
progressText.value = `正在重命名 ${currentItem.value?.path} 及目录内所有文件 ...`
|
||||
progressText.value = t('file.renamingAll', { path: currentItem.value?.path })
|
||||
} else {
|
||||
progressText.value = `正在重命名 ${currentItem.value?.name} ...`
|
||||
progressText.value = t('file.renaming', { name: currentItem.value?.name })
|
||||
}
|
||||
if (renameAll.value) {
|
||||
startLoadingProgress()
|
||||
@@ -410,7 +413,7 @@ watch(
|
||||
// 重置菜单
|
||||
dropdownItems.value = [
|
||||
{
|
||||
title: '识别',
|
||||
title: t('file.recognize'),
|
||||
value: 1,
|
||||
show: true,
|
||||
props: {
|
||||
@@ -421,7 +424,7 @@ watch(
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '刮削',
|
||||
title: t('file.scrape'),
|
||||
value: 2,
|
||||
show: true,
|
||||
props: {
|
||||
@@ -432,7 +435,7 @@ watch(
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '重命名',
|
||||
title: t('file.rename'),
|
||||
value: 3,
|
||||
show: true,
|
||||
props: {
|
||||
@@ -441,7 +444,7 @@ watch(
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '整理',
|
||||
title: t('file.reorganize'),
|
||||
value: 4,
|
||||
show: true,
|
||||
props: {
|
||||
@@ -450,7 +453,7 @@ watch(
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '删除',
|
||||
title: t('common.delete'),
|
||||
value: 5,
|
||||
show: true,
|
||||
props: {
|
||||
@@ -470,7 +473,7 @@ async function recognize(path: string) {
|
||||
try {
|
||||
// 显示进度条
|
||||
progressDialog.value = true
|
||||
progressText.value = `正在识别 ${path} ...`
|
||||
progressText.value = t('file.recognizing', { path })
|
||||
progressValue.value = 0
|
||||
nameTestResult.value = await api.get('media/recognize_file', {
|
||||
params: {
|
||||
@@ -479,7 +482,7 @@ async function recognize(path: string) {
|
||||
})
|
||||
// 关闭进度条
|
||||
progressDialog.value = false
|
||||
if (!nameTestResult.value) $toast.error(`${path} 识别失败!`)
|
||||
if (!nameTestResult.value) $toast.error(t('file.recognizeFailed', { path }))
|
||||
nameTestDialog.value = !!nameTestResult.value?.meta_info?.name
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
@@ -492,22 +495,22 @@ async function scrape(item: FileItem, confirm: boolean = true) {
|
||||
if (confirm) {
|
||||
// 确认
|
||||
const confirmed = await createConfirm({
|
||||
title: '确认',
|
||||
content: `是否确认刮削 ${item.path}?`,
|
||||
title: t('common.confirm'),
|
||||
content: t('file.confirmScrape', { path: item.path }),
|
||||
})
|
||||
if (!confirmed) return
|
||||
}
|
||||
|
||||
// 显示进度条
|
||||
progressDialog.value = true
|
||||
progressText.value = `正在刮削 ${item.path} ...`
|
||||
progressText.value = t('file.scraping', { path: item.path })
|
||||
|
||||
const result: { [key: string]: any } = await api.post(`media/scrape/${inProps.storage}`, item)
|
||||
|
||||
// 关闭进度条
|
||||
progressDialog.value = false
|
||||
if (!result.success) $toast.error(result.message)
|
||||
else $toast.success(`${item.path} 削刮完成!`)
|
||||
else $toast.success(t('file.scrapeCompleted', { path: item.path }))
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
@@ -517,8 +520,8 @@ async function scrape(item: FileItem, confirm: boolean = true) {
|
||||
async function batchScrape() {
|
||||
// 确认
|
||||
const confirmed = await createConfirm({
|
||||
title: '确认',
|
||||
content: `是否确认刮削选中的 ${selected.value.length} 项?`,
|
||||
title: t('common.confirm'),
|
||||
content: t('file.confirmBatchScrape', { count: selected.value.length }),
|
||||
})
|
||||
if (!confirmed) return
|
||||
|
||||
@@ -529,7 +532,7 @@ async function batchScrape() {
|
||||
|
||||
// 使用SSE监听加载进度
|
||||
function startLoadingProgress() {
|
||||
progressText.value = '请稍候 ...'
|
||||
progressText.value = t('common.pleaseWait')
|
||||
progressEventSource.value = new EventSource(`${import.meta.env.VITE_API_BASE_URL}system/progress/batchrename`)
|
||||
progressEventSource.value.onmessage = event => {
|
||||
const progress = JSON.parse(event.data)
|
||||
@@ -564,7 +567,7 @@ onMounted(() => {
|
||||
flat
|
||||
density="compact"
|
||||
variant="plain"
|
||||
placeholder="搜索 ..."
|
||||
:placeholder="t('common.search')"
|
||||
prepend-inner-icon="mdi-filter-outline"
|
||||
class="mx-2"
|
||||
rounded
|
||||
@@ -610,8 +613,8 @@ onMounted(() => {
|
||||
</div>
|
||||
<div class="text-xl text-high-emphasis mt-3">{{ items[0]?.name }}</div>
|
||||
<p class="mt-2" v-if="items[0]?.size && items[0].modify_time">
|
||||
大小:{{ formatBytes(items[0]?.size || 0) }}<br />
|
||||
修改时间:{{ formatTime(items[0]?.modify_time || 0) }}
|
||||
{{ t('file.size') }}:{{ formatBytes(items[0]?.size || 0) }}<br />
|
||||
{{ t('file.modifyTime') }}:{{ formatTime(items[0]?.modify_time || 0) }}
|
||||
</p>
|
||||
</VCardText>
|
||||
<!-- 图片 -->
|
||||
@@ -685,9 +688,11 @@ onMounted(() => {
|
||||
</VList>
|
||||
</VCardText>
|
||||
<VCardText v-else-if="filter" class="grow d-flex justify-center align-center grey--text py-5">
|
||||
没有目录或文件
|
||||
{{ t('file.noFiles') }}
|
||||
</VCardText>
|
||||
<VCardText v-else-if="!loading" class="grow d-flex justify-center align-center grey--text py-5">
|
||||
{{ t('file.emptyDirectory') }}
|
||||
</VCardText>
|
||||
<VCardText v-else-if="!loading" class="grow d-flex justify-center align-center grey--text py-5"> 空目录 </VCardText>
|
||||
</VCard>
|
||||
<!-- 重命名弹窗 -->
|
||||
<VDialog v-if="renamePopper" v-model="renamePopper" max-width="35rem">
|
||||
|
||||
@@ -287,7 +287,7 @@ function getIndentLevel(path: string, ancestorPath: string) {
|
||||
<!-- 加载根目录 -->
|
||||
<div v-if="loading['/']" class="tree-loading">
|
||||
<VProgressCircular indeterminate size="24" color="primary" class="ma-2" />
|
||||
<span>加载目录结构...</span>
|
||||
<span>{{ t('file.loadingDirectoryStructure') }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 目录树结构 -->
|
||||
@@ -328,7 +328,7 @@ function getIndentLevel(path: string, ancestorPath: string) {
|
||||
<!-- 加载中状态 -->
|
||||
<div v-if="loading[directory.path || '']" class="tree-loading pl-8">
|
||||
<VProgressCircular indeterminate size="14" color="primary" class="ma-2" />
|
||||
<span class="text-caption">加载中...</span>
|
||||
<span class="text-caption">{{ t('common.loading') }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 所有层级的子目录列表 -->
|
||||
|
||||
Reference in New Issue
Block a user