You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

languages.go 3.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. // Copyright (c) 2018 Daniel Oaks <daniel@danieloaks.net>
  2. // released under the MIT license
  3. package languages
  4. import (
  5. "fmt"
  6. "sort"
  7. "strings"
  8. "sync"
  9. )
  10. // LangData is the data contained in a language file.
  11. type LangData struct {
  12. Name string
  13. Code string
  14. Contributors string
  15. Incomplete bool
  16. Translations map[string]string
  17. }
  18. // Manager manages our languages and provides translation abilities.
  19. type Manager struct {
  20. sync.RWMutex
  21. Info map[string]LangData
  22. translations map[string]map[string]string
  23. defaultLang string
  24. }
  25. // NewManager returns a new Manager.
  26. func NewManager(defaultLang string, languageData map[string]LangData) *Manager {
  27. lm := Manager{
  28. Info: make(map[string]LangData),
  29. translations: make(map[string]map[string]string),
  30. defaultLang: defaultLang,
  31. }
  32. // make fake "en" info
  33. lm.Info["en"] = LangData{
  34. Code: "en",
  35. Name: "English",
  36. Contributors: "Oragono contributors and the IRC community",
  37. }
  38. // load language data
  39. for name, data := range languageData {
  40. lm.Info[name] = data
  41. // make sure we don't include empty translations
  42. lm.translations[name] = make(map[string]string)
  43. for key, value := range data.Translations {
  44. if strings.TrimSpace(value) == "" {
  45. continue
  46. }
  47. lm.translations[name][key] = value
  48. }
  49. }
  50. return &lm
  51. }
  52. // Default returns the default languages.
  53. func (lm *Manager) Default() []string {
  54. lm.RLock()
  55. defer lm.RUnlock()
  56. if lm.defaultLang == "" {
  57. return []string{}
  58. }
  59. return []string{lm.defaultLang}
  60. }
  61. // Count returns how many languages we have.
  62. func (lm *Manager) Count() int {
  63. lm.RLock()
  64. defer lm.RUnlock()
  65. return len(lm.Info)
  66. }
  67. // Translators returns the languages we have and the translators.
  68. func (lm *Manager) Translators() []string {
  69. lm.RLock()
  70. defer lm.RUnlock()
  71. var tlist sort.StringSlice
  72. for _, info := range lm.Info {
  73. if info.Code == "en" {
  74. continue
  75. }
  76. tlist = append(tlist, fmt.Sprintf("%s (%s): %s", info.Name, info.Code, info.Contributors))
  77. }
  78. sort.Sort(tlist)
  79. return tlist
  80. }
  81. // Codes returns the proper language codes for the given casefolded language codes.
  82. func (lm *Manager) Codes(codes []string) []string {
  83. lm.RLock()
  84. defer lm.RUnlock()
  85. var newCodes []string
  86. for _, code := range codes {
  87. info, exists := lm.Info[code]
  88. if exists {
  89. newCodes = append(newCodes, info.Code)
  90. }
  91. }
  92. if len(newCodes) == 0 {
  93. newCodes = []string{"en"}
  94. }
  95. return newCodes
  96. }
  97. // Translate returns the given string, translated into the given language.
  98. func (lm *Manager) Translate(languages []string, originalString string) string {
  99. // not using any special languages
  100. if len(languages) == 0 || languages[0] == "en" || len(lm.translations) == 0 {
  101. return originalString
  102. }
  103. lm.RLock()
  104. defer lm.RUnlock()
  105. for _, lang := range languages {
  106. lang = strings.ToLower(lang)
  107. if lang == "en" {
  108. return originalString
  109. }
  110. translations, exists := lm.translations[lang]
  111. if !exists {
  112. continue
  113. }
  114. newString, exists := translations[originalString]
  115. if !exists {
  116. continue
  117. }
  118. // found a valid translation!
  119. return newString
  120. }
  121. // didn't find any translation
  122. return originalString
  123. }