For one of our projects, we have a multilingual site, which contains content in Dutch and in English. To make sure that the language of the site isn’t determined just based on a cookie value, we’ve set LanguageEmbedding to Always on our LinkManager.
By default, this will lead to the following:
https://www.testdomain.com/nl-NL/mypage
https://www.testdomain.com/en/mypage
Looks great doesn’t it? However, we would like to exclude the primary language (in this case that’s Dutch) from the url:
https://www.testdomain.com/mypage
https://www.testdomain.com/en/mypage
Unfortunatly this isn’t possible by default, but Sitecore gives us an extension point where we can easily plug in our custom functionality. To add the required functionality, we have to follow the following steps:
- Create a custom LinkProvider that does not embed the language for our primary language.
- Add the LinkProvider to Sitecore
- Register the LinkProvider for your site
- Create a processor that removes the language cookie
- Register the remove cookie processor to Sitecore
- Set the removeLanguageCookie on your site
1. Creating the custom LinkProvider
First of all we create the custom LinkProvider. Please note that this example is based on the LocalizableLinkProvider that is introduced within SXA, but you can extend any LinkProvider.
using System.Collections.Generic; using Sitecore.Data.Items; using Sitecore.Links; using Sitecore.Links.UrlBuilders; using Sitecore.XA.Foundation.Multisite.LinkManagers; using System.Linq; namespace Example { public class SkippableLanguageEmbeddingLinkProvider : LocalizableLinkProvider { private const string SkipEmbedForLanguagesSiteSetting = "skipEmbedForLanguages"; public SkippableLanguageEmbeddingLinkProvider() { } public override string GetItemUrl(Item item, ItemUrlBuilderOptions options) { options.LanguageEmbedding = GetShouldEmbedLanguage(options) ? LanguageEmbedding.Always : LanguageEmbedding.Never; return base.GetItemUrl(item, options); } private bool GetShouldEmbedLanguage(ItemUrlBuilderOptions options) { var languagesToIgnore = options.Site.Properties[SkipEmbedForLanguagesSiteSetting]?.Split('|').Select(l => l.ToLowerInvariant()).ToList() ?? new List<string>(); if (languagesToIgnore.Contains(options.Language.Name.ToLowerInvariant())) { return false; } return true; } } }
The link provider created in the example above, uses the skipEmbedForLanguages setting on the Site to determine for which language(s) it should not include the language in the URL.
2. Adding the new LinkProvider to Sitecore
To add the new LinkProvider to Sitecore, all you need to do is to register it through a config file. Please note that this config file is also scoped to SXA, if you don’t have SXA, remove the “defaultProvider” attribute.
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"> <sitecore> <linkManager defaultProvider="switchableLinkProvider"> <providers> <add name="SkippableLanguageEmbeddingLinkProvider" type="Example.SkippableLanguageEmbeddingLinkProvider, Example" cacheExpiration="5" addAspxExtension="false" alwaysIncludeServerUrl="false" encodeNames="true" languageEmbedding="never" languageLocation="filePath" shortenUrls="true" useDisplayName="true" lowercaseUrls="true" /> </providers> </linkManager> </sitecore> </configuration>
3. Register the LinkProvider for your site
We have to define the skipEmbedForLanguages setting on our site. When using SXA you can do this on your Site Grouping, otherwise add it to your Site Definition config.
For SXA, open your Site Grouping, scroll to Other Properties and add the skipEmbedForLanguages property
4. Create a processor to remove the language cookie
To make sure Sitecore does not take the language from the cookie, when nothing is specified in the URL, we will have to remove the language cookie from the response. This way, the cookie will never be sent to the user.
using Sitecore.Pipelines.HttpRequest; using System; using System.Linq; namespace Example { public class RemoveLanguageCookieProcessor : HttpRequestProcessor { private const string RemoveLanguageCookieSiteSetting = "removeLanguageCookie"; public override void Process(HttpRequestArgs args) { if (Sitecore.Context.Site == null) { return; } if (bool.TryParse(Sitecore.Context.Site.Properties[RemoveLanguageCookieSiteSetting], out var result) && result) { string cookieKey = Sitecore.Context.Site.GetCookieKey("lang"); //Remove the cookie from the response if it's already set if(args.HttpContext.Response.Cookies.AllKeys.Contains(cookieKey)) { args.HttpContext.Response.Cookies.Remove(cookieKey); } //If the user has the cookie set in it's request, invalidate it if (args.HttpContext.Request.Cookies.AllKeys.Contains(cookieKey)) { args.HttpContext.Response.Cookies.Set(new System.Web.HttpCookie(cookieKey) { Expires = DateTime.Now.AddYears(-1) }); } } } } }
The code above removes the cookie from the response, and invalidate the cookie if it already exists in the request from the user. As i want this processor to only run for the sites where i want it to, i added a check the removeLanguageCookie setting on the Site.
5. Register the remove cookie processor to Sitecore
To make sure our processor is executed at the right moment, we have to register it after the LanguageResolver processor
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"> <sitecore> <pipelines> <httpRequestBegin> <processor type="Example.RemoveLanguageCookieProcessor, Example" patch:after="processor[@type='Sitecore.Pipelines.HttpRequest.LanguageResolver, Sitecore.Kernel']"/> </httpRequestBegin> </pipelines> </sitecore> </configuration>
6. Set the removeLanguageCookie on your site.
As explained in Step 3, open your Site Grouping or Site Definition config, and add the following setting:
Now everything should be in place, and you should see that the language is omitted from the url.