- Post History
- Subscribe to RSS Feed
- Mark as New
- Mark as Read
- Bookmark
- Subscribe
- Printer Friendly Page
- Report Inappropriate Content
on 02-19-2019 09:30 AM
Hello Community,
I often come across requests to send emails in multiple languages. This is usual for instances that have a foreign language(s) activated and support translated texts and messages. So a very common solution used to send an email with a translated version is by creating a Notification with the translated text and setting the conditions in the notifications to check the recipients language selection (i.e: French, Spanish or System - (English) ....etc). See example (Incident opened for me (French)):


However what would you do if you have a list of recipients (i.e: Assignment Group, Watch list...) ? The solution would not take into consideration the recipients' language of choice.
I have developed the following solution which allows each and every recipient to receive the email in the language of their choice. The message notification selection is based on the Language set in their profile :


Whenever the system sends an email it creates a Notification Message in the [cmn_notif_message] table for that user. If a user is Unsubscribed from that notification they will not receive the message. This works regardless of how the Notification recipients are set: by Field by Group by User or even by an event Parameters. As long as the user is in the [sys_user] table they have Notification Preferences.
Things to keep in mind before implementing the following solution:
- The default language of the system (glide.sys.language) might NOT necessarily be set to English
- A user might change his/her language in their profile to any language or choose System (language) (make sure the Language field appears in their ESS view of their profile)
- Current Notifications don't have anything that systematically identifies the language used in the email sent. Example: in the above example Incident opened for me (French) it says (French) in the Name of the notification which "labels" the notification to be french but the system does not identify it as it's in French.
- The User at any time would like to unsubscribe from a Notification (even if its in their language)
- Before you implement this soltuion keep in mind that all existing Notification are set to 'System language (or NO language)', which you will have to set after you create the u_language custom field
Here are the steps:
1. Create a Custom field on the Notifications table [sysevent_email_action] named u_language of type String with Choices, and set the Default value to: "javascript: gs.getProperty('glide.sys.language')"


You can structure the choice list similar to the preferred_language field on the sys_user table by adding an extra choice with a NULL_OVERRIDE value and javascript:'System (' + new I18nUtils().getUserLanguage() + ')' as label, I recommend avoiding this as it will create unnecessary duplicates in your list.
Recreate the same notification with the exact same conditions and recipients but different language values. The language value will determine what language it is in and set a Template of your choice by language (or Message or Message HTML).
See Example :


2. Create a Business Rule on the Notification Message Table [cmn_notif_message] and Notification Table [sysevent_email_action] this will check the recipient's language whenever a notification preference is created i.e Email is sent for the first time. Details as follow:
Name: Unsubscribe from Notification Language
Table [cmn_notif_message]
When: Before
On: Insert
Advanced:
Condition: current.user.preferred_language.toString() != current.notification.u_language.toString()
Script:
(function executeRule(current, previous /*null when async*/) {
if(!current.user.preferred_language.hasValue()){
if(current.notification.u_language.toString() != gs.getProperty('glide.sys.language'))
current.notification_filter = 'c1bfa4040a0a0b8b001eeb0f3f5ee961'; //sys_id of the Unsubscribe record
}
else if (current.user.preferred_language.toString() != current.notification.u_language.toString()){
current.notification_filter = 'c1bfa4040a0a0b8b001eeb0f3f5ee961'; //sys_id of the Unsubscribe record
}
})(current, previous);
Name: Update Notification Message of Users
Table: sysevent_email_action
Filter Conditions: Language changes
When: Before
On: Insert, Update
Advanced:
(function executeRule(current, previous /*null when async*/) {
//Update the cmn_notif_message table with the correct language subscription
var grNotif = new GlideRecord('cmn_notif_message');
grNotif.addQuery('notification', current.sys_id);
grNotif.query();
while (grNotif.next()){
if(grNotif.user.preferred_language != current.u_language){
grNotif.notification_filter = 'c1bfa4040a0a0b8b001eeb0f3f5ee961';
}
else {
grNotif.notification_filter = '';
}
grNotif.update();
}
})(current, previous);
3. Create a Business Rule on the User Table [sys_user] to Update notification Preferences:
Name: Update Notification Preferences
Filter Conditions: Language changes
When: Before
On: Update
Advanced:
(function executeRule(current, previous /*null when async*/) {
//get the Notification Messages of the user
var notifgr = new GlideRecord('cmn_notif_message');
notifgr.addQuery('user', current.sys_id);
//notifgr.addQuery('notification.u_language', current.sys_id);
notifgr.query();
while(notifgr.next()){
if (current.preferred_language.hasValue()){
//Subscribe to Notification that matches user language selection or
//to any notification that has NO language
if (notifgr.notification.u_language == current.preferred_language || !notifgr.notification.u_language.hasValue()){
notifgr.notification_filter = '';
}
//Unsubscribe from Notification not matching user language
//The notification needs to have a language Set
else {
notifgr.notification_filter = 'c1bfa4040a0a0b8b001eeb0f3f5ee961'; //sys_id of the Unsubscribe record
}
}
//If user set No preferred language (i.e system langauge)
//Subscribe to Notificaitons that match system language (or no language)
else {
if(!notifgr.notification.u_language.hasValue() || notifgr.notification.u_language == gs.getProperty('glide.sys.language')){
notifgr.notification_filter = '';
}
}
notifgr.update();
}
})(current, previous);
4.(optional) If you want to get the tranlated Text and Value of a field in your notification and keep it dynamic based on language of Notification you can do so by creating a Notification email Script and a Script Include. And use the Mail Script in your email template of your email notification. However since you can NOT pass parameters in your mail script you will have to set a Notification email Script for each field you want to print in the email. This how it works
In the above example we are using the template "incident.opened.fq" for the French Notification "Incident Opened (FQ)":


This is the source Code of the Email Template:


In our example we want to get the translated text for the Urgency field Notification eMail Script "incident_urgency_text":
Notification eMail Script:
Name: incident_urgency_text
Script:
(function runMailScript(/* GlideRecord */ current, /* TemplatePrinter */ template,
/* Optional EmailOutbound */ email, /* Optional GlideRecord */ email_action,
/* Optional GlideRecord */ event) {
var textLabel = new global.EmailTextUtil();
//To get the Label of choice of the field look up in [sys_choice] table
template.print(textLabel.getChoiceLabel('urgency', current.getRecordClassName(), current.urgency, email_action.u_language.toString()));
})(current, template, email, email_action, event);
Script Include:
Name: EmailTextUtil
API Name: global.EmailTextUtil
Client Callable: false
Script:
var EmailTextUtil = Class.create();
EmailTextUtil.prototype = {
initialize: function() {
},
getLabel: function(field, table, language) {
var grElement = new GlideRecord('sys_documentation');
grElement.addQuery('name', table);
grElement.addQuery('element', field);
grElement.addQuery('language', language);
grElement.query();
// gs.log("EmailTextUtil label field " + field);
// gs.log("EmailTextUtil label table " + table);
if(grElement.next()){
return grElement.label.toString();
}
},
getChoiceLabel: function(field, table, value, language) {
var grElement = new GlideRecord('sys_choice');
grElement.addQuery('name', 'task');
grElement.addQuery('value', value);
grElement.addQuery('element', field);
grElement.addQuery('language', language);
grElement.query();
// gs.log("EmailTextUtil label field " + field);
// gs.log("EmailTextUtil label table " + table);
if(grElement.next()){
return grElement.label.toString();
}
},
type: 'EmailTextUtil'
};
And this how the Final message will appear:

You can also leverage the script to print Req Item Varaibles of a catalog requests and so forth.
The solution above also works for Notifications based on Events created holding recipients in the parameters.
There you have it a solution for a notification system with multilingual emails.
Enjoy !
- 2,127 Views
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
A bit improved script include that supports table hierarchies (fields created on different levels)
var EmailTextUtil = Class.create();
EmailTextUtil.prototype = {
initialize: function(table) { // Initializing for specified table
this.tableHierarchy = [];
this.table = false;
if (gs.nil(table)){
return;
}
this.table = table;
this.tableHierarchy = this.getTableHierarchy(this.table);
},
getTableHierarchy: function (table){ // Getting table hierarchy. Table itself always goes first
var tablesArr = [];
var tableHierarchy = new global.TableUtils(table).getTables().toArray();
for (var i = 0; i < tableHierarchy.length; i++) {
tablesArr.push(tableHierarchy[i]);
}
return tablesArr;
},
getLabel: function(field, language) {
if (!this.table){
return field;
}
var i;
var grElement;
for (i=0; i<this.tableHierarchy.length;i++){
// Detecting Label translation for specified language starting from the bottom and going up in hierarchy
grElement = new GlideRecord('sys_documentation');
grElement.addQuery('name', this.tableHierarchy[i]);
grElement.addQuery('element', field);
grElement.addQuery('language', language);
grElement.query();
if(grElement.next()){
return grElement.label.toString();
}
}
// Did not find Label in specified language. Now will try with English
if (language !='en'){
// Detecting English Label translation for specified language starting from the bottom and going up in hierarchy
return this.getLabel(field,'en');
}
// Did not find anything
return field; // Label not found, we rerturn SQL field name itself
},
getChoiceLabel: function(field, value, language) {
if (!this.table){
return value;
}
if (gs.nil(value)){ // Handler for empty or null value
return value;
}
var i;
var grElement;
for (i=0; i<this.tableHierarchy.length;i++){
// Detecting choice Label (translation) for specified language starting from the bottom and going up in hierarchy
grElement = new GlideRecord('sys_choice');
grElement.addQuery('name', this.tableHierarchy[i]);
grElement.addQuery('value', value);
grElement.addQuery('element', field);
grElement.addQuery('language', language);
grElement.query();
if(grElement.next()){
return grElement.label.toString();
}
}
// Did not find choice Label in specified language. Now will try with English
if (language !='en'){
// Detecting English choice Label translation for specified language starting from the bottom and going up in hierarchy
return this.getChoiceLabel(field, value,'en');
}
// Did not find anything
return value; // Label not found, we return value itself
},
type: 'EmailTextUtil'
};