[HN Gopher] Localization in .NET console and desktop apps
___________________________________________________________________
Localization in .NET console and desktop apps
Author : svantex
Score : 78 points
Date : 2024-05-15 10:08 UTC (1 days ago)
(HTM) web link (blog.axantum.com)
(TXT) w3m dump (blog.axantum.com)
| morning4coffe wrote:
| Nice blog post! I see you worked with AvaloniaUI. Have you also
| heard about Uno Platform?
| svantex wrote:
| Thanks. Yes, I looked at AvaloniaUI, Uno, Xwt, and MAUI before
| finally deciding on AvaloniaUI. It's not been entirely
| frictionless, there are some glaring omissions, the
| documentation is not great and the learning threshold if you're
| not really good with WPF is pretty high. Still, it does work,
| and I have the app running on Windows, Linux and macOS with
| very, very little platform specific code.
| kevingadd wrote:
| It still frustrates me that there's no built in gettext-style
| affordances for C#. I guess it doesn't fit the way people
| typically build software in .NET. IMO the result is that it's
| more work to localize your software, so a lot of software that
| should get localized doesn't.
|
| 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.
| gwervc wrote:
| It's even more a mess when doing multi-platform. I've a
| Monogame Android prototype build of my game and somehow the
| .NET localization throws me exception at runtime. So it's
| easier to implement a service that load and handle localization
| than relying on supposed built-in mechanism.
| pjc50 wrote:
| You're "supposed to" use string resources. There's support for
| having a different resource pack per languages. It's not
| exactly frictionless, though.
|
| (With the new "source generator" work it should be relatively
| straightforward to implement a gettext-style source scan if
| that's what you want.)
| svantex wrote:
| There's nothing wrong with the .NET resource system with
| culture-specific satellite assemblies etc as such. The bigger
| problem I see is lack of tooling and services for translation
| by non-developers, volunteers, professional translation
| bureaus etc. You can't expect them to fire up Visual Studio,
| clone your repo and start editing resx files. Especially as
| there's not even a translation view! With .po files, there's
| a ton of editors, online services, translators etc available.
| radnor wrote:
| At a previous job we utilized https://webtranslateit.com/ -
| it organized everything easily for volunteers to provide
| translations for all resx strings.
| svantex wrote:
| Nice, but perhaps a little pricy for small startups.
| That's actually one of the things I didn't emphasize
| perhaps. Not only is the gettext/.po eco system big,
| there's also a lot of free or relatively low cost
| services available.
| ygra wrote:
| > there's not even a translation view
|
| 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 ...
| theolivenbaum wrote:
| We've been using a library called TNT for this job and are quite
| happy with the flow: https://github.com/pragmatrix/tnt
|
| 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.
| svantex wrote:
| Nice, very ambitious! I like the twist to extract from the
| compiled IL code, much easier, more stable and reliable than
| parsing the source. My one gripe here is that the code does not
| follow the .NET paradigm of using resources at all. Still, very
| clever and a lot of functionality.
| tracker1 wrote:
| I've home grown a solution for this a couple times... directories
| of yaml files, where the default is en-US (for those I've worked
| on). The main set(s) of yaml files are built to path.filename as
| a prefix to the internal structure in the file... then typescript
| type(s) are generated from that... with other files then built
| and assigned the default type as the type. Then checks for errors
| are run. From there, code generation for server-side usage is
| done.
|
| It's tended to work relatively well for me.
| ammo1662 wrote:
| I remembered the last time I checked, the code page does not even
| follow the standards (maybe the Shift JIS). Some of the
| characters are missing in that character set.
|
| Hope they can just use iconv directly.
| svantex wrote:
| Thanks for all the feedback! The real issue that is not handled
| by several suggested alternatives is how to actually manage the
| translation process. resx files as such work fine - but... the
| problem is getting them from non-technical translators, possibly
| with their own tool preferences, or volunteers not having any
| tools or particular tech skills at all. That's what I'm trying to
| find a better way for, while still not breaking .NET practices.
| tuwtuwtuwtuw wrote:
| Considering resx has been supported for decades, why not just
| convert the resx into whatever the translator team wants?
|
| 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.
| svantex wrote:
| In my case there's no "translator team" as such. It's a mix
| of volunteers, part-time paid translators, colleagues etc.
| I've never had a translator team, it's always various ad-hoc
| situations and networks of people. And I don't want to write
| and maintain conversion software and such workflows.
| ComputerGuru wrote:
| You can see my top-level comment for more info, but we wrote a
| very quick and dirty UI to manage the XML localizations that
| allows "forking" a language into a new localization and showing
| outdated or missing localization strings. I don't think a
| single person that contributed a translation was actually a
| developer, but I've had no complaints about it being difficult
| to follow in the going-on-twenty-years since its release!
|
| https://neosmart.net/forums/threads/translations-to-other-la...
| svantex wrote:
| Nice - but very special purpose from what I can gather. I've
| done a few custom solutions myself over the years, but that's
| exactly what I'm trying to get away from. I want to write
| code that does cool stuff for the users of my apps, not code
| that does cool stuff to make translations possible - someone
| else can do that cool stuff ;-) where I'm the "user".
| ComputerGuru wrote:
| Thanks. Not actually really special purpose. One-click
| import from any SWF project, though no easy WPF/XAML sdk
| for lack of motivation. The GUI is fully app agnostic.
| unsignedint wrote:
| I'm not sure if I'm missing something here, but many
| translation solutions support ResX files out of the box. For
| example, I use memoQ, which has built-in support for ResX
| files. Additionally, open-source solutions like OmegaT can
| handle ResX files as well.
| WorldMaker wrote:
| The author's choice of Loco also claims to directly support
| ResX: https://localise.biz/help/formats/importing/xml#resx
| svantex wrote:
| Yes, resx support is finally becoming available in more
| solutions, but it's still not always a first class citizen.
| But perhaps that's the long-term solution, wait for resx to
| take over. Although it still doesn't support plural forms
| (then again my current setup doesn't either...).
| WorldMaker wrote:
| gettext/PO is just as deficient at modern plural forms
| support as ResX, out of the box. The only format that I'm
| aware of that is specifically built to include it as
| first-class is Mozilla's Fluent. The same workarounds
| generally apply to ResX as to PO: create a number of
| separate strings and do a bit of math up front to choose
| the right one, or use a formatter on top of PO/ResX that
| supports something like ICU MessageFormat.
|
| 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
| ComputerGuru wrote:
| We came up with our own localization framework back in the .NET
| 2.0 days and we're still using it. Version-numbered translations
| in an XML file with a simple GUI to show missing translations,
| flag out-dated translations, etc.
|
| 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...
| sandreas wrote:
| I wonder why translations always tend to need an extra format or
| framework. Is replacing or customizing translation files after
| deployment a thing or could it be just (generated) compile time
| CODE in the used language based on a simple common format (like
| gettext with macros)?
|
| 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).
| svantex wrote:
| Quite so, and in the case of resx, that's exactly what you're
| getting. A list of key-value-pairs, no support for
| pluralisation either (as you say, it gets hard. I understand
| Polish for example is very complex, perhaps Russian is the
| same?).
|
| 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.
| sandreas wrote:
| That may be the case, but resx is a quite bloated XML format
| for a simple key value pair listing. Besides that, resx is
| yet another format for the same thing.
|
| 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 resx
| sasakrsmanovic2 wrote:
| Unclear to me where this app runs as far as deskop goes?
| Persumably windows, so is there not a way to reuse winui
| localization via WinAppsSDK https://learn.microsoft.com/en-
| us/windows/apps/winui/winui3/...
| svantex wrote:
| If you're referring to my app, Xecrets Ez (
| https://www.axantum.com/ ), it runs in Windows, macOS and
| Linux.
|
| 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.
___________________________________________________________________
(page generated 2024-05-16 23:01 UTC)