2020-03-26 19:41:21 +08:00
# include "qtcommon.h"
# include "extension.h"
# include "network.h"
# include <random>
extern const wchar_t * TRANSLATION_ERROR ;
extern const char * USE_PREV_SENTENCE_CONTEXT ;
2020-03-30 10:55:12 +08:00
extern Synchronized < std : : wstring > translateTo , apiKey ;
2020-03-26 19:41:21 +08:00
const char * TRANSLATION_PROVIDER = " DeepL Translate " ;
2020-03-30 10:55:12 +08:00
const char * GET_API_KEY_FROM = " https://www.deepl.com/pro.html " ;
2020-03-26 19:41:21 +08:00
QStringList languages
{
2020-03-27 18:07:05 +08:00
" Chinese (simplified): ZH " ,
2020-03-26 19:41:21 +08:00
" Dutch: NL " ,
" English: EN " ,
" French: FR " ,
" German: DE " ,
" Italian: IT " ,
" Japanese: JA " ,
" Polish: PL " ,
" Portuguese: PT " ,
" Russian: RU " ,
" Spanish: ES " ,
} ;
2020-03-27 18:07:05 +08:00
bool translateSelectedOnly = true , rateLimitAll = true , rateLimitSelected = true , useCache = false ;
2020-03-30 10:55:12 +08:00
int tokenCount = 10 , tokenRestoreDelay = 60000 , maxSentenceSize = 500 ;
2020-03-27 18:07:05 +08:00
2020-03-26 19:41:21 +08:00
const wchar_t * accept [ ] = { L " */* " , nullptr } ;
Synchronized < std : : wstring > LMTBID ;
std : : pair < bool , std : : wstring > Translate ( const std : : wstring & text , SentenceInfo sentenceInfo )
{
2020-03-30 10:55:12 +08:00
if ( ! apiKey - > empty ( ) )
if ( HttpRequest httpRequest {
L " Mozilla/5.0 Textractor " ,
L " api.deepl.com " ,
L " POST " ,
L " /v2/translate " ,
FormatString ( " text=%S&auth_key=%S&target_lang=%S " , Escape ( text ) , apiKey . Copy ( ) , translateTo . Copy ( ) ) ,
L " Content-Type: application/x-www-form-urlencoded "
} )
// Response formatted as JSON: translation starts with text":" and ends with "}]
if ( std : : wsmatch results ; std : : regex_search ( httpRequest . response , results , std : : wregex ( L " text \" : \" (.+?) \" \\ } \\ ] " ) ) ) return { true , results [ 1 ] } ;
else return { false , FormatString ( L " %s: %s " , TRANSLATION_ERROR , httpRequest . response ) } ;
else return { false , FormatString ( L " %s (code=%u) " , TRANSLATION_ERROR , httpRequest . errorCode ) } ;
2020-03-26 19:41:21 +08: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
2020-03-30 10:55:12 +08:00
int64_t r = _time64 ( nullptr ) , n = std : : count ( text . begin ( ) , text . end ( ) , L ' i ' ) + 1 ;
int id = 10000 * std : : uniform_int_distribution ( 0 , 9999 ) ( std : : mt19937 ( std : : random_device ( ) ( ) ) ) ;
// user_preferred_langs? what should priority be? does timestamp do anything? other translation quality options?
2020-03-26 19:41:21 +08:00
auto body = FormatString ( R " (
{
" id " : % d ,
" jsonrpc " : " 2.0 " ,
" method " : " LMT_handle_jobs " ,
" params " : {
" priority " : - 1 ,
" timestamp " : % lld ,
" lang " : {
2020-03-30 10:55:12 +08:00
" target_lang " : " %S " ,
" source_lang_user_selected " : " auto "
2020-03-26 19:41:21 +08:00
} ,
" jobs " : [ {
2020-03-30 10:55:12 +08:00
" raw_en_sentence " : " %s " ,
" raw_en_context_before " : [ ] ,
2020-03-26 19:41:21 +08:00
" kind " : " default " ,
2020-03-30 10:55:12 +08:00
" preferred_num_beams " : 1 ,
2020-03-26 19:41:21 +08:00
" quality " : " fast " ,
2020-03-30 10:55:12 +08:00
" raw_en_context_after " : [ ]
2020-03-26 19:41:21 +08:00
} ]
}
}
2020-03-30 10:55:12 +08:00
) " , ++id, r + (n - r % n), translateTo.Copy(), JSON::Escape(text));
2020-03-27 18:07:05 +08:00
// missing accept-encoding header since it fucks up HttpRequest
2020-03-30 10:55:12 +08:00
std : : wstring headers = L " Host: www2.deepl.com \r \n Accept-Language: en-US,en;q=0.5 \r \n Content-type: text/plain; charset=utf-8 \r \n Origin: https://www.deepl.com \r \n TE: Trailers " + LMTBID . Acquire ( ) . contents ;
2020-03-26 19:41:21 +08:00
if ( HttpRequest httpRequest {
L " Mozilla/5.0 Textractor " ,
L " www2.deepl.com " ,
L " POST " ,
L " /jsonrpc " ,
2020-03-30 10:55:12 +08:00
body ,
headers . c_str ( ) ,
L " https://www.deepl.com/translator " ,
2020-03-26 19:41:21 +08:00
WINHTTP_FLAG_SECURE ,
NULL ,
2020-03-30 10:55:12 +08:00
accept
2020-03-26 19:41:21 +08:00
} )
{
// Response formatted as JSON: translation starts with preprocessed_sentence":" and ends with ","
if ( std : : wsmatch results ; std : : regex_search ( httpRequest . response , results , std : : wregex ( L " postprocessed_sentence \" : \" (.+?) \" , \" " ) ) ) return { true , results [ 1 ] } ;
else return { false , FormatString ( L " %s: %s " , TRANSLATION_ERROR , httpRequest . response ) } ;
}
else return { false , FormatString ( L " %s (code=%u) " , TRANSLATION_ERROR , httpRequest . errorCode ) } ;
}