mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-22 16:43:35 +00:00
feat: 完成多个组件的国际化支持与文本替换
- 更新 AccountForm.vue 中的占位符文本为 i18n 语言包中的键 - 修改 ConfirmModal.vue 中的确认和取消按钮文本为 i18n 语言包中的键 - 更新 CustomDropdown.vue 中的占位符文本为 i18n 语言包中的键 - 修改 app.js 中的应用标题为英文版本 - 更新 router/index.js 中的日志输出为英文 - 在 accounts.js 和 apiKeys.js 中的错误处理信息中引入 i18n 键以提升多语言一致性 - 更新 dashboard.js 中的系统状态和错误日志为 i18n 键 - 在 DashboardView.vue 中的多个文本替换为 i18n 语言包中的键
This commit is contained in:
@@ -1847,14 +1847,14 @@
|
||||
<input
|
||||
v-model="mapping.from"
|
||||
class="form-input flex-1"
|
||||
placeholder="原始模型名称"
|
||||
:placeholder="t('accountForm.originalModelName')"
|
||||
type="text"
|
||||
/>
|
||||
<i class="fas fa-arrow-right text-gray-400" />
|
||||
<input
|
||||
v-model="mapping.to"
|
||||
class="form-input flex-1"
|
||||
placeholder="映射后的模型名称"
|
||||
:placeholder="t('accountForm.mappedModelName')"
|
||||
type="text"
|
||||
/>
|
||||
<button
|
||||
@@ -1874,7 +1874,7 @@
|
||||
@click="addModelMapping"
|
||||
>
|
||||
<i class="fas fa-plus mr-2" />
|
||||
添加模型映射
|
||||
{{ t('accountForm.addModelMapping') }}
|
||||
</button>
|
||||
|
||||
<!-- 快捷添加按钮 -->
|
||||
|
||||
@@ -25,13 +25,13 @@
|
||||
class="flex-1 rounded-xl bg-gray-100 px-4 py-2.5 font-medium text-gray-700 transition-colors hover:bg-gray-200 dark:bg-gray-700 dark:text-gray-200 dark:hover:bg-gray-600"
|
||||
@click="$emit('cancel')"
|
||||
>
|
||||
{{ cancelText }}
|
||||
{{ cancelLabel }}
|
||||
</button>
|
||||
<button
|
||||
class="flex-1 rounded-xl bg-gradient-to-r from-yellow-500 to-orange-500 px-4 py-2.5 font-medium text-white shadow-sm transition-colors hover:from-yellow-600 hover:to-orange-600"
|
||||
@click="$emit('confirm')"
|
||||
>
|
||||
{{ confirmText }}
|
||||
{{ confirmLabel }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -40,11 +40,12 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
defineProps({
|
||||
const props = defineProps({
|
||||
show: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
@@ -59,14 +60,17 @@ defineProps({
|
||||
},
|
||||
confirmText: {
|
||||
type: String,
|
||||
default: () => t('common.confirmModal.continue')
|
||||
default: ''
|
||||
},
|
||||
cancelText: {
|
||||
type: String,
|
||||
default: () => t('common.confirmModal.cancel')
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
|
||||
const confirmLabel = computed(() => props.confirmText || t('common.confirmModal.continue'))
|
||||
const cancelLabel = computed(() => props.cancelText || t('common.confirmModal.cancel'))
|
||||
|
||||
defineEmits(['confirm', 'cancel'])
|
||||
</script>
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<span
|
||||
class="select-none whitespace-nowrap text-sm font-medium text-gray-700 dark:text-gray-200"
|
||||
>
|
||||
{{ selectedLabel || placeholder }}
|
||||
{{ selectedLabel || placeholderText }}
|
||||
</span>
|
||||
<i
|
||||
:class="[
|
||||
@@ -80,7 +80,7 @@ const props = defineProps({
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: () => t('common.customDropdown.placeholder')
|
||||
default: ''
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
@@ -99,6 +99,8 @@ const triggerRef = ref(null)
|
||||
const dropdownRef = ref(null)
|
||||
const dropdownStyle = ref({})
|
||||
|
||||
const placeholderText = computed(() => props.placeholder || t('common.customDropdown.placeholder'))
|
||||
|
||||
const selectedLabel = computed(() => {
|
||||
const selected = props.options.find((opt) => opt.value === props.modelValue)
|
||||
return selected ? selected.label : ''
|
||||
|
||||
@@ -4,7 +4,7 @@ export const APP_CONFIG = {
|
||||
basePath: import.meta.env.VITE_APP_BASE_URL || (import.meta.env.DEV ? '/admin/' : '/web/admin/'),
|
||||
|
||||
// 应用标题
|
||||
title: import.meta.env.VITE_APP_TITLE || 'Claude Relay Service - 管理后台',
|
||||
title: import.meta.env.VITE_APP_TITLE || 'Claude Relay Service - Admin Panel',
|
||||
|
||||
// 是否为开发环境
|
||||
isDev: import.meta.env.DEV,
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createRouter, createWebHistory } from 'vue-router'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { APP_CONFIG } from '@/config/app'
|
||||
import { showToast } from '@/utils/toast'
|
||||
|
||||
// 路由懒加载
|
||||
const LoginView = () => import('@/views/LoginView.vue')
|
||||
@@ -150,7 +151,7 @@ router.beforeEach(async (to, from, next) => {
|
||||
const authStore = useAuthStore()
|
||||
const userStore = useUserStore()
|
||||
|
||||
console.log('路由导航:', {
|
||||
console.log('Router navigation:', {
|
||||
to: to.path,
|
||||
from: from.path,
|
||||
fullPath: to.fullPath,
|
||||
@@ -177,8 +178,6 @@ router.beforeEach(async (to, from, next) => {
|
||||
} catch (error) {
|
||||
// If the error is about disabled account, redirect to login with error
|
||||
if (error.message && error.message.includes('disabled')) {
|
||||
// Import showToast to display the error
|
||||
const { showToast } = await import('@/utils/toast')
|
||||
showToast(error.message, 'error')
|
||||
}
|
||||
return next('/user-login')
|
||||
|
||||
@@ -204,7 +204,9 @@ export const useAccountsStore = defineStore('accounts', () => {
|
||||
await fetchClaudeConsoleAccounts()
|
||||
return response.data
|
||||
} else {
|
||||
throw new Error(response.message || '创建Claude Console账户失败')
|
||||
throw new Error(
|
||||
response.message || i18n.global.t('common.errors.createClaudeConsoleAccountFailed')
|
||||
)
|
||||
}
|
||||
} catch (err) {
|
||||
error.value = err.message
|
||||
@@ -284,7 +286,9 @@ export const useAccountsStore = defineStore('accounts', () => {
|
||||
await fetchAzureOpenAIAccounts()
|
||||
return response.data
|
||||
} else {
|
||||
throw new Error(response.message || '创建Azure OpenAI账户失败')
|
||||
throw new Error(
|
||||
response.message || i18n.global.t('common.errors.createAzureOpenAIAccountFailed')
|
||||
)
|
||||
}
|
||||
} catch (err) {
|
||||
error.value = err.message
|
||||
@@ -344,7 +348,9 @@ export const useAccountsStore = defineStore('accounts', () => {
|
||||
await fetchClaudeConsoleAccounts()
|
||||
return response
|
||||
} else {
|
||||
throw new Error(response.message || '更新Claude Console账户失败')
|
||||
throw new Error(
|
||||
response.message || i18n.global.t('common.errors.updateClaudeConsoleAccountFailed')
|
||||
)
|
||||
}
|
||||
} catch (err) {
|
||||
error.value = err.message
|
||||
@@ -424,7 +430,9 @@ export const useAccountsStore = defineStore('accounts', () => {
|
||||
await fetchAzureOpenAIAccounts()
|
||||
return response
|
||||
} else {
|
||||
throw new Error(response.message || '更新Azure OpenAI账户失败')
|
||||
throw new Error(
|
||||
response.message || i18n.global.t('common.errors.updateAzureOpenAIAccountFailed')
|
||||
)
|
||||
}
|
||||
} catch (err) {
|
||||
error.value = err.message
|
||||
@@ -624,7 +632,9 @@ export const useAccountsStore = defineStore('accounts', () => {
|
||||
if (response.success) {
|
||||
return response.data // 返回整个对象,包含authUrl和sessionId
|
||||
} else {
|
||||
throw new Error(response.message || '生成Setup Token URL失败')
|
||||
throw new Error(
|
||||
response.message || i18n.global.t('common.errors.generateSetupTokenUrlFailed')
|
||||
)
|
||||
}
|
||||
} catch (err) {
|
||||
error.value = err.message
|
||||
@@ -642,7 +652,7 @@ export const useAccountsStore = defineStore('accounts', () => {
|
||||
if (response.success) {
|
||||
return response.data
|
||||
} else {
|
||||
throw new Error(response.message || '交换Setup Token授权码失败')
|
||||
throw new Error(response.message || i18n.global.t('common.errors.exchangeSetupTokenFailed'))
|
||||
}
|
||||
} catch (err) {
|
||||
error.value = err.message
|
||||
|
||||
@@ -145,7 +145,7 @@ export const useApiKeysStore = defineStore('apiKeys', () => {
|
||||
throw new Error(response.message || i18n.global.t('apiKeys.operationFailed'))
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取API Key统计失败:', err)
|
||||
console.error(i18n.global.t('common.errors.getApiKeyStatsFailed'), err)
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -170,7 +170,7 @@ export const useApiKeysStore = defineStore('apiKeys', () => {
|
||||
throw new Error(response.message || i18n.global.t('apiKeys.operationFailed'))
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取标签失败:', err)
|
||||
console.error(i18n.global.t('common.errors.getTagsFailed'), err)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -367,7 +367,7 @@ export const useApiStatsStore = defineStore('apistats', () => {
|
||||
})
|
||||
|
||||
if (validIds.length === 0) {
|
||||
throw new Error('所有 API Key 都无效')
|
||||
throw new Error(i18n.global.t('common.errors.allApiKeysInvalid'))
|
||||
}
|
||||
|
||||
apiIds.value = validIds
|
||||
|
||||
@@ -107,7 +107,7 @@ export const useAuthStore = defineStore('auth', () => {
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载OEM设置失败:', error)
|
||||
console.error(i18n.global.t('common.errors.loadOemSettingsFailed'), error)
|
||||
} finally {
|
||||
oemLoading.value = false
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ import { ref, computed } from 'vue'
|
||||
import { apiClient } from '@/config/api'
|
||||
import { showToast } from '@/utils/toast'
|
||||
import i18n from '@/i18n'
|
||||
import i18n from '@/i18n'
|
||||
|
||||
export const useDashboardStore = defineStore('dashboard', () => {
|
||||
// 状态
|
||||
@@ -43,7 +42,7 @@ export const useDashboardStore = defineStore('dashboard', () => {
|
||||
realtimeTPM: 0,
|
||||
metricsWindow: 5,
|
||||
isHistoricalMetrics: false,
|
||||
systemStatus: '正常',
|
||||
systemStatus: i18n.global.t('system.status.normal'),
|
||||
uptime: 0,
|
||||
systemTimezone: 8 // 默认 UTC+8
|
||||
})
|
||||
@@ -200,7 +199,9 @@ export const useDashboardStore = defineStore('dashboard', () => {
|
||||
realtimeTPM: realtimeMetrics.tpm || 0,
|
||||
metricsWindow: realtimeMetrics.windowMinutes || 5,
|
||||
isHistoricalMetrics: realtimeMetrics.isHistorical || false,
|
||||
systemStatus: systemHealth.redisConnected ? '正常' : '异常',
|
||||
systemStatus: systemHealth.redisConnected
|
||||
? i18n.global.t('system.status.normal')
|
||||
: i18n.global.t('system.status.abnormal'),
|
||||
uptime: systemHealth.uptime || 0,
|
||||
systemTimezone: dashboardResponse.data.systemTimezone || 8
|
||||
}
|
||||
@@ -220,7 +221,7 @@ export const useDashboardStore = defineStore('dashboard', () => {
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载仪表板数据失败:', error)
|
||||
console.error(i18n.global.t('common.errors.loadDashboardFailed'), error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
@@ -308,7 +309,7 @@ export const useDashboardStore = defineStore('dashboard', () => {
|
||||
trendData.value = response.data
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载使用趋势失败:', error)
|
||||
console.error(i18n.global.t('common.errors.loadUsageTrendFailed'), error)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -399,7 +400,7 @@ export const useDashboardStore = defineStore('dashboard', () => {
|
||||
dashboardModelStats.value = response.data
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载模型统计失败:', error)
|
||||
console.error(i18n.global.t('common.errors.loadModelStatsFailed'), error)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -501,7 +502,7 @@ export const useDashboardStore = defineStore('dashboard', () => {
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载API Keys趋势失败:', error)
|
||||
console.error(i18n.global.t('common.errors.loadApiKeysTrendFailed'), error)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -309,13 +309,13 @@
|
||||
}}</span></span
|
||||
>
|
||||
<span v-if="(dashboardData.totalCacheCreateTokens || 0) > 0" class="text-purple-600"
|
||||
>缓存创建:
|
||||
>{{ t('dashboard.cacheCreateTokens') }}:
|
||||
<span class="font-medium">{{
|
||||
formatNumber(dashboardData.totalCacheCreateTokens || 0)
|
||||
}}</span></span
|
||||
>
|
||||
<span v-if="(dashboardData.totalCacheReadTokens || 0) > 0" class="text-purple-600"
|
||||
>缓存读取:
|
||||
>{{ t('dashboard.cacheReadTokens') }}:
|
||||
<span class="font-medium">{{
|
||||
formatNumber(dashboardData.totalCacheReadTokens || 0)
|
||||
}}</span></span
|
||||
@@ -930,11 +930,14 @@ function createUsageTrendChart() {
|
||||
const bLabel = b.dataset.label || ''
|
||||
|
||||
// 费用和请求数使用不同的轴,单独处理
|
||||
if (aLabel === '费用 (USD)' || bLabel === '费用 (USD)') {
|
||||
return aLabel === '费用 (USD)' ? -1 : 1
|
||||
if (aLabel === t('dashboard.costLabel') || bLabel === t('dashboard.costLabel')) {
|
||||
return aLabel === t('dashboard.costLabel') ? -1 : 1
|
||||
}
|
||||
if (aLabel === '请求数' || bLabel === '请求数') {
|
||||
return aLabel === '请求数' ? 1 : -1
|
||||
if (
|
||||
aLabel === t('dashboard.requestsLabel') ||
|
||||
bLabel === t('dashboard.requestsLabel')
|
||||
) {
|
||||
return aLabel === t('dashboard.requestsLabel') ? 1 : -1
|
||||
}
|
||||
|
||||
// 其他按token值倒序
|
||||
@@ -945,15 +948,15 @@ function createUsageTrendChart() {
|
||||
const label = context.dataset.label || ''
|
||||
let value = context.parsed.y
|
||||
|
||||
if (label === '费用 (USD)') {
|
||||
if (label === t('dashboard.costLabel')) {
|
||||
// 格式化费用显示
|
||||
if (value < 0.01) {
|
||||
return label + ': $' + value.toFixed(6)
|
||||
} else {
|
||||
return label + ': $' + value.toFixed(4)
|
||||
}
|
||||
} else if (label === '请求数') {
|
||||
return label + ': ' + value.toLocaleString() + ' 次'
|
||||
} else if (label === t('dashboard.requestsLabel')) {
|
||||
return label + ': ' + value.toLocaleString()
|
||||
} else {
|
||||
// 格式化token数显示
|
||||
if (value >= 1000000) {
|
||||
|
||||
Reference in New Issue
Block a user