i18n/translator.go

Functions Structs

Functions

func AddBundle

AddBundle registers a message bundle for its locale.

 

If a bundle for the same locale string already exists, it is replaced.

Bundles should be fully populated before being added.

func (t *Translator) AddBundle(bundle *Bundle) {
	if bundle == nil {
		return
	}

	t.mu.Lock()
	defer t.mu.Unlock()

	t.bundles[bundle.Locale().String()] = bundle
}

func BundleCount

BundleCount returns the number of registered bundles.

func (t *Translator) BundleCount() int {
	t.mu.RLock()
	defer t.mu.RUnlock()
	return len(t.bundles)
}

func Direction

Direction returns the text direction for the current locale.

func (t *Translator) Direction() Direction {
	t.mu.RLock()
	defer t.mu.RUnlock()
	return t.current.Direction()
}

func Fallback

Fallback returns the fallback locale.

func (t *Translator) Fallback() Locale {
	t.mu.RLock()
	defer t.mu.RUnlock()
	return t.fallback
}

func Has

Has reports whether a message with the given key exists in the current

or fallback locale.

func (t *Translator) Has(key string) bool {
	t.mu.RLock()
	defer t.mu.RUnlock()

	_, ok := t.resolve(key)
	return ok
}

func Locale

Locale returns the current locale.

func (t *Translator) Locale() Locale {
	t.mu.RLock()
	defer t.mu.RUnlock()
	return t.current
}

func LocaleSignal

LocaleSignal returns a read-only signal of the current locale.

 

Subscribe to this signal to react to locale changes:

 

sig := t.LocaleSignal()

state.Subscribe(sig, ctx, func(locale i18n.Locale) {

// Update UI for new locale

})

func (t *Translator) LocaleSignal() state.ReadonlySignal[Locale] {
	return t.localeSig.AsReadonly()
}

func NewTranslator

NewTranslator creates a new Translator with the given fallback locale.

 

The fallback locale is used when a message is not found in the current locale.

The current locale is initially set to the fallback.

func NewTranslator(fallback Locale) *Translator {
	return &Translator{
		bundles:	make(map[string]*Bundle),
		current:	fallback,
		fallback:	fallback,
		localeSig:	state.NewSignal(fallback),
		pluralRules:	make(map[string]PluralRule),
	}
}

func SetFallback

SetFallback changes the fallback locale.

func (t *Translator) SetFallback(locale Locale) {
	t.mu.Lock()
	defer t.mu.Unlock()
	t.fallback = locale
}

func SetLocale

SetLocale changes the current locale.

 

This triggers the locale signal, notifying all subscribers.

func (t *Translator) SetLocale(locale Locale) {
	t.mu.Lock()
	t.current = locale
	t.mu.Unlock()

	// Signal update outside the lock to avoid deadlock with subscribers.
	t.localeSig.Set(locale)
}

func SetPluralRule

SetPluralRule registers a custom plural rule for a language.

 

This overrides the built-in CLDR rule for the given language code.

func (t *Translator) SetPluralRule(language string, rule PluralRule) {
	t.mu.Lock()
	defer t.mu.Unlock()
	t.pluralRules[language] = rule
}

func T

T resolves a simple message by key.

 

Resolution order: current locale -> fallback locale -> key itself.

func (t *Translator) T(key string) string {
	t.mu.RLock()
	defer t.mu.RUnlock()

	if msg, ok := t.resolve(key); ok {
		return msg
	}

	return key
}

func Tf

Tf resolves a message by key and formats it with fmt.Sprintf.

 

Resolution order: current locale -> fallback locale -> key itself.

 

Example:

 

t.Tf("greeting.name", "World") // "Hello, World!"

func (t *Translator) Tf(key string, args ...any) string {
	t.mu.RLock()
	defer t.mu.RUnlock()

	if msg, ok := t.resolve(key); ok {
		return fmt.Sprintf(msg, args...)
	}

	return key
}

func Tp

Tp resolves a plural message by key and count.

 

The plural category is determined by the locale's plural rules,

then the appropriate plural form is selected and formatted with

the count value.

 

Example:

 

t.Tp("items", 1) // "1 item"

t.Tp("items", 5) // "5 items"

func (t *Translator) Tp(key string, count int) string {
	t.mu.RLock()
	defer t.mu.RUnlock()

	if form, ok := t.resolvePlural(key, count); ok {
		return fmt.Sprintf(form, count)
	}

	return key
}

func Tpf

Tpf resolves a plural message by key and count, then formats with additional args.

 

The count is used only for plural category selection. The args are passed

to fmt.Sprintf for formatting the resolved string.

 

Example:

 

// Bundle: PluralForms{One: "%d item in %s", Other: "%d items in %s"}

t.Tpf("items.location", 3, 3, "cart") // "3 items in cart"

func (t *Translator) Tpf(key string, count int, args ...any) string {
	t.mu.RLock()
	defer t.mu.RUnlock()

	if form, ok := t.resolvePlural(key, count); ok {
		return fmt.Sprintf(form, args...)
	}

	return key
}

Structs

type Translator struct

Translator resolves localized messages with fallback chain support.

 

The resolution order for a message key is:

1. Current locale (exact match: language + region)

2. Current locale (language-only match)

3. Fallback locale (exact match)

4. Fallback locale (language-only match)

5. The key itself (as a last resort)

 

Translator is safe for concurrent access from multiple goroutines.

 

Example:

 

t := i18n.NewTranslator(i18n.NewLocale("en", "US"))

t.AddBundle(enBundle)

t.AddBundle(ruBundle)

 

t.T("greeting") // resolves from en-US bundle

t.SetLocale(i18n.NewLocale("ru", "RU"))

t.T("greeting") // resolves from ru-RU bundle

type Translator struct {
	mu		sync.RWMutex
	bundles		map[string]*Bundle	// keyed by locale.String()
	current		Locale
	fallback	Locale

	// localeSig is a signal that emits the current locale whenever it changes.
	localeSig	state.Signal[Locale]

	// Custom plural rules per language (overrides defaults).
	pluralRules	map[string]PluralRule
}