Skip to content

Commit 529d2a5

Browse files
author
youthlin.chen
committed
feat: add most match
1 parent 5e6f1d7 commit 529d2a5

7 files changed

+262
-6
lines changed

README.md

+10-5
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,13 @@ path := "path/to/filename.po" // .po, .mo file
3737
path = "path/to/po_mo/dir" // or dir.
3838
// (mo po 同名的话,po 后加载,会覆盖 mo 文件,因为 po 是文本文件,方便修改生效)
3939
// 1 bind domain 绑定翻译文件
40-
t.Load(path)
41-
t.Bind("my-domain", path)
40+
t.Load(path) // 默认绑定在 default 域 会自动搜索路径下的文件,读取 po/mo 里的语言标签进行注册
41+
t.Bind("my-domain", path) // 或者指定Ø文本域
4242
// 2 set current domain 设置使用的文本域
4343
t.SetDomain("my-domain")
4444
// 3 set user language 设置用户语言
4545
// t.SetLocale("zh_CN")
46-
t.SetLocale("") // empty to use system default
46+
t.SetLocale(t.MostMatchLocale()) // empty to use system default
4747
// 4 use the gettext api 使用 gettext 翻译接口
4848
fmt.Println(t.T("Hello, world"))
4949
fmt.Println(t.T("Hello, %v", "Tom"))
@@ -139,10 +139,15 @@ t.D(domain).L(userLang).T("msg_id")
139139
```bash
140140
# if you use PoEdit, add a extractor
141141
# 如果你使用 PoEdit,在设置-提取器中新增一个提取器
142-
# ‪xgettext -C --add-comments=TRANSLATORS: --force-po -o %o %C %K %F
142+
# Language: Go, *.go 语言填 Go 扩展名填 *.go 提取翻译的命令填写
143+
# xgettext -C --add-comments=TRANSLATORS: --force-po -o %o %C %K %F
144+
# 最后的三个输入框分别填写
145+
# -k%k
146+
# %f
147+
# --from-code=%c
143148
# keywords: 关键字这样设置:
144149
# T:1;N:1,2;N64:1,2;X:2,1c;XN:2,3,1c;XN64:2,3,1c
145-
xgettext -C --add-comments=TRANSLATORS: --force-po -kT -kN:1,2 -kX:2,1c -kXN:2,3,1c *.go
150+
xgettext -C --add-comments=TRANSLATORS: --force-po -kT -kN:1,2 -kX:2,1c -kXN:2,3,1c *.go
146151
```
147152

148153
## Done 已完成

init.go

+5
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ func Locale() string {
4141
return global.Locale()
4242
}
4343

44+
// MostMatchLocale return the most match language 返回最匹配的语言
45+
func MostMatchLocale() string {
46+
return global.MostMatchLocale()
47+
}
48+
4449
// SetLocale set user language
4550
func SetLocale(locale string) {
4651
global.SetLocale(locale)

matcher.go

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package t
2+
3+
import "golang.org/x/text/language"
4+
5+
func Match(supported []string, userAccept []string) (tag language.Tag, index int, c language.Confidence) {
6+
return MatchTag(Tags(supported), Tags(userAccept))
7+
}
8+
9+
func MatchTag(supportedTags []language.Tag, userAcceptTags []language.Tag) (tag language.Tag, index int, c language.Confidence) {
10+
matcher := language.NewMatcher(supportedTags)
11+
return matcher.Match(userAcceptTags...)
12+
}

matcher_test.go

+174
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
package t
2+
3+
import (
4+
"reflect"
5+
"testing"
6+
7+
"golang.org/x/text/language"
8+
)
9+
10+
func TestMatch(t *testing.T) {
11+
type args struct {
12+
supported []string
13+
userAccept []string
14+
}
15+
tests := []struct {
16+
name string
17+
args args
18+
wantTag language.Tag
19+
wantIndex int
20+
wantC language.Confidence
21+
}{
22+
{
23+
name: "exact", // 精确匹配
24+
args: args{supported: []string{"zh-CN"}, userAccept: []string{"zh-CN"}},
25+
wantTag: language.Make("zh-CN"),
26+
wantIndex: 0,
27+
wantC: language.Exact,
28+
},
29+
{
30+
name: "exact2", // 精确匹配
31+
args: args{supported: []string{"en-US", "zh-CN"}, userAccept: []string{"zh-CN"}},
32+
wantTag: language.Make("zh-CN"),
33+
wantIndex: 1,
34+
wantC: language.Exact,
35+
},
36+
{
37+
name: "exact3", // 精确匹配 zh 默认就是指 zh-CN
38+
args: args{supported: []string{"zh"}, userAccept: []string{"zh-CN"}},
39+
wantTag: language.Make("zh-u-rg-cnzzzz"), // 但返回的 tag 和 support / userAccept 都不同(带 -u 后缀指定了地区 rg=region?)
40+
wantIndex: 0, // 使用 supported 的第 0 个,即 zh
41+
wantC: language.Exact,
42+
},
43+
{
44+
name: "exact4", // 精确匹配 zh-Hant 繁体中文默认就是指 中国台湾的繁体中文
45+
args: args{supported: []string{"zh-Hant"}, userAccept: []string{"zh-TW"}},
46+
wantTag: language.Make("zh-Hant-u-rg-twzzzz"),
47+
wantIndex: 0,
48+
wantC: language.Exact,
49+
},
50+
{
51+
name: "exact5", // 精确匹配 zh-HK 中国香港 默认就是 Hant 繁体
52+
args: args{supported: []string{"zh-Hant-HK"}, userAccept: []string{"zh-HK"}},
53+
wantTag: language.Make("zh-Hant-HK"),
54+
wantIndex: 0,
55+
wantC: language.Exact,
56+
},
57+
{
58+
name: "exact6", // 精确匹配 en 默认就是指美国英语
59+
args: args{supported: []string{"en"}, userAccept: []string{"en-US"}},
60+
wantTag: language.Make("en-u-rg-uszzzz"),
61+
wantIndex: 0,
62+
wantC: language.Exact,
63+
},
64+
{
65+
name: "exact7", // 精确匹配
66+
args: args{supported: []string{"en"}, userAccept: []string{"en"}},
67+
wantTag: language.Make("en"),
68+
wantIndex: 0,
69+
wantC: language.Exact,
70+
},
71+
72+
{
73+
name: "high", // 高度匹配 zh-HK中国香港也使用 zh-Hant 繁体中文(未指明地区时其实默认是指中国台湾)
74+
args: args{supported: []string{"zh-Hant"}, userAccept: []string{"zh-HK"}},
75+
wantTag: language.Make("zh-Hant-u-rg-hkzzzz"),
76+
wantIndex: 0,
77+
wantC: language.High,
78+
},
79+
{
80+
name: "high2", // 高度匹配 提供了 zh-CN中国大陆,zh-MO中国澳门, zh-HK中国香港 更匹配同样使用 Hant繁体 的澳门
81+
args: args{supported: []string{"zh-CN", "zh-MO"}, userAccept: []string{"zh-HK"}},
82+
wantTag: language.Make("zh-MO-u-rg-hkzzzz"),
83+
wantIndex: 1,
84+
wantC: language.High,
85+
},
86+
{
87+
name: "high3", // 高度匹配 en 默认指美国英语 en-GB 英国也是英语
88+
args: args{supported: []string{"en"}, userAccept: []string{"en-GB"}},
89+
wantTag: language.Make("en-u-rg-gbzzzz"),
90+
wantIndex: 0,
91+
wantC: language.High,
92+
},
93+
94+
{
95+
name: "low", // 也算找到了最接近的
96+
args: args{supported: []string{"en", "zh"}, userAccept: []string{"zh-HK"}},
97+
wantTag: language.Make("zh-u-rg-hkzzzz"),
98+
wantIndex: 1,
99+
wantC: language.Low,
100+
},
101+
{
102+
name: "low2", // 也算找到了最接近的 zh-CN中国大陆,从 英文,繁体中文(中国台湾) 中选择 繁体中文 最接近
103+
args: args{supported: []string{"en", "zh-TW"}, userAccept: []string{"zh-CN"}},
104+
wantTag: language.Make("zh-TW-u-rg-cnzzzz"),
105+
wantIndex: 1,
106+
wantC: language.Low,
107+
},
108+
109+
{
110+
name: "no", // 不匹配
111+
args: args{supported: []string{"en"}, userAccept: []string{"zh-HK"}},
112+
wantTag: language.Make("en-u-rg-hkzzzz"),
113+
wantIndex: 0,
114+
wantC: language.No,
115+
},
116+
{
117+
name: "no1", // 不匹配
118+
args: args{supported: []string{"en-US"}, userAccept: []string{"zh-HK"}},
119+
wantTag: language.Make("en-US-u-rg-hkzzzz"),
120+
wantIndex: 0,
121+
wantC: language.No,
122+
},
123+
{
124+
name: "no2", // 不匹配
125+
args: args{supported: []string{"en"}, userAccept: []string{"zh"}},
126+
wantTag: language.Make("en"),
127+
wantIndex: 0,
128+
wantC: language.No,
129+
},
130+
{
131+
name: "no3", // 不匹配
132+
args: args{supported: []string{"en"}, userAccept: []string{"zh-Hans"}},
133+
wantTag: language.Make("en"),
134+
wantIndex: 0,
135+
wantC: language.No,
136+
},
137+
{
138+
name: "no4", // 不匹配
139+
args: args{supported: []string{"ja"}, userAccept: []string{"zh-CN"}},
140+
wantTag: language.Make("ja-u-rg-cnzzzz"),
141+
wantIndex: 0,
142+
wantC: language.No,
143+
},
144+
{
145+
name: "no5", // 不匹配
146+
args: args{supported: []string{"ja", "en"}, userAccept: []string{"zh"}},
147+
wantTag: language.Make("ja"), // 不匹配时都是返回第 0 个 supported
148+
wantIndex: 0,
149+
wantC: language.No,
150+
},
151+
{
152+
name: "no6", // 不匹配
153+
args: args{supported: []string{"en", "jp"}, userAccept: []string{"zh"}},
154+
wantTag: language.Make("en"),
155+
wantIndex: 0,
156+
wantC: language.No,
157+
},
158+
}
159+
160+
for _, tt := range tests {
161+
t.Run(tt.name, func(t *testing.T) {
162+
gotTag, gotIndex, gotC := Match(tt.args.supported, tt.args.userAccept)
163+
if !reflect.DeepEqual(gotTag, tt.wantTag) {
164+
t.Errorf("Match() gotTag = %v, want %v", gotTag, tt.wantTag)
165+
}
166+
if gotIndex != tt.wantIndex {
167+
t.Errorf("Match() gotIndex = %v, want %v", gotIndex, tt.wantIndex)
168+
}
169+
if !reflect.DeepEqual(gotC, tt.wantC) {
170+
t.Errorf("Match() gotC = %v, want %v", gotC, tt.wantC)
171+
}
172+
})
173+
}
174+
}

tag.go

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package t
2+
3+
import (
4+
"sync"
5+
6+
"golang.org/x/text/language"
7+
)
8+
9+
var cachedTag sync.Map
10+
11+
func Tag(locale string) language.Tag {
12+
if v, ok := cachedTag.Load(locale); ok {
13+
return v.(language.Tag)
14+
}
15+
tag := language.Make(locale)
16+
cachedTag.Store(locale, tag)
17+
return tag
18+
}
19+
20+
func Tags(locales []string) (tags []language.Tag) {
21+
for _, locale := range locales {
22+
tags = append(tags, Tag(locale))
23+
}
24+
return
25+
}

tag_test.go

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package t
2+
3+
import (
4+
"reflect"
5+
"testing"
6+
7+
"golang.org/x/text/language"
8+
)
9+
10+
func TestTags(t *testing.T) {
11+
type args struct {
12+
locales []string
13+
}
14+
tests := []struct {
15+
name string
16+
args args
17+
wantTags []language.Tag
18+
}{
19+
{"tags", args{[]string{"zh", "zh"}}, []language.Tag{language.Make("zh"), language.Make("zh")}},
20+
}
21+
for _, tt := range tests {
22+
t.Run(tt.name, func(t *testing.T) {
23+
if gotTags := Tags(tt.args.locales); !reflect.DeepEqual(gotTags, tt.wantTags) {
24+
t.Errorf("Tags() = %v, want %v", gotTags, tt.wantTags)
25+
}
26+
})
27+
}
28+
}

translations.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ func (ts *Translations) Domains() (domains []string) {
8686
return
8787
}
8888

89-
// Locale return current locale 返回当前使用的语言
89+
// Locale return current locale 返回设置的希望使用的语言
9090
func (ts *Translations) Locale() string {
9191
return ts.locale
9292
}
@@ -108,6 +108,13 @@ func (ts *Translations) Locales() (locales []string) {
108108
return
109109
}
110110

111+
// MostMatchLocale return the most match language 返回最匹配的语言
112+
func (ts *Translations) MostMatchLocale() string {
113+
var supported = Locales()
114+
_, index, _ := Match(supported, []string{Locale()})
115+
return supported[index]
116+
}
117+
111118
// UsedLocale return the locale that actually used
112119
func (ts *Translations) UsedLocale() string {
113120
tr, ok := ts.Get(ts.domain)

0 commit comments

Comments
 (0)