feat: implement internationalization for share views and update UI text for better user experience

This commit is contained in:
keven1024
2026-03-08 14:57:46 +08:00
parent 707ade5dd2
commit b69af056aa
7 changed files with 94 additions and 33 deletions

View File

@@ -4,6 +4,7 @@ import FormButton from '@/components/Field/FormButton.vue'
import InputField from '@/components/Field/InputField.vue'
import type { FormContext, GenericObject } from 'vee-validate'
import { toast } from 'vue-sonner'
const { t } = useI18n()
const props = defineProps<{
share_id: string
hide: any
@@ -15,14 +16,14 @@ const handleSubmit = async (form: FormContext<GenericObject, GenericObject>) =>
const password = form.values.password
const token = await getShareToken(props.share_id, { password })
if (!token) {
toast.error('密码错误')
toast.error(t('page.shareView.passwall.passwordError'))
form.resetForm()
return
}
props?.hide(token)
return
} catch (error) {
toast.error('密码错误')
toast.error(t('page.shareView.passwall.passwordError'))
form.resetForm()
}
}
@@ -31,9 +32,9 @@ const handleSubmit = async (form: FormContext<GenericObject, GenericObject>) =>
<template>
<VeeForm>
<div class="flex flex-col gap-5">
<div class="text-xl font-bold">输入密码</div>
<InputField name="password" type="password" rules="required" placeholder="请输入密码" />
<FormButton @click="handleSubmit">提交</FormButton>
<div class="text-xl font-bold">{{ t('page.shareView.passwall.title') }}</div>
<InputField name="password" type="password" rules="required" :placeholder="t('page.shareView.passwall.passwordPlaceholder')" />
<FormButton @click="handleSubmit">{{ t('btn.submit') }}</FormButton>
</div>
</VeeForm>
</template>

View File

@@ -1,20 +1,21 @@
<script setup lang="ts">
import QRCode from "qrcode";
import QRCode from 'qrcode'
const { t } = useI18n()
const props = defineProps<{
hide: () => void;
data: any;
}>();
hide: () => void
data: any
}>()
const { state } = useAsyncState(async () => {
return await QRCode.toDataURL(props.data);
}, null);
return await QRCode.toDataURL(props.data)
}, null)
</script>
<template>
<div class="flex flex-col gap-5">
<div class="text-xl font-bold">分享二维码</div>
<div class="flex flex-row justify-center">
<img :src="state" v-if="!!state" />
<Skeleton class="size-20" v-else />
<div class="flex flex-col gap-5">
<div class="text-xl font-bold">{{ t('page.result.qrCode.title') }}</div>
<div class="flex flex-row justify-center">
<img :src="state" v-if="!!state" />
<Skeleton class="size-20" v-else />
</div>
</div>
</div>
</template>

View File

@@ -12,6 +12,7 @@ import PasswallShareDrawer from '~/components/Drawer/PasswallShareDrawer.vue'
dayjs.extend(duration)
dayjs.extend(relativeTime)
const { t } = useI18n()
const props = defineProps<{
data: any
}>()
@@ -31,7 +32,7 @@ const handleDownload = async () => {
token = await getShareToken(id)
}
if (!token) {
throw new Error('获取token失败')
throw new Error(t('page.shareView.fileShare.getTokenFailed'))
}
downloadFile(token)
} catch (error: any) {
@@ -53,19 +54,19 @@ onMounted(() => {
const fileShareInfo = computed(() => {
return [
{ label: '需要密码', value: props?.data?.has_password ?? false },
{ label: t('page.shareView.fileShare.needPassword'), value: props?.data?.has_password ?? false },
{
label: '过期时间',
value: dayjs.duration(remaining.value, 'seconds').format(`D天 HH:mm:ss`),
label: t('page.shareView.fileShare.expireTime'),
value: dayjs.duration(remaining.value, 'seconds').format(t('page.shareView.fileShare.durationFormat')),
},
{ label: '剩余下载次数', value: props?.data?.download_nums ?? 0 },
{ label: t('page.shareView.fileShare.remainingDownloads'), value: props?.data?.download_nums ?? 0 },
]
})
</script>
<template>
<div class="flex flex-col gap-5 items-center">
<h1 class="text-xl font-bold">下载文件</h1>
<h1 class="text-xl font-bold">{{ t('page.shareView.fileShare.title') }}</h1>
<FilePreviewView :value="props?.data" />
<div class="flex flex-col gap-2 md:flex-row w-full">
<div class="flex flex-row md:flex-col md:gap-1 justify-between items-center md:flex-1" v-for="item in fileShareInfo">
@@ -75,7 +76,7 @@ const fileShareInfo = computed(() => {
</div>
</div>
<div class="w-full">
<AsyncButton @click="handleDownload" class="w-full">下载</AsyncButton>
<AsyncButton @click="handleDownload" class="w-full">{{ t('page.shareView.fileShare.downloadBtn') }}</AsyncButton>
</div>
</div>
</template>

View File

@@ -17,6 +17,7 @@ import PasswallShareDrawer from '~/components/Drawer/PasswallShareDrawer.vue'
dayjs.extend(duration)
dayjs.extend(relativeTime)
const { t } = useI18n()
const props = defineProps<{
data: any
}>()
@@ -37,12 +38,12 @@ onMounted(() => {
const fileShareInfo = computed(() => {
return [
{ label: '需要密码', value: props?.data?.has_password ?? false },
{ label: t('page.shareView.textShare.needPassword'), value: props?.data?.has_password ?? false },
{
label: '过期时间',
value: dayjs.duration(remaining.value, 'seconds').format(`D天 HH:mm:ss`),
label: t('page.shareView.textShare.expireTime'),
value: dayjs.duration(remaining.value, 'seconds').format(t('page.shareView.textShare.durationFormat')),
},
{ label: '剩余浏览次数', value: props?.data?.download_nums ?? 0 },
{ label: t('page.shareView.textShare.remainingViews'), value: props?.data?.download_nums ?? 0 },
]
})
const previewText = ref<string | null>(null)
@@ -72,7 +73,7 @@ const handlePreview = async () => {
<template>
<div :class="cx('flex flex-col max-h-full', !!previewText ? 'gap-3' : 'gap-16 items-center')">
<div :class="cx('flex flex-row w-full', !!previewText ? 'justify-between' : 'justify-center')">
<h1 class="text-xl">查看文本</h1>
<h1 class="text-xl">{{ t('page.shareView.textShare.title') }}</h1>
<Button
v-if="!!previewText"
variant="outline"
@@ -80,7 +81,7 @@ const handlePreview = async () => {
@click="
() => {
copy(previewText as string)
toast.success('复制成功')
toast.success(t('page.result.text.copySuccess'))
}
"
>
@@ -96,7 +97,7 @@ const handlePreview = async () => {
</div>
</div>
<div class="w-full">
<AsyncButton @click="handlePreview" class="w-full">浏览</AsyncButton>
<AsyncButton @click="handlePreview" class="w-full">{{ t('page.shareView.textShare.viewBtn') }}</AsyncButton>
</div>
</template>
<template v-else>

View File

@@ -160,6 +160,34 @@
"link": "Link",
"content": "Content",
"copySuccess": "Copy Success"
},
"qrCode": {
"title": "Share QR code"
}
},
"shareView": {
"linkExpired": "This link has expired.",
"passwall": {
"title": "Enter password",
"passwordError": "Wrong password",
"passwordPlaceholder": "Enter password"
},
"fileShare": {
"title": "Download file",
"downloadBtn": "Download",
"needPassword": "Password required",
"expireTime": "Expire time",
"remainingDownloads": "Remaining downloads",
"getTokenFailed": "Failed to get token",
"durationFormat": "D [days] HH:mm:ss"
},
"textShare": {
"title": "View text",
"viewBtn": "View",
"needPassword": "Password required",
"expireTime": "Expire time",
"remainingViews": "Remaining views",
"durationFormat": "D [days] HH:mm:ss"
}
},
"about": {

View File

@@ -160,6 +160,34 @@
"link": "链接",
"content": "内容",
"copySuccess": "复制成功"
},
"qrCode": {
"title": "分享二维码"
}
},
"shareView": {
"linkExpired": "此链接已过期。",
"passwall": {
"title": "输入密码",
"passwordError": "密码错误",
"passwordPlaceholder": "请输入密码"
},
"fileShare": {
"title": "下载文件",
"downloadBtn": "下载",
"needPassword": "需要密码",
"expireTime": "过期时间",
"remainingDownloads": "剩余下载次数",
"getTokenFailed": "获取token失败",
"durationFormat": "D天 HH:mm:ss"
},
"textShare": {
"title": "查看文本",
"viewBtn": "浏览",
"needPassword": "需要密码",
"expireTime": "过期时间",
"remainingViews": "剩余浏览次数",
"durationFormat": "D天 HH:mm:ss"
}
},
"about": {

View File

@@ -8,6 +8,7 @@ import TextShareView from '@/components/Share/TextShareView.vue'
import { useQuery } from '@tanstack/vue-query'
const route = useRoute()
const router = useRouter()
const { t } = useI18n()
const id = computed(() => route.params.id)
const { data, isLoading, error } = useQuery({
@@ -51,14 +52,14 @@ const componentMap = {
<template v-else>
<div v-if="isExpired || !data" class="flex flex-col gap-5 items-center">
<LucideAlertCircle :size="48" class="text-orange-500 rounded-full bg-orange-500/30 p-2" />
<div class="text-xl">此链接已过期</div>
<div class="text-xl">{{ t('page.shareView.linkExpired') }}</div>
<Button
@click="
() => {
router.push('/')
}
"
>返回首页</Button
>{{ t('btn.backToHome') }}</Button
>
</div>
<template v-else>