/cmd/transifexdl/main.go

https://gitlab.com/steamdriven80/syncthing · Go · 144 lines · 114 code · 23 blank · 7 comment · 31 complexity · 65315bc017ea1e27ec9ee6a46fc628d9 MD5 · raw file

  1. // Copyright (C) 2014 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at http://mozilla.org/MPL/2.0/.
  6. // +build ignore
  7. package main
  8. import (
  9. "encoding/json"
  10. "fmt"
  11. "io/ioutil"
  12. "log"
  13. "net/http"
  14. "os"
  15. "regexp"
  16. "sort"
  17. "strings"
  18. )
  19. type stat struct {
  20. Translated int `json:"translated_entities"`
  21. Untranslated int `json:"untranslated_entities"`
  22. }
  23. type translation struct {
  24. Content string
  25. }
  26. func main() {
  27. log.SetFlags(log.Lshortfile)
  28. if u, p := userPass(); u == "" || p == "" {
  29. log.Fatal("Need environment variables TRANSIFEX_USER and TRANSIFEX_PASS")
  30. }
  31. curValidLangs := map[string]bool{}
  32. for _, lang := range loadValidLangs() {
  33. curValidLangs[lang] = true
  34. }
  35. log.Println(curValidLangs)
  36. resp := req("https://www.transifex.com/api/2/project/syncthing/resource/gui/stats")
  37. var stats map[string]stat
  38. err := json.NewDecoder(resp.Body).Decode(&stats)
  39. if err != nil {
  40. log.Fatal(err)
  41. }
  42. resp.Body.Close()
  43. var langs []string
  44. for code, stat := range stats {
  45. code = strings.Replace(code, "_", "-", 1)
  46. pct := 100 * stat.Translated / (stat.Translated + stat.Untranslated)
  47. if pct < 75 || !curValidLangs[code] && pct < 95 {
  48. log.Printf("Skipping language %q (too low completion ratio %d%%)", code, pct)
  49. os.Remove("lang-" + code + ".json")
  50. continue
  51. }
  52. langs = append(langs, code)
  53. if code == "en" {
  54. continue
  55. }
  56. log.Printf("Updating language %q", code)
  57. resp := req("https://www.transifex.com/api/2/project/syncthing/resource/gui/translation/" + code)
  58. var t translation
  59. err := json.NewDecoder(resp.Body).Decode(&t)
  60. if err != nil {
  61. log.Fatal(err)
  62. }
  63. resp.Body.Close()
  64. fd, err := os.Create("lang-" + code + ".json")
  65. if err != nil {
  66. log.Fatal(err)
  67. }
  68. fd.WriteString(t.Content)
  69. fd.Close()
  70. }
  71. saveValidLangs(langs)
  72. }
  73. func saveValidLangs(langs []string) {
  74. sort.Strings(langs)
  75. fd, err := os.Create("valid-langs.js")
  76. if err != nil {
  77. log.Fatal(err)
  78. }
  79. fmt.Fprint(fd, "var validLangs = ")
  80. json.NewEncoder(fd).Encode(langs)
  81. fd.Close()
  82. }
  83. func userPass() (string, string) {
  84. user := os.Getenv("TRANSIFEX_USER")
  85. pass := os.Getenv("TRANSIFEX_PASS")
  86. return user, pass
  87. }
  88. func req(url string) *http.Response {
  89. user, pass := userPass()
  90. req, err := http.NewRequest("GET", url, nil)
  91. if err != nil {
  92. log.Fatal(err)
  93. }
  94. req.SetBasicAuth(user, pass)
  95. resp, err := http.DefaultClient.Do(req)
  96. if err != nil {
  97. log.Fatal(err)
  98. }
  99. return resp
  100. }
  101. func loadValidLangs() []string {
  102. fd, err := os.Open("valid-langs.js")
  103. if err != nil {
  104. log.Fatal(err)
  105. }
  106. defer fd.Close()
  107. bs, err := ioutil.ReadAll(fd)
  108. if err != nil {
  109. log.Fatal(err)
  110. }
  111. var langs []string
  112. exp := regexp.MustCompile(`\[([a-zA-Z",-]+)\]`)
  113. if matches := exp.FindSubmatch(bs); len(matches) == 2 {
  114. langs = strings.Split(string(matches[1]), ",")
  115. for i := range langs {
  116. // Remove quotes
  117. langs[i] = langs[i][1 : len(langs[i])-1]
  118. }
  119. }
  120. return langs
  121. }