Using Google Translate to automate text translation

Post your working scripts, libraries and tools for AHK v1.1 and older
User avatar
kunkel321
Posts: 1042
Joined: 30 Nov 2015, 21:19

Re: Using Google Translate to automate text translation

Post by kunkel321 » 17 Aug 2022, 09:13

EM3R50N wrote:
17 Aug 2022, 05:58
My apologies on a noob question but I primarily just use AHK for snippet stuff - by typing keywords to get the full string, etc.
How do you guys trigger/use this script? Can I select text in notepad (for example) and trigger this script somehow?
I'm not an expert, but I'll try to answer... The first post of this thread has Teadrinker's original function, which does all the work. Throughout the thread, several people have posted their own GUIs (graphical user interfaces). The gui calls the function. You can probably just take the gui you like best and use it as is. Many of them probably have a hotkey built in. If they do, then you would run the script, and it would sit in RAM. Then when you press the hotkey combo, the gui will appear.

My own application of Teadrinker's function (a couple of replies above this reply) doesn't have a hotkey, because it gets activated from my masterscript that I always have running in the background.

EDIT: Welcome to the forum, by the way! :- }
ste(phen|ve) kunkel

garry
Posts: 3763
Joined: 22 Dec 2013, 12:50

Re: Using Google Translate to automate text translation

Post by garry » 17 Aug 2022, 12:25

at first page , GUI example second with audio : mark text and copy with ctrl+c
see result and also can use audio-button ( selected language is saved in a ini-file )
viewtopic.php?p=273678#p273678

sfrerku
Posts: 3
Joined: 18 Aug 2022, 19:50

Re: Using Google Translate to automate text translation

Post by sfrerku » 18 Aug 2022, 19:57

teadrinker wrote:
19 Oct 2019, 16:59
I fixed the obsolete parameters in the http request, the script is edited.
Hello teadrinker, awesome work. I have 2 questions tho:
1) The only way I have managed to activate it is by executing it. Can't you bind it to a hotkey without having to create another script to execute it?
2) Is there anyway I can get the result directly and automatically copied to my clipboard instead of opening a message box?

sfrerku
Posts: 3
Joined: 18 Aug 2022, 19:50

Re: Using Google Translate to automate text translation

Post by sfrerku » 18 Aug 2022, 21:27

@teadrinker Hi, thanks for your work!

I would like to know if there's a chance to bind this script to be executed by a hotkey, make it cut the selected text, translate it and paste it back.

I found a script that successfully replaces your current clipboard temporarily by another text (in this case the translation), then pastes it and then restores again the clipboard with whatever there was there before. I modified it to what I think would actually first save temporarily your clipboard, then cut the text you selected, then activate your script to translate the text, then replace the clipboard with the translated text, then paste it, and finally restore the clipboard to whatever it was before pressing the hotkey [ALT + T].

Code: Select all

!t::
 {
   temp := clipboardall
   sendinput, ^x
   "EXECUTE YOUR SCRIPT HERE, TRANSLATING THE CONTENTS OF THE CLIPBOARD, BUT WITHOUT DISPLAYING THE MSG BOX AT THE END WITH THE TRANSLATION"
   clipboard := "Translated text should be here"
   sendinput, ^v
   clipboard := temp
 }
return
[Mod edit: [code][/code] tags added.]

Is this possible?

Thanks in advance

User avatar
rommmcek
Posts: 1473
Joined: 15 Aug 2014, 15:18

Re: Using Google Translate to automate text translation

Post by rommmcek » 19 Aug 2022, 11:55

Try:
Spoiler

sfrerku
Posts: 3
Joined: 18 Aug 2022, 19:50

Re: Using Google Translate to automate text translation

Post by sfrerku » 23 Aug 2022, 10:52

rommmcek wrote:
19 Aug 2022, 11:55
Try:
Spoiler
Ok, but where exactly should I add this code on the original teadrinker Script? and what should I delete on the original Script to avoid the pop up window with the translation? I'm a complete beginner in scripting sorry. Thank you so much in advance.

User avatar
rommmcek
Posts: 1473
Joined: 15 Aug 2014, 15:18

Re: Using Google Translate to automate text translation

Post by rommmcek » 24 Aug 2022, 06:18

Just paste the function underneath the code I posted.
P.s.: Replacing only one marked word this way will yield often unexpected result, so avoid it or use my version of the function like: GoogleTranslate(Clipboard, "en", "ru").1.

Gh0sTG0
Posts: 55
Joined: 25 Jun 2018, 07:58

Re: Using Google Translate to automate text translation

Post by Gh0sTG0 » 11 Oct 2022, 10:00

Hi. I find some really strange bug.
I'm trying to do some translator for my own use.

I just copypasted code from 1st post. My command is:

Code: Select all

F2::
{
	Clipboard := GoogleTranslate(Clipboard)
	Return
}

On testing I find some number of things that were translated good and this:
うずまきすすふえん| 卯月総集編

When I press F2 I have in my clipboard this:
Uzumaki Sufuen |
As you can see there's no part that is on right from "|".


I tried to remove "|", and I get this:
Uzumaki Sufuen Uzuki Highlights

Any ideas about why "|" is breaking translation?


I know, that I can just:

Code: Select all

Clipboard := StrReplace(Clipboard, "|", A_Space)
But... Is "|" the only one symbol that is breaking translation? Or I should catch them all manually? Or... what?

teadrinker
Posts: 4326
Joined: 29 Mar 2015, 09:41
Contact:

Re: Using Google Translate to automate text translation

Post by teadrinker » 11 Oct 2022, 10:48

@Gh0sTG0
Perhaps some Japanese language related issue. Try translating from any other language.

Gh0sTG0
Posts: 55
Joined: 25 Jun 2018, 07:58

Re: Using Google Translate to automate text translation

Post by Gh0sTG0 » 11 Oct 2022, 11:05

teadrinker wrote:
11 Oct 2022, 10:48
@Gh0sTG0
Try translating from any other language.
Already tried, it's working ok.
And... I find that it's not script's failure =_= it's some google translate problems, it translates like that in browser window =(.

Rikk03
Posts: 192
Joined: 12 Oct 2020, 02:44

Re: Using Google Translate to automate text translation

Post by Rikk03 » 18 Oct 2022, 01:51

How can I just write the slit text back to the clipboard, each new piece on a new line?
teadrinker wrote:
11 Feb 2021, 10:08
BoBo wrote: split input in (to be specified) chunks allowing to pass Googles' 5K-char per session limit.

Code: Select all

text =
(
@teadrinker - I've used your script a minute ago (and now it looks that I've got blocked :shh:) so, time to ask ...
Has your updated script taken the before mentioned condition already into account? I thought about to translate the transcription of YouTube videos so people from abroad will have a chance to better follow its (German) speaker. Higher translation quality would shrink the time of necessarry corrections.
)
arr := SplitText(text, 200)
for k, v in arr
   MsgBox, % v

SplitText(text, max := 5000) {
   chunks := [], text .= ".", pos := 1
   Loop {
      for k, v in ["\.", "!", "\?", ";", ",", ":", "\(", "\)", " ", "$"]
         RegExMatch(SubStr(text, pos, max), "sO).+" . v . "+", m)
      until m.Len
      chunks.Push(m[0])
      pos += m.Len
   } until pos > StrLen(text)
   last := chunks.Pop()
   chunks.Push( SubStr(last, 1, -1) )
   Return chunks
}

Rikk03
Posts: 192
Joined: 12 Oct 2020, 02:44

Re: Using Google Translate to automate text translation

Post by Rikk03 » 18 Oct 2022, 04:44

Never mind I figured it out

Code: Select all

vid .= Ltrim(v) "`n`n"

mryoussef79
Posts: 4
Joined: 17 Feb 2023, 05:33

Re: Using Google Translate to automate text translation

Post by mryoussef79 » 17 Feb 2023, 14:14

Is there an update for it with Autohotkey V2

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

Re: Using Google Translate to automate text translation

Post by MrDoge » 17 Feb 2023, 16:02

@mryoussef79 not a direct translation but it's v2 : viewtopic.php?p=505855 [v2] GoogleTranslate /_/TranslateWebserverUi

teadrinker
Posts: 4326
Joined: 29 Mar 2015, 09:41
Contact:

Re: Using Google Translate to automate text translation

Post by teadrinker » 17 Feb 2023, 17:37

I added code for AHK v2, please report any bugs you find.
MrDoge wrote: viewtopic.php?f=6&t=63835 incorrectly detects 門 as Chinese Simplified
Looks like the last versoin correctly works with 門.

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

Re: Using Google Translate to automate text translation

Post by MrDoge » 17 Feb 2023, 18:26

teadrinker wrote:
17 Feb 2023, 17:37
I added code for AHK v2, please report any bugs you find.
MrDoge wrote: viewtopic.php?f=6&t=63835 incorrectly detects 門 as Chinese Simplified
Looks like the last versoin correctly works with 門.
it's not a "bug", it has to do with google's api route

[[["Door","門",null,null,10],[null,null,null,"Mén"]],[["noun",["door","field of endeavor","gate","gateway","ostium","phylum","subkingdom"],[["door",["大門","戶","門"]],["field of endeavor",["門"]],["gate",["出入口","大門","登機口","門","門口","閘板"]],["gateway",["出入口","門"]],["ostium",["門"]],["phylum",["門"]],["subkingdom",["門"]]],"門",1]],"zh-CN",null,null,[["門",null,[["Door",1000,true,false,[10,8]],["Gate",1000,true,false,[10]],["the door",0,true,false,[3],null,[[3]]]],[[0,1]],"門",0,0]],0.8984375,[],[["zh-CN"],null,[0.8984375],["zh-TW"]]]

(get fromLanguage)

Code: Select all

#SingleInstance force
ListLines 0
KeyHistory 0
SendMode "Input" ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir A_ScriptDir ; Ensures a consistent starting directory.

json:="
(
[[["Door","門",null,null,10],[null,null,null,"Mén"]],[["noun",["door","field of endeavor","gate","gateway","ostium","phylum","subkingdom"],[["door",["大門","戶","門"]],["field of endeavor",["門"]],["gate",["出入口","大門","登機口","門","門口","閘板"]],["gateway",["出入口","門"]],["ostium",["門"]],["phylum",["門"]],["subkingdom",["門"]]],"門",1]],"zh-CN",null,null,[["門",null,[["Door",1000,true,false,[10,8]],["Gate",1000,true,false,[10]],["the door",0,true,false,[3],null,[[3]]]],[[0,1]],"門",0,0]],0.8984375,[],[["zh-CN"],null,[0.8984375],["zh-TW"]]]
)"

JS := ObjBindMethod(GetJS(), 'eval')
JsonObj := JS('(' . json . ')')

; the way to get the `fromLanguage` from that json is to take the 3rd element in the array
; if you know any other way (because zh-TW IS indeed found in the json, but it's inconsistent/ambiguous), please help
MsgBox fromLanguage:=JsonObj.%2% ;zh-CH stands for Chinese Simplified, it should be zh-TW

return

GetJS() {
    static document := '', JS
    if !document {
        document := ComObject('HTMLFILE')
        document.write('<meta http-equiv="X-UA-Compatible" content="IE=9">')
        JS := document.parentWindow
        (document.documentMode < 9 && JS.execScript())
    }
    return JS
}

f3::Exitapp
(get response json)

Code: Select all

MsgBox A_Clipboard:=GoogleTranslateGetJSON('門', from := 'auto')

GoogleTranslateGetJSON(str, from := 'auto', to := 'en', &variants := '') {
    static JS := ObjBindMethod(GetJS(), 'eval'), _ := JS(GetJScript())

    json := SendRequest(str, Type(from) = 'VarRef' ? %from% : from, to)
    return json

    SendRequest(str, sl, tl) {
        static WR := ''
             , headers := Map('Content-Type', 'application/x-www-form-urlencoded;charset=utf-8',
                              'User-Agent'  , 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0')
        if !WR {
            WR := WebRequest()
            WR.Fetch('https://translate.google.com',, headers)
        }
        url := 'https://translate.googleapis.com/translate_a/single?client=gtx'
             . '&sl=' . sl . '&tl=' . tl . '&hl=' . tl
             . '&dt=at&dt=bd&dt=ex&dt=ld&dt=md&dt=qca&dt=rw&dt=rm&dt=ss&dt=t&ie=UTF-8&oe=UTF-8&otf=0&ssel=0&tsel=0&pc=1&kc=1'
             . '&tk=' . JS('tk')(str)
        return WR.Fetch(url, 'POST', headers, 'q=' . JS('encodeURIComponent')(str))
    }

    GetJScript()
    {
        return '
        (
            var TKK = ((function() {
                var a = 561666268;
                var b = 1526272306;
                return 406398 + '.' + (a + b);
            })());

            function b(a, b) {
                for (var d = 0; d < b.length - 2; d += 3) {
                    var c = b.charAt(d + 2),
                        c = 'a' <= c ? c.charCodeAt(0) - 87 : Number(c),
                        c = '+' == b.charAt(d + 1) ? a >>> c : a << c;
                    a = '+' == b.charAt(d) ? a + c & 4294967295 : a ^ c
                }
                return a
            }

            function tk(a) {
                for (var e = TKK.split('.'), h = Number(e[0]) || 0, g = [], d = 0, f = 0; f < a.length; f++) {
                    var c = a.charCodeAt(f);
                    128 > c ? g[d++] = c : (2048 > c ? g[d++] = c >> 6 | 192 : (55296 == (c & 64512) && f + 1 < a.length && 56320 == (a.charCodeAt(f + 1) & 64512) ?
                    (c = 65536 + ((c & 1023) << 10) + (a.charCodeAt(++f) & 1023), g[d++] = c >> 18 | 240,
                    g[d++] = c >> 12 & 63 | 128) : g[d++] = c >> 12 | 224, g[d++] = c >> 6 & 63 | 128), g[d++] = c & 63 | 128)
                }
                a = h;
                for (d = 0; d < g.length; d++) a += g[d], a = b(a, '+-a^+6');
                a = b(a, '+-3^+b+-f');
                a ^= Number(e[1]) || 0;
                0 > a && (a = (a & 2147483647) + 2147483648);
                a `%= 1E6;
                return a.toString() + '.' + (a ^ h)
            }
        )'
    }

    GetJS() {
        static document := '', JS
        if !document {
            document := ComObject('HTMLFILE')
            document.write('<meta http-equiv="X-UA-Compatible" content="IE=9">')
            JS := document.parentWindow
            (document.documentMode < 9 && JS.execScript())
        }
        return JS
    }
}


class WebRequest
{
    __New() {
        this.whr := ComObject('WinHttp.WinHttpRequest.5.1')
    }

    __Delete() {
        this.whr := ''
    }

    Fetch(url, method := 'GET', HeadersArray := '', body := '', getRawData := false) {
        this.whr.Open(method, url, true)
        for name, value in HeadersArray
            this.whr.SetRequestHeader(name, value)
        this.error := ''
        this.whr.Send(body)
        this.whr.WaitForResponse()
        status := this.whr.status
        if (status != 200)
            this.error := 'HttpRequest error, status: ' . status . ' — ' . this.whr.StatusText
        Arr := this.whr.responseBody
        pData := NumGet(ComObjValue(arr) + 8 + A_PtrSize, 'Ptr')
        length := Arr.MaxIndex() + 1
        if !getRawData
            res := StrGet(pData, length, 'UTF-8')
        else {
            outData := Buffer(length, 0)
            DllCall('RtlMoveMemory', 'Ptr', outData, 'Ptr', pData, 'Ptr', length)
            res := outData
        }
        return res
    }
}

f3::ExitApp

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

Re: Using Google Translate to automate text translation

Post by MrDoge » 17 Feb 2023, 18:33

compare it with the json here, (also 3rd element in the array), here it's : "zh-TW"

[["Mén",null,"zh-TW",[[[0,[[[null,1]],[true]]]],1],[["門",null,null,1]],null,["門","auto","en"]],[[[null,null,null,null,null,[["Door",null,null,null,[["Door",[4,5],[]],["Gate",[4],[]],["Doors",[11],[]]]]]]],"en",1,"zh-TW",["門","auto","en"]],"zh-TW",["門",null,null,null,null,[[["noun",[["door",null,["大門","戶","門"],3,true],["field of endeavor",null,["門"],3,true],["gate",null,["出入口","大門","登機口","門","門口","閘板"],3,true],["gateway",null,["出入口","門"],3,true],["ostium",null,["門"],3,true],["phylum",null,["門"],3,true],["subkingdom",null,["門"],3,true]],"en","zh-TW"]],7],"Mén",null,"zh-TW",1]]

Code: Select all

MsgBox A_Clipboard:=GoogleTranslate("門")

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))
    return jsonTemp[1][3]
}

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

teadrinker
Posts: 4326
Joined: 29 Mar 2015, 09:41
Contact:

Re: Using Google Translate to automate text translation

Post by teadrinker » 17 Feb 2023, 18:56

@MrDoge
Try this one:

Code: Select all

#Requires AutoHotkey v2

text := GoogleTranslate('門', &from := 'auto')
MsgBox 'from: ' . from . '`ntranslate: ' . text, 'from auto to English'

GoogleTranslate(str, from := 'auto', to := 'en', &variants := '') {
    static JS := ObjBindMethod(GetJS(), 'eval'), _ := JS(GetJScript())
    
    json := SendRequest(str, Type(from) = 'VarRef' ? %from% : from, to)
    JsonObj := JS('(' . json . ')')
    variants := ''
    if !IsObject(JsonObj.1) {
        Loop JsonObj.0.length {
            variants .= JsonObj.0.%A_Index - 1%.0
        }
    } else {
        mainTrans := JsonObj.0.0.0
        Loop JsonObj.1.length {
            variants .= '`n+'
            obj := JsonObj.1.%A_Index - 1%.1
            Loop obj.length {
                txt := obj.%A_Index - 1%
                variants .= (mainTrans = txt ? '' : '`n' . txt)
            }
        }
    }
    if !IsObject(JsonObj.1)
        mainTrans := variants := Trim(variants, ',+`n ')
    else
        variants := mainTrans . '`n+`n' . Trim(variants, ',+`n ')

    (Type(from) = 'VarRef' && %from% := JsonObj.8.3.0)
    return mainTrans

    SendRequest(str, sl, tl) {
        static WR := ''
             , headers := Map('Content-Type', 'application/x-www-form-urlencoded;charset=utf-8',
                              'User-Agent'  , 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0')
        if !WR {
            WR := WebRequest()
            WR.Fetch('https://translate.google.com',, headers)
        }
        url := 'https://translate.googleapis.com/translate_a/single?client=gtx'
             . '&sl=' . sl . '&tl=' . tl . '&hl=' . tl
             . '&dt=at&dt=bd&dt=ex&dt=ld&dt=md&dt=qca&dt=rw&dt=rm&dt=ss&dt=t&ie=UTF-8&oe=UTF-8&otf=0&ssel=0&tsel=0&pc=1&kc=1'
             . '&tk=' . JS('tk')(str)
        return WR.Fetch(url, 'POST', headers, 'q=' . JS('encodeURIComponent')(str))
    }

    GetJScript()
    {
        return '
        (
            var TKK = ((function() {
                var a = 561666268;
                var b = 1526272306;
                return 406398 + '.' + (a + b);
            })());

            function b(a, b) {
                for (var d = 0; d < b.length - 2; d += 3) {
                    var c = b.charAt(d + 2),
                        c = 'a' <= c ? c.charCodeAt(0) - 87 : Number(c),
                        c = '+' == b.charAt(d + 1) ? a >>> c : a << c;
                    a = '+' == b.charAt(d) ? a + c & 4294967295 : a ^ c
                }
                return a
            }

            function tk(a) {
                for (var e = TKK.split('.'), h = Number(e[0]) || 0, g = [], d = 0, f = 0; f < a.length; f++) {
                    var c = a.charCodeAt(f);
                    128 > c ? g[d++] = c : (2048 > c ? g[d++] = c >> 6 | 192 : (55296 == (c & 64512) && f + 1 < a.length && 56320 == (a.charCodeAt(f + 1) & 64512) ?
                    (c = 65536 + ((c & 1023) << 10) + (a.charCodeAt(++f) & 1023), g[d++] = c >> 18 | 240,
                    g[d++] = c >> 12 & 63 | 128) : g[d++] = c >> 12 | 224, g[d++] = c >> 6 & 63 | 128), g[d++] = c & 63 | 128)
                }
                a = h;
                for (d = 0; d < g.length; d++) a += g[d], a = b(a, '+-a^+6');
                a = b(a, '+-3^+b+-f');
                a ^= Number(e[1]) || 0;
                0 > a && (a = (a & 2147483647) + 2147483648);
                a `%= 1E6;
                return a.toString() + '.' + (a ^ h)
            }
        )'
    }

    GetJS() {
        static document := '', JS
        if !document {
            document := ComObject('HTMLFILE')
            document.write('<meta http-equiv="X-UA-Compatible" content="IE=9">')
            JS := document.parentWindow
            (document.documentMode < 9 && JS.execScript())
        }
        return JS
    }
}


class WebRequest
{
    __New() {
        this.whr := ComObject('WinHttp.WinHttpRequest.5.1')
    }

    __Delete() {
        this.whr := ''
    }

    Fetch(url, method := 'GET', HeadersArray := '', body := '', getRawData := false) {
        this.whr.Open(method, url, true)
        for name, value in HeadersArray
            this.whr.SetRequestHeader(name, value)
        this.error := ''
        this.whr.Send(body)
        this.whr.WaitForResponse()
        status := this.whr.status
        if (status != 200)
            this.error := 'HttpRequest error, status: ' . status . ' — ' . this.whr.StatusText
        Arr := this.whr.responseBody
        pData := NumGet(ComObjValue(arr) + 8 + A_PtrSize, 'Ptr')
        length := Arr.MaxIndex() + 1
        if !getRawData
            res := StrGet(pData, length, 'UTF-8')
        else {
            outData := Buffer(length, 0)
            DllCall('RtlMoveMemory', 'Ptr', outData, 'Ptr', pData, 'Ptr', length)
            res := outData
        }
        return res
    }
}
Do you think, it is more correct?

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

Re: Using Google Translate to automate text translation

Post by MrDoge » 17 Feb 2023, 19:08

@teadrinker
%from% := JsonObj.8.3.0
the json "path" [8][3][0] works perfectly for 門, I'm getting "zh-TW" (that's good), but it works for 門 only, it fails for
text := GoogleTranslate('día', &from := 'auto')
in which I get "pt"

EDIT: I was too fast to reply, "pt" stands for Portuguese (and not some random thing like Point or px), which is correct

EDIT 2: as perfect as it gets, unless I think of something else and come back to edit

teadrinker
Posts: 4326
Joined: 29 Mar 2015, 09:41
Contact:

Re: Using Google Translate to automate text translation

Post by teadrinker » 17 Feb 2023, 19:21

Thanks for testing, I'll change the code, until someone reports about another issue.

Post Reply

Return to “Scripts and Functions (v1)”