import GoogleLanguages from "./google.json" ; import { createStorageHelper , ProxyRequestInit } from "../extension" ; import { isTranslationError , ITranslationResult , TranslateParams , Translator } from "./translator" ; import { createLogger , delay } from "../utils" ; class Google extends Translator { public name = 'google' ; public title = 'Google' ; public apiUrl = 'https://translate.googleapis.com' ; public publicUrl = 'https://translate.google.com' ; public ttsMaxLength = 187 ; protected logger = createLogger ( { systemPrefix : "[GOOGLE]" } ) ; protected apiClients = [ "gtx" , "dict-chrome-ex" ] ; protected apiClient = createStorageHelper < string > ( "google_api_client" , { defaultValue : this . apiClients [ 0 ] , } ) ; constructor ( ) { super ( GoogleLanguages ) ; } getFullPageTranslationUrl ( pageUrl , lang ) { return `https://translate.google.com/translate?tl=${ lang }&u=${ pageUrl }` ; } protected async refreshApiClient ( ) { await delay ( 1000 ) ; var apiClient = this . apiClient . get ( ) ; var index = this . apiClients . findIndex ( client => client === apiClient ) ; var nextApiClient = this . apiClients [ index + 1 ] ?? this . apiClients [ 0 ] ; this . apiClient . set ( nextApiClient ) ; this . logger . info ( "api client refreshed" , { oldValue : apiClient , newValue : nextApiClient , } ) ; } getAudioUrl ( lang , text ) { if ( text . length > this . ttsMaxLength ) return ; var textEncoded = encodeURIComponent ( text ) ; var apiClient = this . apiClient . get ( ) ; return this . apiUrl + `/translate_tts?client=${ apiClient }&ie=UTF-8&tl=${ lang }&q=${ textEncoded }` ; } async translate ( params ) { var { from : langFrom , to : langTo , text } = params ; var apiClientRefreshed = false ; var requestInit = { method : "POST" , headers : { "Content-type" : "application/x-www-form-urlencoded" } , body : new URLSearchParams ( [ [ "client" , this . apiClient . get ( ) ] , [ "source" , "input" ] , [ "dj" , "1" ] , [ "q" , text ] , [ "sl" , langFrom ] , [ "tl" , langTo ] , [ "hl" , langTo ] , [ "dt" , "t" ] , [ "dt" , "bd" ] , [ "dt" , "rm" ] , [ "dt" , "rw" ] , [ "dt" , "qca" ] , ] ) . toString ( ) , } ; var request = async ( ) : Promise < ITranslationResult > => { var url = `${ this . apiUrl }/translate_a/single` ; var result = await this . request ( { url , requestInit } ) ; var { src , ld_result , sentences , dict , spell } = result ; var detectedLang = src || ld_result ? ld_result . srclangs [ 0 ] : "" ; var translation = { langDetected : detectedLang , translation : sentences . map ( sentence => sentence . trans ) . join ( '' ) , } ; if ( spell ) { translation . spellCorrection = spell . spell_res ; } if ( dict ) { translation . transcription = sentences [ sentences . length - 1 ] . src_translit ; translation . dictionary = dict . map ( dict => { return { wordType : dict . pos , meanings : dict . entry . map ( entry => { return { word : entry . word , translation : entry . reverse_translation , } ; } ) } ; } ) ; } return translation ; } ; try { return await request ( ) ; } catch ( error ) { if ( isTranslationError ( error ) ) { if ( error . statusCode === 503 && ! apiClientRefreshed ) { apiClientRefreshed = true ; return this . refreshApiClient ( ) . then ( request ) ; } } if ( error ) this . logger . error ( error ) ; throw error ; } } } interface GoogleTranslation { src : string ; sentences : { orig : string ; trans : string ; } [ ] & [ { translit : string ; src_translit ? : string ; } ] ; dict ? : { pos : string ; base_form : string ; terms : string [ ] ; entry : { score : number ; word : string ; reverse_translation : string [ ] ; } [ ] ; } [ ] ; spell ? : { spell_res : string ; spell_html_res : string ; } ; alternative_translations ? : { src_phrase : string ; raw_src_segment : string ; start_pos : number ; end_pos : number ; alternative : { word_postproc : string ; score : number ; } [ ] ; } [ ] ; ld_result : { extended_srclangs : string [ ] ; srclangs : string [ ] ; } ; definitions ? : { pos : string ; base_form : string ; entry : { gloss : string ; example : string ; definition_id : string ; } [ ] ; } [ ] ; synsets ? : { pos : string ; base_form : string ; entry : { synonym : string [ ] ; definition_id : string ; } [ ] ; } [ ] ; examples ? : { example : { text : string ; definition_id : string ; } [ ] ; } ; related_words ? : { word : string [ ] ; } ; } const google = new Google ( ) ; Translator . vendors . set ( google . name , google ) ;