Creating A Multi Language Picker In Episerver

In my previous tutorial I wrote about How to enable multi-languages within your website. Today I’m going to talk to you through how to create a language picker so your website users can swap languages.

Determining Languages

In your code, you can always get the current language by reading the CultureInfo.CurrentCulture property like you would any other .NET MVC application. You can also get the current culture by:

var currentCulture = new System.Globalization.CultureInfo(selectedCountryCode);
Thread.CurrentThread.CurrentCulture = currentCulture;

Getting A List Of Available Languages

To get a list of all the available languages

public IEnumerable<SelectListItem> Languages
{
get
{
var languages = new List<SelectListItem>();
if (_epiServerDependencies.CurrentPage.PageLanguages != null)
{
foreach (var langContext in ServiceLocator.Current.GetInstance<LanguageBranchRepository>().ListEnabled())
{
var culture = new CultureInfo(langContext.LanguageID);
var isActive = string.Equals(_epiServerDependencies.CurrentPage.Language.Name,
langContext.LanguageID,
StringComparison.CurrentCultureIgnoreCase)
? true
: false;
languages.Add(new SelectListItem
{
Value = culture.Name,
Text = culture.NativeName,
Selected = isActive
});
}
}
return languages;

To get a list of current languages, you will need to use the Language Branch Repository.

ServiceLocator.Current.GetInstance<LanguageBranchRepository>().ListEnabled()

The thing I’m doing in this code is setting an active state in the drop-down for the current language. When the page loads the current language will be selected. To activate the current language is straightforward:

var isActive = string.Equals(_epiServerDependencies.CurrentPage.Language.Name,
langContext.LanguageID,
StringComparison.CurrentCultureIgnoreCase)
? true
: false;

Now we have the basic building blocks for everything we need to create a working prototype.

Define The Language Picker

[ContentType(DisplayName = "Language Picker Block",
GUID = "342E3F7C-797B-4D69-8FDB-DAAB1E2892BC",
Description = "Language Picker")]
public class LanguagePickerBlock : BlockData
{
[Display(
Name = "Submit Button Text",
Description = "Submit Button Text",
GroupName = SystemTabNames.Content,
Order = 100)]
[CultureSpecific]
public virtual string SubmitButtonText { get; set; }
}

The submit button text will be content added in via Episerver. This will be language specific so when the language changes so will the buttons text.

Defining The ViewModel

public IEnumerable<SelectListItem> Languages
{
get
{
var languages = new List<SelectListItem>();
if (_epiServerDependencies.CurrentPage.PageLanguages != null)
{
foreach (var langContext in ServiceLocator.Current.GetInstance<LanguageBranchRepository>().ListEnabled())
{
var culture = new CultureInfo(langContext.LanguageID);
var isActive = string.Equals(_epiServerDependencies.CurrentPage.Language.Name,
langContext.LanguageID,
StringComparison.CurrentCultureIgnoreCase)
? true
: false;
languages.Add(new SelectListItem
{
Value = culture.Name,
Text = culture.NativeName,
Selected = isActive
});
}
}
return AddDefaultValue.Concat(languages);
}
}
public IEnumerable<SelectListItem> AddDefaultValue
{
get
{
return Enumerable.Repeat(new SelectListItem
{
Value = CultureInfo.CurrentCulture.Name,
Text = "Select a country"
}, count: 1);
}
}
public ContentReference ContentPageReference
{
get
{
return _epiServerDependencies.CurrentPage.ContentLink;
}
}

We’ve talked through the language selection code already. I’ve added a AddDefaultValue method that is concatenated with the languages to provide a default drop down message for the picker.

I’m also exposing a ContentReference to the current page for the redirect part in the form. In this example, you might be wondering what _epiServerDependencies is? I suggest you download the code project at the bottom or read by article EPiServer: Dependencies in Episerver Explained – Unit Testing Part 1 to get a better understanding.

Defining The View

@model JonDJones.Com.EpiserverLanguagePicker.Models.ViewModel.LanguagePickerBlockViewModel
@using (Html.BeginForm("SetLanguage", null, new { node = Model.ContentPageReference }, FormMethod.Post))
{
@Html.DropDownList("selectedCountryCode", Model.Languages)
<button>
@Model.CurrentBlock.SubmitButtonText
</button>
}

It’s worth talking about the reason I am not using the DropDownListFor helper. As this control is very lightweight the only property I care about passing to my base class is the Currency Code, I don’t want to have to get the auto bind the full ViewModel or Block itself in my base controller.

If I used DropDownListFor after the form was submitted I would end up with a key called CurrentBlock.CurrentContentPageId in the Request.Form collection. You can not use a full stop operator in a variable name so that would mean that I wouldn’t be able to use MVC’s model binding feature to auto populate the country code in my base action. Instead when my base controller action was hit, I would have to query the Forms collection manually to get the country code out:

Request.Form["CurrentBlock.CurrentContentPageId"]

By specifying an explicit name in the DropDownList helper and having an input parameter called CurrentContentPageId in the base controller MVC auto populates it for me without me having to write any code at all 🙂 This process is a lot more efficient than passing more data then I need around and having to auto bind a lot of properties you don’t really care about.

The other import thing to note in this code is within the Form tag, notice how I’m passing the current pages content reference in the node property. This will mean that when we hit the base controller the Current Page property will be automatically populated. This feature is pretty cool, but you can please note when you use node within the form, the controller property must be left blank. If you do not do this then the current page will be null in your base controller.

Adding a Method To Set The Language in the Base Controller

As hinted our next step is to create a Set Language method in our base Page controller so it is available from any page.

[HttpPost]
public RedirectResult SetLanguage(string selectedCountryCode, PageData currentPage)
{
var currentCulture = new System.Globalization.CultureInfo(selectedCountryCode);
ContentLanguage.PreferredCulture = currentCulture;
Thread.CurrentThread.CurrentCulture = currentCulture;
var url = EPiServer.UriSupport.AddLanguageSelection(currentPage.LinkURL, selectedCountryCode);
return Redirect(url);
}

In here we use the value posted back from the drop down list, called selectedCountryCode. In the method, I’m setting ContentLanguage.PreferredCulture and Thread.CurrentThread.CurrentCulture to the culture the user has specified.

Tip I’m using MCV’S automatic Model Binding to automatically populate selectedCountryCode. Another way you could get the values is directly through the Request.Forms collection like this:

var selectedCountryCode = Request.Form["selectedCountryCode"];

When posting back data into a controller’s action method from a block it can sometimes be a bit of a headache getting your properties to auto populate. If you’re having problems accessing your posted values in your controller, hit a break-point and have a look in Request.Form and the RouteData collections using the Debugging Watch window.

In the second part of our set language method, we’re generating the return Url. We get the current page that was passed in the view, in our code we’re forcing the return URL to point to the correct language branch of the one the user just selected.

Conclusion

That covers the basics of how to get a language picker up and running. It does involve using some of the more advanced features of MVC and Episerver and knowing which API calls to use and how to pass data around the site is key to getting this sort of functionality working.

Working Code Example

All the above code can be downloaded in a fully working website from my GitHub account here JonDJones.Com.EpiserverLanguagePicker

Note The demo site will only work when the country code is set, s you will need to make sure the /en/ part is in the Url when you submit the form, otherwise the server won’t find the base controller. I haven’t included the code to auto force the languages.

Jon D Jones

Software Architect, Programmer and Technologist Jon Jones is founder and CEO of London-based tech firm Digital Prompt. He has been working in the field for nearly a decade, specializing in new technologies and technical solution research in the web business. A passionate blogger by heart , speaker & consultant from England.. always on the hunt for the next challenge

More Posts

1 reply

Trackbacks & Pingbacks

  1. […] covers everything you need to have a site that works via a language cookie. In the next tutorial Creating A Multi Language Picker In EpiServerI’ll explain how to create a language picker. This picker will provide the functionality to […]

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *