-
-
Notifications
You must be signed in to change notification settings - Fork 5.8k
Unify and simplify TrN for i18n #18141
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
Changes from 4 commits
99d4a26
67a26dd
aba8e9d
86fcd32
9fad209
1eb7379
efd4f54
602b9b4
4ac3f3b
906439b
b1bcc06
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ import ( | |
"bytes" | ||
"encoding/csv" | ||
"io" | ||
"strconv" | ||
"strings" | ||
"testing" | ||
|
||
|
@@ -21,14 +22,23 @@ func TestCreateReader(t *testing.T) { | |
assert.Equal(t, ',', rd.Comma) | ||
} | ||
|
||
//nolint | ||
func decodeSlashes(s string) string { | ||
s = strings.ReplaceAll(s, "\n", "\\n") | ||
s = strings.ReplaceAll(s, "\"", "\\\"") | ||
decoded, err := strconv.Unquote(`"` + s + `"`) | ||
if err != nil { | ||
panic("unable to decode string:" + err.Error() + "\n" + s) | ||
} | ||
return decoded | ||
} | ||
|
||
func TestCreateReaderAndDetermineDelimiter(t *testing.T) { | ||
var cases = []struct { | ||
csv string | ||
expectedRows [][]string | ||
expectedDelimiter rune | ||
}{ | ||
// case 0 - semicolon delmited | ||
// case 0 - semicolon delimited | ||
{ | ||
csv: `a;b;c | ||
1;2;3 | ||
|
@@ -47,11 +57,11 @@ a, b c | |
e f | ||
g h i | ||
j l | ||
m n, | ||
m n,\t | ||
6543 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
p q r | ||
u | ||
v w x | ||
y | ||
y\t\t | ||
`, | ||
expectedRows: [][]string{ | ||
{"col1", "col2", "col3"}, | ||
|
@@ -74,7 +84,7 @@ y | |
a, b, c | ||
d,e,f | ||
,h, i | ||
j, , | ||
j, ,\x20 | ||
, , `, | ||
expectedRows: [][]string{ | ||
{"col1", "col2", "col3"}, | ||
|
@@ -89,7 +99,7 @@ j, , | |
} | ||
|
||
for n, c := range cases { | ||
rd, err := CreateReaderAndDetermineDelimiter(nil, strings.NewReader(c.csv)) | ||
rd, err := CreateReaderAndDetermineDelimiter(nil, strings.NewReader(decodeSlashes(c.csv))) | ||
assert.NoError(t, err, "case %d: should not throw error: %v\n", n, err) | ||
assert.EqualValues(t, c.expectedDelimiter, rd.Comma, "case %d: delimiter should be '%c', got '%c'", n, c.expectedDelimiter, rd.Comma) | ||
rows, err := rd.ReadAll() | ||
|
@@ -222,7 +232,7 @@ John Doe [email protected] This,note,had,a,lot,of,commas,to,test,delimters`, | |
} | ||
|
||
for n, c := range cases { | ||
delimiter := determineDelimiter(&markup.RenderContext{Filename: c.filename}, []byte(c.csv)) | ||
delimiter := determineDelimiter(&markup.RenderContext{Filename: c.filename}, []byte(decodeSlashes(c.csv))) | ||
assert.EqualValues(t, c.expectedDelimiter, delimiter, "case %d: delimiter should be equal, expected '%c' got '%c'", n, c.expectedDelimiter, delimiter) | ||
} | ||
} | ||
|
@@ -287,7 +297,7 @@ abc | |123 | |
} | ||
|
||
for n, c := range cases { | ||
modifiedText := removeQuotedString(c.text) | ||
modifiedText := removeQuotedString(decodeSlashes(c.text)) | ||
assert.EqualValues(t, c.expectedText, modifiedText, "case %d: modified text should be equal", n) | ||
} | ||
} | ||
|
@@ -353,7 +363,7 @@ John Doe [email protected] This,note,had,a,lot,of,commas,to,test,delimters`, | |
quoted, | ||
text," a | ||
2 "some, | ||
quoted, | ||
quoted,\t | ||
text," b | ||
3 "some, | ||
quoted, | ||
|
@@ -442,7 +452,7 @@ jkl`, | |
} | ||
|
||
for n, c := range cases { | ||
delimiter := guessDelimiter([]byte(c.csv)) | ||
delimiter := guessDelimiter([]byte(decodeSlashes(c.csv))) | ||
assert.EqualValues(t, c.expectedDelimiter, delimiter, "case %d: delimiter should be equal, expected '%c' got '%c'", n, c.expectedDelimiter, delimiter) | ||
} | ||
} | ||
|
@@ -459,7 +469,7 @@ func TestGuessFromBeforeAfterQuotes(t *testing.T) { | |
quoted, | ||
text," a | ||
2 "some, | ||
quoted, | ||
quoted,\t | ||
text," b | ||
3 "some, | ||
quoted, | ||
|
@@ -534,7 +544,7 @@ a|"he said, ""here I am"""`, | |
} | ||
|
||
for n, c := range cases { | ||
delimiter := guessFromBeforeAfterQuotes([]byte(c.csv)) | ||
delimiter := guessFromBeforeAfterQuotes([]byte(decodeSlashes(c.csv))) | ||
assert.EqualValues(t, c.expectedDelimiter, delimiter, "case %d: delimiter should be equal, expected '%c' got '%c'", n, c.expectedDelimiter, delimiter) | ||
} | ||
} | ||
|
@@ -549,6 +559,10 @@ 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 TestFormatError(t *testing.T) { | ||
var cases = []struct { | ||
err error | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,7 @@ import ( | |
type Locale interface { | ||
Language() string | ||
Tr(string, ...interface{}) string | ||
TrN(cnt interface{}, key1, keyN string, args ...interface{}) string | ||
} | ||
|
||
// LangType represents a lang type | ||
|
@@ -99,3 +100,66 @@ func (l *locale) Language() string { | |
func (l *locale) Tr(format string, args ...interface{}) string { | ||
return i18n.Tr(l.Lang, format, args...) | ||
} | ||
|
||
// Language specific rules for translating plural texts | ||
var trNLangRules = map[string]func(int64) int{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Off-Topic: I didn't knew about this one, is this documented somewhere for translators? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have no idea about IMO it's mostly a knowledge for developers. If a developer write "text_1" and "text_n", the translators could just translate them without knowing |
||
"en-US": func(cnt int64) int { | ||
6543 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if cnt == 1 { | ||
return 0 | ||
} | ||
return 1 | ||
}, | ||
"lv-LV": func(cnt int64) int { | ||
if cnt%10 == 1 && cnt%100 != 11 { | ||
return 0 | ||
} | ||
return 1 | ||
}, | ||
"ru-RU": func(cnt int64) int { | ||
if cnt%10 == 1 && cnt%100 != 11 { | ||
return 0 | ||
} | ||
return 1 | ||
}, | ||
"zh-CN": func(cnt int64) int { | ||
return 0 | ||
}, | ||
"zh-HK": func(cnt int64) int { | ||
return 0 | ||
}, | ||
"zh-TW": func(cnt int64) int { | ||
return 0 | ||
}, | ||
"fr-FR": func(cnt int64) int { | ||
if cnt > -2 && cnt < 2 { | ||
return 0 | ||
} | ||
return 1 | ||
}, | ||
} | ||
|
||
// TrN returns translated message for plural text translation | ||
func (l *locale) TrN(cnt interface{}, key1, keyN string, args ...interface{}) string { | ||
var c int64 | ||
if t, ok := cnt.(int); ok { | ||
c = int64(t) | ||
} else if t, ok := cnt.(int16); ok { | ||
c = int64(t) | ||
} else if t, ok := cnt.(int32); ok { | ||
c = int64(t) | ||
} else if t, ok := cnt.(int64); ok { | ||
c = t | ||
} else { | ||
return l.Tr(keyN, args...) | ||
} | ||
wxiaoguang marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
ruleFunc, ok := trNLangRules[l.Lang] | ||
if !ok { | ||
ruleFunc = trNLangRules["en-US"] | ||
} | ||
|
||
if ruleFunc(c) == 0 { | ||
return l.Tr(key1, args...) | ||
} | ||
return l.Tr(keyN, args...) | ||
} |
Uh oh!
There was an error while loading. Please reload this page.