Blog / Development

Working with Localization in Kentico Cloud


by Bryan Soltis

Jul 12, 2017

When developing for a global audience, you have to think multi-lingual. Presenting content in native languages helps you connect with your audience and provide them information in a much more personal experience. We recently released an update to Kentico Cloud to enable localization of your data, giving you the ability to edit and store your content in nearly any language. In this blog, I’ll show you how to leverage this new capability within your projects. 


Any company that does business globally knows the value of localized content. By presenting information in different cultures, they can personalize the user's experience and connect them with on a much more personal level. While Kentico EMS developers have leveraged this feature for years, choosing Kentico Cloud meant limiting content to a single language. Until now!

Kentico Cloud gets major updates regularly, often every other week. Because it's a SaaS, we can roll out new features to all users of the platform without impacting existing applications leveraging the service. Recently, we launched our new localization support for Kentico Cloud content, one of our most requested features from the community. This capability allows editors to create and manage content in multiple languages, all from within the Kentico Cloud portal. The API has been updated to allow developers to specify language variants for every call, and there are configurations that can be set to determine if/when to fall back to the "default" language.

In this blog, I will show you how you can use this new functionality to build your multi-lingual sites. I'll explain how I configured my Kentico Cloud project, defined and created my content, and leveraged the API to pull the new data. Let me show you how!

Creating the content

My first step was to create my content. For my extra-awesome demo, I had to come up with something universal. Movies! Everyone watches them, but often a title will have a different name, depending on the country. OK, now that I was set with an idea, it was onto my project.

Creating the default content

I created a simple content type called Movies. For the elements, I created a Title, Year, Genre, Poster (for the image), and a link. 


After defining the content, I created my content items. I started with the Greatest Christmas movie of all time, of course!

Adding language variants

After creating the default content, I updated the project configuration with 2 new language variants.


As the Quick Tip states, you can define any value for the language variants. The variants re really just identifiers for the version of the content. This means you are free to put in the culture code, name, or any other value that makes sense. For my demo, I used the actual culture code for Czech and French to help keep things organized. 

Note that for each variant, you can choose whether to fallback to the default language. This means that if a content item is not translated into the new variant, the API will return the default language version instead. Keep this in mind as you build your sites to makes sure you get the exact functionality that is needed. 

Adding localized content

With the variants in place, I was ready to enter my localized content. For each content item, I selected the language variant (using the new drop down that is enabled after defining a new variant).


I then updated the content with the variant-specific information. 


I was happy to see that the Czech Republic recognizes the awesomeness that is John McLane's epic tale of spreading holiday cheer.

Viewing the inventory

After updating my content, I viewed the Content Inventory. This screen shows you the status of each content item, so you can identify any items that need to be translated. You can also use the language variant dropdown to switch between variants. 


Note that I did not translate Fight Club and The Usual suspects to French. Yes, I'm sure they saw them there but the names weren't different and I needed something to demo. 

Creating the project

With the content in place, I was ready to create my site. I opted for the Kentico Cloud .NET Core Boilerplate as my starting point. This project has a lot of great features already baked in, so it was an easy choice. I also leveraged the Kentico Cloud Code Generator project to create my Movie class to include within my site.


You can find more about the Kentico Cloud .NET Core Boilerplate project here.

Updating the code

After updating my project and classes, I moved onto the code. In the Home controller, I updated the Index function to pull my new Movie content type.

        public async Task<ViewResult> Index()
        {

            var response = await DeliveryClient.GetItemsAsync<Movie>(
            new EqualsFilter("system.type", "movie"),
            new OrderParameter("system.name")
            );

            return View(response.Items);
        }


I then updated my project with a new Movie Display Template and added my layout. 

<div class="col-sm-6">
    <div class="row">
        <div class="col-xs-12">
            <h4>@Model.Title</h4>
        </div>
    </div>
    <div class="row">
        <div class="col-sm-4">
            <img src="@Model.Poster.First().Url" class="img-responsive" alt="@Model.Poster.First().Name" />
        </div>
        <div class="col-sm-8">
            Name: @Model.System.Name
            <br />
            Year: @Model.Year
            <br />
            Genre: @Model.Genre.First().Name
            @if (Model.Link != null) {
                <br />
                <br />
            <a class="btn btn-sm btn-primary" href="@Model.Link" target="_blank" role="button">Link</a>
            }
        </div>
    </div>
    <br />
</div>


I tested the site to make sure everything looked correct.

Adding multi-lingual support

After confirming the site functioned properly and I could view my movies, I moved on to adding support for my language variants. To do this, I had to add the routing, some sort of language selector, and update the API call.

In my StartUp.cs I added the following mapping, This code allowed me to specify the culture as part of the URL. 

                routes.MapRoute(
                    name: "cultureRoute",
                    template: "{culture}/{controller}/{action}/{id?}",
                    defaults: new { controller = "Home", action = "Index" },
                    constraints: new
                    {
                        culture = new RegexRouteConstraint("^[a-z]{2}(?:-[A-Z]{2})?$")
                    });


Next, I added a very complex language selector to my Index.cshtml. The links redirect the user to the same page, appending the language variant. 

<div class="row marketing">
    <div style="float:left;">
        <h2>Movies</h2>
    </div>
    <div style="float:right;">
        <a href="/">English</a> | <a href="/cs-CZ">Czech</a> | <a href="/fr-FR">French</a>
    </div>
    <div style="clean:both;"></div>
</div>
<div class="row marketing">


Lastly, I updated the API call in my Home controller to leverage the culture code. To make it a little cleaner, I decided to use a List<IQueryParameter> object to hold my filters. I then conditionally set the language variant if it’s anything other than English.

        public async Task<ViewResult> Index()
        {
            List<IQueryParameter> filters = new List<IQueryParameter>();
            filters.Add(new EqualsFilter("system.type", "movie"));
            filters.Add(new OrderParameter("system.name"));

            // Check if a culture code is specified
            if(Request.Path != "/")
            {
                string strPath = Request.Path.ToString().Replace("/", "").ToLower();
                filters.Add(new LanguageParameter(strPath));
                filters.Add(new EqualsFilter("system.language", strPath));
            }

            var response = await DeliveryClient.GetItemsAsync<Movie>(
                filters
            );

            return View(response.Items);
        }


Note the EqualsFilter in the API call. This filter tells the API to only return content items that have been translated to the selected language. If this filter was removed, the API would fallback to the default language version of the content item.

Testing

With my content and code in place, I was ready to test my site. First, I hit the site without specifying a culture and confirmed the English version was shown, Additionally, I made sure my extra awesome language selector was displayed. 


I then clicked the Czech link to confirm that content loaded correctly.


Last but not least, I selected French to see those titles.


Because of the EqualsFilter in my API call, the list is filtered to only those content items that have been translated in the French. 

Moving Forward

Multi-lingual content is a key component to any global site. With Kentico Cloud, you can build out your content in multiple languages easily. With the updated API, you can quickly pull the language variants you need, and customize how/when you fallback to the default language. I hope this blog demonstrated how simple it is to get going and helps you get started with your multi-lingual sites right away. Good luck!

View the source code

You can read more about Localization in Kentico Cloud here.