JavaScript Application Development API for Oracle Visual Builder Cloud Service - Classic Applications

Source: translations/js/api/I18n.js

define(['core/js/api/Implementations',
        'translations/js/api/Translatable'],
    function (Implementations,
              Translatable) {

    'use strict';

    /**
     * Static routines for common translation tasks.
     *
     * @AbcsAPI stable
     * @version 16.3.1
     * @exports translations/js/api/I18n
     */
    var I18n = function() {
        AbcsLib.throwStaticClassError();
    };

    /**
     * An enum of common translation categories. All translatable strings in the
     * translation table must be rooted on one of the types below. If used
     * consistently to build the keys of the translation table, the table will
     * in the end look like:
     *
     * @example <caption>A sample of translation table when
     *                   i18n types are used consistently</caption>
     *  "main-menu": {
     *    "homePage": "Home"
     *  }
     *  "entities": {
     *    "Sales" : {
     *      "name": "Sales",
     *      "revenue": {
     *          "name": "Revenue"
     *      }
     *    }
     *  }
     *  "pages": {
     *    "homePage": {
     *      "displayName": "Home",
     *      "button-123456678": {
     *        "displayName":
     *      }
     *    }
     *  }
     *
     * @AbcsExtension stable
     * @version 16.3.1
     * @see {@link module:translations/js/api/I18n.key I18n.key()}
     * @enum {String}
     */
    I18n.Type = {
        /** For app-level metadata: App name, copyright notices, etc.  **/
        Application: 'application',
        /** For the page tree and all components on a page **/
        Page: 'pages',
        /** For entities and fields **/
        Entity: 'entities',
        /** For menus and sub-menus **/
        MainMenu: 'main-menu'
    };

     /**
     * An enum of common translation table suffixes. Although a string
     * stored in the translation table must be rooted on one of the translation
     * types in {@link module:translations/js/api/I18n.Type I18n.Type} it need not necessarily end with one of the
     * suffixes enumerated here.
     *
     * @version 16.3.1
     * @see {@link module:translations/js/api/I18n.key I18n.key()}
     * @enum {String}
     */
    I18n.Suffix = {
        /** Name, 'name' **/
        Name: 'name',
        /** Singular name, 'singularName' **/
        SingularName: 'singularName',
        /** Plural name, 'pluralName' **/
        PluralName: 'pluralName',
        /** Description, 'description' **/
        Description: 'description',
        /** Display Name, 'displayName' **/
        DisplayName: 'displayName',
        /** Methods, 'methods' **/
        Methods: 'methods'
    };

    /**
     * Builds an i18n key from the string tokens passed in.
     *
     * <p>
     * The first parameter passed in must be one of the enum types listed in
     * {@link module:translations/js/api/I18n.Type I18n.Type}.
     * </p>
     *
     * @example <caption>Building a key for the title text of a component on a page</caption>
     * var viewI8nKey = I18n.key(I18n.Type.Page, activePage.getId(), view.getId(), 'titleText');
     *
     * @example <caption>Building a key for a display name of a field</caption>
     * var fieldNameKey = I18n.key(I18n.Type.Entity, entity.getId(), field.getId(), I18n.Suffix.SingularName);
     *
     * @AbcsExtension stable
     * @version 16.3.1
     * @static
     * @param {String} type - one of the enum strings in I18n.Type
     * @param {...String} varArgs - keyTokens a vararg of all string tokens that must be
     *        constructed into a key
     * @returns {String} a key generated from the passed-in tokens
     * @throws {Error} in cases where number of tokens < 2 or > 50
     */
    I18n.key = function (type) {
        AbcsLib.checkDefined(type, 'i18n key type');
        AbcsLib.checkParameterCount(arguments, 2, 48);

        var keyArgumets = I18n._filterFalsyTokens(arguments);
        var result;

        Object.getOwnPropertyNames(I18n.Type).forEach(function (enumType) {
            if (type === I18n.Type[enumType]) {
                result = keyArgumets.join('.');
            }
        });

        if (result) {
            return result;
        } else {
            throw new Error('The first passed-in key token wasn\'t ' +
                            'one of the allowed I18n.Type-s. Was \'' + keyArgumets[0] + '\'');
        }
    };

    I18n._filterFalsyTokens = function (array) {
        var result = [];
        for (var i = 0; i < array.length; i++) {
            if (array[i]) {
                result.push(array[i]);
            }
        }
        return result;
    };

    /**
     * A factory method for instantiating {@link module:translations/js/api/Translatable Translatable}.
     * The i18n key passed into this method can be:
     *
     * <ol>
     *   <li>The key of a currently existing translation, run-time or design-time</li>
     *   <li>A newly minted key for a non-existing translation; use {@link module:translations/js/api/I18n.key I18n.key()}
     *       to construct such keys</li>
     *   <li>The empty string. Creating empty-string translatables can be used to
     *       intialize fields with a {@link module:translations/js/api/Translatable Translatable} whose
     *       value can be entered later</li>
     * </ol>
     *
     * @example <caption>Create a Translatable From a DT String</caption>
     * var displayNameNls = I18n.createTranslatable('componentsDt.createButtonDisplayText');
     *
     * @example <caption>Create a Translatable From a Newly-Minted Key</caption>
     * var fieldNameNls = I18n.createTranslatable(I18n.key(I18n.Type.Entity, entity.getId(), field.getId(), I18n.Suffix.SingularName));
     *
     * @example <caption>Create an Empty-String Translatable</caption>
     * var displayNameNls = I18n.createTranslatable('');
     *
     * @example <caption>Create a Translatable From a Previously Serialized Translatable</caption>
     * // Reading a previously persisted translatable
     * var serializedDisplayName = model.data.displayName;
     * // De-serializing a translatable
     * var displayNameNls = I18n.createTranslatable(serializedDisplayName);
     *
     * @AbcsAPI stable
     * @version 16.3.1
     * @static
     * @param {String} i18nKey the key for the new translatable
     * @returns {translations/js/api/Translatable} the created translatable or
     *          undefined if the passed-in key was invalid
     */
    I18n.createTranslatable = function (i18nKey) {
        var translatableObject;

        var TranslatableImpl = Implementations.getImplementation('Translatable');
        if (i18nKey) {
            if (AbcsLib.isString(i18nKey) && i18nKey !== I18n._SERILIZATION_PREFIX) {
                var checkedKey = i18nKey;
                if (I18n.isSerializedTranslatable(checkedKey)) {
                    checkedKey = checkedKey.substring(I18n._SERILIZATION_PREFIX.length);
                }
                translatableObject = new TranslatableImpl(checkedKey);
            }
        } else if (arguments.length === 0 || i18nKey === '') { // a missing key will create an "empty string" translatable
            translatableObject = new TranslatableImpl();
        }

        return translatableObject;
    };

    I18n.createTranslatableIfKeyExisits = function (i18nKey) {
        if (!i18nKey) {
            return null;
        }
        var checkedKey = i18nKey;
        if (I18n.isSerializedTranslatable(checkedKey)) {
            checkedKey = checkedKey.substring(I18n._SERILIZATION_PREFIX.length);
        }
        return AbcsLib.Translations.isKeyExists(checkedKey) ? this.createTranslatable(i18nKey) : null;
    };

    /**
     * Checks if an object is a translatable.
     *
     * @version 16.3.1
     * @static
     * @param {Object} object to check
     * @returns {Boolean} <b>true</b> if the object is a translatable
     */
    I18n.isTranslatable = function (object) {
        return object && object.i18n && object instanceof Translatable;
    };

    /**
     * Checks if an object is a serialized translatable. Can be used to
     * to check it should re-inflate a translatable from persisted model.
     * To de-serialize into a translatable a caller may do the following:
     *
     * @example <caption>De-serializing a Translatable</caption>
     *  if (I18n.isSerializedTranslatable(modelString)) {
     *     value = I18n.createTranslatable(modelString);
     *     // now the Translatable API is available on 'value
     * }
     *
     * @version 16.3.1
     * @static
     * @param {Object} object to check
     * @returns {Boolean} <b>true</b> if the parameter is a serialized translatable
     */
    I18n.isSerializedTranslatable = function (object) {
        return object && AbcsLib.isString(object) &&
               object.indexOf(I18n._SERILIZATION_PREFIX) === 0 &&
               object.length > I18n._SERILIZATION_PREFIX.length;
    };

    /**
     * Checks if an object is a serialized translatable; if so
     * deserializes it. If not return the passed-in object. This is
     * a convenience method for reinflating translatables.
     *
     * @version 16.4.1
     * @static
     * @param {Object} object to check
     * @returns {Translatable|String} <b>Translatable</b> if the parameter is a
     *          serialized translatable, the string if it is not
     */
    I18n.deserializeIfTranslatable = function (object) {
        return I18n.isSerializedTranslatable(object) ?
               I18n.createTranslatable(object) :
               object;
    };

     /**
     * Desiarlizes all translatables in a string. This could be used to
     * deserialize translatables in a string.
     *
     * @version 16.4.1
     * @static
     * @param {String} the message to check for translatables
     * @returns {String} the message with all translatables deserialized
     */
    I18n.deserializeTranslatablesInMessage = function (message) {
        return message.replace(/(i18n:[\w\.]+)/g, function (i18n) {
            return I18n.deserializeIfTranslatable(i18n).toString();
        });
    };

    /**
     * @private
     * @constant
     **/
    I18n._SERILIZATION_PREFIX = 'i18n:';

    return I18n;
});