package classes import ( "context" "fmt" "strconv" "strings" "git.golem15.com/golem15/sm-user-plugin/models" "git.golem15.com/golem15/summercms/modules/backpack" "git.golem15.com/golem15/summercms/modules/towel" ) const ( // mailFallbackLocaleKey names the mail language used when neither the // user nor the request names one the plugin has mail for. mailFallbackLocaleKey = "golem15.user.mail.fallback_locale" // mailLocalePL is the unsuffixed (Polish) template set and the default // fallback. mailLocalePL = "pl" // mailLocaleEN is the -en template set. mailLocaleEN = "en" ) // supportedMailLocale reports whether the plugin has mail in lang. func supportedMailLocale(lang string) bool { return lang == mailLocalePL || lang == mailLocaleEN } // NormalizeMailLocale reduces a locale value to the language the plugin has // mail for: pl, en or "". It accepts a plain code (en, PL), a region form // (en-GB, pl_PL) and an Accept-Language list with q-weights // (en-GB,en;q=0.9). Entries whose q does not parse, lies outside 0..1 or is // 0 are dropped, as are languages other than pl and en (the wildcard // included); of the rest the one with the highest q wins, ties going to the // earliest. The result never holds anything but pl, en or "". func NormalizeMailLocale(raw string) string { best, bestQ := "", -1.0 for _, entry := range strings.Split(raw, ",") { parts := strings.Split(entry, ";") tag := strings.ToLower(strings.TrimSpace(parts[0])) if i := strings.IndexAny(tag, "-_"); i >= 0 { tag = tag[:i] } if !supportedMailLocale(tag) { continue } q, ok := 1.0, true for _, param := range parts[1:] { param = strings.TrimSpace(param) if len(param) < 2 || !strings.EqualFold(param[:2], "q=") { continue } v, err := strconv.ParseFloat(strings.TrimSpace(param[2:]), 64) if err != nil || v < 0 || v > 1 { ok = false break } q = v } if !ok || q == 0 { continue } if q > bestQ { best, bestQ = tag, q } } return best } // MailTemplate appends -en when locale normalises to English // (NormalizeMailLocale) and leaves every other value, empty included, on the // unsuffixed Polish template name. Callers that want the application's // configured fallback resolve the locale with ResolveMailLocaleFor first. func MailTemplate(base, locale string) string { if NormalizeMailLocale(locale) == mailLocaleEN { return base + "-en" } return base } // ResolveMailLocale prefers the user's saved locale, then the request locale, // each normalised by NormalizeMailLocale; a value naming neither pl nor en is // skipped. It returns pl, en or "" (neither names a supported language). func ResolveMailLocale(ctx context.Context, user *models.User) string { if user != nil && user.PreferredLocale != nil { if loc := NormalizeMailLocale(*user.PreferredLocale); loc != "" { return loc } } if ctx != nil { if raw, ok := towel.Locale(ctx); ok { return NormalizeMailLocale(raw) } } return "" } // MailFallbackLocale returns golem15.user.mail.fallback_locale normalised to // pl or en: the mail language when neither the user nor the request names // one the plugin has mail for. The default is pl (the unsuffixed // templates); an English-only site sets en, for example through // SUMMER_GOLEM15__USER__MAIL__FALLBACK_LOCALE=en. A missing app, config or // blank value gives pl; any other value gives pl and an error naming the key. func MailFallbackLocale(app *backpack.App) (string, error) { if app == nil || app.Config == nil { return mailLocalePL, nil } raw := strings.TrimSpace(app.Config.String(mailFallbackLocaleKey)) if raw == "" { return mailLocalePL, nil } if loc := NormalizeMailLocale(raw); loc != "" { return loc, nil } return mailLocalePL, fmt.Errorf("golem15.user: %s must be pl or en, got %q", mailFallbackLocaleKey, raw) } // ResolveMailLocaleFor returns the language to mail user in, always pl or // en: ResolveMailLocale, then the application's MailFallbackLocale. It is the // helper other plugins use to mail in the user's language with the // application's fallback; an invalid fallback (rejected at boot) counts as pl. func ResolveMailLocaleFor(ctx context.Context, app *backpack.App, user *models.User) string { if loc := ResolveMailLocale(ctx, user); loc != "" { return loc } loc, _ := MailFallbackLocale(app) return loc }