How to use custom cultures? - c#

One of our clients requested that some terminology we're using should be changed according to their needs. That means changing a bunch of labels in forms and user messages. Our application is developed as multi-language application so everything is in resource files.
To solve this need I've decided to create a custom culture. I have created hr-HR-HP from standard hr-HR language. I did some tests and everything worked fine.
However, in our project, our third party components break down with the following exception
CultureNotFoundException: Culture is not supported.
Parameter name: culture
4096 (0x1000) is an invalid culture identifier.
Google says that this happens when CultureInfo is created via LCID and that is not supported for custom cultures. So, to avoid this i set Culture parameters as follows:
Thread.CurrentThread.CurrentCulture = new CultureInfo("hr-HR");
Thread.CurrentThread.CurrentUICulture = new CultureInfo("hr-HR-HP");
Great, the error is gone and forms read their resources as expected. However, now ResourceManager is the problem. It's using hr satellite assembly instead of hr-HR-HP one. I use ResourceManager to read the user messages from satellite assemblies.
Any suggestions? Is it possible to specify which language I want for ResourceManager? Should I try some other approach?

Silly me, I was so close to the answer. Just a little more googling reveals that I can specify what culture I want in ResourceManager.GetString() method.

Related

ClickOnce without custom cultures

I have an WPF application that uses custom culture resources and is published to a server to be later installed, or updated, via ClickOnce (I believe).
The problem lies within the custom cultures, which the hosts don't have and the installation comes to a complete halt due to the missing culture.
Is there anyway to force the installation anyway (the application does have checks to register the missing cultures) or to add somehow these cultures information when publishing the application?
To give some context, I have the following resources files:
Resources.en-GB.resx
Resources.en-GB-informal.rex
The first resources file contains the basic translation of the application, and the second one contains roughly the same content but in an informal/friendly context. This extends to other cultures.

How to set UWP language on runtime

i'm currently developing a cross-platform App using Xamarin.Forms 3.4 and Visual Studio 2017 (latest version by now).
Since that App should support multiple languages which can be changed on runtime, i'm currently looking into ways to get this done. I already added several resources and translated all interface elements which works just fine. I read through this article to get started:
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/localization/
For now, when using the UWP app, the language is automatically set to my current system settings, which is the german language, even if the default app language is english. Thats fine.
Now, I got a method which configures my current language by setting several information, like the default CultureInfo object. That method looks like follows:
public void UpdateAppLanguage()
{
CultureInfo ci;
Language l;
// storage is a class containing several persistent information, like
// the language selected by the user to be used
// the Local attribute states if the language is actually present on
// the current user's system
if(Storage.GetCurrentLanguage().Local == true)
{
// language is present locally, so the user wants to use that one for
// the interface
ci = new CultureInfo(Storage.GetCurrentLanguage().Code);
AppResources.Culture = ci;
CultureInfo.CurrentCulture = ci;
CultureInfo.CurrentUICulture = ci;
CultureInfo.DefaultThreadCurrentCulture = ci;
CultureInfo.DefaultThreadCurrentUICulture = ci;
DependencyService.Get<ILocalize>().SetLocale(ci); // set the Thread for locale-aware methods
}
else
{
// no preferences available yet, use the system's current ci
if (Device.RuntimePlatform != Device.UWP)
ci = DependencyService.Get<ILocalize>().GetCurrentCultureInfo();
else
ci = CultureInfo.CurrentCulture;
l = new Language{
Name = ci.EnglishName,
Code = ci.TwoLetterISOLanguageName
};
Storage.SetCurrentLanguage(l);
CultureInfo.CurrentCulture = ci;
CultureInfo.CurrentUICulture = ci;
AppResources.Culture = ci; // set the RESX for resource localization
DependencyService.Get<ILocalize>().SetLocale(ci); // set the Thread for locale-aware methods
}
}
I'm currently testing with a language set, and that language is English.
And here is the dependency service implementation for the UWP sub-project:
public class Localize : stereopoly.ILocalize
{
public void SetLocale (CultureInfo ci)
{
//Windows.Globalization.ApplicationSettings.PrimaryLanguageOverride = ci.Name;
Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride = "EN-US";
Windows.ApplicationModel.Resources.Core.ResourceContext.GetForCurrentView().Reset();
Windows.ApplicationModel.Resources.Core.ResourceContext.GetForViewIndependentUse().Reset();
}
public CultureInfo GetCurrentCultureInfo ()
{
return null;
}
}
As you can see, I also tried to set the language to EN-US by force, which doesn't work either. I'm calling the UpdateAppLanguage() method even before the initial Application.InitializeComponent() method runs, I also tried calling it within the OnStart() event method, neither works.
I'd expect the language change getting applied since its executed even before the actual Application starts, but I can switch the several pages of my app as often as I want, the language will always be german, no matter what I do.
I found several answers to this question for plain UWP apps, but not for Xamarin.Forms implementations of UWP projects and that seems to be the problem here, because no other hint regarding pure UWP apps seem to work.
Do you have any idea what might help me?
Thanks.
Make sure you are targeting at least UWP 16299 (FCU), because before that version UWP had issues properly switching languages in debug mode. If you run in Release mode however, it should work normally.
In addition the UWP app needs to know it supports a given language, because this is generated at compile time (using <Resource Language="x-generate"/> in Package.appxmanifest)
You can do this by adding a Strings folder in your UWP project and then adding multiple subfolders - one for each supported language. Finally in each of them add a Resources.resw file (right-click folder, Add > New item..., Resources file (RESW)). The result will look like this.
Then inside each RESW file add some resource. I usually put in AppName, as I often localize it as well:
After this, the app should pick up on the fact that you support the given language and display localized.
I finally found the answer to my problem, it was just as simple as it usually is when it comes to such errors.
It turns out that all bootstrap projects like the UWP, iOS and Android sub-projects also inherit the Assembly Neutral Language from the parent project, no matter what configuration is defined in the specific sub-project (at least thats how it works for UWP). I just noticed that I can set an Assembly Neutral Language within the settings of my .Net main project, and as soon as I did that, all the warnings disappeared and my UWP app ended up showing english text instead of the system default german one. I can also switch back to german now, even though I still have to restart the app to get all frames translated, but thats not that big of a problem, I can work on fixing that up later on. Here's the link that finally got me covered:
Xamarin.Forms: Localization of the UWP app
Thanks for your amazing help anyway :).

ResourceManager and not supported platform

I use ResourceManager for UI localization of my WinCE 5 software. I have some resource files with text strings on different languages
Resourse.resx
Resourse.de-DE.resx
Resourse.ru-RU.resx
When I want to display UI in English I call:
Resourse.Culture = new CultureInfo("en-US");
label1.Text = Resourse.LabelText;
in German:
Resourse.Culture = new CultureInfo("de-DE");
label1.Text = Resourse.LabelText;
in Russian:
Resourse.Culture = new CultureInfo("ru-RU");
label1.Text = Resourse.LabelText;
but here I get PlatformNotSupportedException.
I know that my WinCE does not contain Russian and I cannot modify OS to appened this, so my question is how I can say to ResourceManger to use Resourse.ru-RU.resx when I set Culture = new CultureInfo("ru-RU") ?
The answer Jonathan provided is the exact work around I had to do to get my device to show Simplified Chinese. I used "en-ZW" English(Zimbabwe). This worked on 3 different devices all running a different OS (CE5, CE6, and WEH/WM 6.5.3)
If the base Tahoma font doesn't contain everything you need, as in my case, you also need to put the font on the device and make some additional registry changes to enable font linking. It's not very complex, only a couple of registry entries.
This MSDN link provides the information for the Chinese fonts but it would be used the same way for any other font set.
http://msdn.microsoft.com/en-us/library/ms901082.aspx
The more generic MSDN articles on font linking can be found here:
http://msdn.microsoft.com/en-us/library/ms901098.aspx
Other than this the only other option I was able to determine was to roll your own translation resource class.
The following is a rather HACKED workaround, but it will solve the PlatformNotSupportedException issue. I would also recommend doing this only as a last resort. Please note that I have only tested this on WinCE 6.0.
If the culture you are attempting to implement is not supported by WinCE 6.0, simply re-label it as a different culture. For example, rather than marking the Russian culture as "ru-RU" (as above), you could re-name it as "eu-ES" (Basque). Provided that the font being used supports the Cyrillic character set, the values should display as you have written them.
Note: You MUST also rename your resource file to match the target culture you are substituting. If you are using "eu-ES" in place of "ru-RU", you must rename your "Resourse.ru-RU.resx" to "Resourse.eu-ES.resx".
What you lose: Any native support provided by the target culture (Russian in this case), (e.g. correctly formatted currencies, dates, etc), since these would now be being drawn from the work-around target culture (Basque in this case). Note that this should only be a problem in your application if you are formatting your strings via culture (i.e. stringFormat({some CultureInfo.GetCurrentCulture}, {additional formatting}, {some numerical value})).
Seems like you're stuck unfortunately. Your issue is unusual because typically a mobile app does not need to decide on which culture identifier to use. If it just relies on whatever culture the system has set up for it when launches, then users can switch the global culture setting which would affect your app and make it use your localizations if present.
If you are implementing a language selector inside your app, then I guess you need to filter down your list of choices so that you only offer cultures which the device supports (CultureInfo.GetCultures will give you a list of supported cultures, and you can find the subset for which you have localizations available).

Where is the system locale/culture set for .Net

I have a problem with a c# assembly (.net 2.0 written using Visual studio 2005) that is installed on a UK server and should use UK regional settings.
What my code does is to convert a date in the form dd/MM/yyyy into utc. i.e. yyyy-mm-dd. The problem arose with dates like 16/02/2010 where the component failed to convert the date and returned Error. After debugging I realised that, for a strange reason, the CultureInfo returned by System.CultureInfo is en-US.
I can programatically change those settings using:
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-GB", false);
and my code works fine.
However I don't want to do that all the time as my system should be UK. Not US.
So, how do I change the default culture for .Net framework to be by default en-GB instead of en-US ?
For information:
I have tried to update the machine.config file and specify culture=en-GB for the globalization section (it was set to neutral) but it doesn't work either [have done that for 1.1 and 2.0] but it's possible I have not changed it correctly.
I have verified my windows regional settings and they are definitely set-up to UK with dates as dd/MM/yyyy
I am running in a Virtual server and have verified my host system. It too is set to UK
Edit:
A bit of extra detail about the context. The assembly in question is being called via COM interop from a native C++ third party component that is running as a COM+ application.
The server is not configured correctly. Control Panel + Region and Language, Location tab. Changing this could be a bit tricky. The server may well have been mis-configured on purpose. Talk to the server administrator first before doing anything.
Your fallback plan is to use the DateTime.TryParse() method overload that takes the IFormatProvider argument. Pass CultureInfo.GetCultureInfo("en-gb").DateTimeFormat.
To set the UI culture and culture for all pages, add a globalization section to the Web.config file, and then set the uiculture and culture attributes, as shown in the following example:
<globalization uiCulture="en" culture="en-GB" />
Hmmm, according to the API Docs:
When a thread is started, its culture is initially determined by using GetUserDefaultLCID from the Windows API.
This method derives it's locale from the (as the name implies) User's Default Locale, which I assume is in the Control Panel. NOTE: This is NOT the same as the UI Locale.
thanks for your answers (andy posted the question on my behalf). It was indeed an issue with regional settings but neither with the user I was connected under, nor with the user the process was running under. That would have been too easy. It looks like that the default user was still en-US. I did reset by clicking the checkbox "Apply settings to the current user and default user..." in the advanced tab and rebooting the server. System.Globalization.CultureInfo now return {en-GB}. And a MyDate.ToString(yyyy-mm-dd) works fine whether the date is passed as dd/MM/yyyy or dd-MM-yyyy or yyyy-MM-dd without the need to parse.
However thanks you all very much for your suggestions (ParseExact, etc) that did indeed work. They ill be very helpful for other date formats that I was not able to handle in a nice way (yyyyMMdd).
Marc
I believe this is represented by System.Globalization.CultureInfo.InstalledUICulture, so if nothing else maybe you can copy that to the thread's current culture. I'm surprised that you found a case where the threads culture is different than the installed culture. Perhaps your code is running in a process that changed the culture?
It is possible the account running the code has different regional settings than the system default. Have you checked that?
You do not have to change the CurrentCulture to do the transformation. If you are certain that the date is in the form of "dd/MM/yyyy" you could use
DateTime dtTemp = DateTime.ParseExact(dateString, "dd/MM/yyyy", null) // in order not to have to specify a FormatProvider
and then use
dtTemp.ToString("yyyy-MM-dd")
This way you will not have a problem no matter what the CurrentCulture is. However, if you are not certain that the Date is of the form "dd/MM/yyyy" rather it is based on the CurrentCulture short date format, then you should use
DateTime dtTemp = DateTime(dateString, CurrentCulture.DateTimeFormat.ShortDatePattern, CurrentCulture.DateTimeFormat);
Assemblies in .net framework are culture neutral.
What code are you trying to convert the date?
If you are using Parse or TryParse, try providing the culture argument for it to understand the date.

C# Satellite Assemblies? Do I need to link default culture resource

We would like to employ satellite assemblies to contain various locale dependent resource files.
Question is ... do we need to link the default culture?
We have a separate project which will contain all of our different culture resource files. As is shown below, we have the project with two resource files inside of it.
ProjRES
Resource.resx
Resource.it-IT.resx
I am assuming that the "Resource.resx" will act as the default culture and if the Italian culture is selected, the application will adopt the it-IT resource file.
What do we need to do in order to get the rest of the application and projects to access the resource files. How do we set the namespaces for the resource files in order to be able to reference them.
Any help is greatly appreciated.
Basically,
if the current culture that the OS is using matches a certain culture that you've shipped, it will be used, if the current culture matches none of the cultures you've shipped, it will use the neutral culture.
In the most simplistic cases, you'll just need to include any of the localized dlls with the deployment and all will be fine..
When you're using resource managers, I think you can also pass in which culture you want to use explicitly, and the runtime will search for resources that match - this is better when a user of an ASP.Net site might have a certain culture preference that is different from that of the machine that the site is running on.
http://msdn.microsoft.com/en-us/magazine/cc163609.aspx seems to be a good starting point.

Categories