Sitefinity has great multilingual publishing capabilities. From the perspective of an end-user / content manager, the backend offers up a myriad of methods to create content items both in the site’s default language as well as any other languages activated/enabled in the site itself. They’re all usually just one click away, and provide a good experience.
But what about the development side of things? Say we have a custom widget that creates a content item, but the language either must be something apart from the default, or is user-selectable before creation occurs? How do we instruct Sitefinity via the API to publish our content item in another language? Let’s find out by trying to create a new News item (but what we do here will also work for dynamic content).
Let’s say we had a custom widget that gives us some basic fields for news, including some custom fields, as well as specifying what language we want to Publish in. This widget gives us an object of type “CreateNewsViewModel” that has these fields populated for us. The CreateNewsViewModel looks something like this:
In our case we set some built-in fields, a couple custom fields, a Tag (passing along its ID), and what Culture (i.e. Language) we wish to store.
At this point you might be asking how we get SelectedCultureName. Easy! Sitefinity’s API exposes the currently-available languages to the frontend, and we can use that list to create a dropdown selector in our widget, then passing along the selected culture’s name in our above model. The code to fetch the available cultures is:
In our method (coming up in the next bit) we’ll take the name, and get our Culture object back (because it’s easier to pass strings around to/from an MVC model, and to verify that we didn’t get junk data / invalid culture info).
Now we get to the fun part. The first step in multilingual publishing is to simply do what you always do when creating a news item by invoking the NewsManager:
You see for our built-in short text fields Title and Summary that we’re simply calling “SetString()” on them, passing the culture first and the value we wish to store second. In multilingual publishing the culture object is key! Note that for long text fields (Content in this case) the syntax is different. Wait what?
But what about long text fields like Content? The code lets us call “item.Content.SetString(culture, viewModel.Content)”, so why the inconsistency? In fact, there’s also an array indexer built into Sitefinity LStrings that would let us call “item.Content[culture] = viewModel.Content” instead of the more cumbersome SetString method!
As it turns out, while Sitefinity and its LString class has those capabilities exposed for use in its API, they do not function correctly. They either still store the data in the default language field, or simply do not record the value at all! You have to call “SetString” on the data item itself (in this case, the “item” variable we created), passing the field name, string to store, and then the culture, otherwise it will not work.
If you like consistency, you can also use the exact same syntax for the short text fields, so that all field setting (short text or long text) is consistent in your code. While I do like consistency, I also like using the strongly-typed fields where possible (using item.Title instead of item.SetString(“Title”)) because the value of the strings aren’t validated (i.e. throw an exception) until runtime. It’s entirely up to you though!
With that in mind, let’s continue with multilingual publishing.
This one’s easy enough. Since there is no strongly-typed property we can set for custom fields, we simply use the same method for custom fields that we do for long text fields:
For fields such as classifications, non-strings (i.e. booleans), etc., set them like you would any normal content item. They don’t have translatable fields so there’s nothing special to do here when doing multilingual publishing. Here we set our custom boolean field and our Tags field, as well as the boilerplate date content fields like we would normally:
Since each version of the news item will have its own URL Name, we need to set it like we would any other translatable string:
We’ve reached the end of our method! All we have to do now is invoke the usual publishing methods Sitefinity exposes, only passing along the Culture where necessary. Once we do that, our multilingual publishing process is complete!
In this case you see we’re calling the “SetString” method on ApprovalWorkflowState, and are passing along the culture to the Publish and SetWorkflowStatus methods as well. Once we save those changes, our news item is created using the culture we specified. We’ve done it!
For convenience here’s the entire method we pieced together above:
Multilingual publishing using the Sitefinity API is easy. There are some pitfalls to avoid and there’s a little bit of syntax involved, but it largely revolves around curating the appropriate Culture object, and passing that in whenever you need to set a translatable field. Not all fields are translatable, but for those the Culture object is ignored entirely and you just do what you normally do.
The above will work with custom content types as well. Instead of NewsManager, you use DynamicModuleManager. And since everything is a custom field, you simply use the item.SetString(“MyField”, stringValue, culture) syntax we used for some of the fields for news items.
And that’s that. You now have the power of multilingual publishing at your fingertips.