/* Adding the languages support requires - 1. Importing the API18N.js file in the app.js file 2. Adding a dictionary service - The service will return a JSON that holds all of the translations for each screen (it can be a DB service or a JS one) 3. Adding configuration object in the app.js file, the object must include the languages array (all supported languages), and match the defaultLanguageConfiguration object's fields Besides the translation process (which should happen automatically) there are some helper functions - 1. switchLanguage(selectedLanguage) - Switch to different language, and translate 2. getTranslationForId(id, param1, param2,...) - return a translation for a specific id. Use params as a dynamic replacement in the returned message message example with 2 params - "bla ${1} bla ${2} 3. translatePage() - run the translation process manually 4. showLanguageError(error) - overwrite this function to change the way errors are handled 5. createLanguageMenu() - overwrite this function to change the UI for the languages buttons (currently automatically added to the menu bar) */ var api18n; var defaultLanguageConfiguration = { defaultLanguage: 'english', dictionaryService: 'getLanguageDictionary', //each app can have it's own dictionary (e.g. absencesLanguageDictionary), can be configured in app.languageConfiguration languages: [ //all supported languages in the dictionary should be added to app.languageConfiguration { title: 'EN', language: 'english' }, ] } /* version 1.0, 03-2020 note - supports LTR language only */ var API18N = function (dictionary) { var _dictionary = dictionary; if (!_dictionary) { console.error('API18N init error - Must provide a dictionary'); } var _translate = function (forceTranslate) { var languageSelected = localStorage.getItem('language'); // no need to translate english if ((!languageSelected || languageSelected.toLowerCase() === "english") && !forceTranslate) { return; } // Common buttons, Menu items, etc. which will work on every page $.each(_dictionary["Common"], function (selector) { // dynamic key no need to scan page if (selector.indexOf('@') != 0) { elements = _fillSelectorTemplates(selector); elements.forEach(function (element) { $(element).html(_dictionary["Common"][selector][_currentLanguage]); }); } }); // Don't want to fail on missing translation, in that case just display english if (!_dictionary[_currentPage]) return; var elements; $.each(_dictionary[_currentPage], function (selector) { // dynamic key no need to scan page if (selector.indexOf('@') != 0) { elements = _fillSelectorTemplates(selector); elements.forEach(function (element) { $(element).html(_dictionary[_currentPage][selector][_currentLanguage]); }); } }); } var _fillSelectorTemplates = function (selector) { //custom selector or translation key for dynamic translations if ((selector.indexOf('#') >= 0) || (selector.indexOf('.') >= 0)) { return [selector]; } return [ //ID shortcuts for specific AuraPlayer's components 'button#' + selector, //buttons 'th#\\*th\\*' + selector, //Table headers 'h3#' + selector, //Page header '#' + selector + '_container>div>label>nobr', //checkbox '#' + selector + '_container>label>nobr', //labels '.menu-text#' + selector //Menu items ].filter(function(s){ //chain filters here to remove unwanted selectors from being used return $(s).parent().is(':not(.dropdown-container)') //no need to change text for dropdowns (only for their label) }) } var _replaceParamValues = function (str, argsArr) { if (argsArr == null || argsArr.length == 0) return str; var retStr = str; argsArr.forEach(function(element, index) { var ind = index+1; retStr = retStr.replace ("${" + ind + "}", element); }); return retStr; } var _getTranslationForId = function (id, argsArr) { if (!id || id === '') { console.error('API18N _getTranslationForId error - Must provide an Id'); return ''; } if (!_currentLanguage || _currentLanguage === '') { console.error('API18N _getTranslationForId error - Must set language'); return ''; } if (!_currentPage || _currentPage === '') { console.error('API18N _getTranslationForId error - Must set page'); return ''; } // First check in common then in current page if (_dictionary["Common"][id]) { return _replaceParamValues(_dictionary["Common"][id][_currentLanguage], argsArr); } else if (_dictionary[_currentPage][id]) { return _replaceParamValues(_dictionary[_currentPage][id][_currentLanguage], argsArr); } // if id not found then return id (prevent exceptions) return id; } var _setCurrentLanguage = function (language) { _currentLanguage = language.toLowerCase(); } var _getCurrentLanguage = function () { return _currentLanguage; } var _setCurrentPage = function (page) { _currentPage = page; } var _getCurrentPage = function () { return _currentPage; } var _setStyle = function (style) { _style = style; } var _getOriginalStyle = function () { return _originalStyle; } return { translate: _translate, getCurrentLanguage: _getCurrentLanguage, setCurrentLanguage: _setCurrentLanguage, getCurrentPage: _getCurrentPage, setCurrentPage: _setCurrentPage, setStyle: _setStyle, getOriginalStyle: _getOriginalStyle, getTranslationForId: _getTranslationForId } } var loadLanguageModule = function () { config = app.languageConfiguration ? $.extend(defaultLanguageConfiguration, app.languageConfiguration) : defaultLanguageConfiguration; try { var dictionary = loadDictionary(); invokeLanguageServices(dictionary); createLanguageMenu(); api18n.translate(); } catch (error){ showLanguageError(error); } function loadDictionary() { var service = config.dictionaryService; var dictionaryName = service; if (!localStorage.getItem(dictionaryName)) { var response = Services.callSync(service, function(){ throw('Couldn\'t load dictionary'); }); var dictionary = response['Response'][service+'Elements']['dictionary']; localStorage.setItem(dictionaryName, JSON.stringify(dictionary)); return dictionary; } else { //load existing dictionary return JSON.parse(localStorage.getItem(dictionaryName)); } } } function invokeLanguageServices(dictionary) { api18n = new API18N(dictionary); if (typeof api18n === 'undefined') { //not supposed to happen throw('Couldn\'t load language module'); return; } var languageSelected = localStorage.getItem('language'); api18n.setCurrentPage(Page.getCurrentPage().split('.html')[0]); if (!languageSelected) { //first load - set default values api18n.setCurrentLanguage(config.defaultLanguage); localStorage.setItem('language', config.defaultLanguage); Storage.set('language', config.defaultLanguage); //for services } else { api18n.setCurrentLanguage(languageSelected); Storage.set('language', languageSelected); //for services } } var switchLanguage = function (language) { if (typeof api18n === 'undefined') { //not supposed to happen throw('Couldn\'t load language module'); } localStorage.setItem('language', language); Storage.set('language', language); //for services api18n.setCurrentLanguage(language); api18n.translate(true); } var getTranslationForId = function(id){ if (typeof api18n === 'undefined') { //not supposed to happen throw('Couldn\'t load language module'); } var args = Array.prototype.slice.call(arguments).splice(1); return api18n.getTranslationForId(id, args); } var translatePage = function () { if (typeof api18n === 'undefined') {//not supposed to happen throw('Couldn\'t load language module'); } if (!localStorage.getItem('dictionary')) { //weird IE bug... loadLanguageModule(); } else { Storage.set('language', localStorage.getItem('language')); api18n.setCurrentLanguage(localStorage.getItem('language')); api18n.setCurrentPage(Page.getCurrentPage().split('.html')[0]); api18n.translate(true); } } function createLanguageMenu(){ if (!config.languages){ throw('Couldn\'t load languages array from app.config'); } if (config.languages.length <= 1){ throw('Only one language on languages array from app.config'); } var html = ''; config.languages.forEach(function(language){ html+=''; }) html += ''; $(html).insertAfter($('#hamburger-title')[0]? $('#hamburger-title') : $('#mainForm')); } function cleanLanguageDictionary(){ localStorage.removeItem(app.languageConfiguration.dictionaryService); } var showLanguageError = function(error){ console.error(error); Popup.ok('Language Module Error', error); }