3

Background: We have 4 multi-lingual sites.

Objective: When the language is embedded in the url, it should take the user to that specific site, and not the site stored in the cookie, and it should update the cookie accordingly. When there is no language specified in the url, it should take the user to the site specified in the cookie or look up the GeoIp.

Issue: When we do not mention the language in the url, it defaults to 'en' always, even for a new user. This happens because HttpContext.Current.Request.RawUrl always has a value"/en" when no language embedded in the url. We are resolving this at the SiteResolver processor in the HttpRequestBegin pipeline. After debugging some more, it also seemed to be an issue at the NormalizeRawUrl processor of the preprocessRequest pipeline.

Not sure how to capture the exact URL entered in the browser using HttpContext.Current.Request Is this Objective achievable? Has someone gone through similar issues and how did you tackle this problem?

Example:

www.xyz.com/en-ca/abc ---> This will take us to Canada website. HttpRequest.current.Request.RawUrl value is: "/en-ca/abc"

www.xyz.com ---> This should ideally take us to Canadian website because 1) No language specified in the url. 2) The cookies were set in the previous url. HttpRequest.current.Request.RawUrl value is: "/en" where as we expect it to be "/" or "".

Thanks in advance. Ashita

Here is the code snippet that we use:

//First: we try and take the site from the Querystring: KEY_SITE: "site" KEY_SITE_NAME: "sc_site"
var queryString = HttpContext.Current.Request.QueryString;
siteSpecified = string.Empty;
if (!string.IsNullOrEmpty(queryString[QuerystringUtil.KEY_SITE]))
{
    siteSpecified = queryString[QuerystringUtil.KEY_SITE];
}
else if(!string.IsNullOrEmpty(queryString[QuerystringUtil.KEY_SITE_NAME]))
{
    siteSpecified = queryString[QuerystringUtil.KEY_SITE_NAME];
}
else
{
    var siteLng = new Dictionary<string, string>
    {
        {"en", "site-us"},
        {"en-ca", "site-ca"},
        {"en-gb", "site-uk"},
        {"en-au", "site-au"}
    };

    //Second: This is piece where we read from the RawUrl which defaults to EN when no language specified
    foreach (var sl in siteLng.Where(sl => HttpContext.Current.Request.RawUrl.ToLower().Contains("/" + sl.Key)))
            {
                siteSpecified = sl.Value;
            }
SiteContext context;
if(!string.IsNullOrWhiteSpace(siteSpecified))
{
    context = Factory.GetSite(siteSpecified);
}
Language lang;
if(context != null && context.IsCustomSite() && context.Language != null)
{
    lang = Language.Parse(context.Language);
}
KeyValuePair<SiteContext, Language> kvp = new KeyValuePair<SiteContext, Language>();
if(lang != null)
{
   kvp = new KeyValuePair<SiteContext, Language>(context, lang);
}

if(kvp.Key != null && kvp.Value != null)
{
    SettingSite(kvp);
    return;
}

//Third: We try to retrieve from the cookie
kvp = GetSiteFromCookie();
if(kvp.Key != null && kvp.Value != null)
{
    SettingSite(kvp);
    return;
}

//Fourth: We try to get it from GeoIP
kvp = GetSiteFromGeoIP();
if(kvp.Key != null && kvp.Value != null)
{
    SettingSite(kvp);
    return;
}


//SettingSite Function looks like below:
private void SettingSite(KeyValuePair<SiteContext, Language> siteAndLanguage)
    {
        if (siteAndLanguage.Key == null || siteAndLanguage.Value == null)
        {
            return;
        }

        if (VerifyContext(siteAndLanguage.Value, siteAndLanguage.Key) && VerifyCookie(siteAndLanguage.Value, siteAndLanguage.Key))
        {
            return;
        }

        if (!siteAndLanguage.Key.IsCustomSite())
        {
            return;
        }
     Language language;

        if (HttpContext.Current.Request.Url.Segments.Any())
        {
             language = Sitecore.Context.Data.FilePathLanguage;
        }
        if (language != null && language.Name != siteAndLanguage.Value.Name)
        {
            string newUrl = ReplaceLanguageInUrl(siteAndLanguage.Value);
            HttpContext.Current.Response.Redirect(newUrl, true);
        }
        else
        {
            CookieUtil.SetSiteLanguageCookie(site.Name, language.Name);
            Sitecore.Context.SetLanguage(language, true);
            Sitecore.Context.SetActiveSite(site.Name);
        }
    }
  • Can you check the configuration of your site node? I think this will contain language="en". You can set the default language of your website there to "en-ca". <sites><site name="yoursitename" language="en" ....</site></sites> – Koen Heye Mar 7 '17 at 22:24
  • Where do you set the language cookie? If no cookie is present and there's no language in the url, Sitecore will use the language attribute defined in <site> definition (which by default is en). So I'd check if the language cookie is currently set. – Jarmo Jarvi Mar 7 '17 at 22:28
  • Does the 4 sites have the same domain? – Hishaam Namooya Mar 9 '17 at 20:03
  • Yes, they have the same domain. – Ashita Mar 9 '17 at 21:09
  • @HishaamNamooya: Each site has it's own language attribute set in the Site Definitions. Example: <sites> <site name="site-us" language="en" /> <site name="site-uk" language="en-gb" /> And so on </sites> – Ashita Mar 10 '17 at 14:15
3

Ok, this is a bit tricky - as there are a lot of different actors in play here - and I don't know exactly where you are patching in, and expecting what result.

However, let's list them.

StripLanguage

Processor sits in the <preprocessRequest> pipeline. Will internally rewrite your URL if it finds a language string embedded. So if your query string contains /en, it will be rewritten to /?sc_lang=en. If it does not find a language string, this processor does nothing.

The processor can be entirely disabled by the setting AlwaysStripLanguage on your LinkManager. If you are overriding language resolution logic, I recommend doing this - or removing the processor entirely.

SiteResolver

The resolver you have patched into, if I'm reading you right. No secondary language handling has happened at this time. If you do any redirect at this point in time, no language selection or change you make will never take permanent effect. That is to say, this depends a little bit on how you set it - please share the code to clarify.

LanguageResolver

Sits after SiteResolver. Will look for sc_lang=value in the querystring and set Context.Language if found. Context.Language will in turn set both Context.Items["sc_language"] and drop a language cookie - if a Site` has been identified.

Context.Language

Assuming none of the above have done anything, the default behaviour of Context.Language is to first look at Context.Items["sc_language"] and use it if found. If not found, it will look for a site language cookie (default sitename#lang). If one is found, use that language.

In summary

So? Can it be done? Yes. Your scenario can be achieved, but I'm not sure you're a) patching in the right places, and b) fully adhering to how language resolving is supposed to work.

Based on what I know from your question I would suggest you patch in just before the ItemResolver. Check language settings at this point, and redirect specifically to the site you want.

Alternatively

Patch in where you do now, on SiteResolver level. Be aware that, at this point, Context.Language will operate on defaults per the previous page request unless StripLanguage has detected a language and rewritten the url. If it has (which it would have, for /en, Context.Items["sc_language"] will have a value, same as Context.Language.

And I do apologise if this seems confusing; it really is slightly... cryptic, the way this is handled. I can probably give you a better and more direct answer, if I knew exactly how you patched in and the code you are injecting to the pipelines.

| improve this answer | |
  • Thanks for getting back to us. I have edited the question and added the code snippet. default sitename#lang: We see 4 of these in our cookies for 4 of our sites when we change the sites. site-us#lang : "en" site-uk#lang : "en-GB" site-ca#lang : "en-CA" site-au#lang : "en-AU" When we switch sites, site-us#lang value keeps changing depending on the current site. so sometimes it could be "en" or "en-gb" and so on. We thought we should mention it here since you spoke about it. We are unsure if it is supposed to behave in this way or not. – Ashita Mar 8 '17 at 15:31
0

I hope that something like

   if (HttpContext.Current.Request.RawUrl == "/en" && HttpContext.Current.Request.Url.AbsolutePath == "/")
                {
                    siteSpecified = string.Empty;
                }

near your code

 var siteLng = new Dictionary<string, string>
    {
        {"en", "site-us"},
        {"en-ca", "site-ca"},
        {"en-gb", "site-uk"},
        {"en-au", "site-au"}
    };

should help

| improve this answer | |
  • Hi, According to what I am thinking, when someone is on www.xyz.com/en-gb and now enters www.xyz.com/en, it will never consider "/en" and it will always return siteSpecified as empty, even when it is specified (this will take the user back to www.xyz.com/en-gb, since that is stored in the cookies). I did test this scenario and it does not work when I enter "/en" to switch my site from any other site. – Ashita Mar 9 '17 at 19:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.