Wednesday, September 16, 2009

How I did resource files with WSP builder and SharePoint in a DataFormWebPart

Resource files can be either in a .resources format or a .resx format. Visual Studio works great with .resx files where you can call the resource directly via a static class.

Resx files can be put in 12/Resources like core.resx, but I couldn’t get this to work out of the box.  After some googling and trying out different things, this is my receipt  on how to develop a SharePoint webpart and use resources with XSLT.

Firstly create a folder called Resources in the root of your project, and then add your resx files there.

resx

Then I added a class to handle the lookup of resources

public class ResourceHandler
{
private static readonly ResourceManager _resourceManager;
public static readonly ResourceHandler Instance = new ResourceHandler();

static ResourceHandler()
{
if (_resourceManager == null)
{
Type type = typeof(FrontResources);
_resourceManager = new ResourceManager("webparts.front.Resources.FrontResources", type.Assembly);
}
}

public string GetLabel(string key)
{
return GetLabel(key, HttpContext.Current);
}

public string GetLabel(string key, HttpContext context)
{
if(!HasKey(key, context)) return key;
return _resourceManager.GetString(key, GetCulture(context));
}

public bool HasKey(string key, HttpContext context)
{
ResourceSet rs = _resourceManager.GetResourceSet(GetCulture(context), true, true);
IDictionaryEnumerator ide = rs.GetEnumerator();
while (ide.MoveNext())
{
if (ide.Key.Equals(key)) return true;
}
return false;
}

private CultureInfo GetCulture(HttpContext context)
{
if (context.Request.UserLanguages.Length > 0)
{
try
{
return new CultureInfo(context.Request.UserLanguages[0]);
}
catch (ArgumentException)
{
return CultureInfo.CurrentUICulture;
}
}
return CultureInfo.CurrentUICulture;
}
}

The HasKey function was added due to the XSLT failing if accessing a key which wasn’t present, even if I try/catch around _resourceManager.GetString.

Inside the DataFormWebPart I override ModifyXsltArgumentList in order to add a namespace for the ResourceHandler in the xslt.
protected override void ModifyXsltArgumentList(ArgumentClassWrapper argList)
{
argList.AddExtensionObject("http://schemas.company.no/SharePoint/Label", ResourceHandler.Instance);
base.ModifyXsltArgumentList(argList);
}

And in the xslt you access a resource in the following way:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:front="http://schemas.company.no/SharePoint/Label">
<xsl:output method="xml" indent="yes"/>

<xsl:template match="/">
<xsl:value-of select="front:GetLabel('My_label')" />:
</xsl:template>
</xsl:stylesheet>

When you run WSPBuilder it will automatically pick up the resx files and add them as embedded .resources files in the compiled dll.



Resource Assembly added: nb-NO\webparts.front.resources.dll