Hi + tx for support!
What I want to do:
Having a TWebForm with some compoents and labels on it, additionally there is a combobox which allows selecting languages. Having selected a language, I want to translate the labels and text on the form.
I have set up a TMSFNCCloudTranslation successfully.
I also have a translating method _t (see below).
What I want to do is:
procedure TfrmWRMain.TranslateForm(sLng: String);
begin
pgRezeptberechnung.Caption := _t('Rezeptberechnung');
pgZugriffsschluessel.Caption := _t('Zugriffsschlüssel');
lblRezeptBezeichnung.Caption := _t('Rezept-Bezeichnung');
tabZutaten.Caption := _t('Zutaten');
tabMemo.Caption := _t('Beschreibung');
end;
This is the translating method:
function TfrmWRMain._t(s: string):string;
var
sTranslation:String;
begin
TMSFNCCloudTranslation.Translate(s, sFormLanguage,
procedure(const ARequest: TTMSFNCCloudTranslationRequest; const ARequestResult: TTMSFNCCloudBaseRequestResult)
begin
if ARequest.Translations.count > 0 then begin
sTranslation := ARequest.Translations[0].TranslatedText;
Result:=sTranslation; // this does not work, because Result is not available here
end;
end));
Result:=sTranslation; // this does not work, because the callback is not finished yet
end;
However, I am unsure, how to return the translation to the calling method.
How can this be done? Or is it better to chhose anotrher approach?
The result of the translate is received asynchronously.
The translation result is available in the OnTranslate event handler, so please update the label from this OnTranslate event where the translated text will be available.
Tx, Bruno, for your answer. I know the OnTranslate-event, but in the event there is no chance to know what label or other component I have to update.
What I will try next is modifying the translation method, so that there is a parameter taking an anonymous procdure. In this procedure I can set the label.
Basically something like:
_t('Rezeptberechnung', procedure (sTranslatedText:String)
begin
pgRezeptberechnung.Caption:=sTranslatedText;
end;);
And this procedure is called inside the TMSFNCCloudTranslation.Translate method.
Is there any better way to handle this?
Yes, this works as wanted:
procedure TfrmWRMain._t0(s: string; p: TProc<string>);
var
sTranslation: String;
begin
TMSFNCCloudTranslation.Translate(s, sFormLanguage,
procedure(const ARequest: TTMSFNCCloudTranslationRequest; const ARequestResult: TTMSFNCCloudBaseRequestResult)
begin
if ARequest.Translations.count > 0 then begin
sTranslation := ARequest.Translations[0].TranslatedText;
p(sTranslation);
end;
end);
end;
And is called:
_t0('Rezeptberechnung',
procedure(s: string)
begin
pgRezeptberechnung.Caption := s;
end);
Is a bit clumsy, but works as needed, I think.
That is indeed also a good & valid approach.
Still I am unsure, how to deal with something like this:
if not dmWRMain.bLoggedIn then begin
_t('Do you want to login?',
procedure(s: string)
begin
sMsg := s;
end);
if dlgYesNo(sMsg) = mrYes then
Login
else
Exit;
end;
I can put the dialog inside the assigning procedure, but then the flow of the programm will continue unchanged. I can put the whole if/else inside the procedure, but I am sure, there is a more elegant way do handle this.
Of course I can translate the texts in advance, maybe this is an option, too.
Can you give me some hints?
Thanks a lot!
The two solutions that make the coding easier are:
- translate this in advance
- wrap the translation into a promise and await it before the call to show the dialog
Thank you, Bruno.
wrap the translation into a promise and await it before the call to show the dialog
Can you give me code sample?
I don't have it ready here, but the background & information is here:
https://wiki.freepascal.org/pas2js_AsyncAWait