diff --git a/Makefile b/Makefile index 2e2c86376b..3e2f1524e4 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,6 @@ else DIST := dist DIST_DIRS := $(DIST)/binaries $(DIST)/release IMPORT := code.gitea.io/gitea -export GO111MODULE=on GO ?= go SHASUM ?= shasum -a 256 @@ -363,7 +362,7 @@ test\#%: coverage: grep '^\(mode: .*\)\|\(.*:[0-9]\+\.[0-9]\+,[0-9]\+\.[0-9]\+ [0-9]\+ [0-9]\+\)$$' coverage.out > coverage-bodged.out grep '^\(mode: .*\)\|\(.*:[0-9]\+\.[0-9]\+,[0-9]\+\.[0-9]\+ [0-9]\+ [0-9]\+\)$$' integration.coverage.out > integration.coverage-bodged.out - GO111MODULE=on $(GO) run build/gocovmerge.go integration.coverage-bodged.out coverage-bodged.out > coverage.all || (echo "gocovmerge failed"; echo "integration.coverage.out"; cat integration.coverage.out; echo "coverage.out"; cat coverage.out; exit 1) + $(GO) run build/gocovmerge.go integration.coverage-bodged.out coverage-bodged.out > coverage.all || (echo "gocovmerge failed"; echo "integration.coverage.out"; cat integration.coverage.out; echo "coverage.out"; cat coverage.out; exit 1) .PHONY: unit-test-coverage unit-test-coverage: @@ -754,11 +753,11 @@ update-translations: .PHONY: generate-license generate-license: - GO111MODULE=on $(GO) run build/generate-licenses.go + $(GO) run build/generate-licenses.go .PHONY: generate-gitignore generate-gitignore: - GO111MODULE=on $(GO) run build/generate-gitignores.go + $(GO) run build/generate-gitignores.go .PHONY: generate-images generate-images: | node_modules diff --git a/SECURITY.md b/SECURITY.md index 7b43b32de5..9795e3168e 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -11,12 +11,12 @@ Please **DO NOT** file a public issue, instead send your report privately to `se Due to the sensitive nature of security information, you can use below GPG public key encrypt your mail body. -The PGP key is valid until June 24, 2024. -Key ID: 6FCD2D5B -Key Type: RSA -Expires: 6/24/2024 -Key Size: 4096/4096 -Fingerprint: 3DE0 3D1E 144A 7F06 9359 99DC AAFD 2381 6FCD 2D5B +The PGP key is valid until June 24, 2024. +Key ID: 6FCD2D5B +Key Type: RSA +Expires: 6/24/2024 +Key Size: 4096/4096 +Fingerprint: 3DE0 3D1E 144A 7F06 9359 99DC AAFD 2381 6FCD 2D5B UserID: Gitea Security ``` diff --git a/cmd/admin_auth_ldap.go b/cmd/admin_auth_ldap.go index ec86b2c671..9040def822 100644 --- a/cmd/admin_auth_ldap.go +++ b/cmd/admin_auth_ldap.go @@ -34,6 +34,10 @@ var ( Name: "not-active", Usage: "Deactivate the authentication source.", }, + cli.BoolFlag{ + Name: "active", + Usage: "Activate the authentication source.", + }, cli.StringFlag{ Name: "security-protocol", Usage: "Security protocol name.", @@ -117,6 +121,10 @@ var ( Name: "synchronize-users", Usage: "Enable user synchronization.", }, + cli.BoolFlag{ + Name: "disable-synchronize-users", + Usage: "Disable user synchronization.", + }, cli.UintFlag{ Name: "page-size", Usage: "Search page size.", @@ -183,9 +191,15 @@ func parseAuthSource(c *cli.Context, authSource *auth.Source) { if c.IsSet("not-active") { authSource.IsActive = !c.Bool("not-active") } + if c.IsSet("active") { + authSource.IsActive = c.Bool("active") + } if c.IsSet("synchronize-users") { authSource.IsSyncEnabled = c.Bool("synchronize-users") } + if c.IsSet("disable-synchronize-users") { + authSource.IsSyncEnabled = !c.Bool("disable-synchronize-users") + } } // parseLdapConfig assigns values on config according to command line flags. diff --git a/cmd/admin_auth_ldap_test.go b/cmd/admin_auth_ldap_test.go index f050b536fd..2180b24be5 100644 --- a/cmd/admin_auth_ldap_test.go +++ b/cmd/admin_auth_ldap_test.go @@ -858,6 +858,36 @@ func TestUpdateLdapBindDn(t *testing.T) { }, errMsg: "Invalid authentication type. expected: LDAP (via BindDN), actual: OAuth2", }, + // case 24 + { + args: []string{ + "ldap-test", + "--id", "24", + "--name", "ldap (via Bind DN) flip 'active' and 'user sync' attributes", + "--active", + "--disable-synchronize-users", + }, + id: 24, + existingAuthSource: &auth.Source{ + Type: auth.LDAP, + IsActive: false, + IsSyncEnabled: true, + Cfg: &ldap.Source{ + Name: "ldap (via Bind DN) flip 'active' and 'user sync' attributes", + Enabled: true, + }, + }, + authSource: &auth.Source{ + Type: auth.LDAP, + Name: "ldap (via Bind DN) flip 'active' and 'user sync' attributes", + IsActive: true, + IsSyncEnabled: false, + Cfg: &ldap.Source{ + Name: "ldap (via Bind DN) flip 'active' and 'user sync' attributes", + Enabled: true, + }, + }, + }, } for n, c := range cases { @@ -1221,6 +1251,33 @@ func TestUpdateLdapSimpleAuth(t *testing.T) { }, errMsg: "Invalid authentication type. expected: LDAP (simple auth), actual: PAM", }, + // case 20 + { + args: []string{ + "ldap-test", + "--id", "20", + "--name", "ldap (simple auth) flip 'active' attribute", + "--active", + }, + id: 20, + existingAuthSource: &auth.Source{ + Type: auth.DLDAP, + IsActive: false, + Cfg: &ldap.Source{ + Name: "ldap (simple auth) flip 'active' attribute", + Enabled: true, + }, + }, + authSource: &auth.Source{ + Type: auth.DLDAP, + Name: "ldap (simple auth) flip 'active' attribute", + IsActive: true, + Cfg: &ldap.Source{ + Name: "ldap (simple auth) flip 'active' attribute", + Enabled: true, + }, + }, + }, } for n, c := range cases { diff --git a/cmd/dump_repo.go b/cmd/dump_repo.go index e980af3011..c9d24c6c83 100644 --- a/cmd/dump_repo.go +++ b/cmd/dump_repo.go @@ -10,6 +10,7 @@ import ( "strings" "code.gitea.io/gitea/modules/convert" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" base "code.gitea.io/gitea/modules/migration" "code.gitea.io/gitea/modules/setting" @@ -83,6 +84,11 @@ func runDumpRepository(ctx *cli.Context) error { return err } + // migrations.GiteaLocalUploader depends on git module + if err := git.InitSimple(context.Background()); err != nil { + return err + } + log.Info("AppPath: %s", setting.AppPath) log.Info("AppWorkPath: %s", setting.AppWorkPath) log.Info("Custom path: %s", setting.CustomPath) @@ -128,7 +134,9 @@ func runDumpRepository(ctx *cli.Context) error { } else { units := strings.Split(ctx.String("units"), ",") for _, unit := range units { - switch strings.ToLower(unit) { + switch strings.ToLower(strings.TrimSpace(unit)) { + case "": + continue case "wiki": opts.Wiki = true case "issues": @@ -145,6 +153,8 @@ func runDumpRepository(ctx *cli.Context) error { opts.Comments = true case "pull_requests": opts.PullRequests = true + default: + return errors.New("invalid unit: " + unit) } } } diff --git a/cmd/restore_repo.go b/cmd/restore_repo.go index c3081279df..2256cc61ab 100644 --- a/cmd/restore_repo.go +++ b/cmd/restore_repo.go @@ -7,6 +7,7 @@ package cmd import ( "errors" "net/http" + "strings" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/private" @@ -37,10 +38,10 @@ var CmdRestoreRepository = cli.Command{ Value: "", Usage: "Restore destination repository name", }, - cli.StringSliceFlag{ + cli.StringFlag{ Name: "units", - Value: nil, - Usage: `Which items will be restored, one or more units should be repeated with this flag. + Value: "", + Usage: `Which items will be restored, one or more units should be separated as comma. wiki, issues, labels, releases, release_assets, milestones, pull_requests, comments are allowed. Empty means all units.`, }, cli.BoolFlag{ @@ -55,13 +56,16 @@ func runRestoreRepository(c *cli.Context) error { defer cancel() setting.LoadFromExisting() - + var units []string + if s := c.String("units"); s != "" { + units = strings.Split(s, ",") + } statusCode, errStr := private.RestoreRepo( ctx, c.String("repo_dir"), c.String("owner_name"), c.String("repo_name"), - c.StringSlice("units"), + units, c.Bool("validation"), ) if statusCode == http.StatusOK { diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 5016f29cf9..927dc71166 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -475,20 +475,6 @@ ENABLE = true ;; Maximum length of oauth2 token/cookie stored on server ;MAX_TOKEN_LENGTH = 32767 -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -[U2F] -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; -;; NOTE: THE DEFAULT VALUES HERE WILL NEED TO BE CHANGED -;; Two Factor authentication with security keys -;; https://developers.yubico.com/U2F/App_ID.html -;; -;; DEPRECATED - this only applies to previously registered security keys using the U2F standard -APP_ID = ; e.g. http://localhost:3000/ - - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; [log] @@ -1245,7 +1231,7 @@ PATH = ;; Define allowed algorithms and their minimum key length (use -1 to disable a type) ;ED25519 = 256 ;ECDSA = 256 -;RSA = 2048 +;RSA = 2047 ; we allow 2047 here because an otherwise valid 2048 bit RSA key can be reported as having 2047 bit length ;DSA = -1 ; set to 1024 to switch on ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -1690,7 +1676,7 @@ PATH = ;ENABLED = true ;; ;; Comma-separated list of allowed file extensions (`.zip`), mime types (`text/plain`) or wildcard type (`image/*`, `audio/*`, `video/*`). Empty value or `*/*` allows all types. -;ALLOWED_TYPES = .docx,.gif,.gz,.jpeg,.jpg,.mp4,.log,.pdf,.png,.pptx,.txt,.xlsx,.zip +;ALLOWED_TYPES = .csv,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.xls,.xlsx,.zip ;; ;; Max size of each file. Defaults to 4MB ;MAX_SIZE = 4 @@ -2127,7 +2113,7 @@ PATH = ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; The first locale will be used as the default if user browser's language doesn't match any locale in the list. -;LANGS = en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,uk-UA,ja-JP,es-ES,pt-BR,pt-PT,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR,el-GR,fa-IR,hu-HU,id-ID,ml-IN +;LANGS = en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,uk-UA,ja-JP,es-ES,pt-BR,pt-PT,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sv-SE,ko-KR,el-GR,fa-IR,hu-HU,id-ID,ml-IN ;NAMES = English,简体中文,繁體中文(香港),繁體中文(台灣),Deutsch,Français,Nederlands,Latviešu,Русский,Українська,日本語,Español,Português do Brasil,Português de Portugal,Polski,Български,Italiano,Suomi,Türkçe,Čeština,Српски,Svenska,한국어,Ελληνικά,فارسی,Magyar nyelv,Bahasa Indonesia,മലയാളം ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index df659b6540..c16a500ef3 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -621,7 +621,7 @@ Define allowed algorithms and their minimum key length (use -1 to disable a type - `ED25519`: **256** - `ECDSA`: **256** -- `RSA`: **2048** +- `RSA`: **2047**: We set 2047 here because an otherwise valid 2048 RSA key can be reported as 2047 length. - `DSA`: **-1**: DSA is now disabled by default. Set to **1024** to re-enable but ensure you may need to reconfigure your SSHD provider ## Webhook (`webhook`) @@ -742,7 +742,7 @@ Default templates for project boards: ## Issue and pull request attachments (`attachment`) - `ENABLED`: **true**: Whether issue and pull request attachments are enabled. -- `ALLOWED_TYPES`: **.docx,.gif,.gz,.jpeg,.jpg,mp4,.log,.pdf,.png,.pptx,.txt,.xlsx,.zip**: Comma-separated list of allowed file extensions (`.zip`), mime types (`text/plain`) or wildcard type (`image/*`, `audio/*`, `video/*`). Empty value or `*/*` allows all types. +- `ALLOWED_TYPES`: **.csv,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.xls,.xlsx,.zip**: Comma-separated list of allowed file extensions (`.zip`), mime types (`text/plain`) or wildcard type (`image/*`, `audio/*`, `video/*`). Empty value or `*/*` allows all types. - `MAX_SIZE`: **4**: Maximum size (MB). - `MAX_FILES`: **5**: Maximum number of attachments that can be uploaded at once. - `STORAGE_TYPE`: **local**: Storage type for attachments, `local` for local disk or `minio` for s3 compatible object storage service, default is `local` or other name defined with `[storage.xxx]` @@ -999,13 +999,10 @@ Default templates for project boards: ## i18n (`i18n`) -- `LANGS`: **en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,uk-UA,ja-JP,es-ES,pt-BR,pt-PT,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR,el-GR,fa-IR,hu-HU,id-ID,ml-IN**: +- `LANGS`: **en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,uk-UA,ja-JP,es-ES,pt-BR,pt-PT,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sv-SE,ko-KR,el-GR,fa-IR,hu-HU,id-ID,ml-IN**: List of locales shown in language selector. The first locale will be used as the default if user browser's language doesn't match any locale in the list. - `NAMES`: **English,简体中文,繁體中文(香港),繁體中文(台灣),Deutsch,Français,Nederlands,Latviešu,Русский,Українська,日本語,Español,Português do Brasil,Português de Portugal,Polski,Български,Italiano,Suomi,Türkçe,Čeština,Српски,Svenska,한국어,Ελληνικά,فارسی,Magyar nyelv,Bahasa Indonesia,മലയാളം**: Visible names corresponding to the locales -## U2F (`U2F`) **DEPRECATED** -- `APP_ID`: **`ROOT_URL`**: Declares the facet of the application which is used for authentication of previously registered U2F keys. Requires HTTPS. - ## Markup (`markup`) - `MERMAID_MAX_SOURCE_CHARACTERS`: **5000**: Set the maximum size of a Mermaid source. (Set to -1 to disable) diff --git a/docs/content/doc/advanced/customizing-gitea.en-us.md b/docs/content/doc/advanced/customizing-gitea.en-us.md index b97ba03482..3381c66d84 100644 --- a/docs/content/doc/advanced/customizing-gitea.en-us.md +++ b/docs/content/doc/advanced/customizing-gitea.en-us.md @@ -335,8 +335,8 @@ The list of themes a user can choose from can be configured with the `THEMES` va To make a custom theme available to all users: -1. Add a CSS file to `$GITEA_PUBLIC/public/css/theme-.css`. - The value of `$GITEA_PUBLIC` of your instance can be queried by calling `gitea help` and looking up the value of "CustomPath". +1. Add a CSS file to `$GITEA_CUSTOM/public/css/theme-.css`. + The value of `$GITEA_CUSTOM` of your instance can be queried by calling `gitea help` and looking up the value of "CustomPath". 2. Add `` to the comma-separated list of setting `THEMES` in `app.ini` Community themes are listed in [gitea/awesome-gitea#themes](https://gitea.com/gitea/awesome-gitea#themes). diff --git a/docs/content/doc/features/comparison.zh-tw.md b/docs/content/doc/features/comparison.zh-tw.md index 666e82d3c9..a2604c9052 100644 --- a/docs/content/doc/features/comparison.zh-tw.md +++ b/docs/content/doc/features/comparison.zh-tw.md @@ -50,7 +50,7 @@ menu: | 有寫入權限的儲存庫 Token | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✓ | | 內建 Container Registry | [✘](https://github.com/go-gitea/gitea/issues/2316) | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | | 對外部 Git 鏡像 | ✓ | ✓ | ✘ | ✘ | ✓ | ✓ | ✓ | -| FIDO U2F (2FA) | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | +| FIDO (2FA) | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | | 內建 CI/CD | ✘ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | | 子群組: 群組中的群組 | ✘ | ✘ | ✘ | ✓ | ✓ | ✘ | ✓ | diff --git a/go.mod b/go.mod index 9871d95582..8941b0f3ae 100644 --- a/go.mod +++ b/go.mod @@ -66,7 +66,7 @@ require ( github.com/mattn/go-isatty v0.0.14 github.com/mattn/go-sqlite3 v1.14.12 github.com/mholt/archiver/v3 v3.5.1 - github.com/microcosm-cc/bluemonday v1.0.18 + github.com/microcosm-cc/bluemonday v1.0.19 github.com/minio/minio-go/v7 v7.0.26 github.com/msteinert/pam v1.0.0 github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 @@ -94,9 +94,9 @@ require ( go.jolheiser.com/hcaptcha v0.0.4 go.jolheiser.com/pwn v0.0.3 golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122 - golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 + golang.org/x/net v0.0.0-20220630215102-69896b714898 golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 - golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 + golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a golang.org/x/text v0.3.7 golang.org/x/tools v0.1.10 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df diff --git a/go.sum b/go.sum index ae4d06d1f9..cc9cb1cc38 100644 --- a/go.sum +++ b/go.sum @@ -1154,8 +1154,8 @@ github.com/mholt/acmez v1.0.2 h1:C8wsEBIUVi6e0DYoxqCcFuXtwc4AWXL/jgcDjF7mjVo= github.com/mholt/acmez v1.0.2/go.mod h1:8qnn8QA/Ewx8E3ZSsmscqsIjhhpxuy9vqdgbX2ceceM= github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo= github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4= -github.com/microcosm-cc/bluemonday v1.0.18 h1:6HcxvXDAi3ARt3slx6nTesbvorIc3QeTzBNRvWktHBo= -github.com/microcosm-cc/bluemonday v1.0.18/go.mod h1:Z0r70sCuXHig8YpBzCc5eGHAap2K7e/u082ZUpDRRqM= +github.com/microcosm-cc/bluemonday v1.0.19 h1:OI7hoF5FY4pFz2VA//RN8TfM0YJ2dJcl4P4APrCWy6c= +github.com/microcosm-cc/bluemonday v1.0.19/go.mod h1:QNzV2UbLK2/53oIIwTOyLUSABMkjZ4tqiyC1g/DyqxE= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= @@ -1793,14 +1793,13 @@ golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA= -golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220630215102-69896b714898 h1:K7wO6V1IrczY9QOQ2WkVpw4JQSwCd52UsxVEirZUfiw= +golang.org/x/net v0.0.0-20220630215102-69896b714898/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1947,8 +1946,8 @@ golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 h1:nonptSpoQ4vQjyraW20DXPAglgQfVnM9ZC6MmNLMR60= -golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= diff --git a/integrations/auth_ldap_test.go b/integrations/auth_ldap_test.go index 296b647e6d..492a4fdadf 100644 --- a/integrations/auth_ldap_test.go +++ b/integrations/auth_ldap_test.go @@ -16,7 +16,7 @@ import ( "code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/translation/i18n" + "code.gitea.io/gitea/modules/translation" "code.gitea.io/gitea/services/auth" "github.com/stretchr/testify/assert" @@ -275,8 +275,7 @@ func TestLDAPUserSigninFailed(t *testing.T) { addAuthSourceLDAP(t, "") u := otherLDAPUsers[0] - - testLoginFailed(t, u.UserName, u.Password, i18n.Tr("en", "form.username_password_incorrect")) + testLoginFailed(t, u.UserName, u.Password, translation.NewLocale("en-US").Tr("form.username_password_incorrect")) } func TestLDAPUserSSHKeySync(t *testing.T) { diff --git a/integrations/branches_test.go b/integrations/branches_test.go index 551c5f8af8..8b05e24a04 100644 --- a/integrations/branches_test.go +++ b/integrations/branches_test.go @@ -9,7 +9,7 @@ import ( "net/url" "testing" - "code.gitea.io/gitea/modules/translation/i18n" + "code.gitea.io/gitea/modules/translation" "github.com/stretchr/testify/assert" ) @@ -37,7 +37,7 @@ func TestUndoDeleteBranch(t *testing.T) { htmlDoc, name := branchAction(t, ".undo-button") assert.Contains(t, htmlDoc.doc.Find(".ui.positive.message").Text(), - i18n.Tr("en", "repo.branch.restore_success", name), + translation.NewLocale("en-US").Tr("repo.branch.restore_success", name), ) }) } @@ -46,7 +46,7 @@ func deleteBranch(t *testing.T) { htmlDoc, name := branchAction(t, ".delete-branch-button") assert.Contains(t, htmlDoc.doc.Find(".ui.positive.message").Text(), - i18n.Tr("en", "repo.branch.deletion_success", name), + translation.NewLocale("en-US").Tr("repo.branch.deletion_success", name), ) } diff --git a/integrations/migrate_test.go b/integrations/migrate_test.go index 9b59c85a4e..f67e4ed229 100644 --- a/integrations/migrate_test.go +++ b/integrations/migrate_test.go @@ -5,12 +5,17 @@ package integrations import ( + "fmt" + "net/http" + "net/url" "os" "testing" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/services/migrations" "github.com/stretchr/testify/assert" @@ -40,3 +45,54 @@ func TestMigrateLocalPath(t *testing.T) { setting.ImportLocalPaths = old } + +func TestMigrateGiteaForm(t *testing.T) { + onGiteaRun(t, func(t *testing.T, u *url.URL) { + AllowLocalNetworks := setting.Migrations.AllowLocalNetworks + setting.Migrations.AllowLocalNetworks = true + AppVer := setting.AppVer + // Gitea SDK (go-sdk) need to parse the AppVer from server response, so we must set it to a valid version string. + setting.AppVer = "1.16.0" + defer func() { + setting.Migrations.AllowLocalNetworks = AllowLocalNetworks + setting.AppVer = AppVer + migrations.Init() + }() + assert.NoError(t, migrations.Init()) + + ownerName := "user2" + repoName := "repo1" + repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: ownerName}).(*user_model.User) + session := loginUser(t, ownerName) + token := getTokenForLoggedInUser(t, session) + + // Step 0: verify the repo is available + req := NewRequestf(t, "GET", fmt.Sprintf("/%s/%s", ownerName, repoName)) + _ = session.MakeRequest(t, req, http.StatusOK) + // Step 1: get the Gitea migration form + req = NewRequestf(t, "GET", "/repo/migrate/?service_type=%d", structs.GiteaService) + resp := session.MakeRequest(t, req, http.StatusOK) + // Step 2: load the form + htmlDoc := NewHTMLParser(t, resp.Body) + link, exists := htmlDoc.doc.Find(`form.ui.form[action^="/repo/migrate"]`).Attr("action") + assert.True(t, exists, "The template has changed") + // Step 4: submit the migration to only migrate issues + migratedRepoName := "otherrepo" + req = NewRequestWithValues(t, "POST", link, map[string]string{ + "_csrf": htmlDoc.GetCSRF(), + "service": fmt.Sprintf("%d", structs.GiteaService), + "clone_addr": fmt.Sprintf("%s%s/%s", u, ownerName, repoName), + "auth_token": token, + "issues": "on", + "repo_name": migratedRepoName, + "description": "", + "uid": fmt.Sprintf("%d", repoOwner.ID), + }) + resp = session.MakeRequest(t, req, http.StatusSeeOther) + // Step 5: a redirection displays the migrated repository + loc := resp.Header().Get("Location") + assert.EqualValues(t, fmt.Sprintf("/%s/%s", ownerName, migratedRepoName), loc) + // Step 6: check the repo was created + unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: migratedRepoName}) + }) +} diff --git a/integrations/pull_merge_test.go b/integrations/pull_merge_test.go index de519094d4..2a3a461efd 100644 --- a/integrations/pull_merge_test.go +++ b/integrations/pull_merge_test.go @@ -27,7 +27,7 @@ import ( "code.gitea.io/gitea/modules/git" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/test" - "code.gitea.io/gitea/modules/translation/i18n" + "code.gitea.io/gitea/modules/translation" "code.gitea.io/gitea/services/pull" repo_service "code.gitea.io/gitea/services/repository" files_service "code.gitea.io/gitea/services/repository/files" @@ -204,7 +204,7 @@ func TestCantMergeWorkInProgress(t *testing.T) { text := strings.TrimSpace(htmlDoc.doc.Find(".merge-section > .item").Last().Text()) assert.NotEmpty(t, text, "Can't find WIP text") - assert.Contains(t, text, i18n.Tr("en", "repo.pulls.cannot_merge_work_in_progress"), "Unable to 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, "[wip]", "Unable to find WIP text") }) } diff --git a/integrations/release_test.go b/integrations/release_test.go index d75d74956e..dd32a64ed5 100644 --- a/integrations/release_test.go +++ b/integrations/release_test.go @@ -14,7 +14,7 @@ import ( "code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/test" - "code.gitea.io/gitea/modules/translation/i18n" + "code.gitea.io/gitea/modules/translation" "github.com/PuerkitoBio/goquery" "github.com/stretchr/testify/assert" @@ -86,7 +86,7 @@ func TestCreateRelease(t *testing.T) { session := loginUser(t, "user2") createNewRelease(t, session, "/user2/repo1", "v0.0.1", "v0.0.1", false, false) - checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", i18n.Tr("en", "repo.release.stable"), 4) + checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", translation.NewLocale("en-US").Tr("repo.release.stable"), 4) } func TestCreateReleasePreRelease(t *testing.T) { @@ -95,7 +95,7 @@ func TestCreateReleasePreRelease(t *testing.T) { session := loginUser(t, "user2") createNewRelease(t, session, "/user2/repo1", "v0.0.1", "v0.0.1", true, false) - checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", i18n.Tr("en", "repo.release.prerelease"), 4) + checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", translation.NewLocale("en-US").Tr("repo.release.prerelease"), 4) } func TestCreateReleaseDraft(t *testing.T) { @@ -104,7 +104,7 @@ func TestCreateReleaseDraft(t *testing.T) { session := loginUser(t, "user2") createNewRelease(t, session, "/user2/repo1", "v0.0.1", "v0.0.1", false, true) - checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", i18n.Tr("en", "repo.release.draft"), 4) + checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", translation.NewLocale("en-US").Tr("repo.release.draft"), 4) } func TestCreateReleasePaging(t *testing.T) { @@ -124,11 +124,11 @@ func TestCreateReleasePaging(t *testing.T) { } createNewRelease(t, session, "/user2/repo1", "v0.0.12", "v0.0.12", false, true) - checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.12", i18n.Tr("en", "repo.release.draft"), 10) + checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.12", translation.NewLocale("en-US").Tr("repo.release.draft"), 10) // Check that user4 does not see draft and still see 10 latest releases session2 := loginUser(t, "user4") - checkLatestReleaseAndCount(t, session2, "/user2/repo1", "v0.0.11", i18n.Tr("en", "repo.release.stable"), 10) + checkLatestReleaseAndCount(t, session2, "/user2/repo1", "v0.0.11", translation.NewLocale("en-US").Tr("repo.release.stable"), 10) } func TestViewReleaseListNoLogin(t *testing.T) { diff --git a/integrations/repo_branch_test.go b/integrations/repo_branch_test.go index 30a446ccec..74d85c5b1f 100644 --- a/integrations/repo_branch_test.go +++ b/integrations/repo_branch_test.go @@ -13,7 +13,7 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/test" - "code.gitea.io/gitea/modules/translation/i18n" + "code.gitea.io/gitea/modules/translation" "github.com/stretchr/testify/assert" ) @@ -52,37 +52,37 @@ func testCreateBranches(t *testing.T, giteaURL *url.URL) { OldRefSubURL: "branch/master", NewBranch: "feature/test1", ExpectedStatus: http.StatusSeeOther, - FlashMessage: i18n.Tr("en", "repo.branch.create_success", "feature/test1"), + FlashMessage: translation.NewLocale("en-US").Tr("repo.branch.create_success", "feature/test1"), }, { OldRefSubURL: "branch/master", NewBranch: "", ExpectedStatus: http.StatusSeeOther, - FlashMessage: i18n.Tr("en", "form.NewBranchName") + i18n.Tr("en", "form.require_error"), + FlashMessage: translation.NewLocale("en-US").Tr("form.NewBranchName") + translation.NewLocale("en-US").Tr("form.require_error"), }, { OldRefSubURL: "branch/master", NewBranch: "feature=test1", ExpectedStatus: http.StatusSeeOther, - FlashMessage: i18n.Tr("en", "repo.branch.create_success", "feature=test1"), + FlashMessage: translation.NewLocale("en-US").Tr("repo.branch.create_success", "feature=test1"), }, { OldRefSubURL: "branch/master", NewBranch: strings.Repeat("b", 101), ExpectedStatus: http.StatusSeeOther, - FlashMessage: i18n.Tr("en", "form.NewBranchName") + i18n.Tr("en", "form.max_size_error", "100"), + FlashMessage: translation.NewLocale("en-US").Tr("form.NewBranchName") + translation.NewLocale("en-US").Tr("form.max_size_error", "100"), }, { OldRefSubURL: "branch/master", NewBranch: "master", ExpectedStatus: http.StatusSeeOther, - FlashMessage: i18n.Tr("en", "repo.branch.branch_already_exists", "master"), + FlashMessage: translation.NewLocale("en-US").Tr("repo.branch.branch_already_exists", "master"), }, { OldRefSubURL: "branch/master", NewBranch: "master/test", ExpectedStatus: http.StatusSeeOther, - FlashMessage: i18n.Tr("en", "repo.branch.branch_name_conflict", "master/test", "master"), + FlashMessage: translation.NewLocale("en-US").Tr("repo.branch.branch_name_conflict", "master/test", "master"), }, { OldRefSubURL: "commit/acd1d892867872cb47f3993468605b8aa59aa2e0", @@ -93,21 +93,21 @@ func testCreateBranches(t *testing.T, giteaURL *url.URL) { OldRefSubURL: "commit/65f1bf27bc3bf70f64657658635e66094edbcb4d", NewBranch: "feature/test3", ExpectedStatus: http.StatusSeeOther, - FlashMessage: i18n.Tr("en", "repo.branch.create_success", "feature/test3"), + FlashMessage: translation.NewLocale("en-US").Tr("repo.branch.create_success", "feature/test3"), }, { OldRefSubURL: "branch/master", NewBranch: "v1.0.0", CreateRelease: "v1.0.0", ExpectedStatus: http.StatusSeeOther, - FlashMessage: i18n.Tr("en", "repo.branch.tag_collision", "v1.0.0"), + FlashMessage: translation.NewLocale("en-US").Tr("repo.branch.tag_collision", "v1.0.0"), }, { OldRefSubURL: "tag/v1.0.0", NewBranch: "feature/test4", CreateRelease: "v1.0.1", ExpectedStatus: http.StatusSeeOther, - FlashMessage: i18n.Tr("en", "repo.branch.create_success", "feature/test4"), + FlashMessage: translation.NewLocale("en-US").Tr("repo.branch.create_success", "feature/test4"), }, } for _, test := range tests { diff --git a/integrations/signin_test.go b/integrations/signin_test.go index 811f9326ec..952efcfdd9 100644 --- a/integrations/signin_test.go +++ b/integrations/signin_test.go @@ -11,7 +11,7 @@ import ( "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/translation/i18n" + "code.gitea.io/gitea/modules/translation" "github.com/stretchr/testify/assert" ) @@ -47,10 +47,10 @@ func TestSignin(t *testing.T) { password string message string }{ - {username: "wrongUsername", password: "wrongPassword", message: i18n.Tr("en", "form.username_password_incorrect")}, - {username: "wrongUsername", password: "password", message: i18n.Tr("en", "form.username_password_incorrect")}, - {username: "user15", password: "wrongPassword", message: i18n.Tr("en", "form.username_password_incorrect")}, - {username: "user1@example.com", password: "wrongPassword", message: i18n.Tr("en", "form.username_password_incorrect")}, + {username: "wrongUsername", password: "wrongPassword", message: translation.NewLocale("en-US").Tr("form.username_password_incorrect")}, + {username: "wrongUsername", password: "password", message: translation.NewLocale("en-US").Tr("form.username_password_incorrect")}, + {username: "user15", password: "wrongPassword", message: translation.NewLocale("en-US").Tr("form.username_password_incorrect")}, + {username: "user1@example.com", password: "wrongPassword", message: translation.NewLocale("en-US").Tr("form.username_password_incorrect")}, } for _, s := range samples { diff --git a/integrations/signup_test.go b/integrations/signup_test.go index 7b45674376..b34e40f286 100644 --- a/integrations/signup_test.go +++ b/integrations/signup_test.go @@ -13,7 +13,7 @@ import ( "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/translation/i18n" + "code.gitea.io/gitea/modules/translation" "github.com/stretchr/testify/assert" ) @@ -68,9 +68,9 @@ func TestSignupEmail(t *testing.T) { wantStatus int wantMsg string }{ - {"exampleUser@example.com\r\n", http.StatusOK, i18n.Tr("en", "form.email_invalid")}, - {"exampleUser@example.com\r", http.StatusOK, i18n.Tr("en", "form.email_invalid")}, - {"exampleUser@example.com\n", http.StatusOK, i18n.Tr("en", "form.email_invalid")}, + {"exampleUser@example.com\r\n", http.StatusOK, translation.NewLocale("en-US").Tr("form.email_invalid")}, + {"exampleUser@example.com\r", http.StatusOK, translation.NewLocale("en-US").Tr("form.email_invalid")}, + {"exampleUser@example.com\n", http.StatusOK, translation.NewLocale("en-US").Tr("form.email_invalid")}, {"exampleUser@example.com", http.StatusSeeOther, ""}, } diff --git a/integrations/user_test.go b/integrations/user_test.go index 41127a4e40..33113369a7 100644 --- a/integrations/user_test.go +++ b/integrations/user_test.go @@ -14,7 +14,7 @@ import ( user_model "code.gitea.io/gitea/models/user" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/test" - "code.gitea.io/gitea/modules/translation/i18n" + "code.gitea.io/gitea/modules/translation" "github.com/stretchr/testify/assert" ) @@ -67,7 +67,7 @@ func TestRenameInvalidUsername(t *testing.T) { htmlDoc := NewHTMLParser(t, resp.Body) assert.Contains(t, htmlDoc.doc.Find(".ui.negative.message").Text(), - i18n.Tr("en", "form.alpha_dash_dot_error"), + translation.NewLocale("en-US").Tr("form.alpha_dash_dot_error"), ) unittest.AssertNotExistsBean(t, &user_model.User{Name: invalidUsername}) @@ -131,7 +131,7 @@ func TestRenameReservedUsername(t *testing.T) { htmlDoc := NewHTMLParser(t, resp.Body) assert.Contains(t, htmlDoc.doc.Find(".ui.negative.message").Text(), - i18n.Tr("en", "user.form.name_reserved", reservedUsername), + translation.NewLocale("en-US").Tr("user.form.name_reserved", reservedUsername), ) unittest.AssertNotExistsBean(t, &user_model.User{Name: reservedUsername}) diff --git a/models/action.go b/models/action.go index 791759f7e8..14e021389a 100644 --- a/models/action.go +++ b/models/action.go @@ -92,12 +92,12 @@ func init() { // TableIndices implements xorm's TableIndices interface func (a *Action) TableIndices() []*schemas.Index { + repoIndex := schemas.NewIndex("r_u_d", schemas.IndexType) + repoIndex.AddColumn("repo_id", "user_id", "is_deleted") + actUserIndex := schemas.NewIndex("au_r_c_u_d", schemas.IndexType) actUserIndex.AddColumn("act_user_id", "repo_id", "created_unix", "user_id", "is_deleted") - repoIndex := schemas.NewIndex("r_c_u_d", schemas.IndexType) - repoIndex.AddColumn("repo_id", "created_unix", "user_id", "is_deleted") - return []*schemas.Index{actUserIndex, repoIndex} } diff --git a/models/issues/issue_project.go b/models/issues/issue_project.go index b83665c2bb..aed78611ea 100644 --- a/models/issues/issue_project.go +++ b/models/issues/issue_project.go @@ -124,6 +124,17 @@ func ChangeProjectAssign(issue *Issue, doer *user_model.User, newProjectID int64 func addUpdateIssueProject(ctx context.Context, issue *Issue, doer *user_model.User, newProjectID int64) error { oldProjectID := issue.projectID(ctx) + // Only check if we add a new project and not remove it. + if newProjectID > 0 { + newProject, err := project_model.GetProjectByID(ctx, newProjectID) + if err != nil { + return err + } + if newProject.RepoID != issue.RepoID { + return fmt.Errorf("issue's repository is not the same as project's repository") + } + } + if _, err := db.GetEngine(ctx).Where("project_issue.issue_id=?", issue.ID).Delete(&project_model.ProjectIssue{}); err != nil { return err } diff --git a/models/issues/milestone.go b/models/issues/milestone.go index 6c10959108..c49799f391 100644 --- a/models/issues/milestone.go +++ b/models/issues/milestone.go @@ -124,6 +124,11 @@ func NewMilestone(m *Milestone) (err error) { return committer.Commit() } +// HasMilestoneByRepoID returns if the milestone exists in the repository. +func HasMilestoneByRepoID(ctx context.Context, repoID, id int64) (bool, error) { + return db.GetEngine(ctx).ID(id).Where("repo_id=?", repoID).Exist(new(Milestone)) +} + // GetMilestoneByRepoID returns the milestone in a repository. func GetMilestoneByRepoID(ctx context.Context, repoID, id int64) (*Milestone, error) { m := new(Milestone) @@ -356,7 +361,7 @@ func (opts GetMilestonesOption) toCond() builder.Cond { } if len(opts.Name) != 0 { - cond = cond.And(builder.Like{"name", opts.Name}) + cond = cond.And(builder.Like{"UPPER(name)", strings.ToUpper(opts.Name)}) } return cond diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index edd4beb451..0d35ac78d3 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -56,6 +56,9 @@ type Version struct { Version int64 } +// Use noopMigration when there is a migration that has been no-oped +var noopMigration = func(_ *xorm.Engine) error { return nil } + // This is a sequence of migrations. Add new migrations to the bottom of the list. // If you want to "retire" a migration, remove it from the top of the list and // update minDBVersion accordingly @@ -351,7 +354,7 @@ var migrations = []Migration{ // v198 -> v199 NewMigration("Add issue content history table", addTableIssueContentHistory), // v199 -> v200 - NewMigration("No-op (remote version is using AppState now)", addRemoteVersionTableNoop), + NewMigration("No-op (remote version is using AppState now)", noopMigration), // v200 -> v201 NewMigration("Add table app_state", addTableAppState), // v201 -> v202 @@ -388,9 +391,11 @@ var migrations = []Migration{ // v215 -> v216 NewMigration("allow to view files in PRs", addReviewViewedFiles), // v216 -> v217 - NewMigration("Improve Action table indices", improveActionTableIndices), + NewMigration("No-op (Improve Action table indices v1)", noopMigration), // v217 -> v218 NewMigration("Alter hook_task table TEXT fields to LONGTEXT", alterHookTaskTextFieldsToLongText), + // v218 -> v219 + NewMigration("Improve Action table indices v2", improveActionTableIndices), } // GetCurrentDBVersion returns the current db version diff --git a/models/migrations/v199.go b/models/migrations/v199.go index 4351ba4fa8..29f9d49dbe 100644 --- a/models/migrations/v199.go +++ b/models/migrations/v199.go @@ -4,11 +4,4 @@ package migrations -import ( - "xorm.io/xorm" -) - -func addRemoteVersionTableNoop(x *xorm.Engine) error { - // we used to use a table `remote_version` to store information for updater, now we use `AppState`, so this migration task is a no-op now. - return nil -} +// We used to use a table `remote_version` to store information for updater, now we use `AppState`, so this migration task is a no-op now. diff --git a/models/migrations/v216.go b/models/migrations/v216.go index 67c360016d..ab44808402 100644 --- a/models/migrations/v216.go +++ b/models/migrations/v216.go @@ -4,43 +4,5 @@ package migrations -import ( - "code.gitea.io/gitea/modules/timeutil" - - "xorm.io/xorm" - "xorm.io/xorm/schemas" -) - -type improveActionTableIndicesAction struct { - ID int64 `xorm:"pk autoincr"` - UserID int64 // Receiver user id. - OpType int - ActUserID int64 // Action user id. - RepoID int64 - CommentID int64 `xorm:"INDEX"` - IsDeleted bool `xorm:"NOT NULL DEFAULT false"` - RefName string - IsPrivate bool `xorm:"NOT NULL DEFAULT false"` - Content string `xorm:"TEXT"` - CreatedUnix timeutil.TimeStamp `xorm:"created"` -} - -// TableName sets the name of this table -func (a *improveActionTableIndicesAction) TableName() string { - return "action" -} - -// TableIndices implements xorm's TableIndices interface -func (a *improveActionTableIndicesAction) TableIndices() []*schemas.Index { - actUserIndex := schemas.NewIndex("au_r_c_u_d", schemas.IndexType) - actUserIndex.AddColumn("act_user_id", "repo_id", "created_unix", "user_id", "is_deleted") - - repoIndex := schemas.NewIndex("r_c_u_d", schemas.IndexType) - repoIndex.AddColumn("repo_id", "created_unix", "user_id", "is_deleted") - - return []*schemas.Index{actUserIndex, repoIndex} -} - -func improveActionTableIndices(x *xorm.Engine) error { - return x.Sync2(&improveActionTableIndicesAction{}) -} +// This migration added non-ideal indices to the action table which on larger datasets slowed things down +// it has been superceded by v218.go diff --git a/models/migrations/v218.go b/models/migrations/v218.go new file mode 100644 index 0000000000..dee8e5517e --- /dev/null +++ b/models/migrations/v218.go @@ -0,0 +1,46 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package migrations + +import ( + "code.gitea.io/gitea/modules/timeutil" + + "xorm.io/xorm" + "xorm.io/xorm/schemas" +) + +type improveActionTableIndicesAction struct { + ID int64 `xorm:"pk autoincr"` + UserID int64 // Receiver user id. + OpType int + ActUserID int64 // Action user id. + RepoID int64 + CommentID int64 `xorm:"INDEX"` + IsDeleted bool `xorm:"NOT NULL DEFAULT false"` + RefName string + IsPrivate bool `xorm:"NOT NULL DEFAULT false"` + Content string `xorm:"TEXT"` + CreatedUnix timeutil.TimeStamp `xorm:"created"` +} + +// TableName sets the name of this table +func (*improveActionTableIndicesAction) TableName() string { + return "action" +} + +// TableIndices implements xorm's TableIndices interface +func (*improveActionTableIndicesAction) TableIndices() []*schemas.Index { + repoIndex := schemas.NewIndex("r_u_d", schemas.IndexType) + repoIndex.AddColumn("repo_id", "user_id", "is_deleted") + + actUserIndex := schemas.NewIndex("au_r_c_u_d", schemas.IndexType) + actUserIndex.AddColumn("act_user_id", "repo_id", "created_unix", "user_id", "is_deleted") + + return []*schemas.Index{actUserIndex, repoIndex} +} + +func improveActionTableIndices(x *xorm.Engine) error { + return x.Sync2(&improveActionTableIndicesAction{}) +} diff --git a/models/user/user.go b/models/user/user.go index 9460bd38fe..125c643f3e 100644 --- a/models/user/user.go +++ b/models/user/user.go @@ -316,37 +316,45 @@ func (u *User) GenerateEmailActivateCode(email string) string { } // GetUserFollowers returns range of user's followers. -func GetUserFollowers(u *User, listOptions db.ListOptions) ([]*User, error) { - sess := db.GetEngine(db.DefaultContext). +func GetUserFollowers(ctx context.Context, u, viewer *User, listOptions db.ListOptions) ([]*User, int64, error) { + sess := db.GetEngine(ctx). + Select("`user`.*"). + Join("LEFT", "follow", "`user`.id=follow.user_id"). Where("follow.follow_id=?", u.ID). - Join("LEFT", "follow", "`user`.id=follow.user_id") + And(isUserVisibleToViewerCond(viewer)) if listOptions.Page != 0 { sess = db.SetSessionPagination(sess, &listOptions) users := make([]*User, 0, listOptions.PageSize) - return users, sess.Find(&users) + count, err := sess.FindAndCount(&users) + return users, count, err } users := make([]*User, 0, 8) - return users, sess.Find(&users) + count, err := sess.FindAndCount(&users) + return users, count, err } // GetUserFollowing returns range of user's following. -func GetUserFollowing(u *User, listOptions db.ListOptions) ([]*User, error) { +func GetUserFollowing(ctx context.Context, u, viewer *User, listOptions db.ListOptions) ([]*User, int64, error) { sess := db.GetEngine(db.DefaultContext). + Select("`user`.*"). + Join("LEFT", "follow", "`user`.id=follow.follow_id"). Where("follow.user_id=?", u.ID). - Join("LEFT", "follow", "`user`.id=follow.follow_id") + And(isUserVisibleToViewerCond(viewer)) if listOptions.Page != 0 { sess = db.SetSessionPagination(sess, &listOptions) users := make([]*User, 0, listOptions.PageSize) - return users, sess.Find(&users) + count, err := sess.FindAndCount(&users) + return users, count, err } users := make([]*User, 0, 8) - return users, sess.Find(&users) + count, err := sess.FindAndCount(&users) + return users, count, err } // NewGitSig generates and returns the signature of given user. @@ -485,6 +493,9 @@ func (u *User) GitName() string { // ShortName ellipses username to length func (u *User) ShortName(length int) string { + if setting.UI.DefaultShowFullName && len(u.FullName) > 0 { + return base.EllipsisString(u.FullName, length) + } return base.EllipsisString(u.Name, length) } @@ -1219,6 +1230,39 @@ func GetAdminUser() (*User, error) { return &admin, nil } +func isUserVisibleToViewerCond(viewer *User) builder.Cond { + if viewer != nil && viewer.IsAdmin { + return builder.NewCond() + } + + if viewer == nil || viewer.IsRestricted { + return builder.Eq{ + "`user`.visibility": structs.VisibleTypePublic, + } + } + + return builder.Neq{ + "`user`.visibility": structs.VisibleTypePrivate, + }.Or( + builder.In("`user`.id", + builder. + Select("`follow`.user_id"). + From("follow"). + Where(builder.Eq{"`follow`.follow_id": viewer.ID})), + builder.In("`user`.id", + builder. + Select("`team_user`.uid"). + From("team_user"). + Join("INNER", "`team_user` AS t2", "`team_user`.id = `t2`.id"). + Where(builder.Eq{"`t2`.uid": viewer.ID})), + builder.In("`user`.id", + builder. + Select("`team_user`.uid"). + From("team_user"). + Join("INNER", "`team_user` AS t2", "`team_user`.org_id = `t2`.org_id"). + Where(builder.Eq{"`t2`.uid": viewer.ID}))) +} + // IsUserVisibleToViewer check if viewer is able to see user profile func IsUserVisibleToViewer(ctx context.Context, u, viewer *User) bool { if viewer != nil && viewer.IsAdmin { diff --git a/modules/context/context.go b/modules/context/context.go index dcc43973ca..68f8a1b408 100644 --- a/modules/context/context.go +++ b/modules/context/context.go @@ -794,7 +794,7 @@ func Contexter() func(next http.Handler) http.Handler { ctx.Data["UnitPullsGlobalDisabled"] = unit.TypePullRequests.UnitGlobalDisabled() ctx.Data["UnitProjectsGlobalDisabled"] = unit.TypeProjects.UnitGlobalDisabled() - ctx.Data["i18n"] = locale + ctx.Data["locale"] = locale ctx.Data["AllLangs"] = translation.AllLangs() next.ServeHTTP(ctx.Resp, ctx.Req) diff --git a/modules/doctor/breaking.go b/modules/doctor/breaking.go index c4b58d20fb..3e01d97d7c 100644 --- a/modules/doctor/breaking.go +++ b/modules/doctor/breaking.go @@ -58,6 +58,29 @@ func checkUserEmail(ctx context.Context, logger log.Logger, _ bool) error { return nil } +// From time to time Gitea makes changes to the reserved usernames and which symbols +// are allowed for various reasons. This check helps with detecting users that, according +// to our reserved names, don't have a valid username. +func checkUserName(ctx context.Context, logger log.Logger, _ bool) error { + var invalidUserCount int64 + if err := iterateUserAccounts(ctx, func(u *user.User) error { + if err := user.IsUsableUsername(u.Name); err != nil { + invalidUserCount++ + logger.Warn("User[id=%d] does not have a valid username: %v", u.ID, err) + } + return nil + }); err != nil { + return fmt.Errorf("iterateUserAccounts: %v", err) + } + + if invalidUserCount == 0 { + logger.Info("All users have a valid username.") + } else { + logger.Warn("%d user(s) have a non-valid username.", invalidUserCount) + } + return nil +} + func init() { Register(&Check{ Title: "Check if users has an valid email address", @@ -66,4 +89,11 @@ func init() { Run: checkUserEmail, Priority: 9, }) + Register(&Check{ + Title: "Check if users have a valid username", + Name: "check-user-names", + IsDefault: false, + Run: checkUserName, + Priority: 9, + }) } diff --git a/modules/indexer/code/elastic_search.go b/modules/indexer/code/elastic_search.go index a669c66bb4..7727bfacde 100644 --- a/modules/indexer/code/elastic_search.go +++ b/modules/indexer/code/elastic_search.go @@ -284,7 +284,7 @@ func (b *ElasticSearchIndexer) Index(ctx context.Context, repo *repo_model.Repos reqs := make([]elastic.BulkableRequest, 0) if len(changes.Updates) > 0 { // Now because of some insanity with git cat-file not immediately failing if not run in a valid git directory we need to run git rev-parse first! - if err := git.EnsureValidGitRepository(git.DefaultContext, repo.RepoPath()); err != nil { + if err := git.EnsureValidGitRepository(ctx, repo.RepoPath()); err != nil { log.Error("Unable to open git repo: %s for %-v: %v", repo.RepoPath(), repo, err) return err } diff --git a/modules/markup/html.go b/modules/markup/html.go index 69d9ba3ef2..6071180501 100644 --- a/modules/markup/html.go +++ b/modules/markup/html.go @@ -841,9 +841,10 @@ func issueIndexPatternProcessor(ctx *RenderContext, node *html.Node) { // Repos with external issue trackers might still need to reference local PRs // We need to concern with the first one that shows up in the text, whichever it is - if hasExtTrackFormat && !isNumericStyle { + if hasExtTrackFormat && !isNumericStyle && refNumeric != nil { // If numeric (PR) was found, and it was BEFORE the non-numeric pattern, use that - if foundNumeric && refNumeric.RefLocation.Start < ref.RefLocation.Start { + // Allow a free-pass when non-numeric pattern wasn't found. + if found && (ref == nil || refNumeric.RefLocation.Start < ref.RefLocation.Start) { found = foundNumeric ref = refNumeric } diff --git a/modules/markup/markdown/toc.go b/modules/markup/markdown/toc.go index fec45103e5..103894d1ab 100644 --- a/modules/markup/markdown/toc.go +++ b/modules/markup/markdown/toc.go @@ -9,7 +9,7 @@ import ( "net/url" "code.gitea.io/gitea/modules/markup" - "code.gitea.io/gitea/modules/translation/i18n" + "code.gitea.io/gitea/modules/translation" "github.com/yuin/goldmark/ast" ) @@ -18,7 +18,7 @@ func createTOCNode(toc []markup.Header, lang string) ast.Node { details := NewDetails() summary := NewSummary() - summary.AppendChild(summary, ast.NewString([]byte(i18n.Tr(lang, "toc")))) + summary.AppendChild(summary, ast.NewString([]byte(translation.NewLocale(lang).Tr("toc")))) details.AppendChild(details, summary) ul := ast.NewList('-') details.AppendChild(details, ul) diff --git a/modules/migration/null_downloader.go b/modules/migration/null_downloader.go index 32da720f16..ad925c32ce 100644 --- a/modules/migration/null_downloader.go +++ b/modules/migration/null_downloader.go @@ -19,52 +19,52 @@ func (n NullDownloader) SetContext(_ context.Context) {} // GetRepoInfo returns a repository information func (n NullDownloader) GetRepoInfo() (*Repository, error) { - return nil, &ErrNotSupported{Entity: "RepoInfo"} + return nil, ErrNotSupported{Entity: "RepoInfo"} } // GetTopics return repository topics func (n NullDownloader) GetTopics() ([]string, error) { - return nil, &ErrNotSupported{Entity: "Topics"} + return nil, ErrNotSupported{Entity: "Topics"} } // GetMilestones returns milestones func (n NullDownloader) GetMilestones() ([]*Milestone, error) { - return nil, &ErrNotSupported{Entity: "Milestones"} + return nil, ErrNotSupported{Entity: "Milestones"} } // GetReleases returns releases func (n NullDownloader) GetReleases() ([]*Release, error) { - return nil, &ErrNotSupported{Entity: "Releases"} + return nil, ErrNotSupported{Entity: "Releases"} } // GetLabels returns labels func (n NullDownloader) GetLabels() ([]*Label, error) { - return nil, &ErrNotSupported{Entity: "Labels"} + return nil, ErrNotSupported{Entity: "Labels"} } // GetIssues returns issues according start and limit func (n NullDownloader) GetIssues(page, perPage int) ([]*Issue, bool, error) { - return nil, false, &ErrNotSupported{Entity: "Issues"} + return nil, false, ErrNotSupported{Entity: "Issues"} } // GetComments returns comments of an issue or PR func (n NullDownloader) GetComments(commentable Commentable) ([]*Comment, bool, error) { - return nil, false, &ErrNotSupported{Entity: "Comments"} + return nil, false, ErrNotSupported{Entity: "Comments"} } // GetAllComments returns paginated comments func (n NullDownloader) GetAllComments(page, perPage int) ([]*Comment, bool, error) { - return nil, false, &ErrNotSupported{Entity: "AllComments"} + return nil, false, ErrNotSupported{Entity: "AllComments"} } // GetPullRequests returns pull requests according page and perPage func (n NullDownloader) GetPullRequests(page, perPage int) ([]*PullRequest, bool, error) { - return nil, false, &ErrNotSupported{Entity: "PullRequests"} + return nil, false, ErrNotSupported{Entity: "PullRequests"} } // GetReviews returns pull requests review func (n NullDownloader) GetReviews(reviewable Reviewable) ([]*Review, error) { - return nil, &ErrNotSupported{Entity: "Reviews"} + return nil, ErrNotSupported{Entity: "Reviews"} } // FormatCloneURL add authentication into remote URLs diff --git a/modules/setting/attachment.go b/modules/setting/attachment.go index c3c2c3fafd..474b73293c 100644 --- a/modules/setting/attachment.go +++ b/modules/setting/attachment.go @@ -27,7 +27,7 @@ func newAttachmentService() { Attachment.Storage = getStorage("attachments", storageType, sec) - Attachment.AllowedTypes = sec.Key("ALLOWED_TYPES").MustString(".docx,.gif,.gz,.jpeg,.jpg,.mp4,.log,.pdf,.png,.pptx,.txt,.xlsx,.zip") + Attachment.AllowedTypes = sec.Key("ALLOWED_TYPES").MustString(".csv,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.xls,.xlsx,.zip") Attachment.MaxSize = sec.Key("MAX_SIZE").MustInt64(4) Attachment.MaxFiles = sec.Key("MAX_FILES").MustInt(5) Attachment.Enabled = sec.Key("ENABLED").MustBool(true) diff --git a/modules/setting/i18n.go b/modules/setting/i18n.go index 321e144ef3..8b8587e09b 100644 --- a/modules/setting/i18n.go +++ b/modules/setting/i18n.go @@ -26,7 +26,6 @@ var defaultI18nLangNames = []string{ "fi-FI", "Suomi", "tr-TR", "Türkçe", "cs-CZ", "Čeština", - "sr-SP", "Српски", "sv-SE", "Svenska", "ko-KR", "한국어", "el-GR", "Ελληνικά", diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 7be0842b56..510e00e5ab 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -170,7 +170,7 @@ var ( ServerMACs: []string{"hmac-sha2-256-etm@openssh.com", "hmac-sha2-256", "hmac-sha1"}, KeygenPath: "ssh-keygen", MinimumKeySizeCheck: true, - MinimumKeySizes: map[string]int{"ed25519": 256, "ed25519-sk": 256, "ecdsa": 256, "ecdsa-sk": 256, "rsa": 2048}, + MinimumKeySizes: map[string]int{"ed25519": 256, "ed25519-sk": 256, "ecdsa": 256, "ecdsa-sk": 256, "rsa": 2047}, ServerHostKeys: []string{"ssh/gitea.rsa", "ssh/gogs.rsa"}, AuthorizedKeysCommandTemplate: "{{.AppPath}} --config={{.CustomConf}} serv key-{{.Key.ID}}", PerWriteTimeout: PerWriteTimeout, @@ -402,11 +402,6 @@ var ( MaxTokenLength: math.MaxInt16, } - // FIXME: DEPRECATED to be removed in v1.18.0 - U2F = struct { - AppID string - }{} - // Metrics settings Metrics = struct { Enabled bool @@ -1103,16 +1098,6 @@ func loadFromConf(allowEmpty bool, extraConfig string) { for _, emoji := range UI.CustomEmojis { UI.CustomEmojisMap[emoji] = ":" + emoji + ":" } - - // FIXME: DEPRECATED to be removed in v1.18.0 - U2F.AppID = strings.TrimSuffix(AppURL, "/") - if Cfg.Section("U2F").HasKey("APP_ID") { - log.Error("Deprecated setting `[U2F]` `APP_ID` present. This fallback will be removed in v1.18.0") - U2F.AppID = Cfg.Section("U2F").Key("APP_ID").MustString(strings.TrimSuffix(AppURL, "/")) - } else if Cfg.Section("u2f").HasKey("APP_ID") { - log.Error("Deprecated setting `[u2]` `APP_ID` present. This fallback will be removed in v1.18.0") - U2F.AppID = Cfg.Section("u2f").Key("APP_ID").MustString(strings.TrimSuffix(AppURL, "/")) - } } func parseAuthorizedPrincipalsAllow(values []string) ([]string, bool) { diff --git a/modules/templates/helper.go b/modules/templates/helper.go index 93463ce0c2..4679cf9eba 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -105,7 +105,6 @@ func NewFuncMap() []template.FuncMap { "Str2html": Str2html, "TimeSince": timeutil.TimeSince, "TimeSinceUnix": timeutil.TimeSinceUnix, - "RawTimeSince": timeutil.RawTimeSince, "FileSize": base.FileSize, "PrettyNumber": base.PrettyNumber, "JsPrettyNumber": JsPrettyNumber, @@ -484,7 +483,6 @@ func NewTextFuncMap() []texttmpl.FuncMap { }, "TimeSince": timeutil.TimeSince, "TimeSinceUnix": timeutil.TimeSinceUnix, - "RawTimeSince": timeutil.RawTimeSince, "DateFmtLong": func(t time.Time) string { return t.Format(time.RFC1123Z) }, diff --git a/modules/timeutil/since.go b/modules/timeutil/since.go index b22fe59ba2..5e89b0faa2 100644 --- a/modules/timeutil/since.go +++ b/modules/timeutil/since.go @@ -12,7 +12,7 @@ import ( "time" "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/translation/i18n" + "code.gitea.io/gitea/modules/translation" ) // Seconds-based time units @@ -29,146 +29,146 @@ func round(s float64) int64 { return int64(math.Round(s)) } -func computeTimeDiffFloor(diff int64, lang string) (int64, string) { - var diffStr string +func computeTimeDiffFloor(diff int64, lang translation.Locale) (int64, string) { + diffStr := "" switch { case diff <= 0: diff = 0 - diffStr = i18n.Tr(lang, "tool.now") + diffStr = lang.Tr("tool.now") case diff < 2: diff = 0 - diffStr = i18n.Tr(lang, "tool.1s") + diffStr = lang.Tr("tool.1s") case diff < 1*Minute: - diffStr = i18n.Tr(lang, "tool.seconds", diff) + diffStr = lang.Tr("tool.seconds", diff) diff = 0 case diff < 2*Minute: diff -= 1 * Minute - diffStr = i18n.Tr(lang, "tool.1m") + diffStr = lang.Tr("tool.1m") case diff < 1*Hour: - diffStr = i18n.Tr(lang, "tool.minutes", diff/Minute) + diffStr = lang.Tr("tool.minutes", diff/Minute) diff -= diff / Minute * Minute case diff < 2*Hour: diff -= 1 * Hour - diffStr = i18n.Tr(lang, "tool.1h") + diffStr = lang.Tr("tool.1h") case diff < 1*Day: - diffStr = i18n.Tr(lang, "tool.hours", diff/Hour) + diffStr = lang.Tr("tool.hours", diff/Hour) diff -= diff / Hour * Hour case diff < 2*Day: diff -= 1 * Day - diffStr = i18n.Tr(lang, "tool.1d") + diffStr = lang.Tr("tool.1d") case diff < 1*Week: - diffStr = i18n.Tr(lang, "tool.days", diff/Day) + diffStr = lang.Tr("tool.days", diff/Day) diff -= diff / Day * Day case diff < 2*Week: diff -= 1 * Week - diffStr = i18n.Tr(lang, "tool.1w") + diffStr = lang.Tr("tool.1w") case diff < 1*Month: - diffStr = i18n.Tr(lang, "tool.weeks", diff/Week) + diffStr = lang.Tr("tool.weeks", diff/Week) diff -= diff / Week * Week case diff < 2*Month: diff -= 1 * Month - diffStr = i18n.Tr(lang, "tool.1mon") + diffStr = lang.Tr("tool.1mon") case diff < 1*Year: - diffStr = i18n.Tr(lang, "tool.months", diff/Month) + diffStr = lang.Tr("tool.months", diff/Month) diff -= diff / Month * Month case diff < 2*Year: diff -= 1 * Year - diffStr = i18n.Tr(lang, "tool.1y") + diffStr = lang.Tr("tool.1y") default: - diffStr = i18n.Tr(lang, "tool.years", diff/Year) + diffStr = lang.Tr("tool.years", diff/Year) diff -= (diff / Year) * Year } return diff, diffStr } -func computeTimeDiff(diff int64, lang string) (int64, string) { - var diffStr string +func computeTimeDiff(diff int64, lang translation.Locale) (int64, string) { + diffStr := "" switch { case diff <= 0: diff = 0 - diffStr = i18n.Tr(lang, "tool.now") + diffStr = lang.Tr("tool.now") case diff < 2: diff = 0 - diffStr = i18n.Tr(lang, "tool.1s") + diffStr = lang.Tr("tool.1s") case diff < 1*Minute: - diffStr = i18n.Tr(lang, "tool.seconds", diff) + diffStr = lang.Tr("tool.seconds", diff) diff = 0 case diff < Minute+Minute/2: diff -= 1 * Minute - diffStr = i18n.Tr(lang, "tool.1m") + diffStr = lang.Tr("tool.1m") case diff < 1*Hour: minutes := round(float64(diff) / Minute) if minutes > 1 { - diffStr = i18n.Tr(lang, "tool.minutes", minutes) + diffStr = lang.Tr("tool.minutes", minutes) } else { - diffStr = i18n.Tr(lang, "tool.1m") + diffStr = lang.Tr("tool.1m") } diff -= diff / Minute * Minute case diff < Hour+Hour/2: diff -= 1 * Hour - diffStr = i18n.Tr(lang, "tool.1h") + diffStr = lang.Tr("tool.1h") case diff < 1*Day: hours := round(float64(diff) / Hour) if hours > 1 { - diffStr = i18n.Tr(lang, "tool.hours", hours) + diffStr = lang.Tr("tool.hours", hours) } else { - diffStr = i18n.Tr(lang, "tool.1h") + diffStr = lang.Tr("tool.1h") } diff -= diff / Hour * Hour case diff < Day+Day/2: diff -= 1 * Day - diffStr = i18n.Tr(lang, "tool.1d") + diffStr = lang.Tr("tool.1d") case diff < 1*Week: days := round(float64(diff) / Day) if days > 1 { - diffStr = i18n.Tr(lang, "tool.days", days) + diffStr = lang.Tr("tool.days", days) } else { - diffStr = i18n.Tr(lang, "tool.1d") + diffStr = lang.Tr("tool.1d") } diff -= diff / Day * Day case diff < Week+Week/2: diff -= 1 * Week - diffStr = i18n.Tr(lang, "tool.1w") + diffStr = lang.Tr("tool.1w") case diff < 1*Month: weeks := round(float64(diff) / Week) if weeks > 1 { - diffStr = i18n.Tr(lang, "tool.weeks", weeks) + diffStr = lang.Tr("tool.weeks", weeks) } else { - diffStr = i18n.Tr(lang, "tool.1w") + diffStr = lang.Tr("tool.1w") } diff -= diff / Week * Week case diff < 1*Month+Month/2: diff -= 1 * Month - diffStr = i18n.Tr(lang, "tool.1mon") + diffStr = lang.Tr("tool.1mon") case diff < 1*Year: months := round(float64(diff) / Month) if months > 1 { - diffStr = i18n.Tr(lang, "tool.months", months) + diffStr = lang.Tr("tool.months", months) } else { - diffStr = i18n.Tr(lang, "tool.1mon") + diffStr = lang.Tr("tool.1mon") } diff -= diff / Month * Month case diff < Year+Year/2: diff -= 1 * Year - diffStr = i18n.Tr(lang, "tool.1y") + diffStr = lang.Tr("tool.1y") default: years := round(float64(diff) / Year) if years > 1 { - diffStr = i18n.Tr(lang, "tool.years", years) + diffStr = lang.Tr("tool.years", years) } else { - diffStr = i18n.Tr(lang, "tool.1y") + diffStr = lang.Tr("tool.1y") } diff -= (diff / Year) * Year } @@ -177,24 +177,24 @@ func computeTimeDiff(diff int64, lang string) (int64, string) { // MinutesToFriendly returns a user friendly string with number of minutes // converted to hours and minutes. -func MinutesToFriendly(minutes int, lang string) string { +func MinutesToFriendly(minutes int, lang translation.Locale) string { duration := time.Duration(minutes) * time.Minute return TimeSincePro(time.Now().Add(-duration), lang) } // TimeSincePro calculates the time interval and generate full user-friendly string. -func TimeSincePro(then time.Time, lang string) string { +func TimeSincePro(then time.Time, lang translation.Locale) string { return timeSincePro(then, time.Now(), lang) } -func timeSincePro(then, now time.Time, lang string) string { +func timeSincePro(then, now time.Time, lang translation.Locale) string { diff := now.Unix() - then.Unix() if then.After(now) { - return i18n.Tr(lang, "tool.future") + return lang.Tr("tool.future") } if diff == 0 { - return i18n.Tr(lang, "tool.now") + return lang.Tr("tool.now") } var timeStr, diffStr string @@ -209,11 +209,11 @@ func timeSincePro(then, now time.Time, lang string) string { return strings.TrimPrefix(timeStr, ", ") } -func timeSince(then, now time.Time, lang string) string { +func timeSince(then, now time.Time, lang translation.Locale) string { return timeSinceUnix(then.Unix(), now.Unix(), lang) } -func timeSinceUnix(then, now int64, lang string) string { +func timeSinceUnix(then, now int64, lang translation.Locale) string { lbl := "tool.ago" diff := now - then if then > now { @@ -221,36 +221,31 @@ func timeSinceUnix(then, now int64, lang string) string { diff = then - now } if diff <= 0 { - return i18n.Tr(lang, "tool.now") + return lang.Tr("tool.now") } _, diffStr := computeTimeDiff(diff, lang) - return i18n.Tr(lang, lbl, diffStr) -} - -// RawTimeSince retrieves i18n key of time since t -func RawTimeSince(t time.Time, lang string) string { - return timeSince(t, time.Now(), lang) + return lang.Tr(lbl, diffStr) } // TimeSince calculates the time interval and generate user-friendly string. -func TimeSince(then time.Time, lang string) template.HTML { +func TimeSince(then time.Time, lang translation.Locale) template.HTML { return htmlTimeSince(then, time.Now(), lang) } -func htmlTimeSince(then, now time.Time, lang string) template.HTML { +func htmlTimeSince(then, now time.Time, lang translation.Locale) template.HTML { return template.HTML(fmt.Sprintf(`%s`, - then.In(setting.DefaultUILocation).Format(GetTimeFormat(lang)), + then.In(setting.DefaultUILocation).Format(GetTimeFormat(lang.Language())), timeSince(then, now, lang))) } // TimeSinceUnix calculates the time interval and generate user-friendly string. -func TimeSinceUnix(then TimeStamp, lang string) template.HTML { +func TimeSinceUnix(then TimeStamp, lang translation.Locale) template.HTML { return htmlTimeSinceUnix(then, TimeStamp(time.Now().Unix()), lang) } -func htmlTimeSinceUnix(then, now TimeStamp, lang string) template.HTML { +func htmlTimeSinceUnix(then, now TimeStamp, lang translation.Locale) template.HTML { return template.HTML(fmt.Sprintf(`%s`, - then.FormatInLocation(GetTimeFormat(lang), setting.DefaultUILocation), + then.FormatInLocation(GetTimeFormat(lang.Language()), setting.DefaultUILocation), timeSinceUnix(int64(then), int64(now), lang))) } diff --git a/modules/timeutil/since_test.go b/modules/timeutil/since_test.go index 49951b6e41..8bdb9d7546 100644 --- a/modules/timeutil/since_test.go +++ b/modules/timeutil/since_test.go @@ -12,7 +12,6 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/translation" - "code.gitea.io/gitea/modules/translation/i18n" "github.com/stretchr/testify/assert" ) @@ -42,16 +41,16 @@ func TestMain(m *testing.M) { } func TestTimeSince(t *testing.T) { - assert.Equal(t, "now", timeSince(BaseDate, BaseDate, "en")) + assert.Equal(t, "now", timeSince(BaseDate, BaseDate, translation.NewLocale("en-US"))) // test that each diff in `diffs` yields the expected string test := func(expected string, diffs ...time.Duration) { t.Run(expected, func(t *testing.T) { for _, diff := range diffs { - actual := timeSince(BaseDate, BaseDate.Add(diff), "en") - assert.Equal(t, i18n.Tr("en", "tool.ago", expected), actual) - actual = timeSince(BaseDate.Add(diff), BaseDate, "en") - assert.Equal(t, i18n.Tr("en", "tool.from_now", expected), actual) + actual := timeSince(BaseDate, BaseDate.Add(diff), translation.NewLocale("en-US")) + assert.Equal(t, translation.NewLocale("en-US").Tr("tool.ago", expected), actual) + actual = timeSince(BaseDate.Add(diff), BaseDate, translation.NewLocale("en-US")) + assert.Equal(t, translation.NewLocale("en-US").Tr("tool.from_now", expected), actual) } }) } @@ -82,13 +81,13 @@ func TestTimeSince(t *testing.T) { } func TestTimeSincePro(t *testing.T) { - assert.Equal(t, "now", timeSincePro(BaseDate, BaseDate, "en")) + assert.Equal(t, "now", timeSincePro(BaseDate, BaseDate, translation.NewLocale("en-US"))) // test that a difference of `diff` yields the expected string test := func(expected string, diff time.Duration) { - actual := timeSincePro(BaseDate, BaseDate.Add(diff), "en") + actual := timeSincePro(BaseDate, BaseDate.Add(diff), translation.NewLocale("en-US")) assert.Equal(t, expected, actual) - assert.Equal(t, "future", timeSincePro(BaseDate.Add(diff), BaseDate, "en")) + assert.Equal(t, "future", timeSincePro(BaseDate.Add(diff), BaseDate, translation.NewLocale("en-US"))) } test("1 second", time.Second) test("2 seconds", 2*time.Second) @@ -119,7 +118,7 @@ func TestHtmlTimeSince(t *testing.T) { setting.DefaultUILocation = time.UTC // test that `diff` yields a result containing `expected` test := func(expected string, diff time.Duration) { - actual := htmlTimeSince(BaseDate, BaseDate.Add(diff), "en") + actual := htmlTimeSince(BaseDate, BaseDate.Add(diff), translation.NewLocale("en-US")) assert.Contains(t, actual, `title="Sat Jan 1 00:00:00 UTC 2000"`) assert.Contains(t, actual, expected) } @@ -138,7 +137,7 @@ func TestComputeTimeDiff(t *testing.T) { test := func(base int64, str string, offsets ...int64) { for _, offset := range offsets { t.Run(fmt.Sprintf("%s:%d", str, offset), func(t *testing.T) { - diff, diffStr := computeTimeDiff(base+offset, "en") + diff, diffStr := computeTimeDiff(base+offset, translation.NewLocale("en-US")) assert.Equal(t, offset, diff) assert.Equal(t, str, diffStr) }) @@ -171,7 +170,7 @@ func TestComputeTimeDiff(t *testing.T) { func TestMinutesToFriendly(t *testing.T) { // test that a number of minutes yields the expected string test := func(expected string, minutes int) { - actual := MinutesToFriendly(minutes, "en") + actual := MinutesToFriendly(minutes, translation.NewLocale("en-US")) assert.Equal(t, expected, actual) } test("1 minute", 1) diff --git a/modules/translation/i18n/i18n.go b/modules/translation/i18n/i18n.go index 664e457ecf..bb906f3c08 100644 --- a/modules/translation/i18n/i18n.go +++ b/modules/translation/i18n/i18n.go @@ -7,10 +7,13 @@ package i18n import ( "errors" "fmt" + "os" "reflect" - "strings" + "sync" + "time" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" "gopkg.in/ini.v1" ) @@ -18,123 +21,278 @@ import ( var ( ErrLocaleAlreadyExist = errors.New("lang already exists") - DefaultLocales = NewLocaleStore() + DefaultLocales = NewLocaleStore(true) ) type locale struct { + // This mutex will be set if we have live-reload enabled (e.g. dev mode) + reloadMu *sync.RWMutex + store *LocaleStore langName string - langDesc string - messages *ini.File + + idxToMsgMap map[int]string // the map idx is generated by store's trKeyToIdxMap + + sourceFileName string + sourceFileInfo os.FileInfo + lastReloadCheckTime time.Time } type LocaleStore struct { - // at the moment, all these fields are readonly after initialization - langNames []string - langDescs []string - localeMap map[string]*locale + // This mutex will be set if we have live-reload enabled (e.g. dev mode) + reloadMu *sync.RWMutex + + langNames []string + langDescs []string + localeMap map[string]*locale + + // this needs to be locked when live-reloading + trKeyToIdxMap map[string]int + defaultLang string } -func NewLocaleStore() *LocaleStore { - return &LocaleStore{localeMap: make(map[string]*locale)} +func NewLocaleStore(isProd bool) *LocaleStore { + store := &LocaleStore{localeMap: make(map[string]*locale), trKeyToIdxMap: make(map[string]int)} + if !isProd { + store.reloadMu = &sync.RWMutex{} + } + return store } // AddLocaleByIni adds locale by ini into the store -func (ls *LocaleStore) AddLocaleByIni(langName, langDesc string, localeFile interface{}, otherLocaleFiles ...interface{}) error { - if _, ok := ls.localeMap[langName]; ok { +// if source is a string, then the file is loaded. In dev mode, this file will be checked for live-reloading +// if source is a []byte, then the content is used +// Note: this is not concurrent safe +func (store *LocaleStore) AddLocaleByIni(langName, langDesc string, source interface{}) error { + if _, ok := store.localeMap[langName]; ok { return ErrLocaleAlreadyExist } + + l := &locale{store: store, langName: langName} + if store.reloadMu != nil { + l.reloadMu = &sync.RWMutex{} + l.reloadMu.Lock() // Arguably this is not necessary as AddLocaleByIni isn't concurrent safe - but for consistency we do this + defer l.reloadMu.Unlock() + } + + if fileName, ok := source.(string); ok { + l.sourceFileName = fileName + l.sourceFileInfo, _ = os.Stat(fileName) // live-reload only works for regular files. the error can be ignored + } + + var err error + l.idxToMsgMap, err = store.readIniToIdxToMsgMap(source) + if err != nil { + return err + } + + store.langNames = append(store.langNames, langName) + store.langDescs = append(store.langDescs, langDesc) + + store.localeMap[l.langName] = l + + return nil +} + +// readIniToIdxToMsgMap will read a provided ini and creates an idxToMsgMap +func (store *LocaleStore) readIniToIdxToMsgMap(source interface{}) (map[int]string, error) { iniFile, err := ini.LoadSources(ini.LoadOptions{ IgnoreInlineComment: true, UnescapeValueCommentSymbols: true, - }, localeFile, otherLocaleFiles...) - if err == nil { - iniFile.BlockMode = false - lc := &locale{store: ls, langName: langName, langDesc: langDesc, messages: iniFile} - ls.langNames = append(ls.langNames, lc.langName) - ls.langDescs = append(ls.langDescs, lc.langDesc) - ls.localeMap[lc.langName] = lc + }, source) + if err != nil { + return nil, fmt.Errorf("unable to load ini: %w", err) } - return err + iniFile.BlockMode = false + + idxToMsgMap := make(map[int]string) + + if store.reloadMu != nil { + store.reloadMu.Lock() + defer store.reloadMu.Unlock() + } + + for _, section := range iniFile.Sections() { + for _, key := range section.Keys() { + + var trKey string + if section.Name() == "" || section.Name() == "DEFAULT" { + trKey = key.Name() + } else { + trKey = section.Name() + "." + key.Name() + } + + // Instead of storing the key strings in multiple different maps we compute a idx which will act as numeric code for key + // This reduces the size of the locale idxToMsgMaps + idx, ok := store.trKeyToIdxMap[trKey] + if !ok { + idx = len(store.trKeyToIdxMap) + store.trKeyToIdxMap[trKey] = idx + } + idxToMsgMap[idx] = key.Value() + } + } + iniFile = nil + return idxToMsgMap, nil } -func (ls *LocaleStore) HasLang(langName string) bool { - _, ok := ls.localeMap[langName] +func (store *LocaleStore) idxForTrKey(trKey string) (int, bool) { + if store.reloadMu != nil { + store.reloadMu.RLock() + defer store.reloadMu.RUnlock() + } + idx, ok := store.trKeyToIdxMap[trKey] + return idx, ok +} + +// HasLang reports if a language is available in the store +func (store *LocaleStore) HasLang(langName string) bool { + _, ok := store.localeMap[langName] return ok } -func (ls *LocaleStore) ListLangNameDesc() (names, desc []string) { - return ls.langNames, ls.langDescs +// ListLangNameDesc reports if a language available in the store +func (store *LocaleStore) ListLangNameDesc() (names, desc []string) { + return store.langNames, store.langDescs } // SetDefaultLang sets default language as a fallback -func (ls *LocaleStore) SetDefaultLang(lang string) { - ls.defaultLang = lang +func (store *LocaleStore) SetDefaultLang(lang string) { + store.defaultLang = lang } // Tr translates content to target language. fall back to default language. -func (ls *LocaleStore) Tr(lang, trKey string, trArgs ...interface{}) string { - l, ok := ls.localeMap[lang] +func (store *LocaleStore) Tr(lang, trKey string, trArgs ...interface{}) string { + l, ok := store.localeMap[lang] if !ok { - l, ok = ls.localeMap[ls.defaultLang] + l, ok = store.localeMap[store.defaultLang] } + if ok { return l.Tr(trKey, trArgs...) } return trKey } -// Tr translates content to locale language. fall back to default language. -func (l *locale) Tr(trKey string, trArgs ...interface{}) string { - var section string - - idx := strings.IndexByte(trKey, '.') - if idx > 0 { - section = trKey[:idx] - trKey = trKey[idx+1:] +// reloadIfNeeded will check if the locale needs to be reloaded +// this function will assume that the l.reloadMu has been RLocked if it already exists +func (l *locale) reloadIfNeeded() { + if l.reloadMu == nil { + return } - trMsg := trKey - if trIni, err := l.messages.Section(section).GetKey(trKey); err == nil { - trMsg = trIni.Value() - } else if l.store.defaultLang != "" && l.langName != l.store.defaultLang { - // try to fall back to default - if defaultLocale, ok := l.store.localeMap[l.store.defaultLang]; ok { - if trIni, err = defaultLocale.messages.Section(section).GetKey(trKey); err == nil { - trMsg = trIni.Value() - } - } + now := time.Now() + if now.Sub(l.lastReloadCheckTime) < time.Second || l.sourceFileInfo == nil || l.sourceFileName == "" { + return } - if len(trArgs) > 0 { - fmtArgs := make([]interface{}, 0, len(trArgs)) - for _, arg := range trArgs { - val := reflect.ValueOf(arg) - if val.Kind() == reflect.Slice { - // before, it can accept Tr(lang, key, a, [b, c], d, [e, f]) as Sprintf(msg, a, b, c, d, e, f), it's an unstable behavior - // now, we restrict the strange behavior and only support: - // 1. Tr(lang, key, [slice-items]) as Sprintf(msg, items...) - // 2. Tr(lang, key, args...) as Sprintf(msg, args...) - if len(trArgs) == 1 { - for i := 0; i < val.Len(); i++ { - fmtArgs = append(fmtArgs, val.Index(i).Interface()) - } - } else { - log.Error("the args for i18n shouldn't contain uncertain slices, key=%q, args=%v", trKey, trArgs) - break - } - } else { - fmtArgs = append(fmtArgs, arg) - } - } - return fmt.Sprintf(trMsg, fmtArgs...) + l.reloadMu.RUnlock() + l.reloadMu.Lock() // (NOTE: a pre-emption can occur between these two locks so we need to recheck) + defer l.reloadMu.RLock() + defer l.reloadMu.Unlock() + + if now.Sub(l.lastReloadCheckTime) < time.Second || l.sourceFileInfo == nil || l.sourceFileName == "" { + return } - return trMsg + + l.lastReloadCheckTime = now + sourceFileInfo, err := os.Stat(l.sourceFileName) + if err != nil || sourceFileInfo.ModTime().Equal(l.sourceFileInfo.ModTime()) { + return + } + + idxToMsgMap, err := l.store.readIniToIdxToMsgMap(l.sourceFileName) + if err == nil { + l.idxToMsgMap = idxToMsgMap + } else { + log.Error("Unable to live-reload the locale file %q, err: %v", l.sourceFileName, err) + } + + // We will set the sourceFileInfo to this file to prevent repeated attempts to re-load this broken file + l.sourceFileInfo = sourceFileInfo } -func ResetDefaultLocales() { - DefaultLocales = NewLocaleStore() +// Tr translates content to locale language. fall back to default language. +func (l *locale) Tr(trKey string, trArgs ...interface{}) string { + if l.reloadMu != nil { + l.reloadMu.RLock() + defer l.reloadMu.RUnlock() + l.reloadIfNeeded() + } + + msg, _ := l.tryTr(trKey, trArgs...) + return msg +} + +func (l *locale) tryTr(trKey string, trArgs ...interface{}) (msg string, found bool) { + trMsg := trKey + + // convert the provided trKey to a common idx from the store + idx, ok := l.store.idxForTrKey(trKey) + + if ok { + if msg, found = l.idxToMsgMap[idx]; found { + trMsg = msg // use the translation that we have found + } else if l.langName != l.store.defaultLang { + // No translation available in our current language... fallback to the default language + + // Attempt to get the default language from the locale store + if def, ok := l.store.localeMap[l.store.defaultLang]; ok { + + if def.reloadMu != nil { + def.reloadMu.RLock() + def.reloadIfNeeded() + } + if msg, found = def.idxToMsgMap[idx]; found { + trMsg = msg // use the translation that we have found + } + if def.reloadMu != nil { + def.reloadMu.RUnlock() + } + } + } + } + + if !found && !setting.IsProd { + log.Error("missing i18n translation key: %q", trKey) + } + + if len(trArgs) == 0 { + return trMsg, found + } + + fmtArgs := make([]interface{}, 0, len(trArgs)) + for _, arg := range trArgs { + val := reflect.ValueOf(arg) + if val.Kind() == reflect.Slice { + // Previously, we would accept Tr(lang, key, a, [b, c], d, [e, f]) as Sprintf(msg, a, b, c, d, e, f) + // but this is an unstable behavior. + // + // So we restrict the accepted arguments to either: + // + // 1. Tr(lang, key, [slice-items]) as Sprintf(msg, items...) + // 2. Tr(lang, key, args...) as Sprintf(msg, args...) + if len(trArgs) == 1 { + for i := 0; i < val.Len(); i++ { + fmtArgs = append(fmtArgs, val.Index(i).Interface()) + } + } else { + log.Error("the args for i18n shouldn't contain uncertain slices, key=%q, args=%v", trKey, trArgs) + break + } + } else { + fmtArgs = append(fmtArgs, arg) + } + } + + return fmt.Sprintf(trMsg, fmtArgs...), found +} + +// ResetDefaultLocales resets the current default locales +// NOTE: this is not synchronized +func ResetDefaultLocales(isProd bool) { + DefaultLocales = NewLocaleStore(isProd) } // Tr use default locales to translate content to target language. diff --git a/modules/translation/i18n/i18n_test.go b/modules/translation/i18n/i18n_test.go index 70066016cf..32f7585b32 100644 --- a/modules/translation/i18n/i18n_test.go +++ b/modules/translation/i18n/i18n_test.go @@ -27,30 +27,36 @@ fmt = %[2]s %[1]s sub = Changed Sub String `) - ls := NewLocaleStore() - assert.NoError(t, ls.AddLocaleByIni("lang1", "Lang1", testData1)) - assert.NoError(t, ls.AddLocaleByIni("lang2", "Lang2", testData2)) - ls.SetDefaultLang("lang1") + for _, isProd := range []bool{true, false} { + ls := NewLocaleStore(isProd) + assert.NoError(t, ls.AddLocaleByIni("lang1", "Lang1", testData1)) + assert.NoError(t, ls.AddLocaleByIni("lang2", "Lang2", testData2)) + ls.SetDefaultLang("lang1") - result := ls.Tr("lang1", "fmt", "a", "b") - assert.Equal(t, "a b", result) + result := ls.Tr("lang1", "fmt", "a", "b") + assert.Equal(t, "a b", result) - result = ls.Tr("lang2", "fmt", "a", "b") - assert.Equal(t, "b a", result) + result = ls.Tr("lang2", "fmt", "a", "b") + assert.Equal(t, "b a", result) - result = ls.Tr("lang1", "section.sub") - assert.Equal(t, "Sub String", result) + result = ls.Tr("lang1", "section.sub") + assert.Equal(t, "Sub String", result) - result = ls.Tr("lang2", "section.sub") - assert.Equal(t, "Changed Sub String", result) + result = ls.Tr("lang2", "section.sub") + assert.Equal(t, "Changed Sub String", result) - result = ls.Tr("", ".dot.name") - assert.Equal(t, "Dot Name", result) + result = ls.Tr("", ".dot.name") + assert.Equal(t, "Dot Name", result) - result = ls.Tr("lang2", "section.mixed") - assert.Equal(t, `test value; more text`, result) + result = ls.Tr("lang2", "section.mixed") + assert.Equal(t, `test value; more text`, result) - langs, descs := ls.ListLangNameDesc() - assert.Equal(t, []string{"lang1", "lang2"}, langs) - assert.Equal(t, []string{"Lang1", "Lang2"}, descs) + langs, descs := ls.ListLangNameDesc() + assert.Equal(t, []string{"lang1", "lang2"}, langs) + assert.Equal(t, []string{"Lang1", "Lang2"}, descs) + + result, found := ls.localeMap["lang1"].tryTr("no-such") + assert.Equal(t, "no-such", result) + assert.False(t, found) + } } diff --git a/modules/translation/translation.go b/modules/translation/translation.go index da9d9b9b68..fcc101d963 100644 --- a/modules/translation/translation.go +++ b/modules/translation/translation.go @@ -5,6 +5,7 @@ package translation import ( + "path" "sort" "strings" @@ -12,6 +13,7 @@ import ( "code.gitea.io/gitea/modules/options" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/translation/i18n" + "code.gitea.io/gitea/modules/util" "golang.org/x/text/language" ) @@ -40,31 +42,35 @@ func AllLangs() []*LangType { return allLangs } -// TryTr tries to do the translation, if no translation, it returns (format, false) -func TryTr(lang, format string, args ...interface{}) (string, bool) { - s := i18n.Tr(lang, format, args...) - // now the i18n library is not good enough and we can only use this hacky method to detect whether the transaction exists - idx := strings.IndexByte(format, '.') - defaultText := format - if idx > 0 { - defaultText = format[idx+1:] - } - return s, s != defaultText -} - // InitLocales loads the locales func InitLocales() { - i18n.ResetDefaultLocales() + i18n.ResetDefaultLocales(setting.IsProd) localeNames, err := options.Dir("locale") if err != nil { log.Fatal("Failed to list locale files: %v", err) } - localFiles := make(map[string][]byte, len(localeNames)) + localFiles := make(map[string]interface{}, len(localeNames)) for _, name := range localeNames { - localFiles[name], err = options.Locale(name) - if err != nil { - log.Fatal("Failed to load %s locale file. %v", name, err) + if options.IsDynamic() { + // Try to check if CustomPath has the file, otherwise fallback to StaticRootPath + value := path.Join(setting.CustomPath, "options/locale", name) + + isFile, err := util.IsFile(value) + if err != nil { + log.Fatal("Failed to load %s locale file. %v", name, err) + } + + if isFile { + localFiles[name] = value + } else { + localFiles[name] = path.Join(setting.StaticRootPath, "options/locale", name) + } + } else { + localFiles[name], err = options.Locale(name) + if err != nil { + log.Fatal("Failed to load %s locale file. %v", name, err) + } } } @@ -76,6 +82,7 @@ func InitLocales() { matcher = language.NewMatcher(supportedTags) for i := range setting.Names { key := "locale_" + setting.Langs[i] + ".ini" + if err = i18n.DefaultLocales.AddLocaleByIni(setting.Langs[i], setting.Names[i], localFiles[key]); err != nil { log.Error("Failed to set messages to %s: %v", setting.Langs[i], err) } @@ -132,16 +139,7 @@ func (l *locale) Language() string { // Tr translates content to target language. func (l *locale) Tr(format string, args ...interface{}) string { - if setting.IsProd { - return i18n.Tr(l.Lang, format, args...) - } - - // in development, we should show an error if a translation key is missing - s, ok := TryTr(l.Lang, format, args...) - if !ok { - log.Error("missing i18n translation key: %q", format) - } - return s + return i18n.Tr(l.Lang, format, args...) } // Language specific rules for translating plural texts diff --git a/options/locale/locale_cs-CZ.ini b/options/locale/locale_cs-CZ.ini index d9634391e8..8f2288569d 100644 --- a/options/locale/locale_cs-CZ.ini +++ b/options/locale/locale_cs-CZ.ini @@ -46,7 +46,6 @@ webauthn_error_unable_to_process=Server nemohl zpracovat váš požadavek. webauthn_error_duplicated=Zabezpečovací klíč není pro tento požadavek povolen. Prosím ujistěte se, zda klíč není již registrován. webauthn_error_empty=Musíte nastavit název tohoto klíče. webauthn_error_timeout=Požadavek vypršel dříve, než se podařilo přečíst váš klíč. Znovu načtěte tuto stránku a akci opakujte. -webauthn_u2f_deprecated=Klíč: „%s“ autentifikuje pomocí zastaralého procesu U2F. Měli byste znovu zaregistrovat tento klíč a zrušit starou registraci. webauthn_reload=Znovu načíst repository=Repozitář diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index 995d3107c1..f73b1fe285 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -47,7 +47,6 @@ webauthn_error_unable_to_process=Der Server konnte deine Anfrage nicht bearbeite webauthn_error_duplicated=Für diese Anfrage ist der Sicherheitsschlüssel nicht erlaubt. Bitte stell sicher, dass er nicht bereits registriert ist. webauthn_error_empty=Du musst einen Namen für diesen Schlüssel festlegen. webauthn_error_timeout=Das Zeitlimit wurde erreicht, bevor dein Schlüssel gelesen werden konnte. Bitte lade die Seite erneut. -webauthn_u2f_deprecated=Der Schlüssel: '%s' authentifiziert sich über den veralteten U2F-Prozess. Bitte registriere den Schlüssel neu und lösche die alte Registrierung. webauthn_reload=Neu laden repository=Repository @@ -1516,7 +1515,7 @@ pulls.tab_conversation=Diskussion pulls.tab_commits=Commits pulls.tab_files=Geänderte Dateien pulls.reopen_to_merge=Bitte diesen Pull-Request wieder öffnen, um zu mergen. -pulls.cant_reopen_deleted_branch=Dieser Pull-Request kann nicht wieder geöffnet werden, da die Branche bereits gelöscht wurde. +pulls.cant_reopen_deleted_branch=Dieser Pull-Request kann nicht wieder geöffnet werden, da die Branch bereits gelöscht wurde. pulls.merged=Zusammengeführt pulls.merged_as=Der Pull Request wurde als %[2]s gemergt. pulls.manually_merged=Manuell gemergt diff --git a/options/locale/locale_el-GR.ini b/options/locale/locale_el-GR.ini index 473e3dab0a..faedf82c09 100644 --- a/options/locale/locale_el-GR.ini +++ b/options/locale/locale_el-GR.ini @@ -47,7 +47,6 @@ webauthn_error_unable_to_process=Ο διακομιστής δεν μπόρεσε webauthn_error_duplicated=Το κλειδί ασφαλείας δεν επιτρέπεται για αυτό το αίτημα. Βεβαιωθείτε ότι το κλειδί δεν έχει ήδη καταχωρηθεί. webauthn_error_empty=Πρέπει να ορίσετε ένα όνομα για αυτό το κλειδί. webauthn_error_timeout=Το χρονικό όριο έφτασε πριν το κλειδί να διαβαστεί. Παρακαλώ ανανεώστε τη σελίδα και προσπαθήστε ξανά. -webauthn_u2f_deprecated=Το κλειδί: '%s' πιστοποιεί χρησιμοποιώντας το παρωχημένο πρωτόκολλο U2F. Θα πρέπει να καταχωρήσετε ξανά αυτό το κλειδί και να καταργήσετε την παλιά εγγραφή. webauthn_reload=Ανανέωση repository=Αποθετήριο @@ -1276,7 +1275,7 @@ issues.filter_sort=Ταξινόμηση issues.filter_sort.latest=Νεότερα issues.filter_sort.oldest=Παλαιότερα issues.filter_sort.recentupdate=Ενημερώθηκαν πρόσφατα -issues.filter_sort.leastupdate=Λιγότερο πρόσφατα ανανεωμένο +issues.filter_sort.leastupdate=Ενημερώθηκαν παλαιότερα issues.filter_sort.mostcomment=Περισσότερο σχολιασμένα issues.filter_sort.leastcomment=Λιγότερο σχολιασμένα issues.filter_sort.nearduedate=Πλησιέστερη παράδοση diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 72253b3640..eb7ae47743 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -47,7 +47,6 @@ webauthn_error_unable_to_process = The server could not process your request. webauthn_error_duplicated = The security key is not permitted for this request. Please make sure that the key is not already registered. webauthn_error_empty = You must set a name for this key. webauthn_error_timeout = Timeout reached before your key could be read. Please reload this page and retry. -webauthn_u2f_deprecated = The key: '%s' authenticates using the deprecated U2F process. You should re-register this key and remove the old registration. webauthn_reload = Reload repository = Repository diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index f8cb22a296..3328f2ac51 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -47,7 +47,6 @@ webauthn_error_unable_to_process=El servidor no pudo procesar su solicitud. webauthn_error_duplicated=La clave de seguridad no está permitida para esta solicitud. Por favor, asegúrese de que la clave no está ya registrada. webauthn_error_empty=Debe establecer un nombre para esta clave. webauthn_error_timeout=Tiempo de espera máximo alcanzado antes de que su clave pudiese ser leída. Por favor, cargue la página y vuelva a intentarlo. -webauthn_u2f_deprecated=La clave: '%s' se autentifica usando el proceso U2F obsoleto. Debe volver a registrar esta clave y eliminar el registro antiguo. webauthn_reload=Recargar repository=Repositorio @@ -1610,6 +1609,8 @@ pulls.auto_merge_canceled_schedule=Fusión automaticá estaba cancellada para es pulls.auto_merge_newly_scheduled_comment=`programó este Pull Request para fusionar automática cuando todas las comprobaciones tengan éxito %[1]s` pulls.auto_merge_canceled_schedule_comment=`canceló la fusión automática de este Pull Request %[1]s` +pulls.delete.title=¿Borrar este pull request? +pulls.delete.text=¿Realmente quieres eliminar esta pull request? (Esto eliminará permanentemente todo el contenido. Considera cerrarlo si simplemente deseas archivarlo) milestones.new=Nuevo hito milestones.closed=Cerrada %s diff --git a/options/locale/locale_is-IS.ini b/options/locale/locale_is-IS.ini index 6f70c79f4b..c56b14f907 100644 --- a/options/locale/locale_is-IS.ini +++ b/options/locale/locale_is-IS.ini @@ -46,7 +46,6 @@ webauthn_error_unable_to_process=Netþjónninn gat ekki ráðið við beiðni þ webauthn_error_duplicated=Öryggislykillinn er ekki leyfður fyrir þessa beiðni. Gakktu úr skugga um að lykillinn sé ekki þegar skráður. webauthn_error_empty=Þú verður að setja nafn fyrir þennan lykil. webauthn_error_timeout=Tímamörk náð áður en hægt var að lesa lykilinn þinn. Vinsamlegast endurhlaðið þessa síðu og reyndu aftur. -webauthn_u2f_deprecated=Lykillinn: „%s“ auðkennir með því að nota úrelta U2F aðferð. Þú ættir að endurskrá þennan lykil og fjarlægja gömlu skráninguna. webauthn_reload=Endurhlaða repository=Hugbúnaðarsafn diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index f800e8bba3..db66f44bff 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -47,7 +47,6 @@ webauthn_error_unable_to_process=サーバーがリクエストを処理でき webauthn_error_duplicated=このリクエストに対しては、許可されていないセキュリティキーです。 キーが未登録であることを確認してください。 webauthn_error_empty=このキーに名前を設定する必要があります。 webauthn_error_timeout=キーを読み取る前にタイムアウトになりました。 このページをリロードしてもう一度やり直してください。 -webauthn_u2f_deprecated=キー: '%s' は非推奨のU2Fプロセスを使用して認証しています。このキーを再登録して古い登録を削除したほうが良いでしょう。 webauthn_reload=リロード repository=リポジトリ @@ -1610,6 +1609,8 @@ pulls.auto_merge_canceled_schedule=このプルリクエストの自動マージ pulls.auto_merge_newly_scheduled_comment=`が、すべてのチェックが成功すると自動マージを行うよう、このプルリクエストをスケジュール %[1]s` pulls.auto_merge_canceled_schedule_comment=`が、すべてのチェックが成功したときのプルリクエストの自動マージをキャンセル %[1]s` +pulls.delete.title=このプルリクエストを削除しますか? +pulls.delete.text=本当にこのプルリクエストを削除しますか? (これはすべてのコンテンツを完全に削除します。 保存しておきたい場合は、代わりにクローズすることを検討してください) milestones.new=新しいマイルストーン milestones.closed=%s にクローズ diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index 354f663c5a..88c1b4c0b6 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -47,7 +47,6 @@ webauthn_error_unable_to_process=Serveris nevar apstrādāt Jūsu pieprasījumu. webauthn_error_duplicated=Drošības atslēga nav atļauta šim pieprasījumam. Pārliecinieties, ka šī atslēga jau nav reģistrēta. webauthn_error_empty=Norādiet atslēgas nosaukumu. webauthn_error_timeout=Iestājusies noildze, mēģinot, nolasīt atslēgu. Pārlādējiet lapu un mēģiniet vēlreiz. -webauthn_u2f_deprecated=Atslēga '%s' izmanto novecojušu U2F procesu. Noņemiet iepriekšējo reģistrāciju un veiciet reģistrācijas procesu no jauna. webauthn_reload=Pārlādēt repository=Repozitorijs diff --git a/options/locale/locale_pl-PL.ini b/options/locale/locale_pl-PL.ini index ef227b914d..0d9a596e39 100644 --- a/options/locale/locale_pl-PL.ini +++ b/options/locale/locale_pl-PL.ini @@ -46,7 +46,6 @@ webauthn_error_unable_to_process=Serwer nie mógł obsłużyć Twojego żądania webauthn_error_duplicated=Klucz bezpieczeństwa nie jest dozwolony dla tego żądania. Upewnij się, że klucz nie jest już zarejestrowany. webauthn_error_empty=Musisz ustawić nazwę dla tego klucza. webauthn_error_timeout=Osiągnięto limit czasu zanim Twój klucz może zostać odczytany. Odśwież stronę i spróbuj ponownie. -webauthn_u2f_deprecated=Klucz '%s' uwierzytelnia przy użyciu przestarzałego procesu U2F. Powinieneś ponownie zarejestrować ten klucz i usunąć starą rejestrację. webauthn_reload=Odśwież repository=Repozytorium diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index 2e18085493..a91847b68a 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -2,6 +2,7 @@ home=Inicio dashboard=Painel explore=Explorar help=Ajuda +logo=Logotipo sign_in=Acessar sign_in_with=Acessar com sign_out=Sair @@ -46,7 +47,6 @@ webauthn_error_unable_to_process=O servidor não pôde processar sua solicitaç webauthn_error_duplicated=A chave de segurança não é permitida para esta solicitação. Por favor, certifique-se que a chave já não está registrada. webauthn_error_empty=Você deve definir um nome para esta chave. webauthn_error_timeout=Tempo limite atingido antes de sua chave poder ser lida. Por favor, recarregue esta página e tente novamente. -webauthn_u2f_deprecated=A chave: '%s' autentica utilizando o processo U2F descontinuado. Você deve registrar novamente esta chave e remover o registro antigo. webauthn_reload=Recarregar repository=Repositório @@ -442,6 +442,7 @@ size_error=`deve ser do tamanho %s.` min_size_error=` deve conter pelo menos %s caracteres.` max_size_error=` deve conter no máximo %s caracteres.` email_error=` não é um endereço de e-mail válido.` +url_error=`'%s' não é uma URL válida.` include_error=` deve conter '%s'.` glob_pattern_error=` padrão glob é inválido: %s.` regex_pattern_error=` o regex é inválido: %s.` @@ -715,6 +716,9 @@ generate_token_success=Seu novo token foi gerado. Copie-o agora, pois ele não s generate_token_name_duplicate=%s já foi usado como um nome de aplicativo. Por favor, use outro. delete_token=Excluir access_token_deletion=Excluir token de acesso +access_token_deletion_cancel_action=Cancelar +access_token_deletion_confirm_action=Excluir +access_token_deletion_desc=A exclusão de um token revoga o acesso à sua conta para aplicativos que o usam. Continuar? delete_token_success=O token foi excluído. Os aplicativos que o utilizam já não têm acesso à sua conta. manage_oauth2_applications=Gerenciar aplicativos OAuth2 @@ -1487,6 +1491,7 @@ pulls.new=Novo pull request pulls.view=Ver Pull Request pulls.compare_changes=Novo pull request pulls.allow_edits_from_maintainers=Permitir edições de mantenedores +pulls.allow_edits_from_maintainers_err=Falha na atualização pulls.compare_changes_desc=Selecione o branch de destino (push) e o branch de origem (pull) para o merge. pulls.has_viewed_file=Visto pulls.has_changed_since_last_review=Alterado desde a última revisão @@ -1590,6 +1595,7 @@ pulls.merge_instruction_hint=`Você também pode ver as 0 { + if projectID > 0 && isProjectsEnabled { project, err := project_model.GetProjectByID(ctx, projectID) if err != nil { log.Error("GetProjectByID: %d: %v", projectID, err) @@ -1043,6 +1044,11 @@ func NewIssuePost(ctx *context.Context) { } if projectID > 0 { + if !ctx.Repo.CanRead(unit.TypeProjects) { + // User must also be able to see the project. + ctx.Error(http.StatusBadRequest, "user hasn't permissions to read projects") + return + } if err := issues_model.ChangeProjectAssign(issue, ctx.Doer, projectID); err != nil { ctx.ServerError("ChangeProjectAssign", err) return @@ -1783,6 +1789,10 @@ func getActionIssues(ctx *context.Context) []*issues_model.Issue { issueUnitEnabled := ctx.Repo.CanRead(unit.TypeIssues) prUnitEnabled := ctx.Repo.CanRead(unit.TypePullRequests) for _, issue := range issues { + if issue.RepoID != ctx.Repo.Repository.ID { + ctx.NotFound("some issue's RepoID is incorrect", errors.New("some issue's RepoID is incorrect")) + return nil + } if issue.IsPull && !prUnitEnabled || !issue.IsPull && !issueUnitEnabled { ctx.NotFound("IssueOrPullRequestUnitNotAllowed", nil) return nil diff --git a/routers/web/repo/issue_content_history.go b/routers/web/repo/issue_content_history.go index d8a21c7fd7..a9386d274a 100644 --- a/routers/web/repo/issue_content_history.go +++ b/routers/web/repo/issue_content_history.go @@ -17,7 +17,6 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" - "code.gitea.io/gitea/modules/translation/i18n" "github.com/sergi/go-diff/diffmatchpatch" ) @@ -29,14 +28,13 @@ func GetContentHistoryOverview(ctx *context.Context) { return } - lang := ctx.Locale.Language() editedHistoryCountMap, _ := issues_model.QueryIssueContentHistoryEditedCountMap(ctx, issue.ID) ctx.JSON(http.StatusOK, map[string]interface{}{ "i18n": map[string]interface{}{ - "textEdited": i18n.Tr(lang, "repo.issues.content_history.edited"), - "textDeleteFromHistory": i18n.Tr(lang, "repo.issues.content_history.delete_from_history"), - "textDeleteFromHistoryConfirm": i18n.Tr(lang, "repo.issues.content_history.delete_from_history_confirm"), - "textOptions": i18n.Tr(lang, "repo.issues.content_history.options"), + "textEdited": ctx.Tr("repo.issues.content_history.edited"), + "textDeleteFromHistory": ctx.Tr("repo.issues.content_history.delete_from_history"), + "textDeleteFromHistoryConfirm": ctx.Tr("repo.issues.content_history.delete_from_history_confirm"), + "textOptions": ctx.Tr("repo.issues.content_history.options"), }, "editedHistoryCountMap": editedHistoryCountMap, }) @@ -55,7 +53,6 @@ func GetContentHistoryList(ctx *context.Context) { // render history list to HTML for frontend dropdown items: (name, value) // name is HTML of "avatar + userName + userAction + timeSince" // value is historyId - lang := ctx.Locale.Language() var results []map[string]interface{} for _, item := range items { var actionText string @@ -67,7 +64,7 @@ func GetContentHistoryList(ctx *context.Context) { } else { actionText = ctx.Locale.Tr("repo.issues.content_history.edited") } - timeSinceText := timeutil.TimeSinceUnix(item.EditedUnix, lang) + timeSinceText := timeutil.TimeSinceUnix(item.EditedUnix, ctx.Locale) username := item.UserName if setting.UI.DefaultShowFullName && strings.TrimSpace(item.UserFullName) != "" { diff --git a/routers/web/repo/projects.go b/routers/web/repo/projects.go index 0aa9b5effc..f054ad6e54 100644 --- a/routers/web/repo/projects.go +++ b/routers/web/repo/projects.go @@ -5,6 +5,7 @@ package repo import ( + "errors" "fmt" "net/http" "net/url" @@ -633,10 +634,17 @@ func MoveIssues(ctx *context.Context) { } if len(movedIssues) != len(form.Issues) { - ctx.ServerError("IssuesNotFound", err) + ctx.ServerError("some issues do not exist", errors.New("some issues do not exist")) return } + for _, issue := range movedIssues { + if issue.RepoID != project.RepoID { + ctx.ServerError("Some issue's repoID is not equal to project's repoID", errors.New("Some issue's repoID is not equal to project's repoID")) + return + } + } + if err = project_model.MoveIssuesOnProjectBoard(board, sortedIssueIDs); err != nil { ctx.ServerError("MoveIssuesOnProjectBoard", err) return diff --git a/routers/web/repo/pull_review.go b/routers/web/repo/pull_review.go index cc7ae9bbfa..5a9f7a8138 100644 --- a/routers/web/repo/pull_review.go +++ b/routers/web/repo/pull_review.go @@ -5,6 +5,7 @@ package repo import ( + "errors" "fmt" "net/http" @@ -118,6 +119,11 @@ func UpdateResolveConversation(ctx *context.Context) { return } + if comment.Issue.RepoID != ctx.Repo.Repository.ID { + ctx.NotFound("comment's repoID is incorrect", errors.New("comment's repoID is incorrect")) + return + } + var permResult bool if permResult, err = issues_model.CanMarkConversation(comment.Issue, ctx.Doer); err != nil { ctx.ServerError("CanMarkConversation", err) @@ -236,7 +242,7 @@ func SubmitReview(ctx *context.Context) { // DismissReview dismissing stale review by repo admin func DismissReview(ctx *context.Context) { form := web.GetForm(ctx).(*forms.DismissReviewForm) - comm, err := pull_service.DismissReview(ctx, form.ReviewID, form.Message, ctx.Doer, true) + comm, err := pull_service.DismissReview(ctx, form.ReviewID, ctx.Repo.Repository.ID, form.Message, ctx.Doer, true) if err != nil { ctx.ServerError("pull_service.DismissReview", err) return diff --git a/routers/web/user/profile.go b/routers/web/user/profile.go index c76cdc6d2e..792adadd03 100644 --- a/routers/web/user/profile.go +++ b/routers/web/user/profile.go @@ -163,7 +163,7 @@ func Profile(ctx *context.Context) { switch tab { case "followers": - items, err := user_model.GetUserFollowers(ctx.ContextUser, db.ListOptions{ + items, count, err := user_model.GetUserFollowers(ctx, ctx.ContextUser, ctx.Doer, db.ListOptions{ PageSize: setting.UI.User.RepoPagingNum, Page: page, }) @@ -173,9 +173,9 @@ func Profile(ctx *context.Context) { } ctx.Data["Cards"] = items - total = ctx.ContextUser.NumFollowers + total = int(count) case "following": - items, err := user_model.GetUserFollowing(ctx.ContextUser, db.ListOptions{ + items, count, err := user_model.GetUserFollowing(ctx, ctx.ContextUser, ctx.Doer, db.ListOptions{ PageSize: setting.UI.User.RepoPagingNum, Page: page, }) @@ -185,7 +185,7 @@ func Profile(ctx *context.Context) { } ctx.Data["Cards"] = items - total = ctx.ContextUser.NumFollowing + total = int(count) case "activity": ctx.Data["Feeds"], err = models.GetFeeds(ctx, models.GetFeedsOptions{ RequestedUser: ctx.ContextUser, diff --git a/routers/web/user/setting/account.go b/routers/web/user/setting/account.go index 3e96cc7c85..dfade13a1c 100644 --- a/routers/web/user/setting/account.go +++ b/routers/web/user/setting/account.go @@ -34,6 +34,7 @@ func Account(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("settings") ctx.Data["PageIsSettingsAccount"] = true ctx.Data["Email"] = ctx.Doer.Email + ctx.Data["EnableNotifyMail"] = setting.Service.EnableNotifyMail loadAccountData(ctx) @@ -146,7 +147,7 @@ func EmailPost(ctx *context.Context) { log.Error("Set cache(MailResendLimit) fail: %v", err) } } - ctx.Flash.Info(ctx.Tr("settings.add_email_confirmation_sent", address, timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale.Language()))) + ctx.Flash.Info(ctx.Tr("settings.add_email_confirmation_sent", address, timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale))) ctx.Redirect(setting.AppSubURL + "/user/settings/account") return } @@ -208,7 +209,7 @@ func EmailPost(ctx *context.Context) { log.Error("Set cache(MailResendLimit) fail: %v", err) } } - ctx.Flash.Info(ctx.Tr("settings.add_email_confirmation_sent", email.Email, timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale.Language()))) + ctx.Flash.Info(ctx.Tr("settings.add_email_confirmation_sent", email.Email, timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale))) } else { ctx.Flash.Success(ctx.Tr("settings.add_email_success")) } diff --git a/routers/web/user/setting/profile.go b/routers/web/user/setting/profile.go index 46399338fa..b07813e725 100644 --- a/routers/web/user/setting/profile.go +++ b/routers/web/user/setting/profile.go @@ -23,7 +23,7 @@ import ( "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/translation/i18n" + "code.gitea.io/gitea/modules/translation" "code.gitea.io/gitea/modules/typesniffer" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" @@ -136,7 +136,7 @@ func ProfilePost(ctx *context.Context) { middleware.SetLocaleCookie(ctx.Resp, ctx.Doer.Language, 0) log.Trace("User settings updated: %s", ctx.Doer.Name) - ctx.Flash.Success(i18n.Tr(ctx.Doer.Language, "settings.update_profile_success")) + ctx.Flash.Success(translation.NewLocale(ctx.Doer.Language).Tr("settings.update_profile_success")) ctx.Redirect(setting.AppSubURL + "/user/settings") } @@ -425,7 +425,7 @@ func UpdateUserLang(ctx *context.Context) { middleware.SetLocaleCookie(ctx.Resp, ctx.Doer.Language, 0) log.Trace("User settings updated: %s", ctx.Doer.Name) - ctx.Flash.Success(i18n.Tr(ctx.Doer.Language, "settings.update_language_success")) + ctx.Flash.Success(translation.NewLocale(ctx.Doer.Language).Tr("settings.update_language_success")) ctx.Redirect(setting.AppSubURL + "/user/settings/appearance") } diff --git a/routers/web/user/setting/security/security.go b/routers/web/user/setting/security/security.go index 747bf64a17..218cf57ab7 100644 --- a/routers/web/user/setting/security/security.go +++ b/routers/web/user/setting/security/security.go @@ -26,7 +26,6 @@ const ( func Security(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("settings") ctx.Data["PageIsSettingsSecurity"] = true - ctx.Data["RequireU2F"] = true if ctx.FormString("openid.return_to") != "" { settingsOpenIDVerify(ctx) diff --git a/routers/web/web.go b/routers/web/web.go index 80469ef7cd..1b6dd03bc8 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -901,7 +901,7 @@ func RegisterRoutes(m *web.Route) { m.Post("/labels", reqRepoIssuesOrPullsWriter, repo.UpdateIssueLabel) m.Post("/milestone", reqRepoIssuesOrPullsWriter, repo.UpdateIssueMilestone) - m.Post("/projects", reqRepoIssuesOrPullsWriter, repo.UpdateIssueProject) + m.Post("/projects", reqRepoIssuesOrPullsWriter, reqRepoProjectsReader, repo.UpdateIssueProject) m.Post("/assignee", reqRepoIssuesOrPullsWriter, repo.UpdateIssueAssignee) m.Post("/request_review", reqRepoIssuesOrPullsReader, repo.UpdatePullReviewRequest) m.Post("/dismiss_review", reqRepoAdmin, bindIgnErr(forms.DismissReviewForm{}), repo.DismissReview) diff --git a/services/auth/source/ldap/source_search.go b/services/auth/source/ldap/source_search.go index 988d56005e..a97a1179d9 100644 --- a/services/auth/source/ldap/source_search.go +++ b/services/auth/source/ldap/source_search.go @@ -199,7 +199,7 @@ func checkRestricted(l *ldap.Conn, ls *Source, userDN string) bool { // List all group memberships of a user func (source *Source) listLdapGroupMemberships(l *ldap.Conn, uid string) []string { var ldapGroups []string - groupFilter := fmt.Sprintf("(%s=%s)", source.GroupMemberUID, uid) + groupFilter := fmt.Sprintf("(%s=%s)", source.GroupMemberUID, ldap.EscapeFilter(uid)) result, err := l.Search(ldap.NewSearchRequest( source.GroupDN, ldap.ScopeWholeSubtree, diff --git a/services/cron/cron.go b/services/cron/cron.go index ebbcd75b6d..8e19e04416 100644 --- a/services/cron/cron.go +++ b/services/cron/cron.go @@ -13,6 +13,7 @@ import ( "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/modules/sync" + "code.gitea.io/gitea/modules/translation" "github.com/gogs/cron" ) @@ -63,7 +64,7 @@ type TaskTableRow struct { task *Task } -func (t *TaskTableRow) FormatLastMessage(locale string) string { +func (t *TaskTableRow) FormatLastMessage(locale translation.Locale) string { if t.Status == "finished" { return t.task.GetConfig().FormatMessage(locale, t.Name, t.Status, t.LastDoer) } diff --git a/services/cron/setting.go b/services/cron/setting.go index 9b59a562f7..eb13242e94 100644 --- a/services/cron/setting.go +++ b/services/cron/setting.go @@ -7,7 +7,7 @@ package cron import ( "time" - "code.gitea.io/gitea/modules/translation/i18n" + "code.gitea.io/gitea/modules/translation" ) // Config represents a basic configuration interface that cron task @@ -15,7 +15,7 @@ type Config interface { IsEnabled() bool DoRunAtStart() bool GetSchedule() string - FormatMessage(locale, name, status, doer string, args ...interface{}) string + FormatMessage(locale translation.Locale, name, status, doer string, args ...interface{}) string DoNoticeOnSuccess() bool } @@ -69,9 +69,9 @@ func (b *BaseConfig) DoNoticeOnSuccess() bool { // FormatMessage returns a message 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, name, status, doer string, args ...interface{}) string { +func (b *BaseConfig) FormatMessage(locale translation.Locale, name, status, doer string, args ...interface{}) string { realArgs := make([]interface{}, 0, len(args)+2) - realArgs = append(realArgs, i18n.Tr(locale, "admin.dashboard."+name)) + realArgs = append(realArgs, locale.Tr("admin.dashboard."+name)) if doer == "" { realArgs = append(realArgs, "(Cron)") } else { @@ -81,7 +81,7 @@ func (b *BaseConfig) FormatMessage(locale, name, status, doer string, args ...in realArgs = append(realArgs, args...) } if doer == "" { - return i18n.Tr(locale, "admin.dashboard.cron."+status, realArgs...) + return locale.Tr("admin.dashboard.cron."+status, realArgs...) } - return i18n.Tr(locale, "admin.dashboard.task."+status, realArgs...) + return locale.Tr("admin.dashboard.task."+status, realArgs...) } diff --git a/services/cron/tasks.go b/services/cron/tasks.go index 2252ad21e2..c26e47e0ce 100644 --- a/services/cron/tasks.go +++ b/services/cron/tasks.go @@ -94,7 +94,7 @@ func (t *Task) RunWithUser(doer *user_model.User, config Config) { doerName = doer.Name } - ctx, _, finished := pm.AddContext(baseCtx, config.FormatMessage("en-US", t.Name, "process", doerName)) + ctx, _, finished := pm.AddContext(baseCtx, config.FormatMessage(translation.NewLocale("en-US"), t.Name, "process", doerName)) defer finished() if err := t.fun(ctx, doer, config); err != nil { @@ -114,7 +114,7 @@ func (t *Task) RunWithUser(doer *user_model.User, config Config) { t.LastDoer = doerName t.lock.Unlock() - if err := admin_model.CreateNotice(ctx, admin_model.NoticeTask, config.FormatMessage("en-US", t.Name, "cancelled", doerName, message)); err != nil { + if err := admin_model.CreateNotice(ctx, admin_model.NoticeTask, config.FormatMessage(translation.NewLocale("en-US"), t.Name, "cancelled", doerName, message)); err != nil { log.Error("CreateNotice: %v", err) } return @@ -127,7 +127,7 @@ func (t *Task) RunWithUser(doer *user_model.User, config Config) { t.lock.Unlock() if config.DoNoticeOnSuccess() { - if err := admin_model.CreateNotice(ctx, admin_model.NoticeTask, config.FormatMessage("en-US", t.Name, "finished", doerName)); err != nil { + if err := admin_model.CreateNotice(ctx, admin_model.NoticeTask, config.FormatMessage(translation.NewLocale("en-US"), t.Name, "finished", doerName)); err != nil { log.Error("CreateNotice: %v", err) } } @@ -148,7 +148,7 @@ func RegisterTask(name string, config Config, fun func(context.Context, *user_mo log.Debug("Registering task: %s", name) i18nKey := "admin.dashboard." + name - if _, ok := translation.TryTr("en-US", i18nKey); !ok { + if value := translation.NewLocale("en-US").Tr(i18nKey); value == i18nKey { return fmt.Errorf("translation is missing for task %q, please add translation for %q", name, i18nKey) } diff --git a/services/issue/milestone.go b/services/issue/milestone.go index af337c3f14..d7c5fa4551 100644 --- a/services/issue/milestone.go +++ b/services/issue/milestone.go @@ -15,6 +15,17 @@ import ( ) func changeMilestoneAssign(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldMilestoneID int64) error { + // Only check if milestone exists if we don't remove it. + if issue.MilestoneID > 0 { + has, err := issues_model.HasMilestoneByRepoID(ctx, issue.RepoID, issue.MilestoneID) + if err != nil { + return fmt.Errorf("HasMilestoneByRepoID: %v", err) + } + if !has { + return fmt.Errorf("HasMilestoneByRepoID: issue doesn't exist") + } + } + if err := issues_model.UpdateIssueCols(ctx, issue, "milestone_id"); err != nil { return err } diff --git a/services/mailer/mail.go b/services/mailer/mail.go index f936229551..b8d79bd818 100644 --- a/services/mailer/mail.go +++ b/services/mailer/mail.go @@ -75,12 +75,12 @@ func sendUserMail(language string, u *user_model.User, tpl base.TplName, code, s locale := translation.NewLocale(language) data := map[string]interface{}{ "DisplayName": u.DisplayName(), - "ActiveCodeLives": timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, language), - "ResetPwdCodeLives": timeutil.MinutesToFriendly(setting.Service.ResetPwdCodeLives, language), + "ActiveCodeLives": timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, locale), + "ResetPwdCodeLives": timeutil.MinutesToFriendly(setting.Service.ResetPwdCodeLives, locale), "Code": code, "Language": locale.Language(), // helper - "i18n": locale, + "locale": locale, "Str2html": templates.Str2html, "DotEscape": templates.DotEscape, } @@ -126,12 +126,12 @@ func SendActivateEmailMail(u *user_model.User, email *user_model.EmailAddress) { locale := translation.NewLocale(u.Language) data := map[string]interface{}{ "DisplayName": u.DisplayName(), - "ActiveCodeLives": timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, locale.Language()), + "ActiveCodeLives": timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, locale), "Code": u.GenerateEmailActivateCode(email.Email), "Email": email.Email, "Language": locale.Language(), // helper - "i18n": locale, + "locale": locale, "Str2html": templates.Str2html, "DotEscape": templates.DotEscape, } @@ -162,7 +162,7 @@ func SendRegisterNotifyMail(u *user_model.User) { "Username": u.Name, "Language": locale.Language(), // helper - "i18n": locale, + "locale": locale, "Str2html": templates.Str2html, "DotEscape": templates.DotEscape, } @@ -196,7 +196,7 @@ func SendCollaboratorMail(u, doer *user_model.User, repo *repo_model.Repository) "Link": repo.HTMLURL(), "Language": locale.Language(), // helper - "i18n": locale, + "locale": locale, "Str2html": templates.Str2html, "DotEscape": templates.DotEscape, } @@ -281,7 +281,7 @@ func composeIssueCommentMessages(ctx *mailCommentContext, lang string, recipient "ReviewComments": reviewComments, "Language": locale.Language(), // helper - "i18n": locale, + "locale": locale, "Str2html": templates.Str2html, "DotEscape": templates.DotEscape, } diff --git a/services/mailer/mail_release.go b/services/mailer/mail_release.go index b6bddeac04..dd9f78612c 100644 --- a/services/mailer/mail_release.go +++ b/services/mailer/mail_release.go @@ -75,7 +75,7 @@ func mailNewRelease(ctx context.Context, lang string, tos []string, rel *models. "Subject": subject, "Language": locale.Language(), // helper - "i18n": locale, + "locale": locale, "Str2html": templates.Str2html, "DotEscape": templates.DotEscape, } diff --git a/services/mailer/mail_repo.go b/services/mailer/mail_repo.go index 7f856f2d40..6fe9df0926 100644 --- a/services/mailer/mail_repo.go +++ b/services/mailer/mail_repo.go @@ -74,7 +74,7 @@ func sendRepoTransferNotifyMailPerLang(lang string, newOwner, doer *user_model.U "Language": locale.Language(), "Destination": destination, // helper - "i18n": locale, + "locale": locale, "Str2html": templates.Str2html, "DotEscape": templates.DotEscape, } diff --git a/services/migrations/dump.go b/services/migrations/dump.go index 21d03b333f..a9ec459519 100644 --- a/services/migrations/dump.go +++ b/services/migrations/dump.go @@ -590,7 +590,7 @@ func updateOptionsUnits(opts *base.MigrateOptions, units []string) error { opts.ReleaseAssets = true } else { for _, unit := range units { - switch strings.ToLower(unit) { + switch strings.ToLower(strings.TrimSpace(unit)) { case "": continue case "wiki": diff --git a/services/pull/review.go b/services/pull/review.go index 6bb8877b0f..22e0ae9853 100644 --- a/services/pull/review.go +++ b/services/pull/review.go @@ -271,7 +271,7 @@ func SubmitReview(ctx context.Context, doer *user_model.User, gitRepo *git.Repos } // DismissReview dismissing stale review by repo admin -func DismissReview(ctx context.Context, reviewID int64, message string, doer *user_model.User, isDismiss bool) (comment *issues_model.Comment, err error) { +func DismissReview(ctx context.Context, reviewID, repoID int64, message string, doer *user_model.User, isDismiss bool) (comment *issues_model.Comment, err error) { review, err := issues_model.GetReviewByID(ctx, reviewID) if err != nil { return @@ -281,6 +281,16 @@ func DismissReview(ctx context.Context, reviewID int64, message string, doer *us return nil, fmt.Errorf("not need to dismiss this review because it's type is not Approve or change request") } + // load data for notify + if err = review.LoadAttributes(ctx); err != nil { + return nil, err + } + + // Check if the review's repoID is the one we're currently expecting. + if review.Issue.RepoID != repoID { + return nil, fmt.Errorf("reviews's repository is not the same as the one we expect") + } + if err = issues_model.DismissReview(review, isDismiss); err != nil { return } @@ -289,10 +299,6 @@ func DismissReview(ctx context.Context, reviewID int64, message string, doer *us return nil, nil } - // load data for notify - if err = review.LoadAttributes(ctx); err != nil { - return - } if err = review.Issue.LoadPullRequest(); err != nil { return } diff --git a/templates/admin/auth/edit.tmpl b/templates/admin/auth/edit.tmpl index 6e491d6cf4..af3f381c8e 100644 --- a/templates/admin/auth/edit.tmpl +++ b/templates/admin/auth/edit.tmpl @@ -4,7 +4,7 @@
{{template "base/alert" .}}

- {{.i18n.Tr "admin.auths.edit"}} + {{.locale.Tr "admin.auths.edit"}}

@@ -12,12 +12,12 @@ {{.CsrfTokenHtml}}
- + {{.Source.TypeName}}
- +
@@ -25,7 +25,7 @@ {{if or .Source.IsLDAP .Source.IsDLDAP}} {{ $cfg:=.Source.Cfg }}
- +
- +
- +
- +
{{if .Source.IsLDAP}}
- +
- +
{{end}}
- +
{{if .Source.IsDLDAP}}
- +
{{end}}
- +
- +
- + -

{{.i18n.Tr "admin.auths.restricted_filter_helper"}}

+

{{.locale.Tr "admin.auths.restricted_filter_helper"}}

- - + +
- +
- +
- +
- +
- +
@@ -113,33 +113,33 @@
- +
- +
- +
- +
- +
- +
- +
@@ -148,31 +148,31 @@ {{if .Source.IsLDAP}}
- +
- +
- +
{{end}}
- + -

{{.i18n.Tr "admin.auths.skip_local_two_fa_helper"}}

+

{{.locale.Tr "admin.auths.skip_local_two_fa_helper"}}

- +
@@ -182,7 +182,7 @@ {{if .Source.IsSMTP}} {{ $cfg:=.Source.Cfg }}
- +
- +
- +
- +
-

{{.i18n.Tr "admin.auths.force_smtps_helper"}}

+

{{.locale.Tr "admin.auths.force_smtps_helper"}}

- +
- + -

{{.i18n.Tr "admin.auths.helo_hostname_helper"}}

+

{{.locale.Tr "admin.auths.helo_hostname_helper"}}

- +
- + -

{{.i18n.Tr "admin.auths.allowed_domains_helper"}}

+

{{.locale.Tr "admin.auths.allowed_domains_helper"}}

- + -

{{.i18n.Tr "admin.auths.skip_local_two_fa_helper"}}

+

{{.locale.Tr "admin.auths.skip_local_two_fa_helper"}}

{{end}} @@ -244,18 +244,18 @@ {{if .Source.IsPAM}} {{ $cfg:=.Source.Cfg }}
- +
- +
- + -

{{.i18n.Tr "admin.auths.skip_local_two_fa_helper"}}

+

{{.locale.Tr "admin.auths.skip_local_two_fa_helper"}}

{{end}} @@ -264,7 +264,7 @@ {{if .Source.IsOAuth2}} {{ $cfg:=.Source.Cfg }}
- +
- +
- +
- +
- +
- + -

{{.i18n.Tr "admin.auths.skip_local_two_fa_helper"}}

+

{{.locale.Tr "admin.auths.skip_local_two_fa_helper"}}

- +
- +
- +
- +
- +
- +
@@ -336,29 +336,29 @@ {{end}}{{end}}
- +
- + -

{{.i18n.Tr "admin.auths.oauth2_required_claim_name_helper"}}

+

{{.locale.Tr "admin.auths.oauth2_required_claim_name_helper"}}

- + -

{{.i18n.Tr "admin.auths.oauth2_required_claim_value_helper"}}

+

{{.locale.Tr "admin.auths.oauth2_required_claim_value_helper"}}

- +
- +
- +
{{end}} @@ -368,32 +368,32 @@ {{ $cfg:=.Source.Cfg }}
- + -

{{.i18n.Tr "admin.auths.sspi_auto_create_users_helper"}}

+

{{.locale.Tr "admin.auths.sspi_auto_create_users_helper"}}

- + -

{{.i18n.Tr "admin.auths.sspi_auto_activate_users_helper"}}

+

{{.locale.Tr "admin.auths.sspi_auto_activate_users_helper"}}

- + -

{{.i18n.Tr "admin.auths.sspi_strip_domain_names_helper"}}

+

{{.locale.Tr "admin.auths.sspi_strip_domain_names_helper"}}

- + -

{{.i18n.Tr "admin.auths.sspi_separator_replacement_helper"}}

+

{{.locale.Tr "admin.auths.sspi_separator_replacement_helper"}}

- +
-

{{.i18n.Tr "admin.auths.sspi_default_language_helper"}}

+

{{.locale.Tr "admin.auths.sspi_default_language_helper"}}

{{end}} {{if .Source.IsLDAP}}
- +
{{end}}
- +
- -
{{.i18n.Tr "admin.auths.delete"}}
+ +
{{.locale.Tr "admin.auths.delete"}}
@@ -435,10 +435,10 @@ diff --git a/templates/admin/auth/list.tmpl b/templates/admin/auth/list.tmpl index f1b4da35eb..3ce138449d 100644 --- a/templates/admin/auth/list.tmpl +++ b/templates/admin/auth/list.tmpl @@ -4,9 +4,9 @@
{{template "base/alert" .}}

- {{.i18n.Tr "admin.auths.auth_manage_panel"}} ({{.i18n.Tr "admin.total" .Total}}) + {{.locale.Tr "admin.auths.auth_manage_panel"}} ({{.locale.Tr "admin.total" .Total}})

@@ -14,12 +14,12 @@ ID - {{.i18n.Tr "admin.auths.name"}} - {{.i18n.Tr "admin.auths.type"}} - {{.i18n.Tr "admin.auths.enabled"}} - {{.i18n.Tr "admin.auths.updated"}} - {{.i18n.Tr "admin.users.created"}} - {{.i18n.Tr "admin.users.edit"}} + {{.locale.Tr "admin.auths.name"}} + {{.locale.Tr "admin.auths.type"}} + {{.locale.Tr "admin.auths.enabled"}} + {{.locale.Tr "admin.auths.updated"}} + {{.locale.Tr "admin.users.created"}} + {{.locale.Tr "admin.users.edit"}} diff --git a/templates/admin/auth/new.tmpl b/templates/admin/auth/new.tmpl index 9882cde03b..6bfda9fcd3 100644 --- a/templates/admin/auth/new.tmpl +++ b/templates/admin/auth/new.tmpl @@ -4,7 +4,7 @@
{{template "base/alert" .}}

- {{.i18n.Tr "admin.auths.new"}} + {{.locale.Tr "admin.auths.new"}}

@@ -12,7 +12,7 @@ {{.CsrfTokenHtml}}
- +
- +
@@ -37,16 +37,16 @@
- + - +
- + -

{{.i18n.Tr "admin.auths.skip_local_two_fa_helper"}}

+

{{.locale.Tr "admin.auths.skip_local_two_fa_helper"}}

@@ -58,67 +58,67 @@
- +
- +
- +
- +

- {{.i18n.Tr "admin.auths.tips"}} + {{.locale.Tr "admin.auths.tips"}}

GMail Settings:

Host: smtp.gmail.com, Port: 587, Enable TLS Encryption: true

-
{{.i18n.Tr "admin.auths.tips.oauth2.general"}}:
-

{{.i18n.Tr "admin.auths.tips.oauth2.general.tip"}}

+
{{.locale.Tr "admin.auths.tips.oauth2.general"}}:
+

{{.locale.Tr "admin.auths.tips.oauth2.general.tip"}}

-
{{.i18n.Tr "admin.auths.tip.oauth2_provider"}}
+
{{.locale.Tr "admin.auths.tip.oauth2_provider"}}
  • Bitbucket
  • - {{.i18n.Tr "admin.auths.tip.bitbucket"}} + {{.locale.Tr "admin.auths.tip.bitbucket"}}
  • Dropbox
  • - {{.i18n.Tr "admin.auths.tip.dropbox"}} + {{.locale.Tr "admin.auths.tip.dropbox"}}
  • Facebook
  • - {{.i18n.Tr "admin.auths.tip.facebook"}} + {{.locale.Tr "admin.auths.tip.facebook"}}
  • GitHub
  • - {{.i18n.Tr "admin.auths.tip.github"}} + {{.locale.Tr "admin.auths.tip.github"}}
  • GitLab
  • - {{.i18n.Tr "admin.auths.tip.gitlab"}} + {{.locale.Tr "admin.auths.tip.gitlab"}}
  • Google
  • - {{.i18n.Tr "admin.auths.tip.google_plus"}} + {{.locale.Tr "admin.auths.tip.google_plus"}}
  • OpenID Connect
  • - {{.i18n.Tr "admin.auths.tip.openid_connect"}} + {{.locale.Tr "admin.auths.tip.openid_connect"}}
  • Twitter
  • - {{.i18n.Tr "admin.auths.tip.twitter"}} + {{.locale.Tr "admin.auths.tip.twitter"}}
  • Discord
  • - {{.i18n.Tr "admin.auths.tip.discord"}} + {{.locale.Tr "admin.auths.tip.discord"}}
  • Gitea
  • - {{.i18n.Tr "admin.auths.tip.gitea"}} + {{.locale.Tr "admin.auths.tip.gitea"}}
  • Nextcloud
  • - {{.i18n.Tr "admin.auths.tip.nextcloud"}} + {{.locale.Tr "admin.auths.tip.nextcloud"}}
  • Yandex
  • - {{.i18n.Tr "admin.auths.tip.yandex"}} + {{.locale.Tr "admin.auths.tip.yandex"}}
  • Mastodon
  • - {{.i18n.Tr "admin.auths.tip.mastodon"}} + {{.locale.Tr "admin.auths.tip.mastodon"}}
    diff --git a/templates/admin/auth/source/ldap.tmpl b/templates/admin/auth/source/ldap.tmpl index afdfbadd65..b44eb799b9 100644 --- a/templates/admin/auth/source/ldap.tmpl +++ b/templates/admin/auth/source/ldap.tmpl @@ -1,6 +1,6 @@
    - +
    - +
    - +
    - +
    - +
    - +
    - +
    - +
    - +
    - +
    - + -

    {{.i18n.Tr "admin.auths.restricted_filter_helper"}}

    +

    {{.locale.Tr "admin.auths.restricted_filter_helper"}}

    - - + +
    - +
    - +
    - +
    - +
    - +
    - +
    - +
    - +
    - +
    - +
    - +
    - +
    @@ -117,24 +117,24 @@
    - +
    - +
    - + -

    {{.i18n.Tr "admin.auths.skip_local_two_fa_helper"}}

    +

    {{.locale.Tr "admin.auths.skip_local_two_fa_helper"}}

    - +
    diff --git a/templates/admin/auth/source/oauth.tmpl b/templates/admin/auth/source/oauth.tmpl index 3991dc2170..166373a324 100644 --- a/templates/admin/auth/source/oauth.tmpl +++ b/templates/admin/auth/source/oauth.tmpl @@ -1,6 +1,6 @@
    - +
    - +
    - +
    - +
    - +
    - + -

    {{.i18n.Tr "admin.auths.skip_local_two_fa_helper"}}

    +

    {{.locale.Tr "admin.auths.skip_local_two_fa_helper"}}

    - +
    - +
    - +
    - +
    - +
    - +
    @@ -73,29 +73,29 @@ {{end}}{{end}}
    - +
    - + -

    {{.i18n.Tr "admin.auths.oauth2_required_claim_name_helper"}}

    +

    {{.locale.Tr "admin.auths.oauth2_required_claim_name_helper"}}

    - + -

    {{.i18n.Tr "admin.auths.oauth2_required_claim_value_helper"}}

    +

    {{.locale.Tr "admin.auths.oauth2_required_claim_value_helper"}}

    - +
    - +
    - +
    diff --git a/templates/admin/auth/source/smtp.tmpl b/templates/admin/auth/source/smtp.tmpl index 8572d6dc56..2d577412c1 100644 --- a/templates/admin/auth/source/smtp.tmpl +++ b/templates/admin/auth/source/smtp.tmpl @@ -1,6 +1,6 @@
    - +
    - +
    - +
    - + -

    {{.i18n.Tr "admin.auths.force_smtps_helper"}}

    +

    {{.locale.Tr "admin.auths.force_smtps_helper"}}

    - +
    - + -

    {{.i18n.Tr "admin.auths.helo_hostname_helper"}}

    +

    {{.locale.Tr "admin.auths.helo_hostname_helper"}}

    - +
    - + -

    {{.i18n.Tr "admin.auths.allowed_domains_helper"}}

    +

    {{.locale.Tr "admin.auths.allowed_domains_helper"}}

    - + -

    {{.i18n.Tr "admin.auths.skip_local_two_fa_helper"}}

    +

    {{.locale.Tr "admin.auths.skip_local_two_fa_helper"}}

    diff --git a/templates/admin/auth/source/sspi.tmpl b/templates/admin/auth/source/sspi.tmpl index 91697ef9c5..dee40d9fd5 100644 --- a/templates/admin/auth/source/sspi.tmpl +++ b/templates/admin/auth/source/sspi.tmpl @@ -1,32 +1,32 @@
    - + -

    {{.i18n.Tr "admin.auths.sspi_auto_create_users_helper"}}

    +

    {{.locale.Tr "admin.auths.sspi_auto_create_users_helper"}}

    - + -

    {{.i18n.Tr "admin.auths.sspi_auto_activate_users_helper"}}

    +

    {{.locale.Tr "admin.auths.sspi_auto_activate_users_helper"}}

    - + -

    {{.i18n.Tr "admin.auths.sspi_strip_domain_names_helper"}}

    +

    {{.locale.Tr "admin.auths.sspi_strip_domain_names_helper"}}

    - + -

    {{.i18n.Tr "admin.auths.sspi_separator_replacement_helper"}}

    +

    {{.locale.Tr "admin.auths.sspi_separator_replacement_helper"}}

    - +
    -

    {{.i18n.Tr "admin.auths.sspi_default_language_helper"}}

    +

    {{.locale.Tr "admin.auths.sspi_default_language_helper"}}

    diff --git a/templates/admin/base/search.tmpl b/templates/admin/base/search.tmpl index 4ec62c162c..28bc478f6a 100644 --- a/templates/admin/base/search.tmpl +++ b/templates/admin/base/search.tmpl @@ -2,22 +2,22 @@
    - - + +
    diff --git a/templates/admin/config.tmpl b/templates/admin/config.tmpl index 2a27baf535..a55a797262 100644 --- a/templates/admin/config.tmpl +++ b/templates/admin/config.tmpl @@ -4,50 +4,50 @@
    {{template "base/alert" .}}

    - {{.i18n.Tr "admin.config.server_config"}} + {{.locale.Tr "admin.config.server_config"}}

    -
    {{.i18n.Tr "admin.config.app_name"}}
    +
    {{.locale.Tr "admin.config.app_name"}}
    {{AppName}}
    -
    {{.i18n.Tr "admin.config.app_ver"}}
    +
    {{.locale.Tr "admin.config.app_ver"}}
    {{AppVer}}{{AppBuiltWith}}
    -
    {{.i18n.Tr "admin.config.custom_conf"}}
    +
    {{.locale.Tr "admin.config.custom_conf"}}
    {{.CustomConf}}
    -
    {{.i18n.Tr "admin.config.app_url"}}
    +
    {{.locale.Tr "admin.config.app_url"}}
    {{.AppUrl}}
    -
    {{.i18n.Tr "admin.config.domain"}}
    +
    {{.locale.Tr "admin.config.domain"}}
    {{.Domain}}
    -
    {{.i18n.Tr "admin.config.offline_mode"}}
    +
    {{.locale.Tr "admin.config.offline_mode"}}
    {{if .OfflineMode}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.i18n.Tr "admin.config.disable_router_log"}}
    +
    {{.locale.Tr "admin.config.disable_router_log"}}
    {{if .DisableRouterLog}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.i18n.Tr "admin.config.run_user"}}
    +
    {{.locale.Tr "admin.config.run_user"}}
    {{.RunUser}}
    -
    {{.i18n.Tr "admin.config.run_mode"}}
    +
    {{.locale.Tr "admin.config.run_mode"}}
    {{.RunMode}}
    -
    {{.i18n.Tr "admin.config.git_version"}}
    +
    {{.locale.Tr "admin.config.git_version"}}
    {{.GitVersion}}
    -
    {{.i18n.Tr "admin.config.repo_root_path"}}
    +
    {{.locale.Tr "admin.config.repo_root_path"}}
    {{.RepoRootPath}}
    -
    {{.i18n.Tr "admin.config.static_file_root_path"}}
    +
    {{.locale.Tr "admin.config.static_file_root_path"}}
    {{.StaticRootPath}}
    -
    {{.i18n.Tr "admin.config.custom_file_root_path"}}
    +
    {{.locale.Tr "admin.config.custom_file_root_path"}}
    {{.CustomRootPath}}
    -
    {{.i18n.Tr "admin.config.log_file_root_path"}}
    +
    {{.locale.Tr "admin.config.log_file_root_path"}}
    {{.LogRootPath}}
    -
    {{.i18n.Tr "admin.config.script_type"}}
    +
    {{.locale.Tr "admin.config.script_type"}}
    {{.ScriptType}}
    -
    {{.i18n.Tr "admin.config.reverse_auth_user"}}
    +
    {{.locale.Tr "admin.config.reverse_auth_user"}}
    {{.ReverseProxyAuthUser}}
    {{if .EnvVars }} @@ -62,33 +62,33 @@

    - {{.i18n.Tr "admin.config.ssh_config"}} + {{.locale.Tr "admin.config.ssh_config"}}

    -
    {{.i18n.Tr "admin.config.ssh_enabled"}}
    +
    {{.locale.Tr "admin.config.ssh_enabled"}}
    {{if not .SSH.Disabled}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    {{if not .SSH.Disabled}} -
    {{.i18n.Tr "admin.config.ssh_start_builtin_server"}}
    +
    {{.locale.Tr "admin.config.ssh_start_builtin_server"}}
    {{if .SSH.StartBuiltinServer}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.i18n.Tr "admin.config.ssh_domain"}}
    +
    {{.locale.Tr "admin.config.ssh_domain"}}
    {{.SSH.Domain}}
    -
    {{.i18n.Tr "admin.config.ssh_port"}}
    +
    {{.locale.Tr "admin.config.ssh_port"}}
    {{.SSH.Port}}
    -
    {{.i18n.Tr "admin.config.ssh_listen_port"}}
    +
    {{.locale.Tr "admin.config.ssh_listen_port"}}
    {{.SSH.ListenPort}}
    {{if not .SSH.StartBuiltinServer}} -
    {{.i18n.Tr "admin.config.ssh_root_path"}}
    +
    {{.locale.Tr "admin.config.ssh_root_path"}}
    {{.SSH.RootPath}}
    -
    {{.i18n.Tr "admin.config.ssh_key_test_path"}}
    +
    {{.locale.Tr "admin.config.ssh_key_test_path"}}
    {{.SSH.KeyTestPath}}
    -
    {{.i18n.Tr "admin.config.ssh_keygen_path"}}
    +
    {{.locale.Tr "admin.config.ssh_keygen_path"}}
    {{.SSH.KeygenPath}}
    -
    {{.i18n.Tr "admin.config.ssh_minimum_key_size_check"}}
    +
    {{.locale.Tr "admin.config.ssh_minimum_key_size_check"}}
    {{if .SSH.MinimumKeySizeCheck}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    {{if .SSH.MinimumKeySizeCheck}} -
    {{.i18n.Tr "admin.config.ssh_minimum_key_sizes"}}
    +
    {{.locale.Tr "admin.config.ssh_minimum_key_sizes"}}
    {{.SSH.MinimumKeySizes}}
    {{end}} {{end}} @@ -97,304 +97,304 @@

    - {{.i18n.Tr "admin.config.lfs_config"}} + {{.locale.Tr "admin.config.lfs_config"}}

    -
    {{.i18n.Tr "admin.config.lfs_enabled"}}
    +
    {{.locale.Tr "admin.config.lfs_enabled"}}
    {{if .LFS.StartServer}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    {{if .LFS.StartServer}} -
    {{.i18n.Tr "admin.config.lfs_content_path"}}
    +
    {{.locale.Tr "admin.config.lfs_content_path"}}
    {{.LFS.Path}}
    -
    {{.i18n.Tr "admin.config.lfs_http_auth_expiry"}}
    +
    {{.locale.Tr "admin.config.lfs_http_auth_expiry"}}
    {{.LFS.HTTPAuthExpiry}}
    {{end}}

    - {{.i18n.Tr "admin.config.db_config"}} + {{.locale.Tr "admin.config.db_config"}}

    -
    {{.i18n.Tr "admin.config.db_type"}}
    +
    {{.locale.Tr "admin.config.db_type"}}
    {{.DbCfg.Type}}
    {{if not (eq .DbCfg.Type "sqlite3")}} -
    {{.i18n.Tr "admin.config.db_host"}}
    +
    {{.locale.Tr "admin.config.db_host"}}
    {{if .DbCfg.Host}}{{.DbCfg.Host}}{{else}}-{{end}}
    -
    {{.i18n.Tr "admin.config.db_name"}}
    +
    {{.locale.Tr "admin.config.db_name"}}
    {{if .DbCfg.Name}}{{.DbCfg.Name}}{{else}}-{{end}}
    -
    {{.i18n.Tr "admin.config.db_user"}}
    +
    {{.locale.Tr "admin.config.db_user"}}
    {{if .DbCfg.User}}{{.DbCfg.User}}{{else}}-{{end}}
    {{end}} {{if eq .DbCfg.Type "postgres"}} -
    {{.i18n.Tr "admin.config.db_schema"}}
    +
    {{.locale.Tr "admin.config.db_schema"}}
    {{if .DbCfg.Schema}}{{.DbCfg.Schema}}{{else}}-{{end}}
    -
    {{.i18n.Tr "admin.config.db_ssl_mode"}}
    +
    {{.locale.Tr "admin.config.db_ssl_mode"}}
    {{if .DbCfg.SSLMode}}{{.DbCfg.SSLMode}}{{else}}-{{end}}
    {{end}} {{if eq .DbCfg.Type "sqlite3"}} -
    {{.i18n.Tr "admin.config.db_path"}}
    +
    {{.locale.Tr "admin.config.db_path"}}
    {{if .DbCfg.Path}}{{.DbCfg.Path}}{{else}}-{{end}}
    {{end}}

    - {{.i18n.Tr "admin.config.service_config"}} + {{.locale.Tr "admin.config.service_config"}}

    -
    {{.i18n.Tr "admin.config.register_email_confirm"}}
    +
    {{.locale.Tr "admin.config.register_email_confirm"}}
    {{if .Service.RegisterEmailConfirm}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.i18n.Tr "admin.config.disable_register"}}
    +
    {{.locale.Tr "admin.config.disable_register"}}
    {{if .Service.DisableRegistration}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.i18n.Tr "admin.config.allow_only_internal_registration"}}
    +
    {{.locale.Tr "admin.config.allow_only_internal_registration"}}
    {{if .Service.AllowOnlyInternalRegistration}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.i18n.Tr "admin.config.allow_only_external_registration"}}
    +
    {{.locale.Tr "admin.config.allow_only_external_registration"}}
    {{if .Service.AllowOnlyExternalRegistration}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.i18n.Tr "admin.config.show_registration_button"}}
    +
    {{.locale.Tr "admin.config.show_registration_button"}}
    {{if .Service.ShowRegistrationButton}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.i18n.Tr "admin.config.enable_openid_signup"}}
    +
    {{.locale.Tr "admin.config.enable_openid_signup"}}
    {{if .Service.EnableOpenIDSignUp}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.i18n.Tr "admin.config.enable_openid_signin"}}
    +
    {{.locale.Tr "admin.config.enable_openid_signin"}}
    {{if .Service.EnableOpenIDSignIn}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.i18n.Tr "admin.config.require_sign_in_view"}}
    +
    {{.locale.Tr "admin.config.require_sign_in_view"}}
    {{if .Service.RequireSignInView}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.i18n.Tr "admin.config.mail_notify"}}
    +
    {{.locale.Tr "admin.config.mail_notify"}}
    {{if .Service.EnableNotifyMail}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.i18n.Tr "admin.config.disable_key_size_check"}}
    +
    {{.locale.Tr "admin.config.disable_key_size_check"}}
    {{if .SSH.MinimumKeySizeCheck}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.i18n.Tr "admin.config.enable_captcha"}}
    +
    {{.locale.Tr "admin.config.enable_captcha"}}
    {{if .Service.EnableCaptcha}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.i18n.Tr "admin.config.default_keep_email_private"}}
    +
    {{.locale.Tr "admin.config.default_keep_email_private"}}
    {{if .Service.DefaultKeepEmailPrivate}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.i18n.Tr "admin.config.default_allow_create_organization"}}
    +
    {{.locale.Tr "admin.config.default_allow_create_organization"}}
    {{if .Service.DefaultAllowCreateOrganization}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.i18n.Tr "admin.config.enable_timetracking"}}
    +
    {{.locale.Tr "admin.config.enable_timetracking"}}
    {{if .Service.EnableTimetracking}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    {{if .Service.EnableTimetracking}} -
    {{.i18n.Tr "admin.config.default_enable_timetracking"}}
    +
    {{.locale.Tr "admin.config.default_enable_timetracking"}}
    {{if .Service.DefaultEnableTimetracking}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.i18n.Tr "admin.config.default_allow_only_contributors_to_track_time"}}
    +
    {{.locale.Tr "admin.config.default_allow_only_contributors_to_track_time"}}
    {{if .Service.DefaultAllowOnlyContributorsToTrackTime}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    {{end}} -
    {{.i18n.Tr "admin.config.default_visibility_organization"}}
    +
    {{.locale.Tr "admin.config.default_visibility_organization"}}
    {{.Service.DefaultOrgVisibility}}
    -
    {{.i18n.Tr "admin.config.no_reply_address"}}
    +
    {{.locale.Tr "admin.config.no_reply_address"}}
    {{if .Service.NoReplyAddress}}{{.Service.NoReplyAddress}}{{else}}-{{end}}
    -
    {{.i18n.Tr "admin.config.default_enable_dependencies"}}
    +
    {{.locale.Tr "admin.config.default_enable_dependencies"}}
    {{if .Service.DefaultEnableDependencies}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.i18n.Tr "admin.config.active_code_lives"}}
    -
    {{.Service.ActiveCodeLives}} {{.i18n.Tr "tool.raw_minutes"}}
    -
    {{.i18n.Tr "admin.config.reset_password_code_lives"}}
    -
    {{.Service.ResetPwdCodeLives}} {{.i18n.Tr "tool.raw_minutes"}}
    +
    {{.locale.Tr "admin.config.active_code_lives"}}
    +
    {{.Service.ActiveCodeLives}} {{.locale.Tr "tool.raw_minutes"}}
    +
    {{.locale.Tr "admin.config.reset_password_code_lives"}}
    +
    {{.Service.ResetPwdCodeLives}} {{.locale.Tr "tool.raw_minutes"}}

    - {{.i18n.Tr "admin.config.webhook_config"}} + {{.locale.Tr "admin.config.webhook_config"}}

    -
    {{.i18n.Tr "admin.config.queue_length"}}
    +
    {{.locale.Tr "admin.config.queue_length"}}
    {{.Webhook.QueueLength}}
    -
    {{.i18n.Tr "admin.config.deliver_timeout"}}
    -
    {{.Webhook.DeliverTimeout}} {{.i18n.Tr "tool.raw_seconds"}}
    -
    {{.i18n.Tr "admin.config.skip_tls_verify"}}
    +
    {{.locale.Tr "admin.config.deliver_timeout"}}
    +
    {{.Webhook.DeliverTimeout}} {{.locale.Tr "tool.raw_seconds"}}
    +
    {{.locale.Tr "admin.config.skip_tls_verify"}}
    {{if .Webhook.SkipTLSVerify}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}

    - {{.i18n.Tr "admin.config.mailer_config"}} + {{.locale.Tr "admin.config.mailer_config"}}

    -
    {{.i18n.Tr "admin.config.mailer_enabled"}}
    +
    {{.locale.Tr "admin.config.mailer_enabled"}}
    {{if .MailerEnabled}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    {{if .MailerEnabled}} -
    {{.i18n.Tr "admin.config.mailer_name"}}
    +
    {{.locale.Tr "admin.config.mailer_name"}}
    {{.Mailer.Name}}
    {{if eq .Mailer.MailerType "smtp"}} -
    {{.i18n.Tr "admin.config.mailer_disable_helo"}}
    +
    {{.locale.Tr "admin.config.mailer_disable_helo"}}
    {{if .DisableHelo}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.i18n.Tr "admin.config.mailer_host"}}
    +
    {{.locale.Tr "admin.config.mailer_host"}}
    {{.Mailer.Host}}
    {{else if eq .Mailer.MailerType "sendmail"}} -
    {{.i18n.Tr "admin.config.mailer_use_sendmail"}}
    +
    {{.locale.Tr "admin.config.mailer_use_sendmail"}}
    {{svg "octicon-check"}}
    -
    {{.i18n.Tr "admin.config.mailer_sendmail_path"}}
    +
    {{.locale.Tr "admin.config.mailer_sendmail_path"}}
    {{.Mailer.SendmailPath}}
    -
    {{.i18n.Tr "admin.config.mailer_sendmail_args"}}
    +
    {{.locale.Tr "admin.config.mailer_sendmail_args"}}
    {{.Mailer.SendmailArgs}}
    -
    {{.i18n.Tr "admin.config.mailer_sendmail_timeout"}}
    -
    {{.Mailer.SendmailTimeout}} {{.i18n.Tr "tool.raw_seconds"}}
    +
    {{.locale.Tr "admin.config.mailer_sendmail_timeout"}}
    +
    {{.Mailer.SendmailTimeout}} {{.locale.Tr "tool.raw_seconds"}}
    {{end}} -
    {{.i18n.Tr "admin.config.mailer_user"}}
    +
    {{.locale.Tr "admin.config.mailer_user"}}
    {{if .Mailer.User}}{{.Mailer.User}}{{else}}(empty){{end}}

    {{.CsrfTokenHtml}}
    - +
    - +
    {{end}}

    - {{.i18n.Tr "admin.config.cache_config"}} + {{.locale.Tr "admin.config.cache_config"}}

    -
    {{.i18n.Tr "admin.config.cache_adapter"}}
    +
    {{.locale.Tr "admin.config.cache_adapter"}}
    {{.CacheAdapter}}
    {{if eq .CacheAdapter "memory"}} -
    {{.i18n.Tr "admin.config.cache_interval"}}
    -
    {{.CacheInterval}} {{.i18n.Tr "tool.raw_seconds"}}
    +
    {{.locale.Tr "admin.config.cache_interval"}}
    +
    {{.CacheInterval}} {{.locale.Tr "tool.raw_seconds"}}
    {{end}} {{if .CacheConn}} -
    {{.i18n.Tr "admin.config.cache_conn"}}
    +
    {{.locale.Tr "admin.config.cache_conn"}}
    {{.CacheConn}}
    -
    {{.i18n.Tr "admin.config.cache_item_ttl"}}
    +
    {{.locale.Tr "admin.config.cache_item_ttl"}}
    {{.CacheItemTTL}}
    {{end}}

    - {{.i18n.Tr "admin.config.session_config"}} + {{.locale.Tr "admin.config.session_config"}}

    -
    {{.i18n.Tr "admin.config.session_provider"}}
    +
    {{.locale.Tr "admin.config.session_provider"}}
    {{.SessionConfig.Provider}}
    -
    {{.i18n.Tr "admin.config.provider_config"}}
    +
    {{.locale.Tr "admin.config.provider_config"}}
    {{if .SessionConfig.ProviderConfig}}{{.SessionConfig.ProviderConfig}}{{else}}-{{end}}
    -
    {{.i18n.Tr "admin.config.cookie_name"}}
    +
    {{.locale.Tr "admin.config.cookie_name"}}
    {{.SessionConfig.CookieName}}
    -
    {{.i18n.Tr "admin.config.gc_interval_time"}}
    -
    {{.SessionConfig.Gclifetime}} {{.i18n.Tr "tool.raw_seconds"}}
    -
    {{.i18n.Tr "admin.config.session_life_time"}}
    -
    {{.SessionConfig.Maxlifetime}} {{.i18n.Tr "tool.raw_seconds"}}
    -
    {{.i18n.Tr "admin.config.https_only"}}
    +
    {{.locale.Tr "admin.config.gc_interval_time"}}
    +
    {{.SessionConfig.Gclifetime}} {{.locale.Tr "tool.raw_seconds"}}
    +
    {{.locale.Tr "admin.config.session_life_time"}}
    +
    {{.SessionConfig.Maxlifetime}} {{.locale.Tr "tool.raw_seconds"}}
    +
    {{.locale.Tr "admin.config.https_only"}}
    {{if .SessionConfig.Secure}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}

    - {{.i18n.Tr "admin.config.picture_config"}} + {{.locale.Tr "admin.config.picture_config"}}

    -
    {{.i18n.Tr "admin.config.disable_gravatar"}}
    +
    {{.locale.Tr "admin.config.disable_gravatar"}}
    {{if .DisableGravatar}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.i18n.Tr "admin.config.enable_federated_avatar"}}
    +
    {{.locale.Tr "admin.config.enable_federated_avatar"}}
    {{if .EnableFederatedAvatar}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}

    - {{.i18n.Tr "admin.config.git_config"}} + {{.locale.Tr "admin.config.git_config"}}

    -
    {{.i18n.Tr "admin.config.git_disable_diff_highlight"}}
    +
    {{.locale.Tr "admin.config.git_disable_diff_highlight"}}
    {{if .Git.DisableDiffHighlight}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.i18n.Tr "admin.config.git_max_diff_lines"}}
    +
    {{.locale.Tr "admin.config.git_max_diff_lines"}}
    {{.Git.MaxGitDiffLines}}
    -
    {{.i18n.Tr "admin.config.git_max_diff_line_characters"}}
    +
    {{.locale.Tr "admin.config.git_max_diff_line_characters"}}
    {{.Git.MaxGitDiffLineCharacters}}
    -
    {{.i18n.Tr "admin.config.git_max_diff_files"}}
    +
    {{.locale.Tr "admin.config.git_max_diff_files"}}
    {{.Git.MaxGitDiffFiles}}
    -
    {{.i18n.Tr "admin.config.git_gc_args"}}
    +
    {{.locale.Tr "admin.config.git_gc_args"}}
    {{.Git.GCArgs}}
    -
    {{.i18n.Tr "admin.config.git_migrate_timeout"}}
    -
    {{.Git.Timeout.Migrate}} {{.i18n.Tr "tool.raw_seconds"}}
    -
    {{.i18n.Tr "admin.config.git_mirror_timeout"}}
    -
    {{.Git.Timeout.Mirror}} {{.i18n.Tr "tool.raw_seconds"}}
    -
    {{.i18n.Tr "admin.config.git_clone_timeout"}}
    -
    {{.Git.Timeout.Clone}} {{.i18n.Tr "tool.raw_seconds"}}
    -
    {{.i18n.Tr "admin.config.git_pull_timeout"}}
    -
    {{.Git.Timeout.Pull}} {{.i18n.Tr "tool.raw_seconds"}}
    -
    {{.i18n.Tr "admin.config.git_gc_timeout"}}
    -
    {{.Git.Timeout.GC}} {{.i18n.Tr "tool.raw_seconds"}}
    +
    {{.locale.Tr "admin.config.git_migrate_timeout"}}
    +
    {{.Git.Timeout.Migrate}} {{.locale.Tr "tool.raw_seconds"}}
    +
    {{.locale.Tr "admin.config.git_mirror_timeout"}}
    +
    {{.Git.Timeout.Mirror}} {{.locale.Tr "tool.raw_seconds"}}
    +
    {{.locale.Tr "admin.config.git_clone_timeout"}}
    +
    {{.Git.Timeout.Clone}} {{.locale.Tr "tool.raw_seconds"}}
    +
    {{.locale.Tr "admin.config.git_pull_timeout"}}
    +
    {{.Git.Timeout.Pull}} {{.locale.Tr "tool.raw_seconds"}}
    +
    {{.locale.Tr "admin.config.git_gc_timeout"}}
    +
    {{.Git.Timeout.GC}} {{.locale.Tr "tool.raw_seconds"}}

    - {{.i18n.Tr "admin.config.log_config"}} + {{.locale.Tr "admin.config.log_config"}}

    {{range .Loggers.default.SubLogDescriptions}} -
    {{$.i18n.Tr "admin.config.log_mode"}}
    +
    {{$.locale.Tr "admin.config.log_mode"}}
    {{.Name}} ({{.Provider}})
    -
    {{$.i18n.Tr "admin.config.log_config"}}
    +
    {{$.locale.Tr "admin.config.log_config"}}
    {{.Config | JsonPrettyPrint}}
    {{end}}
    -
    {{$.i18n.Tr "admin.config.router_log_mode"}}
    +
    {{$.locale.Tr "admin.config.router_log_mode"}}
    {{if .DisableRouterLog}} -
    {{$.i18n.Tr "admin.config.disabled_logger"}}
    +
    {{$.locale.Tr "admin.config.disabled_logger"}}
    {{else}} {{if .Loggers.router.SubLogDescriptions}} -
    {{$.i18n.Tr "admin.config.own_named_logger"}}
    +
    {{$.locale.Tr "admin.config.own_named_logger"}}
    {{range .Loggers.router.SubLogDescriptions}} -
    {{$.i18n.Tr "admin.config.log_mode"}}
    +
    {{$.locale.Tr "admin.config.log_mode"}}
    {{.Name}} ({{.Provider}})
    -
    {{$.i18n.Tr "admin.config.log_config"}}
    +
    {{$.locale.Tr "admin.config.log_config"}}
    {{.Config | JsonPrettyPrint}}
    {{end}} {{else}} -
    {{$.i18n.Tr "admin.config.routes_to_default_logger"}}
    +
    {{$.locale.Tr "admin.config.routes_to_default_logger"}}
    {{end}} {{end}}
    -
    {{$.i18n.Tr "admin.config.access_log_mode"}}
    +
    {{$.locale.Tr "admin.config.access_log_mode"}}
    {{if .EnableAccessLog}} {{if .Loggers.access.SubLogDescriptions}} -
    {{$.i18n.Tr "admin.config.own_named_logger"}}
    +
    {{$.locale.Tr "admin.config.own_named_logger"}}
    {{range .Loggers.access.SubLogDescriptions}} -
    {{$.i18n.Tr "admin.config.log_mode"}}
    +
    {{$.locale.Tr "admin.config.log_mode"}}
    {{.Name}} ({{.Provider}})
    -
    {{$.i18n.Tr "admin.config.log_config"}}
    +
    {{$.locale.Tr "admin.config.log_config"}}
    {{.Config | JsonPrettyPrint}}
    {{end}} {{else}} -
    {{$.i18n.Tr "admin.config.routes_to_default_logger"}}
    +
    {{$.locale.Tr "admin.config.routes_to_default_logger"}}
    {{end}} -
    {{$.i18n.Tr "admin.config.access_log_template"}}
    +
    {{$.locale.Tr "admin.config.access_log_template"}}
    {{$.AccessLogTemplate}}
    {{else}} -
    {{$.i18n.Tr "admin.config.disabled_logger"}}
    +
    {{$.locale.Tr "admin.config.disabled_logger"}}
    {{end}}
    -
    {{$.i18n.Tr "admin.config.xorm_log_mode"}}
    +
    {{$.locale.Tr "admin.config.xorm_log_mode"}}
    {{if .EnableXORMLog}} {{if .Loggers.xorm.SubLogDescriptions}} -
    {{$.i18n.Tr "admin.config.own_named_logger"}}
    +
    {{$.locale.Tr "admin.config.own_named_logger"}}
    {{range .Loggers.xorm.SubLogDescriptions}} -
    {{$.i18n.Tr "admin.config.log_mode"}}
    +
    {{$.locale.Tr "admin.config.log_mode"}}
    {{.Name}} ({{.Provider}})
    -
    {{$.i18n.Tr "admin.config.log_config"}}
    +
    {{$.locale.Tr "admin.config.log_config"}}
    {{.Config | JsonPrettyPrint}}
    {{end}} {{else}} -
    {{$.i18n.Tr "admin.config.routes_to_default_logger"}}
    +
    {{$.locale.Tr "admin.config.routes_to_default_logger"}}
    {{end}} -
    {{$.i18n.Tr "admin.config.xorm_log_sql"}}
    +
    {{$.locale.Tr "admin.config.xorm_log_sql"}}
    {{if $.LogSQL}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    {{else}} -
    {{$.i18n.Tr "admin.config.disabled_logger"}}
    +
    {{$.locale.Tr "admin.config.disabled_logger"}}
    {{end}}
    diff --git a/templates/admin/cron.tmpl b/templates/admin/cron.tmpl index a73813ef88..b5db356bd8 100644 --- a/templates/admin/cron.tmpl +++ b/templates/admin/cron.tmpl @@ -1,5 +1,5 @@

    - {{.i18n.Tr "admin.monitor.cron"}} + {{.locale.Tr "admin.monitor.cron"}}

    @@ -7,24 +7,24 @@ - {{.i18n.Tr "admin.monitor.name"}} - {{.i18n.Tr "admin.monitor.schedule"}} - {{.i18n.Tr "admin.monitor.next"}} - {{.i18n.Tr "admin.monitor.previous"}} - {{.i18n.Tr "admin.monitor.execute_times"}} - {{.i18n.Tr "admin.monitor.last_execution_result"}} + {{.locale.Tr "admin.monitor.name"}} + {{.locale.Tr "admin.monitor.schedule"}} + {{.locale.Tr "admin.monitor.next"}} + {{.locale.Tr "admin.monitor.previous"}} + {{.locale.Tr "admin.monitor.execute_times"}} + {{.locale.Tr "admin.monitor.last_execution_result"}} {{range .Entries}} - - {{$.i18n.Tr (printf "admin.dashboard.%s" .Name)}} + + {{$.locale.Tr (printf "admin.dashboard.%s" .Name)}} {{.Spec}} {{DateFmtLong .Next}} {{if gt .Prev.Year 1 }}{{DateFmtLong .Prev}}{{else}}N/A{{end}} {{.ExecTimes}} - {{if eq .Status "" }}—{{else if eq .Status "finished"}}{{svg "octicon-check" 16}}{{else}}{{svg "octicon-x" 16}}{{end}} + {{if eq .Status "" }}—{{else if eq .Status "finished"}}{{svg "octicon-check" 16}}{{else}}{{svg "octicon-x" 16}}{{end}} {{end}} diff --git a/templates/admin/dashboard.tmpl b/templates/admin/dashboard.tmpl index 5a4b82f1b9..80eea91210 100644 --- a/templates/admin/dashboard.tmpl +++ b/templates/admin/dashboard.tmpl @@ -5,19 +5,19 @@ {{template "base/alert" .}} {{if .NeedUpdate}}
    -

    {{(.i18n.Tr "admin.dashboard.new_version_hint" .RemoteVersion AppVer) | Str2html}}

    +

    {{(.locale.Tr "admin.dashboard.new_version_hint" .RemoteVersion AppVer) | Str2html}}

    {{end}}

    - {{.i18n.Tr "admin.dashboard.statistic"}} + {{.locale.Tr "admin.dashboard.statistic"}}

    - {{.i18n.Tr "admin.dashboard.statistic_info" .Stats.Counter.User .Stats.Counter.Org .Stats.Counter.PublicKey .Stats.Counter.Repo .Stats.Counter.Watch .Stats.Counter.Star .Stats.Counter.Action .Stats.Counter.Access .Stats.Counter.Issue .Stats.Counter.Comment .Stats.Counter.Oauth .Stats.Counter.Follow .Stats.Counter.Mirror .Stats.Counter.Release .Stats.Counter.AuthSource .Stats.Counter.Webhook .Stats.Counter.Milestone .Stats.Counter.Label .Stats.Counter.HookTask .Stats.Counter.Team .Stats.Counter.UpdateTask .Stats.Counter.Attachment | Str2html}} + {{.locale.Tr "admin.dashboard.statistic_info" .Stats.Counter.User .Stats.Counter.Org .Stats.Counter.PublicKey .Stats.Counter.Repo .Stats.Counter.Watch .Stats.Counter.Star .Stats.Counter.Action .Stats.Counter.Access .Stats.Counter.Issue .Stats.Counter.Comment .Stats.Counter.Oauth .Stats.Counter.Follow .Stats.Counter.Mirror .Stats.Counter.Release .Stats.Counter.AuthSource .Stats.Counter.Webhook .Stats.Counter.Milestone .Stats.Counter.Label .Stats.Counter.HookTask .Stats.Counter.Team .Stats.Counter.UpdateTask .Stats.Counter.Attachment | Str2html}}

    - {{.i18n.Tr "admin.dashboard.operations"}} + {{.locale.Tr "admin.dashboard.operations"}}

    {{.CsrfTokenHtml}} @@ -25,52 +25,52 @@ - - + + - - + + - - + + - - + + {{if and (not .SSH.Disabled) (not .SSH.StartBuiltinServer)}} - - + + - - + + {{end}} - - + + - - + + - - + + - - + + - - + +
    {{.i18n.Tr "admin.dashboard.delete_inactive_accounts"}}{{.locale.Tr "admin.dashboard.delete_inactive_accounts"}}
    {{.i18n.Tr "admin.dashboard.delete_repo_archives"}}{{.locale.Tr "admin.dashboard.delete_repo_archives"}}
    {{.i18n.Tr "admin.dashboard.delete_missing_repos"}}{{.locale.Tr "admin.dashboard.delete_missing_repos"}}
    {{.i18n.Tr "admin.dashboard.git_gc_repos"}}{{.locale.Tr "admin.dashboard.git_gc_repos"}}
    {{.i18n.Tr "admin.dashboard.resync_all_sshkeys"}}
    - {{.i18n.Tr "admin.dashboard.resync_all_sshkeys.desc"}}
    {{.locale.Tr "admin.dashboard.resync_all_sshkeys"}}
    + {{.locale.Tr "admin.dashboard.resync_all_sshkeys.desc"}}
    {{.i18n.Tr "admin.dashboard.resync_all_sshprincipals"}}
    - {{.i18n.Tr "admin.dashboard.resync_all_sshprincipals.desc"}}
    {{.locale.Tr "admin.dashboard.resync_all_sshprincipals"}}
    + {{.locale.Tr "admin.dashboard.resync_all_sshprincipals.desc"}}
    {{.i18n.Tr "admin.dashboard.resync_all_hooks"}}{{.locale.Tr "admin.dashboard.resync_all_hooks"}}
    {{.i18n.Tr "admin.dashboard.reinit_missing_repos"}}{{.locale.Tr "admin.dashboard.reinit_missing_repos"}}
    {{.i18n.Tr "admin.dashboard.sync_external_users"}}{{.locale.Tr "admin.dashboard.sync_external_users"}}
    {{.i18n.Tr "admin.dashboard.repo_health_check"}}{{.locale.Tr "admin.dashboard.repo_health_check"}}
    {{.i18n.Tr "admin.dashboard.delete_generated_repository_avatars"}}{{.locale.Tr "admin.dashboard.delete_generated_repository_avatars"}}
    @@ -78,69 +78,69 @@

    - {{.i18n.Tr "admin.dashboard.system_status"}} + {{.locale.Tr "admin.dashboard.system_status"}}

    -
    {{.i18n.Tr "admin.dashboard.server_uptime"}}
    +
    {{.locale.Tr "admin.dashboard.server_uptime"}}
    {{.SysStatus.Uptime}}
    -
    {{.i18n.Tr "admin.dashboard.current_goroutine"}}
    +
    {{.locale.Tr "admin.dashboard.current_goroutine"}}
    {{.SysStatus.NumGoroutine}}
    -
    {{.i18n.Tr "admin.dashboard.current_memory_usage"}}
    +
    {{.locale.Tr "admin.dashboard.current_memory_usage"}}
    {{.SysStatus.MemAllocated}}
    -
    {{.i18n.Tr "admin.dashboard.total_memory_allocated"}}
    +
    {{.locale.Tr "admin.dashboard.total_memory_allocated"}}
    {{.SysStatus.MemTotal}}
    -
    {{.i18n.Tr "admin.dashboard.memory_obtained"}}
    +
    {{.locale.Tr "admin.dashboard.memory_obtained"}}
    {{.SysStatus.MemSys}}
    -
    {{.i18n.Tr "admin.dashboard.pointer_lookup_times"}}
    +
    {{.locale.Tr "admin.dashboard.pointer_lookup_times"}}
    {{.SysStatus.Lookups}}
    -
    {{.i18n.Tr "admin.dashboard.memory_allocate_times"}}
    +
    {{.locale.Tr "admin.dashboard.memory_allocate_times"}}
    {{.SysStatus.MemMallocs}}
    -
    {{.i18n.Tr "admin.dashboard.memory_free_times"}}
    +
    {{.locale.Tr "admin.dashboard.memory_free_times"}}
    {{.SysStatus.MemFrees}}
    -
    {{.i18n.Tr "admin.dashboard.current_heap_usage"}}
    +
    {{.locale.Tr "admin.dashboard.current_heap_usage"}}
    {{.SysStatus.HeapAlloc}}
    -
    {{.i18n.Tr "admin.dashboard.heap_memory_obtained"}}
    +
    {{.locale.Tr "admin.dashboard.heap_memory_obtained"}}
    {{.SysStatus.HeapSys}}
    -
    {{.i18n.Tr "admin.dashboard.heap_memory_idle"}}
    +
    {{.locale.Tr "admin.dashboard.heap_memory_idle"}}
    {{.SysStatus.HeapIdle}}
    -
    {{.i18n.Tr "admin.dashboard.heap_memory_in_use"}}
    +
    {{.locale.Tr "admin.dashboard.heap_memory_in_use"}}
    {{.SysStatus.HeapInuse}}
    -
    {{.i18n.Tr "admin.dashboard.heap_memory_released"}}
    +
    {{.locale.Tr "admin.dashboard.heap_memory_released"}}
    {{.SysStatus.HeapReleased}}
    -
    {{.i18n.Tr "admin.dashboard.heap_objects"}}
    +
    {{.locale.Tr "admin.dashboard.heap_objects"}}
    {{.SysStatus.HeapObjects}}
    -
    {{.i18n.Tr "admin.dashboard.bootstrap_stack_usage"}}
    +
    {{.locale.Tr "admin.dashboard.bootstrap_stack_usage"}}
    {{.SysStatus.StackInuse}}
    -
    {{.i18n.Tr "admin.dashboard.stack_memory_obtained"}}
    +
    {{.locale.Tr "admin.dashboard.stack_memory_obtained"}}
    {{.SysStatus.StackSys}}
    -
    {{.i18n.Tr "admin.dashboard.mspan_structures_usage"}}
    +
    {{.locale.Tr "admin.dashboard.mspan_structures_usage"}}
    {{.SysStatus.MSpanInuse}}
    -
    {{.i18n.Tr "admin.dashboard.mspan_structures_obtained"}}
    +
    {{.locale.Tr "admin.dashboard.mspan_structures_obtained"}}
    {{.SysStatus.MSpanSys}}
    -
    {{.i18n.Tr "admin.dashboard.mcache_structures_usage"}}
    +
    {{.locale.Tr "admin.dashboard.mcache_structures_usage"}}
    {{.SysStatus.MCacheInuse}}
    -
    {{.i18n.Tr "admin.dashboard.mcache_structures_obtained"}}
    +
    {{.locale.Tr "admin.dashboard.mcache_structures_obtained"}}
    {{.SysStatus.MCacheSys}}
    -
    {{.i18n.Tr "admin.dashboard.profiling_bucket_hash_table_obtained"}}
    +
    {{.locale.Tr "admin.dashboard.profiling_bucket_hash_table_obtained"}}
    {{.SysStatus.BuckHashSys}}
    -
    {{.i18n.Tr "admin.dashboard.gc_metadata_obtained"}}
    +
    {{.locale.Tr "admin.dashboard.gc_metadata_obtained"}}
    {{.SysStatus.GCSys}}
    -
    {{.i18n.Tr "admin.dashboard.other_system_allocation_obtained"}}
    +
    {{.locale.Tr "admin.dashboard.other_system_allocation_obtained"}}
    {{.SysStatus.OtherSys}}
    -
    {{.i18n.Tr "admin.dashboard.next_gc_recycle"}}
    +
    {{.locale.Tr "admin.dashboard.next_gc_recycle"}}
    {{.SysStatus.NextGC}}
    -
    {{.i18n.Tr "admin.dashboard.last_gc_time"}}
    +
    {{.locale.Tr "admin.dashboard.last_gc_time"}}
    {{.SysStatus.LastGC}}
    -
    {{.i18n.Tr "admin.dashboard.total_gc_pause"}}
    +
    {{.locale.Tr "admin.dashboard.total_gc_pause"}}
    {{.SysStatus.PauseTotalNs}}
    -
    {{.i18n.Tr "admin.dashboard.last_gc_pause"}}
    +
    {{.locale.Tr "admin.dashboard.last_gc_pause"}}
    {{.SysStatus.PauseNs}}
    -
    {{.i18n.Tr "admin.dashboard.gc_times"}}
    +
    {{.locale.Tr "admin.dashboard.gc_times"}}
    {{.SysStatus.NumGC}}
    diff --git a/templates/admin/emails/list.tmpl b/templates/admin/emails/list.tmpl index 92444efbd8..adf5b9bef7 100644 --- a/templates/admin/emails/list.tmpl +++ b/templates/admin/emails/list.tmpl @@ -4,28 +4,28 @@
    {{template "base/alert" .}}

    - {{.i18n.Tr "admin.emails.email_manage_panel"}} ({{.i18n.Tr "admin.total" .Total}}) + {{.locale.Tr "admin.emails.email_manage_panel"}} ({{.locale.Tr "admin.total" .Total}})

    @@ -34,16 +34,16 @@ - {{.i18n.Tr "admin.users.name"}} + {{.locale.Tr "admin.users.name"}} {{SortArrow "username" "reverseusername" $.SortType false}} - {{.i18n.Tr "admin.users.full_name"}} + {{.locale.Tr "admin.users.full_name"}} - {{.i18n.Tr "email"}} + {{.locale.Tr "email"}} {{SortArrow "email" "reverseemail" $.SortType true}} - {{.i18n.Tr "admin.emails.primary"}} - {{.i18n.Tr "admin.emails.activated"}} + {{.locale.Tr "admin.emails.primary"}} + {{.locale.Tr "admin.emails.activated"}} @@ -75,10 +75,10 @@ @@ -22,51 +22,51 @@ {{if .Team.Description}} {{.Team.Description}} {{else}} - {{.i18n.Tr "org.teams.no_desc"}} + {{.locale.Tr "org.teams.no_desc"}} {{end}}
    {{if eq .Team.LowerName "owners"}}
    - {{.i18n.Tr "org.teams.owners_permission_desc" | Str2html}} + {{.locale.Tr "org.teams.owners_permission_desc" | Str2html}}
    {{else}}
    -

    {{.i18n.Tr "org.team_access_desc"}}

    +

    {{.locale.Tr "org.team_access_desc"}}

      {{if .Team.IncludesAllRepositories}} -
    • {{.i18n.Tr "org.teams.all_repositories" | Str2html}} +
    • {{.locale.Tr "org.teams.all_repositories" | Str2html}} {{else}} -
    • {{.i18n.Tr "org.teams.specific_repositories" | Str2html}} +
    • {{.locale.Tr "org.teams.specific_repositories" | Str2html}} {{end}} {{if .Team.CanCreateOrgRepo}} -
    • {{.i18n.Tr "org.teams.can_create_org_repo"}} +
    • {{.locale.Tr "org.teams.can_create_org_repo"}} {{end}}
    {{if (eq .Team.AccessMode 2)}} -

    {{.i18n.Tr "org.settings.permission"}}

    - {{.i18n.Tr "org.teams.write_permission_desc" | Str2html}} +

    {{.locale.Tr "org.settings.permission"}}

    + {{.locale.Tr "org.teams.write_permission_desc" | Str2html}} {{else if (eq .Team.AccessMode 3)}} -

    {{.i18n.Tr "org.settings.permission"}}

    - {{.i18n.Tr "org.teams.admin_permission_desc" | Str2html}} +

    {{.locale.Tr "org.settings.permission"}}

    + {{.locale.Tr "org.teams.admin_permission_desc" | Str2html}} {{else}} - - + + {{range $t, $unit := $.Units}} {{if and (lt $unit.MaxPerm 2) (not $unit.Type.UnitGlobalDisabled)}} - + {{end}} @@ -79,17 +79,17 @@ {{if .IsOrganizationOwner}} {{end}} diff --git a/templates/org/team/teams.tmpl b/templates/org/team/teams.tmpl index 49407ef194..465701d96e 100644 --- a/templates/org/team/teams.tmpl +++ b/templates/org/team/teams.tmpl @@ -5,7 +5,7 @@ {{template "base/alert" .}} {{if .IsOrganizationOwner}}
    {{end}} @@ -20,12 +20,12 @@ + data-name="{{.Name}}">{{$.locale.Tr "org.teams.leave"}} {{else if $.IsOrganizationOwner}} {{$.CsrfTokenHtml}} - + {{end}} @@ -38,7 +38,7 @@ {{end}}
    -

    {{.NumMembers}} {{$.i18n.Tr "org.lower_members"}} · {{.NumRepos}} {{$.i18n.Tr "org.lower_repositories"}}

    +

    {{.NumMembers}} {{$.locale.Tr "org.lower_members"}} · {{.NumRepos}} {{$.locale.Tr "org.lower_repositories"}}

    {{end}} @@ -48,10 +48,10 @@ diff --git a/templates/package/content/composer.tmpl b/templates/package/content/composer.tmpl index 29162f97b0..8cc18f8ba8 100644 --- a/templates/package/content/composer.tmpl +++ b/templates/package/content/composer.tmpl @@ -1,9 +1,9 @@ {{if eq .PackageDescriptor.Package.Type "composer"}} -

    {{.i18n.Tr "packages.installation"}}

    +

    {{.locale.Tr "packages.installation"}}

    - +
    {
     	"repositories": [{
     			"type": "composer",
    @@ -13,34 +13,34 @@
     }
    - +
    composer require {{.PackageDescriptor.Package.Name}}:{{.PackageDescriptor.Version.Version}}
    - +
    {{if .PackageDescriptor.Metadata.Description}} -

    {{.i18n.Tr "packages.about"}}

    +

    {{.locale.Tr "packages.about"}}

    {{.PackageDescriptor.Metadata.Description}}
    {{end}} {{if or .PackageDescriptor.Metadata.Require .PackageDescriptor.Metadata.RequireDev}} -

    {{.i18n.Tr "packages.dependencies"}}

    +

    {{.locale.Tr "packages.dependencies"}}

    - {{template "package/content/composer_dependencies" dict "root" $ "dependencies" .PackageDescriptor.Metadata.Require "title" (.i18n.Tr "packages.composer.dependencies")}} - {{template "package/content/composer_dependencies" dict "root" $ "dependencies" .PackageDescriptor.Metadata.RequireDev "title" (.i18n.Tr "packages.composer.dependencies.development")}} + {{template "package/content/composer_dependencies" dict "root" $ "dependencies" .PackageDescriptor.Metadata.Require "title" (.locale.Tr "packages.composer.dependencies")}} + {{template "package/content/composer_dependencies" dict "root" $ "dependencies" .PackageDescriptor.Metadata.RequireDev "title" (.locale.Tr "packages.composer.dependencies.development")}}
    {{end}} {{if or .PackageDescriptor.Metadata.Keywords}} -

    {{.i18n.Tr "packages.keywords"}}

    +

    {{.locale.Tr "packages.keywords"}}

    {{range .PackageDescriptor.Metadata.Keywords}} {{.}} diff --git a/templates/package/content/composer_dependencies.tmpl b/templates/package/content/composer_dependencies.tmpl index 1ab644f417..b55c1b5b88 100644 --- a/templates/package/content/composer_dependencies.tmpl +++ b/templates/package/content/composer_dependencies.tmpl @@ -3,8 +3,8 @@
    {{.i18n.Tr "units.unit"}}{{.i18n.Tr "org.team_permission_desc"}}{{.locale.Tr "units.unit"}}{{.locale.Tr "org.team_permission_desc"}}
    {{$.i18n.Tr $unit.NameKey}}{{$.locale.Tr $unit.NameKey}} {{if eq ($.Team.UnitAccessMode $unit.Type) 0 -}} - {{$.i18n.Tr "org.teams.none_access"}} + {{$.locale.Tr "org.teams.none_access"}} {{- else if or (eq $.Team.ID 0) (eq ($.Team.UnitAccessMode $unit.Type) 1) -}} - {{$.i18n.Tr "org.teams.read_access"}} + {{$.locale.Tr "org.teams.read_access"}} {{- else if eq ($.Team.UnitAccessMode $unit.Type) 2 -}} - {{$.i18n.Tr "org.teams.write_access"}} + {{$.locale.Tr "org.teams.write_access"}} {{- end}}
    - - + + diff --git a/templates/package/content/conan.tmpl b/templates/package/content/conan.tmpl index 3c1c35c00f..c496cee55c 100644 --- a/templates/package/content/conan.tmpl +++ b/templates/package/content/conan.tmpl @@ -1,30 +1,30 @@ {{if eq .PackageDescriptor.Package.Type "conan"}} -

    {{.i18n.Tr "packages.installation"}}

    +

    {{.locale.Tr "packages.installation"}}

    - +
    conan remote add gitea {{AppUrl}}api/packages/{{.PackageDescriptor.Owner.Name}}/conan
    - +
    conan install --remote=gitea {{.PackageDescriptor.Package.Name}}/{{.PackageDescriptor.Version.Version}}
    - +
    {{if .PackageDescriptor.Metadata.Description}} -

    {{.i18n.Tr "packages.about"}}

    +

    {{.locale.Tr "packages.about"}}

    {{if .PackageDescriptor.Metadata.Description}}{{.PackageDescriptor.Metadata.Description}}{{end}}
    {{end}} {{if or .PackageDescriptor.Metadata.Keywords}} -

    {{.i18n.Tr "packages.keywords"}}

    +

    {{.locale.Tr "packages.keywords"}}

    {{range .PackageDescriptor.Metadata.Keywords}} {{.}} diff --git a/templates/package/content/container.tmpl b/templates/package/content/container.tmpl index 14d4a56398..44a64d13ee 100644 --- a/templates/package/content/container.tmpl +++ b/templates/package/content/container.tmpl @@ -1,9 +1,9 @@ {{if eq .PackageDescriptor.Package.Type "container"}} -

    {{.i18n.Tr "packages.installation"}}

    +

    {{.locale.Tr "packages.installation"}}

    - + {{if eq .PackageDescriptor.Metadata.Type "helm"}}
    helm pull oci://{{.RegistryHost}}/{{.PackageDescriptor.Owner.LowerName}}/{{.PackageDescriptor.Package.LowerName}} --version {{.PackageDescriptor.Version.LowerVersion}}
    {{else}} @@ -15,12 +15,12 @@ {{end}}
    - +
    {{if .PackageDescriptor.Metadata.MultiArch}} -

    {{.i18n.Tr "packages.container.multi_arch"}}

    +

    {{.locale.Tr "packages.container.multi_arch"}}

    {{range $arch, $digest := .PackageDescriptor.Metadata.MultiArch}} @@ -35,13 +35,13 @@
    {{end}} {{if .PackageDescriptor.Metadata.Description}} -

    {{.i18n.Tr "packages.about"}}

    +

    {{.locale.Tr "packages.about"}}

    {{.PackageDescriptor.Metadata.Description}}
    {{end}} {{if .PackageDescriptor.Metadata.ImageLayers}} -

    {{.i18n.Tr "packages.container.layers"}}

    +

    {{.locale.Tr "packages.container.layers"}}

    {{.root.i18n.Tr "packages.dependency.id"}}{{.root.i18n.Tr "packages.dependency.version"}}{{.root.locale.Tr "packages.dependency.id"}}{{.root.locale.Tr "packages.dependency.version"}}
    @@ -55,13 +55,13 @@ {{end}} {{if .PackageDescriptor.Metadata.Labels}} -

    {{.i18n.Tr "packages.container.labels"}}

    +

    {{.locale.Tr "packages.container.labels"}}

    - - + + diff --git a/templates/package/content/generic.tmpl b/templates/package/content/generic.tmpl index 05a47b3ef4..045ff7d08a 100644 --- a/templates/package/content/generic.tmpl +++ b/templates/package/content/generic.tmpl @@ -1,13 +1,13 @@ {{if eq .PackageDescriptor.Package.Type "generic"}} -

    {{.i18n.Tr "packages.installation"}}

    +

    {{.locale.Tr "packages.installation"}}

    - +
    curl {{AppUrl}}api/packages/{{.PackageDescriptor.Owner.Name}}/generic/{{.PackageDescriptor.Package.Name}}/{{.PackageDescriptor.Version.Version}}/{{(index .PackageDescriptor.Files 0).File.Name}}
    - +
    diff --git a/templates/package/content/helm.tmpl b/templates/package/content/helm.tmpl index a85f7c4850..59cdc157b4 100644 --- a/templates/package/content/helm.tmpl +++ b/templates/package/content/helm.tmpl @@ -1,37 +1,37 @@ {{if eq .PackageDescriptor.Package.Type "helm"}} -

    {{.i18n.Tr "packages.installation"}}

    +

    {{.locale.Tr "packages.installation"}}

    - +
    helm repo add gitea {{AppUrl}}api/packages/{{.PackageDescriptor.Owner.Name}}/helm
     helm repo update
    - +
    helm install {{.PackageDescriptor.Package.Name}} gitea/{{.PackageDescriptor.Package.Name}}
    - +
    {{if .PackageDescriptor.Metadata.Description}} -

    {{.i18n.Tr "packages.about"}}

    +

    {{.locale.Tr "packages.about"}}

    {{.PackageDescriptor.Metadata.Description}}
    {{end}} {{if .PackageDescriptor.Metadata.Dependencies}} -

    {{.i18n.Tr "packages.dependencies"}}

    +

    {{.locale.Tr "packages.dependencies"}}

    {{.i18n.Tr "packages.container.labels.key"}}{{.i18n.Tr "packages.container.labels.value"}}{{.locale.Tr "packages.container.labels.key"}}{{.locale.Tr "packages.container.labels.value"}}
    - - + + @@ -47,7 +47,7 @@ helm repo update {{end}} {{if .PackageDescriptor.Metadata.Keywords}} -

    {{.i18n.Tr "packages.keywords"}}

    +

    {{.locale.Tr "packages.keywords"}}

    {{range .PackageDescriptor.Metadata.Keywords}} {{.}} diff --git a/templates/package/content/maven.tmpl b/templates/package/content/maven.tmpl index 32b89616cb..0b5612151c 100644 --- a/templates/package/content/maven.tmpl +++ b/templates/package/content/maven.tmpl @@ -1,9 +1,9 @@ {{if eq .PackageDescriptor.Package.Type "maven"}} -

    {{.i18n.Tr "packages.installation"}}

    +

    {{.locale.Tr "packages.installation"}}

    - +
    <repositories>
     	<repository>
     		<id>gitea</id>
    @@ -24,7 +24,7 @@
     </distributionManagement>
    - +
    <dependency>
     	<groupId>{{.PackageDescriptor.Metadata.GroupID}}</groupId>
     	<artifactId>{{.PackageDescriptor.Metadata.ArtifactID}}</artifactId>
    @@ -32,28 +32,28 @@
     </dependency>
    - +
    mvn install
    - +
    mvn dependency:get -DremoteRepositories={{AppUrl}}api/packages/{{.PackageDescriptor.Owner.Name}}/maven -Dartifact={{.PackageDescriptor.Metadata.GroupID}}:{{.PackageDescriptor.Metadata.ArtifactID}}:{{.PackageDescriptor.Version.Version}}
    - +
    {{if .PackageDescriptor.Metadata.Description}} -

    {{.i18n.Tr "packages.about"}}

    +

    {{.locale.Tr "packages.about"}}

    {{.PackageDescriptor.Metadata.Description}}
    {{end}} {{if .PackageDescriptor.Metadata.Dependencies}} -

    {{.i18n.Tr "packages.dependencies"}}

    +

    {{.locale.Tr "packages.dependencies"}}

    {{range .PackageDescriptor.Metadata.Dependencies}} diff --git a/templates/package/content/npm.tmpl b/templates/package/content/npm.tmpl index bc714e5c97..33d51d4dfd 100644 --- a/templates/package/content/npm.tmpl +++ b/templates/package/content/npm.tmpl @@ -1,27 +1,27 @@ {{if eq .PackageDescriptor.Package.Type "npm"}} -

    {{.i18n.Tr "packages.installation"}}

    +

    {{.locale.Tr "packages.installation"}}

    - +
    {{if .PackageDescriptor.Metadata.Scope}}{{.PackageDescriptor.Metadata.Scope}}:{{end}}registry={{AppUrl}}api/packages/{{.PackageDescriptor.Owner.Name}}/npm/
    - +
    npm install {{.PackageDescriptor.Package.Name}}@{{.PackageDescriptor.Version.Version}}
    - +
    "{{.PackageDescriptor.Package.Name}}": "{{.PackageDescriptor.Version.Version}}"
    - +
    {{if or .PackageDescriptor.Metadata.Description .PackageDescriptor.Metadata.Readme}} -

    {{.i18n.Tr "packages.about"}}

    +

    {{.locale.Tr "packages.about"}}

    {{if .PackageDescriptor.Metadata.Readme}}
    @@ -34,19 +34,19 @@ {{end}} {{if or .PackageDescriptor.Metadata.Dependencies .PackageDescriptor.Metadata.DevelopmentDependencies .PackageDescriptor.Metadata.PeerDependencies .PackageDescriptor.Metadata.OptionalDependencies}} -

    {{.i18n.Tr "packages.dependencies"}}

    +

    {{.locale.Tr "packages.dependencies"}}

    - {{template "package/content/npm_dependencies" dict "root" $ "dependencies" .PackageDescriptor.Metadata.Dependencies "title" (.i18n.Tr "packages.npm.dependencies")}} - {{template "package/content/npm_dependencies" dict "root" $ "dependencies" .PackageDescriptor.Metadata.DevelopmentDependencies "title" (.i18n.Tr "packages.npm.dependencies.development")}} - {{template "package/content/npm_dependencies" dict "root" $ "dependencies" .PackageDescriptor.Metadata.PeerDependencies "title" (.i18n.Tr "packages.npm.dependencies.peer")}} - {{template "package/content/npm_dependencies" dict "root" $ "dependencies" .PackageDescriptor.Metadata.OptionalDependencies "title" (.i18n.Tr "packages.npm.dependencies.optional")}} + {{template "package/content/npm_dependencies" dict "root" $ "dependencies" .PackageDescriptor.Metadata.Dependencies "title" (.locale.Tr "packages.npm.dependencies")}} + {{template "package/content/npm_dependencies" dict "root" $ "dependencies" .PackageDescriptor.Metadata.DevelopmentDependencies "title" (.locale.Tr "packages.npm.dependencies.development")}} + {{template "package/content/npm_dependencies" dict "root" $ "dependencies" .PackageDescriptor.Metadata.PeerDependencies "title" (.locale.Tr "packages.npm.dependencies.peer")}} + {{template "package/content/npm_dependencies" dict "root" $ "dependencies" .PackageDescriptor.Metadata.OptionalDependencies "title" (.locale.Tr "packages.npm.dependencies.optional")}}
    {{end}} {{if .PackageDescriptor.Metadata.Keywords}} -

    {{.i18n.Tr "packages.keywords"}}

    +

    {{.locale.Tr "packages.keywords"}}

    {{range .PackageDescriptor.Metadata.Keywords}} {{.}} diff --git a/templates/package/content/npm_dependencies.tmpl b/templates/package/content/npm_dependencies.tmpl index 1ab644f417..b55c1b5b88 100644 --- a/templates/package/content/npm_dependencies.tmpl +++ b/templates/package/content/npm_dependencies.tmpl @@ -3,8 +3,8 @@
    {{.i18n.Tr "packages.dependency.id"}}{{.i18n.Tr "packages.dependency.version"}}{{.locale.Tr "packages.dependency.id"}}{{.locale.Tr "packages.dependency.version"}}
    - - + + diff --git a/templates/package/content/nuget.tmpl b/templates/package/content/nuget.tmpl index 879d7d0176..4ea41fa826 100644 --- a/templates/package/content/nuget.tmpl +++ b/templates/package/content/nuget.tmpl @@ -1,23 +1,23 @@ {{if eq .PackageDescriptor.Package.Type "nuget"}} -

    {{.i18n.Tr "packages.installation"}}

    +

    {{.locale.Tr "packages.installation"}}

    - +
    dotnet nuget add source --name Gitea --username your_username --password your_token {{AppUrl}}api/packages/{{.PackageDescriptor.Owner.Name}}/nuget/index.json
    - +
    dotnet add package --source Gitea --version {{.PackageDescriptor.Version.Version}} {{.PackageDescriptor.Package.Name}}
    - +
    {{if or .PackageDescriptor.Metadata.Description .PackageDescriptor.Metadata.ReleaseNotes}} -

    {{.i18n.Tr "packages.about"}}

    +

    {{.locale.Tr "packages.about"}}

    {{if .PackageDescriptor.Metadata.Description}}{{.PackageDescriptor.Metadata.Description}}{{end}} {{if .PackageDescriptor.Metadata.ReleaseNotes}}{{Str2html .PackageDescriptor.Metadata.ReleaseNotes}}{{end}} @@ -25,14 +25,14 @@ {{end}} {{if .PackageDescriptor.Metadata.Dependencies}} -

    {{.i18n.Tr "packages.dependencies"}}

    +

    {{.locale.Tr "packages.dependencies"}}

    {{.root.i18n.Tr "packages.dependency.id"}}{{.root.i18n.Tr "packages.dependency.version"}}{{.root.locale.Tr "packages.dependency.id"}}{{.root.locale.Tr "packages.dependency.version"}}
    - - - + + + diff --git a/templates/package/content/pypi.tmpl b/templates/package/content/pypi.tmpl index 352f4f617f..1cce31f537 100644 --- a/templates/package/content/pypi.tmpl +++ b/templates/package/content/pypi.tmpl @@ -1,18 +1,18 @@ {{if eq .PackageDescriptor.Package.Type "pypi"}} -

    {{.i18n.Tr "packages.installation"}}

    +

    {{.locale.Tr "packages.installation"}}

    - +
    pip install --extra-index-url {{AppUrl}}api/packages/{{.PackageDescriptor.Owner.Name}}/pypi/simple {{.PackageDescriptor.Package.Name}}
    - +
    {{if or .PackageDescriptor.Metadata.Description .PackageDescriptor.Metadata.LongDescription .PackageDescriptor.Metadata.Summary}} -

    {{.i18n.Tr "packages.about"}}

    +

    {{.locale.Tr "packages.about"}}

    {{if .PackageDescriptor.Metadata.Summary}}{{.PackageDescriptor.Metadata.Summary}}{{end}}

    {{if .PackageDescriptor.Metadata.LongDescription}} @@ -23,9 +23,9 @@
    {{end}} {{if .PackageDescriptor.Metadata.RequiresPython}} -

    {{.i18n.Tr "packages.requirements"}}

    +

    {{.locale.Tr "packages.requirements"}}

    - {{.i18n.Tr "packages.pypi.requires"}}: {{.PackageDescriptor.Metadata.RequiresPython}} + {{.locale.Tr "packages.pypi.requires"}}: {{.PackageDescriptor.Metadata.RequiresPython}}
    {{end}} {{end}} diff --git a/templates/package/content/rubygems.tmpl b/templates/package/content/rubygems.tmpl index 6e22d7fbea..0cb7b670b1 100644 --- a/templates/package/content/rubygems.tmpl +++ b/templates/package/content/rubygems.tmpl @@ -1,39 +1,39 @@ {{if eq .PackageDescriptor.Package.Type "rubygems"}} -

    {{.i18n.Tr "packages.installation"}}

    +

    {{.locale.Tr "packages.installation"}}

    - +
    gem install {{.PackageDescriptor.Package.Name}} --version "{{.PackageDescriptor.Version.Version}}" --source "{{AppUrl}}api/packages/{{.PackageDescriptor.Owner.Name}}/rubygems"
    - +
    source "{{AppUrl}}api/packages/{{.PackageDescriptor.Owner.Name}}/rubygems" do
     	gem "{{.PackageDescriptor.Package.Name}}", "{{.PackageDescriptor.Version.Version}}"
     end
    - +
    {{if .PackageDescriptor.Metadata.Description}} -

    {{.i18n.Tr "packages.about"}}

    +

    {{.locale.Tr "packages.about"}}

    {{.PackageDescriptor.Metadata.Description}}
    {{end}} {{if or .PackageDescriptor.Metadata.RequiredRubyVersion .PackageDescriptor.Metadata.RequiredRubygemsVersion}} -

    {{.i18n.Tr "packages.requirements"}}

    +

    {{.locale.Tr "packages.requirements"}}

    - {{if .PackageDescriptor.Metadata.RequiredRubyVersion}}

    {{.i18n.Tr "packages.rubygems.required.ruby"}}: {{range $i, $v := .PackageDescriptor.Metadata.RequiredRubyVersion}}{{if gt $i 0}}, {{end}}{{$v.Restriction}}{{$v.Version}}{{end}}

    {{end}} - {{if .PackageDescriptor.Metadata.RequiredRubygemsVersion}}

    {{.i18n.Tr "packages.rubygems.required.rubygems"}}: {{range $i, $v := .PackageDescriptor.Metadata.RequiredRubygemsVersion}}{{if gt $i 0}}, {{end}}{{$v.Restriction}}{{$v.Version}}{{end}}

    {{end}} + {{if .PackageDescriptor.Metadata.RequiredRubyVersion}}

    {{.locale.Tr "packages.rubygems.required.ruby"}}: {{range $i, $v := .PackageDescriptor.Metadata.RequiredRubyVersion}}{{if gt $i 0}}, {{end}}{{$v.Restriction}}{{$v.Version}}{{end}}

    {{end}} + {{if .PackageDescriptor.Metadata.RequiredRubygemsVersion}}

    {{.locale.Tr "packages.rubygems.required.rubygems"}}: {{range $i, $v := .PackageDescriptor.Metadata.RequiredRubygemsVersion}}{{if gt $i 0}}, {{end}}{{$v.Restriction}}{{$v.Version}}{{end}}

    {{end}}
    {{end}} {{if or .PackageDescriptor.Metadata.RuntimeDependencies .PackageDescriptor.Metadata.DevelopmentDependencies}} -

    {{.i18n.Tr "packages.dependencies"}}

    +

    {{.locale.Tr "packages.dependencies"}}

    - {{template "package/content/rubygems_dependencies" dict "root" $ "dependencies" .PackageDescriptor.Metadata.RuntimeDependencies "title" (.i18n.Tr "packages.rubygems.dependencies.runtime")}} - {{template "package/content/rubygems_dependencies" dict "root" $ "dependencies" .PackageDescriptor.Metadata.DevelopmentDependencies "title" (.i18n.Tr "packages.rubygems.dependencies.development")}} + {{template "package/content/rubygems_dependencies" dict "root" $ "dependencies" .PackageDescriptor.Metadata.RuntimeDependencies "title" (.locale.Tr "packages.rubygems.dependencies.runtime")}} + {{template "package/content/rubygems_dependencies" dict "root" $ "dependencies" .PackageDescriptor.Metadata.DevelopmentDependencies "title" (.locale.Tr "packages.rubygems.dependencies.development")}}
    {{end}} diff --git a/templates/package/content/rubygems_dependencies.tmpl b/templates/package/content/rubygems_dependencies.tmpl index 79f66ad3f9..80febc84f4 100644 --- a/templates/package/content/rubygems_dependencies.tmpl +++ b/templates/package/content/rubygems_dependencies.tmpl @@ -3,8 +3,8 @@
    {{.i18n.Tr "packages.dependency.id"}}{{.i18n.Tr "packages.dependency.version"}}{{.i18n.Tr "packages.nuget.dependency.framework"}}{{.locale.Tr "packages.dependency.id"}}{{.locale.Tr "packages.dependency.version"}}{{.locale.Tr "packages.nuget.dependency.framework"}}
    - - + + diff --git a/templates/package/metadata/composer.tmpl b/templates/package/metadata/composer.tmpl index 1178d00e0d..2e76a10dab 100644 --- a/templates/package/metadata/composer.tmpl +++ b/templates/package/metadata/composer.tmpl @@ -1,5 +1,5 @@ {{if eq .PackageDescriptor.Package.Type "composer"}} - {{range .PackageDescriptor.Metadata.Authors}}
    {{svg "octicon-person" 16 "mr-3"}} {{.Name}}
    {{end}} - {{if .PackageDescriptor.Metadata.Homepage}}
    {{svg "octicon-link-external" 16 "mr-3"}} {{.i18n.Tr "packages.details.project_site"}}
    {{end}} - {{range .PackageDescriptor.Metadata.License}}
    {{svg "octicon-law" 16 "mr-3"}} {{.}}
    {{end}} + {{range .PackageDescriptor.Metadata.Authors}}
    {{svg "octicon-person" 16 "mr-3"}} {{.Name}}
    {{end}} + {{if .PackageDescriptor.Metadata.Homepage}}
    {{svg "octicon-link-external" 16 "mr-3"}} {{.locale.Tr "packages.details.project_site"}}
    {{end}} + {{range .PackageDescriptor.Metadata.License}}
    {{svg "octicon-law" 16 "mr-3"}} {{.}}
    {{end}} {{end}} diff --git a/templates/package/metadata/conan.tmpl b/templates/package/metadata/conan.tmpl index 1ef82aea4e..41cb42b692 100644 --- a/templates/package/metadata/conan.tmpl +++ b/templates/package/metadata/conan.tmpl @@ -1,6 +1,6 @@ {{if eq .PackageDescriptor.Package.Type "conan"}} - {{if .PackageDescriptor.Metadata.Author}}
    {{svg "octicon-person" 16 "mr-3"}} {{.PackageDescriptor.Metadata.Author}}
    {{end}} - {{if .PackageDescriptor.Metadata.ProjectURL}}
    {{svg "octicon-link-external" 16 "mr-3"}} {{.i18n.Tr "packages.details.project_site"}}
    {{end}} - {{if .PackageDescriptor.Metadata.License}}
    {{svg "octicon-law" 16 "mr-3"}} {{.PackageDescriptor.Metadata.License}}
    {{end}} - {{if .PackageDescriptor.Metadata.RepositoryURL}}
    {{svg "octicon-link-external" 16 "mr-3"}} {{.i18n.Tr "packages.conan.details.repository"}}
    {{end}} + {{if .PackageDescriptor.Metadata.Author}}
    {{svg "octicon-person" 16 "mr-3"}} {{.PackageDescriptor.Metadata.Author}}
    {{end}} + {{if .PackageDescriptor.Metadata.ProjectURL}}
    {{svg "octicon-link-external" 16 "mr-3"}} {{.locale.Tr "packages.details.project_site"}}
    {{end}} + {{if .PackageDescriptor.Metadata.License}}
    {{svg "octicon-law" 16 "mr-3"}} {{.PackageDescriptor.Metadata.License}}
    {{end}} + {{if .PackageDescriptor.Metadata.RepositoryURL}}
    {{svg "octicon-link-external" 16 "mr-3"}} {{.locale.Tr "packages.conan.details.repository"}}
    {{end}} {{end}} diff --git a/templates/package/metadata/container.tmpl b/templates/package/metadata/container.tmpl index 117d7e46a2..1b13072c38 100644 --- a/templates/package/metadata/container.tmpl +++ b/templates/package/metadata/container.tmpl @@ -1,9 +1,9 @@ {{if eq .PackageDescriptor.Package.Type "container"}} -
    {{svg "octicon-package" 16 "mr-3"}} {{.PackageDescriptor.Metadata.Type.Name}}
    - {{if .PackageDescriptor.Metadata.Platform}}
    {{svg "octicon-cpu" 16 "mr-3"}} {{.PackageDescriptor.Metadata.Platform}}
    {{end}} - {{range .PackageDescriptor.Metadata.Authors}}
    {{svg "octicon-person" 16 "mr-3"}} {{.}}
    {{end}} +
    {{svg "octicon-package" 16 "mr-3"}} {{.PackageDescriptor.Metadata.Type.Name}}
    + {{if .PackageDescriptor.Metadata.Platform}}
    {{svg "octicon-cpu" 16 "mr-3"}} {{.PackageDescriptor.Metadata.Platform}}
    {{end}} + {{range .PackageDescriptor.Metadata.Authors}}
    {{svg "octicon-person" 16 "mr-3"}} {{.}}
    {{end}} {{if .PackageDescriptor.Metadata.Licenses}}
    {{svg "octicon-law" 16 "mr-3"}} {{.PackageDescriptor.Metadata.Licenses}}
    {{end}} - {{if .PackageDescriptor.Metadata.ProjectURL}}
    {{svg "octicon-link-external" 16 "mr-3"}} {{.i18n.Tr "packages.details.project_site"}}
    {{end}} - {{if .PackageDescriptor.Metadata.RepositoryURL}}
    {{svg "octicon-link-external" 16 "mr-3"}} {{.i18n.Tr "packages.container.details.repository_site"}}
    {{end}} - {{if .PackageDescriptor.Metadata.DocumentationURL}}
    {{svg "octicon-link-external" 16 "mr-3"}} {{.i18n.Tr "packages.container.details.documentation_site"}}
    {{end}} + {{if .PackageDescriptor.Metadata.ProjectURL}}
    {{svg "octicon-link-external" 16 "mr-3"}} {{.locale.Tr "packages.details.project_site"}}
    {{end}} + {{if .PackageDescriptor.Metadata.RepositoryURL}}
    {{svg "octicon-link-external" 16 "mr-3"}} {{.locale.Tr "packages.container.details.repository_site"}}
    {{end}} + {{if .PackageDescriptor.Metadata.DocumentationURL}}
    {{svg "octicon-link-external" 16 "mr-3"}} {{.locale.Tr "packages.container.details.documentation_site"}}
    {{end}} {{end}} diff --git a/templates/package/metadata/helm.tmpl b/templates/package/metadata/helm.tmpl index 7c97c6358e..9f7f5d6ecd 100644 --- a/templates/package/metadata/helm.tmpl +++ b/templates/package/metadata/helm.tmpl @@ -1,4 +1,4 @@ {{if eq .PackageDescriptor.Package.Type "helm"}} - {{range .PackageDescriptor.Metadata.Maintainers}}
    {{svg "octicon-person" 16 "mr-3"}} {{.Name}}
    {{end}} - {{if .PackageDescriptor.Metadata.Home}}
    {{svg "octicon-link-external" 16 "mr-3"}} {{.i18n.Tr "packages.details.project_site"}}
    {{end}} + {{range .PackageDescriptor.Metadata.Maintainers}}
    {{svg "octicon-person" 16 "mr-3"}} {{.Name}}
    {{end}} + {{if .PackageDescriptor.Metadata.Home}}
    {{svg "octicon-link-external" 16 "mr-3"}} {{.locale.Tr "packages.details.project_site"}}
    {{end}} {{end}} diff --git a/templates/package/metadata/maven.tmpl b/templates/package/metadata/maven.tmpl index 14a613be47..f6fcdf6da8 100644 --- a/templates/package/metadata/maven.tmpl +++ b/templates/package/metadata/maven.tmpl @@ -1,5 +1,5 @@ {{if eq .PackageDescriptor.Package.Type "maven"}} {{if .PackageDescriptor.Metadata.Name}}
    {{svg "octicon-note" 16 "mr-3"}} {{.PackageDescriptor.Metadata.Name}}
    {{end}} - {{if .PackageDescriptor.Metadata.ProjectURL}}
    {{svg "octicon-link-external" 16 "mr-3"}} {{.i18n.Tr "packages.details.project_site"}}
    {{end}} - {{range .PackageDescriptor.Metadata.Licenses}}
    {{svg "octicon-law" 16 "mr-3"}} {{.}}
    {{end}} + {{if .PackageDescriptor.Metadata.ProjectURL}}
    {{svg "octicon-link-external" 16 "mr-3"}} {{.locale.Tr "packages.details.project_site"}}
    {{end}} + {{range .PackageDescriptor.Metadata.Licenses}}
    {{svg "octicon-law" 16 "mr-3"}} {{.}}
    {{end}} {{end}} diff --git a/templates/package/metadata/npm.tmpl b/templates/package/metadata/npm.tmpl index 3279f9edbf..765566cadf 100644 --- a/templates/package/metadata/npm.tmpl +++ b/templates/package/metadata/npm.tmpl @@ -1,8 +1,8 @@ {{if eq .PackageDescriptor.Package.Type "npm"}} - {{if .PackageDescriptor.Metadata.Author}}
    {{svg "octicon-person" 16 "mr-3"}} {{.PackageDescriptor.Metadata.Author}}
    {{end}} - {{if .PackageDescriptor.Metadata.ProjectURL}}
    {{svg "octicon-link-external" 16 "mr-3"}} {{.i18n.Tr "packages.details.project_site"}}
    {{end}} - {{if .PackageDescriptor.Metadata.License}}
    {{svg "octicon-law" 16 "mr-3"}} {{.PackageDescriptor.Metadata.License}}
    {{end}} + {{if .PackageDescriptor.Metadata.Author}}
    {{svg "octicon-person" 16 "mr-3"}} {{.PackageDescriptor.Metadata.Author}}
    {{end}} + {{if .PackageDescriptor.Metadata.ProjectURL}}
    {{svg "octicon-link-external" 16 "mr-3"}} {{.locale.Tr "packages.details.project_site"}}
    {{end}} + {{if .PackageDescriptor.Metadata.License}}
    {{svg "octicon-law" 16 "mr-3"}} {{.PackageDescriptor.Metadata.License}}
    {{end}} {{range .PackageDescriptor.Properties}} - {{if eq .Name "npm.tag"}}
    {{svg "octicon-versions" 16 "mr-3"}} {{.Value}}
    {{end}} + {{if eq .Name "npm.tag"}}
    {{svg "octicon-versions" 16 "mr-3"}} {{.Value}}
    {{end}} {{end}} {{end}} diff --git a/templates/package/metadata/nuget.tmpl b/templates/package/metadata/nuget.tmpl index d5a3e909b9..b4e62b5a08 100644 --- a/templates/package/metadata/nuget.tmpl +++ b/templates/package/metadata/nuget.tmpl @@ -1,4 +1,4 @@ {{if eq .PackageDescriptor.Package.Type "nuget"}} - {{if .PackageDescriptor.Metadata.Authors}}
    {{svg "octicon-person" 16 "mr-3"}} {{.PackageDescriptor.Metadata.Authors}}
    {{end}} - {{if .PackageDescriptor.Metadata.ProjectURL}}
    {{svg "octicon-link-external" 16 "mr-3"}} {{.i18n.Tr "packages.details.project_site"}}
    {{end}} + {{if .PackageDescriptor.Metadata.Authors}}
    {{svg "octicon-person" 16 "mr-3"}} {{.PackageDescriptor.Metadata.Authors}}
    {{end}} + {{if .PackageDescriptor.Metadata.ProjectURL}}
    {{svg "octicon-link-external" 16 "mr-3"}} {{.locale.Tr "packages.details.project_site"}}
    {{end}} {{end}} diff --git a/templates/package/metadata/pypi.tmpl b/templates/package/metadata/pypi.tmpl index 5cdfbdfe66..13b53d3591 100644 --- a/templates/package/metadata/pypi.tmpl +++ b/templates/package/metadata/pypi.tmpl @@ -1,5 +1,5 @@ {{if eq .PackageDescriptor.Package.Type "pypi"}} - {{if .PackageDescriptor.Metadata.Author}}
    {{svg "octicon-person" 16 "mr-3"}} {{.PackageDescriptor.Metadata.Author}}
    {{end}} - {{if .PackageDescriptor.Metadata.ProjectURL}}
    {{svg "octicon-link-external" 16 "mr-3"}} {{.i18n.Tr "packages.details.project_site"}}
    {{end}} - {{if .PackageDescriptor.Metadata.License}}
    {{svg "octicon-law" 16 "mr-3"}} {{.PackageDescriptor.Metadata.License}}
    {{end}} + {{if .PackageDescriptor.Metadata.Author}}
    {{svg "octicon-person" 16 "mr-3"}} {{.PackageDescriptor.Metadata.Author}}
    {{end}} + {{if .PackageDescriptor.Metadata.ProjectURL}}
    {{svg "octicon-link-external" 16 "mr-3"}} {{.locale.Tr "packages.details.project_site"}}
    {{end}} + {{if .PackageDescriptor.Metadata.License}}
    {{svg "octicon-law" 16 "mr-3"}} {{.PackageDescriptor.Metadata.License}}
    {{end}} {{end}} diff --git a/templates/package/metadata/rubygems.tmpl b/templates/package/metadata/rubygems.tmpl index dff6830df3..bddb7b5422 100644 --- a/templates/package/metadata/rubygems.tmpl +++ b/templates/package/metadata/rubygems.tmpl @@ -1,5 +1,5 @@ {{if eq .PackageDescriptor.Package.Type "rubygems"}} - {{range .PackageDescriptor.Metadata.Authors}}
    {{svg "octicon-person" 16 "mr-3"}} {{.}}
    {{end}} - {{if .PackageDescriptor.Metadata.ProjectURL}}
    {{svg "octicon-link-external" 16 "mr-3"}} {{.i18n.Tr "packages.details.project_site"}}
    {{end}} - {{range .PackageDescriptor.Metadata.Licenses}}
    {{svg "octicon-law" 16 "mr-3"}} {{.}}
    {{end}} + {{range .PackageDescriptor.Metadata.Authors}}
    {{svg "octicon-person" 16 "mr-3"}} {{.}}
    {{end}} + {{if .PackageDescriptor.Metadata.ProjectURL}}
    {{svg "octicon-link-external" 16 "mr-3"}} {{.locale.Tr "packages.details.project_site"}}
    {{end}} + {{range .PackageDescriptor.Metadata.Licenses}}
    {{svg "octicon-law" 16 "mr-3"}} {{.}}
    {{end}} {{end}} diff --git a/templates/package/settings.tmpl b/templates/package/settings.tmpl index bf2d1d4912..5f045e98b0 100644 --- a/templates/package/settings.tmpl +++ b/templates/package/settings.tmpl @@ -3,12 +3,12 @@ {{template "user/overview/header" .}}
    {{template "base/alert" .}} -

    {{.PackageDescriptor.Package.Name}} ({{.PackageDescriptor.Version.Version}}) / {{.i18n.Tr "repo.settings"}}

    +

    {{.PackageDescriptor.Package.Name}} ({{.PackageDescriptor.Version.Version}}) / {{.locale.Tr "repo.settings"}}

    - {{.i18n.Tr "packages.settings.link"}} + {{.locale.Tr "packages.settings.link"}}

    -

    {{.i18n.Tr "packages.settings.link.description"}}

    +

    {{.locale.Tr "packages.settings.link.description"}}

    {{template "base/disable_form_autofill"}} {{.CsrfTokenHtml}} @@ -21,7 +21,7 @@ {{end}} -
    {{.i18n.Tr "packages.settings.link.select"}}
    +
    {{.locale.Tr "packages.settings.link.select"}}
    - +

    - {{.i18n.Tr "repo.settings.danger_zone"}} + {{.locale.Tr "repo.settings.danger_zone"}}

    - +
    -
    {{.i18n.Tr "packages.settings.delete"}}
    -

    {{.i18n.Tr "packages.settings.delete.description"}}

    +
    {{.locale.Tr "packages.settings.delete"}}
    +

    {{.locale.Tr "packages.settings.delete.description"}}

    @@ -46,11 +46,11 @@ {{if not .HasPackages}}
    {{svg "octicon-package" 32}} -

    {{.i18n.Tr "packages.empty"}}

    -

    {{.i18n.Tr "packages.empty.documentation" | Safe}}

    +

    {{.locale.Tr "packages.empty"}}

    +

    {{.locale.Tr "packages.empty.documentation" | Safe}}

    {{else}} -

    {{.i18n.Tr "packages.filter.no_result"}}

    +

    {{.locale.Tr "packages.filter.no_result"}}

    {{end}} {{end}} {{template "base/paginate" .}} diff --git a/templates/package/shared/versionlist.tmpl b/templates/package/shared/versionlist.tmpl index 59f7cd1647..02bda3fb8f 100644 --- a/templates/package/shared/versionlist.tmpl +++ b/templates/package/shared/versionlist.tmpl @@ -1,16 +1,16 @@
    -

    {{.PackageDescriptor.Package.Name}} / {{.i18n.Tr "packages.versions"}}

    +

    {{.PackageDescriptor.Package.Name}} / {{.locale.Tr "packages.versions"}}

    - + {{if eq .PackageDescriptor.Package.Type "container"}} {{end}} - +
    @@ -21,12 +21,12 @@ {{.Version.LowerVersion}}
    - {{$.i18n.Tr "packages.published_by" (TimeSinceUnix .Version.CreatedUnix $.i18n.Lang) .Creator.HomeLink (.Creator.GetDisplayName | Escape) | Safe}} + {{$.locale.Tr "packages.published_by" (TimeSinceUnix .Version.CreatedUnix $.locale) .Creator.HomeLink (.Creator.GetDisplayName | Escape) | Safe}}
    {{else}} -

    {{.i18n.Tr "packages.filter.no_result"}}

    +

    {{.locale.Tr "packages.filter.no_result"}}

    {{end}} {{template "base/paginate" .}}
    diff --git a/templates/package/view.tmpl b/templates/package/view.tmpl index efad9f9b8f..ba309b6a77 100644 --- a/templates/package/view.tmpl +++ b/templates/package/view.tmpl @@ -9,11 +9,11 @@

    {{.PackageDescriptor.Package.Name}} ({{.PackageDescriptor.Version.Version}})

    - {{$timeStr := TimeSinceUnix .PackageDescriptor.Version.CreatedUnix $.i18n.Lang}} + {{$timeStr := TimeSinceUnix .PackageDescriptor.Version.CreatedUnix $.locale}} {{if .HasRepositoryAccess}} - {{.i18n.Tr "packages.published_by_in" $timeStr .PackageDescriptor.Creator.HomeLink (.PackageDescriptor.Creator.GetDisplayName | Escape) .PackageDescriptor.Repository.HTMLURL (.PackageDescriptor.Repository.FullName | Escape) | Safe}} + {{.locale.Tr "packages.published_by_in" $timeStr .PackageDescriptor.Creator.HomeLink (.PackageDescriptor.Creator.GetDisplayName | Escape) .PackageDescriptor.Repository.HTMLURL (.PackageDescriptor.Repository.FullName | Escape) | Safe}} {{else}} - {{.i18n.Tr "packages.published_by" $timeStr .PackageDescriptor.Creator.HomeLink (.PackageDescriptor.Creator.GetDisplayName | Escape) | Safe}} + {{.locale.Tr "packages.published_by" $timeStr .PackageDescriptor.Creator.HomeLink (.PackageDescriptor.Creator.GetDisplayName | Escape) | Safe}} {{end}}
    @@ -32,7 +32,7 @@
    - {{.i18n.Tr "packages.details"}} + {{.locale.Tr "packages.details"}}
    {{svg .PackageDescriptor.Package.Type.SVGName 16 "mr-3"}} {{.PackageDescriptor.Package.Type.Name}}
    {{if .HasRepositoryAccess}} @@ -53,7 +53,7 @@
    {{if not (eq .PackageDescriptor.Package.Type "container")}}
    - {{.i18n.Tr "packages.assets"}} ({{len .PackageDescriptor.Files}}) + {{.locale.Tr "packages.assets"}} ({{len .PackageDescriptor.Files}})
    {{range .PackageDescriptor.Files}}
    @@ -65,13 +65,13 @@ {{end}} {{if .LatestVersions}}
    - {{.i18n.Tr "packages.versions"}} ({{.TotalVersionCount}}) - {{.i18n.Tr "packages.versions.view_all"}} + {{.locale.Tr "packages.versions"}} ({{.TotalVersionCount}}) + {{.locale.Tr "packages.versions.view_all"}}
    {{range .LatestVersions}}
    {{.Version}} - {{$.i18n.Tr "packages.versions.on"}} {{.CreatedUnix.FormatDate}} + {{$.locale.Tr "packages.versions.on"}} {{.CreatedUnix.FormatDate}}
    {{end}}
    @@ -80,10 +80,10 @@
    {{if .HasRepositoryAccess}} -
    {{svg "octicon-issue-opened" 16 "mr-3"}} {{.i18n.Tr "repo.issues"}}
    +
    {{svg "octicon-issue-opened" 16 "mr-3"}} {{.locale.Tr "repo.issues"}}
    {{end}} {{if .CanWritePackages}} -
    {{svg "octicon-tools" 16 "mr-3"}} {{.i18n.Tr "repo.settings"}}
    +
    {{svg "octicon-tools" 16 "mr-3"}} {{.locale.Tr "repo.settings"}}
    {{end}}
    {{end}} diff --git a/templates/repo/activity.tmpl b/templates/repo/activity.tmpl index 36108dddcb..37cdf3ef02 100644 --- a/templates/repo/activity.tmpl +++ b/templates/repo/activity.tmpl @@ -8,18 +8,18 @@
    @@ -27,7 +27,7 @@
    {{if (or (.Permission.CanRead $.UnitTypeIssues) (.Permission.CanRead $.UnitTypePullRequests))}} -

    {{.i18n.Tr "repo.activity.overview"}}

    +

    {{.locale.Tr "repo.activity.overview"}}

    {{if .Permission.CanRead $.UnitTypePullRequests}}
    @@ -41,7 +41,7 @@
    {{end}} - {{.i18n.TrN .Activity.ActivePRCount "repo.activity.active_prs_count_1" "repo.activity.active_prs_count_n" .Activity.ActivePRCount | Safe }} + {{.locale.TrN .Activity.ActivePRCount "repo.activity.active_prs_count_1" "repo.activity.active_prs_count_n" .Activity.ActivePRCount | Safe }}
    {{end}} {{if .Permission.CanRead $.UnitTypeIssues}} @@ -56,7 +56,7 @@
    {{end}} - {{.i18n.TrN .Activity.ActiveIssueCount "repo.activity.active_issues_count_1" "repo.activity.active_issues_count_n" .Activity.ActiveIssueCount | Safe }} + {{.locale.TrN .Activity.ActiveIssueCount "repo.activity.active_issues_count_1" "repo.activity.active_issues_count_n" .Activity.ActiveIssueCount | Safe }}
    {{end}}
    @@ -64,21 +64,21 @@ {{if .Permission.CanRead $.UnitTypePullRequests}} {{svg "octicon-git-pull-request"}} {{.Activity.MergedPRCount}}
    - {{.i18n.TrN .Activity.MergedPRCount "repo.activity.merged_prs_count_1" "repo.activity.merged_prs_count_n"}} + {{.locale.TrN .Activity.MergedPRCount "repo.activity.merged_prs_count_1" "repo.activity.merged_prs_count_n"}}
    {{svg "octicon-git-branch"}} {{.Activity.OpenedPRCount}}
    - {{.i18n.TrN .Activity.OpenedPRCount "repo.activity.opened_prs_count_1" "repo.activity.opened_prs_count_n"}} + {{.locale.TrN .Activity.OpenedPRCount "repo.activity.opened_prs_count_1" "repo.activity.opened_prs_count_n"}}
    {{end}} {{if .Permission.CanRead $.UnitTypeIssues}} {{svg "octicon-issue-closed"}} {{.Activity.ClosedIssueCount}}
    - {{.i18n.TrN .Activity.ClosedIssueCount "repo.activity.closed_issues_count_1" "repo.activity.closed_issues_count_n"}} + {{.locale.TrN .Activity.ClosedIssueCount "repo.activity.closed_issues_count_1" "repo.activity.closed_issues_count_n"}}
    {{svg "octicon-issue-opened"}} {{.Activity.OpenedIssueCount}}
    - {{.i18n.TrN .Activity.OpenedIssueCount "repo.activity.new_issues_count_1" "repo.activity.new_issues_count_n"}} + {{.locale.TrN .Activity.OpenedIssueCount "repo.activity.new_issues_count_1" "repo.activity.new_issues_count_n"}}
    {{end}} @@ -87,26 +87,26 @@ {{if .Permission.CanRead $.UnitTypeCode}} {{if eq .Activity.Code.CommitCountInAllBranches 0}}
    -

    {{.i18n.Tr "repo.activity.no_git_activity" }}

    +

    {{.locale.Tr "repo.activity.no_git_activity" }}

    {{end}} {{if gt .Activity.Code.CommitCountInAllBranches 0}}
    - {{.i18n.Tr "repo.activity.git_stats_exclude_merges" }} - {{.i18n.TrN .Activity.Code.AuthorCount "repo.activity.git_stats_author_1" "repo.activity.git_stats_author_n" .Activity.Code.AuthorCount}} - {{.i18n.TrN .Activity.Code.AuthorCount "repo.activity.git_stats_pushed_1" "repo.activity.git_stats_pushed_n"}} - {{.i18n.TrN .Activity.Code.CommitCount "repo.activity.git_stats_commit_1" "repo.activity.git_stats_commit_n" .Activity.Code.CommitCount}} - {{.i18n.Tr "repo.activity.git_stats_push_to_branch" .Repository.DefaultBranch }} - {{.i18n.TrN .Activity.Code.CommitCountInAllBranches "repo.activity.git_stats_commit_1" "repo.activity.git_stats_commit_n" .Activity.Code.CommitCountInAllBranches}} - {{.i18n.Tr "repo.activity.git_stats_push_to_all_branches" }} - {{.i18n.Tr "repo.activity.git_stats_on_default_branch" .Repository.DefaultBranch }} - {{.i18n.TrN .Activity.Code.ChangedFiles "repo.activity.git_stats_file_1" "repo.activity.git_stats_file_n" .Activity.Code.ChangedFiles}} - {{.i18n.TrN .Activity.Code.ChangedFiles "repo.activity.git_stats_files_changed_1" "repo.activity.git_stats_files_changed_n"}} - {{.i18n.Tr "repo.activity.git_stats_additions" }} - {{.i18n.TrN .Activity.Code.Additions "repo.activity.git_stats_addition_1" "repo.activity.git_stats_addition_n" .Activity.Code.Additions}} - {{.i18n.Tr "repo.activity.git_stats_and_deletions" }} - {{.i18n.TrN .Activity.Code.Deletions "repo.activity.git_stats_deletion_1" "repo.activity.git_stats_deletion_n" .Activity.Code.Deletions}}. + {{.locale.Tr "repo.activity.git_stats_exclude_merges" }} + {{.locale.TrN .Activity.Code.AuthorCount "repo.activity.git_stats_author_1" "repo.activity.git_stats_author_n" .Activity.Code.AuthorCount}} + {{.locale.TrN .Activity.Code.AuthorCount "repo.activity.git_stats_pushed_1" "repo.activity.git_stats_pushed_n"}} + {{.locale.TrN .Activity.Code.CommitCount "repo.activity.git_stats_commit_1" "repo.activity.git_stats_commit_n" .Activity.Code.CommitCount}} + {{.locale.Tr "repo.activity.git_stats_push_to_branch" .Repository.DefaultBranch }} + {{.locale.TrN .Activity.Code.CommitCountInAllBranches "repo.activity.git_stats_commit_1" "repo.activity.git_stats_commit_n" .Activity.Code.CommitCountInAllBranches}} + {{.locale.Tr "repo.activity.git_stats_push_to_all_branches" }} + {{.locale.Tr "repo.activity.git_stats_on_default_branch" .Repository.DefaultBranch }} + {{.locale.TrN .Activity.Code.ChangedFiles "repo.activity.git_stats_file_1" "repo.activity.git_stats_file_n" .Activity.Code.ChangedFiles}} + {{.locale.TrN .Activity.Code.ChangedFiles "repo.activity.git_stats_files_changed_1" "repo.activity.git_stats_files_changed_n"}} + {{.locale.Tr "repo.activity.git_stats_additions" }} + {{.locale.TrN .Activity.Code.Additions "repo.activity.git_stats_addition_1" "repo.activity.git_stats_addition_n" .Activity.Code.Additions}} + {{.locale.Tr "repo.activity.git_stats_and_deletions" }} + {{.locale.TrN .Activity.Code.Deletions "repo.activity.git_stats_deletion_1" "repo.activity.git_stats_deletion_n" .Activity.Code.Deletions}}.
    @@ -118,20 +118,20 @@ {{if gt .Activity.PublishedReleaseCount 0}}

    {{svg "octicon-tag"}} - {{.i18n.Tr "repo.activity.title.releases_published_by" - (.i18n.TrN .Activity.PublishedReleaseCount "repo.activity.title.releases_1" "repo.activity.title.releases_n" .Activity.PublishedReleaseCount) - (.i18n.TrN .Activity.PublishedReleaseAuthorCount "repo.activity.title.user_1" "repo.activity.title.user_n" .Activity.PublishedReleaseAuthorCount) + {{.locale.Tr "repo.activity.title.releases_published_by" + (.locale.TrN .Activity.PublishedReleaseCount "repo.activity.title.releases_1" "repo.activity.title.releases_n" .Activity.PublishedReleaseCount) + (.locale.TrN .Activity.PublishedReleaseAuthorCount "repo.activity.title.user_1" "repo.activity.title.user_n" .Activity.PublishedReleaseAuthorCount) }}

    {{range .Activity.PublishedReleases}}

    - {{$.i18n.Tr "repo.activity.published_release_label"}} + {{$.locale.Tr "repo.activity.published_release_label"}} {{.TagName}} {{if not .IsTag}} {{.Title | RenderEmoji}} {{end}} - {{TimeSinceUnix .CreatedUnix $.i18n.Lang}} + {{TimeSinceUnix .CreatedUnix $.locale}}

    {{end}}
    @@ -140,17 +140,17 @@ {{if gt .Activity.MergedPRCount 0}}

    {{svg "octicon-git-pull-request"}} - {{.i18n.Tr "repo.activity.title.prs_merged_by" - (.i18n.TrN .Activity.MergedPRCount "repo.activity.title.prs_1" "repo.activity.title.prs_n" .Activity.MergedPRCount) - (.i18n.TrN .Activity.MergedPRAuthorCount "repo.activity.title.user_1" "repo.activity.title.user_n" .Activity.MergedPRAuthorCount) + {{.locale.Tr "repo.activity.title.prs_merged_by" + (.locale.TrN .Activity.MergedPRCount "repo.activity.title.prs_1" "repo.activity.title.prs_n" .Activity.MergedPRCount) + (.locale.TrN .Activity.MergedPRAuthorCount "repo.activity.title.user_1" "repo.activity.title.user_n" .Activity.MergedPRAuthorCount) }}

    {{range .Activity.MergedPRs}}

    - {{$.i18n.Tr "repo.activity.merged_prs_label"}} + {{$.locale.Tr "repo.activity.merged_prs_label"}} #{{.Index}} {{.Issue.Title | RenderEmoji}} - {{TimeSinceUnix .MergedUnix $.i18n.Lang}} + {{TimeSinceUnix .MergedUnix $.locale}}

    {{end}}
    @@ -159,17 +159,17 @@ {{if gt .Activity.OpenedPRCount 0}}

    {{svg "octicon-git-branch"}} - {{.i18n.Tr "repo.activity.title.prs_opened_by" - (.i18n.TrN .Activity.OpenedPRCount "repo.activity.title.prs_1" "repo.activity.title.prs_n" .Activity.OpenedPRCount) - (.i18n.TrN .Activity.OpenedPRAuthorCount "repo.activity.title.user_1" "repo.activity.title.user_n" .Activity.OpenedPRAuthorCount) + {{.locale.Tr "repo.activity.title.prs_opened_by" + (.locale.TrN .Activity.OpenedPRCount "repo.activity.title.prs_1" "repo.activity.title.prs_n" .Activity.OpenedPRCount) + (.locale.TrN .Activity.OpenedPRAuthorCount "repo.activity.title.user_1" "repo.activity.title.user_n" .Activity.OpenedPRAuthorCount) }}

    {{range .Activity.OpenedPRs}}

    - {{$.i18n.Tr "repo.activity.opened_prs_label"}} + {{$.locale.Tr "repo.activity.opened_prs_label"}} #{{.Index}} {{.Issue.Title | RenderEmoji}} - {{TimeSinceUnix .Issue.CreatedUnix $.i18n.Lang}} + {{TimeSinceUnix .Issue.CreatedUnix $.locale}}

    {{end}}
    @@ -178,17 +178,17 @@ {{if gt .Activity.ClosedIssueCount 0}}

    {{svg "octicon-issue-closed"}} - {{.i18n.Tr "repo.activity.title.issues_closed_from" - (.i18n.TrN .Activity.ClosedIssueCount "repo.activity.title.issues_1" "repo.activity.title.issues_n" .Activity.ClosedIssueCount) - (.i18n.TrN .Activity.ClosedIssueAuthorCount "repo.activity.title.user_1" "repo.activity.title.user_n" .Activity.ClosedIssueAuthorCount) + {{.locale.Tr "repo.activity.title.issues_closed_from" + (.locale.TrN .Activity.ClosedIssueCount "repo.activity.title.issues_1" "repo.activity.title.issues_n" .Activity.ClosedIssueCount) + (.locale.TrN .Activity.ClosedIssueAuthorCount "repo.activity.title.user_1" "repo.activity.title.user_n" .Activity.ClosedIssueAuthorCount) }}

    {{range .Activity.ClosedIssues}}

    - {{$.i18n.Tr "repo.activity.closed_issue_label"}} + {{$.locale.Tr "repo.activity.closed_issue_label"}} #{{.Index}} {{.Title | RenderEmoji}} - {{TimeSinceUnix .ClosedUnix $.i18n.Lang}} + {{TimeSinceUnix .ClosedUnix $.locale}}

    {{end}}
    @@ -197,17 +197,17 @@ {{if gt .Activity.OpenedIssueCount 0}}

    {{svg "octicon-issue-opened"}} - {{.i18n.Tr "repo.activity.title.issues_created_by" - (.i18n.TrN .Activity.OpenedIssueCount "repo.activity.title.issues_1" "repo.activity.title.issues_n" .Activity.OpenedIssueCount) - (.i18n.TrN .Activity.OpenedIssueAuthorCount "repo.activity.title.user_1" "repo.activity.title.user_n" .Activity.OpenedIssueAuthorCount) + {{.locale.Tr "repo.activity.title.issues_created_by" + (.locale.TrN .Activity.OpenedIssueCount "repo.activity.title.issues_1" "repo.activity.title.issues_n" .Activity.OpenedIssueCount) + (.locale.TrN .Activity.OpenedIssueAuthorCount "repo.activity.title.user_1" "repo.activity.title.user_n" .Activity.OpenedIssueAuthorCount) }}

    {{range .Activity.OpenedIssues}}

    - {{$.i18n.Tr "repo.activity.new_issue_label"}} + {{$.locale.Tr "repo.activity.new_issue_label"}} #{{.Index}} {{.Title | RenderEmoji}} - {{TimeSinceUnix .CreatedUnix $.i18n.Lang}} + {{TimeSinceUnix .CreatedUnix $.locale}}

    {{end}}
    @@ -216,22 +216,22 @@ {{if gt .Activity.UnresolvedIssueCount 0}}

    {{svg "octicon-comment-discussion"}} - {{.i18n.TrN .Activity.UnresolvedIssueCount "repo.activity.title.unresolved_conv_1" "repo.activity.title.unresolved_conv_n" .Activity.UnresolvedIssueCount}} + {{.locale.TrN .Activity.UnresolvedIssueCount "repo.activity.title.unresolved_conv_1" "repo.activity.title.unresolved_conv_n" .Activity.UnresolvedIssueCount}}

    - {{.i18n.Tr "repo.activity.unresolved_conv_desc"}} + {{.locale.Tr "repo.activity.unresolved_conv_desc"}}
    {{range .Activity.UnresolvedIssues}}

    - {{$.i18n.Tr "repo.activity.unresolved_conv_label"}} + {{$.locale.Tr "repo.activity.unresolved_conv_label"}} #{{.Index}} {{if .IsPull}} {{.Title | RenderEmoji}} {{else}} {{.Title | RenderEmoji}} {{end}} - {{TimeSinceUnix .UpdatedUnix $.i18n.Lang}} + {{TimeSinceUnix .UpdatedUnix $.locale}}

    {{end}}
    diff --git a/templates/repo/blame.tmpl b/templates/repo/blame.tmpl index 3dc3522275..6b3f3eddd7 100644 --- a/templates/repo/blame.tmpl +++ b/templates/repo/blame.tmpl @@ -3,21 +3,21 @@
    - {{.NumLines}} {{.i18n.TrN .NumLines "repo.line" "repo.lines"}} + {{.NumLines}} {{.locale.TrN .NumLines "repo.line" "repo.lines"}}
    {{FileSize .FileSize}}
    @@ -46,7 +46,7 @@
    {{if $.EscapeStatus.Escaped}} - + {{end}}
    {{.root.i18n.Tr "packages.dependency.id"}}{{.root.i18n.Tr "packages.dependency.version"}}{{.root.locale.Tr "packages.dependency.id"}}{{.root.locale.Tr "packages.dependency.version"}}
    {{if $row.PreviousSha}} - + {{svg "octicon-versions"}} {{end}} @@ -55,7 +55,7 @@ {{if $row.EscapeStatus.Escaped}}{{end}}{{if $row.EscapeStatus.Escaped}}{{end}} {{$row.Code}} diff --git a/templates/repo/branch/list.tmpl b/templates/repo/branch/list.tmpl index 6c34ba4c19..82b88a00ba 100644 --- a/templates/repo/branch/list.tmpl +++ b/templates/repo/branch/list.tmpl @@ -6,7 +6,7 @@ {{template "repo/sub_menu" .}} {{if .DefaultBranchBranch}}

    - {{.i18n.Tr "repo.default_branch"}} + {{.locale.Tr "repo.default_branch"}}

    @@ -18,15 +18,15 @@ {{svg "octicon-shield-lock"}} {{end}} {{.DefaultBranch}} -

    {{svg "octicon-git-commit" 16 "mr-2"}}{{ShortSha .DefaultBranchBranch.Commit.ID.String}} · {{RenderCommitMessage $.Context .DefaultBranchBranch.Commit.CommitMessage .RepoLink .Repository.ComposeMetas}} · {{.i18n.Tr "org.repo_updated"}} {{TimeSince .DefaultBranchBranch.Commit.Committer.When .i18n.Lang}}

    +

    {{svg "octicon-git-commit" 16 "mr-2"}}{{ShortSha .DefaultBranchBranch.Commit.ID.String}} · {{RenderCommitMessage $.Context .DefaultBranchBranch.Commit.CommitMessage .RepoLink .Repository.ComposeMetas}} · {{.locale.Tr "org.repo_updated"}} {{TimeSince .DefaultBranchBranch.Commit.Committer.When .locale}}

    {{if and $.IsWriter (not $.Repository.IsArchived) (not .IsDeleted)}} -
    +
    {{svg "octicon-git-branch"}}
    {{end}} -