There is some strangeness surrounding the retrieval of quick launch links in SharePoint 2013 which may very well be a bug in SharePoint. Although we’re the first ones to admit we haven’t been let in on the exact reasoning behind SharePoint’s implementation of the quick launch title, and there may be very good reasoning behind it, we’re inclined to believe that this is another area where multi-language scenarios have been implemented sloppily in SharePoint 2013. In this article we discuss what the problem is and, better yet, how to solve it.
In principle, retrieving the link title of a quick link is easy. The next C# code uses the server-side OM to retrieve the title of every first link of every web site in a site collection.
string siteUrl = “[site collection URL]”;
using (var site = new SPSite(siteUrl))
{
foreach (SPWeb web in site.AllWebs)
{
string title = web.Navigation.QuickLaunch[0].Title;
}
}
There are situations when the Title does not contain the value you’d expect. There are 2 preconditions that need to be met to experience this strangeness (there may be more scenarios causing it, but we’re describing the one we’ve encountered):
- We’re editing the default first link of a new team site.
- The locale of the thread running the code is different from the default language of the SharePoint web site.
To clarify, let’s present an example that runs as expected, then followed by the example that does not behave as we expect.
Example 1: Expected Title
- Create a new team site and choose language “English”.
- Go to the Navigation link (so the Publishing features need to be enabled in order to do this) and edit the first link and change it’s title to “Test”. Do not change the URL!
- Run the code and verify that web.Navigation.QuickLaunch[0].Title indeed returns the value of “Test”, the same value as seen via the UI in the quick launch bar.
Example 2: Unexpected Title
- Create a new team site and choose language “Dutch” (or some other language as long as its not English).
- Go to the Navigation link (so the Publishing features need to be enabled in order to do this) and edit the first link and change it’s title to “Test”. Do not change the URL as this will ensure the Title functionality to function correctly!
- Run the code and verify that web.Navigation.QuickLaunch[0].Title does not return the value of “Test”, but instead returns “Home”, even when the quick launch bar itself displays the link title “Test” correctly.
Inspecting the implementation of the Title property in the Microsoft.SharePoint.Navigation.SPNavigationNode class sheds some light on this issue:
public string Title
{
get
{
if (System.Globalization.CultureInfo.CurrentUICulture.LCID == this.Navigation.Web.UICulture.LCID)
{
return this.m_strTitle;
}
return this.TitleResource.Value;
}
}
In our case our code was running under a thread with the LCID of 1033 (English – United States). As long as the default language of the SharePoint web site is set to English, this works fine and the member variable m_strTitle is returned containing the correct quick link title value of “Title”.
But, when the LCID of our thread is 1033 and the default language of the SharePoint web site is set to Dutch, we get this.TitleResource.Value which is “Home” and that is incorrect.
As a remedy, we can use reflection to retrieve the value of private member m_strTitle. In C#, this goes like this:
SPNavigationNode firstLink = web.Navigation.QuickLaunch[0];
FieldInfo fieldInfo = firstLink.GetType().GetField(“m_strTitle”, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
string realLinkTitle = fieldInfo.GetValue(firstLink).ToString();
In PowerShell, the same feat goes like this:
$site = Get-SPSite $siteUrl
foreach ($web in $site.AllWebs)
{
$firstLink = $web.Navigation.QuickLaunch[0]
$fieldInfo = $firstLink.GetType().GetField(“m_strTitle”,
[Reflection.BindingFlags]::NonPublic
-bor [Reflection.BindingFlags]::Instance)
$actualLinkTitle = [string]$fieldInfo.GetValue($firstLink)
$web.Dispose()
}
$site.Dispose()
Now, regardless of the thread your code is running in, you get the actual link title instead of the resource value.