Culture issues in ASP.NET MVC 3 - asp.net-mvc

I want to display multiple languages and UI cultures on my website. I have enabled the IIS 7 flag which picks up culture from the browser automatically as so:
<globalization
enableClientBasedCulture="true"
culture="en-GB"
uiCulture="auto:en"/>
This works perfectly in that the correct Resources files are loaded, and the correct culture is displayed (0.00 for GB; 0,00 for DE).
However this has had an unexpected problem of interferring with my external services, for example here is the code for interfacing with PayPal.
var paymentDetails = new PaymentDetailsType
{
ItemTotal = new BasicAmountType
{
currencyID = currencyCode,
Value = basket.SubTotal.ToString("0.00")
},
...
}
This code basically creates a string formatted like so '50.25', however as PayPal always requires a dot decimal point, when a culture is selected that has a comma as a decimal point (for example DE - German) the ToString("0.00") generates '50,25' and so my code fails.
What would be the best method to correct this? I still want the culture set to the user's culture, however I want to set certain parts of my code to use my own culture.
I know I can feed in a specific culture to the ToString() method, but this seems very hackish. Any more professional clean approaches?

Have a look at the InvariantCulture.
Value = basket.SubTotal.ToString("0.00", CultureInfo.InvariantCulture)
Here's a link to the overload of ToString() that takes a second System.IFormatProvider parameter:
http://msdn.microsoft.com/en-us/library/d8ztz0sa.aspx

Related

How to localize the route action/controller in .NET Core

Searched but can't find any question specifically about localizing controller/actions rather than just adding the culture itself to URL.
I have a localized .NET Core website, by inserting /es/ into the URL (before controller/action is the way its set up i.e. www.bla.com/es/account/profile).
This uses culture settings and saves the culture in a cookie, and the site uses IStringLocalizer and it all works well.
My problem is, I now need to translate the route itself.
www.bla.com/account/profile
OR
www.bla.com/es/cuenta/perfil
(google translate just for example)
I don't think I am worried about translating any query strings or variable names at the moment, just the action and controller names themselves.
To add a middleware to rewrite the url, add this into your Startup.Configure method before UseRouting, UseRoute, or UseMvc depending on what is currently used:
//This definition should be moved as a field or property.
//And the value should be loaded dynamically.
var urlMappings = new Dictionary<string, string>
{
{ "/es/cuenta/perfil", "/account/profile" },
// others
};
//Rewriting the matched urls.
app.Use(next => http =>
{
if (urlMappings.TryGetValue(http.Request.Path.Value, out var result))
{
http.Request.Path = new PathString(result);
}
return next(http);
});
This is just an example on how to implement it, though url mapping rule should be managed within services.

ASP.NET MVC Date input format

I have a textbox with date type:
#Html.TextBoxFor(m => m.DateOfBirth, new { #class = "form-control", type = "date" })
of the model's field DateOfBirth
[Required]
[DataType(DataType.Date)]
public DateTime DateOfBirth { get; set; } // Дата рождения
But date format is static mm/dd/yy which is wrong for Russian (dd/mm/yy). Of course I can set date format manually, but the system is multi-lingual and has English language as well as Russian, Kyrgyz, Uzbek (they all use European formats). When a user change a language
Thread.CurrentThread.CurrentCulture =CultureInfo.CreateSpecificCulture(lang);
Thread.CurrentThread.CurrentUICulture = new CultureInfo(lang);
He supposed to see appropriate date format. But somewhy it doesn't happen :(
I have explored that the format depends on the language the browser uses. But chrome can't be displayed in Kyrgyz language...
You can accomplish what you want using the jquery.ui datepicker. By using it (or any other library that provides a similar functionality) you can easily maintain a consistent UX across multiple browsers, while with the standard HTML5 date inputs (<input type="date" />) you'll have browser-specific behaviour.
You can simply set the datepicker "regional" when loading your page. It seems that one of your goals is to be able to address multiple languages, I would recommend sticking with the "localization" idea rather than just setting the dateFormat attribute. If jquery ui does not provide a localization for the culture you are looking for, create one.
I've created a simple example where you can see the localization working in client-side. The idea would be very similar, but in your case it would be in the server-side: https://jsfiddle.net/ipvalverde/wxLxLe7p/9/
Regarding ASP.net MVC, I would suggest you to create a Razor View to setup all your datepicker elements on screen with your culture info. Something like this:
#{
_Layout = null;
}
var currentCulture = System.Threading.Thread.CurrentThread.CurrentUICulture;
string cultureCode = currentCulture.Name;
string datepickerLocalization = // Convert the thread culture name to datepicker culture name...
<script>
$(function () {
$.datepicker.setDefaults($.datepicker.regional["#datepickerLocalization"]);
})
</script>
Make sure you have loaded the javascripts with localization for the supported languages.
Let me know if this helps.

How do I get a custom localized string in the front end?

I'm having trouble accessing localizations, the value always appears in the default language.
I have two resource files in App_GlobalResources:
Resource.resx contains a string with the name "Hello" and the value of "World".
Resource.fr.resx contains a string with the name "Hello" and the value of "Monde"
In my Razor template:
<lang:string key="Resource, Resources.Resource.Hello" xmlns:lang="http://www.composite.net/ns/localization/1.0" />
"World" is always displayed, never "Monde", even when viewing the page in French.
In a vanilla asp.net website template, with the same resources, the following code within a Razor template displays "Monde"
String cultureInfo = "fr-CA";
System.Threading.Thread.CurrentThread.CurrentCulture =
System.Globalization.CultureInfo.CreateSpecificCulture(cultureInfo);
System.Threading.Thread.CurrentThread.CurrentUICulture = new
System.Globalization.CultureInfo(cultureInfo);
Response.Write(ObjectInfo.Print(Resources.Resource.Hello));
However, within C1 it results in "World".
How should I be going about this?
Thanks!
The <lang:string construct is mainly meant for XSLT templates and functions where you can't as easily fallback to calling c# code directly as in Razor.
Have you tried printing out the resource on your Razor template like this instead #Resources.Resource.Hello ?

Nullable DateTime Parameter is never bound when calling the action

I have the following function signuture:
public JsonResult PopulateGrid(int page, Guid? accountId, Guid? systemUserId, Guid? branchId, DateTime? fromDate, DateTime? toDate, HomeVisitType? homeVisitType)
Every single parameter is bound just fine except toDate which turns out to be always null.
When inspecting the Request.QueryString["toDate"] it retrives the right value which is 30/09/2010.
It seems that DateTime expects another format when binding.
What is the right format?
A quick test on my system shows that it expects the data in MM/DD/YYYY and not DD/MM/YYYY which is probably why you're having problems. My guess is that if you try the same date on the fromDate you'll also have the same null issue.
I've changed the current culture in my app to one that uses the DD/MM/YYYY and it seemed to have no effect. Seems to have the same problem with the , decimal for a language that uses 10,01 instead of 10.01...
Update from someone a developer on the ASP.Net team.
"This is intentional. Anything that is part of the URI (note the 'Uniform' in URI) is interpreted as if it were coming from the invariant culture. This is so that a user in the U.S. who copies a link and sends it over IM to a friend in the U.K. can be confident that his friend will see the exact same page (as opposed to an HTTP 500 due to a DateTime conversion error, for example). In general, dates passed in RouteData or QueryString should be in the format yyyy-mm-dd so as to be unambiguous across cultures.
If you need to interpret a QueryString or RouteData parameter in a culture-aware manner, pull it in as a string, then convert it to the desired type manually, passing in the desired culture. (DateTime.Parse has overloads that allow you to specify a culture.) If you do this, I recommend also taking the desired culture as a QueryString or a RouteData parameter so that the 'Uniform' part of URI isn't lost, e.g. the URL will look something like ...?culture=fr-fr&date=01-10-1990."

ASP.NET MVC: When to set Thread.CurrentThread.CurrentUICulture?

I am just beginning to localize an ASP.NET MVC application. Most of the strings will be defined in resource files and retrieved via Matt's Localization Helpers. Other strings must be stored in a database.
My Question:
Should I set CurrentUICulture early in the request pipeline and use that throughout the application, or directly use Request.UserLanguages[0] whenever needed?
Right now I'm thinking that I should set CurrentUICulture in Application_BeginRequest. The implementation would look something like this:
protected void Application_BeginRequest(object sender, EventArgs e)
{
var cultureName = HttpContext.Current.Request.UserLanguages[0];
Thread.CurrentThread.CurrentUICulture = new CultureInfo(cultureName);
}
Is this the best place to set CurrentUICulture and is Request.UserLanguages[0] the best place to get that info?
Update:
Ariel's post shows this can be defined without code, using web.config
<system.web>
<!--If enableClientBasedCulture is true, ASP.NET can set the UI culture and culture for a Web page automatically, based on the values that are sent by a browser.-->
<globalization enableClientBasedCulture="true" culture="auto:en-US" uiCulture="auto:en"/>
Here is a sample using an HttpModule:
http://weblogs.manas.com.ar/smedina/2008/12/17/internationalization-in-aspnet-mvc/
Other options, create a base Controller class and implement the localization logic there.
Or use an action filter attribute, but you'll have to remember to add it on every controller or combine this approach with the base Controller class.
Request.UserLanguages[0] can only be a hint what language the users wishes to see. Most users dont know where to change the browser language.
Another point: Dont be sure that Request.UserLanguages[0] is a valid language. It can even be null. (Not sure what bots have there)
You usually have a Language chooser on the page. Once a user has selected a language there, it is stored in a cookie, session or url. I like to use url because I think it looks pretty.
If a user sees your page without having set a language on your page, you should check if Request.UserLanguages[0] is a language you support and set Thread.CurrentThread.CurrentUICulture.
I use a filter to set Thread.CurrentThread.CurrentUICulture. Thats ok as long as no other filter is using Thread.CurrentThread.CurrentUICulture. Otherwise you would need to set the right execution order for filters.
I also use Matts helper and it worked very well so far.

Resources