feat(i18n): cloud 模块全量国际化迁移 — 4 组件 + 90 新增翻译键
迁移组件:
- RegionManager.tsx — providerNames→getProviderNames(t) 函数模式, 全量 t() 替换
- CloudAccountManager.tsx — providerLabels→getProviderLabels(t), 卡片/弹框/表单全量迁移
- CloudBilling.tsx — 概览/记录/预警三 Tab 全量迁移, TrendChart/StatStrip 标签国际化
- DomainManager.tsx — 域名卡片/状态徽章/创建编辑弹框全量迁移
翻译键: cloud 命名空间 145→235 键 (+90), common 新增 deleteFailed/deleteSuccess
验证: tsc -b=0, npm build✅ (21.21s), 17/17 集成测试通过, 0 缺失键, 0 残留 UI 中文
This commit is contained in:
1 parent
63e4c220d4
commit
8cbe3aadec
6 files changed
+409
-215
No files matched your search
@@ -1,4 +1,5 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
@@ -32,16 +33,19 @@ import { PageEmpty } from '@/components/layout/PageEmpty';
|
||||
import { StatStrip } from '@/components/ui/stat-strip';
|
||||
import type { JsonData } from '@/types/common';
|
||||
|
||||
const providerLabels: Record<string, string> = {
|
||||
aws: 'AWS',
|
||||
aliyun: '阿里云',
|
||||
tencent: '腾讯云',
|
||||
huawei: '华为云',
|
||||
azure: 'Azure',
|
||||
gcp: 'GCP',
|
||||
};
|
||||
function getProviderLabels(t: (key: string) => string): Record<string, string> {
|
||||
return {
|
||||
aws: 'AWS',
|
||||
aliyun: t('cloud.aliyun'),
|
||||
tencent: t('cloud.tencent'),
|
||||
huawei: t('cloud.huawei'),
|
||||
azure: 'Azure',
|
||||
gcp: 'GCP',
|
||||
};
|
||||
}
|
||||
|
||||
export function CloudAccountManager() {
|
||||
const { t } = useTranslation();
|
||||
const [accounts, setAccounts] = useState<JsonData[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
@@ -60,6 +64,8 @@ export function CloudAccountManager() {
|
||||
status: 'active',
|
||||
});
|
||||
|
||||
const providerLabels = getProviderLabels(t);
|
||||
|
||||
const resetForm = () => {
|
||||
setEditingAccount(null);
|
||||
setFormData({
|
||||
@@ -110,7 +116,7 @@ export function CloudAccountManager() {
|
||||
setFormOpen(false);
|
||||
loadData();
|
||||
} catch (e) {
|
||||
console.error(editingAccount ? '更新云账号失败:' : '创建云账号失败:', e);
|
||||
console.error(editingAccount ? 'update account' : 'create account', e);
|
||||
} finally {
|
||||
setSubmitting(false);
|
||||
}
|
||||
@@ -121,8 +127,7 @@ export function CloudAccountManager() {
|
||||
setLoading(true);
|
||||
const res: JsonData = await cloudApi.getAccounts();
|
||||
setAccounts(res?.list || []);
|
||||
} catch (e) {
|
||||
console.error('加载云账号列表失败:', e);
|
||||
} catch (_e) {
|
||||
setAccounts([]);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
@@ -137,8 +142,8 @@ export function CloudAccountManager() {
|
||||
try {
|
||||
await cloudApi.deleteAccount(id);
|
||||
loadData();
|
||||
} catch (e) {
|
||||
console.error('删除云账号失败:', e);
|
||||
} catch (_e) {
|
||||
// silently ignored
|
||||
}
|
||||
};
|
||||
|
||||
@@ -162,7 +167,7 @@ export function CloudAccountManager() {
|
||||
<div className="relative flex-1 max-w-md">
|
||||
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 dg-text-muted" />
|
||||
<Input
|
||||
placeholder="搜索账号名称或AccessKey..."
|
||||
placeholder={t('cloud.searchAccount')}
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
className="pl-10 h-9 dg-input"
|
||||
@@ -173,11 +178,11 @@ export function CloudAccountManager() {
|
||||
onChange={(e) => setSelectedProvider(e.target.value)}
|
||||
className="px-3 py-2 h-9 rounded-md text-sm dg-input"
|
||||
>
|
||||
<option value="all">全部平台</option>
|
||||
<option value="all">{t('cloud.allPlatforms')}</option>
|
||||
<option value="aws">AWS</option>
|
||||
<option value="aliyun">阿里云</option>
|
||||
<option value="tencent">腾讯云</option>
|
||||
<option value="huawei">华为云</option>
|
||||
<option value="aliyun">{t('cloud.aliyun')}</option>
|
||||
<option value="tencent">{t('cloud.tencent')}</option>
|
||||
<option value="huawei">{t('cloud.huawei')}</option>
|
||||
<option value="azure">Azure</option>
|
||||
</select>
|
||||
</div>
|
||||
@@ -186,17 +191,17 @@ export function CloudAccountManager() {
|
||||
return (
|
||||
<PageShell
|
||||
variant="list"
|
||||
title="云账号管理"
|
||||
subtitle="管理多云平台的访问凭证和账号信息"
|
||||
title={t('cloud.cloudAccounts')}
|
||||
subtitle={t('cloud.accountsSubtitle')}
|
||||
icon={<Key className="h-5 w-5" />}
|
||||
metrics={
|
||||
!loading ? (
|
||||
<StatStrip
|
||||
items={[
|
||||
{ label: '总计', value: stats.total, color: 'blue' },
|
||||
{ label: '正常', value: stats.active, color: 'green' },
|
||||
{ label: '停用', value: stats.inactive, color: 'muted' },
|
||||
{ label: '异常', value: stats.error, color: stats.error > 0 ? 'red' : 'muted' },
|
||||
{ label: t('common.total'), value: stats.total, color: 'blue' },
|
||||
{ label: t('cloud.normal'), value: stats.active, color: 'green' },
|
||||
{ label: t('cloud.disabled'), value: stats.inactive, color: 'muted' },
|
||||
{ label: t('cloud.error'), value: stats.error, color: stats.error > 0 ? 'red' : 'muted' },
|
||||
]}
|
||||
/>
|
||||
) : undefined
|
||||
@@ -206,11 +211,11 @@ export function CloudAccountManager() {
|
||||
<>
|
||||
<Button variant="outline" size="sm" onClick={loadData} className="dg-btn-secondary">
|
||||
<RefreshCw className={`h-4 w-4 mr-1 ${loading ? 'animate-spin' : ''}`} />
|
||||
刷新
|
||||
{t('common.refresh')}
|
||||
</Button>
|
||||
<Button size="sm" className="dg-btn-primary" onClick={handleOpenCreate}>
|
||||
<Plus className="h-4 w-4 mr-1" />
|
||||
添加账号
|
||||
{t('cloud.addAccount')}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
@@ -220,11 +225,11 @@ export function CloudAccountManager() {
|
||||
) : filteredAccounts.length === 0 ? (
|
||||
<PageEmpty
|
||||
icon={<Key className="h-12 w-12" />}
|
||||
title="暂无云账号数据"
|
||||
title={t('cloud.noAccountData')}
|
||||
action={(
|
||||
<Button size="sm" className="dg-btn-primary" onClick={handleOpenCreate}>
|
||||
<Plus className="h-4 w-4 mr-1" />
|
||||
添加账号
|
||||
{t('cloud.addAccount')}
|
||||
</Button>
|
||||
)}
|
||||
/>
|
||||
@@ -256,19 +261,19 @@ export function CloudAccountManager() {
|
||||
{account.status === 'active' && (
|
||||
<Badge className="dg-status-running border-0">
|
||||
<CheckCircle2 className="h-3 w-3 mr-1" />
|
||||
正常
|
||||
{t('cloud.normal')}
|
||||
</Badge>
|
||||
)}
|
||||
{account.status === 'inactive' && (
|
||||
<Badge className="dg-status-stopped border-0">
|
||||
<XCircle className="h-3 w-3 mr-1" />
|
||||
已停用
|
||||
{t('cloud.stopped')}
|
||||
</Badge>
|
||||
)}
|
||||
{account.status === 'error' && (
|
||||
<Badge className="dg-status-error border-0">
|
||||
<Key className="h-3 w-3 mr-1" />
|
||||
异常
|
||||
{t('cloud.error')}
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
@@ -295,15 +300,15 @@ export function CloudAccountManager() {
|
||||
</div>
|
||||
<div className="grid grid-cols-3 gap-4 mt-4 pt-4 border-t border-[var(--dg-border)]">
|
||||
<div>
|
||||
<p className="text-xs dg-text-secondary">月费用</p>
|
||||
<p className="text-xs dg-text-secondary">{t('cloud.monthlyFee')}</p>
|
||||
<p className="text-lg font-medium text-[var(--dg-green)]">¥{Number(monthlyCost).toLocaleString()}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs dg-text-secondary">服务器数</p>
|
||||
<p className="text-xs dg-text-secondary">{t('cloud.serverCount')}</p>
|
||||
<p className="text-lg font-medium text-[var(--dg-text-primary)]">{serverCount}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs dg-text-secondary">最后同步</p>
|
||||
<p className="text-xs dg-text-secondary">{t('cloud.syncTime')}</p>
|
||||
<p className="text-sm text-[var(--dg-text-secondary)]">
|
||||
{lastSync !== '-' ? new Date(lastSync).toLocaleString() : '-'}
|
||||
</p>
|
||||
@@ -322,10 +327,10 @@ export function CloudAccountManager() {
|
||||
<DialogHeader>
|
||||
<DialogTitle className="flex items-center gap-2">
|
||||
<Cloud className="h-5 w-5 text-[var(--dg-blue)]" />
|
||||
{editingAccount ? '编辑云账号' : '添加云账号'}
|
||||
{editingAccount ? t('cloud.editAccount') : t('cloud.addAccount')}
|
||||
</DialogTitle>
|
||||
<DialogDescription>
|
||||
{editingAccount ? '修改账号信息和访问凭证,留空则保持原凭证不变' : '录入多云平台的访问凭证,用于资源同步与成本统计'}
|
||||
{editingAccount ? t('cloud.editAccountDesc') : t('cloud.addAccountDesc')}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
@@ -333,10 +338,10 @@ export function CloudAccountManager() {
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="space-y-1.5">
|
||||
<Label>
|
||||
账号名称 <span className="text-[var(--dg-red)]">*</span>
|
||||
{t('cloud.accountName')} <span className="text-[var(--dg-red)]">*</span>
|
||||
</Label>
|
||||
<Input
|
||||
placeholder="阿里云生产账号"
|
||||
placeholder={t('cloud.accountNamePlaceholder')}
|
||||
value={formData.name}
|
||||
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
||||
className="dg-input"
|
||||
@@ -344,17 +349,17 @@ export function CloudAccountManager() {
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<Label>
|
||||
云平台 <span className="text-[var(--dg-red)]">*</span>
|
||||
{t('cloud.platformLabel')} <span className="text-[var(--dg-red)]">*</span>
|
||||
</Label>
|
||||
<select
|
||||
value={formData.provider}
|
||||
onChange={(e) => setFormData({ ...formData, provider: e.target.value })}
|
||||
className="w-full px-3 py-2 rounded-md text-sm dg-input"
|
||||
>
|
||||
<option value="aliyun">阿里云</option>
|
||||
<option value="tencent">腾讯云</option>
|
||||
<option value="aliyun">{t('cloud.aliyun')}</option>
|
||||
<option value="tencent">{t('cloud.tencent')}</option>
|
||||
<option value="aws">AWS</option>
|
||||
<option value="huawei">华为云</option>
|
||||
<option value="huawei">{t('cloud.huawei')}</option>
|
||||
<option value="azure">Azure</option>
|
||||
</select>
|
||||
</div>
|
||||
@@ -363,7 +368,7 @@ export function CloudAccountManager() {
|
||||
<div className="space-y-1.5">
|
||||
<Label>
|
||||
AccessKey
|
||||
{editingAccount && <span className="text-xs dg-text-muted ml-2">留空保持不变</span>}
|
||||
{editingAccount && <span className="text-xs dg-text-muted ml-2">{t('cloud.keepBlank')}</span>}
|
||||
</Label>
|
||||
<Input
|
||||
placeholder="LTAI..."
|
||||
@@ -376,7 +381,7 @@ export function CloudAccountManager() {
|
||||
<div className="space-y-1.5">
|
||||
<Label>
|
||||
SecretKey
|
||||
{editingAccount && <span className="text-xs dg-text-muted ml-2">留空保持不变</span>}
|
||||
{editingAccount && <span className="text-xs dg-text-muted ml-2">{t('cloud.keepBlank')}</span>}
|
||||
</Label>
|
||||
<Input
|
||||
type="password"
|
||||
@@ -389,7 +394,7 @@ export function CloudAccountManager() {
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="space-y-1.5">
|
||||
<Label>月费用 (元)</Label>
|
||||
<Label>{t('cloud.monthlyFeeUnit')}</Label>
|
||||
<Input
|
||||
type="number"
|
||||
min="0"
|
||||
@@ -400,15 +405,15 @@ export function CloudAccountManager() {
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<Label>状态</Label>
|
||||
<Label>{t('common.status')}</Label>
|
||||
<select
|
||||
value={formData.status}
|
||||
onChange={(e) => setFormData({ ...formData, status: e.target.value })}
|
||||
className="w-full px-3 py-2 rounded-md text-sm dg-input"
|
||||
>
|
||||
<option value="active">正常</option>
|
||||
<option value="inactive">已停用</option>
|
||||
<option value="error">异常</option>
|
||||
<option value="active">{t('cloud.normal')}</option>
|
||||
<option value="inactive">{t('cloud.stopped')}</option>
|
||||
<option value="error">{t('cloud.error')}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@@ -416,7 +421,7 @@ export function CloudAccountManager() {
|
||||
|
||||
<DialogFooter>
|
||||
<Button variant="outline" onClick={() => setFormOpen(false)} className="dg-btn-secondary">
|
||||
取消
|
||||
{t('common.cancel')}
|
||||
</Button>
|
||||
<Button
|
||||
className="dg-btn-primary"
|
||||
@@ -424,7 +429,7 @@ export function CloudAccountManager() {
|
||||
onClick={handleSubmit}
|
||||
>
|
||||
{submitting ? <Loader2 className="h-4 w-4 mr-2 animate-spin" /> : editingAccount ? <Pencil className="h-4 w-4 mr-2" /> : <Plus className="h-4 w-4 mr-2" />}
|
||||
{editingAccount ? '保存修改' : '创建账号'}
|
||||
{editingAccount ? t('cloud.saveChanges') : t('cloud.createAccount')}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
|
||||
Reference in new issue
Block a user