The ReportViewer control that Microsoft provides to display SQLServer Reporting Services reports in ASP.NET web applications does not support custom cultures. There doesn’t appear to be any good, or easy work around for the lack of custom culture support. Furthermore, it appears that the Reporting Services team is intent on continuing to use locale IDs to identify .NET cultures instead of culture names regardless of the preferred method of identifying cultures in .NET being by name.
Locales are used to identity formatting and languages in a particular region. Microsoft chose to rename locales in the .NET framework as cultures. Locales are shipped with Windows and are used directly by unmanaged code, that is, code which does not run in the .NET CLR. A locale defines—among other things—the language and the region that language is spoken in. Locales are used within software globalization to help determine which translations to show, which number formats to use, which time format to use, and etc. Cultures exist within the .NET CLR and are automatically generated from Windows locales. A culture in the .NET platform contains the same information as its corresponding Windows locale. For example the .NET culture identified by en-US (English in the United States) contains the same information as the locale identified by locale ID 1033 (English in the United States).
I need to pause here to explain the concept of the locale ID and its relationship to locale standards. The concept of globalizing software is not new and there are a number of standards for how to name a particular region and language. The most current standard (to my knowledge) is the Internet Engineering Task Force’s language tags defined in this RFC document, IETF RFC 5646. The wikipedia article on language tags is also informative, although only slightly less dense than the original RFC document. Still with me? Okay. One of the standards that contributed to and helped to define RFC 5646 was ISO 639-3. The collection of ISO 639-* standards define the familiar en-US, en-GB, es-MX culture names. For reasons I haven’t been able to determine, Microsoft decided some time ago to additionally define a new naming system for locales on the Windows platform. The Microsoft locale naming system is called the MS-LCID, and it’s based on the registered cultures in ISO 639-3. MS-LCID identifies cultures by a number instead of by standardized name. Using MS-LCID, the en-US locale is identified by the locale ID (LCID) 1033 and en-GB is identified by LCID 2057. Moving forward several years, when Microsoft released .NET in 2010 with new globalization features, they recommended only identifying cultures by name (or in words using the standardized naming conventions) instead of MS-LCID. The result is that MS-LCIDs are still supported, but shouldn’t be used, particularly in the .NET world.
Returning to ASP.NET:
In ASP.NET, cultures can, and should be used as part of the globalization system. An application will use cultures associated with the global locations that it should be localized for. For example, if I was developing for the U.S., France, and Spain I would likely use the following cultures: en-US, fr-FR, and es-ES. I would have translators localize my application’s text for those cultures and use the translations as needed given the desired display culture.
Microsoft cannot, however ensure that Windows will have an appropriate locale available for every possible language and region that an application may need to be localized for. Fortunately, it is possible to create and install custom cultures on Windows using .NET that behave almost exactly like the locales and cultures shipped with Windows. A major (and problematic) difference between custom cultures and the cultures shipped with Windows is that all custom cultures are assigned the LCID 4096. Being an internal definition invented by Microsoft, we don’t know how to turn custom culture names into unique LCIDs. Additionally, Microsoft’s stance is that it should not matter because the way of the future is to use culture names in the .NET framework which will always be unique for custom cultures.
Changing gears again:
Another popular Microsoft product is SQLServer. A feature of SQLServer is SQLServer Reporting Services (SSRS) which enables a developer to design reports that display information gathered from queries to a backend database. For context, SSRS’ main competitor is SAP Crystal Reports. A lot of the flash and bang advertisements for SSRS talk about enabling business intelligence, but really at its base SSRS is a tool to dynamically generate reports and charts from information stored in a database.
A reporting tool by itself is great but where does one want to place reports in the modern web enabled world? Why, in a web application of course. The reporting services team provides a ReportViewer control for the purpose of displaying reports in ASP.NET web applications. The ReportViewer handles the interaction with the web service component of SSRS and gracefully displays reports from SSRS as they are generated. The ReportViewer control also provides facilities to send parameters to SSRS to run a parameterized report. Finally, like other Microsoft enterprise products, ReportServer supports globalization by culture. When the ReportService control is instantiated on a web page it attempts to create a new culture object using the LCID of the current culture being used by the web application.
And here is where things break. A custom culture in .NET cannot be instantiated by LCID, attempting to do so yields an exception. A few people have reported the issue to Microsoft over the last couple years on their custom connect website, here, here, and here. The root issue is that .NET has better standard complinace now and we should all be using IETF language tags to identify cultures, but the control provided by the SSRS team uses the older, proprietary MS-LCIDs.
Obviously, Reporting Services is still usable with an ASP.NET application and the ReportViewer control works fine if there is no need for custom cultures. In my work though, custom cultures are needed and they break the ReportViewer badly.