Merge branch 'master' into graceful-queues

This commit is contained in:
Lauris BH 2020-01-05 01:20:52 +02:00 committed by GitHub
commit ec83b83c74
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
161 changed files with 17393 additions and 6702 deletions

View file

@ -4,6 +4,26 @@ 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.10.2](https://github.com/go-gitea/gitea/releases/tag/v1.10.2) - 2020-01-02
* BUGFIXES
* Allow only specific Columns to be updated on Issue via API (#9539) (#9580)
* Add ErrReactionAlreadyExist error (#9550) (#9564)
* Fix bug when migrate from API (#8631) (#9563)
* Use default avatar for ghost user (#9536) (#9537)
* Fix repository issues pagination bug when there are more than one label filter (#9512) (#9528)
* Fix deleted branch not removed when push the branch again (#9516) (#9524)
* Fix missing repository status when migrating repository via API (#9511)
* Trigger webhook when deleting a branch after merging a PR (#9510)
* Fix paging on /repos/{owner}/{repo}/git/trees/{sha} API endpoint (#9482)
* Fix NewCommitStatus (#9434) (#9435)
* Use OriginalURL instead of CloneAddr in migration logging (#9418) (#9420)
* Fix Slack webhook payload title generation to work with Mattermost (#9404)
* DefaultBranch needs to be prefixed by BranchPrefix (#9356) (#9359)
* Fix issue indexer not triggered when migrating a repository (#9333)
* Fix bug that release attachment files not deleted when deleting repository (#9322) (#9329)
* Fix migration releases (#9319) (#9326) (#9328)
* Fix File Edit: Author/Committer interchanged (#9297) (#9300)
## [1.10.1](https://github.com/go-gitea/gitea/releases/tag/v1.10.1) - 2019-12-05 ## [1.10.1](https://github.com/go-gitea/gitea/releases/tag/v1.10.1) - 2019-12-05
* BUGFIXES * BUGFIXES
* Fix max length check and limit in multiple repo forms (#9148) (#9204) * Fix max length check and limit in multiple repo forms (#9148) (#9204)

View file

@ -12,6 +12,7 @@
- [Code review](#code-review) - [Code review](#code-review)
- [Styleguide](#styleguide) - [Styleguide](#styleguide)
- [Design guideline](#design-guideline) - [Design guideline](#design-guideline)
- [API v1](#api-v1)
- [Developer Certificate of Origin (DCO)](#developer-certificate-of-origin-dco) - [Developer Certificate of Origin (DCO)](#developer-certificate-of-origin-dco)
- [Release Cycle](#release-cycle) - [Release Cycle](#release-cycle)
- [Maintainers](#maintainers) - [Maintainers](#maintainers)
@ -177,6 +178,43 @@ To maintain understandable code and avoid circular dependencies it is important
- **templates:** Golang templates for generating the html output. - **templates:** Golang templates for generating the html output.
- **vendor:** External code that Gitea depends on. - **vendor:** External code that Gitea depends on.
## API v1
The API is documented by [swagger](http://try.gitea.io/api/swagger) and is based on [GitHub API v3](https://developer.github.com/v3/).
Thus, Gitea´s API should use the same endpoints and fields as GitHub´s API as far as possible, unless there are good reasons to deviate.
If Gitea provides functionality that GitHub does not, a new endpoint can be created.
If information is provided by Gitea that is not provided by the GitHub API, a new field can be used that doesn't collide with any GitHub fields.
Updating an existing API should not remove existing fields unless there is a really good reason to do so.
The same applies to status responses. If you notice a problem, feel free to leave a comment in the code for future refactoring to APIv2 (which is currently not planned).
All expected results (errors, success, fail messages) should be documented
([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/repo/issue.go#L319-L327)).
All JSON input types must be defined as a struct in `models/structs/`
([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/modules/structs/issue.go#L76-L91))
and referenced in
[routers/api/v1/swagger/options.go](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/swagger/options.go).
They can then be used like the following:
([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/repo/issue.go#L318)).
All JSON responses must be defined as a struct in `models/structs/`
([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/modules/structs/issue.go#L36-L68))
and referenced in its category in `routers/api/v1/swagger/`
([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/swagger/issue.go#L11-L16))
They can be used like the following:
([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/repo/issue.go#L277-L279))
In general, HTTP methods are chosen as follows:
* **GET** endpoints return requested object and status **OK (200)**
* **DELETE** endpoints return status **No Content (204)**
* **POST** endpoints return status **Created (201)**, used to **create** new objects (e.g. a User)
* **PUT** endpoints return status **No Content (204)**, used to **add/assign** existing Obejcts (e.g. User) to something (e.g. Org-Team)
* **PATCH** endpoints return changed object and status **OK (200)**, used to **edit/change** an existing object
An endpoint which changes/edits an object expects all fields to be optional (except ones to identify the object, which are required).
## Developer Certificate of Origin (DCO) ## Developer Certificate of Origin (DCO)

View file

@ -76,6 +76,16 @@ WORK_IN_PROGRESS_PREFIXES=WIP:,[WIP]
CLOSE_KEYWORDS=close,closes,closed,fix,fixes,fixed,resolve,resolves,resolved CLOSE_KEYWORDS=close,closes,closed,fix,fixes,fixed,resolve,resolves,resolved
; List of keywords used in Pull Request comments to automatically reopen a related issue ; List of keywords used in Pull Request comments to automatically reopen a related issue
REOPEN_KEYWORDS=reopen,reopens,reopened REOPEN_KEYWORDS=reopen,reopens,reopened
; In the default merge message for squash commits include at most this many commits
DEFAULT_MERGE_MESSAGE_COMMITS_LIMIT=50
; In the default merge message for squash commits limit the size of the commit messages to this
DEFAULT_MERGE_MESSAGE_SIZE=5120
; In the default merge message for squash commits walk all commits to include all authors in the Co-authored-by otherwise just use those in the limited list
DEFAULT_MERGE_MESSAGE_ALL_AUTHORS=false
; In default merge messages limit the number of approvers listed as Reviewed-by: to this many
DEFAULT_MERGE_MESSAGE_MAX_APPROVERS=10
; In default merge messages only include approvers who are official
DEFAULT_MERGE_MESSAGE_OFFICIAL_APPROVERS_ONLY=true
[repository.issue] [repository.issue]
; List of reasons why a Pull Request or Issue can be locked ; List of reasons why a Pull Request or Issue can be locked

View file

@ -18,7 +18,7 @@ params:
description: Git with a cup of tea description: Git with a cup of tea
author: The Gitea Authors author: The Gitea Authors
website: https://docs.gitea.io website: https://docs.gitea.io
version: 1.10.1 version: 1.10.2
outputs: outputs:
home: home:

View file

@ -77,6 +77,11 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
keywords used in Pull Request comments to automatically close a related issue keywords used in Pull Request comments to automatically close a related issue
- `REOPEN_KEYWORDS`: **reopen**, **reopens**, **reopened**: List of keywords used in Pull Request comments to automatically reopen - `REOPEN_KEYWORDS`: **reopen**, **reopens**, **reopened**: List of keywords used in Pull Request comments to automatically reopen
a related issue a related issue
- `DEFAULT_MERGE_MESSAGE_COMMITS_LIMIT`: **50**: In the default merge message for squash commits include at most this many commits. Set to `-1` to include all commits
- `DEFAULT_MERGE_MESSAGE_SIZE`: **5120**: In the default merge message for squash commits limit the size of the commit messages. Set to `-1` to have no limit.
- `DEFAULT_MERGE_MESSAGE_ALL_AUTHORS`: **false**: In the default merge message for squash commits walk all commits to include all authors in the Co-authored-by otherwise just use those in the limited list
- `DEFAULT_MERGE_MESSAGE_MAX_APPROVERS`: **10**: In default merge messages limit the number of approvers listed as `Reviewed-by:`. Set to `-1` to include all.
- `DEFAULT_MERGE_MESSAGE_OFFICIAL_APPROVERS_ONLY`: **true**: In default merge messages only include approvers who are officially allowed to review.
### Repository - Issue (`repository.issue`) ### Repository - Issue (`repository.issue`)

View file

@ -80,10 +80,10 @@ Dont forget to restart your gitea to apply the changes.
### Adding links and tabs ### Adding links and tabs
If all you want is to add extra links to the top navigation bar, or extra tabs to the repository view, you can put them in `extra_links.tmpl` and `extra_tabs.tmpl` inside your `custom/templates/custom/` directory. If all you want is to add extra links to the top navigation bar or footer, or extra tabs to the repository view, you can put them in `extra_links.tmpl` (links added to the navbar), `extra_links_footer.tmpl` (links added to the left side of footer), and `extra_tabs.tmpl` inside your `custom/templates/custom/` directory.
For instance, let's say you are in Germany and must add the famously legally-required "Impressum"/about page, listing who is responsible for the site's content: For instance, let's say you are in Germany and must add the famously legally-required "Impressum"/about page, listing who is responsible for the site's content:
just place it under your "custom/public/" directory (for instance `custom/public/impressum.html`) and put a link to it in `custom/templates/custom/extra_links.tmpl`. just place it under your "custom/public/" directory (for instance `custom/public/impressum.html`) and put a link to it in either `custom/templates/custom/extra_links.tmpl` or `custom/templates/custom/extra_links_footer.tmpl`.
To match the current style, the link should have the class name "item", and you can use `{{AppSubUrl}}` to get the base URL: To match the current style, the link should have the class name "item", and you can use `{{AppSubUrl}}` to get the base URL:
`<a class="item" href="{{AppSubUrl}}/impressum.html">Impressum</a>` `<a class="item" href="{{AppSubUrl}}/impressum.html">Impressum</a>`

3
go.mod
View file

@ -79,11 +79,9 @@ require (
github.com/prometheus/procfs v0.0.4 // indirect github.com/prometheus/procfs v0.0.4 // indirect
github.com/quasoft/websspi v1.0.0 github.com/quasoft/websspi v1.0.0
github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001 // indirect github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001 // indirect
github.com/russross/blackfriday/v2 v2.0.1
github.com/satori/go.uuid v1.2.0 github.com/satori/go.uuid v1.2.0
github.com/sergi/go-diff v1.0.0 github.com/sergi/go-diff v1.0.0
github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b // indirect github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b // indirect
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd
github.com/steveyen/gtreap v0.0.0-20150807155958-0abe01ef9be2 // indirect github.com/steveyen/gtreap v0.0.0-20150807155958-0abe01ef9be2 // indirect
github.com/stretchr/testify v1.4.0 github.com/stretchr/testify v1.4.0
@ -95,6 +93,7 @@ require (
github.com/unknwon/paginater v0.0.0-20151104151617-7748a72e0141 github.com/unknwon/paginater v0.0.0-20151104151617-7748a72e0141
github.com/urfave/cli v1.20.0 github.com/urfave/cli v1.20.0
github.com/yohcop/openid-go v0.0.0-20160914080427-2c050d2dae53 github.com/yohcop/openid-go v0.0.0-20160914080427-2c050d2dae53
github.com/yuin/goldmark v1.1.19
go.etcd.io/bbolt v1.3.3 // indirect go.etcd.io/bbolt v1.3.3 // indirect
golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876 golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876
golang.org/x/net v0.0.0-20191101175033-0deb6923b6d9 golang.org/x/net v0.0.0-20191101175033-0deb6923b6d9

6
go.sum
View file

@ -462,16 +462,12 @@ github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001/go.mod h1:qq
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b h1:4kg1wyftSKxLtnPAvcRWakIPpokB9w780/KwrNLnfPA= github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b h1:4kg1wyftSKxLtnPAvcRWakIPpokB9w780/KwrNLnfPA=
github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd h1:ug7PpSOB5RBPK1Kg6qskGBoP3Vnj/aNYFTznWvlkGo0= github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd h1:ug7PpSOB5RBPK1Kg6qskGBoP3Vnj/aNYFTznWvlkGo0=
github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw= github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
@ -550,6 +546,8 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yohcop/openid-go v0.0.0-20160914080427-2c050d2dae53 h1:HsIQ6yAjfjQ3IxPGrTusxp6Qxn92gNVq2x5CbvQvx3w= github.com/yohcop/openid-go v0.0.0-20160914080427-2c050d2dae53 h1:HsIQ6yAjfjQ3IxPGrTusxp6Qxn92gNVq2x5CbvQvx3w=
github.com/yohcop/openid-go v0.0.0-20160914080427-2c050d2dae53/go.mod h1:f6elajwZV+xceiaqgRL090YzLEDGSbqr3poGL3ZgXYo= github.com/yohcop/openid-go v0.0.0-20160914080427-2c050d2dae53/go.mod h1:f6elajwZV+xceiaqgRL090YzLEDGSbqr3poGL3ZgXYo=
github.com/yuin/goldmark v1.1.19 h1:0s2/60x0XsFCXHeFut+F3azDVAAyIMyUfJRbRexiTYs=
github.com/yuin/goldmark v1.1.19/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=

View file

@ -47,7 +47,7 @@ func TestAPIIssuesReactions(t *testing.T) {
Reaction: "rocket", Reaction: "rocket",
}) })
resp = session.MakeRequest(t, req, http.StatusCreated) resp = session.MakeRequest(t, req, http.StatusCreated)
var apiNewReaction api.ReactionResponse var apiNewReaction api.Reaction
DecodeJSON(t, resp, &apiNewReaction) DecodeJSON(t, resp, &apiNewReaction)
//Add existing reaction //Add existing reaction
@ -56,10 +56,10 @@ func TestAPIIssuesReactions(t *testing.T) {
//Get end result of reaction list of issue #1 //Get end result of reaction list of issue #1
req = NewRequestf(t, "GET", urlStr) req = NewRequestf(t, "GET", urlStr)
resp = session.MakeRequest(t, req, http.StatusOK) resp = session.MakeRequest(t, req, http.StatusOK)
var apiReactions []*api.ReactionResponse var apiReactions []*api.Reaction
DecodeJSON(t, resp, &apiReactions) DecodeJSON(t, resp, &apiReactions)
expectResponse := make(map[int]api.ReactionResponse) expectResponse := make(map[int]api.Reaction)
expectResponse[0] = api.ReactionResponse{ expectResponse[0] = api.Reaction{
User: user2.APIFormat(), User: user2.APIFormat(),
Reaction: "eyes", Reaction: "eyes",
Created: time.Unix(1573248003, 0), Created: time.Unix(1573248003, 0),
@ -107,7 +107,7 @@ func TestAPICommentReactions(t *testing.T) {
Reaction: "+1", Reaction: "+1",
}) })
resp = session.MakeRequest(t, req, http.StatusCreated) resp = session.MakeRequest(t, req, http.StatusCreated)
var apiNewReaction api.ReactionResponse var apiNewReaction api.Reaction
DecodeJSON(t, resp, &apiNewReaction) DecodeJSON(t, resp, &apiNewReaction)
//Add existing reaction //Add existing reaction
@ -116,15 +116,15 @@ func TestAPICommentReactions(t *testing.T) {
//Get end result of reaction list of issue #1 //Get end result of reaction list of issue #1
req = NewRequestf(t, "GET", urlStr) req = NewRequestf(t, "GET", urlStr)
resp = session.MakeRequest(t, req, http.StatusOK) resp = session.MakeRequest(t, req, http.StatusOK)
var apiReactions []*api.ReactionResponse var apiReactions []*api.Reaction
DecodeJSON(t, resp, &apiReactions) DecodeJSON(t, resp, &apiReactions)
expectResponse := make(map[int]api.ReactionResponse) expectResponse := make(map[int]api.Reaction)
expectResponse[0] = api.ReactionResponse{ expectResponse[0] = api.Reaction{
User: user2.APIFormat(), User: user2.APIFormat(),
Reaction: "laugh", Reaction: "laugh",
Created: time.Unix(1573248004, 0), Created: time.Unix(1573248004, 0),
} }
expectResponse[1] = api.ReactionResponse{ expectResponse[1] = api.Reaction{
User: user1.APIFormat(), User: user1.APIFormat(),
Reaction: "laugh", Reaction: "laugh",
Created: time.Unix(1573248005, 0), Created: time.Unix(1573248005, 0),

View file

@ -62,3 +62,61 @@ func TestAPICreateIssue(t *testing.T) {
Title: title, Title: title,
}) })
} }
func TestAPIEditIssue(t *testing.T) {
defer prepareTestEnv(t)()
issueBefore := models.AssertExistsAndLoadBean(t, &models.Issue{ID: 10}).(*models.Issue)
repo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: issueBefore.RepoID}).(*models.Repository)
owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
assert.NoError(t, issueBefore.LoadAttributes())
assert.Equal(t, int64(1019307200), int64(issueBefore.DeadlineUnix))
assert.Equal(t, api.StateOpen, issueBefore.State())
session := loginUser(t, owner.Name)
token := getTokenForLoggedInUser(t, session)
// update values of issue
issueState := "closed"
removeDeadline := true
milestone := int64(4)
body := "new content!"
title := "new title from api set"
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d?token=%s", owner.Name, repo.Name, issueBefore.Index, token)
req := NewRequestWithJSON(t, "PATCH", urlStr, api.EditIssueOption{
State: &issueState,
RemoveDeadline: &removeDeadline,
Milestone: &milestone,
Body: &body,
Title: title,
// ToDo change more
})
resp := session.MakeRequest(t, req, http.StatusCreated)
var apiIssue api.Issue
DecodeJSON(t, resp, &apiIssue)
issueAfter := models.AssertExistsAndLoadBean(t, &models.Issue{ID: 10}).(*models.Issue)
// check deleted user
assert.Equal(t, int64(500), issueAfter.PosterID)
assert.NoError(t, issueAfter.LoadAttributes())
assert.Equal(t, int64(-1), issueAfter.PosterID)
assert.Equal(t, int64(-1), issueBefore.PosterID)
assert.Equal(t, int64(-1), apiIssue.Poster.ID)
// API response
assert.Equal(t, api.StateClosed, apiIssue.State)
assert.Equal(t, milestone, apiIssue.Milestone.ID)
assert.Equal(t, body, apiIssue.Body)
assert.True(t, apiIssue.Deadline == nil)
assert.Equal(t, title, apiIssue.Title)
// in database
assert.Equal(t, api.StateClosed, issueAfter.State())
assert.Equal(t, milestone, issueAfter.MilestoneID)
assert.Equal(t, int64(0), int64(issueAfter.DeadlineUnix))
assert.Equal(t, body, issueAfter.Content)
assert.Equal(t, title, issueAfter.Title)
}

View file

@ -1,88 +0,0 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package integrations
import (
"bytes"
"image"
"image/png"
"io"
"mime/multipart"
"net/http"
"testing"
"code.gitea.io/gitea/modules/test"
"github.com/stretchr/testify/assert"
)
func generateImg() bytes.Buffer {
// Generate image
myImage := image.NewRGBA(image.Rect(0, 0, 32, 32))
var buff bytes.Buffer
png.Encode(&buff, myImage)
return buff
}
func createAttachment(t *testing.T, session *TestSession, repoURL, filename string, buff bytes.Buffer, expectedStatus int) string {
body := &bytes.Buffer{}
//Setup multi-part
writer := multipart.NewWriter(body)
part, err := writer.CreateFormFile("file", filename)
assert.NoError(t, err)
_, err = io.Copy(part, &buff)
assert.NoError(t, err)
err = writer.Close()
assert.NoError(t, err)
csrf := GetCSRF(t, session, repoURL)
req := NewRequestWithBody(t, "POST", "/attachments", body)
req.Header.Add("X-Csrf-Token", csrf)
req.Header.Add("Content-Type", writer.FormDataContentType())
resp := session.MakeRequest(t, req, expectedStatus)
if expectedStatus != http.StatusOK {
return ""
}
var obj map[string]string
DecodeJSON(t, resp, &obj)
return obj["uuid"]
}
func TestCreateAnonymousAttachment(t *testing.T) {
prepareTestEnv(t)
session := emptyTestSession(t)
createAttachment(t, session, "user2/repo1", "image.png", generateImg(), http.StatusFound)
}
func TestCreateIssueAttachement(t *testing.T) {
prepareTestEnv(t)
const repoURL = "user2/repo1"
session := loginUser(t, "user2")
uuid := createAttachment(t, session, repoURL, "image.png", generateImg(), http.StatusOK)
req := NewRequest(t, "GET", repoURL+"/issues/new")
resp := session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
link, exists := htmlDoc.doc.Find("form").Attr("action")
assert.True(t, exists, "The template has changed")
postData := map[string]string{
"_csrf": htmlDoc.GetCSRF(),
"title": "New Issue With Attachement",
"content": "some content",
"files[0]": uuid,
}
req = NewRequestWithValues(t, "POST", link, postData)
resp = session.MakeRequest(t, req, http.StatusFound)
test.RedirectURL(resp) // check that redirect URL exists
//Validate that attachement is available
req = NewRequest(t, "GET", "/attachments/"+uuid)
session.MakeRequest(t, req, http.StatusOK)
}

View file

@ -0,0 +1,137 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package integrations
import (
"bytes"
"image"
"image/png"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"os"
"path"
"testing"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/test"
"github.com/stretchr/testify/assert"
)
func generateImg() bytes.Buffer {
// Generate image
myImage := image.NewRGBA(image.Rect(0, 0, 32, 32))
var buff bytes.Buffer
png.Encode(&buff, myImage)
return buff
}
func createAttachment(t *testing.T, session *TestSession, repoURL, filename string, buff bytes.Buffer, expectedStatus int) string {
body := &bytes.Buffer{}
//Setup multi-part
writer := multipart.NewWriter(body)
part, err := writer.CreateFormFile("file", filename)
assert.NoError(t, err)
_, err = io.Copy(part, &buff)
assert.NoError(t, err)
err = writer.Close()
assert.NoError(t, err)
csrf := GetCSRF(t, session, repoURL)
req := NewRequestWithBody(t, "POST", "/attachments", body)
req.Header.Add("X-Csrf-Token", csrf)
req.Header.Add("Content-Type", writer.FormDataContentType())
resp := session.MakeRequest(t, req, expectedStatus)
if expectedStatus != http.StatusOK {
return ""
}
var obj map[string]string
DecodeJSON(t, resp, &obj)
return obj["uuid"]
}
func TestCreateAnonymousAttachment(t *testing.T) {
prepareTestEnv(t)
session := emptyTestSession(t)
createAttachment(t, session, "user2/repo1", "image.png", generateImg(), http.StatusFound)
}
func TestCreateIssueAttachment(t *testing.T) {
prepareTestEnv(t)
const repoURL = "user2/repo1"
session := loginUser(t, "user2")
uuid := createAttachment(t, session, repoURL, "image.png", generateImg(), http.StatusOK)
req := NewRequest(t, "GET", repoURL+"/issues/new")
resp := session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
link, exists := htmlDoc.doc.Find("form").Attr("action")
assert.True(t, exists, "The template has changed")
postData := map[string]string{
"_csrf": htmlDoc.GetCSRF(),
"title": "New Issue With Attachment",
"content": "some content",
"files": uuid,
}
req = NewRequestWithValues(t, "POST", link, postData)
resp = session.MakeRequest(t, req, http.StatusFound)
test.RedirectURL(resp) // check that redirect URL exists
//Validate that attachment is available
req = NewRequest(t, "GET", "/attachments/"+uuid)
session.MakeRequest(t, req, http.StatusOK)
}
func TestGetAttachment(t *testing.T) {
prepareTestEnv(t)
adminSession := loginUser(t, "user1")
user2Session := loginUser(t, "user2")
user8Session := loginUser(t, "user8")
emptySession := emptyTestSession(t)
testCases := []struct {
name string
uuid string
createFile bool
session *TestSession
want int
}{
{"LinkedIssueUUID", "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11", true, user2Session, http.StatusOK},
{"LinkedCommentUUID", "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a17", true, user2Session, http.StatusOK},
{"linked_release_uuid", "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a19", true, user2Session, http.StatusOK},
{"NotExistingUUID", "b0eebc99-9c0b-4ef8-bb6d-6bb9bd380a18", false, user2Session, http.StatusNotFound},
{"FileMissing", "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a18", false, user2Session, http.StatusInternalServerError},
{"NotLinked", "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a20", true, user2Session, http.StatusNotFound},
{"NotLinkedAccessibleByUploader", "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a20", true, user8Session, http.StatusOK},
{"PublicByNonLogged", "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11", true, emptySession, http.StatusOK},
{"PrivateByNonLogged", "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a12", true, emptySession, http.StatusNotFound},
{"PrivateAccessibleByAdmin", "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a12", true, adminSession, http.StatusOK},
{"PrivateAccessibleByUser", "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a12", true, user2Session, http.StatusOK},
{"RepoNotAccessibleByUser", "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a12", true, user8Session, http.StatusNotFound},
{"OrgNotAccessibleByUser", "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a21", true, user8Session, http.StatusNotFound},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
//Write empty file to be available for response
if tc.createFile {
localPath := models.AttachmentLocalPath(tc.uuid)
err := os.MkdirAll(path.Dir(localPath), os.ModePerm)
assert.NoError(t, err)
err = ioutil.WriteFile(localPath, []byte("hello world"), 0644)
assert.NoError(t, err)
}
//Actual test
req := NewRequest(t, "GET", "/attachments/"+tc.uuid)
tc.session.MakeRequest(t, req, tc.want)
})
}
}

View file

@ -71,6 +71,26 @@ func (a *Attachment) DownloadURL() string {
return fmt.Sprintf("%sattachments/%s", setting.AppURL, a.UUID) return fmt.Sprintf("%sattachments/%s", setting.AppURL, a.UUID)
} }
// LinkedRepository returns the linked repo if any
func (a *Attachment) LinkedRepository() (*Repository, UnitType, error) {
if a.IssueID != 0 {
iss, err := GetIssueByID(a.IssueID)
if err != nil {
return nil, UnitTypeIssues, err
}
repo, err := GetRepositoryByID(iss.RepoID)
return repo, UnitTypeIssues, err
} else if a.ReleaseID != 0 {
rel, err := GetReleaseByID(a.ReleaseID)
if err != nil {
return nil, UnitTypeReleases, err
}
repo, err := GetRepositoryByID(rel.RepoID)
return repo, UnitTypeReleases, err
}
return nil, -1, nil
}
// NewAttachment creates a new attachment object. // NewAttachment creates a new attachment object.
func NewAttachment(attach *Attachment, buf []byte, file io.Reader) (_ *Attachment, err error) { func NewAttachment(attach *Attachment, buf []byte, file io.Reader) (_ *Attachment, err error) {
attach.UUID = gouuid.NewV4().String() attach.UUID = gouuid.NewV4().String()

View file

@ -61,7 +61,7 @@ func TestGetByCommentOrIssueID(t *testing.T) {
// count of attachments from issue ID // count of attachments from issue ID
attachments, err := GetAttachmentsByIssueID(1) attachments, err := GetAttachmentsByIssueID(1)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, 2, len(attachments)) assert.Equal(t, 1, len(attachments))
attachments, err = GetAttachmentsByCommentID(1) attachments, err = GetAttachmentsByCommentID(1)
assert.NoError(t, err) assert.NoError(t, err)
@ -73,7 +73,7 @@ func TestDeleteAttachments(t *testing.T) {
count, err := DeleteAttachmentsByIssue(4, false) count, err := DeleteAttachmentsByIssue(4, false)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, 1, count) assert.Equal(t, 2, count)
count, err = DeleteAttachmentsByComment(2, false) count, err = DeleteAttachmentsByComment(2, false)
assert.NoError(t, err) assert.NoError(t, err)
@ -128,3 +128,31 @@ func TestGetAttachmentsByUUIDs(t *testing.T) {
assert.Equal(t, int64(1), attachList[0].IssueID) assert.Equal(t, int64(1), attachList[0].IssueID)
assert.Equal(t, int64(5), attachList[1].IssueID) assert.Equal(t, int64(5), attachList[1].IssueID)
} }
func TestLinkedRepository(t *testing.T) {
assert.NoError(t, PrepareTestDatabase())
testCases := []struct {
name string
attachID int64
expectedRepo *Repository
expectedUnitType UnitType
}{
{"LinkedIssue", 1, &Repository{ID: 1}, UnitTypeIssues},
{"LinkedComment", 3, &Repository{ID: 1}, UnitTypeIssues},
{"LinkedRelease", 9, &Repository{ID: 1}, UnitTypeReleases},
{"Notlinked", 10, nil, -1},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
attach, err := GetAttachmentByID(tc.attachID)
assert.NoError(t, err)
repo, unitType, err := attach.LinkedRepository()
assert.NoError(t, err)
if tc.expectedRepo != nil {
assert.Equal(t, tc.expectedRepo.ID, repo.ID)
}
assert.Equal(t, tc.expectedUnitType, unitType)
})
}
}

View file

@ -44,6 +44,7 @@ type ProtectedBranch struct {
ApprovalsWhitelistUserIDs []int64 `xorm:"JSON TEXT"` ApprovalsWhitelistUserIDs []int64 `xorm:"JSON TEXT"`
ApprovalsWhitelistTeamIDs []int64 `xorm:"JSON TEXT"` ApprovalsWhitelistTeamIDs []int64 `xorm:"JSON TEXT"`
RequiredApprovals int64 `xorm:"NOT NULL DEFAULT 0"` RequiredApprovals int64 `xorm:"NOT NULL DEFAULT 0"`
BlockOnRejectedReviews bool `xorm:"NOT NULL DEFAULT false"`
CreatedUnix timeutil.TimeStamp `xorm:"created"` CreatedUnix timeutil.TimeStamp `xorm:"created"`
UpdatedUnix timeutil.TimeStamp `xorm:"updated"` UpdatedUnix timeutil.TimeStamp `xorm:"updated"`
} }
@ -166,6 +167,23 @@ func (protectBranch *ProtectedBranch) GetGrantedApprovalsCount(pr *PullRequest)
return approvals return approvals
} }
// MergeBlockedByRejectedReview returns true if merge is blocked by rejected reviews
func (protectBranch *ProtectedBranch) MergeBlockedByRejectedReview(pr *PullRequest) bool {
if !protectBranch.BlockOnRejectedReviews {
return false
}
rejectExist, err := x.Where("issue_id = ?", pr.IssueID).
And("type = ?", ReviewTypeReject).
And("official = ?", true).
Exist(new(Review))
if err != nil {
log.Error("MergeBlockedByRejectedReview: %v", err)
return true
}
return rejectExist
}
// GetProtectedBranchByRepoID getting protected branch by repo ID // GetProtectedBranchByRepoID getting protected branch by repo ID
func GetProtectedBranchByRepoID(repoID int64) ([]*ProtectedBranch, error) { func GetProtectedBranchByRepoID(repoID int64) ([]*ProtectedBranch, error) {
protectedBranches := make([]*ProtectedBranch, 0) protectedBranches := make([]*ProtectedBranch, 0)
@ -340,7 +358,7 @@ func (repo *Repository) IsProtectedBranchForMerging(pr *PullRequest, branchName
if err != nil { if err != nil {
return true, err return true, err
} else if has { } else if has {
return !protectedBranch.CanUserMerge(doer.ID) || !protectedBranch.HasEnoughApprovals(pr), nil return !protectedBranch.CanUserMerge(doer.ID) || !protectedBranch.HasEnoughApprovals(pr) || protectedBranch.MergeBlockedByRejectedReview(pr), nil
} }
return false, nil return false, nil

View file

@ -1201,6 +1201,21 @@ func (err ErrForbiddenIssueReaction) Error() string {
return fmt.Sprintf("'%s' is not an allowed reaction", err.Reaction) return fmt.Sprintf("'%s' is not an allowed reaction", err.Reaction)
} }
// ErrReactionAlreadyExist is used when a existing reaction was try to created
type ErrReactionAlreadyExist struct {
Reaction string
}
// IsErrReactionAlreadyExist checks if an error is a ErrReactionAlreadyExist.
func IsErrReactionAlreadyExist(err error) bool {
_, ok := err.(ErrReactionAlreadyExist)
return ok
}
func (err ErrReactionAlreadyExist) Error() string {
return fmt.Sprintf("reaction '%s' already exists", err.Reaction)
}
// __________ .__ .__ __________ __ // __________ .__ .__ __________ __
// \______ \__ __| | | |\______ \ ____ ________ __ ____ _______/ |_ // \______ \__ __| | | |\______ \ ____ ________ __ ____ _______/ |_
// | ___/ | \ | | | | _// __ \/ ____/ | \_/ __ \ / ___/\ __\ // | ___/ | \ | | | | _// __ \/ ____/ | \_/ __ \ / ___/\ __\

View file

@ -10,7 +10,7 @@
- -
id: 2 id: 2
uuid: a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a12 uuid: a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a12
issue_id: 1 issue_id: 4
comment_id: 0 comment_id: 0
name: attach2 name: attach2
download_count: 1 download_count: 1
@ -81,6 +81,15 @@
- -
id: 10 id: 10
uuid: a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a20 uuid: a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a20
uploader_id: 8
name: attach1 name: attach1
download_count: 0 download_count: 0
created_unix: 946684800 created_unix: 946684800
-
id: 11
uuid: a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a21
release_id: 2
name: attach1
download_count: 0
created_unix: 946684800

View file

@ -108,4 +108,17 @@
is_closed: false is_closed: false
is_pull: true is_pull: true
created_unix: 946684820 created_unix: 946684820
updated_unix: 978307180 updated_unix: 978307180
-
id: 10
repo_id: 42
index: 1
poster_id: 500
name: issue from deleted account
content: content from deleted account
is_closed: false
is_pull: false
created_unix: 946684830
updated_unix: 999307200
deadline_unix: 1019307200

View file

@ -21,3 +21,11 @@
content: content3 content: content3
is_closed: true is_closed: true
num_issues: 0 num_issues: 0
-
id: 4
repo_id: 42
name: milestone of repo42
content: content random
is_closed: false
num_issues: 0

View file

@ -11,4 +11,19 @@
is_draft: false is_draft: false
is_prerelease: false is_prerelease: false
is_tag: false is_tag: false
created_unix: 946684800 created_unix: 946684800
-
id: 2
repo_id: 40
publisher_id: 2
tag_name: "v1.1"
lower_tag_name: "v1.1"
target: "master"
title: "testing-release"
sha1: "65f1bf27bc3bf70f64657658635e66094edbcb4d"
num_commits: 10
is_draft: false
is_prerelease: false
is_tag: false
created_unix: 946684800

View file

@ -472,4 +472,10 @@
repo_id: 48 repo_id: 48
type: 7 type: 7
config: "{\"ExternalTrackerURL\":\"https://tracker.com\",\"ExternalTrackerFormat\":\"https://tracker.com/{user}/{repo}/issues/{index}\",\"ExternalTrackerStyle\":\"alphanumeric\"}" config: "{\"ExternalTrackerURL\":\"https://tracker.com\",\"ExternalTrackerFormat\":\"https://tracker.com/{user}/{repo}/issues/{index}\",\"ExternalTrackerStyle\":\"alphanumeric\"}"
created_unix: 946684810
-
id: 69
repo_id: 2
type: 2
config: "{}"
created_unix: 946684810 created_unix: 946684810

View file

@ -547,7 +547,8 @@
is_private: false is_private: false
num_stars: 0 num_stars: 0
num_forks: 0 num_forks: 0
num_issues: 0 num_issues: 1
num_milestones: 1
is_mirror: false is_mirror: false
- -
@ -588,7 +589,7 @@
is_mirror: false is_mirror: false
status: 0 status: 0
- -
id: 46 id: 46
owner_id: 26 owner_id: 26
lower_name: repo_external_tracker lower_name: repo_external_tracker
@ -600,7 +601,7 @@
is_mirror: false is_mirror: false
status: 0 status: 0
- -
id: 47 id: 47
owner_id: 26 owner_id: 26
lower_name: repo_external_tracker_numeric lower_name: repo_external_tracker_numeric
@ -612,7 +613,7 @@
is_mirror: false is_mirror: false
status: 0 status: 0
- -
id: 48 id: 48
owner_id: 26 owner_id: 26
lower_name: repo_external_tracker_alpha lower_name: repo_external_tracker_alpha

View file

@ -1,4 +1,5 @@
// Copyright 2014 The Gogs Authors. All rights reserved. // Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2020 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style // Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -239,6 +240,16 @@ func (issue *Issue) loadReactions(e Engine) (err error) {
return nil return nil
} }
func (issue *Issue) loadMilestone(e Engine) (err error) {
if issue.Milestone == nil && issue.MilestoneID > 0 {
issue.Milestone, err = getMilestoneByRepoID(e, issue.RepoID, issue.MilestoneID)
if err != nil && !IsErrMilestoneNotExist(err) {
return fmt.Errorf("getMilestoneByRepoID [repo_id: %d, milestone_id: %d]: %v", issue.RepoID, issue.MilestoneID, err)
}
}
return nil
}
func (issue *Issue) loadAttributes(e Engine) (err error) { func (issue *Issue) loadAttributes(e Engine) (err error) {
if err = issue.loadRepo(e); err != nil { if err = issue.loadRepo(e); err != nil {
return return
@ -252,11 +263,8 @@ func (issue *Issue) loadAttributes(e Engine) (err error) {
return return
} }
if issue.Milestone == nil && issue.MilestoneID > 0 { if err = issue.loadMilestone(e); err != nil {
issue.Milestone, err = getMilestoneByRepoID(e, issue.RepoID, issue.MilestoneID) return
if err != nil && !IsErrMilestoneNotExist(err) {
return fmt.Errorf("getMilestoneByRepoID [repo_id: %d, milestone_id: %d]: %v", issue.RepoID, issue.MilestoneID, err)
}
} }
if err = issue.loadAssignees(e); err != nil { if err = issue.loadAssignees(e); err != nil {
@ -296,6 +304,11 @@ func (issue *Issue) LoadAttributes() error {
return issue.loadAttributes(x) return issue.loadAttributes(x)
} }
// LoadMilestone load milestone of this issue.
func (issue *Issue) LoadMilestone() error {
return issue.loadMilestone(x)
}
// GetIsRead load the `IsRead` field of the issue // GetIsRead load the `IsRead` field of the issue
func (issue *Issue) GetIsRead(userID int64) error { func (issue *Issue) GetIsRead(userID int64) error {
issueUser := &IssueUser{IssueID: issue.ID, UID: userID} issueUser := &IssueUser{IssueID: issue.ID, UID: userID}
@ -1568,27 +1581,25 @@ func SearchIssueIDsByKeyword(kw string, repoIDs []int64, limit, start int) (int6
return total, ids, nil return total, ids, nil
} }
func updateIssue(e Engine, issue *Issue) error { // UpdateIssueByAPI updates all allowed fields of given issue.
_, err := e.ID(issue.ID).AllCols().Update(issue) func UpdateIssueByAPI(issue *Issue) error {
if err != nil {
return err
}
return nil
}
// UpdateIssue updates all fields of given issue.
func UpdateIssue(issue *Issue) error {
sess := x.NewSession() sess := x.NewSession()
defer sess.Close() defer sess.Close()
if err := sess.Begin(); err != nil { if err := sess.Begin(); err != nil {
return err return err
} }
if err := updateIssue(sess, issue); err != nil {
if _, err := sess.ID(issue.ID).Cols(
"name", "is_closed", "content", "milestone_id", "priority",
"deadline_unix", "updated_unix", "closed_unix", "is_locked").
Update(issue); err != nil {
return err return err
} }
if err := issue.loadPoster(sess); err != nil { if err := issue.loadPoster(sess); err != nil {
return err return err
} }
if err := issue.addCrossReferences(sess, issue.Poster, true); err != nil { if err := issue.addCrossReferences(sess, issue.Poster, true); err != nil {
return err return err
} }

View file

@ -30,6 +30,8 @@ type Reaction struct {
type FindReactionsOptions struct { type FindReactionsOptions struct {
IssueID int64 IssueID int64
CommentID int64 CommentID int64
UserID int64
Reaction string
} }
func (opts *FindReactionsOptions) toConds() builder.Cond { func (opts *FindReactionsOptions) toConds() builder.Cond {
@ -46,6 +48,12 @@ func (opts *FindReactionsOptions) toConds() builder.Cond {
} else if opts.CommentID == -1 { } else if opts.CommentID == -1 {
cond = cond.And(builder.Eq{"reaction.comment_id": 0}) cond = cond.And(builder.Eq{"reaction.comment_id": 0})
} }
if opts.UserID > 0 {
cond = cond.And(builder.Eq{"reaction.user_id": opts.UserID})
}
if opts.Reaction != "" {
cond = cond.And(builder.Eq{"reaction.type": opts.Reaction})
}
return cond return cond
} }
@ -80,9 +88,25 @@ func createReaction(e *xorm.Session, opts *ReactionOptions) (*Reaction, error) {
UserID: opts.Doer.ID, UserID: opts.Doer.ID,
IssueID: opts.Issue.ID, IssueID: opts.Issue.ID,
} }
findOpts := FindReactionsOptions{
IssueID: opts.Issue.ID,
CommentID: -1, // reaction to issue only
Reaction: opts.Type,
UserID: opts.Doer.ID,
}
if opts.Comment != nil { if opts.Comment != nil {
reaction.CommentID = opts.Comment.ID reaction.CommentID = opts.Comment.ID
findOpts.CommentID = opts.Comment.ID
} }
existingR, err := findReactions(e, findOpts)
if err != nil {
return nil, err
}
if len(existingR) > 0 {
return existingR[0], ErrReactionAlreadyExist{Reaction: opts.Type}
}
if _, err := e.Insert(reaction); err != nil { if _, err := e.Insert(reaction); err != nil {
return nil, err return nil, err
} }
@ -99,23 +123,23 @@ type ReactionOptions struct {
} }
// CreateReaction creates reaction for issue or comment. // CreateReaction creates reaction for issue or comment.
func CreateReaction(opts *ReactionOptions) (reaction *Reaction, err error) { func CreateReaction(opts *ReactionOptions) (*Reaction, error) {
if !setting.UI.ReactionsMap[opts.Type] { if !setting.UI.ReactionsMap[opts.Type] {
return nil, ErrForbiddenIssueReaction{opts.Type} return nil, ErrForbiddenIssueReaction{opts.Type}
} }
sess := x.NewSession() sess := x.NewSession()
defer sess.Close() defer sess.Close()
if err = sess.Begin(); err != nil { if err := sess.Begin(); err != nil {
return nil, err return nil, err
} }
reaction, err = createReaction(sess, opts) reaction, err := createReaction(sess, opts)
if err != nil { if err != nil {
return nil, err return reaction, err
} }
if err = sess.Commit(); err != nil { if err := sess.Commit(); err != nil {
return nil, err return nil, err
} }
return reaction, nil return reaction, nil

View file

@ -50,9 +50,10 @@ func TestIssueAddDuplicateReaction(t *testing.T) {
Type: "heart", Type: "heart",
}) })
assert.Error(t, err) assert.Error(t, err)
assert.Nil(t, reaction) assert.Equal(t, ErrReactionAlreadyExist{Reaction: "heart"}, err)
AssertExistsAndLoadBean(t, &Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1.ID}) existingR := AssertExistsAndLoadBean(t, &Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1.ID}).(*Reaction)
assert.Equal(t, existingR.ID, reaction.ID)
} }
func TestIssueDeleteReaction(t *testing.T) { func TestIssueDeleteReaction(t *testing.T) {
@ -129,7 +130,6 @@ func TestIssueCommentDeleteReaction(t *testing.T) {
user2 := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User) user2 := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
user3 := AssertExistsAndLoadBean(t, &User{ID: 3}).(*User) user3 := AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
user4 := AssertExistsAndLoadBean(t, &User{ID: 4}).(*User) user4 := AssertExistsAndLoadBean(t, &User{ID: 4}).(*User)
ghost := NewGhostUser()
issue1 := AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue) issue1 := AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue)
@ -139,14 +139,13 @@ func TestIssueCommentDeleteReaction(t *testing.T) {
addReaction(t, user2, issue1, comment1, "heart") addReaction(t, user2, issue1, comment1, "heart")
addReaction(t, user3, issue1, comment1, "heart") addReaction(t, user3, issue1, comment1, "heart")
addReaction(t, user4, issue1, comment1, "+1") addReaction(t, user4, issue1, comment1, "+1")
addReaction(t, ghost, issue1, comment1, "heart")
err := comment1.LoadReactions() err := comment1.LoadReactions()
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, comment1.Reactions, 5) assert.Len(t, comment1.Reactions, 4)
reactions := comment1.Reactions.GroupByType() reactions := comment1.Reactions.GroupByType()
assert.Len(t, reactions["heart"], 4) assert.Len(t, reactions["heart"], 3)
assert.Len(t, reactions["+1"], 1) assert.Len(t, reactions["+1"], 1)
} }
@ -160,7 +159,7 @@ func TestIssueCommentReactionCount(t *testing.T) {
comment1 := AssertExistsAndLoadBean(t, &Comment{ID: 1}).(*Comment) comment1 := AssertExistsAndLoadBean(t, &Comment{ID: 1}).(*Comment)
addReaction(t, user1, issue1, comment1, "heart") addReaction(t, user1, issue1, comment1, "heart")
DeleteCommentReaction(user1, issue1, comment1, "heart") assert.NoError(t, DeleteCommentReaction(user1, issue1, comment1, "heart"))
AssertNotExistsBean(t, &Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1.ID, CommentID: comment1.ID}) AssertNotExistsBean(t, &Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1.ID, CommentID: comment1.ID})
} }

View file

@ -288,6 +288,8 @@ var migrations = []Migration{
NewMigration("add user_id prefix to existing user avatar name", renameExistingUserAvatarName), NewMigration("add user_id prefix to existing user avatar name", renameExistingUserAvatarName),
// v116 -> v117 // v116 -> v117
NewMigration("Extend TrackedTimes", extendTrackedTimes), NewMigration("Extend TrackedTimes", extendTrackedTimes),
// v117 -> v118
NewMigration("Add block on rejected reviews branch protection", addBlockOnRejectedReviews),
} }
// Migrate database to current version // Migrate database to current version

17
models/migrations/v117.go Normal file
View file

@ -0,0 +1,17 @@
// Copyright 2020 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
import (
"xorm.io/xorm"
)
func addBlockOnRejectedReviews(x *xorm.Engine) error {
type ProtectedBranch struct {
BlockOnRejectedReviews bool `xorm:"NOT NULL DEFAULT false"`
}
return x.Sync2(new(ProtectedBranch))
}

View file

@ -7,6 +7,7 @@ package models
import ( import (
"fmt" "fmt"
"io"
"strings" "strings"
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
@ -177,6 +178,206 @@ func (pr *PullRequest) GetDefaultMergeMessage() string {
return fmt.Sprintf("Merge branch '%s' of %s/%s into %s", pr.HeadBranch, pr.MustHeadUserName(), pr.HeadRepo.Name, pr.BaseBranch) return fmt.Sprintf("Merge branch '%s' of %s/%s into %s", pr.HeadBranch, pr.MustHeadUserName(), pr.HeadRepo.Name, pr.BaseBranch)
} }
// GetCommitMessages returns the commit messages between head and merge base (if there is one)
func (pr *PullRequest) GetCommitMessages() string {
if err := pr.LoadIssue(); err != nil {
log.Error("Cannot load issue %d for PR id %d: Error: %v", pr.IssueID, pr.ID, err)
return ""
}
if err := pr.Issue.LoadPoster(); err != nil {
log.Error("Cannot load poster %d for pr id %d, index %d Error: %v", pr.Issue.PosterID, pr.ID, pr.Index, err)
return ""
}
if pr.HeadRepo == nil {
var err error
pr.HeadRepo, err = GetRepositoryByID(pr.HeadRepoID)
if err != nil {
log.Error("GetRepositoryById[%d]: %v", pr.HeadRepoID, err)
return ""
}
}
gitRepo, err := git.OpenRepository(pr.HeadRepo.RepoPath())
if err != nil {
log.Error("Unable to open head repository: Error: %v", err)
return ""
}
defer gitRepo.Close()
headCommit, err := gitRepo.GetBranchCommit(pr.HeadBranch)
if err != nil {
log.Error("Unable to get head commit: %s Error: %v", pr.HeadBranch, err)
return ""
}
mergeBase, err := gitRepo.GetCommit(pr.MergeBase)
if err != nil {
log.Error("Unable to get merge base commit: %s Error: %v", pr.MergeBase, err)
return ""
}
limit := setting.Repository.PullRequest.DefaultMergeMessageCommitsLimit
list, err := gitRepo.CommitsBetweenLimit(headCommit, mergeBase, limit, 0)
if err != nil {
log.Error("Unable to get commits between: %s %s Error: %v", pr.HeadBranch, pr.MergeBase, err)
return ""
}
maxSize := setting.Repository.PullRequest.DefaultMergeMessageSize
posterSig := pr.Issue.Poster.NewGitSig().String()
authorsMap := map[string]bool{}
authors := make([]string, 0, list.Len())
stringBuilder := strings.Builder{}
element := list.Front()
for element != nil {
commit := element.Value.(*git.Commit)
if maxSize < 0 || stringBuilder.Len() < maxSize {
toWrite := []byte(commit.CommitMessage)
if len(toWrite) > maxSize-stringBuilder.Len() && maxSize > -1 {
toWrite = append(toWrite[:maxSize-stringBuilder.Len()], "..."...)
}
if _, err := stringBuilder.Write(toWrite); err != nil {
log.Error("Unable to write commit message Error: %v", err)
return ""
}
if _, err := stringBuilder.WriteRune('\n'); err != nil {
log.Error("Unable to write commit message Error: %v", err)
return ""
}
}
authorString := commit.Author.String()
if !authorsMap[authorString] && authorString != posterSig {
authors = append(authors, authorString)
authorsMap[authorString] = true
}
element = element.Next()
}
// Consider collecting the remaining authors
if limit >= 0 && setting.Repository.PullRequest.DefaultMergeMessageAllAuthors {
skip := limit
limit = 30
for {
list, err := gitRepo.CommitsBetweenLimit(headCommit, mergeBase, limit, skip)
if err != nil {
log.Error("Unable to get commits between: %s %s Error: %v", pr.HeadBranch, pr.MergeBase, err)
return ""
}
if list.Len() == 0 {
break
}
element := list.Front()
for element != nil {
commit := element.Value.(*git.Commit)
authorString := commit.Author.String()
if !authorsMap[authorString] && authorString != posterSig {
authors = append(authors, authorString)
authorsMap[authorString] = true
}
element = element.Next()
}
}
}
if len(authors) > 0 {
if _, err := stringBuilder.WriteRune('\n'); err != nil {
log.Error("Unable to write to string builder Error: %v", err)
return ""
}
}
for _, author := range authors {
if _, err := stringBuilder.Write([]byte("Co-authored-by: ")); err != nil {
log.Error("Unable to write to string builder Error: %v", err)
return ""
}
if _, err := stringBuilder.Write([]byte(author)); err != nil {
log.Error("Unable to write to string builder Error: %v", err)
return ""
}
if _, err := stringBuilder.WriteRune('\n'); err != nil {
log.Error("Unable to write to string builder Error: %v", err)
return ""
}
}
return stringBuilder.String()
}
// GetApprovers returns the approvers of the pull request
func (pr *PullRequest) GetApprovers() string {
stringBuilder := strings.Builder{}
if err := pr.getReviewedByLines(&stringBuilder); err != nil {
log.Error("Unable to getReviewedByLines: Error: %v", err)
return ""
}
return stringBuilder.String()
}
func (pr *PullRequest) getReviewedByLines(writer io.Writer) error {
maxReviewers := setting.Repository.PullRequest.DefaultMergeMessageMaxApprovers
if maxReviewers == 0 {
return nil
}
sess := x.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
return err
}
// Note: This doesn't page as we only expect a very limited number of reviews
reviews, err := findReviews(sess, FindReviewOptions{
Type: ReviewTypeApprove,
IssueID: pr.IssueID,
OfficialOnly: setting.Repository.PullRequest.DefaultMergeMessageOfficialApproversOnly,
})
if err != nil {
log.Error("Unable to FindReviews for PR ID %d: %v", pr.ID, err)
return err
}
reviewersWritten := 0
for _, review := range reviews {
if maxReviewers > 0 && reviewersWritten > maxReviewers {
break
}
if err := review.loadReviewer(sess); err != nil && !IsErrUserNotExist(err) {
log.Error("Unable to LoadReviewer[%d] for PR ID %d : %v", review.ReviewerID, pr.ID, err)
return err
} else if review.Reviewer == nil {
continue
}
if _, err := writer.Write([]byte("Reviewed-by: ")); err != nil {
return err
}
if _, err := writer.Write([]byte(review.Reviewer.NewGitSig().String())); err != nil {
return err
}
if _, err := writer.Write([]byte{'\n'}); err != nil {
return err
}
reviewersWritten++
}
return sess.Commit()
}
// GetDefaultSquashMessage returns default message used when squash and merging pull request // GetDefaultSquashMessage returns default message used when squash and merging pull request
func (pr *PullRequest) GetDefaultSquashMessage() string { func (pr *PullRequest) GetDefaultSquashMessage() string {
if err := pr.LoadIssue(); err != nil { if err := pr.LoadIssue(); err != nil {

View file

@ -125,9 +125,10 @@ func GetReviewByID(id int64) (*Review, error) {
// FindReviewOptions represent possible filters to find reviews // FindReviewOptions represent possible filters to find reviews
type FindReviewOptions struct { type FindReviewOptions struct {
Type ReviewType Type ReviewType
IssueID int64 IssueID int64
ReviewerID int64 ReviewerID int64
OfficialOnly bool
} }
func (opts *FindReviewOptions) toCond() builder.Cond { func (opts *FindReviewOptions) toCond() builder.Cond {
@ -141,6 +142,9 @@ func (opts *FindReviewOptions) toCond() builder.Cond {
if opts.Type != ReviewTypeUnknown { if opts.Type != ReviewTypeUnknown {
cond = cond.And(builder.Eq{"type": opts.Type}) cond = cond.And(builder.Eq{"type": opts.Type})
} }
if opts.OfficialOnly {
cond = cond.And(builder.Eq{"official": true})
}
return cond return cond
} }

View file

@ -791,6 +791,14 @@ func NewGhostUser() *User {
} }
} }
// IsGhost check if user is fake user for a deleted account
func (u *User) IsGhost() bool {
if u == nil {
return false
}
return u.ID == -1 && u.Name == "Ghost"
}
var ( var (
reservedUsernames = []string{ reservedUsernames = []string{
"attachments", "attachments",

View file

@ -171,6 +171,7 @@ type ProtectBranchForm struct {
EnableApprovalsWhitelist bool EnableApprovalsWhitelist bool
ApprovalsWhitelistUsers string ApprovalsWhitelistUsers string
ApprovalsWhitelistTeams string ApprovalsWhitelistTeams string
BlockOnRejectedReviews bool
} }
// Validate validates the fields // Validate validates the fields

View file

@ -315,7 +315,28 @@ func (repo *Repository) FilesCountBetween(startCommitID, endCommitID string) (in
// CommitsBetween returns a list that contains commits between [last, before). // CommitsBetween returns a list that contains commits between [last, before).
func (repo *Repository) CommitsBetween(last *Commit, before *Commit) (*list.List, error) { func (repo *Repository) CommitsBetween(last *Commit, before *Commit) (*list.List, error) {
stdout, err := NewCommand("rev-list", before.ID.String()+"..."+last.ID.String()).RunInDirBytes(repo.Path) var stdout []byte
var err error
if before == nil {
stdout, err = NewCommand("rev-list", before.ID.String()).RunInDirBytes(repo.Path)
} else {
stdout, err = NewCommand("rev-list", before.ID.String()+"..."+last.ID.String()).RunInDirBytes(repo.Path)
}
if err != nil {
return nil, err
}
return repo.parsePrettyFormatLogToList(bytes.TrimSpace(stdout))
}
// CommitsBetweenLimit returns a list that contains at most limit commits skipping the first skip commits between [last, before)
func (repo *Repository) CommitsBetweenLimit(last *Commit, before *Commit, limit, skip int) (*list.List, error) {
var stdout []byte
var err error
if before == nil {
stdout, err = NewCommand("rev-list", "--max-count", strconv.Itoa(limit), "--skip", strconv.Itoa(skip), last.ID.String()).RunInDirBytes(repo.Path)
} else {
stdout, err = NewCommand("rev-list", "--max-count", strconv.Itoa(limit), "--skip", strconv.Itoa(skip), before.ID.String()+"..."+last.ID.String()).RunInDirBytes(repo.Path)
}
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -328,6 +349,9 @@ func (repo *Repository) CommitsBetweenIDs(last, before string) (*list.List, erro
if err != nil { if err != nil {
return nil, err return nil, err
} }
if before == "" {
return repo.CommitsBetween(lastCommit, nil)
}
beforeCommit, err := repo.GetCommit(before) beforeCommit, err := repo.GetCommit(before)
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -0,0 +1,507 @@
// Copyright 2019 Yusuke Inuzuka
// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
// Most of what follows is a subtly changed version of github.com/yuin/goldmark/extension/footnote.go
package common
import (
"bytes"
"fmt"
"os"
"strconv"
"unicode"
"github.com/yuin/goldmark"
"github.com/yuin/goldmark/ast"
"github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/renderer"
"github.com/yuin/goldmark/renderer/html"
"github.com/yuin/goldmark/text"
"github.com/yuin/goldmark/util"
)
// CleanValue will clean a value to make it safe to be an id
// This function is quite different from the original goldmark function
// and more closely matches the output from the shurcooL sanitizer
// In particular Unicode letters and numbers are a lot more than a-zA-Z0-9...
func CleanValue(value []byte) []byte {
value = bytes.TrimSpace(value)
rs := bytes.Runes(value)
result := make([]rune, 0, len(rs))
needsDash := false
for _, r := range rs {
switch {
case unicode.IsLetter(r) || unicode.IsNumber(r):
if needsDash && len(result) > 0 {
result = append(result, '-')
}
needsDash = false
result = append(result, unicode.ToLower(r))
default:
needsDash = true
}
}
return []byte(string(result))
}
// Most of what follows is a subtly changed version of github.com/yuin/goldmark/extension/footnote.go
// A FootnoteLink struct represents a link to a footnote of Markdown
// (PHP Markdown Extra) text.
type FootnoteLink struct {
ast.BaseInline
Index int
Name []byte
}
// Dump implements Node.Dump.
func (n *FootnoteLink) Dump(source []byte, level int) {
m := map[string]string{}
m["Index"] = fmt.Sprintf("%v", n.Index)
m["Name"] = fmt.Sprintf("%v", n.Name)
ast.DumpHelper(n, source, level, m, nil)
}
// KindFootnoteLink is a NodeKind of the FootnoteLink node.
var KindFootnoteLink = ast.NewNodeKind("GiteaFootnoteLink")
// Kind implements Node.Kind.
func (n *FootnoteLink) Kind() ast.NodeKind {
return KindFootnoteLink
}
// NewFootnoteLink returns a new FootnoteLink node.
func NewFootnoteLink(index int, name []byte) *FootnoteLink {
return &FootnoteLink{
Index: index,
Name: name,
}
}
// A FootnoteBackLink struct represents a link to a footnote of Markdown
// (PHP Markdown Extra) text.
type FootnoteBackLink struct {
ast.BaseInline
Index int
Name []byte
}
// Dump implements Node.Dump.
func (n *FootnoteBackLink) Dump(source []byte, level int) {
m := map[string]string{}
m["Index"] = fmt.Sprintf("%v", n.Index)
m["Name"] = fmt.Sprintf("%v", n.Name)
ast.DumpHelper(n, source, level, m, nil)
}
// KindFootnoteBackLink is a NodeKind of the FootnoteBackLink node.
var KindFootnoteBackLink = ast.NewNodeKind("GiteaFootnoteBackLink")
// Kind implements Node.Kind.
func (n *FootnoteBackLink) Kind() ast.NodeKind {
return KindFootnoteBackLink
}
// NewFootnoteBackLink returns a new FootnoteBackLink node.
func NewFootnoteBackLink(index int, name []byte) *FootnoteBackLink {
return &FootnoteBackLink{
Index: index,
Name: name,
}
}
// A Footnote struct represents a footnote of Markdown
// (PHP Markdown Extra) text.
type Footnote struct {
ast.BaseBlock
Ref []byte
Index int
Name []byte
}
// Dump implements Node.Dump.
func (n *Footnote) Dump(source []byte, level int) {
m := map[string]string{}
m["Index"] = fmt.Sprintf("%v", n.Index)
m["Ref"] = fmt.Sprintf("%s", n.Ref)
m["Name"] = fmt.Sprintf("%v", n.Name)
ast.DumpHelper(n, source, level, m, nil)
}
// KindFootnote is a NodeKind of the Footnote node.
var KindFootnote = ast.NewNodeKind("GiteaFootnote")
// Kind implements Node.Kind.
func (n *Footnote) Kind() ast.NodeKind {
return KindFootnote
}
// NewFootnote returns a new Footnote node.
func NewFootnote(ref []byte) *Footnote {
return &Footnote{
Ref: ref,
Index: -1,
Name: ref,
}
}
// A FootnoteList struct represents footnotes of Markdown
// (PHP Markdown Extra) text.
type FootnoteList struct {
ast.BaseBlock
Count int
}
// Dump implements Node.Dump.
func (n *FootnoteList) Dump(source []byte, level int) {
m := map[string]string{}
m["Count"] = fmt.Sprintf("%v", n.Count)
ast.DumpHelper(n, source, level, m, nil)
}
// KindFootnoteList is a NodeKind of the FootnoteList node.
var KindFootnoteList = ast.NewNodeKind("GiteaFootnoteList")
// Kind implements Node.Kind.
func (n *FootnoteList) Kind() ast.NodeKind {
return KindFootnoteList
}
// NewFootnoteList returns a new FootnoteList node.
func NewFootnoteList() *FootnoteList {
return &FootnoteList{
Count: 0,
}
}
var footnoteListKey = parser.NewContextKey()
type footnoteBlockParser struct {
}
var defaultFootnoteBlockParser = &footnoteBlockParser{}
// NewFootnoteBlockParser returns a new parser.BlockParser that can parse
// footnotes of the Markdown(PHP Markdown Extra) text.
func NewFootnoteBlockParser() parser.BlockParser {
return defaultFootnoteBlockParser
}
func (b *footnoteBlockParser) Trigger() []byte {
return []byte{'['}
}
func (b *footnoteBlockParser) Open(parent ast.Node, reader text.Reader, pc parser.Context) (ast.Node, parser.State) {
line, segment := reader.PeekLine()
pos := pc.BlockOffset()
if pos < 0 || line[pos] != '[' {
return nil, parser.NoChildren
}
pos++
if pos > len(line)-1 || line[pos] != '^' {
return nil, parser.NoChildren
}
open := pos + 1
closes := 0
closure := util.FindClosure(line[pos+1:], '[', ']', false, false)
closes = pos + 1 + closure
next := closes + 1
if closure > -1 {
if next >= len(line) || line[next] != ':' {
return nil, parser.NoChildren
}
} else {
return nil, parser.NoChildren
}
padding := segment.Padding
label := reader.Value(text.NewSegment(segment.Start+open-padding, segment.Start+closes-padding))
if util.IsBlank(label) {
return nil, parser.NoChildren
}
item := NewFootnote(label)
pos = next + 1 - padding
if pos >= len(line) {
reader.Advance(pos)
return item, parser.NoChildren
}
reader.AdvanceAndSetPadding(pos, padding)
return item, parser.HasChildren
}
func (b *footnoteBlockParser) Continue(node ast.Node, reader text.Reader, pc parser.Context) parser.State {
line, _ := reader.PeekLine()
if util.IsBlank(line) {
return parser.Continue | parser.HasChildren
}
childpos, padding := util.IndentPosition(line, reader.LineOffset(), 4)
if childpos < 0 {
return parser.Close
}
reader.AdvanceAndSetPadding(childpos, padding)
return parser.Continue | parser.HasChildren
}
func (b *footnoteBlockParser) Close(node ast.Node, reader text.Reader, pc parser.Context) {
var list *FootnoteList
if tlist := pc.Get(footnoteListKey); tlist != nil {
list = tlist.(*FootnoteList)
} else {
list = NewFootnoteList()
pc.Set(footnoteListKey, list)
node.Parent().InsertBefore(node.Parent(), node, list)
}
node.Parent().RemoveChild(node.Parent(), node)
list.AppendChild(list, node)
}
func (b *footnoteBlockParser) CanInterruptParagraph() bool {
return true
}
func (b *footnoteBlockParser) CanAcceptIndentedLine() bool {
return false
}
type footnoteParser struct {
}
var defaultFootnoteParser = &footnoteParser{}
// NewFootnoteParser returns a new parser.InlineParser that can parse
// footnote links of the Markdown(PHP Markdown Extra) text.
func NewFootnoteParser() parser.InlineParser {
return defaultFootnoteParser
}
func (s *footnoteParser) Trigger() []byte {
// footnote syntax probably conflict with the image syntax.
// So we need trigger this parser with '!'.
return []byte{'!', '['}
}
func (s *footnoteParser) Parse(parent ast.Node, block text.Reader, pc parser.Context) ast.Node {
line, segment := block.PeekLine()
pos := 1
if len(line) > 0 && line[0] == '!' {
pos++
}
if pos >= len(line) || line[pos] != '^' {
return nil
}
pos++
if pos >= len(line) {
return nil
}
open := pos
closure := util.FindClosure(line[pos:], '[', ']', false, false)
if closure < 0 {
return nil
}
closes := pos + closure
value := block.Value(text.NewSegment(segment.Start+open, segment.Start+closes))
block.Advance(closes + 1)
var list *FootnoteList
if tlist := pc.Get(footnoteListKey); tlist != nil {
list = tlist.(*FootnoteList)
}
if list == nil {
return nil
}
index := 0
name := []byte{}
for def := list.FirstChild(); def != nil; def = def.NextSibling() {
d := def.(*Footnote)
if bytes.Equal(d.Ref, value) {
if d.Index < 0 {
list.Count++
d.Index = list.Count
val := CleanValue(d.Name)
if len(val) == 0 {
val = []byte(strconv.Itoa(d.Index))
}
d.Name = pc.IDs().Generate(val, KindFootnote)
}
index = d.Index
name = d.Name
break
}
}
if index == 0 {
return nil
}
return NewFootnoteLink(index, name)
}
type footnoteASTTransformer struct {
}
var defaultFootnoteASTTransformer = &footnoteASTTransformer{}
// NewFootnoteASTTransformer returns a new parser.ASTTransformer that
// insert a footnote list to the last of the document.
func NewFootnoteASTTransformer() parser.ASTTransformer {
return defaultFootnoteASTTransformer
}
func (a *footnoteASTTransformer) Transform(node *ast.Document, reader text.Reader, pc parser.Context) {
var list *FootnoteList
if tlist := pc.Get(footnoteListKey); tlist != nil {
list = tlist.(*FootnoteList)
} else {
return
}
pc.Set(footnoteListKey, nil)
for footnote := list.FirstChild(); footnote != nil; {
var container ast.Node = footnote
next := footnote.NextSibling()
if fc := container.LastChild(); fc != nil && ast.IsParagraph(fc) {
container = fc
}
footnoteNode := footnote.(*Footnote)
index := footnoteNode.Index
name := footnoteNode.Name
if index < 0 {
list.RemoveChild(list, footnote)
} else {
container.AppendChild(container, NewFootnoteBackLink(index, name))
}
footnote = next
}
list.SortChildren(func(n1, n2 ast.Node) int {
if n1.(*Footnote).Index < n2.(*Footnote).Index {
return -1
}
return 1
})
if list.Count <= 0 {
list.Parent().RemoveChild(list.Parent(), list)
return
}
node.AppendChild(node, list)
}
// FootnoteHTMLRenderer is a renderer.NodeRenderer implementation that
// renders FootnoteLink nodes.
type FootnoteHTMLRenderer struct {
html.Config
}
// NewFootnoteHTMLRenderer returns a new FootnoteHTMLRenderer.
func NewFootnoteHTMLRenderer(opts ...html.Option) renderer.NodeRenderer {
r := &FootnoteHTMLRenderer{
Config: html.NewConfig(),
}
for _, opt := range opts {
opt.SetHTMLOption(&r.Config)
}
return r
}
// RegisterFuncs implements renderer.NodeRenderer.RegisterFuncs.
func (r *FootnoteHTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
reg.Register(KindFootnoteLink, r.renderFootnoteLink)
reg.Register(KindFootnoteBackLink, r.renderFootnoteBackLink)
reg.Register(KindFootnote, r.renderFootnote)
reg.Register(KindFootnoteList, r.renderFootnoteList)
}
func (r *FootnoteHTMLRenderer) renderFootnoteLink(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
if entering {
n := node.(*FootnoteLink)
n.Dump(source, 0)
is := strconv.Itoa(n.Index)
_, _ = w.WriteString(`<sup id="fnref:`)
_, _ = w.Write(n.Name)
_, _ = w.WriteString(`"><a href="#fn:`)
_, _ = w.Write(n.Name)
_, _ = w.WriteString(`" class="footnote-ref" role="doc-noteref">`)
_, _ = w.WriteString(is)
_, _ = w.WriteString(`</a></sup>`)
}
return ast.WalkContinue, nil
}
func (r *FootnoteHTMLRenderer) renderFootnoteBackLink(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
if entering {
n := node.(*FootnoteBackLink)
fmt.Fprintf(os.Stdout, "source:\n%s\n", string(n.Text(source)))
_, _ = w.WriteString(` <a href="#fnref:`)
_, _ = w.Write(n.Name)
_, _ = w.WriteString(`" class="footnote-backref" role="doc-backlink">`)
_, _ = w.WriteString("&#x21a9;&#xfe0e;")
_, _ = w.WriteString(`</a>`)
}
return ast.WalkContinue, nil
}
func (r *FootnoteHTMLRenderer) renderFootnote(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
n := node.(*Footnote)
if entering {
fmt.Fprintf(os.Stdout, "source:\n%s\n", string(n.Text(source)))
_, _ = w.WriteString(`<li id="fn:`)
_, _ = w.Write(n.Name)
_, _ = w.WriteString(`" role="doc-endnote"`)
if node.Attributes() != nil {
html.RenderAttributes(w, node, html.ListItemAttributeFilter)
}
_, _ = w.WriteString(">\n")
} else {
_, _ = w.WriteString("</li>\n")
}
return ast.WalkContinue, nil
}
func (r *FootnoteHTMLRenderer) renderFootnoteList(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
tag := "div"
if entering {
_, _ = w.WriteString("<")
_, _ = w.WriteString(tag)
_, _ = w.WriteString(` class="footnotes" role="doc-endnotes"`)
if node.Attributes() != nil {
html.RenderAttributes(w, node, html.GlobalAttributeFilter)
}
_ = w.WriteByte('>')
if r.Config.XHTML {
_, _ = w.WriteString("\n<hr />\n")
} else {
_, _ = w.WriteString("\n<hr>\n")
}
_, _ = w.WriteString("<ol>\n")
} else {
_, _ = w.WriteString("</ol>\n")
_, _ = w.WriteString("</")
_, _ = w.WriteString(tag)
_, _ = w.WriteString(">\n")
}
return ast.WalkContinue, nil
}
type footnoteExtension struct{}
// FootnoteExtension represents the Gitea Footnote
var FootnoteExtension = &footnoteExtension{}
// Extend extends the markdown converter with the Gitea Footnote parser
func (e *footnoteExtension) Extend(m goldmark.Markdown) {
m.Parser().AddOptions(
parser.WithBlockParsers(
util.Prioritized(NewFootnoteBlockParser(), 999),
),
parser.WithInlineParsers(
util.Prioritized(NewFootnoteParser(), 101),
),
parser.WithASTTransformers(
util.Prioritized(NewFootnoteASTTransformer(), 999),
),
)
m.Renderer().AddOptions(renderer.WithNodeRenderers(
util.Prioritized(NewFootnoteHTMLRenderer(), 500),
))
}

View file

@ -0,0 +1,19 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package common
import (
"mvdan.cc/xurls/v2"
)
var (
// NOTE: All below regex matching do not perform any extra validation.
// Thus a link is produced even if the linked entity does not exist.
// While fast, this is also incorrect and lead to false positives.
// TODO: fix invalid linking issue
// LinkRegex is a regexp matching a valid link
LinkRegex, _ = xurls.StrictMatchingScheme("https?://")
)

View file

@ -0,0 +1,156 @@
// Copyright 2019 Yusuke Inuzuka
// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
// Most of this file is a subtly changed version of github.com/yuin/goldmark/extension/linkify.go
package common
import (
"bytes"
"regexp"
"github.com/yuin/goldmark"
"github.com/yuin/goldmark/ast"
"github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/text"
"github.com/yuin/goldmark/util"
)
var wwwURLRegxp = regexp.MustCompile(`^www\.[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}((?:/|[#?])[-a-zA-Z0-9@:%_\+.~#!?&//=\(\);,'">\^{}\[\]` + "`" + `]*)?`)
type linkifyParser struct {
}
var defaultLinkifyParser = &linkifyParser{}
// NewLinkifyParser return a new InlineParser can parse
// text that seems like a URL.
func NewLinkifyParser() parser.InlineParser {
return defaultLinkifyParser
}
func (s *linkifyParser) Trigger() []byte {
// ' ' indicates any white spaces and a line head
return []byte{' ', '*', '_', '~', '('}
}
var protoHTTP = []byte("http:")
var protoHTTPS = []byte("https:")
var protoFTP = []byte("ftp:")
var domainWWW = []byte("www.")
func (s *linkifyParser) Parse(parent ast.Node, block text.Reader, pc parser.Context) ast.Node {
if pc.IsInLinkLabel() {
return nil
}
line, segment := block.PeekLine()
consumes := 0
start := segment.Start
c := line[0]
// advance if current position is not a line head.
if c == ' ' || c == '*' || c == '_' || c == '~' || c == '(' {
consumes++
start++
line = line[1:]
}
var m []int
var protocol []byte
var typ ast.AutoLinkType = ast.AutoLinkURL
if bytes.HasPrefix(line, protoHTTP) || bytes.HasPrefix(line, protoHTTPS) || bytes.HasPrefix(line, protoFTP) {
m = LinkRegex.FindSubmatchIndex(line)
}
if m == nil && bytes.HasPrefix(line, domainWWW) {
m = wwwURLRegxp.FindSubmatchIndex(line)
protocol = []byte("http")
}
if m != nil {
lastChar := line[m[1]-1]
if lastChar == '.' {
m[1]--
} else if lastChar == ')' {
closing := 0
for i := m[1] - 1; i >= m[0]; i-- {
if line[i] == ')' {
closing++
} else if line[i] == '(' {
closing--
}
}
if closing > 0 {
m[1] -= closing
}
} else if lastChar == ';' {
i := m[1] - 2
for ; i >= m[0]; i-- {
if util.IsAlphaNumeric(line[i]) {
continue
}
break
}
if i != m[1]-2 {
if line[i] == '&' {
m[1] -= m[1] - i
}
}
}
}
if m == nil {
if len(line) > 0 && util.IsPunct(line[0]) {
return nil
}
typ = ast.AutoLinkEmail
stop := util.FindEmailIndex(line)
if stop < 0 {
return nil
}
at := bytes.IndexByte(line, '@')
m = []int{0, stop, at, stop - 1}
if m == nil || bytes.IndexByte(line[m[2]:m[3]], '.') < 0 {
return nil
}
lastChar := line[m[1]-1]
if lastChar == '.' {
m[1]--
}
if m[1] < len(line) {
nextChar := line[m[1]]
if nextChar == '-' || nextChar == '_' {
return nil
}
}
}
if m == nil {
return nil
}
if consumes != 0 {
s := segment.WithStop(segment.Start + 1)
ast.MergeOrAppendTextSegment(parent, s)
}
consumes += m[1]
block.Advance(consumes)
n := ast.NewTextSegment(text.NewSegment(start, start+m[1]))
link := ast.NewAutoLink(typ, n)
link.Protocol = protocol
return link
}
func (s *linkifyParser) CloseBlock(parent ast.Node, pc parser.Context) {
// nothing to do
}
type linkify struct {
}
// Linkify is an extension that allow you to parse text that seems like a URL.
var Linkify = &linkify{}
func (e *linkify) Extend(m goldmark.Markdown) {
m.Parser().AddOptions(
parser.WithInlineParsers(
util.Prioritized(NewLinkifyParser(), 999),
),
)
}

View file

@ -15,6 +15,7 @@ import (
"code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/markup/common"
"code.gitea.io/gitea/modules/references" "code.gitea.io/gitea/modules/references"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
@ -57,8 +58,6 @@ var (
// https://html.spec.whatwg.org/multipage/input.html#e-mail-state-(type%3Demail) // https://html.spec.whatwg.org/multipage/input.html#e-mail-state-(type%3Demail)
emailRegex = regexp.MustCompile("(?:\\s|^|\\(|\\[)([a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9]{2,}(?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+)(?:\\s|$|\\)|\\]|\\.(\\s|$))") emailRegex = regexp.MustCompile("(?:\\s|^|\\(|\\[)([a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9]{2,}(?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+)(?:\\s|$|\\)|\\]|\\.(\\s|$))")
linkRegex, _ = xurls.StrictMatchingScheme("https?://")
// blackfriday extensions create IDs like fn:user-content-footnote // blackfriday extensions create IDs like fn:user-content-footnote
blackfridayExtRegex = regexp.MustCompile(`[^:]*:user-content-`) blackfridayExtRegex = regexp.MustCompile(`[^:]*:user-content-`)
) )
@ -118,7 +117,7 @@ func CustomLinkURLSchemes(schemes []string) {
} }
withAuth = append(withAuth, s) withAuth = append(withAuth, s)
} }
linkRegex, _ = xurls.StrictMatchingScheme(strings.Join(withAuth, "|")) common.LinkRegex, _ = xurls.StrictMatchingScheme(strings.Join(withAuth, "|"))
} }
// IsSameDomain checks if given url string has the same hostname as current Gitea instance // IsSameDomain checks if given url string has the same hostname as current Gitea instance
@ -509,6 +508,12 @@ func shortLinkProcessorFull(ctx *postProcessCtx, node *html.Node, noLink bool) {
(strings.HasPrefix(val, "") && strings.HasSuffix(val, "")) { (strings.HasPrefix(val, "") && strings.HasSuffix(val, "")) {
const lenQuote = len("") const lenQuote = len("")
val = val[lenQuote : len(val)-lenQuote] val = val[lenQuote : len(val)-lenQuote]
} else if (strings.HasPrefix(val, "\"") && strings.HasSuffix(val, "\"")) ||
(strings.HasPrefix(val, "'") && strings.HasSuffix(val, "'")) {
val = val[1 : len(val)-1]
} else if strings.HasPrefix(val, "'") && strings.HasSuffix(val, "") {
const lenQuote = len("")
val = val[1 : len(val)-lenQuote]
} }
props[key] = val props[key] = val
} }
@ -803,7 +808,7 @@ func emailAddressProcessor(ctx *postProcessCtx, node *html.Node) {
// linkProcessor creates links for any HTTP or HTTPS URL not captured by // linkProcessor creates links for any HTTP or HTTPS URL not captured by
// markdown. // markdown.
func linkProcessor(ctx *postProcessCtx, node *html.Node) { func linkProcessor(ctx *postProcessCtx, node *html.Node) {
m := linkRegex.FindStringIndex(node.Data) m := common.LinkRegex.FindStringIndex(node.Data)
if m == nil { if m == nil {
return return
} }
@ -832,7 +837,7 @@ func genDefaultLinkProcessor(defaultLink string) processor {
// descriptionLinkProcessor creates links for DescriptionHTML // descriptionLinkProcessor creates links for DescriptionHTML
func descriptionLinkProcessor(ctx *postProcessCtx, node *html.Node) { func descriptionLinkProcessor(ctx *postProcessCtx, node *html.Node) {
m := linkRegex.FindStringIndex(node.Data) m := common.LinkRegex.FindStringIndex(node.Data)
if m == nil { if m == nil {
return return
} }

View file

@ -323,6 +323,6 @@ func TestRender_ShortLinks(t *testing.T) {
`<p><a href="`+notencodedImgurlWiki+`" rel="nofollow"><img src="`+notencodedImgurlWiki+`"/></a></p>`) `<p><a href="`+notencodedImgurlWiki+`" rel="nofollow"><img src="`+notencodedImgurlWiki+`"/></a></p>`)
test( test(
"<p><a href=\"https://example.org\">[[foobar]]</a></p>", "<p><a href=\"https://example.org\">[[foobar]]</a></p>",
`<p></p><p><a href="https://example.org" rel="nofollow">[[foobar]]</a></p><p></p>`, `<p><a href="https://example.org" rel="nofollow">[[foobar]]</a></p>`,
`<p></p><p><a href="https://example.org" rel="nofollow">[[foobar]]</a></p><p></p>`) `<p><a href="https://example.org" rel="nofollow">[[foobar]]</a></p>`)
} }

View file

@ -0,0 +1,178 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package markdown
import (
"bytes"
"fmt"
"strings"
"code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/markup/common"
giteautil "code.gitea.io/gitea/modules/util"
"github.com/yuin/goldmark/ast"
east "github.com/yuin/goldmark/extension/ast"
"github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/renderer"
"github.com/yuin/goldmark/renderer/html"
"github.com/yuin/goldmark/text"
"github.com/yuin/goldmark/util"
)
var byteMailto = []byte("mailto:")
// GiteaASTTransformer is a default transformer of the goldmark tree.
type GiteaASTTransformer struct{}
// Transform transforms the given AST tree.
func (g *GiteaASTTransformer) Transform(node *ast.Document, reader text.Reader, pc parser.Context) {
_ = ast.Walk(node, func(n ast.Node, entering bool) (ast.WalkStatus, error) {
if !entering {
return ast.WalkContinue, nil
}
switch v := n.(type) {
case *ast.Image:
// Images need two things:
//
// 1. Their src needs to munged to be a real value
// 2. If they're not wrapped with a link they need a link wrapper
// Check if the destination is a real link
link := v.Destination
if len(link) > 0 && !markup.IsLink(link) {
prefix := pc.Get(urlPrefixKey).(string)
if pc.Get(isWikiKey).(bool) {
prefix = giteautil.URLJoin(prefix, "wiki", "raw")
}
prefix = strings.Replace(prefix, "/src/", "/media/", 1)
lnk := string(link)
lnk = giteautil.URLJoin(prefix, lnk)
lnk = strings.Replace(lnk, " ", "+", -1)
link = []byte(lnk)
}
v.Destination = link
parent := n.Parent()
// Create a link around image only if parent is not already a link
if _, ok := parent.(*ast.Link); !ok && parent != nil {
wrap := ast.NewLink()
wrap.Destination = link
wrap.Title = v.Title
parent.ReplaceChild(parent, n, wrap)
wrap.AppendChild(wrap, n)
}
case *ast.Link:
// Links need their href to munged to be a real value
link := v.Destination
if len(link) > 0 && !markup.IsLink(link) &&
link[0] != '#' && !bytes.HasPrefix(link, byteMailto) {
// special case: this is not a link, a hash link or a mailto:, so it's a
// relative URL
lnk := string(link)
if pc.Get(isWikiKey).(bool) {
lnk = giteautil.URLJoin("wiki", lnk)
}
link = []byte(giteautil.URLJoin(pc.Get(urlPrefixKey).(string), lnk))
}
v.Destination = link
}
return ast.WalkContinue, nil
})
}
type prefixedIDs struct {
values map[string]bool
}
// Generate generates a new element id.
func (p *prefixedIDs) Generate(value []byte, kind ast.NodeKind) []byte {
dft := []byte("id")
if kind == ast.KindHeading {
dft = []byte("heading")
}
return p.GenerateWithDefault(value, dft)
}
// Generate generates a new element id.
func (p *prefixedIDs) GenerateWithDefault(value []byte, dft []byte) []byte {
result := common.CleanValue(value)
if len(result) == 0 {
result = dft
}
if !bytes.HasPrefix(result, []byte("user-content-")) {
result = append([]byte("user-content-"), result...)
}
if _, ok := p.values[util.BytesToReadOnlyString(result)]; !ok {
p.values[util.BytesToReadOnlyString(result)] = true
return result
}
for i := 1; ; i++ {
newResult := fmt.Sprintf("%s-%d", result, i)
if _, ok := p.values[newResult]; !ok {
p.values[newResult] = true
return []byte(newResult)
}
}
}
// Put puts a given element id to the used ids table.
func (p *prefixedIDs) Put(value []byte) {
p.values[util.BytesToReadOnlyString(value)] = true
}
func newPrefixedIDs() *prefixedIDs {
return &prefixedIDs{
values: map[string]bool{},
}
}
// NewTaskCheckBoxHTMLRenderer creates a TaskCheckBoxHTMLRenderer to render tasklists
// in the gitea form.
func NewTaskCheckBoxHTMLRenderer(opts ...html.Option) renderer.NodeRenderer {
r := &TaskCheckBoxHTMLRenderer{
Config: html.NewConfig(),
}
for _, opt := range opts {
opt.SetHTMLOption(&r.Config)
}
return r
}
// TaskCheckBoxHTMLRenderer is a renderer.NodeRenderer implementation that
// renders checkboxes in list items.
// Overrides the default goldmark one to present the gitea format
type TaskCheckBoxHTMLRenderer struct {
html.Config
}
// RegisterFuncs implements renderer.NodeRenderer.RegisterFuncs.
func (r *TaskCheckBoxHTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
reg.Register(east.KindTaskCheckBox, r.renderTaskCheckBox)
}
func (r *TaskCheckBoxHTMLRenderer) renderTaskCheckBox(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
if !entering {
return ast.WalkContinue, nil
}
n := node.(*east.TaskCheckBox)
end := ">"
if r.XHTML {
end = " />"
}
var err error
if n.IsChecked {
_, err = w.WriteString(`<span class="ui fitted disabled checkbox"><input type="checkbox" disabled="disabled"` + end + `<label` + end + `</span>`)
} else {
_, err = w.WriteString(`<span class="ui checked fitted disabled checkbox"><input type="checkbox" checked="" disabled="disabled"` + end + `<label` + end + `</span>`)
}
if err != nil {
return ast.WalkStop, err
}
return ast.WalkContinue, nil
}

View file

@ -7,161 +7,83 @@ package markdown
import ( import (
"bytes" "bytes"
"io" "sync"
"strings"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/markup/common"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util" giteautil "code.gitea.io/gitea/modules/util"
"github.com/russross/blackfriday/v2" "github.com/yuin/goldmark"
"github.com/yuin/goldmark/extension"
"github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/renderer"
"github.com/yuin/goldmark/renderer/html"
"github.com/yuin/goldmark/util"
) )
// Renderer is a extended version of underlying render object. var converter goldmark.Markdown
type Renderer struct { var once = sync.Once{}
blackfriday.Renderer
URLPrefix string var urlPrefixKey = parser.NewContextKey()
IsWiki bool var isWikiKey = parser.NewContextKey()
// NewGiteaParseContext creates a parser.Context with the gitea context set
func NewGiteaParseContext(urlPrefix string, isWiki bool) parser.Context {
pc := parser.NewContext(parser.WithIDs(newPrefixedIDs()))
pc.Set(urlPrefixKey, urlPrefix)
pc.Set(isWikiKey, isWiki)
return pc
} }
var byteMailto = []byte("mailto:")
var htmlEscaper = [256][]byte{
'&': []byte("&amp;"),
'<': []byte("&lt;"),
'>': []byte("&gt;"),
'"': []byte("&quot;"),
}
func escapeHTML(w io.Writer, s []byte) {
var start, end int
for end < len(s) {
escSeq := htmlEscaper[s[end]]
if escSeq != nil {
_, _ = w.Write(s[start:end])
_, _ = w.Write(escSeq)
start = end + 1
}
end++
}
if start < len(s) && end <= len(s) {
_, _ = w.Write(s[start:end])
}
}
// RenderNode is a default renderer of a single node of a syntax tree. For
// block nodes it will be called twice: first time with entering=true, second
// time with entering=false, so that it could know when it's working on an open
// tag and when on close. It writes the result to w.
//
// The return value is a way to tell the calling walker to adjust its walk
// pattern: e.g. it can terminate the traversal by returning Terminate. Or it
// can ask the walker to skip a subtree of this node by returning SkipChildren.
// The typical behavior is to return GoToNext, which asks for the usual
// traversal to the next node.
func (r *Renderer) RenderNode(w io.Writer, node *blackfriday.Node, entering bool) blackfriday.WalkStatus {
switch node.Type {
case blackfriday.Image:
prefix := r.URLPrefix
if r.IsWiki {
prefix = util.URLJoin(prefix, "wiki", "raw")
}
prefix = strings.Replace(prefix, "/src/", "/media/", 1)
link := node.LinkData.Destination
if len(link) > 0 && !markup.IsLink(link) {
lnk := string(link)
lnk = util.URLJoin(prefix, lnk)
lnk = strings.Replace(lnk, " ", "+", -1)
link = []byte(lnk)
}
node.LinkData.Destination = link
// Render link around image only if parent is not link already
if node.Parent != nil && node.Parent.Type != blackfriday.Link {
if entering {
_, _ = w.Write([]byte(`<a href="`))
escapeHTML(w, link)
_, _ = w.Write([]byte(`">`))
return r.Renderer.RenderNode(w, node, entering)
}
s := r.Renderer.RenderNode(w, node, entering)
_, _ = w.Write([]byte(`</a>`))
return s
}
return r.Renderer.RenderNode(w, node, entering)
case blackfriday.Link:
// special case: this is not a link, a hash link or a mailto:, so it's a
// relative URL
link := node.LinkData.Destination
if len(link) > 0 && !markup.IsLink(link) &&
link[0] != '#' && !bytes.HasPrefix(link, byteMailto) &&
node.LinkData.Footnote == nil {
lnk := string(link)
if r.IsWiki {
lnk = util.URLJoin("wiki", lnk)
}
link = []byte(util.URLJoin(r.URLPrefix, lnk))
}
node.LinkData.Destination = link
return r.Renderer.RenderNode(w, node, entering)
case blackfriday.Text:
isListItem := false
for n := node.Parent; n != nil; n = n.Parent {
if n.Type == blackfriday.Item {
isListItem = true
break
}
}
if isListItem {
text := node.Literal
switch {
case bytes.HasPrefix(text, []byte("[ ] ")):
_, _ = w.Write([]byte(`<span class="ui fitted disabled checkbox"><input type="checkbox" disabled="disabled" /><label /></span>`))
text = text[3:]
case bytes.HasPrefix(text, []byte("[x] ")):
_, _ = w.Write([]byte(`<span class="ui checked fitted disabled checkbox"><input type="checkbox" checked="" disabled="disabled" /><label /></span>`))
text = text[3:]
}
node.Literal = text
}
}
return r.Renderer.RenderNode(w, node, entering)
}
const (
blackfridayExtensions = 0 |
blackfriday.NoIntraEmphasis |
blackfriday.Tables |
blackfriday.FencedCode |
blackfriday.Strikethrough |
blackfriday.NoEmptyLineBeforeBlock |
blackfriday.DefinitionLists |
blackfriday.Footnotes |
blackfriday.HeadingIDs |
blackfriday.AutoHeadingIDs
blackfridayHTMLFlags = 0 |
blackfriday.Smartypants
)
// RenderRaw renders Markdown to HTML without handling special links. // RenderRaw renders Markdown to HTML without handling special links.
func RenderRaw(body []byte, urlPrefix string, wikiMarkdown bool) []byte { func RenderRaw(body []byte, urlPrefix string, wikiMarkdown bool) []byte {
renderer := &Renderer{ once.Do(func() {
Renderer: blackfriday.NewHTMLRenderer(blackfriday.HTMLRendererParameters{ converter = goldmark.New(
Flags: blackfridayHTMLFlags, goldmark.WithExtensions(extension.Table,
FootnoteAnchorPrefix: "user-content-", extension.Strikethrough,
HeadingIDPrefix: "user-content-", extension.TaskList,
}), extension.DefinitionList,
URLPrefix: urlPrefix, common.FootnoteExtension,
IsWiki: wikiMarkdown, extension.NewTypographer(
extension.WithTypographicSubstitutions(extension.TypographicSubstitutions{
extension.EnDash: nil,
extension.EmDash: nil,
}),
),
),
goldmark.WithParserOptions(
parser.WithAttribute(),
parser.WithAutoHeadingID(),
parser.WithASTTransformers(
util.Prioritized(&GiteaASTTransformer{}, 10000),
),
),
goldmark.WithRendererOptions(
html.WithUnsafe(),
),
)
// Override the original Tasklist renderer!
converter.Renderer().AddOptions(
renderer.WithNodeRenderers(
util.Prioritized(NewTaskCheckBoxHTMLRenderer(), 1000),
),
)
if setting.Markdown.EnableHardLineBreak {
converter.Renderer().AddOptions(html.WithHardWraps())
}
})
pc := NewGiteaParseContext(urlPrefix, wikiMarkdown)
var buf bytes.Buffer
if err := converter.Convert(giteautil.NormalizeEOL(body), &buf, parser.WithContext(pc)); err != nil {
log.Error("Unable to render: %v", err)
} }
exts := blackfridayExtensions return markup.SanitizeReader(&buf).Bytes()
if setting.Markdown.EnableHardLineBreak {
exts |= blackfriday.HardLineBreak
}
// Need to normalize EOL to UNIX LF to have consistent results in rendering
body = blackfriday.Run(util.NormalizeEOL(body), blackfriday.WithRenderer(renderer), blackfriday.WithExtensions(exts))
return markup.SanitizeBytes(body)
} }
var ( var (
@ -174,8 +96,7 @@ func init() {
} }
// Parser implements markup.Parser // Parser implements markup.Parser
type Parser struct { type Parser struct{}
}
// Name implements markup.Parser // Name implements markup.Parser
func (Parser) Name() string { func (Parser) Name() string {

View file

@ -98,16 +98,12 @@ func TestRender_Images(t *testing.T) {
func testAnswers(baseURLContent, baseURLImages string) []string { func testAnswers(baseURLContent, baseURLImages string) []string {
return []string{ return []string{
`<p>Wiki! Enjoy :)</p> `<p>Wiki! Enjoy :)</p>
<ul> <ul>
<li><a href="` + baseURLContent + `/Links" rel="nofollow">Links, Language bindings, Engine bindings</a></li> <li><a href="` + baseURLContent + `/Links" rel="nofollow">Links, Language bindings, Engine bindings</a></li>
<li><a href="` + baseURLContent + `/Tips" rel="nofollow">Tips</a></li> <li><a href="` + baseURLContent + `/Tips" rel="nofollow">Tips</a></li>
</ul> </ul>
<p>See commit <a href="http://localhost:3000/gogits/gogs/commit/65f1bf27bc" rel="nofollow"><code>65f1bf27bc</code></a></p> <p>See commit <a href="http://localhost:3000/gogits/gogs/commit/65f1bf27bc" rel="nofollow"><code>65f1bf27bc</code></a></p>
<p>Ideas and codes</p> <p>Ideas and codes</p>
<ul> <ul>
<li>Bezier widget (by <a href="` + AppURL + `r-lyeh" rel="nofollow">@r-lyeh</a>) <a href="http://localhost:3000/ocornut/imgui/issues/786" rel="nofollow">ocornut/imgui#786</a></li> <li>Bezier widget (by <a href="` + AppURL + `r-lyeh" rel="nofollow">@r-lyeh</a>) <a href="http://localhost:3000/ocornut/imgui/issues/786" rel="nofollow">ocornut/imgui#786</a></li>
<li>Bezier widget (by <a href="` + AppURL + `r-lyeh" rel="nofollow">@r-lyeh</a>) <a href="http://localhost:3000/gogits/gogs/issues/786" rel="nofollow">#786</a></li> <li>Bezier widget (by <a href="` + AppURL + `r-lyeh" rel="nofollow">@r-lyeh</a>) <a href="http://localhost:3000/gogits/gogs/issues/786" rel="nofollow">#786</a></li>
@ -117,13 +113,9 @@ func testAnswers(baseURLContent, baseURLImages string) []string {
</ul> </ul>
`, `,
`<h2 id="user-content-what-is-wine-staging">What is Wine Staging?</h2> `<h2 id="user-content-what-is-wine-staging">What is Wine Staging?</h2>
<p><strong>Wine Staging</strong> on website <a href="http://wine-staging.com" rel="nofollow">wine-staging.com</a>.</p> <p><strong>Wine Staging</strong> on website <a href="http://wine-staging.com" rel="nofollow">wine-staging.com</a>.</p>
<h2 id="user-content-quick-links">Quick Links</h2> <h2 id="user-content-quick-links">Quick Links</h2>
<p>Here are some links to the most important topics. You can find the full list of pages at the sidebar.</p> <p>Here are some links to the most important topics. You can find the full list of pages at the sidebar.</p>
<table> <table>
<thead> <thead>
<tr> <tr>
@ -131,7 +123,6 @@ func testAnswers(baseURLContent, baseURLImages string) []string {
<th><a href="` + baseURLContent + `/Installation" rel="nofollow">Installation</a></th> <th><a href="` + baseURLContent + `/Installation" rel="nofollow">Installation</a></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
<td><a href="` + baseURLImages + `/images/icon-usage.png" rel="nofollow"><img src="` + baseURLImages + `/images/icon-usage.png" title="icon-usage.png" alt="images/icon-usage.png"/></a></td> <td><a href="` + baseURLImages + `/images/icon-usage.png" rel="nofollow"><img src="` + baseURLImages + `/images/icon-usage.png" title="icon-usage.png" alt="images/icon-usage.png"/></a></td>
@ -141,20 +132,15 @@ func testAnswers(baseURLContent, baseURLImages string) []string {
</table> </table>
`, `,
`<p><a href="http://www.excelsiorjet.com/" rel="nofollow">Excelsior JET</a> allows you to create native executables for Windows, Linux and Mac OS X.</p> `<p><a href="http://www.excelsiorjet.com/" rel="nofollow">Excelsior JET</a> allows you to create native executables for Windows, Linux and Mac OS X.</p>
<ol> <ol>
<li><a href="https://github.com/libgdx/libgdx/wiki/Gradle-on-the-Commandline#packaging-for-the-desktop" rel="nofollow">Package your libGDX application</a> <li><a href="https://github.com/libgdx/libgdx/wiki/Gradle-on-the-Commandline#packaging-for-the-desktop" rel="nofollow">Package your libGDX application</a>
<a href="` + baseURLImages + `/images/1.png" rel="nofollow"><img src="` + baseURLImages + `/images/1.png" title="1.png" alt="images/1.png"/></a></li> <a href="` + baseURLImages + `/images/1.png" rel="nofollow"><img src="` + baseURLImages + `/images/1.png" title="1.png" alt="images/1.png"/></a></li>
<li>Perform a test run by hitting the Run! button. <li>Perform a test run by hitting the Run! button.
<a href="` + baseURLImages + `/images/2.png" rel="nofollow"><img src="` + baseURLImages + `/images/2.png" title="2.png" alt="images/2.png"/></a></li> <a href="` + baseURLImages + `/images/2.png" rel="nofollow"><img src="` + baseURLImages + `/images/2.png" title="2.png" alt="images/2.png"/></a></li>
</ol> </ol>
<h2 id="user-content-custom-id">More tests</h2> <h2 id="user-content-custom-id">More tests</h2>
<p>(from <a href="https://www.markdownguide.org/extended-syntax/" rel="nofollow">https://www.markdownguide.org/extended-syntax/</a>)</p> <p>(from <a href="https://www.markdownguide.org/extended-syntax/" rel="nofollow">https://www.markdownguide.org/extended-syntax/</a>)</p>
<h3 id="user-content-definition-list">Definition list</h3> <h3 id="user-content-definition-list">Definition list</h3>
<dl> <dl>
<dt>First Term</dt> <dt>First Term</dt>
<dd>This is the definition of the first term.</dd> <dd>This is the definition of the first term.</dd>
@ -162,27 +148,21 @@ func testAnswers(baseURLContent, baseURLImages string) []string {
<dd>This is one definition of the second term.</dd> <dd>This is one definition of the second term.</dd>
<dd>This is another definition of the second term.</dd> <dd>This is another definition of the second term.</dd>
</dl> </dl>
<h3 id="user-content-footnotes">Footnotes</h3> <h3 id="user-content-footnotes">Footnotes</h3>
<p>Here is a simple footnote,<sup id="fnref:user-content-1"><a href="#fn:user-content-1" rel="nofollow">1</a></sup> and here is a longer one.<sup id="fnref:user-content-bignote"><a href="#fn:user-content-bignote" rel="nofollow">2</a></sup></p> <p>Here is a simple footnote,<sup id="fnref:user-content-1"><a href="#fn:user-content-1" rel="nofollow">1</a></sup> and here is a longer one.<sup id="fnref:user-content-bignote"><a href="#fn:user-content-bignote" rel="nofollow">2</a></sup></p>
<div> <div>
<hr/> <hr/>
<ol> <ol>
<li id="fn:user-content-1">This is the first footnote.</li> <li id="fn:user-content-1">
<p>This is the first footnote. <a href="#fnref:user-content-1" rel="nofollow"></a></p>
<li id="fn:user-content-bignote"><p>Here is one with multiple paragraphs and code.</p> </li>
<li id="fn:user-content-bignote">
<p>Here is one with multiple paragraphs and code.</p>
<p>Indent paragraphs to include them in the footnote.</p> <p>Indent paragraphs to include them in the footnote.</p>
<p><code>{ my code }</code></p> <p><code>{ my code }</code></p>
<p>Add as many paragraphs as you like. <a href="#fnref:user-content-bignote" rel="nofollow"></a></p>
<p>Add as many paragraphs as you like.</p></li> </li>
</ol> </ol>
</div> </div>
`, `,
} }
@ -299,15 +279,15 @@ func TestRender_RenderParagraphs(t *testing.T) {
test := func(t *testing.T, str string, cnt int) { test := func(t *testing.T, str string, cnt int) {
unix := []byte(str) unix := []byte(str)
res := string(RenderRaw(unix, "", false)) res := string(RenderRaw(unix, "", false))
assert.Equal(t, strings.Count(res, "<p"), cnt) assert.Equal(t, strings.Count(res, "<p"), cnt, "Rendered result for unix should have %d paragraph(s) but has %d:\n%s\n", cnt, strings.Count(res, "<p"), res)
mac := []byte(strings.ReplaceAll(str, "\n", "\r")) mac := []byte(strings.ReplaceAll(str, "\n", "\r"))
res = string(RenderRaw(mac, "", false)) res = string(RenderRaw(mac, "", false))
assert.Equal(t, strings.Count(res, "<p"), cnt) assert.Equal(t, strings.Count(res, "<p"), cnt, "Rendered result for mac should have %d paragraph(s) but has %d:\n%s\n", cnt, strings.Count(res, "<p"), res)
dos := []byte(strings.ReplaceAll(str, "\n", "\r\n")) dos := []byte(strings.ReplaceAll(str, "\n", "\r\n"))
res = string(RenderRaw(dos, "", false)) res = string(RenderRaw(dos, "", false))
assert.Equal(t, strings.Count(res, "<p"), cnt) assert.Equal(t, strings.Count(res, "<p"), cnt, "Rendered result for windows should have %d paragraph(s) but has %d:\n%s\n", cnt, strings.Count(res, "<p"), res)
} }
test(t, "\nOne\nTwo\nThree", 1) test(t, "\nOne\nTwo\nThree", 1)

View file

@ -6,33 +6,86 @@ package mdstripper
import ( import (
"bytes" "bytes"
"sync"
"io" "io"
"github.com/russross/blackfriday/v2" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/markup/common"
"github.com/yuin/goldmark"
"github.com/yuin/goldmark/ast"
"github.com/yuin/goldmark/extension"
"github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/renderer"
"github.com/yuin/goldmark/renderer/html"
"github.com/yuin/goldmark/text"
) )
// MarkdownStripper extends blackfriday.Renderer type stripRenderer struct {
type MarkdownStripper struct { links []string
links []string empty bool
coallesce bool
empty bool
} }
const ( func (r *stripRenderer) Render(w io.Writer, source []byte, doc ast.Node) error {
blackfridayExtensions = 0 | return ast.Walk(doc, func(n ast.Node, entering bool) (ast.WalkStatus, error) {
blackfriday.NoIntraEmphasis | if !entering {
blackfriday.Tables | return ast.WalkContinue, nil
blackfriday.FencedCode | }
blackfriday.Strikethrough | switch v := n.(type) {
blackfriday.NoEmptyLineBeforeBlock | case *ast.Text:
blackfriday.DefinitionLists | if !v.IsRaw() {
blackfriday.Footnotes | _, prevSibIsText := n.PreviousSibling().(*ast.Text)
blackfriday.HeadingIDs | coalesce := prevSibIsText
blackfriday.AutoHeadingIDs | r.processString(
// Not included in modules/markup/markdown/markdown.go; w,
// required here to process inline links v.Text(source),
blackfriday.Autolink coalesce)
) if v.SoftLineBreak() {
r.doubleSpace(w)
}
}
return ast.WalkContinue, nil
case *ast.Link:
r.processLink(w, v.Destination)
return ast.WalkSkipChildren, nil
case *ast.AutoLink:
r.processLink(w, v.URL(source))
return ast.WalkSkipChildren, nil
}
return ast.WalkContinue, nil
})
}
func (r *stripRenderer) doubleSpace(w io.Writer) {
if !r.empty {
_, _ = w.Write([]byte{'\n'})
}
}
func (r *stripRenderer) processString(w io.Writer, text []byte, coalesce bool) {
// Always break-up words
if !coalesce {
r.doubleSpace(w)
}
_, _ = w.Write(text)
r.empty = false
}
func (r *stripRenderer) processLink(w io.Writer, link []byte) {
// Links are processed out of band
r.links = append(r.links, string(link))
}
// GetLinks returns the list of link data collected while parsing
func (r *stripRenderer) GetLinks() []string {
return r.links
}
// AddOptions adds given option to this renderer.
func (r *stripRenderer) AddOptions(...renderer.Option) {
// no-op
}
// StripMarkdown parses markdown content by removing all markup and code blocks // StripMarkdown parses markdown content by removing all markup and code blocks
// in order to extract links and other references // in order to extract links and other references
@ -41,78 +94,40 @@ func StripMarkdown(rawBytes []byte) (string, []string) {
return string(buf), links return string(buf), links
} }
var stripParser parser.Parser
var once = sync.Once{}
// StripMarkdownBytes parses markdown content by removing all markup and code blocks // StripMarkdownBytes parses markdown content by removing all markup and code blocks
// in order to extract links and other references // in order to extract links and other references
func StripMarkdownBytes(rawBytes []byte) ([]byte, []string) { func StripMarkdownBytes(rawBytes []byte) ([]byte, []string) {
stripper := &MarkdownStripper{ once.Do(func() {
gdMarkdown := goldmark.New(
goldmark.WithExtensions(extension.Table,
extension.Strikethrough,
extension.TaskList,
extension.DefinitionList,
common.FootnoteExtension,
common.Linkify,
),
goldmark.WithParserOptions(
parser.WithAttribute(),
parser.WithAutoHeadingID(),
),
goldmark.WithRendererOptions(
html.WithUnsafe(),
),
)
stripParser = gdMarkdown.Parser()
})
stripper := &stripRenderer{
links: make([]string, 0, 10), links: make([]string, 0, 10),
empty: true, empty: true,
} }
reader := text.NewReader(rawBytes)
parser := blackfriday.New(blackfriday.WithRenderer(stripper), blackfriday.WithExtensions(blackfridayExtensions)) doc := stripParser.Parse(reader)
ast := parser.Parse(rawBytes)
var buf bytes.Buffer var buf bytes.Buffer
stripper.RenderHeader(&buf, ast) if err := stripper.Render(&buf, rawBytes, doc); err != nil {
ast.Walk(func(node *blackfriday.Node, entering bool) blackfriday.WalkStatus { log.Error("Unable to strip: %v", err)
return stripper.RenderNode(&buf, node, entering) }
})
stripper.RenderFooter(&buf, ast)
return buf.Bytes(), stripper.GetLinks() return buf.Bytes(), stripper.GetLinks()
} }
// RenderNode is the main rendering method. It will be called once for
// every leaf node and twice for every non-leaf node (first with
// entering=true, then with entering=false). The method should write its
// rendition of the node to the supplied writer w.
func (r *MarkdownStripper) RenderNode(w io.Writer, node *blackfriday.Node, entering bool) blackfriday.WalkStatus {
if !entering {
return blackfriday.GoToNext
}
switch node.Type {
case blackfriday.Text:
r.processString(w, node.Literal, node.Parent == nil)
return blackfriday.GoToNext
case blackfriday.Link:
r.processLink(w, node.LinkData.Destination)
r.coallesce = false
return blackfriday.SkipChildren
}
r.coallesce = false
return blackfriday.GoToNext
}
// RenderHeader is a method that allows the renderer to produce some
// content preceding the main body of the output document.
func (r *MarkdownStripper) RenderHeader(w io.Writer, ast *blackfriday.Node) {
}
// RenderFooter is a symmetric counterpart of RenderHeader.
func (r *MarkdownStripper) RenderFooter(w io.Writer, ast *blackfriday.Node) {
}
func (r *MarkdownStripper) doubleSpace(w io.Writer) {
if !r.empty {
_, _ = w.Write([]byte{'\n'})
}
}
func (r *MarkdownStripper) processString(w io.Writer, text []byte, coallesce bool) {
// Always break-up words
if !coallesce || !r.coallesce {
r.doubleSpace(w)
}
_, _ = w.Write(text)
r.coallesce = coallesce
r.empty = false
}
func (r *MarkdownStripper) processLink(w io.Writer, link []byte) {
// Links are processed out of band
r.links = append(r.links, string(link))
r.coallesce = false
}
// GetLinks returns the list of link data collected while parsing
func (r *MarkdownStripper) GetLinks() []string {
return r.links
}

View file

@ -53,6 +53,20 @@ A HIDDEN ` + "`" + `GHOST` + "`" + ` IN THIS LINE.
[]string{ []string{
"link", "link",
}}, }},
{
"Simply closes: #29 yes",
[]string{
"Simply closes: #29 yes",
},
[]string{},
},
{
"Simply closes: !29 yes",
[]string{
"Simply closes: !29 yes",
},
[]string{},
},
} }
for _, test := range list { for _, test := range list {

View file

@ -6,6 +6,8 @@
package markup package markup
import ( import (
"bytes"
"io"
"regexp" "regexp"
"sync" "sync"
@ -67,6 +69,12 @@ func Sanitize(s string) string {
return sanitizer.policy.Sanitize(s) return sanitizer.policy.Sanitize(s)
} }
// SanitizeReader sanitizes a Reader
func SanitizeReader(r io.Reader) *bytes.Buffer {
NewSanitizer()
return sanitizer.policy.SanitizeReader(r)
}
// SanitizeBytes takes a []byte slice that contains a HTML fragment or document and applies policy whitelist. // SanitizeBytes takes a []byte slice that contains a HTML fragment or document and applies policy whitelist.
func SanitizeBytes(b []byte) []byte { func SanitizeBytes(b []byte) []byte {
if len(b) == 0 { if len(b) == 0 {

View file

@ -53,6 +53,7 @@ func (m *mailNotifier) NotifyNewIssue(issue *models.Issue) {
func (m *mailNotifier) NotifyIssueChangeStatus(doer *models.User, issue *models.Issue, actionComment *models.Comment, isClosed bool) { func (m *mailNotifier) NotifyIssueChangeStatus(doer *models.User, issue *models.Issue, actionComment *models.Comment, isClosed bool) {
var actionType models.ActionType var actionType models.ActionType
issue.Content = ""
if issue.IsPull { if issue.IsPull {
if isClosed { if isClosed {
actionType = models.ActionClosePullRequest actionType = models.ActionClosePullRequest
@ -105,7 +106,7 @@ func (m *mailNotifier) NotifyMergePullRequest(pr *models.PullRequest, doer *mode
log.Error("pr.LoadIssue: %v", err) log.Error("pr.LoadIssue: %v", err)
return return
} }
pr.Issue.Content = ""
if err := mailer.MailParticipants(pr.Issue, doer, models.ActionMergePullRequest); err != nil { if err := mailer.MailParticipants(pr.Issue, doer, models.ActionMergePullRequest); err != nil {
log.Error("MailParticipants: %v", err) log.Error("MailParticipants: %v", err)
} }

View file

@ -43,10 +43,6 @@ func TestFindAllIssueReferences(t *testing.T) {
{29, "", "", "29", true, XRefActionCloses, &RefSpan{Start: 15, End: 18}, &RefSpan{Start: 7, End: 13}}, {29, "", "", "29", true, XRefActionCloses, &RefSpan{Start: 15, End: 18}, &RefSpan{Start: 7, End: 13}},
}, },
}, },
{
"#123 no, this is a title.",
[]testResult{},
},
{ {
" #124 yes, this is a reference.", " #124 yes, this is a reference.",
[]testResult{ []testResult{

View file

@ -60,9 +60,14 @@ var (
// Pull request settings // Pull request settings
PullRequest struct { PullRequest struct {
WorkInProgressPrefixes []string WorkInProgressPrefixes []string
CloseKeywords []string CloseKeywords []string
ReopenKeywords []string ReopenKeywords []string
DefaultMergeMessageCommitsLimit int
DefaultMergeMessageSize int
DefaultMergeMessageAllAuthors bool
DefaultMergeMessageMaxApprovers int
DefaultMergeMessageOfficialApproversOnly bool
} `ini:"repository.pull-request"` } `ini:"repository.pull-request"`
// Issue Setting // Issue Setting
@ -127,15 +132,25 @@ var (
// Pull request settings // Pull request settings
PullRequest: struct { PullRequest: struct {
WorkInProgressPrefixes []string WorkInProgressPrefixes []string
CloseKeywords []string CloseKeywords []string
ReopenKeywords []string ReopenKeywords []string
DefaultMergeMessageCommitsLimit int
DefaultMergeMessageSize int
DefaultMergeMessageAllAuthors bool
DefaultMergeMessageMaxApprovers int
DefaultMergeMessageOfficialApproversOnly bool
}{ }{
WorkInProgressPrefixes: []string{"WIP:", "[WIP]"}, WorkInProgressPrefixes: []string{"WIP:", "[WIP]"},
// Same as GitHub. See // Same as GitHub. See
// https://help.github.com/articles/closing-issues-via-commit-messages // https://help.github.com/articles/closing-issues-via-commit-messages
CloseKeywords: strings.Split("close,closes,closed,fix,fixes,fixed,resolve,resolves,resolved", ","), CloseKeywords: strings.Split("close,closes,closed,fix,fixes,fixed,resolve,resolves,resolved", ","),
ReopenKeywords: strings.Split("reopen,reopens,reopened", ","), ReopenKeywords: strings.Split("reopen,reopens,reopened", ","),
DefaultMergeMessageCommitsLimit: 50,
DefaultMergeMessageSize: 5 * 1024,
DefaultMergeMessageAllAuthors: false,
DefaultMergeMessageMaxApprovers: 10,
DefaultMergeMessageOfficialApproversOnly: true,
}, },
// Issue settings // Issue settings

View file

@ -34,15 +34,19 @@ type Hook struct {
// HookList represents a list of API hook. // HookList represents a list of API hook.
type HookList []*Hook type HookList []*Hook
// CreateHookOptionConfig has all config options in it
// required are "content_type" and "url" Required
type CreateHookOptionConfig map[string]string
// CreateHookOption options when create a hook // CreateHookOption options when create a hook
type CreateHookOption struct { type CreateHookOption struct {
// required: true // required: true
// enum: gitea,gogs,slack,discord // enum: dingtalk,discord,gitea,gogs,msteams,slack,telegram
Type string `json:"type" binding:"Required"` Type string `json:"type" binding:"Required"`
// required: true // required: true
Config map[string]string `json:"config" binding:"Required"` Config CreateHookOptionConfig `json:"config" binding:"Required"`
Events []string `json:"events"` Events []string `json:"events"`
BranchFilter string `json:"branch_filter" binding:"GlobPattern"` BranchFilter string `json:"branch_filter" binding:"GlobPattern"`
// default: false // default: false
Active bool `json:"active"` Active bool `json:"active"`
} }

View file

@ -13,8 +13,8 @@ type EditReactionOption struct {
Reaction string `json:"content"` Reaction string `json:"content"`
} }
// ReactionResponse contain one reaction // Reaction contain one reaction
type ReactionResponse struct { type Reaction struct {
User *User `json:"user"` User *User `json:"user"`
Reaction string `json:"content"` Reaction string `json:"content"`
// swagger:strfmt date-time // swagger:strfmt date-time

View file

@ -132,7 +132,7 @@ func getDingtalkPushPayload(p *api.PushPayload) (*DingtalkPayload, error) {
} }
func getDingtalkIssuesPayload(p *api.IssuePayload) (*DingtalkPayload, error) { func getDingtalkIssuesPayload(p *api.IssuePayload) (*DingtalkPayload, error) {
text, issueTitle, attachmentText, _ := getIssuesPayloadInfo(p, noneLinkFormatter) text, issueTitle, attachmentText, _ := getIssuesPayloadInfo(p, noneLinkFormatter, true)
return &DingtalkPayload{ return &DingtalkPayload{
MsgType: "actionCard", MsgType: "actionCard",
@ -148,7 +148,7 @@ func getDingtalkIssuesPayload(p *api.IssuePayload) (*DingtalkPayload, error) {
} }
func getDingtalkIssueCommentPayload(p *api.IssueCommentPayload) (*DingtalkPayload, error) { func getDingtalkIssueCommentPayload(p *api.IssueCommentPayload) (*DingtalkPayload, error) {
text, issueTitle, _ := getIssueCommentPayloadInfo(p, noneLinkFormatter) text, issueTitle, _ := getIssueCommentPayloadInfo(p, noneLinkFormatter, true)
return &DingtalkPayload{ return &DingtalkPayload{
MsgType: "actionCard", MsgType: "actionCard",
@ -163,7 +163,7 @@ func getDingtalkIssueCommentPayload(p *api.IssueCommentPayload) (*DingtalkPayloa
} }
func getDingtalkPullRequestPayload(p *api.PullRequestPayload) (*DingtalkPayload, error) { func getDingtalkPullRequestPayload(p *api.PullRequestPayload) (*DingtalkPayload, error) {
text, issueTitle, attachmentText, _ := getPullRequestPayloadInfo(p, noneLinkFormatter) text, issueTitle, attachmentText, _ := getPullRequestPayloadInfo(p, noneLinkFormatter, true)
return &DingtalkPayload{ return &DingtalkPayload{
MsgType: "actionCard", MsgType: "actionCard",
@ -236,7 +236,7 @@ func getDingtalkRepositoryPayload(p *api.RepositoryPayload) (*DingtalkPayload, e
} }
func getDingtalkReleasePayload(p *api.ReleasePayload) (*DingtalkPayload, error) { func getDingtalkReleasePayload(p *api.ReleasePayload) (*DingtalkPayload, error) {
text, _ := getReleasePayloadInfo(p, noneLinkFormatter) text, _ := getReleasePayloadInfo(p, noneLinkFormatter, true)
return &DingtalkPayload{ return &DingtalkPayload{
MsgType: "actionCard", MsgType: "actionCard",

View file

@ -227,7 +227,7 @@ func getDiscordPushPayload(p *api.PushPayload, meta *DiscordMeta) (*DiscordPaylo
} }
func getDiscordIssuesPayload(p *api.IssuePayload, meta *DiscordMeta) (*DiscordPayload, error) { func getDiscordIssuesPayload(p *api.IssuePayload, meta *DiscordMeta) (*DiscordPayload, error) {
text, _, attachmentText, color := getIssuesPayloadInfo(p, noneLinkFormatter) text, _, attachmentText, color := getIssuesPayloadInfo(p, noneLinkFormatter, false)
return &DiscordPayload{ return &DiscordPayload{
Username: meta.Username, Username: meta.Username,
@ -249,7 +249,7 @@ func getDiscordIssuesPayload(p *api.IssuePayload, meta *DiscordMeta) (*DiscordPa
} }
func getDiscordIssueCommentPayload(p *api.IssueCommentPayload, discord *DiscordMeta) (*DiscordPayload, error) { func getDiscordIssueCommentPayload(p *api.IssueCommentPayload, discord *DiscordMeta) (*DiscordPayload, error) {
text, _, color := getIssueCommentPayloadInfo(p, noneLinkFormatter) text, _, color := getIssueCommentPayloadInfo(p, noneLinkFormatter, false)
return &DiscordPayload{ return &DiscordPayload{
Username: discord.Username, Username: discord.Username,
@ -271,7 +271,7 @@ func getDiscordIssueCommentPayload(p *api.IssueCommentPayload, discord *DiscordM
} }
func getDiscordPullRequestPayload(p *api.PullRequestPayload, meta *DiscordMeta) (*DiscordPayload, error) { func getDiscordPullRequestPayload(p *api.PullRequestPayload, meta *DiscordMeta) (*DiscordPayload, error) {
text, _, attachmentText, color := getPullRequestPayloadInfo(p, noneLinkFormatter) text, _, attachmentText, color := getPullRequestPayloadInfo(p, noneLinkFormatter, false)
return &DiscordPayload{ return &DiscordPayload{
Username: meta.Username, Username: meta.Username,
@ -368,7 +368,7 @@ func getDiscordRepositoryPayload(p *api.RepositoryPayload, meta *DiscordMeta) (*
} }
func getDiscordReleasePayload(p *api.ReleasePayload, meta *DiscordMeta) (*DiscordPayload, error) { func getDiscordReleasePayload(p *api.ReleasePayload, meta *DiscordMeta) (*DiscordPayload, error) {
text, color := getReleasePayloadInfo(p, noneLinkFormatter) text, color := getReleasePayloadInfo(p, noneLinkFormatter, false)
return &DiscordPayload{ return &DiscordPayload{
Username: meta.Username, Username: meta.Username,

View file

@ -25,8 +25,7 @@ func htmlLinkFormatter(url string, text string) string {
return fmt.Sprintf(`<a href="%s">%s</a>`, url, html.EscapeString(text)) return fmt.Sprintf(`<a href="%s">%s</a>`, url, html.EscapeString(text))
} }
func getIssuesPayloadInfo(p *api.IssuePayload, linkFormatter linkFormatter) (string, string, string, int) { func getIssuesPayloadInfo(p *api.IssuePayload, linkFormatter linkFormatter, withSender bool) (string, string, string, int) {
senderLink := linkFormatter(setting.AppURL+p.Sender.UserName, p.Sender.UserName)
repoLink := linkFormatter(p.Repository.HTMLURL, p.Repository.FullName) repoLink := linkFormatter(p.Repository.HTMLURL, p.Repository.FullName)
issueTitle := fmt.Sprintf("#%d %s", p.Index, p.Issue.Title) issueTitle := fmt.Sprintf("#%d %s", p.Index, p.Issue.Title)
titleLink := linkFormatter(fmt.Sprintf("%s/issues/%d", p.Repository.HTMLURL, p.Index), issueTitle) titleLink := linkFormatter(fmt.Sprintf("%s/issues/%d", p.Repository.HTMLURL, p.Index), issueTitle)
@ -35,34 +34,36 @@ func getIssuesPayloadInfo(p *api.IssuePayload, linkFormatter linkFormatter) (str
switch p.Action { switch p.Action {
case api.HookIssueOpened: case api.HookIssueOpened:
text = fmt.Sprintf("[%s] Issue opened: %s by %s", repoLink, titleLink, senderLink) text = fmt.Sprintf("[%s] Issue opened: %s", repoLink, titleLink)
color = orangeColor color = orangeColor
case api.HookIssueClosed: case api.HookIssueClosed:
text = fmt.Sprintf("[%s] Issue closed: %s by %s", repoLink, titleLink, senderLink) text = fmt.Sprintf("[%s] Issue closed: %s", repoLink, titleLink)
color = redColor color = redColor
case api.HookIssueReOpened: case api.HookIssueReOpened:
text = fmt.Sprintf("[%s] Issue re-opened: %s by %s", repoLink, titleLink, senderLink) text = fmt.Sprintf("[%s] Issue re-opened: %s", repoLink, titleLink)
case api.HookIssueEdited: case api.HookIssueEdited:
text = fmt.Sprintf("[%s] Issue edited: %s by %s", repoLink, titleLink, senderLink) text = fmt.Sprintf("[%s] Issue edited: %s", repoLink, titleLink)
case api.HookIssueAssigned: case api.HookIssueAssigned:
text = fmt.Sprintf("[%s] Issue assigned to %s: %s by %s", repoLink, text = fmt.Sprintf("[%s] Issue assigned to %s: %s", repoLink,
linkFormatter(setting.AppURL+p.Issue.Assignee.UserName, p.Issue.Assignee.UserName), linkFormatter(setting.AppURL+p.Issue.Assignee.UserName, p.Issue.Assignee.UserName), titleLink)
titleLink, senderLink)
color = greenColor color = greenColor
case api.HookIssueUnassigned: case api.HookIssueUnassigned:
text = fmt.Sprintf("[%s] Issue unassigned: %s by %s", repoLink, titleLink, senderLink) text = fmt.Sprintf("[%s] Issue unassigned: %s", repoLink, titleLink)
case api.HookIssueLabelUpdated: case api.HookIssueLabelUpdated:
text = fmt.Sprintf("[%s] Issue labels updated: %s by %s", repoLink, titleLink, senderLink) text = fmt.Sprintf("[%s] Issue labels updated: %s", repoLink, titleLink)
case api.HookIssueLabelCleared: case api.HookIssueLabelCleared:
text = fmt.Sprintf("[%s] Issue labels cleared: %s by %s", repoLink, titleLink, senderLink) text = fmt.Sprintf("[%s] Issue labels cleared: %s", repoLink, titleLink)
case api.HookIssueSynchronized: case api.HookIssueSynchronized:
text = fmt.Sprintf("[%s] Issue synchronized: %s by %s", repoLink, titleLink, senderLink) text = fmt.Sprintf("[%s] Issue synchronized: %s", repoLink, titleLink)
case api.HookIssueMilestoned: case api.HookIssueMilestoned:
mileStoneLink := fmt.Sprintf("%s/milestone/%d", p.Repository.HTMLURL, p.Issue.Milestone.ID) mileStoneLink := fmt.Sprintf("%s/milestone/%d", p.Repository.HTMLURL, p.Issue.Milestone.ID)
text = fmt.Sprintf("[%s] Issue milestoned to %s: %s by %s", repoLink, text = fmt.Sprintf("[%s] Issue milestoned to %s: %s", repoLink,
linkFormatter(mileStoneLink, p.Issue.Milestone.Title), titleLink, senderLink) linkFormatter(mileStoneLink, p.Issue.Milestone.Title), titleLink)
case api.HookIssueDemilestoned: case api.HookIssueDemilestoned:
text = fmt.Sprintf("[%s] Issue milestone cleared: %s by %s", repoLink, titleLink, senderLink) text = fmt.Sprintf("[%s] Issue milestone cleared: %s", repoLink, titleLink)
}
if withSender {
text += fmt.Sprintf(" by %s", linkFormatter(setting.AppURL+p.Sender.UserName, p.Sender.UserName))
} }
var attachmentText string var attachmentText string
@ -73,8 +74,7 @@ func getIssuesPayloadInfo(p *api.IssuePayload, linkFormatter linkFormatter) (str
return text, issueTitle, attachmentText, color return text, issueTitle, attachmentText, color
} }
func getPullRequestPayloadInfo(p *api.PullRequestPayload, linkFormatter linkFormatter) (string, string, string, int) { func getPullRequestPayloadInfo(p *api.PullRequestPayload, linkFormatter linkFormatter, withSender bool) (string, string, string, int) {
senderLink := linkFormatter(setting.AppURL+p.Sender.UserName, p.Sender.UserName)
repoLink := linkFormatter(p.Repository.HTMLURL, p.Repository.FullName) repoLink := linkFormatter(p.Repository.HTMLURL, p.Repository.FullName)
issueTitle := fmt.Sprintf("#%d %s", p.Index, p.PullRequest.Title) issueTitle := fmt.Sprintf("#%d %s", p.Index, p.PullRequest.Title)
titleLink := linkFormatter(p.PullRequest.URL, issueTitle) titleLink := linkFormatter(p.PullRequest.URL, issueTitle)
@ -83,43 +83,45 @@ func getPullRequestPayloadInfo(p *api.PullRequestPayload, linkFormatter linkForm
switch p.Action { switch p.Action {
case api.HookIssueOpened: case api.HookIssueOpened:
text = fmt.Sprintf("[%s] Pull request %s opened by %s", repoLink, titleLink, senderLink) text = fmt.Sprintf("[%s] Pull request opened: %s", repoLink, titleLink)
color = greenColor color = greenColor
case api.HookIssueClosed: case api.HookIssueClosed:
if p.PullRequest.HasMerged { if p.PullRequest.HasMerged {
text = fmt.Sprintf("[%s] Pull request %s merged by %s", repoLink, titleLink, senderLink) text = fmt.Sprintf("[%s] Pull request merged: %s", repoLink, titleLink)
color = purpleColor color = purpleColor
} else { } else {
text = fmt.Sprintf("[%s] Pull request %s closed by %s", repoLink, titleLink, senderLink) text = fmt.Sprintf("[%s] Pull request closed: %s", repoLink, titleLink)
color = redColor color = redColor
} }
case api.HookIssueReOpened: case api.HookIssueReOpened:
text = fmt.Sprintf("[%s] Pull request %s re-opened by %s", repoLink, titleLink, senderLink) text = fmt.Sprintf("[%s] Pull request re-opened: %s", repoLink, titleLink)
case api.HookIssueEdited: case api.HookIssueEdited:
text = fmt.Sprintf("[%s] Pull request %s edited by %s", repoLink, titleLink, senderLink) text = fmt.Sprintf("[%s] Pull request edited: %s", repoLink, titleLink)
case api.HookIssueAssigned: case api.HookIssueAssigned:
list := make([]string, len(p.PullRequest.Assignees)) list := make([]string, len(p.PullRequest.Assignees))
for i, user := range p.PullRequest.Assignees { for i, user := range p.PullRequest.Assignees {
list[i] = linkFormatter(setting.AppURL+user.UserName, user.UserName) list[i] = linkFormatter(setting.AppURL+user.UserName, user.UserName)
} }
text = fmt.Sprintf("[%s] Pull request %s assigned to %s by %s", repoLink, text = fmt.Sprintf("[%s] Pull request assigned: %s to %s", repoLink,
strings.Join(list, ", "), strings.Join(list, ", "), titleLink)
titleLink, senderLink)
color = greenColor color = greenColor
case api.HookIssueUnassigned: case api.HookIssueUnassigned:
text = fmt.Sprintf("[%s] Pull request %s unassigned by %s", repoLink, titleLink, senderLink) text = fmt.Sprintf("[%s] Pull request unassigned: %s", repoLink, titleLink)
case api.HookIssueLabelUpdated: case api.HookIssueLabelUpdated:
text = fmt.Sprintf("[%s] Pull request %s labels updated by %s", repoLink, titleLink, senderLink) text = fmt.Sprintf("[%s] Pull request labels updated: %s", repoLink, titleLink)
case api.HookIssueLabelCleared: case api.HookIssueLabelCleared:
text = fmt.Sprintf("[%s] Pull request %s labels cleared by %s", repoLink, titleLink, senderLink) text = fmt.Sprintf("[%s] Pull request labels cleared: %s", repoLink, titleLink)
case api.HookIssueSynchronized: case api.HookIssueSynchronized:
text = fmt.Sprintf("[%s] Pull request %s synchronized by %s", repoLink, titleLink, senderLink) text = fmt.Sprintf("[%s] Pull request synchronized: %s", repoLink, titleLink)
case api.HookIssueMilestoned: case api.HookIssueMilestoned:
mileStoneLink := fmt.Sprintf("%s/milestone/%d", p.Repository.HTMLURL, p.PullRequest.Milestone.ID) mileStoneLink := fmt.Sprintf("%s/milestone/%d", p.Repository.HTMLURL, p.PullRequest.Milestone.ID)
text = fmt.Sprintf("[%s] Pull request %s milestoned to %s by %s", repoLink, text = fmt.Sprintf("[%s] Pull request milestoned: %s to %s", repoLink,
linkFormatter(mileStoneLink, p.PullRequest.Milestone.Title), titleLink, senderLink) linkFormatter(mileStoneLink, p.PullRequest.Milestone.Title), titleLink)
case api.HookIssueDemilestoned: case api.HookIssueDemilestoned:
text = fmt.Sprintf("[%s] Pull request %s milestone cleared by %s", repoLink, titleLink, senderLink) text = fmt.Sprintf("[%s] Pull request milestone cleared: %s", repoLink, titleLink)
}
if withSender {
text += fmt.Sprintf(" by %s", linkFormatter(setting.AppURL+p.Sender.UserName, p.Sender.UserName))
} }
var attachmentText string var attachmentText string
@ -130,28 +132,29 @@ func getPullRequestPayloadInfo(p *api.PullRequestPayload, linkFormatter linkForm
return text, issueTitle, attachmentText, color return text, issueTitle, attachmentText, color
} }
func getReleasePayloadInfo(p *api.ReleasePayload, linkFormatter linkFormatter) (text string, color int) { func getReleasePayloadInfo(p *api.ReleasePayload, linkFormatter linkFormatter, withSender bool) (text string, color int) {
senderLink := linkFormatter(setting.AppURL+p.Sender.UserName, p.Sender.UserName)
repoLink := linkFormatter(p.Repository.HTMLURL, p.Repository.FullName) repoLink := linkFormatter(p.Repository.HTMLURL, p.Repository.FullName)
refLink := linkFormatter(p.Repository.HTMLURL+"/src/"+p.Release.TagName, p.Release.TagName) refLink := linkFormatter(p.Repository.HTMLURL+"/src/"+p.Release.TagName, p.Release.TagName)
switch p.Action { switch p.Action {
case api.HookReleasePublished: case api.HookReleasePublished:
text = fmt.Sprintf("[%s] Release %s created by %s", repoLink, refLink, senderLink) text = fmt.Sprintf("[%s] Release created: %s", repoLink, refLink)
color = greenColor color = greenColor
case api.HookReleaseUpdated: case api.HookReleaseUpdated:
text = fmt.Sprintf("[%s] Release %s updated by %s", repoLink, refLink, senderLink) text = fmt.Sprintf("[%s] Release updated: %s", repoLink, refLink)
color = yellowColor color = yellowColor
case api.HookReleaseDeleted: case api.HookReleaseDeleted:
text = fmt.Sprintf("[%s] Release %s deleted by %s", repoLink, refLink, senderLink) text = fmt.Sprintf("[%s] Release deleted: %s", repoLink, refLink)
color = redColor color = redColor
} }
if withSender {
text += fmt.Sprintf(" by %s", linkFormatter(setting.AppURL+p.Sender.UserName, p.Sender.UserName))
}
return text, color return text, color
} }
func getIssueCommentPayloadInfo(p *api.IssueCommentPayload, linkFormatter linkFormatter) (string, string, int) { func getIssueCommentPayloadInfo(p *api.IssueCommentPayload, linkFormatter linkFormatter, withSender bool) (string, string, int) {
senderLink := linkFormatter(setting.AppURL+p.Sender.UserName, p.Sender.UserName)
repoLink := linkFormatter(p.Repository.HTMLURL, p.Repository.FullName) repoLink := linkFormatter(p.Repository.HTMLURL, p.Repository.FullName)
issueTitle := fmt.Sprintf("#%d %s", p.Issue.Index, p.Issue.Title) issueTitle := fmt.Sprintf("#%d %s", p.Issue.Index, p.Issue.Title)
@ -168,18 +171,21 @@ func getIssueCommentPayloadInfo(p *api.IssueCommentPayload, linkFormatter linkFo
switch p.Action { switch p.Action {
case api.HookIssueCommentCreated: case api.HookIssueCommentCreated:
text = fmt.Sprintf("[%s] New comment on %s %s by %s", repoLink, typ, titleLink, senderLink) text = fmt.Sprintf("[%s] New comment on %s %s", repoLink, typ, titleLink)
if p.IsPull { if p.IsPull {
color = greenColorLight color = greenColorLight
} else { } else {
color = orangeColorLight color = orangeColorLight
} }
case api.HookIssueCommentEdited: case api.HookIssueCommentEdited:
text = fmt.Sprintf("[%s] Comment on %s %s edited by %s", repoLink, typ, titleLink, senderLink) text = fmt.Sprintf("[%s] Comment edited on %s %s", repoLink, typ, titleLink)
case api.HookIssueCommentDeleted: case api.HookIssueCommentDeleted:
text = fmt.Sprintf("[%s] Comment on %s %s deleted by %s", repoLink, typ, titleLink, senderLink) text = fmt.Sprintf("[%s] Comment deleted on %s %s", repoLink, typ, titleLink)
color = redColor color = redColor
} }
if withSender {
text += fmt.Sprintf(" by %s", linkFormatter(setting.AppURL+p.Sender.UserName, p.Sender.UserName))
}
return text, issueTitle, color return text, issueTitle, color
} }

View file

@ -266,7 +266,7 @@ func getMSTeamsPushPayload(p *api.PushPayload) (*MSTeamsPayload, error) {
} }
func getMSTeamsIssuesPayload(p *api.IssuePayload) (*MSTeamsPayload, error) { func getMSTeamsIssuesPayload(p *api.IssuePayload) (*MSTeamsPayload, error) {
text, _, attachmentText, color := getIssuesPayloadInfo(p, noneLinkFormatter) text, _, attachmentText, color := getIssuesPayloadInfo(p, noneLinkFormatter, false)
return &MSTeamsPayload{ return &MSTeamsPayload{
Type: "MessageCard", Type: "MessageCard",
@ -308,7 +308,7 @@ func getMSTeamsIssuesPayload(p *api.IssuePayload) (*MSTeamsPayload, error) {
} }
func getMSTeamsIssueCommentPayload(p *api.IssueCommentPayload) (*MSTeamsPayload, error) { func getMSTeamsIssueCommentPayload(p *api.IssueCommentPayload) (*MSTeamsPayload, error) {
text, _, color := getIssueCommentPayloadInfo(p, noneLinkFormatter) text, _, color := getIssueCommentPayloadInfo(p, noneLinkFormatter, false)
return &MSTeamsPayload{ return &MSTeamsPayload{
Type: "MessageCard", Type: "MessageCard",
@ -350,7 +350,7 @@ func getMSTeamsIssueCommentPayload(p *api.IssueCommentPayload) (*MSTeamsPayload,
} }
func getMSTeamsPullRequestPayload(p *api.PullRequestPayload) (*MSTeamsPayload, error) { func getMSTeamsPullRequestPayload(p *api.PullRequestPayload) (*MSTeamsPayload, error) {
text, _, attachmentText, color := getPullRequestPayloadInfo(p, noneLinkFormatter) text, _, attachmentText, color := getPullRequestPayloadInfo(p, noneLinkFormatter, false)
return &MSTeamsPayload{ return &MSTeamsPayload{
Type: "MessageCard", Type: "MessageCard",
@ -503,7 +503,7 @@ func getMSTeamsRepositoryPayload(p *api.RepositoryPayload) (*MSTeamsPayload, err
} }
func getMSTeamsReleasePayload(p *api.ReleasePayload) (*MSTeamsPayload, error) { func getMSTeamsReleasePayload(p *api.ReleasePayload) (*MSTeamsPayload, error) {
text, color := getReleasePayloadInfo(p, noneLinkFormatter) text, color := getReleasePayloadInfo(p, noneLinkFormatter, false)
return &MSTeamsPayload{ return &MSTeamsPayload{
Type: "MessageCard", Type: "MessageCard",

View file

@ -144,7 +144,7 @@ func getSlackForkPayload(p *api.ForkPayload, slack *SlackMeta) (*SlackPayload, e
} }
func getSlackIssuesPayload(p *api.IssuePayload, slack *SlackMeta) (*SlackPayload, error) { func getSlackIssuesPayload(p *api.IssuePayload, slack *SlackMeta) (*SlackPayload, error) {
text, issueTitle, attachmentText, color := getIssuesPayloadInfo(p, SlackLinkFormatter) text, issueTitle, attachmentText, color := getIssuesPayloadInfo(p, SlackLinkFormatter, true)
pl := &SlackPayload{ pl := &SlackPayload{
Channel: slack.Channel, Channel: slack.Channel,
@ -167,7 +167,7 @@ func getSlackIssuesPayload(p *api.IssuePayload, slack *SlackMeta) (*SlackPayload
} }
func getSlackIssueCommentPayload(p *api.IssueCommentPayload, slack *SlackMeta) (*SlackPayload, error) { func getSlackIssueCommentPayload(p *api.IssueCommentPayload, slack *SlackMeta) (*SlackPayload, error) {
text, issueTitle, color := getIssueCommentPayloadInfo(p, SlackLinkFormatter) text, issueTitle, color := getIssueCommentPayloadInfo(p, SlackLinkFormatter, true)
return &SlackPayload{ return &SlackPayload{
Channel: slack.Channel, Channel: slack.Channel,
@ -184,7 +184,7 @@ func getSlackIssueCommentPayload(p *api.IssueCommentPayload, slack *SlackMeta) (
} }
func getSlackReleasePayload(p *api.ReleasePayload, slack *SlackMeta) (*SlackPayload, error) { func getSlackReleasePayload(p *api.ReleasePayload, slack *SlackMeta) (*SlackPayload, error) {
text, _ := getReleasePayloadInfo(p, SlackLinkFormatter) text, _ := getReleasePayloadInfo(p, SlackLinkFormatter, true)
return &SlackPayload{ return &SlackPayload{
Channel: slack.Channel, Channel: slack.Channel,
@ -239,7 +239,7 @@ func getSlackPushPayload(p *api.PushPayload, slack *SlackMeta) (*SlackPayload, e
} }
func getSlackPullRequestPayload(p *api.PullRequestPayload, slack *SlackMeta) (*SlackPayload, error) { func getSlackPullRequestPayload(p *api.PullRequestPayload, slack *SlackMeta) (*SlackPayload, error) {
text, issueTitle, attachmentText, color := getPullRequestPayloadInfo(p, SlackLinkFormatter) text, issueTitle, attachmentText, color := getPullRequestPayloadInfo(p, SlackLinkFormatter, true)
pl := &SlackPayload{ pl := &SlackPayload{
Channel: slack.Channel, Channel: slack.Channel,

View file

@ -70,7 +70,7 @@ func TestSlackReleasePayload(t *testing.T) {
require.Nil(t, err) require.Nil(t, err)
require.NotNil(t, pl) require.NotNil(t, pl)
assert.Equal(t, "[<http://localhost:3000/test/repo|test/repo>] Release <http://localhost:3000/test/repo/src/v1.0|v1.0> created by <https://try.gitea.io/user1|user1>", pl.Text) assert.Equal(t, "[<http://localhost:3000/test/repo|test/repo>] Release created: <http://localhost:3000/test/repo/src/v1.0|v1.0> by <https://try.gitea.io/user1|user1>", pl.Text)
} }
func TestSlackPullRequestPayload(t *testing.T) { func TestSlackPullRequestPayload(t *testing.T) {
@ -84,5 +84,5 @@ func TestSlackPullRequestPayload(t *testing.T) {
require.Nil(t, err) require.Nil(t, err)
require.NotNil(t, pl) require.NotNil(t, pl)
assert.Equal(t, "[<http://localhost:3000/test/repo|test/repo>] Pull request <http://localhost:3000/test/repo/pulls/12|#2 Fix bug> opened by <https://try.gitea.io/user1|user1>", pl.Text) assert.Equal(t, "[<http://localhost:3000/test/repo|test/repo>] Pull request opened: <http://localhost:3000/test/repo/pulls/12|#2 Fix bug> by <https://try.gitea.io/user1|user1>", pl.Text)
} }

View file

@ -125,7 +125,7 @@ func getTelegramPushPayload(p *api.PushPayload) (*TelegramPayload, error) {
} }
func getTelegramIssuesPayload(p *api.IssuePayload) (*TelegramPayload, error) { func getTelegramIssuesPayload(p *api.IssuePayload) (*TelegramPayload, error) {
text, _, attachmentText, _ := getIssuesPayloadInfo(p, htmlLinkFormatter) text, _, attachmentText, _ := getIssuesPayloadInfo(p, htmlLinkFormatter, true)
return &TelegramPayload{ return &TelegramPayload{
Message: text + "\n\n" + attachmentText, Message: text + "\n\n" + attachmentText,
@ -133,7 +133,7 @@ func getTelegramIssuesPayload(p *api.IssuePayload) (*TelegramPayload, error) {
} }
func getTelegramIssueCommentPayload(p *api.IssueCommentPayload) (*TelegramPayload, error) { func getTelegramIssueCommentPayload(p *api.IssueCommentPayload) (*TelegramPayload, error) {
text, _, _ := getIssueCommentPayloadInfo(p, htmlLinkFormatter) text, _, _ := getIssueCommentPayloadInfo(p, htmlLinkFormatter, true)
return &TelegramPayload{ return &TelegramPayload{
Message: text + "\n" + p.Comment.Body, Message: text + "\n" + p.Comment.Body,
@ -141,7 +141,7 @@ func getTelegramIssueCommentPayload(p *api.IssueCommentPayload) (*TelegramPayloa
} }
func getTelegramPullRequestPayload(p *api.PullRequestPayload) (*TelegramPayload, error) { func getTelegramPullRequestPayload(p *api.PullRequestPayload) (*TelegramPayload, error) {
text, _, attachmentText, _ := getPullRequestPayloadInfo(p, htmlLinkFormatter) text, _, attachmentText, _ := getPullRequestPayloadInfo(p, htmlLinkFormatter, true)
return &TelegramPayload{ return &TelegramPayload{
Message: text + "\n" + attachmentText, Message: text + "\n" + attachmentText,
@ -166,7 +166,7 @@ func getTelegramRepositoryPayload(p *api.RepositoryPayload) (*TelegramPayload, e
} }
func getTelegramReleasePayload(p *api.ReleasePayload) (*TelegramPayload, error) { func getTelegramReleasePayload(p *api.ReleasePayload) (*TelegramPayload, error) {
text, _ := getReleasePayloadInfo(p, htmlLinkFormatter) text, _ := getReleasePayloadInfo(p, htmlLinkFormatter, true)
return &TelegramPayload{ return &TelegramPayload{
Message: text + "\n", Message: text + "\n",

View file

@ -10,6 +10,7 @@ link_account = Link Account
register = Register register = Register
website = Website website = Website
version = Version version = Version
powered_by = Powered by %s
page = Page page = Page
template = Template template = Template
language = Language language = Language
@ -1054,6 +1055,7 @@ pulls.is_checking = "Merge conflict checking is in progress. Try again in few mo
pulls.required_status_check_failed = Some required checks were not successful. pulls.required_status_check_failed = Some required checks were not successful.
pulls.required_status_check_administrator = As an administrator, you may still merge this pull request. pulls.required_status_check_administrator = As an administrator, you may still merge this pull request.
pulls.blocked_by_approvals = "This Pull Request doesn't have enough approvals yet. %d of %d approvals granted." pulls.blocked_by_approvals = "This Pull Request doesn't have enough approvals yet. %d of %d approvals granted."
pulls.blocked_by_rejection = "This Pull Request has changes requested by an official reviewer."
pulls.can_auto_merge_desc = This pull request can be merged automatically. pulls.can_auto_merge_desc = This pull request can be merged automatically.
pulls.cannot_auto_merge_desc = This pull request cannot be merged automatically due to conflicts. pulls.cannot_auto_merge_desc = This pull request cannot be merged automatically due to conflicts.
pulls.cannot_auto_merge_helper = Merge manually to resolve the conflicts. pulls.cannot_auto_merge_helper = Merge manually to resolve the conflicts.
@ -1417,6 +1419,8 @@ settings.update_protect_branch_success = Branch protection for branch '%s' has b
settings.remove_protected_branch_success = Branch protection for branch '%s' has been disabled. settings.remove_protected_branch_success = Branch protection for branch '%s' has been disabled.
settings.protected_branch_deletion = Disable Branch Protection settings.protected_branch_deletion = Disable Branch Protection
settings.protected_branch_deletion_desc = Disabling branch protection allows users with write permission to push to the branch. Continue? settings.protected_branch_deletion_desc = Disabling branch protection allows users with write permission to push to the branch. Continue?
settings.block_rejected_reviews = Block merge on rejected reviews
settings.block_rejected_reviews_desc = Merging will not be possible when changes are requested by official reviewers, even if there are enough approvals.
settings.default_branch_desc = Select a default repository branch for pull requests and code commits: settings.default_branch_desc = Select a default repository branch for pull requests and code commits:
settings.choose_branch = Choose a branch… settings.choose_branch = Choose a branch…
settings.no_protected_branch = There are no protected branches. settings.no_protected_branch = There are no protected branches.

File diff suppressed because it is too large Load diff

View file

@ -10,6 +10,7 @@ link_account=Saistītie konti
register=Reģistrēties register=Reģistrēties
website=Mājas lapa website=Mājas lapa
version=Versija version=Versija
powered_by=Darbina %s
page=Lapa page=Lapa
template=Sagatave template=Sagatave
language=Valoda language=Valoda
@ -959,6 +960,7 @@ issues.add_time=Manuāli pievienot laiku
issues.add_time_short=Pievienot laiku issues.add_time_short=Pievienot laiku
issues.add_time_cancel=Atcelt issues.add_time_cancel=Atcelt
issues.add_time_history=` pievienoja patērēto laiku %s` issues.add_time_history=` pievienoja patērēto laiku %s`
issues.del_time_history=`dzēsts patērētais laiks %s`
issues.add_time_hours=Stundas issues.add_time_hours=Stundas
issues.add_time_minutes=Minūtes issues.add_time_minutes=Minūtes
issues.add_time_sum_to_small=Nav norādīts laiks. issues.add_time_sum_to_small=Nav norādīts laiks.
@ -1052,6 +1054,7 @@ pulls.is_checking=Notiek konfliktu pārbaude, mirkli uzgaidiet un atjaunojiet la
pulls.required_status_check_failed=Dažas no pārbaudēm nebija veiksmīgas. pulls.required_status_check_failed=Dažas no pārbaudēm nebija veiksmīgas.
pulls.required_status_check_administrator=Kā administrators Jūs varat sapludināt šo izmaiņu pieprasījumu. pulls.required_status_check_administrator=Kā administrators Jūs varat sapludināt šo izmaiņu pieprasījumu.
pulls.blocked_by_approvals=Šim izmaiņu pieprasījumam nav nepieciešamais apstiprinājumu daudzums. %d no %d apstiprinājumi piešķirti. pulls.blocked_by_approvals=Šim izmaiņu pieprasījumam nav nepieciešamais apstiprinājumu daudzums. %d no %d apstiprinājumi piešķirti.
pulls.blocked_by_rejection=Šo izmaiņu pieprasījumu nevar sapludināt, jo tam ir peprasītas izmaiņas.
pulls.can_auto_merge_desc=Šo izmaiņu pieprasījumu var automātiski sapludināt. pulls.can_auto_merge_desc=Šo izmaiņu pieprasījumu var automātiski sapludināt.
pulls.cannot_auto_merge_desc=Šis izmaiņu pieprasījums nevar tikt automātiski sapludināts konfliktu dēļ. pulls.cannot_auto_merge_desc=Šis izmaiņu pieprasījums nevar tikt automātiski sapludināts konfliktu dēļ.
pulls.cannot_auto_merge_helper=Sapludiniet manuāli, lai atrisinātu konfliktus. pulls.cannot_auto_merge_helper=Sapludiniet manuāli, lai atrisinātu konfliktus.
@ -1415,6 +1418,8 @@ settings.update_protect_branch_success=Atzara aizsardzība atzaram '%s' tika sag
settings.remove_protected_branch_success=Atzara aizsardzība atzaram '%s' tika atspējota. settings.remove_protected_branch_success=Atzara aizsardzība atzaram '%s' tika atspējota.
settings.protected_branch_deletion=Atspējot atzara aizsardzību settings.protected_branch_deletion=Atspējot atzara aizsardzību
settings.protected_branch_deletion_desc=Atspējojot atzara aizsardzību, ļaus lietotājiem ar rakstīšanas tiesībām nosūtīt izmaiņas uz atzaru. Vai turpināt? settings.protected_branch_deletion_desc=Atspējojot atzara aizsardzību, ļaus lietotājiem ar rakstīšanas tiesībām nosūtīt izmaiņas uz atzaru. Vai turpināt?
settings.block_rejected_reviews=Neļaut sapludināt izmaiņu pieprasījumus, kam ir pieprasītas izmaiņas
settings.block_rejected_reviews_desc=Sapludināšana nebūs iespējama, kad ir pieprasītas izmaiņas, pat ja ir nepieciešamais apstiprinājumu skaits.
settings.default_branch_desc=Norādiet noklusēto repozitorija atzaru izmaiņu pieprasījumiem un koda revīzijām: settings.default_branch_desc=Norādiet noklusēto repozitorija atzaru izmaiņu pieprasījumiem un koda revīzijām:
settings.choose_branch=Izvēlieties atzaru… settings.choose_branch=Izvēlieties atzaru…
settings.no_protected_branch=Nav neviena aizsargātā atzara. settings.no_protected_branch=Nav neviena aizsargātā atzara.
@ -2046,6 +2051,7 @@ create_pull_request=`izveidoja izmaiņu pieprasījumu <a href="%s/pulls/%s">%s#%
close_pull_request=`aizvēra izmaiņu pieprasījumu <a href="%s/pulls/%s">%s#%[2]s</a>` close_pull_request=`aizvēra izmaiņu pieprasījumu <a href="%s/pulls/%s">%s#%[2]s</a>`
reopen_pull_request=`atkārtoti atvēra izmaiņu pieprasījumu <a href="%s/pulls/%s">%s#%[2]s</a>` reopen_pull_request=`atkārtoti atvēra izmaiņu pieprasījumu <a href="%s/pulls/%s">%s#%[2]s</a>`
comment_issue=`pievienoja komentāru problēmai <a href="%s/issues/%s">%s#%[2]s</a>` comment_issue=`pievienoja komentāru problēmai <a href="%s/issues/%s">%s#%[2]s</a>`
comment_pull=`komentēja izmaiņu pieprasījumu <a href="%s/pulls/%s">%s#%[2]s</a>`
merge_pull_request=`sapludināja izmaiņu pieprasījumu <a href="%s/pulls/%s">%s#%[2]s</a>` merge_pull_request=`sapludināja izmaiņu pieprasījumu <a href="%s/pulls/%s">%s#%[2]s</a>`
transfer_repo=mainīja repozitorija <code>%s</code> īpašnieku uz <a href="%s">%s</a> transfer_repo=mainīja repozitorija <code>%s</code> īpašnieku uz <a href="%s">%s</a>
push_tag=pievienoja tagu <a href="%s/src/tag/%s">%[2]s</a> repozitorijam <a href="%[1]s">%[3]s</a> push_tag=pievienoja tagu <a href="%s/src/tag/%s">%[2]s</a> repozitorijam <a href="%[1]s">%[3]s</a>

View file

@ -1,76 +1,759 @@
home=പൂമുഖം
dashboard=ഡാഷ്ബോർഡ്
explore=കണ്ടെത്തൂ
help=സഹായം
sign_in=പ്രവേശിക്കുക
sign_in_with=ഉപയോഗിച്ചു് പ്രവേശിയ്ക്കുക
sign_out=പുറത്തുകടക്കുക
sign_up=രജിസ്റ്റർ
link_account=അക്കൌണ്ട് ബന്ധിപ്പിയ്ക്കുക
register=രജിസ്റ്റർ
website=വെബ് സൈറ്റ്
version=പതിപ്പ്
page=പേജ്
template=ടെംപ്ലേറ്റ്
language=ഭാഷ
notifications=അറിയിപ്പുകൾ
create_new=സൃഷ്ടിക്കുക…
user_profile_and_more=പ്രൊഫൈലും ക്രമീകരണങ്ങളും…
signed_in_as=ഇയാളായി പ്രവേശിയ്ക്കുക
enable_javascript=ഈ വെബ്‌സൈറ്റ് ജാവാസ്ക്രിപ്റ്റിനൊപ്പം മികച്ച രീതിയിൽ പ്രവർത്തിക്കുന്നു.
username=ഉപയോക്ത്രു നാമം
email=ഈമെയില്‍ വിലാസം
password=രഹസ്യവാക്കു്
re_type=രഹസ്യവാക്കു് വീണ്ടും നല്‍കുക
captcha=ക്യാപ്ച
twofa=ഇരട്ട ഘടക പ്രാമാണീകരണം
twofa_scratch=ഇരട്ട ഫാക്ടർ സ്ക്രാച്ച് കോഡ്
passcode=രഹസ്യ കോഡ്
u2f_insert_key=സെക്യൂരിറ്റി കീ ഇന്‍സേര്‍ട്ടു് ചെയ്യുക
u2f_sign_in=സെക്യൂരിറ്റി കീയിലെ ബട്ടണ്‍ അമര്‍ത്തുക. സെക്യൂരിറ്റി കീയില്‍ ബട്ടണൊന്നും ഇല്ലെങ്കില്‍ വീണ്ടും ഇന്‍സേര്‍ട്ടു് ചെയ്യുക.
u2f_press_button=ദയവായി സെക്യൂരിറ്റി കീയിലെ ബട്ടണ്‍ അമര്‍ത്തൂ…
u2f_use_twofa=നിങ്ങളുടെ ഫോണിൽ നിന്നുള്ള ഇരട്ട-ഘടക കോഡ് ഉപയോഗിക്കുക
u2f_error=സെക്യൂരിറ്റി കീ വായിയ്ക്കാനാകുന്നില്ല.
u2f_unsupported_browser=നീങ്ങളുടെ ബ്രൗസര്‍ ഇരട്ട ഘടക സെക്യൂരിറ്റി പിന്തുണയ്ക്കുന്നില്ല.
u2f_error_1=ഒരു അവിചാരിതമായ പിശക് സംഭവിച്ചു. ദയവായി വീണ്ടും ശ്രമിക്കുക.
u2f_error_2=നിങ്ങള്‍ ഉപയോഗിക്കുന്നത് ശരിയായ, എൻ‌ക്രിപ്റ്റ് ചെയ്ത (https://) യുആർഎൽ ആണെന്നു ദയവായി ഉറപ്പാക്കുക.
u2f_error_3=നിങ്ങളുടെ അഭ്യർത്ഥന പ്രോസസ്സ് ചെയ്യാൻ സെർവറിന് കഴിഞ്ഞില്ല.
u2f_error_4=ഈ അഭ്യർത്ഥന പൂര്‍ത്തിയാക്കാന്‍ സുരക്ഷാ കീ അനുവദനിയ്ക്കുന്നില്ല. ഈ കീ ഇതിനോടകം രജിസ്റ്റർ ചെയ്തിട്ടില്ലെന്ന് ഉറപ്പു വരുത്തുക.
u2f_error_5=നിങ്ങളുടെ കീ വായിക്കുന്നതിന് പൂര്‍ത്തിയാക്കാനായില്ല. ദയവായി ഈ പേജ് പുതുക്കി വീണ്ടും ശ്രമിക്കുക.
u2f_reload=പുതുക്കുക
repository=കലവറ
organization=സംഘടന
mirror=മിറര്‍
new_repo=പുതിയ കലവറ
new_migrate=പുതിയ കുടിയേറ്റിപ്പാര്‍പ്പിക്കല്‍
new_mirror=പുതിയ മിറര്‍
new_fork=കലവറയുടെ പുതിയ ശിഖരം
new_org=പുതിയ സംഘടന
manage_org=സംഘടനകളെ നിയന്ത്രിക്കുക
admin_panel=സൈറ്റിന്റെ കാര്യനിര്‍വ്വാഹണം
account_settings=അക്കൌണ്ട് ക്രമീകരണങള്‍
settings=ക്രമീകരണങ്ങള്‍
your_profile=പ്രൊഫൈൽ
your_starred=നക്ഷത്ര ചിഹ്നമിട്ടവ
your_settings=ക്രമീകരണങ്ങള്‍
all=എല്ലാം
sources=ഉറവിടങ്ങൾ
mirrors=മിററുകള്‍
collaborative=സഹകരിക്കുന്ന
forks=ശാഖകള്‍
activities=പ്രവര്‍ത്തനങ്ങള്‍
pull_requests=ലയന അഭ്യർത്ഥനകൾ
issues=പ്രശ്നങ്ങൾ
cancel=റദ്ദാക്കുക
write=എഴുതുക
preview=തിരനോട്ടം
loading=ലഭ്യമാക്കുന്നു…
[startpage] [startpage]
[install] [install]
install=സന്നിവേശിപ്പിയ്ക്കുക
title=പ്രാരംഭ ക്രമീകരണങ്ങള്‍
docker_helper=ഡോക്കറിനുള്ളിലാണ് ഗിറ്റീ പ്രവര്‍ത്തിപ്പിയ്ക്കുന്നതെങ്കില്‍, മാറ്റങ്ങള്‍ വരുത്തുന്നതിനു മുമ്പു് ദയവായി <a target="_blank" rel="noopener noreferrer" href="%s">ഡോക്യുമെന്റേഷൻ</a> വായിയ്ക്കുക.
requite_db_desc=ഗിറ്റീയ്ക്കു് MySQL, PostgreSQL, MSSQL അല്ലെങ്കിൽ SQLite3 ആവശ്യമാണ്.
db_title=ഡാറ്റാബേസ് ക്രമീകരണങ്ങൾ
db_type=ഡാറ്റാബേസിന്റെ തരം
host=ഹോസ്റ്റ്
user=ഉപയോക്ത്രു നാമം
password=രഹസ്യവാക്കു്
db_name=ഡാറ്റാബേസിന്റെ പേര്
db_helper=MySQL ഉപയോക്താക്കൾക്കുള്ള കുറിപ്പ്: ദയവായി InnoDB സ്റ്റോറേജ് എഞ്ചിൻ ഉപയോഗിക്കുക. നിങ്ങൾ "utf8mb4" ഉപയോഗിക്കുകയാണെങ്കിൽ, InnoDB പതിപ്പ് 5.6 നേക്കാൾ വലുതായിരിക്കണം.
ssl_mode=SSL
charset=ക്യാര്‍സെറ്റ്
path=പാത
sqlite_helper=SQLite3 ഡാറ്റാബേസിന്റെ ഫയല്‍ പാത്ത്.<br>നിങ്ങൾ ഗിറ്റീയെ ഒരു സേവനമായി പ്രവർത്തിപ്പിക്കുകയാണെങ്കിൽ സമ്പൂര്‍ണ്ണ ഫയല്‍ പാത നൽകുക.
err_empty_db_path=SQLite3 ഡാറ്റാബേസ് പാത്ത് ശൂന്യമായിരിക്കരുത്.
no_admin_and_disable_registration=ഒരു അഡ്മിനിസ്ട്രേറ്റർ അക്കൌണ്ട് സൃഷ്ടിക്കാതെ നിങ്ങൾക്ക് ഉപയോക്തൃ സ്വയം രജിസ്ട്രേഷൻ അപ്രാപ്തമാക്കാൻ കഴിയില്ല.
err_empty_admin_password=അഡ്മിനിസ്ട്രേറ്ററുടെ രഹസ്യവാക്കു് ശൂന്യമായിരിക്കരുത്.
err_empty_admin_email=അഡ്മിനിസ്ട്രേറ്ററുടെ ഇമെയില്‍ വിലാസം ശൂന്യമായിരിക്കരുത്.
err_admin_name_is_reserved=അഡ്മിനിസ്ട്രേറ്റര്‍ ഉപയോക്തൃനാമം അസാധുവാണ്, ഉപയോക്തൃനാമം റിസര്‍വ്വ് ചെയ്തതാണ്
err_admin_name_pattern_not_allowed=അഡ്മിനിസ്ട്രേറ്റര്‍ ഉപയോക്തൃനാമം അസാധുവാണ്, ഉപയോക്തൃനാമം അനുവദിനീയമല്ല
err_admin_name_is_invalid=അഡ്മിനിസ്ട്രേറ്റർ ഉപയോക്തൃനാമം അസാധുവാണ്
general_title=പൊതുവായ ക്രമീകരണങ്ങൾ
app_name=സൈറ്റ് ശീർഷകം
app_name_helper=നിങ്ങളുടെ കമ്പനിയുടെ പേര് ഇവിടെ നൽകാം.
repo_path=സംഭരണിയുടെ റൂട്ട് പാത്ത്
repo_path_helper=വിദൂര ഗിറ്റു് സംഭരണികള്‍ ഈ ഡയറക്ടറിയിലേക്ക് സംരക്ഷിക്കും.
lfs_path=Git LFS റൂട്ട് പാത്ത്
lfs_path_helper=Git LFS ട്രാക്കുചെയ്ത ഫയലുകൾ ഈ ഡയറക്ടറിയിൽ സൂക്ഷിക്കും. പ്രവർത്തനരഹിതമാക്കാൻ ഈ കളം ശൂന്യമായി വിടുക.
run_user=ഉപയോക്താവായി പ്രവര്‍ത്തിപ്പിക്കുക
run_user_helper=ഗിറ്റീ പ്രവർത്തിക്കുന്ന ഓപ്പറേറ്റിംഗ് സിസ്റ്റത്തിന്റെ ഉപയോക്തൃനാമം നല്കുക. ഈ ഉപയോക്താവിന് സംഭരണിയുടെ റൂട്ട് പാത്തിലേക്ക് പ്രവേശനം ഉണ്ടായിരിക്കണം.
domain=SSH സെർവർ ഡൊമെയ്ൻ
domain_helper=SSH ക്ലോൺ URL- കൾക്കായുള്ള ഡൊമെയ്ൻ അല്ലെങ്കിൽ ഹോസ്റ്റ് വിലാസം.
ssh_port=SSH സെർവർ പോര്‍ട്ട്
ssh_port_helper=നിങ്ങളുടെ SSH സെർവർ ശ്രവിക്കുന്ന പോർട്ട് നമ്പർ നല്‍കുക. പ്രവർത്തനരഹിതമാക്കാൻ കളം ശൂന്യമായി വിടുക.
http_port=ഗിറ്റീ എച്ച്ടിടിപി ശ്രവിയ്ക്കുന്ന പോർട്ട്
http_port_helper=ഗിറ്റീ വെബ് സെർവർ ശ്രവിയ്ക്കുന്ന പോർട്ട് നമ്പർ.
app_url=ഗിറ്റീയുടെ അടിസ്ഥാന വിലാസം
app_url_helper=എച്ച്ടിടിപി(എസ്) ക്ലോണുകള്‍ക്കും ഇമെയിൽ അറിയിപ്പുകൾക്കുമായുള്ള അടിസ്ഥാന വിലാസം.
log_root_path=ലോഗ് പാത്ത്
log_root_path_helper=ലോഗ് ഫയലുകൾ ഈ ഡയറക്ടറിയിലേക്ക് എഴുതപ്പെടും.
optional_title=ഐച്ഛികമായ ക്രമീകരണങ്ങൾ
email_title=ഇമെയിൽ ക്രമീകരണങ്ങൾ
smtp_host=SMTP ഹോസ്റ്റ്
smtp_from=ഈ വിലാസത്തില്‍ ഇമെയിൽ അയയ്‌ക്കുക
smtp_from_helper=ഗിറ്റീ ഉപയോഗിയ്ക്കുന്ന ഇമെയില്‍ വിലാസം. ഒരു സാധാ ഇമെയിൽ വിലാസം നൽകുക അല്ലെങ്കിൽ "പേര്"<email@example.com> എന്ന ഘടന ഉപയോഗിക്കുക.
mailer_user=SMTP ഉപയോക്തൃനാമം
mailer_password=SMTP രഹസ്യവാക്കു്
register_confirm=രജിസ്റ്റർ ചെയ്യുന്നതിന് ഇമെയിൽ സ്ഥിരീകരണം ആവശ്യമാക്കുക
mail_notify=ഇമെയിൽ അറിയിപ്പുകൾ പ്രാപ്തമാക്കുക
server_service_title=സെർവറിന്റെയും മൂന്നാം കക്ഷി സേവനങ്ങളുടെയും ക്രമീകരണങ്ങള്‍
offline_mode=പ്രാദേശിക മോഡ് പ്രവർത്തനക്ഷമമാക്കുക
offline_mode_popup=മൂന്നാം കക്ഷി ഉള്ളടക്ക ഡെലിവറി നെറ്റ്‌വർക്കുകൾ അപ്രാപ്‌തമാക്കി എല്ലാ വിഭവങ്ങളും പ്രാദേശികമായി നല്‍കുക.
disable_gravatar=ഗ്രവതാര്‍ പ്രവർത്തനരഹിതമാക്കുക
disable_gravatar_popup=ഗ്രവതാര്‍ അല്ലെങ്കില്‍ മൂന്നാം കക്ഷി അവതാർ ഉറവിടങ്ങൾ പ്രവർത്തനരഹിതമാക്കുക. ഒരു ഉപയോക്താവ് പ്രാദേശികമായി ഒരു അവതാർ അപ്‌ലോഡുചെയ്യുന്നില്ലെങ്കിൽ സ്ഥിരസ്ഥിതി അവതാർ ഉപയോഗിക്കും.
federated_avatar_lookup=കേന്ദ്രീകൃത അവതാര്‍ പ്രാപ്തമാക്കുക
federated_avatar_lookup_popup=ലിബ്രാവതാർ ഉപയോഗിച്ച് കേന്ദ്രീക്രത അവതാർ തിരയൽ പ്രാപ്തമാക്കുക.
disable_registration=സ്വയം രജിസ്ട്രേഷൻ അപ്രാപ്തമാക്കുക
disable_registration_popup=ഉപയോക്താക്കള്‍ സ്വയം രജിസ്റ്റര്‍ ചെയ്യുന്നതു അപ്രാപ്യമാക്കുക. അഡ്മിനിസ്ട്രേറ്റർമാർക്ക് മാത്രമേ പുതിയ ഉപയോക്തൃ അക്കൌണ്ടുകൾ സൃഷ്ടിക്കാന്‍ കഴിയൂ.
allow_only_external_registration_popup=ബാഹ്യ സേവനങ്ങളിലൂടെ മാത്രം രജിസ്ട്രേഷന്‍ അനുവദിക്കുക
openid_signin=OpenID പ്രവേശനം പ്രവർത്തനക്ഷമമാക്കുക
openid_signin_popup=OpenID വഴി ഉപയോക്തൃ പ്രവേശനം പ്രാപ്തമാക്കുക.
openid_signup=OpenID സ്വയം രജിസ്ട്രേഷൻ പ്രാപ്തമാക്കുക
openid_signup_popup=OpenID അടിസ്ഥാനമാക്കിയുള്ള ഉപയോക്തൃ സ്വയം രജിസ്ട്രേഷൻ പ്രാപ്തമാക്കുക.
enable_captcha=ക്യാപ്ച പ്രാപ്തമാക്കുക
enable_captcha_popup=ഉപയോക്താക്കള്‍ സ്വയം രജിസ്ട്രേഷന്‍ ചെയ്യുന്നതിനു് ഒരു ക്യാപ്ച ആവശ്യമാണ്.
require_sign_in_view=പേജുകൾ കാണുന്നതിന് സൈറ്റില്‍ പ്രവേശിക്കണം
require_sign_in_view_popup=പേജ് ആക്‌സസ്സ്, പ്രവേശിച്ച ഉപയോക്താക്കൾക്കുമാത്രമായി പരിമിതപ്പെടുത്തുക. സന്ദർശകർ 'പ്രവേശനം', രജിസ്ട്രേഷൻ പേജുകൾ എന്നിവ മാത്രമേ കാണൂ.
admin_setting_desc=ഒരു അഡ്മിനിസ്ട്രേറ്റര്‍ അക്കൗണ്ട് സൃഷ്ടിക്കുന്നത് ഐച്ഛികമാണ്. ആദ്യം രജിസ്റ്റര്‍ ചെയ്ത ഉപയോക്താവ് യാന്ത്രികമായി ഒരു അഡ്മിനിസ്ട്രേറ്ററായി മാറും.
admin_title=അഡ്മിനിസ്ട്രേറ്റര്‍ അക്കൗണ്ട് ക്രമീകരണങ്ങൾ
admin_name=അഡ്മിനിസ്ട്രേറ്ററുടെ ഉപയോക്തൃനാമം
admin_password=രഹസ്യവാക്കു്
confirm_password=രഹസ്യവാക്കു് സ്ഥിരീകരിക്കുക
admin_email=ഇ-മെയില്‍ വിലാസം
install_btn_confirm=ഗിറ്റീ സന്നിവേശിപ്പിയ്ക്കുക
test_git_failed='git' കമാന്‍ഡ് പരീക്ഷിക്കാന്‍ കഴിഞ്ഞില്ല: %v
sqlite3_not_available=ഗിറ്റീയുടെ ഈ വേര്‍ഷന്‍ SQLite3യെ പിന്തുണക്കുന്നില്ല. %s ൽ നിന്നും ഔദ്യോഗിക ബൈനറി പതിപ്പ് ഡൌണ്‍‌ലോഡ് ചെയ്യുക ('gobuild' പതിപ്പല്ല).
invalid_db_setting=ഡാറ്റാബേസ് ക്രമീകരണങ്ങൾ അസാധുവാണ്: %v
invalid_repo_path=കലവറയുടെ റൂട്ട് പാത്ത് അസാധുവാണ്: %v
run_user_not_match='റൺ ആസ്' ഉപയോക്തൃനാമം നിലവിലെ ഉപയോക്തൃനാമമല്ല: %s -> %s
save_config_failed=കോൺഫിഗറേഷൻ സംരക്ഷിക്കുന്നതിൽ പരാജയപ്പെട്ടു: %v
invalid_admin_setting=അഡ്മിനിസ്ട്രേറ്റര്‍ അക്കൌണ്ട് ക്രമീകരണം അസാധുവാണ്: %v
install_success=സ്വാഗതം! ഗിറ്റീ തിരഞ്ഞെടുത്തതിന് നന്ദി. സൂക്ഷിക്കുക, ആസ്വദിക്കൂ,!
invalid_log_root_path=ലോഗ് പാത്ത് അസാധുവാണ്: %v
default_keep_email_private=സ്ഥിരസ്ഥിതിയായി ഇമെയില്‍ വിലാസങ്ങള്‍ മറയ്‌ക്കുക
default_keep_email_private_popup=സ്ഥിരസ്ഥിതിയായി പുതിയ ഉപയോക്തൃ അക്കൗണ്ടുകളുടെ ഇമെയില്‍ വിലാസങ്ങള്‍ മറയ്ക്കുക.
default_allow_create_organization=സ്ഥിരസ്ഥിതിയായി സംഘടനകള്‍ സൃഷ്ടിക്കാന്‍ അനുവദിക്കുക
default_allow_create_organization_popup=സ്ഥിരസ്ഥിതിയായി സംഘടനകള്‍ സൃഷ്ടിക്കാന്‍ പുതിയ ഉപയോക്തൃ അക്കൗണ്ടുകളെ അനുവദിക്കുക.
default_enable_timetracking=സ്ഥിരസ്ഥിതിയായി സമയം ട്രാക്കു് ചെയ്യുന്നതു പ്രാപ്തമാക്കുക
default_enable_timetracking_popup=സ്ഥിരസ്ഥിതിയായി പുതിയ കലവറകള്‍ക്കു് സമയം ട്രാക്കു് ചെയ്യുന്നതു് പ്രാപ്തമാക്കുക.
no_reply_address=മറച്ച ഇമെയിൽ ഡൊമെയ്ൻ
no_reply_address_helper=മറഞ്ഞിരിക്കുന്ന ഇമെയിൽ വിലാസമുള്ള ഉപയോക്താക്കൾക്കുള്ള ഡൊമെയ്ൻ നാമം. ഉദാഹരണത്തിന്, മറഞ്ഞിരിക്കുന്ന ഇമെയിൽ ഡൊമെയ്ൻ 'noreply.example.org' ആയി സജ്ജീകരിച്ചിട്ടുണ്ടെങ്കിൽ 'joe' എന്ന ഉപയോക്താവു് 'joe@noreply.example.org' ആയി ലോഗിൻ ചെയ്യും.
[home] [home]
uname_holder=ഉപയോക്തൃനാമമോ ഇമെയിൽ വിലാസമോ
password_holder=രഹസ്യവാക്കു്
switch_dashboard_context=ഡാഷ്‌ബോർഡ് സന്ദർഭം മാറ്റുക
my_repos=കലവറകള്‍
show_more_repos=കൂടുതൽ കലവറകള്‍ കാണിക്കുക…
collaborative_repos=സഹകരിക്കാവുന്ന കലവറകള്‍
my_orgs=എന്റെ സംഘടനകള്‍
my_mirrors=എന്റെ മിററുകള്‍
view_home=%s കാണുക
search_repos=ഒരു കലവറ കണ്ടെത്തുക…
issues.in_your_repos=നിങ്ങളുടെ കലവറകളില്‍
[explore] [explore]
repos=കലവറകള്‍
users=ഉപയോക്താക്കള്‍
organizations=സംഘടനകള്‍
search=തിരയുക
code=കോഡ്
repo_no_results=പൊരുത്തപ്പെടുന്ന കലവറകളൊന്നും കണ്ടെത്താനായില്ല.
user_no_results=പൊരുത്തപ്പെടുന്ന ഉപയോക്താക്കളെയൊന്നും കണ്ടെത്താനായില്ല.
org_no_results=പൊരുത്തപ്പെടുന്ന സംഘടനകളൊന്നും കണ്ടെത്താനായില്ല.
code_no_results=നിങ്ങളുടെ തിരയൽ പദവുമായി പൊരുത്തപ്പെടുന്ന സോഴ്സ് കോഡുകളൊന്നും കണ്ടെത്താനായില്ല.
code_search_results=%s എന്നതിനായുള്ള തിരയൽ ഫലങ്ങൾ
[auth] [auth]
create_new_account=അക്കൗണ്ട് രജിസ്റ്റർ ചെയ്യുക
register_helper_msg=ഇതിനകം ഒരു അക്കൗണ്ട് ഉണ്ടോ? ഇപ്പോൾ പ്രവേശിക്കുക!
social_register_helper_msg=ഇതിനകം ഒരു അക്കൗണ്ട് ഉണ്ടോ? ഇത് ഇപ്പോൾ ബന്ധിപ്പിയ്ക്കുക!
disable_register_prompt=രജിസ്ട്രേഷൻ അപ്രാപ്തമാക്കി. നിങ്ങളുടെ സൈറ്റ് അഡ്മിനിസ്ട്രേറ്ററുമായി ബന്ധപ്പെടുക.
disable_register_mail=രജിസ്ട്രേഷനായുള്ള ഇമെയിൽ സ്ഥിരീകരണം അപ്രാപ്തമാക്കി.
remember_me=ഓര്‍മ്മിയ്ക്കുക
forgot_password_title=അടയാളവാക്യം മറന്നുപോയോ
forgot_password=അടയാള വാക്ക് ഓർക്കുന്നില്ലേ?
sign_up_now=ഒരു അക്കൗണ്ട് ആവശ്യമുണ്ടോ? ഇപ്പോള്‍ രജിസ്റ്റര്‍ ചെയ്യുക.
sign_up_successful=അക്കൗണ്ട് വിജയകരമായി സൃഷ്ടിച്ചു.
confirmation_mail_sent_prompt=<b>%s</b> ലേക്ക് ഒരു പുതിയ സ്ഥിരീകരണ ഇമെയിൽ അയച്ചു. രജിസ്ട്രേഷൻ പ്രക്രിയ പൂർത്തിയാക്കുന്നതിന് അടുത്ത %s നുള്ളിൽ നിങ്ങളുടെ ഇൻ‌ബോക്സ് പരിശോധിക്കുക.
must_change_password=നിങ്ങളുടെ രഹസ്യവാക്കു് പുതുക്കുക
allow_password_change=രഹസ്യവാക്കു് മാറ്റാൻ ഉപയോക്താവിനോട് ആവശ്യപ്പെടുക (ശുപാർശിതം)
reset_password_mail_sent_prompt=<b>%s</b> ലേക്ക് ഒരു പുതിയ സ്ഥിരീകരണ ഇമെയിൽ അയച്ചു. അക്കൗണ്ട് വീണ്ടെടുക്കൽ പ്രക്രിയ പൂർത്തിയാക്കുന്നതിന് അടുത്ത %s നുള്ളിൽ നിങ്ങളുടെ ഇൻ‌ബോക്സ് പരിശോധിക്കുക.
active_your_account=നിങ്ങളുടെ അക്കൗണ്ട് സജീവമാക്കുക
account_activated=നിങ്ങളുടെ അക്കൗണ്ട് സജീവമാക്കി
prohibit_login=പ്രവേശനം നിരോധിച്ചിരിക്കുന്നു
prohibit_login_desc=നിങ്ങളുടെ അക്കൗണ്ടിലേയ്ക്കുള്ള പ്രവേശനം നിരോധിച്ചിരിക്കുന്നു, ദയവായി നിങ്ങളുടെ സൈറ്റ് അഡ്മിനിസ്ട്രേറ്ററുമായി ബന്ധപ്പെടുക.
resent_limit_prompt=നിങ്ങൾ അടുത്തിടെ ഒരു സജീവമാക്കൽ ഇമെയിൽ അഭ്യർത്ഥിച്ചു. 3 മിനിറ്റ് കാത്തിരുന്ന് വീണ്ടും ശ്രമിക്കുക.
has_unconfirmed_mail=ഹായ് %s, നിങ്ങൾക്ക് സ്ഥിരീകരിക്കാത്ത ഇമെയിൽ വിലാസം (<b>%s</b>) ഉണ്ട്. നിങ്ങൾക്ക് ഒരു സ്ഥിരീകരണ ഇമെയിൽ ലഭിച്ചില്ലെങ്കിലോ പുതിയതൊന്ന് വീണ്ടും അയയ്‌ക്കേണ്ടതുണ്ടെങ്കിലോ, ചുവടെയുള്ള ബട്ടണിൽ ക്ലിക്കുചെയ്യുക.
resend_mail=നിങ്ങളുടെ സജീവമാക്കൽ ഇമെയിൽ വീണ്ടും അയയ്‌ക്കാൻ ഇവിടെ ക്ലിക്കുചെയ്യുക
email_not_associate=ഇമെയിൽ വിലാസം ഏതെങ്കിലും അക്കൗണ്ടുമായി ബന്ധപ്പെടുത്തിയിട്ടില്ല.
send_reset_mail=അക്കൗണ്ട് വീണ്ടെടുക്കൽ ഇമെയിൽ അയയ്‌ക്കുക
reset_password=അക്കൗണ്ട് വീണ്ടെടുക്കൽ
invalid_code=നിങ്ങളുടെ സ്ഥിരീകരണ കോഡ് അസാധുവാണ് അല്ലെങ്കിൽ കാലഹരണപ്പെട്ടു.
reset_password_helper=അക്കൗണ്ട് വീണ്ടെടുക്കുക
reset_password_wrong_user=നിങ്ങൾ %s ആയി സൈൻ ഇൻ ചെയ്‌തു, പക്ഷേ അക്കൗണ്ട് വീണ്ടെടുക്കൽ ലിങ്ക് %s എന്നതിനാണ്
password_too_short=പാസ്‌വേഡ് ദൈർഘ്യം %d അക്ഷരങ്ങളിലും കുറവായിരിക്കരുത്.
non_local_account=പ്രാദേശിക ഇതര ഉപയോക്താക്കൾക്ക് ഗിറ്റീ വെബ് വഴി പാസ്‌വേഡ് പുതുക്കാന്‍ ചെയ്യാൻ കഴിയില്ല.
verify=പ്രമാണീകരിയ്ക്കുക
scratch_code=സ്ക്രാച്ച് കോഡ്
use_scratch_code=ഒരു സ്ക്രാച്ച് കോഡ് ഉപയോഗിക്കുക
twofa_scratch_used=നിങ്ങളുടെ സ്ക്രാച്ച് കോഡ് ഉപയോഗിച്ചു. നിങ്ങളെ രണ്ട്-ഘടക ക്രമീകരണ പേജിലേക്ക് റീഡയറക്‌ട് ചെയ്‌തിരിക്കുന്നതിനാൽ നിങ്ങളുടെ ഉപകരണ എൻറോൾമെന്റ് നീക്കംചെയ്യാനോ പുതിയ സ്‌ക്രാച്ച് കോഡ് സൃഷ്‌ടിക്കാനോ കഴിയും.
twofa_passcode_incorrect=നിങ്ങളുടെ പാസ്‌കോഡ് തെറ്റാണ്. നിങ്ങളുടെ ഉപകരണം തെറ്റായി സ്ഥാപിച്ചിട്ടുണ്ടെങ്കിൽ, പ്രവേശിക്കാൻ നിങ്ങളുടെ സ്ക്രാച്ച് കോഡ് ഉപയോഗിക്കുക.
twofa_scratch_token_incorrect=നിങ്ങളുടെ സ്ക്രാച്ച് കോഡ് തെറ്റാണ്.
login_userpass=പ്രവേശിക്കുക
login_openid=OpenID
oauth_signup_tab=പുതിയ അക്കൗണ്ട് രജിസ്റ്റർ ചെയ്യുക
oauth_signup_title=ഇമെയിലും പാസ്‌വേഡും ചേർക്കുക (അക്കൗണ്ട് വീണ്ടെടുക്കലിനായി)
oauth_signup_submit=അക്കൗണ്ട് പൂർത്തിയാക്കുക
oauth_signin_tab=നിലവിലുള്ള അക്കൌണ്ടുമായി ബന്ധിപ്പിയ്ക്കുക
oauth_signin_title=അക്കൗണ്ട് ബന്ധിപ്പിയ്ക്കുന്നതു് അംഗീകരിക്കുന്നതിനായി സൈറ്റിലേയ്ക്കു് പ്രവേശിക്കുക
oauth_signin_submit=അക്കൌണ്ട് ബന്ധിപ്പിയ്ക്കുക
openid_connect_submit=ബന്ധിപ്പിക്കുക
openid_connect_title=നിലവിലുള്ള അക്കൗണ്ടുമായി ബന്ധിപ്പിയ്ക്കുക
openid_connect_desc=തിരഞ്ഞെടുത്ത ഓപ്പൺഐഡി യുആർഐ അജ്ഞാതമാണ്. ഇവിടെ നിന്നും ഒരു പുതിയ അക്കൗണ്ടുമായി ബന്ധപ്പെടുത്തുക.
openid_register_title=അംഗത്വമെടുക്കുക
openid_register_desc=തിരഞ്ഞെടുത്ത ഓപ്പൺഐഡി യുആർഐ അജ്ഞാതമാണ്. ഇവിടെ നിന്നും ഒരു പുതിയ അക്കൗണ്ടുമായി ബന്ധപ്പെടുത്തുക.
openid_signin_desc=നിങ്ങളുടെ OpenID URI നൽകുക. ഉദാഹരണത്തിന്: https://anne.me, bob.openid.org.cn അല്ലെങ്കിൽ gnusocial.net/carry.
disable_forgot_password_mail=അക്കൗണ്ട് വീണ്ടെടുക്കൽ പ്രവർത്തനരഹിതമാണ്. നിങ്ങളുടെ സൈറ്റ് അഡ്മിനിസ്ട്രേറ്ററുമായി ബന്ധപ്പെടുക.
email_domain_blacklisted=നിങ്ങളുടെ ഇമെയിൽ വിലാസത്തിൽ രജിസ്റ്റർ ചെയ്യാൻ കഴിയില്ല.
authorize_application=അപ്ലിക്കേഷനു് അംഗീകാരം നല്കുക
authorize_application_created_by=%s സൃഷ്‌ടിച്ച അപ്ലിക്കേഷൻ ആണ്.
authorize_application_description=നിങ്ങൾ പ്രവേശനം അനുവദിക്കുകയാണെങ്കിൽ, സ്വകാര്യ റിപ്പോകളും ഓർഗനൈസേഷനുകളും ഉൾപ്പെടെ നിങ്ങളുടെ എല്ലാ അക്കൌണ്ട് വിവരങ്ങള്‍ നേടാനും വേണമെങ്കില്‍‍ മാറ്റങ്ങള്‍ വരുത്താനും അതിന് കഴിയും.
authorize_title=നിങ്ങളുടെ അക്കൌണ്ടില്‍ പ്രവേശിയ്ക്കുന്നതിനു് "%s"നു് അംഗീകാരം നൽകണോ?
authorization_failed=അംഗീകാരം നല്‍കുന്നതില്‍ പരാജയപ്പെട്ടു
authorization_failed_desc=അസാധുവായ ഒരു അഭ്യർത്ഥന കണ്ടെത്തിയതിനാൽ ഞങ്ങൾ അംഗീകാരം പരാജയപ്പെടുത്തി. ദയവായി നിങ്ങൾ അംഗീകരിക്കാൻ ശ്രമിച്ച അപ്ലിക്കേഷന്റെ പരിപാലകനുമായി ബന്ധപ്പെടുക.
[mail] [mail]
activate_account=നിങ്ങളുടെ അക്കൗണ്ട് സജീവമാക്കുക
activate_email=ഇമെയില്‍ വിലാസം സ്ഥിരീകരിയ്ക്കുക
reset_password=നിങ്ങളുടെ അക്കൗണ്ട് വീണ്ടെടുക്കുക
register_success=രജിസ്ട്രേഷൻ വിജയകരം
register_notify=ഗിറ്റീയിലേയ്ക്കു് സ്വാഗതം
[modal] [modal]
yes=അതെ
no=ഇല്ല
modify=പുതുക്കുക
[form] [form]
UserName=ഉപയോക്ത്രു നാമം
RepoName=കലവറയുടെ പേരു്
Email=ഇ-മെയില്‍ വിലാസം
Password=രഹസ്യവാക്കു്
Retype=രഹസ്യവാക്കു് വീണ്ടും നല്‍കുക
SSHTitle=SSH കീയുടെ പേരു്
HttpsUrl=HTTPS URL
PayloadUrl=പേലോഡ് URL
TeamName=ടീമിന്റെ പേരു്
AuthName=അംഗീകാരത്തിന്റെ പേരു്
AdminEmail=അഡ്‌മിൻ ഇമെയിൽ
NewBranchName=പുതിയ ശാഖയുടെ പേരു്
CommitSummary=നിയോഗത്തിന്റെ സംഗ്രഹം
CommitMessage=നിയോഗത്തിന്റെ സന്ദേശം
CommitChoice=നിയോഗത്തിന്റെ തിരഞ്ഞെടുക്കല്‍
TreeName=ഫയല്‍ പാത്ത്
Content=ഉള്ളടക്കം
require_error=`ശൂന്യമായിരിക്കരുത്.`
alpha_dash_error=`ആൽ‌ഫാന്യൂമെറിക്, ഡാഷ് ('-'), അടിവരയിട്ട ('_') എന്നീ ചിഹ്നങ്ങള്‍ മാത്രം അടങ്ങിയിരിക്കണം.`
alpha_dash_dot_error=`ആൽ‌ഫാന്യൂമെറിക്, ഡാഷ് ('-'), അടിവരയിടുക ('_'), ഡോട്ട് ('.') എന്നീ ച്ഹ്നങ്ങള്‍ മാത്രം അടങ്ങിയിരിക്കണം.`
git_ref_name_error=`നന്നായി രൂപപ്പെടുത്തിയ Git റഫറൻസ് നാമമായിരിക്കണം.`
size_error=`വലുപ്പം %s ആയിരിക്കണം.`
min_size_error=`കുറഞ്ഞത് %s അക്ഷരങ്ങള്‍ അടങ്ങിയിരിക്കണം.`
max_size_error=`പരമാവധി %s അക്ഷരങ്ങള്‍ അടങ്ങിയിരിക്കണം.`
email_error=സാധുവായ ഒരു ഈ-മെയിൽ വിലാസം അല്ല
url_error=`സാധുവായ ഒരു URL അല്ല.`
include_error=`%s'എന്ന ഉപവാക്യം അടങ്ങിയിരിക്കണം.`
glob_pattern_error=ഗ്ലോബു് ശൃേണി തെറ്റാണു്: %s
unknown_error=അജ്ഞാതമായ പിശക്:
captcha_incorrect=ക്യാപ്ച കോഡ് തെറ്റാണ്.
password_not_match=രഹസ്യവാക്കുകള്‍ യോജിക്കുന്നില്ല.
username_been_taken=ഉപയോക്തൃനാമം ലഭ്യമല്ല.
repo_name_been_taken=കലവറയുടെ പേരു് ഇതിനോടകം ഉപയോഗിച്ചിട്ടുണ്ടു്.
visit_rate_limit=വിദൂര വിലാസം വിവരകൈമാറ്റത്തിനു് പരിധി നിശ്ചയിച്ചിട്ടുണ്ടു്.
2fa_auth_required=വിദൂര വിലാസം ഇരട്ട ഘടക പ്രാമാണീകരണം ആവശ്യപ്പെടുന്നുണ്ടു്.
org_name_been_taken=സംഘടനയുടെ പേര് ഇതിനകം എടുത്തിട്ടുണ്ട്.
team_name_been_taken=ടീമിന്റെ പേര് ഇതിനകം എടുത്തിട്ടുണ്ട്.
team_no_units_error=കുറഞ്ഞത് ഒരു കലവറ വിഭാഗത്തിലേക്ക് പ്രവേശനം അനുവദിക്കുക.
email_been_used=ഈ ഇമെയിൽ വിലാസം ഇതിനു മുന്നേ എടുത്തിട്ടുണ്ട്.
openid_been_used=%s എന്ന ഓപ്പണ്‍ഐഡി വിലാസം ഇതിനു മുന്നേ എടുത്തിട്ടുണ്ട്.
username_password_incorrect=ഉപഭോക്തൃനാമമോ രഹസ്യവാക്കോ തെറ്റാണ്.
enterred_invalid_repo_name=ഈ കവവറയുടെ പേരു് തെറ്റാണു്.
enterred_invalid_owner_name=പുതിയ ഉടമസ്ഥന്റെ പേരു് സാധുവല്ല.
enterred_invalid_password=താങ്കള്‍ നല്‍കിയ രഹസ്യവാക്കു് തെറ്റാണ്.
user_not_exist=ഉപയോക്താവ് നിലവിലില്ല.
last_org_owner='ഉടമകളുടെ' ടീമിൽ നിന്നും അവസാനത്തെ ഉപയോക്താവിനെ നീക്കംചെയ്യാൻ നിങ്ങൾക്ക് കഴിയില്ല. ടീമിൽ കുറഞ്ഞത് ഒരു ഉടമയെങ്കിലും ഉണ്ടായിരിക്കണം.
cannot_add_org_to_team=ഒരു സംഘടനയെ ടീം അംഗമായി ചേർക്കാൻ കഴിയില്ല.
invalid_ssh_key=നിങ്ങളുടെ SSH കീ സ്ഥിരീകരിക്കാൻ കഴിയില്ല: %s
invalid_gpg_key=നിങ്ങളുടെ GPG കീ സ്ഥിരീകരിക്കാൻ കഴിയില്ല: %s
unable_verify_ssh_key=SSH കീ സ്ഥിരീകരിക്കാൻ കഴിയില്ല; തെറ്റുകളുണ്ടോയെന്നു് ഒന്നുകൂടി പരിശോധിക്കുക.
auth_failed=പ്രാമാണീകരണം പരാജയപ്പെട്ടു: %v
still_own_repo=നിങ്ങളുടെ അക്കൗണ്ടിന് ഒന്നോ അതിലധികമോ കലവറകള്‍ ഉണ്ട്; ആദ്യം അവ ഇല്ലാതാക്കുക അല്ലെങ്കിൽ കൈമാറുക.
still_has_org=നിങ്ങളുടെ അക്കൗണ്ട് ഒന്നോ അതിലധികമോ സംഘടനകളില്‍ അംഗമാണ്; ആദ്യം അവ വിടുക.
org_still_own_repo=നിങ്ങളുടെ സംഘടന ഇനിയും ഒന്നോ അതിലധികമോ കലവറകളുടെ ഉടമസ്ഥനാണു്; ആദ്യം അവ ഇല്ലാതാക്കുക അല്ലെങ്കിൽ കൈമാറുക.
target_branch_not_exist=ലക്ഷ്യമാക്കിയ ശാഖ നിലവിലില്ല.
[user] [user]
change_avatar=നിങ്ങളുടെ അവതാർ മാറ്റുക…
join_on=ചേർന്നതു്
repositories=കലവറകള്‍
activity=പൊതുവായ പ്രവർത്തനങ്ങള്‍
followers=പിന്തുടരുന്നവര്‍‌
starred=നക്ഷത്രമിട്ട കലവറകള്‍
following=പിന്തുടരുന്നവര്‍
follow=പിന്തുടരൂ
unfollow=പിന്തുടരുന്നത് നിര്‍ത്തുക
heatmap.loading=ഹീറ്റ്മാപ്പ് ലോഡുചെയ്യുന്നു…
user_bio=ജീവചരിത്രം
form.name_reserved='%s' എന്ന ഉപയോക്തൃനാമം മറ്റാവശ്യങ്ങള്‍ക്കായി നീക്കിവച്ചിരിക്കുന്നു.
form.name_pattern_not_allowed=ഉപയോക്തൃനാമത്തിൽ '%s' എന്ന ശ്രേണി അനുവദനീയമല്ല.
[settings] [settings]
profile=പ്രൊഫൈൽ
account=അക്കൗണ്ട്
password=രഹസ്യവാക്കു്
security=സുരക്ഷ
avatar=അവതാര്‍
ssh_gpg_keys=SSH / GPG കീകള്‍
social=സോഷ്യൽ അക്കൗണ്ടുകൾ
applications=അപ്ലിക്കേഷനുകൾ
orgs=സംഘടനകളെ നിയന്ത്രിക്കുക
repos=കലവറകള്‍
delete=അക്കൗണ്ട് ഇല്ലാതാക്കുക
twofa=ഇരട്ട ഘടക പ്രാമാണീകരണം
account_link=ബന്ധിപ്പിച്ച അക്കൌണ്ടുകള്‍
organization=സംഘടനകള്‍
uid=Uid
u2f=സുരക്ഷാ കീകൾ
public_profile=പരസ്യമായ പ്രൊഫൈൽ
profile_desc=അറിയിപ്പുകൾക്കും മറ്റ് പ്രവർത്തനങ്ങൾക്കുമായി നിങ്ങളുടെ ഇമെയിൽ വിലാസം ഉപയോഗിക്കും.
password_username_disabled=പ്രാദേശികമല്ലാത്ത ഉപയോക്താക്കൾക്ക് അവരുടെ ഉപയോക്തൃനാമം മാറ്റാൻ അനുവാദമില്ല. കൂടുതൽ വിവരങ്ങൾക്ക് നിങ്ങളുടെ സൈറ്റ് അഡ്മിനിസ്ട്രേറ്ററുമായി ബന്ധപ്പെടുക.
full_name=പൂർണ്ണമായ പേര്
website=വെബ് സൈറ്റ്
location=സ്ഥലം
update_theme=പ്രമേയം പുതുക്കുക
update_profile=പ്രോഫൈല്‍ പരിഷ്കരിക്കുക
update_profile_success=നിങ്ങളുടെ പ്രൊഫൈൽ പരിഷ്കരിച്ചിരിക്കുന്നു.
change_username=നിങ്ങളുടെ ഉപയോക്തൃനാമം മാറ്റി.
change_username_prompt=കുറിപ്പ്: ഉപയോക്തൃനാമത്തിലെ മാറ്റം നിങ്ങളുടെ അക്കൗണ്ട് URLഉ മാറ്റുന്നു.
continue=തുടരുക
cancel=റദ്ദാക്കുക
language=ഭാഷ
ui=പ്രമേയങ്ങള്‍
lookup_avatar_by_mail=ഇമെയിൽ വിലാസം അനുസരിച്ച് അവതാർ കണ്ടെത്തുക
federated_avatar_lookup=കേന്ദ്രീക്രത അവതാര്‍ കണ്ടെത്തല്‍
enable_custom_avatar=ഇഷ്‌ടാനുസൃത അവതാർ ഉപയോഗിക്കുക
choose_new_avatar=പുതിയ അവതാർ തിരഞ്ഞെടുക്കുക
update_avatar=അവതാർ പുതുക്കുക
delete_current_avatar=നിലവിലെ അവതാർ ഇല്ലാതാക്കുക
uploaded_avatar_not_a_image=അപ്‌ലോഡുചെയ്‌ത ഫയൽ ഒരു ചിത്രമല്ല.
uploaded_avatar_is_too_big=അപ്‌ലോഡുചെയ്‌ത ഫയൽ പരമാവധി വലുപ്പം കവിഞ്ഞു.
update_avatar_success=നിങ്ങളുടെ അവതാര്‍ പരിഷ്കരിച്ചിരിക്കുന്നു.
change_password=പാസ്‌വേഡ് പുതുക്കുക
old_password=നിലവിലുള്ള രഹസ്യവാക്കു്
new_password=പുതിയ രഹസ്യവാക്കു്
retype_new_password=പുതിയ രഹസ്യവാക്കു് വീണ്ടും നല്‍കുക
password_incorrect=നിലവിലെ പാസ്‌വേഡ് തെറ്റാണ്.
change_password_success=നിങ്ങളുടെ പാസ്‌വേഡ് അപ്‌ഡേറ്റുചെയ്‌തു. ഇനി മുതൽ നിങ്ങളുടെ പുതിയ പാസ്‌വേഡ് ഉപയോഗിച്ച് പ്രവേശിക്കുക.
password_change_disabled=പ്രാദേശിക ഇതര ഉപയോക്താക്കൾക്ക് ഗിറ്റീ വെബ് വഴി പാസ്‌വേഡ് പുതുക്കാന്‍ ചെയ്യാൻ കഴിയില്ല.
emails=ഇ-മെയില്‍ വിലാസങ്ങള്‍
manage_emails=ഇമെയിൽ വിലാസങ്ങൾ നിയന്ത്രിക്കുക
manage_themes=സ്ഥിരസ്ഥിതി പ്രമേയം തിരഞ്ഞെടുക്കുക
manage_openid=ഓപ്പൺഐഡി വിലാസങ്ങൾ നിയന്ത്രിക്കുക
email_desc=അറിയിപ്പുകൾക്കും മറ്റ് പ്രവർത്തനങ്ങൾക്കുമായി നിങ്ങളുടെ പ്രാഥമിക ഇമെയിൽ വിലാസം ഉപയോഗിക്കും.
theme_desc=സൈറ്റിലുടനീളം ഇത് നിങ്ങളുടെ സ്ഥിരസ്ഥിതി പ്രമേയം ആയിരിക്കും.
primary=പ്രാഥമികം
primary_email=പ്രാഥമികമാക്കുക
delete_email=നീക്കം ചെയ്യുക
email_deletion=ഈ-മെയില്‍ വിലാസം നീക്കം ചെയ്യുക
email_deletion_desc=ഇമെയിൽ വിലാസവും അനുബന്ധ വിവരങ്ങളും നിങ്ങളുടെ അക്കൗണ്ടിൽ നിന്ന് നീക്കംചെയ്യും. ഈ ഇമെയിൽ വിലാസം വഴിയുള്ള ഗിറ്റു് നിയോഗങ്ങളും മാറ്റമില്ലാതെ ഉണ്ടാകും. തുടരട്ടെ?
email_deletion_success=ഇമെയിൽ വിലാസം നീക്കംചെയ്‌തു.
theme_update_success=നിങ്ങളുടെ പ്രമേയം പുതുക്കി.
theme_update_error=തിരഞ്ഞെടുത്ത പ്രമേയം നിലവിലില്ല.
openid_deletion=OpenID വിലാസം നീക്കം ചെയ്യുക
openid_deletion_desc=നിങ്ങളുടെ അക്കൗണ്ടിൽ നിന്ന് ഓപ്പൺഐഡി വിലാസം നീക്കംചെയ്യുന്നത് ഇതുപയോഗിച്ചു് ഇനി പ്രവേശിക്കുന്നതിൽ നിന്ന് നിങ്ങളെ തടയും. തുടരട്ടെ?
openid_deletion_success=ഓപ്പൺഐഡി വിലാസം നീക്കംചെയ്‌തു.
add_new_email=ഈ-മെയില്‍ വിലാസം ചേര്‍ക്കുക
add_new_openid=പുതിയ ഓപ്പണ്‍ ഐഡി വിലാസം ചേര്‍ക്കുക
add_email=ഈ-മെയില്‍ വിലാസം ചേര്‍ക്കുക
add_openid=ഓപ്പണ്‍ ഐഡി വിലാസം ചേര്‍ക്കുക
add_email_confirmation_sent=ഒരു സ്ഥിരീകരണ ഇമെയിൽ '%s' ലേക്ക് അയച്ചു. നിങ്ങളുടെ ഇമെയിൽ വിലാസം സ്ഥിരീകരിക്കുന്നതിന് അടുത്ത %s നുള്ളിൽ നിങ്ങളുടെ ഇൻ‌ബോക്സ് പരിശോധിക്കുക.
add_email_success=പുതിയ ഇമെയിൽ വിലാസം ചേര്‍ത്തു.
add_openid_success=പുതിയ ഓപ്പണ്‍ഐഡി വിലാസം ചേര്‍ത്തു.
keep_email_private=ഈ-മെയില്‍ വിലാസം മറയ്ക്കുക
keep_email_private_popup=നിങ്ങളുടെ ഇമെയിൽ വിലാസം മറ്റ് ഉപയോക്താക്കു് കാണാനാകില്ല.
openid_desc=ഒരു ബാഹ്യ ദാതാവിന് പ്രാമാണീകരണം നിയുക്തമാക്കാൻ ഓപ്പൺഐഡി നിങ്ങളെ അനുവദിക്കുന്നു.
manage_ssh_keys=​എസ്. എസ്. എച്ച് കീകള്‍ നിയന്ത്രിക്കുക
manage_gpg_keys=ജീ പീ. ജി കീകള്‍ നിയന്ത്രിക്കുക
add_key=കീ ചേര്‍ക്കുക
ssh_desc=ഇവയാണു് നിങ്ങളുടെ അക്കൗണ്ടുമായി ബന്ധപ്പെടുത്തിയിരിക്കുന്ന പൊതുവായ എസ്. എസ്. എച്ച് കീകൾ. ഇതിനോടനു ബന്ധിപ്പിച്ചിട്ടുള്ള സ്വകാര്യ കീകൾ നിങ്ങളുടെ കലവറകളിലേയ്ക്കു് പൂർണ്ണ ആക്സസ് അനുവദിക്കുന്നു.
gpg_desc=ഈ പൊതു GPG കീകൾ നിങ്ങളുടെ അക്കൗണ്ടുമായി ബന്ധപ്പെട്ടിരിക്കുന്നു. കമ്മിറ്റുകളെ പരിശോധിച്ചുറപ്പിക്കാൻ നിങ്ങളുടെ സ്വകാര്യ കീകൾ അനുവദിക്കുന്നതിനാൽ അവ സുരക്ഷിതമായി സൂക്ഷിക്കുക.
ssh_helper=<strong>സഹായം ആവശ്യമുണ്ടോ?</strong> <a href="%s"> നിങ്ങളുടെ സ്വന്തം SSH കീകൾ സൃഷ്ടിക്കുക,</a> അല്ലെങ്കിൽ <a href="%s"> പൊതുവായ പ്രശ്നങ്ങൾ </a> എന്നിവയ്ക്കായുള്ള ഗിറ്റ്ഹബ്ബിന്റെ മാര്‍ഗദര്‍ശനങ്ങള്‍ ഉപയോഗിച്ചു് നിങ്ങൾക്ക് എസ്. എസ്. എച്ചുമായി ബന്ധപ്പെട്ട പ്രശ്നങ്ങള്‍ പരിഹരിക്കാം.
gpg_helper=<strong> സഹായം ആവശ്യമുണ്ടോ? </strong> ജിപിജിയെക്കുറിച്ച് ഗിറ്റ്ഹബിന്റെ മാര്‍ഗ്ഗനിര്‍ദ്ദേശങ്ങള്‍ <a href="%s"> പരിശോധിയ്ക്കുക</a>.
add_new_key=SSH കീ ചേർക്കുക
add_new_gpg_key=GPG കീ ചേർക്കുക
ssh_key_been_used=ഈ SSH കീ ഇതിനകം ചേർത്തു.
ssh_key_name_used=ഇതേ പേരിലുള്ള ഒരു SSH കീ ഇതിനകം നിങ്ങളുടെ അക്കൗണ്ടിലേക്ക് ചേർത്തിട്ടുണ്ടു്.
gpg_key_id_used=സമാന ഐഡിയുള്ള ഒരു പൊതു ജിപിജി കീ ഇതിനകം നിലവിലുണ്ട്.
gpg_no_key_email_found=നിങ്ങളുടെ അക്കൗണ്ടുമായി ബന്ധപ്പെട്ട ഏതെങ്കിലും ഇമെയിൽ വിലാസത്തിൽ ഈ GPG കീ ഉപയോഗിക്കാൻ കഴിയില്ല.
subkeys=സബ് കീകള്‍
key_id=കീ ഐഡി
key_name=കീയുടെ പേരു്
key_content=ഉള്ളടക്കം
add_key_success='%s' എന്ന SSH കീ ചേർത്തു.
add_gpg_key_success='%s' എന്ന GPG കീ ചേർത്തു.
delete_key=നീക്കം ചെയ്യുക
ssh_key_deletion=SSH കീ നീക്കം ചെയ്യുക
gpg_key_deletion=GPG കീ നീക്കം ചെയ്യുക
ssh_key_deletion_desc=ഒരു SSH കീ നീക്കംചെയ്യുന്നത് നിങ്ങളുടെ അക്കൌണ്ടിലേക്കുള്ള പ്രവേശനം അസാധുവാക്കുന്നു. തുടരട്ടെ?
gpg_key_deletion_desc=ഒരു ജി‌പി‌ജി കീ നീക്കംചെയ്യുന്നത് അതിൽ ഒപ്പിട്ട കമ്മിറ്റുകളെ സ്ഥിരീകരിക്കില്ല. തുടരട്ടെ?
ssh_key_deletion_success=SSH കീ നീക്കംചെയ്‌തു.
gpg_key_deletion_success=GPG കീ നീക്കംചെയ്‌തു.
add_on=ചേര്‍ത്തതു്
valid_until=വരെ സാധുവാണ്
valid_forever=എന്നും സാധുവാണു്
last_used=അവസാനം ഉപയോഗിച്ചത്
no_activity=സമീപകാലത്തു് പ്രവർത്തനങ്ങളൊന്നുമില്ല
can_read_info=വായിയ്ക്കുക
can_write_info=എഴുതുക
key_state_desc=കഴിഞ്ഞ 7 ദിവസങ്ങളിൽ ഈ കീ ഉപയോഗിച്ചു
token_state_desc=ഈ ടോക്കൺ കഴിഞ്ഞ 7 ദിവസങ്ങളിൽ ഉപയോഗിച്ചു
show_openid=പ്രൊഫൈലിൽ കാണുക
hide_openid=പ്രൊഫൈലിൽ നിന്ന് മറയ്‌ക്കുക
ssh_disabled=SSH അപ്രാപ്‌തമാക്കി
manage_social=സഹവസിക്കുന്ന സോഷ്യൽ അക്കൗണ്ടുകളെ നിയന്ത്രിക്കുക
social_desc=ഈ സോഷ്യൽ അക്കൗണ്ടുകൾ നിങ്ങളുടെ ഗിറ്റീ അക്കൗണ്ടുമായി ലിങ്കുചെയ്‌തു. ഇവ നിങ്ങളുടെ ഗീറ്റീ അക്കൗണ്ടിലേക്ക് പ്രവേശിക്കാൻ ഉപയോഗിക്കാവുന്നതിനാൽ അവയെല്ലാം നിങ്ങൾ തിരിച്ചറിഞ്ഞുവെന്ന് ഉറപ്പാക്കുക.
unbind=അൺലിങ്ക് ചെയ്യുക
unbind_success=നിങ്ങളുടെ ഗീറ്റീ അക്കൗണ്ടിൽ നിന്ന് സോഷ്യൽ അക്കൗണ്ട് അൺലിങ്ക് ചെയ്തു.
manage_access_token=ആക്‌സസ്സ് ടോക്കണുകൾ നിയന്ത്രിക്കുക
generate_new_token=പുതിയ ടോക്കൺ സൃഷ്‌ടിക്കുക
tokens_desc=ഈ ടോക്കണുകൾ ഗിറ്റീ API ഉപയോഗിച്ച് നിങ്ങളുടെ അക്കൌണ്ടിലേക്ക് പ്രവേശനം നൽകുന്നു.
new_token_desc=ഒരു ടോക്കൺ ഉപയോഗിക്കുന്ന അപ്ലിക്കേഷനുകൾക്ക് നിങ്ങളുടെ അക്കൌണ്ടിലേക്ക് പൂർണ്ണ പ്രവേശനം ഉണ്ട്.
token_name=ടോക്കണിന്റെ പേരു്
generate_token=ടോക്കൺ സൃഷ്‌ടിക്കുക
generate_token_success=നിങ്ങളുടെ പുതിയ ടോക്കൺ ജനറേറ്റുചെയ്‌തു. ഇത് വീണ്ടും കാണിക്കാത്തതിനാൽ ഇപ്പോൾ തന്നെ പകർത്തുക.
delete_token=നീക്കം ചെയ്യുക
access_token_deletion=ആക്‌സസ്സ് ടോക്കണ്‍ നീക്കം ചെയ്യുക
access_token_deletion_desc=ഒരു ടോക്കൺ ഇല്ലാതാക്കുന്നത് നിങ്ങളുടെ അക്കൗണ്ട് ഉപയോഗിക്കുന്ന അപ്ലിക്കേഷനുകൾക്കുള്ള പ്രവേശനം അസാധുവാക്കും. തുടരട്ടേ?
delete_token_success=ടോക്കൺ ഇല്ലാതാക്കി. ഇനി ഇത് ഉപയോഗിക്കുന്ന അപ്ലിക്കേഷനുകൾക്ക് നിങ്ങളുടെ അക്കൌണ്ടിലേക്ക് പ്രവേശനം ഉണ്ടാകില്ല.
manage_oauth2_applications=OAuth2 അപ്ലിക്കേഷനുകൾ നിയന്ത്രിക്കുക
edit_oauth2_application=OAuth2 അപ്ലിക്കേഷൻ എഡിറ്റുചെയ്യുക
oauth2_applications_desc=നിങ്ങളുടെ മൂന്നാം കക്ഷി അപ്ലിക്കേഷനെ, ഈ ഗിറ്റീ ഇന്‍സ്റ്റാളേഷനുമായി സുരക്ഷിതമായി ഉപയോക്താക്കളെ പ്രാമാണീകരിക്കാൻ OAuth2 അപ്ലിക്കേഷനുകൾ പ്രാപ്തമാക്കുന്നു.
remove_oauth2_application=OAuth2 അപ്ലിക്കേഷനുകൾ നീക്കംചെയ്യുക
remove_oauth2_application_desc=ഒരു OAuth2 അപ്ലിക്കേഷൻ നീക്കംചെയ്യുന്നത് ഒപ്പിട്ട എല്ലാ ആക്സസ് ടോക്കണുകളിലേക്കും പ്രവേശനം റദ്ദാക്കും. തുടരട്ടെ?
remove_oauth2_application_success=അപ്ലിക്കേഷൻ ഇല്ലാതാക്കി.
create_oauth2_application=ഒരു പുതിയ OAuth2 അപ്ലിക്കേഷൻ സൃഷ്ടിക്കുക
create_oauth2_application_button=അപ്ലിക്കേഷൻ സൃഷ്ടിക്കുക
create_oauth2_application_success=നിങ്ങൾ വിജയകരമായി ഒരു പുതിയ OAuth2 അപ്ലിക്കേഷൻ സൃഷ്ടിച്ചു.
update_oauth2_application_success=നിങ്ങൾ വിജയകരമായി ഒരു പുതിയ OAuth2 അപ്ലിക്കേഷൻ പുതുക്കി.
oauth2_application_name=അപ്ലിക്കേഷന്റെ പേര്
oauth2_select_type=ഏത് തരം അപ്ലിക്കേഷനാണ് ഇതു്?
oauth2_type_web=വെബ് (e.g. Node.JS, Tomcat, Go)
oauth2_type_native=നേറ്റീവ് (ഉദാ. മൊബൈൽ, ഡെസ്ക്ടോപ്പ്, ബ്രൌസർ)
oauth2_redirect_uri=URI റീഡയറക്‌ട് ചെയ്യുക
save_application=സംരക്ഷിയ്ക്കുക
oauth2_client_id=ക്ലൈന്റ് ഐഡി
oauth2_client_secret=ക്ലൈന്റു് രഹസ്യം
oauth2_regenerate_secret=രഹസ്യം പുനഃസൃഷ്ടിയ്ക്കുക
oauth2_regenerate_secret_hint=നിങ്ങളുടെ രഹസ്യം നഷ്ടപ്പെട്ടോ?
oauth2_client_secret_hint=നിങ്ങൾ ഈ പേജ് വീണ്ടും സന്ദർശിക്കുകയാണെങ്കിൽ രഹസ്യം ദൃശ്യമാകില്ല. നിങ്ങളുടെ രഹസ്യം സംരക്ഷിക്കുക.
oauth2_application_edit=ക്രമീകരിക്കുക
oauth2_application_create_description=OAuth2 ആപ്ലിക്കേഷനുകൾ നിങ്ങളുടെ മൂന്നാം കക്ഷി ആപ്ലിക്കേഷൻ ഉപയോക്തൃ അക്കൌണ്ടുകളിലേക്ക് ആക്സസ് നൽകുന്നു.
oauth2_application_remove_description=ഒരു OAuth2 ആപ്ലിക്കേഷൻ നീക്കംചെയ്യുന്നത് ഈ സന്ദർഭത്തിൽ അംഗീകൃത ഉപയോക്തൃ അക്കൌണ്ടുകളിലേക്ക് പ്രവേശിക്കുന്നത് തടയും. തുടരട്ടെ?
authorized_oauth2_applications=അംഗീകൃത OAuth2 അപ്ലിക്കേഷനുകൾ
authorized_oauth2_applications_description=ഈ മൂന്നാം കക്ഷി അപ്ലിക്കേഷനുകളിലേക്ക് നിങ്ങളുടെ സ്വകാര്യ ഗീറ്റീ അക്കൗണ്ടിലേക്ക് പ്രവേശനം അനുവദിച്ചു. അപ്ലിക്കേഷനുകൾക്കായുള്ള നിയന്ത്രണം ഇനി ആവശ്യമില്ല.
revoke_key=അസാധുവാക്കുക
revoke_oauth2_grant=നിയന്ത്രണം തിരിച്ചെടുക്കുക
revoke_oauth2_grant_description=ഈ മൂന്നാം കക്ഷി ആപ്ലിക്കേഷനായി ആക്സസ് അസാധുവാക്കുന്നത് നിങ്ങളുടെ ഡാറ്റ ആക്സസ് ചെയ്യുന്നതിൽ നിന്ന് ഈ ആപ്ലിക്കേഷനെ തടയും. നിങ്ങള്‍ക്ക് ഉറപ്പാണോ?
revoke_oauth2_grant_success=നിങ്ങൾ വിജയകരമായി പ്രവേശനം റദ്ദാക്കി.
twofa_desc=ഇരട്ട ഘടക പ്രാമാണീകരണം നിങ്ങളുടെ അക്കൗണ്ടിന്റെ സുരക്ഷ വർദ്ധിപ്പിക്കുന്നു.
twofa_is_enrolled=നിങ്ങളുടെ അക്കൗണ്ട് നിലവിൽ ഇരട്ട ഘടക പ്രമാണീകരണത്തിനു് <strong> എൻറോൾ ചെയ്തിട്ടുണ്ട്. </strong>.
twofa_not_enrolled=നിങ്ങളുടെ അക്കൗണ്ട് നിലവിൽ ഇരട്ട ഘടക പ്രമാണീകരണത്തിനു് <strong> എൻറോൾ ചെയ്തിട്ടില്ല.</strong>.
twofa_disable=ഇരട്ട ഘടക പ്രാമാണീകരണം റദ്ദാക്കി
twofa_scratch_token_regenerate=സ്ക്രാച്ച് ടോക്കൺ പുനഃനിര്‍മ്മിയ്ക്കുക
twofa_scratch_token_regenerated=%s ആണ് ഇപ്പോൾ നിങ്ങളുടെ സ്ക്രാച്ച് ടോക്കൺ. സുരക്ഷിതമായ സ്ഥലത്ത് സൂക്ഷിക്കുക.
twofa_enroll=ഇരട്ട ഘടക പ്രാമാണീകരണത്തില്‍ അംഗമാകുക
twofa_disable_note=ആവശ്യമെങ്കിൽ നിങ്ങൾക്ക് രണ്ട്-ഘടക പ്രാമാണീകരണം അപ്രാപ്തമാക്കാൻ കഴിയും.
twofa_disable_desc=രണ്ട്-ഘടക പ്രാമാണീകരണം അപ്രാപ്‌തമാക്കുന്നത് നിങ്ങളുടെ അക്കൗണ്ട് സുരക്ഷിതമല്ലാത്തതാക്കും. തുടരട്ടെ?
regenerate_scratch_token_desc=നിങ്ങളുടെ സ്ക്രാച്ച് ടോക്കൺ തെറ്റായി സ്ഥാപിക്കുകയോ അല്ലെങ്കിൽ സൈൻ ഇൻ ചെയ്യാൻ ഇതിനകം ഉപയോഗിക്കുകയോ ചെയ്തിട്ടുണ്ടെങ്കിൽ അത് ഇവിടെനിന്നു് പുനഃസജ്ജമാക്കാൻ കഴിയും.
twofa_disabled=രണ്ട്-ഘട്ട പ്രാമാണീകരണം അപ്രാപ്‌തമാക്കി.
scan_this_image=നിങ്ങളുടെ പ്രാമാണീകരണ ആപ്ലിക്കേഷൻ ഉപയോഗിച്ച് ഈ ചിത്രം സൂക്ഷ്‌മപരിശോധന നടത്തുക:
or_enter_secret=അല്ലെങ്കിൽ രഹസ്യ കോഡ് നൽകുക: %s
then_enter_passcode=അപ്ലിക്കേഷനിൽ കാണിച്ചിരിക്കുന്ന പാസ്‌കോഡ് നൽകുക:
passcode_invalid=പാസ്‌കോഡ് തെറ്റാണ്. വീണ്ടും ശ്രമിക്കുക.
twofa_enrolled=നിങ്ങളുടെ അക്കൌണ്ട് രണ്ട്-ഘട്ട പ്രാമാണീകരണത്തിലേക്ക് ചേർത്തിട്ടുണ്ട്. നിങ്ങളുടെ സ്ക്രാച്ച് ടോക്കൺ (%s) ഒരു തവണ മാത്രം കാണിക്കുന്നതിനാൽ അതു് സുരക്ഷിതമായ സ്ഥലത്ത് സൂക്ഷിക്കുക!
u2f_desc=ക്രിപ്‌റ്റോഗ്രാഫിക് കീകൾ അടങ്ങിയ ഹാർഡ്‌വെയർ ഉപകരണങ്ങളാണ് സുരക്ഷാ കീകൾ. രണ്ട്-ഘട്ട പ്രാമാണീകരണത്തിനായി അവ ഉപയോഗിക്കാം. പക്ഷേ സുരക്ഷാ കീകൾ <a rel="noreferrer" href="https://fidoalliance.org/"> FIDO U2F </a> സ്റ്റാൻഡേർഡിനെ പിന്തുണയ്‌ക്കുന്നവയാകണം.
u2f_require_twofa=സുരക്ഷാ കീകൾ‌ ഉപയോഗിക്കുന്നതിന് നിങ്ങളുടെ അക്കൌണ്ട് രണ്ട്-ഘട്ട പ്രാമാണീകരണത്തിൽ‌ ചേർ‌ത്തിരിക്കണം.
u2f_register_key=സുരക്ഷാ കീ ചേർക്കുക
u2f_nickname=വിളിപ്പേരു്
u2f_press_button=രജിസ്റ്റർ ചെയ്യുന്നതിന് നിങ്ങളുടെ സുരക്ഷാ കീയിലെ ബട്ടൺ അമർത്തുക.
u2f_delete_key=സുരക്ഷാ കീ നീക്കംചെയ്യുക
u2f_delete_key_desc=നിങ്ങൾ ഒരു സുരക്ഷാ കീ നീക്കംചെയ്യുകയാണെങ്കിൽ, നിങ്ങൾക്ക് ഇത് ഉപയോഗിച്ച് പ്രവേശിയ്ക്കാന്‍ കഴിയില്ല. തുടരട്ടെ?
manage_account_links=ബന്ധിപ്പിച്ചിട്ടുള്ള അക്കൗണ്ടുകൾ നിയന്ത്രിക്കുക
manage_account_links_desc=ഈ ബാഹ്യ അക്കൗണ്ടുകൾ നിങ്ങളുടെ ഗിറ്റീ അക്കൗണ്ടുമായി ലിങ്കുചെയ്‌തു.
account_links_not_available=നിങ്ങളുടെ ഗിറ്റീ അക്കൌണ്ടുമായി നിലവിൽ മറ്റു് ബാഹ്യ അക്കൌണ്ടുകളൊന്നും ബന്ധിപ്പിച്ചിട്ടില്ല.
remove_account_link=ബന്ധിപ്പിച്ച അക്കൗണ്ട് നീക്കംചെയ്യുക
remove_account_link_desc=ഒരു ബന്ധിപ്പിച്ച അക്കൗണ്ട് നീക്കംചെയ്യുന്നത് നിങ്ങളുടെ ഗിറ്റീ അക്കൗണ്ടിലേക്കുള്ള പ്രവേശനം അസാധുവാക്കും. തുടരട്ടെ?
remove_account_link_success=ബന്ധിപ്പിച്ച അക്കൗണ്ട് നീക്കംചെയ്‌തു.
orgs_none=നിങ്ങൾ ഏതെങ്കിലും സംഘടനയില്‍ അംഗമല്ല.
repos_none=നിങ്ങൾക്ക് ഒരു കലവറയും സ്വന്തമായി ഇല്ല
delete_account=അക്കൗണ്ട് ഇല്ലാതാക്കുക
delete_prompt=ഈ പ്രവർത്തനം നിങ്ങളുടെ ഉപയോക്തൃ അക്കൗണ്ട് ശാശ്വതമായി ഇല്ലാതാക്കും. ഇത് <strong> പൂർ‌വ്വാവസ്ഥയിലാക്കാൻ‌ കഴിയില്ല.</strong>.
confirm_delete_account=ഇല്ലാതാക്കൽ സ്ഥിരീകരിക്കുക
delete_account_title=ഉപയോക്തൃ അക്കൗണ്ട് ഇല്ലാതാക്കുക
delete_account_desc=ഈ ഉപയോക്തൃ അക്കൗണ്ട് ശാശ്വതമായി ഇല്ലാതാക്കാൻ നിങ്ങൾ ആഗ്രഹിക്കുന്നുണ്ടോ?
email_notifications.enable=ഇമെയിൽ അറിയിപ്പുകൾ പ്രാപ്തമാക്കുക
email_notifications.onmention=ഇ-മെയിൽ പരാമര്‍ശിച്ചാൽ മാത്രം അയയ്ക്കുക
email_notifications.disable=ഇമെയിൽ അറിയിപ്പുകൾ അപ്രാപ്തമാക്കുക
email_notifications.submit=ഇ-മെയില്‍ മുൻഗണനകള്‍
[repo] [repo]
owner=ഉടമസ്ഥന്‍
repo_name=കലവറയുടെ പേരു്
repo_name_helper=നല്ല കലവറയുടെ പേരു് ഹ്രസ്വവും അവിസ്മരണീയവും അതുല്യവുമായ കീവേഡുകൾ ഉപയോഗിക്കുന്നു.
visibility=കാണാനാവുന്നതു്
visibility_description=ഉടമയ്‌ക്കോ ഓർഗനൈസേഷൻ അംഗങ്ങൾക്കോ അവകാശങ്ങളുണ്ടെങ്കിൽ മാത്രമേ കാണാൻ കഴിയൂ.
visibility_helper=കലവറ സ്വകാര്യമാക്കുക
visibility_helper_forced=നിങ്ങളുടെ സൈറ്റ് അഡ്മിനിസ്ട്രേറ്റർ പുതിയ കലവറകളെ സ്വകാര്യമാക്കാൻ നിർബന്ധിക്കുന്നു.
visibility_fork_helper=(മാറ്റം എല്ലാ ഫോർക്കുകളെയും ബാധിക്കും.)
clone_helper=ക്ലോണ്‍ ചെയ്യാന്‍ സഹായം വേണോ? <a target="_blank" rel="noopener noreferrer" href="%s">സഹായം</a> സന്ദര്‍ശിക്കുക.
fork_repo=കലവറ ഫോര്‍ക്കു് ചെയ്യുക
fork_from=ല്‍ നിന്നും ഫോര്‍ക്കു് ചെയ്യൂ
fork_visibility_helper=ഒരു കലവറയുടെ ഫോര്‍ക്കിന്റെ ദൃശ്യപരത മാറ്റാൻ കഴിയില്ല.
repo_desc=വിരരണം
repo_lang=ഭാഷ
repo_gitignore_helper=.gitignore ടെംപ്ലേറ്റുകൾ തിരഞ്ഞെടുക്കുക.
license=ലൈസൻസ്
license_helper=ഒരു ലൈസൻസ് ഫയൽ തിരഞ്ഞെടുക്കുക.
readme=റീഡ്‍മീ
readme_helper=ഒരു റീഡ്‍മീ ഫയൽ ടെംപ്ലേറ്റ് തിരഞ്ഞെടുക്കുക.
auto_init=കലവറ സമാരംഭിക്കുക (.gitignore, ലൈസൻസ്, റീഡ്‍മീ എന്നിവ ചേർക്കുന്നു)
create_repo=കലവറ സൃഷ്ടിക്കുക
default_branch=സ്ഥിരസ്ഥിതി ശാഖ
mirror_prune=വെട്ടിഒതുക്കുക
mirror_prune_desc=കാലഹരണപ്പെട്ട വിദൂര ട്രാക്കിംഗ് റഫറൻസുകൾ നീക്കംചെയ്യുക
mirror_interval=മിറർ ചെയ്യാനുള്ള ഇടവേള (സാധുവായ സമയ യൂണിറ്റുകൾ 'h', 'm', 's' എന്നിവയാണ്). യാന്ത്രിക സമന്വയം പ്രവർത്തനരഹിതമാക്കാൻ 0 നല്‍കുക.
mirror_interval_invalid=മിറർ ചെയ്യാനുള്ള ഇടവേള സാധുവല്ല.
mirror_address=URL- ൽ നിന്നുള്ള ക്ലോൺ
mirror_address_url_invalid=നൽകിയ url അസാധുവാണ്. നിങ്ങൾ url- ന്റെ എല്ലാ ഘടകങ്ങളും ശരിയായി നല്‍കണം.
mirror_address_protocol_invalid=നൽകിയ url അസാധുവാണ്. http(s):// അല്ലെങ്കിൽ git:// ലൊക്കേഷനുകൾ മാത്രമേ മിറർ ചെയ്യാൻ കഴിയൂ.
mirror_last_synced=അവസാനം സമന്വയിപ്പിച്ചതു്
watchers=നിരീക്ഷകർ
stargazers=സ്റ്റാർഗാസറുകൾ
forks=ശാഖകള്‍
pick_reaction=നിങ്ങളുടെ പ്രതികരണം തിരഞ്ഞെടുക്കുക
reactions_more=കൂടാതെ %d അധികം
archive.title=ഈ കലവറ ചരിത്രരേഖാപരമായി നിലനിര്‍ത്തിയിരിക്കുന്നു. നിങ്ങൾക്ക് ഫയലുകൾ കാണാനും ക്ലോൺ ചെയ്യാനും കഴിയും, പക്ഷേ പ്രശ്‌നങ്ങൾ / ലയന അഭ്യർത്ഥനകൾ ഉണ്ടാക്കാനോ തുറക്കാനോ കഴിയില്ല.
archive.issue.nocomment=ഈ കലവറ ചരിത്രപരമായി നിലനിര്‍ത്തിയിരിക്കുന്നതാണു്. നിങ്ങൾക്ക് പ്രശ്നങ്ങളിൽ അഭിപ്രായമിടാൻ കഴിയില്ല.
archive.pull.nocomment=ഈ കലവറ ചരിത്രപരമായി നിലനിര്‍ത്തിയിരിക്കുന്നതാണു്. നിങ്ങൾക്ക് ലയന അഭ്യർത്ഥനകളില്‍ അഭിപ്രായമിടാൻ കഴിയില്ല.
form.reach_limit_of_creation=നിങ്ങളുടെ കലവറകളുടെ പരിധിയായ %d നിങ്ങൾ ഇതിനകം എത്തി.
form.name_reserved='%s' എന്ന കലവറയുടെ പേരു് മറ്റാവശ്യങ്ങള്‍ക്കായി നീക്കിവച്ചിരിക്കുന്നു.
form.name_pattern_not_allowed=കലവറനാമത്തിൽ '%s' എന്ന ശ്രേണി അനുവദനീയമല്ല.
need_auth=ക്ലോൺ അംഗീകാരിയ്ക്കുക
migrate_type=മൈഗ്രേഷൻ തരം
migrate_type_helper=ഈ കലവറ ഒരു <span class="text blue"> മിറർ </span> ആയിരിക്കും
migrate_items=മൈഗ്രേഷൻ ഇനങ്ങൾ
migrate_items_wiki=വിക്കി
migrate_items_milestones=നാഴികക്കല്ലുകള്‍
migrate_items_labels=ലേബലുകള്‍
migrate_items_issues=പ്രശ്നങ്ങൾ
migrate_items_pullrequests=ലയന അഭ്യർത്ഥനകൾ
migrate_items_releases=പ്രസിദ്ധീകരണങ്ങള്‍
migrate_repo=കലവറ മൈഗ്രേറ്റ് ചെയ്യുക
migrate.clone_address=URL- ൽ നിന്ന് മൈഗ്രേറ്റ് / ക്ലോൺ ചെയ്യുക
migrate.clone_address_desc=നിലവിലുള്ള ഒരു കലവറയുടെ HTTP(S) അല്ലെങ്കിൽ ഗിറ്റു് 'ക്ലോൺ' URL
migrate.clone_local_path=അല്ലെങ്കിൽ ഒരു പ്രാദേശിക സെർവർ പാത
migrate.permission_denied=പ്രാദേശിക കലവറകള്‍ ഇറക്കുമതി ചെയ്യാൻ നിങ്ങള്‍ക്കു് അനുവാദമില്ല.
migrate.invalid_local_path=പ്രാദേശിക പാത അസാധുവാണ്. ഇത് നിലവിലില്ല അല്ലെങ്കിൽ ഒരു ഡയറക്ടറിയല്ല.
migrate.failed=മൈഗ്രേഷൻ പരാജയപ്പെട്ടു: %v
migrate.lfs_mirror_unsupported=എൽ‌എഫ്‌എസ് ഒബ്‌ജക്റ്റുകളുടെ മിററിംഗ് പിന്തുണയ്‌ക്കുന്നില്ല - പകരം 'git lfs fetch --all', 'git lfs push --all' എന്നിവ ഉപയോഗിക്കുക.
migrate.migrate_items_options=ഗിറ്റ്ഹബിൽ നിന്ന് മൈഗ്രേറ്റ് ചെയ്യുമ്പോൾ, ഒരു ഉപയോക്തൃനാമവും മൈഗ്രേഷൻ ഓപ്ഷനുകളും നല്‍കാം.
migrated_from=<a href="%[1]s">%[2]s</a> നിന്ന് മൈഗ്രേറ്റുചെയ്‌തു
migrated_from_fake=%[1]s നിന്ന് മൈഗ്രേറ്റുചെയ്തു
mirror_from=ന്റെ കണ്ണാടി
forked_from=ല്‍ നിന്നും വഴിപിരിഞ്ഞതു്
fork_from_self=നിങ്ങളുടെ ഉടമസ്ഥതയിലുള്ള ഒരു ശേഖരം നിങ്ങൾക്ക് ഫോര്‍ക്കു് ചെയ്യാൻ കഴിയില്ല.
fork_guest_user=ഈ ശേഖരം ഫോർക്ക് ചെയ്യുന്നതിന് സൈൻ ഇൻ ചെയ്യുക.
copy_link=പകര്‍ത്തുക
copy_link_success=കണ്ണി പകർത്തി
copy_link_error=പകർത്താൻ ⌘C അല്ലെങ്കിൽ Ctrl-C ഉപയോഗിക്കുക
copied=പകര്‍ത്തല്‍ പൂര്‍ത്തിയായി
unwatch=ശ്രദ്ധിക്കാതിരിയ്ക്കുക
watch=ശ്രദ്ധിയ്ക്കുക
unstar=നക്ഷത്രം നീക്കുക
star=നക്ഷത്രം നല്‍ക്കുക
fork=ഫോര്‍ക്കു്
download_archive=കലവറ ഡൗൺലോഡുചെയ്യുക
no_desc=വിവരണം ലഭ്യമല്ല
quick_guide=ദ്രുത മാര്‍ഗദര്‍ശനം
clone_this_repo=ഈ കലവറ ക്ലോൺ ചെയ്യുക
create_new_repo_command=കമാൻഡ് ലൈന്‍ വഴി ഒരു പുതിയ കലവറ സൃഷ്ടിക്കുക
push_exist_repo=കമാൻഡ് ലൈനിൽ നിന്ന് നിലവിലുള്ള ഒരു കലവറ തള്ളിക്കയറ്റുക
empty_message=ഈ കലവറയില്‍ ഉള്ളടക്കമൊന്നും അടങ്ങിയിട്ടില്ല.
code=കോഡ്
code.desc=ഉറവിട കോഡ്, ഫയലുകൾ, കമ്മിറ്റുകളും ശാഖകളും പ്രവേശിയ്ക്കുക.
branch=ശാഖ
tree=മരം
filter_branch_and_tag=ശാഖ അല്ലെങ്കിൽ ടാഗ് അരിച്ചെടുക്കുക
branches=ശാഖകള്‍
tags=ടാഗുകള്‍
issues=പ്രശ്നങ്ങൾ
pulls=ലയന അഭ്യർത്ഥനകൾ
labels=ലേബലുകള്‍
milestones=നാഴികക്കല്ലുകള്‍
commits=കമ്മിറ്റുകള്‍
commit=കമ്മിറ്റ്
releases=പ്രസിദ്ധപ്പെടുത്തുക
file_raw=കലര്‍പ്പില്ലാത്തതു്
file_history=നാള്‍വഴി
file_view_raw=കലര്‍പ്പില്ലാതെ കാണുക
file_permalink=സ്ഥിരമായ കണ്ണി
file_too_large=ഈ ഫയൽ കാണിക്കാൻ കഴിയാത്തത്ര വലുതാണ്.
video_not_supported_in_browser=നിങ്ങളുടെ ബ്രൌസർ HTML5 'വീഡിയോ' ടാഗിനെ പിന്തുണയ്ക്കുന്നില്ല.
audio_not_supported_in_browser=നിങ്ങളുടെ ബ്ര browser സർ HTML5 'ഓഡിയോ' ടാഗിനെ പിന്തുണയ്ക്കുന്നില്ല.
stored_lfs=ഗിറ്റു് LFS ഉപയോഗിച്ച് സംഭരിച്ചു
commit_graph=കമ്മിറ്റ് ഗ്രാഫ്
blame=ചുമതല
normal_view=സാധാരണ കാഴ്ച
editor.new_file=പുതിയ ഫയൽ
editor.upload_file=ഫയൽ അപ്‌ലോഡ്
editor.edit_file=ഫയൽ തിരുത്തുക
editor.preview_changes=മാറ്റങ്ങൾ കാണുക
editor.cannot_edit_lfs_files=വെബ് ഇന്റർഫേസിൽ LFS ഫയലുകൾ എഡിറ്റുചെയ്യാൻ കഴിയില്ല.
editor.cannot_edit_non_text_files=വെബ് ഇന്റർഫേസിൽ ബൈനറി ഫയലുകൾ എഡിറ്റുചെയ്യാൻ കഴിയില്ല.
editor.edit_this_file=ഫയൽ തിരുത്തുക
editor.must_be_on_a_branch=ഈ ഫയലിൽ മാറ്റങ്ങൾ വരുത്താനോ നിർദ്ദേശിക്കാനോ നിങ്ങൾ ഏതെങ്കിലും ഒരു ശാഖയിൽ ആയിരിക്കണം.
editor.fork_before_edit=ഈ ഫയലിൽ മാറ്റങ്ങൾ വരുത്താനോ നിർദ്ദേശിക്കാനോ നിങ്ങൾ ഈ ശേഖരം ഫോര്‍ക്കു ചെയ്തിരിക്കണം.
editor.delete_this_file=ഫയൽ ഇല്ലാതാക്കുക
editor.must_have_write_access=ഈ ഫയലിൽ മാറ്റങ്ങൾ വരുത്താനോ നിർദ്ദേശിക്കാനോ നിങ്ങൾക്ക് എഴുതാനുള്ള അനുമതി ഉണ്ടായിരിക്കണം.
editor.file_delete_success=%s ഫയൽ ഇല്ലാതാക്കി.
editor.name_your_file=നിങ്ങളുടെ ഫയലിന് പേര് നൽകുക…
editor.filename_help=ഒരു ഡയറക്‌ടറിയുടെ പേര് ടൈപ്പുചെയ്‌ത് സ്ലാഷും ('/') ചേർത്ത് ചേർക്കുക. ഇൻപുട്ട് ഫീൽഡിന്റെ തുടക്കത്തിൽ ബാക്ക്‌സ്‌പെയ്‌സ് ടൈപ്പുചെയ്‌ത് ഒരു ഡയറക്‌ടറി നീക്കംചെയ്യുക.
editor.or=അഥവാ
editor.cancel_lower=റദ്ദാക്കുക
editor.commit_changes=മാറ്റങ്ങൾ വരുത്തുക
editor.add_tmpl='<ഫയല്‍>' ചേർക്കുക
editor.add=%s ചേര്‍ക്കുക
editor.update=%s പുതുക്കുക
editor.delete=%s നീക്കം ചെയ്യുക
editor.propose_file_change=ഫയലിനു് മാറ്റങ്ങള്‍ നിർദ്ദേശിക്കുക
editor.new_branch_name_desc=പുതിയ ശാഖയുടെ പേരു്…
editor.cancel=റദ്ദാക്കുക
editor.filename_cannot_be_empty=ഫയലിന്റെ പേരു് ശൂന്യമായിരിക്കരുത്.
editor.add_subdir=ഒരു ഡയറക്ടറി ചേർക്കുക…
editor.upload_files_to_dir=ഫയലുകൾ %s ലേക്ക് അപ്‌ലോഡുചെയ്യുക
issues.new.clear_labels=ലേബലുകൾ മായ്‌ക്കുക
issues.new.milestone=നാഴികക്കല്ല്
issues.new.no_milestone=നാഴികക്കല്ല് ഇല്ല
issues.new.clear_milestone=നാഴികക്കല്ല് എടുത്തു മാറ്റുക
issues.new.open_milestone=നാഴികക്കല്ലുകൾ തുറക്കുക
issues.new.closed_milestone=അടച്ച നാഴികക്കല്ലുകൾ
issues.new.assignees=നിശ്ചയിക്കുന്നവര്‍
issues.new.clear_assignees=നിശ്ചയിക്കുന്നവരെ നീക്കം ചെയ്യുക
issues.new.no_assignees=നിശ്ചയിക്കുന്നവര്‍ ഇല്ല
issues.no_ref=ശാഖാ അഥവാ ടാഗ് വ്യക്തമാക്കിയിട്ടില്ല
issues.create=പ്രശ്നം സൃഷ്ടിക്കുക
issues.new_label=പുതിയ അടയാളം
issues.new_label_placeholder=അടയാള നാമം
issues.new_label_desc_placeholder=വിരരണം
issues.create_label=അടയാളം സൃഷ്ടിക്കുക
issues.label_templates.title=മുൻ‌നിശ്ചയിച്ച ഒരു കൂട്ടം ലേബലുകൾ‌ നിറയ്‌ക്കുക
issues.label_templates.info=ലേബലുകളൊന്നും ഇതുവരെ നിലവിലില്ല. 'പുതിയ ലേബൽ' ഉപയോഗിച്ച് ഒരു ലേബൽ സൃഷ്ടിക്കുക അല്ലെങ്കിൽ മുൻ‌നിശ്ചയിച്ച ലേബൽ സെറ്റ് ഉപയോഗിക്കുക:
issues.label_templates.helper=ഒരു ലേബൽ സെറ്റ് തിരഞ്ഞെടുക്കുക
issues.label_templates.use=ലേബൽ സെറ്റ് ഉപയോഗിക്കുക
issues.deleted_milestone=`(ഇല്ലാതാക്കി)`
issues.filter_type.all_issues=എല്ലാ ഇഷ്യൂകളും
issues.label_open_issues=%d തുറന്നനിലയിലുള്ള ഇഷ്യൂകള്‍
issues.label_deletion_desc=ഒരു ലേബൽ ഇല്ലാതാക്കിയാല്‍, അതു് നിയുകതമാക്കിയ എല്ലാ ഇഷ്യൂകളില്‍ നിന്നും നീക്കംചെയ്യും. തുടരട്ടെ?
issues.dependency.issue_closing_blockedby=ഈ ലയന അഭ്യര്‍ത്ഥന അടയ്‌ക്കുന്നത് ഇനിപ്പറയുന്ന ഇഷ്യൂകള്‍ തടയുന്നു്
issues.dependency.pr_closing_blockedby=ഈ ഇഷ്യു അടയ്‌ക്കുന്നത് ഇനിപ്പറയുന്ന ലയന അഭ്യര്‍ത്ഥന തടയുന്നു്
issues.dependency.issue_close_blocks=ഈ ഇഷ്യു അടയ്‌ക്കുന്നത് ഇനിപ്പറയുന്ന ഇഷ്യൂകള്‍ തടയുന്നു്
issues.dependency.pr_close_blocks=ഈ ഇഷ്യൂകള്‍ അടയ്‌ക്കുന്നത് ഈ ലയന അഭ്യര്‍ത്ഥന തടയുന്നു്
issues.dependency.issue_close_blocked=ഈ ഇഷ്യൂ അടയ്‌ക്കുന്നതിന് മുമ്പ് ഇതിനെ തടയുന്ന എല്ലാ ഇഷ്യൂകളും നിങ്ങൾ അടയ്‌ക്കേണ്ടതുണ്ട്.
issues.dependency.pr_close_blocked=ഈ ലയന അഭ്യര്‍ത്ഥന സ്ഥിരീകരിയ്ക്കുന്നതിനു മുമ്പ് ഇതിനെ തടയുന്ന എല്ലാ ഇഷ്യൂകളും നിങ്ങൾ അടയ്‌ക്കേണ്ടതുണ്ട്.
issues.dependency.setting=ലയന അഭ്യര്‍ത്ഥനകള്‍ക്കും ഇഷ്യൂകള്‍ക്കുമായി ആശ്രിതത്വം സജ്ജമാക്കുക
issues.dependency.add_error_cannot_create_circular=രണ്ട് ഇഷ്യൂകളും പരസ്പരം തടയുന്നതാകുന്നതിലൂടെ നിങ്ങൾക്ക് ഒരു ആശ്രയത്വം സൃഷ്ടിക്കാൻ കഴിയില്ല.
issues.dependency.add_error_dep_not_same_repo=രണ്ട് പ്രശ്നങ്ങളും ഒരേ കലവറയിലേതു് ആയിരിക്കണം.
milestones.filter_sort.most_issues=മിക്ക ഇഷ്യൂകളും
milestones.filter_sort.least_issues=കുറഞ്ഞ ഇഷ്യൂകളെങ്കിലും
activity.active_issues_count_n=<strong>%d</strong> സജ്ജീവ ഇഷ്യൂകള്‍
activity.closed_issues_count_n=അടച്ച ഇഷ്യൂകള്‍
activity.title.issues_n=%d ഇഷ്യൂകള്‍
activity.new_issues_count_n=പുതിയ ഇഷ്യൂകള്‍
settings.event_issues=ഇഷ്യൂകള്‍
@ -88,6 +771,7 @@
repos.issues=ഇഷ്യൂകള്‍

View file

@ -80,6 +80,7 @@ loading=Ładowanie…
[startpage] [startpage]
app_desc=Bezbolesna usługa Git na własnym serwerze app_desc=Bezbolesna usługa Git na własnym serwerze
install=Łatwa instalacja install=Łatwa instalacja
install_desc=Po prostu <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/install-from-binary/">odpal plik binarny</a> dla swojej platformy. Albo uruchom Gitea przy pomocy <a target="_blank" rel="noopener noreferrer" href="https://github.com/go-gitea/gitea/tree/master/docker">Dockera</a> lub <a target="_blank" rel="noopener noreferrer" href="https://github.com/alvaroaleman/ansible-gitea/blob/master/Vagrantfile">Vagrant</a>, albo zainstaluj <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/install-from-package/">z paczki</a>.
platform=Wieloplatformowość platform=Wieloplatformowość
platform_desc=Gitea ruszy gdziekolwiek <a target="_blank" rel="noopener noreferrer" href="http://golang.org/">Go</a> jest możliwe do skompilowania: Windows, macOS, Linux, ARM, itd. Wybierz swój ulubiony system! platform_desc=Gitea ruszy gdziekolwiek <a target="_blank" rel="noopener noreferrer" href="http://golang.org/">Go</a> jest możliwe do skompilowania: Windows, macOS, Linux, ARM, itd. Wybierz swój ulubiony system!
lightweight=Niskie wymagania lightweight=Niskie wymagania
@ -268,6 +269,7 @@ authorize_application_description=Jeżeli udzielisz dostępu, aplikacja uzyska d
authorize_title=Zezwolić "%s" na dostęp do Twojego konta? authorize_title=Zezwolić "%s" na dostęp do Twojego konta?
authorization_failed=Autoryzacja nie powiodła się authorization_failed=Autoryzacja nie powiodła się
authorization_failed_desc=Autoryzacja nie powiodła się ze względu na niewłaściwe żądanie. Skontaktuj się z osobami utrzymującymi aplikację, którą próbowano autoryzować. authorization_failed_desc=Autoryzacja nie powiodła się ze względu na niewłaściwe żądanie. Skontaktuj się z osobami utrzymującymi aplikację, którą próbowano autoryzować.
sspi_auth_failed=Uwierzytelnianie SSPI nie powiodło się
[mail] [mail]
activate_account=Aktywuj swoje konto activate_account=Aktywuj swoje konto
@ -301,6 +303,8 @@ CommitChoice=Wybór commita
TreeName=Ścieżka pliku TreeName=Ścieżka pliku
Content=Treść Content=Treść
SSPISeparatorReplacement=Separator
SSPIDefaultLanguage=Domyślny język
require_error=` nie może być puste.` require_error=` nie może być puste.`
alpha_dash_error=` powinno zawierać tylko znaki alfanumeryczne, myślniki ("-") i znaki podkreślenia ("_").` alpha_dash_error=` powinno zawierać tylko znaki alfanumeryczne, myślniki ("-") i znaki podkreślenia ("_").`
@ -312,9 +316,11 @@ max_size_error=` musi zawierać co najwyżej %s znaków.`
email_error=` nie jest poprawnym adresem e-mail.` 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'.`
glob_pattern_error=` wzorzec glob jest nieprawidłowy: %s.`
unknown_error=Nieznany błąd: unknown_error=Nieznany błąd:
captcha_incorrect=Kod CAPTCHA jest nieprawidłowy. captcha_incorrect=Kod CAPTCHA jest nieprawidłowy.
password_not_match=Hasła nie są identyczne. password_not_match=Hasła nie są identyczne.
lang_select_error=Wybierz język z listy.
username_been_taken=Ta nazwa użytkownika jest już zajęta. username_been_taken=Ta nazwa użytkownika jest już zajęta.
repo_name_been_taken=Nazwa repozytorium jest już zajęta. repo_name_been_taken=Nazwa repozytorium jest już zajęta.
@ -326,6 +332,11 @@ team_no_units_error=Zezwól na dostęp do co najmniej jednej sekcji repozytorium
email_been_used=Ten adres e-mail jest już używany. email_been_used=Ten adres e-mail jest już używany.
openid_been_used=Ten adres OpenID "%s" jest już używany. openid_been_used=Ten adres OpenID "%s" jest już używany.
username_password_incorrect=Nazwa użytkownika lub hasło jest nieprawidłowe. username_password_incorrect=Nazwa użytkownika lub hasło jest nieprawidłowe.
password_complexity=Hasło nie spełnia wymogów złożoności:
password_lowercase_one=Co najmniej jedna mała litera
password_uppercase_one=Co najmniej jedna duża litera
password_digit_one=Co najmniej jedna cyfra
password_special_one=Co najmniej jeden znak specjalny (interpunkcja, nawiasy, cudzysłowy, itp.)
enterred_invalid_repo_name=Wprowadzona nazwa repozytorium jest niepoprawna. enterred_invalid_repo_name=Wprowadzona nazwa repozytorium jest niepoprawna.
enterred_invalid_owner_name=Nowa nazwa właściciela nie jest prawidłowa. enterred_invalid_owner_name=Nowa nazwa właściciela nie jest prawidłowa.
enterred_invalid_password=Wprowadzone hasło jest nieprawidłowe. enterred_invalid_password=Wprowadzone hasło jest nieprawidłowe.
@ -579,6 +590,11 @@ email_notifications.submit=Ustaw preferencje wiadomości e-mail
owner=Właściciel owner=Właściciel
repo_name=Nazwa repozytorium repo_name=Nazwa repozytorium
repo_name_helper=Dobra nazwa repozytorium jest utworzona z krótkich, łatwych do zapamiętania i unikalnych słów kluczowych. repo_name_helper=Dobra nazwa repozytorium jest utworzona z krótkich, łatwych do zapamiętania i unikalnych słów kluczowych.
repo_size=Rozmiar repozytorium
template=Szablon
template_select=Wybierz szablon.
template_helper=Ustaw repozytorium jako szablon
template_description=Szablony repozytoriów pozwalają użytkownikom generować nowe repozytoria o takiej samej strukturze katalogów, plików i opcjonalnych ustawieniach.
visibility=Widoczność visibility=Widoczność
visibility_description=Tylko właściciel lub członkowie organizacji, jeśli mają odpowiednie uprawnienia, będą mogli to zobaczyć. visibility_description=Tylko właściciel lub członkowie organizacji, jeśli mają odpowiednie uprawnienia, będą mogli to zobaczyć.
visibility_helper=Przekształć repozytorium na prywatne visibility_helper=Przekształć repozytorium na prywatne
@ -588,9 +604,14 @@ clone_helper=Potrzebujesz pomocy z klonowaniem? Odwiedź <a target="_blank" rel=
fork_repo=Forkuj repozytorium fork_repo=Forkuj repozytorium
fork_from=Forkuj z fork_from=Forkuj z
fork_visibility_helper=Widoczność sforkowanego repozytorium nie może być zmieniona. fork_visibility_helper=Widoczność sforkowanego repozytorium nie może być zmieniona.
use_template=Użyj tego szablonu
generate_repo=Generuj repozytorium
generate_from=Generuj z
repo_desc=Opis repo_desc=Opis
repo_lang=Język repo_lang=Język
repo_gitignore_helper=Wybierz szablony pliku .gitignore. repo_gitignore_helper=Wybierz szablony pliku .gitignore.
issue_labels=Etykiety zgłoszenia
issue_labels_helper=Wybierz zestaw etykiet zgłoszeń.
license=Licencja license=Licencja
license_helper=Wybierz plik licencji. license_helper=Wybierz plik licencji.
readme=README readme=README
@ -613,6 +634,16 @@ forks=Forki
pick_reaction=Wybierz swoją reakcję pick_reaction=Wybierz swoją reakcję
reactions_more=i %d więcej reactions_more=i %d więcej
template.items=Elementy szablonu
template.git_content=Zawartość gita (domyślna gałąź)
template.git_hooks=Hooki Git
template.git_hooks_tooltip=Aktualnie nie możesz modyfikować lub usuwać hooków gita po ich utworzeniu. Wybierz to tylko wtedy, gdy ufasz szablonowi tego repozytorium.
template.webhooks=Webhooki
template.topics=Tematy
template.avatar=Awatar
template.issue_labels=Etykiety zgłoszenia
template.one_item=Musisz wybrać co najmniej jeden element szablonu
template.invalid=Musisz wybrać repozytorium dla szablonu
archive.title=To repozytorium jest zarchiwizowane. Możesz wyświetlać pliki i je sklonować, ale nie możesz do niego przepychać zmian lub otwierać zgłoszeń/Pull Requestów. archive.title=To repozytorium jest zarchiwizowane. Możesz wyświetlać pliki i je sklonować, ale nie możesz do niego przepychać zmian lub otwierać zgłoszeń/Pull Requestów.
archive.issue.nocomment=To repozytorium jest zarchiwizowane. Nie możesz komentować zgłoszeń. archive.issue.nocomment=To repozytorium jest zarchiwizowane. Nie możesz komentować zgłoszeń.
@ -643,9 +674,12 @@ migrate.lfs_mirror_unsupported=Tworzenie kopii lustrzanych elementów LFS nie je
migrate.migrate_items_options=Przy migracji z GitHub'a, wpisz nazwę użytkownika, a opcje migracji zostaną wyświetlone. migrate.migrate_items_options=Przy migracji z GitHub'a, wpisz nazwę użytkownika, a opcje migracji zostaną wyświetlone.
migrated_from=Zmigrowane z <a href="%[1]s">%[2]s</a> migrated_from=Zmigrowane z <a href="%[1]s">%[2]s</a>
migrated_from_fake=Zmigrowane z %[1]s migrated_from_fake=Zmigrowane z %[1]s
migrate.migrating=Migrowanie z <b>%s</b>...
migrate.migrating_failed=Migrowanie z <b>%s</b> nie powiodło się.
mirror_from=kopia lustrzana mirror_from=kopia lustrzana
forked_from=sforkowany z forked_from=sforkowany z
generated_from=wygenerowane z
fork_from_self=Nie możesz sforkować swojego własnego repozytorium. fork_from_self=Nie możesz sforkować swojego własnego repozytorium.
fork_guest_user=Zaloguj się, aby sforkować to repozytorium. fork_guest_user=Zaloguj się, aby sforkować to repozytorium.
copy_link=Kopiuj copy_link=Kopiuj
@ -691,6 +725,8 @@ stored_lfs=Przechowane za pomocą Git LFS
commit_graph=Wykres commitów commit_graph=Wykres commitów
blame=Wina blame=Wina
normal_view=Zwykły widok normal_view=Zwykły widok
line=wiersz
lines=wiersze
editor.new_file=Nowy plik editor.new_file=Nowy plik
editor.upload_file=Wyślij plik editor.upload_file=Wyślij plik
@ -699,6 +735,7 @@ editor.preview_changes=Podgląd zmian
editor.cannot_edit_lfs_files=Pliki LFS nie mogą być edytowane poprzez interfejs przeglądarkowy. editor.cannot_edit_lfs_files=Pliki LFS nie mogą być edytowane poprzez interfejs przeglądarkowy.
editor.cannot_edit_non_text_files=Pliki binarne nie mogą być edytowane poprzez interfejs przeglądarkowy. editor.cannot_edit_non_text_files=Pliki binarne nie mogą być edytowane poprzez interfejs przeglądarkowy.
editor.edit_this_file=Edytuj plik editor.edit_this_file=Edytuj plik
editor.this_file_locked=Plik jest zablokowany
editor.must_be_on_a_branch=Musisz znajdować się na gałęzi, aby nanieść lub zaproponować zmiany tego pliku. editor.must_be_on_a_branch=Musisz znajdować się na gałęzi, aby nanieść lub zaproponować zmiany tego pliku.
editor.fork_before_edit=Musisz sforkować to repozytorium, aby nanieść lub zaproponować zmiany tego pliku. editor.fork_before_edit=Musisz sforkować to repozytorium, aby nanieść lub zaproponować zmiany tego pliku.
editor.delete_this_file=Usuń plik editor.delete_this_file=Usuń plik
@ -716,6 +753,7 @@ editor.delete=Usuń '%s'
editor.commit_message_desc=Dodaj dodatkowy rozszerzony opis… 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.create_new_branch_np=Stwórz <strong>nową gałąź</strong> dla tego commita.
editor.propose_file_change=Zaproponuj zmiany w pliku editor.propose_file_change=Zaproponuj zmiany w pliku
editor.new_branch_name_desc=Nazwa nowej gałęzi… editor.new_branch_name_desc=Nazwa nowej gałęzi…
editor.cancel=Anuluj editor.cancel=Anuluj
@ -730,10 +768,13 @@ editor.file_editing_no_longer_exists=Edytowany plik '%s' już nie istnieje w tym
editor.file_deleting_no_longer_exists=Usuwany plik '%s' już nie istnieje w tym repozytorium. editor.file_deleting_no_longer_exists=Usuwany plik '%s' już nie istnieje w tym repozytorium.
editor.file_changed_while_editing=Zawartość pliku zmieniła się, odkąd rozpoczęto jego edycję. <a target="_blank" rel="noopener noreferrer" href="%s">Kliknij tutaj</a>, aby zobaczyć zmiany, lub <strong>ponownie Zatwierdź zmiany</strong>, aby je nadpisać. editor.file_changed_while_editing=Zawartość pliku zmieniła się, odkąd rozpoczęto jego edycję. <a target="_blank" rel="noopener noreferrer" href="%s">Kliknij tutaj</a>, aby zobaczyć zmiany, lub <strong>ponownie Zatwierdź zmiany</strong>, aby je nadpisać.
editor.file_already_exists=Plik o nazwie '%s' już istnieje w tym repozytorium. editor.file_already_exists=Plik o nazwie '%s' już istnieje w tym repozytorium.
editor.commit_empty_file_header=Commituj pusty plik
editor.commit_empty_file_text=Plik, który zamierzasz commitować, jest pusty. Kontynuować?
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.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_file_is_locked=Plik '%s' jest zablokowany przez %s.
editor.upload_files_to_dir=Prześlij pliki do '%s' editor.upload_files_to_dir=Prześlij pliki do '%s'
editor.cannot_commit_to_protected_branch=Nie można commitować do chronionej gałęzi '%s'. editor.cannot_commit_to_protected_branch=Nie można commitować do chronionej gałęzi '%s'.
@ -786,12 +827,16 @@ issues.add_milestone_at=`dodaje to do kamienia milowego <b>%s</b> %s`
issues.change_milestone_at=`zmienia kamień milowy z <b>%s</b> na <b>%s</b> %s` issues.change_milestone_at=`zmienia kamień milowy z <b>%s</b> na <b>%s</b> %s`
issues.remove_milestone_at=`usuwa to z kamienia milowego <b>%s</b> %s` issues.remove_milestone_at=`usuwa to z kamienia milowego <b>%s</b> %s`
issues.deleted_milestone=`(usunięto)` issues.deleted_milestone=`(usunięto)`
issues.self_assign_at=`przypisuje to na siebie %s`
issues.add_assignee_at=`zostaje przypisany(-a) przez <b>%s</b> %s`
issues.remove_assignee_at=`usunięto przypisanie przez <b>%s</b> %s` issues.remove_assignee_at=`usunięto przypisanie przez <b>%s</b> %s`
issues.remove_self_assignment=`usuwa swoje przypisanie %s`
issues.change_title_at=`zmieniono tytuł z <b><strike>%s</strike></b> na <b>%s</b> %s` issues.change_title_at=`zmieniono tytuł z <b><strike>%s</strike></b> na <b>%s</b> %s`
issues.delete_branch_at=`usuwa gałąź <b>%s</b> %s` issues.delete_branch_at=`usuwa 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_exclude=`Użyj <code>Alt</code> + <code>Kliknij/Enter</code>, aby wykluczyć etykiety`
issues.filter_label_no_select=Wszystkie etykiety issues.filter_label_no_select=Wszystkie etykiety
issues.filter_milestone=Kamień milowy issues.filter_milestone=Kamień milowy
issues.filter_milestone_no_select=Wszystkie kamienie milowe issues.filter_milestone_no_select=Wszystkie kamienie milowe
@ -835,6 +880,10 @@ issues.closed_title=Zamknięty
issues.num_comments=%d komentarzy issues.num_comments=%d komentarzy
issues.commented_at=`skomentował(-a) <a href="#%s">%s</a>` issues.commented_at=`skomentował(-a) <a href="#%s">%s</a>`
issues.delete_comment_confirm=Czy na pewno chcesz usunąć ten komentarz? issues.delete_comment_confirm=Czy na pewno chcesz usunąć ten komentarz?
issues.context.copy_link=Skopiuj link
issues.context.quote_reply=Cytuj odpowiedź
issues.context.edit=Edytuj
issues.context.delete=Usuń
issues.no_content=Nie ma jeszcze treści. issues.no_content=Nie ma jeszcze treści.
issues.close_issue=Zamknij issues.close_issue=Zamknij
issues.close_comment_issue=Skomentuj i zamknij issues.close_comment_issue=Skomentuj i zamknij
@ -844,6 +893,13 @@ issues.create_comment=Skomentuj
issues.closed_at=`zamknął(-ęła) <a id="%[1]s" href="#%[1]s">%[2]s</a>` issues.closed_at=`zamknął(-ęła) <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.reopened_at=`otworzył(-a) ponownie <a id="%[1]s" href="#%[1]s">%[2]s</a>` issues.reopened_at=`otworzył(-a) ponownie <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.commit_ref_at=`wspomniał(-a) to zgłoszenie z commita <a id="%[1]s" href="#%[1]s">%[2]s</a>` issues.commit_ref_at=`wspomniał(-a) to zgłoszenie z commita <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.ref_issue_from=`<a href="%[3]s">odwołał(-a) się do tego zgłoszenia %[4]s</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.ref_pull_from=`<a href="%[3]s">odwołał(-a) się do tego Pull Requesta %[4]s</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.ref_closing_from=`<a href="%[3]s">odwołał(-a) się do Pull Requesta %[4]s, który zamknie to zgłoszenie</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.ref_reopening_from=`<a href="%[3]s">odwołał(-a) się do Pull Requesta %[4]s, który otworzy na nowo to zgłoszenie</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.ref_closed_from=`<a href="%[3]s">zamknął(-ęła) to zgłoszenie %[4]s</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.ref_reopened_from=`<a href="%[3]s">ponownie otworzył(-a) to zgłoszenie %[4]s</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.ref_from=`z %[1]s`
issues.poster=Autor issues.poster=Autor
issues.collaborator=Współpracownik issues.collaborator=Współpracownik
issues.owner=Właściciel issues.owner=Właściciel
@ -956,10 +1012,13 @@ issues.review.self.rejection=Nie możesz zażądać zmian w swoim własnym Pull
issues.review.approve=zatwierdza te zmiany %s issues.review.approve=zatwierdza te zmiany %s
issues.review.comment=zrecenzowano %s issues.review.comment=zrecenzowano %s
issues.review.content.empty=Musisz pozostawić komentarz o pożądanej zmianie/zmianach. issues.review.content.empty=Musisz pozostawić komentarz o pożądanej zmianie/zmianach.
issues.review.reject=zażądał(-a) zmian %s
issues.review.pending=Oczekująca
issues.review.review=Recenzuj issues.review.review=Recenzuj
issues.review.reviewers=Recenzenci issues.review.reviewers=Recenzenci
issues.review.show_outdated=Pokaż przedawnione issues.review.show_outdated=Pokaż przedawnione
issues.review.hide_outdated=Ukryj przedawnione issues.review.hide_outdated=Ukryj przedawnione
issues.assignee.error=Nie udało się dodać wszystkich wybranych osób do przypisanych przez nieoczekiwany błąd.
pulls.desc=Włącz Pull Requesty i recenzjonowanie kodu. pulls.desc=Włącz Pull Requesty i recenzjonowanie kodu.
pulls.new=Nowy Pull Request pulls.new=Nowy Pull Request
@ -972,6 +1031,7 @@ pulls.no_results=Nie znaleziono wyników.
pulls.nothing_to_compare=Te gałęzie są sobie równe. Nie ma potrzeby tworzyć Pull Requesta. pulls.nothing_to_compare=Te gałęzie są sobie równe. Nie ma potrzeby tworzyć Pull Requesta.
pulls.has_pull_request=`Pull Request pomiędzy tymi gałęziami już istnieje <a href="%[1]s/pulls/%[3]d">%[2]s#%[3]d</a>` pulls.has_pull_request=`Pull Request pomiędzy tymi gałęziami już istnieje <a href="%[1]s/pulls/%[3]d">%[2]s#%[3]d</a>`
pulls.create=Utwórz Pull Request pulls.create=Utwórz Pull Request
pulls.title_desc=chce scalić %[1]d commity/ów z <code>%[2]s</code> do <code id="branch_target">%[3]s</code>
pulls.merged_title_desc=scala %[1]d commity/ów z <code>%[2]s</code> do <code>%[3]s</code> %[4]s pulls.merged_title_desc=scala %[1]d commity/ów z <code>%[2]s</code> do <code>%[3]s</code> %[4]s
pulls.tab_conversation=Dyskusja pulls.tab_conversation=Dyskusja
pulls.tab_commits=Commity pulls.tab_commits=Commity
@ -986,6 +1046,8 @@ pulls.cannot_merge_work_in_progress=Ten Pull Request został oznaczony jako prac
pulls.data_broken=Ten Pull Request jest uszkodzony ze względu na brakujące informacje o forku. pulls.data_broken=Ten Pull Request jest uszkodzony ze względu na brakujące informacje o forku.
pulls.files_conflicted=Ten Pull Request zawiera zmiany konfliktujące z docelową gałęzią. pulls.files_conflicted=Ten Pull Request zawiera zmiany konfliktujące z docelową gałęzią.
pulls.is_checking=Sprawdzanie konfliktów ze scalaniem w toku. Spróbuj ponownie za chwilę. pulls.is_checking=Sprawdzanie konfliktów ze scalaniem w toku. Spróbuj ponownie za chwilę.
pulls.required_status_check_failed=Niektóre kontrole stanów nie były pomyślne.
pulls.required_status_check_administrator=Jako administrator, możesz wciąż scalić ten Pull Request.
pulls.blocked_by_approvals=Ten Pull Request nie ma jeszcze wymaganej ilości zatwierdzeń. Otrzymał %d z %d wymaganych zatwierdzeń. pulls.blocked_by_approvals=Ten Pull Request nie ma jeszcze wymaganej ilości zatwierdzeń. Otrzymał %d z %d wymaganych zatwierdzeń.
pulls.can_auto_merge_desc=Ten Pull Request może być automatycznie scalony. pulls.can_auto_merge_desc=Ten Pull Request może być automatycznie scalony.
pulls.cannot_auto_merge_desc=Ten Pull Request nie może być automatycznie scalony z powodu konfliktów. pulls.cannot_auto_merge_desc=Ten Pull Request nie może być automatycznie scalony z powodu konfliktów.
@ -993,11 +1055,16 @@ pulls.cannot_auto_merge_helper=Scal ręcznie, aby rozwiązać konflikty.
pulls.no_merge_desc=Ten Pull Request nie może zostać scalony, ponieważ wszystkie opcje scalania dla tego repozytorium są wyłączone. pulls.no_merge_desc=Ten Pull Request nie może zostać scalony, ponieważ wszystkie opcje scalania dla tego repozytorium są wyłączone.
pulls.no_merge_helper=Włącz opcje scalania w ustawieniach repozytorium, lub scal ten Pull Request ręcznie. pulls.no_merge_helper=Włącz opcje scalania w ustawieniach repozytorium, lub scal ten Pull Request ręcznie.
pulls.no_merge_wip=Ten pull request nie może być automatycznie scalony, ponieważ jest oznaczony jako praca w toku. pulls.no_merge_wip=Ten pull request nie może być automatycznie scalony, ponieważ jest oznaczony jako praca w toku.
pulls.no_merge_status_check=Ten Pull Request nie może być scalony, bo nie wszystkie kontrole stanów były pomyślne.
pulls.merge_pull_request=Scal Pull Request pulls.merge_pull_request=Scal Pull Request
pulls.rebase_merge_pull_request=Zmień bazę i scal pulls.rebase_merge_pull_request=Zmień bazę i scal
pulls.rebase_merge_commit_pull_request=Zmień bazę i scal (--no-ff) pulls.rebase_merge_commit_pull_request=Zmień bazę i scal (--no-ff)
pulls.squash_merge_pull_request=Zmiażdż i scal pulls.squash_merge_pull_request=Zmiażdż i scal
pulls.invalid_merge_option=Nie możesz użyć tej opcji scalania dla tego pull request'a. pulls.invalid_merge_option=Nie możesz użyć tej opcji scalania dla tego pull request'a.
pulls.merge_conflict=Scalenie nie powiodło się: Wystąpił konflikt przy scalaniu %[1]s<br>%[2]s<br>Porada: Wypróbuj innej strategii scalania
pulls.rebase_conflict=Scalenie nie powiodło się: Wystąpił konflikt przy zmianie bazy commita: %[1]s<br>%[2]s<br>%[3]s<br>Porada: Wypróbuj innej strategii scalania
pulls.unrelated_histories=Scalenie nie powiodło się: Head scalenia i baza nie mają wspólnej historii. Porada: Spróbuj innej strategii scalania
pulls.merge_out_of_date=Scalenie nie powiodło się: Przy generowaniu scalenia, baza została zaktualizowana. Porada: Spróbuj ponownie.
pulls.open_unmerged_pull_exists=`Nie możesz wykonać operacji ponownego otwarcia, ponieważ jest już oczekujący pull request (#%d) z identycznymi właściwościami.` pulls.open_unmerged_pull_exists=`Nie możesz wykonać operacji ponownego otwarcia, ponieważ jest już oczekujący pull request (#%d) z identycznymi właściwościami.`
pulls.status_checking=Niektóre etapy są w toku pulls.status_checking=Niektóre etapy są w toku
pulls.status_checks_success=Wszystkie etapy powiodły się pulls.status_checks_success=Wszystkie etapy powiodły się
@ -1066,6 +1133,9 @@ activity.period.daily=1 dzień
activity.period.halfweekly=3 dni activity.period.halfweekly=3 dni
activity.period.weekly=1 tydzień activity.period.weekly=1 tydzień
activity.period.monthly=1 miesiąc activity.period.monthly=1 miesiąc
activity.period.quarterly=3 miesiące
activity.period.semiyearly=6 miesięcy
activity.period.yearly=1 rok
activity.overview=Przegląd activity.overview=Przegląd
activity.active_prs_count_1=<strong>%d</strong> aktywny Pull Request activity.active_prs_count_1=<strong>%d</strong> aktywny Pull Request
activity.active_prs_count_n=<strong>%d</strong> aktywne Pull Requesty activity.active_prs_count_n=<strong>%d</strong> aktywne Pull Requesty
@ -1218,6 +1288,9 @@ settings.search_user_placeholder=Szukaj użytkownika…
settings.org_not_allowed_to_be_collaborator=Organizacji nie można dodać jako współpracownika. settings.org_not_allowed_to_be_collaborator=Organizacji nie można dodać jako współpracownika.
settings.change_team_access_not_allowed=Zmiana dostępu zespołu do repozytorium zostało zastrzeżone do właściciela organizacji settings.change_team_access_not_allowed=Zmiana dostępu zespołu do repozytorium zostało zastrzeżone do właściciela organizacji
settings.team_not_in_organization=Zespół nie jest w tej samej organizacji co repozytorium settings.team_not_in_organization=Zespół nie jest w tej samej organizacji co repozytorium
settings.add_team_duplicate=Zespół już posiada repozytorium
settings.add_team_success=Zespół ma teraz dostęp do repozytorium.
settings.remove_team_success=Dostęp zespołu do repozytorium został usunięty.
settings.add_webhook=Dodaj webhooka settings.add_webhook=Dodaj webhooka
settings.add_webhook.invalid_channel_name=Nazwa kanału Webhooka nie może być pusta i nie może zawierać jedynie znaku #. settings.add_webhook.invalid_channel_name=Nazwa kanału Webhooka nie może być pusta i nie może zawierać jedynie znaku #.
settings.hooks_desc=Webhooki automatycznie tworzą zapytania HTTP POST do serwera, kiedy następują pewne zdarzenia w Gitea. Przeczytaj o tym więcej w <a target="_blank" rel="noopener noreferrer" href="%s">przewodniku o Webhookach</a>. settings.hooks_desc=Webhooki automatycznie tworzą zapytania HTTP POST do serwera, kiedy następują pewne zdarzenia w Gitea. Przeczytaj o tym więcej w <a target="_blank" rel="noopener noreferrer" href="%s">przewodniku o Webhookach</a>.
@ -1267,6 +1340,8 @@ settings.event_pull_request=Pull Request
settings.event_pull_request_desc=Pull Request otwarty, zamknięty, ponownie otwarty, zaakceptowany, odrzucony, komentarz oceniający, przypisany, nieprzypisany, etykieta zaktualizowana, etykieta wyczyszczona lub zsynchronizowany. settings.event_pull_request_desc=Pull Request otwarty, zamknięty, ponownie otwarty, zaakceptowany, odrzucony, komentarz oceniający, przypisany, nieprzypisany, etykieta zaktualizowana, etykieta wyczyszczona lub zsynchronizowany.
settings.event_push=Wypchnięcie settings.event_push=Wypchnięcie
settings.event_push_desc=Wypchnięcie git do repozytorium. settings.event_push_desc=Wypchnięcie git do repozytorium.
settings.branch_filter=Filtr gałęzi
settings.branch_filter_desc=Biała lista gałęzi dla przepychania, tworzenia i usuwania gałęzi, określona jako wzorzec glob. Jeśli pusta, lub <code>*</code>, zdarzenia dla wszystkich gałęzi są wyświetlane. Sprawdź dokumentację <a href="https://godoc.org/github.com/gobwas/glob#Compile">github.com/gobwas/glob</a> dla składni. Przykładowo: <code>master</code>, <code>{master,release*}</code>.
settings.event_repository=Repozytorium settings.event_repository=Repozytorium
settings.event_repository_desc=Repozytorium stworzone lub usunięte. settings.event_repository_desc=Repozytorium stworzone lub usunięte.
settings.active=Aktywne settings.active=Aktywne
@ -1287,11 +1362,18 @@ settings.add_telegram_hook_desc=Zintegruj <a href="%s">Telegrama</a> ze swoim re
settings.add_msteams_hook_desc=Zintegruj <a href="%s">Microsoft Teams</a> ze swoim repozytorium. settings.add_msteams_hook_desc=Zintegruj <a href="%s">Microsoft Teams</a> ze swoim repozytorium.
settings.deploy_keys=Klucze wdrożeniowe settings.deploy_keys=Klucze wdrożeniowe
settings.add_deploy_key=Dodaj klucz wdrożeniowy settings.add_deploy_key=Dodaj klucz wdrożeniowy
settings.deploy_key_desc=Klucze wdrożeniowe mają wyłącznie dostęp "tylko do odczytu" do pobierania danych z repozytorium.
settings.is_writable=Włącz dostęp do zapisu settings.is_writable=Włącz dostęp do zapisu
settings.is_writable_info=Zezwól temu kluczowi wdrożeniowemu na <strong>przepychanie</strong> zmian do tego repozytorium.
settings.no_deploy_keys=W tej chwili nie ma kluczy wdrożeniowych.
settings.title=Tytuł settings.title=Tytuł
settings.deploy_key_content=Treść settings.deploy_key_content=Treść
settings.key_been_used=Klucz wdrożeniowy z identyczną zawartością jest już w użyciu.
settings.key_name_used=Klucz wdrożeniowy z identyczną nazwą już istnieje.
settings.add_key_success=Klucz wdrożeniowy '%s' został dodany.
settings.deploy_key_deletion=Usuń klucz wdrożeniowy settings.deploy_key_deletion=Usuń klucz wdrożeniowy
settings.deploy_key_deletion_desc=Usunięcie klucza wdrożeniowego wycofa jego dostęp do tego repozytorium. Kontynuować? settings.deploy_key_deletion_desc=Usunięcie klucza wdrożeniowego wycofa jego dostęp do tego repozytorium. Kontynuować?
settings.deploy_key_deletion_success=Klucz wdrożeniowy został usunięty.
settings.branches=Gałęzie settings.branches=Gałęzie
settings.protected_branch=Ochrona gałęzi settings.protected_branch=Ochrona gałęzi
settings.protected_branch_can_push=Umożliwić push? settings.protected_branch_can_push=Umożliwić push?
@ -1299,11 +1381,29 @@ 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.branch_protection=Ochrona gałęzi dla "<b>%s</b> settings.branch_protection=Ochrona gałęzi dla "<b>%s</b>
settings.protect_this_branch=Włącz ochronę gałęzi settings.protect_this_branch=Włącz ochronę gałęzi
settings.protect_this_branch_desc=Zapobiega usunięciu oraz ogranicza wypychanie i scalanie zmian do tej gałęzi.
settings.protect_disable_push=Wyłącz wypychanie
settings.protect_disable_push_desc=Wypychanie do tej gałęzi nie będzie możliwe.
settings.protect_enable_push=Włącz wypychanie
settings.protect_enable_push_desc=Każdy użytkownik z uprawnieniem zapisu będzie miał możliwość wypychania do tej gałęzi (oprócz wymuszonego wypchnięcia).
settings.protect_whitelist_committers=Wypychanie ograniczone białą listą
settings.protect_whitelist_committers_desc=Tylko dopuszczeni użytkownicy oraz zespoły będą miały możliwość wypychania zmian do tej gałęzi (oprócz wymuszenia wypchnięcia).
settings.protect_whitelist_deploy_keys=Biała lista kluczy wdrożeniowych z uprawnieniem zapisu do push'a
settings.protect_whitelist_users=Użytkownicy dopuszczeni do wypychania: settings.protect_whitelist_users=Użytkownicy dopuszczeni do wypychania:
settings.protect_whitelist_search_users=Szukaj użytkowników… settings.protect_whitelist_search_users=Szukaj użytkowników…
settings.protect_whitelist_teams=Zespoły dopuszczone do wypychania: settings.protect_whitelist_teams=Zespoły dopuszczone do wypychania:
settings.protect_whitelist_search_teams=Szukaj zespołów… settings.protect_whitelist_search_teams=Szukaj zespołów…
settings.protect_merge_whitelist_committers=Włącz dopuszczenie scalania
settings.protect_merge_whitelist_committers_desc=Zezwól jedynie dopuszczonym użytkownikom lub zespołom na scalanie Pull Requestów w tej gałęzi.
settings.protect_merge_whitelist_users=Użytkownicy dopuszczeni do scalania:
settings.protect_merge_whitelist_teams=Zespoły dopuszczone do scalania:
settings.protect_check_status_contexts=Włącz kontrolę stanu
settings.protect_check_status_contexts_desc=Wymagaj powodzenia kontroli stanów przed scalaniem Wybierz które kontrole stanów muszą zostać ukończone pomyślnie, zanim gałęzie będą mogły zostać scalone z gałęzią, która pokrywa się z tą zasadą. Kiedy włączone, commity muszą być najpierw przepchnięte do innej gałęzi, a następnie scalone lub przepchnięte bezpośrednio do gałęzi, która pokrywa się z tą zasadą po pomyślnej kontroli stanów. Jeżeli nie zostaną wybrane konteksty, ostatni commit musi zakończyć się powodzeniem niezależnie od kontekstu.
settings.protect_check_status_contexts_list=Kontrole stanów w poprzednim tygodniu dla tego repozytorium
settings.protect_required_approvals=Wymagane zatwierdzenia: settings.protect_required_approvals=Wymagane zatwierdzenia:
settings.protect_required_approvals_desc=Zezwól na scalanie Pull Requestów tylko z wystarczającą ilością pozytywnych recenzji.
settings.protect_approvals_whitelist_enabled=Ogranicz zatwierdzenia do dopuszczonych użytkowników i zespołów
settings.protect_approvals_whitelist_enabled_desc=Tylko recenzje pochodzące od użytkowników lub zespołów na białej liście będą liczyły się do wymaganych zatwierdzeń. Bez białej listy zatwierdzeń, recenzja od każdego użytkownika z uprawnieniem zapisu będzie liczyła się do wymaganych zatwierdzeń.
settings.protect_approvals_whitelist_users=Dopuszczeni recenzenci: settings.protect_approvals_whitelist_users=Dopuszczeni recenzenci:
settings.protect_approvals_whitelist_teams=Dopuszczone zespoły do recenzji: settings.protect_approvals_whitelist_teams=Dopuszczone zespoły do recenzji:
settings.add_protected_branch=Włącz ochronę settings.add_protected_branch=Włącz ochronę
@ -1312,6 +1412,7 @@ settings.update_protect_branch_success=Ochrona gałęzi dla gałęzi "%s" zosta
settings.remove_protected_branch_success=Ochrona gałęzi dla gałęzi "%s" została wyłączona. settings.remove_protected_branch_success=Ochrona gałęzi dla gałęzi "%s" została wyłączona.
settings.protected_branch_deletion=Wyłącz ochronę gałęzi settings.protected_branch_deletion=Wyłącz ochronę gałęzi
settings.protected_branch_deletion_desc=Wyłączenie ochrony gałęzi pozwoli użytkownikom z uprawnieniami zapisu do przekazywania zmian do gałęzi. Kontynuować? settings.protected_branch_deletion_desc=Wyłączenie ochrony gałęzi pozwoli użytkownikom z uprawnieniami zapisu do przekazywania zmian do gałęzi. Kontynuować?
settings.default_branch_desc=Wybierz domyślną gałąź repozytorium dla Pull Requestów i commitów kodu:
settings.choose_branch=Wybierz gałąź… settings.choose_branch=Wybierz gałąź…
settings.no_protected_branch=Nie ma chronionych gałęzi. settings.no_protected_branch=Nie ma chronionych gałęzi.
settings.edit_protected_branch=Zmień settings.edit_protected_branch=Zmień
@ -1322,12 +1423,40 @@ settings.archive.button=Zarchiwizuj repozytorium
settings.archive.header=Zarchiwizuj to repozytorium settings.archive.header=Zarchiwizuj to repozytorium
settings.archive.text=Zarchiwizowanie repozytorium sprawi, że będzie ono "tylko do odczytu". Zostanie ukryte z pulpitu, nie będzie możliwe commitowanie, otwieranie zgłoszeń, czy tworzenie Pull Requestów. settings.archive.text=Zarchiwizowanie repozytorium sprawi, że będzie ono "tylko do odczytu". Zostanie ukryte z pulpitu, nie będzie możliwe commitowanie, otwieranie zgłoszeń, czy tworzenie Pull Requestów.
settings.archive.success=Repozytorium zostało pomyślnie zarchiwizowane. settings.archive.success=Repozytorium zostało pomyślnie zarchiwizowane.
settings.archive.error=Wystąpił błąd przy próbie zarchiwizowania tego repozytorium. Sprawdź dziennik po więcej szczegółów.
settings.archive.error_ismirror=Nie możesz archiwizować kopii lustrzanej repozytorium.
settings.archive.branchsettings_unavailable=Ustawienia gałęzi nie są dostępne, kiedy repozytorium jest zarchiwizowane.
settings.unarchive.button=Przywróć repozytorium
settings.unarchive.header=Przywróć to repozytorium z archiwum
settings.unarchive.text=Przywrócenie repozytorium z archiwum ponownie umożliwi przyjmowanie commitów i przepchnięć, jak i nowych zgłoszeń oraz Pull Requestów.
settings.unarchive.success=Repozytorium zostało pomyślnie przywrócone z archiwum.
settings.unarchive.error=Wystąpił błąd przy próbie przywrócenia tego repozytorium z archiwum. Sprawdź dziennik po więcej szczegółów.
settings.update_avatar_success=Awatar repozytorium został zaktualizowany.
settings.lfs=LFS
settings.lfs_filelist=Pliki LFS przechowywane w tym repozytorium
settings.lfs_no_lfs_files=Brak plików LFS przechowywanych w tym repozytorium
settings.lfs_findcommits=Znajdź commity
settings.lfs_lfs_file_no_commits=Nie znaleziono commitów dla tego pliku LFS
settings.lfs_delete=Usuń plik LFS z OID %s
settings.lfs_delete_warning=Usunięcie pliku LFS może spowodować błędy typu 'obiekt nie istnieje' przy checkout'cie. Czy chcesz kontynuować?
settings.lfs_findpointerfiles=Znajdź pliki wskaźnika
settings.lfs_pointers.found=Znaleziono %d wskaźników blob - %d powiązanych, %d niepowiązanych (%d brakujących w magazynie danych)
settings.lfs_pointers.sha=SHA bloba
settings.lfs_pointers.oid=OID
settings.lfs_pointers.inRepo=W repozytorium
settings.lfs_pointers.exists=Istnieje w magazynie
settings.lfs_pointers.accessible=Dostępne dla użytkownika
settings.lfs_pointers.associateAccessible=Powiąż dostępne %d OID
diff.browse_source=Przeglądaj źródła diff.browse_source=Przeglądaj źródła
diff.parent=rodzic diff.parent=rodzic
diff.commit=commit diff.commit=commit
diff.git-notes=Notatki diff.git-notes=Notatki
diff.data_not_available=Informacje nt. zmian nie są dostępne diff.data_not_available=Informacje nt. zmian nie są dostępne
diff.options_button=Opcje porównania
diff.show_diff_stats=Pokaż statystyki
diff.download_patch=Ściągnij plik aktualizacji
diff.download_diff=Ściągnij plik porównania
diff.show_split_view=Widok podzielony diff.show_split_view=Widok podzielony
diff.show_unified_view=Zunifikowany widok diff.show_unified_view=Zunifikowany widok
diff.whitespace_button=Znaki białe diff.whitespace_button=Znaki białe
@ -1338,6 +1467,11 @@ diff.whitespace_ignore_at_eol=Ignoruj zmiany w znakach białych przy EOL
diff.stats_desc=<strong>%d zmienionych plików</strong> z <strong>%d dodań</strong> i <strong>%d usunięć</strong> diff.stats_desc=<strong>%d zmienionych plików</strong> z <strong>%d dodań</strong> i <strong>%d usunięć</strong>
diff.bin=BIN diff.bin=BIN
diff.view_file=Wyświetl plik diff.view_file=Wyświetl plik
diff.file_before=Przed
diff.file_after=Po
diff.file_image_width=Szerokość
diff.file_image_height=Wysokość
diff.file_byte_size=Rozmiar
diff.file_suppressed=Plik diff jest za duży diff.file_suppressed=Plik diff jest za duży
diff.too_many_files=Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików diff.too_many_files=Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików
diff.comment.placeholder=Zostaw komentarz diff.comment.placeholder=Zostaw komentarz
@ -1405,6 +1539,8 @@ branch.restore_failed=Nie udało się przywrócić gałęzi '%s'.
branch.protected_deletion_failed=Gałąź '%s' jest chroniona. Nie można jej usunąć. branch.protected_deletion_failed=Gałąź '%s' jest chroniona. Nie można jej usunąć.
branch.restore=Przywróć gałąź '%s' branch.restore=Przywróć gałąź '%s'
branch.download=Pobierz gałąź '%s' branch.download=Pobierz gałąź '%s'
branch.included_desc=Ta gałąź jest częścią domyślnej gałęzi
branch.included=Zawarte
topic.manage_topics=Zarządzaj tematami topic.manage_topics=Zarządzaj tematami
topic.done=Gotowe topic.done=Gotowe
@ -1428,6 +1564,7 @@ team_name=Nazwa zespołu
team_desc=Opis team_desc=Opis
team_name_helper=Nazwy zespołów powinny być krótkie i łatwe do zapamiętania. team_name_helper=Nazwy zespołów powinny być krótkie i łatwe do zapamiętania.
team_desc_helper=Opisz cel lub rolę zespołu. team_desc_helper=Opisz cel lub rolę zespołu.
team_access_desc=Dostęp do repozytorium
team_permission_desc=Uprawnienie team_permission_desc=Uprawnienie
team_unit_desc=Zezwól na dostęp do sekcji repozytoriów team_unit_desc=Zezwól na dostęp do sekcji repozytoriów
@ -1441,6 +1578,7 @@ settings.full_name=Imię i nazwisko
settings.website=Strona settings.website=Strona
settings.location=Lokalizacja settings.location=Lokalizacja
settings.permission=Uprawnienia settings.permission=Uprawnienia
settings.repoadminchangeteam=Administrator repozytorium może dać oraz usunąć dostęp zespołom
settings.visibility=Widoczność settings.visibility=Widoczność
settings.visibility.public=Publiczne settings.visibility.public=Publiczne
settings.visibility.limited=Ukryte (widoczność tylko dla zalogowanych użytkowników) settings.visibility.limited=Ukryte (widoczność tylko dla zalogowanych użytkowników)
@ -1473,6 +1611,8 @@ members.invite_now=Zaproś teraz
teams.join=Dołącz teams.join=Dołącz
teams.leave=Opuść teams.leave=Opuść
teams.can_create_org_repo=Tworzenie repozytoriów
teams.can_create_org_repo_helper=Członkowie mogą tworzyć nowe repozytoria w organizacji. Twórca otrzyma uprawnienia administracyjne do nowego repozytorium.
teams.read_access=Dostęp do odczytu teams.read_access=Dostęp do odczytu
teams.read_access_helper=Członkowie mogą wyświetlać i klonować repozytoria zespołów. teams.read_access_helper=Członkowie mogą wyświetlać i klonować repozytoria zespołów.
teams.write_access=Dostęp do zapisu teams.write_access=Dostęp do zapisu
@ -1492,12 +1632,24 @@ teams.delete_team_success=Zespół został usunięty.
teams.read_permission_desc=Ten zespół udziela dostępu <strong>z odczytem</strong>: członkowie mogą wyświetlać i klonować repozytoria zespołu. teams.read_permission_desc=Ten zespół udziela dostępu <strong>z odczytem</strong>: członkowie mogą wyświetlać i klonować repozytoria zespołu.
teams.write_permission_desc=Ten zespół udziela dostępu <strong>z zapisem</strong>: członkowie mogą wyświetlać i wypychać zmiany do repozytoriów zespołu. teams.write_permission_desc=Ten zespół udziela dostępu <strong>z zapisem</strong>: członkowie mogą wyświetlać i wypychać zmiany do repozytoriów zespołu.
teams.admin_permission_desc=Ten zespół udziela dostępu <strong>administratora</strong>: członkowie mogą wyświetlać i wypychać zmiany oraz dodawać współpracowników do repozytoriów zespołu. teams.admin_permission_desc=Ten zespół udziela dostępu <strong>administratora</strong>: członkowie mogą wyświetlać i wypychać zmiany oraz dodawać współpracowników do repozytoriów zespołu.
teams.create_repo_permission_desc=Dodatkowo, ten zespół otrzyma uprawnienie <strong>Tworzenie repozytoriów</strong>: jego członkowie mogą tworzyć nowe repozytoria w organizacji.
teams.repositories=Repozytoria zespołu teams.repositories=Repozytoria zespołu
teams.search_repo_placeholder=Szukaj repozytorium… teams.search_repo_placeholder=Szukaj repozytorium…
teams.remove_all_repos_title=Usuń wszystkie repozytoria zespołu
teams.remove_all_repos_desc=Usunie to wszystkie repozytoria przypisane do zespołu.
teams.add_all_repos_title=Dodaj wszystkie repozytoria
teams.add_all_repos_desc=Doda to wszystkie repozytoria organizacji do przypisanych repozytoriów zespołu.
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ć.
teams.add_duplicate_users=Użytkownik jest już członkiem zespołu. teams.add_duplicate_users=Użytkownik jest już członkiem zespołu.
teams.repos.none=Ten zespół nie ma dostępu do żadnego repozytorium. teams.repos.none=Ten zespół nie ma dostępu do żadnego repozytorium.
teams.members.none=Ten zespół nie ma żadnych członków. teams.members.none=Ten zespół nie ma żadnych członków.
teams.specific_repositories=Określone repozytoria
teams.specific_repositories_helper=Członkowie uzyskają dostęp wyłącznie do repozytoriów przypisanych do tego zespołu. Wybranie tej opcji <strong>nie</strong> usunie automatycznie repozytoriów dodanych przy pomocy <i>Wszystkie repozytoria</i>.
teams.all_repositories=Wszystkie repozytoria
teams.all_repositories_helper=Zespół ma dostęp do wszystkich repozytoriów. Wybranie tego <strong>doda wszystkie istniejące</strong> repozytoria do tego zespołu.
teams.all_repositories_read_permission_desc=Ten zespół nadaje uprawnienie <strong>Odczytu</strong> do <strong>wszystkich repozytoriów</strong>: jego członkowie mogą wyświetlać i klonować repozytoria.
teams.all_repositories_write_permission_desc=Ten zespół nadaje uprawnienie <strong>Zapisu</strong> do <strong>wszystkich repozytoriów</strong>: jego członkowie mogą odczytywać i przesyłać do repozytoriów.
teams.all_repositories_admin_permission_desc=Ten zespół nadaje uprawnienia <strong>Administratora</strong> do <strong>wszystkich repozytoriów</strong>: jego członkowie mogą odczytywać, przesyłać oraz dodawać innych współtwórców do repozytoriów.
[admin] [admin]
dashboard=Pulpit dashboard=Pulpit
@ -1590,6 +1742,7 @@ users.auth_login_name=Nazwa logowania uwierzytelnienia
users.password_helper=Pozostaw hasło puste, aby go nie zmieniać. users.password_helper=Pozostaw hasło puste, aby go nie zmieniać.
users.update_profile_success=Konto użytkownika zostało zaktualizowane. users.update_profile_success=Konto użytkownika zostało zaktualizowane.
users.edit_account=Edytuj konto użytkownika users.edit_account=Edytuj konto użytkownika
users.max_repo_creation=Maksymalna ilość repozytoriów
users.max_repo_creation_desc=(Wpisz -1, aby użyć domyślnego globalnego limitu.) users.max_repo_creation_desc=(Wpisz -1, aby użyć domyślnego globalnego limitu.)
users.is_activated=Konto użytkownika jest aktywne users.is_activated=Konto użytkownika jest aktywne
users.prohibit_login=Wyłącz logowanie users.prohibit_login=Wyłącz logowanie
@ -1671,6 +1824,15 @@ auths.oauth2_authURL=URL autoryzacji
auths.oauth2_profileURL=URL profilu auths.oauth2_profileURL=URL profilu
auths.oauth2_emailURL=URL adresu e-mail auths.oauth2_emailURL=URL adresu e-mail
auths.enable_auto_register=Włącz automatyczną rejestrację auths.enable_auto_register=Włącz automatyczną rejestrację
auths.sspi_auto_create_users=Automatycznie twórz użytkowników
auths.sspi_auto_create_users_helper=Zezwól metodzie uwierzytelniania SSPI na automatyczne tworzenie nowych kont dla użytkowników, którzy logują się po raz pierwszy
auths.sspi_auto_activate_users=Automatycznie aktywuj użytkowników
auths.sspi_auto_activate_users_helper=Zezwól metodzie uwierzytelnienia SSPI na automatyczne aktywowanie nowych kont użytkowników
auths.sspi_strip_domain_names=Usuwaj nazwy domen z nazw użytkowników
auths.sspi_strip_domain_names_helper=Gdy zaznaczone, nazwy domen będą usuwane z nazw logowania (np. zamiast "DOMENA\osoba", czy osoba@example.org" będą po prostu "osoba").
auths.sspi_separator_replacement=Używany separator zamiast \, / oraz @
auths.sspi_default_language=Domyślny język użytkownika
auths.sspi_default_language_helper=Domyślny język dla użytkowników automatycznie stworzonych przy pomocy metody uwierzytelnienia SSPI. Pozostaw puste, jeśli język ma zostać wykryty automatycznie.
auths.tips=Wskazówki auths.tips=Wskazówki
auths.tips.oauth2.general=Uwierzytelnianie OAuth2 auths.tips.oauth2.general=Uwierzytelnianie OAuth2
auths.tips.oauth2.general.tip=Przy rejestracji nowego uwierzytelnienia OAuth2, URL zwrotny/przekierowań powinien mieć postać <serwer>/user/oauth2/<nazwa uwierzytelnienia>/callback auths.tips.oauth2.general.tip=Przy rejestracji nowego uwierzytelnienia OAuth2, URL zwrotny/przekierowań powinien mieć postać <serwer>/user/oauth2/<nazwa uwierzytelnienia>/callback
@ -1684,6 +1846,7 @@ auths.tip.google_plus=Uzyskaj dane uwierzytelniające klienta OAuth2 z konsoli G
auths.tip.openid_connect=Użyj adresu URL OpenID Connect Discovery (<server>/.well-known/openid-configuration), aby określić punkty końcowe auths.tip.openid_connect=Użyj adresu URL OpenID Connect Discovery (<server>/.well-known/openid-configuration), aby określić punkty końcowe
auths.tip.twitter=Przejdź na https://dev.twitter.com/apps, stwórz aplikację i upewnij się, że opcja “Allow this application to be used to Sign in with Twitter” jest włączona auths.tip.twitter=Przejdź na https://dev.twitter.com/apps, stwórz aplikację i upewnij się, że opcja “Allow this application to be used to Sign in with Twitter” jest włączona
auths.tip.discord=Zarejestruj nową aplikację na https://discordapp.com/developers/applications/me auths.tip.discord=Zarejestruj nową aplikację na https://discordapp.com/developers/applications/me
auths.tip.gitea=Zarejestruj nową aplikację OAuth2. Przewodnik można znaleźć na https://docs.gitea.io/en-us/oauth2-provider/
auths.edit=Edytuj źródło uwierzytelniania auths.edit=Edytuj źródło uwierzytelniania
auths.activated=To źródło uwierzytelniania jest aktywne auths.activated=To źródło uwierzytelniania jest aktywne
auths.new_success=Uwierzytelnienie '%s' zostało dodane. auths.new_success=Uwierzytelnienie '%s' zostało dodane.
@ -1692,6 +1855,10 @@ auths.update=Zaktualizuj źródło uwierzytelniania
auths.delete=Usuń źródło uwierzytelniania auths.delete=Usuń źródło uwierzytelniania
auths.delete_auth_title=Usuń źródło uwierzytelniania auths.delete_auth_title=Usuń źródło uwierzytelniania
auths.delete_auth_desc=Usunięcie źródła uwierzytelniania uniemożliwi użytkownikom używania go do zalogowania się. Kontynuować? auths.delete_auth_desc=Usunięcie źródła uwierzytelniania uniemożliwi użytkownikom używania go do zalogowania się. Kontynuować?
auths.still_in_used=Źródło uwierzytelniania jest wciąż w użyciu. Przekonwertuj lub usuń użytkowników przed użyciem tego źródła uwierzytelniania.
auths.deletion_success=Źródło uwierzytelniania zostało usunięte.
auths.login_source_exist=Źródło uwierzytelniania '%s' już istnieje.
auths.login_source_of_type_exist=Źródło uwierzytelniania tego typu już istnieje.
config.server_config=Konfiguracja serwera config.server_config=Konfiguracja serwera
config.app_name=Tytuł strony config.app_name=Tytuł strony
@ -1727,6 +1894,7 @@ config.ssh_minimum_key_sizes=Minimalne rozmiary kluczy
config.lfs_config=Konfiguracja LFS config.lfs_config=Konfiguracja LFS
config.lfs_enabled=Włączone config.lfs_enabled=Włączone
config.lfs_content_path=Ścieżka zawartości LFS config.lfs_content_path=Ścieżka zawartości LFS
config.lfs_http_auth_expiry=Wygasanie uwierzytelnienia LFS HTTP
config.db_config=Konfiguracja bazy danych config.db_config=Konfiguracja bazy danych
config.db_type=Typ config.db_type=Typ
@ -1737,16 +1905,33 @@ 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.register_email_confirm=Wymagaj potwierdzenia adresu e-mail przy rejestracji
config.disable_register=Wyłącz samodzielną rejestrację
config.allow_only_external_registration=Zezwól na rejestrację wyłącznie za pomocą zewnętrznych usług
config.enable_openid_signup=Włącz samodzielną rejestrację za pomocą OpenID
config.enable_openid_signin=Włącz logowanie za pomocą OpenID
config.show_registration_button=Pokazuj przycisk rejestracji config.show_registration_button=Pokazuj przycisk rejestracji
config.require_sign_in_view=Wymagaj zalogowania w celu wyświetlania stron
config.mail_notify=Włącz powiadomienia e-mail
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.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 przywracania konta
config.default_keep_email_private=Domyślne ukrywanie adresów e-mail
config.default_allow_create_organization=Domyślnie zezwalaj na tworzenie organizacji
config.enable_timetracking=Włącz śledzenie czasu
config.default_enable_timetracking=Domyślnie włącz śledzenie czasu
config.default_allow_only_contributors_to_track_time=Zezwalaj wyłącznie współpracownikom na śledzenie czasu
config.no_reply_address=Ukryta domena e-mail
config.default_visibility_organization=Domyślna widoczność dla nowych organizacji
config.default_enable_dependencies=Domyślne włączanie zależności zgłoszeń
config.webhook_config=Konfiguracja webhooka config.webhook_config=Konfiguracja webhooka
config.queue_length=Długość kolejki config.queue_length=Długość kolejki
config.deliver_timeout=Limit czasu doręczenia config.deliver_timeout=Limit czasu doręczenia
config.skip_tls_verify=Pomiń weryfikację TLS config.skip_tls_verify=Pomiń weryfikację TLS
config.mailer_config=Konfiguracja dostawcy SMTP
config.mailer_enabled=Włączona config.mailer_enabled=Włączona
config.mailer_disable_helo=Wyłącz HELO config.mailer_disable_helo=Wyłącz HELO
config.mailer_name=Nazwa config.mailer_name=Nazwa
@ -1754,6 +1939,9 @@ config.mailer_host=Serwer
config.mailer_user=Użytkownik config.mailer_user=Użytkownik
config.mailer_use_sendmail=Używaj Sendmail config.mailer_use_sendmail=Używaj Sendmail
config.mailer_sendmail_path=Ścieżka Sendmail config.mailer_sendmail_path=Ścieżka Sendmail
config.mailer_sendmail_args=Dodatkowe argumenty Sendmail
config.send_test_mail=Wyślij testową wiadomość e-mail
config.test_mail_failed=Nie udało się wysłać testowej wiadomości e-mail do '%s': %v
config.test_mail_sent=Testowa wiadomość e-mail została wysłana do '%s'. config.test_mail_sent=Testowa wiadomość e-mail została wysłana do '%s'.
config.oauth_config=Konfiguracja OAuth config.oauth_config=Konfiguracja OAuth
@ -1763,6 +1951,7 @@ config.cache_config=Konfiguracja pamięci podręcznej
config.cache_adapter=Adapter pamięci podręcznej config.cache_adapter=Adapter pamięci podręcznej
config.cache_interval=Interwał pamięci podręcznej config.cache_interval=Interwał pamięci podręcznej
config.cache_conn=Połączenie z pamięcią podręczną config.cache_conn=Połączenie z pamięcią podręczną
config.cache_item_ttl=TTL składnika pamięci podręcznej
config.session_config=Konfiguracja sesji config.session_config=Konfiguracja sesji
config.session_provider=Dostawca sesji config.session_provider=Dostawca sesji
@ -1774,6 +1963,7 @@ config.session_life_time=Czas ważności sesji
config.https_only=Tylko HTTPS config.https_only=Tylko HTTPS
config.cookie_life_time=Czas ważności ciasteczka config.cookie_life_time=Czas ważności ciasteczka
config.picture_config=Konfiguracja obrazu i awataru
config.picture_service=Usługa obrazów config.picture_service=Usługa obrazów
config.disable_gravatar=Wyłącz Gravatar config.disable_gravatar=Wyłącz Gravatar
config.enable_federated_avatar=Włącz sfederowane awatary config.enable_federated_avatar=Włącz sfederowane awatary
@ -1792,6 +1982,9 @@ config.git_gc_timeout=Limit czasu usuwania śmieci
config.log_config=Konfiguracja dziennika config.log_config=Konfiguracja dziennika
config.log_mode=Tryb dziennika config.log_mode=Tryb dziennika
config.macaron_log_mode=Tryb dziennika Macaron
config.own_named_logger=Nazwany logger
config.routes_to_default_logger=Ścieżki do domyślnego loggera
config.go_log=Używa dziennika Go (domyślne przekierowanie) config.go_log=Używa dziennika Go (domyślne przekierowanie)
config.router_log_mode=Tryb dziennika routera config.router_log_mode=Tryb dziennika routera
config.disabled_logger=Wyłączone config.disabled_logger=Wyłączone
@ -1810,6 +2003,9 @@ monitor.process=Uruchomione procesy
monitor.desc=Opis monitor.desc=Opis
monitor.start=Czas rozpoczęcia monitor.start=Czas rozpoczęcia
monitor.execute_time=Czas wykonania monitor.execute_time=Czas wykonania
monitor.process.cancel=Anuluj proces
monitor.process.cancel_desc=Anulowanie procesu może spowodować utratę danych
monitor.process.cancel_notices=Anuluj: <strong>%s</strong>?
notices.system_notice_list=Powiadomienia systemu notices.system_notice_list=Powiadomienia systemu
notices.view_detail_header=Pokaż szczegóły powiadomienia notices.view_detail_header=Pokaż szczegóły powiadomienia
@ -1846,6 +2042,8 @@ compare_commits_general=Porównaj commity
mirror_sync_push=synchronizuje commity do <a href="%[1]s/src/%[2]s">%[3]s</a> w <a href="%[1]s">%[4]s</a> z kopii lustrzanej mirror_sync_push=synchronizuje commity do <a href="%[1]s/src/%[2]s">%[3]s</a> w <a href="%[1]s">%[4]s</a> z kopii lustrzanej
mirror_sync_create=synchronizuje nowe odwołanie <a href="%s/src/%s">%[2]s</a> do <a href="%[1]s">%[3]s</a> z kopii lustrzanej mirror_sync_create=synchronizuje nowe odwołanie <a href="%s/src/%s">%[2]s</a> do <a href="%[1]s">%[3]s</a> z kopii lustrzanej
mirror_sync_delete=synchronizuje i usuwa odwołanie <code>%[2]s</code> w <a href="%[1]s">%[3]s</a> z kopii lustrzanej mirror_sync_delete=synchronizuje i usuwa odwołanie <code>%[2]s</code> w <a href="%[1]s">%[3]s</a> z kopii lustrzanej
approve_pull_request=`zatwierdził(-a) <a href="%s/pulls/%s">%s#%[2]s</a>`
reject_pull_request=`zaproponował(-a) zmiany dla <a href="%s/pulls/%s">%s#%[2]s</a>`
[tool] [tool]
ago=%s temu ago=%s temu
@ -1887,12 +2085,15 @@ mark_as_unread=Oznacz jak nieprzeczytane
mark_all_as_read=Oznacz wszystkie jako przeczytane mark_all_as_read=Oznacz wszystkie jako przeczytane
[gpg] [gpg]
default_key=Podpisano domyślnym kluczem
error.extract_sign=Nie udało się wyłuskać podpisu error.extract_sign=Nie udało się wyłuskać podpisu
error.generate_hash=Nie udało się wygenerować skrótu dla commitu error.generate_hash=Nie udało się wygenerować skrótu dla commitu
error.no_committer_account=Brak konta powiązanego z adresem e-mail autora error.no_committer_account=Brak konta powiązanego z adresem e-mail autora
error.no_gpg_keys_found=Nie znaleziono w bazie danych klucza dla tego podpisu error.no_gpg_keys_found=Nie znaleziono w bazie danych klucza dla tego podpisu
error.not_signed_commit=Commit nie podpisany error.not_signed_commit=Commit nie podpisany
error.failed_retrieval_gpg_keys=Nie udało się odzyskać żadnego klucza powiązanego z kontem autora error.failed_retrieval_gpg_keys=Nie udało się odzyskać żadnego klucza powiązanego z kontem autora
error.probable_bad_signature=OSTRZEŻENIE! Pomimo istnienia klucza z takim ID w bazie, nie weryfikuje on tego commita! Ten commit jest PODEJRZANY.
error.probable_bad_default_signature=OSTRZEŻENIE! Pomimo, że domyślny klucz posiada to ID, nie weryfikuje on tego commita! Ten commit jest PODEJRZANY.
[units] [units]
error.no_unit_allowed_repo=Nie masz uprawnień do żadnej sekcji tego repozytorium. error.no_unit_allowed_repo=Nie masz uprawnień do żadnej sekcji tego repozytorium.

View file

@ -959,6 +959,7 @@ issues.add_time=Adicionar tempo manualmente
issues.add_time_short=Adicionar tempo issues.add_time_short=Adicionar tempo
issues.add_time_cancel=Cancelar issues.add_time_cancel=Cancelar
issues.add_time_history=`adicionou tempo gasto %s` issues.add_time_history=`adicionou tempo gasto %s`
issues.del_time_history=`removeu tempo gasto %s`
issues.add_time_hours=Horas issues.add_time_hours=Horas
issues.add_time_minutes=Minutos issues.add_time_minutes=Minutos
issues.add_time_sum_to_small=Nenhum tempo foi inserido. issues.add_time_sum_to_small=Nenhum tempo foi inserido.
@ -1016,7 +1017,7 @@ issues.review.content.empty=Você precisa deixar um comentário indicando as alt
issues.review.reject=alterações solicitadas %s issues.review.reject=alterações solicitadas %s
issues.review.pending=Pendente issues.review.pending=Pendente
issues.review.review=Revisão issues.review.review=Revisão
issues.review.reviewers=Revisões issues.review.reviewers=Revisores
issues.review.show_outdated=Mostrar desatualizado issues.review.show_outdated=Mostrar desatualizado
issues.review.hide_outdated=Ocultar desatualizado issues.review.hide_outdated=Ocultar desatualizado
issues.assignee.error=Nem todos os responsáveis foram adicionados devido a um erro inesperado. issues.assignee.error=Nem todos os responsáveis foram adicionados devido a um erro inesperado.
@ -1052,6 +1053,7 @@ pulls.is_checking=Verificação de conflitos do merge está em andamento. Tente
pulls.required_status_check_failed=Algumas verificações necessárias não foram bem sucedidas. pulls.required_status_check_failed=Algumas verificações necessárias não foram bem sucedidas.
pulls.required_status_check_administrator=Como administrador, você ainda pode aplicar o merge deste pull request. pulls.required_status_check_administrator=Como administrador, você ainda pode aplicar o merge deste pull request.
pulls.blocked_by_approvals=Este pull request ainda não possui aprovações suficientes. %d de %d aprovações concedidas. pulls.blocked_by_approvals=Este pull request ainda não possui aprovações suficientes. %d de %d aprovações concedidas.
pulls.blocked_by_rejection=Este pull request possui alterações solicitadas por um revisor oficial.
pulls.can_auto_merge_desc=O merge deste pull request pode ser aplicado automaticamente. pulls.can_auto_merge_desc=O merge deste pull request pode ser aplicado automaticamente.
pulls.cannot_auto_merge_desc=O merge deste pull request não pode ser aplicado automaticamente pois há conflitos. pulls.cannot_auto_merge_desc=O merge deste pull request não pode ser aplicado automaticamente pois há conflitos.
pulls.cannot_auto_merge_helper=Faça o merge manualmente para resolver os conflitos. pulls.cannot_auto_merge_helper=Faça o merge manualmente para resolver os conflitos.
@ -1415,6 +1417,8 @@ settings.update_protect_branch_success=Proteção do branch '%s' foi atualizada.
settings.remove_protected_branch_success=Proteção do branch '%s' foi desabilitada. settings.remove_protected_branch_success=Proteção do branch '%s' foi desabilitada.
settings.protected_branch_deletion=Desabilitar proteção de branch settings.protected_branch_deletion=Desabilitar proteção de branch
settings.protected_branch_deletion_desc=Desabilitar a proteção de branch permite que os usuários com permissão de escrita realizem push. Continuar? settings.protected_branch_deletion_desc=Desabilitar a proteção de branch permite que os usuários com permissão de escrita realizem push. Continuar?
settings.block_rejected_reviews=Bloquear merge em revisões rejeitadas
settings.block_rejected_reviews_desc=O merge não será possível quando são solicitadas alterações pelos revisores oficiais, mesmo que haja aprovação suficiente.
settings.default_branch_desc=Selecione um branch padrão para pull requests e commits de código: settings.default_branch_desc=Selecione um branch padrão para pull requests e commits de código:
settings.choose_branch=Escolha um branch... settings.choose_branch=Escolha um branch...
settings.no_protected_branch=Não há branches protegidos. settings.no_protected_branch=Não há branches protegidos.

View file

@ -66,14 +66,28 @@ forks=Форки
activities=Активность activities=Активность
pull_requests=Pull Request'ы pull_requests=Pull Request'ы
issues=Задачи issues=Задачи
milestones=Этапы
cancel=Отмена cancel=Отмена
add=Добавить
add_all=Добавить все
remove=Удалить
remove_all=Удалить все
write=Редактирование write=Редактирование
preview=Предпросмотр preview=Предпросмотр
loading=Загрузка… loading=Загрузка…
[startpage] [startpage]
app_desc=Удобный сервис собственного хостинга репозиториев Git
install=Простой в установке
install_desc=Просто <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/install-from-binary/">запустите исполняемый файл</a> для вашей платформы. Иcпользуйте 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>.
platform=Кроссплатформенный
platform_desc=Gitea работает на любой операционной системе, которая может компилировать <a target="_blank" rel="noopener noreferrer" href="http://golang.org/">Go</a>: Windows, macOS, Linux, ARM и т. д. Выбирайте, что вам больше нравится!
lightweight=Легковесный
lightweight_desc=Gitea имеет низкие системные требования и может работать на недорогом Raspberry Pi. Экономьте энергию вашей машины!
license=Открытый исходный код
license_desc=Всё это на <a target="_blank" rel="noopener noreferrer" href="https://code.gitea.io/gitea">code.gitea.io/gitea</a>! Присоединяйтесь к нам, внося <a target="_blank" rel="noopener noreferrer" href="https://github.com/go-gitea/gitea">вклад</a>, чтобы сделать этот проект еще лучше. Не бойтесь помогать!
[install] [install]
install=Установка install=Установка
@ -236,6 +250,10 @@ twofa_scratch_token_incorrect=Неверный scratch-код.
login_userpass=Вход login_userpass=Вход
login_openid=OpenID login_openid=OpenID
oauth_signup_tab=Зарегистрировать новый аккаунт oauth_signup_tab=Зарегистрировать новый аккаунт
oauth_signup_title=Добавить адрес электронной почты и пароль (для восстановления учетной записи)
oauth_signup_submit=Полная учетная запись
oauth_signin_tab=Ссылка на существующую учетную запись
oauth_signin_title=Войдите, чтобы авторизовать связанную учетную запись
oauth_signin_submit=Привязать учетную запись oauth_signin_submit=Привязать учетную запись
openid_connect_submit=Подключить openid_connect_submit=Подключить
openid_connect_title=Подключение к существующей учетной записи openid_connect_title=Подключение к существующей учетной записи
@ -244,7 +262,9 @@ openid_register_title=Создать новый аккаунт
openid_register_desc=Выбранный OpenID URI неизвестен. Свяжите с новой учетной записью здесь. openid_register_desc=Выбранный OpenID URI неизвестен. Свяжите с новой учетной записью здесь.
openid_signin_desc=Введите свой OpenID URI. Например: https://anne.me, bob.openid.org.cn или gnusocial.net/carry. openid_signin_desc=Введите свой OpenID URI. Например: https://anne.me, bob.openid.org.cn или gnusocial.net/carry.
disable_forgot_password_mail=Восстановление аккаунта отключено. Пожалуйста, свяжитесь с администратором сайта. disable_forgot_password_mail=Восстановление аккаунта отключено. Пожалуйста, свяжитесь с администратором сайта.
email_domain_blacklisted=С данным email регистрация невозможна.
authorize_application=Авторизация приложения authorize_application=Авторизация приложения
authorize_redirect_notice=Вы будете перенаправлены на %s, если вы авторизуете это приложение.
authorize_application_created_by=Это приложение было создано %s. authorize_application_created_by=Это приложение было создано %s.
authorize_application_description=Если вы предоставите доступ, оно сможет получить доступ и редактировать любую информацию о вашей учетной записи, включая содержимое частных репозиториев и организаций. authorize_application_description=Если вы предоставите доступ, оно сможет получить доступ и редактировать любую информацию о вашей учетной записи, включая содержимое частных репозиториев и организаций.
authorize_title=Разрешить «%s» доступ к вашей учетной записи? authorize_title=Разрешить «%s» доступ к вашей учетной записи?
@ -283,6 +303,8 @@ CommitChoice=Выбор коммита
TreeName=Путь к файлу TreeName=Путь к файлу
Content=Содержимое Content=Содержимое
SSPISeparatorReplacement=Разделитель
SSPIDefaultLanguage=Язык по умолчанию
require_error=` не может быть пустым.` require_error=` не может быть пустым.`
alpha_dash_error=` должен содержать только буквенно-цифровые символы, тире (' - ') и подчеркивания ('_').` alpha_dash_error=` должен содержать только буквенно-цифровые символы, тире (' - ') и подчеркивания ('_').`
@ -297,6 +319,7 @@ include_error=` должен содержать '%s'.`
unknown_error=Неизвестная ошибка: unknown_error=Неизвестная ошибка:
captcha_incorrect=Капча не пройдена. captcha_incorrect=Капча не пройдена.
password_not_match=Пароли не совпадают. password_not_match=Пароли не совпадают.
lang_select_error=Выберите язык из списка.
username_been_taken=Имя пользователя уже занято. username_been_taken=Имя пользователя уже занято.
repo_name_been_taken=Имя репозитория уже используется. repo_name_been_taken=Имя репозитория уже используется.
@ -308,10 +331,15 @@ team_no_units_error=Разрешите доступ хотя бы к одном
email_been_used=Этот адрес электронной почты уже используется. email_been_used=Этот адрес электронной почты уже используется.
openid_been_used=Адрес OpenID '%s' уже используется. openid_been_used=Адрес OpenID '%s' уже используется.
username_password_incorrect=Неверное имя пользователя или пароль. username_password_incorrect=Неверное имя пользователя или пароль.
password_lowercase_one=Как минимум один строчный символ
password_uppercase_one=Как минимум один заглавный символ
password_digit_one=По крайней мере одна цифра
password_special_one=По крайней мере один специальный символ (знаки пунктуации, скобки, кавычки и т. д.)
enterred_invalid_repo_name=Введенное вами имя репозитория неверно. enterred_invalid_repo_name=Введенное вами имя репозитория неверно.
enterred_invalid_owner_name=Имя нового владельца недоступно. enterred_invalid_owner_name=Имя нового владельца недоступно.
enterred_invalid_password=Введенный пароль неверный. enterred_invalid_password=Введенный пароль неверный.
user_not_exist=Пользователь не существует. user_not_exist=Пользователь не существует.
team_not_exist=Команда не существует.
last_org_owner=Вы не можете удалить последнего пользователя из команды 'владельцы'. В любой команде должен быть хотя бы один владелец. last_org_owner=Вы не можете удалить последнего пользователя из команды 'владельцы'. В любой команде должен быть хотя бы один владелец.
cannot_add_org_to_team=Организацию нельзя добавить в качестве члена команды. cannot_add_org_to_team=Организацию нельзя добавить в качестве члена команды.
@ -479,8 +507,12 @@ access_token_deletion_desc=Удаление токена отменит дост
delete_token_success=Токен удалён. Приложения, использующие его, больше не имеют доступа к вашему аккаунту. delete_token_success=Токен удалён. Приложения, использующие его, больше не имеют доступа к вашему аккаунту.
manage_oauth2_applications=Управление приложениями OAuth2 manage_oauth2_applications=Управление приложениями OAuth2
edit_oauth2_application=Изменить OAuth2 приложение
oauth2_applications_desc=Приложения OAuth2 позволяет стороннему приложению к безопасно аутентифицировать пользователей данной установки Gitea.
remove_oauth2_application=Удалить OAuth2 приложение remove_oauth2_application=Удалить OAuth2 приложение
remove_oauth2_application_desc=Удаление приложения OAuth2 отменит доступ ко всем подписанным токенам доступа. Продолжить?
remove_oauth2_application_success=Приложение было удалено. remove_oauth2_application_success=Приложение было удалено.
create_oauth2_application=Создать новое OAuth2 приложение
create_oauth2_application_button=Создать приложение create_oauth2_application_button=Создать приложение
create_oauth2_application_success=Вы успешно создали новое приложение OAuth2. create_oauth2_application_success=Вы успешно создали новое приложение OAuth2.
update_oauth2_application_success=Изменения настроек приложения OAuth2 успешно применены. update_oauth2_application_success=Изменения настроек приложения OAuth2 успешно применены.
@ -490,14 +522,20 @@ oauth2_type_web=Веб (например: Node.JS, Tomcat, Go)
oauth2_type_native=Нативный (например: телефон, ПК, браузер) oauth2_type_native=Нативный (например: телефон, ПК, браузер)
oauth2_redirect_uri=URI переадресации oauth2_redirect_uri=URI переадресации
save_application=Сохранить save_application=Сохранить
oauth2_client_id=ID клиента
oauth2_client_secret=Клиентский ключ oauth2_client_secret=Клиентский ключ
oauth2_regenerate_secret=Сгенерировать новый ключ oauth2_regenerate_secret=Сгенерировать новый ключ
oauth2_regenerate_secret_hint=Потеряли свой ключ? oauth2_regenerate_secret_hint=Потеряли свой ключ?
oauth2_client_secret_hint=Секретный ключ не будет показан, если вы повторно откроете эту страницу. Пожалуйста сохраните секретный ключ. oauth2_client_secret_hint=Секретный ключ не будет показан, если вы повторно откроете эту страницу. Пожалуйста сохраните секретный ключ.
oauth2_application_edit=Изменить
oauth2_application_create_description=Приложения OAuth2 предоставляет стороннему приложению доступ к учетным записям пользователей данного сервиса.
oauth2_application_remove_description=Удаление приложения OAuth2 приведёт к отмене его доступа к авторизованным учетным записям пользователей в данном экземпляре. Продолжить?
authorized_oauth2_applications=Авторизованные приложения OAuth2 authorized_oauth2_applications=Авторизованные приложения OAuth2
authorized_oauth2_applications_description=Вы предоставили доступ к вашему персональному аккаунту Gitea этим сторонним приложениям. Пожалуйста, отзовите доступ у приложений, которые больше не используются.
revoke_key=Отозвать revoke_key=Отозвать
revoke_oauth2_grant=Отозвать доступ revoke_oauth2_grant=Отозвать доступ
revoke_oauth2_grant_description=Отзыв доступа у этого стороннего приложения не позволит ему получать доступ к вашим данным. Вы уверены?
revoke_oauth2_grant_success=Вы успешно отозвали доступ. revoke_oauth2_grant_success=Вы успешно отозвали доступ.
twofa_desc=Двухфакторная проверка подлинности повышает уровень безопасности вашей учётной записи. twofa_desc=Двухфакторная проверка подлинности повышает уровень безопасности вашей учётной записи.
@ -541,12 +579,22 @@ confirm_delete_account=Подтвердите удаление
delete_account_title=Удалить аккаунт delete_account_title=Удалить аккаунт
delete_account_desc=Вы уверены, что хотите навсегда удалить этот аккаунт? delete_account_desc=Вы уверены, что хотите навсегда удалить этот аккаунт?
email_notifications.enable=Включить почтовые уведомления
email_notifications.onmention=Только уведомлять по почте при упоминании
email_notifications.disable=Отключить почтовые уведомления
email_notifications.submit=Установить настройки электронной почты
[repo] [repo]
owner=Владелец owner=Владелец
repo_name=Имя репозитория repo_name=Имя репозитория
repo_name_helper=Лучшие названия репозиториев состоят из коротких, легко запоминаемых и уникальных ключевых слов. repo_name_helper=Лучшие названия репозиториев состоят из коротких, легко запоминаемых и уникальных ключевых слов.
repo_size=Размер репозитория
template=Шаблон
template_select=Выбрать шаблон.
template_helper=Сделать репозиторий шаблоном
template_description=Шаблонные репозитории дают возможность пользователям создавать новые репозитории с той же структурой каталогов, файлами и дополнительными настройками.
visibility=Видимость visibility=Видимость
visibility_description=Только владелец или члены организации, при наличии прав, смогут увидеть это.
visibility_helper=Сделать репозиторий приватным visibility_helper=Сделать репозиторий приватным
visibility_helper_forced=Администратор сайта настроил параметр видимости новых репозиториев. Репозиторий приватный по умолчанию. visibility_helper_forced=Администратор сайта настроил параметр видимости новых репозиториев. Репозиторий приватный по умолчанию.
visibility_fork_helper=(Изменение этого повлияет на все форки.) visibility_fork_helper=(Изменение этого повлияет на все форки.)
@ -554,9 +602,12 @@ clone_helper=Нужна помощь в клонировании? Посетит
fork_repo=Форкнуть репозиторий fork_repo=Форкнуть репозиторий
fork_from=Форк от fork_from=Форк от
fork_visibility_helper=Видимость форкнутого репозитория изменить нельзя. fork_visibility_helper=Видимость форкнутого репозитория изменить нельзя.
use_template=Использовать этот шаблон
generate_repo=Создать репозиторий
repo_desc=Описание repo_desc=Описание
repo_lang=Язык repo_lang=Язык
repo_gitignore_helper=Выберите шаблон .gitignore. repo_gitignore_helper=Выберите шаблон .gitignore.
issue_labels=Метки задач
license=Лицензия license=Лицензия
license_helper=Выберите файл лицензии. license_helper=Выберите файл лицензии.
readme=README readme=README
@ -569,6 +620,8 @@ mirror_prune_desc=Удаление устаревших отслеживаемы
mirror_interval=Интервал зеркалирования (допустимые единицы измерения 'h', 'm', 's'). Значение 0 отключает синхронизацию. mirror_interval=Интервал зеркалирования (допустимые единицы измерения 'h', 'm', 's'). Значение 0 отключает синхронизацию.
mirror_interval_invalid=Недопустимый интервал зеркалирования. mirror_interval_invalid=Недопустимый интервал зеркалирования.
mirror_address=Клонировать по URL mirror_address=Клонировать по URL
mirror_address_url_invalid=Указанный url неверный. Вы должны правильно экранировать все компоненты url.
mirror_address_protocol_invalid=Указанный url неверный. Только http(s):// или git:// местоположения могут быть зеркалированы.
mirror_last_synced=Последняя синхронизация mirror_last_synced=Последняя синхронизация
watchers=Наблюдатели watchers=Наблюдатели
stargazers=Звездочеты stargazers=Звездочеты
@ -576,6 +629,11 @@ forks=Форки
pick_reaction=Оставьте свою оценку! pick_reaction=Оставьте свою оценку!
reactions_more=и ещё %d reactions_more=и ещё %d
template.git_hooks=Git хуки
template.webhooks=Веб-хуки
template.topics=Темы
template.avatar=Аватар
template.issue_labels=Метки задач
archive.title=Это архивный репозиторий. Вы можете его клонировать или просматривать файлы, но не вносить изменения или открывать задачи/запросы на слияние. archive.title=Это архивный репозиторий. Вы можете его клонировать или просматривать файлы, но не вносить изменения или открывать задачи/запросы на слияние.
archive.issue.nocomment=Этот репозиторий в архиве. Вы не можете комментировать задачи. archive.issue.nocomment=Этот репозиторий в архиве. Вы не можете комментировать задачи.
@ -588,6 +646,7 @@ form.name_pattern_not_allowed=Шаблон имени репозитория '%s
need_auth=Требуется авторизация need_auth=Требуется авторизация
migrate_type=Тип миграции migrate_type=Тип миграции
migrate_type_helper=Этот репозиторий будет <span class="text blue">зеркалом</span> migrate_type_helper=Этот репозиторий будет <span class="text blue">зеркалом</span>
migrate_items=Элементы миграции
migrate_items_wiki=Вики migrate_items_wiki=Вики
migrate_items_milestones=Этапы migrate_items_milestones=Этапы
migrate_items_labels=Метки migrate_items_labels=Метки
@ -602,6 +661,9 @@ migrate.permission_denied=У вас нет прав на импорт локал
migrate.invalid_local_path=Недопустимый локальный путь. Возможно он не существует или не является папкой. 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' вручную.
migrate.migrate_items_options=При миграции из GitHub, укажите имя пользователя - и появятся параметры миграции.
migrated_from=Перенесено с <a href="%[1]s">%[2]s</a>
migrated_from_fake=Перенесено с %[1]s
mirror_from=зеркало из mirror_from=зеркало из
forked_from=форкнуто от forked_from=форкнуто от
@ -648,6 +710,9 @@ video_not_supported_in_browser=Ваш браузер не поддерживае
audio_not_supported_in_browser=Ваш браузер не поддерживает HTML5 'audio' тэг. audio_not_supported_in_browser=Ваш браузер не поддерживает HTML5 'audio' тэг.
stored_lfs=Хранится Git LFS stored_lfs=Хранится Git LFS
commit_graph=Граф коммитов commit_graph=Граф коммитов
normal_view=Обычный вид
line=строка
lines=строки
editor.new_file=Новый файл editor.new_file=Новый файл
editor.upload_file=Загрузить файл editor.upload_file=Загрузить файл
@ -656,6 +721,7 @@ editor.preview_changes=Просмотр изменений
editor.cannot_edit_lfs_files=LFS файлы невозможно редактировать в веб-интерфейсе. editor.cannot_edit_lfs_files=LFS файлы невозможно редактировать в веб-интерфейсе.
editor.cannot_edit_non_text_files=Двоичные файлы нельзя редактировать в веб-интерфейсе. editor.cannot_edit_non_text_files=Двоичные файлы нельзя редактировать в веб-интерфейсе.
editor.edit_this_file=Редактировать файл editor.edit_this_file=Редактировать файл
editor.this_file_locked=Файл заблокирован
editor.must_be_on_a_branch=Чтобы внести или предложить изменения этого файла, необходимо выбрать ветку. editor.must_be_on_a_branch=Чтобы внести или предложить изменения этого файла, необходимо выбрать ветку.
editor.fork_before_edit=Необходимо сделать форк этого репозитория, чтобы внести или предложить изменения этого файла. editor.fork_before_edit=Необходимо сделать форк этого репозитория, чтобы внести или предложить изменения этого файла.
editor.delete_this_file=Удалить файл editor.delete_this_file=Удалить файл
@ -666,12 +732,15 @@ editor.filename_help=Чтобы добавить каталог, просто н
editor.or=или editor.or=или
editor.cancel_lower=Отменить editor.cancel_lower=Отменить
editor.commit_changes=Сохранить правки editor.commit_changes=Сохранить правки
editor.add_tmpl=Добавить '<filename>'
editor.add=Добавить '%s' editor.add=Добавить '%s'
editor.update=Изменить '%s' editor.update=Изменить '%s'
editor.delete=Удалить '%s' editor.delete=Удалить '%s'
editor.commit_message_desc=Добавьте необязательное расширенное описание… editor.commit_message_desc=Добавьте необязательное расширенное описание…
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> для этого коммита, и сделайте Pull Request. editor.create_new_branch=Создайте <strong>новую ветку</strong> для этого коммита, и сделайте Pull Request.
editor.create_new_branch_np=Создать <strong>новую ветку</strong> для этого коммита.
editor.propose_file_change=Предложить изменение файла
editor.new_branch_name_desc=Новое название ветки… editor.new_branch_name_desc=Новое название ветки…
editor.cancel=Отмена editor.cancel=Отмена
editor.filename_cannot_be_empty=Имя файла не может быть пустым. editor.filename_cannot_be_empty=Имя файла не может быть пустым.
@ -685,6 +754,7 @@ editor.file_editing_no_longer_exists=Редактируемый файл '%s' б
editor.file_deleting_no_longer_exists=Удаляемый файл '%s' больше не существует в этом репозитории. editor.file_deleting_no_longer_exists=Удаляемый файл '%s' больше не существует в этом репозитории.
editor.file_changed_while_editing=Содержимое файла изменилось с момента начала редактирования. <a target="_blank" rel="noopener noreferrer" 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.commit_empty_file_header=Закоммитить пустой файл
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=Добавить каталог…
@ -696,6 +766,7 @@ commits.desc=Просмотр истории изменений исходног
commits.commits=коммитов commits.commits=коммитов
commits.no_commits=Ничего общего в коммитах. '%s' и '%s' имеют совершенно разные истории. commits.no_commits=Ничего общего в коммитах. '%s' и '%s' имеют совершенно разные истории.
commits.search=Поиск коммитов… commits.search=Поиск коммитов…
commits.search.tooltip=Вы можете предварять ключевые слова словами "author:", "committer:", "after:", или "before:", например, "revert author:Alice before:2019-04-01".
commits.find=Поиск commits.find=Поиск
commits.search_all=Все ветки commits.search_all=Все ветки
commits.author=Автор commits.author=Автор
@ -711,6 +782,7 @@ ext_issues.desc=Ссылка на внешнюю систему отслежив
issues.desc=Организация отчетов об ошибках, задач и этапов. issues.desc=Организация отчетов об ошибках, задач и этапов.
issues.new=Новая задача issues.new=Новая задача
issues.new.title_empty=Заголовок не может быть пустым
issues.new.labels=Метки issues.new.labels=Метки
issues.new.no_label=Нет меток issues.new.no_label=Нет меток
issues.new.clear_labels=Отчистить метки issues.new.clear_labels=Отчистить метки
@ -742,6 +814,7 @@ issues.deleted_milestone=`(удалено)`
issues.self_assign_at=`самоназначился %s` 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=`был снят с назначения <b>%s</b> %s` issues.remove_assignee_at=`был снят с назначения <b>%s</b> %s`
issues.remove_self_assignment=`убрал их назначение %s`
issues.delete_branch_at=`удалена ветка <b>%s</b> %s` issues.delete_branch_at=`удалена ветка <b>%s</b> %s`
issues.open_tab=%d открыто(ы) issues.open_tab=%d открыто(ы)
issues.close_tab=%d закрыто(ы) issues.close_tab=%d закрыто(ы)
@ -778,6 +851,7 @@ issues.action_assignee=Ответственный
issues.action_assignee_no_select=Нет ответственного issues.action_assignee_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>
pulls.merged_by=принят %[1]s <a href="%[2]s">%[3]s</a> pulls.merged_by=принят %[1]s <a href="%[2]s">%[3]s</a>
pulls.merged_by_fake=%[1]s слита пользователем %[2]s
issues.closed_by=закрыта %[1]s <a href="%[2]s">%[3]s</a> issues.closed_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.closed_by_fake=%[1]s закрыта пользователем %[2]s issues.closed_by_fake=%[1]s закрыта пользователем %[2]s
@ -788,6 +862,9 @@ issues.closed_title=Закрыто
issues.num_comments=комментариев: %d issues.num_comments=комментариев: %d
issues.commented_at=`прокомментировал <a href="#%s"> %s</a>` issues.commented_at=`прокомментировал <a href="#%s"> %s</a>`
issues.delete_comment_confirm=Вы уверены, что хотите удалить этот комментарий? issues.delete_comment_confirm=Вы уверены, что хотите удалить этот комментарий?
issues.context.copy_link=Копировать ссылку
issues.context.edit=Редактировать
issues.context.delete=Удалить
issues.no_content=Пока нет содержимого. issues.no_content=Пока нет содержимого.
issues.close_issue=Закрыть issues.close_issue=Закрыть
issues.close_comment_issue=Прокомментировать и закрыть issues.close_comment_issue=Прокомментировать и закрыть
@ -829,6 +906,7 @@ issues.unlock=Снять ограничение
issues.lock.unknown_reason=Для ограничения обсуждения необходимо указать причину. issues.lock.unknown_reason=Для ограничения обсуждения необходимо указать причину.
issues.lock_duplicate=Обсуждение задачи уже ограничено. issues.lock_duplicate=Обсуждение задачи уже ограничено.
issues.unlock_error=Невозможно снять несуществующее ограничение обсуждения. issues.unlock_error=Невозможно снять несуществующее ограничение обсуждения.
issues.lock_with_reason=заблокировано как <strong>%s</strong> и ограничено обсуждение для соучастников %s
issues.lock_no_reason=ограничил(а) обсуждение задачи кругом соавторов %s issues.lock_no_reason=ограничил(а) обсуждение задачи кругом соавторов %s
issues.unlock_comment=снял(а) ограничение %s issues.unlock_comment=снял(а) ограничение %s
issues.lock_confirm=Ограничить issues.lock_confirm=Ограничить
@ -846,6 +924,7 @@ issues.tracker=Отслеживание времени
issues.start_tracking_short=Начать issues.start_tracking_short=Начать
issues.start_tracking=Начать отслеживание времени issues.start_tracking=Начать отслеживание времени
issues.start_tracking_history=`начал работать %s` issues.start_tracking_history=`начал работать %s`
issues.tracker_auto_close=Таймер будет остановлен автоматически, когда эта проблема будет закрыта
issues.tracking_already_started=`Вы уже начали отслеживать время для этой <a href="%s">задачи</a>!` issues.tracking_already_started=`Вы уже начали отслеживать время для этой <a href="%s">задачи</a>!`
issues.stop_tracking=Остановить issues.stop_tracking=Остановить
issues.stop_tracking_history=`перестал работать %s` issues.stop_tracking_history=`перестал работать %s`
@ -914,6 +993,7 @@ issues.review.reviewers=Рецензенты
issues.review.show_outdated=Показать устаревшие issues.review.show_outdated=Показать устаревшие
issues.review.hide_outdated=Скрыть устаревшие issues.review.hide_outdated=Скрыть устаревшие
pulls.desc=Включить запросы на слияние и проверки кода.
pulls.new=Новый Pull Request pulls.new=Новый Pull Request
pulls.compare_changes=Новый Pull Request pulls.compare_changes=Новый Pull Request
pulls.compare_changes_desc=Сравнить две ветки и создать запрос на слияние для изменений. pulls.compare_changes_desc=Сравнить две ветки и создать запрос на слияние для изменений.
@ -924,11 +1004,13 @@ 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.has_pull_request=`Уже существует запрос на слияние между двумя целями: <a href="%[1]s/pulls/%[3]d">%[2]s#%[3]d</a>`
pulls.create=Создать Pull Request pulls.create=Создать Pull Request
pulls.title_desc=хочет смерджить %[1]d коммит(ов) из <code>%[2]s</code> в <code id="branch_target">%[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
pulls.tab_conversation=Обсуждение pulls.tab_conversation=Обсуждение
pulls.tab_commits=Коммиты pulls.tab_commits=Коммиты
pulls.tab_files=Измененные файлы pulls.tab_files=Измененные файлы
pulls.reopen_to_merge=Пожалуйста, переоткройте этот Pull Request для выполнения слияния. pulls.reopen_to_merge=Пожалуйста, переоткройте этот Pull Request для выполнения слияния.
pulls.cant_reopen_deleted_branch=Этот запрос на слияние не может быть открыт заново, потому что ветка была удалена.
pulls.merged=Слито pulls.merged=Слито
pulls.has_merged=Слияние этого запроса успешно завершено. pulls.has_merged=Слияние этого запроса успешно завершено.
pulls.title_wip_desc=`<a href="#">Добавьте <strong>%s</strong> в начало заголовка</a> для защиты от случайного досрочного принятия Pull Request'а.` pulls.title_wip_desc=`<a href="#">Добавьте <strong>%s</strong> в начало заголовка</a> для защиты от случайного досрочного принятия Pull Request'а.`
@ -949,6 +1031,9 @@ pulls.rebase_merge_commit_pull_request=Выполнить rebase и принят
pulls.squash_merge_pull_request=Объединить и принять PR pulls.squash_merge_pull_request=Объединить и принять PR
pulls.invalid_merge_option=Этот параметр слияния нельзя использовать для этого Pull Request'а. pulls.invalid_merge_option=Этот параметр слияния нельзя использовать для этого Pull Request'а.
pulls.open_unmerged_pull_exists=`Вы не можете снова открыть, поскольку уже существует запрос на слияние (#%d) из того же репозитория с той же информацией о слиянии и ожидающий слияния.` pulls.open_unmerged_pull_exists=`Вы не можете снова открыть, поскольку уже существует запрос на слияние (#%d) из того же репозитория с той же информацией о слиянии и ожидающий слияния.`
pulls.status_checking=Выполняются некоторые проверки
pulls.status_checks_success=Все проверки выполнены успешно
pulls.status_checks_error=Некоторые проверки не удались
milestones.new=Новый этап milestones.new=Новый этап
milestones.open_tab=%d открыты milestones.open_tab=%d открыты
@ -997,6 +1082,8 @@ 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.file_revision=Версия страницы
wiki.back_to_wiki=Вернуться на wiki страницу
wiki.delete_page_button=Удалить страницу wiki.delete_page_button=Удалить страницу
wiki.delete_page_notice_1=Удаление вики-страницы '%s' не может быть отменено. Продолжить? wiki.delete_page_notice_1=Удаление вики-страницы '%s' не может быть отменено. Продолжить?
wiki.page_already_exists=Вики-страница с таким именем уже существует. wiki.page_already_exists=Вики-страница с таким именем уже существует.
@ -1010,6 +1097,9 @@ activity.period.daily=1 день
activity.period.halfweekly=3 дня activity.period.halfweekly=3 дня
activity.period.weekly=1 неделя activity.period.weekly=1 неделя
activity.period.monthly=1 месяц activity.period.monthly=1 месяц
activity.period.quarterly=3 месяца
activity.period.semiyearly=6 месяцев
activity.period.yearly=1 год
activity.overview=Обзор activity.overview=Обзор
activity.active_prs_count_1=<strong>%d</strong> Активный Pull Request activity.active_prs_count_1=<strong>%d</strong> Активный Pull Request
activity.active_prs_count_n=<strong>%d</strong> Активных Pull Request'ов activity.active_prs_count_n=<strong>%d</strong> Активных Pull Request'ов
@ -1046,6 +1136,26 @@ activity.title.releases_n=%d релизов
activity.title.releases_published_by=%s опубликованы %s activity.title.releases_published_by=%s опубликованы %s
activity.published_release_label=Опубликовано activity.published_release_label=Опубликовано
activity.no_git_activity=В этот период не было новых коммитов. activity.no_git_activity=В этот период не было новых коммитов.
activity.git_stats_exclude_merges=За исключением слияний,
activity.git_stats_author_1=%d автор
activity.git_stats_author_n=%d автора(ов)
activity.git_stats_pushed_1=отправлен
activity.git_stats_pushed_n=отправлено
activity.git_stats_commit_1=%d коммит
activity.git_stats_commit_n=%d коммитов
activity.git_stats_push_to_branch=к %s и
activity.git_stats_push_to_all_branches=во все ветки.
activity.git_stats_on_default_branch=На %s,
activity.git_stats_file_1=%d файл
activity.git_stats_file_n=%d файлов
activity.git_stats_files_changed_1=изменилось
activity.git_stats_files_changed_n=изменено
activity.git_stats_additions=и там было
activity.git_stats_addition_1=%d добавление
activity.git_stats_addition_n=%d добавлений
activity.git_stats_and_deletions=и
activity.git_stats_deletion_1=%d удаление
activity.git_stats_deletion_n=%d удалений
search=Поиск search=Поиск
search.search_repo=Поиск по репозиторию search.search_repo=Поиск по репозиторию
@ -1058,6 +1168,7 @@ settings.collaboration=Соавторы
settings.collaboration.admin=Администратор settings.collaboration.admin=Администратор
settings.collaboration.write=Запись settings.collaboration.write=Запись
settings.collaboration.read=Просмотр settings.collaboration.read=Просмотр
settings.collaboration.owner=Владелец
settings.collaboration.undefined=Не определено settings.collaboration.undefined=Не определено
settings.hooks=Автоматическое обновление settings.hooks=Автоматическое обновление
settings.githooks=Git хуки settings.githooks=Git хуки
@ -1065,6 +1176,9 @@ settings.basic_settings=Основные параметры
settings.mirror_settings=Настройки зеркалирования settings.mirror_settings=Настройки зеркалирования
settings.sync_mirror=Синхронизировать settings.sync_mirror=Синхронизировать
settings.mirror_sync_in_progress=Синхронизируются репозитории-зеркала. Подождите минуту и обновите страницу. settings.mirror_sync_in_progress=Синхронизируются репозитории-зеркала. Подождите минуту и обновите страницу.
settings.email_notifications.enable=Включить почтовые уведомления
settings.email_notifications.disable=Отключить почтовые уведомления
settings.email_notifications.submit=Установить настройки электронной почты
settings.site=Сайт settings.site=Сайт
settings.update_settings=Обновить настройки settings.update_settings=Обновить настройки
settings.advanced_settings=Расширенные настройки settings.advanced_settings=Расширенные настройки
@ -1135,6 +1249,10 @@ settings.collaborator_deletion_desc=Этот пользователь больш
settings.remove_collaborator_success=Соавтор удалён. settings.remove_collaborator_success=Соавтор удалён.
settings.search_user_placeholder=Поиск пользователя… settings.search_user_placeholder=Поиск пользователя…
settings.org_not_allowed_to_be_collaborator=Организации не могут быть добавлены как соавторы. settings.org_not_allowed_to_be_collaborator=Организации не могут быть добавлены как соавторы.
settings.team_not_in_organization=Команда не в той же организации, что и репозиторий
settings.add_team_duplicate=Команда уже имеет репозиторий
settings.add_team_success=Команда теперь имеет доступ к репозиторию.
settings.remove_team_success=Доступ команды к репозиторию был удален.
settings.add_webhook=Добавить Webhook settings.add_webhook=Добавить Webhook
settings.add_webhook.invalid_channel_name=Имя канала не может быть пустым или состоять только из символа #. settings.add_webhook.invalid_channel_name=Имя канала не может быть пустым или состоять только из символа #.
settings.hooks_desc=Webhooks позволяют внешним службам получать уведомления при возникновении определенных событий на Gitea. При возникновении указанных событий мы отправим запрос POST на каждый заданный вами URL. Узнать больше можно в нашем <a target="_blank" rel="noopener noreferrer" href="%s">руководстве по webhooks</a>. settings.hooks_desc=Webhooks позволяют внешним службам получать уведомления при возникновении определенных событий на Gitea. При возникновении указанных событий мы отправим запрос POST на каждый заданный вами URL. Узнать больше можно в нашем <a target="_blank" rel="noopener noreferrer" href="%s">руководстве по webhooks</a>.
@ -1184,6 +1302,7 @@ settings.event_pull_request=Pull Request
settings.event_pull_request_desc=Запрос слияния открыт, закрыт, переоткрыт, изменён, одобрен, отклонён, рецензирован, назначен, снят, метка обновлена, метка убрана, или синхронизирован. settings.event_pull_request_desc=Запрос слияния открыт, закрыт, переоткрыт, изменён, одобрен, отклонён, рецензирован, назначен, снят, метка обновлена, метка убрана, или синхронизирован.
settings.event_push=Push settings.event_push=Push
settings.event_push_desc=Push в репозиторий. settings.event_push_desc=Push в репозиторий.
settings.branch_filter=Фильтр веток
settings.event_repository=Репозиторий settings.event_repository=Репозиторий
settings.event_repository_desc=Репозиторий создан или удален. settings.event_repository_desc=Репозиторий создан или удален.
settings.active=Активный settings.active=Активный
@ -1223,6 +1342,8 @@ 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.branch_protection=Защита ветки <b>%s</b>
settings.protect_this_branch=Защитить эту ветку settings.protect_this_branch=Защитить эту ветку
settings.protect_disable_push=Отключить Push
settings.protect_enable_push=Включить Push
settings.protect_whitelist_users=Пользователи, которые могут делать push в эту ветку: settings.protect_whitelist_users=Пользователи, которые могут делать push в эту ветку:
settings.protect_whitelist_search_users=Поиск пользователей… settings.protect_whitelist_search_users=Поиск пользователей…
settings.protect_whitelist_teams=Команды, члены которых могут делать push в эту ветку: settings.protect_whitelist_teams=Команды, члены которых могут делать push в эту ветку:
@ -1231,7 +1352,9 @@ settings.protect_merge_whitelist_committers=Ограничить право на
settings.protect_merge_whitelist_committers_desc=Вы можете добавлять пользователей или целые команды в "белый" список этой ветки. Только присутствующие в списке смогут принимать Pull Request'ы. В противном случае любой с правами на запись в репозиторий будет обладать такой возможностью. settings.protect_merge_whitelist_committers_desc=Вы можете добавлять пользователей или целые команды в "белый" список этой ветки. Только присутствующие в списке смогут принимать Pull Request'ы. В противном случае любой с правами на запись в репозиторий будет обладать такой возможностью.
settings.protect_merge_whitelist_users=Пользователи с правом на принятие Pull Request'ов в эту ветку: settings.protect_merge_whitelist_users=Пользователи с правом на принятие Pull Request'ов в эту ветку:
settings.protect_merge_whitelist_teams=Команды, члены которых обладают правом на принятие Pull Request'ов в эту ветку: settings.protect_merge_whitelist_teams=Команды, члены которых обладают правом на принятие Pull Request'ов в эту ветку:
settings.protect_check_status_contexts=Включить проверку статуса
settings.protect_required_approvals=Необходимые одобрения: settings.protect_required_approvals=Необходимые одобрения:
settings.protect_required_approvals_desc=Разрешить объединение Pull Request'а только с достаточным количеством положительных отзывов.
settings.protect_approvals_whitelist_users=Рецензенты в белом списке: settings.protect_approvals_whitelist_users=Рецензенты в белом списке:
settings.protect_approvals_whitelist_teams=Команды в белом списке для рецензирования: settings.protect_approvals_whitelist_teams=Команды в белом списке для рецензирования:
settings.add_protected_branch=Включить защиту settings.add_protected_branch=Включить защиту
@ -1251,16 +1374,31 @@ settings.archive.button=Архивировать репозиторий
settings.archive.header=Архивировать этот репозиторий settings.archive.header=Архивировать этот репозиторий
settings.archive.text=Архивация репозитория переведет его в режим read-only. Он будет скрыт из панели управления, создание задач, запросов на слияние, или создание коммитов будут запрещены. settings.archive.text=Архивация репозитория переведет его в режим read-only. Он будет скрыт из панели управления, создание задач, запросов на слияние, или создание коммитов будут запрещены.
settings.archive.success=Репозиторий был успешно архивирован. settings.archive.success=Репозиторий был успешно архивирован.
settings.archive.error=Ошибка при попытке архивировать репозиторий. Смотрите логи для получения подробностей.
settings.archive.error_ismirror=Вы не можете поместить зеркалируемый репозиторий в архив. settings.archive.error_ismirror=Вы не можете поместить зеркалируемый репозиторий в архив.
settings.archive.branchsettings_unavailable=Настройки ветки недоступны, если репозиторий архивирован.
settings.unarchive.button=Разархивировать settings.unarchive.button=Разархивировать
settings.unarchive.header=Разархивировать этот репозиторий settings.unarchive.header=Разархивировать этот репозиторий
settings.unarchive.text=Разархивация восстанавливает возможность совершать push в репозиторий, создавать новые коммиты, задачи и запросы на слияние.
settings.unarchive.success=Репозиторий был успешно разархивирован. settings.unarchive.success=Репозиторий был успешно разархивирован.
settings.unarchive.error=Ошибка при попытке разархивировать репозиторий. Смотрите логи для получения подробностей.
settings.update_avatar_success=Аватар репозитория обновлен. settings.update_avatar_success=Аватар репозитория обновлен.
settings.lfs=LFS
settings.lfs_findcommits=Найти коммиты
settings.lfs_force_unlock=Принудительная разблокировка
settings.lfs_pointers.sha=Blob SHA
settings.lfs_pointers.oid=OID
settings.lfs_pointers.inRepo=В репозитории
diff.browse_source=Просмотр исходного кода diff.browse_source=Просмотр исходного кода
diff.parent=Родитель diff.parent=Родитель
diff.commit=Сommit diff.commit=Сommit
diff.git-notes=Заметки
diff.data_not_available=Разница недоступна diff.data_not_available=Разница недоступна
diff.options_button=Опции Diff
diff.show_diff_stats=Показать статистику
diff.download_patch=Скачать Patch файл
diff.download_diff=Скачать Diff файл
diff.show_split_view=Разделённый вид diff.show_split_view=Разделённый вид
diff.show_unified_view=Единый вид diff.show_unified_view=Единый вид
diff.whitespace_button=Пробелы diff.whitespace_button=Пробелы
@ -1271,6 +1409,11 @@ diff.whitespace_ignore_at_eol=Игнорировать изменения в п
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.bin=Двоичные данные
diff.view_file=Просмотреть файл diff.view_file=Просмотреть файл
diff.file_before=До
diff.file_after=После
diff.file_image_width=Ширина
diff.file_image_height=Высота
diff.file_byte_size=Размер
diff.file_suppressed=Разница между файлами не показана из-за своего большого размера diff.file_suppressed=Разница между файлами не показана из-за своего большого размера
diff.too_many_files=Некоторые файлы не были показаны из-за большого количества измененных файлов diff.too_many_files=Некоторые файлы не были показаны из-за большого количества измененных файлов
diff.comment.placeholder=Оставить комментарий diff.comment.placeholder=Оставить комментарий
@ -1284,6 +1427,7 @@ diff.review.header=Отправить рецензию
diff.review.placeholder=Рецензионный комментарий diff.review.placeholder=Рецензионный комментарий
diff.review.comment=Комментировать diff.review.comment=Комментировать
diff.review.approve=Утвердить diff.review.approve=Утвердить
diff.review.reject=Запрос изменений
releases.desc=Релизы позволяют организовать хранение готовых сборок проекта в строгом хронологически верном порядке. releases.desc=Релизы позволяют организовать хранение готовых сборок проекта в строгом хронологически верном порядке.
release.releases=Релизы release.releases=Релизы
@ -1335,6 +1479,8 @@ branch.deleted_by=Удалён %s
branch.restore_success=Ветка '%s' восстановлена. branch.restore_success=Ветка '%s' восстановлена.
branch.restore_failed=Не удалось восстановить ветку '%s'. branch.restore_failed=Не удалось восстановить ветку '%s'.
branch.protected_deletion_failed=Ветка '%s' защищена. Её нельзя удалить. branch.protected_deletion_failed=Ветка '%s' защищена. Её нельзя удалить.
branch.restore=Восстановить ветку '%s'
branch.download=Скачать ветку '%s'
topic.manage_topics=Редактировать тематические метки topic.manage_topics=Редактировать тематические метки
topic.done=Сохранить topic.done=Сохранить
@ -1358,6 +1504,7 @@ team_name=Название команды
team_desc=Описание team_desc=Описание
team_name_helper=Названия команд должны быть короткими и запоминающимися. team_name_helper=Названия команд должны быть короткими и запоминающимися.
team_desc_helper=Что это за команда? team_desc_helper=Что это за команда?
team_access_desc=Доступ к репозиторию
team_permission_desc=Разрешение team_permission_desc=Разрешение
team_unit_desc=Разрешить доступ к разделам репозитория team_unit_desc=Разрешить доступ к разделам репозитория
@ -1370,7 +1517,11 @@ settings.options=Организация
settings.full_name=Полное имя settings.full_name=Полное имя
settings.website=Сайт settings.website=Сайт
settings.location=Местоположение settings.location=Местоположение
settings.permission=Разрешения
settings.visibility=Видимость settings.visibility=Видимость
settings.visibility.public=Публичный
settings.visibility.limited=Ограничено (Видно только для авторизованных пользователей)
settings.visibility.private=Частный (Видимый только для участников организации)
settings.update_settings=Обновить настройки settings.update_settings=Обновить настройки
settings.update_setting_success=Настройки организации обновлены. settings.update_setting_success=Настройки организации обновлены.
@ -1399,6 +1550,7 @@ members.invite_now=Пригласите сейчас
teams.join=Объединить teams.join=Объединить
teams.leave=Выйти teams.leave=Выйти
teams.can_create_org_repo=Создать репозитории
teams.read_access=Доступ на чтение teams.read_access=Доступ на чтение
teams.read_access_helper=Участники могут просматривать и клонировать командные репозитории. teams.read_access_helper=Участники могут просматривать и клонировать командные репозитории.
teams.write_access=Доступ на запись teams.write_access=Доступ на запись
@ -1420,16 +1572,20 @@ teams.write_permission_desc=Эта команда предоставляет д
teams.admin_permission_desc=Эта команда дает <strong>административный</strong> доступ: участники могут читать, пушить и добавлять соавторов к ее репозиториям. teams.admin_permission_desc=Эта команда дает <strong>административный</strong> доступ: участники могут читать, пушить и добавлять соавторов к ее репозиториям.
teams.repositories=Репозитории группы разработки teams.repositories=Репозитории группы разработки
teams.search_repo_placeholder=Поиск репозитория… teams.search_repo_placeholder=Поиск репозитория…
teams.remove_all_repos_title=Удалить все репозитории команды
teams.add_all_repos_title=Добавить все репозитории
teams.add_nonexistent_repo=Вы добавляете в отсутствующий репозиторий, пожалуйста сначала его создайте. teams.add_nonexistent_repo=Вы добавляете в отсутствующий репозиторий, пожалуйста сначала его создайте.
teams.add_duplicate_users=Пользователь уже состоит в команде. teams.add_duplicate_users=Пользователь уже состоит в команде.
teams.repos.none=Для этой команды нет доступных репозиториев. teams.repos.none=Для этой команды нет доступных репозиториев.
teams.members.none=В этой команде нет участников. teams.members.none=В этой команде нет участников.
teams.all_repositories=Все репозитории
[admin] [admin]
dashboard=Панель dashboard=Панель
users=Пользователи users=Пользователи
organizations=Организации organizations=Организации
repositories=Репозитории repositories=Репозитории
hooks=Стандартные Веб-хуки
authentication=Авторизация authentication=Авторизация
config=Конфигурация config=Конфигурация
notices=Системные уведомления notices=Системные уведомления
@ -1453,6 +1609,8 @@ dashboard.delete_repo_archives=Удаление всех архивов репо
dashboard.delete_repo_archives_success=Все архивы репозиториев удалены. dashboard.delete_repo_archives_success=Все архивы репозиториев удалены.
dashboard.delete_missing_repos=Удалить все записи о репозиториях с отсутствующими файлами Git dashboard.delete_missing_repos=Удалить все записи о репозиториях с отсутствующими файлами Git
dashboard.delete_missing_repos_success=Все записи о репозиториях с отсутствующими файлами Git удалены. dashboard.delete_missing_repos_success=Все записи о репозиториях с отсутствующими файлами Git удалены.
dashboard.delete_generated_repository_avatars=Удалить генерированные аватары репозитория
dashboard.delete_generated_repository_avatars_success=Генерированные аватары репозитория были удалены.
dashboard.git_gc_repos=Выполнить сборку мусора для всех репозиториев 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=Перезаписать файл '.ssh/authorized_keys' для SSH ключей Gitea. Не требуется для встроенного SSH сервера.
@ -1513,6 +1671,7 @@ users.auth_login_name=Логин для авторизации
users.password_helper=Оставьте пустым, чтобы оставить без изменений. 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_desc=(Установите -1 для использования стандартного глобального значения предела) users.max_repo_creation_desc=(Установите -1 для использования стандартного глобального значения предела)
users.is_activated=Эта учетная запись активирована users.is_activated=Эта учетная запись активирована
users.prohibit_login=Этой учетной записи запрещен вход в систему users.prohibit_login=Этой учетной записи запрещен вход в систему
@ -1542,6 +1701,8 @@ repos.forks=Форки
repos.issues=Задачи repos.issues=Задачи
repos.size=Размер repos.size=Размер
hooks.add_webhook=Добавить стандартный Веб-хук
hooks.update_webhook=Обновить стандартный Веб-хук
auths.auth_manage_panel=Управление аутентификацией auths.auth_manage_panel=Управление аутентификацией
auths.new=Добавить новый источник auths.new=Добавить новый источник
@ -1591,6 +1752,14 @@ auths.oauth2_authURL=URL авторизации
auths.oauth2_profileURL=URL аккаунта auths.oauth2_profileURL=URL аккаунта
auths.oauth2_emailURL=URL-адрес электронной почты auths.oauth2_emailURL=URL-адрес электронной почты
auths.enable_auto_register=Включить автоматическую регистрацию auths.enable_auto_register=Включить автоматическую регистрацию
auths.sspi_auto_create_users=Автоматически создавать пользователей
auths.sspi_auto_create_users_helper=Разрешить метод аутентификации SSPI для автоматического создания новых учетных записей для пользователей, которые впервые входят в систему
auths.sspi_auto_activate_users=Автоматически активировать пользователей
auths.sspi_auto_activate_users_helper=Разрешить метод аутентификации SSPI для автоматической активации новых пользователей
auths.sspi_strip_domain_names=Удалять доменные имена из имён пользователей
auths.sspi_separator_replacement=Разделитель для использования вместо \, / и @
auths.sspi_default_language=Язык пользователя по умолчанию
auths.sspi_default_language_helper=Язык по умолчанию для пользователей, автоматически создаваемый методом аутентификации SSPI. Оставьте пустым, если вы предпочитаете, чтобы язык определялся автоматически.
auths.tips=Советы 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
@ -1604,6 +1773,7 @@ auths.tip.google_plus=Получите учетные данные клиент
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.tip.twitter=Перейдите на https://dev.twitter.com/apps, создайте приложение и убедитесь, что включена опция «Разрешить это приложение для входа в систему с помощью Twitter»
auths.tip.discord=Добавьте новое приложение на https://discordapp.com/developers/applications/me auths.tip.discord=Добавьте новое приложение на https://discordapp.com/developers/applications/me
auths.tip.gitea=Зарегистрировать новое приложение OAuth2. Руководство можно найти на https://docs.gitea.io/ru-us/oauth2-provider/
auths.edit=Обновить параметры аутентификации auths.edit=Обновить параметры аутентификации
auths.activated=Эта аутентификация активирована auths.activated=Эта аутентификация активирована
auths.new_success=Метод аутентификации '%s' был добавлен. auths.new_success=Метод аутентификации '%s' был добавлен.
@ -1615,12 +1785,14 @@ auths.delete_auth_desc=Этот источник аутентификации б
auths.still_in_used=Эта проверка подлинности до сих пор используется некоторыми пользователями, удалите или преобразуйте этих пользователей в другой тип входа в систему. auths.still_in_used=Эта проверка подлинности до сих пор используется некоторыми пользователями, удалите или преобразуйте этих пользователей в другой тип входа в систему.
auths.deletion_success=Канал аутентификации успешно удален! auths.deletion_success=Канал аутентификации успешно удален!
auths.login_source_exist=Источник входа '%s' уже существует. auths.login_source_exist=Источник входа '%s' уже существует.
auths.login_source_of_type_exist=Источник аутентификации этого типа уже существует.
config.server_config=Конфигурация сервера config.server_config=Конфигурация сервера
config.app_name=Название сайта config.app_name=Название сайта
config.app_ver=Версия Gitea config.app_ver=Версия Gitea
config.app_url=Базовый URL-адрес Gitea config.app_url=Базовый URL-адрес Gitea
config.custom_conf=Путь к файлу конфигурации config.custom_conf=Путь к файлу конфигурации
config.custom_file_root_path=Пользовательский путь до папки с файлами
config.domain=Домен SSH сервера config.domain=Домен SSH сервера
config.offline_mode=Локальный режим config.offline_mode=Локальный режим
config.disable_router_log=Отключение журнала маршрутизатора config.disable_router_log=Отключение журнала маршрутизатора
@ -1646,6 +1818,10 @@ config.ssh_keygen_path=Путь к генератору ключей ('ssh-keyge
config.ssh_minimum_key_size_check=Минимальный размер ключа проверки config.ssh_minimum_key_size_check=Минимальный размер ключа проверки
config.ssh_minimum_key_sizes=Минимальные размеры ключа config.ssh_minimum_key_sizes=Минимальные размеры ключа
config.lfs_config=Конфигурация LFS
config.lfs_enabled=Включено
config.lfs_content_path=Путь к контенту LFS
config.lfs_http_auth_expiry=Устаревание HTTP-аутентификации LFS
config.db_config=Конфигурация базы данных config.db_config=Конфигурация базы данных
config.db_type=Тип config.db_type=Тип
@ -1667,6 +1843,7 @@ 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=Включить отслеживание времени
@ -1701,6 +1878,7 @@ config.cache_config=Настройки кеша
config.cache_adapter=Адаптер кэша config.cache_adapter=Адаптер кэша
config.cache_interval=Интервал кэширования config.cache_interval=Интервал кэширования
config.cache_conn=Подключение кэша config.cache_conn=Подключение кэша
config.cache_item_ttl=Время жизни данных в кеше
config.session_config=Конфигурация сессии config.session_config=Конфигурация сессии
config.session_provider=Провайдер сессии config.session_provider=Провайдер сессии
@ -1731,6 +1909,16 @@ config.git_gc_timeout=Лимит времени сборки мусора
config.log_config=Конфигурация журнала config.log_config=Конфигурация журнала
config.log_mode=Режим журналирования config.log_mode=Режим журналирования
config.macaron_log_mode=Режим журнала Macaron
config.own_named_logger=Именованный журнал
config.routes_to_default_logger=Маршруты в стандартный журнал
config.go_log=Использует Go-журнал (перенаправлено в стандартный)
config.router_log_mode=Режим журнала маршрутизатора
config.disabled_logger=Отключен
config.access_log_mode=Режим доступа к журналу
config.access_log_template=Шаблон
config.xorm_log_mode=Режим журнала XORM
config.xorm_log_sql=Лог SQL
monitor.cron=Задачи cron monitor.cron=Задачи cron
monitor.name=Название monitor.name=Название
@ -1742,6 +1930,9 @@ monitor.process=Запущенные процессы
monitor.desc=Описание monitor.desc=Описание
monitor.start=Время начала monitor.start=Время начала
monitor.execute_time=Время выполнения monitor.execute_time=Время выполнения
monitor.process.cancel=Отменить процесс
monitor.process.cancel_desc=Отмена процесса может привести к потере данных
monitor.process.cancel_notices=Отменить: <strong>%s</strong>?
notices.system_notice_list=Уведомления системы notices.system_notice_list=Уведомления системы
notices.view_detail_header=Подробности уведомления notices.view_detail_header=Подробности уведомления
@ -1774,6 +1965,7 @@ push_tag=создал(а) тэг <a href="%s/src/tag/%s">%[2]s</a> в <a href="%
delete_tag=удалил(а) тэг %[2]s из <a href="%[1]s">%[3]s</a> delete_tag=удалил(а) тэг %[2]s из <a href="%[1]s">%[3]s</a>
delete_branch=удалил(а) ветку %[2]s из <a href="%[1]s">%[3]s</a> delete_branch=удалил(а) ветку %[2]s из <a href="%[1]s">%[3]s</a>
compare_commits=Сравнить %d коммитов compare_commits=Сравнить %d коммитов
compare_commits_general=Сравнить коммиты
mirror_sync_push=синхронизированные коммиты с <a href="%[1]s/src/%[2]s">%[3]s</a> на <a href="%[1]s">%[4]s</a> из зеркала mirror_sync_push=синхронизированные коммиты с <a href="%[1]s/src/%[2]s">%[3]s</a> на <a href="%[1]s">%[4]s</a> из зеркала
mirror_sync_create=синхронизированные новые ссылки <a href="%s/src/%s">%[2]s</a> к <a href="%[1]s">%[3]s</a> из зеркала mirror_sync_create=синхронизированные новые ссылки <a href="%s/src/%s">%[2]s</a> к <a href="%[1]s">%[3]s</a> из зеркала
mirror_sync_delete=синхронизированные и удаленные ссылки <code>%[2]s</code> на <a href="%[1]s">%[3]s</a> из зеркала mirror_sync_delete=синхронизированные и удаленные ссылки <code>%[2]s</code> на <a href="%[1]s">%[3]s</a> из зеркала
@ -1818,6 +2010,7 @@ mark_as_unread=Пометить как непрочитанное
mark_all_as_read=Пометить все как прочитанные mark_all_as_read=Пометить все как прочитанные
[gpg] [gpg]
default_key=Подписано ключом по умолчанию
error.extract_sign=Не удалось извлечь подпись error.extract_sign=Не удалось извлечь подпись
error.generate_hash=Не удается создать хэш коммита error.generate_hash=Не удается создать хэш коммита
error.no_committer_account=Аккаунт пользователя с таким Email не найден error.no_committer_account=Аккаунт пользователя с таким Email не найден

View file

@ -25,6 +25,7 @@ password=Parola
re_type=Parolayı yeniden yazın re_type=Parolayı yeniden yazın
captcha=CAPTCHA captcha=CAPTCHA
twofa=İki Aşamalı Doğrulama twofa=İki Aşamalı Doğrulama
twofa_scratch=İki aşamalı kazınmış kod
passcode=Şifre passcode=Şifre
u2f_insert_key=Güvenlik anahtarınızı girin u2f_insert_key=Güvenlik anahtarınızı girin
@ -65,6 +66,7 @@ forks=Çatallar
activities=Aktiviteler activities=Aktiviteler
pull_requests=Değişiklik İstekleri pull_requests=Değişiklik İstekleri
issues=Konular issues=Konular
milestones=Kilometre Taşları
cancel=İptal cancel=İptal
add=Ekle add=Ekle
@ -85,6 +87,7 @@ platform_desc=Gitea <a target="_blank" rel="noopener noreferrer" href="http://go
lightweight=Hafif lightweight=Hafif
lightweight_desc=Gitea'nın minimal gereksinimleri çok düşüktür ve ucuz bir Raspberry Pi üzerinde çalışabilmektedir. Makine enerjinizden tasarruf edin! lightweight_desc=Gitea'nın minimal gereksinimleri çok düşüktür ve ucuz bir Raspberry Pi üzerinde çalışabilmektedir. Makine enerjinizden tasarruf edin!
license=ık Kaynak license=ık Kaynak
license_desc=Gidin ve <a target="_blank" rel="noopener noreferrer" href="https://code.gitea.io/gitea">code.gitea.io/gitea</a>'yı edinin! Bu projeyi daha da iyi yapmak için <a target="_blank" rel="noopener noreferrer" href="https://github.com/go-gitea/gitea">katkıda bulunarak</a> bize katılın. Katkıda bulunmaktan çekinmeyin!
[install] [install]
install=Kurulum install=Kurulum
@ -122,9 +125,11 @@ run_user_helper=Gitea'nin çalışacağı, işletim sistemi kullanıcı adını
domain=SSH Sunucusu Alan Adı domain=SSH Sunucusu Alan Adı
domain_helper=SSH kopyalama URL'leri için alan adı veya sunucu adresi. domain_helper=SSH kopyalama URL'leri için alan adı veya sunucu adresi.
ssh_port=SSH Sunucu Portu ssh_port=SSH Sunucu Portu
ssh_port_helper=SSH sunucusunun dinleyeceği port numarası. Etkisizleştimek için boş bırakın.
http_port=Gitea HTTP Dinleme Portu http_port=Gitea HTTP Dinleme Portu
http_port_helper=Gitea'nın web sunucusunun dinleyeceği port numarası. http_port_helper=Gitea'nın web sunucusunun dinleyeceği port numarası.
app_url=Gitea Kök URL app_url=Gitea Kök URL
app_url_helper=HTTP(S) kopyalama URL'leri ve e-posta bildirimleri için temel adres.
log_root_path=Günlük Dosyaları Yolu log_root_path=Günlük Dosyaları Yolu
log_root_path_helper=Günlük dosyaları bu dizine kaydedilecektir. log_root_path_helper=Günlük dosyaları bu dizine kaydedilecektir.
@ -139,7 +144,10 @@ register_confirm=Kayıt için E-posta Doğrulaması Gereksin
mail_notify=E-Posta Bildirimlerini Etkinleştir mail_notify=E-Posta Bildirimlerini Etkinleştir
server_service_title=Sunucu ve Diğer Servis Ayarları server_service_title=Sunucu ve Diğer Servis Ayarları
offline_mode=Yerel Kipi Etkinleştir offline_mode=Yerel Kipi Etkinleştir
offline_mode_popup=Üçüncü parti içerik teslim ağlarını etkisizleştirin ve bütün kaynakları yerelden sunun.
disable_gravatar=Gravatar'ı Devre Dışı Bırak disable_gravatar=Gravatar'ı Devre Dışı Bırak
disable_gravatar_popup=Gravatar ve üçüncü parti avatar kaynaklarını iptal edin. Kullanıcı bir avatar yüklemediği zaman varsayılan bir avatar kullanılacaktır.
federated_avatar_lookup=Birleştirilmiş Avatarları Etkinleştir
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=Kendi Kendine Kaydolmayı Devre Dışı Bırak disable_registration=Kendi Kendine Kaydolmayı Devre Dışı Bırak
disable_registration_popup=Kullanıcının kendi kendine kaydolmasını devre dışı bırak. Yalnızca yöneticiler yeni hesaplar oluşturabilecek. disable_registration_popup=Kullanıcının kendi kendine kaydolmasını devre dışı bırak. Yalnızca yöneticiler yeni hesaplar oluşturabilecek.
@ -237,6 +245,7 @@ verify=Doğrula
scratch_code=Çizgi kodu scratch_code=Çizgi kodu
use_scratch_code=Bir çizgi kodu kullanınız use_scratch_code=Bir çizgi kodu kullanınız
twofa_scratch_used=Çizgi kodunuzu kullandınız. İki aşamalı ayarlar sayfasına yönlendirildiniz, burada cihaz kaydınızı kaldırabilir veya yeni bir çizgi kodu oluşturabilirsiniz. twofa_scratch_used=Çizgi kodunuzu kullandınız. İki aşamalı ayarlar sayfasına yönlendirildiniz, burada cihaz kaydınızı kaldırabilir veya yeni bir çizgi kodu oluşturabilirsiniz.
twofa_passcode_incorrect=Şifreniz yanlış. Aygıtınızı yanlış yerleştirdiyseniz, oturum açmak için çizgi kodunuzu kullanın.
twofa_scratch_token_incorrect=Çizgi kodunuz doğru değildir. twofa_scratch_token_incorrect=Çizgi kodunuz doğru değildir.
login_userpass=Oturum Aç login_userpass=Oturum Aç
login_openid=ık Kimlik login_openid=ık Kimlik
@ -251,6 +260,7 @@ openid_connect_title=Mevcut olan bir hesaba bağlan
openid_connect_desc=Seçilen OpenID URI'si bilinmiyor. Burada yeni bir hesapla ilişkilendir. openid_connect_desc=Seçilen OpenID URI'si bilinmiyor. Burada yeni bir hesapla ilişkilendir.
openid_register_title=Yeni hesap oluştur openid_register_title=Yeni hesap oluştur
openid_register_desc=Seçilen OpenID URI'si bilinmiyor. Burada yeni bir hesapla ilişkilendir. openid_register_desc=Seçilen OpenID URI'si bilinmiyor. Burada yeni bir hesapla ilişkilendir.
openid_signin_desc=OpenID URI'nızı girin. Örneğin: https://anne.me, bob.openid.org.cn veya gnusocial.net/carry.
disable_forgot_password_mail=Hesap kurtarma devre dışı. Lütfen site yöneticinizle iletişime geçin. disable_forgot_password_mail=Hesap kurtarma devre dışı. Lütfen site yöneticinizle iletişime geçin.
email_domain_blacklisted=Bu e-posta adresinizle kayıt olamazsınız. email_domain_blacklisted=Bu e-posta adresinizle kayıt olamazsınız.
authorize_application=Uygulamayı Yetkilendir authorize_application=Uygulamayı Yetkilendir
@ -300,6 +310,7 @@ SSPIDefaultLanguage=Varsayılan Dil
require_error=` boş olamaz.` require_error=` boş olamaz.`
alpha_dash_error=` yalnızca alfasayısal, çizgi ('-') ve alt çizgi ('_') karakterlerini içermelidir. ` alpha_dash_error=` yalnızca alfasayısal, çizgi ('-') ve alt çizgi ('_') karakterlerini içermelidir. `
alpha_dash_dot_error=` yalnızca alfasayısal, çizgi ('-'), alt çizgi ('_') ve nokta ('.') karakterlerini içermelidir. ` alpha_dash_dot_error=` yalnızca alfasayısal, çizgi ('-'), alt çizgi ('_') ve nokta ('.') karakterlerini içermelidir. `
git_ref_name_error=` git referans ismi iyi oluşturulmuş olmalıdır.`
size_error=` uzunluk en fazla %s olmalıdır.` size_error=` uzunluk en fazla %s olmalıdır.`
min_size_error=` en az %s karakter içermelidir.` min_size_error=` en az %s karakter içermelidir.`
max_size_error=` en fazla %s karakter içermelidir.` max_size_error=` en fazla %s karakter içermelidir.`
@ -314,6 +325,8 @@ lang_select_error=Listeden bir dil seçin.
username_been_taken=Bu kullanıcı adı daha önce alınmış. username_been_taken=Bu kullanıcı adı daha önce alınmış.
repo_name_been_taken=Depo adı zaten kullanılıyor. repo_name_been_taken=Depo adı zaten kullanılıyor.
visit_rate_limit=Uzaktan ziyarette oran sınırlaması ele alındı.
2fa_auth_required=Uzaktan ziyaret için iki faktörlü kimlik doğrulaması gerekli.
org_name_been_taken=Organizasyon adı zaten kullanılıyor. org_name_been_taken=Organizasyon adı zaten kullanılıyor.
team_name_been_taken=Takım adı zaten alınmış. team_name_been_taken=Takım adı zaten alınmış.
team_no_units_error=En az bir depo bölümüne erişimine izin ver. team_no_units_error=En az bir depo bölümüne erişimine izin ver.
@ -394,6 +407,7 @@ cancel=İptal
language=Dil language=Dil
ui=Tema ui=Tema
lookup_avatar_by_mail=Avatarı E-posta Adresine Göre Ara
federated_avatar_lookup=Birleşmiş Avatar Araması federated_avatar_lookup=Birleşmiş Avatar Araması
enable_custom_avatar=Özel Avatarı Etkinleştir enable_custom_avatar=Özel Avatarı Etkinleştir
choose_new_avatar=Yeni Avatar Seç choose_new_avatar=Yeni Avatar Seç
@ -512,23 +526,45 @@ oauth2_type_native=Yerel (ör. Mobil, Masaüstü, Tarayıcı)
oauth2_redirect_uri=Yönlendirme URI'si oauth2_redirect_uri=Yönlendirme URI'si
save_application=Kaydet save_application=Kaydet
oauth2_client_id=İstemci Kimliği oauth2_client_id=İstemci Kimliği
oauth2_client_secret=İstemci Gizliliği
oauth2_regenerate_secret=Gizliliği Yeniden Oluştur
oauth2_regenerate_secret_hint=Gizliliğini mi kaybettin?
oauth2_client_secret_hint=Bu sayfayı tekrar ziyaret ederseniz gizlilik görünmez. Lütfen gizliliğinizi kaydedin.
oauth2_application_edit=Düzenle oauth2_application_edit=Düzenle
oauth2_application_create_description=OAuth2 uygulamaları, üçüncü taraf uygulamanıza bu durumda kullanıcı hesaplarına erişim sağlar.
oauth2_application_remove_description=Bir OAuth2 uygulamasının kaldırılması, bu durumda yetkili kullanıcı hesaplarına erişmesini önler. Devam edilsin mi?
authorized_oauth2_applications=Yetkili OAuth2 Uygulamaları
authorized_oauth2_applications_description=Kişisel Gitea hesabınıza bu üçüncü parti uygulamalara erişim izni verdiniz. Lütfen artık ihtiyaç duyulmayan uygulamalara erişimi iptal edin.
revoke_key=İptal Et revoke_key=İptal Et
revoke_oauth2_grant=Erişimi İptal Et revoke_oauth2_grant=Erişimi İptal Et
revoke_oauth2_grant_description=Bu üçüncü taraf uygulamasına erişimin iptal edilmesi bu uygulamanın verilerinize erişmesini önleyecektir. Emin misiniz?
revoke_oauth2_grant_success=Erişimi başarıyla iptal ettiniz. revoke_oauth2_grant_success=Erişimi başarıyla iptal ettiniz.
twofa_desc=İki faktörlü kimlik doğrulama, hesabınızın güvenliğini artırır.
twofa_is_enrolled=Hesabınız şu anda iki faktörlü kimlik doğrulaması içinde <strong>kaydedilmiş</strong>. twofa_is_enrolled=Hesabınız şu anda iki faktörlü kimlik doğrulaması içinde <strong>kaydedilmiş</strong>.
twofa_not_enrolled=Hesabınız şu anda iki faktörlü kimlik doğrulaması içinde kaydedilmemiş. twofa_not_enrolled=Hesabınız şu anda iki faktörlü kimlik doğrulaması içinde kaydedilmemiş.
twofa_disable=İki Aşamalı Doğrulamayı Devre Dışı Bırak
twofa_scratch_token_regenerate=Kazıma Belirtecini Yenile
twofa_scratch_token_regenerated=Kazıma belirteciniz şimdi %s. Güvenli bir yerde saklayın.
twofa_enroll=İki Faktörlü Kimlik Doğrulamaya Kaydolun
twofa_disable_note=Gerekirse iki faktörlü kimlik doğrulamayı devre dışı bırakabilirsiniz.
twofa_disable_desc=İki faktörlü kimlik doğrulamayı devre dışı bırakmak hesabınızı daha az güvenli hale getirir. Devam edilsin mi?
regenerate_scratch_token_desc=Karalama belirtecinizi yanlış yerleştirdiyseniz veya oturum açmak için kullandıysanız, buradan sıfırlayabilirsiniz.
twofa_disabled=İki faktörlü kimlik doğrulama devre dışı bırakıldı. twofa_disabled=İki faktörlü kimlik doğrulama devre dışı bırakıldı.
scan_this_image=Kim doğrulama uygulamanızla bu görüntüyü tarayın: scan_this_image=Kim doğrulama uygulamanızla bu görüntüyü tarayın:
or_enter_secret=Veya gizli şeyi girin: %s or_enter_secret=Veya gizli şeyi girin: %s
then_enter_passcode=Ve uygulamada gösterilen şifreyi girin: then_enter_passcode=Ve uygulamada gösterilen şifreyi girin:
passcode_invalid=Şifre geçersiz. Tekrar deneyin. passcode_invalid=Şifre geçersiz. Tekrar deneyin.
twofa_enrolled=Hesabınız iki faktörlü kimlik doğrulamasına kaydedildi. Kazıma belirtecini (%s) yalnızca bir kez gösterdiği gibi güvenli bir yerde saklayın!
u2f_desc=Güvenlik anahtarları, şifreleme anahtarlarını içeren donanım aygıtlarıdır. İki faktörlü kimlik doğrulama için kullanılabilirler. Güvenlik anahtarları <a rel="noreferrer" href="https://fidoalliance.org/">FIDO U2F</a> standardını desteklemelidir.
u2f_require_twofa=Güvenlik anahtarlarını kullanmak için hesabınızın iki faktörlü kimlik doğrulamasına kaydedilmiş olması gerekir.
u2f_register_key=Güvenlik Anahtarı Ekle u2f_register_key=Güvenlik Anahtarı Ekle
u2f_nickname=Takma Ad u2f_nickname=Takma Ad
u2f_press_button=Kaydetmek için güvenlik anahtarınızdaki düğmeye basın.
u2f_delete_key=Güvenlik Anahtarını Sil u2f_delete_key=Güvenlik Anahtarını Sil
u2f_delete_key_desc=Bir güvenlik anahtarını kaldırırsanız, artık onunla giriş yapamazsınız. Devam edilsin mi?
manage_account_links=Bağlı Hesapları Yönet manage_account_links=Bağlı Hesapları Yönet
manage_account_links_desc=Bu harici hesaplar Gitea hesabınızla bağlantılı. manage_account_links_desc=Bu harici hesaplar Gitea hesabınızla bağlantılı.
@ -559,6 +595,7 @@ repo_size=Depo Boyutu
template=Şablon template=Şablon
template_select=Bir şablon seçin. template_select=Bir şablon seçin.
template_helper=Depoyu şablon yap template_helper=Depoyu şablon yap
template_description=Şablon depoları, kullanıcıların aynı dizin yapısı, dosyaları ve isteğe bağlı ayarlarla yeni depoları oluşturmasına izin verir.
visibility=Görünürlük visibility=Görünürlük
visibility_description=Yalnızca sahibi veya haklara sahip organizasyon üyeleri onu görebilecek. visibility_description=Yalnızca sahibi veya haklara sahip organizasyon üyeleri onu görebilecek.
visibility_helper=Depoyu Gizli Yap visibility_helper=Depoyu Gizli Yap
@ -584,8 +621,12 @@ auto_init=Depoyu başlat (.gitignore, Lisans ve README dosyalarını ekler)
create_repo=Depo Oluştur create_repo=Depo Oluştur
default_branch=Varsayılan Dal default_branch=Varsayılan Dal
mirror_prune=Buda mirror_prune=Buda
mirror_prune_desc=Kullanılmayan uzak depoları izleyen referansları kaldır
mirror_interval=Yansı Aralığı (geçerli zaman birimleri 'h', 'm', 's'). 0 otomatik senkronizasyonu devre dışı bırakmak için.
mirror_interval_invalid=Yansı süre aralığı geçerli değil. mirror_interval_invalid=Yansı süre aralığı geçerli değil.
mirror_address=URL'den Klonla mirror_address=URL'den Klonla
mirror_address_desc=Gerekli kimlikleri Yetkilendirmeyi Klonla bölümüne girin.
mirror_address_url_invalid=Sağlanan Url geçersiz. Url'nin tüm bileşenlerinden doğru olarak kaçmalısınız.
mirror_address_protocol_invalid=Sağlanan url geçersiz. Yalnızca http(s):// veya git:// konumları yansıtılabilir. mirror_address_protocol_invalid=Sağlanan url geçersiz. Yalnızca http(s):// veya git:// konumları yansıtılabilir.
mirror_last_synced=Son Senkronize Edilen mirror_last_synced=Son Senkronize Edilen
watchers=İzleyenler watchers=İzleyenler
@ -597,7 +638,9 @@ reactions_more=ve %d daha fazla
template.items=Şablon Öğeleri template.items=Şablon Öğeleri
template.git_content=Git İçeriği (Varsayılan Dal) template.git_content=Git İçeriği (Varsayılan Dal)
template.git_hooks=Git İstekleri template.git_hooks=Git İstekleri
template.git_hooks_tooltip=Şu anda bir kez eklenen git isteklerini değiştirmek veya kaldırmak mümkün değildir. Bunu yalnızca şablon deposuna güveniyorsanız seçin.
template.webhooks=Web İstekleri template.webhooks=Web İstekleri
template.topics=Konular
template.avatar=Profil Resmi template.avatar=Profil Resmi
template.issue_labels=Konu Etiketleri template.issue_labels=Konu Etiketleri
template.one_item=En az bir şablon öğesi seçmelisiniz template.one_item=En az bir şablon öğesi seçmelisiniz
@ -700,6 +743,7 @@ editor.delete_this_file=Dosyayı Sil
editor.must_have_write_access=Bu dosyada değişiklikler yapmak veya önermek için yazma erişiminizin olması gerekir. editor.must_have_write_access=Bu dosyada değişiklikler yapmak veya önermek için yazma erişiminizin olması gerekir.
editor.file_delete_success='%s' dosyası silindi. editor.file_delete_success='%s' dosyası silindi.
editor.name_your_file=Dosyanızı isimlendirin… editor.name_your_file=Dosyanızı isimlendirin…
editor.filename_help=Bölü ('/') işaretiyle ismini yazarak bir dizin ekleyebilirsiniz. Dizini silmek için girdi sahasının başına backspace yazmalısınız.
editor.or=veya editor.or=veya
editor.cancel_lower=İptal editor.cancel_lower=İptal
editor.commit_changes=Değişiklikleri Uygula editor.commit_changes=Değişiklikleri Uygula
@ -739,6 +783,7 @@ commits.desc=Kaynak kodu değişiklik geçmişine göz atın.
commits.commits=İşlemeler commits.commits=İşlemeler
commits.no_commits=Ortak bir işleme yok. '%s' ve '%s' tamamen farklı geçmişlere sahip. commits.no_commits=Ortak bir işleme yok. '%s' ve '%s' tamamen farklı geçmişlere sahip.
commits.search=İşlemeleri ara… commits.search=İşlemeleri ara…
commits.search.tooltip=Anahtar kelimeleri "yazar:", "yorumcu:", "sonra:" veya "önce:", örneğin; "eski haline yazan: Alice önce: 2019-04-01" önekleyebilirsiniz.
commits.find=Ara commits.find=Ara
commits.search_all=Tüm Dallar commits.search_all=Tüm Dallar
commits.author=Yazar commits.author=Yazar
@ -837,6 +882,7 @@ issues.num_comments=%d yorum
issues.commented_at=`<a href="#%s">%s</a> yorum yaptı` issues.commented_at=`<a href="#%s">%s</a> yorum yaptı`
issues.delete_comment_confirm=Bu yorumu silmek istediğinizden emin misiniz? issues.delete_comment_confirm=Bu yorumu silmek istediğinizden emin misiniz?
issues.context.copy_link=Bağlantıyı Kopyala issues.context.copy_link=Bağlantıyı Kopyala
issues.context.quote_reply=Alıntı Cevapla
issues.context.edit=Düzenle issues.context.edit=Düzenle
issues.context.delete=Sil issues.context.delete=Sil
issues.no_content=Henüz bir içerik yok. issues.no_content=Henüz bir içerik yok.
@ -848,6 +894,7 @@ issues.create_comment=Yorum yap
issues.closed_at=`<a id="%[1]s" href="#%[1]s">%[2]s</a> kapattı` issues.closed_at=`<a id="%[1]s" href="#%[1]s">%[2]s</a> kapattı`
issues.reopened_at=`<a id="%[1]s" href="#%[1]s">%[2]s</a> yeniden açtı` issues.reopened_at=`<a id="%[1]s" href="#%[1]s">%[2]s</a> yeniden açtı`
issues.commit_ref_at=`<a id="%[1]s" href="#%[1]s">%[2]s</a> işlemesinde bu konuyu işaret etti` issues.commit_ref_at=`<a id="%[1]s" href="#%[1]s">%[2]s</a> işlemesinde bu konuyu işaret etti`
issues.ref_from=`%[1]s'den`
issues.poster=Poster issues.poster=Poster
issues.collaborator=Katkıcı issues.collaborator=Katkıcı
issues.owner=Sahibi issues.owner=Sahibi
@ -906,6 +953,7 @@ issues.add_time=El ile Zaman Ekle
issues.add_time_short=Zaman Ekle issues.add_time_short=Zaman Ekle
issues.add_time_cancel=İptal issues.add_time_cancel=İptal
issues.add_time_history=`%s harcanan zaman eklendi` issues.add_time_history=`%s harcanan zaman eklendi`
issues.del_time_history=`%s harcanan zaman silindi`
issues.add_time_hours=Saat issues.add_time_hours=Saat
issues.add_time_minutes=Dakika issues.add_time_minutes=Dakika
issues.add_time_sum_to_small=Zaman girilmedi. issues.add_time_sum_to_small=Zaman girilmedi.
@ -972,13 +1020,16 @@ pulls.desc=Değişiklik isteklerini ve kod incelemelerini etkinleştir.
pulls.new=Yeni Değişiklik İsteği pulls.new=Yeni Değişiklik İsteği
pulls.compare_changes=Yeni Değişiklik İsteği pulls.compare_changes=Yeni Değişiklik İsteği
pulls.compare_changes_desc=Birleştirmek için hedef ve kaynak dalı seçin. pulls.compare_changes_desc=Birleştirmek için hedef ve kaynak dalı seçin.
pulls.compare_base=birleştir
pulls.compare_compare=şuradan çek pulls.compare_compare=şuradan çek
pulls.filter_branch=Dal filtrele pulls.filter_branch=Dal filtrele
pulls.no_results=Sonuç bulunamadı. pulls.no_results=Sonuç bulunamadı.
pulls.nothing_to_compare=Bu dallar eşit. Değişiklik isteği oluşturmaya gerek yok. pulls.nothing_to_compare=Bu dallar eşit. Değişiklik isteği oluşturmaya gerek yok.
pulls.has_pull_request=`Bu dallar arasında bir değişiklik isteği zaten var: <a href="%[1]s/pulls/%[3]d">%[2]s#%[3]d</a>` pulls.has_pull_request=`Bu dallar arasında bir değişiklik isteği zaten var: <a href="%[1]s/pulls/%[3]d">%[2]s#%[3]d</a>`
pulls.create=Değişiklik İsteği Oluştur pulls.create=Değişiklik İsteği Oluştur
pulls.title_desc=<code id="branch_target">%[3]s</code> içindeki <code>%[2]s</code> işlemelerini %[1]d ile birleştirmek istiyor
pulls.merged_title_desc=%[4]s <code>%[2]s</code> içindeki %[1]d işleme <code>%[3]s</code> ile birleştirdi pulls.merged_title_desc=%[4]s <code>%[2]s</code> içindeki %[1]d işleme <code>%[3]s</code> ile birleştirdi
pulls.change_target_branch_at='hedef dal <b>%s</b> adresinden <b>%s</b>%s adresine değiştirildi'
pulls.tab_conversation=Sohbet pulls.tab_conversation=Sohbet
pulls.tab_commits=İşlemeler pulls.tab_commits=İşlemeler
pulls.tab_files=Değiştirilen Dosyalar pulls.tab_files=Değiştirilen Dosyalar
@ -986,6 +1037,7 @@ pulls.reopen_to_merge=Bir birleşim uygulamak için lütfen bu çekme isteğini
pulls.cant_reopen_deleted_branch=Dal silindiğinden bu değişiklik isteği yeniden açılamaz. pulls.cant_reopen_deleted_branch=Dal silindiğinden bu değişiklik isteği yeniden açılamaz.
pulls.merged=Birleştirildi pulls.merged=Birleştirildi
pulls.merged_as=Değişiklik isteği <a rel="nofollow" class="ui sha" href="%[1]s"><code>%[2]s</code></a> olarak birleştirildi. pulls.merged_as=Değişiklik isteği <a rel="nofollow" class="ui sha" href="%[1]s"><code>%[2]s</code></a> olarak birleştirildi.
pulls.is_closed=Değişiklik isteği kapatıldı.
pulls.has_merged=Değişiklik isteği birleştirildi. pulls.has_merged=Değişiklik isteği birleştirildi.
pulls.title_wip_desc=`Değişiklik isteğinin yanlışlıkla birleştirilmesini önlemek için, <a href="#">başlığı <strong>%s</strong> ile başlatın</a>` pulls.title_wip_desc=`Değişiklik isteğinin yanlışlıkla birleştirilmesini önlemek için, <a href="#">başlığı <strong>%s</strong> ile başlatın</a>`
pulls.cannot_merge_work_in_progress=Bu değişiklik isteği devam eden bir çalışma olarak işaretlendi. Hazır olduğunda <strong>%s</strong> ön ekini başlıktan kaldırın pulls.cannot_merge_work_in_progress=Bu değişiklik isteği devam eden bir çalışma olarak işaretlendi. Hazır olduğunda <strong>%s</strong> ön ekini başlıktan kaldırın
@ -995,6 +1047,7 @@ pulls.is_checking=Birleştirme çakışması denetimi devam ediyor. Birkaç daki
pulls.required_status_check_failed=Bazı gerekli denetimler başarılı olmadı. pulls.required_status_check_failed=Bazı gerekli denetimler başarılı olmadı.
pulls.required_status_check_administrator=Yönetici olarak, bu değişiklik isteğini yine de birleştirebilirsiniz. pulls.required_status_check_administrator=Yönetici olarak, bu değişiklik isteğini yine de birleştirebilirsiniz.
pulls.blocked_by_approvals=Bu değişiklik isteği henüz onaylanmadı. %[2]d isteğin %[1]d onayı verildi. pulls.blocked_by_approvals=Bu değişiklik isteği henüz onaylanmadı. %[2]d isteğin %[1]d onayı verildi.
pulls.blocked_by_rejection=Bu Değişiklik İsteğinde, resmi bir inceleyeci tarafından istenen değişiklikler var.
pulls.can_auto_merge_desc=Bu değişiklik isteği otomatik olarak birleştirilebilir. pulls.can_auto_merge_desc=Bu değişiklik isteği otomatik olarak birleştirilebilir.
pulls.cannot_auto_merge_desc=Bu değişiklik isteği, çakışmalar nedeniyle otomatik olarak birleştirilemiyor. pulls.cannot_auto_merge_desc=Bu değişiklik isteği, çakışmalar nedeniyle otomatik olarak birleştirilemiyor.
pulls.cannot_auto_merge_helper=Çakışmaları çözmek için el ile birleştirin. pulls.cannot_auto_merge_helper=Çakışmaları çözmek için el ile birleştirin.
@ -1007,6 +1060,10 @@ pulls.rebase_merge_pull_request=Rebase ve Merge
pulls.rebase_merge_commit_pull_request=Rebase ve Merge (--no-ff) pulls.rebase_merge_commit_pull_request=Rebase ve Merge (--no-ff)
pulls.squash_merge_pull_request=Squash ve Merge pulls.squash_merge_pull_request=Squash ve Merge
pulls.invalid_merge_option=Bu değişiklik isteği için bu birleştirme seçeneğini kullanamazsınız. pulls.invalid_merge_option=Bu değişiklik isteği için bu birleştirme seçeneğini kullanamazsınız.
pulls.merge_conflict=Birleştirme Başarısız: Birleşirken bir çakışma oluştu: %[1]s<br>%[2]s<br>İpucu: Farklı bir strateji deneyin
pulls.rebase_conflict=Birleştirme Başarısız: Yeniden işleme yaparken bir çakışma vardı: %[1]s<br>%[2]s<br>%[3]s<br>İpucu: Farklı bir strateji deneyin
pulls.unrelated_histories=Birleştirme Başarısız: Birleştirme başlığı ve tabanı ortak bir geçmişi paylaşmıyor. İpucu: Farklı bir strateji deneyin
pulls.merge_out_of_date=Birleştirme Başarısız: Birleştirme oluşturulurken, taban güncellendi. İpucu: Tekrar deneyin.
pulls.open_unmerged_pull_exists=`Aynı özelliklere sahip bekleyen bir çekme isteği (#%d) olduğundan yeniden açma işlemini gerçekleştiremezsiniz.` pulls.open_unmerged_pull_exists=`Aynı özelliklere sahip bekleyen bir çekme isteği (#%d) olduğundan yeniden açma işlemini gerçekleştiremezsiniz.`
pulls.status_checking=Bazı denetlemeler beklemede pulls.status_checking=Bazı denetlemeler beklemede
pulls.status_checks_success=Tüm denetlemeler başarılı oldu pulls.status_checks_success=Tüm denetlemeler başarılı oldu
@ -1167,18 +1224,26 @@ settings.use_external_wiki=Harici Wiki Kullan
settings.external_wiki_url=Harici Wiki bağlantısı settings.external_wiki_url=Harici Wiki bağlantısı
settings.external_wiki_url_error=Harici wiki URL'si geçerli bir URL değil. settings.external_wiki_url_error=Harici wiki URL'si geçerli bir URL değil.
settings.external_wiki_url_desc=Ziyaretçiler, wiki sekmesine tıklandığında harici wiki URL'sine yönlendirilir. settings.external_wiki_url_desc=Ziyaretçiler, wiki sekmesine tıklandığında harici wiki URL'sine yönlendirilir.
settings.issues_desc=Depo Sorun İzleyicisini Etkinleştir
settings.use_internal_issue_tracker=Yerleşik Sorun İzleyiciyi Kullan
settings.use_external_issue_tracker=Harici Sorun İzleyici Kullan
settings.external_tracker_url=Harici Konu İzleyici URLsi settings.external_tracker_url=Harici Konu İzleyici URLsi
settings.external_tracker_url_error=Harici sorun izleyici URL'si geçerli bir URL değil.
settings.external_tracker_url_desc=Ziyaretçiler, konular sekmesine tıklandığında harici konu izleyici URL'sine yönlendirilir. settings.external_tracker_url_desc=Ziyaretçiler, konular sekmesine tıklandığında harici konu izleyici URL'sine yönlendirilir.
settings.tracker_url_format=Harici Sorun Takipçisi Bağlantı Formatı settings.tracker_url_format=Harici Sorun Takipçisi Bağlantı Formatı
settings.tracker_url_format_error=Harici konu izleyici URL biçimi geçerli bir URL değil. settings.tracker_url_format_error=Harici konu izleyici URL biçimi geçerli bir URL değil.
settings.tracker_issue_style=Harici Konu İzleyici Numara Biçimi settings.tracker_issue_style=Harici Konu İzleyici Numara Biçimi
settings.tracker_issue_style.numeric=Sayısal settings.tracker_issue_style.numeric=Sayısal
settings.tracker_issue_style.alphanumeric=Alfanumerik settings.tracker_issue_style.alphanumeric=Alfanumerik
settings.tracker_url_format_desc=Kullanıcı adı, depo adı ve yayın dizini için <code>{user}</code>, <code>{repo}</code> ve <code>{index}</code> yer tutucularını kullanın.
settings.enable_timetracker=Zaman Takibini Etkinleştir settings.enable_timetracker=Zaman Takibini Etkinleştir
settings.allow_only_contributors_to_track_time=Sadece Katkıcılar İçin Zaman Takibine İzin Ver settings.allow_only_contributors_to_track_time=Sadece Katkıcılar İçin Zaman Takibine İzin Ver
settings.pulls_desc=Değişiklik İsteklerini Etkinleştir settings.pulls_desc=Değişiklik İsteklerini Etkinleştir
settings.pulls.ignore_whitespace=Çakışmalar için Boşlukları Gözardı Et settings.pulls.ignore_whitespace=Çakışmalar için Boşlukları Gözardı Et
settings.pulls.allow_merge_commits=İşleme Birleştirmeyi Etkinleştir settings.pulls.allow_merge_commits=İşleme Birleştirmeyi Etkinleştir
settings.pulls.allow_rebase_merge=İşlemeleri Birleştirmek için Yeniden Yapılandırmayı Etkinleştir
settings.pulls.allow_rebase_merge_commit=ık birleştirme işlemeleri ile Yeniden Yapılandırmayı Etkinleştir (--no-ff)
settings.pulls.allow_squash_commits=İşlemeleri Birleştirmek için Sıkmayı Etkinleştir
settings.admin_settings=Yönetici Ayarları settings.admin_settings=Yönetici Ayarları
settings.admin_enable_health_check=Depo Sağlık Kontrollerini Etkinleştir (git fsck) settings.admin_enable_health_check=Depo Sağlık Kontrollerini Etkinleştir (git fsck)
settings.admin_enable_close_issues_via_commit_in_any_branch=Varsayılan olmayan bir dalda yapılan bir işlemeyle konuyu kapat settings.admin_enable_close_issues_via_commit_in_any_branch=Varsayılan olmayan bir dalda yapılan bir işlemeyle konuyu kapat
@ -1192,6 +1257,7 @@ settings.convert_succeed=Yansı normal bir depoya dönüştürüldü.
settings.transfer=Sahipliği Aktar settings.transfer=Sahipliği Aktar
settings.transfer_desc=Bu depoyu bir kullanıcıya veya yönetici haklarına sahip olduğunuz bir organizasyona aktarın. settings.transfer_desc=Bu depoyu bir kullanıcıya veya yönetici haklarına sahip olduğunuz bir organizasyona aktarın.
settings.transfer_notices_1=- Bireysel bir kullanıcıya aktarırsanız depoya erişiminizi kaybedersiniz. settings.transfer_notices_1=- Bireysel bir kullanıcıya aktarırsanız depoya erişiminizi kaybedersiniz.
settings.transfer_notices_2=- Sahip (-yardımcı) olduğunuz bir kuruluşa devrederseniz, depoya erişmeye devam edersiniz.
settings.transfer_form_title=Onaylamak için depo adını girin: settings.transfer_form_title=Onaylamak için depo adını girin:
settings.wiki_delete=Wiki Verisini Sil settings.wiki_delete=Wiki Verisini Sil
settings.wiki_delete_desc=Depo wiki verilerini silmek kalıcıdır ve geri alınamaz. settings.wiki_delete_desc=Depo wiki verilerini silmek kalıcıdır ve geri alınamaz.
@ -1201,6 +1267,7 @@ settings.wiki_deletion_success=Depo wiki verisi silindi.
settings.delete=Bu Depoyu Sil settings.delete=Bu Depoyu Sil
settings.delete_desc=Bir depoyu silmek kalıcıdır ve geri alınamaz. settings.delete_desc=Bir depoyu silmek kalıcıdır ve geri alınamaz.
settings.delete_notices_1=- Bu işlem geri <strong>ALINAMAZ</strong>. settings.delete_notices_1=- Bu işlem geri <strong>ALINAMAZ</strong>.
settings.delete_notices_2=- Bu işlem, kod, sorunlar, yorumlar, wiki verileri ve katkıcı ayarları dahil olmak üzere <strong>%s</strong> deposunu kalıcı olarak siler.
settings.delete_notices_fork_1=- Silme işleminden sonra bu deponun çatalları bağımsız hale gelecektir. settings.delete_notices_fork_1=- Silme işleminden sonra bu deponun çatalları bağımsız hale gelecektir.
settings.deletion_success=Depo silindi. settings.deletion_success=Depo silindi.
settings.update_settings_success=Depo ayarları güncellendi. settings.update_settings_success=Depo ayarları güncellendi.
@ -1273,6 +1340,7 @@ settings.event_pull_request_desc=Değişiklik isteği açıldığında, kapatıl
settings.event_push=Çek settings.event_push=Çek
settings.event_push_desc=Depo ittirildiğinde. settings.event_push_desc=Depo ittirildiğinde.
settings.branch_filter=Dal filtresi settings.branch_filter=Dal filtresi
settings.branch_filter_desc=Glob deseni olarak belirtilen itme, dal oluşturma ve dal silme olayları için dal beyaz listesi. Boş veya <code>*</code> ise, tüm dallar için olaylar bildirilir. Sözdizimi için <a href="https://godoc.org/github.com/gobwas/glob#Compile">github.com/gobwas/glob</a> belgelerine bakın. Örnekler: <code>master</code>, <code>{master,release*}</code>.
settings.event_repository=Depo settings.event_repository=Depo
settings.event_repository_desc=Depo oluşturuldu veya silindi. settings.event_repository_desc=Depo oluşturuldu veya silindi.
settings.active=Etkin settings.active=Etkin
@ -1312,6 +1380,14 @@ settings.protected_branch_can_push_yes=İtebilirsiniz
settings.protected_branch_can_push_no=İtemezsiniz settings.protected_branch_can_push_no=İtemezsiniz
settings.branch_protection=<b>%s</b> dalı için Dal Koruması settings.branch_protection=<b>%s</b> dalı için Dal Koruması
settings.protect_this_branch=Dal Korumayı Etkinleştir settings.protect_this_branch=Dal Korumayı Etkinleştir
settings.protect_this_branch_desc=Silmeyi önler ve dala Git itmesini ve birleştirmesini kısıtlar.
settings.protect_disable_push=İtmeyi Devre Dışı Bırak
settings.protect_disable_push_desc=Bu dala itme yapılmasına izin verilmeyecek.
settings.protect_enable_push=İtmeyi Etkinleştir
settings.protect_enable_push_desc=Yazma erişimi olan herkesin bu dala itmesine izin verilir (ancak zorla itmeyin).
settings.protect_whitelist_committers=Beyaz Liste Sınırlı İtme
settings.protect_whitelist_committers_desc=Sadece beyaz listeye alınmış kullanıcıların veya takımların bu dala itmesine izin verilir (ancak zorla itmeyin).
settings.protect_whitelist_deploy_keys=Beyaz liste itmek için yazma erişimli anahtarları dağıtır
settings.protect_whitelist_users=İtme için beyaz listedeki kullanıcılar: settings.protect_whitelist_users=İtme için beyaz listedeki kullanıcılar:
settings.protect_whitelist_search_users=Kullanıcı ara… settings.protect_whitelist_search_users=Kullanıcı ara…
settings.protect_whitelist_teams=İtme için beyaz listedeki takımlar: settings.protect_whitelist_teams=İtme için beyaz listedeki takımlar:
@ -1321,8 +1397,12 @@ settings.protect_merge_whitelist_committers_desc=Yalnızca beyaz listedeki kulla
settings.protect_merge_whitelist_users=Birleştirme için beyaz listedeki kullanıcılar: settings.protect_merge_whitelist_users=Birleştirme için beyaz listedeki kullanıcılar:
settings.protect_merge_whitelist_teams=Birleştirme için beyaz listedeki takımlar: settings.protect_merge_whitelist_teams=Birleştirme için beyaz listedeki takımlar:
settings.protect_check_status_contexts=Durum Denetimini Etkinleştir settings.protect_check_status_contexts=Durum Denetimini Etkinleştir
settings.protect_check_status_contexts_desc=Birleşmeden önce durum denetimlerinin geçmesini isteyin Dallar bu kuralla eşleşen bir dalda birleştirilmeden önce hangi durum denetimlerinin geçmesi gerektiğini seçin. Etkinleştirildiğinde, işlemelerin önce başka bir dala itilmesi, ardından durum kontrolleri geçtikten sonra doğrudan bu kuralla eşleşen bir dala birleştirilmesi veya itilmesi gerekir. Hiçbir bağlam seçilmezse, bağlam ne olursa olsun son işlem başarılı olmalıdır.
settings.protect_check_status_contexts_list=Bu depo için geçen haftadaki durum denetimleri settings.protect_check_status_contexts_list=Bu depo için geçen haftadaki durum denetimleri
settings.protect_required_approvals=Gerekli onaylar: settings.protect_required_approvals=Gerekli onaylar:
settings.protect_required_approvals_desc=Değişiklik isteğini yalnızca yeterince olumlu yorumla birleştirmeye izin ver.
settings.protect_approvals_whitelist_enabled=Onayları beyaz listeye giren kullanıcılar veya takımlar için kısıtla
settings.protect_approvals_whitelist_enabled_desc=Yalnızca beyaz listedeki kullanıcıların veya ekiplerin incelemeleri gerekli onaylar için dikkate alınır. Onaylı beyaz liste olmadan, yazma erişimi olan herkesin incelemeleri gerekli onaylar için dikkate alınır.
settings.protect_approvals_whitelist_users=Beyaz listedeki incelemeciler: settings.protect_approvals_whitelist_users=Beyaz listedeki incelemeciler:
settings.protect_approvals_whitelist_teams=Gözden geçirme için beyaz listedeki takımlar: settings.protect_approvals_whitelist_teams=Gözden geçirme için beyaz listedeki takımlar:
settings.add_protected_branch=Korumayı etkinleştir settings.add_protected_branch=Korumayı etkinleştir
@ -1331,6 +1411,8 @@ settings.update_protect_branch_success='%s' dalı için dal koruması güncellen
settings.remove_protected_branch_success='%s' dalı için dal koruması devre dışı bırakıldı. settings.remove_protected_branch_success='%s' dalı için dal koruması devre dışı bırakıldı.
settings.protected_branch_deletion=Dal Korumasını Devre Dışı Bırak settings.protected_branch_deletion=Dal Korumasını Devre Dışı Bırak
settings.protected_branch_deletion_desc=Dal korumasını devre dışı bırakmak, kullanıcıların dalı itmek için yazma izni olmasını sağlar. Devam edilsin mi? settings.protected_branch_deletion_desc=Dal korumasını devre dışı bırakmak, kullanıcıların dalı itmek için yazma izni olmasını sağlar. Devam edilsin mi?
settings.block_rejected_reviews=Reddedilen incelemelerde birleştirmeyi engelle
settings.block_rejected_reviews_desc=Yeterli onay olsa bile resmi inceleyiciler tarafından değişiklik istendiğinde birleşme mümkün olmayacaktır.
settings.default_branch_desc=Değişiklik istekleri ve kod işlemeleri için varsayılan bir depo dalı seçin: settings.default_branch_desc=Değişiklik istekleri ve kod işlemeleri için varsayılan bir depo dalı seçin:
settings.choose_branch=Bir dal seç… settings.choose_branch=Bir dal seç…
settings.no_protected_branch=Korumalı dal yok. settings.no_protected_branch=Korumalı dal yok.
@ -1356,12 +1438,26 @@ settings.lfs_filelist=Bu depoda barındırılan LFS dosyaları
settings.lfs_no_lfs_files=Bu depoda barındırılan herhangi bir LFS dosyası yok settings.lfs_no_lfs_files=Bu depoda barındırılan herhangi bir LFS dosyası yok
settings.lfs_findcommits=İşleme bul settings.lfs_findcommits=İşleme bul
settings.lfs_lfs_file_no_commits=Bu LFS dosyası için hiçbir işleme bulunamadı settings.lfs_lfs_file_no_commits=Bu LFS dosyası için hiçbir işleme bulunamadı
settings.lfs_noattribute=Bu yol, varsayılan dalda kilitlenebilir özelliğe sahip değil
settings.lfs_delete=OID %s ile LFS dosyasını sil
settings.lfs_delete_warning=Bir LFS dosyasını silmek, ödeme sırasında 'nesne yok' hatalarına neden olabilir. Emin misiniz?
settings.lfs_findpointerfiles=İşaretçi dosyalarını bul settings.lfs_findpointerfiles=İşaretçi dosyalarını bul
settings.lfs_locks=Kilitler
settings.lfs_invalid_locking_path=Geçersiz yol: %s
settings.lfs_invalid_lock_directory=Dizin kilitlenemiyor: %s
settings.lfs_lock_already_exists=Kilit zaten var: %s
settings.lfs_lock=Kilitle
settings.lfs_lock_path=Kilitlenecek dosya yolu...
settings.lfs_locks_no_locks=Kilit yok
settings.lfs_lock_file_no_exist=Kilitli dosya varsayılan dalda mevcut değil
settings.lfs_force_unlock=Kilidi Açmaya Zorla
settings.lfs_pointers.found=Bulunan %d blob işaretçi(leri) - %d ilişkili, %d ilişkilendirilmemiş (%d mağazadan eksik)
settings.lfs_pointers.sha=Blob SHA settings.lfs_pointers.sha=Blob SHA
settings.lfs_pointers.oid=OID settings.lfs_pointers.oid=OID
settings.lfs_pointers.inRepo=Depoda settings.lfs_pointers.inRepo=Depoda
settings.lfs_pointers.exists=Mağazada var settings.lfs_pointers.exists=Mağazada var
settings.lfs_pointers.accessible=Kullanıcı tarafından erişilebilir settings.lfs_pointers.accessible=Kullanıcı tarafından erişilebilir
settings.lfs_pointers.associateAccessible=Erişilebilir %d OID ilişkilendirme
diff.browse_source=Kaynağa Gözat diff.browse_source=Kaynağa Gözat
diff.parent=ebeveyn diff.parent=ebeveyn
@ -1455,8 +1551,12 @@ branch.protected_deletion_failed='%s' dalı korunuyor. Silinemez.
branch.restore='%s' Dalını Geri Yükle branch.restore='%s' Dalını Geri Yükle
branch.download='%s' Dalını İndir branch.download='%s' Dalını İndir
branch.included_desc=Bu dal varsayılan dalın bir parçasıdır branch.included_desc=Bu dal varsayılan dalın bir parçasıdır
branch.included=Dahil
topic.manage_topics=Konuları Yönet
topic.done=Bitti topic.done=Bitti
topic.count_prompt=25'ten fazla konu seçemezsiniz
topic.format_prompt=Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
[org] [org]
org_name_holder=Organizasyon Adı org_name_holder=Organizasyon Adı
@ -1522,6 +1622,8 @@ members.invite_now=Şimdi Davet Et
teams.join=Katıl teams.join=Katıl
teams.leave=Ayrıl teams.leave=Ayrıl
teams.can_create_org_repo=Depoları oluştur
teams.can_create_org_repo_helper=Üyeler organizasyonda yeni depolar oluşturabilirler. Oluşturan yeni depoya yönetici erişimi sağlayacak.
teams.read_access=Okuma Erişimi teams.read_access=Okuma Erişimi
teams.read_access_helper=Üyeler, takım depolarını görüntüleyebilir ve klonlayabilir. teams.read_access_helper=Üyeler, takım depolarını görüntüleyebilir ve klonlayabilir.
teams.write_access=Yazma Erişimi teams.write_access=Yazma Erişimi
@ -1541,6 +1643,7 @@ teams.delete_team_success=Takım silindi.
teams.read_permission_desc=Bu takım <strong>Okuma</strong> erişimi veriyor. Üyeler takım depolarını görüntüleyebilir ve klonlayabilir. teams.read_permission_desc=Bu takım <strong>Okuma</strong> erişimi veriyor. Üyeler takım depolarını görüntüleyebilir ve klonlayabilir.
teams.write_permission_desc=Bu takım <strong>Yazma</strong> erişimi veriyor. Üyeler takım depolarından okuyabilir ve takım depolarına itme yapabilir. teams.write_permission_desc=Bu takım <strong>Yazma</strong> erişimi veriyor. Üyeler takım depolarından okuyabilir ve takım depolarına itme yapabilir.
teams.admin_permission_desc=Bu takım <strong>Yönetici</strong> erişimi veriyor. Üyeler takım depolarını okuyabilir, itebilir ve katkıcı ekleyebilir. teams.admin_permission_desc=Bu takım <strong>Yönetici</strong> erişimi veriyor. Üyeler takım depolarını okuyabilir, itebilir ve katkıcı ekleyebilir.
teams.create_repo_permission_desc=Ayrıca, bu takım <strong>Depo oluşturma</strong> izni verir: üyeler organizasyonda yeni depolar oluşturabilir.
teams.repositories=Ekip Depoları teams.repositories=Ekip Depoları
teams.search_repo_placeholder=Depo ara… teams.search_repo_placeholder=Depo ara…
teams.remove_all_repos_title=Tüm takım depolarını kaldır teams.remove_all_repos_title=Tüm takım depolarını kaldır
@ -1552,7 +1655,12 @@ teams.add_duplicate_users=Kullanıcı zaten takımın üyesi.
teams.repos.none=Bu takım tarafından hiçbir depoya erişilemedi. teams.repos.none=Bu takım tarafından hiçbir depoya erişilemedi.
teams.members.none=Bu takımda üye yok. teams.members.none=Bu takımda üye yok.
teams.specific_repositories=Belirli depolar teams.specific_repositories=Belirli depolar
teams.specific_repositories_helper=Üyeler, yalnızca takıma açıkça eklenen depolara erişebilir. Bunu seçmek, <i>Tüm depolarla</i> zaten eklenmiş olan depoları otomatik olarak <strong>kaldırmaz</strong>.
teams.all_repositories=Tüm depolar teams.all_repositories=Tüm depolar
teams.all_repositories_helper=Takımın tüm depolara erişimi vardır. Bunu seçmek, <strong>mevcut tüm depoları takıma ekleyecektir</strong>.
teams.all_repositories_read_permission_desc=Bu takım <strong>tüm depolara Okuma</strong> erişimi sağlar: üyeler depoları görüntüleyebilir ve kopyalayabilir.
teams.all_repositories_write_permission_desc=Bu takım <strong>tüm depolara Yazma</strong> erişimi sağlar: üyeler depolardan okuyabilir ve depolara itebilir.
teams.all_repositories_admin_permission_desc=Bu ekip <strong>tüm depolara Yönetici</strong> erişimi sağlar: üyeler depolardan okuyabilir, itebilir ve katkıcıları ekleyebilir.
[admin] [admin]
dashboard=Pano dashboard=Pano
@ -1560,6 +1668,7 @@ users=Kullanıcı Hesapları
organizations=Organizasyonlar organizations=Organizasyonlar
repositories=Depolar repositories=Depolar
hooks=Varsayılan Web İstemcileri hooks=Varsayılan Web İstemcileri
authentication=Yetkilendirme Kaynakları
config=Yapılandırma config=Yapılandırma
notices=Sistem Bildirimler notices=Sistem Bildirimler
monitor=İzleme monitor=İzleme
@ -1586,7 +1695,10 @@ dashboard.delete_generated_repository_avatars=Oluşturulan depo resimlerini sil
dashboard.delete_generated_repository_avatars_success=Oluşturulan depo resimleri silindi. dashboard.delete_generated_repository_avatars_success=Oluşturulan depo resimleri silindi.
dashboard.git_gc_repos=Depolardaki çöpleri topla dashboard.git_gc_repos=Depolardaki çöpleri topla
dashboard.git_gc_repos_success=Tüm depolardaki çöp toplama işlemi bitti. dashboard.git_gc_repos_success=Tüm depolardaki çöp toplama işlemi bitti.
dashboard.resync_all_sshkeys=Gitea SSH anahtarları ile '.ssh/authorized_keys' dosyasını güncelleyin. (Dahili SSH sunucusu için gerekli değildir.)
dashboard.resync_all_sshkeys_success=Gitea tarafından kontrol edilen açık SSH anahtarları güncellendi. dashboard.resync_all_sshkeys_success=Gitea tarafından kontrol edilen açık SSH anahtarları güncellendi.
dashboard.resync_all_hooks=Tüm depoların alma öncesi, güncelleme ve alma sonrası kancalarını yeniden senkronize edin.
dashboard.resync_all_hooks_success=Tüm depoların alım öncesi, güncelleme ve alım sonrası kancaları yeniden senkronize edildi.
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
@ -1637,6 +1749,7 @@ users.new_success='%s' kullanıcı hesabı oluşturuldu.
users.edit=Düzenle users.edit=Düzenle
users.auth_source=Yetkilendirme Kaynağı users.auth_source=Yetkilendirme Kaynağı
users.local=Yerel users.local=Yerel
users.auth_login_name=Oturum Açma Adı Doğrulaması
users.password_helper=Şifreyi değiştirmemek için boş bırakın. users.password_helper=Şifreyi değiştirmemek için boş bırakın.
users.update_profile_success=Kullanıcı hesabı güncellendi. users.update_profile_success=Kullanıcı hesabı güncellendi.
users.edit_account=Kullanıcı Hesabını Düzenle users.edit_account=Kullanıcı Hesabını Düzenle
@ -1646,6 +1759,7 @@ users.is_activated=Kullanıcı Hesabı Etkinleştirildi
users.prohibit_login=Oturum Açmayı Devre Dışı Bırak users.prohibit_login=Oturum Açmayı Devre Dışı Bırak
users.is_admin=Yöneticidir users.is_admin=Yöneticidir
users.allow_git_hook=Git İstemcileri Oluşturabilir users.allow_git_hook=Git İstemcileri Oluşturabilir
users.allow_import_local=Yerel Depoları Alabilir
users.allow_create_organization=Organizasyon Oluşturabilir users.allow_create_organization=Organizasyon Oluşturabilir
users.update_profile=Kullanıcı Hesabını Güncelle users.update_profile=Kullanıcı Hesabını Güncelle
users.delete_account=Kullanıcı Hesabını Sil users.delete_account=Kullanıcı Hesabını Sil
@ -1669,6 +1783,7 @@ repos.forks=Çatallar
repos.issues=Konular repos.issues=Konular
repos.size=Boyut repos.size=Boyut
hooks.desc=Web İstemcileri, belirli Gitea olayları tetiklendiğinde otomatik olarak HTTP POST isteklerini sunucuya yapar. Burada tanımlanan Web İstemcileri varsayılandır ve tüm yeni depolara kopyalanır. <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/webhooks/">web istemcileri kılavuzunda</a> daha fazla bilgi edinin.
hooks.add_webhook=Varsayılan Web İstemcisi Ekle hooks.add_webhook=Varsayılan Web İstemcisi Ekle
hooks.update_webhook=Varsayılan Web İstemcisini Güncelle hooks.update_webhook=Varsayılan Web İstemcisini Güncelle
@ -1690,11 +1805,13 @@ auths.bind_password=Bağlama Parolası
auths.bind_password_helper=Uyarı: Bu parola düz metin olarak saklanır. Mümkünse salt okunur bir hesap kullanın. auths.bind_password_helper=Uyarı: Bu parola düz metin olarak saklanır. Mümkünse salt okunur bir hesap kullanın.
auths.user_base=Kullanıcı Arama Tabanı auths.user_base=Kullanıcı Arama Tabanı
auths.user_dn=Kullanıcı DN'i auths.user_dn=Kullanıcı DN'i
auths.attribute_username=Kullanıcı Adı Özelliği
auths.attribute_username_placeholder=Gitea'da girilen kullanıcı adını kullanmak için boş bırakın. auths.attribute_username_placeholder=Gitea'da girilen kullanıcı adını kullanmak için boş bırakın.
auths.attribute_name=Ad Özelliği auths.attribute_name=Ad Özelliği
auths.attribute_surname=Soyad Özelliği auths.attribute_surname=Soyad Özelliği
auths.attribute_mail=E-posta Özelliği auths.attribute_mail=E-posta Özelliği
auths.attribute_ssh_public_key=ık SSH Anahtarı Özelliği auths.attribute_ssh_public_key=ık SSH Anahtarı Özelliği
auths.attributes_in_bind=Bağlı DN tabanındaki özellikleri çek
auths.use_paged_search=Sayfalı Aramayı Kullan auths.use_paged_search=Sayfalı Aramayı Kullan
auths.search_page_size=Sayfa Boyutu auths.search_page_size=Sayfa Boyutu
auths.filter=Kullanıcı Filtresi auths.filter=Kullanıcı Filtresi
@ -1710,6 +1827,9 @@ auths.skip_tls_verify=TLS Doğrulamasını Atla
auths.pam_service_name=PAM Servis Adı auths.pam_service_name=PAM Servis Adı
auths.oauth2_provider=OAuth2 Sağlayıcısı auths.oauth2_provider=OAuth2 Sağlayıcısı
auths.oauth2_clientID=İstemci Kimliği (Anahtar) auths.oauth2_clientID=İstemci Kimliği (Anahtar)
auths.oauth2_clientSecret=İstemci Gizliliği
auths.openIdConnectAutoDiscoveryURL=OpenID Connect Otomatik Keşif URLsi
auths.oauth2_use_custom_url=Varsayılan URL'ler Yerine Özel URL'ler Kullanın
auths.oauth2_tokenURL=Jeton URL auths.oauth2_tokenURL=Jeton URL
auths.oauth2_authURL=Yetkilendirme URL'si auths.oauth2_authURL=Yetkilendirme URL'si
auths.oauth2_profileURL=Profil URLsi auths.oauth2_profileURL=Profil URLsi
@ -1720,16 +1840,22 @@ auths.sspi_auto_create_users_helper=SSPI kimlik doğrulama yönteminin ilk kez o
auths.sspi_auto_activate_users=Kullanıcıları otomatik olarak etkinleştir auths.sspi_auto_activate_users=Kullanıcıları otomatik olarak etkinleştir
auths.sspi_auto_activate_users_helper=SSPI kimlik doğrulama yönteminin yeni kullanıcıları otomatik olarak etkinleştirmesine izin ver auths.sspi_auto_activate_users_helper=SSPI kimlik doğrulama yönteminin yeni kullanıcıları otomatik olarak etkinleştirmesine izin ver
auths.sspi_strip_domain_names=Alan adlarını kullanıcı adlarından kaldır auths.sspi_strip_domain_names=Alan adlarını kullanıcı adlarından kaldır
auths.sspi_strip_domain_names_helper=İşaretlenirse, etki alanı adları oturum açma adlarından kaldırılacaktır (örn. "ETKİALANI\kullanıcı" ve " kullanıcı@örnek.org "her ikisi de sadece "kullanıcı" olacak).
auths.sspi_separator_replacement=\, / ve @ yerine kullanılacak ayırıcı auths.sspi_separator_replacement=\, / ve @ yerine kullanılacak ayırıcı
auths.sspi_separator_replacement_helper=Alt seviye oturum açma adlarının (örneğin, "ETKİALANI\kullanıcı" içindeki \) ve kullanıcı asıl adlarının (örneğin, "kullanıcı@örnek.org" daki @) ayırıcılarını değiştirmek için kullanılacak karakter.
auths.sspi_default_language=Varsayılan kullanıcı dili auths.sspi_default_language=Varsayılan kullanıcı dili
auths.sspi_default_language_helper=SSPI kimlik doğrulama yöntemi tarafından otomatik olarak oluşturulan kullanıcılar için varsayılan dil. Dili otomatik olarak algılamayı tercih ederseniz boş bırakın.
auths.tips=İpuçları auths.tips=İpuçları
auths.tips.oauth2.general=OAuth2 Kimlik Doğrulama auths.tips.oauth2.general=OAuth2 Kimlik Doğrulama
auths.tips.oauth2.general.tip=Yeni bir OAuth2 kimlik doğrulaması kaydederken, geri arama/yönlendirme URL'si şöyle olmalıdır: <host>/kullanıcı/oauth2/<Authentication Name>/callback
auths.tip.oauth2_provider=OAuth2 Sağlayıcısı auths.tip.oauth2_provider=OAuth2 Sağlayıcısı
auths.tip.bitbucket=https://bitbucket.org/account/user/<kullanıcı adınız>/oauth-consumers/new adında yeni bir OAuth tüketicisi kaydedin ve 'Hesap' - 'Oku' iznini ekleyin auths.tip.bitbucket=https://bitbucket.org/account/user/<kullanıcı adınız>/oauth-consumers/new adında yeni bir OAuth tüketicisi kaydedin ve 'Hesap' - 'Oku' iznini ekleyin
auths.tip.dropbox=https://www.dropbox.com/developers/apps adresinde yeni bir uygulama oluştur auths.tip.dropbox=https://www.dropbox.com/developers/apps adresinde yeni bir uygulama oluştur
auths.tip.facebook=https://developers.facebook.com/apps adresinde yeni bir uygulama kaydedin ve "Facebook Giriş" ürününü ekleyin auths.tip.facebook=https://developers.facebook.com/apps adresinde yeni bir uygulama kaydedin ve "Facebook Giriş" ürününü ekleyin
auths.tip.github=https://github.com/settings/applications/new adresinde yeni bir OAuth uygulaması kaydedin auths.tip.github=https://github.com/settings/applications/new adresinde yeni bir OAuth uygulaması kaydedin
auths.tip.gitlab=https://gitlab.com/profile/applications adresinde yeni bir uygulama kaydedin auths.tip.gitlab=https://gitlab.com/profile/applications adresinde yeni bir uygulama kaydedin
auths.tip.google_plus=OAuth2 istemci kimlik bilgilerini https://console.developers.google.com/ adresindeki Google API konsolundan edinin
auths.tip.openid_connect=Bitiş noktalarını belirlemek için OpenID Connect Discovery URL'sini kullanın (<server>/.well-known/openid-configuration)
auths.tip.twitter=https://dev.twitter.com/apps adresine gidin, bir uygulama oluşturun ve “Bu uygulamanın Twitter ile oturum açmak için kullanılmasına izin ver” seçeneğinin etkin olduğundan emin olun auths.tip.twitter=https://dev.twitter.com/apps adresine gidin, bir uygulama oluşturun ve “Bu uygulamanın Twitter ile oturum açmak için kullanılmasına izin ver” seçeneğinin etkin olduğundan emin olun
auths.tip.discord=https://discordapp.com/developers/applications/me adresinde yeni bir uygulama kaydedin auths.tip.discord=https://discordapp.com/developers/applications/me adresinde yeni bir uygulama kaydedin
auths.tip.gitea=Yeni bir OAuth2 uygulaması kaydedin. Rehber https://docs.gitea.io/en-us/oauth2-provider/ adresinde bulunabilir auths.tip.gitea=Yeni bir OAuth2 uygulaması kaydedin. Rehber https://docs.gitea.io/en-us/oauth2-provider/ adresinde bulunabilir
@ -1749,7 +1875,10 @@ auths.login_source_of_type_exist=Bu tür bir kimlik doğrulama kaynağı zaten v
config.server_config=Sunucu Yapılandırması config.server_config=Sunucu Yapılandırması
config.app_name=Site Başlığı config.app_name=Site Başlığı
config.app_ver=Gitea Sürümü config.app_ver=Gitea Sürümü
config.app_url=Gitea Taban URL'si
config.custom_conf=Yapılandırma Dosyası Yolu config.custom_conf=Yapılandırma Dosyası Yolu
config.custom_file_root_path=Özel Dosya Kök Yolu
config.domain=SSH Sunucusu Etki Alanı
config.offline_mode=Yerel Kip config.offline_mode=Yerel Kip
config.disable_router_log=Yönlendirici Log'larını Devre Dışı Bırak config.disable_router_log=Yönlendirici Log'larını Devre Dışı Bırak
config.run_user=Şu Kullanıcı Olarak Çalıştır config.run_user=Şu Kullanıcı Olarak Çalıştır
@ -1777,6 +1906,7 @@ config.ssh_minimum_key_sizes=Minimum Anahtar Uzunlukları
config.lfs_config=LFS Yapılandırması config.lfs_config=LFS Yapılandırması
config.lfs_enabled=Etkin config.lfs_enabled=Etkin
config.lfs_content_path=LFS İçerik Yolu config.lfs_content_path=LFS İçerik Yolu
config.lfs_http_auth_expiry=LFS HTTP Yetkilendirme Süresi
config.db_config=Veritabanı Yapılandırması config.db_config=Veritabanı Yapılandırması
config.db_type=Türü config.db_type=Türü
@ -1790,13 +1920,21 @@ config.service_config=Servis Yapılandırması
config.register_email_confirm=Kayıt Olmak İçin E-posta Onayı Gereksin config.register_email_confirm=Kayıt Olmak İçin E-posta Onayı Gereksin
config.disable_register=Kullanıcı Kaydını Devre Dışı Bırak config.disable_register=Kullanıcı Kaydını Devre Dışı Bırak
config.allow_only_external_registration=Sadece Dış Hizmetler Aracılığıyla Kullanıcı Kaydına İzin Ver config.allow_only_external_registration=Sadece Dış Hizmetler Aracılığıyla Kullanıcı Kaydına İzin Ver
config.enable_openid_signup=OpenID Kendinden Kaydı'nı Etkinleştir
config.enable_openid_signin=OpenID Oturum Açmayı Etkinleştiriniz
config.show_registration_button=Kaydolma Tuşunu Göster config.show_registration_button=Kaydolma Tuşunu Göster
config.require_sign_in_view=Sayfaları Görüntülemek için Giriş Yapmaya Zorla config.require_sign_in_view=Sayfaları Görüntülemek için Giriş Yapmaya Zorla
config.mail_notify=E-Posta Bildirimlerini Etkinleştir config.mail_notify=E-Posta Bildirimlerini Etkinleştir
config.disable_key_size_check=Minimum Anahtar Uzunluğu Kontrolünü Devre Dışı Bırak config.disable_key_size_check=Minimum Anahtar Uzunluğu Kontrolünü Devre Dışı Bırak
config.enable_captcha=CAPTCHA'yı Etkinleştir config.enable_captcha=CAPTCHA'yı Etkinleştir
config.active_code_lives=Kod Yaşamlarını Aktifleştir config.active_code_lives=Kod Yaşamlarını Aktifleştir
config.reset_password_code_lives=Hesap Kodunun Sona Erme Zamanını Kurtar
config.default_keep_email_private=E-posta Adreslerini Varsayılan Olarak Gizle config.default_keep_email_private=E-posta Adreslerini Varsayılan Olarak Gizle
config.default_allow_create_organization=Varsayılan Olarak Kuruluşların Oluşturulmasına İzin Ver
config.enable_timetracking=Zaman İzlemeyi Etkinleştir
config.default_enable_timetracking=Varsayılan Olarak Zaman İzlemeyi Etkinleştir
config.default_allow_only_contributors_to_track_time=Yalnızca Katkıda Bulunanlar Zaman İzlesin
config.no_reply_address=Gizlenmiş E-Postalar için Alan Adı
config.default_visibility_organization=Yeni organizasyonlar için varsayılan görünürlük config.default_visibility_organization=Yeni organizasyonlar için varsayılan görünürlük
config.default_enable_dependencies=Konu Bağımlılıklarını Varsayılan Olarak Etkinleştir config.default_enable_dependencies=Konu Bağımlılıklarını Varsayılan Olarak Etkinleştir
@ -1825,6 +1963,7 @@ config.cache_config=Önbellek Yapılandırması
config.cache_adapter=Önbellek Uyarlayıcısı config.cache_adapter=Önbellek Uyarlayıcısı
config.cache_interval=Önbellek Aralığı config.cache_interval=Önbellek Aralığı
config.cache_conn=Önbellek Bağlantısı config.cache_conn=Önbellek Bağlantısı
config.cache_item_ttl=TTL Önbellek Öğesi
config.session_config=Oturum Yapılandırması config.session_config=Oturum Yapılandırması
config.session_provider=Oturum Sağlayıcı config.session_provider=Oturum Sağlayıcı
@ -1839,6 +1978,7 @@ config.cookie_life_time=Çerez Yaşam Zamanı
config.picture_config=Resim ve Avatar Yapılandırması config.picture_config=Resim ve Avatar Yapılandırması
config.picture_service=Resim Servisi config.picture_service=Resim Servisi
config.disable_gravatar=Gravatar Hizmet Dışı config.disable_gravatar=Gravatar Hizmet Dışı
config.enable_federated_avatar=Birleştirilmiş Avatarları Etkinleştir
config.git_config=Git Yapılandırması config.git_config=Git Yapılandırması
config.git_disable_diff_highlight=Değişiklik Sözdizimi Vurgusunu Devre Dışı Bırak config.git_disable_diff_highlight=Değişiklik Sözdizimi Vurgusunu Devre Dışı Bırak
@ -1904,6 +2044,7 @@ create_pull_request=`<a href="%s/pulls/%s">%s#%[2]s</a> değişiklik isteğini o
close_pull_request=`<a href="%s/pulls/%s">%s#%[2]s</a> değişiklik isteğini kapattı` close_pull_request=`<a href="%s/pulls/%s">%s#%[2]s</a> değişiklik isteğini kapattı`
reopen_pull_request=`<a href="%s/pulls/%s">%s#%[2]s</a> değişiklik isteğini tekrar açtı` reopen_pull_request=`<a href="%s/pulls/%s">%s#%[2]s</a> değişiklik isteğini tekrar açtı`
comment_issue=`<a href="%s/issues/%s">%s#%[2]s</a> konusuna yorum yazdı` comment_issue=`<a href="%s/issues/%s">%s#%[2]s</a> konusuna yorum yazdı`
comment_pull=`<a href="%s/pulls/%s">%s#%[2]s</a> değişiklik isteği üzerinde yorum yapıldı`
merge_pull_request=`<a href="%s/pulls/%s">%s#%[2]s</a> değişim isteğini birleştirdi` merge_pull_request=`<a href="%s/pulls/%s">%s#%[2]s</a> değişim isteğini birleştirdi`
transfer_repo=depo <code>%s</code> <a href="%s">%s</a>'a aktarıldı transfer_repo=depo <code>%s</code> <a href="%s">%s</a>'a aktarıldı
push_tag=<a href="%[1]s">%[3]s</a> deposuna <a href="%s/src/tag/%s">%[2]s</a> etiketi itildi push_tag=<a href="%[1]s">%[3]s</a> deposuna <a href="%s/src/tag/%s">%[2]s</a> etiketi itildi

File diff suppressed because it is too large Load diff

View file

@ -664,10 +664,10 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Combo("", reqToken()). m.Combo("", reqToken()).
Patch(mustNotBeArchived, bind(api.EditIssueCommentOption{}), repo.EditIssueComment). Patch(mustNotBeArchived, bind(api.EditIssueCommentOption{}), repo.EditIssueComment).
Delete(repo.DeleteIssueComment) Delete(repo.DeleteIssueComment)
m.Combo("/reactions", reqToken()). m.Combo("/reactions").
Get(repo.GetIssueCommentReactions). Get(repo.GetIssueCommentReactions).
Post(bind(api.EditReactionOption{}), repo.PostIssueCommentReaction). Post(bind(api.EditReactionOption{}), reqToken(), repo.PostIssueCommentReaction).
Delete(bind(api.EditReactionOption{}), repo.DeleteIssueCommentReaction) Delete(bind(api.EditReactionOption{}), reqToken(), repo.DeleteIssueCommentReaction)
}) })
}) })
m.Group("/:index", func() { m.Group("/:index", func() {
@ -704,10 +704,10 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Put("/:user", reqToken(), repo.AddIssueSubscription) m.Put("/:user", reqToken(), repo.AddIssueSubscription)
m.Delete("/:user", reqToken(), repo.DelIssueSubscription) m.Delete("/:user", reqToken(), repo.DelIssueSubscription)
}) })
m.Combo("/reactions", reqToken()). m.Combo("/reactions").
Get(repo.GetIssueReactions). Get(repo.GetIssueReactions).
Post(bind(api.EditReactionOption{}), repo.PostIssueReaction). Post(bind(api.EditReactionOption{}), reqToken(), repo.PostIssueReaction).
Delete(bind(api.EditReactionOption{}), repo.DeleteIssueReaction) Delete(bind(api.EditReactionOption{}), reqToken(), repo.DeleteIssueReaction)
}) })
}, mustEnableIssuesOrPulls) }, mustEnableIssuesOrPulls)
m.Group("/labels", func() { m.Group("/labels", func() {

View file

@ -69,7 +69,6 @@ func TestAPI_RenderGFM(t *testing.T) {
- Bezier widget (by @r-lyeh) https://github.com/ocornut/imgui/issues/786`, - Bezier widget (by @r-lyeh) https://github.com/ocornut/imgui/issues/786`,
// rendered // rendered
`<p>Wiki! Enjoy :)</p> `<p>Wiki! Enjoy :)</p>
<ul> <ul>
<li><a href="` + AppSubURL + `wiki/Links" rel="nofollow">Links, Language bindings, Engine bindings</a></li> <li><a href="` + AppSubURL + `wiki/Links" rel="nofollow">Links, Language bindings, Engine bindings</a></li>
<li><a href="` + AppSubURL + `wiki/Tips" rel="nofollow">Tips</a></li> <li><a href="` + AppSubURL + `wiki/Tips" rel="nofollow">Tips</a></li>
@ -88,13 +87,9 @@ Here are some links to the most important topics. You can find the full list of
`, `,
// rendered // rendered
`<h2 id="user-content-what-is-wine-staging">What is Wine Staging?</h2> `<h2 id="user-content-what-is-wine-staging">What is Wine Staging?</h2>
<p><strong>Wine Staging</strong> on website <a href="http://wine-staging.com" rel="nofollow">wine-staging.com</a>.</p> <p><strong>Wine Staging</strong> on website <a href="http://wine-staging.com" rel="nofollow">wine-staging.com</a>.</p>
<h2 id="user-content-quick-links">Quick Links</h2> <h2 id="user-content-quick-links">Quick Links</h2>
<p>Here are some links to the most important topics. You can find the full list of pages at the sidebar.</p> <p>Here are some links to the most important topics. You can find the full list of pages at the sidebar.</p>
<p><a href="` + AppSubURL + `wiki/Configuration" rel="nofollow">Configuration</a> <p><a href="` + AppSubURL + `wiki/Configuration" rel="nofollow">Configuration</a>
<a href="` + AppSubURL + `wiki/raw/images/icon-bug.png" rel="nofollow"><img src="` + AppSubURL + `wiki/raw/images/icon-bug.png" title="icon-bug.png" alt="images/icon-bug.png"/></a></p> <a href="` + AppSubURL + `wiki/raw/images/icon-bug.png" rel="nofollow"><img src="` + AppSubURL + `wiki/raw/images/icon-bug.png" title="icon-bug.png" alt="images/icon-bug.png"/></a></p>
`, `,

View file

@ -524,8 +524,8 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) {
} }
} }
if err = models.UpdateIssue(issue); err != nil { if err = models.UpdateIssueByAPI(issue); err != nil {
ctx.Error(http.StatusInternalServerError, "UpdateIssue", err) ctx.Error(http.StatusInternalServerError, "UpdateIssueByAPI", err)
return return
} }
if form.State != nil { if form.State != nil {
@ -542,7 +542,11 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) {
// Refetch from database to assign some automatic values // Refetch from database to assign some automatic values
issue, err = models.GetIssueByID(issue.ID) issue, err = models.GetIssueByID(issue.ID)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "GetIssueByID", err) ctx.InternalServerError(err)
return
}
if err = issue.LoadMilestone(); err != nil {
ctx.InternalServerError(err)
return return
} }
ctx.JSON(http.StatusCreated, issue.APIFormat()) ctx.JSON(http.StatusCreated, issue.APIFormat())

View file

@ -41,7 +41,7 @@ func GetIssueCommentReactions(ctx *context.APIContext) {
// required: true // required: true
// responses: // responses:
// "200": // "200":
// "$ref": "#/responses/ReactionResponseList" // "$ref": "#/responses/ReactionList"
// "403": // "403":
// "$ref": "#/responses/forbidden" // "$ref": "#/responses/forbidden"
@ -55,7 +55,7 @@ func GetIssueCommentReactions(ctx *context.APIContext) {
return return
} }
if !ctx.Repo.CanRead(models.UnitTypeIssues) && !ctx.User.IsAdmin { if !ctx.Repo.CanRead(models.UnitTypeIssues) {
ctx.Error(http.StatusForbidden, "GetIssueCommentReactions", errors.New("no permission to get reactions")) ctx.Error(http.StatusForbidden, "GetIssueCommentReactions", errors.New("no permission to get reactions"))
return return
} }
@ -71,9 +71,9 @@ func GetIssueCommentReactions(ctx *context.APIContext) {
return return
} }
var result []api.ReactionResponse var result []api.Reaction
for _, r := range reactions { for _, r := range reactions {
result = append(result, api.ReactionResponse{ result = append(result, api.Reaction{
User: r.User.APIFormat(), User: r.User.APIFormat(),
Reaction: r.Type, Reaction: r.Type,
Created: r.CreatedUnix.AsTime(), Created: r.CreatedUnix.AsTime(),
@ -114,8 +114,10 @@ func PostIssueCommentReaction(ctx *context.APIContext, form api.EditReactionOpti
// schema: // schema:
// "$ref": "#/definitions/EditReactionOption" // "$ref": "#/definitions/EditReactionOption"
// responses: // responses:
// "200":
// "$ref": "#/responses/Reaction"
// "201": // "201":
// "$ref": "#/responses/ReactionResponse" // "$ref": "#/responses/Reaction"
// "403": // "403":
// "$ref": "#/responses/forbidden" // "$ref": "#/responses/forbidden"
@ -177,7 +179,7 @@ func changeIssueCommentReaction(ctx *context.APIContext, form api.EditReactionOp
ctx.Error(http.StatusInternalServerError, "comment.LoadIssue() failed", err) ctx.Error(http.StatusInternalServerError, "comment.LoadIssue() failed", err)
} }
if comment.Issue.IsLocked && !ctx.Repo.CanWrite(models.UnitTypeIssues) && !ctx.User.IsAdmin { if comment.Issue.IsLocked && !ctx.Repo.CanWrite(models.UnitTypeIssues) {
ctx.Error(http.StatusForbidden, "ChangeIssueCommentReaction", errors.New("no permission to change reaction")) ctx.Error(http.StatusForbidden, "ChangeIssueCommentReaction", errors.New("no permission to change reaction"))
return return
} }
@ -188,19 +190,20 @@ func changeIssueCommentReaction(ctx *context.APIContext, form api.EditReactionOp
if err != nil { if err != nil {
if models.IsErrForbiddenIssueReaction(err) { if models.IsErrForbiddenIssueReaction(err) {
ctx.Error(http.StatusForbidden, err.Error(), err) ctx.Error(http.StatusForbidden, err.Error(), err)
} else if models.IsErrReactionAlreadyExist(err) {
ctx.JSON(http.StatusOK, api.Reaction{
User: ctx.User.APIFormat(),
Reaction: reaction.Type,
Created: reaction.CreatedUnix.AsTime(),
})
} else { } else {
ctx.Error(http.StatusInternalServerError, "CreateCommentReaction", err) ctx.Error(http.StatusInternalServerError, "CreateCommentReaction", err)
} }
return return
} }
_, err = reaction.LoadUser()
if err != nil {
ctx.Error(http.StatusInternalServerError, "Reaction.LoadUser()", err)
return
}
ctx.JSON(http.StatusCreated, api.ReactionResponse{ ctx.JSON(http.StatusCreated, api.Reaction{
User: reaction.User.APIFormat(), User: ctx.User.APIFormat(),
Reaction: reaction.Type, Reaction: reaction.Type,
Created: reaction.CreatedUnix.AsTime(), Created: reaction.CreatedUnix.AsTime(),
}) })
@ -244,7 +247,7 @@ func GetIssueReactions(ctx *context.APIContext) {
// required: true // required: true
// responses: // responses:
// "200": // "200":
// "$ref": "#/responses/ReactionResponseList" // "$ref": "#/responses/ReactionList"
// "403": // "403":
// "$ref": "#/responses/forbidden" // "$ref": "#/responses/forbidden"
@ -258,7 +261,7 @@ func GetIssueReactions(ctx *context.APIContext) {
return return
} }
if !ctx.Repo.CanRead(models.UnitTypeIssues) && !ctx.User.IsAdmin { if !ctx.Repo.CanRead(models.UnitTypeIssues) {
ctx.Error(http.StatusForbidden, "GetIssueReactions", errors.New("no permission to get reactions")) ctx.Error(http.StatusForbidden, "GetIssueReactions", errors.New("no permission to get reactions"))
return return
} }
@ -274,9 +277,9 @@ func GetIssueReactions(ctx *context.APIContext) {
return return
} }
var result []api.ReactionResponse var result []api.Reaction
for _, r := range reactions { for _, r := range reactions {
result = append(result, api.ReactionResponse{ result = append(result, api.Reaction{
User: r.User.APIFormat(), User: r.User.APIFormat(),
Reaction: r.Type, Reaction: r.Type,
Created: r.CreatedUnix.AsTime(), Created: r.CreatedUnix.AsTime(),
@ -317,8 +320,10 @@ func PostIssueReaction(ctx *context.APIContext, form api.EditReactionOption) {
// schema: // schema:
// "$ref": "#/definitions/EditReactionOption" // "$ref": "#/definitions/EditReactionOption"
// responses: // responses:
// "200":
// "$ref": "#/responses/Reaction"
// "201": // "201":
// "$ref": "#/responses/ReactionResponse" // "$ref": "#/responses/Reaction"
// "403": // "403":
// "$ref": "#/responses/forbidden" // "$ref": "#/responses/forbidden"
@ -375,7 +380,7 @@ func changeIssueReaction(ctx *context.APIContext, form api.EditReactionOption, i
return return
} }
if issue.IsLocked && !ctx.Repo.CanWrite(models.UnitTypeIssues) && !ctx.User.IsAdmin { if issue.IsLocked && !ctx.Repo.CanWrite(models.UnitTypeIssues) {
ctx.Error(http.StatusForbidden, "ChangeIssueCommentReaction", errors.New("no permission to change reaction")) ctx.Error(http.StatusForbidden, "ChangeIssueCommentReaction", errors.New("no permission to change reaction"))
return return
} }
@ -386,19 +391,20 @@ func changeIssueReaction(ctx *context.APIContext, form api.EditReactionOption, i
if err != nil { if err != nil {
if models.IsErrForbiddenIssueReaction(err) { if models.IsErrForbiddenIssueReaction(err) {
ctx.Error(http.StatusForbidden, err.Error(), err) ctx.Error(http.StatusForbidden, err.Error(), err)
} else if models.IsErrReactionAlreadyExist(err) {
ctx.JSON(http.StatusOK, api.Reaction{
User: ctx.User.APIFormat(),
Reaction: reaction.Type,
Created: reaction.CreatedUnix.AsTime(),
})
} else { } else {
ctx.Error(http.StatusInternalServerError, "CreateCommentReaction", err) ctx.Error(http.StatusInternalServerError, "CreateCommentReaction", err)
} }
return return
} }
_, err = reaction.LoadUser()
if err != nil {
ctx.Error(http.StatusInternalServerError, "Reaction.LoadUser()", err)
return
}
ctx.JSON(http.StatusCreated, api.ReactionResponse{ ctx.JSON(http.StatusCreated, api.Reaction{
User: reaction.User.APIFormat(), User: ctx.User.APIFormat(),
Reaction: reaction.Type, Reaction: reaction.Type,
Created: reaction.CreatedUnix.AsTime(), Created: reaction.CreatedUnix.AsTime(),
}) })

View file

@ -450,8 +450,8 @@ func EditPullRequest(ctx *context.APIContext, form api.EditPullRequestOption) {
} }
} }
if err = models.UpdateIssue(issue); err != nil { if err = models.UpdateIssueByAPI(issue); err != nil {
ctx.Error(http.StatusInternalServerError, "UpdateIssue", err) ctx.Error(http.StatusInternalServerError, "UpdateIssueByAPI", err)
return return
} }
if form.State != nil { if form.State != nil {

View file

@ -99,23 +99,16 @@ type swaggerResponseStopWatchList struct {
Body []api.StopWatch `json:"body"` Body []api.StopWatch `json:"body"`
} }
// EditReactionOption // Reaction
// swagger:response EditReactionOption // swagger:response Reaction
type swaggerEditReactionOption struct { type swaggerReaction struct {
// in:body // in:body
Body api.EditReactionOption `json:"body"` Body api.Reaction `json:"body"`
} }
// ReactionResponse // ReactionList
// swagger:response ReactionResponse // swagger:response ReactionList
type swaggerReactionResponse struct { type swaggerReactionList struct {
// in:body // in:body
Body api.ReactionResponse `json:"body"` Body []api.Reaction `json:"body"`
}
// ReactionResponseList
// swagger:response ReactionResponseList
type swaggerReactionResponseList struct {
// in:body
Body []api.ReactionResponse `json:"body"`
} }

View file

@ -123,4 +123,7 @@ type swaggerParameterBodies struct {
// in:body // in:body
RepoTopicOptions api.RepoTopicOptions RepoTopicOptions api.RepoTopicOptions
// in:body
EditReactionOption api.EditReactionOption
} }

View file

@ -113,6 +113,13 @@ func HookPreReceive(ctx *macaron.Context, opts private.HookOptions) {
}) })
return return
} }
if protectBranch.MergeBlockedByRejectedReview(pr) {
log.Warn("Forbidden: User %d cannot push to protected branch: %s in %-v and pr #%d has requested changes", opts.UserID, branchName, repo, pr.Index)
ctx.JSON(http.StatusForbidden, map[string]interface{}{
"err": fmt.Sprintf("protected branch %s can not be pushed to and pr #%d has requested changes", branchName, opts.ProtectedBranchID),
})
return
}
} else if !canPush { } else if !canPush {
log.Warn("Forbidden: User %d cannot push to protected branch: %s in %-v", opts.UserID, branchName, repo) log.Warn("Forbidden: User %d cannot push to protected branch: %s in %-v", opts.UserID, branchName, repo)
ctx.JSON(http.StatusForbidden, map[string]interface{}{ ctx.JSON(http.StatusForbidden, map[string]interface{}{

View file

@ -6,6 +6,8 @@ package repo
import ( import (
"fmt" "fmt"
"net/http"
"os"
"strings" "strings"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
@ -85,3 +87,57 @@ func DeleteAttachment(ctx *context.Context) {
"uuid": attach.UUID, "uuid": attach.UUID,
}) })
} }
// GetAttachment serve attachements
func GetAttachment(ctx *context.Context) {
attach, err := models.GetAttachmentByUUID(ctx.Params(":uuid"))
if err != nil {
if models.IsErrAttachmentNotExist(err) {
ctx.Error(404)
} else {
ctx.ServerError("GetAttachmentByUUID", err)
}
return
}
repository, unitType, err := attach.LinkedRepository()
if err != nil {
ctx.ServerError("LinkedRepository", err)
return
}
if repository == nil { //If not linked
if !(ctx.IsSigned && attach.UploaderID == ctx.User.ID) { //We block if not the uploader
ctx.Error(http.StatusNotFound)
return
}
} else { //If we have the repository we check access
perm, err := models.GetUserRepoPermission(repository, ctx.User)
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err.Error())
return
}
if !perm.CanRead(unitType) {
ctx.Error(http.StatusNotFound)
return
}
}
//If we have matched and access to release or issue
fr, err := os.Open(attach.LocalPath())
if err != nil {
ctx.ServerError("Open", err)
return
}
defer fr.Close()
if err := attach.IncreaseDownloadCount(); err != nil {
ctx.ServerError("Update", err)
return
}
if err = ServeData(ctx, attach.Name, fr); err != nil {
ctx.ServerError("ServeData", err)
return
}
}

View file

@ -23,7 +23,6 @@ import (
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/markup/markdown"
"code.gitea.io/gitea/modules/notification"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs" api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
@ -963,7 +962,8 @@ func ViewIssue(ctx *context.Context) {
} }
if pull.ProtectedBranch != nil { if pull.ProtectedBranch != nil {
cnt := pull.ProtectedBranch.GetGrantedApprovalsCount(pull) cnt := pull.ProtectedBranch.GetGrantedApprovalsCount(pull)
ctx.Data["IsBlockedByApprovals"] = pull.ProtectedBranch.RequiredApprovals > 0 && cnt < pull.ProtectedBranch.RequiredApprovals ctx.Data["IsBlockedByApprovals"] = !pull.ProtectedBranch.HasEnoughApprovals(pull)
ctx.Data["IsBlockedByRejection"] = pull.ProtectedBranch.MergeBlockedByRejectedReview(pull)
ctx.Data["GrantedApprovals"] = cnt ctx.Data["GrantedApprovals"] = cnt
} }
ctx.Data["IsPullBranchDeletable"] = canDelete && pull.HeadRepo != nil && git.IsBranchExist(pull.HeadRepo.RepoPath(), pull.HeadBranch) ctx.Data["IsPullBranchDeletable"] = canDelete && pull.HeadRepo != nil && git.IsBranchExist(pull.HeadRepo.RepoPath(), pull.HeadBranch)
@ -1177,13 +1177,11 @@ func UpdateIssueAssignee(ctx *context.Context) {
return return
} }
removed, comment, err := issue_service.ToggleAssignee(issue, ctx.User, assigneeID) _, _, err = issue_service.ToggleAssignee(issue, ctx.User, assigneeID)
if err != nil { if err != nil {
ctx.ServerError("ToggleAssignee", err) ctx.ServerError("ToggleAssignee", err)
return return
} }
notification.NotifyIssueChangeAssignee(ctx.User, issue, assignee, removed, comment)
} }
} }
ctx.JSON(200, map[string]interface{}{ ctx.JSON(200, map[string]interface{}{

View file

@ -244,6 +244,7 @@ func SettingsProtectedBranchPost(ctx *context.Context, f auth.ProtectBranchForm)
approvalsWhitelistTeams, _ = base.StringsToInt64s(strings.Split(f.ApprovalsWhitelistTeams, ",")) approvalsWhitelistTeams, _ = base.StringsToInt64s(strings.Split(f.ApprovalsWhitelistTeams, ","))
} }
} }
protectBranch.BlockOnRejectedReviews = f.BlockOnRejectedReviews
err = models.UpdateProtectBranch(ctx.Repo.Repository, protectBranch, models.WhitelistOptions{ err = models.UpdateProtectBranch(ctx.Repo.Repository, protectBranch, models.WhitelistOptions{
UserIDs: whitelistUsers, UserIDs: whitelistUsers,

View file

@ -8,7 +8,6 @@ import (
"bytes" "bytes"
"encoding/gob" "encoding/gob"
"net/http" "net/http"
"os"
"path" "path"
"text/template" "text/template"
"time" "time"
@ -482,34 +481,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("/following", user.Following) m.Get("/following", user.Following)
}) })
m.Get("/attachments/:uuid", func(ctx *context.Context) { m.Get("/attachments/:uuid", repo.GetAttachment)
attach, err := models.GetAttachmentByUUID(ctx.Params(":uuid"))
if err != nil {
if models.IsErrAttachmentNotExist(err) {
ctx.Error(404)
} else {
ctx.ServerError("GetAttachmentByUUID", err)
}
return
}
fr, err := os.Open(attach.LocalPath())
if err != nil {
ctx.ServerError("Open", err)
return
}
defer fr.Close()
if err := attach.IncreaseDownloadCount(); err != nil {
ctx.ServerError("Update", err)
return
}
if err = repo.ServeData(ctx, attach.Name, fr); err != nil {
ctx.ServerError("ServeData", err)
return
}
})
}, ignSignIn) }, ignSignIn)
m.Group("/attachments", func() { m.Group("/attachments", func() {

View file

@ -389,21 +389,23 @@ func Issues(ctx *context.Context) {
reposQuery := ctx.Query("repos") reposQuery := ctx.Query("repos")
var repoIDs []int64 var repoIDs []int64
if issueReposQueryPattern.MatchString(reposQuery) { if len(reposQuery) != 0 {
// remove "[" and "]" from string if issueReposQueryPattern.MatchString(reposQuery) {
reposQuery = reposQuery[1 : len(reposQuery)-1] // remove "[" and "]" from string
//for each ID (delimiter ",") add to int to repoIDs reposQuery = reposQuery[1 : len(reposQuery)-1]
for _, rID := range strings.Split(reposQuery, ",") { //for each ID (delimiter ",") add to int to repoIDs
// Ensure nonempty string entries for _, rID := range strings.Split(reposQuery, ",") {
if rID != "" && rID != "0" { // Ensure nonempty string entries
rIDint64, err := strconv.ParseInt(rID, 10, 64) if rID != "" && rID != "0" {
if err == nil { rIDint64, err := strconv.ParseInt(rID, 10, 64)
repoIDs = append(repoIDs, rIDint64) if err == nil {
repoIDs = append(repoIDs, rIDint64)
}
} }
} }
} else {
log.Error("issueReposQueryPattern not match with query")
} }
} else {
log.Error("issueReposQueryPattern not match with query")
} }
isShowClosed := ctx.Query("state") == "closed" isShowClosed := ctx.Query("state") == "closed"

View file

@ -26,10 +26,10 @@ func TestIssues(t *testing.T) {
Issues(ctx) Issues(ctx)
assert.EqualValues(t, http.StatusOK, ctx.Resp.Status()) assert.EqualValues(t, http.StatusOK, ctx.Resp.Status())
assert.EqualValues(t, map[int64]int64{1: 1}, ctx.Data["Counts"]) assert.EqualValues(t, map[int64]int64{1: 1, 2: 1}, ctx.Data["Counts"])
assert.EqualValues(t, true, ctx.Data["IsShowClosed"]) assert.EqualValues(t, true, ctx.Data["IsShowClosed"])
assert.Len(t, ctx.Data["Issues"], 1) assert.Len(t, ctx.Data["Issues"], 1)
assert.Len(t, ctx.Data["Repos"], 1) assert.Len(t, ctx.Data["Repos"], 2)
} }
func TestMilestones(t *testing.T) { func TestMilestones(t *testing.T) {

View file

@ -177,7 +177,6 @@ func composeIssueCommentMessages(ctx *mailCommentContext, tos []string, fromMent
commentType := models.CommentTypeComment commentType := models.CommentTypeComment
if ctx.Comment != nil { if ctx.Comment != nil {
prefix = "Re: "
commentType = ctx.Comment.Type commentType = ctx.Comment.Type
link = ctx.Issue.HTMLURL() + "#" + ctx.Comment.HashTag() link = ctx.Issue.HTMLURL() + "#" + ctx.Comment.HashTag()
} else { } else {
@ -189,13 +188,16 @@ func composeIssueCommentMessages(ctx *mailCommentContext, tos []string, fromMent
reviewType = ctx.Comment.Review.Type reviewType = ctx.Comment.Review.Type
} }
fallback = prefix + fallbackMailSubject(ctx.Issue)
// This is the body of the new issue or comment, not the mail body // This is the body of the new issue or comment, not the mail body
body := string(markup.RenderByType(markdown.MarkupName, []byte(ctx.Content), ctx.Issue.Repo.HTMLURL(), ctx.Issue.Repo.ComposeMetas())) body := string(markup.RenderByType(markdown.MarkupName, []byte(ctx.Content), ctx.Issue.Repo.HTMLURL(), ctx.Issue.Repo.ComposeMetas()))
actType, actName, tplName := actionToTemplate(ctx.Issue, ctx.ActionType, commentType, reviewType) actType, actName, tplName := actionToTemplate(ctx.Issue, ctx.ActionType, commentType, reviewType)
if actName != "new" {
prefix = "Re: "
}
fallback = prefix + fallbackMailSubject(ctx.Issue)
if ctx.Comment != nil && ctx.Comment.Review != nil { if ctx.Comment != nil && ctx.Comment.Review != nil {
reviewComments = make([]*models.Comment, 0, 10) reviewComments = make([]*models.Comment, 0, 10)
for _, lines := range ctx.Comment.Review.CodeComments { for _, lines := range ctx.Comment.Review.CodeComments {
@ -247,7 +249,7 @@ func composeIssueCommentMessages(ctx *mailCommentContext, tos []string, fromMent
msg.Info = fmt.Sprintf("Subject: %s, %s", subject, info) msg.Info = fmt.Sprintf("Subject: %s, %s", subject, info)
// Set Message-ID on first message so replies know what to reference // Set Message-ID on first message so replies know what to reference
if ctx.Comment == nil { if actName == "new" {
msg.SetHeader("Message-ID", "<"+ctx.Issue.ReplyReference()+">") msg.SetHeader("Message-ID", "<"+ctx.Issue.ReplyReference()+">")
} else { } else {
msg.SetHeader("In-Reply-To", "<"+ctx.Issue.ReplyReference()+">") msg.SetHeader("In-Reply-To", "<"+ctx.Issue.ReplyReference()+">")

View file

@ -410,7 +410,7 @@ func syncMirror(repoID string) {
theCommits.CompareURL = m.Repo.ComposeCompareURL(oldCommitID, newCommitID) theCommits.CompareURL = m.Repo.ComposeCompareURL(oldCommitID, newCommitID)
notification.NotifySyncPushCommits(m.Repo.MustOwner(), m.Repo, result.refName, oldCommitID, newCommitID, models.ListToPushCommits(commits)) notification.NotifySyncPushCommits(m.Repo.MustOwner(), m.Repo, result.refName, oldCommitID, newCommitID, theCommits)
} }
// Get latest commit date and update to current repository updated time // Get latest commit date and update to current repository updated time

View file

@ -1,7 +1,7 @@
<footer> <footer>
<div class="ui container"> <div class="ui container">
<div class="ui left"> <div class="ui left">
© Gitea {{if (or .ShowFooterVersion .PageIsAdmin)}}{{.i18n.Tr "version"}}: {{AppVer}}{{end}} {{if ShowFooterTemplateLoadTime}}{{.i18n.Tr "page"}}: <strong>{{LoadTimes .PageStartTime}}</strong> {{.i18n.Tr "template"}}: <strong>{{call .TmplLoadTimes}}</strong>{{end}} {{.i18n.Tr "powered_by" "Gitea"}} {{if (or .ShowFooterVersion .PageIsAdmin)}}{{.i18n.Tr "version"}}: {{AppVer}}{{end}} {{if ShowFooterTemplateLoadTime}}{{.i18n.Tr "page"}}: <strong>{{LoadTimes .PageStartTime}}</strong> {{.i18n.Tr "template"}}: <strong>{{call .TmplLoadTimes}}</strong>{{end}}
</div> </div>
<div class="ui right links"> <div class="ui right links">
{{if .ShowFooterBranding}} {{if .ShowFooterBranding}}
@ -19,6 +19,7 @@
<a href="{{StaticUrlPrefix}}/vendor/librejs.html" data-jslicense="1">JavaScript licenses</a> <a href="{{StaticUrlPrefix}}/vendor/librejs.html" data-jslicense="1">JavaScript licenses</a>
{{if .EnableSwagger}}<a href="{{AppSubUrl}}/api/swagger">API</a>{{end}} {{if .EnableSwagger}}<a href="{{AppSubUrl}}/api/swagger">API</a>{{end}}
<a target="_blank" rel="noopener noreferrer" href="https://gitea.io">{{.i18n.Tr "website"}}</a> <a target="_blank" rel="noopener noreferrer" href="https://gitea.io">{{.i18n.Tr "website"}}</a>
{{template "custom/extra_links_footer" .}}
{{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

View file

@ -1,17 +1,21 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<style>
.footer { font-size:small; color:#666;}
</style>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>{{.Subject}}</title> <title>{{.Subject}}</title>
</head> </head>
<body> <body>
<p>@{{.Doer.Name}} assigned you to the {{if .IsPull}}pull request{{else}}issue{{end}} <a href="{{.Link}}">#{{.Issue.Index}}</a> in repository {{.Repo}}.</p> <p>@{{.Doer.Name}} assigned you to the {{if .IsPull}}pull request{{else}}issue{{end}} <a href="{{.Link}}">#{{.Issue.Index}}</a> in repository {{.Repo}}.</p>
<p> <div class="footer">
--- <p>
<br> ---
<a href="{{.Link}}">View it on {{AppName}}</a>. <br>
</p> <a href="{{.Link}}">View it on {{AppName}}</a>.
</p>
</div>
</body> </body>
</html> </html>

View file

@ -3,41 +3,56 @@
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>{{.Subject}}</title> <title>{{.Subject}}</title>
{{if .ReviewComments}}
<style> <style>
.review { padding-left: 1em; margin: 1em 0; } .footer { font-size:small; color:#666;}
.review > pre { padding: 1em; border-left: 1px solid grey; } {{if .ReviewComments}}
.review { padding-left: 1em; margin: 1em 0; }
.review > pre { padding: 1em; border-left: 1px solid grey; }
{{end}}
</style> </style>
{{end}}
</head> </head>
<body> <body>
{{if .IsMention}}<p>@{{.Doer.Name}} mentioned you:</p>{{end}} {{if .IsMention}}<p><b>@{{.Doer.Name}}</b> mentioned you:</p>{{end}}
<p> <p>
{{if eq .ActionName "close"}}
Closed #{{.Issue.Index}}.
{{else if eq .ActionName "reopen"}}
Reopened #{{.Issue.Index}}.
{{else if eq .ActionName "merge"}}
Merged #{{.Issue.Index}} into {{.Issue.PullRequest.BaseBranch}}.
{{else if eq .ActionName "approve"}}
<b>@{{.Doer.Name}}</b> approved this pull request.
{{else if eq .ActionName "reject"}}
<b>@{{.Doer.Name}}</b> requested changes on this pull request.
{{else if eq .ActionName "review"}}
<b>@{{.Doer.Name}}</b> commented on this pull request.
{{end}}
{{- if eq .Body ""}} {{- if eq .Body ""}}
{{if eq .ActionName "new"}} {{if eq .ActionName "new"}}
Created #{{.Issue.Index}}. Created #{{.Issue.Index}}.
{{else if eq .ActionName "close"}}
Closed #{{.Issue.Index}}.
{{else if eq .ActionName "reopen"}}
Reopened #{{.Issue.Index}}.
{{else if ne .ReviewComments}}
Empty comment on #{{.Issue.Index}}.
{{end}} {{end}}
{{else}} {{else}}
{{.Body | Str2html}} {{.Body | Str2html}}
{{end -}} {{end -}}
{{- range .ReviewComments}} {{- range .ReviewComments}}
<hr>
In {{.TreePath}}:
<div class="review"> <div class="review">
<pre>{{.Patch}}</pre> <pre>{{.Patch}}</pre>
<div>{{.RenderedContent | Safe}}</div> <div>{{.RenderedContent | Safe}}</div>
</div> </div>
{{end -}} {{end -}}
</p> </p>
<div class="footer">
<p> <p>
--- ---
<br> <br>
<a href="{{.Link}}">View it on {{AppName}}</a>. <a href="{{.Link}}">View it on {{AppName}}</a>.
</p> </p>
</div>
</body> </body>
</html> </html>

View file

@ -1,16 +1,21 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<style>
.footer { font-size:small; color:#666;}
</style>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>{{.Subject}}</title> <title>{{.Subject}}</title>
</head> </head>
<body> <body>
<p>You have been added as a collaborator of repository: <code>{{.RepoName}}</code></p> <p>You have been added as a collaborator of repository: <code>{{.RepoName}}</code></p>
<p> <div class="footer">
--- <p>
<br> ---
<a href="{{.Link}}">View it on Gitea</a>. <br>
</p> <a href="{{.Link}}">View it on {{AppName}}</a>.
</p>
</div>
</body> </body>
</html> </html>

View file

@ -123,7 +123,7 @@
<div class="ui green label">{{$.i18n.Tr "repo.activity.published_release_label"}}</div> <div class="ui green label">{{$.i18n.Tr "repo.activity.published_release_label"}}</div>
{{.TagName}} {{.TagName}}
{{if not .IsTag}} {{if not .IsTag}}
<a class="title has-emoji" href="{{$.Repository.HTMLURL}}/src/{{.TagName | EscapePound}}">{{.Title}}</a> <a class="title has-emoji" href="{{$.RepoLink}}/src/{{.TagName | EscapePound}}">{{.Title}}</a>
{{end}} {{end}}
{{TimeSinceUnix .CreatedUnix $.Lang}} {{TimeSinceUnix .CreatedUnix $.Lang}}
</p> </p>
@ -140,7 +140,7 @@
{{range .Activity.MergedPRs}} {{range .Activity.MergedPRs}}
<p class="desc"> <p class="desc">
<div class="ui purple label">{{$.i18n.Tr "repo.activity.merged_prs_label"}}</div> <div class="ui purple label">{{$.i18n.Tr "repo.activity.merged_prs_label"}}</div>
#{{.Index}} <a class="title has-emoji" href="{{$.Repository.HTMLURL}}/pulls/{{.Index}}">{{.Issue.Title}}</a> #{{.Index}} <a class="title has-emoji" href="{{$.RepoLink}}/pulls/{{.Index}}">{{.Issue.Title}}</a>
{{TimeSinceUnix .MergedUnix $.Lang}} {{TimeSinceUnix .MergedUnix $.Lang}}
</p> </p>
{{end}} {{end}}
@ -156,7 +156,7 @@
{{range .Activity.OpenedPRs}} {{range .Activity.OpenedPRs}}
<p class="desc"> <p class="desc">
<div class="ui green label">{{$.i18n.Tr "repo.activity.opened_prs_label"}}</div> <div class="ui green label">{{$.i18n.Tr "repo.activity.opened_prs_label"}}</div>
#{{.Index}} <a class="title has-emoji" href="{{$.Repository.HTMLURL}}/pulls/{{.Index}}">{{.Issue.Title}}</a> #{{.Index}} <a class="title has-emoji" href="{{$.RepoLink}}/pulls/{{.Index}}">{{.Issue.Title}}</a>
{{TimeSinceUnix .Issue.CreatedUnix $.Lang}} {{TimeSinceUnix .Issue.CreatedUnix $.Lang}}
</p> </p>
{{end}} {{end}}
@ -172,7 +172,7 @@
{{range .Activity.ClosedIssues}} {{range .Activity.ClosedIssues}}
<p class="desc"> <p class="desc">
<div class="ui red label">{{$.i18n.Tr "repo.activity.closed_issue_label"}}</div> <div class="ui red label">{{$.i18n.Tr "repo.activity.closed_issue_label"}}</div>
#{{.Index}} <a class="title has-emoji" href="{{$.Repository.HTMLURL}}/issues/{{.Index}}">{{.Title}}</a> #{{.Index}} <a class="title has-emoji" href="{{$.RepoLink}}/issues/{{.Index}}">{{.Title}}</a>
{{TimeSinceUnix .ClosedUnix $.Lang}} {{TimeSinceUnix .ClosedUnix $.Lang}}
</p> </p>
{{end}} {{end}}
@ -188,7 +188,7 @@
{{range .Activity.OpenedIssues}} {{range .Activity.OpenedIssues}}
<p class="desc"> <p class="desc">
<div class="ui green label">{{$.i18n.Tr "repo.activity.new_issue_label"}}</div> <div class="ui green label">{{$.i18n.Tr "repo.activity.new_issue_label"}}</div>
#{{.Index}} <a class="title has-emoji" href="{{$.Repository.HTMLURL}}/issues/{{.Index}}">{{.Title}}</a> #{{.Index}} <a class="title has-emoji" href="{{$.RepoLink}}/issues/{{.Index}}">{{.Title}}</a>
{{TimeSinceUnix .CreatedUnix $.Lang}} {{TimeSinceUnix .CreatedUnix $.Lang}}
</p> </p>
{{end}} {{end}}
@ -209,9 +209,9 @@
<div class="ui green label">{{$.i18n.Tr "repo.activity.unresolved_conv_label"}}</div> <div class="ui green label">{{$.i18n.Tr "repo.activity.unresolved_conv_label"}}</div>
#{{.Index}} #{{.Index}}
{{if .IsPull}} {{if .IsPull}}
<a class="title has-emoji" href="{{$.Repository.HTMLURL}}/pulls/{{.Index}}">{{.Title}}</a> <a class="title has-emoji" href="{{$.RepoLink}}/pulls/{{.Index}}">{{.Title}}</a>
{{else}} {{else}}
<a class="title has-emoji" href="{{$.Repository.HTMLURL}}/issues/{{.Index}}">{{.Title}}</a> <a class="title has-emoji" href="{{$.RepoLink}}/issues/{{.Index}}">{{.Title}}</a>
{{end}} {{end}}
{{TimeSinceUnix .UpdatedUnix $.Lang}} {{TimeSinceUnix .UpdatedUnix $.Lang}}
</p> </p>

View file

@ -213,7 +213,7 @@
<a class="preview item" data-url="{{$.Repository.APIURL}}/markdown" data-context="{{$.RepoLink}}">{{$.i18n.Tr "preview"}}</a> <a class="preview item" data-url="{{$.Repository.APIURL}}/markdown" data-context="{{$.RepoLink}}">{{$.i18n.Tr "preview"}}</a>
</div> </div>
<div class="ui bottom attached active write tab segment"> <div class="ui bottom attached active write tab segment">
<textarea tabindex="1" name="content"></textarea> <textarea class="review-textarea" tabindex="1" name="content"></textarea>
</div> </div>
<div class="ui bottom attached tab preview segment markdown"> <div class="ui bottom attached tab preview segment markdown">
{{$.i18n.Tr "loading"}} {{$.i18n.Tr "loading"}}

View file

@ -41,6 +41,7 @@
{{else if .IsFilesConflicted}}grey {{else if .IsFilesConflicted}}grey
{{else if .IsPullRequestBroken}}red {{else if .IsPullRequestBroken}}red
{{else if .IsBlockedByApprovals}}red {{else if .IsBlockedByApprovals}}red
{{else if .IsBlockedByRejection}}red
{{else if and .EnableStatusCheck (not .IsRequiredStatusCheckSuccess)}}red {{else if and .EnableStatusCheck (not .IsRequiredStatusCheckSuccess)}}red
{{else if .Issue.PullRequest.IsChecking}}yellow {{else if .Issue.PullRequest.IsChecking}}yellow
{{else if .Issue.PullRequest.CanAutoMerge}}green {{else if .Issue.PullRequest.CanAutoMerge}}green
@ -100,6 +101,11 @@
<span class="octicon octicon-x"></span> <span class="octicon octicon-x"></span>
{{$.i18n.Tr "repo.pulls.blocked_by_approvals" .GrantedApprovals .Issue.PullRequest.ProtectedBranch.RequiredApprovals}} {{$.i18n.Tr "repo.pulls.blocked_by_approvals" .GrantedApprovals .Issue.PullRequest.ProtectedBranch.RequiredApprovals}}
</div> </div>
{{else if .IsBlockedByRejection}}
<div class="item text red">
<span class="octicon octicon-x"></span>
{{$.i18n.Tr "repo.pulls.blocked_by_rejection"}}
</div>
{{else if .Issue.PullRequest.IsChecking}} {{else if .Issue.PullRequest.IsChecking}}
<div class="item text yellow"> <div class="item text yellow">
<span class="octicon octicon-sync"></span> <span class="octicon octicon-sync"></span>
@ -131,6 +137,7 @@
{{end}} {{end}}
{{if .AllowMerge}} {{if .AllowMerge}}
{{$prUnit := .Repository.MustGetUnit $.UnitTypePullRequests}} {{$prUnit := .Repository.MustGetUnit $.UnitTypePullRequests}}
{{$approvers := .Issue.PullRequest.GetApprovers}}
{{if or $prUnit.PullRequestsConfig.AllowMerge $prUnit.PullRequestsConfig.AllowRebase $prUnit.PullRequestsConfig.AllowRebaseMerge $prUnit.PullRequestsConfig.AllowSquash}} {{if or $prUnit.PullRequestsConfig.AllowMerge $prUnit.PullRequestsConfig.AllowRebase $prUnit.PullRequestsConfig.AllowRebaseMerge $prUnit.PullRequestsConfig.AllowSquash}}
<div class="ui divider"></div> <div class="ui divider"></div>
{{if $prUnit.PullRequestsConfig.AllowMerge}} {{if $prUnit.PullRequestsConfig.AllowMerge}}
@ -141,7 +148,7 @@
<input type="text" name="merge_title_field" value="{{.Issue.PullRequest.GetDefaultMergeMessage}}"> <input type="text" name="merge_title_field" value="{{.Issue.PullRequest.GetDefaultMergeMessage}}">
</div> </div>
<div class="field"> <div class="field">
<textarea name="merge_message_field" rows="5" placeholder="{{$.i18n.Tr "repo.editor.commit_message_desc"}}"></textarea> <textarea name="merge_message_field" rows="5" placeholder="{{$.i18n.Tr "repo.editor.commit_message_desc"}}">{{$approvers}}</textarea>
</div> </div>
<button class="ui green button" type="submit" name="do" value="merge"> <button class="ui green button" type="submit" name="do" value="merge">
{{$.i18n.Tr "repo.pulls.merge_pull_request"}} {{$.i18n.Tr "repo.pulls.merge_pull_request"}}
@ -173,7 +180,7 @@
<input type="text" name="merge_title_field" value="{{.Issue.PullRequest.GetDefaultMergeMessage}}"> <input type="text" name="merge_title_field" value="{{.Issue.PullRequest.GetDefaultMergeMessage}}">
</div> </div>
<div class="field"> <div class="field">
<textarea name="merge_message_field" rows="5" placeholder="{{$.i18n.Tr "repo.editor.commit_message_desc"}}"></textarea> <textarea name="merge_message_field" rows="5" placeholder="{{$.i18n.Tr "repo.editor.commit_message_desc"}}">{{$approvers}}</textarea>
</div> </div>
<button class="ui green button" type="submit" name="do" value="rebase-merge"> <button class="ui green button" type="submit" name="do" value="rebase-merge">
{{$.i18n.Tr "repo.pulls.rebase_merge_commit_pull_request"}} {{$.i18n.Tr "repo.pulls.rebase_merge_commit_pull_request"}}
@ -185,6 +192,7 @@
</div> </div>
{{end}} {{end}}
{{if $prUnit.PullRequestsConfig.AllowSquash}} {{if $prUnit.PullRequestsConfig.AllowSquash}}
{{$commitMessages := .Issue.PullRequest.GetCommitMessages}}
<div class="ui form squash-fields" style="display: none"> <div class="ui form squash-fields" style="display: none">
<form action="{{.Link}}/merge" method="post"> <form action="{{.Link}}/merge" method="post">
{{.CsrfTokenHtml}} {{.CsrfTokenHtml}}
@ -192,7 +200,7 @@
<input type="text" name="merge_title_field" value="{{.Issue.PullRequest.GetDefaultSquashMessage}}"> <input type="text" name="merge_title_field" value="{{.Issue.PullRequest.GetDefaultSquashMessage}}">
</div> </div>
<div class="field"> <div class="field">
<textarea name="merge_message_field" rows="5" placeholder="{{$.i18n.Tr "repo.editor.commit_message_desc"}}"></textarea> <textarea name="merge_message_field" rows="5" placeholder="{{$.i18n.Tr "repo.editor.commit_message_desc"}}">{{$commitMessages}}{{$approvers}}</textarea>
</div> </div>
<button class="ui green button" type="submit" name="do" value="squash"> <button class="ui green button" type="submit" name="do" value="squash">
{{$.i18n.Tr "repo.pulls.squash_merge_pull_request"}} {{$.i18n.Tr "repo.pulls.squash_merge_pull_request"}}

View file

@ -204,6 +204,13 @@
</div> </div>
{{end}} {{end}}
</div> </div>
<div class="field">
<div class="ui checkbox">
<input name="block_on_rejected_reviews" type="checkbox" {{if .Branch.BlockOnRejectedReviews}}checked{{end}}>
<label for="block_on_rejected_reviews">{{.i18n.Tr "repo.settings.block_rejected_reviews"}}</label>
<p class="help">{{.i18n.Tr "repo.settings.block_rejected_reviews_desc"}}</p>
</div>
</div>
</div> </div>
<div class="ui divider"></div> <div class="ui divider"></div>

View file

@ -85,13 +85,11 @@ window.onload = function() {
dom_id: '#swagger-ui', dom_id: '#swagger-ui',
deepLinking: true, deepLinking: true,
presets: [ presets: [
SwaggerUIBundle.presets.apis, SwaggerUIBundle.presets.apis
SwaggerUIStandalonePreset
], ],
plugins: [ plugins: [
SwaggerUIBundle.plugins.DownloadUrl SwaggerUIBundle.plugins.DownloadUrl
], ]
layout: "StandaloneLayout"
}) })
// End Swagger UI call region // End Swagger UI call region

View file

@ -3130,7 +3130,7 @@
], ],
"responses": { "responses": {
"200": { "200": {
"$ref": "#/responses/ReactionResponseList" "$ref": "#/responses/ReactionList"
}, },
"403": { "403": {
"$ref": "#/responses/forbidden" "$ref": "#/responses/forbidden"
@ -3181,8 +3181,11 @@
} }
], ],
"responses": { "responses": {
"200": {
"$ref": "#/responses/Reaction"
},
"201": { "201": {
"$ref": "#/responses/ReactionResponse" "$ref": "#/responses/Reaction"
}, },
"403": { "403": {
"$ref": "#/responses/forbidden" "$ref": "#/responses/forbidden"
@ -3896,7 +3899,7 @@
], ],
"responses": { "responses": {
"200": { "200": {
"$ref": "#/responses/ReactionResponseList" "$ref": "#/responses/ReactionList"
}, },
"403": { "403": {
"$ref": "#/responses/forbidden" "$ref": "#/responses/forbidden"
@ -3947,8 +3950,11 @@
} }
], ],
"responses": { "responses": {
"200": {
"$ref": "#/responses/Reaction"
},
"201": { "201": {
"$ref": "#/responses/ReactionResponse" "$ref": "#/responses/Reaction"
}, },
"403": { "403": {
"$ref": "#/responses/forbidden" "$ref": "#/responses/forbidden"
@ -8609,11 +8615,7 @@
"x-go-name": "BranchFilter" "x-go-name": "BranchFilter"
}, },
"config": { "config": {
"type": "object", "$ref": "#/definitions/CreateHookOptionConfig"
"additionalProperties": {
"type": "string"
},
"x-go-name": "Config"
}, },
"events": { "events": {
"type": "array", "type": "array",
@ -8625,16 +8627,27 @@
"type": { "type": {
"type": "string", "type": "string",
"enum": [ "enum": [
"dingtalk",
"discord",
"gitea", "gitea",
"gogs", "gogs",
"msteams",
"slack", "slack",
"discord" "telegram"
], ],
"x-go-name": "Type" "x-go-name": "Type"
} }
}, },
"x-go-package": "code.gitea.io/gitea/modules/structs" "x-go-package": "code.gitea.io/gitea/modules/structs"
}, },
"CreateHookOptionConfig": {
"description": "CreateHookOptionConfig has all config options in it\nrequired are \"content_type\" and \"url\" Required",
"type": "object",
"additionalProperties": {
"type": "string"
},
"x-go-package": "code.gitea.io/gitea/modules/structs"
},
"CreateIssueCommentOption": { "CreateIssueCommentOption": {
"description": "CreateIssueCommentOption options for creating a comment on an issue", "description": "CreateIssueCommentOption options for creating a comment on an issue",
"type": "object", "type": "object",
@ -10815,8 +10828,8 @@
}, },
"x-go-package": "code.gitea.io/gitea/modules/structs" "x-go-package": "code.gitea.io/gitea/modules/structs"
}, },
"ReactionResponse": { "Reaction": {
"description": "ReactionResponse contain one reaction", "description": "Reaction contain one reaction",
"type": "object", "type": "object",
"properties": { "properties": {
"content": { "content": {
@ -11728,12 +11741,6 @@
} }
} }
}, },
"EditReactionOption": {
"description": "EditReactionOption",
"schema": {
"$ref": "#/definitions/EditReactionOption"
}
},
"EmailList": { "EmailList": {
"description": "EmailList", "description": "EmailList",
"schema": { "schema": {
@ -11920,18 +11927,18 @@
} }
} }
}, },
"ReactionResponse": { "Reaction": {
"description": "ReactionResponse", "description": "Reaction",
"schema": { "schema": {
"$ref": "#/definitions/ReactionResponse" "$ref": "#/definitions/Reaction"
} }
}, },
"ReactionResponseList": { "ReactionList": {
"description": "ReactionResponseList", "description": "ReactionList",
"schema": { "schema": {
"type": "array", "type": "array",
"items": { "items": {
"$ref": "#/definitions/ReactionResponse" "$ref": "#/definitions/Reaction"
} }
} }
}, },
@ -12157,7 +12164,7 @@
"parameterBodies": { "parameterBodies": {
"description": "parameterBodies", "description": "parameterBodies",
"schema": { "schema": {
"$ref": "#/definitions/RepoTopicOptions" "$ref": "#/definitions/EditReactionOption"
} }
}, },
"redirect": { "redirect": {

View file

@ -1,8 +0,0 @@
*.out
*.swp
*.8
*.6
_obj
_test*
markdown
tags

View file

@ -1,17 +0,0 @@
sudo: false
language: go
go:
- "1.10.x"
- "1.11.x"
- tip
matrix:
fast_finish: true
allow_failures:
- go: tip
install:
- # Do nothing. This is needed to prevent default install action "go get -t -v ./..." from happening here (we want it to happen inside script step).
script:
- go get -t -v ./...
- diff -u <(echo -n) <(gofmt -d -s .)
- go tool vet .
- go test -v ./...

View file

@ -1,29 +0,0 @@
Blackfriday is distributed under the Simplified BSD License:
> Copyright © 2011 Russ Ross
> All rights reserved.
>
> Redistribution and use in source and binary forms, with or without
> modification, are permitted provided that the following conditions
> are met:
>
> 1. Redistributions of source code must retain the above copyright
> notice, this list of conditions and the following disclaimer.
>
> 2. Redistributions in binary form must reproduce the above
> copyright notice, this list of conditions and the following
> disclaimer in the documentation and/or other materials provided with
> the distribution.
>
> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
> FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
> COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
> INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
> BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
> LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
> CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
> LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
> ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
> POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,291 +0,0 @@
Blackfriday [![Build Status](https://travis-ci.org/russross/blackfriday.svg?branch=master)](https://travis-ci.org/russross/blackfriday)
===========
Blackfriday is a [Markdown][1] processor implemented in [Go][2]. It
is paranoid about its input (so you can safely feed it user-supplied
data), it is fast, it supports common extensions (tables, smart
punctuation substitutions, etc.), and it is safe for all utf-8
(unicode) input.
HTML output is currently supported, along with Smartypants
extensions.
It started as a translation from C of [Sundown][3].
Installation
------------
Blackfriday is compatible with any modern Go release. With Go 1.7 and git
installed:
go get gopkg.in/russross/blackfriday.v2
will download, compile, and install the package into your `$GOPATH`
directory hierarchy. Alternatively, you can achieve the same if you
import it into a project:
import "gopkg.in/russross/blackfriday.v2"
and `go get` without parameters.
Versions
--------
Currently maintained and recommended version of Blackfriday is `v2`. It's being
developed on its own branch: https://github.com/russross/blackfriday/tree/v2 and the
documentation is available at
https://godoc.org/gopkg.in/russross/blackfriday.v2.
It is `go get`-able via via [gopkg.in][6] at `gopkg.in/russross/blackfriday.v2`,
but we highly recommend using package management tool like [dep][7] or
[Glide][8] and make use of semantic versioning. With package management you
should import `github.com/russross/blackfriday` and specify that you're using
version 2.0.0.
Version 2 offers a number of improvements over v1:
* Cleaned up API
* A separate call to [`Parse`][4], which produces an abstract syntax tree for
the document
* Latest bug fixes
* Flexibility to easily add your own rendering extensions
Potential drawbacks:
* Our benchmarks show v2 to be slightly slower than v1. Currently in the
ballpark of around 15%.
* API breakage. If you can't afford modifying your code to adhere to the new API
and don't care too much about the new features, v2 is probably not for you.
* Several bug fixes are trailing behind and still need to be forward-ported to
v2. See issue [#348](https://github.com/russross/blackfriday/issues/348) for
tracking.
Usage
-----
For the most sensible markdown processing, it is as simple as getting your input
into a byte slice and calling:
```go
output := blackfriday.Run(input)
```
Your input will be parsed and the output rendered with a set of most popular
extensions enabled. If you want the most basic feature set, corresponding with
the bare Markdown specification, use:
```go
output := blackfriday.Run(input, blackfriday.WithNoExtensions())
```
### Sanitize untrusted content
Blackfriday itself does nothing to protect against malicious content. If you are
dealing with user-supplied markdown, we recommend running Blackfriday's output
through HTML sanitizer such as [Bluemonday][5].
Here's an example of simple usage of Blackfriday together with Bluemonday:
```go
import (
"github.com/microcosm-cc/bluemonday"
"github.com/russross/blackfriday"
)
// ...
unsafe := blackfriday.Run(input)
html := bluemonday.UGCPolicy().SanitizeBytes(unsafe)
```
### Custom options
If you want to customize the set of options, use `blackfriday.WithExtensions`,
`blackfriday.WithRenderer` and `blackfriday.WithRefOverride`.
You can also check out `blackfriday-tool` for a more complete example
of how to use it. Download and install it using:
go get github.com/russross/blackfriday-tool
This is a simple command-line tool that allows you to process a
markdown file using a standalone program. You can also browse the
source directly on github if you are just looking for some example
code:
* <http://github.com/russross/blackfriday-tool>
Note that if you have not already done so, installing
`blackfriday-tool` will be sufficient to download and install
blackfriday in addition to the tool itself. The tool binary will be
installed in `$GOPATH/bin`. This is a statically-linked binary that
can be copied to wherever you need it without worrying about
dependencies and library versions.
Features
--------
All features of Sundown are supported, including:
* **Compatibility**. The Markdown v1.0.3 test suite passes with
the `--tidy` option. Without `--tidy`, the differences are
mostly in whitespace and entity escaping, where blackfriday is
more consistent and cleaner.
* **Common extensions**, including table support, fenced code
blocks, autolinks, strikethroughs, non-strict emphasis, etc.
* **Safety**. Blackfriday is paranoid when parsing, making it safe
to feed untrusted user input without fear of bad things
happening. The test suite stress tests this and there are no
known inputs that make it crash. If you find one, please let me
know and send me the input that does it.
NOTE: "safety" in this context means *runtime safety only*. In order to
protect yourself against JavaScript injection in untrusted content, see
[this example](https://github.com/russross/blackfriday#sanitize-untrusted-content).
* **Fast processing**. It is fast enough to render on-demand in
most web applications without having to cache the output.
* **Thread safety**. You can run multiple parsers in different
goroutines without ill effect. There is no dependence on global
shared state.
* **Minimal dependencies**. Blackfriday only depends on standard
library packages in Go. The source code is pretty
self-contained, so it is easy to add to any project, including
Google App Engine projects.
* **Standards compliant**. Output successfully validates using the
W3C validation tool for HTML 4.01 and XHTML 1.0 Transitional.
Extensions
----------
In addition to the standard markdown syntax, this package
implements the following extensions:
* **Intra-word emphasis supression**. The `_` character is
commonly used inside words when discussing code, so having
markdown interpret it as an emphasis command is usually the
wrong thing. Blackfriday lets you treat all emphasis markers as
normal characters when they occur inside a word.
* **Tables**. Tables can be created by drawing them in the input
using a simple syntax:
```
Name | Age
--------|------
Bob | 27
Alice | 23
```
* **Fenced code blocks**. In addition to the normal 4-space
indentation to mark code blocks, you can explicitly mark them
and supply a language (to make syntax highlighting simple). Just
mark it like this:
```go
func getTrue() bool {
return true
}
```
You can use 3 or more backticks to mark the beginning of the
block, and the same number to mark the end of the block.
* **Definition lists**. A simple definition list is made of a single-line
term followed by a colon and the definition for that term.
Cat
: Fluffy animal everyone likes
Internet
: Vector of transmission for pictures of cats
Terms must be separated from the previous definition by a blank line.
* **Footnotes**. A marker in the text that will become a superscript number;
a footnote definition that will be placed in a list of footnotes at the
end of the document. A footnote looks like this:
This is a footnote.[^1]
[^1]: the footnote text.
* **Autolinking**. Blackfriday can find URLs that have not been
explicitly marked as links and turn them into links.
* **Strikethrough**. Use two tildes (`~~`) to mark text that
should be crossed out.
* **Hard line breaks**. With this extension enabled newlines in the input
translate into line breaks in the output. This extension is off by default.
* **Smart quotes**. Smartypants-style punctuation substitution is
supported, turning normal double- and single-quote marks into
curly quotes, etc.
* **LaTeX-style dash parsing** is an additional option, where `--`
is translated into `&ndash;`, and `---` is translated into
`&mdash;`. This differs from most smartypants processors, which
turn a single hyphen into an ndash and a double hyphen into an
mdash.
* **Smart fractions**, where anything that looks like a fraction
is translated into suitable HTML (instead of just a few special
cases like most smartypant processors). For example, `4/5`
becomes `<sup>4</sup>&frasl;<sub>5</sub>`, which renders as
<sup>4</sup>&frasl;<sub>5</sub>.
Other renderers
---------------
Blackfriday is structured to allow alternative rendering engines. Here
are a few of note:
* [github_flavored_markdown](https://godoc.org/github.com/shurcooL/github_flavored_markdown):
provides a GitHub Flavored Markdown renderer with fenced code block
highlighting, clickable heading anchor links.
It's not customizable, and its goal is to produce HTML output
equivalent to the [GitHub Markdown API endpoint](https://developer.github.com/v3/markdown/#render-a-markdown-document-in-raw-mode),
except the rendering is performed locally.
* [markdownfmt](https://github.com/shurcooL/markdownfmt): like gofmt,
but for markdown.
* [LaTeX output](https://github.com/Ambrevar/Blackfriday-LaTeX):
renders output as LaTeX.
* [Blackfriday-Confluence](https://github.com/kentaro-m/blackfriday-confluence): provides a [Confluence Wiki Markup](https://confluence.atlassian.com/doc/confluence-wiki-markup-251003035.html) renderer.
Todo
----
* More unit testing
* Improve unicode support. It does not understand all unicode
rules (about what constitutes a letter, a punctuation symbol,
etc.), so it may fail to detect word boundaries correctly in
some instances. It is safe on all utf-8 input.
License
-------
[Blackfriday is distributed under the Simplified BSD License](LICENSE.txt)
[1]: https://daringfireball.net/projects/markdown/ "Markdown"
[2]: https://golang.org/ "Go Language"
[3]: https://github.com/vmg/sundown "Sundown"
[4]: https://godoc.org/gopkg.in/russross/blackfriday.v2#Parse "Parse func"
[5]: https://github.com/microcosm-cc/bluemonday "Bluemonday"
[6]: https://labix.org/gopkg.in "gopkg.in"

File diff suppressed because it is too large Load diff

View file

@ -1,18 +0,0 @@
// Package blackfriday is a markdown processor.
//
// It translates plain text with simple formatting rules into an AST, which can
// then be further processed to HTML (provided by Blackfriday itself) or other
// formats (provided by the community).
//
// The simplest way to invoke Blackfriday is to call the Run function. It will
// take a text input and produce a text output in HTML (or other format).
//
// A slightly more sophisticated way to use Blackfriday is to create a Markdown
// processor and to call Parse, which returns a syntax tree for the input
// document. You can leverage Blackfriday's parsing for content extraction from
// markdown documents. You can assign a custom renderer and set various options
// to the Markdown processor.
//
// If you're interested in calling Blackfriday from command line, see
// https://github.com/russross/blackfriday-tool.
package blackfriday

View file

@ -1,34 +0,0 @@
package blackfriday
import (
"html"
"io"
)
var htmlEscaper = [256][]byte{
'&': []byte("&amp;"),
'<': []byte("&lt;"),
'>': []byte("&gt;"),
'"': []byte("&quot;"),
}
func escapeHTML(w io.Writer, s []byte) {
var start, end int
for end < len(s) {
escSeq := htmlEscaper[s[end]]
if escSeq != nil {
w.Write(s[start:end])
w.Write(escSeq)
start = end + 1
}
end++
}
if start < len(s) && end <= len(s) {
w.Write(s[start:end])
}
}
func escLink(w io.Writer, text []byte) {
unesc := html.UnescapeString(string(text))
escapeHTML(w, []byte(unesc))
}

View file

@ -1 +0,0 @@
module github.com/russross/blackfriday/v2

View file

@ -1,949 +0,0 @@
//
// Blackfriday Markdown Processor
// Available at http://github.com/russross/blackfriday
//
// Copyright © 2011 Russ Ross <russ@russross.com>.
// Distributed under the Simplified BSD License.
// See README.md for details.
//
//
//
// HTML rendering backend
//
//
package blackfriday
import (
"bytes"
"fmt"
"io"
"regexp"
"strings"
)
// HTMLFlags control optional behavior of HTML renderer.
type HTMLFlags int
// HTML renderer configuration options.
const (
HTMLFlagsNone HTMLFlags = 0
SkipHTML HTMLFlags = 1 << iota // Skip preformatted HTML blocks
SkipImages // Skip embedded images
SkipLinks // Skip all links
Safelink // Only link to trusted protocols
NofollowLinks // Only link with rel="nofollow"
NoreferrerLinks // Only link with rel="noreferrer"
NoopenerLinks // Only link with rel="noopener"
HrefTargetBlank // Add a blank target
CompletePage // Generate a complete HTML page
UseXHTML // Generate XHTML output instead of HTML
FootnoteReturnLinks // Generate a link at the end of a footnote to return to the source
Smartypants // Enable smart punctuation substitutions
SmartypantsFractions // Enable smart fractions (with Smartypants)
SmartypantsDashes // Enable smart dashes (with Smartypants)
SmartypantsLatexDashes // Enable LaTeX-style dashes (with Smartypants)
SmartypantsAngledQuotes // Enable angled double quotes (with Smartypants) for double quotes rendering
SmartypantsQuotesNBSP // Enable « French guillemets » (with Smartypants)
TOC // Generate a table of contents
)
var (
htmlTagRe = regexp.MustCompile("(?i)^" + htmlTag)
)
const (
htmlTag = "(?:" + openTag + "|" + closeTag + "|" + htmlComment + "|" +
processingInstruction + "|" + declaration + "|" + cdata + ")"
closeTag = "</" + tagName + "\\s*[>]"
openTag = "<" + tagName + attribute + "*" + "\\s*/?>"
attribute = "(?:" + "\\s+" + attributeName + attributeValueSpec + "?)"
attributeValue = "(?:" + unquotedValue + "|" + singleQuotedValue + "|" + doubleQuotedValue + ")"
attributeValueSpec = "(?:" + "\\s*=" + "\\s*" + attributeValue + ")"
attributeName = "[a-zA-Z_:][a-zA-Z0-9:._-]*"
cdata = "<!\\[CDATA\\[[\\s\\S]*?\\]\\]>"
declaration = "<![A-Z]+" + "\\s+[^>]*>"
doubleQuotedValue = "\"[^\"]*\""
htmlComment = "<!---->|<!--(?:-?[^>-])(?:-?[^-])*-->"
processingInstruction = "[<][?].*?[?][>]"
singleQuotedValue = "'[^']*'"
tagName = "[A-Za-z][A-Za-z0-9-]*"
unquotedValue = "[^\"'=<>`\\x00-\\x20]+"
)
// HTMLRendererParameters is a collection of supplementary parameters tweaking
// the behavior of various parts of HTML renderer.
type HTMLRendererParameters struct {
// Prepend this text to each relative URL.
AbsolutePrefix string
// Add this text to each footnote anchor, to ensure uniqueness.
FootnoteAnchorPrefix string
// Show this text inside the <a> tag for a footnote return link, if the
// HTML_FOOTNOTE_RETURN_LINKS flag is enabled. If blank, the string
// <sup>[return]</sup> is used.
FootnoteReturnLinkContents string
// If set, add this text to the front of each Heading ID, to ensure
// uniqueness.
HeadingIDPrefix string
// If set, add this text to the back of each Heading ID, to ensure uniqueness.
HeadingIDSuffix string
// Increase heading levels: if the offset is 1, <h1> becomes <h2> etc.
// Negative offset is also valid.
// Resulting levels are clipped between 1 and 6.
HeadingLevelOffset int
Title string // Document title (used if CompletePage is set)
CSS string // Optional CSS file URL (used if CompletePage is set)
Icon string // Optional icon file URL (used if CompletePage is set)
Flags HTMLFlags // Flags allow customizing this renderer's behavior
}
// HTMLRenderer is a type that implements the Renderer interface for HTML output.
//
// Do not create this directly, instead use the NewHTMLRenderer function.
type HTMLRenderer struct {
HTMLRendererParameters
closeTag string // how to end singleton tags: either " />" or ">"
// Track heading IDs to prevent ID collision in a single generation.
headingIDs map[string]int
lastOutputLen int
disableTags int
sr *SPRenderer
}
const (
xhtmlClose = " />"
htmlClose = ">"
)
// NewHTMLRenderer creates and configures an HTMLRenderer object, which
// satisfies the Renderer interface.
func NewHTMLRenderer(params HTMLRendererParameters) *HTMLRenderer {
// configure the rendering engine
closeTag := htmlClose
if params.Flags&UseXHTML != 0 {
closeTag = xhtmlClose
}
if params.FootnoteReturnLinkContents == "" {
params.FootnoteReturnLinkContents = `<sup>[return]</sup>`
}
return &HTMLRenderer{
HTMLRendererParameters: params,
closeTag: closeTag,
headingIDs: make(map[string]int),
sr: NewSmartypantsRenderer(params.Flags),
}
}
func isHTMLTag(tag []byte, tagname string) bool {
found, _ := findHTMLTagPos(tag, tagname)
return found
}
// Look for a character, but ignore it when it's in any kind of quotes, it
// might be JavaScript
func skipUntilCharIgnoreQuotes(html []byte, start int, char byte) int {
inSingleQuote := false
inDoubleQuote := false
inGraveQuote := false
i := start
for i < len(html) {
switch {
case html[i] == char && !inSingleQuote && !inDoubleQuote && !inGraveQuote:
return i
case html[i] == '\'':
inSingleQuote = !inSingleQuote
case html[i] == '"':
inDoubleQuote = !inDoubleQuote
case html[i] == '`':
inGraveQuote = !inGraveQuote
}
i++
}
return start
}
func findHTMLTagPos(tag []byte, tagname string) (bool, int) {
i := 0
if i < len(tag) && tag[0] != '<' {
return false, -1
}
i++
i = skipSpace(tag, i)
if i < len(tag) && tag[i] == '/' {
i++
}
i = skipSpace(tag, i)
j := 0
for ; i < len(tag); i, j = i+1, j+1 {
if j >= len(tagname) {
break
}
if strings.ToLower(string(tag[i]))[0] != tagname[j] {
return false, -1
}
}
if i == len(tag) {
return false, -1
}
rightAngle := skipUntilCharIgnoreQuotes(tag, i, '>')
if rightAngle >= i {
return true, rightAngle
}
return false, -1
}
func skipSpace(tag []byte, i int) int {
for i < len(tag) && isspace(tag[i]) {
i++
}
return i
}
func isRelativeLink(link []byte) (yes bool) {
// a tag begin with '#'
if link[0] == '#' {
return true
}
// link begin with '/' but not '//', the second maybe a protocol relative link
if len(link) >= 2 && link[0] == '/' && link[1] != '/' {
return true
}
// only the root '/'
if len(link) == 1 && link[0] == '/' {
return true
}
// current directory : begin with "./"
if bytes.HasPrefix(link, []byte("./")) {
return true
}
// parent directory : begin with "../"
if bytes.HasPrefix(link, []byte("../")) {
return true
}
return false
}
func (r *HTMLRenderer) ensureUniqueHeadingID(id string) string {
for count, found := r.headingIDs[id]; found; count, found = r.headingIDs[id] {
tmp := fmt.Sprintf("%s-%d", id, count+1)
if _, tmpFound := r.headingIDs[tmp]; !tmpFound {
r.headingIDs[id] = count + 1
id = tmp
} else {
id = id + "-1"
}
}
if _, found := r.headingIDs[id]; !found {
r.headingIDs[id] = 0
}
return id
}
func (r *HTMLRenderer) addAbsPrefix(link []byte) []byte {
if r.AbsolutePrefix != "" && isRelativeLink(link) && link[0] != '.' {
newDest := r.AbsolutePrefix
if link[0] != '/' {
newDest += "/"
}
newDest += string(link)
return []byte(newDest)
}
return link
}
func appendLinkAttrs(attrs []string, flags HTMLFlags, link []byte) []string {
if isRelativeLink(link) {
return attrs
}
val := []string{}
if flags&NofollowLinks != 0 {
val = append(val, "nofollow")
}
if flags&NoreferrerLinks != 0 {
val = append(val, "noreferrer")
}
if flags&NoopenerLinks != 0 {
val = append(val, "noopener")
}
if flags&HrefTargetBlank != 0 {
attrs = append(attrs, "target=\"_blank\"")
}
if len(val) == 0 {
return attrs
}
attr := fmt.Sprintf("rel=%q", strings.Join(val, " "))
return append(attrs, attr)
}
func isMailto(link []byte) bool {
return bytes.HasPrefix(link, []byte("mailto:"))
}
func needSkipLink(flags HTMLFlags, dest []byte) bool {
if flags&SkipLinks != 0 {
return true
}
return flags&Safelink != 0 && !isSafeLink(dest) && !isMailto(dest)
}
func isSmartypantable(node *Node) bool {
pt := node.Parent.Type
return pt != Link && pt != CodeBlock && pt != Code
}
func appendLanguageAttr(attrs []string, info []byte) []string {
if len(info) == 0 {
return attrs
}
endOfLang := bytes.IndexAny(info, "\t ")
if endOfLang < 0 {
endOfLang = len(info)
}
return append(attrs, fmt.Sprintf("class=\"language-%s\"", info[:endOfLang]))
}
func (r *HTMLRenderer) tag(w io.Writer, name []byte, attrs []string) {
w.Write(name)
if len(attrs) > 0 {
w.Write(spaceBytes)
w.Write([]byte(strings.Join(attrs, " ")))
}
w.Write(gtBytes)
r.lastOutputLen = 1
}
func footnoteRef(prefix string, node *Node) []byte {
urlFrag := prefix + string(slugify(node.Destination))
anchor := fmt.Sprintf(`<a href="#fn:%s">%d</a>`, urlFrag, node.NoteID)
return []byte(fmt.Sprintf(`<sup class="footnote-ref" id="fnref:%s">%s</sup>`, urlFrag, anchor))
}
func footnoteItem(prefix string, slug []byte) []byte {
return []byte(fmt.Sprintf(`<li id="fn:%s%s">`, prefix, slug))
}
func footnoteReturnLink(prefix, returnLink string, slug []byte) []byte {
const format = ` <a class="footnote-return" href="#fnref:%s%s">%s</a>`
return []byte(fmt.Sprintf(format, prefix, slug, returnLink))
}
func itemOpenCR(node *Node) bool {
if node.Prev == nil {
return false
}
ld := node.Parent.ListData
return !ld.Tight && ld.ListFlags&ListTypeDefinition == 0
}
func skipParagraphTags(node *Node) bool {
grandparent := node.Parent.Parent
if grandparent == nil || grandparent.Type != List {
return false
}
tightOrTerm := grandparent.Tight || node.Parent.ListFlags&ListTypeTerm != 0
return grandparent.Type == List && tightOrTerm
}
func cellAlignment(align CellAlignFlags) string {
switch align {
case TableAlignmentLeft:
return "left"
case TableAlignmentRight:
return "right"
case TableAlignmentCenter:
return "center"
default:
return ""
}
}
func (r *HTMLRenderer) out(w io.Writer, text []byte) {
if r.disableTags > 0 {
w.Write(htmlTagRe.ReplaceAll(text, []byte{}))
} else {
w.Write(text)
}
r.lastOutputLen = len(text)
}
func (r *HTMLRenderer) cr(w io.Writer) {
if r.lastOutputLen > 0 {
r.out(w, nlBytes)
}
}
var (
nlBytes = []byte{'\n'}
gtBytes = []byte{'>'}
spaceBytes = []byte{' '}
)
var (
brTag = []byte("<br>")
brXHTMLTag = []byte("<br />")
emTag = []byte("<em>")
emCloseTag = []byte("</em>")
strongTag = []byte("<strong>")
strongCloseTag = []byte("</strong>")
delTag = []byte("<del>")
delCloseTag = []byte("</del>")
ttTag = []byte("<tt>")
ttCloseTag = []byte("</tt>")
aTag = []byte("<a")
aCloseTag = []byte("</a>")
preTag = []byte("<pre>")
preCloseTag = []byte("</pre>")
codeTag = []byte("<code>")
codeCloseTag = []byte("</code>")
pTag = []byte("<p>")
pCloseTag = []byte("</p>")
blockquoteTag = []byte("<blockquote>")
blockquoteCloseTag = []byte("</blockquote>")
hrTag = []byte("<hr>")
hrXHTMLTag = []byte("<hr />")
ulTag = []byte("<ul>")
ulCloseTag = []byte("</ul>")
olTag = []byte("<ol>")
olCloseTag = []byte("</ol>")
dlTag = []byte("<dl>")
dlCloseTag = []byte("</dl>")
liTag = []byte("<li>")
liCloseTag = []byte("</li>")
ddTag = []byte("<dd>")
ddCloseTag = []byte("</dd>")
dtTag = []byte("<dt>")
dtCloseTag = []byte("</dt>")
tableTag = []byte("<table>")
tableCloseTag = []byte("</table>")
tdTag = []byte("<td")
tdCloseTag = []byte("</td>")
thTag = []byte("<th")
thCloseTag = []byte("</th>")
theadTag = []byte("<thead>")
theadCloseTag = []byte("</thead>")
tbodyTag = []byte("<tbody>")
tbodyCloseTag = []byte("</tbody>")
trTag = []byte("<tr>")
trCloseTag = []byte("</tr>")
h1Tag = []byte("<h1")
h1CloseTag = []byte("</h1>")
h2Tag = []byte("<h2")
h2CloseTag = []byte("</h2>")
h3Tag = []byte("<h3")
h3CloseTag = []byte("</h3>")
h4Tag = []byte("<h4")
h4CloseTag = []byte("</h4>")
h5Tag = []byte("<h5")
h5CloseTag = []byte("</h5>")
h6Tag = []byte("<h6")
h6CloseTag = []byte("</h6>")
footnotesDivBytes = []byte("\n<div class=\"footnotes\">\n\n")
footnotesCloseDivBytes = []byte("\n</div>\n")
)
func headingTagsFromLevel(level int) ([]byte, []byte) {
if level <= 1 {
return h1Tag, h1CloseTag
}
switch level {
case 2:
return h2Tag, h2CloseTag
case 3:
return h3Tag, h3CloseTag
case 4:
return h4Tag, h4CloseTag
case 5:
return h5Tag, h5CloseTag
}
return h6Tag, h6CloseTag
}
func (r *HTMLRenderer) outHRTag(w io.Writer) {
if r.Flags&UseXHTML == 0 {
r.out(w, hrTag)
} else {
r.out(w, hrXHTMLTag)
}
}
// RenderNode is a default renderer of a single node of a syntax tree. For
// block nodes it will be called twice: first time with entering=true, second
// time with entering=false, so that it could know when it's working on an open
// tag and when on close. It writes the result to w.
//
// The return value is a way to tell the calling walker to adjust its walk
// pattern: e.g. it can terminate the traversal by returning Terminate. Or it
// can ask the walker to skip a subtree of this node by returning SkipChildren.
// The typical behavior is to return GoToNext, which asks for the usual
// traversal to the next node.
func (r *HTMLRenderer) RenderNode(w io.Writer, node *Node, entering bool) WalkStatus {
attrs := []string{}
switch node.Type {
case Text:
if r.Flags&Smartypants != 0 {
var tmp bytes.Buffer
escapeHTML(&tmp, node.Literal)
r.sr.Process(w, tmp.Bytes())
} else {
if node.Parent.Type == Link {
escLink(w, node.Literal)
} else {
escapeHTML(w, node.Literal)
}
}
case Softbreak:
r.cr(w)
// TODO: make it configurable via out(renderer.softbreak)
case Hardbreak:
if r.Flags&UseXHTML == 0 {
r.out(w, brTag)
} else {
r.out(w, brXHTMLTag)
}
r.cr(w)
case Emph:
if entering {
r.out(w, emTag)
} else {
r.out(w, emCloseTag)
}
case Strong:
if entering {
r.out(w, strongTag)
} else {
r.out(w, strongCloseTag)
}
case Del:
if entering {
r.out(w, delTag)
} else {
r.out(w, delCloseTag)
}
case HTMLSpan:
if r.Flags&SkipHTML != 0 {
break
}
r.out(w, node.Literal)
case Link:
// mark it but don't link it if it is not a safe link: no smartypants
dest := node.LinkData.Destination
if needSkipLink(r.Flags, dest) {
if entering {
r.out(w, ttTag)
} else {
r.out(w, ttCloseTag)
}
} else {
if entering {
dest = r.addAbsPrefix(dest)
var hrefBuf bytes.Buffer
hrefBuf.WriteString("href=\"")
escLink(&hrefBuf, dest)
hrefBuf.WriteByte('"')
attrs = append(attrs, hrefBuf.String())
if node.NoteID != 0 {
r.out(w, footnoteRef(r.FootnoteAnchorPrefix, node))
break
}
attrs = appendLinkAttrs(attrs, r.Flags, dest)
if len(node.LinkData.Title) > 0 {
var titleBuff bytes.Buffer
titleBuff.WriteString("title=\"")
escapeHTML(&titleBuff, node.LinkData.Title)
titleBuff.WriteByte('"')
attrs = append(attrs, titleBuff.String())
}
r.tag(w, aTag, attrs)
} else {
if node.NoteID != 0 {
break
}
r.out(w, aCloseTag)
}
}
case Image:
if r.Flags&SkipImages != 0 {
return SkipChildren
}
if entering {
dest := node.LinkData.Destination
dest = r.addAbsPrefix(dest)
if r.disableTags == 0 {
//if options.safe && potentiallyUnsafe(dest) {
//out(w, `<img src="" alt="`)
//} else {
r.out(w, []byte(`<img src="`))
escLink(w, dest)
r.out(w, []byte(`" alt="`))
//}
}
r.disableTags++
} else {
r.disableTags--
if r.disableTags == 0 {
if node.LinkData.Title != nil {
r.out(w, []byte(`" title="`))
escapeHTML(w, node.LinkData.Title)
}
r.out(w, []byte(`" />`))
}
}
case Code:
r.out(w, codeTag)
escapeHTML(w, node.Literal)
r.out(w, codeCloseTag)
case Document:
break
case Paragraph:
if skipParagraphTags(node) {
break
}
if entering {
// TODO: untangle this clusterfuck about when the newlines need
// to be added and when not.
if node.Prev != nil {
switch node.Prev.Type {
case HTMLBlock, List, Paragraph, Heading, CodeBlock, BlockQuote, HorizontalRule:
r.cr(w)
}
}
if node.Parent.Type == BlockQuote && node.Prev == nil {
r.cr(w)
}
r.out(w, pTag)
} else {
r.out(w, pCloseTag)
if !(node.Parent.Type == Item && node.Next == nil) {
r.cr(w)
}
}
case BlockQuote:
if entering {
r.cr(w)
r.out(w, blockquoteTag)
} else {
r.out(w, blockquoteCloseTag)
r.cr(w)
}
case HTMLBlock:
if r.Flags&SkipHTML != 0 {
break
}
r.cr(w)
r.out(w, node.Literal)
r.cr(w)
case Heading:
headingLevel := r.HTMLRendererParameters.HeadingLevelOffset + node.Level
openTag, closeTag := headingTagsFromLevel(headingLevel)
if entering {
if node.IsTitleblock {
attrs = append(attrs, `class="title"`)
}
if node.HeadingID != "" {
id := r.ensureUniqueHeadingID(node.HeadingID)
if r.HeadingIDPrefix != "" {
id = r.HeadingIDPrefix + id
}
if r.HeadingIDSuffix != "" {
id = id + r.HeadingIDSuffix
}
attrs = append(attrs, fmt.Sprintf(`id="%s"`, id))
}
r.cr(w)
r.tag(w, openTag, attrs)
} else {
r.out(w, closeTag)
if !(node.Parent.Type == Item && node.Next == nil) {
r.cr(w)
}
}
case HorizontalRule:
r.cr(w)
r.outHRTag(w)
r.cr(w)
case List:
openTag := ulTag
closeTag := ulCloseTag
if node.ListFlags&ListTypeOrdered != 0 {
openTag = olTag
closeTag = olCloseTag
}
if node.ListFlags&ListTypeDefinition != 0 {
openTag = dlTag
closeTag = dlCloseTag
}
if entering {
if node.IsFootnotesList {
r.out(w, footnotesDivBytes)
r.outHRTag(w)
r.cr(w)
}
r.cr(w)
if node.Parent.Type == Item && node.Parent.Parent.Tight {
r.cr(w)
}
r.tag(w, openTag[:len(openTag)-1], attrs)
r.cr(w)
} else {
r.out(w, closeTag)
//cr(w)
//if node.parent.Type != Item {
// cr(w)
//}
if node.Parent.Type == Item && node.Next != nil {
r.cr(w)
}
if node.Parent.Type == Document || node.Parent.Type == BlockQuote {
r.cr(w)
}
if node.IsFootnotesList {
r.out(w, footnotesCloseDivBytes)
}
}
case Item:
openTag := liTag
closeTag := liCloseTag
if node.ListFlags&ListTypeDefinition != 0 {
openTag = ddTag
closeTag = ddCloseTag
}
if node.ListFlags&ListTypeTerm != 0 {
openTag = dtTag
closeTag = dtCloseTag
}
if entering {
if itemOpenCR(node) {
r.cr(w)
}
if node.ListData.RefLink != nil {
slug := slugify(node.ListData.RefLink)
r.out(w, footnoteItem(r.FootnoteAnchorPrefix, slug))
break
}
r.out(w, openTag)
} else {
if node.ListData.RefLink != nil {
slug := slugify(node.ListData.RefLink)
if r.Flags&FootnoteReturnLinks != 0 {
r.out(w, footnoteReturnLink(r.FootnoteAnchorPrefix, r.FootnoteReturnLinkContents, slug))
}
}
r.out(w, closeTag)
r.cr(w)
}
case CodeBlock:
attrs = appendLanguageAttr(attrs, node.Info)
r.cr(w)
r.out(w, preTag)
r.tag(w, codeTag[:len(codeTag)-1], attrs)
escapeHTML(w, node.Literal)
r.out(w, codeCloseTag)
r.out(w, preCloseTag)
if node.Parent.Type != Item {
r.cr(w)
}
case Table:
if entering {
r.cr(w)
r.out(w, tableTag)
} else {
r.out(w, tableCloseTag)
r.cr(w)
}
case TableCell:
openTag := tdTag
closeTag := tdCloseTag
if node.IsHeader {
openTag = thTag
closeTag = thCloseTag
}
if entering {
align := cellAlignment(node.Align)
if align != "" {
attrs = append(attrs, fmt.Sprintf(`align="%s"`, align))
}
if node.Prev == nil {
r.cr(w)
}
r.tag(w, openTag, attrs)
} else {
r.out(w, closeTag)
r.cr(w)
}
case TableHead:
if entering {
r.cr(w)
r.out(w, theadTag)
} else {
r.out(w, theadCloseTag)
r.cr(w)
}
case TableBody:
if entering {
r.cr(w)
r.out(w, tbodyTag)
// XXX: this is to adhere to a rather silly test. Should fix test.
if node.FirstChild == nil {
r.cr(w)
}
} else {
r.out(w, tbodyCloseTag)
r.cr(w)
}
case TableRow:
if entering {
r.cr(w)
r.out(w, trTag)
} else {
r.out(w, trCloseTag)
r.cr(w)
}
default:
panic("Unknown node type " + node.Type.String())
}
return GoToNext
}
// RenderHeader writes HTML document preamble and TOC if requested.
func (r *HTMLRenderer) RenderHeader(w io.Writer, ast *Node) {
r.writeDocumentHeader(w)
if r.Flags&TOC != 0 {
r.writeTOC(w, ast)
}
}
// RenderFooter writes HTML document footer.
func (r *HTMLRenderer) RenderFooter(w io.Writer, ast *Node) {
if r.Flags&CompletePage == 0 {
return
}
io.WriteString(w, "\n</body>\n</html>\n")
}
func (r *HTMLRenderer) writeDocumentHeader(w io.Writer) {
if r.Flags&CompletePage == 0 {
return
}
ending := ""
if r.Flags&UseXHTML != 0 {
io.WriteString(w, "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" ")
io.WriteString(w, "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n")
io.WriteString(w, "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n")
ending = " /"
} else {
io.WriteString(w, "<!DOCTYPE html>\n")
io.WriteString(w, "<html>\n")
}
io.WriteString(w, "<head>\n")
io.WriteString(w, " <title>")
if r.Flags&Smartypants != 0 {
r.sr.Process(w, []byte(r.Title))
} else {
escapeHTML(w, []byte(r.Title))
}
io.WriteString(w, "</title>\n")
io.WriteString(w, " <meta name=\"GENERATOR\" content=\"Blackfriday Markdown Processor v")
io.WriteString(w, Version)
io.WriteString(w, "\"")
io.WriteString(w, ending)
io.WriteString(w, ">\n")
io.WriteString(w, " <meta charset=\"utf-8\"")
io.WriteString(w, ending)
io.WriteString(w, ">\n")
if r.CSS != "" {
io.WriteString(w, " <link rel=\"stylesheet\" type=\"text/css\" href=\"")
escapeHTML(w, []byte(r.CSS))
io.WriteString(w, "\"")
io.WriteString(w, ending)
io.WriteString(w, ">\n")
}
if r.Icon != "" {
io.WriteString(w, " <link rel=\"icon\" type=\"image/x-icon\" href=\"")
escapeHTML(w, []byte(r.Icon))
io.WriteString(w, "\"")
io.WriteString(w, ending)
io.WriteString(w, ">\n")
}
io.WriteString(w, "</head>\n")
io.WriteString(w, "<body>\n\n")
}
func (r *HTMLRenderer) writeTOC(w io.Writer, ast *Node) {
buf := bytes.Buffer{}
inHeading := false
tocLevel := 0
headingCount := 0
ast.Walk(func(node *Node, entering bool) WalkStatus {
if node.Type == Heading && !node.HeadingData.IsTitleblock {
inHeading = entering
if entering {
node.HeadingID = fmt.Sprintf("toc_%d", headingCount)
if node.Level == tocLevel {
buf.WriteString("</li>\n\n<li>")
} else if node.Level < tocLevel {
for node.Level < tocLevel {
tocLevel--
buf.WriteString("</li>\n</ul>")
}
buf.WriteString("</li>\n\n<li>")
} else {
for node.Level > tocLevel {
tocLevel++
buf.WriteString("\n<ul>\n<li>")
}
}
fmt.Fprintf(&buf, `<a href="#toc_%d">`, headingCount)
headingCount++
} else {
buf.WriteString("</a>")
}
return GoToNext
}
if inHeading {
return r.RenderNode(&buf, node, entering)
}
return GoToNext
})
for ; tocLevel > 0; tocLevel-- {
buf.WriteString("</li>\n</ul>")
}
if buf.Len() > 0 {
io.WriteString(w, "<nav>\n")
w.Write(buf.Bytes())
io.WriteString(w, "\n\n</nav>\n")
}
r.lastOutputLen = buf.Len()
}

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