14

I have a website that has 2 languages, lets say English (en) and Dutch (nl). Currently the site runs on a single domain, www.x.be. All is fine. But now the customer want to add another domain www.y.com to this site. We can add this domain to IIS and the site definition in Sitecore and it works - but... the actual requirement is that the site should run on www.x.be in "nl" and on www.y.com in "en".

We need this on first request (correct language must be set) and on language switch (all pages have a language selector). On all pages we have canonical urls and also a <link rel="alternate" ... hreflang=""> to point to the other language - all these links must be set right to make sure we have no duplicate content. I would prefer that all the links are set correctly automatically so that we can't make mistakes.

And we want to make sure that all requests that have a "bad" language are redirected to the correct domain.

For the redirects I will probably just use the IIS Rewrite module. But how should I do the setup in Sitecore to match a domain to a language? Would a custom link provider be sufficient? And how can I prevent hard-coding language/domain pairs?

1
  • 1
    I've flagged my favorite answer, but this approach to multi-language can seriously chew up your page's SEO rank. Oct 25, 2016 at 20:22

3 Answers 3

6

I think you will have to make this functionality yourself. You will most likely have to hook into the httpRequestBegin pipeline and also extend and replace the default LinkProvider.

Here's an (untested) example of how this can be approached.

Start by hooking into the httpRequestBegin pipeline and check if the language matches the language setting on the site definition.

public class SiteLanguageProcessor : HttpRequestProcessor
{
    public override void Process(HttpRequestArgs args)
    {
        var language = Sitecore.Context.Language;
        var siteLanguage = Language.Parse(Sitecore.Context.Site.Language);

        // If languages match, don't do anything
        if (language == siteLanguage)
            return;

        // TODO: Find correct site for current language and redirect to it
    }
}

This will take care of redirecting incoming requests to the correct site.

Next up we need to make sure generated links are also correct. For this we can extend the default LinkProvider and the LinkBuilder it uses. Here we can override the ResolveTargetSite(Item) method. If the site found by the base method doesn't match the requested language then we can go ahead and try to find a matching site.

public class SiteLanguageLinkProvider : Sitecore.Links.LinkProvider
{
    protected override LinkBuilder CreateLinkBuilder(UrlOptions options)
    {
        return new SiteLanguageLinkBuilder(options);
    }
}

public class SiteLanguageLinkBuilder : Sitecore.Links.LinkProvider.LinkBuilder
{
    private readonly UrlOptions _options;

    public SiteLanguageLinkBuilder(UrlOptions options) : base(options)
    {
        _options = options;
    }

    protected override SiteInfo ResolveTargetSite(Item item)
    {
        var targetSite = base.ResolveTargetSite(item);
        var targetLanguage = Language.Parse(targetSite.Language);

        // Site is correct if language match
        if (targetLanguage == _options.Language)
            return targetSite;

        // TODO: Find matching site
    }
}

This will take care of generating links to the correct site.

Here is a config file to patch all this in.

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:set="http://www.sitecore.net/xmlconfig/set/">
  <sitecore>
    <!-- Change default provider to our custom link provider -->
    <linkManager set:defaultProvider="custom">
      <providers>
        <!-- Add our custom link provider - set additional settings to your preferences -->
        <add name="custom" type="YourAssembly.SiteLanguageLinkProvider, YourAssembly"
              addAspxExtension="false"
              alwaysIncludeServerUrl="false"
              encodeNames="true"
              languageLocation="filePath"
              languageEmbedding="always"
              lowercaseUrls="true"
              shortenUrls="true"
              useDisplayName="false" />
      </providers>
    </linkManager>

    <pipelines>
      <httpRequestBegin>
        <!-- Patch after the language resolver (and after site resolver) -->
        <processor type="YourAssembly.SiteLanguageProcessor, YourAssembly" patch:after="processor[@type='Sitecore.Pipelines.HttpRequest.LanguageResolver, Sitecore.Kernel'"/>
      </httpRequestBegin>
    </pipelines>
  </sitecore>
</configuration>

You then need to have a site definition for each site/language with the language attribute set to the language supported for that site.

EDIT: There are actually some settings for site resolving which probably doesn't require you to extend the link provider as long as you make sure to set the targetHostName attribute on your site definitions.

<!--
  SITE RESOLVING
            While rendering item links, some items may belong to different site. Setting this to true
            make LinkManager try to resolve target site in order to use the right host name.
            Default value: true

-->
<setting name="Rendering.SiteResolving" value="true"/>
<!--
  RENDERING - SITE RESOLVING MATCH CURRENT LANGUAGE
            Affects how cross-site links are rendered when Rendering.SiteResolving is enabled.
            If true, the link provider will take the language attribute of the site definitions into consideration when resolving
            which site/hostname to use when rendering a cross-site link.
            Default value: true

-->
<setting name="Rendering.SiteResolvingMatchCurrentLanguage" value="true"/>
<!--
  RENDERING - SITE RESOLVING MATCH CURRENT SITE
            Affects how cross-site links are rendered when Rendering.SiteResolving is enabled.
            If true, the link provider will check if the target item is located under the start item for the current site before it
            tries to find a match in the full list of site definitions. This ensures that when the target item can be resolved using
            the current site, the target link will not change to a different site/hostname.
            Default value: true

-->
<setting name="Rendering.SiteResolvingMatchCurrentSite" value="true"/>
1
  • Accepting this answer as it comes closest to what I need - this way I don't need to add existing code that requests a url.
    – Gatogordo
    Oct 17, 2016 at 9:26
10

To deliver content in different languages per domain you need to create two sites in config and use language attribute in site definition. That attribute tells sitecore what language should be used if language is not explicitly defined in request.

<site 
  name="mySite-en" 
  language="en" 
  hostName="www.x.com" 
  targetHostName = "www.x.com" />
<site 
  name="mySite-nl" 
  language="nl" 
  hostName="www.x.be" 
  targetHostName = "www.x.be" />

hostName attribute routs requests to particular site. You can have multiple domains here delimited by pipe | and wildcards.

targetHostname attribute used by LinkManager to generate page links. It is very useful for cross sile references. In that you should define only one domain without wildcards.

Code snippet below shows how you can create link from en site to nl site:

var urlOptions = UrlOptions.DefaultOptions;
urlOptions.Site = SiteContext.GetSite("mySite-nl")
var url = LinkManager.GetItemUrl(item, urlOptions);

Canonical Url for sitecore is just another markup element that your page generates and you need to build custom code for it.

Using IIS Redirect module for missing languages will work, but it will not be manageable. You will have to manually update that rule every time when new page for only one site added. Moreover, for multiple CD instances you have to do it in every server.

Much better solution is to have some code in Sitecore where you can detect missing languages and redirect to another site. You need implement it once and it will cover all furure content changes.

Your detection/redirection logic can can be implemented as new processor for <httpRequestBegin> pipeline. You need to add it after ItemResolver.

 <httpRequestBegin>
    <processor patch:after="processor[@type='Sitecore.Pipelines.HttpRequest.ItemResolver, Sitecore.Kernel']"
       type="MyProcessorType, MyAssembly">
    </processor>   
  </httpRequestBegin>
2
  • 3
    You can also use the inherits attribute to inherit properties from another site definition so you don't have to maintain them twice (or more).
    – Thomas D
    Oct 14, 2016 at 12:33
  • 2
    I like this solution because it requires no programming to pull off if the existing renderings have been written with multi-site in mind. Oct 25, 2016 at 20:21
0

I thought this could be doing using the web.config Within this config file you can add a website as follow:

<site 
    name="website" 
    virtualFolder="/"
    physicalFolder="/" 
    rootPath="/sitecore/content"
    startItem="/home"
    language="en" 
    database="web" 
    domain="extranet" 
    allowDebug="true" 
    cacheHtml="true" 
    htmlCacheSize="10MB" 
    enablePreview="true"
    enableDebugger="true" />

If you set the language to the correct language correpsonding to the website you want want to pop-up for that website, you should be good to go.

Here is a reference article https://sdn.sitecore.net/Articles/Administration/Configuring%20Multiple%20Sites/Configuring%20Sites%20in%20web,-d-,config%20File.aspx

If this did not work out for you, please let me know.

5
  • Isn't the language setting in the site configuration just the default language? Will Sitecore really create url's to the other domain when requested?
    – Gatogordo
    Oct 14, 2016 at 9:12
  • The thing you can do is set up the site as a multilanguage site, you then will be send to the content items containing the requested language. Using that, you only have to set up 1 website only mutiple languages and you can just redirect the domain to the other website. Oct 14, 2016 at 9:25
  • 4
    I just don't see with this setup how Sitecore will know that the system should not generate url's for domain A in language B. If I request the url for an item in another language, Sitecore will give it to me in the current domain as it does not know that that is not allowed. Which is not what I need..
    – Gatogordo
    Oct 14, 2016 at 9:36
  • Sorry than i misinterpreted your question. Oct 14, 2016 at 13:37
  • No problem.. all ideas are welcome
    – Gatogordo
    Oct 14, 2016 at 13:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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