Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 05/30/2024 in all areas

  1. Hi everybody With the help of this thread, @AspirinJunkie @Nine and @Musashi , I was able to add a GUI to Google translation with AutoIt. Please note the 3 colors possible (green / yellow / red) found in these 3 pics, we'll discuss them later (need some sleep now) The maximum number of characters allowed for the original text is 65535, but imho it's too much. If you experience some slowness with 65535, then you can modify this variable at the very beginning of the script and indicate a lower value : Local $iMaxInputLength = 65535 There are different ways to import the text to translate : * Paste it directly from the clipboard (Ctrl+V) inside the upper edit control * Click the "Paste ClipBoard" button in the GUI * Drag a text file inside the upper edit control * Click the "Open File" button in the GUI (only .txt files for the moment) Then choose in each combo box the language you want ("Detect language" is useful for the Original) and click Translate. After the translation is done, if you want to copy the translated text, then a click on the "Copy Translated" button is possible. During the translation process, you have the possibility to press the "Escape" key if you want to stop the translation. ; Version 11 (June 30, 2024) ; This script requires AutoIt 3.3.16.1 (which includes Maps, as Json.au3 requires Maps for some translations) ; It also requires the file "Google Translate (languages list #3).txt" to be placed in same folder as the script ; To translate pdf files, it requests "pdftotext.exe" (a free command line tool from Xpdf downloadable at https://www.xpdfreader.com) #include "Json.au3" ; by @AspirinJunkie, download from https://github.com/Sylvan86/autoit-json-udf #include <Array.au3> #include <ButtonConstants.au3> #include <ComboConstants.au3> #include <EditConstants.au3> #include <FileConstants.au3> #include <GUIConstantsEx.au3> #include <GUIEdit.au3> #Include <GUIMenu.au3> #include <MsgBoxConstants.au3> #include <StaticConstants.au3> #include <StringConstants.au3> #include <WinAPISysWin.au3> #include <WindowsConstants.au3> Opt("MustDeclareVars", 1) ;0=no, 1=require pre-declaration Opt("GUICloseOnESC", 0) ;1=ESC closes (default), 0=ESC won't close Global $iMaxInputLength = 65535 ; In theory, 65535 is the maximum length of the original encoded string, when it is only composed of ; letters, digits, etc... which have an ascii code < 128 and coded on 1 byte only. ; But in practice, this variable should probably be lower (5000 as Google Translate site ?) or 10000, 15000 ... ; to avoid the warning message that will appear when the original encoded string becomes > 65535 bytes length. ; Also _JSON_Parse() may take some time on slow computers with "big" original encoded strings, we'll see... ; Global $iMaxInputLength = 5460 ; this value allows any encoded string to be < 65536 length, even if each character is a Unicode character ; requiring 4 bytes. In this case, each character will be coded on 12 bytes in the string "%..%..%..%.." ; 5460 * 12 = 65520 bytes (which is < 65536) ; user can choose amongst 39 GUI languages (this has nothing to do with 133 translatable languages) Global $aLangGui = _FillArrayLangGui("Google Translate (languages list #3).txt") Global $sIniFile = StringTrimRight(@ScriptFullPath, 4) & ".ini" ; ".au3" | ".a3x" | ".exe" => ".ini" Global $aLang, $aLink, $sLang = "", $iLangGui = -1, $bRTL Global $aIni = _ReadIniFile($sIniFile, $aLang, $aLink, $sLang) ; _ArrayDisplay($aLang, Ubound($aLang) & " codes & languages", Default, $ARRAYDISPLAY_NOROW, Default, "Code|Language|In Combo ?") #Region ### START Koda GUI section ### Form=C:\Temp\koda_1.7.3.0\Forms\google translate #4.kxf Global $sGUI_Title, $hGUI, $idPasteClip, $idOpenFile, $idLabelFrom, $idLangFrom, $idFontSizeFrom, $idWordWrapFrom, $idLanguageFilter Global $idLabelTo, $idLangTo, $idFontSizeTo, $idWordWrapTo, $idTranslate, $idCopyTrans, $idTextFrom, $idTextTo, $idCharStatus Global $idMsg, $sFileName, $sFileExt, $sEmpty = "" ; variable $sEmpty created only because ByRef doesn't accept literals _CreateGui() GUISetState(@SW_SHOW) #EndRegion ### END Koda GUI section ### GUIRegisterMsg($WM_COMMAND, "WM_COMMAND") While 1 $idMsg = GUIGetMsg() Switch $idMsg Case $GUI_EVENT_CLOSE _WriteIniFile($sIniFile, $aLink) ExitLoop Case $idPasteClip ; in edit control containing the original text _UpdateGUI(StringLeft(ClipGet(), $iMaxInputLength)) Case $idOpenFile, $GUI_EVENT_DROPPED ; in edit control containing the original text $sFileName = ($idMsg = $idOpenFile) ? _OpenFile() : @GUI_DragFile If $sFileName Then $sFileExt = StringMid($sFileName, 1 + StringInStr($sFileName, ".", 0, -1)) ; -1 to start search from the right If StringLen($sFileExt) = StringLen($sFileName) Then $sFileExt = "no dot found" ; no "." found in $sFileName If StringInStr(FileGetAttrib($sFileName), "D") Then $sFileExt = "this is a folder" Select Case $sFileExt = "txt" ; no problem with txt extension Case $sFileExt = "pdf" ; extract pdf content to txt file using pdftotext.exe $sFileName = _PdfToText($sFileName) ; $sFileName (xxx.pdf) => $sFileName (TextExtractedFromPDF.txt) if success. If Not $sFileName Then ContinueLoop ; ... if extraction of txt fails, then $sFileName becomes "" (0 in fact) Case Else MsgBox($MB_TOPMOST, "File extension error ", _ "File extension '" & $sFileExt & "' can't be processed" & @crlf & _ "Only .txt or .pdf file can be processed", 0, $hGUI) _UpdateGUI($sEmpty) ContinueLoop EndSelect _UpdateGUI(StringLeft(FileRead($sFileName), $iMaxInputLength)) EndIf Case $idFontSizeFrom GUICtrlSetFont($idTextFrom, Int(GUICtrlRead($idFontSizeFrom))) GUICtrlSetState($idTextFrom, $GUI_FOCUS) ; keep showing an eventual selection Case $idWordWrapFrom $idTextFrom = _EditRecreate_From(Int(GUICtrlRead($idFontSizeFrom)), GUICtrlRead($idWordWrapFrom)) ; Font size, WordWrap GUICtrlSetState($idTextFrom, $GUI_FOCUS) Case $idFontSizeTo GUICtrlSetFont($idTextTo, Int(GUICtrlRead($idFontSizeTo))) GUICtrlSetState($idTextTo, $GUI_FOCUS) Case $idWordWrapTo $idTextTo = _EditRecreate_To(Int(GUICtrlRead($idFontSizeTo)), GUICtrlRead($idWordWrapTo)) ; Font size, WordWrap GUICtrlSetState($idTextTo, $GUI_FOCUS) Case $idTranslate GUICtrlSetState($idTranslate, $GUI_DISABLE) ; prevent accidental double click on the button GUICtrlSetData($idTextTo, "") WinSetTitle($hGUI, "", _GuiTitle()) HotKeySet("{ESC}", "_Wanna_Quit") ; in case user keys Esc during the translation process _Translate() HotKeySet("{ESC}") GUICtrlSetState($idTranslate, $GUI_ENABLE) Case $idCopyTrans ClipPut(GUICtrlRead($idTextTo)) MsgBox($MB_TOPMOST, "Copy", "Done", 1, $hGUI) ; timeout 1s Case $idLanguageFilter GUIRegisterMsg($WM_COMMAND, "") GUISetState(@SW_DISABLE, $hGUI) _LanguageFilter($aLang, $aLink, $sLang) ; in a new temporary GUI ($hGUI2) GUISetState(@SW_RESTORE, $hGUI) ; only flag that seems to do the job correctly, even on a non-minimized window !? GUISetState(@SW_ENABLE, $hGUI) GUIRegisterMsg($WM_COMMAND, "WM_COMMAND") Case $idLabelFrom ; clickable label to decrease both combobox font size (some GUI languages appear much smaller than others) If $aIni[8] - 1 < 8.3 Then ContinueLoop $aIni[8] -= 1 GUICtrlSetFont($idLangFrom, $aIni[8]) GUICtrlSetFont($idLangTo, $aIni[8]) ; if a language is displayed as squares in the combobox, try instead the 2 following lines ; GUICtrlSetFont($idLangFrom, $aIni[8], 400, 0, "Ms Shell Dlg", 2) ; GUICtrlSetFont($idLangTo, $aIni[8], 400, 0, "Ms Shell Dlg", 2) Case $idLabelTo ; clickable label to increase both combobox font size (some GUI languages appear much smaller than others) If $aIni[8] + 1 > 16.3 Then ContinueLoop $aIni[8] += 1 GUICtrlSetFont($idLangFrom, $aIni[8]) GUICtrlSetFont($idLangTo, $aIni[8]) ; if a language is displayed as squares in the combobox, try instead the 2 following lines ; GUICtrlSetFont($idLangFrom, $aIni[8], 400, 0, "Ms Shell Dlg", 2) ; GUICtrlSetFont($idLangTo, $aIni[8], 400, 0, "Ms Shell Dlg", 2) EndSwitch WEnd GUIDelete($hGUI) ;============================================== Func _UpdateGUI(ByRef $sText) GUICtrlSetData($idTextFrom, $sText) _UpdateCharStatus() GUICtrlSetData($idTextTo, "") WinSetTitle($hGUI, "", _GuiTitle()) EndFunc ;==>_UpdateGUI ;============================================== Func _CreateGui() $sGUI_Title = "Google Translation (v11)" $hGUI = GUICreate(_GuiTitle(), 900, 700, -1, -1, $WS_OVERLAPPEDWINDOW, $WS_EX_ACCEPTFILES) $idPasteClip = GUICtrlCreateButton("Paste Clipboard", 10, 10, 100, 30) $idOpenFile = GUICtrlCreateButton("Open File", 10, 50, 100, 30) GUICtrlCreateGroup(" Original text options ", 120, 10, 310, 70) $idLabelFrom = GUICtrlCreateLabel("Language From", 133, 32, 110, 17) GUICtrlSetTip(-1, "click to decrease both combobox font size", "", 0, 1) $idLangFrom = GUICtrlCreateCombo("", 128, 50, 140, 25, BitOR($CBS_DROPDOWNLIST, $WS_VSCROLL), _ ; $CBS_HASSTRINGS always forced ? $bRTL _ ? BitOr($WS_EX_LEFTSCROLLBAR, $WS_EX_RTLREADING, $WS_EX_RIGHT) _ : -1) GUICtrlSetFont(-1, $aIni[8]) ; if a language is displayed as squares in the combobox, try instead the following line ; GUICtrlSetFont(-1, $aIni[8], 400, 0, "Ms Shell Dlg", 2) GUICtrlSetData(-1, $aLangGui[$iLangGui + 2] & "|" & $sLang) ; ex. item 0 is "Detect language" or "Sprache erkennen" or etc... GUICtrlSendMsg($idLangFrom, $CB_SETCURSEL, $aIni[0], 0) GUICtrlCreateLabel("Font size", 290, 32, 54, 17) $idFontSizeFrom = GUICtrlCreateInput($aIni[1], 288, 50, 57, 21, BitOR($GUI_SS_DEFAULT_INPUT, $ES_CENTER, $ES_NUMBER)) GUICtrlSetLimit(-1, 2) GUICtrlCreateUpdown($idFontSizeFrom) GUICtrlSetLimit(-1, 72, 8) GUICtrlCreateLabel("Word wrap", 364, 32, 64, 17) $idWordWrapFrom = GUICtrlCreateCheckbox("", 382, 46, 17, 25) GUICtrlSetState(-1, $aIni[2]) ; $GUI_CHECKED = 1 , $GUI_UNCHECKED = 4 GUICtrlCreateGroup("", -99, -99, 1, 1) $idLanguageFilter = GUICtrlCreateButton("?", 437, 48, 25, 25) GUICtrlCreateGroup(" Translated text options ", 470, 10, 310, 70) $idLabelTo = GUICtrlCreateLabel("Language To", 483, 32, 110, 17) GUICtrlSetTip(-1, "click to increase both combobox font size", "", 0, 1) $idLangTo = GUICtrlCreateCombo("", 478, 50, 140, 25, BitOR($CBS_DROPDOWNLIST, $WS_VSCROLL), _ ; $CBS_HASSTRINGS always forced ? $bRTL _ ? BitOr($WS_EX_LEFTSCROLLBAR, $WS_EX_RTLREADING, $WS_EX_RIGHT) _ : -1) GUICtrlSetFont(-1, $aIni[8]) ; if a language is displayed as squares in the combobox, try instead the following line ; GUICtrlSetFont(-1, $aIni[8], 400, 0, "Ms Shell Dlg", 2) GUICtrlSetData(-1, $sLang) GUICtrlSendMsg(-1, $CB_SETCURSEL, $aIni[3], 0) GUICtrlCreateLabel("Font size", 640, 32, 54, 17) $idFontSizeTo = GUICtrlCreateInput($aIni[4], 638, 50, 57, 21, BitOR($GUI_SS_DEFAULT_INPUT, $ES_CENTER, $ES_NUMBER)) GUICtrlSetLimit(-1, 2) GUICtrlCreateUpdown($idFontSizeTo) GUICtrlSetLimit(-1, 72, 8) GUICtrlCreateLabel("Word wrap", 714, 32, 64, 17) $idWordWrapTo = GUICtrlCreateCheckbox("", 732, 46, 17, 25) GUICtrlSetState(-1, $aIni[5]) ; $GUI_CHECKED = 1 , $GUI_UNCHECKED = 4 GUICtrlCreateGroup("", -99, -99, 1, 1) $idTranslate = GUICtrlCreateButton("Translate", 790, 10, 100, 30) $idCopyTrans = GUICtrlCreateButton("Copy Translated", 790, 50, 100, 30) $idTextFrom = _EditRecreate_From($aIni[1], $aIni[2]) ; Font size, WordWrap (for edit control containing the original text) $idTextTo = _EditRecreate_To ($aIni[4], $aIni[5]) ; same, for edit control containing the translated text. $idCharStatus = GUICtrlCreateLabel("", 790, 380, 80, 25, BitOR($SS_CENTER,$SS_CENTERIMAGE)) _UpdateCharStatus() EndFunc ;==>_CreateGui ;============================================== Func _Translate() Local $iItemTo = GUICtrlSendMsg($idLangTo, $CB_GETCURSEL, 0, 0) If $iItemTo = - 1 Then ; no "Language To" selected WinSetTitle($hGUI, "", _GuiTitle()) MsgBox($MB_TOPMOST, "'Language To' is undefined", "Please choose a target language from the list", 0, $hGUI) Return EndIf Local $sEncoded = _URIEncode(GUICtrlRead($idTextFrom)) If StringLen($sEncoded) = 0 Then WinSetTitle($hGUI, "", _GuiTitle()) MsgBox($MB_TOPMOST, "No original text", "Nothing to translate", 0, $hGUI) Return EndIf ; ConsoleWrite(BinaryToString(StringToBinary("$sEncoded: " & $sEncoded, $SB_UTF8), $SB_ANSI) & @crlf) Local $iBytes = StringLen($sEncoded) ; ConsoleWrite("Length of $sEncoded : " & $iBytes & @crlf & @crlf) If $iBytes > 65535 Then ; tested (not 65536 !) Local $iYesNo = MsgBox(BitOr($MB_TOPMOST, $MB_YESNO, $MB_DEFBUTTON2, $MB_ICONWARNING), _ "Warning : Encoded text is too big", _ "Encoded text size: " & @Tab & $iBytes & @crlf & _ "Max. allowed:" & @Tab & " 65535" & @crlf & _ "" & @crlf & _ "Do you want to truncate the original text ?", 0, $hGUI) If $iYesNo = $IDNO Then Return $sEncoded = _URIEncode_Truncate(GUICtrlRead($idTextFrom)) EndIf Local $iItemFrom = GUICtrlSendMsg($idLangFrom, $CB_GETCURSEL, 0, 0) Local $sLangFrom = ($iItemFrom = 0) ? "auto" : $aLang[$aLink[$iItemFrom - 1]][0] ; ex. "auto", "en", de", ... ; Local $iItemTo = GUICtrlSendMsg($idLangTo, $CB_GETCURSEL, 0, 0) ; moved at beginning of function, to test if a "Language To" is selected Local $sLangTo = $aLang[$aLink[$iItemTo]][0] ; ex. "en", "de", ... Local $sLangUsed, $sTranslated = _GoogleAPITranslate($sEncoded, $sLangFrom, $sLangTo, $sLangUsed) If $sLangUsed Then ; translation has succeeded and $sLangUsed always contains the code that Google used for its last translation ; ConsoleWrite("$sLangUsed: >>>" & $sLangUsed & "<<<" & @crlf) _GUICtrlEdit_SetText($idTextTo, $sTranslated) If $sLangFrom = "auto" Then Local $sLangUsedFull For $i = 0 To Ubound($aLang) - 1 If $sLangUsed = $aLang[$i][0] Then $sLangUsedFull = $aLang[$i][1] ; ex. "English", "German" , ... ExitLoop EndIf Next WinSetTitle($hGUI, "", "Translated From " & _ ($sLangUsedFull ? $sLangUsedFull : $sLangUsed & " (???)") & _ " To " & $aLang[$aLink[$iItemTo]][1]) Else WinSetTitle($hGUI, "", "Translated From " & $aLang[$aLink[$iItemFrom - 1]][1] & " To " & $aLang[$aLink[$iItemTo]][1]) EndIf Else ; translation failed as $sLangUsed is still empty WinSetTitle($hGUI, "", _GuiTitle()) MsgBox($MB_TOPMOST, "Error", _ "Something went wrong during translation" & @crlf & _ "(Internet connection ok ?)", 0, $hGUI) EndIf EndFunc ;==>_Translate ;============================================== Func _GoogleAPITranslate(Const ByRef $sEncoded, $sFrom, $sTo, ByRef $sLangUsed) Local $oLocalCOMErrorHandler = ObjEvent("AutoIt.Error", "_ErrFuncLocal") ; format and send request With ObjCreate("WinHttp.WinHttpRequest.5.1") ; thanks AspirinJunkie for correct syntax of the Object methods below. .Open("POST", "https://translate.googleapis.com/translate_a/single", False) .SetRequestHeader("Content-Type", "application/x-www-form-urlencoded") .Send(StringFormat("client=gtx&sl=%s&tl=%s&dt=t&q=%s", $sFrom, $sTo, $sEncoded)) Local $sResponse = .ResponseText EndWith ; ConsoleWrite(BinaryToString(StringToBinary("$sResponse: " & $sResponse, $SB_UTF8), $SB_ANSI) & @crlf) Local $vResponse = _JSON_Parse($sResponse) ; process return Local $sOutput = "" If VarGetType($vResponse) = 'Array' Then ; _ArrayDisplay($vResponse, "$vResponse") Local $aData = $vResponse[0] If VarGetType($aData) = 'Array' Then For $i = 0 To UBound($aData) -1 $sOutput &= ($aData[$i])[0] Next EndIf $sLangUsed = $vResponse[2] ; ex. "en" , "de" , ... to display which language Google used for translation, in case user choosed "Detect language" EndIf Return $sOutput EndFunc ;==>_GoogleAPITranslate ;============================================== Func _URIEncode(Const ByRef $sData) ; code below from Prog@ndy (minor changes) : https://www.autoitscript.com/forum/topic/95850-url-encoding/?do=findComment&comment=689060 ; maybe Chr(32) should always be encoded as "%20" and not "+" to be compatible with all browsers (?) we'll see... Local $aData = StringSplit(BinaryToString(StringToBinary($sData, $SB_UTF8), $SB_ANSI), "") ; "" => each character returns as an element Local $nChar, $sEncoded = "" For $i = 1 To $aData[0] $nChar = Asc($aData[$i]) Switch $nChar Case 45, 46, 48 To 57, 65 To 90, 95, 97 To 122, 126 $sEncoded &= $aData[$i] Case 32 $sEncoded &= "+" Case Else $sEncoded &= "%" & Hex($nChar, 2) EndSwitch Next Return $sEncoded EndFunc ;==>_URIEncode ;============================================== Func _URIEncode_Truncate(Const ByRef $sData) Local $dBinary, $nChar, $sEncoded = "", $iGoodLen = 0 For $j = 1 To StringLen($sData) $iGoodLen = StringLen($sEncoded) ; from the previous loop $dBinary = StringToBinary(StringMid($sData, $j, 1), $SB_UTF8) ; for example ะป (russian) becomes 0xD0BB For $i = 1 To BinaryLen($dBinary) $nChar = Number(BinaryMid($dBinary, $i, 1)) Switch $nChar Case 45, 46, 48 To 57, 65 To 90, 95, 97 To 122, 126 $sEncoded &= Chr($nChar) Case 32 $sEncoded &= "+" Case Else $sEncoded &= "%" & Hex($nChar, 2) EndSwitch Next If StringLen($sEncoded) > 65535 Then ; stop encoding... GUICtrlSetData($idTextFrom, StringLeft($sData, $j - 1)) ; ...truncate original text... $sEncoded = StringLeft($sEncoded, $iGoodLen) ;...delete the very last byte(s) in $sEncoded... ExitLoop ; ...return the corresponding encoded string (which will never exceed 65535 bytes) EndIf Next Return $sEncoded EndFunc ;==>_URIEncode_Truncate ;============================================== Func _LanguageFilter(ByRef $aLang, ByRef $aLink, ByRef $sLang) ; Backup 3 arrays (quick), $iLangGui, $bRTL : in case user makes changes in GUI2 then presses Cancel button in GUI2 => revert Local $aLang_backup = $aLang, $aLink_backup = $aLink, $sLang_backup = $sLang, $iLangGui_backup = $iLangGui, $bRTL_backup = $bRTL ; Keep status of combo "Language From" (to select it again, even with another GUI language... if user keeps the language checked) Local $iOld_ItemFrom = GUICtrlSendMsg($idLangFrom, $CB_GETCURSEL, 0, 0) ; always 0+ (0 <=> "Detect language" or "Sprache erkennen" or etc...) Local $sOld_CodeFrom = ($iOld_ItemFrom = 0) ? "auto" : $aLang[$aLink[$iOld_ItemFrom - 1]][0] ; ex. "en" , "de" , ... Local $bCheck_ItemFrom = ($iOld_ItemFrom = 0) ? False : True ; Keep status of combo "Language To" (to select it again, even with another GUI language... if user keeps the language checked) Local $iOld_ItemTo = GUICtrlSendMsg($idLangTo, $CB_GETCURSEL, 0, 0) ; may be -1 if no selected "Language To" . 0+ if selected Local $sOld_CodeTo = ($iOld_ItemTo = -1) ? "" : $aLang[$aLink[$iOld_ItemTo]][0] ; ex. "en" , "de" , ... Local $bCheck_ItemTo = ($iOld_ItemTo = -1) ? False : True Local $iNumLi = -1, $iLeft = 15, $iTop = 49, $iMaxLanguages = Ubound($aLang), $idCheckbox[$iMaxLanguages] Local $iCountGui_Lang = Ubound($aLangGui) / 4, $idMenuItem[$iCountGui_Lang] Local $hGUI2 = GUICreate(_GuiTitle(2), 900, 700, -1, -1, BitOR($WS_CAPTION, $WS_POPUP, $WS_SYSMENU, $WS_MAXIMIZEBOX)) Local $hMenu = _GUICtrlMenu_GetSystemMenu($hGUI2) _GUICtrlMenu_EnableMenuItem($hMenu, $SC_CLOSE, $MF_GRAYED, False) ; "disable red [X] and System Menu 'Close' item" (Melba23, Dec 14 2009) Local $idMenu_Lang = GUICtrlCreateMenu("GUI language") For $i = 0 To Ubound($aLangGui) - 1 Step 4 ; 0, 4, 8, 12, ... , 152 when 39 Gui languages $idMenuItem[$i / 4] = GUICtrlCreateMenuItem($aLangGui[$i + 1], $idMenu_Lang, -1, 1) ; 1 = menuradioitem If $i = $iLangGui Then GUICtrlSetState(-1, $GUI_CHECKED) Next GUICtrlCreateGroup("", 5, 39, 890, 639) ; just to display a thin rectangle around all Checkbox controls For $i = 0 To $iMaxLanguages - 1 $iNumLi += 1 ; 0+ If $iNumLi > 24 Then ; 0 to 24 = 25 checkbox controls per column (x 7 columns => 175 languages max. with these coords. Actually 133) $iLeft += 125 $iNumLi = 0 EndIf $idCheckbox[$i] = GUICtrlCreateCheckbox($aLang[$i][1], $iLeft, $iTop + $iNumLi * 25, 115, 25, _ $bRTL _ ? BitOr($BS_RIGHTBUTTON, $BS_RIGHT) _ : -1) If $aLang[$i][2] = 1 Then ; display this language in combobox GUICtrlSetState($idCheckbox[$i], $GUI_CHECKED) GUICtrlSetBkColor($idCheckbox[$i], 0xC0FFFF) ; light blue when checked EndIf Next GUICtrlCreateGroup("", -99, -99, 1, 1) Local $idCheckAll = GUICtrlCreateButton("Check All", 150, 7, 100, 30) Local $idUncheckAll = GUICtrlCreateButton("Uncheck All", 270, 7, 100, 30) Local $idOk = GUICtrlCreateButton("Ok", 520, 7, 100, 30) Local $idCancel = GUICtrlCreateButton("Cancel", 640, 7, 100, 30) GUISetState(@SW_SHOW) Local $idMsg, $iLangGuiNew While 1 $idMsg = GUIGetMsg() Switch $idMsg Case $idCancel ; no $GUI_EVENT_CLOSE here, as GUI close button disabled just after GUI creation. Also Opt("GUICloseOnESC", 0) $aLang = $aLang_backup $aLink = $aLink_backup $sLang = $sLang_backup $iLangGui = $iLangGui_backup $bRTL = $bRTL_backup ExitLoop Case $idMenuItem[0] To $idMenuItem[$iCountGui_Lang - 1] ; ex. 30 To 68 when 39 GUI languages $iLangGuiNew = 4 * ($idMsg - $idMenuItem[0]) ; 0, 4, 8, 12, ... , 152 (when 39 GUI languages) If $iLangGuiNew <> $iLangGui Then _ChangeGuiLang($hGUI2, $iLangGuiNew, $idCheckbox) Case $idCheckbox[0] To $idCheckbox[$iMaxLanguages - 1] ; ex. 70 To 202 when 133 translatable languages... ; ...surrounded by 2 GUICtrlCreateGroup("") i.e. controls #69 & #203 If GUICtrlRead($idMsg) = $GUI_CHECKED Then GUICtrlSetBkColor($idMsg, 0xC0FFFF) ; light blue when checked $aLang[$idMsg - $idCheckbox[0]][2] = 1 ; display this language in combobox Else GUICtrlSetBkColor($idMsg, $GUI_BKCOLOR_DEFAULT) $aLang[$idMsg - $idCheckbox[0]][2] = "" ; do not display this language in combobox EndIf Case $idCheckAll GUISetState(@SW_LOCK, $hGui2) ; "Lock the window to avoid repainting" For $i = 0 To $iMaxLanguages - 1 GUICtrlSetState($idCheckbox[$i], $GUI_CHECKED) GUICtrlSetBkColor($idCheckbox[$i], 0xC0FFFF) ; light blue when checked $aLang[$i][2] = 1 ; display this language in combobox Next GUISetState(@SW_UNLOCK, $hGui2) ; "Unlock the window to allow repainting" Case $idUncheckAll GUISetState(@SW_LOCK, $hGui2) For $i = 0 To $iMaxLanguages - 1 GUICtrlSetState($idCheckbox[$i], $GUI_UNCHECKED) GUICtrlSetBkColor($idCheckbox[$i], $GUI_BKCOLOR_DEFAULT) $aLang[$i][2] = "" ; do not display this language in combobox Next GUISetState(@SW_UNLOCK, $hGui2) Case $idOk For $i = 0 To $iMaxLanguages - 1 ; test if one language (at least) is checked If GUICtrlRead($idCheckbox[$i]) = $GUI_CHECKED Then ExitLoop Next If $i = $iMaxLanguages Then ; no language checked MsgBox(BitOr($MB_TOPMOST, $MB_ICONWARNING), "Warning", "Please check at least 1 language", 0, $hGUI2) ContinueLoop EndIf ; at this stage $aLang[][2] Col 2 is fully up to date (1 = display this language in combobox, or "" = do not display) Local $iCountChecked = 0, $iNew_ItemFrom = -1, $iNew_ItemTo = -1 Dim $aLink[$iMaxLanguages] $sLang = "" For $i = 0 To $iMaxLanguages - 1 If GUICtrlRead($idCheckbox[$i]) = $GUI_CHECKED Then $iCountChecked += 1 ; 1+ $aLink[$iCountChecked - 1] = $i ; ex. $aLink[0] = 10 (1st combobox item links to row 10 in $aLang) , $aLink[1] = 27 etc... $sLang &= $aLang[$i][1] & "|" If $bCheck_ItemFrom And $aLang[$i][0] = $sOld_CodeFrom Then $iNew_ItemFrom = $iCountChecked ; 1+ (remember item 0 <=> "Detect language" or "Sprache erkennen" or etc...) $bCheck_ItemFrom = False EndIf If $bCheck_ItemTo And $aLang[$i][0] = $sOld_CodeTo Then $iNew_ItemTo = $iCountChecked - 1 ; 0+ $bCheck_ItemTo = False EndIf EndIf Next Redim $aLink[$iCountChecked] ; delete all superfluous empty rows (quick) GUICtrlSetData($idLangFrom, "|" & $aLangGui[$iLangGui + 2] & "|" & $sLang) ; "|" at beginning destroys the previous list (help file) GUICtrlSetData($idLangTo, "|" & $sLang) If $bRTL <> $bRTL_backup Then ; redraw both combo (RTL or LTR) If $bRTL Then _WinAPI_SetWindowLong(GUICtrlGetHandle($idLangFrom), $GWL_EXSTYLE, _ BitOr($WS_EX_LEFTSCROLLBAR, $WS_EX_RTLREADING, $WS_EX_RIGHT)) _WinAPI_SetWindowLong(GUICtrlGetHandle($idLangTo), $GWL_EXSTYLE, _ BitOr($WS_EX_LEFTSCROLLBAR, $WS_EX_RTLREADING, $WS_EX_RIGHT)) Else _WinAPI_SetWindowLong(GUICtrlGetHandle($idLangFrom), $GWL_EXSTYLE, 0) ; combobox don't have default exstyles (help file error) _WinAPI_SetWindowLong(GUICtrlGetHandle($idLangTo) , $GWL_EXSTYLE, 0) EndIf EndIf If $iNew_ItemFrom = - 1 Then ; old language From has been unchecked OR $iOld_ItemFrom = 0 GUICtrlSendMsg($idLangFrom, $CB_SETCURSEL, 0, 0) ; ex. "Detect language" or "Sprache erkennen" or etc... _WinAPI_SetWindowLong(GUICtrlGetHandle($idTextFrom), $GWL_EXSTYLE, $WS_EX_CLIENTEDGE) ; default extended style value in Edit field Else ; 1+ GUICtrlSendMsg($idLangFrom, $CB_SETCURSEL, $iNew_ItemFrom, 0) EndIf If $iNew_ItemTo = - 1 Then ; old language To has been unchecked OR $iOld_ItemTo = -1 GUICtrlSendMsg($idLangTo, $CB_SETCURSEL, -1, 0) ; blank the "Language To" selection GUICtrlSetData($idTextTo, "") ; clear the eventual translated text _WinAPI_SetWindowLong(GUICtrlGetHandle($idTextTo), $GWL_EXSTYLE, $WS_EX_CLIENTEDGE) ; default extended style value in Edit field Else ; 0+ GUICtrlSendMsg($idLangTo, $CB_SETCURSEL, $iNew_ItemTo, 0) EndIf If $iNew_ItemFrom > 0 And $iNew_ItemTo > -1 Then WinSetTitle($hGUI, "", "Translated From " & _ $aLang[$aLink[$iNew_ItemFrom - 1]][1] & " To " & $aLang[$aLink[$iNew_ItemTo]][1]) Else WinSetTitle($hGUI, "", _GuiTitle()) ; display the generic GUI title (which doesn't mention any translation language) EndIf ExitLoop EndSwitch WEnd GUIDelete($hGUI2) EndFunc ;==>_LanguageFilter ;============================================== Func _ChangeGuiLang(Const $hGUI2, Const $iLangGuiNew, Const ByRef $idCheckbox) ; ConsoleWrite($iLangGui & " " & $iLangGuiNew & @crlf) ; both can be 0, 4, 8, 12, ..., 152 (when 39 Gui languages) Local $bRTL_old = $bRTL ; define this variable before _FillArrayLang() ; Remap the links between the 2 language arrays (before redrawing all checkbox) Local $iIndex, $aLangNew = _FillArrayLang($aLangGui[$iLangGuiNew]) ; 3rd column of $aLangNew is empty at this stage ; $iLangGui & $bRTL redefined during _FillArrayLang() ... ; ... which means, from now on, $iLangGui = $iLangGuiNew For $i = 0 To Ubound($aLang) - 1 If Not $aLang[$i][2] Then ContinueLoop $iIndex = _ArraySearch($aLangNew, $aLang[$i][0], 0, 0, 1, 2, 1, 0) ; 2 = exact match, last 0 = search in col 0 of a 2D array If $iIndex > -1 Then $aLangNew[$iIndex][2] = 1 ; same language code (displayed in combobox) will very often have a different index in the new array. Else MsgBox(BitOr($MB_TOPMOST, $MB_ICONWARNING), "Serious warning", _ "Code language '" & $aLang[$i][0] & "' not found in " & $aLangGui[$iLangGui + 1] & @crlf & _ "Language text file is corrupted", 0, $hGUI2) EndIf Next ; redraw all checkbox with their captions reflecting the new language, tick the ones that need to be ticked, take care of LTR / RTL GUISetState(@SW_LOCK, $hGui2) ; Lock the window to avoid repainting Local $iStyle = _WinAPI_GetWindowLong(GUICtrlGetHandle($idCheckbox[0]), $GWL_STYLE) ; all 133 checkbox got the same style, pick any one. For $i = 0 To Ubound($aLang) - 1 If $bRTL <> $bRTL_old Then _WinAPI_SetWindowLong(GUICtrlGetHandle($idCheckbox[$i]), $GWL_STYLE, _ $bRTL _ ? BitOr ($iStyle, $BS_RIGHTBUTTON, $BS_RIGHT) _ : BitXOr($iStyle, $BS_RIGHTBUTTON, $BS_RIGHT)) EndIf GUICtrlSetData($idCheckbox[$i], $aLangNew[$i][1]) If $aLangNew[$i][2] = 1 Then ; display this language in combobox GUICtrlSetState($idCheckbox[$i], $GUI_CHECKED) GUICtrlSetBkColor($idCheckbox[$i], 0xC0FFFF) ; light blue when checked Else GUICtrlSetState($idCheckbox[$i], $GUI_UNCHECKED) GUICtrlSetBkColor($idCheckbox[$i], $GUI_BKCOLOR_DEFAULT) EndIf Next WinSetTitle($hGUI2, "", _GuiTitle(2)) GUISetState(@SW_UNLOCK, $hGui2) ; Unlock the window to allow repainting $aLang = $aLangNew ; note that $iLangGui and $bRTL have been updated during _FillArrayLang() EndFunc ;==>_ChangeGuiLang ;============================================== Func _ReadIniFile($sIniFile, ByRef $aLang, ByRef $aLink, ByRef $sLang) If FileExists($sIniFile) Then Local $aIni = FileReadToArray($sIniFile) If @extended <> 9 Then MsgBox($MB_TOPMOST, "_FileReadToArray: extended = " & @extended, _ "Ini file should have exactly 9 lines, not " & @extended & @crlf & _ "(this message is normal if you just upgraded the script to a new version.)" & @crlf & _ "" & @crlf & _ "Incompatible .ini file will be deleted now, please run the script again.") FileDelete($sIniFile) Exit EndIf For $i = 0 To 5 $aIni[$i] = Number($aIni[$i]) ; Number, or serious issues later with GUICtrlSendMsg() Next $aLink = StringSplit($aIni[6], ",", $STR_NOCOUNT) $aLang = _FillArrayLang(StringStripWS($aIni[7], $STR_STRIPLEADING + $STR_STRIPTRAILING)) ; ex. $aIni[7] = "en" or "de" or etc... ; (GUI interface for the language names) For $i = 0 To Ubound($aLink) - 1 $aLang[$aLink[$i]][2] = 1 ; display this language in ComboBox $sLang &= $aLang[$aLink[$i]][1] & "|" ; "a trailing GUIDataSeparatorChar is ignored" (help file, topic GUICtrlSetData for combo & list control) Next $aIni[8] = Number($aIni[8]) ; _ArrayDisplay($aIni, "Existing ini file") $aIni[6] = "" ; string not needed anymore (no big deal, just to match same behavior when ini file doesn't exist) Else ; ini file doesn't exist Local $aIni[9] $aIni[0] = 0 ; Language From (combobox) (force 'Detect Language' when .ini file doesn't exist) $aIni[1] = 11 ; Font Size for edit control original text $aIni[2] = 1 ; Word wrap for edit control original text (1 = checked, 4 = unchecked) $aIni[3] = -1 ; Language To (combobox) (forced to -1 [unselected] when .ini file doesn't exist) $aIni[4] = 11 ; Font Size for edit control translated text $aIni[5] = 1 ; Word wrap for edit control translated text (1 = checked, 4 = unchecked) ; $aIni[6] : nothing special about $aIni[6] when ini file doesn't exist. $aIni[7] = "en" ; Suggest english GUI interface when no ini file (i.e. language names in english) though it's changeable here $aIni[8] = 9.3 ; Font Size for both combobox (decrease by clicking LABEL $idLabelFrom, increase by clicking LABEL $idLabelTo) $aLang = _FillArrayLang($aIni[7]) Dim $aLink[Ubound($aLang)] For $i = 0 To Ubound($aLang) - 1 ; add all languages in $sLang when ini file doesn't exist (user will keep those he needs, later) $aLang[$i][2] = 1 ; 1 = display this language in ComboBox ("" = don't display it) $aLink[$i] = $i ; link between combobox item # and row in $aLang . This will be useful if user unchecks some languages he doesn't need $sLang &= $aLang[$i][1] & "|" ; "a trailing GUIDataSeparatorChar is ignored" (help file, topic GUICtrlSetData for combo & list control) Next ; _ArrayDisplay($aIni, "New ini file") EndIf Return $aIni EndFunc ;==>_ReadIniFile ;============================================== Func _WriteIniFile($sIniFile, Const ByRef $aLink) Local $hIni = FileOpen($sIniFile, $FO_OVERWRITE) If $hIni = -1 Then MsgBox($MB_TOPMOST, "FileOpen error", $sIniFile, 0, $hGUI) ; 5th param prevents clicking inside the GUI Else FileWrite($hIni, _ GUICtrlSendMsg($idLangFrom, $CB_GETCURSEL, 0, 0) & @crlf & _ Int(GUICtrlRead($idFontSizeFrom)) & @crlf & _ GUICtrlRead($idWordWrapFrom) & @crlf & _ GUICtrlSendMsg($idLangTo, $CB_GETCURSEL, 0, 0) & @crlf & _ Int(GUICtrlRead($idFontSizeTo)) & @crlf & _ GUICtrlRead($idWordWrapTo) & @crlf & _ _ArrayToString($aLink, ",") & @crlf & _ $aLangGui[$iLangGui] & @crlf & _ ; ex. "en" or "de" etc... (it will be the GUI interface for the language names, on next launch) $aIni[8]) ; So there are 9 lines in ini file (no need of a last @crlf , though it is allowed but not mandatory) FileClose($hIni) EndIf EndFunc ;==>_WriteIniFile ;============================================== Func _EditRecreate_From($iFontSize, $iWordWrap) Local $idEdit_Old = $idTextFrom ; 0 at first passage Local $iExStyle If $idEdit_Old Then Local $aPos = ControlGetPos($hGUI, "", $idEdit_Old) Local $sText = GUICtrlRead($idEdit_Old) Local $aSel = _GUICtrlEdit_GetSel($idEdit_Old) $iExStyle = _WinAPI_GetWindowLong(GUICtrlGetHandle($idEdit_Old), $GWL_EXSTYLE) GUICtrlDelete($idEdit_Old) Else ; 1st passage Local $aPos[4] = [10, 100, 880, 275] Local $iItemFrom = GUICtrlSendMsg($idLangFrom, $CB_GETCURSEL, 0, 0) Local $sLangFrom = ($iItemFrom = 0) ? "auto" : $aLang[$aLink[$iItemFrom - 1]][0] ; ex. "auto", "en", de", ... $iExStyle = _IsRTL($sLangFrom) _ ? BitOR($WS_EX_LEFTSCROLLBAR, $WS_EX_RTLREADING, $WS_EX_RIGHT, $WS_EX_CLIENTEDGE) _ : -1 ; -1 is the default value ($WS_EX_CLIENTEDGE) used by GUICtrlCreateEdit below EndIf Local $idTextFrom = GUICtrlCreateEdit("", $aPos[0], $aPos[1], $aPos[2], $aPos[3], _ (($iWordWrap = 1) _ ; Word wrap (1 = unchecked, 4 = checked) ? BitOr($ES_WANTRETURN, $WS_VSCROLL, $ES_AUTOVSCROLL) _ : -1), _ $iExStyle) ; new control ID (1st passage) or same control ID as the deleted edit control (2nd+ passage) => no gap in id's controls list GUICtrlSetFont(-1, $iFontSize) GUICtrlSetState(-1, $GUI_DROPACCEPTED) GUICtrlSendMsg(-1, $EM_LIMITTEXT, $iMaxInputLength, 0) If $idEdit_Old Then _GUICtrlEdit_SetText($idTextFrom, $sText) If $aSel[0] <> $aSel[1] Then _GUICtrlEdit_SetSel($idTextFrom, $aSel[0], $aSel[1]) EndIf Return $idTextFrom EndFunc ;==>_EditRecreate_From ;============================================== Func _EditRecreate_To($iFontSize, $iWordWrap) Local $idEdit_Old = $idTextTo ; 0 at first passage Local $iExStyle If $idEdit_Old Then Local $aPos = ControlGetPos($hGUI, "", $idEdit_Old) Local $sText = GUICtrlRead($idEdit_Old) Local $aSel = _GUICtrlEdit_GetSel($idEdit_Old) $iExStyle = _WinAPI_GetWindowLong(GUICtrlGetHandle($idEdit_Old), $GWL_EXSTYLE) GUICtrlDelete($idEdit_Old) Else ; 1st passage Local $aPos[4] = [10, 410, 880, 275] Local $iItemTo = GUICtrlSendMsg($idLangTo, $CB_GETCURSEL, 0, 0) If $iItemTo = -1 Then ; no "Language To" selected $iExStyle = -1 ; -1 is the default value ($WS_EX_CLIENTEDGE) used by GUICtrlCreateEdit below Else Local $sLangTo = $aLang[$aLink[$iItemTo]][0] ; ex. "en", "de", ... $iExStyle = _IsRTL($sLangTo) _ ? BitOR($WS_EX_LEFTSCROLLBAR, $WS_EX_RTLREADING, $WS_EX_RIGHT, $WS_EX_CLIENTEDGE) _ : -1 ; -1 is the default value ($WS_EX_CLIENTEDGE) EndIf EndIf Local $idTextTo = GUICtrlCreateEdit("", $aPos[0], $aPos[1], $aPos[2], $aPos[3], _ (($iWordWrap = 1) _ ; Word wrap (1 = unchecked, 4 = checked) ? BitOr($ES_WANTRETURN, $WS_VSCROLL, $ES_AUTOVSCROLL) _ : -1), _ $iExStyle) ; new control ID (1st passage) or same control ID as the deleted edit control (2nd+ passage) => no gap in id's controls list GUICtrlSetFont(-1, $iFontSize) GUICtrlSendMsg(-1, $EM_LIMITTEXT, -1, 0) ; allow unlimited text size in edit control (translated text) If $idEdit_Old Then _GUICtrlEdit_SetText($idTextTo, $sText) If $aSel[0] <> $aSel[1] Then _GUICtrlEdit_SetSel($idTextTo, $aSel[0], $aSel[1]) EndIf Return $idTextTo EndFunc ;==>_EditRecreate_To ;============================================== Func _OpenFile() Local $sFileName = FileOpenDialog( _ "Open Text or PDF file", _ @ScriptDir, _ "Text or PDF (*.txt;*.pdf)", _ BitOR($FD_FILEMUSTEXIST, $FD_PATHMUSTEXIST), _ "", _ $hGUI) If @error Then ;~ MsgBox($MB_TOPMOST, "Open File", _ ;~ "No file selected ", 0, $hGUI) ; FileOpenDialog() was exited by Cancel/Red X button, or by Esc key Return ; 0 EndIf ; Change the working directory (@WorkingDir) back to the location of the script directory as FileOpenDialog sets it to the last accessed folder (on successful return) ; FileChangeDir(@ScriptDir) Return $sFileName EndFunc ;==>_OpenFile ;============================================== Func _PdfToText(Const $sInputFileName) Local Static $sPdfToText = @ScriptDir & ((@OSVersion <> "WIN_XP") ? "\pdftotext.exe" : "\pdftotext40.exe") Local Static $sOutputFileName = @ScriptDir & "\TextExtractedFromPDF.txt" If Not FileExists($sPdfToText) Then MsgBox($MB_TOPMOST, "PDF : missing extractor file", _ "To translate a pdf, you need the file 'pdftotext.exe'" & @crlf & _ "" & @crlf & _ "It can be downloaded at https://www.xpdfreader.com" & @crlf & _ "then place it in same folder as the script", 0, $hGUI) _UpdateGUI($sEmpty) Return ; 0 EndIf Local $sCommand = " /c" & " " & _ chr(34) & chr(34) & $sPdfToText & chr(34) & " " & _ "-enc UTF-8" & " " & _ chr(34) & $sInputFileName & chr(34) & " " & _ chr(34) & $sOutputFileName & chr(34) & chr(34) Local $iRet = RunWait(@ComSpec & $sCommand, @ScriptDir, @SW_HIDE) Select Case @error MsgBox($MB_TOPMOST, "RunWait: error " & @error, _ "AutoIt error, please check AutoIt code", 0, $hGUI) Return ; 0 Case $iRet Local $sErr = "" ; following exit codes (from 0 To 99) are found in PdfToText documentation, except the personal "Case Else" Switch $iRet ;~ Case 0 ;~ $sErr = "No error." Case 1 $sErr = "Error opening a PDF file." Case 2 $sErr = "Error opening an output file." Case 3 $sErr = "Error related to PDF permissions." Case 98 $sErr = "Out of memory." ; this exit code 98 was added in last version 4.05 of pdftotxt.exe (released on Feb 8, 2024) Case 99 $sErr = "Other error." Case Else ; should never happen $sErr = "This error isn't found in PdfToText documentation !" EndSwitch MsgBox($MB_TOPMOST, "PdfToText exit code: error " & $iRet, _ $sErr, 0, $hGUI) _UpdateGUI($sEmpty) Return ; 0 EndSelect ; all is good from now on ($iRet = 0, which means no error returned from pdftotext.exe) Return $sOutputFileName EndFunc ;==>_PdfToText ;============================================== Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam) ; Local $hWndFrom = $lParam ; Local $iIDFrom = _WinAPI_LoWord($wParam) Local $iIDFrom = BitAND($wParam, 0xFFFF) ; same (cf WinAPIConv.au3) ; Local $iCode = _WinAPI_HiWord($wParam) Local $iCode = BitShift($wParam, 16) ; same (cf WinAPIConv.au3) Switch $iIDFrom Case $idTextFrom If $iCode = $EN_UPDATE Then ; Sent when an edit control is about to redraw itself _UpdateCharStatus() EndIf Case $idLangFrom If $iCode = $CBN_CLOSEUP Or $iCode = $CBN_KILLFOCUS Then Local $iExStyle_Old = _WinAPI_GetWindowLong(GUICtrlGetHandle($idTextFrom), $GWL_EXSTYLE) ; Edit field From Local $iItemFrom = GUICtrlSendMsg($idLangFrom, $CB_GETCURSEL, 0, 0) Local $sLangFrom = ($iItemFrom = 0) ? "auto" : $aLang[$aLink[$iItemFrom - 1]][0] ; ex. "auto", "en", de", ... Local $iExStyle_New = _IsRTL($sLangFrom) _ ? BitOR($WS_EX_LEFTSCROLLBAR, $WS_EX_RTLREADING, $WS_EX_RIGHT, $WS_EX_CLIENTEDGE) _ : $WS_EX_CLIENTEDGE ; $WS_EX_CLIENTEDGE is the default extended style value in Edit field If $iExStyle_New <> $iExStyle_Old Then _WinAPI_SetWindowLong(GUICtrlGetHandle($idTextFrom), $GWL_EXSTYLE, $iExStyle_New) EndIf EndIf Case $idLangTo If $iCode = $CBN_CLOSEUP Or $iCode = $CBN_KILLFOCUS Then Local $iExStyle_Old = _WinAPI_GetWindowLong(GUICtrlGetHandle($idTextTo), $GWL_EXSTYLE) ; Edit field To Local $iItemTo = GUICtrlSendMsg($idLangTo, $CB_GETCURSEL, 0, 0) If $iItemTo = -1 Then ; no "Language To" selected Local $iExStyle_New = $WS_EX_CLIENTEDGE ; $WS_EX_CLIENTEDGE is the default extended style value in Edit field Else Local $sLangTo = $aLang[$aLink[$iItemTo]][0] ; ex. "en", "de", ... Local $iExStyle_New = _IsRTL($sLangTo) _ ? BitOR($WS_EX_LEFTSCROLLBAR, $WS_EX_RTLREADING, $WS_EX_RIGHT, $WS_EX_CLIENTEDGE) _ : $WS_EX_CLIENTEDGE ; $WS_EX_CLIENTEDGE is the default extended style value in Edit field EndIf If $iExStyle_New <> $iExStyle_Old Then _WinAPI_SetWindowLong(GUICtrlGetHandle($idTextTo), $GWL_EXSTYLE, $iExStyle_New) EndIf EndIf EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>WM_COMMAND ;============================================== Func _UpdateCharStatus() Local $iChars = GUICtrlSendMsg($idTextFrom, $WM_GETTEXTLENGTH, 0, 0) ; same as _GUICtrlEdit_GetTextLen($idTextFrom) ? Select Case $iChars > $iMaxInputLength GUICtrlSetData($idTextFrom, StringLeft(GUICtrlRead($idTextFrom), $iMaxInputLength)) ContinueCase Case $iChars = $iMaxInputLength GUICtrlSetData($idCharStatus, $iMaxInputLength & " / " & $iMaxInputLength) GUICtrlSetBkColor($idCharStatus, 0xFF4040) ; reddish Case Else ; i.e. $iChars < $iMaxInputLength GUICtrlSetData($idCharStatus, $iChars & " / " & $iMaxInputLength) GUICtrlSetBkColor($idCharStatus, ($iChars <= 5460) ? 0x80FF80 : 0xFFFF00) ; greenish => ok, yellow => encoded string may become too long. EndSelect EndFunc ;==>_UpdateCharStatus ;============================================== Func _ErrFuncLocal($oError) ; https://www.autoitscript.com/forum/topic/191401-com-error-handling-in-a-udf-best-practice/?do=findComment&comment=1373102 MsgBox($MB_TOPMOST, @ScriptName & " (" & $oError.scriptline & ") : ==> Local COM error handler - COM Error intercepted !", _ @Tab & "err.number is: " & @Tab & @Tab & "0x" & Hex($oError.number) & @crlf & _ @Tab & "err.windescription:" & @Tab & @Tab & StringStripWS($oError.windescription, 2) & @crlf & _ @Tab & "err.description is: " & @Tab & @Tab & StringStripWS($oError.description, 2) & @crlf & _ @Tab & "err.source is: " & @Tab & @Tab & $oError.source & @crlf & _ @Tab & "err.helpfile is: " & @Tab & @Tab & $oError.helpfile & @crlf & _ @Tab & "err.helpcontext is: " & @Tab & @Tab & $oError.helpcontext & @crlf & _ @Tab & "err.lastdllerror is: " & @Tab & @Tab & $oError.lastdllerror & @crlf & _ @Tab & "err.scriptline is: " & @Tab & @Tab & $oError.scriptline & @crlf & _ @Tab & "err.retcode is: " & @Tab & @Tab & "0x" & Hex($oError.retcode), 0, $hGUI) EndFunc ;==>_ErrFuncLocal ;============================================== Func _Wanna_Quit() ; in case user keys Esc during the translation process HotKeySet("{ESC}") If WinActive($hGUI) Then MouseMove(@DesktopWidth / 2, @DesktopHeight / 2, 0) ; 0 = fastest move If MsgBox(BitOr($MB_TOPMOST, $MB_OKCANCEL, $MB_DEFBUTTON2), _ "Esc was keyed", "Quit translation script ?", 0, $hGUI) = $IDOK Then GUIDelete($hGUI) Exit EndIf Else ; Esc was keyed when another application was on top Send("{ESC}") EndIf HotKeySet("{ESC}", "_Wanna_Quit") EndFunc ;_Wanna_Quit ;============================================== Func _FillArrayLangGUI($sFileName) ; Text file containing a list of 39 languages & codes (for GUI) found patiently on Google translate web site, one by one... Local $sFilePath = @ScriptDir & "\" & $sFileName If Not FileExists($sFilePath) Then Exit MsgBox($MB_TOPMOST, "File not found", $sFilePath) Local $s_String = FileRead($sFilePath) If @error Then Exit MsgBox($MB_TOPMOST, "FileRead : error " & @error, $sFilePath) ; this shouldn't happen, but who knows ? Local $sPattern = '(?i)Language code\h*:?\h*(.+?)\h*\R+\h*Language name\h*:?\h*(.+?)\h*\R+\h*\["auto","(.+?)"],(\[".+"])\h*(?:\R+|$)' Local $aArray = StringRegExp($s_String, $sPattern, 3) If @error Then Exit MsgBox($MB_TOPMOST, "StringRegExp", _ "error = " & @error & (@error = 1 ? " (no matches)" : " (bad pattern)") & @crlf & _ "" & @crlf & _ $sFilePath) If Mod(Ubound($aArray), 4) Then _ArrayDisplay($aArray, "Malformed txt file : number of rows should be a multiple of 4") Exit MsgBox($MB_TOPMOST, "error", _ "Please install a correct language text file" & @crlf & _ "" & @crlf & _ $sFilePath) EndIf ; _ArrayDisplay($aArray, (Ubound($aArray) / 4) & " GUI languages codes & names") Return $aArray EndFunc ;==>_FillArrayLangGUI ;============================================== Func _FillArrayLang($sCode) For $i = 0 To Ubound($aLangGui) - 1 Step 4 ; 4 consecutive rows (in $aLangGui) contain the characteristics of each GUI language If $aLangGui[$i] = $sCode Then ExitLoop ; ex. "en" or "de" etc... Next If $i > Ubound($aLangGui) - 1 Then Exit MsgBox($MB_TOPMOST, 'error', _ 'Language code "' & $sCode & '" not retrieved in language text file' & @crlf & _ 'Please install a correct language text file (and delete your eventual ini file)') $iLangGui = $i ; important global variable indicating the row where starts the characteristics of the actual Gui language. ; its value is 0, 4, 8, 12...152 (when 39 Gui languages) Local $s_String = $aLangGui[$iLangGui + 3] ; string of 133 languages, for ex. ["af","Afrikaans"],["sq","Albanian"],[...],["zu","Zulu"] ; suppress eventual leading & trailing whitespaces ; Regexp Pattern in _FillArrayLangGUI() has already checked this => comment out the test below ; $s_String = StringStripWS($s_String, $STR_STRIPLEADING + $STR_STRIPTRAILING) ; check the string starts with an opening bracket followed by a double quote, then ends with a double quote followed by a closing bracket ; Regexp Pattern in _FillArrayLangGUI() has already checked this => comment out the test below ; If StringLeft($s_String, 2) <> '["' Or StringRight($s_String, 2) <> '"]' Then Exit MsgBox($MB_TOPMOST, _ ; 'Language code "' & $sCode & '" : bracket and double quote error inside language text file', _ ; 'The first 2 characters of the string must be ["' & @crlf & _ ; 'The last 2 characters of the string must be "]') ; beginning of string : suppress leading opening bracket and first double quote ; end of string : suppress last double quote and trailing closing bracket $s_String = StringMid($s_String, 3, StringLen($s_String) - 4) ; Split the string in a 2D array (2 columns) with a 3rd empty column added for further usage (5th param. of _StringSplit2D_EX) Local $aArray = _StringSplit2D_EX($s_String, '","', '"],["', False, 1) If @error Then Exit MsgBox($MB_TOPMOST, "_StringSplit2D_EX : error " & @error, _ "All rows don't have the same number of fields" & @crlf & _ "Please install a correct language text file") If Ubound($aArray, $UBOUND_COLUMNS) <> 3 Then Exit MsgBox($MB_TOPMOST, _ "error : number of columns = " & Ubound($aArray, $UBOUND_COLUMNS), _ "It should be 3 (last column being empty for further usage)" & @crlf & _ "Please install a correct language text file") $bRTL = _IsRTL($sCode) ; True if language is RTL, False if not Return $aArray EndFunc ;==>_FillArrayLang ;============================================== Func _IsRTL($sCode) ; June 2024 : 10 languages are RTL amongst the 133 traductable languages (tested) ; Place them all in the string below, though only 3 of them are accessible from the 39 GUI languages (Arabic, Hebrew, Persian) ; Arabic (ar) , Dhivehi (dv), Hebrew (iw), Kurdish (Sorani) (ckb), Pashto (ps) ; Persian (fa), Sindhi (sd), Urdu (ur), Uyghur (ug), Yiddish (yi) ; Note : in version 10+ the whole list (10 RTL languages) is checked in case of 1 or 2 edit fields are RTL (in edit creation & WM_COMMAND) Local Static $sRTL = "ar,dv,iw,ckb,ps,fa,sd,ur,ug,yi," ; end the string with a comma (to make the search easy on next line) Return (StringInStr($sRTL, $sCode & ",") > 0) ? True : False EndFunc ;==>_IsRTL ;============================================== Func _GuiTitle($iGui = 0) Local $sTitle Switch $iGui Case 0 ; add GUI language code (which may change during the script) to the string, so user knows what GUI language is actually set. ; ex. "Google Translation (v10 - en)" $sTitle = StringTrimRight($sGUI_Title, 1) & " - " & $aLangGui[$iLangGui] & ")" Case 2 ; add GUI language name to the string ; ex. "GUI language (English) & Languages filter" $sTitle = "GUI language (" & $aLangGui[$iLangGui + 1] & ") & Languages filter" Case Else $sTitle = "Scripter, where are you ?" EndSwitch Return $sTitle EndFunc ;==>_GuiTitle ;============================================== Func _StringSplit2D_EX(ByRef $sString, $sDelim_Col = "|", $sDelim_Row = @CRLF, $bExpand = False, $iAdd_EmptyCol = 0) ; based on AspirinJunkie's function _StringSplit2D found at https://autoit.de/thread/85380-1d-array-in-2d-array-splitten/ ; Thanks Nine for suggesting the 4th parameter $bExpand, to allow or not the same number of fields per row (as in _FileReadToArray) Local $a_FirstDim = StringSplit($sString, $sDelim_Row, $STR_ENTIRESPLIT + $STR_NOCOUNT) Local $iKeep_NbCol = Ubound(StringSplit($a_FirstDim[0], $sDelim_Col, $STR_ENTIRESPLIT + $STR_NOCOUNT)) ; keep nb cols row 0 Local $a_Out[UBound($a_FirstDim)][1 + $iAdd_EmptyCol], $a_Line, $i_2DMax = 1 For $i = 0 To UBound($a_FirstDim) - 1 $a_Line = StringSplit($a_FirstDim[$i], $sDelim_Col, $STR_ENTIRESPLIT + $STR_NOCOUNT) If (Not $bExpand) And (Ubound($a_Line) <> $iKeep_NbCol) Then Return SetError(3, 0, 0) ; same error # as _FileReadToArray If UBound($a_Line) > $i_2DMax Then ; when $bExpand = False, this test will be True maximum 1 time, never more. $i_2DMax = UBound($a_Line) ReDim $a_Out[UBound($a_Out)][$i_2DMax + $iAdd_EmptyCol] EndIf For $j = 0 To UBound($a_Line) - 1 $a_Out[$i][$j] = $a_Line[$j] Next Next Return $a_Out EndFunc ;==>_StringSplit2D_EX Please indicate if something doesn't work correctly as I just finished the script a few minutes ago. Have a great day * Update June 7, 2024 (version 7) If you don't need all 133 language names (in both combobox) and prefer to display less names for a better visibility, then it's easily doable as explained in my post just below * Update June 23, 2024 (version 9) list of changes below in this thread, here * Update June 27, 2024 (version 10) this will be probably my final update (unless a bug is discovered in the script) + Added code to take care of possible RTL edit fields (10 languages amongst 133) during Edit controls creation, or during the registered WM_COMMAND function (test on $CBN_CLOSEUP, $CBN_KILLFOCUS etc...) + Minor cosmetic changes * Update June 30, 2024 (version 11) Pdf files can now be opened for translation. Instructions to download the free utility "pdftotext" are found in the post below Google Translate (languages list #3).zip
    3 points
  2. Hey guys, I think I figured it out. You all testing it helped. Turns out the Bitdefender Antivirus was detecting AutoIT process as potential malware under the Advanced Threat Control Module. Making a process exception worked.
    1 point
  3. Changed the colors for my dark theme maybe you can add it in a next build Thanks for sharing. Nice tool to have.
    1 point
  4. Thank you ! It work this way : _WD_Option('Driver', @ScriptDir&'\include\'&(@Compiled?'':'Exe_externe\')&'geckodriver.exe') _WD_Option('DriverParams', '--log trace ') _WD_Option('Port', 4444) _WD_Option('DriverParams', '--marionette-port 2828') $sDesiredCapabilities = '{"capabilities":{"alwaysMatch": {"moz:firefoxOptions": {"args": ["about:blank", "-profile", "C:/ProWeb/Projets/ProWeb/version/scénarios/k736nmka.default"],"log": {"level": "trace"},"prefs": {"browser.download.improvements_to_download_panel": false}}}}}'
    1 point
  5. TheSaint

    Kobo Cover Fixer

    I'm almost done. Spent most of yesterday, when not celebrating my daughter's birthday and dealing with a visitor, modifying my program. The placebo stuff is now redundant of course, so had to get rid of that, which took some doing. Still have to clean up some that is just disabled. I then used that GUI portion for some new buttons, and resized some other controls and added in a CLONE button as well. I've implemented the new compiled Python script, used by the DETERMINE button, and it works well. Not visible in the screenshot is an extra column for the ImageID, which has been present and hidden almost from the beginning of development. And when you select an entry now, that has no images listed, the ImageID displays in a temporarily re-purposed and resized input field along with accompanying pink label. By the way, 5 days ago was the anniversary of when I first started working on this program ... 25 May 2023. I worked on it solidly for almost a month, and then put it aside, until a few days ago. And I have now been able to achieve, at least in theory still, what I could not back then. That said, I did achieve a few useful aspects back then. I could fix things for ebooks that lacked an image or two or had bad images, as many of my side-loaded ones did. The only thing I could not achieve, was where no images existed at all, and so we could not determine what folder to use for the missing three images for an ebook. Those cover images being what you see when browsing your device or the current ebook when the device is put to sleep. I have many such ebooks now, where no cover is displayed when I browse or when my Kobo device is put to sleep. I am looking forward to using my program to fix all that now. Just a few bits more to code to finalize things, and then the ultimate test, which I don't expect to fail. The first thing I will need to do, is refresh everything, because my Kobo has a lot more ebooks on it now, and so I need to retrieve the latest SQL database file from it to use with my program, plus clone all the folders in the .kobo-images folder on my PC again. And because my Kobo's USB connection is a bit flaky sometimes, I need to get things just right, and do things in a quick and timely fashion ... hence the delay, while I have added the new CLONE button, plus re-purposed the ADD button (via checkbox) to be a COPY button. I am essentially using the clone to do all necessary file and folder creation on my PC, then use the COPY button for each ebook I have fixed, using the benefit of the MARK and NEXT buttons. The idea is to spend as short a time as possible working directly with my Kobo device and that temperamental USB connection. As I think I have declared before, the USB connection seems to work fine while my Kobo is charging, but once fully charged it keeps losing the connection. P.S. I have also been held up by needing to do a refresher course of my program, and the code. I've now added some things to make that easier in future. I guess that's pretty normal when not engaging with something for almost a year. By the time I finish coding a program, I do try to make it easy to understand if not used for a while. And I will be the first to admit, that I don't always get it completely right, though I tend to generally be better at doing that these days. Keep it simple, can be a challenge with some programs, both as a user and a coder. While I am providing my still to be completed script, a bunch of things are either not fully finished or tested, so beware. WARNING - The following download is still a work-in-progress and therefor incomplete. It may give errors or more likely not do all it says yet. Kobo Cover Fixer.au3 DisplayArray.au3 GDIP.au3 Python App.html 5.94 Mb (MEGA Link in HTML referral page) That DisplayArray include, is a slightly modified _ArrayDisplay function. Basically I needed to overcome the unavoidable ExitScript functionality. No idea why that default button has to kill the whole program, with no parameter to avoid that. Usually I just avoid having that button display in my final code, but it cannot be avoided when utilizing the FUNCTION button. With my amended code it just closes the _ArrayDisplay window now.
    1 point
×
×
  • Create New...