We have a multilingual site where we needed to do the same thing to set up our hreflang tags. There might be a better way, but I decided on building some Xpath to find out if a matching node exists in the other languages. We are using umbraco 7, and I would shy away from using NodeFactory if at all possible. It is depreciated. Using the umbraco helper won't hit the database, and is one of the best ways to query published content or media from umbraco for umbraco 7.
public static IPublishedContent GetLocalizedVersionOfPage(this IPublishedContent node, string regionName)
{
var umbracoHelper = new UmbracoHelper(UmbracoContext.Current);
var ancestorNames = node.AncestorsOrSelf()
.Where(n => n.Level > 1)
.OrderBy(n => n.Level)
.Select(n => n.Name).ToList();
var xpath = new StringBuilder();
xpath.AppendFormat("/root/HomePage[@nodeName='{0}']", regionName);
foreach (var ancestorName in ancestorNames)
{
xpath.AppendFormat("/*[@nodeName='{0}']", ancestorName);
}
var matchingNode = umbracoHelper.TypedContentAtXPath(xpath.ToString()).FirstOrDefault();
return matchingNode;
}
The above method is an extension method on the IPublishedContent. It allows you to pass in the region and it checks to see if a node with the same path determined by node name exists in the specified region. I thought about using the urlname instead of the node name. You could do that as well and maybe even make this faster by skipping the piece of code that does the .AncestorsOrSelf()
. It just depends on how you want it to work. In my case, I wanted it to find a match based on the node name even if the url path was different, so I had to do the .AncestorsOrSelf()
. Hope this helps.
Another thing to consider is how you call this method. if you use a loop like this:
@foreach (var region in Umbraco.TypedContentAtRoot().Where(n => n.IsDocumentType("HomePage")))
{
var localizedVersion = currentPage.GetLocalizedVersionOfPage(region.Name);
if (localizedVersion != null)
{
<link rel="alternate" href="@localizedVersion.UrlAbsolute()" hreflang="@LocalizeUtils.GetCulture(region.Name)" />
}
}
You will end up getting the ancestors of the current node over and over once for each region because it calls .AncestorsOrSelf()
every time you call GetLocalizedVersionOfPage()
. It probably makes sense to refactor the GetLocalizedVersionOfPage
method so you only have to call .AncestorsOrSelf
once. If you do this sort of thing too many times, it starts to affect performance (especially if your site is very nested).