Localization in .NET console and desktop apps
blog.axantum.com
blog.axantum.com
I did A LOT of translation work and in the end the best, easiest and fastest solution always was a list / map of key value pairs, where key was a unique translation identifier and the value was the translation in one language optionally having placeholders (e.g. for numbers) combined with a simple macro (best case) / function / method similar to sprintf.
Even plural forms should get their own unique identifier - automatic pluralization always failed for my use cases (russian has several different plural forms depending on the context).
I never had a problem with resx and .net satellite assemblies and all that as far as the format goes. But it's always been an issue how to involved translators in a way that's both simple for the translators, safe for the quality and as automated as possible in bringing the translations back to the app.
I think the solution is quite simple:
- One unified key value pair format (for translators and GUI tools)
- One intermediate format that is programming language specific (it could be generated code or highly integrated formats like resx)
- A simple tool that can transliterate between those two formats
Workflow example: - Export a unified format file from resx with placeholders for the translations
- Translators: Here you go, use your GUI tools on this
- Get back the translated unified format
- Import a unified format file to resxAs for bloat, I find the .po format to be quite bloated, with it's use of the full texts as keys in each and every translation. I don't really like that, but in practice it appears to be working well and has been for many years. Then again, the obvious choice today would be json.
I built a gettext-style system for my own software, so I feel like it's possible to do. But the gap between that and making something everyone can use is pretty big.
(With the new "source generator" work it should be relatively straightforward to implement a gettext-style source scan if that's what you want.)
With Windows Forms, at least back in the day, you could open a Form in the designer, change its language to something else and just edit text on the controls (or images, etc.). The changes would go into a resx file for the selected language. At first glance this looked quite cool, but on the other hand, translators now can ruin your UI, as there's not really a dedicated translation view that only allows to change resources ...
You basically annotate all your strings with a "my string".t() or t($"my interpolated string: {var}") and then use their CLI to extract the strings to be translated. It even includes google translation API support for you to kickstart the process.
The framework and UI: https://github.com/neosmart/Localization
Sample translations: https://github.com/neosmart/easybcd-localization
Guide and screenshots (that should have probably be also folded into the non-existent readme for the localization toolkit repo): https://neosmart.net/forums/threads/translations-to-other-la...
XML is a drag, but JSON isn't supported without a dependency under .NET Framework and the single-binary NLTUI app masks that from most users. XML also gives nice schema validation, for example look at how simple the validation is in the github action ci for the real-world app example from above: https://github.com/neosmart/EasyBCD-Localization/blob/master...
Reading/writing resx is 10 lines of code or something. I just dump ours into an excelsheet with one column per language, because for whatever reason the translators wants it in excel like that. Then when they are done I convert it back to resx files.
https://neosmart.net/forums/threads/translations-to-other-la...
The tool loads a directory of xml files; each file is rendered as a tab in the translation GUI. The framework exports the strings from each SWF form as a separate xml file into a directory that matches the native locale’s identifier (eg en-US) and gives it a friendly name based off the form’s title/caption and/or file name. So the end result is a naturally user-friendly approach to translation instead of having all the apps strings dumped together into one PO file as is the norm, and translators can reference the app they are translating’s UI as they methodically translate a component at a time.
I found an attempt at doing Fluent in .NET: https://github.com/blushingpenguin/Fluent.Net/
I also found at least one library for supporting ICU MessageFormat in .NET: https://github.com/jeffijoe/messageformat.net
Hope they can just use iconv directly.
It's tended to work relatively well for me.
As mentioned, the issue I'm trying to solve is not the code end. Resx works fine once it's there. It's the translator end. How to present the texts and translations and context etc to the human, often non-technical, translators and often many and one translator might only translate a few strings, then another one etc. So it has to be real easy to use and gain access to. Can't for example ask them to install a piece of software. Finally, once a text has been translated, how to get it back to the app as easy and preferably as automated as possible.