Thursday, September 17, 2020

SXA language selector in a multisite/multilanguage environment

Sitecore SXA multi-language + multi-site

We have an environment with a full blown SXA site in place, available in 4 languages. Language fallback is setup on item level, including some search engine enhancements to avoid duplicate content issues.

Next to this company site, a bunch of (mini) sites is being created. These sites (should) have nothing in common with the main site (they are in another tenant) but they do share almost everything between them. As they do live in the same environment however, they are also available in all 4 languages - and with the item language fallback those versions will always exist.

But.. those sites do not need to exist in all those languages. They could be in any subset of the available (4) languages of the Sitecore environment.


SXA language selector

We are using the ootb language selector component from SXA to handle our language switch. This works fine on the sites, but of course it will show all the available languages and we would like to limit the number of languages per site. One option is creating our own language selector - that would be easy but I thought there would be a way to tell the ootb component which languages to use. And yes, there is.

First step: add site settings

On the site item in SXA (found in the "Settings/Site Grouping" folder in your site tree) you can add (custom) properties. Normally the formsRoot should be there already (set by the script that generated the site). We add a custom property to define the languages we want on the site: the name is "siteLanguages" and in the example here I've set the value (language list) to "nl|fr" to allow Dutch and French. 

Note that the name and the format for the value are custom - chosen in favor of the implementation.

Setting a default language is an ootb feature of SXA but note that if you do not have English in the list of allowed languages, you should (must) set a default language in the Language field in that same site definition item. 


Step two: a new LanguageSelectorRepository

The Language selector component gets its values from the Sitecore.XA.Feature.Context.Repositories.LanguageSelector.LanguageSelectorRepository which implements an interface ILanguageSelectorRepository. We need to create a new version of this repository and override the GetLangItems function:
public class LanguageSelectorRepository : Sitecore.XA.Feature.Context.Repositories.LanguageSelector.LanguageSelectorRepository, ILanguageSelectorRepository
{
  protected override IEnumerable<Item> GetLangItems(Item item)
  {
    var languageItems = base.GetLangItems(item);
    var languages = Sitecore.Context.Site.Properties["siteLanguages"];
    if (string.IsNullOrEmpty(languages))
    {
      return languageItems;
    }
    
    var siteLanguages = languages.Split(new[] { "|" }, StringSplitOptions.RemoveEmptyEntries);
    if (!siteLanguages.Any())
    {
      return languageItems;
    }

    return languageItems.Where(i => siteLanguages.Contains(i.Language.Name));
  }
}
As you can see we first use the existing (base) function to determine all the possible languages (the ootb implementation here is based on the existing language versions of the current item). We also fetch the siteLanguages property from the current Site. If we detect that this property is set we will filter the list of languages based on the set from the properties. 

It's a pretty simple example of extending this logic - you can do anything you want/need here of course.

Final step

As a final but easy step, use your dependency injection framework and register your LanguageSelectorRepository as the implementation of the ILanguageSelectorRepository interface.


Conclusion

Extending SXA is usually quite easy. That was not different in this case. We can still use the ootb component and only adapted the logic for fetching the data, which saved us time obviously.

However we did only adjust the data logic for the language selector component. We did not put anything in place to prevent viewing pages in the languages that we don't really want. That is out of scope for this blog post, but can be easily achieved with an extra resolver in the httpRequestBegin pipeline (an example can be seen in the EasyLingo module)
 

This is a first post in a series that will come from our multi-site project. Stay tuned for more SXA knowledge sharing...


No comments:

Post a Comment