How to Dynamically Translate Portal Content - Unofficial Guide

Kevin Liao
Tera Expert

Introduction

I recently encountered a requirement to translate portal content into multiple languages. While the Employee Center (EC) supports translation, I quickly realized there’s no out-of-the-box (OOTB) functionality to integrate it with Dynamic Translation. This means you’d need to manually translate each piece of content for every language and insert it one by one into the translated text table.

 

In this post, I’ll share a quick code snippet to simplify this process by leveraging the Dynamic Translation API for translating portal content (or any other records).

 

Prerequisites

To use this guide, ensure the following:

  1. Install the Dynamic Translation plugin and all necessary language localization plugins.
  2. Configure Dynamic Translation and link it to a translation service like Google or Microsoft. (This setup won’t be covered here as there are better resources available for that.)
  3. Familiarize yourself with the relationship between the translated_text field type and the sys_translated_text table.

 

Building a Reusable Translation Utility: ContentTranslationUtils

First, create a Script Include to make the translation service reusable across your instance (e.g., in UI actions, business rules, flow actions, etc.). The utility will include at least two main functions:

 

1. translateMyText

 

    translateMyText: function(engText) {
        var supportedLanguageCodes = gs.getProperty("sn_cd.supported_language_codes").split(",");
        var textInEnglish = engText;
        var translatedObj = sn_dt_api.DynamicTranslation.getTranslation(textInEnglish, {
            "targetLanguages": supportedLanguageCodes,
            "additionalParameters": [{
                "parameterName": "texttype",
                "parameterValue": "plain"
            }],
            "translator": "Microsoft"
        });
		return translatedObj;
    },

 

  • translateMyText: Wraps the OOTB Dynamic Translation API, translating text (or HTML) from English into multiple languages. This wrapper allows better control and reuse of parameters.
  • supportedLanguageCodes: A variable holding a comma-separated list of target language codes.
  • translatedObj: The API’s response, containing an array of translations for the specified languages.
Check DynamicTranslation - Scoped for more detailed use of the OOTB API.

 

Example input: 

 

Hello World

 

Example property:

 

es,pb,zh,cs,da,nl,fi,fr,de

 

Example output:

 

{
  "translations": [
    {"targetLanguage": "de", "translatedText": "Hallo Welt"},
    {"targetLanguage": "fi", "translatedText": "Moi maailma"},
    {"targetLanguage": "zh", "translatedText": "世界您好"}
  ],
  "translator": "Microsoft",
  "detectedLanguage": {"name": "en", "code": "en"}
}

 

 

2. insertTranslationRecords

 

insertTranslationRecords: function(translatedString, contentID, contentTable, contentField){
		var translatedObj = JSON.parse(translatedString);
		translatedObj.forEach(function(languageTrans) {
			//check if translation exists
			var grTrans = new GlideRecord("sys_translated_text");
			grTrans.addEncodedQuery("tablename="+contentTable+"^fieldname="+contentField+"^language="+languageTrans.targetLanguage+"^documentkey="+contentID);
			grTrans.query();
			if(grTrans.next()){ //update if translation already exist for this language
				grTrans.value = languageTrans.translatedText;
				grTrans.update();
			}
			else{ //create if it doesnt exist
				var grTransInsert = new GlideRecord("sys_translated_text");
				grTransInsert.initialize();
				grTransInsert.tablename = contentTable;
				grTransInsert.fieldname = contentField;
				grTransInsert.language = languageTrans.targetLanguage;
				grTransInsert.documentkey = contentID;
				grTransInsert.value = languageTrans.translatedText;
				grTransInsert.insert();
			}
		});
	},

 

  • insertTranslationRecords: Processes the multi-language translation object and creates or updates sys_translated_text records for the English text.

      Inputs:

  • contentID: The Sys ID of the record.
  • contentTable: The table name of the record.
  • contentField: The field name to translate.
 
Example Usage

 

	var transUtil = new sn_cd.ContentTranslationUtils();
	var translationObj = transUtil.translateMyText(current.body_text+"").translations;
	var translatedString = JSON.stringify(translationObj);
	transUtil.insertTranslationRecords(translatedString, current.sys_id+"", "sn_cd_content_portal", "body_text");​

 

This example translates the body_text field of a Portal Content record and inserts the translations into the sys_translated_text table.

 

Other Considerations

  1. Field Type: Ensure fields you want to translate are of type translated_text or translated_html. You can change a string field to one of these types without deleting the original field.
  2. Cross-Scope Privileges: If you encounter cross-scope privilege issues, add Application Cross-Scope Access records to grant create/write access to sys_translated_text.
  3. Cache Invalidation: If privileges still don’t work, follow this cache invalidation guide.
  4. Flexibility: This approach isn’t limited to portal content. You can apply it to emails, notifications, and other string fields.

 

Conclusion

This is my first community guide! While this isn’t a complex implementation, I hope it helps those struggling to apply dynamic translation in unsupported areas. Thanks for reading!

 

 

2 REPLIES 2

Ravi Chandra_K
Kilo Patron
Kilo Patron

Very helpful Post!

 

Can you also post the same article in the Translations forum.

Products -> Other ServiceNow Products > internalizaon and localization 

 

Kind regards,

Ravi Chandra 

 

Sure thing, I'll post something tonight.