Automatic language-culture selection and fallback algorithm in ASP.NET - asp.net

We are building a site that supports several languages. We have created resources to support fr, de, and en-US with en-US as the default. I have added:
<system.web>
<globalization
uiCulture="auto" culture="auto"
requestEncoding="utf-8"
responseEncoding="utf-8"
enableClientBasedCulture="true" />
...
</system.web>
to my web.config file. If I set the language to fr, de, or en-US in IE or Chrome, I get the expected language. If I set the language to ar-EG, I get en-US, also as expected.
If I set my language to fr-FR, but do not include fr in the list of accepted languages, the site returns the fr page, even if I tell the browser that I prefer accept de to generalized fr (as opposed to fr-FR). This appears to be contrary to the RFC's, but is not surprising, because IE defaults to fr-FR in France and de-DE in Germany, and does not work with sites that do not automatically generalize the culture.
However, if I tell the browser that I accept ar-EG and fr, the site defaults to en-US -- even though the Accept-Language header specifies that I will accept fr with a higher priority. I captured the request header in the browser to make sure all the languages I asked for were being sent with the right priorities.
It appears that ASP.NET is only ever looking at the first language specified in the Accept-Language header. Is the ASP.NET language matching algorithm specified anywhere? Is there a way to specify that ASP.NET/MVC should check all the languages in the Accept-Language list to determine the best one? Or do I have to write my own language matching code?

Well, as nobody else answered yet, I make my suggestion. There is a better or at least more beautiful solution for sure, but for my needs it was enough. Just set the culture inside your Application_AcquireRequestState() event:
protected void Application_AcquireRequestState()
{
var language = "whatever"; // default fall back
if (request.UserLanguages.Length > 0)
{
var acceptedLangs = new List<string> {"de", "en"};
var langs = request.UserLanguages.Where(l => acceptedLangs.Any(al => al.Equals(l.Substring(0, 2))));
language = langs.FirstOrDefault();
}
// TODO: may be better inside a try..catch block
var culture = new CultureInfo(language);
Thread.CurrentThread.CurrentUICulture = culture;
Thread.CurrentThread.CurrentCulture = culture;
}

Related

Asp.Net Culture name without region/country name and default settings

I am working a multi-lang site. I want to get and set culture and uiculture with culturename without countryname. If browser is english or lang is English choosen, it will return en not en-US or en-GB. Because I use one localresources file per language and I have to send language code to sql procedure as a parameter.
Thread.CurrentThread.CurrentCulture
Thread.CurrentThread.CurrentCulture.Name
Thread.CurrentThread.CurrentUICulture
All of them returns en-GB,de-DE,de-AT etc... I just want first part and use this ones.
http://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo%28VS.71%29.aspx
There are the name in the link but browser does note return it, I just want and use the simple part.
How can I do that?
It is solved (:
edit:
Now, How can I read browser's culture and if I don't have it, how can I set the culture that I have.
eg: I have en,de,ru and the visitor's browser sen me fr, I want it is shown en ?
Have a look at the TwoLetterISOLanguageName-property. It should return the identifier you are looking for. For example:
var cult = new System.Globalization.CultureInfo("en-US").TwoLetterISOLanguageName;
Returns "en" so that you can send it to the stored procedures.

How can we find the selected language of client machine through programming?

I have set arabic as as client's machine language.But in C# program while am using
var test = Thread.CurrentThread.CurrentCulture;
It shows the language as En-US.?
How i get the selected language of the machine?.
This will depend on how the client browser is configured. If the client browser's default language is configured to be en-US you will never be able to get the actual language on the server. For example in Google Chrome there's a setting where you could specify the preferred languages sent to the server:
So once you have configured the preferred language of your web browser to be something else, the browser will send this language as Accept-Language HTTP request header and you will be able to retrieve it on the server. In this case ASP.NET will automatically assign it to the current thread's culture assuming in your web.config you have not changed it in the <globalization> element but left the default value.
Request.UserLanguages is the property you're looking for.
Just keep in mind that this array may contain arbitrary (even non-exsitent) languages as set by request headers.
Example:
var lobUserLanguages = Request.UserLanguages;
CultureInfo ci;
if (lobUserLanguages.Count > 0)
{
try
{
ci = new CultureInfo(lobUserLanguages[0]);
}
catch(CultureNotFoundException)
{
ci = CultureInfo.InvariantCulture;
}
}
else
{
ci = CultureInfo.InvariantCulture;
}

Possible to use one resource file with multiple languages?

I've got a .net 4.0 website that we have 2 copies of it running. One for US based users and another for AU based users. Code is basically the same, the only differences being some text and wording here or there where it references the US versus Australia. Right now I have two copies of the site which is pretty silly. So I want to maintain just one copy and put all these regional text changes in a resource file.
Is it possible to have just a single resource file contain multiple 'languages' or do i need to create a Resource.US.resx and a Resource.AU.resx file? Also, if i do create two files, how do I tell .net which file to use in each site? I assume in the web.config globalization uiCulture & culture='en-AU' or en-US would tell .net which of the two files to use?
Yes, you are right, you can use Resource.US.resx and a Resource.AU.resx files and tell in web.config globalization uiCulture & culture='en-AU' or en-US
in code:
string culturePref = [Your setting from web-config]; // "en-US" or "en-EU"
try
{
Thread.CurrentThread.CurrentCulture =
CultureInfo.CreateSpecificCulture(culturePref);
}
catch
{
Thread.CurrentThread.CurrentCulture =
new CultureInfo("en-US");
}
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;

Multi-lingual web application - how do I detect the user's language in ASP.NET?

I'm building an ASP.NET web application, and all of my strings are stored in a resource file. I'd like to add a second language to my application, and ideally, I'd like to auto-detect the user's browser language (or windows language) and default to that, instead of making them choose something besides English. Currently, I'm handling all the resource population manually, so adding a second resource file and language is trivial from my point of view, if I had an easy way to automatically figure out what language to display.
Has anybody done this, or do you have any thoughts about how I might retrieve that value? Since ASP.NET is server-based, I don't seem to have any access to specific browser settings.
RESOLUTION: Here's what I ended up doing. I used a "For Each" to go through "HttpContext.Current.Request.UserLanguages" and search for one I support. I'm actually just checking the left two characters, since we don't support any dialects yet - just English and Spanish. Thanks for all the help!
Try this in the web.config:
<globalization culture="auto" uiCulture="auto" />
This will cause ASP.NET to auto-detect the client's culture from the request header. You can also set this on a per-page basis via the Page attribute.
This article (linked to archive.org as original link is now dead) might be helpful with auto detecting the browser's language setting.
[EDIT] Yes. The quoted article does not use ASP.NET. This article does.
Request.UserLanguages in ASP.NET 4 parses this as a string array.
Good info: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
This is a great question, as localization in ASP.NET is overlooked by many developers.
ASP.NET should automatically pick up on the user's browser settings and force the CultureInfo.CurrentCulture to the user's browser language. You can force the issue with a line in Page_OnInit() like:
Thread.CurrentThread.CurrentCulture = new CultureInfo(HttpContext.Current.Request.UserLanguages[0]);
How can you test this? Enter the languages panel on our browser and change settings.
The client generally sets Accept-Language in the HTTP request header with a quantitatively scored list of preferred language, conventionally (but not necessarily) in order of most favored to least favored. You can parse that, but as Maxam has noted, ASP.NET does have a mechanism for doing that on your behalf.
/// <summary>
/// Sets a user's Locale based on the browser's Locale setting. If no setting
/// is provided the default Locale is used.
/// </summary>
public static void SetUserLocale(string CurrencySymbol, bool SetUiCulture)
{
HttpRequest Request = HttpContext.Current.Request;
if (Request.UserLanguages == null)
return;
string Lang = Request.UserLanguages[0];
if (Lang != null)
{
// *** Problems with Turkish Locale and upper/lower case
// *** DataRow/DataTable indexes
if (Lang.StartsWith("tr"))
return;
if (Lang.Length < 3)
Lang = Lang + "-" + Lang.ToUpper();
try
{
System.Globalization.CultureInfo Culture = new System.Globalization.CultureInfo(Lang);
if (CurrencySymbol != null && CurrencySymbol != "")
Culture.NumberFormat.CurrencySymbol = CurrencySymbol;
System.Threading.Thread.CurrentThread.CurrentCulture = Culture;
if (SetUiCulture)
System.Threading.Thread.CurrentThread.CurrentUICulture = Culture;
}
catch
{ ;}
}
}
The source of this article is here:
How to detect browser language

Best way to convert a decimal value to a currency string for display in HTML

I wanting to show prices for my products in my online store.
I'm currently doing:
<span class="ourprice">
<%=GetPrice().ToString("C")%>
</span>
Where GetPrice() returns a decimal. So this currently returns a value e.g. "£12.00"
I think the correct HTML for an output of "£12.00" is "£12.00", so although this is rendering fine in most browsers, some browsers (Mozilla) show this as $12.00.
(The server is in the UK, with localisation is set appropriately in web.config).
Is the below an improvement, or is there a better way?
<span class="ourprice">
<%=GetPrice().ToString("C").Replace("£","£")%>
</span>
Try this, it'll use your locale set for the application:
<%=String.Format("{0:C}",GetPrice())%>
Use
GetPrice().ToString("C", CultureInfo.CreateSpecificCulture("en-GB"))
The £ symbol (U+00A3), and the html entities & #163; and & pound; should all render the same in a browser.
If the browser doesn't recognise £, it probably won't recognise the entity versions.
It's in ISO 8859-1 (Latin-1), so I'd be surprised if a Mozilla browser can't render it (my FF certainly can).
If you see a $ sign, it's likely you have two things:
1. The browser default language is en-us
2. Asp.net is doing automatic locale switching. The default web.config setting is something like
<globalization culture="auto:en-us" uiCulture="auto:en-US" />
As you (almost certainly) want UK-only prices, simply specify the locale in web.config:
<globalization culture="us" uiCulture="en-gb" />
(or on page level:)
<%#Page Culture="en-gb" UICulture="en-gb" ..etc... %>
Thereafter the string formats such as String.Format("{0:C}",GetPrice()) and GetPrice().ToString("C") will use the en-GB locale as asp.net will have set the currentCulture for you
(although you can specify the en-gb culture in the overloads if you're paranoid).
You could write a function which would perform the conversion from price to string. This way you have a lot of control over the output.
The problem with locale is that it's web server dependent and not web browser dependent.
If you need to explicity state the localisation you can use the CultureInfo and pass that to the string formatter.
just use the ToString("C2") property of a decimal value. Set your globalization in the web.config - keep it simple.

Resources