How to configure localization for an entire application? - c#

I know I can set a CultureInfo object with an specified culture in the Application_BeginRequest event as is described here, but I don't want to do it for each request but in the application startup.
All I can imagine is that I can use the Application_Start event, but I don't know how to set the global culture.

Set it in your web.config:
<globalization uiCulture="es" culture="es-MX" />
More info here: http://msdn.microsoft.com/en-us/library/bz9tc508.aspx

Thread.CurrentThread.CurrentUICulture
Keep in mind, this is overriding the settings that the WinForm app will have gotten from the computer. For example, if the user has a custom date format defined, this will replace that.

gattaca's answer is right, but if you want to really dynamically change the cultureinfo based on use's preference or browser's language setting, the best place is override Page class' InitializeCulture method. So you can write a base class to this.
protected override void InitializeCulture()
{
LanguageHelper.RestoreUserLangugagePreferrenceIfAvailabe();
}
Of course this seems to over kill, because you need the change the base class. There are other place to put at, like using a module to inject your code, but I try all those solutions, page_load event, but they all do not work 100% with .net localization architecture. Try the localresource file, global resource file, and you will see what I mean.

Related

ASP.NET local resources' Culture property scope

I have an ASP.NET 5 application and I am currently implementing a localization.
Resources are located in the ASP.NET folder App_LocalResources and everything is working properly. At least, while it is in development phase. I have the following ResourceCultureFilterAttribute:
using MyProject.App_LocalResources;
public class ResourceCultureFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
string language = GetClientLanguageFromCookiesDoesntMatter();
var culture = new CultureInfo(language);
GlobalResources.Culture = culture;
}
}
And now I access it this way in Razor view:
#GlobalResources.SomeResourceName
Now, I am worrying that Culture propery of auto-generated resource class is static.
Does it mean that this property is set per-thread or per-application-pool (please, specify the right one) but not per-user?
If yes, then several users will just override and use the single value and definitely cause problems to localization.
I know how to fix it by replacing direct access by:
#GlobalResources.ResourceManager.GetString("ResourceName",
new CultureInfo(GetClientLanguageFromCookiesDoesntMatter());
But, maybe, there is a more proper solution - something important that I just don't see or don't know. Maybe, there is a special property like CurrentUserCulture, special multi-user resource class, attribute or something else to provide a simple and plain localization into an ASP.NET project.

Culture not being applied in multilingual site

I have a very unusual issue that has me completely stumped. We have a multilingual website so we employ Resource files. However, every piece of text on our Views that has been burned in like #TextResources.my_key will be localized to a random culture. This happens only on my Azure deployment, I cannot reproduce locally.
Adding to the mystery is that there is a lone bit of text that ALWAYS respects my change of culture. That text gets retrieved via a method call:
#.ConfigUtils.getTerms()
Method is:
public static string getTerms()
{
string key = GetKeyFromDb(CONSTANTS.TERMS);
if (!string.IsNullOrEmpty(key))
{
return TextResources.ResourceManager.GetString(key);
I'm still reading from our resource file, but in this context, it is being localized as desired! Is the culture being applied after the resource file is read in the view, but before this method is called?!
All our controllers inherit from a base controller, where we override OnActionExecuting() to apply our culture:
protected override void OnActionExecuting(ActionExecutingContext filterContext) {
ContextModel ctx = (ContextModel) Session["ContextModel"];
// Set the correct localization according to the value set by the user
if (ctx != null && ctx.UserLanguageId != null){
Thread.CurrentThread.CurrentUICulture = new CultureInfo (ctx.UserLanguageId);
Thread.CurrentThread.CurrentCulture = new CultureInfo(ctx.UserLanguageId);
}
}
Before I start moving the culture management code to different spots and re-deploying to Azure in hopes that resolves the issue, I'm hoping that someone has a thought as to why only the text retrieved via the method call gets localized.
OnActionExecuting() is executed before the action, so I had thought this would be the appropriate spot to put culture management code. Is there somewhere else that would be better?
UPDATE
It looks like this issue presents itself after a deployment, but can be resolved by restarting the cloud service.
UPDATE 2
Per #RichardSchneider's request, the auto-generated TextResources code is as follows:
public static string my_key{
get {
return ResourceManager.GetString("my_key", resourceCulture);
}
}
The question is already answered here: Asynchrony and thread culture
One likely option is you are using async and .ConfigureAwait(false) in your code. As result code after awiat (that get text/renders view) picks up random culture from the thread it happen to execute instead of one you were hoping to set in the synchronous part in your action filter.
Possible fixes - don't use that .ConfigureAwait(false) or if you have to than pass culture explicitly through all calls and make sure to set it back before making locale-sensetive calls.
More remote possibility: Assuming you use default resource file generation for its normal functioning in ASP.Net application you should
set CurrentUICulture
make sure that Culture property of generated resource manager set to null.
Based on behavior you see I guess something sets Culture wrong in initial start and as result you get "random" culture.
To debug try to check value of Culture property - should be null.
The method works because it using the ResourceManager which respects the current culture.
TextResources.my_key fails because it is (most likely) only assigned a value once on its fist use.
Update
The auto-generated code for my_key is passing the culture info to ResourceManager.GetString. I suggest modifying the autogenerator to use the overload of just one argument to produce:
public static string my_key{
get {
return ResourceManager.GetString("my_key");
}
}
If this is not possible, then you need OnActionExecuting to set resource_culture. resource_culture will need to be a thread local variable for this to work.
In case this happens to someone else, I determined the root cause. We had a page where users were able to download a report via a URL provided to them in an email. The URL included a language querystring variable used for localization:
/report/download?id=123&lang=de
In the controller action, the original author set the culture on our resource object, not the thread:
TextResources.Culture = new CultureInfo("de");
Looking at the metadata:
[GeneratedCode("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
public class TextResources
{
public static CultureInfo Culture { get; set; }
So, it appears this property takes precedence over the thread culture when it comes times to apply localization in our views. And since the property is static, it was applied globally across whichever Azure instance was serving the report. So as people were downloading these reports in various languages, the effect appeared random.
I admit I am still unclear as to why the following always respected thread culture:
public static string getTerms()
{
string key = GetKeyFromDb(CONSTANTS.TERMS);
if (!string.IsNullOrEmpty(key))
{
return TextResources.ResourceManager.GetString(key);

Good way to changing language resources dynamically by request

I have an ASP.NET Web API application which should react to user's Accept-Language header appropriately.
Currently, the strings are stored in the resx and accessed in compile-safe manner through Visual Studio's generated class. What I would like to do is to keep the current approach and create satellite assemblies for each translated version of resx. Then to analyze the user's Accept-Language header to see what languages a user accepts and load the resources for the requested language from the satellite assembly.
I suppose I could implement all this behavior myself by creating a set of language-specific ResourceManager objects with the help of the ResourceSet but then it would not be possible to keep the compile-time safety, since Visual Studio takes care of automatically updating the class for resx file.
What would be the best way to pick the localized language resource dynamically?
From reading your question, I don't see anything that ASP.NET doesn't offer automatically. You can configure your ASP.NET (whether WebForms or MVC) to use the accept-language request header and set the appropriate UICulture (which will impact which satellite assembly is loaded by ResourceManager) and Culture (which will impact locale-dependent formatting and parsing such as dates and numbers) appropriately.
To configure your app to use the accept-language list to set both UICulture and Culture for each request, (as per this MSDN page), configure your web.config like this:
<globalization uiCulture="auto" culture="auto" />
There is also an equivalent configuration setting per page.
Then, as per the Resource Fallback process, if your app includes a satellite assembly for the matching culture (or, failing that, its parent neutral culture), it will be used by the Resource Manager. If not, then your default resources will be used (English if that's your base language).
You could write an HttpModule that detects the language header, and sets the current thread culture.
public class LanguageModule : IHttpModule
{
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(context_BeginRequest);
}
void context_BeginRequest(object sender, EventArgs e)
{
var application = sender as HttpApplication;
var context = application.Context;
var lang = context.Request.Headers["Accept-Language"];
// eat the cookie (if any) and set the culture
if (!string.IsNullOrEmpty(lang))
{
var culture = new System.Globalization.CultureInfo(lang); // you may need to interpret the value of "lang" to match what is expected by CultureInfo
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
}
}
}
ResourceManager et al will figure out the correct localized version to use from the thread culture.

Changing the user language in an asp.net application based on user choice

I have web application which supports globalization. So i need to provide user a choice to select a language one he/she logs in. Now the problem is where do i have to make changes to set the user's preferred language.
Use the ASP.NET profile feature to declare the user's preferred language as a profile property. See Tutoriel
(Note that this is a rephrasing of #Ikaso's answer, so s/he should answer and get credits)
Ok I got the solution:
I tried the following changes in the global.asax file
protected void Application_PreRequestHandlerExecute(Object sender, EventArgs e)
{
if (Session["userCultureInfo"] != null)
{
Thread.CurrentThread.CurrentUICulture = new CultureInfo(Session["userCultureInfo"].ToString());
}
}
Alternatively to the solution you got, you can have your own HTTP module and set the culture there by passing it through the URL for example. But you need to do that in the module before the page lifecycle starts.

NHibernate Validation Localization with S#arp Architecture

I'm trying to localize error messages from NHibernate.Validator. From what I have read, the messages should automaticaly be localized if I set the CurrentCulture/CurrentUICultule ; wich I tried without success. I'm using S#arp Architecture with the default configuration. As I said, the only thnig I changed is the CurrentCulture/CurrentUICultule.
Do I have to create a custom message interpolator for nhibernate validator?
I have posted in my blog about creating a Custom Interpolator that overrides the default messages if they exist in your resources. It allows you to override the default messages and add new messages for your validators.
Check it out: NHibernate Validator Custom Messages
Changing the culture for was not a good idea, since all my website is in spanish, so the path that I took was to create a SpanishMessageInterpolator and then set it up in my nhv.config like:
<property name="message_interpolator_class">NHibernateValidator.SpanishMessageInterpolator, Assembly</property>
And finally I did modify my global.asax.cs file to include the nhv.config file on NHibernate initialization, like:
NHibernateSession.Init(
webSessionStorage,
new string[] { Server.MapPath("~/bin/Assembly.dll") },
new AutoPersistenceModelGenerator().Generate(),
Server.MapPath("~/NHibernate.config"), Server.MapPath("~/nhv.config"));

Categories

Resources