source: code/trunk/engines/libretranslate.go@ 10

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

Make some identifiers more concise

See https://go.dev/doc/effective_go#package-names, specifically:

The importer of a package will use the name to refer to its contents,
so exported names in the package can use that fact to avoid
repetition.

For example, engines.GoogleTranslateEngine needlessly repeats
"engine," so just get rid of that duplication by renaming it to
engines.GoogleTranslate.

Renaming engines.TranslationEngine to engines.Engine may be
debatable, so if somebody disagrees, feel free to leave a comment
stating your disagreement and with an explanation of why you disagree.

File size: 4.1 KB
Line 
1package engines
2
3import (
4 "bytes"
5 "encoding/json"
6 "fmt"
7 "net/http"
8)
9
10// LibreTranslate is an engine that interfaces with any
11// [LibreTranslate](https://github.com/LibreTranslate/LibreTranslate) instance.
12type LibreTranslate 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 (_ *LibreTranslate) InternalName() string { return "libre" }
27
28func (_ *LibreTranslate) DisplayName() string { return "LibreTranslate" }
29
30type libreLanguagesResponse []struct {
31 Name string `json:"name"`
32 Code string `json:"code"`
33}
34
35func (e *LibreTranslate) 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 *LibreTranslate) SourceLanguages() ([]Language, error) { return e.getLangs() }
65
66func (e *LibreTranslate) TargetLanguages() ([]Language, error) { return e.getLangs() }
67
68func (_ *LibreTranslate) SupportsAutodetect() bool { return true }
69
70type libreDetectResponse []struct {
71 Confidence float64 `json:"confidence"`
72 LanguageCode string `json:"language"`
73}
74
75func (e *LibreTranslate) 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 *LibreTranslate) 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.