From 2d538dc6e2e862a90c156a22ae7e662abe16930d Mon Sep 17 00:00:00 2001 From: BANKA2017 Date: Sun, 7 Apr 2024 02:00:40 +0800 Subject: [PATCH] add: source google browser translate v2 (GoogleBrowserTranslateV2) add: source watson (WatsonDetect, WatsonTranslator) --- README.md | 6 +- assets/target/watson.json | 466 ++++++++++++++++++++++++ package.json | 2 +- scripts/language_list_types_builder.mjs | 24 +- src/index.browser.ts | 5 +- src/index.ts | 14 +- src/language.ts | 3 + src/source/google.ts | 31 +- src/source/watson.ts | 53 +++ src/types.ts | 24 +- tests/google.test.ts | 20 +- tests/watson.test.ts | 38 ++ 12 files changed, 665 insertions(+), 21 deletions(-) create mode 100644 assets/target/watson.json create mode 100644 src/source/watson.ts create mode 100644 tests/watson.test.ts diff --git a/README.md b/README.md index 669338f..b9a0258 100644 --- a/README.md +++ b/README.md @@ -10,10 +10,10 @@ This is an early release version, everything are subject to change, please **DO ## Predict (Nodejs/Deno) -`baidu` / `yandex` / `microsoft` +`baidu` / `yandex` / `microsoft` / `watson` ```javascript -import { BaiduLanguagePredict, YandexDetect, MicrosoftBrowserPredict } from '@kdwnil/translator-utils' +import { BaiduLanguagePredict, YandexDetect, MicrosoftBrowserPredict, WatsonDetect } from '@kdwnil/translator-utils' await BaiduLanguagePredict('hello') // en await BaiduLanguagePredict('你好') // zh @@ -108,6 +108,8 @@ Because of `CORS policy`, you can only use `GoogleBrowserTranslate`, `MicrosoftB `YandexBrowserTranslate` is supported in browser, but predicted service is **NOT** supported, so you can't set `source` to `auto` in function calling. +`GoogleBrowserTranslateV2` is also supported in browser, but the source can not be set to `auto`. + ## Nodejs **Proxy** can only be used in nodejs environment, set environment variable `http_proxy` and `https_proxy` to active it diff --git a/assets/target/watson.json b/assets/target/watson.json new file mode 100644 index 0000000..45ad7f9 --- /dev/null +++ b/assets/target/watson.json @@ -0,0 +1,466 @@ +{ + "status": "success", + "message": "ok", + "payload": { + "sourceLanguages": [ + { + "language": "ar", + "name": "Arabic" + }, + { + "language": "bg", + "name": "Bulgarian" + }, + { + "language": "bn", + "name": "Bengali" + }, + { + "language": "bs", + "name": "Bosnian" + }, + { + "language": "ca", + "name": "Catalan" + }, + { + "language": "cnr", + "name": "Montenegrin" + }, + { + "language": "cs", + "name": "Czech" + }, + { + "language": "cy", + "name": "Welsh" + }, + { + "language": "da", + "name": "Danish" + }, + { + "language": "de", + "name": "German" + }, + { + "language": "el", + "name": "Greek" + }, + { + "language": "en", + "name": "English" + }, + { + "language": "es", + "name": "Spanish" + }, + { + "language": "et", + "name": "Estonian" + }, + { + "language": "eu", + "name": "Basque" + }, + { + "language": "fi", + "name": "Finnish" + }, + { + "language": "fr", + "name": "French" + }, + { + "language": "fr-CA", + "name": "French (Canada)" + }, + { + "language": "ga", + "name": "Irish" + }, + { + "language": "gu", + "name": "Gujarati" + }, + { + "language": "he", + "name": "Hebrew" + }, + { + "language": "hi", + "name": "Hindi" + }, + { + "language": "hr", + "name": "Croatian" + }, + { + "language": "hu", + "name": "Hungarian" + }, + { + "language": "id", + "name": "Indonesian" + }, + { + "language": "it", + "name": "Italian" + }, + { + "language": "ja", + "name": "Japanese" + }, + { + "language": "kn", + "name": "Kannada" + }, + { + "language": "ko", + "name": "Korean" + }, + { + "language": "lt", + "name": "Lithuanian" + }, + { + "language": "lv", + "name": "Latvian" + }, + { + "language": "ml", + "name": "Malayalam" + }, + { + "language": "mr", + "name": "Marathi" + }, + { + "language": "ms", + "name": "Malay" + }, + { + "language": "mt", + "name": "Maltese" + }, + { + "language": "nb", + "name": "Norwegian Bokmal" + }, + { + "language": "ne", + "name": "Nepali" + }, + { + "language": "nl", + "name": "Dutch" + }, + { + "language": "pa", + "name": "Punjabi" + }, + { + "language": "pl", + "name": "Polish" + }, + { + "language": "pt", + "name": "Portuguese" + }, + { + "language": "ro", + "name": "Romanian" + }, + { + "language": "ru", + "name": "Russian" + }, + { + "language": "si", + "name": "Sinhala" + }, + { + "language": "sk", + "name": "Slovakian" + }, + { + "language": "sl", + "name": "Slovenian" + }, + { + "language": "sr", + "name": "Serbian" + }, + { + "language": "sv", + "name": "Swedish" + }, + { + "language": "ta", + "name": "Tamil" + }, + { + "language": "te", + "name": "Telugu" + }, + { + "language": "th", + "name": "Thai" + }, + { + "language": "tr", + "name": "Turkish" + }, + { + "language": "uk", + "name": "Ukrainian" + }, + { + "language": "ur", + "name": "Urdu" + }, + { + "language": "vi", + "name": "Vietnamese" + }, + { + "language": "zh", + "name": "Simplified Chinese" + }, + { + "language": "zh-TW", + "name": "Traditional Chinese" + } + ], + "targetLanguages": [ + { + "language": "ar", + "name": "Arabic" + }, + { + "language": "bg", + "name": "Bulgarian" + }, + { + "language": "bn", + "name": "Bengali" + }, + { + "language": "bs", + "name": "Bosnian" + }, + { + "language": "ca", + "name": "Catalan" + }, + { + "language": "cnr", + "name": "Montenegrin" + }, + { + "language": "cs", + "name": "Czech" + }, + { + "language": "cy", + "name": "Welsh" + }, + { + "language": "da", + "name": "Danish" + }, + { + "language": "de", + "name": "German" + }, + { + "language": "el", + "name": "Greek" + }, + { + "language": "en", + "name": "English" + }, + { + "language": "es", + "name": "Spanish" + }, + { + "language": "et", + "name": "Estonian" + }, + { + "language": "eu", + "name": "Basque" + }, + { + "language": "fi", + "name": "Finnish" + }, + { + "language": "fr", + "name": "French" + }, + { + "language": "fr-CA", + "name": "French (Canada)" + }, + { + "language": "ga", + "name": "Irish" + }, + { + "language": "gu", + "name": "Gujarati" + }, + { + "language": "he", + "name": "Hebrew" + }, + { + "language": "hi", + "name": "Hindi" + }, + { + "language": "hr", + "name": "Croatian" + }, + { + "language": "hu", + "name": "Hungarian" + }, + { + "language": "id", + "name": "Indonesian" + }, + { + "language": "it", + "name": "Italian" + }, + { + "language": "ja", + "name": "Japanese" + }, + { + "language": "kn", + "name": "Kannada" + }, + { + "language": "ko", + "name": "Korean" + }, + { + "language": "lt", + "name": "Lithuanian" + }, + { + "language": "lv", + "name": "Latvian" + }, + { + "language": "ml", + "name": "Malayalam" + }, + { + "language": "mr", + "name": "Marathi" + }, + { + "language": "ms", + "name": "Malay" + }, + { + "language": "mt", + "name": "Maltese" + }, + { + "language": "nb", + "name": "Norwegian Bokmal" + }, + { + "language": "ne", + "name": "Nepali" + }, + { + "language": "nl", + "name": "Dutch" + }, + { + "language": "pa", + "name": "Punjabi" + }, + { + "language": "pl", + "name": "Polish" + }, + { + "language": "pt", + "name": "Portuguese" + }, + { + "language": "ro", + "name": "Romanian" + }, + { + "language": "ru", + "name": "Russian" + }, + { + "language": "si", + "name": "Sinhala" + }, + { + "language": "sk", + "name": "Slovakian" + }, + { + "language": "sl", + "name": "Slovenian" + }, + { + "language": "sr", + "name": "Serbian" + }, + { + "language": "sv", + "name": "Swedish" + }, + { + "language": "ta", + "name": "Tamil" + }, + { + "language": "te", + "name": "Telugu" + }, + { + "language": "th", + "name": "Thai" + }, + { + "language": "tr", + "name": "Turkish" + }, + { + "language": "uk", + "name": "Ukrainian" + }, + { + "language": "ur", + "name": "Urdu" + }, + { + "language": "vi", + "name": "Vietnamese" + }, + { + "language": "zh", + "name": "Simplified Chinese" + }, + { + "language": "zh-TW", + "name": "Traditional Chinese" + } + ] + } +} diff --git a/package.json b/package.json index 3354eb5..4fa126a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@kdwnil/translator-utils", "private": true, - "version": "0.0.2-alpha.31", + "version": "0.0.2-alpha.32", "description": "translate utils", "homepage": "https://github.com/BANKA2017/translator-utils", "bugs": { diff --git a/scripts/language_list_types_builder.mjs b/scripts/language_list_types_builder.mjs index 3c856a0..38e9f00 100644 --- a/scripts/language_list_types_builder.mjs +++ b/scripts/language_list_types_builder.mjs @@ -4,7 +4,7 @@ let jsContent = "import type { TargetFilter } from 'types.js'\n\n" // google content/type/<-tts // JSON.stringify(Object.fromEntries([...document.querySelectorAll()[0].querySelectorAll('[data-language-code]')].map(x => [x.dataset.languageCode.toLowerCase(), x.innerText]).sort((a, b) => a[0] > b[0] ? 1 : -1))) -const google = JSON.parse(readFileSync('../assets/target/google.json').toString()) +const google = JSON.parse(readFileSync('../assets/target/google.json', 'utf-8')) jsContent += `export type GOOGLE_LIST = ${Object.entries(google) .map((lang) => "'" + lang[0] + "'") .join('|')}\n` @@ -15,7 +15,7 @@ jsContent += `export const GOOGLE_LANGUAGE_OBJECT: { [p in GOOGLE_LIST]: string // microsoft content/type/tts // JSON.stringify(Object.fromEntries([...tta_srcsl.querySelectorAll('option[aria-label]')].map(x => [x.value.toLowerCase(), x.innerText]).sort((a, b) => a[0] > b[0] ? 1 : -1))) -const microsoft = JSON.parse(readFileSync('../assets/target/bing.json').toString()) +const microsoft = JSON.parse(readFileSync('../assets/target/bing.json', 'utf-8')) jsContent += `export type BING_LIST = ${Object.entries(microsoft) .map((lang) => "'" + lang[0] + "'") .join('|')}\n` @@ -24,19 +24,19 @@ jsContent += `export const BING_LANGUAGE: TargetFilter['microsoft'][] = [${Objec .join(',')}]\n` jsContent += `export const BING_LANGUAGE_OBJECT: { [p in BING_LIST]: string } = ${JSON.stringify(microsoft)}\n` -const microsoft_tts = JSON.parse(readFileSync('../assets/target/microsoft_tts.json').toString()) +const microsoft_tts = JSON.parse(readFileSync('../assets/target/microsoft_tts.json', 'utf-8')) jsContent += `export type BING_TTS_LIST = ${microsoft_tts.map((msttsItem) => "'" + msttsItem.code + "'").join('|')}\n` jsContent += `export const MICROSOFT_TTS_LIST: { code: BING_TTS_LIST; language: string; gender: 'Male' | 'Female'; model: string }[] = ${JSON.stringify(microsoft_tts)}\n` -const microsoft_edge_tts = JSON.parse(readFileSync('../assets/target/microsoft_edge_tts.json').toString()) +const microsoft_edge_tts = JSON.parse(readFileSync('../assets/target/microsoft_edge_tts.json', 'utf-8')) jsContent += `export type MICROSOFT_EDGE_TTS_TYPE = ${[...new Set(microsoft_edge_tts.map((msttsItem) => "'" + msttsItem.Locale + "'"))].join('|')}\n` jsContent += `export const MICROSOFT_EDGE_TTS_LIST: { language: MICROSOFT_EDGE_TTS_TYPE; gender: 'Male' | 'Female'; model: string }[] = ${JSON.stringify(microsoft_edge_tts.map((msttsItem) => ({ language: msttsItem.Locale, gender: msttsItem.Gender, model: msttsItem.ShortName })))}\n` // yandex content/type // JSON.stringify(Object.fromEntries([...document.querySelectorAll('.langs-item.langs-item_cell.langs-item_hasLetterSpace')].map(x => [x.dataset.value.toLowerCase(), x.innerText.includes('\n') ? x.innerText.split('\n')[1].trim() : x.innerText.trim()]).sort((a, b) => a[0] > b[0] ? 1 : -1))) -const yandex = JSON.parse(readFileSync('../assets/target/yandex.json').toString()) +const yandex = JSON.parse(readFileSync('../assets/target/yandex.json', 'utf-8')) jsContent += `export type YANDEX_LIST = ${Object.entries(yandex) .map((lang) => "'" + lang[0] + "'") .join('|')}\n` @@ -46,7 +46,7 @@ jsContent += `export const YANDEX_LANGUAGE: TargetFilter['yandex'][] = [${Object jsContent += `export const YANDEX_LANGUAGE_OBJECT: { [p in YANDEX_LIST]: string } = ${JSON.stringify(yandex)}\n` // deepl content/type -const deepl = JSON.parse(readFileSync('../assets/target/deepl.json').toString()) +const deepl = JSON.parse(readFileSync('../assets/target/deepl.json', 'utf-8')) jsContent += `export type DEEPL_LIST = ${Object.entries(deepl) .map((lang) => "'" + lang[0] + "'") .join('|')}\n` @@ -56,7 +56,7 @@ jsContent += `export const DEEPL_LANGUAGE: TargetFilter['deepl'][] = [${Object.e jsContent += `export const DEEPL_LANGUAGE_OBJECT: { [p in DEEPL_LIST]: string } = ${JSON.stringify(deepl)}\n` // baidu content/type/tts -const baidu = JSON.parse(readFileSync('../assets/target/baidu.json').toString()) +const baidu = JSON.parse(readFileSync('../assets/target/baidu.json', 'utf-8')) jsContent += `export type BAIDU_LIST = ${Object.entries(baidu) .map((lang) => "'" + lang[0] + "'") .join('|')}\n` @@ -65,11 +65,11 @@ jsContent += `export const BAIDU_LANGUAGE: TargetFilter['baidu'][] = [${Object.e .join(',')}]\n` jsContent += `export const BAIDU_LANGUAGE_OBJECT: { [p in BAIDU_LIST]: string } = ${JSON.stringify(baidu)}\n` -const baidu_tts = JSON.parse(readFileSync('../assets/target/baidu_tts.json').toString()) +const baidu_tts = JSON.parse(readFileSync('../assets/target/baidu_tts.json', 'utf-8')) jsContent += `export type BAIDU_TTS_LIST = ${baidu_tts.map((lang) => "'" + lang + "'").join('|')}\n` // sogou -const sogou = JSON.parse(readFileSync('../assets/target/sogou.json').toString()) +const sogou = JSON.parse(readFileSync('../assets/target/sogou.json', 'utf-8')) jsContent += `export type SOGOU_LIST = ${Object.entries(sogou) .map((lang) => "'" + lang[0] + "'") .join('|')}\n` @@ -80,4 +80,10 @@ jsContent += `export const SOGOU_LANGUAGE_OBJECT: { [p in SOGOU_LIST]: string } jsContent += `export type SOGOU_TTS_LIST = Exclude\n` +// watson +const watson = JSON.parse(readFileSync('../assets/target/watson.json', 'utf-8')) +jsContent += `export type WATSON_LIST = ${watson.payload.sourceLanguages.map((lang) => "'" + lang.language + "'").join('|')}\n` +jsContent += `export const WATSON_LANGUAGE: TargetFilter['watson'][] = [${watson.payload.sourceLanguages.map((lang) => "'" + lang.language + "'").join(',')}]\n` +jsContent += `export const WATSON_LANGUAGE_OBJECT: { [p in WATSON_LIST]: string } = ${JSON.stringify(Object.fromEntries(watson.payload.sourceLanguages.map((lang) => [lang.language, lang.name])))}\n` + writeFileSync('../src/language.ts', jsContent) diff --git a/src/index.browser.ts b/src/index.browser.ts index b8e737e..4714b9d 100644 --- a/src/index.browser.ts +++ b/src/index.browser.ts @@ -1,5 +1,5 @@ import { YandexBrowserTranslator } from './source/yandex.js' -import { GoogleBrowserTranslate } from './source/google.js' +import { GoogleBrowserTranslate, GoogleBrowserTranslateV2 } from './source/google.js' import { MicrosoftBrowserTranslator } from './source/microsoft.js' import { SogouBrowserTranslator } from './source/sogou.js' @@ -14,6 +14,9 @@ const Translator: TranslatorFunction = async (text = '', platform, source, targe case 'google_browser': result.content = await GoogleBrowserTranslate(text, source as GOOGLE_LIST, target as GOOGLE_LIST, !!raw, ext) break + case 'google_browser_v2': + result.content = await GoogleBrowserTranslateV2(text, source as GOOGLE_LIST, target as GOOGLE_LIST, !!raw, ext) + break case 'microsoft': case 'microsoft_browser': result.content = await MicrosoftBrowserTranslator(text, source as BING_LIST, target as BING_LIST, !!raw, ext) diff --git a/src/index.ts b/src/index.ts index 0088095..a75ef48 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,13 +1,14 @@ import { BaiduLanguagePredict, BaiduTranslator, GetBaiduTranslatorToken, BaiduTTS } from './source/baidu.js' import { DeepL } from './source/deepl.js' -import { GoogleTranslate, GoogleBrowserTranslate, GoogleTTS, GoogleTranslateTk } from './source/google.js' +import { GoogleTranslate, GoogleBrowserTranslate, GoogleBrowserTranslateV2, GoogleTTS, GoogleTranslateTk } from './source/google.js' import { MicrosoftTranslator, MicrosoftBrowserTranslator, GetMicrosoftBrowserTranslatorAuth, GetMicrosoftTranslatorToken, MicrosoftBrowserPredict, MicrosoftTTS, MicrosoftBrowserTTS } from './source/microsoft.js' import { SogouBrowserTranslator, SogouTTS } from './source/sogou.js' import { YandexDetect, YandexTranslator, YandexBrowserTranslator } from './source/yandex.js' +import { WatsonDetect, WatsonTranslator } from 'source/watson.js' import { IsChs, IsCht } from './misc.js' import type { TranslatorFunction } from 'types.js' -import type { BAIDU_LIST, BING_LIST, DEEPL_LIST, GOOGLE_LIST, SOGOU_LIST, YANDEX_LIST } from 'language.js' +import type { BAIDU_LIST, BING_LIST, DEEPL_LIST, GOOGLE_LIST, SOGOU_LIST, WATSON_LIST, YANDEX_LIST } from 'language.js' const Translator: TranslatorFunction = async (text = '', platform, source, target, raw, ext = {}) => { let result = { content: '', message: '' } @@ -19,6 +20,9 @@ const Translator: TranslatorFunction = async (text = '', platform, source, targe case 'google_browser': result.content = await GoogleBrowserTranslate(text, source as GOOGLE_LIST, target as GOOGLE_LIST, !!raw, ext) break + case 'google_browser_v2': + result.content = await GoogleBrowserTranslateV2(text, source as GOOGLE_LIST, target as GOOGLE_LIST, !!raw, ext) + break case 'microsoft': result.content = await MicrosoftTranslator(text, source as BING_LIST, target as BING_LIST, !!raw, ext) break @@ -40,6 +44,9 @@ const Translator: TranslatorFunction = async (text = '', platform, source, targe break case 'deepl': result.content = await DeepL(text, source as DEEPL_LIST, target as DEEPL_LIST, !!raw, ext) + break + case 'watson': + result.content = await WatsonTranslator(text, source as WATSON_LIST, target as WATSON_LIST, !!raw, ext) } } catch (e) { result.message = String(e) @@ -51,9 +58,12 @@ export { BaiduLanguagePredict, YandexDetect, MicrosoftBrowserPredict, + WatsonDetect, BaiduTranslator, DeepL, + WatsonTranslator, GoogleBrowserTranslate, + GoogleBrowserTranslateV2, GoogleTranslate, MicrosoftBrowserTranslator, MicrosoftTranslator, diff --git a/src/language.ts b/src/language.ts index 99de490..aaa703d 100644 --- a/src/language.ts +++ b/src/language.ts @@ -24,3 +24,6 @@ export type SOGOU_LIST = 'ar'|'pl'|'da'|'de'|'ru'|'fr'|'fi'|'ko'|'nl'|'cs'|'pt'| export const SOGOU_LANGUAGE: TargetFilter['sogou'][] = ['ar','pl','da','de','ru','fr','fi','ko','nl','cs','pt','ja','sv','th','tr','es','hu','en','it','vi','zh-CHS'] export const SOGOU_LANGUAGE_OBJECT: { [p in SOGOU_LIST]: string } = {"ar":"阿拉伯语","pl":"波兰语","da":"丹麦语","de":"德语","ru":"俄语","fr":"法语","fi":"芬兰语","ko":"韩语","nl":"荷兰语","cs":"捷克语","pt":"葡萄牙语","ja":"日语","sv":"瑞典语","th":"泰语","tr":"土耳其语","es":"西班牙语","hu":"匈牙利语","en":"英语","it":"意大利语","vi":"越南语","zh-CHS":"中文"} export type SOGOU_TTS_LIST = Exclude +export type WATSON_LIST = 'ar'|'bg'|'bn'|'bs'|'ca'|'cnr'|'cs'|'cy'|'da'|'de'|'el'|'en'|'es'|'et'|'eu'|'fi'|'fr'|'fr-CA'|'ga'|'gu'|'he'|'hi'|'hr'|'hu'|'id'|'it'|'ja'|'kn'|'ko'|'lt'|'lv'|'ml'|'mr'|'ms'|'mt'|'nb'|'ne'|'nl'|'pa'|'pl'|'pt'|'ro'|'ru'|'si'|'sk'|'sl'|'sr'|'sv'|'ta'|'te'|'th'|'tr'|'uk'|'ur'|'vi'|'zh'|'zh-TW' +export const WATSON_LANGUAGE: TargetFilter['watson'][] = ['ar','bg','bn','bs','ca','cnr','cs','cy','da','de','el','en','es','et','eu','fi','fr','fr-CA','ga','gu','he','hi','hr','hu','id','it','ja','kn','ko','lt','lv','ml','mr','ms','mt','nb','ne','nl','pa','pl','pt','ro','ru','si','sk','sl','sr','sv','ta','te','th','tr','uk','ur','vi','zh','zh-TW'] +export const WATSON_LANGUAGE_OBJECT: { [p in WATSON_LIST]: string } = {"ar":"Arabic","bg":"Bulgarian","bn":"Bengali","bs":"Bosnian","ca":"Catalan","cnr":"Montenegrin","cs":"Czech","cy":"Welsh","da":"Danish","de":"German","el":"Greek","en":"English","es":"Spanish","et":"Estonian","eu":"Basque","fi":"Finnish","fr":"French","fr-CA":"French (Canada)","ga":"Irish","gu":"Gujarati","he":"Hebrew","hi":"Hindi","hr":"Croatian","hu":"Hungarian","id":"Indonesian","it":"Italian","ja":"Japanese","kn":"Kannada","ko":"Korean","lt":"Lithuanian","lv":"Latvian","ml":"Malayalam","mr":"Marathi","ms":"Malay","mt":"Maltese","nb":"Norwegian Bokmal","ne":"Nepali","nl":"Dutch","pa":"Punjabi","pl":"Polish","pt":"Portuguese","ro":"Romanian","ru":"Russian","si":"Sinhala","sk":"Slovakian","sl":"Slovenian","sr":"Serbian","sv":"Swedish","ta":"Tamil","te":"Telugu","th":"Thai","tr":"Turkish","uk":"Ukrainian","ur":"Urdu","vi":"Vietnamese","zh":"Simplified Chinese","zh-TW":"Traditional Chinese"} diff --git a/src/source/google.ts b/src/source/google.ts index 2552479..ac7cbb5 100644 --- a/src/source/google.ts +++ b/src/source/google.ts @@ -39,7 +39,7 @@ const GoogleTranslate: TranslatorModuleFunction<'google'> = async (text = '', so break } } - resolve(raw && ext.raw_json ? JSON.parse(tmpData) : JSON.parse(JSON.parse(tmpData)[0][2])[1][0][0][5][0][0]) + resolve(raw && ext.raw_json ? JSON.parse(tmpData) : (JSON.parse(JSON.parse(tmpData)[0][2])[1][0][0][5] || []).map((content: any[]) => content[0]).join('')) }) .catch((e) => { console.log(e) @@ -130,6 +130,33 @@ const GoogleBrowserTranslate: TranslatorModuleFunction<'google_browser'> = async }) } +const GoogleBrowserTranslateV2: TranslatorModuleFunction<'google_browser'> = async (text = '', source = 'en', target, raw, ext = {}) => { + if (!text) { + return Promise.reject('Empty text #GoogleTranslate ') + } + if (source === 'auto' || !SupportedLanguage(GOOGLE_LANGUAGE, target || 'en') || !SupportedLanguage(GOOGLE_LANGUAGE, source || 'en')) { + return Promise.reject('Unsupported target language #GoogleTranslate ') + } + return new Promise(async (resolve, reject) => { + axiosFetch + .post('https://translation.googleapis.com/language/translate/v2?key=AIzaSyBOti4mM-6x9WDnZIjIeyEU21OpBXqWBgw', { + q: Array.isArray(text) ? text.join('\n') : text, + source, + target, + format: 'text' + }) + .then((response: any) => { + if (response.data && response.data?.data?.translations instanceof Array) { + resolve(raw ? response.data : response.data.data.translations.map((x: any) => x?.translatedText || '').join('\n')) + } + reject(raw ? response.data : 'Invalid content #GoogleTranslate ') + }) + .catch((e) => { + reject(raw ? e : e.toString()) + }) + }) +} + const hl = function (a: number, b: string) { let c = 0 for (; c < b.length - 2; c += 3) { @@ -214,4 +241,4 @@ const GoogleTTS: TTSModuleFunction<'google'> = async (lang = 'en', text = '', ex } } -export { GoogleTranslate, GoogleBrowserTranslate, GoogleTranslateTk, GoogleTTS } +export { GoogleTranslate, GoogleBrowserTranslate, GoogleBrowserTranslateV2, GoogleTranslateTk, GoogleTTS } diff --git a/src/source/watson.ts b/src/source/watson.ts new file mode 100644 index 0000000..393151d --- /dev/null +++ b/src/source/watson.ts @@ -0,0 +1,53 @@ +import { WATSON_LANGUAGE } from 'language.js' +import { SupportedLanguage } from 'misc.js' +import axiosFetch from 'translator-utils-axios-helper' +import { TranslatorModuleFunction } from 'types.js' + +const WatsonDetect = async (text: string | string[] = ''): Promise => { + if (!text) { + return '_' + } + if (Array.isArray(text)) { + text = text.join('\n') + } + try { + const languageResult = await axiosFetch.post('https://www.ibm.com/demos/live/watson-language-translator/api/translate/detect', { + text + }) + if (languageResult.data?.status === 'success') { + return languageResult.data?.payload?.languages?.[0]?.language?.language || '_' + } else { + return '_' + } + } catch (e) { + return '_' + } +} + +const WatsonTranslator: TranslatorModuleFunction<'watson'> = async (text = '', source = 'en', target, raw, ext = {}) => { + if (!text) { + return Promise.reject('Empty text #WatsonTranslate ') + } + if (source === 'auto' || !SupportedLanguage(WATSON_LANGUAGE, target || 'en') || !SupportedLanguage(WATSON_LANGUAGE, source || 'en')) { + return Promise.reject('Unsupported target language #WatsonTranslate ') + } + return new Promise(async (resolve, reject) => { + axiosFetch + .post('https://www.ibm.com/demos/live/watson-language-translator/api/translate/text', { + source, + target, + text: Array.isArray(text) ? text.join('\n') : text + }) + .then((response: any) => { + if (response.data && response.data?.status === 'success' && response.data?.payload?.translations instanceof Array) { + resolve(raw ? response.data : response.data.payload.translations.map((x: any) => x?.translation || '').join('\n')) + } + reject(raw ? response.data : 'Invalid content #WatsonTranslate ') + }) + .catch((e) => { + reject(raw ? e : e.toString()) + }) + }) +} + +export { WatsonDetect, WatsonTranslator } diff --git a/src/types.ts b/src/types.ts index d21ba3e..9f22758 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,4 +1,4 @@ -import type { BAIDU_LIST, BAIDU_TTS_LIST, BING_LIST, BING_TTS_LIST, MICROSOFT_EDGE_TTS_TYPE, DEEPL_LIST, GOOGLE_LIST, SOGOU_LIST, SOGOU_TTS_LIST, YANDEX_LIST } from 'language.js' +import type { BAIDU_LIST, BAIDU_TTS_LIST, BING_LIST, BING_TTS_LIST, MICROSOFT_EDGE_TTS_TYPE, DEEPL_LIST, GOOGLE_LIST, SOGOU_LIST, SOGOU_TTS_LIST, YANDEX_LIST, WATSON_LIST } from 'language.js' export type TranslatorModuleFunction

= ( text: string | string[], @@ -30,14 +30,31 @@ export type TTSResponse = { export type TTSModuleFunction

= (lang: TargetFilter[P], text: string | string[], ext?: { [p in string]: unknown }) => Promise -export type Platform = 'google' | 'google_browser' | 'microsoft' | 'microsoft_browser' | 'microsoft_tts' | 'microsoft_edge_tts' | 'sogou' | 'sogou_browser' | 'sogou_tts' | 'yandex' | 'yandex_browser' | 'baidu' | 'baidu_tts' | 'deepl' -export type BrowserPlatform = 'google_browser' | 'microsoft_browser' | 'sogou' | 'sogou_browser' | 'yandex_browser' +export type Platform = + | 'google' + | 'google_browser' + | 'google_browser_v2' + | 'microsoft' + | 'microsoft_browser' + | 'microsoft_tts' + | 'microsoft_edge_tts' + | 'sogou' + | 'sogou_browser' + | 'sogou_tts' + | 'yandex' + | 'yandex_browser' + | 'baidu' + | 'baidu_tts' + | 'deepl' + | 'watson' +export type BrowserPlatform = 'google_browser' | 'google_browser_v2' | 'microsoft_browser' | 'sogou' | 'sogou_browser' | 'yandex_browser' export type TargetFilter = { baidu: BAIDU_LIST baidu_tts: BAIDU_TTS_LIST google: GOOGLE_LIST google_browser: GOOGLE_LIST + google_browser_v2: GOOGLE_LIST deepl: DEEPL_LIST microsoft: BING_LIST microsoft_browser: BING_LIST @@ -48,4 +65,5 @@ export type TargetFilter = { sogou_tts: SOGOU_TTS_LIST yandex: YANDEX_LIST yandex_browser: YANDEX_LIST + watson: WATSON_LIST } diff --git a/tests/google.test.ts b/tests/google.test.ts index b321d6c..fad565d 100644 --- a/tests/google.test.ts +++ b/tests/google.test.ts @@ -1,5 +1,5 @@ import { expect, test, describe } from 'vitest' -import { GoogleBrowserTranslate, GoogleTranslate, GoogleTTS, GoogleTranslateTk } from '../dist/esm/index.js' +import { GoogleBrowserTranslate, GoogleBrowserTranslateV2, GoogleTranslate, GoogleTTS, GoogleTranslateTk } from '../dist/esm/index.js' test('Google TK', async () => { expect(GoogleTranslateTk('test content', [464385, 3806605782])).toEqual('531820.985965') @@ -59,6 +59,24 @@ describe('Google translate(browser)', () => { }) }) +describe('Google translate(browser v2)', () => { + test.concurrent('English', async ({ expect }) => { + expect(await GoogleBrowserTranslateV2('hello', 'en', 'zh-cn', false)).toMatch(/(你|妳|您)好/gm) + }) + test.concurrent('Japanese', async ({ expect }) => { + expect(await GoogleBrowserTranslateV2('こんにちわ', 'ja', 'zh-cn', false)).toMatch(/(你|妳|您)好/gm) + }) + test.concurrent('Simplified Chinese', async ({ expect }) => { + expect(await GoogleBrowserTranslateV2('你好', 'zh-tw', 'zh-cn', false)).toMatch(/(你|妳|您)好/gm) + }) + test.concurrent('Korean', async ({ expect }) => { + expect(await GoogleBrowserTranslateV2('안녕하세요', 'ko', 'zh-cn', false)).toMatch(/(你|妳|您)好/gm) + }) + test.concurrent('Empty text', async ({ expect }) => { + await expect(GoogleBrowserTranslateV2('', 'en', 'zh-cn', false)).rejects.toMatch('Empty text #GoogleTranslate ') + }) +}) + test('Google TTS', async () => { const googleTTS = await GoogleTTS('en', 'hi') expect(googleTTS.content_length).toBeGreaterThan(0) diff --git a/tests/watson.test.ts b/tests/watson.test.ts new file mode 100644 index 0000000..ae3ab01 --- /dev/null +++ b/tests/watson.test.ts @@ -0,0 +1,38 @@ +import { test, describe } from 'vitest' +import { WatsonDetect, WatsonTranslator } from '../dist/esm/index.js' + +describe('Watson detect', () => { + test.concurrent('English', async ({ expect }) => { + expect(await WatsonDetect('This is an English text')).toEqual('en') + }) + test.concurrent('Japanese', async ({ expect }) => { + expect(await WatsonDetect('これは日本語のテキストです')).toEqual('ja') + }) + test.concurrent('Simplified Chinese', async ({ expect }) => { + expect(await WatsonDetect('这是一段中文文本')).toEqual('zh') + }) + test.concurrent('Korean', async ({ expect }) => { + expect(await WatsonDetect('이것은 한국어로 된 텍스트입니다')).toEqual('ko') + }) + test.concurrent('Empty text', async ({ expect }) => { + expect(await WatsonDetect('')).toEqual('_') + }) +}) + +describe('Watson translate', () => { + test.concurrent('English', async ({ expect }) => { + expect(await WatsonTranslator('hello', 'en', 'zh', false)).toMatch(/(你|妳|您)好/gm) + }) + test.concurrent('Japanese', async ({ expect }) => { + expect(await WatsonTranslator('こんにちわ', 'ja', 'zh', false)).toMatch(/(早上|你|妳|您)好/gm) + }) + test.concurrent('Simplified Chinese', async ({ expect }) => { + expect(await WatsonTranslator('你好', 'zh-TW', 'zh', false)).toMatch(/(你|妳|您)好/gm) + }) + test.concurrent('Korean', async ({ expect }) => { + expect(await WatsonTranslator('안녕하세요', 'ko', 'zh', false)).toMatch(/(早上|你|妳|您)好/gm) + }) + test.concurrent('Empty text', async ({ expect }) => { + await expect(WatsonTranslator('', 'en', 'zh', false)).rejects.toMatch('Empty text #WatsonTranslate ') + }) +})