|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2017 - 2019 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing the DeepL translation engine. |
|
8 """ |
|
9 |
|
10 from __future__ import unicode_literals |
|
11 try: |
|
12 str = unicode |
|
13 except NameError: |
|
14 pass |
|
15 |
|
16 import json |
|
17 |
|
18 from PyQt5.QtCore import QUrl, QByteArray, QTimer |
|
19 |
|
20 import Utilities |
|
21 |
|
22 from .TranslationEngine import TranslationEngine |
|
23 |
|
24 |
|
25 class DeepLEngine(TranslationEngine): |
|
26 """ |
|
27 Class implementing the translation engine for the DeepL |
|
28 translation service. |
|
29 """ |
|
30 TranslatorUrl = "https://api.deepl.com/v1/translate" |
|
31 MaxTranslationTextLen = 30 * 1024 |
|
32 |
|
33 def __init__(self, plugin, parent=None): |
|
34 """ |
|
35 Constructor |
|
36 |
|
37 @param plugin reference to the plugin object |
|
38 @type TranslatorPlugin |
|
39 @param parent reference to the parent object |
|
40 @type QObject |
|
41 """ |
|
42 super(DeepLEngine, self).__init__(plugin, parent) |
|
43 |
|
44 QTimer.singleShot(0, self.availableTranslationsLoaded.emit) |
|
45 |
|
46 def engineName(self): |
|
47 """ |
|
48 Public method to return the name of the engine. |
|
49 |
|
50 @return engine name |
|
51 @rtype str |
|
52 """ |
|
53 return "deepl" |
|
54 |
|
55 def supportedLanguages(self): |
|
56 """ |
|
57 Public method to get the supported languages. |
|
58 |
|
59 @return list of supported language codes |
|
60 @rtype list of str |
|
61 """ |
|
62 return ["de", "en", "es", "fr", "it", "nl", "pl", ] |
|
63 |
|
64 def getTranslation(self, requestObject, text, originalLanguage, |
|
65 translationLanguage): |
|
66 """ |
|
67 Public method to translate the given text. |
|
68 |
|
69 @param requestObject reference to the request object |
|
70 (TranslatorRequest) |
|
71 @param text text to be translated (string) |
|
72 @param originalLanguage language code of the original (string) |
|
73 @param translationLanguage language code of the translation (string) |
|
74 @return tuple of translated text (string) and flag indicating |
|
75 success (boolean) |
|
76 """ |
|
77 if len(text) > self.MaxTranslationTextLen: |
|
78 return self.tr( |
|
79 "Text to be translated exceeds the translation limit of {0}" |
|
80 " characters.").format(self.MaxTranslationTextLen), False |
|
81 |
|
82 apiKey = self.plugin.getPreferences("DeeplKey") |
|
83 if not apiKey: |
|
84 return self.tr("A valid DeepL Pro key is required."), False |
|
85 |
|
86 params = QByteArray( |
|
87 "auth_key={0}&source_lang={1}&target_lang={2}&text=".format( |
|
88 apiKey, originalLanguage.upper(), translationLanguage.upper()) |
|
89 .encode("utf-8")) |
|
90 encodedText = QByteArray(Utilities.html_encode(text).encode("utf-8"))\ |
|
91 .toPercentEncoding() |
|
92 request = params + encodedText |
|
93 response, ok = requestObject.post(QUrl(self.TranslatorUrl), request) |
|
94 if ok: |
|
95 try: |
|
96 responseDict = json.loads(response) |
|
97 except ValueError: |
|
98 return self.tr("Invalid response received from DeepL"), False |
|
99 |
|
100 if "translations" not in responseDict: |
|
101 return self.tr("DeepL call returned an unknown result"), False |
|
102 |
|
103 translations = responseDict["translations"] |
|
104 if len(translations) == 0: |
|
105 return self.tr("<p>No translation found</p>"), True |
|
106 |
|
107 # show sentence by sentence separated by a line |
|
108 result = ( |
|
109 "<p>" + |
|
110 "<hr/>".join([t["text"] for t in translations]) + |
|
111 "</p>" |
|
112 ) |
|
113 |
|
114 else: |
|
115 result = response |
|
116 return result, ok |