This post has been migrated from www.experimentsincode.com, we apologise if some of the images or content is missing

This is for Sitecore 5.3, there is an alternative Sitecore 6 default language provider Imagine a site built in Sitecore that has multiple languages but not all pages are translated into the different language. When a visitor to the site visits a page that has not been translated they normally receive a 404 error. However you may not want this, instead you might want it to use a default language instead. The user will no longer see a 404 error but will have any missing content replaced by the default language. There are two was to do this, we can either create our own set of classes to wrap the XSLT extensions, XSLT controls and code references or we can alter the way the data is pulled from the database. I have decided to go with altering the data pulled from the database because this is less work and easier to manage. The way this solution works is that it checks every item pulled from the database to see what language versions are available for that item. If the item is missing a particular language it will then inject the default language. If you are using SQL Server the class that does the data pulling is called Sitecore.Data.SqlServer.SqlServerDataProvider and can be found in Sitecore.SqlServer.dll. Using the decorator pattern we inherit from this class like so:
  1. public class SqlServerDataProvider : Sitecore.Data.SqlServer.SqlServerDataProvider
  2. {
  3. public SqlServerDataProvider(string connectionString)
  4. : base(connectionString)
  5. {
  6. }
  7. protected override void LoadItemFields(string itemCondition, string fieldCondition, object[] parameters, Sitecore.Collections.SafeDictionary<ID, Sitecore.Data.DataProviders.PrefetchData> prefetchData)
  8. {
  9. base.LoadItemFields(itemCondition, fieldCondition, parameters, prefetchData);
  10. //set the default language to use
  11. Language defaultLang;
  12. Language.TryParse("en", out defaultLang);
  13. //full list of languages the site uses
  14. LanguageCollection coll = this.GetLanguages();
  15. foreach (var data in prefetchData)
  16. {
  17. if (data.Value != null)
  18. {
  19. var uris = data.Value.GetVersionUris();
  20. //check the item contains the default language before doing anything
  21. if (uris.Cast<VersionUri>().Any(x => x.Language == defaultLang))
  22. {
  23. //get the default language fields
  24. var defaultUri = uris.Cast<VersionUri>().First(x => x.Language == defaultLang);
  25. //loop through each language
  26. foreach (Language lang in coll)
  27. {
  28. //check if language doesn't exist
  29. if (!uris.Cast<VersionUri>().Any(x => x.Language == lang))
  30. {
  31. //update language with default language values
  32. FieldList fields = data.Value.GetFieldList("en", defaultUri.Version.Number);
  33. foreach (var field in fields)
  34. {
  35. data.Value.AddField(lang.Name, 1, field.Key, field.Value);
  36. }
  37. }
  38. }
  39. }
  40. }
  41. }
  42. }
  43. }
    public class SqlServerDataProvider : Sitecore.Data.SqlServer.SqlServerDataProvider
    {

        public SqlServerDataProvider(string connectionString)
            : base(connectionString)
        {
        }
        protected override void LoadItemFields(string itemCondition, string fieldCondition, object[] parameters, Sitecore.Collections.SafeDictionary<ID, Sitecore.Data.DataProviders.PrefetchData> prefetchData)
        {
            base.LoadItemFields(itemCondition, fieldCondition, parameters, prefetchData);

            //set the default language to use
            Language defaultLang;
            Language.TryParse("en", out defaultLang);

            //full list of languages the site uses
            LanguageCollection coll = this.GetLanguages();

            foreach (var data in prefetchData)
            {
                if (data.Value != null)
                {
                    var uris = data.Value.GetVersionUris();
                    //check the item contains the default language before doing anything
                    if (uris.Cast<VersionUri>().Any(x => x.Language == defaultLang))
                    {
                        //get the default language fields
                        var defaultUri = uris.Cast<VersionUri>().First(x => x.Language == defaultLang);
                        //loop through each language
                        foreach (Language lang in coll)
                        {
                            //check if language doesn't exist
                            if (!uris.Cast<VersionUri>().Any(x => x.Language == lang))
                            {
                                //update language with default language values
                                FieldList fields = data.Value.GetFieldList("en", defaultUri.Version.Number);
                                foreach (var field in fields)
                                {
                                    data.Value.AddField(lang.Name, 1, field.Key, field.Value);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
Now that we have our code we need to update the web.config to use our new class. First we need to add our class as a new provider. Find the following section in the Sitecore section of the web.config.
  1. <!-- DATA PROVIDERS -->
  2. <dataProviders>
  3. <main type="Sitecore.Data.$(database).$(database)DataProvider, Sitecore.$(database)">-->
  4. <param ref="connections/$(1)" />
  5. <Name>$(1)</Name>
  6. </main>
<!-- DATA PROVIDERS -->
<dataProviders>
	 <main type="Sitecore.Data.$(database).$(database)DataProvider, Sitecore.$(database)">-->
	 	 <param ref="connections/$(1)" />
	 	 <Name>$(1)</Name>
	 </main>
Update it as shown below so that you now have two providers:
  1. <dataProviders>
  2. <main type="Sitecore.Data.$(database).$(database)DataProvider, Sitecore.$(database)">-->
  3. <param ref="connections/$(1)" />
  4. <Name>$(1)</Name>
  5. </main>
  6. <web type="Demo.Data.SqlServerDataProvider, Demo">
  7. <param ref="connections/$(1)" />
  8. <Name>$(1)</Name>
  9. </web>
<dataProviders>
	 <main type="Sitecore.Data.$(database).$(database)DataProvider, Sitecore.$(database)">-->
	 	 <param ref="connections/$(1)" />
	 	 <Name>$(1)</Name>
	 </main>
	 <web type="Demo.Data.SqlServerDataProvider, Demo">
	 	 <param ref="connections/$(1)" />
	 	 <Name>$(1)</Name>
	 </web>
We then just need to update the relevant databases to use this class. I am assuming that only the web database will use this class. In which case find the following section in the web.config:
  1. <database id="web" singleInstance="true" type="Sitecore.Data.Database, Sitecore.Kernel">
  2. <param desc="name">$(id)</param>
  3. <securityEnabled>true</securityEnabled>
  4. <dataProviders hint="list:AddDataProvider">
  5. <dataProvider ref="dataProviders/main" param1="$(id)">
 <database id="web" singleInstance="true" type="Sitecore.Data.Database, Sitecore.Kernel">
	 <param desc="name">$(id)</param>
	 	 <securityEnabled>true</securityEnabled>
	 	 <dataProviders hint="list:AddDataProvider">
	 	 	 <dataProvider ref="dataProviders/main" param1="$(id)">
Update the providers list to look like this:
  1. <database id="web" singleInstance="true" type="Sitecore.Data.Database, Sitecore.Kernel">
  2. <param desc="name">$(id)</param>
  3. <securityEnabled>true</securityEnabled>
  4. <dataProviders hint="list:AddDataProvider">
  5. <dataProvider ref="dataProviders/web" param1="$