Text translation services can be useful in a variety situations, such as content accessibility for users from different cultures, real-time augmented reality text translation, integration with text-to-speech services, translation to a common “hub” language, and other cases where the input language is not necessarily the desired output language. As voice and language-based techniques gain popularity, user behavior and expectations are shifting from web-based to voice-based user experiences in many everyday settings. In this article, we will dive into a simple example of how to enable multilingual text translation with the SDL Language Cloud using a modest 44-line PubNub JavaScript BLOCK and 70 lines of HTML and JavaScript.
So, what exactly is this “Language Cloud” service we speak of? SDL offers a number of services for machine and human-assisted content translation. In this article, Translation refers to conversion of a piece of text from a known or unknown language into a specific target language. There are a number of considerations there, including language detection, accuracy, and domain-specific issues like acronyms, abbreviations and terms (not to mention internet slang like OMG, BFF, LOL, IMO, TTYS!). We use the Language Cloud Translation Toolkit API to integrate with our real-time messaging channel to provide translation from English to Spanish (for example). As we prepare to explore our sample AngularJS web application with text translation features, let’s check out the underlying Language Cloud Translation Toolkit API.
SDL Language Cloud – Language Toolkit API
Text translation services are a notoriously difficult area, and they require substantial effort and engineering resources to maintain across a diverse array of targeted platforms and user languages. In the meantime, the Translation Toolkit API makes it easy to enable your applications with straightforward text translation to and from a variety of languages.
Since you’re reading this at PubNub, we’ll presume you have a real-time application use case in mind, such as ride-hailing, messaging, IoT or other. In the sections below, we’ll dive into the text translation use case, saving the other cognitive service use cases for the future.
The first things you’ll need before you can create a real-time application with PubNub are publish and subscribe keys from PubNub. Just in case you haven’t already, you can create an account, get your keys and be ready to use the PubNub network in less than 60 seconds using the handy signup form. Once you do that, the publish and subscribe keys look like UUIDs and start with “pub-c-” and “sub-c-” prefixes respectively. Keep those handy – you’ll need to plug them in when initializing the PubNub object in your HTML5 app below.
Getting Started with SDL Language Cloud
The next thing you’ll need to get started with SDL Language Cloud is an SDL account to take advantage of the translation APIs.
- Step 1: go to the SDL signup form.
- Step 2: go to the Language Cloud summary page, enable sandbox mode and create a new Application
- Step 3: go to the API Keys page and make note of the API token.
All in all, not too shabby!
Diving into the Code – the BLOCK
You’ll want to grab the 44 lines of BLOCK JavaScript and save them to a file, say, pubnub_sdl_block.js
. It’s available as a Gist on GitHub for your convenience.
First up, we create a method to handle incoming messages, declare our dependency on xhr (for HTTP requests), and declare constants for the API token and API url.
export default request => { let xhr = require('xhr'); let clientToken = '00000000000000000000000000000000'; let apiUrl = 'https://lc-api.sdl.com/translate';
Next up, we declare variables for the text to be translated, “to” language code (ISO 639 3-letter code), and “from” language code (ISO 639 3-letter code). If any of those are missing, we return from the function and pass the message through unmodified. If all are present, we proceed.
const text = request.message.text; const from = request.message.from; const to = request.message.to; if (!text || !from || !to) { return request.ok(); }
Next, we set up the web service query parameters and authentication header. Note that we use a constant to specify English as the source language and Spanish as the target language from the UI later in this article. In your application, this could also be a dynamic value.
const payload = JSON.stringify({ text, from, to }); let httpOptions = { as: 'json', headers: { 'Content-Type': 'application/json', Accept: 'application/json', Authorization: 'LC apiKey=' + clientToken }, body: payload, method: 'post' };
Finally, we make a remote service request to the SDL Language Cloud Translation Toolkit API, and add a message attribute request.message.translation
with the translated text. We return request.ok()
to pass on that modified message object.
return xhr.fetch(apiUrl, httpOptions) .then((response) => { return response.json() .then((parsedResponse) => { request.message.translation = parsedResponse.translation; return request.ok(); }) .catch((err) => { console.log('error happened on JSON parse', err); return request.ok(); }); }) .catch((err) => { console.log('error happened for XHR.fetch', err); return request.ok(); }); };
All in all, it doesn’t take a lot of code to add text translation to your application. We like that!
OK, that said, let’s move on to the UI!
Diving into the Code – the User Interface
You’ll want to grab these 70 lines of HTML & JavaScript and save them to a file, say, pubnub_sdl_ui.html
.
The first thing you should do after saving the code is to replace two values in the JavaScript:
- YOUR_PUB_KEY: with the PubNub publish key mentioned above.
- YOUR_SUB_KEY: with the PubNub subscribe key mentioned above.
If you don’t, the UI will not be able to communicate with anything and probably clutter your console log
with entirely too many errors.
For your convenience, this code is also available as Gist on GitHub, and a Codepen as well. Enjoy!
Dependencies
First up, we have the JavaScript code & CSS dependencies of our application.
<!doctype html> <html> <head> <script src="https://cdn.pubnub.com/pubnub-3.15.1.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script> <script src="https://cdn.pubnub.com/sdk/pubnub-angular/pubnub-angular-3.2.1.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script> <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.2/css/bootstrap.min.css" /> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" /> </head> <body>
For folks who have done front-end implementation with AngularJS before, these should be the usual suspects:
- PubNub JavaScript client: to connect to our data stream integration channel.
- AngularJS: were you expecting a niftier front-end framework? Impossible!
- PubNub Angular JavaScript client: provides PubNub services in AngularJS quite nicely indeed.
- Underscore.js: we could avoid using Underscore.JS, but then our code would be less awesome.
In addition, we bring in 2 CSS features:
- Bootstrap: in this app, we use it just for vanilla UI presentation.
- Font-Awesome: we love Font Awesome because it lets us use truetype font characters instead of image-based icons. Pretty sweet!
Overall, we were pretty pleased that we could build a nifty UI with so few dependencies. And with that… on to the UI!
The User Interface
Here’s what we intend the UI to look like:
The UI is pretty straightforward – everything is inside a div
tag that is managed by a single controller that we’ll set up in the AngularJS code. That h3
heading should be pretty self-explanatory.
<div class="container" ng-app="PubNubAngularApp" ng-controller="MyTranslateCtrl"> <pre> NOTE: make sure to update the PubNub keys below with your keys, and ensure that the translate BLOCK is configured properly! </pre> <h3>MyText Translation</h3>
We provide a simple text input for a message to send to the PubNub channel as well as a button to perform the publish()
action.
<input ng-model="toSend" /> <input type="button" ng-click="publish()" value="Send!" />
Our UI consists of a simple list of messages. We iterate over the messages in the controller scope using a trusty ng-repeat
. Each message includes the original English text (provided that’s what you publish) as well as the Spanish translation.
<ul> <li ng-repeat="message in messages track by $index"> en: {{message.text}} <br /> es: {{message.translation}} </li> </ul> </div>
And that’s it – a functioning real-time UI in just a handful of code (thanks, AngularJS)!
The AngularJS Code
Right on! Now we’re ready to dive into the AngularJS code. It’s not a ton of JavaScript, so this should hopefully be pretty straightforward.
The first lines we encounter set up our application (with a necessary dependency on the PubNub AngularJS service) and a single controller (which we dub MyTranslateCtrl
). Both of these values correspond to the ng-app
and ng-controller
attributes from the preceding UI code.
<script> angular.module('PubNubAngularApp', ["pubnub.angular.service"]) .controller('MyTranslateCtrl', function($rootScope, $scope, Pubnub) {
Next up, we initialize a bunch of values. First is an array of message objects which starts out empty. After that, we set up the msgChannel as the channel name where we will send and receive real-time structured data messages. NOTE: make sure this matches the channel specified by your BLOCK configuration!
$scope.messages = []; $scope.msgChannel = 'sdl-channel';
We initialize the Pubnub
object with our PubNub publish and subscribe keys mentioned above, and set a scope variable to make sure the initialization only occurs once. NOTE: this uses the v3 API syntax.
if (!$rootScope.initialized) { Pubnub.init({ publish_key: 'YOUR_PUB_KEY', subscribe_key: 'YOUR_SUB_KEY', ssl:true }); $rootScope.initialized = true; }
The next thing we’ll need is a real-time message callback called msgCallback
; it takes care of all the real-time messages we need to handle from PubNub. In our case, we have only one scenario – an incoming message containing text with its translation. The push()
operation should be in a $scope.$apply()
call so that AngularJS gets the idea that a change came in asynchronously.
var msgCallback = function(payload) { $scope.$apply(function() { $scope.messages.push(payload); }); };
The publish()
function takes the contents of the text input, publishes it as a structured data object to the PubNub channel, and resets the text box to empty. The “eng” and “spa” values may be changed to any language pair supported by SDL Language Cloud.
$scope.publish = function() { Pubnub.publish({ channel: $scope.msgChannel, message: {text:$scope.toSend, from:"eng", to:"spa"} }); $scope.toSend = ""; };
In the main body of the controller, we subscribe()
to the message channel (using the JavaScript v3 API syntax) and bind the events to the callback function we just created.
Pubnub.subscribe({ channel: [$scope.msgChannel], message: msgCallback });
We mustn’t forget close out the HTML tags accordingly.
}); </script> </body> </html>
Not too shabby for about seventy lines of HTML & JavaScript!
Additional Features
There are a couple other features worth mentioning in the SDL Language Cloud Translation API.
const queryParams = { from: "eng", target: "spa", text: request.message.text inputFormat:"html", domainCode:"Travel" };
You can find detailed API documentation here (https://languagecloud.sdl.com/translation-toolkit/api-documentation).
- inputFormat is the text input format (html or plain).
- domainCode is the domain-specific model you’d like to use: if you’d like to use specific models for Travel, Automotive or a custom domain.
All in all, we found it pretty easy to get started with Text Translation using the API!
Conclusion
Thank you so much for joining us in the SDL Language Cloud article of our real-time web application series! Hopefully it’s been a useful experience learning about language-enabled technologies. In future articles, we’ll dive deeper into more web service APIs and use cases for PubNub BLOCKS in real time web applications.
Stay tuned, and please reach out anytime if you feel especially inspired or need any help!