diff --git a/controller/internal/web/i18n_cases_a_test.go b/controller/internal/web/i18n_cases_a_test.go new file mode 100644 index 0000000..c06b2fe --- /dev/null +++ b/controller/internal/web/i18n_cases_a_test.go @@ -0,0 +1,354 @@ +package web + +import ( + "time" + + "gitea.dooplex.hu/admin/felhom-controller/internal/stacks" +) + +// ── i18n slice 1, release A (v0.248.0) — parity cases for apps and settings ───────────────────────── +// +// Every case here was captured from the UNCONVERTED template (see REPORT.md for the commit). Data +// carries no one-word Hungarian values (the English page test would read them as template copy) and +// no real customer value. + +func i18nStack(name, display string, st stacks.ContainerState, deployed bool) stacks.Stack { + s := stacks.Stack{Name: name, State: st, Deployed: deployed} + s.Meta = stacks.Metadata{DisplayName: display, Slug: name, Description: "Egy teszt alkalmazás leírása", + Resources: stacks.ResourceHints{MemRequest: "128M", PiCompatible: true, NeedsHDD: true, HungarianUI: true}} + return s +} + +func i18nCasesA() []i18nCase { + at := i18nFixtureTime() + cases := []i18nCase{ + {"dashboard_full", "dashboard", func() map[string]interface{} { + d := i18nLayoutData("dashboard", "Vezérlőpult") + d["RunningCount"], d["StoppedCount"], d["TotalCount"] = 3, 1, 5 + d["SystemInfo"] = map[string]interface{}{"TotalMemMB": uint64(8192), "UsedMemMB": uint64(4096), "MemPercent": 50.0, + "CPUPercent": 12.0, "LoadAvg1": 0.5, "LoadAvg5": 0.4, "LoadAvg15": 0.3, "TemperatureCelsius": 48.0, + "DiskKnown": true, "DiskUsedGB": 80.0, "DiskTotalGB": 100.0, "DiskPercent": 80.0} + d["StorageBars"] = []map[string]interface{}{ + {"Label": "Adat lemez", "Disconnected": false, "Percent": 95.0, "UsedGB": 950.0, "TotalGB": 1000.0}, + {"Label": "Régi lemez", "Disconnected": true}, + } + d["SettingsWarning"] = "A beállítások helyreállítva." + d["DiskWarnings"] = []Alert{{Level: "warning", Message: "A lemez majdnem megtelt.", Link: "/storage", LinkText: "Tárhely oldal"}} + d["DiskHealthRows"] = []DiskHealthRow{{Label: "sda lemez", ChipLabel: "Rendben van", ChipClass: "state-text-run", Temp: "34"}} + d["BackupEnabled"] = true + d["BackupStatus"] = map[string]interface{}{"Success": true, "LastRun": at} + d["DBDumpStatus"] = map[string]interface{}{"Results": []int{1, 2}} + fb := i18nStack("filebrowser", "Fájlkezelő app", stacks.StateRunning, true) + fb.Protected = true + orphan := i18nStack("oldapp", "Régi alkalmazás", stacks.StateStopped, true) + orphan.Orphaned = true + d["Stacks"] = []stacks.Stack{ + fb, + i18nStack("privatebin", "Private Bin", stacks.StateUnhealthy, true), + i18nStack("kimai", "Kimai Time", stacks.StateStopped, true), + orphan, + i18nStack("gokapi", "Go Kapi", stacks.StateNotDeployed, false), + } + d["MissingStorage"] = map[string]string{"privatebin": "HDD egy"} + d["OOMKilled"] = map[string]bool{"privatebin": true} + d["NetworkStubs"] = map[string]string{"privatebin": "NAS egy"} + d["NetworkWarnings"] = map[string]string{"privatebin": "NAS egy"} + d["Subdomains"] = map[string]string{"filebrowser": "files", "privatebin": "paste"} + return d + }}, + {"dashboard_sparse", "dashboard", func() map[string]interface{} { + d := i18nLayoutData("dashboard", "Vezérlőpult") + d["RunningCount"], d["StoppedCount"], d["TotalCount"] = 0, 0, 0 + d["SystemInfo"] = map[string]interface{}{"TotalMemMB": uint64(8192), "UsedMemMB": uint64(1024), "MemPercent": 12.0, + "CPUPercent": 1.0, "LoadAvg1": 0.1, "LoadAvg5": 0.1, "LoadAvg15": 0.1, "TemperatureCelsius": 0.0, "DiskKnown": false} + d["StorageBars"] = []map[string]interface{}{{"Label": "Adat lemez", "Disconnected": false, "Percent": 80.0, "UsedGB": 800.0, "TotalGB": 1000.0}} + d["BackupEnabled"] = true + d["BackupStatus"] = map[string]interface{}{"Success": false, "LastRun": at} + d["Stacks"] = []stacks.Stack{} + return d + }}, + {"dashboard_diskcrit", "dashboard", func() map[string]interface{} { + d := i18nLayoutData("dashboard", "Vezérlőpult") + d["RunningCount"], d["StoppedCount"], d["TotalCount"] = 1, 0, 1 + d["SystemInfo"] = map[string]interface{}{"TotalMemMB": uint64(8192), "UsedMemMB": uint64(8000), "MemPercent": 97.0, + "CPUPercent": 99.0, "LoadAvg1": 4.0, "LoadAvg5": 3.0, "LoadAvg15": 2.0, "TemperatureCelsius": 80.0, + "DiskKnown": true, "DiskUsedGB": 97.0, "DiskTotalGB": 100.0, "DiskPercent": 97.0} + d["BackupEnabled"] = false + d["Stacks"] = []stacks.Stack{} + return d + }}, + {"dashboard_nobackup", "dashboard", func() map[string]interface{} { + d := i18nLayoutData("dashboard", "Vezérlőpult") + d["RunningCount"], d["StoppedCount"], d["TotalCount"] = 1, 0, 1 + d["SystemInfo"] = map[string]interface{}{"TotalMemMB": uint64(0)} + d["BackupEnabled"] = true + d["Stacks"] = []stacks.Stack{} + return d + }}, + {"stacks_full", "stacks", func() map[string]interface{} { + d := i18nLayoutData("stacks", "Alkalmazások") + fb := i18nStack("filebrowser", "Fájlkezelő app", stacks.StateRunning, true) + fb.Protected = true + held := i18nStack("kimai", "Kimai Time", stacks.StateStopped, true) + held.HoldReason = "A frissítés megállt, a mentés hiányzik." + upd := i18nStack("romm", "Rom Manager", stacks.StateRunning, true) + upd.Updating, upd.UpdatePhase, upd.UpdatePhaseLabel = true, "pull", "Letöltés folyamatban…" + errRun := i18nStack("gokapi", "Go Kapi", stacks.StateRunning, true) + errRun.UpdateError = "A frissítés nem sikerült ma." + errRun.Containers = []stacks.ContainerInfo{{Name: "gokapi-app", State: stacks.StateRunning, Status: "Up 2 hours"}} + errStop := i18nStack("bookstack", "Book Stack", stacks.StateStopped, true) + errStop.UpdateError = "A frissítés nem sikerült tegnap." + orphan := i18nStack("oldapp", "Régi alkalmazás", stacks.StateStopped, true) + orphan.Orphaned = true + d["Stacks"] = []stacks.Stack{fb, held, upd, errRun, errStop, orphan, + i18nStack("privatebin", "Private Bin", stacks.StateUnhealthy, true), + i18nStack("immich", "Immich Photos", stacks.StateNotDeployed, false)} + d["Subdomains"] = map[string]string{"filebrowser": "files", "privatebin": "paste"} + d["MissingStorage"] = map[string]string{"privatebin": "HDD egy"} + d["NetworkStubs"] = map[string]string{"privatebin": "NAS egy"} + d["NetworkWarnings"] = map[string]string{"privatebin": "NAS egy"} + d["StorageLabels"] = map[string]string{"privatebin": "HDD egy"} + return d + }}, + {"monitoring_hub_ok", "monitoring", func() map[string]interface{} { + d := i18nLayoutData("monitoring", "Rendszermonitor") + d["SystemInfo"] = map[string]interface{}{"TotalMemMB": uint64(8192), "DiskUsedGB": 40.0, "DiskTotalGB": 100.0, "DiskPercent": 40.0} + d["StorageBars"] = []map[string]interface{}{ + {"Label": "Adat lemez", "Disconnected": false, "Percent": 50.0, "UsedGB": 500.0, "TotalGB": 1000.0, "Purpose": "Alkalmazás adatok helye"}, + {"Label": "Régi lemez", "Disconnected": true}, + } + d["DiskWarnings"] = []Alert{{Level: "warning", Message: "A lemez majdnem megtelt.", Link: "/storage", LinkText: "Tárhely oldal"}} + d["HubEnabled"], d["HubConnected"] = true, true + d["HubURL"], d["CustomerID"] = "https://hub.example", "test-customer" + d["HubLastSuccess"] = at + d["HubLastError"] = "connection refused" + d["MonitoringEnabled"] = true + return d + }}, + {"monitoring_hub_down", "monitoring", func() map[string]interface{} { + d := i18nLayoutData("monitoring", "Rendszermonitor") + d["SystemInfo"] = map[string]interface{}{"TotalMemMB": uint64(8192), "DiskUsedGB": 40.0, "DiskTotalGB": 100.0, "DiskPercent": 40.0} + d["HubEnabled"], d["HubConnected"] = true, false + d["HubURL"], d["CustomerID"] = "https://hub.example", "test-customer" + d["HubLastSuccess"] = time.Time{} + return d + }}, + {"monitoring_hub_off", "monitoring", func() map[string]interface{} { + d := i18nLayoutData("monitoring", "Rendszermonitor") + d["SystemInfo"] = map[string]interface{}{"TotalMemMB": uint64(8192), "DiskUsedGB": 40.0, "DiskTotalGB": 100.0, "DiskPercent": 40.0} + d["HubEnabled"] = false + return d + }}, + {"app_import_empty", "app_import", func() map[string]interface{} { + return i18nLayoutData("stacks", "Alkalmazás importálása") + }}, + {"app_import_bundles", "app_import", func() map[string]interface{} { + d := i18nLayoutData("stacks", "Alkalmazás importálása") + d["Bundles"] = []map[string]interface{}{ + {"DisplayName": "Private Bin", "AppName": "privatebin", "ExportedAt": "2026-09-14 03:12", "SizeHuman": "12 MB", + "DriveLabel": "HDD egy", "DrivePath": "/mnt/hdd1", "Encrypted": true, "Path": "/mnt/hdd1/x.fab"}, + {"DisplayName": "", "AppName": "kimai", "ExportedAt": "2026-09-13 03:12", "SizeHuman": "40 MB", + "DriveLabel": "", "DrivePath": "/mnt/hdd2", "Encrypted": false, "Path": "/mnt/hdd2/y.fab"}, + } + return d + }}, + {"app_export", "app_export", func() map[string]interface{} { + d := i18nLayoutData("stacks", "Private Bin exportálása") + st := i18nStack("privatebin", "Private Bin", stacks.StateRunning, true) + st.Meta.Subdomain = "paste" + d["Stack"] = st + d["Drives"] = []map[string]interface{}{{"Path": "/mnt/hdd1", "Label": "HDD egy"}, {"Path": "/mnt/hdd2", "Label": ""}} + return d + }}, + {"deploy_new", "deploy", func() map[string]interface{} { + return i18nDeployData(false, stacks.StateNotDeployed, 1) + }}, + {"deploy_new_blocked", "deploy", func() map[string]interface{} { + return i18nDeployData(false, stacks.StateNotDeployed, 2) + }}, + {"deploy_new_memory_blocked", "deploy", func() map[string]interface{} { + return i18nDeployData(false, stacks.StateNotDeployed, 3) + }}, + {"deploy_deployed_running", "deploy", func() map[string]interface{} { + return i18nDeployData(true, stacks.StateRunning, 1) + }}, + {"deploy_deployed_stopped", "deploy", func() map[string]interface{} { + return i18nDeployData(true, stacks.StateStopped, 2) + }}, + {"settings_system_full", "settings_system", func() map[string]interface{} { + d := i18nLayoutData("settings", "Rendszer beállítások") + d["CustomerID"], d["CustomerDomain"] = "test-customer", "example.hu" + d["GitRepoURL"], d["GitSyncInterval"] = "https://git.example/catalog", "15m" + d["BackupEnabled"], d["DBDumpSchedule"], d["ResticSchedule"] = true, "02:30", "03:30" + d["MonitoringEnabled"], d["HealthchecksBase"], d["HubEnabled"] = true, "https://hc.example", true + d["SelfUpdateEnabled"], d["LatestVersion"], d["UpdateAvailable"] = true, "0.300.0", true + d["LastCheckTime"], d["RegistryAnonymous"], d["LastCheckError"] = "2026-09-14 03:12", true, "registry timeout" + d["AutoUpdateEnabled"], d["AutoUpdateTime"], d["ControllerFloor"] = true, "04:00", "0.246.0" + d["UpdateRunning"] = true + d["LastUpdateState"] = map[string]interface{}{"Status": "success", "PreviousVersion": "0.245.0", "TargetVersion": "0.246.0"} + d["NetLANAddress"], d["NetSMBName"], d["NetGateway"] = "192.168.1.10", "FELHOM", "192.168.1.1" + d["MemorySupported"], d["MemoryReachable"] = true, true + d["MemoryAllocatedMB"], d["MemoryUsageMB"], d["MemoryMinMB"], d["MemoryMaxMB"] = 4096, 2048, 2048, 8192 + return d + }}, + {"settings_system_failed", "settings_system", func() map[string]interface{} { + d := i18nLayoutData("settings", "Rendszer beállítások") + d["CustomerID"], d["CustomerDomain"] = "test-customer", "example.hu" + d["GitSyncInterval"] = "15m" + d["SelfUpdateEnabled"], d["LatestVersion"], d["UpdateAvailable"] = true, "0.247.0", false + d["RegistryAnonymous"] = false + d["LastUpdateState"] = map[string]interface{}{"Status": "failed", "Error": "pull failed"} + d["MemorySupported"], d["MemoryReachable"], d["MemoryProcMB"] = true, false, 4096 + return d + }}, + {"settings_system_pending", "settings_system", func() map[string]interface{} { + d := i18nLayoutData("settings", "Rendszer beállítások") + d["CustomerID"], d["CustomerDomain"] = "test-customer", "example.hu" + d["SelfUpdateEnabled"] = true + d["LastUpdateState"] = map[string]interface{}{"Status": "pending"} + d["MemorySupported"], d["MemoryReachable"], d["MemoryProcMB"] = true, false, 0 + return d + }}, + {"settings_system_nomemory", "settings_system", func() map[string]interface{} { + d := i18nLayoutData("settings", "Rendszer beállítások") + d["MemorySupported"] = false + return d + }}, + {"settings_security_full", "settings_security", func() map[string]interface{} { + d := i18nLayoutData("settings-security", "Biztonság és hozzáférés") + d["PasswordError"] = "A két jelszó nem egyezik." + d["CFConfigured"], d["GeoEnabled"] = true, true + d["DeployedApps"] = []map[string]string{{"Name": "privatebin", "Display": "Private Bin"}} + d["GeoLastSync"], d["GeoLastError"] = "2026-09-14 03:12", "api error" + d["GeoAllowedCountries"] = []string{"HU"} + d["GeoAppOverrides"] = map[string][]string{"privatebin": {"HU", "AT"}} + d["HasRetrievalPassword"] = true + d["CustomerID"], d["HubURL"] = "test-customer", "https://hub.example" + d["SupportEmail"], d["SupportURL"] = "support@example.hu", "https://example.hu/kapcsolat" + return d + }}, + {"settings_security_noauth", "settings_security", func() map[string]interface{} { + d := i18nLayoutData("settings-security", "Biztonság és hozzáférés") + d["AuthEnabled"] = false + d["CFConfigured"], d["GeoEnabled"] = false, false + d["GeoAllowedCountries"] = []string{} + d["GeoAppOverrides"] = map[string][]string{} + return d + }}, + {"settings_notifications_hub", "settings_notifications", func() map[string]interface{} { + d := i18nLayoutData("settings-notifications", "Értesítések") + d["HubEnabled"] = true + d["NotificationSuccess"], d["NotificationError"] = "A beállítás elmentve.", "A mentés nem sikerült." + d["NotificationPrefs"] = map[string]interface{}{"Email": "anna@example.hu", "EnabledEvents": []string{"backup_failed", "node_down"}, "CooldownHours": 4} + d["AppEmailAvailable"], d["AppEmailEnabled"], d["AppEmailFromName"] = true, true, "Kovács család" + d["AppEmailSuccess"], d["AppEmailError"] = "Az e-mail beállítás mentve.", "Az e-mail beállítás hibás." + return d + }}, + {"settings_notifications_nohub", "settings_notifications", func() map[string]interface{} { + d := i18nLayoutData("settings-notifications", "Értesítések") + d["HubEnabled"] = false + return d + }}, + {"logs", "logs", func() map[string]interface{} { + d := i18nLayoutData("stacks", "Private Bin naplók") + st := i18nStack("privatebin", "Private Bin", stacks.StateRunning, true) + d["Stack"] = st + d["Logs"] = "2026-09-14 line one\nline two" + return d + }}, + } + return cases +} + +// i18nDeployData builds the deploy page. variant 1 and 2 split the branches that cannot co-exist. +func i18nDeployData(deployed bool, st stacks.ContainerState, variant int) map[string]interface{} { + title := "Private Bin telepítése" + d := i18nLayoutData("stacks", title) + stack := i18nStack("privatebin", "Private Bin", st, deployed) + stack.Meta.Subdomain = "paste" + stack.Meta.AppInfo = stacks.AppInfo{FirstSteps: []string{"Nyisd meg a címet"}, DefaultCreds: "nincs ilyen", DocsURL: "https://example.org/docs"} + d["Stack"] = stack + d["Meta"] = stack.Meta + d["AlreadyDeployed"] = deployed + d["LogoURL"], d["LogoPNGURL"], d["AppPageURL"] = "/logo.svg", "/logo.png", "/apps/privatebin" + d["EffectiveSubdomain"] = "paste" + d["SystemDataPath"] = "/mnt/sys_drive/data" + d["FlashSuccess"] = "A mentés sikeresen elkészült." + d["FlashError"] = "A művelet most nem sikerült." + d["DeployedFieldValues"] = map[string]string{"SUBDOMAIN": "paste", "ADMIN_PASSWORD": "rejtett érték"} + d["RestoreFieldValues"] = map[string]string{} + d["CurrentValues"] = map[string]string{"API_KEY": "abc123"} + d["AutoFieldValues"] = map[string]string{"SECRET_KEY": "generated-secret-value", "DB_NAME": "privatebin_db"} + d["AutoFields"] = []map[string]interface{}{ + {"EnvVar": "SECRET_KEY", "Label": "Titkos kulcs érték", "Type": "secret"}, + {"EnvVar": "DB_NAME", "Label": "Adatbázis neve itt", "Type": "text"}, + {"EnvVar": "EMPTY_ONE", "Label": "Üres mező értéke", "Type": "text"}, + } + storagePaths := []map[string]interface{}{ + {"Path": "/mnt/hdd1", "Label": "HDD egy", "FreeHuman": "500 GB", "FreePercent": 50.0, "NotAllowed": false, "IsDefault": true}, + {"Path": "/mnt/nas", "Label": "NAS egy", "FreeHuman": "900 GB", "FreePercent": 90.0, "NotAllowed": true, "NotAllowedNote": "hálózati tárhely nem használható", "IsDefault": false}, + {"Path": "/mnt/hdd2", "Label": "HDD kettő", "FreeHuman": "100 GB", "FreePercent": 10.0, "NotAllowed": false, "IsDefault": false}, + } + d["UserFields"] = []map[string]interface{}{ + {"EnvVar": "SUBDOMAIN", "Label": "Webcím eleje", "Type": "subdomain", "Required": true, "Default": "paste", "Description": "A cím első része"}, + {"EnvVar": "LANG_SEL", "Label": "Felület nyelve", "Type": "select", "Options": []map[string]string{{"Value": "hu", "Label": "Magyar nyelv"}}}, + {"EnvVar": "ADMIN_PASSWORD", "Label": "Admin jelszó mező", "Type": "password", "Placeholder": "Legalább 12 karakter", "LockedAfterDeploy": true}, + {"EnvVar": "FLAG", "Label": "Kapcsoló mező itt", "Type": "boolean", "Description": "Egy kapcsoló leírása"}, + {"EnvVar": "HDD_PATH", "Label": "Adatok helye itt", "Type": "path", "Required": true, "Placeholder": "/mnt/valahol"}, + {"EnvVar": "NOTE", "Label": "Megjegyzés mező", "Type": "text", "Placeholder": "Írj ide valamit"}, + } + d["HasIntegrations"] = true + d["Integrations"] = []map[string]interface{}{ + {"Label": "Integráció egy", "Description": "Első integráció leírása", "Target": "a", "TargetDeployed": false}, + {"Label": "Integráció kettő", "Description": "Második integráció leírása", "Target": "b", "TargetDeployed": true, "TargetRunning": false}, + {"Label": "Integráció három", "Description": "Harmadik integráció leírása", "Target": "c", "TargetDeployed": true, "TargetRunning": true, "Status": "error"}, + {"Label": "Integráció négy", "Description": "Negyedik integráció leírása", "Target": "d", "TargetDeployed": true, "TargetRunning": true, "Status": "ok", "Enabled": true}, + {"Label": "Integráció öt", "Description": "Ötödik integráció leírása", "Target": "e", "TargetDeployed": true, "TargetRunning": true, "Status": "ok", "Enabled": false}, + } + d["GeoGlobalEnabled"] = true + d["GeoGlobalCountries"] = []string{"HU"} + d["GeoAppOverrideCountries"] = []string{"HU", "AT"} + d["HasOptionalConfig"] = true + d["OptionalConfig"] = []map[string]interface{}{ + {"Group": "Külső szolgáltatások", "Description": "Opcionális kulcsok leírása", "Fields": []map[string]interface{}{ + {"EnvVar": "API_KEY", "Label": "API kulcs mező", "Type": "secret_input", "HelpText": "Ide jön a kulcs", "HelpURL": "https://example.org/reg"}, + {"EnvVar": "OTHER", "Label": "Másik mező itt", "Type": "text"}, + }}, + } + d["AppEmailSupported"] = true + d["AppEmailFromAddress"] = "noreply@example.hu" + if variant == 1 { + d["StoragePaths"] = storagePaths + d["RestoreHasRecord"] = true + d["RestoreRecordedAddress"] = "paste.example.hu" + d["RestoreRecordedDrive"] = "HDD egy" + d["RestorePrefillHDDPath"] = "/mnt/hdd1" + d["GeoAppOverride"] = true + d["AppEmailGlobalOn"] = false + d["AppEmailAppOn"] = true + d["MemoryInfo"] = map[string]interface{}{"Available": true, "Blocked": false, "OvercommitWarn": true, "AfterMB": 3000, "UsableMB": 4000, + "Percent": 75, "UsedPercent": 70, "UsedMB": 2800, "NewRequestMB": 128} + d["StorageInfo"] = map[string]interface{}{"Label": "HDD egy", "Path": "/mnt/hdd1", "DataSizeHuman": "2 GB", "FreeHuman": "500 GB", "FreePercent": 50.0} + d["OtherStoragePaths"] = []string{"/mnt/hdd2"} + d["StaleData"] = []map[string]interface{}{{"Label": "HDD kettő", "Path": "/mnt/hdd2", "SizeHuman": "1 GB", "Mounts": []string{"/data/uploads"}}} + d["CurrentHDDPath"] = "/mnt/hdd1" + } else if variant == 3 { + d["StoragePaths"] = storagePaths + d["MemoryInfo"] = map[string]interface{}{"Available": true, "Blocked": true, "AfterMB": 5000, "UsableMB": 4000, + "Percent": 100, "UsedPercent": 90, "UsedMB": 3600, "NewRequestMB": 128} + d["CurrentHDDPath"] = "/mnt/gone" + d["CurrentHDDPathMissing"] = true + } else { + d["RestoreRecordedDeclaresPath"] = true + d["DockerBelowReserve"] = true + d["DockerFreeHuman"], d["DockerReserveHuman"] = "1 GB", "5 GB" + d["AppEmailGlobalOn"] = true + d["MemoryInfo"] = map[string]interface{}{"Available": true, "Blocked": true, "AfterMB": 5000, "UsableMB": 4000, + "Percent": 100, "UsedPercent": 90, "UsedMB": 3600, "NewRequestMB": 128} + d["StorageInfo"] = map[string]interface{}{"Label": "HDD egy", "Path": "/mnt/hdd1"} + d["CurrentHDDPath"] = "/mnt/gone" + d["CurrentHDDPathMissing"] = true + d["StoragePaths"] = nil + } + return d +} diff --git a/controller/internal/web/i18n_parity_test.go b/controller/internal/web/i18n_parity_test.go index f181755..f19567d 100644 --- a/controller/internal/web/i18n_parity_test.go +++ b/controller/internal/web/i18n_parity_test.go @@ -67,7 +67,7 @@ func i18nLayoutData(page, title string) map[string]interface{} { } func i18nCases() []i18nCase { - return []i18nCase{ + base := []i18nCase{ {"launcher_full", "launcher", func() map[string]interface{} { d := i18nLayoutData("launcher", "Indítópult") d["ClaimLegacyOpen"] = true @@ -270,6 +270,9 @@ func i18nCases() []i18nCase { return d }}, } + // Slice 1 (R-556): one file of cases per release, each captured from its unconverted templates. + base = append(base, i18nCasesA()...) + return base } func renderI18nCase(t *testing.T, s *Server, lang string, c i18nCase) string { diff --git a/controller/internal/web/testdata/i18n_parity/app_export.html b/controller/internal/web/testdata/i18n_parity/app_export.html new file mode 100644 index 0000000..4cd66eb --- /dev/null +++ b/controller/internal/web/testdata/i18n_parity/app_export.html @@ -0,0 +1,805 @@ + + + + +
+ + +.fab csomag feltöltése — húzza ide, vagy válassza ki a fájlt
+ + +| Alkalmazás | +Dátum | +Méret | +Tároló | +Titkos | ++ |
|---|---|---|---|---|---|
| Private Bin | +2026-09-14 03:12 | +12 MB | +HDD egy | +🔒 | ++ |
| kimai | +2026-09-13 03:12 | +40 MB | +/mnt/hdd2 | ++ | + |
.fab csomag feltöltése — húzza ide, vagy válassza ki a fájlt
+ + +Nem található .fab csomag a regisztrált tárolókon.
+Exportálj egy alkalmazást az alkalmazás oldaláról, tölts fel egy .fab fájlt itt fent, vagy másolj egyet a {tároló}/felhom-data/exports/ könyvtárba.
Nincs adat
+ +Nincs elérhető alkalmazás.
+Nincs adat
+ +Nincs elérhető alkalmazás.
+Nincs adat
+ +Nincs elérhető alkalmazás.
++ Az alkalmazás adatainak másolata megtalálható egy másik tárolón is. + Ez általában áthelyezés után marad hátra. +
+ ++ Más telepített alkalmazásokkal való összekapcsolás. Az integráció automatikusan felfüggesztődik, ha bármelyik alkalmazás leáll, és újraaktiválódik indításkor. +
+ + +Első integráció leírása
+ + Nincs telepítve + +Második integráció leírása
+ + Célalkalmazás leállítva + +Harmadik integráció leírása
+ + Hiba + +Negyedik integráció leírása
+ + Aktív + +Ötödik integráció leírása
+ ++ Az alkalmazás egyéni országkorlátozás nélkül a globális beállítást követi. +
+ + + +Opcionális kulcsok leírása
+ +Ide jön a kulcs
+ + ++ Ez az alkalmazás tud emailt küldeni (pl. jelszó-visszaállítás, meghívók) a Felhom-on keresztül, + külön szolgáltató beállítása nélkül. A feladó címe: noreply@example.hu. +
+ ++ Az alkalmazás-email jelenleg ki van kapcsolva globálisan. Kapcsold be a + Beállítások oldalon, hogy itt is működjön. +
+ + ++ Más telepített alkalmazásokkal való összekapcsolás. Az integráció automatikusan felfüggesztődik, ha bármelyik alkalmazás leáll, és újraaktiválódik indításkor. +
+ + +Első integráció leírása
+ + Nincs telepítve + +Második integráció leírása
+ + Célalkalmazás leállítva + +Harmadik integráció leírása
+ + Hiba + +Negyedik integráció leírása
+ + Aktív + +Ötödik integráció leírása
+ ++ Az alkalmazás egyéni országkorlátozás nélkül a globális beállítást követi. +
+ + + + +Opcionális kulcsok leírása
+ +Ide jön a kulcs
+ + ++ Ez az alkalmazás tud emailt küldeni (pl. jelszó-visszaállítás, meghívók) a Felhom-on keresztül, + külön szolgáltató beállítása nélkül. A feladó címe: noreply@example.hu. +
+ + ++ Más telepített alkalmazásokkal való összekapcsolás. Az integráció automatikusan felfüggesztődik, ha bármelyik alkalmazás leáll, és újraaktiválódik indításkor. +
+ + +Első integráció leírása
+ + Nincs telepítve + +Második integráció leírása
+ + Célalkalmazás leállítva + +Harmadik integráció leírása
+ + Hiba + +Negyedik integráció leírása
+ + Aktív + +Ötödik integráció leírása
+ ++ Az alkalmazás egyéni országkorlátozás nélkül a globális beállítást követi. +
+ + + +Opcionális kulcsok leírása
+ +Ide jön a kulcs
+ + ++ Ez az alkalmazás tud emailt küldeni (pl. jelszó-visszaállítás, meghívók) a Felhom-on keresztül, + külön szolgáltató beállítása nélkül. A feladó címe: noreply@example.hu. +
+ ++ Az alkalmazás-email jelenleg ki van kapcsolva globálisan. Kapcsold be a + Beállítások oldalon, hogy itt is működjön. +
+ + ++ Más telepített alkalmazásokkal való összekapcsolás. Az integráció automatikusan felfüggesztődik, ha bármelyik alkalmazás leáll, és újraaktiválódik indításkor. +
+ + +Első integráció leírása
+ + Nincs telepítve + +Második integráció leírása
+ + Célalkalmazás leállítva + +Harmadik integráció leírása
+ + Hiba + +Negyedik integráció leírása
+ + Aktív + +Ötödik integráció leírása
+ ++ Az alkalmazás egyéni országkorlátozás nélkül a globális beállítást követi. +
+ + + + +Opcionális kulcsok leírása
+ +Ide jön a kulcs
+ + ++ Ez az alkalmazás tud emailt küldeni (pl. jelszó-visszaállítás, meghívók) a Felhom-on keresztül, + külön szolgáltató beállítása nélkül. A feladó címe: noreply@example.hu. +
+ + ++ Más telepített alkalmazásokkal való összekapcsolás. Az integráció automatikusan felfüggesztődik, ha bármelyik alkalmazás leáll, és újraaktiválódik indításkor. +
+ + +Első integráció leírása
+ + Nincs telepítve + +Második integráció leírása
+ + Célalkalmazás leállítva + +Harmadik integráció leírása
+ + Hiba + +Negyedik integráció leírása
+ + Aktív + +Ötödik integráció leírása
+ ++ Az alkalmazás egyéni országkorlátozás nélkül a globális beállítást követi. +
+ + + + +Opcionális kulcsok leírása
+ +Ide jön a kulcs
+ + ++ Ez az alkalmazás tud emailt küldeni (pl. jelszó-visszaállítás, meghívók) a Felhom-on keresztül, + külön szolgáltató beállítása nélkül. A feladó címe: noreply@example.hu. +
+ ++ Az alkalmazás-email jelenleg ki van kapcsolva globálisan. Kapcsold be a + Beállítások oldalon, hogy itt is működjön. +
+ + +2026-09-14 line one +line two+
https://hub.example
+ test-customer
+ https://hub.example
+ test-customer
+ + Az alkalmazások a Felhom-on keresztül küldhetnek emailt (pl. jelszó-visszaállítás, meghívók), + külön email-szolgáltató beállítása nélkül. A feladó címe minden alkalmazásnál a saját + <alkalmazás>@felhom.eu címe lesz. +
++ Bekapcsolás után az egyes alkalmazásoknál is engedélyezni kell az email-küldést (az alkalmazás oldalán). +
+
+ Ország alapján korlátozható a webes alkalmazások elérése a Cloudflare WAF segítségével.
+
A helyi hálózati hozzáférés mindig engedélyezett (nem halad át a Cloudflare-en).
+
+ Ezeket az adatokat mentse el biztos helyre. Újratelepítés esetén szükség lesz rájuk a rendszer visszaállításához. +
+
+ Ország alapján korlátozható a webes alkalmazások elérése a Cloudflare WAF segítségével.
+
A helyi hálózati hozzáférés mindig engedélyezett (nem halad át a Cloudflare-en).
+
Az üzemeltető által beállított értékek. Módosításhoz kérd az üzemeltetőt.
+Ezek az értékek a helyi hálózattól függenek és változhatnak. Távoli hibaelhárításnál ezt az oldalt kérjük felolvasni.
+A kiszolgáló ügynök jelenleg nem elérhető — próbáld meg később.
+ + ++ Ha a vezérlő hibásan működik, itt biztonságosan újraindíthatja — nem kell az egész szervert újraindítani. + Az alkalmazásai futnak tovább; csak a vezérlő indul újra (néhány másodperc). +
+ + ++ Az egész kiszolgáló (szerver) újraindítása. Minden alkalmazás rövid időre leáll, és a vezérlőpult kb. 30 másodpercig nem elérhető. Akkor használja, ha a teljes rendszer újraindítására van szükség — egyébként a fenti „Vezérlő újraindítása” elegendő. +
+ + +Az üzemeltető által beállított értékek. Módosításhoz kérd az üzemeltetőt.
+Ezek az értékek a helyi hálózattól függenek és változhatnak. Távoli hibaelhárításnál ezt az oldalt kérjük felolvasni.
++ Ha a vezérlő hibásan működik, itt biztonságosan újraindíthatja — nem kell az egész szervert újraindítani. + Az alkalmazásai futnak tovább; csak a vezérlő indul újra (néhány másodperc). +
+ + ++ Az egész kiszolgáló (szerver) újraindítása. Minden alkalmazás rövid időre leáll, és a vezérlőpult kb. 30 másodpercig nem elérhető. Akkor használja, ha a teljes rendszer újraindítására van szükség — egyébként a fenti „Vezérlő újraindítása” elegendő. +
+ + +Az üzemeltető által beállított értékek. Módosításhoz kérd az üzemeltetőt.
+Ezek az értékek a helyi hálózattól függenek és változhatnak. Távoli hibaelhárításnál ezt az oldalt kérjük felolvasni.
+A memória átméretezéséhez a kiszolgáló rendszerfrissítése szükséges.
+ ++ Ha a vezérlő hibásan működik, itt biztonságosan újraindíthatja — nem kell az egész szervert újraindítani. + Az alkalmazásai futnak tovább; csak a vezérlő indul újra (néhány másodperc). +
+ + ++ Az egész kiszolgáló (szerver) újraindítása. Minden alkalmazás rövid időre leáll, és a vezérlőpult kb. 30 másodpercig nem elérhető. Akkor használja, ha a teljes rendszer újraindítására van szükség — egyébként a fenti „Vezérlő újraindítása” elegendő. +
+ + +Az üzemeltető által beállított értékek. Módosításhoz kérd az üzemeltetőt.
+Ezek az értékek a helyi hálózattól függenek és változhatnak. Távoli hibaelhárításnál ezt az oldalt kérjük felolvasni.
+A kiszolgáló ügynök jelenleg nem elérhető — próbáld meg később.
+ + ++ Ha a vezérlő hibásan működik, itt biztonságosan újraindíthatja — nem kell az egész szervert újraindítani. + Az alkalmazásai futnak tovább; csak a vezérlő indul újra (néhány másodperc). +
+ + ++ Az egész kiszolgáló (szerver) újraindítása. Minden alkalmazás rövid időre leáll, és a vezérlőpult kb. 30 másodpercig nem elérhető. Akkor használja, ha a teljes rendszer újraindítására van szükség — egyébként a fenti „Vezérlő újraindítása” elegendő. +
+ + +Fájlkezelő — a tárhely fájljainak böngészése a böngészőből.
+ + + + + + +Egy teszt alkalmazás leírása
+ + + + + + + +Egy teszt alkalmazás leírása
+ + + + + + + +Egy teszt alkalmazás leírása
+ + + + + +Egy teszt alkalmazás leírása
+ + + + + + + +Egy teszt alkalmazás leírása
+ + + + + + +Egy teszt alkalmazás leírása
+ + + + + + + +