Refactor i18n, use Locale to provide i18n/translation related functions (#18648)
* remove unnecessary web context data fields, and unify the i18n/translation related functions to `Locale` * in development, show an error if a translation key is missing * remove the unnecessary loops `for _, lang := range translation.AllLangs()` for every request, which improves the performance slightly * use `ctx.Locale.Language()` instead of `ctx.Data["Lang"].(string)` * add more comments about how the Locale/LangType fields are used
This commit is contained in:
parent
7b25a010c8
commit
a60e8be8d1
|
@ -38,7 +38,6 @@ import (
|
||||||
"gitea.com/go-chi/session"
|
"gitea.com/go-chi/session"
|
||||||
chi "github.com/go-chi/chi/v5"
|
chi "github.com/go-chi/chi/v5"
|
||||||
"github.com/unknwon/com"
|
"github.com/unknwon/com"
|
||||||
"github.com/unknwon/i18n"
|
|
||||||
"github.com/unrolled/render"
|
"github.com/unrolled/render"
|
||||||
"golang.org/x/crypto/pbkdf2"
|
"golang.org/x/crypto/pbkdf2"
|
||||||
)
|
)
|
||||||
|
@ -738,15 +737,7 @@ func Contexter() func(next http.Handler) http.Handler {
|
||||||
ctx.Data["UnitProjectsGlobalDisabled"] = unit.TypeProjects.UnitGlobalDisabled()
|
ctx.Data["UnitProjectsGlobalDisabled"] = unit.TypeProjects.UnitGlobalDisabled()
|
||||||
|
|
||||||
ctx.Data["i18n"] = locale
|
ctx.Data["i18n"] = locale
|
||||||
ctx.Data["Tr"] = i18n.Tr
|
|
||||||
ctx.Data["Lang"] = locale.Language()
|
|
||||||
ctx.Data["AllLangs"] = translation.AllLangs()
|
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)
|
next.ServeHTTP(ctx.Resp, ctx.Req)
|
||||||
|
|
||||||
|
|
|
@ -25,17 +25,18 @@ type Locale interface {
|
||||||
|
|
||||||
// LangType represents a lang type
|
// LangType represents a lang type
|
||||||
type LangType struct {
|
type LangType struct {
|
||||||
Lang, Name string
|
Lang, Name string // these fields are used directly in templates: {{range .AllLangs}}{{.Lang}}{{.Name}}{{end}}
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
matcher language.Matcher
|
matcher language.Matcher
|
||||||
allLangs []LangType
|
allLangs []*LangType
|
||||||
|
allLangMap map[string]*LangType
|
||||||
supportedTags []language.Tag
|
supportedTags []language.Tag
|
||||||
)
|
)
|
||||||
|
|
||||||
// AllLangs returns all supported languages sorted by name
|
// AllLangs returns all supported languages sorted by name
|
||||||
func AllLangs() []LangType {
|
func AllLangs() []*LangType {
|
||||||
return allLangs
|
return allLangs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,14 +82,17 @@ func InitLocales() {
|
||||||
}
|
}
|
||||||
i18n.SetDefaultLang("en-US")
|
i18n.SetDefaultLang("en-US")
|
||||||
|
|
||||||
allLangs = make([]LangType, 0, i18n.Count()-1)
|
allLangs = make([]*LangType, 0, i18n.Count())
|
||||||
|
allLangMap = map[string]*LangType{}
|
||||||
langs := i18n.ListLangs()
|
langs := i18n.ListLangs()
|
||||||
names := i18n.ListLangDescs()
|
descs := i18n.ListLangDescs()
|
||||||
for i, v := range langs {
|
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 {
|
sort.Slice(allLangs, func(i, j int) bool {
|
||||||
return strings.ToLower(allLangs[i].Name) < strings.ToLower(allLangs[j].Name)
|
return strings.ToLower(allLangs[i].Name) < strings.ToLower(allLangs[j].Name)
|
||||||
})
|
})
|
||||||
|
@ -102,13 +106,18 @@ func Match(tags ...language.Tag) language.Tag {
|
||||||
|
|
||||||
// locale represents the information of localization.
|
// locale represents the information of localization.
|
||||||
type locale struct {
|
type locale struct {
|
||||||
Lang string
|
Lang, LangName string // these fields are used directly in templates: .i18n.Lang
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLocale return a locale
|
// NewLocale return a locale
|
||||||
func NewLocale(lang string) Locale {
|
func NewLocale(lang string) Locale {
|
||||||
|
langName := "unknown"
|
||||||
|
if l, ok := allLangMap[lang]; ok {
|
||||||
|
langName = l.Name
|
||||||
|
}
|
||||||
return &locale{
|
return &locale{
|
||||||
Lang: lang,
|
Lang: lang,
|
||||||
|
LangName: langName,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,9 +127,18 @@ func (l *locale) Language() string {
|
||||||
|
|
||||||
// Tr translates content to target language.
|
// Tr translates content to target language.
|
||||||
func (l *locale) Tr(format string, args ...interface{}) string {
|
func (l *locale) Tr(format string, args ...interface{}) string {
|
||||||
|
if setting.IsProd {
|
||||||
return i18n.Tr(l.Lang, format, args...)
|
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("missing i18n translation key: %q", format)
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
// Language specific rules for translating plural texts
|
// Language specific rules for translating plural texts
|
||||||
var trNLangRules = map[string]func(int64) int{
|
var trNLangRules = map[string]func(int64) int{
|
||||||
// the default rule is "en-US" if a language isn't listed here
|
// the default rule is "en-US" if a language isn't listed here
|
||||||
|
|
|
@ -71,25 +71,16 @@ func Init(next http.Handler) http.Handler {
|
||||||
Render: rnd,
|
Render: rnd,
|
||||||
Session: session.GetSession(req),
|
Session: session.GetSession(req),
|
||||||
Data: map[string]interface{}{
|
Data: map[string]interface{}{
|
||||||
|
"i18n": locale,
|
||||||
"Title": locale.Tr("install.install"),
|
"Title": locale.Tr("install.install"),
|
||||||
"PageIsInstall": true,
|
"PageIsInstall": true,
|
||||||
"DbTypeNames": getDbTypeNames(),
|
"DbTypeNames": getDbTypeNames(),
|
||||||
"i18n": locale,
|
|
||||||
"Language": locale.Language(),
|
|
||||||
"Lang": locale.Language(),
|
|
||||||
"AllLangs": translation.AllLangs(),
|
"AllLangs": translation.AllLangs(),
|
||||||
"CurrentURL": setting.AppSubURL + req.URL.RequestURI(),
|
|
||||||
"PageStartTime": startTime,
|
"PageStartTime": startTime,
|
||||||
|
|
||||||
"PasswordHashAlgorithms": user_model.AvailableHashAlgorithms,
|
"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)
|
ctx.Req = context.WithContext(req, &ctx)
|
||||||
next.ServeHTTP(resp, ctx.Req)
|
next.ServeHTTP(resp, ctx.Req)
|
||||||
})
|
})
|
||||||
|
|
|
@ -255,7 +255,7 @@ func renderBlame(ctx *context.Context, blameParts []git.BlamePart, commitNames m
|
||||||
commitCnt++
|
commitCnt++
|
||||||
|
|
||||||
// User avatar image
|
// 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
|
var avatar string
|
||||||
if commit.User != nil {
|
if commit.User != nil {
|
||||||
|
|
|
@ -29,7 +29,7 @@ func GetContentHistoryOverview(ctx *context.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
lang := ctx.Data["Lang"].(string)
|
lang := ctx.Locale.Language()
|
||||||
editedHistoryCountMap, _ := issuesModel.QueryIssueContentHistoryEditedCountMap(db.DefaultContext, issue.ID)
|
editedHistoryCountMap, _ := issuesModel.QueryIssueContentHistoryEditedCountMap(db.DefaultContext, issue.ID)
|
||||||
ctx.JSON(http.StatusOK, map[string]interface{}{
|
ctx.JSON(http.StatusOK, map[string]interface{}{
|
||||||
"i18n": map[string]interface{}{
|
"i18n": map[string]interface{}{
|
||||||
|
@ -55,17 +55,17 @@ func GetContentHistoryList(ctx *context.Context) {
|
||||||
// render history list to HTML for frontend dropdown items: (name, value)
|
// render history list to HTML for frontend dropdown items: (name, value)
|
||||||
// name is HTML of "avatar + userName + userAction + timeSince"
|
// name is HTML of "avatar + userName + userAction + timeSince"
|
||||||
// value is historyId
|
// value is historyId
|
||||||
lang := ctx.Data["Lang"].(string)
|
lang := ctx.Locale.Language()
|
||||||
var results []map[string]interface{}
|
var results []map[string]interface{}
|
||||||
for _, item := range items {
|
for _, item := range items {
|
||||||
var actionText string
|
var actionText string
|
||||||
if item.IsDeleted {
|
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>"
|
actionText = "<i data-history-is-deleted='1'>" + actionTextDeleted + "</i>"
|
||||||
} else if item.IsFirstCreated {
|
} else if item.IsFirstCreated {
|
||||||
actionText = i18n.Tr(lang, "repo.issues.content_history.created")
|
actionText = ctx.Locale.Tr("repo.issues.content_history.created")
|
||||||
} else {
|
} 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)
|
timeSinceText := timeutil.TimeSinceUnix(item.EditedUnix, lang)
|
||||||
results = append(results, map[string]interface{}{
|
results = append(results, map[string]interface{}{
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<div class="df ac">
|
<div class="df ac">
|
||||||
<div class="content f1">
|
<div class="content f1">
|
||||||
<div class="header">{{.Process.Description}}</div>
|
<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>
|
||||||
<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>
|
<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>
|
||||||
|
|
|
@ -9,10 +9,10 @@
|
||||||
{{end}}
|
{{end}}
|
||||||
<div class="ui language bottom floating slide up dropdown link item">
|
<div class="ui language bottom floating slide up dropdown link item">
|
||||||
{{svg "octicon-globe"}}
|
{{svg "octicon-globe"}}
|
||||||
<div class="text">{{.LangName}}</div>
|
<div class="text">{{.i18n.LangName}}</div>
|
||||||
<div class="menu language-menu">
|
<div class="menu language-menu">
|
||||||
{{range .AllLangs}}
|
{{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}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="{{.Lang}}" class="theme-{{.SignedUser.Theme}}">
|
<html lang="{{.i18n.Lang}}" class="theme-{{.SignedUser.Theme}}">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
|
@ -131,7 +131,7 @@
|
||||||
{{if not .IsTag}}
|
{{if not .IsTag}}
|
||||||
<a class="title" href="{{$.RepoLink}}/src/{{.TagName | PathEscapeSegments}}">{{.Title | RenderEmoji}}</a>
|
<a class="title" href="{{$.RepoLink}}/src/{{.TagName | PathEscapeSegments}}">{{.Title | RenderEmoji}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{TimeSinceUnix .CreatedUnix $.Lang}}
|
{{TimeSinceUnix .CreatedUnix $.i18n.Lang}}
|
||||||
</p>
|
</p>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
@ -150,7 +150,7 @@
|
||||||
<p class="desc">
|
<p class="desc">
|
||||||
<span class="ui purple label">{{$.i18n.Tr "repo.activity.merged_prs_label"}}</span>
|
<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>
|
#{{.Index}} <a class="title" href="{{$.RepoLink}}/pulls/{{.Index}}">{{.Issue.Title | RenderEmoji}}</a>
|
||||||
{{TimeSinceUnix .MergedUnix $.Lang}}
|
{{TimeSinceUnix .MergedUnix $.i18n.Lang}}
|
||||||
</p>
|
</p>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
@ -169,7 +169,7 @@
|
||||||
<p class="desc">
|
<p class="desc">
|
||||||
<span class="ui green label">{{$.i18n.Tr "repo.activity.opened_prs_label"}}</span>
|
<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>
|
#{{.Index}} <a class="title" href="{{$.RepoLink}}/pulls/{{.Index}}">{{.Issue.Title | RenderEmoji}}</a>
|
||||||
{{TimeSinceUnix .Issue.CreatedUnix $.Lang}}
|
{{TimeSinceUnix .Issue.CreatedUnix $.i18n.Lang}}
|
||||||
</p>
|
</p>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
@ -188,7 +188,7 @@
|
||||||
<p class="desc">
|
<p class="desc">
|
||||||
<span class="ui red label">{{$.i18n.Tr "repo.activity.closed_issue_label"}}</span>
|
<span class="ui red label">{{$.i18n.Tr "repo.activity.closed_issue_label"}}</span>
|
||||||
#{{.Index}} <a class="title" href="{{$.RepoLink}}/issues/{{.Index}}">{{.Title | RenderEmoji}}</a>
|
#{{.Index}} <a class="title" href="{{$.RepoLink}}/issues/{{.Index}}">{{.Title | RenderEmoji}}</a>
|
||||||
{{TimeSinceUnix .ClosedUnix $.Lang}}
|
{{TimeSinceUnix .ClosedUnix $.i18n.Lang}}
|
||||||
</p>
|
</p>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
@ -207,7 +207,7 @@
|
||||||
<p class="desc">
|
<p class="desc">
|
||||||
<span class="ui green label">{{$.i18n.Tr "repo.activity.new_issue_label"}}</span>
|
<span class="ui green label">{{$.i18n.Tr "repo.activity.new_issue_label"}}</span>
|
||||||
#{{.Index}} <a class="title" href="{{$.RepoLink}}/issues/{{.Index}}">{{.Title | RenderEmoji}}</a>
|
#{{.Index}} <a class="title" href="{{$.RepoLink}}/issues/{{.Index}}">{{.Title | RenderEmoji}}</a>
|
||||||
{{TimeSinceUnix .CreatedUnix $.Lang}}
|
{{TimeSinceUnix .CreatedUnix $.i18n.Lang}}
|
||||||
</p>
|
</p>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
@ -231,7 +231,7 @@
|
||||||
{{else}}
|
{{else}}
|
||||||
<a class="title" href="{{$.RepoLink}}/issues/{{.Index}}">{{.Title | RenderEmoji}}</a>
|
<a class="title" href="{{$.RepoLink}}/issues/{{.Index}}">{{.Title | RenderEmoji}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{TimeSinceUnix .UpdatedUnix $.Lang}}
|
{{TimeSinceUnix .UpdatedUnix $.i18n.Lang}}
|
||||||
</p>
|
</p>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -47,7 +47,7 @@
|
||||||
{{avatarByEmail .Commit.Author.Email .Commit.Author.Email 28 "mr-3"}}
|
{{avatarByEmail .Commit.Author.Email .Commit.Author.Email 28 "mr-3"}}
|
||||||
<strong>{{.Commit.Author.Name}}</strong>
|
<strong>{{.Commit.Author.Name}}</strong>
|
||||||
{{end}}
|
{{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)}}
|
{{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>
|
<span class="text grey mx-3">{{.i18n.Tr "repo.diff.committed_by"}}</span>
|
||||||
{{if ne .Verification.CommittingUser.ID 0}}
|
{{if ne .Verification.CommittingUser.ID 0}}
|
||||||
|
@ -169,7 +169,7 @@
|
||||||
{{else}}
|
{{else}}
|
||||||
<strong>{{.NoteCommit.Author.Name}}</strong>
|
<strong>{{.NoteCommit.Author.Name}}</strong>
|
||||||
{{end}}
|
{{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>
|
||||||
<div class="ui bottom attached info segment git-notes">
|
<div class="ui bottom attached info segment git-notes">
|
||||||
<pre class="commit-body">{{RenderNote $.Context .Note $.RepoLink $.Repository.ComposeMetas}}</pre>
|
<pre class="commit-body">{{RenderNote $.Context .Note $.RepoLink $.Repository.ComposeMetas}}</pre>
|
||||||
|
|
|
@ -76,9 +76,9 @@
|
||||||
{{end}}
|
{{end}}
|
||||||
</td>
|
</td>
|
||||||
{{if .Committer}}
|
{{if .Committer}}
|
||||||
<td class="text right aligned">{{TimeSince .Committer.When $.Lang}}</td>
|
<td class="text right aligned">{{TimeSince .Committer.When $.i18n.Lang}}</td>
|
||||||
{{else}}
|
{{else}}
|
||||||
<td class="text right aligned">{{TimeSince .Author.When $.Lang}}</td>
|
<td class="text right aligned">{{TimeSince .Author.When $.i18n.Lang}}</td>
|
||||||
{{end}}
|
{{end}}
|
||||||
</tr>
|
</tr>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{{range .comments}}
|
{{range .comments}}
|
||||||
|
|
||||||
{{ $createdStr:= TimeSinceUnix .CreatedUnix $.root.Lang }}
|
{{ $createdStr:= TimeSinceUnix .CreatedUnix $.root.i18n.Lang }}
|
||||||
<div class="comment" id="{{.HashTag}}">
|
<div class="comment" id="{{.HashTag}}">
|
||||||
{{if .OriginalAuthor }}
|
{{if .OriginalAuthor }}
|
||||||
<span class="avatar"><img src="{{AppSubUrl}}/assets/img/avatar_default.png"></span>
|
<span class="avatar"><img src="{{AppSubUrl}}/assets/img/avatar_default.png"></span>
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="ui one column stackable grid">
|
<div class="ui one column stackable grid">
|
||||||
<div class="column">
|
<div class="column">
|
||||||
{{ $closedDate:= TimeSinceUnix .Milestone.ClosedDateUnix $.Lang }}
|
{{ $closedDate:= TimeSinceUnix .Milestone.ClosedDateUnix $.i18n.Lang }}
|
||||||
{{if .IsClosed}}
|
{{if .IsClosed}}
|
||||||
{{svg "octicon-clock"}} {{$.i18n.Tr "repo.milestones.closed" $closedDate|Str2html}}
|
{{svg "octicon-clock"}} {{$.i18n.Tr "repo.milestones.closed" $closedDate|Str2html}}
|
||||||
{{else}}
|
{{else}}
|
||||||
|
|
|
@ -68,7 +68,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="meta">
|
<div class="meta">
|
||||||
{{ $closedDate:= TimeSinceUnix .ClosedDateUnix $.Lang }}
|
{{ $closedDate:= TimeSinceUnix .ClosedDateUnix $.i18n.Lang }}
|
||||||
{{if .IsClosed}}
|
{{if .IsClosed}}
|
||||||
{{svg "octicon-clock"}} {{$.i18n.Tr "repo.milestones.closed" $closedDate|Str2html}}
|
{{svg "octicon-clock"}} {{$.i18n.Tr "repo.milestones.closed" $closedDate|Str2html}}
|
||||||
{{else}}
|
{{else}}
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
<input type="hidden" id="issueIndex" value="{{.Issue.Index}}"/>
|
<input type="hidden" id="issueIndex" value="{{.Issue.Index}}"/>
|
||||||
<input type="hidden" id="type" value="{{.IssueType}}">
|
<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">
|
<div class="twelve wide column comment-list prevent-before-timeline">
|
||||||
<ui class="ui timeline">
|
<ui class="ui timeline">
|
||||||
<div id="{{.Issue.HashTag}}" class="timeline-item comment first">
|
<div id="{{.Issue.HashTag}}" class="timeline-item comment first">
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{{ template "base/alert" }}
|
{{ template "base/alert" }}
|
||||||
{{range .Issue.Comments}}
|
{{range .Issue.Comments}}
|
||||||
{{if call $.ShouldShowCommentType .Type}}
|
{{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,
|
<!-- 0 = COMMENT, 1 = REOPEN, 2 = CLOSE, 3 = ISSUE_REF, 4 = COMMIT_REF,
|
||||||
5 = COMMENT_REF, 6 = PULL_REF, 7 = COMMENT_LABEL, 12 = START_TRACKING,
|
5 = COMMENT_REF, 6 = PULL_REF, 7 = COMMENT_LABEL, 12 = START_TRACKING,
|
||||||
|
@ -146,7 +146,7 @@
|
||||||
{{else if eq .RefAction 2 }}
|
{{else if eq .RefAction 2 }}
|
||||||
{{ $refTr = "repo.issues.ref_reopening_from" }}
|
{{ $refTr = "repo.issues.ref_reopening_from" }}
|
||||||
{{end}}
|
{{end}}
|
||||||
{{ $createdStr:= TimeSinceUnix .CreatedUnix $.Lang }}
|
{{ $createdStr:= TimeSinceUnix .CreatedUnix $.i18n.Lang }}
|
||||||
<div class="timeline-item event" id="{{.HashTag}}">
|
<div class="timeline-item event" id="{{.HashTag}}">
|
||||||
<span class="badge">{{svg "octicon-bookmark"}}</span>
|
<span class="badge">{{svg "octicon-bookmark"}}</span>
|
||||||
<a href="{{.Poster.HomeLink}}">
|
<a href="{{.Poster.HomeLink}}">
|
||||||
|
@ -557,7 +557,7 @@
|
||||||
<div id="code-comments-{{(index $comms 0).ID}}" class="comment-code-cloud ui segment{{if $resolved}} hide{{end}}">
|
<div id="code-comments-{{(index $comms 0).ID}}" class="comment-code-cloud ui segment{{if $resolved}} hide{{end}}">
|
||||||
<div class="ui comments mb-0">
|
<div class="ui comments mb-0">
|
||||||
{{range $comms}}
|
{{range $comms}}
|
||||||
{{ $createdSubStr:= TimeSinceUnix .CreatedUnix $.Lang }}
|
{{ $createdSubStr:= TimeSinceUnix .CreatedUnix $.i18n.Lang }}
|
||||||
<div class="comment code-comment pb-4" id="{{.HashTag}}">
|
<div class="comment code-comment pb-4" id="{{.HashTag}}">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="header comment-header">
|
<div class="header comment-header">
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<div class="ui segment">
|
<div class="ui segment">
|
||||||
<h4>{{$.i18n.Tr "repo.issues.review.reviewers"}}</h4>
|
<h4>{{$.i18n.Tr "repo.issues.review.reviewers"}}</h4>
|
||||||
{{range .PullReviewers}}
|
{{range .PullReviewers}}
|
||||||
{{ $createdStr:= TimeSinceUnix .Review.UpdatedUnix $.Lang }}
|
{{ $createdStr:= TimeSinceUnix .Review.UpdatedUnix $.i18n.Lang }}
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
<div class="review-item">
|
<div class="review-item">
|
||||||
<div class="review-item-left">
|
<div class="review-item-left">
|
||||||
|
@ -82,7 +82,7 @@
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{range .OriginalReviews}}
|
{{range .OriginalReviews}}
|
||||||
{{ $createdStr:= TimeSinceUnix .UpdatedUnix $.Lang }}
|
{{ $createdStr:= TimeSinceUnix .UpdatedUnix $.i18n.Lang }}
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
<div class="review-item">
|
<div class="review-item">
|
||||||
<div class="review-item-left">
|
<div class="review-item-left">
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
{{$baseHref = printf "<a href=\"%s\">%s</a>" (.BaseBranchHTMLURL | Escape) $baseHref}}
|
{{$baseHref = printf "<a href=\"%s\">%s</a>" (.BaseBranchHTMLURL | Escape) $baseHref}}
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .Issue.PullRequest.HasMerged}}
|
{{if .Issue.PullRequest.HasMerged}}
|
||||||
{{ $mergedStr:= TimeSinceUnix .Issue.PullRequest.MergedUnix $.Lang }}
|
{{ $mergedStr:= TimeSinceUnix .Issue.PullRequest.MergedUnix $.i18n.Lang }}
|
||||||
{{if .Issue.OriginalAuthor }}
|
{{if .Issue.OriginalAuthor }}
|
||||||
{{.Issue.OriginalAuthor}}
|
{{.Issue.OriginalAuthor}}
|
||||||
<span class="pull-desc">{{$.i18n.Tr "repo.pulls.merged_title_desc" .NumCommits $headHref $baseHref $mergedStr | Safe}}</span>
|
<span class="pull-desc">{{$.i18n.Tr "repo.pulls.merged_title_desc" .NumCommits $headHref $baseHref $mergedStr | Safe}}</span>
|
||||||
|
@ -88,7 +88,7 @@
|
||||||
</span>
|
</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{ $createdStr:= TimeSinceUnix .Issue.CreatedUnix $.Lang }}
|
{{ $createdStr:= TimeSinceUnix .Issue.CreatedUnix $.i18n.Lang }}
|
||||||
<span class="time-desc">
|
<span class="time-desc">
|
||||||
{{if .Issue.OriginalAuthor }}
|
{{if .Issue.OriginalAuthor }}
|
||||||
{{$.i18n.Tr "repo.issues.opened_by_fake" $createdStr (.Issue.OriginalAuthor|Escape) | Safe}}
|
{{$.i18n.Tr "repo.issues.opened_by_fake" $createdStr (.Issue.OriginalAuthor|Escape) | Safe}}
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
<li class="item">
|
<li class="item">
|
||||||
{{svg "octicon-project"}} <a href="{{$.RepoLink}}/projects/{{.ID}}">{{.Title}}</a>
|
{{svg "octicon-project"}} <a href="{{$.RepoLink}}/projects/{{.ID}}">{{.Title}}</a>
|
||||||
<div class="meta">
|
<div class="meta">
|
||||||
{{ $closedDate:= TimeSinceUnix .ClosedDateUnix $.Lang }}
|
{{ $closedDate:= TimeSinceUnix .ClosedDateUnix $.i18n.Lang }}
|
||||||
{{if .IsClosed }}
|
{{if .IsClosed }}
|
||||||
{{svg "octicon-clock"}} {{$.i18n.Tr "repo.milestones.closed" $closedDate|Str2html}}
|
{{svg "octicon-clock"}} {{$.i18n.Tr "repo.milestones.closed" $closedDate|Str2html}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -202,7 +202,7 @@
|
||||||
<div class="meta my-2">
|
<div class="meta my-2">
|
||||||
<span class="text light grey">
|
<span class="text light grey">
|
||||||
#{{.Index}}
|
#{{.Index}}
|
||||||
{{ $timeStr := TimeSinceUnix .GetLastEventTimestamp $.Lang }}
|
{{ $timeStr := TimeSinceUnix .GetLastEventTimestamp $.i18n.Lang }}
|
||||||
{{if .OriginalAuthor }}
|
{{if .OriginalAuthor }}
|
||||||
{{$.i18n.Tr .GetLastEventLabelFake $timeStr (.OriginalAuthor|Escape) | Safe}}
|
{{$.i18n.Tr .GetLastEventLabelFake $timeStr (.OriginalAuthor|Escape) | Safe}}
|
||||||
{{else if gt .Poster.ID 0}}
|
{{else if gt .Poster.ID 0}}
|
||||||
|
|
|
@ -65,7 +65,7 @@
|
||||||
<li class="ui grid">
|
<li class="ui grid">
|
||||||
<div class="ui four wide column meta mt-2">
|
<div class="ui four wide column meta mt-2">
|
||||||
{{if .IsTag}}
|
{{if .IsTag}}
|
||||||
{{if .CreatedUnix}}<span class="time">{{TimeSinceUnix .CreatedUnix $.Lang}}</span>{{end}}
|
{{if .CreatedUnix}}<span class="time">{{TimeSinceUnix .CreatedUnix $.i18n.Lang}}</span>{{end}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{if .IsDraft}}
|
{{if .IsDraft}}
|
||||||
<span class="ui yellow label">{{$.i18n.Tr "repo.release.draft"}}</span>
|
<span class="ui yellow label">{{$.i18n.Tr "repo.release.draft"}}</span>
|
||||||
|
@ -132,7 +132,7 @@
|
||||||
{{$.i18n.Tr "repo.released_this"}}
|
{{$.i18n.Tr "repo.released_this"}}
|
||||||
</span>
|
</span>
|
||||||
{{if .CreatedUnix}}
|
{{if .CreatedUnix}}
|
||||||
<span class="time">{{TimeSinceUnix .CreatedUnix $.Lang}}</span>
|
<span class="time">{{TimeSinceUnix .CreatedUnix $.i18n.Lang}}</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if not .IsDraft}}
|
{{if not .IsDraft}}
|
||||||
| <span class="ahead"><a href="{{$.RepoLink}}/compare/{{.TagName | PathEscapeSegments}}...{{.Target | PathEscapeSegments}}">{{$.i18n.Tr "repo.release.ahead.commits" .NumCommitsBehind | Str2html}}</a> {{$.i18n.Tr "repo.release.ahead.target" .Target}}</span>
|
| <span class="ahead"><a href="{{$.RepoLink}}/compare/{{.TagName | PathEscapeSegments}}...{{.Target | PathEscapeSegments}}">{{$.i18n.Tr "repo.release.ahead.commits" .NumCommitsBehind | Str2html}}</a> {{$.i18n.Tr "repo.release.ahead.target" .Target}}</span>
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td>{{FileSize .Size}}</td>
|
<td>{{FileSize .Size}}</td>
|
||||||
<td>{{TimeSince .CreatedUnix.AsTime $.Lang}}</td>
|
<td>{{TimeSince .CreatedUnix.AsTime $.i18n.Lang}}</td>
|
||||||
<td class="right aligned">
|
<td class="right aligned">
|
||||||
<a class="ui primary show-panel button" href="{{$.Link}}/find?oid={{.Oid}}&size={{.Size}}">{{$.i18n.Tr "repo.settings.lfs_findcommits"}}</a>
|
<a class="ui primary show-panel button" href="{{$.Link}}/find?oid={{.Oid}}&size={{.Size}}">{{$.i18n.Tr "repo.settings.lfs_findcommits"}}</a>
|
||||||
<button class="ui basic show-modal icon button" data-modal="#delete-{{.Oid}}">
|
<button class="ui basic show-modal icon button" data-modal="#delete-{{.Oid}}">
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
{{$.i18n.Tr "repo.diff.commit"}}
|
{{$.i18n.Tr "repo.diff.commit"}}
|
||||||
<a class="ui blue sha label" href="{{$.RepoLink}}/commit/{{.SHA}}">{{ShortSha .SHA}}</a>
|
<a class="ui blue sha label" href="{{$.RepoLink}}/commit/{{.SHA}}">{{ShortSha .SHA}}</a>
|
||||||
</td>
|
</td>
|
||||||
<td>{{TimeSince .When $.Lang}}</td>
|
<td>{{TimeSince .When $.i18n.Lang}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{else}}
|
{{else}}
|
||||||
<tr>
|
<tr>
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
{{$lock.Owner.DisplayName}}
|
{{$lock.Owner.DisplayName}}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td>{{TimeSince .Created $.Lang}}</td>
|
<td>{{TimeSince .Created $.i18n.Lang}}</td>
|
||||||
<td class="right aligned">
|
<td class="right aligned">
|
||||||
<form action="{{$.LFSFilesLink}}/locks/{{$lock.ID}}/unlock" method="POST">
|
<form action="{{$.LFSFilesLink}}/locks/{{$lock.ID}}/unlock" method="POST">
|
||||||
{{$.CsrfTokenHtml}}
|
{{$.CsrfTokenHtml}}
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
</span>
|
</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
</th>
|
</th>
|
||||||
<th class="text grey right age">{{if .LatestCommit}}{{if .LatestCommit.Committer}}{{TimeSince .LatestCommit.Committer.When $.Lang}}{{end}}{{end}}</th>
|
<th class="text grey right age">{{if .LatestCommit}}{{if .LatestCommit.Committer}}{{TimeSince .LatestCommit.Committer.When $.i18n.Lang}}{{end}}{{end}}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
@ -87,7 +87,7 @@
|
||||||
{{end}}
|
{{end}}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="text right age three wide">{{if $commit}}{{TimeSince $commit.Committer.When $.Lang}}{{end}}</td>
|
<td class="text right age three wide">{{if $commit}}{{TimeSince $commit.Committer.When $.i18n.Lang}}{{end}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{end}}
|
{{end}}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
{{svg "octicon-file"}}
|
{{svg "octicon-file"}}
|
||||||
<a href="{{$.RepoLink}}/wiki/{{.SubURL}}">{{.Name}}</a>
|
<a href="{{$.RepoLink}}/wiki/{{.SubURL}}">{{.Name}}</a>
|
||||||
</td>
|
</td>
|
||||||
{{$timeSince := TimeSinceUnix .UpdatedUnix $.Lang}}
|
{{$timeSince := TimeSinceUnix .UpdatedUnix $.i18n.Lang}}
|
||||||
<td class="text right grey">{{$.i18n.Tr "repo.wiki.last_updated" $timeSince | Safe}}</td>
|
<td class="text right grey">{{$.i18n.Tr "repo.wiki.last_updated" $timeSince | Safe}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
<a class="file-revisions-btn ui basic button" title="{{.i18n.Tr "repo.wiki.back_to_wiki"}}" href="{{.RepoLink}}/wiki/{{.PageURL}}" ><span>{{.revision}}</span> {{svg "octicon-home"}}</a>
|
<a class="file-revisions-btn ui basic button" title="{{.i18n.Tr "repo.wiki.back_to_wiki"}}" href="{{.RepoLink}}/wiki/{{.PageURL}}" ><span>{{.revision}}</span> {{svg "octicon-home"}}</a>
|
||||||
{{$title}}
|
{{$title}}
|
||||||
<div class="ui sub header word-break">
|
<div class="ui sub header word-break">
|
||||||
{{$timeSince := TimeSince .Author.When $.Lang}}
|
{{$timeSince := TimeSince .Author.When $.i18n.Lang}}
|
||||||
{{.i18n.Tr "repo.wiki.last_commit_info" .Author.Name $timeSince | Safe}}
|
{{.i18n.Tr "repo.wiki.last_commit_info" .Author.Name $timeSince | Safe}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
<a class="file-revisions-btn ui basic button" title="{{.i18n.Tr "repo.wiki.file_revision"}}" href="{{.RepoLink}}/wiki/{{.PageURL}}?action=_revision" ><span>{{.CommitCount}}</span> {{svg "octicon-history"}}</a>
|
<a class="file-revisions-btn ui basic button" title="{{.i18n.Tr "repo.wiki.file_revision"}}" href="{{.RepoLink}}/wiki/{{.PageURL}}?action=_revision" ><span>{{.CommitCount}}</span> {{svg "octicon-history"}}</a>
|
||||||
{{$title}}
|
{{$title}}
|
||||||
<div class="ui sub header">
|
<div class="ui sub header">
|
||||||
{{$timeSince := TimeSince .Author.When $.Lang}}
|
{{$timeSince := TimeSince .Author.When $.i18n.Lang}}
|
||||||
{{.i18n.Tr "repo.wiki.last_commit_info" .Author.Name $timeSince | Safe}}
|
{{.i18n.Tr "repo.wiki.last_commit_info" .Author.Name $timeSince | Safe}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -51,7 +51,7 @@
|
||||||
#{{.Index}}
|
#{{.Index}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</a>
|
</a>
|
||||||
{{ $timeStr := TimeSinceUnix .GetLastEventTimestamp $.Lang }}
|
{{ $timeStr := TimeSinceUnix .GetLastEventTimestamp $.i18n.Lang }}
|
||||||
{{if .OriginalAuthor }}
|
{{if .OriginalAuthor }}
|
||||||
{{$.i18n.Tr .GetLastEventLabelFake $timeStr (.OriginalAuthor|Escape) | Safe}}
|
{{$.i18n.Tr .GetLastEventLabelFake $timeStr (.OriginalAuthor|Escape) | Safe}}
|
||||||
{{else if gt .Poster.ID 0}}
|
{{else if gt .Poster.ID 0}}
|
||||||
|
|
|
@ -88,7 +88,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="meta">
|
<div class="meta">
|
||||||
{{ $closedDate:= TimeSinceUnix .ClosedDateUnix $.Lang }}
|
{{ $closedDate:= TimeSinceUnix .ClosedDateUnix $.i18n.Lang }}
|
||||||
{{if .IsClosed}}
|
{{if .IsClosed}}
|
||||||
{{svg "octicon-clock"}} {{$.i18n.Tr "repo.milestones.closed" $closedDate|Str2html}}
|
{{svg "octicon-clock"}} {{$.i18n.Tr "repo.milestones.closed" $closedDate|Str2html}}
|
||||||
{{else}}
|
{{else}}
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<strong>{{.Name}}</strong>
|
<strong>{{.Name}}</strong>
|
||||||
</div>
|
</div>
|
||||||
<span class="time">{{TimeSinceUnix .CreatedUnix $.Lang}}</span>
|
<span class="time">{{TimeSinceUnix .CreatedUnix $.i18n.Lang}}</span>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue