github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/golang/text/language/coverage.go (about) 1 // Copyright 2014 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. 4 5 package language 6 7 import ( 8 "fmt" 9 "sort" 10 ) 11 12 // The Coverage interface is used to define the level of coverage of an 13 // internationalization service. Note that not all types are supported by all 14 // services. As lists may be generated on the fly, it is recommended that users 15 // of a Coverage cache the results. 16 type Coverage interface { 17 // Tags returns the list of supported tags. 18 Tags() []Tag 19 20 // BaseLanguages returns the list of supported base languages. 21 BaseLanguages() []Base 22 23 // Scripts returns the list of supported scripts. 24 Scripts() []Script 25 26 // Regions returns the list of supported regions. 27 Regions() []Region 28 } 29 30 var ( 31 // Supported defines a Coverage that lists all supported subtags. Tags 32 // always returns nil. 33 Supported Coverage = allSubtags{} 34 ) 35 36 // TODO: 37 // - Support Variants, numbering systems. 38 // - CLDR coverage levels. 39 // - Set of common tags defined in this package. 40 41 type allSubtags struct{} 42 43 // Regions returns the list of supported regions. As all regions are in a 44 // consecutive range, it simply returns a slice of numbers in increasing order. 45 // The "undefined" region is not returned. 46 func (s allSubtags) Regions() []Region { 47 reg := make([]Region, numRegions) 48 for i := range reg { 49 reg[i] = Region{regionID(i + 1)} 50 } 51 return reg 52 } 53 54 // Scripts returns the list of supported scripts. As all scripts are in a 55 // consecutive range, it simply returns a slice of numbers in increasing order. 56 // The "undefined" script is not returned. 57 func (s allSubtags) Scripts() []Script { 58 scr := make([]Script, numScripts) 59 for i := range scr { 60 scr[i] = Script{scriptID(i + 1)} 61 } 62 return scr 63 } 64 65 // BaseLanguages returns the list of all supported base languages. It generates 66 // the list by traversing the internal structures. 67 func (s allSubtags) BaseLanguages() []Base { 68 base := make([]Base, 0, numLanguages) 69 for i := 0; i < langNoIndexOffset; i++ { 70 // We included "und" already for the value 0. 71 if i != nonCanonicalUnd { 72 base = append(base, Base{langID(i)}) 73 } 74 } 75 i := langNoIndexOffset 76 for _, v := range langNoIndex { 77 for k := 0; k < 8; k++ { 78 if v&1 == 1 { 79 base = append(base, Base{langID(i)}) 80 } 81 v >>= 1 82 i++ 83 } 84 } 85 return base 86 } 87 88 // Tags always returns nil. 89 func (s allSubtags) Tags() []Tag { 90 return nil 91 } 92 93 // coverage is used used by NewCoverage which is used as a convenient way for 94 // creating Coverage implementations for partially defined data. Very often a 95 // package will only need to define a subset of slices. coverage provides a 96 // convenient way to do this. Moreover, packages using NewCoverage, instead of 97 // their own implementation, will not break if later new slice types are added. 98 type coverage struct { 99 tags func() []Tag 100 bases func() []Base 101 scripts func() []Script 102 regions func() []Region 103 } 104 105 func (s *coverage) Tags() []Tag { 106 if s.tags == nil { 107 return nil 108 } 109 return s.tags() 110 } 111 112 // bases implements sort.Interface and is used to sort base languages. 113 type bases []Base 114 115 func (b bases) Len() int { 116 return len(b) 117 } 118 119 func (b bases) Swap(i, j int) { 120 b[i], b[j] = b[j], b[i] 121 } 122 123 func (b bases) Less(i, j int) bool { 124 return b[i].langID < b[j].langID 125 } 126 127 // BaseLanguages returns the result from calling s.bases if it is specified or 128 // otherwise derives the set of supported base languages from tags. 129 func (s *coverage) BaseLanguages() []Base { 130 if s.bases == nil { 131 tags := s.Tags() 132 if len(tags) == 0 { 133 return nil 134 } 135 a := make([]Base, len(tags)) 136 for i, t := range tags { 137 a[i] = Base{langID(t.lang)} 138 } 139 sort.Sort(bases(a)) 140 k := 0 141 for i := 1; i < len(a); i++ { 142 if a[k] != a[i] { 143 k++ 144 a[k] = a[i] 145 } 146 } 147 return a[:k+1] 148 } 149 return s.bases() 150 } 151 152 func (s *coverage) Scripts() []Script { 153 if s.scripts == nil { 154 return nil 155 } 156 return s.scripts() 157 } 158 159 func (s *coverage) Regions() []Region { 160 if s.regions == nil { 161 return nil 162 } 163 return s.regions() 164 } 165 166 // NewCoverage returns a Coverage for the given lists. It is typically used by 167 // packages providing internationalization services to define their level of 168 // coverage. A list may be of type []T or func() []T, where T is either Tag, 169 // Base, Script or Region. The returned Coverage derives the value for Bases 170 // from Tags if no func or slice for []Base is specified. For other unspecified 171 // types the returned Coverage will return nil for the respective methods. 172 func NewCoverage(list ...interface{}) Coverage { 173 s := &coverage{} 174 for _, x := range list { 175 switch v := x.(type) { 176 case func() []Base: 177 s.bases = v 178 case func() []Script: 179 s.scripts = v 180 case func() []Region: 181 s.regions = v 182 case func() []Tag: 183 s.tags = v 184 case []Base: 185 s.bases = func() []Base { return v } 186 case []Script: 187 s.scripts = func() []Script { return v } 188 case []Region: 189 s.regions = func() []Region { return v } 190 case []Tag: 191 s.tags = func() []Tag { return v } 192 default: 193 panic(fmt.Sprintf("language: unsupported set type %T", v)) 194 } 195 } 196 return s 197 }