~yerinalexey/gtranslate

ref: e1c610caf977a9ae78c050accc268d9ed2995297 gtranslate/translate.go -rw-r--r-- 1.9 KiB
e1c610caAlexey Yerin Move writeError to api.go 5 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
// Parser for Google Translate

package main

import (
	"fmt"
	"net/http"
	"net/url"

	"golang.org/x/net/html"
)

func doRequest(settings *TranslateSettings, reqUrl string) (*http.Response, error) {
	client := &http.Client{}

	if settings.proxy != nil {
		tr := &http.Transport{Proxy: http.ProxyURL(settings.proxy)}
		client.Transport = tr
	}

	req, err := http.NewRequest("GET", reqUrl, nil)
	if err != nil {
		return nil, err
	}

	req.Header["User-Agent"] = []string{settings.userAgent}

	resp, err := client.Do(req)

	return resp, err
}

// Requests and parses translation from Google
func Translate(settings *TranslateSettings, fromLang, toLang, text string) (string, error) {
	// Escape parameters before embedding in URL
	fromLang = url.QueryEscape(fromLang)
	toLang = url.QueryEscape(toLang)
	text = url.QueryEscape(text)

	reqUrl := fmt.Sprintf("https://translate.google.com/m?sl=%s&tl=%s&q=%s", fromLang, toLang, text)

	resp, err := doRequest(settings, reqUrl)
	if err != nil {
		return "", fmt.Errorf("Request failed: %v", err)
	}

	doc, err := html.Parse(resp.Body)
	if err != nil {
		return "", fmt.Errorf("HTML parsing failed: %v", err)
	}

	res, err := walk(doc)
	if err != nil {
		return "", fmt.Errorf("Error parsing translation page: %v", err)
	}

	return res, nil
}

func walk(node *html.Node) (string, error) {
	// Check if element has a class of result-container
	if node.Type == html.ElementNode && node.Data == "div" {
		for _, attr := range node.Attr {
			if attr.Key == "class" && attr.Val == "result-container" {
				// Retrieve the content of it
				if content := node.FirstChild; content != nil {
					return content.Data, nil
				} else {
					return "", fmt.Errorf("result-container is empty")
				}
			}
		}
	}

	// Recursively walk through subelements
	for c := node.FirstChild; c != nil; c = c.NextSibling {
		if res, err := walk(c); err == nil {
			return res, err
		}
	}

	return "", fmt.Errorf("no result")
}