diff --git a/.deadcode-out b/.deadcode-out index 1b65e3203d..940551da04 100644 --- a/.deadcode-out +++ b/.deadcode-out @@ -295,6 +295,7 @@ package "code.gitea.io/gitea/modules/translation" func (MockLocale).TrString func (MockLocale).Tr func (MockLocale).TrN + func (MockLocale).TrSize func (MockLocale).PrettyNumber package "code.gitea.io/gitea/modules/util/filebuffer" diff --git a/models/repo/repo.go b/models/repo/repo.go index 4e1b6fcbcf..350dc86d4b 100644 --- a/models/repo/repo.go +++ b/models/repo/repo.go @@ -16,7 +16,6 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup" @@ -24,6 +23,7 @@ import ( "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/translation" "code.gitea.io/gitea/modules/util" "xorm.io/builder" @@ -249,13 +249,17 @@ func (repo *Repository) SizeDetails() []SizeDetail { } // SizeDetailsString returns a concatenation of all repository size details as a string -func (repo *Repository) SizeDetailsString() string { +func (repo *Repository) SizeDetailsString(locale translation.Locale) string { var str strings.Builder sizeDetails := repo.SizeDetails() - for _, detail := range sizeDetails { - str.WriteString(fmt.Sprintf("%s: %s, ", detail.Name, base.FileSize(detail.Size))) + for i, detail := range sizeDetails { + if i > 0 { + // TODO: use semicolon if decimal point of user localization is a comma + str.WriteString(", ") + } + str.WriteString(fmt.Sprintf("%s: %s", detail.Name, locale.TrSize(detail.Size))) } - return strings.TrimSuffix(str.String(), ", ") + return str.String() } func (repo *Repository) LogString() string { diff --git a/modules/templates/helper.go b/modules/templates/helper.go index 18a2993fb8..c9799a38ec 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -63,7 +63,7 @@ func NewFuncMap() template.FuncMap { // ----------------------------------------------------------------- // time / number / format - "FileSize": base.FileSize, + "FileSize": FileSizePanic, "CountFmt": base.FormatNumberSI, "TimeSince": timeutil.TimeSince, "TimeSinceUnix": timeutil.TimeSinceUnix, @@ -249,3 +249,7 @@ func Eval(tokens ...any) (any, error) { n, err := eval.Expr(tokens...) return n.Value, err } + +func FileSizePanic(s int64) string { + panic("Usage of FileSize in templates is deprecated in Forgejo. Locale.TrSize should be used instead.") +} diff --git a/modules/translation/mock.go b/modules/translation/mock.go index 18fbc1044a..fe3a1502ea 100644 --- a/modules/translation/mock.go +++ b/modules/translation/mock.go @@ -31,6 +31,10 @@ func (l MockLocale) TrN(cnt any, key1, keyN string, args ...any) template.HTML { return template.HTML(key1) } +func (l MockLocale) TrSize(s int64) ReadableSize { + return ReadableSize{fmt.Sprint(s), ""} +} + func (l MockLocale) PrettyNumber(v any) string { return fmt.Sprint(v) } diff --git a/modules/translation/translation.go b/modules/translation/translation.go index 36ae58a9f1..16eb55e28e 100644 --- a/modules/translation/translation.go +++ b/modules/translation/translation.go @@ -16,6 +16,7 @@ import ( "code.gitea.io/gitea/modules/translation/i18n" "code.gitea.io/gitea/modules/util" + "github.com/dustin/go-humanize" "golang.org/x/text/language" "golang.org/x/text/message" "golang.org/x/text/number" @@ -33,6 +34,8 @@ type Locale interface { Tr(key string, args ...any) template.HTML TrN(cnt any, key1, keyN string, args ...any) template.HTML + TrSize(size int64) ReadableSize + PrettyNumber(v any) string } @@ -252,6 +255,35 @@ func (l *locale) TrN(cnt any, key1, keyN string, args ...any) template.HTML { return l.Tr(keyN, args...) } +type ReadableSize struct { + PrettyNumber string + TranslatedUnit string +} + +func (bs ReadableSize) String() string { + return bs.PrettyNumber + " " + bs.TranslatedUnit +} + +// TrSize returns array containing pretty formatted size and localized output of FileSize +// output of humanize.IBytes has to be split in order to be localized +func (l *locale) TrSize(s int64) ReadableSize { + us := uint64(s) + if s < 0 { + us = uint64(-s) + } + untranslated := humanize.IBytes(us) + if s < 0 { + untranslated = "-" + untranslated + } + numberVal, unitVal, found := strings.Cut(untranslated, " ") + if !found { + log.Error("no space in go-humanized size of %d: %q", s, untranslated) + } + numberVal = l.PrettyNumber(numberVal) + unitVal = l.TrString("munits.data." + strings.ToLower(unitVal)) + return ReadableSize{numberVal, unitVal} +} + func (l *locale) PrettyNumber(v any) string { // TODO: this mechanism is not good enough, the complete solution is to switch the translation system to ICU message format if s, ok := v.(string); ok { diff --git a/modules/translation/translation_test.go b/modules/translation/translation_test.go index 464aa32661..bffbb155ca 100644 --- a/modules/translation/translation_test.go +++ b/modules/translation/translation_test.go @@ -3,6 +3,8 @@ package translation +// TODO: make this package friendly to testing + import ( "testing" @@ -11,9 +13,25 @@ import ( "github.com/stretchr/testify/assert" ) -func TestPrettyNumber(t *testing.T) { - // TODO: make this package friendly to testing +func TestTrSize(t *testing.T) { + l := NewLocale("") + size := int64(1) + assert.EqualValues(t, "1 munits.data.b", l.TrSize(size).String()) + size *= 2048 + assert.EqualValues(t, "2 munits.data.kib", l.TrSize(size).String()) + size *= 2048 + assert.EqualValues(t, "4 munits.data.mib", l.TrSize(size).String()) + size *= 2048 + assert.EqualValues(t, "8 munits.data.gib", l.TrSize(size).String()) + size *= 2048 + assert.EqualValues(t, "16 munits.data.tib", l.TrSize(size).String()) + size *= 2048 + assert.EqualValues(t, "32 munits.data.pib", l.TrSize(size).String()) + size *= 128 + assert.EqualValues(t, "4 munits.data.eib", l.TrSize(size).String()) +} +func TestPrettyNumber(t *testing.T) { i18n.ResetDefaultLocales() allLangMap = make(map[string]*LangType) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 1bf351e4b1..7660af8be4 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -3418,6 +3418,15 @@ years = %d years raw_seconds = seconds raw_minutes = minutes +[munits.data] +b = B +kib = KiB +mib = MiB +gib = GiB +tib = TiB +pib = PiB +eib = EiB + [dropzone] default_message = Drop files or click here to upload. invalid_input_type = You cannot upload files of this type. diff --git a/options/locale/locale_ru-RU.ini b/options/locale/locale_ru-RU.ini index 0057633e04..55e850e473 100644 --- a/options/locale/locale_ru-RU.ini +++ b/options/locale/locale_ru-RU.ini @@ -3421,6 +3421,15 @@ years=%d лет raw_seconds=секунд raw_minutes=минут +[munits.data] +b = Б +kib = КиБ +mib = МиБ +gib = ГиБ +tib = ТиБ +pib = ПиБ +eib = ЕиБ + [dropzone] default_message=Перетащите файл или кликните сюда для загрузки. invalid_input_type=Вы не можете загружать файлы этого типа. diff --git a/templates/admin/packages/list.tmpl b/templates/admin/packages/list.tmpl index 863f11da25..d111c57378 100644 --- a/templates/admin/packages/list.tmpl +++ b/templates/admin/packages/list.tmpl @@ -2,8 +2,8 @@