R-516: the formal forms in Go literals move into the bundle in the te-form
gates / gates (push) Successful in 50s

22 Go-literal messages (escrow handler, share password page, export
upload, network-storage uid/remove/attach failures) are bundle keys with
te-form Hungarian and English; a detached attach failure renders in the
reader's language. The NAS refusal says „Válassz". Setup wizard,
recovery-info.txt (R-554) and the SMART/fill-watch wire texts are left.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
2026-10-06 21:40:02 +02:00
parent f65ace0ca6
commit 3d6ba2852f
14 changed files with 254 additions and 51 deletions
+34 -29
View File
@@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"net"
"net/http"
"strings"
"sync"
"time"
@@ -41,13 +42,17 @@ type netAgent interface {
// netAddJob is the poll-visible orchestration state (GET /api/storage/netstorage/add/status).
type netAddJob struct {
Name string `json:"name"`
Phase string `json:"phase"` // agent_add | verifying | probing | registering | done | failed
Category string `json:"category,omitempty"` // failure category (agent classifier vocabulary + not_writable/probe_io)
Message string `json:"message,omitempty"` // the category's Hungarian customer message (§3.2)
Detail string `json:"detail,omitempty"` // raw English/journal detail (the collapsible)
Warn string `json:"warn,omitempty"` // non-fatal note on a successful add (e.g. probe cleanup)
Path string `json:"path,omitempty"` // the registered in-guest path (done only)
Name string `json:"name"`
Phase string `json:"phase"` // agent_add | verifying | probing | registering | done | failed
Category string `json:"category,omitempty"` // failure category (agent classifier vocabulary + not_writable/probe_io)
Message string `json:"message,omitempty"` // the category's Hungarian customer message (§3.2)
Detail string `json:"detail,omitempty"` // raw English/journal detail (the collapsible)
Warn string `json:"warn,omitempty"` // non-fatal note on a successful add (e.g. probe cleanup)
Path string `json:"path,omitempty"` // the registered in-guest path (done only)
// server and mappedUID (R-516) parameterize the failure message, which the status handler renders
// in the reader's language.
server string
mappedUID int
StartedAt time.Time `json:"started_at"`
UpdatedAt time.Time `json:"updated_at"`
}
@@ -183,7 +188,8 @@ func (s *Server) runNetAdd(agent netAgent, req agentapi.AddNetStorageRequest, la
fail := func(category, detail string) {
job.Phase = netAddPhaseFailed
job.Category = category
job.Message = netAddMessage(category, req.Server, req.MappedUID)
job.server, job.mappedUID = req.Server, req.MappedUID
job.Message = s.netAddMessage(s.boxLang(), category, req.Server, req.MappedUID)
job.Detail = detail
job.UpdatedAt = time.Now().UTC()
s.netAdd.set(job)
@@ -321,41 +327,40 @@ func (s *Server) pollAgentVerify(ctx context.Context, agent netAgent, jobID stri
}
}
// netAddMessage maps a failure category to the EXACT Hungarian customer message (§3.2). server and
// mappedUID parameterize the unreachable/not_writable texts (host id = mapped uid + 100000).
func netAddMessage(category, server string, mappedUID int) string {
// netAddMessage maps a failure category to the customer message (§3.2) in lang. server and mappedUID
// parameterize the unreachable/not_writable texts (host id = mapped uid + 100000). R-516: the texts
// live in the bundle (api.netstorage.add.*), in the te-form, in both languages.
func (s *Server) netAddMessage(lang, category, server string, mappedUID int) string {
switch category {
case "unreachable":
msg := "A szerver nem érhető el (" + server + "). Ellenőrizze az IP-címet, és hogy a NAS be van-e kapcsolva."
msg := s.msgLang(lang, "api.netstorage.add.unreachable", server)
// R-66 Leg C: a single-label non-IP server (»FELHOM«) is almost always a Windows/NetBIOS
// network name, which this box generally cannot resolve — name the trap instead of letting
// the generic text teach nothing. Purely lexical on the submitted value: NO NetBIOS/mDNS
// resolution is ever attempted, and an IP or dotted DNS name never gets nagged about this.
if looksLikeFlatNetworkName(server) {
msg += " Tipp: a(z) »" + server + "« Windows-hálózati névnek tűnik — használja az eszköz IP-címét."
msg += s.msgLang(lang, "api.netstorage.add.flat_name_tip", server)
}
return msg
case "nfs_export":
return "A megosztás nem található, vagy a NAS nem engedélyezi ennek a gépnek a hozzáférését. Ellenőrizze az export útvonalát, és hogy a NAS engedélyezi-e a Felhom gép IP-címét."
case "smb_auth":
return "Hibás SMB felhasználónév vagy jelszó."
case "smb_share":
return "A megadott SMB-megosztás nem található a szerveren. Ellenőrizze a megosztás nevét."
case "timeout":
return "Időtúllépés a csatolás közben — a szerver elérhető a hálózaton, de a megosztás nem csatolható. Ellenőrizze a NAS NFS/SMB szolgáltatását."
case "nfs_export", "smb_auth", "smb_share", "timeout", "not_network_fs", "probe_io", "busy":
return s.msgLang(lang, "api.netstorage.add."+category)
case "not_writable":
return "A megosztás csatolható, de az alkalmazások nem tudnak rá írni. NFS esetén kapcsolja be a NAS-on a „minden felhasználó leképezése” (map all users / all squash) beállítást a megosztáson — vagy állítsa a fájlok tulajdonosát a(z) " + fmt.Sprint(mappedUID+100000) + " azonosítóra. SMB esetén ellenőrizze, hogy a felhasználónak írási joga van a megosztáson."
case "not_network_fs":
return "A hálózati tárhely csatolása a rendszeren belül nem jött létre megfelelően. Próbálja újra a csatlakoztatást; ha a hiba ismétlődik, jelezze az üzemeltetőnek."
case "probe_io":
return "Írási hiba a megosztáson (az adat nem olvasható vissza hibátlanul). Ellenőrizze a megosztást és a hálózatot."
case "busy":
return "Már folyamatban van egy csatlakoztatás. Várja meg, amíg befejeződik."
return s.msgLang(lang, "api.netstorage.add.not_writable", mappedUID+100000)
default: // mount_failed + agent_error + register_failed + any future agent code
return "A csatolás sikertelen. Részletek alább."
return s.msgLang(lang, "api.netstorage.add.failed")
}
}
// netAddJobMessage renders a failed job's message in the READER's language (the job ran detached,
// with no request; it keeps the category and its parameters). A job with no category passes its own
// Message through.
func (s *Server) netAddJobMessage(r *http.Request, job *netAddJob) string {
if job.Category == "" {
return job.Message
}
return s.netAddMessage(s.langFor(r), job.Category, job.server, job.mappedUID)
}
// looksLikeFlatNetworkName reports whether a submitted server value is a single-label non-IP name
// (no dot, not an IP literal) — the NetBIOS-name shape. `nas.local` (dotted) and any parseable IP
// (v4 or v6 — colons carry the v6 case through ParseIP) are NOT flagged: the hint must never nag