Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor i18n, use Locale to provide i18n/translation related functions #18648

Merged
merged 10 commits into from Feb 8, 2022
9 changes: 0 additions & 9 deletions modules/context/context.go
Expand Up @@ -38,7 +38,6 @@ import (
"gitea.com/go-chi/session"
chi "github.com/go-chi/chi/v5"
"github.com/unknwon/com"
"github.com/unknwon/i18n"
"github.com/unrolled/render"
"golang.org/x/crypto/pbkdf2"
)
Expand Down Expand Up @@ -738,15 +737,7 @@ func Contexter() func(next http.Handler) http.Handler {
ctx.Data["UnitProjectsGlobalDisabled"] = unit.TypeProjects.UnitGlobalDisabled()

ctx.Data["i18n"] = locale
ctx.Data["Tr"] = i18n.Tr
ctx.Data["Lang"] = locale.Language()
ctx.Data["AllLangs"] = translation.AllLangs()
for _, lang := range translation.AllLangs() {
if lang.Lang == locale.Language() {
ctx.Data["LangName"] = lang.Name
break
}
}

next.ServeHTTP(ctx.Resp, ctx.Req)

Expand Down
38 changes: 28 additions & 10 deletions modules/translation/translation.go
Expand Up @@ -25,17 +25,18 @@ type Locale interface {

// LangType represents a lang type
type LangType struct {
Copy link
Contributor

@zeripath zeripath Feb 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a crazy idea here but can't we unify this with type locale?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's feasible, and we could make a better locale struct.

In fact I had a plan to refactor all {{TimeSince .StartTime $.i18n.Lang}} to {{i18nUtil.TimeSince .StartTime}} to make code more simple and clear.

Lang, Name string
Lang, Name string // these fields is used directly in templates: {{range .AllLangs}}{{.Lang}}{{.Name}}{{end}}
wxiaoguang marked this conversation as resolved.
Show resolved Hide resolved
}

var (
matcher language.Matcher
allLangs []LangType
allLangs []*LangType
allLangMap map[string]*LangType
supportedTags []language.Tag
)

// AllLangs returns all supported languages sorted by name
func AllLangs() []LangType {
func AllLangs() []*LangType {
return allLangs
}

Expand Down Expand Up @@ -81,14 +82,17 @@ func InitLocales() {
}
i18n.SetDefaultLang("en-US")

allLangs = make([]LangType, 0, i18n.Count()-1)
allLangs = make([]*LangType, 0, i18n.Count())
allLangMap = map[string]*LangType{}
langs := i18n.ListLangs()
names := i18n.ListLangDescs()
descs := i18n.ListLangDescs()
for i, v := range langs {
allLangs = append(allLangs, LangType{v, names[i]})
l := &LangType{v, descs[i]}
allLangs = append(allLangs, l)
allLangMap[v] = l
}

// Sort languages case insensitive according to their name - needed for the user settings
// Sort languages case-insensitive according to their name - needed for the user settings
sort.Slice(allLangs, func(i, j int) bool {
return strings.ToLower(allLangs[i].Name) < strings.ToLower(allLangs[j].Name)
})
Expand All @@ -102,13 +106,18 @@ func Match(tags ...language.Tag) language.Tag {

// locale represents the information of localization.
type locale struct {
Lang string
Lang, LangName string // these fields is used directly in templates: .i18n.Lang
wxiaoguang marked this conversation as resolved.
Show resolved Hide resolved
}

// NewLocale return a locale
func NewLocale(lang string) Locale {
langName := "unknown"
if l, ok := allLangMap[lang]; ok {
langName = l.Name
}
return &locale{
Lang: lang,
Lang: lang,
LangName: langName,
}
}

Expand All @@ -118,7 +127,16 @@ func (l *locale) Language() string {

// Tr translates content to target language.
func (l *locale) Tr(format string, args ...interface{}) string {
return i18n.Tr(l.Lang, format, args...)
if setting.IsProd {
return i18n.Tr(l.Lang, format, args...)
}

// in development, we should show an error if a translation key is missing
s, ok := TryTr(l.Lang, format, args...)
if !ok {
log.Error("untranslated i18n translation key: %q", format)
wxiaoguang marked this conversation as resolved.
Show resolved Hide resolved
}
return s
}

// Language specific rules for translating plural texts
Expand Down
11 changes: 1 addition & 10 deletions routers/install/install.go
Expand Up @@ -71,25 +71,16 @@ func Init(next http.Handler) http.Handler {
Render: rnd,
Session: session.GetSession(req),
Data: map[string]interface{}{
"i18n": locale,
"Title": locale.Tr("install.install"),
"PageIsInstall": true,
"DbTypeNames": getDbTypeNames(),
"i18n": locale,
"Language": locale.Language(),
"Lang": locale.Language(),
"AllLangs": translation.AllLangs(),
"CurrentURL": setting.AppSubURL + req.URL.RequestURI(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this removal intended? There are still other places which set it and head_navbar.tmpl uses it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The install page do not need it, I have searched the code base.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

install.tmpl only includes head.tmpl, which says:

		{{if not .PageIsInstall}}
			<div class="ui top secondary stackable main menu following bar light">
				{{template "base/head_navbar" .}}
			</div><!-- end bar -->
		{{end}}

"PageStartTime": startTime,

"PasswordHashAlgorithms": user_model.AvailableHashAlgorithms,
},
}
for _, lang := range translation.AllLangs() {
if lang.Lang == locale.Language() {
ctx.Data["LangName"] = lang.Name
break
}
}
ctx.Req = context.WithContext(req, &ctx)
next.ServeHTTP(resp, ctx.Req)
})
Expand Down
2 changes: 1 addition & 1 deletion routers/web/repo/blame.go
Expand Up @@ -255,7 +255,7 @@ func renderBlame(ctx *context.Context, blameParts []git.BlamePart, commitNames m
commitCnt++

// User avatar image
commitSince := timeutil.TimeSinceUnix(timeutil.TimeStamp(commit.Author.When.Unix()), ctx.Data["Lang"].(string))
commitSince := timeutil.TimeSinceUnix(timeutil.TimeStamp(commit.Author.When.Unix()), ctx.Locale.Language())

var avatar string
if commit.User != nil {
Expand Down
10 changes: 5 additions & 5 deletions routers/web/repo/issue_content_history.go
Expand Up @@ -29,7 +29,7 @@ func GetContentHistoryOverview(ctx *context.Context) {
return
}

lang := ctx.Data["Lang"].(string)
lang := ctx.Locale.Language()
editedHistoryCountMap, _ := issuesModel.QueryIssueContentHistoryEditedCountMap(db.DefaultContext, issue.ID)
ctx.JSON(http.StatusOK, map[string]interface{}{
"i18n": map[string]interface{}{
Expand All @@ -55,17 +55,17 @@ func GetContentHistoryList(ctx *context.Context) {
// render history list to HTML for frontend dropdown items: (name, value)
// name is HTML of "avatar + userName + userAction + timeSince"
// value is historyId
lang := ctx.Data["Lang"].(string)
lang := ctx.Locale.Language()
var results []map[string]interface{}
for _, item := range items {
var actionText string
if item.IsDeleted {
actionTextDeleted := i18n.Tr(lang, "repo.issues.content_history.deleted")
actionTextDeleted := ctx.Locale.Tr("repo.issues.content_history.deleted")
actionText = "<i data-history-is-deleted='1'>" + actionTextDeleted + "</i>"
} else if item.IsFirstCreated {
actionText = i18n.Tr(lang, "repo.issues.content_history.created")
actionText = ctx.Locale.Tr("repo.issues.content_history.created")
} else {
actionText = i18n.Tr(lang, "repo.issues.content_history.edited")
actionText = ctx.Locale.Tr("repo.issues.content_history.edited")
}
timeSinceText := timeutil.TimeSinceUnix(item.EditedUnix, lang)
results = append(results, map[string]interface{}{
Expand Down
2 changes: 1 addition & 1 deletion templates/admin/process-row.tmpl
Expand Up @@ -2,7 +2,7 @@
<div class="df ac">
<div class="content f1">
<div class="header">{{.Process.Description}}</div>
<div class="description"><span title="{{DateFmtLong .Process.Start}}">{{TimeSince .Process.Start .root.Lang}}</span></div>
<div class="description"><span title="{{DateFmtLong .Process.Start}}">{{TimeSince .Process.Start .root.i18n.Lang}}</span></div>
</div>
<div>
<a class="delete-button icon" href="" data-url="{{.root.Link}}/cancel/{{.Process.PID}}" data-id="{{.Process.PID}}" data-name="{{.Process.Description}}">{{svg "octicon-trash" 16 "text-red"}}</a>
Expand Down
4 changes: 2 additions & 2 deletions templates/base/footer_content.tmpl
Expand Up @@ -9,10 +9,10 @@
{{end}}
<div class="ui language bottom floating slide up dropdown link item">
{{svg "octicon-globe"}}
<div class="text">{{.LangName}}</div>
<div class="text">{{.i18n.LangName}}</div>
<div class="menu language-menu">
{{range .AllLangs}}
<a lang="{{.Lang}}" data-url="{{AppSubUrl}}/?lang={{.Lang}}" class="item {{if eq $.Lang .Lang}}active selected{{end}}">{{.Name}}</a>
<a lang="{{.Lang}}" data-url="{{AppSubUrl}}/?lang={{.Lang}}" class="item {{if eq $.i18n.Lang .Lang}}active selected{{end}}">{{.Name}}</a>
{{end}}
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion templates/base/head.tmpl
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="{{.Lang}}" class="theme-{{.SignedUser.Theme}}">
<html lang="{{.i18n.Lang}}" class="theme-{{.SignedUser.Theme}}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
Expand Down
12 changes: 6 additions & 6 deletions templates/repo/activity.tmpl
Expand Up @@ -131,7 +131,7 @@
{{if not .IsTag}}
<a class="title" href="{{$.RepoLink}}/src/{{.TagName | PathEscapeSegments}}">{{.Title | RenderEmoji}}</a>
{{end}}
{{TimeSinceUnix .CreatedUnix $.Lang}}
{{TimeSinceUnix .CreatedUnix $.i18n.Lang}}
</p>
{{end}}
</div>
Expand All @@ -150,7 +150,7 @@
<p class="desc">
<span class="ui purple label">{{$.i18n.Tr "repo.activity.merged_prs_label"}}</span>
#{{.Index}} <a class="title" href="{{$.RepoLink}}/pulls/{{.Index}}">{{.Issue.Title | RenderEmoji}}</a>
{{TimeSinceUnix .MergedUnix $.Lang}}
{{TimeSinceUnix .MergedUnix $.i18n.Lang}}
</p>
{{end}}
</div>
Expand All @@ -169,7 +169,7 @@
<p class="desc">
<span class="ui green label">{{$.i18n.Tr "repo.activity.opened_prs_label"}}</span>
#{{.Index}} <a class="title" href="{{$.RepoLink}}/pulls/{{.Index}}">{{.Issue.Title | RenderEmoji}}</a>
{{TimeSinceUnix .Issue.CreatedUnix $.Lang}}
{{TimeSinceUnix .Issue.CreatedUnix $.i18n.Lang}}
</p>
{{end}}
</div>
Expand All @@ -188,7 +188,7 @@
<p class="desc">
<span class="ui red label">{{$.i18n.Tr "repo.activity.closed_issue_label"}}</span>
#{{.Index}} <a class="title" href="{{$.RepoLink}}/issues/{{.Index}}">{{.Title | RenderEmoji}}</a>
{{TimeSinceUnix .ClosedUnix $.Lang}}
{{TimeSinceUnix .ClosedUnix $.i18n.Lang}}
</p>
{{end}}
</div>
Expand All @@ -207,7 +207,7 @@
<p class="desc">
<span class="ui green label">{{$.i18n.Tr "repo.activity.new_issue_label"}}</span>
#{{.Index}} <a class="title" href="{{$.RepoLink}}/issues/{{.Index}}">{{.Title | RenderEmoji}}</a>
{{TimeSinceUnix .CreatedUnix $.Lang}}
{{TimeSinceUnix .CreatedUnix $.i18n.Lang}}
</p>
{{end}}
</div>
Expand All @@ -231,7 +231,7 @@
{{else}}
<a class="title" href="{{$.RepoLink}}/issues/{{.Index}}">{{.Title | RenderEmoji}}</a>
{{end}}
{{TimeSinceUnix .UpdatedUnix $.Lang}}
{{TimeSinceUnix .UpdatedUnix $.i18n.Lang}}
</p>
{{end}}
</div>
Expand Down
4 changes: 2 additions & 2 deletions templates/repo/commit_page.tmpl
Expand Up @@ -47,7 +47,7 @@
{{avatarByEmail .Commit.Author.Email .Commit.Author.Email 28 "mr-3"}}
<strong>{{.Commit.Author.Name}}</strong>
{{end}}
<span class="text grey ml-3" id="authored-time">{{TimeSince .Commit.Author.When $.Lang}}</span>
<span class="text grey ml-3" id="authored-time">{{TimeSince .Commit.Author.When $.i18n.Lang}}</span>
{{if or (ne .Commit.Committer.Name .Commit.Author.Name) (ne .Commit.Committer.Email .Commit.Author.Email)}}
<span class="text grey mx-3">{{.i18n.Tr "repo.diff.committed_by"}}</span>
{{if ne .Verification.CommittingUser.ID 0}}
Expand Down Expand Up @@ -169,7 +169,7 @@
{{else}}
<strong>{{.NoteCommit.Author.Name}}</strong>
{{end}}
<span class="text grey" id="note-authored-time">{{TimeSince .NoteCommit.Author.When $.Lang}}</span>
<span class="text grey" id="note-authored-time">{{TimeSince .NoteCommit.Author.When $.i18n.Lang}}</span>
</div>
<div class="ui bottom attached info segment git-notes">
<pre class="commit-body">{{RenderNote $.Context .Note $.RepoLink $.Repository.ComposeMetas}}</pre>
Expand Down
4 changes: 2 additions & 2 deletions templates/repo/commits_list.tmpl
Expand Up @@ -76,9 +76,9 @@
{{end}}
</td>
{{if .Committer}}
<td class="text right aligned">{{TimeSince .Committer.When $.Lang}}</td>
<td class="text right aligned">{{TimeSince .Committer.When $.i18n.Lang}}</td>
{{else}}
<td class="text right aligned">{{TimeSince .Author.When $.Lang}}</td>
<td class="text right aligned">{{TimeSince .Author.When $.i18n.Lang}}</td>
{{end}}
</tr>
{{end}}
Expand Down
2 changes: 1 addition & 1 deletion templates/repo/diff/comments.tmpl
@@ -1,6 +1,6 @@
{{range .comments}}

{{ $createdStr:= TimeSinceUnix .CreatedUnix $.root.Lang }}
{{ $createdStr:= TimeSinceUnix .CreatedUnix $.root.i18n.Lang }}
<div class="comment" id="{{.HashTag}}">
{{if .OriginalAuthor }}
<span class="avatar"><img src="{{AppSubUrl}}/assets/img/avatar_default.png"></span>
Expand Down
2 changes: 1 addition & 1 deletion templates/repo/issue/milestone_issues.tmpl
Expand Up @@ -22,7 +22,7 @@
</div>
<div class="ui one column stackable grid">
<div class="column">
{{ $closedDate:= TimeSinceUnix .Milestone.ClosedDateUnix $.Lang }}
{{ $closedDate:= TimeSinceUnix .Milestone.ClosedDateUnix $.i18n.Lang }}
{{if .IsClosed}}
{{svg "octicon-clock"}} {{$.i18n.Tr "repo.milestones.closed" $closedDate|Str2html}}
{{else}}
Expand Down
2 changes: 1 addition & 1 deletion templates/repo/issue/milestones.tmpl
Expand Up @@ -68,7 +68,7 @@
</div>
</div>
<div class="meta">
{{ $closedDate:= TimeSinceUnix .ClosedDateUnix $.Lang }}
{{ $closedDate:= TimeSinceUnix .ClosedDateUnix $.i18n.Lang }}
{{if .IsClosed}}
{{svg "octicon-clock"}} {{$.i18n.Tr "repo.milestones.closed" $closedDate|Str2html}}
{{else}}
Expand Down
2 changes: 1 addition & 1 deletion templates/repo/issue/view_content.tmpl
Expand Up @@ -15,7 +15,7 @@
<input type="hidden" id="issueIndex" value="{{.Issue.Index}}"/>
<input type="hidden" id="type" value="{{.IssueType}}">

{{ $createdStr:= TimeSinceUnix .Issue.CreatedUnix $.Lang }}
{{ $createdStr:= TimeSinceUnix .Issue.CreatedUnix $.i18n.Lang }}
<div class="twelve wide column comment-list prevent-before-timeline">
<ui class="ui timeline">
<div id="{{.Issue.HashTag}}" class="timeline-item comment first">
Expand Down
6 changes: 3 additions & 3 deletions templates/repo/issue/view_content/comments.tmpl
@@ -1,7 +1,7 @@
{{ template "base/alert" }}
{{range .Issue.Comments}}
{{if call $.ShouldShowCommentType .Type}}
{{ $createdStr:= TimeSinceUnix .CreatedUnix $.Lang }}
{{ $createdStr:= TimeSinceUnix .CreatedUnix $.i18n.Lang }}

<!-- 0 = COMMENT, 1 = REOPEN, 2 = CLOSE, 3 = ISSUE_REF, 4 = COMMIT_REF,
5 = COMMENT_REF, 6 = PULL_REF, 7 = COMMENT_LABEL, 12 = START_TRACKING,
Expand Down Expand Up @@ -146,7 +146,7 @@
{{else if eq .RefAction 2 }}
{{ $refTr = "repo.issues.ref_reopening_from" }}
{{end}}
{{ $createdStr:= TimeSinceUnix .CreatedUnix $.Lang }}
{{ $createdStr:= TimeSinceUnix .CreatedUnix $.i18n.Lang }}
<div class="timeline-item event" id="{{.HashTag}}">
<span class="badge">{{svg "octicon-bookmark"}}</span>
<a href="{{.Poster.HomeLink}}">
Expand Down Expand Up @@ -557,7 +557,7 @@
<div id="code-comments-{{(index $comms 0).ID}}" class="comment-code-cloud ui segment{{if $resolved}} hide{{end}}">
<div class="ui comments mb-0">
{{range $comms}}
{{ $createdSubStr:= TimeSinceUnix .CreatedUnix $.Lang }}
{{ $createdSubStr:= TimeSinceUnix .CreatedUnix $.i18n.Lang }}
<div class="comment code-comment pb-4" id="{{.HashTag}}">
<div class="content">
<div class="header comment-header">
Expand Down
4 changes: 2 additions & 2 deletions templates/repo/issue/view_content/pull.tmpl
Expand Up @@ -4,7 +4,7 @@
<div class="ui segment">
<h4>{{$.i18n.Tr "repo.issues.review.reviewers"}}</h4>
{{range .PullReviewers}}
{{ $createdStr:= TimeSinceUnix .Review.UpdatedUnix $.Lang }}
{{ $createdStr:= TimeSinceUnix .Review.UpdatedUnix $.i18n.Lang }}
<div class="ui divider"></div>
<div class="review-item">
<div class="review-item-left">
Expand Down Expand Up @@ -82,7 +82,7 @@
</div>
{{end}}
{{range .OriginalReviews}}
{{ $createdStr:= TimeSinceUnix .UpdatedUnix $.Lang }}
{{ $createdStr:= TimeSinceUnix .UpdatedUnix $.i18n.Lang }}
<div class="ui divider"></div>
<div class="review-item">
<div class="review-item-left">
Expand Down
4 changes: 2 additions & 2 deletions templates/repo/issue/view_title.tmpl
Expand Up @@ -40,7 +40,7 @@
{{$baseHref = printf "<a href=\"%s\">%s</a>" (.BaseBranchHTMLURL | Escape) $baseHref}}
{{end}}
{{if .Issue.PullRequest.HasMerged}}
{{ $mergedStr:= TimeSinceUnix .Issue.PullRequest.MergedUnix $.Lang }}
{{ $mergedStr:= TimeSinceUnix .Issue.PullRequest.MergedUnix $.i18n.Lang }}
{{if .Issue.OriginalAuthor }}
{{.Issue.OriginalAuthor}}
<span class="pull-desc">{{$.i18n.Tr "repo.pulls.merged_title_desc" .NumCommits $headHref $baseHref $mergedStr | Safe}}</span>
Expand Down Expand Up @@ -88,7 +88,7 @@
</span>
{{end}}
{{else}}
{{ $createdStr:= TimeSinceUnix .Issue.CreatedUnix $.Lang }}
{{ $createdStr:= TimeSinceUnix .Issue.CreatedUnix $.i18n.Lang }}
<span class="time-desc">
{{if .Issue.OriginalAuthor }}
{{$.i18n.Tr "repo.issues.opened_by_fake" $createdStr (.Issue.OriginalAuthor|Escape) | Safe}}
Expand Down
2 changes: 1 addition & 1 deletion templates/repo/projects/list.tmpl
Expand Up @@ -42,7 +42,7 @@
<li class="item">
{{svg "octicon-project"}} <a href="{{$.RepoLink}}/projects/{{.ID}}">{{.Title}}</a>
<div class="meta">
{{ $closedDate:= TimeSinceUnix .ClosedDateUnix $.Lang }}
{{ $closedDate:= TimeSinceUnix .ClosedDateUnix $.i18n.Lang }}
{{if .IsClosed }}
{{svg "octicon-clock"}} {{$.i18n.Tr "repo.milestones.closed" $closedDate|Str2html}}
{{end}}
Expand Down