Resolve Context Language based on Geolocation

Sitecore Language resolver didn’t change much since I am working with Sitecore. I remember John West blog post explaining the order of resolution.

  1. The sc_lang query string parameter.
  2. The language prefix in the path in the requested URL.
  3. The language cookie associated with the context site.
  4. The default language associated with the context logical site.
  5. The DefaultLanguage setting specified in web.config.

But what if I would like to change it ?

  1. The sc_lang query string parameter.
  2. The language prefix in the path in the requested URL.
  3. The language cookie associated with the context site.
  4. The language corresponding to visitor IP – using Geolocation service 
  5. The default language associated with the context logical site.
  6. 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

  1.  sc_lang https://www.company.com/about-us/?sc_lang=en resolved in protected virtual Language GetLanguageFromRequest(HttpRequestArgs args) method
  2. Language prefix https://www.company.com/en/about-us/  File Path Language has been resolved earlier args.SitecoreContext.Data.FilePathLanguage
  3. 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");
        }

 

Leave a comment