I'm running into a case where an ASP.NET application using the built-in globalization facilities is crashing.
On an ASP.NET page with the Culture="auto" directive, a user with a neutral culture as their browser language (such as "zh-Hans") will produce the following exception:
Culture 'zh-Hans' is a neutral culture. It cannot be used in
formatting and parsing and therefore
cannot be set as the thread's current
culture.
at System.Globalization.CultureInfo.CheckNeutral(CultureInfo
culture)
at System.Threading.Thread.set_CurrentCulture(CultureInfo
value)
at System.Web.UI.Page.set_Culture(String
value)
at ASP.somePage_aspx.__BuildControlTree(somePage_aspx __ctrl)
at ASP.somePage_aspx.FrameworkInitialize()
Any ideas? Garbage fed into the Culture/UICulture parameters generally seem to be ignored, but this case is causing an unhandled exception.
I was having the same problem and after bonking my head against a wall for a while found the answer right under my nose.
The issue I had was in not understanding the difference between CurrentCulture and CurrentUICulture. The difference being CurrentCulture is used to format dates, numbers and perform sorting, CurrentUICulture is used to lookup culture specific strings from a resource.
I had some code that looked like
return input.ToString("C", System.Globalization.CultureInfo.CurrentUICulture);
when it should be been
return input.ToString("C", System.Globalization.CultureInfo.CurrentCulture);
When you start trying to format culture specific items with a non-specific culture you will get the System.NotSupportedException.
First off, you might consider setting UICulture="auto" as well as Culture="auto" in your <%# Page %> declaration.
Now, I am not seeing this repro on my .NET 4.0 (beta) install, so this might be a product bug in .NET 3.5.
Here's a great resource for learning about neutral cultures and the difference between UICulture and Culture: http://blogs.msdn.com/ddietric/archive/2008/02/05/yacvcp-yet-another-currentculture-vs-currentuiculture-post.aspx
Hope that's helpful.
Can't you set the culture on begin request? (Note: asp.net requests can jump between threads so you need to hook into the thread moving as well.)
Related
In my ASP.MVC 2.0 website I have the following setting in web.config:
<globalization uiCulture="da-DK" culture="en-US" />
When I try to display an amount in a view using Html.DisplayFor() or ToString("C2") I expected to get "kr. 3.500,00" (uiCulture) and not "$3,500.00" (culture).
<%:Html.DisplayFor(posting => posting.Amount)%>
<%:Model.Amount.ToString("C2")%>
If I explicit uses CurrentUICulture info it works as expected, but I don't want to do that everytime I need to display a number, date or decimal. And I also like to use DisplayFor, which doesn't support the IFormatProvider parameter.
<%:Model.Amount.ToString("C2", System.Globalization.CultureInfo.CurrentUICulture)%>
How can I change the formatting, without changing the culture of the system?
This is running in Azure, and if I change the culture to "da-DK" all decimal points are lost, when saving to Azure Table storage! #BUG
The UI culture is used to lookup and load resources, the Culture is used for formatting.
So the various ToString(string) and String.Format overloads that don't take a culture will use the thread's current Culture (System.Globalization.CultureInfo.CurrentCulture) to format.
If you want to use Danish formatting for currency, dates, ... then Thread.CurerentThread.CurrentCulture needs to be set to CultureInfo.GetCultureInfo("da-DK") (directly or indirectly).
Summary: you have Culture and UI Culture the wrong way around.
In asp.net multilingual website in english Uk and swedish, i have three rsources file
1. en-GB.resx
2. sv-SE.resx
3. Culture neutral file.
I have create one base class and all pages is inherited from that class. There i write following lines to set UICULTURE and culture
1. Thread.CurrentThread.CurrentUICulture = CultureInfo.CurrentUICulture.Name;
2. Thread.CurrentThread.CurrentCulture = CultureInfo.CurrentCulture.Name;
Question: Suppose my browser language is Swedish(sv-SE) then this code will run because it find CurrentUICulture and CurrentCulture values as sv-SE.
Now if suppose browser language is Swedish(sv) only, in that case values will be set as
CurrentUICulture = sv; and CurrentCulture = sv-SE
Now the problem is that user can able to view all text in Culture neutral resource file that i kept as english while all decimal saperators, currency and other will be appear in swedish.
It looks confusing to usr.
What would be right approach. I am thinking following solution. Please correct me?
1. i can create extra resource file for sv also.
2. I check value of CurrentUICulture in base class and if it is sv then replace it with sv-SE
Please correct me which one is right approach or Is there any other good way of doing?
You can easily replace the value in the base class like you mentioned. I would stay away from creating an additional resource file that duplicates data since it will be harder to maintain.
if (Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName.ToLower() != "sv")
...replace with sv-SE
EDIT See this other question]1 for additional info. There's a good article referenced in the answer of that question
When i visit http://localhost:17357/u/a%2fa/m/ssd-10 and look at HttpContext.Current.Request.Url in Application_BeginRequest i see http://localhost:17357/u/a/a/m/ssd-10 huh? shouldnt i get http://localhost:17357/u/a%2fa/m/ssd-10? i thought the point of escaping urls is so ?, &, / and other special symbols not be confused with their special meaning in urls. Maybe theres a config i need to tweak?
I created 4 usernames, there are
a?#!&ee
a?#!/&ee
as d
クイン
with the links as
a?#!&ee<br>
a?#!/&ee<br>
as d<br>
クイン
The last two work, but the first two i get the exceptio
A first chance exception of type 'System.ArgumentException' occurred in mscorlib.dll
Additional information: Illegal characters in path.
then
A first chance exception of type 'System.Web.HttpException' occurred in System.Web.dll
Additional information: '/u/a?#!&ee' is not a valid virtual path.
and my page says Bad Request. How can i allow these usernames to work. If its impossible how can i write a workaround?
You need to escape it again. Use %252f instead of %2f. To clarify, the URL is unencoded when the server receives it. URL encoding allows you to pass in a / that the server processes as a character instead of the special function that a reserved character would normally trigger. See the Wikipedia page for more info.
Concerning your error with the a?#!&ee username, it seems almost certain that you're running into a problem that ASP.NET has with special characters (even urlencoded properly) that are not in the query string (that is, after the ? part of the URL). Joshua Flanagan talks about it in a blog post, and identifies %, &, *, and : as the problematic characters.
He points to a Dirk.Net blog post that offers a couple of fixes. First, you can edit the registry to allow restricted characters (adding a DWORD key AllowRestrictedChars to HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\HTTP\Parameters and setting its boolean value to true). Or, you can ensure that you have the .NET framework 1.1 SP1 and edit the registry to set ASP.NET VErification Compatibility to true (DWORD HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ASP.NET VerificationCompatibility = 1). Third, you can try setting ValidateRequest to false on the ASPX page. Finally, as Joshua decided to do, you can pass the information using the query string, i.e. after the ? as ASP.Net originally (pre MVC) expected.
I wrote my own solution. Its nice to have a username with / but not consider as / when getting a GET request.
I am using a control for a popup calendar date picker. This uses a javascript function, SetText, to set the textbox to the given date. I can't change anything in the calendar control itself but I can override the SetText function. The SetText javascript just takes the TextBox name and the date value in string format and sets the TextBox to the string.
The problem:
I need to display the date in the format "April 30".
Easy to do. Use getMonth() and getDate() where I can parse the information from there.
Now, I need to make sure this shows correctly for different cultures. For example, the UK shows dates as "30 April". Since the code-behind(c#) could be sending the date in the UK format how do I know in the javascript that they're using UK(dd/mm/yyyy) and not US(mm/dd/yyyy)?
The browsers navigator language could be set to one setting while the server is set to another to cause a January 4 as April 1 mismatch.
You are using the Microsoft Ajax Framework, this framework defines a set of "client-side type extensions" which provide added functions or "extensions" to the JavaScript base types.
The Date Type Extensions is what you're looking for, specifically the Date.parseLocale function.
With this function you can parse a string, using a given format.
You can synchronize your server-side and client-side culture by setting the ScriptManager.EnableScriptGlobalization property to true, and use the Date.parseLocale function without specifying any format.
Give a look to this article:
Walkthrough: Globalizing a Date by Using Client Script
See toLocaleString and related functions.
If you control the backend, why not just send a timestamp and push it into Date object?
As for formatting on the client side, since I was already using Dojo, I solved this problem by using dojo.date.locale.format. It was completely painless.
Locale is detected automatically or can be set arbitrarily.
Shorthand format options (e.g.: long short)
Data selectors (e.g.: time, date)
Ability to specify an arbitrary date/time pattern (probably not application to this application, but still useful).
Tutorial: http://docs.dojocampus.org/dojo/date/locale
API doc:
http://api.dojotoolkit.org/jsdoc/1.3/dojo.date.locale.format
Date format descriptions: http://www.unicode.org/reports/tr35/tr35-4.html#Date_Format_Patterns
Three things you could use:
1) toLocaleString - As suggested already. The problem with this is when sending a string of "4/1/2009" this can result in a couple things. January 4 or April 1.
2) navigator.language and navigator.systemLanguage - After you get the date string you can check to see what language the system is in and parse the date from there. The problem with this and solution 1 is what if you have a UK server and the browsers machine is US. You will have the code behind sending April 1 as 1/4/2009 where the javascript will read the string as whatever language the clients browsers is. So, UK server and US browser will give you a wrong result.
3) Use Code Behinds Culture - Create a variable in your javascript that when the page loads, it will call a function in your code behind that returns this.Page.Culture from there, you will know what culture the string is being sent back as. This will eliminate the mismatch that the first two solutions can cause. It will take a little extra work to make sure it's displayed correctly but at least you will be able to use the string without having the possibility of mismatching cultures.
toLocaleDateString would be a better solution than toLocaleString for your problem as it doesn't include the time (as you only are requesting the date).
The open-source JavaScript library Date.js has some great methods for formatting dates, as well as it supports a bunch of languages:
Date.js at Google Code: http://code.google.com/p/datejs/
If you want nicely formatted dates / times, you can just pass a formatting string (nearly identical to those used in .NET Framework) into any Date object's .toString() method.
It also has a whole set of cultures which allow you to simply include the appropriate script for that culture.
If you want to manage that yourself (as we do in our apps), you can find resources which give you the list of appropriate resource strings for a given culture. Here's one that shows proper formatting strings for a ton of cultures: http://www.transactor.com/misc/ranges.html
As you are using ASP.NET then you may also be using ASP.NET Ajax. If so, there are two properties on the ScriptManager that are of use to you:
EnableScriptLocalization - Gets or sets a value that indicates whether the ScriptManager control renders localized versions of script files.
EnableScriptGlobalization - Gets or sets a value that indicates whether the ScriptManager control renders script that supports parsing and formatting of culture-specific information.
<asp:ScriptManager ID="AjaxManager" runat="Server" EnablePartialRendering="true"
EnableScriptGlobalization="true" EnableScriptLocalization="true" />
When you enable both of these (set to true) then ASP.NET Ajax extenders etc. should automatically be localised into the culture specified in web.config:
<configuration>
<system.web>
<globalization
fileEncoding="utf-8"
requestEncoding="utf-8"
responseEncoding="utf-8"
culture="en-GB"
uiCulture="en-GB" />
</system.web>
</configuration>
For instance, setting this will localise the AjaxControlToolkit Calendar into your specificed culture.
Even if you are NOT using ASP.NET Ajax adding a ScriptManager and enabling localisation will give you a useful javascript variable called __cultureInfo that contains a JSON array of localised formate, such as currencies, dates etc.
"CalendarType":1,"Eras":[1],"TwoDigitYearMax":2029,"IsReadOnly":true},"DateSeparator":"/","FirstDayOfWeek":1,"CalendarWeekRule":0,"FullDateTimePattern":"dd MMMM yyyy HH:mm:ss","LongDatePattern":"dd MMMM yyyy","LongTimePattern":"HH:mm:ss","MonthDayPattern":"dd MMMM","PMDesignator":"PM","RFC1123Pattern":"ddd, dd MMM yyyy HH\u0027:\u0027mm\u0027:\u0027ss etc....
I solved this problem by using Datejs as
In codebehind(aspx.cs) I get the culture for an employee and add the appropriate js to the header as
string path =
"http://datejs.googlecode.com/svn/trunk/build/date-"
+ GetCulture() + ".js"; Helper.AddJavaScript(this, path);
(in your case you can get the culture from navigator.systemLanguage (or navigator.browserLanguge etc) and add a script tag to the header with src attribute pointing to the appropriate path)
On the client-side I use
d.toString(Date.CultureInfo.formatPatterns.shortDate)
where d is any date object
(I tried using Date.today().toShortDateString() but it was throwing exception. (the CultureInfo JSON object had a different structure than what the function expects).
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.