diff --git a/docs-web/src/main/webapp/src/app/docs/app.js b/docs-web/src/main/webapp/src/app/docs/app.js
index e578bc7c..c8407ab5 100644
--- a/docs-web/src/main/webapp/src/app/docs/app.js
+++ b/docs-web/src/main/webapp/src/app/docs/app.js
@@ -350,9 +350,15 @@ angular.module('docs',
'en_*': 'en',
'fr_*': 'fr',
'*': 'en'
- })
- .determinePreferredLanguage()
- .fallbackLanguage('en');
+ });
+
+ if (!_.isUndefined(localStorage.overrideLang)) {
+ // Set the current language if an override is saved in local storage
+ $translateProvider.use(localStorage.overrideLang);
+ } else {
+ // Or else determine the language based on the user's browser
+ $translateProvider.determinePreferredLanguage();
+ }
// Configuring Timago
timeAgoSettings.overrideLang = $translateProvider.preferredLanguage();
diff --git a/docs-web/src/main/webapp/src/app/docs/controller/Footer.js b/docs-web/src/main/webapp/src/app/docs/controller/Footer.js
index f5a60448..272310c3 100644
--- a/docs-web/src/main/webapp/src/app/docs/controller/Footer.js
+++ b/docs-web/src/main/webapp/src/app/docs/controller/Footer.js
@@ -3,24 +3,21 @@
/**
* Footer controller.
*/
-angular.module('docs').controller('Footer', function($scope, Restangular, $translate, timeAgoSettings) {
+angular.module('docs').controller('Footer', function($scope, $rootScope, Restangular, $translate, timeAgoSettings) {
// Load app data
Restangular.one('app').get().then(function(data) {
$scope.app = data;
});
- $scope.currentLang = $translate.use();
+ // Save the current language to local storage
+ $rootScope.$on('$translateChangeSuccess', function() {
+ $scope.currentLang = $translate.use();
+ timeAgoSettings.overrideLang = $scope.currentLang;
+ localStorage.overrideLang = $scope.currentLang;
+ });
- // Change the current language and save it to local storage
+ // Change the current language
$scope.changeLanguage = function(lang) {
$translate.use(lang);
- timeAgoSettings.overrideLang = lang;
- localStorage.overrideLang = lang;
- $scope.currentLang = lang;
};
-
- // Set the current language if an override is saved in local storage
- if (!_.isUndefined(localStorage.overrideLang)) {
- $scope.changeLanguage(localStorage.overrideLang);
- }
});
\ No newline at end of file
diff --git a/docs-web/src/main/webapp/src/index.html b/docs-web/src/main/webapp/src/index.html
index 087c9349..3b0e642d 100644
--- a/docs-web/src/main/webapp/src/index.html
+++ b/docs-web/src/main/webapp/src/index.html
@@ -30,6 +30,7 @@
+
@@ -88,7 +89,7 @@
-
+
@@ -2616,7 +2938,8 @@ angular.module('pascalprecht.translate')
$translateProvider.translations('en',{
'TRANSLATION_ID': 'Hello there!',
- 'WITH_VALUES': 'The following value is dynamic: {{value}}'
+ 'WITH_VALUES': 'The following value is dynamic: {{value}}',
+ 'WITH_CAMEL_CASE_KEY': 'The interpolation key is camel cased: {{camelCaseKey}}'
}).preferredLanguage('en');
});
@@ -2653,13 +2976,17 @@ angular.module('pascalprecht.translate')
element = $compile('
')($rootScope);
$rootScope.$digest();
expect(element.attr('title')).toBe('Hello there!');
+
+ element = $compile('
')($rootScope);
+ $rootScope.$digest();
+ expect(element.text()).toBe('The interpolation key is camel cased: Hello');
});
});
*/
.directive('translate', translateDirective);
-function translateDirective($translate, $q, $interpolate, $compile, $parse, $rootScope) {
+function translateDirective($translate, $interpolate, $compile, $parse, $rootScope) {
'use strict';
@@ -2676,6 +3003,19 @@ function translateDirective($translate, $q, $interpolate, $compile, $parse, $roo
return this.toString().replace(/^\s+|\s+$/g, '');
};
+ /**
+ * @name lowercase
+ * @private
+ *
+ * @description
+ * Return the lowercase string only if the type is string
+ *
+ * @returns {string} The string all in lowercase
+ */
+ var lowercase = function (string) {
+ return angular.isString(string) ? string.toLowerCase() : string;
+ };
+
return {
restrict: 'AE',
scope: true,
@@ -2688,6 +3028,9 @@ function translateDirective($translate, $q, $interpolate, $compile, $parse, $roo
var translateInterpolation = (tAttr.translateInterpolation) ?
tAttr.translateInterpolation : undefined;
+ var translateSanitizeStrategyExist = (tAttr.translateSanitizeStrategy) ?
+ tAttr.translateSanitizeStrategy : undefined;
+
var translateValueExist = tElement[0].outerHTML.match(/translate-value-+/i);
var interpolateRegExp = '^(.*)(' + $interpolate.startSymbol() + '.*' + $interpolate.endSymbol() + ')(.*)',
@@ -2710,7 +3053,7 @@ function translateDirective($translate, $q, $interpolate, $compile, $parse, $roo
if (translateValueExist) {
for (var attr in tAttr) {
if (Object.prototype.hasOwnProperty.call(iAttr, attr) && attr.substr(0, 14) === 'translateValue' && attr !== 'translateValues') {
- var attributeName = angular.lowercase(attr.substr(14, 1)) + attr.substr(15);
+ var attributeName = lowercase(attr.substr(14, 1)) + attr.substr(15);
interpolateParams[attributeName] = tAttr[attr];
}
}
@@ -2781,7 +3124,7 @@ function translateDirective($translate, $q, $interpolate, $compile, $parse, $roo
});
for (var translateAttr in iAttr) {
- if (iAttr.hasOwnProperty(translateAttr) && translateAttr.substr(0, 13) === 'translateAttr') {
+ if (iAttr.hasOwnProperty(translateAttr) && translateAttr.substr(0, 13) === 'translateAttr' && translateAttr.length > 13) {
observeAttributeTranslation(translateAttr);
}
}
@@ -2791,6 +3134,13 @@ function translateDirective($translate, $q, $interpolate, $compile, $parse, $roo
updateTranslations();
});
+ if (translateSanitizeStrategyExist) {
+ iAttr.$observe('translateSanitizeStrategy', function (value) {
+ scope.sanitizeStrategy = $parse(value)(scope.$parent);
+ updateTranslations();
+ });
+ }
+
if (translateValuesExist) {
iAttr.$observe('translateValues', function (interpolateParams) {
if (interpolateParams) {
@@ -2804,7 +3154,7 @@ function translateDirective($translate, $q, $interpolate, $compile, $parse, $roo
if (translateValueExist) {
var observeValueAttribute = function (attrName) {
iAttr.$observe(attrName, function (value) {
- var attributeName = angular.lowercase(attrName.substr(14, 1)) + attrName.substr(15);
+ var attributeName = lowercase(attrName.substr(14, 1)) + attrName.substr(15);
scope.interpolateParams[attributeName] = value;
});
};
@@ -2818,7 +3168,6 @@ function translateDirective($translate, $q, $interpolate, $compile, $parse, $roo
// Master update function
var updateTranslations = function () {
for (var key in translationIds) {
-
if (translationIds.hasOwnProperty(key) && translationIds[key] !== undefined) {
updateTranslation(key, translationIds[key], scope, scope.interpolateParams, scope.defaultText, scope.translateNamespace);
}
@@ -2833,7 +3182,7 @@ function translateDirective($translate, $q, $interpolate, $compile, $parse, $roo
translationId = translateNamespace + translationId;
}
- $translate(translationId, interpolateParams, translateInterpolation, defaultTranslationText, scope.translateLanguage)
+ $translate(translationId, interpolateParams, translateInterpolation, defaultTranslationText, scope.translateLanguage, scope.sanitizeStrategy)
.then(function (translation) {
applyTranslation(translation, scope, true, translateAttr);
}, function (translationId) {
@@ -2846,12 +3195,16 @@ function translateDirective($translate, $q, $interpolate, $compile, $parse, $roo
};
var applyTranslation = function (value, scope, successful, translateAttr) {
- if (translateAttr === 'translate') {
- // default translate into innerHTML
- if (!successful && typeof scope.defaultText !== 'undefined') {
+ if (!successful) {
+ if (typeof scope.defaultText !== 'undefined') {
value = scope.defaultText;
}
- iElement.empty().append(scope.preText + value + scope.postText);
+ }
+ if (translateAttr === 'translate') {
+ // default translate into innerHTML
+ if (successful || (!successful && !$translate.isKeepContent() && typeof iAttr.translateKeepContent === 'undefined')) {
+ iElement.empty().append(scope.preText + value + scope.postText);
+ }
var globallyEnabled = $translate.isPostCompilingEnabled();
var locallyDefined = typeof tAttr.translateCompile !== 'undefined';
var locallyEnabled = locallyDefined && tAttr.translateCompile !== 'false';
@@ -2860,9 +3213,6 @@ function translateDirective($translate, $q, $interpolate, $compile, $parse, $roo
}
} else {
// translate attribute
- if (!successful && typeof scope.defaultText !== 'undefined') {
- value = scope.defaultText;
- }
var attributeName = iAttr.$attr[translateAttr];
if (attributeName.substr(0, 5) === 'data-') {
// ensure html5 data prefix is stripped
@@ -2876,7 +3226,9 @@ function translateDirective($translate, $q, $interpolate, $compile, $parse, $roo
if (translateValuesExist || translateValueExist || iAttr.translateDefault) {
scope.$watch('interpolateParams', updateTranslations, true);
}
- scope.$watch('translateLanguage', updateTranslations);
+
+ // Replaced watcher on translateLanguage with event listener
+ scope.$on('translateLanguageChanged', updateTranslations);
// Ensures the text will be refreshed after the current language was changed
// w/ $translate.use(...)
@@ -2899,7 +3251,6 @@ function translateDirective($translate, $q, $interpolate, $compile, $parse, $roo
}
};
}
-translateDirective.$inject = ['$translate', '$q', '$interpolate', '$compile', '$parse', '$rootScope'];
/**
* Returns the scope's namespace.
@@ -2919,11 +3270,169 @@ function getTranslateNamespace(scope) {
translateDirective.displayName = 'translateDirective';
+angular.module('pascalprecht.translate')
+/**
+ * @ngdoc directive
+ * @name pascalprecht.translate.directive:translate-attr
+ * @restrict A
+ *
+ * @description
+ * Translates attributes like translate-attr-ATTR, but with an object like ng-class.
+ * Internally it uses `translate` service to translate translation id. It possible to
+ * pass an optional `translate-values` object literal as string into translation id.
+ *
+ * @param {string=} translate-attr Object literal mapping attributes to translation ids.
+ * @param {string=} translate-values Values to pass into the translation ids. Can be passed as object literal string.
+ * @param {string=} translate-sanitize-strategy defines locally sanitize strategy
+ *
+ * @example
+
+
+
+
+
+
+
+
+
+ angular.module('ngView', ['pascalprecht.translate'])
+
+ .config(function ($translateProvider) {
+
+ $translateProvider.translations('en',{
+ 'TRANSLATION_ID': 'Hello there!',
+ 'WITH_VALUES': 'The following value is dynamic: {{value}}',
+ }).preferredLanguage('en');
+
+ });
+
+ angular.module('ngView').controller('TranslateCtrl', function ($scope) {
+ $scope.translationId = 'TRANSLATION_ID';
+
+ $scope.values = {
+ value: 78
+ };
+ });
+
+
+ it('should translate', function () {
+ inject(function ($rootScope, $compile) {
+ $rootScope.translationId = 'TRANSLATION_ID';
+
+ element = $compile(' ')($rootScope);
+ $rootScope.$digest();
+ expect(element.attr('placeholder)).toBe('Hello there!');
+ expect(element.attr('title)).toBe('The following value is dynamic: 5');
+ });
+ });
+
+
+ */
+.directive('translateAttr', translateAttrDirective);
+function translateAttrDirective($translate, $rootScope) {
+
+ 'use strict';
+
+ return {
+ restrict: 'A',
+ priority: $translate.directivePriority(),
+ link: function linkFn(scope, element, attr) {
+
+ var translateAttr,
+ translateValues,
+ translateSanitizeStrategy,
+ previousAttributes = {};
+
+ // Main update translations function
+ var updateTranslations = function () {
+ angular.forEach(translateAttr, function (translationId, attributeName) {
+ if (!translationId) {
+ return;
+ }
+ previousAttributes[attributeName] = true;
+
+ // if translation id starts with '.' and translateNamespace given, prepend namespace
+ if (scope.translateNamespace && translationId.charAt(0) === '.') {
+ translationId = scope.translateNamespace + translationId;
+ }
+ $translate(translationId, translateValues, attr.translateInterpolation, undefined, scope.translateLanguage, translateSanitizeStrategy)
+ .then(function (translation) {
+ element.attr(attributeName, translation);
+ }, function (translationId) {
+ element.attr(attributeName, translationId);
+ });
+ });
+
+ // Removing unused attributes that were previously used
+ angular.forEach(previousAttributes, function (flag, attributeName) {
+ if (!translateAttr[attributeName]) {
+ element.removeAttr(attributeName);
+ delete previousAttributes[attributeName];
+ }
+ });
+ };
+
+ // Watch for attribute changes
+ watchAttribute(
+ scope,
+ attr.translateAttr,
+ function (newValue) { translateAttr = newValue; },
+ updateTranslations
+ );
+ // Watch for value changes
+ watchAttribute(
+ scope,
+ attr.translateValues,
+ function (newValue) { translateValues = newValue; },
+ updateTranslations
+ );
+ // Watch for sanitize strategy changes
+ watchAttribute(
+ scope,
+ attr.translateSanitizeStrategy,
+ function (newValue) { translateSanitizeStrategy = newValue; },
+ updateTranslations
+ );
+
+ if (attr.translateValues) {
+ scope.$watch(attr.translateValues, updateTranslations, true);
+ }
+
+ // Replaced watcher on translateLanguage with event listener
+ scope.$on('translateLanguageChanged', updateTranslations);
+
+ // Ensures the text will be refreshed after the current language was changed
+ // w/ $translate.use(...)
+ var unbind = $rootScope.$on('$translateChangeSuccess', updateTranslations);
+
+ updateTranslations();
+ scope.$on('$destroy', unbind);
+ }
+ };
+}
+
+function watchAttribute(scope, attribute, valueCallback, changeCallback) {
+ 'use strict';
+ if (!attribute) {
+ return;
+ }
+ if (attribute.substr(0, 2) === '::') {
+ attribute = attribute.substr(2);
+ } else {
+ scope.$watch(attribute, function(newValue) {
+ valueCallback(newValue);
+ changeCallback();
+ }, true);
+ }
+ valueCallback(scope.$eval(attribute));
+}
+
+translateAttrDirective.displayName = 'translateAttrDirective';
+
angular.module('pascalprecht.translate')
/**
* @ngdoc directive
* @name pascalprecht.translate.directive:translateCloak
- * @requires $rootScope
* @requires $translate
* @restrict A
*
@@ -2948,34 +3457,33 @@ function translateCloakDirective($translate, $rootScope) {
'use strict';
return {
- compile: function (tElement) {
- var applyCloak = function () {
- tElement.addClass($translate.cloakClassName());
- },
- removeCloak = function () {
- tElement.removeClass($translate.cloakClassName());
- };
- $translate.onReady(function () {
- removeCloak();
- });
- applyCloak();
+ compile : function (tElement) {
+ var applyCloak = function (element) {
+ element.addClass($translate.cloakClassName());
+ },
+ removeCloak = function (element) {
+ element.removeClass($translate.cloakClassName());
+ };
+ applyCloak(tElement);
return function linkFn(scope, iElement, iAttr) {
+ //Create bound functions that incorporate the active DOM element.
+ var iRemoveCloak = removeCloak.bind(this, iElement), iApplyCloak = applyCloak.bind(this, iElement);
if (iAttr.translateCloak && iAttr.translateCloak.length) {
// Register a watcher for the defined translation allowing a fine tuned cloak
iAttr.$observe('translateCloak', function (translationId) {
- $translate(translationId).then(removeCloak, applyCloak);
+ $translate(translationId).then(iRemoveCloak, iApplyCloak);
});
- // Register for change events as this is being another indicicator revalidating the cloak)
$rootScope.$on('$translateChangeSuccess', function () {
- $translate(iAttr.translateCloak).then(removeCloak, applyCloak);
+ $translate(iAttr.translateCloak).then(iRemoveCloak, iApplyCloak);
});
+ } else {
+ $translate.onReady(iRemoveCloak);
}
};
}
};
}
-translateCloakDirective.$inject = ['$translate', '$rootScope'];
translateCloakDirective.displayName = 'translateCloakDirective';
@@ -3110,7 +3618,7 @@ angular.module('pascalprecht.translate')
.translations('de',{
'HELLO': 'Hallo Welt!'
})
- .translations(.preferredLanguage('en');
+ .preferredLanguage('en');
});
@@ -3128,9 +3636,14 @@ function translateLanguageDirective() {
scope: true,
compile: function () {
return function linkFn(scope, iElement, iAttrs) {
+
iAttrs.$observe('translateLanguage', function (newTranslateLanguage) {
scope.translateLanguage = newTranslateLanguage;
});
+
+ scope.$watch('translateLanguage', function(){
+ scope.$broadcast('translateLanguageChanged');
+ });
};
}
};
@@ -3138,7 +3651,6 @@ function translateLanguageDirective() {
translateLanguageDirective.displayName = 'translateLanguageDirective';
-
angular.module('pascalprecht.translate')
/**
* @ngdoc filter
@@ -3198,9 +3710,11 @@ function translateFilterFactory($parse, $translate) {
'use strict';
var translateFilter = function (translationId, interpolateParams, interpolation, forceLanguage) {
-
if (!angular.isObject(interpolateParams)) {
- interpolateParams = $parse(interpolateParams)(this);
+ var ctx = this || {
+ '__SCOPE_IS_NOT_AVAILABLE': 'More info at https://github.com/angular/angular.js/commit/8863b9d04c722b278fa93c5d66ad1e578ad6eb1f'
+ };
+ interpolateParams = $parse(interpolateParams)(ctx);
}
return $translate.instant(translationId, interpolateParams, interpolation, forceLanguage);
@@ -3212,7 +3726,6 @@ function translateFilterFactory($parse, $translate) {
return translateFilter;
}
-translateFilterFactory.$inject = ['$parse', '$translate'];
translateFilterFactory.displayName = 'translateFilterFactory';
@@ -3238,118 +3751,8 @@ function $translationCache($cacheFactory) {
return $cacheFactory('translations');
}
-$translationCache.$inject = ['$cacheFactory'];
$translationCache.displayName = '$translationCache';
return 'pascalprecht.translate';
}));
-
-
-/*!
- * angular-translate - v2.9.0 - 2016-01-24
- *
- * Copyright (c) 2016 The angular-translate team, Pascal Precht; Licensed MIT
- */
-(function (root, factory) {
- if (typeof define === 'function' && define.amd) {
- // AMD. Register as an anonymous module unless amdModuleId is set
- define([], function () {
- return (factory());
- });
- } else if (typeof exports === 'object') {
- // Node. Does not work with strict CommonJS, but
- // only CommonJS-like environments that support module.exports,
- // like Node.
- module.exports = factory();
- } else {
- factory();
- }
-}(this, function () {
-
- angular.module('pascalprecht.translate')
- /**
- * @ngdoc object
- * @name pascalprecht.translate.$translateStaticFilesLoader
- * @requires $q
- * @requires $http
- *
- * @description
- * Creates a loading function for a typical static file url pattern:
- * "lang-en_US.json", "lang-de_DE.json", etc. Using this builder,
- * the response of these urls must be an object of key-value pairs.
- *
- * @param {object} options Options object, which gets prefix, suffix and key.
- */
- .factory('$translateStaticFilesLoader', $translateStaticFilesLoader);
-
- function $translateStaticFilesLoader($q, $http) {
-
- 'use strict';
-
- return function (options) {
-
- if (!options || (!angular.isArray(options.files) && (!angular.isString(options.prefix) || !angular.isString(options.suffix)))) {
- throw new Error('Couldn\'t load static files, no files and prefix or suffix specified!');
- }
-
- if (!options.files) {
- options.files = [{
- prefix: options.prefix,
- suffix: options.suffix
- }];
- }
-
- var load = function (file) {
- if (!file || (!angular.isString(file.prefix) || !angular.isString(file.suffix))) {
- throw new Error('Couldn\'t load static file, no prefix or suffix specified!');
- }
-
- return $http(angular.extend({
- url: [
- file.prefix,
- options.key,
- file.suffix
- ].join(''),
- method: 'GET',
- params: ''
- }, options.$http))
- .then(function(result) {
- return result.data;
- }, function () {
- return $q.reject(options.key);
- });
- };
-
- var promises = [],
- length = options.files.length;
-
- for (var i = 0; i < length; i++) {
- promises.push(load({
- prefix: options.files[i].prefix,
- key: options.key,
- suffix: options.files[i].suffix
- }));
- }
-
- return $q.all(promises)
- .then(function (data) {
- var length = data.length,
- mergedData = {};
-
- for (var i = 0; i < length; i++) {
- for (var key in data[i]) {
- mergedData[key] = data[i][key];
- }
- }
-
- return mergedData;
- });
- };
- }
- $translateStaticFilesLoader.$inject = ['$q', '$http'];
-
- $translateStaticFilesLoader.displayName = '$translateStaticFilesLoader';
- return 'pascalprecht.translate';
-
-}));
\ No newline at end of file
diff --git a/docs-web/src/main/webapp/src/lib/angular.ui-bootstrap.js b/docs-web/src/main/webapp/src/lib/angular.ui-bootstrap.js
index 29a74a6a..474e2d3a 100644
--- a/docs-web/src/main/webapp/src/lib/angular.ui-bootstrap.js
+++ b/docs-web/src/main/webapp/src/lib/angular.ui-bootstrap.js
@@ -1794,6 +1794,20 @@ angular.module('ui.bootstrap.pagination', [])
});
}
+ if (attrs.nextText) {
+ attrs.$observe('nextText', function(value) {
+ nextText = paginationCtrl.getAttributeValue(value, config.nextText, true);
+ paginationCtrl.render();
+ });
+ }
+
+ if (attrs.previousText) {
+ attrs.$observe('previousText', function(value) {
+ previousText = paginationCtrl.getAttributeValue(value, config.previousText, true);
+ paginationCtrl.render();
+ });
+ }
+
// Create page object used in template
function makePage(number, text, isActive, isDisabled) {
return {
diff --git a/docs-web/src/main/webapp/src/partial/docs/document.default.html b/docs-web/src/main/webapp/src/partial/docs/document.default.html
index 984c2925..afc7c067 100644
--- a/docs-web/src/main/webapp/src/partial/docs/document.default.html
+++ b/docs-web/src/main/webapp/src/partial/docs/document.default.html
@@ -1,6 +1,6 @@
-
+
{{ 'document.default.quick_upload' | translate }}
-
{{ 'document.default.latest_activity' | translate }}
-
+
+
{{ 'document.default.latest_activity' | translate }}
+
+
\ No newline at end of file
diff --git a/docs-web/src/main/webapp/src/style/main.less b/docs-web/src/main/webapp/src/style/main.less
index 9e3ce839..97a915f1 100644
--- a/docs-web/src/main/webapp/src/style/main.less
+++ b/docs-web/src/main/webapp/src/style/main.less
@@ -335,6 +335,11 @@ input[readonly].share-link {
z-index: 99999;
}
+// Translate
+.translate-cloak {
+ display: none;
+}
+
// Heart
.glyphicon-heart {
&:hover {