123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 |
- // Copyright 2017 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 catalog
- import (
- "sync"
- "golang.org/x/text/internal"
- "golang.org/x/text/internal/catmsg"
- "golang.org/x/text/language"
- )
- // TODO:
- // Dictionary returns a Dictionary that returns the first Message, using the
- // given language tag, that matches:
- // 1. the last one registered by one of the Set methods
- // 2. returned by one of the Loaders
- // 3. repeat from 1. using the parent language
- // This approach allows messages to be underspecified.
- // func (c *Catalog) Dictionary(tag language.Tag) (Dictionary, error) {
- // // TODO: verify dictionary exists.
- // return &dict{&c.index, tag}, nil
- // }
- type dict struct {
- s *store
- tag language.Tag // TODO: make compact tag.
- }
- func (d *dict) Lookup(key string) (data string, ok bool) {
- return d.s.lookup(d.tag, key)
- }
- func (b *Builder) lookup(tag language.Tag, key string) (data string, ok bool) {
- return b.index.lookup(tag, key)
- }
- func (c *Builder) set(tag language.Tag, key string, s *store, msg ...Message) error {
- data, err := catmsg.Compile(tag, &dict{&c.macros, tag}, firstInSequence(msg))
- s.mutex.Lock()
- defer s.mutex.Unlock()
- m := s.index[tag]
- if m == nil {
- m = msgMap{}
- if s.index == nil {
- s.index = map[language.Tag]msgMap{}
- }
- c.matcher = nil
- s.index[tag] = m
- }
- m[key] = data
- return err
- }
- func (c *Builder) Matcher() language.Matcher {
- c.index.mutex.RLock()
- m := c.matcher
- c.index.mutex.RUnlock()
- if m != nil {
- return m
- }
- c.index.mutex.Lock()
- if c.matcher == nil {
- c.matcher = language.NewMatcher(c.unlockedLanguages())
- }
- m = c.matcher
- c.index.mutex.Unlock()
- return m
- }
- type store struct {
- mutex sync.RWMutex
- index map[language.Tag]msgMap
- }
- type msgMap map[string]string
- func (s *store) lookup(tag language.Tag, key string) (data string, ok bool) {
- s.mutex.RLock()
- defer s.mutex.RUnlock()
- for ; ; tag = tag.Parent() {
- if msgs, ok := s.index[tag]; ok {
- if msg, ok := msgs[key]; ok {
- return msg, true
- }
- }
- if tag == language.Und {
- break
- }
- }
- return "", false
- }
- // Languages returns all languages for which the Catalog contains variants.
- func (b *Builder) Languages() []language.Tag {
- s := &b.index
- s.mutex.RLock()
- defer s.mutex.RUnlock()
- return b.unlockedLanguages()
- }
- func (b *Builder) unlockedLanguages() []language.Tag {
- s := &b.index
- if len(s.index) == 0 {
- return nil
- }
- tags := make([]language.Tag, 0, len(s.index))
- _, hasFallback := s.index[b.options.fallback]
- offset := 0
- if hasFallback {
- tags = append(tags, b.options.fallback)
- offset = 1
- }
- for t := range s.index {
- if t != b.options.fallback {
- tags = append(tags, t)
- }
- }
- internal.SortTags(tags[offset:])
- return tags
- }
|