i18n: fix critical untranslated strings across the UI
Some checks failed
Deploy to Production / Trigger production update (push) Failing after 10s

- DestroyTab: wrap all hardcoded English strings with t()
- instances: add status_reinstalling, status_changing_password keys
- common: add shutdown key (ru + en)
- fw: translate groups, ipsets, aliases, security_group and related actions
- nodeadm: translate upgrade button label
- en.json: fix Russian placeholder_notes in English locale
This commit is contained in:
2026-08-13 16:17:07 +05:00
parent d88647de77
commit 80d7a98256
3 changed files with 44 additions and 21 deletions

View File

@@ -1,5 +1,6 @@
import { useState } from 'react';
import { useNavigate } from 'react-router';
import { useTranslation } from 'react-i18next';
import { AlertTriangle, Loader2 } from 'lucide-react';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
@@ -19,6 +20,7 @@ interface Props {
export default function DestroyTab({ serverId, vmid, type, node, name }: Props) {
const navigate = useNavigate();
const { t } = useTranslation();
const deleteVM = useDeleteVM(serverId, vmid, type, node);
const [confirmation, setConfirmation] = useState('');
@@ -29,7 +31,7 @@ export default function DestroyTab({ serverId, vmid, type, node, name }: Props)
if (!canDelete) return;
deleteVM.mutate(undefined, {
onSuccess: () => {
toast.success(`${displayName} has been destroyed`);
toast.success(t('instances.destroyed', { name: displayName }));
navigate('/instances');
},
onError: (err) => toast.error(err.message),
@@ -42,21 +44,20 @@ export default function DestroyTab({ serverId, vmid, type, node, name }: Props)
<CardHeader className="pb-3">
<CardTitle className="flex items-center gap-2 text-destructive">
<AlertTriangle className="h-5 w-5" />
Destroy {vmTypeLabel(type)}
{t('instances.destroy_title', { type: vmTypeLabel(type) })}
</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<div className="rounded-md bg-destructive/10 p-3 text-sm text-destructive">
<p className="font-medium">This action is irreversible!</p>
<p className="font-medium">{t('instances.destroy_irreversible')}</p>
<p className="mt-1 text-destructive/80">
This will permanently delete <strong>{displayName}</strong> (#{vmid}) and all its data,
including disks and snapshots. IP allocations will be released.
{t('instances.destroy_warning_before')} <strong>{displayName}</strong> (#{vmid}){t('instances.destroy_warning_after')}
</p>
</div>
<div>
<Label htmlFor="confirm-name">
Type <strong className="text-foreground">{displayName}</strong> to confirm
{t('instances.destroy_confirm_label_before')} <strong className="text-foreground">{displayName}</strong> {t('instances.destroy_confirm_label_after')}
</Label>
<Input
id="confirm-name"
@@ -74,7 +75,7 @@ export default function DestroyTab({ serverId, vmid, type, node, name }: Props)
className="w-full"
>
{deleteVM.isPending && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
Permanently Destroy {vmTypeLabel(type)}
{t('instances.destroy_button', { type: vmTypeLabel(type) })}
</Button>
</CardContent>
</Card>

View File

@@ -303,6 +303,7 @@
"console": "Console",
"start": "Start",
"stop": "Stop",
"shutdown": "Shutdown",
"restart": "Restart",
"snapshots": "Snapshots",
"suspend": "Suspend",
@@ -357,7 +358,7 @@
"placeholder_snapshot_name": "e.g. before-update",
"placeholder_root_pam": "root@pam",
"placeholder_disk": "scsi0",
"placeholder_notes": "Описание / заметки об инстансе...",
"placeholder_notes": "Description / notes about the instance...",
"ipam": "IPAM"
},
"snap_archive": {
@@ -530,7 +531,17 @@
"backup_now": "Create backup",
"backup_started": "Backup started in background",
"backup_create": "Create backup",
"backup_no_storages": "No backup-capable storages on this node"
"backup_no_storages": "No backup-capable storages on this node",
"destroy_title": "Destroy {{type}}",
"destroy_irreversible": "This action is irreversible!",
"destroy_warning_before": "This will permanently delete",
"destroy_warning_after": " and all its data, including disks and snapshots. IP allocations will be released.",
"destroy_confirm_label_before": "Type",
"destroy_confirm_label_after": "to confirm",
"destroy_button": "Permanently Destroy {{type}}",
"destroyed": "{{name}} has been destroyed",
"status_reinstalling": "Reinstalling",
"status_changing_password": "Changing password"
},
"wizard": {
"title": "Create Instance",

View File

@@ -303,6 +303,7 @@
"console": "Консоль",
"start": "Запустить",
"stop": "Остановить",
"shutdown": "Выключить",
"restart": "Перезагрузить",
"snapshots": "Снимки",
"suspend": "Приостановить",
@@ -530,7 +531,17 @@
"backup_now": "Создать резервную копию",
"backup_started": "Бэкап запущен в фоне",
"backup_create": "Создать бэкап",
"backup_no_storages": "Нет хранилищ с поддержкой бэкапов на этой ноде"
"backup_no_storages": "Нет хранилищ с поддержкой бэкапов на этой ноде",
"destroy_title": "Уничтожить {{type}}",
"destroy_irreversible": "Это действие необратимо!",
"destroy_warning_before": "Будут безвозвратно удалены",
"destroy_warning_after": " и все данные, включая диски и снимки. IP-адреса будут освобождены.",
"destroy_confirm_label_before": "Введите",
"destroy_confirm_label_after": "для подтверждения",
"destroy_button": "Безвозвратно уничтожить {{type}}",
"destroyed": "{{name}} уничтожен",
"status_reinstalling": "Переустановка",
"status_changing_password": "Смена пароля"
},
"wizard": {
"title": "Создание инстанса",
@@ -808,16 +819,16 @@
"enable": "Включить",
"disable": "Выключить",
"rules": "Правила",
"groups": "Security Groups",
"ipsets": "IP Sets",
"aliases": "Aliases",
"groups": "Группы безопасности",
"ipsets": "IP-множества",
"aliases": "Псевдонимы",
"options": "Опции",
"add_rule": "Добавить правило",
"rule_hint": "Правила применяются сверху вниз.",
"direction": "Направление",
"action": "Действие",
"match": "Источник → Назначение",
"security_group": "Security group",
"security_group": "Группа безопасности",
"select_group": "Выберите группу",
"proto": "Протокол",
"macro": "Макрос",
@@ -827,18 +838,18 @@
"sport": "Порт источн.",
"enabled": "Включено",
"log": "Логировать",
"err_group_required": "Выберите security group",
"err_group_required": "Выберите группу безопасности",
"rule_added": "Правило добавлено",
"rule_deleted": "Правило удалено",
"delete_rule_confirm": "Удалить правило?",
"add_group": "Добавить security group",
"delete_group": "Удалить security group",
"add_group": "Добавить группу безопасности",
"delete_group": "Удалить группу безопасности",
"group_name": "Имя группы",
"group_added": "Группа создана",
"group_deleted": "Группа удалена",
"add_ipset": "Добавить IP set",
"delete_ipset": "Удалить IP set",
"ipset_name": "Имя IP set",
"add_ipset": "Добавить IP-множество",
"delete_ipset": "Удалить IP-множество",
"ipset_name": "Имя IP-множества",
"ipset_added": "IP set создан",
"ipset_deleted": "IP set удалён",
"add_alias": "Добавить алиас",
@@ -966,7 +977,7 @@
"updates_count": "Доступно обновлений: {{n}}",
"upgrade_hint": "«Установить обновления» откроет консоль ноды с apt dist-upgrade (потребуется подтверждение). Не закрывайте вкладку до завершения.",
"do_upgrade": "Установить обновления",
"upgrade": "Upgrade",
"upgrade": "Обновить",
"repo_updated": "Репозиторий обновлён",
"enable": "Включить",
"disable": "Выключить"