mirror of
				https://github.com/go-gitea/gitea
				synced 2025-10-31 03:18:24 +00:00 
			
		
		
		
	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:
		| @@ -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,7 +127,16 @@ 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 | ||||||
|   | |||||||
| @@ -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> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user