123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- package internal
- import (
- "regexp"
- "sort"
- )
- // Var represents a message variable.
- // The variables, like the sub messages are sorted.
- // First: plurals (which again, are sorted)
- // and then any custom keys.
- // In variables, the sorting depends on the exact
- // order the associated message uses the variables.
- // This is extremely handy.
- // This package requires the golang.org/x/text/message capabilities
- // only for the variables feature, the message itself's pluralization is managed by the package.
- type Var struct {
- Name string // Variable name, e.g. Name
- Literal string // Its literal is ${Name}
- Cases []interface{} // one:...,few:...,...
- Format string // defaults to "%d".
- Argth int // 1, 2, 3...
- }
- func getVars(loc *Locale, key string, src map[string]interface{}) []Var {
- if len(src) == 0 {
- return nil
- }
- varsKey, ok := src[key]
- if !ok {
- return nil
- }
- varValue, ok := varsKey.([]interface{})
- if !ok {
- return nil
- }
- vars := make([]Var, 0, len(varValue))
- for _, v := range varValue {
- m, ok := v.(map[string]interface{})
- if !ok {
- continue
- }
- for k, inner := range m {
- varFormat := "%d"
- innerMap, ok := inner.(map[string]interface{})
- if !ok {
- continue
- }
- for kk, vv := range innerMap {
- if kk == "format" {
- if format, ok := vv.(string); ok {
- varFormat = format
- }
- break
- }
- }
- cases := getCases(loc, innerMap)
- if len(cases) > 0 {
- // cases = sortCases(cases)
- vars = append(vars, Var{
- Name: k,
- Literal: "${" + k + "}",
- Cases: cases,
- Format: varFormat,
- Argth: 1,
- })
- }
- }
- }
- delete(src, key) // delete the key after.
- return vars
- }
- var unescapeVariableRegex = regexp.MustCompile(`\$\{(.*?)}`)
- func sortVars(text string, vars []Var) (newVars []Var) {
- argth := 1
- for _, submatches := range unescapeVariableRegex.FindAllStringSubmatch(text, -1) {
- name := submatches[1]
- for _, variable := range vars {
- if variable.Name == name {
- variable.Argth = argth
- newVars = append(newVars, variable)
- argth++
- break
- }
- }
- }
- sort.SliceStable(newVars, func(i, j int) bool {
- return newVars[i].Argth < newVars[j].Argth
- })
- return
- }
- // it will panic if the incoming "elements" are not catmsg.Var (internal text package).
- func removeVarsDuplicates(elements []Var) (result []Var) {
- seen := make(map[string]struct{})
- for v := range elements {
- variable := elements[v]
- name := variable.Name
- if _, ok := seen[name]; !ok {
- seen[name] = struct{}{}
- result = append(result, variable)
- }
- }
- return result
- }
- /*
- func removeMsgVarsDuplicates(elements []catalog.Message) (result []catalog.Message) {
- seen := make(map[string]struct{})
- for _, elem := range elements {
- val := reflect.Indirect(reflect.ValueOf(elem))
- if val.Type().String() != "catmsg.Var" {
- // keep.
- result = append(result, elem)
- continue // it's not a var.
- }
- name := val.FieldByName("Name").Interface().(string)
- if _, ok := seen[name]; !ok {
- seen[name] = struct{}{}
- result = append(result, elem)
- }
- }
- return
- }
- */
- func getCases(loc *Locale, src map[string]interface{}) []interface{} {
- type PluralCase struct {
- Form PluralForm
- Value interface{}
- }
- pluralCases := make([]PluralCase, 0, len(src))
- for key, value := range src {
- form, ok := loc.Options.PluralFormDecoder(loc, key)
- if !ok {
- continue
- }
- pluralCases = append(pluralCases, PluralCase{
- Form: form,
- Value: value,
- })
- }
- if len(pluralCases) == 0 {
- return nil
- }
- sort.SliceStable(pluralCases, func(i, j int) bool {
- left, right := pluralCases[i].Form, pluralCases[j].Form
- return left.Less(right)
- })
- cases := make([]interface{}, 0, len(pluralCases)*2)
- for _, pluralCase := range pluralCases {
- // fmt.Printf("%s=%v\n", pluralCase.Form, pluralCase.Value)
- cases = append(cases, pluralCase.Form.String(), pluralCase.Value)
- }
- return cases
- }
|