bundle.go

  1package i18n
  2
  3import (
  4	"fmt"
  5	"sync"
  6)
  7
  8// Bundle holds all translation messages for all languages.
  9type Bundle struct {
 10	defaultLang string
 11	messages    map[string]MessageMap // lang -> MessageMap
 12	locales     map[string]*Locale    // lang -> Locale
 13	mu          sync.RWMutex
 14}
 15
 16// NewBundle creates a new Bundle with a default language.
 17func NewBundle(defaultLang string) *Bundle {
 18	return &Bundle{
 19		defaultLang: defaultLang,
 20		messages:    make(map[string]MessageMap),
 21		locales:     make(map[string]*Locale),
 22	}
 23}
 24
 25// AddMessages adds translation messages for a language.
 26func (b *Bundle) AddMessages(lang string, messages MessageMap) error {
 27	if lang == "" {
 28		return ErrInvalidLocale
 29	}
 30
 31	b.mu.Lock()
 32	defer b.mu.Unlock()
 33
 34	if b.messages[lang] == nil {
 35		b.messages[lang] = make(MessageMap)
 36	}
 37
 38	// Merge messages
 39	for id, msg := range messages {
 40		b.messages[lang][id] = msg
 41	}
 42
 43	return nil
 44}
 45
 46// GetMessage retrieves a message for a specific language and ID.
 47func (b *Bundle) GetMessage(lang, id string) (*Message, error) {
 48	b.mu.RLock()
 49	defer b.mu.RUnlock()
 50
 51	langMessages, ok := b.messages[lang]
 52	if !ok {
 53		return nil, fmt.Errorf("%w: %s", ErrLanguageNotFound, lang)
 54	}
 55
 56	msg, ok := langMessages[id]
 57	if !ok {
 58		return nil, fmt.Errorf("%w: %s", ErrMessageNotFound, id)
 59	}
 60
 61	return msg, nil
 62}
 63
 64// RegisterLocale registers a locale configuration.
 65func (b *Bundle) RegisterLocale(locale *Locale) {
 66	if locale == nil || locale.Code == "" {
 67		return
 68	}
 69
 70	b.mu.Lock()
 71	defer b.mu.Unlock()
 72
 73	b.locales[locale.Code] = locale
 74}
 75
 76// GetLocale retrieves a registered locale.
 77func (b *Bundle) GetLocale(lang string) (*Locale, bool) {
 78	b.mu.RLock()
 79	defer b.mu.RUnlock()
 80
 81	locale, ok := b.locales[lang]
 82	return locale, ok
 83}
 84
 85// AvailableLanguages returns a list of all languages with loaded messages.
 86func (b *Bundle) AvailableLanguages() []string {
 87	b.mu.RLock()
 88	defer b.mu.RUnlock()
 89
 90	langs := make([]string, 0, len(b.messages))
 91	for lang := range b.messages {
 92		langs = append(langs, lang)
 93	}
 94	return langs
 95}
 96
 97// DefaultLanguage returns the default language code.
 98func (b *Bundle) DefaultLanguage() string {
 99	return b.defaultLang
100}
101
102// MessageCount returns the number of messages for a language.
103func (b *Bundle) MessageCount(lang string) int {
104	b.mu.RLock()
105	defer b.mu.RUnlock()
106
107	if messages, ok := b.messages[lang]; ok {
108		return len(messages)
109	}
110	return 0
111}
112
113// HasLanguage checks if a language has been loaded.
114func (b *Bundle) HasLanguage(lang string) bool {
115	b.mu.RLock()
116	defer b.mu.RUnlock()
117
118	_, ok := b.messages[lang]
119	return ok
120}