match.go raw

   1  // Copyright 2015 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 internal
   6  
   7  // This file contains matchers that implement CLDR inheritance.
   8  //
   9  //     See https://unicode.org/reports/tr35/#Locale_Inheritance.
  10  //
  11  // Some of the inheritance described in this document is already handled by
  12  // the cldr package.
  13  
  14  import (
  15  	"golang.org/x/text/language"
  16  )
  17  
  18  // TODO: consider if (some of the) matching algorithm needs to be public after
  19  // getting some feel about what is generic and what is specific.
  20  
  21  // NewInheritanceMatcher returns a matcher that matches based on the inheritance
  22  // chain.
  23  //
  24  // The matcher uses canonicalization and the parent relationship to find a
  25  // match. The resulting match will always be either Und or a language with the
  26  // same language and script as the requested language. It will not match
  27  // languages for which there is understood to be mutual or one-directional
  28  // intelligibility.
  29  //
  30  // A Match will indicate an Exact match if the language matches after
  31  // canonicalization and High if the matched tag is a parent.
  32  func NewInheritanceMatcher(t []language.Tag) *InheritanceMatcher {
  33  	tags := &InheritanceMatcher{make(map[language.Tag]int)}
  34  	for i, tag := range t {
  35  		ct, err := language.All.Canonicalize(tag)
  36  		if err != nil {
  37  			ct = tag
  38  		}
  39  		tags.index[ct] = i
  40  	}
  41  	return tags
  42  }
  43  
  44  type InheritanceMatcher struct {
  45  	index map[language.Tag]int
  46  }
  47  
  48  func (m InheritanceMatcher) Match(want ...language.Tag) (language.Tag, int, language.Confidence) {
  49  	for _, t := range want {
  50  		ct, err := language.All.Canonicalize(t)
  51  		if err != nil {
  52  			ct = t
  53  		}
  54  		conf := language.Exact
  55  		for {
  56  			if index, ok := m.index[ct]; ok {
  57  				return ct, index, conf
  58  			}
  59  			if ct == language.Und {
  60  				break
  61  			}
  62  			ct = ct.Parent()
  63  			conf = language.High
  64  		}
  65  	}
  66  	return language.Und, 0, language.No
  67  }
  68