refactor(front): update localization keys across components to improve consistency and maintainability

This commit is contained in:
keven1024
2025-12-20 09:22:58 +08:00
parent 85c6b4582f
commit ca33fcc332
16 changed files with 392 additions and 370 deletions

View File

@@ -52,14 +52,14 @@ const genUserAvatar = (email: string) => {
<div class="flex flex-col gap-2 items-center">
<div class="text-xl">{{ renderI18n(appConfig?.site_title ?? {}, 'en', locale) }}</div>
<div class="text-sm opacity-75 text-center px-5">
<I18nT keypath="about.powerBy" tag="span">
<I18nT keypath="page.about.powerBy" tag="span">
<NuxtLink href="https://github.com/keven1024/015" target="_blank" class="text-primary hover:underline">015</NuxtLink>
</I18nT>
</div>
</div>
</template>
<div class="font-semibold">{{ t('about.systemInfo') }}</div>
<div class="font-semibold">{{ t('page.about.systemInfo') }}</div>
<template v-if="isLoading">
<div class="flex flex-row gap-2">
<Skeleton class="w-full h-20 rounded-xl" v-for="i in 2" :key="i" />
@@ -68,7 +68,7 @@ const genUserAvatar = (email: string) => {
<template v-else>
<div class="grid grid-cols-1 md:grid-cols-2 gap-2">
<div class="rounded-xl bg-white/50 flex-1 flex flex-col p-3 gap-2">
<div class="opacity-75 text-xs">{{ t('about.admin') }}</div>
<div class="opacity-75 text-xs">{{ t('page.about.admin') }}</div>
<div
class="flex flex-row gap-2 items-center cursor-pointer"
@click="
@@ -98,7 +98,7 @@ const genUserAvatar = (email: string) => {
</div>
</div>
<div class="rounded-xl bg-white/50 flex-1 flex flex-col p-3 gap-2">
<div class="opacity-75 text-xs">{{ t('about.storage') }}</div>
<div class="opacity-75 text-xs">{{ t('page.about.storage') }}</div>
<div class="text-right flex flex-row items-baseline">
<span class="text-lg font-semibold">{{ getFileSize(data?.file?.current ?? 0) }}</span>
<span class="text-md opacity-75">/ {{ getFileSize(data?.file?.maximun ?? 0) }}</span>
@@ -115,7 +115,7 @@ const genUserAvatar = (email: string) => {
<Accordion type="single" collapsible>
<AccordionItem value="about">
<AccordionTrigger>
<span class="font-semibold">{{ t('about.about') }}</span>
<span class="font-semibold">{{ t('page.about.about') }}</span>
</AccordionTrigger>
<AccordionContent>
<MarkdownRender class="max-w-full" :markdown="renderI18n(data?.content ?? {}, 'en', locale) ?? ''" />

View File

@@ -51,28 +51,28 @@ const { t } = useI18n()
const chartTabs = computed(() => {
return [
{
label: t('about.file'),
label: t('page.about.file'),
value: 'storage',
total: data.value?.chart?.storage
? Object.values(data.value.chart.storage).reduce((acc: number, curr: StatChartData) => acc + curr.file_num, 0)
: 0,
},
{
label: t('about.share'),
label: t('page.about.share'),
value: 'share',
total: data.value?.chart?.storage
? Object.values(data.value.chart.storage).reduce((acc: number, curr: StatChartData) => acc + curr.share_num, 0)
: 0,
},
{
label: t('about.download'),
label: t('page.about.download'),
value: 'download',
total: data.value?.chart?.storage
? Object.values(data.value.chart.storage).reduce((acc: number, curr: StatChartData) => acc + curr.download_num, 0)
: 0,
},
{
label: t('about.task'),
label: t('page.about.task'),
value: 'queue',
total: data.value?.chart?.queue
? Object.values(data.value.chart.queue).reduce((acc: number, curr: QueueChartData) => acc + curr.processed + curr.failed, 0)
@@ -144,7 +144,7 @@ const currentChartData = computed((): ChartConfig => {
</script>
<template>
<div class="font-semibold">{{ t('about.analysis') }}</div>
<div class="font-semibold">{{ t('page.about.analysis') }}</div>
<template v-if="isLoading">
<div class="flex flex-row gap-2">
<Skeleton class="w-full h-96 rounded-xl" />

View File

@@ -35,7 +35,7 @@ const isPPT = computed(() => props.file.every((r) => r?.type?.startsWith('applic
const isDocument = computed(() => isPDF.value || isDOC.value || isXLS.value || isPPT.value)
const actions = [
{
label: t('file.handleType.file-share'),
label: t('page.upload.file.handleType.file-share'),
icon: LucideShare,
className: 'bg-green-300',
onClick: () => {
@@ -45,7 +45,7 @@ const actions = [
},
},
isImage.value && {
label: t('file.handleType.file-image-compress'),
label: t('page.upload.file.handleType.file-image-compress'),
icon: LucideImageMinus,
className: 'bg-red-300',
onClick: () => {

View File

@@ -18,7 +18,7 @@ const handleSubmit = async (form: FormContext<GenericObject, GenericObject>) =>
}
}>(`/api/share/pickup/${code}`)
if (!data.data.share_id) {
toast.error(t('pickup.codeError'))
toast.error(t('page.upload.pickup.codeError'))
form.resetForm()
return
}
@@ -29,7 +29,7 @@ const handleSubmit = async (form: FormContext<GenericObject, GenericObject>) =>
})
return
} catch (error) {
toast.error(t('pickup.codeError'))
toast.error(t('page.upload.pickup.codeError'))
form.resetForm()
}
}
@@ -38,7 +38,7 @@ const handleSubmit = async (form: FormContext<GenericObject, GenericObject>) =>
<template>
<VeeForm>
<div class="flex flex-col gap-5">
<div class="text-xl font-bold">{{ t('pickup.title') }}</div>
<div class="text-xl font-bold">{{ t('page.upload.pickup.title') }}</div>
<PinInputField
name="code"
:rules="

View File

@@ -1,74 +1,62 @@
<script setup lang="ts">
import {
LucideShare,
LucideImage,
LucideBot,
LucideLanguages,
} from "lucide-vue-next";
import { cx } from "class-variance-authority";
import showDrawer from "@/lib/showDrawer";
import TextShareHandle from "@/components/Preprocessing/TextShareHandle.vue";
import { LucideShare, LucideImage, LucideBot, LucideLanguages } from 'lucide-vue-next'
import { cx } from 'class-variance-authority'
import showDrawer from '@/lib/showDrawer'
import TextShareHandle from '@/components/Preprocessing/TextShareHandle.vue'
const props = defineProps<{
hide: () => void;
text: string;
onTextHandle: ({ type, config }: { type: string; config: any }) => void;
}>();
const { t } = useI18n();
hide: () => void
text: string
onTextHandle: ({ type, config }: { type: string; config: any }) => void
}>()
const { t } = useI18n()
const actions = [
{
label: t("text.handleType.text-share"),
icon: LucideShare,
className: "bg-green-300",
onClick: () => {
showDrawer({
render: ({ hide }) => h(TextShareHandle, { ...props, hide }),
});
{
label: t('page.upload.text.handleType.text-share'),
icon: LucideShare,
className: 'bg-green-300',
onClick: () => {
showDrawer({
render: ({ hide }) => h(TextShareHandle, { ...props, hide }),
})
},
},
},
// {
// label: '生成配图', icon: LucideImage, className: 'bg-red-300', onClick: () => {
// console.log('复制链接')
// }
// },
// {
// label: '问大模型', icon: LucideBot, className: 'bg-blue-300', onClick: () => {
// console.log('复制链接')
// }
// },
// {
// label: '文本翻译', icon: LucideLanguages, className: 'bg-orange-300', onClick: () => {
// console.log('复制链接')
// }
// },
];
// {
// label: '生成配图', icon: LucideImage, className: 'bg-red-300', onClick: () => {
// console.log('复制链接')
// }
// },
// {
// label: '问大模型', icon: LucideBot, className: 'bg-blue-300', onClick: () => {
// console.log('复制链接')
// }
// },
// {
// label: '文本翻译', icon: LucideLanguages, className: 'bg-orange-300', onClick: () => {
// console.log('复制链接')
// }
// },
]
</script>
<template>
<div class="flex flex-col gap-5 p-5">
<div class="flex flex-row gap-2">
<div
v-for="item in actions"
:key="item.label"
class="flex flex-col items-center gap-2 max-w-20"
@click="
() => {
props?.hide();
item?.onClick();
}
"
>
<div
:class="
cx(
'size-14 flex justify-center items-center rounded-full mx-3',
item?.className,
)
"
>
<component :is="item?.icon" />
<div class="flex flex-col gap-5 p-5">
<div class="flex flex-row gap-2">
<div
v-for="item in actions"
:key="item.label"
class="flex flex-col items-center gap-2 max-w-20"
@click="
() => {
props?.hide()
item?.onClick()
}
"
>
<div :class="cx('size-14 flex justify-center items-center rounded-full mx-3', item?.className)">
<component :is="item?.icon" />
</div>
<div class="text-xs truncate w-full text-center">{{ item?.label }}</div>
</div>
</div>
<div class="text-xs truncate w-full text-center">{{ item?.label }}</div>
</div>
</div>
</div>
</template>

View File

@@ -56,14 +56,14 @@ const { t } = useI18n()
<div class="size-16 flex justify-center items-center rounded-xl bg-white/80">
<PlusIcon class="size-7" />
</div>
<div class="mb-3">{{ t('file.addMore') }}</div>
<div class="mb-3">{{ t('page.upload.file.addMore') }}</div>
</div>
</div>
</template>
<template v-else>
<LucideUpload class="size-10" />
<div class="text-sm select-none">
{{ t('file.uploadFilePlaceholder') }}
{{ t('page.upload.file.uploadFilePlaceholder') }}
</div>
</template>
</div>

View File

@@ -1,42 +1,40 @@
<script lang="ts" setup>
import showDrawer from "@/lib/showDrawer";
import FileShareDrawer from "@/components/Drawer/FileShareDrawer.vue";
import FileUploadField from "@/components/Field/FileUploadField.vue";
import FormButton from "@/components/Field/FormButton.vue";
import PickupShareBtn from "@/components/PickupShareBtn.vue";
import showDrawer from '@/lib/showDrawer'
import FileShareDrawer from '@/components/Drawer/FileShareDrawer.vue'
import FileUploadField from '@/components/Field/FileUploadField.vue'
import FormButton from '@/components/Field/FormButton.vue'
import PickupShareBtn from '@/components/PickupShareBtn.vue'
const emit = defineEmits<{
(e: "change", key: string): void;
}>();
(e: 'change', key: string): void
}>()
const { t } = useI18n();
const { t } = useI18n()
const handleFormSubmit = async (form: any) => {
const { file } = form?.values || {};
showDrawer({
render: ({ hide }) =>
h(FileShareDrawer, {
hide,
file,
onFileHandle: ({ type, config }) => {
form.setFieldValue("handle_type", type);
form.setFieldValue("config", config);
emit("change", "progress");
},
}),
});
};
const { file } = form?.values || {}
showDrawer({
render: ({ hide }) =>
h(FileShareDrawer, {
hide,
file,
onFileHandle: ({ type, config }) => {
form.setFieldValue('handle_type', type)
form.setFieldValue('config', config)
emit('change', 'progress')
},
}),
})
}
</script>
<template>
<div class="gap-5 flex flex-col">
<div class="text-xl font-normal">{{ t("file.uploadFile") }}</div>
<FileUploadField name="file" rules="required" />
<div class="flex flex-row gap-3">
<FormButton @click="handleFormSubmit">
<LucideShare class="size-4" />{{ t("btn.submit") }}
</FormButton>
<PickupShareBtn />
<div class="gap-5 flex flex-col">
<div class="text-xl font-normal">{{ t('page.upload.file.uploadFile') }}</div>
<FileUploadField name="file" rules="required" />
<div class="flex flex-row gap-3">
<FormButton @click="handleFormSubmit"> <LucideShare class="size-4" />{{ t('btn.submit') }} </FormButton>
<PickupShareBtn />
</div>
</div>
</div>
</template>

View File

@@ -22,12 +22,12 @@ const handleTextShare = ({ type, config }: { type: string; config: any }) => {
</script>
<template>
<div class="gap-5 flex flex-col">
<div class="text-xl font-normal">{{ t('text.uploadText') }}</div>
<div class="text-xl font-normal">{{ t('page.upload.text.uploadText') }}</div>
<div class="relative">
<MarkdownInputField
name="text"
:placeholder="t('text.uploadTextPlaceholder')"
class="max-h-[50vh] min-h-40 overflow-y-auto max-w-full [&>*]:pr-10 flex flex-col"
:placeholder="t('page.upload.text.uploadTextPlaceholder')"
class="max-h-[50vh] min-h-40 overflow-y-auto max-w-full *:pr-10 flex flex-col"
rules="required"
/>
<Button

View File

@@ -16,6 +16,6 @@ const { t } = useI18n()
"
>
<LucideArchive class="size-4" />
{{ t('pickup.btn') }}
{{ t('page.upload.pickup.btn') }}
</AsyncButton>
</template>

View File

@@ -15,37 +15,37 @@ const props = defineProps<{
<template>
<VeeForm v-slot="{ values, setFieldValue }" :initialValues="{ download_nums: 1, expire_time: 1440 }">
<div class="flex flex-col gap-3">
<h2 class="text-lg font-bold">{{ t('fileshare.title') }}</h2>
<h2 class="text-lg font-bold">{{ t('page.shareOptions.file.title') }}</h2>
<div class="flex flex-row items-center gap-2 text-sm">
<SelectField
name="download_nums"
:label="t('fileshare.downloadNums')"
:label="t('page.shareOptions.file.downloadNums')"
:options="[
{ label: t('fileshare.downloadOptions.xdownload', 1), value: 1 },
{ label: t('fileshare.downloadOptions.xdownload', 2), value: 2 },
{ label: t('fileshare.downloadOptions.xdownload', 3), value: 3 },
{ label: t('fileshare.downloadOptions.xdownload', 5), value: 5 },
{ label: t('fileshare.downloadOptions.xdownload', 10), value: 10 },
{ label: t('page.shareOptions.file.downloadOptions.xdownload', 1), value: 1 },
{ label: t('page.shareOptions.file.downloadOptions.xdownload', 2), value: 2 },
{ label: t('page.shareOptions.file.downloadOptions.xdownload', 3), value: 3 },
{ label: t('page.shareOptions.file.downloadOptions.xdownload', 5), value: 5 },
{ label: t('page.shareOptions.file.downloadOptions.xdownload', 10), value: 10 },
]"
/>
{{ t('fileshare.or') }}
{{ t('page.shareOptions.file.or') }}
<SelectField
name="expire_time"
:label="t('fileshare.expireTime')"
:label="t('page.shareOptions.file.expireTime')"
:options="[
{ label: t('fileshare.expireOptions.5min'), value: 5 },
{ label: t('fileshare.expireOptions.1hour'), value: 60 },
{ label: t('fileshare.expireOptions.1day'), value: 1440 },
{ label: t('fileshare.expireOptions.3days'), value: 4320 },
{ label: t('page.shareOptions.file.expireOptions.5min'), value: 5 },
{ label: t('page.shareOptions.file.expireOptions.1hour'), value: 60 },
{ label: t('page.shareOptions.file.expireOptions.1day'), value: 1440 },
{ label: t('page.shareOptions.file.expireOptions.3days'), value: 4320 },
]"
/>
{{ t('fileshare.expireAfter') }}
{{ t('page.shareOptions.file.expireAfter') }}
</div>
<div class="flex flex-col gap-1">
<div class="flex flex-row gap-3 min-h-9">
<SwitchField
name="has_pickup_code"
:label="t('fileshare.pickupCode')"
:label="t('page.shareOptions.file.pickupCode')"
:rules="
(value: boolean) => {
if (!!value) {
@@ -59,7 +59,7 @@ const props = defineProps<{
<div class="flex flex-row gap-3 min-h-9">
<SwitchField
name="has_password"
:label="t('fileshare.passwordProtection')"
:label="t('page.shareOptions.file.passwordProtection')"
:rules="
(value: boolean) => {
if (!!value) {
@@ -69,11 +69,21 @@ const props = defineProps<{
}
"
/>
<InputField v-if="!!values.has_password" name="password" :placeholder="t('fileshare.passwordPlaceholder')" rules="required" />
<InputField
v-if="!!values.has_password"
name="password"
:placeholder="t('page.shareOptions.file.passwordPlaceholder')"
rules="required"
/>
</div>
<div class="flex flex-row gap-3 min-h-9">
<SwitchField name="has_notify" :label="t('fileshare.downloadNotify')" />
<InputField v-if="!!values.has_notify" name="notify_email" :placeholder="t('fileshare.emailPlaceholder')" rules="required" />
<SwitchField name="has_notify" :label="t('page.shareOptions.file.downloadNotify')" />
<InputField
v-if="!!values.has_notify"
name="notify_email"
:placeholder="t('page.shareOptions.file.emailPlaceholder')"
rules="required"
/>
</div>
</div>
<FormButton

View File

@@ -15,37 +15,37 @@ const props = defineProps<{
<template>
<VeeForm v-slot="{ values, setFieldValue }" :initialValues="{ download_nums: 1, expire_time: 1440 }">
<div class="flex flex-col gap-3">
<h2 class="text-lg font-bold">{{ t('textshare.title') }}</h2>
<h2 class="text-lg font-bold">{{ t('page.shareOptions.text.title') }}</h2>
<div class="flex flex-row items-center gap-2 text-sm">
<SelectField
name="download_nums"
:label="t('textshare.viewNums')"
:label="t('page.shareOptions.text.viewNums')"
:options="[
{ label: t('textshare.viewOptions.xview', 1), value: 1 },
{ label: t('textshare.viewOptions.xview', 2), value: 2 },
{ label: t('textshare.viewOptions.xview', 3), value: 3 },
{ label: t('textshare.viewOptions.xview', 5), value: 5 },
{ label: t('textshare.viewOptions.xview', 10), value: 10 },
{ label: t('page.shareOptions.text.viewOptions.xview', 1), value: 1 },
{ label: t('page.shareOptions.text.viewOptions.xview', 2), value: 2 },
{ label: t('page.shareOptions.text.viewOptions.xview', 3), value: 3 },
{ label: t('page.shareOptions.text.viewOptions.xview', 5), value: 5 },
{ label: t('page.shareOptions.text.viewOptions.xview', 10), value: 10 },
]"
/>
{{ t('textshare.or') }}
{{ t('page.shareOptions.text.or') }}
<SelectField
name="expire_time"
:label="t('textshare.expireTime')"
:label="t('page.shareOptions.text.expireTime')"
:options="[
{ label: t('textshare.expireOptions.5min'), value: 5 },
{ label: t('textshare.expireOptions.1hour'), value: 60 },
{ label: t('textshare.expireOptions.1day'), value: 1440 },
{ label: t('textshare.expireOptions.3days'), value: 4320 },
{ label: t('page.shareOptions.text.expireOptions.5min'), value: 5 },
{ label: t('page.shareOptions.text.expireOptions.1hour'), value: 60 },
{ label: t('page.shareOptions.text.expireOptions.1day'), value: 1440 },
{ label: t('page.shareOptions.text.expireOptions.3days'), value: 4320 },
]"
/>
{{ t('textshare.expireAfter') }}
{{ t('page.shareOptions.text.expireAfter') }}
</div>
<div class="flex flex-col gap-1">
<div class="flex flex-row gap-3 min-h-9">
<SwitchField
name="has_pickup_code"
:label="t('textshare.pickupCode')"
:label="t('page.shareOptions.text.pickupCode')"
:rules="
(value: boolean) => {
if (!!value) {
@@ -59,7 +59,7 @@ const props = defineProps<{
<div class="flex flex-row gap-3 min-h-9">
<SwitchField
name="has_password"
:label="t('textshare.passwordProtection')"
:label="t('page.shareOptions.text.passwordProtection')"
:rules="
(value: boolean) => {
if (!!value) {
@@ -69,11 +69,21 @@ const props = defineProps<{
}
"
/>
<InputField v-if="!!values.has_password" name="password" :placeholder="t('textshare.passwordPlaceholder')" rules="required" />
<InputField
v-if="!!values.has_password"
name="password"
:placeholder="t('page.shareOptions.text.passwordPlaceholder')"
rules="required"
/>
</div>
<div class="flex flex-row gap-3 min-h-9">
<SwitchField name="has_notify" :label="t('textshare.readNotify')" />
<InputField v-if="!!values.has_notify" name="notify_email" :placeholder="t('textshare.emailPlaceholder')" rules="required" />
<SwitchField name="has_notify" :label="t('page.shareOptions.text.readNotify')" />
<InputField
v-if="!!values.has_notify"
name="notify_email"
:placeholder="t('page.shareOptions.text.emailPlaceholder')"
rules="required"
/>
</div>
</div>
<FormButton

View File

@@ -58,13 +58,13 @@ const { copy } = useClipboard()
<template>
<div class="flex flex-col gap-3">
<h2 class="text-lg">{{ t('fileshareresult.title') }}</h2>
<h2 class="text-lg">{{ t('page.result.file.title') }}</h2>
<div class="flex flex-col gap-3 items-center">
<div v-if="data?.length === 1" class="flex flex-col h-30 items-center">
<FilePreviewView :value="props?.data?.files?.[0]?.file as File" />
</div>
<div v-else class="flex flex-col gap-2 w-full p-5 bg-white/20 backdrop-blur-xl rounded-md">
<div class="text-sm font-semibold">{{ t('fileshareresult.fileList') }}</div>
<div class="text-sm font-semibold">{{ t('page.result.file.fileList') }}</div>
<div
v-for="file in data"
:class="
@@ -90,7 +90,7 @@ const { copy } = useClipboard()
@click="
() => {
copy(getShareUrl(file?.id as string))
toast.success(t('fileshareresult.copySuccess'))
toast.success(t('page.result.file.copySuccess'))
}
"
>
@@ -119,21 +119,21 @@ const { copy } = useClipboard()
</div>
<div v-if="!!selectedFileShare" class="flex flex-col md:flex-row gap-5 rounded-md p-5 bg-white/20 backdrop-blur-xl w-full">
<div class="flex flex-col gap-2 flex-1">
<div class="text-sm font-semibold">{{ t('fileshareresult.info') }}</div>
<div class="text-sm font-semibold">{{ t('page.result.file.info') }}</div>
<div class="grid grid-cols-2 gap-2">
<div class="rounded-xl flex flex-col bg-black/10 px-3 py-2 gap-1">
<div class="text-xs font-semibold">{{ t('fileshareresult.downloadNums') }}</div>
<div class="text-xs font-semibold">{{ t('page.result.file.downloadNums') }}</div>
<div class="text-3xl font-light">{{ selectedFileShare?.download_nums }}</div>
</div>
<div class="rounded-xl flex flex-col bg-black/10 px-3 py-2 gap-1">
<div class="text-xs font-semibold">{{ t('fileshareresult.expireTime') }}</div>
<div class="text-xs font-semibold">{{ t('page.result.file.expireTime') }}</div>
<div class="text-md font-light">
{{ dayjs((selectedFileShare?.expire_at || 0) * 1000).format('YYYY-MM-DD HH:mm:ss') }}
</div>
</div>
<div class="rounded-xl flex flex-col bg-black/10 px-3 py-2 gap-1" v-if="selectedFileShare?.pickup_code">
<div class="flex flex-row justify-between w-full items-center">
<div class="text-xs font-semibold">{{ t('fileshareresult.pickupCode') }}</div>
<div class="text-xs font-semibold">{{ t('page.result.file.pickupCode') }}</div>
<Button
variant="outline"
class="bg-white/70 p-0 size-6"
@@ -141,7 +141,7 @@ const { copy } = useClipboard()
@click="
() => {
copy(selectedFileShare?.pickup_code as string)
toast.success(t('fileshareresult.copySuccess'))
toast.success(t('page.result.file.copySuccess'))
}
"
>
@@ -157,7 +157,7 @@ const { copy } = useClipboard()
</div>
</div>
<div class="flex flex-col gap-5 flex-1">
<div class="text-sm font-semibold">{{ t('fileshareresult.link') }}</div>
<div class="text-sm font-semibold">{{ t('page.result.file.link') }}</div>
<div class="flex flex-row gap-2">
<Input :model-value="getShareUrl(selectedFileShare?.id as string)" class="bg-white/70" readonly />
<Button
@@ -167,7 +167,7 @@ const { copy } = useClipboard()
@click="
() => {
copy(getShareUrl(selectedFileShare?.id as string))
toast.success(t('fileshareresult.copySuccess'))
toast.success(t('page.result.file.copySuccess'))
}
"
>

View File

@@ -45,7 +45,7 @@ const { t } = useI18n()
<div class="flex flex-col gap-3">
<div class="flex flex-row gap-2">
<div class="flex flex-row justify-between w-full">
<h2 class="text-lg">{{ t('textshareresult.title') }}</h2>
<h2 class="text-lg">{{ t('page.result.text.title') }}</h2>
<Button
variant="outline"
class="bg-white/70"
@@ -62,21 +62,21 @@ const { t } = useI18n()
</div>
<div class="flex flex-col md:flex-row gap-5 rounded-md p-5 bg-white/20 backdrop-blur-xl w-full">
<div class="flex flex-col gap-2 flex-1">
<div class="text-sm font-semibold">{{ t('textshareresult.info') }}</div>
<div class="text-sm font-semibold">{{ t('page.result.text.info') }}</div>
<div class="grid grid-cols-2 gap-2">
<div class="rounded-xl flex flex-col bg-black/10 px-3 py-2 gap-1">
<div class="text-xs font-semibold">{{ t('textshareresult.viewNums') }}</div>
<div class="text-xs font-semibold">{{ t('page.result.text.viewNums') }}</div>
<div class="text-3xl font-light">{{ data?.download_nums }}</div>
</div>
<div class="rounded-xl flex flex-col bg-black/5 px-3 py-2 gap-1">
<div class="text-xs font-semibold">{{ t('textshareresult.expireTime') }}</div>
<div class="text-xs font-semibold">{{ t('page.result.text.expireTime') }}</div>
<div class="text-md font-light">
{{ dayjs((data?.expire_at ?? 0) * 1000).format('YYYY-MM-DD HH:mm:ss') }}
</div>
</div>
<div class="rounded-xl flex flex-col bg-black/10 px-3 py-2 gap-1" v-if="data?.pickup_code">
<div class="flex flex-row justify-between w-full items-center">
<div class="text-xs font-semibold">{{ t('textshareresult.pickupCode') }}</div>
<div class="text-xs font-semibold">{{ t('page.result.text.pickupCode') }}</div>
<Button
variant="outline"
class="bg-white/70 p-0 size-6"
@@ -84,7 +84,7 @@ const { t } = useI18n()
@click="
() => {
copy(data?.pickup_code as string)
toast.success(t('textshareresult.copySuccess'))
toast.success(t('page.result.text.copySuccess'))
}
"
>
@@ -100,7 +100,7 @@ const { t } = useI18n()
</div>
</div>
<div class="flex flex-col gap-5 flex-1">
<div class="text-sm font-semibold">{{ t('textshareresult.link') }}</div>
<div class="text-sm font-semibold">{{ t('page.result.text.link') }}</div>
<div class="flex flex-row gap-2">
<Input v-model="url" class="bg-white/70" readonly />
<Button
@@ -110,7 +110,7 @@ const { t } = useI18n()
@click="
() => {
copy(url)
toast.success(t('textshareresult.copySuccess'))
toast.success(t('page.result.text.copySuccess'))
}
"
>
@@ -138,7 +138,7 @@ const { t } = useI18n()
</div>
</div>
</div>
<h2 class="text-md">{{ t('textshareresult.content') }}</h2>
<h2 class="text-md">{{ t('page.result.text.content') }}</h2>
<MarkdownRender class="prose rounded-md bg-white/70 p-3 w-full max-w-full min-h-[30vh]" :markdown="props?.data?.text" />
</div>
</template>

View File

@@ -13,106 +13,114 @@
"submit": "Submit",
"backToHome": "Back to Home"
},
"file": {
"uploadFile": "Upload File",
"uploadFilePlaceholder": "Drag and drop files or click to upload",
"addMore": "Add More",
"handleType": {
"file-share": "File Share",
"file-image-compress": "Image Compress"
}
},
"text": {
"uploadText": "Upload Text",
"uploadTextPlaceholder": "Share, translate, summarize, generate images, and ask large models with our text processor",
"handleType": {
"text-share": "Text Share"
}
},
"pickup": {
"title": "Enter Pickup Code",
"codeError": "Invalid pickup code",
"btn": "Pickup"
},
"fileshare": {
"title": "Share Options",
"downloadNums": "Download Count",
"expireTime": "Expire Time",
"or": "or",
"expireAfter": "expire",
"pickupCode": "Pickup Code",
"passwordProtection": "Password Protection",
"downloadNotify": "Download Notification",
"passwordPlaceholder": "Enter password",
"emailPlaceholder": "Enter email",
"downloadOptions": {
"xdownload": "{0} downloads"
"page": {
"upload": {
"file": {
"uploadFile": "Upload File",
"uploadFilePlaceholder": "Drag and drop files or click to upload",
"addMore": "Add More",
"handleType": {
"file-share": "File Share",
"file-image-compress": "Image Compress"
}
},
"text": {
"uploadText": "Upload Text",
"uploadTextPlaceholder": "Share, translate, summarize, generate images, and ask large models with our text processor",
"handleType": {
"text-share": "Text Share"
}
},
"pickup": {
"title": "Enter Pickup Code",
"codeError": "Invalid pickup code",
"btn": "Pickup"
}
},
"expireOptions": {
"5min": "5 minutes",
"1hour": "1 hour",
"1day": "1 day",
"3days": "3 days"
}
},
"textshare": {
"title": "Share Options",
"viewNums": "View Count",
"expireTime": "Expire Time",
"or": "or",
"expireAfter": "expire",
"pickupCode": "Pickup Code",
"passwordProtection": "Password Protection",
"readNotify": "Read Notification",
"passwordPlaceholder": "Enter password",
"emailPlaceholder": "Enter email",
"viewOptions": {
"xview": "{0} views"
"shareOptions": {
"file": {
"title": "Share Options",
"downloadNums": "Download Count",
"expireTime": "Expire Time",
"or": "or",
"expireAfter": "expire",
"pickupCode": "Pickup Code",
"passwordProtection": "Password Protection",
"downloadNotify": "Download Notification",
"passwordPlaceholder": "Enter password",
"emailPlaceholder": "Enter email",
"downloadOptions": {
"xdownload": "{0} downloads"
},
"expireOptions": {
"5min": "5 minutes",
"1hour": "1 hour",
"1day": "1 day",
"3days": "3 days"
}
},
"text": {
"title": "Share Options",
"viewNums": "View Count",
"expireTime": "Expire Time",
"or": "or",
"expireAfter": "expire",
"pickupCode": "Pickup Code",
"passwordProtection": "Password Protection",
"readNotify": "Read Notification",
"passwordPlaceholder": "Enter password",
"emailPlaceholder": "Enter email",
"viewOptions": {
"xview": "{0} views"
},
"expireOptions": {
"5min": "5 minutes",
"1hour": "1 hour",
"1day": "1 day",
"3days": "3 days"
}
}
},
"expireOptions": {
"5min": "5 minutes",
"1hour": "1 hour",
"1day": "1 day",
"3days": "3 days"
"result": {
"file": {
"title": "Upload Successful",
"fileList": "File List",
"info": "Info",
"downloadNums": "Download Count",
"expireTime": "Expire Time",
"pickupCode": "Pickup Code",
"link": "Link",
"copySuccess": "Copy Success"
},
"text": {
"title": "Share Successful",
"info": "Info",
"viewNums": "View Count",
"expireTime": "Expire Time",
"pickupCode": "Pickup Code",
"link": "Link",
"content": "Content",
"copySuccess": "Copy Success"
}
},
"about": {
"powerBy": "Power by {0} as a open source temporary file sharing platform",
"file": "File",
"share": "Share",
"download": "Download",
"task": "Task",
"admin": "Site Admin",
"author": "Author",
"title": "About",
"about": "About",
"systemInfo": "System Info",
"systemVersion": "System Version",
"storage": "Storage",
"analysis": "Analysis",
"fileSize": "File Size",
"fileNum": "File Num",
"processed": "Processed",
"failed": "Failed"
}
},
"fileshareresult": {
"title": "Upload Successful",
"fileList": "File List",
"info": "Info",
"downloadNums": "Download Count",
"expireTime": "Expire Time",
"pickupCode": "Pickup Code",
"link": "Link",
"copySuccess": "Copy Success"
},
"textshareresult": {
"title": "Share Successful",
"info": "Info",
"viewNums": "View Count",
"expireTime": "Expire Time",
"pickupCode": "Pickup Code",
"link": "Link",
"content": "Content",
"copySuccess": "Copy Success"
},
"about": {
"powerBy": "Power by {0} as a open source temporary file sharing platform",
"file": "File",
"share": "Share",
"download": "Download",
"task": "Task",
"admin": "Site Admin",
"author": "Author",
"title": "About",
"about": "About",
"systemInfo": "System Info",
"systemVersion": "System Version",
"storage": "Storage",
"analysis": "Analysis",
"fileSize": "File Size",
"fileNum": "File Num",
"processed": "Processed",
"failed": "Failed"
}
}

View File

@@ -13,106 +13,114 @@
"submit": "提交",
"backToHome": "返回首页"
},
"file": {
"uploadFile": "上传文件",
"uploadFilePlaceholder": "拖拽文件 或 点击上传",
"addMore": "添加更多",
"handleType": {
"file-share": "文件分享",
"file-image-compress": "图片压缩"
}
},
"text": {
"uploadText": "上传文本",
"uploadTextPlaceholder": "使用我们的文本处理器轻松分享,翻译,总结,生成图片,询问大模型",
"handleType": {
"text-share": "文本分享"
}
},
"pickup": {
"title": "输入取件码",
"codeError": "取件码错误",
"btn": "取件"
},
"fileshare": {
"title": "分享选项",
"downloadNums": "下载次数",
"expireTime": "过期时间",
"or": "或",
"expireAfter": "后过期",
"pickupCode": "取件码",
"passwordProtection": "密码保护",
"downloadNotify": "下载通知",
"passwordPlaceholder": "请输入密码",
"emailPlaceholder": "请输入邮箱",
"downloadOptions": {
"xdownload": "{0}次下载"
"page": {
"upload": {
"file": {
"uploadFile": "上传文件",
"uploadFilePlaceholder": "拖拽文件 或 点击上传",
"addMore": "添加更多",
"handleType": {
"file-share": "文件分享",
"file-image-compress": "图片压缩"
}
},
"text": {
"uploadText": "上传文本",
"uploadTextPlaceholder": "使用我们的文本处理器轻松分享,翻译,总结,生成图片,询问大模型",
"handleType": {
"text-share": "文本分享"
}
},
"pickup": {
"title": "输入取件码",
"codeError": "取件码错误",
"btn": "取件"
}
},
"expireOptions": {
"5min": "5分钟",
"1hour": "1小时",
"1day": "1天",
"3days": "3天"
}
},
"textshare": {
"title": "分享选项",
"viewNums": "浏览次数",
"expireTime": "过期时间",
"or": "",
"expireAfter": "后过期",
"pickupCode": "取件码",
"passwordProtection": "密码保护",
"readNotify": "已读通知",
"passwordPlaceholder": "请输入密码",
"emailPlaceholder": "请输入邮箱",
"viewOptions": {
"xview": "{0}次浏览"
"shareOptions": {
"file": {
"title": "分享选项",
"downloadNums": "下载次数",
"expireTime": "过期时间",
"or": "或",
"expireAfter": "后过期",
"pickupCode": "取件码",
"passwordProtection": "密码保护",
"downloadNotify": "下载通知",
"passwordPlaceholder": "请输入密码",
"emailPlaceholder": "请输入邮箱",
"downloadOptions": {
"xdownload": "{0}次下载"
},
"expireOptions": {
"5min": "5分钟",
"1hour": "1小时",
"1day": "1天",
"3days": "3天"
}
},
"text": {
"title": "分享选项",
"viewNums": "浏览次数",
"expireTime": "过期时间",
"or": "或",
"expireAfter": "后过期",
"pickupCode": "取件码",
"passwordProtection": "密码保护",
"readNotify": "已读通知",
"passwordPlaceholder": "请输入密码",
"emailPlaceholder": "请输入邮箱",
"viewOptions": {
"xview": "{0}次浏览"
},
"expireOptions": {
"5min": "5分钟",
"1hour": "1小时",
"1day": "1天",
"3days": "3天"
}
}
},
"expireOptions": {
"5min": "5分钟",
"1hour": "1小时",
"1day": "1天",
"3days": "3天"
"result": {
"file": {
"title": "上传成功",
"fileList": "文件列表",
"info": "信息",
"downloadNums": "下载次数",
"expireTime": "过期时间",
"pickupCode": "提取码",
"link": "链接",
"copySuccess": "复制成功"
},
"text": {
"title": "分享成功",
"info": "信息",
"viewNums": "浏览次数",
"expireTime": "过期时间",
"pickupCode": "提取码",
"link": "链接",
"content": "内容",
"copySuccess": "复制成功"
}
},
"about": {
"powerBy": "由 {0} 驱动的开源自托管临时文件分享平台",
"file": "文件",
"share": "分享",
"download": "下载",
"task": "任务",
"admin": "本站管理员",
"author": "作者",
"title": "关于",
"about": "关于",
"systemInfo": "系统信息",
"systemVersion": "系统版本",
"storage": "已托管的文件",
"analysis": "分析",
"fileSize": "文件大小",
"fileNum": "文件数量",
"processed": "处理数量",
"failed": "失败数量"
}
},
"fileshareresult": {
"title": "上传成功",
"fileList": "文件列表",
"info": "信息",
"downloadNums": "下载次数",
"expireTime": "过期时间",
"pickupCode": "提取码",
"link": "链接",
"copySuccess": "复制成功"
},
"textshareresult": {
"title": "分享成功",
"info": "信息",
"viewNums": "浏览次数",
"expireTime": "过期时间",
"pickupCode": "提取码",
"link": "链接",
"content": "内容",
"copySuccess": "复制成功"
},
"about": {
"powerBy": "由 {0} 驱动的开源自托管临时文件分享平台",
"file": "文件",
"share": "分享",
"download": "下载",
"task": "任务",
"admin": "本站管理员",
"author": "作者",
"title": "关于",
"about": "关于",
"systemInfo": "系统信息",
"systemVersion": "系统版本",
"storage": "已托管的文件",
"analysis": "分析",
"fileSize": "文件大小",
"fileNum": "文件数量",
"processed": "处理数量",
"failed": "失败数量"
}
}

View File

@@ -7,7 +7,7 @@ const { t } = useI18n()
<template>
<div class="rounded-xl p-5 bg-white/50 backdrop-blur-xl w-full lg:w-200 my-5 flex flex-col gap-5">
<div class="text-xl font-normal">{{ t('about.title') }}</div>
<div class="text-xl font-normal">{{ t('page.about.title') }}</div>
<AboutBaseInfo />
<AboutChartView />
<AboutVersionView />