'use strict'; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /** * Licensed Materials - Property of IBM * IBM Cognos Products: BI Cloud (C) Copyright IBM Corp. 2018, 2020 * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */ define(['jquery', 'underscore', '../../app/nls/StringResources', 'doT', 'text!../../common/templates/TranslationOverlayTemplate.html', '../../app/ui/dialogs/ConfirmationDialog', '../util/ButtonHideHelper', '../../lib/@waca/core-client/js/core-client/utils/Utils'], function ($, _, StringResources, dot, TranslationOverlay, ConfirmationDialog, ButtonHideHelper, Utils) { 'use strict'; var TranslationService = function () { /** * @param options.glassContext - glass context * @param options.eventRouter - event router */ function TranslationService(options) { _classCallCheck(this, TranslationService); _.extend(this, options); this.blacklistCSVAttributes = ['titleHtml']; this.propsStoredAsHTML = ['content']; this.localizedItems = {}; this.dashboardApi.getFeature('Properties').registerProvider(this); this._icons = this.dashboardApi.getFeature('Icons'); this.registeredHandlers = []; } /** * @param options.view * @param options.model */ TranslationService.prototype.registerView = function registerView(options) { this.localizedItems[options.model.id] = options; if (this.isInTranslationMode()) { this._startModelTranslationMode(options.model, options.view, this._getTranslationModeLocale()); } }; /** * @param options.model */ TranslationService.prototype.deregisterView = function deregisterView(id) { if (this.isInTranslationMode()) { this._endModelTranslationMode(this.localizedItems[id].model, this.localizedItems[id].view, true); } delete this.localizedItems[id]; }; /** * @param options.defaultLocale */ TranslationService.prototype.initialize = function initialize(options) { var _this = this; this.$el = options.view; this.boardModel = options.boardModel; this.defaultLocale = options.boardModel.properties.defaultLocale; options.boardModel.properties.on('change:translationModeLocale', this._onChangeTranslationMode, this); options.boardModel.properties.on('change:defaultLocale', this._onChangeDefaultLocale, this); options.boardModel.properties.on('change:switchLanguageInfo', this._onChangeToLocale, this); this._contentLocalesPromise = this.dashboardApi.getFeature('UserProfile').getAvailableContentLocales().then(function (locales) { _this._contentLocales = locales; }); // [perf] we started this in the ctor... return this._contentLocalesPromise; }; /** * Returns an array of radio button property specs to show in the select a language slideout */ TranslationService.prototype.getLanguageRadioItems = function getLanguageRadioItems() { var languageList = []; var selectedLanguages = this.getSelectedLanguages(); if (this.getDefaultLanguage() === 'Default') { // If a defaultLocale hasn't been chosen, 'Default' will be one of the selected languages // we need to remove any selected languages so any default may be chosen selectedLanguages = []; } _.each(this._contentLocales, function (label, value) { if (selectedLanguages.indexOf(value) === -1) { languageList.push({ value: value, label: label }); } }); return languageList; }; TranslationService.prototype.getContentLocales = function getContentLocales() { return this._contentLocales; }; TranslationService.prototype.getLanguageName = function getLanguageName(languageId) { return this._contentLocales[languageId]; }; TranslationService.prototype._onChangeTranslationMode = function _onChangeTranslationMode() { var translationModeLocale = this._getTranslationModeLocale(); if (!translationModeLocale) { this._endTranslationMode(); } else { this._startTranslationMode(translationModeLocale); } }; TranslationService.prototype._getTranslationModeLocale = function _getTranslationModeLocale() { return this.boardModel.properties.get('translationModeLocale'); }; TranslationService.prototype.isInTranslationMode = function isInTranslationMode() { return this.translationModeOn; }; /** * Use a property in the model to trigger the translation mode so that * we can take advantage of the undo/redo stack */ TranslationService.prototype.startTranslationMode = function startTranslationMode(selectedLanguage) { this.boardModel.setTranslationLocale(selectedLanguage); }; TranslationService.prototype.endTranslationMode = function endTranslationMode() { this.boardModel.setTranslationLocale(null); }; TranslationService.prototype._startTranslationMode = function _startTranslationMode(selectedLanguage) { var translationOverlay = dot.template(TranslationOverlay)({ 'text': StringResources.get('multilingualDashboardTranslationMode', { currentLanguage: this.getLanguageName(selectedLanguage) }), 'buttonText': StringResources.get('multilingualDashboardTranslationDone') }); this.$el.append(translationOverlay); this.$el.find('.translate-button').click(this.endTranslationMode.bind(this)); this.translationModeOn = true; this.translationModeLanguage = selectedLanguage; this.eventRouter.trigger('properties:refreshPane'); ButtonHideHelper.changeMode(this.glassContext, 'translation'); this.numTranslationsLeft = 0; this.showingMissingTranslationCount = false; for (var itemId in this.localizedItems) { var _localizedItems$itemI = this.localizedItems[itemId], model = _localizedItems$itemI.model, view = _localizedItems$itemI.view; this._startModelTranslationMode(model, view, selectedLanguage); } }; TranslationService.prototype._startModelTranslationMode = function _startModelTranslationMode(model, view, selectedLanguage) { var _this2 = this; var multilingualAttributesInfo = model.getMultilingualAttributes(); var missingTranslationMultilingualAttributesInfo = []; var localizedItem = this.localizedItems[model.id]; if (localizedItem.enterTranslationMode) { localizedItem.enterTranslationMode(); } multilingualAttributesInfo.forEach(function (multilingualAttributeInfo) { var propertyName = multilingualAttributeInfo.propertyName, propertyParentModel = multilingualAttributeInfo.propertyParentModel, multilingualProperty = multilingualAttributeInfo.multilingualProperty; multilingualProperty.startTranslation(selectedLanguage); if (_this2.dashboardApi && propertyParentModel.multilingual) { var content = _this2.dashboardApi.getCanvas().getContent(model.id); content.on('change:property:' + multilingualAttributeInfo.propertyParentModel.name, _this2._onPropertyChange.bind(_this2, model.id, model, multilingualAttributeInfo.propertyParentModel.name)); } else { var handler = propertyParentModel.on('change:' + propertyName, _this2._onPropertyChange.bind(_this2, model.id, propertyParentModel, propertyName)); _this2.registeredHandlers.push(handler); } if (Object.keys(multilingualProperty.translationTable).length === 0) { return; } if (multilingualProperty.needsTranslation()) { missingTranslationMultilingualAttributesInfo.push(multilingualAttributeInfo); } else { _this2._updateView(propertyParentModel, propertyName, _this2.localizedItems[model.id]); } }); if (missingTranslationMultilingualAttributesInfo.length > 0) { this._appendTranslationIcon(view, missingTranslationMultilingualAttributesInfo); } }; TranslationService.prototype._onPropertyChange = function _onPropertyChange(modelId, parentModel, propertyName) { var multilingualAttributeInfo = parentModel.getMultilingualAttribute(propertyName); if (!multilingualAttributeInfo) { return; } var multilingualProperty = multilingualAttributeInfo.multilingualProperty; var view = this.localizedItems[modelId].view; if (multilingualProperty.needsTranslation()) { this._appendTranslationIcon(view, [multilingualAttributeInfo]); } else { this._removeTranslationIcon(view, [multilingualAttributeInfo]); } }; TranslationService.prototype._endTranslationMode = function _endTranslationMode() { this.$el.find('div.translate-overlay').remove(); this.translationModeOn = false; this.showingMissingTranslationCount = false; for (var itemId in this.localizedItems) { var item = this.localizedItems[itemId]; this._endModelTranslationMode(item.model, item.view, false); } this.eventRouter.trigger('properties:refreshPane', { focusSelector: '.clickablelanguage_' + this.translationModeLanguage }); ButtonHideHelper.changeMode(this.glassContext, 'authoring'); }; TranslationService.prototype._endModelTranslationMode = function _endModelTranslationMode(model, view, deregisteringView) { var _this3 = this; var localizedItem = this.localizedItems[model.id]; if (localizedItem.leaveTranslationMode) { localizedItem.leaveTranslationMode(); } this.registeredHandlers.forEach(function (handler) { handler.remove(); }); this.registeredHandlers = []; var multilingualAttributesInfo = model.getMultilingualAttributes(); multilingualAttributesInfo.forEach(function (multilingualAttributeInfo) { var propertyName = multilingualAttributeInfo.propertyName, propertyParentModel = multilingualAttributeInfo.propertyParentModel, multilingualProperty = multilingualAttributeInfo.multilingualProperty; multilingualProperty.stopTranslation(); if (!deregisteringView) { _this3._updateView(propertyParentModel, propertyName, _this3.localizedItems[model.id]); } if (_this3.dashboardApi && propertyParentModel.multilingual) { var content = _this3.dashboardApi.getCanvas().getContent(model.id); content.off('change:property:' + multilingualAttributeInfo.propertyParentModel.name, _this3._onPropertyChange.bind(_this3, model.id, model, multilingualAttributeInfo.propertyParentModel.name)); } }); this._removeTranslationIcon(view, multilingualAttributesInfo); }; /** * Will cause the view/text to get updated so the correct string (locale) is shown */ TranslationService.prototype._updateView = function _updateView(mode, propertyName, localizedItem) { if (localizedItem.reRender) { localizedItem.reRender(); } else { this._triggerTextUpdate(mode, propertyName); } }; TranslationService.prototype._triggerTextUpdate = function _triggerTextUpdate(model, propertyName) { var obj = {}; obj[propertyName] = model.get(propertyName); //TODO fix this in Endor with ES6 model.set(obj, { payloadData: { forceEvent: true, skipUndoRedo: true }, sender: 'TranslationService' }); }; /** * Adds the translation icon * @param {Object} view - the view that was registered with the translation service * @param {Array} multilingualAttributesInfo - All the information about the multilingual attributes in the model that are missing translations */ TranslationService.prototype._appendTranslationIcon = function _appendTranslationIcon(view, multilingualAttributesInfo) { // We should never append translation icons if we're not in translation mode if (!this.isInTranslationMode()) { return; } if (view.addTranslationIcon) { this.numTranslationsLeft += view.addTranslationIcon(multilingualAttributesInfo); } else { this.appendTranslationIcon(view.$el); this.numTranslationsLeft++; } this._displayRemainingMessage(); }; TranslationService.prototype.appendTranslationIcon = function appendTranslationIcon($el) { if (this.isInTranslationMode()) { var $iconContainer = $('
'); Utils.setIcon($iconContainer, this._icons.getIcon('warning').id, StringResources.get('multilingualDashboardIconTranslatableArea')); $el.append($iconContainer); } }; TranslationService.prototype.updateRemainingCount = function updateRemainingCount(delta) { if (delta !== 0) { this.showingMissingTranslationCount = true; } this.numTranslationsLeft += delta; this._displayRemainingMessage(); }; /** * Adds the translation icon * @param {Object} view - the view that was registered with the translation service * @param {Array} multilingualAttributesInfo - All the information about the multilingual attributes in the model for which we want the icon to be removed */ TranslationService.prototype._removeTranslationIcon = function _removeTranslationIcon(view, multilingualAttributesInfo) { var el = view.$el; if (view.removeTranslationIcon) { var numRemoved = view.removeTranslationIcon(multilingualAttributesInfo); if (numRemoved) { this.updateRemainingCount(-numRemoved); } } else { if (this.hasTranslationIcon(el)) { this.updateRemainingCount(-1); this.removeTranslationIcon(el); } } }; TranslationService.prototype.hasTranslationIcon = function hasTranslationIcon($el) { return $el.find('.translateIcon').length > 0; }; TranslationService.prototype.removeTranslationIcon = function removeTranslationIcon($el) { $el.find('.translateIcon').remove(); }; TranslationService.prototype._displayRemainingMessage = function _displayRemainingMessage() { if (this.numTranslationsLeft >= 0 && this.showingMissingTranslationCount) { var remainingTranslations; if (this.numTranslationsLeft === 1) { remainingTranslations = StringResources.get('multilingualDashboardRemainingString'); } else { remainingTranslations = StringResources.get('multilingualDashboardRemainingStrings', { numTranslationsLeft: this.numTranslationsLeft }); } this.$el.find('.translate-text').text(remainingTranslations); } }; TranslationService.prototype.downloadTranslations = function downloadTranslations(selectedLanguage) { var localizedStrings = this._getLocalizedStrings(selectedLanguage); var filename = 'OriginalStrings_' + selectedLanguage; this.dashboardApi.getFeature('CsvExport').export(filename, [localizedStrings]); }; TranslationService.prototype.removeTranslations = function removeTranslations(selectedLanguage) { var _this4 = this; var language = this.getContentLocales()[selectedLanguage]; var dlg = new ConfirmationDialog('warning', StringResources.get('multilingualDeleteTitle'), StringResources.get('multilingualDeleteLanguageWarning', { language: language })); dlg.confirm(function () { var undoRedoTransactionId = _.uniqueId('removeTranslations'); for (var itemId in _this4.localizedItems) { var model = _this4.localizedItems[itemId].model; var multilingualAttributesInfo = model.getMultilingualAttributes(); multilingualAttributesInfo.forEach(function (_ref) { var propertyName = _ref.propertyName, propertyParentModel = _ref.propertyParentModel; var payload = {}; payload[propertyName] = { value: null, locale: selectedLanguage }; propertyParentModel.set(payload, { sender: 'TranslationService', payloadData: { undoRedoTransactionId: undoRedoTransactionId } }); }); _this4._onMultilingualPropertyChange(itemId); } _this4.eventRouter.trigger('properties:refreshPane', { focusSelector: '.r_addLanguage-1' }); }, function () {}); }; TranslationService.prototype.changeDefaultLanguage = function changeDefaultLanguage(selectedLanguage) { this.boardModel.properties.set({ defaultLocale: selectedLanguage }); }; /** * * @param {Object} property It should has the following structure: * { * editor: { * uiControl: {} * } * } * @param {MultilingualAttribute Object} multilingualProperty * @returns The passed in property * @description This will end up being called by PropertyUIControlView after the property has been rendered. */ TranslationService.prototype.processMultilingualProperty = function processMultilingualProperty(property, multilingualProperty) { if (multilingualProperty) { var appendTranslationIcon = function appendTranslationIcon($el) { if (multilingualProperty.needsTranslation()) { this.appendTranslationIcon($el); } }; property.editor.uiControl.appendTranslationIcon = appendTranslationIcon.bind(this); } return property; }; /** * Currently only needed by LiveWidget to deal with the fact they have 2 model representing the same information */ TranslationService.prototype._onMultilingualPropertyChange = function _onMultilingualPropertyChange(modelId) { var localizedItem = this.localizedItems[modelId]; if (localizedItem && localizedItem.onMultilingualPropertyChange) { localizedItem.onMultilingualPropertyChange(); } }; TranslationService.prototype._onChangeDefaultLocale = function _onChangeDefaultLocale() { var _this5 = this; var defaultLocale = this.getDefaultLanguage(); this.boardModel.setDefaultLocale(defaultLocale); var _loop = function _loop(itemId) { var model = _this5.localizedItems[itemId].model; var multilingualAttributesInfo = model.getMultilingualAttributes(); multilingualAttributesInfo.forEach(function (_ref2) { var propertyName = _ref2.propertyName, propertyParentModel = _ref2.propertyParentModel, multilingualProperty = _ref2.multilingualProperty; multilingualProperty.setDefaultLocale(defaultLocale); _this5._updateView(propertyParentModel, propertyName, _this5.localizedItems[itemId]); }); _this5._onMultilingualPropertyChange(itemId); }; for (var itemId in this.localizedItems) { _loop(itemId); } this.eventRouter.trigger('properties:refreshPane', { focusSelector: '.clickablelanguage_' + defaultLocale }); }; TranslationService.prototype._onChangeToLocale = function _onChangeToLocale() { var _this6 = this; var options = this.boardModel.properties.get('switchLanguageInfo'); var _loop2 = function _loop2(itemId) { var model = _this6.localizedItems[itemId].model; var multilingualAttributesInfo = model.getMultilingualAttributes(); multilingualAttributesInfo.forEach(function (_ref3) { var propertyName = _ref3.propertyName, propertyParentModel = _ref3.propertyParentModel, multilingualProperty = _ref3.multilingualProperty; multilingualProperty.switchLocale(options); _this6._updateView(propertyParentModel, propertyName, _this6.localizedItems[itemId]); }); _this6._onMultilingualPropertyChange(itemId); }; for (var itemId in this.localizedItems) { _loop2(itemId); } this.eventRouter.trigger('properties:refreshPane', { focusSelector: '.clickablelanguage_' + options.to }); }; /** * @param {String} options.from - locale switch from * @param {String} options.to - locale switching to */ TranslationService.prototype.switchLanguage = function switchLanguage(options) { if (options.from === this.getDefaultLanguage()) { this.changeDefaultLanguage(options.to); } else { // Set the property silently so the undo/redo stack will get the correct 'before' value this.boardModel.properties.set({ switchLanguageInfo: { from: options.to, to: options.from } }, { silent: true, payloadData: { skipUndoRedo: true } }); this.boardModel.properties.set({ switchLanguageInfo: options }); } }; TranslationService.prototype.getDefaultLanguage = function getDefaultLanguage() { return this.boardModel.get('properties').get('defaultLocale'); }; TranslationService.prototype._getLocalizedStrings = function _getLocalizedStrings(language) { var _this7 = this; var stringList = []; for (var itemId in this.localizedItems) { var model = this.localizedItems[itemId].model; var multilingualAttributes = model.getMultilingualAttributes(); multilingualAttributes.forEach(function (_ref4) { var propertyName = _ref4.propertyName, multilingualProperty = _ref4.multilingualProperty; if (_this7.blacklistCSVAttributes.indexOf(propertyName) !== -1) { return; } var value = multilingualProperty.getValue(language); if (!value) { return; } if (_this7.propsStoredAsHTML.indexOf(propertyName) !== -1) { var $textNode = void 0; try { $textNode = $(value); } catch (error) { $textNode = []; } finally { if ($textNode.length) { value = $textNode.text(); } } } value = value.trim(); stringList.push(value); }); } return stringList; }; TranslationService.prototype._addTo = function _addTo(list, values) { return _.union(list, Object.keys(values)); }; /** * Gets all the locales the dashboard has been translated into */ TranslationService.prototype.getSelectedLanguages = function getSelectedLanguages() { var languageList = []; for (var itemId in this.localizedItems) { var model = this.localizedItems[itemId].model; var multilingualAttributes = model.getMultilingualAttributes(); multilingualAttributes.forEach(function (_ref5) { var multilingualProperty = _ref5.multilingualProperty; languageList = languageList.concat(multilingualProperty.getLanguages()); }); } return _.uniq(languageList); }; TranslationService.prototype.destroy = function destroy() { if (this.dashboardApi) { this.dashboardApi.getFeature('Properties').deregisterProvider(this); } this.localizedItems = null; this._contentLocales = null; }; TranslationService.prototype.getPropertyLayoutList = function getPropertyLayoutList() { return [{ id: 'advanced', type: 'Section', label: StringResources.get('sectionName_advanced'), position: 99 }, { id: 'languages', type: 'Section', label: StringResources.get('multilingualDashboardsLabel'), collapsible: false, style: 'light' }]; }; TranslationService.prototype.getPropertyList = function getPropertyList() { var propertiesManager = this.dashboardApi.getFeature('propertiesManager'); if (!propertiesManager) { return []; } if (this.getDefaultLanguage() === 'Default') { //Advanced.languages property's selection list is populated using content locale list //Hide Advanced.languages property when there are no available content locales if (this.getContentLocales()) { return this._getLanguageSpecWhenNoLocaleSet(propertiesManager); } else { return []; } } return this._getMultilingualProperties(propertiesManager); }; /** * Language property spec when no language has been selected yet */ TranslationService.prototype._getLanguageSpecWhenNoLocaleSet = function _getLanguageSpecWhenNoLocaleSet(propertiesManager) { var _this8 = this; var defaultLanguage = this.getDefaultLanguage(); return [{ id: 'language_' + defaultLanguage, editor: { sectionId: 'general.advanced', position: 3, uiControl: { type: 'SingleLineLinks', items: [{ align: 'left', items: [{ type: 'text', id: 'text' + defaultLanguage, value: StringResources.get('multilingualDashboardsLabel') }] }, { align: 'right', items: [{ type: 'text', value: StringResources.get('multilingualDashboardsSetDefault'), clickCallback: function clickCallback() { _this8.launchLanguageSelectSlideout(defaultLanguage, false, propertiesManager); } }] }] } } }]; }; TranslationService.prototype._getMultilingualProperties = function _getMultilingualProperties(propertiesManager) { var _this9 = this; var defaultLanguage = this.getDefaultLanguage(); var properties = [].concat(this._createLanguageRow(defaultLanguage, true)); // Rows for all other available languages this.getSelectedLanguages().sort(function (a, b) { return _this9.getLanguageName(a) > _this9.getLanguageName(b) ? 1 : -1; }).forEach(function (language) { if (language !== defaultLanguage && language !== 'Default') { properties.push(_this9._createLanguageRow(language, false)); } }); properties.push({ id: 'addLanguage', editor: { sectionId: 'general.advanced.languages', uiControl: { type: 'SingleLineLinks', isDisabled: this.translationModeOn, items: [{ align: 'right', items: [{ type: 'text', value: StringResources.get('multilingualDashboardsAddLinkText'), clickCallback: function clickCallback() { _this9.launchLanguageSelectSlideout(null, true, propertiesManager); } }] }] } } }); return properties; }; /** * Creats a SingleLineLink property spec that describes a language */ TranslationService.prototype._createLanguageRow = function _createLanguageRow(locale, isDefaultLocale) { var _this10 = this; var languageName = this.getLanguageName(locale); return { id: 'language_' + locale, editor: { sectionId: 'general.advanced.languages', uiControl: { type: 'SingleLineLinks', indent: 2, disabled: this.translationModeOn, items: [{ align: 'left', items: [] }, { align: 'right', items: [{ type: 'text', id: 'text' + locale, value: isDefaultLocale ? StringResources.get('multilingualDashboardsDefault', { defaultLanguage: languageName }) : languageName }, { type: 'icon', svgIcon: 'common-menuoverflow', iconTooltip: StringResources.get('multilingualDashboardIconMore', { currentLanguage: languageName }), clickCallback: function clickCallback(evt) { _this10.launchLanguageMenu(evt, locale); } }] }] } } }; }; /** * When picking a language, we launch an overlay slideout with all the content locales */ TranslationService.prototype.launchLanguageSelectSlideout = function launchLanguageSelectSlideout(selectedLocale, addLanguage, propertiesManager) { var _this11 = this; // ensure properties manager is available propertiesManager = propertiesManager || this.dashboardApi.getFeature('propertiesManager'); propertiesManager.addChild({ overlay: true, label: StringResources.get('multilingualSelectLanguage'), content: { module: 'dashboard-core/js/dashboard/contentpane/PropertyUIControlView', items: [{ value: StringResources.get('multilingualSelectLanguage'), centerLabel: true, type: 'Banner', backButton: true, ariaLabel: StringResources.get('multilingualSelectLanguage') }, { type: 'RadioButtonGroup', name: 'language', separator: true, ariaLabel: StringResources.get('multilingualSelectLanguage'), value: selectedLocale, selectOnNavigation: false, items: this.getLanguageRadioItems(), onChange: function onChange(name, newLocale) { propertiesManager.closeChild(); if (selectedLocale === 'Default') { _this11.changeDefaultLanguage(newLocale); } else if (addLanguage) { _this11.startTranslationMode(newLocale); } else { _this11.switchLanguage({ from: selectedLocale, to: newLocale }); } } }] } }); }; /** * User clicked on the ..., so show the menu */ TranslationService.prototype.launchLanguageMenu = function launchLanguageMenu(evt, locale) { var position = {}; if (evt.pageX === undefined || evt.gesture && (evt.gesture.center === undefined || evt.gesture.center.pageX === undefined)) { position = $(evt.target).offset(); } else { position.left = evt.pageX || evt.gesture.center.pageX; position.top = evt.pageY || evt.gesture.center.pageY; } this.glassContext.appController.showContextMenu({ position: { pageX: position.left, pageY: position.top }, menuId: 'com.ibm.bi.dashboard.languageMenu', activeObject: { selectedLocale: locale, translationService: this, layoutBaseView: this } }); }; return TranslationService; }(); return TranslationService; }); //# sourceMappingURL=TranslationService.js.map