DxDublin 9 Posted October 30, 2022 (edited) I am currently looking for a localization tool for my Delphi VCL application. I have found three localization tools for Delphi that are also actively maintained. They are: TsiLang Korzh Localizer Soluling I have quickly tested them all. TsiLang is Delphi only and based on components. It is cheap. The downside is that it requires adding components of every form and also refactors my code. Has an external translation editor. No form editor. Korzh is Delphi only. Does not require components. Has external translation editor. Little more expensive than TsiLang. Soluling supports many file formats including Delphi. It seems that it is written in Delphi. Does not require components or refactoring. More expensive that the others. Modern UI. External translation editor with WYSIWYG form editor. Seems to be a full featured CAT tool with support for translation memory, terminology, machine translation, fuzzy, etc. What I would like to know in each tool. Is support good? How do they maintain the product? When a new Delphi version comes, are they up to date? Any other comments are welcome. Any other tools I missed? However, I am only interested in tools that are actively maintained and supported. Edited October 30, 2022 by DxDublin Share this post Link to post
aehimself 396 Posted October 30, 2022 Came here to post the same. Better translation manager is working wonders. Share this post Link to post
dummzeuch 1505 Posted October 30, 2022 I would really have liked to recommend gnugettext for Delphi (dxgettext) + the tools for the standard po file format here (I really do like Gorm for editing po files). Unfortunately it is mostly unmaintained by now, even the homepage has now disappeared into the depth of the Internet Archive. The only plus is the price: You can't beat free. Share this post Link to post
Fr0sT.Brutal 900 Posted October 31, 2022 AFAIU the main task of these tools is handling strings defined inside forms. Translating string literals in code is simple, the devil is in forms. Thus if forms do have texts, gettext and similar generic tools are not applicable. If forms do not have texts, any tool will fit, including primitive quickly self-made stuff Share this post Link to post
dummzeuch 1505 Posted October 31, 2022 32 minutes ago, Fr0sT.Brutal said: AFAIU the main task of these tools is handling strings defined inside forms. Translating string literals in code is simple, the devil is in forms. Thus if forms do have texts, gettext and similar generic tools are not applicable. If forms do not have texts, any tool will fit, including primitive quickly self-made stuff Gnugettext for Delphi (dxgettext) handles (VCL) forms. 1 Share this post Link to post
Fr0sT.Brutal 900 Posted October 31, 2022 (edited) 3 hours ago, dummzeuch said: Gnugettext for Delphi (dxgettext) handles (VCL) forms. Then the only difference between translation engines is how powerful their translation UIs are. Edited October 31, 2022 by Fr0sT.Brutal Share this post Link to post
DxDublin 9 Posted November 1, 2022 (edited) I did a more thorough test with these four localization tools. Our application is huge. It contains hundreds of forms and thousands of units. Most of those units have resource strings. We also use visual form inheritance in every form. We use frames and inherited frames, too. Our forms have been designed such a way that there is plenty of room for string expansion. So, we do not need a form editor to change the layout. However, translators need a form preview to see the context of the strings. We use several freelance translators that need to work simultaneously with the developers. We use CI/CD and new content appears almost every week. Finally, we have both 32-bit and 64-bit version of our application. We target to 6 languages. Before we start, I would like to point it out that Delphi has a specific pattern how the localization should be done. It is to use forms, resource strings and resource DLLs. ITE uses this approach. Unfortunately, the implementation of ITE is just so bad that it is barely useable. Therefore, there is room for other tools. Let’s start write TsiLang. It is a component-based solution. It does not follow the standard VCL localization method but forces you to do major refactoring to your code. This means adding components to every form and replacing resource strings with TsiLang’s own implementation. The product works, and it is very cheap. I am sure TsiLang has its own fans. In a large project like ours, the price of the localization tool is not the prime factor. The features are. This is where TsiLang gets short. No form preview, propriety implementation, limited team work features, limited translation aids (TM, MT, terminology). This was the first to go. Korzh Localizer is a step forward. It allows you to use resource strings. It does not refactor your source code hardly at all. However, it is not based on resource DLL but uses its own language files. Like TsiLang it does not have form preview and has very limited translation aids. This was the second to go. Remaining two tools, BTM and Soluling, both works on the right principle: the standard VCL localization method. They are also totally decoupled from Delphi IDE that is very important. I like them both. BTM is a free tool and a very good one. It does the localization so much better than the TsiLang and Localizer. BTM is free and Anders has maintained it for three years. Huge respect for him. However, BTM lacks some very important features. First the form preview. Second is that if you have both 32-bit and 64-bit applications, you need to create two separate projects and somehow copy paste the translations. In addition, it scans all strings properties and you have to exclude them manually. There are no rules to configure what properties to localize and what to ignore. BTM has some translations aids but lots of features are missing, such as translation validation and interactive TM/MT/terms. My test sample contains TTreeView and TListView components. TsiLang, Localizer and BTM did not scan the nodes of those components. They were just ignored. What am I supposed to do in a case like that? Remove the design time data and populate the nodes on runtime using resource strings. No thanks. In most case you do not need (and should not) localize images but sometimes you have to. These tree tools cannot handle them either. This brings me to the last tool, Soluling. Soluling is more expensive than the above three tools. However, with that price, you get a tool that has all the features you need to localize a large VCL application. Soluling has a brilliant form editor. It is not only a preview, but you can change the layout. I would suggest not to go on that path but to pay some extra attention to your original UI design. However, if you need to do layout change, you can. Soluling localizes TTreeView, TListView and images. Soluling also has a concept of platform files. It means that you can add many variants of the same EXE file (e.g. 32-bit, 64-bit, debug, trial, etc.). No need to have a duplicate project file. No need to translate the same strings twice. Soluling’s translation aids are top level. Soluling’s features even exceed the features of the mainstream CAT tools like Passolo, MemoQ and Catalyst! Finally, in most cases you have also some other files but Delphi application to localize. For example, you might have some documentation files and web pages. Soluling can do those too. I quickly tested HTML, React and Markdown. All worked nicely. Both BTM and Soluling have a command-line tool to be used in the build pipeline. The both tools require zero changes to your source code and you are not forever bound to the tool you selected, such in the case you selected TsiLang or Localizer. Ultimately, this is a “battle“ between two Nordic guys: Anders and Jaakko. They both did it right. If you have a small Delphi-only project and small budget, go for Better Translation Manager. If you have a larger project or budget, or you also have other files but Delphi EXEs, go for Soluling. I have attached screnshots from each tool. Edited November 1, 2022 by DxDublin 4 5 Share this post Link to post
aehimself 396 Posted November 1, 2022 I never checked, but isn’t the Delphi localization file a regular resource DLL, without code? If this is the case (and your source is not IFDEF-ing resource stings) the same file can be used by 32 and 64 bit applications. Afaik a new DLL is only required if there is ANY code (including self-extracting, like UPX). Share this post Link to post
Anders Melander 1782 Posted November 1, 2022 Thanks for the kind words. Much appreciated. 1 hour ago, DxDublin said: First the form preview. Yes, I made a conscious choice not to include any kind of form editor or preview, even though I have these features implemented locally, simply because they never work reliably. The main problem is that in case your forms contains 3rd party controls, then the viewer/editor will need to be able to load the runtime packages containing these controls, and the packages have to be the correct version, for the correct version of Delphi. etc. etc. It's a nightmare. For in-house translation, I think I came up with a better solution to providing context. With a few lines of code one can have BTM follow the focus of the target application. Start the target application, open a form in the application and BTM will automatically select the corresponding module. Click a control in the application and BTM will select the properties of that control. Of course with external translators providing the application, and all the dependencies it might have, might not be feasible (it isn't in our case). In that case a simple screenshot should do it. 1 hour ago, DxDublin said: Second is that if you have both 32-bit and 64-bit applications, you need to create two separate projects and somehow copy paste the translations. No need for that. The language modules, as @aehimself said, are just empty resource DLLs with no code. The same DLL stub is used for 32- and 64-bit. 1 hour ago, DxDublin said: In addition, it scans all strings properties and you have to exclude them manually. There are no rules to configure what properties to localize and what to ignore. Sure there is; It's called a Stop List. You can configure properties or modules to ignore based on a plethora of different rules - or regex if everything else fails. 2 hours ago, DxDublin said: BTM has some translations aids but lots of features are missing, such as translation validation and interactive TM/MT/terms. Validation is performed live. In addition, you can validate the whole project via the ribbon: BTM validates a host of different properties such as leading and trailing space/colons/whatnot, delimiters, shortcuts, case (and type of casing), etc. etc. Many validation violations can be resolved automatically. Some are too risky to try and do automatically. I don't know what you mean by "interactive TM/MT/terms". If you mean automatic translation lookup and prompt, then BTM does that too. The UI sucks a bit though. 2 hours ago, DxDublin said: My test sample contains TTreeView and TListView components Yes, these are Windows common controls and unfortunately, the VCL developers chose to persist them using their internal binary (and undocumented) stream format. If you look at the DFM file of a form containing one of these controls you will see what I mean. I guess I could write adapters specifically for these controls but so far I haven't had any requests for them. 3 Share this post Link to post
John R. 18 Posted November 2, 2022 15 hours ago, DxDublin said: I did a more thorough test with these four localization tools. Thanks for your feedback as it will be helpful to me down the line. I'm still using Sisulizer which still works very well and have all the features that you describe. Unfortunately, his author died and the tool is not maintained or available anymore 😞 It looks like his brother is the creator of Soluling (from the screenshot, they sure look quite similar) and it might be a good path forward in case I can't use Sisulizer anymore due to a future Windows / Delphi breaking update! I also like what I see with Better Translation Manager and will surely investigate that one when the time comes. Hopefully, I will be able to import existing translation into those tools 🤞 Share this post Link to post
Jaska 7 Posted November 2, 2022 17 hours ago, aehimself said: I never checked, but isn’t the Delphi localization file a regular resource DLL, without code? If this is the case (and your source is not IFDEF-ing resource stings) the same file can be used by 32 and 64 bit applications. Afaik a new DLL is only required if there is ANY code (including self-extracting, like UPX). Resource only DLLs are platform independent so the same DLL can be loaded in both 32 and 64-bit environment. However this doesn't solve the problem. It only works if the resource string IDs in both 32-bit and 64-bit EXE are exactly the same. This is not the case on most Delphi application. If you compile the same source to 32 and 64 bit you will see that 1) The amount resource strings differ 2) The Ids of the resource strings differ So you have to build two sets of resource DLLs. One for 32 bit and another for 64-bit 1 Share this post Link to post
Sherlock 663 Posted November 2, 2022 I admit it has been 10+ years since I looked into translation tools, but dxgettext was the least Delphi like with an inability to use resourcestrings. Multilizer and later on Sisulizer have been the tools of choice for me ever since. But I must admit I have not been needing localization tool in the past couple of years so my bias is very sure to be outdated. Share this post Link to post
Anders Melander 1782 Posted November 2, 2022 18 minutes ago, Jaska said: It only works if the resource string IDs in both 32-bit and 64-bit EXE are exactly the same. This is not the case on most Delphi application. Good point. Luckily it's just the numeric ID values that change and these values aren't even guaranteed to be stable across compiles within the same platform. This is why BTM (and I'm guessing Soluling too) use the resourcestring names instead of the ID values to identify the strings. The DRC file contains the mapping between name and ID value and this file is used when scanning the source application and when building the resource module DLL. So in order to build a resource module for a particular platform, you just point the build tool to the exe and drc of that platform and you will get a resource module that matches them. Share this post Link to post
Jaska 7 Posted November 2, 2022 17 minutes ago, Anders Melander said: Good point. Luckily it's just the numeric ID values that change and these values aren't even guaranteed to be stable across compiles within the same platform. This is why BTM (and I'm guessing Soluling too) use the resourcestring names instead of the ID values to identify the strings. The DRC file contains the mapping between name and ID value and this file is used when scanning the source application and when building the resource module DLL. So in order to build a resource module for a particular platform, you just point the build tool to the exe and drc of that platform and you will get a resource module that matches them. Yes we use DRC files and resource names. I noticed that BTM is forcing to use them. Good choice. I should start doing the same 🙂 This ID shifting is very annoying, but I guess it is very difficult the prevent it unless Delphi compiler starts caching the name-id maps. Now it seems to regenerate them every time in the order it processes each string. Share this post Link to post
Anders Melander 1782 Posted November 2, 2022 2 minutes ago, Jaska said: This ID shifting is very annoying, but I guess it is very difficult the prevent it unless Delphi compiler starts caching the name-id maps. It's unavoidable. For instance if a resourcestring is deleted then the whole range of IDs above it must change their ID. With regard to Windows resources I don't think ordinal resource IDs (not just string IDs) were ever meant to be stable. Instead we were supposed to use .rc and .h files and symbolic names - which is basically what the drc file is. 1 Share this post Link to post
pyscripter 689 Posted November 2, 2022 (edited) In PyScripter we use dxgettext along with https://www.transifex.com/ for translations teams collaboration and github integration. dxgettext offers a great deal of control as to what should get translated and there is an advantage in using industry standard translation formats for which a variety of editing and management tools exist. Edited November 2, 2022 by pyscripter Share this post Link to post
shineworld 73 Posted November 2, 2022 In my projects, I use dxgettext with PoEdit pro, which creates an internal net DBase of translated terms, so any old translation, made by me or my colleagues can be fastly re-used. It also permits auto-translations using Microsoft Translation tools, Deepl (if you have a pro account), etc. It has also a free version so end-customers can translate the programs to their native language with total autonomy, because gettext translations are in extern .mo files (but can also be embedded in the EXE if you want). Share this post Link to post
dummzeuch 1505 Posted November 2, 2022 2 hours ago, Sherlock said: I admit it has been 10+ years since I looked into translation tools, but dxgettext was the least Delphi like with an inability to use resourcestrings. dxgettext has been supporting ressourcestrings ever since I started using it, about 15 years ago. I don't know when that was implemented. Share this post Link to post
DxDublin 9 Posted November 2, 2022 2 hours ago, pyscripter said: In PyScripter we use dxgettext along with https://www.transifex.com/ for translations teams collaboration and github integration. dxgettext offers a great deal of control as to what should get translated and there is an advantage in using industry standard translation formats for which a variety of editing and management tools exist. We are also planning to integrate to a translation service. Our security (and I agree) does not allow a direct Git integration to a third-party service. So, we are planning to do that with a CLI or REST API. The planned process in our build server: Delphi EXE -> Soluling command line -> XLIFF (or TMX or Excel) -> translation service API -> Translated XLIFF -> Soluling command line -> Resource DLLs We haven't picked the service yet. Currently looking for MemSource and XTM Cloud. Maybe now also Transifex. Share this post Link to post
omnibrain 15 Posted November 2, 2022 Tsilang is horrible, horrible, horrible for source control. It stores the translation data in a blob within the DFM. I don't know the other tools, but I would take a sharp look at how they store their translation data. Share this post Link to post
limelect 48 Posted November 4, 2022 I have been using for years https://github.com/yktoo/dklang Share this post Link to post
TigerLilly 16 Posted November 7, 2022 At the moment, I have no experiences with that: https://components4developers.blog/tag/i18n/ Share this post Link to post
Igor Sitikov 5 Posted December 12, 2022 On 11/1/2022 at 10:28 PM, DxDublin said: replacing resource strings with TsiLang’s own implementation. You don't need to replace resource strings if you don't want. Just use Import Resource Strings Wizard and set HandleResourceStrings property to True. And TsiLang will translate your resource strings on-fly. Quote No form preview, propriety implementation, limited team work features, limited translation aids (TM, MT, terminology). This was the first to go. Using Translations Comments you can add comments and preview image to any element: Dictionary Manager, that builds you translations database for easy re-use, supports wide range of automatic translations services: Quote My test sample contains TTreeView and TListView components. TsiLang, Localizer and BTM did not scan the nodes of those components. They were just ignored. What am I supposed to do in a case like that? Just use TsiLangTLV component instead of regular TsiLang and your TTreeView and TListView items will be translated the same way as others properties: And using Extended Translations property you can translate almost ANY property of any component: Share this post Link to post