The Now Platform® Washington DC release is live. Watch now!

Help
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Alex Coope - SN
ServiceNow Employee
ServiceNow Employee

The Localization Framework...

As some of you know, in Quebec we launched the "Localization Framework". Which is a new functionality where you can leverage "artefacts" to identify the translatable elements to action accordingly. Think of LF as an engine, and the "artefacts" as the gears. 

In the Quebec release we released 2 artefacts - "Catalog Items"  and "VA Topics". Which allowed suitably rolled individuals to request such items to be translated into a chosen language generating a task, then allowing a translator to see the elements making it up and actioning accordingly (either via MT or performing manually, or even extracting to a TMS).

In Rome, we added a whole bunch more Artefacts such as "HTML Document Templates" (great for HR scenarios), "NLU Models" (making VA Topics take into account actual NLU models in other languages, so that the utterances can also be factored in) and "Document Template Block Content" (also helping out some of those HR scenarios). 

 

However, what if we wanted to make our own, could we?

Well, let's look at Portal announcements, the type that sit in the [announcement] table, that we want to show on the top of a Service Portal, or tucked into a widget like this one:
find_real_file.png


The first thing we'd need to understand is whether these are even translatable. Short answer is they are, because the "Title" & "Summary" fields are of "translated_text" type which means it would need it's translations to sit in the [sys_translated_text] table:
find_real_file.png


Let's just have a look with the i18n debugger enabled to see what's possible:
find_real_file.png

Sure enough, we can see a "TRT" prefix next to both the "Title" and "Summary" values.

So, of course we could manually populate the [sys_translated_text] table with the translations via a spreadsheet, running a suitable import. However, it's not a particularly great process experience, in that wouldn't it be far easier if we could just request the translations so that someone could action it?

If we have the "Localization Framework" (com.glide.localization_framework) already installed, then navigate to:
Localization Framework > Artifact Configurations.

You should be presented with a list of the ones provided in your release. As we're going to be creating our own one click "new".
One thing to be aware of, depending on your release this bit might be a little different. Meaning, in Quebec the "Processor script" could be created in this record, where as in Rome the "Processor script" is now created as a separate Script Include that you're essentially calling.

Quebec - check here
Rome - check here

Ultimately, the concepts are the same, and the method in Rome will honour how it's done in Quebec, it's just to say that the form layout is slightly different between the releases, yet the concepts are fundamentally the same.

 

How do we make one?

[EDIT] - The following assumes that you have a "setting" in the Localization Framework for "all artifacts", if you actually have one per artifact to direct which languages follow which workflow, then you would need to define an additional setting for this new artifact (and any other new artifacts). This is in "Localization Framework" > "Settings".

Now that we know we need to write a little script, let's become familiar with what's possible. For this example we'll be building our Artifact in a Rome release and so the API details are here

So, we need to define our "Artifact" like this:
find_real_file.png

But... we need a "Processor Script", so let's define that as well:
By clicking "Create Processor Script" (before we submit our Artifact) it will open an interceptor in a new tab to preserve our values. Let's call it "LF_Announcements" and hit submit:
find_real_file.png


You'll be presented with a lot of useful info in the following screen. Essentially all we really need to do is run a query back to the [announcement] table where the sys_id is the current (because of how the UIaction we'll make later, works) and process it into 
processTranslatableFieldsForSingleRecord (glideRecord, groupName) because with announcements there are no sub-records or parallel records.

Set up the "Processor Script" as follows:
Name - "LF_Announcements" - this should be carried over from the previous screen
Descriptionedit as desired
Script:

var LF_Announcements = Class.create();
LF_Announcements.prototype = Object.extendsObject(global.LFArtifactProcessorSNC, {
    category: 'localization_framework', // DO NOT REMOVE THIS LINE!

    /**********
     * Extracts the translatable content for the artifact record
     * 
     * @param params.tableName The table name of the artifact record
     * @param params.sysId The sys_id of the artifact record 
     * @param params.language Language into which the artifact has to be translated (Target language)
     * @return LFDocumentContent object
     **********/
    getTranslatableContent: function(params) {
        /**********
         * Use LFDocumentContentBuilder to build the LFDocumentContent object
         * Use the build() to return the LFDocumentContent object
         **********/
        var tableName = params.tableName;
        var sysId = params.sysId;
        var language = params.language;
        var groupName = "";
        var lfDocumentContentBuilder = new global.LFDocumentContentBuilder("v1", language, sysId, tableName);

        var msgArr = []; // array for later
        // what announcement are we looking at?
        var announceCheck = new GlideRecord('announcement');
        announceCheck.addQuery('sys_id', sysId);
        announceCheck.query();

        if (announceCheck.next()) {
            lfDocumentContentBuilder.processTranslatableFieldsForSingleRecord(announceCheck, 'Announcement', 'Name');
        }

        return lfDocumentContentBuilder.build();
    },

    /**********
     * Uncomment the saveTranslatedContent function to override the default behavior of saving translations
     * 
     * @param documentContent LFDocumentContent object
     * @return
     **********/
    /**********
        saveTranslatedContent: function(documentContent) {},
    **********/

    type: 'LF_Announcements'
});

^ I've kept in the default notes just so that you can see how it's structured.

Active - true

Submit when ready.

 

All that's left now, is to make a UI action to allow us to request the translations from the announcement records. Let's go to the [announcement] table and go to it's UIactions and click "new",

Name - Request Translations
Table - (should already be "announcement" if it's not then set accordingly)
Order - 100 is fine
Form button - true
Active - true
Show insert - true
Show update - true
Client - true

Onclick - 

renderLanguagePickerModal();

Condition - 

new global.LFTaskUtils().showUIAction("announcements")

^ note the parameter sent is "announcements", not the table name. This is because it's run by the internal name of the Artifact we made.

Script - 

function renderLanguagePickerModal() {
	// we need to call the modal
    var dlg = new GlideModal('sn_lf_language_picker');
    dlg.setTitle(getMessage('Request Translations'));
    dlg.setPreference('sys_id', g_form.getUniqueValue());
    dlg.setPreference('table_name', g_form.getTableName());
    dlg.setPreference('request_type', "form");
    dlg.setPreference('focusTrap', true);
    dlg.render();
}

 

When it's all created and active, navigating back to our test announcement, we should see the UI action as follows:
find_real_file.png

 

Let's Test it

If we click the UI action, we should be presented with the following modal (based on what languages you have set up on your instance your "settings" in the Localization Framework😞
find_real_file.png


Let's try Japanese for this example, and when "submit" is clicked you should see the following message:
find_real_file.png

 


To find the task, let's go to Localization Framework > My Tasks (we'll likely need to un-filter the breadcrumbs unless our user is in the group the task is assigned to). We should see it here:
find_real_file.png 


Going into the task, it's just like any other task in LF. In that it will follow any workflow you've determined, approvals you've determined etc. However, if we click that little "translate" UIaction in the top right then we can see the comparison UI which gives us:
find_real_file.png

 

From here, we can choose to manually translate the strings, MT them via Google, Azure or Watson (if we have a suitable subscription), or even export them to a TMS like RWS or XTM. It' entirely our choice as it's completely flexible.

 

What have we learned?

LF is very powerful. It has some "artifacts" provided out of the box, yet it can be expanded out to many many other areas, combining things into a simple translatable concept, removing the complexities of yucky spreadsheets and complex imports that require a System Admin to perform each time.

Here's an example of the translations held in the "comparison" UI:
find_real_file.png

* Apologies in advance for the translations in my screenshot, they were performed by an untrained MT.

When I hit "Publish Translations", they will follow what workflow I have set-up, then become available for all to consume:
find_real_file.png

 

Comment below if you can think of any other Artifact ideas or concepts you'd like me to explore in a future post

 

 

Comments
Fernando Schep1
Tera Contributor

Hi, this is nice. 

I am not a developer but I am trying to validate if this would work to be able to translate all our notifications through Machine Translation as we use the platform in multiple languages in our organization.

We are in Quebec release.

Thank you for your feedback

Fernando

Alex Coope - SN
ServiceNow Employee
ServiceNow Employee

Fernando, 

Currently notifications in other languages would typically be handled through solution design. Meaning, potentially a notification per language of that notification type, or some scripted logic (often using "mail scripts") to fetch the other language template based upon the recipients language.

If you'd like to learn more, I go through a bit of it in the second module of the "Localization Journey" course here,

Many thanks,
Kind regards

Fernando Schep1
Tera Contributor

Thank you for your fast feedback Alex. 

Honestly the whole notifications definition by ServiceNow needs a lot of work, by far is the activity that took us the most time to work on when preparing the platform in an international organization with around 100K users like ours.

Even if we could have a baseline notifications package like the one ServiceNow itself uses for support.servicenow.com would be already amazingly helpful. Being able to change the colors and the logos on header and footer instead of having to define all from scratch would have saved us a lot of time.

The translation piece, I would also expect it to be managed in a better way with variables being detected but still being able to define additional language versions of them with automatic machine learning translations in a side by side look without having to create copies of the notifications. Similar to what today is being offered through the localization framework for Catalog Items.

Thank you for your consideration, happy to jump into a call if you would like to talk more about this.

Fernando Scheps

Alex Coope - SN
ServiceNow Employee
ServiceNow Employee

Fernando, 

You're welcome, with regards to the email structures (such as those from NowSupport) they're just Email Templates, which have their contents populated via mail scripts as parameters, with a pre-defined header / body / footer, which can be repeatedly called in multiple notifications as required,

OOtB, there should be a "Created", "Opened For", "Updated", "Resolved" and "Closed" type of notification for the originator, as well as "Assigned" for the fulfillers in most product lines (e.g. ITSM, CSM and HR),

And I'm always up for a call if you'd like to discuss further, we'll connect offline,

Many thanks,
Kind regards

Zarina
Tera Contributor

I have done all the above steps except Workflow. Do we need to create a new Workflow to run when Publish Translations is hit. If so what actions we need in the workflow. 

Zarina.

Alex Coope - SN
ServiceNow Employee
ServiceNow Employee

No you shouldn't need to create a new workflow. You might need to define a new "setting" in the Localization Framework for the new artifact if your current "setting" doesn't apply to all artifacts, however it can absolutely use the existing workflows,

Sorry I should have made that clearer (I'll update the original post shortly),

Many thanks,
Kind regards

Frans Brus - No
Giga Guru

So I tried to create a processor script for Knowledge Articles.

var LF_Knowledge = Class.create();
LF_Knowledge.prototype = Object.extendsObject(global.LFArtifactProcessorSNC, {
    category: 'localization_framework', // DO NOT REMOVE THIS LINE!

    /**********
     * Extracts the translatable content for the artifact record
     * 
     * @param params.tableName The table name of the artifact record
     * @param params.sysId The sys_id of the artifact record 
     * @param params.language Language into which the artifact has to be translated (Target language)
     * @return LFDocumentContent object
     **********/
    getTranslatableContent: function(params) {
        /**********
         * Use LFDocumentContentBuilder to build the LFDocumentContent object
         * Use the build() to return the LFDocumentContent object
         **********/
        var tableName = params.tableName;
        var sysId = params.sysId;
        var language = params.language;
        var groupName = "";
        var lfDocumentContentBuilder = new global.LFDocumentContentBuilder("v1", language, sysId, tableName);

        var msgArr = []; // array for later
        // what KB Article are we looking at?
        var KbCheck = new GlideRecord('kb_knowledge');
        KbCheck.addQuery('sys_id', sysId);
        KbCheck.query();

        if (KbCheck.next()) {
            lfDocumentContentBuilder.processTranslatableFieldsForSingleRecord(KbCheck, 'Knowledge', 'Number');
        }

        return lfDocumentContentBuilder.build();
    },

    /**********
     * Uncomment the saveTranslatedContent function to override the default behavior of saving translations
     * 
     * @param documentContent LFDocumentContent object
     * @return
     **********/
    /**********
        saveTranslatedContent: function(documentContent) {},
    **********/

    type: 'LF_Knowledge'
});

The LFTASK is created.

find_real_file.png

But when clicking on the Translate button now fields are shown....

find_real_file.png

HWhat am I missing in the script creation?

(it does work for the announcement like the example)

Alex Coope - SN
ServiceNow Employee
ServiceNow Employee

@Frans Brus - NorthC 

At the moment you probably won't be able to make an artifact for Knowledge Articles, because you wouldn't look to replace text on an existing article but instead actually create a child article in that language,

Currently the feature that covers that is "Translation Management" within KM, however, watch this space in the future,

 

Many thanks,
Kind regards

Nelisvdw
Giga Explorer

Hi Alex quick question!

 

I've done everything to your instruction and it works fine for the first request of translations, but when the announcement would have been updated in one language and your try to use the request translations button again, the localization task will mention that "The task does not have any fields available for machine translation." and will not override the current, already translated other languages - is there a fix for this?

 

greetings!

Niels

Alex Coope - SN
ServiceNow Employee
ServiceNow Employee

Hi @Nelisvdw,

If in the comparison UI all of the translations are greyed out because there's a value already present then that would make sense. Currently it wouldn't clear the translation if the English source has changed, so if in the situation you have a piece of English text that has changed, find the row, click the "padlock" icon on that row and clear the previous translation, then you'll be able to send it. 

 

It's important to note, that the behaviour is true for any artifact,

 

Many thanks,

kind regards 

Version history
Last update:
‎10-05-2021 01:56 AM
Updated by: