From fd4af07b66ffbf9db507046b0c19c01bb0818bb7 Mon Sep 17 00:00:00 2001 From: end candle Date: Mon, 28 Aug 2023 05:05:15 +0800 Subject: [PATCH] feat: add Baidu translation engine support (#768) * feat: Added Baidu translation support * fix: Baidu translation results are not displayed correctly * Fix merge error in Turkish translation --------- Co-authored-by: Alex Terehov --- locales/de.json | 2 + locales/en.json | 2 + locales/es.json | 2 + locales/fr.json | 2 + locales/ja.json | 2 + locales/nb-NO.json | 2 + locales/nl-NL.json | 2 + locales/pt-BR.json | 2 + locales/ru.json | 2 + locales/sv-SE.json | 2 + locales/tr.json | 2 + locales/uk-UA.json | 2 + locales/zh-CN.json | 2 + locales/zh-TW.json | 2 + package.json | 11 +++++ src/core/Config.ts | 8 +++ src/translators/engines/baidu.ts | 84 ++++++++++++++++++++++++++++++++ src/translators/index.ts | 3 ++ 18 files changed, 134 insertions(+) create mode 100644 src/translators/engines/baidu.ts diff --git a/locales/de.json b/locales/de.json index efb0cc43..c7330360 100644 --- a/locales/de.json +++ b/locales/de.json @@ -37,6 +37,8 @@ "config.annotation_max_length": "Maximale Zeichenlänge für Hinweise die im Text angezeigt werden. Abgeschnitte Zeichen werden als (...) angezeigt", "config.annotations": "Hinweise im Text aktivieren", "config.auto_detection": "Automatische Erkennung von Übersetzung aktivieren", + "config.baidu_app_secret": "", + "config.baidu_appid": "", "config.deepl_api_key": "API key für die DeepL translate engine", "config.deepl_log": "DeepL debug logs anzeigen", "config.deepl_use_free_api_entry": "Kostenlose DeepL Version benutzen", diff --git a/locales/en.json b/locales/en.json index 32b9d487..875a28cc 100644 --- a/locales/en.json +++ b/locales/en.json @@ -37,6 +37,8 @@ "config.annotation_max_length": "Max number of characters shown in the inline annotations. Excess characters will display as an ellipses (...)", "config.annotations": "Enable the inline annotations.", "config.auto_detection": "Enable locales auto detection for projects", + "config.baidu_app_secret": "APP Secret to use Baidu translate engine", + "config.baidu_appid": "APP ID to use Baidu translate engine", "config.deepl_api_key": "API key to use DeepL translate engine", "config.deepl_log": "Show DeepL engine debug logs", "config.deepl_use_free_api_entry": "Use DeepL Free API entry point", diff --git a/locales/es.json b/locales/es.json index fc073450..95a73caf 100644 --- a/locales/es.json +++ b/locales/es.json @@ -37,6 +37,8 @@ "config.annotation_max_length": "Máximo número de caracteres que se mostrarán en las anotaciones en línea. Los restantes se mostrarán como elipses (...)", "config.annotations": "Habilitar las anotaciones en línea.", "config.auto_detection": "", + "config.baidu_app_secret": "", + "config.baidu_appid": "", "config.deepl_api_key": "API key para el traductor DeepL", "config.deepl_log": "Mostrar mensajes de depuración del motor DeepL", "config.deepl_use_free_api_entry": "", diff --git a/locales/fr.json b/locales/fr.json index bcaf79d0..332a5147 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -37,6 +37,8 @@ "config.annotation_max_length": "Nombre maximum de caractères à afficher dans les annotations. Le surplus sera affiché sous forme d'ellipse (...)", "config.annotations": "Activer les annotations.", "config.auto_detection": "Activer la détection automatique des langues pour les projets", + "config.baidu_app_secret": "", + "config.baidu_appid": "", "config.deepl_api_key": "Clé API pour utiliser le moteur de traduction DeepL", "config.deepl_log": "Montrer le journal de debug du moteur DeepL", "config.deepl_use_free_api_entry": "Utiliser le point d'entrée gratuite de DeepL", diff --git a/locales/ja.json b/locales/ja.json index 0c774e84..55de2f6e 100644 --- a/locales/ja.json +++ b/locales/ja.json @@ -37,6 +37,8 @@ "config.annotation_max_length": "インラインアノテーションの最大文字数です。超過している部分は(...)と表示されます。", "config.annotations": "インラインアノテーションを有効にする.", "config.auto_detection": "", + "config.baidu_app_secret": "", + "config.baidu_appid": "", "config.deepl_api_key": "", "config.deepl_log": "", "config.deepl_use_free_api_entry": "", diff --git a/locales/nb-NO.json b/locales/nb-NO.json index 4bfef28f..b47f09c1 100644 --- a/locales/nb-NO.json +++ b/locales/nb-NO.json @@ -37,6 +37,8 @@ "config.annotation_max_length": "Maksimalt antall tegn vist i hjelpevindu. Resterende del vil bli vist som (...)", "config.annotations": "Slå på hjelpevindu", "config.auto_detection": "", + "config.baidu_app_secret": "", + "config.baidu_appid": "", "config.deepl_api_key": "", "config.deepl_log": "", "config.deepl_use_free_api_entry": "", diff --git a/locales/nl-NL.json b/locales/nl-NL.json index 4588982b..579cc088 100644 --- a/locales/nl-NL.json +++ b/locales/nl-NL.json @@ -37,6 +37,8 @@ "config.annotation_max_length": "Max. aantal karakters zichtbaar binnen inline annotaties. Overschreden delen worden getoond als ellipses (...)", "config.annotations": "Inline annotaties inschakelen.", "config.auto_detection": "", + "config.baidu_app_secret": "", + "config.baidu_appid": "", "config.deepl_api_key": "", "config.deepl_log": "", "config.deepl_use_free_api_entry": "", diff --git a/locales/pt-BR.json b/locales/pt-BR.json index a0ac6db7..d6026e6c 100644 --- a/locales/pt-BR.json +++ b/locales/pt-BR.json @@ -37,6 +37,8 @@ "config.annotation_max_length": "Número máximo de caracteres exibidos nas anotações inline. O restante será exibido em forma de reticências (...)", "config.annotations": "Habilitar anotações inline", "config.auto_detection": "", + "config.baidu_app_secret": "", + "config.baidu_appid": "", "config.deepl_api_key": "", "config.deepl_log": "", "config.deepl_use_free_api_entry": "", diff --git a/locales/ru.json b/locales/ru.json index 59432a0c..d2135d08 100644 --- a/locales/ru.json +++ b/locales/ru.json @@ -37,6 +37,8 @@ "config.annotation_max_length": "Максимальное количество символов, отображаемых во встроенных аннотациях. Лишние символы будут отображаться в виде многоточия (...)", "config.annotations": "Включить встроенные аннотации.", "config.auto_detection": "Включить автоматическое определение переводов для проектов", + "config.baidu_app_secret": "", + "config.baidu_appid": "", "config.deepl_api_key": "API ключ для использования DeepL", "config.deepl_log": "Отображать отладочные журналы DeepL", "config.deepl_use_free_api_entry": "Использовать бесплатную версию DeepL API", diff --git a/locales/sv-SE.json b/locales/sv-SE.json index bdb9f1e4..d2c21df0 100644 --- a/locales/sv-SE.json +++ b/locales/sv-SE.json @@ -37,6 +37,8 @@ "config.annotation_max_length": "Max antal bokstävers som visas i insatta anteckningen. Överflödiga bokstäver kommer visas som en ellips (…)", "config.annotations": "Aktivera insatta anteckningar.", "config.auto_detection": "", + "config.baidu_app_secret": "", + "config.baidu_appid": "", "config.deepl_api_key": "", "config.deepl_log": "", "config.deepl_use_free_api_entry": "", diff --git a/locales/tr.json b/locales/tr.json index f28c7ef5..35163602 100644 --- a/locales/tr.json +++ b/locales/tr.json @@ -37,6 +37,8 @@ "config.annotation_max_length": "Satır aralığında gösterilen ek açıklamaların maksimum karakter uzunluğu. Fazladan karakterler noktalı şekilde görüntülenecektir (...)", "config.annotations": "Satır aralığında ek açıklamaları etkinleştir", "config.auto_detection": "Projeler için otomatik çeviri algılamasını etkinleştir", + "config.baidu_app_secret": "", + "config.baidu_appid": "", "config.deepl_api_key": "DeepL çeviri sistemini kullanmak için API anahtarı", "config.deepl_log": "DeepL sisteminin hata ayıklama kayıtlarını göster", "config.deepl_use_free_api_entry": "DeepL'in Bedava API giriş noktasını kullanın", diff --git a/locales/uk-UA.json b/locales/uk-UA.json index 3ad70a7d..29fa0876 100644 --- a/locales/uk-UA.json +++ b/locales/uk-UA.json @@ -37,6 +37,8 @@ "config.annotation_max_length": "Максимальна кількість символів, що відображаються у вбудованих анотаціях. Зайві символи будуть відображатися у вигляді трьох крапок (...)", "config.annotations": "Включити вбудовані анотації.", "config.auto_detection": "", + "config.baidu_app_secret": "", + "config.baidu_appid": "", "config.deepl_api_key": "Ключ для використання API DeepL", "config.deepl_log": "Відображати налагоджувальні журнали DeepL", "config.deepl_use_free_api_entry": "", diff --git a/locales/zh-CN.json b/locales/zh-CN.json index 3676de62..cef8d35a 100644 --- a/locales/zh-CN.json +++ b/locales/zh-CN.json @@ -37,6 +37,8 @@ "config.annotation_max_length": "内联注释显示的最大字符数。超出的部分将显示为省略号(...)", "config.annotations": "启用内联注释", "config.auto_detection": "", + "config.baidu_app_secret": "百度平台分配的密钥", + "config.baidu_appid": "百度平台APPID", "config.deepl_api_key": "", "config.deepl_log": "", "config.deepl_use_free_api_entry": "", diff --git a/locales/zh-TW.json b/locales/zh-TW.json index 1ef55aa2..9ccdf581 100644 --- a/locales/zh-TW.json +++ b/locales/zh-TW.json @@ -37,6 +37,8 @@ "config.annotation_max_length": "內聯註釋顯示的最大文字數。超出的部分將顯示為省略號(...)", "config.annotations": "啟用內聯註釋", "config.auto_detection": "", + "config.baidu_app_secret": "", + "config.baidu_appid": "", "config.deepl_api_key": "", "config.deepl_log": "", "config.deepl_use_free_api_entry": "", diff --git a/package.json b/package.json index f5d8475c..a558bfad 100644 --- a/package.json +++ b/package.json @@ -1026,6 +1026,7 @@ "google-cn", "deepl", "libretranslate", + "baidu", "openai" ] }, @@ -1059,6 +1060,16 @@ "default": null, "description": "%config.deepl_api_key%" }, + "i18n-ally.translate.baidu.appid": { + "type": "string", + "default": null, + "description": "%config.baidu_appid%" + }, + "i18n-ally.translate.baidu.apiSecret": { + "type": "string", + "default": null, + "description": "%config.baidu_app_secret%" + }, "i18n-ally.translate.deepl.enableLog": { "type": "boolean", "default": false, diff --git a/src/core/Config.ts b/src/core/Config.ts index a2da96cc..1af99192 100644 --- a/src/core/Config.ts +++ b/src/core/Config.ts @@ -536,6 +536,14 @@ export class Config { .update(key, value, isGlobal) } + static get baiduApiSecret() { + return this.getConfig('translate.baidu.apiSecret') + } + + static get baiduAppid() { + return this.getConfig('translate.baidu.appid') + } + static get googleApiKey() { return this.getConfig('translate.google.apiKey') } diff --git a/src/translators/engines/baidu.ts b/src/translators/engines/baidu.ts new file mode 100644 index 00000000..51baf765 --- /dev/null +++ b/src/translators/engines/baidu.ts @@ -0,0 +1,84 @@ +import crypto from 'crypto' +import axios from 'axios' +import qs from 'qs' +import TranslateEngine, { TranslateOptions, TranslateResult } from './base' +import { Config } from '~/core' + +interface BaiduSignOptions { + appid: string | null | undefined + salt: string + secret: string | null | undefined + query: string +} + +export default class BaiduTranslate extends TranslateEngine { + apiLink = 'https://fanyi.baidu.com' + apiRoot = 'https://fanyi-api.baidu.com' + + async translate(options: TranslateOptions) { + let { from = 'auto', to = 'auto' } = options + + from = this.convertToSupportedLocalesForGoogleCloud(from) + to = this.convertToSupportedLocalesForGoogleCloud(to) + + const appid = Config.baiduAppid + const secret = Config.baiduApiSecret + const salt = Date.now().toString() + const sign = this.getSign({ appid, secret, query: options.text, salt }) + + const form = { + q: options.text, + appid, + salt, + from, + to, + sign, + } + + const { data } = await axios({ + method: 'GET', + url: `${this.apiRoot}/api/trans/vip/translate?${qs.stringify(form)}`, + }) + + return this.transform(data, options) + } + + convertToSupportedLocalesForGoogleCloud(locale: string): string { + return locale.replace(/-/g, '_').split('_')[0] + } + + getSign({ appid, salt, query, secret }: BaiduSignOptions): string { + if (appid && salt) { + const string = appid + query + salt + secret + const md5 = crypto.createHash('md5') + md5.update(string) + return md5.digest('hex') + } + return '' + } + + transform(response: any, options: TranslateOptions): TranslateResult { + const { text } = options + + const r: TranslateResult = { + text, + to: response.to, + from: response.from, + response, + linkToResult: `${this.apiLink}/#${response.from}/${response.to}/${text}`, + } + + try { + const result: string[] = [] + response.trans_result.forEach((v: any) => { + result.push(v.dst) + }) + r.result = result + } + catch (e) {} + + if (!r.result) r.error = new Error((`[${response.error_code}] ${response.error_msg}`) || 'No result') + + return r + } +} diff --git a/src/translators/index.ts b/src/translators/index.ts index 749f48f2..31474df6 100644 --- a/src/translators/index.ts +++ b/src/translators/index.ts @@ -3,6 +3,7 @@ import GoogleTranslateEngine from './engines/google' import GoogleTranslateCnEngine from './engines/google-cn' import DeepLTranslateEngine from './engines/deepl' import LibreTranslateEngine from './engines/libretranslate' +import BaiduTranslate from './engines/baidu' import OpenAITranslateEngine from './engines/openai' export class Translator { @@ -11,6 +12,7 @@ export class Translator { 'google-cn': new GoogleTranslateCnEngine(), 'deepl': new DeepLTranslateEngine(), 'libretranslate': new LibreTranslateEngine(), + 'baidu': new BaiduTranslate(), 'openai': new OpenAITranslateEngine(), } @@ -26,6 +28,7 @@ export { GoogleTranslateCnEngine, DeepLTranslateEngine, LibreTranslateEngine, + BaiduTranslate, OpenAITranslateEngine, }