Skip to content

Multilingual support

Simon Yohannes edited this page Jan 26, 2020 · 13 revisions

Puck supports multi site and 1:1 approach to multilingual web sites.

Multi site

for this approach, you have multiple site roots in the back office mapped to different domains. for example, the root level content HomeUK might be your default so this can be mapped to *, an asterisk mapping sets it as a wildcard meaning it's the default for all domains. then you might have another root named ContentJP which you can map to the domain jp.domain.com. in the localisation settings for these roots, they will be set to have the variant name of en-gb and ja-jp, respectively and content queries in your views will respect these settings and retrieve the correct language content.

you can also set different localisation settings further down the site tree so although HomeUK might be set to the language variant en-gb, HomeUK/News could be set to a different language if you prefer. ¬¬

1:1 approach

for this approach, you can simply have translations of all of your content under one site root. if you click the settings icon for a content item in the site tree, you will have the option to translate to one of the available languages you've set in the settings->languages page of the Backoffice.

in your views, you can then query for available translations (called variants) and show that translation based on a querystring parameter or cookie value. to get all the translations of any ViewModel all you need to do is call Model.Variants(). to get a specific variant, you can do the following:

var variant = new QueryHelper<T>()
   .Id(Model.Id)
   .Variant("en-gb")
   .Get();

click here for more information about the QueryHelper.

mixing both approaches - complex scenarios

if you wanted to have 1:1 translations but have the current language used by Puck to be mapped by the domain/subdomain or some other custom method, you can pass the language you would like to use to Puck as an override to the default culture setting for that page.

by default, the HomeController inherits from Pucks BaseController and calls base.Puck() in the Index action to serve the current page.

in this approach, you could check what the subdomain is of the current request, for example en-gb.domain.com and use that to pass the language to Puck. so you'd pass it like so:

public IActionResult Index()
{
     var variantFromSubdomain = Request.Host.Host.Split(".")[0];
     return base.Puck(variant:variantFromSubdomain);
}

likewise you could get the culture/variant from the querystring:

public IActionResult Index(string variantFromQuerystring=null)
{
     return base.Puck(variant:variantFromQuerystring);
}

here the variant will be taken from the querystring if it exists, if null the current culture setting for that node will be used by default.

you could also add the culture to the end of the path, for example /news/tech/en-gb then do the following:

public IActionResult Index()
{
      var pathAndCultureSegment = Request.Path.ToString();
      var path = pathAndCultureSegment.Substring(0, pathAndCultureSegment.LastIndexOf("/"));
      var variant = pathAndCultureSegment.Substring(pathAndCultureSegment.LastIndexOf("/")).TrimEnd('/');
      return base.Puck(path:path,variant:variant);
}

in the above example, the last segment of the url is used to get the Culture or Variant. it's then stripped from the path to get the actual path of the content and both the path and culture are passed to the base.Puck method.

falling back to defaults when overriding culture

with any of the previous approaches shown where you're overriding the Culture and passing it to base.Puck, you can make sure you fallback to the default content if the translation for the overridden culture doesn't exist by doing the following:

public IActionResult Index()
{
      var pathAndCultureSegment = Request.Path.ToString();
      var path = pathAndCultureSegment.Substring(0, pathAndCultureSegment.LastIndexOf("/"));
      var variant = pathAndCultureSegment.Substring(pathAndCultureSegment.LastIndexOf("/")).TrimEnd('/');
            
      var result = base.Puck(path:path,variant:variant) as ViewResult;

      if (result.Model == null)
          return base.Puck();
      else
          return result;
}

in the example above, you first attempt to override the Culture and check the result's Model is null. if it is, it means Puck couldn't find the content with the override you specified and then you can return the default translation for the current page based on its Localisation settings in the backoffice.

in your views when using QueryHelper to query for content, you would then use the CurrentLanguage() method of QueryHelper to make sure that the content returned is of the current language.