Page 1 of 1

Dynamically adding languages at runtime

Posted: Wed Jan 17, 2007 6:11 pm
by Paul Zip
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?

Posted: Thu Jan 18, 2007 8:41 am
by isiticov
How do you load Language information from DB? It looks like dispatcher didn't propagate it into linked TsiLangs.

Posted: Thu Jan 18, 2007 11:18 am
by Paul Zip
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 :

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 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.

Code: Select all

with siLangCombo do
begin
  siLangDispatcher := nil;
  siLangDispatcher := dmoTranslator.siLangDispatcher;
  ItemIndex := siLangDispatcher.ActiveLanguage - 1;
end; 
I think this may highlight the same issue.

We really need this fixed!

Posted: Thu Jan 18, 2007 11:45 am
by Paul Zip
I forgot to mention that at runtime, TfrmBase loads any saved SIB file the user has created and saved.

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;
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.

Posted: Thu Jan 18, 2007 2:38 pm
by isiticov
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;

Posted: Thu Jan 18, 2007 2:59 pm
by Paul Zip
Thanks, that worked!