For us 'English as an only language' folks, it's easy to skim over globalization issues. But with a global audience, sooner or later you'll run into problems. Here's one of mine.
I had an interesting bug recently on one of my products that requires a licence file. The customer installed it on a website which was a multi-lingual DNN site. The site had the ability to switch between English and French content, and detected the default language based on the browser settings, using the ‘Adequation Localization’ module. This module localises the menu system and changes the language.
The modules I sell with licensing built in work on a licence file. If you have the correct licence file, the modules work as normal. If you have the wrong licence file, or an expired trial licence file, then you’ll get a message asking you to licence the product. This message changes in its location depending on the product, but it invariably shows up as ‘nagware’. I like this model because it allows people to try the module out free of charge, and if they like the module they can follow the links and purchase a licence. Simple enough.
The problem came about when the customer reported that on the English version, it all worked fine, but on the French version of the same website, the licence message showed up. Now this was the same module, same domain, same database – same everything. The only difference was one page was showing up in English, and the other page shows up in French.
This had me scratching my head for a while, and I had to work with the customer to systematically rule out possibilities. When all the other possibilities were eliminated, the answer had to be something in the ‘French’ version was causing the licence file to be read incorrectly. But what? I checked all the code and the licence file, thinking perhaps an accented character or something was failing a string comparison. No luck there. Then I though perhaps there was some type of file-reading Unicode/UTF-8 problem. No, and it didn’t make sense anyway.
In the end I re-created the entire customers site on my test server, installed all the same modules and watched each line of code, step by step until I could find out what was wrong. Finally I discovered that the data being used to determine if the licence file was valid was missing a few key values. But these key values were present in the licence file. Then I realised that, due to backwards compatibility, the key values weren’t present because the licence file version was incorrect. But the licence file version was correct in the file. Then finally I discovered the problem line:
string version = ReadVersionFromFile(licenceFile);
if (double.TryParse(version, out licenceVersion))
{
//do licence stuff
}
else
{
//fail
}
The ‘version’ variable was a string value of “1.2” in this case. When running with a culture of ‘en-US’ (or en-GB, for that matter), then “1.2” parses OK into a value of 1.2. However, when the language in DNN is set to ‘fr-FR’ (or fr-CA) then “1.2” doesn’t parse at all. The French version wants to see “1,2”. Anyone who has had a coffee in a Parisian café will know they get the bill looking something like this:
| Un Café au Lait: |
10,50 € |
| Impôt l'étranger: |
11,50 € |
| Total : |
21,50 € |
(But I jest, ‘foreigner tax’ isn’t nearly as much! And I do love a coffee in Paris café, whatever the cost)
The point is, French culture settings use commas as decimal points, and so all code running under a French culture will do the same, even if it’s not part of the UI.
The fix was to change the code to use the specific culture that the licence file was created with.
string version = ReadVersionFromFile(licenceFile);
if (double.TryParse(version, System.Globalization.NumberStyles.AllowDecimalPoint,
CultureInfo.CreateSpecificCulture("en-US"), out licenceVersion))
{
//do licence stuff
}
else
{
//fail
}
This solved the problem instantly by forcing the expected culture for the double parsing.
Now, I like to think of myself as pretty ‘culture aware’ when building code. I’ve had a policy of “every string value is ‘nvarchar’”, and “all string comparisons are culture and case invariant” for a long time. I realise that probably 50% of the sales I make are to people who aren’t using an ‘en-US’ setting on their computer or browser.
I just got caught out by forgetting that when the language of a site changes, the culture settings change as well. You might consider this when parsing some currency values, but you also need to remember when dealing with seemingly unrelated functions.
(thanks to Pierre for being patient while I solved it, and thanks to Etienne for pointing me in the right direction)