Documentation
¶
Index ¶
- Constants
- Variables
- func DetectLocale() string
- func DiscoverLocales(fs embed.FS, basePath string) []string
- func EncodeBinary(translations map[string]string) ([]byte, error)
- func FlattenKeys(nested map[string]interface{}) map[string]string
- func GetLogger() core.Logger
- func GetParser(ext string) (core.TranslationParser, error)
- func GetSupportedLocales(loader core.TranslationLoader, locales ...string) []string
- func NormalizeLocale(locale string) string
- func RegisterParser(ext string, p core.TranslationParser) error
- func RegisteredFormats() []string
- func RegisteredLocales() []string
- func SetLogger(l core.Logger)
- type AcceptLanguageDetector
- type BinaryParser
- type BrowserDetector
- type ChainDetector
- type ContextTranslator
- func (ct *ContextTranslator) GetLocale() string
- func (ct *ContextTranslator) HasKey(key string) bool
- func (ct *ContextTranslator) SetLocale(locale string)
- func (ct *ContextTranslator) Translate(key string) string
- func (ct *ContextTranslator) TranslateGender(key string, gender core.GenderCategory) string
- func (ct *ContextTranslator) TranslatePlural(key string, count interface{}) string
- func (ct *ContextTranslator) TranslateWithArgs(key string, args ...interface{}) string
- type DefaultFallbackChainer
- type DefaultKeyResolver
- type DefaultLocaleDetector
- type DefaultPluralResolver
- type EmbedFSLoader
- type FileSystemLoader
- type JSONParser
- type LoaderOption
- type LocaleSet
- type MapCache
- type Namespace
- type NopLogger
- func (NopLogger) Debug(string, ...any)
- func (NopLogger) Enabled(core.LogLevel) bool
- func (NopLogger) Error(string, ...any)
- func (NopLogger) Fatal(string, ...any)
- func (NopLogger) Info(string, ...any)
- func (NopLogger) Warn(string, ...any)
- func (n NopLogger) WithContext(context.Context) core.Logger
- func (n NopLogger) WithFields(...any) core.Logger
- func (n NopLogger) WithLevel(core.LogLevel) core.Logger
- type OSEnvProvider
- type Option
- func WithCache(cache core.Cacher) Option
- func WithDefaultLocale(locale string) Option
- func WithFallbackChainer(chainer core.FallbackChainer) Option
- func WithFileSystemLoader(baseDir string) Option
- func WithLoader(loader core.TranslationLoader) Option
- func WithLocaleDetector(detector core.LocaleDetector) Option
- func WithLogger(l core.Logger) Option
- func WithParser(parser core.TranslationParser) Option
- func WithPluralResolver(resolver core.PluralResolver) Option
- func WithRegisteredParser(ext string) Option
- func WithRegistryLoader() Option
- func WithResolver(resolver core.KeyResolver) Option
- type PackageOption
- type PackageTranslator
- func (pt *PackageTranslator) GetLocale() string
- func (pt *PackageTranslator) GetTranslator() core.TranslatorProvider
- func (pt *PackageTranslator) Has(key string) bool
- func (pt *PackageTranslator) HasKey(key string) bool
- func (pt *PackageTranslator) SetLocale(locale string)
- func (pt *PackageTranslator) SetTranslator(t core.TranslatorProvider)
- func (pt *PackageTranslator) T(key string) string
- func (pt *PackageTranslator) TF(key string, args ...interface{}) string
- func (pt *PackageTranslator) Translate(key string) string
- func (pt *PackageTranslator) TranslateGender(key string, gender core.GenderCategory) string
- func (pt *PackageTranslator) TranslatePlural(key string, count interface{}) string
- func (pt *PackageTranslator) TranslateWithArgs(key string, args ...interface{}) string
- type Registry
- type RegistryLoader
- type StaticDetector
- type StructTranslator
- type Translator
- func (t *Translator) GetLocale() string
- func (t *Translator) HasKey(key string) bool
- func (t *Translator) ReloadLocale(locale string) error
- func (t *Translator) SetLocale(locale string)
- func (t *Translator) Translate(key string) string
- func (t *Translator) TranslateGender(key string, gender core.GenderCategory) string
- func (t *Translator) TranslatePlural(key string, count interface{}) string
- func (t *Translator) TranslatePluralWithArgs(key string, count interface{}, args ...interface{}) string
- func (t *Translator) TranslateWithArgs(key string, args ...interface{}) string
- func (t *Translator) TranslateWithMessage(key string, args map[string]interface{}) string
- func (t *Translator) WithContext(ctx context.Context) *ContextTranslator
- func (t *Translator) WithLocaleContext(ctx context.Context, locale string) *ContextTranslator
Constants ¶
const MaxRegisteredLocales = 256
MaxRegisteredLocales caps the total number of locales that may be held in the global registry simultaneously. It exists to prevent unbounded growth of the in-memory locale table, which could otherwise be exploited by a component that calls registerLocale in a loop (or by a misconfigured dynamic registration path).
The limit is intentionally generous — CLDR currently covers roughly 200 locales — but finite.
Variables ¶
var ErrRegistryFull = errors.New("locale registry is full (MaxRegisteredLocales reached)")
ErrRegistryFull is returned by registerLocale when the registry already holds MaxRegisteredLocales distinct entries and the caller is attempting to add a NEW locale (replacing an existing entry is always permitted).
Functions ¶
func DetectLocale ¶
func DetectLocale() string
DetectLocale creates a temporary DefaultLocaleDetector and returns the detected system locale. This eliminates per-package DetectLocale duplication.
func DiscoverLocales ¶
DiscoverLocales reads an embed.FS directory and returns the locale codes found based on JSON filenames. This eliminates the per-package GetSupportedLocales reimplementation (~30 packages do this identically).
Example:
//go:embed locales/*.json var localeFS embed.FS locales := i18n.DiscoverLocales(localeFS, "locales") // returns ["en-US", "es-ES", "fr-FR"]
func EncodeBinary ¶
EncodeBinary converts a flat map of translations to the compact binary format. Keys must be in dot notation and no longer than 255 bytes. Values must be no longer than 65535 bytes. The entry count must not exceed 65535.
func FlattenKeys ¶
FlattenKeys converts a nested map to a flat dot-notation map. For example, {"error": {"required": "..."}} becomes {"error.required": "..."}. Non-string leaf values are converted using fmt.Sprint.
func GetLogger ¶
GetLogger returns the package-level logger. By default, this returns NopLogger which discards all log messages.
func GetParser ¶
func GetParser(ext string) (core.TranslationParser, error)
GetParser returns the core.TranslationParser registered for the given extension in the default package-level registry. See Registry.GetParser for details.
func GetSupportedLocales ¶
func GetSupportedLocales(loader core.TranslationLoader, locales ...string) []string
GetSupportedLocales probes a core.TranslationLoader with the given candidate locale codes and returns those for which Load succeeds without error. Returns an empty slice (never nil) if no candidates are supported.
func NormalizeLocale ¶
NormalizeLocale converts a locale string to BCP 47 format. It handles encoding suffix removal (e.g., .UTF-8), underscore-to-hyphen conversion, case normalization, POSIX/C locale mapping, and language-only codes mapped to their primary regional variant.
All LocaleDetector implementations delegate their Normalize method to this shared function to avoid duplicating normalization logic.
func RegisterParser ¶
func RegisterParser(ext string, p core.TranslationParser) error
RegisterParser registers a core.TranslationParser for the given file extension in the default package-level registry. See Registry.RegisterParser for details.
func RegisteredFormats ¶
func RegisteredFormats() []string
RegisteredFormats returns a sorted slice of all registered file extensions from the default package-level registry. See Registry.RegisteredFormats for details.
func RegisteredLocales ¶
func RegisteredLocales() []string
RegisteredLocales returns a sorted slice of all locale codes currently in the global registry. The returned slice is safe to modify; it does not share memory with the registry internals.
func SetLogger ¶
SetLogger sets the package-level logger. If l is nil, the logger is reset to NopLogger (silent operation). This logger will be used by all Translator instances that don't have a custom logger configured via WithLogger option.
The Logger interface is compatible with github.com/0verkilll/logger.Logger, so you can pass any implementation from that package directly.
Types ¶
type AcceptLanguageDetector ¶
type AcceptLanguageDetector struct {
// contains filtered or unexported fields
}
AcceptLanguageDetector is a core.LocaleDetector that parses an HTTP Accept-Language header per RFC 7231 Section 5.3.5 and returns the highest-priority language tag.
func NewAcceptLanguageDetector ¶
func NewAcceptLanguageDetector(header string) *AcceptLanguageDetector
NewAcceptLanguageDetector creates a new AcceptLanguageDetector that parses the given raw Accept-Language header value. The header is parsed lazily when Detect is called.
Example usage in an HTTP handler:
func handler(w http.ResponseWriter, r *http.Request) {
detector := engine.NewAcceptLanguageDetector(r.Header.Get("Accept-Language"))
translator, _ := engine.New(
engine.WithFileSystemLoader("locales"),
engine.WithLocaleDetector(detector),
)
// translator will use the browser's preferred language
}
func (*AcceptLanguageDetector) Detect ¶
func (d *AcceptLanguageDetector) Detect() string
Detect parses the Accept-Language header and returns the highest-priority language tag after normalization. Returns "" if the header is empty, exceeds the length limit, contains only wildcards, or is unparseable.
func (*AcceptLanguageDetector) Normalize ¶
func (d *AcceptLanguageDetector) Normalize(locale string) string
Normalize converts a locale string to BCP 47 format using the shared normalization logic.
type BinaryParser ¶
type BinaryParser struct{}
BinaryParser parses translations from the compact binary format. The binary format eliminates JSON syntax overhead (quotes, braces, colons) saving approximately 40% on translation data size. The parser implementation is minimal compared to the full JSON parser, reducing compiled binary size.
Binary format specification (version 1):
Header: [0x69][0x31][version:1][entry_count:2 big-endian] Entries: [key_len:1][key:N][val_len:2 big-endian][value:N]...
Keys are stored in pre-flattened dot notation (e.g., "error.validation.required"). Values are always UTF-8 strings. The parser reconstructs the nested map structure expected by the KeyResolver.
func NewBinaryParser ¶
func NewBinaryParser() *BinaryParser
NewBinaryParser creates a new BinaryParser for the compact binary translation format.
func (*BinaryParser) Parse ¶
func (p *BinaryParser) Parse(data []byte) (map[string]interface{}, error)
Parse decodes binary translation data into a nested map compatible with the KeyResolver interface. It validates magic bytes, version, and enforces core.MaxKeyCount. Keys in dot notation are unflattened into nested maps.
type BrowserDetector ¶
type BrowserDetector struct{}
BrowserDetector is a core.LocaleDetector that reads the user's preferred language from the browser via navigator.language / navigator.languages.
On non-WASM builds Detect always returns "". The real implementation is in locale_browser_js.go and is compiled only when targeting js/wasm.
func NewBrowserDetector ¶
func NewBrowserDetector() *BrowserDetector
NewBrowserDetector creates a new BrowserDetector. On non-WASM builds, Detect always returns "". Use this in a ChainDetector so that a fallback detector provides the locale when not running in a browser.
Example usage:
chain := engine.NewChainDetector(
engine.NewBrowserDetector(),
engine.NewDefaultLocaleDetector(nil),
)
func (*BrowserDetector) Detect ¶
func (d *BrowserDetector) Detect() string
Detect returns "" on non-WASM builds.
func (*BrowserDetector) Normalize ¶
func (d *BrowserDetector) Normalize(locale string) string
Normalize converts a locale string to BCP 47 format using the shared normalization logic.
type ChainDetector ¶
type ChainDetector struct {
// contains filtered or unexported fields
}
ChainDetector is a core.LocaleDetector that composes multiple detectors in priority order. It iterates through its detectors and returns the first non-empty result. If all detectors return "", it falls back to "en-US".
func NewChainDetector ¶
func NewChainDetector(detectors ...core.LocaleDetector) *ChainDetector
NewChainDetector creates a new ChainDetector that iterates the given detectors in order, returning the first non-empty locale. If no detectors are provided or all return "", Detect falls back to "en-US".
Example usage composing multiple detection strategies:
chain := engine.NewChainDetector(
engine.NewStaticDetector(overrideFromURL), // highest priority
engine.NewAcceptLanguageDetector(acceptHeader), // browser preference
engine.NewDefaultLocaleDetector(nil), // env var fallback
)
translator, _ := engine.New(
engine.WithFileSystemLoader("locales"),
engine.WithLocaleDetector(chain),
)
func (*ChainDetector) Detect ¶
func (c *ChainDetector) Detect() string
Detect iterates detectors in order and returns the first non-empty result. If all detectors return "" or the chain is empty, returns "en-US".
func (*ChainDetector) Normalize ¶
func (c *ChainDetector) Normalize(locale string) string
Normalize converts a locale string to BCP 47 format. If the chain has at least one detector, it delegates to the first detector's Normalize method. Otherwise it calls NormalizeLocale directly.
type ContextTranslator ¶
type ContextTranslator struct {
// contains filtered or unexported fields
}
ContextTranslator wraps a Translator and passes a context.Context to the logger for trace correlation and observability integration. Since translations are resolved from in-memory data (no I/O), context cancellation does not apply. The context is used solely for structured logging enrichment.
A ContextTranslator may optionally carry a locale override. When set, all translation operations route through that locale instead of reading the underlying Translator's shared locale state. This enables per-request locale scoping (e.g., in HTTP middleware) without mutating the shared Translator, which would race between concurrent requests.
ContextTranslator implements core.TranslatorProvider so it is substitutable anywhere a TranslatorProvider is accepted.
func (*ContextTranslator) GetLocale ¶
func (ct *ContextTranslator) GetLocale() string
GetLocale returns the ContextTranslator's effective locale: the per-instance override if set (via WithLocaleContext), otherwise the underlying Translator's current locale.
func (*ContextTranslator) HasKey ¶
func (ct *ContextTranslator) HasKey(key string) bool
HasKey checks whether a key exists for the ContextTranslator's effective locale (or its fallback chain).
func (*ContextTranslator) SetLocale ¶
func (ct *ContextTranslator) SetLocale(locale string)
SetLocale delegates to the underlying Translator's SetLocale method. The context is passed to the logger for trace correlation.
NOTE: SetLocale mutates shared Translator state; it is NOT scoped to this ContextTranslator's locale override. For per-request locale scoping, use Translator.WithLocaleContext instead.
func (*ContextTranslator) Translate ¶
func (ct *ContextTranslator) Translate(key string) string
Translate delegates to the underlying Translator, scoped to the ContextTranslator's effective locale. The context is passed to the logger for trace correlation.
func (*ContextTranslator) TranslateGender ¶
func (ct *ContextTranslator) TranslateGender(key string, gender core.GenderCategory) string
TranslateGender delegates to the underlying Translator, scoped to the ContextTranslator's effective locale. The context is passed to the logger for trace correlation.
func (*ContextTranslator) TranslatePlural ¶
func (ct *ContextTranslator) TranslatePlural(key string, count interface{}) string
TranslatePlural delegates to the underlying Translator, scoped to the ContextTranslator's effective locale. The context is passed to the logger for trace correlation.
func (*ContextTranslator) TranslateWithArgs ¶
func (ct *ContextTranslator) TranslateWithArgs(key string, args ...interface{}) string
TranslateWithArgs delegates to the underlying Translator, scoped to the ContextTranslator's effective locale. The context is passed to the logger for trace correlation.
type DefaultFallbackChainer ¶
type DefaultFallbackChainer struct {
// contains filtered or unexported fields
}
DefaultFallbackChainer generates locale fallback chains using a built-in mapping of language codes to their primary regional variant. It always includes en-US as the final fallback when the input is not already en-US. Computed chains are cached internally so repeated calls for the same locale return a pre-built slice without allocation.
func NewDefaultFallbackChainer ¶
func NewDefaultFallbackChainer() *DefaultFallbackChainer
NewDefaultFallbackChainer creates a new DefaultFallbackChainer with built-in language-to-region mappings for 28 languages.
func (*DefaultFallbackChainer) GetChain ¶
func (c *DefaultFallbackChainer) GetChain(locale string) []string
GetChain returns the fallback chain for a given locale. The returned slice must not be modified by the caller. Examples:
- "es-MX" returns ["es-MX", "es-ES", "en-US"]
- "pt-BR" returns ["pt-BR", "pt-PT", "en-US"]
- "en-GB" returns ["en-GB", "en-US"]
- "en-US" returns ["en-US"]
type DefaultKeyResolver ¶
type DefaultKeyResolver struct{}
DefaultKeyResolver resolves translation keys using dot notation to navigate nested maps. It enforces MaxKeyLength and MaxKeyDepth validation via ValidateKey before performing the lookup.
func NewDefaultKeyResolver ¶
func NewDefaultKeyResolver() *DefaultKeyResolver
NewDefaultKeyResolver creates a new DefaultKeyResolver that resolves keys using dot-separated notation (e.g., "user.profile.title").
func (*DefaultKeyResolver) Resolve ¶
func (r *DefaultKeyResolver) Resolve(translations map[string]interface{}, key string) (string, error)
Resolve retrieves a translation string for the given key from the translations map. Supports dot notation for nested keys (e.g., "error.validation.required"). Returns the translation string, or an error if the key is not found or invalid.
type DefaultLocaleDetector ¶
type DefaultLocaleDetector struct {
// contains filtered or unexported fields
}
DefaultLocaleDetector is the default implementation of core.LocaleDetector. It reads locale information from environment variables using the provided core.EnvProvider, falling back to "en-US" when no locale is configured.
func NewDefaultLocaleDetector ¶
func NewDefaultLocaleDetector(env core.EnvProvider) *DefaultLocaleDetector
NewDefaultLocaleDetector creates a new DefaultLocaleDetector. If env is nil, the platform default core.EnvProvider is used (OSEnvProvider on standard Go, WASMEnvProvider on js/wasm).
func (*DefaultLocaleDetector) Detect ¶
func (d *DefaultLocaleDetector) Detect() string
Detect retrieves the system locale from environment variables. Priority order: LC_ALL > LANG > LC_MESSAGES > default (en-US).
func (*DefaultLocaleDetector) Normalize ¶
func (d *DefaultLocaleDetector) Normalize(locale string) string
Normalize converts locale strings to BCP 47 format. Handles: en_US.UTF-8 -> en-US, POSIX -> en-US, en -> en-US.
type DefaultPluralResolver ¶
type DefaultPluralResolver struct{}
DefaultPluralResolver resolves plural categories using built-in CLDR rules.
func NewDefaultPluralResolver ¶
func NewDefaultPluralResolver() *DefaultPluralResolver
NewDefaultPluralResolver creates a new DefaultPluralResolver.
func (*DefaultPluralResolver) Resolve ¶
func (r *DefaultPluralResolver) Resolve(locale string, count interface{}) core.PluralCategory
Resolve determines the plural category for the given locale and count. It extracts the language subtag from the locale and looks up the CLDR rule. Returns Other for unknown locales or unrecognized count types.
type EmbedFSLoader ¶
type EmbedFSLoader struct {
// contains filtered or unexported fields
}
EmbedFSLoader loads translation files from an embedded filesystem.
func NewEmbedFSLoader ¶
func NewEmbedFSLoader(fs embed.FS, basePath string, opts ...LoaderOption) *EmbedFSLoader
NewEmbedFSLoader creates a new EmbedFSLoader. The default file extension is ".json"; use WithExtension to override it.
type FileSystemLoader ¶
type FileSystemLoader struct {
// contains filtered or unexported fields
}
FileSystemLoader loads translation files from the filesystem.
func NewFileSystemLoader ¶
func NewFileSystemLoader(baseDir string, opts ...LoaderOption) *FileSystemLoader
NewFileSystemLoader creates a new FileSystemLoader. The default file extension is ".json"; use WithExtension to override it.
type JSONParser ¶
type JSONParser struct{}
JSONParser parses JSON translation files into key-value maps. It enforces size limits (core.MaxJSONSize), nesting depth limits (core.MaxJSONDepth), and key count limits (core.MaxKeyCount) to prevent denial-of-service attacks from malicious input.
func NewJSONParser ¶
func NewJSONParser() *JSONParser
NewJSONParser creates a new JSONParser with built-in security limits for input size, nesting depth, and key count.
func (*JSONParser) Parse ¶
func (p *JSONParser) Parse(data []byte) (map[string]interface{}, error)
Parse decodes data from JSON into a map of translation keys to values. The data must be a JSON object (not array, string, or null). Parse enforces core.MaxJSONSize, core.MaxJSONDepth, and core.MaxKeyCount, returning an ErrInvalidFormat on violations.
type LoaderOption ¶
type LoaderOption func(*loaderConfig)
LoaderOption configures a loader via the functional options pattern.
func WithExtension ¶
func WithExtension(ext string) LoaderOption
WithExtension sets the file extension used by a loader to construct filenames. The extension must include the leading dot (e.g., ".toml", ".yaml").
type LocaleSet ¶
type LocaleSet[T any] struct { // contains filtered or unexported fields }
LocaleSet holds named locale structs for StructTranslator registration. Use RegisterLocales to set up build-tag-selected locale switching.
func NewLocaleSet ¶
NewLocaleSet creates a LocaleSet with a fallback locale.
type MapCache ¶
type MapCache struct {
// contains filtered or unexported fields
}
MapCache is a thread-safe, in-memory translation cache backed by a map. It supports an optional LRU eviction policy when a maximum entry count is configured. When no limit is set (maxEntries == 0), the cache grows without bound. All methods are safe for concurrent use by multiple goroutines.
func NewMapCache ¶
func NewMapCache() *MapCache
NewMapCache creates a new MapCache with no size limit (unlimited mode). Entries are never evicted; call Invalidate to clear the cache.
func NewMapCacheWithLimit ¶
NewMapCacheWithLimit creates a new MapCache with LRU eviction enabled. When the entry count exceeds maxEntries, the least-recently-used entry is evicted. If maxEntries is zero or negative, the cache behaves as unlimited.
func (*MapCache) Get ¶
Get retrieves a cached translation by its cache key. Returns the cached value and true on a hit, or an empty string and false on a miss. When LRU eviction is enabled, a hit promotes the entry to the head of the access list (requires a write lock).
func (*MapCache) Invalidate ¶
func (c *MapCache) Invalidate()
Invalidate discards all cached entries, resetting the cache to an empty state.
type Namespace ¶
type Namespace struct {
// contains filtered or unexported fields
}
Namespace automatically prefixes translation keys with a package name, eliminating manual key prefixing across ecosystem packages.
Namespace is immutable after construction. It holds no mutable state and requires no mutex of its own. All translation operations delegate to the underlying core.TranslatorProvider, which is already thread-safe. Multiple goroutines may safely share a single *Namespace instance.
func NewNamespace ¶
func NewNamespace(prefix string, t core.TranslatorProvider) (*Namespace, error)
NewNamespace creates a Namespace that prefixes all translation keys with the given prefix. The prefix must be non-empty, at most 64 characters, and contain only alphanumeric characters, underscores, or hyphens.
A nil core.TranslatorProvider is accepted without error; all methods will degrade gracefully by returning the namespaced key or a default value.
func (*Namespace) Has ¶
Has checks whether the namespaced key exists in the translator.
When the translator is nil, it returns false. Nil receiver safe: returns false.
func (*Namespace) Key ¶
Key returns the full namespaced key (prefix + "." + key) without performing any translation lookup. Useful for logging, error wrapping, or passing keys to other systems.
Nil receiver safe: returns the key argument unchanged.
func (*Namespace) T ¶
T translates the namespaced key by joining the prefix and key with a dot separator and delegating to the underlying core.TranslatorProvider.
When the translator is nil, it returns the full namespaced key as a fallback. Nil receiver safe: returns the key argument unchanged.
func (*Namespace) TD ¶
TD translates the namespaced key, returning defaultValue when the key is not found or the translator is nil. This is the primary method for ecosystem packages that provide hardcoded English defaults.
Nil receiver safe: returns defaultValue.
func (*Namespace) TF ¶
TF translates the namespaced key with format arguments by joining the prefix and key with a dot separator and delegating to TranslateWithArgs.
When the translator is nil, it returns the full namespaced key without formatting. Nil receiver safe: returns the key argument unchanged.
type NopLogger ¶
type NopLogger struct{}
NopLogger is a silent logger that discards all messages. This is the default logger when no logger is configured. NopLogger is stateless and safe for concurrent use.
func (NopLogger) WithContext ¶
WithContext returns the same NopLogger since context is not used.
func (NopLogger) WithFields ¶
WithFields returns the same NopLogger since fields are not used.
type OSEnvProvider ¶
type OSEnvProvider struct{}
OSEnvProvider wraps os.Getenv for standard Go environments.
func (*OSEnvProvider) Getenv ¶
func (p *OSEnvProvider) Getenv(key string) string
Getenv returns the value of the environment variable named by the key.
type Option ¶
type Option func(*Translator) error
Option is a functional option for configuring the Translator.
func WithCache ¶
WithCache sets a Cacher for resolved-translation caching. When enabled, Translate, TranslatePlural, and TranslateGender cache their results to avoid repeated fallback chain traversal and key resolution. Caching is opt-in; when not set, the Translator has zero caching overhead.
func WithDefaultLocale ¶
WithDefaultLocale sets the default locale for the translator.
func WithFallbackChainer ¶
func WithFallbackChainer(chainer core.FallbackChainer) Option
WithFallbackChainer sets a custom FallbackChainer.
func WithFileSystemLoader ¶
WithFileSystemLoader creates a FileSystemLoader with the given base directory. This is a convenience function that combines loader creation with configuration.
func WithLoader ¶
func WithLoader(loader core.TranslationLoader) Option
WithLoader sets a custom TranslationLoader.
func WithLocaleDetector ¶
func WithLocaleDetector(detector core.LocaleDetector) Option
WithLocaleDetector sets a custom LocaleDetector.
func WithLogger ¶
WithLogger sets a custom Logger for the Translator instance. If l is nil, NopLogger is used (silent operation). This logger takes precedence over the package-level logger set via SetLogger.
func WithParser ¶
func WithParser(parser core.TranslationParser) Option
WithParser sets a custom TranslationParser.
func WithPluralResolver ¶
func WithPluralResolver(resolver core.PluralResolver) Option
WithPluralResolver sets a custom PluralResolver.
func WithRegisteredParser ¶
WithRegisteredParser resolves a TranslationParser from the default package-level registry by file extension and sets it on the Translator. The extension must already be registered (e.g., ".json" is registered by default; external modules register additional formats in their init() functions).
Returns an error wrapping ErrUnknownFormat if no parser is registered for ext.
func WithRegistryLoader ¶
func WithRegistryLoader() Option
WithRegistryLoader creates a RegistryLoader and configures it as the translation loader for a Translator. Because built-in locale data is stored in the compact binary format, this option also sets the BinaryParser as the translation parser. A subsequent WithParser call in the options chain can override the parser if needed.
Usage:
translator, err := i18n.New(
i18n.WithRegistryLoader(),
i18n.WithDefaultLocale("en-US"),
)
func WithResolver ¶
func WithResolver(resolver core.KeyResolver) Option
WithResolver sets a custom KeyResolver.
type PackageOption ¶
type PackageOption func(*PackageTranslator)
PackageOption is a functional option for configuring a PackageTranslator. Unlike the core Option type, PackageOption does not return an error because option setters are trivial value assignments.
func WithDefaults ¶
func WithDefaults(defaults map[string]string) PackageOption
WithDefaults sets the hardcoded English fallback strings on the PackageTranslator. Keys in the map are short keys (e.g., "error.empty_path"), not namespace-prefixed. A nil map is acceptable and is treated as empty.
func WithTranslator ¶
func WithTranslator(t core.TranslatorProvider) PackageOption
WithTranslator sets the initial translator on the PackageTranslator. This has the same effect as calling SetTranslator after construction. A nil value is acceptable and puts the PackageTranslator in defaults-only mode.
type PackageTranslator ¶
type PackageTranslator struct {
// contains filtered or unexported fields
}
PackageTranslator provides per-package translation with namespace scoping, thread-safe translator swapping, and hardcoded default fallbacks. Package authors use this type to eliminate ~100-200 lines of duplicated i18n boilerplate per package.
All methods are nil-safe for the translator field: when no translator has been set, methods fall back to the defaults map, then to the raw key.
PackageTranslator implements core.TranslatorProvider so it can be passed to other packages expecting that interface.
The translator pointer is swapped atomically via atomic.Pointer for lock-free reads. Reads observe either the most recent Store or the zero value (which is treated as "no translator set").
func NewPackageTranslator ¶
func NewPackageTranslator(namespace string, opts ...PackageOption) *PackageTranslator
NewPackageTranslator creates a PackageTranslator with the given namespace and optional configuration. The namespace is validated with core.ValidateKey and becomes a dot-notation prefix for all translation keys.
Returns nil if the namespace is invalid.
func NewPackageTranslatorWithFS ¶
func NewPackageTranslatorWithFS(namespace string, fs embed.FS, basePath string, opts ...PackageOption) *PackageTranslator
NewPackageTranslatorWithFS creates a fully-configured PackageTranslator backed by an embedded filesystem. This is the primary integration point for ecosystem packages — it replaces ~300 lines of per-package i18n.go boilerplate with a single constructor call.
It creates an i18n.Translator with EmbedFSLoader, detects the system locale, and wires everything into a PackageTranslator with namespace scoping.
Example — replaces the entire per-package i18n.go:
//go:embed locales/*.json
var localeFS embed.FS
var I18n = i18n.NewPackageTranslatorWithFS("filesystem", localeFS, "locales",
i18n.WithDefaults(map[string]string{
"error.empty_path": "path cannot be empty",
"error.not_found": "file not found: %s",
}),
)
The returned PackageTranslator:
- Loads translations from the embedded filesystem
- Auto-detects system locale (LC_ALL > LANG > en-US)
- Prefixes all keys with the namespace (e.g., "filesystem.error.empty_path")
- Falls back to defaults when translator is nil or key is missing
- Is thread-safe for concurrent use
- Implements TranslatorProvider for passing to other packages
func (*PackageTranslator) GetLocale ¶
func (pt *PackageTranslator) GetLocale() string
GetLocale implements core.TranslatorProvider. Delegates to the underlying translator's GetLocale. Returns "en-US" if the translator is nil.
func (*PackageTranslator) GetTranslator ¶
func (pt *PackageTranslator) GetTranslator() core.TranslatorProvider
GetTranslator returns the current underlying translator, or nil if none is set.
func (*PackageTranslator) Has ¶
func (pt *PackageTranslator) Has(key string) bool
Has checks whether the namespaced key exists in the underlying translator. Returns false when the translator is nil.
func (*PackageTranslator) HasKey ¶
func (pt *PackageTranslator) HasKey(key string) bool
HasKey implements core.TranslatorProvider. Delegates directly to the underlying translator's HasKey. Returns false if the translator is nil.
func (*PackageTranslator) SetLocale ¶
func (pt *PackageTranslator) SetLocale(locale string)
SetLocale implements core.TranslatorProvider. Delegates to the underlying translator's SetLocale. No-op if the translator is nil.
func (*PackageTranslator) SetTranslator ¶
func (pt *PackageTranslator) SetTranslator(t core.TranslatorProvider)
SetTranslator swaps the underlying translator. Nil is allowed and resets the PackageTranslator to defaults-only mode. This method is thread-safe.
func (*PackageTranslator) T ¶
func (pt *PackageTranslator) T(key string) string
T translates a key by prepending the namespace prefix, delegating to the underlying translator, and falling back to defaults or the raw key.
func (*PackageTranslator) TF ¶
func (pt *PackageTranslator) TF(key string, args ...interface{}) string
TF translates a key with format arguments by prepending the namespace prefix, delegating to the underlying translator, and falling back to formatting the default string or returning the raw key.
func (*PackageTranslator) Translate ¶
func (pt *PackageTranslator) Translate(key string) string
Translate implements core.TranslatorProvider. The key is expected to be fully qualified (already includes namespace when called through the interface). This method does NOT double-prepend the namespace.
func (*PackageTranslator) TranslateGender ¶
func (pt *PackageTranslator) TranslateGender(key string, gender core.GenderCategory) string
TranslateGender implements core.TranslatorProvider. Delegates to the underlying translator's TranslateGender. Returns the key if the translator is nil.
func (*PackageTranslator) TranslatePlural ¶
func (pt *PackageTranslator) TranslatePlural(key string, count interface{}) string
TranslatePlural implements core.TranslatorProvider. Delegates to the underlying translator's TranslatePlural. Returns the key if the translator is nil.
func (*PackageTranslator) TranslateWithArgs ¶
func (pt *PackageTranslator) TranslateWithArgs(key string, args ...interface{}) string
TranslateWithArgs implements core.TranslatorProvider. The key is expected to be fully qualified. This method does NOT double-prepend the namespace.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry holds a map of file extensions to core.TranslationParser implementations. It provides thread-safe registration and lookup of parsers by file extension.
Registration typically happens in init() functions, which run in a single goroutine before main(). However, the Registry is safe for concurrent access at any time via its internal sync.RWMutex. Callers registering parsers concurrently outside init() should be aware of potential races between registration and first use if done in separate goroutines.
func (*Registry) GetParser ¶
func (r *Registry) GetParser(ext string) (core.TranslationParser, error)
GetParser returns the core.TranslationParser registered for the given extension. Returns ErrUnknownFormat if no parser is registered for the extension.
func (*Registry) RegisterParser ¶
func (r *Registry) RegisterParser(ext string, p core.TranslationParser) error
RegisterParser registers a core.TranslationParser for the given file extension. The extension must start with a dot followed by one or more lowercase alphanumeric characters (e.g., ".json", ".toml", ".yaml"). If a parser is already registered for the extension, it is overwritten (last-write-wins).
Returns an error if ext is invalid or p is nil.
External Module Pattern ¶
A separate Go module can provide parsers for additional formats without adding any dependency to the core i18n module. The external module:
- Implements the core.TranslationParser interface
- Calls RegisterParser in its init() function
For example, a TOML parser module would contain:
func init() {
i18n.RegisterParser(".toml", &TOMLParser{})
}
Application code activates the parser via a blank import:
import _ "github.com/0verkilll/i18n-toml"
The same pattern applies to YAML or any other format. External parsers should enforce equivalent size and nesting depth limits (see core.MaxJSONSize and core.MaxJSONDepth) to maintain security parity with the built-in JSON parser.
func (*Registry) RegisteredFormats ¶
RegisteredFormats returns a sorted slice of all registered file extensions. The returned slice is safe to modify; it does not share memory with the registry internals.
type RegistryLoader ¶
type RegistryLoader struct{}
RegistryLoader loads translation data from the global locale registry. Locale data is registered at init time by build-tag-selected locale files. This loader is a peer to FileSystemLoader and EmbedFSLoader; all three loaders remain available and interchangeable via the core.TranslationLoader interface.
func NewRegistryLoader ¶
func NewRegistryLoader() *RegistryLoader
NewRegistryLoader creates a new RegistryLoader that reads from the global locale registry populated by build-tag-selected locale files.
func (*RegistryLoader) Load ¶
func (l *RegistryLoader) Load(locale string) ([]byte, error)
Load retrieves translation data for the specified locale from the global registry. If the locale is registered, Load returns a defensive copy of the data to prevent caller mutation of registry contents. If the locale is not registered, Load returns a descriptive error that mentions the build-tag mechanism.
type StaticDetector ¶
type StaticDetector struct {
// contains filtered or unexported fields
}
StaticDetector is a core.LocaleDetector that always returns a fixed locale. It is intended for testing and explicit locale overrides. Placing it first in a ChainDetector forces a specific locale regardless of other detectors.
func NewStaticDetector ¶
func NewStaticDetector(locale string) *StaticDetector
NewStaticDetector creates a new StaticDetector that always returns the given locale from Detect. The locale is returned exactly as provided, without normalization.
Example usage:
translator, _ := engine.New(
engine.WithFileSystemLoader("locales"),
engine.WithLocaleDetector(engine.NewStaticDetector("fr-FR")),
)
func (*StaticDetector) Detect ¶
func (s *StaticDetector) Detect() string
Detect returns the configured locale string exactly as provided to the constructor.
func (*StaticDetector) Normalize ¶
func (s *StaticDetector) Normalize(locale string) string
Normalize converts a locale string to BCP 47 format using the shared normalization logic.
type StructTranslator ¶
type StructTranslator[T any] struct { // contains filtered or unexported fields }
StructTranslator provides zero-cost translation lookups using Go struct field access instead of map lookups. Each locale is a struct instance with string fields for each translation key. Locale switching is an atomic pointer swap.
Performance: 0.25 ns per lookup (vs 25 ns for cached map-based Translate). This is 100x faster and ideal for game loops and real-time applications.
Usage:
type Messages struct {
Greeting string
Farewell string
ErrEmpty string
}
var enUS = Messages{Greeting: "Hello", Farewell: "Goodbye", ErrEmpty: "cannot be empty"}
var esES = Messages{Greeting: "Hola", Farewell: "Adiós", ErrEmpty: "no puede estar vacío"}
var Msg = NewStructTranslator(&enUS)
// Read (0.25 ns, zero alloc):
fmt.Println(Msg.Get().Greeting)
// Switch locale (atomic, safe from any goroutine):
Msg.Set(&esES)
func NewStructTranslator ¶
func NewStructTranslator[T any](initial *T) *StructTranslator[T]
NewStructTranslator creates a StructTranslator with the given initial locale data.
func (*StructTranslator[T]) Get ¶
func (st *StructTranslator[T]) Get() *T
Get returns a pointer to the active locale struct. The returned pointer is safe to read from any goroutine. Field access on the returned pointer is a single CPU instruction with zero overhead.
Do NOT cache the returned pointer across frames or requests — call Get() each time to respect locale switches.
func (*StructTranslator[T]) Set ¶
func (st *StructTranslator[T]) Set(locale *T)
Set atomically switches the active locale to a new struct instance. This is safe to call from any goroutine. All subsequent Get() calls will return the new locale data.
type Translator ¶
type Translator struct {
// contains filtered or unexported fields
}
Translator is the main type for translation operations. It coordinates between loaders, parsers, and resolvers to provide a complete translation service with fallback support and thread safety.
func New ¶
func New(opts ...Option) (*Translator, error)
New creates a new Translator with the given options. At minimum, a loader must be provided (either through WithLoader or WithFileSystemLoader). Other components will use default implementations if not specified.
func NewWithFS ¶
func NewWithFS(baseDir, defaultLocale string, opts ...Option) (*Translator, error)
NewWithFS creates a Translator that loads translations from the filesystem. This is a convenience wrapper around New with WithFileSystemLoader and WithDefaultLocale pre-applied. Additional options can be provided to customize other components.
func NewWithRegistry ¶
func NewWithRegistry(defaultLocale string, opts ...Option) (*Translator, error)
NewWithRegistry creates a Translator that loads translations from build-tag locale data registered at init time. This is a convenience wrapper around New with WithRegistryLoader, WithParser(BinaryParser), and WithDefaultLocale pre-applied. The BinaryParser is used because built-in locale data is stored in the compact binary format. Additional options can be provided to customize other components; a user-supplied WithParser overrides the default.
func (*Translator) GetLocale ¶
func (t *Translator) GetLocale() string
GetLocale returns the current locale being used for translations.
func (*Translator) HasKey ¶
func (t *Translator) HasKey(key string) bool
HasKey checks if a translation key exists in the current locale or its fallback chain.
func (*Translator) ReloadLocale ¶
func (t *Translator) ReloadLocale(locale string) error
ReloadLocale forces a reload of translations for the given locale from the underlying loader. This clears both the internal translation cache for that locale and the resolved-translation cache.
func (*Translator) SetLocale ¶
func (t *Translator) SetLocale(locale string)
SetLocale changes the current locale for translation lookups. The locale is normalized then validated; invalid locales are silently rejected (the current locale is preserved and a warning is logged). If a translation cache is configured, it is invalidated on a successful change.
NOTE: SetLocale mutates shared Translator state. In multi-tenant HTTP request scenarios where each request needs a distinct locale, prefer WithLocaleContext to obtain a per-request, locale-scoped view without mutating the shared Translator.
func (*Translator) Translate ¶
func (t *Translator) Translate(key string) string
Translate looks up a translation key in the current locale. If the key is not found, it tries the fallback chain. If the key is still not found, it returns the key itself. When a translation cache is configured, resolved values are cached to skip fallback chain traversal on subsequent calls for the same key.
func (*Translator) TranslateGender ¶
func (t *Translator) TranslateGender(key string, gender core.GenderCategory) string
TranslateGender looks up key.<gender>, falls back to key.other, sanitizes the output, and traverses the fallback chain. When a translation cache is configured, resolved values are cached with a gender-differentiated key to skip repeated lookups.
func (*Translator) TranslatePlural ¶
func (t *Translator) TranslatePlural(key string, count interface{}) string
TranslatePlural resolves the plural category for the current locale and count, looks up key.<category> (falling back to key.other in the SAME locale, then walking the fallback chain), replaces # with the count, sanitizes the output, and traverses the fallback chain if needed. When a translation cache is configured, resolved values are cached with a count-differentiated key to skip repeated lookups.
func (*Translator) TranslatePluralWithArgs ¶
func (t *Translator) TranslatePluralWithArgs(key string, count interface{}, args ...interface{}) string
TranslatePluralWithArgs resolves the plural category, looks up the translation, replaces # with count, then applies fmt.Sprintf with the provided args. This method is not individually cached because args are arbitrary interface{} values that are not safely serializable without reflect.
For a given locale, both key.<category> and key.other are tried before advancing to the next locale in the fallback chain.
func (*Translator) TranslateWithArgs ¶
func (t *Translator) TranslateWithArgs(key string, args ...interface{}) string
TranslateWithArgs looks up a translation key and formats it with the given arguments. It uses fmt.Sprintf for formatting, and validates the format string before use. If the key is not found, it returns the key itself without formatting. This method is not individually cached because args are arbitrary interface{} values that are not safely serializable without reflect. It benefits indirectly from the Translate() cache on the format string lookup.
func (*Translator) TranslateWithMessage ¶
func (t *Translator) TranslateWithMessage(key string, args map[string]interface{}) string
TranslateWithMessage resolves a key to an ICU MessageFormat template and evaluates it with the provided named arguments. For plural expressions, the Translator's PluralResolver determines the category. Falls back through the locale chain. This method is not individually cached because args are arbitrary interface{} values that are not safely serializable without reflect.
func (*Translator) WithContext ¶
func (t *Translator) WithContext(ctx context.Context) *ContextTranslator
WithContext returns a ContextTranslator that passes ctx to the Translator's logger for trace correlation. The returned ContextTranslator delegates all translation operations to the underlying Translator using the Translator's current shared locale.
func (*Translator) WithLocaleContext ¶
func (t *Translator) WithLocaleContext(ctx context.Context, locale string) *ContextTranslator
WithLocaleContext returns a ContextTranslator scoped to a specific locale AND context. Unlike SetLocale (which mutates shared Translator state), WithLocaleContext creates a lightweight per-call view whose translation operations use the supplied locale. This is the recommended approach for request-scoped locale selection (e.g., from an Accept-Language header) in concurrent HTTP handlers.
The locale is normalized and validated. An invalid locale logs a warning and falls back to the Translator's current shared locale.