Using SharePoint site’s Regional Settings as your UICulture for WCM presence sites.

This post describes how I use resource files in SharePoint on the custom created publishing pages and DVWP web-parts. The solution provided uses the standard <%resources … %> tag and reads the culture from the regional settings then uses this culture to load the resource file from the APP_GLOBAL_RESOURCES and display the localized text. Therefore enabling to display localized static text to users on a per-site-basis.

I am using variations as a part of an solution for a client. I’ve created quite a lot of web-parts in using the DVWP SharePoint designer, layout pages and master-pages. At some point I needed to localize the static text’s on the pages. The requirements stated that the resources language used on the sites should be on a per-site-basis (such as contact form for nl-NL/de-DE), and had to be made possible to switch it afterwards. The authoring environment or back-end (such as lists etc) should be in English. The first thing that popped in my head was the use of resource functionality provided by the SharePoint or actually ASP.NET framework itself. In this way I could just use the OOB <%$Resources: MyFile, MyKey %> functionality provided by ASP.NET.

1. Creating the resource file for translation
This is pretty straightforward, just create your resources files such as., and etc. NOTE: don’t forget to alter the localeID between the comments. This is essential if you want SharePoint to pick up the locales.

2. Deploying your resource files to the app_globalresources.
However, to get the resources loaded, files needed to be placed in the “app_globalresources” in the IIS directory of the web site. This can be done manually, but since this requires copy pasting by inferior humans such as I, it is a risk we can’t take (And it would be a showstopper in our automatic build). So we’ll do it by featuring. Unfortunately there is no default way of provisioning this directory using feature functionality out of the box.  Luckily, using SharePoint’s extensive object model and feature receiver API we can create our own logic for copying the resources to the IIS “app_globalresources” directory as pointed out by this post. However, I adapted it slightly to support retracting of resource files, but the main functionality kept intact.

3. Making SharePoint use the regional settings as your culture for displaying publishing pages.
So I created a couple of resource files, in different locale’s but SharePoint didn’t pick it up when I changed the regional settings. This is because ASP.NET uses UICulture for loading resources instead of the Culture setting and ignores the Regional Settings. To bend SharePoint to our will. I derived a class from PublishingPageLayout override the PreInit and the IntializeCulture culture to set the the:

CurrentThread.Current.UICulture = SPContext.Current.Web.Locale.

I used my own PublishingPageLayout (made it RegionalAwarePublishingPageLayout) and used this instead of the original PublishingPageLayout that is used for creating page layouts. This way, SharePoint uses my RegionalPublishingPageLayout implementation instead of its own.

And there you go! Now you can use the standard resources approach in SharePoint, and let SharePoint load the correct language by reading from the Regional Settings.

Exporting lists for features programmatically using SolGen’s API and reflection

This post describes how I re-use SharePoint Solution Generator’s API by reverse engineering the code using Reflector and calling using reflection. By using the SPListTemplateExporter provided by SharePoint Solution Generator we can export List definitions programmatically with necessary companion files and use them in my features for automatic build and packaging. Thus eliminating tedious error prone manual writing of XML files.

For my WCM Presence Factory (I’ll talk about this puppy in my upcoming posts) I needed to export lists I’ve created with SharePoint designer. This had to be done programmatically, so that my factory can export lists from existing sites for automatic builds. I could then use this list template to package it and support incremental updates on my WCM environment. SharePoint Solution Generator (solgen) already hosts functionality to do so, so I decided to use their API to export the lists. Unfortunately MS has all it types set to internal so I couldn’t just reference their API and use their classes. Luckily with some handy reflection work you can still instantiate internal types and call its methods on it to achieve the desired result.

I used Lutz’ reflector to inspect the API and came up with the SPListTemplateExporter to export the lists definitions. (I cramped it all into something that is sort of readable)

private static void ExportTemplate(string
    outputdir, string url, string listname)
  using (SPSite site = new SPSite(url))
     using (SPWeb web = site.OpenWeb())
       //Access internal ListTemplateExporter using reflection
       Type t = Type.GetType(“Microsoft.SharePoint.Tools.IO.”+
       “SPListTemplateExporter,SPSolGen, Version=”);

       //Create a new instance
       object instance = Activator.CreateInstance(t);

       //Create a list of guids
       Guid[] g = new Guid[] { web.Lists[listname].ID };

           SetValue(instance, url, null);

           SetValue(instance, outputdir, null);

       //Call Export(Guid[] ids)
       t.GetMethod(“Export”, new Type[]
         { typeof(ICollection<Guid>) })
         .Invoke(instance, new object[] { g });

And now you can easily generate a list with its companion files  such as schema.xml. etc which you can use for your feature packaging. Calling the method would be something like:

ExportTemplate(“C:\\”, “http://myserver/&#8221;, “MyList”);

PS. Don’t forget to create a reference to solution generator’ exe.
PSPS. You can use the same method to export other artifacts from SharePoint.
PSPSPS. Lutz Roeder should get a medal, or two.

Addendum: Just some general information. If you have lookups defined in your list’ schema.xml, it will not work by default since its referenced to the lookup list by ID. If you change this to ListName=”Lists/<TheNameOfListToLookupTo>”, Sharepoint will try to fix the relationship. Just make sure that the list you are referring to exists.

MS releases WSS/Office/MOSS service packs!

Find all the information you need here: