Documentation
¶
Overview ¶
Package i18n is the runtime counterpart of the `nucleus makemessages` / `nucleus compilemessages` CLI pair. The CLI extracts translatable strings into `.po` catalogs and compiles them into JSON bundles under `<locales_path>/<locale>/LC_MESSAGES/<domain>.json`; this package loads those bundles, negotiates the request locale from `Accept-Language`, and resolves message keys to translated strings with a deterministic fallback chain (requested locale → its base language → the default locale → the key itself).
Lifecycle: experimental (see docs/reference/API_CONTRACT_INVENTORY.md). The surface may still grow (plural forms, per-domain lookup) before it freezes. Pure stdlib.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Locale ¶
Locale returns the locale stored by WithLocale / the Middleware, or "" when the context carries none.
func T ¶
T resolves key using the translator and locale carried by ctx (both are injected by the Middleware, or by WithTranslator/WithLocale). Without a translator on the context it degrades to the key itself (fmt-formatted when args are given) — the untranslated-application behaviour, never an error.
func WithLocale ¶
WithLocale returns a context carrying the resolved locale. The Middleware calls it for every request; call it directly in non-HTTP code paths (task handlers, mail rendering) that want T to resolve for a specific locale.
func WithTranslator ¶
func WithTranslator(ctx context.Context, t *Translator) context.Context
WithTranslator returns a context carrying the translator T reads from. The Middleware injects it on every request; inject it manually in non-HTTP code paths that call T.
Types ¶
type Catalog ¶
type Catalog struct {
// contains filtered or unexported fields
}
Catalog holds the compiled message entries for every discovered locale. Lookup keys are message IDs as extracted by makemessages; values are the translated strings from the compiled bundles.
func Load ¶
Load reads every compiled bundle under dir, the locales root that `nucleus compilemessages` writes to. The expected layout is the gettext convention the CLI produces:
<dir>/<locale>/LC_MESSAGES/<domain>.json
All domains found for a locale are merged into one lookup table (in lexical file order, so a key defined in two domains resolves to the later domain's value — deterministically). A missing dir, or a dir with no compiled bundles, yields an empty catalog and no error: an application without translations is not misconfigured. A bundle that exists but does not parse IS an error — a corrupt catalog should fail loudly at startup, not fall back to untranslated strings in production.
type Translator ¶
type Translator struct {
// contains filtered or unexported fields
}
Translator resolves message keys against a Catalog with a fixed default locale. It is safe for concurrent use: the catalog is read-only after Load.
func New ¶
func New(catalog *Catalog, defaultLocale string) *Translator
New builds a Translator over catalog. defaultLocale is the fallback when a requested locale has no catalog or no entry for a key; an empty defaultLocale disables that middle step of the fallback chain (the key itself is always the final fallback).
func TranslatorFromContext ¶
func TranslatorFromContext(ctx context.Context) *Translator
TranslatorFromContext returns the translator stored by WithTranslator / the Middleware, or nil when the context carries none.
func (*Translator) DefaultLocale ¶
func (t *Translator) DefaultLocale() string
DefaultLocale returns the configured fallback locale, normalized.
func (*Translator) Locales ¶
func (t *Translator) Locales() []string
Locales returns the locale names the underlying catalog was loaded with.
func (*Translator) Middleware ¶
func (t *Translator) Middleware() func(http.Handler) http.Handler
Middleware returns standard net/http middleware that negotiates the request locale from the Accept-Language header (falling back to the translator's default locale) and stores both the locale and the translator on the request context, where T and router.Context.T read them. It also sets the Content-Language response header to the resolved locale.
func (*Translator) Negotiate ¶
func (t *Translator) Negotiate(acceptLanguage string) string
Negotiate picks the best available catalog locale for an Accept-Language header value. For each accepted tag, in quality order, it tries: an exact catalog match, the tag's base language ("es-MX" → "es"), and finally any catalog locale sharing the tag's base language ("es" matches a catalog that only ships "es-ES"). A `*` tag and an unmatched header both resolve to the default locale.
func (*Translator) T ¶
func (t *Translator) T(locale, key string, args ...any) string
T resolves key for locale. The fallback chain is: the requested locale, its base language (`es-MX` → `es`), the default locale, and finally the key itself — so T always returns a usable string. When args are given the resolved string is treated as a fmt format.