golang.org/x/text@v0.14.0/message/catalog/dict.go (about) 1 // Copyright 2017 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 catalog 6 7 import ( 8 "sync" 9 10 "golang.org/x/text/internal" 11 "golang.org/x/text/internal/catmsg" 12 "golang.org/x/text/language" 13 ) 14 15 // TODO: 16 // Dictionary returns a Dictionary that returns the first Message, using the 17 // given language tag, that matches: 18 // 1. the last one registered by one of the Set methods 19 // 2. returned by one of the Loaders 20 // 3. repeat from 1. using the parent language 21 // This approach allows messages to be underspecified. 22 // func (c *Catalog) Dictionary(tag language.Tag) (Dictionary, error) { 23 // // TODO: verify dictionary exists. 24 // return &dict{&c.index, tag}, nil 25 // } 26 27 type dict struct { 28 s *store 29 tag language.Tag // TODO: make compact tag. 30 } 31 32 func (d *dict) Lookup(key string) (data string, ok bool) { 33 return d.s.lookup(d.tag, key) 34 } 35 36 func (b *Builder) lookup(tag language.Tag, key string) (data string, ok bool) { 37 return b.index.lookup(tag, key) 38 } 39 40 func (c *Builder) set(tag language.Tag, key string, s *store, msg ...Message) error { 41 data, err := catmsg.Compile(tag, &dict{&c.macros, tag}, firstInSequence(msg)) 42 43 s.mutex.Lock() 44 defer s.mutex.Unlock() 45 46 m := s.index[tag] 47 if m == nil { 48 m = msgMap{} 49 if s.index == nil { 50 s.index = map[language.Tag]msgMap{} 51 } 52 c.matcher = nil 53 s.index[tag] = m 54 } 55 56 m[key] = data 57 return err 58 } 59 60 func (c *Builder) Matcher() language.Matcher { 61 c.index.mutex.RLock() 62 m := c.matcher 63 c.index.mutex.RUnlock() 64 if m != nil { 65 return m 66 } 67 68 c.index.mutex.Lock() 69 if c.matcher == nil { 70 c.matcher = language.NewMatcher(c.unlockedLanguages()) 71 } 72 m = c.matcher 73 c.index.mutex.Unlock() 74 return m 75 } 76 77 type store struct { 78 mutex sync.RWMutex 79 index map[language.Tag]msgMap 80 } 81 82 type msgMap map[string]string 83 84 func (s *store) lookup(tag language.Tag, key string) (data string, ok bool) { 85 s.mutex.RLock() 86 defer s.mutex.RUnlock() 87 88 for ; ; tag = tag.Parent() { 89 if msgs, ok := s.index[tag]; ok { 90 if msg, ok := msgs[key]; ok { 91 return msg, true 92 } 93 } 94 if tag == language.Und { 95 break 96 } 97 } 98 return "", false 99 } 100 101 // Languages returns all languages for which the Catalog contains variants. 102 func (b *Builder) Languages() []language.Tag { 103 s := &b.index 104 s.mutex.RLock() 105 defer s.mutex.RUnlock() 106 107 return b.unlockedLanguages() 108 } 109 110 func (b *Builder) unlockedLanguages() []language.Tag { 111 s := &b.index 112 if len(s.index) == 0 { 113 return nil 114 } 115 tags := make([]language.Tag, 0, len(s.index)) 116 _, hasFallback := s.index[b.options.fallback] 117 offset := 0 118 if hasFallback { 119 tags = append(tags, b.options.fallback) 120 offset = 1 121 } 122 for t := range s.index { 123 if t != b.options.fallback { 124 tags = append(tags, t) 125 } 126 } 127 internal.SortTags(tags[offset:]) 128 return tags 129 }