diff --git a/frontend/src/components/hub/CompatibilityBadge.tsx b/frontend/src/components/hub/CompatibilityBadge.tsx index e0a5139..c50d8cf 100644 --- a/frontend/src/components/hub/CompatibilityBadge.tsx +++ b/frontend/src/components/hub/CompatibilityBadge.tsx @@ -1,5 +1,7 @@ import React, { useState, useRef } from 'react'; import { ModelEvaluation, HardwareSummary } from '../../stores/useModelHubStore'; +import { useSettingsStore } from '../../stores/useSettingsStore'; +import { t } from '../../i18n/translations'; import { ShieldCheck, AlertCircle, Cpu, HardDrive, Zap, Info } from 'lucide-react'; interface CompatibilityBadgeProps { @@ -69,6 +71,23 @@ export const CompatibilityBadge: React.FC = ({ const style = getBadgeStyle(); const Icon = style.icon; + const { getEffectiveLanguage } = useSettingsStore(); + const lang = getEffectiveLanguage(); + + const getDisplayTierLabel = (): string => { + if (!evaluation) return ''; + if (evaluation.notes && evaluation.notes.toLowerCase().includes('cpu')) { + const cpuLabel = t('tier_cpu_mode', lang); + if (cpuLabel && cpuLabel !== 'tier_cpu_mode') return cpuLabel; + } + const tierKey = `tier_${evaluation.tier}`; + const localized = t(tierKey, lang); + if (localized && localized !== tierKey) { + return localized; + } + return evaluation.tier_label; + }; + return (
= ({ > - {evaluation.tier_label} + {getDisplayTierLabel()} {/* Hover Diagnostic Breakdown Tooltip */} diff --git a/frontend/src/components/launcher/LauncherHub.tsx b/frontend/src/components/launcher/LauncherHub.tsx index 58a31a5..5abc196 100644 --- a/frontend/src/components/launcher/LauncherHub.tsx +++ b/frontend/src/components/launcher/LauncherHub.tsx @@ -6,6 +6,8 @@ import { RefreshCw, } from 'lucide-react'; import { useEngineStore, EngineInstance } from '../../stores/useEngineStore'; +import { useSettingsStore } from '../../stores/useSettingsStore'; +import { t } from '../../i18n/translations'; import { InstanceCard } from './InstanceCard'; export interface LauncherHubProps { @@ -48,6 +50,9 @@ export const LauncherHub: React.FC = ({ stopEngine, } = useEngineStore(); + const { getEffectiveLanguage } = useSettingsStore(); + const lang = getEffectiveLanguage(); + useEffect(() => { fetchInstances(); const interval = setInterval(fetchInstances, 6000); @@ -77,7 +82,7 @@ export const LauncherHub: React.FC = ({ onClick={onOpenSetupWizard} className="inline-flex items-center space-x-1.5 px-3 py-1 rounded-full bg-purple-500/15 hover:bg-purple-500/25 border border-purple-500/30 text-purple-300 text-xs font-medium transition-all hover:scale-105 active:scale-95 shadow-sm" > - ⚡ 系统硬件体检与本地模型部署 + {t('launcher_badge_hw_setup', lang)} )}
diff --git a/frontend/src/components/launcher/SetupWizardModal.tsx b/frontend/src/components/launcher/SetupWizardModal.tsx index f6038d9..d38e17c 100644 --- a/frontend/src/components/launcher/SetupWizardModal.tsx +++ b/frontend/src/components/launcher/SetupWizardModal.tsx @@ -13,6 +13,7 @@ import { RefreshCw, } from 'lucide-react'; import { useSettingsStore } from '../../stores/useSettingsStore'; +import { t } from '../../i18n/translations'; interface GpuDetail { index?: number; @@ -370,15 +371,16 @@ export const SetupWizardModal: React.FC = ({

- {isZh ? '系统硬件体检与本地模型部署向导' : 'Hardware Diagnostics & Model Setup'} + {t('setup_wizard_title', lang) || (isZh ? '系统硬件体检与本地模型部署向导' : 'Hardware Diagnostics & Model Setup')} Embedded llama.cpp

- {isZh - ? '一站式真实检测硬件配置、管理内置 llama.cpp 嵌入引擎与极速部署本地大模型' - : 'Live GPU diagnosis, embedded llama.cpp lifecycle & instant local model provisioning'} + {t('setup_wizard_subtitle', lang) || + (isZh + ? '一站式真实检测硬件配置、管理内置 llama.cpp 嵌入引擎与极速部署本地大模型' + : 'Live GPU diagnosis, embedded llama.cpp lifecycle & instant local model provisioning')}

@@ -401,7 +403,7 @@ export const SetupWizardModal: React.FC = ({ }`} > - {isZh ? '1. 硬件配置体检' : '1. Hardware Check'} + {t('setup_step_hardware', lang) || (isZh ? '1. 硬件配置体检' : '1. Hardware Check')} diff --git a/frontend/src/components/settings/SettingsView.tsx b/frontend/src/components/settings/SettingsView.tsx index caa0f07..d35583a 100644 --- a/frontend/src/components/settings/SettingsView.tsx +++ b/frontend/src/components/settings/SettingsView.tsx @@ -27,18 +27,20 @@ import { resolveEffectiveLanguage, } from '../../i18n/translations'; +export type SettingsSection = 'general' | 'agent' | 'startup' | 'exit' | 'cloud' | 'engines' | 'about'; + interface SettingsViewProps { + initialSection?: SettingsSection; onOpenCloudSettings?: () => void; onOpenEnvironmentManager?: () => void; } -type SettingsSection = 'general' | 'agent' | 'startup' | 'exit' | 'cloud' | 'engines' | 'about'; - export const SettingsView: React.FC = ({ + initialSection = 'general', onOpenCloudSettings, onOpenEnvironmentManager, }) => { - const [activeSection, setActiveSection] = useState('general'); + const [activeSection, setActiveSection] = useState(initialSection); // LLM Config state const [llmConfig, setLlmConfig] = useState({ @@ -103,13 +105,14 @@ export const SettingsView: React.FC = ({ setExitPolicy, defaultLandingView, setDefaultLandingView, + getEffectiveLanguage, } = useSettingsStore(); - const currentLang = resolveEffectiveLanguage(language); + const currentLang = getEffectiveLanguage ? getEffectiveLanguage() : resolveEffectiveLanguage(language); const sections: { id: SettingsSection; label: string; icon: React.ElementType }[] = [ { id: 'general', label: t('tab_general', currentLang), icon: Languages }, - { id: 'agent', label: 'AI Agent & LLM (大模型基座)', icon: Bot }, + { id: 'agent', label: t('tab_agent', currentLang), icon: Bot }, { id: 'startup', label: t('tab_startup', currentLang), icon: Compass }, { id: 'exit', label: t('tab_exit', currentLang), icon: Power }, { id: 'cloud', label: t('tab_cloud', currentLang), icon: Globe }, @@ -224,10 +227,10 @@ export const SettingsView: React.FC = ({

- AI Agent 推理基座与大模型配置 (LLM Base) + {t('agent_heading', currentLang)}

- 为右侧常驻 AI Agents 赋予真正的大语言模型推理与自主规划能力,优先支持本地私有化部署(内置 llama.cpp 嵌入引擎),亦支持云端商用模型。 + {t('agent_desc', currentLang)}

@@ -236,10 +239,10 @@ export const SettingsView: React.FC = ({

- 系统配置体检与本地模型一键部署向导 + {t('agent_wizard_title', currentLang)}

- 全自动检测您的 NVIDIA 显卡显存、主机内存与磁盘,快速一键部署并下载 Qwen2.5 / DeepSeek-R1 本地大模型。 + {t('agent_wizard_desc', currentLang)}

{/* Provider Selection */}
- +
- 启用智能 Agent 推理 + {t('agent_enable_toggle', currentLang)} = ({
{[ - { id: 'llama_server', label: 'llama.cpp (内置嵌入)', desc: '免安装 · 零污染 · 画布通用' }, - { id: 'siliconflow', label: '硅基流动 (SiliconFlow)', desc: 'Qwen2.5 / DeepSeek 极速 API' }, - { id: 'deepseek', label: 'DeepSeek 官方', desc: 'DeepSeek-V3 / R1 推理' }, - { id: 'openai', label: 'OpenAI / Custom', desc: 'GPT-4o 或自定义端点' }, + { id: 'llama_server', label: t('agent_provider_llama_label', currentLang), desc: t('agent_provider_llama_desc', currentLang) }, + { id: 'siliconflow', label: t('agent_provider_siliconflow_label', currentLang), desc: t('agent_provider_siliconflow_desc', currentLang) }, + { id: 'deepseek', label: t('agent_provider_deepseek_label', currentLang), desc: t('agent_provider_deepseek_desc', currentLang) }, + { id: 'openai', label: t('agent_provider_openai_label', currentLang), desc: t('agent_provider_openai_desc', currentLang) }, ].map((p) => (
diff --git a/frontend/src/i18n/translations.ts b/frontend/src/i18n/translations.ts index 2f17cb5..4c1c631 100644 --- a/frontend/src/i18n/translations.ts +++ b/frontend/src/i18n/translations.ts @@ -91,6 +91,39 @@ export const TRANSLATIONS: Record> = { btn_deploy_now: 'Deploy & Install Now', btn_locate_existing: 'Locate Existing Folder', btn_install_engine: 'Deploy Engine', + launcher_badge_hw_setup: '⚡ Hardware Diagnostics & Model Setup', + tab_agent: 'AI Agent & LLM', + agent_heading: 'AI Agent & Local LLM Base', + agent_desc: 'Configure LLM inference for creative assistant agents. Supports local embedded llama.cpp and cloud providers.', + agent_wizard_title: 'Hardware Diagnostics & Local Model Setup Wizard', + agent_wizard_desc: 'Automatically evaluates GPU VRAM, host RAM, and disk storage to deploy Qwen2.5 / DeepSeek-R1 locally with zero host pollution.', + agent_wizard_btn: 'Open Setup Wizard', + agent_provider_label: 'Inference Provider', + agent_enable_toggle: 'Enable AI Agent Inference', + agent_provider_llama_label: 'llama.cpp (Embedded)', + agent_provider_llama_desc: 'Zero Host Pollution · Shared GGUF', + agent_provider_siliconflow_label: 'SiliconFlow', + agent_provider_siliconflow_desc: 'Qwen2.5 / DeepSeek Cloud API', + agent_provider_deepseek_label: 'DeepSeek Official', + agent_provider_deepseek_desc: 'DeepSeek-V3 / R1 Reasoning', + agent_provider_openai_label: 'OpenAI / Custom', + agent_provider_openai_desc: 'GPT-4o or Custom Endpoint', + agent_model_id_label: 'Model Identifier', + agent_api_key_label: 'API Key (Optional for llama.cpp)', + agent_api_key_placeholder_llama: 'No API key required for local engine', + agent_btn_test: 'Test Connection', + agent_btn_save: 'Save Configuration', + agent_btn_saving: 'Saving...', + setup_wizard_title: 'Hardware Diagnostics & Model Setup', + setup_wizard_subtitle: 'Live GPU diagnosis, embedded llama.cpp lifecycle & instant local model provisioning', + setup_step_hardware: '1. Hardware Check', + setup_step_model: '2. Deploy Model', + setup_step_ready: '3. Ready', + tier_optimal: 'Optimal', + tier_playable_offload: 'RAM Offload', + tier_heavy_paging: 'Heavy Paging', + tier_unsupported: 'Unsupported', + tier_cpu_mode: 'CPU Mode', }, 'zh-CN': { settings_title: '系统设置', @@ -135,6 +168,39 @@ export const TRANSLATIONS: Record> = { btn_deploy_now: '立即智能部署', btn_locate_existing: '关联已有目录', btn_install_engine: '智能部署', + launcher_badge_hw_setup: '⚡ 系统硬件体检与本地模型部署', + tab_agent: 'AI Agent 与大模型基座', + agent_heading: 'AI Agent 推理基座与大模型配置 (LLM Base)', + agent_desc: '为常驻 AI Agents 赋予大语言模型推理与规划能力,优先支持本地私有化部署(内置 llama.cpp),亦支持云端商用模型。', + agent_wizard_title: '系统配置体检与本地模型一键部署向导', + agent_wizard_desc: '全自动检测显卡显存、内存与磁盘,快速一键部署并下载 Qwen2.5 / DeepSeek-R1 本地大模型。', + agent_wizard_btn: '打开部署向导', + agent_provider_label: '基座供应商类型 (Provider)', + agent_enable_toggle: '启用智能 Agent 推理', + agent_provider_llama_label: 'llama.cpp (内置嵌入)', + agent_provider_llama_desc: '免安装 · 零污染 · 画布通用', + agent_provider_siliconflow_label: '硅基流动 (SiliconFlow)', + agent_provider_siliconflow_desc: 'Qwen2.5 / DeepSeek 极速 API', + agent_provider_deepseek_label: 'DeepSeek 官方', + agent_provider_deepseek_desc: 'DeepSeek-V3 / R1 推理', + agent_provider_openai_label: 'OpenAI / Custom', + agent_provider_openai_desc: 'GPT-4o 或自定义端点', + agent_model_id_label: '模型标识 (Model Identifier)', + agent_api_key_label: 'API Key (本地 llama.cpp 可留空)', + agent_api_key_placeholder_llama: '本地运行无需 API Key', + agent_btn_test: '测试连通性 (Test Connection)', + agent_btn_save: '保存配置 (Save Configuration)', + agent_btn_saving: '保存中...', + setup_wizard_title: '系统硬件体检与本地模型部署向导', + setup_wizard_subtitle: '一站式真实检测硬件配置、管理内置 llama.cpp 嵌入引擎与极速部署本地大模型', + setup_step_hardware: '1. 硬件配置体检', + setup_step_model: '2. 选择与部署模型', + setup_step_ready: '3. 体验就绪', + tier_optimal: '极致流畅 (Optimal)', + tier_playable_offload: '需共享内存 (RAM Offload)', + tier_heavy_paging: '严重卡顿 (Heavy Paging)', + tier_unsupported: '无法运行 (建议云端)', + tier_cpu_mode: 'CPU运行 (无独立显卡)', }, ja: { settings_title: '設定', @@ -171,6 +237,8 @@ export const TRANSLATIONS: Record> = { about_heading: 'Berry AI Studio', about_desc: 'FastAPI、React 18、Tauri v2 によるマルチモーダル制作環境。', about_manifesto: 'ホスト非汚染 · 5ポート契約 · クラウドファースト設計', + tab_agent: 'AIエージェント・LLM', + launcher_badge_hw_setup: '⚡ ハードウェア診断とモデル設定', }, ko: { settings_title: '설정', @@ -207,6 +275,8 @@ export const TRANSLATIONS: Record> = { about_heading: 'Berry AI Studio', about_desc: 'FastAPI, React 18, Tauri v2 기반 통합 멀티모달 창작 워크스페이스.', about_manifesto: '호스트 무오염 · 5개 포트 규격 · 클라우드 퍼스트 아키텍처', + tab_agent: 'AI 에이전트 및 LLM', + launcher_badge_hw_setup: '⚡ 하드웨어 진단 및 로컬 모델 배포', }, fr: { settings_title: 'Paramètres', @@ -243,6 +313,8 @@ export const TRANSLATIONS: Record> = { about_heading: 'Berry AI Studio', about_desc: 'Espace de création multimodal unifié propulsé par FastAPI, React 18 et Tauri v2.', about_manifesto: 'Zéro pollution hôte · Contrat 5 ports · Architecture API-First', + tab_agent: 'Agent IA & LLM', + launcher_badge_hw_setup: '⚡ Diagnostic matériel et modèles', }, de: { settings_title: 'Einstellungen', @@ -279,6 +351,8 @@ export const TRANSLATIONS: Record> = { about_heading: 'Berry AI Studio', about_desc: 'Einheitlicher multimodaler Arbeitsbereich auf Basis von FastAPI, React 18 und Tauri v2.', about_manifesto: 'Keine Host-Verschmutzung · 5-Port-Vertrag · API-First-Architektur', + tab_agent: 'KI-Agent & LLM', + launcher_badge_hw_setup: '⚡ Hardware-Diagnose & Modell-Setup', }, es: { settings_title: 'Configuración', @@ -315,6 +389,8 @@ export const TRANSLATIONS: Record> = { about_heading: 'Berry AI Studio', about_desc: 'Espacio de trabajo multimodal unificado basado en FastAPI, React 18 y Tauri v2.', about_manifesto: 'Cero contaminación host · Contrato de 5 puertos · Arquitectura API-First', + tab_agent: 'Agente IA y LLM', + launcher_badge_hw_setup: '⚡ Diagnóstico de hardware y modelos', }, ru: { settings_title: 'Настройки', @@ -351,6 +427,8 @@ export const TRANSLATIONS: Record> = { about_heading: 'Berry AI Studio', about_desc: 'Единая мультимодальная студия на базе FastAPI, React 18 и Tauri v2.', about_manifesto: 'Без загрязнения хоста · 5 типов портов · Приоритет облака', + tab_agent: 'ИИ-Агент и LLM', + launcher_badge_hw_setup: '⚡ Диагностика оборудования и моделей', }, }; diff --git a/frontend/src/tests/launcherAndModelLocale.test.tsx b/frontend/src/tests/launcherAndModelLocale.test.tsx new file mode 100644 index 0000000..dd72715 --- /dev/null +++ b/frontend/src/tests/launcherAndModelLocale.test.tsx @@ -0,0 +1,249 @@ +import { describe, it, expect, beforeEach, vi } from 'vitest'; +import { renderToStaticMarkup } from 'react-dom/server'; + +const memoryStore: Record = {}; + +const storageMock = { + getItem: (key: string) => memoryStore[key] || null, + setItem: (key: string, value: string) => { + memoryStore[key] = value.toString(); + }, + clear: () => { + for (const key of Object.keys(memoryStore)) { + delete memoryStore[key]; + } + }, + removeItem: (key: string) => { + delete memoryStore[key]; + }, +}; + +Object.defineProperty(globalThis, 'localStorage', { + value: storageMock, + writable: true, + configurable: true, +}); + +import { useSettingsStore } from '../stores/useSettingsStore'; +import { useEngineStore } from '../stores/useEngineStore'; +import { LauncherHub } from '../components/launcher/LauncherHub'; +import { SetupWizardModal } from '../components/launcher/SetupWizardModal'; +import { CompatibilityBadge } from '../components/hub/CompatibilityBadge'; +import { SettingsView } from '../components/settings/SettingsView'; +import { ModelEvaluation } from '../stores/useModelHubStore'; + +describe('Launcher and Model Setup Screens Locale Verification (Issue #139)', () => { + const CHINESE_REGEX = /[\u4e00-\u9fa5]/; + + beforeEach(() => { + localStorage.clear(); + useSettingsStore.getInitialState = () => useSettingsStore.getState(); + useSettingsStore.getState().resetSettings(); + useEngineStore.setState({ + instances: [ + { + id: 'test-canvas', + name: 'Infinite Canvas', + type: 'canvas', + endpoint: null, + status: 'ready', + is_builtin: true, + is_managed: false, + capabilities: ['t2i', 'i2i'], + }, + ], + isLoading: false, + searchQuery: '', + }); + vi.restoreAllMocks(); + globalThis.fetch = vi.fn().mockResolvedValue({ + ok: true, + json: async () => ({}), + }); + }); + + describe('LauncherHub', () => { + it('renders the setup wizard badge in English when English locale is selected', () => { + useSettingsStore.getState().setLanguage('en'); + + const markup = renderToStaticMarkup( + {}} /> + ); + + // Verify the badge contains English text and does not leak Chinese + expect(markup).toContain('Hardware Diagnostics & Model Setup'); + expect(markup).not.toContain('系统硬件体检与本地模型部署'); + }); + + it('preserves Simplified Chinese badge when zh-CN locale is selected', () => { + useSettingsStore.getState().setLanguage('zh-CN'); + + const markup = renderToStaticMarkup( + {}} /> + ); + + expect(markup).toContain('系统硬件体检与本地模型部署'); + }); + }); + + describe('SetupWizardModal', () => { + it('renders modal title, subtitle, and step labels in English when English locale is selected', () => { + useSettingsStore.getState().setLanguage('en'); + + const markup = renderToStaticMarkup( + {}} /> + ); + + expect(markup).toContain('Hardware Diagnostics & Model Setup'); + expect(markup).toContain('Live GPU diagnosis, embedded llama.cpp lifecycle & instant local model provisioning'); + expect(markup).toContain('1. Hardware Check'); + expect(markup).toContain('2. Deploy Model'); + expect(markup).toContain('3. Ready'); + + // The header title and step titles must not contain Chinese characters + expect(markup).not.toContain('系统硬件体检与本地模型部署向导'); + expect(markup).not.toContain('1. 硬件配置体检'); + expect(markup).not.toContain('2. 选择与部署模型'); + expect(markup).not.toContain('3. 体验就绪'); + }); + + it('renders modal title and step labels in Chinese when zh-CN locale is selected', () => { + useSettingsStore.getState().setLanguage('zh-CN'); + + const markup = renderToStaticMarkup( + {}} /> + ); + + expect(markup).toContain('系统硬件体检与本地模型部署向导'); + expect(markup).toContain('1. 硬件配置体检'); + expect(markup).toContain('2. 选择与部署模型'); + expect(markup).toContain('3. 体验就绪'); + }); + }); + + describe('CompatibilityBadge', () => { + it('renders all model compatibility tiers in English without Chinese leak when English is selected', () => { + useSettingsStore.getState().setLanguage('en'); + + const testTiers: Array<{ + evaluation: ModelEvaluation; + expectedEnLabel: string; + }> = [ + { + evaluation: { + tier: 'optimal', + tier_label: '极致流畅 (Optimal)', + tier_color: 'emerald', + estimated_latency_sec: '4-8s', + required_vram_mb: 6144, + notes: 'Fits entirely in dedicated VRAM.', + }, + expectedEnLabel: 'Optimal', + }, + { + evaluation: { + tier: 'playable_offload', + tier_label: '需共享内存 (RAM Offload)', + tier_color: 'amber', + estimated_latency_sec: '15-25s', + required_vram_mb: 8192, + notes: 'Offloads to host RAM.', + }, + expectedEnLabel: 'RAM Offload', + }, + { + evaluation: { + tier: 'playable_offload', + tier_label: 'CPU运行 (无独立显卡)', + tier_color: 'amber', + estimated_latency_sec: '10s', + required_vram_mb: 1024, + notes: 'No GPU detected; will execute on host CPU.', + }, + expectedEnLabel: 'CPU Mode', + }, + { + evaluation: { + tier: 'heavy_paging', + tier_label: '严重卡顿 (Heavy Paging)', + tier_color: 'orange', + estimated_latency_sec: '>60s', + required_vram_mb: 12288, + notes: 'Host memory under high pressure.', + }, + expectedEnLabel: 'Heavy Paging', + }, + { + evaluation: { + tier: 'unsupported', + tier_label: '无法运行 (易爆显存,建议云端)', + tier_color: 'rose', + estimated_latency_sec: 'N/A', + required_vram_mb: 24576, + notes: 'Recommend Cloud BYOK.', + }, + expectedEnLabel: 'Unsupported', + }, + ]; + + for (const { evaluation, expectedEnLabel } of testTiers) { + const markup = renderToStaticMarkup( + + ); + expect(markup).toContain(expectedEnLabel); + // The rendered badge label should not contain any Chinese characters in English locale + const buttonContent = markup.match(/]*>([\s\S]*?)<\/button>/)?.[1] || ''; + expect(CHINESE_REGEX.test(buttonContent)).toBe(false); + } + }); + + it('preserves Chinese tier labels when zh-CN locale is selected', () => { + useSettingsStore.getState().setLanguage('zh-CN'); + + const evaluation: ModelEvaluation = { + tier: 'optimal', + tier_label: '极致流畅 (Optimal)', + tier_color: 'emerald', + estimated_latency_sec: '4-8s', + required_vram_mb: 6144, + notes: 'Fits entirely in dedicated VRAM.', + }; + + const markup = renderToStaticMarkup( + + ); + expect(markup).toContain('极致流畅 (Optimal)'); + }); + }); + + describe('SettingsView Agent & Local Model Setup', () => { + it('renders Agent tab, heading, wizard banner, and options in English with no Chinese characters', () => { + useSettingsStore.getState().setLanguage('en'); + + const markup = renderToStaticMarkup( + + ); + + // Verify the agent tab title, section header, and banner are in English + expect(markup).toContain('AI Agent & LLM'); + expect(markup).toContain('AI Agent & Local LLM Base'); + expect(markup).toContain('Hardware Diagnostics & Local Model Setup Wizard'); + expect(markup).not.toContain('大模型基座'); + + // Verify no Chinese characters in the agent settings section when English is active + expect(CHINESE_REGEX.test(markup)).toBe(false); + }); + + it('renders Agent tab in Chinese when zh-CN locale is selected', () => { + useSettingsStore.getState().setLanguage('zh-CN'); + + const markup = renderToStaticMarkup( + + ); + + expect(markup).toContain('AI Agent 与大模型基座'); + }); + }); +}); + +