Forum > Translations

How to use translations in applications made with Lazarus ?

(1/1)

mingodad:
I'm looking for how to make my application use transaltions stored in po files, but I couldn't find a way to do so.

I followed the example and instructions on the lazarus (http://wiki.lazarus.freepascal.org/Translations_/_i18n_/_localizations_for_programs) and I can get the LCLStrConsts to get translated but my application strings no.

Lazarus generate the po files for my application, I translate then but nothing happens, I've tried with this :

     //TranslateUnitResourceStrings('myapp', PODirectory + 'myapp.%s.po', Lang, FallbackLang);
     TranslateUnitResourceStrings('TFormMain', PODirectory + 'myapp.%s.po', Lang, FallbackLang);
     TranslateUnitResourceStrings('LCLStrConsts', PODirectory + 'lclstrconsts.%s.po', Lang, FallbackLang);
     //TranslateResourceStrings(PODirectory + 'myapp.es.mo');

None of then worked, I saw that Lazarus IDE have all strings in a resource file, shoul I make one by hand too ?

I couldn't find any complete example to help, could be a good idea include a simpe example with the lazarus distribution.

Thanks in advance and appreciate any help !

OnixJr:
I was trouble with this too some time ago...

My steps:
1 - Create a resourcestring in unit1.pas;
2 - Convert rst file to po file;
3 - Create a new language file (on my case, unit1.pb.po);
4 - Call translations: TranslateUnitResourceStrings('unit1', PODirectory + 'unit1.%s.po', 'pb', FallbackLang);

On my real case, I has don't use "unit1", obviously ^^...
I has created a specific unit to translations and add resourcestrings in this unit:
The unit is speLocalization.pas.
I has translated them and call translations in mainform:


--- Code: ---procedure TfrInicial.FormCreate(Sender: TObject);
const
  SPE_ST = 'speLocalization'; // the unit name without extension
  SPE_POFile = 'speLocalization.%s.po'; // thefile name
begin
  TranslateUnitResourceStrings(SPE_ST, CamRoot + SPE_POFile, 'pb','');  // Translation to brazilian portuguese..
  // Remember: CamRaiz = A variable with stores directory of my app...
  ShowMessage(speSO_meInfo_Lines_Text); // Testing with a resourcestring
  {...}
end;

--- End code ---


Good Luck!

mingodad:
I saw that it's the same as used in Lazarus IDE but it's a pain in the ass write again the strings as a resource file, I want a way that's magically automatic, I'm frustrated with this aproach and I'm creating a function than open the "mo" file ans deep in the forms to translate it's contents, something like this:

unit datamodule;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, LResources, Forms, Controls, Dialogs, Postgres3dyn, dblogin, gettext, translations;

type

  { TDataModuleMain }

  TDataModuleMain = class(TDataModule)
    procedure DataModuleCreate(Sender: TObject);
    procedure DataModuleDestroy(Sender: TObject);
  private
    { private declarations }
    conn :  PPGConn;
    pghost,pgport,pgoptions,pgtty,pgdbname, pgdbuser, pgdbpass : Pchar;
    mofTranslations : TMOFile;
  public
    { public declarations }
    property DbHost : Pchar write pghost;
    property DbPort : Pchar write pgport;
    property DbOptions : Pchar write pgoptions;
    property DbTTY : Pchar write pgtty;
    property DbName : Pchar write pgdbname;
    property DbUser : Pchar write pgdbuser;
    property DbPass : Pchar write pgdbpass;
    function GetPGconn() : PPGConn;
    procedure TranslateForm(frm : TForm);
    function TranslateStr(str : String) : String;
  end;

var
  DataModuleMain: TDataModuleMain;

implementation

uses menus;

{ TDataModuleMain }

procedure TDataModuleMain.DataModuleCreate(Sender: TObject);
var
      PODirectory, Lang, FallbackLang : String;
begin
  InitialisePostgres3;
  conn := nil;
     PODirectory := 'languages/';
     GetLanguageIDs(Lang, FallbackLang); // in unit gettext
     try
          TranslateUnitResourceStrings('LCLStrConsts', PODirectory + 'lclstrconsts.%s.po', Lang, FallbackLang);
          TranslateUnitResourceStrings('lr_const', PODirectory + 'lr_const.%s.po', Lang, FallbackLang);
          mofTranslations := TMOFile.Create(PODirectory + Format('dadbiz.%s.mo', [FallbackLang]));
     except
          mofTranslations := nil;
     end;
end;

procedure TDataModuleMain.DataModuleDestroy(Sender: TObject);
begin
  PQfinish(conn);
  ReleasePostgres3;
  mofTranslations.Destroy;
end;

.......

procedure TDataModuleMain.TranslateForm(frm : TForm);
var
   i, j : Integer;
   str, strt : String;
   
   procedure deepControls(ctrl : TWinControl);
   var
      i, j : Integer;
      str, strt : String;
      wctrl : TControl;
   begin
       for j := 0 to ctrl.ControlCount-1 do
       begin
              wctrl := TWinControl(ctrl).Controls[j];
              wctrl.Caption:= TranslateStr(wctrl.Caption);
              if wctrl is TWinControl then
                 deepControls(TWinControl(wctrl));
       end;
   end;
   procedure deepMenus(mn : TMenuItem);
   var
      i, j : Integer;
      str, strt : String;
      wmn : TMenuItem;
   begin
     for j := 0 to mn.Count-1 do
     begin
            wmn := mn.Items[j];
            wmn.Caption:= TranslateStr(wmn.Caption);
            deepMenus(wmn);
     end;
   end;
begin
     if mofTranslations = nil then exit;

     deepControls(frm);
     if frm.Menu <> nil then
     begin
       for j := 0 to frm.Menu.Items.Count -1 do
       begin
            frm.Menu.Items[j].Caption:= TranslateStr(frm.Menu.Items[j].Caption);
            deepMenus(frm.Menu.Items[j])
       end;
     end;

end;

function TDataModuleMain.TranslateStr(str : String) : String;
begin
     if mofTranslations = nil then
        Result := str
     else
     begin
         Result := mofTranslations.Translate(str);
         if Result = '' then Result := str;
     end;
end;

initialization
  {$I datamodule.lrs}

end.


This is the first attempt, I should go inside grids and translates it column headers and with others I should find it's way,
I only need to add

DataModuleMain.TranslateForm(self);

on the FormCreate event and voyla it's done, well almost done !

I still appreciate new feedback, thanks for your answer !

OnixJr:
Yeah, but as my app is small, I don't see [yet] a reason to do everything automatically [or magically =]...
Actually, I'm using a "TranslateForm" procedure to do this "manually" too...
But your idea is very nice, maybe the program can check if Components[n].ClassName = 'blablabla' and apply respective property...

In IDE code, it's passed as parameter in menu creation...
See MainBase file...
It's create menus with respective resourcestring...


--- Code: ---CreateMenuItem(ParentMI,itmFileNewUnit,'itmFileNewUnit',lisMenuNewUnit,'item_unit');
--- End code ---


I don't know today, but some time ago I has downloaded Virtual Magnifying Glass and it translates manually all components too (but it doesn't use po files, because it compiles in Delphi too... It's uses other way to store/read translations...)

If you write a good procedure to get all components on form and translate them, maybe you can send as patch to developers put it on examples directory...

And don't forget to compile and use updatepofiles program (in \tools directory) to update your .po files after you add new resourcestrings...

So long =)

LazaruX:
Hi, this is something I wrote and will use from now to translate my applications, I don't know the methods you used, but I think my solution is simple enough:


--- Code: ---unit Unit2;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs;

type
  TForm2 = class(TForm)
  private
    { private declarations }
  public
    { public declarations }
  end;

  procedure Translate;

var
  Form2: TForm2;

implementation


uses
 unit1;

{==============================================================================}
{- T R N S L ------------------------------------------------------------------}
{==============================================================================}
function trnsl(name:string;strng:string):string;
var
 f:text;
 ch:char;
 strA, strB:string;
begin

 try
  begin
   assignfile(f,name);
   reset(f);

   strA:='';
   while not eof(f) do //Repeat this until the end of the file is reached
    begin
     read(f,ch);       //Read a charachter

     strA:=strA+ch;
     {If the string of charachters read until now matches the defined string,
      then read the rest and return it }
     if(strA = strng)then
      begin
       readln(f,strB);
       trnsl:=strB;    //Return the correct value
      end;
   end;
   closefile(f);
  end;

 except

  begin
   showmessage('There was an error when trying to process the file');
  end;
 end;

end;


{==============================================================================}
{- T R A N S L A T E-----------------------------------------------------------}
{=This is a procedure for the language=========================================}
procedure Translate;
begin
 Form1.Caption:=trnsl('test.txt','[FormName]');

end;

initialization
  {$I unit2.lrs}

end.


--- End code ---

Just change the file name and use some constants for all your components, the load the procedure onCreate.

Navigation

[0] Message Index

Go to full version