mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 08:30:25 +08:00 
			
		
		
		
	Unify and simplify TrN for i18n (#18141)
Refer: https://github.com/go-gitea/gitea/pull/18135#issuecomment-1003246099 Now we have a unique and simple `TrN`, and make the fix of PR #18135 also use the better `TrN` logic.
This commit is contained in:
		@@ -8,6 +8,7 @@ import (
 | 
				
			|||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
	"encoding/csv"
 | 
						"encoding/csv"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -21,14 +22,21 @@ func TestCreateReader(t *testing.T) {
 | 
				
			|||||||
	assert.Equal(t, ',', rd.Comma)
 | 
						assert.Equal(t, ',', rd.Comma)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//nolint
 | 
					func decodeSlashes(t *testing.T, s string) string {
 | 
				
			||||||
 | 
						s = strings.ReplaceAll(s, "\n", "\\n")
 | 
				
			||||||
 | 
						s = strings.ReplaceAll(s, "\"", "\\\"")
 | 
				
			||||||
 | 
						decoded, err := strconv.Unquote(`"` + s + `"`)
 | 
				
			||||||
 | 
						assert.NoError(t, err, "unable to decode string")
 | 
				
			||||||
 | 
						return decoded
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestCreateReaderAndDetermineDelimiter(t *testing.T) {
 | 
					func TestCreateReaderAndDetermineDelimiter(t *testing.T) {
 | 
				
			||||||
	var cases = []struct {
 | 
						var cases = []struct {
 | 
				
			||||||
		csv               string
 | 
							csv               string
 | 
				
			||||||
		expectedRows      [][]string
 | 
							expectedRows      [][]string
 | 
				
			||||||
		expectedDelimiter rune
 | 
							expectedDelimiter rune
 | 
				
			||||||
	}{
 | 
						}{
 | 
				
			||||||
		// case 0 - semicolon delmited
 | 
							// case 0 - semicolon delimited
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			csv: `a;b;c
 | 
								csv: `a;b;c
 | 
				
			||||||
1;2;3
 | 
					1;2;3
 | 
				
			||||||
@@ -47,11 +55,11 @@ a,	b	c
 | 
				
			|||||||
	e	f
 | 
						e	f
 | 
				
			||||||
g	h	i
 | 
					g	h	i
 | 
				
			||||||
j		l
 | 
					j		l
 | 
				
			||||||
m	n,	
 | 
					m	n,\t
 | 
				
			||||||
p	q	r
 | 
					p	q	r
 | 
				
			||||||
		u
 | 
							u
 | 
				
			||||||
v	w	x
 | 
					v	w	x
 | 
				
			||||||
y		
 | 
					y\t\t
 | 
				
			||||||
		`,
 | 
							`,
 | 
				
			||||||
			expectedRows: [][]string{
 | 
								expectedRows: [][]string{
 | 
				
			||||||
				{"col1", "col2", "col3"},
 | 
									{"col1", "col2", "col3"},
 | 
				
			||||||
@@ -74,7 +82,7 @@ y
 | 
				
			|||||||
 a, b, c
 | 
					 a, b, c
 | 
				
			||||||
d,e,f
 | 
					d,e,f
 | 
				
			||||||
 ,h, i
 | 
					 ,h, i
 | 
				
			||||||
j, , 
 | 
					j, ,\x20
 | 
				
			||||||
 , , `,
 | 
					 , , `,
 | 
				
			||||||
			expectedRows: [][]string{
 | 
								expectedRows: [][]string{
 | 
				
			||||||
				{"col1", "col2", "col3"},
 | 
									{"col1", "col2", "col3"},
 | 
				
			||||||
@@ -89,7 +97,7 @@ j, ,
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for n, c := range cases {
 | 
						for n, c := range cases {
 | 
				
			||||||
		rd, err := CreateReaderAndDetermineDelimiter(nil, strings.NewReader(c.csv))
 | 
							rd, err := CreateReaderAndDetermineDelimiter(nil, strings.NewReader(decodeSlashes(t, c.csv)))
 | 
				
			||||||
		assert.NoError(t, err, "case %d: should not throw error: %v\n", n, err)
 | 
							assert.NoError(t, err, "case %d: should not throw error: %v\n", n, err)
 | 
				
			||||||
		assert.EqualValues(t, c.expectedDelimiter, rd.Comma, "case %d: delimiter should be '%c', got '%c'", n, c.expectedDelimiter, rd.Comma)
 | 
							assert.EqualValues(t, c.expectedDelimiter, rd.Comma, "case %d: delimiter should be '%c', got '%c'", n, c.expectedDelimiter, rd.Comma)
 | 
				
			||||||
		rows, err := rd.ReadAll()
 | 
							rows, err := rd.ReadAll()
 | 
				
			||||||
@@ -222,7 +230,7 @@ John Doe	john@doe.com	This,note,had,a,lot,of,commas,to,test,delimters`,
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for n, c := range cases {
 | 
						for n, c := range cases {
 | 
				
			||||||
		delimiter := determineDelimiter(&markup.RenderContext{Filename: c.filename}, []byte(c.csv))
 | 
							delimiter := determineDelimiter(&markup.RenderContext{Filename: c.filename}, []byte(decodeSlashes(t, c.csv)))
 | 
				
			||||||
		assert.EqualValues(t, c.expectedDelimiter, delimiter, "case %d: delimiter should be equal, expected '%c' got '%c'", n, c.expectedDelimiter, delimiter)
 | 
							assert.EqualValues(t, c.expectedDelimiter, delimiter, "case %d: delimiter should be equal, expected '%c' got '%c'", n, c.expectedDelimiter, delimiter)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -287,7 +295,7 @@ abc   | |123
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for n, c := range cases {
 | 
						for n, c := range cases {
 | 
				
			||||||
		modifiedText := removeQuotedString(c.text)
 | 
							modifiedText := removeQuotedString(decodeSlashes(t, c.text))
 | 
				
			||||||
		assert.EqualValues(t, c.expectedText, modifiedText, "case %d: modified text should be equal", n)
 | 
							assert.EqualValues(t, c.expectedText, modifiedText, "case %d: modified text should be equal", n)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -353,7 +361,7 @@ John Doe	john@doe.com	This,note,had,a,lot,of,commas,to,test,delimters`,
 | 
				
			|||||||
	quoted,
 | 
						quoted,
 | 
				
			||||||
text,"	a
 | 
					text,"	a
 | 
				
			||||||
2	"some,
 | 
					2	"some,
 | 
				
			||||||
quoted,	
 | 
					quoted,\t
 | 
				
			||||||
	text,"	b
 | 
						text,"	b
 | 
				
			||||||
3	"some,
 | 
					3	"some,
 | 
				
			||||||
quoted,
 | 
					quoted,
 | 
				
			||||||
@@ -442,7 +450,7 @@ jkl`,
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for n, c := range cases {
 | 
						for n, c := range cases {
 | 
				
			||||||
		delimiter := guessDelimiter([]byte(c.csv))
 | 
							delimiter := guessDelimiter([]byte(decodeSlashes(t, c.csv)))
 | 
				
			||||||
		assert.EqualValues(t, c.expectedDelimiter, delimiter, "case %d: delimiter should be equal, expected '%c' got '%c'", n, c.expectedDelimiter, delimiter)
 | 
							assert.EqualValues(t, c.expectedDelimiter, delimiter, "case %d: delimiter should be equal, expected '%c' got '%c'", n, c.expectedDelimiter, delimiter)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -459,7 +467,7 @@ func TestGuessFromBeforeAfterQuotes(t *testing.T) {
 | 
				
			|||||||
	quoted,
 | 
						quoted,
 | 
				
			||||||
text,"	a
 | 
					text,"	a
 | 
				
			||||||
2	"some,
 | 
					2	"some,
 | 
				
			||||||
quoted,	
 | 
					quoted,\t
 | 
				
			||||||
	text,"	b
 | 
						text,"	b
 | 
				
			||||||
3	"some,
 | 
					3	"some,
 | 
				
			||||||
quoted,
 | 
					quoted,
 | 
				
			||||||
@@ -534,7 +542,7 @@ a|"he said, ""here I am"""`,
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for n, c := range cases {
 | 
						for n, c := range cases {
 | 
				
			||||||
		delimiter := guessFromBeforeAfterQuotes([]byte(c.csv))
 | 
							delimiter := guessFromBeforeAfterQuotes([]byte(decodeSlashes(t, c.csv)))
 | 
				
			||||||
		assert.EqualValues(t, c.expectedDelimiter, delimiter, "case %d: delimiter should be equal, expected '%c' got '%c'", n, c.expectedDelimiter, delimiter)
 | 
							assert.EqualValues(t, c.expectedDelimiter, delimiter, "case %d: delimiter should be equal, expected '%c' got '%c'", n, c.expectedDelimiter, delimiter)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -549,6 +557,10 @@ func (l mockLocale) Tr(s string, _ ...interface{}) string {
 | 
				
			|||||||
	return s
 | 
						return s
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (l mockLocale) TrN(_cnt interface{}, key1, _keyN string, _args ...interface{}) string {
 | 
				
			||||||
 | 
						return key1
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestFormatError(t *testing.T) {
 | 
					func TestFormatError(t *testing.T) {
 | 
				
			||||||
	var cases = []struct {
 | 
						var cases = []struct {
 | 
				
			||||||
		err             error
 | 
							err             error
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -239,7 +239,6 @@ func NewFuncMap() []template.FuncMap {
 | 
				
			|||||||
		"DisableImportLocal": func() bool {
 | 
							"DisableImportLocal": func() bool {
 | 
				
			||||||
			return !setting.ImportLocalPaths
 | 
								return !setting.ImportLocalPaths
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		"TrN": TrN,
 | 
					 | 
				
			||||||
		"Dict": func(values ...interface{}) (map[string]interface{}, error) {
 | 
							"Dict": func(values ...interface{}) (map[string]interface{}, error) {
 | 
				
			||||||
			if len(values)%2 != 0 {
 | 
								if len(values)%2 != 0 {
 | 
				
			||||||
				return nil, errors.New("invalid dict call")
 | 
									return nil, errors.New("invalid dict call")
 | 
				
			||||||
@@ -857,69 +856,6 @@ func DiffLineTypeToStr(diffType int) string {
 | 
				
			|||||||
	return "same"
 | 
						return "same"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Language specific rules for translating plural texts
 | 
					 | 
				
			||||||
var trNLangRules = map[string]func(int64) int{
 | 
					 | 
				
			||||||
	"en-US": func(cnt int64) int {
 | 
					 | 
				
			||||||
		if cnt == 1 {
 | 
					 | 
				
			||||||
			return 0
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return 1
 | 
					 | 
				
			||||||
	},
 | 
					 | 
				
			||||||
	"lv-LV": func(cnt int64) int {
 | 
					 | 
				
			||||||
		if cnt%10 == 1 && cnt%100 != 11 {
 | 
					 | 
				
			||||||
			return 0
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return 1
 | 
					 | 
				
			||||||
	},
 | 
					 | 
				
			||||||
	"ru-RU": func(cnt int64) int {
 | 
					 | 
				
			||||||
		if cnt%10 == 1 && cnt%100 != 11 {
 | 
					 | 
				
			||||||
			return 0
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return 1
 | 
					 | 
				
			||||||
	},
 | 
					 | 
				
			||||||
	"zh-CN": func(cnt int64) int {
 | 
					 | 
				
			||||||
		return 0
 | 
					 | 
				
			||||||
	},
 | 
					 | 
				
			||||||
	"zh-HK": func(cnt int64) int {
 | 
					 | 
				
			||||||
		return 0
 | 
					 | 
				
			||||||
	},
 | 
					 | 
				
			||||||
	"zh-TW": func(cnt int64) int {
 | 
					 | 
				
			||||||
		return 0
 | 
					 | 
				
			||||||
	},
 | 
					 | 
				
			||||||
	"fr-FR": func(cnt int64) int {
 | 
					 | 
				
			||||||
		if cnt > -2 && cnt < 2 {
 | 
					 | 
				
			||||||
			return 0
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return 1
 | 
					 | 
				
			||||||
	},
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// TrN returns key to be used for plural text translation
 | 
					 | 
				
			||||||
func TrN(lang string, cnt interface{}, key1, keyN string) string {
 | 
					 | 
				
			||||||
	var c int64
 | 
					 | 
				
			||||||
	if t, ok := cnt.(int); ok {
 | 
					 | 
				
			||||||
		c = int64(t)
 | 
					 | 
				
			||||||
	} else if t, ok := cnt.(int16); ok {
 | 
					 | 
				
			||||||
		c = int64(t)
 | 
					 | 
				
			||||||
	} else if t, ok := cnt.(int32); ok {
 | 
					 | 
				
			||||||
		c = int64(t)
 | 
					 | 
				
			||||||
	} else if t, ok := cnt.(int64); ok {
 | 
					 | 
				
			||||||
		c = t
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		return keyN
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ruleFunc, ok := trNLangRules[lang]
 | 
					 | 
				
			||||||
	if !ok {
 | 
					 | 
				
			||||||
		ruleFunc = trNLangRules["en-US"]
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if ruleFunc(c) == 0 {
 | 
					 | 
				
			||||||
		return key1
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return keyN
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// MigrationIcon returns a SVG name matching the service an issue/comment was migrated from
 | 
					// MigrationIcon returns a SVG name matching the service an issue/comment was migrated from
 | 
				
			||||||
func MigrationIcon(hostname string) string {
 | 
					func MigrationIcon(hostname string) string {
 | 
				
			||||||
	switch hostname {
 | 
						switch hostname {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -103,6 +103,10 @@ func (l mockLocale) Tr(s string, _ ...interface{}) string {
 | 
				
			|||||||
	return s
 | 
						return s
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (l mockLocale) TrN(_cnt interface{}, key1, _keyN string, _args ...interface{}) string {
 | 
				
			||||||
 | 
						return key1
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type mockResponseWriter struct {
 | 
					type mockResponseWriter struct {
 | 
				
			||||||
	httptest.ResponseRecorder
 | 
						httptest.ResponseRecorder
 | 
				
			||||||
	size int
 | 
						size int
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,6 +17,7 @@ import (
 | 
				
			|||||||
type Locale interface {
 | 
					type Locale interface {
 | 
				
			||||||
	Language() string
 | 
						Language() string
 | 
				
			||||||
	Tr(string, ...interface{}) string
 | 
						Tr(string, ...interface{}) string
 | 
				
			||||||
 | 
						TrN(cnt interface{}, key1, keyN string, args ...interface{}) string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// LangType represents a lang type
 | 
					// LangType represents a lang type
 | 
				
			||||||
@@ -99,3 +100,67 @@ func (l *locale) Language() string {
 | 
				
			|||||||
func (l *locale) Tr(format string, args ...interface{}) string {
 | 
					func (l *locale) Tr(format string, args ...interface{}) string {
 | 
				
			||||||
	return i18n.Tr(l.Lang, format, args...)
 | 
						return i18n.Tr(l.Lang, format, args...)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Language specific rules for translating plural texts
 | 
				
			||||||
 | 
					var trNLangRules = map[string]func(int64) int{
 | 
				
			||||||
 | 
						// the default rule is "en-US" if a language isn't listed here
 | 
				
			||||||
 | 
						"en-US": func(cnt int64) int {
 | 
				
			||||||
 | 
							if cnt == 1 {
 | 
				
			||||||
 | 
								return 0
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return 1
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						"lv-LV": func(cnt int64) int {
 | 
				
			||||||
 | 
							if cnt%10 == 1 && cnt%100 != 11 {
 | 
				
			||||||
 | 
								return 0
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return 1
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						"ru-RU": func(cnt int64) int {
 | 
				
			||||||
 | 
							if cnt%10 == 1 && cnt%100 != 11 {
 | 
				
			||||||
 | 
								return 0
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return 1
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						"zh-CN": func(cnt int64) int {
 | 
				
			||||||
 | 
							return 0
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						"zh-HK": func(cnt int64) int {
 | 
				
			||||||
 | 
							return 0
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						"zh-TW": func(cnt int64) int {
 | 
				
			||||||
 | 
							return 0
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						"fr-FR": func(cnt int64) int {
 | 
				
			||||||
 | 
							if cnt > -2 && cnt < 2 {
 | 
				
			||||||
 | 
								return 0
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return 1
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TrN returns translated message for plural text translation
 | 
				
			||||||
 | 
					func (l *locale) TrN(cnt interface{}, key1, keyN string, args ...interface{}) string {
 | 
				
			||||||
 | 
						var c int64
 | 
				
			||||||
 | 
						if t, ok := cnt.(int); ok {
 | 
				
			||||||
 | 
							c = int64(t)
 | 
				
			||||||
 | 
						} else if t, ok := cnt.(int16); ok {
 | 
				
			||||||
 | 
							c = int64(t)
 | 
				
			||||||
 | 
						} else if t, ok := cnt.(int32); ok {
 | 
				
			||||||
 | 
							c = int64(t)
 | 
				
			||||||
 | 
						} else if t, ok := cnt.(int64); ok {
 | 
				
			||||||
 | 
							c = t
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							return l.Tr(keyN, args...)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ruleFunc, ok := trNLangRules[l.Lang]
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							ruleFunc = trNLangRules["en-US"]
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ruleFunc(c) == 0 {
 | 
				
			||||||
 | 
							return l.Tr(key1, args...)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return l.Tr(keyN, args...)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -81,13 +81,8 @@ func handleMigrateError(ctx *context.Context, owner *user_model.User, err error,
 | 
				
			|||||||
	case migrations.IsTwoFactorAuthError(err):
 | 
						case migrations.IsTwoFactorAuthError(err):
 | 
				
			||||||
		ctx.RenderWithErr(ctx.Tr("form.2fa_auth_required"), tpl, form)
 | 
							ctx.RenderWithErr(ctx.Tr("form.2fa_auth_required"), tpl, form)
 | 
				
			||||||
	case repo_model.IsErrReachLimitOfRepo(err):
 | 
						case repo_model.IsErrReachLimitOfRepo(err):
 | 
				
			||||||
		var msg string
 | 
					 | 
				
			||||||
		maxCreationLimit := owner.MaxCreationLimit()
 | 
							maxCreationLimit := owner.MaxCreationLimit()
 | 
				
			||||||
		if maxCreationLimit == 1 {
 | 
							msg := ctx.TrN(maxCreationLimit, "repo.form.reach_limit_of_creation_1", "repo.form.reach_limit_of_creation_n", maxCreationLimit)
 | 
				
			||||||
			msg = ctx.Tr("repo.form.reach_limit_of_creation_1", maxCreationLimit)
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			msg = ctx.Tr("repo.form.reach_limit_of_creation_n", maxCreationLimit)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		ctx.RenderWithErr(msg, tpl, form)
 | 
							ctx.RenderWithErr(msg, tpl, form)
 | 
				
			||||||
	case repo_model.IsErrRepoAlreadyExist(err):
 | 
						case repo_model.IsErrRepoAlreadyExist(err):
 | 
				
			||||||
		ctx.Data["Err_RepoName"] = true
 | 
							ctx.Data["Err_RepoName"] = true
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -162,13 +162,8 @@ func Create(ctx *context.Context) {
 | 
				
			|||||||
func handleCreateError(ctx *context.Context, owner *user_model.User, err error, name string, tpl base.TplName, form interface{}) {
 | 
					func handleCreateError(ctx *context.Context, owner *user_model.User, err error, name string, tpl base.TplName, form interface{}) {
 | 
				
			||||||
	switch {
 | 
						switch {
 | 
				
			||||||
	case repo_model.IsErrReachLimitOfRepo(err):
 | 
						case repo_model.IsErrReachLimitOfRepo(err):
 | 
				
			||||||
		var msg string
 | 
					 | 
				
			||||||
		maxCreationLimit := owner.MaxCreationLimit()
 | 
							maxCreationLimit := owner.MaxCreationLimit()
 | 
				
			||||||
		if maxCreationLimit == 1 {
 | 
							msg := ctx.TrN(maxCreationLimit, "repo.form.reach_limit_of_creation_1", "repo.form.reach_limit_of_creation_n", maxCreationLimit)
 | 
				
			||||||
			msg = ctx.Tr("repo.form.reach_limit_of_creation_1", maxCreationLimit)
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			msg = ctx.Tr("repo.form.reach_limit_of_creation_n", maxCreationLimit)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		ctx.RenderWithErr(msg, tpl, form)
 | 
							ctx.RenderWithErr(msg, tpl, form)
 | 
				
			||||||
	case repo_model.IsErrRepoAlreadyExist(err):
 | 
						case repo_model.IsErrRepoAlreadyExist(err):
 | 
				
			||||||
		ctx.Data["Err_RepoName"] = true
 | 
							ctx.Data["Err_RepoName"] = true
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -610,11 +610,8 @@ func SettingsPost(ctx *context.Context) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		if !ctx.Repo.Owner.CanCreateRepo() {
 | 
							if !ctx.Repo.Owner.CanCreateRepo() {
 | 
				
			||||||
			maxCreationLimit := ctx.Repo.Owner.MaxCreationLimit()
 | 
								maxCreationLimit := ctx.Repo.Owner.MaxCreationLimit()
 | 
				
			||||||
			if maxCreationLimit == 1 {
 | 
								msg := ctx.TrN(maxCreationLimit, "repo.form.reach_limit_of_creation_1", "repo.form.reach_limit_of_creation_n", maxCreationLimit)
 | 
				
			||||||
				ctx.Flash.Error(ctx.Tr("repo.form.reach_limit_of_creation_1", maxCreationLimit))
 | 
								ctx.Flash.Error(msg)
 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				ctx.Flash.Error(ctx.Tr("repo.form.reach_limit_of_creation_n", maxCreationLimit))
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			ctx.Redirect(repo.Link() + "/settings")
 | 
								ctx.Redirect(repo.Link() + "/settings")
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -78,7 +78,6 @@ func sendUserMail(language string, u *user_model.User, tpl base.TplName, code, s
 | 
				
			|||||||
		// helper
 | 
							// helper
 | 
				
			||||||
		"i18n":     locale,
 | 
							"i18n":     locale,
 | 
				
			||||||
		"Str2html": templates.Str2html,
 | 
							"Str2html": templates.Str2html,
 | 
				
			||||||
		"TrN":      templates.TrN,
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var content bytes.Buffer
 | 
						var content bytes.Buffer
 | 
				
			||||||
@@ -129,7 +128,6 @@ func SendActivateEmailMail(u *user_model.User, email *user_model.EmailAddress) {
 | 
				
			|||||||
		// helper
 | 
							// helper
 | 
				
			||||||
		"i18n":     locale,
 | 
							"i18n":     locale,
 | 
				
			||||||
		"Str2html": templates.Str2html,
 | 
							"Str2html": templates.Str2html,
 | 
				
			||||||
		"TrN":      templates.TrN,
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var content bytes.Buffer
 | 
						var content bytes.Buffer
 | 
				
			||||||
@@ -160,7 +158,6 @@ func SendRegisterNotifyMail(u *user_model.User) {
 | 
				
			|||||||
		// helper
 | 
							// helper
 | 
				
			||||||
		"i18n":     locale,
 | 
							"i18n":     locale,
 | 
				
			||||||
		"Str2html": templates.Str2html,
 | 
							"Str2html": templates.Str2html,
 | 
				
			||||||
		"TrN":      templates.TrN,
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var content bytes.Buffer
 | 
						var content bytes.Buffer
 | 
				
			||||||
@@ -194,7 +191,6 @@ func SendCollaboratorMail(u, doer *user_model.User, repo *repo_model.Repository)
 | 
				
			|||||||
		// helper
 | 
							// helper
 | 
				
			||||||
		"i18n":     locale,
 | 
							"i18n":     locale,
 | 
				
			||||||
		"Str2html": templates.Str2html,
 | 
							"Str2html": templates.Str2html,
 | 
				
			||||||
		"TrN":      templates.TrN,
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var content bytes.Buffer
 | 
						var content bytes.Buffer
 | 
				
			||||||
@@ -278,7 +274,6 @@ func composeIssueCommentMessages(ctx *mailCommentContext, lang string, recipient
 | 
				
			|||||||
		// helper
 | 
							// helper
 | 
				
			||||||
		"i18n":     locale,
 | 
							"i18n":     locale,
 | 
				
			||||||
		"Str2html": templates.Str2html,
 | 
							"Str2html": templates.Str2html,
 | 
				
			||||||
		"TrN":      templates.TrN,
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var mailSubject bytes.Buffer
 | 
						var mailSubject bytes.Buffer
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -76,7 +76,6 @@ func mailNewRelease(lang string, tos []string, rel *models.Release) {
 | 
				
			|||||||
		// helper
 | 
							// helper
 | 
				
			||||||
		"i18n":     locale,
 | 
							"i18n":     locale,
 | 
				
			||||||
		"Str2html": templates.Str2html,
 | 
							"Str2html": templates.Str2html,
 | 
				
			||||||
		"TrN":      templates.TrN,
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var mailBody bytes.Buffer
 | 
						var mailBody bytes.Buffer
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -71,7 +71,6 @@ func sendRepoTransferNotifyMailPerLang(lang string, newOwner, doer *user_model.U
 | 
				
			|||||||
		// helper
 | 
							// helper
 | 
				
			||||||
		"i18n":     locale,
 | 
							"i18n":     locale,
 | 
				
			||||||
		"Str2html": templates.Str2html,
 | 
							"Str2html": templates.Str2html,
 | 
				
			||||||
		"TrN":      templates.TrN,
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := bodyTemplates.ExecuteTemplate(&content, string(mailRepoTransferNotify), data); err != nil {
 | 
						if err := bodyTemplates.ExecuteTemplate(&content, string(mailRepoTransferNotify), data); err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,7 +30,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
				{{.i18n.Tr "mail.issue.action.force_push" .Doer.Name .Comment.Issue.PullRequest.HeadBranch $oldCommitLink $newCommitLink | Str2html}}
 | 
									{{.i18n.Tr "mail.issue.action.force_push" .Doer.Name .Comment.Issue.PullRequest.HeadBranch $oldCommitLink $newCommitLink | Str2html}}
 | 
				
			||||||
			{{else}}
 | 
								{{else}}
 | 
				
			||||||
				{{.i18n.Tr (TrN .i18n.Lang (len .Comment.Commits) "mail.issue.action.push_1" "mail.issue.action.push_n") .Doer.Name .Comment.Issue.PullRequest.HeadBranch (len .Comment.Commits) | Str2html}}
 | 
									{{.i18n.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}}
 | 
								{{end}}
 | 
				
			||||||
		</p>
 | 
							</p>
 | 
				
			||||||
	{{end}}
 | 
						{{end}}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -41,7 +41,7 @@
 | 
				
			|||||||
						<a class="table-cell tiny background light grey"></a>
 | 
											<a class="table-cell tiny background light grey"></a>
 | 
				
			||||||
					</div>
 | 
										</div>
 | 
				
			||||||
					{{end}}
 | 
										{{end}}
 | 
				
			||||||
					{{.i18n.Tr (TrN .i18n.Lang .Activity.ActivePRCount "repo.activity.active_prs_count_1" "repo.activity.active_prs_count_n") .Activity.ActivePRCount | Safe }}
 | 
										{{.i18n.TrN .Activity.ActivePRCount "repo.activity.active_prs_count_1" "repo.activity.active_prs_count_n" .Activity.ActivePRCount | Safe }}
 | 
				
			||||||
				</div>
 | 
									</div>
 | 
				
			||||||
			{{end}}
 | 
								{{end}}
 | 
				
			||||||
			{{if .Permission.CanRead $.UnitTypeIssues}}
 | 
								{{if .Permission.CanRead $.UnitTypeIssues}}
 | 
				
			||||||
@@ -56,7 +56,7 @@
 | 
				
			|||||||
						<a class="table-cell tiny background light grey"></a>
 | 
											<a class="table-cell tiny background light grey"></a>
 | 
				
			||||||
					</div>
 | 
										</div>
 | 
				
			||||||
					{{end}}
 | 
										{{end}}
 | 
				
			||||||
					{{.i18n.Tr (TrN .i18n.Lang .Activity.ActiveIssueCount "repo.activity.active_issues_count_1" "repo.activity.active_issues_count_n") .Activity.ActiveIssueCount | Safe }}
 | 
										{{.i18n.TrN .Activity.ActiveIssueCount "repo.activity.active_issues_count_1" "repo.activity.active_issues_count_n" .Activity.ActiveIssueCount | Safe }}
 | 
				
			||||||
				</div>
 | 
									</div>
 | 
				
			||||||
			{{end}}
 | 
								{{end}}
 | 
				
			||||||
		</div>
 | 
							</div>
 | 
				
			||||||
@@ -64,21 +64,21 @@
 | 
				
			|||||||
			{{if .Permission.CanRead $.UnitTypePullRequests}}
 | 
								{{if .Permission.CanRead $.UnitTypePullRequests}}
 | 
				
			||||||
				<a href="#merged-pull-requests" class="ui attached segment text center">
 | 
									<a href="#merged-pull-requests" class="ui attached segment text center">
 | 
				
			||||||
					<span class="text purple">{{svg "octicon-git-pull-request"}}</span> <strong>{{.Activity.MergedPRCount}}</strong><br>
 | 
										<span class="text purple">{{svg "octicon-git-pull-request"}}</span> <strong>{{.Activity.MergedPRCount}}</strong><br>
 | 
				
			||||||
					{{.i18n.Tr (TrN .i18n.Lang .Activity.MergedPRCount "repo.activity.merged_prs_count_1" "repo.activity.merged_prs_count_n") }}
 | 
										{{.i18n.TrN .Activity.MergedPRCount "repo.activity.merged_prs_count_1" "repo.activity.merged_prs_count_n"}}
 | 
				
			||||||
				</a>
 | 
									</a>
 | 
				
			||||||
				<a href="#proposed-pull-requests" class="ui attached segment text center">
 | 
									<a href="#proposed-pull-requests" class="ui attached segment text center">
 | 
				
			||||||
					<span class="text green">{{svg "octicon-git-branch"}}</span> <strong>{{.Activity.OpenedPRCount}}</strong><br>
 | 
										<span class="text green">{{svg "octicon-git-branch"}}</span> <strong>{{.Activity.OpenedPRCount}}</strong><br>
 | 
				
			||||||
					{{.i18n.Tr (TrN .i18n.Lang .Activity.OpenedPRCount "repo.activity.opened_prs_count_1" "repo.activity.opened_prs_count_n") }}
 | 
										{{.i18n.TrN .Activity.OpenedPRCount "repo.activity.opened_prs_count_1" "repo.activity.opened_prs_count_n"}}
 | 
				
			||||||
				</a>
 | 
									</a>
 | 
				
			||||||
			{{end}}
 | 
								{{end}}
 | 
				
			||||||
			{{if .Permission.CanRead $.UnitTypeIssues}}
 | 
								{{if .Permission.CanRead $.UnitTypeIssues}}
 | 
				
			||||||
				<a href="#closed-issues" class="ui attached segment text center">
 | 
									<a href="#closed-issues" class="ui attached segment text center">
 | 
				
			||||||
					<span class="text red">{{svg "octicon-issue-closed"}}</span> <strong>{{.Activity.ClosedIssueCount}}</strong><br>
 | 
										<span class="text red">{{svg "octicon-issue-closed"}}</span> <strong>{{.Activity.ClosedIssueCount}}</strong><br>
 | 
				
			||||||
					{{.i18n.Tr (TrN .i18n.Lang .Activity.ClosedIssueCount "repo.activity.closed_issues_count_1" "repo.activity.closed_issues_count_n") }}
 | 
										{{.i18n.TrN .Activity.ClosedIssueCount "repo.activity.closed_issues_count_1" "repo.activity.closed_issues_count_n"}}
 | 
				
			||||||
				</a>
 | 
									</a>
 | 
				
			||||||
				<a href="#new-issues" class="ui attached segment text center">
 | 
									<a href="#new-issues" class="ui attached segment text center">
 | 
				
			||||||
					<span class="text green">{{svg "octicon-issue-opened"}}</span> <strong>{{.Activity.OpenedIssueCount}}</strong><br>
 | 
										<span class="text green">{{svg "octicon-issue-opened"}}</span> <strong>{{.Activity.OpenedIssueCount}}</strong><br>
 | 
				
			||||||
					{{.i18n.Tr (TrN .i18n.Lang .Activity.OpenedIssueCount "repo.activity.new_issues_count_1" "repo.activity.new_issues_count_n") }}
 | 
										{{.i18n.TrN .Activity.OpenedIssueCount "repo.activity.new_issues_count_1" "repo.activity.new_issues_count_n"}}
 | 
				
			||||||
				</a>
 | 
									</a>
 | 
				
			||||||
			{{end}}
 | 
								{{end}}
 | 
				
			||||||
		</div>
 | 
							</div>
 | 
				
			||||||
@@ -94,19 +94,19 @@
 | 
				
			|||||||
				<div class="ui attached segment horizontal segments">
 | 
									<div class="ui attached segment horizontal segments">
 | 
				
			||||||
					<div class="ui attached segment text">
 | 
										<div class="ui attached segment text">
 | 
				
			||||||
						{{.i18n.Tr "repo.activity.git_stats_exclude_merges" }}
 | 
											{{.i18n.Tr "repo.activity.git_stats_exclude_merges" }}
 | 
				
			||||||
						<strong>{{.i18n.Tr (TrN .i18n.Lang .Activity.Code.AuthorCount "repo.activity.git_stats_author_1" "repo.activity.git_stats_author_n") .Activity.Code.AuthorCount }}</strong>
 | 
											<strong>{{.i18n.TrN .Activity.Code.AuthorCount "repo.activity.git_stats_author_1" "repo.activity.git_stats_author_n" .Activity.Code.AuthorCount}}</strong>
 | 
				
			||||||
						{{.i18n.Tr (TrN .i18n.Lang .Activity.Code.AuthorCount "repo.activity.git_stats_pushed_1" "repo.activity.git_stats_pushed_n") }}
 | 
											{{.i18n.TrN .Activity.Code.AuthorCount "repo.activity.git_stats_pushed_1" "repo.activity.git_stats_pushed_n"}}
 | 
				
			||||||
						<strong>{{.i18n.Tr (TrN .i18n.Lang .Activity.Code.CommitCount "repo.activity.git_stats_commit_1" "repo.activity.git_stats_commit_n") .Activity.Code.CommitCount }}</strong>
 | 
											<strong>{{.i18n.TrN .Activity.Code.CommitCount "repo.activity.git_stats_commit_1" "repo.activity.git_stats_commit_n" .Activity.Code.CommitCount}}</strong>
 | 
				
			||||||
						{{.i18n.Tr "repo.activity.git_stats_push_to_branch" .Repository.DefaultBranch }}
 | 
											{{.i18n.Tr "repo.activity.git_stats_push_to_branch" .Repository.DefaultBranch }}
 | 
				
			||||||
						<strong>{{.i18n.Tr (TrN .i18n.Lang .Activity.Code.CommitCountInAllBranches "repo.activity.git_stats_commit_1" "repo.activity.git_stats_commit_n") .Activity.Code.CommitCountInAllBranches }}</strong>
 | 
											<strong>{{.i18n.TrN .Activity.Code.CommitCountInAllBranches "repo.activity.git_stats_commit_1" "repo.activity.git_stats_commit_n" .Activity.Code.CommitCountInAllBranches}}</strong>
 | 
				
			||||||
						{{.i18n.Tr "repo.activity.git_stats_push_to_all_branches" }}
 | 
											{{.i18n.Tr "repo.activity.git_stats_push_to_all_branches" }}
 | 
				
			||||||
						{{.i18n.Tr "repo.activity.git_stats_on_default_branch" .Repository.DefaultBranch }}
 | 
											{{.i18n.Tr "repo.activity.git_stats_on_default_branch" .Repository.DefaultBranch }}
 | 
				
			||||||
						<strong>{{.i18n.Tr (TrN .i18n.Lang .Activity.Code.ChangedFiles "repo.activity.git_stats_file_1" "repo.activity.git_stats_file_n") .Activity.Code.ChangedFiles }}</strong>
 | 
											<strong>{{.i18n.TrN .Activity.Code.ChangedFiles "repo.activity.git_stats_file_1" "repo.activity.git_stats_file_n" .Activity.Code.ChangedFiles}}</strong>
 | 
				
			||||||
						{{.i18n.Tr (TrN .i18n.Lang .Activity.Code.ChangedFiles "repo.activity.git_stats_files_changed_1" "repo.activity.git_stats_files_changed_n") }}
 | 
											{{.i18n.TrN .Activity.Code.ChangedFiles "repo.activity.git_stats_files_changed_1" "repo.activity.git_stats_files_changed_n"}}
 | 
				
			||||||
						{{.i18n.Tr "repo.activity.git_stats_additions" }}
 | 
											{{.i18n.Tr "repo.activity.git_stats_additions" }}
 | 
				
			||||||
						<strong class="text green">{{.i18n.Tr (TrN .i18n.Lang .Activity.Code.Additions "repo.activity.git_stats_addition_1" "repo.activity.git_stats_addition_n") .Activity.Code.Additions }}</strong>
 | 
											<strong class="text green">{{.i18n.TrN .Activity.Code.Additions "repo.activity.git_stats_addition_1" "repo.activity.git_stats_addition_n" .Activity.Code.Additions}}</strong>
 | 
				
			||||||
						{{.i18n.Tr "repo.activity.git_stats_and_deletions" }}
 | 
											{{.i18n.Tr "repo.activity.git_stats_and_deletions" }}
 | 
				
			||||||
						<strong class="text red">{{.i18n.Tr (TrN .i18n.Lang .Activity.Code.Deletions "repo.activity.git_stats_deletion_1" "repo.activity.git_stats_deletion_n") .Activity.Code.Deletions }}</strong>.
 | 
											<strong class="text red">{{.i18n.TrN .Activity.Code.Deletions "repo.activity.git_stats_deletion_1" "repo.activity.git_stats_deletion_n" .Activity.Code.Deletions}}</strong>.
 | 
				
			||||||
					</div>
 | 
										</div>
 | 
				
			||||||
					<div class="ui attached segment">
 | 
										<div class="ui attached segment">
 | 
				
			||||||
						<div id="repo-activity-top-authors-chart"></div>
 | 
											<div id="repo-activity-top-authors-chart"></div>
 | 
				
			||||||
@@ -118,7 +118,10 @@
 | 
				
			|||||||
		{{if gt .Activity.PublishedReleaseCount 0}}
 | 
							{{if gt .Activity.PublishedReleaseCount 0}}
 | 
				
			||||||
			<h4 class="ui horizontal divider header" id="published-releases">
 | 
								<h4 class="ui horizontal divider header" id="published-releases">
 | 
				
			||||||
				<span class="text">{{svg "octicon-tag"}}</span>
 | 
									<span class="text">{{svg "octicon-tag"}}</span>
 | 
				
			||||||
				{{.i18n.Tr "repo.activity.title.releases_published_by" (.i18n.Tr (TrN .i18n.Lang .Activity.PublishedReleaseCount "repo.activity.title.releases_1" "repo.activity.title.releases_n") .Activity.PublishedReleaseCount) (.i18n.Tr (TrN .i18n.Lang .Activity.PublishedReleaseAuthorCount "repo.activity.title.user_1" "repo.activity.title.user_n") .Activity.PublishedReleaseAuthorCount) }}
 | 
									{{.i18n.Tr "repo.activity.title.releases_published_by"
 | 
				
			||||||
 | 
										(.i18n.TrN .Activity.PublishedReleaseCount "repo.activity.title.releases_1" "repo.activity.title.releases_n" .Activity.PublishedReleaseCount)
 | 
				
			||||||
 | 
										(.i18n.TrN .Activity.PublishedReleaseAuthorCount "repo.activity.title.user_1" "repo.activity.title.user_n" .Activity.PublishedReleaseAuthorCount)
 | 
				
			||||||
 | 
									}}
 | 
				
			||||||
			</h4>
 | 
								</h4>
 | 
				
			||||||
			<div class="list">
 | 
								<div class="list">
 | 
				
			||||||
				{{range .Activity.PublishedReleases}}
 | 
									{{range .Activity.PublishedReleases}}
 | 
				
			||||||
@@ -137,7 +140,10 @@
 | 
				
			|||||||
		{{if gt .Activity.MergedPRCount 0}}
 | 
							{{if gt .Activity.MergedPRCount 0}}
 | 
				
			||||||
			<h4 class="ui horizontal divider header" id="merged-pull-requests">
 | 
								<h4 class="ui horizontal divider header" id="merged-pull-requests">
 | 
				
			||||||
				<span class="text">{{svg "octicon-git-pull-request"}}</span>
 | 
									<span class="text">{{svg "octicon-git-pull-request"}}</span>
 | 
				
			||||||
				{{.i18n.Tr "repo.activity.title.prs_merged_by" (.i18n.Tr (TrN .i18n.Lang .Activity.MergedPRCount "repo.activity.title.prs_1" "repo.activity.title.prs_n") .Activity.MergedPRCount) (.i18n.Tr (TrN .i18n.Lang .Activity.MergedPRAuthorCount "repo.activity.title.user_1" "repo.activity.title.user_n") .Activity.MergedPRAuthorCount) }}
 | 
									{{.i18n.Tr "repo.activity.title.prs_merged_by"
 | 
				
			||||||
 | 
										(.i18n.TrN .Activity.MergedPRCount "repo.activity.title.prs_1" "repo.activity.title.prs_n" .Activity.MergedPRCount)
 | 
				
			||||||
 | 
										(.i18n.TrN .Activity.MergedPRAuthorCount "repo.activity.title.user_1" "repo.activity.title.user_n" .Activity.MergedPRAuthorCount)
 | 
				
			||||||
 | 
									}}
 | 
				
			||||||
			</h4>
 | 
								</h4>
 | 
				
			||||||
			<div class="list">
 | 
								<div class="list">
 | 
				
			||||||
				{{range .Activity.MergedPRs}}
 | 
									{{range .Activity.MergedPRs}}
 | 
				
			||||||
@@ -153,7 +159,10 @@
 | 
				
			|||||||
		{{if gt .Activity.OpenedPRCount 0}}
 | 
							{{if gt .Activity.OpenedPRCount 0}}
 | 
				
			||||||
			<h4 class="ui horizontal divider header" id="proposed-pull-requests">
 | 
								<h4 class="ui horizontal divider header" id="proposed-pull-requests">
 | 
				
			||||||
				<span class="text">{{svg "octicon-git-branch"}}</span>
 | 
									<span class="text">{{svg "octicon-git-branch"}}</span>
 | 
				
			||||||
				{{.i18n.Tr "repo.activity.title.prs_opened_by" (.i18n.Tr (TrN .i18n.Lang .Activity.OpenedPRCount "repo.activity.title.prs_1" "repo.activity.title.prs_n") .Activity.OpenedPRCount) (.i18n.Tr (TrN .i18n.Lang .Activity.OpenedPRAuthorCount "repo.activity.title.user_1" "repo.activity.title.user_n") .Activity.OpenedPRAuthorCount) }}
 | 
									{{.i18n.Tr "repo.activity.title.prs_opened_by"
 | 
				
			||||||
 | 
										(.i18n.TrN .Activity.OpenedPRCount "repo.activity.title.prs_1" "repo.activity.title.prs_n" .Activity.OpenedPRCount)
 | 
				
			||||||
 | 
										(.i18n.TrN .Activity.OpenedPRAuthorCount "repo.activity.title.user_1" "repo.activity.title.user_n" .Activity.OpenedPRAuthorCount)
 | 
				
			||||||
 | 
									}}
 | 
				
			||||||
			</h4>
 | 
								</h4>
 | 
				
			||||||
			<div class="list">
 | 
								<div class="list">
 | 
				
			||||||
				{{range .Activity.OpenedPRs}}
 | 
									{{range .Activity.OpenedPRs}}
 | 
				
			||||||
@@ -169,7 +178,10 @@
 | 
				
			|||||||
		{{if gt .Activity.ClosedIssueCount 0}}
 | 
							{{if gt .Activity.ClosedIssueCount 0}}
 | 
				
			||||||
			<h4 class="ui horizontal divider header" id="closed-issues">
 | 
								<h4 class="ui horizontal divider header" id="closed-issues">
 | 
				
			||||||
				<span class="text">{{svg "octicon-issue-closed"}}</span>
 | 
									<span class="text">{{svg "octicon-issue-closed"}}</span>
 | 
				
			||||||
				{{.i18n.Tr "repo.activity.title.issues_closed_from" (.i18n.Tr (TrN .i18n.Lang .Activity.ClosedIssueCount "repo.activity.title.issues_1" "repo.activity.title.issues_n") .Activity.ClosedIssueCount) (.i18n.Tr (TrN .i18n.Lang .Activity.ClosedIssueAuthorCount "repo.activity.title.user_1" "repo.activity.title.user_n") .Activity.ClosedIssueAuthorCount) }}
 | 
									{{.i18n.Tr "repo.activity.title.issues_closed_from"
 | 
				
			||||||
 | 
										(.i18n.TrN .Activity.ClosedIssueCount "repo.activity.title.issues_1" "repo.activity.title.issues_n" .Activity.ClosedIssueCount)
 | 
				
			||||||
 | 
										(.i18n.TrN .Activity.ClosedIssueAuthorCount "repo.activity.title.user_1" "repo.activity.title.user_n" .Activity.ClosedIssueAuthorCount)
 | 
				
			||||||
 | 
									}}
 | 
				
			||||||
			</h4>
 | 
								</h4>
 | 
				
			||||||
			<div class="list">
 | 
								<div class="list">
 | 
				
			||||||
				{{range .Activity.ClosedIssues}}
 | 
									{{range .Activity.ClosedIssues}}
 | 
				
			||||||
@@ -185,7 +197,10 @@
 | 
				
			|||||||
		{{if gt .Activity.OpenedIssueCount 0}}
 | 
							{{if gt .Activity.OpenedIssueCount 0}}
 | 
				
			||||||
			<h4 class="ui horizontal divider header" id="new-issues">
 | 
								<h4 class="ui horizontal divider header" id="new-issues">
 | 
				
			||||||
				<span class="text">{{svg "octicon-issue-opened"}}</span>
 | 
									<span class="text">{{svg "octicon-issue-opened"}}</span>
 | 
				
			||||||
				{{.i18n.Tr "repo.activity.title.issues_created_by" (.i18n.Tr (TrN .i18n.Lang .Activity.OpenedIssueCount "repo.activity.title.issues_1" "repo.activity.title.issues_n") .Activity.OpenedIssueCount) (.i18n.Tr (TrN .i18n.Lang .Activity.OpenedIssueAuthorCount "repo.activity.title.user_1" "repo.activity.title.user_n") .Activity.OpenedIssueAuthorCount) }}
 | 
									{{.i18n.Tr "repo.activity.title.issues_created_by"
 | 
				
			||||||
 | 
										(.i18n.TrN .Activity.OpenedIssueCount "repo.activity.title.issues_1" "repo.activity.title.issues_n" .Activity.OpenedIssueCount)
 | 
				
			||||||
 | 
										(.i18n.TrN .Activity.OpenedIssueAuthorCount "repo.activity.title.user_1" "repo.activity.title.user_n" .Activity.OpenedIssueAuthorCount)
 | 
				
			||||||
 | 
									}}
 | 
				
			||||||
			</h4>
 | 
								</h4>
 | 
				
			||||||
			<div class="list">
 | 
								<div class="list">
 | 
				
			||||||
				{{range .Activity.OpenedIssues}}
 | 
									{{range .Activity.OpenedIssues}}
 | 
				
			||||||
@@ -201,7 +216,7 @@
 | 
				
			|||||||
		{{if gt .Activity.UnresolvedIssueCount 0}}
 | 
							{{if gt .Activity.UnresolvedIssueCount 0}}
 | 
				
			||||||
			<h4 class="ui horizontal divider header" id="unresolved-conversations">
 | 
								<h4 class="ui horizontal divider header" id="unresolved-conversations">
 | 
				
			||||||
				<span class="text">{{svg "octicon-comment-discussion"}}</span>
 | 
									<span class="text">{{svg "octicon-comment-discussion"}}</span>
 | 
				
			||||||
				{{.i18n.Tr (TrN .i18n.Lang .Activity.UnresolvedIssueCount "repo.activity.title.unresolved_conv_1" "repo.activity.title.unresolved_conv_n") .Activity.UnresolvedIssueCount }}
 | 
									{{.i18n.TrN .Activity.UnresolvedIssueCount "repo.activity.title.unresolved_conv_1" "repo.activity.title.unresolved_conv_n" .Activity.UnresolvedIssueCount}}
 | 
				
			||||||
			</h4>
 | 
								</h4>
 | 
				
			||||||
			<div class="text center desc">
 | 
								<div class="text center desc">
 | 
				
			||||||
				{{.i18n.Tr "repo.activity.unresolved_conv_desc"}}
 | 
									{{.i18n.Tr "repo.activity.unresolved_conv_desc"}}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,7 @@
 | 
				
			|||||||
		<div class="file-header-left df ac">
 | 
							<div class="file-header-left df ac">
 | 
				
			||||||
			<div class="file-info text grey normal mono">
 | 
								<div class="file-info text grey normal mono">
 | 
				
			||||||
				<div class="file-info-entry">
 | 
									<div class="file-info-entry">
 | 
				
			||||||
					{{.NumLines}} {{.i18n.Tr (TrN .i18n.Lang .NumLines "repo.line" "repo.lines") }}
 | 
										{{.NumLines}} {{.i18n.TrN .NumLines "repo.line" "repo.lines"}}
 | 
				
			||||||
				</div>
 | 
									</div>
 | 
				
			||||||
				<div class="file-info-entry">{{FileSize .FileSize}}</div>
 | 
									<div class="file-info-entry">{{FileSize .FileSize}}</div>
 | 
				
			||||||
			</div>
 | 
								</div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,7 +16,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
					{{if not .CanCreateRepo}}
 | 
										{{if not .CanCreateRepo}}
 | 
				
			||||||
						<div class="ui negative message">
 | 
											<div class="ui negative message">
 | 
				
			||||||
							<p>{{.i18n.Tr (TrN .i18n.Lang .MaxCreationLimit "repo.form.reach_limit_of_creation_1" "repo.form.reach_limit_of_creation_n") .MaxCreationLimit}}</p>
 | 
												<p>{{.i18n.TrN .MaxCreationLimit "repo.form.reach_limit_of_creation_1" "repo.form.reach_limit_of_creation_n" .MaxCreationLimit}}</p>
 | 
				
			||||||
						</div>
 | 
											</div>
 | 
				
			||||||
					{{end}}
 | 
										{{end}}
 | 
				
			||||||
					<div class="inline required field {{if .Err_Owner}}error{{end}}">
 | 
										<div class="inline required field {{if .Err_Owner}}error{{end}}">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -187,9 +187,9 @@
 | 
				
			|||||||
				<span class="text grey">
 | 
									<span class="text grey">
 | 
				
			||||||
					<a class="author" href="{{.Poster.HomeLink}}">{{.Poster.GetDisplayName}}</a>
 | 
										<a class="author" href="{{.Poster.HomeLink}}">{{.Poster.GetDisplayName}}</a>
 | 
				
			||||||
					{{if and .AddedLabels (not .RemovedLabels)}}
 | 
										{{if and .AddedLabels (not .RemovedLabels)}}
 | 
				
			||||||
						{{$.i18n.Tr (TrN $.i18n.Lang (len .AddedLabels) "repo.issues.add_label" "repo.issues.add_labels") (RenderLabels .AddedLabels) $createdStr | Safe}}
 | 
											{{$.i18n.TrN (len .AddedLabels) "repo.issues.add_label" "repo.issues.add_labels" (RenderLabels .AddedLabels) $createdStr | Safe}}
 | 
				
			||||||
					{{else if and (not .AddedLabels) .RemovedLabels}}
 | 
										{{else if and (not .AddedLabels) .RemovedLabels}}
 | 
				
			||||||
						{{$.i18n.Tr (TrN $.i18n.Lang (len .RemovedLabels) "repo.issues.remove_label" "repo.issues.remove_labels") (RenderLabels .RemovedLabels) $createdStr | Safe}}
 | 
											{{$.i18n.TrN (len .RemovedLabels) "repo.issues.remove_label" "repo.issues.remove_labels" (RenderLabels .RemovedLabels) $createdStr | Safe}}
 | 
				
			||||||
					{{else}}
 | 
										{{else}}
 | 
				
			||||||
						{{$.i18n.Tr "repo.issues.add_remove_labels" (RenderLabels .AddedLabels) (RenderLabels .RemovedLabels) $createdStr | Safe}}
 | 
											{{$.i18n.Tr "repo.issues.add_remove_labels" (RenderLabels .AddedLabels) (RenderLabels .RemovedLabels) $createdStr | Safe}}
 | 
				
			||||||
					{{end}}
 | 
										{{end}}
 | 
				
			||||||
@@ -716,7 +716,7 @@
 | 
				
			|||||||
				{{ if .IsForcePush }}
 | 
									{{ if .IsForcePush }}
 | 
				
			||||||
					{{$.i18n.Tr "repo.issues.force_push_codes" ($.Issue.PullRequest.HeadBranch|Escape) (ShortSha .OldCommit) (($.Issue.Repo.CommitLink .OldCommit)|Escape)  (ShortSha .NewCommit) (($.Issue.Repo.CommitLink .NewCommit)|Escape) $createdStr | Safe}}
 | 
										{{$.i18n.Tr "repo.issues.force_push_codes" ($.Issue.PullRequest.HeadBranch|Escape) (ShortSha .OldCommit) (($.Issue.Repo.CommitLink .OldCommit)|Escape)  (ShortSha .NewCommit) (($.Issue.Repo.CommitLink .NewCommit)|Escape) $createdStr | Safe}}
 | 
				
			||||||
				{{else}}
 | 
									{{else}}
 | 
				
			||||||
					{{$.i18n.Tr (TrN $.i18n.Lang (len .Commits) "repo.issues.push_commit_1" "repo.issues.push_commits_n") (len .Commits) $createdStr | Safe}}
 | 
										{{$.i18n.TrN (len .Commits) "repo.issues.push_commit_1" "repo.issues.push_commits_n" (len .Commits) $createdStr | Safe}}
 | 
				
			||||||
				{{end}}
 | 
									{{end}}
 | 
				
			||||||
			</span>
 | 
								</span>
 | 
				
			||||||
		</div>
 | 
							</div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -224,7 +224,7 @@
 | 
				
			|||||||
				{{else if .IsBlockedByChangedProtectedFiles}}
 | 
									{{else if .IsBlockedByChangedProtectedFiles}}
 | 
				
			||||||
					<div class="item">
 | 
										<div class="item">
 | 
				
			||||||
						<i class="icon icon-octicon">{{svg "octicon-x" 16}}</i>
 | 
											<i class="icon icon-octicon">{{svg "octicon-x" 16}}</i>
 | 
				
			||||||
						{{$.i18n.Tr (TrN $.i18n.Lang $.ChangedProtectedFilesNum "repo.pulls.blocked_by_changed_protected_files_1" "repo.pulls.blocked_by_changed_protected_files_n") | Safe }}
 | 
											{{$.i18n.TrN $.ChangedProtectedFilesNum "repo.pulls.blocked_by_changed_protected_files_1" "repo.pulls.blocked_by_changed_protected_files_n" | Safe }}
 | 
				
			||||||
						<div class="ui ordered list">
 | 
											<div class="ui ordered list">
 | 
				
			||||||
							{{range .ChangedProtectedFiles}}
 | 
												{{range .ChangedProtectedFiles}}
 | 
				
			||||||
								<div data-value="-" class="item">{{.}}</div>
 | 
													<div data-value="-" class="item">{{.}}</div>
 | 
				
			||||||
@@ -555,7 +555,7 @@
 | 
				
			|||||||
				{{else if .IsBlockedByChangedProtectedFiles}}
 | 
									{{else if .IsBlockedByChangedProtectedFiles}}
 | 
				
			||||||
					<div class="item text red">
 | 
										<div class="item text red">
 | 
				
			||||||
						<i class="icon icon-octicon">{{svg "octicon-x" 16}}</i>
 | 
											<i class="icon icon-octicon">{{svg "octicon-x" 16}}</i>
 | 
				
			||||||
						{{$.i18n.Tr (TrN $.i18n.Lang $.ChangedProtectedFilesNum "repo.pulls.blocked_by_changed_protected_files_1" "repo.pulls.blocked_by_changed_protected_files_n") | Safe }}
 | 
											{{$.i18n.TrN $.ChangedProtectedFilesNum "repo.pulls.blocked_by_changed_protected_files_1" "repo.pulls.blocked_by_changed_protected_files_n" | Safe }}
 | 
				
			||||||
						<div class="ui ordered list">
 | 
											<div class="ui ordered list">
 | 
				
			||||||
							{{range .ChangedProtectedFiles}}
 | 
												{{range .ChangedProtectedFiles}}
 | 
				
			||||||
								<div data-value="-" class="item">{{.}}</div>
 | 
													<div data-value="-" class="item">{{.}}</div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,14 +3,14 @@
 | 
				
			|||||||
		<div class="ui two horizontal center link list">
 | 
							<div class="ui two horizontal center link list">
 | 
				
			||||||
			{{if and (.Permission.CanRead $.UnitTypeCode) (not .IsEmptyRepo)}}
 | 
								{{if and (.Permission.CanRead $.UnitTypeCode) (not .IsEmptyRepo)}}
 | 
				
			||||||
				<div class="item{{if .PageIsCommits}} active{{end}}">
 | 
									<div class="item{{if .PageIsCommits}} active{{end}}">
 | 
				
			||||||
					<a class="ui" href="{{.RepoLink}}/commits/{{.BranchNameSubURL}}">{{svg "octicon-history"}} <b>{{.CommitsCount}}</b> {{.i18n.Tr (TrN .i18n.Lang .CommitsCount "repo.commit" "repo.commits") }}</a>
 | 
										<a class="ui" href="{{.RepoLink}}/commits/{{.BranchNameSubURL}}">{{svg "octicon-history"}} <b>{{.CommitsCount}}</b> {{.i18n.TrN .CommitsCount "repo.commit" "repo.commits"}}</a>
 | 
				
			||||||
				</div>
 | 
									</div>
 | 
				
			||||||
				<div class="item{{if .PageIsBranches}} active{{end}}">
 | 
									<div class="item{{if .PageIsBranches}} active{{end}}">
 | 
				
			||||||
					<a class="ui" href="{{.RepoLink}}/branches">{{svg "octicon-git-branch"}} <b>{{.BranchesCount}}</b> {{.i18n.Tr (TrN .i18n.Lang .BranchesCount "repo.branch" "repo.branches") }}</a>
 | 
										<a class="ui" href="{{.RepoLink}}/branches">{{svg "octicon-git-branch"}} <b>{{.BranchesCount}}</b> {{.i18n.TrN .BranchesCount "repo.branch" "repo.branches"}}</a>
 | 
				
			||||||
				</div>
 | 
									</div>
 | 
				
			||||||
				{{if $.Permission.CanRead $.UnitTypeCode}}
 | 
									{{if $.Permission.CanRead $.UnitTypeCode}}
 | 
				
			||||||
					<div class="item">
 | 
										<div class="item">
 | 
				
			||||||
						<a class="ui" href="{{.RepoLink}}/tags">{{svg "octicon-tag"}} <b>{{.NumTags}}</b> {{.i18n.Tr (TrN .i18n.Lang .NumTags "repo.tag" "repo.tags") }}</a>
 | 
											<a class="ui" href="{{.RepoLink}}/tags">{{svg "octicon-tag"}} <b>{{.NumTags}}</b> {{.i18n.TrN .NumTags "repo.tag" "repo.tags"}}</a>
 | 
				
			||||||
					</div>
 | 
										</div>
 | 
				
			||||||
				{{end}}
 | 
									{{end}}
 | 
				
			||||||
				<div class="item">
 | 
									<div class="item">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,7 +13,7 @@
 | 
				
			|||||||
					{{end}}
 | 
										{{end}}
 | 
				
			||||||
					{{if .NumLinesSet}}
 | 
										{{if .NumLinesSet}}
 | 
				
			||||||
						<div class="file-info-entry">
 | 
											<div class="file-info-entry">
 | 
				
			||||||
							{{.NumLines}} {{.i18n.Tr (TrN .i18n.Lang .NumLines "repo.line" "repo.lines") }}
 | 
												{{.NumLines}} {{.i18n.TrN .NumLines "repo.line" "repo.lines"}}
 | 
				
			||||||
						</div>
 | 
											</div>
 | 
				
			||||||
					{{end}}
 | 
										{{end}}
 | 
				
			||||||
					{{if .FileSize}}
 | 
										{{if .FileSize}}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -91,25 +91,25 @@
 | 
				
			|||||||
						{{if gt $approveOfficial 0}}
 | 
											{{if gt $approveOfficial 0}}
 | 
				
			||||||
							<span class="approvals df ac">
 | 
												<span class="approvals df ac">
 | 
				
			||||||
								{{svg "octicon-check" 14 "mr-1"}}
 | 
													{{svg "octicon-check" 14 "mr-1"}}
 | 
				
			||||||
								{{$.i18n.Tr (TrN $.i18n.Lang $approveOfficial "repo.pulls.approve_count_1" "repo.pulls.approve_count_n") $approveOfficial}}
 | 
													{{$.i18n.TrN $approveOfficial "repo.pulls.approve_count_1" "repo.pulls.approve_count_n" $approveOfficial}}
 | 
				
			||||||
							</span>
 | 
												</span>
 | 
				
			||||||
						{{end}}
 | 
											{{end}}
 | 
				
			||||||
						{{if gt $rejectOfficial 0}}
 | 
											{{if gt $rejectOfficial 0}}
 | 
				
			||||||
							<span class="rejects df ac">
 | 
												<span class="rejects df ac">
 | 
				
			||||||
								{{svg "octicon-diff" 14 "mr-2"}}
 | 
													{{svg "octicon-diff" 14 "mr-2"}}
 | 
				
			||||||
								{{$.i18n.Tr (TrN $.i18n.Lang $rejectOfficial "repo.pulls.reject_count_1" "repo.pulls.reject_count_n") $rejectOfficial}}
 | 
													{{$.i18n.TrN $rejectOfficial "repo.pulls.reject_count_1" "repo.pulls.reject_count_n" $rejectOfficial}}
 | 
				
			||||||
							</span>
 | 
												</span>
 | 
				
			||||||
						{{end}}
 | 
											{{end}}
 | 
				
			||||||
						{{if gt $waitingOfficial 0}}
 | 
											{{if gt $waitingOfficial 0}}
 | 
				
			||||||
							<span class="waiting df ac">
 | 
												<span class="waiting df ac">
 | 
				
			||||||
								{{svg "octicon-eye" 14 "mr-2"}}
 | 
													{{svg "octicon-eye" 14 "mr-2"}}
 | 
				
			||||||
								{{$.i18n.Tr (TrN $.i18n.Lang $waitingOfficial "repo.pulls.waiting_count_1" "repo.pulls.waiting_count_n") $waitingOfficial}}
 | 
													{{$.i18n.TrN $waitingOfficial "repo.pulls.waiting_count_1" "repo.pulls.waiting_count_n" $waitingOfficial}}
 | 
				
			||||||
							</span>
 | 
												</span>
 | 
				
			||||||
						{{end}}
 | 
											{{end}}
 | 
				
			||||||
						{{if and (not .PullRequest.HasMerged) (gt (len .PullRequest.ConflictedFiles) 0)}}
 | 
											{{if and (not .PullRequest.HasMerged) (gt (len .PullRequest.ConflictedFiles) 0)}}
 | 
				
			||||||
							<span class="conflicting df ac">
 | 
												<span class="conflicting df ac">
 | 
				
			||||||
								{{svg "octicon-x" 14}}
 | 
													{{svg "octicon-x" 14}}
 | 
				
			||||||
								{{$.i18n.Tr (TrN $.i18n.Lang (len .PullRequest.ConflictedFiles) "repo.pulls.num_conflicting_files_1" "repo.pulls.num_conflicting_files_n") (len .PullRequest.ConflictedFiles)}}
 | 
													{{$.i18n.TrN (len .PullRequest.ConflictedFiles) "repo.pulls.num_conflicting_files_1" "repo.pulls.num_conflicting_files_n" (len .PullRequest.ConflictedFiles)}}
 | 
				
			||||||
							</span>
 | 
												</span>
 | 
				
			||||||
						{{end}}
 | 
											{{end}}
 | 
				
			||||||
					{{end}}
 | 
										{{end}}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user