feat: 修复AccountForm组件中所有遗漏的国际化内容

- 添加60+个新的翻译键到三语言文件
- 国际化所有placeholder属性
- 国际化按钮文本和标签
- 国际化错误消息和验证提示
- 国际化OAuth步骤描述文本
- 国际化Claude功能描述和配置说明
- 确保三种语言完整覆盖所有UI文本
This commit is contained in:
Wangnov
2025-09-09 17:34:30 +08:00
parent be7416386f
commit 30acf4a374
4 changed files with 232 additions and 40 deletions

View File

@@ -710,14 +710,14 @@
<input
v-model="mapping.from"
class="form-input flex-1 border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 dark:placeholder-gray-400"
placeholder="原始模型名称"
:placeholder="t('accountForm.originalModelNamePlaceholder')"
type="text"
/>
<i class="fas fa-arrow-right text-gray-400 dark:text-gray-500" />
<input
v-model="mapping.to"
class="form-input flex-1 border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 dark:placeholder-gray-400"
placeholder="映射后的模型名称"
:placeholder="t('accountForm.mappedModelNamePlaceholder')"
type="text"
/>
<button
@@ -786,12 +786,12 @@
<div>
<label class="mb-3 block text-sm font-semibold text-gray-700 dark:text-gray-300"
>自定义 User-Agent (可选)</label
>{{ t('accountForm.customUserAgentOptional') }}</label
>
<input
v-model="form.userAgent"
class="form-input w-full border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 dark:placeholder-gray-400"
placeholder="留空则透传客户端 User-Agent"
:placeholder="t('accountForm.userAgentPlaceholder')"
type="text"
/>
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
@@ -862,7 +862,7 @@
</div>
<p class="mt-2 text-xs text-gray-500 dark:text-gray-400">
<i class="fas fa-info-circle mr-1" />
Pro 账号不支持 Claude Opus 4 模型
{{ t('accountForm.claudeProLimitation') }}
</p>
</div>
@@ -876,10 +876,10 @@
/>
<div class="ml-3">
<span class="text-sm font-medium text-gray-700 dark:text-gray-300">
5小时使用量接近限制时自动停止调度
{{ t('accountForm.claude5HourLimitDesc') }}
</span>
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
当系统检测到账户接近5小时使用限制时自动暂停调度该账户。进入新的时间窗口后会自动恢复调度。
{{ t('accountForm.claude5HourLimitExplanation') }}
</p>
</div>
</label>
@@ -895,15 +895,15 @@
/>
<div class="ml-3">
<span class="text-sm font-medium text-gray-700 dark:text-gray-300">
使用统一 Claude Code 版本
{{ t('accountForm.useUnifiedClaudeVersion') }}
</span>
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
开启后将使用从真实 Claude Code 客户端捕获的统一 User-Agent提高兼容性
{{ t('accountForm.unifiedVersionDesc') }}
</p>
<div v-if="unifiedUserAgent" class="mt-1">
<div class="flex items-center justify-between">
<p class="text-xs text-green-600 dark:text-green-400">
💡 当前统一版本:{{ unifiedUserAgent }}
{{ t('accountForm.currentUnifiedVersion') }} {{ unifiedUserAgent }}
</p>
<button
class="ml-2 text-xs text-red-500 hover:text-red-700 dark:text-red-400 dark:hover:text-red-300"
@@ -919,11 +919,11 @@
</div>
<div v-else class="mt-1">
<p class="text-xs text-gray-500 dark:text-gray-400">
⏳ 等待从 Claude Code 客户端捕获 User-Agent
{{ t('accountForm.waitingUserAgent') }}
</p>
<p class="mt-1 text-xs text-gray-400 dark:text-gray-500">
💡 提示:如果长时间未能捕获,请确认有 Claude Code 客户端正在使用此账户,
或联系开发者检查 User-Agent 格式是否发生变化
{{ t('accountForm.userAgentTip') }}
{{ t('accountForm.contactDeveloper') }}
</p>
</div>
</div>
@@ -941,10 +941,10 @@
/>
<div class="ml-3 flex-1">
<span class="text-sm font-medium text-gray-700 dark:text-gray-300">
使用统一的客户端标识
{{ t('accountForm.useUnifiedClientId') }}
</span>
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
开启后将使用固定的客户端标识,使所有请求看起来来自同一个客户端,减少特征
{{ t('accountForm.unifiedClientIdDesc') }}
</p>
<div v-if="form.useUnifiedClientId" class="mt-3">
<div
@@ -952,7 +952,7 @@
>
<div class="mb-2 flex items-center justify-between">
<span class="text-xs font-medium text-gray-600 dark:text-gray-400"
>客户端标识 ID</span
>{{ t('accountForm.clientIdLabel') }}</span
>
<button
class="rounded-md bg-blue-100 px-2.5 py-1 text-xs font-medium text-blue-700 transition-colors hover:bg-blue-200 dark:bg-blue-900/30 dark:text-blue-400 dark:hover:bg-blue-900/50"
@@ -980,7 +980,7 @@
</div>
<p class="mt-2 text-xs text-gray-500 dark:text-gray-400">
<i class="fas fa-info-circle mr-1 text-blue-500" />
此ID将替换请求中的user_id客户端部分保留session部分用于粘性会话
{{ t('accountForm.clientIdReplaceDesc') }}
</p>
</div>
</div>
@@ -991,7 +991,7 @@
<!-- 所有平台的优先级设置 -->
<div>
<label class="mb-3 block text-sm font-semibold text-gray-700 dark:text-gray-300"
>调度优先级 (1-100)</label
>{{ t('accountForm.schedulePriorityLabel') }}</label
>
<input
v-model.number="form.priority"
@@ -1268,7 +1268,7 @@
class="text-xs text-blue-600 hover:text-blue-700"
@click="regenerateSetupTokenAuthUrl"
>
<i class="fas fa-sync-alt mr-1" />重新生成
<i class="fas fa-sync-alt mr-1" />{{ t('accountForm.regenerateBtn') }}
</button>
</div>
</div>
@@ -1297,7 +1297,7 @@
>
<p class="text-xs text-yellow-800 dark:text-yellow-300">
<i class="fas fa-exclamation-triangle mr-1" />
<strong>注意:</strong
<strong>{{ t('accountForm.attentionLabel') }}</strong
>如果您设置了代理,请确保浏览器也使用相同的代理访问授权页面。
</p>
</div>
@@ -1332,7 +1332,7 @@
<textarea
v-model="setupTokenAuthCode"
class="form-input w-full resize-none border-gray-300 font-mono text-sm dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 dark:placeholder-gray-400"
placeholder="粘贴从Claude Code授权页面获取的Authorization Code..."
:placeholder="t('accountForm.authCodePlaceholder')"
rows="3"
/>
</div>
@@ -1356,7 +1356,7 @@
type="button"
@click="oauthStep = 1"
>
上一步
{{ t('accountForm.previousStepBtn') }}
</button>
<button
class="btn btn-primary flex-1 px-6 py-3 font-semibold"
@@ -1695,10 +1695,10 @@
<input
v-model="form.apiKey"
class="form-input w-full"
placeholder="留空表示不更新"
:placeholder="t('accountForm.leaveEmptyNoUpdate')"
type="password"
/>
<p class="mt-1 text-xs text-gray-500">留空表示不更新 API Key</p>
<p class="mt-1 text-xs text-gray-500">{{ t('accountForm.leaveEmptyNoUpdateKey') }}</p>
</div>
<!-- {{ t('accountForm.quotaManagement') }} -->
@@ -2081,18 +2081,18 @@
v-model="form.apiKey"
class="form-input w-full border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 dark:placeholder-gray-400"
:class="{ 'border-red-500': errors.apiKey }"
placeholder="留空表示不更新"
:placeholder="t('accountForm.leaveEmptyNoUpdate')"
type="password"
/>
<p v-if="errors.apiKey" class="mt-1 text-xs text-red-500">
{{ errors.apiKey }}
</p>
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">留空表示不更新 API Key</p>
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">{{ t('accountForm.leaveEmptyNoUpdateKey') }}</p>
</div>
<div>
<label class="mb-3 block text-sm font-semibold text-gray-700 dark:text-gray-300"
>支持的模型</label
>{{ t('accountForm.supportedModelsLabel') }}</label
>
<div class="flex flex-wrap gap-2">
<label
@@ -2139,7 +2139,7 @@
<i class="fas fa-key text-sm text-white" />
</div>
<div>
<h5 class="mb-2 font-semibold text-amber-900 dark:text-amber-300">更新 Token</h5>
<h5 class="mb-2 font-semibold text-amber-900 dark:text-amber-300">{{ t('accountForm.updateTokenLabel') }}</h5>
<p class="mb-2 text-sm text-amber-800 dark:text-amber-300">
可以更新 Access Token 和 Refresh Token。为了安全起见不会显示当前的 Token 值。
</p>
@@ -2150,24 +2150,24 @@
<div class="space-y-4">
<div>
<label class="mb-3 block text-sm font-semibold text-gray-700 dark:text-gray-300"
>新的 Access Token</label
>{{ t('accountForm.newAccessTokenLabel') }}</label
>
<textarea
v-model="form.accessToken"
class="form-input w-full resize-none border-gray-300 font-mono text-xs dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 dark:placeholder-gray-400"
placeholder="留空表示不更新..."
:placeholder="t('accountForm.leaveEmptyNoUpdateToken')"
rows="4"
/>
</div>
<div>
<label class="mb-3 block text-sm font-semibold text-gray-700 dark:text-gray-300"
>新的 Refresh Token</label
>{{ t('accountForm.newRefreshTokenLabel') }}</label
>
<textarea
v-model="form.refreshToken"
class="form-input w-full resize-none border-gray-300 font-mono text-xs dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 dark:placeholder-gray-400"
placeholder="留空表示不更新..."
:placeholder="t('accountForm.leaveEmptyNoUpdateToken')"
rows="4"
/>
</div>
@@ -2556,7 +2556,7 @@ const copySetupTokenAuthUrl = async () => {
showToast(t('accountForm.copyFailed'), 'error')
}
} catch (err) {
showToast('复制失败,请手动复制', 'error')
showToast(t('accountForm.copyFailedManual'), 'error')
}
document.body.removeChild(textarea)
@@ -2730,7 +2730,7 @@ const createAccount = async () => {
hasError = true
}
if (!form.value.apiKey || form.value.apiKey.trim() === '') {
errors.value.apiKey = '请填写 API Key'
errors.value.apiKey = t('accountForm.apiKeyRequired')
hasError = true
}
} else if (form.value.platform === 'bedrock') {
@@ -2758,7 +2758,7 @@ const createAccount = async () => {
hasError = true
}
if (!form.value.apiKey || form.value.apiKey.trim() === '') {
errors.value.apiKey = '请填写 API Key'
errors.value.apiKey = t('accountForm.apiKeyRequired')
hasError = true
}
} else if (form.value.addType === 'manual') {
@@ -2766,14 +2766,14 @@ const createAccount = async () => {
if (form.value.platform === 'openai') {
// OpenAI 平台必须有 Refresh Token
if (!form.value.refreshToken || form.value.refreshToken.trim() === '') {
errors.value.refreshToken = '请填写 Refresh Token'
errors.value.refreshToken = t('accountForm.refreshTokenRequired')
hasError = true
}
// Access Token 可选,如果没有会通过 Refresh Token 获取
} else {
// 其他平台Gemini需要 Access Token
if (!form.value.accessToken || form.value.accessToken.trim() === '') {
errors.value.accessToken = '请填写 Access Token'
errors.value.accessToken = t('accountForm.accessTokenRequired')
hasError = true
}
}

View File

@@ -1628,6 +1628,70 @@ export default {
createNewGroupOption: 'Create new group option',
// Manual Token Input Tips
credentialsFromFile: 'credentials from file.'
credentialsFromFile: 'credentials from file.',
// Placeholder texts
originalModelNamePlaceholder: 'Original model name',
mappedModelNamePlaceholder: 'Mapped model name',
userAgentPlaceholder: 'Leave empty to pass through client User-Agent',
authCodePlaceholder: 'Paste Authorization Code obtained from Claude Code auth page...',
leaveEmptyNoUpdate: 'Leave empty for no update',
leaveEmptyNoUpdateKey: 'Leave empty for no API Key update',
leaveEmptyNoUpdateToken: 'Leave empty for no update...',
// Labels and descriptions
customUserAgentOptional: 'Custom User-Agent (optional)',
clientIdLabel: 'Client ID',
schedulePriorityLabel: 'Schedule Priority (1-100)',
attentionLabel: 'Attention:',
supportedModelsLabel: 'Supported Models',
newAccessTokenLabel: 'New Access Token',
newRefreshTokenLabel: 'New Refresh Token',
updateTokenLabel: 'Update Token',
// Button texts
regenerateBtn: 'Regenerate',
previousStepBtn: 'Previous Step',
// Descriptive texts
claudeProLimitation: 'Pro accounts do not support Claude Opus 4 model',
claude5HourLimitDesc: 'Auto-stop scheduling when approaching 5-hour usage limit',
claude5HourLimitExplanation: 'When system detects account approaching 5-hour usage limit, automatically pause scheduling for this account. Will resume automatically when entering new time window.',
useUnifiedClaudeVersion: 'Use unified Claude Code version',
unifiedVersionDesc: 'When enabled, will use unified User-Agent captured from real Claude Code client, improving compatibility',
currentUnifiedVersion: '💡 Current unified version:',
waitingUserAgent: '⏳ Waiting to capture User-Agent from Claude Code client',
userAgentTip: '💡 Tip: If unable to capture for a long time, please confirm that Claude Code client is using this account,',
contactDeveloper: 'or contact developer to check if User-Agent format has changed',
useUnifiedClientId: 'Use unified client identifier',
unifiedClientIdDesc: 'When enabled, will use fixed client identifier, making all requests appear from same client, reducing fingerprinting',
clientIdReplaceDesc: 'This ID will replace the user_id client part in requests, retaining session part for sticky sessions',
// OAuth step texts
step1GenerateAuthLink: 'Step 1: Generate Authorization Link',
clickButtonGenerate: 'Click button below to generate authorization link',
copyLinkTitle: 'Copy Link',
step2AccessAndAuth: 'Step 2: Access Link and Authorize',
openInBrowser: 'Open link in browser and complete authorization',
browserAuthDesc: 'Please open the authorization link in a new tab, login to your Claude account and authorize Claude Code.',
proxyNotice: 'If you have set up a proxy, please ensure your browser also uses the same proxy to access the authorization page.',
step3InputAuthCode: 'Step 3: Input Authorization Code',
inputAuthCodeTitle: 'Input Authorization Code',
authCompleteDesc: 'After authorization is complete, copy Authorization Code from the return page and paste it into the input box below:',
pasteAuthCodeDesc: 'Please paste the Authorization Code copied from Claude Code authorization page',
// AWS region reference
awsRegionRef: 'Common AWS regions reference:',
// Error messages
apiKeyRequired: 'Please enter API Key',
refreshTokenRequired: 'Please enter Refresh Token',
accessTokenRequired: 'Please enter Access Token',
copyFailedManual: 'Copy failed, please copy manually',
// Form descriptions
modelSupportDesc: 'Leave empty to support all models. If models are specified, requests with models not in the list will not be scheduled to this account',
modelTypeSelectionDesc: 'Select model types supported by this deployment',
userAgentDesc: 'When empty, will automatically use client User-Agent, only fill when need to fix specific UA'
}
}

View File

@@ -1628,6 +1628,70 @@ export default {
createNewGroupOption: '新建分组选项',
// 手动输入Token提示
credentialsFromFile: '文件中的凭证。'
credentialsFromFile: '文件中的凭证。',
// Placeholder 文本
originalModelNamePlaceholder: '原始模型名称',
mappedModelNamePlaceholder: '映射后的模型名称',
userAgentPlaceholder: '留空则透传客户端 User-Agent',
authCodePlaceholder: '粘贴从Claude Code授权页面获取的Authorization Code...',
leaveEmptyNoUpdate: '留空表示不更新',
leaveEmptyNoUpdateKey: '留空表示不更新 API Key',
leaveEmptyNoUpdateToken: '留空表示不更新...',
// 标签和描述
customUserAgentOptional: '自定义 User-Agent (可选)',
clientIdLabel: '客户端标识 ID',
schedulePriorityLabel: '调度优先级 (1-100)',
attentionLabel: '注意:',
supportedModelsLabel: '支持的模型',
newAccessTokenLabel: '新的 Access Token',
newRefreshTokenLabel: '新的 Refresh Token',
updateTokenLabel: '更新 Token',
// 按钮文本
regenerateBtn: '重新生成',
previousStepBtn: '上一步',
// 描述性文本
claudeProLimitation: 'Pro 账号不支持 Claude Opus 4 模型',
claude5HourLimitDesc: '5小时使用量接近限制时自动停止调度',
claude5HourLimitExplanation: '当系统检测到账户接近5小时使用限制时自动暂停调度该账户。进入新的时间窗口后会自动恢复调度。',
useUnifiedClaudeVersion: '使用统一 Claude Code 版本',
unifiedVersionDesc: '开启后将使用从真实 Claude Code 客户端捕获的统一 User-Agent提高兼容性',
currentUnifiedVersion: '💡 当前统一版本:',
waitingUserAgent: '⏳ 等待从 Claude Code 客户端捕获 User-Agent',
userAgentTip: '💡 提示:如果长时间未能捕获,请确认有 Claude Code 客户端正在使用此账户,',
contactDeveloper: '或联系开发者检查 User-Agent 格式是否发生变化',
useUnifiedClientId: '使用统一的客户端标识',
unifiedClientIdDesc: '开启后将使用固定的客户端标识,使所有请求看起来来自同一个客户端,减少特征',
clientIdReplaceDesc: '此ID将替换请求中的user_id客户端部分保留session部分用于粘性会话',
// OAuth 步骤文本
step1GenerateAuthLink: '步骤1: 生成授权链接',
clickButtonGenerate: '点击下方按钮生成授权链接',
copyLinkTitle: '复制链接',
step2AccessAndAuth: '步骤2: 访问链接并授权',
openInBrowser: '在浏览器中打开链接并完成授权',
browserAuthDesc: '请在新标签页中打开授权链接,登录您的 Claude 账户并授权 Claude Code。',
proxyNotice: '如果您设置了代理,请确保浏览器也使用相同的代理访问授权页面。',
step3InputAuthCode: '步骤3: 输入授权码',
inputAuthCodeTitle: '输入 Authorization Code',
authCompleteDesc: '授权完成后,从返回页面复制 Authorization Code并粘贴到下方输入框',
pasteAuthCodeDesc: '请粘贴从 Claude Code 授权页面复制的 Authorization Code',
// AWS 区域参考
awsRegionRef: '常用 AWS 区域参考:',
// 错误信息
apiKeyRequired: '请填写 API Key',
refreshTokenRequired: '请填写 Refresh Token',
accessTokenRequired: '请填写 Access Token',
copyFailedManual: '复制失败,请手动复制',
// 表单描述
modelSupportDesc: '留空表示支持所有模型。如果指定模型,请求中的模型不在列表内将不会调度到此账号',
modelTypeSelectionDesc: '选择此部署支持的模型类型',
userAgentDesc: '留空时将自动使用客户端的 User-Agent仅在需要固定特定 UA 时填写'
}
}

View File

@@ -1628,6 +1628,70 @@ export default {
createNewGroupOption: '新建群組選項',
// 手動輸入Token提示
credentialsFromFile: '檔案中的憑證。'
credentialsFromFile: '檔案中的憑證。',
// Placeholder 文字
originalModelNamePlaceholder: '原始模型名稱',
mappedModelNamePlaceholder: '映射後的模型名稱',
userAgentPlaceholder: '留空則透傳用戶端 User-Agent',
authCodePlaceholder: '貼上Claude Code授權頁面獲取的Authorization Code...',
leaveEmptyNoUpdate: '留空表示不更新',
leaveEmptyNoUpdateKey: '留空表示不更新 API Key',
leaveEmptyNoUpdateToken: '留空表示不更新...',
// 標籤和描述
customUserAgentOptional: '自定義 User-Agent (可選)',
clientIdLabel: '用戶端標識 ID',
schedulePriorityLabel: '調度優先級 (1-100)',
attentionLabel: '注意:',
supportedModelsLabel: '支援的模型',
newAccessTokenLabel: '新的 Access Token',
newRefreshTokenLabel: '新的 Refresh Token',
updateTokenLabel: '更新 Token',
// 按鈕文字
regenerateBtn: '重新產生',
previousStepBtn: '上一步',
// 描述性文字
claudeProLimitation: 'Pro 帳戶不支援 Claude Opus 4 模型',
claude5HourLimitDesc: '5小時使用量接近限制時自動停止調度',
claude5HourLimitExplanation: '當系統檢測到帳戶接近5小時使用限制時自動暫停調度該帳戶。進入新的時間視窗後會自動恢復調度。',
useUnifiedClaudeVersion: '使用統一 Claude Code 版本',
unifiedVersionDesc: '開啟後將使用從真實 Claude Code 用戶端捕獲的統一 User-Agent提高相容性',
currentUnifiedVersion: '💡 目前統一版本:',
waitingUserAgent: '⏳ 等待從 Claude Code 用戶端捕獲 User-Agent',
userAgentTip: '💡 提示:如果長時間未能捕獲,請確認有 Claude Code 用戶端正在使用此帳戶,',
contactDeveloper: '或聯繫開發者檢查 User-Agent 格式是否發生變化',
useUnifiedClientId: '使用統一的用戶端標識',
unifiedClientIdDesc: '開啟後將使用固定的用戶端標識,使所有請求看起來來自同一個用戶端,減少特徵',
clientIdReplaceDesc: '此ID將替換請求中的user_id用戶端部分保留session部分用於黏性工作階段',
// OAuth 步驟文字
step1GenerateAuthLink: '步驟1: 產生授權連結',
clickButtonGenerate: '點擊下方按鈕產生授權連結',
copyLinkTitle: '複製連結',
step2AccessAndAuth: '步驟2: 訪問連結並授權',
openInBrowser: '在瀏覽器中開啟連結並完成授權',
browserAuthDesc: '請在新分頁中開啟授權連結,登錄您的 Claude 帳戶並授權 Claude Code。',
proxyNotice: '如果您設定了代理,請確保瀏覽器也使用相同的代理訪問授權頁面。',
step3InputAuthCode: '步驟3: 輸入授權碼',
inputAuthCodeTitle: '輸入 Authorization Code',
authCompleteDesc: '授權完成後,從返回頁面複製 Authorization Code並貼上到下方輸入框',
pasteAuthCodeDesc: '請貼上從 Claude Code 授權頁面複製的 Authorization Code',
// AWS 區域參考
awsRegionRef: '常用 AWS 區域參考:',
// 錯誤訊息
apiKeyRequired: '請填寫 API Key',
refreshTokenRequired: '請填寫 Refresh Token',
accessTokenRequired: '請填寫 Access Token',
copyFailedManual: '複製失敗,請手動複製',
// 表單描述
modelSupportDesc: '留空表示支援所有模型。如果指定模型,請求中的模型不在列表內將不會調度到此帳戶',
modelTypeSelectionDesc: '選擇此部署支援的模型類型',
userAgentDesc: '留空時將自動使用用戶端的 User-Agent僅在需要固定特定 UA 時填寫'
}
}