mirror of
https://github.com/eeeXun/GTT.git
synced 2025-05-19 09:10:42 -07:00
feat(translator): add BingTranslate (#16)
This commit is contained in:
parent
7773bb3e8f
commit
e0c5569adf
@ -5,6 +5,7 @@ Google Translate TUI (Originally)
|
|||||||
Supported Translator:
|
Supported Translator:
|
||||||
[`ApertiumTranslate`](https://www.apertium.org/),
|
[`ApertiumTranslate`](https://www.apertium.org/),
|
||||||
[`ArgosTranslate`](https://translate.argosopentech.com/),
|
[`ArgosTranslate`](https://translate.argosopentech.com/),
|
||||||
|
[`BingTranslate`](https://www.bing.com/translator),
|
||||||
[`GoogleTranslate`](https://translate.google.com/),
|
[`GoogleTranslate`](https://translate.google.com/),
|
||||||
[`ReversoTranslate`](https://www.reverso.net/text-translation)
|
[`ReversoTranslate`](https://www.reverso.net/text-translation)
|
||||||
|
|
||||||
@ -48,6 +49,7 @@ See available languages on:
|
|||||||
|
|
||||||
- [Apertium Translate](https://www.apertium.org/) for `ApertiumTranslate`
|
- [Apertium Translate](https://www.apertium.org/) for `ApertiumTranslate`
|
||||||
- [argosopentech/argos-translate](https://github.com/argosopentech/argos-translate#supported-languages) for `ArgosTranslate`
|
- [argosopentech/argos-translate](https://github.com/argosopentech/argos-translate#supported-languages) for `ArgosTranslate`
|
||||||
|
- [Bing language-support](https://learn.microsoft.com/en-us/azure/cognitive-services/translator/language-support#translation) for `BingTranslate`
|
||||||
- [Google Language support](https://cloud.google.com/translate/docs/languages) for `GoogleTranslate`
|
- [Google Language support](https://cloud.google.com/translate/docs/languages) for `GoogleTranslate`
|
||||||
- [Reverso Translation](https://www.reverso.net/text-translation) for `ReversoTranslate`
|
- [Reverso Translation](https://www.reverso.net/text-translation) for `ReversoTranslate`
|
||||||
|
|
||||||
|
@ -22,6 +22,8 @@ func configInit() {
|
|||||||
"destination.language.apertiumtranslate": "English",
|
"destination.language.apertiumtranslate": "English",
|
||||||
"source.language.argostranslate": "English",
|
"source.language.argostranslate": "English",
|
||||||
"destination.language.argostranslate": "English",
|
"destination.language.argostranslate": "English",
|
||||||
|
"source.language.bingtranslate": "English",
|
||||||
|
"destination.language.bingtranslate": "English",
|
||||||
"source.language.googletranslate": "English",
|
"source.language.googletranslate": "English",
|
||||||
"destination.language.googletranslate": "English",
|
"destination.language.googletranslate": "English",
|
||||||
"source.language.reversotranslate": "English",
|
"source.language.reversotranslate": "English",
|
||||||
|
320
internal/translate/bingtranslate/lang.go
Normal file
320
internal/translate/bingtranslate/lang.go
Normal file
@ -0,0 +1,320 @@
|
|||||||
|
package bingtranslate
|
||||||
|
|
||||||
|
var (
|
||||||
|
lang = []string{
|
||||||
|
"Afrikaans",
|
||||||
|
"Albanian",
|
||||||
|
"Amharic",
|
||||||
|
"Auto",
|
||||||
|
"Arabic",
|
||||||
|
"Armenian",
|
||||||
|
"Assamese",
|
||||||
|
"Azerbaijani",
|
||||||
|
"Bangla",
|
||||||
|
"Bashkir",
|
||||||
|
"Basque",
|
||||||
|
"Bosnian",
|
||||||
|
"Bulgarian",
|
||||||
|
"Cantonese (Traditional)",
|
||||||
|
"Catalan",
|
||||||
|
"Chinese (Literary)",
|
||||||
|
"Chinese Simplified",
|
||||||
|
"Chinese Traditional",
|
||||||
|
"Croatian",
|
||||||
|
"Czech",
|
||||||
|
"Danish",
|
||||||
|
"Dari",
|
||||||
|
"Divehi",
|
||||||
|
"Dutch",
|
||||||
|
"English",
|
||||||
|
"Estonian",
|
||||||
|
"Faroese",
|
||||||
|
"Fijian",
|
||||||
|
"Filipino",
|
||||||
|
"Finnish",
|
||||||
|
"French",
|
||||||
|
"French (Canada)",
|
||||||
|
"Galician",
|
||||||
|
"Ganda",
|
||||||
|
"Georgian",
|
||||||
|
"German",
|
||||||
|
"Greek",
|
||||||
|
"Gujarati",
|
||||||
|
"Haitian Creole",
|
||||||
|
"Hausa",
|
||||||
|
"Hebrew",
|
||||||
|
"Hindi",
|
||||||
|
"Hmong Daw",
|
||||||
|
"Hungarian",
|
||||||
|
"Icelandic",
|
||||||
|
"Igbo",
|
||||||
|
"Indonesian",
|
||||||
|
"Inuinnaqtun",
|
||||||
|
"Inuktitut",
|
||||||
|
"Inuktitut (Latin)",
|
||||||
|
"Irish",
|
||||||
|
"Italian",
|
||||||
|
"Japanese",
|
||||||
|
"Kannada",
|
||||||
|
"Kazakh",
|
||||||
|
"Khmer",
|
||||||
|
"Kinyarwanda",
|
||||||
|
"Klingon (Latin)",
|
||||||
|
"Korean",
|
||||||
|
"Kurdish (Central)",
|
||||||
|
"Kurdish (Northern)",
|
||||||
|
"Kyrgyz",
|
||||||
|
"Lao",
|
||||||
|
"Latvian",
|
||||||
|
"Lingala",
|
||||||
|
"Lithuanian",
|
||||||
|
"Macedonian",
|
||||||
|
"Malagasy",
|
||||||
|
"Malay",
|
||||||
|
"Malayalam",
|
||||||
|
"Maltese",
|
||||||
|
"Marathi",
|
||||||
|
"Mongolian (Cyrillic)",
|
||||||
|
"Mongolian (Traditional)",
|
||||||
|
"Myanmar (Burmese)",
|
||||||
|
"Māori",
|
||||||
|
"Nepali",
|
||||||
|
"Norwegian",
|
||||||
|
"Nyanja",
|
||||||
|
"Odia",
|
||||||
|
"Pashto",
|
||||||
|
"Persian",
|
||||||
|
"Polish",
|
||||||
|
"Portuguese (Brazil)",
|
||||||
|
"Portuguese (Portugal)",
|
||||||
|
"Punjabi",
|
||||||
|
"Querétaro Otomi",
|
||||||
|
"Romanian",
|
||||||
|
"Rundi",
|
||||||
|
"Russian",
|
||||||
|
"Samoan",
|
||||||
|
"Serbian (Cyrillic)",
|
||||||
|
"Serbian (Latin)",
|
||||||
|
"Sesotho",
|
||||||
|
"Sesotho sa Leboa",
|
||||||
|
"Setswana",
|
||||||
|
"Shona",
|
||||||
|
"Slovak",
|
||||||
|
"Slovenian",
|
||||||
|
"Somali",
|
||||||
|
"Spanish",
|
||||||
|
"Swahili",
|
||||||
|
"Swedish",
|
||||||
|
"Tahitian",
|
||||||
|
"Tamil",
|
||||||
|
"Tatar",
|
||||||
|
"Telugu",
|
||||||
|
"Thai",
|
||||||
|
"Tibetan",
|
||||||
|
"Tigrinya",
|
||||||
|
"Tongan",
|
||||||
|
"Turkish",
|
||||||
|
"Turkmen",
|
||||||
|
"Ukrainian",
|
||||||
|
"Urdu",
|
||||||
|
"Uyghur",
|
||||||
|
"Uzbek (Latin)",
|
||||||
|
"Vietnamese",
|
||||||
|
"Welsh",
|
||||||
|
"Xhosa",
|
||||||
|
"Yoruba",
|
||||||
|
"Yucatec Maya",
|
||||||
|
"Zulu",
|
||||||
|
}
|
||||||
|
langCode = map[string]string{
|
||||||
|
"Afrikaans": "af",
|
||||||
|
"Albanian": "sq",
|
||||||
|
"Amharic": "am",
|
||||||
|
"Auto": "auto-detect",
|
||||||
|
"Arabic": "ar",
|
||||||
|
"Armenian": "hy",
|
||||||
|
"Assamese": "as",
|
||||||
|
"Azerbaijani": "az",
|
||||||
|
"Bangla": "bn",
|
||||||
|
"Bashkir": "ba",
|
||||||
|
"Basque": "eu",
|
||||||
|
"Bosnian": "bs",
|
||||||
|
"Bulgarian": "bg",
|
||||||
|
"Cantonese (Traditional)": "yue",
|
||||||
|
"Catalan": "ca",
|
||||||
|
"Chinese (Literary)": "lzh",
|
||||||
|
"Chinese Simplified": "zh-Hans",
|
||||||
|
"Chinese Traditional": "zh-Hant",
|
||||||
|
"Croatian": "hr",
|
||||||
|
"Czech": "cs",
|
||||||
|
"Danish": "da",
|
||||||
|
"Dari": "prs",
|
||||||
|
"Divehi": "dv",
|
||||||
|
"Dutch": "nl",
|
||||||
|
"English": "en",
|
||||||
|
"Estonian": "et",
|
||||||
|
"Faroese": "fo",
|
||||||
|
"Fijian": "fj",
|
||||||
|
"Filipino": "fil",
|
||||||
|
"Finnish": "fi",
|
||||||
|
"French": "fr",
|
||||||
|
"French (Canada)": "fr-CA",
|
||||||
|
"Galician": "gl",
|
||||||
|
"Ganda": "lug",
|
||||||
|
"Georgian": "ka",
|
||||||
|
"German": "de",
|
||||||
|
"Greek": "el",
|
||||||
|
"Gujarati": "gu",
|
||||||
|
"Haitian Creole": "ht",
|
||||||
|
"Hausa": "ha",
|
||||||
|
"Hebrew": "he",
|
||||||
|
"Hindi": "hi",
|
||||||
|
"Hmong Daw": "mww",
|
||||||
|
"Hungarian": "hu",
|
||||||
|
"Icelandic": "is",
|
||||||
|
"Igbo": "ig",
|
||||||
|
"Indonesian": "id",
|
||||||
|
"Inuinnaqtun": "ikt",
|
||||||
|
"Inuktitut": "iu",
|
||||||
|
"Inuktitut (Latin)": "iu-Latn",
|
||||||
|
"Irish": "ga",
|
||||||
|
"Italian": "it",
|
||||||
|
"Japanese": "ja",
|
||||||
|
"Kannada": "kn",
|
||||||
|
"Kazakh": "kk",
|
||||||
|
"Khmer": "km",
|
||||||
|
"Kinyarwanda": "rw",
|
||||||
|
"Klingon (Latin)": "tlh-Latn",
|
||||||
|
"Korean": "ko",
|
||||||
|
"Kurdish (Central)": "ku",
|
||||||
|
"Kurdish (Northern)": "kmr",
|
||||||
|
"Kyrgyz": "ky",
|
||||||
|
"Lao": "lo",
|
||||||
|
"Latvian": "lv",
|
||||||
|
"Lingala": "ln",
|
||||||
|
"Lithuanian": "lt",
|
||||||
|
"Macedonian": "mk",
|
||||||
|
"Malagasy": "mg",
|
||||||
|
"Malay": "ms",
|
||||||
|
"Malayalam": "ml",
|
||||||
|
"Maltese": "mt",
|
||||||
|
"Marathi": "mr",
|
||||||
|
"Mongolian (Cyrillic)": "mn-Cyrl",
|
||||||
|
"Mongolian (Traditional)": "mn-Mong",
|
||||||
|
"Myanmar (Burmese)": "my",
|
||||||
|
"Māori": "mi",
|
||||||
|
"Nepali": "ne",
|
||||||
|
"Norwegian": "nb",
|
||||||
|
"Nyanja": "nya",
|
||||||
|
"Odia": "or",
|
||||||
|
"Pashto": "ps",
|
||||||
|
"Persian": "fa",
|
||||||
|
"Polish": "pl",
|
||||||
|
"Portuguese (Brazil)": "pt",
|
||||||
|
"Portuguese (Portugal)": "pt-PT",
|
||||||
|
"Punjabi": "pa",
|
||||||
|
"Querétaro Otomi": "otq",
|
||||||
|
"Romanian": "ro",
|
||||||
|
"Rundi": "run",
|
||||||
|
"Russian": "ru",
|
||||||
|
"Samoan": "sm",
|
||||||
|
"Serbian (Cyrillic)": "sr-Cyrl",
|
||||||
|
"Serbian (Latin)": "sr-Latn",
|
||||||
|
"Sesotho": "st",
|
||||||
|
"Sesotho sa Leboa": "nso",
|
||||||
|
"Setswana": "tn",
|
||||||
|
"Shona": "sn",
|
||||||
|
"Slovak": "sk",
|
||||||
|
"Slovenian": "sl",
|
||||||
|
"Somali": "so",
|
||||||
|
"Spanish": "es",
|
||||||
|
"Swahili": "sw",
|
||||||
|
"Swedish": "sv",
|
||||||
|
"Tahitian": "ty",
|
||||||
|
"Tamil": "ta",
|
||||||
|
"Tatar": "tt",
|
||||||
|
"Telugu": "te",
|
||||||
|
"Thai": "th",
|
||||||
|
"Tibetan": "bo",
|
||||||
|
"Tigrinya": "ti",
|
||||||
|
"Tongan": "to",
|
||||||
|
"Turkish": "tr",
|
||||||
|
"Turkmen": "tk",
|
||||||
|
"Ukrainian": "uk",
|
||||||
|
"Urdu": "ur",
|
||||||
|
"Uyghur": "ug",
|
||||||
|
"Uzbek (Latin)": "uz",
|
||||||
|
"Vietnamese": "vi",
|
||||||
|
"Welsh": "cy",
|
||||||
|
"Xhosa": "xh",
|
||||||
|
"Yoruba": "yo",
|
||||||
|
"Yucatec Maya": "yua",
|
||||||
|
"Zulu": "zu",
|
||||||
|
}
|
||||||
|
voiceName = map[string]string{
|
||||||
|
"Afrikaans": "af-ZA-AdriNeural",
|
||||||
|
"Amharic": "am-ET-MekdesNeural",
|
||||||
|
"Arabic": "ar-SA-HamedNeural",
|
||||||
|
"Bangla": "bn-IN-TanishaaNeural",
|
||||||
|
"Bulgarian": "bg-BG-BorislavNeural",
|
||||||
|
"Cantonese (Traditional)": "zh-HK-HiuGaaiNeural",
|
||||||
|
"Catalan": "ca-ES-JoanaNeural",
|
||||||
|
"Chinese Simplified": "zh-CN-XiaoxiaoNeural",
|
||||||
|
"Chinese Traditional": "zh-CN-XiaoxiaoNeural",
|
||||||
|
"Croatian": "hr-HR-SreckoNeural",
|
||||||
|
"Czech": "cs-CZ-AntoninNeural",
|
||||||
|
"Danish": "da-DK-ChristelNeural",
|
||||||
|
"Dutch": "nl-NL-ColetteNeural",
|
||||||
|
"English": "en-US-AriaNeural",
|
||||||
|
"Estonian": "et-EE-AnuNeural",
|
||||||
|
"Finnish": "fi-FI-NooraNeural",
|
||||||
|
"French": "fr-FR-DeniseNeural",
|
||||||
|
"French (Canada)": "fr-CA-SylvieNeural",
|
||||||
|
"German": "de-DE-KatjaNeural",
|
||||||
|
"Greek": "el-GR-NestorasNeural",
|
||||||
|
"Gujarati": "gu-IN-DhwaniNeural",
|
||||||
|
"Hebrew": "he-IL-AvriNeural",
|
||||||
|
"Hindi": "hi-IN-SwaraNeural",
|
||||||
|
"Hungarian": "hu-HU-TamasNeural",
|
||||||
|
"Icelandic": "is-IS-GudrunNeural",
|
||||||
|
"Indonesian": "id-ID-ArdiNeural",
|
||||||
|
"Irish": "ga-IE-OrlaNeural",
|
||||||
|
"Italian": "it-IT-DiegoNeural",
|
||||||
|
"Japanese": "ja-JP-NanamiNeural",
|
||||||
|
"Kannada": "kn-IN-SapnaNeural",
|
||||||
|
"Kazakh": "kk-KZ-AigulNeural",
|
||||||
|
"Khmer": "km-KH-SreymomNeural",
|
||||||
|
"Korean": "ko-KR-SunHiNeural",
|
||||||
|
"Lao": "lo-LA-KeomanyNeural",
|
||||||
|
"Latvian": "lv-LV-EveritaNeural",
|
||||||
|
"Lithuanian": "lt-LT-OnaNeural",
|
||||||
|
"Macedonian": "mk-MK-MarijaNeural",
|
||||||
|
"Malay": "ms-MY-OsmanNeural",
|
||||||
|
"Malayalam": "ml-IN-SobhanaNeural",
|
||||||
|
"Maltese": "mt-MT-GraceNeural",
|
||||||
|
"Marathi": "mr-IN-AarohiNeural",
|
||||||
|
"Myanmar (Burmese)": "my-MM-NilarNeural",
|
||||||
|
"Norwegian": "nb-NO-PernilleNeural",
|
||||||
|
"Pashto": "ps-AF-LatifaNeural",
|
||||||
|
"Persian": "fa-IR-DilaraNeural",
|
||||||
|
"Polish": "pl-PL-ZofiaNeural",
|
||||||
|
"Portuguese (Brazil)": "pt-BR-FranciscaNeural",
|
||||||
|
"Portuguese (Portugal)": "pt-PT-FernandaNeural",
|
||||||
|
"Romanian": "ro-RO-EmilNeural",
|
||||||
|
"Russian": "ru-RU-DariyaNeural",
|
||||||
|
"Serbian (Cyrillic)": "sr-RS-SophieNeural",
|
||||||
|
"Slovak": "sk-SK-LukasNeural",
|
||||||
|
"Slovenian": "sl-SI-RokNeural",
|
||||||
|
"Spanish": "es-ES-ElviraNeural",
|
||||||
|
"Swedish": "sv-SE-SofieNeural",
|
||||||
|
"Tamil": "ta-IN-PallaviNeural",
|
||||||
|
"Telugu": "te-IN-ShrutiNeural",
|
||||||
|
"Thai": "th-TH-NiwatNeural",
|
||||||
|
"Turkish": "tr-TR-EmelNeural",
|
||||||
|
"Ukrainian": "uk-UA-PolinaNeural",
|
||||||
|
"Urdu": "ur-IN-GulNeural",
|
||||||
|
"Uzbek (Latin)": "uz-UZ-MadinaNeural",
|
||||||
|
"Vietnamese": "vi-VN-NamMinhNeural",
|
||||||
|
"Welsh": "cy-GB-NiaNeural",
|
||||||
|
}
|
||||||
|
)
|
214
internal/translate/bingtranslate/translator.go
Normal file
214
internal/translate/bingtranslate/translator.go
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
package bingtranslate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/eeeXun/gtt/internal/translate/core"
|
||||||
|
"github.com/hajimehoshi/go-mp3"
|
||||||
|
"github.com/hajimehoshi/oto/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
setUpURL = "https://www.bing.com/translator"
|
||||||
|
textURL = "https://www.bing.com/ttranslatev3?IG=%s&IID=%s"
|
||||||
|
posURL = "https://www.bing.com/tlookupv3?IG=%s&IID=%s"
|
||||||
|
ttsURL = "https://www.bing.com/tfettts?IG=%s&IID=%s"
|
||||||
|
ttsSSML = "<speak version='1.0' xml:lang='%[1]s'><voice xml:lang='%[1]s' xml:gender='Female' name='%s'><prosody rate='-20.00%%'>%s</prosody></voice></speak>"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BingTranslate struct {
|
||||||
|
*core.Language
|
||||||
|
*core.TTSLock
|
||||||
|
core.EngineName
|
||||||
|
}
|
||||||
|
|
||||||
|
type setUpData struct {
|
||||||
|
ig string
|
||||||
|
iid string
|
||||||
|
key string
|
||||||
|
token string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBingTranslate() *BingTranslate {
|
||||||
|
return &BingTranslate{
|
||||||
|
Language: core.NewLanguage(),
|
||||||
|
TTSLock: core.NewTTSLock(),
|
||||||
|
EngineName: core.NewEngineName("BingTranslate"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *BingTranslate) GetAllLang() []string {
|
||||||
|
return lang
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *BingTranslate) setUp() (*setUpData, error) {
|
||||||
|
var data setUpData
|
||||||
|
|
||||||
|
res, err := http.Get(setUpURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
body, err := ioutil.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
bodyStr := string(body)
|
||||||
|
igData := regexp.MustCompile(`IG:"([^"]+)"`).FindStringSubmatch(bodyStr)
|
||||||
|
if len(igData) < 2 {
|
||||||
|
return nil, errors.New(t.GetEngineName() + " IG not found")
|
||||||
|
}
|
||||||
|
data.ig = igData[1]
|
||||||
|
iidData := regexp.MustCompile(`data-iid="([^"]+)`).FindStringSubmatch(bodyStr)
|
||||||
|
if len(iidData) < 2 {
|
||||||
|
return nil, errors.New(t.GetEngineName() + " IID not found")
|
||||||
|
}
|
||||||
|
data.iid = iidData[1]
|
||||||
|
params := regexp.MustCompile(`params_AbusePreventionHelper = ([^;]+);`).FindStringSubmatch(bodyStr)
|
||||||
|
if len(params) < 2 {
|
||||||
|
return nil, errors.New(t.GetEngineName() + " Key and Token not found")
|
||||||
|
}
|
||||||
|
paramsStr := strings.Split(params[1][1:len(params[1])-1], ",")
|
||||||
|
data.key = paramsStr[0]
|
||||||
|
data.token = paramsStr[1][1 : len(paramsStr[1])-1]
|
||||||
|
|
||||||
|
return &data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *BingTranslate) Translate(message string) (translation, definition, partOfSpeech string, err error) {
|
||||||
|
var data []interface{}
|
||||||
|
|
||||||
|
initData, err := t.setUp()
|
||||||
|
if err != nil {
|
||||||
|
return "", "", "", err
|
||||||
|
}
|
||||||
|
userData := url.Values{
|
||||||
|
"fromLang": {langCode[t.GetSrcLang()]},
|
||||||
|
"to": {langCode[t.GetDstLang()]},
|
||||||
|
"text": {message},
|
||||||
|
"key": {initData.key},
|
||||||
|
"token": {initData.token},
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest("POST",
|
||||||
|
fmt.Sprintf(textURL, initData.ig, initData.iid),
|
||||||
|
strings.NewReader(userData.Encode()),
|
||||||
|
)
|
||||||
|
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
req.Header.Add("User-Agent", core.UserAgent)
|
||||||
|
res, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", "", err
|
||||||
|
}
|
||||||
|
body, err := ioutil.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", "", err
|
||||||
|
}
|
||||||
|
if err = json.Unmarshal(body, &data); err != nil {
|
||||||
|
return "", "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(data) <= 0 {
|
||||||
|
return "", "", "", errors.New("Translation not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
// translation
|
||||||
|
translation = fmt.Sprintf("%v",
|
||||||
|
data[0].(map[string]interface{})["translations"].([]interface{})[0].(map[string]interface{})["text"])
|
||||||
|
|
||||||
|
// request part of speech
|
||||||
|
userData.Del("fromLang")
|
||||||
|
userData.Add("from", langCode[t.GetSrcLang()])
|
||||||
|
req, err = http.NewRequest("POST",
|
||||||
|
fmt.Sprintf(posURL, initData.ig, initData.iid),
|
||||||
|
strings.NewReader(userData.Encode()),
|
||||||
|
)
|
||||||
|
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
req.Header.Add("User-Agent", core.UserAgent)
|
||||||
|
res, err = http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", "", err
|
||||||
|
}
|
||||||
|
body, err = ioutil.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", "", err
|
||||||
|
}
|
||||||
|
// Bing will return the request with list when success.
|
||||||
|
// Otherwises, it would return map. Then the following err would not be nil.
|
||||||
|
if err = json.Unmarshal(body, &data); err == nil {
|
||||||
|
poses := make(posSet)
|
||||||
|
for _, pos := range data[0].(map[string]interface{})["translations"].([]interface{}) {
|
||||||
|
pos := pos.(map[string]interface{})
|
||||||
|
var words posWords
|
||||||
|
|
||||||
|
words.target = pos["displayTarget"].(string)
|
||||||
|
for _, backTranslation := range pos["backTranslations"].([]interface{}) {
|
||||||
|
backTranslation := backTranslation.(map[string]interface{})
|
||||||
|
words.add(backTranslation["displayText"].(string))
|
||||||
|
}
|
||||||
|
poses.add(pos["posTag"].(string), words)
|
||||||
|
}
|
||||||
|
partOfSpeech = poses.format()
|
||||||
|
}
|
||||||
|
|
||||||
|
return translation, definition, partOfSpeech, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *BingTranslate) PlayTTS(lang, message string) error {
|
||||||
|
defer t.ReleaseLock()
|
||||||
|
|
||||||
|
name, ok := voiceName[lang]
|
||||||
|
if !ok {
|
||||||
|
return errors.New(t.GetEngineName() + " does not support text to speech of " + lang)
|
||||||
|
}
|
||||||
|
initData, err := t.setUp()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
userData := url.Values{
|
||||||
|
// lang='%s' in ssml should be xx-XX, e.g. en-US
|
||||||
|
// But xx also works, e.g. en
|
||||||
|
// So don't do extra work to get xx-XX
|
||||||
|
"ssml": {fmt.Sprintf(ttsSSML, langCode[lang], name, message)},
|
||||||
|
"key": {initData.key},
|
||||||
|
"token": {initData.token},
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest("POST",
|
||||||
|
fmt.Sprintf(ttsURL, initData.ig, initData.iid),
|
||||||
|
strings.NewReader(userData.Encode()),
|
||||||
|
)
|
||||||
|
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
req.Header.Add("User-Agent", core.UserAgent)
|
||||||
|
res, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
decoder, err := mp3.NewDecoder(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
otoCtx, readyChan, err := oto.NewContext(decoder.SampleRate(), 2, 2)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
<-readyChan
|
||||||
|
player := otoCtx.NewPlayer(decoder)
|
||||||
|
player.Play()
|
||||||
|
for player.IsPlaying() {
|
||||||
|
if t.IsStopped() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
time.Sleep(time.Millisecond)
|
||||||
|
}
|
||||||
|
if err = player.Close(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
40
internal/translate/bingtranslate/utils.go
Normal file
40
internal/translate/bingtranslate/utils.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package bingtranslate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type posWords struct {
|
||||||
|
target string
|
||||||
|
backTargets []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *posWords) add(s string) {
|
||||||
|
t.backTargets = append(t.backTargets, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
type posSet map[string][]posWords
|
||||||
|
|
||||||
|
func (set posSet) add(tag string, words posWords) {
|
||||||
|
set[tag] = append(set[tag], words)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (set posSet) format() (s string) {
|
||||||
|
for tag := range set {
|
||||||
|
s += fmt.Sprintf("[%s]\n", tag)
|
||||||
|
for _, words := range set[tag] {
|
||||||
|
s += fmt.Sprintf("\t%s:", words.target)
|
||||||
|
firstWord := true
|
||||||
|
for _, backTarget := range words.backTargets {
|
||||||
|
if firstWord {
|
||||||
|
s += fmt.Sprintf(" %s", backTarget)
|
||||||
|
firstWord = false
|
||||||
|
} else {
|
||||||
|
s += fmt.Sprintf(", %s", backTarget)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s += "\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
5
internal/translate/core/utils.go
Normal file
5
internal/translate/core/utils.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
const (
|
||||||
|
UserAgent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36"
|
||||||
|
)
|
@ -19,7 +19,6 @@ import (
|
|||||||
const (
|
const (
|
||||||
textURL = "https://api.reverso.net/translate/v1/translation"
|
textURL = "https://api.reverso.net/translate/v1/translation"
|
||||||
ttsURL = "https://voice.reverso.net/RestPronunciation.svc/v1/output=json/GetVoiceStream/voiceName=%s?voiceSpeed=80&inputText=%s"
|
ttsURL = "https://voice.reverso.net/RestPronunciation.svc/v1/output=json/GetVoiceStream/voiceName=%s?voiceSpeed=80&inputText=%s"
|
||||||
userAgent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ReversoTranslate struct {
|
type ReversoTranslate struct {
|
||||||
@ -65,7 +64,7 @@ func (t *ReversoTranslate) Translate(message string) (translation, definition, p
|
|||||||
textURL,
|
textURL,
|
||||||
bytes.NewBuffer([]byte(userData)))
|
bytes.NewBuffer([]byte(userData)))
|
||||||
req.Header.Add("Content-Type", "application/json")
|
req.Header.Add("Content-Type", "application/json")
|
||||||
req.Header.Add("User-Agent", userAgent)
|
req.Header.Add("User-Agent", core.UserAgent)
|
||||||
res, err := http.DefaultClient.Do(req)
|
res, err := http.DefaultClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", "", err
|
return "", "", "", err
|
||||||
@ -124,7 +123,7 @@ func (t *ReversoTranslate) PlayTTS(lang, message string) error {
|
|||||||
base64.StdEncoding.EncodeToString([]byte(message)),
|
base64.StdEncoding.EncodeToString([]byte(message)),
|
||||||
)
|
)
|
||||||
req, _ := http.NewRequest("GET", urlStr, nil)
|
req, _ := http.NewRequest("GET", urlStr, nil)
|
||||||
req.Header.Add("User-Agent", userAgent)
|
req.Header.Add("User-Agent", core.UserAgent)
|
||||||
res, err := http.DefaultClient.Do(req)
|
res, err := http.DefaultClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -3,12 +3,19 @@ package translate
|
|||||||
import (
|
import (
|
||||||
"github.com/eeeXun/gtt/internal/translate/apertiumtranslate"
|
"github.com/eeeXun/gtt/internal/translate/apertiumtranslate"
|
||||||
"github.com/eeeXun/gtt/internal/translate/argostranslate"
|
"github.com/eeeXun/gtt/internal/translate/argostranslate"
|
||||||
|
"github.com/eeeXun/gtt/internal/translate/bingtranslate"
|
||||||
"github.com/eeeXun/gtt/internal/translate/googletranslate"
|
"github.com/eeeXun/gtt/internal/translate/googletranslate"
|
||||||
"github.com/eeeXun/gtt/internal/translate/reversotranslate"
|
"github.com/eeeXun/gtt/internal/translate/reversotranslate"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
AllTranslator = []string{"ApertiumTranslate", "ArgosTranslate", "GoogleTranslate", "ReversoTranslate"}
|
AllTranslator = []string{
|
||||||
|
"ApertiumTranslate",
|
||||||
|
"BingTranslate",
|
||||||
|
"ArgosTranslate",
|
||||||
|
"GoogleTranslate",
|
||||||
|
"ReversoTranslate",
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
type Translator interface {
|
type Translator interface {
|
||||||
@ -57,6 +64,8 @@ func NewTranslator(name string) Translator {
|
|||||||
translator = apertiumtranslate.NewApertiumTranslate()
|
translator = apertiumtranslate.NewApertiumTranslate()
|
||||||
case "ArgosTranslate":
|
case "ArgosTranslate":
|
||||||
translator = argostranslate.NewArgosTranslate()
|
translator = argostranslate.NewArgosTranslate()
|
||||||
|
case "BingTranslate":
|
||||||
|
translator = bingtranslate.NewBingTranslate()
|
||||||
case "GoogleTranslate":
|
case "GoogleTranslate":
|
||||||
translator = googletranslate.NewGoogleTranslate()
|
translator = googletranslate.NewGoogleTranslate()
|
||||||
case "ReversoTranslate":
|
case "ReversoTranslate":
|
||||||
|
Loading…
x
Reference in New Issue
Block a user