mirror of
https://github.com/eeeXun/GTT.git
synced 2025-05-16 07:40:44 -07:00
feat(translator): add ReversoTranslate (#14)
This commit is contained in:
parent
9060a3999b
commit
ea1e23172c
18
README.md
18
README.md
@ -6,6 +6,7 @@ Support:
|
||||
[`ApertiumTranslate`](https://www.apertium.org/),
|
||||
[`ArgosTranslate`](https://translate.argosopentech.com/),
|
||||
[`GoogleTranslate`](https://translate.google.com/)
|
||||
[`ReversoTranslate`](https://www.reverso.net/text-translation)
|
||||
|
||||
## ScreenShot
|
||||
|
||||
@ -43,10 +44,12 @@ You can pass `-src` and `-dst` in argument to set source and destination languag
|
||||
gtt -src "English" -dst "Chinese (Traditional)"
|
||||
```
|
||||
|
||||
See language on
|
||||
[Apertium Translate](https://www.apertium.org/) for `ApertiumTranslate`,
|
||||
[argosopentech/argos-translate](https://github.com/argosopentech/argos-translate#supported-languages) for `ArgosTranslate`,
|
||||
[Google Language support](https://cloud.google.com/translate/docs/languages) for `GoogleTranslate`.
|
||||
See language on:
|
||||
|
||||
- [Apertium Translate](https://www.apertium.org/) for `ApertiumTranslate`
|
||||
- [argosopentech/argos-translate](https://github.com/argosopentech/argos-translate#supported-languages) for `ArgosTranslate`
|
||||
- [Google Language support](https://cloud.google.com/translate/docs/languages) for `GoogleTranslate`
|
||||
- [Reverso Translation](https://www.reverso.net/text-translation) for `ReversoTranslate`
|
||||
|
||||
## Key Map
|
||||
|
||||
@ -87,7 +90,7 @@ Stop play sound.
|
||||
Toggle transparent.
|
||||
|
||||
`<C-\>`
|
||||
Toggle Definition & Part of speech
|
||||
Toggle Definition/Example & Part of speech.
|
||||
|
||||
`<Tab>`, `<S-Tab>`
|
||||
Cycle through the pop out widget.
|
||||
@ -105,7 +108,10 @@ Switch pop out window.
|
||||
|
||||
## Credit
|
||||
|
||||
[soimort/translate-shell](https://github.com/soimort/translate-shell) For translation URL.
|
||||
[soimort/translate-shell](https://github.com/soimort/translate-shell),
|
||||
[SimplyTranslate-Engines](https://codeberg.org/SimpleWeb/SimplyTranslate-Engines),
|
||||
[s0ftik3/reverso-api](https://github.com/s0ftik3/reverso-api)
|
||||
For translation URL.
|
||||
|
||||
[snsd0805/GoogleTranslate-TUI](https://github.com/snsd0805/GoogleTranslate-TUI) For inspiration.
|
||||
|
||||
|
@ -24,6 +24,8 @@ func configInit() {
|
||||
"destination.language.argostranslate": "English",
|
||||
"source.language.googletranslate": "English",
|
||||
"destination.language.googletranslate": "English",
|
||||
"source.language.reversotranslate": "English",
|
||||
"destination.language.reversotranslate": "English",
|
||||
"translator": "ArgosTranslate",
|
||||
}
|
||||
)
|
||||
|
82
internal/translate/reversotranslate/language.go
Normal file
82
internal/translate/reversotranslate/language.go
Normal file
@ -0,0 +1,82 @@
|
||||
package reversotranslate
|
||||
|
||||
var (
|
||||
lang = []string{
|
||||
"Arabic",
|
||||
"Chinese (Simplified)",
|
||||
"Czech",
|
||||
"Danish",
|
||||
"Dutch",
|
||||
"English",
|
||||
"French",
|
||||
"German",
|
||||
"Greek",
|
||||
"Hebrew",
|
||||
"Hindi",
|
||||
"Hungarian",
|
||||
"Italian",
|
||||
"Japanese",
|
||||
"Korean",
|
||||
"Persian",
|
||||
"Polish",
|
||||
"Portuguese",
|
||||
"Romanian",
|
||||
"Russian",
|
||||
"Slovak",
|
||||
"Spanish",
|
||||
"Swedish",
|
||||
"Thai",
|
||||
"Turkish",
|
||||
"Ukrainian",
|
||||
}
|
||||
langCode = map[string]string{
|
||||
"Arabic": "ara",
|
||||
"Chinese (Simplified)": "chi",
|
||||
"Czech": "cze",
|
||||
"Danish": "dan",
|
||||
"Dutch": "dut",
|
||||
"English": "eng",
|
||||
"French": "fra",
|
||||
"German": "ger",
|
||||
"Greek": "gre",
|
||||
"Hebrew": "heb",
|
||||
"Hindi": "hin",
|
||||
"Hungarian": "hun",
|
||||
"Italian": "ita",
|
||||
"Japanese": "jpn",
|
||||
"Korean": "kor",
|
||||
"Persian": "per",
|
||||
"Polish": "pol",
|
||||
"Portuguese": "por",
|
||||
"Romanian": "rum",
|
||||
"Russian": "rus",
|
||||
"Slovak": "slo",
|
||||
"Spanish": "spa",
|
||||
"Swedish": "swe",
|
||||
"Thai": "tha",
|
||||
"Turkish": "tur",
|
||||
"Ukrainian": "ukr",
|
||||
}
|
||||
voiceName = map[string]string{
|
||||
"Arabic": "Mehdi22k",
|
||||
"Chinese (Simplified)": "Lulu22k",
|
||||
"Czech": "Eliska22k",
|
||||
"Danish": "Mette22k",
|
||||
"Dutch": "Sofie22k",
|
||||
"English": "Heather22k",
|
||||
"French": "Alice22k",
|
||||
"German": "Andreas22k",
|
||||
"Greek": "Dimitris22k",
|
||||
"Hebrew": "he-IL-Asaf",
|
||||
"Italian": "Fabiana22k",
|
||||
"Japanese": "Sakura22k",
|
||||
"Korean": "Minji22k",
|
||||
"Polish": "Monika22k",
|
||||
"Portuguese": "Celia22k",
|
||||
"Romanian": "ro-RO-Andrei",
|
||||
"Russian": "Alyona22k",
|
||||
"Spanish": "Antonio22k",
|
||||
"Swedish": "Emma22k",
|
||||
"Turkish": "Ipek22k",
|
||||
}
|
||||
)
|
116
internal/translate/reversotranslate/translator.go
Normal file
116
internal/translate/reversotranslate/translator.go
Normal file
@ -0,0 +1,116 @@
|
||||
package reversotranslate
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"regexp"
|
||||
|
||||
"github.com/eeeXun/gtt/internal/lock"
|
||||
)
|
||||
|
||||
const (
|
||||
textURL = "https://api.reverso.net/translate/v1/translation"
|
||||
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 {
|
||||
srcLang string
|
||||
dstLang string
|
||||
EngineName string
|
||||
SoundLock *lock.Lock
|
||||
}
|
||||
|
||||
func (t *ReversoTranslate) GetEngineName() string {
|
||||
return t.EngineName
|
||||
}
|
||||
|
||||
func (t *ReversoTranslate) GetAllLang() []string {
|
||||
return lang
|
||||
}
|
||||
|
||||
func (t *ReversoTranslate) GetSrcLang() string {
|
||||
return t.srcLang
|
||||
}
|
||||
|
||||
func (t *ReversoTranslate) GetDstLang() string {
|
||||
return t.dstLang
|
||||
}
|
||||
|
||||
func (t *ReversoTranslate) SetSrcLang(srcLang string) {
|
||||
t.srcLang = srcLang
|
||||
}
|
||||
|
||||
func (t *ReversoTranslate) SetDstLang(dstLang string) {
|
||||
t.dstLang = dstLang
|
||||
}
|
||||
|
||||
func (t *ReversoTranslate) SwapLang() {
|
||||
t.srcLang, t.dstLang = t.dstLang, t.srcLang
|
||||
}
|
||||
|
||||
func (t *ReversoTranslate) Translate(message string) (translation, definition, partOfSpeech string, err error) {
|
||||
var data map[string]interface{}
|
||||
|
||||
userData, _ := json.Marshal(map[string]interface{}{
|
||||
"format": "text",
|
||||
"from": langCode[t.srcLang],
|
||||
"to": langCode[t.dstLang],
|
||||
"input": message,
|
||||
"options": map[string]string{
|
||||
"sentenceSplitter": "true",
|
||||
"origin": "translation.web",
|
||||
"contextResults": "true",
|
||||
"languageDetection": "false",
|
||||
},
|
||||
})
|
||||
req, _ := http.NewRequest("POST",
|
||||
textURL,
|
||||
bytes.NewBuffer([]byte(userData)))
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
req.Header.Add("User-Agent", 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["translation"].([]interface{})[0])
|
||||
// definition and part of speech
|
||||
if data["contextResults"] != nil {
|
||||
for _, results := range data["contextResults"].(map[string]interface{})["results"].([]interface{}) {
|
||||
results := results.(map[string]interface{})
|
||||
// definition
|
||||
srcExample := results["sourceExamples"].([]interface{})
|
||||
dstExample := results["targetExamples"].([]interface{})
|
||||
if len(srcExample) > 0 && len(dstExample) > 0 {
|
||||
for i := 0; i < len(srcExample) && i < len(dstExample); i++ {
|
||||
definition += fmt.Sprintf("- %v\n\t\"%v\"\n", srcExample[i], dstExample[i])
|
||||
}
|
||||
}
|
||||
// part of speech
|
||||
if results["partOfSpeech"] == nil {
|
||||
partOfSpeech += fmt.Sprintf("%v\n", results["translation"])
|
||||
} else {
|
||||
partOfSpeech += fmt.Sprintf("%v [%v]\n", results["translation"], results["partOfSpeech"])
|
||||
}
|
||||
}
|
||||
definition = regexp.MustCompile("<(|/)em>").ReplaceAllString(definition, "")
|
||||
}
|
||||
|
||||
return translation, definition, partOfSpeech, nil
|
||||
}
|
75
internal/translate/reversotranslate/tts.go
Normal file
75
internal/translate/reversotranslate/tts.go
Normal file
@ -0,0 +1,75 @@
|
||||
package reversotranslate
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/hajimehoshi/go-mp3"
|
||||
"github.com/hajimehoshi/oto/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
ttsURL = "https://voice.reverso.net/RestPronunciation.svc/v1/output=json/GetVoiceStream/voiceName=%s?voiceSpeed=80&inputText=%s"
|
||||
)
|
||||
|
||||
func (t *ReversoTranslate) LockAvailable() bool {
|
||||
return t.SoundLock.Available()
|
||||
}
|
||||
|
||||
func (t *ReversoTranslate) LockAcquire() {
|
||||
t.SoundLock.Acquire()
|
||||
}
|
||||
|
||||
func (t *ReversoTranslate) StopTTS() {
|
||||
t.SoundLock.Stop = true
|
||||
}
|
||||
|
||||
func (t *ReversoTranslate) PlayTTS(lang, message string) error {
|
||||
name, ok := voiceName[lang]
|
||||
if !ok {
|
||||
return errors.New(t.EngineName + " does not support text to speech of " + lang)
|
||||
}
|
||||
urlStr := fmt.Sprintf(
|
||||
ttsURL,
|
||||
name,
|
||||
base64.StdEncoding.EncodeToString([]byte(message)),
|
||||
)
|
||||
req, _ := http.NewRequest("GET", urlStr, nil)
|
||||
req.Header.Add("User-Agent", userAgent)
|
||||
res, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
t.SoundLock.Release()
|
||||
return err
|
||||
}
|
||||
decoder, err := mp3.NewDecoder(res.Body)
|
||||
if err != nil {
|
||||
t.SoundLock.Release()
|
||||
return err
|
||||
}
|
||||
otoCtx, readyChan, err := oto.NewContext(decoder.SampleRate(), 2, 2)
|
||||
if err != nil {
|
||||
t.SoundLock.Release()
|
||||
return err
|
||||
}
|
||||
<-readyChan
|
||||
player := otoCtx.NewPlayer(decoder)
|
||||
player.Play()
|
||||
for player.IsPlaying() {
|
||||
if t.SoundLock.Stop {
|
||||
t.SoundLock.Release()
|
||||
return nil
|
||||
} else {
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
}
|
||||
if err = player.Close(); err != nil {
|
||||
t.SoundLock.Release()
|
||||
return err
|
||||
}
|
||||
|
||||
t.SoundLock.Release()
|
||||
return nil
|
||||
}
|
@ -5,10 +5,11 @@ import (
|
||||
"github.com/eeeXun/gtt/internal/translate/apertiumtranslate"
|
||||
"github.com/eeeXun/gtt/internal/translate/argostranslate"
|
||||
"github.com/eeeXun/gtt/internal/translate/googletranslate"
|
||||
"github.com/eeeXun/gtt/internal/translate/reversotranslate"
|
||||
)
|
||||
|
||||
var (
|
||||
AllTranslator = []string{"ApertiumTranslate", "ArgosTranslate", "GoogleTranslate"}
|
||||
AllTranslator = []string{"ApertiumTranslate", "ArgosTranslate", "GoogleTranslate", "ReversoTranslate"}
|
||||
)
|
||||
|
||||
type Translator interface {
|
||||
@ -48,6 +49,11 @@ func NewTranslator(name string) Translator {
|
||||
EngineName: "GoogleTranslate",
|
||||
SoundLock: lock.NewLock(),
|
||||
}
|
||||
case "ReversoTranslate":
|
||||
translator = &reversotranslate.ReversoTranslate{
|
||||
EngineName: "ReversoTranslate",
|
||||
SoundLock: lock.NewLock(),
|
||||
}
|
||||
}
|
||||
|
||||
return translator
|
||||
|
4
ui.go
4
ui.go
@ -38,7 +38,7 @@ const (
|
||||
[#%[1]s]<C-t>[-]
|
||||
Toggle transparent.
|
||||
[#%[1]s]<C-\>[-]
|
||||
Toggle Definition & Part of speech
|
||||
Toggle Definition/Example & Part of speech.
|
||||
[#%[1]s]<Tab>, <S-Tab>[-]
|
||||
Cycle through the pop out widget.
|
||||
[#%[1]s]<1>, <2>, <3>[-]
|
||||
@ -237,7 +237,7 @@ func uiInit() {
|
||||
// input/output
|
||||
srcInput.SetBorder(true)
|
||||
dstOutput.SetBorder(true)
|
||||
defOutput.SetBorder(true).SetTitle("Definition")
|
||||
defOutput.SetBorder(true).SetTitle("Definition/Example")
|
||||
posOutput.SetBorder(true).SetTitle("Part of speech")
|
||||
|
||||
// dropdown
|
||||
|
Loading…
x
Reference in New Issue
Block a user