|
| 1 | +package intl |
| 2 | + |
| 3 | +import ( |
| 4 | + "embed" |
| 5 | + "fmt" |
| 6 | + "log/slog" |
| 7 | + "strings" |
| 8 | + |
| 9 | + "github.com/BurntSushi/toml" |
| 10 | + "github.com/nicksnyder/go-i18n/v2/i18n" |
| 11 | + "golang.org/x/text/language" |
| 12 | +) |
| 13 | + |
| 14 | +var DefaultLang language.Tag = language.English |
| 15 | + |
| 16 | +var SupportedLangs = []language.Tag{ |
| 17 | + language.English, |
| 18 | + language.French, |
| 19 | +} |
| 20 | + |
| 21 | +const LocalizeErrorMessage string = "<failed to localize>" |
| 22 | + |
| 23 | +type Intl struct { |
| 24 | + CurrentLang language.Tag |
| 25 | + localizer *i18n.Localizer |
| 26 | + logger *slog.Logger |
| 27 | +} |
| 28 | + |
| 29 | +func NewBundle(localesFS embed.FS) (*i18n.Bundle, error) { |
| 30 | + b := i18n.NewBundle(DefaultLang) |
| 31 | + b.RegisterUnmarshalFunc("toml", toml.Unmarshal) |
| 32 | + |
| 33 | + for _, tag := range SupportedLangs { |
| 34 | + path := fmt.Sprintf("locales/active.%s.toml", tag.String()) |
| 35 | + // debug: check if path exists in localFS |
| 36 | + // if _, err := localeFS.Open(path); err != nil { |
| 37 | + // return nil, fmt.Errorf("loading i18n file %q: %w", path, err) |
| 38 | + // } |
| 39 | + if _, err := b.LoadMessageFileFS(localesFS, path); err != nil { |
| 40 | + return nil, fmt.Errorf("loading i18n file %q: %w", path, err) |
| 41 | + } |
| 42 | + } |
| 43 | + |
| 44 | + return b, nil |
| 45 | +} |
| 46 | + |
| 47 | +func New(logger *slog.Logger, i18nBundle *i18n.Bundle, lang language.Tag) *Intl { |
| 48 | + localizer := i18n.NewLocalizer(i18nBundle, lang.String()) |
| 49 | + |
| 50 | + return &Intl{ |
| 51 | + CurrentLang: lang, |
| 52 | + localizer: localizer, |
| 53 | + logger: logger, |
| 54 | + } |
| 55 | +} |
| 56 | + |
| 57 | +func (i *Intl) Localize(lc *i18n.LocalizeConfig) string { |
| 58 | + msg, err := i.localizer.Localize(lc) |
| 59 | + if err != nil { |
| 60 | + i.logger.Error( |
| 61 | + "failed to localize", |
| 62 | + slog.Any("error", err), |
| 63 | + slog.String("lang", i.CurrentLang.String()), |
| 64 | + slog.String("key", lc.MessageID), |
| 65 | + ) |
| 66 | + return LocalizeErrorMessage |
| 67 | + } |
| 68 | + |
| 69 | + return msg |
| 70 | +} |
| 71 | + |
| 72 | +func (i *Intl) SplitOnSlot(s, slot string) (string, string) { |
| 73 | + j := strings.Index(s, slot) |
| 74 | + if j < 0 { |
| 75 | + return s, "" |
| 76 | + } |
| 77 | + return s[:j], s[j+len(slot):] |
| 78 | +} |
0 commit comments