package util import "fmt" // R-553 — a decision must never be made by reading a customer-facing Hungarian word. // // Five places in this product branched on their own copy (`strings.Contains(err.Error(), "kötelező")` // and friends). The day that copy is translated — localisation slice 2 — every one of them silently // takes the other branch: an install error becomes a 500, a quota failure reads as "unknown cause". // // KindErrorf is the fix in one line: it produces the EXACT same message bytes as `fmt.Errorf` while // carrying a sentinel that `errors.Is` can test. The message is display; the sentinel is the decision. // // return util.KindErrorf(ErrRequiredField, "a(z) %q mező kitöltése kötelező", label) // ... // if errors.Is(err, stacks.ErrRequiredField) { status = http.StatusBadRequest } // // Deliberately NOT `fmt.Errorf("%w: …")`: that prepends the sentinel's own text and would change the // sentence the customer reads, which a localisation-adjacent change may never do. func KindErrorf(kind error, format string, a ...interface{}) error { return &kindError{kind: kind, msg: fmt.Sprintf(format, a...)} } // KindError wraps an existing message (a string built elsewhere) with its kind, bytes unchanged. func KindError(kind error, msg string) error { return &kindError{kind: kind, msg: msg} } type kindError struct { kind error msg string } func (e *kindError) Error() string { return e.msg } // Unwrap is what makes errors.Is(err, kind) true. It deliberately returns the KIND, not a cause // chain: the message is a leaf, and the kind is the only thing a caller may branch on. func (e *kindError) Unwrap() error { return e.kind }