Sitecore Language resolver didn’t change much since I am working with Sitecore. I remember John West blog post explaining the order of resolution.
- The sc_lang query string parameter.
- The language prefix in the path in the requested URL.
- The language cookie associated with the context site.
- The default language associated with the context logical site.
- The DefaultLanguage setting specified in web.config.
But what if I would like to change it ?
- The sc_lang query string parameter.
- The language prefix in the path in the requested URL.
- The language cookie associated with the context site.
- The language corresponding to visitor IP – using Geolocation service
- The default language associated with the context logical site.
- The DefaultLanguage setting specified in web.config.
First, let see how Sitecore Language Resolver works, and how we can hook our custom logic into.
Sitecore.Pipelines.HttpRequest.LanguageResolver
- sc_lang https://www.company.com/about-us/?sc_lang=en resolved in protected virtual Language GetLanguageFromRequest(HttpRequestArgs args) method
- Language prefix https://www.company.com/en/about-us/ File Path Language has been resolved earlier args.SitecoreContext.Data.FilePathLanguage
- Language cookie . This one is tricky. Langue class geter and setter read and write from/into language cookie.
-
public static Language Language { get { Language language1 = Context.Items[Context.Constants.LANGUAGEKEY] as Language; if ((object) language1 != null) return language1; string name = string.Empty; SiteContext site = Context.Site; if (site != null) { name = WebUtil.GetCookieValue(site.GetCookieKey("lang"), site.Language); Assert.IsNotNull((object) name, "languageName"); } if (name.Length == 0) name = Settings.DefaultLanguage; Language language2 = Language.Parse(name); if (Sitecore.Configuration.State.Sites.IsSiteResolved) Context.Items[Context.Constants.LANGUAGEKEY] = (object) language2; return language2; } set { Assert.ArgumentNotNull((object) value, nameof (value)); Context.SetLanguage(value, true); } }
-
Your custom Language Revolver make look like this
public override void Process(Sitecore.Pipelines.HttpRequest.HttpRequestArgs args) { Log.Audit("CustomLanguageResolver: Entered LanguageResolver Pipeline", this); Assert.ArgumentNotNull(args, "args"); if (Sitecore.Context.Site.IsSxaSite() && Sitecore.Context.Site.Name != "admin" && Sitecore.Context.Site.Name != "shell" && (Sitecore.Context.PageMode.IsExperienceEditor || Sitecore.Context.PageMode.IsNormal || Sitecore.Context.PageMode.IsPreview)) { Language language1 = GetLanguageFromRequest(args) ?? Sitecore.Context.Data.FilePathLanguage; if (language1 == null) { SiteContext site = Sitecore.Context.Site; if (site != null) { if (!HttpContext.Current.Response.Cookies.AllKeys.Contains(site.GetCookieKey("lang"))) { Language language3 = GetLanguageItemFromRequestIp(); Sitecore.Context.SetLanguage(language3, true); } } } } base.Process(args); Log.Audit("CustomLanguageResolver: Exit LanguageResolver Pipeline", this); }
Your GetLanguageItemFromRequestIp mathod can contain Business Logic such as:
- call to geolocation service of your choice (I couldn’t use sitecore tracker because I disabled it for GDPR reasons – need a consent)
- for countries with more than language you may want to check browser preference
- timeout before spiking the step or returning default value
- filter, content type, sites, etc
If you use sitecore GeoIp lookup Sitecore.CES.GeoIp.Core.Lookups.LookupManager.GetWhoIsInformationByIp(ip);
make sure that you are parsing well IP (ports, IPv6 vs IPv4, etc)
var ipWithoutPort = ParseIPEndPoint(ip);
ip = ipWithoutPort.Address.ToString();
public static IPEndPoint ParseIPEndPoint(string text) { Uri uri; if (Uri.TryCreate(text, UriKind.Absolute, out uri)) return new IPEndPoint(IPAddress.Parse(uri.Host), uri.Port < 0 ? 0 : uri.Port); if (Uri.TryCreate(String.Concat("tcp://", text), UriKind.Absolute, out uri)) return new IPEndPoint(IPAddress.Parse(uri.Host), uri.Port < 0 ? 0 : uri.Port); if (Uri.TryCreate(String.Concat("tcp://", String.Concat("[", text, "]")), UriKind.Absolute, out uri)) return new IPEndPoint(IPAddress.Parse(uri.Host), uri.Port < 0 ? 0 : uri.Port); throw new FormatException("Failed to parse text to IPEndPoint"); }