Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support for non-english resourcestrings, no need to restart an app after change of language, support for build under FMX #146

Open

Conversation

@paustr
Copy link

@paustr paustr commented Oct 29, 2018

  1. Extract non English resourcestrings into .messages files (used rawUTF8 type istead of Ansi)
  2. Change language on the fly without restarting an application, many times
  • added {$undef USEFORMCREATEHOOK}, to make SetCurrentLanguage procedurę available
  • modified procedurę SetCurrentLanguage
  1. some FMXAPP directives in order to be able to build under fmxApplication

Sample application
https://github.com/paustr/multiLangApp

…rcestrings, build under FMX

- added FMXAPP directive to be able to build under FireMonkey
-added support for non-english resourcestrings
-added support for changing on the fly without closing an application
@@ -1907,9 +1931,10 @@ procedure TLanguageFile.Translate(var English: string);
// case-sensitive (same as standard gettext)
var result: string;
begin
result := FindMessage(Hash32(
//resourcestrings may be not in English

This comment has been minimized.

@synopse

synopse Oct 29, 2018
Owner

this comment (and below) is a bit confusing for sure -> need to delete old code, and fix comments

This comment has been minimized.

@paustr

paustr Oct 30, 2018
Author

removed

i: PtrInt;
begin
result := true;
if (PtrInt(lpszType)<>PtrInt(RT_STRING)) then exit;
i := (PtrInt(lpszName)-1)shl 4;
for i := i to i+15 do begin // resourcestrings are stored by groups of 16
SetString(s,buf,LoadStringA(hInstance,i,buf,sizeof(buf)));
SetString(s,buf,LoadStringW(hInstance,i,buf,sizeof(buf)));

This comment has been minimized.

@synopse

synopse Oct 29, 2018
Owner

this is IMHO wrong: s is UTF-8 while LoadStringW returns UTF-16 content

This comment has been minimized.

@paustr

paustr Oct 30, 2018
Author

SetString method causes a problem unless buf is declared as array od WideChar. Please look at callstack

  1. LoadStringA and buf is array of AnsiChar
    cb_enumstringproc_1
  2. LoadStringW and buf is array od WideChar
    cb_enumstringproc_2

This comment has been minimized.

@synopse

synopse Oct 30, 2018
Owner

if s is a RawUTF8 you should NOT use UTF-16 input
use RawUnicodeToUtf8() instead of SetString()

@@ -11303,7 +11303,7 @@ function Hash32(Data: pointer; Len: integer): cardinal; overload;
// - has less colision than Adler32 for short strings
// - is faster than CRC32 or Adler32, since use DQWord (128 bytes) aligned read
// - uses RawByteString for binary content hashing, whatever the codepage is
function Hash32(const Text: RawByteString): cardinal; overload;
function Hash32(const Text: RawUTF8): cardinal; overload;

This comment has been minimized.

@synopse

synopse Oct 29, 2018
Owner

not acceptable (it breaks existing user code), nor needed RawByteString as input allows to pass a RawUTF8

This comment has been minimized.

@paustr

paustr Oct 30, 2018
Author

Change is reverted.

This comment has been minimized.

@paustr

paustr Oct 30, 2018
Author

I still need Hash32(const Text: RawUTF8), so it was written in mORMoti18n.
After SetCurrentLanguage(lngEnglish) method was called, all resourcestring need to be tranlated and method GetText was called. There is an implicit conversion from RawUTF8 to RawByteString and it causes loss of data. Please look at attached call stacks.

  1. function Hash32(const Text: RawByteString) was used

setcurrentlangugage_en

  1. function Hash32(const Text: RawUTF8) was used
    setcurrentlangugage_en2

This comment has been minimized.

@synopse

synopse Oct 30, 2018
Owner

Don't trust the debugger. IMHO this is a debugger issue/bug/feature, which makes on its side a conversion when displaying the value in the IDE.
There is no actual conversion in the generated assembly when you assign a RawUTF8 to a RawByteString (use Alt-F2 to see it).

This comment has been minimized.

@paustr

paustr Oct 30, 2018
Author

But Hash32(const Text: RawByteString) called inside TLanguageFile.Translate(var English: string) returns result which is not equal to the hash saved in .messages file and so that TLanguage.FindMessage returns an empty string.
When I use Hash32(const Text: RawUTF8) both for writing strings to .messages file (inside ExtractAllResources) and inside TLanguageFile.Translate method I'm getting the same results.

@paustr
Copy link
Author

@paustr paustr commented Oct 29, 2018

I have an application, which default langage is polish and all it's text are in polish.
Now I need to provide language selection (english translation will not be needed) and we have to ba able to change langugage many times without restart an application.
I use SetCurrentLanguage method but it wasn't available unless {$undef USEFORMCREATEHOOK} was used (note that I dint't want to use LVCL directive, whitch undefines USEFORMCREATEHOOK).
I also made some changes in ExtractAllResources procedure to write correctly polish texts into .messages file.
I want to use mORMori18n bot in VCL and FMX(in FMX only for translating resourcestrings), so I had to use FMXAPP directive to make it compilable under FireMonkey.
Please look at sample application

@synopse
Copy link
Owner

@synopse synopse commented Oct 29, 2018

Please see my review above, to make some needed corrections in your branch, then try again the pull request.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

2 participants
You can’t perform that action at this time.