Localization of SiteMapNodes broken?

Topics: Web Client Software Factory, User Forum
Feb 16, 2007 at 9:46 PM
Hello,

I've read the explaination of how to localize sitemap nodes here:

http://msdn2.microsoft.com/en-us/library/ms178427.aspx

However this seems not to work. The constructor for the SiteMapNodeInfo class does take a NameValueCollection of explicit resources, however they don't seem to work. Is the enableLocalization property even settable on the provider used in WCSF For the sitemap? I've tried this:

protected virtual void RegisterSiteMapInformation(ISiteMapBuilderService siteMapBuilderService)
{
// Add the "Home" node
SiteMapNodeInfo moduleNode = new SiteMapNodeInfo("Home", "~/", "$resources:MyAppGlobalResourceFile,MyKey,MyDefaultValue");
_siteMapBuilderService.AddNode(moduleNode);
}

as well as this:

protected virtual void RegisterSiteMapInformation(ISiteMapBuilderService siteMapBuilderService)
{
NameValueCollection res = new NameValueCollection();
res.Add("title", "$resources:MyAppGlobalResourceFile,MyKey,MyDefaultValue");

// Add the "Home" node
SiteMapNodeInfo moduleNode = new SiteMapNodeInfo("Home", "~/", "Home", "Home");
moduleNode.ExplicitResourceKey = res;
_siteMapBuilderService.AddNode(moduleNode);
}

and when I switch the language of the Session.LCID all the rest of my view's strings are retrieved correctly from the right resource file, but I always see english for the sitemap nodes.

Help! :)

-eav
Mar 1, 2007 at 5:14 AM
No-one knows eh? =(
Apr 15, 2007 at 7:06 AM
I know ;)

1- Add in the App_GlobalResources folder your resource files //Ex: SiteMapLocalizations.resx & SiteMapLocalizations.ar-LB.resx

2- Add keys to the resources files //Ex: ResourceKeyName.title

3- In the ModuleSiteMapProvider class in the CompositeWeb assembly in the Initialize method, add the following lines of code:

this.EnableLocalization = true;
this.ResourceKey = "SiteMapLocalizations"; //Where SiteMapLocalizations is the name of the resource file.

NB: I would recommend creating another class inheriting from ModuleSiteMapProvider and overriding the Initialize method as not to change the CompositeWeb code.

4- Go the Module Initializer class in your module, in the RegisterSiteMapInformation method, add the nodes as follows:

SiteMapNodeInfo node1 = new SiteMapNodeInfo("MyNodeKey", "", "My Node Title");
node1.ImplicitResourceKey = "ResourceKeyName";
_siteMapBuilderService.AddNode(node1);

Now once your change your culture, the site map will be updated appropriately

And that should solve your problem

Regards,
Apr 15, 2007 at 2:32 PM
works great, thanks
Jun 22, 2007 at 6:14 PM
I tried what you suggested but to no avail. What am I missing? I am required to do Site map localizations for my web page. I want to use the WCSF. If this doesn't work can I continue with regular sitemaps datasources and the WCSF instead. Thanks loads... waiting for your reply.
Jun 23, 2007 at 2:32 AM

ridgte wrote:
I tried what you suggested but to no avail. What am I missing?


did you put the resource file in the App_GlobalResources folder?

1. inherit from ModuleSiteMapProvider and override the Initialize method
public class MySiteMapProvider : Microsoft.Practices.CompositeWeb.Providers.ModuleSiteMapProvider
{
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
{
base.Initialize(name, config);
EnableLocalization = true;
ResourceKey = "SiteMap"; // name of the global resource file, Add SiteMap.resx in the App_GlobalResources folder
}
}

2. Register the node in the Module Initializer
protected virtual void RegisterSiteMapInformation(ISiteMapBuilderService siteMapBuilderService)
{
// add menu items
SiteMapNodeInfo node = new SiteMapNodeInfo("NodeKey", "~/Default.aspx", "Node Title");

// set the resource key
node.ImplicitResourceKey = "MyMenu";

siteMapBuilderService.AddNode(node);
}

3. Add keys to SiteMap.resx
MyMenu.Title = "My Menu"

hope it helps
Jun 25, 2007 at 1:31 PM
Thanks folks for your help. It's now working for me. It is the .Title for the resource file name; however, I am getting an warning. For example, Home.Title for name key gives me a warning that The Resource 'Home.Title' is not a valid identifier; however, saving it as such and ignoring the warning fixes the problem. Thanks very much again for your help.

p.s. the following code was added to the ModuleSiteMapProvider in the CompositeWeb assembly...

/// <summary>
/// Initializes SiteMapLocalizations
/// </summary>
/// <param name="name"></param>
/// <param name="attributes"></param>
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection attributes)
{

this.EnableLocalization = true;
this.ResourceKey = "SiteMapLocalizations";
base.Initialize(name, attributes);
}

Jul 21, 2007 at 2:46 PM
Thats all great BUT, How do you localize your URLs ??? Like, you CAN'T have a page called "buy-my-stuff.aspx" and expect people from other countries to understand what your URL means. I don't see any easy solutions using the ModuleSiteMapProvider ? Can someone help

Thx

Tief
Mar 28, 2008 at 9:14 AM
Using explicit resources works like this:

NameValueCollection keyCollection = new NameValueCollection();
keyCollection.Add("title", classNameTitle);
keyCollection.Add("title", resourceKeyTitle);
keyCollection.Add("description", classNameDescription);
keyCollection.Add("description", resourceKeyDescription);
SiteMapNodeInfo info = new SiteMapNodeInfo(key, url, null, null, null, null, keyCollection, null);

className is the name of the global resource file (e.g., "SiteMap" for SiteMap.resx), resourceKey the full name of the key in the resource file.
Dec 7, 2008 at 7:25 PM
Hi, The above mentioned approach works fine but there is some problems, I tested it on wcsf feb 2008, both on WAP and Web applications, and it just works when the resource files are reside in the app_GlobalResources of the main web project/ application. I thing this breaks the modularity of the whole application. For example when you have a shell and two modules named OrderManagement and CustomerManagement its expeted that thier localization info get resided some whre in the module assembly or in the module.Web project not in the main web project.
I have tries using
            NameValueCollection keyCollection = new NameValueCollection();
            //className is the name of the global resource file (e.g., "SiteMap" for SiteMap.resx),
            //resourceKey the full name of the key in the resource file.
            keyCollection.Add("Title", "SiteMapInfo.resx");
            keyCollection.Add("Title", "MyMenu.Title");
            //keyCollection.Add("description", classNameDescription);
            //keyCollection.Add("description", resourceKeyDescription);
            SiteMapNodeInfo info = new SiteMapNodeInfo("Module1", "~/Module1/Default.aspx", null, null, null, null, keyCollection, null);            
            siteMapBuilderService.AddNode(info);
and specify the location of SiteMapInfo in the module and module web in WAP and Web App approaches but it doesnt work. The following is the more detail exception message:

The resource object with classname 'LocalInfo.resx' and key 'MyMenu.Title' was not found.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.InvalidOperationException: The resource object with classname 'LocalInfo.resx' and key 'MyMenu.Title' was not found.

Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Stack Trace:

[InvalidOperationException: The resource object with classname 'LocalInfo.resx' and key 'MyMenu.Title' was not found.]
   System.Web.SiteMapNode.GetExplicitResourceString(String attributeName, String defaultValue, Boolean throwIfNotFound) +2625186
   System.Web.SiteMapNode.get_Title() +56
   System.Web.SiteMapNode.System.Web.UI.INavigateUIData.get_Name() +7
   System.Web.UI.WebControls.TreeView.DataBindRecursive(TreeNode node, IHierarchicalEnumerable enumerable, Boolean ignorePopulateOnDemand) +4118
   System.Web.UI.WebControls.TreeView.DataBindNode(TreeNode node) +285
   System.Web.UI.WebControls.TreeView.PerformDataBinding() +120
   System.Web.UI.WebControls.HierarchicalDataBoundControl.PerformSelect() +85
   System.Web.UI.WebControls.BaseDataBoundControl.DataBind() +73
   System.Web.UI.WebControls.TreeView.DataBind() +4
   System.Web.UI.WebControls.BaseDataBoundControl.EnsureDataBound() +82
   System.Web.UI.WebControls.BaseDataBoundControl.OnPreRender(EventArgs e) +22
   System.Web.UI.WebControls.TreeView.OnPreRender(EventArgs e) +36
   System.Web.UI.Control.PreRenderRecursiveInternal() +80
   System.Web.UI.Control.PreRenderRecursiveInternal() +171
   System.Web.UI.Control.PreRenderRecursiveInternal() +171
   System.Web.UI.Control.PreRenderRecursiveInternal() +171
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +842

Nov 13, 2009 at 3:38 PM

I agree 100% with the last post: this breaks the modularity of the whole application.

From what I'm reading, we will have to define strings in a resource file in the Shell projectthat will cover all the needs of all the modules that will ever be a part of this shell... but the Shell project should not know the intricate details of its modules, its the module's responsibility to know about itself including its resources.

This goes right against the whole point of the WCSF, has anyone found a modular solution to this?