diff --git a/README.md b/README.md index e9aa294..4d1f298 100644 --- a/README.md +++ b/README.md @@ -7,17 +7,23 @@ Supported Translator: [`Argos`](https://translate.argosopentech.com/), [`Bing`](https://www.bing.com/translator), [`ChatGPT`](https://chat.openai.com/), +[`DeepL`](https://deepl.com/translator) (only free API), [`Google`](https://translate.google.com/)(default), [`Reverso`](https://www.reverso.net/text-translation) -## ⚠️ Note for ChatGPT +## ⚠️ Note for ChatGPT and DeepL -You need to apply an API key on [OpenAI API keys](https://platform.openai.com/account/api-keys). -And write it to `$XDG_CONFIG_HOME/gtt/gtt.yaml` or `$HOME/.config/gtt/gtt.yaml`. +ChatGPT and DeepL translations require API keys, which can be obtained from +[OpenAI API keys](https://platform.openai.com/account/api-keys) and +[DeepL API signup](https://www.deepl.com/pro-api) pages, respectively. Note +that only the free API is supported for DeepL currently. Once you have your +API key add it to `$XDG_CONFIG_HOME/gtt/gtt.yaml` or +`$HOME/.config/gtt/gtt.yaml`: ```yaml api_key: - chatgpt: YOUR_API_KEY # <- Replace with your API Key + chatgpt: CHATGPT_API_KEY # <- Replace with your API Key + deepl: DEEPL_API_KEY # <- Replace with your API Key ``` ## ScreenShot @@ -100,6 +106,7 @@ See available languages on: - [argosopentech/argos-translate](https://github.com/argosopentech/argos-translate#supported-languages) for `Argos` - [Bing language-support](https://learn.microsoft.com/en-us/azure/cognitive-services/translator/language-support#translation) for `Bing` - `ChatGPT` is same as `Google`. See [Google Language support](https://cloud.google.com/translate/docs/languages) +- [DeepL API docs](https://www.deepl.com/docs-api/translate-text/) for `DeepL` - [Google Language support](https://cloud.google.com/translate/docs/languages) for `Google` - [Reverso Translation](https://www.reverso.net/text-translation) for `Reverso` diff --git a/config.go b/config.go index 7dba1fe..120bb80 100644 --- a/config.go +++ b/config.go @@ -28,6 +28,8 @@ func configInit() { "destination.language.bing": "English", "source.language.chatgpt": "English", "destination.language.chatgpt": "English", + "source.language.deepl": "English", + "destination.language.deepl": "English", "source.language.google": "English", "destination.language.google": "English", "source.language.reverso": "English", @@ -110,10 +112,13 @@ func configInit() { uiStyle.Transparent = config.GetBool("transparent") uiStyle.SetSrcBorderColor(config.GetString("source.border_color")). SetDstBorderColor(config.GetString("destination.border_color")) - // Set API Key + // Set API Keys if config.Get("api_key.chatgpt") != nil { translators["ChatGPT"].SetAPIKey(config.GetString("api_key.chatgpt")) } + if config.Get("api_key.deepl") != nil { + translators["DeepL"].SetAPIKey(config.GetString("api_key.deepl")) + } // Set argument language if len(*srcLangArg) > 0 { translator.SetSrcLang(*srcLangArg) diff --git a/internal/translate/deepl/language.go b/internal/translate/deepl/language.go new file mode 100644 index 0000000..b16e42a --- /dev/null +++ b/internal/translate/deepl/language.go @@ -0,0 +1,68 @@ +package deepl + +// https://www.deepl.com/docs-api/translate-text +// TODO: Retrieve from DeepL API (https://www.deepl.com/docs-api/general/get-languages/) +var ( + lang = []string{ + "Bulgarian", + "Czech", + "Danish", + "German", + "Greek", + "English", + "Spanish", + "Estonian", + "Finnish", + "French", + "Hungarian", + "Indonesian", + "Italian", + "Japanese", + "Korean", + "Lithuanian", + "Latvian", + "Norwegian", + "Dutch", + "Polish", + "Portuguese", + "Romanian", + "Russian", + "Slovak", + "Slovenian", + "Swedish", + "Turkish", + "Ukrainian", + "Chinese", + } + langCode = map[string]string{ + "Bulgarian": "BG", + "Czech": "CS", + "Danish": "DA", + "German": "DE", + "Greek": "EL", + "English": "EN", + "Spanish": "ES", + "Estonian": "ET", + "Finnish": "FI", + "French": "FR", + "Hungarian": "HU", + "Indonesian": "ID", + "Italian": "IT", + "Japanese": "JA", + "Korean": "KO", + "Lithuanian": "LT", + "Latvian": "LV", + "Norwegian": "NB", + "Dutch": "NL", + "Polish": "PL", + "Portuguese": "PT", + "Romanian": "RO", + "Russian": "RU", + "Slovak": "SK", + "Slovenian": "SL", + "Swedish": "SV", + "Turkish": "TR", + "Ukrainian": "UK", + "Chinese": "ZH", + } +) diff --git a/internal/translate/deepl/translator.go b/internal/translate/deepl/translator.go new file mode 100644 index 0000000..ca7e31e --- /dev/null +++ b/internal/translate/deepl/translator.go @@ -0,0 +1,84 @@ +package deepl + +import ( + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "net/url" + "strings" + + "github.com/eeeXun/gtt/internal/translate/core" +) + +const ( + textURL = "https://api-free.deepl.com/v2/translate" +) + +type Translator struct { + *core.APIKey + *core.Language + *core.TTSLock + core.EngineName +} + +func NewTranslator() *Translator { + return &Translator{ + APIKey: new(core.APIKey), + Language: new(core.Language), + TTSLock: core.NewTTSLock(), + EngineName: core.NewEngineName("DeepL"), + } +} + +func (t *Translator) GetAllLang() []string { + return lang +} + +func (t *Translator) Translate(message string) (translation *core.Translation, err error) { + translation = new(core.Translation) + var data map[string]interface{} + + if len(t.GetAPIKey()) <= 0 { + return nil, errors.New("Please write your API Key in config file for " + t.GetEngineName()) + } + + userData := url.Values{} + userData.Set("text", message) + userData.Set("source_lang", langCode[t.GetSrcLang()]) + userData.Set("target_lang", langCode[t.GetDstLang()]) + req, _ := http.NewRequest(http.MethodPost, + textURL, + strings.NewReader(userData.Encode()), + ) + req.Header.Add("Authorization", fmt.Sprintf("DeepL-Auth-Key %s", t.GetAPIKey())) + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + res, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + body, err := io.ReadAll(res.Body) + if err != nil { + return nil, err + } + if err = json.Unmarshal(body, &data); err != nil { + return nil, err + } + + if len(data) <= 0 { + return nil, errors.New("translation not found") + } + + // fmt.Println("Request: ", req) + translation.TEXT = data["translations"].([]interface{})[0].(map[string]interface{})["text"].(string) + // translation.TEXT = fmt.Sprintf("Data: %s\nBody: %s\nRequest: %v", userData.Encode(), body, req) + + return translation, nil +} + +func (t *Translator) PlayTTS(lang, message string) error { + defer t.ReleaseLock() + + return errors.New(t.GetEngineName() + " does not support text to speech") +} diff --git a/internal/translate/translator.go b/internal/translate/translator.go index 4fa6aa4..8e44928 100644 --- a/internal/translate/translator.go +++ b/internal/translate/translator.go @@ -6,6 +6,7 @@ import ( "github.com/eeeXun/gtt/internal/translate/bing" "github.com/eeeXun/gtt/internal/translate/chatgpt" "github.com/eeeXun/gtt/internal/translate/core" + "github.com/eeeXun/gtt/internal/translate/deepl" "github.com/eeeXun/gtt/internal/translate/google" "github.com/eeeXun/gtt/internal/translate/reverso" ) @@ -16,6 +17,7 @@ var ( "Argos", "Bing", "ChatGPT", + "DeepL", "Google", "Reverso", } @@ -74,6 +76,8 @@ func NewTranslator(name string) Translator { translator = bing.NewTranslator() case "ChatGPT": translator = chatgpt.NewTranslator() + case "DeepL": + translator = deepl.NewTranslator() case "Google": translator = google.NewTranslator() case "Reverso":