Programming => General => Topic started by: TheLastCayen on December 16, 2019, 10:20:13 pm

Title: Translation use .po and ignore my .mo files
Post by: TheLastCayen on December 16, 2019, 10:20:13 pm

I am using
 - Lazarus 2.0.6
 - FPC 3.0.4
 - Windows 7 64 bit
 - Poedit 1.5.7

I code something to add the language files in the menu of my application. The user is able to swap language on the fly. For testing purposes, I did 3 different language files for my application. EN, FR and ES. When I keep the .po files in my language folder, my application works fine. When I remove the .po and leave the .mo files, the translation stop working.

This is my code:
Code: Pascal  [Select][+][-]
  1. uses
  2.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, Menus, ExtCtrls,
  3.   Buttons, StdCtrls, EditBtn, BCButton, BCComboBox, BCLabel, DefaultTranslator,
  4.   LCLTranslator, translations, LazUTF8, BGRAResizeSpeedButton, fileutil,
  5.   backupclass, ustatus, dbf, uabout, LazFileUtils;
  6. ...
  7. function TFMain.FindLanguageFiles:TStringList;
  8. begin
  9.   Result := TStringList.Create;
  10.   Result := FindAllFiles(ExtractFilePath(Application.ExeName)+'languages','*.mo',False);
  11. end;
  12. procedure TFMain.CreateLanguageMenuItems;
  13. var
  14.   TMILanguage : TMenuItem;
  15.   LFiles     : TStringList;
  16.   tmpstring  : string;
  17.   I          : Integer;
  18.   Lang, FallbackLang: String;
  19. begin
  20.   LazGetLanguageIDs(Lang,FallbackLang);
  21.   LFiles := FindLanguageFiles;
  22.   try
  23.     if LFiles.Count > 0 then
  24.       MILanguages.Enabled := True
  25.     else
  26.        MILanguages.Enabled := False;
  27.     For I := 0 to LFiles.Count -1 do
  28.       begin
  29.         LFiles[I] := ExtractFileNameOnly(LFiles[I]);
  30.         tmpstring := UpperCase(StringReplace(LFiles[I],
  31.                      ExtractFileNameOnly(Application.ExeName)+'.',
  32.                      '',
  33.                      [rfReplaceAll, rfIgnoreCase])
  34.         );
  35.         if trim(tmpstring) <> '' then
  36.           begin
  37.             TMILanguage := TMenuItem.Create(Self);
  38.             TMILanguage.Caption := tmpstring;
  39.             MILanguages.Add(TMILanguage);
  40.             TMILanguage.ImageIndex:=SelectLanguageFlag(tmpstring);
  41.             TMILanguage.RadioItem := True;
  42.             If pos(tmpstring,Lang) > 0 then
  43.                TMILanguage.Checked := True;
  44.             TMILanguage.OnClick := @ChangeLanguage;
  45.           end;
  46.       end;
  48.   finally
  49.     if Assigned(LFiles) then
  50.       FreeAndNil(LFiles);
  51.   end;
  53.   If MILanguages.Count> 0 then
  54.     MILanguages.Enabled := True
  55.   else
  56.     MILanguages.Enabled := False;
  58. end;
  59. function TFMain.SelectLanguageFlag(Language:String): Integer;
  60. begin
  61.   Result := 2;
  62.   case Language of
  63.     'EN' : Result := 3;
  64.     'FR' : Result := 4;
  65.     'ES' : Result := 5;
  66.     'RU' : Result := 6;
  67.     'ZH' : Result := 7;
  68.     'JA' : Result := 8;
  69.   end;
  70. end;
  72. procedure TFMain.ChangeLanguage(Sender: TObject);
  73. begin
  74.   SetDefaultLang(LowerCase(TMenuItem(Sender).Caption));
  75.   MILanguages.Items[TMenuItem(Sender).MenuIndex].Checked  := True;
  76. end;  

I do not want to distribute un-compiled language file. Does someone know what I am doing wrong?

Thank you

Title: Re: Translation use .po and ignore my .mo files
Post by: wp on December 17, 2019, 01:18:46 am
I played a bit with the translation demo which comes with Lazarus and can confirm the issue. However, when I remove the .pot master file from the languages folder the mo files are detected, and translation is working. Of course, removing the pot file is not a permanent solution because changes in the source code will cause trouble. I think this is a bug and should be reported.
Title: Re: Translation use .po and ignore my .mo files
Post by: dbannon on December 17, 2019, 01:34:01 am
My model is to keep all translation files 'somewhere else', ../po/ in practice. Once I tell Lazarus they are there its happy to maintain them but they are not found at run time.

Then, when building a release (or lots and lots of pre-release tests) I generate .mo files using msgfmt.  ie

Code: [Select]
msgfmt -o BUILD/usr/share/locale/"$CCODE"/LC_MESSAGES/"$BASENAME".mo "$i"
msgfmt -o BUILD/usr/share/locale/"$CCODE"/LC_MESSAGES/ "$LAZ_FULL_DIR"/lcl/languages/lclstrconsts."$CCODE".po

That way, the final product never sees the .po or .pot files. The same .mo file works fine on Linux, Mac and Windows.

Title: Re: Translation use .po and ignore my .mo files
Post by: TheLastCayen on December 17, 2019, 02:21:13 am
Thank's for your answer.

dbanon, I hid the po files and try to recompile my software. As expected I get the same problem. I am not aware of msgfmt, I will search for these tools. It kind of worries me if msgfmt is able to compile .mo that works when other tools can't... I tough the structure of .po and .mo files were standardized for a quiet sometime now.

wp, my template is also a .po. I can't find any other .pot in my software folder:( Do I miss something?
Title: Re: Translation use .po and ignore my .mo files
Post by: dbannon on December 17, 2019, 07:03:37 am
Al, LCL looks for the translate files in a (quite a long) list of places, if it finds a .po it uses it, then it looks for a .mo.   Sort of, around the wrong way IMHO.  If you put them somewhere thats not on its list, it quietly fails and continues on.

So, do you mean that you have .mo files in the right place but no translate files are being found ?  That might indicate to me that the .mo file is somehow invalid.  But you do need to get the right combination of directory name and filename. I suggest you step through the code with the debugger, tedious but productive.

What operating system are you using ?  I expect msgfmt is Linux only, possibly Mac but probably not Windows. There is a standalone GUI tool, POEdit from memory the Windows people use.

Title: Re: Translation use .po and ignore my .mo files
Post by: TheLastCayen on December 17, 2019, 05:38:56 pm
Hi dbannon,

As mentioned in the original post, I am using windows and poedit. The mo files are found and in the right folder. If you look at the code I posted, the language option will be disabled if the files are not in the right folder. Actually, per mistake, I check twice to disable the language options.
Code: Pascal  [Select][+][-]
  1.     if LFiles.Count > 0 then
  2.       MILanguages.Enabled := True
  3.     else
  4.        MILanguages.Enabled := False;
I know the folder is the right one because when I copy my .po files in that folder, everything works fine.
Also, Before I deploy, I always test my app in a virtual machine without Lazarus... actually basic windows installation with only a free antivirus install. SetDefaultLang just ignores my .mo files.

I was waiting to see if anyone can help me with this issue but I think wp is right. This is a bug and I will have to report it.
Title: Re: Translation use .po and ignore my .mo files
Post by: wp on December 17, 2019, 06:54:51 pm
I am returning because you mentioned that you don't have a .pot template file, and I this reminded me that I am using Laz trunk, but you use v2.0.6.

So, I repeated my test: I copied the po files of the translations demo (in (lazarus)\examples\translations) to a new subfolder "po" of "languages"  and assigned this to the "PO output directiory" of the "i18n" options. Then I loaded the project into Laz 2.0.6 (later also into Laz trunk - with the same result), changed the main form caption in order to trigger a re-write of the po files. I opened all po files by poedit and updated the translations. This rewrites new mo files. I copied the mo files one directory level higher into the "languages" directory which is searched by LCLTranslator. In this configuration, LCLTranslator finds only the mo files. Running the demo in fact verifies that the translations are not used - just as you described. Something strange, though: Strings which are updated manually in the demo (such as the items in the "drinks" radiogroup) ARE translated - the GUI strings are not; see screenshot.

This happens also with Laz trunk - I don't know why I did not see this yesterday (too late?).

So, this really is a bug and you should report it to bugtracker. I am attaching the modified translations demo project. If you can verify my observations you can attach this project to the bug report.
Title: Re: Translation use .po and ignore my .mo files
Post by: TheLastCayen on December 17, 2019, 10:59:20 pm
Thank you for your help wp. I sent my software to a friend so he can test it for me and he notices when he changes the language from Spanish to English, few fields stay in Spanish... But if he opens the program in Spanish or in English, all the fields are translated properly. That was using the po file... something is really weird with lclTranslator.
Title: Re: Translation use .po and ignore my .mo files
Post by: dbannon on December 17, 2019, 11:43:30 pm
OK TheLastCayen, while you can post a bug report as WP suggested, I reckon you will get a lot further if you track the actual problem down and, ideally provide a fix.

While I normally work on Linux, I make install packages for Windows and the translation appears to work fine, I ship only .mo files of course.

So, back in your Lazarus IDE, open {lazarus source}/lcl/lcltranslate.pas, you can get there from the entry in your 'uses' line.

Go to about line 95, function FindLocaleFileName(LCExt: string; Lang: string; Dir: string): string;

Thats the function that attempts to find po and mo files. Incidently, apart from wasting a few cycles, its all you need to decide to use non-english or not, you don't need to check in your own code for the presence of the files.

Set a break point at the fist 'begin' and set a watch on 'Result' and you can step through the functions attempts to open your translate files. Last time I did this I notes that it tried to open -


My app, pretty obviously, is tomboy-ng and in this case its launched from /home/dbannon/Pascal/tomboy-ng/tomboy-ng/, I don't see any mention of it trying in a directory one up from current directory but maybe I found what I was trying to understand and stopped watching.

Also as I noted above, you need two .mo files, one with the same name as your executable (less the .exe in your case) and one that has the LCL constants, when you generate it, its called and lives in the same place as {your-app}.mo

If you are seeing some things translated and some not, it could be that you have only one of the required files, or it could mean that your .po file is not being updated as you add extra string constants.  Lazarus automatically puts the string constants you use in the ObjectInspector but you need to declare other string constants as "RESOURCESTRINGS".

But, anyway, I strongly advise you to really track down the bug before logging a report, you will get far better attention if you do.

Title: Re: Translation use .po and ignore my .mo files
Post by: AL on December 30, 2019, 12:53:11 am
Same problem here.
Program translation works fine with po files but does not work when only mo files are present.

May be this is related:

The new function; SetDefaultLang('') always return the system language

My windows is in french
Calling SetdefaultLang('') returns fr

After calling SetDefaultLang('en')

Calling SetdefaultLang('') returns fr

Calling GetdefaultLang returns en

I never had a pot file created before laz 2.1.0
Title: Re: Translation use .po and ignore my .mo files
Post by: AL on March 28, 2020, 10:35:11 pm
As I am still having this problem:  .po files work Ok everything translate
                                                 .mo files work only on some resources strings
I made some investigation:
The LCLTranslator unit used works OK.  the .po files are found and the .mo files are also found when there is no .po or .pot files.(IMPORTANT) If you want the .mo to be used, do not leave the .po or the .pot  in the /languages directory as they get first priority.

Once found,
these procedures are called :
        LocalTranslator := TDefaultTranslator.Create(lcfn);
Strangely, the debugger did not went to the GetText.TranslateResourceStrings(UTF8ToSys(lcfn));
It just skipped to the next line even if I ask for StepInto and the source file was available.

So I think the problem is there but I cannot explain why this Gettext procedure was never called.  Note: there are 2 procedures with the same name , one for a string file name and one for tmofile file.  Might be related.

This is as far as I can go, I will leave the continuation to more experienced programmers
Title: Re: Translation use .po and ignore my .mo files
Post by: jamie on March 28, 2020, 11:15:42 pm
The debugger will not step into a file if it was not compiled with debug information.

The source file most likely will be available to you to view but the debugger does not have a debugger file to walk through it.

  More than likely you can step to that function but what happens is the next STEP it just goes to the next function. That does not mean it didn't get executed..
 But to rephrase that a bit, when stepping the code the debugger should stop on that line and then you should be able to step to the next line, you won't be able to STEP into the source code of that line if there is no debug info for it.

  if you don't see the debugger stopping on that line then there could be some issue at hand.

Title: Re: Translation use .po and ignore my .mo files
Post by: AL on March 29, 2020, 12:44:33 am
If I compile my app with the debugger ON this should also get debugger info no?
Title: Re: Translation use .po and ignore my .mo files
Post by: jamie on March 29, 2020, 12:49:30 am
Most likely not...

 You need to compile the package/Lib those functions are in with debugging on to generate a debug file for them.
TinyPortal © 2005-2018