Merge branch 'master' into tklk/issue-3389

This commit is contained in:
techknowlogick 2018-07-04 23:48:53 -04:00 committed by GitHub
commit 5cb253ad10
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
476 changed files with 5862 additions and 167238 deletions

View File

@ -4,6 +4,54 @@ This changelog goes through all the changes that have been made in each release
without substantial changes to our git log; to see the highlights of what has without substantial changes to our git log; to see the highlights of what has
been added to each release, please refer to the [blog](https://blog.gitea.io). been added to each release, please refer to the [blog](https://blog.gitea.io).
## [1.5.0-RC1](https://github.com/go-gitea/gitea/releases/tag/v1.5.0-rc1) - 2018-07-04
* SECURITY
* Limit uploaded avatar image-size to 4096px x 3072px by default (#4353)
* Do not allow to reuse TOTP passcode (#3878)
* FEATURE
* Add cli commands to regen hooks & keys (#3979)
* Add support for FIDO U2F (#3971)
* Added user language setting (#3875)
* LDAP Public SSH Keys synchronization (#1844)
* Add topic support (#3711)
* Multiple assignees (#3705)
* Add protected branch whitelists for merging (#3689)
* Global code search support (#3664)
* Add label descriptions (#3662)
* Add issue search via API (#3612)
* Add repository setting to enable/disable health checks (#3607)
* Emoji Autocomplete (#3433)
* Implements generator cli for secrets (#3531)
* ENHANCEMENT
* Add more webhooks support and refactor webhook templates directory (#3929)
* Add new option to allow only OAuth2/OpenID user registration (#3910)
* Add option to use paged LDAP search when synchronizing users (#3895)
* Symlink icons (#1416)
* Improve release page UI (#3693)
* Add admin dashboard option to run health checks (#3606)
* Add branch link in branch list (#3576)
* Reduce sql query times in retrieveFeeds (#3547)
* Option to enable or disable swagger endpoints (#3502)
* Add missing licenses (#3497)
* Reduce repo indexer disk usage (#3452)
* Enable caching on assets and avatars (#3376)
* Add repository search ordered by stars/forks. Forks column in admin repo list (#3969)
* Add Environment Variables to Docker template (#4012)
* LFS: make HTTP auth period configurable (#4035)
* Add config path as an optionial flag when changing pass via CLI (#4184)
* Refactor User Settings sections (#3900)
* Allow square brackets in external issue patterns (#3408)
* Add Attachment API (#3478)
* Add EnableTimetracking option to app settings (#3719)
* Add config option to enable or disable log executed SQL (#3726)
* Shows total tracked time in issue and milestone list (#3341)
* TRANSLATION
* Improve English grammar and consistency (#3614)
* DEPLOYMENT
* Allow Gitea to run as different USER in Docker (#3961)
* Provide compressed release binaries (#3991)
* Sign release binaries (#4188)
## [1.4.3](https://github.com/go-gitea/gitea/releases/tag/v1.4.3) - 2018-06-26 ## [1.4.3](https://github.com/go-gitea/gitea/releases/tag/v1.4.3) - 2018-06-26
* SECURITY * SECURITY
* HTML-escape plain-text READMEs (#4192) (#4214) * HTML-escape plain-text READMEs (#4192) (#4214)

View File

@ -58,3 +58,4 @@ CMD ["/bin/s6-svscan", "/etc/s6"]
COPY docker / COPY docker /
COPY --from=build-env /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea COPY --from=build-env /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea
RUN ln -s /app/gitea/gitea /usr/local/bin/gitea

176
Gopkg.lock generated
View File

@ -143,17 +143,6 @@
packages = ["."] packages = ["."]
revision = "098da33fde5f9220736531b3cb26a2dec86a8367" revision = "098da33fde5f9220736531b3cb26a2dec86a8367"
[[projects]]
name = "github.com/coreos/etcd"
packages = ["error"]
revision = "01c303113d0a3d5a8075864321c3aedb72035bdd"
[[projects]]
branch = "master"
name = "github.com/coreos/go-etcd"
packages = ["etcd"]
revision = "003851be7bb0694fe3cc457a49529a19388ee7cf"
[[projects]] [[projects]]
branch = "master" branch = "master"
name = "github.com/couchbase/vellum" name = "github.com/couchbase/vellum"
@ -294,7 +283,7 @@
[[projects]] [[projects]]
name = "github.com/go-sql-driver/mysql" name = "github.com/go-sql-driver/mysql"
packages = ["."] packages = ["."]
revision = "ce924a41eea897745442daaa1739089b0f3f561d" revision = "d523deb1b23d913de5bdada721a6071e71283618"
[[projects]] [[projects]]
name = "github.com/go-xorm/builder" name = "github.com/go-xorm/builder"
@ -306,11 +295,6 @@
packages = ["."] packages = ["."]
revision = "cb1d0ca71f42d3ee1bf4aba7daa16099bc31a7e9" revision = "cb1d0ca71f42d3ee1bf4aba7daa16099bc31a7e9"
[[projects]]
name = "github.com/go-xorm/tidb"
packages = ["."]
revision = "21e49190ce47a766fa741cf7edc831a30c12c6ac"
[[projects]] [[projects]]
name = "github.com/go-xorm/xorm" name = "github.com/go-xorm/xorm"
packages = ["."] packages = ["."]
@ -370,11 +354,6 @@
packages = ["."] packages = ["."]
revision = "8fb95d837f7d6db1913fecfd7bcc5333e6499596" revision = "8fb95d837f7d6db1913fecfd7bcc5333e6499596"
[[projects]]
name = "github.com/juju/errors"
packages = ["."]
revision = "b2c7a7da5b2995941048f60146e67702a292e468"
[[projects]] [[projects]]
name = "github.com/kballard/go-shellquote" name = "github.com/kballard/go-shellquote"
packages = ["."] packages = ["."]
@ -497,134 +476,12 @@
packages = ["."] packages = ["."]
revision = "891127d8d1b52734debe1b3c3d7e747502b6c366" revision = "891127d8d1b52734debe1b3c3d7e747502b6c366"
[[projects]]
name = "github.com/ngaut/deadline"
packages = ["."]
revision = "fae8f9dfd7048de16575b9d4c255278e38c28a4f"
[[projects]]
branch = "master"
name = "github.com/ngaut/go-zookeeper"
packages = ["zk"]
revision = "9c3719e318c7cfd072e41eb48cb71fcaa49d5e05"
[[projects]]
name = "github.com/ngaut/log"
packages = ["."]
revision = "d2af3a61f64d093457fb23b25d20f4ce3cd551ce"
[[projects]]
branch = "master"
name = "github.com/ngaut/pools"
packages = ["."]
revision = "b7bc8c42aac787667ba45adea78233f53f548443"
[[projects]]
branch = "master"
name = "github.com/ngaut/sync2"
packages = ["."]
revision = "7a24ed77b2efb460c1468b7dc917821c66e80e55"
[[projects]]
branch = "master"
name = "github.com/ngaut/tso"
packages = [
"client",
"proto",
"util"
]
revision = "118f6c141d58f1e72577ff61f43f649bf39355ee"
[[projects]]
branch = "master"
name = "github.com/ngaut/zkhelper"
packages = ["."]
revision = "6738bdc138d469112c6687fbfcfe049ccabd6a0a"
[[projects]]
branch = "master"
name = "github.com/petar/GoLLRB"
packages = ["llrb"]
revision = "53be0d36a84c2a886ca057d34b6aa4468df9ccb4"
[[projects]] [[projects]]
name = "github.com/philhofer/fwd" name = "github.com/philhofer/fwd"
packages = ["."] packages = ["."]
revision = "bb6d471dc95d4fe11e432687f8b70ff496cf3136" revision = "bb6d471dc95d4fe11e432687f8b70ff496cf3136"
version = "v1.0.0" version = "v1.0.0"
[[projects]]
name = "github.com/pingcap/go-hbase"
packages = [
".",
"iohelper",
"proto"
]
revision = "7a98d1fe4e9e115de8c77ae0e158c0d08732c550"
[[projects]]
branch = "master"
name = "github.com/pingcap/go-themis"
packages = [
".",
"oracle",
"oracle/oracles"
]
revision = "dbb996606c1d1fe8571fd9ac6da2254c76d2c5c9"
[[projects]]
name = "github.com/pingcap/tidb"
packages = [
".",
"ast",
"column",
"context",
"ddl",
"domain",
"evaluator",
"executor",
"infoschema",
"inspectkv",
"kv",
"kv/memkv",
"meta",
"meta/autoid",
"model",
"mysql",
"optimizer",
"optimizer/plan",
"parser",
"parser/opcode",
"perfschema",
"privilege",
"privilege/privileges",
"sessionctx",
"sessionctx/autocommit",
"sessionctx/db",
"sessionctx/forupdate",
"sessionctx/variable",
"store/hbase",
"store/localstore",
"store/localstore/boltdb",
"store/localstore/engine",
"store/localstore/goleveldb",
"structure",
"table",
"table/tables",
"terror",
"util",
"util/bytes",
"util/charset",
"util/codec",
"util/distinct",
"util/hack",
"util/segmentmap",
"util/sqlexec",
"util/stringutil",
"util/types"
]
revision = "33197485abe227dcb254644cf5081c9a3c281669"
[[projects]] [[projects]]
name = "github.com/pmezard/go-difflib" name = "github.com/pmezard/go-difflib"
packages = ["difflib"] packages = ["difflib"]
@ -673,24 +530,6 @@
revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71" revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71"
version = "v1.2.1" version = "v1.2.1"
[[projects]]
name = "github.com/syndtr/goleveldb"
packages = [
"leveldb",
"leveldb/cache",
"leveldb/comparer",
"leveldb/errors",
"leveldb/filter",
"leveldb/iterator",
"leveldb/journal",
"leveldb/memdb",
"leveldb/opt",
"leveldb/storage",
"leveldb/table",
"leveldb/util"
]
revision = "917f41c560270110ceb73c5b38be2a9127387071"
[[projects]] [[projects]]
branch = "master" branch = "master"
name = "github.com/tinylib/msgp" name = "github.com/tinylib/msgp"
@ -703,17 +542,6 @@
packages = ["."] packages = ["."]
revision = "d21a03e0b1d9fc1df59ff54e7a513655c1748b0c" revision = "d21a03e0b1d9fc1df59ff54e7a513655c1748b0c"
[[projects]]
name = "github.com/twinj/uuid"
packages = ["."]
revision = "89173bcdda19db0eb88aef1e1cb1cb2505561d31"
version = "0.10.0"
[[projects]]
name = "github.com/ugorji/go"
packages = ["codec"]
revision = "c062049c1793b01a3cc3fe786108edabbaf7756b"
[[projects]] [[projects]]
name = "github.com/urfave/cli" name = "github.com/urfave/cli"
packages = ["."] packages = ["."]
@ -873,6 +701,6 @@
[solve-meta] [solve-meta]
analyzer-name = "dep" analyzer-name = "dep"
analyzer-version = 1 analyzer-version = 1
inputs-digest = "036b8c882671cf8d2c5e2fdbe53b1bdfbd39f7ebd7765bd50276c7c4ecf16687" inputs-digest = "59451a3ad1d449f75c5e9035daf542a377c5c4a397e219bebec0aa0007ab9c39"
solver-name = "gps-cdcl" solver-name = "gps-cdcl"
solver-version = 1 solver-version = 1

View File

@ -30,16 +30,15 @@ ignored = ["google.golang.org/appengine*"]
revision = "f2499483f923065a842d38eb4c7f1927e6fc6e6d" revision = "f2499483f923065a842d38eb4c7f1927e6fc6e6d"
name = "golang.org/x/net" name = "golang.org/x/net"
[[constraint]]
#version = "v1.0.0"
revision = "33197485abe227dcb254644cf5081c9a3c281669"
name = "github.com/pingcap/tidb"
[[override]] [[override]]
name = "github.com/go-xorm/xorm" name = "github.com/go-xorm/xorm"
#version = "0.6.5" #version = "0.6.5"
revision = "d4149d1eee0c2c488a74a5863fd9caf13d60fd03" revision = "d4149d1eee0c2c488a74a5863fd9caf13d60fd03"
[[override]]
name = "github.com/go-sql-driver/mysql"
revision = "d523deb1b23d913de5bdada721a6071e71283618"
[[override]] [[override]]
name = "github.com/gorilla/mux" name = "github.com/gorilla/mux"
revision = "757bef944d0f21880861c2dd9c871ca543023cba" revision = "757bef944d0f21880861c2dd9c871ca543023cba"

View File

@ -23,3 +23,4 @@ Matti Ranta <matti@mdranta.net> (@techknowlogick)
Michael Lustfield <mtecknology@debian.org> (@MTecknology) Michael Lustfield <mtecknology@debian.org> (@MTecknology)
Jonas Franz <info@jonasfranz.software> (@JonasFranzDEV) Jonas Franz <info@jonasfranz.software> (@JonasFranzDEV)
Flynn Lufmons <fluf@warpmail.net> (@flufmonster) Flynn Lufmons <fluf@warpmail.net> (@flufmonster)
Alexey Terentyev <axifnx@gmail.com> (@axifive)

View File

@ -402,6 +402,10 @@ SESSION_LIFE_TIME = 86400
[picture] [picture]
AVATAR_UPLOAD_PATH = data/avatars AVATAR_UPLOAD_PATH = data/avatars
; Max Width and Height of uploaded avatars. This is to limit the amount of RAM
; used when resizing the image.
AVATAR_MAX_WIDTH = 4096
AVATAR_MAX_HEIGHT = 3072
; Chinese users can choose "duoshuo" ; Chinese users can choose "duoshuo"
; or a custom avatar source, like: http://cn.gravatar.com/avatar/ ; or a custom avatar source, like: http://cn.gravatar.com/avatar/
GRAVATAR_SOURCE = gravatar GRAVATAR_SOURCE = gravatar

View File

@ -4,6 +4,9 @@ RUN_MODE = $RUN_MODE
[repository] [repository]
ROOT = /data/git/repositories ROOT = /data/git/repositories
[repository.local]
LOCAL_COPY_PATH = /data/gitea/tmp/local-repo
[repository.upload] [repository.upload]
TEMP_PATH = /data/gitea/uploads TEMP_PATH = /data/gitea/uploads
@ -14,6 +17,7 @@ HTTP_PORT = $HTTP_PORT
ROOT_URL = $ROOT_URL ROOT_URL = $ROOT_URL
DISABLE_SSH = $DISABLE_SSH DISABLE_SSH = $DISABLE_SSH
SSH_PORT = $SSH_PORT SSH_PORT = $SSH_PORT
LFS_CONTENT_PATH = /data/git/lfs
[database] [database]
PATH = /data/gitea/gitea.db PATH = /data/gitea/gitea.db
@ -23,6 +27,9 @@ NAME = $DB_NAME
USER = $DB_USER USER = $DB_USER
PASSWD = $DB_PASSWD PASSWD = $DB_PASSWD
[indexer]
ISSUE_INDEXER_PATH = /data/gitea/indexers/issues.bleve
[session] [session]
PROVIDER_CONFIG = /data/gitea/sessions PROVIDER_CONFIG = /data/gitea/sessions

View File

@ -235,3 +235,53 @@ func TestAPIGetRepoByIDUnauthorized(t *testing.T) {
req := NewRequestf(t, "GET", "/api/v1/repositories/2") req := NewRequestf(t, "GET", "/api/v1/repositories/2")
sess.MakeRequest(t, req, http.StatusNotFound) sess.MakeRequest(t, req, http.StatusNotFound)
} }
func TestAPIRepoMigrate(t *testing.T) {
testCases := []struct {
ctxUserID, userID int64
cloneURL, repoName string
expectedStatus int
}{
{ctxUserID: 1, userID: 2, cloneURL: "https://github.com/go-gitea/git.git", repoName: "git-admin", expectedStatus: http.StatusCreated},
{ctxUserID: 2, userID: 2, cloneURL: "https://github.com/go-gitea/git.git", repoName: "git-own", expectedStatus: http.StatusCreated},
{ctxUserID: 2, userID: 1, cloneURL: "https://github.com/go-gitea/git.git", repoName: "git-bad", expectedStatus: http.StatusForbidden},
{ctxUserID: 2, userID: 3, cloneURL: "https://github.com/go-gitea/git.git", repoName: "git-org", expectedStatus: http.StatusCreated},
{ctxUserID: 2, userID: 6, cloneURL: "https://github.com/go-gitea/git.git", repoName: "git-bad-org", expectedStatus: http.StatusForbidden},
}
prepareTestEnv(t)
for _, testCase := range testCases {
user := models.AssertExistsAndLoadBean(t, &models.User{ID: testCase.ctxUserID}).(*models.User)
session := loginUser(t, user.Name)
req := NewRequestWithJSON(t, "POST", "/api/v1/repos/migrate", &api.MigrateRepoOption{
CloneAddr: testCase.cloneURL,
UID: int(testCase.userID),
RepoName: testCase.repoName,
})
session.MakeRequest(t, req, testCase.expectedStatus)
}
}
func TestAPIOrgRepoCreate(t *testing.T) {
testCases := []struct {
ctxUserID int64
orgName, repoName string
expectedStatus int
}{
{ctxUserID: 1, orgName: "user3", repoName: "repo-admin", expectedStatus: http.StatusCreated},
{ctxUserID: 2, orgName: "user3", repoName: "repo-own", expectedStatus: http.StatusCreated},
{ctxUserID: 2, orgName: "user6", repoName: "repo-bad-org", expectedStatus: http.StatusForbidden},
}
prepareTestEnv(t)
for _, testCase := range testCases {
user := models.AssertExistsAndLoadBean(t, &models.User{ID: testCase.ctxUserID}).(*models.User)
session := loginUser(t, user.Name)
req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/org/%s/repos", testCase.orgName), &api.CreateRepoOption{
Name: testCase.repoName,
})
session.MakeRequest(t, req, testCase.expectedStatus)
}
}

View File

@ -1,18 +0,0 @@
// +build tidb
// Copyright 2015 The Gogs 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 models
import (
_ "github.com/go-xorm/tidb"
"github.com/ngaut/log"
_ "github.com/pingcap/tidb"
)
func init() {
EnableTiDB = true
log.SetLevelByString("error")
}

View File

@ -781,7 +781,7 @@ var (
// DescriptionHTML does special handles to description and return HTML string. // DescriptionHTML does special handles to description and return HTML string.
func (repo *Repository) DescriptionHTML() template.HTML { func (repo *Repository) DescriptionHTML() template.HTML {
sanitize := func(s string) string { sanitize := func(s string) string {
return fmt.Sprintf(`<a href="%[1]s" target="_blank" rel="noopener">%[1]s</a>`, s) return fmt.Sprintf(`<a href="%[1]s" target="_blank" rel="noopener noreferrer">%[1]s</a>`, s)
} }
return template.HTML(descPattern.ReplaceAllStringFunc(markup.Sanitize(repo.Description), sanitize)) return template.HTML(descPattern.ReplaceAllStringFunc(markup.Sanitize(repo.Description), sanitize))
} }
@ -1347,6 +1347,12 @@ func createRepository(e *xorm.Session, doer, u *User, repo *Repository) (err err
Type: tp, Type: tp,
Config: &IssuesConfig{EnableTimetracker: setting.Service.DefaultEnableTimetracking, AllowOnlyContributorsToTrackTime: setting.Service.DefaultAllowOnlyContributorsToTrackTime}, Config: &IssuesConfig{EnableTimetracker: setting.Service.DefaultEnableTimetracking, AllowOnlyContributorsToTrackTime: setting.Service.DefaultAllowOnlyContributorsToTrackTime},
}) })
} else if tp == UnitTypePullRequests {
units = append(units, RepoUnit{
RepoID: repo.ID,
Type: tp,
Config: &PullRequestsConfig{AllowMerge: true, AllowRebase: true, AllowSquash: true},
})
} else { } else {
units = append(units, RepoUnit{ units = append(units, RepoUnit{
RepoID: repo.ID, RepoID: repo.ID,

View File

@ -433,6 +433,17 @@ func (u *User) IsPasswordSet() bool {
// UploadAvatar saves custom avatar for user. // UploadAvatar saves custom avatar for user.
// FIXME: split uploads to different subdirs in case we have massive users. // FIXME: split uploads to different subdirs in case we have massive users.
func (u *User) UploadAvatar(data []byte) error { func (u *User) UploadAvatar(data []byte) error {
imgCfg, _, err := image.DecodeConfig(bytes.NewReader(data))
if err != nil {
return fmt.Errorf("DecodeConfig: %v", err)
}
if imgCfg.Width > setting.AvatarMaxWidth {
return fmt.Errorf("Image width is to large: %d > %d", imgCfg.Width, setting.AvatarMaxWidth)
}
if imgCfg.Height > setting.AvatarMaxHeight {
return fmt.Errorf("Image height is to large: %d > %d", imgCfg.Height, setting.AvatarMaxHeight)
}
img, _, err := image.Decode(bytes.NewReader(data)) img, _, err := image.Decode(bytes.NewReader(data))
if err != nil { if err != nil {
return fmt.Errorf("Decode: %v", err) return fmt.Errorf("Decode: %v", err)
@ -945,7 +956,7 @@ func deleteUser(e *xorm.Session, u *User) error {
Where("watch.user_id = ?", u.ID).Find(&watchedRepoIDs); err != nil { Where("watch.user_id = ?", u.ID).Find(&watchedRepoIDs); err != nil {
return fmt.Errorf("get all watches: %v", err) return fmt.Errorf("get all watches: %v", err)
} }
if _, err = e.Decr("num_watches").In("id", watchedRepoIDs).Update(new(Repository)); err != nil { if _, err = e.Decr("num_watches").In("id", watchedRepoIDs).NoAutoTime().Update(new(Repository)); err != nil {
return fmt.Errorf("decrease repository num_watches: %v", err) return fmt.Errorf("decrease repository num_watches: %v", err)
} }
// ***** END: Watch ***** // ***** END: Watch *****
@ -955,7 +966,7 @@ func deleteUser(e *xorm.Session, u *User) error {
if err = e.Table("star").Cols("star.repo_id"). if err = e.Table("star").Cols("star.repo_id").
Where("star.uid = ?", u.ID).Find(&starredRepoIDs); err != nil { Where("star.uid = ?", u.ID).Find(&starredRepoIDs); err != nil {
return fmt.Errorf("get all stars: %v", err) return fmt.Errorf("get all stars: %v", err)
} else if _, err = e.Decr("num_stars").In("id", starredRepoIDs).Update(new(Repository)); err != nil { } else if _, err = e.Decr("num_stars").In("id", starredRepoIDs).NoAutoTime().Update(new(Repository)); err != nil {
return fmt.Errorf("decrease repository num_stars: %v", err) return fmt.Errorf("decrease repository num_stars: %v", err)
} }
// ***** END: Star ***** // ***** END: Star *****

View File

@ -163,7 +163,7 @@ func createProvider(providerName, providerType, clientID, clientSecret, openIDCo
profileURL = customURLMapping.ProfileURL profileURL = customURLMapping.ProfileURL
} }
} }
provider = gitlab.NewCustomisedURL(clientID, clientSecret, callbackURL, authURL, tokenURL, profileURL) provider = gitlab.NewCustomisedURL(clientID, clientSecret, callbackURL, authURL, tokenURL, profileURL, "read_user")
case "gplus": case "gplus":
provider = gplus.New(clientID, clientSecret, callbackURL, "email") provider = gplus.New(clientID, clientSecret, callbackURL, "email")
case "openidConnect": case "openidConnect":

View File

@ -341,6 +341,8 @@ var (
// Picture settings // Picture settings
AvatarUploadPath string AvatarUploadPath string
AvatarMaxWidth int
AvatarMaxHeight int
GravatarSource string GravatarSource string
GravatarSourceURL *url.URL GravatarSourceURL *url.URL
DisableGravatar bool DisableGravatar bool
@ -1024,6 +1026,8 @@ func NewContext() {
if !filepath.IsAbs(AvatarUploadPath) { if !filepath.IsAbs(AvatarUploadPath) {
AvatarUploadPath = path.Join(AppWorkPath, AvatarUploadPath) AvatarUploadPath = path.Join(AppWorkPath, AvatarUploadPath)
} }
AvatarMaxWidth = sec.Key("AVATAR_MAX_WIDTH").MustInt(4096)
AvatarMaxHeight = sec.Key("AVATAR_MAX_HEIGHT").MustInt(3072)
switch source := sec.Key("GRAVATAR_SOURCE").MustString("gravatar"); source { switch source := sec.Key("GRAVATAR_SOURCE").MustString("gravatar"); source {
case "duoshuo": case "duoshuo":
GravatarSource = "http://gravatar.duoshuo.com/avatar/" GravatarSource = "http://gravatar.duoshuo.com/avatar/"

View File

@ -27,6 +27,7 @@ Enrico Testori hypertesto AT gmail DOT com
Ezequiel Gonzalez Rial <gonrial AT gmail DOT com> Ezequiel Gonzalez Rial <gonrial AT gmail DOT com>
Gabriel Dugny <gabriel DOT dugny AT gmail DOT com> Gabriel Dugny <gabriel DOT dugny AT gmail DOT com>
Gregor Santner <gdev AT live DOT de> Gregor Santner <gdev AT live DOT de>
Guilhem Marion <gmarion AT netc DOT fr>
Halil Kaya <halil AT halilkaya DOT net> Halil Kaya <halil AT halilkaya DOT net>
Hamid Feizabadi <hamidfzm AT gmail DOT com> Hamid Feizabadi <hamidfzm AT gmail DOT com>
Hilton Wichwski Silva <hilton AT hiltonws DOT com DOT br> Hilton Wichwski Silva <hilton AT hiltonws DOT com DOT br>

View File

@ -11,6 +11,7 @@ version=Версия
page=Страница page=Страница
template=Шаблон template=Шаблон
language=Език language=Език
notifications=Известия
signed_in_as=Вписан като signed_in_as=Вписан като
username=Потребител username=Потребител
@ -28,6 +29,9 @@ manage_org=Управление на организации
account_settings=Настройки на профила account_settings=Настройки на профила
settings=Настройки settings=Настройки
all=Всичко
sources=Източници
mirrors=Огледала
activities=Активности activities=Активности
pull_requests=Заявки за сливане pull_requests=Заявки за сливане
@ -69,7 +73,9 @@ issues.in_your_repos=Във Вашите хранилища
[explore] [explore]
repos=Хранилища repos=Хранилища
users=Потребители users=Потребители
organizations=Организации
search=Търсене search=Търсене
code=Код
[auth] [auth]
register_helper_msg=Вече имате профил? Впишете се сега! register_helper_msg=Вече имате профил? Впишете се сега!
@ -79,11 +85,14 @@ has_unconfirmed_mail=Здравейте %s, имате непотвърден а
resend_mail=Щракнете тук, за да се изпрати ново писмо за потвърждение resend_mail=Щракнете тук, за да се изпрати ново писмо за потвърждение
reset_password=Нулиране на паролата reset_password=Нулиране на паролата
reset_password_helper=Щракнете тук, за да нулирате паролата си reset_password_helper=Щракнете тук, за да нулирате паролата си
openid_connect_submit=Свързване
[mail] [mail]
activate_account=Моля активирайте Вашия профил activate_account=Моля активирайте Вашия профил
activate_email=Провери адрес на ел. поща activate_email=Провери адрес на ел. поща
reset_password=Нулиране на паролата reset_password=Нулиране на паролата
register_success=Успешна регистрация
register_notify=Добре дошли в Gitea
[modal] [modal]
yes=Да yes=Да
@ -117,6 +126,7 @@ url_error=` не е валиден URL адрес.`
include_error=` трябва да съдържа текст '%s'.` include_error=` трябва да съдържа текст '%s'.`
unknown_error=Неизвестна грешка: unknown_error=Неизвестна грешка:
user_not_exist=Потребителят не съществува.
auth_failed=Неуспешно удостоверяване: %v auth_failed=Неуспешно удостоверяване: %v
@ -136,9 +146,11 @@ unfollow=Не следвай
[settings] [settings]
profile=Профил profile=Профил
password=Парола password=Парола
security=Сигурност
avatar=Аватар avatar=Аватар
social=Социални профили social=Социални профили
delete=Изтрий профил delete=Изтрий профил
twofa=Двуфакторно удостоверяване
uid=UID uid=UID
public_profile=Публичен профил public_profile=Публичен профил
@ -169,6 +181,8 @@ key_content=Съдържание
add_on=Добавен на add_on=Добавен на
last_used=Последно използван на last_used=Последно използван на
no_activity=Няма скорошна дейност no_activity=Няма скорошна дейност
show_openid=Показване в профила
hide_openid=Скриване от профила
manage_social=Управление на свързани профили в социалните мрежи manage_social=Управление на свързани профили в социалните мрежи
@ -239,6 +253,7 @@ file_view_raw=Виж директен файл
file_permalink=Постоянна връзка file_permalink=Постоянна връзка
editor.preview_changes=Преглед на промени editor.preview_changes=Преглед на промени
editor.name_your_file=Име на файла ви…
editor.or=или editor.or=или
editor.commit_changes=Промени в ревизия editor.commit_changes=Промени в ревизия
editor.add_tmpl=Добави '%s/<filename>' editor.add_tmpl=Добави '%s/<filename>'
@ -247,6 +262,7 @@ editor.update=Модифицирай '%s'
editor.delete=Изтрий '%s' editor.delete=Изтрий '%s'
editor.commit_directly_to_this_branch=Запази ревизия директно в клон <strong class="branch-name">%s</strong>. editor.commit_directly_to_this_branch=Запази ревизия директно в клон <strong class="branch-name">%s</strong>.
editor.create_new_branch=Създай <strong>нов клон</strong> от тази ревизия и изпрати заявки за сливане. editor.create_new_branch=Създай <strong>нов клон</strong> от тази ревизия и изпрати заявки за сливане.
editor.new_branch_name_desc=Име на новия клон…
editor.cancel=Отказ editor.cancel=Отказ
editor.branch_already_exists=Клон '%s' вече съществува в това хранилище. editor.branch_already_exists=Клон '%s' вече съществува в това хранилище.
editor.no_changes_to_show=Няма промени. editor.no_changes_to_show=Няма промени.
@ -255,6 +271,7 @@ editor.unable_to_upload_files=Невъзможно качване на файл
editor.upload_files_to_dir=Качи файлове в '%s' editor.upload_files_to_dir=Качи файлове в '%s'
commits.commits=Ревизии commits.commits=Ревизии
commits.find=Търсене
commits.author=Автор commits.author=Автор
commits.message=Съобщение commits.message=Съобщение
commits.date=Дата commits.date=Дата
@ -277,6 +294,7 @@ issues.create_label=Създай етикет
issues.label_templates.title=Зареждане на предварително зададен набор от етикети issues.label_templates.title=Зареждане на предварително зададен набор от етикети
issues.label_templates.helper=Изберете набор етикети issues.label_templates.helper=Изберете набор етикети
issues.label_templates.fail_to_load_file=Неуспешно зареждане на шаблон с етикети '%s': %v issues.label_templates.fail_to_load_file=Неуспешно зареждане на шаблон с етикети '%s': %v
issues.deleted_milestone=`(изтрито)`
issues.open_tab=%d отворени issues.open_tab=%d отворени
issues.close_tab=%d затворени issues.close_tab=%d затворени
issues.filter_label=Етикет issues.filter_label=Етикет
@ -294,6 +312,11 @@ issues.filter_sort.recentupdate=Последно променени
issues.filter_sort.leastupdate=Отдавна променени issues.filter_sort.leastupdate=Отдавна променени
issues.filter_sort.mostcomment=Най-много коментирани issues.filter_sort.mostcomment=Най-много коментирани
issues.filter_sort.leastcomment=Най-малко коментирани issues.filter_sort.leastcomment=Най-малко коментирани
issues.action_open=Отваряне
issues.action_close=Затваряне
issues.action_label=Етикет
issues.action_milestone=Етап
issues.action_milestone_no_select=Няма етап
issues.opened_by=отворен %[1]s от <a href="%[2]s">%[3]s</a> issues.opened_by=отворен %[1]s от <a href="%[2]s">%[3]s</a>
issues.opened_by_fake=отворен %[1]s от %[2]s issues.opened_by_fake=отворен %[1]s от %[2]s
issues.previous=Предишна issues.previous=Предишна
@ -323,9 +346,17 @@ issues.label_count=%d етикети
issues.label_open_issues=%d отворени задачи issues.label_open_issues=%d отворени задачи
issues.label_edit=Редакция issues.label_edit=Редакция
issues.label_delete=Изтрий issues.label_delete=Изтрий
issues.label.filter_sort.alphabetically=По азбучен ред
issues.label.filter_sort.by_size=Големина
issues.num_participants=%d участника issues.num_participants=%d участника
issues.attachment.open_tab=`Щракнете за да прегледате "%s" в нов раздел` issues.attachment.open_tab=`Щракнете за да прегледате "%s" в нов раздел`
issues.attachment.download=`Щракнете за да изтеглите "%s"` issues.attachment.download=`Щракнете за да изтеглите "%s"`
issues.start_tracking_short=Начало
issues.stop_tracking=Спиране
issues.add_time_cancel=Отказ
issues.add_time_hours=Часа
issues.add_time_minutes=Минути
issues.cancel_tracking=Отказ
pulls.new=Нова заявка за сливане pulls.new=Нова заявка за сливане
pulls.filter_branch=Филтър по клон pulls.filter_branch=Филтър по клон
@ -367,7 +398,19 @@ wiki.page_already_exists=Страница със същото име вече с
wiki.pages=Страници wiki.pages=Страници
wiki.last_updated=Последна модификация на %s wiki.last_updated=Последна модификация на %s
activity.period.filter_label=Период:
activity.period.daily=1 ден
activity.period.halfweekly=3 дни
activity.period.weekly=1 седмица
activity.period.monthly=1 месец
activity.title.user_1=%d потребител
activity.title.user_n=%d потребителя
activity.closed_issue_label=Затворено
activity.new_issue_label=Отворено
activity.unresolved_conv_label=Отваряне
activity.published_release_label=Публикувано
search=Търсене
settings=Настройки settings=Настройки
settings.collaboration.write=За писане settings.collaboration.write=За писане
@ -389,6 +432,7 @@ settings.transfer=Прехвърли притежание
settings.delete=Изтрий това хранилище settings.delete=Изтрий това хранилище
settings.delete_notices_1=- Тази операция <strong>НЕ МОЖЕ</strong> да бъде отменена в последствие. settings.delete_notices_1=- Тази операция <strong>НЕ МОЖЕ</strong> да бъде отменена в последствие.
settings.transfer_owner=Нов притежател settings.transfer_owner=Нов притежател
settings.search_user_placeholder=Търсене на потребител…
settings.add_webhook=Добави уеб-кука settings.add_webhook=Добави уеб-кука
settings.webhook.test_delivery=Тестово изпращане settings.webhook.test_delivery=Тестово изпращане
settings.webhook.request=Заявка settings.webhook.request=Заявка
@ -402,6 +446,8 @@ settings.update_githook=Запази куката
settings.secret=Тайна settings.secret=Тайна
settings.slack_username=Потребителско име settings.slack_username=Потребителско име
settings.slack_icon_url=URL адрес на икона settings.slack_icon_url=URL адрес на икона
settings.discord_username=Потребителско име
settings.discord_icon_url=URL адрес на икона
settings.slack_color=Цвят settings.slack_color=Цвят
settings.event_create=Създаване settings.event_create=Създаване
settings.event_pull_request=Заявка за сливане settings.event_pull_request=Заявка за сливане
@ -416,6 +462,11 @@ settings.deploy_keys=Ключове за внедряване
settings.add_deploy_key=Добави ключ за внедряване settings.add_deploy_key=Добави ключ за внедряване
settings.title=Заглавие settings.title=Заглавие
settings.deploy_key_content=Съдържание settings.deploy_key_content=Съдържание
settings.branches=Клонове
settings.protected_branch=Защита на клона
settings.add_protected_branch=Включване на защита
settings.delete_protected_branch=Изключване на защита
settings.choose_branch=Изберете клон…
diff.browse_source=Преглед на файлове diff.browse_source=Преглед на файлове
diff.parent=родител diff.parent=родител
@ -424,6 +475,7 @@ diff.show_diff_stats=Покажи статистика за разликите
diff.show_split_view=Разделен изглед diff.show_split_view=Разделен изглед
diff.show_unified_view=Обединен изглед diff.show_unified_view=Обединен изглед
diff.stats_desc=променени са <strong>%d файла</strong>, в които са <strong>добавени %d</strong> реда и са <strong>изтрити %d</strong> реда diff.stats_desc=променени са <strong>%d файла</strong>, в които са <strong>добавени %d</strong> реда и са <strong>изтрити %d</strong> реда
diff.bin=Двоични данни
diff.view_file=Целия файл diff.view_file=Целия файл
diff.file_suppressed=Файловите разлики са ограничени, защото са твърде много diff.file_suppressed=Файловите разлики са ограничени, защото са твърде много
diff.too_many_files=Някои файлове не бяха показани, защото твърде много файлове са промени diff.too_many_files=Някои файлове не бяха показани, защото твърде много файлове са промени
@ -442,11 +494,17 @@ release.title=Заглавие
release.content=Съдържание release.content=Съдържание
release.write=Редактор release.write=Редактор
release.preview=Преглед release.preview=Преглед
release.loading=Зарежда се…
release.cancel=Отказ release.cancel=Отказ
release.publish=Публикувай версия release.publish=Публикувай версия
release.save_draft=Запис на чернова release.save_draft=Запис на чернова
release.downloads=Изтегляния release.downloads=Изтегляния
branch.search=Търсене на клонове
branch.delete_head=Изтриване
branch.delete_html=Изтриване на клон
branch.create_from=от '%s'
branch.deleted_by=Изтрито от %s
[org] [org]
@ -458,6 +516,8 @@ people=Участници
teams=Екипи teams=Екипи
lower_members=участници lower_members=участници
lower_repositories=хранилища lower_repositories=хранилища
create_new_team=Нов отбор
create_team=Създаване на отбор
org_desc=Описание org_desc=Описание
team_name=Име на екипа team_name=Име на екипа
team_desc=Описание team_desc=Описание
@ -509,7 +569,6 @@ total=Общо: %d
dashboard.operation_name=Име на операцията dashboard.operation_name=Име на операцията
dashboard.operation_switch=Превключи dashboard.operation_switch=Превключи
dashboard.operation_run=Изпълни dashboard.operation_run=Изпълни
dashboard.delete_inactivate_accounts=Изтрий всички неактивни профили
dashboard.server_uptime=Операционно време dashboard.server_uptime=Операционно време
dashboard.current_goroutine=Текущи Goroutines dashboard.current_goroutine=Текущи Goroutines
dashboard.current_memory_usage=Текущо използвана памет dashboard.current_memory_usage=Текущо използвана памет
@ -546,6 +605,7 @@ users.edit=Редакция
users.auth_source=Начин на удостоверяване users.auth_source=Начин на удостоверяване
users.local=Локално users.local=Локално
orgs.org_manage_panel=Управление на организацията
orgs.name=Име orgs.name=Име
orgs.teams=Екипи orgs.teams=Екипи
orgs.members=Участници orgs.members=Участници
@ -556,6 +616,7 @@ repos.private=Частно
repos.watches=Наблюдавания repos.watches=Наблюдавания
repos.stars=Харесвания repos.stars=Харесвания
repos.issues=Задачи repos.issues=Задачи
repos.size=Големина
auths.name=Име auths.name=Име
auths.type=Тип auths.type=Тип
@ -580,12 +641,15 @@ auths.allowed_domains=Разрешени домейни
auths.enable_tls=Включи TLS криптиране auths.enable_tls=Включи TLS криптиране
auths.skip_tls_verify=Пропусни проверка на TLS сертификат auths.skip_tls_verify=Пропусни проверка на TLS сертификат
auths.pam_service_name=Име на PAM услуга auths.pam_service_name=Име на PAM услуга
auths.oauth2_profileURL=URL адрес на профила
auths.oauth2_emailURL=Имейл адрес
auths.enable_auto_register=Включи автоматична регистрация auths.enable_auto_register=Включи автоматична регистрация
auths.tips=Съвети auths.tips=Съвети
config.server_config=Сървърни настройки config.server_config=Сървърни настройки
config.disable_router_log=Изключи журнал на маршрутизатора config.disable_router_log=Изключи журнал на маршрутизатора
config.run_mode=Режим на изпълнение config.run_mode=Режим на изпълнение
config.git_version=Версия на Git
config.repo_root_path=Основен път към хранилища config.repo_root_path=Основен път към хранилища
config.static_file_root_path=Път към статични файлове config.static_file_root_path=Път към статични файлове
config.script_type=Тип на скрипта config.script_type=Тип на скрипта
@ -700,6 +764,7 @@ push_tag=предаде маркер <a href="%s/src/%s">%[2]s</a> към <a hre
ago=преди %s ago=преди %s
from_now=след %s from_now=след %s
now=сега now=сега
future=в бъдеще
1s=1 секунда 1s=1 секунда
1m=1 минута 1m=1 минута
1h=1 час 1h=1 час
@ -721,6 +786,12 @@ raw_minutes=минути
remove_file=Премахни файл remove_file=Премахни файл
[notification] [notification]
notifications=Известия
unread=Непрочетенo
read=За четене
mark_as_read=Бележа като прочетено
mark_as_unread=Бележа като непрочетено
mark_all_as_read=Бележа всичко като прочетено
[gpg] [gpg]

View File

@ -508,7 +508,6 @@ total=Celkem: %d
dashboard.operation_name=Název operace dashboard.operation_name=Název operace
dashboard.operation_switch=Přepnout dashboard.operation_switch=Přepnout
dashboard.operation_run=Spustit dashboard.operation_run=Spustit
dashboard.delete_inactivate_accounts=Smazat všechny neaktivní účty
dashboard.server_uptime=Doba provozu serveru dashboard.server_uptime=Doba provozu serveru
dashboard.current_goroutine=Aktuální Goroutines dashboard.current_goroutine=Aktuální Goroutines
dashboard.current_memory_usage=Aktuální využití paměti dashboard.current_memory_usage=Aktuální využití paměti

View File

@ -75,7 +75,6 @@ cancel=Abbrechen
[install] [install]
install=Installation install=Installation
title=Erstkonfiguration title=Erstkonfiguration
docker_helper=Wenn du Gitea in einem Docker-Container nutzt, lies bitte die <a target="_blank" rel="noopener" href="%s">Dokumentation</a>, bevor du irgendwelche Einstellungen veränderst.
requite_db_desc=Gitea benötigt MySQL, PostgreSQL, MSSQL, SQLite3 oder TiDB. requite_db_desc=Gitea benötigt MySQL, PostgreSQL, MSSQL, SQLite3 oder TiDB.
db_title=Datenbankeinstellungen db_title=Datenbankeinstellungen
db_type=Datenbanktyp db_type=Datenbanktyp
@ -98,13 +97,13 @@ app_name_helper=Du kannst hier den Namen deines Unternehmens eingeben.
repo_path=Repository-Verzeichnis repo_path=Repository-Verzeichnis
repo_path_helper=Remote-Git-Repositories werden in diesem Verzeichnis gespeichert. repo_path_helper=Remote-Git-Repositories werden in diesem Verzeichnis gespeichert.
lfs_path=Git-LFS-Wurzelpfad lfs_path=Git-LFS-Wurzelpfad
lfs_path_helper=In diesem Verzeichnis werden die Dateien von Git LFS abgespeichert. Leer lassen um LFS zu deaktivieren. lfs_path_helper=In diesem Verzeichnis werden die Dateien von Git LFS abgespeichert. Leer lassen, um LFS zu deaktivieren.
run_user=Ausführen als run_user=Ausführen als
run_user_helper=Gebe den Betriebssystem-Benutzernamen ein, unter welchem Gitea laufen soll. Beachte, dass dieser Nutzer Zugriff auf den Repository-Ordner haben muss. run_user_helper=Gib den Betriebssystem-Benutzernamen ein, unter welchem Gitea laufen soll. Beachte, dass dieser Nutzer Zugriff auf den Repository-Ordner haben muss.
domain=SSH-Server-Domain domain=SSH-Server-Domain
domain_helper=Domain oder Host-Adresse für die SSH-URL. domain_helper=Domain oder Host-Adresse für die SSH-URL.
ssh_port=SSH-Server-Port ssh_port=SSH-Server-Port
ssh_port_helper=Der Port deines SSH-Servers. Leer lassen um SSH zu deaktivieren. ssh_port_helper=Der Port deines SSH-Servers. Leer lassen, um SSH zu deaktivieren.
http_port=Gitea-HTTP-Listen-Port http_port=Gitea-HTTP-Listen-Port
http_port_helper=Port, unter dem der Gitea-Webserver laufen soll. http_port_helper=Port, unter dem der Gitea-Webserver laufen soll.
app_url=Gitea-Basis-URL app_url=Gitea-Basis-URL
@ -116,7 +115,7 @@ optional_title=Optionale Einstellungen
email_title=E-Mail-Einstellungen email_title=E-Mail-Einstellungen
smtp_host=SMTP-Server smtp_host=SMTP-Server
smtp_from=E-Mail senden als smtp_from=E-Mail senden als
smtp_from_helper=E-Mail-Adresse, die von Gitea genutzt werden soll. Bitte gib die E-Mail-Adresse im '"Name" <email@example.com>'-Format ein. smtp_from_helper=E-Mail-Adresse, die von Gitea genutzt werden soll. Bitte gib die E-Mail-Adresse im Format „"Name" <email@example.com>“ ein.
mailer_user=SMTP-Benutzername mailer_user=SMTP-Benutzername
mailer_password=SMTP-Passwort mailer_password=SMTP-Passwort
register_confirm=E-Mail-Bestätigung benötigt zum Registrieren register_confirm=E-Mail-Bestätigung benötigt zum Registrieren
@ -146,7 +145,7 @@ admin_password=Passwort
confirm_password=Passwort bestätigen confirm_password=Passwort bestätigen
admin_email=E-Mail-Adresse admin_email=E-Mail-Adresse
install_btn_confirm=Gitea installieren install_btn_confirm=Gitea installieren
test_git_failed=Fehler beim Test des 'git' Kommandos: %v test_git_failed=Fehler beim Test des „git“-Befehls: %v
sqlite3_not_available=Diese Gitea-Version unterstützt SQLite3 nicht. Bitte lade die offizielle binäre Version von %s herunter (nicht die „gobuild“-Version). sqlite3_not_available=Diese Gitea-Version unterstützt SQLite3 nicht. Bitte lade die offizielle binäre Version von %s herunter (nicht die „gobuild“-Version).
invalid_db_setting=Datenbankeinstellungen sind ungültig: %v invalid_db_setting=Datenbankeinstellungen sind ungültig: %v
invalid_repo_path=Repository-Verzeichnis ist ungültig: %v invalid_repo_path=Repository-Verzeichnis ist ungültig: %v
@ -188,7 +187,7 @@ repo_no_results=Keine passenden Repositories gefunden.
user_no_results=Keine passenden Benutzer gefunden. user_no_results=Keine passenden Benutzer gefunden.
org_no_results=Keine passenden Organisatioen gefunden. org_no_results=Keine passenden Organisatioen gefunden.
code_no_results=Es konnte kein passender Code für deinen Suchbegriff gefunden werden. code_no_results=Es konnte kein passender Code für deinen Suchbegriff gefunden werden.
code_search_results=Suchergebnisse für '%s' code_search_results=Suchergebnisse für „%s“
[auth] [auth]
create_new_account=Konto anlegen create_new_account=Konto anlegen
@ -254,12 +253,12 @@ HttpsUrl=HTTPS-URL
PayloadUrl=Payload-URL PayloadUrl=Payload-URL
TeamName=Teamname TeamName=Teamname
AuthName=Name der Autorisierung AuthName=Name der Autorisierung
AdminEmail=Administrator E-Mail AdminEmail=Administrator-E-Mail
NewBranchName=Neuer Branch Name NewBranchName=Neuer Branchname
CommitSummary=Commit Zusammenfassung CommitSummary=Commit-Zusammenfassung
CommitMessage=Commit Nachricht CommitMessage=Commit-Nachricht
CommitChoice=Commit Auswahl CommitChoice=Commit-Auswahl
TreeName=Dateipfad TreeName=Dateipfad
Content=Inhalt Content=Inhalt
@ -272,7 +271,7 @@ min_size_error=` muss mindestens %s Zeichen enthalten.`
max_size_error=` darf höchstens %s Zeichen enthalten.` max_size_error=` darf höchstens %s Zeichen enthalten.`
email_error=` ist keine gültige E-Mail-Adresse.` email_error=` ist keine gültige E-Mail-Adresse.`
url_error=` ist keine gültige URL.` url_error=` ist keine gültige URL.`
include_error=` muss den Text '%s' enthalten.` include_error=` muss den Text „%s“ enthalten.`
unknown_error=Unbekannter Fehler: unknown_error=Unbekannter Fehler:
captcha_incorrect=Der eingegebene CAPTCHA-Code ist falsch. captcha_incorrect=Der eingegebene CAPTCHA-Code ist falsch.
password_not_match=Die Passwörter stimmen nicht überein. password_not_match=Die Passwörter stimmen nicht überein.
@ -314,8 +313,8 @@ following=Folge ich
follow=Folgen follow=Folgen
unfollow=Nicht mehr folgen unfollow=Nicht mehr folgen
form.name_reserved=Der Benutzername '%s' ist reserviert. form.name_reserved=Der Benutzername „%s“ ist reserviert.
form.name_pattern_not_allowed='%s' ist nicht erlaubt für Benutzernamen. form.name_pattern_not_allowed=Das Muster „%s“ ist nicht in einem Benutzernamen erlaubt.
[settings] [settings]
profile=Profil profile=Profil
@ -323,7 +322,7 @@ account=Account
password=Passwort password=Passwort
security=Sicherheit security=Sicherheit
avatar=Profilbild avatar=Profilbild
ssh_gpg_keys=SSH / GPG Schlüssel ssh_gpg_keys=SSH- / GPG-Schlüssel
social=Soziale Konten social=Soziale Konten
applications=Anwendungen applications=Anwendungen
orgs=Organisationen verwalten orgs=Organisationen verwalten
@ -402,7 +401,7 @@ add_new_gpg_key=GPG-Schlüssel hinzufügen
ssh_key_been_used=Dieser SSH-Key wurde bereits zu deinem Account hinzugefügt. ssh_key_been_used=Dieser SSH-Key wurde bereits zu deinem Account hinzugefügt.
ssh_key_name_used=Ein gleichnamiger SSH-Key existiert bereits in deinem Account. ssh_key_name_used=Ein gleichnamiger SSH-Key existiert bereits in deinem Account.
gpg_key_id_used=Ein öffentlicher GPG-Schlüssel mit der gleichen ID existiert bereits. gpg_key_id_used=Ein öffentlicher GPG-Schlüssel mit der gleichen ID existiert bereits.
gpg_no_key_email_found=Dieser GPG Schlüssel kann mit keiner E-Mail-Adresse deines Accounts verwendet werden. gpg_no_key_email_found=Dieser GPG-Schlüssel kann mit keiner E-Mail-Adresse deines Kontos verwendet werden.
subkeys=Unterschlüssel subkeys=Unterschlüssel
key_id=Schlüssel-ID key_id=Schlüssel-ID
key_name=Schlüsselname key_name=Schlüsselname
@ -463,7 +462,7 @@ then_enter_passcode=Und gebe dann die angezeigte PIN der Anwendung ein:
passcode_invalid=Die PIN ist falsch. Probiere es erneut. passcode_invalid=Die PIN ist falsch. Probiere es erneut.
twofa_enrolled=Die Zwei-Faktor-Authentifizierung wurde für dein Konto aktiviert. Bewahre dein Einmalpasswort (%s) an einem sicheren Ort auf, da es nicht wieder angezeigt werden wird. twofa_enrolled=Die Zwei-Faktor-Authentifizierung wurde für dein Konto aktiviert. Bewahre dein Einmalpasswort (%s) an einem sicheren Ort auf, da es nicht wieder angezeigt werden wird.
u2f_desc=Hardware-Sicherheitsschlüssel sind Geräte, die kryptografische Schlüssel beinhalten. Diese können für die Zwei-Faktor-Authentifizierung verwendet werden. Der Sicherheitsschlüssel muss den <a href="https://fidoalliance.org/">FIDO U2F</a>-Standard unterstützen. u2f_desc=Hardware-Sicherheitsschlüssel sind Geräte, die kryptografische Schlüssel beinhalten. Diese können für die Zwei-Faktor-Authentifizierung verwendet werden. Der Sicherheitsschlüssel muss den Standard <a href="https://fidoalliance.org/">FIDO U2F</a> unterstützen.
u2f_require_twofa=Du musst die Zwei-Faktor-Authentifizierung aktivieren, um Hardware-Sicherheitsschlüssel nutzen zu können. u2f_require_twofa=Du musst die Zwei-Faktor-Authentifizierung aktivieren, um Hardware-Sicherheitsschlüssel nutzen zu können.
u2f_register_key=Sicherheitsschlüssel hinzufügen u2f_register_key=Sicherheitsschlüssel hinzufügen
u2f_nickname=Nickname u2f_nickname=Nickname
@ -482,7 +481,7 @@ orgs_none=Du bist kein Mitglied in einer Organisation.
repos_none=Du besitzt keine Repositories repos_none=Du besitzt keine Repositories
delete_account=Konto löschen delete_account=Konto löschen
delete_prompt=Wenn du fortfährst wird dein Account permanent gelöscht. Dies <strong>KANN NICHT</strong> rückgängig gemacht werden. delete_prompt=Wenn du fortfährst, wird dein Account permanent gelöscht. Dies <strong>KANN NICHT</strong> rückgängig gemacht werden.
confirm_delete_account=Löschen bestätigen confirm_delete_account=Löschen bestätigen
delete_account_title=Benutzerkonto löschen delete_account_title=Benutzerkonto löschen
delete_account_desc=Bist du sicher, dass du diesen Account dauerhaft löschen möchtest? delete_account_desc=Bist du sicher, dass du diesen Account dauerhaft löschen möchtest?
@ -492,13 +491,8 @@ owner=Besitzer
repo_name=Repository-Name repo_name=Repository-Name
repo_name_helper=Ein guter Repository-Name besteht normalerweise aus kurzen, unvergesslichen und einzigartigen Schlagwörtern. repo_name_helper=Ein guter Repository-Name besteht normalerweise aus kurzen, unvergesslichen und einzigartigen Schlagwörtern.
visibility=Sichtbarkeit visibility=Sichtbarkeit
visiblity_helper=privates Repository
visiblity_helper_forced=Auf dieser Gitea-Instanz können nur private Repositories angelegt werden.
visiblity_fork_helper=(Eine Änderung dieses Wertes wirkt sich auf alle Forks aus)
clone_helper=Brauchst du Hilfe beim Klonen? Öffne die <a target="_blank" rel="noopener" href="%s">Hilfe</a>.
fork_repo=Repository forken fork_repo=Repository forken
fork_from=Fork von fork_from=Fork von
fork_visiblity_helper=Die Sichtbarkeit einer geforkten Repository kann nicht geändert werden.
repo_desc=Beschreibung repo_desc=Beschreibung
repo_lang=Sprache repo_lang=Sprache
repo_gitignore_helper=Wähle eine .gitignore-Vorlage aus. repo_gitignore_helper=Wähle eine .gitignore-Vorlage aus.
@ -531,7 +525,7 @@ migrate_type=Migrationstyp
migrate_type_helper=Dieses Repository wird ein <span class="text blue">Mirror</span> sein migrate_type_helper=Dieses Repository wird ein <span class="text blue">Mirror</span> sein
migrate_repo=Repository migrieren migrate_repo=Repository migrieren
migrate.clone_address=Migrations- / Klon-URL migrate.clone_address=Migrations- / Klon-URL
migrate.clone_address_desc=Die HTTP(s) oder Klon-URL eines bereits existierenden Repositories migrate.clone_address_desc=Die HTTP(S)- oder „git clone“-URL eines bereits existierenden Repositorys
migrate.clone_local_path=oder ein lokaler Serverpfad migrate.clone_local_path=oder ein lokaler Serverpfad
migrate.permission_denied=Du hast keine Berechtigung zum Importieren lokaler Repositories. migrate.permission_denied=Du hast keine Berechtigung zum Importieren lokaler Repositories.
migrate.invalid_local_path=Der lokale Pfad ist ungültig, existiert nicht oder ist kein Ordner. migrate.invalid_local_path=Der lokale Pfad ist ungültig, existiert nicht oder ist kein Ordner.
@ -608,18 +602,17 @@ editor.create_new_branch=Einen <strong>neuen Branch</strong> für diesen Commit
editor.new_branch_name_desc=Neuer Branchname… editor.new_branch_name_desc=Neuer Branchname…
editor.cancel=Abbrechen editor.cancel=Abbrechen
editor.filename_cannot_be_empty=Der Dateiname darf nicht leer sein. editor.filename_cannot_be_empty=Der Dateiname darf nicht leer sein.
editor.branch_already_exists=Branch '%s' existiert bereits in diesem Repository. editor.branch_already_exists=Branch „%s“ existiert bereits in diesem Repository.
editor.directory_is_a_file=Der Verzeichnisname „%s“ wird bereits als Dateiname in diesem Repository verwendet. editor.directory_is_a_file=Der Verzeichnisname „%s“ wird bereits als Dateiname in diesem Repository verwendet.
editor.file_is_a_symlink='%s' ist ein symolischer Link. Symbolische Links können mit dem Web Editor nicht bearbeitet werden. editor.file_is_a_symlink='%s' ist ein symolischer Link. Symbolische Links können mit dem Web Editor nicht bearbeitet werden.
editor.filename_is_a_directory=Der Dateiname „%s“ wird bereits als Verzeichnisname in diesem Repository verwendet. editor.filename_is_a_directory=Der Dateiname „%s“ wird bereits als Verzeichnisname in diesem Repository verwendet.
editor.file_editing_no_longer_exists=Die bearbeitete Datei „%s“ existiert nicht mehr in diesem Repository. editor.file_editing_no_longer_exists=Die bearbeitete Datei „%s“ existiert nicht mehr in diesem Repository.
editor.file_changed_while_editing=Der Inhalt der Datei hat sich seit dem Beginn der Bearbeitung geändert. <a target="_blank" rel="noopener" href="%s">Hier klicken</a>, um die Änderungen anzusehen, oder <strong>Änderungen erneut comitten</strong>, um sie zu überschreiben.
editor.file_already_exists=Eine Datei mit dem Namen „%s“ ist bereits in diesem Repository vorhanden. editor.file_already_exists=Eine Datei mit dem Namen „%s“ ist bereits in diesem Repository vorhanden.
editor.no_changes_to_show=Keine Änderungen vorhanden. editor.no_changes_to_show=Keine Änderungen vorhanden.
editor.fail_to_update_file=Fehler beim Ändern/Erstellen der Datei '%s'. Fehler: %v editor.fail_to_update_file=Fehler beim Ändern/Erstellen der Datei „%s“. Fehler: %v
editor.add_subdir=Verzeichnis erstellen… editor.add_subdir=Verzeichnis erstellen…
editor.unable_to_upload_files=Fehler beim Hochladen der Dateien nach „%s“. Fehler: %v editor.unable_to_upload_files=Fehler beim Hochladen der Dateien nach „%s“. Fehler: %v
editor.upload_files_to_dir=Dateien hochladen nach '%s' editor.upload_files_to_dir=Dateien hochladen nach „%s“
editor.cannot_commit_to_protected_branch=Commit in den geschützten Branch „%s“ ist nicht möglich. editor.cannot_commit_to_protected_branch=Commit in den geschützten Branch „%s“ ist nicht möglich.
commits.desc=Durchsuche die Quellcode-Änderungshistorie. commits.desc=Durchsuche die Quellcode-Änderungshistorie.
@ -639,10 +632,10 @@ ext_issues=Externe Issues
ext_issues.desc=Link zu externem Issuetracker. ext_issues.desc=Link zu externem Issuetracker.
issues.desc=Verwalte Bug-Reports, Aufgaben und Meilensteine. issues.desc=Verwalte Bug-Reports, Aufgaben und Meilensteine.
issues.new=Neuer Issue issues.new=Neues Issue
issues.new.labels=Label issues.new.labels=Label
issues.new.no_label=Kein Label issues.new.no_label=Kein Label
issues.new.clear_labels=Labels entfernen issues.new.clear_labels=Label entfernen
issues.new.milestone=Meilenstein issues.new.milestone=Meilenstein
issues.new.no_milestone=Kein Meilenstein issues.new.no_milestone=Kein Meilenstein
issues.new.clear_milestone=Meilenstein entfernen issues.new.clear_milestone=Meilenstein entfernen
@ -659,9 +652,9 @@ issues.new_label_desc_placeholder=Beschreibung
issues.create_label=Label erstellen issues.create_label=Label erstellen
issues.label_templates.title=Lade vordefinierte Label issues.label_templates.title=Lade vordefinierte Label
issues.label_templates.info=Es existieren noch keine Label. Erstelle ein neues Label („Neues Label“) oder verwende das Standard-Label-Set: issues.label_templates.info=Es existieren noch keine Label. Erstelle ein neues Label („Neues Label“) oder verwende das Standard-Label-Set:
issues.label_templates.helper=Wähle ein Label issues.label_templates.helper=Wähle ein Label-Set
issues.label_templates.use=Label-Set verwenden issues.label_templates.use=Label-Set verwenden
issues.label_templates.fail_to_load_file=Fehler beim Laden der Label Template Datei '%s': %v issues.label_templates.fail_to_load_file=Fehler beim Laden der Label-Vorlagendatei „%s“: %v
issues.add_label_at=hat das <div class="ui label"style="color: %s\; background-color: %s">%s</div>-Label %s hinzugefügt issues.add_label_at=hat das <div class="ui label"style="color: %s\; background-color: %s">%s</div>-Label %s hinzugefügt
issues.remove_label_at=hat das <div class="ui label"style="color: %s\; background-color: %s">%s</div>-Label %s entfernt issues.remove_label_at=hat das <div class="ui label"style="color: %s\; background-color: %s">%s</div>-Label %s entfernt
issues.add_milestone_at=`hat diesen Issue %[2]s zum <b>%[1]s</b> Meilenstein hinzugefügt` issues.add_milestone_at=`hat diesen Issue %[2]s zum <b>%[1]s</b> Meilenstein hinzugefügt`
@ -745,8 +738,8 @@ issues.label.filter_sort.reverse_alphabetically=Umgekehrt alphabetisch
issues.label.filter_sort.by_size=Kleinste zuerst issues.label.filter_sort.by_size=Kleinste zuerst
issues.label.filter_sort.reverse_by_size=Größte zuerst issues.label.filter_sort.reverse_by_size=Größte zuerst
issues.num_participants=%d Beteiligte issues.num_participants=%d Beteiligte
issues.attachment.open_tab=`Klicken um "%s" in einem neuen Tab zu öffnen` issues.attachment.open_tab=`Klicken, um „%s“ in einem neuen Tab zu öffnen`
issues.attachment.download=`Klicken um "%s" herunterzuladen` issues.attachment.download=`Klicken, um „%s“ herunterzuladen`
issues.subscribe=Abonnieren issues.subscribe=Abonnieren
issues.unsubscribe=Abbestellen issues.unsubscribe=Abbestellen
issues.tracker=Zeiterfassung issues.tracker=Zeiterfassung
@ -914,7 +907,7 @@ search.search_repo=Repository durchsuchen
search.results=Suchergebnisse für „%s“ in <a href="%s"> %s</a> search.results=Suchergebnisse für „%s“ in <a href="%s"> %s</a>
settings=Einstellungen settings=Einstellungen
settings.desc=In den Einstellungen kannst du die Einstellungen des Repository anpassen settings.desc=In den Einstellungen kannst du die Einstellungen des Repositorys anpassen
settings.options=Repository settings.options=Repository
settings.collaboration=Mitarbeiter settings.collaboration=Mitarbeiter
settings.collaboration.admin=Administrator settings.collaboration.admin=Administrator
@ -924,7 +917,7 @@ settings.collaboration.undefined=Nicht definiert
settings.hooks=Webhooks settings.hooks=Webhooks
settings.githooks=Git-Hooks settings.githooks=Git-Hooks
settings.basic_settings=Grundeinstellungen settings.basic_settings=Grundeinstellungen
settings.mirror_settings=Mirror Einstellungen settings.mirror_settings=Mirror-Einstellungen
settings.sync_mirror=Jetzt synchronisieren settings.sync_mirror=Jetzt synchronisieren
settings.mirror_sync_in_progress=Mirror-Synchronisierung wird zurzeit ausgeführt. Komm in ein paar Minuten zurück. settings.mirror_sync_in_progress=Mirror-Synchronisierung wird zurzeit ausgeführt. Komm in ein paar Minuten zurück.
settings.site=Webseite settings.site=Webseite
@ -933,13 +926,13 @@ settings.advanced_settings=Erweiterte Einstellungen
settings.wiki_desc=Repository-Wiki aktivieren settings.wiki_desc=Repository-Wiki aktivieren
settings.use_internal_wiki=Eingebautes Wiki verwenden settings.use_internal_wiki=Eingebautes Wiki verwenden
settings.use_external_wiki=Externes Wiki verwenden settings.use_external_wiki=Externes Wiki verwenden
settings.external_wiki_url=Externe Wiki URL settings.external_wiki_url=Externe Wiki-URL
settings.external_wiki_url_error=Die externe Wiki-URL ist ungültig. settings.external_wiki_url_error=Die externe Wiki-URL ist ungültig.
settings.external_wiki_url_desc=Besucher werden auf die externe Wiki-URL weitergeleitet, wenn sie auf das Wiki-Tab klicken. settings.external_wiki_url_desc=Besucher werden auf die externe Wiki-URL weitergeleitet, wenn sie auf das Wiki-Tab klicken.
settings.issues_desc=Repository-Issue-Tracker aktivieren settings.issues_desc=Repository-Issue-Tracker aktivieren
settings.use_internal_issue_tracker=Integrierten Issue-Tracker verwenden settings.use_internal_issue_tracker=Integrierten Issue-Tracker verwenden
settings.use_external_issue_tracker=Externen Issue-Tracker verwenden settings.use_external_issue_tracker=Externen Issue-Tracker verwenden
settings.external_tracker_url=URL eines externen Issue Trackers settings.external_tracker_url=URL eines externen Issue-Trackers
settings.external_tracker_url_error=Die URL des externen Issue-Trackers ist ungültig. settings.external_tracker_url_error=Die URL des externen Issue-Trackers ist ungültig.
settings.external_tracker_url_desc=Besucher werden auf die externe Issue-Tracker-URL weitergeleitet, wenn sie auf das Issues-Tab klicken. settings.external_tracker_url_desc=Besucher werden auf die externe Issue-Tracker-URL weitergeleitet, wenn sie auf das Issues-Tab klicken.
settings.tracker_url_format=URL-Format des externen Issue-Systems settings.tracker_url_format=URL-Format des externen Issue-Systems
@ -975,7 +968,7 @@ settings.confirm_wiki_delete=Wiki-Daten löschen
settings.wiki_deletion_success=Repository-Wiki-Daten wurden gelöscht. settings.wiki_deletion_success=Repository-Wiki-Daten wurden gelöscht.
settings.delete=Dieses Repository löschen settings.delete=Dieses Repository löschen
settings.delete_desc=Wenn dieses Repository gelöscht wurde, gibt es keinen Weg zurück. Bitte sei vorsichtig. settings.delete_desc=Wenn dieses Repository gelöscht wurde, gibt es keinen Weg zurück. Bitte sei vorsichtig.
settings.delete_notices_1=- Diese Operation kann <strong>NICHT</strong> rückgängig gemacht werden. settings.delete_notices_1= Diese Operation <strong>KANN NICHT</strong> rückgängig gemacht werden.
settings.delete_notices_2= Die Operation wird das <strong>%s</strong>-Repository dauerhaft löschen, inklusive der Dateien, Issues, Kommentare und Zugriffseinstellungen. settings.delete_notices_2= Die Operation wird das <strong>%s</strong>-Repository dauerhaft löschen, inklusive der Dateien, Issues, Kommentare und Zugriffseinstellungen.
settings.delete_notices_fork_1= Forks dieses Repositorys werden nach dem Löschen unabhängig. settings.delete_notices_fork_1= Forks dieses Repositorys werden nach dem Löschen unabhängig.
settings.deletion_success=Das Repository wurde gelöscht. settings.deletion_success=Das Repository wurde gelöscht.
@ -994,7 +987,6 @@ settings.search_user_placeholder=Benutzer suchen…
settings.org_not_allowed_to_be_collaborator=Organisationen können nicht als Mitarbeiter hinzugefügt werden. settings.org_not_allowed_to_be_collaborator=Organisationen können nicht als Mitarbeiter hinzugefügt werden.
settings.user_is_org_member=Der Benutzer ist ein Organisationsmitglied und kann nicht als Mitarbeiter hinzugefügt werden. settings.user_is_org_member=Der Benutzer ist ein Organisationsmitglied und kann nicht als Mitarbeiter hinzugefügt werden.
settings.add_webhook=Webhook hinzufügen settings.add_webhook=Webhook hinzufügen
settings.hooks_desc=Webhooks senden bei bestimmten Gitea-Events automatisch „HTTP POST“-Anfragen an einen Server. Lies mehr in unserer <a target="_blank" rel="noopener" href="%s">Anleitung zu Webhooks (auf Englisch)</a>.
settings.webhook_deletion=Webhook löschen settings.webhook_deletion=Webhook löschen
settings.webhook_deletion_desc=Das Entfernen eines Webhooks löscht seine Einstellungen und Zustellungsverlauf. Fortfahren? settings.webhook_deletion_desc=Das Entfernen eines Webhooks löscht seine Einstellungen und Zustellungsverlauf. Fortfahren?
settings.webhook_deletion_success=Webhook wurde entfernt. settings.webhook_deletion_success=Webhook wurde entfernt.
@ -1011,7 +1003,6 @@ settings.githook_edit_desc=Wenn ein Hook nicht aktiv ist, wird der Standardinhal
settings.githook_name=Hook-Name settings.githook_name=Hook-Name
settings.githook_content=Hook-Inhalt settings.githook_content=Hook-Inhalt
settings.update_githook=Hook aktualisieren settings.update_githook=Hook aktualisieren
settings.add_webhook_desc=Gitea sendet einen <code>POST</code>-Request mit festgelegtem Content-Type an die Ziel-URL. Mehr Informationen findest du in der <a target="_blank" rel="noopener" href="%s">Anleitung zu Webhooks (Englisch)</a>.
settings.payload_url=Ziel-URL settings.payload_url=Ziel-URL
settings.content_type=POST-Content-Type settings.content_type=POST-Content-Type
settings.secret=Secret settings.secret=Secret
@ -1049,7 +1040,7 @@ settings.update_webhook=Webhook aktualisieren
settings.update_hook_success=Webhook wurde aktualisiert. settings.update_hook_success=Webhook wurde aktualisiert.
settings.delete_webhook=Webhook entfernen settings.delete_webhook=Webhook entfernen
settings.recent_deliveries=Letzte Zustellungen settings.recent_deliveries=Letzte Zustellungen
settings.hook_type=Hook Typ settings.hook_type=Hook-Typ
settings.add_slack_hook_desc=<a href="%s">Slack</a>-Integration zu deinem Repository hinzufügen. settings.add_slack_hook_desc=<a href="%s">Slack</a>-Integration zu deinem Repository hinzufügen.
settings.slack_token=Token settings.slack_token=Token
settings.slack_domain=Domain settings.slack_domain=Domain
@ -1077,7 +1068,7 @@ settings.protected_branch_can_push_yes=Du kannst pushen
settings.protected_branch_can_push_no=Du kannst nicht pushen settings.protected_branch_can_push_no=Du kannst nicht pushen
settings.branch_protection=Branch-Schutz für Branch „<b>%s</b>“ settings.branch_protection=Branch-Schutz für Branch „<b>%s</b>“
settings.protect_this_branch=Brach-Schutz aktivieren settings.protect_this_branch=Brach-Schutz aktivieren
settings.protect_this_branch_desc=Verhindere Löschen und deaktiviere das sog. „force pushing” von Git auf diesen Branch. settings.protect_this_branch_desc=Verhindere Löschen und deaktiviere das „force pushing” von Git auf diesen Branch.
settings.protect_whitelist_committers=Push-Whitelist aktivieren settings.protect_whitelist_committers=Push-Whitelist aktivieren
settings.protect_whitelist_committers_desc=Erlaube Nutzern oder Teams auf der Whitelist Push-Beschränkungen zu umgehen. settings.protect_whitelist_committers_desc=Erlaube Nutzern oder Teams auf der Whitelist Push-Beschränkungen zu umgehen.
settings.protect_whitelist_users=Nutzer, die pushen dürfen: settings.protect_whitelist_users=Nutzer, die pushen dürfen:
@ -1155,9 +1146,9 @@ branch.deletion_success=Branch „%s“ wurde gelöscht.
branch.deletion_failed=Branch „%s“ konnte nicht gelöscht werden. branch.deletion_failed=Branch „%s“ konnte nicht gelöscht werden.
branch.delete_branch_has_new_commits=Der Branch „%s“ kann nicht gelöscht weden, da seit dem letzten Merge neue Commits hinzugefügt wurden. branch.delete_branch_has_new_commits=Der Branch „%s“ kann nicht gelöscht weden, da seit dem letzten Merge neue Commits hinzugefügt wurden.
branch.create_branch=Erstelle Branch <strong>%s</strong> branch.create_branch=Erstelle Branch <strong>%s</strong>
branch.create_from=von '%s' branch.create_from=von „%s“
branch.create_success=Branch „%s“ wurde erstellt. branch.create_success=Branch „%s“ wurde erstellt.
branch.branch_already_exists=Branch '%s' existiert bereits in diesem Repository. branch.branch_already_exists=Branch „%s“ existiert bereits in diesem Repository.
branch.branch_name_conflict=Der Branch-Name „%s“ steht in Konflikt mit dem bestehenden Branch „%s“. branch.branch_name_conflict=Der Branch-Name „%s“ steht in Konflikt mit dem bestehenden Branch „%s“.
branch.tag_collision=Branch „%s“ kann nicht erstellt werden, da in diesem Repository bereits ein Tag mit dem selben Namen existiert. branch.tag_collision=Branch „%s“ kann nicht erstellt werden, da in diesem Repository bereits ein Tag mit dem selben Namen existiert.
branch.deleted_by=Von %s gelöscht branch.deleted_by=Von %s gelöscht
@ -1206,7 +1197,7 @@ settings.update_avatar_success=Der Organisationsavatar wurde aktualisiert.
settings.delete=Organisation löschen settings.delete=Organisation löschen
settings.delete_account=Diese Organisation löschen settings.delete_account=Diese Organisation löschen
settings.delete_prompt=Die Organisation wird dauerhaft gelöscht. Dies <strong>KANN NICHT</strong> rückgängig gemacht werden! settings.delete_prompt=Die Organisation wird dauerhaft gelöscht. Dies <strong>KANN NICHT</strong> rückgängig gemacht werden!
settings.confirm_delete_account=Löschen settings.confirm_delete_account=Löschen bestätigen
settings.delete_org_title=Organisation löschen settings.delete_org_title=Organisation löschen
settings.delete_org_desc=Diese Organisation wird dauerhaft gelöscht. Fortfahren? settings.delete_org_desc=Diese Organisation wird dauerhaft gelöscht. Fortfahren?
settings.hooks_desc=Webhooks hinzufügen, die für <strong>alle</strong> Repositories dieser Organisation ausgelöst werden. settings.hooks_desc=Webhooks hinzufügen, die für <strong>alle</strong> Repositories dieser Organisation ausgelöst werden.
@ -1267,14 +1258,12 @@ total=Gesamt: %d
dashboard.statistic=Übersicht dashboard.statistic=Übersicht
dashboard.operations=Wartungsoperationen dashboard.operations=Wartungsoperationen
dashboard.system_status=System-Status dashboard.system_status=System-Status
dashboard.statistic_info=Gitea's Datenbank hat <b>%d</b> Benutzer, <b>%d</b> Organisationen, <b>%d</b> öffentliche Schlüssel, <b>%d</b> Repositories, <b>%d</b> Beobachtungen, <b>%d</b> Favoriten, <b>%d</b> Aktionen, <b>%d</b> Zugriffe, <b>%d</b> Issues, <b>%d</b> Kommentare, <b>%d</b> Konten sozialer Netzwerke, <b>%d</b> Gefolgte, <b>%d</b> Mirrors, <b>%d</b> Releases, <b>%d</b> Login-Quellen, <b>%d</b> Webhooks, <b>%d</b> Meilensteine, <b>%d</b> Label, <b>%d</b> Hook-Tasks, <b>%d</b> Teams, <b>%d</b> Aktualisierungs-Tasks, <b>%d</b> Anhänge. dashboard.statistic_info=Giteas Datenbank hat <b>%d</b> Benutzer, <b>%d</b> Organisationen, <b>%d</b> öffentliche Schlüssel, <b>%d</b> Repositorys, <b>%d</b> Beobachtungen, <b>%d</b> Favoriten, <b>%d</b> Aktionen, <b>%d</b> Zugriffe, <b>%d</b> Issues, <b>%d</b> Kommentare, <b>%d</b> Konten sozialer Netzwerke, <b>%d</b> Gefolgte, <b>%d</b> Mirrors, <b>%d</b> Releases, <b>%d</b> Login-Quellen, <b>%d</b> Webhooks, <b>%d</b> Meilensteine, <b>%d</b> Label, <b>%d</b> Hook-Tasks, <b>%d</b> Teams, <b>%d</b> Aktualisierungs-Tasks, <b>%d</b> Anhänge.
dashboard.operation_name=Name der Operation dashboard.operation_name=Name der Operation
dashboard.operation_switch=Wechseln dashboard.operation_switch=Wechseln
dashboard.operation_run=Ausführen dashboard.operation_run=Ausführen
dashboard.clean_unbind_oauth=Nicht verbundene OAuth-Verbindungen löschen dashboard.clean_unbind_oauth=Nicht verbundene OAuth-Verbindungen löschen
dashboard.clean_unbind_oauth_success=Alle unverbundene OAuth-Verbindungen wurden gelöscht. dashboard.clean_unbind_oauth_success=Alle unverbundene OAuth-Verbindungen wurden gelöscht.
dashboard.delete_inactivate_accounts=Deaktivierte Konten löschen
dashboard.delete_inactivate_accounts_success=Alle deaktivierten Konten wurden erfolgreich gelöscht.
dashboard.delete_repo_archives=Alle Repository-Archive löschen dashboard.delete_repo_archives=Alle Repository-Archive löschen
dashboard.delete_repo_archives_success=Alle Repository-Archive wurden gelöscht. dashboard.delete_repo_archives_success=Alle Repository-Archive wurden gelöscht.
dashboard.delete_missing_repos=Alle Repository-Datensätze mit verlorenen gegangenen Git-Dateien löschen dashboard.delete_missing_repos=Alle Repository-Datensätze mit verlorenen gegangenen Git-Dateien löschen
@ -1283,7 +1272,7 @@ dashboard.git_gc_repos=Garbage-Collection auf Repositories ausführen
dashboard.git_gc_repos_success=Alle Repositories haben Garbage-Collection beendet. dashboard.git_gc_repos_success=Alle Repositories haben Garbage-Collection beendet.
dashboard.resync_all_sshkeys=„.ssh/authorized_keys“-Datei mit Gitea-SSH-Keys neu schreiben. (Wenn Du den eingebauten SSH-Server nutzt, musst du das nicht ausführen.) dashboard.resync_all_sshkeys=„.ssh/authorized_keys“-Datei mit Gitea-SSH-Keys neu schreiben. (Wenn Du den eingebauten SSH-Server nutzt, musst du das nicht ausführen.)
dashboard.resync_all_sshkeys_success=Alle von Gitea verwalteten öffentlichen Schlüssel wurden neu geschrieben. dashboard.resync_all_sshkeys_success=Alle von Gitea verwalteten öffentlichen Schlüssel wurden neu geschrieben.
dashboard.resync_all_hooks=Synchronisiere „pre-receive“-, „update“- und „post-receive“-Hooks für alle Repositorys erneut. dashboard.resync_all_hooks=Synchronisiere „pre-receive“-, „update“- und „post-receive“-Hooks für alle Repositories erneut.
dashboard.resync_all_hooks_success=Alle „pre-receive“-, „update“- und „post-receive“-Repository-Hooks wurden erneut synchronisiert. dashboard.resync_all_hooks_success=Alle „pre-receive“-, „update“- und „post-receive“-Repository-Hooks wurden erneut synchronisiert.
dashboard.reinit_missing_repos=Alle Git-Repositories mit Einträgen neu einlesen dashboard.reinit_missing_repos=Alle Git-Repositories mit Einträgen neu einlesen
dashboard.reinit_missing_repos_success=Alle verlorenen Git-Repositories mit existierenden Einträgen wurden erfolgreich aktualisiert. dashboard.reinit_missing_repos_success=Alle verlorenen Git-Repositories mit existierenden Einträgen wurden erfolgreich aktualisiert.
@ -1331,13 +1320,13 @@ users.created=Registriert am
users.last_login=Letzte Anmeldung users.last_login=Letzte Anmeldung
users.never_login=Hat sich noch nie eingeloggt users.never_login=Hat sich noch nie eingeloggt
users.send_register_notify=Benutzer-Registrierungsbenachrichtigung senden users.send_register_notify=Benutzer-Registrierungsbenachrichtigung senden
users.new_success=Der Account '%s' wurde erstellt. users.new_success=Der Account „%s“ wurde erstellt.
users.edit=Bearbeiten users.edit=Bearbeiten
users.auth_source=Authentifizierungsquelle users.auth_source=Authentifizierungsquelle
users.local=Lokal users.local=Lokal
users.auth_login_name=Anmeldename zur Authentifizierung users.auth_login_name=Anmeldename zur Authentifizierung
users.password_helper=Passwort leerlassen, um es nicht zu verändern. users.password_helper=Passwort leerlassen, um es nicht zu verändern.
users.update_profile_success=Der Account '%s' wurde aktualisiert. users.update_profile_success=Der Account „%s“ wurde aktualisiert.
users.edit_account=Benutzerkonto bearbeiten users.edit_account=Benutzerkonto bearbeiten
users.max_repo_creation=Maximale Anzahl Repositories users.max_repo_creation=Maximale Anzahl Repositories
users.max_repo_creation_desc=(Gib -1 ein, um das globale Standardlimit zu verwenden.) users.max_repo_creation_desc=(Gib -1 ein, um das globale Standardlimit zu verwenden.)
@ -1384,7 +1373,7 @@ auths.host=Host
auths.port=Port auths.port=Port
auths.bind_dn=DN binden auths.bind_dn=DN binden
auths.bind_password=Passwort binden auths.bind_password=Passwort binden
auths.bind_password_helper=Achtung: Das Passwort wird im Klartext gespeichert. Benutze wenn möglich einen Account mit nur Lesezugriff. auths.bind_password_helper=Achtung: Das Passwort wird im Klartext gespeichert. Benutze, wenn möglich, einen Account, der nur über Lesezugriff verfügt.
auths.user_base=Basis für Benutzersuche auths.user_base=Basis für Benutzersuche
auths.user_dn=Benutzer-DN auths.user_dn=Benutzer-DN
auths.attribute_username=Benutzernamens-Attribut auths.attribute_username=Benutzernamens-Attribut
@ -1427,7 +1416,7 @@ auths.tip.facebook=Erstelle eine neue Anwendung auf https://developers.facebook.
auths.tip.github=Erstelle unter https://github.com/settings/applications/new eine neue OAuth-Anwendung. auths.tip.github=Erstelle unter https://github.com/settings/applications/new eine neue OAuth-Anwendung.
auths.tip.gitlab=Erstelle unter https://gitlab.com/profile/applications eine neue Anwendung. auths.tip.gitlab=Erstelle unter https://gitlab.com/profile/applications eine neue Anwendung.
auths.tip.google_plus=Du erhältst die OAuth2-Client-Zugangsdaten in der Google-API-Konsole unter https://console.developers.google.com/ auths.tip.google_plus=Du erhältst die OAuth2-Client-Zugangsdaten in der Google-API-Konsole unter https://console.developers.google.com/
auths.tip.openid_connect=Benutze die OpenID Connect Discovery URL (<server>/.well-known/openid-configuration) als Endpunkt. auths.tip.openid_connect=Benutze die OpenID-Connect-Discovery-URL (<server>/.well-known/openid-configuration), um die Endpunkte zu spezifizieren
auths.tip.twitter=Gehe auf https://dev.twitter.com/apps, erstelle eine Anwendung und stelle sicher, dass die Option „Allow this application to be used to Sign in with Twitter“ aktiviert ist auths.tip.twitter=Gehe auf https://dev.twitter.com/apps, erstelle eine Anwendung und stelle sicher, dass die Option „Allow this application to be used to Sign in with Twitter“ aktiviert ist
auths.edit=Authentifikationsquelle bearbeiten auths.edit=Authentifikationsquelle bearbeiten
auths.activated=Diese Authentifikationsquelle ist aktiviert auths.activated=Diese Authentifikationsquelle ist aktiviert
@ -1584,13 +1573,13 @@ notices.delete_success=Diese Systemmeldung wurde gelöscht.
create_repo=hat das Repository <a href="%s">%s</a> erstellt create_repo=hat das Repository <a href="%s">%s</a> erstellt
rename_repo=hat das Repository von <code>%[1]s</code> zu <a href="%[2]s">%[3]s</a> umbenannt rename_repo=hat das Repository von <code>%[1]s</code> zu <a href="%[2]s">%[3]s</a> umbenannt
commit_repo=hat auf <a href="%[1]s/src/%[2]s">%[3]s</a> in <a href="%[1]s">%[4]s</a> gepusht commit_repo=hat auf <a href="%[1]s/src/%[2]s">%[3]s</a> in <a href="%[1]s">%[4]s</a> gepusht
create_issue=`hat den Issue <a href="%s/issues/%s">%s#%[2]s</a> geöffnet` create_issue=`hat das Issue <a href="%s/issues/%s">%s#%[2]s</a> geöffnet`
close_issue=`hat den Issue <a href="%s/issues/%s">%s#%[2]s</a> geschlossen` close_issue=`hat das Issue <a href="%s/issues/%s">%s#%[2]s</a> geschlossen`
reopen_issue=`hat den Issue <a href="%s/issues/%s">%s#%[2]s</a> wieder geöffnet` reopen_issue=`hat das Issue <a href="%s/issues/%s">%s#%[2]s</a> erneut geöffnet`
create_pull_request=`hat den Pull-Request <a href="%s/pulls/%s">%s#%[2]s</a> erstellt` create_pull_request=`hat den Pull-Request <a href="%s/pulls/%s">%s#%[2]s</a> erstellt`
close_pull_request=`hat den Pull-Request <a href="%s/pulls/%s">%s#%[2]s</a> geschlossen` close_pull_request=`hat den Pull-Request <a href="%s/pulls/%s">%s#%[2]s</a> geschlossen`
reopen_pull_request=`hat den Pull-Request <a href="%s/pulls/%s">%s#%[2]s</a> wieder geöffnet` reopen_pull_request=`hat den Pull-Request <a href="%s/pulls/%s">%s#%[2]s</a> wieder geöffnet`
comment_issue=`hat den Issue <a href="%s/issues/%s">%s#%[2]s</a> kommentiert` comment_issue=`hat das Issue <a href="%s/issues/%s">%s#%[2]s</a> kommentiert`
merge_pull_request=`hat den Pull-Request <a href="%s/pulls/%s">%s#%[2]s</a> zusammengeführt` merge_pull_request=`hat den Pull-Request <a href="%s/pulls/%s">%s#%[2]s</a> zusammengeführt`
transfer_repo=hat Repository <code>%s</code> transferiert an <a href="%s">%s</a> transfer_repo=hat Repository <code>%s</code> transferiert an <a href="%s">%s</a>
push_tag=hat Tag <a href="%s/src/%s">%[2]s</a> auf <a href="%[1]s">%[3]s</a> gepusht push_tag=hat Tag <a href="%s/src/%s">%[2]s</a> auf <a href="%[1]s">%[3]s</a> gepusht
@ -1640,7 +1629,7 @@ mark_all_as_read=Alle als gelesen markieren
[gpg] [gpg]
error.extract_sign=Die Signatur konnte nicht extrahiert werden error.extract_sign=Die Signatur konnte nicht extrahiert werden
error.generate_hash=Es konnte kein Hash vom Commit generiert werden error.generate_hash=Es konnte kein Hash vom Commit generiert werden
error.no_committer_account=Es ist kein Benutzerkonto mit der E-Mail-Adresse des Committers verbunden error.no_committer_account=Es ist kein Account mit der E-Mail-Adresse des Committers verbunden
error.no_gpg_keys_found=Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden error.no_gpg_keys_found=Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden
error.not_signed_commit=Kein signierter Commit error.not_signed_commit=Kein signierter Commit
error.failed_retrieval_gpg_keys=Fehler beim Abrufen eines Keys des Commiter-Kontos error.failed_retrieval_gpg_keys=Fehler beim Abrufen eines Keys des Commiter-Kontos

View File

@ -75,7 +75,7 @@ cancel = Cancel
[install] [install]
install = Installation install = Installation
title = Initial Configuration title = Initial Configuration
docker_helper = If you run Gitea inside Docker, please read the <a target="_blank" rel="noopener" href="%s">documentation</a> before changing any settings. docker_helper = If you run Gitea inside Docker, please read the <a target="_blank" rel="noopener noreferrer" href="%s">documentation</a> before changing any settings.
requite_db_desc = Gitea requires MySQL, PostgreSQL, MSSQL, SQLite3 or TiDB. requite_db_desc = Gitea requires MySQL, PostgreSQL, MSSQL, SQLite3 or TiDB.
db_title = Database Settings db_title = Database Settings
db_type = Database Type db_type = Database Type
@ -492,13 +492,13 @@ owner = Owner
repo_name = Repository Name repo_name = Repository Name
repo_name_helper = Good repository names use short, memorable and unique keywords. repo_name_helper = Good repository names use short, memorable and unique keywords.
visibility = Visibility visibility = Visibility
visiblity_helper = Make Repository Private visibility_helper = Make Repository Private
visiblity_helper_forced = Your site administrator forces new repositories to be private. visibility_helper_forced = Your site administrator forces new repositories to be private.
visiblity_fork_helper = (Changing this will affect all forks.) visibility_fork_helper = (Changing this will affect all forks.)
clone_helper = Need help cloning? Visit <a target="_blank" rel="noopener" href="%s">Help</a>. clone_helper = Need help cloning? Visit <a target="_blank" rel="noopener noreferrer" href="%s">Help</a>.
fork_repo = Fork Repository fork_repo = Fork Repository
fork_from = Fork From fork_from = Fork From
fork_visiblity_helper = The visibility of a forked repository cannot be changed. fork_visibility_helper = The visibility of a forked repository cannot be changed.
repo_desc = Description repo_desc = Description
repo_lang = Language repo_lang = Language
repo_gitignore_helper = Select .gitignore templates. repo_gitignore_helper = Select .gitignore templates.
@ -613,7 +613,7 @@ editor.directory_is_a_file = Directory name '%s' is already used as a filename i
editor.file_is_a_symlink = '%s' is a symbolic link. Symbolic links cannot be edited in the web editor editor.file_is_a_symlink = '%s' is a symbolic link. Symbolic links cannot be edited in the web editor
editor.filename_is_a_directory = Filename '%s' is already used as a directory name in this repository. editor.filename_is_a_directory = Filename '%s' is already used as a directory name in this repository.
editor.file_editing_no_longer_exists = The file being edited, '%s', no longer exists in this repository. editor.file_editing_no_longer_exists = The file being edited, '%s', no longer exists in this repository.
editor.file_changed_while_editing = The file contents have changed since you started editing. <a target="_blank" rel="noopener" href="%s">Click here</a> to see them or <strong>Commit Changes again</strong> to overwrite them. editor.file_changed_while_editing = The file contents have changed since you started editing. <a target="_blank" rel="noopener noreferrer" href="%s">Click here</a> to see them or <strong>Commit Changes again</strong> to overwrite them.
editor.file_already_exists = A file named '%s' already exists in this repository. editor.file_already_exists = A file named '%s' already exists in this repository.
editor.no_changes_to_show = There are no changes to show. editor.no_changes_to_show = There are no changes to show.
editor.fail_to_update_file = Failed to update/create file '%s' with error: %v editor.fail_to_update_file = Failed to update/create file '%s' with error: %v
@ -994,7 +994,7 @@ settings.search_user_placeholder = Search user…
settings.org_not_allowed_to_be_collaborator = Organizations cannot be added as a collaborator. settings.org_not_allowed_to_be_collaborator = Organizations cannot be added as a collaborator.
settings.user_is_org_member = The user is an organization member who cannot be added as a collaborator. settings.user_is_org_member = The user is an organization member who cannot be added as a collaborator.
settings.add_webhook = Add Webhook settings.add_webhook = Add Webhook
settings.hooks_desc = Webhooks automatically make HTTP POST requests to a server when certain Gitea events trigger. Read more in the <a target="_blank" rel="noopener" href="%s">webhooks guide</a>. settings.hooks_desc = Webhooks automatically make HTTP POST requests to a server when certain Gitea events trigger. Read more in the <a target="_blank" rel="noopener noreferrer" href="%s">webhooks guide</a>.
settings.webhook_deletion = Remove Webhook settings.webhook_deletion = Remove Webhook
settings.webhook_deletion_desc = Removing a webhook deletes its settings and delivery history. Continue? settings.webhook_deletion_desc = Removing a webhook deletes its settings and delivery history. Continue?
settings.webhook_deletion_success = The webhook has been removed. settings.webhook_deletion_success = The webhook has been removed.
@ -1011,7 +1011,7 @@ settings.githook_edit_desc = If the hook is inactive, sample content will be pre
settings.githook_name = Hook Name settings.githook_name = Hook Name
settings.githook_content = Hook Content settings.githook_content = Hook Content
settings.update_githook = Update Hook settings.update_githook = Update Hook
settings.add_webhook_desc = Gitea will send <code>POST</code> requests with a specified content type to the target URL. Read more in the <a target="_blank" rel="noopener" href="%s">webhooks guide</a>. settings.add_webhook_desc = Gitea will send <code>POST</code> requests with a specified content type to the target URL. Read more in the <a target="_blank" rel="noopener noreferrer" href="%s">webhooks guide</a>.
settings.payload_url = Target URL settings.payload_url = Target URL
settings.content_type = POST Content Type settings.content_type = POST Content Type
settings.secret = Secret settings.secret = Secret
@ -1273,8 +1273,8 @@ dashboard.operation_switch = Switch
dashboard.operation_run = Run dashboard.operation_run = Run
dashboard.clean_unbind_oauth = Clean unbound OAuth connections dashboard.clean_unbind_oauth = Clean unbound OAuth connections
dashboard.clean_unbind_oauth_success = All unbound OAuth connections have been deleted. dashboard.clean_unbind_oauth_success = All unbound OAuth connections have been deleted.
dashboard.delete_inactivate_accounts = Delete all inactive accounts dashboard.delete_inactivate_accounts = Delete all not activated accounts
dashboard.delete_inactivate_accounts_success = All inactive accounts have been deleted. dashboard.delete_inactivate_accounts_success = All not activated accounts have been deleted.
dashboard.delete_repo_archives = Delete all repository archives dashboard.delete_repo_archives = Delete all repository archives
dashboard.delete_repo_archives_success = All repository archives have been deleted. dashboard.delete_repo_archives_success = All repository archives have been deleted.
dashboard.delete_missing_repos = Delete all repositories missing their Git files dashboard.delete_missing_repos = Delete all repositories missing their Git files

View File

@ -1,11 +1,15 @@
app_desc=Un servicio de Git auto alojado y sin complicaciones
home=Inicio home=Inicio
dashboard=Panel de control dashboard=Panel de control
explore=Explorar explore=Explorar
help=Ayuda help=Ayuda
sign_in=Iniciar sesión sign_in=Iniciar sesión
sign_in_with=Iniciar sesión con
sign_out=Cerrar sesión sign_out=Cerrar sesión
sign_up=Registro
link_account=Vincular Cuenta link_account=Vincular Cuenta
link_account_signin_or_signup=Inicia sesión con credenciales existentes para vincular tu cuenta a esta cuenta. O registra una nueva.
register=Registro register=Registro
website=Página web website=Página web
version=Versión version=Versión
@ -13,12 +17,27 @@ page=Página
template=Plantilla template=Plantilla
language=Idioma language=Idioma
notifications=Notificaciones notifications=Notificaciones
create_new=Crear…
user_profile_and_more=Perfil y ajustes…
signed_in_as=Identificado como signed_in_as=Identificado como
enable_javascript=Este sitio web funciona mejor con JavaScript.
username=Nombre de usuario username=Nombre de usuario
email=Correo electrónico
password=Contraseña password=Contraseña
re_type=Vuelva a escribir la contraseña
captcha=CAPTCHA
twofa=Autenticación de dos factores
passcode=Contraseña passcode=Contraseña
u2f_insert_key=Inserte su clave de seguridad
u2f_use_twofa=Use un código de dos factores de su celular
u2f_error=No podemos leer su llave de seguridad!
u2f_unsupported_browser=Su navegador no soporta llaves U2F. Por favor utilicé otro navegador.
u2f_error_1=Un error desconocido ha ocurrido. Por favor vuelva a intentarlo.
u2f_error_2=Por favor asegúrese de que está utilizando una conexión cifrada (https://) y que esta visitando la dirección URL correcta.
u2f_error_3=El servidor no pudo procesar su petición.
u2f_reload=Recargar
repository=Repositorio repository=Repositorio
organization=Organización organization=Organización
@ -31,6 +50,9 @@ new_org=Nueva organización
manage_org=Administrar organizaciones manage_org=Administrar organizaciones
account_settings=Configuraciones de la cuenta account_settings=Configuraciones de la cuenta
settings=Configuraciones settings=Configuraciones
your_profile=Perfil
your_starred=Destacado
your_settings=Configuración
all=Todos all=Todos
sources=Fuentes sources=Fuentes
@ -46,29 +68,63 @@ cancel=Cancelar
[install] [install]
install=Instalación install=Instalación
title=Configuración inicial
requite_db_desc=Gitea requiere una base de datos MySQL, PostgreSQL, MSSQL, SQLite3 o TiDB.
db_title=Configuración de base de datos db_title=Configuración de base de datos
db_type=Tipo de base de datos db_type=Tipo de base de datos
host=Servidor host=Servidor
user=Nombre de usuario
password=Contraseña password=Contraseña
db_name=Nombre de la base de datos db_name=Nombre de la base de datos
db_helper=Nota para usuarios de la base de datos MySQL: por favor use el motor InnoDB y el esquema de caracteres 'utf8_general_ci'.
ssl_mode=SSL
path=Ruta path=Ruta
general_title=Configuración general
app_name=Título del Sitio
app_name_helper=Puedes colocar aquí el nombre de tu empresa.
repo_path=Ruta del repositorio de Raiz (Root) repo_path=Ruta del repositorio de Raiz (Root)
run_user=Ejecutar como usuario
domain=Dominio del servidor SSH
log_root_path=Ruta del registro log_root_path=Ruta del registro
optional_title=Configuración opcional optional_title=Configuración opcional
email_title=Configuración de Correo
smtp_host=Servidor SMTP smtp_host=Servidor SMTP
mailer_user=Nombre de usuario SMTP
mailer_password=Contraseña SMTP
offline_mode=Habilitar autenticación Local
disable_gravatar=Desactivar Gravatar
federated_avatar_lookup_popup=Habilitar búsqueda de avatares federador para usar el servicio federado de código abierto basado en libravatar. federated_avatar_lookup_popup=Habilitar búsqueda de avatares federador para usar el servicio federado de código abierto basado en libravatar.
enable_captcha=Activar CAPTCHA
enable_captcha_popup=Requerir CAPTCHA para auto-registro de usuario. enable_captcha_popup=Requerir CAPTCHA para auto-registro de usuario.
require_sign_in_view=Debes iniciar sesión para ver las páginas
admin_password=Contraseña admin_password=Contraseña
confirm_password=Confirmar Contraseña confirm_password=Confirmar Contraseña
admin_email=Correo electrónico
install_btn_confirm=Instalar Gitea install_btn_confirm=Instalar Gitea
test_git_failed=Fallo al probar el comando 'git': %v test_git_failed=Fallo al probar el comando 'git': %v
invalid_db_setting=La configuración de la base de datos no es válida: %v
invalid_repo_path=La ruta de la raíz del repositorio no es válida: %v
run_user_not_match=El nombre de usuario 'ejecutar como' no es el nombre actual de usuario: %s -> %s
save_config_failed=Error al guardar la configuración: %v save_config_failed=Error al guardar la configuración: %v
invalid_admin_setting=La configuración de la cuenta de administración no es válida: %v
install_success=¡Bienvenido! Gracias por elegir Gitea. ¡Diviértete y cuidate!
invalid_log_root_path=La ruta para los registros no es válida: %v
default_keep_email_private=Ocultar direcciones de correo electrónico por defecto
default_keep_email_private_popup=Ocultar direcciones de correo electrónico de nuevas cuentas de usuario por defecto.
default_allow_create_organization=Permitir la creación de organizaciones por defecto
default_allow_create_organization_popup=Permitir crear organizaciones a las nuevas cuentas de usuario de forma predeterminada.
default_enable_timetracking=Activar el seguimiento de tiempo por defecto
default_enable_timetracking_popup=Activar el seguimiento de tiempo para nuevos repositorios por defecto.
no_reply_address=Dominio de correos electrónicos ocultos
[home] [home]
uname_holder=Nombre de usuario o correo electrónico
password_holder=Contraseña password_holder=Contraseña
switch_dashboard_context=Cambiar el contexto del Dashboard switch_dashboard_context=Cambiar el contexto del Dashboard
my_repos=Repositorios
show_more_repos=Mostrar más repositorios…
collaborative_repos=Repositorios colaborativos collaborative_repos=Repositorios colaborativos
my_orgs=Mis organizaciones my_orgs=Mis organizaciones
my_mirrors=Mis réplicas my_mirrors=Mis réplicas
@ -81,28 +137,46 @@ repos=Repositorios
users=Usuarios users=Usuarios
organizations=Organizaciones organizations=Organizaciones
search=Buscar search=Buscar
code=Código
repo_no_results=No se ha encontrado ningún repositorio coincidente.
user_no_results=No se ha encontrado ningún usuario coincidente.
org_no_results=No se ha encontrado ninguna organización coincidente.
code_no_results=No se ha encontrado código de fuente que coincida con su término de búsqueda.
code_search_results=Resultados de búsqueda para '%s'
[auth] [auth]
create_new_account=Registrar una cuenta
register_helper_msg=¿Ya tienes una cuenta? ¡Inicia sesión! register_helper_msg=¿Ya tienes una cuenta? ¡Inicia sesión!
social_register_helper_msg=¿Ya tienes una cuenta? ¡Enlázala!
disable_register_prompt=Registro deshabilitado. Por favor, póngase en contacto con el administrador del sitio.
disable_register_mail=Correo electrónico de confirmación de registro deshabilitado.
remember_me=Recuérdame remember_me=Recuérdame
forgot_password_title=He olvidado mi contraseña forgot_password_title=He olvidado mi contraseña
forgot_password=¿Has olvidado tu contraseña? forgot_password=¿Has olvidado tu contraseña?
sign_up_now=¿Necesitas una cuenta? Regístrate ahora.
confirmation_mail_sent_prompt=Un nuevo correo de confirmación se ha enviado a <b>%s</b>. Comprueba tu bandeja de entrada en las siguientes %s para completar el registro. confirmation_mail_sent_prompt=Un nuevo correo de confirmación se ha enviado a <b>%s</b>. Comprueba tu bandeja de entrada en las siguientes %s para completar el registro.
reset_password_mail_sent_prompt=Un correo de confirmación se ha enviado a <b>%s</b>. Comprueba tu bandeja de entrada en las siguientes %s para completar el reinicio de contraseña. reset_password_mail_sent_prompt=Un correo de confirmación se ha enviado a <b>%s</b>. Comprueba tu bandeja de entrada en las siguientes %s para completar el reinicio de contraseña.
active_your_account=Activa tu cuenta active_your_account=Activa tu cuenta
prohibit_login=Ingreso prohibido
prohibit_login_desc=Su cuenta tiene prohibido ingresar al sistema. Por favor contacte con el administrador del sistema.
resent_limit_prompt=Ya ha solicitado recientemente un correo de activación. Por favor, espere 3 minutos y vuelva a intentarlo.
has_unconfirmed_mail=Hola %s, tu correo electrónico (<b>%s</b>) no está confirmado. Si no has recibido un correo de confirmación o necesitas que lo enviemos de nuevo, por favor, haz click en el siguiente botón. has_unconfirmed_mail=Hola %s, tu correo electrónico (<b>%s</b>) no está confirmado. Si no has recibido un correo de confirmación o necesitas que lo enviemos de nuevo, por favor, haz click en el siguiente botón.
resend_mail=Haz click aquí para reenviar tu correo electrónico de activación resend_mail=Haz click aquí para reenviar tu correo electrónico de activación
email_not_associate=Esta dirección de correo electrónico no esta asociada a ninguna cuenta. email_not_associate=Esta dirección de correo electrónico no esta asociada a ninguna cuenta.
send_reset_mail=Haz clic aquí para reenviar tu email de restauración de contraseña send_reset_mail=Haz clic aquí para reenviar tu email de restauración de contraseña
reset_password=Restablecer su contraseña reset_password=Restablecer su contraseña
invalid_code=Su código de confirmación no es válido o ha caducado.
reset_password_helper=Haga Clic aquí para restablecer su contraseña reset_password_helper=Haga Clic aquí para restablecer su contraseña
non_local_account=Los usuarios no locales no pueden actualizar su contraseña a través de la interfaz web de Gitea.
verify=Verificar verify=Verificar
twofa_scratch_used=Ya has utilizado el código. Has sido redirigido a la página de configuración de dos factores poder remover la inscripción del dispositivo o generar un nuevo código. twofa_scratch_used=Ya has utilizado el código. Has sido redirigido a la página de configuración de dos factores poder remover la inscripción del dispositivo o generar un nuevo código.
twofa_scratch_token_incorrect=El código cero es incorrecto. twofa_scratch_token_incorrect=El código cero es incorrecto.
login_userpass=Iniciar sesión
login_openid=OpenID login_openid=OpenID
openid_connect_submit=Conectar openid_connect_submit=Conectar
openid_connect_title=Accede con una cuenta existente openid_connect_title=Accede con una cuenta existente
openid_register_title=Crear una nueva cuenta openid_register_title=Crear una nueva cuenta
disable_forgot_password_mail=El restablecimiento de contraseña está desactivado. Por favor, contacte con el administrador del sitio.
[mail] [mail]
activate_account=Por favor, active su cuenta activate_account=Por favor, active su cuenta
@ -114,12 +188,14 @@ register_notify=¡Bienvenido a Gitea
[modal] [modal]
yes= yes=
no=No no=No
modify=Actualizar
[form] [form]
UserName=Nombre de usuario UserName=Nombre de usuario
RepoName=Nombre del repositorio RepoName=Nombre del repositorio
Email=Dirección de correo electrónico Email=Dirección de correo electrónico
Password=Contraseña Password=Contraseña
Retype=Vuelva a escribir la contraseña
SSHTitle=Nombre de la Clave de SSH SSHTitle=Nombre de la Clave de SSH
HttpsUrl=URL HTTPS HttpsUrl=URL HTTPS
PayloadUrl=URL de carga PayloadUrl=URL de carga
@ -135,6 +211,7 @@ TreeName=Ruta del archivo
Content=Contenido Content=Contenido
require_error=` no puede estar vacío.` require_error=` no puede estar vacío.`
alpha_dash_error=` solo debe contener caracteres alfanuméricos, guiones medios ('-') y guiones bajos ('_').`
size_error=` debe ser de tamaño %s.` size_error=` debe ser de tamaño %s.`
min_size_error=` debe contener al menos %s caracteres.` min_size_error=` debe contener al menos %s caracteres.`
max_size_error=` debe contener como máximo %s caracteres.` max_size_error=` debe contener como máximo %s caracteres.`
@ -142,7 +219,10 @@ email_error=` no es una dirección de correo válida.`
url_error=` no es una URL válida.` url_error=` no es una URL válida.`
include_error=` debe contener la subcadena '%s'.` include_error=` debe contener la subcadena '%s'.`
unknown_error=Error desconocido: unknown_error=Error desconocido:
captcha_incorrect=El código CAPTCHA no es correcto.
password_not_match=Las contraseñas no coinciden.
username_been_taken=El nombre de usuario ya está en uso.
user_not_exist=Este usuario no existe. user_not_exist=Este usuario no existe.
auth_failed=Autenticación fallo: %v auth_failed=Autenticación fallo: %v
@ -248,6 +328,7 @@ fork_from=Crear un Fork desde
repo_desc=Descripción repo_desc=Descripción
repo_lang=Idioma repo_lang=Idioma
license=Licencia license=Licencia
auto_init=Inicializar el repositorio (añade .gitignore, licencia y README)
create_repo=Crear repositorio create_repo=Crear repositorio
default_branch=Rama por defecto default_branch=Rama por defecto
mirror_prune=Purgar mirror_prune=Purgar
@ -343,8 +424,8 @@ issues.label_templates.helper=Seleccionar un conjunto de etiquetas
issues.label_templates.fail_to_load_file=Error al cargar el archivo de plantilla de etiqueta '%s': %v issues.label_templates.fail_to_load_file=Error al cargar el archivo de plantilla de etiqueta '%s': %v
issues.add_label_at=añadida la etiqueta <div class="ui label" style="color: %s\; background-color: %s">%s</div> %s issues.add_label_at=añadida la etiqueta <div class="ui label" style="color: %s\; background-color: %s">%s</div> %s
issues.remove_label_at=eliminada la etiqueta <div class="ui label" style="color: %s\; background-color: %s">%s</div> %s issues.remove_label_at=eliminada la etiqueta <div class="ui label" style="color: %s\; background-color: %s">%s</div> %s
issues.add_milestone_at=`agregado esto al <b>%s</b> hito %s ' issues.add_milestone_at=`ha añadido esto al hito <b>%s</b> %s '
issues.change_milestone_at=` modificó el hito de <b>%s</b> to <b>%s</b> %s` issues.change_milestone_at=`modificó el hito de <b>%s</b> a <b>%s</b> %s`
issues.remove_milestone_at=`eliminado esto del <b>%s</b> hito %s ' issues.remove_milestone_at=`eliminado esto del <b>%s</b> hito %s '
issues.deleted_milestone=`(eliminado)` issues.deleted_milestone=`(eliminado)`
issues.self_assign_at=`auto asignado este %s` issues.self_assign_at=`auto asignado este %s`
@ -411,6 +492,8 @@ issues.attachment.open_tab='Haga clic para ver "%s" en una pestaña nueva'
issues.attachment.download=`Haga clic para descargar "%s"` issues.attachment.download=`Haga clic para descargar "%s"`
issues.subscribe=Suscribir issues.subscribe=Suscribir
issues.unsubscribe=Desuscribirse issues.unsubscribe=Desuscribirse
issues.start_tracking_short=Iniciar
issues.start_tracking_history=`ha empezado a trabajar %s`
issues.tracking_already_started='Ya has comenzado el tiempo de seguimiento en este <a href="%s">tema</a>!' issues.tracking_already_started='Ya has comenzado el tiempo de seguimiento en este <a href="%s">tema</a>!'
issues.add_time_hours=Horas issues.add_time_hours=Horas
issues.add_time_minutes=Minutos issues.add_time_minutes=Minutos
@ -461,6 +544,8 @@ wiki.page_already_exists=Ya existe una página con el mismo nombre.
wiki.pages=Páginas wiki.pages=Páginas
wiki.last_updated=Última actualización %s wiki.last_updated=Última actualización %s
activity=Actividad
activity.period.filter_label=Periodo:
activity.period.daily=1 día activity.period.daily=1 día
activity.period.halfweekly=3 días activity.period.halfweekly=3 días
activity.period.weekly=1 semana activity.period.weekly=1 semana
@ -503,6 +588,7 @@ settings.new_owner_has_same_repo=El nuevo propietario tiene un repositorio con e
settings.transfer=Transferir la propiedad settings.transfer=Transferir la propiedad
settings.delete=Eliminar este repositorio settings.delete=Eliminar este repositorio
settings.delete_notices_1=- Esta operación <strong>NO PUEDE</strong> revertirse. settings.delete_notices_1=- Esta operación <strong>NO PUEDE</strong> revertirse.
settings.delete_notices_fork_1=Los forks de este repositorio serán independientes después de eliminarlo.
settings.transfer_owner=Nuevo Propietario settings.transfer_owner=Nuevo Propietario
settings.add_webhook=Añadir Webhook settings.add_webhook=Añadir Webhook
settings.webhook.test_delivery=Test de entrega settings.webhook.test_delivery=Test de entrega
@ -531,6 +617,7 @@ settings.deploy_keys=Claves de Despliegue
settings.add_deploy_key=Añadir Clave de Despliegue settings.add_deploy_key=Añadir Clave de Despliegue
settings.title=Título settings.title=Título
settings.deploy_key_content=Contenido settings.deploy_key_content=Contenido
settings.protect_merge_whitelist_committers_desc=Permitir a los usuarios o equipos de la lista a fusionar peticiones pull dentro de esta rama.
settings.add_protected_branch=Activar protección settings.add_protected_branch=Activar protección
settings.delete_protected_branch=Desactivar protección settings.delete_protected_branch=Desactivar protección
@ -574,6 +661,7 @@ branch.create_from=desde '%s'
branch.branch_already_exists=La rama '%s' ya existe en este repositorio. branch.branch_already_exists=La rama '%s' ya existe en este repositorio.
branch.deleted_by=Eliminada por %s branch.deleted_by=Eliminada por %s
topic.done=Hecho
[org] [org]
org_name_holder=Nombre de la organización org_name_holder=Nombre de la organización
@ -613,6 +701,7 @@ teams.join=Unirse
teams.leave=Abandonar teams.leave=Abandonar
teams.read_access=Acceso de Lectura teams.read_access=Acceso de Lectura
teams.write_access=Acceso de Escritura teams.write_access=Acceso de Escritura
teams.admin_access_helper=Los miembros pueden hacer pull y push a los repositorios del equipo y añadir colaboradores a ellos.
teams.no_desc=Este equipo no tiene descripción teams.no_desc=Este equipo no tiene descripción
teams.settings=Configuración teams.settings=Configuración
teams.members=Miembros del equipo teams.members=Miembros del equipo
@ -638,8 +727,7 @@ dashboard.operation_name=Nombre de la operación
dashboard.operation_switch=Interruptor dashboard.operation_switch=Interruptor
dashboard.operation_run=Ejecutar dashboard.operation_run=Ejecutar
dashboard.clean_unbind_oauth_success=Se han eliminado las conexiones de OAuth no vinculadas. dashboard.clean_unbind_oauth_success=Se han eliminado las conexiones de OAuth no vinculadas.
dashboard.delete_inactivate_accounts=Eliminar todas las cuentas inactivas dashboard.resync_all_sshkeys=Actualizar el archivo '.ssh/authorized_keys' con las claves SSH de Gitea (no es necesario para el servidor SSH incorporado).
dashboard.delete_inactivate_accounts_success=Todas las cuentas inactivas han sido eliminadas.
dashboard.reinit_missing_repos=Reiniciar todos los repositorios Git faltantes de los que existen registros dashboard.reinit_missing_repos=Reiniciar todos los repositorios Git faltantes de los que existen registros
dashboard.reinit_missing_repos_success=Todos los repositorios Git faltantes para los que existen registros se han reinicializado. dashboard.reinit_missing_repos_success=Todos los repositorios Git faltantes para los que existen registros se han reinicializado.
dashboard.server_uptime=Tiempo de actividad del servidor dashboard.server_uptime=Tiempo de actividad del servidor
@ -859,6 +947,7 @@ file_too_big=El tamaño del archivo ({{filesize}} MB) excede el tamaño máximo
remove_file=Eliminar archivo remove_file=Eliminar archivo
[notification] [notification]
notifications=Notificaciones
unread=Sin leer unread=Sin leer
read=Leídas read=Leídas
mark_as_read=Marcar como leído mark_as_read=Marcar como leído

View File

@ -1,10 +1,15 @@
app_desc=Ongelmaton, itsehostattu Git-palvelu
home=Etusivu home=Etusivu
dashboard=Kojelauta dashboard=Kojelauta
explore=Tutki explore=Tutki
help=Apua help=Apua
sign_in=Kirjaudu sisään sign_in=Kirjaudu sisään
sign_in_with=Kirjaudu sisään tunnuksilla
sign_out=Kirjaudu ulos sign_out=Kirjaudu ulos
sign_up=Rekisteröidy
link_account=Yhdistä tili
link_account_signin_or_signup=Kirjaudu sisään olemassaolevilla tunnuksilla yhdistääksesi tilisi käyttäjätunnukseen. Tai rekisteröi uusi käyttäjätunnus.
register=Rekisteröidy register=Rekisteröidy
website=Nettisivut website=Nettisivut
version=Versio version=Versio
@ -12,10 +17,18 @@ page=Sivu
template=Malli template=Malli
language=Kieli language=Kieli
notifications=Ilmoitukset notifications=Ilmoitukset
create_new=Luo…
user_profile_and_more=Profiili ja asetukset…
signed_in_as=Kirjautuneena käyttäjänä signed_in_as=Kirjautuneena käyttäjänä
enable_javascript=Tämä sivusto toimii paremmin JavaScriptillä.
username=Käyttäjätunnus username=Käyttäjätunnus
email=Sähköpostiosoite
password=Salasana password=Salasana
re_type=Kirjoita salasana uudelleen
captcha=CAPTCHA
twofa=Kaksivaiheinen todennus
twofa_scratch=Kaksivaiheinen kertakäyttöinen koodi
passcode=Tunnuskoodi passcode=Tunnuskoodi
@ -25,11 +38,21 @@ mirror=Peili
new_repo=Uusi repo new_repo=Uusi repo
new_migrate=Uusi migraatio new_migrate=Uusi migraatio
new_mirror=Uusi peilaus new_mirror=Uusi peilaus
new_fork=Uusi repositorio
new_org=Uusi organisaatio new_org=Uusi organisaatio
manage_org=Ylläpidä organisaatioita manage_org=Ylläpidä organisaatioita
admin_panel=Sivuston ylläpito
account_settings=Tilin asetukset account_settings=Tilin asetukset
settings=Asetukset settings=Asetukset
your_profile=Profiili
your_starred=Tähdelliset
your_settings=Asetukset
all=Kaikki
sources=Lähteet
mirrors=Peilit
collaborative=Yhteistyössä
forks=Haarat
activities=Toimet activities=Toimet
pull_requests=Pull requestit pull_requests=Pull requestit
@ -39,19 +62,59 @@ cancel=Peruuta
[install] [install]
install=Asennus install=Asennus
title=Alkuperäiset asetukset
requite_db_desc=Gitea tarvitsee toimiakseen MySQL-, PostgreSQL-, MSSQL-, SQLite3 tai TiDB-tietokannan.
db_title=Tietokanta asetukset db_title=Tietokanta asetukset
db_type=Tietokanta tyyppi db_type=Tietokanta tyyppi
host=Isäntä host=Isäntä
user=Käyttäjätunnus
password=Salasana password=Salasana
db_name=Tietokannan nimi db_name=Tietokannan nimi
db_helper=Huomio MySQL-käyttäjille: käytäthän InnoDB-kantamoottoria ja 'utf8_general_ci'-merkistöä.
ssl_mode=SSL
path=Polku path=Polku
sqlite_helper=Tiedostopolku SQLite3- tai TiDB-tietokantaan.<br>Kirjoita absoluuttinen polku, jos ajat Giteaa palveluna.
err_empty_db_path=SQLite3- tai TiDB-tietokantapolku ei voi olla tyhjä.
err_invalid_tidb_name=TiDB-tietokannan nimi ei voi sisältää '.'- tai '-'-merkkejä.
no_admin_and_disable_registration=Et voi kytkeä rekisteröintiä pois luomatta sitä ennen ylläpitotiliä.
err_empty_admin_password=Ylläpitäjän salasana ei voi olla tyhjä.
general_title=Yleiset asetukset
app_name=Sivuston otsikko
repo_path=Repon juuren polku repo_path=Repon juuren polku
repo_path_helper=Muualla olevat git-repositoriot tullaan tallentamaan tähän kansioon.
lfs_path=Git LFS -juuripolku
lfs_path_helper=Git LFS:n ylläpitämät tiedostot tullaan tallentamaan tähän hakemistoon. Jätä tyhjäksi kytkeäksesi toiminnon pois.
run_user=Aja käyttäjänä
run_user_helper=Anna käyttäjätunnus, jona Giteaa ajetaan. Käyttäjällä on oltava oikeudet repositorioiden juuripolkuun.
domain=SSH-palvelimen osoite (hostname)
domain_helper=Domain tai osoite SSH-klooniosoitteille.
ssh_port=SSH-palvelimen portti
ssh_port_helper=Porttinumero, jossa SSH-palvelimesi kuuntelee. Jätä tyhjäksi kytkeäksesi pois.
http_port=Gitean HTTP-kuunteluportti
http_port_helper=Portti, jossa Gitean web-palvelin kuuntelee.
app_url=Gitean juuriosoite
app_url_helper=Juuriosoite HTTP(S)-klooniosoitteille ja sähköpostimuistutuksille.
log_root_path=Lokin polku log_root_path=Lokin polku
log_root_path_helper=Lokitiedostot kirjoitetaan tähän kansioon.
optional_title=Valinnaiset asetukset optional_title=Valinnaiset asetukset
email_title=Sähköpostiasetukset
smtp_host=SMTP isäntä smtp_host=SMTP isäntä
smtp_from=Lähetä sähköpostit osoitteella
smtp_from_helper=Sähköpostiosoite, jota Gitea käyttää. Kirjoita osoite ”nimi” <email@example.com> -muodossa.
mailer_user=SMTP-käyttäjätunnus
mailer_password=SMTP-salasana
register_confirm=Vaadi sähköpostin vahvistaminen rekisteröintiin
mail_notify=Ota käyttöön sähköpostiilmoitukset
server_service_title=Palvelin ja kolmansien osapuolten palveluiden asetukset
offline_mode=Ota käyttöön lokaali tila
offline_mode_popup=Poista kolmannen osapuolen sisällöstä jakeluverkot ja tarjoa kaikki resurssit paikallisesti.
disable_gravatar=Poista Gravatar käytöstä
disable_gravatar_popup=Poista Gravatar ja kolmannen osapuolen avaratir käytöstä. Oletus-avatar näytetään, ellei käyttäjä ole ladannut omaansa.
federated_avatar_lookup=Käytä ulkopuolisia profiilikuvia
federated_avatar_lookup_popup=Enable federated avatars lookup to use federated open source service based on libravatar. federated_avatar_lookup_popup=Enable federated avatars lookup to use federated open source service based on libravatar.
disable_registration=Poista rekisteröinti käytöstä
enable_captcha_popup=Pakollinen captcha käyttäjän itse rekisteröityessä. enable_captcha_popup=Pakollinen captcha käyttäjän itse rekisteröityessä.
admin_password=Salasana admin_password=Salasana
confirm_password=Varmista salasana confirm_password=Varmista salasana
@ -73,32 +136,69 @@ repos=Repot
users=Käyttäjät users=Käyttäjät
organizations=Organisaatiot organizations=Organisaatiot
search=Hae search=Hae
code_no_results=Hakuehtoasi vastaavaa lähdekoodia ei löytynyt.
code_search_results=Hakutulokset: '%s '
[auth] [auth]
create_new_account=Rekisteröi tili
register_helper_msg=On jo tili? Kirjaudu sisään nyt! register_helper_msg=On jo tili? Kirjaudu sisään nyt!
social_register_helper_msg=Onko sinulla jo tili? Linkitä se nyt!
disable_register_prompt=Rekisteröinti on estetty. Ota yhteys ylläpitäjääsi.
disable_register_mail=Sähköpostivahvistus rekisteröinnille on estetty.
remember_me=Muista minut remember_me=Muista minut
forgot_password_title=Unohtuiko salasana
forgot_password=Unohtuiko salasana?
sign_up_now=Tarvitsetko tilin? Rekisteröidy nyt.
confirmation_mail_sent_prompt=Uusi varmistussähköposti on lähetetty osoitteeseen <b>%s</b>, ole hyvä ja tarkista saapuneet seuraavan %s tunnin sisällä saadaksesi rekisteröintiprosessin valmiiksi.
reset_password_mail_sent_prompt=Varmistussähköposti on lähetetty osoitteeseen <b>%s</b>, ole hyvä ja tarkista saapuneet seuraavan %s tunnin sisällä saadaksesi salasananvaihdon valmiiksi.
active_your_account=Aktivoi tilisi active_your_account=Aktivoi tilisi
prohibit_login=Kirjautuminen estetty
prohibit_login_desc=Käyttäjätilisi kirjautuminen on estetty. Ota yhteys sivuston ylläpitäjään.
resent_limit_prompt=Olet jo tilannut aktivointisähköpostin hetki sitten. Ole hyvä ja odota 3 minuuttia ja yritä sitten uudelleen.
has_unconfirmed_mail=Hei %s, sinulla on varmistamaton sähköposti osoite (<b>%s</b>). Jos et ole saanut varmistus sähköpostia tai tarvitset uudelleenlähetyksen, ole hyvä ja klikkaa allaolevaa painiketta. has_unconfirmed_mail=Hei %s, sinulla on varmistamaton sähköposti osoite (<b>%s</b>). Jos et ole saanut varmistus sähköpostia tai tarvitset uudelleenlähetyksen, ole hyvä ja klikkaa allaolevaa painiketta.
resend_mail=Klikkaa tästä uudelleenlähettääksesi aktivointi sähköpostisi resend_mail=Klikkaa tästä uudelleenlähettääksesi aktivointi sähköpostisi
email_not_associate=Tätä sähköpostiosoitetta ei ole liitetty mihinkään tiliin.
send_reset_mail=Klikkaa tästä (uudelleen) lähettääksesi salasanan nollaussähköpostin
reset_password=Nollaa salasanasi reset_password=Nollaa salasanasi
invalid_code=Vahvistusavain on virheellinen tai vanhentunut.
reset_password_helper=Klikkaa tästä nollataksesi salasanasi reset_password_helper=Klikkaa tästä nollataksesi salasanasi
non_local_account=Ei-lokaalit käyttäjät eivät voi päivittää salasanojaan Gitean web-käyttöliittymän kautta.
verify=Vahvista verify=Vahvista
scratch_code=Kertakäyttökoodi
use_scratch_code=Käytä kertakäyttökoodia
twofa_scratch_used=Olet käyttänyt kertakäyttökoodisi. Sinut on uudelleenohjattu kaksivaiheisen kirjautumisen asetussivulle, jotta voit kytkeä sen pois tai luoda uuden kertakäyttökoodin.
twofa_passcode_incorrect=Salasanasi on väärä. Jos olet hukannut laitteesi, käytäthän kertakäyttökoodia sisäänkirjautumiseen.
twofa_scratch_token_incorrect=Kertakäyttökoodisi on virheellinen.
login_userpass=Kirjaudu sisään
login_openid=OpenID
openid_connect_submit=Connect
openid_connect_title=Yhdistä olemassaolevaan tiliin
openid_connect_desc=Valittu OpenID-osoite on tuntematon. Liitä se uuteen tiliin täällä.
openid_register_title=Luo uusi tili
openid_register_desc=Valittu OpenID-osoite on tuntematon. Liitä se uuteen tiliin täällä.
openid_signin_desc=Anna OpenID-osoitteesi. Esimerkiksi: https://anne.me, bob.openid.org.cn tai gnusocial.net/carry.
disable_forgot_password_mail=Salasanan nollaus on estetty. Ota yhteys ylläpitäjääsi.
[mail] [mail]
activate_account=Ole hyvä ja aktivoi tilisi activate_account=Ole hyvä ja aktivoi tilisi
activate_email=Vahvista sähköpostiosoitteesi activate_email=Vahvista sähköpostiosoitteesi
reset_password=Tyhjennä salasana reset_password=Tyhjennä salasana
register_success=Rekisteröinti onnistui
register_notify=Tervetuloa Giteaan
[modal] [modal]
yes=Kyllä yes=Kyllä
no=Ei no=Ei
modify=Päivitys
[form] [form]
UserName=Käyttäjätunnus UserName=Käyttäjätunnus
RepoName=Repon nimi RepoName=Repon nimi
Email=Sähköposti osoite Email=Sähköposti osoite
Password=Salasana Password=Salasana
Retype=Kirjoita salasana uudelleen
SSHTitle=SSH avain nimi SSHTitle=SSH avain nimi
HttpsUrl=HTTPS-osoite
TeamName=Tiimin nimi TeamName=Tiimin nimi
AuthName=Luvan nimi AuthName=Luvan nimi
AdminEmail=Ylläpito sähköposti AdminEmail=Ylläpito sähköposti
@ -488,7 +588,6 @@ total=Yhteensä: %d
dashboard.operation_name=Toiminnon nimi dashboard.operation_name=Toiminnon nimi
dashboard.operation_switch=Vaihda dashboard.operation_switch=Vaihda
dashboard.operation_run=Suorita dashboard.operation_run=Suorita
dashboard.delete_inactivate_accounts=Poista kaikki passiiviset tunnukset
dashboard.server_uptime=Palvelimen Uptime dashboard.server_uptime=Palvelimen Uptime
dashboard.current_goroutine=Nykyiset Goroutinet dashboard.current_goroutine=Nykyiset Goroutinet
dashboard.current_memory_usage=Nykyinen muistinkäyttö dashboard.current_memory_usage=Nykyinen muistinkäyttö

File diff suppressed because it is too large Load Diff

View File

@ -708,8 +708,6 @@ dashboard.operation_switch=Váltás
dashboard.operation_run=Futtatás dashboard.operation_run=Futtatás
dashboard.clean_unbind_oauth=Megszüntetett OAuth kapcsolatok törlése dashboard.clean_unbind_oauth=Megszüntetett OAuth kapcsolatok törlése
dashboard.clean_unbind_oauth_success=Az összes megszüntetett OAuth kapcsolat törölve. dashboard.clean_unbind_oauth_success=Az összes megszüntetett OAuth kapcsolat törölve.
dashboard.delete_inactivate_accounts=Minden inaktív fiók törlése
dashboard.delete_inactivate_accounts_success=Minden inaktív fiók törölve.
dashboard.reinit_missing_repos=Az összes Git tároló újra-inicializálása amihez léteznek bejegyzések dashboard.reinit_missing_repos=Az összes Git tároló újra-inicializálása amihez léteznek bejegyzések
dashboard.reinit_missing_repos_success=Az összes Git tároló amihez létezett bejegyzés újra lett iniciaizálva. dashboard.reinit_missing_repos_success=Az összes Git tároló amihez létezett bejegyzés újra lett iniciaizálva.
dashboard.sync_external_users=Külső felhasználói adatok szinkronizálása dashboard.sync_external_users=Külső felhasználói adatok szinkronizálása

View File

@ -1,11 +1,15 @@
app_desc=Sebuah layanan Git hosting pribadi yang mudah
home=Beranda home=Beranda
dashboard=Dasbor dashboard=Dasbor
explore=Jelajahi explore=Jelajahi
help=Bantuan help=Bantuan
sign_in=Masuk sign_in=Masuk
sign_in_with=Masuk Dengan
sign_out=Keluar sign_out=Keluar
sign_up=Daftar
link_account=Tautan Akun link_account=Tautan Akun
link_account_signin_or_signup=Masuk dengan kredensial yang ada untuk menautkan akun anda yang ada ke akun ini atau daftar akun yang baru.
register=Daftar register=Daftar
website=Situs Web website=Situs Web
version=Versi version=Versi
@ -13,12 +17,32 @@ page=Halaman
template=Contoh template=Contoh
language=Bahasa language=Bahasa
notifications=Notifikasi notifications=Notifikasi
create_new=Buat…
user_profile_and_more=Profil dan Pengaturan…
signed_in_as=Masuk sebagai signed_in_as=Masuk sebagai
enable_javascript=Situs web ini bekerja lebih baik dengan JavaScript.
username=Nama Pengguna username=Nama Pengguna
email=Alamat Email
password=Kata Sandi password=Kata Sandi
re_type=Ketik Ulang Kata Sandi
captcha=CAPTCHA
twofa=Otentikasi Dua Faktor
twofa_scratch=Kode Awal Dua Faktor
passcode=Kode Akses passcode=Kode Akses
u2f_insert_key=Masukkan kunci keamanan anda
u2f_sign_in=Tekan tombol pada kunci keamanan anda. Jika anda tidak menemukan tombol, masukkan kembali.
u2f_press_button=Silahkan tekan tombol pada kunci keamanan anda…
u2f_use_twofa=Menggunakan kode dua faktor dari telepon anda
u2f_error=Kami tidak bisa membaca kunci keamanan anda!
u2f_unsupported_browser=Browser anda tidak mendukung kunci U2F. Silakan mencoba browser lain.
u2f_error_1=Terdapat kesalahan yang tidak diketahui. Mohon coba lagi.
u2f_error_2=Pastikan bahwa anda menggunakan koneksi terenkripsi (https://) dan mengunjungi URL yang benar.
u2f_error_3=Server tidak bisa melanjutkan permintaan anda.
u2f_error_4=Kunci tidak layak untuk permintaan ini. Jika Anda mencoba untuk mendaftarkanya, pastikan bahwa kunci sudah tidak terdaftar.
u2f_error_5=Timeout tercapai sebelum kunci anda bisa terbaca. Silahkan muat ulang untuk mencoba kembali.
u2f_reload=Muat Ulang
repository=Repositori repository=Repositori
organization=Organisasi organization=Organisasi
@ -29,8 +53,12 @@ new_mirror=Duplikat Baru
new_fork=Fork Repositori Baru new_fork=Fork Repositori Baru
new_org=Organisasi Baru new_org=Organisasi Baru
manage_org=Mengelola Organisasi manage_org=Mengelola Organisasi
admin_panel=Administrasi Situs
account_settings=Pengaturan Akun account_settings=Pengaturan Akun
settings=Pengaturan settings=Pengaturan
your_profile=Profil
your_starred=Dibintangi
your_settings=Pengaturan
all=Semua all=Semua
sources=Sumber sources=Sumber
@ -46,34 +74,85 @@ cancel=Batal
[install] [install]
install=Pemasangan install=Pemasangan
title=Konfigurasi Awal
requite_db_desc=Gitea memerlukan MySQL, PostgreSQL, MSSQL, SQLite3 atau TiDB.
db_title=Pengaturan Basis Data db_title=Pengaturan Basis Data
db_type=Tipe Basis Data db_type=Tipe Basis Data
host=Host host=Host
user=Nama Pengguna
password=Kata Sandi password=Kata Sandi
db_name=Nama Basis Data db_name=Nama Basis Data
db_helper=Catatan untuk pengguna MySQL: Gunakan mesin penyimpanan InnoDB dan karakter set 'utf8_general_ci'.
ssl_mode=SSL
path=Jalur path=Jalur
sqlite_helper=Path berkas untuk basis data SQLite3 atau TiDB.<br>Masukkan path absolut jika anda menjalankan Gitea sebagai layanan.
err_empty_db_path=Path basis data SQLite3 atau TiDB tidak boleh kosong.
err_invalid_tidb_name=Nama basis data TiDB tidak boleh berisi karakter '.' dan '-'.
no_admin_and_disable_registration=Anda tidak dapat menonaktifkan pendaftaran tanpa membuat akun admin.
err_empty_admin_password=Sandi administrator tidak boleh kosong.
general_title=Pengaturan Umum
app_name=Judul Situs
app_name_helper=Anda dapat memasukkan nama perusahaan anda di sini.
repo_path=Path Root Repositori repo_path=Path Root Repositori
repo_path_helper=Repositori Git remote akan disimpan ke direktori ini.
lfs_path=Path Akar Git LFS
lfs_path_helper=Berkas yang tersimpan dengan Git LFS akan disimpan ke direktori ini. Biarkan kosong untuk menonaktifkan LFS.
run_user=Jalankan Sebagai Nama Pengguna
run_user_helper=Masukkan nama pengguna sistem operasi yang menjalankan Gitea. Perhatikan bahwa pengguna ini harus memiliki akses ke path akar dari repositori.
domain=SSH Server Domain
domain_helper=Alamat domain atau host untuk URL klon SSH.
ssh_port=Port Server SSH
ssh_port_helper=Nomor port server SSH anda. Biarkan kosong untuk menonaktifkan.
http_port=Port HTTP Gitea
http_port_helper=Nomor port web server dimana Gitea akan berjalan.
app_url=URL Dasar Gitea
app_url_helper=Alamat dasar untuk klon URL HTTP(S) dan pemberitahuan lewat surel.
log_root_path=Path Log log_root_path=Path Log
log_root_path_helper=Berkas log akan ditulis ke direktori ini.
optional_title=Pengaturan Opsional optional_title=Pengaturan Opsional
email_title=Pengaturan Surel
smtp_host=Host SMTP smtp_host=Host SMTP
smtp_from=Kirim Surel sebagai
smtp_from_helper=Alamat surel Gitea akan digunakan. Masukkan alamat surel atau gunakan fomat "Nama" <email@example.com>.
mailer_user=Nama Pengguna SMTP
mailer_password=Sandi SMTP
register_confirm=Memerlukan Konfirmasi Surel Untuk Mendaftar
mail_notify=Aktifkan Pemberitahuan Surel
server_service_title=Server dan Pengaturan Layanan Pihak Ketiga
offline_mode=Aktifkan Mode Lokal
offline_mode_popup=Non-aktifkan jaringan pengiriman konten dari pihak ketiga dan layani semua sumber daya secara lokal.
disable_gravatar=Non-aktifkan Gravatar
federated_avatar_lookup_popup=Mengaktifkan pencarian avatar federasi menggunakan Libravatar. federated_avatar_lookup_popup=Mengaktifkan pencarian avatar federasi menggunakan Libravatar.
openid_signin=Aktifkan Login OpenID openid_signin=Aktifkan Login OpenID
openid_signup=Aktifkan Pendaftaran OpenID
openid_signup_popup=Aktifkan pendaftaran berdasarkan OpenID.
enable_captcha=Aktifkan CAPTCHA
enable_captcha_popup=Membutukan CAPTCHA untuk pendaftaran. enable_captcha_popup=Membutukan CAPTCHA untuk pendaftaran.
require_sign_in_view=Anda Harus Login untuk Melihat Halaman
admin_title=Pengaturan Akun Admin
admin_name=Nama Pengguna Admin
admin_password=Kata sandi admin_password=Kata sandi
confirm_password=Konfirmasi Kata Sandi confirm_password=Konfirmasi Kata Sandi
admin_email=Alamat Surel
install_btn_confirm=Memasang Gitea install_btn_confirm=Memasang Gitea
test_git_failed=Tidak dapat menguji perintah 'git': %v test_git_failed=Tidak dapat menguji perintah 'git': %v
sqlite3_not_available=Gitea versi ini tidak mendukung SQLite3, Silahkan untuh versi biner resmi dari %s (bukan versi 'gobuild').
invalid_db_setting=Pengaturan basis data tidak valid: %v
save_config_failed=Gagal menyimpan konfigurasi: %v save_config_failed=Gagal menyimpan konfigurasi: %v
[home] [home]
uname_holder=Nama Pengguna atau Alamat Surel
password_holder=Kata Sandi password_holder=Kata Sandi
switch_dashboard_context=Alihkan Dasbor Konteks switch_dashboard_context=Alihkan Dasbor Konteks
my_repos=Repositori
show_more_repos=Tampilkan repositori lainnya…
collaborative_repos=Repositori Kolaboratif collaborative_repos=Repositori Kolaboratif
my_orgs=Organisasi Saya my_orgs=Organisasi Saya
my_mirrors=Duplikat Saya my_mirrors=Duplikat Saya
view_home=Lihat %s view_home=Lihat %s
search_repos=Cari repositori…
issues.in_your_repos=Dalam repositori anda issues.in_your_repos=Dalam repositori anda
@ -82,9 +161,16 @@ repos=Repositori
users=Pengguna users=Pengguna
organizations=Organisasi organizations=Organisasi
search=Cari search=Cari
code=Kode
repo_no_results=Tidak ditemukan repositori yang cocok.
org_no_results=Tidak ada organisasi yang cocok ditemukan.
code_no_results=Tidak ada kode sumber yang cocok dengan istilah yang anda cari.
code_search_results=Hasil pencarian untuk '%s'
[auth] [auth]
create_new_account=Daftar Akun
register_helper_msg=Sudah memiliki akun? Masuk sekarang! register_helper_msg=Sudah memiliki akun? Masuk sekarang!
social_register_helper_msg=Sudah memiliki akun? Hubungkan sekarang!
remember_me=Ingat Saya remember_me=Ingat Saya
forgot_password_title=Lupa Kata Sandi forgot_password_title=Lupa Kata Sandi
forgot_password=Lupa kata sandi? forgot_password=Lupa kata sandi?
@ -306,14 +392,17 @@ file_permalink=Permalink
stored_lfs=Tersimpan dengan GIT LFS stored_lfs=Tersimpan dengan GIT LFS
editor.preview_changes=Tinjau Perubahan editor.preview_changes=Tinjau Perubahan
editor.name_your_file=Nama berkas…
editor.or=atau editor.or=atau
editor.commit_changes=Perubahan komitmen editor.commit_changes=Perubahan komitmen
editor.add_tmpl=Tambah '%s/<filename>' editor.add_tmpl=Tambah '%s/<filename>'
editor.add=Menambah '%s' editor.add=Menambah '%s'
editor.update=Memperbarui '%s' editor.update=Memperbarui '%s'
editor.delete=Menghapus '%s' editor.delete=Menghapus '%s'
editor.commit_message_desc=Tambahkan deskripsi opsional yang panjang…
editor.commit_directly_to_this_branch=Komitmen langsung ke <strong class="branch-name">%s</strong> cabang. editor.commit_directly_to_this_branch=Komitmen langsung ke <strong class="branch-name">%s</strong> cabang.
editor.create_new_branch=Membuat <strong>new branch</strong> untuk tarik komit ini mulai permintaan. editor.create_new_branch=Membuat <strong>new branch</strong> untuk tarik komit ini mulai permintaan.
editor.new_branch_name_desc=Nama branch baru…
editor.cancel=Membatalkan editor.cancel=Membatalkan
editor.branch_already_exists=Cabang '%s' sudah ada di repositori ini. editor.branch_already_exists=Cabang '%s' sudah ada di repositori ini.
editor.no_changes_to_show=Tidak ada perubahan untuk ditampilkan. editor.no_changes_to_show=Tidak ada perubahan untuk ditampilkan.
@ -406,6 +495,7 @@ issues.edit=Sunting
issues.cancel=Batal issues.cancel=Batal
issues.save=Simpan issues.save=Simpan
issues.label_title=Nama label issues.label_title=Nama label
issues.label_description=Keterangan label
issues.label_color=Warna label issues.label_color=Warna label
issues.label_count=%d label issues.label_count=%d label
issues.label_open_issues=%d masalah terbuka issues.label_open_issues=%d masalah terbuka
@ -547,6 +637,7 @@ settings.transfer=Transfer Kepemilikan
settings.delete=Menghapus Repositori Ini settings.delete=Menghapus Repositori Ini
settings.delete_notices_1=- Operasi ini <strong>TIDAK BISA</strong> dibatalkan. settings.delete_notices_1=- Operasi ini <strong>TIDAK BISA</strong> dibatalkan.
settings.transfer_owner=Pemilik Baru settings.transfer_owner=Pemilik Baru
settings.search_user_placeholder=Cari pengguna…
settings.add_webhook=Tambahkan Webhook settings.add_webhook=Tambahkan Webhook
settings.webhook.test_delivery=Percobaan Pengiriman settings.webhook.test_delivery=Percobaan Pengiriman
settings.webhook.request=Permintaan settings.webhook.request=Permintaan
@ -584,6 +675,7 @@ settings.protected_branch_can_push_yes=Anda dapat mendorong
settings.protected_branch_can_push_no=Anda tidak dapat mendorong settings.protected_branch_can_push_no=Anda tidak dapat mendorong
settings.add_protected_branch=Aktifkan perlindungan settings.add_protected_branch=Aktifkan perlindungan
settings.delete_protected_branch=Nonaktifkan perlindungan settings.delete_protected_branch=Nonaktifkan perlindungan
settings.choose_branch=Pilih branch…
diff.browse_source=Telusuri Sumber diff.browse_source=Telusuri Sumber
diff.parent=orang tua diff.parent=orang tua
@ -612,6 +704,7 @@ release.title=Judul
release.content=Konten release.content=Konten
release.write=Menulis release.write=Menulis
release.preview=Pratinjau release.preview=Pratinjau
release.loading=Memuat…
release.cancel=Membatalkan release.cancel=Membatalkan
release.publish=Mempublikasikan Rilis release.publish=Mempublikasikan Rilis
release.save_draft=Simpan Draft release.save_draft=Simpan Draft
@ -636,6 +729,8 @@ people=Orang
teams=Tim teams=Tim
lower_members=anggota lower_members=anggota
lower_repositories=repositori lower_repositories=repositori
create_new_team=Tim Baru
create_team=Buat Tim Baru
org_desc=Deskripsi org_desc=Deskripsi
team_name=Nama tim team_name=Nama tim
team_desc=Deskripsi team_desc=Deskripsi
@ -672,6 +767,7 @@ teams.update_settings=Memperbarui pengaturan
teams.add_team_member=Tambahkan Anggota Tim teams.add_team_member=Tambahkan Anggota Tim
teams.delete_team_success=Tim sudah di hapus. teams.delete_team_success=Tim sudah di hapus.
teams.repositories=Tim repositori teams.repositories=Tim repositori
teams.search_repo_placeholder=Cari repositori…
teams.add_team_repository=Tambahkan Tim Repositori teams.add_team_repository=Tambahkan Tim Repositori
teams.remove_repo=Menghapus teams.remove_repo=Menghapus
teams.add_nonexistent_repo=Repositori yang ingin Anda tambahkan tidak ada; Silahkan buat terlebih dahulu. teams.add_nonexistent_repo=Repositori yang ingin Anda tambahkan tidak ada; Silahkan buat terlebih dahulu.
@ -692,11 +788,10 @@ dashboard.operation_switch=Beralih
dashboard.operation_run=Lari dashboard.operation_run=Lari
dashboard.clean_unbind_oauth=Bersihkan koneksi OAuth yang tidak terikat dashboard.clean_unbind_oauth=Bersihkan koneksi OAuth yang tidak terikat
dashboard.clean_unbind_oauth_success=Semua koneksi OAuth yang tidak terikat telah dihapus. dashboard.clean_unbind_oauth_success=Semua koneksi OAuth yang tidak terikat telah dihapus.
dashboard.delete_inactivate_accounts=Hapus semua akun yang tidak aktif
dashboard.delete_inactivate_accounts_success=Semua akun yang tidak aktif telah dihapus.
dashboard.reinit_missing_repos=Menginstal kembali semua repositori Git yang hilang dimana ada catatan dashboard.reinit_missing_repos=Menginstal kembali semua repositori Git yang hilang dimana ada catatan
dashboard.reinit_missing_repos_success=Semua repositori Git yang hilang yang catatannya dan telah diinisialisasi ulang. dashboard.reinit_missing_repos_success=Semua repositori Git yang hilang yang catatannya dan telah diinisialisasi ulang.
dashboard.sync_external_users=Sinkronkan data pengguna eksternal dashboard.sync_external_users=Sinkronkan data pengguna eksternal
dashboard.git_fsck=Lakukan pemeriksaan kesehatan pada semua repositori
dashboard.server_uptime=Waktu tambahan server dashboard.server_uptime=Waktu tambahan server
dashboard.current_goroutine=Goroutin saat ini dashboard.current_goroutine=Goroutin saat ini
dashboard.current_memory_usage=Penggunaan memori saat ini dashboard.current_memory_usage=Penggunaan memori saat ini
@ -709,6 +804,8 @@ dashboard.heap_memory_idle=Tumpukan memori yang menganggur
dashboard.heap_memory_in_use=Tumpukan memori yang digunakan dashboard.heap_memory_in_use=Tumpukan memori yang digunakan
dashboard.heap_memory_released=Tumpukan memori dirilis dashboard.heap_memory_released=Tumpukan memori dirilis
dashboard.heap_objects=Benda tumpukan dashboard.heap_objects=Benda tumpukan
dashboard.bootstrap_stack_usage=Penggunaan bootstrap Stack
dashboard.stack_memory_obtained=Memori Stack Didapat
dashboard.mspan_structures_usage=Penggunaan struktur MSpan dashboard.mspan_structures_usage=Penggunaan struktur MSpan
dashboard.mspan_structures_obtained=Struktur MSpan didapatkan dashboard.mspan_structures_obtained=Struktur MSpan didapatkan
dashboard.mcache_structures_usage=Penggunaan struktur MCache dashboard.mcache_structures_usage=Penggunaan struktur MCache
@ -725,6 +822,7 @@ dashboard.gc_times=Waktu GC
users.activated=Diaktifkan users.activated=Diaktifkan
users.admin=Pengelola users.admin=Pengelola
users.repos=Repo
users.created=Dibuat users.created=Dibuat
users.edit=Edit users.edit=Edit
users.auth_source=Sumber Otentikasi users.auth_source=Sumber Otentikasi
@ -795,16 +893,24 @@ config.disable_router_log=Menonaktifkan router log
config.run_mode=Jalankan mode config.run_mode=Jalankan mode
config.git_version=Versi Git config.git_version=Versi Git
config.repo_root_path=Jalur akar repositori config.repo_root_path=Jalur akar repositori
config.lfs_root_path=Path Root LFS
config.static_file_root_path=Jalur akar berkas statis config.static_file_root_path=Jalur akar berkas statis
config.script_type=Jenis skrip config.script_type=Jenis skrip
config.reverse_auth_user=Mengembalikan pengguna otentikasi config.reverse_auth_user=Mengembalikan pengguna otentikasi
config.ssh_config=Konfigurasi SSH config.ssh_config=Konfigurasi SSH
config.ssh_enabled=Aktif config.ssh_enabled=Aktif
config.ssh_port=Port
config.ssh_listen_port=Listen Port
config.ssh_root_path=Path Induk
config.ssh_key_test_path=Path Key Test
config.ssh_keygen_path=Path Keygen ('ssh-keygen')
config.ssh_minimum_key_size_check=Periksa ukuran kunci minimum config.ssh_minimum_key_size_check=Periksa ukuran kunci minimum
config.ssh_minimum_key_sizes=Ukuran kunci minimum config.ssh_minimum_key_sizes=Ukuran kunci minimum
config.db_config=Konfigurasi basis data config.db_config=Konfigurasi basis data
config.db_type=Tipe
config.db_host=Host
config.db_name=Nama config.db_name=Nama
config.db_path=Jalur config.db_path=Jalur

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,11 @@
app_desc=痛みのない、自己ホスト型の Git サービス
home=ホーム home=ホーム
dashboard=ダッシュボード dashboard=ダッシュボード
explore=エクスプローラ explore=エクスプローラ
help=ヘルプ help=ヘルプ
sign_in=サインイン sign_in=サインイン
sign_in_with=サインインします。
sign_out=サインアウト sign_out=サインアウト
link_account=連携アカウント link_account=連携アカウント
register=登録 register=登録
@ -706,8 +708,6 @@ dashboard.operation_switch=スイッチ
dashboard.operation_run=実行 dashboard.operation_run=実行
dashboard.clean_unbind_oauth=関連付けられていないOAuth接続を削除 dashboard.clean_unbind_oauth=関連付けられていないOAuth接続を削除
dashboard.clean_unbind_oauth_success=すべての関連付けられていないOAuth接続は削除されました。 dashboard.clean_unbind_oauth_success=すべての関連付けられていないOAuth接続は削除されました。
dashboard.delete_inactivate_accounts=非アクティブのアカウントをすべて削除
dashboard.delete_inactivate_accounts_success=すべての非アクティブなアカウントは削除されました。
dashboard.reinit_missing_repos=レコードが存在するが見当たらないすべてのGitリポジトリを再初期化する dashboard.reinit_missing_repos=レコードが存在するが見当たらないすべてのGitリポジトリを再初期化する
dashboard.reinit_missing_repos_success=レコードが存在するが見当たらないすべてのGitリポジトリが再初期化されました。 dashboard.reinit_missing_repos_success=レコードが存在するが見当たらないすべてのGitリポジトリが再初期化されました。
dashboard.sync_external_users=外部ユーザーデータの同期 dashboard.sync_external_users=外部ユーザーデータの同期

View File

@ -591,7 +591,6 @@ total=총: %d
dashboard.operation_name=작업 명 dashboard.operation_name=작업 명
dashboard.operation_switch=스위치 dashboard.operation_switch=스위치
dashboard.operation_run=실행 dashboard.operation_run=실행
dashboard.delete_inactivate_accounts=활성화되지 않은 모든 계정을 삭제합니다.
dashboard.server_uptime=서버를 켠 시간 dashboard.server_uptime=서버를 켠 시간
dashboard.current_goroutine=현재 Go루틴 dashboard.current_goroutine=현재 Go루틴
dashboard.current_memory_usage=현재 메모리 사용율 dashboard.current_memory_usage=현재 메모리 사용율

File diff suppressed because it is too large Load Diff

View File

@ -61,11 +61,17 @@ smtp_host=SMTP-vert
admin_password=Passord admin_password=Passord
[home] [home]
password_holder=Passord
[explore] [explore]
users=Brukere
[auth] [auth]
register_helper_msg=Har du allerede en konto? Logg inn nå!
remember_me=Husk meg
forgot_password_title=Glemt passord
forgot_password=Glemt passord?
[mail] [mail]

View File

@ -1,11 +1,15 @@
app_desc=Een eenvoudige, self-hosted Git service
home=Beginscherm home=Beginscherm
dashboard=Overzicht dashboard=Overzicht
explore=Verkennen explore=Verkennen
help=Help help=Help
sign_in=Inloggen sign_in=Inloggen
sign_in_with=Inloggen met
sign_out=Uitloggen sign_out=Uitloggen
sign_up=Registreren
link_account=Account Koppelen link_account=Account Koppelen
link_account_signin_or_signup=Login met een bestaande gebruikersnaam/wachtwoord om een bestaand account te koppelen aan dit account, of maak een nieuw account aan.
register=Registreren register=Registreren
website=Website website=Website
version=Versie version=Versie
@ -14,12 +18,29 @@ template=Sjabloon
language=Taal language=Taal
notifications=Meldingen notifications=Meldingen
create_new=Maken… create_new=Maken…
user_profile_and_more=Profiel en instellingen…
signed_in_as=Aangemeld als signed_in_as=Aangemeld als
enable_javascript=Deze website werkt beter met JavaScript.
username=Gebruikersnaam username=Gebruikersnaam
email=E-mail adres
password=Wachtwoord password=Wachtwoord
re_type=Typ uw wachtwoord opnieuw in
captcha=CAPTCHA
twofa=Twee factor authenticatie
twofa_scratch=Eenmalige twee factor authenticatie code
passcode=PIN passcode=PIN
u2f_insert_key=Uw beveiligingssleutel invoegen
u2f_sign_in=Druk op de knop op uw beveiligingssleutel. Als u een knop niet kunt vinden, deze opnieuw invoegen.
u2f_press_button=Druk op de knop op uw beveiligingssleutel…
u2f_use_twofa=Gebruik een twee-factor code van uw telefoon
u2f_error=Wij kunnen niet uw beveiligingssleutel lezen!
u2f_unsupported_browser=Uw browser geen ondersteund U2F keys. Probeer een andere browser.
u2f_error_1=Er is een onbekende fout opgetreden. Probeer het opnieuw.
u2f_error_2=Zorg voor een versleutelde verbinding (https://) en een bezoek aan de juiste URL.
u2f_error_3=De server kan uw aanvraag niet verhandelen.
u2f_reload=Herladen
repository=Repository repository=Repository
organization=Organisatie organization=Organisatie
@ -32,6 +53,8 @@ new_org=Nieuwe organisatie
manage_org=Beheer organisaties manage_org=Beheer organisaties
account_settings=Accountinstellingen account_settings=Accountinstellingen
settings=Instellingen settings=Instellingen
your_profile=Profiel
your_settings=Instellingen
all=Alles all=Alles
sources=Bronnen sources=Bronnen
@ -47,21 +70,35 @@ cancel=Annuleren
[install] [install]
install=Installatie install=Installatie
title=Initiële configuratie
requite_db_desc=Gitea vereist MySQL, PostgreSQL, MSSQL, SQLite3 of TiDB.
db_title=Database-instellingen db_title=Database-instellingen
db_type=Database-type db_type=Database-type
host=Server host=Server
user=Gebruikersnaam
password=Wachtwoord password=Wachtwoord
db_name=Database naam db_name=Database naam
ssl_mode=SSL
path=Pad path=Pad
err_empty_db_path=Het SQLite3 of TiDB database pad mag niet leeg zijn.
err_empty_admin_password=Het administrator-wachtwoord mag niet leeg zijn.
general_title=Algemene Instellingen
repo_path=Repositories basis map repo_path=Repositories basis map
lfs_path=Git LFS root pad
app_url=Gitea base URL
log_root_path=Log-pad log_root_path=Log-pad
optional_title=Optionele instellingen optional_title=Optionele instellingen
email_title=E-mail instellingen
smtp_host=SMTP host smtp_host=SMTP host
smtp_from=E-mails versturen als
mailer_user=SMTP gebruikersnaam
mailer_password=SMTP wachtwoord
federated_avatar_lookup_popup=Enable federated avatars lookup to use federated open source service based on libravatar. federated_avatar_lookup_popup=Enable federated avatars lookup to use federated open source service based on libravatar.
openid_signin=OpenID-inloggen inschakelen openid_signin=OpenID-inloggen inschakelen
enable_captcha_popup=Vereis captcha validatie voor zelf-registratie van gebruiker. enable_captcha_popup=Vereis captcha validatie voor zelf-registratie van gebruiker.
admin_name=Admin gebruikersnaam
admin_password=Wachtwoord admin_password=Wachtwoord
confirm_password=Verifieer wachtwoord confirm_password=Verifieer wachtwoord
install_btn_confirm=Installeer Gitea install_btn_confirm=Installeer Gitea
@ -95,6 +132,8 @@ forgot_password=Wachtwoord vergeten?
confirmation_mail_sent_prompt=Een nieuwe bevestigingsmail is gestuurd naar <b>%s</b>. De mail moet binnen %s worden bevestigd om je registratie te voltooien. confirmation_mail_sent_prompt=Een nieuwe bevestigingsmail is gestuurd naar <b>%s</b>. De mail moet binnen %s worden bevestigd om je registratie te voltooien.
reset_password_mail_sent_prompt=Een bevestigingsmail is gestuurd naar <b>%s</b>. De mail moet binnen %s worden bevestigd om wachtwoord reset proces te voltooien. reset_password_mail_sent_prompt=Een bevestigingsmail is gestuurd naar <b>%s</b>. De mail moet binnen %s worden bevestigd om wachtwoord reset proces te voltooien.
active_your_account=Activeer uw account active_your_account=Activeer uw account
prohibit_login=Inloggen niet toegestaan
prohibit_login_desc=Je mag met dit account niet inloggen, neem contact op met de beheerder van de site.
has_unconfirmed_mail=Beste %s, u heeft een onbevestigd e-mailadres (<b>%s</b>). Als u nog geen bevestiging heeft ontvangen, of u een nieuwe aanvraag wilt doen, klik dan op de onderstaande knop. has_unconfirmed_mail=Beste %s, u heeft een onbevestigd e-mailadres (<b>%s</b>). Als u nog geen bevestiging heeft ontvangen, of u een nieuwe aanvraag wilt doen, klik dan op de onderstaande knop.
resend_mail=Klik hier om uw activatie mail nog een keer te verzenden resend_mail=Klik hier om uw activatie mail nog een keer te verzenden
email_not_associate=Dit emailadres is niet gekoppeld aan een account. email_not_associate=Dit emailadres is niet gekoppeld aan een account.
@ -150,6 +189,8 @@ url_error=is niet een valide URL.
include_error=` moet substring '%s' bevatten.` include_error=` moet substring '%s' bevatten.`
unknown_error=Onbekende fout: unknown_error=Onbekende fout:
username_been_taken=Deze naam is al in gebruik.
username_password_incorrect=Gebruikersnaam of wachtwoord is onjuist.
user_not_exist=De gebruiker bestaat niet. user_not_exist=De gebruiker bestaat niet.
auth_failed=Verificatie mislukt: %v auth_failed=Verificatie mislukt: %v
@ -186,6 +227,7 @@ website=Website
location=Locatie location=Locatie
update_profile=Profiel bijwerken update_profile=Profiel bijwerken
update_profile_success=Je profiel is bijgewerkt. update_profile_success=Je profiel is bijgewerkt.
change_username=Je gebruikersnaam is gewijzigd.
continue=Doorgaan continue=Doorgaan
cancel=Annuleren cancel=Annuleren
@ -678,8 +720,6 @@ total=Totaal: %d
dashboard.operation_name=Bewerking naam dashboard.operation_name=Bewerking naam
dashboard.operation_switch=Omschakelen dashboard.operation_switch=Omschakelen
dashboard.operation_run=Uitvoeren dashboard.operation_run=Uitvoeren
dashboard.delete_inactivate_accounts=Verwijder alle inactieve accounts
dashboard.delete_inactivate_accounts_success=Alle inactieve accounts zijn verwijderd.
dashboard.sync_external_users=Externe gebruikersgegevens synchroniseren dashboard.sync_external_users=Externe gebruikersgegevens synchroniseren
dashboard.server_uptime=Uptime server dashboard.server_uptime=Uptime server
dashboard.current_goroutine=Huidige Goroutines dashboard.current_goroutine=Huidige Goroutines
@ -709,6 +749,7 @@ dashboard.total_gc_pause=Totaal GC verwerkingstijd
dashboard.last_gc_pause=Laatste GC verwerkingstijd dashboard.last_gc_pause=Laatste GC verwerkingstijd
dashboard.gc_times=GC verwerkingen dashboard.gc_times=GC verwerkingen
users.name=Gebruikersnaam
users.activated=Geactiveerd users.activated=Geactiveerd
users.admin=Beheerder users.admin=Beheerder
users.repos=Repos users.repos=Repos
@ -783,6 +824,7 @@ config.db_config=Databaseconfiguratie
config.db_type=Type config.db_type=Type
config.db_host=Host config.db_host=Host
config.db_name=Naam config.db_name=Naam
config.db_user=Gebruikersnaam
config.db_path=Pad config.db_path=Pad
config.service_config=Serviceconfiguratie config.service_config=Serviceconfiguratie

View File

@ -1,10 +1,13 @@
app_desc=Bezbolesna usługa Git na własnym serwerze
home=Strona główna home=Strona główna
dashboard=Pulpit dashboard=Pulpit
explore=Odkrywaj explore=Odkrywaj
help=Pomoc help=Pomoc
sign_in=Zaloguj się sign_in=Zaloguj się
sign_in_with=Zaloguj się za pomocą
sign_out=Wyloguj sign_out=Wyloguj
sign_up=Zarejestruj
link_account=Powiąż konto link_account=Powiąż konto
register=Zarejestruj się register=Zarejestruj się
website=Strona website=Strona
@ -13,12 +16,21 @@ page=Strona
template=Szablon template=Szablon
language=Język language=Język
notifications=Powiadomienia notifications=Powiadomienia
create_new=Utwórz…
user_profile_and_more=Profil i ustawienia…
signed_in_as=Zalogowany jako signed_in_as=Zalogowany jako
enable_javascript=Strona działa najlepiej z włączonym JavaScript.
username=Nazwa użytkownika username=Nazwa użytkownika
email=Adres e-mail
password=Hasło password=Hasło
re_type=Wpisz ponownie hasło
captcha=CAPTCHA
twofa=Autoryzacja dwuskładnikowa
twofa_scratch=Kod jednorazowy weryfikacji dwuetapowej
passcode=Kod dostępu passcode=Kod dostępu
u2f_reload=Odśwież
repository=Repozytorium repository=Repozytorium
organization=Organizacja organization=Organizacja
@ -29,8 +41,12 @@ new_mirror=Nowa kopia lustrzana
new_fork=Nowy fork repozytorium new_fork=Nowy fork repozytorium
new_org=Nowa organizacja new_org=Nowa organizacja
manage_org=Zarządzaj organizacjami manage_org=Zarządzaj organizacjami
admin_panel=Administracja stron
account_settings=Ustawienia konta account_settings=Ustawienia konta
settings=Ustawienia settings=Ustawienia
your_profile=Profil
your_starred=Z gwiazdką
your_settings=Ustawienia
all=Wszystko all=Wszystko
sources=Źródła sources=Źródła
@ -46,34 +62,61 @@ cancel=Anuluj
[install] [install]
install=Instalacja install=Instalacja
title=Wstępna konfiguracja
db_title=Ustawienia bazy danych db_title=Ustawienia bazy danych
db_type=Typ bazy danych db_type=Typ bazy danych
host=Serwer host=Serwer
user=Nazwa użytkownika
password=Hasło password=Hasło
db_name=Nazwa bazy danych db_name=Nazwa bazy danych
ssl_mode=SSL
path=Ścieżka path=Ścieżka
err_empty_db_path=Ścieżka do bazy danych SQLite3 lub TiDB nie może być pusta.
err_empty_admin_password=Hasło administratora nie może być puste.
general_title=Ustawienia ogólne
app_name=Tytuł witryny
app_name_helper=Wprowadź nazwę firmy.
repo_path=Katalog repozytoriów repo_path=Katalog repozytoriów
lfs_path=Ścieżka główna Git LFS
run_user=Uruchom jako nazwa użytkownika
domain=Domena serwera SSH
ssh_port=Port serwera SSH
app_url=Podstawowy adres URL Gitea
log_root_path=Ścieżka dla logów log_root_path=Ścieżka dla logów
optional_title=Ustawienia opcjonalne optional_title=Ustawienia opcjonalne
email_title=Ustawienia e-mail
smtp_host=Serwer SMTP smtp_host=Serwer SMTP
smtp_from=Wyślij e-mail jako
mailer_user=Nazwa użytkownika SMTP
mailer_password=Hasło SMTP
register_confirm=Wymagają potwierdzenia e-mail przy rejestracji
mail_notify=Włącz powiadomienia e-mail
disable_gravatar=Wyłącz Gravatar
federated_avatar_lookup_popup=Enable federated avatars lookup to use federated open source service based on libravatar. federated_avatar_lookup_popup=Enable federated avatars lookup to use federated open source service based on libravatar.
disable_registration=Wyłącz rejestrację dwuskładnikową
openid_signin=Włącz logowanie za pomocą OpenID openid_signin=Włącz logowanie za pomocą OpenID
enable_captcha=Włącz CAPTCHA
enable_captcha_popup=Wymagaj walidacji CAPTCHA przy samodzielnej rejestracji użytkownika. enable_captcha_popup=Wymagaj walidacji CAPTCHA przy samodzielnej rejestracji użytkownika.
admin_password=Hasło admin_password=Hasło
confirm_password=Potwierdź hasło confirm_password=Potwierdź hasło
admin_email=Adres e-mail
install_btn_confirm=Zainstaluj Gitea install_btn_confirm=Zainstaluj Gitea
test_git_failed=Nie udało się przetestować polecenia „git”: %v test_git_failed=Nie udało się przetestować polecenia „git”: %v
save_config_failed=Nie udało się zapisać konfiguracji: %v save_config_failed=Nie udało się zapisać konfiguracji: %v
[home] [home]
uname_holder=Nazwa użytkownika lub adres email
password_holder=Hasło password_holder=Hasło
switch_dashboard_context=Przełącz kontekst pulpitu switch_dashboard_context=Przełącz kontekst pulpitu
my_repos=Repozytoria
show_more_repos=Pokaż więcej repozytoriów…
collaborative_repos=Wspólne repozytoria collaborative_repos=Wspólne repozytoria
my_orgs=Moje organizacje my_orgs=Moje organizacje
my_mirrors=Moje kopie lustrzane my_mirrors=Moje kopie lustrzane
view_home=Zobacz %s view_home=Zobacz %s
search_repos=Znajdź repozytorium…
issues.in_your_repos=W Twoich repozytoriach issues.in_your_repos=W Twoich repozytoriach
@ -82,12 +125,20 @@ repos=Repozytoria
users=Użytkownicy users=Użytkownicy
organizations=Organizacje organizations=Organizacje
search=Wyszukiwanie search=Wyszukiwanie
code=Kod
repo_no_results=Nie znaleziono pasujących repozytoriów.
user_no_results=Nie znaleziono pasującego użytkowników.
org_no_results=Nie znaleziono pasujących organizacji.
code_search_results=Wyniki wyszukiwania dla '%s'
[auth] [auth]
create_new_account=Zarejestruj konto
register_helper_msg=Masz już konto? Zaloguj się teraz! register_helper_msg=Masz już konto? Zaloguj się teraz!
social_register_helper_msg=Masz już konto? Powiąż je teraz!
remember_me=Zapamiętaj mnie remember_me=Zapamiętaj mnie
forgot_password_title=Zapomniałem hasła forgot_password_title=Zapomniałem hasła
forgot_password=Zapomniałeś hasła? forgot_password=Zapomniałeś hasła?
sign_up_now=Potrzebujesz konta? Zarejestruj się teraz.
confirmation_mail_sent_prompt=Nowy email aktywacyjny został wysłany na adres <b>%s</b>. Sprawdź swoją skrzynkę odbiorczą w ciągu %s aby zakończyć proces rejestracji. confirmation_mail_sent_prompt=Nowy email aktywacyjny został wysłany na adres <b>%s</b>. Sprawdź swoją skrzynkę odbiorczą w ciągu %s aby zakończyć proces rejestracji.
reset_password_mail_sent_prompt=Email potwierdzający został wysłany na adres <b>%s</b>. Sprawdź swoją skrzynkę odbiorczą w ciągu %s aby zakończyć proces resetowania hasła. reset_password_mail_sent_prompt=Email potwierdzający został wysłany na adres <b>%s</b>. Sprawdź swoją skrzynkę odbiorczą w ciągu %s aby zakończyć proces resetowania hasła.
active_your_account=Aktywuj swoje konto active_your_account=Aktywuj swoje konto
@ -102,6 +153,7 @@ scratch_code=Kod jednorazowy
use_scratch_code=Użyj kodu jednorazowego use_scratch_code=Użyj kodu jednorazowego
twofa_scratch_used=Użyłeś/aś swojego kodu jednorazowego. Przekierowano Cię do strony z ustawieniami autoryzacji dwuetapowej, gdzie możesz usunąć swoje urządzenie lub wygenerować nowy kod jednorazowy. twofa_scratch_used=Użyłeś/aś swojego kodu jednorazowego. Przekierowano Cię do strony z ustawieniami autoryzacji dwuetapowej, gdzie możesz usunąć swoje urządzenie lub wygenerować nowy kod jednorazowy.
twofa_scratch_token_incorrect=Twój kod jednorazowy jest niepoprawny. twofa_scratch_token_incorrect=Twój kod jednorazowy jest niepoprawny.
login_userpass=Zaloguj się
login_openid=OpenID login_openid=OpenID
openid_connect_submit=Połącz openid_connect_submit=Połącz
openid_connect_title=Połącz z istniejącym kontem openid_connect_title=Połącz z istniejącym kontem
@ -117,12 +169,14 @@ register_notify=Witamy w Gitea
[modal] [modal]
yes=Tak yes=Tak
no=Nie no=Nie
modify=Aktualizuj
[form] [form]
UserName=Nazwa użytkownika UserName=Nazwa użytkownika
RepoName=Nazwa repozytorium RepoName=Nazwa repozytorium
Email=Adres e-mail Email=Adres e-mail
Password=Hasło Password=Hasło
Retype=Wpisz ponownie hasło
SSHTitle=Nazwa klucza SSH SSHTitle=Nazwa klucza SSH
HttpsUrl=HTTPS URL HttpsUrl=HTTPS URL
PayloadUrl=URL do wywołania PayloadUrl=URL do wywołania
@ -145,7 +199,13 @@ email_error=` nie jest poprawnym adresem e-mail.`
url_error=` nie jest poprawnym adresem URL.` url_error=` nie jest poprawnym adresem URL.`
include_error=`musi zawierać tekst '%s'.` include_error=`musi zawierać tekst '%s'.`
unknown_error=Nieznany błąd: unknown_error=Nieznany błąd:
captcha_incorrect=Kod CAPTCHA jest nieprawidłowy.
password_not_match=Hasła nie są identyczne.
username_been_taken=Ta nazwa użytkownika jest już zajęta.
repo_name_been_taken=Nazwa repozytorium jest już zajęta.
org_name_been_taken=Nazwa organizacji jest już zajęta.
team_name_been_taken=Nazwa zespołu jest już zajęta.
user_not_exist=Użytkownik nie istnieje. user_not_exist=Użytkownik nie istnieje.
auth_failed=Uwierzytelnienie się nie powiodło: %v auth_failed=Uwierzytelnienie się nie powiodło: %v
@ -154,6 +214,7 @@ auth_failed=Uwierzytelnienie się nie powiodło: %v
target_branch_not_exist=Gałąź docelowa nie istnieje. target_branch_not_exist=Gałąź docelowa nie istnieje.
[user] [user]
change_avatar=Zmień swój awatar…
join_on=Dołączył join_on=Dołączył
repositories=Repozytoria repositories=Repozytoria
activity=Publiczna aktywność activity=Publiczna aktywność
@ -166,15 +227,21 @@ form.name_reserved=Nazwa użytkownika '%s' jest zarezerwowana.
[settings] [settings]
profile=Profil profile=Profil
account=Konto
password=Hasło password=Hasło
security=Bezpieczeństwo security=Bezpieczeństwo
avatar=Awatar avatar=Awatar
ssh_gpg_keys=Klucze SSH / GPG ssh_gpg_keys=Klucze SSH / GPG
social=Konta społecznościowe social=Konta społecznościowe
applications=Aplikacje
orgs=Zarządzaj organizacjami
repos=Repozytoria repos=Repozytoria
delete=Usuń konto delete=Usuń konto
twofa=Autoryzacja dwuetapowa twofa=Autoryzacja dwuetapowa
account_link=Powiązane Konta
organization=Organizacje
uid=UID uid=UID
u2f=Klucze bezpieczeństwa
public_profile=Profil publiczny public_profile=Profil publiczny
full_name=Imię i nazwisko full_name=Imię i nazwisko
@ -182,20 +249,33 @@ website=Strona
location=Lokalizacja location=Lokalizacja
update_profile=Zaktualizuj profil update_profile=Zaktualizuj profil
update_profile_success=Twój profil został zaktualizowany. update_profile_success=Twój profil został zaktualizowany.
change_username=Twój nick został zmieniony.
continue=Kontynuuj continue=Kontynuuj
cancel=Anuluj cancel=Anuluj
language=Język
federated_avatar_lookup=Wyszukiwanie zewnętrznych awatarów federated_avatar_lookup=Wyszukiwanie zewnętrznych awatarów
enable_custom_avatar=Włącz niestandardowe awatary enable_custom_avatar=Włącz niestandardowe awatary
choose_new_avatar=Wybierz nowy avatar choose_new_avatar=Wybierz nowy avatar
update_avatar=Aktualizuj awatar
delete_current_avatar=Usuń obecny Avatar delete_current_avatar=Usuń obecny Avatar
uploaded_avatar_not_a_image=Załadowany plik nie jest obrazem.
update_avatar_success=Twój awatar został zmieniony.
change_password=Aktualizuj hasło
old_password=Aktualne hasło old_password=Aktualne hasło
new_password=Nowe hasło new_password=Nowe hasło
retype_new_password=Powtórz nowe hasło
password_incorrect=Bieżące hasło nie jest prawidłowe.
emails=Adresy e-mail emails=Adresy e-mail
manage_emails=Zarządzaj adresami e-mail
email_desc=Twój podstawowy adres e-mail będzie używany do powiadomień i innych działań. email_desc=Twój podstawowy adres e-mail będzie używany do powiadomień i innych działań.
primary=Podstawowy primary=Podstawowy
delete_email=Usuń
email_deletion=Usuń adres email
add_new_email=Dodaj nowy e-mail
add_email=Dodaj adres e-mail
add_openid=Dodaj OpenID URI add_openid=Dodaj OpenID URI
manage_ssh_keys=Zarządzaj kluczami SSH manage_ssh_keys=Zarządzaj kluczami SSH
@ -209,6 +289,11 @@ subkeys=Podklucze
key_id=ID klucza key_id=ID klucza
key_name=Nazwa klucza key_name=Nazwa klucza
key_content=Treść key_content=Treść
delete_key=Usuń
ssh_key_deletion=Usuń klucz SSH
gpg_key_deletion=Usuń klucz GPG
ssh_key_deletion_success=Klucz SSH został usunięty.
gpg_key_deletion_success=Klucz GPG został usunięty.
add_on=Dodano add_on=Dodano
valid_until=Ważne do valid_until=Ważne do
valid_forever=Ważne bezterminowo valid_forever=Ważne bezterminowo
@ -220,8 +305,10 @@ key_state_desc=Ten klucz był użyty w ciągu ostatnich 7 dni
token_state_desc=Ten token był użyty w ciągu ostatnich 7 dni token_state_desc=Ten token był użyty w ciągu ostatnich 7 dni
show_openid=Pokaż w profilu show_openid=Pokaż w profilu
hide_openid=Ukryj w profilu hide_openid=Ukryj w profilu
ssh_disabled=SSH jest wyłączony
manage_social=Zarządzaj powiązanymi kontami społecznościowymi manage_social=Zarządzaj powiązanymi kontami społecznościowymi
unbind=Rozłącz
generate_new_token=Wygeneruj nowy token generate_new_token=Wygeneruj nowy token
token_name=Nazwa tokena token_name=Nazwa tokena
@ -230,6 +317,7 @@ delete_token=Usuń
twofa_is_enrolled=Twoje konto ma obecnie <strong>włączoną</strong> autoryzację dwuetapową. twofa_is_enrolled=Twoje konto ma obecnie <strong>włączoną</strong> autoryzację dwuetapową.
twofa_not_enrolled=Twoje konto obecnie nie ma włączonej autoryzacji dwuetapowej. twofa_not_enrolled=Twoje konto obecnie nie ma włączonej autoryzacji dwuetapowej.
twofa_disable=Wyłącz weryfikację dwuetapową
twofa_disabled=Dwuetapowa autoryzacja została wyłączona. twofa_disabled=Dwuetapowa autoryzacja została wyłączona.
scan_this_image=Zeskanuj ten obraz za pomocą swojej aplikacji uwierzytelniającej: scan_this_image=Zeskanuj ten obraz za pomocą swojej aplikacji uwierzytelniającej:
or_enter_secret=Lub wprowadź sekret: %s or_enter_secret=Lub wprowadź sekret: %s
@ -241,6 +329,7 @@ repos_none=Nie posiadasz żadnych repozytoriów
delete_account=Usuń swoje konto delete_account=Usuń swoje konto
confirm_delete_account=Potwierdź usunięcie confirm_delete_account=Potwierdź usunięcie
delete_account_title=Usuń swoje konto
[repo] [repo]
owner=Właściciel owner=Właściciel
@ -250,7 +339,10 @@ fork_repo=Sforkowane
fork_from=Forkuj z fork_from=Forkuj z
repo_desc=Opis repo_desc=Opis
repo_lang=Język repo_lang=Język
repo_gitignore_helper=Wybierz szablony pliku .gitignore.
license=Licencja license=Licencja
license_helper=Wybierz plik licencji.
readme=README
create_repo=Utwórz repozytorium create_repo=Utwórz repozytorium
default_branch=Domyślna gałąź default_branch=Domyślna gałąź
mirror_prune=Wyczyść mirror_prune=Wyczyść
@ -272,12 +364,14 @@ migrate.failed=Migracja nie powiodła się: %v
mirror_from=kopia lustrzana mirror_from=kopia lustrzana
forked_from=sklonowany z forked_from=sklonowany z
copy_link=Kopiuj copy_link=Kopiuj
copy_link_success=Link został skopiowany
copied=Skopiowano copied=Skopiowano
unwatch=Przestań obserwować unwatch=Przestań obserwować
watch=Obserwuj watch=Obserwuj
unstar=Usuń gwiazdkę unstar=Usuń gwiazdkę
star=Gwiazdka star=Gwiazdka
fork=Forkuj fork=Forkuj
download_archive=Pobierz repozytorium
no_desc=Brak opisu no_desc=Brak opisu
quick_guide=Skrócona instrukcja quick_guide=Skrócona instrukcja
@ -305,30 +399,45 @@ file_view_raw=Zobacz czysty
file_permalink=Bezpośredni odnośnik file_permalink=Bezpośredni odnośnik
stored_lfs=Przechowane za pomocą Git LFS stored_lfs=Przechowane za pomocą Git LFS
editor.new_file=Nowy plik
editor.upload_file=Wyślik plik
editor.edit_file=Edytuj plik
editor.preview_changes=Podgląd zmian editor.preview_changes=Podgląd zmian
editor.edit_this_file=Edytuj plik
editor.delete_this_file=Usuń plik
editor.file_delete_success=Plik %s został usunięty.
editor.name_your_file=Nazwij plik…
editor.or=lub editor.or=lub
editor.cancel_lower=Anuluj
editor.commit_changes=Zatwierdź zmiany editor.commit_changes=Zatwierdź zmiany
editor.add_tmpl=Dodaj '%s/<filename>' editor.add_tmpl=Dodaj '%s/<filename>'
editor.add=Dodaj '%s' editor.add=Dodaj '%s'
editor.update=Zaktualizuj '%s' editor.update=Zaktualizuj '%s'
editor.delete=Usuń '%s' editor.delete=Usuń '%s'
editor.commit_message_desc=Dodaj dodatkowy rozszerzony opis…
editor.commit_directly_to_this_branch=Zmieniaj bezpośrednio gałąź <strong class="branch-name">%s</strong>. editor.commit_directly_to_this_branch=Zmieniaj bezpośrednio gałąź <strong class="branch-name">%s</strong>.
editor.create_new_branch=Stwórz <strong>nową gałąź</strong> dla tego commita i rozpocznij pull request. editor.create_new_branch=Stwórz <strong>nową gałąź</strong> dla tego commita i rozpocznij pull request.
editor.new_branch_name_desc=Nazwa nowej gałęzi…
editor.cancel=Anuluj editor.cancel=Anuluj
editor.filename_cannot_be_empty=Nazwa pliku nie może być pusta.
editor.branch_already_exists=Gałąź '%s' już istnieje w tym repozytorium. editor.branch_already_exists=Gałąź '%s' już istnieje w tym repozytorium.
editor.no_changes_to_show=Brak zmian do pokazania. editor.no_changes_to_show=Brak zmian do pokazania.
editor.fail_to_update_file=Tworzenie/aktualizacja pliku '%s' nie powiodła się z błędem: %v editor.fail_to_update_file=Tworzenie/aktualizacja pliku '%s' nie powiodła się z błędem: %v
editor.add_subdir=Dodaj katalog…
editor.unable_to_upload_files=Wysyłanie plików do '%s' nie powiodło się z błędem: %v editor.unable_to_upload_files=Wysyłanie plików do '%s' nie powiodło się z błędem: %v
editor.upload_files_to_dir=Prześlij pliki do '%s' editor.upload_files_to_dir=Prześlij pliki do '%s'
commits.commits=Commity commits.commits=Commity
commits.search=Przeszukaj commity…
commits.find=Szukaj commits.find=Szukaj
commits.search_all=Wszystkie gałęzie
commits.author=Autor commits.author=Autor
commits.message=Wiadomość commits.message=Wiadomość
commits.date=Data commits.date=Data
commits.older=Starsze commits.older=Starsze
commits.newer=Nowsze commits.newer=Nowsze
commits.signed_by=Podpisane przez commits.signed_by=Podpisane przez
commits.gpg_key_id=ID klucza GPG
issues.new=Nowy problem issues.new=Nowy problem
@ -343,6 +452,8 @@ issues.new.closed_milestone=Zamknięte kamienie milowe
issues.no_ref=Nie określono gałęzi/etykiety issues.no_ref=Nie określono gałęzi/etykiety
issues.create=Utwórz problem issues.create=Utwórz problem
issues.new_label=Nowa etykieta issues.new_label=Nowa etykieta
issues.new_label_placeholder=Nazwa etykiety
issues.new_label_desc_placeholder=Opis
issues.create_label=Utwórz etykietę issues.create_label=Utwórz etykietę
issues.label_templates.title=Załaduj wstępnie przygotowany zestaw etykiet issues.label_templates.title=Załaduj wstępnie przygotowany zestaw etykiet
issues.label_templates.helper=Wybierz zestaw etykiet issues.label_templates.helper=Wybierz zestaw etykiet
@ -361,6 +472,7 @@ issues.delete_branch_at=`usunął gałąź <b>%s</b> %s`
issues.open_tab=Otwarte %d issues.open_tab=Otwarte %d
issues.close_tab=Zamknięte %d issues.close_tab=Zamknięte %d
issues.filter_label=Etykieta issues.filter_label=Etykieta
issues.filter_label_no_select=Wszystkie etykiety
issues.filter_milestone=Kamień milowy issues.filter_milestone=Kamień milowy
issues.filter_assignee=Przypisany issues.filter_assignee=Przypisany
issues.filter_type=Typ issues.filter_type=Typ
@ -411,6 +523,8 @@ issues.label_count=Etykiety %d
issues.label_open_issues=Otwarte problemy %d issues.label_open_issues=Otwarte problemy %d
issues.label_edit=Edytuj issues.label_edit=Edytuj
issues.label_delete=Usuń issues.label_delete=Usuń
issues.label_modify=Edytuj etykietę
issues.label_deletion=Usuń etykietę
issues.label.filter_sort.alphabetically=Alfabetycznie issues.label.filter_sort.alphabetically=Alfabetycznie
issues.label.filter_sort.reverse_alphabetically=Alfabetycznie odwrotnie issues.label.filter_sort.reverse_alphabetically=Alfabetycznie odwrotnie
issues.label.filter_sort.by_size=Rozmiar issues.label.filter_sort.by_size=Rozmiar
@ -420,17 +534,20 @@ issues.attachment.open_tab=`Kliknij, aby zobaczyć „%s” w nowej karcie`
issues.attachment.download=`Kliknij, aby pobrać „%s”` issues.attachment.download=`Kliknij, aby pobrać „%s”`
issues.subscribe=Subskrybuj issues.subscribe=Subskrybuj
issues.unsubscribe=Anuluj subskrypcję issues.unsubscribe=Anuluj subskrypcję
issues.tracker=Śledzenie czasu
issues.start_tracking_short=Rozpocznij issues.start_tracking_short=Rozpocznij
issues.start_tracking_history=`rozpoczął pracę nad %s` issues.start_tracking_history=`rozpoczął pracę nad %s`
issues.tracking_already_started=`Już śledzisz czas pracy nad tą <a href="%s">sprawą</a>!` issues.tracking_already_started=`Już śledzisz czas pracy nad tą <a href="%s">sprawą</a>!`
issues.stop_tracking=Zatrzymaj issues.stop_tracking=Zatrzymaj
issues.stop_tracking_history=`zakończył pracę nad %s` issues.stop_tracking_history=`zakończył pracę nad %s`
issues.add_time_short=Dodaj czas
issues.add_time_cancel=Anuluj issues.add_time_cancel=Anuluj
issues.add_time_history=`dodano spędzony czas %s` issues.add_time_history=`dodano spędzony czas %s`
issues.add_time_hours=Godziny issues.add_time_hours=Godziny
issues.add_time_minutes=Minuty issues.add_time_minutes=Minuty
issues.cancel_tracking=Anuluj issues.cancel_tracking=Anuluj
issues.cancel_tracking_history=`anulowanie śledzenie czasu %s` issues.cancel_tracking_history=`anulowanie śledzenie czasu %s`
issues.due_date_form=yyyy-mm-dd
pulls.new=Nowy pull request pulls.new=Nowy pull request
pulls.filter_branch=Filtruj branch pulls.filter_branch=Filtruj branch
@ -471,6 +588,7 @@ milestones.filter_sort.least_issues=Najmniej problemów
wiki=Wiki wiki=Wiki
wiki.page=Strona wiki.page=Strona
wiki.filter_page=Filtruj stronę wiki.filter_page=Filtruj stronę
wiki.new_page=Strona
wiki.default_commit_message=Opisz tę zmianę (opcjonalne). wiki.default_commit_message=Opisz tę zmianę (opcjonalne).
wiki.save_page=Zapisz stronę wiki.save_page=Zapisz stronę
wiki.last_commit_info=%s edytuje tę stronę %s wiki.last_commit_info=%s edytuje tę stronę %s
@ -526,6 +644,7 @@ search.results=Wyniki wyszukiwania dla "%s" w <a href="%s">%s</a>
settings=Ustawienia settings=Ustawienia
settings.desc=Ustawienia to miejsce, w którym możesz zmieniać parametry repozytorium settings.desc=Ustawienia to miejsce, w którym możesz zmieniać parametry repozytorium
settings.options=Repozytorium
settings.collaboration.write=Zapis settings.collaboration.write=Zapis
settings.collaboration.read=Odczyt settings.collaboration.read=Odczyt
settings.collaboration.undefined=Niezdefiniowany settings.collaboration.undefined=Niezdefiniowany
@ -533,6 +652,8 @@ settings.hooks=Webhooki
settings.githooks=Hooki Git settings.githooks=Hooki Git
settings.basic_settings=Ustawienia podstawowe settings.basic_settings=Ustawienia podstawowe
settings.mirror_settings=Kopia lustrzana ustawień settings.mirror_settings=Kopia lustrzana ustawień
settings.sync_mirror=Synchronizuj teraz
settings.site=Strona
settings.update_settings=Aktualizuj ustawienia settings.update_settings=Aktualizuj ustawienia
settings.advanced_settings=Ustawienia zaawansowane settings.advanced_settings=Ustawienia zaawansowane
settings.external_wiki_url=Adres URL zewnętrznego Wiki settings.external_wiki_url=Adres URL zewnętrznego Wiki
@ -546,11 +667,15 @@ settings.transfer=Przeniesienie własności
settings.delete=Usuń to repozytorium settings.delete=Usuń to repozytorium
settings.delete_notices_1=- Ta operacja <strong>NIE MOŻE</strong> zostać cofnięta. settings.delete_notices_1=- Ta operacja <strong>NIE MOŻE</strong> zostać cofnięta.
settings.transfer_owner=Nowy właściciel settings.transfer_owner=Nowy właściciel
settings.confirm_delete=Usuń repozytorium
settings.delete_collaborator=Usuń
settings.search_user_placeholder=Szukaj użytkownika…
settings.add_webhook=Dodaj webhooka settings.add_webhook=Dodaj webhooka
settings.webhook.test_delivery=Testuj dostawę settings.webhook.test_delivery=Testuj dostawę
settings.webhook.request=Żądanie settings.webhook.request=Żądanie
settings.webhook.response=Odpowiedź settings.webhook.response=Odpowiedź
settings.webhook.headers=Nagłówki settings.webhook.headers=Nagłówki
settings.webhook.payload=Zawartość
settings.webhook.body=Treść settings.webhook.body=Treść
settings.githook_edit_desc=Jeśli hook jest nieaktywny, zaprezentowana zostanie przykładowa treść. Pozostawienie pustej wartości wyłączy ten hook. settings.githook_edit_desc=Jeśli hook jest nieaktywny, zaprezentowana zostanie przykładowa treść. Pozostawienie pustej wartości wyłączy ten hook.
settings.githook_name=Nazwa hooka settings.githook_name=Nazwa hooka
@ -583,6 +708,7 @@ settings.protected_branch_can_push_yes=Możesz wysyłać
settings.protected_branch_can_push_no=Nie możesz wysyłać settings.protected_branch_can_push_no=Nie możesz wysyłać
settings.add_protected_branch=Włącz ochronę settings.add_protected_branch=Włącz ochronę
settings.delete_protected_branch=Wyłącz ochronę settings.delete_protected_branch=Wyłącz ochronę
settings.choose_branch=Wybierz gałąź…
diff.browse_source=Przeglądaj źródła diff.browse_source=Przeglądaj źródła
diff.parent=rodzic diff.parent=rodzic
@ -611,6 +737,7 @@ release.title=Tytuł
release.content=Treść release.content=Treść
release.write=Napisz release.write=Napisz
release.preview=Podgląd release.preview=Podgląd
release.loading=Ładowanie…
release.cancel=Anuluj release.cancel=Anuluj
release.publish=Publikuj wersję release.publish=Publikuj wersję
release.save_draft=Zapisz szkic release.save_draft=Zapisz szkic
@ -625,6 +752,7 @@ branch.create_from=z '%s'
branch.branch_already_exists=Gałąź '%s' już istnieje w tym repozytorium. branch.branch_already_exists=Gałąź '%s' już istnieje w tym repozytorium.
branch.deleted_by=Usunięta przez %s branch.deleted_by=Usunięta przez %s
topic.done=Gotowe
[org] [org]
org_name_holder=Nazwa organizacji org_name_holder=Nazwa organizacji
@ -635,12 +763,16 @@ people=Ludzie
teams=Zespoły teams=Zespoły
lower_members=członkowie lower_members=członkowie
lower_repositories=repozytoria lower_repositories=repozytoria
create_new_team=Nowy zespół
create_team=Utwórz zespół
org_desc=Opis org_desc=Opis
team_name=Nazwa zespołu team_name=Nazwa zespołu
team_desc=Opis team_desc=Opis
team_permission_desc=Uprawnienie
settings=Ustawienia settings=Ustawienia
settings.options=Organizacja
settings.full_name=Imię i nazwisko settings.full_name=Imię i nazwisko
settings.website=Strona settings.website=Strona
settings.location=Lokalizacja settings.location=Lokalizacja
@ -649,9 +781,12 @@ settings.update_setting_success=Ustawienia organizacji zostały zaktualizowane.
settings.delete=Usuń organizację settings.delete=Usuń organizację
settings.delete_account=Usuń tą organizację settings.delete_account=Usuń tą organizację
settings.confirm_delete_account=Potwierdź usunięcie settings.confirm_delete_account=Potwierdź usunięcie
settings.delete_org_title=Usuń organizację
settings.hooks_desc=Dodaj webhooki, uruchamiane dla <strong>wszystkich repozytoriów</strong> w tej organizacji. settings.hooks_desc=Dodaj webhooki, uruchamiane dla <strong>wszystkich repozytoriów</strong> w tej organizacji.
members.membership_visibility=Widoczność członkostwa: members.membership_visibility=Widoczność członkostwa:
members.public=Widoczny
members.private=Ukryty
members.member_role=Rola: members.member_role=Rola:
members.owner=Właściciel members.owner=Właściciel
members.member=Członek members.member=Członek
@ -668,15 +803,19 @@ teams.no_desc=Ten zespół nie ma opisu
teams.settings=Ustawienia teams.settings=Ustawienia
teams.members=Członkowie zespołu teams.members=Członkowie zespołu
teams.update_settings=Aktualizuj ustawienia teams.update_settings=Aktualizuj ustawienia
teams.delete_team=Usuń zespół
teams.add_team_member=Dodaj członka zespołu teams.add_team_member=Dodaj członka zespołu
teams.delete_team_title=Usuń zespół
teams.delete_team_success=Zespół został usunięty. teams.delete_team_success=Zespół został usunięty.
teams.repositories=Repozytoria zespołu teams.repositories=Repozytoria zespołu
teams.search_repo_placeholder=Szukaj repozytorium…
teams.add_team_repository=Dodaj repozytorium zespołu teams.add_team_repository=Dodaj repozytorium zespołu
teams.remove_repo=Usuń teams.remove_repo=Usuń
teams.add_nonexistent_repo=Repozytorium, które próbujesz dodać, nie istnieje. Proszę je najpierw utworzyć. teams.add_nonexistent_repo=Repozytorium, które próbujesz dodać, nie istnieje. Proszę je najpierw utworzyć.
[admin] [admin]
dashboard=Pulpit dashboard=Pulpit
users=Konta użytkownika
organizations=Organizacje organizations=Organizacje
repositories=Repozytoria repositories=Repozytoria
config=Konfiguracja config=Konfiguracja
@ -686,13 +825,13 @@ first_page=Pierwsza
last_page=Ostatnia last_page=Ostatnia
total=Ogółem: %d total=Ogółem: %d
dashboard.statistic=Podsumowanie
dashboard.system_status=Status strony
dashboard.operation_name=Nazwa operacji dashboard.operation_name=Nazwa operacji
dashboard.operation_switch=Przełącz dashboard.operation_switch=Przełącz
dashboard.operation_run=Uruchom dashboard.operation_run=Uruchom
dashboard.clean_unbind_oauth=Usuń wychodzące połączenia OAuth dashboard.clean_unbind_oauth=Usuń wychodzące połączenia OAuth
dashboard.clean_unbind_oauth_success=Wszystkie połączenia wychodzące OAuth zostały usunięte. dashboard.clean_unbind_oauth_success=Wszystkie połączenia wychodzące OAuth zostały usunięte.
dashboard.delete_inactivate_accounts=Usuń wszystkie nieaktywne konta
dashboard.delete_inactivate_accounts_success=Wszystkie nieaktywne konta zostały usunięte.
dashboard.reinit_missing_repos=Ponownie zainicjalizuj wszystkie brakujące repozytoria Git, dla których istnieją rekordy dashboard.reinit_missing_repos=Ponownie zainicjalizuj wszystkie brakujące repozytoria Git, dla których istnieją rekordy
dashboard.reinit_missing_repos_success=Wszystkie brakujące repozytoria Git, dla których istnieją rekordy, zostały zainicjalizowane. dashboard.reinit_missing_repos_success=Wszystkie brakujące repozytoria Git, dla których istnieją rekordy, zostały zainicjalizowane.
dashboard.sync_external_users=Synchronizuj zewnętrzne dane użytkownika dashboard.sync_external_users=Synchronizuj zewnętrzne dane użytkownika
@ -724,6 +863,7 @@ dashboard.total_gc_pause=Sumaryczny czas wstrzymania przez GC
dashboard.last_gc_pause=Ostatnie wstrzymanie przez GC dashboard.last_gc_pause=Ostatnie wstrzymanie przez GC
dashboard.gc_times=Ilość wywołań GC dashboard.gc_times=Ilość wywołań GC
users.name=Nazwa użytkownika
users.activated=Aktywowany users.activated=Aktywowany
users.admin=Administrator users.admin=Administrator
users.repos=Repozytoria users.repos=Repozytoria
@ -731,11 +871,14 @@ users.created=Utworzony
users.edit=Edytuj users.edit=Edytuj
users.auth_source=Źródło uwierzytelniania users.auth_source=Źródło uwierzytelniania
users.local=Lokalny users.local=Lokalny
users.update_profile=Zaktualizuj konto użytkownika
users.delete_account=Usuń konto użytkownika
orgs.org_manage_panel=Zarządzanie organizacją orgs.org_manage_panel=Zarządzanie organizacją
orgs.name=Nazwa orgs.name=Nazwa
orgs.teams=Zespoły orgs.teams=Zespoły
orgs.members=Członkowie orgs.members=Członkowie
orgs.new_orga=Nowa organizacja
repos.repo_manage_panel=Zarządzanie repozytoriami repos.repo_manage_panel=Zarządzanie repozytoriami
repos.owner=Właściciel repos.owner=Właściciel
@ -760,6 +903,7 @@ auths.bind_dn=DN powiązania
auths.bind_password=Hasło Bind auths.bind_password=Hasło Bind
auths.user_base=Baza wyszukiwania auths.user_base=Baza wyszukiwania
auths.user_dn=DN użytkownika auths.user_dn=DN użytkownika
auths.search_page_size=Rozmiar strony
auths.filter=Filtr użytkownika auths.filter=Filtr użytkownika
auths.admin_filter=Filtr administratora auths.admin_filter=Filtr administratora
auths.ms_ad_sa=Atrybuty wyszukiwania MS AD auths.ms_ad_sa=Atrybuty wyszukiwania MS AD
@ -791,6 +935,8 @@ auths.new_success=Uwierzytelnienie '%s' zostało dodane.
auths.delete_auth_title=Usuń źródło uwierzytelniania auths.delete_auth_title=Usuń źródło uwierzytelniania
config.server_config=Konfiguracja serwera config.server_config=Konfiguracja serwera
config.app_name=Tytuł strony
config.app_ver=Wersja Gitea
config.custom_conf=Ścieżka do pliku konfiguracyjnego config.custom_conf=Ścieżka do pliku konfiguracyjnego
config.disable_router_log=Wyłącz dziennik routera config.disable_router_log=Wyłącz dziennik routera
config.run_mode=Tryb uruchamienia config.run_mode=Tryb uruchamienia
@ -798,11 +944,13 @@ config.git_version=Wersja Git
config.repo_root_path=Ścieżka główna repozytoriów config.repo_root_path=Ścieżka główna repozytoriów
config.lfs_root_path=Ścieżka główna katalogu LFS config.lfs_root_path=Ścieżka główna katalogu LFS
config.static_file_root_path=Ścieżka główna plików statycznych config.static_file_root_path=Ścieżka główna plików statycznych
config.log_file_root_path=Ścieżka dla logów
config.script_type=Typ skryptu config.script_type=Typ skryptu
config.reverse_auth_user=Użytkownik odwrotnego proxy config.reverse_auth_user=Użytkownik odwrotnego proxy
config.ssh_config=Konfiguracja SSH config.ssh_config=Konfiguracja SSH
config.ssh_enabled=Włączone config.ssh_enabled=Włączone
config.ssh_domain=Domena serwera
config.ssh_port=Port config.ssh_port=Port
config.ssh_listen_port=Port nasłuchiwania config.ssh_listen_port=Port nasłuchiwania
config.ssh_root_path=Ścieżka do katalogu głównego config.ssh_root_path=Ścieżka do katalogu głównego
@ -815,11 +963,13 @@ config.db_config=Konfiguracja bazy danych
config.db_type=Typ config.db_type=Typ
config.db_host=Serwer config.db_host=Serwer
config.db_name=Nazwa config.db_name=Nazwa
config.db_ssl_mode=SSL
config.db_path=Ścieżka config.db_path=Ścieżka
config.service_config=Konfiguracja usługi config.service_config=Konfiguracja usługi
config.show_registration_button=Pokazuj przycisk rejestracji config.show_registration_button=Pokazuj przycisk rejestracji
config.disable_key_size_check=Wyłącz sprawdzanie minimalnego rozmiaru klucza config.disable_key_size_check=Wyłącz sprawdzanie minimalnego rozmiaru klucza
config.enable_captcha=Włącz CAPTCHA
config.active_code_lives=Ważność kodów aktywacyjnych config.active_code_lives=Ważność kodów aktywacyjnych
config.reset_password_code_lives=Czas wygaśnięcia kodu resetowania hasła config.reset_password_code_lives=Czas wygaśnięcia kodu resetowania hasła

View File

@ -75,7 +75,7 @@ cancel=Cancelar
[install] [install]
install=Instalação install=Instalação
title=Configuração inicial title=Configuração inicial
docker_helper=Se você está rodando o Gitea dentro do Docker, por favor leia a <a target="_blank" rel="noopener" href="%s">documentação</a> cuidadosamente antes de alterar qualquer coisa nesta página. docker_helper=Se você está rodando o Gitea dentro do Docker, por favor leia a <a target="_blank" rel="noopener noreferrer" href="%s">documentação</a> cuidadosamente antes de alterar qualquer coisa nesta página.
requite_db_desc=Gitea requer MySQL, PostgreSQL, MSSQL, SQLite3 ou TiDB. requite_db_desc=Gitea requer MySQL, PostgreSQL, MSSQL, SQLite3 ou TiDB.
db_title=Configurações de banco de dados db_title=Configurações de banco de dados
db_type=Tipo de banco de dados db_type=Tipo de banco de dados
@ -492,13 +492,13 @@ owner=Proprietário
repo_name=Nome do repositório repo_name=Nome do repositório
repo_name_helper=Um bom nome de repositório é composto por palavras curtas, memorizáveis e únicas. repo_name_helper=Um bom nome de repositório é composto por palavras curtas, memorizáveis e únicas.
visibility=Visibilidade visibility=Visibilidade
visiblity_helper=Tornar este repositório privado visibility_helper=Tornar este repositório privado
visiblity_helper_forced=O administrador do site força novos repositórios a serem privados. visibility_helper_forced=O administrador do site força novos repositórios a serem privados.
visiblity_fork_helper=(Esta alteração irá afetar todos os forks.) visibility_fork_helper=(Esta alteração irá afetar todos os forks.)
clone_helper=Precisa de ajuda com o clone? Visite a <a target="_blank" rel="noopener" href="%s">Ajuda</a>. clone_helper=Precisa de ajuda com o clone? Visite a <a target="_blank" rel="noopener noreferrer" href="%s">Ajuda</a>.
fork_repo=Fork do repositório fork_repo=Fork do repositório
fork_from=Fork de fork_from=Fork de
fork_visiblity_helper=A visibilidade do fork de um repositório não pode ser alterada. fork_visibility_helper=A visibilidade do fork de um repositório não pode ser alterada.
repo_desc=Descrição repo_desc=Descrição
repo_lang=Linguagem repo_lang=Linguagem
repo_gitignore_helper=Selecione modelos do .gitignore. repo_gitignore_helper=Selecione modelos do .gitignore.
@ -613,7 +613,7 @@ editor.directory_is_a_file=O nome do diretório '%s' já é usado como um nome d
editor.file_is_a_symlink='%s' é um link simbólico. Links simbólicos não podem ser editados no editor da web editor.file_is_a_symlink='%s' é um link simbólico. Links simbólicos não podem ser editados no editor da web
editor.filename_is_a_directory=O nome do arquivo '%s' já é usado como um nome de diretório neste repositório. editor.filename_is_a_directory=O nome do arquivo '%s' já é usado como um nome de diretório neste repositório.
editor.file_editing_no_longer_exists=O arquivo que está sendo editado, '%s', não existe mais neste repositório. editor.file_editing_no_longer_exists=O arquivo que está sendo editado, '%s', não existe mais neste repositório.
editor.file_changed_while_editing=O conteúdo do arquivo mudou desde que você começou a editar. <a target="_blank" rel="noopener" href="%s">Clique aqui</a> para ver o que foi editado ou <strong>clique em Commit novamemente</strong> para sobreescrever essas mudanças. editor.file_changed_while_editing=O conteúdo do arquivo mudou desde que você começou a editar. <a target="_blank" rel="noopener noreferrer" href="%s">Clique aqui</a> para ver o que foi editado ou <strong>clique em Commit novamemente</strong> para sobreescrever essas mudanças.
editor.file_already_exists=Um arquivo com nome '%s' já existe neste repositório. editor.file_already_exists=Um arquivo com nome '%s' já existe neste repositório.
editor.no_changes_to_show=Nenhuma alteração a mostrar. editor.no_changes_to_show=Nenhuma alteração a mostrar.
editor.fail_to_update_file=Houve erro ao criar ou atualizar arquivo '%s': %v editor.fail_to_update_file=Houve erro ao criar ou atualizar arquivo '%s': %v
@ -994,7 +994,7 @@ settings.search_user_placeholder=Pesquisar usuário...
settings.org_not_allowed_to_be_collaborator=Organizações não podem ser adicionadas como um colaborador. settings.org_not_allowed_to_be_collaborator=Organizações não podem ser adicionadas como um colaborador.
settings.user_is_org_member=O usuário é um membro da organização e não pode ser adicionado como um colaborador. settings.user_is_org_member=O usuário é um membro da organização e não pode ser adicionado como um colaborador.
settings.add_webhook=Adicionar webhook settings.add_webhook=Adicionar webhook
settings.hooks_desc=Webhooks automaticamente fazem requisições de HTTP POST para um servidor quando acionados determinados eventos de Gitea. Leia mais no <a target="_blank" rel="noopener" href="%s">guia de webhooks</a>. settings.hooks_desc=Webhooks automaticamente fazem requisições de HTTP POST para um servidor quando acionados determinados eventos de Gitea. Leia mais no <a target="_blank" rel="noopener noreferrer" href="%s">guia de webhooks</a>.
settings.webhook_deletion=Remover webhook settings.webhook_deletion=Remover webhook
settings.webhook_deletion_desc=A exclusão de um webhook exclui suas configurações e o histórico de entrega. Continuar? settings.webhook_deletion_desc=A exclusão de um webhook exclui suas configurações e o histórico de entrega. Continuar?
settings.webhook_deletion_success=O webhook foi removido. settings.webhook_deletion_success=O webhook foi removido.
@ -1011,7 +1011,7 @@ settings.githook_edit_desc=Se o hook não estiver ativo, o conteúdo de exemplo
settings.githook_name=Nome do Hook settings.githook_name=Nome do Hook
settings.githook_content=Conteúdo do Hook settings.githook_content=Conteúdo do Hook
settings.update_githook=Atualizar Hook settings.update_githook=Atualizar Hook
settings.add_webhook_desc=Gitea enviará requisições <code>POST</code> com um tipo de conteúdo especificado para a URL de destino. Leia mais no <a target="_blank" rel="noopener" href="%s">guia de webhooks</a>. settings.add_webhook_desc=Gitea enviará requisições <code>POST</code> com um tipo de conteúdo especificado para a URL de destino. Leia mais no <a target="_blank" rel="noopener noreferrer" href="%s">guia de webhooks</a>.
settings.payload_url=URL de destino settings.payload_url=URL de destino
settings.content_type=Tipo de conteúdo POST settings.content_type=Tipo de conteúdo POST
settings.secret=Senha settings.secret=Senha
@ -1273,8 +1273,8 @@ dashboard.operation_switch=Trocar
dashboard.operation_run=Executar dashboard.operation_run=Executar
dashboard.clean_unbind_oauth=Limpar conexões OAuth não vinculadas dashboard.clean_unbind_oauth=Limpar conexões OAuth não vinculadas
dashboard.clean_unbind_oauth_success=Todas as conexões de OAuth não vinculadas foram excluídas. dashboard.clean_unbind_oauth_success=Todas as conexões de OAuth não vinculadas foram excluídas.
dashboard.delete_inactivate_accounts=Excluir todas as contas inativas dashboard.delete_inactivate_accounts=Excluir todas as contas não ativadas
dashboard.delete_inactivate_accounts_success=Todas as contas inativas foram excluídas. dashboard.delete_inactivate_accounts_success=Todas as contas não ativadas foram excluídas.
dashboard.delete_repo_archives=Excluir todos os arquivos do repositório dashboard.delete_repo_archives=Excluir todos os arquivos do repositório
dashboard.delete_repo_archives_success=Todos os arquivos do repositório foram excluídos. dashboard.delete_repo_archives_success=Todos os arquivos do repositório foram excluídos.
dashboard.delete_missing_repos=Excluir todos os repositórios que não possuem seus arquivos Git dashboard.delete_missing_repos=Excluir todos os repositórios que não possuem seus arquivos Git

View File

@ -75,7 +75,7 @@ cancel=Отмена
[install] [install]
install=Установка install=Установка
title=Начальная конфигурация title=Начальная конфигурация
docker_helper=Если вы запускаете Gitea внутри Docker, пожалуйста внимательно прочтите <a target="_blank" rel="noopener" href="%s">документацию</a> перед тем, как что-либо изменить на этой странице. docker_helper=Если вы запускаете Gitea внутри Docker, пожалуйста внимательно прочтите <a target="_blank" rel="noopener noreferrer" href="%s">документацию</a> перед тем, как изменить любые настройки.
requite_db_desc=Gitea требует MySQL, PostgreSQL, MSSQL, SQLite3 или TiDB. requite_db_desc=Gitea требует MySQL, PostgreSQL, MSSQL, SQLite3 или TiDB.
db_title=Настройки базы данных db_title=Настройки базы данных
db_type=Тип базы данных db_type=Тип базы данных
@ -492,13 +492,9 @@ owner=Владелец
repo_name=Имя репозитория repo_name=Имя репозитория
repo_name_helper=Лучшие названия репозиториев состоят из коротких, легко запоминаемых и уникальных ключевых слов. repo_name_helper=Лучшие названия репозиториев состоят из коротких, легко запоминаемых и уникальных ключевых слов.
visibility=Видимость visibility=Видимость
visiblity_helper=Сделать репозиторий приватным clone_helper=Нужна помощь в клонировании? Посетите страницу <a target="_blank" rel="noopener noreferrer" href="%s">помощи</a>.
visiblity_helper_forced=Администратор сайта настроил параметр видимости новых репозиториев. Репозиторий приватный по умолчанию.
visiblity_fork_helper=(Изменение этого повлияет на все форки.)
clone_helper=Нужна помощь в клонировании? Посетите страницу <a target="_blank" rel="noopener" href="%s">справки</a>.
fork_repo=Форкнуть репозиторий fork_repo=Форкнуть репозиторий
fork_from=Форк от fork_from=Форк от
fork_visiblity_helper=Видимость форкнутого репозитория изменить нельзя.
repo_desc=Описание repo_desc=Описание
repo_lang=Язык repo_lang=Язык
repo_gitignore_helper=Выберите шаблон .gitignore. repo_gitignore_helper=Выберите шаблон .gitignore.
@ -613,7 +609,7 @@ editor.directory_is_a_file=Имя каталога '%s' уже использу
editor.file_is_a_symlink='%s' является символической ссылкой. Символические ссылки нельзя редактировать в веб-редакторе editor.file_is_a_symlink='%s' является символической ссылкой. Символические ссылки нельзя редактировать в веб-редакторе
editor.filename_is_a_directory=Имя файла '%s' уже используется в качестве имени каталога в этом репозитории. editor.filename_is_a_directory=Имя файла '%s' уже используется в качестве имени каталога в этом репозитории.
editor.file_editing_no_longer_exists=Редактируемый файл '%s' больше не существует в этом репозитории. editor.file_editing_no_longer_exists=Редактируемый файл '%s' больше не существует в этом репозитории.
editor.file_changed_while_editing=Содержимое файла изменилось с момента начала редактирования. <a target="_blank" rel="noopener" href="%s">Нажмите здесь</a>, чтобы увидеть, что было изменено, или <strong>Зафиксировать изменения снова</strong>, чтобы заменить их. editor.file_changed_while_editing=Содержимое файла изменилось с момента начала редактирования. <a target="_blank" rel="noopener noreferrer" href="%s">Нажмите здесь</a>, чтобы увидеть, что было изменено, или <strong>Зафиксировать изменения снова</strong>, чтобы заменить их.
editor.file_already_exists=Файл с именем '%s' уже существует в репозитории. editor.file_already_exists=Файл с именем '%s' уже существует в репозитории.
editor.no_changes_to_show=Нет изменений. editor.no_changes_to_show=Нет изменений.
editor.fail_to_update_file=Не удалось обновить/создать файл «%s» из-за ошибки: %v editor.fail_to_update_file=Не удалось обновить/создать файл «%s» из-за ошибки: %v
@ -994,7 +990,7 @@ settings.search_user_placeholder=Поиск пользователя…
settings.org_not_allowed_to_be_collaborator=Организации не могут быть добавлены как соавторы. settings.org_not_allowed_to_be_collaborator=Организации не могут быть добавлены как соавторы.
settings.user_is_org_member=Пользователь является членом организации, члены которой не могут быть добавлены в качестве соавтора. settings.user_is_org_member=Пользователь является членом организации, члены которой не могут быть добавлены в качестве соавтора.
settings.add_webhook=Добавить Webhook settings.add_webhook=Добавить Webhook
settings.hooks_desc=Webhooks позволяют внешним службам получать уведомления при возникновении определенных событий на Gitea. При возникновении указанных событий мы отправим запрос POST на каждый заданный вами URL. Узнать больше можно в нашем <a target="_blank" rel="noopener" href="%s">руководстве по webhooks</a>. settings.hooks_desc=Webhooks автоматически создает запросы HTTP POST на сервер, при возникновении определенных событий на Gitea. Подробнее читайте в <a target="_blank" rel="noopener noreferrer" href="%s">руководство по webhooks</a>.
settings.webhook_deletion=Удалить Webhook settings.webhook_deletion=Удалить Webhook
settings.webhook_deletion_desc=Удаление этого веб-хука приведет к удалению всей связанной с ним информации, включая историю. Хотите продолжить? settings.webhook_deletion_desc=Удаление этого веб-хука приведет к удалению всей связанной с ним информации, включая историю. Хотите продолжить?
settings.webhook_deletion_success=Webhook был удалён. settings.webhook_deletion_success=Webhook был удалён.
@ -1011,7 +1007,7 @@ settings.githook_edit_desc=Если хук не активен, будет по
settings.githook_name=Название Hook'a settings.githook_name=Название Hook'a
settings.githook_content=Перехватить содержание settings.githook_content=Перехватить содержание
settings.update_githook=Обновить Hook settings.update_githook=Обновить Hook
settings.add_webhook_desc=Gitea будет оправлять <code>POST</code> запросы на указанный URL адрес, с информацией о происходящих событиях. Вы также можете указать формат данных (JSON, x-www-form-urlencoded, XML и т.д.). Подробности на странице <a target="_blank" rel="noopener" href="%s">инструкции по использованию webhooks</a>. settings.add_webhook_desc=Gitea будет оправлять <code>POST</code> запросы на указанный URL адрес, с информацией о происходящих событиях. Подробности на странице <a target="_blank" rel="noopener noreferrer" href="%s">инструкции по использованию webhooks</a>.
settings.payload_url=URL обработчика settings.payload_url=URL обработчика
settings.content_type=Тип содержимого settings.content_type=Тип содержимого
settings.secret=Секретный ключ settings.secret=Секретный ключ
@ -1274,7 +1270,7 @@ dashboard.operation_run=Запуск
dashboard.clean_unbind_oauth=Очистить список незавершённых авторизаций OAuth dashboard.clean_unbind_oauth=Очистить список незавершённых авторизаций OAuth
dashboard.clean_unbind_oauth_success=Все незавершённые связи OAuth были удалены. dashboard.clean_unbind_oauth_success=Все незавершённые связи OAuth были удалены.
dashboard.delete_inactivate_accounts=Удалить все неактивированные учетные записи dashboard.delete_inactivate_accounts=Удалить все неактивированные учетные записи
dashboard.delete_inactivate_accounts_success=Все неактивные учётные записи удалены. dashboard.delete_inactivate_accounts_success=Все не активированные учетные записи были удалены.
dashboard.delete_repo_archives=Удаление всех архивов репозиториев dashboard.delete_repo_archives=Удаление всех архивов репозиториев
dashboard.delete_repo_archives_success=Все архивы репозиториев удалены. dashboard.delete_repo_archives_success=Все архивы репозиториев удалены.
dashboard.delete_missing_repos=Удалить все записи о репозиториях с отсутствующими файлами Git dashboard.delete_missing_repos=Удалить все записи о репозиториях с отсутствующими файлами Git

View File

@ -506,7 +506,6 @@ total=Укупно: %d
dashboard.operation_name=Име операције dashboard.operation_name=Име операције
dashboard.operation_switch=Пребаци dashboard.operation_switch=Пребаци
dashboard.operation_run=Покрени dashboard.operation_run=Покрени
dashboard.delete_inactivate_accounts=Уклони све неактивне налоге
dashboard.server_uptime=Време непрекидног рада сервера dashboard.server_uptime=Време непрекидног рада сервера
dashboard.current_goroutine=Тренутнe Goroutine dashboard.current_goroutine=Тренутнe Goroutine
dashboard.current_memory_usage=Тренутна употреба меморије dashboard.current_memory_usage=Тренутна употреба меморије

View File

@ -1,11 +1,15 @@
app_desc=En smidig, självhostad Git-tjänst
home=Startsida home=Startsida
dashboard=Instrumentpanel dashboard=Instrumentpanel
explore=Utforska explore=Utforska
help=Hjälp help=Hjälp
sign_in=Logga in sign_in=Logga in
sign_in_with=Logga in med
sign_out=Logga ut sign_out=Logga ut
sign_up=Registrera
link_account=Länka konto link_account=Länka konto
link_account_signin_or_signup=Logga in med befintliga inloggningsuppgifter för att länka samman det kontot till detta kontot. Eller registrera ett nytt.
register=Registrera dig register=Registrera dig
website=Webbplats website=Webbplats
version=Version version=Version
@ -13,12 +17,32 @@ page=Sida
template=Mall template=Mall
language=Språk language=Språk
notifications=Notiser notifications=Notiser
create_new=Skapa…
user_profile_and_more=Profil och Inställningar…
signed_in_as=Inloggad som signed_in_as=Inloggad som
enable_javascript=Denna sida fungerar bättre med Javascript igång.
username=Användarnamn username=Användarnamn
email=E-postadress
password=Lösenord password=Lösenord
re_type=Upprepa lösenordet
captcha=CAPTCHA
twofa=Tvåfaktorsautentisering
twofa_scratch=Tvåfaktorsskrapkod
passcode=Kod passcode=Kod
u2f_insert_key=Sätt i din säkerhetsnyckel
u2f_sign_in=Tryck på knappen på din säkerhetsnyckel. Om du inte kan hitta en knapp, dra ur och sätt i nyckeln igen.
u2f_press_button=Vänligen tryck på knappen på din säkerhetsnyckel…
u2f_use_twofa=Använd en tvåfaktorskod från din telefon
u2f_error=Vi kan inte läsa din säkerhetsnyckel!
u2f_unsupported_browser=Din webbläsare stödjer inte U2F-nycklar. Vänligen prova en annan webbläsare.
u2f_error_1=Ett okänt fel uppstod. Vänligen försök igen.
u2f_error_2=Kontrollera att du använder en krypterad anslutning (https://) och besöker korrekt länk.
u2f_error_3=Servern kunde inte hantera din förfrågan.
u2f_error_4=Den givna nyckeln är inte behörig för denna förfrågan. Om du försöker registrera den, se till att den inte redan är registrerad.
u2f_error_5=Timeout uppnådd innan nyckeln kunde bli läst. Vänligen ladda om sidan och för att försök igen.
u2f_reload=Ladda om
repository=Utvecklingskatalog repository=Utvecklingskatalog
organization=Organisation organization=Organisation
@ -29,8 +53,12 @@ new_mirror=Ny Spegling
new_fork=Ny förgrening av utvecklingskatalog new_fork=Ny förgrening av utvecklingskatalog
new_org=Ny organisation new_org=Ny organisation
manage_org=Hantera organisationer manage_org=Hantera organisationer
admin_panel=Sidadministration
account_settings=Kontoinställningar account_settings=Kontoinställningar
settings=inställningar settings=inställningar
your_profile=Profil
your_starred=Stjärnmärkt
your_settings=Inställningar
all=Alla all=Alla
sources=Källor sources=Källor
@ -46,14 +74,36 @@ cancel=Avbryt
[install] [install]
install=Installation install=Installation
title=Ursprunglig konfiguration
requite_db_desc=Gitea behöver MySQL, PostgreSQL, MSSQL, SQLite3 eller TiDB.
db_title=Databasinställningar db_title=Databasinställningar
db_type=Databastyp db_type=Databastyp
host=Server host=Server
user=Användarnamn
password=Lösenord password=Lösenord
db_name=Databasens namn db_name=Databasens namn
db_helper=Notis för MySQL-användare: Använd InnoDB-lagringsmotorn och teckenuppsättning 'utf8_general_ci'.
ssl_mode=SSL
path=Filväg path=Filväg
sqlite_helper=Sökväg för SQLite3 eller TiDB databasen.<br>Ange en absolut sökväg om du kör Gitea som en systemtjänst.
err_empty_db_path=Sökvägen till SQLite3- eller TiDB-databasen kan inte vara tom.
err_invalid_tidb_name=TiDB-databases namn får inte innehålla '.'- eller '-'-tecken.
no_admin_and_disable_registration=Du kan inte inaktivera självregistrering utan att skapa ett administratörskonto.
err_empty_admin_password=Administratörslösenordet kan inte vara tomt.
general_title=Allmänna inställningar
app_name=Sajtens namn
app_name_helper=Du kan ange ditt företagsnamn här.
repo_path=Rotsökväg för utvecklingskatalog repo_path=Rotsökväg för utvecklingskatalog
repo_path_helper=Fjärrutvecklingskataloger kommer att sparas i denna katalog.
lfs_path=LFS Rotsökväg
lfs_path_helper=Filer hanterade av Git LFS kommer att sparas i denna mapp. Lämna tom för att avaktivera.
run_user=Kör som användarnamn
run_user_helper=Ange operativsystemets användarnamn som Gitea ska köras under. Denna användare måste ha tillgång till utvecklingskatalogens rotsökväg.
domain=SSH-Serverdomän
domain_helper=Domän- eller hostadress för SSH-kloningslänkar.
ssh_port=SSH-serverport
ssh_port_helper=Portnumret som din SSH-server lyssnar på. Lämna tom för att inaktivera.
log_root_path=Loggsökväg log_root_path=Loggsökväg
optional_title=Övriga inställningar optional_title=Övriga inställningar
@ -65,15 +115,32 @@ admin_password=Lösenord
confirm_password=Bekräfta lösenord confirm_password=Bekräfta lösenord
install_btn_confirm=Installera Gitea install_btn_confirm=Installera Gitea
test_git_failed=Misslyckades att testa 'git' kommando: %v test_git_failed=Misslyckades att testa 'git' kommando: %v
invalid_repo_path=Utvecklingskatalogens rotsökväg är ogiltig: %v
run_user_not_match=Systemtjänstanvändaren är inte den nuvarande användaren: %s -> %s
save_config_failed=Misslyckades att spara konfigurationen: %v save_config_failed=Misslyckades att spara konfigurationen: %v
invalid_admin_setting=Inställning för administartörskontot är ogiltig: %v
install_success=Välkommen! Tack för att du valt Gitea. Ha det så roligt, väl mött!
invalid_log_root_path=Sökvägen för loggar är ogiltig: %v
default_keep_email_private=Dölj mailadresser som standard
default_keep_email_private_popup=Dölj mailadresser för nya användarkonton som standard.
default_allow_create_organization=Tillåt skapandet utav organisationer som standard
default_allow_create_organization_popup=Tillåt nya användarkonton att skapa organisationer som standard.
default_enable_timetracking=Aktivera tidredovisning som Standard
default_enable_timetracking_popup=Aktivera tidsredovisning för nya utvecklingskataloger som standard.
no_reply_address=Dold mejldomän
no_reply_address_helper=Domännamn för användare med en dold mailadress. Exempelvis kommer användarnamnet 'joe' att loggas i Git som 'joe@noreply.example.org' om dold maildomän är satt till 'noreply.example.org'.
[home] [home]
uname_holder=Användarnamn eller Mejladress
password_holder=Lösenord password_holder=Lösenord
switch_dashboard_context=Växla Visad Instrumentpanel switch_dashboard_context=Växla Visad Instrumentpanel
my_repos=Utvecklingskataloger
show_more_repos=Visa flera utvecklingskataloger…
collaborative_repos=Kollaborativa Utvecklingskataloger collaborative_repos=Kollaborativa Utvecklingskataloger
my_orgs=Mina organisationer my_orgs=Mina organisationer
my_mirrors=Mina speglar my_mirrors=Mina speglar
view_home=Visa %s view_home=Visa %s
search_repos=Hitta en utvecklingskatalog…
issues.in_your_repos=I dina utvecklingskataloger issues.in_your_repos=I dina utvecklingskataloger
@ -82,9 +149,19 @@ repos=Utvecklingskataloger
users=Användare users=Användare
organizations=Organisationer organizations=Organisationer
search=Sök search=Sök
code=Kod
repo_no_results=Inga matchande utvecklingskataloger hittades.
user_no_results=Inga matchande användare hittades.
org_no_results=Inga matchande organisationer hittades.
code_no_results=Ingen källkod hittades som matchar din sökterm.
code_search_results=Söktresultat för '%s'
[auth] [auth]
create_new_account=Registrera Konto
register_helper_msg=Har du redan ett konto? Logga in nu! register_helper_msg=Har du redan ett konto? Logga in nu!
social_register_helper_msg=Har du redan ett konto? Länka det nu!
disable_register_prompt=Registrering inaktiverad. Vänligen kontakta din sidadministratör.
disable_register_mail=Bekräftelsemejl vid registrering är inaktiverad.
remember_me=Kom ihåg mig remember_me=Kom ihåg mig
forgot_password_title=Glömt lösenord forgot_password_title=Glömt lösenord
forgot_password=Glömt lösenord? forgot_password=Glömt lösenord?
@ -102,6 +179,7 @@ scratch_code=Skrapkod
use_scratch_code=Använd en skrapkod use_scratch_code=Använd en skrapkod
twofa_scratch_used=Du har använt din skrapkod. Du har blivit omdirigerad till tvåfaktorsinställningarna så att du kan ta bort din aktiverade enhet eller generera en ny skrapkod. twofa_scratch_used=Du har använt din skrapkod. Du har blivit omdirigerad till tvåfaktorsinställningarna så att du kan ta bort din aktiverade enhet eller generera en ny skrapkod.
twofa_scratch_token_incorrect=Din skrapkod är ogiltlig. twofa_scratch_token_incorrect=Din skrapkod är ogiltlig.
login_userpass=Logga in
login_openid=OpenID login_openid=OpenID
openid_connect_submit=Anslut openid_connect_submit=Anslut
openid_connect_title=Anslut ett existerande konto openid_connect_title=Anslut ett existerande konto
@ -146,6 +224,7 @@ url_error=Den givna URL-adressen är inte valid
include_error=` måste innehålla texten '%s'.` include_error=` måste innehålla texten '%s'.`
unknown_error=Okänt fel: unknown_error=Okänt fel:
repo_name_been_taken=Namnet för utvecklingskatalogen är upptaget.
user_not_exist=Användaren finns inte. user_not_exist=Användaren finns inte.
auth_failed=Autentisering misslyckades: %v auth_failed=Autentisering misslyckades: %v
@ -154,26 +233,34 @@ auth_failed=Autentisering misslyckades: %v
target_branch_not_exist=Målgrenen finns inte. target_branch_not_exist=Målgrenen finns inte.
[user] [user]
change_avatar=Byt din avatar…
join_on=Gick med join_on=Gick med
repositories=Utvecklingskataloger repositories=Utvecklingskataloger
activity=Offentlig Aktivitet activity=Offentlig Aktivitet
followers=Följare followers=Följare
starred=Stjärnmärkta Utvecklingskataloger
following=Följer following=Följer
follow=Följ follow=Följ
unfollow=Sluta följa unfollow=Sluta följa
form.name_reserved=Användarnamnet '%s' är reserverat. form.name_reserved=Användarnamnet '%s' är reserverat.
form.name_pattern_not_allowed=Mönstret '%s' är otillåtet i ett användarnamn.
[settings] [settings]
profile=Profil profile=Profil
account=Konto
password=Lösenord password=Lösenord
security=Säkerhet security=Säkerhet
avatar=Visningsbild avatar=Visningsbild
ssh_gpg_keys=SSH / GPG-nycklar ssh_gpg_keys=SSH / GPG-nycklar
social=Sociala konton social=Sociala konton
applications=Applikationer
orgs=Hantera Organisationer
repos=Utvecklingskataloger repos=Utvecklingskataloger
delete=Radera konto delete=Radera konto
twofa=Tvåfaktorsautentisering twofa=Tvåfaktorsautentisering
account_link=Länkade Konton
organization=Organisationer
uid=AnvändarID uid=AnvändarID
public_profile=Offentlig profil public_profile=Offentlig profil
@ -340,13 +427,18 @@ issues.new.no_milestone=Ingen Milsten
issues.new.clear_milestone=Rensa milstenar issues.new.clear_milestone=Rensa milstenar
issues.new.open_milestone=Öppna Milstenar issues.new.open_milestone=Öppna Milstenar
issues.new.closed_milestone=Stängda Milstenar issues.new.closed_milestone=Stängda Milstenar
issues.new.no_assignees=Ingen tilldelad
issues.no_ref=Ingen branch/Tag specificerad issues.no_ref=Ingen branch/Tag specificerad
issues.create=Skapa Ärende issues.create=Skapa Ärende
issues.new_label=Ny etikett issues.new_label=Ny etikett
issues.new_label_placeholder=Etikettsnamn
issues.new_label_desc_placeholder=Beskrivning
issues.create_label=Skapa Etikett issues.create_label=Skapa Etikett
issues.label_templates.title=Ladda en fördefinierad uppsättning etiketter issues.label_templates.title=Ladda en fördefinierad uppsättning etiketter
issues.label_templates.helper=Markera en uppsättning etiketter issues.label_templates.helper=Markera en uppsättning etiketter
issues.label_templates.fail_to_load_file=Laddning av etikettmallen '%s' misslyckades: %v issues.label_templates.fail_to_load_file=Laddning av etikettmallen '%s' misslyckades: %v
issues.add_label_at=lade till etiketten <div class="ui label" style="color: %s\; background-color: %s">%s</div> %s
issues.remove_label_at=tog bort etiketten <div class="ui label" style="color: %s\; background-color: %s">%s</div> %s
issues.add_milestone_at=`lade till denna till milstolpe <b>%s</b> %s` issues.add_milestone_at=`lade till denna till milstolpe <b>%s</b> %s`
issues.change_milestone_at='modifierade milstolpen från <b>%s</b> till <b>%s</b> %s' issues.change_milestone_at='modifierade milstolpen från <b>%s</b> till <b>%s</b> %s'
issues.remove_milestone_at='tog bort denna från milstolpen <b>%s</b> %s' issues.remove_milestone_at='tog bort denna från milstolpen <b>%s</b> %s'
@ -373,6 +465,10 @@ issues.filter_sort.recentupdate=Nyligen uppdaterade
issues.filter_sort.leastupdate=Äldst uppdaterad issues.filter_sort.leastupdate=Äldst uppdaterad
issues.filter_sort.mostcomment=Mest kommenterade issues.filter_sort.mostcomment=Mest kommenterade
issues.filter_sort.leastcomment=Minst kommenterade issues.filter_sort.leastcomment=Minst kommenterade
issues.filter_sort.moststars=Flest stjärnor
issues.filter_sort.feweststars=Minst stjärnor
issues.filter_sort.mostforks=Flest forks
issues.filter_sort.fewestforks=Minst forks
issues.action_open=Öppna issues.action_open=Öppna
issues.action_close=Stäng issues.action_close=Stäng
issues.action_label=Etikett issues.action_label=Etikett
@ -391,7 +487,9 @@ issues.commented_at=`kommenterad <a href="#%s">%s</a>`
issues.delete_comment_confirm=Är du säker på att du vill ta bort den här kommentaren? issues.delete_comment_confirm=Är du säker på att du vill ta bort den här kommentaren?
issues.no_content=Det finns inget innehåll än. issues.no_content=Det finns inget innehåll än.
issues.close_issue=Stäng issues.close_issue=Stäng
issues.close_comment_issue=Kommentera och stäng
issues.reopen_issue=Återöppna issues.reopen_issue=Återöppna
issues.reopen_comment_issue=Kommentera och återöppna
issues.create_comment=Kommentera issues.create_comment=Kommentera
issues.closed_at=`stängde <a id="%[1]s" href="#%[1]s">%[2]s</a>` issues.closed_at=`stängde <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.reopened_at=`återöppnade <a if="%[1]s" href="#%[1]s">%[2]s</a>` issues.reopened_at=`återöppnade <a if="%[1]s" href="#%[1]s">%[2]s</a>`
@ -404,11 +502,16 @@ issues.edit=Redigera
issues.cancel=Avbryt issues.cancel=Avbryt
issues.save=Spara issues.save=Spara
issues.label_title=Etikettsnamn issues.label_title=Etikettsnamn
issues.label_description=Etikettbeskrivning
issues.label_color=Etikettsfärg issues.label_color=Etikettsfärg
issues.label_count=%d etiketter issues.label_count=%d etiketter
issues.label_open_issues=%d öppna ärenden issues.label_open_issues=%d öppna ärenden
issues.label_edit=Redigera issues.label_edit=Redigera
issues.label_delete=Radera issues.label_delete=Radera
issues.label_modify=Redigera etikett
issues.label_deletion=Ta bort etikett
issues.label_deletion_desc=Bottagning av en etikett tar bort den från alla ärenden. Fortsätta?
issues.label_deletion_success=Etiketten har tagits bort.
issues.label.filter_sort.alphabetically=Alfabetiskt A-Ö issues.label.filter_sort.alphabetically=Alfabetiskt A-Ö
issues.label.filter_sort.reverse_alphabetically=Alfabetiskt Ö-A issues.label.filter_sort.reverse_alphabetically=Alfabetiskt Ö-A
issues.label.filter_sort.by_size=Storlek issues.label.filter_sort.by_size=Storlek
@ -418,10 +521,21 @@ issues.attachment.open_tab=`Klicka för att se "%s" i en ny flik`
issues.attachment.download=`Klicka för att hämta "%s"` issues.attachment.download=`Klicka för att hämta "%s"`
issues.subscribe=Prenumerera issues.subscribe=Prenumerera
issues.unsubscribe=Avsluta prenumerationen issues.unsubscribe=Avsluta prenumerationen
issues.tracker=Tidsredovisning
issues.start_tracking_short=Starta issues.start_tracking_short=Starta
issues.start_tracking=Starta tidsredovisning
issues.start_tracking_history=`började arbeta %s` issues.start_tracking_history=`började arbeta %s`
issues.tracking_already_started=`Du har redan påbörjat tidredovisning på detta <a href="%s"> ärende</a>!`
issues.stop_tracking=Stoppa
issues.stop_tracking_history=`slutade arbeta %s`
issues.add_time=Lägg till tid manuellt
issues.add_time_short=Lägg till tid
issues.add_time_cancel=Avbryt
issues.add_time_history=`la till tillbringad tid %s`
issues.add_time_hours=Timmar issues.add_time_hours=Timmar
issues.add_time_minutes=Minuter issues.add_time_minutes=Minuter
issues.cancel_tracking=Avfärda
issues.cancel_tracking_history=”avbröt tidredovisning %s'
pulls.new=Ny Pull-Förfrågan pulls.new=Ny Pull-Förfrågan
pulls.filter_branch=Filtrera gren pulls.filter_branch=Filtrera gren
@ -431,9 +545,12 @@ pulls.title_desc=vill sammanfoga %[1]d incheckningar från <code>s[2]s</code> in
pulls.merged_title_desc=sammanfogade %[1]d incheckningar från <code>%[2]s</code> in i <code>%[3]s</code> %[4]s pulls.merged_title_desc=sammanfogade %[1]d incheckningar från <code>%[2]s</code> in i <code>%[3]s</code> %[4]s
pulls.tab_conversation=Konversation pulls.tab_conversation=Konversation
pulls.tab_commits=Incheckningar pulls.tab_commits=Incheckningar
pulls.reopen_to_merge=Vänligen återöppna denna Pull-förfrågan igen för att utföra sammanfogningen.
pulls.merged=Sammanfogat pulls.merged=Sammanfogat
pulls.can_auto_merge_desc=Denna pull-förfrågan kan sammanfogas automatiskt. pulls.can_auto_merge_desc=Denna pull-förfrågan kan sammanfogas automatiskt.
pulls.merge_pull_request=Sammanfoga Pull-förfrågan pulls.merge_pull_request=Sammanfoga Pull-förfrågan
pulls.rebase_merge_pull_request=Rebase och sammanfogning
pulls.squash_merge_pull_request=Squasha och sammanfogning
milestones.new=Ny milstolpe milestones.new=Ny milstolpe
milestones.open_tab=%d Öppna milestones.open_tab=%d Öppna
@ -449,6 +566,11 @@ milestones.due_date=Förfallodatum (valfritt)
milestones.clear=Rensa milestones.clear=Rensa
milestones.edit=Redigera milstolpe milestones.edit=Redigera milstolpe
milestones.cancel=Avbryt milestones.cancel=Avbryt
milestones.modify=Uppdatera milstolpe
milestones.edit_success=Milstolpe '%s' har blivit uppdaterad.
milestones.deletion=Ta bort milstolpe
milestones.deletion_desc=Borttagning av en milstolpe tar bort den från samtliga relaterade ärende. Fortsätta?
milestones.deletion_success=Milstolpen har blivit borttagen.
milestones.filter_sort.closest_due_date=Närmaste förfallodatum milestones.filter_sort.closest_due_date=Närmaste förfallodatum
milestones.filter_sort.furthest_due_date=Mest avlägsna förfallodatum milestones.filter_sort.furthest_due_date=Mest avlägsna förfallodatum
milestones.filter_sort.least_complete=Minst klar milestones.filter_sort.least_complete=Minst klar
@ -456,28 +578,50 @@ milestones.filter_sort.most_complete=Mest klar
milestones.filter_sort.most_issues=Mest ärenden milestones.filter_sort.most_issues=Mest ärenden
milestones.filter_sort.least_issues=Minst ärenden milestones.filter_sort.least_issues=Minst ärenden
ext_wiki=Extern Wiki
ext_wiki.desc=Länk till extern wiki.
wiki=Wiki wiki=Wiki
wiki.welcome=Välkommen till Wikin.
wiki.welcome_desc=Wikin låter dig skriva och dela dokumentation med medarbetare.
wiki.desc=Skriv och dela dokumentation med medarbetare.
wiki.create_first_page=Skapa den första sidan
wiki.page=Sida wiki.page=Sida
wiki.filter_page=Filtrera sida wiki.filter_page=Filtrera sida
wiki.new_page=Sida
wiki.default_commit_message=Skriv en anteckning om den här uppdateringen (valfritt). wiki.default_commit_message=Skriv en anteckning om den här uppdateringen (valfritt).
wiki.save_page=Spara sidan wiki.save_page=Spara sidan
wiki.last_commit_info=%s redigerade denna sida %s wiki.last_commit_info=%s redigerade denna sida %s
wiki.edit_page_button=Redigera wiki.edit_page_button=Redigera
wiki.new_page_button=Ny Sida wiki.new_page_button=Ny Sida
wiki.delete_page_button=Tag bort sida wiki.delete_page_button=Tag bort sida
wiki.delete_page_notice_1=Borttagning utav wiki sidan '%s' kan inte ångras. Fortsätta?
wiki.page_already_exists=Wiki-sida med samma namn finns redan. wiki.page_already_exists=Wiki-sida med samma namn finns redan.
wiki.reserved_page=Namnet för wikisidan '%s' är reserverat.
wiki.pages=Sidor wiki.pages=Sidor
wiki.last_updated=Senast uppdaterad %s wiki.last_updated=Senast uppdaterad %s
activity=Aktiviteter
activity.period.filter_label=Period: activity.period.filter_label=Period:
activity.period.daily=1 dag activity.period.daily=1 dag
activity.period.halfweekly=3 dagar activity.period.halfweekly=3 dagar
activity.period.weekly=1 vecka activity.period.weekly=1 vecka
activity.period.monthly=1 månad activity.period.monthly=1 månad
activity.overview=Översikt activity.overview=Översikt
activity.active_prs_count_1=<strong>%d</strong> Aktiv Pull begäran
activity.active_prs_count_n=<strong>%d</strong> Aktiva Pull begärelser
activity.merged_prs_count_1=Sammanfogad Pull-förfrågan
activity.merged_prs_count_n=Sammanfogade Pull-förfrågningar
activity.opened_prs_count_1=Föreslagen Pull begäran
activity.opened_prs_count_n=Föreslagna Pull-begärelser
activity.title.user_1=%d användare activity.title.user_1=%d användare
activity.title.user_n=%d användare activity.title.user_n=%d användare
activity.title.prs_1=%d Pull-begäran
activity.title.prs_n=%d Pull begärelser
activity.title.prs_merged_by=%s sammanfogad av %s
activity.title.prs_opened_by=%s föreslås av %s
activity.merged_prs_label=Sammanfogad
activity.opened_prs_label=Föreslagen
activity.active_issues_count_1=<strong>%d</strong> Aktivt ärende activity.active_issues_count_1=<strong>%d</strong> Aktivt ärende
activity.active_issues_count_n=<strong>%d</strong> Aktiva ärenden activity.active_issues_count_n=<strong>%d</strong> Aktiva ärenden
activity.closed_issues_count_1=Stängt ärende activity.closed_issues_count_1=Stängt ärende
@ -488,9 +632,26 @@ activity.title.issues_closed_by=%s stängd av %s
activity.title.issues_created_by=%s skapad av %s activity.title.issues_created_by=%s skapad av %s
activity.closed_issue_label=Stängd activity.closed_issue_label=Stängd
activity.new_issues_count_1=Nytt ärende activity.new_issues_count_1=Nytt ärende
activity.new_issues_count_n=Nya ärenden
activity.new_issue_label=Öppnad
activity.title.unresolved_conv_1=%d Olöst konversation
activity.title.unresolved_conv_n=%d Olösta konversationer
activity.unresolved_conv_desc=De nyligen förändrade ärendena och pull-requesterna har inte blivit lösta ännu.
activity.unresolved_conv_label=Öppna
activity.title.releases_1=%d release
activity.title.releases_n=%d releaser
activity.title.releases_published_by=%s publicerad av %s
activity.published_release_label=Publicerad
search=Sök
search.search_repo=Sök utvecklingskatalog
search.results=Sökresultat för ”%s” i <a href="%s"> %s</a>
settings=Inställningar settings=Inställningar
settings.desc=Inställningarna är där du kan hantera inställningar för utvecklingskatalogen
settings.options=Utvecklingskatalog
settings.collaboration=Medarbetare
settings.collaboration.admin=Administratör
settings.collaboration.write=Skriva settings.collaboration.write=Skriva
settings.collaboration.read=Läsa settings.collaboration.read=Läsa
settings.collaboration.undefined=Odefinierad settings.collaboration.undefined=Odefinierad
@ -498,10 +659,23 @@ settings.hooks=Webbhookar
settings.githooks=Githookar settings.githooks=Githookar
settings.basic_settings=Basinställningar settings.basic_settings=Basinställningar
settings.mirror_settings=Inställningar för spegling settings.mirror_settings=Inställningar för spegling
settings.sync_mirror=Synkronisera nu
settings.mirror_sync_in_progress=Synkronisering utav speglingar pågår. Kontrollera igen om en minut.
settings.site=Webbplats
settings.update_settings=Uppdatera inställningar settings.update_settings=Uppdatera inställningar
settings.advanced_settings=Advancerade Inställningar settings.advanced_settings=Advancerade Inställningar
settings.wiki_desc=Aktivera wiki för utvecklingskatalog
settings.use_internal_wiki=Använd inbyggd Wiki
settings.use_external_wiki=Använd extern wiki
settings.external_wiki_url=Extern Wiki-URL settings.external_wiki_url=Extern Wiki-URL
settings.external_wiki_url_error=Den externa wiki-länken är inte giltig.
settings.external_wiki_url_desc=Besökare omdirigeras till den externa wiki-länken när de trycker på wiki-tabben.
settings.issues_desc=Aktivera ärendehantering för utvecklingskatalogen
settings.use_internal_issue_tracker=Använd inbyggt ärendehanteringssystem
settings.use_external_issue_tracker=Använd externt ärendehanteringssystem
settings.external_tracker_url=URL För Extern Ärendehanterare settings.external_tracker_url=URL För Extern Ärendehanterare
settings.external_tracker_url_error=Länken för ärendehanteringsystemet är inte en giltig länk.
settings.external_tracker_url_desc=Besökare dirigeras om till länken för det externa ärendehanteringssystemet när de trycker på ärende-tabben.
settings.tracker_url_format=URL-Format För Extern Ärendehanterare settings.tracker_url_format=URL-Format För Extern Ärendehanterare
settings.tracker_issue_style.numeric=Numerisk settings.tracker_issue_style.numeric=Numerisk
settings.tracker_issue_style.alphanumeric=Alfanumerisk settings.tracker_issue_style.alphanumeric=Alfanumerisk
@ -541,10 +715,18 @@ settings.deploy_keys=Driftsättningsnycklar
settings.add_deploy_key=Lägg till driftsättningsnyckel settings.add_deploy_key=Lägg till driftsättningsnyckel
settings.title=Titel settings.title=Titel
settings.deploy_key_content=Innehåll settings.deploy_key_content=Innehåll
settings.branches=Brancher
settings.protected_branch=Branchskydd
settings.protected_branch_can_push=Tillåt push?
settings.protected_branch_can_push_yes=Du kan pusha
settings.protected_branch_can_push_no=Du kan inte pusha
settings.add_protected_branch=Aktivera skydd
settings.delete_protected_branch=Inaktivera skydd
diff.browse_source=Bläddra i källkod diff.browse_source=Bläddra i källkod
diff.parent=förälder diff.parent=förälder
diff.commit=incheckning diff.commit=incheckning
diff.data_not_available=Diff Content ej tillgänglig
diff.show_diff_stats=Visa Diff Statistik diff.show_diff_stats=Visa Diff Statistik
diff.show_split_view=Delad Vy diff.show_split_view=Delad Vy
diff.show_unified_view=Unifierad Vy diff.show_unified_view=Unifierad Vy
@ -571,8 +753,16 @@ release.preview=Förhandsgranska
release.cancel=Avbryt release.cancel=Avbryt
release.publish=Publicera Släpp release.publish=Publicera Släpp
release.save_draft=Spara Utkast release.save_draft=Spara Utkast
release.deletion_success=Releasen har blivit raderad.
release.downloads=Nedladdningar release.downloads=Nedladdningar
branch.search=Sök brancher
branch.delete_head=Radera
branch.delete_html=Radera branch
branch.create_branch=Skapa branchen <strong>%s</strong>
branch.create_from=från '%s'
branch.branch_already_exists=Branch '%s' existerar redan i denna utvecklingskatalog.
branch.deleted_by=Raderad av %s
[org] [org]
@ -598,6 +788,7 @@ settings.update_setting_success=Organisationsinställningarna har uppdaterats.
settings.delete=Tag bort organisation settings.delete=Tag bort organisation
settings.delete_account=Tag bort denna organisation settings.delete_account=Tag bort denna organisation
settings.confirm_delete_account=Bekräfta borttagning settings.confirm_delete_account=Bekräfta borttagning
settings.hooks_desc=Lägg till webbhook som triggas för <strong>alla utvecklingskataloger</strong> under denna organisationen.
members.membership_visibility=Synlighet för medlemskap: members.membership_visibility=Synlighet för medlemskap:
members.member_role=Medlemsroll: members.member_role=Medlemsroll:
@ -617,6 +808,7 @@ teams.settings=Inställningar
teams.members=Teammedlemmar teams.members=Teammedlemmar
teams.update_settings=Uppdatera inställningar teams.update_settings=Uppdatera inställningar
teams.add_team_member=Lägg till teammedlem teams.add_team_member=Lägg till teammedlem
teams.delete_team_success=Teamet har blivit borttaget.
teams.repositories=Teamförråd teams.repositories=Teamförråd
teams.add_team_repository=Lägg till teamförråd teams.add_team_repository=Lägg till teamförråd
teams.remove_repo=Ta bort teams.remove_repo=Ta bort
@ -636,7 +828,11 @@ total=Totalt: %d
dashboard.operation_name=Operationsnamn dashboard.operation_name=Operationsnamn
dashboard.operation_switch=Byt till dashboard.operation_switch=Byt till
dashboard.operation_run=Kör dashboard.operation_run=Kör
dashboard.delete_inactivate_accounts=Ta bort alla inaktiva konton dashboard.clean_unbind_oauth=Rena obundna OAuth anslutningar
dashboard.clean_unbind_oauth_success=Alla obundna OAuth anslutningar har raderats.
dashboard.reinit_missing_repos=Återinitialisera alla saknade utvecklingskataloger som vi känner till
dashboard.reinit_missing_repos_success=Alla utvecklingskataloger som det saknades filer från har blivit återinitaliserade.
dashboard.sync_external_users=Synkronisera extern användardata
dashboard.server_uptime=Serverns upptid dashboard.server_uptime=Serverns upptid
dashboard.current_goroutine=Aktuella Goroutiner dashboard.current_goroutine=Aktuella Goroutiner
dashboard.current_memory_usage=Nuvarande Minnesanvändning dashboard.current_memory_usage=Nuvarande Minnesanvändning
@ -655,6 +851,7 @@ dashboard.mspan_structures_usage=MSpan strukturanvändning
dashboard.mspan_structures_obtained=MSpan strukturer som erhållits dashboard.mspan_structures_obtained=MSpan strukturer som erhållits
dashboard.mcache_structures_usage=MCache strukturanvändning dashboard.mcache_structures_usage=MCache strukturanvändning
dashboard.mcache_structures_obtained=MCache-strukturer som erhållits dashboard.mcache_structures_obtained=MCache-strukturer som erhållits
dashboard.profiling_bucket_hash_table_obtained=Profilering av Bucket Hash Table erhållen
dashboard.gc_metadata_obtained=Metainformation om Skräpsamlaren Ihopsamlad dashboard.gc_metadata_obtained=Metainformation om Skräpsamlaren Ihopsamlad
dashboard.other_system_allocation_obtained=Övriga Systemallokeringar dashboard.other_system_allocation_obtained=Övriga Systemallokeringar
dashboard.next_gc_recycle=Nästa Skräpsamlarrunda dashboard.next_gc_recycle=Nästa Skräpsamlarrunda
@ -677,6 +874,7 @@ orgs.name=Namn
orgs.teams=Team orgs.teams=Team
orgs.members=Medlemmar orgs.members=Medlemmar
repos.repo_manage_panel=Utvecklingskatalogshantering
repos.owner=Ägare repos.owner=Ägare
repos.name=Namn repos.name=Namn
repos.private=Privat repos.private=Privat
@ -694,11 +892,14 @@ auths.auth_name=Autentiseringsnamn
auths.security_protocol=Säkerhetsprotokoll auths.security_protocol=Säkerhetsprotokoll
auths.domain=Domän auths.domain=Domän
auths.host=Värd auths.host=Värd
auths.port=Port
auths.bind_dn=Bind DN
auths.bind_password=Bind Lösenord auths.bind_password=Bind Lösenord
auths.user_base=Användarsökbas auths.user_base=Användarsökbas
auths.user_dn=Användarnas DN auths.user_dn=Användarnas DN
auths.filter=Användarfilter auths.filter=Användarfilter
auths.admin_filter=Administratörsfilter auths.admin_filter=Administratörsfilter
auths.ms_ad_sa=MS AD sökattribut
auths.smtp_auth=SMTP Autentiseringstyp auths.smtp_auth=SMTP Autentiseringstyp
auths.smtphost=SMTP-server auths.smtphost=SMTP-server
auths.smtpport=SMTP-port auths.smtpport=SMTP-port
@ -706,26 +907,41 @@ auths.allowed_domains=Tillåtna Domäner
auths.enable_tls=Aktivera TLS-kryptering auths.enable_tls=Aktivera TLS-kryptering
auths.skip_tls_verify=Skippa verifikation av TLS auths.skip_tls_verify=Skippa verifikation av TLS
auths.pam_service_name=PAM Tjänstnamn auths.pam_service_name=PAM Tjänstnamn
auths.oauth2_provider=OAuth2 leverantör
auths.oauth2_clientID=Klient ID (Nyckel)
auths.oauth2_clientSecret=Klienthemlighet
auths.openIdConnectAutoDiscoveryURL=OpenID Connect Auto Discovery länk
auths.oauth2_tokenURL=Tokenlänk
auths.oauth2_authURL=Auktoriseringslänk
auths.oauth2_profileURL=Profil-URL auths.oauth2_profileURL=Profil-URL
auths.oauth2_emailURL=E-post URL auths.oauth2_emailURL=E-post URL
auths.enable_auto_register=Aktivera Automatisk Registrering auths.enable_auto_register=Aktivera Automatisk Registrering
auths.tips=Tips
auths.tips.oauth2.general=OAuth2 Autensiering
auths.tips.oauth2.general.tip=När man registrerar en ny OAuth2-autentisering, så skall callback/redirect-länken vara: <host>/user/oauth2/<Authentication Name>/callback
auths.tip.oauth2_provider=OAuth2 leverantör
auths.tip.dropbox=Skapa en ny applikation på https://www.dropbox.com/developers/apps auths.tip.dropbox=Skapa en ny applikation på https://www.dropbox.com/developers/apps
auths.tip.facebook=Registrera en ny appliaktion på https://developers.facebook.com/apps och lägg till produkten ”Facebook-inloggning” auths.tip.facebook=Registrera en ny appliaktion på https://developers.facebook.com/apps och lägg till produkten ”Facebook-inloggning”
auths.tip.github=Registrera en ny OAuth applikation på https://github.com/settings/applications/new auths.tip.github=Registrera en ny OAuth applikation på https://github.com/settings/applications/new
auths.tip.gitlab=Registrera en ny applikation på https://gitlab.com/profile/applications auths.tip.gitlab=Registrera en ny applikation på https://gitlab.com/profile/applications
auths.tip.openid_connect=Använd OpenID Connect Discovery länken (<server>/.well-known/openid-configuration) för att ange slutpunkterna
auths.new_success=Autentisering '%s' har lagts till. auths.new_success=Autentisering '%s' har lagts till.
auths.delete_auth_title=Tag bort denna autentisering
config.server_config=Server-konfiguration config.server_config=Server-konfiguration
config.custom_conf=Konfigurationsfil config.custom_conf=Konfigurationsfil
config.disable_router_log=Avaktivera Router Loggning config.disable_router_log=Avaktivera Router Loggning
config.run_mode=Exekveringsläge config.run_mode=Exekveringsläge
config.git_version=Git version
config.repo_root_path=Rotsökväg för utvecklingskatalog config.repo_root_path=Rotsökväg för utvecklingskatalog
config.lfs_root_path=LFS Rotsökväg config.lfs_root_path=LFS Rotsökväg
config.static_file_root_path=Rotsökväg för Statiska Filer config.static_file_root_path=Rotsökväg för Statiska Filer
config.script_type=Script-typ config.script_type=Script-typ
config.reverse_auth_user=Motsatt autentiserings användare
config.ssh_config=SSH-konfiguration config.ssh_config=SSH-konfiguration
config.ssh_enabled=Aktiverad config.ssh_enabled=Aktiverad
config.ssh_port=Port
config.ssh_listen_port=Lyssningsport config.ssh_listen_port=Lyssningsport
config.ssh_root_path=Rotsökväg config.ssh_root_path=Rotsökväg
config.ssh_key_test_path=Testsökväg för nyckel config.ssh_key_test_path=Testsökväg för nyckel
@ -743,16 +959,20 @@ config.service_config=Tjänstkonfiguration
config.show_registration_button=Visa registreringsknapp config.show_registration_button=Visa registreringsknapp
config.disable_key_size_check=Avaktivera kontroll av minsta tillåtna nyckelstorlek config.disable_key_size_check=Avaktivera kontroll av minsta tillåtna nyckelstorlek
config.active_code_lives=Aktivera livstid för koder config.active_code_lives=Aktivera livstid för koder
config.reset_password_code_lives=Återställ giltighetstid för passerkod
config.webhook_config=Webbkrokskonfiguration config.webhook_config=Webbkrokskonfiguration
config.queue_length=Kölängd config.queue_length=Kölängd
config.deliver_timeout=Tidsfrist för leverans config.deliver_timeout=Tidsfrist för leverans
config.skip_tls_verify=Skippa TLS verifiering
config.mailer_enabled=Aktiverad config.mailer_enabled=Aktiverad
config.mailer_disable_helo=Avaktivera HELO config.mailer_disable_helo=Avaktivera HELO
config.mailer_name=Namn config.mailer_name=Namn
config.mailer_host=Server config.mailer_host=Server
config.mailer_user=Användare config.mailer_user=Användare
config.mailer_use_sendmail=Använd Sendmail
config.mailer_sendmail_path=Sendmail sökväg
config.oauth_config=OAuth-konfiguration config.oauth_config=OAuth-konfiguration
config.oauth_enabled=Aktiverad config.oauth_enabled=Aktiverad
@ -777,6 +997,7 @@ config.disable_gravatar=Inaktivera Gravatar
config.enable_federated_avatar=Aktivera Förenad Uppslaging av Profilbilder config.enable_federated_avatar=Aktivera Förenad Uppslaging av Profilbilder
config.git_config=Git-konfiguration config.git_config=Git-konfiguration
config.git_disable_diff_highlight=Inaktivera Diff Syntax Highlight
config.git_max_diff_lines=Max Diff-rader (per fil) config.git_max_diff_lines=Max Diff-rader (per fil)
config.git_max_diff_line_characters=Max Diff-tecken (per rad) config.git_max_diff_line_characters=Max Diff-tecken (per rad)
config.git_max_diff_files=Max Diff-filer (att visa) config.git_max_diff_files=Max Diff-filer (att visa)
@ -811,6 +1032,8 @@ notices.delete_all=Ta Bort Alla Notiser
notices.type=Typ notices.type=Typ
notices.type_1=Utvecklingskatalog notices.type_1=Utvecklingskatalog
notices.desc=Beskrivning notices.desc=Beskrivning
notices.op=Op.
notices.delete_success=Systemnotifikationer har blivit raderade.
[action] [action]
create_repo=skapade utvecklingskatalog <a href="%s"> %s</a> create_repo=skapade utvecklingskatalog <a href="%s"> %s</a>
@ -826,11 +1049,15 @@ comment_issue=`kommenterade på ärende <a href="%s/issues/%s">%s#%[2]s</a>`
merge_pull_request=`sammanslog pull-request <a href="%s/pulls/%s">%s#%[2]s</a>` merge_pull_request=`sammanslog pull-request <a href="%s/pulls/%s">%s#%[2]s</a>`
transfer_repo=överförde utvecklingskalatogen <code>%s</code> till <a href="%s">%s</a> transfer_repo=överförde utvecklingskalatogen <code>%s</code> till <a href="%s">%s</a>
push_tag=laddade upp taggen <a href="%s/src/%s">%[2]s</a> till <a href="%[1]s">%[3]s</a> push_tag=laddade upp taggen <a href="%s/src/%s">%[2]s</a> till <a href="%[1]s">%[3]s</a>
delete_tag=tog bort taggen %[2]s från <a href="%[1]s">%[3]s</a>
delete_branch=tog bort branchen %[2]s from <a href="%[1]s">%[3]s</a>
compare_commits=Jämför %d commits
[tool] [tool]
ago=%s sedan ago=%s sedan
from_now=%s från och med nu from_now=%s från och med nu
now=nu now=nu
future=framtiden
1s=1 sekund 1s=1 sekund
1m=1 minut 1m=1 minut
1h=1 timme 1h=1 timme
@ -849,17 +1076,23 @@ raw_seconds=sekunder
raw_minutes=minuter raw_minutes=minuter
[dropzone] [dropzone]
file_too_big=Filstorleken ({{filesize}} MB) överskrider maxstorleken ({{maxFilesize}} MB).
remove_file=Ta bort fil remove_file=Ta bort fil
[notification] [notification]
notifications=Notiser notifications=Notiser
unread=Olästa unread=Olästa
read=Lästa read=Lästa
pin=Pinna notifiering
mark_as_read=Markera som läst mark_as_read=Markera som läst
mark_as_unread=Markera som oläst mark_as_unread=Markera som oläst
mark_all_as_read=Markera alla som lästa
[gpg] [gpg]
error.extract_sign=Det gick inte att extrahera signatur error.extract_sign=Det gick inte att extrahera signatur
error.generate_hash=Misslyckades att generera hashsumma av commiten
error.no_gpg_keys_found=Ingen känd nyckel hittad för denna signaturen i databasen
error.not_signed_commit=Inte en signerad commit
[units] [units]

View File

@ -688,8 +688,6 @@ dashboard.operation_switch=Geç
dashboard.operation_run=Çalıştır dashboard.operation_run=Çalıştır
dashboard.clean_unbind_oauth=Bağsız OAuth bağlantılarını temizle dashboard.clean_unbind_oauth=Bağsız OAuth bağlantılarını temizle
dashboard.clean_unbind_oauth_success=Tüm bağsız OAuth bağlantıları silindi. dashboard.clean_unbind_oauth_success=Tüm bağsız OAuth bağlantıları silindi.
dashboard.delete_inactivate_accounts=Etkin olmayan tüm hesapları sil
dashboard.delete_inactivate_accounts_success=Tüm aktif olmayan hesaplar silindi.
dashboard.reinit_missing_repos=Kayıtları bulunanlar için tüm eksik Git depolarını yeniden başlat dashboard.reinit_missing_repos=Kayıtları bulunanlar için tüm eksik Git depolarını yeniden başlat
dashboard.reinit_missing_repos_success=Kayıtları bulunanlar için tüm eksik Git depoları yeniden başlatıldı. dashboard.reinit_missing_repos_success=Kayıtları bulunanlar için tüm eksik Git depoları yeniden başlatıldı.
dashboard.sync_external_users=Harici kullanıcı verisini senkronize et dashboard.sync_external_users=Harici kullanıcı verisini senkronize et

View File

@ -102,6 +102,7 @@ lfs_path_helper=У цій папці будуть зберігатися фай
run_user=Запуск від імені Користувача run_user=Запуск від імені Користувача
run_user_helper=Введіть ім'я користувача операційної системи, під яким працює Gitea. Зверніть увагу, що цей користувач повинен бути доступ до кореневого шляху репозиторія. run_user_helper=Введіть ім'я користувача операційної системи, під яким працює Gitea. Зверніть увагу, що цей користувач повинен бути доступ до кореневого шляху репозиторія.
domain=Домен SSH сервера domain=Домен SSH сервера
domain_helper=Домен або хост-адреса для клонування через SSH - впливає на URL-адресу.
ssh_port=Порт SSH сервера ssh_port=Порт SSH сервера
ssh_port_helper=Номер порту, який використовує SSH сервер. Залиште порожнім, щоб вимкнути SSH. ssh_port_helper=Номер порту, який використовує SSH сервер. Залиште порожнім, щоб вимкнути SSH.
http_port=Gitea HTTP порт http_port=Gitea HTTP порт
@ -149,6 +150,7 @@ test_git_failed=Не в змозі перевірити 'git' команду: %v
sqlite3_not_available=Ця версія Gitea не підтримує SQLite3. Будь ласка, завантажте офіційну бінарну версію з %s (не версію gobuild). sqlite3_not_available=Ця версія Gitea не підтримує SQLite3. Будь ласка, завантажте офіційну бінарну версію з %s (не версію gobuild).
invalid_db_setting=Налаштування бази даних є некоректними: %v invalid_db_setting=Налаштування бази даних є некоректними: %v
invalid_repo_path=Помилковий шлях до кореня репозиторію: %v invalid_repo_path=Помилковий шлях до кореня репозиторію: %v
run_user_not_match=Ім'я користувача 'run as' не є поточним ім'ям користувача: %s -> %s
save_config_failed=Не в змозі зберегти конфігурацію: %v save_config_failed=Не в змозі зберегти конфігурацію: %v
invalid_admin_setting=Неприпустимі налаштування облікового запису адміністратора: %v invalid_admin_setting=Неприпустимі налаштування облікового запису адміністратора: %v
install_success=Ласкаво просимо! Дякуємо вам за вибір Gitea. Розважайтеся, і будьте обережні! install_success=Ласкаво просимо! Дякуємо вам за вибір Gitea. Розважайтеся, і будьте обережні!
@ -342,6 +344,7 @@ location=Місцезнаходження
update_profile=Оновити профіль update_profile=Оновити профіль
update_profile_success=Профіль успішно оновлено. update_profile_success=Профіль успішно оновлено.
change_username=Ваше Ім'я кристувача було змінено. change_username=Ваше Ім'я кристувача було змінено.
change_username_prompt=Примітка. Зміни в імені також змінюють URL-адресу облікового запису.
continue=Продовжити continue=Продовжити
cancel=Відмінити cancel=Відмінити
language=Мова language=Мова
@ -371,8 +374,10 @@ primary=Основний
primary_email=Зробити основним primary_email=Зробити основним
delete_email=Видалити delete_email=Видалити
email_deletion=Видалити адресу електронної пошти email_deletion=Видалити адресу електронної пошти
email_deletion_desc=Електронна адреса та пов'язана з нею інформація буде видалена з вашого облікового запису. Git коміти, здійснені через цю електронну адресу, залишиться без змін. Продовжити?
email_deletion_success=Адресу електронної пошти було видалено. email_deletion_success=Адресу електронної пошти було видалено.
openid_deletion=Видалити адресу OpenID openid_deletion=Видалити адресу OpenID
openid_deletion_desc=Видалення цієї OpenID-адреси з вашого облікового запису забороняє вам входити з ним. Продовжити?
openid_deletion_success=Адреса OpenID була видалена. openid_deletion_success=Адреса OpenID була видалена.
add_new_email=Додати нову адресу електронної пошти add_new_email=Додати нову адресу електронної пошти
add_new_openid=Додати новий OpenID URI add_new_openid=Додати новий OpenID URI
@ -383,6 +388,7 @@ add_email_success=Додано нову адресу електронної по
add_openid_success=Нова адреса OpenID була додана. add_openid_success=Нова адреса OpenID була додана.
keep_email_private=Приховати адресу електронної пошти keep_email_private=Приховати адресу електронної пошти
keep_email_private_popup=Вашу адресу електронної пошти буде приховано від інших користувачів. keep_email_private_popup=Вашу адресу електронної пошти буде приховано від інших користувачів.
openid_desc=OpenID дозволяє делегувати аутентифікацію зовнішньому постачальнику послуг.
manage_ssh_keys=Керувати SSH ключами manage_ssh_keys=Керувати SSH ключами
manage_gpg_keys=Керувати GPG ключами manage_gpg_keys=Керувати GPG ключами
@ -396,6 +402,7 @@ add_new_gpg_key=Додати GPG ключ
ssh_key_been_used=Цей ключ SSH вже додано до вашого облікового запису. ssh_key_been_used=Цей ключ SSH вже додано до вашого облікового запису.
ssh_key_name_used=Ключ SSH з таким самим ім'ям вже додано до вашого облікового запису. ssh_key_name_used=Ключ SSH з таким самим ім'ям вже додано до вашого облікового запису.
gpg_key_id_used=Публічний ключ GPG з таким самим ідентифікатором вже існує. gpg_key_id_used=Публічний ключ GPG з таким самим ідентифікатором вже існує.
gpg_no_key_email_found=Цей ключ GPG непридатний для використання з будь-якою електронною адресою, що пов'язана з вашим обліковим записом.
subkeys=Підключі subkeys=Підключі
key_id=ID ключа key_id=ID ключа
key_name=Ім'я ключа key_name=Ім'я ключа
@ -407,7 +414,7 @@ ssh_key_deletion=Видалити SSH ключ
gpg_key_deletion=Видалити GPG ключ gpg_key_deletion=Видалити GPG ключ
ssh_key_deletion_desc=Видалення ключа SSH скасовує доступ до вашого облікового запису. Продовжити? ssh_key_deletion_desc=Видалення ключа SSH скасовує доступ до вашого облікового запису. Продовжити?
gpg_key_deletion_desc=Видалення GPG ключа скасовує перевірку підписаних ним комітів. Продовжити? gpg_key_deletion_desc=Видалення GPG ключа скасовує перевірку підписаних ним комітів. Продовжити?
ssh_key_deletion_success=SSH було видалено. ssh_key_deletion_success=SSH ключ був видалений.
gpg_key_deletion_success=GPG було видалено. gpg_key_deletion_success=GPG було видалено.
add_on=Додано add_on=Додано
valid_until=Дійсний до valid_until=Дійсний до
@ -423,7 +430,9 @@ hide_openid=Не показувати у профілі
ssh_disabled=SSH вимкнено ssh_disabled=SSH вимкнено
manage_social=Керувати зв'язаними обліковими записами соціальних мереж manage_social=Керувати зв'язаними обліковими записами соціальних мереж
social_desc=Ці адреси соціальних мереж пов'язані з вашим обліковим записом Gitea. Переконайтеся, що ви їх впізнаєте, оскільки вони можуть бути використані для входу в обліковий запис Gitea.
unbind=Від'єднати unbind=Від'єднати
unbind_success=Зв'язаний зовнішній обліковий запис було видалено.
manage_access_token=Керування токенами доступу manage_access_token=Керування токенами доступу
generate_new_token=Згенерувати новий токен generate_new_token=Згенерувати новий токен
@ -431,30 +440,43 @@ tokens_desc=Ці токени надають доступ до вашого об
new_token_desc=Додатки, що використовують токен, мають повний доступ до вашого облікового запису. new_token_desc=Додатки, що використовують токен, мають повний доступ до вашого облікового запису.
token_name=Ім'я токену token_name=Ім'я токену
generate_token=Згенерувати токен generate_token=Згенерувати токен
generate_token_success=Ваш новий токен був створений. Скопіюйте його зараз, оскільки він не буде показаний знову.
delete_token=Видалити delete_token=Видалити
access_token_deletion=Видалити токен доступу access_token_deletion=Видалити токен доступу
access_token_deletion_desc=Видалення токена скасовує доступ до вашого облікового запису для програм, що використовують його. Продовжити?
delete_token_success=Токен був знищений. Програми, що використовують його, більше не мають доступу до вашого облікового запису.
twofa_desc=Двофакторна автентифікація підвищує безпеку вашого облікового запису. twofa_desc=Двофакторна автентифікація підвищує безпеку вашого облікового запису.
twofa_is_enrolled=Ваш обліковий запис на даний час <strong>використовує</strong> двофакторну автентифікацію. twofa_is_enrolled=Ваш обліковий запис на даний час <strong>використовує</strong> двофакторну автентифікацію.
twofa_not_enrolled=Ваш обліковий запис наразі не використовує двофакторну автентифікаціїю. twofa_not_enrolled=Ваш обліковий запис наразі не використовує двофакторну автентифікаціїю.
twofa_disable=Вимкнути двофакторну автентифікацію twofa_disable=Вимкнути двофакторну автентифікацію
twofa_scratch_token_regenerate=Перестворити токен одноразового пароля twofa_scratch_token_regenerate=Перестворити токен одноразового пароля
twofa_scratch_token_regenerated=Ваш новий scratch-токен %s. Зберігайте його в безпечному місці.
twofa_enroll=Увімкнути двофакторну автентифікацію twofa_enroll=Увімкнути двофакторну автентифікацію
twofa_disable_note=При необхідності можна відключити двофакторну автентифікацію. twofa_disable_note=При необхідності можна відключити двофакторну автентифікацію.
twofa_disable_desc=Вимкнення двофакторної автентифікації зробить ваш обліковий запис менш безпечним. Продовжити?
regenerate_scratch_token_desc=Якщо ви втратили свій токен одноразового пароля або вже використовували його для входу, ви можете скинути його тут. regenerate_scratch_token_desc=Якщо ви втратили свій токен одноразового пароля або вже використовували його для входу, ви можете скинути його тут.
twofa_disabled=Двофакторна автентифікація вимкнена. twofa_disabled=Двофакторна автентифікація вимкнена.
scan_this_image=Проскануйте це зображення вашим додатком для двуфакторної автентифікації: scan_this_image=Проскануйте це зображення вашим додатком для двуфакторної автентифікації:
or_enter_secret=Або введіть секрет: %s or_enter_secret=Або введіть секрет: %s
then_enter_passcode=І введіть пароль, який відображається в додатку:
passcode_invalid=Некоректний пароль. Спробуй ще раз. passcode_invalid=Некоректний пароль. Спробуй ще раз.
twofa_enrolled=Для вашого облікового запису було включена двофакторна автентифікація. Зберігайте свій scratch-токен (%s) у безпечному місці, оскільки він показується лише один раз!
u2f_desc=Ключами безпеки є апаратні пристрої, що містять криптографічні ключі. Вони можуть використовуватися для двофакторної автентифікації. Ключ безпеки повинен підтримувати стандарт <a href="https://fidoalliance.org/">FIDO U2F</a>. u2f_desc=Ключами безпеки є апаратні пристрої, що містять криптографічні ключі. Вони можуть використовуватися для двофакторної автентифікації. Ключ безпеки повинен підтримувати стандарт <a href="https://fidoalliance.org/">FIDO U2F</a>.
u2f_require_twofa=Для використання ключів безпеки необхідно зареєструвати двофакторну аутентифікацію.
u2f_register_key=Додати ключ безпеки u2f_register_key=Додати ключ безпеки
u2f_nickname=Псевдонім u2f_nickname=Псевдонім
u2f_press_button=Натисніть кнопку на ключі безпеки, щоб зареєструвати його.
u2f_delete_key=Видалити ключ безпеки u2f_delete_key=Видалити ключ безпеки
u2f_delete_key_desc=Якщо ви видалите ключ безпеки, ви не зможете використати його для входу. Ти впевнені?
manage_account_links=Керування обліковими записами manage_account_links=Керування обліковими записами
manage_account_links_desc=Ці зовнішні акаунти прив'язані до вашого аккаунту Gitea. manage_account_links_desc=Ці зовнішні акаунти прив'язані до вашого аккаунту Gitea.
account_links_not_available=Наразі немає зовнішніх облікових записів, пов'язаних із вашим обліковим записом Gitea.
remove_account_link=Видалити облікові записи remove_account_link=Видалити облікові записи
remove_account_link_desc=Видалення пов'язаного облікового запису відкликає його доступ до вашого облікового запису Gitea. Продовжити?
remove_account_link_success=Зв'язаний обліковий запис видалено.
orgs_none=Ви не є учасником будь-якої організації. orgs_none=Ви не є учасником будь-якої організації.
repos_none=У вас немає власних репозиторіїв repos_none=У вас немає власних репозиторіїв
@ -463,17 +485,20 @@ delete_account=Видалити ваш обліковий запис
delete_prompt=Ця операція остаточно видалить обліковий запис користувача. Це <strong>НЕ МОЖЛИВО</strong> відмінити. delete_prompt=Ця операція остаточно видалить обліковий запис користувача. Це <strong>НЕ МОЖЛИВО</strong> відмінити.
confirm_delete_account=Підтвердження видалення confirm_delete_account=Підтвердження видалення
delete_account_title=Видалити цей обліковий запис delete_account_title=Видалити цей обліковий запис
delete_account_desc=Ви впевнені, що хочете остаточно видалити цей обліковий запис?
[repo] [repo]
owner=Власник owner=Власник
repo_name=Назва репозиторію repo_name=Назва репозиторію
repo_name_helper=Хороші назви репозиторіїв використовують короткі, унікальні ключові слова що легко запам'ятати.
visibility=Видимість visibility=Видимість
visiblity_helper=Зробити репозиторій приватним visibility_helper=Створити приватний репозиторій
visiblity_fork_helper=(Зміна цього вплине на всі форки.) visibility_helper_forced=Адміністратор вашого сайту налаштував параметри: всі нові репозиторії будуть приватними.
clone_helper=Потрібна допомога у клонуванні? Відвідайте <a target="_blank" rel="noopener" href="%s">Допомогу</a>. visibility_fork_helper=(Ці зміни вплинуть на всі форки.)
clone_helper=Потрібна допомога у клонуванні? Відвідайте сторінку <a target="_blank" rel="noopener" href="%s">Допомога</a>.
fork_repo=Форкнути репозиторій fork_repo=Форкнути репозиторій
fork_from=Форк з fork_from=Форк з
fork_visiblity_helper=Видимість форкнутого репозиторію змінити не можна. fork_visibility_helper=Неможливо змінити видимість форкнутого репозиторію.
repo_desc=Опис repo_desc=Опис
repo_lang=Мова repo_lang=Мова
repo_gitignore_helper=Виберіть шаблон .gitignore. repo_gitignore_helper=Виберіть шаблон .gitignore.
@ -485,9 +510,11 @@ auto_init=Ініціалізувати репозиторій (Додає .gitig
create_repo=Створити репозиторій create_repo=Створити репозиторій
default_branch=Головна гілка default_branch=Головна гілка
mirror_prune=Очистити mirror_prune=Очистити
mirror_prune_desc=Видалення застарілих посилань які ви відслідковуєте
mirror_interval=Інтервал дзеркалювання (доступні значення 'h', 'm', 's') mirror_interval=Інтервал дзеркалювання (доступні значення 'h', 'm', 's')
mirror_interval_invalid=Інтервал дзеркалювання є неприпустимим. mirror_interval_invalid=Інтервал дзеркалювання є неприпустимим.
mirror_address=Клонування з URL-адреси mirror_address=Клонування з URL-адреси
mirror_address_desc=Включіть необхідні облікові дані в URL-адресу.
mirror_last_synced=Остання синхронізація mirror_last_synced=Остання синхронізація
watchers=Спостерігачі watchers=Спостерігачі
stargazers=Зацікавлені stargazers=Зацікавлені
@ -497,6 +524,7 @@ reactions_more=додати %d більше
form.reach_limit_of_creation=Ви досягли максимальної кількості %d створених репозиторіїв. form.reach_limit_of_creation=Ви досягли максимальної кількості %d створених репозиторіїв.
form.name_reserved=Назву репозиторію '%s' зарезервовано. form.name_reserved=Назву репозиторію '%s' зарезервовано.
form.name_pattern_not_allowed=Шаблон '%s' не дозволено в назві репозиторія.
need_auth=Клонувати з авторизацією need_auth=Клонувати з авторизацією
migrate_type=Тип міграції migrate_type=Тип міграції
@ -506,6 +534,7 @@ migrate.clone_address=Міграція / клонувати з URL-адреси
migrate.clone_address_desc=URL-адреса HTTP(S) або Git "clone" існуючого репозиторія migrate.clone_address_desc=URL-адреса HTTP(S) або Git "clone" існуючого репозиторія
migrate.clone_local_path=або шлях до локального серверу migrate.clone_local_path=або шлях до локального серверу
migrate.permission_denied=Вам не дозволено імпортувати локальні репозиторії. migrate.permission_denied=Вам не дозволено імпортувати локальні репозиторії.
migrate.invalid_local_path=Локальний шлях недійсний. Він не існує або не є каталогом.
migrate.failed=Міграція не вдалася: %v migrate.failed=Міграція не вдалася: %v
migrate.lfs_mirror_unsupported=Дзеркалювання LFS об'єктів не підтримується - використовуйте 'git lfs fetch --all' і 'git lfs push --all' вручну. migrate.lfs_mirror_unsupported=Дзеркалювання LFS об'єктів не підтримується - використовуйте 'git lfs fetch --all' і 'git lfs push --all' вручну.
@ -531,6 +560,7 @@ push_exist_repo=Опублікувати існуючий репозиторій
bare_message=Цей репозиторій порожній. bare_message=Цей репозиторій порожній.
code=Код code=Код
code.desc=Доступ до коду, файлів, комітів та гілок.
branch=Гілка branch=Гілка
tree=Дерево tree=Дерево
filter_branch_and_tag=Фільтрувати гілку або тег filter_branch_and_tag=Фільтрувати гілку або тег
@ -564,6 +594,7 @@ editor.delete_this_file=Видалити файл
editor.must_have_write_access=Ви повинні мати доступ на запис щоб запропонувати зміни до цього файлу. editor.must_have_write_access=Ви повинні мати доступ на запис щоб запропонувати зміни до цього файлу.
editor.file_delete_success=Файл '%s' видалено. editor.file_delete_success=Файл '%s' видалено.
editor.name_your_file=Дайте назву файлу… editor.name_your_file=Дайте назву файлу…
editor.filename_help=Щоб додати каталог, наберіть його назву, а потім - косу риску ('/'). Щоб видалити каталог, перейдіть до початку поля і натисніть backspace.
editor.or=або editor.or=або
editor.cancel_lower=Скасувати editor.cancel_lower=Скасувати
editor.commit_changes=Закомітити зміни editor.commit_changes=Закомітити зміни
@ -579,13 +610,19 @@ editor.cancel=Відмінити
editor.filename_cannot_be_empty=Ім'я файлу не може бути порожнім. editor.filename_cannot_be_empty=Ім'я файлу не може бути порожнім.
editor.branch_already_exists=Гілка '%s' вже присутня в репозиторії. editor.branch_already_exists=Гілка '%s' вже присутня в репозиторії.
editor.directory_is_a_file=Ім'я каталогу "%s" уже використовується як ім'я файлу в цьому репозиторії. editor.directory_is_a_file=Ім'я каталогу "%s" уже використовується як ім'я файлу в цьому репозиторії.
editor.file_is_a_symlink='%s' є символічним посиланням. Символічні посилання не можливо редагувати в веб-редакторі
editor.filename_is_a_directory=Назва файлу '%s' вже використовується як ім'я каталогу в цьому репозиторії.
editor.file_editing_no_longer_exists=Редагований файл '%s' більше не існує в цьому репозиторії.
editor.file_changed_while_editing=Зміст файлу змінився з моменту початку редагування. <a target="_blank" rel="noopener" href="%s"> Натисніть тут </a>, щоб переглянути що було змінено, або <strong>закомітьте зміни ще раз</strong>, щоб переписати їх.
editor.file_already_exists=Файл з назвою "%s" уже існує у цьому репозиторію. editor.file_already_exists=Файл з назвою "%s" уже існує у цьому репозиторію.
editor.no_changes_to_show=Нема змін для показу. editor.no_changes_to_show=Нема змін для показу.
editor.fail_to_update_file=Не вдалося оновити/створити файл '%s' через помилку: %v editor.fail_to_update_file=Не вдалося оновити/створити файл '%s' через помилку: %v
editor.add_subdir=Додати каталог… editor.add_subdir=Додати каталог…
editor.unable_to_upload_files=Не вдалося завантажити файли до '%s' через помилку: %v editor.unable_to_upload_files=Не вдалося завантажити файли до '%s' через помилку: %v
editor.upload_files_to_dir=Завантажувати файли до '%s' editor.upload_files_to_dir=Завантажувати файли до '%s'
editor.cannot_commit_to_protected_branch=Заборонено вносити коміт до захищеної гілки '%s'.
commits.desc=Переглянути історію зміни коду.
commits.commits=Коміти commits.commits=Коміти
commits.search=Знайти коміт… commits.search=Знайти коміт…
commits.find=Пошук commits.find=Пошук
@ -601,6 +638,7 @@ commits.gpg_key_id=Ідентифікатор GPG ключа
ext_issues=Зов. Проблеми ext_issues=Зов. Проблеми
ext_issues.desc=Посилання на зовнішню систему відстеження проблем. ext_issues.desc=Посилання на зовнішню систему відстеження проблем.
issues.desc=Організація звітів про помилки, завдань та етапів.
issues.new=Нова проблема issues.new=Нова проблема
issues.new.labels=Мітки issues.new.labels=Мітки
issues.new.no_label=Без мітки issues.new.no_label=Без мітки
@ -620,12 +658,17 @@ issues.new_label_placeholder=Назва мітки
issues.new_label_desc_placeholder=Опис issues.new_label_desc_placeholder=Опис
issues.create_label=Створити мітку issues.create_label=Створити мітку
issues.label_templates.title=Завантажити визначений набір міток issues.label_templates.title=Завантажити визначений набір міток
issues.label_templates.info=Ще немає міток. Натисніть 'Нова мітка' або використовуйте попередньо визначений набір міток:
issues.label_templates.helper=Оберіть набір міток issues.label_templates.helper=Оберіть набір міток
issues.label_templates.use=Використовувати набір міток issues.label_templates.use=Використовувати набір міток
issues.label_templates.fail_to_load_file=Не вдалося завантажити файл шаблона мітки '%s': %v issues.label_templates.fail_to_load_file=Не вдалося завантажити файл шаблона мітки '%s': %v
issues.add_label_at=додав(ла) мітку <div class="ui label" style="color: %s\; background-color: %s">%s</div> %s issues.add_label_at=додав(ла) мітку <div class="ui label" style="color: %s\; background-color: %s">%s</div> %s
issues.remove_label_at=видалив(ла) метку <div class="ui label" style="color: %s\; background-color: %s">%s</div> %s
issues.add_milestone_at=`додав(ла) до <b>%s</b> етапу %s` issues.add_milestone_at=`додав(ла) до <b>%s</b> етапу %s`
issues.change_milestone_at=`змінено цільової етап з <b>%s</b> на <b>%s</b> %s`
issues.remove_milestone_at=`видалено з етапу<b>%s</b> %s`
issues.deleted_milestone=`(видалено)` issues.deleted_milestone=`(видалено)`
issues.self_assign_at=`самонавчался %s`
issues.add_assignee_at=`був призначений <b>%s</b> %s` issues.add_assignee_at=`був призначений <b>%s</b> %s`
issues.remove_assignee_at=`видалили із призначених %s` issues.remove_assignee_at=`видалили із призначених %s`
issues.change_title_at=`змінив(ла) заголовок з <b>%s</b> на <b>%s</b> %s` issues.change_title_at=`змінив(ла) заголовок з <b>%s</b> на <b>%s</b> %s`
@ -695,6 +738,7 @@ issues.label_edit=Редагувати
issues.label_delete=Видалити issues.label_delete=Видалити
issues.label_modify=Редагувати мітку issues.label_modify=Редагувати мітку
issues.label_deletion=Видалити мітку issues.label_deletion=Видалити мітку
issues.label_deletion_desc=Видалення мітки видаляє її з усіх обговорень. Продовжити?
issues.label_deletion_success=Мітку було видалено. issues.label_deletion_success=Мітку було видалено.
issues.label.filter_sort.alphabetically=За алфавітом issues.label.filter_sort.alphabetically=За алфавітом
issues.label.filter_sort.reverse_alphabetically=З кінця алфавіту issues.label.filter_sort.reverse_alphabetically=З кінця алфавіту
@ -726,21 +770,28 @@ issues.time_spent_from_all_authors=`Загальний витрачений ча
issues.due_date=Дата завершення issues.due_date=Дата завершення
issues.invalid_due_date_format=Дата закінчення має бути в форматі 'ррр-мм-дд'. issues.invalid_due_date_format=Дата закінчення має бути в форматі 'ррр-мм-дд'.
issues.error_modifying_due_date=Не вдалося змінити дату завершення. issues.error_modifying_due_date=Не вдалося змінити дату завершення.
issues.error_removing_due_date=Не вдалося видалити дату завершення.
issues.due_date_form=рррр-мм-дд issues.due_date_form=рррр-мм-дд
issues.due_date_form_add=Додати дату завершення issues.due_date_form_add=Додати дату завершення
issues.due_date_form_update=Оновити дату завершення issues.due_date_form_update=Оновити дату завершення
issues.due_date_form_remove=Видалити дату завершення issues.due_date_form_remove=Видалити дату завершення
issues.due_date_not_writer=Вам потрібен доступ до запису в репозиторії, щоб оновити дату завершення проблем.
issues.due_date_not_set=Термін виконання не встановлений. issues.due_date_not_set=Термін виконання не встановлений.
issues.due_date_added=додав(ла) дату завершення %s %s issues.due_date_added=додав(ла) дату завершення %s %s
issues.due_date_modified=термін змінено з %s %s на %s
issues.due_date_remove=видалив(ла) дату завершення %s %s
issues.due_date_overdue=Прострочено issues.due_date_overdue=Прострочено
pulls.desc=Увімкнути запити на злиття та інтерфейс узгодження правок.
pulls.new=Новий запит на злиття pulls.new=Новий запит на злиття
pulls.compare_changes=Новий запит на злиття pulls.compare_changes=Новий запит на злиття
pulls.compare_changes_desc=Порівняти дві гілки і створити запит на злиття для змін.
pulls.compare_base=злити в pulls.compare_base=злити в
pulls.compare_compare=pull з pulls.compare_compare=pull з
pulls.filter_branch=Фільтр по гілці pulls.filter_branch=Фільтр по гілці
pulls.no_results=Результатів не знайдено. pulls.no_results=Результатів не знайдено.
pulls.nothing_to_compare=Ці гілки однакові. Немає необхідності створювати запитів на злиття. pulls.nothing_to_compare=Ці гілки однакові. Немає необхідності створювати запитів на злиття.
pulls.has_pull_request=`Вже існує запит на злиття між двома цілями: <a href="%[1]s/pulls/%[3]d">%[2]s#%[3]d</a>`
pulls.create=Створити запит на злиття pulls.create=Створити запит на злиття
pulls.title_desc=хоче злити %[1]d комітів з <code>%[2]s</code> до <code>%[3]s</code> pulls.title_desc=хоче злити %[1]d комітів з <code>%[2]s</code> до <code>%[3]s</code>
pulls.merged_title_desc=злито %[1]d комітів з <code>%[2]s</code> до <code>%[3]s</code> %[4]s pulls.merged_title_desc=злито %[1]d комітів з <code>%[2]s</code> до <code>%[3]s</code> %[4]s
@ -750,6 +801,8 @@ pulls.tab_files=Змінені файли
pulls.reopen_to_merge=Будь ласка перевідкрийте цей запит щоб здіснити операцію злиття. pulls.reopen_to_merge=Будь ласка перевідкрийте цей запит щоб здіснити операцію злиття.
pulls.merged=Злито pulls.merged=Злито
pulls.has_merged=Запит на злиття було об'єднано. pulls.has_merged=Запит на злиття було об'єднано.
pulls.data_broken=Вміст цього запиту було порушено внаслідок видалення інформації ФОРКОМ.
pulls.is_checking=Триває перевірка конфліктів, будь ласка обновіть сторінку дещо пізніше.
pulls.can_auto_merge_desc=Цей запит можна об'єднати автоматично. pulls.can_auto_merge_desc=Цей запит можна об'єднати автоматично.
pulls.cannot_auto_merge_desc=Цей запит на злиття не може бути злитий автоматично через конфлікти. pulls.cannot_auto_merge_desc=Цей запит на злиття не може бути злитий автоматично через конфлікти.
pulls.cannot_auto_merge_helper=Злийте вручну для вирішення конфліктів. pulls.cannot_auto_merge_helper=Злийте вручну для вирішення конфліктів.
@ -758,6 +811,8 @@ pulls.no_merge_helper=Увімкніть параметри злиття в на
pulls.merge_pull_request=Об'єднати запит на злиття pulls.merge_pull_request=Об'єднати запит на злиття
pulls.rebase_merge_pull_request=Зробити Rebase і злити pulls.rebase_merge_pull_request=Зробити Rebase і злити
pulls.squash_merge_pull_request=Об'єднати (Squash) і злити pulls.squash_merge_pull_request=Об'єднати (Squash) і злити
pulls.invalid_merge_option=Цей параметр злиття не можна використовувати для цього Pull Request'а.
pulls.open_unmerged_pull_exists=`Ви не можете знову відкрити, оскільки вже існує запит на злиття (%d) з того ж репозиторія з тією ж інформацією про злиття і в очікуванні.`
milestones.new=Новий етап milestones.new=Новий етап
milestones.open_tab=%d відкрито milestones.open_tab=%d відкрито
@ -766,17 +821,26 @@ milestones.closed=Закрито %s
milestones.no_due_date=Немає дати завершення milestones.no_due_date=Немає дати завершення
milestones.open=Відкрити milestones.open=Відкрити
milestones.close=Закрити milestones.close=Закрити
milestones.new_subheader=Створюйте етапи для організації ваших завдань.
milestones.create=Створити етап milestones.create=Створити етап
milestones.title=Заголовок milestones.title=Заголовок
milestones.desc=Опис milestones.desc=Опис
milestones.due_date=Дата завершення (опціонально) milestones.due_date=Дата завершення (опціонально)
milestones.clear=Очистити milestones.clear=Очистити
milestones.invalid_due_date_format=Дата завершення має бути в форматі 'рррр-мм-дд'.
milestones.create_success=Етап '%s' створений.
milestones.edit=Редагувати етап milestones.edit=Редагувати етап
milestones.edit_subheader=Використовуйте кращий опис контрольної точки, щоб уникнути нерозуміння з боку інших людей.
milestones.cancel=Відмінити milestones.cancel=Відмінити
milestones.modify=Оновити етап milestones.modify=Оновити етап
milestones.edit_success=Етап '%s' був оновлений.
milestones.deletion=Видалити етап milestones.deletion=Видалити етап
milestones.deletion_desc=Видалення етапу призведе до його видалення з усіх пов'язаних завдань. Продовжити?
milestones.deletion_success=Етап успішно видалено.
milestones.filter_sort.closest_due_date=Найближче за датою milestones.filter_sort.closest_due_date=Найближче за датою
milestones.filter_sort.furthest_due_date=Далі за датою milestones.filter_sort.furthest_due_date=Далі за датою
milestones.filter_sort.least_complete=Менш повне
milestones.filter_sort.most_complete=Більш повне
milestones.filter_sort.most_issues=Найбільш проблем milestones.filter_sort.most_issues=Найбільш проблем
milestones.filter_sort.least_issues=Найменш проблем milestones.filter_sort.least_issues=Найменш проблем
@ -785,16 +849,21 @@ ext_wiki.desc=Посилання на зовнішню вікі.
wiki=Вікі wiki=Вікі
wiki.welcome=Ласкаво просимо до Вікі. wiki.welcome=Ласкаво просимо до Вікі.
wiki.welcome_desc=Wiki дозволяє писати та ділитися документацією з співавторами.
wiki.desc=Пишіть та обмінюйтеся документацією із співавторами.
wiki.create_first_page=Створити першу сторінку wiki.create_first_page=Створити першу сторінку
wiki.page=Сторінка wiki.page=Сторінка
wiki.filter_page=Фільтр сторінок wiki.filter_page=Фільтр сторінок
wiki.new_page=Сторінка wiki.new_page=Сторінка
wiki.default_commit_message=Напишіть примітку про оновлення цієї сторінки (необов'язково).
wiki.save_page=Зберегти сторінку wiki.save_page=Зберегти сторінку
wiki.last_commit_info=%s редагував цю сторінку %s wiki.last_commit_info=%s редагував цю сторінку %s
wiki.edit_page_button=Редагувати wiki.edit_page_button=Редагувати
wiki.new_page_button=Нова сторінка wiki.new_page_button=Нова сторінка
wiki.delete_page_button=Видалити сторінку wiki.delete_page_button=Видалити сторінку
wiki.delete_page_notice_1=Видалення сторінки вікі '%s' не може бути скасовано. Продовжити?
wiki.page_already_exists=Вікі-сторінка з таким самим ім'ям вже існує. wiki.page_already_exists=Вікі-сторінка з таким самим ім'ям вже існує.
wiki.reserved_page=Назва сторінки вікі '%s' зарезервована.
wiki.pages=Сторінки wiki.pages=Сторінки
wiki.last_updated=Останні оновлення %s wiki.last_updated=Останні оновлення %s
@ -832,6 +901,8 @@ activity.new_issues_count_1=Нова Проблема
activity.new_issues_count_n=%d Проблем activity.new_issues_count_n=%d Проблем
activity.new_issue_label=Відкриті activity.new_issue_label=Відкриті
activity.title.unresolved_conv_1=%d Незавершене обговорення activity.title.unresolved_conv_1=%d Незавершене обговорення
activity.title.unresolved_conv_n=%d Незавершених обговорень
activity.unresolved_conv_desc=Список всіх старих тікетів і Pull Request'ів з недавньої активністю, але ще не закритих або прийнятих.
activity.unresolved_conv_label=Відкрити activity.unresolved_conv_label=Відкрити
activity.title.releases_1=%d Реліз activity.title.releases_1=%d Реліз
activity.title.releases_n=%d Релізів activity.title.releases_n=%d Релізів
@ -840,8 +911,10 @@ activity.published_release_label=Опубліковано
search=Пошук search=Пошук
search.search_repo=Пошук репозиторію search.search_repo=Пошук репозиторію
search.results=Результати пошуку для "%s" в <a href="%s">%s</a>
settings=Налаштування settings=Налаштування
settings.desc=У налаштуваннях ви можете змінювати різні параметри цього репозиторія
settings.options=Репозиторій settings.options=Репозиторій
settings.collaboration=Співавтори settings.collaboration=Співавтори
settings.collaboration.admin=Адміністратор settings.collaboration.admin=Адміністратор
@ -853,6 +926,7 @@ settings.githooks=Git хуки
settings.basic_settings=Базові налаштування settings.basic_settings=Базові налаштування
settings.mirror_settings=Налаштування дзеркала settings.mirror_settings=Налаштування дзеркала
settings.sync_mirror=Синхронізувати зараз settings.sync_mirror=Синхронізувати зараз
settings.mirror_sync_in_progress=Синхронізуються репозиторії-дзеркала. Зачекайте хвилину і обновіть сторінку.
settings.site=Веб-сайт settings.site=Веб-сайт
settings.update_settings=Оновити налаштування settings.update_settings=Оновити налаштування
settings.advanced_settings=Додаткові налаштування settings.advanced_settings=Додаткові налаштування
@ -860,15 +934,24 @@ settings.wiki_desc=Увімкнути репозиторії Вікі
settings.use_internal_wiki=Використовувати вбудовані Вікі settings.use_internal_wiki=Використовувати вбудовані Вікі
settings.use_external_wiki=Використовувати зовнішні Вікі settings.use_external_wiki=Використовувати зовнішні Вікі
settings.external_wiki_url=URL зовнішньої вікі settings.external_wiki_url=URL зовнішньої вікі
settings.external_wiki_url_error=Зовнішня URL-адреса wiki не є допустимою URL-адресою.
settings.external_wiki_url_desc=Відвідувачі будуть перенаправлені на URL-адресу, коли вони клацають по вкладці.
settings.issues_desc=Увімкнути відстеження проблем в репозиторію settings.issues_desc=Увімкнути відстеження проблем в репозиторію
settings.use_internal_issue_tracker=Використовувати вбудовану систему відстеження проблем settings.use_internal_issue_tracker=Використовувати вбудовану систему відстеження проблем
settings.use_external_issue_tracker=Використовувати зовнішню систему обліку завдань
settings.external_tracker_url=URL зовнішньої системи відстеження проблем settings.external_tracker_url=URL зовнішньої системи відстеження проблем
settings.external_tracker_url_error=URL зовнішнього баг-трекера не є допустимою URL-адресою.
settings.external_tracker_url_desc=Відвідувачі перенаправляються на зовнішню URL-адресу, коли натискають вкладку 'Проблеми'.
settings.tracker_url_format=Формат URL зовнішнього трекера задач settings.tracker_url_format=Формат URL зовнішнього трекера задач
settings.tracker_issue_style=Формат номеру для зовнішньої системи обліку задач
settings.tracker_issue_style.numeric=Цифровий settings.tracker_issue_style.numeric=Цифровий
settings.tracker_issue_style.alphanumeric=Буквено-цифровий settings.tracker_issue_style.alphanumeric=Буквено-цифровий
settings.tracker_url_format_desc=Використовуйте шаблони <code>{user}</code>, <code>{repo}</code> та <code>{index}</code> для імені користувача, репозиторію та номеру задічі.
settings.enable_timetracker=Увімкнути відстеження часу settings.enable_timetracker=Увімкнути відстеження часу
settings.allow_only_contributors_to_track_time=Враховувати тільки учасників розробки в підрахунку часу
settings.pulls_desc=Увімкнути запити на злиття в репозиторій settings.pulls_desc=Увімкнути запити на злиття в репозиторій
settings.pulls.ignore_whitespace=Ігнорувати пробіл у конфліктах settings.pulls.ignore_whitespace=Ігнорувати пробіл у конфліктах
settings.pulls.allow_merge_commits=Дозволити коміти злиття
settings.pulls.allow_rebase_merge=Увімкнути Rebasing коміти перед злиттям settings.pulls.allow_rebase_merge=Увімкнути Rebasing коміти перед злиттям
settings.pulls.allow_squash_commits=Увімкнути об'єднувати коміти перед злиттям settings.pulls.allow_squash_commits=Увімкнути об'єднувати коміти перед злиттям
settings.admin_settings=Налаштування адміністратора settings.admin_settings=Налаштування адміністратора
@ -877,36 +960,60 @@ settings.danger_zone=Небезпечна зона
settings.new_owner_has_same_repo=Новий власник вже має репозиторій з такою назвою. Будь ласка, виберіть інше ім'я. settings.new_owner_has_same_repo=Новий власник вже має репозиторій з такою назвою. Будь ласка, виберіть інше ім'я.
settings.convert=Перетворити на звичайний репозиторій settings.convert=Перетворити на звичайний репозиторій
settings.convert_desc=Ви можете сконвертувати це дзеркало у звичайний репозиторій. Це не може бути скасовано. settings.convert_desc=Ви можете сконвертувати це дзеркало у звичайний репозиторій. Це не може бути скасовано.
settings.convert_notices_1=Ця операція перетворить дзеркало у звичайний репозиторій і не може бути скасована.
settings.convert_confirm=Перетворити репозиторій settings.convert_confirm=Перетворити репозиторій
settings.convert_succeed=Репозиторій успішно перетворений в звичайний.
settings.transfer=Передати новому власнику settings.transfer=Передати новому власнику
settings.transfer_desc=Передати репозиторій користувачеві або організації, де ви маєте права адміністратора.
settings.transfer_notices_1=- Ви втратите доступ до репозиторія, якщо ви переведете його окремому користувачеві.
settings.transfer_notices_2=- Ви збережете доступ, якщо новим власником стане організація, власником якої ви є.
settings.transfer_form_title=Введіть ім'я репозиторія як підтвердження: settings.transfer_form_title=Введіть ім'я репозиторія як підтвердження:
settings.wiki_delete=Видалити вікі-дані settings.wiki_delete=Видалити вікі-дані
settings.wiki_delete_desc=Будьте уважні! Як тільки ви видалите Вікі - шляху назад не буде.
settings.wiki_delete_notices_1=- Це назавжди знищить і відключить wiki для %s.
settings.confirm_wiki_delete=Видалити Вікі-дані settings.confirm_wiki_delete=Видалити Вікі-дані
settings.wiki_deletion_success=Дані wiki були видалені.
settings.delete=Видалити цей репозиторій settings.delete=Видалити цей репозиторій
settings.delete_desc=Будьте уважні! Як тільки ви видалите репозиторій - шляху назад не буде.
settings.delete_notices_1=- Цю операцію <strong>НЕ МОЖНА</strong> відмінити. settings.delete_notices_1=- Цю операцію <strong>НЕ МОЖНА</strong> відмінити.
settings.delete_notices_2=- Ця операція назавжди видалить все з репозиторію <strong>%s</strong>, включаючи дані Git, пов'язані з ним завдання, коментарі і права доступу для співробітників.
settings.delete_notices_fork_1=- Всі форки стануть незалежними репозиторіями після видалення.
settings.deletion_success=Репозиторій успішно видалено. settings.deletion_success=Репозиторій успішно видалено.
settings.update_settings_success=Налаштування репозиторію було оновлено. settings.update_settings_success=Налаштування репозиторію було оновлено.
settings.transfer_owner=Новий власник settings.transfer_owner=Новий власник
settings.make_transfer=Здіснити перенесення settings.make_transfer=Здіснити перенесення
settings.transfer_succeed=Репозиторій був перенесений.
settings.confirm_delete=Видалити репозиторій settings.confirm_delete=Видалити репозиторій
settings.add_collaborator=Додати співавтора settings.add_collaborator=Додати співавтора
settings.add_collaborator_success=Додано співавтора. settings.add_collaborator_success=Додано співавтора.
settings.delete_collaborator=Видалити settings.delete_collaborator=Видалити
settings.collaborator_deletion=Видалити співавтора settings.collaborator_deletion=Видалити співавтора
settings.collaborator_deletion_desc=Цей користувач більше не матиме доступу для спільної роботи в цьому репозиторії після видалення. Ви хочете продовжити?
settings.remove_collaborator_success=Співавтор видалений.
settings.search_user_placeholder=Пошук користувача… settings.search_user_placeholder=Пошук користувача…
settings.org_not_allowed_to_be_collaborator=Організації не можуть бути додані як співавтори.
settings.user_is_org_member=Користувач є учасником організації, учасники якої не можуть бути додані в якості співавтора.
settings.add_webhook=Додати веб-хук settings.add_webhook=Додати веб-хук
settings.hooks_desc=Веб-хуки автоматично робить HTTP POST-запити на сервер, коли відбуваються певні події Gitea. Дізнайтеся більше в <a target="_blank" rel="noopener" href="%s"> інструкції по використанню web-хуків </a>.
settings.webhook_deletion=Видалити веб-хук settings.webhook_deletion=Видалити веб-хук
settings.webhook_deletion_desc=Видалення цього веб-хука призведе до видалення всієї пов'язаної з ним інформації, включаючи історію. Бажаєте продовжити?
settings.webhook_deletion_success=Webhook видалено.
settings.webhook.test_delivery=Перевірити доставку settings.webhook.test_delivery=Перевірити доставку
settings.webhook.test_delivery_desc=Перевірте цей веб-хук з підробленою подією. settings.webhook.test_delivery_desc=Перевірте цей веб-хук з підробленою подією.
settings.webhook.test_delivery_success=Тест веб-хука був доданий в чергу доставки. Це може зайняти кілька секунд, перш ніж він відобразиться в історії доставки.
settings.webhook.request=Запит settings.webhook.request=Запит
settings.webhook.response=Відповідь settings.webhook.response=Відповідь
settings.webhook.headers=Заголовки settings.webhook.headers=Заголовки
settings.webhook.payload=Зміст settings.webhook.payload=Зміст
settings.webhook.body=Тіло settings.webhook.body=Тіло
settings.githooks_desc=Git-хукі надаються Git самим по собі, ви можете змінювати файли підтримуваних хуков зі списку нижче щоб виконувати зовнішні операції.
settings.githook_edit_desc=Якщо хук неактивний, буде представлено зразок вмісту. Порожнє значення у цьому полі призведе до вимкнення хуку.
settings.githook_name=Ім'я хуку settings.githook_name=Ім'я хуку
settings.githook_content=Зміст хука settings.githook_content=Зміст хука
settings.update_githook=Оновити хук settings.update_githook=Оновити хук
settings.add_webhook_desc=Gitea буде відправляти <code>POST</code> запити на вказану URL адресу, з інформацією про події, що відбуваються. Подробиці на сторінці <a target="_blank" rel="noopener" href="%s"> інструкції по використанню web-хуків </a>.
settings.payload_url=Цільова URL-адреса settings.payload_url=Цільова URL-адреса
settings.content_type=Тип вмісту
settings.secret=Секрет settings.secret=Секрет
settings.slack_username=Ім'я кристувача settings.slack_username=Ім'я кристувача
settings.slack_icon_url=URL іконки settings.slack_icon_url=URL іконки
@ -928,6 +1035,7 @@ settings.event_issues_desc=Проблему відкрито, закрито, п
settings.event_issue_comment=Коментар проблеми settings.event_issue_comment=Коментар проблеми
settings.event_issue_comment_desc=Коментар проблеми створено, видалено чи відредаговано. settings.event_issue_comment_desc=Коментар проблеми створено, видалено чи відредаговано.
settings.event_release=Реліз settings.event_release=Реліз
settings.event_release_desc=Реліз опублікований, оновлений або видалений з репозиторія.
settings.event_pull_request=Запити до злиття settings.event_pull_request=Запити до злиття
settings.event_pull_request_desc=Запит до злиття відкрито, закрито, перевідкрито, змінено, призначено, знято, мітку оновлено, мітку прибрано або синхронізовано. settings.event_pull_request_desc=Запит до злиття відкрито, закрито, перевідкрито, змінено, призначено, знято, мітку оновлено, мітку прибрано або синхронізовано.
settings.event_push=Push settings.event_push=Push
@ -935,6 +1043,7 @@ settings.event_push_desc=Git push до репозиторію.
settings.event_repository=Репозиторій settings.event_repository=Репозиторій
settings.event_repository_desc=Репозиторій створений або видалено. settings.event_repository_desc=Репозиторій створений або видалено.
settings.active=Додавати інформацію про події settings.active=Додавати інформацію про події
settings.active_helper=Також буде відправлена ​​інформація про подію, що відбулася.
settings.add_hook_success=Веб-хук було додано. settings.add_hook_success=Веб-хук було додано.
settings.update_webhook=Оновити веб-хук settings.update_webhook=Оновити веб-хук
settings.update_hook_success=Веб-хук було оновлено. settings.update_hook_success=Веб-хук було оновлено.
@ -949,27 +1058,50 @@ settings.add_discord_hook_desc=Інтеграція <a href="%s">Discord</a> у
settings.add_dingtalk_hook_desc=Інтеграція <a href="%s">Dingtalk</a> у ваш репозиторії. settings.add_dingtalk_hook_desc=Інтеграція <a href="%s">Dingtalk</a> у ваш репозиторії.
settings.deploy_keys=Ключі для розгортування settings.deploy_keys=Ключі для розгортування
settings.add_deploy_key=Додати ключ для розгортування settings.add_deploy_key=Додати ключ для розгортування
settings.deploy_key_desc=Ключі розгортання доступні тільки для читання. Це не те ж саме що і SSH-ключі аккаунта.
settings.is_writable=Увімкнути доступ для запису settings.is_writable=Увімкнути доступ для запису
settings.is_writable_info=Чи може цей ключ бути використаний для виконання <strong>push</strong> в репозиторій? Ключі розгортання завжди мають доступ на pull.
settings.no_deploy_keys=Ви не додавали ключі розгортання.
settings.title=Заголовок settings.title=Заголовок
settings.deploy_key_content=Зміст settings.deploy_key_content=Зміст
settings.key_been_used=Вміст ключа розгортання вже використовується.
settings.key_name_used=Ключ розгортання з таким заголовком вже існує.
settings.add_key_success=Новий ключ розгортання '%s' успішно доданий.
settings.deploy_key_deletion=Видалити ключ для розгортування settings.deploy_key_deletion=Видалити ключ для розгортування
settings.deploy_key_deletion_desc=Видалення ключа розгортки унеможливить доступ до репозиторія з його допомогою. Ви впевнені?
settings.deploy_key_deletion_success=Ключі розгортання було видалено. settings.deploy_key_deletion_success=Ключі розгортання було видалено.
settings.branches=Гілки settings.branches=Гілки
settings.protected_branch=Захист гілки settings.protected_branch=Захист гілки
settings.protected_branch_can_push=Дозволити push? settings.protected_branch_can_push=Дозволити push?
settings.protected_branch_can_push_yes=Ви можете виконувати push settings.protected_branch_can_push_yes=Ви можете виконувати push
settings.protected_branch_can_push_no=Ви не можете виконувати push settings.protected_branch_can_push_no=Ви не можете виконувати push
settings.branch_protection=Захист гілки <b>%s</b>
settings.protect_this_branch=Захистити цю гілку
settings.protect_this_branch_desc=Вимкнути примусовий push і захистити від видалення.
settings.protect_whitelist_committers=Білий список тих, хто може робити push в цю гілку
settings.protect_whitelist_committers_desc=Додати користувачів або команди в білий список гілки. На них не будуть поширюватися звичайні обмеження на push.
settings.protect_whitelist_users=Користувачі, які можуть робити push в цю гілку:
settings.protect_whitelist_search_users=Пошук користувачів… settings.protect_whitelist_search_users=Пошук користувачів…
settings.protect_whitelist_teams=Команди, учасники яких можуть робити push в цю гілку:
settings.protect_whitelist_search_teams=Пошук команд… settings.protect_whitelist_search_teams=Пошук команд…
settings.protect_merge_whitelist_committers=Обмежити право на прийняття Pull Request'ів в цю гілку списком
settings.protect_merge_whitelist_committers_desc=Ви можете додавати користувачів або цілі команди в 'білий' список цієї гілки. Тільки присутні в списку зможуть приймати запити на злиття. В іншому випадку будь-хто з правами запису до головного репозиторію буде володіти такою можливістю.
settings.protect_merge_whitelist_users=Користувачі з правом на прийняття Pull Request'ів в цю гілку:
settings.protect_merge_whitelist_teams=Команди, яким дозволено злиття:
settings.add_protected_branch=Увімкнути захист settings.add_protected_branch=Увімкнути захист
settings.delete_protected_branch=Вимкнути захист settings.delete_protected_branch=Вимкнути захист
settings.update_protect_branch_success=Налаштування захисту гілки '%s' були успішно змінені.
settings.remove_protected_branch_success=Захист гілки '%s' був успішно відключений.
settings.protected_branch_deletion=Відключити захист гілки settings.protected_branch_deletion=Відключити захист гілки
settings.protected_branch_deletion_desc=Будь-який користувач з дозволами на запис зможе виконувати push в цю гілку. Ви впевнені?
settings.default_branch_desc=Головна гілка є 'базовою' для вашого репозиторія, на яку за замовчуванням спрямовані всі запити на злиття і яка є обличчям вашого репозиторія. Перше, що побачить відвідувач - це зміст головної гілки. Виберіть її з уже існуючих:
settings.choose_branch=Оберіть гілку… settings.choose_branch=Оберіть гілку…
settings.no_protected_branch=Немає захищених гілок. settings.no_protected_branch=Немає захищених гілок.
diff.browse_source=Переглянути джерело diff.browse_source=Переглянути джерело
diff.parent=джерело diff.parent=джерело
diff.commit=коміт diff.commit=коміт
diff.data_not_available=Різниця недоступна
diff.show_diff_stats=Показати статистику Diff diff.show_diff_stats=Показати статистику Diff
diff.show_split_view=Розділений перегляд diff.show_split_view=Розділений перегляд
diff.show_unified_view=Об'єднаний перегляд diff.show_unified_view=Об'єднаний перегляд
@ -979,6 +1111,7 @@ diff.view_file=Переглянути файл
diff.file_suppressed=Різницю між файлами не показано, бо вона завелика diff.file_suppressed=Різницю між файлами не показано, бо вона завелика
diff.too_many_files=Деякі файли не було показано, через те що забагато файлів було змінено diff.too_many_files=Деякі файли не було показано, через те що забагато файлів було змінено
releases.desc=Відслідковувати версії проекту (релізи) та завантаження.
release.releases=Релізи release.releases=Релізи
release.new_release=Новий реліз release.new_release=Новий реліз
release.draft=Чернетка release.draft=Чернетка
@ -987,6 +1120,8 @@ release.stable=Стабільний
release.edit=редагувати release.edit=редагувати
release.ahead=<strong>%d</strong> комітів %s після цього релізу release.ahead=<strong>%d</strong> комітів %s після цього релізу
release.source_code=Код release.source_code=Код
release.new_subheader=Публікація релізів допоможе зберігати чітку історію розвитку вашого проекту.
release.edit_subheader=Публікація релізів допоможе зберігати чітку історію розвитку вашого проекту.
release.tag_name=Назва тегу release.tag_name=Назва тегу
release.target=Ціль release.target=Ціль
release.tag_helper=Виберіть існуючий тег або створіть новий. release.tag_helper=Виберіть існуючий тег або створіть новий.
@ -1003,25 +1138,37 @@ release.save_draft=Зберегти чернетку
release.edit_release=Оновити реліз release.edit_release=Оновити реліз
release.delete_release=Видалити реліз release.delete_release=Видалити реліз
release.deletion=Видалити реліз release.deletion=Видалити реліз
release.deletion_desc=Видалення релізу видаляє Git-тег з репозиторіїв. Зміст репозиторія і історія залишаться незмінними. Продовжити?
release.deletion_success=Реліз, було видалено. release.deletion_success=Реліз, було видалено.
release.tag_name_already_exist=Реліз з цим ім'ям мітки вже існує.
release.tag_name_invalid=Неприпустиме ім'я тега. release.tag_name_invalid=Неприпустиме ім'я тега.
release.downloads=Завантажити release.downloads=Завантажити
branch.name=Ім'я гілки branch.name=Ім'я гілки
branch.search=Пошук гілок branch.search=Пошук гілок
branch.already_exists=Гілка з ім'ям '%s' вже існує.
branch.delete_head=Видалити branch.delete_head=Видалити
branch.delete=Видалити гілку '%s' branch.delete=Видалити гілку '%s'
branch.delete_html=Видалити гілку branch.delete_html=Видалити гілку
branch.delete_desc=Видалення гілки <strong>НЕЗВОРОТНЕ</strong>. Дію не можна скасувати. Продовжити?
branch.deletion_success=Гілка '%s' видалена. branch.deletion_success=Гілка '%s' видалена.
branch.deletion_failed=Не вдалося видалити гілку "%s". branch.deletion_failed=Не вдалося видалити гілку "%s".
branch.delete_branch_has_new_commits=Гілку '%s' не можна видалити, оскільки після злиття були додані нові коміти.
branch.create_branch=Створити гілку <strong>%s</strong>
branch.create_from=з '%s' branch.create_from=з '%s'
branch.create_success=Створено гілку "%s". branch.create_success=Створено гілку "%s".
branch.branch_already_exists=Гілка '%s' вже присутня в репозиторії. branch.branch_already_exists=Гілка '%s' вже присутня в репозиторії.
branch.branch_name_conflict=Ім'я гілки '%s' конфліктує з уже існуючою гілкою '%s'.
branch.tag_collision=Гілка '%s' не може бути створена, так як вже існує тег з таким ім'ям.
branch.deleted_by=Видалено %s branch.deleted_by=Видалено %s
branch.restore_success=Гілку "%s" відновлено. branch.restore_success=Гілку "%s" відновлено.
branch.restore_failed=Не вдалося відновити гілку '%s'.
branch.protected_deletion_failed=Гілка '%s' захищена. Її не можна видалити.
topic.manage_topics=Керувати тематичними мітками topic.manage_topics=Керувати тематичними мітками
topic.done=Готово topic.done=Готово
topic.count_prompt=Ви не можете вибрати більше 25 тем
topic.format_prompt=Теми мають починатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів
[org] [org]
org_name_holder=Назва організації org_name_holder=Назва організації
@ -1044,6 +1191,8 @@ team_permission_desc=Права доступу
team_unit_desc=Дозволити доступ до розділів репозиторію team_unit_desc=Дозволити доступ до розділів репозиторію
form.name_reserved=Назву організації '%s' зарезервовано. form.name_reserved=Назву організації '%s' зарезервовано.
form.name_pattern_not_allowed=Шаблон '%s' не дозволено в назві організації.
form.create_org_not_allowed=Вам не дозволено створювати організації.
settings=Налаштування settings=Налаштування
settings.options=Організація settings.options=Організація
@ -1056,8 +1205,11 @@ settings.change_orgname_prompt=Ця зміна змінить посилання
settings.update_avatar_success=Аватар організації оновлений. settings.update_avatar_success=Аватар організації оновлений.
settings.delete=Видалити організацію settings.delete=Видалити організацію
settings.delete_account=Видалити цю організацію settings.delete_account=Видалити цю організацію
settings.delete_prompt=Організація буде остаточно видалена. Це <strong>НЕ МОЖЛИВО</strong> відмінити!
settings.confirm_delete_account=Підтвердіть видалення settings.confirm_delete_account=Підтвердіть видалення
settings.delete_org_title=Видалити організацію settings.delete_org_title=Видалити організацію
settings.delete_org_desc=Ця організація буде безповоротно видалена. Продовжити?
settings.hooks_desc=Додайте webhooks, який буде викликатися для <strong>всіх репозиторіїв</strong> якими володіє ця організація.
members.membership_visibility=Видимість учасника: members.membership_visibility=Видимість учасника:
members.public=Показувати members.public=Показувати
@ -1075,8 +1227,11 @@ members.invite_now=Запросити зараз
teams.join=Приєднатися teams.join=Приєднатися
teams.leave=Покинути teams.leave=Покинути
teams.read_access=Доступ для читання teams.read_access=Доступ для читання
teams.read_access_helper=Учасники можуть переглядати та клонувати репозиторії команд.
teams.write_access=Доступ на запис teams.write_access=Доступ на запис
teams.write_access_helper=Учасники можуть читати і виконувати push в репозиторії команд.
teams.admin_access=Доступ адміністратора teams.admin_access=Доступ адміністратора
teams.admin_access_helper=Учасники можуть виконувати pull, push в репозиторії команд і додавати співавторів в команду.
teams.no_desc=Ця команда не має опису teams.no_desc=Ця команда не має опису
teams.settings=Налаштування teams.settings=Налаштування
teams.owners_permission_desc=Власник має повний доступ до <strong>усіх репозиторіїв</strong> та має <strong>права адміністратора</strong> організації. teams.owners_permission_desc=Власник має повний доступ до <strong>усіх репозиторіїв</strong> та має <strong>права адміністратора</strong> організації.
@ -1085,6 +1240,7 @@ teams.update_settings=Оновити налаштування
teams.delete_team=Видалити команду teams.delete_team=Видалити команду
teams.add_team_member=Додати учасника команди teams.add_team_member=Додати учасника команди
teams.delete_team_title=Видалити команду teams.delete_team_title=Видалити команду
teams.delete_team_desc=Видалення команди скасовує доступ до репозиторія для її учасників. Продовжити?
teams.delete_team_success=Команду було видалено. teams.delete_team_success=Команду було видалено.
teams.read_permission_desc=Ця команда має доступ для <strong>читання</strong>: учасники можуть переглядати та клонувати репозиторії. teams.read_permission_desc=Ця команда має доступ для <strong>читання</strong>: учасники можуть переглядати та клонувати репозиторії.
teams.write_permission_desc=Ця команда надає доступ на <strong>запис</strong>: учасники можуть отримувати й виконувати push команди до репозитрію. teams.write_permission_desc=Ця команда надає доступ на <strong>запис</strong>: учасники можуть отримувати й виконувати push команди до репозитрію.
@ -1111,13 +1267,30 @@ total=Разом: %d
dashboard.statistic=Підсумок dashboard.statistic=Підсумок
dashboard.operations=Технічне обслуговування dashboard.operations=Технічне обслуговування
dashboard.system_status=Статус системи dashboard.system_status=Статус системи
dashboard.statistic_info=У базі даних Gitea записано <b>%d</b> користувачів, <b>%d</b> організацій, <b>%d</b> публічних ключів, <b>%d</b> репозиторіїв, <b>%d</b> підписок на репозиторії, <b>%d</b> додавань в обране, <b>%d</b> дій, <b>%d</b> доступів, <b>%d</b> задач, <b>%d</b> коментарів, <b>%d</b> соціальних облікових записів, <b>%d</b> підписок на користувачів, <b>%d</b> зеркал, <b>%d</b> релізів, <b>%d</b> джерел входу, <b>%d</b> веб-хуків, <b>%d</b> етапів, <b>%d</b> міток, <b>%d</b> задач хуків, <b>%d</b> команд, <b>%d</b> задач по оновленню, <b>%d</b> приєднаних файлів.
dashboard.operation_name=Назва операції dashboard.operation_name=Назва операції
dashboard.operation_switch=Перемкнути dashboard.operation_switch=Перемкнути
dashboard.operation_run=Запустити dashboard.operation_run=Запустити
dashboard.delete_inactivate_accounts=Видалити всі неактивні облікові записи dashboard.clean_unbind_oauth=Очистити список незавершених авторизацій OAuth
dashboard.delete_inactivate_accounts_success=Усі неактивні облікові записи успішно видалено. dashboard.clean_unbind_oauth_success=Всі незавершені зв'язки OAuth були видалені.
dashboard.delete_inactivate_accounts=Видалити всі неактивовані облікові записи
dashboard.delete_inactivate_accounts_success=Усі неактивовані облікові записи успішно видалено.
dashboard.delete_repo_archives=Видалити всі архіви репозиторіїв dashboard.delete_repo_archives=Видалити всі архіви репозиторіїв
dashboard.delete_repo_archives_success=Всі архіви репозиторіїв були видалені.
dashboard.delete_missing_repos=Видалити всі записи про репозиторії з відсутніми файлами Git
dashboard.delete_missing_repos_success=Всі записи про репозиторії з відсутніми файлами Git видалені.
dashboard.git_gc_repos=Виконати очистку сміття для всіх репозиторіїв
dashboard.git_gc_repos_success=Всі репозиторії завершили збирання сміття. dashboard.git_gc_repos_success=Всі репозиторії завершили збирання сміття.
dashboard.resync_all_sshkeys=Перезаписати файл '.ssh/authorized_keys' для SSH ключів Gitea. (Не потрібно для вбудованого SSH сервера.)
dashboard.resync_all_sshkeys_success=Всі відкриті ключі були перезаписані.
dashboard.resync_all_hooks=Пересинхронізувати перед-прийнятні, оновлюючі та пост-прийнятні хуки в усіх репозиторіях.
dashboard.resync_all_hooks_success=Були пересинхронізовані всі pre-receive, update і post-receive Git хуки.
dashboard.reinit_missing_repos=Переініціалізувати усі репозитрії git-файли яких втрачено
dashboard.reinit_missing_repos_success=Усі репозитрії git-файли яких втрачено, успішно переініціалізовано.
dashboard.sync_external_users=Синхронізувати дані зовнішніх користувачів
dashboard.sync_external_users_started=Запущена синхронізація зовнішніх користувачів.
dashboard.git_fsck=Запустити перевірку даних всіх репозиторіїв (git fsck)
dashboard.git_fsck_started=Перевірка даних репозиторіїв запущена.
dashboard.server_uptime=Uptime серверу dashboard.server_uptime=Uptime серверу
dashboard.current_goroutine=Поточна кількість Goroutines dashboard.current_goroutine=Поточна кількість Goroutines
dashboard.current_memory_usage=Поточне використання пам'яті dashboard.current_memory_usage=Поточне використання пам'яті
@ -1125,6 +1298,7 @@ dashboard.total_memory_allocated=Виділено пам'яті загалом
dashboard.memory_obtained=Отримано пам'яті dashboard.memory_obtained=Отримано пам'яті
dashboard.pointer_lookup_times=Пошуків вказівника dashboard.pointer_lookup_times=Пошуків вказівника
dashboard.memory_allocate_times=Виділення пам'яті dashboard.memory_allocate_times=Виділення пам'яті
dashboard.memory_free_times=Звільнень пам'яті
dashboard.current_heap_usage=Поточне використання динамічної пам'яті dashboard.current_heap_usage=Поточне використання динамічної пам'яті
dashboard.heap_memory_obtained=Отримано динамічної пам'яті dashboard.heap_memory_obtained=Отримано динамічної пам'яті
dashboard.heap_memory_idle=Не використовується динамічною пам'яттю dashboard.heap_memory_idle=Не використовується динамічною пам'яттю
@ -1161,6 +1335,8 @@ users.new_success=Обліковий запис '%s' створений.
users.edit=Редагувати users.edit=Редагувати
users.auth_source=Джерело автентифікації users.auth_source=Джерело автентифікації
users.local=Локальні users.local=Локальні
users.auth_login_name=Логін для авторизації
users.password_helper=Залиште пароль порожнім, щоб не змінювати його.
users.update_profile_success=Обліковий запис користувача було оновлено. users.update_profile_success=Обліковий запис користувача було оновлено.
users.edit_account=Редагувати обліковий запис users.edit_account=Редагувати обліковий запис
users.max_repo_creation=Максимальна кількість репозиторіїв users.max_repo_creation=Максимальна кількість репозиторіїв
@ -1173,6 +1349,8 @@ users.allow_import_local=Може імпортувати локальні реп
users.allow_create_organization=Може створювати організацій users.allow_create_organization=Може створювати організацій
users.update_profile=Оновити обліковий запис users.update_profile=Оновити обліковий запис
users.delete_account=Видалити цей обліковий запис users.delete_account=Видалити цей обліковий запис
users.still_own_repo=Ваш обліковий запис все ще володіє одним або кількома репозиторіями, спочатку вам потрібно видалити або передати їх.
users.still_has_org=Цей обліковий запис все ще є учасником однієї або декількох організацій. Для продовження, покиньте або видаліть організації.
users.deletion_success=Обліковий запис користувача було видалено. users.deletion_success=Обліковий запис користувача було видалено.
orgs.org_manage_panel=Керування організаціями orgs.org_manage_panel=Керування організаціями
@ -1206,22 +1384,34 @@ auths.host=Хост
auths.port=Порт auths.port=Порт
auths.bind_dn=Прив'язати DN auths.bind_dn=Прив'язати DN
auths.bind_password=Прив'язати пароль auths.bind_password=Прив'язати пароль
auths.bind_password_helper=Попередження: цей пароль зберігається у вигляді простого тексту. Використовуйте обліковий запис тільки для читання, якщо це можливо.
auths.user_base=База пошуку користувачів auths.user_base=База пошуку користувачів
auths.user_dn=DN користувача auths.user_dn=DN користувача
auths.attribute_username=Атрибут імені користувача auths.attribute_username=Атрибут імені користувача
auths.attribute_username_placeholder=Залиште порожнім, щоб використовувати ім'я користувача для реєстрації.
auths.attribute_name=Атрибут імені
auths.attribute_surname=Атрибут Surname
auths.attribute_mail=Атрибут Email
auths.attribute_ssh_public_key=Атрибут Відкритий SSH ключ
auths.attributes_in_bind=Витягувати атрибути в контексті Bind DN
auths.use_paged_search=Використовувати посторінковий пошук
auths.search_page_size=Розмір сторінки auths.search_page_size=Розмір сторінки
auths.filter=Користувацький фільтр auths.filter=Користувацький фільтр
auths.admin_filter=Фільтр адміністратора auths.admin_filter=Фільтр адміністратора
auths.ms_ad_sa=Атрибути пошуку MS AD
auths.smtp_auth=Тип автентифікації SMTP auths.smtp_auth=Тип автентифікації SMTP
auths.smtphost=SMTP хост auths.smtphost=SMTP хост
auths.smtpport=SMTP порт auths.smtpport=SMTP порт
auths.allowed_domains=Дозволені домени auths.allowed_domains=Дозволені домени
auths.allowed_domains_helper=Залиште порожнім, щоб дозволити всі домени. Розділіть кілька доменів за допомогою коми (',').
auths.enable_tls=Увімкнути TLS-шифрування auths.enable_tls=Увімкнути TLS-шифрування
auths.skip_tls_verify=Пропустити перевірку TLS auths.skip_tls_verify=Пропустити перевірку TLS
auths.pam_service_name=Ім'я служби PAM auths.pam_service_name=Ім'я служби PAM
auths.oauth2_provider=Постачальник OAuth2 auths.oauth2_provider=Постачальник OAuth2
auths.oauth2_clientID=ID клієнта (ключ) auths.oauth2_clientID=ID клієнта (ключ)
auths.oauth2_clientSecret=Ключ клієнта auths.oauth2_clientSecret=Ключ клієнта
auths.openIdConnectAutoDiscoveryURL=OpenID Connect URL для автоматизації входу
auths.oauth2_use_custom_url=Використовувати для користувача URL замість URL за замовчуванням
auths.oauth2_tokenURL=URL токену auths.oauth2_tokenURL=URL токену
auths.oauth2_authURL=URL авторизації auths.oauth2_authURL=URL авторизації
auths.oauth2_profileURL=URL профілю auths.oauth2_profileURL=URL профілю
@ -1231,15 +1421,25 @@ auths.tips=Поради
auths.tips.oauth2.general=OAuth2 автентифікація auths.tips.oauth2.general=OAuth2 автентифікація
auths.tips.oauth2.general.tip=При додаванні нового OAuth2 провайдера, URL адреса переадресації по завершенні автентифікації повинена виглядати так:<host>/user/oauth2/<Authentication Name>/callback auths.tips.oauth2.general.tip=При додаванні нового OAuth2 провайдера, URL адреса переадресації по завершенні автентифікації повинена виглядати так:<host>/user/oauth2/<Authentication Name>/callback
auths.tip.oauth2_provider=Постачальник OAuth2 auths.tip.oauth2_provider=Постачальник OAuth2
auths.tip.bitbucket=Створіть OAuth URI на сторінці https://bitbucket.org/account/user/<your username>/oauth-consumers/new і додайте права 'Account' - 'Read'
auths.tip.dropbox=Додайте новий додаток на https://www.dropbox.com/developers/apps auths.tip.dropbox=Додайте новий додаток на https://www.dropbox.com/developers/apps
auths.tip.facebook=Створіть новий додаток на https://developers.facebook.com/apps і додайте модуль "Facebook Login auths.tip.facebook=Створіть новий додаток на https://developers.facebook.com/apps і додайте модуль "Facebook Login
auths.tip.github=Додайте OAuth додаток на https://github.com/settings/applications/new auths.tip.github=Додайте OAuth додаток на https://github.com/settings/applications/new
auths.tip.gitlab=Додайте новий додаток на https://gitlab.com/profile/applications auths.tip.gitlab=Додайте новий додаток на https://gitlab.com/profile/applications
auths.tip.google_plus=Отримайте облікові дані клієнта OAuth2 в консолі Google API на сторінці https://console.developers.google.com/
auths.tip.openid_connect=Використовуйте OpenID Connect Discovery URL (<server>/.well-known/openid-configuration) для автоматичної настройки входу OAuth auths.tip.openid_connect=Використовуйте OpenID Connect Discovery URL (<server>/.well-known/openid-configuration) для автоматичної настройки входу OAuth
auths.tip.twitter=Перейдіть на https://dev.twitter.com/apps, створіть програму і переконайтеся, що включена опція «Дозволити цю програму для входу в систему за допомогою Twitter»
auths.edit=Редагувати джерело автентифікації auths.edit=Редагувати джерело автентифікації
auths.activated=Ця аутентифікація активована
auths.new_success=Метод аутентифікації '%s' був доданий.
auths.update_success=Параметри аутентифікації оновлені.
auths.update=Оновити джерело автентифікації auths.update=Оновити джерело автентифікації
auths.delete=Видалити джерело автентифікації auths.delete=Видалити джерело автентифікації
auths.delete_auth_title=Видалити джерело автентифікації auths.delete_auth_title=Видалити джерело автентифікації
auths.delete_auth_desc=Це джерело аутентифікації буде видалене, ви впевнені, що ви хочете продовжити?
auths.still_in_used=Ця перевірка справжності досі використовується деякими користувачами. Видаліть або змініть для цих користувачів тип входу в систему.
auths.deletion_success=Канал аутентифікації успішно знищений.
auths.login_source_exist=Джерело входу '%s' вже існує.
config.server_config=Конфігурація сервера config.server_config=Конфігурація сервера
config.app_name=Назва сайту config.app_name=Назва сайту
@ -1257,6 +1457,7 @@ config.lfs_root_path=Кореневої шлях LFS
config.static_file_root_path=Повний шлях до статичного файлу config.static_file_root_path=Повний шлях до статичного файлу
config.log_file_root_path=Шлях до лог файлу config.log_file_root_path=Шлях до лог файлу
config.script_type=Тип скрипта config.script_type=Тип скрипта
config.reverse_auth_user=Ім'я користувача для авторизації на reverse proxy
config.ssh_config=Конфігурація SSH config.ssh_config=Конфігурація SSH
config.ssh_enabled=Увімкнено config.ssh_enabled=Увімкнено
@ -1281,6 +1482,7 @@ config.db_path=Шлях
config.service_config=Конфігурація сервісу config.service_config=Конфігурація сервісу
config.register_email_confirm=Потрібно підтвердити електронну пошту для реєстрації config.register_email_confirm=Потрібно підтвердити електронну пошту для реєстрації
config.disable_register=Вимкнути самостійну реєстрацію config.disable_register=Вимкнути самостійну реєстрацію
config.allow_only_external_registration=Включити реєстрацію тільки через сторонні сервіси
config.enable_openid_signup=Увімкнути самостійну реєстрацію за допомогою OpenID config.enable_openid_signup=Увімкнути самостійну реєстрацію за допомогою OpenID
config.enable_openid_signin=Увімкнути реєстрацію за допомогою OpenID config.enable_openid_signin=Увімкнути реєстрацію за допомогою OpenID
config.show_registration_button=Показувати кнопку "Реєстрація config.show_registration_button=Показувати кнопку "Реєстрація
@ -1289,10 +1491,12 @@ config.mail_notify=Увімкнути сповіщення електронно
config.disable_key_size_check=Вимкнути перевірку мінімального розміру ключа config.disable_key_size_check=Вимкнути перевірку мінімального розміру ключа
config.enable_captcha=Увімкнути CAPTCHA config.enable_captcha=Увімкнути CAPTCHA
config.active_code_lives=Час актуальності кода підтвердження config.active_code_lives=Час актуальності кода підтвердження
config.reset_password_code_lives=Час життя коду на скидання пароля
config.default_keep_email_private=Приховати адресу електронної пошти за замовчуванням config.default_keep_email_private=Приховати адресу електронної пошти за замовчуванням
config.default_allow_create_organization=Дозволити створення організацій за замовчуванням config.default_allow_create_organization=Дозволити створення організацій за замовчуванням
config.enable_timetracking=Увімкнути відстеження часу config.enable_timetracking=Увімкнути відстеження часу
config.default_enable_timetracking=Увімкнути відстеження часу за замовчуванням config.default_enable_timetracking=Увімкнути відстеження часу за замовчуванням
config.default_allow_only_contributors_to_track_time=Враховувати тільки учасників розробки в підрахунку часу
config.no_reply_address=Прихований домен електронної пошти config.no_reply_address=Прихований домен електронної пошти
config.webhook_config=Конфігурація web-хуків config.webhook_config=Конфігурація web-хуків
@ -1300,6 +1504,7 @@ config.queue_length=Довжина черги
config.deliver_timeout=Затримка доставки config.deliver_timeout=Затримка доставки
config.skip_tls_verify=Пропустити перевірку TLS config.skip_tls_verify=Пропустити перевірку TLS
config.mailer_config=Конфігурація SMTP-сервера
config.mailer_enabled=Увімкнено config.mailer_enabled=Увімкнено
config.mailer_disable_helo=Вимкнути HELO config.mailer_disable_helo=Вимкнути HELO
config.mailer_name=Ім'я config.mailer_name=Ім'я
@ -1307,7 +1512,9 @@ config.mailer_host=Хост
config.mailer_user=Користувач config.mailer_user=Користувач
config.mailer_use_sendmail=Використовувати Sendmail config.mailer_use_sendmail=Використовувати Sendmail
config.mailer_sendmail_path=Шлях до Sendmail config.mailer_sendmail_path=Шлях до Sendmail
config.mailer_sendmail_args=Додаткові аргументи до Sendmail
config.send_test_mail=Відправити тестового листа config.send_test_mail=Відправити тестового листа
config.test_mail_failed=Не вдалося відправити тестовий лист на «%s»: %v
config.test_mail_sent=Тестового листа було відправлено до '%s'. config.test_mail_sent=Тестового листа було відправлено до '%s'.
config.oauth_config=Конфігурація OAuth config.oauth_config=Конфігурація OAuth
@ -1431,8 +1638,14 @@ mark_as_unread=Позначити як непрочитане
mark_all_as_read=Позначити всі як прочитані mark_all_as_read=Позначити всі як прочитані
[gpg] [gpg]
error.extract_sign=Не вдалося витягти підпис
error.generate_hash=Не вдалося згенерувати хеш коміту error.generate_hash=Не вдалося згенерувати хеш коміту
error.no_committer_account=Аккаунт користувача з таким Email не знайдено
error.no_gpg_keys_found=Не вдалося знайти GPG ключ що відповідає даному підпису
error.not_signed_commit=Непідписаний коміт error.not_signed_commit=Непідписаний коміт
error.failed_retrieval_gpg_keys=Не вдалося отримати відповідний GPG ключ користувача
[units] [units]
error.no_unit_allowed_repo=У вас немає доступу до жодного розділу цього репозитория.
error.unit_not_allowed=У вас немає доступу до жодного розділу цього репозитория.

View File

@ -75,7 +75,6 @@ cancel=取消
[install] [install]
install=安装页面 install=安装页面
title=初始配置 title=初始配置
docker_helper=如果您正在使用 Docker 容器运行 Gitea请务必先仔细阅读 <a target="_blank" rel="noopener" href="%s">官方文档</a> 后再对本页面进行填写。
requite_db_desc=Gitea 要求安装 MySQL、PostgreSQL、SQLite3 或 TiDB。 requite_db_desc=Gitea 要求安装 MySQL、PostgreSQL、SQLite3 或 TiDB。
db_title=数据库设置 db_title=数据库设置
db_type=数据库类型 db_type=数据库类型
@ -492,13 +491,8 @@ owner=拥有者
repo_name=仓库名称 repo_name=仓库名称
repo_name_helper=好的存储库名称使用简短、深刻和独特的关键字。 repo_name_helper=好的存储库名称使用简短、深刻和独特的关键字。
visibility=可见性 visibility=可见性
visiblity_helper=将仓库设为私有
visiblity_helper_forced=站点管理员强制要求新仓库为私有。
visiblity_fork_helper=(修改该值将会影响到所有派生仓库)
clone_helper=不知道如何克隆?查看<a target="_blank" rel="noopener" href="%s">帮助</a> 。
fork_repo=派生仓库 fork_repo=派生仓库
fork_from=派生自 fork_from=派生自
fork_visiblity_helper=无法更改派生仓库的可见性。
repo_desc=仓库描述 repo_desc=仓库描述
repo_lang=仓库语言 repo_lang=仓库语言
repo_gitignore_helper=选择 .gitignore 模板。 repo_gitignore_helper=选择 .gitignore 模板。
@ -613,7 +607,6 @@ editor.directory_is_a_file='%s' 已经作为文件名在此仓库中存在。
editor.file_is_a_symlink='%s' 是一个符号链接,无法在线编辑。 editor.file_is_a_symlink='%s' 是一个符号链接,无法在线编辑。
editor.filename_is_a_directory='%s' 已经作为目录名在此仓库中存在。 editor.filename_is_a_directory='%s' 已经作为目录名在此仓库中存在。
editor.file_editing_no_longer_exists=正在编辑的文件 '%s' 已不存在。 editor.file_editing_no_longer_exists=正在编辑的文件 '%s' 已不存在。
editor.file_changed_while_editing=文件内容在您进行编辑时已经发生变动。<a target="_blank" rel="noopener" href="%s">单击此处</a> 查看变动的具体内容,或者 <strong>再次提交</strong> 覆盖已发生的变动。
editor.file_already_exists=此仓库已经存在名为 '%s' 的文件。 editor.file_already_exists=此仓库已经存在名为 '%s' 的文件。
editor.no_changes_to_show=没有可以显示的变更。 editor.no_changes_to_show=没有可以显示的变更。
editor.fail_to_update_file=更新/创建文件 '%s' 时发生错误:%v editor.fail_to_update_file=更新/创建文件 '%s' 时发生错误:%v
@ -994,7 +987,6 @@ settings.search_user_placeholder=搜索用户...
settings.org_not_allowed_to_be_collaborator=组织不允许被添加为仓库协作者! settings.org_not_allowed_to_be_collaborator=组织不允许被添加为仓库协作者!
settings.user_is_org_member=被操作的用户是组织,因此无法添加为协作者! settings.user_is_org_member=被操作的用户是组织,因此无法添加为协作者!
settings.add_webhook=添加 Web 钩子 settings.add_webhook=添加 Web 钩子
settings.hooks_desc=当Gitea事件发生时Web钩子自动发出HTTP POST请求。在 <a target="_blank" rel="noopener" href="%s"> 指南</a> 中阅读更多内容。
settings.webhook_deletion=删除 Web 钩子 settings.webhook_deletion=删除 Web 钩子
settings.webhook_deletion_desc=删除 web钩子 将删除其设置和历史记录。继续? settings.webhook_deletion_desc=删除 web钩子 将删除其设置和历史记录。继续?
settings.webhook_deletion_success=Web 钩子删除成功! settings.webhook_deletion_success=Web 钩子删除成功!
@ -1011,7 +1003,6 @@ settings.githook_edit_desc=如果钩子未启动,则会显示样例文件中
settings.githook_name=钩子名称 settings.githook_name=钩子名称
settings.githook_content=钩子文本 settings.githook_content=钩子文本
settings.update_githook=更新钩子设置 settings.update_githook=更新钩子设置
settings.add_webhook_desc=Gitea 将向目标 URL 发送具有指定内容类型的 <code>POST</code> 请求。在 <a target="_blank" rel="noopener" href="%s">webhooks 指南</a> 中阅读更多内容。
settings.payload_url=目标 URL settings.payload_url=目标 URL
settings.content_type=POST Content Type settings.content_type=POST Content Type
settings.secret=密钥文本 settings.secret=密钥文本
@ -1167,6 +1158,8 @@ branch.protected_deletion_failed=分支 '%s' 已被保护,不可删除。
topic.manage_topics=管理主题 topic.manage_topics=管理主题
topic.done=保存 topic.done=保存
topic.count_prompt=您最多选择25个主题
topic.format_prompt=主题必须以字母或数字开头,可以包含连字符 (-)并且长度不得超过35个字符
[org] [org]
org_name_holder=组织名称 org_name_holder=组织名称
@ -1271,8 +1264,6 @@ dashboard.operation_switch=开关
dashboard.operation_run=执行 dashboard.operation_run=执行
dashboard.clean_unbind_oauth=清理未绑定的 OAuth 连接 dashboard.clean_unbind_oauth=清理未绑定的 OAuth 连接
dashboard.clean_unbind_oauth_success=所有未绑定的 OAuth 连接已被删除。 dashboard.clean_unbind_oauth_success=所有未绑定的 OAuth 连接已被删除。
dashboard.delete_inactivate_accounts=删除所有未激活帐户
dashboard.delete_inactivate_accounts_success=所有未激活帐号清除成功!
dashboard.delete_repo_archives=删除所有仓库存档 dashboard.delete_repo_archives=删除所有仓库存档
dashboard.delete_repo_archives_success=所有仓库存档清除成功! dashboard.delete_repo_archives_success=所有仓库存档清除成功!
dashboard.delete_missing_repos=删除所有丢失 Git 文件的仓库 dashboard.delete_missing_repos=删除所有丢失 Git 文件的仓库

View File

@ -613,8 +613,6 @@ dashboard.operation_switch=開關
dashboard.operation_run=執行 dashboard.operation_run=執行
dashboard.clean_unbind_oauth=清理未綁定OAuth的連結 dashboard.clean_unbind_oauth=清理未綁定OAuth的連結
dashboard.clean_unbind_oauth_success=所有未綁定 OAuth 的連結已刪除。 dashboard.clean_unbind_oauth_success=所有未綁定 OAuth 的連結已刪除。
dashboard.delete_inactivate_accounts=刪除所有未啟用帳戶
dashboard.delete_inactivate_accounts_success=成功清除所有未啟用帳號!
dashboard.reinit_missing_repos=重新初始化所有遺失具已存在記錄的Git 儲存庫 dashboard.reinit_missing_repos=重新初始化所有遺失具已存在記錄的Git 儲存庫
dashboard.reinit_missing_repos_success=所有遺失具已存在記錄的Git 儲存庫已重新初始化。 dashboard.reinit_missing_repos_success=所有遺失具已存在記錄的Git 儲存庫已重新初始化。
dashboard.sync_external_users=同步外部使用者資料 dashboard.sync_external_users=同步外部使用者資料

File diff suppressed because it is too large Load Diff

View File

@ -257,13 +257,15 @@ func CreateOrgRepo(ctx *context.APIContext, opt api.CreateRepoOption) {
return return
} }
isOwner, err := org.IsOwnedBy(ctx.User.ID) if !ctx.User.IsAdmin {
if err != nil { isOwner, err := org.IsOwnedBy(ctx.User.ID)
ctx.ServerError("IsOwnedBy", err) if err != nil {
return ctx.ServerError("IsOwnedBy", err)
} else if !isOwner { return
ctx.Error(403, "", "Given user is not owner of organization.") } else if !isOwner {
return ctx.Error(403, "", "Given user is not owner of organization.")
return
}
} }
CreateUserRepo(ctx, org, opt) CreateUserRepo(ctx, org, opt)
} }
@ -306,16 +308,23 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) {
return return
} }
if ctxUser.IsOrganization() && !ctx.User.IsAdmin { if !ctx.User.IsAdmin {
// Check ownership of organization. if !ctxUser.IsOrganization() && ctx.User.ID != ctxUser.ID {
isOwner, err := ctxUser.IsOwnedBy(ctx.User.ID) ctx.Error(403, "", "Given user is not an organization.")
if err != nil {
ctx.Error(500, "IsOwnedBy", err)
return
} else if !isOwner {
ctx.Error(403, "", "Given user is not owner of organization.")
return return
} }
if ctxUser.IsOrganization() {
// Check ownership of organization.
isOwner, err := ctxUser.IsOwnedBy(ctx.User.ID)
if err != nil {
ctx.Error(500, "IsOwnedBy", err)
return
} else if !isOwner {
ctx.Error(403, "", "Given user is not owner of organization.")
return
}
}
} }
remoteAddr, err := form.ParseRemoteAddr(ctx.User) remoteAddr, err := form.ParseRemoteAddr(ctx.User)

View File

@ -58,6 +58,7 @@ func Install(ctx *context.Context) {
// Database settings // Database settings
form.DbHost = models.DbCfg.Host form.DbHost = models.DbCfg.Host
form.DbUser = models.DbCfg.User form.DbUser = models.DbCfg.User
form.DbPasswd = models.DbCfg.Passwd
form.DbName = models.DbCfg.Name form.DbName = models.DbCfg.Name
form.DbPath = models.DbCfg.Path form.DbPath = models.DbCfg.Path

View File

@ -77,6 +77,7 @@ func twofaGenerateSecretAndQr(ctx *context.Context) bool {
if otpKey == nil { if otpKey == nil {
err = nil // clear the error, in case the URL was invalid err = nil // clear the error, in case the URL was invalid
otpKey, err = totp.Generate(totp.GenerateOpts{ otpKey, err = totp.Generate(totp.GenerateOpts{
SecretSize: 40,
Issuer: setting.AppName + " (" + strings.TrimRight(setting.AppURL, "/") + ")", Issuer: setting.AppName + " (" + strings.TrimRight(setting.AppURL, "/") + ")",
AccountName: ctx.User.Name, AccountName: ctx.User.Name,
}) })

View File

@ -17,7 +17,7 @@
</div> </div>
<div class="ui right links"> <div class="ui right links">
{{if .ShowFooterBranding}} {{if .ShowFooterBranding}}
<a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea"><i class="fa fa-github-square"></i><span class="sr-only">GitHub</span></a> <a target="_blank" rel="noopener noreferrer" href="https://github.com/go-gitea/gitea"><i class="fa fa-github-square"></i><span class="sr-only">GitHub</span></a>
{{end}} {{end}}
<div class="ui language bottom floating slide up dropdown link item"> <div class="ui language bottom floating slide up dropdown link item">
<i class="world icon"></i> <i class="world icon"></i>
@ -30,7 +30,7 @@
</div> </div>
<a href="{{AppSubUrl}}/vendor/librejs.html" data-jslicense="1">JavaScript licenses</a> <a href="{{AppSubUrl}}/vendor/librejs.html" data-jslicense="1">JavaScript licenses</a>
{{if .EnableSwaggerEndpoint}}<a href="{{AppSubUrl}}/api/swagger">API</a>{{end}} {{if .EnableSwaggerEndpoint}}<a href="{{AppSubUrl}}/api/swagger">API</a>{{end}}
<a target="_blank" rel="noopener" href="https://gitea.io">{{.i18n.Tr "website"}}</a> <a target="_blank" rel="noopener noreferrer" href="https://gitea.io">{{.i18n.Tr "website"}}</a>
{{if (or .ShowFooterVersion .PageIsAdmin)}}<span class="version">{{GoVer}}</span>{{end}} {{if (or .ShowFooterVersion .PageIsAdmin)}}<span class="version">{{GoVer}}</span>{{end}}
</div> </div>
</div> </div>

View File

@ -174,7 +174,7 @@
<div class="right stackable menu"> <div class="right stackable menu">
<a href="{{AppSubUrl}}/notifications" class="item poping up" data-content='{{.i18n.Tr "notifications"}}' data-variation="tiny inverted"> <a href="{{AppSubUrl}}/notifications" class="item poping up" data-content='{{.i18n.Tr "notifications"}}' data-variation="tiny inverted">
<span class="text"> <span class="text">
<i class="fitted octicon octicon-inbox"></i> <i class="fitted octicon octicon-bell"></i>
<span class="sr-mobile-only">{{.i18n.Tr "notifications"}}</span> <span class="sr-mobile-only">{{.i18n.Tr "notifications"}}</span>
{{if .NotificationUnreadCount}} {{if .NotificationUnreadCount}}

60
templates/home.tmpl vendored
View File

@ -20,7 +20,7 @@
<i class="octicon octicon-flame"></i> Einfach zu installieren <i class="octicon octicon-flame"></i> Einfach zu installieren
</h1> </h1>
<p class="large"> <p class="large">
Starte einfach <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/install-from-binary/">die Anwendung</a> für deine Plattform. Gitea gibt es auch für <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/tree/master/docker">Docker</a>, <a target="_blank" rel="noopener" href="https://github.com/alvaroaleman/ansible-gitea/blob/master/Vagrantfile">Vagrant</a> oder als <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/install-from-package/">Installationspaket</a>. Starte einfach <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/install-from-binary/">die Anwendung</a> für deine Plattform. Gitea gibt es auch für <a target="_blank" rel="noopener noreferrer" href="https://github.com/go-gitea/gitea/tree/master/docker">Docker</a>, <a target="_blank" rel="noopener noreferrer" href="https://github.com/alvaroaleman/ansible-gitea/blob/master/Vagrantfile">Vagrant</a> oder als <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/install-from-package/">Installationspaket</a>.
</p> </p>
</div> </div>
<div class="eight wide center column"> <div class="eight wide center column">
@ -28,7 +28,7 @@
<i class="octicon octicon-device-desktop"></i> Plattformübergreifend <i class="octicon octicon-device-desktop"></i> Plattformübergreifend
</h1> </h1>
<p class="large"> <p class="large">
Gitea läuft überall. <a target="_blank" rel="noopener" href="http://golang.org/">Go</a> kompiliert für: Windows, macOS, Linux, ARM, etc. Wähle dasjenige System, was dir am meisten gefällt! Gitea läuft überall. <a target="_blank" rel="noopener noreferrer" href="http://golang.org/">Go</a> kompiliert für: Windows, macOS, Linux, ARM, etc. Wähle dasjenige System, was dir am meisten gefällt!
</p> </p>
</div> </div>
</div> </div>
@ -46,7 +46,7 @@
<i class="octicon octicon-code"></i> Quelloffen <i class="octicon octicon-code"></i> Quelloffen
</h1> </h1>
<p class="large"> <p class="large">
Der komplette Code befindet sich auf <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/">GitHub</a>! Unterstütze uns bei der Verbesserung dieses Projekts. Trau dich! Der komplette Code befindet sich auf <a target="_blank" rel="noopener noreferrer" href="https://github.com/go-gitea/gitea/">GitHub</a>! Unterstütze uns bei der Verbesserung dieses Projekts. Trau dich!
</p> </p>
</div> </div>
</div> </div>
@ -57,7 +57,7 @@
<i class="octicon octicon-flame"></i> 易安裝 <i class="octicon octicon-flame"></i> 易安裝
</h1> </h1>
<p class="large"> <p class="large">
直接用 <a target="_blank" rel="noopener" href="https://docs.gitea.io/zh-cn/install-from-binary/">執行檔安裝</a>,還可以透過 <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/tree/master/docker">Docker</a> 或 <a target="_blank" rel="noopener" href="https://github.com/alvaroaleman/ansible-gitea/blob/master/Vagrantfile">Vagrant</a>,以及 <a target="_blank" rel="noopener" href="https://docs.gitea.io/zh-cn/install-from-package/">套件</a>安装。 直接用 <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/zh-cn/install-from-binary/">執行檔安裝</a>,還可以透過 <a target="_blank" rel="noopener noreferrer" href="https://github.com/go-gitea/gitea/tree/master/docker">Docker</a> 或 <a target="_blank" rel="noopener noreferrer" href="https://github.com/alvaroaleman/ansible-gitea/blob/master/Vagrantfile">Vagrant</a>,以及 <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/zh-cn/install-from-package/">套件</a>安装。
</p> </p>
</div> </div>
<div class="eight wide center column"> <div class="eight wide center column">
@ -65,7 +65,7 @@
<i class="octicon octicon-device-desktop"></i> 跨平台 <i class="octicon octicon-device-desktop"></i> 跨平台
</h1> </h1>
<p class="large"> <p class="large">
Gitea 可以運作在任何 <a target="_blank" rel="noopener" href="http://golang.org/">Go 語言</a>能夠編譯的平台: Windows, macOS, Linux, ARM 等等。挑一個您喜歡的就好。 Gitea 可以運作在任何 <a target="_blank" rel="noopener noreferrer" href="http://golang.org/">Go 語言</a>能夠編譯的平台: Windows, macOS, Linux, ARM 等等。挑一個您喜歡的就好。
</p> </p>
</div> </div>
</div> </div>
@ -83,7 +83,7 @@
<i class="octicon octicon-code"></i> 開源化 <i class="octicon octicon-code"></i> 開源化
</h1> </h1>
<p class="large"> <p class="large">
所有程式碼都在 <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/">GitHub</a> 上,加入我們讓 Gitea 更好,別害羞,你可以做到的。 所有程式碼都在 <a target="_blank" rel="noopener noreferrer" href="https://github.com/go-gitea/gitea/">GitHub</a> 上,加入我們讓 Gitea 更好,別害羞,你可以做到的。
</p> </p>
</div> </div>
</div> </div>
@ -94,7 +94,7 @@
<i class="octicon octicon-flame"></i> 易安装 <i class="octicon octicon-flame"></i> 易安装
</h1> </h1>
<p class="large"> <p class="large">
您除了可以根据操作系统平台通过 <a target="_blank" rel="noopener" href="https://docs.gitea.io/zh-cn/install-from-binary/">二进制运行</a>,还可以通过 <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/tree/master/docker">Docker</a> 或 <a target="_blank" rel="noopener" href="https://github.com/alvaroaleman/ansible-gitea/blob/master/Vagrantfile">Vagrant</a>,以及 <a target="_blank" rel="noopener" href="https://docs.gitea.io/zh-cn/install-from-package/">包管理</a> 安装。 您除了可以根据操作系统平台通过 <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/zh-cn/install-from-binary/">二进制运行</a>,还可以通过 <a target="_blank" rel="noopener noreferrer" href="https://github.com/go-gitea/gitea/tree/master/docker">Docker</a> 或 <a target="_blank" rel="noopener noreferrer" href="https://github.com/alvaroaleman/ansible-gitea/blob/master/Vagrantfile">Vagrant</a>,以及 <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/zh-cn/install-from-package/">包管理</a> 安装。
</p> </p>
</div> </div>
<div class="eight wide center column"> <div class="eight wide center column">
@ -102,7 +102,7 @@
<i class="octicon octicon-device-desktop"></i> 跨平台 <i class="octicon octicon-device-desktop"></i> 跨平台
</h1> </h1>
<p class="large"> <p class="large">
任何 <a target="_blank" rel="noopener" href="http://golang.org/">Go 语言</a> 支持的平台都可以运行 Gitea包括 Windows、Mac、Linux 以及 ARM。挑一个您喜欢的就行 任何 <a target="_blank" rel="noopener noreferrer" href="http://golang.org/">Go 语言</a> 支持的平台都可以运行 Gitea包括 Windows、Mac、Linux 以及 ARM。挑一个您喜欢的就行
</p> </p>
</div> </div>
</div> </div>
@ -120,7 +120,7 @@
<i class="octicon octicon-code"></i> 开源化 <i class="octicon octicon-code"></i> 开源化
</h1> </h1>
<p class="large"> <p class="large">
所有的代码都开源在 <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/">GitHub</a> 上,赶快加入我们来共同发展这个伟大的项目!还等什么?成为贡献者吧! 所有的代码都开源在 <a target="_blank" rel="noopener noreferrer" href="https://github.com/go-gitea/gitea/">GitHub</a> 上,赶快加入我们来共同发展这个伟大的项目!还等什么?成为贡献者吧!
</p> </p>
</div> </div>
</div> </div>
@ -131,10 +131,10 @@
<i class="octicon octicon-flame"></i> Facile à installer <i class="octicon octicon-flame"></i> Facile à installer
</h1> </h1>
<p class="large"> <p class="large">
Il suffit de <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/install-from-binary/">lancer l'exécutable</a> correspondant à votre système. Il suffit de <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/install-from-binary/">lancer l'exécutable</a> correspondant à votre système.
Ou d'utiliser Gitea avec <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/tree/master/docker">Docker</a> ou Ou d'utiliser Gitea avec <a target="_blank" rel="noopener noreferrer" href="https://github.com/go-gitea/gitea/tree/master/docker">Docker</a> ou
<a target="_blank" rel="noopener" href="https://github.com/alvaroaleman/ansible-gitea/blob/master/Vagrantfile">Vagrant</a> <a target="_blank" rel="noopener noreferrer" href="https://github.com/alvaroaleman/ansible-gitea/blob/master/Vagrantfile">Vagrant</a>
ou en l'installant depuis un <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/install-from-package/">package</a>. ou en l'installant depuis un <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/install-from-package/">package</a>.
</p> </p>
</div> </div>
<div class="eight wide center column"> <div class="eight wide center column">
@ -142,7 +142,7 @@
<i class="octicon octicon-device-desktop"></i> Multi-plateforme <i class="octicon octicon-device-desktop"></i> Multi-plateforme
</h1> </h1>
<p class="large"> <p class="large">
Gitea tourne partout où <a target="_blank" rel="noopener" href="http://golang.org/">Go</a> peut être compilé : Windows, macOS, Linux, ARM, etc. Choisissez votre préféré ! Gitea tourne partout où <a target="_blank" rel="noopener noreferrer" href="http://golang.org/">Go</a> peut être compilé : Windows, macOS, Linux, ARM, etc. Choisissez votre préféré !
</p> </p>
</div> </div>
</div> </div>
@ -160,7 +160,7 @@
<i class="octicon octicon-code"></i> Open Source <i class="octicon octicon-code"></i> Open Source
</h1> </h1>
<p class="large"> <p class="large">
Toutes les sources sont sur <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/">GitHub</a> ! Rejoignez-nous et contribuez à rendre ce projet encore meilleur. Toutes les sources sont sur <a target="_blank" rel="noopener noreferrer" href="https://github.com/go-gitea/gitea/">GitHub</a> ! Rejoignez-nous et contribuez à rendre ce projet encore meilleur.
</p> </p>
</div> </div>
</div> </div>
@ -171,7 +171,7 @@
<i class="octicon octicon-flame"></i> Fácil de instalar <i class="octicon octicon-flame"></i> Fácil de instalar
</h1> </h1>
<p class="large"> <p class="large">
Simplemente <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/install-from-binary/">arranca el binario</a> para tu plataforma. O usa Gitea con <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/tree/master/docker">Docker</a> o <a target="_blank" rel="noopener" href="https://github.com/alvaroaleman/ansible-gitea/blob/master/Vagrantfile">Vagrant</a>, o utilice el <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/install-from-package/">paquete</a>. Simplemente <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/install-from-binary/">arranca el binario</a> para tu plataforma. O usa Gitea con <a target="_blank" rel="noopener noreferrer" href="https://github.com/go-gitea/gitea/tree/master/docker">Docker</a> o <a target="_blank" rel="noopener noreferrer" href="https://github.com/alvaroaleman/ansible-gitea/blob/master/Vagrantfile">Vagrant</a>, o utilice el <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/install-from-package/">paquete</a>.
</p> </p>
</div> </div>
<div class="eight wide center column"> <div class="eight wide center column">
@ -179,7 +179,7 @@
<i class="octicon octicon-device-desktop"></i> Multiplatforma <i class="octicon octicon-device-desktop"></i> Multiplatforma
</h1> </h1>
<p class="large"> <p class="large">
Gitea funciona en cualquier parte, <a target="_blank" rel="noopener" href="http://golang.org/">Go</a> puede compilarse en: Windows, macOS, Linux, ARM, etc. !Elige tu favorita! Gitea funciona en cualquier parte, <a target="_blank" rel="noopener noreferrer" href="http://golang.org/">Go</a> puede compilarse en: Windows, macOS, Linux, ARM, etc. !Elige tu favorita!
</p> </p>
</div> </div>
</div> </div>
@ -197,7 +197,7 @@
<i class="octicon octicon-code"></i> Open Source <i class="octicon octicon-code"></i> Open Source
</h1> </h1>
<p class="large"> <p class="large">
¡Está todo en <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/">GitHub</a>! Uniros contribuyendo a hacer este proyecto todavía mejor. ¡No seas tímido y colabora! ¡Está todo en <a target="_blank" rel="noopener noreferrer" href="https://github.com/go-gitea/gitea/">GitHub</a>! Uniros contribuyendo a hacer este proyecto todavía mejor. ¡No seas tímido y colabora!
</p> </p>
</div> </div>
</div> </div>
@ -208,7 +208,7 @@
<i class="octicon octicon-flame"></i> Fácil de instalar <i class="octicon octicon-flame"></i> Fácil de instalar
</h1> </h1>
<p class="large"> <p class="large">
Simplesmente <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/install-from-binary/">rode o executável</a> para o seu sistema operacional. Ou obtenha o Gitea com o <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/tree/master/docker">Docker</a> ou <a target="_blank" rel="noopener" href="https://github.com/alvaroaleman/ansible-gitea/blob/master/Vagrantfile">Vagrant</a>, ou baixe o <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/install-from-package/">pacote</a>. Simplesmente <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/install-from-binary/">rode o executável</a> para o seu sistema operacional. Ou obtenha o Gitea com o <a target="_blank" rel="noopener noreferrer" href="https://github.com/go-gitea/gitea/tree/master/docker">Docker</a> ou <a target="_blank" rel="noopener noreferrer" href="https://github.com/alvaroaleman/ansible-gitea/blob/master/Vagrantfile">Vagrant</a>, ou baixe o <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/install-from-package/">pacote</a>.
</p> </p>
</div> </div>
<div class="eight wide center column"> <div class="eight wide center column">
@ -216,7 +216,7 @@
<i class="octicon octicon-device-desktop"></i> Multi-plataforma <i class="octicon octicon-device-desktop"></i> Multi-plataforma
</h1> </h1>
<p class="large"> <p class="large">
Gitea roda em qualquer sistema operacional em que <a target="_blank" rel="noopener" href="http://golang.org/">Go</a> consegue compilar: Windows, macOS, Linux, ARM, etc. Escolha qual você gosta mais! Gitea roda em qualquer sistema operacional em que <a target="_blank" rel="noopener noreferrer" href="http://golang.org/">Go</a> consegue compilar: Windows, macOS, Linux, ARM, etc. Escolha qual você gosta mais!
</p> </p>
</div> </div>
</div> </div>
@ -234,7 +234,7 @@
<i class="octicon octicon-code"></i> Código aberto <i class="octicon octicon-code"></i> Código aberto
</h1> </h1>
<p class="large"> <p class="large">
Está tudo no <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/">GitHub</a>! Contribua e torne este projeto ainda melhor. Não tenha vergonha de contribuir! Está tudo no <a target="_blank" rel="noopener noreferrer" href="https://github.com/go-gitea/gitea/">GitHub</a>! Contribua e torne este projeto ainda melhor. Não tenha vergonha de contribuir!
</p> </p>
</div> </div>
</div> </div>
@ -245,7 +245,7 @@
<i class="octicon octicon-flame"></i> Простой в установке <i class="octicon octicon-flame"></i> Простой в установке
</h1> </h1>
<p class="large"> <p class="large">
Просто <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/install-from-binary/">запустите исполняемый файл</a> для вашей платформы. Изпользуйте Gitea с <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/tree/master/docker">Docker</a> или <a target="_blank" rel="noopener" href="https://github.com/alvaroaleman/ansible-gitea/blob/master/Vagrantfile">Vagrant</a>, или загрузите <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/install-from-package/">пакет</a>. Просто <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/install-from-binary/">запустите исполняемый файл</a> для вашей платформы. Изпользуйте Gitea с <a target="_blank" rel="noopener noreferrer" href="https://github.com/go-gitea/gitea/tree/master/docker">Docker</a> или <a target="_blank" rel="noopener noreferrer" href="https://github.com/alvaroaleman/ansible-gitea/blob/master/Vagrantfile">Vagrant</a>, или загрузите <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/install-from-package/">пакет</a>.
</p> </p>
</div> </div>
<div class="eight wide center column"> <div class="eight wide center column">
@ -253,7 +253,7 @@
<i class="octicon octicon-device-desktop"></i> Кроссплатформенный <i class="octicon octicon-device-desktop"></i> Кроссплатформенный
</h1> </h1>
<p class="large"> <p class="large">
Gitea работает на любой операционной системе, которая может компилировать <a target="_blank" rel="noopener" href="http://golang.org/">Go</a>: Windows, macOS, Linux, ARM и т. д. Выбирайте, что вам больше нравится! Gitea работает на любой операционной системе, которая может компилировать <a target="_blank" rel="noopener noreferrer" href="http://golang.org/">Go</a>: Windows, macOS, Linux, ARM и т. д. Выбирайте, что вам больше нравится!
</p> </p>
</div> </div>
</div> </div>
@ -271,7 +271,7 @@
<i class="octicon octicon-code"></i> Открытый исходный код <i class="octicon octicon-code"></i> Открытый исходный код
</h1> </h1>
<p class="large"> <p class="large">
Всё это на <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/">GitHub</a>! Присоединяйтесь к нам, внося вклад, чтобы сделать этот проект еще лучше. Не бойтесь помогать! Всё это на <a target="_blank" rel="noopener noreferrer" href="https://github.com/go-gitea/gitea/">GitHub</a>! Присоединяйтесь к нам, внося вклад, чтобы сделать этот проект еще лучше. Не бойтесь помогать!
</p> </p>
</div> </div>
</div> </div>
@ -282,7 +282,7 @@
<i class="octicon octicon-flame"></i> Makkelijk te installeren <i class="octicon octicon-flame"></i> Makkelijk te installeren
</h1> </h1>
<p class="large"> <p class="large">
Je hoeft alleen maar de <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/install-from-binary/">binary</a> uit te voeren. Of gebruik Gitea met <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/tree/master/docker">Docker</a>, <a target="_blank" rel="noopener" href="https://github.com/alvaroaleman/ansible-gitea/blob/master/Vagrantfile">Vagrant</a>, of download een <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/install-from-package/">installatiepakket</a>. Je hoeft alleen maar de <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/install-from-binary/">binary</a> uit te voeren. Of gebruik Gitea met <a target="_blank" rel="noopener noreferrer" href="https://github.com/go-gitea/gitea/tree/master/docker">Docker</a>, <a target="_blank" rel="noopener noreferrer" href="https://github.com/alvaroaleman/ansible-gitea/blob/master/Vagrantfile">Vagrant</a>, of download een <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/install-from-package/">installatiepakket</a>.
</p> </p>
</div> </div>
<div class="eight wide center column"> <div class="eight wide center column">
@ -290,7 +290,7 @@
<i class="octicon octicon-device-desktop"></i> Cross-platform <i class="octicon octicon-device-desktop"></i> Cross-platform
</h1> </h1>
<p class="large"> <p class="large">
Gitea werkt op alles waar <a target="_blank" rel="noopener" href="http://golang.org/">Go</a> op kan compileren: Windows, macOS, Linux, ARM, etc. Kies het platform dat bij je past! Gitea werkt op alles waar <a target="_blank" rel="noopener noreferrer" href="http://golang.org/">Go</a> op kan compileren: Windows, macOS, Linux, ARM, etc. Kies het platform dat bij je past!
</p> </p>
</div> </div>
</div> </div>
@ -308,7 +308,7 @@
<i class="octicon octicon-code"></i> Open Source <i class="octicon octicon-code"></i> Open Source
</h1> </h1>
<p class="large"> <p class="large">
Alles staat op <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/">GitHub</a>! Help ons door mee te bouwen aan Gitea, samen maken we dit project nog beter. Aarzel dus niet om een bijdrage te leveren! Alles staat op <a target="_blank" rel="noopener noreferrer" href="https://github.com/go-gitea/gitea/">GitHub</a>! Help ons door mee te bouwen aan Gitea, samen maken we dit project nog beter. Aarzel dus niet om een bijdrage te leveren!
</p> </p>
</div> </div>
</div> </div>
@ -319,7 +319,7 @@
<i class="octicon octicon-flame"></i> Easy to install <i class="octicon octicon-flame"></i> Easy to install
</h1> </h1>
<p class="large"> <p class="large">
Simply <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/install-from-binary/">run the binary</a> for your platform. Or ship Gitea with <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/tree/master/docker">Docker</a> or <a target="_blank" rel="noopener" href="https://github.com/alvaroaleman/ansible-gitea/blob/master/Vagrantfile">Vagrant</a>, or get it <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/install-from-package/">packaged</a>. Simply <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/install-from-binary/">run the binary</a> for your platform. Or ship Gitea with <a target="_blank" rel="noopener noreferrer" href="https://github.com/go-gitea/gitea/tree/master/docker">Docker</a> or <a target="_blank" rel="noopener noreferrer" href="https://github.com/alvaroaleman/ansible-gitea/blob/master/Vagrantfile">Vagrant</a>, or get it <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/install-from-package/">packaged</a>.
</p> </p>
</div> </div>
<div class="eight wide center column"> <div class="eight wide center column">
@ -327,7 +327,7 @@
<i class="octicon octicon-device-desktop"></i> Cross-platform <i class="octicon octicon-device-desktop"></i> Cross-platform
</h1> </h1>
<p class="large"> <p class="large">
Gitea runs anywhere <a target="_blank" rel="noopener" href="http://golang.org/">Go</a> can compile for: Windows, macOS, Linux, ARM, etc. Choose the one you love! Gitea runs anywhere <a target="_blank" rel="noopener noreferrer" href="http://golang.org/">Go</a> can compile for: Windows, macOS, Linux, ARM, etc. Choose the one you love!
</p> </p>
</div> </div>
</div> </div>
@ -345,7 +345,7 @@
<i class="octicon octicon-code"></i> Open Source <i class="octicon octicon-code"></i> Open Source
</h1> </h1>
<p class="large"> <p class="large">
It's all on <a target="_blank" rel="noopener" href="https://github.com/go-gitea/gitea/">GitHub</a>! Join us by contributing to make this project even better. Don't be shy to be a contributor! It's all on <a target="_blank" rel="noopener noreferrer" href="https://github.com/go-gitea/gitea/">GitHub</a>! Join us by contributing to make this project even better. Don't be shy to be a contributor!
</p> </p>
</div> </div>
</div> </div>

View File

@ -10,6 +10,6 @@
<p>Please click the following link to activate your account within <b>{{.ActiveCodeLives}}</b>:</p> <p>Please click the following link to activate your account within <b>{{.ActiveCodeLives}}</b>:</p>
<p><a href="{{AppUrl}}user/activate?code={{.Code}}">{{AppUrl}}user/activate?code={{.Code}}</a></p> <p><a href="{{AppUrl}}user/activate?code={{.Code}}">{{AppUrl}}user/activate?code={{.Code}}</a></p>
<p>Not working? Try copying and pasting it to your browser.</p> <p>Not working? Try copying and pasting it to your browser.</p>
<p>© <a target="_blank" rel="noopener" href="{{AppUrl}}">{{AppName}}</a></p> <p>© <a target="_blank" rel="noopener noreferrer" href="{{AppUrl}}">{{AppName}}</a></p>
</body> </body>
</html> </html>

View File

@ -10,6 +10,6 @@
<p>Please click the following link to verify your email address within <b>{{.ActiveCodeLives}}</b>:</p> <p>Please click the following link to verify your email address within <b>{{.ActiveCodeLives}}</b>:</p>
<p><a href="{{AppUrl}}user/activate_email?code={{.Code}}&email={{.Email}}">{{AppUrl}}user/activate_email?code={{.Code}}&email={{.Email}}</a></p> <p><a href="{{AppUrl}}user/activate_email?code={{.Code}}&email={{.Email}}">{{AppUrl}}user/activate_email?code={{.Code}}&email={{.Email}}</a></p>
<p>Not working? Try copying and pasting it to your browser.</p> <p>Not working? Try copying and pasting it to your browser.</p>
<p>© <a target="_blank" rel="noopener" href="{{AppUrl}}">{{AppName}}</a></p> <p>© <a target="_blank" rel="noopener noreferrer" href="{{AppUrl}}">{{AppName}}</a></p>
</body> </body>
</html> </html>

View File

@ -10,6 +10,6 @@
<p>You can now login via username: {{.Username}}.</p> <p>You can now login via username: {{.Username}}.</p>
<p><a href="{{AppUrl}}user/login">{{AppUrl}}user/login</a></p> <p><a href="{{AppUrl}}user/login">{{AppUrl}}user/login</a></p>
<p>If this account has been created for you, please <a href="{{AppUrl}}user/forgot_password">reset your password</a> first.</p> <p>If this account has been created for you, please <a href="{{AppUrl}}user/forgot_password">reset your password</a> first.</p>
<p>© <a target="_blank" rel="noopener" href="{{AppUrl}}">{{AppName}}</a></p> <p>© <a target="_blank" rel="noopener noreferrer" href="{{AppUrl}}">{{AppName}}</a></p>
</body> </body>
</html> </html>

View File

@ -10,6 +10,6 @@
<p>Please click the following link to reset your password within <b>{{.ResetPwdCodeLives}}</b>:</p> <p>Please click the following link to reset your password within <b>{{.ResetPwdCodeLives}}</b>:</p>
<p><a href="{{AppUrl}}user/reset_password?code={{.Code}}">{{AppUrl}}user/reset_password?code={{.Code}}</a></p> <p><a href="{{AppUrl}}user/reset_password?code={{.Code}}">{{AppUrl}}user/reset_password?code={{.Code}}</a></p>
<p>Not working? Try copying and pasting it to your browser.</p> <p>Not working? Try copying and pasting it to your browser.</p>
<p>© <a target="_blank" rel="noopener" href="{{AppUrl}}">{{AppName}}</a></p> <p>© <a target="_blank" rel="noopener noreferrer" href="{{AppUrl}}">{{AppName}}</a></p>
</body> </body>
</html> </html>

View File

@ -12,7 +12,7 @@
{{if .Org.Description}}<p class="desc">{{.Org.Description}}</p>{{end}} {{if .Org.Description}}<p class="desc">{{.Org.Description}}</p>{{end}}
<div class="text grey meta"> <div class="text grey meta">
{{if .Org.Location}}<div class="item"><span class="octicon octicon-location"></span> <span>{{.Org.Location}}</span></div>{{end}} {{if .Org.Location}}<div class="item"><span class="octicon octicon-location"></span> <span>{{.Org.Location}}</span></div>{{end}}
{{if .Org.Website}}<div class="item"><span class="octicon octicon-link"></span> <a target="_blank" rel="noopener" href="{{.Org.Website}}">{{.Org.Website}}</a></div>{{end}} {{if .Org.Website}}<div class="item"><span class="octicon octicon-link"></span> <a target="_blank" rel="noopener noreferrer" href="{{.Org.Website}}">{{.Org.Website}}</a></div>{{end}}
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,15 +1,15 @@
{{if eq .State "pending"}} {{if eq .State "pending"}}
<a href="{{.TargetURL}}" target=_blank><i class="commit-status circle icon yellow"></i></a> <a href="{{.TargetURL}}" target="_blank" rel="noopener noreferrer"><i class="commit-status circle icon yellow"></i></a>
{{end}} {{end}}
{{if eq .State "success"}} {{if eq .State "success"}}
<a href="{{.TargetURL}}" target=_blank><i class="commit-status check icon green"></i></a> <a href="{{.TargetURL}}" target="_blank" rel="noopener noreferrer"><i class="commit-status check icon green"></i></a>
{{end}} {{end}}
{{if eq .State "error"}} {{if eq .State "error"}}
<a href="{{.TargetURL}}" target=_blank><i class="commit-status warning icon red"></i></a> <a href="{{.TargetURL}}" target="_blank" rel="noopener noreferrer"><i class="commit-status warning icon red"></i></a>
{{end}} {{end}}
{{if eq .State "failure"}} {{if eq .State "failure"}}
<a href="{{.TargetURL}}" target=_blank><i class="commit-status remove icon red"></i></a> <a href="{{.TargetURL}}" target="_blank" rel="noopener noreferrer"><i class="commit-status remove icon red"></i></a>
{{end}} {{end}}
{{if eq .State "warning"}} {{if eq .State "warning"}}
<a href="{{.TargetURL}}" target=_blank><i class="commit-status warning sign icon yellow"></i></a> <a href="{{.TargetURL}}" target="_blank" rel="noopener noreferrer"><i class="commit-status warning sign icon yellow"></i></a>
{{end}} {{end}}

View File

@ -43,10 +43,10 @@
<div class="ui checkbox"> <div class="ui checkbox">
{{if .IsForcedPrivate}} {{if .IsForcedPrivate}}
<input name="private" type="checkbox" checked readonly> <input name="private" type="checkbox" checked readonly>
<label>{{.i18n.Tr "repo.visiblity_helper_forced" | Safe}}</label> <label>{{.i18n.Tr "repo.visibility_helper_forced" | Safe}}</label>
{{else}} {{else}}
<input name="private" type="checkbox" {{if .private}}checked{{end}}> <input name="private" type="checkbox" {{if .private}}checked{{end}}>
<label>{{.i18n.Tr "repo.visiblity_helper" | Safe}}</label> <label>{{.i18n.Tr "repo.visibility_helper" | Safe}}</label>
{{end}} {{end}}
</div> </div>
</div> </div>

View File

@ -8,7 +8,7 @@
<a href="{{AppSubUrl}}/{{.Owner.Name}}">{{.Owner.Name}}</a> <a href="{{AppSubUrl}}/{{.Owner.Name}}">{{.Owner.Name}}</a>
<div class="divider"> / </div> <div class="divider"> / </div>
<a href="{{$.RepoLink}}">{{.Name}}</a> <a href="{{$.RepoLink}}">{{.Name}}</a>
{{if .IsMirror}}<div class="fork-flag">{{$.i18n.Tr "repo.mirror_from"}} <a target="_blank" rel="noopener" href="{{$.Mirror.Address}}">{{$.Mirror.Address}}</a></div>{{end}} {{if .IsMirror}}<div class="fork-flag">{{$.i18n.Tr "repo.mirror_from"}} <a target="_blank" rel="noopener noreferrer" href="{{$.Mirror.Address}}">{{$.Mirror.Address}}</a></div>{{end}}
{{if .IsFork}}<div class="fork-flag">{{$.i18n.Tr "repo.forked_from"}} <a href="{{.BaseRepo.Link}}">{{SubStr .BaseRepo.RelLink 1 -1}}</a></div>{{end}} {{if .IsFork}}<div class="fork-flag">{{$.i18n.Tr "repo.forked_from"}} <a href="{{.BaseRepo.Link}}">{{SubStr .BaseRepo.RelLink 1 -1}}</a></div>{{end}}
</div> </div>
</div> </div>
@ -60,7 +60,7 @@
{{end}} {{end}}
{{if .Repository.UnitEnabled $.UnitTypeExternalTracker}} {{if .Repository.UnitEnabled $.UnitTypeExternalTracker}}
<a class="{{if .PageIsIssueList}}active{{end}} item" href="{{.RepoLink}}/issues" target="_blank"> <a class="{{if .PageIsIssueList}}active{{end}} item" href="{{.RepoLink}}/issues" target="_blank" rel="noopener noreferrer">
<i class="octicon octicon-issue-opened"></i> {{.i18n.Tr "repo.issues"}} </span> <i class="octicon octicon-issue-opened"></i> {{.i18n.Tr "repo.issues"}} </span>
</a> </a>
{{end}} {{end}}
@ -78,7 +78,7 @@
{{end}} {{end}}
{{if or (.Repository.UnitEnabled $.UnitTypeWiki) (.Repository.UnitEnabled $.UnitTypeExternalWiki)}} {{if or (.Repository.UnitEnabled $.UnitTypeWiki) (.Repository.UnitEnabled $.UnitTypeExternalWiki)}}
<a class="{{if .PageIsWiki}}active{{end}} item" href="{{.RepoLink}}/wiki" {{if (.Repository.UnitEnabled $.UnitTypeExternalWiki)}} target="_blank" {{end}}> <a class="{{if .PageIsWiki}}active{{end}} item" href="{{.RepoLink}}/wiki" {{if (.Repository.UnitEnabled $.UnitTypeExternalWiki)}} target="_blank" rel="noopener noreferrer" {{end}}>
<i class="octicon octicon-book"></i> {{.i18n.Tr "repo.wiki"}} <i class="octicon octicon-book"></i> {{.i18n.Tr "repo.wiki"}}
</a> </a>
{{end}} {{end}}

View File

@ -63,7 +63,7 @@
<div class="ui attached left aligned segment"> <div class="ui attached left aligned segment">
<!-- <h4 class="ui header"> <!-- <h4 class="ui header">
{{.i18n.Tr "repo.issues.label_templates.title"}} {{.i18n.Tr "repo.issues.label_templates.title"}}
<a target="_blank" rel="noopener" <a target="_blank" rel="noopener noreferrer"
href="https://discuss.gogs.io/t/how-to-use-predefined-label-templates/599"> href="https://discuss.gogs.io/t/how-to-use-predefined-label-templates/599">
<span class="octicon octicon-question"></span> <span class="octicon octicon-question"></span>
</a> </a>

View File

@ -48,7 +48,7 @@
<div class="ui bottom attached segment"> <div class="ui bottom attached segment">
<div class="ui small images"> <div class="ui small images">
{{range .Issue.Attachments}} {{range .Issue.Attachments}}
<a target="_blank" rel="noopener" href="{{AppSubUrl}}/attachments/{{.UUID}}"> <a target="_blank" rel="noopener noreferrer" href="{{AppSubUrl}}/attachments/{{.UUID}}">
{{if FilenameIsImage .Name}} {{if FilenameIsImage .Name}}
<img class="ui image" src="{{AppSubUrl}}/attachments/{{.UUID}}" title='{{$.i18n.Tr "repo.issues.attachment.open_tab" .Name}}'> <img class="ui image" src="{{AppSubUrl}}/attachments/{{.UUID}}" title='{{$.i18n.Tr "repo.issues.attachment.open_tab" .Name}}'>
{{else}} {{else}}

View File

@ -52,7 +52,7 @@
<div class="ui bottom attached segment"> <div class="ui bottom attached segment">
<div class="ui small images"> <div class="ui small images">
{{range .Attachments}} {{range .Attachments}}
<a target="_blank" rel="noopener" href="{{AppSubUrl}}/attachments/{{.UUID}}"> <a target="_blank" rel="noopener noreferrer" href="{{AppSubUrl}}/attachments/{{.UUID}}">
{{if FilenameIsImage .Name}} {{if FilenameIsImage .Name}}
<img class="ui image" src="{{AppSubUrl}}/attachments/{{.UUID}}" title='{{$.i18n.Tr "repo.issues.attachment.open_tab" .Name}}'> <img class="ui image" src="{{AppSubUrl}}/attachments/{{.UUID}}" title='{{$.i18n.Tr "repo.issues.attachment.open_tab" .Name}}'>
{{else}} {{else}}

View File

@ -70,10 +70,10 @@
<div class="ui checkbox"> <div class="ui checkbox">
{{if .IsForcedPrivate}} {{if .IsForcedPrivate}}
<input name="private" type="checkbox" checked readonly> <input name="private" type="checkbox" checked readonly>
<label>{{.i18n.Tr "repo.visiblity_helper_forced" | Safe}}</label> <label>{{.i18n.Tr "repo.visibility_helper_forced" | Safe}}</label>
{{else}} {{else}}
<input name="private" type="checkbox" {{if .private}}checked{{end}}> <input name="private" type="checkbox" {{if .private}}checked{{end}}>
<label>{{.i18n.Tr "repo.visiblity_helper" | Safe}}</label> <label>{{.i18n.Tr "repo.visibility_helper" | Safe}}</label>
{{end}} {{end}}
</div> </div>
</div> </div>

View File

@ -47,9 +47,9 @@
<label>{{.i18n.Tr "repo.visibility"}}</label> <label>{{.i18n.Tr "repo.visibility"}}</label>
<div class="ui read-only checkbox"> <div class="ui read-only checkbox">
<input type="checkbox" {{if .IsPrivate}}checked{{end}}> <input type="checkbox" {{if .IsPrivate}}checked{{end}}>
<label>{{.i18n.Tr "repo.visiblity_helper" | Safe}}</label> <label>{{.i18n.Tr "repo.visibility_helper" | Safe}}</label>
</div> </div>
<span class="help">{{.i18n.Tr "repo.fork_visiblity_helper"}}</span> <span class="help">{{.i18n.Tr "repo.fork_visibility_helper"}}</span>
</div> </div>
<div class="inline field {{if .Err_Description}}error{{end}}"> <div class="inline field {{if .Err_Description}}error{{end}}">
<label for="description">{{.i18n.Tr "repo.repo_desc"}}</label> <label for="description">{{.i18n.Tr "repo.repo_desc"}}</label>

View File

@ -77,7 +77,7 @@
{{if .Attachments}} {{if .Attachments}}
{{range .Attachments}} {{range .Attachments}}
<li> <li>
<a target="_blank" rel="noopener" href="{{AppSubUrl}}/attachments/{{.UUID}}"> <a target="_blank" rel="noopener noreferrer" href="{{AppSubUrl}}/attachments/{{.UUID}}">
<strong><span class="ui image octicon octicon-package" title='{{.Name}}'></span> {{.Name}}</strong> <strong><span class="ui image octicon octicon-package" title='{{.Name}}'></span> {{.Name}}</strong>
<span class="ui text grey right">{{.Size | FileSize}}</span> <span class="ui text grey right">{{.Size | FileSize}}</span>
</a> </a>

View File

@ -20,7 +20,7 @@
<label>{{.i18n.Tr "repo.visibility"}}</label> <label>{{.i18n.Tr "repo.visibility"}}</label>
<div class="ui checkbox"> <div class="ui checkbox">
<input name="private" type="checkbox" {{if .Repository.IsPrivate}}checked{{end}}> <input name="private" type="checkbox" {{if .Repository.IsPrivate}}checked{{end}}>
<label>{{.i18n.Tr "repo.visiblity_helper" | Safe}} {{if .Repository.NumForks}}<span class="text red">{{.i18n.Tr "repo.visiblity_fork_helper"}}</span>{{end}}</label> <label>{{.i18n.Tr "repo.visibility_helper" | Safe}} {{if .Repository.NumForks}}<span class="text red">{{.i18n.Tr "repo.visibility_fork_helper"}}</span>{{end}}</label>
</div> </div>
</div> </div>
{{end}} {{end}}

View File

@ -12,7 +12,7 @@
<div class="meta"> <div class="meta">
{{if .Website}} {{if .Website}}
<span class="octicon octicon-link"></span> <a href="{{.Website}}" target="_blank" rel="noopener">{{.Website}}</a> <span class="octicon octicon-link"></span> <a href="{{.Website}}" target="_blank" rel="noopener noreferrer">{{.Website}}</a>
{{else if .Location}} {{else if .Location}}
<span class="octicon octicon-location"></span> {{.Location}} <span class="octicon octicon-location"></span> {{.Location}}
{{else}} {{else}}

View File

@ -31,14 +31,14 @@
{{if .Owner.Website}} {{if .Owner.Website}}
<li> <li>
<i class="octicon octicon-link"></i> <i class="octicon octicon-link"></i>
<a target="_blank" rel="noopener" href="{{.Owner.Website}}">{{.Owner.Website}}</a> <a target="_blank" rel="noopener noreferrer" href="{{.Owner.Website}}">{{.Owner.Website}}</a>
</li> </li>
{{end}} {{end}}
{{range .OpenIDs}} {{range .OpenIDs}}
{{if .Show}} {{if .Show}}
<li> <li>
<i class="fa fa-openid"></i> <i class="fa fa-openid"></i>
<a target="_blank" rel="noopener" href="{{.URI}}">{{.URI}}</a> <a target="_blank" rel="noopener noreferrer" href="{{.URI}}">{{.URI}}</a>
</li> </li>
{{end}} {{end}}
{{end}} {{end}}

202
vendor/github.com/coreos/etcd/LICENSE generated vendored
View File

@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -1,5 +0,0 @@
CoreOS Project
Copyright 2014 CoreOS, Inc
This product includes software developed at CoreOS, Inc.
(http://www.coreos.com/).

View File

@ -1,162 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package error describes errors in etcd project. When any change happens,
// Documentation/errorcode.md needs to be updated correspondingly.
package error
import (
"encoding/json"
"fmt"
"net/http"
)
var errors = map[int]string{
// command related errors
EcodeKeyNotFound: "Key not found",
EcodeTestFailed: "Compare failed", //test and set
EcodeNotFile: "Not a file",
ecodeNoMorePeer: "Reached the max number of peers in the cluster",
EcodeNotDir: "Not a directory",
EcodeNodeExist: "Key already exists", // create
ecodeKeyIsPreserved: "The prefix of given key is a keyword in etcd",
EcodeRootROnly: "Root is read only",
EcodeDirNotEmpty: "Directory not empty",
ecodeExistingPeerAddr: "Peer address has existed",
EcodeUnauthorized: "The request requires user authentication",
// Post form related errors
ecodeValueRequired: "Value is Required in POST form",
EcodePrevValueRequired: "PrevValue is Required in POST form",
EcodeTTLNaN: "The given TTL in POST form is not a number",
EcodeIndexNaN: "The given index in POST form is not a number",
ecodeValueOrTTLRequired: "Value or TTL is required in POST form",
ecodeTimeoutNaN: "The given timeout in POST form is not a number",
ecodeNameRequired: "Name is required in POST form",
ecodeIndexOrValueRequired: "Index or value is required",
ecodeIndexValueMutex: "Index and value cannot both be specified",
EcodeInvalidField: "Invalid field",
EcodeInvalidForm: "Invalid POST form",
EcodeRefreshValue: "Value provided on refresh",
EcodeRefreshTTLRequired: "A TTL must be provided on refresh",
// raft related errors
EcodeRaftInternal: "Raft Internal Error",
EcodeLeaderElect: "During Leader Election",
// etcd related errors
EcodeWatcherCleared: "watcher is cleared due to etcd recovery",
EcodeEventIndexCleared: "The event in requested index is outdated and cleared",
ecodeStandbyInternal: "Standby Internal Error",
ecodeInvalidActiveSize: "Invalid active size",
ecodeInvalidRemoveDelay: "Standby remove delay",
// client related errors
ecodeClientInternal: "Client Internal Error",
}
var errorStatus = map[int]int{
EcodeKeyNotFound: http.StatusNotFound,
EcodeNotFile: http.StatusForbidden,
EcodeDirNotEmpty: http.StatusForbidden,
EcodeUnauthorized: http.StatusUnauthorized,
EcodeTestFailed: http.StatusPreconditionFailed,
EcodeNodeExist: http.StatusPreconditionFailed,
EcodeRaftInternal: http.StatusInternalServerError,
EcodeLeaderElect: http.StatusInternalServerError,
}
const (
EcodeKeyNotFound = 100
EcodeTestFailed = 101
EcodeNotFile = 102
ecodeNoMorePeer = 103
EcodeNotDir = 104
EcodeNodeExist = 105
ecodeKeyIsPreserved = 106
EcodeRootROnly = 107
EcodeDirNotEmpty = 108
ecodeExistingPeerAddr = 109
EcodeUnauthorized = 110
ecodeValueRequired = 200
EcodePrevValueRequired = 201
EcodeTTLNaN = 202
EcodeIndexNaN = 203
ecodeValueOrTTLRequired = 204
ecodeTimeoutNaN = 205
ecodeNameRequired = 206
ecodeIndexOrValueRequired = 207
ecodeIndexValueMutex = 208
EcodeInvalidField = 209
EcodeInvalidForm = 210
EcodeRefreshValue = 211
EcodeRefreshTTLRequired = 212
EcodeRaftInternal = 300
EcodeLeaderElect = 301
EcodeWatcherCleared = 400
EcodeEventIndexCleared = 401
ecodeStandbyInternal = 402
ecodeInvalidActiveSize = 403
ecodeInvalidRemoveDelay = 404
ecodeClientInternal = 500
)
type Error struct {
ErrorCode int `json:"errorCode"`
Message string `json:"message"`
Cause string `json:"cause,omitempty"`
Index uint64 `json:"index"`
}
func NewRequestError(errorCode int, cause string) *Error {
return NewError(errorCode, cause, 0)
}
func NewError(errorCode int, cause string, index uint64) *Error {
return &Error{
ErrorCode: errorCode,
Message: errors[errorCode],
Cause: cause,
Index: index,
}
}
// Error is for the error interface
func (e Error) Error() string {
return e.Message + " (" + e.Cause + ")"
}
func (e Error) toJsonString() string {
b, _ := json.Marshal(e)
return string(b)
}
func (e Error) StatusCode() int {
status, ok := errorStatus[e.ErrorCode]
if !ok {
status = http.StatusBadRequest
}
return status
}
func (e Error) WriteTo(w http.ResponseWriter) {
w.Header().Add("X-Etcd-Index", fmt.Sprint(e.Index))
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(e.StatusCode())
fmt.Fprintln(w, e.toJsonString())
}

View File

@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -1,23 +0,0 @@
package etcd
// Add a new directory with a random etcd-generated key under the given path.
func (c *Client) AddChildDir(key string, ttl uint64) (*Response, error) {
raw, err := c.post(key, "", ttl)
if err != nil {
return nil, err
}
return raw.Unmarshal()
}
// Add a new file with a random etcd-generated key under the given path.
func (c *Client) AddChild(key string, value string, ttl uint64) (*Response, error) {
raw, err := c.post(key, value, ttl)
if err != nil {
return nil, err
}
return raw.Unmarshal()
}

View File

@ -1,476 +0,0 @@
package etcd
import (
"crypto/tls"
"crypto/x509"
"encoding/json"
"errors"
"io"
"io/ioutil"
"math/rand"
"net"
"net/http"
"net/url"
"os"
"path"
"strings"
"time"
)
// See SetConsistency for how to use these constants.
const (
// Using strings rather than iota because the consistency level
// could be persisted to disk, so it'd be better to use
// human-readable values.
STRONG_CONSISTENCY = "STRONG"
WEAK_CONSISTENCY = "WEAK"
)
const (
defaultBufferSize = 10
)
func init() {
rand.Seed(int64(time.Now().Nanosecond()))
}
type Config struct {
CertFile string `json:"certFile"`
KeyFile string `json:"keyFile"`
CaCertFile []string `json:"caCertFiles"`
DialTimeout time.Duration `json:"timeout"`
Consistency string `json:"consistency"`
}
type credentials struct {
username string
password string
}
type Client struct {
config Config `json:"config"`
cluster *Cluster `json:"cluster"`
httpClient *http.Client
credentials *credentials
transport *http.Transport
persistence io.Writer
cURLch chan string
// CheckRetry can be used to control the policy for failed requests
// and modify the cluster if needed.
// The client calls it before sending requests again, and
// stops retrying if CheckRetry returns some error. The cases that
// this function needs to handle include no response and unexpected
// http status code of response.
// If CheckRetry is nil, client will call the default one
// `DefaultCheckRetry`.
// Argument cluster is the etcd.Cluster object that these requests have been made on.
// Argument numReqs is the number of http.Requests that have been made so far.
// Argument lastResp is the http.Responses from the last request.
// Argument err is the reason of the failure.
CheckRetry func(cluster *Cluster, numReqs int,
lastResp http.Response, err error) error
}
// NewClient create a basic client that is configured to be used
// with the given machine list.
func NewClient(machines []string) *Client {
config := Config{
// default timeout is one second
DialTimeout: time.Second,
Consistency: WEAK_CONSISTENCY,
}
client := &Client{
cluster: NewCluster(machines),
config: config,
}
client.initHTTPClient()
client.saveConfig()
return client
}
// NewTLSClient create a basic client with TLS configuration
func NewTLSClient(machines []string, cert, key, caCert string) (*Client, error) {
// overwrite the default machine to use https
if len(machines) == 0 {
machines = []string{"https://127.0.0.1:4001"}
}
config := Config{
// default timeout is one second
DialTimeout: time.Second,
Consistency: WEAK_CONSISTENCY,
CertFile: cert,
KeyFile: key,
CaCertFile: make([]string, 0),
}
client := &Client{
cluster: NewCluster(machines),
config: config,
}
err := client.initHTTPSClient(cert, key)
if err != nil {
return nil, err
}
err = client.AddRootCA(caCert)
client.saveConfig()
return client, nil
}
// NewClientFromFile creates a client from a given file path.
// The given file is expected to use the JSON format.
func NewClientFromFile(fpath string) (*Client, error) {
fi, err := os.Open(fpath)
if err != nil {
return nil, err
}
defer func() {
if err := fi.Close(); err != nil {
panic(err)
}
}()
return NewClientFromReader(fi)
}
// NewClientFromReader creates a Client configured from a given reader.
// The configuration is expected to use the JSON format.
func NewClientFromReader(reader io.Reader) (*Client, error) {
c := new(Client)
b, err := ioutil.ReadAll(reader)
if err != nil {
return nil, err
}
err = json.Unmarshal(b, c)
if err != nil {
return nil, err
}
if c.config.CertFile == "" {
c.initHTTPClient()
} else {
err = c.initHTTPSClient(c.config.CertFile, c.config.KeyFile)
}
if err != nil {
return nil, err
}
for _, caCert := range c.config.CaCertFile {
if err := c.AddRootCA(caCert); err != nil {
return nil, err
}
}
return c, nil
}
// Override the Client's HTTP Transport object
func (c *Client) SetTransport(tr *http.Transport) {
c.httpClient.Transport = tr
c.transport = tr
}
func (c *Client) SetCredentials(username, password string) {
c.credentials = &credentials{username, password}
}
func (c *Client) Close() {
c.transport.DisableKeepAlives = true
c.transport.CloseIdleConnections()
}
// initHTTPClient initializes a HTTP client for etcd client
func (c *Client) initHTTPClient() {
c.transport = &http.Transport{
Dial: c.DefaultDial,
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
}
c.httpClient = &http.Client{Transport: c.transport}
}
// initHTTPClient initializes a HTTPS client for etcd client
func (c *Client) initHTTPSClient(cert, key string) error {
if cert == "" || key == "" {
return errors.New("Require both cert and key path")
}
tlsCert, err := tls.LoadX509KeyPair(cert, key)
if err != nil {
return err
}
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{tlsCert},
InsecureSkipVerify: true,
}
c.transport = &http.Transport{
TLSClientConfig: tlsConfig,
Dial: c.DefaultDial,
}
c.httpClient = &http.Client{Transport: c.transport}
return nil
}
// SetPersistence sets a writer to which the config will be
// written every time it's changed.
func (c *Client) SetPersistence(writer io.Writer) {
c.persistence = writer
}
// SetConsistency changes the consistency level of the client.
//
// When consistency is set to STRONG_CONSISTENCY, all requests,
// including GET, are sent to the leader. This means that, assuming
// the absence of leader failures, GET requests are guaranteed to see
// the changes made by previous requests.
//
// When consistency is set to WEAK_CONSISTENCY, other requests
// are still sent to the leader, but GET requests are sent to a
// random server from the server pool. This reduces the read
// load on the leader, but it's not guaranteed that the GET requests
// will see changes made by previous requests (they might have not
// yet been committed on non-leader servers).
func (c *Client) SetConsistency(consistency string) error {
if !(consistency == STRONG_CONSISTENCY || consistency == WEAK_CONSISTENCY) {
return errors.New("The argument must be either STRONG_CONSISTENCY or WEAK_CONSISTENCY.")
}
c.config.Consistency = consistency
return nil
}
// Sets the DialTimeout value
func (c *Client) SetDialTimeout(d time.Duration) {
c.config.DialTimeout = d
}
// AddRootCA adds a root CA cert for the etcd client
func (c *Client) AddRootCA(caCert string) error {
if c.httpClient == nil {
return errors.New("Client has not been initialized yet!")
}
certBytes, err := ioutil.ReadFile(caCert)
if err != nil {
return err
}
tr, ok := c.httpClient.Transport.(*http.Transport)
if !ok {
panic("AddRootCA(): Transport type assert should not fail")
}
if tr.TLSClientConfig.RootCAs == nil {
caCertPool := x509.NewCertPool()
ok = caCertPool.AppendCertsFromPEM(certBytes)
if ok {
tr.TLSClientConfig.RootCAs = caCertPool
}
tr.TLSClientConfig.InsecureSkipVerify = false
} else {
ok = tr.TLSClientConfig.RootCAs.AppendCertsFromPEM(certBytes)
}
if !ok {
err = errors.New("Unable to load caCert")
}
c.config.CaCertFile = append(c.config.CaCertFile, caCert)
c.saveConfig()
return err
}
// SetCluster updates cluster information using the given machine list.
func (c *Client) SetCluster(machines []string) bool {
success := c.internalSyncCluster(machines)
return success
}
func (c *Client) GetCluster() []string {
return c.cluster.Machines
}
// SyncCluster updates the cluster information using the internal machine list.
// If no members are found, the intenral machine list is left untouched.
func (c *Client) SyncCluster() bool {
return c.internalSyncCluster(c.cluster.Machines)
}
// internalSyncCluster syncs cluster information using the given machine list.
func (c *Client) internalSyncCluster(machines []string) bool {
// comma-separated list of machines in the cluster.
members := ""
for _, machine := range machines {
httpPath := c.createHttpPath(machine, path.Join(version, "members"))
resp, err := c.httpClient.Get(httpPath)
if err != nil {
// try another machine in the cluster
continue
}
if resp.StatusCode != http.StatusOK { // fall-back to old endpoint
httpPath := c.createHttpPath(machine, path.Join(version, "machines"))
resp, err := c.httpClient.Get(httpPath)
if err != nil {
// try another machine in the cluster
continue
}
b, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
// try another machine in the cluster
continue
}
members = string(b)
} else {
b, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
// try another machine in the cluster
continue
}
var mCollection memberCollection
if err := json.Unmarshal(b, &mCollection); err != nil {
// try another machine
continue
}
urls := make([]string, 0)
for _, m := range mCollection {
urls = append(urls, m.ClientURLs...)
}
members = strings.Join(urls, ",")
}
// We should never do an empty cluster update.
if members == "" {
continue
}
// update Machines List
c.cluster.updateFromStr(members)
logger.Debug("sync.machines ", c.cluster.Machines)
c.saveConfig()
return true
}
return false
}
// createHttpPath creates a complete HTTP URL.
// serverName should contain both the host name and a port number, if any.
func (c *Client) createHttpPath(serverName string, _path string) string {
u, err := url.Parse(serverName)
if err != nil {
panic(err)
}
u.Path = path.Join(u.Path, _path)
if u.Scheme == "" {
u.Scheme = "http"
}
return u.String()
}
// DefaultDial attempts to open a TCP connection to the provided address, explicitly
// enabling keep-alives with a one-second interval.
func (c *Client) DefaultDial(network, addr string) (net.Conn, error) {
dialer := net.Dialer{
Timeout: c.config.DialTimeout,
KeepAlive: time.Second,
}
return dialer.Dial(network, addr)
}
func (c *Client) OpenCURL() {
c.cURLch = make(chan string, defaultBufferSize)
}
func (c *Client) CloseCURL() {
c.cURLch = nil
}
func (c *Client) sendCURL(command string) {
go func() {
select {
case c.cURLch <- command:
default:
}
}()
}
func (c *Client) RecvCURL() string {
return <-c.cURLch
}
// saveConfig saves the current config using c.persistence.
func (c *Client) saveConfig() error {
if c.persistence != nil {
b, err := json.Marshal(c)
if err != nil {
return err
}
_, err = c.persistence.Write(b)
if err != nil {
return err
}
}
return nil
}
// MarshalJSON implements the Marshaller interface
// as defined by the standard JSON package.
func (c *Client) MarshalJSON() ([]byte, error) {
b, err := json.Marshal(struct {
Config Config `json:"config"`
Cluster *Cluster `json:"cluster"`
}{
Config: c.config,
Cluster: c.cluster,
})
if err != nil {
return nil, err
}
return b, nil
}
// UnmarshalJSON implements the Unmarshaller interface
// as defined by the standard JSON package.
func (c *Client) UnmarshalJSON(b []byte) error {
temp := struct {
Config Config `json:"config"`
Cluster *Cluster `json:"cluster"`
}{}
err := json.Unmarshal(b, &temp)
if err != nil {
return err
}
c.cluster = temp.Cluster
c.config = temp.Config
return nil
}

View File

@ -1,54 +0,0 @@
package etcd
import (
"math/rand"
"strings"
"sync"
)
type Cluster struct {
Leader string `json:"leader"`
Machines []string `json:"machines"`
picked int
mu sync.RWMutex
}
func NewCluster(machines []string) *Cluster {
// if an empty slice was sent in then just assume HTTP 4001 on localhost
if len(machines) == 0 {
machines = []string{"http://127.0.0.1:4001"}
}
machines = shuffleStringSlice(machines)
logger.Debug("Shuffle cluster machines", machines)
// default leader and machines
return &Cluster{
Leader: "",
Machines: machines,
picked: rand.Intn(len(machines)),
}
}
func (cl *Cluster) failure() {
cl.mu.Lock()
defer cl.mu.Unlock()
cl.picked = (cl.picked + 1) % len(cl.Machines)
}
func (cl *Cluster) pick() string {
cl.mu.Lock()
defer cl.mu.Unlock()
return cl.Machines[cl.picked]
}
func (cl *Cluster) updateFromStr(machines string) {
cl.mu.Lock()
defer cl.mu.Unlock()
cl.Machines = strings.Split(machines, ",")
for i := range cl.Machines {
cl.Machines[i] = strings.TrimSpace(cl.Machines[i])
}
cl.Machines = shuffleStringSlice(cl.Machines)
cl.picked = rand.Intn(len(cl.Machines))
}

View File

@ -1,34 +0,0 @@
package etcd
import "fmt"
func (c *Client) CompareAndDelete(key string, prevValue string, prevIndex uint64) (*Response, error) {
raw, err := c.RawCompareAndDelete(key, prevValue, prevIndex)
if err != nil {
return nil, err
}
return raw.Unmarshal()
}
func (c *Client) RawCompareAndDelete(key string, prevValue string, prevIndex uint64) (*RawResponse, error) {
if prevValue == "" && prevIndex == 0 {
return nil, fmt.Errorf("You must give either prevValue or prevIndex.")
}
options := Options{}
if prevValue != "" {
options["prevValue"] = prevValue
}
if prevIndex != 0 {
options["prevIndex"] = prevIndex
}
raw, err := c.delete(key, options)
if err != nil {
return nil, err
}
return raw, err
}

View File

@ -1,36 +0,0 @@
package etcd
import "fmt"
func (c *Client) CompareAndSwap(key string, value string, ttl uint64,
prevValue string, prevIndex uint64) (*Response, error) {
raw, err := c.RawCompareAndSwap(key, value, ttl, prevValue, prevIndex)
if err != nil {
return nil, err
}
return raw.Unmarshal()
}
func (c *Client) RawCompareAndSwap(key string, value string, ttl uint64,
prevValue string, prevIndex uint64) (*RawResponse, error) {
if prevValue == "" && prevIndex == 0 {
return nil, fmt.Errorf("You must give either prevValue or prevIndex.")
}
options := Options{}
if prevValue != "" {
options["prevValue"] = prevValue
}
if prevIndex != 0 {
options["prevIndex"] = prevIndex
}
raw, err := c.put(key, value, ttl, options)
if err != nil {
return nil, err
}
return raw, err
}

View File

@ -1,55 +0,0 @@
package etcd
import (
"fmt"
"io/ioutil"
"log"
"strings"
)
var logger *etcdLogger
func SetLogger(l *log.Logger) {
logger = &etcdLogger{l}
}
func GetLogger() *log.Logger {
return logger.log
}
type etcdLogger struct {
log *log.Logger
}
func (p *etcdLogger) Debug(args ...interface{}) {
msg := "DEBUG: " + fmt.Sprint(args...)
p.log.Println(msg)
}
func (p *etcdLogger) Debugf(f string, args ...interface{}) {
msg := "DEBUG: " + fmt.Sprintf(f, args...)
// Append newline if necessary
if !strings.HasSuffix(msg, "\n") {
msg = msg + "\n"
}
p.log.Print(msg)
}
func (p *etcdLogger) Warning(args ...interface{}) {
msg := "WARNING: " + fmt.Sprint(args...)
p.log.Println(msg)
}
func (p *etcdLogger) Warningf(f string, args ...interface{}) {
msg := "WARNING: " + fmt.Sprintf(f, args...)
// Append newline if necessary
if !strings.HasSuffix(msg, "\n") {
msg = msg + "\n"
}
p.log.Print(msg)
}
func init() {
// Default logger uses the go default log.
SetLogger(log.New(ioutil.Discard, "go-etcd", log.LstdFlags))
}

View File

@ -1,40 +0,0 @@
package etcd
// Delete deletes the given key.
//
// When recursive set to false, if the key points to a
// directory the method will fail.
//
// When recursive set to true, if the key points to a file,
// the file will be deleted; if the key points to a directory,
// then everything under the directory (including all child directories)
// will be deleted.
func (c *Client) Delete(key string, recursive bool) (*Response, error) {
raw, err := c.RawDelete(key, recursive, false)
if err != nil {
return nil, err
}
return raw.Unmarshal()
}
// DeleteDir deletes an empty directory or a key value pair
func (c *Client) DeleteDir(key string) (*Response, error) {
raw, err := c.RawDelete(key, false, true)
if err != nil {
return nil, err
}
return raw.Unmarshal()
}
func (c *Client) RawDelete(key string, recursive bool, dir bool) (*RawResponse, error) {
ops := Options{
"recursive": recursive,
"dir": dir,
}
return c.delete(key, ops)
}

View File

@ -1,49 +0,0 @@
package etcd
import (
"encoding/json"
"fmt"
)
const (
ErrCodeEtcdNotReachable = 501
ErrCodeUnhandledHTTPStatus = 502
)
var (
errorMap = map[int]string{
ErrCodeEtcdNotReachable: "All the given peers are not reachable",
}
)
type EtcdError struct {
ErrorCode int `json:"errorCode"`
Message string `json:"message"`
Cause string `json:"cause,omitempty"`
Index uint64 `json:"index"`
}
func (e EtcdError) Error() string {
return fmt.Sprintf("%v: %v (%v) [%v]", e.ErrorCode, e.Message, e.Cause, e.Index)
}
func newError(errorCode int, cause string, index uint64) *EtcdError {
return &EtcdError{
ErrorCode: errorCode,
Message: errorMap[errorCode],
Cause: cause,
Index: index,
}
}
func handleError(b []byte) error {
etcdErr := new(EtcdError)
err := json.Unmarshal(b, etcdErr)
if err != nil {
logger.Warningf("cannot unmarshal etcd error: %v", err)
return err
}
return etcdErr
}

View File

@ -1,32 +0,0 @@
package etcd
// Get gets the file or directory associated with the given key.
// If the key points to a directory, files and directories under
// it will be returned in sorted or unsorted order, depending on
// the sort flag.
// If recursive is set to false, contents under child directories
// will not be returned.
// If recursive is set to true, all the contents will be returned.
func (c *Client) Get(key string, sort, recursive bool) (*Response, error) {
raw, err := c.RawGet(key, sort, recursive)
if err != nil {
return nil, err
}
return raw.Unmarshal()
}
func (c *Client) RawGet(key string, sort, recursive bool) (*RawResponse, error) {
var q bool
if c.config.Consistency == STRONG_CONSISTENCY {
q = true
}
ops := Options{
"recursive": recursive,
"sorted": sort,
"quorum": q,
}
return c.get(key, ops)
}

View File

@ -1,30 +0,0 @@
package etcd
import "encoding/json"
type Member struct {
ID string `json:"id"`
Name string `json:"name"`
PeerURLs []string `json:"peerURLs"`
ClientURLs []string `json:"clientURLs"`
}
type memberCollection []Member
func (c *memberCollection) UnmarshalJSON(data []byte) error {
d := struct {
Members []Member
}{}
if err := json.Unmarshal(data, &d); err != nil {
return err
}
if d.Members == nil {
*c = make([]Member, 0)
return nil
}
*c = d.Members
return nil
}

View File

@ -1,72 +0,0 @@
package etcd
import (
"fmt"
"net/url"
"reflect"
)
type Options map[string]interface{}
// An internally-used data structure that represents a mapping
// between valid options and their kinds
type validOptions map[string]reflect.Kind
// Valid options for GET, PUT, POST, DELETE
// Using CAPITALIZED_UNDERSCORE to emphasize that these
// values are meant to be used as constants.
var (
VALID_GET_OPTIONS = validOptions{
"recursive": reflect.Bool,
"quorum": reflect.Bool,
"sorted": reflect.Bool,
"wait": reflect.Bool,
"waitIndex": reflect.Uint64,
}
VALID_PUT_OPTIONS = validOptions{
"prevValue": reflect.String,
"prevIndex": reflect.Uint64,
"prevExist": reflect.Bool,
"dir": reflect.Bool,
}
VALID_POST_OPTIONS = validOptions{}
VALID_DELETE_OPTIONS = validOptions{
"recursive": reflect.Bool,
"dir": reflect.Bool,
"prevValue": reflect.String,
"prevIndex": reflect.Uint64,
}
)
// Convert options to a string of HTML parameters
func (ops Options) toParameters(validOps validOptions) (string, error) {
p := "?"
values := url.Values{}
if ops == nil {
return "", nil
}
for k, v := range ops {
// Check if the given option is valid (that it exists)
kind := validOps[k]
if kind == reflect.Invalid {
return "", fmt.Errorf("Invalid option: %v", k)
}
// Check if the given option is of the valid type
t := reflect.TypeOf(v)
if kind != t.Kind() {
return "", fmt.Errorf("Option %s should be of %v kind, not of %v kind.",
k, kind, t.Kind())
}
values.Set(k, fmt.Sprintf("%v", v))
}
p += values.Encode()
return p, nil
}

View File

@ -1,403 +0,0 @@
package etcd
import (
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"path"
"strings"
"sync"
"time"
)
// Errors introduced by handling requests
var (
ErrRequestCancelled = errors.New("sending request is cancelled")
)
type RawRequest struct {
Method string
RelativePath string
Values url.Values
Cancel <-chan bool
}
// NewRawRequest returns a new RawRequest
func NewRawRequest(method, relativePath string, values url.Values, cancel <-chan bool) *RawRequest {
return &RawRequest{
Method: method,
RelativePath: relativePath,
Values: values,
Cancel: cancel,
}
}
// getCancelable issues a cancelable GET request
func (c *Client) getCancelable(key string, options Options,
cancel <-chan bool) (*RawResponse, error) {
logger.Debugf("get %s [%s]", key, c.cluster.pick())
p := keyToPath(key)
str, err := options.toParameters(VALID_GET_OPTIONS)
if err != nil {
return nil, err
}
p += str
req := NewRawRequest("GET", p, nil, cancel)
resp, err := c.SendRequest(req)
if err != nil {
return nil, err
}
return resp, nil
}
// get issues a GET request
func (c *Client) get(key string, options Options) (*RawResponse, error) {
return c.getCancelable(key, options, nil)
}
// put issues a PUT request
func (c *Client) put(key string, value string, ttl uint64,
options Options) (*RawResponse, error) {
logger.Debugf("put %s, %s, ttl: %d, [%s]", key, value, ttl, c.cluster.pick())
p := keyToPath(key)
str, err := options.toParameters(VALID_PUT_OPTIONS)
if err != nil {
return nil, err
}
p += str
req := NewRawRequest("PUT", p, buildValues(value, ttl), nil)
resp, err := c.SendRequest(req)
if err != nil {
return nil, err
}
return resp, nil
}
// post issues a POST request
func (c *Client) post(key string, value string, ttl uint64) (*RawResponse, error) {
logger.Debugf("post %s, %s, ttl: %d, [%s]", key, value, ttl, c.cluster.pick())
p := keyToPath(key)
req := NewRawRequest("POST", p, buildValues(value, ttl), nil)
resp, err := c.SendRequest(req)
if err != nil {
return nil, err
}
return resp, nil
}
// delete issues a DELETE request
func (c *Client) delete(key string, options Options) (*RawResponse, error) {
logger.Debugf("delete %s [%s]", key, c.cluster.pick())
p := keyToPath(key)
str, err := options.toParameters(VALID_DELETE_OPTIONS)
if err != nil {
return nil, err
}
p += str
req := NewRawRequest("DELETE", p, nil, nil)
resp, err := c.SendRequest(req)
if err != nil {
return nil, err
}
return resp, nil
}
// SendRequest sends a HTTP request and returns a Response as defined by etcd
func (c *Client) SendRequest(rr *RawRequest) (*RawResponse, error) {
var req *http.Request
var resp *http.Response
var httpPath string
var err error
var respBody []byte
var numReqs = 1
checkRetry := c.CheckRetry
if checkRetry == nil {
checkRetry = DefaultCheckRetry
}
cancelled := make(chan bool, 1)
reqLock := new(sync.Mutex)
if rr.Cancel != nil {
cancelRoutine := make(chan bool)
defer close(cancelRoutine)
go func() {
select {
case <-rr.Cancel:
cancelled <- true
logger.Debug("send.request is cancelled")
case <-cancelRoutine:
return
}
// Repeat canceling request until this thread is stopped
// because we have no idea about whether it succeeds.
for {
reqLock.Lock()
c.httpClient.Transport.(*http.Transport).CancelRequest(req)
reqLock.Unlock()
select {
case <-time.After(100 * time.Millisecond):
case <-cancelRoutine:
return
}
}
}()
}
// If we connect to a follower and consistency is required, retry until
// we connect to a leader
sleep := 25 * time.Millisecond
maxSleep := time.Second
for attempt := 0; ; attempt++ {
if attempt > 0 {
select {
case <-cancelled:
return nil, ErrRequestCancelled
case <-time.After(sleep):
sleep = sleep * 2
if sleep > maxSleep {
sleep = maxSleep
}
}
}
logger.Debug("Connecting to etcd: attempt ", attempt+1, " for ", rr.RelativePath)
// get httpPath if not set
if httpPath == "" {
httpPath = c.getHttpPath(rr.RelativePath)
}
// Return a cURL command if curlChan is set
if c.cURLch != nil {
command := fmt.Sprintf("curl -X %s %s", rr.Method, httpPath)
for key, value := range rr.Values {
command += fmt.Sprintf(" -d %s=%s", key, value[0])
}
if c.credentials != nil {
command += fmt.Sprintf(" -u %s", c.credentials.username)
}
c.sendCURL(command)
}
logger.Debug("send.request.to ", httpPath, " | method ", rr.Method)
req, err := func() (*http.Request, error) {
reqLock.Lock()
defer reqLock.Unlock()
if rr.Values == nil {
if req, err = http.NewRequest(rr.Method, httpPath, nil); err != nil {
return nil, err
}
} else {
body := strings.NewReader(rr.Values.Encode())
if req, err = http.NewRequest(rr.Method, httpPath, body); err != nil {
return nil, err
}
req.Header.Set("Content-Type",
"application/x-www-form-urlencoded; param=value")
}
return req, nil
}()
if err != nil {
return nil, err
}
if c.credentials != nil {
req.SetBasicAuth(c.credentials.username, c.credentials.password)
}
resp, err = c.httpClient.Do(req)
// clear previous httpPath
httpPath = ""
defer func() {
if resp != nil {
resp.Body.Close()
}
}()
// If the request was cancelled, return ErrRequestCancelled directly
select {
case <-cancelled:
return nil, ErrRequestCancelled
default:
}
numReqs++
// network error, change a machine!
if err != nil {
logger.Debug("network error: ", err.Error())
lastResp := http.Response{}
if checkErr := checkRetry(c.cluster, numReqs, lastResp, err); checkErr != nil {
return nil, checkErr
}
c.cluster.failure()
continue
}
// if there is no error, it should receive response
logger.Debug("recv.response.from ", httpPath)
if validHttpStatusCode[resp.StatusCode] {
// try to read byte code and break the loop
respBody, err = ioutil.ReadAll(resp.Body)
if err == nil {
logger.Debug("recv.success ", httpPath)
break
}
// ReadAll error may be caused due to cancel request
select {
case <-cancelled:
return nil, ErrRequestCancelled
default:
}
if err == io.ErrUnexpectedEOF {
// underlying connection was closed prematurely, probably by timeout
// TODO: empty body or unexpectedEOF can cause http.Transport to get hosed;
// this allows the client to detect that and take evasive action. Need
// to revisit once code.google.com/p/go/issues/detail?id=8648 gets fixed.
respBody = []byte{}
break
}
}
if resp.StatusCode == http.StatusTemporaryRedirect {
u, err := resp.Location()
if err != nil {
logger.Warning(err)
} else {
// set httpPath for following redirection
httpPath = u.String()
}
resp.Body.Close()
continue
}
if checkErr := checkRetry(c.cluster, numReqs, *resp,
errors.New("Unexpected HTTP status code")); checkErr != nil {
return nil, checkErr
}
resp.Body.Close()
}
r := &RawResponse{
StatusCode: resp.StatusCode,
Body: respBody,
Header: resp.Header,
}
return r, nil
}
// DefaultCheckRetry defines the retrying behaviour for bad HTTP requests
// If we have retried 2 * machine number, stop retrying.
// If status code is InternalServerError, sleep for 200ms.
func DefaultCheckRetry(cluster *Cluster, numReqs int, lastResp http.Response,
err error) error {
if numReqs > 2*len(cluster.Machines) {
errStr := fmt.Sprintf("failed to propose on members %v twice [last error: %v]", cluster.Machines, err)
return newError(ErrCodeEtcdNotReachable, errStr, 0)
}
if isEmptyResponse(lastResp) {
// always retry if it failed to get response from one machine
return nil
}
if !shouldRetry(lastResp) {
body := []byte("nil")
if lastResp.Body != nil {
if b, err := ioutil.ReadAll(lastResp.Body); err == nil {
body = b
}
}
errStr := fmt.Sprintf("unhandled http status [%s] with body [%s]", http.StatusText(lastResp.StatusCode), body)
return newError(ErrCodeUnhandledHTTPStatus, errStr, 0)
}
// sleep some time and expect leader election finish
time.Sleep(time.Millisecond * 200)
logger.Warning("bad response status code ", lastResp.StatusCode)
return nil
}
func isEmptyResponse(r http.Response) bool { return r.StatusCode == 0 }
// shouldRetry returns whether the reponse deserves retry.
func shouldRetry(r http.Response) bool {
// TODO: only retry when the cluster is in leader election
// We cannot do it exactly because etcd doesn't support it well.
return r.StatusCode == http.StatusInternalServerError
}
func (c *Client) getHttpPath(s ...string) string {
fullPath := c.cluster.pick() + "/" + version
for _, seg := range s {
fullPath = fullPath + "/" + seg
}
return fullPath
}
// buildValues builds a url.Values map according to the given value and ttl
func buildValues(value string, ttl uint64) url.Values {
v := url.Values{}
if value != "" {
v.Set("value", value)
}
if ttl > 0 {
v.Set("ttl", fmt.Sprintf("%v", ttl))
}
return v
}
// convert key string to http path exclude version, including URL escaping
// for example: key[foo] -> path[keys/foo]
// key[/%z] -> path[keys/%25z]
// key[/] -> path[keys/]
func keyToPath(key string) string {
// URL-escape our key, except for slashes
p := strings.Replace(url.QueryEscape(path.Join("keys", key)), "%2F", "/", -1)
// corner case: if key is "/" or "//" ect
// path join will clear the tailing "/"
// we need to add it back
if p == "keys" {
p = "keys/"
}
return p
}

File diff suppressed because it is too large Load Diff

View File

@ -1,93 +0,0 @@
package etcd
//go:generate codecgen -d 1978 -o response.generated.go response.go
import (
"net/http"
"strconv"
"time"
"github.com/ugorji/go/codec"
)
const (
rawResponse = iota
normalResponse
)
type responseType int
type RawResponse struct {
StatusCode int
Body []byte
Header http.Header
}
var (
validHttpStatusCode = map[int]bool{
http.StatusCreated: true,
http.StatusOK: true,
http.StatusBadRequest: true,
http.StatusNotFound: true,
http.StatusPreconditionFailed: true,
http.StatusForbidden: true,
http.StatusUnauthorized: true,
}
)
// Unmarshal parses RawResponse and stores the result in Response
func (rr *RawResponse) Unmarshal() (*Response, error) {
if rr.StatusCode != http.StatusOK && rr.StatusCode != http.StatusCreated {
return nil, handleError(rr.Body)
}
resp := new(Response)
err := codec.NewDecoderBytes(rr.Body, new(codec.JsonHandle)).Decode(resp)
if err != nil {
return nil, err
}
// attach index and term to response
resp.EtcdIndex, _ = strconv.ParseUint(rr.Header.Get("X-Etcd-Index"), 10, 64)
resp.RaftIndex, _ = strconv.ParseUint(rr.Header.Get("X-Raft-Index"), 10, 64)
resp.RaftTerm, _ = strconv.ParseUint(rr.Header.Get("X-Raft-Term"), 10, 64)
return resp, nil
}
type Response struct {
Action string `json:"action"`
Node *Node `json:"node"`
PrevNode *Node `json:"prevNode,omitempty"`
EtcdIndex uint64 `json:"etcdIndex"`
RaftIndex uint64 `json:"raftIndex"`
RaftTerm uint64 `json:"raftTerm"`
}
type Node struct {
Key string `json:"key, omitempty"`
Value string `json:"value,omitempty"`
Dir bool `json:"dir,omitempty"`
Expiration *time.Time `json:"expiration,omitempty"`
TTL int64 `json:"ttl,omitempty"`
Nodes Nodes `json:"nodes,omitempty"`
ModifiedIndex uint64 `json:"modifiedIndex,omitempty"`
CreatedIndex uint64 `json:"createdIndex,omitempty"`
}
type Nodes []*Node
// interfaces for sorting
func (ns Nodes) Len() int {
return len(ns)
}
func (ns Nodes) Less(i, j int) bool {
return ns[i].Key < ns[j].Key
}
func (ns Nodes) Swap(i, j int) {
ns[i], ns[j] = ns[j], ns[i]
}

View File

@ -1,137 +0,0 @@
package etcd
// Set sets the given key to the given value.
// It will create a new key value pair or replace the old one.
// It will not replace a existing directory.
func (c *Client) Set(key string, value string, ttl uint64) (*Response, error) {
raw, err := c.RawSet(key, value, ttl)
if err != nil {
return nil, err
}
return raw.Unmarshal()
}
// SetDir sets the given key to a directory.
// It will create a new directory or replace the old key value pair by a directory.
// It will not replace a existing directory.
func (c *Client) SetDir(key string, ttl uint64) (*Response, error) {
raw, err := c.RawSetDir(key, ttl)
if err != nil {
return nil, err
}
return raw.Unmarshal()
}
// CreateDir creates a directory. It succeeds only if
// the given key does not yet exist.
func (c *Client) CreateDir(key string, ttl uint64) (*Response, error) {
raw, err := c.RawCreateDir(key, ttl)
if err != nil {
return nil, err
}
return raw.Unmarshal()
}
// UpdateDir updates the given directory. It succeeds only if the
// given key already exists.
func (c *Client) UpdateDir(key string, ttl uint64) (*Response, error) {
raw, err := c.RawUpdateDir(key, ttl)
if err != nil {
return nil, err
}
return raw.Unmarshal()
}
// Create creates a file with the given value under the given key. It succeeds
// only if the given key does not yet exist.
func (c *Client) Create(key string, value string, ttl uint64) (*Response, error) {
raw, err := c.RawCreate(key, value, ttl)
if err != nil {
return nil, err
}
return raw.Unmarshal()
}
// CreateInOrder creates a file with a key that's guaranteed to be higher than other
// keys in the given directory. It is useful for creating queues.
func (c *Client) CreateInOrder(dir string, value string, ttl uint64) (*Response, error) {
raw, err := c.RawCreateInOrder(dir, value, ttl)
if err != nil {
return nil, err
}
return raw.Unmarshal()
}
// Update updates the given key to the given value. It succeeds only if the
// given key already exists.
func (c *Client) Update(key string, value string, ttl uint64) (*Response, error) {
raw, err := c.RawUpdate(key, value, ttl)
if err != nil {
return nil, err
}
return raw.Unmarshal()
}
func (c *Client) RawUpdateDir(key string, ttl uint64) (*RawResponse, error) {
ops := Options{
"prevExist": true,
"dir": true,
}
return c.put(key, "", ttl, ops)
}
func (c *Client) RawCreateDir(key string, ttl uint64) (*RawResponse, error) {
ops := Options{
"prevExist": false,
"dir": true,
}
return c.put(key, "", ttl, ops)
}
func (c *Client) RawSet(key string, value string, ttl uint64) (*RawResponse, error) {
return c.put(key, value, ttl, nil)
}
func (c *Client) RawSetDir(key string, ttl uint64) (*RawResponse, error) {
ops := Options{
"dir": true,
}
return c.put(key, "", ttl, ops)
}
func (c *Client) RawUpdate(key string, value string, ttl uint64) (*RawResponse, error) {
ops := Options{
"prevExist": true,
}
return c.put(key, value, ttl, ops)
}
func (c *Client) RawCreate(key string, value string, ttl uint64) (*RawResponse, error) {
ops := Options{
"prevExist": false,
}
return c.put(key, value, ttl, ops)
}
func (c *Client) RawCreateInOrder(dir string, value string, ttl uint64) (*RawResponse, error) {
return c.post(dir, value, ttl)
}

View File

@ -1,19 +0,0 @@
package etcd
import (
"math/rand"
)
func shuffleStringSlice(cards []string) []string {
size := len(cards)
//Do not need to copy if nothing changed
if size <= 1 {
return cards
}
shuffled := make([]string, size)
index := rand.Perm(size)
for i := range cards {
shuffled[index[i]] = cards[i]
}
return shuffled
}

View File

@ -1,6 +0,0 @@
package etcd
const (
version = "v2"
packageVersion = "v2.0.0+git"
)

View File

@ -1,103 +0,0 @@
package etcd
import (
"errors"
)
// Errors introduced by the Watch command.
var (
ErrWatchStoppedByUser = errors.New("Watch stopped by the user via stop channel")
)
// If recursive is set to true the watch returns the first change under the given
// prefix since the given index.
//
// If recursive is set to false the watch returns the first change to the given key
// since the given index.
//
// To watch for the latest change, set waitIndex = 0.
//
// If a receiver channel is given, it will be a long-term watch. Watch will block at the
//channel. After someone receives the channel, it will go on to watch that
// prefix. If a stop channel is given, the client can close long-term watch using
// the stop channel.
func (c *Client) Watch(prefix string, waitIndex uint64, recursive bool,
receiver chan *Response, stop chan bool) (*Response, error) {
logger.Debugf("watch %s [%s]", prefix, c.cluster.Leader)
if receiver == nil {
raw, err := c.watchOnce(prefix, waitIndex, recursive, stop)
if err != nil {
return nil, err
}
return raw.Unmarshal()
}
defer close(receiver)
for {
raw, err := c.watchOnce(prefix, waitIndex, recursive, stop)
if err != nil {
return nil, err
}
resp, err := raw.Unmarshal()
if err != nil {
return nil, err
}
waitIndex = resp.Node.ModifiedIndex + 1
receiver <- resp
}
}
func (c *Client) RawWatch(prefix string, waitIndex uint64, recursive bool,
receiver chan *RawResponse, stop chan bool) (*RawResponse, error) {
logger.Debugf("rawWatch %s [%s]", prefix, c.cluster.Leader)
if receiver == nil {
return c.watchOnce(prefix, waitIndex, recursive, stop)
}
for {
raw, err := c.watchOnce(prefix, waitIndex, recursive, stop)
if err != nil {
return nil, err
}
resp, err := raw.Unmarshal()
if err != nil {
return nil, err
}
waitIndex = resp.Node.ModifiedIndex + 1
receiver <- raw
}
}
// helper func
// return when there is change under the given prefix
func (c *Client) watchOnce(key string, waitIndex uint64, recursive bool, stop chan bool) (*RawResponse, error) {
options := Options{
"wait": true,
}
if waitIndex > 0 {
options["waitIndex"] = waitIndex
}
if recursive {
options["recursive"] = true
}
resp, err := c.getCancelable(key, options, stop)
if err == ErrRequestCancelled {
return nil, ErrWatchStoppedByUser
}
return resp, err
}

View File

@ -12,34 +12,63 @@
# Individual Persons # Individual Persons
Aaron Hopkins <go-sql-driver at die.net> Aaron Hopkins <go-sql-driver at die.net>
Achille Roussel <achille.roussel at gmail.com>
Alexey Palazhchenko <alexey.palazhchenko at gmail.com>
Andrew Reid <andrew.reid at tixtrack.com>
Arne Hormann <arnehormann at gmail.com> Arne Hormann <arnehormann at gmail.com>
Asta Xie <xiemengjun at gmail.com>
Bulat Gaifullin <gaifullinbf at gmail.com>
Carlos Nieto <jose.carlos at menteslibres.net> Carlos Nieto <jose.carlos at menteslibres.net>
Chris Moos <chris at tech9computers.com> Chris Moos <chris at tech9computers.com>
Craig Wilson <craiggwilson at gmail.com>
Daniel Montoya <dsmontoyam at gmail.com>
Daniel Nichter <nil at codenode.com> Daniel Nichter <nil at codenode.com>
Daniël van Eeden <git at myname.nl> Daniël van Eeden <git at myname.nl>
Dave Protasowski <dprotaso at gmail.com>
DisposaBoy <disposaboy at dby.me> DisposaBoy <disposaboy at dby.me>
Egor Smolyakov <egorsmkv at gmail.com>
Evan Shaw <evan at vendhq.com>
Frederick Mayle <frederickmayle at gmail.com> Frederick Mayle <frederickmayle at gmail.com>
Gustavo Kristic <gkristic at gmail.com> Gustavo Kristic <gkristic at gmail.com>
Hajime Nakagami <nakagami at gmail.com>
Hanno Braun <mail at hannobraun.com> Hanno Braun <mail at hannobraun.com>
Henri Yandell <flamefew at gmail.com> Henri Yandell <flamefew at gmail.com>
Hirotaka Yamamoto <ymmt2005 at gmail.com> Hirotaka Yamamoto <ymmt2005 at gmail.com>
ICHINOSE Shogo <shogo82148 at gmail.com>
INADA Naoki <songofacandy at gmail.com> INADA Naoki <songofacandy at gmail.com>
Jacek Szwec <szwec.jacek at gmail.com>
James Harr <james.harr at gmail.com> James Harr <james.harr at gmail.com>
Jeff Hodges <jeff at somethingsimilar.com>
Jeffrey Charles <jeffreycharles at gmail.com>
Jian Zhen <zhenjl at gmail.com> Jian Zhen <zhenjl at gmail.com>
Joshua Prunier <joshua.prunier at gmail.com> Joshua Prunier <joshua.prunier at gmail.com>
Julien Lefevre <julien.lefevr at gmail.com> Julien Lefevre <julien.lefevr at gmail.com>
Julien Schmidt <go-sql-driver at julienschmidt.com> Julien Schmidt <go-sql-driver at julienschmidt.com>
Justin Li <jli at j-li.net>
Justin Nuß <nuss.justin at gmail.com>
Kamil Dziedzic <kamil at klecza.pl> Kamil Dziedzic <kamil at klecza.pl>
Kevin Malachowski <kevin at chowski.com> Kevin Malachowski <kevin at chowski.com>
Kieron Woodhouse <kieron.woodhouse at infosum.com>
Lennart Rudolph <lrudolph at hmc.edu> Lennart Rudolph <lrudolph at hmc.edu>
Leonardo YongUk Kim <dalinaum at gmail.com> Leonardo YongUk Kim <dalinaum at gmail.com>
Linh Tran Tuan <linhduonggnu at gmail.com>
Lion Yang <lion at aosc.xyz>
Luca Looz <luca.looz92 at gmail.com> Luca Looz <luca.looz92 at gmail.com>
Lucas Liu <extrafliu at gmail.com> Lucas Liu <extrafliu at gmail.com>
Luke Scott <luke at webconnex.com> Luke Scott <luke at webconnex.com>
Maciej Zimnoch <maciej.zimnoch at codilime.com>
Michael Woolnough <michael.woolnough at gmail.com> Michael Woolnough <michael.woolnough at gmail.com>
Nicola Peduzzi <thenikso at gmail.com> Nicola Peduzzi <thenikso at gmail.com>
Olivier Mengué <dolmen at cpan.org>
oscarzhao <oscarzhaosl at gmail.com>
Paul Bonser <misterpib at gmail.com> Paul Bonser <misterpib at gmail.com>
Peter Schultz <peter.schultz at classmarkets.com>
Rebecca Chin <rchin at pivotal.io>
Reed Allman <rdallman10 at gmail.com>
Richard Wilkes <wilkes at me.com>
Robert Russell <robert at rrbrussell.com>
Runrioter Wung <runrioter at gmail.com> Runrioter Wung <runrioter at gmail.com>
Shuode Li <elemount at qq.com>
Soroush Pour <me at soroushjp.com> Soroush Pour <me at soroushjp.com>
Stan Putrya <root.vagner at gmail.com> Stan Putrya <root.vagner at gmail.com>
Stanley Gunawan <gunawan.stanley at gmail.com> Stanley Gunawan <gunawan.stanley at gmail.com>
@ -51,5 +80,10 @@ Zhenye Xie <xiezhenye at gmail.com>
# Organizations # Organizations
Barracuda Networks, Inc. Barracuda Networks, Inc.
Counting Ltd.
Google Inc. Google Inc.
InfoSum Ltd.
Keybase Inc.
Percona LLC
Pivotal Inc.
Stripe Inc. Stripe Inc.

View File

@ -11,7 +11,7 @@
package mysql package mysql
import ( import (
"appengine/cloudsql" "google.golang.org/appengine/cloudsql"
) )
func init() { func init() {

420
vendor/github.com/go-sql-driver/mysql/auth.go generated vendored Normal file
View File

@ -0,0 +1,420 @@
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
//
// Copyright 2018 The Go-MySQL-Driver Authors. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.
package mysql
import (
"crypto/rand"
"crypto/rsa"
"crypto/sha1"
"crypto/sha256"
"crypto/x509"
"encoding/pem"
"sync"
)
// server pub keys registry
var (
serverPubKeyLock sync.RWMutex
serverPubKeyRegistry map[string]*rsa.PublicKey
)
// RegisterServerPubKey registers a server RSA public key which can be used to
// send data in a secure manner to the server without receiving the public key
// in a potentially insecure way from the server first.
// Registered keys can afterwards be used adding serverPubKey=<name> to the DSN.
//
// Note: The provided rsa.PublicKey instance is exclusively owned by the driver
// after registering it and may not be modified.
//
// data, err := ioutil.ReadFile("mykey.pem")
// if err != nil {
// log.Fatal(err)
// }
//
// block, _ := pem.Decode(data)
// if block == nil || block.Type != "PUBLIC KEY" {
// log.Fatal("failed to decode PEM block containing public key")
// }
//
// pub, err := x509.ParsePKIXPublicKey(block.Bytes)
// if err != nil {
// log.Fatal(err)
// }
//
// if rsaPubKey, ok := pub.(*rsa.PublicKey); ok {
// mysql.RegisterServerPubKey("mykey", rsaPubKey)
// } else {
// log.Fatal("not a RSA public key")
// }
//
func RegisterServerPubKey(name string, pubKey *rsa.PublicKey) {
serverPubKeyLock.Lock()
if serverPubKeyRegistry == nil {
serverPubKeyRegistry = make(map[string]*rsa.PublicKey)
}
serverPubKeyRegistry[name] = pubKey
serverPubKeyLock.Unlock()
}
// DeregisterServerPubKey removes the public key registered with the given name.
func DeregisterServerPubKey(name string) {
serverPubKeyLock.Lock()
if serverPubKeyRegistry != nil {
delete(serverPubKeyRegistry, name)
}
serverPubKeyLock.Unlock()
}
func getServerPubKey(name string) (pubKey *rsa.PublicKey) {
serverPubKeyLock.RLock()
if v, ok := serverPubKeyRegistry[name]; ok {
pubKey = v
}
serverPubKeyLock.RUnlock()
return
}
// Hash password using pre 4.1 (old password) method
// https://github.com/atcurtis/mariadb/blob/master/mysys/my_rnd.c
type myRnd struct {
seed1, seed2 uint32
}
const myRndMaxVal = 0x3FFFFFFF
// Pseudo random number generator
func newMyRnd(seed1, seed2 uint32) *myRnd {
return &myRnd{
seed1: seed1 % myRndMaxVal,
seed2: seed2 % myRndMaxVal,
}
}
// Tested to be equivalent to MariaDB's floating point variant
// http://play.golang.org/p/QHvhd4qved
// http://play.golang.org/p/RG0q4ElWDx
func (r *myRnd) NextByte() byte {
r.seed1 = (r.seed1*3 + r.seed2) % myRndMaxVal
r.seed2 = (r.seed1 + r.seed2 + 33) % myRndMaxVal
return byte(uint64(r.seed1) * 31 / myRndMaxVal)
}
// Generate binary hash from byte string using insecure pre 4.1 method
func pwHash(password []byte) (result [2]uint32) {
var add uint32 = 7
var tmp uint32
result[0] = 1345345333
result[1] = 0x12345671
for _, c := range password {
// skip spaces and tabs in password
if c == ' ' || c == '\t' {
continue
}
tmp = uint32(c)
result[0] ^= (((result[0] & 63) + add) * tmp) + (result[0] << 8)
result[1] += (result[1] << 8) ^ result[0]
add += tmp
}
// Remove sign bit (1<<31)-1)
result[0] &= 0x7FFFFFFF
result[1] &= 0x7FFFFFFF
return
}
// Hash password using insecure pre 4.1 method
func scrambleOldPassword(scramble []byte, password string) []byte {
if len(password) == 0 {
return nil
}
scramble = scramble[:8]
hashPw := pwHash([]byte(password))
hashSc := pwHash(scramble)
r := newMyRnd(hashPw[0]^hashSc[0], hashPw[1]^hashSc[1])
var out [8]byte
for i := range out {
out[i] = r.NextByte() + 64
}
mask := r.NextByte()
for i := range out {
out[i] ^= mask
}
return out[:]
}
// Hash password using 4.1+ method (SHA1)
func scramblePassword(scramble []byte, password string) []byte {
if len(password) == 0 {
return nil
}
// stage1Hash = SHA1(password)
crypt := sha1.New()
crypt.Write([]byte(password))
stage1 := crypt.Sum(nil)
// scrambleHash = SHA1(scramble + SHA1(stage1Hash))
// inner Hash
crypt.Reset()
crypt.Write(stage1)
hash := crypt.Sum(nil)
// outer Hash
crypt.Reset()
crypt.Write(scramble)
crypt.Write(hash)
scramble = crypt.Sum(nil)
// token = scrambleHash XOR stage1Hash
for i := range scramble {
scramble[i] ^= stage1[i]
}
return scramble
}
// Hash password using MySQL 8+ method (SHA256)
func scrambleSHA256Password(scramble []byte, password string) []byte {
if len(password) == 0 {
return nil
}
// XOR(SHA256(password), SHA256(SHA256(SHA256(password)), scramble))
crypt := sha256.New()
crypt.Write([]byte(password))
message1 := crypt.Sum(nil)
crypt.Reset()
crypt.Write(message1)
message1Hash := crypt.Sum(nil)
crypt.Reset()
crypt.Write(message1Hash)
crypt.Write(scramble)
message2 := crypt.Sum(nil)
for i := range message1 {
message1[i] ^= message2[i]
}
return message1
}
func encryptPassword(password string, seed []byte, pub *rsa.PublicKey) ([]byte, error) {
plain := make([]byte, len(password)+1)
copy(plain, password)
for i := range plain {
j := i % len(seed)
plain[i] ^= seed[j]
}
sha1 := sha1.New()
return rsa.EncryptOAEP(sha1, rand.Reader, pub, plain, nil)
}
func (mc *mysqlConn) sendEncryptedPassword(seed []byte, pub *rsa.PublicKey) error {
enc, err := encryptPassword(mc.cfg.Passwd, seed, pub)
if err != nil {
return err
}
return mc.writeAuthSwitchPacket(enc, false)
}
func (mc *mysqlConn) auth(authData []byte, plugin string) ([]byte, bool, error) {
switch plugin {
case "caching_sha2_password":
authResp := scrambleSHA256Password(authData, mc.cfg.Passwd)
return authResp, (authResp == nil), nil
case "mysql_old_password":
if !mc.cfg.AllowOldPasswords {
return nil, false, ErrOldPassword
}
// Note: there are edge cases where this should work but doesn't;
// this is currently "wontfix":
// https://github.com/go-sql-driver/mysql/issues/184
authResp := scrambleOldPassword(authData[:8], mc.cfg.Passwd)
return authResp, true, nil
case "mysql_clear_password":
if !mc.cfg.AllowCleartextPasswords {
return nil, false, ErrCleartextPassword
}
// http://dev.mysql.com/doc/refman/5.7/en/cleartext-authentication-plugin.html
// http://dev.mysql.com/doc/refman/5.7/en/pam-authentication-plugin.html
return []byte(mc.cfg.Passwd), true, nil
case "mysql_native_password":
if !mc.cfg.AllowNativePasswords {
return nil, false, ErrNativePassword
}
// https://dev.mysql.com/doc/internals/en/secure-password-authentication.html
// Native password authentication only need and will need 20-byte challenge.
authResp := scramblePassword(authData[:20], mc.cfg.Passwd)
return authResp, false, nil
case "sha256_password":
if len(mc.cfg.Passwd) == 0 {
return nil, true, nil
}
if mc.cfg.tls != nil || mc.cfg.Net == "unix" {
// write cleartext auth packet
return []byte(mc.cfg.Passwd), true, nil
}
pubKey := mc.cfg.pubKey
if pubKey == nil {
// request public key from server
return []byte{1}, false, nil
}
// encrypted password
enc, err := encryptPassword(mc.cfg.Passwd, authData, pubKey)
return enc, false, err
default:
errLog.Print("unknown auth plugin:", plugin)
return nil, false, ErrUnknownPlugin
}
}
func (mc *mysqlConn) handleAuthResult(oldAuthData []byte, plugin string) error {
// Read Result Packet
authData, newPlugin, err := mc.readAuthResult()
if err != nil {
return err
}
// handle auth plugin switch, if requested
if newPlugin != "" {
// If CLIENT_PLUGIN_AUTH capability is not supported, no new cipher is
// sent and we have to keep using the cipher sent in the init packet.
if authData == nil {
authData = oldAuthData
} else {
// copy data from read buffer to owned slice
copy(oldAuthData, authData)
}
plugin = newPlugin
authResp, addNUL, err := mc.auth(authData, plugin)
if err != nil {
return err
}
if err = mc.writeAuthSwitchPacket(authResp, addNUL); err != nil {
return err
}
// Read Result Packet
authData, newPlugin, err = mc.readAuthResult()
if err != nil {
return err
}
// Do not allow to change the auth plugin more than once
if newPlugin != "" {
return ErrMalformPkt
}
}
switch plugin {
// https://insidemysql.com/preparing-your-community-connector-for-mysql-8-part-2-sha256/
case "caching_sha2_password":
switch len(authData) {
case 0:
return nil // auth successful
case 1:
switch authData[0] {
case cachingSha2PasswordFastAuthSuccess:
if err = mc.readResultOK(); err == nil {
return nil // auth successful
}
case cachingSha2PasswordPerformFullAuthentication:
if mc.cfg.tls != nil || mc.cfg.Net == "unix" {
// write cleartext auth packet
err = mc.writeAuthSwitchPacket([]byte(mc.cfg.Passwd), true)
if err != nil {
return err
}
} else {
pubKey := mc.cfg.pubKey
if pubKey == nil {
// request public key from server
data := mc.buf.takeSmallBuffer(4 + 1)
data[4] = cachingSha2PasswordRequestPublicKey
mc.writePacket(data)
// parse public key
data, err := mc.readPacket()
if err != nil {
return err
}
block, _ := pem.Decode(data[1:])
pkix, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return err
}
pubKey = pkix.(*rsa.PublicKey)
}
// send encrypted password
err = mc.sendEncryptedPassword(oldAuthData, pubKey)
if err != nil {
return err
}
}
return mc.readResultOK()
default:
return ErrMalformPkt
}
default:
return ErrMalformPkt
}
case "sha256_password":
switch len(authData) {
case 0:
return nil // auth successful
default:
block, _ := pem.Decode(authData)
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return err
}
// send encrypted password
err = mc.sendEncryptedPassword(oldAuthData, pub.(*rsa.PublicKey))
if err != nil {
return err
}
return mc.readResultOK()
}
default:
return nil // auth successful
}
return err
}

View File

@ -130,18 +130,18 @@ func (b *buffer) takeBuffer(length int) []byte {
// smaller than defaultBufSize // smaller than defaultBufSize
// Only one buffer (total) can be used at a time. // Only one buffer (total) can be used at a time.
func (b *buffer) takeSmallBuffer(length int) []byte { func (b *buffer) takeSmallBuffer(length int) []byte {
if b.length == 0 { if b.length > 0 {
return b.buf[:length] return nil
} }
return nil return b.buf[:length]
} }
// takeCompleteBuffer returns the complete existing buffer. // takeCompleteBuffer returns the complete existing buffer.
// This can be used if the necessary buffer size is unknown. // This can be used if the necessary buffer size is unknown.
// Only one buffer (total) can be used at a time. // Only one buffer (total) can be used at a time.
func (b *buffer) takeCompleteBuffer() []byte { func (b *buffer) takeCompleteBuffer() []byte {
if b.length == 0 { if b.length > 0 {
return b.buf return nil
} }
return nil return b.buf
} }

View File

@ -9,6 +9,7 @@
package mysql package mysql
const defaultCollation = "utf8_general_ci" const defaultCollation = "utf8_general_ci"
const binaryCollation = "binary"
// A list of available collations mapped to the internal ID. // A list of available collations mapped to the internal ID.
// To update this map use the following MySQL query: // To update this map use the following MySQL query:

View File

@ -10,12 +10,23 @@ package mysql
import ( import (
"database/sql/driver" "database/sql/driver"
"io"
"net" "net"
"strconv" "strconv"
"strings" "strings"
"time" "time"
) )
// a copy of context.Context for Go 1.7 and earlier
type mysqlContext interface {
Done() <-chan struct{}
Err() error
// defined in context.Context, but not used in this driver:
// Deadline() (deadline time.Time, ok bool)
// Value(key interface{}) interface{}
}
type mysqlConn struct { type mysqlConn struct {
buf buffer buf buffer
netConn net.Conn netConn net.Conn
@ -29,7 +40,14 @@ type mysqlConn struct {
status statusFlag status statusFlag
sequence uint8 sequence uint8
parseTime bool parseTime bool
strict bool
// for context support (Go 1.8+)
watching bool
watcher chan<- mysqlContext
closech chan struct{}
finished chan<- struct{}
canceled atomicError // set non-nil if conn is canceled
closed atomicBool // set when conn is closed, before closech is closed
} }
// Handles parameters set in DSN after the connection is established // Handles parameters set in DSN after the connection is established
@ -62,22 +80,41 @@ func (mc *mysqlConn) handleParams() (err error) {
return return
} }
func (mc *mysqlConn) markBadConn(err error) error {
if mc == nil {
return err
}
if err != errBadConnNoWrite {
return err
}
return driver.ErrBadConn
}
func (mc *mysqlConn) Begin() (driver.Tx, error) { func (mc *mysqlConn) Begin() (driver.Tx, error) {
if mc.netConn == nil { return mc.begin(false)
}
func (mc *mysqlConn) begin(readOnly bool) (driver.Tx, error) {
if mc.closed.IsSet() {
errLog.Print(ErrInvalidConn) errLog.Print(ErrInvalidConn)
return nil, driver.ErrBadConn return nil, driver.ErrBadConn
} }
err := mc.exec("START TRANSACTION") var q string
if readOnly {
q = "START TRANSACTION READ ONLY"
} else {
q = "START TRANSACTION"
}
err := mc.exec(q)
if err == nil { if err == nil {
return &mysqlTx{mc}, err return &mysqlTx{mc}, err
} }
return nil, mc.markBadConn(err)
return nil, err
} }
func (mc *mysqlConn) Close() (err error) { func (mc *mysqlConn) Close() (err error) {
// Makes Close idempotent // Makes Close idempotent
if mc.netConn != nil { if !mc.closed.IsSet() {
err = mc.writeCommandPacket(comQuit) err = mc.writeCommandPacket(comQuit)
} }
@ -91,26 +128,39 @@ func (mc *mysqlConn) Close() (err error) {
// is called before auth or on auth failure because MySQL will have already // is called before auth or on auth failure because MySQL will have already
// closed the network connection. // closed the network connection.
func (mc *mysqlConn) cleanup() { func (mc *mysqlConn) cleanup() {
// Makes cleanup idempotent if !mc.closed.TrySet(true) {
if mc.netConn != nil { return
if err := mc.netConn.Close(); err != nil {
errLog.Print(err)
}
mc.netConn = nil
} }
mc.cfg = nil
mc.buf.nc = nil // Makes cleanup idempotent
close(mc.closech)
if mc.netConn == nil {
return
}
if err := mc.netConn.Close(); err != nil {
errLog.Print(err)
}
}
func (mc *mysqlConn) error() error {
if mc.closed.IsSet() {
if err := mc.canceled.Value(); err != nil {
return err
}
return ErrInvalidConn
}
return nil
} }
func (mc *mysqlConn) Prepare(query string) (driver.Stmt, error) { func (mc *mysqlConn) Prepare(query string) (driver.Stmt, error) {
if mc.netConn == nil { if mc.closed.IsSet() {
errLog.Print(ErrInvalidConn) errLog.Print(ErrInvalidConn)
return nil, driver.ErrBadConn return nil, driver.ErrBadConn
} }
// Send command // Send command
err := mc.writeCommandPacketStr(comStmtPrepare, query) err := mc.writeCommandPacketStr(comStmtPrepare, query)
if err != nil { if err != nil {
return nil, err return nil, mc.markBadConn(err)
} }
stmt := &mysqlStmt{ stmt := &mysqlStmt{
@ -144,7 +194,7 @@ func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (strin
if buf == nil { if buf == nil {
// can not take the buffer. Something must be wrong with the connection // can not take the buffer. Something must be wrong with the connection
errLog.Print(ErrBusyBuffer) errLog.Print(ErrBusyBuffer)
return "", driver.ErrBadConn return "", ErrInvalidConn
} }
buf = buf[:0] buf = buf[:0]
argPos := 0 argPos := 0
@ -257,7 +307,7 @@ func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (strin
} }
func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, error) { func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, error) {
if mc.netConn == nil { if mc.closed.IsSet() {
errLog.Print(ErrInvalidConn) errLog.Print(ErrInvalidConn)
return nil, driver.ErrBadConn return nil, driver.ErrBadConn
} }
@ -271,7 +321,6 @@ func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, err
return nil, err return nil, err
} }
query = prepared query = prepared
args = nil
} }
mc.affectedRows = 0 mc.affectedRows = 0
mc.insertId = 0 mc.insertId = 0
@ -283,32 +332,43 @@ func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, err
insertId: int64(mc.insertId), insertId: int64(mc.insertId),
}, err }, err
} }
return nil, err return nil, mc.markBadConn(err)
} }
// Internal function to execute commands // Internal function to execute commands
func (mc *mysqlConn) exec(query string) error { func (mc *mysqlConn) exec(query string) error {
// Send command // Send command
err := mc.writeCommandPacketStr(comQuery, query) if err := mc.writeCommandPacketStr(comQuery, query); err != nil {
if err != nil { return mc.markBadConn(err)
return err
} }
// Read Result // Read Result
resLen, err := mc.readResultSetHeaderPacket() resLen, err := mc.readResultSetHeaderPacket()
if err == nil && resLen > 0 { if err != nil {
if err = mc.readUntilEOF(); err != nil { return err
}
if resLen > 0 {
// columns
if err := mc.readUntilEOF(); err != nil {
return err return err
} }
err = mc.readUntilEOF() // rows
if err := mc.readUntilEOF(); err != nil {
return err
}
} }
return err return mc.discardResults()
} }
func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, error) { func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, error) {
if mc.netConn == nil { return mc.query(query, args)
}
func (mc *mysqlConn) query(query string, args []driver.Value) (*textRows, error) {
if mc.closed.IsSet() {
errLog.Print(ErrInvalidConn) errLog.Print(ErrInvalidConn)
return nil, driver.ErrBadConn return nil, driver.ErrBadConn
} }
@ -322,7 +382,6 @@ func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, erro
return nil, err return nil, err
} }
query = prepared query = prepared
args = nil
} }
// Send command // Send command
err := mc.writeCommandPacketStr(comQuery, query) err := mc.writeCommandPacketStr(comQuery, query)
@ -335,15 +394,22 @@ func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, erro
rows.mc = mc rows.mc = mc
if resLen == 0 { if resLen == 0 {
// no columns, no more data rows.rs.done = true
return emptyRows{}, nil
switch err := rows.NextResultSet(); err {
case nil, io.EOF:
return rows, nil
default:
return nil, err
}
} }
// Columns // Columns
rows.columns, err = mc.readColumns(resLen) rows.rs.columns, err = mc.readColumns(resLen)
return rows, err return rows, err
} }
} }
return nil, err return nil, mc.markBadConn(err)
} }
// Gets the value of the given MySQL System Variable // Gets the value of the given MySQL System Variable
@ -359,7 +425,7 @@ func (mc *mysqlConn) getSystemVar(name string) ([]byte, error) {
if err == nil { if err == nil {
rows := new(textRows) rows := new(textRows)
rows.mc = mc rows.mc = mc
rows.columns = []mysqlField{{fieldType: fieldTypeVarChar}} rows.rs.columns = []mysqlField{{fieldType: fieldTypeVarChar}}
if resLen > 0 { if resLen > 0 {
// Columns // Columns
@ -375,3 +441,21 @@ func (mc *mysqlConn) getSystemVar(name string) ([]byte, error) {
} }
return nil, err return nil, err
} }
// finish is called when the query has canceled.
func (mc *mysqlConn) cancel(err error) {
mc.canceled.Set(err)
mc.cleanup()
}
// finish is called when the query has succeeded.
func (mc *mysqlConn) finish() {
if !mc.watching || mc.finished == nil {
return
}
select {
case mc.finished <- struct{}{}:
mc.watching = false
case <-mc.closech:
}
}

View File

@ -0,0 +1,208 @@
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
//
// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.
// +build go1.8
package mysql
import (
"context"
"database/sql"
"database/sql/driver"
)
// Ping implements driver.Pinger interface
func (mc *mysqlConn) Ping(ctx context.Context) (err error) {
if mc.closed.IsSet() {
errLog.Print(ErrInvalidConn)
return driver.ErrBadConn
}
if err = mc.watchCancel(ctx); err != nil {
return
}
defer mc.finish()
if err = mc.writeCommandPacket(comPing); err != nil {
return
}
return mc.readResultOK()
}
// BeginTx implements driver.ConnBeginTx interface
func (mc *mysqlConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
if err := mc.watchCancel(ctx); err != nil {
return nil, err
}
defer mc.finish()
if sql.IsolationLevel(opts.Isolation) != sql.LevelDefault {
level, err := mapIsolationLevel(opts.Isolation)
if err != nil {
return nil, err
}
err = mc.exec("SET TRANSACTION ISOLATION LEVEL " + level)
if err != nil {
return nil, err
}
}
return mc.begin(opts.ReadOnly)
}
func (mc *mysqlConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
dargs, err := namedValueToValue(args)
if err != nil {
return nil, err
}
if err := mc.watchCancel(ctx); err != nil {
return nil, err
}
rows, err := mc.query(query, dargs)
if err != nil {
mc.finish()
return nil, err
}
rows.finish = mc.finish
return rows, err
}
func (mc *mysqlConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
dargs, err := namedValueToValue(args)
if err != nil {
return nil, err
}
if err := mc.watchCancel(ctx); err != nil {
return nil, err
}
defer mc.finish()
return mc.Exec(query, dargs)
}
func (mc *mysqlConn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) {
if err := mc.watchCancel(ctx); err != nil {
return nil, err
}
stmt, err := mc.Prepare(query)
mc.finish()
if err != nil {
return nil, err
}
select {
default:
case <-ctx.Done():
stmt.Close()
return nil, ctx.Err()
}
return stmt, nil
}
func (stmt *mysqlStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
dargs, err := namedValueToValue(args)
if err != nil {
return nil, err
}
if err := stmt.mc.watchCancel(ctx); err != nil {
return nil, err
}
rows, err := stmt.query(dargs)
if err != nil {
stmt.mc.finish()
return nil, err
}
rows.finish = stmt.mc.finish
return rows, err
}
func (stmt *mysqlStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {
dargs, err := namedValueToValue(args)
if err != nil {
return nil, err
}
if err := stmt.mc.watchCancel(ctx); err != nil {
return nil, err
}
defer stmt.mc.finish()
return stmt.Exec(dargs)
}
func (mc *mysqlConn) watchCancel(ctx context.Context) error {
if mc.watching {
// Reach here if canceled,
// so the connection is already invalid
mc.cleanup()
return nil
}
if ctx.Done() == nil {
return nil
}
mc.watching = true
select {
default:
case <-ctx.Done():
return ctx.Err()
}
if mc.watcher == nil {
return nil
}
mc.watcher <- ctx
return nil
}
func (mc *mysqlConn) startWatcher() {
watcher := make(chan mysqlContext, 1)
mc.watcher = watcher
finished := make(chan struct{})
mc.finished = finished
go func() {
for {
var ctx mysqlContext
select {
case ctx = <-watcher:
case <-mc.closech:
return
}
select {
case <-ctx.Done():
mc.cancel(ctx.Err())
case <-finished:
case <-mc.closech:
return
}
}
}()
}
func (mc *mysqlConn) CheckNamedValue(nv *driver.NamedValue) (err error) {
nv.Value, err = converter{}.ConvertValue(nv.Value)
return
}
// ResetSession implements driver.SessionResetter.
// (From Go 1.10)
func (mc *mysqlConn) ResetSession(ctx context.Context) error {
if mc.closed.IsSet() {
return driver.ErrBadConn
}
return nil
}

View File

@ -9,7 +9,9 @@
package mysql package mysql
const ( const (
minProtocolVersion byte = 10 defaultAuthPlugin = "mysql_native_password"
defaultMaxAllowedPacket = 4 << 20 // 4 MiB
minProtocolVersion = 10
maxPacketSize = 1<<24 - 1 maxPacketSize = 1<<24 - 1
timeFormat = "2006-01-02 15:04:05.999999" timeFormat = "2006-01-02 15:04:05.999999"
) )
@ -18,10 +20,11 @@ const (
// http://dev.mysql.com/doc/internals/en/client-server-protocol.html // http://dev.mysql.com/doc/internals/en/client-server-protocol.html
const ( const (
iOK byte = 0x00 iOK byte = 0x00
iLocalInFile byte = 0xfb iAuthMoreData byte = 0x01
iEOF byte = 0xfe iLocalInFile byte = 0xfb
iERR byte = 0xff iEOF byte = 0xfe
iERR byte = 0xff
) )
// https://dev.mysql.com/doc/internals/en/capability-flags.html#packet-Protocol::CapabilityFlags // https://dev.mysql.com/doc/internals/en/capability-flags.html#packet-Protocol::CapabilityFlags
@ -87,8 +90,10 @@ const (
) )
// https://dev.mysql.com/doc/internals/en/com-query-response.html#packet-Protocol::ColumnType // https://dev.mysql.com/doc/internals/en/com-query-response.html#packet-Protocol::ColumnType
type fieldType byte
const ( const (
fieldTypeDecimal byte = iota fieldTypeDecimal fieldType = iota
fieldTypeTiny fieldTypeTiny
fieldTypeShort fieldTypeShort
fieldTypeLong fieldTypeLong
@ -107,7 +112,7 @@ const (
fieldTypeBit fieldTypeBit
) )
const ( const (
fieldTypeJSON byte = iota + 0xf5 fieldTypeJSON fieldType = iota + 0xf5
fieldTypeNewDecimal fieldTypeNewDecimal
fieldTypeEnum fieldTypeEnum
fieldTypeSet fieldTypeSet
@ -161,3 +166,9 @@ const (
statusInTransReadonly statusInTransReadonly
statusSessionStateChanged statusSessionStateChanged
) )
const (
cachingSha2PasswordRequestPublicKey = 2
cachingSha2PasswordFastAuthSuccess = 3
cachingSha2PasswordPerformFullAuthentication = 4
)

View File

@ -4,7 +4,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this file, // License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/. // You can obtain one at http://mozilla.org/MPL/2.0/.
// Package mysql provides a MySQL driver for Go's database/sql package // Package mysql provides a MySQL driver for Go's database/sql package.
// //
// The driver should be used via the database/sql package: // The driver should be used via the database/sql package:
// //
@ -20,8 +20,14 @@ import (
"database/sql" "database/sql"
"database/sql/driver" "database/sql/driver"
"net" "net"
"sync"
) )
// watcher interface is used for context support (From Go 1.8)
type watcher interface {
startWatcher()
}
// MySQLDriver is exported to make the driver directly accessible. // MySQLDriver is exported to make the driver directly accessible.
// In general the driver is used via the database/sql package. // In general the driver is used via the database/sql package.
type MySQLDriver struct{} type MySQLDriver struct{}
@ -30,12 +36,17 @@ type MySQLDriver struct{}
// Custom dial functions must be registered with RegisterDial // Custom dial functions must be registered with RegisterDial
type DialFunc func(addr string) (net.Conn, error) type DialFunc func(addr string) (net.Conn, error)
var dials map[string]DialFunc var (
dialsLock sync.RWMutex
dials map[string]DialFunc
)
// RegisterDial registers a custom dial function. It can then be used by the // RegisterDial registers a custom dial function. It can then be used by the
// network address mynet(addr), where mynet is the registered new network. // network address mynet(addr), where mynet is the registered new network.
// addr is passed as a parameter to the dial function. // addr is passed as a parameter to the dial function.
func RegisterDial(net string, dial DialFunc) { func RegisterDial(net string, dial DialFunc) {
dialsLock.Lock()
defer dialsLock.Unlock()
if dials == nil { if dials == nil {
dials = make(map[string]DialFunc) dials = make(map[string]DialFunc)
} }
@ -52,16 +63,19 @@ func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {
mc := &mysqlConn{ mc := &mysqlConn{
maxAllowedPacket: maxPacketSize, maxAllowedPacket: maxPacketSize,
maxWriteSize: maxPacketSize - 1, maxWriteSize: maxPacketSize - 1,
closech: make(chan struct{}),
} }
mc.cfg, err = ParseDSN(dsn) mc.cfg, err = ParseDSN(dsn)
if err != nil { if err != nil {
return nil, err return nil, err
} }
mc.parseTime = mc.cfg.ParseTime mc.parseTime = mc.cfg.ParseTime
mc.strict = mc.cfg.Strict
// Connect to Server // Connect to Server
if dial, ok := dials[mc.cfg.Net]; ok { dialsLock.RLock()
dial, ok := dials[mc.cfg.Net]
dialsLock.RUnlock()
if ok {
mc.netConn, err = dial(mc.cfg.Addr) mc.netConn, err = dial(mc.cfg.Addr)
} else { } else {
nd := net.Dialer{Timeout: mc.cfg.Timeout} nd := net.Dialer{Timeout: mc.cfg.Timeout}
@ -81,6 +95,11 @@ func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {
} }
} }
// Call startWatcher for context support (From Go 1.8)
if s, ok := interface{}(mc).(watcher); ok {
s.startWatcher()
}
mc.buf = newBuffer(mc.netConn) mc.buf = newBuffer(mc.netConn)
// Set I/O timeouts // Set I/O timeouts
@ -88,20 +107,31 @@ func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {
mc.writeTimeout = mc.cfg.WriteTimeout mc.writeTimeout = mc.cfg.WriteTimeout
// Reading Handshake Initialization Packet // Reading Handshake Initialization Packet
cipher, err := mc.readInitPacket() authData, plugin, err := mc.readHandshakePacket()
if err != nil { if err != nil {
mc.cleanup() mc.cleanup()
return nil, err return nil, err
} }
// Send Client Authentication Packet // Send Client Authentication Packet
if err = mc.writeAuthPacket(cipher); err != nil { authResp, addNUL, err := mc.auth(authData, plugin)
if err != nil {
// try the default auth plugin, if using the requested plugin failed
errLog.Print("could not use requested auth plugin '"+plugin+"': ", err.Error())
plugin = defaultAuthPlugin
authResp, addNUL, err = mc.auth(authData, plugin)
if err != nil {
mc.cleanup()
return nil, err
}
}
if err = mc.writeHandshakeResponsePacket(authResp, addNUL, plugin); err != nil {
mc.cleanup() mc.cleanup()
return nil, err return nil, err
} }
// Handle response to auth packet, switch methods if possible // Handle response to auth packet, switch methods if possible
if err = handleAuthResult(mc); err != nil { if err = mc.handleAuthResult(authData, plugin); err != nil {
// Authentication failed and MySQL has already closed the connection // Authentication failed and MySQL has already closed the connection
// (https://dev.mysql.com/doc/internals/en/authentication-fails.html). // (https://dev.mysql.com/doc/internals/en/authentication-fails.html).
// Do not send COM_QUIT, just cleanup and return the error. // Do not send COM_QUIT, just cleanup and return the error.
@ -134,43 +164,6 @@ func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {
return mc, nil return mc, nil
} }
func handleAuthResult(mc *mysqlConn) error {
// Read Result Packet
cipher, err := mc.readResultOK()
if err == nil {
return nil // auth successful
}
if mc.cfg == nil {
return err // auth failed and retry not possible
}
// Retry auth if configured to do so.
if mc.cfg.AllowOldPasswords && err == ErrOldPassword {
// Retry with old authentication method. Note: there are edge cases
// where this should work but doesn't; this is currently "wontfix":
// https://github.com/go-sql-driver/mysql/issues/184
if err = mc.writeOldAuthPacket(cipher); err != nil {
return err
}
_, err = mc.readResultOK()
} else if mc.cfg.AllowCleartextPasswords && err == ErrCleartextPassword {
// Retry with clear text password for
// http://dev.mysql.com/doc/refman/5.7/en/cleartext-authentication-plugin.html
// http://dev.mysql.com/doc/refman/5.7/en/pam-authentication-plugin.html
if err = mc.writeClearAuthPacket(); err != nil {
return err
}
_, err = mc.readResultOK()
} else if mc.cfg.AllowNativePasswords && err == ErrNativePassword {
if err = mc.writeNativeAuthPacket(cipher); err != nil {
return err
}
_, err = mc.readResultOK()
}
return err
}
func init() { func init() {
sql.Register("mysql", &MySQLDriver{}) sql.Register("mysql", &MySQLDriver{})
} }

View File

@ -10,11 +10,13 @@ package mysql
import ( import (
"bytes" "bytes"
"crypto/rsa"
"crypto/tls" "crypto/tls"
"errors" "errors"
"fmt" "fmt"
"net" "net"
"net/url" "net/url"
"sort"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@ -27,7 +29,9 @@ var (
errInvalidDSNUnsafeCollation = errors.New("invalid DSN: interpolateParams can not be used with unsafe collations") errInvalidDSNUnsafeCollation = errors.New("invalid DSN: interpolateParams can not be used with unsafe collations")
) )
// Config is a configuration parsed from a DSN string // Config is a configuration parsed from a DSN string.
// If a new Config is created instead of being parsed from a DSN string,
// the NewConfig function should be used, which sets default values.
type Config struct { type Config struct {
User string // Username User string // Username
Passwd string // Password (requires User) Passwd string // Password (requires User)
@ -38,6 +42,8 @@ type Config struct {
Collation string // Connection collation Collation string // Connection collation
Loc *time.Location // Location for time.Time values Loc *time.Location // Location for time.Time values
MaxAllowedPacket int // Max packet size allowed MaxAllowedPacket int // Max packet size allowed
ServerPubKey string // Server public key name
pubKey *rsa.PublicKey // Server public key
TLSConfig string // TLS configuration name TLSConfig string // TLS configuration name
tls *tls.Config // TLS configuration tls *tls.Config // TLS configuration
Timeout time.Duration // Dial timeout Timeout time.Duration // Dial timeout
@ -53,7 +59,54 @@ type Config struct {
InterpolateParams bool // Interpolate placeholders into query string InterpolateParams bool // Interpolate placeholders into query string
MultiStatements bool // Allow multiple statements in one query MultiStatements bool // Allow multiple statements in one query
ParseTime bool // Parse time values to time.Time ParseTime bool // Parse time values to time.Time
Strict bool // Return warnings as errors RejectReadOnly bool // Reject read-only connections
}
// NewConfig creates a new Config and sets default values.
func NewConfig() *Config {
return &Config{
Collation: defaultCollation,
Loc: time.UTC,
MaxAllowedPacket: defaultMaxAllowedPacket,
AllowNativePasswords: true,
}
}
func (cfg *Config) normalize() error {
if cfg.InterpolateParams && unsafeCollations[cfg.Collation] {
return errInvalidDSNUnsafeCollation
}
// Set default network if empty
if cfg.Net == "" {
cfg.Net = "tcp"
}
// Set default address if empty
if cfg.Addr == "" {
switch cfg.Net {
case "tcp":
cfg.Addr = "127.0.0.1:3306"
case "unix":
cfg.Addr = "/tmp/mysql.sock"
default:
return errors.New("default addr for network '" + cfg.Net + "' unknown")
}
} else if cfg.Net == "tcp" {
cfg.Addr = ensureHavePort(cfg.Addr)
}
if cfg.tls != nil {
if cfg.tls.ServerName == "" && !cfg.tls.InsecureSkipVerify {
host, _, err := net.SplitHostPort(cfg.Addr)
if err == nil {
cfg.tls.ServerName = host
}
}
}
return nil
} }
// FormatDSN formats the given Config into a DSN string which can be passed to // FormatDSN formats the given Config into a DSN string which can be passed to
@ -102,12 +155,12 @@ func (cfg *Config) FormatDSN() string {
} }
} }
if cfg.AllowNativePasswords { if !cfg.AllowNativePasswords {
if hasParam { if hasParam {
buf.WriteString("&allowNativePasswords=true") buf.WriteString("&allowNativePasswords=false")
} else { } else {
hasParam = true hasParam = true
buf.WriteString("?allowNativePasswords=true") buf.WriteString("?allowNativePasswords=false")
} }
} }
@ -195,15 +248,25 @@ func (cfg *Config) FormatDSN() string {
buf.WriteString(cfg.ReadTimeout.String()) buf.WriteString(cfg.ReadTimeout.String())
} }
if cfg.Strict { if cfg.RejectReadOnly {
if hasParam { if hasParam {
buf.WriteString("&strict=true") buf.WriteString("&rejectReadOnly=true")
} else { } else {
hasParam = true hasParam = true
buf.WriteString("?strict=true") buf.WriteString("?rejectReadOnly=true")
} }
} }
if len(cfg.ServerPubKey) > 0 {
if hasParam {
buf.WriteString("&serverPubKey=")
} else {
hasParam = true
buf.WriteString("?serverPubKey=")
}
buf.WriteString(url.QueryEscape(cfg.ServerPubKey))
}
if cfg.Timeout > 0 { if cfg.Timeout > 0 {
if hasParam { if hasParam {
buf.WriteString("&timeout=") buf.WriteString("&timeout=")
@ -234,7 +297,7 @@ func (cfg *Config) FormatDSN() string {
buf.WriteString(cfg.WriteTimeout.String()) buf.WriteString(cfg.WriteTimeout.String())
} }
if cfg.MaxAllowedPacket > 0 { if cfg.MaxAllowedPacket != defaultMaxAllowedPacket {
if hasParam { if hasParam {
buf.WriteString("&maxAllowedPacket=") buf.WriteString("&maxAllowedPacket=")
} else { } else {
@ -247,7 +310,12 @@ func (cfg *Config) FormatDSN() string {
// other params // other params
if cfg.Params != nil { if cfg.Params != nil {
for param, value := range cfg.Params { var params []string
for param := range cfg.Params {
params = append(params, param)
}
sort.Strings(params)
for _, param := range params {
if hasParam { if hasParam {
buf.WriteByte('&') buf.WriteByte('&')
} else { } else {
@ -257,7 +325,7 @@ func (cfg *Config) FormatDSN() string {
buf.WriteString(param) buf.WriteString(param)
buf.WriteByte('=') buf.WriteByte('=')
buf.WriteString(url.QueryEscape(value)) buf.WriteString(url.QueryEscape(cfg.Params[param]))
} }
} }
@ -267,10 +335,7 @@ func (cfg *Config) FormatDSN() string {
// ParseDSN parses the DSN string to a Config // ParseDSN parses the DSN string to a Config
func ParseDSN(dsn string) (cfg *Config, err error) { func ParseDSN(dsn string) (cfg *Config, err error) {
// New config with some default values // New config with some default values
cfg = &Config{ cfg = NewConfig()
Loc: time.UTC,
Collation: defaultCollation,
}
// [user[:password]@][net[(addr)]]/dbname[?param1=value1&paramN=valueN] // [user[:password]@][net[(addr)]]/dbname[?param1=value1&paramN=valueN]
// Find the last '/' (since the password or the net addr might contain a '/') // Find the last '/' (since the password or the net addr might contain a '/')
@ -338,28 +403,9 @@ func ParseDSN(dsn string) (cfg *Config, err error) {
return nil, errInvalidDSNNoSlash return nil, errInvalidDSNNoSlash
} }
if cfg.InterpolateParams && unsafeCollations[cfg.Collation] { if err = cfg.normalize(); err != nil {
return nil, errInvalidDSNUnsafeCollation return nil, err
} }
// Set default network if empty
if cfg.Net == "" {
cfg.Net = "tcp"
}
// Set default address if empty
if cfg.Addr == "" {
switch cfg.Net {
case "tcp":
cfg.Addr = "127.0.0.1:3306"
case "unix":
cfg.Addr = "/tmp/mysql.sock"
default:
return nil, errors.New("default addr for network '" + cfg.Net + "' unknown")
}
}
return return
} }
@ -374,7 +420,6 @@ func parseDSNParams(cfg *Config, params string) (err error) {
// cfg params // cfg params
switch value := param[1]; param[0] { switch value := param[1]; param[0] {
// Disable INFILE whitelist / enable all files // Disable INFILE whitelist / enable all files
case "allowAllFiles": case "allowAllFiles":
var isBool bool var isBool bool
@ -472,14 +517,32 @@ func parseDSNParams(cfg *Config, params string) (err error) {
return return
} }
// Strict mode // Reject read-only connections
case "strict": case "rejectReadOnly":
var isBool bool var isBool bool
cfg.Strict, isBool = readBool(value) cfg.RejectReadOnly, isBool = readBool(value)
if !isBool { if !isBool {
return errors.New("invalid bool value: " + value) return errors.New("invalid bool value: " + value)
} }
// Server public key
case "serverPubKey":
name, err := url.QueryUnescape(value)
if err != nil {
return fmt.Errorf("invalid value for server pub key name: %v", err)
}
if pubKey := getServerPubKey(name); pubKey != nil {
cfg.ServerPubKey = name
cfg.pubKey = pubKey
} else {
return errors.New("invalid value / unknown server pub key name: " + name)
}
// Strict mode
case "strict":
panic("strict mode has been removed. See https://github.com/go-sql-driver/mysql/wiki/strict-mode")
// Dial Timeout // Dial Timeout
case "timeout": case "timeout":
cfg.Timeout, err = time.ParseDuration(value) cfg.Timeout, err = time.ParseDuration(value)
@ -506,14 +569,7 @@ func parseDSNParams(cfg *Config, params string) (err error) {
return fmt.Errorf("invalid value for TLS config name: %v", err) return fmt.Errorf("invalid value for TLS config name: %v", err)
} }
if tlsConfig, ok := tlsConfigRegister[name]; ok { if tlsConfig := getTLSConfigClone(name); tlsConfig != nil {
if len(tlsConfig.ServerName) == 0 && !tlsConfig.InsecureSkipVerify {
host, _, err := net.SplitHostPort(cfg.Addr)
if err == nil {
tlsConfig.ServerName = host
}
}
cfg.TLSConfig = name cfg.TLSConfig = name
cfg.tls = tlsConfig cfg.tls = tlsConfig
} else { } else {
@ -546,3 +602,10 @@ func parseDSNParams(cfg *Config, params string) (err error) {
return return
} }
func ensureHavePort(addr string) string {
if _, _, err := net.SplitHostPort(addr); err != nil {
return net.JoinHostPort(addr, "3306")
}
return addr
}

View File

@ -9,10 +9,8 @@
package mysql package mysql
import ( import (
"database/sql/driver"
"errors" "errors"
"fmt" "fmt"
"io"
"log" "log"
"os" "os"
) )
@ -31,6 +29,12 @@ var (
ErrPktSyncMul = errors.New("commands out of sync. Did you run multiple statements at once?") ErrPktSyncMul = errors.New("commands out of sync. Did you run multiple statements at once?")
ErrPktTooLarge = errors.New("packet for query is too large. Try adjusting the 'max_allowed_packet' variable on the server") ErrPktTooLarge = errors.New("packet for query is too large. Try adjusting the 'max_allowed_packet' variable on the server")
ErrBusyBuffer = errors.New("busy buffer") ErrBusyBuffer = errors.New("busy buffer")
// errBadConnNoWrite is used for connection errors where nothing was sent to the database yet.
// If this happens first in a function starting a database interaction, it should be replaced by driver.ErrBadConn
// to trigger a resend.
// See https://github.com/go-sql-driver/mysql/pull/302
errBadConnNoWrite = errors.New("bad connection")
) )
var errLog = Logger(log.New(os.Stderr, "[mysql] ", log.Ldate|log.Ltime|log.Lshortfile)) var errLog = Logger(log.New(os.Stderr, "[mysql] ", log.Ldate|log.Ltime|log.Lshortfile))
@ -59,74 +63,3 @@ type MySQLError struct {
func (me *MySQLError) Error() string { func (me *MySQLError) Error() string {
return fmt.Sprintf("Error %d: %s", me.Number, me.Message) return fmt.Sprintf("Error %d: %s", me.Number, me.Message)
} }
// MySQLWarnings is an error type which represents a group of one or more MySQL
// warnings
type MySQLWarnings []MySQLWarning
func (mws MySQLWarnings) Error() string {
var msg string
for i, warning := range mws {
if i > 0 {
msg += "\r\n"
}
msg += fmt.Sprintf(
"%s %s: %s",
warning.Level,
warning.Code,
warning.Message,
)
}
return msg
}
// MySQLWarning is an error type which represents a single MySQL warning.
// Warnings are returned in groups only. See MySQLWarnings
type MySQLWarning struct {
Level string
Code string
Message string
}
func (mc *mysqlConn) getWarnings() (err error) {
rows, err := mc.Query("SHOW WARNINGS", nil)
if err != nil {
return
}
var warnings = MySQLWarnings{}
var values = make([]driver.Value, 3)
for {
err = rows.Next(values)
switch err {
case nil:
warning := MySQLWarning{}
if raw, ok := values[0].([]byte); ok {
warning.Level = string(raw)
} else {
warning.Level = fmt.Sprintf("%s", values[0])
}
if raw, ok := values[1].([]byte); ok {
warning.Code = string(raw)
} else {
warning.Code = fmt.Sprintf("%s", values[1])
}
if raw, ok := values[2].([]byte); ok {
warning.Message = string(raw)
} else {
warning.Message = fmt.Sprintf("%s", values[0])
}
warnings = append(warnings, warning)
case io.EOF:
return warnings
default:
rows.Close()
return
}
}
}

194
vendor/github.com/go-sql-driver/mysql/fields.go generated vendored Normal file
View File

@ -0,0 +1,194 @@
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
//
// Copyright 2017 The Go-MySQL-Driver Authors. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.
package mysql
import (
"database/sql"
"reflect"
)
func (mf *mysqlField) typeDatabaseName() string {
switch mf.fieldType {
case fieldTypeBit:
return "BIT"
case fieldTypeBLOB:
if mf.charSet != collations[binaryCollation] {
return "TEXT"
}
return "BLOB"
case fieldTypeDate:
return "DATE"
case fieldTypeDateTime:
return "DATETIME"
case fieldTypeDecimal:
return "DECIMAL"
case fieldTypeDouble:
return "DOUBLE"
case fieldTypeEnum:
return "ENUM"
case fieldTypeFloat:
return "FLOAT"
case fieldTypeGeometry:
return "GEOMETRY"
case fieldTypeInt24:
return "MEDIUMINT"
case fieldTypeJSON:
return "JSON"
case fieldTypeLong:
return "INT"
case fieldTypeLongBLOB:
if mf.charSet != collations[binaryCollation] {
return "LONGTEXT"
}
return "LONGBLOB"
case fieldTypeLongLong:
return "BIGINT"
case fieldTypeMediumBLOB:
if mf.charSet != collations[binaryCollation] {
return "MEDIUMTEXT"
}
return "MEDIUMBLOB"
case fieldTypeNewDate:
return "DATE"
case fieldTypeNewDecimal:
return "DECIMAL"
case fieldTypeNULL:
return "NULL"
case fieldTypeSet:
return "SET"
case fieldTypeShort:
return "SMALLINT"
case fieldTypeString:
if mf.charSet == collations[binaryCollation] {
return "BINARY"
}
return "CHAR"
case fieldTypeTime:
return "TIME"
case fieldTypeTimestamp:
return "TIMESTAMP"
case fieldTypeTiny:
return "TINYINT"
case fieldTypeTinyBLOB:
if mf.charSet != collations[binaryCollation] {
return "TINYTEXT"
}
return "TINYBLOB"
case fieldTypeVarChar:
if mf.charSet == collations[binaryCollation] {
return "VARBINARY"
}
return "VARCHAR"
case fieldTypeVarString:
if mf.charSet == collations[binaryCollation] {
return "VARBINARY"
}
return "VARCHAR"
case fieldTypeYear:
return "YEAR"
default:
return ""
}
}
var (
scanTypeFloat32 = reflect.TypeOf(float32(0))
scanTypeFloat64 = reflect.TypeOf(float64(0))
scanTypeInt8 = reflect.TypeOf(int8(0))
scanTypeInt16 = reflect.TypeOf(int16(0))
scanTypeInt32 = reflect.TypeOf(int32(0))
scanTypeInt64 = reflect.TypeOf(int64(0))
scanTypeNullFloat = reflect.TypeOf(sql.NullFloat64{})
scanTypeNullInt = reflect.TypeOf(sql.NullInt64{})
scanTypeNullTime = reflect.TypeOf(NullTime{})
scanTypeUint8 = reflect.TypeOf(uint8(0))
scanTypeUint16 = reflect.TypeOf(uint16(0))
scanTypeUint32 = reflect.TypeOf(uint32(0))
scanTypeUint64 = reflect.TypeOf(uint64(0))
scanTypeRawBytes = reflect.TypeOf(sql.RawBytes{})
scanTypeUnknown = reflect.TypeOf(new(interface{}))
)
type mysqlField struct {
tableName string
name string
length uint32
flags fieldFlag
fieldType fieldType
decimals byte
charSet uint8
}
func (mf *mysqlField) scanType() reflect.Type {
switch mf.fieldType {
case fieldTypeTiny:
if mf.flags&flagNotNULL != 0 {
if mf.flags&flagUnsigned != 0 {
return scanTypeUint8
}
return scanTypeInt8
}
return scanTypeNullInt
case fieldTypeShort, fieldTypeYear:
if mf.flags&flagNotNULL != 0 {
if mf.flags&flagUnsigned != 0 {
return scanTypeUint16
}
return scanTypeInt16
}
return scanTypeNullInt
case fieldTypeInt24, fieldTypeLong:
if mf.flags&flagNotNULL != 0 {
if mf.flags&flagUnsigned != 0 {
return scanTypeUint32
}
return scanTypeInt32
}
return scanTypeNullInt
case fieldTypeLongLong:
if mf.flags&flagNotNULL != 0 {
if mf.flags&flagUnsigned != 0 {
return scanTypeUint64
}
return scanTypeInt64
}
return scanTypeNullInt
case fieldTypeFloat:
if mf.flags&flagNotNULL != 0 {
return scanTypeFloat32
}
return scanTypeNullFloat
case fieldTypeDouble:
if mf.flags&flagNotNULL != 0 {
return scanTypeFloat64
}
return scanTypeNullFloat
case fieldTypeDecimal, fieldTypeNewDecimal, fieldTypeVarChar,
fieldTypeBit, fieldTypeEnum, fieldTypeSet, fieldTypeTinyBLOB,
fieldTypeMediumBLOB, fieldTypeLongBLOB, fieldTypeBLOB,
fieldTypeVarString, fieldTypeString, fieldTypeGeometry, fieldTypeJSON,
fieldTypeTime:
return scanTypeRawBytes
case fieldTypeDate, fieldTypeNewDate,
fieldTypeTimestamp, fieldTypeDateTime:
// NullTime is always returned for more consistent behavior as it can
// handle both cases of parseTime regardless if the field is nullable.
return scanTypeNullTime
default:
return scanTypeUnknown
}
}

View File

@ -147,7 +147,8 @@ func (mc *mysqlConn) handleInFileRequest(name string) (err error) {
} }
// send content packets // send content packets
if err == nil { // if packetSize == 0, the Reader contains no data
if err == nil && packetSize > 0 {
data := make([]byte, 4+packetSize) data := make([]byte, 4+packetSize)
var n int var n int
for err == nil { for err == nil {
@ -173,8 +174,7 @@ func (mc *mysqlConn) handleInFileRequest(name string) (err error) {
// read OK packet // read OK packet
if err == nil { if err == nil {
_, err = mc.readResultOK() return mc.readResultOK()
return err
} }
mc.readPacket() mc.readPacket()

View File

@ -25,26 +25,23 @@ import (
// Read packet to buffer 'data' // Read packet to buffer 'data'
func (mc *mysqlConn) readPacket() ([]byte, error) { func (mc *mysqlConn) readPacket() ([]byte, error) {
var payload []byte var prevData []byte
for { for {
// Read packet header // read packet header
data, err := mc.buf.readNext(4) data, err := mc.buf.readNext(4)
if err != nil { if err != nil {
if cerr := mc.canceled.Value(); cerr != nil {
return nil, cerr
}
errLog.Print(err) errLog.Print(err)
mc.Close() mc.Close()
return nil, driver.ErrBadConn return nil, ErrInvalidConn
} }
// Packet Length [24 bit] // packet length [24 bit]
pktLen := int(uint32(data[0]) | uint32(data[1])<<8 | uint32(data[2])<<16) pktLen := int(uint32(data[0]) | uint32(data[1])<<8 | uint32(data[2])<<16)
if pktLen < 1 { // check packet sync [8 bit]
errLog.Print(ErrMalformPkt)
mc.Close()
return nil, driver.ErrBadConn
}
// Check Packet Sync [8 bit]
if data[3] != mc.sequence { if data[3] != mc.sequence {
if data[3] > mc.sequence { if data[3] > mc.sequence {
return nil, ErrPktSyncMul return nil, ErrPktSyncMul
@ -53,26 +50,41 @@ func (mc *mysqlConn) readPacket() ([]byte, error) {
} }
mc.sequence++ mc.sequence++
// Read packet body [pktLen bytes] // packets with length 0 terminate a previous packet which is a
// multiple of (2^24)1 bytes long
if pktLen == 0 {
// there was no previous packet
if prevData == nil {
errLog.Print(ErrMalformPkt)
mc.Close()
return nil, ErrInvalidConn
}
return prevData, nil
}
// read packet body [pktLen bytes]
data, err = mc.buf.readNext(pktLen) data, err = mc.buf.readNext(pktLen)
if err != nil { if err != nil {
if cerr := mc.canceled.Value(); cerr != nil {
return nil, cerr
}
errLog.Print(err) errLog.Print(err)
mc.Close() mc.Close()
return nil, driver.ErrBadConn return nil, ErrInvalidConn
} }
isLastPacket := (pktLen < maxPacketSize) // return data if this was the last packet
if pktLen < maxPacketSize {
// zero allocations for non-split packets
if prevData == nil {
return data, nil
}
// Zero allocations for non-splitting packets return append(prevData, data...), nil
if isLastPacket && payload == nil {
return data, nil
} }
payload = append(payload, data...) prevData = append(prevData, data...)
if isLastPacket {
return payload, nil
}
} }
} }
@ -119,33 +131,47 @@ func (mc *mysqlConn) writePacket(data []byte) error {
// Handle error // Handle error
if err == nil { // n != len(data) if err == nil { // n != len(data)
mc.cleanup()
errLog.Print(ErrMalformPkt) errLog.Print(ErrMalformPkt)
} else { } else {
if cerr := mc.canceled.Value(); cerr != nil {
return cerr
}
if n == 0 && pktLen == len(data)-4 {
// only for the first loop iteration when nothing was written yet
return errBadConnNoWrite
}
mc.cleanup()
errLog.Print(err) errLog.Print(err)
} }
return driver.ErrBadConn return ErrInvalidConn
} }
} }
/****************************************************************************** /******************************************************************************
* Initialisation Process * * Initialization Process *
******************************************************************************/ ******************************************************************************/
// Handshake Initialization Packet // Handshake Initialization Packet
// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::Handshake // http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::Handshake
func (mc *mysqlConn) readInitPacket() ([]byte, error) { func (mc *mysqlConn) readHandshakePacket() ([]byte, string, error) {
data, err := mc.readPacket() data, err := mc.readPacket()
if err != nil { if err != nil {
return nil, err // for init we can rewrite this to ErrBadConn for sql.Driver to retry, since
// in connection initialization we don't risk retrying non-idempotent actions.
if err == ErrInvalidConn {
return nil, "", driver.ErrBadConn
}
return nil, "", err
} }
if data[0] == iERR { if data[0] == iERR {
return nil, mc.handleErrorPacket(data) return nil, "", mc.handleErrorPacket(data)
} }
// protocol version [1 byte] // protocol version [1 byte]
if data[0] < minProtocolVersion { if data[0] < minProtocolVersion {
return nil, fmt.Errorf( return nil, "", fmt.Errorf(
"unsupported protocol version %d. Version %d or higher is required", "unsupported protocol version %d. Version %d or higher is required",
data[0], data[0],
minProtocolVersion, minProtocolVersion,
@ -157,7 +183,7 @@ func (mc *mysqlConn) readInitPacket() ([]byte, error) {
pos := 1 + bytes.IndexByte(data[1:], 0x00) + 1 + 4 pos := 1 + bytes.IndexByte(data[1:], 0x00) + 1 + 4
// first part of the password cipher [8 bytes] // first part of the password cipher [8 bytes]
cipher := data[pos : pos+8] authData := data[pos : pos+8]
// (filler) always 0x00 [1 byte] // (filler) always 0x00 [1 byte]
pos += 8 + 1 pos += 8 + 1
@ -165,13 +191,14 @@ func (mc *mysqlConn) readInitPacket() ([]byte, error) {
// capability flags (lower 2 bytes) [2 bytes] // capability flags (lower 2 bytes) [2 bytes]
mc.flags = clientFlag(binary.LittleEndian.Uint16(data[pos : pos+2])) mc.flags = clientFlag(binary.LittleEndian.Uint16(data[pos : pos+2]))
if mc.flags&clientProtocol41 == 0 { if mc.flags&clientProtocol41 == 0 {
return nil, ErrOldProtocol return nil, "", ErrOldProtocol
} }
if mc.flags&clientSSL == 0 && mc.cfg.tls != nil { if mc.flags&clientSSL == 0 && mc.cfg.tls != nil {
return nil, ErrNoTLS return nil, "", ErrNoTLS
} }
pos += 2 pos += 2
plugin := ""
if len(data) > pos { if len(data) > pos {
// character set [1 byte] // character set [1 byte]
// status flags [2 bytes] // status flags [2 bytes]
@ -192,32 +219,34 @@ func (mc *mysqlConn) readInitPacket() ([]byte, error) {
// //
// The official Python library uses the fixed length 12 // The official Python library uses the fixed length 12
// which seems to work but technically could have a hidden bug. // which seems to work but technically could have a hidden bug.
cipher = append(cipher, data[pos:pos+12]...) authData = append(authData, data[pos:pos+12]...)
pos += 13
// TODO: Verify string termination
// EOF if version (>= 5.5.7 and < 5.5.10) or (>= 5.6.0 and < 5.6.2) // EOF if version (>= 5.5.7 and < 5.5.10) or (>= 5.6.0 and < 5.6.2)
// \NUL otherwise // \NUL otherwise
// if end := bytes.IndexByte(data[pos:], 0x00); end != -1 {
//if data[len(data)-1] == 0 { plugin = string(data[pos : pos+end])
// return } else {
//} plugin = string(data[pos:])
//return ErrMalformPkt }
// make a memory safe copy of the cipher slice // make a memory safe copy of the cipher slice
var b [20]byte var b [20]byte
copy(b[:], cipher) copy(b[:], authData)
return b[:], nil return b[:], plugin, nil
} }
plugin = defaultAuthPlugin
// make a memory safe copy of the cipher slice // make a memory safe copy of the cipher slice
var b [8]byte var b [8]byte
copy(b[:], cipher) copy(b[:], authData)
return b[:], nil return b[:], plugin, nil
} }
// Client Authentication Packet // Client Authentication Packet
// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::HandshakeResponse // http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::HandshakeResponse
func (mc *mysqlConn) writeAuthPacket(cipher []byte) error { func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, addNUL bool, plugin string) error {
// Adjust client flags based on server support // Adjust client flags based on server support
clientFlags := clientProtocol41 | clientFlags := clientProtocol41 |
clientSecureConn | clientSecureConn |
@ -241,10 +270,19 @@ func (mc *mysqlConn) writeAuthPacket(cipher []byte) error {
clientFlags |= clientMultiStatements clientFlags |= clientMultiStatements
} }
// User Password // encode length of the auth plugin data
scrambleBuff := scramblePassword(cipher, []byte(mc.cfg.Passwd)) var authRespLEIBuf [9]byte
authRespLEI := appendLengthEncodedInteger(authRespLEIBuf[:0], uint64(len(authResp)))
if len(authRespLEI) > 1 {
// if the length can not be written in 1 byte, it must be written as a
// length encoded integer
clientFlags |= clientPluginAuthLenEncClientData
}
pktLen := 4 + 4 + 1 + 23 + len(mc.cfg.User) + 1 + 1 + len(scrambleBuff) + 21 + 1 pktLen := 4 + 4 + 1 + 23 + len(mc.cfg.User) + 1 + len(authRespLEI) + len(authResp) + 21 + 1
if addNUL {
pktLen++
}
// To specify a db name // To specify a db name
if n := len(mc.cfg.DBName); n > 0 { if n := len(mc.cfg.DBName); n > 0 {
@ -255,9 +293,9 @@ func (mc *mysqlConn) writeAuthPacket(cipher []byte) error {
// Calculate packet length and get buffer with that size // Calculate packet length and get buffer with that size
data := mc.buf.takeSmallBuffer(pktLen + 4) data := mc.buf.takeSmallBuffer(pktLen + 4)
if data == nil { if data == nil {
// can not take the buffer. Something must be wrong with the connection // cannot take the buffer. Something must be wrong with the connection
errLog.Print(ErrBusyBuffer) errLog.Print(ErrBusyBuffer)
return driver.ErrBadConn return errBadConnNoWrite
} }
// ClientFlags [32 bit] // ClientFlags [32 bit]
@ -312,9 +350,13 @@ func (mc *mysqlConn) writeAuthPacket(cipher []byte) error {
data[pos] = 0x00 data[pos] = 0x00
pos++ pos++
// ScrambleBuffer [length encoded integer] // Auth Data [length encoded integer]
data[pos] = byte(len(scrambleBuff)) pos += copy(data[pos:], authRespLEI)
pos += 1 + copy(data[pos+1:], scrambleBuff) pos += copy(data[pos:], authResp)
if addNUL {
data[pos] = 0x00
pos++
}
// Databasename [null terminated string] // Databasename [null terminated string]
if len(mc.cfg.DBName) > 0 { if len(mc.cfg.DBName) > 0 {
@ -323,72 +365,32 @@ func (mc *mysqlConn) writeAuthPacket(cipher []byte) error {
pos++ pos++
} }
// Assume native client during response pos += copy(data[pos:], plugin)
pos += copy(data[pos:], "mysql_native_password")
data[pos] = 0x00 data[pos] = 0x00
// Send Auth packet // Send Auth packet
return mc.writePacket(data) return mc.writePacket(data)
} }
// Client old authentication packet
// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse // http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse
func (mc *mysqlConn) writeOldAuthPacket(cipher []byte) error { func (mc *mysqlConn) writeAuthSwitchPacket(authData []byte, addNUL bool) error {
// User password pktLen := 4 + len(authData)
scrambleBuff := scrambleOldPassword(cipher, []byte(mc.cfg.Passwd)) if addNUL {
pktLen++
// Calculate the packet length and add a tailing 0 }
pktLen := len(scrambleBuff) + 1 data := mc.buf.takeSmallBuffer(pktLen)
data := mc.buf.takeSmallBuffer(4 + pktLen)
if data == nil { if data == nil {
// can not take the buffer. Something must be wrong with the connection // cannot take the buffer. Something must be wrong with the connection
errLog.Print(ErrBusyBuffer) errLog.Print(ErrBusyBuffer)
return driver.ErrBadConn return errBadConnNoWrite
} }
// Add the scrambled password [null terminated string] // Add the auth data [EOF]
copy(data[4:], scrambleBuff) copy(data[4:], authData)
data[4+pktLen-1] = 0x00 if addNUL {
data[pktLen-1] = 0x00
return mc.writePacket(data)
}
// Client clear text authentication packet
// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse
func (mc *mysqlConn) writeClearAuthPacket() error {
// Calculate the packet length and add a tailing 0
pktLen := len(mc.cfg.Passwd) + 1
data := mc.buf.takeSmallBuffer(4 + pktLen)
if data == nil {
// can not take the buffer. Something must be wrong with the connection
errLog.Print(ErrBusyBuffer)
return driver.ErrBadConn
} }
// Add the clear password [null terminated string]
copy(data[4:], mc.cfg.Passwd)
data[4+pktLen-1] = 0x00
return mc.writePacket(data)
}
// Native password authentication method
// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse
func (mc *mysqlConn) writeNativeAuthPacket(cipher []byte) error {
scrambleBuff := scramblePassword(cipher, []byte(mc.cfg.Passwd))
// Calculate the packet length and add a tailing 0
pktLen := len(scrambleBuff)
data := mc.buf.takeSmallBuffer(4 + pktLen)
if data == nil {
// can not take the buffer. Something must be wrong with the connection
errLog.Print(ErrBusyBuffer)
return driver.ErrBadConn
}
// Add the scramble
copy(data[4:], scrambleBuff)
return mc.writePacket(data) return mc.writePacket(data)
} }
@ -402,9 +404,9 @@ func (mc *mysqlConn) writeCommandPacket(command byte) error {
data := mc.buf.takeSmallBuffer(4 + 1) data := mc.buf.takeSmallBuffer(4 + 1)
if data == nil { if data == nil {
// can not take the buffer. Something must be wrong with the connection // cannot take the buffer. Something must be wrong with the connection
errLog.Print(ErrBusyBuffer) errLog.Print(ErrBusyBuffer)
return driver.ErrBadConn return errBadConnNoWrite
} }
// Add command byte // Add command byte
@ -421,9 +423,9 @@ func (mc *mysqlConn) writeCommandPacketStr(command byte, arg string) error {
pktLen := 1 + len(arg) pktLen := 1 + len(arg)
data := mc.buf.takeBuffer(pktLen + 4) data := mc.buf.takeBuffer(pktLen + 4)
if data == nil { if data == nil {
// can not take the buffer. Something must be wrong with the connection // cannot take the buffer. Something must be wrong with the connection
errLog.Print(ErrBusyBuffer) errLog.Print(ErrBusyBuffer)
return driver.ErrBadConn return errBadConnNoWrite
} }
// Add command byte // Add command byte
@ -442,9 +444,9 @@ func (mc *mysqlConn) writeCommandPacketUint32(command byte, arg uint32) error {
data := mc.buf.takeSmallBuffer(4 + 1 + 4) data := mc.buf.takeSmallBuffer(4 + 1 + 4)
if data == nil { if data == nil {
// can not take the buffer. Something must be wrong with the connection // cannot take the buffer. Something must be wrong with the connection
errLog.Print(ErrBusyBuffer) errLog.Print(ErrBusyBuffer)
return driver.ErrBadConn return errBadConnNoWrite
} }
// Add command byte // Add command byte
@ -464,43 +466,50 @@ func (mc *mysqlConn) writeCommandPacketUint32(command byte, arg uint32) error {
* Result Packets * * Result Packets *
******************************************************************************/ ******************************************************************************/
// Returns error if Packet is not an 'Result OK'-Packet func (mc *mysqlConn) readAuthResult() ([]byte, string, error) {
func (mc *mysqlConn) readResultOK() ([]byte, error) {
data, err := mc.readPacket() data, err := mc.readPacket()
if err == nil { if err != nil {
// packet indicator return nil, "", err
switch data[0] {
case iOK:
return nil, mc.handleOkPacket(data)
case iEOF:
if len(data) > 1 {
pluginEndIndex := bytes.IndexByte(data, 0x00)
plugin := string(data[1:pluginEndIndex])
cipher := data[pluginEndIndex+1 : len(data)-1]
if plugin == "mysql_old_password" {
// using old_passwords
return cipher, ErrOldPassword
} else if plugin == "mysql_clear_password" {
// using clear text password
return cipher, ErrCleartextPassword
} else if plugin == "mysql_native_password" {
// using mysql default authentication method
return cipher, ErrNativePassword
} else {
return cipher, ErrUnknownPlugin
}
} else {
return nil, ErrOldPassword
}
default: // Error otherwise
return nil, mc.handleErrorPacket(data)
}
} }
return nil, err
// packet indicator
switch data[0] {
case iOK:
return nil, "", mc.handleOkPacket(data)
case iAuthMoreData:
return data[1:], "", err
case iEOF:
if len(data) < 1 {
// https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::OldAuthSwitchRequest
return nil, "mysql_old_password", nil
}
pluginEndIndex := bytes.IndexByte(data, 0x00)
if pluginEndIndex < 0 {
return nil, "", ErrMalformPkt
}
plugin := string(data[1:pluginEndIndex])
authData := data[pluginEndIndex+1:]
return authData, plugin, nil
default: // Error otherwise
return nil, "", mc.handleErrorPacket(data)
}
}
// Returns error if Packet is not an 'Result OK'-Packet
func (mc *mysqlConn) readResultOK() error {
data, err := mc.readPacket()
if err != nil {
return err
}
if data[0] == iOK {
return mc.handleOkPacket(data)
}
return mc.handleErrorPacket(data)
} }
// Result Set Header Packet // Result Set Header Packet
@ -543,6 +552,22 @@ func (mc *mysqlConn) handleErrorPacket(data []byte) error {
// Error Number [16 bit uint] // Error Number [16 bit uint]
errno := binary.LittleEndian.Uint16(data[1:3]) errno := binary.LittleEndian.Uint16(data[1:3])
// 1792: ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
// 1290: ER_OPTION_PREVENTS_STATEMENT (returned by Aurora during failover)
if (errno == 1792 || errno == 1290) && mc.cfg.RejectReadOnly {
// Oops; we are connected to a read-only connection, and won't be able
// to issue any write statements. Since RejectReadOnly is configured,
// we throw away this connection hoping this one would have write
// permission. This is specifically for a possible race condition
// during failover (e.g. on AWS Aurora). See README.md for more.
//
// We explicitly close the connection before returning
// driver.ErrBadConn to ensure that `database/sql` purges this
// connection and initiates a new one for next statement next time.
mc.Close()
return driver.ErrBadConn
}
pos := 3 pos := 3
// SQL State [optional: # + 5bytes string] // SQL State [optional: # + 5bytes string]
@ -577,19 +602,12 @@ func (mc *mysqlConn) handleOkPacket(data []byte) error {
// server_status [2 bytes] // server_status [2 bytes]
mc.status = readStatus(data[1+n+m : 1+n+m+2]) mc.status = readStatus(data[1+n+m : 1+n+m+2])
if err := mc.discardResults(); err != nil { if mc.status&statusMoreResultsExists != 0 {
return err
}
// warning count [2 bytes]
if !mc.strict {
return nil return nil
} }
pos := 1 + n + m + 2 // warning count [2 bytes]
if binary.LittleEndian.Uint16(data[pos:pos+2]) > 0 {
return mc.getWarnings()
}
return nil return nil
} }
@ -661,14 +679,21 @@ func (mc *mysqlConn) readColumns(count int) ([]mysqlField, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
pos += n
// Filler [uint8] // Filler [uint8]
pos++
// Charset [charset, collation uint8] // Charset [charset, collation uint8]
columns[i].charSet = data[pos]
pos += 2
// Length [uint32] // Length [uint32]
pos += n + 1 + 2 + 4 columns[i].length = binary.LittleEndian.Uint32(data[pos : pos+4])
pos += 4
// Field type [uint8] // Field type [uint8]
columns[i].fieldType = data[pos] columns[i].fieldType = fieldType(data[pos])
pos++ pos++
// Flags [uint16] // Flags [uint16]
@ -691,6 +716,10 @@ func (mc *mysqlConn) readColumns(count int) ([]mysqlField, error) {
func (rows *textRows) readRow(dest []driver.Value) error { func (rows *textRows) readRow(dest []driver.Value) error {
mc := rows.mc mc := rows.mc
if rows.rs.done {
return io.EOF
}
data, err := mc.readPacket() data, err := mc.readPacket()
if err != nil { if err != nil {
return err return err
@ -700,10 +729,10 @@ func (rows *textRows) readRow(dest []driver.Value) error {
if data[0] == iEOF && len(data) == 5 { if data[0] == iEOF && len(data) == 5 {
// server_status [2 bytes] // server_status [2 bytes]
rows.mc.status = readStatus(data[3:]) rows.mc.status = readStatus(data[3:])
if err := rows.mc.discardResults(); err != nil { rows.rs.done = true
return err if !rows.HasNextResultSet() {
rows.mc = nil
} }
rows.mc = nil
return io.EOF return io.EOF
} }
if data[0] == iERR { if data[0] == iERR {
@ -725,7 +754,7 @@ func (rows *textRows) readRow(dest []driver.Value) error {
if !mc.parseTime { if !mc.parseTime {
continue continue
} else { } else {
switch rows.columns[i].fieldType { switch rows.rs.columns[i].fieldType {
case fieldTypeTimestamp, fieldTypeDateTime, case fieldTypeTimestamp, fieldTypeDateTime,
fieldTypeDate, fieldTypeNewDate: fieldTypeDate, fieldTypeNewDate:
dest[i], err = parseDateTime( dest[i], err = parseDateTime(
@ -797,14 +826,7 @@ func (stmt *mysqlStmt) readPrepareResultPacket() (uint16, error) {
// Reserved [8 bit] // Reserved [8 bit]
// Warning count [16 bit uint] // Warning count [16 bit uint]
if !stmt.mc.strict {
return columnCount, nil
}
// Check for warnings count > 0, only available in MySQL > 4.1
if len(data) >= 12 && binary.LittleEndian.Uint16(data[10:12]) > 0 {
return columnCount, stmt.mc.getWarnings()
}
return columnCount, nil return columnCount, nil
} }
return 0, err return 0, err
@ -821,7 +843,7 @@ func (stmt *mysqlStmt) writeCommandLongData(paramID int, arg []byte) error {
// 2 bytes paramID // 2 bytes paramID
const dataOffset = 1 + 4 + 2 const dataOffset = 1 + 4 + 2
// Can not use the write buffer since // Cannot use the write buffer since
// a) the buffer is too small // a) the buffer is too small
// b) it is in use // b) it is in use
data := make([]byte, 4+1+4+2+len(arg)) data := make([]byte, 4+1+4+2+len(arg))
@ -876,6 +898,12 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
const minPktLen = 4 + 1 + 4 + 1 + 4 const minPktLen = 4 + 1 + 4 + 1 + 4
mc := stmt.mc mc := stmt.mc
// Determine threshould dynamically to avoid packet size shortage.
longDataSize := mc.maxAllowedPacket / (stmt.paramCount + 1)
if longDataSize < 64 {
longDataSize = 64
}
// Reset packet-sequence // Reset packet-sequence
mc.sequence = 0 mc.sequence = 0
@ -887,9 +915,9 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
data = mc.buf.takeCompleteBuffer() data = mc.buf.takeCompleteBuffer()
} }
if data == nil { if data == nil {
// can not take the buffer. Something must be wrong with the connection // cannot take the buffer. Something must be wrong with the connection
errLog.Print(ErrBusyBuffer) errLog.Print(ErrBusyBuffer)
return driver.ErrBadConn return errBadConnNoWrite
} }
// command [1 byte] // command [1 byte]
@ -948,7 +976,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
// build NULL-bitmap // build NULL-bitmap
if arg == nil { if arg == nil {
nullMask[i/8] |= 1 << (uint(i) & 7) nullMask[i/8] |= 1 << (uint(i) & 7)
paramTypes[i+i] = fieldTypeNULL paramTypes[i+i] = byte(fieldTypeNULL)
paramTypes[i+i+1] = 0x00 paramTypes[i+i+1] = 0x00
continue continue
} }
@ -956,7 +984,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
// cache types and values // cache types and values
switch v := arg.(type) { switch v := arg.(type) {
case int64: case int64:
paramTypes[i+i] = fieldTypeLongLong paramTypes[i+i] = byte(fieldTypeLongLong)
paramTypes[i+i+1] = 0x00 paramTypes[i+i+1] = 0x00
if cap(paramValues)-len(paramValues)-8 >= 0 { if cap(paramValues)-len(paramValues)-8 >= 0 {
@ -972,7 +1000,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
} }
case float64: case float64:
paramTypes[i+i] = fieldTypeDouble paramTypes[i+i] = byte(fieldTypeDouble)
paramTypes[i+i+1] = 0x00 paramTypes[i+i+1] = 0x00
if cap(paramValues)-len(paramValues)-8 >= 0 { if cap(paramValues)-len(paramValues)-8 >= 0 {
@ -988,7 +1016,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
} }
case bool: case bool:
paramTypes[i+i] = fieldTypeTiny paramTypes[i+i] = byte(fieldTypeTiny)
paramTypes[i+i+1] = 0x00 paramTypes[i+i+1] = 0x00
if v { if v {
@ -1000,10 +1028,10 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
case []byte: case []byte:
// Common case (non-nil value) first // Common case (non-nil value) first
if v != nil { if v != nil {
paramTypes[i+i] = fieldTypeString paramTypes[i+i] = byte(fieldTypeString)
paramTypes[i+i+1] = 0x00 paramTypes[i+i+1] = 0x00
if len(v) < mc.maxAllowedPacket-pos-len(paramValues)-(len(args)-(i+1))*64 { if len(v) < longDataSize {
paramValues = appendLengthEncodedInteger(paramValues, paramValues = appendLengthEncodedInteger(paramValues,
uint64(len(v)), uint64(len(v)),
) )
@ -1018,14 +1046,14 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
// Handle []byte(nil) as a NULL value // Handle []byte(nil) as a NULL value
nullMask[i/8] |= 1 << (uint(i) & 7) nullMask[i/8] |= 1 << (uint(i) & 7)
paramTypes[i+i] = fieldTypeNULL paramTypes[i+i] = byte(fieldTypeNULL)
paramTypes[i+i+1] = 0x00 paramTypes[i+i+1] = 0x00
case string: case string:
paramTypes[i+i] = fieldTypeString paramTypes[i+i] = byte(fieldTypeString)
paramTypes[i+i+1] = 0x00 paramTypes[i+i+1] = 0x00
if len(v) < mc.maxAllowedPacket-pos-len(paramValues)-(len(args)-(i+1))*64 { if len(v) < longDataSize {
paramValues = appendLengthEncodedInteger(paramValues, paramValues = appendLengthEncodedInteger(paramValues,
uint64(len(v)), uint64(len(v)),
) )
@ -1037,23 +1065,25 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
} }
case time.Time: case time.Time:
paramTypes[i+i] = fieldTypeString paramTypes[i+i] = byte(fieldTypeString)
paramTypes[i+i+1] = 0x00 paramTypes[i+i+1] = 0x00
var val []byte var a [64]byte
var b = a[:0]
if v.IsZero() { if v.IsZero() {
val = []byte("0000-00-00") b = append(b, "0000-00-00"...)
} else { } else {
val = []byte(v.In(mc.cfg.Loc).Format(timeFormat)) b = v.In(mc.cfg.Loc).AppendFormat(b, timeFormat)
} }
paramValues = appendLengthEncodedInteger(paramValues, paramValues = appendLengthEncodedInteger(paramValues,
uint64(len(val)), uint64(len(b)),
) )
paramValues = append(paramValues, val...) paramValues = append(paramValues, b...)
default: default:
return fmt.Errorf("can not convert type: %T", arg) return fmt.Errorf("cannot convert type: %T", arg)
} }
} }
@ -1086,8 +1116,6 @@ func (mc *mysqlConn) discardResults() error {
if err := mc.readUntilEOF(); err != nil { if err := mc.readUntilEOF(); err != nil {
return err return err
} }
} else {
mc.status &^= statusMoreResultsExists
} }
} }
return nil return nil
@ -1105,16 +1133,17 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
// EOF Packet // EOF Packet
if data[0] == iEOF && len(data) == 5 { if data[0] == iEOF && len(data) == 5 {
rows.mc.status = readStatus(data[3:]) rows.mc.status = readStatus(data[3:])
if err := rows.mc.discardResults(); err != nil { rows.rs.done = true
return err if !rows.HasNextResultSet() {
rows.mc = nil
} }
rows.mc = nil
return io.EOF return io.EOF
} }
mc := rows.mc
rows.mc = nil rows.mc = nil
// Error otherwise // Error otherwise
return rows.mc.handleErrorPacket(data) return mc.handleErrorPacket(data)
} }
// NULL-bitmap, [(column-count + 7 + 2) / 8 bytes] // NULL-bitmap, [(column-count + 7 + 2) / 8 bytes]
@ -1130,14 +1159,14 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
} }
// Convert to byte-coded string // Convert to byte-coded string
switch rows.columns[i].fieldType { switch rows.rs.columns[i].fieldType {
case fieldTypeNULL: case fieldTypeNULL:
dest[i] = nil dest[i] = nil
continue continue
// Numeric Types // Numeric Types
case fieldTypeTiny: case fieldTypeTiny:
if rows.columns[i].flags&flagUnsigned != 0 { if rows.rs.columns[i].flags&flagUnsigned != 0 {
dest[i] = int64(data[pos]) dest[i] = int64(data[pos])
} else { } else {
dest[i] = int64(int8(data[pos])) dest[i] = int64(int8(data[pos]))
@ -1146,7 +1175,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
continue continue
case fieldTypeShort, fieldTypeYear: case fieldTypeShort, fieldTypeYear:
if rows.columns[i].flags&flagUnsigned != 0 { if rows.rs.columns[i].flags&flagUnsigned != 0 {
dest[i] = int64(binary.LittleEndian.Uint16(data[pos : pos+2])) dest[i] = int64(binary.LittleEndian.Uint16(data[pos : pos+2]))
} else { } else {
dest[i] = int64(int16(binary.LittleEndian.Uint16(data[pos : pos+2]))) dest[i] = int64(int16(binary.LittleEndian.Uint16(data[pos : pos+2])))
@ -1155,7 +1184,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
continue continue
case fieldTypeInt24, fieldTypeLong: case fieldTypeInt24, fieldTypeLong:
if rows.columns[i].flags&flagUnsigned != 0 { if rows.rs.columns[i].flags&flagUnsigned != 0 {
dest[i] = int64(binary.LittleEndian.Uint32(data[pos : pos+4])) dest[i] = int64(binary.LittleEndian.Uint32(data[pos : pos+4]))
} else { } else {
dest[i] = int64(int32(binary.LittleEndian.Uint32(data[pos : pos+4]))) dest[i] = int64(int32(binary.LittleEndian.Uint32(data[pos : pos+4])))
@ -1164,7 +1193,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
continue continue
case fieldTypeLongLong: case fieldTypeLongLong:
if rows.columns[i].flags&flagUnsigned != 0 { if rows.rs.columns[i].flags&flagUnsigned != 0 {
val := binary.LittleEndian.Uint64(data[pos : pos+8]) val := binary.LittleEndian.Uint64(data[pos : pos+8])
if val > math.MaxInt64 { if val > math.MaxInt64 {
dest[i] = uint64ToString(val) dest[i] = uint64ToString(val)
@ -1178,7 +1207,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
continue continue
case fieldTypeFloat: case fieldTypeFloat:
dest[i] = float32(math.Float32frombits(binary.LittleEndian.Uint32(data[pos : pos+4]))) dest[i] = math.Float32frombits(binary.LittleEndian.Uint32(data[pos : pos+4]))
pos += 4 pos += 4
continue continue
@ -1218,10 +1247,10 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
case isNull: case isNull:
dest[i] = nil dest[i] = nil
continue continue
case rows.columns[i].fieldType == fieldTypeTime: case rows.rs.columns[i].fieldType == fieldTypeTime:
// database/sql does not support an equivalent to TIME, return a string // database/sql does not support an equivalent to TIME, return a string
var dstlen uint8 var dstlen uint8
switch decimals := rows.columns[i].decimals; decimals { switch decimals := rows.rs.columns[i].decimals; decimals {
case 0x00, 0x1f: case 0x00, 0x1f:
dstlen = 8 dstlen = 8
case 1, 2, 3, 4, 5, 6: case 1, 2, 3, 4, 5, 6:
@ -1229,7 +1258,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
default: default:
return fmt.Errorf( return fmt.Errorf(
"protocol error, illegal decimals value %d", "protocol error, illegal decimals value %d",
rows.columns[i].decimals, rows.rs.columns[i].decimals,
) )
} }
dest[i], err = formatBinaryDateTime(data[pos:pos+int(num)], dstlen, true) dest[i], err = formatBinaryDateTime(data[pos:pos+int(num)], dstlen, true)
@ -1237,10 +1266,10 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
dest[i], err = parseBinaryDateTime(num, data[pos:], rows.mc.cfg.Loc) dest[i], err = parseBinaryDateTime(num, data[pos:], rows.mc.cfg.Loc)
default: default:
var dstlen uint8 var dstlen uint8
if rows.columns[i].fieldType == fieldTypeDate { if rows.rs.columns[i].fieldType == fieldTypeDate {
dstlen = 10 dstlen = 10
} else { } else {
switch decimals := rows.columns[i].decimals; decimals { switch decimals := rows.rs.columns[i].decimals; decimals {
case 0x00, 0x1f: case 0x00, 0x1f:
dstlen = 19 dstlen = 19
case 1, 2, 3, 4, 5, 6: case 1, 2, 3, 4, 5, 6:
@ -1248,7 +1277,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
default: default:
return fmt.Errorf( return fmt.Errorf(
"protocol error, illegal decimals value %d", "protocol error, illegal decimals value %d",
rows.columns[i].decimals, rows.rs.columns[i].decimals,
) )
} }
} }
@ -1264,7 +1293,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
// Please report if this happens! // Please report if this happens!
default: default:
return fmt.Errorf("unknown field type %d", rows.columns[i].fieldType) return fmt.Errorf("unknown field type %d", rows.rs.columns[i].fieldType)
} }
} }

View File

@ -11,19 +11,20 @@ package mysql
import ( import (
"database/sql/driver" "database/sql/driver"
"io" "io"
"math"
"reflect"
) )
type mysqlField struct { type resultSet struct {
tableName string columns []mysqlField
name string columnNames []string
flags fieldFlag done bool
fieldType byte
decimals byte
} }
type mysqlRows struct { type mysqlRows struct {
mc *mysqlConn mc *mysqlConn
columns []mysqlField rs resultSet
finish func()
} }
type binaryRows struct { type binaryRows struct {
@ -34,37 +35,86 @@ type textRows struct {
mysqlRows mysqlRows
} }
type emptyRows struct{}
func (rows *mysqlRows) Columns() []string { func (rows *mysqlRows) Columns() []string {
columns := make([]string, len(rows.columns)) if rows.rs.columnNames != nil {
return rows.rs.columnNames
}
columns := make([]string, len(rows.rs.columns))
if rows.mc != nil && rows.mc.cfg.ColumnsWithAlias { if rows.mc != nil && rows.mc.cfg.ColumnsWithAlias {
for i := range columns { for i := range columns {
if tableName := rows.columns[i].tableName; len(tableName) > 0 { if tableName := rows.rs.columns[i].tableName; len(tableName) > 0 {
columns[i] = tableName + "." + rows.columns[i].name columns[i] = tableName + "." + rows.rs.columns[i].name
} else { } else {
columns[i] = rows.columns[i].name columns[i] = rows.rs.columns[i].name
} }
} }
} else { } else {
for i := range columns { for i := range columns {
columns[i] = rows.columns[i].name columns[i] = rows.rs.columns[i].name
} }
} }
rows.rs.columnNames = columns
return columns return columns
} }
func (rows *mysqlRows) Close() error { func (rows *mysqlRows) ColumnTypeDatabaseTypeName(i int) string {
return rows.rs.columns[i].typeDatabaseName()
}
// func (rows *mysqlRows) ColumnTypeLength(i int) (length int64, ok bool) {
// return int64(rows.rs.columns[i].length), true
// }
func (rows *mysqlRows) ColumnTypeNullable(i int) (nullable, ok bool) {
return rows.rs.columns[i].flags&flagNotNULL == 0, true
}
func (rows *mysqlRows) ColumnTypePrecisionScale(i int) (int64, int64, bool) {
column := rows.rs.columns[i]
decimals := int64(column.decimals)
switch column.fieldType {
case fieldTypeDecimal, fieldTypeNewDecimal:
if decimals > 0 {
return int64(column.length) - 2, decimals, true
}
return int64(column.length) - 1, decimals, true
case fieldTypeTimestamp, fieldTypeDateTime, fieldTypeTime:
return decimals, decimals, true
case fieldTypeFloat, fieldTypeDouble:
if decimals == 0x1f {
return math.MaxInt64, math.MaxInt64, true
}
return math.MaxInt64, decimals, true
}
return 0, 0, false
}
func (rows *mysqlRows) ColumnTypeScanType(i int) reflect.Type {
return rows.rs.columns[i].scanType()
}
func (rows *mysqlRows) Close() (err error) {
if f := rows.finish; f != nil {
f()
rows.finish = nil
}
mc := rows.mc mc := rows.mc
if mc == nil { if mc == nil {
return nil return nil
} }
if mc.netConn == nil { if err := mc.error(); err != nil {
return ErrInvalidConn return err
} }
// Remove unread packets from stream // Remove unread packets from stream
err := mc.readUntilEOF() if !rows.rs.done {
err = mc.readUntilEOF()
}
if err == nil { if err == nil {
if err = mc.discardResults(); err != nil { if err = mc.discardResults(); err != nil {
return err return err
@ -75,10 +125,66 @@ func (rows *mysqlRows) Close() error {
return err return err
} }
func (rows *mysqlRows) HasNextResultSet() (b bool) {
if rows.mc == nil {
return false
}
return rows.mc.status&statusMoreResultsExists != 0
}
func (rows *mysqlRows) nextResultSet() (int, error) {
if rows.mc == nil {
return 0, io.EOF
}
if err := rows.mc.error(); err != nil {
return 0, err
}
// Remove unread packets from stream
if !rows.rs.done {
if err := rows.mc.readUntilEOF(); err != nil {
return 0, err
}
rows.rs.done = true
}
if !rows.HasNextResultSet() {
rows.mc = nil
return 0, io.EOF
}
rows.rs = resultSet{}
return rows.mc.readResultSetHeaderPacket()
}
func (rows *mysqlRows) nextNotEmptyResultSet() (int, error) {
for {
resLen, err := rows.nextResultSet()
if err != nil {
return 0, err
}
if resLen > 0 {
return resLen, nil
}
rows.rs.done = true
}
}
func (rows *binaryRows) NextResultSet() error {
resLen, err := rows.nextNotEmptyResultSet()
if err != nil {
return err
}
rows.rs.columns, err = rows.mc.readColumns(resLen)
return err
}
func (rows *binaryRows) Next(dest []driver.Value) error { func (rows *binaryRows) Next(dest []driver.Value) error {
if mc := rows.mc; mc != nil { if mc := rows.mc; mc != nil {
if mc.netConn == nil { if err := mc.error(); err != nil {
return ErrInvalidConn return err
} }
// Fetch next row from stream // Fetch next row from stream
@ -87,10 +193,20 @@ func (rows *binaryRows) Next(dest []driver.Value) error {
return io.EOF return io.EOF
} }
func (rows *textRows) NextResultSet() (err error) {
resLen, err := rows.nextNotEmptyResultSet()
if err != nil {
return err
}
rows.rs.columns, err = rows.mc.readColumns(resLen)
return err
}
func (rows *textRows) Next(dest []driver.Value) error { func (rows *textRows) Next(dest []driver.Value) error {
if mc := rows.mc; mc != nil { if mc := rows.mc; mc != nil {
if mc.netConn == nil { if err := mc.error(); err != nil {
return ErrInvalidConn return err
} }
// Fetch next row from stream // Fetch next row from stream
@ -98,15 +214,3 @@ func (rows *textRows) Next(dest []driver.Value) error {
} }
return io.EOF return io.EOF
} }
func (rows emptyRows) Columns() []string {
return nil
}
func (rows emptyRows) Close() error {
return nil
}
func (rows emptyRows) Next(dest []driver.Value) error {
return io.EOF
}

View File

@ -11,6 +11,7 @@ package mysql
import ( import (
"database/sql/driver" "database/sql/driver"
"fmt" "fmt"
"io"
"reflect" "reflect"
"strconv" "strconv"
) )
@ -19,12 +20,14 @@ type mysqlStmt struct {
mc *mysqlConn mc *mysqlConn
id uint32 id uint32
paramCount int paramCount int
columns []mysqlField // cached from the first query
} }
func (stmt *mysqlStmt) Close() error { func (stmt *mysqlStmt) Close() error {
if stmt.mc == nil || stmt.mc.netConn == nil { if stmt.mc == nil || stmt.mc.closed.IsSet() {
errLog.Print(ErrInvalidConn) // driver.Stmt.Close can be called more than once, thus this function
// has to be idempotent.
// See also Issue #450 and golang/go#16019.
//errLog.Print(ErrInvalidConn)
return driver.ErrBadConn return driver.ErrBadConn
} }
@ -42,14 +45,14 @@ func (stmt *mysqlStmt) ColumnConverter(idx int) driver.ValueConverter {
} }
func (stmt *mysqlStmt) Exec(args []driver.Value) (driver.Result, error) { func (stmt *mysqlStmt) Exec(args []driver.Value) (driver.Result, error) {
if stmt.mc.netConn == nil { if stmt.mc.closed.IsSet() {
errLog.Print(ErrInvalidConn) errLog.Print(ErrInvalidConn)
return nil, driver.ErrBadConn return nil, driver.ErrBadConn
} }
// Send command // Send command
err := stmt.writeExecutePacket(args) err := stmt.writeExecutePacket(args)
if err != nil { if err != nil {
return nil, err return nil, stmt.mc.markBadConn(err)
} }
mc := stmt.mc mc := stmt.mc
@ -59,37 +62,45 @@ func (stmt *mysqlStmt) Exec(args []driver.Value) (driver.Result, error) {
// Read Result // Read Result
resLen, err := mc.readResultSetHeaderPacket() resLen, err := mc.readResultSetHeaderPacket()
if err == nil { if err != nil {
if resLen > 0 { return nil, err
// Columns }
err = mc.readUntilEOF()
if err != nil {
return nil, err
}
// Rows if resLen > 0 {
err = mc.readUntilEOF() // Columns
if err = mc.readUntilEOF(); err != nil {
return nil, err
} }
if err == nil {
return &mysqlResult{ // Rows
affectedRows: int64(mc.affectedRows), if err := mc.readUntilEOF(); err != nil {
insertId: int64(mc.insertId), return nil, err
}, nil
} }
} }
return nil, err if err := mc.discardResults(); err != nil {
return nil, err
}
return &mysqlResult{
affectedRows: int64(mc.affectedRows),
insertId: int64(mc.insertId),
}, nil
} }
func (stmt *mysqlStmt) Query(args []driver.Value) (driver.Rows, error) { func (stmt *mysqlStmt) Query(args []driver.Value) (driver.Rows, error) {
if stmt.mc.netConn == nil { return stmt.query(args)
}
func (stmt *mysqlStmt) query(args []driver.Value) (*binaryRows, error) {
if stmt.mc.closed.IsSet() {
errLog.Print(ErrInvalidConn) errLog.Print(ErrInvalidConn)
return nil, driver.ErrBadConn return nil, driver.ErrBadConn
} }
// Send command // Send command
err := stmt.writeExecutePacket(args) err := stmt.writeExecutePacket(args)
if err != nil { if err != nil {
return nil, err return nil, stmt.mc.markBadConn(err)
} }
mc := stmt.mc mc := stmt.mc
@ -104,14 +115,15 @@ func (stmt *mysqlStmt) Query(args []driver.Value) (driver.Rows, error) {
if resLen > 0 { if resLen > 0 {
rows.mc = mc rows.mc = mc
// Columns rows.rs.columns, err = mc.readColumns(resLen)
// If not cached, read them and cache them } else {
if stmt.columns == nil { rows.rs.done = true
rows.columns, err = mc.readColumns(resLen)
stmt.columns = rows.columns switch err := rows.NextResultSet(); err {
} else { case nil, io.EOF:
rows.columns = stmt.columns return rows, nil
err = mc.readUntilEOF() default:
return nil, err
} }
} }
@ -120,19 +132,36 @@ func (stmt *mysqlStmt) Query(args []driver.Value) (driver.Rows, error) {
type converter struct{} type converter struct{}
// ConvertValue mirrors the reference/default converter in database/sql/driver
// with _one_ exception. We support uint64 with their high bit and the default
// implementation does not. This function should be kept in sync with
// database/sql/driver defaultConverter.ConvertValue() except for that
// deliberate difference.
func (c converter) ConvertValue(v interface{}) (driver.Value, error) { func (c converter) ConvertValue(v interface{}) (driver.Value, error) {
if driver.IsValue(v) { if driver.IsValue(v) {
return v, nil return v, nil
} }
if vr, ok := v.(driver.Valuer); ok {
sv, err := callValuerValue(vr)
if err != nil {
return nil, err
}
if !driver.IsValue(sv) {
return nil, fmt.Errorf("non-Value type %T returned from Value", sv)
}
return sv, nil
}
rv := reflect.ValueOf(v) rv := reflect.ValueOf(v)
switch rv.Kind() { switch rv.Kind() {
case reflect.Ptr: case reflect.Ptr:
// indirect pointers // indirect pointers
if rv.IsNil() { if rv.IsNil() {
return nil, nil return nil, nil
} else {
return c.ConvertValue(rv.Elem().Interface())
} }
return c.ConvertValue(rv.Elem().Interface())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return rv.Int(), nil return rv.Int(), nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32: case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
@ -145,6 +174,38 @@ func (c converter) ConvertValue(v interface{}) (driver.Value, error) {
return int64(u64), nil return int64(u64), nil
case reflect.Float32, reflect.Float64: case reflect.Float32, reflect.Float64:
return rv.Float(), nil return rv.Float(), nil
case reflect.Bool:
return rv.Bool(), nil
case reflect.Slice:
ek := rv.Type().Elem().Kind()
if ek == reflect.Uint8 {
return rv.Bytes(), nil
}
return nil, fmt.Errorf("unsupported type %T, a slice of %s", v, ek)
case reflect.String:
return rv.String(), nil
} }
return nil, fmt.Errorf("unsupported type %T, a %s", v, rv.Kind()) return nil, fmt.Errorf("unsupported type %T, a %s", v, rv.Kind())
} }
var valuerReflectType = reflect.TypeOf((*driver.Valuer)(nil)).Elem()
// callValuerValue returns vr.Value(), with one exception:
// If vr.Value is an auto-generated method on a pointer type and the
// pointer is nil, it would panic at runtime in the panicwrap
// method. Treat it like nil instead.
//
// This is so people can implement driver.Value on value types and
// still use nil pointers to those types to mean nil/NULL, just like
// string/*string.
//
// This is an exact copy of the same-named unexported function from the
// database/sql package.
func callValuerValue(vr driver.Valuer) (v driver.Value, err error) {
if rv := reflect.ValueOf(vr); rv.Kind() == reflect.Ptr &&
rv.IsNil() &&
rv.Type().Elem().Implements(valuerReflectType) {
return nil, nil
}
return vr.Value()
}

Some files were not shown because too many files have changed in this diff Show More