Clément 148 Posted September 28, 2020 Hi, I'm revisiting the application I wrote to help me manage my applications localization, but after seeing all the nice work done in better translation manager... I'm puzzled.. Should I continue with my interface, or move to BTM? So here I am....I need to know how I can duplicate some features my implementation has. Basically my application generates a global class (glbLocalization) that I include in my projects. I can access all the localization properties I require. For example: glbLocalization.FormLogin.btnLogin.caption( aLanguageID : Cardinal = 0 ) When LanguageID is 0, the user default kicks in, which means, can be windows language, or any other language the user wants to be its default. There is a feature that my customers are very used too: Multi language UI. Basically this features allows the user to do whatever localization combination he likes: * The application remains in the main language, reports can be generated in any other languages. * Any form can be opened in different languages. Ex: All the user interface is in portuguese. The reports can be viewed in portuguese and mailed to a Brazilian manager, switch to any other supported language and email the report directlly The user might need to share some information available on his form with another user in LA, He opens another form in Spanish and share the contents. The implementation became trivial since I just have pass the LanguageID as the parameter ( to a form, report, etc) and everything is retrieved from the corresponding resource. To achieve this I generate a single resource file (.RC) with all the supported languages and translation. Given the LanguageID, it's a matter to go the corresponding section and get the string. Delphi's RTL resources (aka ResourceString) are not translated, it's a feature I would like to add in this new version. Back in Borland era, when I studied delphi translation features, I haven't found a way to implement the above features. Is there a way to use BTM (or delphi native localization) to mimic the above feature? Share this post Link to post
Anders Melander 1783 Posted September 28, 2020 It seems to me that what you're describing is beyond the scope of localization and therefore BTM. BTM is a localization manager/editor. It provides translations to the standard localization mechanism built into the Delphi RTL. If you're not using that, and it doesn't sound like it, then I can't see how BTM can meet your needs. That said, the translated resource modules generated by BTM are just DLLs containing the translated resources (i.e. resourcestrings and DFMs). This means that you can use regular Windows APIs to load and extract the resources from these resource modules. It's also possible to hook into the resource loading mechanism and redirect the loading of selected forms to other resource modules. This could provide the multi-language capability. You could also just read the translation project file (it's XML) and extract the translations from there. But, to be honest, none of the above sounds like a good path to go down. Share this post Link to post
Clément 148 Posted September 28, 2020 I liked BTM but I was afraid you would say that. I will have to keep my interface then. Anyway, thanks for that great tool! Share this post Link to post
FPiette 383 Posted September 29, 2020 I use dxGetText (https://sourceforge.net/projects/dxgettext/) in all my application which must support several languages. To do the translation it self, I used PoEdit (https://poedit.net/). I have never been confronted to some parts being translated in one language and others translated in a different languages but I think it is possible to do it since translation process pass by functions you have control on it. Share this post Link to post
dummzeuch 1505 Posted September 29, 2020 1 hour ago, FPiette said: I have never been confronted to some parts being translated in one language and others translated in a different languages but I think it is possible to do it since translation process pass by functions you have control on it. I have done that with dxgettext, so, yes, it can be done. But beware that dxgettext does not support translating FMX forms out of the box, only VCL. As for the translation tool, I prefer Gorm over PoEdit, mostly because it's written in Delphi and I have got the source code and write access to the repository, so I can adapt and extend it (and have done that). Share this post Link to post
luebbe 26 Posted September 29, 2020 There's also the Virtaal translation editor, which hasn't been updated for a while, but works fine. There are many platforms that can handle gettext .po files and provide nice web editors, if you are in need of collaborative translation. Most of them are free for OSS projects. Share this post Link to post
Clément 148 Posted October 10, 2020 (edited) Hi, I finally reached a Beta version of the utility I'm rewriting to help me manage my application localization. Since I talked about it here, I thought I could share some screens to give you an idea of this tool. I'm using mustache templates to generate the output, in theory the utility can generate code for any language. The generation process creates a JSON containing the translations that is merged with the templates. For the .RC and Delphi I using the following templates: .RC: {{#constants}} #define {{name}} {{value}} {{/constants}} {{#resources}} STRINGTABLE LANGUAGE {{language}}, {{subLanguage}} BEGIN {{#stringTable}} {{{name}}} "{{{value}}}" {{/stringTable}} END {{/resources}} .PAS (part of it): unit app.localization; interface uses WinAPI.Windows; const {{#languages}} {{constantName}} = {{languageID}}; {{/languages}} // --------------- {{#constants}} {{name}} = {{value}}; {{/constants}} function _( const StringID : DWORD; aLanguageID : DWORD = 0 ) : String; procedure SetDefaultLanguage( aLanguageID : DWord ); implementation {$R {{outputRES}}} var gDefaultLanguage : DWord; procedure SetDefaultLanguage( aLanguageID : DWord ); begin gDefaultLanguage := aLanguageID; end; function StringTableRes(hInstLib: Cardinal; idString: DWORD; wLang: Word): String; This is the generate .PAS: unit app.localization; interface uses WinAPI.Windows; const _EN_US = 1033; _PT_BR = 1046; _EL_GR = 1032; // --------------- GLOBAL_CPTN_BTN_OK = 1; GLOBAL_CPTN_BTN_APPLY = 2; GLOBAL_CPTN_BTN_CANCEL = 3; GLOBAL_CPTN_BTN_PRINT = 4; GLOBAL_CPTN_BTN_EXPORT = 5; GLOBAL_CPTN_BTN_FILTER = 6; GLOBAL_CPTN_GB_SAMPLEDATA = 7; GLOBAL_TXT_SAMPLE_DESCRIPTION = 8; FORMLOGIN_CPTN_WELCOME = 9; function _( const StringID : DWORD; aLanguageID : DWORD = 0 ) : String; procedure SetDefaultLanguage( aLanguageID : DWord ); implementation {$R teste.res} var gDefaultLanguage : DWord; procedure SetDefaultLanguage( aLanguageID : DWord ); begin gDefaultLanguage := aLanguageID; end; Let me show you the result: The code: implementation uses app.localization; {$R *.dfm} procedure TForm1.DoLocalize; begin GroupBox1.Caption := _( GLOBAL_CPTN_GB_SAMPLEDATA, _EN_US ); GroupBox2.Caption := _( GLOBAL_CPTN_GB_SAMPLEDATA, _PT_BR ); GroupBox3.Caption := _( GLOBAL_CPTN_GB_SAMPLEDATA, _EL_GR ); btnOK.Caption := _( GLOBAL_CPTN_BTN_APPLY, _EN_US ); btnOk1.Caption := _( GLOBAL_CPTN_BTN_APPLY, _PT_BR ); btnOk2.Caption := _( GLOBAL_CPTN_BTN_APPLY, _EL_GR ); btnCancel.Caption := _( GLOBAL_CPTN_BTN_CANCEL, _EN_US ); btnCancel1.Caption := _( GLOBAL_CPTN_BTN_CANCEL, _PT_BR ); btnCancel2.Caption := _( GLOBAL_CPTN_BTN_CANCEL, _EL_GR ); label1.caption := _( GLOBAL_TXT_SAMPLE_DESCRIPTION, _EN_US ); label2.caption := _( GLOBAL_TXT_SAMPLE_DESCRIPTION, _PT_BR ); label3.caption := _( GLOBAL_TXT_SAMPLE_DESCRIPTION, _EL_GR ); end; procedure TForm1.DoShow; begin DoLocalize; inherited; end; And the generator Edited October 10, 2020 by Clément Share this post Link to post