Localization of navigation

Nov 17, 2010 at 12:37 PM

Hello Jeremy,

In the ExportAsView attribute you can assign the MenuName and ToolTip properties. But this is not localization friendly, because in an attribute you can't access the resources. When developing a framework, keep in mind to never have hardcoded UI text.

My idea to solve the problem is to let the NavigationViewModel (based on the SimpleNavigation quickstart) get the menuname and tooltip from the resourcemanager. This can be done by convension that the NavigationViewModel searches in the resources for entries with the names MenuName_[ViewType] and ToolTip_[ViewType].

But perhaps you have better ideas to solve this problem?

With regards,

Jaap

Nov 17, 2010 at 12:55 PM

My above mentioned solution is not corrent. The resources should have to be in the assembly in which the NavigationViewModel exists or it should have access to it. But that's not a good idea if you want to build an application with different modules.

So to solve this, the ExportAsView should get ResourceType property, must like the way the localization of the Validation attributes is working. Then the NavigationVIewModel can take this type and get the resources from it.

Jaap

BTW: I like Jounce. I am just starting creating our own framework for our applications, and, after much reading on the internet about Prism, Caliburn, MVVM Light, and so on...., you ideas match very well my ideas. So Jounce arrived just in time ;-) I have not yet decided if I just add the Jounce projects to my framework as they are. Or that I take the code I need and incorperate it into my code (with my own namespaces, and so on).

Coordinator
Nov 17, 2010 at 11:17 PM

Actually, it should be relatively straightforward. If you want internationalization, you make the text you assign to the attributes the key to the resource dictionary. Then, you can do 1 of 2 things:

1. In code-behind, load the attribute metadata, then call the Resource file and pass the key from the metadata to resolve the internationalized result, or

2. In XAML, use a value-converter that does the same thing

Nov 18, 2010 at 10:32 AM

This is only a part of the solution. If I have several views in multiple projects (and perhaps different XAP's), each project will have it's own resource dictionary. The shell project, containing the navigation view(model), should not now them. So the view metadata must also have the ResourceType, just as it is done in the Validation attributes in the data annotations assembly.

Nov 18, 2010 at 4:07 PM
Edited Nov 20, 2010 at 10:08 PM

Hello,

I had the same problem but i didn't used the Export MenuName because I want to Load Module On Demand.

So I Use a XML File like

 

<?xml version="1.0" encoding="utf-8" ?>
<SiteMap>
<SiteMapNode Id="AdministrationSection" Label="Administration" ResourcesXapUri="TestResources.xap">
<SiteMapView ViewName="TestView" ViewModel="TestViewModel" XapUri="Test.xap"/>
</SiteMapNode>
</SiteMap>

 

Then at start i get all ResourcesXapUri where i put my resx and with IModuleInitializer i add all Resources file ResourceManager to a class :

 

 

    /// <summary>
/// The resources manager.
/// </summary>
[Export(typeof(IResourcesManager))]
public class ResourcesManager : IResourcesManager
{
#region Constants and Fields

/// <summary>
/// The resources.
/// </summary>
private static readonly List<ResourceManager> Resources = new List<ResourceManager>();

#endregion

#region Indexers

/// <summary>
/// The this.
/// </summary>
/// <param name="index">
/// The index.
/// </param>
public string this[string index]
{
get
{
return GetString(index);
}
}

#endregion

#region Implemented Interfaces

#region IResourcesManager

/// <summary>
/// The add resource.
/// </summary>
/// <param name="manager">
/// The manager.
/// </param>
public void AddResource(ResourceManager manager)
{
if (!Resources.Contains(manager))
{
Resources.Add(manager);
}
}

#endregion

#endregion

#region Methods

/// <summary>
/// The get string.
/// </summary>
/// <param name="index">
/// The index.
/// </param>
/// <returns>
/// The get string.
/// </returns>
private static string GetString(string index)
{
return Resources.Where(res => HasNeededString(res, index)).Select(s => s.GetString(index, Thread.CurrentThread.CurrentCulture)).FirstOrDefault();
}

/// <summary>
/// The has needed string.
/// </summary>
/// <param name="resourceManager">
/// The resource manager.
/// </param>
/// <param name="index">
/// The index.
/// </param>
/// <returns>
/// The has needed string.
/// </returns>
private static bool HasNeededString(ResourceManager resourceManager, string index)
{
try
{
if (resourceManager.GetString(index) == null)
{
return false;
}
}
catch (Exception)
{
return false;
}

return true;
}

#endregion
}


And then i create my Menu from xml.

 

Jan 5, 2011 at 4:36 PM

Hi Jeremy,

In a comment above, you mention using a value converter to resolve resource strings in XAML for dynamically loaded XAP files. Can you give us an example?

Also, do you see anything wrong with adding resources to the XAML, such as

    <controls:ChildWindow.Resources>
        <helpers:ResourceWrapper x:Key="ResourceWrapper"/>
    </controls:ChildWindow.Resources>

and then referencing the resource normally like:

<TextBlock Text="{Binding Path=ApplicationStrings.MyString, Source={StaticResource ResourceWrapper}}"/>

Normally, this would be done in the resource dictionary in App.xaml, but the dynamically loaded XAP 
does not have App.xaml, and I would like to keep the XAP-specific strings in the XAP rather than the shell.
 
Thanks,
John
Coordinator
Jan 5, 2011 at 4:40 PM

Hey, John. I'll see what I can put together for an example. I don't see any issue with what you posted above, it makes sense to me.