mirror of https://github.com/gogits/gogs.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
197 lines
5.0 KiB
197 lines
5.0 KiB
// 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" |
|
) |
|
|
|
// 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, numRegions) |
|
for i := range reg { |
|
reg[i] = Region{regionID(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, numScripts) |
|
for i := range scr { |
|
scr[i] = Script{scriptID(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 { |
|
base := make([]Base, 0, numLanguages) |
|
for i := 0; i < langNoIndexOffset; i++ { |
|
// We included "und" already for the value 0. |
|
if i != nonCanonicalUnd { |
|
base = append(base, Base{langID(i)}) |
|
} |
|
} |
|
i := langNoIndexOffset |
|
for _, v := range langNoIndex { |
|
for k := 0; k < 8; k++ { |
|
if v&1 == 1 { |
|
base = append(base, Base{langID(i)}) |
|
} |
|
v >>= 1 |
|
i++ |
|
} |
|
} |
|
return base |
|
} |
|
|
|
// Tags always returns nil. |
|
func (s allSubtags) Tags() []Tag { |
|
return nil |
|
} |
|
|
|
// coverage is used 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{langID(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 |
|
}
|
|
|