We've come to the final post in my blog series on Language Fallback and using Alex Shyba's Partial Language Fallback Module.
In my previous posts, I've gone over strategy for multilingual sites with language fallback, instructions on how to install and configure the Partial Language Fallback Module, using the module to Enforce Language Version Presence and when to do so, customizations that can be made involving that Enforcement, using fallback with the Sitecore Dictionary, using fallback with Advanced Database Crawler, defaulting language version creation for fallback, the Language Migration Tool, and the Language Fallback Report Tool.
Now I'd like to discuss a few other things to consider during implementation, including references to other blogs and tools that will definitely aid you in finishing your multilingual and multi-cultural solution.
i.LinkManager attributes for languageEmbedding and useDisplayName:
<add name="sitecore" type="Sitecore.Links.LinkProvider, Sitecore.Kernel" addAspxExtension="false" alwaysIncludeServerUrl="false" encodeNames="true" languageEmbedding="always" languageLocation="filePath" lowercaseUrls="true" shortenUrls="true" useDisplayName="true" />
addAspxExtension="false" alwaysIncludeServerUrl="false" encodeNames="true" languageEmbedding="always"
languageLocation="filePath" lowercaseUrls="true" shortenUrls="true" useDisplayName="true" />
<!-- MEDIA - UPLOAD AS VERSIONABLE AS DEFAULT
This setting controls if uploaded media is versionable by default or not.
<setting name="Media.UploadAsVersionableByDefault" value="false" />
<patch:attribute name="type">Verndale.SharedSource.SitecoreProviders.CustomMediaProvider, Verndale.SharedSource</patch:attribute>
iii.Determining Sitecore Context Language
· A few years ago, John West wrote a blog post about overriding Sitecore's logic for figuring out the context language through which the user is viewing the site.
<!-- Custom pipeline processor that will set the .net culture based on the current sitecore context language -->
<processor patch:after="*[@type='Verndale.SharedSource.SitecoreProcessors.ItemLanguageValidation, Verndale.SharedSource']" type="Verndale.SharedSource.SitecoreProcessors.CultureResolver, Verndale.SharedSource" />
System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture(Sitecore.Context.Language.Name);
iv.Other Cultural Considerations
· As mentioned above, the current culture through which .NET is displaying things such as date is important to consider. You could set it in a processor during httpBeginRequest pipeline. Or you could set it at the time the user selects the language or when language is loaded from a cookie. Regardless, you would set it with the above code.
· If you don't set it at this global level, you would have to pass in a CultureInfo object for the specific language whenever you are working with something that could differ based on culture (string methods, date methods, currency methods, etc).
System.Globalization.CultureInfo ci = new System.Globalization.CultureInfo(Sitecore.Context.Language.Name));
DateTime dt = DateTime.Parse(date, ci);
System.Globalization.CultureInfo CultureInfo ci = new CultureInfo(Sitecore.Context.Language.Name));
v.Unsharing the Layout fields
· By default, the Layout fields, such as Renderings, are 'Shared' fields. This means that whatever it is set to in any language or version number is shared across all languages, and presentation cannot be changed based on language version. You can use conditional rendering and personalization to change out datasources of sublayouts on the page and change visibility of the sublayouts, but otherwise, you are pretty much committed to having the same presentation across languages.
· Although I personally have not done this before, you can un-share the Layout fields. Jan Hebnes discusses doing so for a project here and it is worth reading when considering this strategy:
· There are pros and cons to doing this and extra customization work that you must put in place. I have also read that some unexpected results can occur when using fallback with these fields, so be forewarned!
vi.Conditional Rendering and Personalization by Language
· A simpler, less intrusive alternative to unsharing the Layout fields is to setup some rules that can be used in conditional rendering.
· First, add a Rule in the Personalization section of the Marketing Center.
vii.Security For Languages
· There is most likely going to be a need for different content authors to have different access writes to different languages. It could be that an author in Germany will need to be able to go in and view/translate only the German version of all the pages. For this reason, Sitecore has two additional permissions that can be set when you are on a language item (in /sitecore/system/languages): Language Read and Language Write. You could create a German Editor Role that only has access to the German language. Give that role to anyone who will be editing German content only.
viii.Translating Content and Tools to help
· The whole point of a multilingual site is to have content in other languages. Content authors could supply their English content to a professional translating service, receive back the content and then manually enter it. They could have translators on staff who log into sitecore and update the content. But there are also some tools that integrate seamlessly into Sitecore to aid with this.
· Per the above link: "You can select one item or all your content and send it out to any translation provider or technology (like Google Translate) instantly. More importantly, translated content is automatically returned into the correct locations in Sitecore, saving more time."
· This is the Sitecore recommended solution and was co-developed with Sitecore. It is not free, however.
· We recently integrated a client with this and it went well.
· My colleague Julie Moynihan had this to say about it: Clay tablet is a Sitecore integrated module that provides the ability to send items to an external system/ vendor for translation. Translation can be batched and multiple types of translation (machine, human) or multiple vendors. The items are placed into a workflow and sent through the Clay tablet system to the translation vendor. Clay tablet works with the translation vendor regarding integration with their software. Items are then returned through Sitecore and placed back into workflow.
· I haven't used this myself, however it seems pretty cool. It leverages the Google translate functionality. The content author will click a button and it will translate the content. Granted, Google translate is not perfect, but it could be a good starting point (and it's free).
ix.Custom Language Registration
· My coworker Summit Phadke recommended that I include the following information since he had to implement this for one of our clients as well.
· When you add a new language to Sitecore, in /sitcore/system/language, it allows you to either choose from a pre-defined language culture, or you can enter your own. If you decide to enter your own, you can specify the code for Language and optionally a code for Culture
· At this point you decide you want a language specifically for German in the United State, so you enter 'de' and 'US' in the language and Culture code fields.
· You submit and are presented with a message telling you that it is not a valid option
Link to Resources:
Hi Elizabeth, first of all, thank you for this very helpful post. But in my opinion, one detail is missing in a multilingual solution. Above you described two important config changes: languageEmbedding="always" and useDisplayName="true" With these attributes, we are able to create language specific url's like <host>/en-us/company or <host>/es-es/empresa With Alex Shyba's FallbackProvider, it is possible to render pages with no content, if they have a fallback to a language with content, e.g. /en-ca has a fallback to /en-us. Now, the attribute "useDisplayNames" will not be used, because en-ca has no value in "__DisplayName"-field and the fallback of en-us is not used. This ends up in different urls for /en-ca and /en-us. I hope, you understand my explanations. Do you have any idea, how to solve this issue? Thanks in advance and best regards Fabian
To be honest, we don't often use the Display Name, so although I would have thought theoretically it should function as expected, I can't speak to the specific issue. For sure if we run into an answer, I will post it here.