taldir

Directory service to resolve wallet mailboxes by messenger addresses
Log | Files | Refs | Submodules | README | LICENSE

var.go (4003B)


      1 package internal
      2 
      3 import (
      4 	"reflect"
      5 	"regexp"
      6 	"sort"
      7 
      8 	"golang.org/x/text/message/catalog"
      9 )
     10 
     11 // Var represents a message variable.
     12 // The variables, like the sub messages are sorted.
     13 // First: plurals (which again, are sorted)
     14 // and then any custom keys.
     15 // In variables, the sorting depends on the exact
     16 // order the associated message uses the variables.
     17 // This is extremely handy.
     18 // This package requires the golang.org/x/text/message capabilities
     19 // only for the variables feature, the message itself's pluralization is managed by the package.
     20 type Var struct {
     21 	Name    string        // Variable name, e.g. Name
     22 	Literal string        // Its literal is ${Name}
     23 	Cases   []interface{} // one:...,few:...,...
     24 	Format  string        // defaults to "%d".
     25 	Argth   int           // 1, 2, 3...
     26 }
     27 
     28 func getVars(loc *Locale, key string, src map[string]interface{}) []Var {
     29 	if len(src) == 0 {
     30 		return nil
     31 	}
     32 
     33 	varsKey, ok := src[key]
     34 	if !ok {
     35 		return nil
     36 	}
     37 
     38 	varValue, ok := varsKey.([]interface{})
     39 	if !ok {
     40 		return nil
     41 	}
     42 
     43 	vars := make([]Var, 0, len(varValue))
     44 
     45 	for _, v := range varValue {
     46 		m, ok := v.(map[string]interface{})
     47 		if !ok {
     48 			continue
     49 		}
     50 
     51 		for k, inner := range m {
     52 			varFormat := "%d"
     53 
     54 			innerMap, ok := inner.(map[string]interface{})
     55 			if !ok {
     56 				continue
     57 			}
     58 
     59 			for kk, vv := range innerMap {
     60 				if kk == "format" {
     61 					if format, ok := vv.(string); ok {
     62 						varFormat = format
     63 					}
     64 					break
     65 				}
     66 			}
     67 
     68 			cases := getCases(loc, innerMap)
     69 
     70 			if len(cases) > 0 {
     71 				// cases = sortCases(cases)
     72 				vars = append(vars, Var{
     73 					Name:    k,
     74 					Literal: "${" + k + "}",
     75 					Cases:   cases,
     76 					Format:  varFormat,
     77 					Argth:   1,
     78 				})
     79 			}
     80 		}
     81 	}
     82 
     83 	delete(src, key) // delete the key after.
     84 	return vars
     85 }
     86 
     87 var unescapeVariableRegex = regexp.MustCompile("\\$\\{(.*?)}")
     88 
     89 func sortVars(text string, vars []Var) (newVars []Var) {
     90 	argth := 1
     91 	for _, submatches := range unescapeVariableRegex.FindAllStringSubmatch(text, -1) {
     92 		name := submatches[1]
     93 		for _, variable := range vars {
     94 			if variable.Name == name {
     95 				variable.Argth = argth
     96 				newVars = append(newVars, variable)
     97 				argth++
     98 				break
     99 			}
    100 		}
    101 	}
    102 
    103 	sort.SliceStable(newVars, func(i, j int) bool {
    104 		return newVars[i].Argth < newVars[j].Argth
    105 	})
    106 	return
    107 }
    108 
    109 // it will panic if the incoming "elements" are not catmsg.Var (internal text package).
    110 func removeVarsDuplicates(elements []Var) (result []Var) {
    111 	seen := make(map[string]struct{})
    112 
    113 	for v := range elements {
    114 		variable := elements[v]
    115 		name := variable.Name
    116 		if _, ok := seen[name]; !ok {
    117 			seen[name] = struct{}{}
    118 			result = append(result, variable)
    119 		}
    120 	}
    121 
    122 	return result
    123 }
    124 
    125 func removeMsgVarsDuplicates(elements []catalog.Message) (result []catalog.Message) {
    126 	seen := make(map[string]struct{})
    127 
    128 	for _, elem := range elements {
    129 		val := reflect.Indirect(reflect.ValueOf(elem))
    130 		if val.Type().String() != "catmsg.Var" {
    131 			// keep.
    132 			result = append(result, elem)
    133 			continue // it's not a var.
    134 		}
    135 		name := val.FieldByName("Name").Interface().(string)
    136 		if _, ok := seen[name]; !ok {
    137 			seen[name] = struct{}{}
    138 			result = append(result, elem)
    139 		}
    140 	}
    141 
    142 	return
    143 }
    144 
    145 func getCases(loc *Locale, src map[string]interface{}) []interface{} {
    146 	type PluralCase struct {
    147 		Form  PluralForm
    148 		Value interface{}
    149 	}
    150 
    151 	pluralCases := make([]PluralCase, 0, len(src))
    152 
    153 	for key, value := range src {
    154 		form, ok := loc.Options.PluralFormDecoder(loc, key)
    155 		if !ok {
    156 			continue
    157 		}
    158 
    159 		pluralCases = append(pluralCases, PluralCase{
    160 			Form:  form,
    161 			Value: value,
    162 		})
    163 	}
    164 
    165 	if len(pluralCases) == 0 {
    166 		return nil
    167 	}
    168 
    169 	sort.SliceStable(pluralCases, func(i, j int) bool {
    170 		left, right := pluralCases[i].Form, pluralCases[j].Form
    171 		return left.Less(right)
    172 	})
    173 
    174 	cases := make([]interface{}, 0, len(pluralCases)*2)
    175 	for _, pluralCase := range pluralCases {
    176 		// fmt.Printf("%s=%v\n", pluralCase.Form, pluralCase.Value)
    177 		cases = append(cases, pluralCase.Form.String())
    178 		cases = append(cases, pluralCase.Value)
    179 	}
    180 
    181 	return cases
    182 }