Tuesday, 17 November 2015

Custom multilingual text in SharePoint Online using Taxonomy and JSOM

I have been working on an Office 365 intranet which will be rolled out globally. Naturally, one of the core requirements of the solution is that it should be multilingual. In my previous posts on this topic, Modify Site Regional and Language settings with JSOM and JavaScript, we had a look at how to set alternate languages for a site and in Update user language and regional settings with CSOM, we saw how to set the preferred display languages for a user.

This allows a user to see the SharePoint site chrome in their own preferred language. Now in this post, lets have a look at how to have localized custom text so that the user can see custom labels, headings etc. in their preferred language.

Some notes around this:

1) This approach is based on the multilingual features of SharePoint Term Sets:


It is possible to have multi-lingual term sets because each term in a term set has a unique ID and each term can have multiple labels. You can designate a default label for a term in each language available for a term store. A term can then have multiple synonyms in each of these languages, as well as labels and synonyms in other languages.

Users will also see managed terms displayed in their preferred language, regardless of the actual default language of the term store.

If no labels are specified for terms in the language in which a user is viewing a term, then the default label for the term in the default language of the term store will be displayed to users.

https://support.office.com/en-us/article/Work-with-multi-lingual-term-sets-D04098AF-282B-45C3-97CB-59363042C1B3

3) Based completely on JSOM, JavaScript and the SharePoint Term Store.


4) This approach is built on top of the MUI features in SharePoint. Which means that the user created content such as list item data, documents etc. will NOT be translated.


5) The SharePoint Online Term Store is treated as a "data source" for custom multilingual text. Each custom text is a term in the "Translations" term set. For each language that you have to support add a new label to the term for that language.


Lets get started:

1) Setup the Term Store to support term labels in multiple languages


I have set the default language of the Term Store as English and then added Dutch as a Working Language. This means that the term store will be able to support labels for a term in English as well as Dutch.



After adding the working languages, I have created a new Term Group called "My Group".
Under "My Group", I have created a Term Set called "Translations".
Under "Translations", I have created 3 terms: Communications, Marketing and News.
We will use these 3 terms to show the custom multilingual text.

We need to add the default language labels for each term:



After a label has been specified for each term, they will appear in the following way:

When English (default) is selected:



When Dutch is selected:



The translation framework will work in the following way:

If I am an English user and I have set my preferred language as English, when the terms for the "Translations" term set will be returned,  JSOM will return the English language labels by default. 

If I am a Dutch user and I have set my preferred language as Dutch, when the terms for the "Translations" term set will be returned,  JSOM will return the Dutch language labels by default. 

If I am an Italian user and have set Italian as my preferred language in my user profile,  SharePoint will return the English labels for the Translations term set as we have not selected Italian as one of the Working Languages of the Term store, nor have we set any labels in Italian.



2) Add Local Custom Properties to Terms


Next, we will add a local custom property for each term to identify it regardless of the language. This will serve as the ID of the term when we fetch it from JSOM:



This is the list of the local custom properties I have created for my terms:

Term
Local Property Name
Value
Communications
TranslationID
MUITextCommunication
Marketing
TranslationID
MUITextMarketing
News
TranslationID
MUITextNews

We could use the Term GUID here but I prefer using a custom ID as it is more readable. Also, if someone deletes one of the terms by mistake, it is easy to create a new Term and set the custom ID in the properties. If we were using a GUID, we would have to use code to create a new term with a specific GUID.

3) The Translation framework


After the Term Store is correctly setup, all we need to do is get the terms from the "Translations" term using the JavaScript Client Object Model (JSOM) and display them in the UI:
  • Query the term store to get the terms from the "Translations" term set.
  • SharePoint will return the term labels in the current user's preferred language if:
    • The alternate language is enabled on the current site
    • The current user has set the language as a preferred language in their user profile
    • The term store supports the language as a "Working Language" as shown in step 1
    • A default label is defined for the terms in that language.
  • If any one of these conditions is not fulfilled, then the English labels for the terms will be fetched as it is the default language of the Term Store. 
  • The term labels will be stored in the cache.



4) Performance/Caching


Since it is not advisable to make a call to the Term Store on every page load, it is a good idea to cache the labels for a particular user. My recommendation would be to use the browser web storage. Whether you use session storage or local storage depends on the implementation of the solution. MDN has a great article on this https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API

For demo purposes, I am using the sessionStorage and storing the term labels as a JSON object.

When the preferred language of the current user is English:


When the preferred language of the current user is Dutch:


5) Using the framework to show localized text


After the framework is correctly setup, all we need to do is call the framework correctly to show the custom text in the language of the current user:



When this code runs, if the preferred language of the current user is English, they will see the English text:




If the preferred language of the current user is Dutch, they will see the custom text in Dutch:


This way, you can utilize the multilingual features of the SharePoint Taxonomy Term Store to show multilingual custom text in your solution.

8 comments:

Sandeep Singh said...

This has been really helpful. One question though, why MMS? why not use list to keep the same data? That way the data can be fetched from search index and it will be way faster (in case one does not want to use any caching).

Sandeep Singh said...

Oh, I see one reason, if this metadata is associated with any other data (documents), Search can easily find that other data by any other language term as they are all synonyms. Are there other reasons?

Vardhaman Deshpande said...

Hi Sandeep.

Yes we did consider using a List based approach before going down the MMS way. The main advantage of MMS in my opinion is that it is easily extendable to support additional languages. Consider this, if you have to add a new language, all you have to do now is to add the language to the "Working languages" in the term store, add the labels for it to the terms and you are done. JSOM will automatically pickup the new language term labels if the user preference is set for it.

In case of a list based approach, you would have to add a new column to the list to support the new language and update that column for every list item for the new labels. This then becomes a code change as opposed to just a configuration change.

Hope this makes sense.

Thanks!

Sandeep Singh said...

Thanks for the response.

I gave it a little more thought. I was thinking, if this data is in list, then the search will crawl and index this data. Then it can be fetched from search index rather than from List and that will make the rendering very fast. But, this list should be structured in key-value pair rather than adding new column for new language. That way, no code change for new language.

Do you think that would be better design and less reliability on browser caching? Do you see any other issue?
regards,

Vardhaman Deshpande said...

It depends a lot on your business requirements. If it is a list based approach, you will also have to write the code to fetch the correct language titles depending on the user's language preference. See here for the language priority SharePoint uses to determine the correct language for the user: https://technet.microsoft.com/en-us/library/ff805087.aspx#bkmkHowMUIWorks

You also have to account for scenarios where no language titles have been specified so default english titles will have to be shown.

With the MMS based approach, all this is handled for you by SharePoint.

But again, it depends a lot on your business requirements, budget and the level of control you want to have on your solution.

Hope this helps.

Sandeep Singh said...

It surely does Vardhmaan. Thanks!

Yes, it took me some time to find out how to change the language and unfortunately the change is in profile, therefore, it changes for all sites. I was hoping I could change the language for one site/subsite, but that is not possible.
I guess the main benefit I see is that I can get the list data from search index. Other logic requirements aren't that time consuming. Therefore I will try the list based approach and see how it goes. Thanks again for the post and help....

Vardhaman Deshpande said...

No problem. Happy to help.

Just bear in mind that even if the list data is stored in the search index, you are still making a REST call to SharePoint to query the data.

You will still stand to benefit a lot from using the browser sessionStorage or localStorage even in this scenario.

Sandeep Singh said...

Good point. I will do that.