On Fri, 2012-07-13 at 15:51 +0200, zeljko wrote:
> On Friday 13 of July 2012 15:49:37 Joost van der Sluis wrote:
> > I'm using the DefaultTranslator unit to translate my application,
> but I
> > would also like to switch to another language on-the-fly, thus
> without
> > restarting the application.

> I need that too atm :)

Try the attached patch for DefaultTranslator. With SetDefaultLang('nl')
it will switch the language on-the-fly (to Dutch in this case). 

It will loop through all forms in screens and will change all properties
that are present in the .po-file.

Maybe it is an idea to apply this patch so that others can also use
this? Or should users write their own 'DefaultTranslator' unit? (Then
this one could be added to the Wiki as an example)

-- 
Met vriendelijke groeten,

  Joost van der Sluis
  CNOC Informatiesystemen en Netwerken
  http://www.cnoc.nl
Index: defaulttranslator.pas
===================================================================
--- defaulttranslator.pas	(revision 37902)
+++ defaulttranslator.pas	(working copy)
@@ -33,11 +33,22 @@
 
 uses
   Classes, SysUtils, LResources, GetText, Controls, typinfo, FileUtil, LCLProc,
-  Translations;
+  Translations, Forms;
 
 type
-  TDefaultTranslator = class(TAbstractTranslator)
+
+  { TUpdateTranslator }
+
+  TUpdateTranslator = class(TAbstractTranslator)
   private
+    FStackPath: string;
+    procedure IntUpdateTranslation(AnInstance: TPersistent);
+  public
+    procedure UpdateTranslation(AnInstance: TPersistent);
+  end;
+
+  TDefaultTranslator = class(TUpdateTranslator)
+  private
     FMOFile: TMOFile;
   public
     constructor Create(MOFileName: string);
@@ -46,7 +57,9 @@
       PropInfo: PPropInfo; var Content: string); override;
   end;
 
-  TPOTranslator = class(TAbstractTranslator)
+  { TPOTranslator }
+
+  TPOTranslator = class(TUpdateTranslator)
   private
     FPOFile: TPOFile;
   public
@@ -56,6 +69,8 @@
       PropInfo: PPropInfo; var Content: string); override;
   end;
 
+procedure SetDefaultLang(Lang: string);
+
 implementation
 
 uses
@@ -64,9 +79,9 @@
 type
   TPersistentAccess = class(TPersistent);
 
-function FindLocaleFileName(LCExt: string): string;
+function FindLocaleFileName(LCExt: string; Lang: string): string;
 var
-  Lang, T: string;
+  T: string;
   i: integer;
 
   function GetLocaleFileName(const LangID, LCExt: string): string;
@@ -176,12 +191,12 @@
 
 begin
   Result := '';
-  Lang := '';
 
-  for i := 1 to Paramcount - 1 do
-    if (ParamStrUTF8(i) = '--LANG') or (ParamStrUTF8(i) = '-l') or
-      (ParamStrUTF8(i) = '--lang') then
-      Lang := ParamStrUTF8(i + 1);
+  if Lang = '' then
+    for i := 1 to Paramcount - 1 do
+      if (ParamStrUTF8(i) = '--LANG') or (ParamStrUTF8(i) = '-l') or
+        (ParamStrUTF8(i) = '--lang') then
+        Lang := ParamStrUTF8(i + 1);
 
   //Win32 user may decide to override locale with LANG variable.
   if Lang = '' then
@@ -225,19 +240,108 @@
   if (csDesigning in Component.ComponentState) then
     exit;
 
-  if not (Sender is TReader) then
-    exit;
-  Reader := TReader(Sender);
-  if Reader.Driver is TLRSObjectReader then
-    Result := TLRSObjectReader(Reader.Driver).GetStackPath
-  else
-    Result := Instance.ClassName + '.' + PropInfo^.Name;
+  if (Sender is TReader) then
+  begin
+    Reader := TReader(Sender);
+    if Reader.Driver is TLRSObjectReader then
+      Result := TLRSObjectReader(Reader.Driver).GetStackPath
+    else
+      Result := Instance.ClassName + '.' + PropInfo^.Name;
+  end else if (Sender is TUpdateTranslator) then
+    Result := TUpdateTranslator(Sender).FStackPath + '.' + PropInfo^.Name;
   Result := UpperCase(Result);
 end;
 
 var
   lcfn: string;
 
+{ TUpdateTranslator }
+
+procedure TUpdateTranslator.IntUpdateTranslation(AnInstance: TPersistent);
+var
+  i,j: integer;
+  APropCount: integer;
+  APropList: PPropList;
+  APropInfo: PPropInfo;
+  TmpStr: string;
+  APersistentProp: TPersistent;
+  StoreStackPath: string;
+begin
+  APropCount := GetPropList(AnInstance.ClassInfo, APropList);
+  try
+    for i := 0 to APropCount-1 do
+      begin
+      APropInfo:=APropList^[i];
+      if Assigned(PPropInfo(APropInfo)^.GetProc) and
+         assigned(APropInfo^.PropType) and
+         IsStoredProp(AnInstance, APropInfo) then
+        case APropInfo^.PropType^.Kind of
+          tkSString,
+          tkLString,
+          tkAString:  begin
+                      TmpStr := '';
+                      LRSTranslator.TranslateStringProperty(self,aninstance,APropInfo,TmpStr);
+                      if TmpStr <>'' then
+                        SetStrProp(AnInstance, APropInfo, TmpStr);
+                      end;
+          tkclass:    begin
+                      APersistentProp := TPersistent(GetObjectProp(AnInstance, APropInfo, TPersistent));
+                      if Assigned(APersistentProp) then
+                        begin
+                        if APersistentProp is TCollection then
+                          begin
+                          for j := 0 to TCollection(APersistentProp).Count-1 do
+                            begin
+                            StoreStackPath:=FStackPath;
+                            FStackPath:=FStackPath+'.'+APropInfo^.Name+'['+inttostr(j)+']';
+                            IntUpdateTranslation(TCollection(APersistentProp).Items[j]);
+                            FStackPath:=StoreStackPath;
+                            end;
+                          end
+                        else
+                          begin
+                          if APersistentProp is TComponent then
+                            begin
+                            if (csSubComponent in TComponent(APersistentProp).ComponentStyle) then
+                              begin
+                              StoreStackPath:=FStackPath;
+                              FStackPath:=FStackPath+'.'+TComponent(APersistentProp).Name;
+                              IntUpdateTranslation(APersistentProp);
+                              FStackPath:=StoreStackPath;
+                              end
+                            end
+                          else
+                            begin
+                            StoreStackPath:=FStackPath;
+                            FStackPath:=FStackPath+'.'+APropInfo^.Name;
+                            IntUpdateTranslation(APersistentProp);
+                            FStackPath:=StoreStackPath;
+                            end;
+                          end;
+                        end;
+                      end;
+          end;
+      end;
+  finally
+    freemem(APropList);
+  end;
+
+  if (AnInstance is TComponent) then
+    for i := 0 to TComponent(AnInstance).ComponentCount-1 do
+      begin
+      StoreStackPath:=FStackPath;
+      FStackPath:=FStackPath+'.'+TComponent(AnInstance).Components[i].Name;
+      IntUpdateTranslation(TComponent(AnInstance).Components[i]);
+      FStackPath:=StoreStackPath;
+      end;
+end;
+
+procedure TUpdateTranslator.UpdateTranslation(AnInstance: TPersistent);
+begin
+  FStackPath:=AnInstance.ClassName;
+  IntUpdateTranslation(AnInstance);
+end;
+
 { TDefaultTranslator }
 
 constructor TDefaultTranslator.Create(MOFileName: string);
@@ -311,19 +415,19 @@
   end;
 end;
 
+procedure SetDefaultLang(Lang: string);
+
 var
   Dot1: integer;
   LCLPath: string;
-  LocalTranslator: TAbstractTranslator;
+  LocalTranslator: TUpdateTranslator;
+  i: integer;
 
-initialization
-  //It is safe to place code here as no form is initialized before unit
-  //initialization made
-
+begin
   LocalTranslator := nil;
   // search first po translation resources
   try
-     lcfn := FindLocaleFileName('.po');
+     lcfn := FindLocaleFileName('.po', Lang);
      if lcfn <> '' then
      begin
        Translations.TranslateResourceStrings(lcfn);
@@ -345,7 +449,7 @@
   begin
     // try now with MO traslation resources
     try
-      lcfn := FindLocaleFileName('.mo');
+      lcfn := FindLocaleFileName('.mo', Lang);
       if lcfn <> '' then
       begin
         GetText.TranslateResourceStrings(UTF8ToSys(lcfn));
@@ -366,9 +470,28 @@
   end;
 
   if LocalTranslator<>nil then
+  begin
+    if Assigned(LRSTranslator) then
+      LRSTranslator.Free;
     LRSTranslator := LocalTranslator;
 
+    // Do not update the translations when this function is called from within
+    // the unit initialization.
+    if (Lang<>'') then
+    begin
+      for i := 0 to Screen.CustomFormCount-1 do
+        LocalTranslator.UpdateTranslation(Screen.CustomForms[i]);
+    end;
+  end;
+end;
+
+
+initialization
+  //It is safe to place code here as no form is initialized before unit
+  //initialization made
+  SetDefaultLang('');
+
 finalization
-  LocalTranslator.Free;
+  LRSTranslator.Free;
 
 end.
--
_______________________________________________
Lazarus mailing list
Lazarus@lists.lazarus.freepascal.org
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus

Reply via email to