Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce GiteaLocaleNumber custom element to handle number localization on pages. #23861

Merged
merged 4 commits into from
Apr 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions modules/base/tool.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import (
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"

"github.com/dustin/go-humanize"
"github.com/minio/sha256-simd"
Expand Down Expand Up @@ -142,12 +141,6 @@ func FileSize(s int64) string {
return humanize.IBytes(uint64(s))
}

// PrettyNumber produces a string form of the given number in base 10 with
// commas after every three orders of magnitude
func PrettyNumber(i interface{}) string {
return humanize.Comma(util.NumberIntoInt64(i))
}

// Subtract deals with subtraction of all types of number.
func Subtract(left, right interface{}) interface{} {
var rleft, rright int64
Expand Down
7 changes: 0 additions & 7 deletions modules/base/tool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,6 @@ func TestFileSize(t *testing.T) {
assert.Equal(t, "2.0 EiB", FileSize(size))
}

func TestPrettyNumber(t *testing.T) {
assert.Equal(t, "23,342,432", PrettyNumber(23342432))
assert.Equal(t, "23,342,432", PrettyNumber(int32(23342432)))
assert.Equal(t, "0", PrettyNumber(0))
assert.Equal(t, "-100,000", PrettyNumber(-100000))
}

func TestSubtract(t *testing.T) {
toFloat64 := func(n interface{}) float64 {
switch v := n.(type) {
Expand Down
93 changes: 18 additions & 75 deletions modules/templates/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (
"reflect"
"regexp"
"runtime"
"strconv"
"strings"
texttmpl "text/template"
"time"
Expand Down Expand Up @@ -112,18 +111,17 @@ func NewFuncMap() []template.FuncMap {
"IsShowFullName": func() bool {
return setting.UI.DefaultShowFullName
},
"Safe": Safe,
"SafeJS": SafeJS,
"JSEscape": JSEscape,
"Str2html": Str2html,
"TimeSince": timeutil.TimeSince,
"TimeSinceUnix": timeutil.TimeSinceUnix,
"FileSize": base.FileSize,
"PrettyNumber": base.PrettyNumber,
"JsPrettyNumber": JsPrettyNumber,
"Subtract": base.Subtract,
"EntryIcon": base.EntryIcon,
"MigrationIcon": MigrationIcon,
"Safe": Safe,
"SafeJS": SafeJS,
"JSEscape": JSEscape,
"Str2html": Str2html,
"TimeSince": timeutil.TimeSince,
"TimeSinceUnix": timeutil.TimeSinceUnix,
"FileSize": base.FileSize,
"LocaleNumber": LocaleNumber,
"Subtract": base.Subtract,
"EntryIcon": base.EntryIcon,
"MigrationIcon": MigrationIcon,
"Add": func(a ...int) int {
sum := 0
for _, val := range a {
Expand Down Expand Up @@ -410,62 +408,9 @@ func NewFuncMap() []template.FuncMap {
"Join": strings.Join,
"QueryEscape": url.QueryEscape,
"DotEscape": DotEscape,
"Iterate": func(arg interface{}) (items []uint64) {
count := uint64(0)
switch val := arg.(type) {
case uint64:
count = val
case *uint64:
count = *val
case int64:
if val < 0 {
val = 0
}
count = uint64(val)
case *int64:
if *val < 0 {
*val = 0
}
count = uint64(*val)
case int:
if val < 0 {
val = 0
}
count = uint64(val)
case *int:
if *val < 0 {
*val = 0
}
count = uint64(*val)
case uint:
count = uint64(val)
case *uint:
count = uint64(*val)
case int32:
if val < 0 {
val = 0
}
count = uint64(val)
case *int32:
if *val < 0 {
*val = 0
}
count = uint64(*val)
case uint32:
count = uint64(val)
case *uint32:
count = uint64(*val)
case string:
cnt, _ := strconv.ParseInt(val, 10, 64)
if cnt < 0 {
cnt = 0
}
count = uint64(cnt)
}
if count <= 0 {
return items
}
for i := uint64(0); i < count; i++ {
"Iterate": func(arg interface{}) (items []int64) {
count := util.ToInt64(arg)
for i := int64(0); i < count; i++ {
items = append(items, i)
}
return items
Expand Down Expand Up @@ -1067,10 +1012,8 @@ func mirrorRemoteAddress(ctx context.Context, m *repo_model.Repository, remoteNa
return a
}

// JsPrettyNumber renders a number using english decimal separators, e.g. 1,200 and subsequent
// JS will replace the number with locale-specific separators, based on the user's selected language
func JsPrettyNumber(i interface{}) template.HTML {
num := util.NumberIntoInt64(i)

return template.HTML(`<span class="js-pretty-number" data-value="` + strconv.FormatInt(num, 10) + `">` + base.PrettyNumber(num) + `</span>`)
// LocaleNumber renders a number with a Custom Element, browser will render it with a locale number
func LocaleNumber(v interface{}) template.HTML {
num := util.ToInt64(v)
return template.HTML(fmt.Sprintf(`<gitea-locale-number data-number="%d">%d</gitea-locale-number>`, num, num))
}
24 changes: 0 additions & 24 deletions modules/util/truncate.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,27 +35,3 @@ func SplitStringAtByteN(input string, n int) (left, right string) {

return input[:end] + utf8Ellipsis, utf8Ellipsis + input[end:]
}

// SplitStringAtRuneN splits a string at rune n accounting for rune boundaries. (Combining characters are not accounted for.)
func SplitStringAtRuneN(input string, n int) (left, right string) {
if !utf8.ValidString(input) {
if len(input) <= n || n-3 < 0 {
return input, ""
}
return input[:n-3] + asciiEllipsis, asciiEllipsis + input[n-3:]
}

if utf8.RuneCountInString(input) <= n {
return input, ""
}

count := 0
end := 0
for count < n-1 {
_, size := utf8.DecodeRuneInString(input[end:])
end += size
count++
}

return input[:end] + utf8Ellipsis, utf8Ellipsis + input[end:]
}
14 changes: 0 additions & 14 deletions modules/util/truncate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,4 @@ func TestSplitString(t *testing.T) {
{"\xef\x03", 1, "\xef\x03", ""},
}
test(tc, SplitStringAtByteN)

tc = []*testCase{
{"abc123xyz", 0, "", utf8Ellipsis},
{"abc123xyz", 1, "", utf8Ellipsis},
{"abc123xyz", 4, "abc", utf8Ellipsis},
{"啊bc123xyz", 4, "啊bc", utf8Ellipsis},
{"啊bc123xyz", 6, "啊bc12", utf8Ellipsis},
{"啊bc", 3, "啊bc", ""},
{"啊bc", 4, "啊bc", ""},
{"abc\xef\x03\xfe", 3, "", asciiEllipsis},
{"abc\xef\x03\xfe", 4, "a", asciiEllipsis},
{"\xef\x03", 1, "\xef\x03", ""},
}
test(tc, SplitStringAtRuneN)
}
58 changes: 25 additions & 33 deletions modules/util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import (
"bytes"
"crypto/rand"
"errors"
"fmt"
"math/big"
"regexp"
"os"
"strconv"
"strings"

Expand Down Expand Up @@ -200,40 +201,14 @@ func ToTitleCaseNoLower(s string) string {
return titleCaserNoLower.String(s)
}

var (
whitespaceOnly = regexp.MustCompile("(?m)^[ \t]+$")
leadingWhitespace = regexp.MustCompile("(?m)(^[ \t]*)(?:[^ \t\n])")
)

// Dedent removes common indentation of a multi-line string along with whitespace around it
// Based on https://github.com/lithammer/dedent
func Dedent(s string) string {
var margin string

s = whitespaceOnly.ReplaceAllString(s, "")
indents := leadingWhitespace.FindAllStringSubmatch(s, -1)

for i, indent := range indents {
if i == 0 {
margin = indent[1]
} else if strings.HasPrefix(indent[1], margin) {
continue
} else if strings.HasPrefix(margin, indent[1]) {
margin = indent[1]
} else {
margin = ""
break
}
}

if margin != "" {
s = regexp.MustCompile("(?m)^"+margin).ReplaceAllString(s, "")
}
return strings.TrimSpace(s)
func logError(msg string, args ...any) {
// TODO: the "util" package can not import the "modules/log" package, so we use the "fmt" package here temporarily.
// In the future, we should decouple the dependency between them.
_, _ = fmt.Fprintf(os.Stderr, msg, args...)
}

// NumberIntoInt64 transform a given int into int64.
func NumberIntoInt64(number interface{}) int64 {
// ToInt64 transform a given int into int64.
func ToInt64(number interface{}) int64 {
var value int64
switch v := number.(type) {
case int:
Expand All @@ -246,6 +221,23 @@ func NumberIntoInt64(number interface{}) int64 {
value = int64(v)
case int64:
value = v
case uint:
value = int64(v)
case uint8:
value = int64(v)
case uint16:
value = int64(v)
case uint32:
value = int64(v)
case uint64:
value = int64(v)
case string:
var err error
if value, err = strconv.ParseInt(v, 10, 64); err != nil {
logError("strconv.ParseInt failed for %q: %v", v, err)
}
default:
logError("unable to convert %q to int64", v)
}
return value
}
7 changes: 0 additions & 7 deletions modules/util/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,10 +224,3 @@ func TestToTitleCase(t *testing.T) {
assert.Equal(t, ToTitleCase(`foo bar baz`), `Foo Bar Baz`)
assert.Equal(t, ToTitleCase(`FOO BAR BAZ`), `Foo Bar Baz`)
}

func TestDedent(t *testing.T) {
assert.Equal(t, Dedent(`
foo
bar
`), "foo\n\tbar")
}
8 changes: 4 additions & 4 deletions templates/projects/list.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@
<div class="ui compact tiny menu">
<a class="item{{if not .IsShowClosed}} active{{end}}" href="{{$.Link}}?state=open">
{{svg "octicon-project-symlink" 16 "gt-mr-3"}}
{{JsPrettyNumber .OpenCount}}&nbsp;{{.locale.Tr "repo.issues.open_title"}}
{{LocaleNumber .OpenCount}}&nbsp;{{.locale.Tr "repo.issues.open_title"}}
</a>
<a class="item{{if .IsShowClosed}} active{{end}}" href="{{$.Link}}?state=closed">
{{svg "octicon-check" 16 "gt-mr-3"}}
{{JsPrettyNumber .ClosedCount}}&nbsp;{{.locale.Tr "repo.issues.closed_title"}}
{{LocaleNumber .ClosedCount}}&nbsp;{{.locale.Tr "repo.issues.closed_title"}}
</a>
</div>

Expand Down Expand Up @@ -46,9 +46,9 @@
{{end}}
<span class="issue-stats">
{{svg "octicon-issue-opened" 16 "gt-mr-3"}}
{{JsPrettyNumber .NumOpenIssues}}&nbsp;{{$.locale.Tr "repo.issues.open_title"}}
{{LocaleNumber .NumOpenIssues}}&nbsp;{{$.locale.Tr "repo.issues.open_title"}}
{{svg "octicon-check" 16 "gt-mr-3"}}
{{JsPrettyNumber .NumClosedIssues}}&nbsp;{{$.locale.Tr "repo.issues.closed_title"}}
{{LocaleNumber .NumClosedIssues}}&nbsp;{{$.locale.Tr "repo.issues.closed_title"}}
</span>
</div>
{{if and $.CanWriteProjects (not $.Repository.IsArchived)}}
Expand Down
8 changes: 4 additions & 4 deletions templates/repo/issue/milestones.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@
<div class="ui compact tiny menu">
<a class="item{{if not .IsShowClosed}} active{{end}}" href="{{.RepoLink}}/milestones?state=open&q={{$.Keyword}}">
{{svg "octicon-milestone" 16 "gt-mr-3"}}
{{JsPrettyNumber .OpenCount}}&nbsp;{{.locale.Tr "repo.issues.open_title"}}
{{LocaleNumber .OpenCount}}&nbsp;{{.locale.Tr "repo.issues.open_title"}}
</a>
<a class="item{{if .IsShowClosed}} active{{end}}" href="{{.RepoLink}}/milestones?state=closed&q={{$.Keyword}}">
{{svg "octicon-check" 16 "gt-mr-3"}}
{{JsPrettyNumber .ClosedCount}}&nbsp;{{.locale.Tr "repo.issues.closed_title"}}
{{LocaleNumber .ClosedCount}}&nbsp;{{.locale.Tr "repo.issues.closed_title"}}
</a>
</div>
</div>
Expand Down Expand Up @@ -84,9 +84,9 @@
{{end}}
<span class="issue-stats">
{{svg "octicon-issue-opened" 16 "gt-mr-3"}}
{{JsPrettyNumber .NumOpenIssues}}&nbsp;{{$.locale.Tr "repo.issues.open_title"}}
{{LocaleNumber .NumOpenIssues}}&nbsp;{{$.locale.Tr "repo.issues.open_title"}}
{{svg "octicon-check" 16 "gt-mr-3"}}
{{JsPrettyNumber .NumClosedIssues}}&nbsp;{{$.locale.Tr "repo.issues.closed_title"}}
{{LocaleNumber .NumClosedIssues}}&nbsp;{{$.locale.Tr "repo.issues.closed_title"}}
{{if .TotalTrackedTime}}{{svg "octicon-clock"}} {{.TotalTrackedTime|Sec2Time}}{{end}}
{{if .UpdatedUnix}}{{svg "octicon-clock"}} {{$.locale.Tr "repo.milestones.update_ago" (.TimeSinceUpdate|Sec2Time)}}{{end}}
</span>
Expand Down
4 changes: 2 additions & 2 deletions templates/repo/issue/openclose.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
{{else}}
{{svg "octicon-issue-opened" 16 "gt-mr-3"}}
{{end}}
{{JsPrettyNumber .IssueStats.OpenCount}}&nbsp;{{.locale.Tr "repo.issues.open_title"}}
{{LocaleNumber .IssueStats.OpenCount}}&nbsp;{{.locale.Tr "repo.issues.open_title"}}
</a>
<a class="{{if .IsShowClosed}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&type={{.ViewType}}&sort={{$.SortType}}&state=closed&labels={{.SelectLabels}}&milestone={{.MilestoneID}}&project={{.ProjectID}}&assignee={{.AssigneeID}}&poster={{.PosterID}}">
{{svg "octicon-check" 16 "gt-mr-3"}}
{{JsPrettyNumber .IssueStats.ClosedCount}}&nbsp;{{.locale.Tr "repo.issues.closed_title"}}
{{LocaleNumber .IssueStats.ClosedCount}}&nbsp;{{.locale.Tr "repo.issues.closed_title"}}
</a>
</div>
8 changes: 4 additions & 4 deletions templates/repo/projects/list.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
<div class="ui compact tiny menu">
<a class="item{{if not .IsShowClosed}} active{{end}}" href="{{.RepoLink}}/projects?state=open">
{{svg "octicon-project" 16 "gt-mr-3"}}
{{JsPrettyNumber .OpenCount}}&nbsp;{{.locale.Tr "repo.issues.open_title"}}
{{LocaleNumber .OpenCount}}&nbsp;{{.locale.Tr "repo.issues.open_title"}}
</a>
<a class="item{{if .IsShowClosed}} active{{end}}" href="{{.RepoLink}}/projects?state=closed">
{{svg "octicon-check" 16 "gt-mr-3"}}
{{JsPrettyNumber .ClosedCount}}&nbsp;{{.locale.Tr "repo.issues.closed_title"}}
{{LocaleNumber .ClosedCount}}&nbsp;{{.locale.Tr "repo.issues.closed_title"}}
</a>
</div>

Expand Down Expand Up @@ -48,9 +48,9 @@
{{end}}
<span class="issue-stats">
{{svg "octicon-issue-opened" 16 "gt-mr-3"}}
{{JsPrettyNumber .NumOpenIssues}}&nbsp;{{$.locale.Tr "repo.issues.open_title"}}
{{LocaleNumber .NumOpenIssues}}&nbsp;{{$.locale.Tr "repo.issues.open_title"}}
{{svg "octicon-check" 16 "gt-mr-3"}}
{{JsPrettyNumber .NumClosedIssues}}&nbsp;{{$.locale.Tr "repo.issues.closed_title"}}
{{LocaleNumber .NumClosedIssues}}&nbsp;{{$.locale.Tr "repo.issues.closed_title"}}
</span>
</div>
{{if and $.CanWriteProjects (not $.Repository.IsArchived)}}
Expand Down
4 changes: 2 additions & 2 deletions templates/repo/release/list.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,9 @@
<li>
<span class="ui text middle aligned right">
<span class="ui text grey">{{.Size | FileSize}}</span>
<span data-tooltip-content="{{$.locale.Tr "repo.release.download_count" (.DownloadCount | PrettyNumber)}}">
<gitea-locale-number data-number-in-tooltip="{{dict "message" ($.locale.Tr "repo.release.download_count") "number" .DownloadCount | Json}}">
{{svg "octicon-info"}}
</span>
</gitea-locale-number>
</span>
<a target="_blank" rel="noopener noreferrer" href="{{.DownloadURL}}">
<strong>{{svg "octicon-package" 16 "gt-mr-2"}}{{.Name}}</strong>
Expand Down
Loading