1 // Copyright 2013 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.
20 // A Decoder loads an archive of CLDR data.
23 sectionFilter []string
29 // SetSectionFilter takes a list top-level LDML element names to which
30 // evaluation of LDML should be limited. It automatically calls SetDirFilter.
31 func (d *Decoder) SetSectionFilter(filter ...string) {
32 d.sectionFilter = filter
33 // TODO: automatically set dir filter
36 // SetDirFilter limits the loading of LDML XML files of the specied directories.
37 // Note that sections may be split across directories differently for different CLDR versions.
38 // For more robust code, use SetSectionFilter.
39 func (d *Decoder) SetDirFilter(dir ...string) {
43 // A Loader provides access to the files of a CLDR archive.
44 type Loader interface {
47 Reader(i int) (io.ReadCloser, error)
50 var fileRe = regexp.MustCompile(`.*[/\\](.*)[/\\](.*)\.xml`)
52 // Decode loads and decodes the files represented by l.
53 func (d *Decoder) Decode(l Loader) (cldr *CLDR, err error) {
55 for i := 0; i < l.Len(); i++ {
57 if m := fileRe.FindStringSubmatch(fname); m != nil {
58 if len(d.dirFilter) > 0 && !in(d.dirFilter, m[1]) {
62 if r, err = l.Reader(i); err == nil {
63 err = d.decode(m[1], m[2], r)
71 d.cldr.finalize(d.sectionFilter)
75 func (d *Decoder) decode(dir, id string, r io.Reader) error {
80 case dir == "supplemental":
82 case dir == "transforms":
86 case dir == "validity":
90 if v, ok = cldr.locale[id]; !ok {
92 v, cldr.locale[id] = l, l
95 x := xml.NewDecoder(r)
96 if err := x.Decode(v); err != nil {
97 log.Printf("%s/%s: %v", dir, id, err)
101 if l.Identity == nil {
102 return fmt.Errorf("%s/%s: missing identity element", dir, id)
104 // TODO: verify when CLDR bug https://unicode.org/cldr/trac/ticket/8970
106 // path := strings.Split(id, "_")
107 // if lang := l.Identity.Language.Type; lang != path[0] {
108 // return fmt.Errorf("%s/%s: language was %s; want %s", dir, id, lang, path[0])
114 type pathLoader []string
116 func makePathLoader(path string) (pl pathLoader, err error) {
117 err = filepath.Walk(path, func(path string, _ os.FileInfo, err error) error {
118 pl = append(pl, path)
124 func (pl pathLoader) Len() int {
128 func (pl pathLoader) Path(i int) string {
132 func (pl pathLoader) Reader(i int) (io.ReadCloser, error) {
133 return os.Open(pl[i])
136 // DecodePath loads CLDR data from the given path.
137 func (d *Decoder) DecodePath(path string) (cldr *CLDR, err error) {
138 loader, err := makePathLoader(path)
142 return d.Decode(loader)
145 type zipLoader struct {
149 func (zl zipLoader) Len() int {
150 return len(zl.r.File)
153 func (zl zipLoader) Path(i int) string {
154 return zl.r.File[i].Name
157 func (zl zipLoader) Reader(i int) (io.ReadCloser, error) {
158 return zl.r.File[i].Open()
161 // DecodeZip loads CLDR data from the zip archive for which r is the source.
162 func (d *Decoder) DecodeZip(r io.Reader) (cldr *CLDR, err error) {
163 buffer, err := ioutil.ReadAll(r)
167 archive, err := zip.NewReader(bytes.NewReader(buffer), int64(len(buffer)))
171 return d.Decode(zipLoader{archive})