Our users want to dynamically add languages at run time, and although we can do this by changing LangDispatcher.LangNames, when you go to use the si translation form to translate, they only see columns for languages created at design time, even though we are loading / saving translations to an external file on FormCreate and FormClose.
e.g. We give our vanilla product to a Swiss customer, with English and French as two languages set-up at design time. They wish to add Italian and German at runtime, (we allow them to do that and save to the DB). When they start our app next time, we read all of their languages from DB, and populate LangDispatcher.LangNames accodingly. When they go to translate a form, all they get are columns for English and French, even though the dispatcher has Italian and German. Why???? This is a major problem for us because it is impractical to have lots of different versions of the same DFMs just to store the combinations of languages involved.
Any ideas how we can solve this?
Dynamically adding languages at runtime
Due to the sheer size of our applications (1000s of forms) we use form inheritance to achieve multi-lingual capability, this is achieved in the following way:
TdmoTranslator = class(TDatamodule) holds our language dispatcher on, loads languages at app start-up. Created and persistent for lifetime of
application.
TfrmBase = class(TForm) is our base form with tsiLangRT on it, IsInheritedOwner = False, linked to dmoTranslator.tsiLangDistpatcher, hotkey F10 to invoke frmTranslateOptions (see below).
TfrmTranslateBase = class(TfrmBase) sets IsInheritedOwner = True.
TfrmTranslateOptions = class(TfrmTranslateBase) allows user to change languages using TsiLangCombo, to invoke SI Editor for invoker form, or to translate global resourcestrings stored in frmAppTranslateGlobal (see below).
TfrmAppTranslateGlobal = class(TForm), invisible form with tsiLangRT on it used to stored extracted resourcestrings. We could not inherit from TfrmTranslateBase as the ResourceString wizard will not work with an inherited tsiLangRT, this is a weakness I think.
All other forms inherit from TfrmTranslateBase.
Languages are loaded in dmoTranslator as follows :
I opened a form at design time using si lang wizard, and saved so info is stored in DFM - at design time there are only two languages (English, French). When I invoke form at runtime the dispatcher has 4-5 languages but the RT language editor only has columns for the design time languages, and no way to add the others.
I have noticed that when langauages are loaded in dmoTranslator I have to disconnect frmTranslateOptions.siLangcombo from dispatcher and reconnect it to see new languages.
I think this may highlight the same issue.
We really need this fixed!
TdmoTranslator = class(TDatamodule) holds our language dispatcher on, loads languages at app start-up. Created and persistent for lifetime of
application.
TfrmBase = class(TForm) is our base form with tsiLangRT on it, IsInheritedOwner = False, linked to dmoTranslator.tsiLangDistpatcher, hotkey F10 to invoke frmTranslateOptions (see below).
TfrmTranslateBase = class(TfrmBase) sets IsInheritedOwner = True.
TfrmTranslateOptions = class(TfrmTranslateBase) allows user to change languages using TsiLangCombo, to invoke SI Editor for invoker form, or to translate global resourcestrings stored in frmAppTranslateGlobal (see below).
TfrmAppTranslateGlobal = class(TForm), invisible form with tsiLangRT on it used to stored extracted resourcestrings. We could not inherit from TfrmTranslateBase as the ResourceString wizard will not work with an inherited tsiLangRT, this is a weakness I think.
All other forms inherit from TfrmTranslateBase.
Languages are loaded in dmoTranslator as follows :
Code: Select all
var
n : integer;
begin
with qryLanguages do
begin
Active := True;
n := 0;
First;
while not EOF do
begin
if n <= siLangDispatcher.LangNames.Count - 1 then // Don't clear all, simply replace to prevent knock on to rtLang Components
siLangDispatcher.LangNames[n] := FieldByName('DESCRIPTION').AsString
else
siLangDispatcher.LangNames.Add(FieldByName('DESCRIPTION').AsString);
Next;
inc(n);
end;
Active := False;
end;
end;
I have noticed that when langauages are loaded in dmoTranslator I have to disconnect frmTranslateOptions.siLangcombo from dispatcher and reconnect it to see new languages.
Code: Select all
with siLangCombo do
begin
siLangDispatcher := nil;
siLangDispatcher := dmoTranslator.siLangDispatcher;
ItemIndex := siLangDispatcher.ActiveLanguage - 1;
end;
We really need this fixed!
I forgot to mention that at runtime, TfrmBase loads any saved SIB file the user has created and saved.
I have tried several techniquees to work around this bug but none work. e.g. assign langnames to siLangRT from dispatcher, or disconnect and reconnect dispatcher before loading SIB file.
Code: Select all
constructor TfrmBase.Create(AOwner: TComponent);
var
TranslationFile : string;
begin
inherited;
TranslationFile := ExtractFilePath(Application.ExeName) + Self.ClassName + '.sib';
siLangRT.StorageFile := TranslationFile;
siLangRT.LoadOnCreate := True;
end;
The problem is that dispatcher doesn't propagate the changes in language names to linked components. I would suggest you to use the following to load languages:
Code: Select all
var
n : integer;
Langs: TStringList;
begin
Langs := TStringList.Create;
try
Langs.Assign(siLangDispatcher.LangNames);
with qryLanguages do
begin
Active := True;
n := 0;
First;
while not EOF do
begin
if n <= Langs.Count - 1 then // Don't clear all, simply replace to prevent knock on to rtLang Components
Langs[n] := FieldByName('DESCRIPTION').AsString
else
Langs.Add(FieldByName('DESCRIPTION').AsString);
Next;
inc(n);
end;
Active := False;
end;
// this will enforce to propagate the language changes
siLangDispatcher.LangNames := Langs;
finally
Langs.Free;
end;
end;
Best regards,
Igor Siticov.
Igor Siticov.