This blos post describes how you can override the logic that the Sitecore ASP.NET CMS uses to determine the context language.
This is an almost direct, untested repost of http://sitecorejohn.spaces.live.com/blog/cns!960125F1D4A59952!165.entry from November of 2008. Please comment below if this solution does not work for you.
The Sitecore layout engine retrieves content from the Sitecore repository in the context language (Sitecore.Context.Language). The default logic to determine the context language is to use the first of these variables that specifies a value:
In the first two cases, Sitecore generates a session cookie so that subsequent requests do not have to include the URL query string or language prefix in the URL. If the user returns to the site without specifying the URL query string parameter or the language prefix in the URL path, their language selection would be lost.
If the organization has not published a translation of the context item in the context language, Sitecore acts as if all fields in that item are empty.
Some solutions need to augment the default logic for determining the context language. For instance, the developer may want to:
Additionally, ASP.NET uses the System.Threading.Thread.CurrentThread.CurrentUICulture and System.Threading.Thread.CurrentThread.CurrentCulture properties for localization, such as formatting dates. Sitecore does not set these properties based on the context language, so they default to the operating system configuration. It might be helpful if the language resolution logic set these properties.
The following solution is relatively untested but could provide inspiration for a production-quality solution to meet these requirements.
Sitecore.Context.Language is a smart property, which means it follows the lazy load pattern: if code accesses this property when nothing has set it, the getter for the property contains logic to determine the context language.
Sitecore uses the Sitecore.Pipelines.HttpRequest.LanguageResolver processor in the httpRequestBegin pipeline to determine the context language. Because Sitecore.Context.Language is a smart property, this processor probably isn't necessary, as some subsequent logic in the processing of the request is almost guaranteed to access Sitecore.Context.Language. In any case, we want to override this logic. Normally when adding logic to a pipeline, we replace an existing processor with our processor, or add our processor before or after a default processor. But in this case our processor depends on Sitecore.Context.Item, and therefore must appear after the Sitecore.Pipelines.HttpRequest.ItemResolver processor which sets the Sitecore.Context.Item property. Without investigating, we don't know whether processors between Sitecore.Pipelines.HttpRequest.LanguageResolver and Sitecore.Pipelines.HttpRequest.ItemResolver use Sitecore.Context.Language, so we'll just leave that default Sitecore.Pipelines.HttpRequest.LanguageResolver alone and add our processor after Sitecore.Pipelines.HttpRequest.ItemResolver.
You can download my prototype for the httpRequestBegin pipeline processor and compile it into your Visual Studio project. This code could definitely use some refactoring.
Add the custom processor after the default Sitecore.Pipelines.HttpRequest.ItemResolver processor in web.config:
<processor type="Sitecore.Pipelines.HttpRequest.ItemResolver, Sitecore.Kernel" /><processor type="Namespace.Pipelines.HttpRequestBegin.LanguageResolver, assembly"> <persistLanguage>true</persistLanguage> <setCulture>true</setCulture></processor>
If you don't want to create a persistant cookie to persist the user's language preference between browser sessions, set the value of the <persistLanguage> element to false, or simply remove this property setter.
To support fallback languages:
Note that asNeeded is the default value for the languageEmbedding attribute of the /configuration/sitecore/linkManager/providers/add element in web.config that controls the logic for generating friendly URLs. The logic applied for this value may not be exactly what you expect, which can result in multiple URLs for a single content item in a single language. I recommend setting languageEmbedding to always for solutions that involve multiple languages, or never otherwise.
The following properties, which default to false unless set in the processor signature in web.config, serve the purposes described:
The following methods serve the purposes described:
One thing that concerns me is how ASP.NET uses the language associated with the current thread. If we assume that the entire system processes the entire request using this thread, or passes this setting to any child threads, then I think this should be reliable. But this is obviously far beyond my knowledge of ASP.NET threading. For me, it seemed to work using the Sitecore.Web.UI.WebControls.FieldRenderer Web control, the <sc:date> XSL extension control, and a custom XSL extension method, but my test system doesn't have the kind of load that might raise threading issues.
"Note that asNeeded is the default value for the languageEmbedding attribute ... The logic applied for this value may not be exactly what you expect, which can result in multiple URLs for a single content item in a single language. I recommend setting this to always for solutions involving a single language, or never otherwise." Shouldn't that be the other way around? Why would I want or need to embed language in the URL if I only had one language? I also need my multiple languages to ccrawled by search engines, so the URL embedding offers me quesry string and session independent paths to language versioned content.
@James - yes, I will correct that. Thanks!
Thanks for the reply, apologies for apparently typing the above with six thumbs!
Is it safe to use this as a replacement for the item fallback code found in the Presentation Component Cookbook section 5.2.6?
@Bryan: I think that falling back at the item level is too simple for most requirements - you generally want to fall back at the field level instead. I suggest that you investigate this solution instead: trac.sitecore.net/LanguageFallbackItemProvider Personally, I don't like complex language fallback, or mixing languages on a page.
In regards to the order of the logic: 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. I am seeing that it behaves slightly different. A language cookie appears to overwrite the language prefix in the path in the request URL. Example: My browser is set to "English (United Kingdom)"; the cookie value is "en-GB", and when I go to: dev.mysitecoresite.com/.../home.aspx I receive the "en-GB" content. I would prefer to get the "en-CA" content because it's in the URL path. Can this be achieved? Thanks, Russ
I digress. I actually had a separate issue. The original logic sequence appears to be working as you stated. Thanks, Russ
Hi, I am having an issue with the language in the url. My problem is as follows: When loading a URL, for example, http://[domainName]/article-box/, I got an error in the CultureNotFound exception. It takes the article-box as a culture or language. Can you please provide me some advice how to solve this issue. Sorry for this question since i'm new to sitecore. Thanks
It sounds like Sitecore interprets article-box as a language, when it should not. You have a few options. If you never include a language in the URL, then I think you can simply set the languageEmbedding attribute under linkManager in web.config to false. If you sometimes include the language in the URL (which I would not - for SEO, either the URL should always contain the language, or it should never contain the language, to avoid multiple URLs for a single page), then you may need to override the StripLanguage processor in the preprocessRequest pipeline. Actually, you may just want to upgrade, as I believe later versions may address this issue (Sitecore should only interpret URL prefixes as languages if a corresponding language exists, which is not the case for URLs such as /article-box - you might be facing a defect fixed in a later version). If your URL is actually something more like /en-US and you cannot set languageEmbedding to never, then you may need to address StripLanguage, to avoid interpreting specific URL prefixes as languages.
Thanks for your reply John. Based on the information you provided in the comment, I've been able to solve the issue. That is, the /article-box is no longer being seen as a culture/language. I've used the strip language and modified the ExtractLanguage method. However, when entering the sitecore CMS, it leads to and error 404. Can you help me on this issue or is there any patch that can fix the bug in sitecore as you said there might be a fixed for this issue in a later version. The sitecore version being used is 7.0 Thanks again for your help
@Hishaam: Switching to email.