var.go 3.8 KB

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