2020-03-26 05:41:21 -06: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-29 20:55:12 -06:00
extern Synchronized < std : : wstring > translateTo , apiKey ;
2020-03-26 05:41:21 -06:00
const char * TRANSLATION_PROVIDER = " DeepL Translate " ;
2020-03-29 20:55:12 -06:00
const char * GET_API_KEY_FROM = " https://www.deepl.com/pro.html " ;
2020-03-26 05:41:21 -06:00
QStringList languages
{
2020-03-27 04:07:05 -06:00
" Chinese (simplified): ZH " ,
2020-03-26 05:41:21 -06:00
" Dutch: NL " ,
" English: EN " ,
" French: FR " ,
" German: DE " ,
" Italian: IT " ,
" Japanese: JA " ,
" Polish: PL " ,
" Portuguese: PT " ,
" Russian: RU " ,
" Spanish: ES " ,
} ;
2020-04-25 20:39:12 -06:00
bool translateSelectedOnly = true , rateLimitAll = true , rateLimitSelected = true , useCache = true ;
2020-03-29 20:55:12 -06:00
int tokenCount = 10 , tokenRestoreDelay = 60000 , maxSentenceSize = 500 ;
2020-03-27 04:07:05 -06:00
2020-08-12 01:42:24 -06:00
enum KeyType { CAT , REST } ;
int keyType = CAT ;
2020-03-26 05:41:21 -06:00
2020-04-25 20:39:12 -06:00
std : : pair < bool , std : : wstring > Translate ( const std : : wstring & text )
2020-03-26 05:41:21 -06:00
{
2020-03-29 20:55:12 -06:00
if ( ! apiKey - > empty ( ) )
if ( HttpRequest httpRequest {
L " Mozilla/5.0 Textractor " ,
L " api.deepl.com " ,
L " POST " ,
2020-08-12 01:42:24 -06:00
keyType = = CAT ? L " /v1/translate " : L " /v2/translate " ,
2020-03-29 20:55:12 -06:00
FormatString ( " text=%S&auth_key=%S&target_lang=%S " , Escape ( text ) , apiKey . Copy ( ) , translateTo . Copy ( ) ) ,
L " Content-Type: application/x-www-form-urlencoded "
2020-08-12 01:42:24 -06:00
} ; httpRequest & & ( ! httpRequest . response . empty ( ) | | ( httpRequest = HttpRequest {
L " Mozilla/5.0 Textractor " ,
L " api.deepl.com " ,
L " POST " ,
( keyType = ! keyType ) = = CAT ? L " /v1/translate " : 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 "
} ) ) )
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 ) } ;
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
2020-03-29 20:55:12 -06:00
int64_t r = _time64 ( nullptr ) , n = std : : count ( text . begin ( ) , text . end ( ) , L ' i ' ) + 1 ;
2020-10-13 20:19:53 -06:00
thread_local auto generator = std : : mt19937 ( std : : random_device ( ) ( ) ) ;
2020-12-14 06:26:01 -07:00
int id = 10000 * std : : uniform_int_distribution ( 0 , 9999 ) ( generator ) + 1 ;
2020-03-29 20:55:12 -06:00
// 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 " : {
2020-03-29 20:55:12 -06:00
" target_lang " : " %S " ,
" source_lang_user_selected " : " auto "
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
} ]
}
}
2020-12-14 06:26:01 -07:00
) " , id, r + (n - r % n), translateTo.Copy(), 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 " ,
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 ) } ;
}