I’m part way through a series in looking at how we can provide multi-lingual user interfaces (or MUI) when designing custom SharePoint solutions. In what turned into Part 0 we saw SharePoint’s out of the box MUI by way of Language packs. Then in Part 1 we saw how we could Feature resource files to provide alternative text for SharePoint elements like list and content types.
This post we’re going to look at how we can use SharePoint Resource files which are deployed to the Resources folder within the 14 folder. Feature resources work well in the context of list definitions, content types – the CAML/declarative type elements. However, try to use those in say code and you’ll struggle! What if we want to set the text of a label in code? Or provide validation messages on a form? These are the kind of elements that we can’t declare in CAML and have to use some code. Here’s where SharePoint brings its own helper method to retrieve localised values.
SPUtility.GetLocalizedString(string source, string defaultResourceFile, uint language)
On the surface this looks great as it gives a simple way to retrieve those localised values from our Resource files, but the gotcha here is that this method doesn’t look at the Feature resources! If you need to access localised values through code we have to create additional resource files which are globally available to SharePoint. What’s handy with these files is that once they’re deployed they can be re-used by different features.
Adding SharePoint Resource Files
1) In Visual Studio, right-click the project and Add > SharePoint Mapped Folder…
2) In the dialog window that opens, select Resources
3) In the project folder, there’ll now be a folder called Resources. Whatever is added to this folder will automatically be copied to the Resources folder when the solution is deployed.
4) Now let’s a Resource file, select the Resources folder and then Add > New Item
5) Under the General templates, find the Resources File
6) We need to specify a filename, let’s make this the default one and call it CustomResources.resx
7) Now we have our familiar editor where we can enter our resources just like before
We can add further resource files in the same way, creating new files as required, using whatever file names we like. The only thing to remember is that when we create different languages we need to manually specify the language as part of the filename, for example: CustomResources.fr-FR.resx.
Add the following text:
|Name||Value (English)||Value (French)|
Now we’ve created our resource files let’s see how we can use them in conjunction with the GetLocalizedString. For this demo, I’ve added an Application page to the project (so it gets added to the layouts folder) and I’ve added a couple of ASP labels and textboxes to the aspx page:
<ul> <li><asp:Label ID="ltFirstname" runat="server" AssociatedControlID="txtFirstname" /><asp:TextBox id="txtFirstname" runat="server" /></li> <li><asp:Label ID="ltSurname" runat="server" Text="Surname" AssociatedControlID="txtSurname" /><asp:TextBox id="txtSurname" runat="server" /></li> <li><asp:Label ID="ltComment" runat="server" Text="Comment" AssociatedControlID="txtComment" /><asp:TextBox id="txtComment" runat="server" /></li> <li><asp:Button id="btnSubmit" text="Send" runat="server" /></li> </ul>
Nothing special, except that I’ve not provided any Text for the labels since for simplicity we’re going to set these in code behind. So, let’s jump into the .cs file and add the following to the Page_Load method:
var lcid = (uint)CultureInfo.CurrentUICulture.LCID; ltFirstname.Text = SPUtility.GetLocalizedString("$Resources:FormFirstname", "CustomResources", lcid); ltSurname.Text = SPUtility.GetLocalizedString("$Resources:FormSurname", "CustomResources", lcid); ltComment.Text = SPUtility.GetLocalizedString("$Resources:FormSurname", "CustomResources", lcid); btnSubmit.Text = SPUtility.GetLocalizedString("$Resources:SendButton", "CustomResources", lcid);
Deploy and fingers crossed all should work. Load the page in English and the labels and button should display the English text, switch to French and it should change to the French version.
SPWeb.Language vs CultureInfo.CurrentUICulture.LCID
Here’s something that’s worth noting. SPWeb has a number of properties that are language related: Language, Locale.LCID and if like me, you’d expect these to return the current language of the site. For example, if I’m in English it would return 1033, switch to French and it returns 1036, however that’s not the case. In both these examples they always return the default language and not the current language. In my case the default language is English so it always returns 1033 even though the UI is in French. When a user switches between languages then we need to get the information from the CurrentUICulture which is part of System.Globalization.CultureInfo, it’s this property that indicates when a user has switched languages.
What does this mean? If your code runs on multiple sites which only use a single language (for example, a French site, an English site, a Spanish site etc) then you should be able to get away with just using SPContext.Current.Web.Language and passing that through to the GetLocalizedString method, however if users within a site can alter their languages then you’ll need to use CurrentUICulture.
There’s also a couple of additional properties that might be helpful – SPWeb.IsMultlingual is a bool which funnily enough shows if multi-languages are supported and another property – SPWeb.SupportedUICultures which indicates which languages have been enabled for this site.
So that’s a brief look at one way in which we can use SharePoint resource files which makes providing localised text available through code. Like we saw with Feature resource files, even global SharePoint resource files can’t be used in every situation. In this example I set the label text programmatically, but realistically this is something I’d prefer to do in markup whilst still providing multi-lingual support and this is where our App_GlobalResources come into play… but more on that next time!