// Copyright 2014 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package language import ( "fmt" "sort" "golang.org/x/text/internal/language" ) // The Coverage interface is used to define the level of coverage of an // internationalization service. Note that not all types are supported by all // services. As lists may be generated on the fly, it is recommended that users // of a Coverage cache the results. type Coverage interface { // Tags returns the list of supported tags. Tags() []Tag // BaseLanguages returns the list of supported base languages. BaseLanguages() []Base // Scripts returns the list of supported scripts. Scripts() []Script // Regions returns the list of supported regions. Regions() []Region } var ( // Supported defines a Coverage that lists all supported subtags. Tags // always returns nil. Supported Coverage = allSubtags{} ) // TODO: // - Support Variants, numbering systems. // - CLDR coverage levels. // - Set of common tags defined in this package. type allSubtags struct{} // Regions returns the list of supported regions. As all regions are in a // consecutive range, it simply returns a slice of numbers in increasing order. // The "undefined" region is not returned. func (s allSubtags) Regions() []Region { reg := make([]Region, language.NumRegions) for i := range reg { reg[i] = Region{language.Region(i + 1)} } return reg } // Scripts returns the list of supported scripts. As all scripts are in a // consecutive range, it simply returns a slice of numbers in increasing order. // The "undefined" script is not returned. func (s allSubtags) Scripts() []Script { scr := make([]Script, language.NumScripts) for i := range scr { scr[i] = Script{language.Script(i + 1)} } return scr } // BaseLanguages returns the list of all supported base languages. It generates // the list by traversing the internal structures. func (s allSubtags) BaseLanguages() []Base { bs := language.BaseLanguages() base := make([]Base, len(bs)) for i, b := range bs { base[i] = Base{b} } return base } // Tags always returns nil. func (s allSubtags) Tags() []Tag { return nil } // coverage is used by NewCoverage which is used as a convenient way for // creating Coverage implementations for partially defined data. Very often a // package will only need to define a subset of slices. coverage provides a // convenient way to do this. Moreover, packages using NewCoverage, instead of // their own implementation, will not break if later new slice types are added. type coverage struct { tags func() []Tag bases func() []Base scripts func() []Script regions func() []Region } func (s *coverage) Tags() []Tag { if s.tags == nil { return nil } return s.tags() } // bases implements sort.Interface and is used to sort base languages. type bases []Base func (b bases) Len() int { return len(b) } func (b bases) Swap(i, j int) { b[i], b[j] = b[j], b[i] } func (b bases) Less(i, j int) bool { return b[i].langID < b[j].langID } // BaseLanguages returns the result from calling s.bases if it is specified or // otherwise derives the set of supported base languages from tags. func (s *coverage) BaseLanguages() []Base { if s.bases == nil { tags := s.Tags() if len(tags) == 0 { return nil } a := make([]Base, len(tags)) for i, t := range tags { a[i] = Base{language.Language(t.lang())} } sort.Sort(bases(a)) k := 0 for i := 1; i < len(a); i++ { if a[k] != a[i] { k++ a[k] = a[i] } } return a[:k+1] } return s.bases() } func (s *coverage) Scripts() []Script { if s.scripts == nil { return nil } return s.scripts() } func (s *coverage) Regions() []Region { if s.regions == nil { return nil } return s.regions() } // NewCoverage returns a Coverage for the given lists. It is typically used by // packages providing internationalization services to define their level of // coverage. A list may be of type []T or func() []T, where T is either Tag, // Base, Script or Region. The returned Coverage derives the value for Bases // from Tags if no func or slice for []Base is specified. For other unspecified // types the returned Coverage will return nil for the respective methods. func NewCoverage(list ...interface{}) Coverage { s := &coverage{} for _, x := range list { switch v := x.(type) { case func() []Base: s.bases = v case func() []Script: s.scripts = v case func() []Region: s.regions = v case func() []Tag: s.tags = v case []Base: s.bases = func() []Base { return v } case []Script: s.scripts = func() []Script { return v } case []Region: s.regions = func() []Region { return v } case []Tag: s.tags = func() []Tag { return v } default: panic(fmt.Sprintf("language: unsupported set type %T", v)) } } return s }