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  }