mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-09-07 15:33:26 +00:00
Merge pull request '[gitea] cherry-pick' (#2353) from earl-warren/forgejo:wip-gitea-cherry-pick into forgejo
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/2353 Reviewed-by: Otto <otto@codeberg.org>
This commit is contained in:
commit
7ea1ef2c2b
94 changed files with 478 additions and 377 deletions
|
@ -289,6 +289,7 @@ package "code.gitea.io/gitea/modules/timeutil"
|
||||||
|
|
||||||
package "code.gitea.io/gitea/modules/translation"
|
package "code.gitea.io/gitea/modules/translation"
|
||||||
func (MockLocale).Language
|
func (MockLocale).Language
|
||||||
|
func (MockLocale).TrString
|
||||||
func (MockLocale).Tr
|
func (MockLocale).Tr
|
||||||
func (MockLocale).TrN
|
func (MockLocale).TrN
|
||||||
func (MockLocale).PrettyNumber
|
func (MockLocale).PrettyNumber
|
||||||
|
|
15
.gitpod.yml
15
.gitpod.yml
|
@ -10,10 +10,19 @@ tasks:
|
||||||
- name: Run backend
|
- name: Run backend
|
||||||
command: |
|
command: |
|
||||||
gp sync-await setup
|
gp sync-await setup
|
||||||
if [ ! -f custom/conf/app.ini ]
|
|
||||||
then
|
# Get the URL and extract the domain
|
||||||
|
url=$(gp url 3000)
|
||||||
|
domain=$(echo $url | awk -F[/:] '{print $4}')
|
||||||
|
|
||||||
|
if [ -f custom/conf/app.ini ]; then
|
||||||
|
sed -i "s|^ROOT_URL =.*|ROOT_URL = ${url}/|" custom/conf/app.ini
|
||||||
|
sed -i "s|^DOMAIN =.*|DOMAIN = ${domain}|" custom/conf/app.ini
|
||||||
|
sed -i "s|^SSH_DOMAIN =.*|SSH_DOMAIN = ${domain}|" custom/conf/app.ini
|
||||||
|
sed -i "s|^NO_REPLY_ADDRESS =.*|SSH_DOMAIN = noreply.${domain}|" custom/conf/app.ini
|
||||||
|
else
|
||||||
mkdir -p custom/conf/
|
mkdir -p custom/conf/
|
||||||
echo -e "[server]\nROOT_URL=$(gp url 3000)/" > custom/conf/app.ini
|
echo -e "[server]\nROOT_URL = ${url}/" > custom/conf/app.ini
|
||||||
echo -e "\n[database]\nDB_TYPE = sqlite3\nPATH = $GITPOD_REPO_ROOT/data/gitea.db" >> custom/conf/app.ini
|
echo -e "\n[database]\nDB_TYPE = sqlite3\nPATH = $GITPOD_REPO_ROOT/data/gitea.db" >> custom/conf/app.ini
|
||||||
fi
|
fi
|
||||||
export TAGS="sqlite sqlite_unlock_notify"
|
export TAGS="sqlite sqlite_unlock_notify"
|
||||||
|
|
|
@ -97,7 +97,7 @@ func (r *ActionRunner) StatusName() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ActionRunner) StatusLocaleName(lang translation.Locale) string {
|
func (r *ActionRunner) StatusLocaleName(lang translation.Locale) string {
|
||||||
return lang.Tr("actions.runners.status." + r.StatusName())
|
return lang.TrString("actions.runners.status." + r.StatusName())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ActionRunner) IsOnline() bool {
|
func (r *ActionRunner) IsOnline() bool {
|
||||||
|
|
|
@ -41,7 +41,7 @@ func (s Status) String() string {
|
||||||
|
|
||||||
// LocaleString returns the locale string name of the Status
|
// LocaleString returns the locale string name of the Status
|
||||||
func (s Status) LocaleString(lang translation.Locale) string {
|
func (s Status) LocaleString(lang translation.Locale) string {
|
||||||
return lang.Tr("actions.status." + s.String())
|
return lang.TrString("actions.status." + s.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsDone returns whether the Status is final
|
// IsDone returns whether the Status is final
|
||||||
|
|
|
@ -194,7 +194,7 @@ func (status *CommitStatus) APIURL(ctx context.Context) string {
|
||||||
|
|
||||||
// LocaleString returns the locale string name of the Status
|
// LocaleString returns the locale string name of the Status
|
||||||
func (status *CommitStatus) LocaleString(lang translation.Locale) string {
|
func (status *CommitStatus) LocaleString(lang translation.Locale) string {
|
||||||
return lang.Tr("repo.commitstatus." + status.State.String())
|
return lang.TrString("repo.commitstatus." + status.State.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// CalcCommitStatus returns commit status state via some status, the commit statues should order by id desc
|
// CalcCommitStatus returns commit status state via some status, the commit statues should order by id desc
|
||||||
|
|
|
@ -210,12 +210,12 @@ const (
|
||||||
|
|
||||||
// LocaleString returns the locale string name of the role
|
// LocaleString returns the locale string name of the role
|
||||||
func (r RoleInRepo) LocaleString(lang translation.Locale) string {
|
func (r RoleInRepo) LocaleString(lang translation.Locale) string {
|
||||||
return lang.Tr("repo.issues.role." + string(r))
|
return lang.TrString("repo.issues.role." + string(r))
|
||||||
}
|
}
|
||||||
|
|
||||||
// LocaleHelper returns the locale tooltip of the role
|
// LocaleHelper returns the locale tooltip of the role
|
||||||
func (r RoleInRepo) LocaleHelper(lang translation.Locale) string {
|
func (r RoleInRepo) LocaleHelper(lang translation.Locale) string {
|
||||||
return lang.Tr("repo.issues.role." + string(r) + "_helper")
|
return lang.TrString("repo.issues.role." + string(r) + "_helper")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Comment represents a comment in commit and issue page.
|
// Comment represents a comment in commit and issue page.
|
||||||
|
|
|
@ -225,6 +225,10 @@ func (comments CommentList) loadAssignees(ctx context.Context) error {
|
||||||
|
|
||||||
for _, comment := range comments {
|
for _, comment := range comments {
|
||||||
comment.Assignee = assignees[comment.AssigneeID]
|
comment.Assignee = assignees[comment.AssigneeID]
|
||||||
|
if comment.Assignee == nil {
|
||||||
|
comment.AssigneeID = user_model.GhostUserID
|
||||||
|
comment.Assignee = user_model.NewGhostUser()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,6 +159,14 @@ func (r *Review) LoadReviewer(ctx context.Context) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
r.Reviewer, err = user_model.GetPossibleUserByID(ctx, r.ReviewerID)
|
r.Reviewer, err = user_model.GetPossibleUserByID(ctx, r.ReviewerID)
|
||||||
|
if err != nil {
|
||||||
|
if !user_model.IsErrUserNotExist(err) {
|
||||||
|
return fmt.Errorf("GetPossibleUserByID [%d]: %w", r.ReviewerID, err)
|
||||||
|
}
|
||||||
|
r.ReviewerID = user_model.GhostUserID
|
||||||
|
r.Reviewer = user_model.NewGhostUser()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -594,9 +594,7 @@ func GetOrgByID(ctx context.Context, id int64) (*Organization, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
} else if !has {
|
||||||
return nil, user_model.ErrUserNotExist{
|
return nil, user_model.ErrUserNotExist{
|
||||||
UID: id,
|
UID: id,
|
||||||
Name: "",
|
|
||||||
KeyID: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return u, nil
|
return u, nil
|
||||||
|
|
|
@ -17,13 +17,13 @@ const (
|
||||||
func (o OwnerType) LocaleString(locale translation.Locale) string {
|
func (o OwnerType) LocaleString(locale translation.Locale) string {
|
||||||
switch o {
|
switch o {
|
||||||
case OwnerTypeSystemGlobal:
|
case OwnerTypeSystemGlobal:
|
||||||
return locale.Tr("concept_system_global")
|
return locale.TrString("concept_system_global")
|
||||||
case OwnerTypeIndividual:
|
case OwnerTypeIndividual:
|
||||||
return locale.Tr("concept_user_individual")
|
return locale.TrString("concept_user_individual")
|
||||||
case OwnerTypeRepository:
|
case OwnerTypeRepository:
|
||||||
return locale.Tr("concept_code_repository")
|
return locale.TrString("concept_code_repository")
|
||||||
case OwnerTypeOrganization:
|
case OwnerTypeOrganization:
|
||||||
return locale.Tr("concept_user_organization")
|
return locale.TrString("concept_user_organization")
|
||||||
}
|
}
|
||||||
return locale.Tr("unknown")
|
return locale.TrString("unknown")
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,9 +31,8 @@ func (err ErrUserAlreadyExist) Unwrap() error {
|
||||||
|
|
||||||
// ErrUserNotExist represents a "UserNotExist" kind of error.
|
// ErrUserNotExist represents a "UserNotExist" kind of error.
|
||||||
type ErrUserNotExist struct {
|
type ErrUserNotExist struct {
|
||||||
UID int64
|
UID int64
|
||||||
Name string
|
Name string
|
||||||
KeyID int64
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsErrUserNotExist checks if an error is a ErrUserNotExist.
|
// IsErrUserNotExist checks if an error is a ErrUserNotExist.
|
||||||
|
@ -43,7 +42,7 @@ func IsErrUserNotExist(err error) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (err ErrUserNotExist) Error() string {
|
func (err ErrUserNotExist) Error() string {
|
||||||
return fmt.Sprintf("user does not exist [uid: %d, name: %s, keyid: %d]", err.UID, err.Name, err.KeyID)
|
return fmt.Sprintf("user does not exist [uid: %d, name: %s]", err.UID, err.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unwrap unwraps this error as a ErrNotExist error
|
// Unwrap unwraps this error as a ErrNotExist error
|
||||||
|
|
|
@ -847,7 +847,7 @@ func GetUserByID(ctx context.Context, id int64) (*User, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
} else if !has {
|
||||||
return nil, ErrUserNotExist{id, "", 0}
|
return nil, ErrUserNotExist{UID: id}
|
||||||
}
|
}
|
||||||
return u, nil
|
return u, nil
|
||||||
}
|
}
|
||||||
|
@ -897,14 +897,14 @@ func GetPossibleUserByIDs(ctx context.Context, ids []int64) ([]*User, error) {
|
||||||
// GetUserByNameCtx returns user by given name.
|
// GetUserByNameCtx returns user by given name.
|
||||||
func GetUserByName(ctx context.Context, name string) (*User, error) {
|
func GetUserByName(ctx context.Context, name string) (*User, error) {
|
||||||
if len(name) == 0 {
|
if len(name) == 0 {
|
||||||
return nil, ErrUserNotExist{0, name, 0}
|
return nil, ErrUserNotExist{Name: name}
|
||||||
}
|
}
|
||||||
u := &User{LowerName: strings.ToLower(name), Type: UserTypeIndividual}
|
u := &User{LowerName: strings.ToLower(name), Type: UserTypeIndividual}
|
||||||
has, err := db.GetEngine(ctx).Get(u)
|
has, err := db.GetEngine(ctx).Get(u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
} else if !has {
|
||||||
return nil, ErrUserNotExist{0, name, 0}
|
return nil, ErrUserNotExist{Name: name}
|
||||||
}
|
}
|
||||||
return u, nil
|
return u, nil
|
||||||
}
|
}
|
||||||
|
@ -1045,7 +1045,7 @@ func ValidateCommitsWithEmails(ctx context.Context, oldCommits []*git.Commit) []
|
||||||
// GetUserByEmail returns the user object by given e-mail if exists.
|
// GetUserByEmail returns the user object by given e-mail if exists.
|
||||||
func GetUserByEmail(ctx context.Context, email string) (*User, error) {
|
func GetUserByEmail(ctx context.Context, email string) (*User, error) {
|
||||||
if len(email) == 0 {
|
if len(email) == 0 {
|
||||||
return nil, ErrUserNotExist{0, email, 0}
|
return nil, ErrUserNotExist{Name: email}
|
||||||
}
|
}
|
||||||
|
|
||||||
email = strings.ToLower(email)
|
email = strings.ToLower(email)
|
||||||
|
@ -1072,7 +1072,7 @@ func GetUserByEmail(ctx context.Context, email string) (*User, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, ErrUserNotExist{0, email, 0}
|
return nil, ErrUserNotExist{Name: email}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUser checks if a user already exists
|
// GetUser checks if a user already exists
|
||||||
|
@ -1083,7 +1083,7 @@ func GetUser(ctx context.Context, user *User) (bool, error) {
|
||||||
// GetUserByOpenID returns the user object by given OpenID if exists.
|
// GetUserByOpenID returns the user object by given OpenID if exists.
|
||||||
func GetUserByOpenID(ctx context.Context, uri string) (*User, error) {
|
func GetUserByOpenID(ctx context.Context, uri string) (*User, error) {
|
||||||
if len(uri) == 0 {
|
if len(uri) == 0 {
|
||||||
return nil, ErrUserNotExist{0, uri, 0}
|
return nil, ErrUserNotExist{Name: uri}
|
||||||
}
|
}
|
||||||
|
|
||||||
uri, err := openid.Normalize(uri)
|
uri, err := openid.Normalize(uri)
|
||||||
|
@ -1103,7 +1103,7 @@ func GetUserByOpenID(ctx context.Context, uri string) (*User, error) {
|
||||||
return GetUserByID(ctx, oid.UID)
|
return GetUserByID(ctx, oid.UID)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, ErrUserNotExist{0, uri, 0}
|
return nil, ErrUserNotExist{Name: uri}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAdminUser returns the first administrator
|
// GetAdminUser returns the first administrator
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"errors"
|
"errors"
|
||||||
|
"html/template"
|
||||||
"math/big"
|
"math/big"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -121,15 +122,15 @@ func Generate(n int) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuildComplexityError builds the error message when password complexity checks fail
|
// BuildComplexityError builds the error message when password complexity checks fail
|
||||||
func BuildComplexityError(locale translation.Locale) string {
|
func BuildComplexityError(locale translation.Locale) template.HTML {
|
||||||
var buffer bytes.Buffer
|
var buffer bytes.Buffer
|
||||||
buffer.WriteString(locale.Tr("form.password_complexity"))
|
buffer.WriteString(locale.TrString("form.password_complexity"))
|
||||||
buffer.WriteString("<ul>")
|
buffer.WriteString("<ul>")
|
||||||
for _, c := range requiredList {
|
for _, c := range requiredList {
|
||||||
buffer.WriteString("<li>")
|
buffer.WriteString("<li>")
|
||||||
buffer.WriteString(locale.Tr(c.TrNameOne))
|
buffer.WriteString(locale.TrString(c.TrNameOne))
|
||||||
buffer.WriteString("</li>")
|
buffer.WriteString("</li>")
|
||||||
}
|
}
|
||||||
buffer.WriteString("</ul>")
|
buffer.WriteString("</ul>")
|
||||||
return buffer.String()
|
return template.HTML(buffer.String())
|
||||||
}
|
}
|
||||||
|
|
|
@ -173,7 +173,7 @@ func (e *escapeStreamer) ambiguousRune(r, c rune) error {
|
||||||
Val: "ambiguous-code-point",
|
Val: "ambiguous-code-point",
|
||||||
}, html.Attribute{
|
}, html.Attribute{
|
||||||
Key: "data-tooltip-content",
|
Key: "data-tooltip-content",
|
||||||
Val: e.locale.Tr("repo.ambiguous_character", r, c),
|
Val: e.locale.TrString("repo.ambiguous_character", r, c),
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -247,7 +247,7 @@ func APIContexter() func(http.Handler) http.Handler {
|
||||||
// NotFound handles 404s for APIContext
|
// NotFound handles 404s for APIContext
|
||||||
// String will replace message, errors will be added to a slice
|
// String will replace message, errors will be added to a slice
|
||||||
func (ctx *APIContext) NotFound(objs ...any) {
|
func (ctx *APIContext) NotFound(objs ...any) {
|
||||||
message := ctx.Tr("error.not_found")
|
message := ctx.Locale.TrString("error.not_found")
|
||||||
var errors []string
|
var errors []string
|
||||||
for _, obj := range objs {
|
for _, obj := range objs {
|
||||||
// Ignore nil
|
// Ignore nil
|
||||||
|
|
|
@ -6,6 +6,7 @@ package context
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
@ -286,11 +287,11 @@ func (b *Base) cleanUp() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Base) Tr(msg string, args ...any) string {
|
func (b *Base) Tr(msg string, args ...any) template.HTML {
|
||||||
return b.Locale.Tr(msg, args...)
|
return b.Locale.Tr(msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Base) TrN(cnt any, key1, keyN string, args ...any) string {
|
func (b *Base) TrN(cnt any, key1, keyN string, args ...any) template.HTML {
|
||||||
return b.Locale.TrN(cnt, key1, keyN, args...)
|
return b.Locale.TrN(cnt, key1, keyN, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ package context
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"html"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -71,16 +71,6 @@ func init() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// TrHTMLEscapeArgs runs ".Locale.Tr()" but pre-escapes all arguments with html.EscapeString.
|
|
||||||
// This is useful if the locale message is intended to only produce HTML content.
|
|
||||||
func (ctx *Context) TrHTMLEscapeArgs(msg string, args ...string) string {
|
|
||||||
trArgs := make([]any, len(args))
|
|
||||||
for i, arg := range args {
|
|
||||||
trArgs[i] = html.EscapeString(arg)
|
|
||||||
}
|
|
||||||
return ctx.Locale.Tr(msg, trArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
type webContextKeyType struct{}
|
type webContextKeyType struct{}
|
||||||
|
|
||||||
var WebContextKey = webContextKeyType{}
|
var WebContextKey = webContextKeyType{}
|
||||||
|
@ -253,6 +243,13 @@ func (ctx *Context) JSONOK() {
|
||||||
ctx.JSON(http.StatusOK, map[string]any{"ok": true}) // this is only a dummy response, frontend seldom uses it
|
ctx.JSON(http.StatusOK, map[string]any{"ok": true}) // this is only a dummy response, frontend seldom uses it
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Context) JSONError(msg string) {
|
func (ctx *Context) JSONError(msg any) {
|
||||||
ctx.JSON(http.StatusBadRequest, map[string]any{"errorMessage": msg})
|
switch v := msg.(type) {
|
||||||
|
case string:
|
||||||
|
ctx.JSON(http.StatusBadRequest, map[string]any{"errorMessage": v, "renderFormat": "text"})
|
||||||
|
case template.HTML:
|
||||||
|
ctx.JSON(http.StatusBadRequest, map[string]any{"errorMessage": v, "renderFormat": "html"})
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("unsupported type: %T", msg))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,12 +98,11 @@ func (ctx *Context) RenderToString(name base.TplName, data map[string]any) (stri
|
||||||
}
|
}
|
||||||
|
|
||||||
// RenderWithErr used for page has form validation but need to prompt error to users.
|
// RenderWithErr used for page has form validation but need to prompt error to users.
|
||||||
func (ctx *Context) RenderWithErr(msg string, tpl base.TplName, form any) {
|
func (ctx *Context) RenderWithErr(msg any, tpl base.TplName, form any) {
|
||||||
if form != nil {
|
if form != nil {
|
||||||
middleware.AssignForm(form, ctx.Data)
|
middleware.AssignForm(form, ctx.Data)
|
||||||
}
|
}
|
||||||
ctx.Flash.ErrorMsg = msg
|
ctx.Flash.Error(msg, true)
|
||||||
ctx.Data["Flash"] = ctx.Flash
|
|
||||||
ctx.HTML(http.StatusOK, tpl)
|
ctx.HTML(http.StatusOK, tpl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ package context
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html"
|
"html"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -110,7 +111,7 @@ func (r *Repository) AllUnitsEnabled(ctx context.Context) bool {
|
||||||
func RepoMustNotBeArchived() func(ctx *Context) {
|
func RepoMustNotBeArchived() func(ctx *Context) {
|
||||||
return func(ctx *Context) {
|
return func(ctx *Context) {
|
||||||
if ctx.Repo.Repository.IsArchived {
|
if ctx.Repo.Repository.IsArchived {
|
||||||
ctx.NotFound("IsArchived", fmt.Errorf(ctx.Tr("repo.archive.title")))
|
ctx.NotFound("IsArchived", errors.New(ctx.Locale.TrString("repo.archive.title")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,9 +123,9 @@ func guessDelimiter(data []byte) rune {
|
||||||
func FormatError(err error, locale translation.Locale) (string, error) {
|
func FormatError(err error, locale translation.Locale) (string, error) {
|
||||||
if perr, ok := err.(*stdcsv.ParseError); ok {
|
if perr, ok := err.(*stdcsv.ParseError); ok {
|
||||||
if perr.Err == stdcsv.ErrFieldCount {
|
if perr.Err == stdcsv.ErrFieldCount {
|
||||||
return locale.Tr("repo.error.csv.invalid_field_count", perr.Line), nil
|
return locale.TrString("repo.error.csv.invalid_field_count", perr.Line), nil
|
||||||
}
|
}
|
||||||
return locale.Tr("repo.error.csv.unexpected", perr.Line, perr.Column), nil
|
return locale.TrString("repo.error.csv.unexpected", perr.Line, perr.Column), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", err
|
return "", err
|
||||||
|
|
|
@ -804,7 +804,7 @@ func fullIssuePatternProcessor(ctx *RenderContext, node *html.Node) {
|
||||||
// indicate that in the text by appending (comment)
|
// indicate that in the text by appending (comment)
|
||||||
if m[4] != -1 && m[5] != -1 {
|
if m[4] != -1 && m[5] != -1 {
|
||||||
if locale, ok := ctx.Ctx.Value(translation.ContextKey).(translation.Locale); ok {
|
if locale, ok := ctx.Ctx.Value(translation.ContextKey).(translation.Locale); ok {
|
||||||
text += " " + locale.Tr("repo.from_comment")
|
text += " " + locale.TrString("repo.from_comment")
|
||||||
} else {
|
} else {
|
||||||
text += " (comment)"
|
text += " (comment)"
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ func createTOCNode(toc []markup.Header, lang string, detailsAttrs map[string]str
|
||||||
details.SetAttributeString(k, []byte(v))
|
details.SetAttributeString(k, []byte(v))
|
||||||
}
|
}
|
||||||
|
|
||||||
summary.AppendChild(summary, ast.NewString([]byte(translation.NewLocale(lang).Tr("toc"))))
|
summary.AppendChild(summary, ast.NewString([]byte(translation.NewLocale(lang).TrString("toc"))))
|
||||||
details.AppendChild(details, summary)
|
details.AppendChild(details, summary)
|
||||||
ul := ast.NewList('-')
|
ul := ast.NewList('-')
|
||||||
details.AppendChild(details, ul)
|
details.AppendChild(details, ul)
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
package migration
|
package migration
|
||||||
|
|
||||||
// Messenger is a formatting function similar to i18n.Tr
|
// Messenger is a formatting function similar to i18n.TrString
|
||||||
type Messenger func(key string, args ...any)
|
type Messenger func(key string, args ...any)
|
||||||
|
|
||||||
// NilMessenger represents an empty formatting function
|
// NilMessenger represents an empty formatting function
|
||||||
|
|
|
@ -36,7 +36,7 @@ func NewFuncMap() template.FuncMap {
|
||||||
"dict": dict, // it's lowercase because this name has been widely used. Our other functions should have uppercase names.
|
"dict": dict, // it's lowercase because this name has been widely used. Our other functions should have uppercase names.
|
||||||
"Eval": Eval,
|
"Eval": Eval,
|
||||||
"Safe": Safe,
|
"Safe": Safe,
|
||||||
"Escape": html.EscapeString,
|
"Escape": Escape,
|
||||||
"QueryEscape": url.QueryEscape,
|
"QueryEscape": url.QueryEscape,
|
||||||
"JSEscape": template.JSEscapeString,
|
"JSEscape": template.JSEscapeString,
|
||||||
"Str2html": Str2html, // TODO: rename it to SanitizeHTML
|
"Str2html": Str2html, // TODO: rename it to SanitizeHTML
|
||||||
|
@ -162,7 +162,7 @@ func NewFuncMap() template.FuncMap {
|
||||||
"RenderCodeBlock": RenderCodeBlock,
|
"RenderCodeBlock": RenderCodeBlock,
|
||||||
"RenderIssueTitle": RenderIssueTitle,
|
"RenderIssueTitle": RenderIssueTitle,
|
||||||
"RenderEmoji": RenderEmoji,
|
"RenderEmoji": RenderEmoji,
|
||||||
"RenderEmojiPlain": emoji.ReplaceAliases,
|
"RenderEmojiPlain": RenderEmojiPlain,
|
||||||
"ReactionToEmoji": ReactionToEmoji,
|
"ReactionToEmoji": ReactionToEmoji,
|
||||||
|
|
||||||
"RenderMarkdownToHtml": RenderMarkdownToHtml,
|
"RenderMarkdownToHtml": RenderMarkdownToHtml,
|
||||||
|
@ -183,13 +183,45 @@ func NewFuncMap() template.FuncMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Safe render raw as HTML
|
// Safe render raw as HTML
|
||||||
func Safe(raw string) template.HTML {
|
func Safe(s any) template.HTML {
|
||||||
return template.HTML(raw)
|
switch v := s.(type) {
|
||||||
|
case string:
|
||||||
|
return template.HTML(v)
|
||||||
|
case template.HTML:
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
panic(fmt.Sprintf("unexpected type %T", s))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Str2html render Markdown text to HTML
|
// Str2html sanitizes the input by pre-defined markdown rules
|
||||||
func Str2html(raw string) template.HTML {
|
func Str2html(s any) template.HTML {
|
||||||
return template.HTML(markup.Sanitize(raw))
|
switch v := s.(type) {
|
||||||
|
case string:
|
||||||
|
return template.HTML(markup.Sanitize(v))
|
||||||
|
case template.HTML:
|
||||||
|
return template.HTML(markup.Sanitize(string(v)))
|
||||||
|
}
|
||||||
|
panic(fmt.Sprintf("unexpected type %T", s))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Escape(s any) template.HTML {
|
||||||
|
switch v := s.(type) {
|
||||||
|
case string:
|
||||||
|
return template.HTML(html.EscapeString(v))
|
||||||
|
case template.HTML:
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
panic(fmt.Sprintf("unexpected type %T", s))
|
||||||
|
}
|
||||||
|
|
||||||
|
func RenderEmojiPlain(s any) any {
|
||||||
|
switch v := s.(type) {
|
||||||
|
case string:
|
||||||
|
return emoji.ReplaceAliases(v)
|
||||||
|
case template.HTML:
|
||||||
|
return template.HTML(emoji.ReplaceAliases(string(v)))
|
||||||
|
}
|
||||||
|
panic(fmt.Sprintf("unexpected type %T", s))
|
||||||
}
|
}
|
||||||
|
|
||||||
// DotEscape wraps a dots in names with ZWJ [U+200D] in order to prevent autolinkers from detecting these as urls
|
// DotEscape wraps a dots in names with ZWJ [U+200D] in order to prevent autolinkers from detecting these as urls
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
package templates
|
package templates
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"html/template"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
|
@ -17,8 +18,14 @@ func NewStringUtils() *StringUtils {
|
||||||
return &stringUtils
|
return &stringUtils
|
||||||
}
|
}
|
||||||
|
|
||||||
func (su *StringUtils) HasPrefix(s, prefix string) bool {
|
func (su *StringUtils) HasPrefix(s any, prefix string) bool {
|
||||||
return strings.HasPrefix(s, prefix)
|
switch v := s.(type) {
|
||||||
|
case string:
|
||||||
|
return strings.HasPrefix(v, prefix)
|
||||||
|
case template.HTML:
|
||||||
|
return strings.HasPrefix(string(v), prefix)
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (su *StringUtils) Contains(s, substr string) bool {
|
func (su *StringUtils) Contains(s, substr string) bool {
|
||||||
|
|
20
modules/templates/util_string_test.go
Normal file
20
modules/templates/util_string_test.go
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// Copyright Earl Warren <contact@earl-warren.org>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package templates
|
||||||
|
|
||||||
|
import (
|
||||||
|
"html/template"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_StringUtils_HasPrefix(t *testing.T) {
|
||||||
|
su := &StringUtils{}
|
||||||
|
assert.True(t, su.HasPrefix("ABC", "A"))
|
||||||
|
assert.False(t, su.HasPrefix("ABC", "B"))
|
||||||
|
assert.True(t, su.HasPrefix(template.HTML("ABC"), "A"))
|
||||||
|
assert.False(t, su.HasPrefix(template.HTML("ABC"), "B"))
|
||||||
|
assert.False(t, su.HasPrefix(123, "B"))
|
||||||
|
}
|
|
@ -28,54 +28,54 @@ func computeTimeDiffFloor(diff int64, lang translation.Locale) (int64, string) {
|
||||||
switch {
|
switch {
|
||||||
case diff <= 0:
|
case diff <= 0:
|
||||||
diff = 0
|
diff = 0
|
||||||
diffStr = lang.Tr("tool.now")
|
diffStr = lang.TrString("tool.now")
|
||||||
case diff < 2:
|
case diff < 2:
|
||||||
diff = 0
|
diff = 0
|
||||||
diffStr = lang.Tr("tool.1s")
|
diffStr = lang.TrString("tool.1s")
|
||||||
case diff < 1*Minute:
|
case diff < 1*Minute:
|
||||||
diffStr = lang.Tr("tool.seconds", diff)
|
diffStr = lang.TrString("tool.seconds", diff)
|
||||||
diff = 0
|
diff = 0
|
||||||
|
|
||||||
case diff < 2*Minute:
|
case diff < 2*Minute:
|
||||||
diff -= 1 * Minute
|
diff -= 1 * Minute
|
||||||
diffStr = lang.Tr("tool.1m")
|
diffStr = lang.TrString("tool.1m")
|
||||||
case diff < 1*Hour:
|
case diff < 1*Hour:
|
||||||
diffStr = lang.Tr("tool.minutes", diff/Minute)
|
diffStr = lang.TrString("tool.minutes", diff/Minute)
|
||||||
diff -= diff / Minute * Minute
|
diff -= diff / Minute * Minute
|
||||||
|
|
||||||
case diff < 2*Hour:
|
case diff < 2*Hour:
|
||||||
diff -= 1 * Hour
|
diff -= 1 * Hour
|
||||||
diffStr = lang.Tr("tool.1h")
|
diffStr = lang.TrString("tool.1h")
|
||||||
case diff < 1*Day:
|
case diff < 1*Day:
|
||||||
diffStr = lang.Tr("tool.hours", diff/Hour)
|
diffStr = lang.TrString("tool.hours", diff/Hour)
|
||||||
diff -= diff / Hour * Hour
|
diff -= diff / Hour * Hour
|
||||||
|
|
||||||
case diff < 2*Day:
|
case diff < 2*Day:
|
||||||
diff -= 1 * Day
|
diff -= 1 * Day
|
||||||
diffStr = lang.Tr("tool.1d")
|
diffStr = lang.TrString("tool.1d")
|
||||||
case diff < 1*Week:
|
case diff < 1*Week:
|
||||||
diffStr = lang.Tr("tool.days", diff/Day)
|
diffStr = lang.TrString("tool.days", diff/Day)
|
||||||
diff -= diff / Day * Day
|
diff -= diff / Day * Day
|
||||||
|
|
||||||
case diff < 2*Week:
|
case diff < 2*Week:
|
||||||
diff -= 1 * Week
|
diff -= 1 * Week
|
||||||
diffStr = lang.Tr("tool.1w")
|
diffStr = lang.TrString("tool.1w")
|
||||||
case diff < 1*Month:
|
case diff < 1*Month:
|
||||||
diffStr = lang.Tr("tool.weeks", diff/Week)
|
diffStr = lang.TrString("tool.weeks", diff/Week)
|
||||||
diff -= diff / Week * Week
|
diff -= diff / Week * Week
|
||||||
|
|
||||||
case diff < 2*Month:
|
case diff < 2*Month:
|
||||||
diff -= 1 * Month
|
diff -= 1 * Month
|
||||||
diffStr = lang.Tr("tool.1mon")
|
diffStr = lang.TrString("tool.1mon")
|
||||||
case diff < 1*Year:
|
case diff < 1*Year:
|
||||||
diffStr = lang.Tr("tool.months", diff/Month)
|
diffStr = lang.TrString("tool.months", diff/Month)
|
||||||
diff -= diff / Month * Month
|
diff -= diff / Month * Month
|
||||||
|
|
||||||
case diff < 2*Year:
|
case diff < 2*Year:
|
||||||
diff -= 1 * Year
|
diff -= 1 * Year
|
||||||
diffStr = lang.Tr("tool.1y")
|
diffStr = lang.TrString("tool.1y")
|
||||||
default:
|
default:
|
||||||
diffStr = lang.Tr("tool.years", diff/Year)
|
diffStr = lang.TrString("tool.years", diff/Year)
|
||||||
diff -= (diff / Year) * Year
|
diff -= (diff / Year) * Year
|
||||||
}
|
}
|
||||||
return diff, diffStr
|
return diff, diffStr
|
||||||
|
@ -97,10 +97,10 @@ func timeSincePro(then, now time.Time, lang translation.Locale) string {
|
||||||
diff := now.Unix() - then.Unix()
|
diff := now.Unix() - then.Unix()
|
||||||
|
|
||||||
if then.After(now) {
|
if then.After(now) {
|
||||||
return lang.Tr("tool.future")
|
return lang.TrString("tool.future")
|
||||||
}
|
}
|
||||||
if diff == 0 {
|
if diff == 0 {
|
||||||
return lang.Tr("tool.now")
|
return lang.TrString("tool.now")
|
||||||
}
|
}
|
||||||
|
|
||||||
var timeStr, diffStr string
|
var timeStr, diffStr string
|
||||||
|
@ -115,7 +115,7 @@ func timeSincePro(then, now time.Time, lang translation.Locale) string {
|
||||||
return strings.TrimPrefix(timeStr, ", ")
|
return strings.TrimPrefix(timeStr, ", ")
|
||||||
}
|
}
|
||||||
|
|
||||||
func timeSinceUnix(then, now time.Time, lang translation.Locale) template.HTML {
|
func timeSinceUnix(then, now time.Time, _ translation.Locale) template.HTML {
|
||||||
friendlyText := then.Format("2006-01-02 15:04:05 -07:00")
|
friendlyText := then.Format("2006-01-02 15:04:05 -07:00")
|
||||||
|
|
||||||
// document: https://github.com/github/relative-time-element
|
// document: https://github.com/github/relative-time-element
|
||||||
|
|
|
@ -4,26 +4,25 @@
|
||||||
package i18n
|
package i18n
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
var DefaultLocales = NewLocaleStore()
|
var DefaultLocales = NewLocaleStore()
|
||||||
|
|
||||||
type Locale interface {
|
type Locale interface {
|
||||||
// Tr translates a given key and arguments for a language
|
// TrString translates a given key and arguments for a language
|
||||||
Tr(trKey string, trArgs ...any) string
|
TrString(trKey string, trArgs ...any) string
|
||||||
// Has reports if a locale has a translation for a given key
|
// TrHTML translates a given key and arguments for a language, string arguments are escaped to HTML
|
||||||
Has(trKey string) bool
|
TrHTML(trKey string, trArgs ...any) template.HTML
|
||||||
|
// HasKey reports if a locale has a translation for a given key
|
||||||
|
HasKey(trKey string) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// LocaleStore provides the functions common to all locale stores
|
// LocaleStore provides the functions common to all locale stores
|
||||||
type LocaleStore interface {
|
type LocaleStore interface {
|
||||||
io.Closer
|
io.Closer
|
||||||
|
|
||||||
// Tr translates a given key and arguments for a language
|
|
||||||
Tr(lang, trKey string, trArgs ...any) string
|
|
||||||
// Has reports if a locale has a translation for a given key
|
|
||||||
Has(lang, trKey string) bool
|
|
||||||
// SetDefaultLang sets the default language to fall back to
|
// SetDefaultLang sets the default language to fall back to
|
||||||
SetDefaultLang(lang string)
|
SetDefaultLang(lang string)
|
||||||
// ListLangNameDesc provides paired slices of language names to descriptors
|
// ListLangNameDesc provides paired slices of language names to descriptors
|
||||||
|
@ -45,7 +44,7 @@ func ResetDefaultLocales() {
|
||||||
DefaultLocales = NewLocaleStore()
|
DefaultLocales = NewLocaleStore()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLocales returns the locale from the default locales
|
// GetLocale returns the locale from the default locales
|
||||||
func GetLocale(lang string) (Locale, bool) {
|
func GetLocale(lang string) (Locale, bool) {
|
||||||
return DefaultLocales.Locale(lang)
|
return DefaultLocales.Locale(lang)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ fmt = %[1]s %[2]s
|
||||||
|
|
||||||
[section]
|
[section]
|
||||||
sub = Sub String
|
sub = Sub String
|
||||||
mixed = test value; <span style="color: red\; background: none;">more text</span>
|
mixed = test value; <span style="color: red\; background: none;">%s</span>
|
||||||
`)
|
`)
|
||||||
|
|
||||||
testData2 := []byte(`
|
testData2 := []byte(`
|
||||||
|
@ -32,29 +32,33 @@ sub = Changed Sub String
|
||||||
assert.NoError(t, ls.AddLocaleByIni("lang2", "Lang2", testData2, nil))
|
assert.NoError(t, ls.AddLocaleByIni("lang2", "Lang2", testData2, nil))
|
||||||
ls.SetDefaultLang("lang1")
|
ls.SetDefaultLang("lang1")
|
||||||
|
|
||||||
result := ls.Tr("lang1", "fmt", "a", "b")
|
lang1, _ := ls.Locale("lang1")
|
||||||
|
lang2, _ := ls.Locale("lang2")
|
||||||
|
|
||||||
|
result := lang1.TrString("fmt", "a", "b")
|
||||||
assert.Equal(t, "a b", result)
|
assert.Equal(t, "a b", result)
|
||||||
|
|
||||||
result = ls.Tr("lang2", "fmt", "a", "b")
|
result = lang2.TrString("fmt", "a", "b")
|
||||||
assert.Equal(t, "b a", result)
|
assert.Equal(t, "b a", result)
|
||||||
|
|
||||||
result = ls.Tr("lang1", "section.sub")
|
result = lang1.TrString("section.sub")
|
||||||
assert.Equal(t, "Sub String", result)
|
assert.Equal(t, "Sub String", result)
|
||||||
|
|
||||||
result = ls.Tr("lang2", "section.sub")
|
result = lang2.TrString("section.sub")
|
||||||
assert.Equal(t, "Changed Sub String", result)
|
assert.Equal(t, "Changed Sub String", result)
|
||||||
|
|
||||||
result = ls.Tr("", ".dot.name")
|
langNone, _ := ls.Locale("none")
|
||||||
|
result = langNone.TrString(".dot.name")
|
||||||
assert.Equal(t, "Dot Name", result)
|
assert.Equal(t, "Dot Name", result)
|
||||||
|
|
||||||
result = ls.Tr("lang2", "section.mixed")
|
result2 := lang2.TrHTML("section.mixed", "a&b")
|
||||||
assert.Equal(t, `test value; <span style="color: red; background: none;">more text</span>`, result)
|
assert.EqualValues(t, `test value; <span style="color: red; background: none;">a&b</span>`, result2)
|
||||||
|
|
||||||
langs, descs := ls.ListLangNameDesc()
|
langs, descs := ls.ListLangNameDesc()
|
||||||
assert.ElementsMatch(t, []string{"lang1", "lang2"}, langs)
|
assert.ElementsMatch(t, []string{"lang1", "lang2"}, langs)
|
||||||
assert.ElementsMatch(t, []string{"Lang1", "Lang2"}, descs)
|
assert.ElementsMatch(t, []string{"Lang1", "Lang2"}, descs)
|
||||||
|
|
||||||
found := ls.Has("lang1", "no-such")
|
found := lang1.HasKey("no-such")
|
||||||
assert.False(t, found)
|
assert.False(t, found)
|
||||||
assert.NoError(t, ls.Close())
|
assert.NoError(t, ls.Close())
|
||||||
}
|
}
|
||||||
|
@ -72,9 +76,10 @@ c=22
|
||||||
|
|
||||||
ls := NewLocaleStore()
|
ls := NewLocaleStore()
|
||||||
assert.NoError(t, ls.AddLocaleByIni("lang1", "Lang1", testData1, testData2))
|
assert.NoError(t, ls.AddLocaleByIni("lang1", "Lang1", testData1, testData2))
|
||||||
assert.Equal(t, "11", ls.Tr("lang1", "a"))
|
lang1, _ := ls.Locale("lang1")
|
||||||
assert.Equal(t, "21", ls.Tr("lang1", "b"))
|
assert.Equal(t, "11", lang1.TrString("a"))
|
||||||
assert.Equal(t, "22", ls.Tr("lang1", "c"))
|
assert.Equal(t, "21", lang1.TrString("b"))
|
||||||
|
assert.Equal(t, "22", lang1.TrString("c"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLocaleStoreQuirks(t *testing.T) {
|
func TestLocaleStoreQuirks(t *testing.T) {
|
||||||
|
@ -110,8 +115,9 @@ func TestLocaleStoreQuirks(t *testing.T) {
|
||||||
for _, testData := range testDataList {
|
for _, testData := range testDataList {
|
||||||
ls := NewLocaleStore()
|
ls := NewLocaleStore()
|
||||||
err := ls.AddLocaleByIni("lang1", "Lang1", []byte("a="+testData.in), nil)
|
err := ls.AddLocaleByIni("lang1", "Lang1", []byte("a="+testData.in), nil)
|
||||||
|
lang1, _ := ls.Locale("lang1")
|
||||||
assert.NoError(t, err, testData.hint)
|
assert.NoError(t, err, testData.hint)
|
||||||
assert.Equal(t, testData.out, ls.Tr("lang1", "a"), testData.hint)
|
assert.Equal(t, testData.out, lang1.TrString("a"), testData.hint)
|
||||||
assert.NoError(t, ls.Close())
|
assert.NoError(t, ls.Close())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,8 @@ package i18n
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"html/template"
|
||||||
|
"slices"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
@ -18,6 +20,8 @@ type locale struct {
|
||||||
idxToMsgMap map[int]string // the map idx is generated by store's trKeyToIdxMap
|
idxToMsgMap map[int]string // the map idx is generated by store's trKeyToIdxMap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ Locale = (*locale)(nil)
|
||||||
|
|
||||||
type localeStore struct {
|
type localeStore struct {
|
||||||
// After initializing has finished, these fields are read-only.
|
// After initializing has finished, these fields are read-only.
|
||||||
langNames []string
|
langNames []string
|
||||||
|
@ -88,20 +92,6 @@ func (store *localeStore) SetDefaultLang(lang string) {
|
||||||
store.defaultLang = lang
|
store.defaultLang = lang
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tr translates content to target language. fall back to default language.
|
|
||||||
func (store *localeStore) Tr(lang, trKey string, trArgs ...any) string {
|
|
||||||
l, _ := store.Locale(lang)
|
|
||||||
|
|
||||||
return l.Tr(trKey, trArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Has returns whether the given language has a translation for the provided key
|
|
||||||
func (store *localeStore) Has(lang, trKey string) bool {
|
|
||||||
l, _ := store.Locale(lang)
|
|
||||||
|
|
||||||
return l.Has(trKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Locale returns the locale for the lang or the default language
|
// Locale returns the locale for the lang or the default language
|
||||||
func (store *localeStore) Locale(lang string) (Locale, bool) {
|
func (store *localeStore) Locale(lang string) (Locale, bool) {
|
||||||
l, found := store.localeMap[lang]
|
l, found := store.localeMap[lang]
|
||||||
|
@ -116,13 +106,11 @@ func (store *localeStore) Locale(lang string) (Locale, bool) {
|
||||||
return l, found
|
return l, found
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close implements io.Closer
|
|
||||||
func (store *localeStore) Close() error {
|
func (store *localeStore) Close() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tr translates content to locale language. fall back to default language.
|
func (l *locale) TrString(trKey string, trArgs ...any) string {
|
||||||
func (l *locale) Tr(trKey string, trArgs ...any) string {
|
|
||||||
format := trKey
|
format := trKey
|
||||||
|
|
||||||
idx, ok := l.store.trKeyToIdxMap[trKey]
|
idx, ok := l.store.trKeyToIdxMap[trKey]
|
||||||
|
@ -144,8 +132,23 @@ func (l *locale) Tr(trKey string, trArgs ...any) string {
|
||||||
return msg
|
return msg
|
||||||
}
|
}
|
||||||
|
|
||||||
// Has returns whether a key is present in this locale or not
|
func (l *locale) TrHTML(trKey string, trArgs ...any) template.HTML {
|
||||||
func (l *locale) Has(trKey string) bool {
|
args := slices.Clone(trArgs)
|
||||||
|
for i, v := range args {
|
||||||
|
switch v := v.(type) {
|
||||||
|
case string:
|
||||||
|
args[i] = template.HTML(template.HTMLEscapeString(v))
|
||||||
|
case fmt.Stringer:
|
||||||
|
args[i] = template.HTMLEscapeString(v.String())
|
||||||
|
default: // int, float, include template.HTML
|
||||||
|
// do nothing, just use it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return template.HTML(l.TrString(trKey, args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasKey returns whether a key is present in this locale or not
|
||||||
|
func (l *locale) HasKey(trKey string) bool {
|
||||||
idx, ok := l.store.trKeyToIdxMap[trKey]
|
idx, ok := l.store.trKeyToIdxMap[trKey]
|
||||||
if !ok {
|
if !ok {
|
||||||
return false
|
return false
|
||||||
|
|
|
@ -3,7 +3,10 @@
|
||||||
|
|
||||||
package translation
|
package translation
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"html/template"
|
||||||
|
)
|
||||||
|
|
||||||
// MockLocale provides a mocked locale without any translations
|
// MockLocale provides a mocked locale without any translations
|
||||||
type MockLocale struct{}
|
type MockLocale struct{}
|
||||||
|
@ -14,12 +17,16 @@ func (l MockLocale) Language() string {
|
||||||
return "en"
|
return "en"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l MockLocale) Tr(s string, _ ...any) string {
|
func (l MockLocale) TrString(s string, _ ...any) string {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l MockLocale) TrN(_cnt any, key1, _keyN string, _args ...any) string {
|
func (l MockLocale) Tr(s string, a ...any) template.HTML {
|
||||||
return key1
|
return template.HTML(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l MockLocale) TrN(cnt any, key1, keyN string, args ...any) template.HTML {
|
||||||
|
return template.HTML(key1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l MockLocale) PrettyNumber(v any) string {
|
func (l MockLocale) PrettyNumber(v any) string {
|
||||||
|
|
|
@ -5,6 +5,7 @@ package translation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"html/template"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -27,8 +28,11 @@ var ContextKey any = &contextKey{}
|
||||||
// Locale represents an interface to translation
|
// Locale represents an interface to translation
|
||||||
type Locale interface {
|
type Locale interface {
|
||||||
Language() string
|
Language() string
|
||||||
Tr(string, ...any) string
|
TrString(string, ...any) string
|
||||||
TrN(cnt any, key1, keyN string, args ...any) string
|
|
||||||
|
Tr(key string, args ...any) template.HTML
|
||||||
|
TrN(cnt any, key1, keyN string, args ...any) template.HTML
|
||||||
|
|
||||||
PrettyNumber(v any) string
|
PrettyNumber(v any) string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,6 +148,8 @@ type locale struct {
|
||||||
msgPrinter *message.Printer
|
msgPrinter *message.Printer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ Locale = (*locale)(nil)
|
||||||
|
|
||||||
// NewLocale return a locale
|
// NewLocale return a locale
|
||||||
func NewLocale(lang string) Locale {
|
func NewLocale(lang string) Locale {
|
||||||
if lock != nil {
|
if lock != nil {
|
||||||
|
@ -216,8 +222,12 @@ var trNLangRules = map[string]func(int64) int{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *locale) Tr(s string, args ...any) template.HTML {
|
||||||
|
return l.TrHTML(s, args...)
|
||||||
|
}
|
||||||
|
|
||||||
// TrN returns translated message for plural text translation
|
// TrN returns translated message for plural text translation
|
||||||
func (l *locale) TrN(cnt any, key1, keyN string, args ...any) string {
|
func (l *locale) TrN(cnt any, key1, keyN string, args ...any) template.HTML {
|
||||||
var c int64
|
var c int64
|
||||||
if t, ok := cnt.(int); ok {
|
if t, ok := cnt.(int); ok {
|
||||||
c = int64(t)
|
c = int64(t)
|
||||||
|
|
|
@ -105,44 +105,44 @@ func Validate(errs binding.Errors, data map[string]any, f Form, l translation.Lo
|
||||||
|
|
||||||
trName := field.Tag.Get("locale")
|
trName := field.Tag.Get("locale")
|
||||||
if len(trName) == 0 {
|
if len(trName) == 0 {
|
||||||
trName = l.Tr("form." + field.Name)
|
trName = l.TrString("form." + field.Name)
|
||||||
} else {
|
} else {
|
||||||
trName = l.Tr(trName)
|
trName = l.TrString(trName)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch errs[0].Classification {
|
switch errs[0].Classification {
|
||||||
case binding.ERR_REQUIRED:
|
case binding.ERR_REQUIRED:
|
||||||
data["ErrorMsg"] = trName + l.Tr("form.require_error")
|
data["ErrorMsg"] = trName + l.TrString("form.require_error")
|
||||||
case binding.ERR_ALPHA_DASH:
|
case binding.ERR_ALPHA_DASH:
|
||||||
data["ErrorMsg"] = trName + l.Tr("form.alpha_dash_error")
|
data["ErrorMsg"] = trName + l.TrString("form.alpha_dash_error")
|
||||||
case binding.ERR_ALPHA_DASH_DOT:
|
case binding.ERR_ALPHA_DASH_DOT:
|
||||||
data["ErrorMsg"] = trName + l.Tr("form.alpha_dash_dot_error")
|
data["ErrorMsg"] = trName + l.TrString("form.alpha_dash_dot_error")
|
||||||
case validation.ErrGitRefName:
|
case validation.ErrGitRefName:
|
||||||
data["ErrorMsg"] = trName + l.Tr("form.git_ref_name_error")
|
data["ErrorMsg"] = trName + l.TrString("form.git_ref_name_error")
|
||||||
case binding.ERR_SIZE:
|
case binding.ERR_SIZE:
|
||||||
data["ErrorMsg"] = trName + l.Tr("form.size_error", GetSize(field))
|
data["ErrorMsg"] = trName + l.TrString("form.size_error", GetSize(field))
|
||||||
case binding.ERR_MIN_SIZE:
|
case binding.ERR_MIN_SIZE:
|
||||||
data["ErrorMsg"] = trName + l.Tr("form.min_size_error", GetMinSize(field))
|
data["ErrorMsg"] = trName + l.TrString("form.min_size_error", GetMinSize(field))
|
||||||
case binding.ERR_MAX_SIZE:
|
case binding.ERR_MAX_SIZE:
|
||||||
data["ErrorMsg"] = trName + l.Tr("form.max_size_error", GetMaxSize(field))
|
data["ErrorMsg"] = trName + l.TrString("form.max_size_error", GetMaxSize(field))
|
||||||
case binding.ERR_EMAIL:
|
case binding.ERR_EMAIL:
|
||||||
data["ErrorMsg"] = trName + l.Tr("form.email_error")
|
data["ErrorMsg"] = trName + l.TrString("form.email_error")
|
||||||
case binding.ERR_URL:
|
case binding.ERR_URL:
|
||||||
data["ErrorMsg"] = trName + l.Tr("form.url_error", errs[0].Message)
|
data["ErrorMsg"] = trName + l.TrString("form.url_error", errs[0].Message)
|
||||||
case binding.ERR_INCLUDE:
|
case binding.ERR_INCLUDE:
|
||||||
data["ErrorMsg"] = trName + l.Tr("form.include_error", GetInclude(field))
|
data["ErrorMsg"] = trName + l.TrString("form.include_error", GetInclude(field))
|
||||||
case validation.ErrGlobPattern:
|
case validation.ErrGlobPattern:
|
||||||
data["ErrorMsg"] = trName + l.Tr("form.glob_pattern_error", errs[0].Message)
|
data["ErrorMsg"] = trName + l.TrString("form.glob_pattern_error", errs[0].Message)
|
||||||
case validation.ErrRegexPattern:
|
case validation.ErrRegexPattern:
|
||||||
data["ErrorMsg"] = trName + l.Tr("form.regex_pattern_error", errs[0].Message)
|
data["ErrorMsg"] = trName + l.TrString("form.regex_pattern_error", errs[0].Message)
|
||||||
case validation.ErrUsername:
|
case validation.ErrUsername:
|
||||||
if setting.Service.AllowDotsInUsernames {
|
if setting.Service.AllowDotsInUsernames {
|
||||||
data["ErrorMsg"] = trName + l.Tr("form.username_error")
|
data["ErrorMsg"] = trName + l.TrString("form.username_error")
|
||||||
} else {
|
} else {
|
||||||
data["ErrorMsg"] = trName + l.Tr("form.username_error_no_dots")
|
data["ErrorMsg"] = trName + l.TrString("form.username_error_no_dots")
|
||||||
}
|
}
|
||||||
case validation.ErrInvalidGroupTeamMap:
|
case validation.ErrInvalidGroupTeamMap:
|
||||||
data["ErrorMsg"] = trName + l.Tr("form.invalid_group_team_map_error", errs[0].Message)
|
data["ErrorMsg"] = trName + l.TrString("form.invalid_group_team_map_error", errs[0].Message)
|
||||||
default:
|
default:
|
||||||
msg := errs[0].Classification
|
msg := errs[0].Classification
|
||||||
if msg != "" && errs[0].Message != "" {
|
if msg != "" && errs[0].Message != "" {
|
||||||
|
@ -151,7 +151,7 @@ func Validate(errs binding.Errors, data map[string]any, f Form, l translation.Lo
|
||||||
|
|
||||||
msg += errs[0].Message
|
msg += errs[0].Message
|
||||||
if msg == "" {
|
if msg == "" {
|
||||||
msg = l.Tr("form.unknown_error")
|
msg = l.TrString("form.unknown_error")
|
||||||
}
|
}
|
||||||
data["ErrorMsg"] = trName + ": " + msg
|
data["ErrorMsg"] = trName + ": " + msg
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,11 @@
|
||||||
|
|
||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import "net/url"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"html/template"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
// Flash represents a one time data transfer between two requests.
|
// Flash represents a one time data transfer between two requests.
|
||||||
type Flash struct {
|
type Flash struct {
|
||||||
|
@ -26,26 +30,36 @@ func (f *Flash) set(name, msg string, current ...bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func flashMsgStringOrHTML(msg any) string {
|
||||||
|
switch v := msg.(type) {
|
||||||
|
case string:
|
||||||
|
return v
|
||||||
|
case template.HTML:
|
||||||
|
return string(v)
|
||||||
|
}
|
||||||
|
panic(fmt.Sprintf("unknown type: %T", msg))
|
||||||
|
}
|
||||||
|
|
||||||
// Error sets error message
|
// Error sets error message
|
||||||
func (f *Flash) Error(msg string, current ...bool) {
|
func (f *Flash) Error(msg any, current ...bool) {
|
||||||
f.ErrorMsg = msg
|
f.ErrorMsg = flashMsgStringOrHTML(msg)
|
||||||
f.set("error", msg, current...)
|
f.set("error", f.ErrorMsg, current...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warning sets warning message
|
// Warning sets warning message
|
||||||
func (f *Flash) Warning(msg string, current ...bool) {
|
func (f *Flash) Warning(msg any, current ...bool) {
|
||||||
f.WarningMsg = msg
|
f.WarningMsg = flashMsgStringOrHTML(msg)
|
||||||
f.set("warning", msg, current...)
|
f.set("warning", f.WarningMsg, current...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Info sets info message
|
// Info sets info message
|
||||||
func (f *Flash) Info(msg string, current ...bool) {
|
func (f *Flash) Info(msg any, current ...bool) {
|
||||||
f.InfoMsg = msg
|
f.InfoMsg = flashMsgStringOrHTML(msg)
|
||||||
f.set("info", msg, current...)
|
f.set("info", f.InfoMsg, current...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Success sets success message
|
// Success sets success message
|
||||||
func (f *Flash) Success(msg string, current ...bool) {
|
func (f *Flash) Success(msg any, current ...bool) {
|
||||||
f.SuccessMsg = msg
|
f.SuccessMsg = flashMsgStringOrHTML(msg)
|
||||||
f.set("success", msg, current...)
|
f.set("success", f.SuccessMsg, current...)
|
||||||
}
|
}
|
||||||
|
|
|
@ -779,13 +779,13 @@ func changeFilesCommitMessage(ctx *context.APIContext, files []*files_service.Ch
|
||||||
}
|
}
|
||||||
message := ""
|
message := ""
|
||||||
if len(createFiles) != 0 {
|
if len(createFiles) != 0 {
|
||||||
message += ctx.Tr("repo.editor.add", strings.Join(createFiles, ", ")+"\n")
|
message += ctx.Locale.TrString("repo.editor.add", strings.Join(createFiles, ", ")+"\n")
|
||||||
}
|
}
|
||||||
if len(updateFiles) != 0 {
|
if len(updateFiles) != 0 {
|
||||||
message += ctx.Tr("repo.editor.update", strings.Join(updateFiles, ", ")+"\n")
|
message += ctx.Locale.TrString("repo.editor.update", strings.Join(updateFiles, ", ")+"\n")
|
||||||
}
|
}
|
||||||
if len(deleteFiles) != 0 {
|
if len(deleteFiles) != 0 {
|
||||||
message += ctx.Tr("repo.editor.delete", strings.Join(deleteFiles, ", "))
|
message += ctx.Locale.TrString("repo.editor.delete", strings.Join(deleteFiles, ", "))
|
||||||
}
|
}
|
||||||
return strings.Trim(message, "\n")
|
return strings.Trim(message, "\n")
|
||||||
}
|
}
|
||||||
|
|
|
@ -395,7 +395,7 @@ func CreateIssueComment(ctx *context.APIContext) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if issue.IsLocked && !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) && !ctx.Doer.IsAdmin {
|
if issue.IsLocked && !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) && !ctx.Doer.IsAdmin {
|
||||||
ctx.Error(http.StatusForbidden, "CreateIssueComment", errors.New(ctx.Tr("repo.issues.comment_on_locked")))
|
ctx.Error(http.StatusForbidden, "CreateIssueComment", errors.New(ctx.Locale.TrString("repo.issues.comment_on_locked")))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -210,16 +210,16 @@ func parseOAuth2Config(form forms.AuthenticationForm) *oauth2.Source {
|
||||||
func parseSSPIConfig(ctx *context.Context, form forms.AuthenticationForm) (*sspi.Source, error) {
|
func parseSSPIConfig(ctx *context.Context, form forms.AuthenticationForm) (*sspi.Source, error) {
|
||||||
if util.IsEmptyString(form.SSPISeparatorReplacement) {
|
if util.IsEmptyString(form.SSPISeparatorReplacement) {
|
||||||
ctx.Data["Err_SSPISeparatorReplacement"] = true
|
ctx.Data["Err_SSPISeparatorReplacement"] = true
|
||||||
return nil, errors.New(ctx.Tr("form.SSPISeparatorReplacement") + ctx.Tr("form.require_error"))
|
return nil, errors.New(ctx.Locale.TrString("form.SSPISeparatorReplacement") + ctx.Locale.TrString("form.require_error"))
|
||||||
}
|
}
|
||||||
if separatorAntiPattern.MatchString(form.SSPISeparatorReplacement) {
|
if separatorAntiPattern.MatchString(form.SSPISeparatorReplacement) {
|
||||||
ctx.Data["Err_SSPISeparatorReplacement"] = true
|
ctx.Data["Err_SSPISeparatorReplacement"] = true
|
||||||
return nil, errors.New(ctx.Tr("form.SSPISeparatorReplacement") + ctx.Tr("form.alpha_dash_dot_error"))
|
return nil, errors.New(ctx.Locale.TrString("form.SSPISeparatorReplacement") + ctx.Locale.TrString("form.alpha_dash_dot_error"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if form.SSPIDefaultLanguage != "" && !langCodePattern.MatchString(form.SSPIDefaultLanguage) {
|
if form.SSPIDefaultLanguage != "" && !langCodePattern.MatchString(form.SSPIDefaultLanguage) {
|
||||||
ctx.Data["Err_SSPIDefaultLanguage"] = true
|
ctx.Data["Err_SSPIDefaultLanguage"] = true
|
||||||
return nil, errors.New(ctx.Tr("form.lang_select_error"))
|
return nil, errors.New(ctx.Locale.TrString("form.lang_select_error"))
|
||||||
}
|
}
|
||||||
|
|
||||||
return &sspi.Source{
|
return &sspi.Source{
|
||||||
|
|
|
@ -37,7 +37,7 @@ func ForgotPasswd(ctx *context.Context) {
|
||||||
ctx.Data["Title"] = ctx.Tr("auth.forgot_password_title")
|
ctx.Data["Title"] = ctx.Tr("auth.forgot_password_title")
|
||||||
|
|
||||||
if setting.MailService == nil {
|
if setting.MailService == nil {
|
||||||
log.Warn(ctx.Tr("auth.disable_forgot_password_mail_admin"))
|
log.Warn("no mail service configured")
|
||||||
ctx.Data["IsResetDisable"] = true
|
ctx.Data["IsResetDisable"] = true
|
||||||
ctx.HTML(http.StatusOK, tplForgotPassword)
|
ctx.HTML(http.StatusOK, tplForgotPassword)
|
||||||
return
|
return
|
||||||
|
|
|
@ -6,6 +6,7 @@ package feed
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"html"
|
"html"
|
||||||
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -80,119 +81,120 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio
|
||||||
|
|
||||||
// title
|
// title
|
||||||
title = act.ActUser.DisplayName() + " "
|
title = act.ActUser.DisplayName() + " "
|
||||||
|
var titleExtra template.HTML
|
||||||
switch act.OpType {
|
switch act.OpType {
|
||||||
case activities_model.ActionCreateRepo:
|
case activities_model.ActionCreateRepo:
|
||||||
title += ctx.TrHTMLEscapeArgs("action.create_repo", act.GetRepoAbsoluteLink(ctx), act.ShortRepoPath(ctx))
|
titleExtra = ctx.Locale.Tr("action.create_repo", act.GetRepoAbsoluteLink(ctx), act.ShortRepoPath(ctx))
|
||||||
link.Href = act.GetRepoAbsoluteLink(ctx)
|
link.Href = act.GetRepoAbsoluteLink(ctx)
|
||||||
case activities_model.ActionRenameRepo:
|
case activities_model.ActionRenameRepo:
|
||||||
title += ctx.TrHTMLEscapeArgs("action.rename_repo", act.GetContent(), act.GetRepoAbsoluteLink(ctx), act.ShortRepoPath(ctx))
|
titleExtra = ctx.Locale.Tr("action.rename_repo", act.GetContent(), act.GetRepoAbsoluteLink(ctx), act.ShortRepoPath(ctx))
|
||||||
link.Href = act.GetRepoAbsoluteLink(ctx)
|
link.Href = act.GetRepoAbsoluteLink(ctx)
|
||||||
case activities_model.ActionCommitRepo:
|
case activities_model.ActionCommitRepo:
|
||||||
link.Href = toBranchLink(ctx, act)
|
link.Href = toBranchLink(ctx, act)
|
||||||
if len(act.Content) != 0 {
|
if len(act.Content) != 0 {
|
||||||
title += ctx.TrHTMLEscapeArgs("action.commit_repo", act.GetRepoAbsoluteLink(ctx), link.Href, act.GetBranch(), act.ShortRepoPath(ctx))
|
titleExtra = ctx.Locale.Tr("action.commit_repo", act.GetRepoAbsoluteLink(ctx), link.Href, act.GetBranch(), act.ShortRepoPath(ctx))
|
||||||
} else {
|
} else {
|
||||||
title += ctx.TrHTMLEscapeArgs("action.create_branch", act.GetRepoAbsoluteLink(ctx), link.Href, act.GetBranch(), act.ShortRepoPath(ctx))
|
titleExtra = ctx.Locale.Tr("action.create_branch", act.GetRepoAbsoluteLink(ctx), link.Href, act.GetBranch(), act.ShortRepoPath(ctx))
|
||||||
}
|
}
|
||||||
case activities_model.ActionCreateIssue:
|
case activities_model.ActionCreateIssue:
|
||||||
link.Href = toIssueLink(ctx, act)
|
link.Href = toIssueLink(ctx, act)
|
||||||
title += ctx.TrHTMLEscapeArgs("action.create_issue", link.Href, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
|
titleExtra = ctx.Locale.Tr("action.create_issue", link.Href, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
|
||||||
case activities_model.ActionCreatePullRequest:
|
case activities_model.ActionCreatePullRequest:
|
||||||
link.Href = toPullLink(ctx, act)
|
link.Href = toPullLink(ctx, act)
|
||||||
title += ctx.TrHTMLEscapeArgs("action.create_pull_request", link.Href, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
|
titleExtra = ctx.Locale.Tr("action.create_pull_request", link.Href, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
|
||||||
case activities_model.ActionTransferRepo:
|
case activities_model.ActionTransferRepo:
|
||||||
link.Href = act.GetRepoAbsoluteLink(ctx)
|
link.Href = act.GetRepoAbsoluteLink(ctx)
|
||||||
title += ctx.TrHTMLEscapeArgs("action.transfer_repo", act.GetContent(), act.GetRepoAbsoluteLink(ctx), act.ShortRepoPath(ctx))
|
titleExtra = ctx.Locale.Tr("action.transfer_repo", act.GetContent(), act.GetRepoAbsoluteLink(ctx), act.ShortRepoPath(ctx))
|
||||||
case activities_model.ActionPushTag:
|
case activities_model.ActionPushTag:
|
||||||
link.Href = toTagLink(ctx, act)
|
link.Href = toTagLink(ctx, act)
|
||||||
title += ctx.TrHTMLEscapeArgs("action.push_tag", act.GetRepoAbsoluteLink(ctx), link.Href, act.GetTag(), act.ShortRepoPath(ctx))
|
titleExtra = ctx.Locale.Tr("action.push_tag", act.GetRepoAbsoluteLink(ctx), link.Href, act.GetTag(), act.ShortRepoPath(ctx))
|
||||||
case activities_model.ActionCommentIssue:
|
case activities_model.ActionCommentIssue:
|
||||||
issueLink := toIssueLink(ctx, act)
|
issueLink := toIssueLink(ctx, act)
|
||||||
if link.Href == "#" {
|
if link.Href == "#" {
|
||||||
link.Href = issueLink
|
link.Href = issueLink
|
||||||
}
|
}
|
||||||
title += ctx.TrHTMLEscapeArgs("action.comment_issue", issueLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
|
titleExtra = ctx.Locale.Tr("action.comment_issue", issueLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
|
||||||
case activities_model.ActionMergePullRequest:
|
case activities_model.ActionMergePullRequest:
|
||||||
pullLink := toPullLink(ctx, act)
|
pullLink := toPullLink(ctx, act)
|
||||||
if link.Href == "#" {
|
if link.Href == "#" {
|
||||||
link.Href = pullLink
|
link.Href = pullLink
|
||||||
}
|
}
|
||||||
title += ctx.TrHTMLEscapeArgs("action.merge_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
|
titleExtra = ctx.Locale.Tr("action.merge_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
|
||||||
case activities_model.ActionAutoMergePullRequest:
|
case activities_model.ActionAutoMergePullRequest:
|
||||||
pullLink := toPullLink(ctx, act)
|
pullLink := toPullLink(ctx, act)
|
||||||
if link.Href == "#" {
|
if link.Href == "#" {
|
||||||
link.Href = pullLink
|
link.Href = pullLink
|
||||||
}
|
}
|
||||||
title += ctx.TrHTMLEscapeArgs("action.auto_merge_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
|
titleExtra = ctx.Locale.Tr("action.auto_merge_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
|
||||||
case activities_model.ActionCloseIssue:
|
case activities_model.ActionCloseIssue:
|
||||||
issueLink := toIssueLink(ctx, act)
|
issueLink := toIssueLink(ctx, act)
|
||||||
if link.Href == "#" {
|
if link.Href == "#" {
|
||||||
link.Href = issueLink
|
link.Href = issueLink
|
||||||
}
|
}
|
||||||
title += ctx.TrHTMLEscapeArgs("action.close_issue", issueLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
|
titleExtra = ctx.Locale.Tr("action.close_issue", issueLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
|
||||||
case activities_model.ActionReopenIssue:
|
case activities_model.ActionReopenIssue:
|
||||||
issueLink := toIssueLink(ctx, act)
|
issueLink := toIssueLink(ctx, act)
|
||||||
if link.Href == "#" {
|
if link.Href == "#" {
|
||||||
link.Href = issueLink
|
link.Href = issueLink
|
||||||
}
|
}
|
||||||
title += ctx.TrHTMLEscapeArgs("action.reopen_issue", issueLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
|
titleExtra = ctx.Locale.Tr("action.reopen_issue", issueLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
|
||||||
case activities_model.ActionClosePullRequest:
|
case activities_model.ActionClosePullRequest:
|
||||||
pullLink := toPullLink(ctx, act)
|
pullLink := toPullLink(ctx, act)
|
||||||
if link.Href == "#" {
|
if link.Href == "#" {
|
||||||
link.Href = pullLink
|
link.Href = pullLink
|
||||||
}
|
}
|
||||||
title += ctx.TrHTMLEscapeArgs("action.close_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
|
titleExtra = ctx.Locale.Tr("action.close_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
|
||||||
case activities_model.ActionReopenPullRequest:
|
case activities_model.ActionReopenPullRequest:
|
||||||
pullLink := toPullLink(ctx, act)
|
pullLink := toPullLink(ctx, act)
|
||||||
if link.Href == "#" {
|
if link.Href == "#" {
|
||||||
link.Href = pullLink
|
link.Href = pullLink
|
||||||
}
|
}
|
||||||
title += ctx.TrHTMLEscapeArgs("action.reopen_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
|
titleExtra = ctx.Locale.Tr("action.reopen_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
|
||||||
case activities_model.ActionDeleteTag:
|
case activities_model.ActionDeleteTag:
|
||||||
link.Href = act.GetRepoAbsoluteLink(ctx)
|
link.Href = act.GetRepoAbsoluteLink(ctx)
|
||||||
title += ctx.TrHTMLEscapeArgs("action.delete_tag", act.GetRepoAbsoluteLink(ctx), act.GetTag(), act.ShortRepoPath(ctx))
|
titleExtra = ctx.Locale.Tr("action.delete_tag", act.GetRepoAbsoluteLink(ctx), act.GetTag(), act.ShortRepoPath(ctx))
|
||||||
case activities_model.ActionDeleteBranch:
|
case activities_model.ActionDeleteBranch:
|
||||||
link.Href = act.GetRepoAbsoluteLink(ctx)
|
link.Href = act.GetRepoAbsoluteLink(ctx)
|
||||||
title += ctx.TrHTMLEscapeArgs("action.delete_branch", act.GetRepoAbsoluteLink(ctx), html.EscapeString(act.GetBranch()), act.ShortRepoPath(ctx))
|
titleExtra = ctx.Locale.Tr("action.delete_branch", act.GetRepoAbsoluteLink(ctx), html.EscapeString(act.GetBranch()), act.ShortRepoPath(ctx))
|
||||||
case activities_model.ActionMirrorSyncPush:
|
case activities_model.ActionMirrorSyncPush:
|
||||||
srcLink := toSrcLink(ctx, act)
|
srcLink := toSrcLink(ctx, act)
|
||||||
if link.Href == "#" {
|
if link.Href == "#" {
|
||||||
link.Href = srcLink
|
link.Href = srcLink
|
||||||
}
|
}
|
||||||
title += ctx.TrHTMLEscapeArgs("action.mirror_sync_push", act.GetRepoAbsoluteLink(ctx), srcLink, act.GetBranch(), act.ShortRepoPath(ctx))
|
titleExtra = ctx.Locale.Tr("action.mirror_sync_push", act.GetRepoAbsoluteLink(ctx), srcLink, act.GetBranch(), act.ShortRepoPath(ctx))
|
||||||
case activities_model.ActionMirrorSyncCreate:
|
case activities_model.ActionMirrorSyncCreate:
|
||||||
srcLink := toSrcLink(ctx, act)
|
srcLink := toSrcLink(ctx, act)
|
||||||
if link.Href == "#" {
|
if link.Href == "#" {
|
||||||
link.Href = srcLink
|
link.Href = srcLink
|
||||||
}
|
}
|
||||||
title += ctx.TrHTMLEscapeArgs("action.mirror_sync_create", act.GetRepoAbsoluteLink(ctx), srcLink, act.GetBranch(), act.ShortRepoPath(ctx))
|
titleExtra = ctx.Locale.Tr("action.mirror_sync_create", act.GetRepoAbsoluteLink(ctx), srcLink, act.GetBranch(), act.ShortRepoPath(ctx))
|
||||||
case activities_model.ActionMirrorSyncDelete:
|
case activities_model.ActionMirrorSyncDelete:
|
||||||
link.Href = act.GetRepoAbsoluteLink(ctx)
|
link.Href = act.GetRepoAbsoluteLink(ctx)
|
||||||
title += ctx.TrHTMLEscapeArgs("action.mirror_sync_delete", act.GetRepoAbsoluteLink(ctx), act.GetBranch(), act.ShortRepoPath(ctx))
|
titleExtra = ctx.Locale.Tr("action.mirror_sync_delete", act.GetRepoAbsoluteLink(ctx), act.GetBranch(), act.ShortRepoPath(ctx))
|
||||||
case activities_model.ActionApprovePullRequest:
|
case activities_model.ActionApprovePullRequest:
|
||||||
pullLink := toPullLink(ctx, act)
|
pullLink := toPullLink(ctx, act)
|
||||||
title += ctx.TrHTMLEscapeArgs("action.approve_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
|
titleExtra = ctx.Locale.Tr("action.approve_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
|
||||||
case activities_model.ActionRejectPullRequest:
|
case activities_model.ActionRejectPullRequest:
|
||||||
pullLink := toPullLink(ctx, act)
|
pullLink := toPullLink(ctx, act)
|
||||||
title += ctx.TrHTMLEscapeArgs("action.reject_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
|
titleExtra = ctx.Locale.Tr("action.reject_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
|
||||||
case activities_model.ActionCommentPull:
|
case activities_model.ActionCommentPull:
|
||||||
pullLink := toPullLink(ctx, act)
|
pullLink := toPullLink(ctx, act)
|
||||||
title += ctx.TrHTMLEscapeArgs("action.comment_pull", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
|
titleExtra = ctx.Locale.Tr("action.comment_pull", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx))
|
||||||
case activities_model.ActionPublishRelease:
|
case activities_model.ActionPublishRelease:
|
||||||
releaseLink := toReleaseLink(ctx, act)
|
releaseLink := toReleaseLink(ctx, act)
|
||||||
if link.Href == "#" {
|
if link.Href == "#" {
|
||||||
link.Href = releaseLink
|
link.Href = releaseLink
|
||||||
}
|
}
|
||||||
title += ctx.TrHTMLEscapeArgs("action.publish_release", act.GetRepoAbsoluteLink(ctx), releaseLink, act.ShortRepoPath(ctx), act.Content)
|
titleExtra = ctx.Locale.Tr("action.publish_release", act.GetRepoAbsoluteLink(ctx), releaseLink, act.ShortRepoPath(ctx), act.Content)
|
||||||
case activities_model.ActionPullReviewDismissed:
|
case activities_model.ActionPullReviewDismissed:
|
||||||
pullLink := toPullLink(ctx, act)
|
pullLink := toPullLink(ctx, act)
|
||||||
title += ctx.TrHTMLEscapeArgs("action.review_dismissed", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx), act.GetIssueInfos()[1])
|
titleExtra = ctx.Locale.Tr("action.review_dismissed", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx), act.GetIssueInfos()[1])
|
||||||
case activities_model.ActionStarRepo:
|
case activities_model.ActionStarRepo:
|
||||||
link.Href = act.GetRepoAbsoluteLink(ctx)
|
link.Href = act.GetRepoAbsoluteLink(ctx)
|
||||||
title += ctx.TrHTMLEscapeArgs("action.starred_repo", act.GetRepoAbsoluteLink(ctx), act.GetRepoPath(ctx))
|
titleExtra = ctx.Locale.Tr("action.starred_repo", act.GetRepoAbsoluteLink(ctx), act.GetRepoPath(ctx))
|
||||||
case activities_model.ActionWatchRepo:
|
case activities_model.ActionWatchRepo:
|
||||||
link.Href = act.GetRepoAbsoluteLink(ctx)
|
link.Href = act.GetRepoAbsoluteLink(ctx)
|
||||||
title += ctx.TrHTMLEscapeArgs("action.watched_repo", act.GetRepoAbsoluteLink(ctx), act.GetRepoPath(ctx))
|
titleExtra = ctx.Locale.Tr("action.watched_repo", act.GetRepoAbsoluteLink(ctx), act.GetRepoPath(ctx))
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unknown action type: %v", act.OpType)
|
return nil, fmt.Errorf("unknown action type: %v", act.OpType)
|
||||||
}
|
}
|
||||||
|
@ -234,7 +236,7 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio
|
||||||
case activities_model.ActionCloseIssue, activities_model.ActionReopenIssue, activities_model.ActionClosePullRequest, activities_model.ActionReopenPullRequest:
|
case activities_model.ActionCloseIssue, activities_model.ActionReopenIssue, activities_model.ActionClosePullRequest, activities_model.ActionReopenPullRequest:
|
||||||
desc = act.GetIssueTitle(ctx)
|
desc = act.GetIssueTitle(ctx)
|
||||||
case activities_model.ActionPullReviewDismissed:
|
case activities_model.ActionPullReviewDismissed:
|
||||||
desc = ctx.Tr("action.review_dismissed_reason") + "\n\n" + act.GetIssueInfos()[2]
|
desc = ctx.Locale.TrString("action.review_dismissed_reason") + "\n\n" + act.GetIssueInfos()[2]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(content) == 0 {
|
if len(content) == 0 {
|
||||||
|
@ -243,7 +245,7 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio
|
||||||
|
|
||||||
// It's a common practice for feed generators to use plain text titles.
|
// It's a common practice for feed generators to use plain text titles.
|
||||||
// See https://codeberg.org/forgejo/forgejo/pulls/1595
|
// See https://codeberg.org/forgejo/forgejo/pulls/1595
|
||||||
plainTitle, err := html2text.FromString(title, html2text.Options{OmitLinks: true})
|
plainTitle, err := html2text.FromString(title+" "+string(titleExtra), html2text.Options{OmitLinks: true})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ func showUserFeed(ctx *context.Context, formatType string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
feed := &feeds.Feed{
|
feed := &feeds.Feed{
|
||||||
Title: ctx.Tr("home.feed_of", ctx.ContextUser.DisplayName()),
|
Title: ctx.Locale.TrString("home.feed_of", ctx.ContextUser.DisplayName()),
|
||||||
Link: &feeds.Link{Href: ctx.ContextUser.HTMLURL()},
|
Link: &feeds.Link{Href: ctx.ContextUser.HTMLURL()},
|
||||||
Description: ctxUserDescription,
|
Description: ctxUserDescription,
|
||||||
Created: time.Now(),
|
Created: time.Now(),
|
||||||
|
|
|
@ -28,10 +28,10 @@ func ShowReleaseFeed(ctx *context.Context, repo *repo_model.Repository, isReleas
|
||||||
var link *feeds.Link
|
var link *feeds.Link
|
||||||
|
|
||||||
if isReleasesOnly {
|
if isReleasesOnly {
|
||||||
title = ctx.Tr("repo.release.releases_for", repo.FullName())
|
title = ctx.Locale.TrString("repo.release.releases_for", repo.FullName())
|
||||||
link = &feeds.Link{Href: repo.HTMLURL() + "/release"}
|
link = &feeds.Link{Href: repo.HTMLURL() + "/release"}
|
||||||
} else {
|
} else {
|
||||||
title = ctx.Tr("repo.release.tags_for", repo.FullName())
|
title = ctx.Locale.TrString("repo.release.tags_for", repo.FullName())
|
||||||
link = &feeds.Link{Href: repo.HTMLURL() + "/tags"}
|
link = &feeds.Link{Href: repo.HTMLURL() + "/tags"}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ func ShowRepoFeed(ctx *context.Context, repo *repo_model.Repository, formatType
|
||||||
}
|
}
|
||||||
|
|
||||||
feed := &feeds.Feed{
|
feed := &feeds.Feed{
|
||||||
Title: ctx.Tr("home.feed_of", repo.FullName()),
|
Title: ctx.Locale.TrString("home.feed_of", repo.FullName()),
|
||||||
Link: &feeds.Link{Href: repo.HTMLURL()},
|
Link: &feeds.Link{Href: repo.HTMLURL()},
|
||||||
Description: repo.Description,
|
Description: repo.Description,
|
||||||
Created: time.Now(),
|
Created: time.Now(),
|
||||||
|
|
|
@ -29,7 +29,7 @@ func Create(ctx *context.Context) {
|
||||||
ctx.Data["Title"] = ctx.Tr("new_org")
|
ctx.Data["Title"] = ctx.Tr("new_org")
|
||||||
ctx.Data["DefaultOrgVisibilityMode"] = setting.Service.DefaultOrgVisibilityMode
|
ctx.Data["DefaultOrgVisibilityMode"] = setting.Service.DefaultOrgVisibilityMode
|
||||||
if !ctx.Doer.CanCreateOrganization() {
|
if !ctx.Doer.CanCreateOrganization() {
|
||||||
ctx.ServerError("Not allowed", errors.New(ctx.Tr("org.form.create_org_not_allowed")))
|
ctx.ServerError("Not allowed", errors.New(ctx.Locale.TrString("org.form.create_org_not_allowed")))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.HTML(http.StatusOK, tplCreateOrg)
|
ctx.HTML(http.StatusOK, tplCreateOrg)
|
||||||
|
@ -41,7 +41,7 @@ func CreatePost(ctx *context.Context) {
|
||||||
ctx.Data["Title"] = ctx.Tr("new_org")
|
ctx.Data["Title"] = ctx.Tr("new_org")
|
||||||
|
|
||||||
if !ctx.Doer.CanCreateOrganization() {
|
if !ctx.Doer.CanCreateOrganization() {
|
||||||
ctx.ServerError("Not allowed", errors.New(ctx.Tr("org.form.create_org_not_allowed")))
|
ctx.ServerError("Not allowed", errors.New(ctx.Locale.TrString("org.form.create_org_not_allowed")))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -353,7 +353,7 @@ func ViewProject(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if boards[0].ID == 0 {
|
if boards[0].ID == 0 {
|
||||||
boards[0].Title = ctx.Tr("repo.projects.type.uncategorized")
|
boards[0].Title = ctx.Locale.TrString("repo.projects.type.uncategorized")
|
||||||
}
|
}
|
||||||
|
|
||||||
issuesMap, err := issues_model.LoadIssuesFromBoardList(ctx, boards)
|
issuesMap, err := issues_model.LoadIssuesFromBoardList(ctx, boards)
|
||||||
|
@ -679,7 +679,7 @@ func MoveIssues(ctx *context.Context) {
|
||||||
board = &project_model.Board{
|
board = &project_model.Board{
|
||||||
ID: 0,
|
ID: 0,
|
||||||
ProjectID: project.ID,
|
ProjectID: project.ID,
|
||||||
Title: ctx.Tr("repo.projects.type.uncategorized"),
|
Title: ctx.Locale.TrString("repo.projects.type.uncategorized"),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
board, err = project_model.GetBoard(ctx, ctx.ParamsInt64(":boardID"))
|
board, err = project_model.GetBoard(ctx, ctx.ParamsInt64(":boardID"))
|
||||||
|
|
|
@ -100,7 +100,7 @@ func List(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
wf, err := model.ReadWorkflow(bytes.NewReader(content))
|
wf, err := model.ReadWorkflow(bytes.NewReader(content))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
workflow.ErrMsg = ctx.Locale.Tr("actions.runs.invalid_workflow_helper", err.Error())
|
workflow.ErrMsg = ctx.Locale.TrString("actions.runs.invalid_workflow_helper", err.Error())
|
||||||
workflows = append(workflows, workflow)
|
workflows = append(workflows, workflow)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -115,7 +115,7 @@ func List(ctx *context.Context) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !allRunnerLabels.Contains(ro) {
|
if !allRunnerLabels.Contains(ro) {
|
||||||
workflow.ErrMsg = ctx.Locale.Tr("actions.runs.no_matching_online_runner_helper", ro)
|
workflow.ErrMsg = ctx.Locale.TrString("actions.runs.no_matching_online_runner_helper", ro)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -209,8 +209,8 @@ func ViewPost(ctx *context_module.Context) {
|
||||||
Link: run.RefLink(),
|
Link: run.RefLink(),
|
||||||
}
|
}
|
||||||
resp.State.Run.Commit = ViewCommit{
|
resp.State.Run.Commit = ViewCommit{
|
||||||
LocaleCommit: ctx.Tr("actions.runs.commit"),
|
LocaleCommit: ctx.Locale.TrString("actions.runs.commit"),
|
||||||
LocalePushedBy: ctx.Tr("actions.runs.pushed_by"),
|
LocalePushedBy: ctx.Locale.TrString("actions.runs.pushed_by"),
|
||||||
ShortSha: base.ShortSha(run.CommitSHA),
|
ShortSha: base.ShortSha(run.CommitSHA),
|
||||||
Link: fmt.Sprintf("%s/commit/%s", run.Repo.Link(), run.CommitSHA),
|
Link: fmt.Sprintf("%s/commit/%s", run.Repo.Link(), run.CommitSHA),
|
||||||
Pusher: pusher,
|
Pusher: pusher,
|
||||||
|
@ -235,7 +235,7 @@ func ViewPost(ctx *context_module.Context) {
|
||||||
resp.State.CurrentJob.Title = current.Name
|
resp.State.CurrentJob.Title = current.Name
|
||||||
resp.State.CurrentJob.Detail = current.Status.LocaleString(ctx.Locale)
|
resp.State.CurrentJob.Detail = current.Status.LocaleString(ctx.Locale)
|
||||||
if run.NeedApproval {
|
if run.NeedApproval {
|
||||||
resp.State.CurrentJob.Detail = ctx.Locale.Tr("actions.need_approval_desc")
|
resp.State.CurrentJob.Detail = ctx.Locale.TrString("actions.need_approval_desc")
|
||||||
}
|
}
|
||||||
resp.State.CurrentJob.Steps = make([]*ViewJobStep, 0) // marshal to '[]' instead fo 'null' in json
|
resp.State.CurrentJob.Steps = make([]*ViewJobStep, 0) // marshal to '[]' instead fo 'null' in json
|
||||||
resp.Logs.StepsLog = make([]*ViewStepLog, 0) // marshal to '[]' instead fo 'null' in json
|
resp.Logs.StepsLog = make([]*ViewStepLog, 0) // marshal to '[]' instead fo 'null' in json
|
||||||
|
|
|
@ -19,6 +19,7 @@ import (
|
||||||
"code.gitea.io/gitea/modules/templates"
|
"code.gitea.io/gitea/modules/templates"
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
files_service "code.gitea.io/gitea/services/repository/files"
|
||||||
)
|
)
|
||||||
|
|
||||||
type blameRow struct {
|
type blameRow struct {
|
||||||
|
@ -218,31 +219,11 @@ func processBlameParts(ctx *context.Context, blameParts []*git.BlamePart) map[st
|
||||||
func renderBlame(ctx *context.Context, blameParts []*git.BlamePart, commitNames map[string]*user_model.UserCommit) {
|
func renderBlame(ctx *context.Context, blameParts []*git.BlamePart, commitNames map[string]*user_model.UserCommit) {
|
||||||
repoLink := ctx.Repo.RepoLink
|
repoLink := ctx.Repo.RepoLink
|
||||||
|
|
||||||
language := ""
|
language, err := files_service.TryGetContentLanguage(ctx.Repo.GitRepo, ctx.Repo.CommitID, ctx.Repo.TreePath)
|
||||||
|
if err != nil {
|
||||||
indexFilename, worktree, deleteTemporaryFile, err := ctx.Repo.GitRepo.ReadTreeToTemporaryIndex(ctx.Repo.CommitID)
|
log.Error("Unable to get file language for %-v:%s. Error: %v", ctx.Repo.Repository, ctx.Repo.TreePath, err)
|
||||||
if err == nil {
|
|
||||||
defer deleteTemporaryFile()
|
|
||||||
|
|
||||||
filename2attribute2info, err := ctx.Repo.GitRepo.CheckAttribute(git.CheckAttributeOpts{
|
|
||||||
CachedOnly: true,
|
|
||||||
Attributes: []string{"linguist-language", "gitlab-language"},
|
|
||||||
Filenames: []string{ctx.Repo.TreePath},
|
|
||||||
IndexFile: indexFilename,
|
|
||||||
WorkTree: worktree,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Unable to load attributes for %-v:%s. Error: %v", ctx.Repo.Repository, ctx.Repo.TreePath, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
language = filename2attribute2info[ctx.Repo.TreePath]["linguist-language"]
|
|
||||||
if language == "" || language == "unspecified" {
|
|
||||||
language = filename2attribute2info[ctx.Repo.TreePath]["gitlab-language"]
|
|
||||||
}
|
|
||||||
if language == "unspecified" {
|
|
||||||
language = ""
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lines := make([]string, 0)
|
lines := make([]string, 0)
|
||||||
rows := make([]*blameRow, 0)
|
rows := make([]*blameRow, 0)
|
||||||
escapeStatus := &charset.EscapeStatus{}
|
escapeStatus := &charset.EscapeStatus{}
|
||||||
|
|
|
@ -104,9 +104,9 @@ func CherryPickPost(ctx *context.Context) {
|
||||||
message := strings.TrimSpace(form.CommitSummary)
|
message := strings.TrimSpace(form.CommitSummary)
|
||||||
if message == "" {
|
if message == "" {
|
||||||
if form.Revert {
|
if form.Revert {
|
||||||
message = ctx.Tr("repo.commit.revert-header", sha)
|
message = ctx.Locale.TrString("repo.commit.revert-header", sha)
|
||||||
} else {
|
} else {
|
||||||
message = ctx.Tr("repo.commit.cherry-pick-header", sha)
|
message = ctx.Locale.TrString("repo.commit.cherry-pick-header", sha)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -126,7 +126,7 @@ func setCsvCompareContext(ctx *context.Context) {
|
||||||
return CsvDiffResult{nil, ""}
|
return CsvDiffResult{nil, ""}
|
||||||
}
|
}
|
||||||
|
|
||||||
errTooLarge := errors.New(ctx.Locale.Tr("repo.error.csv.too_large"))
|
errTooLarge := errors.New(ctx.Locale.TrString("repo.error.csv.too_large"))
|
||||||
|
|
||||||
csvReaderFromCommit := func(ctx *markup.RenderContext, blob *git.Blob) (*csv.Reader, io.Closer, error) {
|
csvReaderFromCommit := func(ctx *markup.RenderContext, blob *git.Blob) (*csv.Reader, io.Closer, error) {
|
||||||
if blob == nil {
|
if blob == nil {
|
||||||
|
|
|
@ -300,9 +300,9 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b
|
||||||
message := strings.TrimSpace(form.CommitSummary)
|
message := strings.TrimSpace(form.CommitSummary)
|
||||||
if len(message) == 0 {
|
if len(message) == 0 {
|
||||||
if isNewFile {
|
if isNewFile {
|
||||||
message = ctx.Tr("repo.editor.add", form.TreePath)
|
message = ctx.Locale.TrString("repo.editor.add", form.TreePath)
|
||||||
} else {
|
} else {
|
||||||
message = ctx.Tr("repo.editor.update", form.TreePath)
|
message = ctx.Locale.TrString("repo.editor.update", form.TreePath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
form.CommitMessage = strings.TrimSpace(form.CommitMessage)
|
form.CommitMessage = strings.TrimSpace(form.CommitMessage)
|
||||||
|
@ -479,7 +479,7 @@ func DiffPreviewPost(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if diff.NumFiles == 0 {
|
if diff.NumFiles == 0 {
|
||||||
ctx.PlainText(http.StatusOK, ctx.Tr("repo.editor.no_changes_to_show"))
|
ctx.PlainText(http.StatusOK, ctx.Locale.TrString("repo.editor.no_changes_to_show"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.Data["File"] = diff.Files[0]
|
ctx.Data["File"] = diff.Files[0]
|
||||||
|
@ -546,7 +546,7 @@ func DeleteFilePost(ctx *context.Context) {
|
||||||
|
|
||||||
message := strings.TrimSpace(form.CommitSummary)
|
message := strings.TrimSpace(form.CommitSummary)
|
||||||
if len(message) == 0 {
|
if len(message) == 0 {
|
||||||
message = ctx.Tr("repo.editor.delete", ctx.Repo.TreePath)
|
message = ctx.Locale.TrString("repo.editor.delete", ctx.Repo.TreePath)
|
||||||
}
|
}
|
||||||
form.CommitMessage = strings.TrimSpace(form.CommitMessage)
|
form.CommitMessage = strings.TrimSpace(form.CommitMessage)
|
||||||
if len(form.CommitMessage) > 0 {
|
if len(form.CommitMessage) > 0 {
|
||||||
|
@ -755,7 +755,7 @@ func UploadFilePost(ctx *context.Context) {
|
||||||
if dir == "" {
|
if dir == "" {
|
||||||
dir = "/"
|
dir = "/"
|
||||||
}
|
}
|
||||||
message = ctx.Tr("repo.editor.upload_files_to_dir", dir)
|
message = ctx.Locale.TrString("repo.editor.upload_files_to_dir", dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
form.CommitMessage = strings.TrimSpace(form.CommitMessage)
|
form.CommitMessage = strings.TrimSpace(form.CommitMessage)
|
||||||
|
|
|
@ -1042,7 +1042,7 @@ func renderErrorOfTemplates(ctx *context.Context, errs map[string]error) string
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("render flash error: %v", err)
|
log.Debug("render flash error: %v", err)
|
||||||
flashError = ctx.Tr("repo.issues.choose.ignore_invalid_templates")
|
flashError = ctx.Locale.TrString("repo.issues.choose.ignore_invalid_templates")
|
||||||
}
|
}
|
||||||
return flashError
|
return flashError
|
||||||
}
|
}
|
||||||
|
@ -1664,7 +1664,7 @@ func ViewIssue(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
ghostMilestone := &issues_model.Milestone{
|
ghostMilestone := &issues_model.Milestone{
|
||||||
ID: -1,
|
ID: -1,
|
||||||
Name: ctx.Tr("repo.issues.deleted_milestone"),
|
Name: ctx.Locale.TrString("repo.issues.deleted_milestone"),
|
||||||
}
|
}
|
||||||
if comment.OldMilestoneID > 0 && comment.OldMilestone == nil {
|
if comment.OldMilestoneID > 0 && comment.OldMilestone == nil {
|
||||||
comment.OldMilestone = ghostMilestone
|
comment.OldMilestone = ghostMilestone
|
||||||
|
@ -1681,7 +1681,7 @@ func ViewIssue(ctx *context.Context) {
|
||||||
|
|
||||||
ghostProject := &project_model.Project{
|
ghostProject := &project_model.Project{
|
||||||
ID: -1,
|
ID: -1,
|
||||||
Title: ctx.Tr("repo.issues.deleted_project"),
|
Title: ctx.Locale.TrString("repo.issues.deleted_project"),
|
||||||
}
|
}
|
||||||
|
|
||||||
if comment.OldProjectID > 0 && comment.OldProject == nil {
|
if comment.OldProjectID > 0 && comment.OldProject == nil {
|
||||||
|
|
|
@ -56,12 +56,12 @@ func GetContentHistoryList(ctx *context.Context) {
|
||||||
for _, item := range items {
|
for _, item := range items {
|
||||||
var actionText string
|
var actionText string
|
||||||
if item.IsDeleted {
|
if item.IsDeleted {
|
||||||
actionTextDeleted := ctx.Locale.Tr("repo.issues.content_history.deleted")
|
actionTextDeleted := ctx.Locale.TrString("repo.issues.content_history.deleted")
|
||||||
actionText = "<i data-history-is-deleted='1'>" + actionTextDeleted + "</i>"
|
actionText = "<i data-history-is-deleted='1'>" + actionTextDeleted + "</i>"
|
||||||
} else if item.IsFirstCreated {
|
} else if item.IsFirstCreated {
|
||||||
actionText = ctx.Locale.Tr("repo.issues.content_history.created")
|
actionText = ctx.Locale.TrString("repo.issues.content_history.created")
|
||||||
} else {
|
} else {
|
||||||
actionText = ctx.Locale.Tr("repo.issues.content_history.edited")
|
actionText = ctx.Locale.TrString("repo.issues.content_history.edited")
|
||||||
}
|
}
|
||||||
|
|
||||||
username := item.UserName
|
username := item.UserName
|
||||||
|
|
|
@ -123,7 +123,7 @@ func TestDeleteLabel(t *testing.T) {
|
||||||
assert.EqualValues(t, http.StatusOK, ctx.Resp.Status())
|
assert.EqualValues(t, http.StatusOK, ctx.Resp.Status())
|
||||||
unittest.AssertNotExistsBean(t, &issues_model.Label{ID: 2})
|
unittest.AssertNotExistsBean(t, &issues_model.Label{ID: 2})
|
||||||
unittest.AssertNotExistsBean(t, &issues_model.IssueLabel{LabelID: 2})
|
unittest.AssertNotExistsBean(t, &issues_model.IssueLabel{LabelID: 2})
|
||||||
assert.Equal(t, ctx.Tr("repo.issues.label_deletion_success"), ctx.Flash.SuccessMsg)
|
assert.EqualValues(t, ctx.Tr("repo.issues.label_deletion_success"), ctx.Flash.SuccessMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdateIssueLabel_Clear(t *testing.T) {
|
func TestUpdateIssueLabel_Clear(t *testing.T) {
|
||||||
|
|
|
@ -79,7 +79,7 @@ func NewDiffPatchPost(ctx *context.Context) {
|
||||||
// `message` will be both the summary and message combined
|
// `message` will be both the summary and message combined
|
||||||
message := strings.TrimSpace(form.CommitSummary)
|
message := strings.TrimSpace(form.CommitSummary)
|
||||||
if len(message) == 0 {
|
if len(message) == 0 {
|
||||||
message = ctx.Tr("repo.editor.patch")
|
message = ctx.Locale.TrString("repo.editor.patch")
|
||||||
}
|
}
|
||||||
|
|
||||||
form.CommitMessage = strings.TrimSpace(form.CommitMessage)
|
form.CommitMessage = strings.TrimSpace(form.CommitMessage)
|
||||||
|
|
|
@ -315,7 +315,7 @@ func ViewProject(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if boards[0].ID == 0 {
|
if boards[0].ID == 0 {
|
||||||
boards[0].Title = ctx.Tr("repo.projects.type.uncategorized")
|
boards[0].Title = ctx.Locale.TrString("repo.projects.type.uncategorized")
|
||||||
}
|
}
|
||||||
|
|
||||||
issuesMap, err := issues_model.LoadIssuesFromBoardList(ctx, boards)
|
issuesMap, err := issues_model.LoadIssuesFromBoardList(ctx, boards)
|
||||||
|
@ -633,7 +633,7 @@ func MoveIssues(ctx *context.Context) {
|
||||||
board = &project_model.Board{
|
board = &project_model.Board{
|
||||||
ID: 0,
|
ID: 0,
|
||||||
ProjectID: project.ID,
|
ProjectID: project.ID,
|
||||||
Title: ctx.Tr("repo.projects.type.uncategorized"),
|
Title: ctx.Locale.TrString("repo.projects.type.uncategorized"),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
board, err = project_model.GetBoard(ctx, ctx.ParamsInt64(":boardID"))
|
board, err = project_model.GetBoard(ctx, ctx.ParamsInt64(":boardID"))
|
||||||
|
|
|
@ -733,7 +733,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C
|
||||||
type pullCommitList struct {
|
type pullCommitList struct {
|
||||||
Commits []pull_service.CommitInfo `json:"commits"`
|
Commits []pull_service.CommitInfo `json:"commits"`
|
||||||
LastReviewCommitSha string `json:"last_review_commit_sha"`
|
LastReviewCommitSha string `json:"last_review_commit_sha"`
|
||||||
Locale map[string]string `json:"locale"`
|
Locale map[string]any `json:"locale"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPullCommits get all commits for given pull request
|
// GetPullCommits get all commits for given pull request
|
||||||
|
@ -751,7 +751,7 @@ func GetPullCommits(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the needed locale
|
// Get the needed locale
|
||||||
resp.Locale = map[string]string{
|
resp.Locale = map[string]any{
|
||||||
"lang": ctx.Locale.Language(),
|
"lang": ctx.Locale.Language(),
|
||||||
"show_all_commits": ctx.Tr("repo.pulls.show_all_commits"),
|
"show_all_commits": ctx.Tr("repo.pulls.show_all_commits"),
|
||||||
"stats_num_commits": ctx.TrN(len(commits), "repo.activity.git_stats_commit_1", "repo.activity.git_stats_commit_n", len(commits)),
|
"stats_num_commits": ctx.TrN(len(commits), "repo.activity.git_stats_commit_1", "repo.activity.git_stats_commit_n", len(commits)),
|
||||||
|
|
|
@ -209,9 +209,9 @@ func SubmitReview(ctx *context.Context) {
|
||||||
if issue.IsPoster(ctx.Doer.ID) {
|
if issue.IsPoster(ctx.Doer.ID) {
|
||||||
var translated string
|
var translated string
|
||||||
if reviewType == issues_model.ReviewTypeApprove {
|
if reviewType == issues_model.ReviewTypeApprove {
|
||||||
translated = ctx.Tr("repo.issues.review.self.approval")
|
translated = ctx.Locale.TrString("repo.issues.review.self.approval")
|
||||||
} else {
|
} else {
|
||||||
translated = ctx.Tr("repo.issues.review.self.rejection")
|
translated = ctx.Locale.TrString("repo.issues.review.self.rejection")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Flash.Error(translated)
|
ctx.Flash.Error(translated)
|
||||||
|
|
|
@ -38,7 +38,7 @@ func UpdateAvatarSetting(ctx *context.Context, form forms.AvatarForm) error {
|
||||||
defer r.Close()
|
defer r.Close()
|
||||||
|
|
||||||
if form.Avatar.Size > setting.Avatar.MaxFileSize {
|
if form.Avatar.Size > setting.Avatar.MaxFileSize {
|
||||||
return errors.New(ctx.Tr("settings.uploaded_avatar_is_too_big", form.Avatar.Size/1024, setting.Avatar.MaxFileSize/1024))
|
return errors.New(ctx.Locale.TrString("settings.uploaded_avatar_is_too_big", form.Avatar.Size/1024, setting.Avatar.MaxFileSize/1024))
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := io.ReadAll(r)
|
data, err := io.ReadAll(r)
|
||||||
|
@ -47,7 +47,7 @@ func UpdateAvatarSetting(ctx *context.Context, form forms.AvatarForm) error {
|
||||||
}
|
}
|
||||||
st := typesniffer.DetectContentType(data)
|
st := typesniffer.DetectContentType(data)
|
||||||
if !(st.IsImage() && !st.IsSvgImage()) {
|
if !(st.IsImage() && !st.IsSvgImage()) {
|
||||||
return errors.New(ctx.Tr("settings.uploaded_avatar_not_a_image"))
|
return errors.New(ctx.Locale.TrString("settings.uploaded_avatar_not_a_image"))
|
||||||
}
|
}
|
||||||
if err = repo_service.UploadAvatar(ctx, ctxRepo, data); err != nil {
|
if err = repo_service.UploadAvatar(ctx, ctxRepo, data); err != nil {
|
||||||
return fmt.Errorf("UploadAvatar: %w", err)
|
return fmt.Errorf("UploadAvatar: %w", err)
|
||||||
|
|
|
@ -68,7 +68,7 @@ func SettingsProtectedBranch(c *context.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["PageIsSettingsBranches"] = true
|
c.Data["PageIsSettingsBranches"] = true
|
||||||
c.Data["Title"] = c.Tr("repo.settings.protected_branch") + " - " + rule.RuleName
|
c.Data["Title"] = c.Locale.TrString("repo.settings.protected_branch") + " - " + rule.RuleName
|
||||||
|
|
||||||
users, err := access_model.GetRepoReaders(c, c.Repo.Repository)
|
users, err := access_model.GetRepoReaders(c, c.Repo.Repository)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -49,6 +49,7 @@ import (
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/routers/web/feed"
|
"code.gitea.io/gitea/routers/web/feed"
|
||||||
issue_service "code.gitea.io/gitea/services/issue"
|
issue_service "code.gitea.io/gitea/services/issue"
|
||||||
|
files_service "code.gitea.io/gitea/services/repository/files"
|
||||||
|
|
||||||
"github.com/nektos/act/pkg/model"
|
"github.com/nektos/act/pkg/model"
|
||||||
|
|
||||||
|
@ -557,31 +558,11 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry) {
|
||||||
}
|
}
|
||||||
ctx.Data["NumLinesSet"] = true
|
ctx.Data["NumLinesSet"] = true
|
||||||
|
|
||||||
language := ""
|
language, err := files_service.TryGetContentLanguage(ctx.Repo.GitRepo, ctx.Repo.CommitID, ctx.Repo.TreePath)
|
||||||
|
if err != nil {
|
||||||
indexFilename, worktree, deleteTemporaryFile, err := ctx.Repo.GitRepo.ReadTreeToTemporaryIndex(ctx.Repo.CommitID)
|
log.Error("Unable to get file language for %-v:%s. Error: %v", ctx.Repo.Repository, ctx.Repo.TreePath, err)
|
||||||
if err == nil {
|
|
||||||
defer deleteTemporaryFile()
|
|
||||||
|
|
||||||
filename2attribute2info, err := ctx.Repo.GitRepo.CheckAttribute(git.CheckAttributeOpts{
|
|
||||||
CachedOnly: true,
|
|
||||||
Attributes: []string{"linguist-language", "gitlab-language"},
|
|
||||||
Filenames: []string{ctx.Repo.TreePath},
|
|
||||||
IndexFile: indexFilename,
|
|
||||||
WorkTree: worktree,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Unable to load attributes for %-v:%s. Error: %v", ctx.Repo.Repository, ctx.Repo.TreePath, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
language = filename2attribute2info[ctx.Repo.TreePath]["linguist-language"]
|
|
||||||
if language == "" || language == "unspecified" {
|
|
||||||
language = filename2attribute2info[ctx.Repo.TreePath]["gitlab-language"]
|
|
||||||
}
|
|
||||||
if language == "unspecified" {
|
|
||||||
language = ""
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fileContent, lexerName, err := highlight.File(blob.Name(), language, buf)
|
fileContent, lexerName, err := highlight.File(blob.Name(), language, buf)
|
||||||
ctx.Data["LexerName"] = lexerName
|
ctx.Data["LexerName"] = lexerName
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -762,7 +743,7 @@ func checkHomeCodeViewable(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.NotFound("Home", fmt.Errorf(ctx.Tr("units.error.no_unit_allowed_repo")))
|
ctx.NotFound("Home", fmt.Errorf(ctx.Locale.TrString("units.error.no_unit_allowed_repo")))
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkCitationFile(ctx *context.Context, entry *git.TreeEntry) {
|
func checkCitationFile(ctx *context.Context, entry *git.TreeEntry) {
|
||||||
|
|
|
@ -714,7 +714,7 @@ func NewWikiPost(ctx *context.Context) {
|
||||||
wikiName := wiki_service.UserTitleToWebPath("", form.Title)
|
wikiName := wiki_service.UserTitleToWebPath("", form.Title)
|
||||||
|
|
||||||
if len(form.Message) == 0 {
|
if len(form.Message) == 0 {
|
||||||
form.Message = ctx.Tr("repo.editor.add", form.Title)
|
form.Message = ctx.Locale.TrString("repo.editor.add", form.Title)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := wiki_service.AddWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, wikiName, form.Content, form.Message); err != nil {
|
if err := wiki_service.AddWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, wikiName, form.Content, form.Message); err != nil {
|
||||||
|
@ -766,7 +766,7 @@ func EditWikiPost(ctx *context.Context) {
|
||||||
newWikiName := wiki_service.UserTitleToWebPath("", form.Title)
|
newWikiName := wiki_service.UserTitleToWebPath("", form.Title)
|
||||||
|
|
||||||
if len(form.Message) == 0 {
|
if len(form.Message) == 0 {
|
||||||
form.Message = ctx.Tr("repo.editor.update", form.Title)
|
form.Message = ctx.Locale.TrString("repo.editor.update", form.Title)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := wiki_service.EditWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, oldWikiName, newWikiName, form.Content, form.Message); err != nil {
|
if err := wiki_service.EditWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, oldWikiName, newWikiName, form.Content, form.Message); err != nil {
|
||||||
|
|
|
@ -85,7 +85,7 @@ func Dashboard(ctx *context.Context) {
|
||||||
page = 1
|
page = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Data["Title"] = ctxUser.DisplayName() + " - " + ctx.Tr("dashboard")
|
ctx.Data["Title"] = ctxUser.DisplayName() + " - " + ctx.Locale.TrString("dashboard")
|
||||||
ctx.Data["PageIsDashboard"] = true
|
ctx.Data["PageIsDashboard"] = true
|
||||||
ctx.Data["PageIsNews"] = true
|
ctx.Data["PageIsNews"] = true
|
||||||
cnt, _ := organization.GetOrganizationCount(ctx, ctxUser)
|
cnt, _ := organization.GetOrganizationCount(ctx, ctxUser)
|
||||||
|
|
|
@ -126,7 +126,7 @@ func UpdateAvatarSetting(ctx *context.Context, form *forms.AvatarForm, ctxUser *
|
||||||
defer fr.Close()
|
defer fr.Close()
|
||||||
|
|
||||||
if form.Avatar.Size > setting.Avatar.MaxFileSize {
|
if form.Avatar.Size > setting.Avatar.MaxFileSize {
|
||||||
return errors.New(ctx.Tr("settings.uploaded_avatar_is_too_big", form.Avatar.Size/1024, setting.Avatar.MaxFileSize/1024))
|
return errors.New(ctx.Locale.TrString("settings.uploaded_avatar_is_too_big", form.Avatar.Size/1024, setting.Avatar.MaxFileSize/1024))
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := io.ReadAll(fr)
|
data, err := io.ReadAll(fr)
|
||||||
|
@ -136,7 +136,7 @@ func UpdateAvatarSetting(ctx *context.Context, form *forms.AvatarForm, ctxUser *
|
||||||
|
|
||||||
st := typesniffer.DetectContentType(data)
|
st := typesniffer.DetectContentType(data)
|
||||||
if !(st.IsImage() && !st.IsSvgImage()) {
|
if !(st.IsImage() && !st.IsSvgImage()) {
|
||||||
return errors.New(ctx.Tr("settings.uploaded_avatar_not_a_image"))
|
return errors.New(ctx.Locale.TrString("settings.uploaded_avatar_not_a_image"))
|
||||||
}
|
}
|
||||||
if err = user_service.UploadAvatar(ctx, ctxUser, data); err != nil {
|
if err = user_service.UploadAvatar(ctx, ctxUser, data); err != nil {
|
||||||
return fmt.Errorf("UploadAvatar: %w", err)
|
return fmt.Errorf("UploadAvatar: %w", err)
|
||||||
|
@ -389,7 +389,7 @@ func UpdateUserLang(ctx *context.Context) {
|
||||||
middleware.SetLocaleCookie(ctx.Resp, ctx.Doer.Language, 0)
|
middleware.SetLocaleCookie(ctx.Resp, ctx.Doer.Language, 0)
|
||||||
|
|
||||||
log.Trace("User settings updated: %s", ctx.Doer.Name)
|
log.Trace("User settings updated: %s", ctx.Doer.Name)
|
||||||
ctx.Flash.Success(translation.NewLocale(ctx.Doer.Language).Tr("settings.update_language_success"))
|
ctx.Flash.Success(translation.NewLocale(ctx.Doer.Language).TrString("settings.update_language_success"))
|
||||||
ctx.Redirect(setting.AppSubURL + "/user/settings/appearance")
|
ctx.Redirect(setting.AppSubURL + "/user/settings/appearance")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ func TaskStatus(ctx *context.Context) {
|
||||||
Args: []any{task.Message},
|
Args: []any{task.Message},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
message = ctx.Tr(translatableMessage.Format, translatableMessage.Args...)
|
message = ctx.Locale.TrString(translatableMessage.Format, translatableMessage.Args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.JSON(http.StatusOK, map[string]any{
|
ctx.JSON(http.StatusOK, map[string]any{
|
||||||
|
|
|
@ -152,7 +152,7 @@ func verifyAuthWithOptions(options *common.VerifyOptions) func(ctx *context.Cont
|
||||||
if ctx.Doer.MustChangePassword {
|
if ctx.Doer.MustChangePassword {
|
||||||
if ctx.Req.URL.Path != "/user/settings/change_password" {
|
if ctx.Req.URL.Path != "/user/settings/change_password" {
|
||||||
if strings.HasPrefix(ctx.Req.UserAgent(), "git") {
|
if strings.HasPrefix(ctx.Req.UserAgent(), "git") {
|
||||||
ctx.Error(http.StatusUnauthorized, ctx.Tr("auth.must_change_password"))
|
ctx.Error(http.StatusUnauthorized, ctx.Locale.TrString("auth.must_change_password"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.Data["Title"] = ctx.Tr("auth.must_change_password")
|
ctx.Data["Title"] = ctx.Tr("auth.must_change_password")
|
||||||
|
|
|
@ -70,7 +70,7 @@ func (b *BaseConfig) DoNoticeOnSuccess() bool {
|
||||||
// Please note the `status` string will be concatenated with `admin.dashboard.cron.` and `admin.dashboard.task.` to provide locale messages. Similarly `name` will be composed with `admin.dashboard.` to provide the locale name for the task.
|
// Please note the `status` string will be concatenated with `admin.dashboard.cron.` and `admin.dashboard.task.` to provide locale messages. Similarly `name` will be composed with `admin.dashboard.` to provide the locale name for the task.
|
||||||
func (b *BaseConfig) FormatMessage(locale translation.Locale, name, status, doer string, args ...any) string {
|
func (b *BaseConfig) FormatMessage(locale translation.Locale, name, status, doer string, args ...any) string {
|
||||||
realArgs := make([]any, 0, len(args)+2)
|
realArgs := make([]any, 0, len(args)+2)
|
||||||
realArgs = append(realArgs, locale.Tr("admin.dashboard."+name))
|
realArgs = append(realArgs, locale.TrString("admin.dashboard."+name))
|
||||||
if doer == "" {
|
if doer == "" {
|
||||||
realArgs = append(realArgs, "(Cron)")
|
realArgs = append(realArgs, "(Cron)")
|
||||||
} else {
|
} else {
|
||||||
|
@ -80,7 +80,7 @@ func (b *BaseConfig) FormatMessage(locale translation.Locale, name, status, doer
|
||||||
realArgs = append(realArgs, args...)
|
realArgs = append(realArgs, args...)
|
||||||
}
|
}
|
||||||
if doer == "" {
|
if doer == "" {
|
||||||
return locale.Tr("admin.dashboard.cron."+status, realArgs...)
|
return locale.TrString("admin.dashboard.cron."+status, realArgs...)
|
||||||
}
|
}
|
||||||
return locale.Tr("admin.dashboard.task."+status, realArgs...)
|
return locale.TrString("admin.dashboard.task."+status, realArgs...)
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,7 +159,7 @@ func RegisterTask(name string, config Config, fun func(context.Context, *user_mo
|
||||||
log.Debug("Registering task: %s", name)
|
log.Debug("Registering task: %s", name)
|
||||||
|
|
||||||
i18nKey := "admin.dashboard." + name
|
i18nKey := "admin.dashboard." + name
|
||||||
if value := translation.NewLocale("en-US").Tr(i18nKey); value == i18nKey {
|
if value := translation.NewLocale("en-US").TrString(i18nKey); value == i18nKey {
|
||||||
return fmt.Errorf("translation is missing for task %q, please add translation for %q", name, i18nKey)
|
return fmt.Errorf("translation is missing for task %q, please add translation for %q", name, i18nKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -325,7 +325,7 @@ func (f *NewSlackHookForm) Validate(req *http.Request, errs binding.Errors) bind
|
||||||
errs = append(errs, binding.Error{
|
errs = append(errs, binding.Error{
|
||||||
FieldNames: []string{"Channel"},
|
FieldNames: []string{"Channel"},
|
||||||
Classification: "",
|
Classification: "",
|
||||||
Message: ctx.Tr("repo.settings.add_webhook.invalid_channel_name"),
|
Message: ctx.Locale.TrString("repo.settings.add_webhook.invalid_channel_name"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
||||||
|
|
|
@ -94,7 +94,7 @@ func SendActivateAccountMail(locale translation.Locale, u *user_model.User) {
|
||||||
// No mail service configured
|
// No mail service configured
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sendUserMail(locale.Language(), u, mailAuthActivate, u.GenerateEmailActivateCode(u.Email), locale.Tr("mail.activate_account"), "activate account")
|
sendUserMail(locale.Language(), u, mailAuthActivate, u.GenerateEmailActivateCode(u.Email), locale.TrString("mail.activate_account"), "activate account")
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendResetPasswordMail sends a password reset mail to the user
|
// SendResetPasswordMail sends a password reset mail to the user
|
||||||
|
@ -104,7 +104,7 @@ func SendResetPasswordMail(u *user_model.User) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
locale := translation.NewLocale(u.Language)
|
locale := translation.NewLocale(u.Language)
|
||||||
sendUserMail(u.Language, u, mailAuthResetPassword, u.GenerateEmailActivateCode(u.Email), locale.Tr("mail.reset_password"), "recover account")
|
sendUserMail(u.Language, u, mailAuthResetPassword, u.GenerateEmailActivateCode(u.Email), locale.TrString("mail.reset_password"), "recover account")
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendActivateEmailMail sends confirmation email to confirm new email address
|
// SendActivateEmailMail sends confirmation email to confirm new email address
|
||||||
|
@ -130,7 +130,7 @@ func SendActivateEmailMail(u *user_model.User, email string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
msg := NewMessage(email, locale.Tr("mail.activate_email"), content.String())
|
msg := NewMessage(email, locale.TrString("mail.activate_email"), content.String())
|
||||||
msg.Info = fmt.Sprintf("UID: %d, activate email", u.ID)
|
msg.Info = fmt.Sprintf("UID: %d, activate email", u.ID)
|
||||||
|
|
||||||
SendAsync(msg)
|
SendAsync(msg)
|
||||||
|
@ -158,7 +158,7 @@ func SendRegisterNotifyMail(u *user_model.User) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
msg := NewMessage(u.Email, locale.Tr("mail.register_notify"), content.String())
|
msg := NewMessage(u.Email, locale.TrString("mail.register_notify"), content.String())
|
||||||
msg.Info = fmt.Sprintf("UID: %d, registration notify", u.ID)
|
msg.Info = fmt.Sprintf("UID: %d, registration notify", u.ID)
|
||||||
|
|
||||||
SendAsync(msg)
|
SendAsync(msg)
|
||||||
|
@ -173,7 +173,7 @@ func SendCollaboratorMail(u, doer *user_model.User, repo *repo_model.Repository)
|
||||||
locale := translation.NewLocale(u.Language)
|
locale := translation.NewLocale(u.Language)
|
||||||
repoName := repo.FullName()
|
repoName := repo.FullName()
|
||||||
|
|
||||||
subject := locale.Tr("mail.repo.collaborator.added.subject", doer.DisplayName(), repoName)
|
subject := locale.TrString("mail.repo.collaborator.added.subject", doer.DisplayName(), repoName)
|
||||||
data := map[string]any{
|
data := map[string]any{
|
||||||
"locale": locale,
|
"locale": locale,
|
||||||
"Subject": subject,
|
"Subject": subject,
|
||||||
|
|
|
@ -52,8 +52,8 @@ func mailNewUser(ctx context.Context, u *user_model.User, lang string, tos []str
|
||||||
locale := translation.NewLocale(lang)
|
locale := translation.NewLocale(lang)
|
||||||
|
|
||||||
manageUserURL := setting.AppURL + "admin/users/" + strconv.FormatInt(u.ID, 10)
|
manageUserURL := setting.AppURL + "admin/users/" + strconv.FormatInt(u.ID, 10)
|
||||||
subject := locale.Tr("mail.admin.new_user.subject", u.Name)
|
subject := locale.TrString("mail.admin.new_user.subject", u.Name)
|
||||||
body := locale.Tr("mail.admin.new_user.text", manageUserURL)
|
body := locale.TrString("mail.admin.new_user.text", manageUserURL)
|
||||||
mailMeta := map[string]any{
|
mailMeta := map[string]any{
|
||||||
"NewUser": u,
|
"NewUser": u,
|
||||||
"NewUserUrl": u.HTMLURL(),
|
"NewUserUrl": u.HTMLURL(),
|
||||||
|
|
|
@ -68,7 +68,7 @@ func mailNewRelease(ctx context.Context, lang string, tos []string, rel *repo_mo
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
subject := locale.Tr("mail.release.new.subject", rel.TagName, rel.Repo.FullName())
|
subject := locale.TrString("mail.release.new.subject", rel.TagName, rel.Repo.FullName())
|
||||||
mailMeta := map[string]any{
|
mailMeta := map[string]any{
|
||||||
"locale": locale,
|
"locale": locale,
|
||||||
"Release": rel,
|
"Release": rel,
|
||||||
|
|
|
@ -56,11 +56,11 @@ func sendRepoTransferNotifyMailPerLang(lang string, newOwner, doer *user_model.U
|
||||||
content bytes.Buffer
|
content bytes.Buffer
|
||||||
)
|
)
|
||||||
|
|
||||||
destination := locale.Tr("mail.repo.transfer.to_you")
|
destination := locale.TrString("mail.repo.transfer.to_you")
|
||||||
subject := locale.Tr("mail.repo.transfer.subject_to_you", doer.DisplayName(), repo.FullName())
|
subject := locale.TrString("mail.repo.transfer.subject_to_you", doer.DisplayName(), repo.FullName())
|
||||||
if newOwner.IsOrganization() {
|
if newOwner.IsOrganization() {
|
||||||
destination = newOwner.DisplayName()
|
destination = newOwner.DisplayName()
|
||||||
subject = locale.Tr("mail.repo.transfer.subject_to", doer.DisplayName(), repo.FullName(), destination)
|
subject = locale.TrString("mail.repo.transfer.subject_to", doer.DisplayName(), repo.FullName(), destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
data := map[string]any{
|
data := map[string]any{
|
||||||
|
|
|
@ -50,7 +50,7 @@ func MailTeamInvite(ctx context.Context, inviter *user_model.User, team *org_mod
|
||||||
inviteURL = fmt.Sprintf("%suser/login?redirect_to=%s", setting.AppURL, inviteRedirect)
|
inviteURL = fmt.Sprintf("%suser/login?redirect_to=%s", setting.AppURL, inviteRedirect)
|
||||||
}
|
}
|
||||||
|
|
||||||
subject := locale.Tr("mail.team_invite.subject", inviter.DisplayName(), org.DisplayName())
|
subject := locale.TrString("mail.team_invite.subject", inviter.DisplayName(), org.DisplayName())
|
||||||
mailMeta := map[string]any{
|
mailMeta := map[string]any{
|
||||||
"locale": locale,
|
"locale": locale,
|
||||||
"Inviter": inviter,
|
"Inviter": inviter,
|
||||||
|
|
|
@ -270,3 +270,34 @@ func GetBlobBySHA(ctx context.Context, repo *repo_model.Repository, gitRepo *git
|
||||||
Content: content,
|
Content: content,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TryGetContentLanguage tries to get the (linguist) language of the file content
|
||||||
|
func TryGetContentLanguage(gitRepo *git.Repository, commitID, treePath string) (string, error) {
|
||||||
|
indexFilename, worktree, deleteTemporaryFile, err := gitRepo.ReadTreeToTemporaryIndex(commitID)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer deleteTemporaryFile()
|
||||||
|
|
||||||
|
filename2attribute2info, err := gitRepo.CheckAttribute(git.CheckAttributeOpts{
|
||||||
|
CachedOnly: true,
|
||||||
|
Attributes: []string{"linguist-language", "gitlab-language"},
|
||||||
|
Filenames: []string{treePath},
|
||||||
|
IndexFile: indexFilename,
|
||||||
|
WorkTree: worktree,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
language := filename2attribute2info[treePath]["linguist-language"]
|
||||||
|
if language == "" || language == "unspecified" {
|
||||||
|
language = filename2attribute2info[treePath]["gitlab-language"]
|
||||||
|
}
|
||||||
|
if language == "unspecified" {
|
||||||
|
language = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return language, nil
|
||||||
|
}
|
||||||
|
|
|
@ -153,9 +153,7 @@ func ReplaceInactivePrimaryEmail(ctx context.Context, oldEmail string, email *us
|
||||||
return err
|
return err
|
||||||
} else if !has {
|
} else if !has {
|
||||||
return user_model.ErrUserNotExist{
|
return user_model.ErrUserNotExist{
|
||||||
UID: email.UID,
|
UID: email.UID,
|
||||||
Name: "",
|
|
||||||
KeyID: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,9 +13,9 @@
|
||||||
<body>
|
<body>
|
||||||
<p>
|
<p>
|
||||||
{{if .IsPull}}
|
{{if .IsPull}}
|
||||||
{{.locale.Tr "mail.issue_assigned.pull" .Doer.Name $link $repo_url | Str2html}}
|
{{.locale.Tr "mail.issue_assigned.pull" .Doer.Name ($link|Safe) ($repo_url|Safe)}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{.locale.Tr "mail.issue_assigned.issue" .Doer.Name $link $repo_url | Str2html}}
|
{{.locale.Tr "mail.issue_assigned.issue" .Doer.Name ($link|Safe) ($repo_url|Safe)}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</p>
|
</p>
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
{{$newShortSha := ShortSha .Comment.NewCommit}}
|
{{$newShortSha := ShortSha .Comment.NewCommit}}
|
||||||
{{$newCommitLink := printf "<a href='%[1]s'><b>%[2]s</b></a>" (Escape $newCommitUrl) (Escape $newShortSha)}}
|
{{$newCommitLink := printf "<a href='%[1]s'><b>%[2]s</b></a>" (Escape $newCommitUrl) (Escape $newShortSha)}}
|
||||||
|
|
||||||
{{.locale.Tr "mail.issue.action.force_push" .Doer.Name .Comment.Issue.PullRequest.HeadBranch $oldCommitLink $newCommitLink | Str2html}}
|
{{.locale.Tr "mail.issue.action.force_push" .Doer.Name .Comment.Issue.PullRequest.HeadBranch ($oldCommitLink|Safe) ($newCommitLink|Safe)}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{.locale.TrN (len .Comment.Commits) "mail.issue.action.push_1" "mail.issue.action.push_n" .Doer.Name .Comment.Issue.PullRequest.HeadBranch (len .Comment.Commits) | Str2html}}
|
{{.locale.TrN (len .Comment.Commits) "mail.issue.action.push_1" "mail.issue.action.push_n" .Doer.Name .Comment.Issue.PullRequest.HeadBranch (len .Comment.Commits) | Str2html}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
{{$url := printf "<a href='%[1]s'>%[2]s</a>" (Escape .Link) (Escape .Repo)}}
|
{{$url := printf "<a href='%[1]s'>%[2]s</a>" (Escape .Link) (Escape .Repo)}}
|
||||||
<body>
|
<body>
|
||||||
<p>{{.Subject}}.
|
<p>{{.Subject}}.
|
||||||
{{.locale.Tr "mail.repo.transfer.body" $url | Str2html}}
|
{{.locale.Tr "mail.repo.transfer.body" ($url|Safe)}}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
---
|
---
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
{{$repo_url := printf "<a href='%s'>%s</a>" (.Release.Repo.HTMLURL | Escape) (.Release.Repo.FullName | Escape)}}
|
{{$repo_url := printf "<a href='%s'>%s</a>" (.Release.Repo.HTMLURL | Escape) (.Release.Repo.FullName | Escape)}}
|
||||||
<body>
|
<body>
|
||||||
<p>
|
<p>
|
||||||
{{.locale.Tr "mail.release.new.text" .Release.Publisher.Name $release_url $repo_url | Str2html}}
|
{{.locale.Tr "mail.release.new.text" .Release.Publisher.Name ($release_url|Safe) ($repo_url|Safe)}}
|
||||||
</p>
|
</p>
|
||||||
<h4>{{.locale.Tr "mail.release.title" .Release.Title}}</h4>
|
<h4>{{.locale.Tr "mail.release.title" .Release.Title}}</h4>
|
||||||
<p>
|
<p>
|
||||||
|
|
|
@ -13,9 +13,9 @@
|
||||||
{{$shaurl := printf "%s/commit/%s" $.RepoLink (PathEscape .SHA)}}
|
{{$shaurl := printf "%s/commit/%s" $.RepoLink (PathEscape .SHA)}}
|
||||||
{{$shalink := printf `<a class="ui primary sha label" href="%s">%s</a>` (Escape $shaurl) (ShortSha .SHA)}}
|
{{$shalink := printf `<a class="ui primary sha label" href="%s">%s</a>` (Escape $shaurl) (ShortSha .SHA)}}
|
||||||
{{if eq .CherryPickType "revert"}}
|
{{if eq .CherryPickType "revert"}}
|
||||||
{{ctx.Locale.Tr "repo.editor.revert" $shalink | Str2html}}
|
{{ctx.Locale.Tr "repo.editor.revert" ($shalink|Safe)}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{ctx.Locale.Tr "repo.editor.cherry_pick" $shalink | Str2html}}
|
{{ctx.Locale.Tr "repo.editor.cherry_pick" ($shalink|Safe)}}
|
||||||
{{end}}
|
{{end}}
|
||||||
<a class="section" href="{{$.RepoLink}}">{{.Repository.FullName}}</a>
|
<a class="section" href="{{$.RepoLink}}">{{.Repository.FullName}}</a>
|
||||||
<div class="breadcrumb-divider">:</div>
|
<div class="breadcrumb-divider">:</div>
|
||||||
|
|
|
@ -595,11 +595,11 @@
|
||||||
{{$newProjectDisplayHtml = printf `<span data-tooltip-content="%s">%s</span>` (ctx.Locale.Tr $trKey | Escape) (.Project.Title | Escape)}}
|
{{$newProjectDisplayHtml = printf `<span data-tooltip-content="%s">%s</span>` (ctx.Locale.Tr $trKey | Escape) (.Project.Title | Escape)}}
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if and (gt .OldProjectID 0) (gt .ProjectID 0)}}
|
{{if and (gt .OldProjectID 0) (gt .ProjectID 0)}}
|
||||||
{{ctx.Locale.Tr "repo.issues.change_project_at" $oldProjectDisplayHtml $newProjectDisplayHtml $createdStr | Safe}}
|
{{ctx.Locale.Tr "repo.issues.change_project_at" ($oldProjectDisplayHtml|Safe) ($newProjectDisplayHtml|Safe) $createdStr}}
|
||||||
{{else if gt .OldProjectID 0}}
|
{{else if gt .OldProjectID 0}}
|
||||||
{{ctx.Locale.Tr "repo.issues.remove_project_at" $oldProjectDisplayHtml $createdStr | Safe}}
|
{{ctx.Locale.Tr "repo.issues.remove_project_at" ($oldProjectDisplayHtml|Safe) $createdStr}}
|
||||||
{{else if gt .ProjectID 0}}
|
{{else if gt .ProjectID 0}}
|
||||||
{{ctx.Locale.Tr "repo.issues.add_project_at" $newProjectDisplayHtml $createdStr | Safe}}
|
{{ctx.Locale.Tr "repo.issues.add_project_at" ($newProjectDisplayHtml|Safe) $createdStr}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -56,18 +56,18 @@
|
||||||
{{$mergedStr:= TimeSinceUnix .Issue.PullRequest.MergedUnix ctx.Locale}}
|
{{$mergedStr:= TimeSinceUnix .Issue.PullRequest.MergedUnix ctx.Locale}}
|
||||||
{{if .Issue.OriginalAuthor}}
|
{{if .Issue.OriginalAuthor}}
|
||||||
{{.Issue.OriginalAuthor}}
|
{{.Issue.OriginalAuthor}}
|
||||||
<span class="pull-desc">{{ctx.Locale.Tr "repo.pulls.merged_title_desc" .NumCommits $headHref $baseHref $mergedStr | Safe}}</span>
|
<span class="pull-desc">{{ctx.Locale.Tr "repo.pulls.merged_title_desc" .NumCommits ($headHref|Safe) ($baseHref|Safe) $mergedStr}}</span>
|
||||||
{{else}}
|
{{else}}
|
||||||
<a {{if gt .Issue.PullRequest.Merger.ID 0}}href="{{.Issue.PullRequest.Merger.HomeLink}}"{{end}}>{{.Issue.PullRequest.Merger.GetDisplayName}}</a>
|
<a {{if gt .Issue.PullRequest.Merger.ID 0}}href="{{.Issue.PullRequest.Merger.HomeLink}}"{{end}}>{{.Issue.PullRequest.Merger.GetDisplayName}}</a>
|
||||||
<span class="pull-desc">{{ctx.Locale.Tr "repo.pulls.merged_title_desc" .NumCommits $headHref $baseHref $mergedStr | Safe}}</span>
|
<span class="pull-desc">{{ctx.Locale.Tr "repo.pulls.merged_title_desc" .NumCommits ($headHref|Safe) ($baseHref|Safe) $mergedStr}}</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{if .Issue.OriginalAuthor}}
|
{{if .Issue.OriginalAuthor}}
|
||||||
<span id="pull-desc" class="pull-desc">{{.Issue.OriginalAuthor}} {{ctx.Locale.Tr "repo.pulls.title_desc" .NumCommits $headHref $baseHref | Safe}}</span>
|
<span id="pull-desc" class="pull-desc">{{.Issue.OriginalAuthor}} {{ctx.Locale.Tr "repo.pulls.title_desc" .NumCommits ($headHref|Safe) ($baseHref|Safe)}}</span>
|
||||||
{{else}}
|
{{else}}
|
||||||
<span id="pull-desc" class="pull-desc">
|
<span id="pull-desc" class="pull-desc">
|
||||||
<a {{if gt .Issue.Poster.ID 0}}href="{{.Issue.Poster.HomeLink}}"{{end}}>{{.Issue.Poster.GetDisplayName}}</a>
|
<a {{if gt .Issue.Poster.ID 0}}href="{{.Issue.Poster.HomeLink}}"{{end}}>{{.Issue.Poster.GetDisplayName}}</a>
|
||||||
{{ctx.Locale.Tr "repo.pulls.title_desc" .NumCommits $headHref $baseHref | Safe}}
|
{{ctx.Locale.Tr "repo.pulls.title_desc" .NumCommits ($headHref|Safe) ($baseHref|Safe)}}
|
||||||
</span>
|
</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
<span id="pull-desc-edit" class="gt-hidden flex-text-block">
|
<span id="pull-desc-edit" class="gt-hidden flex-text-block">
|
||||||
|
|
|
@ -9,21 +9,20 @@
|
||||||
{{end}}
|
{{end}}
|
||||||
</h4>
|
</h4>
|
||||||
<div class="ui attached segment">
|
<div class="ui attached segment">
|
||||||
<form class="ui form" action="{{.SignInLink}}" method="post">
|
<form class="ui form gt-max-width-36rem gt-m-auto" action="{{.SignInLink}}" method="post">
|
||||||
{{.CsrfTokenHtml}}
|
{{.CsrfTokenHtml}}
|
||||||
<div class="required inline field {{if and (.Err_UserName) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeSignIn))}}error{{end}}">
|
<div class="required inline field {{if and (.Err_UserName) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeSignIn))}}error{{end}}">
|
||||||
<label for="user_name">{{ctx.Locale.Tr "home.uname_holder"}}</label>
|
<label for="user_name">{{ctx.Locale.Tr "home.uname_holder"}}</label>
|
||||||
<input id="user_name" type="text" name="user_name" value="{{.user_name}}" autofocus required>
|
<input id="user_name" class="gt-w-full" type="text" name="user_name" value="{{.user_name}}" autofocus required>
|
||||||
</div>
|
</div>
|
||||||
{{if or (not .DisablePassword) .LinkAccountMode}}
|
{{if or (not .DisablePassword) .LinkAccountMode}}
|
||||||
<div class="required inline field {{if and (.Err_Password) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeSignIn))}}error{{end}}">
|
<div class="required inline field {{if and (.Err_Password) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeSignIn))}}error{{end}}">
|
||||||
<label for="password">{{ctx.Locale.Tr "password"}}</label>
|
<label for="password">{{ctx.Locale.Tr "password"}}</label>
|
||||||
<input id="password" name="password" type="password" value="{{.password}}" autocomplete="current-password" required>
|
<input id="password" class="gt-w-full" name="password" type="password" value="{{.password}}" autocomplete="current-password" required>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if not .LinkAccountMode}}
|
{{if not .LinkAccountMode}}
|
||||||
<div class="inline field">
|
<div class="inline field">
|
||||||
<label></label>
|
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
<label>{{ctx.Locale.Tr "auth.remember_me"}}</label>
|
<label>{{ctx.Locale.Tr "auth.remember_me"}}</label>
|
||||||
<input name="remember" type="checkbox">
|
<input name="remember" type="checkbox">
|
||||||
|
@ -34,7 +33,6 @@
|
||||||
{{template "user/auth/captcha" .}}
|
{{template "user/auth/captcha" .}}
|
||||||
|
|
||||||
<div class="inline field">
|
<div class="inline field">
|
||||||
<label></label>
|
|
||||||
<button class="ui primary button">
|
<button class="ui primary button">
|
||||||
{{if .LinkAccountMode}}
|
{{if .LinkAccountMode}}
|
||||||
{{ctx.Locale.Tr "auth.oauth_signin_submit"}}
|
{{ctx.Locale.Tr "auth.oauth_signin_submit"}}
|
||||||
|
@ -47,7 +45,6 @@
|
||||||
|
|
||||||
{{if .ShowRegistrationButton}}
|
{{if .ShowRegistrationButton}}
|
||||||
<div class="inline field">
|
<div class="inline field">
|
||||||
<label></label>
|
|
||||||
<a href="{{AppSubUrl}}/user/sign_up">{{ctx.Locale.Tr "auth.sign_up_now" | Str2html}}</a>
|
<a href="{{AppSubUrl}}/user/sign_up">{{ctx.Locale.Tr "auth.sign_up_now" | Str2html}}</a>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -60,7 +57,7 @@
|
||||||
<div class="gt-df gt-fc gt-jc">
|
<div class="gt-df gt-fc gt-jc">
|
||||||
<div id="oauth2-login-navigator-inner" class="gt-df gt-fc gt-fw gt-ac gt-gap-3">
|
<div id="oauth2-login-navigator-inner" class="gt-df gt-fc gt-fw gt-ac gt-gap-3">
|
||||||
{{range $provider := .OAuth2Providers}}
|
{{range $provider := .OAuth2Providers}}
|
||||||
<a class="{{$provider.Name}} ui button gt-df gt-ac gt-jc gt-py-3 oauth-login-link" href="{{AppSubUrl}}/user/oauth2/{{$provider.DisplayName}}">
|
<a class="{{$provider.Name}} ui button gt-df gt-ac gt-jc gt-py-3 gt-w-full oauth-login-link" href="{{AppSubUrl}}/user/oauth2/{{$provider.DisplayName}}">
|
||||||
{{$provider.IconHTML 28}}
|
{{$provider.IconHTML 28}}
|
||||||
{{ctx.Locale.Tr "sign_in_with_provider" $provider.DisplayName}}
|
{{ctx.Locale.Tr "sign_in_with_provider" $provider.DisplayName}}
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
OpenID
|
OpenID
|
||||||
</h4>
|
</h4>
|
||||||
<div class="ui attached segment">
|
<div class="ui attached segment">
|
||||||
<form class="ui form" action="{{.Link}}" method="post">
|
<form class="ui form gt-m-auto" action="{{.Link}}" method="post">
|
||||||
{{.CsrfTokenHtml}}
|
{{.CsrfTokenHtml}}
|
||||||
<div class="inline field">
|
<div class="inline field">
|
||||||
{{ctx.Locale.Tr "auth.openid_signin_desc"}}
|
{{ctx.Locale.Tr "auth.openid_signin_desc"}}
|
||||||
|
@ -18,17 +18,15 @@
|
||||||
{{svg "fontawesome-openid"}}
|
{{svg "fontawesome-openid"}}
|
||||||
OpenID URI
|
OpenID URI
|
||||||
</label>
|
</label>
|
||||||
<input id="openid" name="openid" value="{{.openid}}" autofocus required>
|
<input id="openid" class="gt-w-full" name="openid" value="{{.openid}}" autofocus required>
|
||||||
</div>
|
</div>
|
||||||
<div class="inline field">
|
<div class="inline field">
|
||||||
<label></label>
|
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
<label>{{ctx.Locale.Tr "auth.remember_me"}}</label>
|
<label>{{ctx.Locale.Tr "auth.remember_me"}}</label>
|
||||||
<input name="remember" type="checkbox">
|
<input name="remember" type="checkbox">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="inline field">
|
<div class="inline field">
|
||||||
<label></label>
|
|
||||||
<button class="ui primary button">{{ctx.Locale.Tr "sign_in"}}</button>
|
<button class="ui primary button">{{ctx.Locale.Tr "sign_in"}}</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
{{end}}
|
{{end}}
|
||||||
</h4>
|
</h4>
|
||||||
<div class="ui attached segment">
|
<div class="ui attached segment">
|
||||||
<form class="ui form" action="{{.SignUpLink}}" method="post">
|
<form class="ui form gt-max-width-36rem gt-m-auto" action="{{.SignUpLink}}" method="post">
|
||||||
{{.CsrfTokenHtml}}
|
{{.CsrfTokenHtml}}
|
||||||
{{if or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeRegister)}}
|
{{if or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeRegister)}}
|
||||||
{{template "base/alert" .}}
|
{{template "base/alert" .}}
|
||||||
|
@ -17,28 +17,27 @@
|
||||||
{{else}}
|
{{else}}
|
||||||
<div class="required inline field {{if and (.Err_UserName) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeRegister))}}error{{end}}">
|
<div class="required inline field {{if and (.Err_UserName) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeRegister))}}error{{end}}">
|
||||||
<label for="user_name">{{ctx.Locale.Tr "username"}}</label>
|
<label for="user_name">{{ctx.Locale.Tr "username"}}</label>
|
||||||
<input id="user_name" type="text" name="user_name" value="{{.user_name}}" autofocus required>
|
<input id="user_name" class="gt-w-full" type="text" name="user_name" value="{{.user_name}}" autofocus required>
|
||||||
</div>
|
</div>
|
||||||
<div class="required inline field {{if .Err_Email}}error{{end}}">
|
<div class="required inline field {{if .Err_Email}}error{{end}}">
|
||||||
<label for="email">{{ctx.Locale.Tr "email"}}</label>
|
<label for="email">{{ctx.Locale.Tr "email"}}</label>
|
||||||
<input id="email" name="email" type="email" value="{{.email}}" required>
|
<input id="email" class="gt-w-full" name="email" type="email" value="{{.email}}" required>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{if not .DisablePassword}}
|
{{if not .DisablePassword}}
|
||||||
<div class="required inline field {{if and (.Err_Password) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeRegister))}}error{{end}}">
|
<div class="required inline field {{if and (.Err_Password) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeRegister))}}error{{end}}">
|
||||||
<label for="password">{{ctx.Locale.Tr "password"}}</label>
|
<label for="password">{{ctx.Locale.Tr "password"}}</label>
|
||||||
<input id="password" name="password" type="password" value="{{.password}}" autocomplete="new-password" required>
|
<input id="password" class="gt-w-full" name="password" type="password" value="{{.password}}" autocomplete="new-password" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="required inline field {{if and (.Err_Password) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeRegister))}}error{{end}}">
|
<div class="required inline field {{if and (.Err_Password) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeRegister))}}error{{end}}">
|
||||||
<label for="retype">{{ctx.Locale.Tr "re_type"}}</label>
|
<label for="retype">{{ctx.Locale.Tr "re_type"}}</label>
|
||||||
<input id="retype" name="retype" type="password" value="{{.retype}}" autocomplete="new-password" required>
|
<input id="retype" class="gt-w-full" name="retype" type="password" value="{{.retype}}" autocomplete="new-password" required>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{template "user/auth/captcha" .}}
|
{{template "user/auth/captcha" .}}
|
||||||
|
|
||||||
<div class="inline field">
|
<div class="inline field">
|
||||||
<label></label>
|
|
||||||
<button class="ui primary button">
|
<button class="ui primary button">
|
||||||
{{if .LinkAccountMode}}
|
{{if .LinkAccountMode}}
|
||||||
{{ctx.Locale.Tr "auth.oauth_signup_submit"}}
|
{{ctx.Locale.Tr "auth.oauth_signup_submit"}}
|
||||||
|
@ -50,7 +49,6 @@
|
||||||
|
|
||||||
{{if not .LinkAccountMode}}
|
{{if not .LinkAccountMode}}
|
||||||
<div class="inline field">
|
<div class="inline field">
|
||||||
<label></label>
|
|
||||||
<a href="{{AppSubUrl}}/user/login">{{ctx.Locale.Tr "auth.register_helper_msg"}}</a>
|
<a href="{{AppSubUrl}}/user/login">{{ctx.Locale.Tr "auth.register_helper_msg"}}</a>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -64,7 +62,7 @@
|
||||||
<div class="gt-df gt-fc gt-jc">
|
<div class="gt-df gt-fc gt-jc">
|
||||||
<div id="oauth2-login-navigator-inner" class="gt-df gt-fc gt-fw gt-ac gt-gap-3">
|
<div id="oauth2-login-navigator-inner" class="gt-df gt-fc gt-fw gt-ac gt-gap-3">
|
||||||
{{range $provider := .OAuth2Providers}}
|
{{range $provider := .OAuth2Providers}}
|
||||||
<a class="{{$provider.Name}} ui button gt-df gt-ac gt-jc gt-py-3 oauth-login-link" href="{{AppSubUrl}}/user/oauth2/{{$provider.DisplayName}}">
|
<a class="{{$provider.Name}} ui button gt-df gt-ac gt-jc gt-py-3 gt-w-full oauth-login-link" href="{{AppSubUrl}}/user/oauth2/{{$provider.DisplayName}}">
|
||||||
{{$provider.IconHTML 28}}
|
{{$provider.IconHTML 28}}
|
||||||
{{ctx.Locale.Tr "sign_in_with_provider" $provider.DisplayName}}
|
{{ctx.Locale.Tr "sign_in_with_provider" $provider.DisplayName}}
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -309,7 +309,7 @@ func TestLDAPUserSyncWithGroupFilter(t *testing.T) {
|
||||||
// all groups the user is a member of, the user filter is modified accordingly inside
|
// all groups the user is a member of, the user filter is modified accordingly inside
|
||||||
// the addAuthSourceLDAP based on the value of the groupFilter
|
// the addAuthSourceLDAP based on the value of the groupFilter
|
||||||
u := otherLDAPUsers[0]
|
u := otherLDAPUsers[0]
|
||||||
testLoginFailed(t, u.UserName, u.Password, translation.NewLocale("en-US").Tr("form.username_password_incorrect"))
|
testLoginFailed(t, u.UserName, u.Password, translation.NewLocale("en-US").TrString("form.username_password_incorrect"))
|
||||||
|
|
||||||
auth.SyncExternalUsers(context.Background(), true)
|
auth.SyncExternalUsers(context.Background(), true)
|
||||||
|
|
||||||
|
@ -362,7 +362,7 @@ func TestLDAPUserSigninFailed(t *testing.T) {
|
||||||
addAuthSourceLDAP(t, "", "")
|
addAuthSourceLDAP(t, "", "")
|
||||||
|
|
||||||
u := otherLDAPUsers[0]
|
u := otherLDAPUsers[0]
|
||||||
testLoginFailed(t, u.UserName, u.Password, translation.NewLocale("en-US").Tr("form.username_password_incorrect"))
|
testLoginFailed(t, u.UserName, u.Password, translation.NewLocale("en-US").TrString("form.username_password_incorrect"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLDAPUserSSHKeySync(t *testing.T) {
|
func TestLDAPUserSSHKeySync(t *testing.T) {
|
||||||
|
|
|
@ -218,7 +218,7 @@ func TestCantMergeWorkInProgress(t *testing.T) {
|
||||||
text := strings.TrimSpace(htmlDoc.doc.Find(".merge-section > .item").Last().Text())
|
text := strings.TrimSpace(htmlDoc.doc.Find(".merge-section > .item").Last().Text())
|
||||||
assert.NotEmpty(t, text, "Can't find WIP text")
|
assert.NotEmpty(t, text, "Can't find WIP text")
|
||||||
|
|
||||||
assert.Contains(t, text, translation.NewLocale("en-US").Tr("repo.pulls.cannot_merge_work_in_progress"), "Unable to find WIP text")
|
assert.Contains(t, text, translation.NewLocale("en-US").TrString("repo.pulls.cannot_merge_work_in_progress"), "Unable to find WIP text")
|
||||||
assert.Contains(t, text, "[wip]", "Unable to find WIP text")
|
assert.Contains(t, text, "[wip]", "Unable to find WIP text")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,7 +90,7 @@ func TestCreateRelease(t *testing.T) {
|
||||||
session := loginUser(t, "user2")
|
session := loginUser(t, "user2")
|
||||||
createNewRelease(t, session, "/user2/repo1", "v0.0.1", "v0.0.1", false, false)
|
createNewRelease(t, session, "/user2/repo1", "v0.0.1", "v0.0.1", false, false)
|
||||||
|
|
||||||
checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", translation.NewLocale("en-US").Tr("repo.release.stable"), 4)
|
checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", translation.NewLocale("en-US").TrString("repo.release.stable"), 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDeleteRelease(t *testing.T) {
|
func TestDeleteRelease(t *testing.T) {
|
||||||
|
@ -137,7 +137,7 @@ func TestCreateReleasePreRelease(t *testing.T) {
|
||||||
session := loginUser(t, "user2")
|
session := loginUser(t, "user2")
|
||||||
createNewRelease(t, session, "/user2/repo1", "v0.0.1", "v0.0.1", true, false)
|
createNewRelease(t, session, "/user2/repo1", "v0.0.1", "v0.0.1", true, false)
|
||||||
|
|
||||||
checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", translation.NewLocale("en-US").Tr("repo.release.prerelease"), 4)
|
checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", translation.NewLocale("en-US").TrString("repo.release.prerelease"), 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateReleaseDraft(t *testing.T) {
|
func TestCreateReleaseDraft(t *testing.T) {
|
||||||
|
@ -146,7 +146,7 @@ func TestCreateReleaseDraft(t *testing.T) {
|
||||||
session := loginUser(t, "user2")
|
session := loginUser(t, "user2")
|
||||||
createNewRelease(t, session, "/user2/repo1", "v0.0.1", "v0.0.1", false, true)
|
createNewRelease(t, session, "/user2/repo1", "v0.0.1", "v0.0.1", false, true)
|
||||||
|
|
||||||
checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", translation.NewLocale("en-US").Tr("repo.release.draft"), 4)
|
checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", translation.NewLocale("en-US").TrString("repo.release.draft"), 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateReleasePaging(t *testing.T) {
|
func TestCreateReleasePaging(t *testing.T) {
|
||||||
|
@ -166,11 +166,11 @@ func TestCreateReleasePaging(t *testing.T) {
|
||||||
}
|
}
|
||||||
createNewRelease(t, session, "/user2/repo1", "v0.0.12", "v0.0.12", false, true)
|
createNewRelease(t, session, "/user2/repo1", "v0.0.12", "v0.0.12", false, true)
|
||||||
|
|
||||||
checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.12", translation.NewLocale("en-US").Tr("repo.release.draft"), 10)
|
checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.12", translation.NewLocale("en-US").TrString("repo.release.draft"), 10)
|
||||||
|
|
||||||
// Check that user4 does not see draft and still see 10 latest releases
|
// Check that user4 does not see draft and still see 10 latest releases
|
||||||
session2 := loginUser(t, "user4")
|
session2 := loginUser(t, "user4")
|
||||||
checkLatestReleaseAndCount(t, session2, "/user2/repo1", "v0.0.11", translation.NewLocale("en-US").Tr("repo.release.stable"), 10)
|
checkLatestReleaseAndCount(t, session2, "/user2/repo1", "v0.0.11", translation.NewLocale("en-US").TrString("repo.release.stable"), 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestViewReleaseListNoLogin(t *testing.T) {
|
func TestViewReleaseListNoLogin(t *testing.T) {
|
||||||
|
@ -265,7 +265,7 @@ func TestReleaseOnCommit(t *testing.T) {
|
||||||
session := loginUser(t, "user2")
|
session := loginUser(t, "user2")
|
||||||
createNewReleaseTarget(t, session, "/user2/repo1", "v0.0.1", "v0.0.1", "65f1bf27bc3bf70f64657658635e66094edbcb4d", false, false)
|
createNewReleaseTarget(t, session, "/user2/repo1", "v0.0.1", "v0.0.1", "65f1bf27bc3bf70f64657658635e66094edbcb4d", false, false)
|
||||||
|
|
||||||
checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", translation.NewLocale("en-US").Tr("repo.release.stable"), 4)
|
checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", translation.NewLocale("en-US").TrString("repo.release.stable"), 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestViewTagsList(t *testing.T) {
|
func TestViewTagsList(t *testing.T) {
|
||||||
|
|
|
@ -63,39 +63,39 @@ func testCreateBranches(t *testing.T, giteaURL *url.URL) {
|
||||||
OldRefSubURL: "branch/master",
|
OldRefSubURL: "branch/master",
|
||||||
NewBranch: "feature/test1",
|
NewBranch: "feature/test1",
|
||||||
ExpectedStatus: http.StatusSeeOther,
|
ExpectedStatus: http.StatusSeeOther,
|
||||||
FlashMessage: translation.NewLocale("en-US").Tr("repo.branch.create_success", "feature/test1"),
|
FlashMessage: translation.NewLocale("en-US").TrString("repo.branch.create_success", "feature/test1"),
|
||||||
CheckBranch: true,
|
CheckBranch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
OldRefSubURL: "branch/master",
|
OldRefSubURL: "branch/master",
|
||||||
NewBranch: "",
|
NewBranch: "",
|
||||||
ExpectedStatus: http.StatusSeeOther,
|
ExpectedStatus: http.StatusSeeOther,
|
||||||
FlashMessage: translation.NewLocale("en-US").Tr("form.NewBranchName") + translation.NewLocale("en-US").Tr("form.require_error"),
|
FlashMessage: translation.NewLocale("en-US").TrString("form.NewBranchName") + translation.NewLocale("en-US").TrString("form.require_error"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
OldRefSubURL: "branch/master",
|
OldRefSubURL: "branch/master",
|
||||||
NewBranch: "feature=test1",
|
NewBranch: "feature=test1",
|
||||||
ExpectedStatus: http.StatusSeeOther,
|
ExpectedStatus: http.StatusSeeOther,
|
||||||
FlashMessage: translation.NewLocale("en-US").Tr("repo.branch.create_success", "feature=test1"),
|
FlashMessage: translation.NewLocale("en-US").TrString("repo.branch.create_success", "feature=test1"),
|
||||||
CheckBranch: true,
|
CheckBranch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
OldRefSubURL: "branch/master",
|
OldRefSubURL: "branch/master",
|
||||||
NewBranch: strings.Repeat("b", 101),
|
NewBranch: strings.Repeat("b", 101),
|
||||||
ExpectedStatus: http.StatusSeeOther,
|
ExpectedStatus: http.StatusSeeOther,
|
||||||
FlashMessage: translation.NewLocale("en-US").Tr("form.NewBranchName") + translation.NewLocale("en-US").Tr("form.max_size_error", "100"),
|
FlashMessage: translation.NewLocale("en-US").TrString("form.NewBranchName") + translation.NewLocale("en-US").TrString("form.max_size_error", "100"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
OldRefSubURL: "branch/master",
|
OldRefSubURL: "branch/master",
|
||||||
NewBranch: "master",
|
NewBranch: "master",
|
||||||
ExpectedStatus: http.StatusSeeOther,
|
ExpectedStatus: http.StatusSeeOther,
|
||||||
FlashMessage: translation.NewLocale("en-US").Tr("repo.branch.branch_already_exists", "master"),
|
FlashMessage: translation.NewLocale("en-US").TrString("repo.branch.branch_already_exists", "master"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
OldRefSubURL: "branch/master",
|
OldRefSubURL: "branch/master",
|
||||||
NewBranch: "master/test",
|
NewBranch: "master/test",
|
||||||
ExpectedStatus: http.StatusSeeOther,
|
ExpectedStatus: http.StatusSeeOther,
|
||||||
FlashMessage: translation.NewLocale("en-US").Tr("repo.branch.branch_name_conflict", "master/test", "master"),
|
FlashMessage: translation.NewLocale("en-US").TrString("repo.branch.branch_name_conflict", "master/test", "master"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
OldRefSubURL: "commit/acd1d892867872cb47f3993468605b8aa59aa2e0",
|
OldRefSubURL: "commit/acd1d892867872cb47f3993468605b8aa59aa2e0",
|
||||||
|
@ -106,7 +106,7 @@ func testCreateBranches(t *testing.T, giteaURL *url.URL) {
|
||||||
OldRefSubURL: "commit/65f1bf27bc3bf70f64657658635e66094edbcb4d",
|
OldRefSubURL: "commit/65f1bf27bc3bf70f64657658635e66094edbcb4d",
|
||||||
NewBranch: "feature/test3",
|
NewBranch: "feature/test3",
|
||||||
ExpectedStatus: http.StatusSeeOther,
|
ExpectedStatus: http.StatusSeeOther,
|
||||||
FlashMessage: translation.NewLocale("en-US").Tr("repo.branch.create_success", "feature/test3"),
|
FlashMessage: translation.NewLocale("en-US").TrString("repo.branch.create_success", "feature/test3"),
|
||||||
CheckBranch: true,
|
CheckBranch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -114,14 +114,14 @@ func testCreateBranches(t *testing.T, giteaURL *url.URL) {
|
||||||
NewBranch: "v1.0.0",
|
NewBranch: "v1.0.0",
|
||||||
CreateRelease: "v1.0.0",
|
CreateRelease: "v1.0.0",
|
||||||
ExpectedStatus: http.StatusSeeOther,
|
ExpectedStatus: http.StatusSeeOther,
|
||||||
FlashMessage: translation.NewLocale("en-US").Tr("repo.branch.tag_collision", "v1.0.0"),
|
FlashMessage: translation.NewLocale("en-US").TrString("repo.branch.tag_collision", "v1.0.0"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
OldRefSubURL: "tag/v1.0.0",
|
OldRefSubURL: "tag/v1.0.0",
|
||||||
NewBranch: "feature/test4",
|
NewBranch: "feature/test4",
|
||||||
CreateRelease: "v1.0.1",
|
CreateRelease: "v1.0.1",
|
||||||
ExpectedStatus: http.StatusSeeOther,
|
ExpectedStatus: http.StatusSeeOther,
|
||||||
FlashMessage: translation.NewLocale("en-US").Tr("repo.branch.create_success", "feature/test4"),
|
FlashMessage: translation.NewLocale("en-US").TrString("repo.branch.create_success", "feature/test4"),
|
||||||
CheckBranch: true,
|
CheckBranch: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,10 +49,10 @@ func TestSignin(t *testing.T) {
|
||||||
password string
|
password string
|
||||||
message string
|
message string
|
||||||
}{
|
}{
|
||||||
{username: "wrongUsername", password: "wrongPassword", message: translation.NewLocale("en-US").Tr("form.username_password_incorrect")},
|
{username: "wrongUsername", password: "wrongPassword", message: translation.NewLocale("en-US").TrString("form.username_password_incorrect")},
|
||||||
{username: "wrongUsername", password: "password", message: translation.NewLocale("en-US").Tr("form.username_password_incorrect")},
|
{username: "wrongUsername", password: "password", message: translation.NewLocale("en-US").TrString("form.username_password_incorrect")},
|
||||||
{username: "user15", password: "wrongPassword", message: translation.NewLocale("en-US").Tr("form.username_password_incorrect")},
|
{username: "user15", password: "wrongPassword", message: translation.NewLocale("en-US").TrString("form.username_password_incorrect")},
|
||||||
{username: "user1@example.com", password: "wrongPassword", message: translation.NewLocale("en-US").Tr("form.username_password_incorrect")},
|
{username: "user1@example.com", password: "wrongPassword", message: translation.NewLocale("en-US").TrString("form.username_password_incorrect")},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range samples {
|
for _, s := range samples {
|
||||||
|
|
|
@ -69,9 +69,9 @@ func TestSignupEmail(t *testing.T) {
|
||||||
wantStatus int
|
wantStatus int
|
||||||
wantMsg string
|
wantMsg string
|
||||||
}{
|
}{
|
||||||
{"exampleUser@example.com\r\n", http.StatusOK, translation.NewLocale("en-US").Tr("form.email_invalid")},
|
{"exampleUser@example.com\r\n", http.StatusOK, translation.NewLocale("en-US").TrString("form.email_invalid")},
|
||||||
{"exampleUser@example.com\r", http.StatusOK, translation.NewLocale("en-US").Tr("form.email_invalid")},
|
{"exampleUser@example.com\r", http.StatusOK, translation.NewLocale("en-US").TrString("form.email_invalid")},
|
||||||
{"exampleUser@example.com\n", http.StatusOK, translation.NewLocale("en-US").Tr("form.email_invalid")},
|
{"exampleUser@example.com\n", http.StatusOK, translation.NewLocale("en-US").TrString("form.email_invalid")},
|
||||||
{"exampleUser@example.com", http.StatusSeeOther, ""},
|
{"exampleUser@example.com", http.StatusSeeOther, ""},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,7 +85,7 @@ func TestRenameInvalidUsername(t *testing.T) {
|
||||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||||
assert.Contains(t,
|
assert.Contains(t,
|
||||||
htmlDoc.doc.Find(".ui.negative.message").Text(),
|
htmlDoc.doc.Find(".ui.negative.message").Text(),
|
||||||
translation.NewLocale("en-US").Tr("form.username_error"),
|
translation.NewLocale("en-US").TrString("form.username_error"),
|
||||||
)
|
)
|
||||||
|
|
||||||
unittest.AssertNotExistsBean(t, &user_model.User{Name: invalidUsername})
|
unittest.AssertNotExistsBean(t, &user_model.User{Name: invalidUsername})
|
||||||
|
@ -147,7 +147,7 @@ func TestRenameReservedUsername(t *testing.T) {
|
||||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||||
assert.Contains(t,
|
assert.Contains(t,
|
||||||
htmlDoc.doc.Find(".ui.negative.message").Text(),
|
htmlDoc.doc.Find(".ui.negative.message").Text(),
|
||||||
translation.NewLocale("en-US").Tr("user.form.name_reserved", reservedUsername),
|
translation.NewLocale("en-US").TrString("user.form.name_reserved", reservedUsername),
|
||||||
)
|
)
|
||||||
|
|
||||||
unittest.AssertNotExistsBean(t, &user_model.User{Name: reservedUsername})
|
unittest.AssertNotExistsBean(t, &user_model.User{Name: reservedUsername})
|
||||||
|
|
|
@ -243,7 +243,6 @@ textarea:focus,
|
||||||
.user.forgot.password form,
|
.user.forgot.password form,
|
||||||
.user.reset.password form,
|
.user.reset.password form,
|
||||||
.user.link-account form,
|
.user.link-account form,
|
||||||
.user.signin form,
|
|
||||||
.user.signup form {
|
.user.signup form {
|
||||||
margin: auto;
|
margin: auto;
|
||||||
width: 700px !important;
|
width: 700px !important;
|
||||||
|
@ -279,7 +278,6 @@ textarea:focus,
|
||||||
.user.forgot.password form .inline.field > label,
|
.user.forgot.password form .inline.field > label,
|
||||||
.user.reset.password form .inline.field > label,
|
.user.reset.password form .inline.field > label,
|
||||||
.user.link-account form .inline.field > label,
|
.user.link-account form .inline.field > label,
|
||||||
.user.signin form .inline.field > label,
|
|
||||||
.user.signup form .inline.field > label {
|
.user.signup form .inline.field > label {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
width: 250px !important;
|
width: 250px !important;
|
||||||
|
|
|
@ -48,6 +48,7 @@ Gitea's private styles use `g-` prefix.
|
||||||
|
|
||||||
.gt-max-width-12rem { max-width: 12rem !important; }
|
.gt-max-width-12rem { max-width: 12rem !important; }
|
||||||
.gt-max-width-24rem { max-width: 24rem !important; }
|
.gt-max-width-24rem { max-width: 24rem !important; }
|
||||||
|
.gt-max-width-36rem { max-width: 36rem !important; }
|
||||||
|
|
||||||
/* below class names match Tailwind CSS */
|
/* below class names match Tailwind CSS */
|
||||||
.gt-break-all { word-break: break-all !important; }
|
.gt-break-all { word-break: break-all !important; }
|
||||||
|
|
Loading…
Reference in a new issue