locale.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. package internal
  2. import (
  3. "fmt"
  4. "text/template"
  5. "github.com/kataras/iris/v12/context"
  6. "golang.org/x/text/language"
  7. "golang.org/x/text/message"
  8. "golang.org/x/text/message/catalog"
  9. )
  10. // Locale is the default Locale.
  11. // Created by Catalog.
  12. // One Locale maps to one registered and loaded language.
  13. // Stores the translation variables and most importantly, the Messages (keys and their renderers).
  14. type Locale struct {
  15. // The index of the language registered by the user, starting from zero.
  16. index int
  17. tag language.Tag
  18. // ID is the tag.String().
  19. ID string
  20. // Options given by the Catalog
  21. Options Options
  22. // Fields set by Catalog.
  23. FuncMap template.FuncMap
  24. Printer *message.Printer
  25. //
  26. // Fields set by this Load method.
  27. Messages map[string]Renderer
  28. Vars []Var // shared per-locale variables.
  29. }
  30. // Ensures that the Locale completes the context.Locale interface.
  31. var _ context.Locale = (*Locale)(nil)
  32. // Load sets the translation messages based on the Catalog's key values.
  33. func (loc *Locale) Load(c *Catalog, keyValues Map) error {
  34. return loc.setMap(c, "", keyValues)
  35. }
  36. func (loc *Locale) setMap(c *Catalog, key string, keyValues Map) error {
  37. // unique locals or the shared ones.
  38. isRoot := key == ""
  39. vars := getVars(loc, VarsKey, keyValues)
  40. if isRoot {
  41. loc.Vars = vars
  42. } else {
  43. vars = removeVarsDuplicates(append(vars, loc.Vars...))
  44. }
  45. for k, v := range keyValues {
  46. form, isPlural := loc.Options.PluralFormDecoder(loc, k)
  47. if isPlural {
  48. k = key
  49. } else if !isRoot {
  50. k = key + "." + k
  51. }
  52. switch value := v.(type) {
  53. case string:
  54. if err := loc.setString(c, k, value, vars, form); err != nil {
  55. return fmt.Errorf("%s:%s parse string: %w", loc.ID, key, err)
  56. }
  57. case Map:
  58. // fmt.Printf("%s is map\n", fullKey)
  59. if err := loc.setMap(c, k, value); err != nil {
  60. return fmt.Errorf("%s:%s parse map: %w", loc.ID, key, err)
  61. }
  62. default:
  63. return fmt.Errorf("%s:%s unexpected type of %T as value", loc.ID, key, value)
  64. }
  65. }
  66. return nil
  67. }
  68. func (loc *Locale) setString(c *Catalog, key string, value string, vars []Var, form PluralForm) (err error) {
  69. isPlural := form != nil
  70. // fmt.Printf("setStringVars: %s=%s\n", key, value)
  71. msgs, vars := makeSelectfVars(value, vars, isPlural)
  72. msgs = append(msgs, catalog.String(value))
  73. m := &Message{
  74. Locale: loc,
  75. Key: key,
  76. Value: value,
  77. Vars: vars,
  78. Plural: isPlural,
  79. }
  80. var (
  81. renderer, pluralRenderer Renderer = m, m
  82. )
  83. if stringIsTemplateValue(value, loc.Options.Left, loc.Options.Right) {
  84. t, err := NewTemplate(c, m)
  85. if err != nil {
  86. return err
  87. }
  88. pluralRenderer = t
  89. if !isPlural {
  90. renderer = t
  91. }
  92. } else {
  93. if isPlural {
  94. pluralRenderer, err = newIndependentPluralRenderer(c, loc, key, msgs...)
  95. if err != nil {
  96. return fmt.Errorf("<%s = %s>: %w", key, value, err)
  97. }
  98. } else if err = c.Set(loc.tag, key, msgs...); err != nil {
  99. // let's make normal keys direct fire:
  100. // renderer = &simpleRenderer{key, loc.Printer}
  101. return fmt.Errorf("<%s = %s>: %w", key, value, err)
  102. }
  103. }
  104. if isPlural {
  105. if existingMsg, ok := loc.Messages[key]; ok {
  106. if msg, ok := existingMsg.(*Message); ok {
  107. msg.AddPlural(form, pluralRenderer)
  108. return
  109. }
  110. }
  111. m.AddPlural(form, pluralRenderer)
  112. }
  113. loc.Messages[key] = renderer
  114. return
  115. }
  116. /* context.Locale interface */
  117. // Index returns the current locale index from the languages list.
  118. func (loc *Locale) Index() int {
  119. return loc.index
  120. }
  121. // Tag returns the full language Tag attached to this Locale,
  122. // it should be unique across different Locales.
  123. func (loc *Locale) Tag() *language.Tag {
  124. return &loc.tag
  125. }
  126. // Language should return the exact languagecode of this `Locale`
  127. // that the user provided on `New` function.
  128. //
  129. // Same as `Tag().String()` but it's static.
  130. func (loc *Locale) Language() string {
  131. return loc.ID
  132. }
  133. // GetMessage should return translated text based on the given "key".
  134. func (loc *Locale) GetMessage(key string, args ...interface{}) string {
  135. if msg, ok := loc.Messages[key]; ok {
  136. result, err := msg.Render(args...)
  137. if err != nil {
  138. result = err.Error()
  139. }
  140. return result
  141. }
  142. return ""
  143. }