1
2
3
4
5 package display
6
7
8
9
10 import (
11 "fmt"
12 "sort"
13 "strings"
14
15 "golang.org/x/text/language"
16 )
17
18 type namer interface {
19
20
21 name(idx int) string
22 }
23
24 func nameLanguage(n namer, x interface{}) string {
25 t, _ := language.All.Compose(x)
26 for {
27 i, _, _ := langTagSet.index(t.Raw())
28 if s := n.name(i); s != "" {
29 return s
30 }
31 if t = t.Parent(); t == language.Und {
32 return ""
33 }
34 }
35 }
36
37 func nameScript(n namer, x interface{}) string {
38 t, _ := language.DeprecatedScript.Compose(x)
39 _, s, _ := t.Raw()
40 return n.name(scriptIndex.index(s.String()))
41 }
42
43 func nameRegion(n namer, x interface{}) string {
44 t, _ := language.DeprecatedRegion.Compose(x)
45 _, _, r := t.Raw()
46 return n.name(regionIndex.index(r.String()))
47 }
48
49 func nameTag(langN, scrN, regN namer, x interface{}) string {
50 t, ok := x.(language.Tag)
51 if !ok {
52 return ""
53 }
54 const form = language.All &^ language.SuppressScript
55 if c, err := form.Canonicalize(t); err == nil {
56 t = c
57 }
58 _, sRaw, rRaw := t.Raw()
59 i, scr, reg := langTagSet.index(t.Raw())
60 for i != -1 {
61 if str := langN.name(i); str != "" {
62 if hasS, hasR := (scr != language.Script{}), (reg != language.Region{}); hasS || hasR {
63 ss, sr := "", ""
64 if hasS {
65 ss = scrN.name(scriptIndex.index(scr.String()))
66 }
67 if hasR {
68 sr = regN.name(regionIndex.index(reg.String()))
69 }
70
71
72 if ss != "" && sr != "" {
73 return fmt.Sprintf("%s (%s, %s)", str, ss, sr)
74 }
75 if ss != "" || sr != "" {
76 return fmt.Sprintf("%s (%s%s)", str, ss, sr)
77 }
78 }
79 return str
80 }
81 scr, reg = sRaw, rRaw
82 if t = t.Parent(); t == language.Und {
83 return ""
84 }
85 i, _, _ = langTagSet.index(t.Raw())
86 }
87 return ""
88 }
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105 type header struct {
106 data string
107 index []uint16
108 }
109
110
111 func (h *header) name(i int) string {
112 if 0 <= i && i < len(h.index)-1 {
113 return h.data[h.index[i]:h.index[i+1]]
114 }
115 return ""
116 }
117
118
119 type tagSet struct {
120 single tagIndex
121 long []string
122 }
123
124 var (
125 langTagSet = tagSet{
126 single: langIndex,
127 long: langTagsLong,
128 }
129
130
131
132 selfTagSet = tagSet{
133 single: selfIndex,
134 long: selfTagsLong,
135 }
136
137 zzzz = language.MustParseScript("Zzzz")
138 zz = language.MustParseRegion("ZZ")
139 )
140
141
142
143
144 func (ts *tagSet) index(base language.Base, scr language.Script, reg language.Region) (int, language.Script, language.Region) {
145 lang := base.String()
146 index := -1
147 if (scr != language.Script{} || reg != language.Region{}) {
148 if scr == zzzz {
149 scr = language.Script{}
150 }
151 if reg == zz {
152 reg = language.Region{}
153 }
154
155 i := sort.SearchStrings(ts.long, lang)
156
157 scrStr, regStr := scr.String(), reg.String()
158 for ; i < len(ts.long) && strings.HasPrefix(ts.long[i], lang); i++ {
159 if s := ts.long[i][len(lang)+1:]; s == scrStr {
160 scr = language.Script{}
161 index = i + ts.single.len()
162 break
163 } else if s == regStr {
164 reg = language.Region{}
165 index = i + ts.single.len()
166 break
167 }
168 }
169 }
170 if index == -1 {
171 index = ts.single.index(lang)
172 }
173 return index, scr, reg
174 }
175
176 func (ts *tagSet) Tags() []language.Tag {
177 tags := make([]language.Tag, 0, ts.single.len()+len(ts.long))
178 ts.single.keys(func(s string) {
179 tags = append(tags, language.Raw.MustParse(s))
180 })
181 for _, s := range ts.long {
182 tags = append(tags, language.Raw.MustParse(s))
183 }
184 return tags
185 }
186
187 func supportedScripts() []language.Script {
188 scr := make([]language.Script, 0, scriptIndex.len())
189 scriptIndex.keys(func(s string) {
190 scr = append(scr, language.MustParseScript(s))
191 })
192 return scr
193 }
194
195 func supportedRegions() []language.Region {
196 reg := make([]language.Region, 0, regionIndex.len())
197 regionIndex.keys(func(s string) {
198 reg = append(reg, language.MustParseRegion(s))
199 })
200 return reg
201 }
202
203
204
205
206
207
208
209
210
211
212
213
214
215 type tagIndex [3]string
216
217 func (t *tagIndex) index(s string) int {
218 sz := len(s)
219 if sz < 2 || 4 < sz {
220 return -1
221 }
222 a := t[sz-2]
223 index := sort.Search(len(a)/sz, func(i int) bool {
224 p := i * sz
225 return a[p:p+sz] >= s
226 })
227 p := index * sz
228 if end := p + sz; end > len(a) || a[p:end] != s {
229 return -1
230 }
231
232 for i := 0; i < sz-2; i++ {
233 index += len(t[i]) / (i + 2)
234 }
235 return index
236 }
237
238
239 func (t *tagIndex) len() (n int) {
240 for i, s := range t {
241 n += len(s) / (i + 2)
242 }
243 return n
244 }
245
246
247 func (t *tagIndex) keys(f func(key string)) {
248 for i, s := range *t {
249 for ; s != ""; s = s[i+2:] {
250 f(s[:i+2])
251 }
252 }
253 }
254
View as plain text