Roundedcube will be featuring Sitecore at the National Association of Government Webmasters (NAGW) to be held in St. Louis, MO from Sept. 22 – 24. We’re definitely excited for being part of the show because I think we definitely got something to show. One of the highlights will be our work for the City of Ogden, UT which was released last year (a Sitecore case study is also available if you want a copy).
One of our goals in the NAGW show is to feature how Sitecore’s capabilities match up with government sites’ needs and processes. This is not just in the technical point of view but also with its user-experience, deployment scenarios, maintenance, and multi-site/multi-language capabilities. I think these are some of the most important factors that government entities look for. So, let’s take a look at them one by on in summary form. This is by no means the complete list but I’m highlighting what government sites may be looking for.
Technical Capabilities
I can’t tell you everything about Sitecore here so go to sitecore.net to get more details but here’s a quick synopsis. It’s built on .NET (primarily ASP.NET). If you know .NET, then you should know that Sitecore takes advantage of .NET capabilities and enhance upon them such as provider model, reflection, XML/XSLT, and others. Programmatically, if you’re a C# or VB.NET shop, you’re good to go. Sitecore has a rich set of API from content creation, workflow invocation, security, to just about anything else you can do with .NET. It supports .NET 3.5 and up, so if you like lambda expressions, LINQ, entity framework, and other enhancements, go for it. One of the most complex systems we built with Sitecore was integrating JD Edwards on AS/400 through a SOA-based middle-tier using Web services as Sitecore integration points to expose customer-based pricing, product configuration, and others. In government sites, you could be talking about several disparate custom/off-the-shelf systems. Having a common platform to integrate them and manage them can be a key factor in realizing your ROI. So, in short, Sitecore is so open that you can do whatever you need to do in .NET. I consider it a development platform not just a CMS.
Multi-site/Multi-language Capabilities
If you’re looking into Sitecore to fire up your city site, then you might also consider using it for other sites. Sometimes, it’s hard to justify having a commercial product when open-source options are available. But, if you start thinking that you can have several sites on one instance of Sitecore, you can start lowering the cost/site. Even if you only have an Intranet, that’s using Sitecore twice. In Sitecore, you can create different security domains similar to Windows. That means, you can set up different domains and security access per site. There’s also the UI, Sitecore uses the Windows Explorer paradigm for traversing your Website. That means that you can make your Website root nodes be like your C and D drives. Of course, everything else in Sitecore can be multi-site aware and group content, workflow, media files, users/roles, and others together. You can also share them between each site if you need to. If you really need more advanced multi-site capabilities, consider looking into Sitecore Foundry which is built on top of Sitecore CMS.
Some government sites have multi-language needs. Sitecore’s architecture accommodates basically any languages. You can either have a per-content translation if all your site requirement is that the site have a language translation. Or, you can combine Sitecore multi-site and multi-language capabilities to have a very flexible content-managed site. For instance, you have an English-based site but also want a Spanish translated version of the site but not the entire site. So, you can create another site and have Spanish be its default language. Remember that a content’s language can be versioned as well. This means that your English version can be in version 5 while your Spanish version can still be in version 3. Not the same version has to be published at the same time.
User-Experience
I quickly mentioned earlier that Sitecore uses Windows Explorer paradigm. That’s just for the Content Editor (which is a built-in Sitecore app). Sitecore has several user interfaces (UI) but its main one mimics your Window desktop. This means that a Sitecore app runs inside a Sitecore window. Can you say multi-tasking?
The coolest feature is obviously the Page Editor which allows you to update your site within the site’s design. It’s old news of course, but just remember that a Sitecore solution should have content reusability. This means that if you update content such as a news item’s title on the news listing page, then it better be updated in the related news areas or even on the news details page without anymore than saving and publishing the content. Other CMS systems unfortunately do not have the level of content/design separation that Sitecore has so even if they have the in-page editing capability, it doesn’t necessarily mean that it’s easy to update content.
Sitecore also has UIs for designers, developers, and administrators in addition to typical author/reviewer/publisher UIs. This makes the Windows paradigm much more effective. If it’s worth it, imagine creating your own Sitecore apps to manage external systems or data. This gives everyone a single point of site administration…all browser-based.
Deployment Scenarios
City/town/county sites are normally on a one-server deployment scenario. That’s why hosted CMS solutions are one of the more popular commodities out there for government. But there are those that would like to consolidate systems together and when you do that, you sometimes need in-house servers. And if you have in-house servers, security and performance become factors to consider. Sitecore can accommodate separate function-specific servers such as an authoring, publishing, and delivery server. You can cluster these servers when needed. Since Sitecore uses your database (SQL Server or Oracle), it’ll run on whatever clustering you have on those. Sitecore can even run on Azure (cloud-processing/computing available from Microsoft) but I’m sure it can maybe even run on your own cloud if you have one. Obviously, clusters and separation of roles contribute to the overall performance of the system. It also contributes to the solution’s security since now each layer (or environment) can be protected in different levels. You can put your delivery servers outside your firewall while keep the authoring server internally.
For disaster recovery (DR), you can have your load-balancer control that if you like. You can have Sitecore publish to a DR server at the same time the delivery servers are updated. So, when the regular servers go down, the DR server can kick in immediately. Or, you can use the DR server in a load-balanced environment to help performance. Yes, it sounds easy because it is.
If you have only one server, then you can still separate the server roles if desired because remember, Sitecore is built on top of ASP.NET which makes it just another ASP.NET application. So, you can have multiple instances of it in one server (or virtualized if you like). Just make sure to talk to your Sitecore rep on what this entails in terms of licensing.
Anyway, Sitecore’s deployment capabilities is one of the factors that I consider it as an enterprise-ready CMS but flexible enough in a one-server environment.
Maintenance
Government sites normally means a limited IT staff, even less when it comes to the Web site. So, having a CMS that make administration easy should be on top of the requirement needs. With Sitecore’s UIs, all the day-to-day site operations are readily available such as security.
There was a question on LinkedIn regarding Sitecore maintenance on the type of staff member that should be an administrator. Basically, I recommended a technical person who has experience with security, audits, applications, and other technical stuff. I added that separating Webmaster roles from site admin can sometimes be crucial but if that’s not possible, then you need to have both the marketing and technical skills to administer Sitecore. The CMS addresses both the marketing and IT responsibilities when it comes to Web sites.
In terms of the Sitecore’s performance and availability, remember that since this is built on ASP.NET, it’s just an ASP.NET application. There are no additional server components that are installed on the server(s). This means that you should plan the same way you would with another ASP.NET application.
Bottom line though, the administrator should attend a Sitecore Administration training and see how easy it is.
Summary
Government sites pose a different level of challenges for Sitecore such as budget, staff, and processes. At first glance, Sitecore can be extravagant if you consider open-source or hosted alternatives, but if you consider the above factors, you may be able to determine how to maximize your ROI. I know our clients have.
*EDIT October 28, 2010. We have moved our blog to http://blog.roundedcube.com and you can now comment on this specific post at http://www.roundedcube.com/WhatsNew/Blog/sitecore-for-president
Showing posts with label globalization. Show all posts
Showing posts with label globalization. Show all posts
Wednesday, September 22, 2010
Thursday, August 12, 2010
Tackling Fallback Fields and Values in Sitecore
I recently had the opportunity to fight with …. Err … learn about globalization within Sitecore. If you don’t know what Globalization is within Sitecore, then you are reading the right article, because your knowledge on the subject is the same as mine was when I first started working with it. I almost viewed it as the scary monster under my bed, about to tear my feet off the moment the light goes out. But, trudging forward and facing my fears, I pressed on and the outcome was quite surprising. I actually had a lot of fun once I got around some of the major obstacles in my way, the largest and most pronounced being my very own lack of knowledge on this specific subject. So, after beating my head against the wall, sweating profusely for days at a time, and finally consulting an oracle (he looked kind of like a homeless person to me, but I took his word for it) here is what I have found out about Globalization within Sitecore.
Before I begin, let me preface this with the following statement: this post is not an end-all be-all for globalization, just information I happen to remember and care to relate from my experiences. It also only deals with globalization within the context of Sitecore. Good, now that we got that out of the way, we can continue….
As you may or may not know, globalization is just a fancy pants way to say multi-lingual, which is an even more fancy way to say multiple languages. So, if you want multiple languages to display on your site, then you are going to have to use some form of globalization. For the purposes of this post, let us assume that we are dealing with English as your main language and Bangladeshi (just because I like the way it sounds….. Bangladeshi ) as your secondary language.
In order to create a user-friendly website that caters to both of your demographic groups, we need some form of language switching on the site. Putting a dropdown at the top of your site is easy enough. In this example, we are setting our language embedding to “always”, so the URL of the current page also defines the language context being used. We do this with the following line in the web.config:
<linkManager defaultProvider="sitecore">
<providers>
<clear />
<add name="sitecore" type="Sitecore.Links.LinkProvider, Sitecore.Kernel" addAspxExtension="true" alwaysIncludeServerUrl="false" encodeNames="true" languageEmbedding="always" languageLocation="filePath" shortenUrls="true" useDisplayName="false" />
</providers>
</linkManager>
Now when you navigate to a page within Sitecore, you should see something like this: http://www.yoursite.com/en/ItemName.aspx for the English version or http://www.yoursite.com/bgd/ItemName.aspx for the Bangladeshi version.
Create a Bangladeshi versions of “ItemName”, fill it with content, publish, and BLAMO, Bangladeshi content for all to see. Easy enough, right? Yay for out of the box functionality! And for most websites this is all that will ever be required. But let’s get our knees dirty and dig in a bit deeper.
Say we want to fall back to the English version of the page if the Bangladeshi version doesn’t exist. All we do is write a custom pipeline process that will determine if the item exists in the current language, and if it doesn’t, send the user to the /en/ version of the page. This is pretty basic stuff. Here is a quick overview on how to do that if you are interested:
Update web.config with your custom pipeline process. Make sure it’s in the correct location…
<processor type="Sitecore.Pipelines.HttpRequest.ItemResolver, Sitecore.Kernel" />
<processor type="YourAssemblyHere.Pipelines.HttpRequest.FallbackLanguageProcessor, YourAssemblyHere " />
<processor type="Sitecore.Pipelines.HttpRequest.LayoutResolver, Sitecore.Kernel" />
And add the corresponding class to your project…
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace YourAssemblyHere.Pipelines.HttpRequest
{
public class FallbackLanguageProcessor
{
public void Process(Sitecore.Pipelines.HttpRequest.HttpRequestArgs args)
{
Sitecore.Data.Items.Item contextItem = Sitecore.Context.Item;
if (contextItem == null || contextItem.Versions.Count > 0)
return;
Sitecore.Globalization.Language language = Sitecore.Context.Language;
if (Sitecore.Context.Language.Name != "en")
language = Sitecore.Globalization.Language.Parse("en");
Sitecore.Data.Database contextDatabase = Sitecore.Context.Database;
Sitecore.Context.Item = contextDatabase.GetItem(Sitecore.Context.Item.ID, language);
}
}
}
As you can see, all this does is determine if the current item does NOT have a version (so you are trying to view a Bangladeshi page but it doesn’t exist), get the English version of this page, reset the context, and you are on your merry way. Weeeeeeeeee, isn’t this fun!?!
By this time in the project, I was feeling pretty good about my accomplishments and up to this point wasn’t getting tripped up too much. But alas, a new requirement came down from above: let’s make each FIELD fall back to English if there is no value within the Bangladeshi version. This means that if I go to the About Us page, and I’m in the Bangladeshi context, and there is no About Us page within Sitecore for the Bangladeshi item then I need to display the English version of that page without changing the context of the site! I know, I get a migraine just thinking about it.
Before I continue, I must give you fellow Globalization newbie’s a bit of advice… If you can help it, NEVER display multiple languages to the user on the same page. Not only does this create confusion for the user, it is rather pointless. If the user doesn’t understand English, then why would they ever care to see it on your website? Once you start mixing and matching languages on the same page the context of the site gets confusing for the user. They see content that is in their native language, but the navigation links (some or all of them) are in some foreign language (English in this case). But what the heck right? Let’s see just how extensible Sitecore really is (I love trying to break stuff!).
The process is similar to what we did earlier. We need to add a process to the “renderField” pipeline section of the web.config like this…
<processor type="Sitecore.Pipelines.RenderField.GetDateFieldValue, Sitecore.Kernel" />
<processor type="YourAssemblyHere.Pipelines.FieldRender.FallbackLanguageProcessor, YourAssemblyHere" />
<processor type="Sitecore.Pipelines.RenderField.AddBeforeAndAfterValues, Sitecore.Kernel" />
And add another class that handles this process like so…
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Sitecore.Pipelines.RenderField;
namespace YourAssemblyHere.Pipelines.FieldRender
{
public class FallbackLanguageProcessor
{
public void Process(RenderFieldArgs args)
{
//only perform this logic if this is not the default language
if (Sitecore.Context.Language.Name != "en")
{
if (args.Item != null)
{
//Get the current Item passed in by the arguments
Sitecore.Data.Items.Item currentItem = args.Item;
if (currentItem != null)
{
if (currentItem.Fields[args.FieldName] != null)
{
//if the current item has no valid value
if (currentItem.Fields[args.FieldName].Value.Equals("$name") ||
(currentItem.Fields[args.FieldName].Value.Equals(string.Empty)))
{
//Determine the fallback language for this item. in this case, we are forcing english.
Sitecore.Globalization.Language language = Sitecore.Globalization.Language.Parse("en");
//get the item in the default language
Sitecore.Data.Items.Item newItem = Sitecore.Context.Database.GetItem(currentItem.ID, language);
if (newItem != null)
{
//only make the update if the english field has a value
if (newItem.Fields[args.FieldName] != null)
if (!string.IsNullOrEmpty(newItem.Fields[args.FieldName].Value))
args.Result.FirstPart = newItem.Fields[args.FieldName].Value;
//disable web edit for this field, since it’s a fallback field editors should not be able to edit
args.DisableWebEditContentEditing = true;
}
}
}
}
}
}
}
}
}
Seems easy enough! Now, like before, our process will tick off and check to see if the FIELD that is trying to be displayed exist in Bangladeshi, and if not, go get the English value for that field and display that instead. Quick note: if you are accustomed to using sc:fld(‘Title’,.) in your xslt renderings, then those values don’t go through the fieldRender pipeline. You must use sc:field(‘Title’,.) in order for our custom process to have any effect. This specific issue causes grey hair apparently, so take heed! Just make sure your outputting your xslt value-of’s with sc:field. If you are using <sc:text, etc, then it should work fine.
Now, we have our FIELDS displaying English if the Bangladeshi field doesn’t have a value (this is mostly due to lazy or “too-busy-to-get-to-it” content editors ). So, here is where we currently are at. We are on the Bangladeshi site, looking at the About Us page. The top navigation is displaying either English or Bangladeshi links, depending on if that value exists in Sitecore, and all is good in the world.
“What about non-“fieldRender” pipeline values that are grabbed programmatically?” you say. Alright, let’s explore that. One example of why it is important to be able to get a fallback for a specific field programmatically is when you are setting the text property of a label to a field of an item.
So, pretend that on the Page_Load method we set a <asp: Label’s “Text” property to the Title field of the current item. We have to check to see if the item exists in Bangladeshi first, and if it doesn’t, then get the English version of the item and then display the title. Here is how to do that.
public static bool HasContextLanguage(Item item)
{
Item latestVersion = item.Versions.GetLatestVersion();
return ((latestVersion != null) && (latestVersion.Versions.Count > 0));
}
As you can see, pass it the item you want to check and it will return a “true” if the item exist within Bangladeshi (assuming you are within the Bangladeshi context), and “false” if it does not. You will use this method to see if you need to perform some additional logic, like grabbing an English version of the item and displaying the Title. Your Page_Load method might look a little something like this….
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
Item currentItem = Sitecore.Context.CurrentItem;
if (!HasContextLanguage(currentItem))
currentItem = currentItem.Versions.GetLatestVersion(Sitecore.Globalization.Language.Parse("en"));
lblTitle.Text = currentItem.Fields["Title"].Value;
}
}
The last thing I want to go over is quite a bit more complex that what has been covered so far, so I apologize in advance for the mass confusion you are about to read and my general lack of ability to convey something in a more precise manner. It has to do with a fallback field on a fallback item that is a referenced target item of the current item. All that alludes to is how we handle globalization on referenced items within Sitecore (lookup fields, reference fields, multi-select fields, etc).
For example, imagine you have a “Page” Template with a lookup field called “Contact”. This “Contact” field will reference an item based on a “Contact” template that has the following fields: Name, Title, Company, Phone Number, and Address. Assume that the page and the contact are already created within Sitecore, but only in English. Along comes the Bangladeshi content editor and they add a Bangladeshi version to the page. While entering in content for the page, they select the English-only contact (we will call him “Bob” for now) and publish the item. We have to take a few things into consideration when trying to output Bob’s information.
When someone goes to the page and is in the Bangladeshi context, how do we display Bob correctly? Normally you get the TargetItem of the Contact field and display the name. In this case, it’s not so simple. You have to remember that Bob doesn’t exist within the Bangladeshi context. So first we have to get the Target item, and then do our check to see if it (Bob) exists in the current context and if not, get the English version of Bob to display. Here is how we would go about that:
Sitecore.Data.Fields.LookupField lookupField = item.Fields["Contact"];
if (lookupField != null && lookupField.TargetItem != null)
{
Item targetItem = lookupField.TargetItem;
if (!HasContextLanguage(targetItem))
targetItem = targetItem.Versions.GetLatestVersion(Sitecore.Globalization.Language.Parse("en"));
//Do Stuff with Bob here....
}
This logic is getting the “Contact” lookup field, getting its “TargetItem”(Bob), checking to see if the TargetItem exist within the current context, and if not, re-getting the target item as the English version, and then displaying the information as necessary.
I hope this all makes sense, I know I babble on and on and on and on a ….err, heh. Oh, and even after typing it 18,976 times, I still like the word “Bangladeshi”. Congratulations, you are at the end of my ranting and can go on with your lives. I hope you have learned something of value. Happy globalization!
Thanks – Caleb Miller.
*EDIT October 28, 2010. We have moved our blog to http://blog.roundedcube.com and you can now comment on this specific post at http://www.roundedcube.com/WhatsNew/Blog/tackling-fallback-fields-and-values-in-sitecore
Before I begin, let me preface this with the following statement: this post is not an end-all be-all for globalization, just information I happen to remember and care to relate from my experiences. It also only deals with globalization within the context of Sitecore. Good, now that we got that out of the way, we can continue….
As you may or may not know, globalization is just a fancy pants way to say multi-lingual, which is an even more fancy way to say multiple languages. So, if you want multiple languages to display on your site, then you are going to have to use some form of globalization. For the purposes of this post, let us assume that we are dealing with English as your main language and Bangladeshi (just because I like the way it sounds….. Bangladeshi ) as your secondary language.
In order to create a user-friendly website that caters to both of your demographic groups, we need some form of language switching on the site. Putting a dropdown at the top of your site is easy enough. In this example, we are setting our language embedding to “always”, so the URL of the current page also defines the language context being used. We do this with the following line in the web.config:
<linkManager defaultProvider="sitecore">
<providers>
<clear />
<add name="sitecore" type="Sitecore.Links.LinkProvider, Sitecore.Kernel" addAspxExtension="true" alwaysIncludeServerUrl="false" encodeNames="true" languageEmbedding="always" languageLocation="filePath" shortenUrls="true" useDisplayName="false" />
</providers>
</linkManager>
Now when you navigate to a page within Sitecore, you should see something like this: http://www.yoursite.com/en/ItemName.aspx for the English version or http://www.yoursite.com/bgd/ItemName.aspx for the Bangladeshi version.
Create a Bangladeshi versions of “ItemName”, fill it with content, publish, and BLAMO, Bangladeshi content for all to see. Easy enough, right? Yay for out of the box functionality! And for most websites this is all that will ever be required. But let’s get our knees dirty and dig in a bit deeper.
Say we want to fall back to the English version of the page if the Bangladeshi version doesn’t exist. All we do is write a custom pipeline process that will determine if the item exists in the current language, and if it doesn’t, send the user to the /en/ version of the page. This is pretty basic stuff. Here is a quick overview on how to do that if you are interested:
Update web.config with your custom pipeline process. Make sure it’s in the correct location…
<processor type="Sitecore.Pipelines.HttpRequest.ItemResolver, Sitecore.Kernel" />
<processor type="YourAssemblyHere.Pipelines.HttpRequest.FallbackLanguageProcessor, YourAssemblyHere " />
<processor type="Sitecore.Pipelines.HttpRequest.LayoutResolver, Sitecore.Kernel" />
And add the corresponding class to your project…
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace YourAssemblyHere.Pipelines.HttpRequest
{
public class FallbackLanguageProcessor
{
public void Process(Sitecore.Pipelines.HttpRequest.HttpRequestArgs args)
{
Sitecore.Data.Items.Item contextItem = Sitecore.Context.Item;
if (contextItem == null || contextItem.Versions.Count > 0)
return;
Sitecore.Globalization.Language language = Sitecore.Context.Language;
if (Sitecore.Context.Language.Name != "en")
language = Sitecore.Globalization.Language.Parse("en");
Sitecore.Data.Database contextDatabase = Sitecore.Context.Database;
Sitecore.Context.Item = contextDatabase.GetItem(Sitecore.Context.Item.ID, language);
}
}
}
As you can see, all this does is determine if the current item does NOT have a version (so you are trying to view a Bangladeshi page but it doesn’t exist), get the English version of this page, reset the context, and you are on your merry way. Weeeeeeeeee, isn’t this fun!?!
By this time in the project, I was feeling pretty good about my accomplishments and up to this point wasn’t getting tripped up too much. But alas, a new requirement came down from above: let’s make each FIELD fall back to English if there is no value within the Bangladeshi version. This means that if I go to the About Us page, and I’m in the Bangladeshi context, and there is no About Us page within Sitecore for the Bangladeshi item then I need to display the English version of that page without changing the context of the site! I know, I get a migraine just thinking about it.
Before I continue, I must give you fellow Globalization newbie’s a bit of advice… If you can help it, NEVER display multiple languages to the user on the same page. Not only does this create confusion for the user, it is rather pointless. If the user doesn’t understand English, then why would they ever care to see it on your website? Once you start mixing and matching languages on the same page the context of the site gets confusing for the user. They see content that is in their native language, but the navigation links (some or all of them) are in some foreign language (English in this case). But what the heck right? Let’s see just how extensible Sitecore really is (I love trying to break stuff!).
The process is similar to what we did earlier. We need to add a process to the “renderField” pipeline section of the web.config like this…
<processor type="Sitecore.Pipelines.RenderField.GetDateFieldValue, Sitecore.Kernel" />
<processor type="YourAssemblyHere.Pipelines.FieldRender.FallbackLanguageProcessor, YourAssemblyHere" />
<processor type="Sitecore.Pipelines.RenderField.AddBeforeAndAfterValues, Sitecore.Kernel" />
And add another class that handles this process like so…
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Sitecore.Pipelines.RenderField;
namespace YourAssemblyHere.Pipelines.FieldRender
{
public class FallbackLanguageProcessor
{
public void Process(RenderFieldArgs args)
{
//only perform this logic if this is not the default language
if (Sitecore.Context.Language.Name != "en")
{
if (args.Item != null)
{
//Get the current Item passed in by the arguments
Sitecore.Data.Items.Item currentItem = args.Item;
if (currentItem != null)
{
if (currentItem.Fields[args.FieldName] != null)
{
//if the current item has no valid value
if (currentItem.Fields[args.FieldName].Value.Equals("$name") ||
(currentItem.Fields[args.FieldName].Value.Equals(string.Empty)))
{
//Determine the fallback language for this item. in this case, we are forcing english.
Sitecore.Globalization.Language language = Sitecore.Globalization.Language.Parse("en");
//get the item in the default language
Sitecore.Data.Items.Item newItem = Sitecore.Context.Database.GetItem(currentItem.ID, language);
if (newItem != null)
{
//only make the update if the english field has a value
if (newItem.Fields[args.FieldName] != null)
if (!string.IsNullOrEmpty(newItem.Fields[args.FieldName].Value))
args.Result.FirstPart = newItem.Fields[args.FieldName].Value;
//disable web edit for this field, since it’s a fallback field editors should not be able to edit
args.DisableWebEditContentEditing = true;
}
}
}
}
}
}
}
}
}
Seems easy enough! Now, like before, our process will tick off and check to see if the FIELD that is trying to be displayed exist in Bangladeshi, and if not, go get the English value for that field and display that instead. Quick note: if you are accustomed to using sc:fld(‘Title’,.) in your xslt renderings, then those values don’t go through the fieldRender pipeline. You must use sc:field(‘Title’,.) in order for our custom process to have any effect. This specific issue causes grey hair apparently, so take heed! Just make sure your outputting your xslt value-of’s with sc:field. If you are using <sc:text, etc, then it should work fine.
Now, we have our FIELDS displaying English if the Bangladeshi field doesn’t have a value (this is mostly due to lazy or “too-busy-to-get-to-it” content editors ). So, here is where we currently are at. We are on the Bangladeshi site, looking at the About Us page. The top navigation is displaying either English or Bangladeshi links, depending on if that value exists in Sitecore, and all is good in the world.
“What about non-“fieldRender” pipeline values that are grabbed programmatically?” you say. Alright, let’s explore that. One example of why it is important to be able to get a fallback for a specific field programmatically is when you are setting the text property of a label to a field of an item.
So, pretend that on the Page_Load method we set a <asp: Label’s “Text” property to the Title field of the current item. We have to check to see if the item exists in Bangladeshi first, and if it doesn’t, then get the English version of the item and then display the title. Here is how to do that.
public static bool HasContextLanguage(Item item)
{
Item latestVersion = item.Versions.GetLatestVersion();
return ((latestVersion != null) && (latestVersion.Versions.Count > 0));
}
As you can see, pass it the item you want to check and it will return a “true” if the item exist within Bangladeshi (assuming you are within the Bangladeshi context), and “false” if it does not. You will use this method to see if you need to perform some additional logic, like grabbing an English version of the item and displaying the Title. Your Page_Load method might look a little something like this….
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
Item currentItem = Sitecore.Context.CurrentItem;
if (!HasContextLanguage(currentItem))
currentItem = currentItem.Versions.GetLatestVersion(Sitecore.Globalization.Language.Parse("en"));
lblTitle.Text = currentItem.Fields["Title"].Value;
}
}
The last thing I want to go over is quite a bit more complex that what has been covered so far, so I apologize in advance for the mass confusion you are about to read and my general lack of ability to convey something in a more precise manner. It has to do with a fallback field on a fallback item that is a referenced target item of the current item. All that alludes to is how we handle globalization on referenced items within Sitecore (lookup fields, reference fields, multi-select fields, etc).
For example, imagine you have a “Page” Template with a lookup field called “Contact”. This “Contact” field will reference an item based on a “Contact” template that has the following fields: Name, Title, Company, Phone Number, and Address. Assume that the page and the contact are already created within Sitecore, but only in English. Along comes the Bangladeshi content editor and they add a Bangladeshi version to the page. While entering in content for the page, they select the English-only contact (we will call him “Bob” for now) and publish the item. We have to take a few things into consideration when trying to output Bob’s information.
When someone goes to the page and is in the Bangladeshi context, how do we display Bob correctly? Normally you get the TargetItem of the Contact field and display the name. In this case, it’s not so simple. You have to remember that Bob doesn’t exist within the Bangladeshi context. So first we have to get the Target item, and then do our check to see if it (Bob) exists in the current context and if not, get the English version of Bob to display. Here is how we would go about that:
Sitecore.Data.Fields.LookupField lookupField = item.Fields["Contact"];
if (lookupField != null && lookupField.TargetItem != null)
{
Item targetItem = lookupField.TargetItem;
if (!HasContextLanguage(targetItem))
targetItem = targetItem.Versions.GetLatestVersion(Sitecore.Globalization.Language.Parse("en"));
//Do Stuff with Bob here....
}
This logic is getting the “Contact” lookup field, getting its “TargetItem”(Bob), checking to see if the TargetItem exist within the current context, and if not, re-getting the target item as the English version, and then displaying the information as necessary.
I hope this all makes sense, I know I babble on and on and on and on a ….err, heh. Oh, and even after typing it 18,976 times, I still like the word “Bangladeshi”. Congratulations, you are at the end of my ranting and can go on with your lives. I hope you have learned something of value. Happy globalization!
Thanks – Caleb Miller.
*EDIT October 28, 2010. We have moved our blog to http://blog.roundedcube.com and you can now comment on this specific post at http://www.roundedcube.com/WhatsNew/Blog/tackling-fallback-fields-and-values-in-sitecore
Subscribe to:
Posts (Atom)