Provide a way to translate data units

This commit is contained in:
0ko 2024-03-19 15:52:32 +05:00
parent 7b9c346cde
commit 29cc80d849
19 changed files with 69 additions and 29 deletions

View file

@ -295,6 +295,7 @@ package "code.gitea.io/gitea/modules/translation"
func (MockLocale).TrString func (MockLocale).TrString
func (MockLocale).Tr func (MockLocale).Tr
func (MockLocale).TrN func (MockLocale).TrN
func (MockLocale).TrSize
func (MockLocale).PrettyNumber func (MockLocale).PrettyNumber
package "code.gitea.io/gitea/modules/util/filebuffer" package "code.gitea.io/gitea/modules/util/filebuffer"

View file

@ -16,7 +16,6 @@ import (
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user" 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/git"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup"
@ -24,6 +23,7 @@ import (
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs" api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/translation"
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
"xorm.io/builder" "xorm.io/builder"
@ -249,13 +249,17 @@ func (repo *Repository) SizeDetails() []SizeDetail {
} }
// SizeDetailsString returns a concatenation of all repository size details as a string // 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 var str strings.Builder
sizeDetails := repo.SizeDetails() sizeDetails := repo.SizeDetails()
for _, detail := range sizeDetails { for i, detail := range sizeDetails {
str.WriteString(fmt.Sprintf("%s: %s, ", detail.Name, base.FileSize(detail.Size))) 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 { func (repo *Repository) LogString() string {

View file

@ -31,6 +31,10 @@ func (l MockLocale) TrN(cnt any, key1, keyN string, args ...any) template.HTML {
return template.HTML(key1) return template.HTML(key1)
} }
func (l MockLocale) TrSize(s int64) ByteSize {
return ByteSize{fmt.Sprint(s), ""}
}
func (l MockLocale) PrettyNumber(v any) string { func (l MockLocale) PrettyNumber(v any) string {
return fmt.Sprint(v) return fmt.Sprint(v)
} }

View file

@ -15,6 +15,7 @@ import (
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/translation/i18n" "code.gitea.io/gitea/modules/translation/i18n"
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
"github.com/dustin/go-humanize"
"golang.org/x/text/language" "golang.org/x/text/language"
"golang.org/x/text/message" "golang.org/x/text/message"
@ -33,6 +34,8 @@ type Locale interface {
Tr(key string, args ...any) template.HTML Tr(key string, args ...any) template.HTML
TrN(cnt any, key1, keyN string, args ...any) template.HTML TrN(cnt any, key1, keyN string, args ...any) template.HTML
TrSize(size int64) ByteSize
PrettyNumber(v any) string 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...) return l.Tr(keyN, args...)
} }
type ByteSize struct {
PrettyNumber string
TranslatedUnit string
}
func (bs ByteSize) 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) ByteSize {
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 ByteSize{numberVal, unitVal}
}
func (l *locale) PrettyNumber(v any) string { 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 // 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 { if s, ok := v.(string); ok {

View file

@ -2,8 +2,8 @@
<div class="admin-setting-content"> <div class="admin-setting-content">
<h4 class="ui top attached header"> <h4 class="ui top attached header">
{{ctx.Locale.Tr "admin.packages.package_manage_panel"}} ({{ctx.Locale.Tr "admin.total" .TotalCount}}, {{ctx.Locale.Tr "admin.packages.package_manage_panel"}} ({{ctx.Locale.Tr "admin.total" .TotalCount}},
{{ctx.Locale.Tr "admin.packages.total_size" (FileSize .TotalBlobSize)}}, {{ctx.Locale.Tr "admin.packages.total_size" (ctx.Locale.TrSize .TotalBlobSize)}},
{{ctx.Locale.Tr "admin.packages.unreferenced_size" (FileSize .TotalUnreferencedBlobSize)}}) {{ctx.Locale.Tr "admin.packages.unreferenced_size" (ctx.Locale.TrSize .TotalUnreferencedBlobSize)}})
<div class="ui right"> <div class="ui right">
<form method="post" action="/admin/packages/cleanup"> <form method="post" action="/admin/packages/cleanup">
{{.CsrfTokenHtml}} {{.CsrfTokenHtml}}
@ -70,7 +70,7 @@
<a href="{{.Repository.Link}}">{{.Repository.Name}}</a> <a href="{{.Repository.Link}}">{{.Repository.Name}}</a>
{{end}} {{end}}
</td> </td>
<td>{{FileSize .CalculateBlobSize}}</td> <td>{{ctx.Locale.TrSize .CalculateBlobSize}}</td>
<td>{{DateTime "short" .Version.CreatedUnix}}</td> <td>{{DateTime "short" .Version.CreatedUnix}}</td>
<td><a class="delete-button" href="" data-url="{{$.Link}}/delete?page={{$.Page.Paginater.Current}}&sort={{$.SortType}}" data-id="{{.Version.ID}}" data-name="{{.Package.Name}}" data-data-version="{{.Version.Version}}">{{svg "octicon-trash"}}</a></td> <td><a class="delete-button" href="" data-url="{{$.Link}}/delete?page={{$.Page.Paginater.Current}}&sort={{$.SortType}}" data-id="{{.Version.ID}}" data-name="{{.Package.Name}}" data-data-version="{{.Version.Version}}">{{svg "octicon-trash"}}</a></td>
</tr> </tr>

View file

@ -80,8 +80,8 @@
<td>{{.NumStars}}</td> <td>{{.NumStars}}</td>
<td>{{.NumForks}}</td> <td>{{.NumForks}}</td>
<td>{{.NumIssues}}</td> <td>{{.NumIssues}}</td>
<td>{{FileSize .GitSize}}</td> <td>{{ctx.Locale.TrSize .GitSize}}</td>
<td>{{FileSize .LFSSize}}</td> <td>{{ctx.Locale.TrSize .LFSSize}}</td>
<td>{{DateTime "short" .UpdatedUnix}}</td> <td>{{DateTime "short" .UpdatedUnix}}</td>
<td>{{DateTime "short" .CreatedUnix}}</td> <td>{{DateTime "short" .CreatedUnix}}</td>
<td><a class="delete-button" href="" data-url="{{$.Link}}/delete?page={{$.Page.Paginater.Current}}&sort={{$.SortType}}" data-id="{{.ID}}" data-name="{{.Name}}">{{svg "octicon-trash"}}</a></td> <td><a class="delete-button" href="" data-url="{{$.Link}}/delete?page={{$.Page.Paginater.Current}}&sort={{$.SortType}}" data-id="{{.ID}}" data-name="{{.Name}}">{{svg "octicon-trash"}}</a></td>

View file

@ -43,7 +43,7 @@
{{range .Release.Attachments}} {{range .Release.Attachments}}
<li> <li>
<a target="_blank" rel="noopener noreferrer" href="{{.DownloadURL}}"> <a target="_blank" rel="noopener noreferrer" href="{{.DownloadURL}}">
<strong>{{.Name}} ({{.Size | FileSize}})</strong> <strong>{{.Name}} ({{.Size | $.locale.TrSize}})</strong>
</a> </a>
</li> </li>
{{end}} {{end}}

View file

@ -39,7 +39,7 @@
<tr> <tr>
<td><a href="{{$.PackageDescriptor.PackageWebLink}}/{{PathEscape .Digest}}">{{.Digest}}</a></td> <td><a href="{{$.PackageDescriptor.PackageWebLink}}/{{PathEscape .Digest}}">{{.Digest}}</a></td>
<td>{{.Platform}}</td> <td>{{.Platform}}</td>
<td>{{FileSize .Size}}</td> <td>{{ctx.Locale.TrSize .Size}}</td>
</tr> </tr>
{{end}} {{end}}
</tbody> </tbody>

View file

@ -21,7 +21,7 @@
<td>{{.Package.Name}}</td> <td>{{.Package.Name}}</td>
<td><a href="{{.VersionWebLink}}">{{.Version.Version}}</a></td> <td><a href="{{.VersionWebLink}}">{{.Version.Version}}</a></td>
<td><a href="{{.Creator.HomeLink}}">{{.Creator.Name}}</a></td> <td><a href="{{.Creator.HomeLink}}">{{.Creator.Name}}</a></td>
<td>{{FileSize .CalculateBlobSize}}</td> <td>{{ctx.Locale.TrSize .CalculateBlobSize}}</td>
<td>{{DateTime "short" .Version.CreatedUnix}}</td> <td>{{DateTime "short" .Version.CreatedUnix}}</td>
</tr> </tr>
{{else}} {{else}}

View file

@ -70,7 +70,7 @@
{{template "package/metadata/swift" .}} {{template "package/metadata/swift" .}}
{{template "package/metadata/vagrant" .}} {{template "package/metadata/vagrant" .}}
{{if not (and (eq .PackageDescriptor.Package.Type "container") .PackageDescriptor.Metadata.Manifests)}} {{if not (and (eq .PackageDescriptor.Package.Type "container") .PackageDescriptor.Metadata.Manifests)}}
<div class="item">{{svg "octicon-database" 16 "tw-mr-2"}} {{FileSize .PackageDescriptor.CalculateBlobSize}}</div> <div class="item">{{svg "octicon-database" 16 "tw-mr-2"}} {{ctx.Locale.TrSize .PackageDescriptor.CalculateBlobSize}}</div>
{{end}} {{end}}
</div> </div>
{{if not (eq .PackageDescriptor.Package.Type "container")}} {{if not (eq .PackageDescriptor.Package.Type "container")}}
@ -80,7 +80,7 @@
{{range .PackageDescriptor.Files}} {{range .PackageDescriptor.Files}}
<div class="item"> <div class="item">
<a href="{{$.Link}}/files/{{.File.ID}}">{{.File.Name}}</a> <a href="{{$.Link}}/files/{{.File.ID}}">{{.File.Name}}</a>
<span class="text small file-size">{{FileSize .Blob.Size}}</span> <span class="text small file-size">{{ctx.Locale.TrSize .Blob.Size}}</span>
</div> </div>
{{end}} {{end}}
</div> </div>

View file

@ -30,7 +30,7 @@
{{ctx.Locale.Tr "repo.diff.file_image_height"}}: <span class="text bounds-info-height"></span> {{ctx.Locale.Tr "repo.diff.file_image_height"}}: <span class="text bounds-info-height"></span>
&nbsp;|&nbsp; &nbsp;|&nbsp;
</span> </span>
{{ctx.Locale.Tr "repo.diff.file_byte_size"}}: <span class="text">{{FileSize .blobBase.Size}}</span> {{ctx.Locale.Tr "repo.diff.file_byte_size"}}: <span class="text">{{ctx.Locale.TrSize .blobBase.Size}}</span>
</p> </p>
</span> </span>
{{end}} {{end}}
@ -45,7 +45,7 @@
{{ctx.Locale.Tr "repo.diff.file_image_height"}}: <span class="text bounds-info-height"></span> {{ctx.Locale.Tr "repo.diff.file_image_height"}}: <span class="text bounds-info-height"></span>
&nbsp;|&nbsp; &nbsp;|&nbsp;
</span> </span>
{{ctx.Locale.Tr "repo.diff.file_byte_size"}}: <span class="text">{{FileSize .blobHead.Size}}</span> {{ctx.Locale.Tr "repo.diff.file_byte_size"}}: <span class="text">{{ctx.Locale.TrSize .blobHead.Size}}</span>
</p> </p>
</span> </span>
{{end}} {{end}}

View file

@ -11,7 +11,7 @@
{{end}} {{end}}
{{if .FileSize}} {{if .FileSize}}
<div class="file-info-entry"> <div class="file-info-entry">
{{FileSize .FileSize}}{{if .IsLFSFile}} ({{ctx.Locale.Tr "repo.stored_lfs"}}){{end}} {{ctx.Locale.TrSize .FileSize}}{{if .IsLFSFile}} ({{ctx.Locale.Tr "repo.stored_lfs"}}){{end}}
</div> </div>
{{end}} {{end}}
{{if .LFSLock}} {{if .LFSLock}}

View file

@ -19,7 +19,7 @@
</a> </a>
</div> </div>
<div class="tw-p-2 tw-flex tw-items-center"> <div class="tw-p-2 tw-flex tw-items-center">
<span class="ui text grey">{{.Size | FileSize}}</span> <span class="ui text grey">{{.Size | ctx.Locale.TrSize}}</span>
</div> </div>
</div> </div>
{{end -}} {{end -}}

View file

@ -80,7 +80,7 @@
<strong>{{svg "octicon-package" 16 "tw-mr-1"}}{{.Name}}</strong> <strong>{{svg "octicon-package" 16 "tw-mr-1"}}{{.Name}}</strong>
</a> </a>
<div> <div>
<span class="text grey">{{.Size | FileSize}}</span> <span class="text grey">{{.Size | ctx.Locale.TrSize}}</span>
<span data-tooltip-content="{{ctx.Locale.Tr "repo.release.download_count" (ctx.Locale.PrettyNumber .DownloadCount)}}"> <span data-tooltip-content="{{ctx.Locale.Tr "repo.release.download_count" (ctx.Locale.PrettyNumber .DownloadCount)}}">
{{svg "octicon-info"}} {{svg "octicon-info"}}
</span> </span>

View file

@ -64,7 +64,7 @@
<div class="flex-text-inline tw-flex-1"> <div class="flex-text-inline tw-flex-1">
<input name="attachment-edit-{{.UUID}}" class="attachment_edit" required value="{{.Name}}"> <input name="attachment-edit-{{.UUID}}" class="attachment_edit" required value="{{.Name}}">
<input name="attachment-del-{{.UUID}}" type="hidden" value="false"> <input name="attachment-del-{{.UUID}}" type="hidden" value="false">
<span class="ui text grey tw-whitespace-nowrap">{{.Size | FileSize}}</span> <span class="ui text grey tw-whitespace-nowrap">{{.Size | ctx.Locale.TrSize}}</span>
<span data-tooltip-content="{{ctx.Locale.Tr "repo.release.download_count" (ctx.Locale.PrettyNumber .DownloadCount)}}"> <span data-tooltip-content="{{ctx.Locale.Tr "repo.release.download_count" (ctx.Locale.PrettyNumber .DownloadCount)}}">
{{svg "octicon-info"}} {{svg "octicon-info"}}
</span> </span>

View file

@ -16,7 +16,7 @@
{{ShortSha .Oid}} {{ShortSha .Oid}}
</a> </a>
</td> </td>
<td>{{FileSize .Size}}</td> <td>{{ctx.Locale.TrSize .Size}}</td>
<td>{{TimeSince .CreatedUnix.AsTime ctx.Locale}}</td> <td>{{TimeSince .CreatedUnix.AsTime ctx.Locale}}</td>
<td class="right aligned"> <td class="right aligned">
<a class="ui primary button" href="{{$.Link}}/find?oid={{.Oid}}&size={{.Size}}">{{ctx.Locale.Tr "repo.settings.lfs_findcommits"}}</a> <a class="ui primary button" href="{{$.Link}}/find?oid={{.Oid}}&size={{.Size}}">{{ctx.Locale.Tr "repo.settings.lfs_findcommits"}}</a>

View file

@ -14,7 +14,7 @@
</div> </div>
<div class="inline field"> <div class="inline field">
<label>{{ctx.Locale.Tr "repo.repo_size"}}</label> <label>{{ctx.Locale.Tr "repo.repo_size"}}</label>
<span {{if not (eq .Repository.Size 0)}} data-tooltip-content="{{.Repository.SizeDetailsString}}"{{end}}>{{FileSize .Repository.Size}}</span> <span {{if not (eq .Repository.Size 0)}} data-tooltip-content="{{.Repository.SizeDetailsString ctx.Locale}}"{{end}}>{{ctx.Locale.TrSize .Repository.Size}}</span>
</div> </div>
<div class="inline field"> <div class="inline field">
<label>{{ctx.Locale.Tr "repo.template"}}</label> <label>{{ctx.Locale.Tr "repo.template"}}</label>

View file

@ -13,10 +13,9 @@
{{svg "octicon-tag"}} {{ctx.Locale.TrN .NumTags "repo.n_tag_one" "repo.n_tag_few" (printf "<b>%d</b>" .NumTags | SafeHTML)}} {{svg "octicon-tag"}} {{ctx.Locale.TrN .NumTags "repo.n_tag_one" "repo.n_tag_few" (printf "<b>%d</b>" .NumTags | SafeHTML)}}
</a> </a>
{{end}} {{end}}
<span class="item not-mobile" {{if not (eq .Repository.Size 0)}}data-tooltip-content="{{.Repository.SizeDetailsString}}"{{end}}> <span class="item not-mobile" {{if not (eq .Repository.Size 0)}}data-tooltip-content="{{.Repository.SizeDetailsString ctx.Locale}}"{{end}}>
{{$fileSizeFormatted := FileSize .Repository.Size}}{{/* the formatted string is always "{val} {unit}" */}} {{$fileSizeFields := ctx.Locale.TrSize .Repository.Size }}
{{$fileSizeFields := StringUtils.Split $fileSizeFormatted " "}} {{svg "octicon-database"}} <b>{{$fileSizeFields.PrettyNumber}}</b> {{$fileSizeFields.TranslatedUnit}}
{{svg "octicon-database"}} <b>{{ctx.Locale.PrettyNumber (index $fileSizeFields 0)}}</b> {{index $fileSizeFields 1}}
</span> </span>
{{end}} {{end}}
</div> </div>

View file

@ -24,7 +24,7 @@
<span class="icon">{{svg "octicon-repo"}}</span> <span class="icon">{{svg "octicon-repo"}}</span>
{{end}} {{end}}
<a class="muted name" href="{{$repo.Link}}">{{$repo.OwnerName}}/{{$repo.Name}}</a> <a class="muted name" href="{{$repo.Link}}">{{$repo.OwnerName}}/{{$repo.Name}}</a>
<span class="text light-3" {{if not (eq $repo.Size 0)}} data-tooltip-content="{{$repo.SizeDetailsString}}"{{end}}>{{FileSize $repo.Size}}</span> <span class="text light-3" {{if not (eq $repo.Size 0)}} data-tooltip-content="{{$repo.SizeDetailsString ctx.Locale}}"{{end}}>{{ctx.Locale.TrSize $repo.Size}}</span>
{{if $repo.IsFork}} {{if $repo.IsFork}}
{{ctx.Locale.Tr "repo.forked_from"}} {{ctx.Locale.Tr "repo.forked_from"}}
<span><a href="{{$repo.BaseRepo.Link}}">{{$repo.BaseRepo.OwnerName}}/{{$repo.BaseRepo.Name}}</a></span> <span><a href="{{$repo.BaseRepo.Link}}">{{$repo.BaseRepo.OwnerName}}/{{$repo.BaseRepo.Name}}</a></span>
@ -97,7 +97,7 @@
{{svg "octicon-repo" 16 "tw-mr-1 iconFloat"}} {{svg "octicon-repo" 16 "tw-mr-1 iconFloat"}}
{{end}} {{end}}
<a class="name" href="{{.Link}}">{{.OwnerName}}/{{.Name}}</a> <a class="name" href="{{.Link}}">{{.OwnerName}}/{{.Name}}</a>
<span>{{FileSize .Size}}</span> <span>{{ctx.Locale.TrSize .Size}}</span>
{{if .IsFork}} {{if .IsFork}}
{{ctx.Locale.Tr "repo.forked_from"}} {{ctx.Locale.Tr "repo.forked_from"}}
<span><a href="{{.BaseRepo.Link}}">{{.BaseRepo.OwnerName}}/{{.BaseRepo.Name}}</a></span> <span><a href="{{.BaseRepo.Link}}">{{.BaseRepo.OwnerName}}/{{.BaseRepo.Name}}</a></span>