manager.go

  1package i18n
  2
  3import (
  4	"fmt"
  5	"sync"
  6)
  7
  8var (
  9	globalManager *Manager
 10	managerOnce   sync.Once
 11)
 12
 13// Manager is the global translation manager.
 14type Manager struct {
 15	bundle      *Bundle
 16	currentLang string
 17	localizers  map[string]*Localizer
 18	cache       *Cache
 19	mu          sync.RWMutex
 20}
 21
 22// Init initializes the global translation manager with a default language.
 23func Init(defaultLang string) error {
 24	var initErr error
 25
 26	managerOnce.Do(func() {
 27		bundle := NewBundle(defaultLang)
 28
 29		// Load all embedded translations
 30		if err := LoadTranslations(bundle); err != nil {
 31			initErr = err
 32			return
 33		}
 34
 35		// Register locales from registry into bundle
 36		for _, locale := range AvailableLanguages() {
 37			bundle.RegisterLocale(locale)
 38		}
 39
 40		globalManager = &Manager{
 41			bundle:      bundle,
 42			currentLang: defaultLang,
 43			localizers:  make(map[string]*Localizer),
 44			cache:       NewCache(),
 45		}
 46
 47		// Create default localizer
 48		globalManager.localizers[defaultLang] = NewLocalizer(defaultLang, bundle)
 49	})
 50
 51	return initErr
 52}
 53
 54// GetManager returns the global manager instance.
 55func GetManager() *Manager {
 56	if globalManager == nil {
 57		// Auto-initialize with English if not yet initialized
 58		_ = Init("en")
 59	}
 60	return globalManager
 61}
 62
 63// SetLanguage changes the current language.
 64func (m *Manager) SetLanguage(lang string) error {
 65	if lang == "" {
 66		return ErrInvalidLocale
 67	}
 68
 69	lang = normalizeLanguageCode(lang)
 70
 71	m.mu.Lock()
 72	defer m.mu.Unlock()
 73
 74	// Check if language is available
 75	if !m.bundle.HasLanguage(lang) {
 76		return fmt.Errorf("%w: %s", ErrLanguageNotFound, lang)
 77	}
 78
 79	// Create localizer if not exists
 80	if _, ok := m.localizers[lang]; !ok {
 81		m.localizers[lang] = NewLocalizer(lang, m.bundle)
 82	}
 83
 84	m.currentLang = lang
 85	m.cache.Clear() // Clear cache when switching languages
 86
 87	return nil
 88}
 89
 90// GetLanguage returns the current language code.
 91func (m *Manager) GetLanguage() string {
 92	m.mu.RLock()
 93	defer m.mu.RUnlock()
 94
 95	return m.currentLang
 96}
 97
 98// T translates a message key using the current language.
 99func (m *Manager) T(key string) string {
100	m.mu.RLock()
101	localizer := m.localizers[m.currentLang]
102	m.mu.RUnlock()
103
104	if localizer == nil {
105		return key
106	}
107
108	return localizer.Localize(key)
109}
110
111// Tn translates a message with plural support.
112func (m *Manager) Tn(key string, count int, data map[string]interface{}) string {
113	m.mu.RLock()
114	localizer := m.localizers[m.currentLang]
115	m.mu.RUnlock()
116
117	if localizer == nil {
118		return key
119	}
120
121	// Ensure count is in data
122	if data == nil {
123		data = make(map[string]interface{})
124	}
125	if _, ok := data["count"]; !ok {
126		data["count"] = count
127	}
128
129	return localizer.LocalizePlural(key, count, data)
130}
131
132// Tpl translates a message and applies template variables.
133func (m *Manager) Tpl(key string, data map[string]interface{}) string {
134	m.mu.RLock()
135	localizer := m.localizers[m.currentLang]
136	m.mu.RUnlock()
137
138	if localizer == nil {
139		return key
140	}
141
142	return localizer.LocalizeTemplate(key, data)
143}
144
145// AvailableLanguages returns all loaded languages.
146func (m *Manager) AvailableLanguages() []string {
147	return m.bundle.AvailableLanguages()
148}
149
150// GetLocale returns the current locale.
151func (m *Manager) GetLocale() *Locale {
152	m.mu.RLock()
153	defer m.mu.RUnlock()
154
155	if localizer, ok := m.localizers[m.currentLang]; ok {
156		return localizer.Locale()
157	}
158
159	locale, _ := ParseLocale(m.currentLang)
160	return locale
161}
162
163// ClearCache clears all translation caches.
164func (m *Manager) ClearCache() {
165	m.cache.Clear()
166
167	m.mu.Lock()
168	defer m.mu.Unlock()
169
170	for _, localizer := range m.localizers {
171		localizer.ClearCache()
172	}
173}