How to Dynamically Translate Portal Content - Unofficial Guide
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
11-19-2024 05:37 PM - edited 11-19-2024 05:41 PM
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:
- Install the Dynamic Translation plugin and all necessary language localization plugins.
- 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.)
- 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.
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"}
}
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.
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
- 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.
- 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.
- Cache Invalidation: If privileges still don’t work, follow this cache invalidation guide.
- 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!
- 1,902 Views
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
11-19-2024 09:34 PM
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
11-20-2024 12:44 PM
Sure thing, I'll post something tonight.