i18n: translate frontend UI strings to English

This commit is contained in:
zhi
2026-03-11 21:19:54 +00:00
parent 34ab80e50d
commit 0ab1d2f380
14 changed files with 147 additions and 147 deletions

View File

@@ -21,7 +21,7 @@ interface SetupForm {
project_description: string
}
const STEPS = ['欢迎', '数据库', '管理员', '项目', '完成']
const STEPS = ['Welcome', 'Database', 'Admin', 'Projects', 'Finish']
export default function SetupWizardPage({ wizardBase, onComplete }: Props) {
const [step, setStep] = useState(0)
@@ -40,7 +40,7 @@ export default function SetupWizardPage({ wizardBase, onComplete }: Props) {
db_database: 'harborforge',
backend_base_url: 'http://127.0.0.1:8000',
project_name: 'Default',
project_description: '默认项目',
project_description: 'Default project',
})
const wizardApi = axios.create({
@@ -59,7 +59,7 @@ export default function SetupWizardPage({ wizardBase, onComplete }: Props) {
setStep(1)
} catch {
setWizardOk(false)
setError(`无法连接 AbstractWizard (${wizardBase})\n请确认已通过 SSH 隧道映射端口:\nssh -L <wizard_port>:127.0.0.1:<wizard_port> user@server`)
setError(`Unable to connect to AbstractWizard (${wizardBase}).\nPlease ensure the SSH tunnel is configured:\nssh -L <wizard_port>:127.0.0.1:<wizard_port> user@server`)
}
}
@@ -98,7 +98,7 @@ export default function SetupWizardPage({ wizardBase, onComplete }: Props) {
setStep(4)
} catch (err: any) {
setError(`保存配置失败: ${err.message}`)
setError(`Failed to save configuration: ${err.message}`)
} finally {
setSaving(false)
}
@@ -108,7 +108,7 @@ export default function SetupWizardPage({ wizardBase, onComplete }: Props) {
<div className="setup-wizard">
<div className="setup-container">
<div className="setup-header">
<h1> HarborForge </h1>
<h1> HarborForge Setup Wizard</h1>
<div className="setup-steps">
{STEPS.map((s, i) => (
<span key={i} className={`setup-step ${i === step ? 'active' : i < step ? 'done' : ''}`}>
@@ -123,17 +123,17 @@ export default function SetupWizardPage({ wizardBase, onComplete }: Props) {
{/* Step 0: Welcome */}
{step === 0 && (
<div className="setup-step-content">
<h2>使 HarborForge</h2>
<p>Agent/</p>
<h2>Welcome to HarborForge</h2>
<p>Agent/Human collaborative task management platform</p>
<div className="setup-info">
<p> SSH AbstractWizard</p>
<p> The setup wizard connects to AbstractWizard via SSH tunnel. Ensure the port is forwarded:</p>
<code>ssh -L &lt;wizard_port&gt;:127.0.0.1:&lt;wizard_port&gt; user@your-server</code>
</div>
<button className="btn-primary" onClick={checkWizard}>
Wizard
Connect to Wizard
</button>
{wizardOk === false && (
<p className="setup-hint"> SSH </p>
<p className="setup-hint">Connection failed. Check the SSH tunnel.</p>
)}
</div>
)}
@@ -141,18 +141,18 @@ export default function SetupWizardPage({ wizardBase, onComplete }: Props) {
{/* Step 1: Database */}
{step === 1 && (
<div className="setup-step-content">
<h2></h2>
<p className="text-dim"> MySQL 使 docker-compose MySQL </p>
<h2>Database configuration</h2>
<p className="text-dim">Configure MySQL connection (docker-compose defaults are fine if using the bundled MySQL).</p>
<div className="setup-form">
<label> <input value={form.db_host} onChange={(e) => set('db_host', e.target.value)} /></label>
<label> <input type="number" value={form.db_port} onChange={(e) => set('db_port', Number(e.target.value))} /></label>
<label> <input value={form.db_user} onChange={(e) => set('db_user', e.target.value)} /></label>
<label> <input type="password" value={form.db_password} onChange={(e) => set('db_password', e.target.value)} /></label>
<label> <input value={form.db_database} onChange={(e) => set('db_database', e.target.value)} /></label>
<label>Host <input value={form.db_host} onChange={(e) => set('db_host', e.target.value)} /></label>
<label>Port <input type="number" value={form.db_port} onChange={(e) => set('db_port', Number(e.target.value))} /></label>
<label>Username <input value={form.db_user} onChange={(e) => set('db_user', e.target.value)} /></label>
<label>Password <input type="password" value={form.db_password} onChange={(e) => set('db_password', e.target.value)} /></label>
<label>Database <input value={form.db_database} onChange={(e) => set('db_database', e.target.value)} /></label>
</div>
<div className="setup-nav">
<button className="btn-back" onClick={() => setStep(0)}></button>
<button className="btn-primary" onClick={() => setStep(2)}></button>
<button className="btn-back" onClick={() => setStep(0)}>Back</button>
<button className="btn-primary" onClick={() => setStep(2)}>Next</button>
</div>
</div>
)}
@@ -160,21 +160,21 @@ export default function SetupWizardPage({ wizardBase, onComplete }: Props) {
{/* Step 2: Admin */}
{step === 2 && (
<div className="setup-step-content">
<h2></h2>
<p className="text-dim"></p>
<h2>Admin account</h2>
<p className="text-dim">Create the first admin user</p>
<div className="setup-form">
<label> <input value={form.admin_username} onChange={(e) => set('admin_username', e.target.value)} required /></label>
<label> <input type="password" value={form.admin_password} onChange={(e) => set('admin_password', e.target.value)} required placeholder="设置管理员密码" /></label>
<label> <input type="email" value={form.admin_email} onChange={(e) => set('admin_email', e.target.value)} placeholder="admin@example.com" /></label>
<label> <input value={form.admin_full_name} onChange={(e) => set('admin_full_name', e.target.value)} /></label>
<label>Username <input value={form.admin_username} onChange={(e) => set('admin_username', e.target.value)} required /></label>
<label>Password <input type="password" value={form.admin_password} onChange={(e) => set('admin_password', e.target.value)} required placeholder="Set admin password" /></label>
<label>Email <input type="email" value={form.admin_email} onChange={(e) => set('admin_email', e.target.value)} placeholder="admin@example.com" /></label>
<label>Full name <input value={form.admin_full_name} onChange={(e) => set('admin_full_name', e.target.value)} /></label>
</div>
<div className="setup-nav">
<button className="btn-back" onClick={() => setStep(1)}></button>
<button className="btn-back" onClick={() => setStep(1)}>Back</button>
<button className="btn-primary" onClick={() => {
if (!form.admin_password) { setError('请设置管理员密码'); return }
if (!form.admin_password) { setError('Please set an admin password'); return }
setError('')
setStep(3)
}}></button>
}}>Next</button>
</div>
</div>
)}
@@ -182,17 +182,17 @@ export default function SetupWizardPage({ wizardBase, onComplete }: Props) {
{/* Step 3: Project */}
{step === 3 && (
<div className="setup-step-content">
<h2></h2>
<p className="text-dim"></p>
<h2>Default project (optional)</h2>
<p className="text-dim">Create an initial project or skip</p>
<div className="setup-form">
<label> Base URL <input value={form.backend_base_url} onChange={(e) => set('backend_base_url', e.target.value)} placeholder="http://127.0.0.1:8000" /></label>
<label> <input value={form.project_name} onChange={(e) => set('project_name', e.target.value)} placeholder="留空则跳过" /></label>
<label> <input value={form.project_description} onChange={(e) => set('project_description', e.target.value)} /></label>
<label>Backend Base URL <input value={form.backend_base_url} onChange={(e) => set('backend_base_url', e.target.value)} placeholder="http://127.0.0.1:8000" /></label>
<label>Project name <input value={form.project_name} onChange={(e) => set('project_name', e.target.value)} placeholder="Leave blank to skip" /></label>
<label>ProjectsDescription <input value={form.project_description} onChange={(e) => set('project_description', e.target.value)} /></label>
</div>
<div className="setup-nav">
<button className="btn-back" onClick={() => setStep(2)}></button>
<button className="btn-back" onClick={() => setStep(2)}>Back</button>
<button className="btn-primary" onClick={saveConfig} disabled={saving}>
{saving ? '保存中...' : '完成配置'}
{saving ? 'Saving...' : 'Finish setup'}
</button>
</div>
</div>
@@ -202,16 +202,16 @@ export default function SetupWizardPage({ wizardBase, onComplete }: Props) {
{step === 4 && (
<div className="setup-step-content">
<div className="setup-done">
<h2> </h2>
<p> AbstractWizard</p>
<h2> Setup complete!</h2>
<p>Configuration saved to AbstractWizard.</p>
<div className="setup-info">
<p></p>
<p>Restart services on the server:</p>
<code>docker compose restart</code>
<p style={{ marginTop: '1rem' }}></p>
<p>: <strong>{form.admin_username}</strong></p>
<p style={{ marginTop: '1rem' }}>After the backend starts, refresh this page to go to login.</p>
<p>Admin account: <strong>{form.admin_username}</strong></p>
</div>
<button className="btn-primary" onClick={onComplete}>
Refresh to check
</button>
</div>
</div>