Proper internationalization (I18N) or localization (L10N) support for WPF, facilited by NGettext
inside.
Review the change history, including what's new in the latest release and what will be included in the upcomming release.
Find the NuGet package. You may download the package itself, or add it among your <PackageReference/>
notations, and so on.
Ellumination.NGettext.Wpf
is intended to work with dependency injection. Integration occurs via the following entry point from your application:
NGettext.Wpf.CompositionRoot.Compose("ExampleDomainName");
The "ExampleDomainName"
string is the domain name. This means that, when the current culture is set to "da-DK"
, localization shall occur from Locale\da-DK\LC_MESSAGES\ExampleDomainName.mo
, relative to where your WPF application is running. You must include the corresponding .mo
files in your application, ensuring that they are copied to the output directory.
Now you can do something like this in XAML:
<Button CommandParameter="en-US"
Command="{StaticResource ChangeCultureCommand}"
Content="{wpf:Gettext English}" />
Which demonstrates two features of this library. First, most importantly, is the Gettext
markup extension, which will make sure the Content
is set to the localization of "English", with respect to current culture, and update it when the current culture has changed. Second, another feature it demonstrates is the ChangeCultureCommand
, which changes the current culture to the given culture, in this case "en-US"
.
Have a look at Ellumination.NGettext.Wpf.Example/UpdateLocalization.ps1 for how to extract MsgId
's from both .xaml
and .cs
files.
Note: The script will silently fail (i.e. 2> $null
), initially, because there is no .po
file for the given language. In the gettext world, one is supposed to create that with the msginit command, which ships with the Gettext.Tools
NuGet package, or PoEdit
may be used to initialize the catalog from an intermediate .pot
file created.
Here is what recently worked for me:
PM> mkdir -p Locale\en-GB\LC_MESSAGES\
PM> msginit --input=obj\result.pot --output-file=Locale\en-GB\LC_MESSAGES\ExampleDomainName.po --locale=en_GB
Keep your compiled localizations in Locale\<LOCALE>\LC_MESSAGES\<DOMAIN>.mo
. This library will force you to follow this convention. Or rather, NGettext forces you to follow a convention like "<PATH_TO_LOCALES>\<LOCALE>\LC_MESSAGES\<DOMAIN>.mo"
, and I refined it.
Keep your raw localizations in Locale\<LOCALE>\LC_MESSAGES\<DOMAIN>.po
. This is not enforced, but when working with PoEdit
, it will compile the .mo
file into the correct location when following this convention, and it does not remember your previous choice, so stick with the defaults.
There are lots of GNU conventions related to I18N and L10N. One of them is the notion that the original program be written in US English, so you do not need to localize anything to facilitate I18N. The original text in US English is called the msgId
.
One of the most important GNU convention related to I18N is providing a context to an Interpreter so they have a chance to do it right. For instance, the English word 'order' has a number of more or less related meanings and thus may be interpreted differently depending usage. For instance, in the context of sequential ordering, 'order' translates to 'rækkefølge' in da-DK
, but the imperative for placing an order translates to 'bestil'. Here is an example of how this sort of circumstance may be clarified:
<!-- A button with the text 'Order' but with a helpful context for an Interpreters -->
<Button Command="{StaticResource PlaceOrderCommand}"
Content="{wpf:Gettext Imperative for placing an order|Order}" />
<!-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -->
Interpreters will rarely think of it, and just translate the first meaning that comes to mind, and as a programmer you might not know which words or sentenses need further context. Therefore, we strongly recommend to always provide a helpful context. At the very least grammatical usage, whether noun or verb, along these lines.
Further directions coming soon, I just wanted to get this supporting documentation somewhat refreshed and presentable, than put my future thinking cap on for the immediate road ahead.
Have a question, want to participate, you get out of it what you contribute:
- By participating in the project discussions;
- By connecting with me on Github, following my work;
- By contacting me on Gab, where you may reach me, primarily;
- By following my Twitter feed; although I do not use this for contact;
- By networking with me via LinkedIn, always interested in solid business leads;
- By asking a StackOverflow question, and by including at least the annotated tags;
- Or, by opening a project issue
As presented by Ellumination.NGettext.Wpf.Example, you will discover a sample application which illustrates the key features of the packaged dotnet assembly.
Big shout out to our colleague and peer, Robert Jørgensgaard Engdahl, without whom, in whose stead we are carrying the NGettext.Wpf
torch forward.
Some other mentions via StackOverflow. His former LinkedIn unavailable at the time of this entry.
I am not personally aware of his whereabouts or well being today, but where ever life may find him, in this world in the here and now, or the Great Beyond, may GOD bless and GODSPEED, my friend.