aboutsummaryrefslogtreecommitdiffstats
path: root/modules/translation
diff options
context:
space:
mode:
authorwxiaoguang <wxiaoguang@gmail.com>2023-04-17 11:37:23 +0800
committerGitHub <noreply@github.com>2023-04-17 11:37:23 +0800
commit7681d582cdae42d9322309ddf732117e6d332776 (patch)
tree6cdfa61a2055f23153884404fe93d4b4792fd532 /modules/translation
parentbe7cd73439c2210bfd889915f74d66686e99dab6 (diff)
downloadgitea-7681d582cdae42d9322309ddf732117e6d332776.tar.gz
gitea-7681d582cdae42d9322309ddf732117e6d332776.zip
Refactor locale number (#24134)
Before, the `GiteaLocaleNumber.js` was just written as a a drop-in replacement for old `js-pretty-number`. Actually, we can use Golang's `text` package to format. This PR partially completes the TODOs in `GiteaLocaleNumber.js`: > if we have complete backend locale support (eg: Golang "x/text" package), we can drop this component. > tooltip: only 2 usages of this, we can replace it with Golang's "x/text/number" package in the future. This PR also helps #24131 Screenshots: <details> ![image](https://user-images.githubusercontent.com/2114189/232179420-b1b9974b-9d96-4408-b209-b80182c8b359.png) ![image](https://user-images.githubusercontent.com/2114189/232179416-14f36aa0-3f3e-4ac9-b366-7bd3a4464a11.png) </details>
Diffstat (limited to 'modules/translation')
-rw-r--r--modules/translation/mock.go27
-rw-r--r--modules/translation/translation.go30
-rw-r--r--modules/translation/translation_test.go27
3 files changed, 79 insertions, 5 deletions
diff --git a/modules/translation/mock.go b/modules/translation/mock.go
new file mode 100644
index 0000000000..6ce66166aa
--- /dev/null
+++ b/modules/translation/mock.go
@@ -0,0 +1,27 @@
+// Copyright 2020 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package translation
+
+import "fmt"
+
+// MockLocale provides a mocked locale without any translations
+type MockLocale struct{}
+
+var _ Locale = (*MockLocale)(nil)
+
+func (l MockLocale) Language() string {
+ return "en"
+}
+
+func (l MockLocale) Tr(s string, _ ...interface{}) string {
+ return s
+}
+
+func (l MockLocale) TrN(_cnt interface{}, key1, _keyN string, _args ...interface{}) string {
+ return key1
+}
+
+func (l MockLocale) PrettyNumber(v any) string {
+ return fmt.Sprint(v)
+}
diff --git a/modules/translation/translation.go b/modules/translation/translation.go
index 331da0f965..56cf1df2d4 100644
--- a/modules/translation/translation.go
+++ b/modules/translation/translation.go
@@ -15,17 +15,20 @@ import (
"code.gitea.io/gitea/modules/translation/i18n"
"golang.org/x/text/language"
+ "golang.org/x/text/message"
+ "golang.org/x/text/number"
)
type contextKey struct{}
-var ContextKey interface{} = &contextKey{}
+var ContextKey any = &contextKey{}
// Locale represents an interface to translation
type Locale interface {
Language() string
- Tr(string, ...interface{}) string
- TrN(cnt interface{}, key1, keyN string, args ...interface{}) string
+ Tr(string, ...any) string
+ TrN(cnt any, key1, keyN string, args ...any) string
+ PrettyNumber(v any) string
}
// LangType represents a lang type
@@ -135,6 +138,7 @@ func Match(tags ...language.Tag) language.Tag {
type locale struct {
i18n.Locale
Lang, LangName string // these fields are used directly in templates: .i18n.Lang
+ msgPrinter *message.Printer
}
// NewLocale return a locale
@@ -147,13 +151,24 @@ func NewLocale(lang string) Locale {
langName := "unknown"
if l, ok := allLangMap[lang]; ok {
langName = l.Name
+ } else if len(setting.Langs) > 0 {
+ lang = setting.Langs[0]
+ langName = setting.Names[0]
}
+
i18nLocale, _ := i18n.GetLocale(lang)
- return &locale{
+ l := &locale{
Locale: i18nLocale,
Lang: lang,
LangName: langName,
}
+ if langTag, err := language.Parse(lang); err != nil {
+ log.Error("Failed to parse language tag from name %q: %v", l.Lang, err)
+ l.msgPrinter = message.NewPrinter(language.English)
+ } else {
+ l.msgPrinter = message.NewPrinter(langTag)
+ }
+ return l
}
func (l *locale) Language() string {
@@ -199,7 +214,7 @@ var trNLangRules = map[string]func(int64) int{
}
// TrN returns translated message for plural text translation
-func (l *locale) TrN(cnt interface{}, key1, keyN string, args ...interface{}) string {
+func (l *locale) TrN(cnt any, key1, keyN string, args ...any) string {
var c int64
if t, ok := cnt.(int); ok {
c = int64(t)
@@ -223,3 +238,8 @@ func (l *locale) TrN(cnt interface{}, key1, keyN string, args ...interface{}) st
}
return l.Tr(keyN, args...)
}
+
+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
+ return l.msgPrinter.Sprintf("%v", number.Decimal(v))
+}
diff --git a/modules/translation/translation_test.go b/modules/translation/translation_test.go
new file mode 100644
index 0000000000..83a40f1458
--- /dev/null
+++ b/modules/translation/translation_test.go
@@ -0,0 +1,27 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package translation
+
+import (
+ "testing"
+
+ "code.gitea.io/gitea/modules/translation/i18n"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestPrettyNumber(t *testing.T) {
+ // TODO: make this package friendly to testing
+
+ i18n.ResetDefaultLocales()
+
+ allLangMap = make(map[string]*LangType)
+ allLangMap["id-ID"] = &LangType{Lang: "id-ID", Name: "Bahasa Indonesia"}
+
+ l := NewLocale("id-ID")
+ assert.EqualValues(t, "1.000.000", l.PrettyNumber(1000000))
+
+ l = NewLocale("nosuch")
+ assert.EqualValues(t, "1,000,000", l.PrettyNumber(1000000))
+}