Initial QSfera import
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
package email
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"embed"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/qsfera/server/pkg/l10n"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed l10n/locale
|
||||
_translationFS embed.FS
|
||||
_domain = "notifications"
|
||||
)
|
||||
|
||||
// NewTextTemplate replace the body message template placeholders with the translated template
|
||||
func NewTextTemplate(mt MessageTemplate, locale, defaultLocale string, translationPath string, vars map[string]string) (MessageTemplate, error) {
|
||||
var err error
|
||||
t := l10n.NewTranslatorFromCommonConfig(defaultLocale, _domain, translationPath, _translationFS, "l10n/locale").Locale(locale)
|
||||
mt.Subject, err = composeMessage(t.Get(mt.Subject, []any{}...), vars)
|
||||
if err != nil {
|
||||
return mt, err
|
||||
}
|
||||
mt.Greeting, err = composeMessage(t.Get(mt.Greeting, []any{}...), vars)
|
||||
if err != nil {
|
||||
return mt, err
|
||||
}
|
||||
mt.MessageBody, err = composeMessage(t.Get(mt.MessageBody, []any{}...), vars)
|
||||
if err != nil {
|
||||
return mt, err
|
||||
}
|
||||
mt.CallToAction, err = composeMessage(t.Get(mt.CallToAction, []any{}...), vars)
|
||||
if err != nil {
|
||||
return mt, err
|
||||
}
|
||||
return mt, nil
|
||||
}
|
||||
|
||||
// NewHTMLTemplate replace the body message template placeholders with the translated template
|
||||
func NewHTMLTemplate(mt MessageTemplate, locale, defaultLocale string, translationPath string, vars map[string]string) (MessageTemplate, error) {
|
||||
var err error
|
||||
t := l10n.NewTranslatorFromCommonConfig(defaultLocale, _domain, translationPath, _translationFS, "l10n/locale").Locale(locale)
|
||||
mt.Subject, err = composeMessage(t.Get(mt.Subject, []any{}...), vars)
|
||||
if err != nil {
|
||||
return mt, err
|
||||
}
|
||||
mt.Greeting, err = composeMessage(newlineToBr(t.Get(mt.Greeting, []any{}...)), vars)
|
||||
if err != nil {
|
||||
return mt, err
|
||||
}
|
||||
mt.MessageBody, err = composeMessage(newlineToBr(t.Get(mt.MessageBody, []any{}...)), vars)
|
||||
if err != nil {
|
||||
return mt, err
|
||||
}
|
||||
mt.CallToAction, err = composeMessage(callToActionToHTML(t.Get(mt.CallToAction, []any{}...)), vars)
|
||||
if err != nil {
|
||||
return mt, err
|
||||
}
|
||||
return mt, nil
|
||||
}
|
||||
|
||||
// NewGroupedTextTemplate replace the body message template placeholders with the translated template
|
||||
func NewGroupedTextTemplate(gmt GroupedMessageTemplate, vars map[string]string, locale, defaultLocale string, translationPath string, mts []MessageTemplate, mtsVars []map[string]string) (GroupedMessageTemplate, error) {
|
||||
if len(mts) != len(mtsVars) {
|
||||
return gmt, errors.New("number of templates does not match number of variables")
|
||||
}
|
||||
|
||||
var err error
|
||||
t := l10n.NewTranslatorFromCommonConfig(defaultLocale, _domain, translationPath, _translationFS, "l10n/locale").Locale(locale)
|
||||
gmt.Subject, err = composeMessage(t.Get(gmt.Subject, []any{}...), vars)
|
||||
if err != nil {
|
||||
return gmt, err
|
||||
}
|
||||
gmt.Greeting, err = composeMessage(t.Get(gmt.Greeting, []any{}...), vars)
|
||||
if err != nil {
|
||||
return gmt, err
|
||||
}
|
||||
|
||||
bodyParts := make([]string, 0, len(mtsVars))
|
||||
for i, mt := range mts {
|
||||
bodyPart, err := composeMessage(t.Get(mt.MessageBody, []any{}...), mtsVars[i])
|
||||
if err != nil {
|
||||
return gmt, err
|
||||
}
|
||||
bodyParts = append(bodyParts, bodyPart)
|
||||
}
|
||||
gmt.MessageBody = strings.Join(bodyParts, "\n\n\n")
|
||||
return gmt, nil
|
||||
}
|
||||
|
||||
// NewGroupedHTMLTemplate replace the body message template placeholders with the translated template
|
||||
func NewGroupedHTMLTemplate(gmt GroupedMessageTemplate, vars map[string]string, locale, defaultLocale string, translationPath string, mts []MessageTemplate, mtsVars []map[string]string) (GroupedMessageTemplate, error) {
|
||||
if len(mts) != len(mtsVars) {
|
||||
return gmt, errors.New("number of templates does not match number of variables")
|
||||
}
|
||||
|
||||
var err error
|
||||
t := l10n.NewTranslatorFromCommonConfig(defaultLocale, _domain, translationPath, _translationFS, "l10n/locale").Locale(locale)
|
||||
gmt.Subject, err = composeMessage(t.Get(gmt.Subject, []any{}...), vars)
|
||||
if err != nil {
|
||||
return gmt, err
|
||||
}
|
||||
gmt.Greeting, err = composeMessage(newlineToBr(t.Get(gmt.Greeting, []any{}...)), vars)
|
||||
if err != nil {
|
||||
return gmt, err
|
||||
}
|
||||
|
||||
bodyParts := make([]string, 0, len(mtsVars))
|
||||
for i, mt := range mts {
|
||||
bodyPart, err := composeMessage(t.Get(mt.MessageBody, []any{}...), mtsVars[i])
|
||||
if err != nil {
|
||||
return gmt, err
|
||||
}
|
||||
bodyParts = append(bodyParts, bodyPart)
|
||||
}
|
||||
gmt.MessageBody = strings.Join(bodyParts, "<br><br><br>")
|
||||
|
||||
return gmt, nil
|
||||
}
|
||||
|
||||
// composeMessage renders the message based on template
|
||||
func composeMessage(tmpl string, vars map[string]string) (string, error) {
|
||||
tpl, err := template.New("").Parse(replacePlaceholders(tmpl))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
var writer bytes.Buffer
|
||||
if err := tpl.Execute(&writer, vars); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return writer.String(), nil
|
||||
}
|
||||
|
||||
func replacePlaceholders(raw string) string {
|
||||
for o, n := range _placeholders {
|
||||
raw = strings.ReplaceAll(raw, o, n)
|
||||
}
|
||||
return raw
|
||||
}
|
||||
|
||||
func newlineToBr(s string) string {
|
||||
return strings.Replace(s, "\n", "<br>", -1)
|
||||
}
|
||||
|
||||
func callToActionToHTML(s string) string {
|
||||
if strings.TrimSpace(s) == "" {
|
||||
return ""
|
||||
}
|
||||
s = strings.TrimSuffix(s, "{ShareLink}")
|
||||
return s + `<a href="{ShareLink}">{ShareLink}</a>`
|
||||
}
|
||||
Reference in New Issue
Block a user