Compare commits

..

No commits in common. "faf28b28233b18289e0a398ea22265bb87b1e1b5" and "c5e187c389b35b9e080a3187b93a775a3c81e585" have entirely different histories.

13 changed files with 15 additions and 160 deletions

View File

@ -23,8 +23,7 @@
"Vue.volar",
"ms-azuretools.vscode-docker",
"zixuanchen.vitest-explorer",
"qwtel.sqlite-viewer",
"GitHub.vscode-pull-request-github"
"qwtel.sqlite-viewer"
]
}
},

View File

@ -35,7 +35,6 @@ vscode:
- ms-azuretools.vscode-docker
- zixuanchen.vitest-explorer
- qwtel.sqlite-viewer
- GitHub.vscode-pull-request-github
ports:
- name: Gitea

View File

@ -8,8 +8,6 @@ import (
"io"
"code.gitea.io/gitea/modules/validation"
"golang.org/x/net/html/charset"
)
// Metadata represents the metadata of a Maven package
@ -54,10 +52,7 @@ type pomStruct struct {
// ParsePackageMetaData parses the metadata of a pom file
func ParsePackageMetaData(r io.Reader) (*Metadata, error) {
var pom pomStruct
dec := xml.NewDecoder(r)
dec.CharsetReader = charset.NewReaderLabel
if err := dec.Decode(&pom); err != nil {
if err := xml.NewDecoder(r).Decode(&pom); err != nil {
return nil, err
}

View File

@ -8,7 +8,6 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"golang.org/x/text/encoding/charmap"
)
const (
@ -70,20 +69,4 @@ func TestParsePackageMetaData(t *testing.T) {
assert.Equal(t, dependencyArtifactID, m.Dependencies[0].ArtifactID)
assert.Equal(t, dependencyVersion, m.Dependencies[0].Version)
})
t.Run("Encoding", func(t *testing.T) {
// UTF-8 is default but the metadata could be encoded differently
pomContent8859_1, err := charmap.ISO8859_1.NewEncoder().String(
strings.ReplaceAll(
pomContent,
`<?xml version="1.0"?>`,
`<?xml version="1.0" encoding="ISO-8859-1"?>`,
),
)
assert.NoError(t, err)
m, err := ParsePackageMetaData(strings.NewReader(pomContent8859_1))
assert.NoError(t, err)
assert.NotNil(t, m)
})
}

View File

@ -2205,8 +2205,8 @@ settings.protect_enable_push=Push aktivieren
settings.protect_enable_push_desc=Jeder, der Schreibzugriff hat, darf in diesen Branch Pushen (aber kein Force-Push).
settings.protect_enable_merge=Merge aktivieren
settings.protect_enable_merge_desc=Jeder mit Schreibzugriff darf die Pull-Requests in diesen Branch mergen.
settings.protect_whitelist_committers=Schütze gewhitelistete Commiter
settings.protect_whitelist_committers_desc=Jeder, der auf der Whitelist steht, darf in diesen Branch pushen (aber kein Force-Push).
settings.protect_whitelist_committers=Schütze gewhitlistede Commiter
settings.protect_whitelist_committers_desc=Jeder, der auf der Whiteliste steht, darf in diesen Branch pushen (aber kein Force-Push).
settings.protect_whitelist_deploy_keys=Deploy-Schlüssel mit Schreibzugriff zum Pushen whitelisten.
settings.protect_whitelist_users=Nutzer, die pushen dürfen:
settings.protect_whitelist_search_users=Benutzer suchen…
@ -2925,7 +2925,6 @@ auths.deletion_success=Die Authentifizierungsquelle „%s“ wurde gelöscht.
auths.login_source_exist=Die Authentifizierungsquelle "%s" existiert bereits.
auths.login_source_of_type_exist=Eine Authentifizierungart dieses Typs existiert bereits.
auths.unable_to_initialize_openid=OpenID Connect Provider konnte nicht initialisiert werden: %s
auths.invalid_openIdConnectAutoDiscoveryURL=Ungültige Auto-Discovery-URL (dies muss eine gültige URL sein, die mit http:// oder https:// beginnt)
config.server_config=Serverkonfiguration
config.app_name=Seitentitel
@ -3096,7 +3095,6 @@ monitor.queue.numberinqueue=Nummer in der Warteschlange
monitor.queue.review=Konfiguration überprüfen
monitor.queue.review_add=Worker hinzufügen/prüfen
monitor.queue.settings.title=Pool-Einstellungen
monitor.queue.settings.desc=Pools wachsen dynamisch basierend auf der Blockierung der Arbeitswarteschlange.
monitor.queue.settings.maxnumberworkers=Maximale Anzahl an Workern
monitor.queue.settings.maxnumberworkers.placeholder=Derzeit %[1]d
monitor.queue.settings.maxnumberworkers.error=Die Anzahl der Worker muss eine Zahl sein
@ -3190,7 +3188,6 @@ mark_as_read=Als gelesen markieren
mark_as_unread=Als ungelesen markieren
mark_all_as_read=Alle als gelesen markieren
subscriptions=Abonnements
watching=Gefolgt
no_subscriptions=Keine Abonnements
[gpg]
@ -3213,7 +3210,6 @@ error.unit_not_allowed=Du hast keine Berechtigung, um auf diesen Repository-Bere
title=Pakete
desc=Repository-Pakete verwalten.
empty=Noch keine Pakete vorhanden.
empty.documentation=Weitere Informationen zur Paket-Registry finden Sie in der <a target="_blank" rel="noopener noreferrer" href="%s">Dokumentation</a>.
empty.repo=Hast du ein Paket hochgeladen, das hier nicht angezeigt wird? Gehe zu den <a href="%[1]s">Paketeinstellungen</a> und verlinke es mit diesem Repo.
filter.type=Typ
filter.type.all=Alle
@ -3230,31 +3226,16 @@ keywords=Schlüsselwörter
details=Details
details.author=Autor
details.project_site=Projektseite
details.repository_site=Repository-Seite
details.documentation_site=Dokumentationsseite
details.license=Lizenz
assets=Dateien
versions=Versionen
versions.view_all=Alle anzeigen
dependency.id=ID
dependency.version=Version
alpine.registry=Richten Sie diese Registry ein, indem Sie die URL in die <code>/etc/apk/repositories</code>-Datei hinzufügen:
alpine.registry.key=Laden Sie den öffentlichen RSA-Schlüssel der Registry in den <code>/etc/apk/keys/</code>-Ordner um die Signatur zu überprüfen:
alpine.registry.info=Wählen Sie $branch und $repository aus der Liste unten.
alpine.install=Nutze folgenden Befehl, um das Paket zu installieren:
alpine.documentation=Für weitere Informationen zur Alpine-Registry, schauen Sie in der <a target="_blank" rel="noopener noreferrer" href="%s">Dokumentation</a> nach.
alpine.repository=Repository-Informationen
alpine.repository.branches=Branches
alpine.repository.repositories=Repositories
alpine.repository.architectures=Architekturen
cargo.registry=Richten Sie diese Registry in der Cargo-Konfigurationsdatei ein (z.B. <code>~/.cargo/config.toml</code>):
cargo.install=Um das Paket mit Cargo zu installieren, führen Sie den folgenden Befehl aus:
cargo.documentation=Weitere Informationen zur Cargo-Paketverwaltung finden Sie in der <a target="_blank" rel="noopener noreferrer" href="%s">Dokumentation</a>.
cargo.details.repository_site=Repository-Seite
cargo.details.documentation_site=Dokumentationsseite
chef.registry=Richten Sie diese Registry in Ihrer <code>~/.chef/config.rb</code> Datei ein:
chef.install=Nutze folgenden Befehl, um das Paket zu installieren:
chef.documentation=Weitere Informationen zur Chef-Paketverwaltung finden Sie in der <a target="_blank" rel="noopener noreferrer" href="%s">Dokumentation</a>.
composer.registry=Setze diese Paketverwaltung in deiner <code>~/.composer/config.json</code> Datei auf:
composer.install=Nutze folgenden Befehl, um das Paket mit Composer zu installieren:
composer.documentation=Weitere Informationen zur Composer-Paketverwaltung findest du in der <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/composer/">Dokumentation</a>.
@ -3264,11 +3245,6 @@ conan.details.repository=Repository
conan.registry=Diese Registry über die Kommandozeile einrichten:
conan.install=Um das Paket mit Conan zu installieren, führe den folgenden Befehl aus:
conan.documentation=Weitere Informationen zur Conan-Paketverwaltung findest du in der <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/conan/">Dokumentation</a>.
conda.registry=Richten Sie diese Registry als Conda-Repository in Ihrer <code>.condarc</code> Datei ein:
conda.install=Um das Paket mit Conda zu installieren, führen Sie den folgenden Befehl aus:
conda.documentation=Weitere Informationen zur Conda-Paketverwaltung finden Sie in der <a target="_blank" rel="noopener noreferrer" href="%s">Dokumentation</a>.
conda.details.repository_site=Repository-Seite
conda.details.documentation_site=Dokumentationsseite
container.details.type=Container-Image Typ
container.details.platform=Plattform
container.pull=Downloade das Container-Image aus der Kommandozeile:
@ -3279,21 +3255,11 @@ container.layers=Container-Image Ebenen
container.labels=Labels
container.labels.key=Schlüssel
container.labels.value=Wert
cran.registry=Richten Sie diese Registry in Ihrer <code>Rprofile.site</code> Datei ein:
cran.install=Nutze folgenden Befehl, um das Paket zu installieren:
cran.documentation=Für weitere Informationen zur CRAN-Registry, schauen Sie in der <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/cran/">Dokumentation</a> nach.
debian.registry=Diese Registry über die Kommandozeile einrichten:
debian.registry.info=Wählen Sie $distribution und $component aus der Liste unten.
debian.install=Nutze folgenden Befehl, um das Paket zu installieren:
debian.documentation=Für weitere Informationen zur Debian-Registry, schauen Sie in der <a target="_blank" rel="noopener noreferrer" href="%s">Dokumentation</a> nach.
debian.repository=Repository-Informationen
debian.repository.distributions=Distributionen
debian.repository.components=Komponenten
debian.repository.architectures=Architekturen
generic.download=Downloade das Paket aus der Kommandozeile:
generic.documentation=Weitere Informationen zur generischen Paketverwaltung findest du in der <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/generic">Dokumentation</a>.
go.install=Installieren Sie das Paket über die Kommandozeile:
go.documentation=Für weitere Informationen zur Go-Registry, schauen Sie in der <a target="_blank" rel="noopener noreferrer" href="%s">Dokumentation</a> nach.
helm.registry=Diese Paketverwaltung über die Kommandozeile einrichten:
helm.install=Nutze folgenden Befehl, um das Paket zu installieren:
helm.documentation=Weitere Informationen zur Helm-Paketverwaltung findest du in der <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/helm/">Dokumentation</a>.
@ -3322,7 +3288,6 @@ pypi.install=Nutze folgenden Befehl, um das Paket mit pip zu installieren:
pypi.documentation=Weitere Informationen zur PyPI-Paketverwaltung findest du in der <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/pypi/">Dokumentation</a>.
rpm.registry=Diese Registry über die Kommandozeile einrichten:
rpm.install=Nutze folgenden Befehl, um das Paket zu installieren:
rpm.documentation=Für weitere Informationen zur RPM-Registry, schauen Sie in der <a target="_blank" rel="noopener noreferrer" href="%s">Dokumentation</a> nach.
rubygems.install=Um das Paket mit gem zu installieren, führe den folgenden Befehl aus:
rubygems.install2=oder füg es zum Gemfile hinzu:
rubygems.dependencies.runtime=Laufzeitabhängigkeiten
@ -3331,9 +3296,6 @@ rubygems.required.ruby=Benötigt Ruby Version
rubygems.required.rubygems=Benötigt RubyGem Version
rubygems.documentation=Weitere Informationen zur RubyGems-Paketverwaltung findest du in der <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/rubygems/">Dokumentation</a>.
swift.registry=Diese Registry über die Kommandozeile einrichten:
swift.install=Fügen Sie das Paket Ihrer <code>Package.swift</code> Datei hinzu:
swift.install2=und führen Sie den folgenden Befehl aus:
swift.documentation=Weitere Informationen zur Swift-Paketverwaltung finden Sie in der <a target="_blank" rel="noopener noreferrer" href="%s">Dokumentation</a>.
vagrant.install=Um eine Vagrant-Box hinzuzufügen, führen Sie folgenden Befehl aus:
vagrant.documentation=Für weitere Informationen zur Vagrant-Registry, siehe <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/vagrant/">Dokumentation</a>.
settings.link=Dieses Paket einem Repository zuweisen
@ -3347,118 +3309,41 @@ settings.delete.description=Das Löschen eines Pakets ist dauerhaft und kann nic
settings.delete.notice=Du bist dabei, %s (%s) zu löschen. Dieser Vorgang ist unwiderruflich. Bist du sicher?
settings.delete.success=Das Paket wurde gelöscht.
settings.delete.error=Löschen des Pakets fehlgeschlagen.
owner.settings.cargo.title=Cargo-Registry-Index
owner.settings.cargo.initialize=Index initialisieren
owner.settings.cargo.initialize.description=Um die Cargo-Registry nutzen zu können, wird ein spezielles Git-Repository als Index benötigt. Hier können Sie es mit der erforderlichen Konfiguration (neu) erstellen.
owner.settings.cargo.initialize.error=Cargo-Index konnte nicht initialisiert werden: %v
owner.settings.cargo.initialize.success=Der Cargo-Index wurde erfolgreich erstellt.
owner.settings.cargo.rebuild=Index neu erstellen
owner.settings.cargo.rebuild.description=Wenn der Index nicht mit den gespeicherten Cargo-Paketen übereinstimmt, können Sie ihn hier neu erstellen.
owner.settings.cargo.rebuild.error=Cargo-Index konnte nicht neu erstellt werden: %v
owner.settings.cargo.rebuild.success=Der Cargo-Index wurde erfolgreich neu erstellt.
owner.settings.cleanuprules.title=Bereinigungsregeln verwalten
owner.settings.cleanuprules.add=Bereinigungsregel hinzufügen
owner.settings.cleanuprules.edit=Bereinigungsregel bearbeiten
owner.settings.cleanuprules.none=Keine Bereinigungsregeln verfügbar. Lesen Sie die Dokumentation um mehr zu erfahren.
owner.settings.cleanuprules.preview=Vorschau der Bereinigungsregel
owner.settings.cleanuprules.preview.overview=%d Pakete sollen entfernt werden.
owner.settings.cleanuprules.preview.none=Bereinigungsregel stimmt mit keinem Paket überein.
owner.settings.cleanuprules.enabled=Aktiviert
owner.settings.cleanuprules.pattern_full_match=Muster auf den vollständigen Paketnamen anwenden
owner.settings.cleanuprules.keep.title=Versionen, die diesen Regeln entsprechen, werden beibehalten, auch wenn sie mit einer Entfernungsregel unten übereinstimmen.
owner.settings.cleanuprules.keep.count=Behalte die aktuellsten
owner.settings.cleanuprules.keep.count.1=1 Version pro Paket
owner.settings.cleanuprules.keep.count.n=%d Versionen pro Paket
owner.settings.cleanuprules.keep.pattern=Behalte übereinstimmende Versionen
owner.settings.cleanuprules.keep.pattern.container=Die Version <code>latest</code> bei Container-Paketen wird immer behalten.
owner.settings.cleanuprules.remove.title=Versionen, die diesen Regeln entsprechen, werden entfernt, es sei denn, eine obige Regel besagt, sie zu behalten.
owner.settings.cleanuprules.remove.days=Entferne Versionen älter als
owner.settings.cleanuprules.remove.pattern=Entferne übereinstimmende Versionen
owner.settings.cleanuprules.success.update=Bereinigungsregel wurde aktualisiert.
owner.settings.cleanuprules.success.delete=Bereinigungsregel wurde gelöscht.
owner.settings.chef.title=Chef-Registry
owner.settings.chef.keypair=Schlüsselpaar generieren
owner.settings.chef.keypair.description=Schlüsselpaar zur Authentifizierung gegen die Chef-Registry generieren. Der bisherige Schlüssel kann danach nicht mehr verwendet werden.
[secrets]
secrets=Secrets
description=Secrets werden an bestimmte Aktionen weitergegeben und können nicht anderweitig ausgelesen werden.
none=Noch keine Secrets vorhanden.
value=Wert
name=Name
creation=Secret hinzufügen
creation.name_placeholder=Groß-/Kleinschreibung wird ignoriert, nur alphanumerische Zeichen oder Unterstriche, darf nicht mit GITEA_ oder GITHUB_ beginnen
creation.value_placeholder=Beliebigen Inhalt eingeben. Leerzeichen am Anfang und Ende werden weggelassen.
creation.success=Das Secret "%s" wurde hinzugefügt.
creation.failed=Secret konnte nicht hinzugefügt werden.
deletion=Secret entfernen
deletion.description=Das Entfernen eines Secrets kann nicht rückgängig gemacht werden. Fortfahren?
deletion.success=Das Secret wurde entfernt.
deletion.failed=Secret konnte nicht entfernt werden.
management=Secret-Verwaltung
[actions]
actions=Actions
unit.desc=Actions verwalten
status.unknown=Unbekannt
status.waiting=Wartend
status.running=Laufend
status.success=Erfolg
status.failure=Fehler
status.cancelled=Abgebrochen
status.skipped=Übersprungen
status.blocked=Blockiert
runners=Runner
runners.runner_manage_panel=Runner-Verwaltung
runners.new=Neuen Runner erstellen
runners.new_notice=Wie man einen Runner startet
runners.status=Status
runners.id=ID
runners.name=Name
runners.owner_type=Typ
runners.description=Beschreibung
runners.labels=Labels
runners.last_online=Letzte Online-Zeit
runners.agent_labels=Agent-Labels
runners.custom_labels=Benutzerdefinierte Labels
runners.custom_labels_helper=Benutzerdefinierte Labels sind Labels, die von einem Administrator manuell hinzugefügt werden. Labels werden durch Komma getrennt, Leerzeichen am Anfang und am Ende jedes Labels werden ignoriert.
runners.runner_title=Runner
runners.task_list=Letzte Aufgaben dieses Runners
runners.task_list.run=Ausführen
runners.task_list.status=Status
runners.task_list.repository=Repository
runners.task_list.commit=Commit
runners.task_list.done_at=Fertig um
runners.edit_runner=Runner bearbeiten
runners.update_runner=Änderungen anwenden
runners.update_runner_success=Runner erfolgreich aktualisiert
runners.update_runner_failed=Der Runner konnte nicht aktualisiert werden
runners.delete_runner=Diesen Runner löschen
runners.delete_runner_success=Runner erfolgreich gelöscht
runners.delete_runner_failed=Der Runner konnte nicht gelöscht werden
runners.delete_runner_header=Bestätigen, um diesen Runner zu löschen
runners.delete_runner_notice=Wenn eine Aufgabe auf diesem Runner ausgeführt wird, wird sie beendet und als fehlgeschlagen markiert. Dies könnte Workflows zerstören.
runners.none=Keine Runner verfügbar
runners.status.unspecified=Unbekannt
runners.status.idle=Inaktiv
runners.status.active=Aktiv
runners.status.offline=Offline
runners.version=Version
runners.reset_registration_token_success=Runner-Registrierungstoken erfolgreich zurückgesetzt
runs.all_workflows=Alle Workflows
runs.commit=Commit
runs.pushed_by=Gepushed von
runs.invalid_workflow_helper=Die Workflow-Konfigurationsdatei ist ungültig. Bitte überprüfen Sie Ihre Konfigurationsdatei: %s
runs.no_matching_runner_helper=Kein passender Runner: %s
need_approval_desc=Um Workflows für den Pull-Request eines Forks auszuführen, ist eine Genehmigung erforderlich.
[projects]
type-1.display_name=Individuelles Projekt
type-2.display_name=Repository-Projekt
type-3.display_name=Organisationsprojekt

View File

@ -935,7 +935,6 @@ fork_from = Fork From
already_forked = You've already forked %s
fork_to_different_account = Fork to a different account
fork_visibility_helper = The visibility of a forked repository cannot be changed.
fork_no_valid_owners = This repository can not be forked because there are no valid owners.
use_template = Use this template
clone_in_vsc = Clone in VS Code
download_zip = Download ZIP

View File

@ -49,11 +49,6 @@ var (
func apiError(ctx *context.Context, status int, obj any) {
helper.LogAndProcessError(ctx, status, obj, func(message string) {
// The maven client does not present the error message to the user. Log it for users with access to server logs.
if status == http.StatusBadRequest || status == http.StatusInternalServerError {
log.Error(message)
}
ctx.PlainText(status, message)
})
}
@ -325,8 +320,7 @@ func UploadPackageFile(ctx *context.Context) {
var err error
pvci.Metadata, err = maven_module.ParsePackageMetaData(buf)
if err != nil {
apiError(ctx, http.StatusBadRequest, err)
return
log.Error("Error parsing package metadata: %v", err)
}
if pvci.Metadata != nil {

View File

@ -89,6 +89,7 @@ func SettingsPost(ctx *context.Context) {
// reset ctx.org.OrgLink with new name
ctx.Org.OrgLink = setting.AppSubURL + "/org/" + url.PathEscape(form.Name)
log.Trace("Organization name changed: %s -> %s", org.Name, form.Name)
nameChanged = false
}
// In case it's just a case change.
@ -129,6 +130,11 @@ func SettingsPost(ctx *context.Context) {
return
}
}
} else if nameChanged {
if err := repo_model.UpdateRepositoryOwnerNames(org.ID, org.Name); err != nil {
ctx.ServerError("UpdateRepository", err)
return
}
}
log.Trace("Organization setting updated: %s", org.Name)

View File

@ -174,12 +174,6 @@ func getForkRepository(ctx *context.Context) *repo_model.Repository {
ctx.Data["ContextUser"] = ctx.Doer
} else if len(orgs) > 0 {
ctx.Data["ContextUser"] = orgs[0]
} else {
msg := ctx.Tr("repo.fork_no_valid_owners")
ctx.Data["Flash"] = ctx.Flash
ctx.Flash.Error(msg)
ctx.Data["CanForkRepo"] = false
return nil
}
return forkRepo

View File

@ -196,6 +196,7 @@ func releasesOrTags(ctx *context.Context, isTagList bool) {
}
ctx.Data["Releases"] = releases
ctx.Data["ReleasesNum"] = len(releases)
pager := context.NewPagination(int(count), opts.PageSize, opts.Page, 5)
pager.SetDefaultParams(ctx)

View File

@ -58,7 +58,7 @@ func RenameUser(ctx context.Context, u *user_model.User, newUserName string) err
u.Name = oldUserName
return err
}
return repo_model.UpdateRepositoryOwnerNames(u.ID, newUserName)
return nil
}
ctx, committer, err := db.TxContext(ctx)

View File

@ -125,7 +125,7 @@
{{end}}
{{else if and .LatestPullRequest.HasMerged .MergeMovedOn}}
{{if and (not .DBBranch.IsDeleted) $.AllowsPulls (gt .CommitsAhead 0)}}
<a href="{{$.RepoLink}}/compare/{{PathEscapeSegments $.DefaultBranchBranch.DBBranch.Name}}...{{if ne $.Repository.Owner.Name $.Owner.Name}}{{PathEscape $.Owner.Name}}:{{end}}{{PathEscapeSegments .DBBranch.Name}}">
<a href="{{$.RepoLink}}/compare/{{PathEscapeSegments $.DefaultBranchBranch}}...{{if ne $.Repository.Owner.Name $.Owner.Name}}{{$.Owner.Name}}:{{end}}{{.Name | PathEscapeSegments}}">
<button id="new-pull-request" class="ui compact basic button gt-mr-0">{{if $.CanPull}}{{$.locale.Tr "repo.pulls.compare_changes"}}{{else}}{{$.locale.Tr "action.compare_branch"}}{{end}}</button>
</a>
{{end}}

View File

@ -5,7 +5,7 @@
<div class="gt-df">
<div class="gt-f1 gt-df gt-ac">
<h2 class="ui compact small menu header small-menu-items">
<a class="{{if .PageIsReleaseList}}active {{end}}item" href="{{.RepoLink}}/releases">{{.locale.PrettyNumber .NumReleases}} {{.locale.TrN .NumReleases "repo.release" "repo.releases"}}</a>
<a class="{{if .PageIsReleaseList}}active {{end}}item" href="{{.RepoLink}}/releases">{{.locale.PrettyNumber .ReleasesNum}} {{.locale.TrN .ReleasesNum "repo.release" "repo.releases"}}</a>
{{if $canReadCode}}
<a class="{{if .PageIsTagList}}active {{end}}item" href="{{.RepoLink}}/tags">{{.locale.PrettyNumber .NumTags}} {{.locale.TrN .NumTags "repo.tag" "repo.tags"}}</a>
{{end}}