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.