Skip to content

Commit 8ced1b7

Browse files
committed
Add Youdao Translator
1 parent 2c9cf35 commit 8ced1b7

File tree

5 files changed

+303
-0
lines changed

5 files changed

+303
-0
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package com.airsaid.localization.translate.impl.youdao;
2+
3+
import com.airsaid.localization.translate.TranslationResult;
4+
import com.intellij.openapi.util.text.StringUtil;
5+
import org.jetbrains.annotations.NotNull;
6+
7+
import java.util.List;
8+
import java.util.Objects;
9+
10+
/**
11+
* @author airsaid
12+
*/
13+
public class YoudaoTranslationResult implements TranslationResult {
14+
private String requestId;
15+
private String errorCode;
16+
private List<String> translation;
17+
18+
public String getRequestId() {
19+
return requestId;
20+
}
21+
22+
public void setRequestId(String requestId) {
23+
this.requestId = requestId;
24+
}
25+
26+
public String getErrorCode() {
27+
return errorCode;
28+
}
29+
30+
public void setErrorCode(String errorCode) {
31+
this.errorCode = errorCode;
32+
}
33+
34+
public List<String> getTranslation() {
35+
return translation;
36+
}
37+
38+
public void setTranslation(List<String> translation) {
39+
this.translation = translation;
40+
}
41+
42+
@Override
43+
public boolean equals(Object o) {
44+
if (this == o) return true;
45+
if (o == null || getClass() != o.getClass()) return false;
46+
YoudaoTranslationResult that = (YoudaoTranslationResult) o;
47+
return Objects.equals(requestId, that.requestId);
48+
}
49+
50+
@Override
51+
public int hashCode() {
52+
return Objects.hash(requestId);
53+
}
54+
55+
public boolean isSuccess() {
56+
String errorCode = getErrorCode();
57+
return !StringUtil.isEmpty(errorCode) && "0".equals(errorCode);
58+
}
59+
60+
@Override
61+
public @NotNull String getTranslationResult() {
62+
List<String> translation = getTranslation();
63+
if (translation != null) {
64+
String result = translation.get(0);
65+
return result != null ? result : "";
66+
}
67+
return "";
68+
}
69+
70+
@Override
71+
public String toString() {
72+
return "YoudaoTranslationResult{" +
73+
"requestId='" + requestId + '\'' +
74+
", errorCode='" + errorCode + '\'' +
75+
", translation=" + translation +
76+
'}';
77+
}
78+
}
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
package com.airsaid.localization.translate.impl.youdao;
2+
3+
import com.airsaid.localization.translate.AbstractTranslator;
4+
import com.airsaid.localization.translate.TranslationException;
5+
import com.airsaid.localization.translate.impl.baidu.BaiduTranslationResult;
6+
import com.airsaid.localization.translate.lang.Lang;
7+
import com.airsaid.localization.translate.lang.Languages;
8+
import com.airsaid.localization.translate.util.GsonUtil;
9+
import com.airsaid.localization.translate.util.UrlBuilder;
10+
import com.intellij.openapi.util.Pair;
11+
import com.intellij.util.io.RequestBuilder;
12+
import icons.PluginIcons;
13+
import org.apache.commons.lang.StringEscapeUtils;
14+
import org.jetbrains.annotations.NotNull;
15+
import org.jetbrains.annotations.Nullable;
16+
17+
import javax.swing.*;
18+
import java.nio.charset.StandardCharsets;
19+
import java.security.MessageDigest;
20+
import java.security.NoSuchAlgorithmException;
21+
import java.util.ArrayList;
22+
import java.util.List;
23+
24+
/**
25+
* @author airsaid
26+
*/
27+
@SuppressWarnings(value = {"SpellCheckingInspection", "unused"})
28+
public class YoudaoTranslator extends AbstractTranslator {
29+
30+
private static final String KEY = "Youdao";
31+
private static final String HOST_URL = "https://openapi.youdao.com";
32+
private static final String TRANSLATE_URL = HOST_URL.concat("/api");
33+
private static final String APPLY_APP_ID_URL = "https://ai.youdao.com/DOCSIRMA/html/%E8%87%AA%E7%84%B6%E8%AF%AD%E8%A8%80%E7%BF%BB%E8%AF%91/API%E6%96%87%E6%A1%A3/%E6%96%87%E6%9C%AC%E7%BF%BB%E8%AF%91%E6%9C%8D%E5%8A%A1/%E6%96%87%E6%9C%AC%E7%BF%BB%E8%AF%91%E6%9C%8D%E5%8A%A1-API%E6%96%87%E6%A1%A3.html";
34+
35+
private List<Lang> supportedLanguages;
36+
37+
@Override
38+
public @NotNull String getKey() {
39+
return KEY;
40+
}
41+
42+
@Override
43+
public @NotNull String getName() {
44+
return "Youdao";
45+
}
46+
47+
@Override
48+
public @Nullable Icon getIcon() {
49+
return PluginIcons.YOUDAO_ICON;
50+
}
51+
52+
@Override
53+
public @NotNull List<Lang> getSupportedLanguages() {
54+
if (supportedLanguages == null) {
55+
supportedLanguages = new ArrayList<>();
56+
supportedLanguages.add(Languages.CHINESE_SIMPLIFIED.clone().setCode("zh-CHS"));
57+
supportedLanguages.add(Languages.ENGLISH);
58+
supportedLanguages.add(Languages.JAPANESE);
59+
supportedLanguages.add(Languages.KOREAN);
60+
supportedLanguages.add(Languages.FRENCH);
61+
supportedLanguages.add(Languages.SPANISH);
62+
supportedLanguages.add(Languages.ITALIAN);
63+
supportedLanguages.add(Languages.RUSSIAN);
64+
supportedLanguages.add(Languages.VIETNAMESE);
65+
supportedLanguages.add(Languages.GERMAN);
66+
supportedLanguages.add(Languages.ARABIC);
67+
supportedLanguages.add(Languages.INDONESIAN);
68+
supportedLanguages.add(Languages.AFRIKAANS);
69+
supportedLanguages.add(Languages.BOSNIAN);
70+
supportedLanguages.add(Languages.BULGARIAN);
71+
supportedLanguages.add(Languages.CATALAN);
72+
supportedLanguages.add(Languages.CROATIAN);
73+
supportedLanguages.add(Languages.CZECH);
74+
supportedLanguages.add(Languages.DANISH);
75+
supportedLanguages.add(Languages.DUTCH);
76+
supportedLanguages.add(Languages.ESTONIAN);
77+
supportedLanguages.add(Languages.FINNISH);
78+
supportedLanguages.add(Languages.HAITIAN_CREOLE);
79+
supportedLanguages.add(Languages.HINDI);
80+
supportedLanguages.add(Languages.HUNGARIAN);
81+
supportedLanguages.add(Languages.SWAHILI_SWAHILI);
82+
supportedLanguages.add(Languages.LITHUANIAN);
83+
supportedLanguages.add(Languages.MALAY);
84+
supportedLanguages.add(Languages.MALTESE);
85+
supportedLanguages.add(Languages.NORWEGIAN);
86+
supportedLanguages.add(Languages.POLISH);
87+
supportedLanguages.add(Languages.ROMANIAN);
88+
supportedLanguages.add(Languages.SERBIAN.clone().setCode("sr-Cyrl"));
89+
supportedLanguages.add(Languages.SLOVAK);
90+
supportedLanguages.add(Languages.SLOVENIAN);
91+
supportedLanguages.add(Languages.SWEDISH);
92+
supportedLanguages.add(Languages.THAI);
93+
supportedLanguages.add(Languages.TURKISH);
94+
supportedLanguages.add(Languages.UKRAINIAN);
95+
supportedLanguages.add(Languages.URDU);
96+
supportedLanguages.add(Languages.AMHARIC);
97+
supportedLanguages.add(Languages.AZERBAIJANI);
98+
supportedLanguages.add(Languages.BENGALI);
99+
supportedLanguages.add(Languages.BASQUE);
100+
supportedLanguages.add(Languages.BELARUSIAN);
101+
supportedLanguages.add(Languages.CEBUANO);
102+
supportedLanguages.add(Languages.CORSICAN);
103+
supportedLanguages.add(Languages.ESPERANTO);
104+
supportedLanguages.add(Languages.FILIPINO);
105+
supportedLanguages.add(Languages.FRISIAN);
106+
supportedLanguages.add(Languages.GUJARATI);
107+
supportedLanguages.add(Languages.HAUSA);
108+
supportedLanguages.add(Languages.HAWAIIAN);
109+
supportedLanguages.add(Languages.ICELANDIC);
110+
supportedLanguages.add(Languages.JAVANESE);
111+
supportedLanguages.add(Languages.KANNADA);
112+
supportedLanguages.add(Languages.KAZAKH);
113+
supportedLanguages.add(Languages.KHMER);
114+
supportedLanguages.add(Languages.KURDISH);
115+
supportedLanguages.add(Languages.KYRGYZ);
116+
supportedLanguages.add(Languages.LAOTIAN);
117+
supportedLanguages.add(Languages.LATIN);
118+
supportedLanguages.add(Languages.LUXEMBOURGISH);
119+
supportedLanguages.add(Languages.MACEDONIAN);
120+
supportedLanguages.add(Languages.MALAGASY);
121+
supportedLanguages.add(Languages.MALAYALAM);
122+
supportedLanguages.add(Languages.MARATHI);
123+
supportedLanguages.add(Languages.MONGOLIAN);
124+
supportedLanguages.add(Languages.BURMESE);
125+
supportedLanguages.add(Languages.NEPALI);
126+
supportedLanguages.add(Languages.CHICHEWA);
127+
supportedLanguages.add(Languages.PASHTO);
128+
supportedLanguages.add(Languages.PUNJABI);
129+
supportedLanguages.add(Languages.SAMOAN);
130+
supportedLanguages.add(Languages.SCOTTISH_GAELIC);
131+
supportedLanguages.add(Languages.SOTHO);
132+
supportedLanguages.add(Languages.SHONA);
133+
supportedLanguages.add(Languages.SINDHI);
134+
supportedLanguages.add(Languages.SLOVENIAN);
135+
supportedLanguages.add(Languages.SOMALI);
136+
supportedLanguages.add(Languages.SUNDANESE);
137+
supportedLanguages.add(Languages.TAJIK);
138+
supportedLanguages.add(Languages.TAMIL);
139+
supportedLanguages.add(Languages.TELUGU);
140+
supportedLanguages.add(Languages.UZBEK);
141+
supportedLanguages.add(Languages.XHOSA);
142+
supportedLanguages.add(Languages.YORUBA);
143+
supportedLanguages.add(Languages.ZULU);
144+
}
145+
return supportedLanguages;
146+
}
147+
148+
@Nullable
149+
@Override
150+
public String getApplyAppIdUrl() {
151+
return APPLY_APP_ID_URL;
152+
}
153+
154+
@Override
155+
public @NotNull String getRequestUrl(@NotNull Lang fromLang, @NotNull Lang toLang, @NotNull String text) {
156+
String salt = String.valueOf(System.currentTimeMillis());
157+
String curTime = String.valueOf(System.currentTimeMillis() / 1000);
158+
String appId = getAppId();
159+
String appKey = getAppKey();
160+
String sign = getDigest(appId + truncate(text) + salt + curTime + appKey);
161+
return new UrlBuilder(TRANSLATE_URL)
162+
.addQueryParameter("from", fromLang.getCode())
163+
.addQueryParameter("to", toLang.getCode())
164+
.addQueryParameter("signType", "v3")
165+
.addQueryParameter("curtime", curTime)
166+
.addQueryParameter("appKey", appId)
167+
.addQueryParameter("salt", salt)
168+
.addQueryParameter("sign", sign)
169+
.build();
170+
}
171+
172+
private String truncate(String q) {
173+
int len = q.length();
174+
return len <= 20 ? q : (q.substring(0, 10) + len + q.substring(len - 10, len));
175+
}
176+
177+
private String getDigest(String string) {
178+
char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
179+
byte[] btInput = string.getBytes(StandardCharsets.UTF_8);
180+
try {
181+
MessageDigest mdInst = MessageDigest.getInstance("SHA-256");
182+
mdInst.update(btInput);
183+
byte[] md = mdInst.digest();
184+
int j = md.length;
185+
char[] str = new char[j * 2];
186+
int k = 0;
187+
for (byte byte0 : md) {
188+
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
189+
str[k++] = hexDigits[byte0 & 0xf];
190+
}
191+
return new String(str);
192+
} catch (NoSuchAlgorithmException e) {
193+
return null;
194+
}
195+
}
196+
197+
@Override
198+
public @NotNull List<Pair<String, String>> getRequestParams(@NotNull Lang fromLang, @NotNull Lang toLang, @NotNull String text) {
199+
List<Pair<String, String>> params = new ArrayList<>();
200+
params.add(Pair.create("q", StringEscapeUtils.escapeJava(text)));
201+
return params;
202+
}
203+
204+
@Override
205+
public void configureRequestBuilder(@NotNull RequestBuilder requestBuilder) {
206+
requestBuilder.tuner(connection -> connection.setRequestProperty("Referer", HOST_URL));
207+
}
208+
209+
@Override
210+
public @NotNull String parsingResult(@NotNull Lang fromLang, @NotNull Lang toLang, @NotNull String text, @NotNull String resultText) {
211+
LOG.info("parsingResult: " + resultText);
212+
YoudaoTranslationResult translationResult = GsonUtil.getInstance().getGson().fromJson(resultText, YoudaoTranslationResult.class);
213+
if (translationResult.isSuccess()) {
214+
return translationResult.getTranslationResult();
215+
} else {
216+
throw new TranslationException(fromLang, toLang, text, translationResult.getErrorCode());
217+
}
218+
}
219+
}

src/main/java/com/airsaid/localization/translate/services/TranslatorService.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.airsaid.localization.translate.AbstractTranslator;
44
import com.airsaid.localization.translate.impl.baidu.BaiduTranslator;
55
import com.airsaid.localization.translate.impl.google.GoogleTranslator;
6+
import com.airsaid.localization.translate.impl.youdao.YoudaoTranslator;
67
import com.airsaid.localization.translate.lang.Lang;
78
import com.intellij.openapi.application.ApplicationManager;
89
import com.intellij.openapi.components.Service;
@@ -38,6 +39,9 @@ public TranslatorService() {
3839
BaiduTranslator baiduTranslator = new BaiduTranslator();
3940
translators.put(baiduTranslator.getKey(), baiduTranslator);
4041

42+
YoudaoTranslator youdaoTranslator = new YoudaoTranslator();
43+
translators.put(youdaoTranslator.getKey(), youdaoTranslator);
44+
4145
cacheService = TranslationCacheService.getInstance();
4246
}
4347

src/main/java/icons/PluginIcons.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,5 @@ public interface PluginIcons {
2727
Icon TRANSLATE_ACTION_ICON = IconLoader.getIcon("/icons/icon_translate.svg");
2828
Icon GOOGLE_ICON = IconLoader.getIcon("/icons/icon_google.svg");
2929
Icon BAIDU_ICON = IconLoader.getIcon("/icons/icon_baidu.svg");
30+
Icon YOUDAO_ICON = IconLoader.getIcon("/icons/icon_youdao.svg");
3031
}
Lines changed: 1 addition & 0 deletions
Loading

0 commit comments

Comments
 (0)