I have a situation where I would like to present a list of the "available languages" for my application (which, incidentally, is an ASP .NET MVC 3 application if that makes any odds). I thought that I could automatically get this list somehow since it should just be the resx files that are included in the build (I don't need to support English UK, German Austria or anything, just English or German) and I came up with a scheme that I will present below (implemented as a singleton since it is a bit of an intensive approach).
The problem is that on some machines it returns "Arabic" even though I have no such resource and on mine (since I installed VS 2012) it returns all of them (this makes more sense to me than returning just the two real cultures plus Arabic but it seems that the ResourceManager just wasn't designed to let me get at this information so I probably should not complain). Here is the scheme...
(I have a Strings.resx and a Strings.de.resx file)
IEnumerable<CultureInfo> cultures =
CultureInfo.GetCultures(CultureTypes.NeutralCultures)
.Where(c =>
{
// Exclude the invariant culture and then load up
// an arbitrary string so the resource manager
// loads a resource set, then get the set for the
// current culture specifically and it is, sometimes
// (I thought always but I was wrong) null if no
// set exists
if (c.LCID == CultureInfo.InvariantCulture.LCID)
return false;
var rm = Strings.ResourceManager;
rm.GetString("HELLO", c);
return rm.GetResourceSet(c, false, false) != null;
});
So then I thought, well, I could do this based on whether the language-specific directory exists like so:
var neutralCulture = new[]
{
CultureInfo
.CreateSpecificCulture(((NeutralResourcesLanguageAttribute)
Assembly
.GetExecutingAssembly()
.GetCustomAttributes(
typeof (NeutralResourcesLanguageAttribute),
false)[0])
.CultureName)
};
IEnumerable<CultureInfo> cultures =
CultureInfo.GetCultures(CultureTypes.NeutralCultures)
.Where(c => Directory.Exists(c.TwoLetterISOLanguageName))
.Union(neutralCulture);
This "works" (in so much as it returns English and German) but I think it is not a very stable approach being as it is prone to random problems like someone creating a folder and throwing it all out of whack. I can probably alleviate these issues with some more judicious checks (the where clause is crying out for more sophistication) but and here is the question (finally)...
Right now I am thinking of just going with a config file and keeping it totally simple since I do not really like where I have got to but is there a better way to do this (or: can it be done automatically in a safe way)?
I like your second approach for automatic detection. I would add though that you should only do this once (on application start or as part of a static constructor) and make it static instead of computing it every time you request the supported culture info.
I think the config approach would work as well, though it's not really automatic. My only thought for that case is that if you are localizing for a language, it's not something that's going to sneak into your application under the radar. That being said, adding a config value at that point seems like an easy thing to do (or to forget to do).
I'm not aware of anything built into the .NET Framework to give you this information with a method call.
I found no valid and reliable way of doing this.
In each of my assemblies I write a code like this that references the supported cultures. That's all we can do. You have to remember to update this array when you add a localization.
internal static class ThisAssembly
{
static readonly string[] SupportedCultures = new string[] { "en-US", "de-DE", };
}
I also tried to:
ResourceManager._resourceSets
: the dictionary of loaded sets gives correct and invalid values.But to no avail.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With