[v2] GoogleTranslate /_/TranslateWebserverUi

Post your working scripts, libraries and tools.
MrDoge
Posts: 161
Joined: 27 Apr 2020, 21:29

[v2] GoogleTranslate /_/TranslateWebserverUi

Post by MrDoge » 05 Feb 2023, 17:59

motivation:
viewtopic.php?f=6&t=63835 incorrectly detects 門 as Chinese Simplified, it uses url path: /translate_a/single
there's another url path of translate.google.com which detects this correctly: /_/TranslateWebserverUi
it is the same url path that the website https://translate.google.com/ uses, which also detects it correctly: Chinese (Traditional)

Code: Select all

MsgBox JSON_stringify(GoogleTranslate("hello world", "zh-CH")) ;{"fromLanguage": "en","text": "你好世界"}
MsgBox JSON_stringify(GoogleTranslate("门", "zh-TW")) ;{"fromLanguage": "zh-CN","text": "門"}
; good luck finding out what 门 means

GoogleTranslate(text, languageTo:="en", languageFrom:="auto") {
    if (!GoogleTranslate.HasOwnProp("extracted")) {
        hObject:=ComObject("WinHttp.WinHttpRequest.5.1")
        hObject.Open("GET","https://translate.google.com")
        hObject.SetRequestHeader("User-Agent", "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)")
        hObject.Send()
        lol:=hObject.ResponseText

        pos_FdrFJe := InStr(lol, "FdrFJe", true)
        pos_quote_FdrFJe := InStr(lol, "`"", true, pos_FdrFJe + 9)
        value_FdrFJe := SubStr(lol, pos_FdrFJe + 9, pos_quote_FdrFJe - (pos_FdrFJe + 9))

        pos_cfb2h := InStr(lol, "cfb2h", true)
        pos_quote_cfb2h := InStr(lol, "`"", true, pos_cfb2h + 8)
        value_cfb2h := SubStr(lol, pos_cfb2h + 8, pos_quote_cfb2h - (pos_cfb2h + 8))
        GoogleTranslate.extracted:={ FdrFJe: value_FdrFJe, cfb2h: value_cfb2h }
    }

    hObject:=ComObject("WinHttp.WinHttpRequest.5.1")
    hObject.Open("POST","https://translate.google.com/_/TranslateWebserverUi/data/batchexecute?rpcids=MkEWBc&source-path=%2F&f.sid=" GoogleTranslate.extracted.FdrFJe "&bl=" GoogleTranslate.extracted.cfb2h "&hl=en-US&soc-app=1&soc-platform=1&soc-device=1&_reqid=" Random(1000,9999) "&rt=c")
    hObject.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8")
    hObject.Send("f.req=" encodeURIComponent(JSON_stringify([[["MkEWBc",JSON_stringify([[text, languageFrom, languageTo, {Base:{__Class:"JSON_false"}}], [{Base:{__Class:"JSON_null"}}]]), {Base:{__Class:"JSON_null"}}, 'generic']]])))
    lol:=hObject.ResponseText

    pos_newline := InStr(lol,"`n",true,8)
    fwef:=SubStr(lol,7,pos_newline - 7)
    size := Integer(SubStr(lol,7,pos_newline - 7)) - 2
    jsonTemp := JSON_parse(SubStr(lol,pos_newline+1,size))
    json := JSON_parse(jsonTemp[1][3])

    if (type(json[1][2])=="JSON_null" || type(json[1][2][1])=="JSON_null") {
        fromText:=false
    } else {
        fromText:=json[1][2][1][5]
    }
    ;fromText is the autocorrected
    return {text:json[2][1][1][6][1][1],fromLanguage:json[3],fromText:fromText}
}

JSON_parse(str) {

    c_:=1

    return JSON_value()

    JSON_value() {

        char_:=SubStr(str, c_, 1)
        Switch char_ {
            case "{":
                obj_:=Map()
                ;object
                c_++
                loop {
                    skip_s()
                    if (SubStr(str, c_, 1) == "}") {
                        c_++
                        return obj_
                    }

                    ; key_:=JSON_objKey()
                    ; a or "a"
                    if (SubStr(str, c_, 1) == "`"") {
                        RegExMatch(str, "(?:\\.|.)*?(?=`")", &OutputVar, c_ + 1)
                        key_:=StrReplace(StrReplace(StrReplace(StrReplace(StrReplace(StrReplace(StrReplace(OutputVar.0, "\`"", "`"", true), "\f", "`f", true), "\r", "`r", true), "\n", "`n", true), "\b", "`b", true), "\t", "`t", true), "\\", "\", true)
                        c_+=OutputVar.Len
                    } else {
                        RegExMatch(str, ".*?(?=[\s:])", &OutputVar, c_)
                        key_:=OutputVar.0
                        c_+=OutputVar.Len
                    }

                    c_:=InStr(str, ":", true, c_) + 1
                    skip_s()

                    value_:=JSON_value()
                    obj_[key_]:=value_
                    obj_.DefineProp(key_, {Value: value_})

                    skip_s()
                    if (SubStr(str, c_, 1) == ",") {
                        c_++, skip_s()
                    }
                }
            case "[":
                arr_:=[]
                ;array
                c_++
                loop {
                    skip_s()
                    if (SubStr(str, c_, 1) == "]") {
                        c_++
                        return arr_
                    }

                    value_:=JSON_value()
                    arr_.Push(value_)

                    skip_s()
                    char_:=SubStr(str, c_, 1)
                    if (char_ == ",") {
                        c_++, skip_s()
                    }
                }
            case "`"":
                RegExMatch(str, "(?:\\.|.)*?(?=`")", &OutputVar, c_ + 1)
                unquoted:=StrReplace(StrReplace(StrReplace(StrReplace(StrReplace(StrReplace(StrReplace(OutputVar.0, "\`"", "`"", true), "\f", "`f", true), "\r", "`r", true), "\n", "`n", true), "\b", "`b", true), "\t", "`t", true), "\\", "\", true)
                c_+=OutputVar.Len + 2
                return unquoted
            case "-", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9":
                ; -100
                ; 100.0
                ; 1.0E+2
                ; 1E-2
                RegExMatch(str, "[0-9.eE\-+]*", &OutputVar, c_)
                c_+=OutputVar.Len
                return Number(OutputVar.0)
            case "t":
                ;"true"
                c_+=4
                return {Base:{__Class:"JSON_true"}}
            case "f":
                ;"false"
                c_+=5
                return {Base:{__Class:"JSON_false"}}
            case "n":
                ;"null"
                c_+=4
                return {Base:{__Class:"JSON_null"}}

        }
    }

    skip_s() {
        RegExMatch(str, "\s*", &OutputVar, c_)
        c_+=OutputVar.Len
    }
}

JSON_stringify(obj, maxDepth := 5) {

    stringified := ""

    escape(str) {
        str:=StrReplace(str, "\", "\\", true)
        str:=StrReplace(str, "`t", "\t", true)
        str:=StrReplace(str, "`b", "\b", true)
        str:=StrReplace(str, "`n", "\n", true)
        str:=StrReplace(str, "`r", "\r", true)
        str:=StrReplace(str, "`f", "\f", true)
        str:=StrReplace(str, "`"", "\`"", true)
        return str
    }
    ok(obj, depth) {
        switch (Type(obj)) {
            case 'Map':
                if (depth > maxDepth) {
                    stringified.="`"[DEEP ...Map]`""
                } else {
                    stringified.="{"
                    for k, v in obj {
                        (A_Index > 1 && stringified.=",")
                        stringified.="`"" escape(k) "`": "
                        ok(v, depth+1)
                    }
                    stringified.="}"
                }
            case 'Object':
                if (depth > maxDepth) {
                    stringified.="`"[DEEP ...Object]`""
                } else {
                    stringified.="{"
                    for k, v in obj.OwnProps() {
                        (A_Index > 1 && stringified.=",")
                        stringified.="`"" escape(k) "`": "
                        ok(v, depth+1)
                    }
                    stringified.="}"
                }
            case 'Array':
                if (depth > maxDepth) {
                    stringified.="`"[DEEP ...Array]`""
                } else {
                    stringified.="["
                    for v in obj {
                        (A_Index > 1 && stringified.=",")
                        ok(v, depth+1)
                    }
                    stringified.="]"
                }
            case 'String':
                stringified.="`"" escape(obj) "`"" ;in order to escape \n and etc
            case "Integer", "Float":
                stringified.=obj
            case "JSON_true":
                stringified.="true"
            case "JSON_false":
                stringified.="false"
            case "JSON_null":
                stringified.="null"
        }

    }
    ok(obj, 0)

    return stringified

}

encodeURIComponent(str) {
    static arr:=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"!",0,0,0,0,0,"'","(",")","*",0,0,"-",".",0,"0","1","2","3","4","5","6","7","8","9",0,0,0,0,0,0,0,"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z",0,0,0,0,"_",0,"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z",0,0,0,"~",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,]

    size:=StrPut(str, "UTF-8")
    buf := Buffer(size)
    StrPut(str, buf, "UTF-8")

    i_ := 0
    sizeMinusOne := size - 1
    finalStr:=""

    while (i_ < sizeMinusOne) {
        uChar:=NumGet(buf, i_, "UChar")
        if (type(arr[uChar + 1])=="String") { ;I REALLY don't know how to get : "0"!==0 -> to give me false
            finalStr.=arr[uChar + 1]
        } else {
            finalStr.="%" Format("{:02X}",uChar)
        }
        ++i_
    }

    return finalStr
}

Exitapp

f3::Exitapp
edit: added autocorrect, use it to correct dia to día for example
fromText is the autocorrected

User avatar
andymbody
Posts: 906
Joined: 02 Jul 2017, 23:47

Re: [v2] GoogleTranslate /_/TranslateWebserverUi

Post by andymbody » Yesterday, 20:53

Hello @MrDoge ... thank you for this! It is really excellent!

I can get this to work as long as the translation has only one possible response. But when there are multiple translation possibilities, it fails with the following:

Error: This value of type "JSON_null" has no property named "__Item".
on line 41
translation error 1.ahk.png
translation error 1.ahk.png (4.63 KiB) Viewed 213 times

One example that causes the error... but many more also cause the error and the commonality is multiple possible translations.

Code: Select all

MsgBox JSON_stringify(GoogleTranslate("dog", "it"))

I know virtually nothing about Json, so trying to sort out the array/object parts to overcome this error has been unsuccessful. Are you able to assist with fixing this error and allowing multiple responses to be successful?

Thanks!
Andy

Google translate showing multiple possibilities
Translate error.png
Translate error.png (9.73 KiB) Viewed 221 times

MrDoge
Posts: 161
Joined: 27 Apr 2020, 21:29

Re: [v2] GoogleTranslate /_/TranslateWebserverUi

Post by MrDoge » Yesterday, 21:50

json[2][1][1][1]=="cagna"
json[2][1][1][3]=="(feminine)"
json[2][1][2][1]=="cane"
json[2][1][2][3]=="(masculine)"

you can debug the json by putting
A_Clipboard:=JSON_stringify(json,100)
after the line:
json := JSON_parse(jsonTemp[1][3])
and setting a breakpoint in vscode to stop execution

Code: Select all

MsgBox JSON_stringify(GoogleTranslate("dog", "it")) ;{"fromLanguage": "en","phoneticNotation": "dôɡ","translation": ["cagna","cane"]}

GoogleTranslate(text, languageTo:="en", languageFrom:="auto") {
    if (!GoogleTranslate.HasOwnProp("extracted")) {
        hObject:=ComObject("WinHttp.WinHttpRequest.5.1")
        hObject.Open("GET","https://translate.google.com")
        hObject.SetRequestHeader("User-Agent", "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)")
        hObject.Send()
        lol:=hObject.ResponseText

        pos_FdrFJe := InStr(lol, "FdrFJe", true)
        pos_quote_FdrFJe := InStr(lol, "`"", true, pos_FdrFJe + 9)
        value_FdrFJe := SubStr(lol, pos_FdrFJe + 9, pos_quote_FdrFJe - (pos_FdrFJe + 9))

        pos_cfb2h := InStr(lol, "cfb2h", true)
        pos_quote_cfb2h := InStr(lol, "`"", true, pos_cfb2h + 8)
        value_cfb2h := SubStr(lol, pos_cfb2h + 8, pos_quote_cfb2h - (pos_cfb2h + 8))
        GoogleTranslate.extracted:={ FdrFJe: value_FdrFJe, cfb2h: value_cfb2h }
    }

    hObject:=ComObject("WinHttp.WinHttpRequest.5.1")
    hObject.Open("POST","https://translate.google.com/_/TranslateWebserverUi/data/batchexecute?rpcids=MkEWBc&source-path=%2F&f.sid=" GoogleTranslate.extracted.FdrFJe "&bl=" GoogleTranslate.extracted.cfb2h "&hl=en-US&soc-app=1&soc-platform=1&soc-device=1&_reqid=" Random(1000,9999) "&rt=c")
    hObject.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8")
    hObject.Send("f.req=" encodeURIComponent(JSON_stringify([[["MkEWBc",JSON_stringify([[text, languageFrom, languageTo, {Base:{__Class:"JSON_false"}}], [{Base:{__Class:"JSON_null"}}]]), {Base:{__Class:"JSON_null"}}, 'generic']]])))
    lol:=hObject.ResponseText

    pos_newline := InStr(lol,"`n",true,8)
    fwef:=SubStr(lol,7,pos_newline - 7)
    size := Integer(SubStr(lol,7,pos_newline - 7)) - 2
    jsonTemp := JSON_parse(SubStr(lol,pos_newline+1,size))
    json := JSON_parse(jsonTemp[1][3])

    ;autocorrected
    if (type(json[1][2])=="JSON_null" || type(json[1][2][1])=="JSON_null") {
        autocorrected:=false
    } else {
        autocorrected:=json[1][2][1][5]
    }

    ;phoneticNotation
    if (type(json[1][1])=="JSON_null") {
        phoneticNotation:=false
    } else {
        phoneticNotation:=json[1][1]
    }

    ;translation
    switch (json[2][1].Length) {
        case 1:
            translation:=json[2][1][1][6][1][1]
        case 2:
            ;assume (feminine) then (masculine)
            translation:=[json[2][1][1][1],json[2][1][2][1]]
    }

    return {translation:translation,fromLanguage:json[3],autocorrected:autocorrected,phoneticNotation:phoneticNotation}
}

JSON_parse(str) {

    c_:=1

    return JSON_value()

    JSON_value() {

        char_:=SubStr(str, c_, 1)
        Switch char_ {
            case "{":
                obj_:=Map()
                ;object
                c_++
                loop {
                    skip_s()
                    if (SubStr(str, c_, 1) == "}") {
                        c_++
                        return obj_
                    }

                    ; key_:=JSON_objKey()
                    ; a or "a"
                    if (SubStr(str, c_, 1) == "`"") {
                        RegExMatch(str, "(?:\\.|.)*?(?=`")", &OutputVar, c_ + 1)
                        key_:=StrReplace(StrReplace(StrReplace(StrReplace(StrReplace(StrReplace(StrReplace(OutputVar.0, "\`"", "`"", true), "\f", "`f", true), "\r", "`r", true), "\n", "`n", true), "\b", "`b", true), "\t", "`t", true), "\\", "\", true)
                        c_+=OutputVar.Len
                    } else {
                        RegExMatch(str, ".*?(?=[\s:])", &OutputVar, c_)
                        key_:=OutputVar.0
                        c_+=OutputVar.Len
                    }

                    c_:=InStr(str, ":", true, c_) + 1
                    skip_s()

                    value_:=JSON_value()
                    obj_[key_]:=value_
                    obj_.DefineProp(key_, {Value: value_})

                    skip_s()
                    if (SubStr(str, c_, 1) == ",") {
                        c_++, skip_s()
                    }
                }
            case "[":
                arr_:=[]
                ;array
                c_++
                loop {
                    skip_s()
                    if (SubStr(str, c_, 1) == "]") {
                        c_++
                        return arr_
                    }

                    value_:=JSON_value()
                    arr_.Push(value_)

                    skip_s()
                    char_:=SubStr(str, c_, 1)
                    if (char_ == ",") {
                        c_++, skip_s()
                    }
                }
            case "`"":
                RegExMatch(str, "(?:\\.|.)*?(?=`")", &OutputVar, c_ + 1)
                unquoted:=StrReplace(StrReplace(StrReplace(StrReplace(StrReplace(StrReplace(StrReplace(OutputVar.0, "\`"", "`"", true), "\f", "`f", true), "\r", "`r", true), "\n", "`n", true), "\b", "`b", true), "\t", "`t", true), "\\", "\", true)
                c_+=OutputVar.Len + 2
                return unquoted
            case "-", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9":
                ; -100
                ; 100.0
                ; 1.0E+2
                ; 1E-2
                RegExMatch(str, "[0-9.eE\-+]*", &OutputVar, c_)
                c_+=OutputVar.Len
                return Number(OutputVar.0)
            case "t":
                ;"true"
                c_+=4
                return {Base:{__Class:"JSON_true"}}
            case "f":
                ;"false"
                c_+=5
                return {Base:{__Class:"JSON_false"}}
            case "n":
                ;"null"
                c_+=4
                return {Base:{__Class:"JSON_null"}}

        }
    }

    skip_s() {
        RegExMatch(str, "\s*", &OutputVar, c_)
        c_+=OutputVar.Len
    }
}

JSON_stringify(obj, maxDepth := 5) {

    stringified := ""

    escape(str) {
        str:=StrReplace(str, "\", "\\", true)
        str:=StrReplace(str, "`t", "\t", true)
        str:=StrReplace(str, "`b", "\b", true)
        str:=StrReplace(str, "`n", "\n", true)
        str:=StrReplace(str, "`r", "\r", true)
        str:=StrReplace(str, "`f", "\f", true)
        str:=StrReplace(str, "`"", "\`"", true)
        return str
    }
    ok(obj, depth) {
        switch (Type(obj)) {
            case 'Map':
                if (depth > maxDepth) {
                    stringified.="`"[DEEP ...Map]`""
                } else {
                    stringified.="{"
                    for k, v in obj {
                        (A_Index > 1 && stringified.=",")
                        stringified.="`"" escape(k) "`": "
                        ok(v, depth+1)
                    }
                    stringified.="}"
                }
            case 'Object':
                if (depth > maxDepth) {
                    stringified.="`"[DEEP ...Object]`""
                } else {
                    stringified.="{"
                    for k, v in obj.OwnProps() {
                        (A_Index > 1 && stringified.=",")
                        stringified.="`"" escape(k) "`": "
                        ok(v, depth+1)
                    }
                    stringified.="}"
                }
            case 'Array':
                if (depth > maxDepth) {
                    stringified.="`"[DEEP ...Array]`""
                } else {
                    stringified.="["
                    for v in obj {
                        (A_Index > 1 && stringified.=",")
                        ok(v, depth+1)
                    }
                    stringified.="]"
                }
            case 'String':
                stringified.="`"" escape(obj) "`"" ;in order to escape \n and etc
            case "Integer", "Float":
                stringified.=obj
            case "JSON_true":
                stringified.="true"
            case "JSON_false":
                stringified.="false"
            case "JSON_null":
                stringified.="null"
        }

    }
    ok(obj, 0)

    return stringified

}

encodeURIComponent(str) {
    static arr:=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"!",0,0,0,0,0,"'","(",")","*",0,0,"-",".",0,"0","1","2","3","4","5","6","7","8","9",0,0,0,0,0,0,0,"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z",0,0,0,0,"_",0,"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z",0,0,0,"~",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,]

    size:=StrPut(str, "UTF-8")
    buf := Buffer(size)
    StrPut(str, buf, "UTF-8")

    i_ := 0
    sizeMinusOne := size - 1
    finalStr:=""

    while (i_ < sizeMinusOne) {
        uChar:=NumGet(buf, i_, "UChar")
        if (type(arr[uChar + 1])=="String") { ;I REALLY don't know how to get : "0"!==0 -> to give me false
            finalStr.=arr[uChar + 1]
        } else {
            finalStr.="%" Format("{:02X}",uChar)
        }
        ++i_
    }

    return finalStr
}

Exitapp

f3::Exitapp

User avatar
andymbody
Posts: 906
Joined: 02 Jul 2017, 23:47

Re: [v2] GoogleTranslate /_/TranslateWebserverUi

Post by andymbody » Yesterday, 22:13

Thank you very much!!

Post Reply

Return to “Scripts and Functions (v2)”