Merge branch 'origin/stable-7.2' into 'next-release/stable-7.2'

This commit is contained in:
oauth committed 2026-10-27 15:07:07 +00:00
commit d138d5beef
2 files changed
+43 -15

No files matched your search

+24 -14
View File
@@ -6,6 +6,7 @@ import (
"strings"
"text/template"
"github.com/leonelquinteros/gotext"
"github.com/pkg/errors"
"github.com/opencloud-eu/opencloud/pkg/l10n"
@@ -21,19 +22,19 @@ var (
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)
mt.Subject, err = composeMessage(translate(t, mt.Subject), vars)
if err != nil {
return mt, err
}
mt.Greeting, err = composeMessage(t.Get(mt.Greeting, []any{}...), vars)
mt.Greeting, err = composeMessage(translate(t, mt.Greeting), vars)
if err != nil {
return mt, err
}
mt.MessageBody, err = composeMessage(t.Get(mt.MessageBody, []any{}...), vars)
mt.MessageBody, err = composeMessage(translate(t, mt.MessageBody), vars)
if err != nil {
return mt, err
}
mt.CallToAction, err = composeMessage(t.Get(mt.CallToAction, []any{}...), vars)
mt.CallToAction, err = composeMessage(translate(t, mt.CallToAction), vars)
if err != nil {
return mt, err
}
@@ -44,19 +45,19 @@ func NewTextTemplate(mt MessageTemplate, locale, defaultLocale string, translati
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)
mt.Subject, err = composeMessage(translate(t, mt.Subject), vars)
if err != nil {
return mt, err
}
mt.Greeting, err = composeMessage(newlineToBr(t.Get(mt.Greeting, []any{}...)), vars)
mt.Greeting, err = composeMessage(newlineToBr(translate(t, mt.Greeting)), vars)
if err != nil {
return mt, err
}
mt.MessageBody, err = composeMessage(newlineToBr(t.Get(mt.MessageBody, []any{}...)), vars)
mt.MessageBody, err = composeMessage(newlineToBr(translate(t, mt.MessageBody)), vars)
if err != nil {
return mt, err
}
mt.CallToAction, err = composeMessage(callToActionToHTML(t.Get(mt.CallToAction, []any{}...)), vars)
mt.CallToAction, err = composeMessage(callToActionToHTML(translate(t, mt.CallToAction)), vars)
if err != nil {
return mt, err
}
@@ -71,18 +72,18 @@ func NewGroupedTextTemplate(gmt GroupedMessageTemplate, vars map[string]string,
var err error
t := l10n.NewTranslatorFromCommonConfig(defaultLocale, _domain, translationPath, _translationFS, "l10n/locale").Locale(locale)
gmt.Subject, err = composeMessage(t.Get(gmt.Subject, []any{}...), vars)
gmt.Subject, err = composeMessage(translate(t, gmt.Subject), vars)
if err != nil {
return gmt, err
}
gmt.Greeting, err = composeMessage(t.Get(gmt.Greeting, []any{}...), vars)
gmt.Greeting, err = composeMessage(translate(t, gmt.Greeting), 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])
bodyPart, err := composeMessage(translate(t, mt.MessageBody), mtsVars[i])
if err != nil {
return gmt, err
}
@@ -100,18 +101,18 @@ func NewGroupedHTMLTemplate(gmt GroupedMessageTemplate, vars map[string]string,
var err error
t := l10n.NewTranslatorFromCommonConfig(defaultLocale, _domain, translationPath, _translationFS, "l10n/locale").Locale(locale)
gmt.Subject, err = composeMessage(t.Get(gmt.Subject, []any{}...), vars)
gmt.Subject, err = composeMessage(translate(t, gmt.Subject), vars)
if err != nil {
return gmt, err
}
gmt.Greeting, err = composeMessage(newlineToBr(t.Get(gmt.Greeting, []any{}...)), vars)
gmt.Greeting, err = composeMessage(newlineToBr(translate(t, gmt.Greeting)), 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])
bodyPart, err := composeMessage(translate(t, mt.MessageBody), mtsVars[i])
if err != nil {
return gmt, err
}
@@ -122,6 +123,15 @@ func NewGroupedHTMLTemplate(gmt GroupedMessageTemplate, vars map[string]string,
return gmt, nil
}
// translate returns the translation of s. An empty string stays empty: gotext returns the
// header of the .po file for it.
func translate(t *gotext.Locale, s string) string {
if s == "" {
return ""
}
return t.Get(s)
}
// composeMessage renders the message based on template
func composeMessage(tmpl string, vars map[string]string) (string, error) {
tpl, err := template.New("").Parse(replacePlaceholders(tmpl))
+19 -1
View File
@@ -1,6 +1,9 @@
package email
import "testing"
import (
"strings"
"testing"
)
// Regression for #2804: escapeStringMap used to mutate its input map, and the
// recipient render loop reuses that map across iterations.
@@ -23,3 +26,18 @@ func TestEscapeStringMapDoesNotMutateInput(t *testing.T) {
input["SpaceName"], raw)
}
}
// Regression for #3830: translating an empty string returns the header of the .po file, so emails
// without a call to action got "Project-Id-Version: …" in every translated language.
func TestEmptyStringsAreNotTranslated(t *testing.T) {
vars := map[string]string{"ShareGrantee": "Ben", "ShareFolder": "Q3 Report", "ExpiredAt": "2026-10-27 10:00:00"}
msg, err := RenderEmailTemplate(ShareExpired, "de", "en", "", "", vars)
if err != nil {
t.Fatal(err)
}
for name, body := range map[string]string{"text": msg.TextBody, "html": msg.HTMLBody} {
if strings.Contains(body, "Project-Id-Version") {
t.Errorf("%s body contains the header of the translation file:\n%s", name, body)
}
}
}