From 27c34dd011cceb8232d1c3307f87b53a147c75c3 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Sun, 3 Apr 2022 00:17:41 +0000 Subject: [PATCH 1/4] [skip ci] Updated translations via Crowdin --- options/locale/locale_zh-CN.ini | 66 +++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 2b4936bacc..62a1967748 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -1181,6 +1181,7 @@ projects.board.deletion_desc=删除项目看板会将所有相关问题移至“ projects.board.color=颜色 projects.open=开启 projects.close=关闭 +projects.board.assigned_to=指派给 issues.desc=组织 bug 报告、任务和里程碑。 issues.filter_assignees=筛选指派人 @@ -1373,6 +1374,8 @@ issues.lock.reason=锁定原因 issues.lock.title=锁定有关此问题的对话。 issues.unlock.title=解锁有关此问题的对话。 issues.comment_on_locked=您不能对锁定的问题发表评论。 +issues.delete=删除 +issues.delete.title=是否删除工单? issues.tracker=时间跟踪 issues.start_tracking_short=启动计时器 issues.start_tracking=开始时间跟踪 @@ -1413,6 +1416,8 @@ issues.due_date_remove=到期时间 %s %s 已删除 issues.due_date_overdue=过期 issues.due_date_invalid=到期日期无效或超出范围。请使用 'yyyy-mm-dd' 格式。 issues.dependency.title=依赖工单 +issues.dependency.issue_no_dependencies=没有设置依赖项。 +issues.dependency.pr_no_dependencies=没有设置依赖项。 issues.dependency.add=添加依赖工单... issues.dependency.cancel=取消 issues.dependency.remove=删除 @@ -1942,6 +1947,7 @@ settings.event_pull_request_review=已审核的合并请求 settings.event_pull_request_review_desc=合并请求被批准、拒绝或提出审查意见 settings.event_pull_request_sync=合并请求被同步 settings.event_pull_request_sync_desc=合并请求被同步。 +settings.event_package=软件包 settings.branch_filter=分支过滤 settings.branch_filter_desc=推送、创建,删除分支事件的分支白名单,使用 glob 模式匹配指定。若为空或 *,则将报告所有分支的事件。语法文档见 github.com/gobwas/glob。示例:master,{master,release*}。 settings.active=激活 @@ -2537,6 +2543,13 @@ repos.forks=派生数 repos.issues=工单数 repos.size=大小 +packages.owner=所有者 +packages.creator=创建者 +packages.name=名称 +packages.version=版本 +packages.type=类型 +packages.repository=仓库 +packages.size=大小 defaulthooks=默认Web钩子 defaulthooks.desc=当某些 Gitea 事件触发时,Web 钩子自动向服务器发出 HTTP POST 请求。这里定义的 Web 钩子是默认配置,将被复制到所有新的仓库中。详情请访问 Web 钩子指南。 @@ -2975,4 +2988,57 @@ error.no_unit_allowed_repo=您没有被允许访问此仓库的任何单元。 error.unit_not_allowed=您没有权限访问此仓库单元 [packages] +title=软件包 +filter.type=类型 +filter.type.all=所有 +details=详情 +details.author=作者 +details.project_site=项目站点 +details.license=许可协议 +container.multi_arch=OS / Arch +container.layers=镜像层 +container.labels=标签 +container.labels.key=键 +container.labels.value=值 +generic.download=从命令行下载软件包: +generic.documentation=关于通用注册中心的更多信息,请参阅 文档 。 +maven.registry=在您项目的 pom.xml 文件中设置此注册中心: +maven.install=要使用这个软件包,在 pom.xml 文件中的 依赖项 块中包含以下内容: +maven.install2=通过命令行运行: +maven.download=要下载依赖项,请通过命令行运行: +maven.documentation=关于 Maven 注册中心的更多信息,请参阅 文档。 +nuget.registry=从命令行设置此注册中心: +nuget.install=要使用 Nuget 安装软件包,请运行以下命令: +nuget.documentation=关于 Nuget 注册中心的更多信息,请参阅 文档。 +nuget.dependency.framework=目标框架 +npm.registry=在您项目的 .npmrc 文件中设置此注册中心: +npm.install=要使用 npm 安装软件包,请运行以下命令: +npm.install2=或将其添加到 package.json 文件: +npm.documentation=关于 npm 注册中心的更多信息,请参阅 文档。 +npm.dependencies=依赖项 +npm.dependencies.development=开发依赖 +npm.dependencies.peer=Peer 依赖 +npm.dependencies.optional=可选依赖 +npm.details.tag=标签 +pypi.requires=需要 Python +pypi.install=要使用 pip 安装软件包,请运行以下命令: +pypi.documentation=关于 PyPI 注册中心的更多信息,请参阅 文档。 +rubygems.install=要使用 gem 安装软件包,请运行以下命令: +rubygems.install2=或将它添加到 Gemfile: +rubygems.dependencies.runtime=运行时依赖 +rubygems.dependencies.development=开发依赖 +rubygems.required.ruby=需要 Ruby 版本 +rubygems.required.rubygems=需要 RubyGem 版本 +rubygems.documentation=关于 RubyGems 注册中心的更多信息,请参阅 文档 。 +settings.link=将此软件包链接到仓库 +settings.link.description=如果您将一个软件包与一个代码库链接起来,软件包将显示在代码库的软件包列表中。 +settings.link.select=选择仓库 +settings.link.button=更新仓库链接 +settings.link.success=仓库链接已成功更新。 +settings.link.error=更新仓库链接失败。 +settings.delete=删除软件包 +settings.delete.description=删除软件包是永久性的,无法撤消。 +settings.delete.notice=您将要删除 %s (%s)。此操作是不可逆的,您确定吗? +settings.delete.success=软件包已被删除。 +settings.delete.error=删除软件包失败。 From d242511e86c3a6d8a7013100845d2cdc8eb5252c Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Sun, 3 Apr 2022 17:46:48 +0800 Subject: [PATCH 2/4] Remove legacy unmaintained packages, refactor to support change default locale (#19308) Remove two unmaintained vendor packages `i18n` and `paginater`. Changes: * Rewrite `i18n` package with a more clear fallback mechanism. Fix an unstable `Tr` behavior, add more tests. * Refactor the legacy `Paginater` to `Paginator`, test cases are kept unchanged. Trivial enhancement (no breaking for end users): * Use the first locale in LANGS setting option as the default, add a log to prevent from surprising users. --- custom/conf/app.example.ini | 1 + .../doc/advanced/config-cheat-sheet.en-us.md | 3 +- .../doc/advanced/customizing-gitea.en-us.md | 2 + go.mod | 2 - go.sum | 5 - integrations/auth_ldap_test.go | 2 +- integrations/branches_test.go | 3 +- integrations/pull_merge_test.go | 2 +- integrations/release_test.go | 2 +- integrations/repo_branch_test.go | 2 +- integrations/signin_test.go | 2 +- integrations/signup_test.go | 8 +- integrations/user_test.go | 2 +- modules/context/pagination.go | 9 +- modules/markup/markdown/toc.go | 3 +- modules/paginator/paginator.go | 203 ++++++++++++ modules/paginator/paginator_test.go | 311 ++++++++++++++++++ modules/timeutil/since.go | 3 +- modules/timeutil/since_test.go | 2 +- modules/translation/i18n/i18n.go | 143 ++++++++ modules/translation/i18n/i18n_test.go | 56 ++++ modules/translation/translation.go | 21 +- modules/web/middleware/locale.go | 6 +- routers/web/repo/issue_content_history.go | 2 +- routers/web/user/setting/profile.go | 3 +- services/cron/setting.go | 2 +- 26 files changed, 758 insertions(+), 42 deletions(-) create mode 100644 modules/paginator/paginator.go create mode 100644 modules/paginator/paginator_test.go create mode 100644 modules/translation/i18n/i18n.go create mode 100644 modules/translation/i18n/i18n_test.go diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 8cc22f1d14..822be00bae 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -2117,6 +2117,7 @@ PATH = ;[i18n] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; The first locale will be used as the default if user browser's language doesn't match any locale in the list. ;LANGS = en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,uk-UA,ja-JP,es-ES,pt-BR,pt-PT,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR,el-GR,fa-IR,hu-HU,id-ID,ml-IN ;NAMES = English,简体中文,繁體中文(香港),繁體中文(台灣),Deutsch,français,Nederlands,latviešu,русский,Українська,日本語,español,português do Brasil,Português de Portugal,polski,български,italiano,suomi,Türkçe,čeština,српски,svenska,한국어,ελληνικά,فارسی,magyar nyelv,bahasa Indonesia,മലയാളം diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 25247a6805..b3c015cb88 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -997,7 +997,8 @@ Default templates for project boards: ## i18n (`i18n`) -- `LANGS`: **en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,ja-JP,es-ES,pt-BR,pt-PT,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR,el-GR,fa-IR,hu-HU,id-ID,ml-IN**: List of locales shown in language selector +- `LANGS`: **en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,ja-JP,es-ES,pt-BR,pt-PT,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR,el-GR,fa-IR,hu-HU,id-ID,ml-IN**: + List of locales shown in language selector. The first locale will be used as the default if user browser's language doesn't match any locale in the list. - `NAMES`: **English,简体中文,繁體中文(香港),繁體中文(台灣),Deutsch,français,Nederlands,latviešu,русский,日本語,español,português do Brasil,Português de Portugal,polski,български,italiano,suomi,Türkçe,čeština,српски,svenska,한국어,ελληνικά,فارسی,magyar nyelv,bahasa Indonesia,മലയാളം**: Visible names corresponding to the locales ## U2F (`U2F`) **DEPRECATED** diff --git a/docs/content/doc/advanced/customizing-gitea.en-us.md b/docs/content/doc/advanced/customizing-gitea.en-us.md index 39a08308b8..1a8386fc3e 100644 --- a/docs/content/doc/advanced/customizing-gitea.en-us.md +++ b/docs/content/doc/advanced/customizing-gitea.en-us.md @@ -299,6 +299,8 @@ LANGS = en-US,foo-BAR NAMES = English,FooBar ``` +The first locale will be used as the default if user browser's language doesn't match any locale in the list. + Locales may change between versions, so keeping track of your customized locales is highly encouraged. ### Readmes diff --git a/go.mod b/go.mod index 957e8fc68b..bfb87a1b37 100644 --- a/go.mod +++ b/go.mod @@ -78,8 +78,6 @@ require ( github.com/stretchr/testify v1.7.0 github.com/syndtr/goleveldb v1.0.0 github.com/tstranex/u2f v1.0.0 - github.com/unknwon/i18n v0.0.0-20210904045753-ff3a8617e361 - github.com/unknwon/paginater v0.0.0-20200328080006-042474bd0eae github.com/unrolled/render v1.4.1 github.com/urfave/cli v1.22.5 github.com/xanzy/go-gitlab v0.58.0 diff --git a/go.sum b/go.sum index d43cc56e8d..d969c26bf5 100644 --- a/go.sum +++ b/go.sum @@ -1503,10 +1503,6 @@ github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0o github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM= github.com/unknwon/com v1.0.1 h1:3d1LTxD+Lnf3soQiD4Cp/0BRB+Rsa/+RTvz8GMMzIXs= github.com/unknwon/com v1.0.1/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM= -github.com/unknwon/i18n v0.0.0-20210904045753-ff3a8617e361 h1:4Ij5sX4JEzCCY/CCl8trJHey1tPsIDomYTZf145GKk0= -github.com/unknwon/i18n v0.0.0-20210904045753-ff3a8617e361/go.mod h1:+5rDk6sDGpl3azws3O+f+GpFSyN9GVr0K8cvQLQM2ZQ= -github.com/unknwon/paginater v0.0.0-20200328080006-042474bd0eae h1:ihaXiJkaca54IaCSnEXtE/uSZOmPxKZhDfVLrzZLFDs= -github.com/unknwon/paginater v0.0.0-20200328080006-042474bd0eae/go.mod h1:1fdkY6xxl6ExVs2QFv7R0F5IRZHKA8RahhB9fMC9RvM= github.com/unrolled/render v1.4.1 h1:VdpMc2YkAOWzbmC/P2yoHhRDXgsaCQHcTJ1KK6SNCA4= github.com/unrolled/render v1.4.1/go.mod h1:cK4RSTTVdND5j9EYEc0LAMOvdG11JeiKjyjfyZRvV2w= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= @@ -2272,7 +2268,6 @@ gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AW gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/ini.v1 v1.44.2/go.mod h1:M3Cogqpuv0QCi3ExAY5V4uOt4qb/R3xZubo9m8lK5wg= -gopkg.in/ini.v1 v1.46.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= diff --git a/integrations/auth_ldap_test.go b/integrations/auth_ldap_test.go index 93334aec00..0eee5ae0cd 100644 --- a/integrations/auth_ldap_test.go +++ b/integrations/auth_ldap_test.go @@ -16,10 +16,10 @@ import ( "code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/translation/i18n" "code.gitea.io/gitea/services/auth" "github.com/stretchr/testify/assert" - "github.com/unknwon/i18n" ) type ldapUser struct { diff --git a/integrations/branches_test.go b/integrations/branches_test.go index aa4df6ac6a..551c5f8af8 100644 --- a/integrations/branches_test.go +++ b/integrations/branches_test.go @@ -9,8 +9,9 @@ import ( "net/url" "testing" + "code.gitea.io/gitea/modules/translation/i18n" + "github.com/stretchr/testify/assert" - "github.com/unknwon/i18n" ) func TestViewBranches(t *testing.T) { diff --git a/integrations/pull_merge_test.go b/integrations/pull_merge_test.go index 4e063bbdb6..d7cb042e9c 100644 --- a/integrations/pull_merge_test.go +++ b/integrations/pull_merge_test.go @@ -24,10 +24,10 @@ import ( "code.gitea.io/gitea/modules/git" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/test" + "code.gitea.io/gitea/modules/translation/i18n" "code.gitea.io/gitea/services/pull" "github.com/stretchr/testify/assert" - "github.com/unknwon/i18n" ) func testPullMerge(t *testing.T, session *TestSession, user, repo, pullnum string, mergeStyle repo_model.MergeStyle) *httptest.ResponseRecorder { diff --git a/integrations/release_test.go b/integrations/release_test.go index 88591a05e9..d75d74956e 100644 --- a/integrations/release_test.go +++ b/integrations/release_test.go @@ -14,10 +14,10 @@ import ( "code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/test" + "code.gitea.io/gitea/modules/translation/i18n" "github.com/PuerkitoBio/goquery" "github.com/stretchr/testify/assert" - "github.com/unknwon/i18n" ) func createNewRelease(t *testing.T, session *TestSession, repoURL, tag, title string, preRelease, draft bool) { diff --git a/integrations/repo_branch_test.go b/integrations/repo_branch_test.go index ade5d673b9..30a446ccec 100644 --- a/integrations/repo_branch_test.go +++ b/integrations/repo_branch_test.go @@ -13,9 +13,9 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/test" + "code.gitea.io/gitea/modules/translation/i18n" "github.com/stretchr/testify/assert" - "github.com/unknwon/i18n" ) func testCreateBranch(t testing.TB, session *TestSession, user, repo, oldRefSubURL, newBranchName string, expectedStatus int) string { diff --git a/integrations/signin_test.go b/integrations/signin_test.go index a6e4b7d4d2..811f9326ec 100644 --- a/integrations/signin_test.go +++ b/integrations/signin_test.go @@ -11,9 +11,9 @@ import ( "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/translation/i18n" "github.com/stretchr/testify/assert" - "github.com/unknwon/i18n" ) func testLoginFailed(t *testing.T, username, password, message string) { diff --git a/integrations/signup_test.go b/integrations/signup_test.go index 87dea2fbe7..7b45674376 100644 --- a/integrations/signup_test.go +++ b/integrations/signup_test.go @@ -13,9 +13,9 @@ import ( "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/translation/i18n" "github.com/stretchr/testify/assert" - "github.com/unknwon/i18n" ) func TestSignup(t *testing.T) { @@ -68,9 +68,9 @@ func TestSignupEmail(t *testing.T) { wantStatus int wantMsg string }{ - {"exampleUser@example.com\r\n", http.StatusOK, i18n.Tr("en", "form.email_invalid", nil)}, - {"exampleUser@example.com\r", http.StatusOK, i18n.Tr("en", "form.email_invalid", nil)}, - {"exampleUser@example.com\n", http.StatusOK, i18n.Tr("en", "form.email_invalid", nil)}, + {"exampleUser@example.com\r\n", http.StatusOK, i18n.Tr("en", "form.email_invalid")}, + {"exampleUser@example.com\r", http.StatusOK, i18n.Tr("en", "form.email_invalid")}, + {"exampleUser@example.com\n", http.StatusOK, i18n.Tr("en", "form.email_invalid")}, {"exampleUser@example.com", http.StatusSeeOther, ""}, } diff --git a/integrations/user_test.go b/integrations/user_test.go index f7c9acb057..e8fbccd51e 100644 --- a/integrations/user_test.go +++ b/integrations/user_test.go @@ -11,9 +11,9 @@ import ( "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/test" + "code.gitea.io/gitea/modules/translation/i18n" "github.com/stretchr/testify/assert" - "github.com/unknwon/i18n" ) func TestViewUser(t *testing.T) { diff --git a/modules/context/pagination.go b/modules/context/pagination.go index 107cbf6186..c0079c2950 100644 --- a/modules/context/pagination.go +++ b/modules/context/pagination.go @@ -10,19 +10,19 @@ import ( "net/url" "strings" - "github.com/unknwon/paginater" + "code.gitea.io/gitea/modules/paginator" ) -// Pagination provides a pagination via Paginater and additional configurations for the link params used in rendering +// Pagination provides a pagination via paginator.Paginator and additional configurations for the link params used in rendering type Pagination struct { - Paginater *paginater.Paginater + Paginater *paginator.Paginator urlParams []string } // NewPagination creates a new instance of the Pagination struct func NewPagination(total, page, issueNum, numPages int) *Pagination { p := &Pagination{} - p.Paginater = paginater.New(total, page, issueNum, numPages) + p.Paginater = paginator.New(total, page, issueNum, numPages) return p } @@ -53,5 +53,6 @@ func (p *Pagination) SetDefaultParams(ctx *Context) { p.AddParam(ctx, "sort", "SortType") p.AddParam(ctx, "q", "Keyword") p.AddParam(ctx, "tab", "TabName") + // do not add any more uncommon params here! p.AddParam(ctx, "t", "queryType") } diff --git a/modules/markup/markdown/toc.go b/modules/markup/markdown/toc.go index 189821c341..9d11b771f7 100644 --- a/modules/markup/markdown/toc.go +++ b/modules/markup/markdown/toc.go @@ -8,7 +8,8 @@ import ( "fmt" "net/url" - "github.com/unknwon/i18n" + "code.gitea.io/gitea/modules/translation/i18n" + "github.com/yuin/goldmark/ast" ) diff --git a/modules/paginator/paginator.go b/modules/paginator/paginator.go new file mode 100644 index 0000000000..873cfe49d4 --- /dev/null +++ b/modules/paginator/paginator.go @@ -0,0 +1,203 @@ +// Copyright 2022 The Gitea Authors. +// Copyright 2015 Unknwon. Licensed under the Apache License, Version 2.0 + +package paginator + +/* +In template: + +```html +{{if not .Page.IsFirst}}[First](1){{end}} +{{if .Page.HasPrevious}}[Previous]({{.Page.Previous}}){{end}} + +{{range .Page.Pages}} + {{if eq .Num -1}} + ... + {{else}} + {{.Num}}{{if .IsCurrent}}(current){{end}} + {{end}} +{{end}} + +{{if .Page.HasNext}}[Next]({{.Page.Next}}){{end}} +{{if not .Page.IsLast}}[Last]({{.Page.TotalPages}}){{end}} +``` + +Output: + +``` +[First](1) [Previous](2) ... 2 3(current) 4 ... [Next](4) [Last](5) +``` +*/ + +// Paginator represents a set of results of pagination calculations. +type Paginator struct { + total int // total rows count + pagingNum int // how many rows in one page + current int // current page number + numPages int // how many pages to show on the UI +} + +// New initialize a new pagination calculation and returns a Paginator as result. +func New(total, pagingNum, current, numPages int) *Paginator { + if pagingNum <= 0 { + pagingNum = 1 + } + if current <= 0 { + current = 1 + } + p := &Paginator{total, pagingNum, current, numPages} + if p.current > p.TotalPages() { + p.current = p.TotalPages() + } + return p +} + +// IsFirst returns true if current page is the first page. +func (p *Paginator) IsFirst() bool { + return p.current == 1 +} + +// HasPrevious returns true if there is a previous page relative to current page. +func (p *Paginator) HasPrevious() bool { + return p.current > 1 +} + +func (p *Paginator) Previous() int { + if !p.HasPrevious() { + return p.current + } + return p.current - 1 +} + +// HasNext returns true if there is a next page relative to current page. +func (p *Paginator) HasNext() bool { + return p.total > p.current*p.pagingNum +} + +func (p *Paginator) Next() int { + if !p.HasNext() { + return p.current + } + return p.current + 1 +} + +// IsLast returns true if current page is the last page. +func (p *Paginator) IsLast() bool { + if p.total == 0 { + return true + } + return p.total > (p.current-1)*p.pagingNum && !p.HasNext() +} + +// Total returns number of total rows. +func (p *Paginator) Total() int { + return p.total +} + +// TotalPages returns number of total pages. +func (p *Paginator) TotalPages() int { + if p.total == 0 { + return 1 + } + return (p.total + p.pagingNum - 1) / p.pagingNum +} + +// Current returns current page number. +func (p *Paginator) Current() int { + return p.current +} + +// PagingNum returns number of page size. +func (p *Paginator) PagingNum() int { + return p.pagingNum +} + +// Page presents a page in the paginator. +type Page struct { + num int + isCurrent bool +} + +func (p *Page) Num() int { + return p.num +} + +func (p *Page) IsCurrent() bool { + return p.isCurrent +} + +func getMiddleIdx(numPages int) int { + return (numPages + 1) / 2 +} + +// Pages returns a list of nearby page numbers relative to current page. +// If value is -1 means "..." that more pages are not showing. +func (p *Paginator) Pages() []*Page { + if p.numPages == 0 { + return []*Page{} + } else if p.numPages == 1 && p.TotalPages() == 1 { + // Only show current page. + return []*Page{{1, true}} + } + + // Total page number is less or equal. + if p.TotalPages() <= p.numPages { + pages := make([]*Page, p.TotalPages()) + for i := range pages { + pages[i] = &Page{i + 1, i+1 == p.current} + } + return pages + } + + numPages := p.numPages + offsetIdx := 0 + hasMoreNext := false + + // Check more previous and next pages. + previousNum := getMiddleIdx(p.numPages) - 1 + if previousNum > p.current-1 { + previousNum -= previousNum - (p.current - 1) + } + nextNum := p.numPages - previousNum - 1 + if p.current+nextNum > p.TotalPages() { + delta := nextNum - (p.TotalPages() - p.current) + nextNum -= delta + previousNum += delta + } + + offsetVal := p.current - previousNum + if offsetVal > 1 { + numPages++ + offsetIdx = 1 + } + + if p.current+nextNum < p.TotalPages() { + numPages++ + hasMoreNext = true + } + + pages := make([]*Page, numPages) + + // There are more previous pages. + if offsetIdx == 1 { + pages[0] = &Page{-1, false} + } + // There are more next pages. + if hasMoreNext { + pages[len(pages)-1] = &Page{-1, false} + } + + // Check previous pages. + for i := 0; i < previousNum; i++ { + pages[offsetIdx+i] = &Page{i + offsetVal, false} + } + + pages[offsetIdx+previousNum] = &Page{p.current, true} + + // Check next pages. + for i := 1; i <= nextNum; i++ { + pages[offsetIdx+previousNum+i] = &Page{p.current + i, false} + } + + return pages +} diff --git a/modules/paginator/paginator_test.go b/modules/paginator/paginator_test.go new file mode 100644 index 0000000000..ce7b7275e1 --- /dev/null +++ b/modules/paginator/paginator_test.go @@ -0,0 +1,311 @@ +// Copyright 2022 The Gitea Authors. +// Copyright 2015 Unknwon. Licensed under the Apache License, Version 2.0 + +package paginator + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestPaginator(t *testing.T) { + t.Run("Basic logics", func(t *testing.T) { + p := New(0, -1, -1, 0) + assert.Equal(t, 1, p.PagingNum()) + assert.True(t, p.IsFirst()) + assert.False(t, p.HasPrevious()) + assert.Equal(t, 1, p.Previous()) + assert.False(t, p.HasNext()) + assert.Equal(t, 1, p.Next()) + assert.True(t, p.IsLast()) + assert.Equal(t, 0, p.Total()) + + p = New(1, 10, 2, 0) + assert.Equal(t, 10, p.PagingNum()) + assert.True(t, p.IsFirst()) + assert.False(t, p.HasPrevious()) + assert.False(t, p.HasNext()) + assert.True(t, p.IsLast()) + + p = New(10, 10, 1, 0) + assert.Equal(t, 10, p.PagingNum()) + assert.True(t, p.IsFirst()) + assert.False(t, p.HasPrevious()) + assert.False(t, p.HasNext()) + assert.True(t, p.IsLast()) + + p = New(11, 10, 1, 0) + assert.Equal(t, 10, p.PagingNum()) + assert.True(t, p.IsFirst()) + assert.False(t, p.HasPrevious()) + assert.True(t, p.HasNext()) + assert.Equal(t, 2, p.Next()) + assert.False(t, p.IsLast()) + + p = New(11, 10, 2, 0) + assert.Equal(t, 10, p.PagingNum()) + assert.False(t, p.IsFirst()) + assert.True(t, p.HasPrevious()) + assert.Equal(t, 1, p.Previous()) + assert.False(t, p.HasNext()) + assert.True(t, p.IsLast()) + + p = New(20, 10, 2, 0) + assert.Equal(t, 10, p.PagingNum()) + assert.False(t, p.IsFirst()) + assert.True(t, p.HasPrevious()) + assert.False(t, p.HasNext()) + assert.True(t, p.IsLast()) + + p = New(25, 10, 2, 0) + assert.Equal(t, 10, p.PagingNum()) + assert.False(t, p.IsFirst()) + assert.True(t, p.HasPrevious()) + assert.True(t, p.HasNext()) + assert.False(t, p.IsLast()) + }) + + t.Run("Generate pages", func(t *testing.T) { + p := New(0, 10, 1, 0) + pages := p.Pages() + assert.Equal(t, 0, len(pages)) + }) + + t.Run("Only current page", func(t *testing.T) { + p := New(0, 10, 1, 1) + pages := p.Pages() + assert.Equal(t, 1, len(pages)) + assert.Equal(t, 1, pages[0].Num()) + assert.True(t, pages[0].IsCurrent()) + + p = New(1, 10, 1, 1) + pages = p.Pages() + assert.Equal(t, 1, len(pages)) + assert.Equal(t, 1, pages[0].Num()) + assert.True(t, pages[0].IsCurrent()) + }) + + t.Run("Total page number is less or equal", func(t *testing.T) { + p := New(1, 10, 1, 2) + pages := p.Pages() + assert.Equal(t, 1, len(pages)) + assert.Equal(t, 1, pages[0].Num()) + assert.True(t, pages[0].IsCurrent()) + + p = New(11, 10, 1, 2) + pages = p.Pages() + assert.Equal(t, 2, len(pages)) + assert.Equal(t, 1, pages[0].Num()) + assert.True(t, pages[0].IsCurrent()) + assert.Equal(t, 2, pages[1].Num()) + assert.False(t, pages[1].IsCurrent()) + + p = New(11, 10, 2, 2) + pages = p.Pages() + assert.Equal(t, 2, len(pages)) + assert.Equal(t, 1, pages[0].Num()) + assert.False(t, pages[0].IsCurrent()) + assert.Equal(t, 2, pages[1].Num()) + assert.True(t, pages[1].IsCurrent()) + + p = New(25, 10, 2, 3) + pages = p.Pages() + assert.Equal(t, 3, len(pages)) + assert.Equal(t, 1, pages[0].Num()) + assert.False(t, pages[0].IsCurrent()) + assert.Equal(t, 2, pages[1].Num()) + assert.True(t, pages[1].IsCurrent()) + assert.Equal(t, 3, pages[2].Num()) + assert.False(t, pages[2].IsCurrent()) + }) + + t.Run("Has more previous pages ", func(t *testing.T) { + // ... 2 + p := New(11, 10, 2, 1) + pages := p.Pages() + assert.Equal(t, 2, len(pages)) + assert.Equal(t, -1, pages[0].Num()) + assert.False(t, pages[0].IsCurrent()) + assert.Equal(t, 2, pages[1].Num()) + assert.True(t, pages[1].IsCurrent()) + + // ... 2 3 + p = New(21, 10, 2, 2) + pages = p.Pages() + assert.Equal(t, 3, len(pages)) + assert.Equal(t, -1, pages[0].Num()) + assert.False(t, pages[0].IsCurrent()) + assert.Equal(t, 2, pages[1].Num()) + assert.True(t, pages[1].IsCurrent()) + assert.Equal(t, 3, pages[2].Num()) + assert.False(t, pages[2].IsCurrent()) + + // ... 2 3 4 + p = New(31, 10, 3, 3) + pages = p.Pages() + assert.Equal(t, 4, len(pages)) + assert.Equal(t, -1, pages[0].Num()) + assert.False(t, pages[0].IsCurrent()) + assert.Equal(t, 2, pages[1].Num()) + assert.False(t, pages[1].IsCurrent()) + assert.Equal(t, 3, pages[2].Num()) + assert.True(t, pages[2].IsCurrent()) + assert.Equal(t, 4, pages[3].Num()) + assert.False(t, pages[3].IsCurrent()) + + // ... 3 4 5 + p = New(41, 10, 4, 3) + pages = p.Pages() + assert.Equal(t, 4, len(pages)) + assert.Equal(t, -1, pages[0].Num()) + assert.False(t, pages[0].IsCurrent()) + assert.Equal(t, 3, pages[1].Num()) + assert.False(t, pages[1].IsCurrent()) + assert.Equal(t, 4, pages[2].Num()) + assert.True(t, pages[2].IsCurrent()) + assert.Equal(t, 5, pages[3].Num()) + assert.False(t, pages[3].IsCurrent()) + + // ... 4 5 6 7 8 9 10 + p = New(100, 10, 9, 7) + pages = p.Pages() + assert.Equal(t, 8, len(pages)) + assert.Equal(t, -1, pages[0].Num()) + assert.False(t, pages[0].IsCurrent()) + assert.Equal(t, 4, pages[1].Num()) + assert.False(t, pages[1].IsCurrent()) + assert.Equal(t, 5, pages[2].Num()) + assert.False(t, pages[2].IsCurrent()) + assert.Equal(t, 6, pages[3].Num()) + assert.False(t, pages[3].IsCurrent()) + assert.Equal(t, 7, pages[4].Num()) + assert.False(t, pages[4].IsCurrent()) + assert.Equal(t, 8, pages[5].Num()) + assert.False(t, pages[5].IsCurrent()) + assert.Equal(t, 9, pages[6].Num()) + assert.True(t, pages[6].IsCurrent()) + assert.Equal(t, 10, pages[7].Num()) + assert.False(t, pages[7].IsCurrent()) + }) + + t.Run("Has more next pages", func(t *testing.T) { + // 1 ... + p := New(21, 10, 1, 1) + pages := p.Pages() + assert.Equal(t, 2, len(pages)) + assert.Equal(t, 1, pages[0].Num()) + assert.True(t, pages[0].IsCurrent()) + assert.Equal(t, -1, pages[1].Num()) + assert.False(t, pages[1].IsCurrent()) + + // 1 2 ... + p = New(21, 10, 1, 2) + pages = p.Pages() + assert.Equal(t, 3, len(pages)) + assert.Equal(t, 1, pages[0].Num()) + assert.True(t, pages[0].IsCurrent()) + assert.Equal(t, 2, pages[1].Num()) + assert.False(t, pages[1].IsCurrent()) + assert.Equal(t, -1, pages[2].Num()) + assert.False(t, pages[2].IsCurrent()) + + // 1 2 3 ... + p = New(31, 10, 2, 3) + pages = p.Pages() + assert.Equal(t, 4, len(pages)) + assert.Equal(t, 1, pages[0].Num()) + assert.False(t, pages[0].IsCurrent()) + assert.Equal(t, 2, pages[1].Num()) + assert.True(t, pages[1].IsCurrent()) + assert.Equal(t, 3, pages[2].Num()) + assert.False(t, pages[2].IsCurrent()) + assert.Equal(t, -1, pages[3].Num()) + assert.False(t, pages[3].IsCurrent()) + + // 1 2 3 ... + p = New(41, 10, 2, 3) + pages = p.Pages() + assert.Equal(t, 4, len(pages)) + assert.Equal(t, 1, pages[0].Num()) + assert.False(t, pages[0].IsCurrent()) + assert.Equal(t, 2, pages[1].Num()) + assert.True(t, pages[1].IsCurrent()) + assert.Equal(t, 3, pages[2].Num()) + assert.False(t, pages[2].IsCurrent()) + assert.Equal(t, -1, pages[3].Num()) + assert.False(t, pages[3].IsCurrent()) + + // 1 2 3 4 5 6 7 ... + p = New(100, 10, 1, 7) + pages = p.Pages() + assert.Equal(t, 8, len(pages)) + assert.Equal(t, 1, pages[0].Num()) + assert.True(t, pages[0].IsCurrent()) + assert.Equal(t, 2, pages[1].Num()) + assert.False(t, pages[1].IsCurrent()) + assert.Equal(t, 3, pages[2].Num()) + assert.False(t, pages[2].IsCurrent()) + assert.Equal(t, 4, pages[3].Num()) + assert.False(t, pages[3].IsCurrent()) + assert.Equal(t, 5, pages[4].Num()) + assert.False(t, pages[4].IsCurrent()) + assert.Equal(t, 6, pages[5].Num()) + assert.False(t, pages[5].IsCurrent()) + assert.Equal(t, 7, pages[6].Num()) + assert.False(t, pages[6].IsCurrent()) + assert.Equal(t, -1, pages[7].Num()) + assert.False(t, pages[7].IsCurrent()) + + // 1 2 3 4 5 6 7 ... + p = New(100, 10, 2, 7) + pages = p.Pages() + assert.Equal(t, 8, len(pages)) + assert.Equal(t, 1, pages[0].Num()) + assert.False(t, pages[0].IsCurrent()) + assert.Equal(t, 2, pages[1].Num()) + assert.True(t, pages[1].IsCurrent()) + assert.Equal(t, 3, pages[2].Num()) + assert.False(t, pages[2].IsCurrent()) + assert.Equal(t, 4, pages[3].Num()) + assert.False(t, pages[3].IsCurrent()) + assert.Equal(t, 5, pages[4].Num()) + assert.False(t, pages[4].IsCurrent()) + assert.Equal(t, 6, pages[5].Num()) + assert.False(t, pages[5].IsCurrent()) + assert.Equal(t, 7, pages[6].Num()) + assert.False(t, pages[6].IsCurrent()) + assert.Equal(t, -1, pages[7].Num()) + assert.False(t, pages[7].IsCurrent()) + }) + + t.Run("Has both more previous and next pages", func(t *testing.T) { + // ... 2 3 ... + p := New(35, 10, 2, 2) + pages := p.Pages() + assert.Equal(t, 4, len(pages)) + assert.Equal(t, -1, pages[0].Num()) + assert.False(t, pages[0].IsCurrent()) + assert.Equal(t, 2, pages[1].Num()) + assert.True(t, pages[1].IsCurrent()) + assert.Equal(t, 3, pages[2].Num()) + assert.False(t, pages[2].IsCurrent()) + assert.Equal(t, -1, pages[3].Num()) + assert.False(t, pages[3].IsCurrent()) + + // ... 2 3 4 ... + p = New(49, 10, 3, 3) + pages = p.Pages() + assert.Equal(t, 5, len(pages)) + assert.Equal(t, -1, pages[0].Num()) + assert.False(t, pages[0].IsCurrent()) + assert.Equal(t, 2, pages[1].Num()) + assert.False(t, pages[1].IsCurrent()) + assert.Equal(t, 3, pages[2].Num()) + assert.True(t, pages[2].IsCurrent()) + assert.Equal(t, 4, pages[3].Num()) + assert.False(t, pages[3].IsCurrent()) + assert.Equal(t, -1, pages[4].Num()) + assert.False(t, pages[4].IsCurrent()) + }) +} diff --git a/modules/timeutil/since.go b/modules/timeutil/since.go index c0240907ae..38b12829ad 100644 --- a/modules/timeutil/since.go +++ b/modules/timeutil/since.go @@ -12,8 +12,7 @@ import ( "time" "code.gitea.io/gitea/modules/setting" - - "github.com/unknwon/i18n" + "code.gitea.io/gitea/modules/translation/i18n" ) // Seconds-based time units diff --git a/modules/timeutil/since_test.go b/modules/timeutil/since_test.go index 1379e71c3d..49951b6e41 100644 --- a/modules/timeutil/since_test.go +++ b/modules/timeutil/since_test.go @@ -12,9 +12,9 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/translation" + "code.gitea.io/gitea/modules/translation/i18n" "github.com/stretchr/testify/assert" - "github.com/unknwon/i18n" ) var BaseDate time.Time diff --git a/modules/translation/i18n/i18n.go b/modules/translation/i18n/i18n.go new file mode 100644 index 0000000000..664e457ecf --- /dev/null +++ b/modules/translation/i18n/i18n.go @@ -0,0 +1,143 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package i18n + +import ( + "errors" + "fmt" + "reflect" + "strings" + + "code.gitea.io/gitea/modules/log" + + "gopkg.in/ini.v1" +) + +var ( + ErrLocaleAlreadyExist = errors.New("lang already exists") + + DefaultLocales = NewLocaleStore() +) + +type locale struct { + store *LocaleStore + langName string + langDesc string + messages *ini.File +} + +type LocaleStore struct { + // at the moment, all these fields are readonly after initialization + langNames []string + langDescs []string + localeMap map[string]*locale + defaultLang string +} + +func NewLocaleStore() *LocaleStore { + return &LocaleStore{localeMap: make(map[string]*locale)} +} + +// AddLocaleByIni adds locale by ini into the store +func (ls *LocaleStore) AddLocaleByIni(langName, langDesc string, localeFile interface{}, otherLocaleFiles ...interface{}) error { + if _, ok := ls.localeMap[langName]; ok { + return ErrLocaleAlreadyExist + } + iniFile, err := ini.LoadSources(ini.LoadOptions{ + IgnoreInlineComment: true, + UnescapeValueCommentSymbols: true, + }, localeFile, otherLocaleFiles...) + if err == nil { + iniFile.BlockMode = false + lc := &locale{store: ls, langName: langName, langDesc: langDesc, messages: iniFile} + ls.langNames = append(ls.langNames, lc.langName) + ls.langDescs = append(ls.langDescs, lc.langDesc) + ls.localeMap[lc.langName] = lc + } + return err +} + +func (ls *LocaleStore) HasLang(langName string) bool { + _, ok := ls.localeMap[langName] + return ok +} + +func (ls *LocaleStore) ListLangNameDesc() (names, desc []string) { + return ls.langNames, ls.langDescs +} + +// SetDefaultLang sets default language as a fallback +func (ls *LocaleStore) SetDefaultLang(lang string) { + ls.defaultLang = lang +} + +// Tr translates content to target language. fall back to default language. +func (ls *LocaleStore) Tr(lang, trKey string, trArgs ...interface{}) string { + l, ok := ls.localeMap[lang] + if !ok { + l, ok = ls.localeMap[ls.defaultLang] + } + if ok { + return l.Tr(trKey, trArgs...) + } + return trKey +} + +// Tr translates content to locale language. fall back to default language. +func (l *locale) Tr(trKey string, trArgs ...interface{}) string { + var section string + + idx := strings.IndexByte(trKey, '.') + if idx > 0 { + section = trKey[:idx] + trKey = trKey[idx+1:] + } + + trMsg := trKey + if trIni, err := l.messages.Section(section).GetKey(trKey); err == nil { + trMsg = trIni.Value() + } else if l.store.defaultLang != "" && l.langName != l.store.defaultLang { + // try to fall back to default + if defaultLocale, ok := l.store.localeMap[l.store.defaultLang]; ok { + if trIni, err = defaultLocale.messages.Section(section).GetKey(trKey); err == nil { + trMsg = trIni.Value() + } + } + } + + if len(trArgs) > 0 { + fmtArgs := make([]interface{}, 0, len(trArgs)) + for _, arg := range trArgs { + val := reflect.ValueOf(arg) + if val.Kind() == reflect.Slice { + // before, it can accept Tr(lang, key, a, [b, c], d, [e, f]) as Sprintf(msg, a, b, c, d, e, f), it's an unstable behavior + // now, we restrict the strange behavior and only support: + // 1. Tr(lang, key, [slice-items]) as Sprintf(msg, items...) + // 2. Tr(lang, key, args...) as Sprintf(msg, args...) + if len(trArgs) == 1 { + for i := 0; i < val.Len(); i++ { + fmtArgs = append(fmtArgs, val.Index(i).Interface()) + } + } else { + log.Error("the args for i18n shouldn't contain uncertain slices, key=%q, args=%v", trKey, trArgs) + break + } + } else { + fmtArgs = append(fmtArgs, arg) + } + } + return fmt.Sprintf(trMsg, fmtArgs...) + } + return trMsg +} + +func ResetDefaultLocales() { + DefaultLocales = NewLocaleStore() +} + +// Tr use default locales to translate content to target language. +func Tr(lang, trKey string, trArgs ...interface{}) string { + return DefaultLocales.Tr(lang, trKey, trArgs...) +} diff --git a/modules/translation/i18n/i18n_test.go b/modules/translation/i18n/i18n_test.go new file mode 100644 index 0000000000..70066016cf --- /dev/null +++ b/modules/translation/i18n/i18n_test.go @@ -0,0 +1,56 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package i18n + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_Tr(t *testing.T) { + testData1 := []byte(` +.dot.name = Dot Name +fmt = %[1]s %[2]s + +[section] +sub = Sub String +mixed = test value; more text +`) + + testData2 := []byte(` +fmt = %[2]s %[1]s + +[section] +sub = Changed Sub String +`) + + ls := NewLocaleStore() + assert.NoError(t, ls.AddLocaleByIni("lang1", "Lang1", testData1)) + assert.NoError(t, ls.AddLocaleByIni("lang2", "Lang2", testData2)) + ls.SetDefaultLang("lang1") + + result := ls.Tr("lang1", "fmt", "a", "b") + assert.Equal(t, "a b", result) + + result = ls.Tr("lang2", "fmt", "a", "b") + assert.Equal(t, "b a", result) + + result = ls.Tr("lang1", "section.sub") + assert.Equal(t, "Sub String", result) + + result = ls.Tr("lang2", "section.sub") + assert.Equal(t, "Changed Sub String", result) + + result = ls.Tr("", ".dot.name") + assert.Equal(t, "Dot Name", result) + + result = ls.Tr("lang2", "section.mixed") + assert.Equal(t, `test value; more text`, result) + + langs, descs := ls.ListLangNameDesc() + assert.Equal(t, []string{"lang1", "lang2"}, langs) + assert.Equal(t, []string{"Lang1", "Lang2"}, descs) +} diff --git a/modules/translation/translation.go b/modules/translation/translation.go index fd38e4d510..da9d9b9b68 100644 --- a/modules/translation/translation.go +++ b/modules/translation/translation.go @@ -11,8 +11,8 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/options" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/translation/i18n" - "github.com/unknwon/i18n" "golang.org/x/text/language" ) @@ -54,13 +54,13 @@ func TryTr(lang, format string, args ...interface{}) (string, bool) { // InitLocales loads the locales func InitLocales() { - i18n.Reset() + i18n.ResetDefaultLocales() localeNames, err := options.Dir("locale") if err != nil { log.Fatal("Failed to list locale files: %v", err) } - localFiles := make(map[string][]byte) + localFiles := make(map[string][]byte, len(localeNames)) for _, name := range localeNames { localFiles[name], err = options.Locale(name) if err != nil { @@ -76,16 +76,21 @@ func InitLocales() { matcher = language.NewMatcher(supportedTags) for i := range setting.Names { key := "locale_" + setting.Langs[i] + ".ini" - if err = i18n.SetMessageWithDesc(setting.Langs[i], setting.Names[i], localFiles[key]); err != nil { + if err = i18n.DefaultLocales.AddLocaleByIni(setting.Langs[i], setting.Names[i], localFiles[key]); err != nil { log.Error("Failed to set messages to %s: %v", setting.Langs[i], err) } } - i18n.SetDefaultLang("en-US") + if len(setting.Langs) != 0 { + defaultLangName := setting.Langs[0] + if defaultLangName != "en-US" { + log.Info("Use the first locale (%s) in LANGS setting option as default", defaultLangName) + } + i18n.DefaultLocales.SetDefaultLang(defaultLangName) + } - allLangs = make([]*LangType, 0, i18n.Count()) + langs, descs := i18n.DefaultLocales.ListLangNameDesc() + allLangs = make([]*LangType, 0, len(langs)) allLangMap = map[string]*LangType{} - langs := i18n.ListLangs() - descs := i18n.ListLangDescs() for i, v := range langs { l := &LangType{v, descs[i]} allLangs = append(allLangs, l) diff --git a/modules/web/middleware/locale.go b/modules/web/middleware/locale.go index 3daf5f32d4..de8e497965 100644 --- a/modules/web/middleware/locale.go +++ b/modules/web/middleware/locale.go @@ -9,8 +9,8 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/translation" + "code.gitea.io/gitea/modules/translation/i18n" - "github.com/unknwon/i18n" "golang.org/x/text/language" ) @@ -28,8 +28,8 @@ func Locale(resp http.ResponseWriter, req *http.Request) translation.Locale { } } - // Check again in case someone modify by purpose. - if lang != "" && !i18n.IsExist(lang) { + // Check again in case someone changes the supported language list. + if lang != "" && !i18n.DefaultLocales.HasLang(lang) { lang = "" changeLang = false } diff --git a/routers/web/repo/issue_content_history.go b/routers/web/repo/issue_content_history.go index 21b22aa710..11cc8a2a6f 100644 --- a/routers/web/repo/issue_content_history.go +++ b/routers/web/repo/issue_content_history.go @@ -18,9 +18,9 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/translation/i18n" "github.com/sergi/go-diff/diffmatchpatch" - "github.com/unknwon/i18n" ) // GetContentHistoryOverview get overview diff --git a/routers/web/user/setting/profile.go b/routers/web/user/setting/profile.go index 7a875e38cb..0123b9b523 100644 --- a/routers/web/user/setting/profile.go +++ b/routers/web/user/setting/profile.go @@ -24,6 +24,7 @@ import ( "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/translation/i18n" "code.gitea.io/gitea/modules/typesniffer" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" @@ -31,8 +32,6 @@ import ( "code.gitea.io/gitea/services/agit" "code.gitea.io/gitea/services/forms" user_service "code.gitea.io/gitea/services/user" - - "github.com/unknwon/i18n" ) const ( diff --git a/services/cron/setting.go b/services/cron/setting.go index f0683393ff..9b59a562f7 100644 --- a/services/cron/setting.go +++ b/services/cron/setting.go @@ -7,7 +7,7 @@ package cron import ( "time" - "github.com/unknwon/i18n" + "code.gitea.io/gitea/modules/translation/i18n" ) // Config represents a basic configuration interface that cron task From be9ef15f8a6346987294ae0b6185e393253f6673 Mon Sep 17 00:00:00 2001 From: Steven <61625851+justusbunsi@users.noreply.github.com> Date: Sun, 3 Apr 2022 18:22:01 +0200 Subject: [PATCH 3/4] Fix links to packages documentation (#19315) --- options/locale/locale_en-US.ini | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index f6b9d47008..40d4c1c940 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -3032,39 +3032,39 @@ dependency.id = ID dependency.version = Version composer.registry = Setup this registry in your ~/.composer/config.json file: composer.install = To install the package using Composer, run the following command: -composer.documentation = For more information on the Composer registry, see the documentation. +composer.documentation = For more information on the Composer registry, see the documentation. composer.dependencies = Dependencies composer.dependencies.development = Development Dependencies conan.details.repository = Repository conan.registry = Setup this registry from the command line: conan.install = To install the package using Conan, run the following command: -conan.documentation = For more information on the Conan registry, see the documentation. +conan.documentation = For more information on the Conan registry, see the documentation. container.details.type = Image Type container.details.platform = Platform container.details.repository_site = Repository Site container.details.documentation_site = Documentation Site container.pull = Pull the image from the command line: -container.documentation = For more information on the Container registry, see the documentation. +container.documentation = For more information on the Container registry, see the documentation. container.multi_arch = OS / Arch container.layers = Image Layers container.labels = Labels container.labels.key = Key container.labels.value = Value generic.download = Download package from the command line: -generic.documentation = For more information on the generic registry, see the documentation. +generic.documentation = For more information on the generic registry, see the documentation. maven.registry = Setup this registry in your project pom.xml file: maven.install = To use the package include the following in the dependencies block in the pom.xml file: maven.install2 = Run via command line: maven.download = To download the dependency, run via command line: -maven.documentation = For more information on the Maven registry, see the documentation. +maven.documentation = For more information on the Maven registry, see the documentation. nuget.registry = Setup this registry from the command line: nuget.install = To install the package using NuGet, run the following command: -nuget.documentation = For more information on the NuGet registry, see the documentation. +nuget.documentation = For more information on the NuGet registry, see the documentation. nuget.dependency.framework = Target Framework npm.registry = Setup this registry in your project .npmrc file: npm.install = To install the package using npm, run the following command: npm.install2 = or add it to the package.json file: -npm.documentation = For more information on the npm registry, see the documentation. +npm.documentation = For more information on the npm registry, see the documentation. npm.dependencies = Dependencies npm.dependencies.development = Development Dependencies npm.dependencies.peer = Peer Dependencies @@ -3072,14 +3072,14 @@ npm.dependencies.optional = Optional Dependencies npm.details.tag = Tag pypi.requires = Requires Python pypi.install = To install the package using pip, run the following command: -pypi.documentation = For more information on the PyPI registry, see the documentation. +pypi.documentation = For more information on the PyPI registry, see the documentation. rubygems.install = To install the package using gem, run the following command: rubygems.install2 = or add it to the Gemfile: rubygems.dependencies.runtime = Runtime Dependencies rubygems.dependencies.development = Development Dependencies rubygems.required.ruby = Requires Ruby version rubygems.required.rubygems = Requires RubyGem version -rubygems.documentation = For more information on the RubyGems registry, see the documentation. +rubygems.documentation = For more information on the RubyGems registry, see the documentation. settings.link = Link this package to a repository settings.link.description = If you link a package with a repository, the package is listed in the repository's package list. settings.link.select = Select Repository From 256204befaba203b9cf081a5d479a9932ad4b171 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Mon, 4 Apr 2022 00:17:51 +0000 Subject: [PATCH 4/4] [skip ci] Updated translations via Crowdin --- options/locale/locale_pt-BR.ini | 388 +++++++++++++++++++++++++++++++- options/locale/locale_pt-PT.ini | 89 ++++++++ options/locale/locale_zh-CN.ini | 58 ++++- 3 files changed, 530 insertions(+), 5 deletions(-) diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index 553c617ad6..eeb141850c 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -34,6 +34,20 @@ twofa=Autenticação de dois fatores twofa_scratch=Código de backup da autenticação de dois fatores passcode=Senha +webauthn_insert_key=Insira sua chave de segurança +webauthn_sign_in=Pressione o botão na sua chave de segurança. Se a sua chave de segurança não tiver um botão, insira-a novamente. +webauthn_press_button=Por favor, pressione o botão na sua chave de segurança… +webauthn_use_twofa=Use um código de duas etapas do seu telefone +webauthn_error=Não foi possível ler sua chave de segurança. +webauthn_unsupported_browser=Seu navegador não oferece suporte ao WebAuthn. +webauthn_error_unknown=Ocorreu um erro desconhecido. Por favor, tente novamente. +webauthn_error_insecure=WebAuthn suporta apenas conexões seguras. Para testar via HTTP, você pode usar a origem "localhost" ou "127.0.0.1" +webauthn_error_unable_to_process=O servidor não pôde processar sua solicitação. +webauthn_error_duplicated=A chave de segurança não é permitida para esta solicitação. Por favor, certifique-se que a chave já não está registrada. +webauthn_error_empty=Você deve definir um nome para esta chave. +webauthn_error_timeout=Tempo limite atingido antes de sua chave poder ser lida. Por favor, recarregue esta página e tente novamente. +webauthn_u2f_deprecated=A chave: '%s' autentica utilizando o processo U2F descontinuado. Você deve registrar novamente esta chave e remover o registro antigo. +webauthn_reload=Recarregar repository=Repositório organization=Organização @@ -92,7 +106,12 @@ error404=A página que você está tentando acessar não existe never=Nunca [error] +occurred=Ocorreu um erro +report_message=Se você tem certeza de que é um bug do Gitea, procure por issues no GitHub ou abra uma nova issue, se necessário. missing_csrf=Pedido inválido: não tem token CSRF presente +invalid_csrf=Requisição Inválida: token CSRF inválido +not_found=Não foi possível encontrar o destino. +network_error=Erro de rede [startpage] app_desc=Um serviço de hospedagem Git amigável @@ -109,6 +128,7 @@ license_desc=Está tudo no documentação cuidadosamente antes de alterar qualquer coisa nesta página. +require_db_desc=Gitea requer MySQL, PostgreSQL, MSSQL, SQLite3 ou TiDB (protocolo MySQL). db_title=Configurações de banco de dados db_type=Tipo de banco de dados host=Servidor @@ -122,6 +142,8 @@ ssl_mode=SSL charset=Charset path=Caminho sqlite_helper=Caminho do arquivo do banco de dados SQLite3.
Informe um caminho absoluto se você executar o Gitea como um serviço. +reinstall_error=Você está tentando instalar em um banco de dados existente do Gitea +reinstall_confirm_message=Reinstalar com um banco de dados Gitea existente pode causar vários problemas. Na maioria dos casos, você deve usar seu "app.ini" existente para executar o Gitea. Se você sabe o que está fazendo, confirme o seguinte: err_empty_db_path=O caminho do banco de dados SQLite3 não pode ser em branco. no_admin_and_disable_registration=Você não pode desabilitar o auto-cadastro do usuário sem criar uma conta de administrador. err_empty_admin_password=A senha do administrador não pode ser em branco. @@ -187,8 +209,12 @@ install_btn_confirm=Instalar Gitea test_git_failed=Falha ao testar o comando 'git': %v sqlite3_not_available=Esta versão do Gitea não suporta SQLite3. Por favor faça o download da versão binária oficial em %s (não utilize a versão 'gobuild'). invalid_db_setting=Configuração de banco de dados está inválida: %v +invalid_db_table=A tabela '%s' do banco de dados é inválida: %v invalid_repo_path=A raiz do repositório está inválida: %v +invalid_app_data_path=O caminho dos dados do aplicativo é inválido: %v run_user_not_match=O nome de usuário 'Executar como' não é o nome de usuário atual: %s -> %s +internal_token_failed=Falha ao gerar o token interno: %v +secret_key_failed=Falha ao gerar a chave secreta: %v save_config_failed=Falha ao salvar a configuração: %v invalid_admin_setting=Configuração da conta de administrador está inválida: %v install_success=Bem-vindo! Obrigado por escolher Gitea. Divertir-se. E, tome cuidado! @@ -237,6 +263,7 @@ organizations=Organizações search=Pesquisar code=Código search.fuzzy=Similar +code_search_unavailable=A pesquisa por código não está disponível no momento. Entre em contato com o administrador do site. repo_no_results=Nenhum repositório correspondente foi encontrado. user_no_results=Nenhum usuário correspondente foi encontrado. org_no_results=Nenhuma organização correspondente foi encontrada. @@ -250,6 +277,7 @@ register_helper_msg=Já tem uma conta? Acesse agora! social_register_helper_msg=Já tem uma conta? Vincule agora! disable_register_prompt=Cadastro está desabilitado. Entre em contato com o administrador do site. disable_register_mail=E-mail de confirmação de cadastro está desabilitado. +manual_activation_only=Entre em contato com o administrador do site para concluir a ativação. remember_me=Lembrar deste Dispositivo forgot_password_title=Esqueci minha senha forgot_password=Esqueceu sua senha? @@ -288,12 +316,17 @@ oauth_signup_submit=Completar conta oauth_signin_tab=Vincular à uma conta existente oauth_signin_title=Acesse com uma conta vinculada oauth_signin_submit=Vincular conta +oauth.signin.error=Ocorreu um erro durante o processamento do pedido de autorização. Se este erro persistir, contate o administrador. +oauth.signin.error.access_denied=O pedido de autorização foi negado. +oauth.signin.error.temporarily_unavailable=A autorização falhou porque o servidor de autenticação está temporariamente indisponível. Por favor, tente novamente mais tarde. openid_connect_submit=Conectar openid_connect_title=Conectar à uma conta existente openid_connect_desc=O URI do OpenID escolhido é desconhecido. Associe-o com uma nova conta aqui. openid_register_title=Criar uma nova conta openid_register_desc=O URI do OpenID escolhido é desconhecido. Associe-o com uma nova conta aqui. openid_signin_desc=Digite a URI do seu OpenID. Por exemplo: https://anne.me, bob.openid.org.cn ou gnusocial.net/carry. +disable_forgot_password_mail=A recuperação de conta está desativada porque nenhum e-mail está configurado. Por favor, contate o administrador do site. +disable_forgot_password_mail_admin=A recuperação de conta só está disponível quando o e-mail está configurado. Por favor, configure o e-mail para permitir a recuperação de conta. email_domain_blacklisted=Você não pode se cadastrar com seu endereço de e-mail. authorize_application=Autorizar aplicativo authorize_redirect_notice=Você será redirecionado para %s se você autorizar este aplicativo. @@ -307,27 +340,63 @@ password_pwned=A senha escolhida está em uma lista de defina sua senha primeiro. reset_password=Recuperar sua conta +reset_password.title=%s, você pediu para recuperar a sua conta +reset_password.text=Por favor clique no link a seguir para recuperar sua conta em %s: register_success=Cadastro bem-sucedido +issue_assigned.pull=@%[1]atribuiu a você o pull request %[2]s no repositório %[3]s. +issue_assigned.issue=@%[1]s atribuiu a você a issue %[2]s no repositório %[3]s. +issue.x_mentioned_you=@%s mencionou você: +issue.action.force_push=%[1]s forçou o push de %[2]s de %[3]s para %[4]s. +issue.action.push_1=@%[1]s fez o push de %[3]d commit para %[2]s +issue.action.push_n=@%[1]s fez o push de %[3]d commits para %[2]s +issue.action.close=@%[1]s fechou #%[2]d. +issue.action.reopen=@%[1]s reabriu #%[2]d. +issue.action.approve=@%[1]s aprovou este pull request. +issue.action.reject=@%[1]s solicitou alterações neste pull request. +issue.action.review=@%[1]s fez um comentário neste pull request. +issue.action.review_dismissed=@%[1]s descartou a última revisão de %[2]s para este pull request. +issue.action.ready_for_review=@%[1]s marcou este pull request como pronto para revisão. +issue.action.new=@%[1]s criou #%[2]d. +issue.in_tree_path=Em %s: release.new.subject=%s em %s lançado release.new.text=@%[1]s lançou a versão %[2]s em %[3]s +release.title=Título: %s +release.note=Nota: +release.downloads=Downloads: +release.download.zip=Código fonte (ZIP) +release.download.targz=Código fonte (TAR.GZ) repo.transfer.subject_to=%s gostaria de transferir "%s" para %s repo.transfer.subject_to_you=%s gostaria de transferir "%s" para você repo.transfer.to_you=você +repo.transfer.body=Para o aceitar ou rejeitar visite %s, ou simplesmente o ignore. repo.collaborator.added.subject=%s adicionou você a %s +repo.collaborator.added.text=Você foi adicionado como um colaborador do repositório: [modal] yes=Sim @@ -368,6 +437,7 @@ email_error=` não é um endereço de e-mail válido.` url_error=`não é uma URL válida.` include_error=` deve conter '%s'.` glob_pattern_error=` padrão glob é inválido: %s.` +regex_pattern_error=` o regex é inválido: %s.` unknown_error=Erro desconhecido: captcha_incorrect=O código CAPTCHA está incorreto. password_not_match=As senhas não coincidem. @@ -411,7 +481,9 @@ auth_failed=Autenticação falhou: %v still_own_repo=Sua conta possui um ou mais repositórios; você deve excluí-los ou transferi-los primeiro. still_has_org=Sua conta é um membro de uma ou mais organizações; você deve deixá-las primeiro. +still_own_packages=Sua conta possui um ou mais pacotes; você deve excluí-los primeiro. org_still_own_repo=Esta organização ainda possui repositórios; você deve excluí-los ou transferi-los primeiro. +org_still_own_packages=Esta organização ainda possui pacotes; você deve excluí-los primeiro. target_branch_not_exist=O branch de destino não existe. @@ -452,6 +524,7 @@ twofa=Autenticação de dois fatores account_link=Contas vinculadas organization=Organizações uid=Uid +webauthn=Chaves de segurança public_profile=Perfil público biography_placeholder=Nos conte um pouco sobre você @@ -473,6 +546,16 @@ continue=Continuar cancel=Cancelar language=Idioma ui=Tema +hidden_comment_types=Tipos de comentários ocultos +comment_type_group_reference=Referência +comment_type_group_label=Rótulo +comment_type_group_title=Título +comment_type_group_branch=Branch +comment_type_group_deadline=Prazo final +comment_type_group_review_request=Revisar solicitação +comment_type_group_pull_request_push=Commits adicionados +comment_type_group_project=Projeto +saved_successfully=Suas configurações foram salvas com sucesso. privacy=Privacidade keep_activity_private=Ocultar a atividade da página de perfil keep_activity_private_popup=Torna a atividade visível somente para você e os administradores @@ -547,12 +630,30 @@ ssh_key_been_used=Esta chave SSH já foi adicionada ao servidor. ssh_key_name_used=Uma chave SSH com o mesmo nome já existe em sua conta. ssh_principal_been_used=Este nome principal já foi adicionada ao servidor. gpg_key_id_used=Uma chave GPG pública com a mesma ID já existe. +gpg_no_key_email_found=Esta chave GPG não corresponde a nenhum endereço de e-mail ativado associado à sua conta. Ela ainda pode ser adicionada se você assinar o token fornecido. +gpg_key_matched_identities=Identidades correspondentes: +gpg_key_matched_identities_long=As identidades incorporadas nesta chave coincidem com os seguintes endereços de email ativados para este usuário. Os commits correspondentes a estes endereços de e-mail podem ser verificados com esta chave. +gpg_key_verified=Chave validada +gpg_key_verified_long=A chave foi validada com um token e pode ser usada para verificar commits correspondentes a qualquer endereço de e-mail ativado para esse usuário, além de quaisquer identidades correspondentes para essa chave. +gpg_key_verify=Validar gpg_invalid_token_signature=A chave GPG fornecida, a assinatura ou o token não correspondem ou o token está desatualizado. gpg_token_required=Você tem que fornecer uma assinatura para o token abaixo gpg_token=Token gpg_token_help=Você pode gerar uma assinatura usando: gpg_token_code=echo "%s" | gpg -a --default-key %s --detach-sig +gpg_token_signature=Assinatura GPG blindada key_signature_gpg_placeholder=Começa com '-----BEGIN PGP SIGNATURE-----' +verify_gpg_key_success=A chave GPG '%s' foi validada. +ssh_key_verified=Chave validada +ssh_key_verified_long=A chave foi validada com um token e pode ser usada para validar commits que correspondam a qualquer dos endereços de e-mail ativados deste usuário. +ssh_key_verify=Validar +ssh_token_required=Você tem que fornecer uma assinatura para o token abaixo +ssh_token=Token +ssh_token_help=Você pode gerar uma assinatura usando: +ssh_token_code=echo -n "%s" | ssh-keygen -Y sign -n gitea -f /caminho_para_a_sua_chave_pública +ssh_token_signature=Assinatura SSH blindada +key_signature_ssh_placeholder=Começa com '-----BEGIN SSH SIGNATURE-----' +verify_ssh_key_success=A chave SSH '%s' foi validada. subkeys=Subchaves key_id=ID da chave key_name=Nome da Chave @@ -653,6 +754,10 @@ passcode_invalid=Esse código de acesso é inválido. Tente novamente. twofa_enrolled=Sua conta foi inscrita na autenticação de dois fatores. Armazene seu token de backup (%s) em um local seguro, pois ele é exibido apenas uma vez! twofa_failed_get_secret=Falha ao obter o segredo. +webauthn_desc=Chaves de segurança são dispositivos de hardware que contém chaves de criptografia. Elas podem ser usadas para autenticação de dois fatores. A chave de segurança deve suportar o padrão WebAuthnn Authenticator. +webauthn_register_key=Adicionar chave de segurança +webauthn_delete_key=Remover chave de segurança +webauthn_delete_key_desc=Se você remover uma chave de segurança, não poderá mais entrar com ela. Continuar? manage_account_links=Gerenciar contas vinculadas manage_account_links_desc=Estas contas externas estão vinculadas a sua conta de Gitea. @@ -703,6 +808,8 @@ visibility_fork_helper=(Esta alteração irá afetar todos os forks.) clone_helper=Precisa de ajuda com o clone? Visite a Ajuda. fork_repo=Fork do repositório fork_from=Fork de +already_forked=Você já fez o fork de %s +fork_to_different_account=Faça um fork para uma conta diferente fork_visibility_helper=A visibilidade do fork de um repositório não pode ser alterada. use_template=Usar este modelo clone_in_vsc=Clonar no VS Code @@ -730,7 +837,7 @@ trust_model_helper_collaborator=Colaborador: Confiar em assinaturas de colaborad trust_model_helper_committer=Committer: Confiar em assinaturas que correspondem aos committers trust_model_helper_default=Padrão: Usar o modelo de confiança padrão para esta instalação create_repo=Criar repositório -default_branch=Branch padrão +default_branch=Branch Padrão default_branch_helper=O branch padrão é o branch base para pull requests e commits de código. mirror_prune=Varrer mirror_prune_desc=Remover referências obsoletas de controle remoto @@ -821,6 +928,7 @@ migrate_items_releases=Versões migrate_repo=Migrar repositório migrate.clone_address=Migrar / Clonar de URL migrate.clone_address_desc=URL HTTP (S) ou Git 'clone' de um repositório existente +migrate.github_token_desc=Você pode colocar aqui um ou mais tokens separados por vírgulas para tornar a migração mais rápida para compensar o limite de taxa de API do GitHub. AVISO: abusar desse recurso pode violar a política do provedor de serviços e levar ao bloqueio da conta. migrate.clone_local_path=ou um caminho de servidor local migrate.permission_denied=Você não pode importar repositórios locais. migrate.permission_denied_blocked=Você não pode importar dos hosts não permitidos, por favor peça ao administrador para verificar as configurações ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS. @@ -835,11 +943,13 @@ migrate.migrating=Migrando a partir de %s ... migrate.migrating_failed=Migração a partir de %s falhou. migrate.migrating_failed.error=Erro: %s migrate.migrating_failed_no_addr=A migração falhou. +migrate.github.description=Migrar dados de github.com ou de outras instâncias do GitHub. migrate.git.description=Migrar um repositório somente de qualquer serviço Git. migrate.gitlab.description=Migrar dados de gitlab.com ou de outras instâncias do GitLab. migrate.gitea.description=Migrar dados de gitea.com ou de outras instâncias do Gitea. migrate.gogs.description=Migrar dados de notabug.org ou de outras instâncias do Gogs. migrate.onedev.description=Migrar dados de code.onedev.io ou de outras instâncias do OneDev. +migrate.codebase.description=Migrar dados de codebasehq.com. migrate.gitbucket.description=Migrar dados de instâncias do GitBucket. migrate.migrating_git=Migrando dados Git migrate.migrating_topics=Migrando tópicos @@ -869,6 +979,7 @@ clone_this_repo=Clonar este repositório create_new_repo_command=Criando um novo repositório por linha de comando push_exist_repo=Realizando push para um repositório existente por linha de comando empty_message=Este repositório está vazio. +broken_message=Os dados Git subjacentes a este repositório não podem ser lidos. Entre em contato com o administrador desta instância ou exclua este repositório. code=Código code.desc=Acesso a código-fonte, arquivos, commits e branches. @@ -883,6 +994,7 @@ issues=Issues pulls=Pull requests project_board=Projetos labels=Etiquetas +org_labels_desc=Rótulos de nível de organização que podem ser usados em todos os repositórios sob esta organização org_labels_desc_manage=gerenciar milestones=Marcos @@ -890,6 +1002,7 @@ commits=Commits commit=Commit release=Versão releases=Versões +tag=Tag released_this=lançou isto file.title=%s em %s file_raw=Original @@ -899,7 +1012,16 @@ file_view_rendered=Ver Renderizado file_view_raw=Ver original file_permalink=Link permanente file_too_large=O arquivo é muito grande para ser mostrado. +bidi_bad_header=`Este arquivo contém caracteres Unicode Bidirecionais inesperados!` +bidi_bad_description=`Este arquivo contém caracteres Unicode bidirecionais inesperados que podem ser processados de forma diferente do que aparece abaixo. Se seu caso de uso for intencional e legítimo, você pode ignorar com segurança esse aviso. Use o botão Escapar para revelar caracteres ocultos.` +bidi_bad_description_escaped=`Este arquivo contém caracteres Unicode Bidirecionais inesperados. Caracteres unicode ocultos estão escapados abaixo. Use o botão Desescapar para mostrar como eles são mostrados.` +unicode_header=`Este arquivo contém caracteres Unicode ocultos!` +unicode_description=`Este arquivo contém caracteres Unicode ocultos que podem ser processados de forma diferente do que aparece abaixo. Se seu caso de uso for intencional e legítimo, você pode ignorar com segurança esse aviso. Use o botão Escapar para revelar caracteres ocultos.` +unicode_description_escaped=`Este arquivo contém caracteres Unicode ocultos. Caracteres unicode ocultos estão escapados abaixo. Utilize o botão Desescapar para mostrar como eles são mostrados.` +line_unicode=`Esta linha possui caracteres unicode ocultos` +escape_control_characters=Escapar +unescape_control_characters=Desescapar video_not_supported_in_browser=Seu navegador não suporta a tag 'video' do HTML5. audio_not_supported_in_browser=Seu navegador não suporta a tag 'audio' do HTML5. stored_lfs=Armazenado com Git LFS @@ -938,6 +1060,10 @@ editor.add_tmpl=Adicionar '' editor.add=Adicionar '%s' editor.update=Atualizar '%s' editor.delete=Excluir '%s' +editor.patch=Aplicar Correção +editor.patching=Corrigindo: +editor.fail_to_apply_patch=Não foi possível aplicar a correção '%s' +editor.new_patch=Nova correção editor.commit_message_desc=Adicione uma descrição detalhada (opcional)... editor.signoff_desc=Adicione um assinado-por-committer no final do log do commit. editor.commit_directly_to_this_branch=Commit diretamente no branch %s. @@ -962,6 +1088,8 @@ editor.commit_empty_file_text=O arquivo que você está prestes fazer commit est editor.no_changes_to_show=Nenhuma alteração a mostrar. editor.fail_to_update_file=Falha ao atualizar/criar arquivo '%s'. editor.fail_to_update_file_summary=Mensagem de erro: +editor.push_rejected_no_message=A alteração foi rejeitada pelo servidor sem uma mensagem. Por favor, verifique os Hooks Git. +editor.push_rejected=A alteração foi rejeitada pelo servidor. Por favor, verifique os Hooks Git. editor.push_rejected_summary=Mensagem completa de rejeição: editor.add_subdir=Adicionar um subdiretório... editor.unable_to_upload_files=Houve erro ao fazer upload de arquivos para '%s': %v @@ -971,10 +1099,13 @@ editor.cannot_commit_to_protected_branch=Branch '%s' está protegido para commit editor.no_commit_to_branch=Não foi possível fazer commit diretamente no branch porque: editor.user_no_push_to_branch=O usuário não pode fazer push no branch editor.require_signed_commit=Branch requer um commit assinado +editor.cherry_pick=Cherry-pick %s para: +editor.revert=Reverter %s para: commits.desc=Veja o histórico de alterações do código de fonte. commits.commits=Commits commits.no_commits=Nenhum commit em comum. '%s' e '%s' tem histórias completamente diferentes. +commits.nothing_to_compare=Estes branches são iguais. commits.search=Pesquisar commits... commits.search.tooltip=Você pode prefixar palavras-chave com "author:", "committer:", "after:", ou "before:", por exemplo: "revert author:Alice before:2019-04-01". commits.find=Pesquisar @@ -988,8 +1119,16 @@ commits.signed_by=Acessado por commits.signed_by_untrusted_user=Assinado por usuário não confiável commits.signed_by_untrusted_user_unmatched=Assinado por usuário não confiável que não corresponde ao autor da submissão commits.gpg_key_id=ID da chave GPG +commits.ssh_key_fingerprint=Impressão Digital da Chave SSH +commit.actions=Ações +commit.revert=Reverter +commit.revert-header=Reverter: %s +commit.revert-content=Selecione a branch para reverter para: +commit.cherry-pick=Cherry-pick +commit.cherry-pick-header=Cherry-pick: %s +ext_issues=Acesso a Issues Externos ext_issues.desc=Link para o issue tracker externo. projects=Projetos @@ -1026,11 +1165,13 @@ projects.board.deletion_desc=Excluir um quadro de projeto move todas as issues r projects.board.color=Cor projects.open=Abrir projects.close=Fechar +projects.board.assigned_to=Atribuído a issues.desc=Organize relatórios de bugs, tarefas e marcos. issues.filter_assignees=Filtrar Atribuição issues.filter_milestones=Filtrar Marco issues.filter_projects=Filtrar Projeto +issues.filter_labels=Filtrar Rótulo issues.filter_reviewers=Filtrar Revisor issues.new=Nova issue issues.new.title_empty=Título não pode ser em branco @@ -1071,6 +1212,11 @@ issues.label_templates.info=Ainda não existem etiquetas. Crie uma etiqueta em ' issues.label_templates.helper=Selecione um conjunto de etiquetas issues.label_templates.use=Use o conjunto de etiquetas issues.label_templates.fail_to_load_file=Houve erro ao carregar arquivo de template '%s': %v +issues.add_label=adicionou o rótulo %s %s +issues.add_labels=adicionou os rótulos %s %s +issues.remove_label=removeu o rótulo %s %s +issues.remove_labels=removeu os rótulos %s %s +issues.add_remove_labels=adicionou o(s) rótulo(s) %s e removeu %s %s issues.add_milestone_at=`adicionou esta issue para o marco %s %s` issues.add_project_at=`adicionado ao projeto %s %s` issues.change_milestone_at=`modificou o marco de %s para %s %s` @@ -1116,6 +1262,7 @@ issues.filter_sort.moststars=Mais estrelas issues.filter_sort.feweststars=Menos estrelas issues.filter_sort.mostforks=Mais forks issues.filter_sort.fewestforks=Menos forks +issues.keyword_search_unavailable=A pesquisa por palavra-chave não está disponível no momento. Entre em contato com o administrador do site. issues.action_open=Abrir issues.action_close=Fechar issues.action_label=Etiqueta @@ -1133,6 +1280,7 @@ issues.commented_at=`comentou %s` issues.delete_comment_confirm=Tem certeza que deseja excluir este comentário? issues.context.copy_link=Copiar link issues.context.quote_reply=Citar resposta +issues.context.reference_issue=Referência em uma nova issue issues.context.edit=Editar issues.context.delete=Excluir issues.no_content=Ainda não há conteúdo. @@ -1152,7 +1300,12 @@ issues.ref_from=`de %[1]s` issues.poster=Autor issues.collaborator=Colaborador issues.owner=Proprietário +issues.re_request_review=Re-solicitar revisão +issues.is_stale=Houve alterações nessa PR desde essa revisão +issues.remove_request_review=Remover solicitação de revisão issues.remove_request_review_block=Não é possível remover a solicitação de revisão +issues.dismiss_review=Descartar revisão +issues.dismiss_review_warning=Tem certeza de que deseja descartar esta revisão? issues.sign_in_require_desc=Acesse para participar desta conversação. issues.edit=Editar issues.cancel=Cancelar @@ -1196,13 +1349,20 @@ issues.lock.reason=Motivo do bloqueio issues.lock.title=Conversação bloqueada para esta issue. issues.unlock.title=Conversação desbloqueada para esta issue. issues.comment_on_locked=Você não pode comentar em uma issue bloqueada. +issues.delete=Apagar +issues.delete.title=Apagar esta issue? +issues.delete.text=Você realmente deseja excluir esta issue? (Isto irá remover permanentemente todo o conteúdo. Considere fechá-la em vez disso, se você pretende mantê-la arquivado) issues.tracker=Contador de tempo +issues.start_tracking_short=Iniciar Cronômetro issues.start_tracking=Iniciar contador de tempo issues.start_tracking_history=`começou a trabalhar %s` issues.tracker_auto_close=Contador de tempo será parado automaticamente quando esta issue for fechada +issues.stop_tracking=Parar cronômetro issues.stop_tracking_history=`parou de trabalhar %s` +issues.cancel_tracking=Descartar issues.cancel_tracking_history=`cancelou contador de tempo %s` issues.add_time=Adicionar tempo manualmente +issues.del_time=Apagar este registro de tempo issues.add_time_short=Adicionar tempo issues.add_time_cancel=Cancelar issues.add_time_history=`adicionou tempo gasto %s` @@ -1216,6 +1376,9 @@ issues.due_date=Data limite issues.invalid_due_date_format=Formato da data limite inválido, deve ser 'dd/mm/aaaa'. issues.error_modifying_due_date=Falha ao modificar a data limite. issues.error_removing_due_date=Falha ao remover a data limite. +issues.push_commit_1=adicionou %d commit %s +issues.push_commits_n=adicionou %d commits %s +issues.force_push_codes=`forçou o push %[1]s de %[2]s para %[4]s %[6]s` issues.due_date_form=dd/mm/aaaa issues.due_date_form_add=Adicionar data limite issues.due_date_form_edit=Editar @@ -1228,10 +1391,14 @@ issues.due_date_remove=removeu a data limite %s %s issues.due_date_overdue=Em atraso issues.due_date_invalid=A data limite é inválida ou está fora do intervalo. Por favor, use o formato 'dd/mm/aaaa'. issues.dependency.title=Dependências +issues.dependency.issue_no_dependencies=Nenhuma dependência definida. +issues.dependency.pr_no_dependencies=Nenhuma dependência definida. issues.dependency.add=Adicione… issues.dependency.cancel=Cancelar issues.dependency.remove=Remover issues.dependency.remove_info=Remover esta dependência +issues.dependency.added_dependency=`adicionou uma nova dependência %s` +issues.dependency.removed_dependency=`removeu uma dependência %s` issues.dependency.issue_close_blocks=Esta issue bloqueia o fechamento das seguintes issues issues.dependency.pr_close_blocks=Este pull request bloqueia o fechamento das seguintes issues issues.dependency.issue_close_blocked=Você precisa fechar todas as issues que bloqueiam esta issue antes de poder fechá-la. @@ -1252,14 +1419,23 @@ issues.review.self.approval=Você não pode aprovar o seu próprio pull request. issues.review.self.rejection=Você não pode solicitar alterações em seu próprio pull request. issues.review.approve=aprovou estas alterações %s issues.review.comment=revisou %s +issues.review.dismissed=rejeitou a revisão de %s %s +issues.review.dismissed_label=Rejeitada +issues.review.left_comment=deixou um comentário issues.review.content.empty=Você precisa deixar um comentário indicando as alterações solicitadas. issues.review.reject=alterações solicitadas %s issues.review.pending=Pendente issues.review.review=Revisão issues.review.reviewers=Revisores +issues.review.outdated=Desatualizado issues.review.show_outdated=Mostrar desatualizado issues.review.hide_outdated=Ocultar desatualizado +issues.review.show_resolved=Mostrar resolvidas +issues.review.hide_resolved=Ocultar resolvidas +issues.review.resolve_conversation=Resolver conversa +issues.review.resolved_by=marcou esta conversa como resolvida issues.assignee.error=Nem todos os responsáveis foram adicionados devido a um erro inesperado. +issues.reference_issue.body=Conteúdo issues.content_history.deleted=excluído issues.content_history.edited=editado issues.content_history.created=criado @@ -1272,6 +1448,7 @@ compare.compare_head=comparar pulls.desc=Habilitar pull requests e revisões de código. pulls.new=Novo pull request +pulls.view=Ver Pull Request pulls.compare_changes=Novo pull request pulls.compare_changes_desc=Selecione a branch de destino (push) e a branch de origem (pull) para o merge. pulls.compare_base=merge em @@ -1281,6 +1458,7 @@ pulls.switch_head_and_base=Trocar cabeça e base pulls.filter_branch=Filtrar branch pulls.no_results=Nada encontrado. pulls.nothing_to_compare=Estes branches são iguais. Não há nenhuma necessidade para criar um pull request. +pulls.nothing_to_compare_and_allow_empty_pr=Estes branches são iguais. Este PR ficará vazio. pulls.has_pull_request=`Um pull request entre esses branches já existe: %[2]s#%[3]d` pulls.create=Criar pull request pulls.title_desc=quer aplicar o merge de %[1]d commits de %[2]s em %[3]s @@ -1405,6 +1583,7 @@ signing.wont_sign.headsigned=O merge não será assinado porque o commit princip signing.wont_sign.commitssigned=O merge não será assinado pois todos os commits associados não foram assinados signing.wont_sign.approved=O merge não será assinado pois o PR não foi aprovado +ext_wiki=Acesso a Wiki Externo ext_wiki.desc=Link para uma wiki externa. wiki=Wiki @@ -1429,6 +1608,7 @@ wiki.page_already_exists=Uma página de wiki com o mesmo nome já existe. wiki.reserved_page=O nome da página wiki '%s' está reservada. wiki.pages=Páginas wiki.last_updated=Última atualização %s +wiki.page_name_desc=Digite um nome para esta página Wiki. Alguns nomes especiais são: 'Home', '_Sidebar' e '_Footer'. activity=Atividade activity.period.filter_label=Período: @@ -1460,6 +1640,7 @@ activity.closed_issues_count_1=Issue fechada activity.closed_issues_count_n=Issues fechadas activity.title.issues_1=+%d Issue activity.title.issues_n=+%d Issues +activity.title.issues_closed_from=%s fechada por %s activity.title.issues_created_by=%s criada por %s activity.closed_issue_label=Fechado activity.new_issues_count_1=Nova issue @@ -1499,6 +1680,8 @@ search=Pesquisar search.search_repo=Pesquisar no repositório... search.fuzzy=Aproximada search.results=Resultados da pesquisa para "%s" em %s +search.code_no_results=Nenhum código-fonte correspondente ao seu termo de pesquisa foi encontrado. +search.code_search_unavailable=A pesquisa por código não está disponível no momento. Entre em contato com o administrador do site. settings=Configurações settings.desc=Opções é onde você pode gerenciar as configurações para o repositório @@ -1513,7 +1696,12 @@ settings.hooks=Webhooks settings.githooks=Hooks do Git settings.basic_settings=Configurações básicas settings.mirror_settings=Opções de espelhamento +settings.mirror_settings.docs=Configure seu projeto para fazer push e/ou pull de alterações automaticamente para outro repositório. Branches, tags e commits serão sincronizados automaticamente. Como espelhar repositórios? settings.mirror_settings.mirrored_repository=Repositório espelhado +settings.mirror_settings.direction=Sentido +settings.mirror_settings.direction.pull=Pull +settings.mirror_settings.direction.push=Push +settings.mirror_settings.last_update=Última atualização settings.sync_mirror=Sincronizar agora settings.mirror_sync_in_progress=Sincronização do espelhamento está em andamento. Verifique novamente em um minuto. settings.email_notifications.enable=Habilitar notificações de e-mail @@ -1522,6 +1710,7 @@ settings.email_notifications.disable=Desabilitar notificações de e-mail settings.email_notifications.submit=Atualizar preferências de e-mail settings.site=Site settings.update_settings=Atualizar configurações +settings.branches.update_default_branch=Atualizar Branch Padrão settings.advanced_settings=Configurações avançadas settings.wiki_desc=Habilitar a wiki do repositório settings.use_internal_wiki=Usar a wiki nativa @@ -1549,8 +1738,16 @@ settings.pulls.allow_merge_commits=Habilitar commit no merge settings.pulls.allow_rebase_merge=Habilitar Rebasing em commits via merge settings.pulls.allow_rebase_merge_commit=Habilitar Rebasing com commits explícitos no merge (--no-ff) settings.pulls.allow_squash_commits=Habilitar Squashing em commits via merge +settings.packages_desc=Habilitar Registro de Pacotes de Repositório +settings.projects_desc=Habilitar Projetos do Repositório settings.admin_settings=Configurações do administrador settings.admin_enable_health_check=Habilitar verificações de integridade (git fsck) no repositório +settings.admin_code_indexer=Indexador de código +settings.admin_stats_indexer=Indexador de Estatísticas do Código +settings.admin_indexer_commit_sha=Último SHA indexado +settings.admin_indexer_unindexed=Não indexado +settings.reindex_button=Adicionar à fila de reindexação +settings.reindex_requested=Reindexação requisitada settings.admin_enable_close_issues_via_commit_in_any_branch=Fechar issue via commit em um branch não padrão settings.danger_zone=Zona de perigo settings.new_owner_has_same_repo=O novo proprietário já tem um repositório com o mesmo nome. Por favor, escolha outro nome. @@ -1559,13 +1756,32 @@ settings.convert_desc=Você pode converter este espelhamento em um repositório settings.convert_notices_1=Esta operação vai converter este espelhamento em um repositório tradicional. Esta ação não pode ser desfeita. settings.convert_confirm=Converter o repositório settings.convert_succeed=O espelhamento foi convertido em um repositório tradicional. +settings.convert_fork=Converter Para Um Repositório Normal +settings.convert_fork_desc=Você pode converter este fork em um repositório normal. Esta ação não pode ser desfeita. +settings.convert_fork_notices_1=Esta operação irá converter o fork em um repositório normal e não pode ser desfeita. +settings.convert_fork_confirm=Converter repositório +settings.convert_fork_succeed=O fork foi convertido em um repositório normal. settings.transfer=Transferir propriedade +settings.transfer.rejected=A transferência do repositório foi rejeitada. +settings.transfer.success=A transferência do repositório foi bem sucedida. +settings.transfer_abort=Cancelar transferência +settings.transfer_abort_invalid=Não é possível cancelar uma transferência de repositório não existente. +settings.transfer_abort_success=A transferência de repositório para %s foi cancelada com sucesso. settings.transfer_desc=Transferir este repositório para outro usuário ou para uma organização onde você tem direitos de administrador. settings.transfer_form_title=Digite o nome do repositório para confirmar: +settings.transfer_in_progress=Há uma transferência em andamento. Por favor, cancele se você gostaria de transferir este repositório para outro usuário. settings.transfer_notices_1=- Você perderá o acesso ao repositório se transferir para um usuário individual. settings.transfer_notices_2=- Você manterá acesso ao repositório se transferi-lo para uma organização que você também é proprietário. +settings.transfer_notices_3=- Se o repositório for privado e for transferido para um usuário individual, esta ação certifica que o usuário tem pelo menos permissão de leitura (e altera as permissões se necessário). settings.transfer_owner=Novo proprietário +settings.transfer_perform=Executar Transferência +settings.transfer_started=Este repositório foi marcado para transferência e aguarda a confirmação de "%s" settings.transfer_succeed=O repositório foi transferido. +settings.signing_settings=Configurações de Verificação de Assinatura +settings.trust_model=Modelo de Confiança na Assinatura +settings.trust_model.default=Modelo Padrão de Confiança +settings.trust_model.collaborator=Colaborador +settings.trust_model.collaborator.long=Colaborador: Confiar em assinaturas feitas por colaboradores settings.wiki_delete=Excluir dados da wiki settings.wiki_delete_desc=A exclusão de dados da wiki é permanente e não pode ser desfeita. settings.wiki_delete_notices_1=- Isso excluirá e desabilitará permanentemente a wiki do repositório %s. @@ -1591,8 +1807,13 @@ settings.search_user_placeholder=Pesquisar usuário... settings.org_not_allowed_to_be_collaborator=Organizações não podem ser adicionadas como um colaborador. settings.change_team_access_not_allowed=Alteração do acesso da equipe para o repositório está restrito ao proprietário da organização settings.team_not_in_organization=A equipe não está na mesma organização que o repositório +settings.teams=Equipes +settings.add_team=Adicionar Equipe settings.add_team_duplicate=A equipe já tem o repositório settings.add_team_success=A equipe agora tem acesso ao repositório. +settings.search_team=Pesquisar Equipe… +settings.change_team_permission_tip=A permissão da equipe está definida na página de configurações da equipe e não pode ser alterada por repositório +settings.delete_team_tip=Esta equipe tem acesso a todos os repositórios e não pode ser removida settings.remove_team_success=O acesso da equipe ao repositório foi removido. settings.add_webhook=Adicionar webhook settings.add_webhook.invalid_channel_name=Nome do canal no webhook não pode estar em branco e não pode conter somente o caractere #. @@ -1607,6 +1828,7 @@ settings.webhook.response=Resposta settings.webhook.headers=Cabeçalhos settings.webhook.payload=Conteúdo settings.webhook.body=Corpo +settings.webhook.replay.description=Executar novamente esse webhook. settings.githook_edit_desc=Se o hook não estiver ativo, o conteúdo de exemplo será apresentado. Deixar o conteúdo em branco irá desabilitar esse hook. settings.githook_name=Nome do Hook settings.githook_content=Conteúdo do Hook @@ -1625,9 +1847,11 @@ settings.event_desc=Acionado em: settings.event_push_only=Eventos de push settings.event_send_everything=Todos os eventos settings.event_choose=Eventos personalizados... +settings.event_header_repository=Eventos do Repositório settings.event_create=Criar settings.event_create_desc=Branch ou tag criado. settings.event_delete=Excluir +settings.event_delete_desc=Branch ou tag deletado. settings.event_fork=Fork settings.event_release=Versão settings.event_release_desc=Versão publicada, atualizada ou excluída em um repositório. @@ -1635,10 +1859,17 @@ settings.event_push=Push settings.event_push_desc=Git push para o repositório. settings.event_repository=Repositório settings.event_repository_desc=Repositório criado ou excluído. +settings.event_header_issue=Eventos da Issue settings.event_issues=Issues +settings.event_issues_desc=Issue aberta, fechada, reaberta ou editada. +settings.event_issue_assign=Issue Atribuída +settings.event_issue_label=Issue Rotulada +settings.event_issue_label_desc=Rótulos da issue atualizados ou removidos. settings.event_issue_comment=Comentário da issue settings.event_issue_comment_desc=Comentário da issue criado, editado ou excluído. +settings.event_header_pull_request=Eventos de Pull Request settings.event_pull_request=Pull request +settings.event_package=Pacote settings.branch_filter=Filtro de branch settings.active=Ativo settings.active_helper=Informações sobre eventos disparados serão enviadas para esta URL do webhook. @@ -1651,6 +1882,22 @@ settings.hook_type=Tipo de Hook settings.slack_token=Token settings.slack_domain=Domínio settings.slack_channel=Canal +settings.web_hook_name_gitea=Gitea +settings.web_hook_name_gogs=Gogs +settings.web_hook_name_slack=Slack +settings.web_hook_name_discord=Discord +settings.web_hook_name_dingtalk=DingTalk +settings.web_hook_name_telegram=Telegram +settings.web_hook_name_matrix=Matrix +settings.web_hook_name_msteams=Microsoft Teams +settings.web_hook_name_feishu_or_larksuite=Feishu / Lark Suite +settings.web_hook_name_feishu=Feishu +settings.web_hook_name_larksuite=Lark Suite +settings.web_hook_name_wechatwork=WeCom (Wechat Work) +settings.web_hook_name_packagist=Packagist +settings.packagist_username=Nome de usuário no Packagist +settings.packagist_api_token=Token de API +settings.packagist_package_url=URL do pacote do Packagist settings.deploy_keys=Chaves de Deploy settings.add_deploy_key=Nova chave settings.deploy_key_desc=As chaves de deploy possuem somente acesso de leitura (pull) ao repositório. @@ -1713,8 +1960,22 @@ settings.choose_branch=Escolha um branch... settings.no_protected_branch=Não há branches protegidos. settings.edit_protected_branch=Editar settings.protected_branch_required_approvals_min=Aprovações necessárias não podem ser negativas. +settings.tags=Tags +settings.tags.protection=Proteção das Tags +settings.tags.protection.pattern=Padrão de Tag +settings.tags.protection.allowed=Permitido +settings.tags.protection.allowed.users=Usuários permitidos +settings.tags.protection.allowed.teams=Equipes permitidas +settings.tags.protection.allowed.noone=Ninguém +settings.tags.protection.create=Proteger tag +settings.tags.protection.none=Não há tags protegidas. +settings.tags.protection.pattern.description=Você pode usar um só nome ou um padrão glob ou uma expressão regular para corresponder a várias tags. Para mais informações leia o guia das tags protegidas. settings.bot_token=Token do Bot settings.chat_id=ID do Chat +settings.matrix.homeserver_url=URL do Homeserver +settings.matrix.room_id=ID da Sala +settings.matrix.access_token=Token de Acesso +settings.matrix.message_type=Tipo de Mensagem settings.archive.button=Arquivar repositório settings.archive.header=Arquivar este repositório settings.archive.text=Arquivando um repositório fará com que o mesmo fique inteiramente em modo somente leitura. Ele ficará oculto no painel, não poderá receber commits e nem será possível criar issues e pull requests. @@ -1722,6 +1983,7 @@ settings.archive.success=O repositório foi arquivado com sucesso. settings.archive.error=Um erro ocorreu enquanto estava sendo arquivado o repositório. Veja o log para mais detalhes. settings.archive.error_ismirror=Você não pode arquivar um repositório espelhado. settings.archive.branchsettings_unavailable=Configurações do branch não estão disponíveis quando o repositório está arquivado. +settings.archive.tagsettings_unavailable=As configurações de tag não estão disponíveis se o repositório estiver arquivado. settings.unarchive.button=Desarquivar repositório settings.unarchive.header=Desarquivar este repositório settings.unarchive.text=Desarquivando um repositório irá restaurar a capacidade do mesmo receber commits, pushs, assim como novas issues e pull requests. @@ -1777,7 +2039,9 @@ diff.whitespace_ignore_all_whitespace=Ignorar todas as alterações de espaço e diff.whitespace_ignore_amount_changes=Ignorar alterações na quantidade de espaço em branco diff.whitespace_ignore_at_eol=Ignorar alterações com espaço em branco no final da linha diff.stats_desc= %d arquivos alterados com %d adições e %d exclusões +diff.stats_desc_file=%d alterações: %d adições e %d exclusões diff.bin=BIN +diff.bin_not_shown=Arquivo binário não exibido. diff.view_file=Ver arquivo diff.file_before=Antes diff.file_after=Depois @@ -1785,6 +2049,7 @@ diff.file_image_width=Largura diff.file_image_height=Altura diff.file_byte_size=Tamanho diff.file_suppressed=Diferenças do arquivo suprimidas por serem muito extensas +diff.file_suppressed_line_too_long=Diff do arquivo suprimido porque uma ou mais linhas são muito longas diff.too_many_files=Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff diff.show_more=Mostrar mais diff.load=Carregar Diff @@ -1802,14 +2067,22 @@ diff.review.placeholder=Comentário da revisão diff.review.comment=Comentar diff.review.approve=Aprovar diff.review.reject=Solicitar alterações +diff.protected=Protegido +diff.image.side_by_side=Lado a Lado +diff.image.swipe=Deslizar +diff.image.overlay=Sobrepor +diff.has_escaped=Essa linha tem caracteres Unicode ocultos releases.desc=Acompanhe as versões e downloads do projeto. release.releases=Versões +release.tags=Tags release.new_release=Nova versão release.draft=Rascunho release.prerelease=Versão prévia release.stable=Estável +release.compare=Comparar release.edit=editar +release.ahead.commits=%d commits release.source_code=Código fonte release.new_subheader=Lançamentos organizam versões do projeto. release.edit_subheader=Lançamentos organizam versões do projeto. @@ -1825,12 +2098,20 @@ release.publish=Publicar versão release.save_draft=Salvar rascunho release.edit_release=Atualizar versão release.delete_release=Excluir versão +release.delete_tag=Apagar Tag release.deletion=Excluir versão +release.deletion_desc=A exclusão de uma versão só a remove do Gitea. As tags do Git, conteúdo e histórico do repositório permanecem inalterados. Continuar? release.deletion_success=A versão foi excluída. +release.deletion_tag_desc=A tag será excluída do repositório. Conteúdo do repositório e histórico permanecerão inalterados. Continuar? +release.deletion_tag_success=A tag foi excluída. release.tag_name_already_exist=Uma versão com esse nome de tag já existe. release.tag_name_invalid=O nome da tag não é válido. +release.tag_name_protected=O nome da tag está protegido. +release.tag_already_exist=Este nome de tag já existe. release.downloads=Downloads release.download_count=Downloads: %s +release.add_tag_msg=Use o título e o conteúdo do lançamento como mensagem da tag. +release.add_tag=Criar apenas a tag branch.name=Nome da branch branch.search=Pesquisar branches @@ -1856,9 +2137,19 @@ branch.restore=Restaurar branch '%s' branch.download=Baixar branch '%s' branch.included_desc=Este branch faz parte do branch padrão branch.included=Incluído +branch.create_new_branch=Criar branch a partir do branch: +branch.confirm_create_branch=Criar branch +branch.create_branch_operation=Criar branch +branch.new_branch=Criar novo branch +branch.new_branch_from=Criar novo branch a partir de '%s' branch.renamed=Branch %s foi renomeado para %s. +tag.create_tag=Criar tag %s +tag.create_tag_operation=Criar tag +tag.confirm_create_tag=Criar tag +tag.create_tag_from=Criar tag a partir de '%s' +tag.create_success=Tag '%s' foi criada. topic.manage_topics=Gerenciar Tópicos topic.done=Feito @@ -1903,10 +2194,12 @@ settings.visibility=Visibilidade settings.visibility.public=Pública settings.visibility.limited=Limitada (Visível apenas para usuários registrados) settings.visibility.private=Privada (Visível apenas para membros da organização) +settings.visibility.private_shortname=Privado settings.update_settings=Atualizar Configurações settings.update_setting_success=Configurações da organização foram atualizadas. settings.change_orgname_prompt=Nota: alterar o nome da organização também altera a URL da mesma. +settings.change_orgname_redirect_prompt=O nome antigo irá redirecionar até que seja reivindicado. settings.update_avatar_success=O avatar da organização foi atualizado. settings.delete=Excluir organização settings.delete_account=Excluir esta organização @@ -1916,6 +2209,7 @@ settings.delete_org_title=Excluir organização settings.delete_org_desc=Essa organização será excluída permanentemente. Continuar? settings.hooks_desc=Adicionar Webhooks que serão acionados para todos os repositórios desta organização. +settings.labels_desc=Adicionar rótulos que possam ser usadas em issues para todos os repositórios desta organização. members.membership_visibility=Visibilidade da associação: members.public=Público @@ -1937,7 +2231,13 @@ teams.leave=Deixar teams.leave.detail=Sair de %s? teams.can_create_org_repo=Criar repositórios teams.can_create_org_repo_helper=Membros podem criar novos repositórios na organização. O criador terá acesso administrativo ao novo repositório. +teams.none_access=Sem Acesso +teams.none_access_helper=Os membros não podem ver ou fazer qualquer outra ação nesta unidade. +teams.general_access=Acesso Geral +teams.general_access_helper=As permissões dos membros serão decididas pela tabela de permissões abaixo. +teams.read_access=Leitura teams.read_access_helper=Os membros podem ver e clonar os repositórios da equipe. +teams.write_access=Escrita teams.write_access_helper=Os membros podem ler e realizar push para os repositórios da equipe. teams.admin_access=Acesso de administrador teams.admin_access_helper=Os membros podem realizar pull e push em repositórios da equipe e adicionar colaboradores a eles. @@ -1978,7 +2278,9 @@ dashboard=Painel users=Contas de usuário organizations=Organizações repositories=Repositórios +hooks=Webhooks authentication=Fontes de autenticação +emails=E-mails do Usuário config=Configuração notices=Avisos do sistema monitor=Monitoramento @@ -2002,10 +2304,15 @@ dashboard.delete_inactive_accounts.started=A tarefa de apagar todas as contas n dashboard.delete_missing_repos=Excluir todos os repositórios que não possuem seus arquivos Git dashboard.delete_generated_repository_avatars=Excluir avatares gerados do repositório dashboard.update_mirrors=Atualizar espelhamentos +dashboard.deleted_branches_cleanup=Realizar limpeza de branches apagados dashboard.git_gc_repos=Coleta de lixo em todos os repositórios +dashboard.resync_all_sshkeys.desc=(Não necessário para o servidor SSH embutido.) +dashboard.resync_all_sshprincipals.desc=(Não necessário para o servidor SSH embutido.) dashboard.resync_all_hooks=Ressincronizar hooks pre-receive, update e post-receive de todos os repositórios. dashboard.reinit_missing_repos=Reinicializar todos os repositórios Git perdidos cujos registros existem dashboard.sync_external_users=Sincronizar dados de usuário externo +dashboard.cleanup_hook_task_table=Limpar tabela hook_task +dashboard.cleanup_packages=Limpar pacotes expirados dashboard.server_uptime=Tempo de atividade do Servidor dashboard.current_goroutine=Goroutines Atuais dashboard.current_memory_usage=Uso de memória atual @@ -2035,10 +2342,12 @@ dashboard.total_gc_time=Pausa total do GC dashboard.total_gc_pause=Pausa total do GC dashboard.last_gc_pause=Última pausa do GC dashboard.gc_times=Nº de execuções do GC +dashboard.delete_old_system_notices=Excluir todos os avisos de sistema antigos do banco de dados users.user_manage_panel=Gerenciamento de conta de usuário users.new_account=Criar conta de usuário users.name=Nome de usuário +users.full_name=Nome Completo users.activated=Ativado users.admin=Administrador users.restricted=Restrito @@ -2084,7 +2393,14 @@ users.list_status_filter.not_prohibit_login=Permitir login users.list_status_filter.is_2fa_enabled=2FA Ativado users.list_status_filter.not_2fa_enabled=2FA Desativado +emails.email_manage_panel=Gerenciamento de E-mail de Usuário +emails.primary=Principal +emails.activated=Ativado emails.filter_sort.email=E-mail +emails.filter_sort.email_reverse=E-mail (reverso) +emails.filter_sort.name=Nome de Usuário +emails.filter_sort.name_reverse=Nome de Usuário (reverso) +emails.updated=E-mail atualizado emails.not_updated=Falha ao atualizar o endereço de e-mail solicitado: %v emails.duplicate_active=Este endereço de e-mail já está ativo para um usuário diferente. emails.change_email_header=Atualizar Propriedades do E-mail @@ -2106,6 +2422,15 @@ repos.forks=Forks repos.issues=Issues repos.size=Tamanho +packages.package_manage_panel=Gerenciamento de Pacotes +packages.total_size=Tamanho Total: %s +packages.owner=Proprietário +packages.creator=Criador +packages.name=Nome +packages.version=Versão +packages.type=Tipo +packages.repository=Repositório +packages.size=Tamanho @@ -2139,6 +2464,7 @@ auths.use_paged_search=Use a pesquisa paginada auths.search_page_size=Tamanho da página auths.filter=Filtro de usuário auths.admin_filter=Filtro de administrador +auths.enable_ldap_groups=Habilitar grupos do LDAP auths.ms_ad_sa=Atributos de pesquisa do MS AD auths.smtp_auth=Tipo de autenticação SMTP auths.smtphost=Host SMTP @@ -2250,6 +2576,7 @@ config.db_path=Caminho config.service_config=Configuração do serviço config.register_email_confirm=Exigir confirmação de e-mail para se cadastrar config.disable_register=Desabilitar auto-cadastro +config.allow_only_internal_registration=Permitir Registro Somente Através do Próprio Gitea config.allow_only_external_registration=Permitir cadastro somente por meio de serviços externos config.enable_openid_signup=Habilitar o auto-cadastro via OpenID config.enable_openid_signin=Habilitar acesso via OpenID @@ -2284,6 +2611,7 @@ config.mailer_use_sendmail=Usar o Sendmail config.mailer_sendmail_path=Caminho do Sendmail config.mailer_sendmail_args=Argumentos extras para o Sendmail config.mailer_sendmail_timeout=Tempo limite do Sendmail +config.test_email_placeholder=E-mail (por exemplo, teste@exemplo.com.br) config.send_test_mail=Enviar e-mail de teste config.test_mail_failed=Falha ao enviar o e-mail de teste para '%s': %v config.test_mail_sent=O e-mail de teste foi enviado para '%s'. @@ -2342,9 +2670,11 @@ monitor.next=Próxima vez monitor.previous=Vez anterior monitor.execute_times=Execuções monitor.process=Processos em execução +monitor.goroutines=%d Goroutines monitor.desc=Descrição monitor.start=Hora de início monitor.execute_time=Tempo de execução +monitor.last_execution_result=Resultado monitor.process.cancel=Cancelar processo monitor.process.cancel_desc=Cancelar um processo pode causar perda de dados monitor.process.cancel_notices=Cancelar: %s? @@ -2356,6 +2686,7 @@ monitor.queue.type=Tipo monitor.queue.exemplar=Tipo de modelo monitor.queue.numberworkers=Número de executores monitor.queue.maxnumberworkers=Número máximo de executores +monitor.queue.numberinqueue=Número na Fila monitor.queue.review=Revisar configuração monitor.queue.review_add=Revisar/Adicionar executores monitor.queue.configuration=Configuração inicial @@ -2375,6 +2706,12 @@ monitor.queue.pool.flush.title=Fila de liberação monitor.queue.pool.flush.desc=Liberação adicionará um executor que será encerrado assim que a fila estiver vazia ou atingir o tempo limite. monitor.queue.pool.flush.submit=Adicionar executor de liberação monitor.queue.pool.flush.added=Executor de liberação adicionado para %[1]s +monitor.queue.pool.pause.title=Pausar Fila +monitor.queue.pool.pause.desc=Pausar uma Fila impedirá o processamento de dados +monitor.queue.pool.pause.submit=Pausar Fila +monitor.queue.pool.resume.title=Retomar fila +monitor.queue.pool.resume.desc=Definir esta fila para retomar o trabalho +monitor.queue.pool.resume.submit=Retomar fila monitor.queue.settings.title=Configurações do conjunto monitor.queue.settings.desc=Os conjuntos crescem dinamicamente com um aumento em resposta ao bloqueio da fila de executores. Essas alterações não afetarão os grupos de executores atuais. @@ -2444,6 +2781,7 @@ approve_pull_request=`aprovou %[3]s#%[2]s` reject_pull_request=`sugeriu modificações para %[3]s#%[2]s` publish_release=`lançou a versão "%[4]s" em %[3]s` review_dismissed=`descartou a revisão de %[4]s para %[3]s#%[2]s` +review_dismissed_reason=Motivo: create_branch=criou o branch %[3]s em %[4]s watched_repo=começou a observar %[2]s @@ -2498,8 +2836,56 @@ error.probable_bad_signature=AVISO! Embora exista uma chave com este ID no banco error.probable_bad_default_signature=AVISO! Embora a chave padrão tenha este ID, ela não verifica este commit! Este commit é SUSPEITO. [units] +unit=Unidade error.no_unit_allowed_repo=Você não tem permissão para acessar nenhuma seção deste repositório. error.unit_not_allowed=Você não tem permissão para acessar esta seção do repositório. [packages] +title=Pacotes +desc=Gerenciar pacotes do repositório. +empty=Não há pacotes ainda. +filter.type=Tipo +filter.type.all=Todos +filter.no_result=Seu filtro não produziu resultados. +installation=Instalação +about=Sobre este pacote +requirements=Requisitos +dependencies=Dependências +keywords=Palavras-chave +details=Detalhes +details.author=Autor +details.project_site=Site do Projeto +details.license=Licença +versions=Versões +versions.view_all=Ver todas +dependency.version=Versão +composer.dependencies=Dependências +composer.dependencies.development=Dependências de Desenvolvimento +conan.details.repository=Repositório +container.details.type=Tipo de Imagem +container.details.platform=Plataforma +container.details.repository_site=Site do Repositório +container.details.documentation_site=Site da Documentação +container.multi_arch=S.O. / Arquitetura +container.labels=Rótulos +container.labels.key=Chave +container.labels.value=Valor +generic.download=Baixar pacote pela linha de comando: +maven.install2=Executar via linha de comando: +npm.dependencies=Dependências +npm.dependencies.development=Dependências de Desenvolvimento +npm.dependencies.optional=Dependências Opcionais +npm.details.tag=Tag +pypi.requires=Requer Python +settings.link=Vincular este pacote a um repositório +settings.link.description=Se você vincular um pacote a um repositório, o pacote será listado na lista de pacotes do repositório. +settings.link.select=Selecionar Repositório +settings.link.button=Atualizar Link do Repositório +settings.link.success=Link do repositório foi atualizado com sucesso. +settings.link.error=Falha ao atualizar o link do repositório. +settings.delete=Excluir o pacote +settings.delete.description=A exclusão de um pacote é permanente e não pode ser desfeita. +settings.delete.notice=Você está prestes a excluir %s (%s). Esta operação é irreversível, tem certeza? +settings.delete.success=O pacote foi excluído. +settings.delete.error=Falha ao excluir o pacote. diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index 1db1ea09ca..834cd47716 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -488,7 +488,9 @@ auth_failed=Falhou a autenticação: %v still_own_repo=A sua conta possui um ou mais repositórios; deve excluí-los ou transferi-los primeiro. still_has_org=A sua conta é membro de uma ou mais organizações; deixe-as primeiro. +still_own_packages=A sua conta possui um ou mais pacotes; elimine-os primeiro. org_still_own_repo=Esta organização ainda possui repositórios; deve excluí-los ou transferi-los primeiro. +org_still_own_packages=Esta organização ainda possui um ou mais pacotes; elimine-os primeiro. target_branch_not_exist=O ramo de destino não existe. @@ -1792,6 +1794,7 @@ settings.pulls.allow_manual_merge=Habilitar a marcação dos pedidos de integra settings.pulls.enable_autodetect_manual_merge=Habilitar a identificação automática de integrações manuais (obs.: nalguns casos especiais a avaliação pode ser errada) settings.pulls.allow_rebase_update=Habilitar a modificação do ramo do pedido de integração através da mudança de base settings.pulls.default_delete_branch_after_merge=Eliminar o ramo do pedido de integração depois de finalizada a integração, como predefinição +settings.packages_desc=Habilitar o registo de pacotes do repositório settings.projects_desc=Habilitar planeamentos no repositório settings.admin_settings=Configurações do administrador settings.admin_enable_health_check=Habilitar verificações de integridade (git fsck) no repositório @@ -1949,6 +1952,8 @@ settings.event_pull_request_review=Pedido de integração revisto settings.event_pull_request_review_desc=Pedido de integração aprovado, rejeitado ou comentado na revisão. settings.event_pull_request_sync=Pedido de integração sincronizado settings.event_pull_request_sync_desc=Pedido de integração sincronizado. +settings.event_package=Pacote +settings.event_package_desc=Pacote criado ou eliminado num repositório. settings.branch_filter=Filtro de ramos settings.branch_filter_desc=Lista dos ramos a serem considerados nos eventos de envio e de criação e eliminação de ramos, especificada como um padrão glob. Se estiver em branco ou for *, serão reportados eventos para todos os ramos. Veja a documentação github.com/gobwas/glob para ver os detalhes da sintaxe. Exemplos: trunk, {trunk,release*}. settings.active=Em funcionamento @@ -2430,6 +2435,7 @@ dashboard.resync_all_hooks=Voltar a sincronizar automatismos de pré-acolhimento dashboard.reinit_missing_repos=Reinicializar todos os repositórios Git em falta para os quais existam registos dashboard.sync_external_users=Sincronizar dados externos do utilizador dashboard.cleanup_hook_task_table=Limpar tabela hook_task +dashboard.cleanup_packages=Limpar pacotes expirados dashboard.server_uptime=Tempo em funcionamento contínuo do servidor dashboard.current_goroutine=Goroutines em execução dashboard.current_memory_usage=Utilização de memória corrente @@ -2499,6 +2505,7 @@ users.update_profile=Modificar conta do utilizador users.delete_account=Eliminar conta de utilizador users.still_own_repo=Este utilizador ainda possui um ou mais repositórios. Elimine ou transfira esses repositórios primeiro. users.still_has_org=Este utilizador é membro de uma organização. Remova, primeiro, o utilizador de todas as organizações. +users.still_own_packages=Este utilizador ainda possui um ou mais pacotes. Elimine esses pacotes primeiro. users.deletion_success=A conta de utilizador foi eliminada. users.reset_2fa=Reinicializar a autenticação em dois passos users.list_status_filter.menu_text=Filtro @@ -2545,6 +2552,15 @@ repos.forks=Derivações repos.issues=Questões repos.size=Tamanho +packages.package_manage_panel=Gestão de pacotes +packages.total_size=Tamanho total: %s +packages.owner=Proprietário +packages.creator=Criador +packages.name=Nome +packages.version=Versão +packages.type=Tipo +packages.repository=Repositório +packages.size=Tamanho defaulthooks=Automatismos web padrão defaulthooks.desc=Os automatismos web fazem pedidos HTTP POST automaticamente a um servidor quando são despoletados determinados eventos do Gitea. Os automatismos web definidos aqui são os padrões e serão copiados para todos os novos repositórios. Leia mais no guia de automatismos web. @@ -2984,4 +3000,77 @@ error.no_unit_allowed_repo=Não tem permissão para aceder a nenhuma parte deste error.unit_not_allowed=Não tem permissão para aceder a esta parte do repositório. [packages] +title=Pacotes +desc=Gerir pacotes do repositório. +empty=Ainda não há pacotes. +empty.documentation=Para obter mais informação sobre o registo de pacotes, veja a documentação. +filter.type=Tipo +filter.type.all=Todos +filter.no_result=O seu filtro não produziu quaisquer resultados. +published_by=Publicado %[1]s por %[3]s +published_by_in=Publicado %[1]s por %[3]s em %[5]s +installation=Instalação +about=Sobre este pacote +requirements=Requisitos +dependencies=Dependências +keywords=Palavras-chave +details=Detalhes +details.author=Autor(a) +details.license=Licença +assets=Recursos +versions=Versões +versions.view_all=Ver todas +dependency.id=ID +dependency.version=Versão +composer.registry=Configure este registo no seu ficheiro ~/.composer/config.json: +composer.install=Para instalar o pacote usando o Composer, execute o seguinte comando: +composer.documentation=Para obter mais informações sobre o registo do Composer, consulte a documentação. +composer.dependencies=Dependências +composer.dependencies.development=Dependências de desenvolvimento +conan.details.repository=Repositório +conan.registry=Configurar este registo usando a linha de comandos: +conan.install=Para instalar o pacote usando o Conan, execute o seguinte comando: +conan.documentation=Para obter mais informações sobre o registo do Conan, consulte a documentação. +container.details.type=Tipo de imagem +container.details.platform=Plataforma +container.details.repository_site=Página web do repositório +container.details.documentation_site=Página web da documentação +container.pull=Puxar a imagem usando a linha de comandos: +container.documentation=Para obter mais informações sobre o registo do Contentor, consulte a documentação. +container.multi_arch=S.O. / Arquit. +container.labels=Rótulos +container.labels.key=Chave +container.labels.value=Valor +generic.download=Descarregar pacote usando a linha de comandos: +generic.documentation=Para obter mais informações sobre o registo genérico, consulte a documentação. +maven.registry=Configure este registo no seu ficheiro pom.xml do projecto: +maven.install=Para usar este pacote, inclua no bloco dependencies do ficheiro pom.xml o seguinte: +maven.install2=Executar usando a linha de comandos: +maven.download=Para descarregar a dependência, execute na linha de comandos: +maven.documentation=Para obter mais informações sobre o registo Maven, consulte a documentação. +nuget.registry=Configurar este registo usando a linha de comandos: +nuget.install=Para instalar o pacote usando NuGet, execute o seguinte comando: +nuget.documentation=Para obter mais informações sobre o registo Nuget, consulte a documentação. +npm.install=Para instalar o pacote usando o npm, execute o seguinte comando: +npm.documentation=Para obter mais informações sobre o registo npm, consulte a documentação. +npm.dependencies=Dependências +npm.dependencies.development=Dependências de desenvolvimento +npm.dependencies.optional=Dependências opcionais +pypi.requires=Requer Python +pypi.install=Para instalar o pacote usando o pip, execute o seguinte comando: +pypi.documentation=Para obter mais informações sobre o registo do PyPI, consulte a documentação. +rubygems.install=Para instalar o pacote usando o gem, execute o seguinte comando: +rubygems.dependencies.development=Dependências de desenvolvimento +rubygems.documentation=Para obter mais informações sobre o registo do RubyGems, consulte a documentação. +settings.link=Vincular este pacote a um repositório +settings.link.description=Se você vincular um pacote a um repositório, o pacote será listado na lista de pacotes do repositório. +settings.link.select=Escolha o repositório +settings.link.button=Modificar vínculo ao repositório +settings.link.success=O vínculo ao repositório foi modificado com sucesso. +settings.link.error=Falhou a modificação do vínculo ao repositório. +settings.delete=Eliminar pacote +settings.delete.description=Eliminar o pacote é permanente e não pode ser desfeito. +settings.delete.notice=Está prestes a eliminar %s (%s). Esta operação é irreversível. Tem a certeza? +settings.delete.success=O pacote foi eliminado. +settings.delete.error=Falhou a eliminação do pacote. diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 62a1967748..caebde87a9 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -282,6 +282,7 @@ register_helper_msg=已经注册?立即登录! social_register_helper_msg=已经注册?立即绑定! disable_register_prompt=对不起,注册功能已被关闭。请联系网站管理员。 disable_register_mail=已禁用注册的电子邮件确认。 +manual_activation_only=请联系您的站点管理员来完成激活。 remember_me=记住此设备 forgot_password_title=忘记密码 forgot_password=忘记密码? @@ -351,11 +352,11 @@ hi_user_x=%s 您好, activate_account=请激活您的帐户 activate_account.title=%s,请激活您的帐户 activate_account.text_1=%[1]s 您好,感谢注册 %[2]s ! -activate_account.text_2=请点击以下链接激活您在 %s 的帐户: +activate_account.text_2=请在 %s 时间内,点击以下链接激活您的账户: activate_email=请验证您的邮箱地址 activate_email.title=%s,请验证您的电子邮件地址 -activate_email.text=请点击以下链接,以验证你的电子邮件地址在 %s 中 +activate_email.text=请在 %s 时间内,点击以下链接,以验证你的电子邮件地址: register_notify=欢迎来到 Gitea register_notify.title=%[1]s,欢迎来到 %[2]s @@ -365,7 +366,7 @@ register_notify.text_3=如果此账户已为您创建,请先 设 reset_password=恢复您的账户 reset_password.title=%s,您已请求恢复您的帐户 -reset_password.text=请点击以下链接,恢复你在 %s 的账户: +reset_password.text=请在 %s 时间内,点击以下链接,恢复你的账户: register_success=注册成功 @@ -487,7 +488,9 @@ auth_failed=授权验证失败:%v still_own_repo=此帐户仍拥有至少一个仓库,您需要先删除或转移它们。 still_has_org=此帐户仍隶属于一个或多个组织,您需要退出他们。 +still_own_packages=您的账户拥有一个或多个软件包;请先删除它们。 org_still_own_repo=该组织仍然是某些仓库的拥有者,您必须先转移或删除它们才能执行删除组织操作! +org_still_own_packages=该组织仍然是一个或多个软件包的拥有者,您必须先删除它们。 target_branch_not_exist=目标分支不存在。 @@ -1269,7 +1272,7 @@ issues.filter_sort=排序 issues.filter_sort.latest=最新创建 issues.filter_sort.oldest=最早创建 issues.filter_sort.recentupdate=最近更新 -issues.filter_sort.leastupdate=最少更新 +issues.filter_sort.leastupdate=最早更新 issues.filter_sort.mostcomment=最多评论 issues.filter_sort.leastcomment=最少评论 issues.filter_sort.nearduedate=到期日从近到远 @@ -1376,6 +1379,7 @@ issues.unlock.title=解锁有关此问题的对话。 issues.comment_on_locked=您不能对锁定的问题发表评论。 issues.delete=删除 issues.delete.title=是否删除工单? +issues.delete.text=您真的要删除这个工单吗?(该操作将会永久删除所有内容。如果您需要保留,请关闭它) issues.tracker=时间跟踪 issues.start_tracking_short=启动计时器 issues.start_tracking=开始时间跟踪 @@ -1789,7 +1793,9 @@ settings.pulls.allow_rebase_merge_commit=启用变基显式合并 (--no-ff) settings.pulls.allow_squash_commits=启用Squash合并提交 settings.pulls.allow_manual_merge=允许将合并请求标记为手动合并 settings.pulls.enable_autodetect_manual_merge=启用自动检测手动合并 (注意:在某些特殊情况下可能发生错误判断) +settings.pulls.allow_rebase_update=允许通过变基更新拉取请求分支 settings.pulls.default_delete_branch_after_merge=默认合并后删除合并请求分支 +settings.packages_desc=启用仓库软件包注册中心 settings.projects_desc=启用仓库项目 settings.admin_settings=管理员设置 settings.admin_enable_health_check=启用仓库健康检查 (git fsck) @@ -1948,6 +1954,7 @@ settings.event_pull_request_review_desc=合并请求被批准、拒绝或提出 settings.event_pull_request_sync=合并请求被同步 settings.event_pull_request_sync_desc=合并请求被同步。 settings.event_package=软件包 +settings.event_package_desc=软件包已在仓库中被创建或删除。 settings.branch_filter=分支过滤 settings.branch_filter_desc=推送、创建,删除分支事件的分支白名单,使用 glob 模式匹配指定。若为空或 *,则将报告所有分支的事件。语法文档见 github.com/gobwas/glob。示例:master,{master,release*}。 settings.active=激活 @@ -2429,6 +2436,7 @@ dashboard.resync_all_hooks=重新同步所有仓库的 pre-receive、update 和 dashboard.reinit_missing_repos=重新初始化所有丢失的 Git 仓库存在的记录 dashboard.sync_external_users=同步外部用户数据 dashboard.cleanup_hook_task_table=清理 hook_task 表 +dashboard.cleanup_packages=清理过期的软件包 dashboard.server_uptime=服务运行时间 dashboard.current_goroutine=当前 Goroutines 数量 dashboard.current_memory_usage=当前内存使用量 @@ -2461,6 +2469,7 @@ dashboard.gc_times=GC 执行次数 dashboard.delete_old_actions=从数据库中删除所有旧操作记录 dashboard.delete_old_actions.started=已开始从数据库中删除所有旧操作记录。 dashboard.update_checker=更新检查器 +dashboard.delete_old_system_notices=从数据库中删除所有旧系统通知 users.user_manage_panel=用户帐户管理 users.new_account=创建新帐户 @@ -2497,6 +2506,7 @@ users.update_profile=更新帐户 users.delete_account=删除帐户 users.still_own_repo=此用户仍然拥有一个或多个仓库。必须首先删除或转让这些仓库。 users.still_has_org=此用户是组织的成员。必须先从组织中删除用户。 +users.still_own_packages=此用户仍然拥有一个或多个软件包。请先删除这些软件包。 users.deletion_success=用户帐户已被删除。 users.reset_2fa=重置两步验证 users.list_status_filter.menu_text=过滤 @@ -2543,6 +2553,8 @@ repos.forks=派生数 repos.issues=工单数 repos.size=大小 +packages.package_manage_panel=软件包管理 +packages.total_size=总大小:%s packages.owner=所有者 packages.creator=创建者 packages.name=名称 @@ -2550,6 +2562,7 @@ packages.version=版本 packages.type=类型 packages.repository=仓库 packages.size=大小 +packages.published=已发布 defaulthooks=默认Web钩子 defaulthooks.desc=当某些 Gitea 事件触发时,Web 钩子自动向服务器发出 HTTP POST 请求。这里定义的 Web 钩子是默认配置,将被复制到所有新的仓库中。详情请访问 Web 钩子指南。 @@ -2818,9 +2831,12 @@ monitor.next=下次执行时间 monitor.previous=上次执行时间 monitor.execute_times=执行次数 monitor.process=运行中进程 +monitor.stacktrace=调用栈踪迹 +monitor.goroutines=%d 个 Goroutine monitor.desc=进程描述 monitor.start=开始时间 monitor.execute_time=执行时长 +monitor.last_execution_result=结果 monitor.process.cancel=中止进程 monitor.process.cancel_desc=中止一个进程可能导致数据丢失 monitor.process.cancel_notices=中止:%s ? @@ -2989,12 +3005,46 @@ error.unit_not_allowed=您没有权限访问此仓库单元 [packages] title=软件包 +desc=管理仓库软件包。 +empty=还没有软件包。 +empty.documentation=关于软件包注册中心的更多信息,请参阅 文档 。 filter.type=类型 filter.type.all=所有 +filter.no_result=您的过滤器没有产生任何结果。 +filter.container.tagged=已加标签 +filter.container.untagged=未加标签 +published_by=于 %[1]s 发布了 %[3]s +published_by_in=%[3]s 于 %[1]s 发布了 %[5]s +installation=安装 +about=关于这个软件包 +requirements=要求 +dependencies=依赖 +keywords=关键词 details=详情 details.author=作者 details.project_site=项目站点 details.license=许可协议 +assets=文件 +versions=版本 +versions.on=于 +versions.view_all=查看全部 +dependency.id=ID +dependency.version=版本 +composer.registry=在您的 ~/.composer/config.json 文件中设置此注册中心: +composer.install=要使用 Composer 安装软件包,请运行以下命令: +composer.documentation=关于 Composer 注册中心的更多信息,请参阅 文档。 +composer.dependencies=依赖 +composer.dependencies.development=开发依赖 +conan.details.repository=仓库 +conan.registry=从命令行设置此注册中心: +conan.install=要使用 Conan 安装软件包,请运行以下命令: +conan.documentation=关于 Conan 注册中心的更多信息,请参阅 文档。 +container.details.type=镜像类型 +container.details.platform=平台 +container.details.repository_site=仓库站点 +container.details.documentation_site=文档网站 +container.pull=从命令行拉取镜像: +container.documentation=关于 Container 注册中心的更多信息,请参阅 文档 。 container.multi_arch=OS / Arch container.layers=镜像层 container.labels=标签