{"id":14,"date":"2008-04-08T15:02:00","date_gmt":"2008-04-08T19:02:00","guid":{"rendered":"http:\/\/everysport.net\/GamePlan3\/Default.aspx?tabid=489&amp;EntryID=4"},"modified":"2008-10-29T12:16:53","modified_gmt":"2008-10-29T16:16:53","slug":"enabling-aspnet-20-localization-in-a-dotnetnuke-application","status":"publish","type":"post","link":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/2008\/04\/08\/enabling-aspnet-20-localization-in-a-dotnetnuke-application\/","title":{"rendered":"Enabling ASP.NET 2.0 Localization in a DotNetNuke Application"},"content":{"rendered":"<p><em>Editor&#8217;s note<\/em>: This approach has been obsoleted in favor of the more straightforward, core-friendly ASP.NET 2.0 Localization approach outlined <a href=\"http:\/\/blogs.law.harvard.edu\/brandonhaynes\/2008\/10\/29\/a-second-look-enabling-aspnet-20-localization-in-a-dotnetnuke-application-2\/\">here<\/a>.<\/p>\n<hr \/>\n<p>DotNetNuke provided rich localization support (in the DotNetNuke.Services.Localization namespace) long before ASP.NET caught up in version 2.0. Indeed, the core DotNetNuke libraries and UI continue to heavily rely upon this custom implementation to this day.<\/p>\n<p>However, after ASP.NET 2.0 was released, there were apparently a number of issues revolving around the new localization, backwards compatibility, and the existing DotNetNuke localization. As a result, the core team chose to disable all ASP.NET 2.0 localization at the application level and to rely exclusively upon its internal implementation. This is unfortunate, but understandable &#8212; the core team has a lot of audiences, and must balance the act of pleasing them all.<\/p>\n<p>DotNetNuke localization is excellent, and for almost every scenario, I strongly recommend using this API.\u00a0 However, there do exist some niche circumstances that lend toward using ASP.NET 2.0 localization.<br \/>\nFortunately, with a few small changes, it is possible to restore limited ASP.NET 2.0 functionality to your DotNetNuke installation. Herein I discuss these changes and their system-wide impact.<\/p>\n<p>Before I begin, all the usual warnings apply: back up your data, attempt this only on a development machine, thoroughly test before entering production, et cetera, et cetera. Caveat lector!<\/p>\n<p>With that, let&#8217;s get started.<!--more--><\/p>\n<h3>Restore .resx compilation<\/h3>\n<p>DotNetNuke disables ASP.NET 2.0 localization by explicitly removing .resx and .resources from the set of custom buildProviders. This is accomplished in the web.config as follows:<\/p>\n<p><span class=\"kwrd\">&lt;<\/span><span class=\"html\">buildProviders<\/span><span class=\"kwrd\">&gt;<\/span> <span class=\"kwrd\">&lt;<\/span><span class=\"html\">remove<\/span> <span class=\"attr\">extension<\/span><span class=\"kwrd\">=&#8221;.resx&#8221;<\/span><span class=\"kwrd\">\/&gt;<\/span> <span class=\"kwrd\">&lt;<\/span><span class=\"html\">remove<\/span> <span class=\"attr\">extension<\/span><span class=\"kwrd\">=&#8221;.resources&#8221;<\/span><span class=\"kwrd\">\/&gt;<\/span> <span class=\"kwrd\">&lt;\/<\/span><span class=\"html\">buildProviders<\/span><span class=\"kwrd\">&gt;<\/span><\/p>\n<p>Perhaps obviously, we&#8217;ll first need to re-enable .resx compilation by deleting \u201c&lt;remove extension=&#8221;.resx&#8221;\/&gt;\u201d.<\/p>\n<p>Warning: Because DotNetNuke uses the .resources extension for a number of other purposes (including to prevent IIS from serving sensitive files), I neither recommend enabling this extension, nor have performed ANY testing with regards to files having this extension. I strongly suggest leaving it alone.<\/p>\n<h3>Dealing with Portal-Specific Resources in App_GlobalResources<\/h3>\n<p>Once the .resx extension has been re-enabled, ASP.NET will begin compiling existing .resx resource files. However, this will cause a problem for those resources that have been localized for a specific portal. DotNetNuke creates these files with a [FileName].Portal-[PortalId].resx format (e.g. \u201cSharedResources.Portal-0.resx\u201d). When the ASP.NET resource compiler attempts to compile these files, it will generate an error. This is because ASP.NET expects the \u201cPortal-[PortalId]\u201d token to be a valid language (e.g. en-US). Obviously, \u201cPortal-[PortalId]\u201d is not a valid language, and the resource compiler chokes with: \u201cCS0101: The namespace &#8216;Resources&#8217; already contains a definition for &#8216;SharedResources&#8217;\u201d<\/p>\n<p>If you never expect to localize any of your resources (never!), then you will not encounter this situation, and may skip this step.<\/p>\n<p>Otherwise, we are thus forced to prevent the ASP.NET resource compiler from compiling these files. Although I am not fully happy with this solution, to date the best method that I have found to accomplish this is to rename the App_GlobalResources directory.<\/p>\n<p>This requires two changes:<\/p>\n<p>1) Rename your App_GlobalResources directory to GlobalResources.<\/p>\n<p>2) Update the DotNetNuke core to look in the new GlobalResources directory. This value is set on or about line 73 of Library\/Components\/Localization\/Localization.vb:<\/p>\n<p><span class=\"kwrd\">Public<\/span> <span class=\"kwrd\">Const<\/span> ApplicationResourceDirectory <span class=\"kwrd\">As<\/span> <span class=\"kwrd\">String<\/span> = <span class=\"str\">&#8220;~\/App_GlobalResources&#8221;<\/span><\/p>\n<p>Changed to:<\/p>\n<p><span class=\"kwrd\">Public<\/span> <span class=\"kwrd\">Const<\/span> ApplicationResourceDirectory <span class=\"kwrd\">As<\/span> <span class=\"kwrd\">String<\/span> = <span class=\"str\">&#8220;~\/GlobalResources&#8221;<\/span><\/p>\n<p>I have requested that this value be settable via external configuration so that a core compilation is not required, but this is yet unimplemented.<\/p>\n<h3>Restore resheaders and schema to invalid DotNetNuke resource files.<\/h3>\n<p>ASP.NET 2.0 localization requires a valid set of resheaders <span style=\"text-decoration: line-through\">and schema<\/span> for its resource files. Since DotNetNuke treats .resx files as simple xml files, it does not need this additional information. As a result, some language pack designers have intentionally omitted these data. DotNetNuke itself provides ASP.NET 2.0 localization-friendly .resx files for the most part, but there are random and frustrating omissions.<\/p>\n<p>You\u2019ll know you\u2019ve encountered one of these problematic .resx files when a page fails with the following exception: DotNetNuke.Services.Exceptions.ModuleLoadException: ResX input is not valid. Cannot find valid &#8220;resheader&#8221; tags for the ResX reader and writer type names. Note that that since ASP.NET 2.0 compiles all resources in App_LocalResources at once, the problem could be in ANY of the files, <strong>not <\/strong>just the one being accessed.<\/p>\n<p>Unfortunately, these values must be manually added to those ASP.NET 2.0-invalid .resx files. Admin\/Host\/App_LocalResources\/Solutions.ascx.resx is a continual culprit. Open with any text editor and paste the following <span style=\"text-decoration: line-through\">schema and<\/span> resheaders under the element:<\/p>\n<p><span class=\"kwrd\">&lt;<\/span><span class=\"html\">resheader<\/span> <span class=\"attr\">name<\/span><span class=\"kwrd\">=&#8221;resmimetype&#8221;<\/span><span class=\"kwrd\">&gt;<\/span> <span class=\"kwrd\">&lt;<\/span><span class=\"html\">value<\/span><span class=\"kwrd\">&gt;<\/span>text\/microsoft-resx<span class=\"kwrd\">&lt;\/<\/span><span class=\"html\">value<\/span><span class=\"kwrd\">&gt;<\/span> <span class=\"kwrd\">&lt;\/<\/span><span class=\"html\">resheader<\/span><span class=\"kwrd\">&gt;<\/span> <span class=\"kwrd\">&lt;<\/span><span class=\"html\">resheader<\/span> <span class=\"attr\">name<\/span><span class=\"kwrd\">=&#8221;version&#8221;<\/span><span class=\"kwrd\">&gt;<\/span> <span class=\"kwrd\">&lt;<\/span><span class=\"html\">value<\/span><span class=\"kwrd\">&gt;<\/span>2.0<span class=\"kwrd\">&lt;\/<\/span><span class=\"html\">value<\/span><span class=\"kwrd\">&gt;<\/span> <span class=\"kwrd\">&lt;\/<\/span><span class=\"html\">resheader<\/span><span class=\"kwrd\">&gt;<\/span> <span class=\"kwrd\">&lt;<\/span><span class=\"html\">resheader<\/span> <span class=\"attr\">name<\/span><span class=\"kwrd\">=&#8221;reader&#8221;<\/span><span class=\"kwrd\">&gt;<\/span> <span class=\"kwrd\">&lt;<\/span><span class=\"html\">value<\/span><span class=\"kwrd\">&gt;<\/span>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089<span class=\"kwrd\">&lt;<\/span><span class=\"html\">value<\/span><span class=\"kwrd\">&gt;<\/span> <span class=\"kwrd\">&lt;\/<\/span><span class=\"html\">resheader<\/span><span class=\"kwrd\">&gt;<\/span> <span class=\"kwrd\">&lt;<\/span><span class=\"html\">resheader<\/span> <span class=\"attr\">name<\/span><span class=\"kwrd\">=&#8221;writer&#8221;<\/span><span class=\"kwrd\">&gt;<\/span> <span class=\"kwrd\">&lt;<\/span><span class=\"html\">value<\/span><span class=\"kwrd\">&gt;<\/span>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089<span class=\"kwrd\">&lt;\/<\/span><span class=\"html\">value<\/span><span class=\"kwrd\">&gt;<\/span> <span class=\"kwrd\">&lt;\/<\/span><span class=\"html\">resheader<\/span><span class=\"kwrd\">&gt;<\/span><\/p>\n<blockquote><p><span style=\"color: #800000\">Note: After publishing, I discovered that only the resheaders are required; the schema remains optional.\u00a0 For those that wish to include schema, I will include it as a comment below.<\/span><\/p><\/blockquote>\n<p>Once you save the resource file with the expected data, the exception should go away. I have requested that these data be added to all standard DotNetNuke resources files, but the core team has disagreed with me. Charles Nurse indicated that:<\/p>\n<blockquote><p><em>&#8230;We have for historical reasons used the resx language files as standard xml files. This is how they are processed &#8211; in fact the resx file extension is eplicitly disabled from the BuildManager in web.config.<\/em><\/p>\n<p><em>While the schema is added automatically to the resx files by the resource editor in Visual Studio, it is our intention to remove the headers as they affect performance in our implementation.<\/em><\/p>\n<p><em>The fact that you have decided to compile those resources in your modules means that your requirements conflict with the core requirements. We cannot address this.<\/em><\/p><\/blockquote>\n<p>He has an excellent point, and though my requirements do differ, I completely agree with his conclusion. Read the full details <a href=\"http:\/\/support.dotnetnuke.com\/issue\/ViewIssue.aspx?id=6383&amp;PROJID=2\"><span style=\"text-decoration: underline\"><span style=\"color: #669966\">here<\/span><\/span><\/a>.<\/p>\n<h3>Compile and Enjoy<\/h3>\n<p>These changes will allow you to use ASP.NET 2.0 localization at the App_LocalResources level \u2013 including .ascx syntax (via the &lt;%$ %&gt;or meta:resourcekey methods) and by code (via the strongly-typed Resources object, or by a GetLocalResourceObject call.<\/p>\n<p>GlobalResources should also be accessible, provided a new App_GlobalResources directory is created and resources are placed within. However, the DotNetNuke GlobalResources and SharedResources values will need to be accessed via the DotNetNuke localization API (as they probably should be).<\/p>\n<p>If anyone actually chooses to go this route and implement the changes I\u2019ve outlined above, I\u2019d appreciate feedback and information about any problems encountered. Eventually I\u2019m sure that DotNetNuke will move to support ASP.NET 2.0 localization, and this is a good step in that direction!<\/p>\n<p>B<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Editor&#8217;s note: This approach has been obsoleted in favor of the more straightforward, core-friendly ASP.NET 2.0 Localization approach outlined here. DotNetNuke provided rich localization support (in the DotNetNuke.Services.Localization namespace) long before ASP.NET caught up in version 2.0. Indeed, the core DotNetNuke libraries and UI continue to heavily rely upon this custom implementation to this day. [&hellip;]<\/p>\n","protected":false},"author":1933,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3062,142],"tags":[3367,3070,19470,3366],"class_list":["post-14","post","type-post","status-publish","format-standard","hentry","category-dotnetnuke-dnn-content-management-system","category-technology","tag-aspnet","tag-dotnetnuke","tag-dotnetnuke-dnn-content-management-system","tag-localization"],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/wp-json\/wp\/v2\/posts\/14","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/wp-json\/wp\/v2\/users\/1933"}],"replies":[{"embeddable":true,"href":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/wp-json\/wp\/v2\/comments?post=14"}],"version-history":[{"count":0,"href":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/wp-json\/wp\/v2\/posts\/14\/revisions"}],"wp:attachment":[{"href":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/wp-json\/wp\/v2\/media?parent=14"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/wp-json\/wp\/v2\/categories?post=14"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/wp-json\/wp\/v2\/tags?post=14"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}