aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwxiaoguang <wxiaoguang@gmail.com>2024-02-15 05:48:45 +0800
committerGitHub <noreply@github.com>2024-02-14 21:48:45 +0000
commitf3eb835886031df7a562abc123c3f6011c81eca8 (patch)
tree6db218680b00a81f2ea46675d5dde94642a232b9
parent94d06be035bac468129903c9f32e785baf3c1c3b (diff)
downloadgitea-f3eb835886031df7a562abc123c3f6011c81eca8.tar.gz
gitea-f3eb835886031df7a562abc123c3f6011c81eca8.zip
Refactor locale&string&template related code (#29165)
Clarify when "string" should be used (and be escaped), and when "template.HTML" should be used (no need to escape) And help PRs like #29059 , to render the error messages correctly.
-rw-r--r--models/actions/runner.go2
-rw-r--r--models/actions/status.go2
-rw-r--r--models/git/commit_status.go2
-rw-r--r--models/issues/comment.go4
-rw-r--r--models/shared/types/ownertype.go10
-rw-r--r--modules/auth/password/password.go9
-rw-r--r--modules/charset/escape_stream.go2
-rw-r--r--modules/context/api.go2
-rw-r--r--modules/context/base.go5
-rw-r--r--modules/context/context.go23
-rw-r--r--modules/context/context_response.go5
-rw-r--r--modules/context/repo.go3
-rw-r--r--modules/csv/csv.go4
-rw-r--r--modules/markup/html.go2
-rw-r--r--modules/markup/markdown/toc.go2
-rw-r--r--modules/migration/messenger.go2
-rw-r--r--modules/templates/helper.go46
-rw-r--r--modules/timeutil/since.go36
-rw-r--r--modules/translation/i18n/i18n.go17
-rw-r--r--modules/translation/i18n/i18n_test.go32
-rw-r--r--modules/translation/i18n/localestore.go41
-rw-r--r--modules/translation/mock.go15
-rw-r--r--modules/translation/translation.go16
-rw-r--r--modules/web/middleware/binding.go34
-rw-r--r--modules/web/middleware/flash.go40
-rw-r--r--routers/api/v1/repo/file.go6
-rw-r--r--routers/api/v1/repo/issue_comment.go2
-rw-r--r--routers/web/admin/auths.go6
-rw-r--r--routers/web/auth/password.go2
-rw-r--r--routers/web/feed/convert.go60
-rw-r--r--routers/web/feed/profile.go2
-rw-r--r--routers/web/feed/release.go4
-rw-r--r--routers/web/feed/repo.go2
-rw-r--r--routers/web/org/org.go4
-rw-r--r--routers/web/org/projects.go4
-rw-r--r--routers/web/repo/actions/actions.go4
-rw-r--r--routers/web/repo/actions/view.go6
-rw-r--r--routers/web/repo/cherry_pick.go4
-rw-r--r--routers/web/repo/compare.go2
-rw-r--r--routers/web/repo/editor.go10
-rw-r--r--routers/web/repo/issue.go6
-rw-r--r--routers/web/repo/issue_content_history.go6
-rw-r--r--routers/web/repo/issue_label_test.go2
-rw-r--r--routers/web/repo/patch.go2
-rw-r--r--routers/web/repo/projects.go4
-rw-r--r--routers/web/repo/pull.go4
-rw-r--r--routers/web/repo/pull_review.go4
-rw-r--r--routers/web/repo/setting/avatar.go4
-rw-r--r--routers/web/repo/setting/protected_branch.go2
-rw-r--r--routers/web/repo/view.go2
-rw-r--r--routers/web/repo/wiki.go4
-rw-r--r--routers/web/user/home.go2
-rw-r--r--routers/web/user/setting/profile.go6
-rw-r--r--routers/web/user/task.go2
-rw-r--r--routers/web/web.go2
-rw-r--r--services/cron/setting.go6
-rw-r--r--services/cron/tasks.go2
-rw-r--r--services/forms/repo_form.go2
-rw-r--r--services/mailer/mail.go10
-rw-r--r--services/mailer/mail_release.go2
-rw-r--r--services/mailer/mail_repo.go6
-rw-r--r--services/mailer/mail_team_invite.go2
-rw-r--r--templates/mail/issue/assigned.tmpl4
-rw-r--r--templates/mail/issue/default.tmpl2
-rw-r--r--templates/mail/notify/repo_transfer.tmpl2
-rw-r--r--templates/mail/release.tmpl2
-rw-r--r--templates/repo/editor/cherry_pick.tmpl4
-rw-r--r--templates/repo/issue/view_content/comments.tmpl6
-rw-r--r--templates/repo/issue/view_title.tmpl8
-rw-r--r--tests/integration/auth_ldap_test.go4
-rw-r--r--tests/integration/branches_test.go4
-rw-r--r--tests/integration/pull_merge_test.go2
-rw-r--r--tests/integration/release_test.go10
-rw-r--r--tests/integration/repo_branch_test.go18
-rw-r--r--tests/integration/signin_test.go8
-rw-r--r--tests/integration/signup_test.go6
-rw-r--r--tests/integration/user_test.go4
77 files changed, 356 insertions, 284 deletions
diff --git a/models/actions/runner.go b/models/actions/runner.go
index 4103ba4477..b646146ee6 100644
--- a/models/actions/runner.go
+++ b/models/actions/runner.go
@@ -97,7 +97,7 @@ func (r *ActionRunner) StatusName() string {
}
func (r *ActionRunner) StatusLocaleName(lang translation.Locale) string {
- return lang.Tr("actions.runners.status." + r.StatusName())
+ return lang.TrString("actions.runners.status." + r.StatusName())
}
func (r *ActionRunner) IsOnline() bool {
diff --git a/models/actions/status.go b/models/actions/status.go
index c97578f2ac..eda2234137 100644
--- a/models/actions/status.go
+++ b/models/actions/status.go
@@ -41,7 +41,7 @@ func (s Status) String() string {
// LocaleString returns the locale string name of the Status
func (s Status) LocaleString(lang translation.Locale) string {
- return lang.Tr("actions.status." + s.String())
+ return lang.TrString("actions.status." + s.String())
}
// IsDone returns whether the Status is final
diff --git a/models/git/commit_status.go b/models/git/commit_status.go
index 1118b6cc8c..2d1d1bcb06 100644
--- a/models/git/commit_status.go
+++ b/models/git/commit_status.go
@@ -194,7 +194,7 @@ func (status *CommitStatus) APIURL(ctx context.Context) string {
// LocaleString returns the locale string name of the Status
func (status *CommitStatus) LocaleString(lang translation.Locale) string {
- return lang.Tr("repo.commitstatus." + status.State.String())
+ return lang.TrString("repo.commitstatus." + status.State.String())
}
// CalcCommitStatus returns commit status state via some status, the commit statues should order by id desc
diff --git a/models/issues/comment.go b/models/issues/comment.go
index a586caf1b5..fa0eb3cc0f 100644
--- a/models/issues/comment.go
+++ b/models/issues/comment.go
@@ -210,12 +210,12 @@ const (
// LocaleString returns the locale string name of the role
func (r RoleInRepo) LocaleString(lang translation.Locale) string {
- return lang.Tr("repo.issues.role." + string(r))
+ return lang.TrString("repo.issues.role." + string(r))
}
// LocaleHelper returns the locale tooltip of the role
func (r RoleInRepo) LocaleHelper(lang translation.Locale) string {
- return lang.Tr("repo.issues.role." + string(r) + "_helper")
+ return lang.TrString("repo.issues.role." + string(r) + "_helper")
}
// Comment represents a comment in commit and issue page.
diff --git a/models/shared/types/ownertype.go b/models/shared/types/ownertype.go
index e6fe4e4cfd..a1d46c986f 100644
--- a/models/shared/types/ownertype.go
+++ b/models/shared/types/ownertype.go
@@ -17,13 +17,13 @@ const (
func (o OwnerType) LocaleString(locale translation.Locale) string {
switch o {
case OwnerTypeSystemGlobal:
- return locale.Tr("concept_system_global")
+ return locale.TrString("concept_system_global")
case OwnerTypeIndividual:
- return locale.Tr("concept_user_individual")
+ return locale.TrString("concept_user_individual")
case OwnerTypeRepository:
- return locale.Tr("concept_code_repository")
+ return locale.TrString("concept_code_repository")
case OwnerTypeOrganization:
- return locale.Tr("concept_user_organization")
+ return locale.TrString("concept_user_organization")
}
- return locale.Tr("unknown")
+ return locale.TrString("unknown")
}
diff --git a/modules/auth/password/password.go b/modules/auth/password/password.go
index 2c7205b708..27074358a9 100644
--- a/modules/auth/password/password.go
+++ b/modules/auth/password/password.go
@@ -8,6 +8,7 @@ import (
"context"
"crypto/rand"
"errors"
+ "html/template"
"math/big"
"strings"
"sync"
@@ -121,15 +122,15 @@ func Generate(n int) (string, error) {
}
// BuildComplexityError builds the error message when password complexity checks fail
-func BuildComplexityError(locale translation.Locale) string {
+func BuildComplexityError(locale translation.Locale) template.HTML {
var buffer bytes.Buffer
- buffer.WriteString(locale.Tr("form.password_complexity"))
+ buffer.WriteString(locale.TrString("form.password_complexity"))
buffer.WriteString("<ul>")
for _, c := range requiredList {
buffer.WriteString("<li>")
- buffer.WriteString(locale.Tr(c.TrNameOne))
+ buffer.WriteString(locale.TrString(c.TrNameOne))
buffer.WriteString("</li>")
}
buffer.WriteString("</ul>")
- return buffer.String()
+ return template.HTML(buffer.String())
}
diff --git a/modules/charset/escape_stream.go b/modules/charset/escape_stream.go
index 3f08fd94a4..29943eb858 100644
--- a/modules/charset/escape_stream.go
+++ b/modules/charset/escape_stream.go
@@ -173,7 +173,7 @@ func (e *escapeStreamer) ambiguousRune(r, c rune) error {
Val: "ambiguous-code-point",
}, html.Attribute{
Key: "data-tooltip-content",
- Val: e.locale.Tr("repo.ambiguous_character", r, c),
+ Val: e.locale.TrString("repo.ambiguous_character", r, c),
}); err != nil {
return err
}
diff --git a/modules/context/api.go b/modules/context/api.go
index e226264a87..f8bc682fed 100644
--- a/modules/context/api.go
+++ b/modules/context/api.go
@@ -245,7 +245,7 @@ func APIContexter() func(http.Handler) http.Handler {
// NotFound handles 404s for APIContext
// String will replace message, errors will be added to a slice
func (ctx *APIContext) NotFound(objs ...any) {
- message := ctx.Tr("error.not_found")
+ message := ctx.Locale.TrString("error.not_found")
var errors []string
for _, obj := range objs {
// Ignore nil
diff --git a/modules/context/base.go b/modules/context/base.go
index 8df1dde866..fa05850a16 100644
--- a/modules/context/base.go
+++ b/modules/context/base.go
@@ -6,6 +6,7 @@ package context
import (
"context"
"fmt"
+ "html/template"
"io"
"net/http"
"net/url"
@@ -286,11 +287,11 @@ func (b *Base) cleanUp() {
}
}
-func (b *Base) Tr(msg string, args ...any) string {
+func (b *Base) Tr(msg string, args ...any) template.HTML {
return b.Locale.Tr(msg, args...)
}
-func (b *Base) TrN(cnt any, key1, keyN string, args ...any) string {
+func (b *Base) TrN(cnt any, key1, keyN string, args ...any) template.HTML {
return b.Locale.TrN(cnt, key1, keyN, args...)
}
diff --git a/modules/context/context.go b/modules/context/context.go
index d19c5d1198..4d367b3242 100644
--- a/modules/context/context.go
+++ b/modules/context/context.go
@@ -6,7 +6,7 @@ package context
import (
"context"
- "html"
+ "fmt"
"html/template"
"io"
"net/http"
@@ -71,16 +71,6 @@ func init() {
})
}
-// TrHTMLEscapeArgs runs ".Locale.Tr()" but pre-escapes all arguments with html.EscapeString.
-// This is useful if the locale message is intended to only produce HTML content.
-func (ctx *Context) TrHTMLEscapeArgs(msg string, args ...string) string {
- trArgs := make([]any, len(args))
- for i, arg := range args {
- trArgs[i] = html.EscapeString(arg)
- }
- return ctx.Locale.Tr(msg, trArgs...)
-}
-
type webContextKeyType struct{}
var WebContextKey = webContextKeyType{}
@@ -253,6 +243,13 @@ func (ctx *Context) JSONOK() {
ctx.JSON(http.StatusOK, map[string]any{"ok": true}) // this is only a dummy response, frontend seldom uses it
}
-func (ctx *Context) JSONError(msg string) {
- ctx.JSON(http.StatusBadRequest, map[string]any{"errorMessage": msg})
+func (ctx *Context) JSONError(msg any) {
+ switch v := msg.(type) {
+ case string:
+ ctx.JSON(http.StatusBadRequest, map[string]any{"errorMessage": v, "renderFormat": "text"})
+ case template.HTML:
+ ctx.JSON(http.StatusBadRequest, map[string]any{"errorMessage": v, "renderFormat": "html"})
+ default:
+ panic(fmt.Sprintf("unsupported type: %T", msg))
+ }
}
diff --git a/modules/context/context_response.go b/modules/context/context_response.go
index 5729865561..d9102b77bd 100644
--- a/modules/context/context_response.go
+++ b/modules/context/context_response.go
@@ -98,12 +98,11 @@ func (ctx *Context) RenderToString(name base.TplName, data map[string]any) (stri
}
// RenderWithErr used for page has form validation but need to prompt error to users.
-func (ctx *Context) RenderWithErr(msg string, tpl base.TplName, form any) {
+func (ctx *Context) RenderWithErr(msg any, tpl base.TplName, form any) {
if form != nil {
middleware.AssignForm(form, ctx.Data)
}
- ctx.Flash.ErrorMsg = msg
- ctx.Data["Flash"] = ctx.Flash
+ ctx.Flash.Error(msg, true)
ctx.HTML(http.StatusOK, tpl)
}
diff --git a/modules/context/repo.go b/modules/context/repo.go
index 75ebfec705..3ff7209c4c 100644
--- a/modules/context/repo.go
+++ b/modules/context/repo.go
@@ -6,6 +6,7 @@ package context
import (
"context"
+ "errors"
"fmt"
"html"
"net/http"
@@ -85,7 +86,7 @@ func (r *Repository) CanCreateBranch() bool {
func RepoMustNotBeArchived() func(ctx *Context) {
return func(ctx *Context) {
if ctx.Repo.Repository.IsArchived {
- ctx.NotFound("IsArchived", fmt.Errorf(ctx.Tr("repo.archive.title")))
+ ctx.NotFound("IsArchived", errors.New(ctx.Locale.TrString("repo.archive.title")))
}
}
}
diff --git a/modules/csv/csv.go b/modules/csv/csv.go
index c5497befe7..35c5d6ab67 100644
--- a/modules/csv/csv.go
+++ b/modules/csv/csv.go
@@ -123,9 +123,9 @@ func guessDelimiter(data []byte) rune {
func FormatError(err error, locale translation.Locale) (string, error) {
if perr, ok := err.(*stdcsv.ParseError); ok {
if perr.Err == stdcsv.ErrFieldCount {
- return locale.Tr("repo.error.csv.invalid_field_count", perr.Line), nil
+ return locale.TrString("repo.error.csv.invalid_field_count", perr.Line), nil
}
- return locale.Tr("repo.error.csv.unexpected", perr.Line, perr.Column), nil
+ return locale.TrString("repo.error.csv.unexpected", perr.Line, perr.Column), nil
}
return "", err
diff --git a/modules/markup/html.go b/modules/markup/html.go
index 33dc1e9086..b7291823b5 100644
--- a/modules/markup/html.go
+++ b/modules/markup/html.go
@@ -804,7 +804,7 @@ func fullIssuePatternProcessor(ctx *RenderContext, node *html.Node) {
// indicate that in the text by appending (comment)
if m[4] != -1 && m[5] != -1 {
if locale, ok := ctx.Ctx.Value(translation.ContextKey).(translation.Locale); ok {
- text += " " + locale.Tr("repo.from_comment")
+ text += " " + locale.TrString("repo.from_comment")
} else {
text += " (comment)"
}
diff --git a/modules/markup/markdown/toc.go b/modules/markup/markdown/toc.go
index 9602040931..38f744a25f 100644
--- a/modules/markup/markdown/toc.go
+++ b/modules/markup/markdown/toc.go
@@ -21,7 +21,7 @@ func createTOCNode(toc []markup.Header, lang string, detailsAttrs map[string]str
details.SetAttributeString(k, []byte(v))
}
- summary.AppendChild(summary, ast.NewString([]byte(translation.NewLocale(lang).Tr("toc"))))
+ summary.AppendChild(summary, ast.NewString([]byte(translation.NewLocale(lang).TrString("toc"))))
details.AppendChild(details, summary)
ul := ast.NewList('-')
details.AppendChild(details, ul)
diff --git a/modules/migration/messenger.go b/modules/migration/messenger.go
index 924aac9769..6f9cad3f10 100644
--- a/modules/migration/messenger.go
+++ b/modules/migration/messenger.go
@@ -3,7 +3,7 @@
package migration
-// Messenger is a formatting function similar to i18n.Tr
+// Messenger is a formatting function similar to i18n.TrString
type Messenger func(key string, args ...any)
// NilMessenger represents an empty formatting function
diff --git a/modules/templates/helper.go b/modules/templates/helper.go
index 96cdd9ca46..9ff5d8927f 100644
--- a/modules/templates/helper.go
+++ b/modules/templates/helper.go
@@ -36,7 +36,7 @@ func NewFuncMap() template.FuncMap {
"dict": dict, // it's lowercase because this name has been widely used. Our other functions should have uppercase names.
"Eval": Eval,
"Safe": Safe,
- "Escape": html.EscapeString,
+ "Escape": Escape,
"QueryEscape": url.QueryEscape,
"JSEscape": template.JSEscapeString,
"Str2html": Str2html, // TODO: rename it to SanitizeHTML
@@ -159,7 +159,7 @@ func NewFuncMap() template.FuncMap {
"RenderCodeBlock": RenderCodeBlock,
"RenderIssueTitle": RenderIssueTitle,
"RenderEmoji": RenderEmoji,
- "RenderEmojiPlain": emoji.ReplaceAliases,
+ "RenderEmojiPlain": RenderEmojiPlain,
"ReactionToEmoji": ReactionToEmoji,
"RenderMarkdownToHtml": RenderMarkdownToHtml,
@@ -180,13 +180,45 @@ func NewFuncMap() template.FuncMap {
}
// Safe render raw as HTML
-func Safe(raw string) template.HTML {
- return template.HTML(raw)
+func Safe(s any) template.HTML {
+ switch v := s.(type) {
+ case string:
+ return template.HTML(v)
+ case template.HTML:
+ return v
+ }
+ panic(fmt.Sprintf("unexpected type %T", s))
+}
+
+// Str2html sanitizes the input by pre-defined markdown rules
+func Str2html(s any) template.HTML {
+ switch v := s.(type) {
+ case string:
+ return template.HTML(markup.Sanitize(v))
+ case template.HTML:
+ return template.HTML(markup.Sanitize(string(v)))
+ }
+ panic(fmt.Sprintf("unexpected type %T", s))
}
-// Str2html render Markdown text to HTML
-func Str2html(raw string) template.HTML {
- return template.HTML(markup.Sanitize(raw))
+func Escape(s any) template.HTML {
+ switch v := s.(type) {
+ case string:
+ return template.HTML(html.EscapeString(v))
+ case template.HTML:
+ return v
+ }
+ panic(fmt.Sprintf("unexpected type %T", s))
+}
+
+func RenderEmojiPlain(s any) any {
+ switch v := s.(type) {
+ case string:
+ return emoji.ReplaceAliases(v)
+ case template.HTML:
+ return template.HTML(emoji.ReplaceAliases(string(v)))
+ }
+ panic(fmt.Sprintf("unexpected type %T", s))
}
// DotEscape wraps a dots in names with ZWJ [U+200D] in order to prevent autolinkers from detecting these as urls
diff --git a/modules/timeutil/since.go b/modules/timeutil/since.go
index 1cb3c4f288..dfaa0e3e3a 100644
--- a/modules/timeutil/since.go
+++ b/modules/timeutil/since.go
@@ -28,54 +28,54 @@ func computeTimeDiffFloor(diff int64, lang translation.Locale) (int64, string) {
switch {
case diff <= 0:
diff = 0
- diffStr = lang.Tr("tool.now")
+ diffStr = lang.TrString("tool.now")
case diff < 2:
diff = 0
- diffStr = lang.Tr("tool.1s")
+ diffStr = lang.TrString("tool.1s")
case diff < 1*Minute:
- diffStr = lang.Tr("tool.seconds", diff)
+ diffStr = lang.TrString("tool.seconds", diff)
diff = 0
case diff < 2*Minute:
diff -= 1 * Minute
- diffStr = lang.Tr("tool.1m")
+ diffStr = lang.TrString("tool.1m")
case diff < 1*Hour:
- diffStr = lang.Tr("tool.minutes", diff/Minute)
+ diffStr = lang.TrString("tool.minutes", diff/Minute)
diff -= diff / Minute * Minute
case diff < 2*Hour:
diff -= 1 * Hour
- diffStr = lang.Tr("tool.1h")
+ diffStr = lang.TrString("tool.1h")
case diff < 1*Day:
- diffStr = lang.Tr("tool.hours", diff/Hour)
+ diffStr = lang.TrString("tool.hours", diff/Hour)
diff -= diff / Hour * Hour
case diff < 2*Day:
diff -= 1 * Day
- diffStr = lang.Tr("tool.1d")
+ diffStr = lang.TrString("tool.1d")
case diff < 1*Week:
- diffStr = lang.Tr("tool.days", diff/Day)
+ diffStr = lang.TrString("tool.days", diff/Day)
diff -= diff / Day * Day
case diff < 2*Week:
diff -= 1 * Week
- diffStr = lang.Tr("tool.1w")
+ diffStr = lang.TrString("tool.1w")
case diff < 1*Month:
- diffStr = lang.Tr("tool.weeks", diff/Week)
+ diffStr = lang.TrString("tool.weeks", diff/Week)
diff -= diff / Week * Week
case diff < 2*Month:
diff -= 1 * Month
- diffStr = lang.Tr("tool.1mon")
+ diffStr = lang.TrString("tool.1mon")
case diff < 1*Year:
- diffStr = lang.Tr("tool.months", diff/Month)
+ diffStr = lang.TrString("tool.months", diff/Month)
diff -= diff / Month * Month
case diff < 2*Year:
diff -= 1 * Year
- diffStr = lang.Tr("tool.1y")
+ diffStr = lang.TrString("tool.1y")
default:
- diffStr = lang.Tr("tool.years", diff/Year)
+ diffStr = lang.TrString("tool.years", diff/Year)
diff -= (diff / Year) * Year
}
return diff, diffStr
@@ -97,10 +97,10 @@ func timeSincePro(then, now time.Time, lang translation.Locale) string {
diff := now.Unix() - then.Unix()
if then.After(now) {
- return lang.Tr("tool.future")
+ return lang.TrString("tool.future")
}
if diff == 0 {
- return lang.Tr("tool.now")
+ return lang.TrString("tool.now")
}
var timeStr, diffStr string
@@ -115,7 +115,7 @@ func timeSincePro(then, now time.Time, lang translation.Locale) string {
return strings.TrimPrefix(timeStr, ", ")
}
-func timeSinceUnix(then, now time.Time, lang translation.Locale) template.HTML {
+func timeSinceUnix(then, now time.Time, _ translation.Locale) template.HTML {
friendlyText := then.Format("2006-01-02 15:04:05 -07:00")
// document: https://github.com/github/relative-time-element
diff --git a/modules/translation/i18n/i18n.go b/modules/translation/i18n/i18n.go
index 42475545b3..1555cd961e 100644
--- a/modules/translation/i18n/i18n.go
+++ b/modules/translation/i18n/i18n.go
@@ -4,26 +4,25 @@
package i18n
import (
+ "html/template"
"io"
)
var DefaultLocales = NewLocaleStore()
type Locale interface {
- // Tr translates a given key and arguments for a language
- Tr(trKey string, trArgs ...any) string
- // Has reports if a locale has a translation for a given key
- Has(trKey string) bool
+ // TrString translates a given key and arguments for a language
+ TrString(trKey string, trArgs ...any) string
+ // TrHTML translates a given key and arguments for a language, string arguments are escaped to HTML
+ TrHTML(trKey string, trArgs ...any) template.HTML
+ // HasKey reports if a locale has a translation for a given key
+ HasKey(trKey string) bool
}
// LocaleStore provides the functions common to all locale stores
type LocaleStore interface {
io.Closer
- // Tr translates a given key and arguments for a language
- Tr(lang, trKey string, trArgs ...any) string
- // Has reports if a locale has a translation for a given key
- Has(lang, trKey string) bool
// SetDefaultLang sets the default language to fall back to
SetDefaultLang(lang string)
// ListLangNameDesc provides paired slices of language names to descriptors
@@ -45,7 +44,7 @@ func ResetDefaultLocales() {
DefaultLocales = NewLocaleStore()
}
-// GetLocales returns the locale from the default locales
+// GetLocale returns the locale from the default locales
func GetLocale(lang string) (Locale, bool) {
return DefaultLocales.Locale(lang)
}
diff --git a/modules/translation/i18n/i18n_test.go b/modules/translation/i18n/i18n_test.go
index 1d1be43318..ffe69a74df 100644
--- a/modules/translation/i18n/i18n_test.go
+++ b/modules/translation/i18n/i18n_test.go
@@ -17,7 +17,7 @@ fmt = %[1]s %[2]s
[section]
sub = Sub String
-mixed = test value; <span style="color: red\; background: none;">more text</span>
+mixed = test value; <span style="color: red\; background: none;">%s</span>
`)
testData2 := []byte(`
@@ -32,29 +32,33 @@ sub = Changed Sub String
assert.NoError(t, ls.AddLocaleByIni("lang2", "Lang2", testData2, nil))
ls.SetDefaultLang("lang1")
- result := ls.Tr("lang1", "fmt", "a", "b")
+ lang1, _ := ls.Locale("lang1")
+ lang2, _ := ls.Locale("lang2")
+
+ result := lang1.TrString("fmt", "a", "b")
assert.Equal(t, "a b", result)
- result = ls.Tr("lang2", "fmt", "a", "b")
+ result = lang2.TrString("fmt", "a", "b")
assert.Equal(t, "b a", result)
- result = ls.Tr("lang1", "section.sub")
+ result = lang1.TrString("section.sub")
assert.Equal(t, "Sub String", result)
- result = ls.Tr("lang2", "section.sub")
+ result = lang2.TrString("section.sub")
assert.Equal(t, "Changed Sub String", result)
- result = ls.Tr("", ".dot.name")
+ langNone, _ := ls.Locale("none")
+ result = langNone.TrString(".dot.name")
assert.Equal(t, "Dot Name", result)
- result = ls.Tr("lang2", "section.mixed")
- assert.Equal(t, `test value; <span style="color: red; background: none;">more text</span>`, result)
+ result2 := lang2.TrHTML("section.mixed", "a&b")
+ assert.EqualValues(t, `test value; <span style="color: red; background: none;">a&amp;b</span>`, result2)
langs, descs := ls.ListLangNameDesc()
assert.ElementsMatch(t, []string{"lang1", "lang2"}, langs)
assert.ElementsMatch(t, []string{"Lang1", "Lang2"}, descs)
- found := ls.Has("lang1", "no-such")
+ found := lang1.HasKey("no-such")
assert.False(t, found)
assert.NoError(t, ls.Close())
}
@@ -72,9 +76,10 @@ c=22
ls := NewLocaleStore()
assert.NoError(t, ls.AddLocaleByIni("lang1", "Lang1", testData1, testData2))
- assert.Equal(t, "11", ls.Tr("lang1", "a"))
- assert.Equal(t, "21", ls.Tr("lang1", "b"))
- assert.Equal(t, "22", ls.Tr("lang1", "c"))
+ lang1, _ := ls.Locale("lang1")
+ assert.Equal(t, "11", lang1.TrString("a"))
+ assert.Equal(t, "21", lang1.TrString("b"))
+ assert.Equal(t, "22", lang1.TrString("c"))
}
func TestLocaleStoreQuirks(t *testing.T) {
@@ -110,8 +115,9 @@ func TestLocaleStoreQuirks(t *testing.T) {
for _, testData := range testDataList {
ls := NewLocaleStore()
err := ls.AddLocaleByIni("lang1", "Lang1", []byte("a="+testData.in), nil)
+ lang1, _ := ls.Locale("lang1")
assert.NoError(t, err, testData.hint)
- assert.Equal(t, testData.out, ls.Tr("lang1", "a"), testData.hint)
+ assert.Equal(t, testData.out, lang1.TrString("a"), testData.hint)
assert.NoError(t, ls.Close())
}
diff --git a/modules/translation/i18n/localestore.go b/modules/translation/i18n/localestore.go
index f5a951a79f..69cc9fd91d 100644
--- a/modules/translation/i18n/localestore.go
+++ b/modules/translation/i18n/localestore.go
@@ -5,6 +5,8 @@ package i18n
import (
"fmt"
+ "html/template"
+ "slices"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
@@ -18,6 +20,8 @@ type locale struct {
idxToMsgMap map[int]string // the map idx is generated by store's trKeyToIdxMap
}
+var _ Locale = (*locale)(nil)
+
type localeStore struct {
// After initializing has finished, these fields are read-only.
langNames []string
@@ -85,20 +89,6 @@ func (store *localeStore) SetDefaultLang(lang string) {
store.defaultLang = lang
}
-// Tr translates content to target language. fall back to default language.
-func (store *localeStore) Tr(lang, trKey string, trArgs ...any) string {
- l, _ := store.Locale(lang)
-
- return l.Tr(trKey, trArgs...)
-}
-
-// Has returns whether the given language has a translation for the provided key
-func (store *localeStore) Has(lang, trKey string) bool {
- l, _ := store.Locale(lang)
-
- return l.Has(trKey)
-}
-
// Locale returns the locale for the lang or the default language
func (store *localeStore) Locale(lang string) (Locale, bool) {
l, found := store.localeMap[lang]
@@ -113,13 +103,11 @@ func (store *localeStore) Locale(lang string) (Locale, bool) {
return l, found
}
-// Close implements io.Closer
func (store *localeStore) Close() error {
return nil
}
-// Tr translates content to locale language. fall back to default language.
-func (l *locale) Tr(trKey string, trArgs ...any) string {
+func (l *locale) TrString(trKey string, trArgs ...any) string {
format := trKey
idx, ok := l.store.trKeyToIdxMap[trKey]
@@ -141,8 +129,23 @@ func (l *locale) Tr(trKey string, trArgs ...any) string {
return msg
}
-// Has returns whether a key is present in this locale or not
-func (l *locale) Has(trKey string) bool {
+func (l *locale) TrHTML(trKey string, trArgs ...any) template.HTML {
+ args := slices.Clone(trArgs)
+ for i, v := range args {
+ switch v := v.(type) {
+ case string:
+ args[i] = template.HTML(template.HTMLEscapeString(v))
+ case fmt.Stringer:
+ args[i] = template.HTMLEscapeString(v.String())
+ default: // int, float, include template.HTML
+ // do nothing, just use it
+ }
+ }
+ return template.HTML(l.TrString(trKey, args...))
+}
+
+// HasKey returns whether a key is present in this locale or not
+func (l *locale) HasKey(trKey string) bool {
idx, ok := l.store.trKeyToIdxMap[trKey]
if !ok {
return false
diff --git a/modules/translation/mock.go b/modules/translation/mock.go
index 2d0cb17324..1f0559f38d 100644
--- a/modules/translation/mock.go
+++ b/modules/translation/mock.go
@@ -3,7 +3,10 @@
package translation
-import "fmt"
+import (
+ "fmt"
+ "html/template"
+)
// MockLocale provides a mocked locale without any translations
type MockLocale struct{}
@@ -14,12 +17,16 @@ func (l MockLocale) Language() string {
return "en"
}
-func (l MockLocale) Tr(s string, _ ...any) string {
+func (l MockLocale) TrString(s string, _ ...any) string {
return s
}
-func (l MockLocale) TrN(_cnt any, key1, _keyN string, _args ...any) string {
- return key1
+func (l MockLocale) Tr(s string, a ...any) template.HTML {
+ return template.HTML(s)
+}
+
+func (l MockLocale) TrN(cnt any, key1, keyN string, args ...any) template.HTML {
+ return template.HTML(key1)
}
func (l MockLocale) PrettyNumber(v any) string {
diff --git a/modules/translation/translation.go b/modules/translation/translation.go
index dba4de6607..b7c18f610a 100644
--- a/modules/translation/translation.go
+++ b/modules/translation/translation.go
@@ -5,6 +5,7 @@ package translation
import (
"context"
+ "html/template"
"sort"
"strings"
"sync"
@@ -27,8 +28,11 @@ var ContextKey any = &contextKey{}
// Locale represents an interface to translation
type Locale interface {
Language() string
- Tr(string, ...any) string
- TrN(cnt any, key1, keyN string, args ...any) string
+ TrString(string, ...any) string
+
+ Tr(key string, args ...any) template.HTML
+ TrN(cnt any, key1, keyN string, args ...any) template.HTML
+
PrettyNumber(v any) string
}
@@ -144,6 +148,8 @@ type locale struct {
msgPrinter *message.Printer
}
+var _ Locale = (*locale)(nil)
+
// NewLocale return a locale
func NewLocale(lang string) Locale {
if lock != nil {
@@ -216,8 +222,12 @@ var trNLangRules = map[string]func(int64) int{
},
}
+func (l *locale) Tr(s string, args ...any) template.HTML {
+ return l.TrHTML(s, args...)
+}
+
// TrN returns translated message for plural text translation
-func (l *locale) TrN(cnt any, key1, keyN string, args ...any) string {
+func (l *locale) TrN(cnt any, key1, keyN string, args ...any) template.HTML {
var c int64
if t, ok := cnt.(int); ok {
c = int64(t)
diff --git a/modules/web/middleware/binding.go b/modules/web/middleware/binding.go
index d9bcdf3b2a..43e1bbc70e 100644
--- a/modules/web/middleware/binding.go
+++ b/modules/web/middleware/binding.go
@@ -104,40 +104,40 @@ func Validate(errs binding.Errors, data map[string]any, f Form, l translation.Lo
trName := field.Tag.Get("locale")
if len(trName) == 0 {
- trName = l.Tr("form." + field.Name)
+ trName = l.TrString("form." + field.Name)
} else {
- trName = l.Tr(trName)
+ trName = l.TrString(trName)
}
switch errs[0].Classification {
case binding.ERR_REQUIRED:
- data["ErrorMsg"] = trName + l.Tr("form.require_error")
+ data["ErrorMsg"] = trName + l.TrString("form.require_error")
case binding.ERR_ALPHA_DASH:
- data["ErrorMsg"] = trName + l.Tr("form.alpha_dash_error")
+ data["ErrorMsg"] = trName + l.TrString("form.alpha_dash_error")
case binding.ERR_ALPHA_DASH_DOT:
- data["ErrorMsg"] = trName + l.Tr("form.alpha_dash_dot_error")
+ data["ErrorMsg"] = trName + l.TrString("form.alpha_dash_dot_error")
case validation.ErrGitRefName:
- data["ErrorMsg"] = trName + l.Tr("form.git_ref_name_error")
+ data["ErrorMsg"] = trName + l.TrString("form.git_ref_name_error")
case binding.ERR_SIZE:
- data["ErrorMsg"] = trName + l.Tr("form.size_error", GetSize(field))
+ data["ErrorMsg"] = trName + l.TrString("form.size_error", GetSize(field))
case binding.ERR_MIN_SIZE:
- data["ErrorMsg"] = trName + l.Tr("form.min_size_error", GetMinSize(field))
+ data["ErrorMsg"] = trName + l.TrString("form.min_size_error", GetMinSize(field))
case binding.ERR_MAX_SIZE:
- data["ErrorMsg"] = trName + l.Tr("form.max_size_error", GetMaxSize(field))
+ data["ErrorMsg"] = trName + l.TrString("form.max_size_error", GetMaxSize(field))
case binding.ERR_EMAIL:
- data["ErrorMsg"] = trName + l.Tr("form.email_error")
+ data["ErrorMsg"] = trName + l.TrString("form.email_error")
case binding.ERR_URL:
- data["ErrorMsg"] = trName + l.Tr("form.url_error", errs[0].Message)
+ data["ErrorMsg"] = trName + l.TrString("form.url_error", errs[0].Message)
case binding.ERR_INCLUDE:
- data["ErrorMsg"] = trName + l.Tr("form.include_error", GetInclude(field))
+ data["ErrorMsg"] = trName + l.TrString("form.include_error", GetInclude(field))
case validation.ErrGlobPattern:
- data["ErrorMsg"] = trName + l.Tr("form.glob_pattern_error", errs[0].Message)
+ data["ErrorMsg"] = trName + l.TrString("form.glob_pattern_error", errs[0].Message)
case validation.ErrRegexPattern:
- data["ErrorMsg"] = trName + l.Tr("form.regex_pattern_error", errs[0].Message)
+ data["ErrorMsg"] = trName + l.TrString("form.regex_pattern_error", errs[0].Message)
case validation.ErrUsername:
- data["ErrorMsg"] = trName + l.Tr("form.username_error")
+ data["ErrorMsg"] = trName + l.TrString("form.username_error")
case validation.ErrInvalidGroupTeamMap:
- data["ErrorMsg"] = trName + l.Tr("form.invalid_group_team_map_error", errs[0].Message)
+ data["ErrorMsg"] = trName + l.TrString("form.invalid_group_team_map_error", errs[0].Message)
default:
msg := errs[0].Classification
if msg != "" && errs[0].Message != "" {
@@ -146,7 +146,7 @@ func Validate(errs binding.Errors, data map[string]any, f Form, l translation.Lo
msg += errs[0].Message
if msg == "" {
- msg = l.Tr("form.unknown_error")
+ msg = l.TrString("form.unknown_error")
}
data["ErrorMsg"] = trName + ": " + msg
}
diff --git a/modules/web/middleware/flash.go b/modules/web/middleware/flash.go
index 41f3aac27c..88da2049a4 100644
--- a/modules/web/middleware/flash.go
+++ b/modules/web/middleware/flash.go
@@ -3,7 +3,11 @@
package middleware
-import "net/url"
+import (
+ "fmt"
+ "html/template"
+ "net/url"
+)
// Flash represents a one time data transfer between two requests.
type Flash struct {
@@ -26,26 +30,36 @@ func (f *Flash) set(name, msg string, current ...bool) {
}
}
+func flashMsgStringOrHTML(msg any) string {
+ switch v := msg.(type) {
+ case string:
+ return v
+ case template.HTML:
+ return string(v)
+ }
+ panic(fmt.Sprintf("unknown type: %T", msg))
+}
+
// Error sets error message
-func (f *Flash) Error(msg string, current ...bool) {
- f.ErrorMsg = msg
- f.set("error", msg, current...)
+func (f *Flash) Error(msg any, current ...bool) {
+ f.ErrorMsg = flashMsgStringOrHTML(msg)
+ f.set("error", f.ErrorMsg, current...)
}
// Warning sets warning message
-func (f *Flash) Warning(msg string, current ...bool) {
- f.WarningMsg = msg
- f.set("warning", msg, current...)
+func (f *Flash) Warning(msg any, current ...bool) {
+ f.WarningMsg = flashMsgStringOrHTML(msg)
+ f.set("warning", f.WarningMsg, current...)
}
// Info sets info message
-func (f *Flash) Info(msg string, current ...bool) {
- f.InfoMsg = msg
- f.set("info", msg, current...)
+func (f *Flash) Info(msg any, current ...bool) {
+ f.InfoMsg = flashMsgStringOrHTML(msg)
+ f.set("info", f.InfoMsg, current...)
}
// Success sets success message
-func (f *Flash) Success(msg string, current ...bool) {
- f.SuccessMsg = msg
- f.set("success", msg, current...)
+func (f *Flash) Success(msg any, current ...bool) {
+ f.SuccessMsg = flashMsgStringOrHTML(msg)
+ f.set("success", f.SuccessMsg, current...)
}
diff --git a/routers/api/v1/repo/file.go b/routers/api/v1/repo/file.go
index 065d6bf8b2..370e4753f3 100644
--- a/routers/api/v1/repo/file.go
+++ b/routers/api/v1/repo/file.go
@@ -762,13 +762,13 @@ func changeFilesCommitMessage(ctx *context.APIContext, files []*files_service.Ch
}
message := ""
if len(createFiles) != 0 {
- message += ctx.Tr("repo.editor.add", strings.Join(createFiles, ", ")+"\n")
+ message += ctx.Locale.TrString("repo.editor.add", strings.Join(createFiles, ", ")+"\n")
}
if len(updateFiles) != 0 {
- message += ctx.Tr("repo.editor.update", strings.Join(updateFiles, ", ")+"\n")
+ message += ctx.Locale.TrString("repo.editor.update", strings.Join(updateFiles, ", ")+"\n")
}
if len(deleteFiles) != 0 {
- message += ctx.Tr("repo.editor.delete", strings.Join(deleteFiles, ", "))
+ message += ctx.Locale.TrString("repo.editor.delete", strings.Join(deleteFiles, ", "))
}
return strings.Trim(message, "\n")
}
diff --git a/routers/api/v1/repo/issue_comment.go b/routers/api/v1/repo/issue_comment.go
index 4db2c68a79..2b7a8f7ba1 100644
--- a/routers/api/v1/repo/issue_comment.go
+++ b/routers/api/v1/repo/issue_comment.go
@@ -395,7 +395,7 @@ func CreateIssueComment(ctx *context.APIContext) {
}
if issue.IsLocked && !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) && !ctx.Doer.IsAdmin {
- ctx.Error(http.StatusForbidden, "CreateIssueComment", errors.New(ctx.Tr("repo.issues.comment_on_locked")))
+ ctx.Error(http.StatusForbidden, "CreateIssueComment", errors.New(ctx.Locale.TrString("repo.issues.comment_on_locked")))
return
}
diff --git a/routers/web/admin/auths.go b/routers/web/admin/auths.go
index 2cf63c646d..7fdd18dfae 100644
--- a/routers/web/admin/auths.go
+++ b/routers/web/admin/auths.go
@@ -210,16 +210,16 @@ func parseOAuth2Config(form forms.AuthenticationForm) *oauth2.Source {
func parseSSPIConfig(ctx *context.Context, form forms.AuthenticationForm) (*sspi.Source, error) {
if util.IsEmptyString(form.SSPISeparatorReplacement) {
ctx.Data["Err_SSPISeparatorReplacement"] = true
- return nil, errors.New(ctx.Tr("form.SSPISeparatorReplacement") + ctx.Tr("form.require_error"))
+ return nil, errors.New(ctx.Locale.TrString("form.SSPISeparatorReplacement") + ctx.Locale.TrString("form.require_error"))
}
if separatorAntiPattern.MatchString(form.SSPISeparatorReplacement) {
ctx.Data["Err_SSPISeparatorReplacement"] = true
- return nil, errors.New(ctx.Tr("form.SSPISeparatorReplacement") + ctx.Tr("form.alpha_dash_dot_error"))
+ return nil, errors.New(ctx.Locale.TrString("form.SSPISeparatorReplacement") + ctx.Locale.TrString("form.alpha_dash_dot_error"))
}
if form.SSPIDefaultLanguage != "" && !langCodePattern.MatchString(form.SSPIDefaultLanguage) {
ctx.Data["Err_SSPIDefaultLanguage"] = true
- return nil, errors.New(ctx.Tr("form.lang_select_error"))
+ return nil, errors.New(ctx.Locale.TrString("form.lang_select_error"))
}
return &sspi.Source{
diff --git a/routers/web/auth/password.go b/routers/web/auth/password.go
index 5af1696a64..c23379b87a 100644
--- a/routers/web/auth/password.go
+++ b/routers/web/auth/password.go
@@ -37,7 +37,7 @@ func ForgotPasswd(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("auth.forgot_password_title")
if setting.MailService == nil {
- log.Warn(ctx.Tr("auth.disable_forgot_password_mail_admin"))
+ log.Warn("no mail service configured")
ctx.Data["IsResetDisable"] = true
ctx.HTML(http.StatusOK, tplForgotPassword)
return
diff --git a/routers/web/feed/convert.go b/routers/web/feed/convert.go
index 66b01d3680..1e040ed819 100644
--- a/routers/web/feed/convert.go
+++ b/routers/web/feed/convert.go
@@ -6,6 +6,7 @@ package feed
import (
"fmt"
"html"
+ "html/template"
"net/http"
"net/url"
"strconv"
@@ -79,119 +80,120 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio
// title
title = act.ActUser.DisplayName() + " "
+ var titleExtra template.HTML
switch act.OpType {
case activities_model.ActionCreateRepo:
- title += ctx.TrHTMLEscapeArgs("action.create_repo", act.GetRepoAbsoluteLink(ctx), act.ShortRepoPath(ctx))
+ titleExtra = ctx.Locale.Tr("action.create_repo", act.GetRepoAbsoluteLink(ctx), act.ShortRepoPath(ctx))
link.Href = act.GetRepoAbsoluteLink(ctx)
case activities_model.ActionRenameRepo:
- title += ctx.TrHTMLEscapeArgs("action.rename_repo", act.GetContent(), act.GetRepoAbsoluteLink(ctx), act.ShortRepoPath(ctx))
+ titleExtra = ctx.Locale.Tr("action.rename_repo", act.GetContent(), act.GetRepoAbsoluteLink(ctx), act.ShortRepoPath(ctx))
link.Href = act.GetRepoAbsoluteLink(ctx)
case activities_model.ActionCommitRepo:
link.Href = toBranchLink(ctx, act)
if len(act.Content) != 0 {
- title += ctx.TrHTMLEscapeArgs("action.commit_repo", act.GetRepoAbsoluteLink(ctx), link.Href, act.GetBranch(), act.ShortRepoPath(ctx))
+ titleExtra = ctx.Locale.Tr("action.commit_repo", act.GetRepoAbsoluteLink(ctx), link.Href, act.GetBranch(), act.ShortRepoPath(ctx))
} else {
- title += ctx.TrHTMLEscapeArgs("action.create_branch", act.GetRepoAbsoluteLink(ctx), link.Href, act.GetBranch(), act.ShortRepoPath(ctx))
+ titleExtra = ctx.Locale.Tr("action.create_branch", act.GetRepoAbsoluteLink(ctx), link.Href, act.GetBranch(), act.ShortRepoPath(ctx))
}
case activities_model.ActionCreateIssue:
link.Href = toIssueLink(ctx, act)
- title += ctx.TrHTMLEscapeArgs("action.create_issue", link.Href, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
+ titleExtra = ctx.Locale.Tr("action.create_issue", link.Href, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
case activities_model.ActionCreatePullRequest:
link.Href = toPullLink(ctx, act)
- title += ctx.TrHTMLEscapeArgs("action.create_pull_request", link.Href, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
+ titleExtra = ctx.Locale.Tr("action.create_pull_request", link.Href, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
case activities_model.ActionTransferRepo:
link.Href = act.GetRepoAbsoluteLink(ctx)
- title += ctx.TrHTMLEscapeArgs("action.transfer_repo", act.GetContent(), act.GetRepoAbsoluteLink(ctx), act.ShortRepoPath(ctx))
+ titleExtra = ctx.Locale.Tr("action.transfer_repo", act.GetContent(), act.GetRepoAbsoluteLink(ctx), act.ShortRepoPath(ctx))
case activities_model.ActionPushTag:
link.Href = toTagLink(ctx, act)
- title += ctx.TrHTMLEscapeArgs("action.push_tag", act.GetRepoAbsoluteLink(ctx), link.Href, act.GetTag(), act.ShortRepoPath(ctx))
+ titleExtra = ctx.Locale.Tr("action.push_tag", act.GetRepoAbsoluteLink(ctx), link.Href, act.GetTag(), act.ShortRepoPath(ctx))
case activities_model.ActionCommentIssue:
issueLink := toIssueLink(ctx, act)
if link.Href == "#" {
link.Href = issueLink
}
- title += ctx.TrHTMLEscapeArgs("action.comment_issue", issueLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
+ titleExtra = ctx.Locale.Tr("action.comment_issue", issueLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
case activities_model.ActionMergePullRequest:
pullLink := toPullLink(ctx, act)
if link.Href == "#" {
link.Href = pullLink
}
- title += ctx.TrHTMLEscapeArgs("action.merge_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
+ titleExtra = ctx.Locale.Tr("action.merge_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
case activities_model.ActionAutoMergePullRequest:
pullLink := toPullLink(ctx, act)
if link.Href == "#" {
link.Href = pullLink
}
- title += ctx.TrHTMLEscapeArgs("action.auto_merge_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
+ titleExtra = ctx.Locale.Tr("action.auto_merge_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
case activities_model.ActionCloseIssue:
issueLink := toIssueLink(ctx, act)
if link.Href == "#" {
link.Href = issueLink
}
- title += ctx.TrHTMLEscapeArgs("action.close_issue", issueLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
+ titleExtra = ctx.Locale.Tr("action.close_issue", issueLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
case activities_model.ActionReopenIssue:
issueLink := toIssueLink(ctx, act)
if link.Href == "#" {
link.Href = issueLink
}
- title += ctx.TrHTMLEscapeArgs("action.reopen_issue", issueLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
+ titleExtra = ctx.Locale.Tr("action.reopen_issue", issueLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
case activities_model.ActionClosePullRequest:
pullLink := toPullLink(ctx, act)
if link.Href == "#" {
link.Href = pullLink
}
- title += ctx.TrHTMLEscapeArgs("action.close_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
+ titleExtra = ctx.Locale.Tr("action.close_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
case activities_model.ActionReopenPullRequest:
pullLink := toPullLink(ctx, act)
if link.Href == "#" {
link.Href = pullLink
}
- title += ctx.TrHTMLEscapeArgs("action.reopen_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
+ titleExtra = ctx.Locale.Tr("action.reopen_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
case activities_model.ActionDeleteTag:
link.Href = act.GetRepoAbsoluteLink(ctx)
- title += ctx.TrHTMLEscapeArgs("action.delete_tag", act.GetRepoAbsoluteLink(ctx), act.GetTag(), act.ShortRepoPath(ctx))
+ titleExtra = ctx.Locale.Tr("action.delete_tag", act.GetRepoAbsoluteLink(ctx), act.GetTag(), act.ShortRepoPath(ctx))
case activities_model.ActionDeleteBranch:
link.Href = act.GetRepoAbsoluteLink(ctx)
- title += ctx.TrHTMLEscapeArgs("action.delete_branch", act.GetRepoAbsoluteLink(ctx), html.EscapeString(act.GetBranch()), act.ShortRepoPath(ctx))
+ titleExtra = ctx.Locale.Tr("action.delete_branch", act.GetRepoAbsoluteLink(ctx), html.EscapeString(act.GetBranch()), act.ShortRepoPath(ctx))
case activities_model.ActionMirrorSyncPush:
srcLink := toSrcLink(ctx, act)
if link.Href == "#" {
link.Href = srcLink
}
- title += ctx.TrHTMLEscapeArgs("action.mirror_sync_push", act.GetRepoAbsoluteLink(ctx), srcLink, act.GetBranch(), act.ShortRepoPath(ctx))
+ titleExtra = ctx.Locale.Tr("action.mirror_sync_push", act.GetRepoAbsoluteLink(ctx), srcLink, act.GetBranch(), act.ShortRepoPath(ctx))
case activities_model.ActionMirrorSyncCreate:
srcLink := toSrcLink(ctx, act)
if link.Href == "#" {
link.Href = srcLink
}
- title += ctx.TrHTMLEscapeArgs("action.mirror_sync_create", act.GetRepoAbsoluteLink(ctx), srcLink, act.GetBranch(), act.ShortRepoPath(ctx))
+ titleExtra = ctx.Locale.Tr("action.mirror_sync_create", act.GetRepoAbsoluteLink(ctx), srcLink, act.GetBranch(), act.ShortRepoPath(ctx))
case activities_model.ActionMirrorSyncDelete:
link.Href = act.GetRepoAbsoluteLink(ctx)
- title += ctx.TrHTMLEscapeArgs("action.mirror_sync_delete", act.GetRepoAbsoluteLink(ctx), act.GetBranch(), act.ShortRepoPath(ctx))
+ titleExtra = ctx.Locale.Tr("action.mirror_sync_delete", act.GetRepoAbsoluteLink(ctx), act.GetBranch(), act.ShortRepoPath(ctx))
case activities_model.ActionApprovePullRequest:
pullLink := toPullLink(ctx, act)
- title += ctx.TrHTMLEscapeArgs("action.approve_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
+ titleExtra = ctx.Locale.Tr("action.approve_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
case activities_model.ActionRejectPullRequest:
pullLink := toPullLink(ctx, act)
- title += ctx.TrHTMLEscapeArgs("action.reject_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
+ titleExtra = ctx.Locale.Tr("action.reject_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
case activities_model.ActionCommentPull:
pullLink := toPullLink(ctx, act)
- title += ctx.TrHTMLEscapeArgs("action.comment_pull", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
+ titleExtra = ctx.Locale.Tr("action.comment_pull", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
case activities_model.ActionPublishRelease:
releaseLink := toReleaseLink(ctx, act)
if link.Href == "#" {
link.Href = releaseLink
}
- title += ctx.TrHTMLEscapeArgs("action.publish_release", act.GetRepoAbsoluteLink(ctx), releaseLink, act.ShortRepoPath(ctx), act.Content)
+ titleExtra = ctx.Locale.Tr("action.publish_release", act.GetRepoAbsoluteLink(ctx), releaseLink, act.ShortRepoPath(ctx), act.Content)
case activities_model.ActionPullReviewDismissed:
pullLink := toPullLink(ctx, act)
- title += ctx.TrHTMLEscapeArgs("action.review_dismissed", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx), act.GetIssueInfos()[1])
+ titleExtra = ctx.Locale.Tr("action.review_dismissed", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx), act.GetIssueInfos()[1])
case activities_model.ActionStarRepo:
link.Href = act.GetRepoAbsoluteLink(ctx)
- title += ctx.TrHTMLEscapeArgs("action.starred_repo", act.GetRepoAbsoluteLink(ctx), act.GetRepoPath(ctx))
+ titleExtra = ctx.Locale.Tr("action.starred_repo", act.GetRepoAbsoluteLink(ctx), act.GetRepoPath(ctx))
case activities_model.ActionWatchRepo:
link.Href = act.GetRepoAbsoluteLink(ctx)
- title += ctx.TrHTMLEscapeArgs("action.watched_repo", act.GetRepoAbsoluteLink(ctx), act.GetRepoPath(ctx))
+ titleExtra = ctx.Locale.Tr("action.watched_repo", act.GetRepoAbsoluteLink(ctx), act.GetRepoPath(ctx))
default:
return nil, fmt.Errorf("unknown action type: %v", act.OpType)
}
@@ -233,7 +235,7 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio
case activities_model.ActionCloseIssue, activities_model.ActionReopenIssue, activities_model.ActionClosePullRequest, activities_model.ActionReopenPullRequest:
desc = act.GetIssueTitle(ctx)
case activities_model.ActionPullReviewDismissed:
- desc = ctx.Tr("action.review_dismissed_reason") + "\n\n" + act.GetIssueInfos()[2]
+ desc = ctx.Locale.TrString("action.review_dismissed_reason") + "\n\n" + act.GetIssueInfos()[2]
}
}
if len(content) == 0 {
@@ -241,7 +243,7 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio
}
items = append(items, &feeds.Item{
- Title: title,
+ Title: template.HTMLEscapeString(title) + string(titleExtra),
Link: link,
Description: desc,
IsPermaLink: "false",
diff --git a/routers/web/feed/profile.go b/routers/web/feed/profile.go
index 04f84c0c8d..3feca68d61 100644
--- a/routers/web/feed/profile.go
+++ b/routers/web/feed/profile.go
@@ -56,7 +56,7 @@ func showUserFeed(ctx *context.Context, formatType string) {
}
feed := &feeds.Feed{
- Title: ctx.Tr("home.feed_of", ctx.ContextUser.DisplayName()),
+ Title: ctx.Locale.TrString("home.feed_of", ctx.ContextUser.DisplayName()),
Link: &feeds.Link{Href: ctx.ContextUser.HTMLURL()},
Description: ctxUserDescription,
Created: time.Now(),
diff --git a/routers/web/feed/release.go b/routers/web/feed/release.go
index 57b0c92766..558c03dba7 100644
--- a/routers/web/feed/release.go
+++ b/routers/web/feed/release.go
@@ -28,10 +28,10 @@ func ShowReleaseFeed(ctx *context.Context, repo *repo_model.Repository, isReleas
var link *feeds.Link
if isReleasesOnly {
- title = ctx.Tr("repo.release.releases_for", repo.FullName())
+ title = ctx.Locale.TrString("repo.release.releases_for", repo.FullName())
link = &feeds.Link{Href: repo.HTMLURL() + "/release"}
} else {
- title = ctx.Tr("repo.release.tags_for", repo.FullName())
+ title = ctx.Locale.TrString("repo.release.tags_for", repo.FullName())
link = &feeds.Link{Href: repo.HTMLURL() + "/tags"}
}
diff --git a/routers/web/feed/repo.go b/routers/web/feed/repo.go
index 5fcad26779..51c24510c7 100644
--- a/routers/web/feed/repo.go
+++ b/routers/web/feed/repo.go
@@ -27,7 +27,7 @@ func ShowRepoFeed(ctx *context.Context, repo *repo_model.Repository, formatType
}
feed := &feeds.Feed{
- Title: ctx.Tr("home.feed_of", repo.FullName()),
+ Title: ctx.Locale.TrString("home.feed_of", repo.FullName()),
Link: &feeds.Link{Href: repo.HTMLURL()},
Description: repo.Description,
Created: time.Now(),
diff --git a/routers/web/org/org.go b/routers/web/org/org.go
index 52f8df8a1c..1e4544730e 100644
--- a/routers/web/org/org.go
+++ b/routers/web/org/org.go
@@ -29,7 +29,7 @@ func Create(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("new_org")
ctx.Data["DefaultOrgVisibilityMode"] = setting.Service.DefaultOrgVisibilityMode
if !ctx.Doer.CanCreateOrganization() {
- ctx.ServerError("Not allowed", errors.New(ctx.Tr("org.form.create_org_not_allowed")))
+ ctx.ServerError("Not allowed", errors.New(ctx.Locale.TrString("org.form.create_org_not_allowed")))
return
}
ctx.HTML(http.StatusOK, tplCreateOrg)
@@ -41,7 +41,7 @@ func CreatePost(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("new_org")
if !ctx.Doer.CanCreateOrganization() {
- ctx.ServerError("Not allowed", errors.New(ctx.Tr("org.form.create_org_not_allowed")))
+ ctx.ServerError("Not allowed", errors.New(ctx.Locale.TrString("org.form.create_org_not_allowed")))
return
}
diff --git a/routers/web/org/projects.go b/routers/web/org/projects.go
index f65cc6e679..f062127d24 100644
--- a/routers/web/org/projects.go
+++ b/routers/web/org/projects.go
@@ -353,7 +353,7 @@ func ViewProject(ctx *context.Context) {
}
if boards[0].ID == 0 {
- boards[0].Title = ctx.Tr("repo.projects.type.uncategorized")
+ boards[0].Title = ctx.Locale.TrString("repo.projects.type.uncategorized")
}
issuesMap, err := issues_model.LoadIssuesFromBoardList(ctx, boards)
@@ -679,7 +679,7 @@ func MoveIssues(ctx *context.Context) {
board = &project_model.Board{
ID: 0,
ProjectID: project.ID,
- Title: ctx.Tr("repo.projects.type.uncategorized"),
+ Title: ctx.Locale.TrString("repo.projects.type.uncategorized"),
}
} else {
board, err = project_model.GetBoard(ctx, ctx.ParamsInt64(":boardID"))
diff --git a/routers/web/repo/actions/actions.go b/routers/web/repo/actions/actions.go
index 5f6a1ec36a..19aca26711 100644
--- a/routers/web/repo/actions/actions.go
+++ b/routers/web/repo/actions/actions.go
@@ -100,7 +100,7 @@ func List(ctx *context.Context) {
}
wf, err := model.ReadWorkflow(bytes.NewReader(content))
if err != nil {
- workflow.ErrMsg = ctx.Locale.Tr("actions.runs.invalid_workflow_helper", err.Error())
+ workflow.ErrMsg = ctx.Locale.TrString("actions.runs.invalid_workflow_helper", err.Error())
workflows = append(workflows, workflow)
continue
}
@@ -115,7 +115,7 @@ func List(ctx *context.Context) {
continue
}
if !allRunnerLabels.Contains(ro) {
- workflow.ErrMsg = ctx.Locale.Tr("actions.runs.no_matching_online_runner_helper", ro)
+ workflow.ErrMsg = ctx.Locale.TrString("actions.runs.no_matching_online_runner_helper", ro)
break
}
}
diff --git a/routers/web/repo/actions/view.go b/routers/web/repo/actions/view.go
index 9cda30d23d..59fb25b680 100644
--- a/routers/web/repo/actions/view.go
+++ b/routers/web/repo/actions/view.go
@@ -168,8 +168,8 @@ func ViewPost(ctx *context_module.Context) {
Link: run.RefLink(),
}
resp.State.Run.Commit = ViewCommit{
- LocaleCommit: ctx.Tr("actions.runs.commit"),
- LocalePushedBy: ctx.Tr("actions.runs.pushed_by"),
+ LocaleCommit: ctx.Locale.TrString("actions.runs.commit"),
+ LocalePushedBy: ctx.Locale.TrString("actions.runs.pushed_by"),
ShortSha: base.ShortSha(run.CommitSHA),
Link: fmt.Sprintf("%s/commit/%s", run.Repo.Link(), run.CommitSHA),
Pusher: pusher,
@@ -194,7 +194,7 @@ func ViewPost(ctx *context_module.Context) {
resp.State.CurrentJob.Title = current.Name
resp.State.CurrentJob.Detail = current.Status.LocaleString(ctx.Locale)
if run.NeedApproval {
- resp.State.CurrentJob.Detail = ctx.Locale.Tr("actions.need_approval_desc")
+ resp.State.CurrentJob.Detail = ctx.Locale.TrString("actions.need_approval_desc")
}
resp.State.CurrentJob.Steps = make([]*ViewJobStep, 0) // marshal to '[]' instead fo 'null' in json
resp.Logs.StepsLog = make([]*ViewStepLog, 0) // marshal to '[]' instead fo 'null' in json
diff --git a/routers/web/repo/cherry_pick.go b/routers/web/repo/cherry_pick.go
index 25dd881219..8de54d569f 100644
--- a/routers/web/repo/cherry_pick.go
+++ b/routers/web/repo/cherry_pick.go
@@ -104,9 +104,9 @@ func CherryPickPost(ctx *context.Context) {
message := strings.TrimSpace(form.CommitSummary)
if message == "" {
if form.Revert {
- message = ctx.Tr("repo.commit.revert-header", sha)
+ message = ctx.Locale.TrString("repo.commit.revert-header", sha)
} else {
- message = ctx.Tr("repo.commit.cherry-pick-header", sha)
+ message = ctx.Locale.TrString("repo.commit.cherry-pick-header", sha)
}
}
diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go
index a3593815b8..67d41cf807 100644
--- a/routers/web/repo/compare.go
+++ b/routers/web/repo/compare.go
@@ -126,7 +126,7 @@ func setCsvCompareContext(ctx *context.Context) {
return CsvDiffResult{nil, ""}
}
- errTooLarge := errors.New(ctx.Locale.Tr("repo.error.csv.too_large"))
+ errTooLarge := errors.New(ctx.Locale.TrString("repo.error.csv.too_large"))
csvReaderFromCommit := func(ctx *markup.RenderContext, blob *git.Blob) (*csv.Reader, io.Closer, error) {
if blob == nil {
diff --git a/routers/web/repo/editor.go b/routers/web/repo/editor.go
index 85d40e7820..bc3cb8801d 100644
--- a/routers/web/repo/editor.go
+++ b/routers/web/repo/editor.go
@@ -262,9 +262,9 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b
message := strings.TrimSpace(form.CommitSummary)
if len(message) == 0 {
if isNewFile {
- message = ctx.Tr("repo.editor.add", form.TreePath)
+ message = ctx.Locale.TrString("repo.editor.add", form.TreePath)
} else {
- message = ctx.Tr("repo.editor.update", form.TreePath)
+ message = ctx.Locale.TrString("repo.editor.update", form.TreePath)
}
}
form.CommitMessage = strings.TrimSpace(form.CommitMessage)
@@ -415,7 +415,7 @@ func DiffPreviewPost(ctx *context.Context) {
}
if diff.NumFiles == 0 {
- ctx.PlainText(http.StatusOK, ctx.Tr("repo.editor.no_changes_to_show"))
+ ctx.PlainText(http.StatusOK, ctx.Locale.TrString("repo.editor.no_changes_to_show"))
return
}
ctx.Data["File"] = diff.Files[0]
@@ -482,7 +482,7 @@ func DeleteFilePost(ctx *context.Context) {
message := strings.TrimSpace(form.CommitSummary)
if len(message) == 0 {
- message = ctx.Tr("repo.editor.delete", ctx.Repo.TreePath)
+ message = ctx.Locale.TrString("repo.editor.delete", ctx.Repo.TreePath)
}
form.CommitMessage = strings.TrimSpace(form.CommitMessage)
if len(form.CommitMessage) > 0 {
@@ -691,7 +691,7 @@ func UploadFilePost(ctx *context.Context) {
if dir == "" {
dir = "/"
}
- message = ctx.Tr("repo.editor.upload_files_to_dir", dir)
+ message = ctx.Locale.TrString("repo.editor.upload_files_to_dir", dir)
}
form.CommitMessage = strings.TrimSpace(form.CommitMessage)
diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go
index a85f6e7666..d5e49960a1 100644
--- a/routers/web/repo/issue.go
+++ b/routers/web/repo/issue.go
@@ -1036,7 +1036,7 @@ func renderErrorOfTemplates(ctx *context.Context, errs map[string]error) string
})
if err != nil {
log.Debug("render flash error: %v", err)
- flashError = ctx.Tr("repo.issues.choose.ignore_invalid_templates")
+ flashError = ctx.Locale.TrString("repo.issues.choose.ignore_invalid_templates")
}
return flashError
}
@@ -1655,7 +1655,7 @@ func ViewIssue(ctx *context.Context) {
}
ghostMilestone := &issues_model.Milestone{
ID: -1,
- Name: ctx.Tr("repo.issues.deleted_milestone"),
+ Name: ctx.Locale.TrString("repo.issues.deleted_milestone"),
}
if comment.OldMilestoneID > 0 && comment.OldMilestone == nil {
comment.OldMilestone = ghostMilestone
@@ -1672,7 +1672,7 @@ func ViewIssue(ctx *context.Context) {
ghostProject := &project_model.Project{
ID: -1,
- Title: ctx.Tr("repo.issues.deleted_project"),
+ Title: ctx.Locale.TrString("repo.issues.deleted_project"),
}
if comment.OldProjectID > 0 && comment.OldProject == nil {
diff --git a/routers/web/repo/issue_content_history.go b/routers/web/repo/issue_content_history.go
index 0f376db145..0939af487c 100644
--- a/routers/web/repo/issue_content_history.go
+++ b/routers/web/repo/issue_content_history.go
@@ -56,12 +56,12 @@ func GetContentHistoryList(ctx *context.Context) {
for _, item := range items {
var actionText string
if item.IsDeleted {
- actionTextDeleted := ctx.Locale.Tr("repo.issues.content_history.deleted")
+ actionTextDeleted := ctx.Locale.TrString("repo.issues.content_history.deleted")
actionText = "<i data-history-is-deleted='1'>" + actionTextDeleted + "</i>"
} else if item.IsFirstCreated {
- actionText = ctx.Locale.Tr("repo.issues.content_history.created")
+ actionText = ctx.Locale.TrString("repo.issues.content_history.created")
} else {
- actionText = ctx.Locale.Tr("repo.issues.content_history.edited")
+ actionText = ctx.Locale.TrString("repo.issues.content_history.edited")
}
username := item.UserName
diff --git a/routers/web/repo/issue_label_test.go b/routers/web/repo/issue_label_test.go
index e0d49e44e1..742f12114d 100644
--- a/routers/web/repo/issue_label_test.go
+++ b/routers/web/repo/issue_label_test.go
@@ -123,7 +123,7 @@ func TestDeleteLabel(t *testing.T) {
assert.EqualValues(t, http.StatusOK, ctx.Resp.Status())
unittest.AssertNotExistsBean(t, &issues_model.Label{ID: 2})
unittest.AssertNotExistsBean(t, &issues_model.IssueLabel{LabelID: 2})
- assert.Equal(t, ctx.Tr("repo.issues.label_deletion_success"), ctx.Flash.SuccessMsg)
+ assert.EqualValues(t, ctx.Tr("repo.issues.label_deletion_success"), ctx.Flash.SuccessMsg)
}
func TestUpdateIssueLabel_Clear(t *testing.T) {
diff --git a/routers/web/repo/patch.go b/routers/web/repo/patch.go
index c04435cf1b..00bd45aaec 100644
--- a/routers/web/repo/patch.go
+++ b/routers/web/repo/patch.go
@@ -79,7 +79,7 @@ func NewDiffPatchPost(ctx *context.Context) {
// `message` will be both the summary and message combined
message := strings.TrimSpace(form.CommitSummary)
if len(message) == 0 {
- message = ctx.Tr("repo.editor.patch")
+ message = ctx.Locale.TrString("repo.editor.patch")
}
form.CommitMessage = strings.TrimSpace(form.CommitMessage)
diff --git a/routers/web/repo/projects.go b/routers/web/repo/projects.go
index 001f0752c3..cc0127e7e1 100644
--- a/routers/web/repo/projects.go
+++ b/routers/web/repo/projects.go
@@ -315,7 +315,7 @@ func ViewProject(ctx *context.Context) {
}
if boards[0].ID == 0 {
- boards[0].Title = ctx.Tr("repo.projects.type.uncategorized")
+ boards[0].Title = ctx.Locale.TrString("repo.projects.type.uncategorized")
}
issuesMap, err := issues_model.LoadIssuesFromBoardList(ctx, boards)
@@ -633,7 +633,7 @@ func MoveIssues(ctx *context.Context) {
board = &project_model.Board{
ID: 0,
ProjectID: project.ID,
- Title: ctx.Tr("repo.projects.type.uncategorized"),
+ Title: ctx.Locale.TrString("repo.projects.type.uncategorized"),
}
} else {
board, err = project_model.GetBoard(ctx, ctx.ParamsInt64(":boardID"))
diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go
index b265cf4754..365d9bf258 100644
--- a/routers/web/repo/pull.go
+++ b/routers/web/repo/pull.go
@@ -723,7 +723,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C
type pullCommitList struct {
Commits []pull_service.CommitInfo `json:"commits"`
LastReviewCommitSha string `json:"last_review_commit_sha"`
- Locale map[string]string `json:"locale"`
+ Locale map[string]any `json:"locale"`
}
// GetPullCommits get all commits for given pull request
@@ -741,7 +741,7 @@ func GetPullCommits(ctx *context.Context) {
}
// Get the needed locale
- resp.Locale = map[string]string{
+ resp.Locale = map[string]any{
"lang": ctx.Locale.Language(),
"show_all_commits": ctx.Tr("repo.pulls.show_all_commits"),
"stats_num_commits": ctx.TrN(len(commits), "repo.activity.git_stats_commit_1", "repo.activity.git_stats_commit_n", len(commits)),
diff --git a/routers/web/repo/pull_review.go b/routers/web/repo/pull_review.go
index b93460d169..217f2dea6d 100644
--- a/routers/web/repo/pull_review.go
+++ b/routers/web/repo/pull_review.go
@@ -219,9 +219,9 @@ func SubmitReview(ctx *context.Context) {
if issue.IsPoster(ctx.Doer.ID) {
var translated string
if reviewType == issues_model.ReviewTypeApprove {
- translated = ctx.Tr("repo.issues.review.self.approval")
+ translated = ctx.Locale.TrString("repo.issues.review.self.approval")
} else {
- translated = ctx.Tr("repo.issues.review.self.rejection")
+ translated = ctx.Locale.TrString("repo.issues.review.self.rejection")
}
ctx.Flash.Error(translated)
diff --git a/routers/web/repo/setting/avatar.go b/routers/web/repo/setting/avatar.go
index 02c807b775..44468d2666 100644
--- a/routers/web/repo/setting/avatar.go
+++ b/routers/web/repo/setting/avatar.go
@@ -38,7 +38,7 @@ func UpdateAvatarSetting(ctx *context.Context, form forms.AvatarForm) error {
defer r.Close()
if form.Avatar.Size > setting.Avatar.MaxFileSize {
- return errors.New(ctx.Tr("settings.uploaded_avatar_is_too_big", form.Avatar.Size/1024, setting.Avatar.MaxFileSize/1024))
+ return errors.New(ctx.Locale.TrString("settings.uploaded_avatar_is_too_big", form.Avatar.Size/1024, setting.Avatar.MaxFileSize/1024))
}
data, err := io.ReadAll(r)
@@ -47,7 +47,7 @@ func UpdateAvatarSetting(ctx *context.Context, form forms.AvatarForm) error {
}
st := typesniffer.DetectContentType(data)
if !(st.IsImage() && !st.IsSvgImage()) {
- return errors.New(ctx.Tr("settings.uploaded_avatar_not_a_image"))
+ return errors.New(ctx.Locale.TrString("settings.uploaded_avatar_not_a_image"))
}
if err = repo_service.UploadAvatar(ctx, ctxRepo, data); err != nil {
return fmt.Errorf("UploadAvatar: %w", err)
diff --git a/routers/web/repo/setting/protected_branch.go b/routers/web/repo/setting/protected_branch.go
index 98d6977b81..85068f0ab2 100644
--- a/routers/web/repo/setting/protected_branch.go
+++ b/routers/web/repo/setting/protected_branch.go
@@ -68,7 +68,7 @@ func SettingsProtectedBranch(c *context.Context) {
}
c.Data["PageIsSettingsBranches"] = true
- c.Data["Title"] = c.Tr("repo.settings.protected_branch") + " - " + rule.RuleName
+ c.Data["Title"] = c.Locale.TrString("repo.settings.protected_branch") + " - " + rule.RuleName
users, err := access_model.GetRepoReaders(c, c.Repo.Repository)
if err != nil {
diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go
index 75051d1995..15f22237a8 100644
--- a/routers/web/repo/view.go
+++ b/routers/web/repo/view.go
@@ -739,7 +739,7 @@ func checkHomeCodeViewable(ctx *context.Context) {
}
}
- ctx.NotFound("Home", fmt.Errorf(ctx.Tr("units.error.no_unit_allowed_repo")))
+ ctx.NotFound("Home", fmt.Errorf(ctx.Locale.TrString("units.error.no_unit_allowed_repo")))
}
func checkCitationFile(ctx *context.Context, entry *git.TreeEntry) {
diff --git a/routers/web/repo/wiki.go b/routers/web/repo/wiki.go
index 5e7b971e67..49e95faaba 100644
--- a/routers/web/repo/wiki.go
+++ b/routers/web/repo/wiki.go
@@ -714,7 +714,7 @@ func NewWikiPost(ctx *context.Context) {
wikiName := wiki_service.UserTitleToWebPath("", form.Title)
if len(form.Message) == 0 {
- form.Message = ctx.Tr("repo.editor.add", form.Title)
+ form.Message = ctx.Locale.TrString("repo.editor.add", form.Title)
}
if err := wiki_service.AddWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, wikiName, form.Content, form.Message); err != nil {
@@ -766,7 +766,7 @@ func EditWikiPost(ctx *context.Context) {
newWikiName := wiki_service.UserTitleToWebPath("", form.Title)
if len(form.Message) == 0 {
- form.Message = ctx.Tr("repo.editor.update", form.Title)
+ form.Message = ctx.Locale.TrString("repo.editor.update", form.Title)
}
if err := wiki_service.EditWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, oldWikiName, newWikiName, form.Content, form.Message); err != nil {
diff --git a/routers/web/user/home.go b/routers/web/user/home.go
index 83fc4d7162..b7abbcbc00 100644
--- a/routers/web/user/home.go
+++ b/routers/web/user/home.go
@@ -85,7 +85,7 @@ func Dashboard(ctx *context.Context) {
page = 1
}
- ctx.Data["Title"] = ctxUser.DisplayName() + " - " + ctx.Tr("dashboard")
+ ctx.Data["Title"] = ctxUser.DisplayName() + " - " + ctx.Locale.TrString("dashboard")
ctx.Data["PageIsDashboard"] = true
ctx.Data["PageIsNews"] = true
cnt, _ := organization.GetOrganizationCount(ctx, ctxUser)
diff --git a/routers/web/user/setting/profile.go b/routers/web/user/setting/profile.go
index 95b350528c..24a807d518 100644
--- a/routers/web/user/setting/profile.go
+++ b/routers/web/user/setting/profile.go
@@ -126,7 +126,7 @@ func UpdateAvatarSetting(ctx *context.Context, form *forms.AvatarForm, ctxUser *
defer fr.Close()
if form.Avatar.Size > setting.Avatar.MaxFileSize {
- return errors.New(ctx.Tr("settings.uploaded_avatar_is_too_big", form.Avatar.Size/1024, setting.Avatar.MaxFileSize/1024))
+ return errors.New(ctx.Locale.TrString("settings.uploaded_avatar_is_too_big", form.Avatar.Size/1024, setting.Avatar.MaxFileSize/1024))
}
data, err := io.ReadAll(fr)
@@ -136,7 +136,7 @@ func UpdateAvatarSetting(ctx *context.Context, form *forms.AvatarForm, ctxUser *
st := typesniffer.DetectContentType(data)
if !(st.IsImage() && !st.IsSvgImage()) {
- return errors.New(ctx.Tr("settings.uploaded_avatar_not_a_image"))
+ return errors.New(ctx.Locale.TrString("settings.uploaded_avatar_not_a_image"))
}
if err = user_service.UploadAvatar(ctx, ctxUser, data); err != nil {
return fmt.Errorf("UploadAvatar: %w", err)
@@ -389,7 +389,7 @@ func UpdateUserLang(ctx *context.Context) {
middleware.SetLocaleCookie(ctx.Resp, ctx.Doer.Language, 0)
log.Trace("User settings updated: %s", ctx.Doer.Name)
- ctx.Flash.Success(translation.NewLocale(ctx.Doer.Language).Tr("settings.update_language_success"))
+ ctx.Flash.Success(translation.NewLocale(ctx.Doer.Language).TrString("settings.update_language_success"))
ctx.Redirect(setting.AppSubURL + "/user/settings/appearance")
}
diff --git a/routers/web/user/task.go b/routers/web/user/task.go
index f35f40e6a0..bec68c5f20 100644
--- a/routers/web/user/task.go
+++ b/routers/web/user/task.go
@@ -39,7 +39,7 @@ func TaskStatus(ctx *context.Context) {
Args: []any{task.Message},
}
}
- message = ctx.Tr(translatableMessage.Format, translatableMessage.Args...)
+ message = ctx.Locale.TrString(translatableMessage.Format, translatableMessage.Args...)
}
ctx.JSON(http.StatusOK, map[string]any{
diff --git a/routers/web/web.go b/routers/web/web.go
index 92cf5132b4..ba5c86cc7e 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -155,7 +155,7 @@ func verifyAuthWithOptions(options *common.VerifyOptions) func(ctx *context.Cont
if ctx.Doer.MustChangePassword {
if ctx.Req.URL.Path != "/user/settings/change_password" {
if strings.HasPrefix(ctx.Req.UserAgent(), "git") {
- ctx.Error(http.StatusUnauthorized, ctx.Tr("auth.must_change_password"))
+ ctx.Error(http.StatusUnauthorized, ctx.Locale.TrString("auth.must_change_password"))
return
}
ctx.Data["Title"] = ctx.Tr("auth.must_change_password")
diff --git a/services/cron/setting.go b/services/cron/setting.go
index 0656307cba..6dad88830a 100644
--- a/services/cron/setting.go
+++ b/services/cron/setting.go
@@ -70,7 +70,7 @@ func (b *BaseConfig) DoNoticeOnSuccess() bool {
// Please note the `status` string will be concatenated with `admin.dashboard.cron.` and `admin.dashboard.task.` to provide locale messages. Similarly `name` will be composed with `admin.dashboard.` to provide the locale name for the task.
func (b *BaseConfig) FormatMessage(locale translation.Locale, name, status, doer string, args ...any) string {
realArgs := make([]any, 0, len(args)+2)
- realArgs = append(realArgs, locale.Tr("admin.dashboard."+name))
+ realArgs = append(realArgs, locale.TrString("admin.dashboard."+name))
if doer == "" {
realArgs = append(realArgs, "(Cron)")
} else {
@@ -80,7 +80,7 @@ func (b *BaseConfig) FormatMessage(locale translation.Locale, name, status, doer
realArgs = append(realArgs, args...)
}
if doer == "" {
- return locale.Tr("admin.dashboard.cron."+status, realArgs...)
+ return locale.TrString("admin.dashboard.cron."+status, realArgs...)
}
- return locale.Tr("admin.dashboard.task."+status, realArgs...)
+ return locale.TrString("admin.dashboard.task."+status, realArgs...)
}
diff --git a/services/cron/tasks.go b/services/cron/tasks.go
index f0956a97d8..f8a7444c49 100644
--- a/services/cron/tasks.go
+++ b/services/cron/tasks.go
@@ -159,7 +159,7 @@ func RegisterTask(name string, config Config, fun func(context.Context, *user_mo
log.Debug("Registering task: %s", name)
i18nKey := "admin.dashboard." + name
- if value := translation.NewLocale("en-US").Tr(i18nKey); value == i18nKey {
+ if value := translation.NewLocale("en-US").TrString(i18nKey); value == i18nKey {
return fmt.Errorf("translation is missing for task %q, please add translation for %q", name, i18nKey)
}
diff --git a/services/forms/repo_form.go b/services/forms/repo_form.go
index 60fa0ab363..98d556b946 100644
--- a/services/forms/repo_form.go
+++ b/services/forms/repo_form.go
@@ -314,7 +314,7 @@ func (f *NewSlackHookForm) Validate(req *http.Request, errs binding.Errors) bind
errs = append(errs, binding.Error{
FieldNames: []string{"Channel"},
Classification: "",
- Message: ctx.Tr("repo.settings.add_webhook.invalid_channel_name"),
+ Message: ctx.Locale.TrString("repo.settings.add_webhook.invalid_channel_name"),
})
}
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
diff --git a/services/mailer/mail.go b/services/mailer/mail.go
index ca27336f92..38973ea935 100644
--- a/services/mailer/mail.go
+++ b/services/mailer/mail.go
@@ -94,7 +94,7 @@ func SendActivateAccountMail(locale translation.Locale, u *user_model.User) {
// No mail service configured
return
}
- sendUserMail(locale.Language(), u, mailAuthActivate, u.GenerateEmailActivateCode(u.Email), locale.Tr("mail.activate_account"), "activate account")
+ sendUserMail(locale.Language(), u, mailAuthActivate, u.GenerateEmailActivateCode(u.Email), locale.TrString("mail.activate_account"), "activate account")
}
// SendResetPasswordMail sends a password reset mail to the user
@@ -104,7 +104,7 @@ func SendResetPasswordMail(u *user_model.User) {
return
}
locale := translation.NewLocale(u.Language)
- sendUserMail(u.Language, u, mailAuthResetPassword, u.GenerateEmailActivateCode(u.Email), locale.Tr("mail.reset_password"), "recover account")
+ sendUserMail(u.Language, u, mailAuthResetPassword, u.GenerateEmailActivateCode(u.Email), locale.TrString("mail.reset_password"), "recover account")
}
// SendActivateEmailMail sends confirmation email to confirm new email address
@@ -130,7 +130,7 @@ func SendActivateEmailMail(u *user_model.User, email string) {
return
}
- msg := NewMessage(email, locale.Tr("mail.activate_email"), content.String())
+ msg := NewMessage(email, locale.TrString("mail.activate_email"), content.String())
msg.Info = fmt.Sprintf("UID: %d, activate email", u.ID)
SendAsync(msg)
@@ -158,7 +158,7 @@ func SendRegisterNotifyMail(u *user_model.User) {
return
}
- msg := NewMessage(u.Email, locale.Tr("mail.register_notify"), content.String())
+ msg := NewMessage(u.Email, locale.TrString("mail.register_notify"), content.String())
msg.Info = fmt.Sprintf("UID: %d, registration notify", u.ID)
SendAsync(msg)
@@ -173,7 +173,7 @@ func SendCollaboratorMail(u, doer *user_model.User, repo *repo_model.Repository)
locale := translation.NewLocale(u.Language)
repoName := repo.FullName()
- subject := locale.Tr("mail.repo.collaborator.added.subject", doer.DisplayName(), repoName)
+ subject := locale.TrString("mail.repo.collaborator.added.subject", doer.DisplayName(), repoName)
data := map[string]any{
"locale": locale,
"Subject": subject,
diff --git a/services/mailer/mail_release.go b/services/mailer/mail_release.go
index 5e8e5b6af3..6682774a04 100644
--- a/services/mailer/mail_release.go
+++ b/services/mailer/mail_release.go
@@ -68,7 +68,7 @@ func mailNewRelease(ctx context.Context, lang string, tos []string, rel *repo_mo
return
}
- subject := locale.Tr("mail.release.new.subject", rel.TagName, rel.Repo.FullName())
+ subject := locale.TrString("mail.release.new.subject", rel.TagName, rel.Repo.FullName())
mailMeta := map[string]any{
"locale": locale,
"Release": rel,
diff --git a/services/mailer/mail_repo.go b/services/mailer/mail_repo.go
index b89dcd43b5..e0d55bb120 100644
--- a/services/mailer/mail_repo.go
+++ b/services/mailer/mail_repo.go
@@ -56,11 +56,11 @@ func sendRepoTransferNotifyMailPerLang(lang string, newOwner, doer *user_model.U
content bytes.Buffer
)
- destination := locale.Tr("mail.repo.transfer.to_you")
- subject := locale.Tr("mail.repo.transfer.subject_to_you", doer.DisplayName(), repo.FullName())
+ destination := locale.TrString("mail.repo.transfer.to_you")
+ subject := locale.TrString("mail.repo.transfer.subject_to_you", doer.DisplayName(), repo.FullName())
if newOwner.IsOrganization() {
destination = newOwner.DisplayName()
- subject = locale.Tr("mail.repo.transfer.subject_to", doer.DisplayName(), repo.FullName(), destination)
+ subject = locale.TrString("mail.repo.transfer.subject_to", doer.DisplayName(), repo.FullName(), destination)
}
data := map[string]any{
diff --git a/services/mailer/mail_team_invite.go b/services/mailer/mail_team_invite.go
index ab32beefac..ceecefa50f 100644
--- a/services/mailer/mail_team_invite.go
+++ b/services/mailer/mail_team_invite.go
@@ -50,7 +50,7 @@ func MailTeamInvite(ctx context.Context, inviter *user_model.User, team *org_mod
inviteURL = fmt.Sprintf("%suser/login?redirect_to=%s", setting.AppURL, inviteRedirect)
}
- subject := locale.Tr("mail.team_invite.subject", inviter.DisplayName(), org.DisplayName())
+ subject := locale.TrString("mail.team_invite.subject", inviter.DisplayName(), org.DisplayName())
mailMeta := map[string]any{
"locale": locale,
"Inviter": inviter,
diff --git a/templates/mail/issue/assigned.tmpl b/templates/mail/issue/assigned.tmpl
index d02ea39918..e80bd2fc31 100644
--- a/templates/mail/issue/assigned.tmpl
+++ b/templates/mail/issue/assigned.tmpl
@@ -13,9 +13,9 @@
<body>
<p>
{{if .IsPull}}
- {{.locale.Tr "mail.issue_assigned.pull" .Doer.Name $link $repo_url | Str2html}}
+ {{.locale.Tr "mail.issue_assigned.pull" .Doer.Name ($link|Safe) ($repo_url|Safe)}}
{{else}}
- {{.locale.Tr "mail.issue_assigned.issue" .Doer.Name $link $repo_url | Str2html}}
+ {{.locale.Tr "mail.issue_assigned.issue" .Doer.Name ($link|Safe) ($repo_url|Safe)}}
{{end}}
</p>
<div class="footer">
diff --git a/templates/mail/issue/default.tmpl b/templates/mail/issue/default.tmpl
index 422a4f0461..b5a7ab95cf 100644
--- a/templates/mail/issue/default.tmpl
+++ b/templates/mail/issue/default.tmpl
@@ -28,7 +28,7 @@
{{$newShortSha := ShortSha .Comment.NewCommit}}
{{$newCommitLink := printf "<a href='%[1]s'><b>%[2]s</b></a>" (Escape $newCommitUrl) (Escape $newShortSha)}}
- {{.locale.Tr "mail.issue.action.force_push" .Doer.Name .Comment.Issue.PullRequest.HeadBranch $oldCommitLink $newCommitLink | Str2html}}
+ {{.locale.Tr "mail.issue.action.force_push" .Doer.Name .Comment.Issue.PullRequest.HeadBranch ($oldCommitLink|Safe) ($newCommitLink|Safe)}}
{{else}}
{{.locale.TrN (len .Comment.Commits) "mail.issue.action.push_1" "mail.issue.action.push_n" .Doer.Name .Comment.Issue.PullRequest.HeadBranch (len .Comment.Commits) | Str2html}}
{{end}}
diff --git a/templates/mail/notify/repo_transfer.tmpl b/templates/mail/notify/repo_transfer.tmpl
index 43d95b3ff0..1b23593f6b 100644
--- a/templates/mail/notify/repo_transfer.tmpl
+++ b/templates/mail/notify/repo_transfer.tmpl
@@ -8,7 +8,7 @@
{{$url := printf "<a href='%[1]s'>%[2]s</a>" (Escape .Link) (Escape .Repo)}}
<body>
<p>{{.Subject}}.
- {{.locale.Tr "mail.repo.transfer.body" $url | Str2html}}
+ {{.locale.Tr "mail.repo.transfer.body" ($url|Safe)}}
</p>
<p>
---
diff --git a/templates/mail/release.tmpl b/templates/mail/release.tmpl
index f588d8224f..96dc769993 100644
--- a/templates/mail/release.tmpl
+++ b/templates/mail/release.tmpl
@@ -15,7 +15,7 @@
{{$repo_url := printf "<a href='%s'>%s</a>" (.Release.Repo.HTMLURL | Escape) (.Release.Repo.FullName | Escape)}}
<body>
<p>
- {{.locale.Tr "mail.release.new.text" .Release.Publisher.Name $release_url $repo_url | Str2html}}
+ {{.locale.Tr "mail.release.new.text" .Release.Publisher.Name ($release_url|Safe) ($repo_url|Safe)}}
</p>
<h4>{{.locale.Tr "mail.release.title" .Release.Title}}</h4>
<p>
diff --git a/templates/repo/editor/cherry_pick.tmpl b/templates/repo/editor/cherry_pick.tmpl
index ab2c3c3349..b65c3a3033 100644
--- a/templates/repo/editor/cherry_pick.tmpl
+++ b/templates/repo/editor/cherry_pick.tmpl
@@ -13,9 +13,9 @@
{{$shaurl := printf "%s/commit/%s" $.RepoLink (PathEscape .SHA)}}
{{$shalink := printf `<a class="ui primary sha label" href="%s">%s</a>` (Escape $shaurl) (ShortSha .SHA)}}
{{if eq .CherryPickType "revert"}}
- {{ctx.Locale.Tr "repo.editor.revert" $shalink | Str2html}}
+ {{ctx.Locale.Tr "repo.editor.revert" ($shalink|Safe)}}
{{else}}
- {{ctx.Locale.Tr "repo.editor.cherry_pick" $shalink | Str2html}}
+ {{ctx.Locale.Tr "repo.editor.cherry_pick" ($shalink|Safe)}}
{{end}}
<a class="section" href="{{$.RepoLink}}">{{.Repository.FullName}}</a>
<div class="breadcrumb-divider">:</div>
diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl
index 3cb7f7d0cf..c1797ba77d 100644
--- a/templates/repo/issue/view_content/comments.tmpl
+++ b/templates/repo/issue/view_content/comments.tmpl
@@ -591,11 +591,11 @@
{{$newProjectDisplayHtml = printf `<span data-tooltip-content="%s">%s</span>` (ctx.Locale.Tr $trKey | Escape) (.Project.Title | Escape)}}
{{end}}
{{if and (gt .OldProjectID 0) (gt .ProjectID 0)}}
- {{ctx.Locale.Tr "repo.issues.change_project_at" $oldProjectDisplayHtml $newProjectDisplayHtml $createdStr | Safe}}
+ {{ctx.Locale.Tr "repo.issues.change_project_at" ($oldProjectDisplayHtml|Safe) ($newProjectDisplayHtml|Safe) $createdStr}}
{{else if gt .OldProjectID 0}}
- {{ctx.Locale.Tr "repo.issues.remove_project_at" $oldProjectDisplayHtml $createdStr | Safe}}
+ {{ctx.Locale.Tr "repo.issues.remove_project_at" ($oldProjectDisplayHtml|Safe) $createdStr}}
{{else if gt .ProjectID 0}}
- {{ctx.Locale.Tr "repo.issues.add_project_at" $newProjectDisplayHtml $createdStr | Safe}}
+ {{ctx.Locale.Tr "repo.issues.add_project_at" ($newProjectDisplayHtml|Safe) $createdStr}}
{{end}}
</span>
</div>
diff --git a/templates/repo/issue/view_title.tmpl b/templates/repo/issue/view_title.tmpl
index 7ec48c6734..582e9864fb 100644
--- a/templates/repo/issue/view_title.tmpl
+++ b/templates/repo/issue/view_title.tmpl
@@ -56,18 +56,18 @@
{{$mergedStr:= TimeSinceUnix .Issue.PullRequest.MergedUnix ctx.Locale}}
{{if .Issue.OriginalAuthor}}
{{.Issue.OriginalAuthor}}
- <span class="pull-desc">{{ctx.Locale.Tr "repo.pulls.merged_title_desc" .NumCommits $headHref $baseHref $mergedStr | Safe}}</span>
+ <span class="pull-desc">{{ctx.Locale.Tr "repo.pulls.merged_title_desc" .NumCommits ($headHref|Safe) ($baseHref|Safe) $mergedStr}}</span>
{{else}}
<a {{if gt .Issue.PullRequest.Merger.ID 0}}href="{{.Issue.PullRequest.Merger.HomeLink}}"{{end}}>{{.Issue.PullRequest.Merger.GetDisplayName}}</a>
- <span class="pull-desc">{{ctx.Locale.Tr "repo.pulls.merged_title_desc" .NumCommits $headHref $baseHref $mergedStr | Safe}}</span>
+ <span class="pull-desc">{{ctx.Locale.Tr "repo.pulls.merged_title_desc" .NumCommits ($headHref|Safe) ($baseHref|Safe) $mergedStr}}</span>
{{end}}
{{else}}
{{if .Issue.OriginalAuthor}}
- <span id="pull-desc" class="pull-desc">{{.Issue.OriginalAuthor}} {{ctx.Locale.Tr "repo.pulls.title_desc" .NumCommits $headHref $baseHref | Safe}}</span>
+ <span id="pull-desc" class="pull-desc">{{.Issue.OriginalAuthor}} {{ctx.Locale.Tr "repo.pulls.title_desc" .NumCommits ($headHref|Safe) ($baseHref|Safe)}}</span>
{{else}}
<span id="pull-desc" class="pull-desc">
<a {{if gt .Issue.Poster.ID 0}}href="{{.Issue.Poster.HomeLink}}"{{end}}>{{.Issue.Poster.GetDisplayName}}</a>
- {{ctx.Locale.Tr "repo.pulls.title_desc" .NumCommits $headHref $baseHref | Safe}}
+ {{ctx.Locale.Tr "repo.pulls.title_desc" .NumCommits ($headHref|Safe) ($baseHref|Safe)}}
</span>
{{end}}
<span id="pull-desc-edit" class="gt-hidden flex-text-block">
diff --git a/tests/integration/auth_ldap_test.go b/tests/integration/auth_ldap_test.go
index 1148b3ad39..2d69dfcfd7 100644
--- a/tests/integration/auth_ldap_test.go
+++ b/tests/integration/auth_ldap_test.go
@@ -309,7 +309,7 @@ func TestLDAPUserSyncWithGroupFilter(t *testing.T) {
// all groups the user is a member of, the user filter is modified accordingly inside
// the addAuthSourceLDAP based on the value of the groupFilter
u := otherLDAPUsers[0]
- testLoginFailed(t, u.UserName, u.Password, translation.NewLocale("en-US").Tr("form.username_password_incorrect"))
+ testLoginFailed(t, u.UserName, u.Password, translation.NewLocale("en-US").TrString("form.username_password_incorrect"))
auth.SyncExternalUsers(context.Background(), true)
@@ -362,7 +362,7 @@ func TestLDAPUserSigninFailed(t *testing.T) {
addAuthSourceLDAP(t, "", "")
u := otherLDAPUsers[0]
- testLoginFailed(t, u.UserName, u.Password, translation.NewLocale("en-US").Tr("form.username_password_incorrect"))
+ testLoginFailed(t, u.UserName, u.Password, translation.NewLocale("en-US").TrString("form.username_password_incorrect"))
}
func TestLDAPUserSSHKeySync(t *testing.T) {
diff --git a/tests/integration/branches_test.go b/tests/integration/branches_test.go
index 99d7eef706..e148fe2d6f 100644
--- a/tests/integration/branches_test.go
+++ b/tests/integration/branches_test.go
@@ -37,7 +37,7 @@ func TestUndoDeleteBranch(t *testing.T) {
htmlDoc, name := branchAction(t, ".restore-branch-button")
assert.Contains(t,
htmlDoc.doc.Find(".ui.positive.message").Text(),
- translation.NewLocale("en-US").Tr("repo.branch.restore_success", name),
+ translation.NewLocale("en-US").TrString("repo.branch.restore_success", name),
)
})
}
@@ -46,7 +46,7 @@ func deleteBranch(t *testing.T) {
htmlDoc, name := branchAction(t, ".delete-branch-button")
assert.Contains(t,
htmlDoc.doc.Find(".ui.positive.message").Text(),
- translation.NewLocale("en-US").Tr("repo.branch.deletion_success", name),
+ translation.NewLocale("en-US").TrString("repo.branch.deletion_success", name),
)
}
diff --git a/tests/integration/pull_merge_test.go b/tests/integration/pull_merge_test.go
index 5205df2f8e..a04b4c98cd 100644
--- a/tests/integration/pull_merge_test.go
+++ b/tests/integration/pull_merge_test.go
@@ -219,7 +219,7 @@ func TestCantMergeWorkInProgress(t *testing.T) {
text := strings.TrimSpace(htmlDoc.doc.Find(".merge-section > .item").Last().Text())
assert.NotEmpty(t, text, "Can't find WIP text")
- assert.Contains(t, text, translation.NewLocale("en-US").Tr("repo.pulls.cannot_merge_work_in_progress"), "Unable to find WIP text")
+ assert.Contains(t, text, translation.NewLocale("en-US").TrString("repo.pulls.cannot_merge_work_in_progress"), "Unable to find WIP text")
assert.Contains(t, text, "[wip]", "Unable to find WIP text")
})
}
diff --git a/tests/integration/release_test.go b/tests/integration/release_test.go
index 42d0d00e78..04de0c123f 100644
--- a/tests/integration/release_test.go
+++ b/tests/integration/release_test.go
@@ -86,7 +86,7 @@ func TestCreateRelease(t *testing.T) {
session := loginUser(t, "user2")
createNewRelease(t, session, "/user2/repo1", "v0.0.1", "v0.0.1", false, false)
- checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", translation.NewLocale("en-US").Tr("repo.release.stable"), 4)
+ checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", translation.NewLocale("en-US").TrString("repo.release.stable"), 4)
}
func TestCreateReleasePreRelease(t *testing.T) {
@@ -95,7 +95,7 @@ func TestCreateReleasePreRelease(t *testing.T) {
session := loginUser(t, "user2")
createNewRelease(t, session, "/user2/repo1", "v0.0.1", "v0.0.1", true, false)
- checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", translation.NewLocale("en-US").Tr("repo.release.prerelease"), 4)
+ checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", translation.NewLocale("en-US").TrString("repo.release.prerelease"), 4)
}
func TestCreateReleaseDraft(t *testing.T) {
@@ -104,7 +104,7 @@ func TestCreateReleaseDraft(t *testing.T) {
session := loginUser(t, "user2")
createNewRelease(t, session, "/user2/repo1", "v0.0.1", "v0.0.1", false, true)
- checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", translation.NewLocale("en-US").Tr("repo.release.draft"), 4)
+ checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", translation.NewLocale("en-US").TrString("repo.release.draft"), 4)
}
func TestCreateReleasePaging(t *testing.T) {
@@ -124,11 +124,11 @@ func TestCreateReleasePaging(t *testing.T) {
}
createNewRelease(t, session, "/user2/repo1", "v0.0.12", "v0.0.12", false, true)
- checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.12", translation.NewLocale("en-US").Tr("repo.release.draft"), 10)
+ checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.12", translation.NewLocale("en-US").TrString("repo.release.draft"), 10)
// Check that user4 does not see draft and still see 10 latest releases
session2 := loginUser(t, "user4")
- checkLatestReleaseAndCount(t, session2, "/user2/repo1", "v0.0.11", translation.NewLocale("en-US").Tr("repo.release.stable"), 10)
+ checkLatestReleaseAndCount(t, session2, "/user2/repo1", "v0.0.11", translation.NewLocale("en-US").TrString("repo.release.stable"), 10)
}
func TestViewReleaseListNoLogin(t *testing.T) {
diff --git a/tests/integration/repo_branch_test.go b/tests/integration/repo_branch_test.go
index 91674ddc82..baa8da4b75 100644
--- a/tests/integration/repo_branch_test.go
+++ b/tests/integration/repo_branch_test.go
@@ -52,37 +52,37 @@ func testCreateBranches(t *testing.T, giteaURL *url.URL) {
OldRefSubURL: "branch/master",
NewBranch: "feature/test1",
ExpectedStatus: http.StatusSeeOther,
- FlashMessage: translation.NewLocale("en-US").Tr("repo.branch.create_success", "feature/test1"),
+ FlashMessage: translation.NewLocale("en-US").TrString("repo.branch.create_success", "feature/test1"),
},
{
OldRefSubURL: "branch/master",
NewBranch: "",
ExpectedStatus: http.StatusSeeOther,
- FlashMessage: translation.NewLocale("en-US").Tr("form.NewBranchName") + translation.NewLocale("en-US").Tr("form.require_error"),
+ FlashMessage: translation.NewLocale("en-US").TrString("form.NewBranchName") + translation.NewLocale("en-US").TrString("form.require_error"),
},
{
OldRefSubURL: "branch/master",
NewBranch: "feature=test1",
ExpectedStatus: http.StatusSeeOther,
- FlashMessage: translation.NewLocale("en-US").Tr("repo.branch.create_success", "feature=test1"),
+ FlashMessage: translation.NewLocale("en-US").TrString("repo.branch.create_success", "feature=test1"),
},
{
OldRefSubURL: "branch/master",
NewBranch: strings.Repeat("b", 101),
ExpectedStatus: http.StatusSeeOther,
- FlashMessage: translation.NewLocale("en-US").Tr("form.NewBranchName") + translation.NewLocale("en-US").Tr("form.max_size_error", "100"),
+ FlashMessage: translation.NewLocale("en-US").TrString("form.NewBranchName") + translation.NewLocale("en-US").TrString("form.max_size_error", "100"),
},
{
OldRefSubURL: "branch/master",
NewBranch: "master",
ExpectedStatus: http.StatusSeeOther,
- FlashMessage: translation.NewLocale("en-US").Tr("repo.branch.branch_already_exists", "master"),
+ FlashMessage: translation.NewLocale("en-US").TrString("repo.branch.branch_already_exists", "master"),
},
{
OldRefSubURL: "branch/master",
NewBranch: "master/test",
ExpectedStatus: http.StatusSeeOther,
- FlashMessage: translation.NewLocale("en-US").Tr("repo.branch.branch_name_conflict", "master/test", "master"),
+ FlashMessage: translation.NewLocale("en-US").TrString("repo.branch.branch_name_conflict", "master/test", "master"),
},
{
OldRefSubURL: "commit/acd1d892867872cb47f3993468605b8aa59aa2e0",
@@ -93,21 +93,21 @@ func testCreateBranches(t *testing.T, giteaURL *url.URL) {
OldRefSubURL: "commit/65f1bf27bc3bf70f64657658635e66094edbcb4d",
NewBranch: "feature/test3",
ExpectedStatus: http.StatusSeeOther,
- FlashMessage: translation.NewLocale("en-US").Tr("repo.branch.create_success", "feature/test3"),
+ FlashMessage: translation.NewLocale("en-US").TrString("repo.branch.create_success", "feature/test3"),
},
{
OldRefSubURL: "branch/master",
NewBranch: "v1.0.0",
CreateRelease: "v1.0.0",
ExpectedStatus: http.StatusSeeOther,
- FlashMessage: translation.NewLocale("en-US").Tr("repo.branch.tag_collision", "v1.0.0"),
+ FlashMessage: translation.NewLocale("en-US").TrString("repo.branch.tag_collision", "v1.0.0"),
},
{
OldRefSubURL: "tag/v1.0.0",
NewBranch: "feature/test4",
CreateRelease: "v1.0.1",
ExpectedStatus: http.StatusSeeOther,
- FlashMessage: translation.NewLocale("en-US").Tr("repo.branch.create_success", "feature/test4"),
+ FlashMessage: translation.NewLocale("en-US").TrString("repo.branch.create_success", "feature/test4"),
},
}
for _, test := range tests {
diff --git a/tests/integration/signin_test.go b/tests/integration/signin_test.go
index 2584b88f65..77e19bba96 100644
--- a/tests/integration/signin_test.go
+++ b/tests/integration/signin_test.go
@@ -49,10 +49,10 @@ func TestSignin(t *testing.T) {
password string
message string
}{
- {username: "wrongUsername", password: "wrongPassword", message: translation.NewLocale("en-US").Tr("form.username_password_incorrect")},
- {username: "wrongUsername", password: "password", message: translation.NewLocale("en-US").Tr("form.username_password_incorrect")},
- {username: "user15", password: "wrongPassword", message: translation.NewLocale("en-US").Tr("form.username_password_incorrect")},
- {username: "user1@example.com", password: "wrongPassword", message: translation.NewLocale("en-US").Tr("form.username_password_incorrect")},
+ {username: "wrongUsername", password: "wrongPassword", message: translation.NewLocale("en-US").TrString("form.username_password_incorrect")},
+ {username: "wrongUsername", password: "password", message: translation.NewLocale("en-US").TrString("form.username_password_incorrect")},
+ {username: "user15", password: "wrongPassword", message: translation.NewLocale("en-US").TrString("form.username_password_incorrect")},
+ {username: "user1@example.com", password: "wrongPassword", message: translation.NewLocale("en-US").TrString("form.username_password_incorrect")},
}
for _, s := range samples {
diff --git a/tests/integration/signup_test.go b/tests/integration/signup_test.go
index f983f98ad8..859f873f85 100644
--- a/tests/integration/signup_test.go
+++ b/tests/integration/signup_test.go
@@ -68,9 +68,9 @@ func TestSignupEmail(t *testing.T) {
wantStatus int
wantMsg string
}{
- {"exampleUser@example.com\r\n", http.StatusOK, translation.NewLocale("en-US").Tr("form.email_invalid")},
- {"exampleUser@example.com\r", http.StatusOK, translation.NewLocale("en-US").Tr("form.email_invalid")},
- {"exampleUser@example.com\n", http.StatusOK, translation.NewLocale("en-US").Tr("form.email_invalid")},
+ {"exampleUser@example.com\r\n", http.StatusOK, translation.NewLocale("en-US").TrString("form.email_invalid")},
+ {"exampleUser@example.com\r", http.StatusOK, translation.NewLocale("en-US").TrString("form.email_invalid")},
+ {"exampleUser@example.com\n", http.StatusOK, translation.NewLocale("en-US").TrString("form.email_invalid")},
{"exampleUser@example.com", http.StatusSeeOther, ""},
}
diff --git a/tests/integration/user_test.go b/tests/integration/user_test.go
index d8e4c64e85..c30733b1b0 100644
--- a/tests/integration/user_test.go
+++ b/tests/integration/user_test.go
@@ -85,7 +85,7 @@ func TestRenameInvalidUsername(t *testing.T) {
htmlDoc := NewHTMLParser(t, resp.Body)
assert.Contains(t,
htmlDoc.doc.Find(".ui.negative.message").Text(),
- translation.NewLocale("en-US").Tr("form.username_error"),
+ translation.NewLocale("en-US").TrString("form.username_error"),
)
unittest.AssertNotExistsBean(t, &user_model.User{Name: invalidUsername})
@@ -147,7 +147,7 @@ func TestRenameReservedUsername(t *testing.T) {
htmlDoc := NewHTMLParser(t, resp.Body)
assert.Contains(t,
htmlDoc.doc.Find(".ui.negative.message").Text(),
- translation.NewLocale("en-US").Tr("user.form.name_reserved", reservedUsername),
+ translation.NewLocale("en-US").TrString("user.form.name_reserved", reservedUsername),
)
unittest.AssertNotExistsBean(t, &user_model.User{Name: reservedUsername})