Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Translate the specific controls in the dialog one by one
#1
Hi,
   
This is a practical, useful feature,

 In a dialog, if the role of a control is STATICTEXT or CHECKBUTTON or PUSHBUTTON , I need to translate it

 In order to make the translation faster, I thought of the following method:

 1.get all the controls text that needs to be translated
 
 2.Merge all text into one line, the delimiter is | , Replace some symbols like , :  Like this below
   hello world | hello friend | Father | Mother | my city | your country

 3.Use Google Translate the line text, and re-split the string, delimiter is |

 4.Set the translated text to the matching control

 5.When I press the hotkey Ctrl+Q again, the controls text returns to its original

In the QM code below, I've only done part of it, I can only translate the text of one control at a time
My level of programming is not very good, some are not done
this is a very comprehensive example

Thanks for any advice and help
david

Macro Tran
Code:
Copy      Help
str dd=
;BEGIN DIALOG
;0 "" 0x90C80AC8 0x0 0 0 224 136 "Press Ctrl+Q translate controls text" "4"
;3 Button 0x54032000 0x0 32 44 48 14 "Father"
;4 Button 0x54032000 0x0 144 44 48 14 "Mother"
;5 Static 0x54000000 0x0 40 16 48 13 "hello,world"
;6 Static 0x54000000 0x0 144 16 48 13 "hello: friend"
;7 Button 0x54012003 0x0 32 72 48 10 "my city"
;8 Button 0x54012003 0x0 144 72 64 10 "your country"
;9 Edit 0x54030080 0x200 8 96 72 12 ""
;10 Edit 0x54030080 0x200 144 96 72 12 ""
;1 Button 0x54030001 0x4 48 116 48 14 "OK"
;2 Button 0x54030000 0x4 120 116 48 14 "Cancel"
;END DIALOG
;DIALOG EDITOR: "" 0x2040C02 "*" "" "" ""

str controls = "7 8 9 10"
str c7my c8you e9 e10
if(!ShowDialog(dd &sub.DlgProc &controls)) ret


#sub DlgProc
function# hDlg message wParam lParam

sel message
,case WM_INITDIALOG
,DT_SetAccelerators(hDlg "401 Cq")
,case WM_DESTROY
,case WM_COMMAND goto messages2
ret
;messages2
sel wParam
,case IDOK
,case IDCANCEL
,case 401 ;;Ctrl+Q
,;Todo_1: Gets all the specific role controls text (STATICTEXT or CHECKBUTTON or PUSHBUTTON)
,
,;Todo_2: Merge all text into one line, the delimiter is | , Replace some symbols like , :
,
,;Todo_3: Use Google Translate text, and re-split the string, delimiter is | see below #sub tran
,
,;Todo_4: Set the translated text to the matching control

,;Todo_5: When I press the hotkey Ctrl+Q again, the controls text returns to its original
,_s.getwintext(id(5 hDlg))
,_s.replacerx(",|:" " ") ;;Replace , : with spaces
,_s=sub.tran(_s) ;;Translate control text
,_s.setwintext(id(5 hDlg))

ret 1

#sub tran
function'str str's

;Todo_3: change the following Powershell code to QM code

;sl=en -> Set the source language
;tl=zh-CN -> Set the target language
_s=
F
;function tran
;{{
;,$data = @('', '')
;,$objRet = Invoke-WebRequest "https://translate.googleapis.com/translate_a/single?client=gtx&sl=en&tl=zh-CN&dt=t&q=$args"
;,$data[0] = $objRet.Content
;,$objJson = ConvertFrom-Json $data[0]
;,$objJson[0][0][0]
;}
;tran "{s}"
PsCmd2 _s "" _s
ret _s.trim
#2
try this out 

Function DialogTranslateControls
Code:
Copy      Help
str dd=
;BEGIN DIALOG
;0 "" 0x90C80AC8 0x0 0 0 224 136 "Press Ctrl+Q translate controls text" "4"
;3 Button 0x54032000 0x0 32 44 48 14 "Father"
;4 Button 0x54032000 0x0 144 44 48 14 "Mother"
;5 Static 0x54000000 0x0 40 16 48 13 "hello,world"
;6 Static 0x54000000 0x0 144 16 48 13 "hello: friend"
;7 Button 0x54012003 0x0 32 72 48 10 "my city"
;8 Button 0x54012003 0x0 144 72 64 10 "your country"
;9 Edit 0x54030080 0x200 8 96 72 12 ""
;10 Edit 0x54030080 0x200 144 96 72 12 ""
;1 Button 0x54030001 0x4 48 116 48 14 "OK"
;2 Button 0x54030000 0x4 120 116 48 14 "Cancel"
;END DIALOG
;DIALOG EDITOR: "" 0x2040C02 "*" "" "" ""

str controls = "7 8 9 10"
str c7my c8you e9 e10
if(!ShowDialog(dd &sub.DlgProc &controls)) ret

#sub DlgProc
function# hDlg message wParam lParam

sel message
,case WM_INITDIALOG
,int- tn
,ARRAY(str)- translate original
,ARRAY(int)- a
,DT_SetAccelerators(hDlg "401 Cq")
,case WM_DESTROY
,case WM_COMMAND goto messages2
ret
;messages2
sel wParam
,case IDOK
,case IDCANCEL
,case 401 ;;Ctrl+Q
,tn=!tn
,if(translate.len =0)
,,ARRAY(str) roles="STATICTEXT[]PUSHBUTTON[]CHECKBUTTON"
,,Acc a1.Find(hDlg "DIALOG")
,,ARRAY(Acc) ac
,,a1.GetChildObjects(ac 1)
,,for _i 0 ac.len
,,,Acc& r1=ac[_i]
,,,str role name
,,,r1.Role(role); name=r1.Name
,,,for int'i 0 roles.len
,,,,if(!StrCompare(role roles[i]))
,,,,,a[]=r1.Hwnd
,,,,,original[]=name
,,,,,name.replacerx(",|:" " ") ;;Replace , : with spaces
,,,,,if _i !=ac.len-1
,,,,,,name+ " | "
,,,,,_s+name
,,sub.GetTranslation(_s "en" "zh-CN" &translate) ;;Translate control text
,int ii=0
,for i 0 a.len
,,if(tn)
,,,translate[ii].replacerx("\|" "");err
,,,translate[ii].rtrim;err
,,,translate[ii].setwintext(a[i]);err
,,else
,,,original[ii].setwintext(a[i]);err
,,ii+1
ret 1

#sub GetTranslation
function ~sourceText ~sourceLang ~targetLang ARRAY(str)&tl

sourceText.escape(11)
str s
IntGetFile F"https://translate.googleapis.com/translate_a/single?client=gtx&sl={sourceLang}&tl={targetLang}&dt=t&q={sourceText}" s
IXml x=JsonToXml(s)
IXmlNode r=x.RootElement
ARRAY(IXmlNode) a; r.Path("item/item/item[@type='string']" a 1)
for(int'i 0 a.len) 
,,if(!(i&1))
,,,tl[]=a[i].Value
also need this function
Function JsonToXml
Code:
Copy      Help
;/
function'IXml $JSON [flags] ;;flags: 1 display XML text in QM output

;Converts JSON text to XML and returns IXml object.

;REMARKS
;On Windows XP SP2 and Vista must be installed .NET 3.5 or later. Older OS are not supported.

;EXAMPLE
;out
;str JSON=
;;{
;;;;;"hello": "world",
;;;;;"t": true ,
;;;;;"f": false,
;;;;;"n": null,
;;;;;"i": 123,
;;;;;"pi": 3.14,
;;;;;"Address": { "City": "New York", "State": "NY" },
;;;;;"a": [1, 2, 3, 4]
;;}
;IXml x=JsonToXml(JSON 1)
;IXmlNode r=x.RootElement
;;get simple
;out r.Child("hello").Value
;;get with XPath
;out r.Path("Address/State").Value
;;get array
;ARRAY(IXmlNode) a; r.Path("a/*" a)
;int i; for(i 0 a.len) out a[i].Value


opt noerrorshere 1
CsScript x.SetOptions("references=System.Xml;System.Runtime.Serialization;System.ServiceModel.Web")
x.AddCode("")
_s=x.Call("ToXml" JSON)
if(flags&1) out _s
IXml k._create
k.FromString(_s)
ret k


#ret
using System;
using System.Text;
using System.Runtime.Serialization.Json;
using System.Xml;
using System.Xml.Linq;

public class Json
{
static public string ToXml(string JSON)
{
XmlDictionaryReader reader = JsonReaderWriterFactory.CreateJsonReader(Encoding.UTF8.GetBytes(JSON), new System.Xml.XmlDictionaryReaderQuotas());
return XElement.Load(reader).ToString();
}

}
#3
@Kevin

Thank you so much, it worked perfectly

QM is too powerful, QM looks like it can do anything Heart
#4
@Kevin

Hello, I put the Translate Control function, saved as a separate function (Tran_Ctrls) It assigns a hotkey Ctrl+Q

This way I can translate controls from other windows, but a lot of times it doesn't work,

is there a way to make the functions more generic? Thanks in advance

For example, I want to translate controls inside the custom dialog
[Image: a.png]

Function Tran_Ctrls
Trigger Cq     Help - how to add the trigger to the macro
Code:
Copy      Help
int h = win

int tn
ARRAY(str) translate original
ARRAY(int) a

tn=!tn
if(translate.len =0)
,ARRAY(str) roles="STATICTEXT[]PUSHBUTTON[]CHECKBUTTON[]RADIOBUTTON[]LISTITEM[]CLIENT"
,Acc a1.Find(h "DIALOG") ;;WINDOW
,ARRAY(Acc) ac
,a1.GetChildObjects(ac 1)
,for _i 0 ac.len
,,Acc& r1=ac[_i]
,,str role name
,,r1.Role(role); name=r1.Name
,,for int'i 0 roles.len
,,,if(!StrCompare(role roles[i]))
,,,,a[]=r1.Hwnd
,,,,original[]=name
,,,,name.replacerx(",|:" " ") ;;Replace , : with spaces
,,,,if _i !=ac.len-1
,,,,,name+ " | "
,,,,_s+name
,sub.GetTranslation(_s "en" "zh-CN" &translate) ;;Translate control text
,_s=translate
,out _s
int ii=0
for i 0 a.len
,if(tn)
,,translate[ii].replacerx("\|" "");err
,,translate[ii].rtrim;err
,,translate[ii].setwintext(a[i]);err
,else
,,original[ii].setwintext(a[i]);err
,ii+1

#sub GetTranslation
function ~sourceText ~sourceLang ~targetLang ARRAY(str)&tl

sourceText.escape(11)
str s
IntGetFile F"https://translate.googleapis.com/translate_a/single?client=gtx&sl={sourceLang}&tl={targetLang}&dt=t&q={sourceText}" s
IXml x=JsonToXml(s)
IXmlNode r=x.RootElement
ARRAY(IXmlNode) a; r.Path("item/item/item[@type='string']" a 1)
for(int'i 0 a.len)
,,if(!(i&1))
,,,tl[]=a[i].Value

I found a more general way to locate:
Acc a.Find(w "RADIOBUTTON" "" "class=Button" 0x1004 1 1)     -> Positioning of the first button
Acc a.Find(w "RADIOBUTTON" "" "class=Button" 0x1004 1 2)     -> Positioning of the second button

If there is no third button, with the method above, an error will occur

Acc a1.Find(w1 "CHECKBUTTON" "" "class=Button" 0x1004 1 1)   -> Positioning of the first checkbutton
If there is no second checkbutton, with the method above, an error will occur

...... Other control positioning is the same logic 

But  I don't know how to modify the code above 
Huh

@Gintaras

Currently, learning QM and Uiscripter, my biggest obstacle is poor English proficiency, at the same time, the software interface is not localized, 

Can you use Uiscripter to create an assistant with a translation UI interface similar to the one above? Thanks in advance Heart

With an assistant similar to the above, it is convenient for more people to use and learn QM and Uiscripter
#5
C# code:
// script "Translate UI element text.cs" /// Gets UI element text and translates with Google Cloud Translation API. Displays the result as a tooltip.
/// Edit the langTo string. Optionally edit langFrom.
/// By default gets text of UI element from mouse (uses elm functions). If script command line contains "copy", gets the selected text (uses the clipboard).
/// Hotkey trigger example: hk["F4"] = o => script.run(@"Translate UI element text.cs");
/// Hotkey trigger example for translating the selected text: hk["Ctrl+F4"] = o => script.run(@"Translate UI element text.cs", "copy");
/// Bad: Uses a Google translation service URL that is undocumented and may stop working in the future. Good: don't need authentication, API key.
/// If the used URL will stop working or does not work well, try the official API instead. Also there are libraries.
/// Not tested: max allowed text length. It is passed in URL. The script does not limit the text. Not tested: try POST request instead of GET.

/*/ ifRunning restart; /*/

string langFrom = "en", langTo = "es"; //edit these strings
bool debug = !true; //if true, prints the source and translated texts and errors

if (debug) print.clear();
try {
    string text;
    if (args.Contains("copy")) clipboard.tryCopy(out text); else text = _GetMouseElementText();
    if (text == null) return;
    if (debug) print.it(text);
    var s = _Translate(text, langFrom, langTo); if (s == null) return;
    if (debug) print.it($"<><c green>{s}<>");
    osdText.showText(s, xy: PopupXY.Mouse);
}
catch (Exception e1) { if (debug) print.it(e1); }

string _GetMouseElementText() {
    var e = elm.fromMouse();
    
    var name = e.Name;
    if (name.NE() || !name.RxIsMatch(@"(?i)[a-z]")) name = null;
    
    if (name != null && name.Contains('_') && e.WndContainer.ClassNameIs("HwndWrapper[*")) name = name.Replace("_", ""); //remove WPF accelerator prefix char
    
    var help = e.Help; //tooltip
    if (help.NE() || help == name || !help.RxIsMatch(@"(?i)[a-z]")) help = null;
    
    var val = e.Value; //textbox text
    if (val.NE() || val == name || val == help || !val.RxIsMatch(@"(?i)[a-z]")) val = null;
    
    if (name == null && help == null && val == null) return null;
    if ((help ?? val) == null) return name;
    var sb = new StringBuilder(name);
    if (help != null) sb.Append(sb.Length > 0 ? "\n" : null).Append("Help: ").Append(help);
    if (val != null) sb.Append(sb.Length > 0 ? "\n" : null).Append("Text: ").Append(val);
    return sb.ToString();
}

string _Translate(string sourceText, string sourceLang, string targetLang) {
    var url = internet.urlAppend("https://translate.googleapis.com/translate_a/single", "client=gtx", "sl=" + sourceLang, "tl=" + targetLang, "dt=t", "q=" + sourceText);
    var r = internet.http.Get(url);
    if (!r.IsSuccessStatusCode) {
        if (debug) print.it($"translate.googleapis.com error: {(int)r.StatusCode} {r.ReasonPhrase}");
        return null;
    }
    
    var sb = new StringBuilder();
    foreach (var v in r.Json()[0].AsArray()) sb.Append((string)v[0]);
    return sb.ToString();
}
#6
@Gintaras

Worked well, thanks very much

I just implemented a similar feature in QM2, PS: May not be perfect, welcome to correct

QM2 is really like a legend, I can understand the code  Tongue   QM setting hotkeys is more convenient, Faster startup and execution

but for Uiscripter, it is still difficult to understand, maybe I need to learn more programming knowledge


Macro Macro14
Trigger F4     Help - how to add the trigger to the macro
Code:
Copy      Help
Acc ac = acc(mouse)
_s = ac.Name
if (empty(_s))
,int h = child(mouse)
,if h=0
,,h = win(mouse)
,_s.getwintext(h)

ARRAY(str) tl
sub.GetTranslation(_s "en" "zh_cn" tl)
str d=tl

OnScreenDisplay d.trim 1 0.5 0.5 "" 36 0xFF0000 4

#sub GetTranslation
function ~sourceText ~sourceLang ~targetLang ARRAY(str)&tl

sourceText.escape(11)
str s
IntGetFile F"https://translate.googleapis.com/translate_a/single?client=gtx&sl={sourceLang}&tl={targetLang}&dt=t&q={sourceText}" s
IXml x=JsonToXml(s)
IXmlNode r=x.RootElement
ARRAY(IXmlNode) a; r.Path("item/item/item[@type='string']" a 1)
for(int'i 0 a.len)
,,if(!(i&1))
,,,tl[]=a[i].Value

I found a problem, the flag 4 didn't work

4 click to hide

OnScreenDisplay d.trim 1 0.5 0.5 "" 36 0xFF0000 4
#7
Flag 4: the window is not transparent; users can click it to close.
#8
I changed the translation parameter [sourceLang] to "auto", and the output result has extra characters

I tried to make the following modifications, but it didn't work

ARRAY(IXmlNode) a; r.Path("item/item/item[@type='string'][0]" a 1)

Function Test
Trigger K     Help - how to add the trigger to the macro
Code:
Copy      Help
_s="hello"

ARRAY(str) tl
sub.GetTranslation(_s "auto" "zh_cn" tl)
str d=tl

OnScreenDisplay d.trim 1 0.5 0.5 "" 36 0xFF0000 4

#sub GetTranslation
function ~sourceText ~sourceLang ~targetLang ARRAY(str)&tl

sourceText.escape(11)
str s
IntGetFile F"https://translate.googleapis.com/translate_a/single?client=gtx&sl={sourceLang}&tl={targetLang}&dt=t&q={sourceText}" s
IXml x=JsonToXml(s 1)
IXmlNode r=x.RootElement

ARRAY(IXmlNode) a; r.Path("item/item/item[@type='string']" a 1)
;ARRAY(IXmlNode) a; r.Path("item/item/item[@type='string'][0]" a 1)
for(int'i 0 a.len)
,,if(!(i&1))
,,,tl[]=a[i].Value
#9
[number] in QM strings is an escape sequence (character code). Need to escape [. To easily create text with escape sequences, use the Text dialog.
#10
Had some time to look at this again. I changed the translate subfunction to use c#(CsScript) in qm2 now for the translation. Much easier to handle the Json array returned using c#.
Function Trans2 
Trigger K     Help - how to add the trigger to the macro
Code:
Copy      Help
out
Acc ac.FromMouse 
str name = ac.Name
if(ac.Role =18)
,ret
if(empty(name))
,int h = child(mouse)
,if h=0
,,h = win(mouse)
,_s.getwintext(h)
,if _s.len=0
,,_s.getsel
,,if(_s.len =0)
,,,out "nothing selected"
,,,ret

,name=_s
out name
str d
sub.GetTranslation(name "auto" "zh_cn" d);;change values  for other Languages
out d
OnScreenDisplay d -1 0 20 "" 24 0xFF0000 4|32 "TosdHwnd"

#sub GetTranslation
function ~sourceText ~sourceLang ~targetLang ~&tl

CsScript x
x.SetOptions("references=System.Web.Extensions.dll;System.Runtime.Serialization;Microsoft.CSharp.dll;System.Core.dll")
x.AddCode("")
tl=x.Call("Example.TranslateText" sourceText sourceLang targetLang)

#ret
using System.Net.Http;
using System.Collections;
using System.Web.Script.Serialization;
using System;
using System.Collections.Generic;

public class Example
{
,public static string TranslateText(string input , string sLang ,string tLang)
,{
,,string url = String.Format("https://translate.googleapis.com/translate_a/single?client=gtx&sl={0}&tl={1}&dt=t&q={2}", sLang, tLang, Uri.EscapeUriString(input));
,,HttpClient httpClient = new HttpClient();
,,string result = httpClient.GetStringAsync(url).Result;
,,var jsonData = new JavaScriptSerializer().Deserialize<List<dynamic>>(result);
,,var translationItems = jsonData[0];
,,string translation = "";
,,foreach (object item in translationItems)
,,{
,,,IEnumerable translationLineObject = item as IEnumerable;
,,,IEnumerator translationLineString = translationLineObject.GetEnumerator();
,,,translationLineString.MoveNext();
,,,translation += string.Format(" {0}", Convert.ToString(translationLineString.Current));
,,}
,,if (translation.Length > 1) { translation = translation.Substring(1); };
,,return translation;
,}
}
#11
@Kevin

This time the effect is better, thanks again
#12
Quote:
Code:
Copy      Help
// script "Translate UI element text.cs" /// Gets UI element text and translates with Google Cloud Translation API. Displays the result as a tooltip.
/// Edit the langTo string. Optionally edit langFrom.
/// By default gets text of UI element from mouse (uses elm functions). If script command line contains "copy", gets the selected text (uses the clipboard).
/// Hotkey trigger example: hk["F4"] = o => script.run(@"Translate UI element text.cs");
/// Hotkey trigger example for translating the selected text: hk["Ctrl+F4"] = o => script.run(@"Translate UI element text.cs", "copy");
/// Bad: Uses a Google translation service URL that is undocumented and may stop working in the future. Good: don't need authentication, API key.
/// If the used URL will stop working or does not work well, try the official API instead. Also there are libraries.
/// Not tested: max allowed text length. It is passed in URL. The script does not limit the text. Not tested: try POST request instead of GET.

/*/ ifRunning restart; /*/

string langFrom = "en", langTo = "es"; //edit these strings
bool debug = !true; //if true, prints the source and translated texts and errors

if (debug) print.clear();
try {
    string text;
    if (args.Contains("copy")) clipboard.tryCopy(out text); else text = _GetMouseElementText();
    if (text == null) return;
    if (debug) print.it(text);
    var s = _Translate(text, langFrom, langTo); if (s == null) return;
    if (debug) print.it($"<><c green>{s}<>");
    osdText.showText(s, xy: PopupXY.Mouse);
}
catch (Exception e1) { if (debug) print.it(e1); }

string _GetMouseElementText() {
    var e = elm.fromMouse();
    
    var name = e.Name;
    if (name.NE() || !name.RxIsMatch(@"(?i)[a-z]")) name = null;
    
    if (name != null && name.Contains('_') && e.WndContainer.ClassNameIs("HwndWrapper[*")) name = name.Replace("_", ""); //remove WPF accelerator prefix char
    
    var help = e.Help; //tooltip
    if (help.NE() || help == name || !help.RxIsMatch(@"(?i)[a-z]")) help = null;
    
    var val = e.Value; //textbox text
    if (val.NE() || val == name || val == help || !val.RxIsMatch(@"(?i)[a-z]")) val = null;
    
    if (name == null && help == null && val == null) return null;
    if ((help ?? val) == null) return name;
    var sb = new StringBuilder(name);
    if (help != null) sb.Append(sb.Length > 0 ? "\n" : null).Append("Help: ").Append(help);
    if (val != null) sb.Append(sb.Length > 0 ? "\n" : null).Append("Text: ").Append(val);
    return sb.ToString();
}

string _Translate(string sourceText, string sourceLang, string targetLang) {
    var url = internet.urlAppend("https://translate.googleapis.com/translate_a/single", "client=gtx", "sl=" + sourceLang, "tl=" + targetLang, "dt=t", "q=" + sourceText);
    var r = internet.http.Get(url);
    if (!r.IsSuccessStatusCode) {
        if (debug) print.it($"translate.googleapis.com error: {(int)r.StatusCode} {r.ReasonPhrase}");
        return null;
    }
    
    var sb = new StringBuilder();
    foreach (var v in r.Json()[0].AsArray()) sb.Append((string)v[0]);
    return sb.ToString();
}

How to improve the above code
Use a hotkey to implement the above two functions
e.g:
window: Limited to QM3 only
Hotkey: Press the ctrl key twice in a row
then: If there is selected text under the mouse pointer, the selected text is translated, otherwise the text of the control is translated


Forum Jump:


Users browsing this thread: 5 Guest(s)