39 lines
2.4 KiB
Markdown
39 lines
2.4 KiB
Markdown
|
|
# ADR-003: MessageProvider Pattern for i18n
|
||
|
|
|
||
|
|
**Status:** Accepted
|
||
|
|
**Date:** 2026-03-18
|
||
|
|
|
||
|
|
## Context
|
||
|
|
|
||
|
|
Validation error messages shown to end users must be human-readable. Applications targeting different locales need messages in different languages. Hardcoding English messages inside the `Validator` implementation would make internationalization impossible without forking the package.
|
||
|
|
|
||
|
|
At the same time, the majority of applications use a single language throughout their lifetime. Requiring every caller to configure a message provider would be boilerplate-heavy for the common case.
|
||
|
|
|
||
|
|
## Decision
|
||
|
|
|
||
|
|
A `MessageProvider` interface is defined:
|
||
|
|
|
||
|
|
```go
|
||
|
|
type MessageProvider interface {
|
||
|
|
Message(field, tag, param string) string
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
`Message` receives the failing field name, the rule tag, and the rule parameter (e.g., `"5"` for `min=5`, or `""` if none), and returns a human-readable string.
|
||
|
|
|
||
|
|
Two built-in implementations are provided as package-level variables:
|
||
|
|
- `DefaultMessages` — English, used automatically when no option is passed to `New()`.
|
||
|
|
- `SpanishMessages` — Spanish, available as an opt-in via `WithMessageProvider(valid.SpanishMessages)`.
|
||
|
|
|
||
|
|
Custom implementations are supported by passing any value that satisfies `MessageProvider` to `WithMessageProvider`.
|
||
|
|
|
||
|
|
The `New()` constructor defaults to `DefaultMessages` and applies options via a `config` struct, following the functional options pattern. This means zero boilerplate for the common (English) case and a single option call for overrides.
|
||
|
|
|
||
|
|
## Consequences
|
||
|
|
|
||
|
|
- **Positive**: English is the zero-configuration default — `valid.New()` requires no arguments.
|
||
|
|
- **Positive**: Spanish is available without any external dependency — just `valid.SpanishMessages`.
|
||
|
|
- **Positive**: Applications can supply their own `MessageProvider` for any other language or for message formats that include the failing value, link to docs, etc.
|
||
|
|
- **Negative**: The built-in providers handle only four tags (`required`, `email`, `min`, `max`) explicitly; all others fall through to a generic fallback message. Applications using many custom tags should supply a custom provider.
|
||
|
|
- **Note**: Message formatting uses the struct field name as returned by `go-playground/validator` (the Go field name, e.g. `"Email"`), not a JSON tag. If user-facing messages must show the JSON key name, a custom `MessageProvider` combined with a registered tag name function on the playground validator would be needed.
|