loader.go

  1package i18n
  2
  3import (
  4	"fmt"
  5	"os"
  6	"path/filepath"
  7	"strings"
  8)
  9
 10// LoadTranslations loads all translation files into a bundle.
 11// First attempts to load from embedded files, then checks for external files.
 12func LoadTranslations(bundle *Bundle) error {
 13	// Load from embedded files
 14	if err := loadFromEmbedded(bundle); err != nil {
 15		return fmt.Errorf("%w: embedded load failed: %v", ErrLoadFailed, err)
 16	}
 17
 18	return nil
 19}
 20
 21// loadFromEmbedded loads translation files from the embedded filesystem.
 22func loadFromEmbedded(bundle *Bundle) error {
 23	entries, err := localeFS.ReadDir("locales")
 24	if err != nil {
 25		return err
 26	}
 27
 28	for _, entry := range entries {
 29		if entry.IsDir() {
 30			continue
 31		}
 32
 33		filename := entry.Name()
 34		if !strings.HasSuffix(filename, ".json") {
 35			continue
 36		}
 37
 38		// Read file
 39		data, err := localeFS.ReadFile(filepath.Join("locales", filename))
 40		if err != nil {
 41			continue
 42		}
 43
 44		// Extract language code from filename (e.g., "en.json" -> "en")
 45		lang := strings.TrimSuffix(filename, ".json")
 46
 47		// Load into bundle
 48		if err := loadLanguageFile(bundle, lang, data); err != nil {
 49			return err
 50		}
 51	}
 52
 53	return nil
 54}
 55
 56// LoadFromDirectory loads translation files from a directory on disk.
 57// This allows overriding embedded translations with external files.
 58func LoadFromDirectory(bundle *Bundle, dir string) error {
 59	entries, err := os.ReadDir(dir)
 60	if err != nil {
 61		return fmt.Errorf("%w: %v", ErrLoadFailed, err)
 62	}
 63
 64	for _, entry := range entries {
 65		if entry.IsDir() {
 66			continue
 67		}
 68
 69		filename := entry.Name()
 70		if !strings.HasSuffix(filename, ".json") {
 71			continue
 72		}
 73
 74		// Read file
 75		path := filepath.Join(dir, filename)
 76		data, err := os.ReadFile(path)
 77		if err != nil {
 78			continue
 79		}
 80
 81		// Extract language code
 82		lang := strings.TrimSuffix(filename, ".json")
 83
 84		// Load into bundle
 85		if err := loadLanguageFile(bundle, lang, data); err != nil {
 86			return err
 87		}
 88	}
 89
 90	return nil
 91}
 92
 93// loadLanguageFile parses and loads a single language file into the bundle.
 94func loadLanguageFile(bundle *Bundle, lang string, data []byte) error {
 95	messages, err := ParseJSON(data)
 96	if err != nil {
 97		return fmt.Errorf("%w: language %s: %v", ErrParseFailed, lang, err)
 98	}
 99
100	return bundle.AddMessages(lang, messages)
101}