i18n: translate hardcoded Russian strings in graphs, wizard, storages, scripts
Some checks failed
Deploy to Production / Trigger production update (push) Failing after 12s

- GraphsTab: wrap "Все", "Сбросить", "Нет данных", IOPS and disk-pct chart
  titles with t(); add graphs.iops_read/write/disk_usage_pct keys
- CreateInstanceWizard: translate (безопаснее) spans via common.safer;
  translate IP placeholder via wizard.ip_cidr_placeholder
- StoragesTab: translate Ceph monhost placeholder via storages.monhost_placeholder
- ScriptEditDialog: translate name placeholder via scripts.name_placeholder
- Add scripts.execution_title and scripts.no_output keys (EN + RU)
- Add common.safer key (EN + RU)
This commit is contained in:
2026-08-14 14:06:10 +05:00
parent 5af2ffed01
commit 3540291c0e
6 changed files with 32 additions and 14 deletions

View File

@@ -228,14 +228,14 @@ function StorageDialog({ serverId, open, onOpenChange, editing }: {
<div className="grid grid-cols-2 gap-3">
<div><Label>{t('storages.ceph_pool')}</Label><Input value={form.pool} onChange={e => set('pool', e.target.value)} className="mt-1 font-mono" placeholder="vm-pool" /></div>
<div><Label>{t('storages.username')}</Label><Input value={form.username} onChange={e => set('username', e.target.value)} className="mt-1" placeholder="admin" /></div>
<div className="col-span-2"><Label>{t('storages.monhost')}</Label><Input value={form.monhost} onChange={e => set('monhost', e.target.value)} className="mt-1 font-mono" placeholder="10.0.0.1 10.0.0.2 (внешний Ceph)" /></div>
<div className="col-span-2"><Label>{t('storages.monhost')}</Label><Input value={form.monhost} onChange={e => set('monhost', e.target.value)} className="mt-1 font-mono" placeholder={t('storages.monhost_placeholder')} /></div>
</div>
)}
{!editing && form.type === 'cephfs' && (
<div className="grid grid-cols-2 gap-3">
<div><Label>{t('storages.fsname')}</Label><Input value={form.fsname} onChange={e => set('fsname', e.target.value)} className="mt-1 font-mono" placeholder="cephfs" /></div>
<div><Label>{t('storages.username')}</Label><Input value={form.username} onChange={e => set('username', e.target.value)} className="mt-1" placeholder="admin" /></div>
<div className="col-span-2"><Label>{t('storages.monhost')}</Label><Input value={form.monhost} onChange={e => set('monhost', e.target.value)} className="mt-1 font-mono" placeholder="10.0.0.1 10.0.0.2 (внешний Ceph)" /></div>
<div className="col-span-2"><Label>{t('storages.monhost')}</Label><Input value={form.monhost} onChange={e => set('monhost', e.target.value)} className="mt-1 font-mono" placeholder={t('storages.monhost_placeholder')} /></div>
</div>
)}

View File

@@ -816,7 +816,7 @@ export default function CreateInstanceWizard({ onClose }: { onClose?: () => void
<SSHKeyPicker keys={availableKeys} selected={selectedKeyIds} onToggle={toggleKey} />
{availableKeys.length === 0 && (
<div>
<Label>SSH Keys <span className="text-muted-foreground text-xs font-normal">(безопаснее)</span></Label>
<Label>SSH Keys <span className="text-muted-foreground text-xs font-normal">{t('common.safer')}</span></Label>
<textarea
className="w-full rounded-md border bg-transparent px-3 py-2 text-sm font-mono min-h-[60px]"
value={config.ssh_keys}
@@ -1096,7 +1096,7 @@ export default function CreateInstanceWizard({ onClose }: { onClose?: () => void
<>
<div>
<Label>IP (CIDR)</Label>
<Input value={lxcConfig.ip_address} onChange={e => setLxcConfig(p => ({ ...p, ip_address: e.target.value }))} placeholder="10.10.10.5/24 или dhcp" />
<Input value={lxcConfig.ip_address} onChange={e => setLxcConfig(p => ({ ...p, ip_address: e.target.value }))} placeholder={t('wizard.ip_cidr_placeholder')} />
</div>
<div>
<Label>Gateway</Label>
@@ -1134,7 +1134,7 @@ export default function CreateInstanceWizard({ onClose }: { onClose?: () => void
<SSHKeyPicker keys={availableKeys} selected={selectedKeyIds} onToggle={toggleKey} />
{availableKeys.length === 0 && (
<div>
<Label>SSH Keys <span className="text-muted-foreground text-xs font-normal">(безопаснее)</span></Label>
<Label>SSH Keys <span className="text-muted-foreground text-xs font-normal">{t('common.safer')}</span></Label>
<textarea
className="w-full rounded-md border bg-transparent px-3 py-2 text-sm font-mono min-h-[60px]"
value={lxcConfig.ssh_keys}

View File

@@ -73,7 +73,7 @@ export default function GraphsTab({ serverId, vmid, type, node }: Props) {
onChange={(e) => setNic(e.target.value)}
className="ml-1 rounded border border-border bg-background px-1 py-0.5 text-xs text-foreground focus:outline-none"
>
<option value="all">Все</option>
<option value="all">{t('common.all')}</option>
{nics.map((n) => (
<option key={n} value={n}>
{n}
@@ -120,7 +120,7 @@ export default function GraphsTab({ serverId, vmid, type, node }: Props) {
/>
{hasCustom && (
<Button variant="outline" size="sm" onClick={resetCustom}>
Сбросить
{t('common.reset')}
</Button>
)}
</div>
@@ -133,7 +133,7 @@ export default function GraphsTab({ serverId, vmid, type, node }: Props) {
</div>
) : points.length === 0 ? (
<div className="flex items-center justify-center py-20 text-sm text-muted-foreground">
Нет данных
{t('common.no_data')}
</div>
) : (
<div className="grid gap-4 lg:grid-cols-2">
@@ -190,7 +190,7 @@ export default function GraphsTab({ serverId, vmid, type, node }: Props) {
/>
<ChartCard
tickFormatter={xTick}
title="IOPS чтение"
title={t('graphs.iops_read')}
data={points}
dataKey="iops_read"
color="hsl(180, 70%, 40%)"
@@ -199,7 +199,7 @@ export default function GraphsTab({ serverId, vmid, type, node }: Props) {
/>
<ChartCard
tickFormatter={xTick}
title="IOPS запись"
title={t('graphs.iops_write')}
data={points}
dataKey="iops_write"
color="hsl(300, 60%, 50%)"
@@ -208,7 +208,7 @@ export default function GraphsTab({ serverId, vmid, type, node }: Props) {
/>
<ChartCard
tickFormatter={xTick}
title="Заполненность диска"
title={t('graphs.disk_usage_pct')}
data={points}
dataKey="diskpct"
color="hsl(45, 93%, 47%)"

View File

@@ -89,7 +89,7 @@ export default function ScriptEditDialog({ open, onOpenChange, script }: Props)
<div className="grid grid-cols-2 gap-3">
<div className="space-y-1.5">
<Label>{t('scripts.name', 'Имя')}</Label>
<Input value={name} onChange={(e) => handleNameChange(e.target.value)} placeholder="Очистка логов" />
<Input value={name} onChange={(e) => handleNameChange(e.target.value)} placeholder={t('scripts.name_placeholder')} />
</div>
<div className="space-y-1.5">
<Label>{t('scripts.slug', 'Slug')}</Label>

View File

@@ -384,6 +384,7 @@
"ipam": "IPAM",
"comment": "Comment",
"add": "Add",
"safer": "(more secure)",
"clone": "Clone",
"iso": "ISO image",
"notes": "Notes",
@@ -753,7 +754,8 @@
"quota_exceeded_title": "This configuration does not fit your quota",
"quota_exceeded_hint": "Reduce the resources above to continue.",
"quota_used_of": "{{used}} of {{limit}}",
"quota_projection_note": "Including the instance being created."
"quota_projection_note": "Including the instance being created.",
"ip_cidr_placeholder": "10.10.10.5/24 or dhcp"
},
"nodes": {
"title": "Servers",
@@ -1243,6 +1245,7 @@
"zfs_pool": "ZFS pool / dataset",
"ceph_pool": "Ceph pool",
"monhost": "Monitor hosts",
"monhost_placeholder": "10.0.0.1 10.0.0.2 (external Ceph)",
"fsname": "CephFS name",
"sparse": "Thin provisioning",
"disabled_ok": "Storage disabled",
@@ -1700,6 +1703,9 @@
"network_out": "Network Out",
"disk_read": "Disk Read",
"disk_write": "Disk Write",
"iops_read": "IOPS Read",
"iops_write": "IOPS Write",
"disk_usage_pct": "Disk Usage",
"io_delay": "IO Delay",
"load_average": "Load Average",
"swap_usage": "Swap Usage",
@@ -1821,6 +1827,9 @@
"source_community": "Community Scripts",
"run": "Run",
"run_title": "Run: {{name}}",
"execution_title": "Run: {{name}}",
"no_output": "(no output)",
"name_placeholder": "Log cleanup",
"confirm_delete": "Delete script «{{name}}»?",
"deleted": "Script deleted",
"repo_added": "Source added",

View File

@@ -383,6 +383,7 @@
"ipam": "IPAM",
"comment": "Комментарий",
"add": "Добавить",
"safer": "(безопаснее)",
"clone": "Клонировать",
"iso": "ISO образ",
"notes": "Примечание",
@@ -752,7 +753,8 @@
"quota_exceeded_title": "Конфигурация не укладывается в квоту",
"quota_exceeded_hint": "Уменьшите ресурсы выше, чтобы продолжить.",
"quota_used_of": "{{used}} из {{limit}}",
"quota_projection_note": "С учётом создаваемого инстанса."
"quota_projection_note": "С учётом создаваемого инстанса.",
"ip_cidr_placeholder": "10.10.10.5/24 или dhcp"
},
"nodes": {
"title": "Серверы",
@@ -1226,6 +1228,7 @@
"zfs_pool": "ZFS пул / датасет",
"ceph_pool": "Ceph pool",
"monhost": "Monitor hosts",
"monhost_placeholder": "10.0.0.1 10.0.0.2 (внешний Ceph)",
"fsname": "Имя CephFS",
"sparse": "Тонкое выделение",
"disabled_ok": "Хранилище отключено",
@@ -1685,6 +1688,9 @@
"network_out": "Исходящий трафик",
"disk_read": "Чтение диска",
"disk_write": "Запись диска",
"iops_read": "IOPS чтение",
"iops_write": "IOPS запись",
"disk_usage_pct": "Заполненность диска",
"io_delay": "Задержка ввода-вывода",
"load_average": "Средняя нагрузка",
"swap_usage": "Использование swap",
@@ -1929,6 +1935,9 @@
"source_community": "Community Scripts",
"run": "Запустить",
"run_title": "Запустить: {{name}}",
"execution_title": "Запуск: {{name}}",
"no_output": "(нет вывода)",
"name_placeholder": "Очистка логов",
"confirm_delete": "Удалить скрипт «{{name}}»?",
"deleted": "Скрипт удалён",
"repo_added": "Источник добавлен",