更新国际化支持:将多个组件中的文本替换为国际化支持

This commit is contained in:
jxxghp
2025-04-28 16:25:45 +08:00
parent b24c29b217
commit 149403e5c0
7 changed files with 322 additions and 79 deletions
+53 -42
View File
@@ -5,6 +5,10 @@ import { doneNProgress, startNProgress } from '@/api/nprogress'
import { numberValidator, requiredValidator } from '@/@validators' import { numberValidator, requiredValidator } from '@/@validators'
import api from '@/api' import api from '@/api'
import { useDisplay } from 'vuetify' import { useDisplay } from 'vuetify'
import { useI18n } from 'vue-i18n'
// 国际化
const { t } = useI18n()
// 显示器宽度 // 显示器宽度
const display = useDisplay() const display = useDisplay()
@@ -45,8 +49,8 @@ const isLimit = ref(false)
// 状态下拉项 // 状态下拉项
const statusItems = [ const statusItems = [
{ title: '启用', value: true }, { title: t('site.status.enabled'), value: true },
{ title: '停用', value: false }, { title: t('site.status.disabled'), value: false },
] ]
// 生成1到50的优先级下拉框选项 // 生成1到50的优先级下拉框选项
@@ -64,14 +68,14 @@ async function loadDownloaderSetting() {
try { try {
const downloaders: DownloaderConf[] = await api.get('download/clients') const downloaders: DownloaderConf[] = await api.get('download/clients')
downloaderOptions.value = [ downloaderOptions.value = [
{ title: '默认', value: '' }, { title: t('common.default'), value: '' },
...downloaders.map((item: { name: any }) => ({ ...downloaders.map((item: { name: any }) => ({
title: item.name, title: item.name,
value: item.name, value: item.name,
})), })),
] ]
} catch (error) { } catch (error) {
console.error('加载下载器设置失败:', error) console.error(t('site.errors.loadDownloader'), error)
} }
} }
@@ -93,10 +97,10 @@ async function addSite() {
try { try {
const result: { [key: string]: string } = await api.post('site/', siteForm.value) const result: { [key: string]: string } = await api.post('site/', siteForm.value)
if (result.success) { if (result.success) {
$toast.success('新增站点成功') $toast.success(t('site.messages.addSuccess'))
emit('save') emit('save')
} else { } else {
$toast.error(`新增站点失败${result.message}`) $toast.error(`${t('site.messages.addFailed')}${result.message}`)
} }
} catch (error) { } catch (error) {
console.error(error) console.error(error)
@@ -119,13 +123,13 @@ async function updateSiteInfo() {
} }
const result: { [key: string]: any } = await api.put('site/', siteForm.value) const result: { [key: string]: any } = await api.put('site/', siteForm.value)
if (result.success) { if (result.success) {
$toast.success(`${siteForm.value?.name} 更新成功!`) $toast.success(`${siteForm.value?.name} ${t('site.messages.updateSuccess')}`)
emit('save') emit('save')
} else { } else {
$toast.error(`${siteForm.value?.name} 更新失败${result.message}`) $toast.error(`${siteForm.value?.name} ${t('site.messages.updateFailed')}${result.message}`)
} }
} catch (error) { } catch (error) {
$toast.error(`${siteForm.value?.name} 更新失败`) $toast.error(`${siteForm.value?.name} ${t('site.messages.updateFailed')}`)
console.error(error) console.error(error)
} }
doneNProgress() doneNProgress()
@@ -145,7 +149,9 @@ onMounted(async () => {
<template> <template>
<VDialog scrollable :close-on-back="false" eager max-width="45rem" :fullscreen="!display.mdAndUp.value"> <VDialog scrollable :close-on-back="false" eager max-width="45rem" :fullscreen="!display.mdAndUp.value">
<VCard <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" class="rounded-t"
> >
<VDialogCloseBtn @click="emit('close')" /> <VDialogCloseBtn @click="emit('close')" />
@@ -156,19 +162,19 @@ onMounted(async () => {
<VCol cols="12" md="6"> <VCol cols="12" md="6">
<VTextField <VTextField
v-model="siteForm.url" v-model="siteForm.url"
label="站点地址" :label="t('site.fields.url')"
:rules="[requiredValidator]" :rules="[requiredValidator]"
hint="格式:http://www.example.com/" :hint="t('site.hints.url')"
persistent-hint persistent-hint
/> />
</VCol> </VCol>
<VCol cols="6" md="3"> <VCol cols="6" md="3">
<VSelect <VSelect
v-model="siteForm.pri" v-model="siteForm.pri"
label="优先级" :label="t('site.fields.priority')"
:items="priorityItems" :items="priorityItems"
:rules="[requiredValidator]" :rules="[requiredValidator]"
hint="优先级越小越优先" :hint="t('site.hints.priority')"
persistent-hint persistent-hint
/> />
</VCol> </VCol>
@@ -176,8 +182,8 @@ onMounted(async () => {
<VSelect <VSelect
v-model="siteForm.is_active" v-model="siteForm.is_active"
:items="statusItems" :items="statusItems"
label="状态" :label="t('site.fields.status')"
hint="站点启用/停用" :hint="t('site.hints.status')"
persistent-hint persistent-hint
/> />
</VCol> </VCol>
@@ -186,25 +192,25 @@ onMounted(async () => {
<VCol cols="12" md="6"> <VCol cols="12" md="6">
<VTextField <VTextField
v-model="siteForm.rss" v-model="siteForm.rss"
label="RSS地址" :label="t('site.fields.rss')"
hint="订阅模式为`站点RSS`时使用的订阅链接,如未自动获取需手动补充" :hint="t('site.hints.rss')"
persistent-hint persistent-hint
/> />
</VCol> </VCol>
<VCol cols="12" md="3"> <VCol cols="12" md="3">
<VTextField <VTextField
v-model="siteForm.timeout" v-model="siteForm.timeout"
label="超时时间(秒)" :label="t('site.fields.timeout')"
hint="站点请求超时时间,为0时不限制" :hint="t('site.hints.timeout')"
persistent-hint persistent-hint
/> />
</VCol> </VCol>
<VCol cols="6" md="3"> <VCol cols="6" md="3">
<VSelect <VSelect
v-model="siteForm.downloader" v-model="siteForm.downloader"
label="下载器" :label="t('site.fields.downloader')"
:items="downloaderOptions" :items="downloaderOptions"
hint="此站点使用的下载器" :hint="t('site.hints.downloader')"
persistent-hint persistent-hint
/> />
</VCol> </VCol>
@@ -229,16 +235,16 @@ onMounted(async () => {
<VCol cols="12"> <VCol cols="12">
<VTextarea <VTextarea
v-model="siteForm.cookie" v-model="siteForm.cookie"
label="站点Cookie" :label="t('site.fields.cookie')"
hint="站点请求头中的Cookie信息" :hint="t('site.hints.cookie')"
persistent-hint persistent-hint
/> />
</VCol> </VCol>
<VCol cols="12"> <VCol cols="12">
<VTextField <VTextField
v-model="siteForm.ua" v-model="siteForm.ua"
label="站点User-Agent" :label="t('site.fields.userAgent')"
hint="获取Cookie的浏览器对应的User-Agent" :hint="t('site.hints.userAgent')"
persistent-hint persistent-hint
/> />
</VCol> </VCol>
@@ -249,16 +255,16 @@ onMounted(async () => {
<VCol cols="12" md="6"> <VCol cols="12" md="6">
<VTextField <VTextField
v-model="siteForm.token" v-model="siteForm.token"
label="请求头(Authorization" :label="t('site.fields.authorization')"
hint="站点请求头中的Authorization信息,特殊站点需要" :hint="t('site.hints.authorization')"
persistent-hint persistent-hint
/> />
</VCol> </VCol>
<VCol cols="12" md="6"> <VCol cols="12" md="6">
<VTextField <VTextField
v-model="siteForm.apikey" v-model="siteForm.apikey"
label="令牌(API Key" :label="t('site.fields.apiKey')"
hint="站点的访问API Key,特殊站点需要" :hint="t('site.hints.apiKey')"
persistent-hint persistent-hint
/> />
</VCol> </VCol>
@@ -267,47 +273,52 @@ onMounted(async () => {
</VWindow> </VWindow>
<VRow> <VRow>
<VCol cols="12" md="4"> <VCol cols="12" md="4">
<VSwitch v-model="isLimit" label="限制站点访问频率" /> <VSwitch v-model="isLimit" :label="t('site.fields.limitAccess')" />
</VCol> </VCol>
</VRow> </VRow>
<VRow v-if="isLimit"> <VRow v-if="isLimit">
<VCol cols="12" md="4"> <VCol cols="12" md="4">
<VTextField <VTextField
v-model="siteForm.limit_interval" v-model="siteForm.limit_interval"
label="单位周期(秒)" :label="t('site.fields.limitInterval')"
:rules="[numberValidator]" :rules="[numberValidator]"
hint="限流控制的单位周期时长" :hint="t('site.hints.limitInterval')"
persistent-hint persistent-hint
/> />
</VCol> </VCol>
<VCol cols="12" md="4"> <VCol cols="12" md="4">
<VTextField <VTextField
v-model="siteForm.limit_count" v-model="siteForm.limit_count"
label="周期内访问次数" :label="t('site.fields.limitCount')"
:rules="[numberValidator]" :rules="[numberValidator]"
hint="单位周期内允许的访问次数" :hint="t('site.hints.limitCount')"
persistent-hint persistent-hint
/> />
</VCol> </VCol>
<VCol cols="12" md="4"> <VCol cols="12" md="4">
<VTextField <VTextField
v-model="siteForm.limit_seconds" v-model="siteForm.limit_seconds"
label="访问间隔(秒)" :label="t('site.fields.limitSeconds')"
:rules="[numberValidator]" :rules="[numberValidator]"
hint="每次访问需要间隔的最小时间" :hint="t('site.hints.limitSeconds')"
persistent-hint persistent-hint
/> />
</VCol> </VCol>
</VRow> </VRow>
<VRow> <VRow>
<VCol cols="12" md="6"> <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>
<VCol cols="12" md="6"> <VCol cols="12" md="6">
<VSwitch <VSwitch
v-model="siteForm.render" v-model="siteForm.render"
label="浏览器仿真" :label="t('site.fields.browserSimulation')"
hint="使用浏览器模拟真实访问该站点" :hint="t('site.hints.browserSimulation')"
persistent-hint persistent-hint
/> />
</VCol> </VCol>
@@ -324,7 +335,7 @@ onMounted(async () => {
prepend-icon="mdi-plus" prepend-icon="mdi-plus"
class="px-5" class="px-5"
> >
新增 {{ t('site.actions.add') }}
</VBtn> </VBtn>
<VBtn <VBtn
v-else v-else
@@ -334,7 +345,7 @@ onMounted(async () => {
prepend-icon="mdi-content-save" prepend-icon="mdi-content-save"
class="px-5" class="px-5"
> >
保存 {{ t('common.save') }}
</VBtn> </VBtn>
</VCardActions> </VCardActions>
</VCard> </VCard>
+32 -27
View File
@@ -67,7 +67,7 @@ const renameLoading = ref(false)
const progressDialog = ref(false) const progressDialog = ref(false)
// 识别进度文本 // 识别进度文本
const progressText = ref('请稍候 ...') const progressText = ref(t('common.pleaseWait'))
// 识别进度 // 识别进度
const progressValue = ref(0) const progressValue = ref(0)
@@ -162,8 +162,11 @@ async function list_files() {
async function deleteItem(item: FileItem, confirm: boolean = true) { async function deleteItem(item: FileItem, confirm: boolean = true) {
if (confirm) { if (confirm) {
const confirmed = await createConfirm({ const confirmed = await createConfirm({
title: '确认', title: t('common.confirm'),
content: `是否确认删除${item.type === 'dir' ? '目录' : '文件'} ${item.name}`, content: t('file.confirmFileDelete', {
type: item.type === 'dir' ? t('file.directory') : t('file.file'),
name: item.name,
}),
}) })
if (!confirmed) return if (!confirmed) return
} }
@@ -191,8 +194,8 @@ async function deleteItem(item: FileItem, confirm: boolean = true) {
// 批量删除 // 批量删除
async function batchDelete() { async function batchDelete() {
const confirmed = await createConfirm({ const confirmed = await createConfirm({
title: '确认', title: t('common.confirm'),
content: `是否确认删除选中的 ${selected.value.length} 个项目?`, content: t('file.confirmBatchDelete', { count: selected.value.length }),
}) })
if (!confirmed) return if (!confirmed) return
@@ -203,7 +206,7 @@ async function batchDelete() {
// 删除选中的项目 // 删除选中的项目
selected.value.every(async item => { selected.value.every(async item => {
progressText.value = `正在删除 ${item.name} ...` progressText.value = t('file.deleting', { name: item.name })
await deleteItem(item, false) await deleteItem(item, false)
}) })
@@ -322,9 +325,9 @@ async function rename() {
progressDialog.value = true progressDialog.value = true
progressValue.value = 0 progressValue.value = 0
if (renameAll.value) { if (renameAll.value) {
progressText.value = `正在重命名 ${currentItem.value?.path} 及目录内所有文件 ...` progressText.value = t('file.renamingAll', { path: currentItem.value?.path })
} else { } else {
progressText.value = `正在重命名 ${currentItem.value?.name} ...` progressText.value = t('file.renaming', { name: currentItem.value?.name })
} }
if (renameAll.value) { if (renameAll.value) {
startLoadingProgress() startLoadingProgress()
@@ -410,7 +413,7 @@ watch(
// 重置菜单 // 重置菜单
dropdownItems.value = [ dropdownItems.value = [
{ {
title: '识别', title: t('file.recognize'),
value: 1, value: 1,
show: true, show: true,
props: { props: {
@@ -421,7 +424,7 @@ watch(
}, },
}, },
{ {
title: '刮削', title: t('file.scrape'),
value: 2, value: 2,
show: true, show: true,
props: { props: {
@@ -432,7 +435,7 @@ watch(
}, },
}, },
{ {
title: '重命名', title: t('file.rename'),
value: 3, value: 3,
show: true, show: true,
props: { props: {
@@ -441,7 +444,7 @@ watch(
}, },
}, },
{ {
title: '整理', title: t('file.reorganize'),
value: 4, value: 4,
show: true, show: true,
props: { props: {
@@ -450,7 +453,7 @@ watch(
}, },
}, },
{ {
title: '删除', title: t('common.delete'),
value: 5, value: 5,
show: true, show: true,
props: { props: {
@@ -470,7 +473,7 @@ async function recognize(path: string) {
try { try {
// 显示进度条 // 显示进度条
progressDialog.value = true progressDialog.value = true
progressText.value = `正在识别 ${path} ...` progressText.value = t('file.recognizing', { path })
progressValue.value = 0 progressValue.value = 0
nameTestResult.value = await api.get('media/recognize_file', { nameTestResult.value = await api.get('media/recognize_file', {
params: { params: {
@@ -479,7 +482,7 @@ async function recognize(path: string) {
}) })
// 关闭进度条 // 关闭进度条
progressDialog.value = false 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 nameTestDialog.value = !!nameTestResult.value?.meta_info?.name
} catch (error) { } catch (error) {
console.error(error) console.error(error)
@@ -492,22 +495,22 @@ async function scrape(item: FileItem, confirm: boolean = true) {
if (confirm) { if (confirm) {
// 确认 // 确认
const confirmed = await createConfirm({ const confirmed = await createConfirm({
title: '确认', title: t('common.confirm'),
content: `是否确认刮削 ${item.path}`, content: t('file.confirmScrape', { path: item.path }),
}) })
if (!confirmed) return if (!confirmed) return
} }
// 显示进度条 // 显示进度条
progressDialog.value = true 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) const result: { [key: string]: any } = await api.post(`media/scrape/${inProps.storage}`, item)
// 关闭进度条 // 关闭进度条
progressDialog.value = false progressDialog.value = false
if (!result.success) $toast.error(result.message) if (!result.success) $toast.error(result.message)
else $toast.success(`${item.path} 削刮完成!`) else $toast.success(t('file.scrapeCompleted', { path: item.path }))
} catch (error) { } catch (error) {
console.error(error) console.error(error)
} }
@@ -517,8 +520,8 @@ async function scrape(item: FileItem, confirm: boolean = true) {
async function batchScrape() { async function batchScrape() {
// 确认 // 确认
const confirmed = await createConfirm({ const confirmed = await createConfirm({
title: '确认', title: t('common.confirm'),
content: `是否确认刮削选中的 ${selected.value.length} 项?`, content: t('file.confirmBatchScrape', { count: selected.value.length }),
}) })
if (!confirmed) return if (!confirmed) return
@@ -529,7 +532,7 @@ async function batchScrape() {
// 使用SSE监听加载进度 // 使用SSE监听加载进度
function startLoadingProgress() { 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 = new EventSource(`${import.meta.env.VITE_API_BASE_URL}system/progress/batchrename`)
progressEventSource.value.onmessage = event => { progressEventSource.value.onmessage = event => {
const progress = JSON.parse(event.data) const progress = JSON.parse(event.data)
@@ -564,7 +567,7 @@ onMounted(() => {
flat flat
density="compact" density="compact"
variant="plain" variant="plain"
placeholder="搜索 ..." :placeholder="t('common.search')"
prepend-inner-icon="mdi-filter-outline" prepend-inner-icon="mdi-filter-outline"
class="mx-2" class="mx-2"
rounded rounded
@@ -610,8 +613,8 @@ onMounted(() => {
</div> </div>
<div class="text-xl text-high-emphasis mt-3">{{ items[0]?.name }}</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"> <p class="mt-2" v-if="items[0]?.size && items[0].modify_time">
大小{{ formatBytes(items[0]?.size || 0) }}<br /> {{ t('file.size') }}{{ formatBytes(items[0]?.size || 0) }}<br />
修改时间{{ formatTime(items[0]?.modify_time || 0) }} {{ t('file.modifyTime') }}{{ formatTime(items[0]?.modify_time || 0) }}
</p> </p>
</VCardText> </VCardText>
<!-- 图片 --> <!-- 图片 -->
@@ -685,9 +688,11 @@ onMounted(() => {
</VList> </VList>
</VCardText> </VCardText>
<VCardText v-else-if="filter" class="grow d-flex justify-center align-center grey--text py-5"> <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>
<VCardText v-else-if="!loading" class="grow d-flex justify-center align-center grey--text py-5"> 空目录 </VCardText>
</VCard> </VCard>
<!-- 重命名弹窗 --> <!-- 重命名弹窗 -->
<VDialog v-if="renamePopper" v-model="renamePopper" max-width="35rem"> <VDialog v-if="renamePopper" v-model="renamePopper" max-width="35rem">
+2 -2
View File
@@ -287,7 +287,7 @@ function getIndentLevel(path: string, ancestorPath: string) {
<!-- 加载根目录 --> <!-- 加载根目录 -->
<div v-if="loading['/']" class="tree-loading"> <div v-if="loading['/']" class="tree-loading">
<VProgressCircular indeterminate size="24" color="primary" class="ma-2" /> <VProgressCircular indeterminate size="24" color="primary" class="ma-2" />
<span>加载目录结构...</span> <span>{{ t('file.loadingDirectoryStructure') }}</span>
</div> </div>
<!-- 目录树结构 --> <!-- 目录树结构 -->
@@ -328,7 +328,7 @@ function getIndentLevel(path: string, ancestorPath: string) {
<!-- 加载中状态 --> <!-- 加载中状态 -->
<div v-if="loading[directory.path || '']" class="tree-loading pl-8"> <div v-if="loading[directory.path || '']" class="tree-loading pl-8">
<VProgressCircular indeterminate size="14" color="primary" class="ma-2" /> <VProgressCircular indeterminate size="14" color="primary" class="ma-2" />
<span class="text-caption">加载中...</span> <span class="text-caption">{{ t('common.loading') }}</span>
</div> </div>
<!-- 所有层级的子目录列表 --> <!-- 所有层级的子目录列表 -->
+80 -4
View File
@@ -23,6 +23,7 @@ export default {
reset: 'Reset', reset: 'Reset',
theme: 'Theme', theme: 'Theme',
language: 'Language', language: 'Language',
pleaseWait: 'Please wait...',
}, },
mediaType: { mediaType: {
movie: 'Movie', movie: 'Movie',
@@ -357,7 +358,60 @@ export default {
}, },
site: { site: {
noSites: 'No Sites', noSites: 'No Sites',
sitesWillBeShownHere: 'Added and supported sites will be shown here.', sitesWillBeShownHere: 'Added and supported sites will be displayed here.',
title: 'Site',
status: {
enabled: 'Enabled',
disabled: 'Disabled',
},
fields: {
url: 'Site URL',
priority: 'Priority',
status: 'Status',
rss: 'RSS URL',
timeout: 'Timeout (seconds)',
downloader: 'Downloader',
cookie: 'Site Cookie',
userAgent: 'User-Agent',
authorization: 'Authorization Header',
apiKey: 'API Key',
limitAccess: 'Limit Site Access Frequency',
limitInterval: 'Interval Period (seconds)',
limitCount: 'Access Count per Period',
limitSeconds: 'Access Interval (seconds)',
useProxy: 'Use Proxy',
browserSimulation: 'Browser Simulation',
},
hints: {
url: 'Format: http://www.example.com/',
priority: 'Lower priority value means higher priority',
status: 'Enable/Disable site',
rss: 'Subscription link used when subscription mode is `Site RSS`, manual input if not auto-retrieved',
timeout: 'Site request timeout, no limit when set to 0',
downloader: 'Downloader used for this site',
cookie: 'Cookie information in site request header',
userAgent: 'User-Agent of the browser used to get Cookie',
authorization: 'Authorization information in site request header, required for special sites',
apiKey: 'Site API Key, required for special sites',
limitInterval: 'Duration of the rate limit control period',
limitCount: 'Allowed access count within the period',
limitSeconds: 'Minimum interval between each access',
useProxy: 'Use proxy server to access this site',
browserSimulation: 'Use browser simulation for authentic site access',
},
actions: {
add: 'Add',
edit: 'Edit',
},
messages: {
addSuccess: 'Site added successfully',
addFailed: 'Failed to add site',
updateSuccess: 'Updated successfully',
updateFailed: 'Update failed',
},
errors: {
loadDownloader: 'Failed to load downloader settings',
},
}, },
message: { message: {
loadMore: 'Load More', loadMore: 'Load More',
@@ -1317,20 +1371,20 @@ export default {
file: { file: {
newFolder: 'New Folder', newFolder: 'New Folder',
createFolder: 'Create Folder', createFolder: 'Create Folder',
fileName: 'Filename', fileName: 'File Name',
fileSize: 'File Size', fileSize: 'File Size',
fileType: 'File Type', fileType: 'File Type',
lastModified: 'Last Modified', lastModified: 'Last Modified',
actions: 'Actions', actions: 'Actions',
rename: 'Rename', rename: 'Rename',
delete: 'Delete', delete: 'Delete',
confirmDelete: 'Confirm Delete', confirmFileDelete: 'Confirm Delete',
upload: 'Upload', upload: 'Upload',
download: 'Download', download: 'Download',
preview: 'Preview', preview: 'Preview',
selectAll: 'Select All', selectAll: 'Select All',
deselectAll: 'Deselect All', deselectAll: 'Deselect All',
moveUp: 'Go Up', moveUp: 'Go Back',
sortByName: 'Sort by Name', sortByName: 'Sort by Name',
sortByTime: 'Sort by Time', sortByTime: 'Sort by Time',
currentName: 'Current Name', currentName: 'Current Name',
@@ -1342,6 +1396,28 @@ export default {
directoryTree: 'Directory Tree', directoryTree: 'Directory Tree',
rootDirectory: 'Root Directory', rootDirectory: 'Root Directory',
noDirectories: 'No directories available', noDirectories: 'No directories available',
directory: 'Directory',
file: 'File',
size: 'Size',
modifyTime: 'Modify Time',
noFiles: 'No directories or files',
emptyDirectory: 'Empty directory',
confirmDelete: 'Are you sure you want to delete {type} {name}?',
confirmBatchDelete: 'Are you sure you want to delete {count} selected items?',
deleting: 'Deleting {name}...',
recognize: 'Recognize',
recognizing: 'Recognizing {path}...',
recognizeFailed: '{path} recognition failed!',
scrape: 'Scrape',
scraping: 'Scraping {path}...',
scrapeCompleted: '{path} scraping completed!',
confirmScrape: 'Are you sure you want to scrape {path}?',
confirmBatchScrape: 'Are you sure you want to scrape {count} selected items?',
renaming: 'Renaming {name}...',
renamingAll: 'Renaming {path} and all files in the directory...',
close: 'Close',
loadingDirectoryStructure: 'Loading directory structure...',
reorganize: 'Reorganize',
}, },
person: { person: {
alias: 'Also Known As:', alias: 'Also Known As:',
+76 -1
View File
@@ -23,6 +23,7 @@ export default {
reset: '重置', reset: '重置',
theme: '主题', theme: '主题',
language: '语言', language: '语言',
pleaseWait: '请稍候...',
}, },
mediaType: { mediaType: {
movie: '电影', movie: '电影',
@@ -358,6 +359,59 @@ export default {
site: { site: {
noSites: '没有站点', noSites: '没有站点',
sitesWillBeShownHere: '已添加并支持的站点将会在这里显示。', sitesWillBeShownHere: '已添加并支持的站点将会在这里显示。',
title: '站点',
status: {
enabled: '启用',
disabled: '停用',
},
fields: {
url: '站点地址',
priority: '优先级',
status: '状态',
rss: 'RSS地址',
timeout: '超时时间(秒)',
downloader: '下载器',
cookie: '站点Cookie',
userAgent: '站点User-Agent',
authorization: '请求头(Authorization',
apiKey: '令牌(API Key',
limitAccess: '限制站点访问频率',
limitInterval: '单位周期(秒)',
limitCount: '周期内访问次数',
limitSeconds: '访问间隔(秒)',
useProxy: '使用代理访问',
browserSimulation: '浏览器仿真',
},
hints: {
url: '格式:http://www.example.com/',
priority: '优先级越小越优先',
status: '站点启用/停用',
rss: '订阅模式为`站点RSS`时使用的订阅链接,如未自动获取需手动补充',
timeout: '站点请求超时时间,为0时不限制',
downloader: '此站点使用的下载器',
cookie: '站点请求头中的Cookie信息',
userAgent: '获取Cookie的浏览器对应的User-Agent',
authorization: '站点请求头中的Authorization信息,特殊站点需要',
apiKey: '站点的访问API Key,特殊站点需要',
limitInterval: '限流控制的单位周期时长',
limitCount: '单位周期内允许的访问次数',
limitSeconds: '每次访问需要间隔的最小时间',
useProxy: '使用代理服务器访问该站点',
browserSimulation: '使用浏览器模拟真实访问该站点',
},
actions: {
add: '新增',
edit: '编辑',
},
messages: {
addSuccess: '新增站点成功',
addFailed: '新增站点失败',
updateSuccess: '更新成功',
updateFailed: '更新失败',
},
errors: {
loadDownloader: '加载下载器设置失败',
},
}, },
message: { message: {
loadMore: '加载更多', loadMore: '加载更多',
@@ -1304,7 +1358,7 @@ export default {
actions: '操作', actions: '操作',
rename: '重命名', rename: '重命名',
delete: '删除', delete: '删除',
confirmDelete: '确认删除', confirmFileDelete: '确认删除',
upload: '上传', upload: '上传',
download: '下载', download: '下载',
preview: '预览', preview: '预览',
@@ -1322,6 +1376,27 @@ export default {
directoryTree: '目录树', directoryTree: '目录树',
rootDirectory: '根目录', rootDirectory: '根目录',
noDirectories: '没有可用的目录', noDirectories: '没有可用的目录',
directory: '目录',
file: '文件',
size: '大小',
modifyTime: '修改时间',
noFiles: '没有目录或文件',
emptyDirectory: '空目录',
confirmDelete: '是否确认删除{type} {name}',
confirmBatchDelete: '是否确认删除选中的 {count} 个项目?',
deleting: '正在删除 {name}...',
recognize: '识别',
recognizing: '正在识别 {path}...',
recognizeFailed: '{path} 识别失败!',
scrape: '刮削',
scraping: '正在刮削 {path}...',
scrapeCompleted: '{path} 削刮完成!',
confirmScrape: '是否确认刮削 {path}',
confirmBatchScrape: '是否确认刮削选中的 {count} 项?',
renaming: '正在重命名 {name}...',
renamingAll: '正在重命名 {path} 及目录内所有文件...',
close: '关闭',
loadingDirectoryStructure: '加载目录结构...',
}, },
person: { person: {
alias: '别名:', alias: '别名:',
+77 -1
View File
@@ -23,6 +23,7 @@ export default {
reset: '重置', reset: '重置',
theme: '主題', theme: '主題',
language: '語言', language: '語言',
pleaseWait: '請稍候...',
}, },
mediaType: { mediaType: {
movie: '電影', movie: '電影',
@@ -358,6 +359,59 @@ export default {
site: { site: {
noSites: '沒有站點', noSites: '沒有站點',
sitesWillBeShownHere: '已添加並支持的站點將會在這裡顯示。', sitesWillBeShownHere: '已添加並支持的站點將會在這裡顯示。',
title: '站點',
status: {
enabled: '啟用',
disabled: '停用',
},
fields: {
url: '站點地址',
priority: '優先級',
status: '狀態',
rss: 'RSS地址',
timeout: '超時時間(秒)',
downloader: '下載器',
cookie: '站點Cookie',
userAgent: '站點User-Agent',
authorization: '請求頭(Authorization',
apiKey: '令牌(API Key',
limitAccess: '限制站點訪問頻率',
limitInterval: '單位週期(秒)',
limitCount: '週期內訪問次數',
limitSeconds: '訪問間隔(秒)',
useProxy: '使用代理訪問',
browserSimulation: '瀏覽器仿真',
},
hints: {
url: '格式:http://www.example.com/',
priority: '優先級越小越優先',
status: '站點啟用/停用',
rss: '訂閱模式為`站點RSS`時使用的訂閱鏈接,如未自動獲取需手動補充',
timeout: '站點請求超時時間,為0時不限制',
downloader: '此站點使用的下載器',
cookie: '站點請求頭中的Cookie信息',
userAgent: '獲取Cookie的瀏覽器對應的User-Agent',
authorization: '站點請求頭中的Authorization信息,特殊站點需要',
apiKey: '站點的訪問API Key,特殊站點需要',
limitInterval: '限流控制的單位週期時長',
limitCount: '單位週期內允許的訪問次數',
limitSeconds: '每次訪問需要間隔的最小時間',
useProxy: '使用代理服務器訪問該站點',
browserSimulation: '使用瀏覽器模擬真實訪問該站點',
},
actions: {
add: '新增',
edit: '編輯',
},
messages: {
addSuccess: '新增站點成功',
addFailed: '新增站點失敗',
updateSuccess: '更新成功',
updateFailed: '更新失敗',
},
errors: {
loadDownloader: '加載下載器設置失敗',
},
}, },
message: { message: {
loadMore: '加載更多', loadMore: '加載更多',
@@ -1304,7 +1358,7 @@ export default {
actions: '操作', actions: '操作',
rename: '重命名', rename: '重命名',
delete: '刪除', delete: '刪除',
confirmDelete: '確認刪除', confirmFileDelete: '確認刪除',
upload: '上傳', upload: '上傳',
download: '下載', download: '下載',
preview: '預覽', preview: '預覽',
@@ -1322,6 +1376,28 @@ export default {
directoryTree: '目錄樹', directoryTree: '目錄樹',
rootDirectory: '根目錄', rootDirectory: '根目錄',
noDirectories: '沒有可用的目錄', noDirectories: '沒有可用的目錄',
directory: '目錄',
file: '文件',
size: '大小',
modifyTime: '修改時間',
noFiles: '沒有目錄或文件',
emptyDirectory: '空目錄',
confirmDelete: '是否確認刪除{type} {name}',
confirmBatchDelete: '是否確認刪除選中的 {count} 個項目?',
deleting: '正在刪除 {name}...',
recognize: '識別',
recognizing: '正在識別 {path}...',
recognizeFailed: '{path} 識別失敗!',
scrape: '刮削',
scraping: '正在刮削 {path}...',
scrapeCompleted: '{path} 削刮完成!',
confirmScrape: '是否確認刮削 {path}',
confirmBatchScrape: '是否確認刮削選中的 {count} 項?',
renaming: '正在重命名 {name}...',
renamingAll: '正在重命名 {path} 及目錄內所有文件...',
close: '關閉',
loadingDirectoryStructure: '加載目錄結構...',
reorganize: '整理',
}, },
person: { person: {
alias: '別名:', alias: '別名:',
+2 -2
View File
@@ -114,8 +114,8 @@ initializeApp().then(() => {
color: 'secondary', color: 'secondary',
class: 'me-3', class: 'me-3',
}, },
confirmationText: '确认', confirmationText: i18n.global.t('common.confirm'),
cancellationText: '取消', cancellationText: i18n.global.t('common.cancel'),
}, },
}) })
.use(i18n) .use(i18n)