source: code/trunk/libretranslate.go@ 5

Last change on this file since 5 was 5, checked in by fattalion, 3 years ago

Add LibreTranslate engine

File size: 4.2 KB
RevLine 
[5]1package simplytranslate_engines
2
3import (
4 "bytes"
5 "encoding/json"
6 "fmt"
7 "net/http"
8)
9
10// LibreTranslateEngine is an engine that interfaces with any
11// [LibreTranslate](https://github.com/LibreTranslate/LibreTranslate) instance.
12type LibreTranslateEngine struct {
13 // InstanceURL is the URL to a LibreTranslate instance, for instance
14 // "https://libretranslate.com".
15 InstanceURL string
16 // APIKey is the API key for the given instance. If empty, then no API
17 // key will be sent along with requests to the instance.
18 //
19 // Some instances issue API keys to users so that they can have a
20 // higher rate limit. See
21 // https://github.com/LibreTranslate/LibreTranslate#manage-api-keys for
22 // more information.
23 APIKey string
24}
25
26func (_ *LibreTranslateEngine) InternalName() string { return "libre" }
27
28func (_ *LibreTranslateEngine) DisplayName() string { return "LibreTranslate" }
29
30type libreLanguagesResponse []struct {
31 Name string `json:"name"`
32 Code string `json:"code"`
33}
34
35func (e *LibreTranslateEngine) getLangs() ([]Language, error) {
36 response, err := http.Get(e.InstanceURL + "/languages")
37
38 if err != nil {
39 return nil, err
40 }
41
42 defer response.Body.Close()
43
44 if response.StatusCode != 200 {
45 return nil, fmt.Errorf("got status code %d from LibreTranslate API", response.StatusCode)
46 }
47
48 var langsResponse libreLanguagesResponse
49
50 if err := json.NewDecoder(response.Body).Decode(&langsResponse); err != nil {
51 return nil, err
52 }
53
54 langs := make([]Language, len(langsResponse))
55
56 for i, lang := range langsResponse {
57 langs[i] = Language{Name: lang.Name, Code: lang.Code}
58 }
59
60 return langs, nil
61
62}
63
64func (e *LibreTranslateEngine) SourceLanguages() ([]Language, error) { return e.getLangs() }
65
66func (e *LibreTranslateEngine) TargetLanguages() ([]Language, error) { return e.getLangs() }
67
68func (_ *LibreTranslateEngine) SupportsAutodetect() bool { return true }
69
70type libreDetectResponse []struct {
71 Confidence float64 `json:"confidence"`
72 LanguageCode string `json:"language"`
73}
74
75func (e *LibreTranslateEngine) DetectLanguage(text string) (Language, error) {
76 formData := map[string]string{"q": text}
77
78 if e.APIKey != "" {
79 formData["api_key"] = e.APIKey
80 }
81
82 formDataJSON, err := json.Marshal(formData)
83
84 if err != nil {
85 return Language{}, err
86 }
87
88 response, err := http.Post(e.InstanceURL+"/detect", "application/json", bytes.NewBuffer(formDataJSON))
89
90 if err != nil {
91 return Language{}, err
92 }
93
94 defer response.Body.Close()
95
96 if response.StatusCode != 200 {
97 return Language{}, fmt.Errorf("got status code %d from LibreTranslate API", response.StatusCode)
98 }
99
100 var langs libreDetectResponse
101
102 if err := json.NewDecoder(response.Body).Decode(&langs); err != nil {
103 return Language{}, err
104 }
105
106 maxConfidenceLang := langs[0]
107
108 for _, lang := range langs[1:] {
109 if lang.Confidence > maxConfidenceLang.Confidence {
110 maxConfidenceLang = lang
111 }
112 }
113
114 engineLangs, err := e.getLangs()
115
116 if err != nil {
117 return Language{}, err
118 }
119
120 for _, lang := range engineLangs {
121 if lang.Code == maxConfidenceLang.LanguageCode {
122 return lang, nil
123 }
124 }
125
126 return Language{}, fmt.Errorf("language code \"%s\" is not in the instance's language list", maxConfidenceLang.LanguageCode)
127}
128
129type libreTranslateResponse struct {
130 TranslatedText string `json:"translatedText"`
131}
132
133func (e *LibreTranslateEngine) Translate(text string, from Language, to Language) (TranslationResult, error) {
134 formData := map[string]string{
135 "q": text,
136 "source": from.Code,
137 "target": to.Code,
138 }
139
140 if e.APIKey != "" {
141 formData["api_key"] = e.APIKey
142 }
143
144 formDataJSON, err := json.Marshal(formData)
145
146 if err != nil {
147 return TranslationResult{}, err
148 }
149
150 response, err := http.Post(e.InstanceURL+"/translate", "application/json", bytes.NewBuffer(formDataJSON))
151
152 if err != nil {
153 return TranslationResult{}, err
154 }
155
156 defer response.Body.Close()
157
158 if response.StatusCode != 200 {
159 return TranslationResult{}, fmt.Errorf("got status code %d from LibreTranslate API", response.StatusCode)
160 }
161
162 var responseJSON libreTranslateResponse
163
164 if err := json.NewDecoder(response.Body).Decode(&responseJSON); err != nil {
165 return TranslationResult{}, err
166 }
167
168 return TranslationResult{SourceLanguage: from, TranslatedText: responseJSON.TranslatedText}, nil
169}
Note: See TracBrowser for help on using the repository browser.