My colleague got a task to create a way of localizing file metadata. The requirements were to be as close to regular page translations that come out of the box. Unfortunately EPiServer does not support this kind of functionality yet so he needed to code it himself.

localized media - expected result

After a little research he found a blog post from 2014 with a hint on how to solve this problem. In that implementation the DataFactory LoadedContent, LoadedChildren and SavingContent events were used to store translations in DDS. My colleague tried to use the code and it looked like everything worked properly. The editor was able to edit alt text and show the content in different languages on frontend side.
But there were a few limitations regarding client requirements:

  • After switching the language, the plugin would automatically load media from currently selected culture – there was no explicit Translate button.
  • EPiServer fallbacks configuration was not used.

How the page localization works

He looked closer into how page localization works internally. Why the page can be localized while the media doesn’t. It should be possible, because they both inherit from ContentData class and implement the IContent interface right? 😉

However, it turned out that in fact there is a difference between PageData and MediaData. It’s all about EPiServer.Core.ILocalizable interface which is not implemented by MediaData.

The interface exposes two properties:

  • ExistingLanguages – return all existing languages for content,
  • MasterLanguage – returns the master language for content.

He tried to simply add the ILocalizable interface to ImageFile media model.

Implementation

Implementing ILocalizable interface in ImageFile class was not difficult. Just added those two properties to the class :).

The code compiled, but the media still didn’t worked. In translated versions the image was not available (404 status was returned). The problem was that the BinaryData property is stored in CultureSpecific way. The MediaData implements the IBinaryStorable interface which is the key here.

Localizable media - Class diagram

Class diagram

The IBinaryStorable interface is used by RawContentRetriever class to create content. In the CreateRawContent methods, the list of content properties is extended. The list of new properties depends on which interfaces are implemented by the content (like IVersionable, IResourceable, ICategorizable etc.). After IBinaryStorable is implemented, then BinaryData string property is added.

The last parameter of MetaData class constructor is boolean isLanguageSpecific which is set to true. It means that for different languages media could store different binary content. Usually the editor don’t need to change the whole image, but for example just the alt text.

When clicking Translate on a media item, a new language branch is created. All culture specific properties are set to null. This is why this solution did not worked. The property with media URL was blank. In this case it should be treat as not localizable. So the only thing that have to be overridden is the behavior of BinaryData and Thumbnail properties. We need to ensure that the value is always loaded from Master Language.

Now the edit mode for Media looks like for Pages and Blocks.

Localized media - translate button

Translate button

The All properties editing where non-localizable properties are in readonly state.

Localized media - editing properties

Editing properties

The full source code is below: