1 // Copyright 2013 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
9 type scriptRegionFlags uint8
17 func (t *Tag) setUndefinedLang(id Language) {
23 func (t *Tag) setUndefinedScript(id Script) {
29 func (t *Tag) setUndefinedRegion(id Region) {
30 if t.RegionID == 0 || t.RegionID.Contains(id) {
35 // ErrMissingLikelyTagsData indicates no information was available
36 // to compute likely values of missing tags.
37 var ErrMissingLikelyTagsData = errors.New("missing likely tags data")
39 // addLikelySubtags sets subtags to their most likely value, given the locale.
40 // In most cases this means setting fields for unknown values, but in some
41 // cases it may alter a value. It returns an ErrMissingLikelyTagsData error
42 // if the given locale cannot be expanded.
43 func (t Tag) addLikelySubtags() (Tag, error) {
47 } else if id.equalTags(t) {
54 // specializeRegion attempts to specialize a group region.
55 func specializeRegion(t *Tag) bool {
56 if i := regionInclusion[t.RegionID]; i < nRegionGroups {
57 x := likelyRegionGroup[i]
58 if Language(x.lang) == t.LangID && Script(x.script) == t.ScriptID {
59 t.RegionID = Region(x.region)
66 // Maximize returns a new tag with missing tags filled in.
67 func (t Tag) Maximize() (Tag, error) {
71 func addTags(t Tag) (Tag, error) {
72 // We leave private use identifiers alone.
76 if t.ScriptID != 0 && t.RegionID != 0 {
78 // already fully specified
82 // Search matches for und-script-region. Note that for these cases
83 // region will never be a group so there is no need to check for this.
84 list := likelyRegion[t.RegionID : t.RegionID+1]
85 if x := list[0]; x.flags&isList != 0 {
86 list = likelyRegionList[x.lang : x.lang+uint16(x.script)]
88 for _, x := range list {
89 // Deviating from the spec. See match_test.go for details.
90 if Script(x.script) == t.ScriptID {
91 t.setUndefinedLang(Language(x.lang))
97 // Search matches for lang-script and lang-region, where lang != und.
98 if t.LangID < langNoIndexOffset {
99 x := likelyLang[t.LangID]
100 if x.flags&isList != 0 {
101 list := likelyLangList[x.region : x.region+uint16(x.script)]
103 for _, x := range list {
104 if Script(x.script) == t.ScriptID && x.flags&scriptInFrom != 0 {
105 t.setUndefinedRegion(Region(x.region))
109 } else if t.RegionID != 0 {
113 for _, x := range list {
114 // We visit all entries for which the script was not
115 // defined, including the ones where the region was not
116 // defined. This allows for proper disambiguation within
118 if x.flags&scriptInFrom == 0 && t.RegionID.Contains(Region(x.region)) {
119 tt.RegionID = Region(x.region)
120 tt.setUndefinedScript(Script(x.script))
121 goodScript = goodScript && tt.ScriptID == Script(x.script)
128 // Even if we fail to find a unique Region, we might have
129 // an unambiguous script.
131 t.ScriptID = tt.ScriptID
137 // Search matches for und-script.
139 x := likelyScript[t.ScriptID]
141 t.setUndefinedRegion(Region(x.region))
142 t.setUndefinedLang(Language(x.lang))
146 // Search matches for und-region. If und-script-region exists, it would
147 // have been found earlier.
149 if i := regionInclusion[t.RegionID]; i < nRegionGroups {
150 x := likelyRegionGroup[i]
152 t.setUndefinedLang(Language(x.lang))
153 t.setUndefinedScript(Script(x.script))
154 t.RegionID = Region(x.region)
157 x := likelyRegion[t.RegionID]
158 if x.flags&isList != 0 {
159 x = likelyRegionList[x.lang]
161 if x.script != 0 && x.flags != scriptInFrom {
162 t.setUndefinedLang(Language(x.lang))
163 t.setUndefinedScript(Script(x.script))
170 // Search matches for lang.
171 if t.LangID < langNoIndexOffset {
172 x := likelyLang[t.LangID]
173 if x.flags&isList != 0 {
174 x = likelyLangList[x.region]
177 t.setUndefinedScript(Script(x.script))
178 t.setUndefinedRegion(Region(x.region))
182 t.LangID = _en // default language
186 return t, ErrMissingLikelyTagsData
189 func (t *Tag) setTagsFrom(id Tag) {
191 t.ScriptID = id.ScriptID
192 t.RegionID = id.RegionID
195 // minimize removes the region or script subtags from t such that
196 // t.addLikelySubtags() == t.minimize().addLikelySubtags().
197 func (t Tag) minimize() (Tag, error) {
198 t, err := minimizeTags(t)
206 // minimizeTags mimics the behavior of the ICU 51 C implementation.
207 func minimizeTags(t Tag) (Tag, error) {
208 if t.equalTags(Und) {
211 max, err := addTags(t)
215 for _, id := range [...]Tag{
217 {LangID: t.LangID, RegionID: t.RegionID},
218 {LangID: t.LangID, ScriptID: t.ScriptID},
220 if x, err := addTags(id); err == nil && max.equalTags(x) {