package web import ( "time" "gitea.dooplex.hu/admin/felhom-controller/internal/backup" ) // ── i18n slice 1, release B (v0.249.0) — parity cases for the backup pages ───────────────────────── // // Captured from the UNCONVERTED templates (commit in REPORT.md). Data: multi-word or ASCII values only. type m = map[string]interface{} func i18nBackupStatus(running bool, withResults bool) m { at := i18nFixtureTime() b := m{"DBDumpSchedule": "02:30", "NextDBDump": at, "Running": running, "AppDataInfo": []m{{"StackName": "privatebin"}}, "DiscoveredDBs": []m{{"StackName": "kimai"}}, } if withResults { b["LastDBDump"] = m{"LastRun": at, "Results": []m{ {"DB": m{"StackName": "kimai", "DBType": backup.DBTypeMariaDB}, "Error": "dump failed", "Size": int64(0), "Validation": m{}}, {"DB": m{"StackName": "bookstack", "DBType": backup.DBTypeMariaDB}, "Error": "", "Size": int64(1 << 20), "Validation": m{"Valid": true, "TableCount": 12}}, {"DB": m{"StackName": "immich", "DBType": backup.DBTypePostgres}, "Error": "", "Size": int64(2 << 20), "Validation": m{"Valid": false, "Error": "no create table"}}, {"DB": m{"StackName": "romm", "DBType": backup.DBTypePostgres}, "Error": "", "Size": int64(3 << 20), "Validation": m{"Valid": false}}, }} } else { b["DumpFiles"] = []m{ {"StackName": "bookstack", "DBType": backup.DBTypeMariaDB, "Size": int64(1 << 20), "ModTime": at, "Validation": m{"Valid": true, "TableCount": 12}}, {"StackName": "immich", "DBType": backup.DBTypePostgres, "Size": int64(2 << 20), "ModTime": at, "Validation": m{"Error": "no create table"}}, {"StackName": "romm", "DBType": backup.DBTypePostgres, "Size": int64(3 << 20), "ModTime": at, "Validation": m{}}, } } return b } func i18nAppRows() []m { base := func(name string) m { return m{"StackName": name, "Slug": name, "DisplayName": "App " + name, "Status": "ok", "StatusText": "Minden rendben van", "Tier1Contents": "Adatbázis és beállítások", "Tier23Contents": "Teljes helyreállítási egység", "Tier2Dest": "HDD kettő", "Tier2Schedule": "naponta 03:00", "Tier2StatusBadge": "Sikeres mentés", "Tier3State": "none"} } rows := []m{} r := base("removed") r["Removed"], r["StorageLabel"], r["RemovedUnitTime"] = true, "HDD egy", "2026-09-14T03:12:00Z" rows = append(rows, r) r = base("disconnected") r["DriveDisconnected"] = true r["Tier1LastRun"], r["Tier1LastStatus"] = "2026-09-14T03:12:00Z", "ok" r["Tier2UserDisabled"], r["Tier3State"] = true, "active" r["Warnings"] = []string{"Egy figyelmeztetés szövege"} rows = append(rows, r) r = base("hdd") r["HasHDDData"], r["StorageLabel"], r["HDDSizeHuman"] = true, "HDD egy", "12 GB" r["Tier1LastRun"], r["Tier1LastStatus"] = "2026-09-14T03:12:00Z", "error" r["DriveFilesNote"], r["DriveFilesNoteLink"], r["DriveFilesNoteLinkText"] = "A fájlok nincsenek benne", "/backups/remote", "Távoli mentés oldal" r["HasDB"], r["Tier1DBStatus"] = true, "error" r["Tier2Configured"], r["Tier2DestDisconnected"], r["Tier2SuccessTracked"], r["Tier2LastRun"] = true, true, false, "2026-09-14T03:12:00Z" r["Tier3State"] = "escrow_pending" rows = append(rows, r) r = base("volume") r["HasVolumeData"], r["HasDB"] = true, true r["Tier1LastRun"], r["Tier1LastStatus"] = "2026-09-14T03:12:00Z", "unknown" r["Tier2Configured"], r["Tier2DestDisconnected"], r["Tier2SuccessTracked"], r["Tier2LastSuccess"] = true, true, true, "2026-09-14T03:12:00Z" r["Tier3State"] = "off" rows = append(rows, r) r = base("confonly") r["Tier2Configured"], r["Tier2DestDisconnected"], r["Tier2SuccessTracked"] = true, true, true rows = append(rows, r) for i, v := range []m{{"Tier2SuccessTracked": false, "Tier2LastRun": "2026-09-14T03:12:00Z"}, {"Tier2SuccessTracked": true, "Tier2LastSuccess": "2026-09-14T03:12:00Z"}, {"Tier2SuccessTracked": true}} { r = base([]string{"inact1", "inact2", "inact3"}[i]) r["HasVolumeData"] = true r["Tier2Configured"], r["Tier2DestInactive"] = true, true for k, x := range v { r[k] = x } rows = append(rows, r) } r = base("okrun") r["Tier2Configured"], r["Tier2SuccessTracked"], r["Tier2LastRun"], r["Tier2LastStatus"] = true, false, "2026-09-14T03:12:00Z", "ok" r["Tier2SizeHuman"], r["Tier2LastWarning"], r["Tier2UnitStaleNotice"] = "3 GB", "Egy figyelmeztetés a másolatról", "A másolat régebbi a mentésnél" r["Tier2UnitRestorable"], r["Tier2UnitConfirm"] = true, "Biztosan visszaállítod a teljes egységet?" rows = append(rows, r) r = base("oksucc") r["Tier2Configured"], r["Tier2SuccessTracked"], r["Tier2LastSuccess"], r["Tier2LastStatus"] = true, true, "2026-09-14T03:12:00Z", "error" rows = append(rows, r) r = base("nosucc") r["Tier2Configured"], r["Tier2SuccessTracked"], r["Tier2LastStatus"] = true, true, "error" rows = append(rows, r) r = base("nosucc2") r["Tier2Configured"], r["Tier2SuccessTracked"], r["Tier2LastRun"], r["Tier2LastStatus"] = true, false, "", "running" rows = append(rows, r) r = base("t2err") r["Tier2LastError"] = "Nincs második meghajtó csatlakoztatva" rows = append(rows, r) return rows } func i18nAppsData(offboxStatus string, running bool, withResults bool, dbState string) map[string]interface{} { d := i18nLayoutData("backups-apps", "Alkalmazás mentések") d["Backup"] = i18nBackupStatus(running, withResults) d["DBSectionState"] = dbState d["NoUserDataBackupWarning"] = true d["AppBackupRows"] = i18nAppRows() d["Offbox"] = m{"LastStatus": offboxStatus, "Host": "nas.example", "LastRun": "2026-09-14T03:12:00Z"} return d } func i18nCasesB() []i18nCase { return []i18nCase{ {"backups_apps_ok", "backups_apps", func() map[string]interface{} { return i18nAppsData("ok", false, true, "dumps") }}, {"backups_apps_error", "backups_apps", func() map[string]interface{} { return i18nAppsData("error", true, false, "dumps") }}, {"backups_apps_running", "backups_apps", func() map[string]interface{} { d := i18nAppsData("running", false, false, "pending") d["Backup"].(m)["DumpFiles"] = []m{} d["Backup"].(m)["DiscoveredDBs"] = []m{} return d }}, {"backups_apps_other", "backups_apps", func() map[string]interface{} { d := i18nAppsData("incomplete", false, false, "embedded") d["Backup"].(m)["DumpFiles"] = []m{} d["Backup"].(m)["DiscoveredDBs"] = []m{} return d }}, {"backups_apps_stale_copy", "backups_apps", func() map[string]interface{} { d := i18nAppsData("ok", false, true, "dumps") rows := d["AppBackupRows"].([]m) for _, r := range rows { if r["StackName"] == "oksucc" { r["Tier2StaleCopy"] = true } } return d }}, {"backups_apps_empty", "backups_apps", func() map[string]interface{} { return i18nLayoutData("backups-apps", "Alkalmazás mentések") }}, {"backups_remote_full", "backups_remote", func() map[string]interface{} { return i18nRemoteData(func(d, o m) { d["RecoveryOffer"], d["OffboxToggledCount"] = true, 0 o["LastStatus"], o["StatsKnown"], o["RepoSizeHuman"], o["SnapshotCount"] = "ok", true, "12 GB", 40 o["OrphanedRenamedTo"], o["LastError"], o["LastWarning"], o["RepoState"] = "repo-old-2026", "timeout while uploading", "quota near limit", "orphaned" d["OffboxQuotaPct"], d["OffboxWarningDisplay"] = 110, "quota near limit" d["OffboxCeremonyAwaiting"] = true d["AbandonActive"], d["AbandonDate"], d["AbandonDaysLeft"], d["AbandonRetrievalOffered"] = true, "2026-09-30", 13, true d["OffboxApps"] = []m{{"Slug": "immich", "DisplayName": "Immich Photos", "Name": "immich", "Enabled": true}, {"Slug": "kimai", "DisplayName": "Kimai Time", "Name": "kimai", "Enabled": false}} d["OffboxBlockedSet"] = map[string]bool{"immich": true} }) }}, {"backups_remote_incomplete", "backups_remote", func() map[string]interface{} { return i18nRemoteData(func(d, o m) { d["OffboxToggledCount"] = 2 o["LastStatus"], o["StatsKnown"], o["QuotaGB"], o["EscrowState"] = "incomplete", false, 50, "" d["OffboxQuotaPct"], d["OffboxWarningDisplay"] = 85, "The selection changed since the warning" d["OffboxCeremonyTimedOut"], d["EscrowAgentOK"] = true, true d["AbandonActive"], d["AbandonDate"], d["AbandonDaysLeft"] = true, "2026-09-30", 13 }) }}, {"backups_remote_error", "backups_remote", func() map[string]interface{} { return i18nRemoteData(func(d, o m) { o["LastStatus"], o["Enabled"], o["StatsKnown"], o["RepoSizeHuman"] = "error", false, true, "" d["OffboxCeremonyTimedOut"], d["EscrowAgentOK"] = true, false d["AbandonPurging"] = true }) }}, {"backups_remote_running", "backups_remote", func() map[string]interface{} { return i18nRemoteData(func(d, o m) { o["LastStatus"], o["QuotaGB"], o["StatsKnown"], o["RepoSizeHuman"], o["EscrowState"] = "running", 10, true, "", "pending" d["OffboxQuotaPct"], d["RecoveryOffer"] = 10, true }) }}, {"backups_remote_pending_agent", "backups_remote", func() map[string]interface{} { return i18nRemoteData(func(d, o m) { o["LastStatus"], o["EscrowState"] = "never", "pending"; d["EscrowAgentOK"] = true }) }}, {"backups_remote_pending_old", "backups_remote", func() map[string]interface{} { return i18nRemoteData(func(d, o m) { o["EscrowState"] = "pending"; d["EscrowAgentOK"] = false }) }}, {"backups_remote_stale", "backups_remote", func() map[string]interface{} { return i18nRemoteData(func(d, o m) { d["EscrowStale"], d["EscrowAgentOK"] = true, true }) }}, {"backups_remote_stale_old", "backups_remote", func() map[string]interface{} { return i18nRemoteData(func(d, o m) { d["EscrowStale"], d["EscrowAgentOK"] = true, false }) }}, {"backups_remote_escrowed", "backups_remote", func() map[string]interface{} { return i18nRemoteData(func(d, o m) { d["EscrowAgentOK"] = true }) }}, {"backups_remote_notconf_hub", "backups_remote", func() map[string]interface{} { d := i18nLayoutData("backups-remote", "Távoli mentés beállítása") d["Backup"] = i18nBackupStatus(false, false) d["OffboxConfigured"], d["OffsiteHubEnabled"] = false, true return d }}, {"backups_remote_notconf", "backups_remote", func() map[string]interface{} { d := i18nLayoutData("backups-remote", "Távoli mentés beállítása") d["Backup"] = i18nBackupStatus(false, false) d["OffboxConfigured"], d["OffsiteHubEnabled"] = false, false return d }}, {"backups_remote_empty", "backups_remote", func() map[string]interface{} { return i18nLayoutData("backups-remote", "Távoli mentés beállítása") }}, {"backups_restore_full", "backups_restore", func() map[string]interface{} { d := i18nLayoutData("backups-restore", "Visszaállítás a mentésből") d["InterruptedRestores"] = []m{{"Stack": "immich", "Message": "A visszaállítás megszakadt, indítsd újra"}} b := i18nBackupStatus(false, false) b["AppDataInfo"] = []m{{"StackName": "immich", "HasHDDData": true, "HasDBDump": true, "HasVolumeData": true, "DisplayName": "Immich Photos"}} d["Backup"] = b d["RemovedApps"] = []m{{"StackName": "oldapp", "DisplayName": "Régi alkalmazás"}} d["OffboxConfigured"] = true d["NoRestoreDestination"], d["HasAttachDestination"] = true, true d["OffsiteStoreState"] = "unreadable" d["OffsiteRestoreRows"] = []m{ {"Slug": "immich", "DisplayName": "Immich Photos", "App": "immich", "Restorable": true, "InStore": true, "Installed": false, "StoreUnknown": true}, {"Slug": "kimai", "DisplayName": "Kimai Time", "App": "kimai", "Restorable": false}, } d["SharesRestoreOffered"], d["SharesDisplayName"], d["SharesScratchReady"] = true, "Hálózati megosztások", true d["OffsiteRestoreCopies"] = []m{{"Stack": "immich", "SizeHuman": "2 GB", "Created": i18nFixtureTime(), "Path": "/mnt/hdd1/copy"}} d["OffboxApps"] = []m{{"Slug": "immich", "DisplayName": "Immich Photos", "Name": "immich"}} return d }}, {"backups_restore_known_empty", "backups_restore", func() map[string]interface{} { d := i18nLayoutData("backups-restore", "Visszaállítás a mentésből") d["Backup"] = i18nBackupStatus(false, false) d["OffboxConfigured"] = true d["NoRestoreDestination"], d["HasAttachDestination"] = true, false d["OffsiteStoreState"] = "known" return d }}, {"backups_restore_notarget", "backups_restore", func() map[string]interface{} { d := i18nLayoutData("backups-restore", "Visszaállítás a mentésből") d["Backup"] = i18nBackupStatus(false, false) d["OffboxConfigured"] = true d["OffsiteStoreState"] = "no-target" return d }}, {"backups_restore_empty", "backups_restore", func() map[string]interface{} { return i18nLayoutData("backups-restore", "Visszaállítás a mentésből") }}, {"restore_wizard_exec", "backups_restore_wizard", func() map[string]interface{} { d := i18nWizardData("vegrehajtas", "execution") d["LastResult"] = m{"OK": true, "Message": "A visszaállítás elkészült rendben", "Interrupted": false, "FinishedAt": i18nFixtureTime()} d["RunningStack"] = "immich" return d }}, {"restore_wizard_prepare_confirm", "backups_restore_wizard", func() map[string]interface{} { d := i18nWizardData("megerosites", "prepare-confirm") d["LastResult"] = m{"OK": false, "Message": "A visszaállítás megszakadt közben", "Interrupted": true, "FinishedAt": i18nFixtureTime()} d["FullPrepSize"] = "3 GB" return d }}, {"restore_wizard_ready", "backups_restore_wizard", func() map[string]interface{} { d := i18nWizardData("elokeszites", "verify") w := d["Wizard"].(m) w["VerifyEnabled"], w["PlaceEnabled"], w["RestoreEnabled"] = true, true, true d["Pair"] = m{"DumpsAt": i18nFixtureTime(), "Skewed": true, "LooksEmpty": true} return d }}, {"restore_wizard_nodumptime", "backups_restore_wizard", func() map[string]interface{} { d := i18nWizardData("eredmeny", "verify") d["Wizard"].(m)["RestoreEnabled"] = true d["Pair"] = m{"DumpsAt": time.Time{}, "Skewed": false, "LooksEmpty": false} return d }}, {"escrow_not_ready", "backups_escrow", func() map[string]interface{} { d := i18nLayoutData("backups-remote", "Helyreállítási kód létrehozása") d["EscrowNotReady"], d["EscrowNotReadyMessage"] = true, "A doboz még nem áll készen erre" return d }}, {"escrow_agent_old", "backups_escrow", func() map[string]interface{} { d := i18nLayoutData("backups-remote", "Helyreállítási kód létrehozása") d["AgentSupported"] = false return d }}, {"escrow_receremony", "backups_escrow", func() map[string]interface{} { d := i18nLayoutData("backups-remote", "Helyreállítási kód létrehozása") d["AgentSupported"], d["Receremony"] = true, true return d }}, {"escrow_first", "backups_escrow", func() map[string]interface{} { d := i18nLayoutData("backups-remote", "Helyreállítási kód létrehozása") d["AgentSupported"] = true return d }}, {"tier2_not_hdd", "tier2_config", func() map[string]interface{} { d := i18nLayoutData("backups", "Második mentés beállítása") d["DisplayName"], d["StackName"] = "Private Bin", "privatebin" d["Flash"], d["FlashError"] = "A beállítás elmentve rendben.", "A mentés nem sikerült most." d["Tier2"] = m{"IsHDDApp": false, "Disabled": false, "NoTarget": true} return d }}, {"tier2_notarget_disabled", "tier2_config", func() map[string]interface{} { d := i18nLayoutData("backups", "Második mentés beállítása") d["DisplayName"], d["StackName"] = "Immich Photos", "immich" d["Tier2"] = m{"IsHDDApp": true, "Disabled": true, "NoTarget": true, "NoTargetReason": "Nincs második meghajtó csatlakoztatva"} return d }}, {"tier2_target_ssd", "tier2_config", func() map[string]interface{} { d := i18nLayoutData("backups", "Második mentés beállítása") d["DisplayName"], d["StackName"] = "Immich Photos", "immich" d["Tier2"] = m{"IsHDDApp": true, "Disabled": false, "NoTarget": false, "EffectiveLabel": "SSD meghajtó egy", "EffectiveIsSSD": true, "Preferred": "/mnt/ssd", "EffectiveDesc": "a leggyorsabb meghajtó", "Alternatives": []m{{"Path": "/mnt/ssd", "Label": "SSD meghajtó egy"}}} return d }}, {"tier2_target_auto", "tier2_config", func() map[string]interface{} { d := i18nLayoutData("backups", "Második mentés beállítása") d["DisplayName"], d["StackName"] = "Immich Photos", "immich" d["Tier2"] = m{"IsHDDApp": true, "Disabled": false, "NoTarget": false, "EffectiveLabel": "HDD kettő", "EffectiveIsSSD": false, "Preferred": "", "EffectiveDesc": "a legnagyobb szabad hely"} return d }}, {"recovery_unlocked_apps", "recovery", func() map[string]interface{} { d := i18nLayoutData("recovery", "Korábbi mentések visszaszerzése") d["Unlocked"], d["Flash"], d["Error"] = true, "A kód elfogadva rendben.", "Egy hiba történt közben." d["InvApps"] = []m{{"App": "immich", "LatestAt": i18nFixtureTime(), "SizeBytes": int64(5 << 30)}, {"App": "kimai", "LatestAt": i18nFixtureTime(), "SizeBytes": int64(0)}} return d }}, {"recovery_unlocked_unavailable", "recovery", func() map[string]interface{} { d := i18nLayoutData("recovery", "Korábbi mentések visszaszerzése") d["Unlocked"], d["InvUnavailable"] = true, true return d }}, {"recovery_unlocked_empty", "recovery", func() map[string]interface{} { d := i18nLayoutData("recovery", "Korábbi mentések visszaszerzése") d["Unlocked"], d["InvEmpty"] = true, true return d }}, {"recovery_unlocked_untagged", "recovery", func() map[string]interface{} { d := i18nLayoutData("recovery", "Korábbi mentések visszaszerzése") d["Unlocked"], d["InvUntagged"] = true, true return d }}, {"recovery_locked_confirm", "recovery", func() map[string]interface{} { d := i18nLayoutData("recovery", "Korábbi mentések visszaszerzése") d["Flash"], d["Error"] = "A kód elfogadva rendben.", "Egy hiba történt közben." d["SealedAt"], d["ConfirmSetAside"], d["AbandonGraceDays"] = "2026-09-01 10:00", true, 30 return d }}, {"recovery_locked_can", "recovery", func() map[string]interface{} { d := i18nLayoutData("recovery", "Korábbi mentések visszaszerzése") d["CanSetAside"], d["AbandonGraceDays"] = true, 30 return d }}, {"recovery_locked_cannot", "recovery", func() map[string]interface{} { d := i18nLayoutData("recovery", "Korábbi mentések visszaszerzése") d["CanSetAside"], d["AbandonGraceDays"] = false, 30 return d }}, {"restore_wizard_blocked", "backups_restore_wizard", func() map[string]interface{} { d := i18nWizardData("eredmeny", "verify") d["Pair"] = m{"DumpsAt": time.Time{}, "Skewed": true, "LooksEmpty": false} return d }}, } } func i18nRemoteData(tweak func(d, o m)) map[string]interface{} { d := i18nLayoutData("backups-remote", "Távoli mentés beállítása") d["Backup"] = i18nBackupStatus(false, false) o := m{"LastStatus": "ok", "LastRun": "2026-09-14T03:12:00Z", "Enabled": true, "User": "felhom", "Host": "nas.example", "RepoPath": "/srv/repo", "Port": 22, "QuotaGB": 100, "StatsKnown": true, "RepoSizeHuman": "5 GB", "SnapshotCount": 10, "EscrowState": "escrowed", "RepoState": "ok"} d["Offbox"] = o d["OffboxConfigured"] = true d["OffboxToggledCount"] = 1 d["OffboxQuotaPct"] = 5 tweak(d, o) return d } func i18nWizardData(phase, step string) map[string]interface{} { d := i18nLayoutData("backups-restore", "Visszaállítás varázsló") d["AppDisplayName"], d["App"] = "Immich Photos", "immich" d["Wizard"] = m{"Phase": phase, "Step": step} d["Pair"] = m{"DumpsAt": time.Time{}} return d }