* Update makefile to use dep * Migrate to dep * Fix some deps * Try to find a better version for golang.org/x/net * Try to find a better version for golang.org/x/oauth2
		
			
				
	
	
		
			603 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			603 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2013 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 cldr
 | |
| 
 | |
| // This file implements the various inheritance constructs defined by LDML.
 | |
| // See http://www.unicode.org/reports/tr35/#Inheritance_and_Validity
 | |
| // for more details.
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"log"
 | |
| 	"reflect"
 | |
| 	"regexp"
 | |
| 	"sort"
 | |
| 	"strings"
 | |
| )
 | |
| 
 | |
| // fieldIter iterates over fields in a struct. It includes
 | |
| // fields of embedded structs.
 | |
| type fieldIter struct {
 | |
| 	v        reflect.Value
 | |
| 	index, n []int
 | |
| }
 | |
| 
 | |
| func iter(v reflect.Value) fieldIter {
 | |
| 	if v.Kind() != reflect.Struct {
 | |
| 		log.Panicf("value %v must be a struct", v)
 | |
| 	}
 | |
| 	i := fieldIter{
 | |
| 		v:     v,
 | |
| 		index: []int{0},
 | |
| 		n:     []int{v.NumField()},
 | |
| 	}
 | |
| 	i.descent()
 | |
| 	return i
 | |
| }
 | |
| 
 | |
| func (i *fieldIter) descent() {
 | |
| 	for f := i.field(); f.Anonymous && f.Type.NumField() > 0; f = i.field() {
 | |
| 		i.index = append(i.index, 0)
 | |
| 		i.n = append(i.n, f.Type.NumField())
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (i *fieldIter) done() bool {
 | |
| 	return len(i.index) == 1 && i.index[0] >= i.n[0]
 | |
| }
 | |
| 
 | |
| func skip(f reflect.StructField) bool {
 | |
| 	return !f.Anonymous && (f.Name[0] < 'A' || f.Name[0] > 'Z')
 | |
| }
 | |
| 
 | |
| func (i *fieldIter) next() {
 | |
| 	for {
 | |
| 		k := len(i.index) - 1
 | |
| 		i.index[k]++
 | |
| 		if i.index[k] < i.n[k] {
 | |
| 			if !skip(i.field()) {
 | |
| 				break
 | |
| 			}
 | |
| 		} else {
 | |
| 			if k == 0 {
 | |
| 				return
 | |
| 			}
 | |
| 			i.index = i.index[:k]
 | |
| 			i.n = i.n[:k]
 | |
| 		}
 | |
| 	}
 | |
| 	i.descent()
 | |
| }
 | |
| 
 | |
| func (i *fieldIter) value() reflect.Value {
 | |
| 	return i.v.FieldByIndex(i.index)
 | |
| }
 | |
| 
 | |
| func (i *fieldIter) field() reflect.StructField {
 | |
| 	return i.v.Type().FieldByIndex(i.index)
 | |
| }
 | |
| 
 | |
| type visitor func(v reflect.Value) error
 | |
| 
 | |
| var stopDescent = fmt.Errorf("do not recurse")
 | |
| 
 | |
| func (f visitor) visit(x interface{}) error {
 | |
| 	return f.visitRec(reflect.ValueOf(x))
 | |
| }
 | |
| 
 | |
| // visit recursively calls f on all nodes in v.
 | |
| func (f visitor) visitRec(v reflect.Value) error {
 | |
| 	if v.Kind() == reflect.Ptr {
 | |
| 		if v.IsNil() {
 | |
| 			return nil
 | |
| 		}
 | |
| 		return f.visitRec(v.Elem())
 | |
| 	}
 | |
| 	if err := f(v); err != nil {
 | |
| 		if err == stopDescent {
 | |
| 			return nil
 | |
| 		}
 | |
| 		return err
 | |
| 	}
 | |
| 	switch v.Kind() {
 | |
| 	case reflect.Struct:
 | |
| 		for i := iter(v); !i.done(); i.next() {
 | |
| 			if err := f.visitRec(i.value()); err != nil {
 | |
| 				return err
 | |
| 			}
 | |
| 		}
 | |
| 	case reflect.Slice:
 | |
| 		for i := 0; i < v.Len(); i++ {
 | |
| 			if err := f.visitRec(v.Index(i)); err != nil {
 | |
| 				return err
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // getPath is used for error reporting purposes only.
 | |
| func getPath(e Elem) string {
 | |
| 	if e == nil {
 | |
| 		return "<nil>"
 | |
| 	}
 | |
| 	if e.enclosing() == nil {
 | |
| 		return e.GetCommon().name
 | |
| 	}
 | |
| 	if e.GetCommon().Type == "" {
 | |
| 		return fmt.Sprintf("%s.%s", getPath(e.enclosing()), e.GetCommon().name)
 | |
| 	}
 | |
| 	return fmt.Sprintf("%s.%s[type=%s]", getPath(e.enclosing()), e.GetCommon().name, e.GetCommon().Type)
 | |
| }
 | |
| 
 | |
| // xmlName returns the xml name of the element or attribute
 | |
| func xmlName(f reflect.StructField) (name string, attr bool) {
 | |
| 	tags := strings.Split(f.Tag.Get("xml"), ",")
 | |
| 	for _, s := range tags {
 | |
| 		attr = attr || s == "attr"
 | |
| 	}
 | |
| 	return tags[0], attr
 | |
| }
 | |
| 
 | |
| func findField(v reflect.Value, key string) (reflect.Value, error) {
 | |
| 	v = reflect.Indirect(v)
 | |
| 	for i := iter(v); !i.done(); i.next() {
 | |
| 		if n, _ := xmlName(i.field()); n == key {
 | |
| 			return i.value(), nil
 | |
| 		}
 | |
| 	}
 | |
| 	return reflect.Value{}, fmt.Errorf("cldr: no field %q in element %#v", key, v.Interface())
 | |
| }
 | |
| 
 | |
| var xpathPart = regexp.MustCompile(`(\pL+)(?:\[@(\pL+)='([\w-]+)'\])?`)
 | |
| 
 | |
| func walkXPath(e Elem, path string) (res Elem, err error) {
 | |
| 	for _, c := range strings.Split(path, "/") {
 | |
| 		if c == ".." {
 | |
| 			if e = e.enclosing(); e == nil {
 | |
| 				panic("path ..")
 | |
| 				return nil, fmt.Errorf(`cldr: ".." moves past root in path %q`, path)
 | |
| 			}
 | |
| 			continue
 | |
| 		} else if c == "" {
 | |
| 			continue
 | |
| 		}
 | |
| 		m := xpathPart.FindStringSubmatch(c)
 | |
| 		if len(m) == 0 || len(m[0]) != len(c) {
 | |
| 			return nil, fmt.Errorf("cldr: syntax error in path component %q", c)
 | |
| 		}
 | |
| 		v, err := findField(reflect.ValueOf(e), m[1])
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		switch v.Kind() {
 | |
| 		case reflect.Slice:
 | |
| 			i := 0
 | |
| 			if m[2] != "" || v.Len() > 1 {
 | |
| 				if m[2] == "" {
 | |
| 					m[2] = "type"
 | |
| 					if m[3] = e.GetCommon().Default(); m[3] == "" {
 | |
| 						return nil, fmt.Errorf("cldr: type selector or default value needed for element %s", m[1])
 | |
| 					}
 | |
| 				}
 | |
| 				for ; i < v.Len(); i++ {
 | |
| 					vi := v.Index(i)
 | |
| 					key, err := findField(vi.Elem(), m[2])
 | |
| 					if err != nil {
 | |
| 						return nil, err
 | |
| 					}
 | |
| 					key = reflect.Indirect(key)
 | |
| 					if key.Kind() == reflect.String && key.String() == m[3] {
 | |
| 						break
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 			if i == v.Len() || v.Index(i).IsNil() {
 | |
| 				return nil, fmt.Errorf("no %s found with %s==%s", m[1], m[2], m[3])
 | |
| 			}
 | |
| 			e = v.Index(i).Interface().(Elem)
 | |
| 		case reflect.Ptr:
 | |
| 			if v.IsNil() {
 | |
| 				return nil, fmt.Errorf("cldr: element %q not found within element %q", m[1], e.GetCommon().name)
 | |
| 			}
 | |
| 			var ok bool
 | |
| 			if e, ok = v.Interface().(Elem); !ok {
 | |
| 				return nil, fmt.Errorf("cldr: %q is not an XML element", m[1])
 | |
| 			} else if m[2] != "" || m[3] != "" {
 | |
| 				return nil, fmt.Errorf("cldr: no type selector allowed for element %s", m[1])
 | |
| 			}
 | |
| 		default:
 | |
| 			return nil, fmt.Errorf("cldr: %q is not an XML element", m[1])
 | |
| 		}
 | |
| 	}
 | |
| 	return e, nil
 | |
| }
 | |
| 
 | |
| const absPrefix = "//ldml/"
 | |
| 
 | |
| func (cldr *CLDR) resolveAlias(e Elem, src, path string) (res Elem, err error) {
 | |
| 	if src != "locale" {
 | |
| 		if !strings.HasPrefix(path, absPrefix) {
 | |
| 			return nil, fmt.Errorf("cldr: expected absolute path, found %q", path)
 | |
| 		}
 | |
| 		path = path[len(absPrefix):]
 | |
| 		if e, err = cldr.resolve(src); err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 	}
 | |
| 	return walkXPath(e, path)
 | |
| }
 | |
| 
 | |
| func (cldr *CLDR) resolveAndMergeAlias(e Elem) error {
 | |
| 	alias := e.GetCommon().Alias
 | |
| 	if alias == nil {
 | |
| 		return nil
 | |
| 	}
 | |
| 	a, err := cldr.resolveAlias(e, alias.Source, alias.Path)
 | |
| 	if err != nil {
 | |
| 		return fmt.Errorf("%v: error evaluating path %q: %v", getPath(e), alias.Path, err)
 | |
| 	}
 | |
| 	// Ensure alias node was already evaluated. TODO: avoid double evaluation.
 | |
| 	err = cldr.resolveAndMergeAlias(a)
 | |
| 	v := reflect.ValueOf(e).Elem()
 | |
| 	for i := iter(reflect.ValueOf(a).Elem()); !i.done(); i.next() {
 | |
| 		if vv := i.value(); vv.Kind() != reflect.Ptr || !vv.IsNil() {
 | |
| 			if _, attr := xmlName(i.field()); !attr {
 | |
| 				v.FieldByIndex(i.index).Set(vv)
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| func (cldr *CLDR) aliasResolver() visitor {
 | |
| 	return func(v reflect.Value) (err error) {
 | |
| 		if e, ok := v.Addr().Interface().(Elem); ok {
 | |
| 			err = cldr.resolveAndMergeAlias(e)
 | |
| 			if err == nil && blocking[e.GetCommon().name] {
 | |
| 				return stopDescent
 | |
| 			}
 | |
| 		}
 | |
| 		return err
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // elements within blocking elements do not inherit.
 | |
| // Taken from CLDR's supplementalMetaData.xml.
 | |
| var blocking = map[string]bool{
 | |
| 	"identity":         true,
 | |
| 	"supplementalData": true,
 | |
| 	"cldrTest":         true,
 | |
| 	"collation":        true,
 | |
| 	"transform":        true,
 | |
| }
 | |
| 
 | |
| // Distinguishing attributes affect inheritance; two elements with different
 | |
| // distinguishing attributes are treated as different for purposes of inheritance,
 | |
| // except when such attributes occur in the indicated elements.
 | |
| // Taken from CLDR's supplementalMetaData.xml.
 | |
| var distinguishing = map[string][]string{
 | |
| 	"key":        nil,
 | |
| 	"request_id": nil,
 | |
| 	"id":         nil,
 | |
| 	"registry":   nil,
 | |
| 	"alt":        nil,
 | |
| 	"iso4217":    nil,
 | |
| 	"iso3166":    nil,
 | |
| 	"mzone":      nil,
 | |
| 	"from":       nil,
 | |
| 	"to":         nil,
 | |
| 	"type": []string{
 | |
| 		"abbreviationFallback",
 | |
| 		"default",
 | |
| 		"mapping",
 | |
| 		"measurementSystem",
 | |
| 		"preferenceOrdering",
 | |
| 	},
 | |
| 	"numberSystem": nil,
 | |
| }
 | |
| 
 | |
| func in(set []string, s string) bool {
 | |
| 	for _, v := range set {
 | |
| 		if v == s {
 | |
| 			return true
 | |
| 		}
 | |
| 	}
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| // attrKey computes a key based on the distinguishable attributes of
 | |
| // an element and it's values.
 | |
| func attrKey(v reflect.Value, exclude ...string) string {
 | |
| 	parts := []string{}
 | |
| 	ename := v.Interface().(Elem).GetCommon().name
 | |
| 	v = v.Elem()
 | |
| 	for i := iter(v); !i.done(); i.next() {
 | |
| 		if name, attr := xmlName(i.field()); attr {
 | |
| 			if except, ok := distinguishing[name]; ok && !in(exclude, name) && !in(except, ename) {
 | |
| 				v := i.value()
 | |
| 				if v.Kind() == reflect.Ptr {
 | |
| 					v = v.Elem()
 | |
| 				}
 | |
| 				if v.IsValid() {
 | |
| 					parts = append(parts, fmt.Sprintf("%s=%s", name, v.String()))
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	sort.Strings(parts)
 | |
| 	return strings.Join(parts, ";")
 | |
| }
 | |
| 
 | |
| // Key returns a key for e derived from all distinguishing attributes
 | |
| // except those specified by exclude.
 | |
| func Key(e Elem, exclude ...string) string {
 | |
| 	return attrKey(reflect.ValueOf(e), exclude...)
 | |
| }
 | |
| 
 | |
| // linkEnclosing sets the enclosing element as well as the name
 | |
| // for all sub-elements of child, recursively.
 | |
| func linkEnclosing(parent, child Elem) {
 | |
| 	child.setEnclosing(parent)
 | |
| 	v := reflect.ValueOf(child).Elem()
 | |
| 	for i := iter(v); !i.done(); i.next() {
 | |
| 		vf := i.value()
 | |
| 		if vf.Kind() == reflect.Slice {
 | |
| 			for j := 0; j < vf.Len(); j++ {
 | |
| 				linkEnclosing(child, vf.Index(j).Interface().(Elem))
 | |
| 			}
 | |
| 		} else if vf.Kind() == reflect.Ptr && !vf.IsNil() && vf.Elem().Kind() == reflect.Struct {
 | |
| 			linkEnclosing(child, vf.Interface().(Elem))
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func setNames(e Elem, name string) {
 | |
| 	e.setName(name)
 | |
| 	v := reflect.ValueOf(e).Elem()
 | |
| 	for i := iter(v); !i.done(); i.next() {
 | |
| 		vf := i.value()
 | |
| 		name, _ = xmlName(i.field())
 | |
| 		if vf.Kind() == reflect.Slice {
 | |
| 			for j := 0; j < vf.Len(); j++ {
 | |
| 				setNames(vf.Index(j).Interface().(Elem), name)
 | |
| 			}
 | |
| 		} else if vf.Kind() == reflect.Ptr && !vf.IsNil() && vf.Elem().Kind() == reflect.Struct {
 | |
| 			setNames(vf.Interface().(Elem), name)
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // deepCopy copies elements of v recursively.  All elements of v that may
 | |
| // be modified by inheritance are explicitly copied.
 | |
| func deepCopy(v reflect.Value) reflect.Value {
 | |
| 	switch v.Kind() {
 | |
| 	case reflect.Ptr:
 | |
| 		if v.IsNil() || v.Elem().Kind() != reflect.Struct {
 | |
| 			return v
 | |
| 		}
 | |
| 		nv := reflect.New(v.Elem().Type())
 | |
| 		nv.Elem().Set(v.Elem())
 | |
| 		deepCopyRec(nv.Elem(), v.Elem())
 | |
| 		return nv
 | |
| 	case reflect.Slice:
 | |
| 		nv := reflect.MakeSlice(v.Type(), v.Len(), v.Len())
 | |
| 		for i := 0; i < v.Len(); i++ {
 | |
| 			deepCopyRec(nv.Index(i), v.Index(i))
 | |
| 		}
 | |
| 		return nv
 | |
| 	}
 | |
| 	panic("deepCopy: must be called with pointer or slice")
 | |
| }
 | |
| 
 | |
| // deepCopyRec is only called by deepCopy.
 | |
| func deepCopyRec(nv, v reflect.Value) {
 | |
| 	if v.Kind() == reflect.Struct {
 | |
| 		t := v.Type()
 | |
| 		for i := 0; i < v.NumField(); i++ {
 | |
| 			if name, attr := xmlName(t.Field(i)); name != "" && !attr {
 | |
| 				deepCopyRec(nv.Field(i), v.Field(i))
 | |
| 			}
 | |
| 		}
 | |
| 	} else {
 | |
| 		nv.Set(deepCopy(v))
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // newNode is used to insert a missing node during inheritance.
 | |
| func (cldr *CLDR) newNode(v, enc reflect.Value) reflect.Value {
 | |
| 	n := reflect.New(v.Type())
 | |
| 	for i := iter(v); !i.done(); i.next() {
 | |
| 		if name, attr := xmlName(i.field()); name == "" || attr {
 | |
| 			n.Elem().FieldByIndex(i.index).Set(i.value())
 | |
| 		}
 | |
| 	}
 | |
| 	n.Interface().(Elem).GetCommon().setEnclosing(enc.Addr().Interface().(Elem))
 | |
| 	return n
 | |
| }
 | |
| 
 | |
| // v, parent must be pointers to struct
 | |
| func (cldr *CLDR) inheritFields(v, parent reflect.Value) (res reflect.Value, err error) {
 | |
| 	t := v.Type()
 | |
| 	nv := reflect.New(t)
 | |
| 	nv.Elem().Set(v)
 | |
| 	for i := iter(v); !i.done(); i.next() {
 | |
| 		vf := i.value()
 | |
| 		f := i.field()
 | |
| 		name, attr := xmlName(f)
 | |
| 		if name == "" || attr {
 | |
| 			continue
 | |
| 		}
 | |
| 		pf := parent.FieldByIndex(i.index)
 | |
| 		if blocking[name] {
 | |
| 			if vf.IsNil() {
 | |
| 				vf = pf
 | |
| 			}
 | |
| 			nv.Elem().FieldByIndex(i.index).Set(deepCopy(vf))
 | |
| 			continue
 | |
| 		}
 | |
| 		switch f.Type.Kind() {
 | |
| 		case reflect.Ptr:
 | |
| 			if f.Type.Elem().Kind() == reflect.Struct {
 | |
| 				if !vf.IsNil() {
 | |
| 					if vf, err = cldr.inheritStructPtr(vf, pf); err != nil {
 | |
| 						return reflect.Value{}, err
 | |
| 					}
 | |
| 					vf.Interface().(Elem).setEnclosing(nv.Interface().(Elem))
 | |
| 					nv.Elem().FieldByIndex(i.index).Set(vf)
 | |
| 				} else if !pf.IsNil() {
 | |
| 					n := cldr.newNode(pf.Elem(), v)
 | |
| 					if vf, err = cldr.inheritStructPtr(n, pf); err != nil {
 | |
| 						return reflect.Value{}, err
 | |
| 					}
 | |
| 					vf.Interface().(Elem).setEnclosing(nv.Interface().(Elem))
 | |
| 					nv.Elem().FieldByIndex(i.index).Set(vf)
 | |
| 				}
 | |
| 			}
 | |
| 		case reflect.Slice:
 | |
| 			vf, err := cldr.inheritSlice(nv.Elem(), vf, pf)
 | |
| 			if err != nil {
 | |
| 				return reflect.Zero(t), err
 | |
| 			}
 | |
| 			nv.Elem().FieldByIndex(i.index).Set(vf)
 | |
| 		}
 | |
| 	}
 | |
| 	return nv, nil
 | |
| }
 | |
| 
 | |
| func root(e Elem) *LDML {
 | |
| 	for ; e.enclosing() != nil; e = e.enclosing() {
 | |
| 	}
 | |
| 	return e.(*LDML)
 | |
| }
 | |
| 
 | |
| // inheritStructPtr first merges possible aliases in with v and then inherits
 | |
| // any underspecified elements from parent.
 | |
| func (cldr *CLDR) inheritStructPtr(v, parent reflect.Value) (r reflect.Value, err error) {
 | |
| 	if !v.IsNil() {
 | |
| 		e := v.Interface().(Elem).GetCommon()
 | |
| 		alias := e.Alias
 | |
| 		if alias == nil && !parent.IsNil() {
 | |
| 			alias = parent.Interface().(Elem).GetCommon().Alias
 | |
| 		}
 | |
| 		if alias != nil {
 | |
| 			a, err := cldr.resolveAlias(v.Interface().(Elem), alias.Source, alias.Path)
 | |
| 			if a != nil {
 | |
| 				if v, err = cldr.inheritFields(v.Elem(), reflect.ValueOf(a).Elem()); err != nil {
 | |
| 					return reflect.Value{}, err
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		if !parent.IsNil() {
 | |
| 			return cldr.inheritFields(v.Elem(), parent.Elem())
 | |
| 		}
 | |
| 	} else if parent.IsNil() {
 | |
| 		panic("should not reach here")
 | |
| 	}
 | |
| 	return v, nil
 | |
| }
 | |
| 
 | |
| // Must be slice of struct pointers.
 | |
| func (cldr *CLDR) inheritSlice(enc, v, parent reflect.Value) (res reflect.Value, err error) {
 | |
| 	t := v.Type()
 | |
| 	index := make(map[string]reflect.Value)
 | |
| 	if !v.IsNil() {
 | |
| 		for i := 0; i < v.Len(); i++ {
 | |
| 			vi := v.Index(i)
 | |
| 			key := attrKey(vi)
 | |
| 			index[key] = vi
 | |
| 		}
 | |
| 	}
 | |
| 	if !parent.IsNil() {
 | |
| 		for i := 0; i < parent.Len(); i++ {
 | |
| 			vi := parent.Index(i)
 | |
| 			key := attrKey(vi)
 | |
| 			if w, ok := index[key]; ok {
 | |
| 				index[key], err = cldr.inheritStructPtr(w, vi)
 | |
| 			} else {
 | |
| 				n := cldr.newNode(vi.Elem(), enc)
 | |
| 				index[key], err = cldr.inheritStructPtr(n, vi)
 | |
| 			}
 | |
| 			index[key].Interface().(Elem).setEnclosing(enc.Addr().Interface().(Elem))
 | |
| 			if err != nil {
 | |
| 				return v, err
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	keys := make([]string, 0, len(index))
 | |
| 	for k, _ := range index {
 | |
| 		keys = append(keys, k)
 | |
| 	}
 | |
| 	sort.Strings(keys)
 | |
| 	sl := reflect.MakeSlice(t, len(index), len(index))
 | |
| 	for i, k := range keys {
 | |
| 		sl.Index(i).Set(index[k])
 | |
| 	}
 | |
| 	return sl, nil
 | |
| }
 | |
| 
 | |
| func parentLocale(loc string) string {
 | |
| 	parts := strings.Split(loc, "_")
 | |
| 	if len(parts) == 1 {
 | |
| 		return "root"
 | |
| 	}
 | |
| 	parts = parts[:len(parts)-1]
 | |
| 	key := strings.Join(parts, "_")
 | |
| 	return key
 | |
| }
 | |
| 
 | |
| func (cldr *CLDR) resolve(loc string) (res *LDML, err error) {
 | |
| 	if r := cldr.resolved[loc]; r != nil {
 | |
| 		return r, nil
 | |
| 	}
 | |
| 	x := cldr.RawLDML(loc)
 | |
| 	if x == nil {
 | |
| 		return nil, fmt.Errorf("cldr: unknown locale %q", loc)
 | |
| 	}
 | |
| 	var v reflect.Value
 | |
| 	if loc == "root" {
 | |
| 		x = deepCopy(reflect.ValueOf(x)).Interface().(*LDML)
 | |
| 		linkEnclosing(nil, x)
 | |
| 		err = cldr.aliasResolver().visit(x)
 | |
| 	} else {
 | |
| 		key := parentLocale(loc)
 | |
| 		var parent *LDML
 | |
| 		for ; cldr.locale[key] == nil; key = parentLocale(key) {
 | |
| 		}
 | |
| 		if parent, err = cldr.resolve(key); err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		v, err = cldr.inheritFields(reflect.ValueOf(x).Elem(), reflect.ValueOf(parent).Elem())
 | |
| 		x = v.Interface().(*LDML)
 | |
| 		linkEnclosing(nil, x)
 | |
| 	}
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	cldr.resolved[loc] = x
 | |
| 	return x, err
 | |
| }
 | |
| 
 | |
| // finalize finalizes the initialization of the raw LDML structs.  It also
 | |
| // removed unwanted fields, as specified by filter, so that they will not
 | |
| // be unnecessarily evaluated.
 | |
| func (cldr *CLDR) finalize(filter []string) {
 | |
| 	for _, x := range cldr.locale {
 | |
| 		if filter != nil {
 | |
| 			v := reflect.ValueOf(x).Elem()
 | |
| 			t := v.Type()
 | |
| 			for i := 0; i < v.NumField(); i++ {
 | |
| 				f := t.Field(i)
 | |
| 				name, _ := xmlName(f)
 | |
| 				if name != "" && name != "identity" && !in(filter, name) {
 | |
| 					v.Field(i).Set(reflect.Zero(f.Type))
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		linkEnclosing(nil, x) // for resolving aliases and paths
 | |
| 		setNames(x, "ldml")
 | |
| 	}
 | |
| }
 |