i18n

package
v0.9.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 10, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package i18n provides tanGO's small text-translation primitives.

It is intentionally an override layer: callers keep English fallback text inline in source, while registered catalogs provide translated replacements for stable symbolic keys.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DefaultLocaleResolver

func DefaultLocaleResolver(r *http.Request) string

DefaultLocaleResolver resolves the request locale from Accept-Language, using the registered catalogs as the set of supported locales.

func Locale

func Locale(ctx context.Context) string

Locale returns the resolved locale carried by ctx, or "" when none is set.

func Middleware

func Middleware(resolver LocaleResolver) tango.Middleware

Middleware stores the locale resolved for each request on the request's context so later T calls can observe it, and tells caches and clients what it did: Content-Language names the catalog that was selected (nothing is sent when no catalog matched), and a nil resolver, which uses DefaultLocaleResolver, also adds Vary: Accept-Language to every response. A resolver function cannot say which headers it reads, so none is added for it; wrap it with FuncResolver and MiddlewareResolver to declare them.

func MiddlewareResolver added in v0.7.0

func MiddlewareResolver(resolver Resolver) tango.Middleware

MiddlewareResolver is Middleware for a Resolver: it stores the resolved locale on the request's context, adds the resolver's Vary tokens to every response (merged with any Vary header already present, ignoring case and never repeating a token, and leaving "*" alone), and sets Content-Language to the selected catalog's locale when there is one and nothing else has set it. A nil resolver uses the Accept-Language header.

func OnMissing added in v0.7.0

func OnMissing(f func(locale, key string))

OnMissing registers f to be told about a missing translation: a lookup whose resolved locale has a catalog (or a base-language one) that supplied no usable text for the key, either because the key is absent, its value is empty, or its format verbs do not match the fallback's. f receives the resolved locale and the key, at most once per pair for the life of the process. It is meant for development: run the application in a locale and see what is untranslated.

OnMissing(nil) clears the hook, and the hook is nil by default. Setting, clearing and dispatching are safe for concurrent use. f runs on the goroutine that called T, outside any lock of this package, so it may call T or RegisterCatalog; a panic in f is not recovered.

func RegisterCatalog

func RegisterCatalog(locale string, catalog map[string]string)

RegisterCatalog merges catalog into the existing catalog for locale. Registering the same key again replaces that key's previous value; other keys and other locales are left untouched. Locales are matched without regard to case or to "-" versus "_", so "es-MX" and "es_mx" name one catalog; the spelling used by the first registration is the one DefaultLocaleResolver and Middleware report.

func T

func T(ctx context.Context, key, fallback string, args ...any) string

T returns the translated string for key using the locale carried by ctx, falling back to fallback when no locale/catalog/key is available. When args are present, the chosen string is formatted with fmt.Sprintf before being returned.

func WithLocale

func WithLocale(ctx context.Context, locale string) context.Context

WithLocale returns a child context carrying locale as the resolved locale for translation lookups.

Types

type Key added in v0.7.0

type Key struct {
	Key      string
	Fallback string
}

Key is a translation key together with the fallback text of an i18n.T call that has run in this process.

func Keys added in v0.7.0

func Keys() []Key

Keys returns the keys observed so far, sorted by key. Only text that has run with a resolved locale is known: a key no code path has executed is not listed. The slice is a copy.

type LocaleResolver

type LocaleResolver func(*http.Request) string

LocaleResolver resolves the active locale for one incoming request.

type Problem added in v0.7.0

type Problem struct {
	Kind   ProblemKind
	Locale string
	Key    string
	Detail string
}

Problem is one finding of Validate. Locale is empty for a problem that belongs to a key rather than a catalog.

type ProblemKind added in v0.7.0

type ProblemKind string

ProblemKind says what is wrong with a Problem.

const (
	// ProblemMismatch: a catalog value's format verbs differ from the
	// fallback's, so T would ignore it.
	ProblemMismatch ProblemKind = "mismatch"
	// ProblemEmpty: a catalog value is empty, so T would ignore it.
	ProblemEmpty ProblemKind = "empty"
	// ProblemConflictingFallback: one key was observed with two different
	// fallback texts.
	ProblemConflictingFallback ProblemKind = "conflicting-fallback"
	// ProblemRegistryFull: more distinct keys ran than the registry records
	// (translation fallbacks must be stable literals, never request- or
	// user-derived text), so Validate has not seen every key.
	ProblemRegistryFull ProblemKind = "registry-full"
)

type Report added in v0.7.0

type Report struct {
	// Problems are real defects, sorted by locale, key and kind.
	Problems []Problem
	// Unobserved is advisory, sorted by locale then key: a page that did not
	// run in this process leaves its keys here. A host whose test exercised
	// every page may treat a non-empty list as a failure.
	Unobserved []Unobserved
}

Report is the result of Validate.

func Validate added in v0.7.0

func Validate() Report

Validate checks every registered catalog against the keys observed so far (see Keys). It is a check of what has run in this process, not a startup or static guarantee: exercise the application's pages in the locale first, for instance in a test.

type Resolver added in v0.7.0

type Resolver interface {
	// Resolve returns the locale for r, or "" when it has none. The helpers
	// in this package return only a locale that has a registered catalog.
	Resolve(r *http.Request) string
	// Vary returns the request headers the answer depends on, in canonical
	// form and without duplicates. The caller may keep or change the slice.
	Vary() []string
}

Resolver decides the locale of one request. Unlike a bare LocaleResolver it also says which request headers its answer depends on, so the middleware can tell caches (see Vary).

func Chain added in v0.7.0

func Chain(resolvers ...Resolver) Resolver

Chain tries resolvers in the order given and returns the first answer that has a registered catalog (a resolver that answers a locale nobody translated is skipped), then falls back to the Accept-Language header. Its Vary is the union of the resolvers' and Accept-Language, so a cache in front of the application keeps one copy per language.

func FromCookie added in v0.7.0

func FromCookie(name string) Resolver

FromCookie resolves the locale saved in the cookie called name. A value without a registered catalog resolves nothing. The host sets the cookie; this package never does.

func FromHost added in v0.7.0

func FromHost(hosts map[string]string) Resolver

FromHost resolves the locale a host name stands for, such as "es.example.com" to "es". The map is copied, and its keys compared in lower case without port or trailing dot, so later changes by the caller change nothing. The locale is checked against the catalogs on every request, so catalogs may be registered after the resolver is built.

func FromQuery added in v0.7.0

func FromQuery(param string) Resolver

FromQuery resolves the locale named by the URL query parameter param, for a link or form that asks for a language for one request. A value without a registered catalog resolves nothing.

func FuncResolver added in v0.7.0

func FuncResolver(f LocaleResolver, vary ...string) Resolver

FuncResolver adapts a plain function, for a locale source this package has no helper for (a session, an account preference, a path prefix). A plain function cannot say what it depends on, so name the request headers it reads in vary (for instance "Cookie"); they are normalized and de-duplicated. With none, no Vary header is added for it.

type Unobserved added in v0.7.0

type Unobserved struct {
	Locale string
	Key    string
}

Unobserved is a catalog key that no observed call uses, such as a typo.

Directories

Path Synopsis
Package i18ntest is test support for code that uses the i18n package.
Package i18ntest is test support for code that uses the i18n package.
internal
testhook
Package testhook lets i18n/i18ntest reach the package's global state without exporting a reset from i18n itself.
Package testhook lets i18n/i18ntest reach the package's global state without exporting a reset from i18n itself.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL