mirror of
https://github.com/go-gitea/gitea.git
synced 2026-05-09 16:28:19 +02:00
Merge remote-tracking branch 'origin/main' into fix-24635
This commit is contained in:
commit
04a66583d1
2
.github/workflows/files-changed.yml
vendored
2
.github/workflows/files-changed.yml
vendored
@ -53,7 +53,7 @@ jobs:
|
||||
- "Makefile"
|
||||
- ".golangci.yml"
|
||||
- ".editorconfig"
|
||||
- "options/locale/locale_en-US.ini"
|
||||
- "options/locale/locale_en-US.json"
|
||||
|
||||
frontend:
|
||||
- "*.js"
|
||||
|
||||
14
Makefile
14
Makefile
@ -166,8 +166,8 @@ WEB_DIRS := web_src/js web_src/css
|
||||
|
||||
ESLINT_FILES := web_src/js tools *.ts tests/e2e
|
||||
STYLELINT_FILES := web_src/css web_src/js/components/*.vue
|
||||
SPELLCHECK_FILES := $(GO_DIRS) $(WEB_DIRS) templates options/locale/locale_en-US.ini .github $(filter-out CHANGELOG.md, $(wildcard *.go *.md *.yml *.yaml *.toml))
|
||||
EDITORCONFIG_FILES := templates .github/workflows options/locale/locale_en-US.ini
|
||||
SPELLCHECK_FILES := $(GO_DIRS) $(WEB_DIRS) templates options/locale/locale_en-US.json .github $(filter-out CHANGELOG.md, $(wildcard *.go *.md *.yml *.yaml *.toml))
|
||||
EDITORCONFIG_FILES := templates .github/workflows options/locale/locale_en-US.json
|
||||
|
||||
GO_SOURCES := $(wildcard *.go)
|
||||
GO_SOURCES += $(shell find $(GO_DIRS) -type f -name "*.go")
|
||||
@ -911,16 +911,6 @@ lockfile-check:
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
.PHONY: update-translations
|
||||
update-translations:
|
||||
mkdir -p ./translations
|
||||
cd ./translations && curl -L https://crowdin.com/download/project/gitea.zip > gitea.zip && unzip gitea.zip
|
||||
rm ./translations/gitea.zip
|
||||
$(SED_INPLACE) -e 's/="/=/g' -e 's/"$$//g' ./translations/*.ini
|
||||
$(SED_INPLACE) -e 's/\\"/"/g' ./translations/*.ini
|
||||
mv ./translations/*.ini ./options/locale/
|
||||
rmdir ./translations
|
||||
|
||||
.PHONY: generate-gitignore
|
||||
generate-gitignore: ## update gitignore files
|
||||
$(GO) run build/generate-gitignores.go
|
||||
|
||||
@ -1,47 +1,17 @@
|
||||
#!/bin/sh
|
||||
|
||||
# this script runs in alpine image which only has `sh` shell
|
||||
|
||||
set +e
|
||||
if sed --version 2>/dev/null | grep -q GNU; then
|
||||
SED_INPLACE="sed -i"
|
||||
else
|
||||
SED_INPLACE="sed -i ''"
|
||||
fi
|
||||
set -e
|
||||
|
||||
if [ ! -f ./options/locale/locale_en-US.ini ]; then
|
||||
if [ ! -f ./options/locale/locale_en-US.json ]; then
|
||||
echo "please run this script in the root directory of the project"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mv ./options/locale/locale_en-US.ini ./options/
|
||||
|
||||
# the "ini" library for locale has many quirks, its behavior is different from Crowdin.
|
||||
# see i18n_test.go for more details
|
||||
|
||||
# this script helps to unquote the Crowdin outputs for the quirky ini library
|
||||
# * find all `key="...\"..."` lines
|
||||
# * remove the leading quote
|
||||
# * remove the trailing quote
|
||||
# * unescape the quotes
|
||||
# * eg: key="...\"..." => key=..."...
|
||||
$SED_INPLACE -r -e '/^[-.A-Za-z0-9_]+[ ]*=[ ]*".*"$/ {
|
||||
s/^([-.A-Za-z0-9_]+)[ ]*=[ ]*"/\1=/
|
||||
s/"$//
|
||||
s/\\"/"/g
|
||||
}' ./options/locale/*.ini
|
||||
|
||||
# * if the escaped line is incomplete like `key="...` or `key=..."`, quote it with backticks
|
||||
# * eg: key="... => key=`"...`
|
||||
# * eg: key=..." => key=`..."`
|
||||
$SED_INPLACE -r -e 's/^([-.A-Za-z0-9_]+)[ ]*=[ ]*(".*[^"])$/\1=`\2`/' ./options/locale/*.ini
|
||||
$SED_INPLACE -r -e 's/^([-.A-Za-z0-9_]+)[ ]*=[ ]*([^"].*")$/\1=`\2`/' ./options/locale/*.ini
|
||||
mv ./options/locale/locale_en-US.json ./options/
|
||||
|
||||
# Remove translation under 25% of en_us
|
||||
baselines=$(wc -l "./options/locale_en-US.ini" | cut -d" " -f1)
|
||||
baselines=$(wc -l "./options/locale_en-US.json" | cut -d" " -f1)
|
||||
baselines=$((baselines / 4))
|
||||
for filename in ./options/locale/*.ini; do
|
||||
for filename in ./options/locale/*.json; do
|
||||
lines=$(wc -l "$filename" | cut -d" " -f1)
|
||||
if [ $lines -lt $baselines ]; then
|
||||
echo "Removing $filename: $lines/$baselines"
|
||||
@ -49,4 +19,4 @@ for filename in ./options/locale/*.ini; do
|
||||
fi
|
||||
done
|
||||
|
||||
mv ./options/locale_en-US.ini ./options/locale/
|
||||
mv ./options/locale_en-US.json ./options/locale/
|
||||
|
||||
@ -4,9 +4,9 @@ base_path: "."
|
||||
base_url: "https://api.crowdin.com"
|
||||
preserve_hierarchy: true
|
||||
files:
|
||||
- source: "/options/locale/locale_en-US.ini"
|
||||
translation: "/options/locale/locale_%locale%.ini"
|
||||
type: "ini"
|
||||
- source: "/options/locale/locale_en-US.json"
|
||||
translation: "/options/locale/locale_%locale%.json"
|
||||
type: "json"
|
||||
skip_untranslated_strings: true
|
||||
export_only_approved: true
|
||||
update_option: "update_as_unapproved"
|
||||
|
||||
@ -10,6 +10,7 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
@ -50,12 +51,42 @@ func WriteAuthorizedStringForValidKey(key *PublicKey, w io.Writer) error {
|
||||
return err
|
||||
}
|
||||
|
||||
var globalVars = sync.OnceValue(func() (ret struct {
|
||||
principalRegexp *regexp.Regexp
|
||||
},
|
||||
) {
|
||||
// principalRegexp expresses whether a principal is considered valid.
|
||||
// This reverse engineers how sshd parses the authorized keys file,
|
||||
// see e.g. https://github.com/openssh/openssh-portable/blob/32deb00b38b4ee2b3302f261ea1e68c04e020a08/auth2-pubkeyfile.c#L221-L256
|
||||
// Any newline or # comment will be stripped when parsing, so don't allow
|
||||
// those. Also, if any space or tab is present in the principal, the part
|
||||
// proceeding this would be parsed as an option, so just avoid any whitespace
|
||||
// altogether.
|
||||
ret.principalRegexp = regexp.MustCompile(`^[^\s#]+$`)
|
||||
return ret
|
||||
})
|
||||
|
||||
func writeAuthorizedStringForKey(key *PublicKey, w io.Writer) (keyValid bool, err error) {
|
||||
const tpl = AuthorizedStringCommentPrefix + "\n" + `command=%s,no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty,no-user-rc,restrict %s %s` + "\n"
|
||||
pubKey, _, _, _, err := ssh.ParseAuthorizedKey([]byte(key.Content))
|
||||
if err != nil {
|
||||
return false, err
|
||||
const tpl = AuthorizedStringCommentPrefix + "\n" + `command=%s,no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty,no-user-rc,restrict %s` + "\n"
|
||||
|
||||
var sshKey string
|
||||
|
||||
if key.Type == KeyTypePrincipal {
|
||||
// TODO: actually using PublicKey to store "principal" is an abuse
|
||||
if !globalVars().principalRegexp.MatchString(key.Content) {
|
||||
return false, fmt.Errorf("invalid principal key: %s", key.Content)
|
||||
}
|
||||
sshKey = fmt.Sprintf("%s # user-%d", key.Content, key.OwnerID)
|
||||
} else {
|
||||
pubKey, _, _, _, err := ssh.ParseAuthorizedKey([]byte(key.Content))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
sshKeyMarshalled := strings.TrimSpace(string(ssh.MarshalAuthorizedKey(pubKey)))
|
||||
sshKey = fmt.Sprintf("%s user-%d", sshKeyMarshalled, key.OwnerID)
|
||||
}
|
||||
|
||||
// now the key is valid, the code below could only return template/IO related errors
|
||||
sbCmd := &strings.Builder{}
|
||||
err = setting.SSH.AuthorizedKeysCommandTemplateTemplate.Execute(sbCmd, map[string]any{
|
||||
@ -69,9 +100,7 @@ func writeAuthorizedStringForKey(key *PublicKey, w io.Writer) (keyValid bool, er
|
||||
return true, err
|
||||
}
|
||||
sshCommandEscaped := util.ShellEscape(sbCmd.String())
|
||||
sshKeyMarshalled := strings.TrimSpace(string(ssh.MarshalAuthorizedKey(pubKey)))
|
||||
sshKeyComment := fmt.Sprintf("user-%d", key.OwnerID)
|
||||
_, err = fmt.Fprintf(w, tpl, sshCommandEscaped, sshKeyMarshalled, sshKeyComment)
|
||||
_, err = fmt.Fprintf(w, tpl, sshCommandEscaped, sshKey)
|
||||
return true, err
|
||||
}
|
||||
|
||||
|
||||
90
models/asymkey/ssh_key_authorized_keys_test.go
Normal file
90
models/asymkey/ssh_key_authorized_keys_test.go
Normal file
@ -0,0 +1,90 @@
|
||||
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package asymkey
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestWriteAuthorizedStringForKey(t *testing.T) {
|
||||
defer test.MockVariableValue(&setting.AppPath, "/tmp/gitea")()
|
||||
defer test.MockVariableValue(&setting.CustomConf, "/tmp/app.ini")()
|
||||
writeKey := func(t *testing.T, key *PublicKey) (bool, string, error) {
|
||||
sb := &strings.Builder{}
|
||||
valid, err := writeAuthorizedStringForKey(key, sb)
|
||||
return valid, sb.String(), err
|
||||
}
|
||||
const validKeyContent = `ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICV0MGX/W9IvLA4FXpIuUcdDcbj5KX4syHgsTy7soVgf`
|
||||
|
||||
testValid := func(t *testing.T, key *PublicKey, expected string) {
|
||||
valid, content, err := writeKey(t, key)
|
||||
assert.True(t, valid)
|
||||
assert.Equal(t, expected, content)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
testInvalid := func(t *testing.T, key *PublicKey) {
|
||||
valid, content, err := writeKey(t, key)
|
||||
assert.False(t, valid)
|
||||
assert.Empty(t, content)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
t.Run("PublicKey", func(t *testing.T) {
|
||||
testValid(t, &PublicKey{
|
||||
OwnerID: 123,
|
||||
Content: validKeyContent + " any-comment",
|
||||
Type: KeyTypeUser,
|
||||
}, `# gitea public key
|
||||
command="/tmp/gitea --config=/tmp/app.ini serv key-0",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty,no-user-rc,restrict ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICV0MGX/W9IvLA4FXpIuUcdDcbj5KX4syHgsTy7soVgf user-123
|
||||
`)
|
||||
})
|
||||
|
||||
t.Run("PublicKeyWithNewLine", func(t *testing.T) {
|
||||
testValid(t, &PublicKey{
|
||||
OwnerID: 123,
|
||||
Content: validKeyContent + "\nany-more", // the new line should be ignored
|
||||
Type: KeyTypeUser,
|
||||
}, `# gitea public key
|
||||
command="/tmp/gitea --config=/tmp/app.ini serv key-0",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty,no-user-rc,restrict ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICV0MGX/W9IvLA4FXpIuUcdDcbj5KX4syHgsTy7soVgf user-123
|
||||
`)
|
||||
})
|
||||
|
||||
t.Run("PublicKeyInvalid", func(t *testing.T) {
|
||||
testInvalid(t, &PublicKey{
|
||||
OwnerID: 123,
|
||||
Content: validKeyContent + "any-more",
|
||||
Type: KeyTypeUser,
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Principal", func(t *testing.T) {
|
||||
testValid(t, &PublicKey{
|
||||
OwnerID: 123,
|
||||
Content: "any-content",
|
||||
Type: KeyTypePrincipal,
|
||||
}, `# gitea public key
|
||||
command="/tmp/gitea --config=/tmp/app.ini serv key-0",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty,no-user-rc,restrict any-content # user-123
|
||||
`)
|
||||
})
|
||||
|
||||
t.Run("PrincipalInvalid", func(t *testing.T) {
|
||||
testInvalid(t, &PublicKey{
|
||||
OwnerID: 123,
|
||||
Content: "a b",
|
||||
Type: KeyTypePrincipal,
|
||||
})
|
||||
testInvalid(t, &PublicKey{
|
||||
OwnerID: 123,
|
||||
Content: "a\nb",
|
||||
Type: KeyTypePrincipal,
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -32,7 +32,7 @@ type LocaleStore interface {
|
||||
// HasLang returns whether a given language is present in the store
|
||||
HasLang(langName string) bool
|
||||
// AddLocaleByIni adds a new language to the store
|
||||
AddLocaleByIni(langName, langDesc string, source, moreSource []byte) error
|
||||
AddLocaleByJSON(langName, langDesc string, source, moreSource []byte) error
|
||||
}
|
||||
|
||||
// ResetDefaultLocales resets the current default locales
|
||||
|
||||
@ -13,24 +13,23 @@ import (
|
||||
|
||||
func TestLocaleStore(t *testing.T) {
|
||||
testData1 := []byte(`
|
||||
.dot.name = Dot Name
|
||||
fmt = %[1]s %[2]s
|
||||
{
|
||||
".dot.name": "Dot Name",
|
||||
"fmt": "%[1]s %[2]s",
|
||||
|
||||
[section]
|
||||
sub = Sub String
|
||||
mixed = test value; <span style="color: red\; background: none;">%s</span>
|
||||
`)
|
||||
"section.sub": "Sub String",
|
||||
"section.mixed": "test value; <span style=\"color: red; background: none;\">%s</span>"
|
||||
}`)
|
||||
|
||||
testData2 := []byte(`
|
||||
fmt = %[2]s %[1]s
|
||||
|
||||
[section]
|
||||
sub = Changed Sub String
|
||||
`)
|
||||
{
|
||||
"fmt": "%[2]s %[1]s",
|
||||
"section.sub": "Changed Sub String"
|
||||
}`)
|
||||
|
||||
ls := NewLocaleStore()
|
||||
assert.NoError(t, ls.AddLocaleByIni("lang1", "Lang1", testData1, nil))
|
||||
assert.NoError(t, ls.AddLocaleByIni("lang2", "Lang2", testData2, nil))
|
||||
assert.NoError(t, ls.AddLocaleByJSON("lang1", "Lang1", testData1, nil))
|
||||
assert.NoError(t, ls.AddLocaleByJSON("lang2", "Lang2", testData2, nil))
|
||||
ls.SetDefaultLang("lang1")
|
||||
|
||||
lang1, _ := ls.Locale("lang1")
|
||||
@ -69,17 +68,21 @@ sub = Changed Sub String
|
||||
|
||||
func TestLocaleStoreMoreSource(t *testing.T) {
|
||||
testData1 := []byte(`
|
||||
a=11
|
||||
b=12
|
||||
{
|
||||
"a": "11",
|
||||
"b": "12"
|
||||
}
|
||||
`)
|
||||
|
||||
testData2 := []byte(`
|
||||
b=21
|
||||
c=22
|
||||
{
|
||||
"b": "21",
|
||||
"c": "22"
|
||||
}
|
||||
`)
|
||||
|
||||
ls := NewLocaleStore()
|
||||
assert.NoError(t, ls.AddLocaleByIni("lang1", "Lang1", testData1, testData2))
|
||||
assert.NoError(t, ls.AddLocaleByJSON("lang1", "Lang1", testData1, testData2))
|
||||
lang1, _ := ls.Locale("lang1")
|
||||
assert.Equal(t, "11", lang1.TrString("a"))
|
||||
assert.Equal(t, "21", lang1.TrString("b"))
|
||||
@ -120,7 +123,7 @@ func (e *errorPointerReceiver) Error() string {
|
||||
|
||||
func TestLocaleWithTemplate(t *testing.T) {
|
||||
ls := NewLocaleStore()
|
||||
assert.NoError(t, ls.AddLocaleByIni("lang1", "Lang1", []byte(`key=<a>%s</a>`), nil))
|
||||
assert.NoError(t, ls.AddLocaleByJSON("lang1", "Lang1", []byte(`{"key":"<a>%s</a>"}`), nil))
|
||||
lang1, _ := ls.Locale("lang1")
|
||||
|
||||
tmpl := template.New("test").Funcs(template.FuncMap{"tr": lang1.TrHTML})
|
||||
@ -150,57 +153,3 @@ func TestLocaleWithTemplate(t *testing.T) {
|
||||
assert.Equal(t, c.want, buf.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocaleStoreQuirks(t *testing.T) {
|
||||
const nl = "\n"
|
||||
q := func(q1, s string, q2 ...string) string {
|
||||
return q1 + s + strings.Join(q2, "")
|
||||
}
|
||||
testDataList := []struct {
|
||||
in string
|
||||
out string
|
||||
hint string
|
||||
}{
|
||||
{` xx`, `xx`, "simple, no quote"},
|
||||
{`" xx"`, ` xx`, "simple, double-quote"},
|
||||
{`' xx'`, ` xx`, "simple, single-quote"},
|
||||
{"` xx`", ` xx`, "simple, back-quote"},
|
||||
|
||||
{`x\"y`, `x\"y`, "no unescape, simple"},
|
||||
{q(`"`, `x\"y`, `"`), `"x\"y"`, "unescape, double-quote"},
|
||||
{q(`'`, `x\"y`, `'`), `x\"y`, "no unescape, single-quote"},
|
||||
{q("`", `x\"y`, "`"), `x\"y`, "no unescape, back-quote"},
|
||||
|
||||
{q(`"`, `x\"y`) + nl + "b=", `"x\"y`, "half open, double-quote"},
|
||||
{q(`'`, `x\"y`) + nl + "b=", `'x\"y`, "half open, single-quote"},
|
||||
{q("`", `x\"y`) + nl + "b=`", `x\"y` + nl + "b=", "half open, back-quote, multi-line"},
|
||||
|
||||
{`x ; y`, `x ; y`, "inline comment (;)"},
|
||||
{`x # y`, `x # y`, "inline comment (#)"},
|
||||
{`x \; y`, `x ; y`, `inline comment (\;)`},
|
||||
{`x \# y`, `x # y`, `inline comment (\#)`},
|
||||
}
|
||||
|
||||
for _, testData := range testDataList {
|
||||
ls := NewLocaleStore()
|
||||
err := ls.AddLocaleByIni("lang1", "Lang1", []byte("a="+testData.in), nil)
|
||||
lang1, _ := ls.Locale("lang1")
|
||||
assert.NoError(t, err, testData.hint)
|
||||
assert.Equal(t, testData.out, lang1.TrString("a"), testData.hint)
|
||||
assert.NoError(t, ls.Close())
|
||||
}
|
||||
|
||||
// TODO: Crowdin needs the strings to be quoted correctly and doesn't like incomplete quotes
|
||||
// and Crowdin always outputs quoted strings if there are quotes in the strings.
|
||||
// So, Gitea's `key="quoted" unquoted` content shouldn't be used on Crowdin directly,
|
||||
// it should be converted to `key="\"quoted\" unquoted"` first.
|
||||
// TODO: We can not use UnescapeValueDoubleQuotes=true, because there are a lot of back-quotes in en-US.ini,
|
||||
// then Crowdin will output:
|
||||
// > key = "`x \" y`"
|
||||
// Then Gitea will read a string with back-quotes, which is incorrect.
|
||||
// TODO: Crowdin might generate multi-line strings, quoted by double-quote, it's not supported by LocaleStore
|
||||
// LocaleStore uses back-quote for multi-line strings, it's not supported by Crowdin.
|
||||
// TODO: Crowdin doesn't support back-quote as string quoter, it mainly uses double-quote
|
||||
// so, the following line will be parsed as: value="`first", comment="second`" on Crowdin
|
||||
// > a = `first; second`
|
||||
}
|
||||
|
||||
@ -10,8 +10,8 @@ import (
|
||||
"html/template"
|
||||
"slices"
|
||||
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
)
|
||||
|
||||
// This file implements the static LocaleStore that will not watch for changes
|
||||
@ -40,8 +40,8 @@ func NewLocaleStore() LocaleStore {
|
||||
return &localeStore{localeMap: make(map[string]*locale), trKeyToIdxMap: make(map[string]int)}
|
||||
}
|
||||
|
||||
// AddLocaleByIni adds locale by ini into the store
|
||||
func (store *localeStore) AddLocaleByIni(langName, langDesc string, source, moreSource []byte) error {
|
||||
// AddLocaleByJSON adds locale by JSON into the store
|
||||
func (store *localeStore) AddLocaleByJSON(langName, langDesc string, source, moreSource []byte) error {
|
||||
if _, ok := store.localeMap[langName]; ok {
|
||||
return errors.New("lang has already been added")
|
||||
}
|
||||
@ -52,28 +52,46 @@ func (store *localeStore) AddLocaleByIni(langName, langDesc string, source, more
|
||||
l := &locale{store: store, langName: langName, idxToMsgMap: make(map[int]string)}
|
||||
store.localeMap[l.langName] = l
|
||||
|
||||
iniFile, err := setting.NewConfigProviderForLocale(source, moreSource)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load ini: %w", err)
|
||||
}
|
||||
|
||||
for _, section := range iniFile.Sections() {
|
||||
for _, key := range section.Keys() {
|
||||
var trKey string
|
||||
if section.Name() == "" || section.Name() == "DEFAULT" {
|
||||
trKey = key.Name()
|
||||
} else {
|
||||
trKey = section.Name() + "." + key.Name()
|
||||
}
|
||||
idx, ok := store.trKeyToIdxMap[trKey]
|
||||
if !ok {
|
||||
idx = len(store.trKeyToIdxMap)
|
||||
store.trKeyToIdxMap[trKey] = idx
|
||||
}
|
||||
l.idxToMsgMap[idx] = key.Value()
|
||||
addFunc := func(source []byte) error {
|
||||
if len(source) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
values := make(map[string]any)
|
||||
if err := json.Unmarshal(source, &values); err != nil {
|
||||
return fmt.Errorf("unable to load json: %w", err)
|
||||
}
|
||||
for trKey, value := range values {
|
||||
switch v := value.(type) {
|
||||
case string:
|
||||
idx, ok := store.trKeyToIdxMap[trKey]
|
||||
if !ok {
|
||||
idx = len(store.trKeyToIdxMap)
|
||||
store.trKeyToIdxMap[trKey] = idx
|
||||
}
|
||||
l.idxToMsgMap[idx] = v
|
||||
case map[string]any:
|
||||
for key, val := range v {
|
||||
idx, ok := store.trKeyToIdxMap[trKey+"."+key]
|
||||
if !ok {
|
||||
idx = len(store.trKeyToIdxMap)
|
||||
store.trKeyToIdxMap[trKey+"."+key] = idx
|
||||
}
|
||||
l.idxToMsgMap[idx] = val.(string)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unsupported value type %T for key %q", v, trKey)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := addFunc(source); err != nil {
|
||||
return fmt.Errorf("unable to load json: %w", err)
|
||||
}
|
||||
if err := addFunc(moreSource); err != nil {
|
||||
return fmt.Errorf("unable to load json: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@ -74,6 +74,9 @@ func InitLocales(ctx context.Context) {
|
||||
|
||||
localeData := make(map[string][]byte, len(localeNames))
|
||||
for _, name := range localeNames {
|
||||
if !strings.HasPrefix(name, "locale_") || !strings.HasSuffix(name, ".json") {
|
||||
continue
|
||||
}
|
||||
localeData[name], err = options.Locale(name)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to load %s locale file. %v", name, err)
|
||||
@ -90,14 +93,14 @@ func InitLocales(ctx context.Context) {
|
||||
var localeDataBase []byte
|
||||
if i == 0 && setting.Langs[0] != "en-US" {
|
||||
// Only en-US has complete translations. When use other language as default, the en-US should still be used as fallback.
|
||||
localeDataBase = localeData["locale_en-US.ini"]
|
||||
localeDataBase = localeData["locale_en-US.json"]
|
||||
if localeDataBase == nil {
|
||||
log.Fatal("Failed to load locale_en-US.ini file.")
|
||||
log.Fatal("Failed to load locale_en-US.json file.")
|
||||
}
|
||||
}
|
||||
|
||||
key := "locale_" + setting.Langs[i] + ".ini"
|
||||
if err = i18n.DefaultLocales.AddLocaleByIni(setting.Langs[i], setting.Names[i], localeDataBase, localeData[key]); err != nil {
|
||||
key := "locale_" + setting.Langs[i] + ".json"
|
||||
if err = i18n.DefaultLocales.AddLocaleByJSON(setting.Langs[i], setting.Names[i], localeDataBase, localeData[key]); err != nil {
|
||||
log.Error("Failed to set messages to %s: %v", setting.Langs[i], err)
|
||||
}
|
||||
}
|
||||
|
||||
3790
options/locale/locale_ar-SA.json
Normal file
3790
options/locale/locale_ar-SA.json
Normal file
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_bg-BG.json
Normal file
3790
options/locale/locale_bg-BG.json
Normal file
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_bn-BD.json
Normal file
3790
options/locale/locale_bn-BD.json
Normal file
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_bn-IN.json
Normal file
3790
options/locale/locale_bn-IN.json
Normal file
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_ca-ES.json
Normal file
3790
options/locale/locale_ca-ES.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_cs-CZ.json
Normal file
3790
options/locale/locale_cs-CZ.json
Normal file
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_da-DK.json
Normal file
3790
options/locale/locale_da-DK.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_de-DE.json
Normal file
3790
options/locale/locale_de-DE.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_el-GR.json
Normal file
3790
options/locale/locale_el-GR.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -3937,7 +3937,6 @@ general.collaborative_owner_not_exist = The collaborative owner does not exist.
|
||||
general.remove_collaborative_owner = Remove Collaborative Owner
|
||||
general.remove_collaborative_owner_desc = Removing a collaborative owner will prevent the repositories of the owner from accessing the actions in this repository. Continue?
|
||||
|
||||
|
||||
general.token_permissions = Workflow Permissions
|
||||
general.token_permissions.description = Configure the default permissions granted to the GITHUB_TOKEN when running workflows in this repository.
|
||||
general.token_permissions.mode = Permission Mode
|
||||
|
||||
3790
options/locale/locale_en-US.json
Normal file
3790
options/locale/locale_en-US.json
Normal file
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_eo-UY.json
Normal file
3790
options/locale/locale_eo-UY.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_es-ES.json
Normal file
3790
options/locale/locale_es-ES.json
Normal file
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_eu-ES.json
Normal file
3790
options/locale/locale_eu-ES.json
Normal file
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_fa-AF.json
Normal file
3790
options/locale/locale_fa-AF.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_fa-IR.json
Normal file
3790
options/locale/locale_fa-IR.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_fi-FI.json
Normal file
3790
options/locale/locale_fi-FI.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_fr-FR.json
Normal file
3790
options/locale/locale_fr-FR.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_ga-IE.json
Normal file
3790
options/locale/locale_ga-IE.json
Normal file
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_he-IL.json
Normal file
3790
options/locale/locale_he-IL.json
Normal file
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_hi-IN.json
Normal file
3790
options/locale/locale_hi-IN.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_hu-HU.json
Normal file
3790
options/locale/locale_hu-HU.json
Normal file
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_hy-AM.json
Normal file
3790
options/locale/locale_hy-AM.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_id-ID.json
Normal file
3790
options/locale/locale_id-ID.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_is-IS.json
Normal file
3790
options/locale/locale_is-IS.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_it-IT.json
Normal file
3790
options/locale/locale_it-IT.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_ja-JP.json
Normal file
3790
options/locale/locale_ja-JP.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_ko-KR.json
Normal file
3790
options/locale/locale_ko-KR.json
Normal file
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_lt-LT.json
Normal file
3790
options/locale/locale_lt-LT.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_lv-LV.json
Normal file
3790
options/locale/locale_lv-LV.json
Normal file
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_ml-IN.json
Normal file
3790
options/locale/locale_ml-IN.json
Normal file
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_mn-MN.json
Normal file
3790
options/locale/locale_mn-MN.json
Normal file
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_nb-NO.json
Normal file
3790
options/locale/locale_nb-NO.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_nl-NL.json
Normal file
3790
options/locale/locale_nl-NL.json
Normal file
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_nn-NO.json
Normal file
3790
options/locale/locale_nn-NO.json
Normal file
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_no-NO.json
Normal file
3790
options/locale/locale_no-NO.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_pl-PL.json
Normal file
3790
options/locale/locale_pl-PL.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_pt-BR.json
Normal file
3790
options/locale/locale_pt-BR.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_pt-PT.json
Normal file
3790
options/locale/locale_pt-PT.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_ru-RU.json
Normal file
3790
options/locale/locale_ru-RU.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_si-LK.json
Normal file
3790
options/locale/locale_si-LK.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_sk-SK.json
Normal file
3790
options/locale/locale_sk-SK.json
Normal file
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_sr-SP.json
Normal file
3790
options/locale/locale_sr-SP.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_sv-SE.json
Normal file
3790
options/locale/locale_sv-SE.json
Normal file
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_sw-KE.json
Normal file
3790
options/locale/locale_sw-KE.json
Normal file
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_ta-IN.json
Normal file
3790
options/locale/locale_ta-IN.json
Normal file
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_tk-TM.json
Normal file
3790
options/locale/locale_tk-TM.json
Normal file
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_tlh-AA.json
Normal file
3790
options/locale/locale_tlh-AA.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_tr-TR.json
Normal file
3790
options/locale/locale_tr-TR.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_uk-UA.json
Normal file
3790
options/locale/locale_uk-UA.json
Normal file
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_vi-VN.json
Normal file
3790
options/locale/locale_vi-VN.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_zh-CN.json
Normal file
3790
options/locale/locale_zh-CN.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,988 +0,0 @@
|
||||
home=首頁
|
||||
dashboard=控制面版
|
||||
explore=探索
|
||||
help=說明
|
||||
sign_in=登入
|
||||
sign_in_or=或
|
||||
sign_out=登出
|
||||
link_account=連結帳戶
|
||||
register=註冊
|
||||
version=版本
|
||||
page=頁面
|
||||
template=樣板
|
||||
language=語言
|
||||
notifications=訊息
|
||||
|
||||
password=密碼
|
||||
re_type=確認密碼
|
||||
passcode=驗證碼
|
||||
|
||||
|
||||
repository=儲存庫
|
||||
organization=組織
|
||||
mirror=鏡像
|
||||
new_repo=新增儲存庫
|
||||
new_migrate=遷移外部儲存庫
|
||||
new_mirror=新鏡像
|
||||
new_fork=Fork 新的儲存庫
|
||||
new_org=新增組織
|
||||
manage_org=管理組織
|
||||
account_settings=帳號設定
|
||||
settings=設定
|
||||
your_settings=組織設定
|
||||
|
||||
all=所有
|
||||
sources=來源
|
||||
mirrors=鏡像
|
||||
collaborative=協同者
|
||||
forks=複製列表
|
||||
|
||||
activities=活動
|
||||
pull_requests=合併請求
|
||||
issues=問題
|
||||
|
||||
cancel=取消
|
||||
remove=移除成員
|
||||
edit=編輯
|
||||
|
||||
enabled=已啟用
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
concept_code_repository=儲存庫
|
||||
|
||||
|
||||
|
||||
name=組織名稱
|
||||
|
||||
filter.is_template=樣板
|
||||
filter.private=私有庫
|
||||
|
||||
|
||||
[search]
|
||||
|
||||
[aria]
|
||||
|
||||
[heatmap]
|
||||
|
||||
[editor]
|
||||
|
||||
[filter]
|
||||
|
||||
[error]
|
||||
|
||||
[startpage]
|
||||
|
||||
[install]
|
||||
install=安裝頁面
|
||||
db_title=資料庫設定
|
||||
db_type=資料庫類型
|
||||
host=主機
|
||||
password=密碼
|
||||
db_name=資料庫名稱
|
||||
path=資料庫文件路徑
|
||||
|
||||
repo_path=儲存庫的根目錄
|
||||
log_root_path=日誌路徑
|
||||
|
||||
optional_title=可選設定
|
||||
smtp_addr=SMTP 主機地址
|
||||
smtp_port=SMTP 主機端口
|
||||
disable_gravatar=禁用 Gravatar 頭像
|
||||
federated_avatar_lookup=開啟聯合頭像
|
||||
federated_avatar_lookup_popup=開啟聯合頭像查詢並使用基於開放源碼的 libravatar 服務
|
||||
enable_captcha_popup=要求在用戶註冊時輸入驗證碼
|
||||
admin_password=管理員密碼
|
||||
confirm_password=確認密碼
|
||||
install_btn_confirm=立即安裝
|
||||
test_git_failed=無法識別 'git' 命令:%v
|
||||
save_config_failed=儲存設定失敗:%v
|
||||
|
||||
[home]
|
||||
password_holder=密碼
|
||||
switch_dashboard_context=切換控制面版用戶
|
||||
my_repos=儲存庫管理
|
||||
collaborative_repos=參與協作的儲存庫
|
||||
my_orgs=我的組織
|
||||
my_mirrors=我的鏡像
|
||||
view_home=訪問 %s
|
||||
|
||||
|
||||
show_private=私有庫
|
||||
|
||||
issues.in_your_repos=屬於該用戶儲存庫的
|
||||
|
||||
|
||||
[explore]
|
||||
repos=儲存庫
|
||||
users=使用者
|
||||
organizations=組織
|
||||
|
||||
[auth]
|
||||
forgot_password_title=忘記密碼
|
||||
forgot_password=忘記密碼?
|
||||
active_your_account=啟用您的帳戶
|
||||
has_unconfirmed_mail=%s 您好,您有一封發送至( <b>%s</b>) 但未被確認的郵件。如果您未收到啟用郵件,或需要重新發送,請單擊下方的按鈕。
|
||||
resend_mail=單擊此處重新發送確認郵件
|
||||
email_not_associate=此電子郵件地址未與任何帳戶連結
|
||||
verify=驗證
|
||||
scratch_code=備用碼
|
||||
use_scratch_code=使用備用碼
|
||||
twofa_scratch_used=你已經使用了你的備用碼。你將會被轉到兩步驟驗證設定頁面以便移除你已註冊設備或重新產生新的備用碼。
|
||||
twofa_scratch_token_incorrect=您的備用碼不正確
|
||||
login_userpass=登入
|
||||
oauth_signin_submit=連結帳戶
|
||||
openid_connect_submit=連接
|
||||
openid_connect_title=連接到現有帳戶
|
||||
openid_register_title=建立新帳戶
|
||||
|
||||
[mail]
|
||||
|
||||
activate_account=請啟用您的帳戶
|
||||
|
||||
activate_email=請驗證您的郵箱地址
|
||||
|
||||
|
||||
|
||||
register_success=註冊成功
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
[modal]
|
||||
yes=確認操作
|
||||
no=取消操作
|
||||
cancel=取消
|
||||
|
||||
[form]
|
||||
UserName=使用者名稱
|
||||
RepoName=儲存庫名稱
|
||||
Email=郵箱地址
|
||||
Password=密碼
|
||||
Retype=確認密碼
|
||||
SSHTitle=SSH 金鑰名稱
|
||||
HttpsUrl=HTTPS URL 地址
|
||||
PayloadUrl=推送地址
|
||||
TeamName=團隊名稱
|
||||
AuthName=認證名稱
|
||||
AdminEmail=管理員郵箱
|
||||
|
||||
NewBranchName=新的分支名稱
|
||||
CommitSummary=提交摘要
|
||||
CommitMessage=提交訊息
|
||||
CommitChoice=提交選擇
|
||||
TreeName=檔案路徑
|
||||
Content=內容
|
||||
|
||||
|
||||
require_error=不能為空。
|
||||
size_error=長度必須為 %s。
|
||||
min_size_error=長度最小為 %s 個字符。
|
||||
max_size_error=長度最大為 %s 個字符。
|
||||
email_error=不是一個有效的郵箱地址。
|
||||
unknown_error=未知錯誤:
|
||||
|
||||
user_not_exist=該使用者名稱並不存在
|
||||
|
||||
auth_failed=授權驗證失敗:%v
|
||||
|
||||
|
||||
target_branch_not_exist=目標分支不存在
|
||||
|
||||
|
||||
[user]
|
||||
repositories=儲存庫列表
|
||||
activity=公開活動
|
||||
followers=關註者
|
||||
following=關註中
|
||||
follow=關注
|
||||
unfollow=取消關注
|
||||
|
||||
|
||||
|
||||
[settings]
|
||||
profile=個人訊息
|
||||
password=修改密碼
|
||||
avatar=頭像
|
||||
ssh_gpg_keys=SSH / GPG 金鑰
|
||||
social=社交帳號綁定
|
||||
orgs=管理組織
|
||||
repos=儲存庫管理
|
||||
delete=刪除帳戶
|
||||
organization=組織管理
|
||||
|
||||
public_profile=公開訊息
|
||||
full_name=自定義名稱
|
||||
website=個人網站
|
||||
location=所在地區
|
||||
update_profile=更新訊息
|
||||
update_profile_success=您的個人資料已被更新
|
||||
continue=繼續操作
|
||||
cancel=取消操作
|
||||
language=語言
|
||||
comment_type_group_title=標題
|
||||
|
||||
federated_avatar_lookup=Federated Avatar 查詢
|
||||
enable_custom_avatar=啟動自定義頭像
|
||||
choose_new_avatar=選擇新的頭像
|
||||
delete_current_avatar=刪除當前頭像
|
||||
|
||||
old_password=當前密碼
|
||||
new_password=新的密碼
|
||||
|
||||
emails=電子郵件地址
|
||||
primary=主要
|
||||
activated=已啟用
|
||||
delete_email=移除成員
|
||||
add_openid=新增 OpenID URI
|
||||
|
||||
manage_ssh_keys=管理 SSH 金鑰
|
||||
manage_gpg_keys=管理 GPG 金鑰
|
||||
add_key=增加金鑰
|
||||
ssh_helper=<strong>需要協助?</strong> 查詢GitHub的文件以 <a href="%s">您自有SSH金鑰</a> or solve <a href="%s">common problems</a> you may encounter using SSH.
|
||||
gpg_helper=<strong>需要協助嗎?</strong>建議可看看 GitHub 的 <a href="%s">about GPG</a> 文件。
|
||||
add_new_key=增加 SSH 金鑰
|
||||
add_new_gpg_key=新增 GPG 金鑰
|
||||
gpg_key_verify=驗證
|
||||
gpg_token=令牌
|
||||
ssh_key_verify=驗證
|
||||
ssh_token=令牌
|
||||
subkeys=次金鑰
|
||||
key_id=金鑰 ID
|
||||
key_name=金鑰名稱
|
||||
key_content=金鑰內容
|
||||
principal_content=金鑰文本
|
||||
delete_key=移除成員
|
||||
valid_forever=永遠有效
|
||||
last_used=上次使用在
|
||||
no_activity=沒有最近活動
|
||||
can_read_info=已讀
|
||||
key_state_desc=該金鑰在 7 天內被使用過
|
||||
token_state_desc=此 token 在過去七天內曾經被使用過
|
||||
show_openid=在設定檔顯示
|
||||
hide_openid=從設定檔隱藏
|
||||
manage_social=管理關聯社交帳戶
|
||||
|
||||
generate_new_token=生成新的令牌
|
||||
token_name=令牌名稱
|
||||
generate_token=生成令牌
|
||||
delete_token=删除令牌
|
||||
access_token_deletion_cancel_action=取消
|
||||
permission_read=已讀
|
||||
|
||||
oauth2_client_secret=用戶端金鑰
|
||||
oauth2_application_edit=編輯
|
||||
|
||||
|
||||
twofa_is_enrolled=您的帳號已經<strong>啟用</strong>兩步驟驗證。
|
||||
twofa_not_enrolled=您的帳號目前尚未啟用兩步驟驗證。
|
||||
twofa_disabled=兩步驟驗證已經被關閉。
|
||||
scan_this_image=使用您的授權應用程式來掃瞄圖片:
|
||||
or_enter_secret=或者輸入密碼: %s
|
||||
|
||||
|
||||
link_account=連結帳戶
|
||||
|
||||
|
||||
orgs_none=您尚未成為任一組織的成員。
|
||||
|
||||
delete_account=刪除當前帳戶
|
||||
confirm_delete_account=確認刪除帳戶
|
||||
|
||||
|
||||
visibility.private=私有庫
|
||||
|
||||
[repo]
|
||||
owner=擁有者
|
||||
repo_name=儲存庫名稱
|
||||
template=樣板
|
||||
visibility=可見度
|
||||
fork_repo=複製儲存庫
|
||||
fork_from=複製自
|
||||
repo_desc=儲存庫描述
|
||||
license=授權許可
|
||||
create_repo=建立儲存庫
|
||||
default_branch=默認分支
|
||||
mirror_prune=裁減
|
||||
watchers=關注者
|
||||
stargazers=稱讚者
|
||||
forks=複製儲存庫
|
||||
|
||||
|
||||
|
||||
desc.private=私有庫
|
||||
desc.template=樣板
|
||||
|
||||
template.avatar=頭像
|
||||
|
||||
|
||||
|
||||
migrate_items_issues=問題數
|
||||
migrate_items_pullrequests=合併請求
|
||||
migrate_items_releases=版本發佈
|
||||
migrate_repo=遷移儲存庫
|
||||
migrate.permission_denied=您並沒有導入本地儲存庫的權限。
|
||||
migrate.failed=遷移失敗:%v
|
||||
|
||||
mirror_from=镜像来自
|
||||
forked_from=複製自
|
||||
unwatch=取消關注
|
||||
watch=關註
|
||||
unstar=取消收藏
|
||||
star=收藏
|
||||
fork=複製
|
||||
|
||||
quick_guide=快速幫助
|
||||
clone_this_repo=複製當前儲存庫
|
||||
create_new_repo_command=從命令列建立新儲存庫。
|
||||
push_exist_repo=從命令列推送已存在的儲存庫
|
||||
|
||||
code=程式碼
|
||||
branch=分支
|
||||
tree=目錄樹
|
||||
filter_branch_and_tag=過濾分支或標籤
|
||||
branches=分支列表
|
||||
tags=標籤列表
|
||||
issues=問題管理
|
||||
pulls=合併請求
|
||||
labels=標籤
|
||||
|
||||
milestones=里程碑
|
||||
commits=提交歷史
|
||||
releases=版本發佈
|
||||
file_raw=原始文件
|
||||
file_history=文件歷史
|
||||
file_view_raw=查看原始文件
|
||||
file_permalink=永久連結
|
||||
|
||||
|
||||
editor.preview_changes=預覽更改
|
||||
editor.or=或
|
||||
editor.cancel_lower=取消
|
||||
editor.commit_changes=提交更改嗎?
|
||||
editor.commit_directly_to_this_branch=直接提交到 <strong class="branch-name">%s</strong> 分支。
|
||||
editor.create_new_branch=建立 <strong>新的分支</strong> 為此提交和開始合併請求。
|
||||
editor.cancel=取消
|
||||
editor.no_changes_to_show=沒有可以顯示的變更。
|
||||
|
||||
|
||||
commits.commits=次程式碼提交
|
||||
commits.author=作者
|
||||
commits.message=備註
|
||||
commits.date=提交日期
|
||||
commits.older=更舊的提交
|
||||
commits.newer=更新的提交
|
||||
commits.signed_by=簽署人
|
||||
|
||||
|
||||
|
||||
|
||||
projects.description_placeholder=組織描述
|
||||
projects.title=標題
|
||||
projects.template.desc=樣板
|
||||
projects.column.edit_title=組織名稱
|
||||
projects.column.new_title=組織名稱
|
||||
|
||||
issues.new=建立問題
|
||||
issues.new.labels=標籤
|
||||
issues.new.no_label=未選擇標籤
|
||||
issues.new.clear_labels=清除已選取標籤
|
||||
issues.new.milestone=里程碑
|
||||
issues.new.no_milestone=未選擇里程碑
|
||||
issues.new.clear_milestone=清除已選取里程碑
|
||||
issues.create=建立問題
|
||||
issues.new_label=建立標籤
|
||||
issues.new_label_desc_placeholder=組織描述
|
||||
issues.create_label=建立標籤
|
||||
issues.label_templates.title=載入一組預定義的標籤
|
||||
issues.label_templates.helper=選擇一個標籤集
|
||||
issues.add_milestone_at=`新增至<b>%s</b> 里程碑 %s`
|
||||
issues.change_milestone_at=`%[3]s 修改了里程碑 <b>%[1]s</b> 到 <b>%[2]s</b>`
|
||||
issues.remove_milestone_at=`從里程碑 %[2]s 刪除 <b>%[1]s</b>`
|
||||
issues.deleted_milestone=`(已刪除)`
|
||||
issues.deleted_project=`(已刪除)`
|
||||
issues.self_assign_at=將 %s 指派給自己
|
||||
issues.add_assignee_at=`被<b>%s</b> %s指派`
|
||||
issues.delete_branch_at=`刪除分支 <b>%s</b> %s`
|
||||
issues.filter_label=標籤篩選
|
||||
issues.filter_milestone=里程碑篩選
|
||||
issues.filter_assignee=指派人篩選
|
||||
issues.filter_type=類型篩選
|
||||
issues.filter_type.all_issues=所有問題
|
||||
issues.filter_type.assigned_to_you=指派給您的
|
||||
issues.filter_type.created_by_you=由您建立的
|
||||
issues.filter_type.mentioning_you=提及您的
|
||||
issues.filter_sort=排序
|
||||
issues.filter_sort.latest=最新建立
|
||||
issues.filter_sort.oldest=最早建立
|
||||
issues.filter_sort.leastupdate=最少更新
|
||||
issues.filter_sort.mostcomment=最多評論
|
||||
issues.filter_sort.leastcomment=最少評論
|
||||
issues.action_open=開啟
|
||||
issues.action_close=關閉
|
||||
issues.action_label=標籤
|
||||
issues.action_milestone=里程碑
|
||||
issues.action_milestone_no_select=無里程碑
|
||||
issues.action_assignee=負責人
|
||||
issues.action_assignee_no_select=無負責人
|
||||
issues.opened_by=由 <a href="%[2]s">%[3]s</a> 於 %[1]s建立
|
||||
issues.previous=上一頁
|
||||
issues.next=下一頁
|
||||
issues.open_title=開啟中
|
||||
issues.closed_title=已關閉
|
||||
issues.draft_title=草稿
|
||||
issues.num_comments=%d 條評論
|
||||
issues.commented_at=` 評論 <a href="#%s"> %s</a>`
|
||||
issues.delete_comment_confirm=您確定要刪除該條評論嗎?
|
||||
issues.context.edit=編輯
|
||||
issues.reopen_issue=重新開啟
|
||||
issues.create_comment=評論
|
||||
issues.commit_ref_at=`在代碼提交 <a id="%[1]s" href="#%[1]s">%[2]s</a> 中引用了該問題`
|
||||
issues.role.owner=管理員
|
||||
issues.role.member=普通成員
|
||||
issues.sign_in_require_desc=<a href="%s"> 登入</a> 才能加入這對話。
|
||||
issues.edit=編輯
|
||||
issues.cancel=取消
|
||||
issues.save=儲存
|
||||
issues.label_title=標籤名稱
|
||||
issues.label_description=組織描述
|
||||
issues.label_color=標籤顏色
|
||||
issues.label_count=%d 個標籤
|
||||
issues.label_open_issues=%d 個開啓的問題
|
||||
issues.label_edit=編輯
|
||||
issues.label_delete=刪除
|
||||
issues.label.filter_sort.alphabetically=按字母顺序排序
|
||||
issues.label.filter_sort.reverse_alphabetically=按字母反向排序
|
||||
issues.num_participants=%d 參與者
|
||||
issues.attachment.open_tab=`在新的標籤頁中查看 '%s'`
|
||||
issues.attachment.download=`點擊下載 '%s'`
|
||||
issues.subscribe=訂閱
|
||||
issues.unsubscribe=取消訂閱
|
||||
|
||||
|
||||
|
||||
issues.due_date_form_edit=編輯
|
||||
issues.due_date_form_remove=移除成員
|
||||
issues.dependency.cancel=取消
|
||||
issues.dependency.remove=移除成員
|
||||
|
||||
|
||||
pulls.new=建立合併請求
|
||||
pulls.compare_changes=建立合併請求
|
||||
pulls.filter_branch=過濾分支
|
||||
pulls.create=建立合併請求
|
||||
pulls.merged_title_desc=於 %[4]s 將 %[1]d 次代碼提交從 <code>%[2]s</code>合併至 <code>%[3]s</code>
|
||||
pulls.tab_conversation=對話內容
|
||||
pulls.tab_commits=程式碼提交
|
||||
pulls.reopen_to_merge=請重新開啟合併請求來完成合併操作。
|
||||
pulls.merged=已合併
|
||||
pulls.can_auto_merge_desc=這個拉請求可以自動合併。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
milestones.new=新的里程碑
|
||||
milestones.closed=於 %s關閉
|
||||
milestones.no_due_date=暫無截止日期
|
||||
milestones.open=開啟
|
||||
milestones.close=關閉
|
||||
milestones.create=建立里程碑
|
||||
milestones.title=標題
|
||||
milestones.desc=描述
|
||||
milestones.due_date=截止日期(可選)
|
||||
milestones.clear=清除
|
||||
milestones.edit=編輯里程碑
|
||||
milestones.cancel=取消
|
||||
milestones.filter_sort.name=組織名稱
|
||||
milestones.filter_sort.least_complete=完成度由低到高
|
||||
milestones.filter_sort.most_complete=完成度由高到低
|
||||
milestones.filter_sort.most_issues=問題由多到少
|
||||
milestones.filter_sort.least_issues=問題由少到多
|
||||
|
||||
|
||||
|
||||
wiki.page=頁面
|
||||
wiki.filter_page=過濾頁面
|
||||
wiki.new_page=頁面
|
||||
wiki.default_commit_message=關於此次頁面修改的說明(非必要)。
|
||||
wiki.save_page=儲存頁面
|
||||
wiki.last_commit_info=%s 於 %s 修改了此頁面
|
||||
wiki.edit_page_button=修改
|
||||
wiki.new_page_button=新的頁面
|
||||
wiki.delete_page_button=刪除頁面
|
||||
wiki.page_already_exists=相同名稱的 Wiki 頁面已經存在。
|
||||
wiki.pages=所有頁面
|
||||
wiki.last_updated=最後更新於 %s
|
||||
|
||||
activity.period.daily=1 天
|
||||
activity.period.weekly=1 周
|
||||
activity.period.monthly=1 月
|
||||
activity.period.yearly=1 年
|
||||
activity.merged_prs_label=已合併
|
||||
activity.closed_issue_label=已關閉
|
||||
activity.new_issues_count_1=建立問題
|
||||
|
||||
contributors.contribution_type.commits=提交歷史
|
||||
|
||||
settings=儲存庫設定
|
||||
settings.options=儲存庫
|
||||
settings.collaboration.write=可寫權限
|
||||
settings.collaboration.read=可讀權限
|
||||
settings.collaboration.owner=管理員
|
||||
settings.collaboration.undefined=未定義
|
||||
settings.hooks=管理 Webhooks
|
||||
settings.githooks=管理 Git Hooks
|
||||
settings.basic_settings=基本設定
|
||||
settings.mirror_settings=鏡像設定
|
||||
|
||||
settings.site=官方網站
|
||||
settings.update_settings=更新儲存庫設定
|
||||
settings.advanced_settings=高級設定
|
||||
settings.external_wiki_url=外部 Wiki 連結
|
||||
settings.external_tracker_url=外部 Issue 追蹤網址
|
||||
settings.tracker_url_format=外部問題管理系統的 URL 格式
|
||||
settings.tracker_issue_style.numeric=數字
|
||||
settings.tracker_issue_style.alphanumeric=字母及數字
|
||||
settings.danger_zone=危險操作區
|
||||
settings.new_owner_has_same_repo=新的儲存庫擁有者已經存在同名儲存庫!
|
||||
settings.transfer=轉移儲存庫所有權
|
||||
settings.transfer_owner=新擁有者
|
||||
settings.delete=刪除本儲存庫
|
||||
settings.delete_notices_1=- 此操作 <strong>不可以</strong> 被回滾。
|
||||
settings.delete_collaborator=移除成員
|
||||
settings.teams=組織團隊
|
||||
settings.add_webhook=建立 Webhook
|
||||
settings.webhook.request=請求內容
|
||||
settings.webhook.response=響應內容
|
||||
settings.webhook.headers=標題
|
||||
settings.webhook.payload=金鑰文本
|
||||
settings.webhook.body=響應內容
|
||||
settings.githook_edit_desc=如果 Hook 未啟動,則會顯示樣例文件中的內容。如果想要刪除某個 Hook,則提交空白文本即可。
|
||||
settings.githook_name=Hook 名稱
|
||||
settings.githook_content=Hook 內容
|
||||
settings.update_githook=更新 Hook 設定
|
||||
settings.secret=金鑰文本
|
||||
settings.slack_username=服務名稱
|
||||
settings.slack_icon_url=圖標 URL
|
||||
settings.event_create=建立
|
||||
settings.event_fork=複製
|
||||
settings.event_push=推送
|
||||
settings.event_repository=儲存庫
|
||||
settings.event_issues=問題數
|
||||
settings.event_pull_request=合併請求
|
||||
settings.update_webhook=更新 Webhook
|
||||
settings.recent_deliveries=最近推送記錄
|
||||
settings.hook_type=Hook 類型
|
||||
settings.slack_token=令牌
|
||||
settings.slack_domain=域名
|
||||
settings.slack_channel=頻道
|
||||
settings.deploy_keys=管理部署金鑰
|
||||
settings.add_deploy_key=新增部署金鑰
|
||||
settings.title=標題
|
||||
settings.deploy_key_content=金鑰文本
|
||||
settings.edit_protected_branch=編輯
|
||||
|
||||
diff.browse_source=瀏覽代碼
|
||||
diff.parent=父節點
|
||||
diff.commit=當前提交
|
||||
diff.data_not_available=沒有內容比較可以使用
|
||||
diff.show_split_view=分割檢視
|
||||
diff.show_unified_view=統一視圖
|
||||
diff.stats_desc=共有 <strong> %d 個文件被更改</strong>,包括 <strong>%d 次插入</strong> 和 <strong>%d 次删除</strong>
|
||||
diff.bin=二進制
|
||||
diff.view_file=查看文件
|
||||
diff.file_byte_size=大小
|
||||
diff.file_suppressed=文件差異過大導致無法顯示
|
||||
|
||||
release.releases=版本發佈
|
||||
release.new_release=發佈新版本
|
||||
release.draft=草稿
|
||||
release.prerelease=預發佈版本
|
||||
release.stable=穩定
|
||||
release.edit=編輯
|
||||
release.source_code=程式碼
|
||||
release.tag_name=標籤名稱
|
||||
release.target=目標分支
|
||||
release.cancel=取消
|
||||
release.publish=發佈版本
|
||||
release.save_draft=儲存草稿
|
||||
release.deletion_success=已刪除此版本發佈。
|
||||
release.downloads=下載附件
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
[graphs]
|
||||
|
||||
[org]
|
||||
org_name_holder=組織名稱
|
||||
org_full_name_holder=組織全名
|
||||
create_org=建立組織
|
||||
repo_updated=最後更新於
|
||||
members=成員數
|
||||
teams=組織團隊
|
||||
lower_members=名成員
|
||||
lower_repositories=個儲存庫
|
||||
org_desc=組織描述
|
||||
team_name=團隊名稱
|
||||
team_desc=團隊描述
|
||||
|
||||
|
||||
settings=組織設定
|
||||
settings.full_name=組織全名
|
||||
settings.website=官方網站
|
||||
settings.location=所在地區
|
||||
settings.visibility.private_shortname=私有庫
|
||||
|
||||
settings.update_settings=更新組織設定
|
||||
settings.update_setting_success=組織設定已更新。
|
||||
|
||||
|
||||
settings.delete=刪除組織
|
||||
settings.delete_account=刪除當前組織
|
||||
settings.confirm_delete_account=確認刪除組織
|
||||
settings.hooks_desc=新增 webhooks 將觸發在這個組織下 <strong>全部的儲存庫</strong> 。
|
||||
|
||||
|
||||
members.membership_visibility=成員可見性:
|
||||
members.member_role=成員角色:
|
||||
members.owner=管理員
|
||||
members.member=普通成員
|
||||
members.remove=移除成員
|
||||
members.leave=離開組織
|
||||
members.invite_desc=邀請新的用戶加入 %s:
|
||||
members.invite_now=立即邀請
|
||||
|
||||
teams.join=加入團隊
|
||||
teams.leave=離開團隊
|
||||
teams.read_access=已讀
|
||||
teams.no_desc=該團隊暫無描述
|
||||
teams.settings=團隊設定
|
||||
teams.members=團隊成員
|
||||
teams.update_settings=更新團隊設定
|
||||
teams.add_team_member=新增團隊成員
|
||||
teams.delete_team_success=該團隊已被刪除。
|
||||
teams.repositories=團隊儲存庫
|
||||
|
||||
|
||||
|
||||
[admin]
|
||||
dashboard=控制面版
|
||||
organizations=組織管理
|
||||
repositories=儲存庫管理
|
||||
config=應用設定管理
|
||||
config_settings=組織設定
|
||||
notices=系統提示管理
|
||||
monitor=應用監控面版
|
||||
first_page=首頁
|
||||
last_page=末頁
|
||||
total=總計:%d
|
||||
|
||||
dashboard.operation_name=操作名稱
|
||||
dashboard.operation_switch=開關
|
||||
dashboard.operation_run=執行
|
||||
dashboard.clean_unbind_oauth=清理未綁定OAuth的連結
|
||||
dashboard.clean_unbind_oauth_success=所有未綁定 OAuth 的連結已刪除。
|
||||
dashboard.reinit_missing_repos=重新初始化所有遺失具已存在記錄的Git 儲存庫
|
||||
dashboard.sync_external_users=同步外部使用者資料
|
||||
dashboard.server_uptime=服務執行時間
|
||||
dashboard.current_goroutine=當前 Goroutines 數量
|
||||
dashboard.current_memory_usage=當前內存使用量
|
||||
dashboard.total_memory_allocated=所有被分配的內存
|
||||
dashboard.memory_obtained=內存佔用量
|
||||
dashboard.pointer_lookup_times=指針查找次數
|
||||
dashboard.current_heap_usage=當前 Heap 內存使用量
|
||||
dashboard.heap_memory_obtained=Heap 內存佔用量
|
||||
dashboard.heap_memory_idle=Heap 內存空閒量
|
||||
dashboard.heap_memory_in_use=正在使用的 Heap 內存
|
||||
dashboard.heap_memory_released=被釋放的 Heap 內存
|
||||
dashboard.heap_objects=Heap 對象數量
|
||||
dashboard.bootstrap_stack_usage=啟動 Stack 使用量
|
||||
dashboard.stack_memory_obtained=被分配的 Stack 內存
|
||||
dashboard.mspan_structures_usage=MSpan 結構內存使用量
|
||||
dashboard.mspan_structures_obtained=被分配的 MSpan 結構內存
|
||||
dashboard.mcache_structures_usage=MCache 結構內存使用量
|
||||
dashboard.mcache_structures_obtained=被分配的 MCache 結構內存
|
||||
dashboard.profiling_bucket_hash_table_obtained=被分配的剖析哈希表內存
|
||||
dashboard.gc_metadata_obtained=被分配的垃圾收集元資料內存
|
||||
dashboard.other_system_allocation_obtained=其它被分配的系統內存
|
||||
dashboard.next_gc_recycle=下次垃圾收集內存回收量
|
||||
dashboard.last_gc_time=距離上次垃圾收集時間
|
||||
dashboard.total_gc_time=垃圾收集執行時間總量
|
||||
dashboard.total_gc_pause=垃圾收集暫停時間總量
|
||||
dashboard.last_gc_pause=上次垃圾收集暫停時間
|
||||
dashboard.gc_times=垃圾收集執行次數
|
||||
|
||||
users.full_name=組織全名
|
||||
users.activated=已啟用
|
||||
users.admin=管理員
|
||||
users.repos=儲存庫數
|
||||
users.created=建立時間
|
||||
users.edit=編輯
|
||||
users.auth_source=認證源
|
||||
users.local=本地
|
||||
users.list_status_filter.is_admin=管理員
|
||||
|
||||
emails.activated=已啟用
|
||||
|
||||
orgs.org_manage_panel=組織管理
|
||||
orgs.name=組織名稱
|
||||
orgs.teams=團隊數
|
||||
orgs.members=成員數
|
||||
|
||||
repos.repo_manage_panel=儲存庫管理
|
||||
repos.owner=所有者
|
||||
repos.name=儲存庫名稱
|
||||
repos.private=私有庫
|
||||
repos.issues=問題數
|
||||
repos.size=大小
|
||||
|
||||
packages.owner=管理員
|
||||
packages.name=組織名稱
|
||||
packages.type=認證類型
|
||||
packages.repository=儲存庫
|
||||
packages.size=大小
|
||||
|
||||
|
||||
|
||||
auths.name=認證名稱
|
||||
auths.type=認證類型
|
||||
auths.enabled=已啟用
|
||||
auths.updated=最後更新時間
|
||||
auths.auth_type=認證類型
|
||||
auths.auth_name=認證名稱
|
||||
auths.security_protocol=安全協定
|
||||
auths.domain=域名
|
||||
auths.host=主機地址
|
||||
auths.port=主機端口
|
||||
auths.bind_dn=綁定DN
|
||||
auths.bind_password=綁定密碼
|
||||
auths.user_base=用戶搜尋基準
|
||||
auths.user_dn=用戶 DN
|
||||
auths.filter=使用者篩選器
|
||||
auths.admin_filter=管理者篩選器
|
||||
auths.smtp_auth=SMTP 驗證類型
|
||||
auths.smtphost=SMTP 主機地址
|
||||
auths.smtpport=SMTP 主機端口
|
||||
auths.allowed_domains=域名白名單
|
||||
auths.skip_tls_verify=忽略 TLS 驗證
|
||||
auths.pam_service_name=PAM 服務名稱
|
||||
auths.oauth2_provider=OAuth2 提供者
|
||||
auths.oauth2_clientID=用戶端 ID (金鑰)
|
||||
auths.oauth2_clientSecret=用戶端金鑰
|
||||
auths.openIdConnectAutoDiscoveryURL=OpenID 連接自動探索 URL
|
||||
auths.oauth2_authURL=授權 URL
|
||||
auths.oauth2_profileURL=個人訊息 URL
|
||||
auths.oauth2_emailURL=電子郵件 URL
|
||||
auths.enable_auto_register=允許授權用戶自動註冊
|
||||
auths.tips=幫助提示
|
||||
auths.tips.oauth2.general=OAuth2 認證
|
||||
auths.tip.oauth2_provider=OAuth2 提供者
|
||||
auths.delete=刪除認證來源
|
||||
auths.delete_auth_title=刪除認證來源
|
||||
|
||||
config.server_config=伺服器設定
|
||||
config.custom_conf=設定檔案路徑
|
||||
config.disable_router_log=關閉路由日誌
|
||||
config.run_mode=執行模式
|
||||
config.git_version=Git 版本
|
||||
config.repo_root_path=儲存庫目錄
|
||||
config.lfs_root_path=LFS 根目錄
|
||||
config.script_type=腳本類型
|
||||
config.reverse_auth_user=反向代理認證
|
||||
|
||||
config.ssh_config=SSH 設定
|
||||
config.ssh_enabled=已啟用
|
||||
config.ssh_port=埠
|
||||
config.ssh_listen_port=監聽埠
|
||||
config.ssh_root_path=根路徑
|
||||
config.ssh_minimum_key_size_check=金鑰最小大小檢查
|
||||
config.ssh_minimum_key_sizes=金鑰最小大小
|
||||
|
||||
config.lfs_enabled=已啟用
|
||||
|
||||
config.db_config=資料庫設定
|
||||
config.db_type=資料庫類型
|
||||
config.db_host=主機地址
|
||||
config.db_name=資料庫名稱
|
||||
config.db_path=資料庫路徑
|
||||
|
||||
config.service_config=服務設定
|
||||
config.show_registration_button=顯示註冊按鈕
|
||||
config.active_code_lives=啟用用戶連結有效期
|
||||
|
||||
config.webhook_config=Webhook 設定
|
||||
config.queue_length=隊列長度
|
||||
config.deliver_timeout=推送超時
|
||||
config.skip_tls_verify=略過 TLS 驗證
|
||||
|
||||
config.mailer_enabled=啟用服務
|
||||
config.mailer_name=發送者名稱
|
||||
config.mailer_smtp_port=SMTP 主機端口
|
||||
config.mailer_user=發送者帳號
|
||||
|
||||
config.oauth_config=社交帳號設定
|
||||
config.oauth_enabled=啟用服務
|
||||
|
||||
config.cache_config=Cache 設定
|
||||
config.cache_adapter=Cache 適配器
|
||||
config.cache_interval=Cache 周期
|
||||
config.cache_conn=Cache 連接字符串
|
||||
|
||||
config.session_config=Session 設定
|
||||
config.session_provider=Session 提供者
|
||||
config.provider_config=提供者設定
|
||||
config.cookie_name=Cookie 名稱
|
||||
config.gc_interval_time=垃圾收集周期
|
||||
config.session_life_time=Session 生命周期
|
||||
config.https_only=僅限 HTTPS
|
||||
config.cookie_life_time=Cookie 生命周期
|
||||
|
||||
config.picture_service=圖片服務
|
||||
config.disable_gravatar=禁用 Gravatar 頭像
|
||||
config.enable_federated_avatar=開啟聯合頭像
|
||||
|
||||
config.git_config=Git 設定
|
||||
config.git_disable_diff_highlight=禁用比較語法高亮
|
||||
config.git_max_diff_lines=Max Diff 線 (對於單個檔)
|
||||
config.git_max_diff_line_characters=最大比較的字元 (單行)
|
||||
config.git_max_diff_files=Max Diff 檔 (顯示)
|
||||
config.git_gc_args=GC 參數
|
||||
config.git_migrate_timeout=移動超時
|
||||
config.git_mirror_timeout=鏡像更新超時
|
||||
config.git_clone_timeout=複製操作超時
|
||||
config.git_pull_timeout=操作超時
|
||||
config.git_gc_timeout=GC 操作超時
|
||||
|
||||
config.log_config=日誌設定
|
||||
|
||||
|
||||
|
||||
monitor.cron=Cron 任務
|
||||
monitor.name=任務名稱
|
||||
monitor.schedule=任務安排
|
||||
monitor.next=下次執行時間
|
||||
monitor.previous=上次執行時間
|
||||
monitor.process=執行中進程
|
||||
monitor.desc=進程描述
|
||||
monitor.start=開始時間
|
||||
monitor.execute_time=已執行時間
|
||||
|
||||
monitor.queue.name=組織名稱
|
||||
monitor.queue.type=認證類型
|
||||
monitor.queue.settings.submit=更新組織設定
|
||||
|
||||
notices.system_notice_list=系統提示管理
|
||||
notices.view_detail_header=查看提示細節
|
||||
notices.select_all=選取全部
|
||||
notices.deselect_all=取消所有選取
|
||||
notices.inverse_selection=反向選取
|
||||
notices.delete_selected=刪除選取項
|
||||
notices.delete_all=刪除所有提示
|
||||
notices.type=提示類型
|
||||
notices.type_1=儲存庫
|
||||
notices.desc=描述
|
||||
notices.op=操作
|
||||
notices.delete_success=已刪除系統提示。
|
||||
|
||||
|
||||
[action]
|
||||
create_repo=建立了儲存庫 <a href="%s">%s</a>
|
||||
rename_repo=重新命名儲存庫 <code>%[1]s</code> 為 <a href="%[2]s">%[3]s</a>
|
||||
transfer_repo=將儲存庫 <code>%s</code> 轉移至 <a href="%s">%s</a>
|
||||
compare_commits=比較 %d 提交
|
||||
|
||||
[tool]
|
||||
now=現在
|
||||
future=未來
|
||||
1s=1 秒
|
||||
1m=1 分鐘
|
||||
1h=1 小時
|
||||
1d=1 天
|
||||
1w=1 周
|
||||
1mon=1 月
|
||||
1y=1 年
|
||||
seconds=%d 秒
|
||||
minutes=%d 分
|
||||
hours=%d 小時
|
||||
days=%d 天
|
||||
weeks=%d 週
|
||||
months=%d 月
|
||||
years=%d 年
|
||||
raw_seconds=秒
|
||||
raw_minutes=分鐘
|
||||
|
||||
[dropzone]
|
||||
file_too_big=檔案大小({{filesize}} MB) 超過了最大允許大小({{maxFilesize}} MB)
|
||||
remove_file=移除文件
|
||||
|
||||
[notification]
|
||||
notifications=訊息
|
||||
unread=未讀
|
||||
read=已讀
|
||||
pin=固定通知
|
||||
mark_as_read=標記為已讀
|
||||
mark_as_unread=標記為未讀
|
||||
|
||||
[gpg]
|
||||
error.extract_sign=無法提取簽署
|
||||
error.generate_hash=無法產生提交的雜湊值
|
||||
error.no_gpg_keys_found=沒有發現已知的金鑰在資料庫的簽署中
|
||||
error.not_signed_commit=未簽名的提交
|
||||
|
||||
[units]
|
||||
|
||||
[packages]
|
||||
filter.type=認證類型
|
||||
alpine.repository.repositories=儲存庫管理
|
||||
arch.repository.repositories=儲存庫管理
|
||||
conan.details.repository=儲存庫
|
||||
owner.settings.cleanuprules.enabled=已啟用
|
||||
|
||||
[secrets]
|
||||
|
||||
; These keys are also for "edit secret", the keys are kept as-is to avoid unnecessary re-translation
|
||||
creation.description=組織描述
|
||||
|
||||
|
||||
|
||||
[actions]
|
||||
|
||||
|
||||
|
||||
runners.name=組織名稱
|
||||
runners.owner_type=認證類型
|
||||
runners.description=組織描述
|
||||
runners.task_list.run=執行
|
||||
runners.task_list.repository=儲存庫
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
[projects]
|
||||
|
||||
[git.filemode]
|
||||
; Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", …
|
||||
|
||||
3790
options/locale/locale_zh-HK.json
Normal file
3790
options/locale/locale_zh-HK.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3790
options/locale/locale_zh-TW.json
Normal file
3790
options/locale/locale_zh-TW.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -73,7 +73,7 @@ func EditApplicationPost(ctx *context.Context) {
|
||||
|
||||
// ApplicationsRegenerateSecret handles the post request for regenerating the secret
|
||||
func ApplicationsRegenerateSecret(ctx *context.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("settings")
|
||||
ctx.Data["Title"] = ctx.Tr("settings_title")
|
||||
ctx.Data["PageIsAdminApplications"] = true
|
||||
|
||||
oa := newOAuth2CommonHandlers()
|
||||
|
||||
@ -31,7 +31,7 @@ func Code(ctx *context.Context) {
|
||||
ctx.Data["UsersPageIsDisabled"] = setting.Service.Explore.DisableUsersPage
|
||||
ctx.Data["OrganizationsPageIsDisabled"] = setting.Service.Explore.DisableOrganizationsPage
|
||||
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
|
||||
ctx.Data["Title"] = ctx.Tr("explore")
|
||||
ctx.Data["Title"] = ctx.Tr("explore_title")
|
||||
ctx.Data["PageIsExplore"] = true
|
||||
ctx.Data["PageIsExploreCode"] = true
|
||||
ctx.Data["PageIsViewCode"] = true
|
||||
|
||||
@ -22,7 +22,7 @@ func Organizations(ctx *context.Context) {
|
||||
|
||||
ctx.Data["UsersPageIsDisabled"] = setting.Service.Explore.DisableUsersPage
|
||||
ctx.Data["CodePageIsDisabled"] = setting.Service.Explore.DisableCodePage
|
||||
ctx.Data["Title"] = ctx.Tr("explore")
|
||||
ctx.Data["Title"] = ctx.Tr("explore_title")
|
||||
ctx.Data["PageIsExplore"] = true
|
||||
ctx.Data["PageIsExploreOrganizations"] = true
|
||||
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
|
||||
|
||||
@ -149,7 +149,7 @@ func Repos(ctx *context.Context) {
|
||||
ctx.Data["UsersPageIsDisabled"] = setting.Service.Explore.DisableUsersPage
|
||||
ctx.Data["OrganizationsPageIsDisabled"] = setting.Service.Explore.DisableOrganizationsPage
|
||||
ctx.Data["CodePageIsDisabled"] = setting.Service.Explore.DisableCodePage
|
||||
ctx.Data["Title"] = ctx.Tr("explore")
|
||||
ctx.Data["Title"] = ctx.Tr("explore_title")
|
||||
ctx.Data["PageIsExplore"] = true
|
||||
ctx.Data["ShowRepoOwnerOnList"] = true
|
||||
ctx.Data["PageIsExploreRepositories"] = true
|
||||
|
||||
@ -134,7 +134,7 @@ func Users(ctx *context.Context) {
|
||||
}
|
||||
ctx.Data["OrganizationsPageIsDisabled"] = setting.Service.Explore.DisableOrganizationsPage
|
||||
ctx.Data["CodePageIsDisabled"] = setting.Service.Explore.DisableCodePage
|
||||
ctx.Data["Title"] = ctx.Tr("explore")
|
||||
ctx.Data["Title"] = ctx.Tr("explore_title")
|
||||
ctx.Data["PageIsExplore"] = true
|
||||
ctx.Data["PageIsExploreUsers"] = true
|
||||
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
|
||||
|
||||
@ -84,7 +84,7 @@ func OAuth2ApplicationEdit(ctx *context.Context) {
|
||||
|
||||
// OAuthApplicationsRegenerateSecret handles the post request for regenerating the secret
|
||||
func OAuthApplicationsRegenerateSecret(ctx *context.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("settings")
|
||||
ctx.Data["Title"] = ctx.Tr("settings_title")
|
||||
ctx.Data["PageIsOrgSettings"] = true
|
||||
ctx.Data["PageIsSettingsApplications"] = true
|
||||
|
||||
|
||||
@ -57,7 +57,7 @@ func AccountPost(ctx *context.Context) {
|
||||
}
|
||||
|
||||
form := web.GetForm(ctx).(*forms.ChangePasswordForm)
|
||||
ctx.Data["Title"] = ctx.Tr("settings")
|
||||
ctx.Data["Title"] = ctx.Tr("settings_title")
|
||||
ctx.Data["PageIsSettingsAccount"] = true
|
||||
ctx.Data["Email"] = ctx.Doer.Email
|
||||
|
||||
@ -107,7 +107,7 @@ func EmailPost(ctx *context.Context) {
|
||||
}
|
||||
|
||||
form := web.GetForm(ctx).(*forms.AddEmailForm)
|
||||
ctx.Data["Title"] = ctx.Tr("settings")
|
||||
ctx.Data["Title"] = ctx.Tr("settings_title")
|
||||
ctx.Data["PageIsSettingsAccount"] = true
|
||||
ctx.Data["Email"] = ctx.Doer.Email
|
||||
|
||||
@ -237,7 +237,7 @@ func DeleteAccount(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["Title"] = ctx.Tr("settings")
|
||||
ctx.Data["Title"] = ctx.Tr("settings_title")
|
||||
ctx.Data["PageIsSettingsAccount"] = true
|
||||
ctx.Data["Email"] = ctx.Doer.Email
|
||||
|
||||
|
||||
@ -37,7 +37,7 @@ func Applications(ctx *context.Context) {
|
||||
// ApplicationsPost response for add user's access token
|
||||
func ApplicationsPost(ctx *context.Context) {
|
||||
form := web.GetForm(ctx).(*forms.NewAccessTokenForm)
|
||||
ctx.Data["Title"] = ctx.Tr("settings")
|
||||
ctx.Data["Title"] = ctx.Tr("settings_title")
|
||||
ctx.Data["PageIsSettingsApplications"] = true
|
||||
ctx.Data["UserDisabledFeatures"] = user_model.DisabledFeaturesWithLoginType(ctx.Doer)
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user