X

Technical Articles relating to Oracle Development Tools and Frameworks

  • JET
    February 14, 2017

JET Custom Components XV - Translations

Duncan Mills
Architect

Introduction

Once you start to get serious about building truly reusable components, the issue of language support will come to the fore. The JET components that you use within your CCA will of course do the right thing based on the language and locale settings of the application, however, what about your own resources?

Background on Translatable Strings in JET

In the context of a JET application, an application developer will usually define translatable resources using the following steps:

  1. Create a /resources/nls folder under /js
  2. Create one subfolder under this nls folder for each supported language / region
  3. Define the default bundle with a particular name (e.g. myappstrings.js) in the /nls folder
  4. Define corresponding translated versions of myappstrings.js in each language subdirectory
  5. Configure the requirejs ojL10n plugin to merge the custom bundle (myappstrings.js) with the built-in JET bundles

This is all covered in detail in the documentation. Reading this, however, you might notice two particular issues which have a direct bearing on Composite Components.
 
  1. The configuration of the application bundle merging is done within the main application code (usually main.js)
  2. You can actually only merge one custom bundle into JET

Both of these restrictions make it impossible for a Composite Component to magically merge its strings into the default JET bundle for access via oj.Translations.getTranslatedString() and oj.Translations.gerResource(). So what should you do?

Steps to Apply Translations to Your Composite Components

Defining Your Bundles

I'd recommend that you define a single resource bundle file for your Composite component, there would be little need to have more that one. The base bundle in your default language should be placed in a suitable subdirectory of your composite component. To keep things consistent, I'd recommend using /resources/nls as the subdirectory. This /nls directory would then contain further subdirectories for the required language / region combinations. Thus, should your component support english as the base language, along with german and french you might end up with the following folders and files:

/js
  /jet-composites
    /acme-coyote-tracker
      loader.js
      acme-coyote-tracker.json
      acme-coyote-tracker.html
      acme-coyote-tracker.css
      acme-coyote-tracker.js
      /resources
        /images
          paintedDesert.png
        /nls
          acme-coyote-tracker-strings.js
          /de
            acme-coyote-tracker-strings.js
          /fr-FR
            acme-coyote-tracker-strings.js

The actual formatting of the translation bundles will be exactly the same as that shown in the doc for the main application bundles.

Referencing Your Resources

Once you have the bundles set up, you can still use default JET functionality to do the heavy lifting for you and to load the correct bundle for the current language in use (be that based on the HTML lang setting or oj.Config.setLocale()). In your Composite Component viewModel script, simply inject the bundle using the define block with the ojL10n plugin. For example:

    define(
      ['ojs/ojcore','knockout','jquery',
       'ojL10n!./resources/nls/acme-coyote-tracker-strings'
          ], function (oj, ko, $, coyoteTrackerStrings) {
          'use strict';
          function CoyoteTrackerComponentModel() {
              var self = this;
              self.res = coyoteTrackerStrings;
              ....
          };
          return CoyoteTrackerComponentModel;
      });

Note how the bundle is mapped to a variable called self.res via the injected coyoteTrackerStrings. This can then be referenced by the Composite Component viewModel or directly by the composite view itself:
<h1 data-bind="text:res.coyotetracker.pageTitle"></h1>
...
<input data-bind="attr:{placeholder:res.coyotetracker.coyoteName.placeholder},
                  ojComponent : {component: 'ojInputText',
                                 value: coyoteName,
                                 required: true,
                                 translations: {
                                     'required': {
                                         messageSummary: 
                                           res.coyotetracker.nameRequiredMessage,  
                                         messageDetail: 
                                           res.coyotetracker.nameRequiredDetail
                                         }
                                     }
                                 }">
</input>

Managing Strings with Substitution

You'll note that because you have direct access to the string bundle via the injected reference, you don't need to access the string through the oj.Translations.getTranslatedString() API. That's good because your code is somewhat less verbose, however, what about the token substitution feature of that API? Fortunately, this feature is available separately through the oj.Translations.applyParameters(pattern, parameters) API. So you can still manage your token substitutions without having to write a separate function to do so.


JET Custom Component Series

If you've just arrived at Custom JET Components and would like to learn more, then you can access the whole series of articles on the topic from the Custom JET Component Learning Path

Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.Captcha