1
2
3
4
5
6
7
8 package compact
9
10
11
12
13 import (
14 "strings"
15
16 "golang.org/x/text/internal/language"
17 )
18
19
20
21
22 type Tag struct {
23
24 language ID
25 locale ID
26 full fullTag
27 }
28
29 const _und = 0
30
31 type fullTag interface {
32 IsRoot() bool
33 Parent() language.Tag
34 }
35
36
37 func Make(t language.Tag) (tag Tag) {
38 if region := t.TypeForKey("rg"); len(region) == 6 && region[2:] == "zzzz" {
39 if r, err := language.ParseRegion(region[:2]); err == nil {
40 tFull := t
41 t, _ = t.SetTypeForKey("rg", "")
42
43 var exact1, exact2 bool
44 tag.language, exact1 = FromTag(t)
45 t.RegionID = r
46 tag.locale, exact2 = FromTag(t)
47 if !exact1 || !exact2 {
48 tag.full = tFull
49 }
50 return tag
51 }
52 }
53 lang, ok := FromTag(t)
54 tag.language = lang
55 tag.locale = lang
56 if !ok {
57 tag.full = t
58 }
59 return tag
60 }
61
62
63 func (t Tag) Tag() language.Tag {
64 if t.full != nil {
65 return t.full.(language.Tag)
66 }
67 tag := t.language.Tag()
68 if t.language != t.locale {
69 loc := t.locale.Tag()
70 tag, _ = tag.SetTypeForKey("rg", strings.ToLower(loc.RegionID.String())+"zzzz")
71 }
72 return tag
73 }
74
75
76 func (t *Tag) IsCompact() bool {
77 return t.full == nil
78 }
79
80
81
82 func (t Tag) MayHaveVariants() bool {
83 return t.full != nil || int(t.language) >= len(coreTags)
84 }
85
86
87
88 func (t Tag) MayHaveExtensions() bool {
89 return t.full != nil ||
90 int(t.language) >= len(coreTags) ||
91 t.language != t.locale
92 }
93
94
95 func (t Tag) IsRoot() bool {
96 if t.full != nil {
97 return t.full.IsRoot()
98 }
99 return t.language == _und
100 }
101
102
103
104
105 func (t Tag) Parent() Tag {
106 if t.full != nil {
107 return Make(t.full.Parent())
108 }
109 if t.language != t.locale {
110
111 return Tag{language: t.language, locale: t.language}
112 }
113
114
115
116
117 lang, _ := FromTag(t.language.Tag().Parent())
118 return Tag{language: lang, locale: lang}
119 }
120
121
122 func nextToken(s string) (t, tail string) {
123 p := strings.Index(s[1:], "-")
124 if p == -1 {
125 return s[1:], ""
126 }
127 p++
128 return s[1:p], s[p:]
129 }
130
131
132
133
134
135
136 func LanguageID(t Tag) (id ID, exact bool) {
137 return t.language, t.full == nil
138 }
139
140
141
142
143
144
145
146
147
148
149 func RegionalID(t Tag) (id ID, exact bool) {
150 return t.locale, t.full == nil
151 }
152
153
154
155
156
157 func (t Tag) LanguageTag() Tag {
158 if t.full == nil {
159 return Tag{language: t.language, locale: t.language}
160 }
161 tt := t.Tag()
162 tt.SetTypeForKey("rg", "")
163 tt.SetTypeForKey("va", "")
164 return Make(tt)
165 }
166
167
168
169
170
171 func (t Tag) RegionalTag() Tag {
172 rt := Tag{language: t.locale, locale: t.locale}
173 if t.full == nil {
174 return rt
175 }
176 b := language.Builder{}
177 tag := t.Tag()
178
179 b.SetTag(t.locale.Tag())
180 if v := tag.Variants(); v != "" {
181 for _, v := range strings.Split(v, "-") {
182 b.AddVariant(v)
183 }
184 }
185 for _, e := range tag.Extensions() {
186 b.AddExt(e)
187 }
188 return t
189 }
190
191
192 func FromTag(t language.Tag) (id ID, exact bool) {
193
194
195
196 exact = true
197
198 b, s, r := t.Raw()
199 if t.HasString() {
200 if t.IsPrivateUse() {
201
202 return 0, false
203 }
204 hasExtra := false
205 if t.HasVariants() {
206 if t.HasExtensions() {
207 build := language.Builder{}
208 build.SetTag(language.Tag{LangID: b, ScriptID: s, RegionID: r})
209 build.AddVariant(t.Variants())
210 exact = false
211 t = build.Make()
212 }
213 hasExtra = true
214 } else if _, ok := t.Extension('u'); ok {
215
216
217 old := t
218 variant := t.TypeForKey("va")
219 t = language.Tag{LangID: b, ScriptID: s, RegionID: r}
220 if variant != "" {
221 t, _ = t.SetTypeForKey("va", variant)
222 hasExtra = true
223 }
224 exact = old == t
225 } else {
226 exact = false
227 }
228 if hasExtra {
229
230 for i, s := range specialTags {
231 if s == t {
232 return ID(i + len(coreTags)), exact
233 }
234 }
235 exact = false
236 }
237 }
238 if x, ok := getCoreIndex(t); ok {
239 return x, exact
240 }
241 exact = false
242 if r != 0 && s == 0 {
243
244 t, _ := t.Maximize()
245 if x, ok := getCoreIndex(t); ok {
246 return x, exact
247 }
248 }
249 for t = t.Parent(); t != root; t = t.Parent() {
250
251
252
253 if x, ok := getCoreIndex(t); ok {
254 return x, exact
255 }
256 }
257 return 0, exact
258 }
259
260 var root = language.Tag{}
261
View as plain text