parser.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. package language
  2. import (
  3. "sort"
  4. "strconv"
  5. "strings"
  6. )
  7. type language struct {
  8. name string
  9. quality float64
  10. }
  11. type languageSlice []language
  12. func (e languageSlice) SortByQuality() {
  13. sort.Sort(e)
  14. }
  15. func (e languageSlice) Len() int {
  16. return len(e)
  17. }
  18. func (e languageSlice) Swap(i, j int) {
  19. e[i], e[j] = e[j], e[i]
  20. }
  21. func (e languageSlice) Less(i, j int) bool {
  22. return e[i].quality > e[j].quality
  23. }
  24. // ParseAcceptLanguage returns RFC1766 language codes parsed and sorted from
  25. // languages.
  26. //
  27. // If supportedLanguages is not empty, the returned codes will be filtered
  28. // by its contents.
  29. func ParseAcceptLanguage(languages string, supportedLanguages []string) []string {
  30. preferredLanguages := strings.Split(languages, ",")
  31. preferredLanguagesLen := len(preferredLanguages)
  32. // Preallocate processed languages, as we know the maximum possible.
  33. langCap := preferredLanguagesLen
  34. if len(supportedLanguages) > 0 {
  35. langCap = len(supportedLanguages)
  36. }
  37. langs := make(languageSlice, 0, langCap)
  38. for i, rawPreferredLanguage := range preferredLanguages {
  39. // Format strings.
  40. preferredLanguage := strings.Replace(strings.ToLower(strings.TrimSpace(rawPreferredLanguage)), "_", "-", 0)
  41. if preferredLanguage == "" {
  42. continue
  43. }
  44. // Split out quality factor.
  45. parts := strings.SplitN(preferredLanguage, ";", 2)
  46. // If supported languages are given, return only the langs that fit.
  47. supported := len(supportedLanguages) == 0
  48. for _, supportedLanguage := range supportedLanguages {
  49. if supported = supportedLanguage == parts[0]; supported {
  50. break
  51. }
  52. }
  53. if !supported {
  54. continue
  55. }
  56. lang := language{parts[0], 0}
  57. if len(parts) == 2 {
  58. q := parts[1]
  59. if strings.HasPrefix(q, "q=") {
  60. q = strings.SplitN(q, "=", 2)[1]
  61. var err error
  62. if lang.quality, err = strconv.ParseFloat(q, 64); err != nil {
  63. // Default value (1) if quality is empty.
  64. lang.quality = 1
  65. }
  66. }
  67. }
  68. // Use order of items if no quality is given.
  69. if lang.quality == 0 {
  70. lang.quality = float64(preferredLanguagesLen - i)
  71. }
  72. langs = append(langs, lang)
  73. }
  74. langs.SortByQuality()
  75. // Filter quality string.
  76. langString := make([]string, 0, len(langs))
  77. for _, lang := range langs {
  78. langString = append(langString, lang.name)
  79. }
  80. return langString
  81. }