Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial implementation of go-translate #1

Merged
merged 14 commits into from Mar 22, 2019

Add language endpoint for get language list requests

  • Loading branch information
yrliou committed Mar 18, 2019
commit e1dde004307034e9ab52dbe0d4033adc31faf6ec
@@ -7,6 +7,7 @@ import (
"net/http"
"time"

"github.com/brave/go-translate/language"
"github.com/brave/go-translate/translate"
"github.com/go-chi/chi"
log "github.com/sirupsen/logrus"
@@ -16,11 +17,20 @@ import (
// brave-core, and it can be set to other hosts during testing.
var MSTranslateServer = "https://api.cognitive.microsofttranslator.com"


const (
languageEndpoint = "/languages?api-version=3.0&scope=translation"
)

// TranslateRouter add routers for translate requests and translate script
// requests.
func TranslateRouter() chi.Router {
r := chi.NewRouter()

r.Post("/translate", Translate)
r.Get("/language", GetLanguageList)


return r
}

@@ -30,6 +40,57 @@ func getHTTPClient() *http.Client {
}
}

// GetLanguageList send a request to Microsoft server and convert the response
// into google format and reply back to the client.
func GetLanguageList(w http.ResponseWriter, r *http.Request) {
// Send a get language list request to MS
req, err := http.NewRequest("GET", MSTranslateServer+languageEndpoint, nil)
This conversation was marked as resolved by yrliou

This comment has been minimized.

Copy link
@jumde

jumde Mar 21, 2019

Collaborator

We unset the X-Forwarded-* headers sent to Google servers at the proxy. We should unset the headers for connection to Microsoft servers as well. See: https://github.com/brave/devops/pull/785/files#diff-e262328707cf31665d8378e0949ef286R67

This comment has been minimized.

Copy link
@evq

evq Mar 21, 2019

Member

they aren't automatically set. since we're not explicitly setting them on the Request struct I think no change is needed?

This comment has been minimized.

Copy link
@yrliou

yrliou Mar 21, 2019

Author Member

@jumde This is a newly created request and won't have headers from google request, and I dump the request here to double check, we only have Host: api.cognitive.microsofttranslator.com header here.
Does this answer your concern here?

if err != nil {
http.Error(w, fmt.Sprintf("Error creating MS request: %v", err), http.StatusInternalServerError)
This conversation was marked as resolved by yrliou

This comment has been minimized.

Copy link
@jumde

jumde Mar 20, 2019

Collaborator

return here if there is an error

This comment has been minimized.

Copy link
@yrliou

yrliou Mar 20, 2019

Author Member

addressed in 81590b7

}

client := getHTTPClient()
msResp, err := client.Do(req)
if err != nil {
http.Error(w, fmt.Sprintf("Error sending request to MS server: %v", err), http.StatusInternalServerError)
return
}
defer func() {
err := msResp.Body.Close()
if err != nil {
log.Errorf("Error closing response body stream: %v", err)
}
}()

// Set response header
w.Header().Set("Content-Type", msResp.Header["Content-Type"][0])
w.WriteHeader(msResp.StatusCode)

// Copy resonse body if status is not OK
if msResp.StatusCode != http.StatusOK {
_, err = io.Copy(w, msResp.Body)
if err != nil {
http.Error(w, fmt.Sprintf("Error copying MS response body: %v", err), http.StatusInternalServerError)
}
return
}

// Convert to google format language list and write it back
msBody, err := ioutil.ReadAll(msResp.Body)
if err != nil {
http.Error(w, fmt.Sprintf("Error reading MS response body: %v", err), http.StatusInternalServerError)
}
body, err := language.ToGoogleLanguageList(msBody)
if err != nil {
http.Error(w, fmt.Sprintf("Error converting to google language list: %v", err), http.StatusInternalServerError)
return
}
_, err = w.Write(body)
if err != nil {
log.Errorf("Error writing response body for translate requests: %v", err)
}
}

// Translate converts a Google format translate request into a Microsoft format
// one which will be send to the Microsoft server, and write a Google format
// response back to the client.
@@ -0,0 +1,66 @@
package language

import (
"encoding/json"
)

// Language represents the format of language in Microsoft language list
// Note that nativeName and dir are not used in this package since Google
// doesn't have them.
type Language struct {
Name string `json:"name"`
}

// MicrosoftLanguageList represents the JSON format for Microsoft language list
// Example:
// {
// "translation": {
// "af": {
// "name": "Afrikaans",
// "nativeName": "Afrikaans",
// "dir": "ltr"
// },
// "en": {
// "name": "English",
// "nativeName": "English",
// "dir": "ltr"
// }
// }
// }
type MicrosoftLanguageList struct {
Translation map[string]Language
}

// GoogleLanguageList represents the JSON format for Google language list
// Example:
// {
// "sl":{"auto":"Detect language","af":"Afrikaans"},
// "tl":{"af": "Afrikaans", "sq": "Albanian"}
// "al":{}
// }
// Note that al is not used in this package since Microsoft don't have it.
type GoogleLanguageList struct {
Sl map[string]string `json:"sl"`
Tl map[string]string `json:"tl"`
}

// ToGoogleLanguageList unmarshal a MS language list and marshal a corresponding
// google language list and return it.
func ToGoogleLanguageList(body []byte) ([]byte, error) {
// Unmarshal the MS language list from the response
var msLangList MicrosoftLanguageList
err := json.Unmarshal(body, &msLangList)
if err != nil {
return nil, err
}

// Marshal the language list using google's format
var googleLangList GoogleLanguageList
googleLangList.Sl = make(map[string]string, len(msLangList.Translation))
googleLangList.Tl = make(map[string]string, len(msLangList.Translation))
for k, lang := range msLangList.Translation {
googleLangList.Sl[k] = lang.Name
googleLangList.Tl[k] = lang.Name
}
return json.Marshal(googleLangList)
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.