Variations sind im SharePoint dasMittel der Wahl, wenn es um Mehrsprachigkeit geht. Ohne diesen out-of-the-box Mechanismus müsste man einen eigenen Weg implementieren, um Inhalte von einer Sprache in einen anderen, sprachbezogenen Kontext zu transportieren. Dies kann sehr kostspielig werden! Um mehrsprachige Inhalte im SharePoint verwalten zu können, kommt man also um Variationen nicht herum.

Vor der Entwicklung neuer Komponenten steht man als Entwickler oft vor der undankbaren Aufgabe sein Portal mit Inhalten und Struktur zu füllen, damit eine Grundlage für die Entwicklungsphase gegeben ist.  Das Anlegen von Websitesammlungen, Websites, Listen, etc. kann mit Hilfe kleiner Tools oder mit PowerShell über die SharePoint API automatisiert werden. Sobald man es allerdings mit Variations zu tun hat, gibt es leider keine Möglichkeit dies über die API zu realisieren. Die Methoden dafür sind nicht öffentlich verfügbar.

Nun kommt es aber doch öfters vor, dass eine Entwicklungs-, Integrations- oder QS-Maschine initial oder erneut aufgesetzt werden muss. Hat man nun mehrere Websitesammlungen, in denen Variationen angelegt werden müssen, dann hat man eine Menge “Klickerei” vor sich, bis alles angelegt ist und funktioniert wie es soll.

Aus diesem Grund habe ich mir angeschaut, was überhaupt intern passiert, wenn SharePoint Variationen und Variationsbezeichnungen anlegt. Und wie sollte es anders sein – es funktioniert über interne Listen, die entsprechend gefüllt werden, so dass ein Timerjob (“Variations Create Hierarchies Job Definition”) die Hierarchien anlegt und pflegen kann.

Um die, für die Anlage von Variationen, nötigen Aktionen dennoch automatisieren zu können, habe ich den Mechanismus analysiert und nachgebaut.   Nachfolgend ein paar Auszüge.

Anlegen der Variation

private static void CreateVariations(string url, SiteCreationData sData)
        {
            using (SPSite site = new SPSite(url))
            {
                HvVariationSettings variationSettings = new HvVariationSettings(site, false);
                try
                {
                    PublishingWeb pWeb = PublishingWeb.GetPublishingWeb(site.RootWeb);
                    variationSettings.RootPublishingWeb = pWeb;
                    variationSettings.UserConfiguredEnableAutoSpawn = false;
                    variationSettings.StopAutoSpawnAfterDelete = false;
                    variationSettings.UpdateWebParts = true;
                    variationSettings.CopyResources = false;
                    variationSettings.SendNotificationEmail = false;
                    variationSettings.Update();

                    Console.WriteLine("Variation created for " + site.Url);
                    CreateVariationLabel(variationSettings, sData);
                    Console.WriteLine("Variation labels created for " + site.Url);

                    CreateHierarchy(site);
                    Console.WriteLine("Variation hierarchy ceated for " + site.Url);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Creating variations failed: "+ex.ToString());
                }
                finally
                {
                    if (site != null)
                    {
                        site.Dispose();
                    }

                    if (variationSettings != null)
                    {
                        variationSettings.Dispose();
                    }
                }
            }
        }

Unter der Haube werden die Variation-Informationen in das PropertyBag des Hauptverzeichnisses der internen Liste “/Relationships List” geschrieben. Die Variationsbezeichnungen hingegen landen als Listeneinträge in der internen Liste “/Variation Labels”.

Anlegen der Variationsbezeichnungen

 private static void CreateVariationLabel(HvVariationSettings variationSettings, SiteCreationData sData)
        {
            SPList variationLabelsList = variationSettings.VariationLabelsList;
            SPListItem spListItem;

            spListItem = variationLabelsList.AddItem();
            ((SPItem)spListItem)["Hierarchy Is Created"] = false;

            bool isRootVariation = true;

            spListItem[SPBuiltInFieldId.Title] = sData.DeTitle;
            ((SPItem)spListItem)["Description"] = "ToDo: Set german description";
            ((SPItem)spListItem)["Flag Control Display Name"] =  sData.DeTitle;
            ((SPItem)spListItem)["Language"] = "de-DE";
            ((SPItem)spListItem)["Locale"] = "1031";
            ((SPItem)spListItem)["Hierarchy Creation Mode"] = "Publishing Sites and All Pages";
            ((SPItem)spListItem)["Is Source"] = isRootVariation;

            if (isRootVariation)
            {
                variationSettings.SourceRootWebTemplate = "BLANKINTERNET#2";
                variationSettings.Update();
            }
            spListItem.Update();

            // english variation
            spListItem = variationLabelsList.AddItem();
            ((SPItem)spListItem)["Hierarchy Is Created"] = false;

            isRootVariation = false;

            spListItem[SPBuiltInFieldId.Title] = sData.EnTitle;
            ((SPItem)spListItem)["Description"] = "ToDo: Set english description";
            ((SPItem)spListItem)["Flag Control Display Name"] =   sData.EnTitle;
            ((SPItem)spListItem)["Language"] = "en-US";
            ((SPItem)spListItem)["Locale"] = "1033";
            ((SPItem)spListItem)["Hierarchy Creation Mode"] = "Publishing Sites and All Pages";
            ((SPItem)spListItem)["Is Source"] = isRootVariation;
            if (isRootVariation)
            {
                variationSettings.SourceRootWebTemplate = "BLANKINTERNET#2";
                variationSettings.Update();
            }
            spListItem.Update();

            // france variation
            spListItem = variationLabelsList.AddItem();
            ((SPItem)spListItem)["Hierarchy Is Created"] = false;

            isRootVariation = false;

            spListItem[SPBuiltInFieldId.Title] = sData.FrTitle;
            ((SPItem)spListItem)["Description"] = "ToDo: Set franc description";
            ((SPItem)spListItem)["Flag Control Display Name"] =  sData.FrTitle;
            ((SPItem)spListItem)["Language"] = "fr-FR";
            ((SPItem)spListItem)["Locale"] = "1036";
            ((SPItem)spListItem)["Hierarchy Creation Mode"] = "Publishing Sites and All Pages";
            ((SPItem)spListItem)["Is Source"] = isRootVariation;
            if (isRootVariation)
            {
                variationSettings.SourceRootWebTemplate = "BLANKINTERNET#2";
                variationSettings.Update();
            }
            spListItem.Update();
        }

Mit Hilfe dieser Provisionierungs-Lösung für Variationen kann sehr viele Zeit eingespart werden. Und vor allem sind die Systeme danach auf jeden Fall identisch aufgebaut.

Für den Aufbau eines Live-Systems würde ich diesen Mechanismus allerdings nicht verwenden, da ich keine Aussage von Microsoft bzgl. der Supportbarkeit habe. Ich tippe allerdings auf ein “Nein”. Daher sollte die automatische Provisionierung nur auf Entwicklungssystemen genutzt werden.

Wenn dieser Artikel eins verdeutlicht, dann dass es mit SharePoint immer einen Lösungsweg gibt!!!

Leave a comment

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Time limit is exhausted. Please reload the CAPTCHA.