From d611fe8d262d51732a418d2a96ed203280e39cd4 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Sun, 18 Feb 2024 20:15:24 +0800 Subject: [PATCH] Improve TrHTML and add more tests (#29228) Follow #29165. Co-authored-by: KN4CK3R (cherry picked from commit 4345cac52971c13debfe5e6f311aef3930fe2eed) --- modules/translation/i18n/i18n_test.go | 66 +++++++++++++++++++++++++ modules/translation/i18n/localestore.go | 8 +-- 2 files changed, 71 insertions(+), 3 deletions(-) diff --git a/modules/translation/i18n/i18n_test.go b/modules/translation/i18n/i18n_test.go index ffe69a74df..b364992dfe 100644 --- a/modules/translation/i18n/i18n_test.go +++ b/modules/translation/i18n/i18n_test.go @@ -4,6 +4,7 @@ package i18n import ( + "html/template" "strings" "testing" @@ -82,6 +83,71 @@ c=22 assert.Equal(t, "22", lang1.TrString("c")) } +type stringerPointerReceiver struct { + s string +} + +func (s *stringerPointerReceiver) String() string { + return s.s +} + +type stringerStructReceiver struct { + s string +} + +func (s stringerStructReceiver) String() string { + return s.s +} + +type errorStructReceiver struct { + s string +} + +func (e errorStructReceiver) Error() string { + return e.s +} + +type errorPointerReceiver struct { + s string +} + +func (e *errorPointerReceiver) Error() string { + return e.s +} + +func TestLocaleWithTemplate(t *testing.T) { + ls := NewLocaleStore() + assert.NoError(t, ls.AddLocaleByIni("lang1", "Lang1", []byte(`key=%s`), nil)) + lang1, _ := ls.Locale("lang1") + + tmpl := template.New("test").Funcs(template.FuncMap{"tr": lang1.TrHTML}) + tmpl = template.Must(tmpl.Parse(`{{tr "key" .var}}`)) + + cases := []struct { + in any + want string + }{ + {"", "<str>"}, + {[]byte(""), "[60 98 121 116 101 115 62]"}, + {template.HTML(""), ""}, + {stringerPointerReceiver{""}, "{<stringerPointerReceiver>}"}, + {&stringerPointerReceiver{""}, "<stringerPointerReceiver ptr>"}, + {stringerStructReceiver{""}, "<stringerStructReceiver>"}, + {&stringerStructReceiver{""}, "<stringerStructReceiver ptr>"}, + {errorStructReceiver{""}, "<errorStructReceiver>"}, + {&errorStructReceiver{""}, "<errorStructReceiver ptr>"}, + {errorPointerReceiver{""}, "{<errorPointerReceiver>}"}, + {&errorPointerReceiver{""}, "<errorPointerReceiver ptr>"}, + } + + buf := &strings.Builder{} + for _, c := range cases { + buf.Reset() + assert.NoError(t, tmpl.Execute(buf, map[string]any{"var": c.in})) + assert.Equal(t, c.want, buf.String()) + } +} + func TestLocaleStoreQuirks(t *testing.T) { const nl = "\n" q := func(q1, s string, q2 ...string) string { diff --git a/modules/translation/i18n/localestore.go b/modules/translation/i18n/localestore.go index d0b5e05649..44c3fb0c88 100644 --- a/modules/translation/i18n/localestore.go +++ b/modules/translation/i18n/localestore.go @@ -136,12 +136,14 @@ func (l *locale) TrHTML(trKey string, trArgs ...any) template.HTML { args := slices.Clone(trArgs) for i, v := range args { switch v := v.(type) { + case nil, bool, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64, template.HTML: + // for most basic types (including template.HTML which is safe), just do nothing and use it case string: - args[i] = template.HTML(template.HTMLEscapeString(v)) + args[i] = template.HTMLEscapeString(v) case fmt.Stringer: args[i] = template.HTMLEscapeString(v.String()) - default: // int, float, include template.HTML - // do nothing, just use it + default: + args[i] = template.HTMLEscapeString(fmt.Sprint(v)) } } return template.HTML(l.TrString(trKey, args...))