In my previous post I described how Sharepoint configures CurrentUICulture and CurrentCulture properties of current thread based on SPWeb.Language. I also wrote that described algorithm is used only for application layouts page (pages which located in 12/template/layouts folder), but not for publishing pages (or content or site pages). And I said that I will write another blog post about setting of locale of current thread if request goes to publishing pages. And I keep my promise :)
Publishing functionality is available on sites with activated Publishing Infrastructure feature (there are several publishing features actually). By default it is activated on sites created with Publishing Site or Collaboration Site templates under Publishing category on site or site collection creation page. I would separate 2 types of pages in publishing infrastructure:
- publishing page layouts. They are provisioned into http://example.com/_catalogs/masterpage. You can find them in Site Settings > Master pages and page layouts
- publishing page instances – i.e. publishing pages itself. These are the pages which were created based on some publishing page layout. Most often publishing page instances are created in OTB Pages doclib (actually they should be created there because Sharepoint has several assumptions when handle publishing page instances. One of the assumption is that publishing page instance is located in Pages doclib. But this is not necessary, i.e. you can create publishing page instances in custom doclib also. In this case additional actions are required in order to avoid limitation of Sharepoint – this is out of scope of current blog post. I will write another post about it)
I.e. there is analogy with OOP: publishing page layouts are kind of “classes” of pages, and publishing page instances are “objects”. Often Sharepoint uses the following classes for mentioned pages:
- Microsoft.SharePoint.Publishing.PublishingLayoutPage for publishing page layout pages
- Microsoft.SharePoint.Publishing.TemplateRedirectionPage for publishing page instances
Both classes inherit PublishingCachablePage class which in turn inherits WebPartPage class. Lets see constructor of WebPartPage:
So if SPRequestModuleData.GetRequestData(…) method returns null for publishing page (in this case publishign page is treated as “exclusion” as you can see in code above) locale of current thread will be initialized from SPWeb.Locale and SPWeb.LanguageCulture of current web. But what if SPRequestModuleData.GetRequestData(…) method will return non-null result:
As you can see in our case it GetRequestData can return non-null result if HttpContext.Items collection contains instance of SPRequestModuleData (as 3rd parameter allowCreate is false). I will not deeply ananlyze in what cases Sharepoint returns null or not-nulls from GetRequestData. For this article it is enough that MOSS treats this situation as “exclusion”, i.e. I can assume that most of publishing pages should have non-null value returned from GetRequestData in constructor. Even more, if such situation occured, i.e. if GetRequestData returned null, see that last param “force” in Utility.SetThreadCulture is false also:
I already showed code of Utility.SetThreadCulture(), but it is important for this post also, so I will show it again:
I.e. even if publishing page is treated as exclusion – locale of current thread will be set only if HttpContext.Current = null (I think it is non-common situation) or when thread culture has not been initialized yet (HttpContext.Current.Items[IsThreadCultureSet] == null). So there should be a place where language is initialized for most of publishing pages (and this is not SPRequest.PreRequestExecuteAppHandler).
After analysis of all places where SetThreadCulture methods of SPUtility and WebPartPages.Utility classes are called, the most earlier place in pipeline where SetThreadCulture is called is SPWeb.InitWeb() method:
This method is called from constructor of SPWeb. So when current SPWeb is initialized for SPContext 1st time, Sharepoint sets locale of current thread (but with force = false in opposite to SPRequest.PreRequestExecuteAppHandler Sharepoint which calls this method with force = true. Actually there are no so many places where Sharepoint calls SetThreadCulture with force = true. I found only ThreadCultureScope class and mentioned SPRequest.PreRequestExecuteAppHandler). I.e. once SetThreadCulture method is called Sharepoint will use locale which was used in 1st call until next call with force = true. So for publishing pages mechanism a bit different. If for _layouts pages Sharepoint sets locale of current thread on later step explicitly (SPRequest.PreRequestExecuteAppHandler), for publishing pages Sharepoint sets locale of current thread on earlier steps in constructor of context SPWeb.
This is the internal mechanism of current thread locale initialization for publishing pages in Sharepoint.