feat(i18n): replace hardcoded Chinese in frontend components with i18n calls

Replace all user-visible hardcoded Chinese strings in 7 component files
with $t() / t() calls using vue-i18n:

- Step1GraphBuild: ontology generation, graph build, status badges
- Step2EnvSetup: simulation setup, agent personas, platform config,
  time config, initial activation, modal profile details
- Step3Simulation: report generation button
- Step4Report: section loading text, interaction button
- Step5Interaction: chat interface, survey UI, tool descriptions,
  error messages, agent selection
- GraphPanel: graph status hints, loading states, tooltips
- HistoryDatabase: history cards, modal, replay buttons

Added missing translation keys to both zh.json and en.json locale files.
Added useI18n imports to components that need script-level translations.
This commit is contained in:
ghostubborn
2026-04-01 15:43:11 +08:00
parent 70833821a2
commit fc47ae81b5
9 changed files with 253 additions and 208 deletions

View File

@@ -13,7 +13,7 @@
<!-- 标题区域 -->
<div class="section-header">
<div class="section-line"></div>
<span class="section-title">推演记录</span>
<span class="section-title">{{ $t('history.title') }}</span>
<div class="section-line"></div>
</div>
@@ -36,16 +36,16 @@
<span
class="status-icon"
:class="{ available: project.project_id, unavailable: !project.project_id }"
title="图谱构建"
:title="$t('history.graphBuild')"
></span>
<span
class="status-icon available"
title="环境搭建"
:title="$t('history.envSetup')"
></span>
<span
class="status-icon"
:class="{ available: project.report_id, unavailable: !project.report_id }"
title="分析报告"
:title="$t('history.analysisReport')"
></span>
</div>
</div>
@@ -67,13 +67,13 @@
</div>
<!-- 如果有更多文件显示提示 -->
<div v-if="project.files.length > 3" class="files-more">
+{{ project.files.length - 3 }} 个文件
{{ $t('history.moreFiles', { count: project.files.length - 3 }) }}
</div>
</div>
<!-- 无文件时的占位 -->
<div class="files-empty" v-else>
<span class="empty-file-icon"></span>
<span class="empty-file-text">暂无文件</span>
<span class="empty-file-text">{{ $t('history.noFiles') }}</span>
</div>
</div>
@@ -102,7 +102,7 @@
<!-- 加载状态 -->
<div v-if="loading" class="loading-state">
<span class="loading-spinner"></span>
<span class="loading-text">加载中...</span>
<span class="loading-text">{{ $t('history.loadingText') }}</span>
</div>
<!-- 历史回放详情弹窗 -->
@@ -126,27 +126,27 @@
<div class="modal-body">
<!-- 模拟需求 -->
<div class="modal-section">
<div class="modal-label">模拟需求</div>
<div class="modal-requirement">{{ selectedProject.simulation_requirement || '无' }}</div>
<div class="modal-label">{{ $t('history.simRequirement') }}</div>
<div class="modal-requirement">{{ selectedProject.simulation_requirement || $t('common.none') }}</div>
</div>
<!-- 文件列表 -->
<div class="modal-section">
<div class="modal-label">关联文件</div>
<div class="modal-label">{{ $t('history.relatedFiles') }}</div>
<div class="modal-files" v-if="selectedProject.files && selectedProject.files.length > 0">
<div v-for="(file, index) in selectedProject.files" :key="index" class="modal-file-item">
<span class="file-tag" :class="getFileType(file.filename)">{{ getFileTypeLabel(file.filename) }}</span>
<span class="modal-file-name">{{ file.filename }}</span>
</div>
</div>
<div class="modal-empty" v-else>暂无关联文件</div>
<div class="modal-empty" v-else>{{ $t('history.noRelatedFiles') }}</div>
</div>
</div>
<!-- 推演回放分割线 -->
<div class="modal-divider">
<span class="divider-line"></span>
<span class="divider-text">推演回放</span>
<span class="divider-text">{{ $t('history.replayTitle') }}</span>
<span class="divider-line"></span>
</div>
@@ -159,7 +159,7 @@
>
<span class="btn-step">Step1</span>
<span class="btn-icon"></span>
<span class="btn-text">图谱构建</span>
<span class="btn-text">{{ $t('history.step1Button') }}</span>
</button>
<button
class="modal-btn btn-simulation"
@@ -167,7 +167,7 @@
>
<span class="btn-step">Step2</span>
<span class="btn-icon"></span>
<span class="btn-text">环境搭建</span>
<span class="btn-text">{{ $t('history.step2Button') }}</span>
</button>
<button
class="modal-btn btn-report"
@@ -176,12 +176,12 @@
>
<span class="btn-step">Step4</span>
<span class="btn-icon"></span>
<span class="btn-text">分析报告</span>
<span class="btn-text">{{ $t('history.step4Button') }}</span>
</button>
</div>
<!-- 不可回放提示 -->
<div class="modal-playback-hint">
<span class="hint-text">Step3开始模拟 Step5深度互动需在运行中启动不支持历史回放</span>
<span class="hint-text">{{ $t('history.replayHint') }}</span>
</div>
</div>
</div>
@@ -193,10 +193,12 @@
<script setup>
import { ref, computed, onMounted, onUnmounted, onActivated, watch, nextTick } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useI18n } from 'vue-i18n'
import { getSimulationHistory } from '../api/simulation'
const router = useRouter()
const route = useRoute()
const { t } = useI18n()
// 状态
const projects = ref([])
@@ -337,7 +339,7 @@ const truncateText = (text, maxLength) => {
// 从模拟需求生成标题取前20字
const getSimulationTitle = (requirement) => {
if (!requirement) return '未命名模拟'
if (!requirement) return t('history.untitledSimulation')
const title = requirement.slice(0, 20)
return requirement.length > 20 ? title + '...' : title
}
@@ -353,8 +355,8 @@ const formatSimulationId = (simulationId) => {
const formatRounds = (simulation) => {
const current = simulation.current_round || 0
const total = simulation.total_rounds || 0
if (total === 0) return '未开始'
return `${current}/${total}`
if (total === 0) return t('history.notStarted')
return t('history.roundsProgress', { current, total })
}
// 获取文件类型(用于样式)
@@ -382,7 +384,7 @@ const getFileTypeLabel = (filename) => {
// 截断文件名(保留扩展名)
const truncateFilename = (filename, maxLength) => {
if (!filename) return '未知文件'
if (!filename) return t('history.unknownFile')
if (filename.length <= maxLength) return filename
const ext = filename.includes('.') ? '.' + filename.split('.').pop() : ''