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;
});