refactor: internationalize HomePage component

- Replace all hardcoded Chinese text with t() function calls
- Add Chinese translations for all new i18n keys in zh-CN.json
- Update UI text including buttons, labels, error messages, and status messages
- Ensure all user-facing strings are properly internationalized
This commit is contained in:
jingrow 2025-12-26 20:57:14 +08:00
parent 05fce42cbf
commit fd84f1458a
2 changed files with 83 additions and 59 deletions

View File

@ -1193,5 +1193,30 @@
"URL": "URL",
"Created": "创建时间",
"Last Updated": "最后更新",
"Click image to try": "点击图片快速体验"
"Click image to try": "点击图片快速体验",
"Remove Background": "去除背景",
"Download": "下载",
"Change Image": "更换图片",
"Upload Image": "上传图片",
"or": "或",
"Paste image URL here": "粘贴图片URL",
"Drag and drop your image anywhere, or paste image directly": "拖放图片到任意位置,或直接粘贴图片",
"Supports JPG, PNG, WebP formats": "支持 JPG、PNG、WebP 格式",
"Loading image from URL...": "加载图片URL中...",
"Original": "原图",
"Background Removed": "去背景后",
"Processing...": "处理中...",
"Add new image": "添加新图片",
"Delete": "删除",
"Unsupported image format. Please use JPG, PNG, or WebP": "不支持的图片格式,请使用 JPG、PNG 或 WebP",
"Image size exceeds 10MB limit": "图片大小超过 10MB 限制",
"Please upload an image first": "请先上传图片",
"Failed to download image": "下载失败",
"Please enter an image URL": "请输入图片URL",
"Please enter a valid image URL": "请输入有效的图片URL",
"Image processing failed, please try again": "图片处理失败,请重试",
"Failed to load sample image": "加载示例图片失败",
"Failed to remove background": "去背景失败",
"Failed to load image from URL": "从URL加载图片失败",
"Sign up successful, but auto login failed. Please login manually": "注册成功,但自动登录失败,请手动登录"
}

View File

@ -160,7 +160,7 @@ const handleSignupSubmit = async () => {
signupFormData.email = ''
signupFormData.phoneNumber = ''
} else {
message.warning(loginResult.error || t('注册成功,但自动登录失败,请手动登录'))
message.warning(loginResult.error || t('Sign up successful, but auto login failed. Please login manually'))
showSignupModal.value = false
showLoginModal.value = true
}
@ -385,13 +385,13 @@ const handleFileSelect = (e: Event) => {
const processFile = async (file: File) => {
const validTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp']
if (!validTypes.includes(file.type)) {
message.warning('不支持的图片格式,请使用 JPG、PNG 或 WebP')
message.warning(t('Unsupported image format. Please use JPG, PNG, or WebP'))
return
}
const maxSize = 10 * 1024 * 1024
if (file.size > maxSize) {
message.warning('图片大小超过 10MB 限制')
message.warning(t('Image size exceeds 10MB limit'))
return
}
@ -416,7 +416,7 @@ const processFile = async (file: File) => {
reader.readAsDataURL(compressedFile)
} catch (error) {
console.error('图片压缩失败:', error)
message.error('图片处理失败,请重试')
message.error(t('Image processing failed, please try again'))
}
}
@ -437,7 +437,7 @@ const handleSampleImageClick = async (imageUrl: string) => {
//
const validTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp']
if (!validTypes.includes(blob.type)) {
message.warning('不支持的图片格式')
message.warning(t('Unsupported image format. Please use JPG, PNG, or WebP'))
processing.value = false
return
}
@ -445,7 +445,7 @@ const handleSampleImageClick = async (imageUrl: string) => {
//
const maxSize = 10 * 1024 * 1024
if (blob.size > maxSize) {
message.warning('图片大小超过 10MB 限制')
message.warning(t('Image size exceeds 10MB limit'))
processing.value = false
return
}
@ -455,12 +455,12 @@ const handleSampleImageClick = async (imageUrl: string) => {
await processFile(file)
} catch (error: any) {
console.error('加载示例图片失败:', error)
let errorMessage = '加载示例图片失败'
let errorMessage = t('Failed to load sample image')
if (error.message?.includes('CORS')) {
errorMessage = '图片服务器不允许跨域访问'
errorMessage = t('CORS error. The image server does not allow cross-origin access.')
} else if (error.message?.includes('Failed to load')) {
errorMessage = '加载图片失败,请稍后重试'
errorMessage = t('Failed to load image. Please check the URL and try again.')
}
message.error(errorMessage)
@ -470,7 +470,7 @@ const handleSampleImageClick = async (imageUrl: string) => {
const handleRemoveBackground = async () => {
if (!uploadedImage.value) {
message.warning('请先上传图片')
message.warning(t('Please upload an image first'))
return
}
@ -519,16 +519,16 @@ const handleRemoveBackground = async () => {
historyList.value[currentHistoryIndex.value].resultImage = firstResult.image_url
}
} else {
message.error(firstResult.error || '去背景失败')
message.error(firstResult.error || t('Failed to remove background'))
}
} else {
message.error(result.error || '去背景失败')
message.error(result.error || t('Failed to remove background'))
}
} else {
message.error(response.data?.error || response.data?.message || '去背景失败')
message.error(response.data?.error || response.data?.message || t('Failed to remove background'))
}
} catch (error: any) {
let errorMessage = '去背景失败'
let errorMessage = t('Failed to remove background')
if (error.response?.data?.error) {
errorMessage = error.response.data.error
} else if (error.message) {
@ -596,7 +596,7 @@ const handleDownload = async () => {
// blob URL使
} catch (error) {
console.error('下载失败:', error)
message.error('下载失败')
message.error(t('Failed to download image'))
}
}
@ -789,12 +789,12 @@ const handleUrlPaste = async (event: ClipboardEvent) => {
const handleUrlSubmit = async () => {
const url = imageUrl.value.trim()
if (!url) {
message.warning('请输入图片URL')
message.warning(t('Please enter an image URL'))
return
}
if (!isValidImageUrl(url)) {
message.warning('请输入有效的图片URL')
message.warning(t('Please enter a valid image URL'))
return
}
@ -813,14 +813,14 @@ const handleUrlSubmit = async () => {
const validTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp']
if (!validTypes.includes(blob.type)) {
message.warning('不支持的图片格式,请使用 JPG、PNG 或 WebP')
message.warning(t('Unsupported image format. Please use JPG, PNG, or WebP'))
processing.value = false
return
}
const maxSize = 10 * 1024 * 1024
if (blob.size > maxSize) {
message.warning('图片大小超过 10MB 限制')
message.warning(t('Image size exceeds 10MB limit'))
processing.value = false
return
}
@ -842,17 +842,17 @@ const handleUrlSubmit = async () => {
await handleRemoveBackground()
} catch (error) {
console.error('图片压缩失败:', error)
message.error('图片处理失败,请重试')
message.error(t('Image processing failed, please try again'))
processing.value = false
}
} catch (error: any) {
console.error('加载图片URL失败:', error)
let errorMessage = '加载图片URL失败'
let errorMessage = t('Failed to load image from URL')
if (error.message?.includes('CORS')) {
errorMessage = 'CORS错误。图片服务器不允许跨域访问。'
errorMessage = t('CORS error. The image server does not allow cross-origin access.')
} else if (error.message?.includes('Failed to load')) {
errorMessage = '加载图片失败。请检查URL并重试。'
errorMessage = t('Failed to load image. Please check the URL and try again.')
}
message.error(errorMessage)
@ -955,8 +955,8 @@ onUnmounted(() => {
</div>
<div class="header-right">
<n-space :size="12">
<n-button quaternary @click="handleSignup">注册</n-button>
<n-button type="primary" @click="handleLogin" class="login-btn">登录</n-button>
<n-button quaternary @click="handleSignup">{{ t('Sign up') }}</n-button>
<n-button type="primary" @click="handleLogin" class="login-btn">{{ t('Login') }}</n-button>
</n-space>
</div>
</div>
@ -974,12 +974,12 @@ onUnmounted(() => {
<div class="tool-page">
<div class="page-header">
<h2>去除背景</h2>
<h2>{{ t('Remove Background') }}</h2>
<div v-if="uploadedImage" class="toolbar-actions">
<button v-if="resultImage" class="toolbar-btn" @click="handleDownload" title="下载">
<button v-if="resultImage" class="toolbar-btn" @click="handleDownload" :title="t('Download')">
<i class="fa fa-download"></i>
</button>
<button class="toolbar-btn" @click="resetUpload" title="更换图片">
<button class="toolbar-btn" @click="resetUpload" :title="t('Change Image')">
<i class="fa fa-refresh"></i>
</button>
</div>
@ -992,11 +992,11 @@ onUnmounted(() => {
<div class="upload-content">
<button type="button" class="upload-btn" @click="triggerFileInput" :disabled="processing">
<i class="fa fa-upload"></i>
<span>上传图片</span>
<span>{{ t('Upload Image') }}</span>
</button>
<div class="divider">
<span></span>
<span>{{ t('or') }}</span>
</div>
<div class="url-input-wrapper" @click.stop>
@ -1005,19 +1005,19 @@ onUnmounted(() => {
v-model="imageUrl"
type="text"
class="url-input"
placeholder="粘贴图片URL"
:placeholder="t('Paste image URL here')"
@keyup.enter="handleUrlSubmit"
@paste="handleUrlPaste"
:disabled="processing"
/>
</div>
<p class="upload-hint">拖放图片到任意位置或直接粘贴图片</p>
<p class="upload-format-hint">支持 JPGPNGWebP 格式</p>
<p class="upload-hint">{{ t('Drag and drop your image anywhere, or paste image directly') }}</p>
<p class="upload-format-hint">{{ t('Supports JPG, PNG, WebP formats') }}</p>
</div>
<div v-if="processing" class="upload-processing-overlay">
<div class="spinner"></div>
<p>加载图片URL中...</p>
<p>{{ t('Loading image from URL...') }}</p>
</div>
</div>
@ -1025,10 +1025,10 @@ onUnmounted(() => {
<div class="comparison-view" v-if="resultImage">
<div class="comparison-container" ref="comparisonContainerRef">
<div class="comparison-image original-image" :style="{ clipPath: `inset(0 ${100 - splitPosition}% 0 0)` }">
<img ref="originalImageRef" :src="uploadedImageUrl" alt="原图" @load="adjustContainerSize" />
<img ref="originalImageRef" :src="uploadedImageUrl" :alt="t('Original')" @load="adjustContainerSize" />
</div>
<div class="comparison-image result-image" :style="{ clipPath: `inset(0 0 0 ${splitPosition}%)` }">
<img ref="resultImageRef" :src="resultImageUrl" alt="结果" @load="adjustContainerSize" />
<img ref="resultImageRef" :src="resultImageUrl" :alt="t('Background Removed')" @load="adjustContainerSize" />
</div>
<div class="split-line" :class="{ dragging: isDraggingSplitLine }" :style="{ left: `${splitPosition}%` }" @mousedown.prevent.stop="handleSplitLineMouseDown">
<div class="split-line-handle">
@ -1040,11 +1040,11 @@ onUnmounted(() => {
<div v-else class="single-image-view">
<div class="image-wrapper" ref="singleImageWrapperRef">
<div class="single-image-container">
<img ref="singleImageRef" :src="uploadedImageUrl" alt="原图" @load="adjustContainerSize" />
<img ref="singleImageRef" :src="uploadedImageUrl" :alt="t('Original')" @load="adjustContainerSize" />
</div>
<div v-if="processing" class="processing-overlay">
<div class="spinner"></div>
<p>处理中...</p>
<p>{{ t('Processing...') }}</p>
</div>
</div>
</div>
@ -1057,7 +1057,7 @@ onUnmounted(() => {
type="button"
class="history-item add-button"
@click.stop="triggerFileInput"
title="添加新图片"
:title="t('Add new image')"
>
<i class="fa fa-plus"></i>
</button>
@ -1075,8 +1075,8 @@ onUnmounted(() => {
type="button"
class="history-delete-btn"
@click.stop="removeHistoryItem(index)"
title="删除"
:aria-label="'删除'"
:title="t('Delete')"
:aria-label="t('Delete')"
></button>
</div>
</div>
@ -1223,12 +1223,12 @@ onUnmounted(() => {
<div class="tool-page">
<div class="page-header">
<h2>去除背景</h2>
<h2>{{ t('Remove Background') }}</h2>
<div v-if="uploadedImage" class="toolbar-actions">
<button v-if="resultImage" class="toolbar-btn" @click="handleDownload" title="下载">
<button v-if="resultImage" class="toolbar-btn" @click="handleDownload" :title="t('Download')">
<i class="fa fa-download"></i>
</button>
<button class="toolbar-btn" @click="resetUpload" title="更换图片">
<button class="toolbar-btn" @click="resetUpload" :title="t('Change Image')">
<i class="fa fa-refresh"></i>
</button>
</div>
@ -1241,11 +1241,11 @@ onUnmounted(() => {
<div class="upload-content">
<button type="button" class="upload-btn" @click="triggerFileInput" :disabled="processing">
<i class="fa fa-upload"></i>
<span>上传图片</span>
<span>{{ t('Upload Image') }}</span>
</button>
<div class="divider">
<span></span>
<span>{{ t('or') }}</span>
</div>
<div class="url-input-wrapper" @click.stop>
@ -1254,19 +1254,19 @@ onUnmounted(() => {
v-model="imageUrl"
type="text"
class="url-input"
placeholder="粘贴图片URL"
:placeholder="t('Paste image URL here')"
@keyup.enter="handleUrlSubmit"
@paste="handleUrlPaste"
:disabled="processing"
/>
</div>
<p class="upload-hint">拖放图片到任意位置或直接粘贴图片</p>
<p class="upload-format-hint">支持 JPGPNGWebP 格式</p>
<p class="upload-hint">{{ t('Drag and drop your image anywhere, or paste image directly') }}</p>
<p class="upload-format-hint">{{ t('Supports JPG, PNG, WebP formats') }}</p>
</div>
<div v-if="processing" class="upload-processing-overlay">
<div class="spinner"></div>
<p>加载图片URL中...</p>
<p>{{ t('Loading image from URL...') }}</p>
</div>
</div>
@ -1274,10 +1274,10 @@ onUnmounted(() => {
<div class="comparison-view" v-if="resultImage">
<div class="comparison-container" ref="comparisonContainerRef">
<div class="comparison-image original-image" :style="{ clipPath: `inset(0 ${100 - splitPosition}% 0 0)` }">
<img ref="originalImageRef" :src="uploadedImageUrl" alt="原图" @load="adjustContainerSize" />
<img ref="originalImageRef" :src="uploadedImageUrl" :alt="t('Original')" @load="adjustContainerSize" />
</div>
<div class="comparison-image result-image" :style="{ clipPath: `inset(0 0 0 ${splitPosition}%)` }">
<img ref="resultImageRef" :src="resultImageUrl" alt="结果" @load="adjustContainerSize" />
<img ref="resultImageRef" :src="resultImageUrl" :alt="t('Background Removed')" @load="adjustContainerSize" />
</div>
<div class="split-line" :class="{ dragging: isDraggingSplitLine }" :style="{ left: `${splitPosition}%` }" @mousedown.prevent.stop="handleSplitLineMouseDown">
<div class="split-line-handle">
@ -1289,11 +1289,11 @@ onUnmounted(() => {
<div v-else class="single-image-view">
<div class="image-wrapper" ref="singleImageWrapperRef">
<div class="single-image-container">
<img ref="singleImageRef" :src="uploadedImageUrl" alt="原图" @load="adjustContainerSize" />
<img ref="singleImageRef" :src="uploadedImageUrl" :alt="t('Original')" @load="adjustContainerSize" />
</div>
<div v-if="processing" class="processing-overlay">
<div class="spinner"></div>
<p>处理中...</p>
<p>{{ t('Processing...') }}</p>
</div>
</div>
</div>
@ -1306,7 +1306,7 @@ onUnmounted(() => {
type="button"
class="history-item add-button"
@click.stop="triggerFileInput"
title="添加新图片"
:title="t('Add new image')"
>
<i class="fa fa-plus"></i>
</button>
@ -1324,8 +1324,8 @@ onUnmounted(() => {
type="button"
class="history-delete-btn"
@click.stop="removeHistoryItem(index)"
title="删除"
:aria-label="'删除'"
:title="t('Delete')"
:aria-label="t('Delete')"
></button>
</div>
</div>
@ -1909,7 +1909,6 @@ onUnmounted(() => {
font-weight: 600;
color: #64748b;
margin: 0 0 16px 0;
text-transform: uppercase;
letter-spacing: 0.05em;
}