2020-03-26 05:41:21 -06:00
# include "qtcommon.h"
2021-06-28 22:24:59 -06:00
# include "translatewrapper.h"
2020-03-26 05:41:21 -06:00
# include "network.h"
# include <random>
extern const wchar_t * TRANSLATION_ERROR ;
const char * TRANSLATION_PROVIDER = " DeepL Translate " ;
2021-08-17 22:48:16 -06:00
const char * GET_API_KEY_FROM = " https://www.deepl.com/pro.html#developer " ;
2021-06-28 22:24:59 -06:00
extern const QStringList languagesTo
{
" Bulgarian " ,
" Chinese (Simplified) " ,
" Czech " ,
" Danish " ,
" Dutch " ,
" English (American) " ,
" English (British) " ,
" Estonian " ,
" Finnish " ,
" French " ,
" German " ,
" Greek " ,
" Hungarian " ,
" Italian " ,
" Japanese " ,
" Latvian " ,
" Lithuanian " ,
" Polish " ,
" Portuguese (Brazil) " ,
" Portuguese (Portugal) " ,
" Romanian " ,
" Russian " ,
" Slovak " ,
" Slovenian " ,
" Spanish " ,
" Swedish "
} ,
languagesFrom
{
" Bulgarian " ,
" Chinese " ,
" Czech " ,
" Danish " ,
" Dutch " ,
" English " ,
" Estonian " ,
" Finnish " ,
" French " ,
" German " ,
" Greek " ,
" Hungarian " ,
" Italian " ,
" Japanese " ,
" Latvian " ,
" Lithuanian " ,
" Polish " ,
" Portuguese " ,
" Romanian " ,
" Russian " ,
" Slovak " ,
" Slovenian " ,
" Spanish " ,
" Swedish "
} ;
extern const std : : unordered_map < std : : wstring , std : : wstring > codes
2020-03-26 05:41:21 -06:00
{
2021-06-28 22:24:59 -06:00
{ { L " Bulgarian " } , { L " BG " } } ,
{ { L " Chinese " } , { L " ZH " } } ,
{ { L " Chinese (Simplified) " } , { L " ZH " } } ,
{ { L " Czech " } , { L " CS " } } ,
{ { L " Danish " } , { L " DA " } } ,
{ { L " Dutch " } , { L " NL " } } ,
{ { L " English " } , { L " EN " } } ,
{ { L " English (American) " } , { L " EN-US " } } ,
{ { L " English (British) " } , { L " EN-GB " } } ,
{ { L " Estonian " } , { L " ET " } } ,
{ { L " Finnish " } , { L " FI " } } ,
{ { L " French " } , { L " FR " } } ,
{ { L " German " } , { L " DE " } } ,
{ { L " Greek " } , { L " EL " } } ,
{ { L " Hungarian " } , { L " HU " } } ,
{ { L " Italian " } , { L " IT " } } ,
{ { L " Japanese " } , { L " JA " } } ,
{ { L " Latvian " } , { L " LV " } } ,
{ { L " Lithuanian " } , { L " LT " } } ,
{ { L " Polish " } , { L " PL " } } ,
{ { L " Portuguese " } , { L " PT " } } ,
{ { L " Portuguese (Brazil) " } , { L " PT-BR " } } ,
{ { L " Portuguese (Portugal) " } , { L " PT-PT " } } ,
{ { L " Romanian " } , { L " RO " } } ,
{ { L " Russian " } , { L " RU " } } ,
{ { L " Slovak " } , { L " SK " } } ,
{ { L " Slovenian " } , { L " SL " } } ,
{ { L " Spanish " } , { L " ES " } } ,
{ { L " Swedish " } , { L " SV " } } ,
{ { L " ? " } , { L " auto " } }
2020-03-26 05:41:21 -06:00
} ;
2021-08-17 22:48:16 -06:00
bool translateSelectedOnly = true , useRateLimiter = true , rateLimitSelected = true , useCache = true , useFilter = true ;
2021-06-30 17:52:52 -06:00
int tokenCount = 10 , rateLimitTimespan = 60000 , maxSentenceSize = 1000 ;
2020-03-27 04:07:05 -06:00
2020-08-12 01:42:24 -06:00
enum KeyType { CAT , REST } ;
2021-06-05 08:25:46 -06:00
int keyType = REST ;
2020-03-26 05:41:21 -06:00
2021-06-28 22:24:59 -06:00
std : : pair < bool , std : : wstring > Translate ( const std : : wstring & text , TranslationParam tlp )
2020-03-26 05:41:21 -06:00
{
2021-06-28 22:24:59 -06:00
if ( ! tlp . authKey . empty ( ) )
2021-01-21 07:07:09 -07:00
{
2021-06-28 22:24:59 -06:00
std : : string translateFromComponent = tlp . translateFrom = = L " ? " ? " " : " &source_lang= " + WideStringToString ( codes . at ( tlp . translateFrom ) ) ;
2020-03-29 20:55:12 -06:00
if ( HttpRequest httpRequest {
L " Mozilla/5.0 Textractor " ,
2021-06-28 22:24:59 -06:00
tlp . authKey . find ( L " :fx " ) = = std : : string : : npos ? L " api.deepl.com " : L " api-free.deepl.com " ,
2020-03-29 20:55:12 -06:00
L " POST " ,
2020-08-12 01:42:24 -06:00
keyType = = CAT ? L " /v1/translate " : L " /v2/translate " ,
2021-06-28 22:24:59 -06:00
FormatString ( " text=%S&auth_key=%S&target_lang=%S " , Escape ( text ) , tlp . authKey , codes . at ( tlp . translateTo ) ) + translateFromComponent ,
2020-03-29 20:55:12 -06:00
L " Content-Type: application/x-www-form-urlencoded "
2021-06-28 22:24:59 -06:00
} ; httpRequest & & ( httpRequest . response . find ( L " translations " ) ! = std : : string : : npos | | ( httpRequest = HttpRequest {
2020-08-12 01:42:24 -06:00
L " Mozilla/5.0 Textractor " ,
2021-06-28 22:24:59 -06:00
tlp . authKey . find ( L " :fx " ) = = std : : string : : npos ? L " api.deepl.com " : L " api-free.deepl.com " ,
2020-08-12 01:42:24 -06:00
L " POST " ,
( keyType = ! keyType ) = = CAT ? L " /v1/translate " : L " /v2/translate " ,
2021-06-28 22:24:59 -06:00
FormatString ( " text=%S&auth_key=%S&target_lang=%S " , Escape ( text ) , tlp . authKey , codes . at ( tlp . translateTo ) ) + translateFromComponent ,
2021-06-05 08:25:46 -06:00
L " Content-Type: application/x-www-form-urlencoded "
2020-08-12 01:42:24 -06:00
} ) ) )
2020-03-29 20:55:12 -06:00
// Response formatted as JSON: translation starts with text":" and ends with "}]
2020-12-14 06:26:01 -07:00
if ( auto translation = Copy ( JSON : : Parse ( httpRequest . response ) [ L " translations " ] [ 0 ] [ L " text " ] . String ( ) ) ) return { true , translation . value ( ) } ;
2020-03-29 20:55:12 -06:00
else return { false , FormatString ( L " %s: %s " , TRANSLATION_ERROR , httpRequest . response ) } ;
else return { false , FormatString ( L " %s (code=%u) " , TRANSLATION_ERROR , httpRequest . errorCode ) } ;
2021-01-21 07:07:09 -07:00
}
2020-03-29 20:55:12 -06:00
2020-03-26 05:41:21 -06:00
// the following code was reverse engineered from the DeepL website; it's as close as I could make it but I'm not sure what parts of this could be removed and still have it work
2021-07-01 23:50:47 -06:00
int id = 10000 * std : : uniform_int_distribution ( 0 , 9999 ) ( std : : random_device ( ) ) + 1 ;
2020-03-29 20:55:12 -06:00
int64_t r = _time64 ( nullptr ) , n = std : : count ( text . begin ( ) , text . end ( ) , L ' i ' ) + 1 ;
// user_preferred_langs? what should priority be? does timestamp do anything? other translation quality options?
2020-03-26 05:41:21 -06:00
auto body = FormatString ( R " (
{
" id " : % d ,
" jsonrpc " : " 2.0 " ,
" method " : " LMT_handle_jobs " ,
" params " : {
" priority " : - 1 ,
" timestamp " : % lld ,
" lang " : {
2021-06-28 22:24:59 -06:00
" target_lang " : " %.2S " ,
2021-01-21 07:07:09 -07:00
" source_lang_user_selected " : " %S "
2020-03-26 05:41:21 -06:00
} ,
" jobs " : [ {
2020-03-29 20:55:12 -06:00
" raw_en_sentence " : " %s " ,
" raw_en_context_before " : [ ] ,
2020-03-26 05:41:21 -06:00
" kind " : " default " ,
2020-03-29 20:55:12 -06:00
" preferred_num_beams " : 1 ,
2020-03-26 05:41:21 -06:00
" quality " : " fast " ,
2020-03-29 20:55:12 -06:00
" raw_en_context_after " : [ ]
2020-03-26 05:41:21 -06:00
} ]
}
}
2021-06-28 22:24:59 -06:00
) " , id, r + (n - r % n), codes.at(tlp.translateTo), codes.at(tlp.translateFrom), JSON::Escape(WideStringToString(text)));
2020-03-27 04:07:05 -06:00
// missing accept-encoding header since it fucks up HttpRequest
2020-03-26 05:41:21 -06:00
if ( HttpRequest httpRequest {
L " Mozilla/5.0 Textractor " ,
L " www2.deepl.com " ,
L " POST " ,
L " /jsonrpc " ,
2020-03-29 20:55:12 -06:00
body ,
2020-10-13 20:19:53 -06:00
L " Host: www2.deepl.com \r \n Accept-Language: en-US,en;q=0.5 \r \n Content-type: application/json; charset=utf-8 \r \n Origin: https://www.deepl.com \r \n TE: Trailers " ,
2021-01-15 06:07:23 -07:00
INTERNET_DEFAULT_PORT ,
2020-03-29 20:55:12 -06:00
L " https://www.deepl.com/translator " ,
2020-08-12 01:42:24 -06:00
WINHTTP_FLAG_SECURE
2020-03-26 05:41:21 -06:00
} )
2020-12-14 06:26:01 -07:00
if ( auto translation = Copy ( JSON : : Parse ( httpRequest . response ) [ L " result " ] [ L " translations " ] [ 0 ] [ L " beams " ] [ 0 ] [ L " postprocessed_sentence " ] . String ( ) ) ) return { true , translation . value ( ) } ;
2020-03-26 05:41:21 -06:00
else return { false , FormatString ( L " %s: %s " , TRANSLATION_ERROR , httpRequest . response ) } ;
else return { false , FormatString ( L " %s (code=%u) " , TRANSLATION_ERROR , httpRequest . errorCode ) } ;
}