This blog post describes a technique that you can use to prevent the Sitecore ASP.NET web Content Management System (CMS) and Experience Platform (XP) from interpreting the first step in the path in a requested URL as a language.
The StripLanguage processor in the preprocessRequest pipeline attempts to remove the language from the path and rewrite the URL. In some cases, the StripLanguage processor can interpret values that are actually item names as language names. For example, in a default configuration, if you create an item named "da" under the home item, and try to request that item with a URL such as http://instance/da, the StripLanguage processor will interpret "da" as the Danish language and remove it from the URL. When the ItemResolver processor in the httpRequestBegin pipeline later attempts to determine the context item, it will not find "da" in the requested path, and will set the context item to the home item rather than the child of the home item named "da".
Assuming a default configuration, there are at least two potential ways to disable this logic:
Another solution could be to override the StripLanguage processor to specify the values that it should interpret as languages (or alternatively, values that StripLanguage should not interpret as languages).
namespace
SitecoreJohn.Pipelines.PreprocessRequest
{
using
System.Collections;
Sitecore.Web;
public
class
StripLanguage :
Sitecore.Pipelines.PreprocessRequest.StripLanguage
private
ArrayList _validLanguages =
new
ArrayList();
void
AddValidLanguage(
string
language)
this
._validLanguages.Add(language.ToLower());
}
override
Process(
Sitecore.Pipelines.PreprocessRequest.PreprocessRequestArgs args)
if
(args !=
null
&& args.Context !=
&& !
.IsNullOrWhiteSpace(args.Context.Request.FilePath))
prefix = WebUtil.ExtractLanguageName(
args.Context.Request.FilePath);
((!
.IsNullOrWhiteSpace(prefix))
._validLanguages.Contains(prefix.ToLower()))
return
;
base
.Process(args);
You can use a Web.config include file such as the following to enable and configure this processor:
<
configuration
xmlns:patch
=
"https://www.sitecore.com/xmlconfig/"
>
sitecore
pipelines
preprocessRequest
processor
type
"Sitecore.Pipelines.PreprocessRequest.StripLanguage, Sitecore.Kernel"
patch:attribute
name
"type"
>SitecoreJohn.Pipelines.PreprocessRequest.StripLanguage, SitecoreJohn</
allowedLanguges
hint
"list:AddValidLanguage"
en
>en</
</
To add an allowed language, add another element like <en>en<en>, where the name of the element does not matter (but might as well be the name of the language); the text value within the element is the allowed value.
This approach has some disadvantages:
Since I know that *somebody* will eventually ask, I will try it the harder way (mapping domain names to allowed languages). This approach could have issues as well, specifically if one of the managed sites associated with a single domain should strip the language and some should not. The StripLanguage processor records the language stripped from the path in the Sitecore.Context.Data.FilePathLanguage property. I assume that in some cases, you could add that language back to the URL after the SiteResolver processor. I do not know for sure; maybe there is no issue, or maybe there is a better solution.
System.Xml;
Sitecore.Diagnostics;
Hashtable _validLanguages;
ConfigureValidLanguages(XmlNode config)
Assert.IsNotNull(config,
"config"
);
._validLanguages =
Hashtable();
foreach
(XmlNode domainNode
in
config.SelectNodes(
"./*"
))
ArrayList langs =
(XmlNode langNode
domainNode.SelectNodes(
Assert.IsNotNull(langNode.InnerText,
"langNode.InnerText"
langs.Add(langNode.Name.ToLower());
._validLanguages.Add(domainNode.Name.ToLower(), langs);
.IsNullOrWhiteSpace(args.Context.Request.FilePath)
&&
._validLanguages !=
)
(!
Assert.IsTrue(
._validLanguages.Contains(args.Context.Request.Url.Host),
"invalid configuration for "
+ args.Context.Request.Url.Host);
(!((ArrayList)
._validLanguages[args.Context.Request.Url.Host]).Contains(
prefix))
The Web.config include file:
"raw:ConfigureValidLanguages"
sc150223
/>
localhost
Note that without modification, this requires some duplication of configuration (for example, to support both domain.tld and www.domain.tld) and cannot support IP addresses, which are not valid as XML element names (you could store the domain name in an attribute rather than using the element name).
Of course you could do the opposite – rather than listing the allowed languages, you could list prefixes to ignore. My thought is that this would require more frequent configuration updates, as I expect to add languages infrequently, but could add top-level items at any time.
As I tried to indicate above, I expect that this code could result in new issues, especially under various configurations. As always, do not just laugh at my code. Instead, refactor it, test it, and make it work for your solution. This is just a proof of concept.
sitecorecontextitem.wordpress.com/.../
Hi John, This post was very helpful. One improvement concerning the languages is that, we can directly retrieve the languages from Sitecore itself since all languages will be stored in Sitecore/System/Languages. This will therefore allow for extensibility and without each time editing the config file to add new language.
@Hishaam: Because preprocessRequest runs before httpRequestBegin, which contains DatabaseResolver, I am not sure that one should access Sitecore.Context.Database from such a processor (it might work, but I don't know if it would use the same/correct resolution logic as the DatabaseResolver). As an alternative, you could pass a database name to the processor rather than the list of languages, but that would result in using the same database for all managed sites (maybe this is acceptable). At some point, a degree of caching around this data may be beneficial.
Hi @John, I found an alternative to resolve the database as well the sitecore context. loic-rabehaja.squarespace.com/.../prevent-sitecore-aspnet-cms-from-interpreting-url-path-as-language-rabehaja-loic-sitecore This approach dynamically uses languages available in the database depending on the Sitecontext. Hence we can get rid of the patch of config file. I think that adding cache on this approach as well would be great since this preprocessor is always triggered on each request.