The MASM Forum

Projects => ObjAsm => Topic started by: Biterider on November 13, 2022, 05:58:54 PM

Title: Multilingual GUI
Post by: Biterider on November 13, 2022, 05:58:54 PM
Hi
Deploying an application for the international market mostly requires some kind of localization (https://en.wikipedia.org/wiki/Multilingual_User_Interface).

In recent years, several online services have started offering online translations into a large number of languages, more than what is normally supported by a regular application.
In this sense, it would be nice to use these services on-site to translate the text resources into the target language chosen by the user and store them locally, avoiding further use of the translator.
From what I've seen, using such services can be done using a relatively simple HTTP API set and a user account. This last point requires registration and payment.

I was wondering how Google's Chrome does this since it doesn't require a login? Does anyone have an idea how it works? Any link or working example?  :tongue:

Biterider
Title: Re: Multilingual GUI
Post by: jj2007 on November 13, 2022, 08:52:30 PM
I've played with the idea, see attached multilingual editor, but with a slightly different approach:
- all GUI strings are handled in an Excel spreadsheet (attached)
- that implies getting translations for each column manually from Google or DeepL (https://www.deepl.com/translator)
- a copy gets saved in Utf8 format as GuiData.tab
- the tab file gets embedded as a resource
- the editor picks the language "on the fly" from that resource

You can test it using the Language menu entry.

Your version would go online to request the desired language for each GUI string, is that correct?
Title: Re: Multilingual GUI
Post by: Biterider on November 13, 2022, 10:09:13 PM
Hi
Quote from: jj2007 on November 13, 2022, 08:52:30 PM
Your version would go online to request the desired language for each GUI string, is that correct?
Yes, but only if the provided localization is not available. If you cannot go online, a default language, in most cases English, will be selected and must always be present.

Biterider
Title: Re: Multilingual GUI
Post by: Biterider on November 14, 2022, 08:37:03 PM
Hi
I found something on GitHub easygoogletranslate (https://github.com/ahmeterenodaci/easygoogletranslate)
The author claims that he uses an "unofficial Google Translate API".
I extracted the relevant request from the Python code
https://translate.google.com/m?tl=sv&sl=en&q=Open%20File (https://translate.google.com/m?tl=sv&sl=en&q=Open%20File) which, for example, translates "Open File" from English to Swedish

Available languages are listed here https://cloud.google.com/translate/docs/languages (https://cloud.google.com/translate/docs/languages)

Biterider
Title: Re: Multilingual GUI
Post by: jj2007 on November 14, 2022, 09:25:55 PM
Try this link (https://www.deepl.com/translator#en/fr/%26File%0A%26New%0A%26Open%0A%26Save%0A%26Save%20as%E2%80%A6%0A%0AE%26xit%0A) for a change. It works in a browser, but not as a direct download request, unfortunately. They have an API, though, but it requires authentication, i.e. your user would have to register. That is one reason why I would prefer the Excel spreadsheet approach mentioned above: a few kBytes more embedded in the executable, but no hassle with registration etc
Title: Re: Multilingual GUI
Post by: Biterider on November 15, 2022, 10:09:31 AM
Hi
After all, it wasn't that difficult :cool:
Here is the unpolished code:

TranslateText proc uses xbx xdi, pDstLang:PSTRING, pSrcLang:PSTRING, pSrcText:PSTRING
  local hInternet:HINTERNET, hConnect:HINTERNET, hRequest:HINTERNET
  local dBytesRead:DWORD, pStartChar:POINTER, pTranslation:PSTRINGW
  local pBuffer:POINTER, wDstBuffer[128]:CHRW, bURI[128]:CHRA

  RCV_BUFFER_SIZE equ 4*PAGESIZE         ;Reserve 4 pages, should be enough

  mov pTranslation, NULL
  invoke InternetOpen, $OfsCStr("Chrome/5.0"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0
  .if xax != 0
    mov hInternet, xax
    invoke InternetConnect, hInternet, $OfsCStr("translate.google.com"), INTERNET_DEFAULT_HTTPS_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, NULL
    .if xax != 0
      mov hConnect, xax
      lea xdi, bURI
      WriteF xdi, "/m?hl=en&tl=¦ST&sl=¦ST&q=¦ST", pDstLang, pSrcLang, pSrcText
      invoke HttpOpenRequest, hConnect, $OfsCStr("GET"), addr bURI, NULL, NULL, NULL, INTERNET_FLAG_RELOAD or INTERNET_FLAG_EXISTING_CONNECT or INTERNET_FLAG_SECURE, NULL
      .if xax != 0
        mov hRequest, xax
        invoke HttpSendRequest, hRequest, NULL, 0, NULL, 0
        invoke VirtualAlloc, NULL, RCV_BUFFER_SIZE, MEM_COMMIT, PAGE_READWRITE
        .if xax != NULL
          mov pBuffer, xax
          mov xdi, xax
          mov ebx, RCV_BUFFER_SIZE - 1
          .repeat
            invoke InternetReadFile, hRequest, xdi, ebx, addr dBytesRead
            mov ecx, dBytesRead
            .break .if eax == 0 || ecx == 0
            add xdi, xcx
            sub ebx, ecx
          .until FALSE
          mov CHRA ptr [xdi], 0
          .if eax != 0
            invoke StrPosA, pBuffer, $OfsCStrA(3Ch, 'div class="result-container"', 3Eh)
            .if xax != NULL
              add xax, 30
              mov pStartChar, xax
              invoke StrPos, xax, $OfsCStr(3Ch)
              mov CHRA ptr [xax], 0
              invoke UTF8ToWide, addr wDstBuffer, pStartChar, sizeof wDstBuffer
              invoke StrNewW, addr wDstBuffer
              mov pTranslation, xax
            .endif
          .endif
          invoke VirtualFree, pBuffer, RCV_BUFFER_SIZE, MEM_RELEASE
        .endif
        invoke InternetCloseHandle, hRequest
      .endif
      invoke InternetCloseHandle, hConnect
    .endif 
    invoke InternetCloseHandle, hInternet
  .endif
  mov xax, pTranslation
  ret
TranslateText endp 


For example, to translate "Open File" into Spanish, the code should look like this
  invoke TranslateText, $OfsCStr("es"), $OfsCStr("en"), $OfsCStr("Open File")
  .if xax != NULL
    DbgStrW xax
    invoke StrDispose, xax
  .else
    DbgWarning "No translation"
  .endif


In this case the output is "Abrir documento"

Biterider
Title: Re: Multilingual GUI
Post by: HSE on November 15, 2022, 11:02:14 AM
Hi Biterider!

But correct translation is "Abrir archivo"  :biggrin: :biggrin: :biggrin:

HSE
Title: Re: Multilingual GUI
Post by: Biterider on November 15, 2022, 05:57:36 PM
Hi HSE
In this regard, DeepL does a better job.

Biterider
Title: Re: Multilingual GUI
Post by: jj2007 on November 15, 2022, 09:19:23 PM
Quote from: Biterider on November 15, 2022, 05:57:36 PM
In this regard, DeepL does a better job.

If I need a translation, I rarely use Google. DeepL does an incredible job (and I can judge it, I am 100% fluent in 4 languages). Even very difficult phrases get translated correctly, it's really flabbergasting what these guys (https://www.deepl.com/translator#en/es/Open%20File) have achieved.
Title: Re: Multilingual GUI
Post by: Biterider on November 15, 2022, 10:51:37 PM
Hi
Looking at how DeepL can be used, it seems very complicated to use the web browser approach. It is easier to register and use the free version. Unfortunately, you have to give them your credit card information to register. An absolute no-go for me.  :sad:

Biterider
Title: Re: Multilingual GUI
Post by: jj2007 on November 15, 2022, 11:32:09 PM
With the Excel approach, see reply #1, DeepL is very easy to use. I select the English column:
&File
&New
&Open
&Save
&Save as...

E&xit
&Language
english
español
portogues
italiano
deutsch
français


Then I copy the column, paste it in DeepL and choose e.g. Spanish. Result:
&Archivo
&Nuevo
&Abrir
&Ahorro
&Guardar como...

E&Sit
&Idioma
inglés
english
portogues
italiano
alemán
francés


Ready to be pasted in the Spanish column of the spreadsheet, including even the ampersands :thumbsup:

And no hassle with registration or missing online access etc for the user.
Title: Re: Multilingual GUI
Post by: Biterider on November 15, 2022, 11:49:32 PM
Hi JJ
There are many other ways to get multilingual support, including your spreadsheet approach, but that's not the goal here.
As explained in the very first post, the concept I am following is using an online service on the customer side, as it is practically impossible to provide all the languages offered by these services.

BTW, I don't think that's the intended translation "E&Sit". It seems that the & is handled in a special way... Google has a similar issue.

Biterider
Title: Re: Multilingual GUI
Post by: Biterider on November 16, 2022, 04:06:02 AM
Hi
Looking again at the DeepL translations into Spanish using JJ's example, I saw the translation of "&Save" as "&Ahorro", which is completely wrong in this context. This shows me that this translator is also struggling with some isolated words. Maybe they can do better if the AI has more context from a full sentence.

Biterider
Title: Re: Multilingual GUI
Post by: TimoVJL on November 16, 2022, 04:18:42 AM
What is a best word for context ?

option &Save

opción &Guardar
Title: Re: Multilingual GUI
Post by: Biterider on November 16, 2022, 04:34:16 AM
Hi TimoVJL
Exactly, that's what I mean. If you try to precede each item with the word "menu" then the result will be correct.
I guess it acts like a hint for the AI. I don't know if it works in all situations, but I will try it.

Biterider
Title: Re: Multilingual GUI
Post by: Biterider on November 16, 2022, 07:26:30 AM
Hi
I'm starting to get something to work with. Now I pass a hint to the translation procedure:

CStr SrcLang, "en"
CStr DstLang, "de"

.code
start proc                                              ;Program entry point
  SysInit                                               ;Runtime initialization of OOP model
  DbgClearAll

  OCall $ObjTmpl(Application)::Application.Init         ;Initialize application
  invoke TranslateText, offset DstLang, offset SrcLang, $OfsCStr("File"), $OfsCStr("Menu")
  DbgStrW xax
  invoke TranslateText, offset DstLang, offset SrcLang, $OfsCStr("Open File"), $OfsCStr("Menu")
  DbgStrW xax
  invoke TranslateText, offset DstLang, offset SrcLang, $OfsCStr("Open"), $OfsCStr("Menu")
  DbgStrW xax
  invoke TranslateText, offset DstLang, offset SrcLang, $OfsCStr("Save"), $OfsCStr("Menu")
  DbgStrW xax
  invoke TranslateText, offset DstLang, offset SrcLang, $OfsCStr("Save as..."), $OfsCStr("Menu")
  DbgStrW xax
  invoke TranslateText, offset DstLang, offset SrcLang, $OfsCStr("Print"), $OfsCStr("Menu")
  DbgStrW xax
  invoke TranslateText, offset DstLang, offset SrcLang, $OfsCStr("Exit"), $OfsCStr("Menu")
  DbgStrW xax
  invoke TranslateText, offset DstLang, offset SrcLang, $OfsCStr("Language"), $OfsCStr("Menu")
  DbgStrW xax
  invoke TranslateText, offset DstLang, offset SrcLang, $OfsCStr("English"), NULL
  DbgStrW xax
  invoke TranslateText, offset DstLang, offset SrcLang, $OfsCStr("Spanish"), NULL
  DbgStrW xax
  invoke TranslateText, offset DstLang, offset SrcLang, $OfsCStr("Portuguese"), NULL
  DbgStrW xax
  invoke TranslateText, offset DstLang, offset SrcLang, $OfsCStr("Italian"), NULL
  DbgStrW xax
  invoke TranslateText, offset DstLang, offset SrcLang, $OfsCStr("German"), NULL
  DbgStrW xax
  invoke TranslateText, offset DstLang, offset SrcLang, $OfsCStr("French"), NULL
  DbgStrW xax
  invoke TranslateText, offset DstLang, offset SrcLang, $OfsCStr("OK"), $OfsCStr("Button")
  DbgStrW xax
  invoke TranslateText, offset DstLang, offset SrcLang, $OfsCStr("Cancel"), $OfsCStr("Button")
  DbgStrW xax
  invoke TranslateText, offset DstLang, offset SrcLang, $OfsCStr("Search"), $OfsCStr("Button")
  DbgStrW xax

;  OCall $ObjTmpl(Application)::Application.Run          ;Execute application
  OCall $ObjTmpl(Application)::Application.Done         ;Finalize application

  SysDone                                               ;Runtime finalization of the OOP model
  invoke ExitProcess, 0                                 ;Exit program returning 0 to the OS
start endp


All results seem to be correct, at least for the languages I know
German
xax -> Datei
xax -> Datei öffnen
xax -> Öffnen
xax -> Speichern
xax -> Speichern unter...
xax -> Drucken
xax -> Beenden
xax -> Sprache
xax -> Englisch
xax -> Spanisch
xax -> Portugiesisch
xax -> Italienisch
xax -> Deutsch
xax -> Französisch
xax -> OK
xax -> Abbrechen
xax -> Suchen

Spanish
xax -> Archivo
xax -> Abrir archivo
xax -> Abrir
xax -> Guardar
xax -> Guardar como...
xax -> Imprimir
xax -> Salir
xax -> Idioma
xax -> Inglés
xax -> Español
xax -> Portugués
xax -> Italiano
xax -> Alemán
xax -> Francés
xax -> Aceptar
xax -> Cancelar
xax -> Buscar

Italian
xax -> File
xax -> Apri file
xax -> Apri
xax -> Salva
xax -> Salva con nome...
xax -> Stampa
xax -> Esci
xax -> Lingua
xax -> Inglese
xax -> Spagnolo
xax -> Portoghese
xax -> Italiano
xax -> Tedesco
xax -> Francese
xax -> OK
xax -> Annulla
xax -> Cerca


I can not check the correctness in other languages.
Maybe I can write a test application where other languages like Russian or Chinese can be selected and other forum members could check the results.

These are the results for now:
Russian
xax -> Файл
xax -> Открыть файл
xax -> Открыть
xax -> Сохранить
xax -> Сохранить как...
xax -> Печать
xax -> Выход
xax -> Язык
xax -> Английский
xax -> Испанский
xax -> Португальский
xax -> итальянский
xax -> Немецкий
xax -> Французский
xax -> ОК
xax -> Отмена
xax -> Искать

Simplified Chinese
Work in progress... :-)



Biterider
Title: Re: Multilingual GUI
Post by: Biterider on November 16, 2022, 07:42:14 AM
Traditional Chinese
xax -> 文件
xax -> 打開文件
xax -> 打開
xax -> 保存
xax -> 另存為...
xax -> 打印
xax -> 退出
xax -> 語言
xax -> 英語
xax -> 西班牙語
xax -> 葡萄牙語
xax -> 意大利語
xax -> 德語
xax -> 法語
xax -> 確定
xax -> 取消
xax -> 搜索


Biterider
Title: Re: Multilingual GUI
Post by: learn64bit on November 16, 2022, 07:46:59 AM
Simplified(cn) - Traditional(tw)
开 - 開
为 - 為
语 - 語
确 - 確
Title: Re: Multilingual GUI
Post by: Biterider on November 16, 2022, 07:56:18 AM
Thanks learn64bit
I mixed the chinese language definitions. I corrected the above post.
The result for simplified chinese is

xax -> 文件
xax -> 打开文件
xax -> 打开
xax -> 保存
xax -> 另存为...
xax -> 打印
xax -> 退出
xax -> 语言
xax -> 英语
xax -> 西班牙语
xax -> 葡萄牙语
xax -> 意大利语
xax -> 德语
xax -> 法语
xax -> 确定
xax -> 取消
xax -> 搜索


Hindi
xax -> फ़ाइल
xax -> फ़ाइल खोलें
xax -> खोलें
xax -> सहेजें
xax -> इस रूप में सहेजें ...
xax -> प्रिंट
xax -> बाहर निकलें
xax -> भाषा
xax -> अंग्रेज़ी
xax -> स्पैनिश
xax -> पुर्तगाली
xax -> इतालवी
xax -> जर्मन
xax -> फ्रेंच
xax -> ठीक है
xax -> रद्द करें
xax -> खोज


Japanese
xax -> ファイル
xax -> ファイルを開く
xax -> 開く
xax -> 保存
xax -> 名前を付けて保存...
xax -> 印刷
xax -> 終了
xax -> 言語
xax -> 英語
xax -> スペイン語
xax -> ポルトガル語
xax -> イタリアの
xax -> ドイツ人
xax -> フランス語
xax -> OK
xax -> キャンセル
xax -> 検索



Biterider

Title: Re: Multilingual GUI
Post by: Biterider on November 16, 2022, 06:49:32 PM
Hi all
I ask those members who are fluent in the languages of the above posts to check that the translations are correct.
It would help me a lot to verify that the hints are working as intended.

Many thanks.  :thumbsup:

Biterider
Title: Re: Multilingual GUI
Post by: Biterider on November 18, 2022, 06:45:25 PM
Hi
When translating a bunch of single words one after the other, the overall process is slow.
For this reason I am changing the strategy, collecting the words first and sending them all together in a single request. This means the response has to be parsed, but I think the speed gain is worth the effort.

Biterider
Title: Re: Multilingual GUI
Post by: Biterider on November 19, 2022, 06:03:51 AM
Hi
Bad news...  :sad:
The free service seems to have some limitations: it can not process multiple lines at the same time.
It is designed to translate single sentences.

We have to live with it, which isn't a major problem for the current goal.


Biterider
Title: Re: Multilingual GUI
Post by: Biterider on November 20, 2022, 09:13:32 PM
Hi
As a proof of concept, I wrote a demo application that changes the main menu based on a user selection.
Alternatively, the machine locale could be used, but the demo was written to show their online translation capabilities.
Once a language has been selected via the "Languages" submenu (this submenu is intentionally excluded from the translation, preserving the native language names), a nice throbber will appear (only if the OS version is >= 8) while the translation is in action.  :cool:
The final result is saved in a file, so that the next time the application is started, the last translation is immediately active.

For this demo I randomly selected only 10 languages from Google's list. It currently contains more than 90 languages.

Since the application resource section is filled with a large amount of throbber images, its size exceeds the upload limit of the forum. The application can be downloaded from GitHub using the following link https://github.com/ObjAsm/ObjAsm-C.1/raw/master/Projects/X/Multilingual%20GUI/ML_GUI.exe

The complete source code is also available on GitHub, but the original idea and code is posted above.
The code for single translations can be found in the attachment.

Biterider
Title: Re: Multilingual GUI
Post by: HSE on November 21, 2022, 12:07:57 AM
Hi Biterider!

Quote from: Biterider on November 20, 2022, 09:13:32 PM
application resource section is filled with a large amount of throbber images

Nice, but to much. In Win7 (without throbber) translation is instantaneus.  :thumbsup:

Quote from: Biterider on November 20, 2022, 09:13:32 PM
The complete source code is also available on GitHub

I cloned full repository in High Contrast machine.

Look fantastic. Still some dynamic layout metric is not perfect, because there are some superpositions (1 to 3 pixels, or so).

Object Explorer don't work. I was thinking I brokened that, but apparently wasn't me this time  :biggrin:

HSE
Title: Re: Multilingual GUI
Post by: jj2007 on November 21, 2022, 12:08:44 AM
No throbber on Win7-64, as expected, but the translation works fine, with a 3 second delay :thumbsup:
Title: Re: Multilingual GUI
Post by: Biterider on November 21, 2022, 04:43:38 AM
Hi
Thanks for testing  :cool:

@HSE:
Knowing that a good friend uses HC, I invested some time to add some improvements :biggrin:
Can you send me a screenshot of the "dynamic layout" issue? It will help a lot to pinpoint the problem.
It may be that the ObjectExplorer is confused because I uploaded the file ObjAsm\code\OA_Info.stm which contains information about my own system. Try deleting the file and restarting the application.
I'll remove this file from GitHub too.

@JJ:
The few seconds delay is due to the running of the online service. It's not related to the application itself. I tried using a batch approach but it didn't work. Maybe sending multiple requests at once can solve the problem.
Since I haven't had any more time so far, I've installed the Throbber, which makes those few seconds go by much faster.  :rolleyes:

Biterider
Title: Re: Multilingual GUI
Post by: jj2007 on December 03, 2022, 03:28:08 AM
Quote from: Biterider on November 20, 2022, 09:13:32 PMAs a proof of concept, I wrote a demo application that changes the main menu based on a user selection.

Hi Biterider,

News from my own baby (http://masm32.com/board/index.php?topic=10401.msg116123#msg116123), with now about 700 translations :cool:
Title: Re: Multilingual GUI
Post by: daydreamer on December 10, 2022, 08:56:36 PM
I have interest in foreign languages, so i downloaded language packs,for example japanese, would it be possible to get info from language pack instead?
Or some way to find windows data somewhere it keeps native meny texts?
.cpp for example in resource file dialogs for file, help,about box is kept there
So swedish version programs probably keep it there or indirect loads it from other files
@JJ
Fluent in x86,x64,German, Italian I guess  :greenclp:
Title: Re: Multilingual GUI
Post by: TimoVJL on December 10, 2022, 10:55:20 PM
EnumUILanguagesA function (winnls.h) (https://learn.microsoft.com/fi-fi/windows/win32/api/winnls/nf-winnls-enumuilanguagesa?redirectedfrom=MSDN)

QuoteIn the registry is this

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\MUI\UILanguages\en-US]
"LCID"=dword:00000409
"Type"=dword:00000091

Some experiments:
https://forum.pellesc.de/index.php?topic=5324.msg20459#msg20459
void SetLang(HWND hwnd, LANGID lid)
{
typedef LANGID (WINAPI *fnSetThreadUILanguage) (LANGID wReserved);
HMENU hMenu;
if ((GetVersion() & 0x00FF) > 5) // Vista =>
{
fnSetThreadUILanguage fnPtr = (fnSetThreadUILanguage)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "SetThreadUILanguage");
if (fnPtr)
(*fnPtr) (lid);
} else
SetThreadLocale(MAKELCID(lid, SORT_DEFAULT));
hMenu = GetMenu(hwnd);
SetMenu(hwnd, NULL);
DestroyMenu(hMenu);
hMenu = LoadMenu(GetModuleHandle(NULL), MAKEINTRESOURCE(2001));
SetMenu(hwnd, hMenu);
}
Is this, what you was after ?
Title: Re: Multilingual GUI
Post by: jj2007 on December 12, 2022, 09:24:55 PM
Hi Biterider,

You might find these interesting:

https://translatepress.com/deepl-vs-google-translate-comparison/

QuoteWith both Google Translate and DeepL, you can translate up to 500,000 characters (not words) per month for free. This is 100% free forever. So as long as you stay under 500,000 characters per month, you could use either API for free.

https://blog.meinrad.cc/en/deepl-google-translate-not-all-machine-translation-engines-are-created-equal

QuoteThe real difference between these two engines is in the technology they use. Both use neural networks, but Google Translate (like most other machine translation engines) uses what are known as recurrent neural networks. By contrast, DeepL uses convolutional neural networks (CNNs), which produce better all-round results for longer, continuous sequences of words. Although CNNs aren't perfect, and so far haven't been used by other machine translation providers, they process texts better in parallel and produce better translations as a result.
Title: Re: Multilingual GUI
Post by: Biterider on December 13, 2022, 03:04:48 AM
Thanks JJ
Very interesting comparisons. From my experience, I agree with them.  :thumbsup:

Biterider