In this post I will provide you with code that will localize your 404 page in your Kentico Xperience website.
The problem
In my Xperience website, I am using 2 cultures. When I was about to create a 404 page, I didn't want to re-invent the wheel. Therefore, I took out the 404 page implementation from the Dancing Goat site which is a sample site that comes with Kentico Xperience in one package.
Regrettably, I found out that the implementation is not ready for localization and must be adjusted to show localized strings. With the kind help of Kentico's support, I was able to find a solution.
Please note, that this solution is valid for URL structure where
- URL paths for the default culture do not contain culture code (i.e. "/clanky" for "cs-CZ" default culture)
- URL paths for other cultures contain culture code (i.e. "/en-us/articles" for "en-US" culture)
The solution
There are a couple of code files that you have to create.
HttpErrorsController.cs
using Microsoft.AspNetCore.Mvc;
namespace DancingGoat.Controllers
{
public class HttpErrorsController : Controller
{
public IActionResult Error(int code)
{
if (code == 404)
{
return View("NotFound");
}
return StatusCode(code);
}
}
}
NotFoundSiteCultureConstraint.cs
using Kentico.Content.Web.Mvc;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing;
using System;
using System.Globalization;
namespace DancingGoat
{
public class NotFoundSiteCultureConstraint : IRouteConstraint
{
public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection)
{
var cultureCode = values[routeKey]?.ToString();
if (string.IsNullOrEmpty(cultureCode))
{
if (values != null && values.Count == 3 && string.Equals("Error", values["action"].ToString(), StringComparison.OrdinalIgnoreCase) && string.Equals("HttpErrors", values["controller"].ToString(), StringComparison.OrdinalIgnoreCase))
{
var originalTarget = httpContext.Features.Get<IHttpRequestFeature>().RawTarget;
cultureCode = originalTarget.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries)[0];
}
if (!string.IsNullOrEmpty(cultureCode))
{
try
{
var cultureInfo = CultureInfo.GetCultureInfo(cultureCode);
}
catch (CultureNotFoundException)
{
cultureCode = null;
}
}
values[routeKey] = cultureCode;
}
return new SiteCultureConstraint().Match(httpContext, route, routeKey, values, routeDirection);
}
}
}
NotFound.cshtml - This is a view and it should contain your own markup that fits your website. Here I post an example that uses Localization strings. They could be defined in the Xperience Admin in the Localization application.
@{
ViewBag.Title = @ResHelper.GetString("notfoundtitle");
}
<main id="main">
<section class="error">
<div class="error__heading">
<div class="error__text">@ResHelper.GetString("notfoundheading")</div>
</div>
</section>
</main>
In the Startup.cs file, add the following code in the Configure
method after endpoints.Kentico().MapRoutes();
endpoints.MapControllerRoute(
name: "error",
pattern: "/error/{code}",
defaults: new { controller = "HttpErrors", action = "Error" },
constraints: new { culture = new NotFoundSiteCultureConstraint() }
);
And that's it.
Side notes
Considering the Dancing Goat site, the only extra piece in the implementation is the NotFoundSiteCultureConstraint.cs file. What I really like here is the way the originalTarget
is obtained. You can also use that in your controller to add some extra logic to your 404 page.
Example - Redirects article details that are not localized to a listing page.
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc;
using System;
namespace jobs.kentico.com.Web.Controllers
{
public class HttpErrorsController : Controller
{
public IActionResult Error(int code, string culture)
{
var originalTarget = Request.HttpContext.Features.Get<IHttpRequestFeature>().RawTarget;
var path = originalTarget.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
var pathSegment = "";
if (path.Length > 1 && culture == "en-us")
{
pathSegment = path[1];
}
else if (path.Length > 0 && culture == "cs-CZ")
{
pathSegment = path[0];
}
if (code == 404)
{
if (culture == "en-us" && pathSegment == "articles")
{
return LocalRedirect("/en-us/articles");
}
else if (culture == "cs-CZ" && pathSegment == "clanky")
{
return LocalRedirect("/clanky");
}
else
{
return View("NotFound");
}
}
return StatusCode(code);
}
}
}
Further reading
all posts- Kentico Xperience
Open graph meta tags enhanced by Kentico macros
Social media networks need more information about your content than just an url to be able to display it in their feeds. For such a purpose we put open graph meta tags in the head …
- Front-end & JavaScript
Philips Hue experiments
I created an app for the Anybody hotel that controls Philips Hue lights. However, before I was able to design and implement the app, I researched the possibilities of the technolog…
- Kentico Xperience
Reload Javascript after postback in Kentico
For any kind of form web parts, I like using update panel to avoid full page reload when the form is submitted. In such situation, a postback is invoked. When you execute a Javascr…