core

package
v1.0.1 Latest Latest
Warning

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

Go to latest
Published: Jun 30, 2026 License: MIT Imports: 4 Imported by: 0

Documentation

Index

Constants

View Source
const MaxFormatPrecision = 1024

MaxFormatPrecision is the maximum allowed precision value in a printf-style format specifier (e.g., %.1000s). Larger values would let a malicious or corrupt translation string balloon fmt.Sprintf's output into a huge allocation — e.g., "%.99999999s" would cause fmt to pad the argument with spaces up to ~100M characters. 1024 is chosen as a generous cap: CJK width alignment, long log lines, and common formatting use well under 100; 1024 accommodates a paragraph of padded text without inviting abuse.

View Source
const MaxJSONDepth = 50

MaxJSONDepth is the maximum allowed nesting depth for JSON documents.

View Source
const MaxJSONSize = 10 * 1024 * 1024

MaxJSONSize is the maximum allowed size for JSON input in bytes (10 MB).

View Source
const MaxKeyCount = 10000

MaxKeyCount is the maximum number of total keys (including nested) allowed in a single parsed translation file. This prevents denial-of-service from translation files with an excessive number of entries.

View Source
const MaxKeyDepth = 10

MaxKeyDepth is the maximum nesting depth for translation keys.

View Source
const MaxKeyLength = 256

MaxKeyLength is the maximum allowed length for translation keys.

View Source
const MaxLocaleLength = 10

MaxLocaleLength is the maximum allowed length for locale strings.

View Source
const MaxOutputLength = 10240

MaxOutputLength is the maximum allowed length for sanitized output (10 KB).

View Source
const MaxPrefixLength = 64

MaxPrefixLength is the maximum allowed length for namespace prefixes.

Variables

This section is empty.

Functions

func SanitizeOutput

func SanitizeOutput(s string) string

SanitizeOutput removes dangerous characters and sequences from output strings. It strips control characters (except newline and tab), ANSI escape sequences, and BiDi override characters (U+202A through U+202E). The result is truncated to MaxOutputLength bytes if it exceeds that limit.

func ValidateFormatString

func ValidateFormatString(format string, argCount int) error

ValidateFormatString validates that format is safe and that its format specifiers match argCount. The dangerous %n specifier is rejected, and precision values greater than MaxFormatPrecision are rejected to prevent allocation-amplification attacks (e.g., a malicious "%.99999999s" translation string coercing fmt.Sprintf into a ~100MB allocation). Returns an ErrInvalidFormat on any violation.

func ValidateKey

func ValidateKey(key string) error

ValidateKey validates a translation key for security and format compliance.

func ValidateLocale

func ValidateLocale(locale string) error

ValidateLocale validates a locale string according to BCP 47 format and performs security checks to prevent path traversal and injection attacks.

Types

type Cacher

type Cacher interface {
	// 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.
	Get(key string) (string, bool)

	// Set stores a resolved translation under the given cache key.
	Set(key string, value string)

	// Invalidate discards all cached entries.
	Invalidate()
}

Cacher abstracts resolved-translation caching for the Translator. Implementations must be safe for concurrent use by multiple goroutines. This interface is independent of TranslatorProvider and all other interfaces.

type Detector

type Detector interface {
	// Detect retrieves the system locale from environment variables.
	// Returns a locale string (which may need normalization).
	Detect() string
}

Detector retrieves the system locale from environment variables.

type EnvProvider

type EnvProvider interface {
	// Getenv returns the value of the environment variable named by the key.
	Getenv(key string) string
}

EnvProvider abstracts environment variable access for testing.

type ErrInvalidFormat

type ErrInvalidFormat struct {
	Cause  error
	Format string
}

ErrInvalidFormat indicates that a format string is invalid.

func NewErrInvalidFormat

func NewErrInvalidFormat(format string, cause error) *ErrInvalidFormat

NewErrInvalidFormat creates a new ErrInvalidFormat error for the given format identifier and underlying cause.

func (ErrInvalidFormat) Error

func (e ErrInvalidFormat) Error() string

Error returns a formatted message including the format identifier and its cause.

func (ErrInvalidFormat) Is

func (e ErrInvalidFormat) Is(target error) bool

Is implements error comparison for ErrInvalidFormat.

func (ErrInvalidFormat) Unwrap

func (e ErrInvalidFormat) Unwrap() error

Unwrap returns the underlying cause of the error.

type ErrInvalidKey

type ErrInvalidKey struct {
	Cause error
	Key   string
}

ErrInvalidKey indicates that a translation key is invalid.

func NewErrInvalidKey

func NewErrInvalidKey(key string, cause error) *ErrInvalidKey

NewErrInvalidKey creates a new ErrInvalidKey error for the given key and underlying cause.

func (ErrInvalidKey) Error

func (e ErrInvalidKey) Error() string

Error returns a formatted message including the invalid key and its cause.

func (ErrInvalidKey) Is

func (e ErrInvalidKey) Is(target error) bool

Is implements error comparison for ErrInvalidKey.

func (ErrInvalidKey) Unwrap

func (e ErrInvalidKey) Unwrap() error

Unwrap returns the underlying cause of the error.

type ErrInvalidLocale

type ErrInvalidLocale struct {
	Cause  error
	Locale string
}

ErrInvalidLocale indicates that a locale string is invalid or malformed.

func NewErrInvalidLocale

func NewErrInvalidLocale(locale string, cause error) *ErrInvalidLocale

NewErrInvalidLocale creates a new ErrInvalidLocale error for the given locale string and underlying cause.

func (ErrInvalidLocale) Error

func (e ErrInvalidLocale) Error() string

Error returns a formatted message including the invalid locale and its cause.

func (ErrInvalidLocale) Is

func (e ErrInvalidLocale) Is(target error) bool

Is implements error comparison for ErrInvalidLocale. Called by errors.Is() which handles unwrapping; this method only matches the immediate target.

func (ErrInvalidLocale) Unwrap

func (e ErrInvalidLocale) Unwrap() error

Unwrap returns the underlying cause of the error.

type ErrKeyNotFound

type ErrKeyNotFound struct {
	Key string
}

ErrKeyNotFound indicates that a translation key was not found.

func NewErrKeyNotFound

func NewErrKeyNotFound(key string) *ErrKeyNotFound

NewErrKeyNotFound creates a new ErrKeyNotFound error for the given key.

func (ErrKeyNotFound) Error

func (e ErrKeyNotFound) Error() string

Error returns a formatted message including the missing key.

func (ErrKeyNotFound) Is

func (e ErrKeyNotFound) Is(target error) bool

Is implements error comparison for ErrKeyNotFound.

type ErrPathTraversal

type ErrPathTraversal struct {
	Path string
}

ErrPathTraversal indicates that a path traversal attempt was detected.

func NewErrPathTraversal

func NewErrPathTraversal(path string) *ErrPathTraversal

NewErrPathTraversal creates a new ErrPathTraversal error for the given path.

func (ErrPathTraversal) Error

func (e ErrPathTraversal) Error() string

Error returns a formatted message including the offending path.

func (ErrPathTraversal) Is

func (e ErrPathTraversal) Is(target error) bool

Is implements error comparison for ErrPathTraversal.

type ErrUnknownFormat

type ErrUnknownFormat struct {
	Extension string
}

ErrUnknownFormat indicates that no parser is registered for a given file extension.

func NewErrUnknownFormat

func NewErrUnknownFormat(ext string) *ErrUnknownFormat

NewErrUnknownFormat creates a new ErrUnknownFormat error for the given extension string.

func (ErrUnknownFormat) Error

func (e ErrUnknownFormat) Error() string

Error returns a formatted message including the unregistered extension.

func (ErrUnknownFormat) Is

func (e ErrUnknownFormat) Is(target error) bool

Is implements error comparison for ErrUnknownFormat.

type FallbackChainer

type FallbackChainer interface {
	// GetChain returns the fallback chain for a given locale.
	// For example, "es-MX" might return ["es-MX", "es-ES", "en-US"].
	// The chain should always include a default fallback locale.
	GetChain(locale string) []string
}

FallbackChainer generates fallback locale chains for graceful degradation.

type FormattedTranslator

type FormattedTranslator interface {
	// TranslateWithArgs looks up a translation key and formats it with arguments.
	// Uses fmt.Sprintf formatting. If the key is not found, returns the key itself.
	TranslateWithArgs(key string, args ...interface{}) string
}

FormattedTranslator provides formatted translation lookup with arguments.

type GenderCategory

type GenderCategory string

GenderCategory represents a grammatical gender for message selection. The caller specifies the gender value; no linguistic rule engine is needed.

const (
	Masculine   GenderCategory = "masculine"
	Feminine    GenderCategory = "feminine"
	Neuter      GenderCategory = "neuter"
	GenderOther GenderCategory = "other"
)

Grammatical gender categories for gender-aware message selection.

type GenderTranslator

type GenderTranslator interface {
	// TranslateGender looks up key.<gender>, falling back to key.other.
	TranslateGender(key string, gender GenderCategory) string
}

GenderTranslator provides gender-aware translation lookup.

type KeyChecker

type KeyChecker interface {
	// HasKey checks if a translation key exists in the current locale or fallback chain.
	HasKey(key string) bool
}

KeyChecker checks whether a translation key exists.

type KeyResolver

type KeyResolver interface {
	// Resolve looks up a translation key in the provided translations map.
	// Keys use dot notation for nested values (e.g., "error.validation.required").
	// Returns the translated string or an error if the key is invalid or not found.
	Resolve(translations map[string]interface{}, key string) (string, error)
}

KeyResolver handles nested key resolution using dot notation. Implementations must enforce maximum key depth and length limits.

type LeveledLogger

type LeveledLogger interface {
	// Debug logs a debug-level message with optional format arguments.
	Debug(msg string, args ...any)

	// Info logs an info-level message with optional format arguments.
	Info(msg string, args ...any)

	// Warn logs a warn-level message with optional format arguments.
	Warn(msg string, args ...any)

	// Error logs an error-level message with optional format arguments.
	Error(msg string, args ...any)

	// Fatal logs a fatal-level message with optional format arguments.
	Fatal(msg string, args ...any)
}

LeveledLogger defines minimal leveled logging without fields or context. Use this interface when you only need basic logging capabilities.

type LocaleDetector

type LocaleDetector interface {
	Detector
	Normalizer
}

LocaleDetector detects and normalizes system locale information. It composes the Detector and Normalizer interfaces.

type LocaleGetter

type LocaleGetter interface {
	// GetLocale returns the current locale being used for translations.
	GetLocale() string
}

LocaleGetter retrieves the active locale.

type LocaleSetter

type LocaleSetter interface {
	// SetLocale changes the current locale for translation lookups.
	// The locale will be normalized before being set.
	SetLocale(locale string)
}

LocaleSetter changes the active locale for translation lookups.

type LogLevel

type LogLevel int

LogLevel represents logging severity levels.

const (
	LevelDebug LogLevel = iota
	LevelInfo
	LevelWarn
	LevelError
	LevelFatal
)

Log levels matching github.com/0verkilll/logger.Level values.

type Logger

type Logger interface {
	// LeveledLogger provides the core logging methods.
	LeveledLogger

	// WithFields returns a new Logger with additional structured fields.
	// Fields are provided as key-value pairs: ("user_id", 123, "action", "login").
	WithFields(fields ...any) Logger

	// WithContext returns a new Logger with the given context.
	WithContext(ctx context.Context) Logger

	// WithLevel returns a new Logger that only logs at or above the given level.
	WithLevel(level LogLevel) Logger

	// Enabled returns true if logging at the given level would produce output.
	Enabled(level LogLevel) bool
}

Logger defines the logging interface accepted by the i18n package. This interface is compatible with github.com/0verkilll/logger.Logger and allows any implementation that satisfies these methods.

The interface follows SOLID principles:

  • Single Responsibility: focused on logging operations
  • Open/Closed: extensible through implementation
  • Liskov Substitution: any implementation is substitutable
  • Interface Segregation: LeveledLogger provides minimal subset
  • Dependency Inversion: depend on this abstraction, not concrete loggers

type Normalizer

type Normalizer interface {
	// Normalize converts locale strings to BCP 47 format.
	// Handles various input formats (en_US, en_US.UTF-8, etc.) and
	// returns a standardized BCP 47 code (e.g., "en-US").
	Normalize(locale string) string
}

Normalizer converts locale strings to BCP 47 format.

type PluralCategory

type PluralCategory string

PluralCategory represents a CLDR plural category. Values are lowercase strings that double as key suffixes in translation files.

const (
	Zero  PluralCategory = "zero"
	One   PluralCategory = "one"
	Two   PluralCategory = "two"
	Few   PluralCategory = "few"
	Many  PluralCategory = "many"
	Other PluralCategory = "other"
)

CLDR plural categories used by plural rules to select the correct translation form.

type PluralResolver

type PluralResolver interface {
	// Resolve returns the plural category for the given locale and count.
	// The count parameter accepts int, int64, float64, and string (numeric string).
	// Returns Other for unrecognized types or unknown locales.
	Resolve(locale string, count interface{}) PluralCategory
}

PluralResolver determines the plural category for a given locale and count.

type PluralTranslator

type PluralTranslator interface {
	// TranslatePlural resolves the plural category for the current locale and count,
	// looks up key.<category>, and falls back to key.other.
	TranslatePlural(key string, count interface{}) string
}

PluralTranslator provides count-dependent translation lookup.

type TranslationLoader

type TranslationLoader interface {
	// Load retrieves translation data for the specified locale.
	// The locale parameter must be a valid BCP 47 code.
	// Returns the raw translation data or an error if loading fails.
	Load(locale string) ([]byte, error)
}

TranslationLoader abstracts loading translation data from various sources. Implementations must ensure secure file access and prevent path traversal attacks.

type TranslationLookup

type TranslationLookup interface {
	// Translate looks up a translation key in the current locale.
	// If the key is not found, it tries the fallback chain.
	// Returns the key itself if not found in any locale.
	Translate(key string) string
}

TranslationLookup provides single-key translation lookup.

type TranslationParser

type TranslationParser interface {
	// Parse converts raw translation data into a structured format.
	// The data should be validated for security issues (nesting depth, size, etc.).
	// Returns a map of translation keys to values (which may be nested) or an error.
	Parse(data []byte) (map[string]interface{}, error)
}

TranslationParser abstracts parsing translation data formats. Implementations must validate input and prevent malicious data from causing issues.

type TranslatorProvider

TranslatorProvider defines the interface for translation services. This interface allows other packages to accept translation capabilities without creating a hard dependency on the full i18n package.

TranslatorProvider composes seven single-responsibility sub-interfaces: TranslationLookup, FormattedTranslator, KeyChecker, LocaleSetter, LocaleGetter, PluralTranslator, and GenderTranslator. Consumers that need only a subset of these capabilities should accept the narrower sub-interface instead.

Integration Pattern

Other Go packages can support optional i18n by defining a local interface matching this signature. Application developers then pass their i18n.Translator instance to the package's SetTranslator() function.

Example usage in a package:

// In mypackage/i18n.go
type TranslatorProvider interface {
    Translate(key string) string
    TranslateWithArgs(key string, args ...interface{}) string
    TranslatePlural(key string, count interface{}) string
    TranslateGender(key string, gender i18n.GenderCategory) string
    HasKey(key string) bool
    SetLocale(locale string)
    GetLocale() string
}

var globalTranslator TranslatorProvider

func SetTranslator(t TranslatorProvider) {
    globalTranslator = t
}

Application developers can then use it:

translator, _ := i18n.New(
    i18n.WithFileSystemLoader("locales"),
    i18n.WithDefaultLocale("en-US"),
)
mypackage.SetTranslator(translator)

Benefits

  • No forced dependencies: Packages work with or without i18n
  • Shared translator: One translator instance serves all packages
  • Centralized control: Application manages all translations
  • Language switching: Changes affect all integrated packages

The Translator type in this package implements TranslatorProvider automatically.

Jump to

Keyboard shortcuts

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