Try our conversational search powered by Generative AI!

Johan Björnfot
Feb 20, 2015
(5 votes)

Changes regarding language handling during content loading in CMS8


Previously there were overloads to content loading methods in IContentLoader that took an ILanguageSelector as a parameter. When working on multilingual sites these overloads could be used to load content in a specific language, and/or define if language fallback rules should apply.

The way it worked behind the scenes during load was that first the content provider could operate on the passed in language selector to decide which language to return. Then the language selector was used again to select which language version to return according to defined language fallback rules.

The main implementation of ILanguageSelector is LanguageSelector. It is a fairly complex class that previously both acted as a data carrier as well as a service. It can be hard to handle in unit tests, mainly due to a static dependency to ContentLanguage.PreferredCulture but also complexity to mock. Another feedback we heard was from implementers of content providers was that the language selector is complex to work with.

We finally ran into some issue with the language selector and the Preview functionality in the recently introduced Project feature (beta description of projects). As the language fallback functionality in the LanguageSelector was run after the project version was selected it would not take projects into consideration and the two features would not work well together.

So the current language handling using LanguageSelector which already was complex did not work very well in the project preview scenario. We did not want to add project awareness to LanguageSelector, due to the tight coupling this would mean, also considering that LanguageSelector was already complex in its own.

New loading handling

So we decided to do some improvements regarding language handling during content loading. Some of the goals we set up where:

  1. Possibility to specify options for language that does not have static dependencies such as ContentLanguage.PreferredCulture or the inversion of control magic (SelectPageLanguage etc)
  2. Make a smooth upgrade from CMS7, preferably just a recompile without changing any code
  3. Simplify language selector and how to use it

We moved the language selection from the content provider level to the loader above the providers. We have changed IContentLoader by replacing the ILanguageSelector with LoaderOptions instead. We have also added simpler overloads that just take a CultureInfo. LoaderOptions is basically just a collection of LoaderOption (currently there are LanguageLoaderOption and ProjectLoaderOption). During loading there are specific components that acts on the different loader options, affecting which language/version of a content to return.

What about LanguageSelector?

To minimize the impact on existing code, we have changed LanguageSelector to inherit from LoaderOptions. This means you can still pass in a LanguageSelector to the overloads that take a LoaderOption. We have changed the implementation of LanguageSelector so that the constructor and the static methods (like MasterLanguage) creates corresponding LoaderOptions instances. This means there is no immediate demand to replace current usage of LanguageSelector as parameter to loading methods.

Usage of IContentLoader

Below are some examples on how to load content with some different fallback strategies applied. The examples shows usage of LanguageSelector and alternatives using CultureInfo and LoaderOptions instead.

Loading specific language

Loading a page in a specific language, using LanguageSelector:

var swedishPage = contentLoader.Get<StandardPage>(contentLink, new LanguageSelector("sv"));

Using the new overload that takes a CultureInfo, the same page can be loaded as:

var swedishPage = contentLoader.Get<StandardPage>(contentLink, CultureInfo.GetCultureInfo("sv"));

This is equivalent to:

swedishPage = contentLoader.Get<StandardPage>(contentLink, 
    new LoaderOptions(){ LanguageLoaderOption.Specific(CultureInfo.GetCultureInfo("sv")) });

Loading master language

To load the master language version of a content (the master language version is the language version in which the common non-language specific properties are stored) using LanguageSelector:

var master = contentLoader.Get<StandardPage>(contentLink, LanguageSelector.MasterLanguage());

Using the new overload that takes a CultureInfo the master version can be loaded as:

master = contentLoader.Get<StandardPage>(contentLink, CultureInfo.InvariantCulture);

This is equivalent to:

master = contentLoader.Get<StandardPage>(contentLink,
    new LoaderOptions() { LanguageLoaderOption.MasterLanguage() });

Loading in current language with fallback

Using LanguageSelector to load a content instance in the same language as the current request was routed to:

var current = contentLoader.Get<StandardPage>(contentLink, LanguageSelector.AutoDetect());

LanguageSelector.AutoDetect() uses language fallback settings, which means that if the content does not exist in the requested language or if the language is not published, then another language version might be returned (according to defined fallback rules). Using LoaderOptions the call would look like:

current = contentLoader.Get<StandardPage>(contentLink, new LoaderOptions() { LanguageLoaderOption.Fallback() });

Loading specific language with fallback (including master)

Loading content in a preferred culture with fallback rules applied, including a final fallback to master (if no other fallback rules apply) can be done using LanguageSelector:

var fallback = contentLoader.Get<StandardPage>(contentLink, LanguageSelector.Fallback("sv", true));

The equivalent call using LoaderOptions is:

fallback = contentLoader.Get<StandardPage>(contentLink, new LoaderOptions(){ LanguageLoaderOption.FallbackWithMaster(CultureInfo.GetCultureInfo("sv")) });

Related changes

Changes in IContentRepository

The methods CreateLanguageBranch and GetDefault have been simplifed to take a CultureInfo as parameter, instead of an ILanguageSelector.

ILanguageSelector and content providers

The interface ILanguageSelector has been simplified to only contain a single property Language of type CultureInfo. This means content provider implementations no longer needs to call any methods on ILanguageSelector to decide which language version to return. Instead they can just return the language version specified by ILanguageSelector.Language. If CultureInfo.InvariantCulture is passed in, the provider should return content in the master language. If the content does not exist in the specified language, then the master language should be returned.


ContentReference has a property GetPublishedOrLatest that loads the published version or the latest version if no published version exists. When using this property with language fallback previously it only loaded published versions in the fallback chain. This has been corrected to select the published or latest version in the fallback chain as well. This property is normally not used in templates.


In previous versions of CMS, it was possible to cast the passed in LanguageSelector to ILanguageSelectionSource after content retrieval. That interface contained information about why the content was selected, for instance that the content was selected due to language fallback or replacement rules. The same information can now be retrieved after content retrieval by calling MatchLanguageSettings on IContentLanguageSettingsHandler passing in the retrieved content instance and the requested language.

Feb 20, 2015


Frederik Vig
Frederik Vig Feb 20, 2015 07:45 PM

Just to make sure: var current = contentLoader.Get(contentLink, LanguageSelector.AutoDetect()); is the equivalent of: var current = contentLoader.Get(contentLink);?

Great changes!


Feb 21, 2015 07:14 AM

current = contentLoader.Get(contentLink);
is actually equivalent to
current = contentLoader.Get(contentLink, LanguageSelector.AutoDetect(true));
which means it has fallback to master enabled.

Johan Book
Johan Book Feb 22, 2015 01:24 AM

Seems like a fair change, makes code more predictable. However, I'm wondering if we're adviced not to use LanguageSelector anymore when starting from scratch in Episerver 8? I kind of like the simpler notation of LanguageSelector, compared to LoaderOptions. Couldn't there be default constructs for LoaderOptions that worked in the same way as LanguageSelector?

K Khan
K Khan Feb 23, 2015 01:56 PM

Is there any Changes in relation with Language and Commerce Markets ?

Please login to comment.
Latest blogs
Developer meetups in Stockholm & Helsinki

It's time for developer meetups! Next month we will be in Stockholm and Helsinki. Join us for getting the latest updates from Optimizely, be inspir...

Magnus Kjellander | Feb 23, 2024

Roll Your Own Security Headers

Proper security headers are a must for your Optimizely driven website. There are a variety of tools out there that will help with this, but when...

Ethan Schofer | Feb 21, 2024

Migrate Catalog content properties

A colleague asked me yesterday – how do we migrate properties of catalog content. There is, unfortunately, no official way to do it. There are...

Quan Mai | Feb 20, 2024 | Syndicated blog

Adjust log levels in Optimizely DXP

You may adjust the log levels for your site in Optimizely DXP yourself, but only for the Integration environment. Follow this step-by-step guide.

Tomas Hensrud Gulla | Feb 20, 2024 | Syndicated blog