aboutsummaryrefslogtreecommitdiffstats
path: root/vnfmarket/common/thirdparty/angular-translate
diff options
context:
space:
mode:
Diffstat (limited to 'vnfmarket/common/thirdparty/angular-translate')
-rw-r--r--vnfmarket/common/thirdparty/angular-translate/.bower.json23
-rw-r--r--vnfmarket/common/thirdparty/angular-translate/README.md23
-rw-r--r--vnfmarket/common/thirdparty/angular-translate/angular-translate.js3704
-rw-r--r--vnfmarket/common/thirdparty/angular-translate/angular-translate.min.js6
-rw-r--r--vnfmarket/common/thirdparty/angular-translate/bower.json12
5 files changed, 3768 insertions, 0 deletions
diff --git a/vnfmarket/common/thirdparty/angular-translate/.bower.json b/vnfmarket/common/thirdparty/angular-translate/.bower.json
new file mode 100644
index 00000000..abb1be90
--- /dev/null
+++ b/vnfmarket/common/thirdparty/angular-translate/.bower.json
@@ -0,0 +1,23 @@
+{
+ "name": "angular-translate",
+ "description": "A translation module for AngularJS",
+ "version": "2.14.0",
+ "main": "./angular-translate.js",
+ "ignore": [],
+ "author": "Pascal Precht",
+ "license": "MIT",
+ "dependencies": {
+ "angular": ">=1.2.26 <1.7"
+ },
+ "homepage": "https://github.com/PascalPrecht/bower-angular-translate",
+ "_release": "2.14.0",
+ "_resolution": {
+ "type": "version",
+ "tag": "2.14.0",
+ "commit": "de75c2457dfc3609230f23f7ebbf1d55f493bdfe"
+ },
+ "_source": "https://github.com/PascalPrecht/bower-angular-translate.git",
+ "_target": "^2.14.0",
+ "_originalSource": "angular-translate",
+ "_direct": true
+} \ No newline at end of file
diff --git a/vnfmarket/common/thirdparty/angular-translate/README.md b/vnfmarket/common/thirdparty/angular-translate/README.md
new file mode 100644
index 00000000..4991a999
--- /dev/null
+++ b/vnfmarket/common/thirdparty/angular-translate/README.md
@@ -0,0 +1,23 @@
+# angular-translate (bower shadow repository)
+
+This is the _Bower shadow_ repository for *angular-translate*.
+
+## Bugs and issues
+
+Please file any issues and bugs in our main repository at [angular-translate/angular-translate](https://github.com/angular-translate/angular-translate/issues).
+
+## Usage
+
+### via Bower
+
+```bash
+$ bower install angular-translate
+```
+
+### via cdnjs
+
+Please have a look at https://cdnjs.com/libraries/angular-translate for specific versions.
+
+## License
+
+Licensed under MIT. See more details at [angular-translate/angular-translate](https://github.com/angular-translate/angular-translate).
diff --git a/vnfmarket/common/thirdparty/angular-translate/angular-translate.js b/vnfmarket/common/thirdparty/angular-translate/angular-translate.js
new file mode 100644
index 00000000..f53cbb2c
--- /dev/null
+++ b/vnfmarket/common/thirdparty/angular-translate/angular-translate.js
@@ -0,0 +1,3704 @@
+/*!
+ * angular-translate - v2.14.0 - 2017-02-11
+ *
+ * Copyright (c) 2017 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 () {
+
+/**
+ * @ngdoc overview
+ * @name pascalprecht.translate
+ *
+ * @description
+ * The main module which holds everything together.
+ */
+runTranslate.$inject = ['$translate'];
+$translate.$inject = ['$STORAGE_KEY', '$windowProvider', '$translateSanitizationProvider', 'pascalprechtTranslateOverrider'];
+$translateDefaultInterpolation.$inject = ['$interpolate', '$translateSanitization'];
+translateDirective.$inject = ['$translate', '$interpolate', '$compile', '$parse', '$rootScope'];
+translateAttrDirective.$inject = ['$translate', '$rootScope'];
+translateCloakDirective.$inject = ['$translate'];
+translateFilterFactory.$inject = ['$parse', '$translate'];
+$translationCache.$inject = ['$cacheFactory'];
+angular.module('pascalprecht.translate', ['ng'])
+ .run(runTranslate);
+
+function runTranslate($translate) {
+
+ 'use strict';
+
+ var key = $translate.storageKey(),
+ storage = $translate.storage();
+
+ var fallbackFromIncorrectStorageValue = function () {
+ var preferred = $translate.preferredLanguage();
+ if (angular.isString(preferred)) {
+ $translate.use(preferred);
+ // $translate.use() will also remember the language.
+ // So, we don't need to call storage.put() here.
+ } else {
+ storage.put(key, $translate.use());
+ }
+ };
+
+ fallbackFromIncorrectStorageValue.displayName = 'fallbackFromIncorrectStorageValue';
+
+ if (storage) {
+ if (!storage.get(key)) {
+ fallbackFromIncorrectStorageValue();
+ } else {
+ $translate.use(storage.get(key))['catch'](fallbackFromIncorrectStorageValue);
+ }
+ } else if (angular.isString($translate.preferredLanguage())) {
+ $translate.use($translate.preferredLanguage());
+ }
+}
+
+runTranslate.displayName = 'runTranslate';
+
+/**
+ * @ngdoc object
+ * @name pascalprecht.translate.$translateSanitizationProvider
+ *
+ * @description
+ *
+ * Configurations for $translateSanitization
+ */
+angular.module('pascalprecht.translate').provider('$translateSanitization', $translateSanitizationProvider);
+
+function $translateSanitizationProvider () {
+
+ 'use strict';
+
+ var $sanitize,
+ $sce,
+ currentStrategy = null, // TODO change to either 'sanitize', 'escape' or ['sanitize', 'escapeParameters'] in 3.0.
+ hasConfiguredStrategy = false,
+ hasShownNoStrategyConfiguredWarning = false,
+ strategies;
+
+ /**
+ * Definition of a sanitization strategy function
+ * @callback StrategyFunction
+ * @param {string|object} value - value to be sanitized (either a string or an interpolated value map)
+ * @param {string} mode - either 'text' for a string (translation) or 'params' for the interpolated params
+ * @return {string|object}
+ */
+
+ /**
+ * @ngdoc property
+ * @name strategies
+ * @propertyOf pascalprecht.translate.$translateSanitizationProvider
+ *
+ * @description
+ * Following strategies are built-in:
+ * <dl>
+ * <dt>sanitize</dt>
+ * <dd>Sanitizes HTML in the translation text using $sanitize</dd>
+ * <dt>escape</dt>
+ * <dd>Escapes HTML in the translation</dd>
+ * <dt>sanitizeParameters</dt>
+ * <dd>Sanitizes HTML in the values of the interpolation parameters using $sanitize</dd>
+ * <dt>escapeParameters</dt>
+ * <dd>Escapes HTML in the values of the interpolation parameters</dd>
+ * <dt>escaped</dt>
+ * <dd>Support legacy strategy name 'escaped' for backwards compatibility (will be removed in 3.0)</dd>
+ * </dl>
+ *
+ */
+
+ strategies = {
+ sanitize: function (value, mode/*, context*/) {
+ if (mode === 'text') {
+ value = htmlSanitizeValue(value);
+ }
+ return value;
+ },
+ escape: function (value, mode/*, context*/) {
+ if (mode === 'text') {
+ value = htmlEscapeValue(value);
+ }
+ return value;
+ },
+ sanitizeParameters: function (value, mode/*, context*/) {
+ if (mode === 'params') {
+ value = mapInterpolationParameters(value, htmlSanitizeValue);
+ }
+ return value;
+ },
+ escapeParameters: function (value, mode/*, context*/) {
+ if (mode === 'params') {
+ value = mapInterpolationParameters(value, htmlEscapeValue);
+ }
+ return value;
+ },
+ sce: function (value, mode, context) {
+ if (mode === 'text') {
+ value = htmlTrustValue(value);
+ } else if (mode === 'params') {
+ if (context !== 'filter') {
+ // do html escape in filter context #1101
+ value = mapInterpolationParameters(value, htmlEscapeValue);
+ }
+ }
+ return value;
+ },
+ sceParameters: function (value, mode/*, context*/) {
+ if (mode === 'params') {
+ value = mapInterpolationParameters(value, htmlTrustValue);
+ }
+ return value;
+ }
+ };
+ // Support legacy strategy name 'escaped' for backwards compatibility.
+ // TODO should be removed in 3.0
+ strategies.escaped = strategies.escapeParameters;
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateSanitizationProvider#addStrategy
+ * @methodOf pascalprecht.translate.$translateSanitizationProvider
+ *
+ * @description
+ * Adds a sanitization strategy to the list of known strategies.
+ *
+ * @param {string} strategyName - unique key for a strategy
+ * @param {StrategyFunction} strategyFunction - strategy function
+ * @returns {object} this
+ */
+ this.addStrategy = function (strategyName, strategyFunction) {
+ strategies[strategyName] = strategyFunction;
+ return this;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateSanitizationProvider#removeStrategy
+ * @methodOf pascalprecht.translate.$translateSanitizationProvider
+ *
+ * @description
+ * Removes a sanitization strategy from the list of known strategies.
+ *
+ * @param {string} strategyName - unique key for a strategy
+ * @returns {object} this
+ */
+ this.removeStrategy = function (strategyName) {
+ delete strategies[strategyName];
+ return this;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateSanitizationProvider#useStrategy
+ * @methodOf pascalprecht.translate.$translateSanitizationProvider
+ *
+ * @description
+ * Selects a sanitization strategy. When an array is provided the strategies will be executed in order.
+ *
+ * @param {string|StrategyFunction|array} strategy The sanitization strategy / strategies which should be used. Either a name of an existing strategy, a custom strategy function, or an array consisting of multiple names and / or custom functions.
+ * @returns {object} this
+ */
+ this.useStrategy = function (strategy) {
+ hasConfiguredStrategy = true;
+ currentStrategy = strategy;
+ return this;
+ };
+
+ /**
+ * @ngdoc object
+ * @name pascalprecht.translate.$translateSanitization
+ * @requires $injector
+ * @requires $log
+ *
+ * @description
+ * Sanitizes interpolation parameters and translated texts.
+ *
+ */
+ this.$get = ['$injector', '$log', function ($injector, $log) {
+
+ var cachedStrategyMap = {};
+
+ var applyStrategies = function (value, mode, context, selectedStrategies) {
+ angular.forEach(selectedStrategies, function (selectedStrategy) {
+ if (angular.isFunction(selectedStrategy)) {
+ value = selectedStrategy(value, mode, context);
+ } else if (angular.isFunction(strategies[selectedStrategy])) {
+ value = strategies[selectedStrategy](value, mode, context);
+ } else if (angular.isString(strategies[selectedStrategy])) {
+ if (!cachedStrategyMap[strategies[selectedStrategy]]) {
+ try {
+ cachedStrategyMap[strategies[selectedStrategy]] = $injector.get(strategies[selectedStrategy]);
+ } catch (e) {
+ cachedStrategyMap[strategies[selectedStrategy]] = function() {};
+ throw new Error('pascalprecht.translate.$translateSanitization: Unknown sanitization strategy: \'' + selectedStrategy + '\'');
+ }
+ }
+ value = cachedStrategyMap[strategies[selectedStrategy]](value, mode, context);
+ } else {
+ throw new Error('pascalprecht.translate.$translateSanitization: Unknown sanitization strategy: \'' + selectedStrategy + '\'');
+ }
+ });
+ return value;
+ };
+
+ // TODO: should be removed in 3.0
+ var showNoStrategyConfiguredWarning = function () {
+ if (!hasConfiguredStrategy && !hasShownNoStrategyConfiguredWarning) {
+ $log.warn('pascalprecht.translate.$translateSanitization: No sanitization strategy has been configured. This can have serious security implications. See http://angular-translate.github.io/docs/#/guide/19_security for details.');
+ hasShownNoStrategyConfiguredWarning = true;
+ }
+ };
+
+ if ($injector.has('$sanitize')) {
+ $sanitize = $injector.get('$sanitize');
+ }
+ if ($injector.has('$sce')) {
+ $sce = $injector.get('$sce');
+ }
+
+ return {
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateSanitization#useStrategy
+ * @methodOf pascalprecht.translate.$translateSanitization
+ *
+ * @description
+ * Selects a sanitization strategy. When an array is provided the strategies will be executed in order.
+ *
+ * @param {string|StrategyFunction|array} strategy The sanitization strategy / strategies which should be used. Either a name of an existing strategy, a custom strategy function, or an array consisting of multiple names and / or custom functions.
+ */
+ useStrategy: (function (self) {
+ return function (strategy) {
+ self.useStrategy(strategy);
+ };
+ })(this),
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateSanitization#sanitize
+ * @methodOf pascalprecht.translate.$translateSanitization
+ *
+ * @description
+ * Sanitizes a value.
+ *
+ * @param {string|object} value The value which should be sanitized.
+ * @param {string} mode The current sanitization mode, either 'params' or 'text'.
+ * @param {string|StrategyFunction|array} [strategy] Optional custom strategy which should be used instead of the currently selected strategy.
+ * @param {string} [context] The context of this call: filter, service. Default is service
+ * @returns {string|object} sanitized value
+ */
+ sanitize: function (value, mode, strategy, context) {
+ if (!currentStrategy) {
+ showNoStrategyConfiguredWarning();
+ }
+
+ if (!strategy && strategy !== null) {
+ strategy = currentStrategy;
+ }
+
+ if (!strategy) {
+ return value;
+ }
+
+ if (!context) {
+ context = 'service';
+ }
+
+ var selectedStrategies = angular.isArray(strategy) ? strategy : [strategy];
+ return applyStrategies(value, mode, context, selectedStrategies);
+ }
+ };
+ }];
+
+ var htmlEscapeValue = function (value) {
+ var element = angular.element('<div></div>');
+ element.text(value); // not chainable, see #1044
+ return element.html();
+ };
+
+ var htmlSanitizeValue = function (value) {
+ if (!$sanitize) {
+ throw new Error('pascalprecht.translate.$translateSanitization: Error cannot find $sanitize service. Either include the ngSanitize module (https://docs.angularjs.org/api/ngSanitize) or use a sanitization strategy which does not depend on $sanitize, such as \'escape\'.');
+ }
+ return $sanitize(value);
+ };
+
+ var htmlTrustValue = function (value) {
+ if (!$sce) {
+ throw new Error('pascalprecht.translate.$translateSanitization: Error cannot find $sce service.');
+ }
+ return $sce.trustAsHtml(value);
+ };
+
+ var mapInterpolationParameters = function (value, iteratee, stack) {
+ if (angular.isDate(value)) {
+ return value;
+ } else if (angular.isObject(value)) {
+ var result = angular.isArray(value) ? [] : {};
+
+ if (!stack) {
+ stack = [];
+ } else {
+ if (stack.indexOf(value) > -1) {
+ throw new Error('pascalprecht.translate.$translateSanitization: Error cannot interpolate parameter due recursive object');
+ }
+ }
+
+ stack.push(value);
+ angular.forEach(value, function (propertyValue, propertyKey) {
+
+ /* Skipping function properties. */
+ if (angular.isFunction(propertyValue)) {
+ return;
+ }
+
+ result[propertyKey] = mapInterpolationParameters(propertyValue, iteratee, stack);
+ });
+ stack.splice(-1, 1); // remove last
+
+ return result;
+ } else if (angular.isNumber(value)) {
+ return value;
+ } else if (!angular.isUndefined(value) && value !== null) {
+ return iteratee(value);
+ } else {
+ return value;
+ }
+ };
+}
+
+/**
+ * @ngdoc object
+ * @name pascalprecht.translate.$translateProvider
+ * @description
+ *
+ * $translateProvider allows developers to register translation-tables, asynchronous loaders
+ * and similar to configure translation behavior directly inside of a module.
+ *
+ */
+angular.module('pascalprecht.translate')
+ .constant('pascalprechtTranslateOverrider', {})
+ .provider('$translate', $translate);
+
+function $translate($STORAGE_KEY, $windowProvider, $translateSanitizationProvider, pascalprechtTranslateOverrider) {
+
+ 'use strict';
+
+ var $translationTable = {},
+ $preferredLanguage,
+ $availableLanguageKeys = [],
+ $languageKeyAliases,
+ $fallbackLanguage,
+ $fallbackWasString,
+ $uses,
+ $nextLang,
+ $storageFactory,
+ $storageKey = $STORAGE_KEY,
+ $storagePrefix,
+ $missingTranslationHandlerFactory,
+ $interpolationFactory,
+ $interpolatorFactories = [],
+ $loaderFactory,
+ $cloakClassName = 'translate-cloak',
+ $loaderOptions,
+ $notFoundIndicatorLeft,
+ $notFoundIndicatorRight,
+ $postCompilingEnabled = false,
+ $forceAsyncReloadEnabled = false,
+ $nestedObjectDelimeter = '.',
+ $isReady = false,
+ $keepContent = false,
+ loaderCache,
+ directivePriority = 0,
+ statefulFilter = true,
+ postProcessFn,
+ uniformLanguageTagResolver = 'default',
+ languageTagResolver = {
+ 'default' : function (tag) {
+ return (tag || '').split('-').join('_');
+ },
+ java : function (tag) {
+ var temp = (tag || '').split('-').join('_');
+ var parts = temp.split('_');
+ return parts.length > 1 ? (parts[0].toLowerCase() + '_' + parts[1].toUpperCase()) : temp;
+ },
+ bcp47 : function (tag) {
+ var temp = (tag || '').split('_').join('-');
+ var parts = temp.split('-');
+ return parts.length > 1 ? (parts[0].toLowerCase() + '-' + parts[1].toUpperCase()) : temp;
+ },
+ 'iso639-1' : function (tag) {
+ var temp = (tag || '').split('_').join('-');
+ var parts = temp.split('-');
+ return parts[0].toLowerCase();
+ }
+ };
+
+ var version = '2.14.0';
+
+ // tries to determine the browsers language
+ var getFirstBrowserLanguage = function () {
+
+ // internal purpose only
+ if (angular.isFunction(pascalprechtTranslateOverrider.getLocale)) {
+ return pascalprechtTranslateOverrider.getLocale();
+ }
+
+ var nav = $windowProvider.$get().navigator,
+ browserLanguagePropertyKeys = ['language', 'browserLanguage', 'systemLanguage', 'userLanguage'],
+ i,
+ language;
+
+ // support for HTML 5.1 "navigator.languages"
+ if (angular.isArray(nav.languages)) {
+ for (i = 0; i < nav.languages.length; i++) {
+ language = nav.languages[i];
+ if (language && language.length) {
+ return language;
+ }
+ }
+ }
+
+ // support for other well known properties in browsers
+ for (i = 0; i < browserLanguagePropertyKeys.length; i++) {
+ language = nav[browserLanguagePropertyKeys[i]];
+ if (language && language.length) {
+ return language;
+ }
+ }
+
+ return null;
+ };
+ getFirstBrowserLanguage.displayName = 'angular-translate/service: getFirstBrowserLanguage';
+
+ // tries to determine the browsers locale
+ var getLocale = function () {
+ var locale = getFirstBrowserLanguage() || '';
+ if (languageTagResolver[uniformLanguageTagResolver]) {
+ locale = languageTagResolver[uniformLanguageTagResolver](locale);
+ }
+ return locale;
+ };
+ getLocale.displayName = 'angular-translate/service: getLocale';
+
+ /**
+ * @name indexOf
+ * @private
+ *
+ * @description
+ * indexOf polyfill. Kinda sorta.
+ *
+ * @param {array} array Array to search in.
+ * @param {string} searchElement Element to search for.
+ *
+ * @returns {int} Index of search element.
+ */
+ var indexOf = function (array, searchElement) {
+ for (var i = 0, len = array.length; i < len; i++) {
+ if (array[i] === searchElement) {
+ return i;
+ }
+ }
+ return -1;
+ };
+
+ /**
+ * @name trim
+ * @private
+ *
+ * @description
+ * trim polyfill
+ *
+ * @returns {string} The string stripped of whitespace from both ends
+ */
+ var trim = function () {
+ return this.toString().replace(/^\s+|\s+$/g, '');
+ };
+
+ var negotiateLocale = function (preferred) {
+ if (!preferred) {
+ return;
+ }
+
+ var avail = [],
+ locale = angular.lowercase(preferred),
+ i = 0,
+ n = $availableLanguageKeys.length;
+
+ for (; i < n; i++) {
+ avail.push(angular.lowercase($availableLanguageKeys[i]));
+ }
+
+ // Check for an exact match in our list of available keys
+ if (indexOf(avail, locale) > -1) {
+ return preferred;
+ }
+
+ if ($languageKeyAliases) {
+ var alias;
+ for (var langKeyAlias in $languageKeyAliases) {
+ if ($languageKeyAliases.hasOwnProperty(langKeyAlias)) {
+ var hasWildcardKey = false;
+ var hasExactKey = Object.prototype.hasOwnProperty.call($languageKeyAliases, langKeyAlias) &&
+ angular.lowercase(langKeyAlias) === angular.lowercase(preferred);
+
+ if (langKeyAlias.slice(-1) === '*') {
+ hasWildcardKey = langKeyAlias.slice(0, -1) === preferred.slice(0, langKeyAlias.length - 1);
+ }
+ if (hasExactKey || hasWildcardKey) {
+ alias = $languageKeyAliases[langKeyAlias];
+ if (indexOf(avail, angular.lowercase(alias)) > -1) {
+ return alias;
+ }
+ }
+ }
+ }
+ }
+
+ // Check for a language code without region
+ var parts = preferred.split('_');
+
+ if (parts.length > 1 && indexOf(avail, angular.lowercase(parts[0])) > -1) {
+ return parts[0];
+ }
+
+ // If everything fails, return undefined.
+ return;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateProvider#translations
+ * @methodOf pascalprecht.translate.$translateProvider
+ *
+ * @description
+ * Registers a new translation table for specific language key.
+ *
+ * To register a translation table for specific language, pass a defined language
+ * key as first parameter.
+ *
+ * <pre>
+ * // register translation table for language: 'de_DE'
+ * $translateProvider.translations('de_DE', {
+ * 'GREETING': 'Hallo Welt!'
+ * });
+ *
+ * // register another one
+ * $translateProvider.translations('en_US', {
+ * 'GREETING': 'Hello world!'
+ * });
+ * </pre>
+ *
+ * When registering multiple translation tables for for the same language key,
+ * the actual translation table gets extended. This allows you to define module
+ * specific translation which only get added, once a specific module is loaded in
+ * your app.
+ *
+ * Invoking this method with no arguments returns the translation table which was
+ * registered with no language key. Invoking it with a language key returns the
+ * related translation table.
+ *
+ * @param {string} langKey A language key.
+ * @param {object} translationTable A plain old JavaScript object that represents a translation table.
+ *
+ */
+ var translations = function (langKey, translationTable) {
+
+ if (!langKey && !translationTable) {
+ return $translationTable;
+ }
+
+ if (langKey && !translationTable) {
+ if (angular.isString(langKey)) {
+ return $translationTable[langKey];
+ }
+ } else {
+ if (!angular.isObject($translationTable[langKey])) {
+ $translationTable[langKey] = {};
+ }
+ angular.extend($translationTable[langKey], flatObject(translationTable));
+ }
+ return this;
+ };
+
+ this.translations = translations;
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateProvider#cloakClassName
+ * @methodOf pascalprecht.translate.$translateProvider
+ *
+ * @description
+ *
+ * Let's you change the class name for `translate-cloak` directive.
+ * Default class name is `translate-cloak`.
+ *
+ * @param {string} name translate-cloak class name
+ */
+ this.cloakClassName = function (name) {
+ if (!name) {
+ return $cloakClassName;
+ }
+ $cloakClassName = name;
+ return this;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateProvider#nestedObjectDelimeter
+ * @methodOf pascalprecht.translate.$translateProvider
+ *
+ * @description
+ *
+ * Let's you change the delimiter for namespaced translations.
+ * Default delimiter is `.`.
+ *
+ * @param {string} delimiter namespace separator
+ */
+ this.nestedObjectDelimeter = function (delimiter) {
+ if (!delimiter) {
+ return $nestedObjectDelimeter;
+ }
+ $nestedObjectDelimeter = delimiter;
+ return this;
+ };
+
+ /**
+ * @name flatObject
+ * @private
+ *
+ * @description
+ * Flats an object. This function is used to flatten given translation data with
+ * namespaces, so they are later accessible via dot notation.
+ */
+ var flatObject = function (data, path, result, prevKey) {
+ var key, keyWithPath, keyWithShortPath, val;
+
+ if (!path) {
+ path = [];
+ }
+ if (!result) {
+ result = {};
+ }
+ for (key in data) {
+ if (!Object.prototype.hasOwnProperty.call(data, key)) {
+ continue;
+ }
+ val = data[key];
+ if (angular.isObject(val)) {
+ flatObject(val, path.concat(key), result, key);
+ } else {
+ keyWithPath = path.length ? ('' + path.join($nestedObjectDelimeter) + $nestedObjectDelimeter + key) : key;
+ if (path.length && key === prevKey) {
+ // Create shortcut path (foo.bar == foo.bar.bar)
+ keyWithShortPath = '' + path.join($nestedObjectDelimeter);
+ // Link it to original path
+ result[keyWithShortPath] = '@:' + keyWithPath;
+ }
+ result[keyWithPath] = val;
+ }
+ }
+ return result;
+ };
+ flatObject.displayName = 'flatObject';
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateProvider#addInterpolation
+ * @methodOf pascalprecht.translate.$translateProvider
+ *
+ * @description
+ * Adds interpolation services to angular-translate, so it can manage them.
+ *
+ * @param {object} factory Interpolation service factory
+ */
+ this.addInterpolation = function (factory) {
+ $interpolatorFactories.push(factory);
+ return this;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateProvider#useMessageFormatInterpolation
+ * @methodOf pascalprecht.translate.$translateProvider
+ *
+ * @description
+ * Tells angular-translate to use interpolation functionality of messageformat.js.
+ * This is useful when having high level pluralization and gender selection.
+ */
+ this.useMessageFormatInterpolation = function () {
+ return this.useInterpolation('$translateMessageFormatInterpolation');
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateProvider#useInterpolation
+ * @methodOf pascalprecht.translate.$translateProvider
+ *
+ * @description
+ * Tells angular-translate which interpolation style to use as default, application-wide.
+ * Simply pass a factory/service name. The interpolation service has to implement
+ * the correct interface.
+ *
+ * @param {string} factory Interpolation service name.
+ */
+ this.useInterpolation = function (factory) {
+ $interpolationFactory = factory;
+ return this;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateProvider#useSanitizeStrategy
+ * @methodOf pascalprecht.translate.$translateProvider
+ *
+ * @description
+ * Simply sets a sanitation strategy type.
+ *
+ * @param {string} value Strategy type.
+ */
+ this.useSanitizeValueStrategy = function (value) {
+ $translateSanitizationProvider.useStrategy(value);
+ return this;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateProvider#preferredLanguage
+ * @methodOf pascalprecht.translate.$translateProvider
+ *
+ * @description
+ * Tells the module which of the registered translation tables to use for translation
+ * at initial startup by passing a language key. Similar to `$translateProvider#use`
+ * only that it says which language to **prefer**.
+ *
+ * @param {string} langKey A language key.
+ */
+ this.preferredLanguage = function (langKey) {
+ if (langKey) {
+ setupPreferredLanguage(langKey);
+ return this;
+ }
+ return $preferredLanguage;
+ };
+ var setupPreferredLanguage = function (langKey) {
+ if (langKey) {
+ $preferredLanguage = langKey;
+ }
+ return $preferredLanguage;
+ };
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateProvider#translationNotFoundIndicator
+ * @methodOf pascalprecht.translate.$translateProvider
+ *
+ * @description
+ * Sets an indicator which is used when a translation isn't found. E.g. when
+ * setting the indicator as 'X' and one tries to translate a translation id
+ * called `NOT_FOUND`, this will result in `X NOT_FOUND X`.
+ *
+ * Internally this methods sets a left indicator and a right indicator using
+ * `$translateProvider.translationNotFoundIndicatorLeft()` and
+ * `$translateProvider.translationNotFoundIndicatorRight()`.
+ *
+ * **Note**: These methods automatically add a whitespace between the indicators
+ * and the translation id.
+ *
+ * @param {string} indicator An indicator, could be any string.
+ */
+ this.translationNotFoundIndicator = function (indicator) {
+ this.translationNotFoundIndicatorLeft(indicator);
+ this.translationNotFoundIndicatorRight(indicator);
+ return this;
+ };
+
+ /**
+ * ngdoc function
+ * @name pascalprecht.translate.$translateProvider#translationNotFoundIndicatorLeft
+ * @methodOf pascalprecht.translate.$translateProvider
+ *
+ * @description
+ * Sets an indicator which is used when a translation isn't found left to the
+ * translation id.
+ *
+ * @param {string} indicator An indicator.
+ */
+ this.translationNotFoundIndicatorLeft = function (indicator) {
+ if (!indicator) {
+ return $notFoundIndicatorLeft;
+ }
+ $notFoundIndicatorLeft = indicator;
+ return this;
+ };
+
+ /**
+ * ngdoc function
+ * @name pascalprecht.translate.$translateProvider#translationNotFoundIndicatorLeft
+ * @methodOf pascalprecht.translate.$translateProvider
+ *
+ * @description
+ * Sets an indicator which is used when a translation isn't found right to the
+ * translation id.
+ *
+ * @param {string} indicator An indicator.
+ */
+ this.translationNotFoundIndicatorRight = function (indicator) {
+ if (!indicator) {
+ return $notFoundIndicatorRight;
+ }
+ $notFoundIndicatorRight = indicator;
+ return this;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateProvider#fallbackLanguage
+ * @methodOf pascalprecht.translate.$translateProvider
+ *
+ * @description
+ * Tells the module which of the registered translation tables to use when missing translations
+ * at initial startup by passing a language key. Similar to `$translateProvider#use`
+ * only that it says which language to **fallback**.
+ *
+ * @param {string||array} langKey A language key.
+ *
+ */
+ this.fallbackLanguage = function (langKey) {
+ fallbackStack(langKey);
+ return this;
+ };
+
+ var fallbackStack = function (langKey) {
+ if (langKey) {
+ if (angular.isString(langKey)) {
+ $fallbackWasString = true;
+ $fallbackLanguage = [langKey];
+ } else if (angular.isArray(langKey)) {
+ $fallbackWasString = false;
+ $fallbackLanguage = langKey;
+ }
+ if (angular.isString($preferredLanguage) && indexOf($fallbackLanguage, $preferredLanguage) < 0) {
+ $fallbackLanguage.push($preferredLanguage);
+ }
+
+ return this;
+ } else {
+ if ($fallbackWasString) {
+ return $fallbackLanguage[0];
+ } else {
+ return $fallbackLanguage;
+ }
+ }
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateProvider#use
+ * @methodOf pascalprecht.translate.$translateProvider
+ *
+ * @description
+ * Set which translation table to use for translation by given language key. When
+ * trying to 'use' a language which isn't provided, it'll throw an error.
+ *
+ * You actually don't have to use this method since `$translateProvider#preferredLanguage`
+ * does the job too.
+ *
+ * @param {string} langKey A language key.
+ */
+ this.use = function (langKey) {
+ if (langKey) {
+ if (!$translationTable[langKey] && (!$loaderFactory)) {
+ // only throw an error, when not loading translation data asynchronously
+ throw new Error('$translateProvider couldn\'t find translationTable for langKey: \'' + langKey + '\'');
+ }
+ $uses = langKey;
+ return this;
+ }
+ return $uses;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateProvider#resolveClientLocale
+ * @methodOf pascalprecht.translate.$translateProvider
+ *
+ * @description
+ * This returns the current browser/client's language key. The result is processed with the configured uniform tag resolver.
+ *
+ * @returns {string} the current client/browser language key
+ */
+ this.resolveClientLocale = function () {
+ return getLocale();
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateProvider#storageKey
+ * @methodOf pascalprecht.translate.$translateProvider
+ *
+ * @description
+ * Tells the module which key must represent the choosed language by a user in the storage.
+ *
+ * @param {string} key A key for the storage.
+ */
+ var storageKey = function (key) {
+ if (!key) {
+ if ($storagePrefix) {
+ return $storagePrefix + $storageKey;
+ }
+ return $storageKey;
+ }
+ $storageKey = key;
+ return this;
+ };
+
+ this.storageKey = storageKey;
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateProvider#useUrlLoader
+ * @methodOf pascalprecht.translate.$translateProvider
+ *
+ * @description
+ * Tells angular-translate to use `$translateUrlLoader` extension service as loader.
+ *
+ * @param {string} url Url
+ * @param {Object=} options Optional configuration object
+ */
+ this.useUrlLoader = function (url, options) {
+ return this.useLoader('$translateUrlLoader', angular.extend({url : url}, options));
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateProvider#useStaticFilesLoader
+ * @methodOf pascalprecht.translate.$translateProvider
+ *
+ * @description
+ * Tells angular-translate to use `$translateStaticFilesLoader` extension service as loader.
+ *
+ * @param {Object=} options Optional configuration object
+ */
+ this.useStaticFilesLoader = function (options) {
+ return this.useLoader('$translateStaticFilesLoader', options);
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateProvider#useLoader
+ * @methodOf pascalprecht.translate.$translateProvider
+ *
+ * @description
+ * Tells angular-translate to use any other service as loader.
+ *
+ * @param {string} loaderFactory Factory name to use
+ * @param {Object=} options Optional configuration object
+ */
+ this.useLoader = function (loaderFactory, options) {
+ $loaderFactory = loaderFactory;
+ $loaderOptions = options || {};
+ return this;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateProvider#useLocalStorage
+ * @methodOf pascalprecht.translate.$translateProvider
+ *
+ * @description
+ * Tells angular-translate to use `$translateLocalStorage` service as storage layer.
+ *
+ */
+ this.useLocalStorage = function () {
+ return this.useStorage('$translateLocalStorage');
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateProvider#useCookieStorage
+ * @methodOf pascalprecht.translate.$translateProvider
+ *
+ * @description
+ * Tells angular-translate to use `$translateCookieStorage` service as storage layer.
+ */
+ this.useCookieStorage = function () {
+ return this.useStorage('$translateCookieStorage');
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateProvider#useStorage
+ * @methodOf pascalprecht.translate.$translateProvider
+ *
+ * @description
+ * Tells angular-translate to use custom service as storage layer.
+ */
+ this.useStorage = function (storageFactory) {
+ $storageFactory = storageFactory;
+ return this;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateProvider#storagePrefix
+ * @methodOf pascalprecht.translate.$translateProvider
+ *
+ * @description
+ * Sets prefix for storage key.
+ *
+ * @param {string} prefix Storage key prefix
+ */
+ this.storagePrefix = function (prefix) {
+ if (!prefix) {
+ return prefix;
+ }
+ $storagePrefix = prefix;
+ return this;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateProvider#useMissingTranslationHandlerLog
+ * @methodOf pascalprecht.translate.$translateProvider
+ *
+ * @description
+ * Tells angular-translate to use built-in log handler when trying to translate
+ * a translation Id which doesn't exist.
+ *
+ * This is actually a shortcut method for `useMissingTranslationHandler()`.
+ *
+ */
+ this.useMissingTranslationHandlerLog = function () {
+ return this.useMissingTranslationHandler('$translateMissingTranslationHandlerLog');
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateProvider#useMissingTranslationHandler
+ * @methodOf pascalprecht.translate.$translateProvider
+ *
+ * @description
+ * Expects a factory name which later gets instantiated with `$injector`.
+ * This method can be used to tell angular-translate to use a custom
+ * missingTranslationHandler. Just build a factory which returns a function
+ * and expects a translation id as argument.
+ *
+ * Example:
+ * <pre>
+ * app.config(function ($translateProvider) {
+ * $translateProvider.useMissingTranslationHandler('customHandler');
+ * });
+ *
+ * app.factory('customHandler', function (dep1, dep2) {
+ * return function (translationId) {
+ * // something with translationId and dep1 and dep2
+ * };
+ * });
+ * </pre>
+ *
+ * @param {string} factory Factory name
+ */
+ this.useMissingTranslationHandler = function (factory) {
+ $missingTranslationHandlerFactory = factory;
+ return this;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateProvider#usePostCompiling
+ * @methodOf pascalprecht.translate.$translateProvider
+ *
+ * @description
+ * If post compiling is enabled, all translated values will be processed
+ * again with AngularJS' $compile.
+ *
+ * Example:
+ * <pre>
+ * app.config(function ($translateProvider) {
+ * $translateProvider.usePostCompiling(true);
+ * });
+ * </pre>
+ *
+ * @param {string} factory Factory name
+ */
+ this.usePostCompiling = function (value) {
+ $postCompilingEnabled = !(!value);
+ return this;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateProvider#forceAsyncReload
+ * @methodOf pascalprecht.translate.$translateProvider
+ *
+ * @description
+ * If force async reload is enabled, async loader will always be called
+ * even if $translationTable already contains the language key, adding
+ * possible new entries to the $translationTable.
+ *
+ * Example:
+ * <pre>
+ * app.config(function ($translateProvider) {
+ * $translateProvider.forceAsyncReload(true);
+ * });
+ * </pre>
+ *
+ * @param {boolean} value - valid values are true or false
+ */
+ this.forceAsyncReload = function (value) {
+ $forceAsyncReloadEnabled = !(!value);
+ return this;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateProvider#uniformLanguageTag
+ * @methodOf pascalprecht.translate.$translateProvider
+ *
+ * @description
+ * Tells angular-translate which language tag should be used as a result when determining
+ * the current browser language.
+ *
+ * This setting must be set before invoking {@link pascalprecht.translate.$translateProvider#methods_determinePreferredLanguage determinePreferredLanguage()}.
+ *
+ * <pre>
+ * $translateProvider
+ * .uniformLanguageTag('bcp47')
+ * .determinePreferredLanguage()
+ * </pre>
+ *
+ * The resolver currently supports:
+ * * default
+ * (traditionally: hyphens will be converted into underscores, i.e. en-US => en_US)
+ * en-US => en_US
+ * en_US => en_US
+ * en-us => en_us
+ * * java
+ * like default, but the second part will be always in uppercase
+ * en-US => en_US
+ * en_US => en_US
+ * en-us => en_US
+ * * BCP 47 (RFC 4646 & 4647)
+ * en-US => en-US
+ * en_US => en-US
+ * en-us => en-US
+ *
+ * See also:
+ * * http://en.wikipedia.org/wiki/IETF_language_tag
+ * * http://www.w3.org/International/core/langtags/
+ * * http://tools.ietf.org/html/bcp47
+ *
+ * @param {string|object} options - options (or standard)
+ * @param {string} options.standard - valid values are 'default', 'bcp47', 'java'
+ */
+ this.uniformLanguageTag = function (options) {
+
+ if (!options) {
+ options = {};
+ } else if (angular.isString(options)) {
+ options = {
+ standard : options
+ };
+ }
+
+ uniformLanguageTagResolver = options.standard;
+
+ return this;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateProvider#determinePreferredLanguage
+ * @methodOf pascalprecht.translate.$translateProvider
+ *
+ * @description
+ * Tells angular-translate to try to determine on its own which language key
+ * to set as preferred language. When `fn` is given, angular-translate uses it
+ * to determine a language key, otherwise it uses the built-in `getLocale()`
+ * method.
+ *
+ * The `getLocale()` returns a language key in the format `[lang]_[country]` or
+ * `[lang]` depending on what the browser provides.
+ *
+ * Use this method at your own risk, since not all browsers return a valid
+ * locale (see {@link pascalprecht.translate.$translateProvider#methods_uniformLanguageTag uniformLanguageTag()}).
+ *
+ * @param {Function=} fn Function to determine a browser's locale
+ */
+ this.determinePreferredLanguage = function (fn) {
+
+ var locale = (fn && angular.isFunction(fn)) ? fn() : getLocale();
+
+ if (!$availableLanguageKeys.length) {
+ $preferredLanguage = locale;
+ } else {
+ $preferredLanguage = negotiateLocale(locale) || locale;
+ }
+
+ return this;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateProvider#registerAvailableLanguageKeys
+ * @methodOf pascalprecht.translate.$translateProvider
+ *
+ * @description
+ * Registers a set of language keys the app will work with. Use this method in
+ * combination with
+ * {@link pascalprecht.translate.$translateProvider#determinePreferredLanguage determinePreferredLanguage}.
+ * When available languages keys are registered, angular-translate
+ * tries to find the best fitting language key depending on the browsers locale,
+ * considering your language key convention.
+ *
+ * @param {object} languageKeys Array of language keys the your app will use
+ * @param {object=} aliases Alias map.
+ */
+ this.registerAvailableLanguageKeys = function (languageKeys, aliases) {
+ if (languageKeys) {
+ $availableLanguageKeys = languageKeys;
+ if (aliases) {
+ $languageKeyAliases = aliases;
+ }
+ return this;
+ }
+ return $availableLanguageKeys;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateProvider#useLoaderCache
+ * @methodOf pascalprecht.translate.$translateProvider
+ *
+ * @description
+ * Registers a cache for internal $http based loaders.
+ * {@link pascalprecht.translate.$translationCache $translationCache}.
+ * When false the cache will be disabled (default). When true or undefined
+ * the cache will be a default (see $cacheFactory). When an object it will
+ * be treat as a cache object itself: the usage is $http({cache: cache})
+ *
+ * @param {object} cache boolean, string or cache-object
+ */
+ this.useLoaderCache = function (cache) {
+ if (cache === false) {
+ // disable cache
+ loaderCache = undefined;
+ } else if (cache === true) {
+ // enable cache using AJS defaults
+ loaderCache = true;
+ } else if (typeof(cache) === 'undefined') {
+ // enable cache using default
+ loaderCache = '$translationCache';
+ } else if (cache) {
+ // enable cache using given one (see $cacheFactory)
+ loaderCache = cache;
+ }
+ return this;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateProvider#directivePriority
+ * @methodOf pascalprecht.translate.$translateProvider
+ *
+ * @description
+ * Sets the default priority of the translate directive. The standard value is `0`.
+ * Calling this function without an argument will return the current value.
+ *
+ * @param {number} priority for the translate-directive
+ */
+ this.directivePriority = function (priority) {
+ if (priority === undefined) {
+ // getter
+ return directivePriority;
+ } else {
+ // setter with chaining
+ directivePriority = priority;
+ return this;
+ }
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateProvider#statefulFilter
+ * @methodOf pascalprecht.translate.$translateProvider
+ *
+ * @description
+ * Since AngularJS 1.3, filters which are not stateless (depending at the scope)
+ * have to explicit define this behavior.
+ * Sets whether the translate filter should be stateful or stateless. The standard value is `true`
+ * meaning being stateful.
+ * Calling this function without an argument will return the current value.
+ *
+ * @param {boolean} state - defines the state of the filter
+ */
+ this.statefulFilter = function (state) {
+ if (state === undefined) {
+ // getter
+ return statefulFilter;
+ } else {
+ // setter with chaining
+ statefulFilter = state;
+ return this;
+ }
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateProvider#postProcess
+ * @methodOf pascalprecht.translate.$translateProvider
+ *
+ * @description
+ * The post processor will be intercept right after the translation result. It can modify the result.
+ *
+ * @param {object} fn Function or service name (string) to be called after the translation value has been set / resolved. The function itself will enrich every value being processed and then continue the normal resolver process
+ */
+ this.postProcess = function (fn) {
+ if (fn) {
+ postProcessFn = fn;
+ } else {
+ postProcessFn = undefined;
+ }
+ return this;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateProvider#keepContent
+ * @methodOf pascalprecht.translate.$translateProvider
+ *
+ * @description
+ * If keepContent is set to true than translate directive will always use innerHTML
+ * as a default translation
+ *
+ * Example:
+ * <pre>
+ * app.config(function ($translateProvider) {
+ * $translateProvider.keepContent(true);
+ * });
+ * </pre>
+ *
+ * @param {boolean} value - valid values are true or false
+ */
+ this.keepContent = function (value) {
+ $keepContent = !(!value);
+ return this;
+ };
+
+ /**
+ * @ngdoc object
+ * @name pascalprecht.translate.$translate
+ * @requires $interpolate
+ * @requires $log
+ * @requires $rootScope
+ * @requires $q
+ *
+ * @description
+ * The `$translate` service is the actual core of angular-translate. It expects a translation id
+ * and optional interpolate parameters to translate contents.
+ *
+ * <pre>
+ * $translate('HEADLINE_TEXT').then(function (translation) {
+ * $scope.translatedText = translation;
+ * });
+ * </pre>
+ *
+ * @param {string|array} translationId A token which represents a translation id
+ * This can be optionally an array of translation ids which
+ * results that the function returns an object where each key
+ * is the translation id and the value the translation.
+ * @param {object=} interpolateParams An object hash for dynamic values
+ * @param {string} interpolationId The id of the interpolation to use
+ * @param {string} defaultTranslationText the optional default translation text that is written as
+ * as default text in case it is not found in any configured language
+ * @param {string} forceLanguage A language to be used instead of the current language
+ * @returns {object} promise
+ */
+ this.$get = ['$log', '$injector', '$rootScope', '$q', function ($log, $injector, $rootScope, $q) {
+
+ var Storage,
+ defaultInterpolator = $injector.get($interpolationFactory || '$translateDefaultInterpolation'),
+ pendingLoader = false,
+ interpolatorHashMap = {},
+ langPromises = {},
+ fallbackIndex,
+ startFallbackIteration;
+
+ var $translate = function (translationId, interpolateParams, interpolationId, defaultTranslationText, forceLanguage) {
+ if (!$uses && $preferredLanguage) {
+ $uses = $preferredLanguage;
+ }
+ var uses = (forceLanguage && forceLanguage !== $uses) ? // we don't want to re-negotiate $uses
+ (negotiateLocale(forceLanguage) || forceLanguage) : $uses;
+
+ // Check forceLanguage is present
+ if (forceLanguage) {
+ loadTranslationsIfMissing(forceLanguage);
+ }
+
+ // Duck detection: If the first argument is an array, a bunch of translations was requested.
+ // The result is an object.
+ if (angular.isArray(translationId)) {
+ // Inspired by Q.allSettled by Kris Kowal
+ // https://github.com/kriskowal/q/blob/b0fa72980717dc202ffc3cbf03b936e10ebbb9d7/q.js#L1553-1563
+ // This transforms all promises regardless resolved or rejected
+ var translateAll = function (translationIds) {
+ var results = {}; // storing the actual results
+ var promises = []; // promises to wait for
+ // Wraps the promise a) being always resolved and b) storing the link id->value
+ var translate = function (translationId) {
+ var deferred = $q.defer();
+ var regardless = function (value) {
+ results[translationId] = value;
+ deferred.resolve([translationId, value]);
+ };
+ // we don't care whether the promise was resolved or rejected; just store the values
+ $translate(translationId, interpolateParams, interpolationId, defaultTranslationText, forceLanguage).then(regardless, regardless);
+ return deferred.promise;
+ };
+ for (var i = 0, c = translationIds.length; i < c; i++) {
+ promises.push(translate(translationIds[i]));
+ }
+ // wait for all (including storing to results)
+ return $q.all(promises).then(function () {
+ // return the results
+ return results;
+ });
+ };
+ return translateAll(translationId);
+ }
+
+ var deferred = $q.defer();
+
+ // trim off any whitespace
+ if (translationId) {
+ translationId = trim.apply(translationId);
+ }
+
+ var promiseToWaitFor = (function () {
+ var promise = $preferredLanguage ?
+ langPromises[$preferredLanguage] :
+ langPromises[uses];
+
+ fallbackIndex = 0;
+
+ if ($storageFactory && !promise) {
+ // looks like there's no pending promise for $preferredLanguage or
+ // $uses. Maybe there's one pending for a language that comes from
+ // storage.
+ var langKey = Storage.get($storageKey);
+ promise = langPromises[langKey];
+
+ if ($fallbackLanguage && $fallbackLanguage.length) {
+ var index = indexOf($fallbackLanguage, langKey);
+ // maybe the language from storage is also defined as fallback language
+ // we increase the fallback language index to not search in that language
+ // as fallback, since it's probably the first used language
+ // in that case the index starts after the first element
+ fallbackIndex = (index === 0) ? 1 : 0;
+
+ // but we can make sure to ALWAYS fallback to preferred language at least
+ if (indexOf($fallbackLanguage, $preferredLanguage) < 0) {
+ $fallbackLanguage.push($preferredLanguage);
+ }
+ }
+ }
+ return promise;
+ }());
+
+ if (!promiseToWaitFor) {
+ // no promise to wait for? okay. Then there's no loader registered
+ // nor is a one pending for language that comes from storage.
+ // We can just translate.
+ determineTranslation(translationId, interpolateParams, interpolationId, defaultTranslationText, uses).then(deferred.resolve, deferred.reject);
+ } else {
+ var promiseResolved = function () {
+ // $uses may have changed while waiting
+ if (!forceLanguage) {
+ uses = $uses;
+ }
+ determineTranslation(translationId, interpolateParams, interpolationId, defaultTranslationText, uses).then(deferred.resolve, deferred.reject);
+ };
+ promiseResolved.displayName = 'promiseResolved';
+
+ promiseToWaitFor['finally'](promiseResolved)
+ .catch(angular.noop); // we don't care about errors here, already handled
+ }
+ return deferred.promise;
+ };
+
+ /**
+ * @name applyNotFoundIndicators
+ * @private
+ *
+ * @description
+ * Applies not fount indicators to given translation id, if needed.
+ * This function gets only executed, if a translation id doesn't exist,
+ * which is why a translation id is expected as argument.
+ *
+ * @param {string} translationId Translation id.
+ * @returns {string} Same as given translation id but applied with not found
+ * indicators.
+ */
+ var applyNotFoundIndicators = function (translationId) {
+ // applying notFoundIndicators
+ if ($notFoundIndicatorLeft) {
+ translationId = [$notFoundIndicatorLeft, translationId].join(' ');
+ }
+ if ($notFoundIndicatorRight) {
+ translationId = [translationId, $notFoundIndicatorRight].join(' ');
+ }
+ return translationId;
+ };
+
+ /**
+ * @name useLanguage
+ * @private
+ *
+ * @description
+ * Makes actual use of a language by setting a given language key as used
+ * language and informs registered interpolators to also use the given
+ * key as locale.
+ *
+ * @param {string} key Locale key.
+ */
+ var useLanguage = function (key) {
+ $uses = key;
+
+ // make sure to store new language key before triggering success event
+ if ($storageFactory) {
+ Storage.put($translate.storageKey(), $uses);
+ }
+
+ $rootScope.$emit('$translateChangeSuccess', {language : key});
+
+ // inform default interpolator
+ defaultInterpolator.setLocale($uses);
+
+ var eachInterpolator = function (interpolator, id) {
+ interpolatorHashMap[id].setLocale($uses);
+ };
+ eachInterpolator.displayName = 'eachInterpolatorLocaleSetter';
+
+ // inform all others too!
+ angular.forEach(interpolatorHashMap, eachInterpolator);
+ $rootScope.$emit('$translateChangeEnd', {language : key});
+ };
+
+ /**
+ * @name loadAsync
+ * @private
+ *
+ * @description
+ * Kicks off registered async loader using `$injector` and applies existing
+ * loader options. When resolved, it updates translation tables accordingly
+ * or rejects with given language key.
+ *
+ * @param {string} key Language key.
+ * @return {Promise} A promise.
+ */
+ var loadAsync = function (key) {
+ if (!key) {
+ throw 'No language key specified for loading.';
+ }
+
+ var deferred = $q.defer();
+
+ $rootScope.$emit('$translateLoadingStart', {language : key});
+ pendingLoader = true;
+
+ var cache = loaderCache;
+ if (typeof(cache) === 'string') {
+ // getting on-demand instance of loader
+ cache = $injector.get(cache);
+ }
+
+ var loaderOptions = angular.extend({}, $loaderOptions, {
+ key : key,
+ $http : angular.extend({}, {
+ cache : cache
+ }, $loaderOptions.$http)
+ });
+
+ var onLoaderSuccess = function (data) {
+ var translationTable = {};
+ $rootScope.$emit('$translateLoadingSuccess', {language : key});
+
+ if (angular.isArray(data)) {
+ angular.forEach(data, function (table) {
+ angular.extend(translationTable, flatObject(table));
+ });
+ } else {
+ angular.extend(translationTable, flatObject(data));
+ }
+ pendingLoader = false;
+ deferred.resolve({
+ key : key,
+ table : translationTable
+ });
+ $rootScope.$emit('$translateLoadingEnd', {language : key});
+ };
+ onLoaderSuccess.displayName = 'onLoaderSuccess';
+
+ var onLoaderError = function (key) {
+ $rootScope.$emit('$translateLoadingError', {language : key});
+ deferred.reject(key);
+ $rootScope.$emit('$translateLoadingEnd', {language : key});
+ };
+ onLoaderError.displayName = 'onLoaderError';
+
+ $injector.get($loaderFactory)(loaderOptions)
+ .then(onLoaderSuccess, onLoaderError);
+
+ return deferred.promise;
+ };
+
+ if ($storageFactory) {
+ Storage = $injector.get($storageFactory);
+
+ if (!Storage.get || !Storage.put) {
+ throw new Error('Couldn\'t use storage \'' + $storageFactory + '\', missing get() or put() method!');
+ }
+ }
+
+ // if we have additional interpolations that were added via
+ // $translateProvider.addInterpolation(), we have to map'em
+ if ($interpolatorFactories.length) {
+ var eachInterpolationFactory = function (interpolatorFactory) {
+ var interpolator = $injector.get(interpolatorFactory);
+ // setting initial locale for each interpolation service
+ interpolator.setLocale($preferredLanguage || $uses);
+ // make'em recognizable through id
+ interpolatorHashMap[interpolator.getInterpolationIdentifier()] = interpolator;
+ };
+ eachInterpolationFactory.displayName = 'interpolationFactoryAdder';
+
+ angular.forEach($interpolatorFactories, eachInterpolationFactory);
+ }
+
+ /**
+ * @name getTranslationTable
+ * @private
+ *
+ * @description
+ * Returns a promise that resolves to the translation table
+ * or is rejected if an error occurred.
+ *
+ * @param langKey
+ * @returns {Q.promise}
+ */
+ var getTranslationTable = function (langKey) {
+ var deferred = $q.defer();
+ if (Object.prototype.hasOwnProperty.call($translationTable, langKey)) {
+ deferred.resolve($translationTable[langKey]);
+ } else if (langPromises[langKey]) {
+ var onResolve = function (data) {
+ translations(data.key, data.table);
+ deferred.resolve(data.table);
+ };
+ onResolve.displayName = 'translationTableResolver';
+ langPromises[langKey].then(onResolve, deferred.reject);
+ } else {
+ deferred.reject();
+ }
+ return deferred.promise;
+ };
+
+ /**
+ * @name getFallbackTranslation
+ * @private
+ *
+ * @description
+ * Returns a promise that will resolve to the translation
+ * or be rejected if no translation was found for the language.
+ * This function is currently only used for fallback language translation.
+ *
+ * @param langKey The language to translate to.
+ * @param translationId
+ * @param interpolateParams
+ * @param Interpolator
+ * @param sanitizeStrategy
+ * @returns {Q.promise}
+ */
+ var getFallbackTranslation = function (langKey, translationId, interpolateParams, Interpolator, sanitizeStrategy) {
+ var deferred = $q.defer();
+
+ var onResolve = function (translationTable) {
+ if (Object.prototype.hasOwnProperty.call(translationTable, translationId) && translationTable[translationId] !== null) {
+ Interpolator.setLocale(langKey);
+ var translation = translationTable[translationId];
+ if (translation.substr(0, 2) === '@:') {
+ getFallbackTranslation(langKey, translation.substr(2), interpolateParams, Interpolator, sanitizeStrategy)
+ .then(deferred.resolve, deferred.reject);
+ } else {
+ var interpolatedValue = Interpolator.interpolate(translationTable[translationId], interpolateParams, 'service', sanitizeStrategy, translationId);
+ interpolatedValue = applyPostProcessing(translationId, translationTable[translationId], interpolatedValue, interpolateParams, langKey);
+
+ deferred.resolve(interpolatedValue);
+
+ }
+ Interpolator.setLocale($uses);
+ } else {
+ deferred.reject();
+ }
+ };
+ onResolve.displayName = 'fallbackTranslationResolver';
+
+ getTranslationTable(langKey).then(onResolve, deferred.reject);
+
+ return deferred.promise;
+ };
+
+ /**
+ * @name getFallbackTranslationInstant
+ * @private
+ *
+ * @description
+ * Returns a translation
+ * This function is currently only used for fallback language translation.
+ *
+ * @param langKey The language to translate to.
+ * @param translationId
+ * @param interpolateParams
+ * @param Interpolator
+ * @param sanitizeStrategy sanitize strategy override
+ *
+ * @returns {string} translation
+ */
+ var getFallbackTranslationInstant = function (langKey, translationId, interpolateParams, Interpolator, sanitizeStrategy) {
+ var result, translationTable = $translationTable[langKey];
+
+ if (translationTable && Object.prototype.hasOwnProperty.call(translationTable, translationId) && translationTable[translationId] !== null) {
+ Interpolator.setLocale(langKey);
+ result = Interpolator.interpolate(translationTable[translationId], interpolateParams, 'filter', sanitizeStrategy, translationId);
+ result = applyPostProcessing(translationId, translationTable[translationId], result, interpolateParams, langKey, sanitizeStrategy);
+ // workaround for TrustedValueHolderType
+ if (!angular.isString(result) && angular.isFunction(result.$$unwrapTrustedValue)) {
+ var result2 = result.$$unwrapTrustedValue();
+ if (result2.substr(0, 2) === '@:') {
+ return getFallbackTranslationInstant(langKey, result2.substr(2), interpolateParams, Interpolator, sanitizeStrategy);
+ }
+ } else if (result.substr(0, 2) === '@:') {
+ return getFallbackTranslationInstant(langKey, result.substr(2), interpolateParams, Interpolator, sanitizeStrategy);
+ }
+ Interpolator.setLocale($uses);
+ }
+
+ return result;
+ };
+
+
+ /**
+ * @name translateByHandler
+ * @private
+ *
+ * Translate by missing translation handler.
+ *
+ * @param translationId
+ * @param interpolateParams
+ * @param defaultTranslationText
+ * @param sanitizeStrategy sanitize strategy override
+ *
+ * @returns translation created by $missingTranslationHandler or translationId is $missingTranslationHandler is
+ * absent
+ */
+ var translateByHandler = function (translationId, interpolateParams, defaultTranslationText, sanitizeStrategy) {
+ // If we have a handler factory - we might also call it here to determine if it provides
+ // a default text for a translationid that can't be found anywhere in our tables
+ if ($missingTranslationHandlerFactory) {
+ return $injector.get($missingTranslationHandlerFactory)(translationId, $uses, interpolateParams, defaultTranslationText, sanitizeStrategy);
+ } else {
+ return translationId;
+ }
+ };
+
+ /**
+ * @name resolveForFallbackLanguage
+ * @private
+ *
+ * Recursive helper function for fallbackTranslation that will sequentially look
+ * for a translation in the fallbackLanguages starting with fallbackLanguageIndex.
+ *
+ * @param fallbackLanguageIndex
+ * @param translationId
+ * @param interpolateParams
+ * @param Interpolator
+ * @param defaultTranslationText
+ * @param sanitizeStrategy
+ * @returns {Q.promise} Promise that will resolve to the translation.
+ */
+ var resolveForFallbackLanguage = function (fallbackLanguageIndex, translationId, interpolateParams, Interpolator, defaultTranslationText, sanitizeStrategy) {
+ var deferred = $q.defer();
+
+ if (fallbackLanguageIndex < $fallbackLanguage.length) {
+ var langKey = $fallbackLanguage[fallbackLanguageIndex];
+ getFallbackTranslation(langKey, translationId, interpolateParams, Interpolator, sanitizeStrategy).then(
+ function (data) {
+ deferred.resolve(data);
+ },
+ function () {
+ // Look in the next fallback language for a translation.
+ // It delays the resolving by passing another promise to resolve.
+ return resolveForFallbackLanguage(fallbackLanguageIndex + 1, translationId, interpolateParams, Interpolator, defaultTranslationText, sanitizeStrategy).then(deferred.resolve, deferred.reject);
+ }
+ );
+ } else {
+ // No translation found in any fallback language
+ // if a default translation text is set in the directive, then return this as a result
+ if (defaultTranslationText) {
+ deferred.resolve(defaultTranslationText);
+ } else {
+ var missingTranslationHandlerTranslation = translateByHandler(translationId, interpolateParams, defaultTranslationText);
+
+ // if no default translation is set and an error handler is defined, send it to the handler
+ // and then return the result if it isn't undefined
+ if ($missingTranslationHandlerFactory && missingTranslationHandlerTranslation) {
+ deferred.resolve(missingTranslationHandlerTranslation);
+ } else {
+ deferred.reject(applyNotFoundIndicators(translationId));
+ }
+ }
+ }
+ return deferred.promise;
+ };
+
+ /**
+ * @name resolveForFallbackLanguageInstant
+ * @private
+ *
+ * Recursive helper function for fallbackTranslation that will sequentially look
+ * for a translation in the fallbackLanguages starting with fallbackLanguageIndex.
+ *
+ * @param fallbackLanguageIndex
+ * @param translationId
+ * @param interpolateParams
+ * @param Interpolator
+ * @param sanitizeStrategy
+ * @returns {string} translation
+ */
+ var resolveForFallbackLanguageInstant = function (fallbackLanguageIndex, translationId, interpolateParams, Interpolator, sanitizeStrategy) {
+ var result;
+
+ if (fallbackLanguageIndex < $fallbackLanguage.length) {
+ var langKey = $fallbackLanguage[fallbackLanguageIndex];
+ result = getFallbackTranslationInstant(langKey, translationId, interpolateParams, Interpolator, sanitizeStrategy);
+ if (!result && result !== '') {
+ result = resolveForFallbackLanguageInstant(fallbackLanguageIndex + 1, translationId, interpolateParams, Interpolator);
+ }
+ }
+ return result;
+ };
+
+ /**
+ * Translates with the usage of the fallback languages.
+ *
+ * @param translationId
+ * @param interpolateParams
+ * @param Interpolator
+ * @param defaultTranslationText
+ * @param sanitizeStrategy
+ * @returns {Q.promise} Promise, that resolves to the translation.
+ */
+ var fallbackTranslation = function (translationId, interpolateParams, Interpolator, defaultTranslationText, sanitizeStrategy) {
+ // Start with the fallbackLanguage with index 0
+ return resolveForFallbackLanguage((startFallbackIteration > 0 ? startFallbackIteration : fallbackIndex), translationId, interpolateParams, Interpolator, defaultTranslationText, sanitizeStrategy);
+ };
+
+ /**
+ * Translates with the usage of the fallback languages.
+ *
+ * @param translationId
+ * @param interpolateParams
+ * @param Interpolator
+ * @param sanitizeStrategy
+ * @returns {String} translation
+ */
+ var fallbackTranslationInstant = function (translationId, interpolateParams, Interpolator, sanitizeStrategy) {
+ // Start with the fallbackLanguage with index 0
+ return resolveForFallbackLanguageInstant((startFallbackIteration > 0 ? startFallbackIteration : fallbackIndex), translationId, interpolateParams, Interpolator, sanitizeStrategy);
+ };
+
+ var determineTranslation = function (translationId, interpolateParams, interpolationId, defaultTranslationText, uses, sanitizeStrategy) {
+
+ var deferred = $q.defer();
+
+ var table = uses ? $translationTable[uses] : $translationTable,
+ Interpolator = (interpolationId) ? interpolatorHashMap[interpolationId] : defaultInterpolator;
+
+ // if the translation id exists, we can just interpolate it
+ if (table && Object.prototype.hasOwnProperty.call(table, translationId) && table[translationId] !== null) {
+ var translation = table[translationId];
+
+ // If using link, rerun $translate with linked translationId and return it
+ if (translation.substr(0, 2) === '@:') {
+
+ $translate(translation.substr(2), interpolateParams, interpolationId, defaultTranslationText, uses)
+ .then(deferred.resolve, deferred.reject);
+ } else {
+ //
+ var resolvedTranslation = Interpolator.interpolate(translation, interpolateParams, 'service', sanitizeStrategy, translationId);
+ resolvedTranslation = applyPostProcessing(translationId, translation, resolvedTranslation, interpolateParams, uses);
+ deferred.resolve(resolvedTranslation);
+ }
+ } else {
+ var missingTranslationHandlerTranslation;
+ // for logging purposes only (as in $translateMissingTranslationHandlerLog), value is not returned to promise
+ if ($missingTranslationHandlerFactory && !pendingLoader) {
+ missingTranslationHandlerTranslation = translateByHandler(translationId, interpolateParams, defaultTranslationText);
+ }
+
+ // since we couldn't translate the inital requested translation id,
+ // we try it now with one or more fallback languages, if fallback language(s) is
+ // configured.
+ if (uses && $fallbackLanguage && $fallbackLanguage.length) {
+ fallbackTranslation(translationId, interpolateParams, Interpolator, defaultTranslationText, sanitizeStrategy)
+ .then(function (translation) {
+ deferred.resolve(translation);
+ }, function (_translationId) {
+ deferred.reject(applyNotFoundIndicators(_translationId));
+ });
+ } else if ($missingTranslationHandlerFactory && !pendingLoader && missingTranslationHandlerTranslation) {
+ // looks like the requested translation id doesn't exists.
+ // Now, if there is a registered handler for missing translations and no
+ // asyncLoader is pending, we execute the handler
+ if (defaultTranslationText) {
+ deferred.resolve(defaultTranslationText);
+ } else {
+ deferred.resolve(missingTranslationHandlerTranslation);
+ }
+ } else {
+ if (defaultTranslationText) {
+ deferred.resolve(defaultTranslationText);
+ } else {
+ deferred.reject(applyNotFoundIndicators(translationId));
+ }
+ }
+ }
+ return deferred.promise;
+ };
+
+ var determineTranslationInstant = function (translationId, interpolateParams, interpolationId, uses, sanitizeStrategy) {
+
+ var result, table = uses ? $translationTable[uses] : $translationTable,
+ Interpolator = defaultInterpolator;
+
+ // if the interpolation id exists use custom interpolator
+ if (interpolatorHashMap && Object.prototype.hasOwnProperty.call(interpolatorHashMap, interpolationId)) {
+ Interpolator = interpolatorHashMap[interpolationId];
+ }
+
+ // if the translation id exists, we can just interpolate it
+ if (table && Object.prototype.hasOwnProperty.call(table, translationId) && table[translationId] !== null) {
+ var translation = table[translationId];
+
+ // If using link, rerun $translate with linked translationId and return it
+ if (translation.substr(0, 2) === '@:') {
+ result = determineTranslationInstant(translation.substr(2), interpolateParams, interpolationId, uses, sanitizeStrategy);
+ } else {
+ result = Interpolator.interpolate(translation, interpolateParams, 'filter', sanitizeStrategy, translationId);
+ result = applyPostProcessing(translationId, translation, result, interpolateParams, uses, sanitizeStrategy);
+ }
+ } else {
+ var missingTranslationHandlerTranslation;
+ // for logging purposes only (as in $translateMissingTranslationHandlerLog), value is not returned to promise
+ if ($missingTranslationHandlerFactory && !pendingLoader) {
+ missingTranslationHandlerTranslation = translateByHandler(translationId, interpolateParams, sanitizeStrategy);
+ }
+
+ // since we couldn't translate the inital requested translation id,
+ // we try it now with one or more fallback languages, if fallback language(s) is
+ // configured.
+ if (uses && $fallbackLanguage && $fallbackLanguage.length) {
+ fallbackIndex = 0;
+ result = fallbackTranslationInstant(translationId, interpolateParams, Interpolator, sanitizeStrategy);
+ } else if ($missingTranslationHandlerFactory && !pendingLoader && missingTranslationHandlerTranslation) {
+ // looks like the requested translation id doesn't exists.
+ // Now, if there is a registered handler for missing translations and no
+ // asyncLoader is pending, we execute the handler
+ result = missingTranslationHandlerTranslation;
+ } else {
+ result = applyNotFoundIndicators(translationId);
+ }
+ }
+
+ return result;
+ };
+
+ var clearNextLangAndPromise = function (key) {
+ if ($nextLang === key) {
+ $nextLang = undefined;
+ }
+ langPromises[key] = undefined;
+ };
+
+ var applyPostProcessing = function (translationId, translation, resolvedTranslation, interpolateParams, uses, sanitizeStrategy) {
+ var fn = postProcessFn;
+
+ if (fn) {
+
+ if (typeof(fn) === 'string') {
+ // getting on-demand instance
+ fn = $injector.get(fn);
+ }
+ if (fn) {
+ return fn(translationId, translation, resolvedTranslation, interpolateParams, uses, sanitizeStrategy);
+ }
+ }
+
+ return resolvedTranslation;
+ };
+
+ var loadTranslationsIfMissing = function (key) {
+ if (!$translationTable[key] && $loaderFactory && !langPromises[key]) {
+ langPromises[key] = loadAsync(key).then(function (translation) {
+ translations(translation.key, translation.table);
+ return translation;
+ });
+ }
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translate#preferredLanguage
+ * @methodOf pascalprecht.translate.$translate
+ *
+ * @description
+ * Returns the language key for the preferred language.
+ *
+ * @param {string} langKey language String or Array to be used as preferredLanguage (changing at runtime)
+ *
+ * @return {string} preferred language key
+ */
+ $translate.preferredLanguage = function (langKey) {
+ if (langKey) {
+ setupPreferredLanguage(langKey);
+ }
+ return $preferredLanguage;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translate#cloakClassName
+ * @methodOf pascalprecht.translate.$translate
+ *
+ * @description
+ * Returns the configured class name for `translate-cloak` directive.
+ *
+ * @return {string} cloakClassName
+ */
+ $translate.cloakClassName = function () {
+ return $cloakClassName;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translate#nestedObjectDelimeter
+ * @methodOf pascalprecht.translate.$translate
+ *
+ * @description
+ * Returns the configured delimiter for nested namespaces.
+ *
+ * @return {string} nestedObjectDelimeter
+ */
+ $translate.nestedObjectDelimeter = function () {
+ return $nestedObjectDelimeter;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translate#fallbackLanguage
+ * @methodOf pascalprecht.translate.$translate
+ *
+ * @description
+ * Returns the language key for the fallback languages or sets a new fallback stack.
+ *
+ * @param {string=} langKey language String or Array of fallback languages to be used (to change stack at runtime)
+ *
+ * @return {string||array} fallback language key
+ */
+ $translate.fallbackLanguage = function (langKey) {
+ if (langKey !== undefined && langKey !== null) {
+ fallbackStack(langKey);
+
+ // as we might have an async loader initiated and a new translation language might have been defined
+ // we need to add the promise to the stack also. So - iterate.
+ if ($loaderFactory) {
+ if ($fallbackLanguage && $fallbackLanguage.length) {
+ for (var i = 0, len = $fallbackLanguage.length; i < len; i++) {
+ if (!langPromises[$fallbackLanguage[i]]) {
+ langPromises[$fallbackLanguage[i]] = loadAsync($fallbackLanguage[i]);
+ }
+ }
+ }
+ }
+ $translate.use($translate.use());
+ }
+ if ($fallbackWasString) {
+ return $fallbackLanguage[0];
+ } else {
+ return $fallbackLanguage;
+ }
+
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translate#useFallbackLanguage
+ * @methodOf pascalprecht.translate.$translate
+ *
+ * @description
+ * Sets the first key of the fallback language stack to be used for translation.
+ * Therefore all languages in the fallback array BEFORE this key will be skipped!
+ *
+ * @param {string=} langKey Contains the langKey the iteration shall start with. Set to false if you want to
+ * get back to the whole stack
+ */
+ $translate.useFallbackLanguage = function (langKey) {
+ if (langKey !== undefined && langKey !== null) {
+ if (!langKey) {
+ startFallbackIteration = 0;
+ } else {
+ var langKeyPosition = indexOf($fallbackLanguage, langKey);
+ if (langKeyPosition > -1) {
+ startFallbackIteration = langKeyPosition;
+ }
+ }
+
+ }
+
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translate#proposedLanguage
+ * @methodOf pascalprecht.translate.$translate
+ *
+ * @description
+ * Returns the language key of language that is currently loaded asynchronously.
+ *
+ * @return {string} language key
+ */
+ $translate.proposedLanguage = function () {
+ return $nextLang;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translate#storage
+ * @methodOf pascalprecht.translate.$translate
+ *
+ * @description
+ * Returns registered storage.
+ *
+ * @return {object} Storage
+ */
+ $translate.storage = function () {
+ return Storage;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translate#negotiateLocale
+ * @methodOf pascalprecht.translate.$translate
+ *
+ * @description
+ * Returns a language key based on available languages and language aliases. If a
+ * language key cannot be resolved, returns undefined.
+ *
+ * If no or a falsy key is given, returns undefined.
+ *
+ * @param {string} [key] Language key
+ * @return {string|undefined} Language key or undefined if no language key is found.
+ */
+ $translate.negotiateLocale = negotiateLocale;
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translate#use
+ * @methodOf pascalprecht.translate.$translate
+ *
+ * @description
+ * Tells angular-translate which language to use by given language key. This method is
+ * used to change language at runtime. It also takes care of storing the language
+ * key in a configured store to let your app remember the choosed language.
+ *
+ * When trying to 'use' a language which isn't available it tries to load it
+ * asynchronously with registered loaders.
+ *
+ * Returns promise object with loaded language file data or string of the currently used language.
+ *
+ * If no or a falsy key is given it returns the currently used language key.
+ * The returned string will be ```undefined``` if setting up $translate hasn't finished.
+ * @example
+ * $translate.use("en_US").then(function(data){
+ * $scope.text = $translate("HELLO");
+ * });
+ *
+ * @param {string} [key] Language key
+ * @return {object|string} Promise with loaded language data or the language key if a falsy param was given.
+ */
+ $translate.use = function (key) {
+ if (!key) {
+ return $uses;
+ }
+
+ var deferred = $q.defer();
+ deferred.promise.then(null, angular.noop); // AJS "Possibly unhandled rejection"
+
+ $rootScope.$emit('$translateChangeStart', {language : key});
+
+ // Try to get the aliased language key
+ var aliasedKey = negotiateLocale(key);
+ // Ensure only registered language keys will be loaded
+ if ($availableLanguageKeys.length > 0 && !aliasedKey) {
+ return $q.reject(key);
+ }
+
+ if (aliasedKey) {
+ key = aliasedKey;
+ }
+
+ // if there isn't a translation table for the language we've requested,
+ // we load it asynchronously
+ $nextLang = key;
+ if (($forceAsyncReloadEnabled || !$translationTable[key]) && $loaderFactory && !langPromises[key]) {
+ langPromises[key] = loadAsync(key).then(function (translation) {
+ translations(translation.key, translation.table);
+ deferred.resolve(translation.key);
+ if ($nextLang === key) {
+ useLanguage(translation.key);
+ }
+ return translation;
+ }, function (key) {
+ $rootScope.$emit('$translateChangeError', {language : key});
+ deferred.reject(key);
+ $rootScope.$emit('$translateChangeEnd', {language : key});
+ return $q.reject(key);
+ });
+ langPromises[key]['finally'](function () {
+ clearNextLangAndPromise(key);
+ }).catch(angular.noop); // we don't care about errors (clearing)
+ } else if (langPromises[key]) {
+ // we are already loading this asynchronously
+ // resolve our new deferred when the old langPromise is resolved
+ langPromises[key].then(function (translation) {
+ if ($nextLang === translation.key) {
+ useLanguage(translation.key);
+ }
+ deferred.resolve(translation.key);
+ return translation;
+ }, function (key) {
+ // find first available fallback language if that request has failed
+ if (!$uses && $fallbackLanguage && $fallbackLanguage.length > 0 && $fallbackLanguage[0] !== key) {
+ return $translate.use($fallbackLanguage[0]).then(deferred.resolve, deferred.reject);
+ } else {
+ return deferred.reject(key);
+ }
+ });
+ } else {
+ deferred.resolve(key);
+ useLanguage(key);
+ }
+
+ return deferred.promise;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translate#resolveClientLocale
+ * @methodOf pascalprecht.translate.$translate
+ *
+ * @description
+ * This returns the current browser/client's language key. The result is processed with the configured uniform tag resolver.
+ *
+ * @returns {string} the current client/browser language key
+ */
+ $translate.resolveClientLocale = function () {
+ return getLocale();
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translate#storageKey
+ * @methodOf pascalprecht.translate.$translate
+ *
+ * @description
+ * Returns the key for the storage.
+ *
+ * @return {string} storage key
+ */
+ $translate.storageKey = function () {
+ return storageKey();
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translate#isPostCompilingEnabled
+ * @methodOf pascalprecht.translate.$translate
+ *
+ * @description
+ * Returns whether post compiling is enabled or not
+ *
+ * @return {bool} storage key
+ */
+ $translate.isPostCompilingEnabled = function () {
+ return $postCompilingEnabled;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translate#isForceAsyncReloadEnabled
+ * @methodOf pascalprecht.translate.$translate
+ *
+ * @description
+ * Returns whether force async reload is enabled or not
+ *
+ * @return {boolean} forceAsyncReload value
+ */
+ $translate.isForceAsyncReloadEnabled = function () {
+ return $forceAsyncReloadEnabled;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translate#isKeepContent
+ * @methodOf pascalprecht.translate.$translate
+ *
+ * @description
+ * Returns whether keepContent or not
+ *
+ * @return {boolean} keepContent value
+ */
+ $translate.isKeepContent = function () {
+ return $keepContent;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translate#refresh
+ * @methodOf pascalprecht.translate.$translate
+ *
+ * @description
+ * Refreshes a translation table pointed by the given langKey. If langKey is not specified,
+ * the module will drop all existent translation tables and load new version of those which
+ * are currently in use.
+ *
+ * Refresh means that the module will drop target translation table and try to load it again.
+ *
+ * In case there are no loaders registered the refresh() method will throw an Error.
+ *
+ * If the module is able to refresh translation tables refresh() method will broadcast
+ * $translateRefreshStart and $translateRefreshEnd events.
+ *
+ * @example
+ * // this will drop all currently existent translation tables and reload those which are
+ * // currently in use
+ * $translate.refresh();
+ * // this will refresh a translation table for the en_US language
+ * $translate.refresh('en_US');
+ *
+ * @param {string} langKey A language key of the table, which has to be refreshed
+ *
+ * @return {promise} Promise, which will be resolved in case a translation tables refreshing
+ * process is finished successfully, and reject if not.
+ */
+ $translate.refresh = function (langKey) {
+ if (!$loaderFactory) {
+ throw new Error('Couldn\'t refresh translation table, no loader registered!');
+ }
+
+ $rootScope.$emit('$translateRefreshStart', {language : langKey});
+
+ var deferred = $q.defer(), updatedLanguages = {};
+
+ //private helper
+ function loadNewData(languageKey) {
+ var promise = loadAsync(languageKey);
+ //update the load promise cache for this language
+ langPromises[languageKey] = promise;
+ //register a data handler for the promise
+ promise.then(function (data) {
+ //clear the cache for this language
+ $translationTable[languageKey] = {};
+ //add the new data for this language
+ translations(languageKey, data.table);
+ //track that we updated this language
+ updatedLanguages[languageKey] = true;
+ },
+ //handle rejection to appease the $q validation
+ angular.noop);
+ return promise;
+ }
+
+ //set up post-processing
+ deferred.promise.then(
+ function () {
+ for (var key in $translationTable) {
+ if ($translationTable.hasOwnProperty(key)) {
+ //delete cache entries that were not updated
+ if (!(key in updatedLanguages)) {
+ delete $translationTable[key];
+ }
+ }
+ }
+ if ($uses) {
+ useLanguage($uses);
+ }
+ },
+ //handle rejection to appease the $q validation
+ angular.noop
+ ).finally(
+ function () {
+ $rootScope.$emit('$translateRefreshEnd', {language : langKey});
+ }
+ );
+
+ if (!langKey) {
+ // if there's no language key specified we refresh ALL THE THINGS!
+ var languagesToReload = $fallbackLanguage && $fallbackLanguage.slice() || [];
+ if ($uses && languagesToReload.indexOf($uses) === -1) {
+ languagesToReload.push($uses);
+ }
+ $q.all(languagesToReload.map(loadNewData)).then(deferred.resolve, deferred.reject);
+
+ } else if ($translationTable[langKey]) {
+ //just refresh the specified language cache
+ loadNewData(langKey).then(deferred.resolve, deferred.reject);
+
+ } else {
+ deferred.reject();
+ }
+
+ return deferred.promise;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translate#instant
+ * @methodOf pascalprecht.translate.$translate
+ *
+ * @description
+ * Returns a translation instantly from the internal state of loaded translation. All rules
+ * regarding the current language, the preferred language of even fallback languages will be
+ * used except any promise handling. If a language was not found, an asynchronous loading
+ * will be invoked in the background.
+ *
+ * @param {string|array} translationId A token which represents a translation id
+ * This can be optionally an array of translation ids which
+ * results that the function's promise returns an object where
+ * each key is the translation id and the value the translation.
+ * @param {object} interpolateParams Params
+ * @param {string} interpolationId The id of the interpolation to use
+ * @param {string} forceLanguage A language to be used instead of the current language
+ * @param {string} sanitizeStrategy force sanitize strategy for this call instead of using the configured one
+ *
+ * @return {string|object} translation
+ */
+ $translate.instant = function (translationId, interpolateParams, interpolationId, forceLanguage, sanitizeStrategy) {
+
+ // we don't want to re-negotiate $uses
+ var uses = (forceLanguage && forceLanguage !== $uses) ? // we don't want to re-negotiate $uses
+ (negotiateLocale(forceLanguage) || forceLanguage) : $uses;
+
+ // Detect undefined and null values to shorten the execution and prevent exceptions
+ if (translationId === null || angular.isUndefined(translationId)) {
+ return translationId;
+ }
+
+ // Check forceLanguage is present
+ if (forceLanguage) {
+ loadTranslationsIfMissing(forceLanguage);
+ }
+
+ // Duck detection: If the first argument is an array, a bunch of translations was requested.
+ // The result is an object.
+ if (angular.isArray(translationId)) {
+ var results = {};
+ for (var i = 0, c = translationId.length; i < c; i++) {
+ results[translationId[i]] = $translate.instant(translationId[i], interpolateParams, interpolationId, forceLanguage, sanitizeStrategy);
+ }
+ return results;
+ }
+
+ // We discarded unacceptable values. So we just need to verify if translationId is empty String
+ if (angular.isString(translationId) && translationId.length < 1) {
+ return translationId;
+ }
+
+ // trim off any whitespace
+ if (translationId) {
+ translationId = trim.apply(translationId);
+ }
+
+ var result, possibleLangKeys = [];
+ if ($preferredLanguage) {
+ possibleLangKeys.push($preferredLanguage);
+ }
+ if (uses) {
+ possibleLangKeys.push(uses);
+ }
+ if ($fallbackLanguage && $fallbackLanguage.length) {
+ possibleLangKeys = possibleLangKeys.concat($fallbackLanguage);
+ }
+ for (var j = 0, d = possibleLangKeys.length; j < d; j++) {
+ var possibleLangKey = possibleLangKeys[j];
+ if ($translationTable[possibleLangKey]) {
+ if (typeof $translationTable[possibleLangKey][translationId] !== 'undefined') {
+ result = determineTranslationInstant(translationId, interpolateParams, interpolationId, uses, sanitizeStrategy);
+ }
+ }
+ if (typeof result !== 'undefined') {
+ break;
+ }
+ }
+
+ if (!result && result !== '') {
+ if ($notFoundIndicatorLeft || $notFoundIndicatorRight) {
+ result = applyNotFoundIndicators(translationId);
+ } else {
+ // Return translation of default interpolator if not found anything.
+ result = defaultInterpolator.interpolate(translationId, interpolateParams, 'filter', sanitizeStrategy);
+
+ // looks like the requested translation id doesn't exists.
+ // Now, if there is a registered handler for missing translations and no
+ // asyncLoader is pending, we execute the handler
+ var missingTranslationHandlerTranslation;
+ if ($missingTranslationHandlerFactory && !pendingLoader) {
+ missingTranslationHandlerTranslation = translateByHandler(translationId, interpolateParams, sanitizeStrategy);
+ }
+
+ if ($missingTranslationHandlerFactory && !pendingLoader && missingTranslationHandlerTranslation) {
+ result = missingTranslationHandlerTranslation;
+ }
+ }
+ }
+
+ return result;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translate#versionInfo
+ * @methodOf pascalprecht.translate.$translate
+ *
+ * @description
+ * Returns the current version information for the angular-translate library
+ *
+ * @return {string} angular-translate version
+ */
+ $translate.versionInfo = function () {
+ return version;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translate#loaderCache
+ * @methodOf pascalprecht.translate.$translate
+ *
+ * @description
+ * Returns the defined loaderCache.
+ *
+ * @return {boolean|string|object} current value of loaderCache
+ */
+ $translate.loaderCache = function () {
+ return loaderCache;
+ };
+
+ // internal purpose only
+ $translate.directivePriority = function () {
+ return directivePriority;
+ };
+
+ // internal purpose only
+ $translate.statefulFilter = function () {
+ return statefulFilter;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translate#isReady
+ * @methodOf pascalprecht.translate.$translate
+ *
+ * @description
+ * Returns whether the service is "ready" to translate (i.e. loading 1st language).
+ *
+ * See also {@link pascalprecht.translate.$translate#methods_onReady onReady()}.
+ *
+ * @return {boolean} current value of ready
+ */
+ $translate.isReady = function () {
+ return $isReady;
+ };
+
+ var $onReadyDeferred = $q.defer();
+ $onReadyDeferred.promise.then(function () {
+ $isReady = true;
+ });
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translate#onReady
+ * @methodOf pascalprecht.translate.$translate
+ *
+ * @description
+ * Returns whether the service is "ready" to translate (i.e. loading 1st language).
+ *
+ * See also {@link pascalprecht.translate.$translate#methods_isReady isReady()}.
+ *
+ * @param {Function=} fn Function to invoke when service is ready
+ * @return {object} Promise resolved when service is ready
+ */
+ $translate.onReady = function (fn) {
+ var deferred = $q.defer();
+ if (angular.isFunction(fn)) {
+ deferred.promise.then(fn);
+ }
+ if ($isReady) {
+ deferred.resolve();
+ } else {
+ $onReadyDeferred.promise.then(deferred.resolve);
+ }
+ return deferred.promise;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translate#getAvailableLanguageKeys
+ * @methodOf pascalprecht.translate.$translate
+ *
+ * @description
+ * This function simply returns the registered language keys being defined before in the config phase
+ * With this, an application can use the array to provide a language selection dropdown or similar
+ * without any additional effort
+ *
+ * @returns {object} returns the list of possibly registered language keys and mapping or null if not defined
+ */
+ $translate.getAvailableLanguageKeys = function () {
+ if ($availableLanguageKeys.length > 0) {
+ return $availableLanguageKeys;
+ }
+ return null;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translate#getTranslationTable
+ * @methodOf pascalprecht.translate.$translate
+ *
+ * @description
+ * Returns translation table by the given language key.
+ *
+ * Unless a language is provided it returns a translation table of the current one.
+ * Note: If translation dictionary is currently downloading or in progress
+ * it will return null.
+ *
+ * @param {string} langKey A token which represents a translation id
+ *
+ * @return {object} a copy of angular-translate $translationTable
+ */
+ $translate.getTranslationTable = function (langKey) {
+ langKey = langKey || $translate.use();
+ if (langKey && $translationTable[langKey]) {
+ return angular.copy($translationTable[langKey]);
+ }
+ return null;
+ };
+
+ // Whenever $translateReady is being fired, this will ensure the state of $isReady
+ var globalOnReadyListener = $rootScope.$on('$translateReady', function () {
+ $onReadyDeferred.resolve();
+ globalOnReadyListener(); // one time only
+ globalOnReadyListener = null;
+ });
+ var globalOnChangeListener = $rootScope.$on('$translateChangeEnd', function () {
+ $onReadyDeferred.resolve();
+ globalOnChangeListener(); // one time only
+ globalOnChangeListener = null;
+ });
+
+ if ($loaderFactory) {
+
+ // If at least one async loader is defined and there are no
+ // (default) translations available we should try to load them.
+ if (angular.equals($translationTable, {})) {
+ if ($translate.use()) {
+ $translate.use($translate.use());
+ }
+ }
+
+ // Also, if there are any fallback language registered, we start
+ // loading them asynchronously as soon as we can.
+ if ($fallbackLanguage && $fallbackLanguage.length) {
+ var processAsyncResult = function (translation) {
+ translations(translation.key, translation.table);
+ $rootScope.$emit('$translateChangeEnd', {language : translation.key});
+ return translation;
+ };
+ for (var i = 0, len = $fallbackLanguage.length; i < len; i++) {
+ var fallbackLanguageId = $fallbackLanguage[i];
+ if ($forceAsyncReloadEnabled || !$translationTable[fallbackLanguageId]) {
+ langPromises[fallbackLanguageId] = loadAsync(fallbackLanguageId).then(processAsyncResult);
+ }
+ }
+ }
+ } else {
+ $rootScope.$emit('$translateReady', {language : $translate.use()});
+ }
+
+ return $translate;
+ }];
+}
+
+$translate.displayName = 'displayName';
+
+/**
+ * @ngdoc object
+ * @name pascalprecht.translate.$translateDefaultInterpolation
+ * @requires $interpolate
+ *
+ * @description
+ * Uses angular's `$interpolate` services to interpolate strings against some values.
+ *
+ * Be aware to configure a proper sanitization strategy.
+ *
+ * See also:
+ * * {@link pascalprecht.translate.$translateSanitization}
+ *
+ * @return {object} $translateDefaultInterpolation Interpolator service
+ */
+angular.module('pascalprecht.translate').factory('$translateDefaultInterpolation', $translateDefaultInterpolation);
+
+function $translateDefaultInterpolation ($interpolate, $translateSanitization) {
+
+ 'use strict';
+
+ var $translateInterpolator = {},
+ $locale,
+ $identifier = 'default';
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateDefaultInterpolation#setLocale
+ * @methodOf pascalprecht.translate.$translateDefaultInterpolation
+ *
+ * @description
+ * Sets current locale (this is currently not use in this interpolation).
+ *
+ * @param {string} locale Language key or locale.
+ */
+ $translateInterpolator.setLocale = function (locale) {
+ $locale = locale;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateDefaultInterpolation#getInterpolationIdentifier
+ * @methodOf pascalprecht.translate.$translateDefaultInterpolation
+ *
+ * @description
+ * Returns an identifier for this interpolation service.
+ *
+ * @returns {string} $identifier
+ */
+ $translateInterpolator.getInterpolationIdentifier = function () {
+ return $identifier;
+ };
+
+ /**
+ * @deprecated will be removed in 3.0
+ * @see {@link pascalprecht.translate.$translateSanitization}
+ */
+ $translateInterpolator.useSanitizeValueStrategy = function (value) {
+ $translateSanitization.useStrategy(value);
+ return this;
+ };
+
+ /**
+ * @ngdoc function
+ * @name pascalprecht.translate.$translateDefaultInterpolation#interpolate
+ * @methodOf pascalprecht.translate.$translateDefaultInterpolation
+ *
+ * @description
+ * Interpolates given value agains given interpolate params using angulars
+ * `$interpolate` service.
+ *
+ * Since AngularJS 1.5, `value` must not be a string but can be anything input.
+ *
+ * @param value translation
+ * @param interpolationParams interpolation params
+ * @param context current context (filter, directive, service)
+ * @param sanitizeStrategy sanitize strategy
+ * @param translationId current translationId
+ *
+ * @returns {string} interpolated string
+ */
+ $translateInterpolator.interpolate = function (value, interpolationParams, context, sanitizeStrategy/*, translationId*/) {
+ interpolationParams = interpolationParams || {};
+ interpolationParams = $translateSanitization.sanitize(interpolationParams, 'params', sanitizeStrategy, context);
+
+ var interpolatedText;
+ if (angular.isNumber(value)) {
+ // numbers are safe
+ interpolatedText = '' + value;
+ } else if (angular.isString(value)) {
+ // strings must be interpolated (that's the job here)
+ interpolatedText = $interpolate(value)(interpolationParams);
+ interpolatedText = $translateSanitization.sanitize(interpolatedText, 'text', sanitizeStrategy, context);
+ } else {
+ // neither a number or a string, cant interpolate => empty string
+ interpolatedText = '';
+ }
+
+ return interpolatedText;
+ };
+
+ return $translateInterpolator;
+}
+
+$translateDefaultInterpolation.displayName = '$translateDefaultInterpolation';
+
+angular.module('pascalprecht.translate').constant('$STORAGE_KEY', 'NG_TRANSLATE_LANG_KEY');
+
+angular.module('pascalprecht.translate')
+/**
+ * @ngdoc directive
+ * @name pascalprecht.translate.directive:translate
+ * @requires $interpolate,
+ * @requires $compile,
+ * @requires $parse,
+ * @requires $rootScope
+ * @restrict AE
+ *
+ * @description
+ * Translates given translation id either through attribute or DOM content.
+ * Internally it uses $translate service to translate the translation id. It possible to
+ * pass an optional `translate-values` object literal as string into translation id.
+ *
+ * @param {string=} translate Translation id which could be either string or interpolated string.
+ * @param {string=} translate-values Values to pass into translation id. Can be passed as object literal string or interpolated object.
+ * @param {string=} translate-attr-ATTR translate Translation id and put it into ATTR attribute.
+ * @param {string=} translate-default will be used unless translation was successful
+ * @param {boolean=} translate-compile (default true if present) defines locally activation of {@link pascalprecht.translate.$translateProvider#methods_usePostCompiling}
+ * @param {boolean=} translate-keep-content (default true if present) defines that in case a KEY could not be translated, that the existing content is left in the innerHTML}
+ *
+ * @example
+ <example module="ngView">
+ <file name="index.html">
+ <div ng-controller="TranslateCtrl">
+
+ <pre translate="TRANSLATION_ID"></pre>
+ <pre translate>TRANSLATION_ID</pre>
+ <pre translate translate-attr-title="TRANSLATION_ID"></pre>
+ <pre translate="{{translationId}}"></pre>
+ <pre translate>{{translationId}}</pre>
+ <pre translate="WITH_VALUES" translate-values="{value: 5}"></pre>
+ <pre translate translate-values="{value: 5}">WITH_VALUES</pre>
+ <pre translate="WITH_VALUES" translate-values="{{values}}"></pre>
+ <pre translate translate-values="{{values}}">WITH_VALUES</pre>
+ <pre translate translate-attr-title="WITH_VALUES" translate-values="{{values}}"></pre>
+ <pre translate="WITH_CAMEL_CASE_KEY" translate-value-camel-case-key="Hi"></pre>
+
+ </div>
+ </file>
+ <file name="script.js">
+ angular.module('ngView', ['pascalprecht.translate'])
+
+ .config(function ($translateProvider) {
+
+ $translateProvider.translations('en',{
+ 'TRANSLATION_ID': 'Hello there!',
+ 'WITH_VALUES': 'The following value is dynamic: {{value}}',
+ 'WITH_CAMEL_CASE_KEY': 'The interpolation key is camel cased: {{camelCaseKey}}'
+ }).preferredLanguage('en');
+
+ });
+
+ angular.module('ngView').controller('TranslateCtrl', function ($scope) {
+ $scope.translationId = 'TRANSLATION_ID';
+
+ $scope.values = {
+ value: 78
+ };
+ });
+ </file>
+ <file name="scenario.js">
+ it('should translate', function () {
+ inject(function ($rootScope, $compile) {
+ $rootScope.translationId = 'TRANSLATION_ID';
+
+ element = $compile('<p translate="TRANSLATION_ID"></p>')($rootScope);
+ $rootScope.$digest();
+ expect(element.text()).toBe('Hello there!');
+
+ element = $compile('<p translate="{{translationId}}"></p>')($rootScope);
+ $rootScope.$digest();
+ expect(element.text()).toBe('Hello there!');
+
+ element = $compile('<p translate>TRANSLATION_ID</p>')($rootScope);
+ $rootScope.$digest();
+ expect(element.text()).toBe('Hello there!');
+
+ element = $compile('<p translate>{{translationId}}</p>')($rootScope);
+ $rootScope.$digest();
+ expect(element.text()).toBe('Hello there!');
+
+ element = $compile('<p translate translate-attr-title="TRANSLATION_ID"></p>')($rootScope);
+ $rootScope.$digest();
+ expect(element.attr('title')).toBe('Hello there!');
+
+ element = $compile('<p translate="WITH_CAMEL_CASE_KEY" translate-value-camel-case-key="Hello"></p>')($rootScope);
+ $rootScope.$digest();
+ expect(element.text()).toBe('The interpolation key is camel cased: Hello');
+ });
+ });
+ </file>
+ </example>
+ */
+.directive('translate', translateDirective);
+function translateDirective($translate, $interpolate, $compile, $parse, $rootScope) {
+
+ 'use strict';
+
+ /**
+ * @name trim
+ * @private
+ *
+ * @description
+ * trim polyfill
+ *
+ * @returns {string} The string stripped of whitespace from both ends
+ */
+ var trim = function() {
+ return this.toString().replace(/^\s+|\s+$/g, '');
+ };
+
+ return {
+ restrict: 'AE',
+ scope: true,
+ priority: $translate.directivePriority(),
+ compile: function (tElement, tAttr) {
+
+ var translateValuesExist = (tAttr.translateValues) ?
+ tAttr.translateValues : undefined;
+
+ var translateInterpolation = (tAttr.translateInterpolation) ?
+ tAttr.translateInterpolation : undefined;
+
+ var translateValueExist = tElement[0].outerHTML.match(/translate-value-+/i);
+
+ var interpolateRegExp = '^(.*)(' + $interpolate.startSymbol() + '.*' + $interpolate.endSymbol() + ')(.*)',
+ watcherRegExp = '^(.*)' + $interpolate.startSymbol() + '(.*)' + $interpolate.endSymbol() + '(.*)';
+
+ return function linkFn(scope, iElement, iAttr) {
+
+ scope.interpolateParams = {};
+ scope.preText = '';
+ scope.postText = '';
+ scope.translateNamespace = getTranslateNamespace(scope);
+ var translationIds = {};
+
+ var initInterpolationParams = function (interpolateParams, iAttr, tAttr) {
+ // initial setup
+ if (iAttr.translateValues) {
+ angular.extend(interpolateParams, $parse(iAttr.translateValues)(scope.$parent));
+ }
+ // initially fetch all attributes if existing and fill the params
+ 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);
+ interpolateParams[attributeName] = tAttr[attr];
+ }
+ }
+ }
+ };
+
+ // Ensures any change of the attribute "translate" containing the id will
+ // be re-stored to the scope's "translationId".
+ // If the attribute has no content, the element's text value (white spaces trimmed off) will be used.
+ var observeElementTranslation = function (translationId) {
+
+ // Remove any old watcher
+ if (angular.isFunction(observeElementTranslation._unwatchOld)) {
+ observeElementTranslation._unwatchOld();
+ observeElementTranslation._unwatchOld = undefined;
+ }
+
+ if (angular.equals(translationId , '') || !angular.isDefined(translationId)) {
+ var iElementText = trim.apply(iElement.text());
+
+ // Resolve translation id by inner html if required
+ var interpolateMatches = iElementText.match(interpolateRegExp);
+ // Interpolate translation id if required
+ if (angular.isArray(interpolateMatches)) {
+ scope.preText = interpolateMatches[1];
+ scope.postText = interpolateMatches[3];
+ translationIds.translate = $interpolate(interpolateMatches[2])(scope.$parent);
+ var watcherMatches = iElementText.match(watcherRegExp);
+ if (angular.isArray(watcherMatches) && watcherMatches[2] && watcherMatches[2].length) {
+ observeElementTranslation._unwatchOld = scope.$watch(watcherMatches[2], function (newValue) {
+ translationIds.translate = newValue;
+ updateTranslations();
+ });
+ }
+ } else {
+ // do not assigne the translation id if it is empty.
+ translationIds.translate = !iElementText ? undefined : iElementText;
+ }
+ } else {
+ translationIds.translate = translationId;
+ }
+ updateTranslations();
+ };
+
+ var observeAttributeTranslation = function (translateAttr) {
+ iAttr.$observe(translateAttr, function (translationId) {
+ translationIds[translateAttr] = translationId;
+ updateTranslations();
+ });
+ };
+
+ // initial setup with values
+ initInterpolationParams(scope.interpolateParams, iAttr, tAttr);
+
+ var firstAttributeChangedEvent = true;
+ iAttr.$observe('translate', function (translationId) {
+ if (typeof translationId === 'undefined') {
+ // case of element "<translate>xyz</translate>"
+ observeElementTranslation('');
+ } else {
+ // case of regular attribute
+ if (translationId !== '' || !firstAttributeChangedEvent) {
+ translationIds.translate = translationId;
+ updateTranslations();
+ }
+ }
+ firstAttributeChangedEvent = false;
+ });
+
+ for (var translateAttr in iAttr) {
+ if (iAttr.hasOwnProperty(translateAttr) && translateAttr.substr(0, 13) === 'translateAttr' && translateAttr.length > 13) {
+ observeAttributeTranslation(translateAttr);
+ }
+ }
+
+ iAttr.$observe('translateDefault', function (value) {
+ scope.defaultText = value;
+ updateTranslations();
+ });
+
+ if (translateValuesExist) {
+ iAttr.$observe('translateValues', function (interpolateParams) {
+ if (interpolateParams) {
+ scope.$parent.$watch(function () {
+ angular.extend(scope.interpolateParams, $parse(interpolateParams)(scope.$parent));
+ });
+ }
+ });
+ }
+
+ if (translateValueExist) {
+ var observeValueAttribute = function (attrName) {
+ iAttr.$observe(attrName, function (value) {
+ var attributeName = angular.lowercase(attrName.substr(14, 1)) + attrName.substr(15);
+ scope.interpolateParams[attributeName] = value;
+ });
+ };
+ for (var attr in iAttr) {
+ if (Object.prototype.hasOwnProperty.call(iAttr, attr) && attr.substr(0, 14) === 'translateValue' && attr !== 'translateValues') {
+ observeValueAttribute(attr);
+ }
+ }
+ }
+
+ // 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);
+ }
+ }
+ };
+
+ // Put translation processing function outside loop
+ var updateTranslation = function(translateAttr, translationId, scope, interpolateParams, defaultTranslationText, translateNamespace) {
+ if (translationId) {
+ // if translation id starts with '.' and translateNamespace given, prepend namespace
+ if (translateNamespace && translationId.charAt(0) === '.') {
+ translationId = translateNamespace + translationId;
+ }
+
+ $translate(translationId, interpolateParams, translateInterpolation, defaultTranslationText, scope.translateLanguage)
+ .then(function (translation) {
+ applyTranslation(translation, scope, true, translateAttr);
+ }, function (translationId) {
+ applyTranslation(translationId, scope, false, translateAttr);
+ });
+ } else {
+ // as an empty string cannot be translated, we can solve this using successful=false
+ applyTranslation(translationId, scope, false, translateAttr);
+ }
+ };
+
+ var applyTranslation = function (value, scope, successful, translateAttr) {
+ if (!successful) {
+ if (typeof scope.defaultText !== 'undefined') {
+ value = scope.defaultText;
+ }
+ }
+ 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';
+ if ((globallyEnabled && !locallyDefined) || locallyEnabled) {
+ $compile(iElement.contents())(scope);
+ }
+ } else {
+ // translate attribute
+ var attributeName = iAttr.$attr[translateAttr];
+ if (attributeName.substr(0, 5) === 'data-') {
+ // ensure html5 data prefix is stripped
+ attributeName = attributeName.substr(5);
+ }
+ attributeName = attributeName.substr(15);
+ iElement.attr(attributeName, value);
+ }
+ };
+
+ if (translateValuesExist || translateValueExist || iAttr.translateDefault) {
+ scope.$watch('interpolateParams', 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);
+
+ // ensure translation will be looked up at least one
+ if (iElement.text().length) {
+ if (iAttr.translate) {
+ observeElementTranslation(iAttr.translate);
+ } else {
+ observeElementTranslation('');
+ }
+ } else if (iAttr.translate) {
+ // ensure attribute will be not skipped
+ observeElementTranslation(iAttr.translate);
+ }
+ updateTranslations();
+ scope.$on('$destroy', unbind);
+ };
+ }
+ };
+}
+
+/**
+ * Returns the scope's namespace.
+ * @private
+ * @param scope
+ * @returns {string}
+ */
+function getTranslateNamespace(scope) {
+ 'use strict';
+ if (scope.translateNamespace) {
+ return scope.translateNamespace;
+ }
+ if (scope.$parent) {
+ return getTranslateNamespace(scope.$parent);
+ }
+}
+
+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.
+ *
+ * @example
+ <example module="ngView">
+ <file name="index.html">
+ <div ng-controller="TranslateCtrl">
+
+ <input translate-attr="{ placeholder: translationId, title: 'WITH_VALUES' }" translate-values="{value: 5}" />
+
+ </div>
+ </file>
+ <file name="script.js">
+ 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
+ };
+ });
+ </file>
+ <file name="scenario.js">
+ it('should translate', function () {
+ inject(function ($rootScope, $compile) {
+ $rootScope.translationId = 'TRANSLATION_ID';
+
+ element = $compile('<input translate-attr="{ placeholder: translationId, title: 'WITH_VALUES' }" translate-values="{ value: 5 }" />')($rootScope);
+ $rootScope.$digest();
+ expect(element.attr('placeholder)).toBe('Hello there!');
+ expect(element.attr('title)).toBe('The following value is dynamic: 5');
+ });
+ });
+ </file>
+ </example>
+ */
+.directive('translateAttr', translateAttrDirective);
+function translateAttrDirective($translate, $rootScope) {
+
+ 'use strict';
+
+ return {
+ restrict: 'A',
+ priority: $translate.directivePriority(),
+ link: function linkFn(scope, element, attr) {
+
+ var translateAttr,
+ translateValues,
+ 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)
+ .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
+ );
+
+ 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 $translate
+ * @restrict A
+ *
+ * $description
+ * Adds a `translate-cloak` class name to the given element where this directive
+ * is applied initially and removes it, once a loader has finished loading.
+ *
+ * This directive can be used to prevent initial flickering when loading translation
+ * data asynchronously.
+ *
+ * The class name is defined in
+ * {@link pascalprecht.translate.$translateProvider#cloakClassName $translate.cloakClassName()}.
+ *
+ * @param {string=} translate-cloak If a translationId is provided, it will be used for showing
+ * or hiding the cloak. Basically it relies on the translation
+ * resolve.
+ */
+.directive('translateCloak', translateCloakDirective);
+
+function translateCloakDirective($translate) {
+
+ 'use strict';
+
+ return {
+ 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(iRemoveCloak, iApplyCloak);
+ });
+ }
+ else {
+ $translate.onReady(iRemoveCloak);
+ }
+ };
+ }
+ };
+}
+
+translateCloakDirective.displayName = 'translateCloakDirective';
+
+angular.module('pascalprecht.translate')
+/**
+ * @ngdoc directive
+ * @name pascalprecht.translate.directive:translateNamespace
+ * @restrict A
+ *
+ * @description
+ * Translates given translation id either through attribute or DOM content.
+ * Internally it uses `translate` filter to translate translation id. It possible to
+ * pass an optional `translate-values` object literal as string into translation id.
+ *
+ * @param {string=} translate namespace name which could be either string or interpolated string.
+ *
+ * @example
+ <example module="ngView">
+ <file name="index.html">
+ <div translate-namespace="CONTENT">
+
+ <div>
+ <h1 translate>.HEADERS.TITLE</h1>
+ <h1 translate>.HEADERS.WELCOME</h1>
+ </div>
+
+ <div translate-namespace=".HEADERS">
+ <h1 translate>.TITLE</h1>
+ <h1 translate>.WELCOME</h1>
+ </div>
+
+ </div>
+ </file>
+ <file name="script.js">
+ angular.module('ngView', ['pascalprecht.translate'])
+
+ .config(function ($translateProvider) {
+
+ $translateProvider.translations('en',{
+ 'TRANSLATION_ID': 'Hello there!',
+ 'CONTENT': {
+ 'HEADERS': {
+ TITLE: 'Title'
+ }
+ },
+ 'CONTENT.HEADERS.WELCOME': 'Welcome'
+ }).preferredLanguage('en');
+
+ });
+
+ </file>
+ </example>
+ */
+.directive('translateNamespace', translateNamespaceDirective);
+
+function translateNamespaceDirective() {
+
+ 'use strict';
+
+ return {
+ restrict: 'A',
+ scope: true,
+ compile: function () {
+ return {
+ pre: function (scope, iElement, iAttrs) {
+ scope.translateNamespace = getTranslateNamespace(scope);
+
+ if (scope.translateNamespace && iAttrs.translateNamespace.charAt(0) === '.') {
+ scope.translateNamespace += iAttrs.translateNamespace;
+ } else {
+ scope.translateNamespace = iAttrs.translateNamespace;
+ }
+ }
+ };
+ }
+ };
+}
+
+/**
+ * Returns the scope's namespace.
+ * @private
+ * @param scope
+ * @returns {string}
+ */
+function getTranslateNamespace(scope) {
+ 'use strict';
+ if (scope.translateNamespace) {
+ return scope.translateNamespace;
+ }
+ if (scope.$parent) {
+ return getTranslateNamespace(scope.$parent);
+ }
+}
+
+translateNamespaceDirective.displayName = 'translateNamespaceDirective';
+
+angular.module('pascalprecht.translate')
+/**
+ * @ngdoc directive
+ * @name pascalprecht.translate.directive:translateLanguage
+ * @restrict A
+ *
+ * @description
+ * Forces the language to the directives in the underlying scope.
+ *
+ * @param {string=} translate language that will be negotiated.
+ *
+ * @example
+ <example module="ngView">
+ <file name="index.html">
+ <div>
+
+ <div>
+ <h1 translate>HELLO</h1>
+ </div>
+
+ <div translate-language="de">
+ <h1 translate>HELLO</h1>
+ </div>
+
+ </div>
+ </file>
+ <file name="script.js">
+ angular.module('ngView', ['pascalprecht.translate'])
+
+ .config(function ($translateProvider) {
+
+ $translateProvider
+ .translations('en',{
+ 'HELLO': 'Hello world!'
+ })
+ .translations('de',{
+ 'HELLO': 'Hallo Welt!'
+ })
+ .preferredLanguage('en');
+
+ });
+
+ </file>
+ </example>
+ */
+.directive('translateLanguage', translateLanguageDirective);
+
+function translateLanguageDirective() {
+
+ 'use strict';
+
+ return {
+ restrict: 'A',
+ 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');
+ });
+ };
+ }
+ };
+}
+
+translateLanguageDirective.displayName = 'translateLanguageDirective';
+
+angular.module('pascalprecht.translate')
+/**
+ * @ngdoc filter
+ * @name pascalprecht.translate.filter:translate
+ * @requires $parse
+ * @requires pascalprecht.translate.$translate
+ * @function
+ *
+ * @description
+ * Uses `$translate` service to translate contents. Accepts interpolate parameters
+ * to pass dynamized values though translation.
+ *
+ * @param {string} translationId A translation id to be translated.
+ * @param {*=} interpolateParams Optional object literal (as hash or string) to pass values into translation.
+ *
+ * @returns {string} Translated text.
+ *
+ * @example
+ <example module="ngView">
+ <file name="index.html">
+ <div ng-controller="TranslateCtrl">
+
+ <pre>{{ 'TRANSLATION_ID' | translate }}</pre>
+ <pre>{{ translationId | translate }}</pre>
+ <pre>{{ 'WITH_VALUES' | translate:'{value: 5}' }}</pre>
+ <pre>{{ 'WITH_VALUES' | translate:values }}</pre>
+
+ </div>
+ </file>
+ <file name="script.js">
+ angular.module('ngView', ['pascalprecht.translate'])
+
+ .config(function ($translateProvider) {
+
+ $translateProvider.translations('en', {
+ 'TRANSLATION_ID': 'Hello there!',
+ 'WITH_VALUES': 'The following value is dynamic: {{value}}'
+ });
+ $translateProvider.preferredLanguage('en');
+
+ });
+
+ angular.module('ngView').controller('TranslateCtrl', function ($scope) {
+ $scope.translationId = 'TRANSLATION_ID';
+
+ $scope.values = {
+ value: 78
+ };
+ });
+ </file>
+ </example>
+ */
+.filter('translate', translateFilterFactory);
+
+function translateFilterFactory($parse, $translate) {
+
+ 'use strict';
+
+ var translateFilter = function (translationId, interpolateParams, interpolation, forceLanguage) {
+ if (!angular.isObject(interpolateParams)) {
+ interpolateParams = $parse(interpolateParams)(this);
+ }
+
+ return $translate.instant(translationId, interpolateParams, interpolation, forceLanguage);
+ };
+
+ if ($translate.statefulFilter()) {
+ translateFilter.$stateful = true;
+ }
+
+ return translateFilter;
+}
+
+translateFilterFactory.displayName = 'translateFilterFactory';
+
+angular.module('pascalprecht.translate')
+
+/**
+ * @ngdoc object
+ * @name pascalprecht.translate.$translationCache
+ * @requires $cacheFactory
+ *
+ * @description
+ * The first time a translation table is used, it is loaded in the translation cache for quick retrieval. You
+ * can load translation tables directly into the cache by consuming the
+ * `$translationCache` service directly.
+ *
+ * @return {object} $cacheFactory object.
+ */
+ .factory('$translationCache', $translationCache);
+
+function $translationCache($cacheFactory) {
+
+ 'use strict';
+
+ return $cacheFactory('translations');
+}
+
+$translationCache.displayName = '$translationCache';
+return 'pascalprecht.translate';
+
+}));
diff --git a/vnfmarket/common/thirdparty/angular-translate/angular-translate.min.js b/vnfmarket/common/thirdparty/angular-translate/angular-translate.min.js
new file mode 100644
index 00000000..c0a94474
--- /dev/null
+++ b/vnfmarket/common/thirdparty/angular-translate/angular-translate.min.js
@@ -0,0 +1,6 @@
+/*!
+ * angular-translate - v2.14.0 - 2017-02-11
+ *
+ * Copyright (c) 2017 The angular-translate team, Pascal Precht; Licensed MIT
+ */
+!function(a,b){"function"==typeof define&&define.amd?define([],function(){return b()}):"object"==typeof exports?module.exports=b():b()}(this,function(){function a(a){"use strict";var b=a.storageKey(),c=a.storage(),d=function(){var d=a.preferredLanguage();angular.isString(d)?a.use(d):c.put(b,a.use())};d.displayName="fallbackFromIncorrectStorageValue",c?c.get(b)?a.use(c.get(b)).catch(d):d():angular.isString(a.preferredLanguage())&&a.use(a.preferredLanguage())}function b(){"use strict";var a,b,c,d=null,e=!1,f=!1;c={sanitize:function(a,b){return"text"===b&&(a=h(a)),a},escape:function(a,b){return"text"===b&&(a=g(a)),a},sanitizeParameters:function(a,b){return"params"===b&&(a=j(a,h)),a},escapeParameters:function(a,b){return"params"===b&&(a=j(a,g)),a},sce:function(a,b,c){return"text"===b?a=i(a):"params"===b&&"filter"!==c&&(a=j(a,g)),a},sceParameters:function(a,b){return"params"===b&&(a=j(a,i)),a}},c.escaped=c.escapeParameters,this.addStrategy=function(a,b){return c[a]=b,this},this.removeStrategy=function(a){return delete c[a],this},this.useStrategy=function(a){return e=!0,d=a,this},this.$get=["$injector","$log",function(g,h){var i={},j=function(a,b,d,e){return angular.forEach(e,function(e){if(angular.isFunction(e))a=e(a,b,d);else if(angular.isFunction(c[e]))a=c[e](a,b,d);else{if(!angular.isString(c[e]))throw new Error("pascalprecht.translate.$translateSanitization: Unknown sanitization strategy: '"+e+"'");if(!i[c[e]])try{i[c[e]]=g.get(c[e])}catch(a){throw i[c[e]]=function(){},new Error("pascalprecht.translate.$translateSanitization: Unknown sanitization strategy: '"+e+"'")}a=i[c[e]](a,b,d)}}),a},k=function(){e||f||(h.warn("pascalprecht.translate.$translateSanitization: No sanitization strategy has been configured. This can have serious security implications. See http://angular-translate.github.io/docs/#/guide/19_security for details."),f=!0)};return g.has("$sanitize")&&(a=g.get("$sanitize")),g.has("$sce")&&(b=g.get("$sce")),{useStrategy:function(a){return function(b){a.useStrategy(b)}}(this),sanitize:function(a,b,c,e){if(d||k(),c||null===c||(c=d),!c)return a;e||(e="service");var f=angular.isArray(c)?c:[c];return j(a,b,e,f)}}}];var g=function(a){var b=angular.element("<div></div>");return b.text(a),b.html()},h=function(b){if(!a)throw new Error("pascalprecht.translate.$translateSanitization: Error cannot find $sanitize service. Either include the ngSanitize module (https://docs.angularjs.org/api/ngSanitize) or use a sanitization strategy which does not depend on $sanitize, such as 'escape'.");return a(b)},i=function(a){if(!b)throw new Error("pascalprecht.translate.$translateSanitization: Error cannot find $sce service.");return b.trustAsHtml(a)},j=function(a,b,c){if(angular.isDate(a))return a;if(angular.isObject(a)){var d=angular.isArray(a)?[]:{};if(c){if(c.indexOf(a)>-1)throw new Error("pascalprecht.translate.$translateSanitization: Error cannot interpolate parameter due recursive object")}else c=[];return c.push(a),angular.forEach(a,function(a,e){angular.isFunction(a)||(d[e]=j(a,b,c))}),c.splice(-1,1),d}return angular.isNumber(a)?a:angular.isUndefined(a)||null===a?a:b(a)}}function c(a,b,c,d){"use strict";var e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u={},v=[],w=a,x=[],y="translate-cloak",z=!1,A=!1,B=".",C=!1,D=!1,E=0,F=!0,G="default",H={default:function(a){return(a||"").split("-").join("_")},java:function(a){var b=(a||"").split("-").join("_"),c=b.split("_");return c.length>1?c[0].toLowerCase()+"_"+c[1].toUpperCase():b},bcp47:function(a){var b=(a||"").split("_").join("-"),c=b.split("-");return c.length>1?c[0].toLowerCase()+"-"+c[1].toUpperCase():b},"iso639-1":function(a){var b=(a||"").split("_").join("-"),c=b.split("-");return c[0].toLowerCase()}},I="2.14.0",J=function(){if(angular.isFunction(d.getLocale))return d.getLocale();var a,c,e=b.$get().navigator,f=["language","browserLanguage","systemLanguage","userLanguage"];if(angular.isArray(e.languages))for(a=0;a<e.languages.length;a++)if(c=e.languages[a],c&&c.length)return c;for(a=0;a<f.length;a++)if(c=e[f[a]],c&&c.length)return c;return null};J.displayName="angular-translate/service: getFirstBrowserLanguage";var K=function(){var a=J()||"";return H[G]&&(a=H[G](a)),a};K.displayName="angular-translate/service: getLocale";var L=function(a,b){for(var c=0,d=a.length;c<d;c++)if(a[c]===b)return c;return-1},M=function(){return this.toString().replace(/^\s+|\s+$/g,"")},N=function(a){if(a){for(var b=[],c=angular.lowercase(a),d=0,e=v.length;d<e;d++)b.push(angular.lowercase(v[d]));if(L(b,c)>-1)return a;if(f){var g;for(var h in f)if(f.hasOwnProperty(h)){var i=!1,j=Object.prototype.hasOwnProperty.call(f,h)&&angular.lowercase(h)===angular.lowercase(a);if("*"===h.slice(-1)&&(i=h.slice(0,-1)===a.slice(0,h.length-1)),(j||i)&&(g=f[h],L(b,angular.lowercase(g))>-1))return g}}var k=a.split("_");return k.length>1&&L(b,angular.lowercase(k[0]))>-1?k[0]:void 0}},O=function(a,b){if(!a&&!b)return u;if(a&&!b){if(angular.isString(a))return u[a]}else angular.isObject(u[a])||(u[a]={}),angular.extend(u[a],P(b));return this};this.translations=O,this.cloakClassName=function(a){return a?(y=a,this):y},this.nestedObjectDelimeter=function(a){return a?(B=a,this):B};var P=function(a,b,c,d){var e,f,g,h;b||(b=[]),c||(c={});for(e in a)Object.prototype.hasOwnProperty.call(a,e)&&(h=a[e],angular.isObject(h)?P(h,b.concat(e),c,e):(f=b.length?""+b.join(B)+B+e:e,b.length&&e===d&&(g=""+b.join(B),c[g]="@:"+f),c[f]=h));return c};P.displayName="flatObject",this.addInterpolation=function(a){return x.push(a),this},this.useMessageFormatInterpolation=function(){return this.useInterpolation("$translateMessageFormatInterpolation")},this.useInterpolation=function(a){return n=a,this},this.useSanitizeValueStrategy=function(a){return c.useStrategy(a),this},this.preferredLanguage=function(a){return a?(Q(a),this):e};var Q=function(a){return a&&(e=a),e};this.translationNotFoundIndicator=function(a){return this.translationNotFoundIndicatorLeft(a),this.translationNotFoundIndicatorRight(a),this},this.translationNotFoundIndicatorLeft=function(a){return a?(q=a,this):q},this.translationNotFoundIndicatorRight=function(a){return a?(r=a,this):r},this.fallbackLanguage=function(a){return R(a),this};var R=function(a){return a?(angular.isString(a)?(h=!0,g=[a]):angular.isArray(a)&&(h=!1,g=a),angular.isString(e)&&L(g,e)<0&&g.push(e),this):h?g[0]:g};this.use=function(a){if(a){if(!u[a]&&!o)throw new Error("$translateProvider couldn't find translationTable for langKey: '"+a+"'");return i=a,this}return i},this.resolveClientLocale=function(){return K()};var S=function(a){return a?(w=a,this):l?l+w:w};this.storageKey=S,this.useUrlLoader=function(a,b){return this.useLoader("$translateUrlLoader",angular.extend({url:a},b))},this.useStaticFilesLoader=function(a){return this.useLoader("$translateStaticFilesLoader",a)},this.useLoader=function(a,b){return o=a,p=b||{},this},this.useLocalStorage=function(){return this.useStorage("$translateLocalStorage")},this.useCookieStorage=function(){return this.useStorage("$translateCookieStorage")},this.useStorage=function(a){return k=a,this},this.storagePrefix=function(a){return a?(l=a,this):a},this.useMissingTranslationHandlerLog=function(){return this.useMissingTranslationHandler("$translateMissingTranslationHandlerLog")},this.useMissingTranslationHandler=function(a){return m=a,this},this.usePostCompiling=function(a){return z=!!a,this},this.forceAsyncReload=function(a){return A=!!a,this},this.uniformLanguageTag=function(a){return a?angular.isString(a)&&(a={standard:a}):a={},G=a.standard,this},this.determinePreferredLanguage=function(a){var b=a&&angular.isFunction(a)?a():K();return e=v.length?N(b)||b:b,this},this.registerAvailableLanguageKeys=function(a,b){return a?(v=a,b&&(f=b),this):v},this.useLoaderCache=function(a){return a===!1?s=void 0:a===!0?s=!0:"undefined"==typeof a?s="$translationCache":a&&(s=a),this},this.directivePriority=function(a){return void 0===a?E:(E=a,this)},this.statefulFilter=function(a){return void 0===a?F:(F=a,this)},this.postProcess=function(a){return t=a?a:void 0,this},this.keepContent=function(a){return D=!!a,this},this.$get=["$log","$injector","$rootScope","$q",function(a,b,c,d){var f,l,G,H=b.get(n||"$translateDefaultInterpolation"),J=!1,T={},U={},V=function(a,b,c,h,j){!i&&e&&(i=e);var m=j&&j!==i?N(j)||j:i;if(j&&ka(j),angular.isArray(a)){var n=function(a){for(var e={},f=[],g=function(a){var f=d.defer(),g=function(b){e[a]=b,f.resolve([a,b])};return V(a,b,c,h,j).then(g,g),f.promise},i=0,k=a.length;i<k;i++)f.push(g(a[i]));return d.all(f).then(function(){return e})};return n(a)}var o=d.defer();a&&(a=M.apply(a));var p=function(){var a=e?U[e]:U[m];if(l=0,k&&!a){var b=f.get(w);if(a=U[b],g&&g.length){var c=L(g,b);l=0===c?1:0,L(g,e)<0&&g.push(e)}}return a}();if(p){var q=function(){j||(m=i),ga(a,b,c,h,m).then(o.resolve,o.reject)};q.displayName="promiseResolved",p.finally(q).catch(angular.noop)}else ga(a,b,c,h,m).then(o.resolve,o.reject);return o.promise},W=function(a){return q&&(a=[q,a].join(" ")),r&&(a=[a,r].join(" ")),a},X=function(a){i=a,k&&f.put(V.storageKey(),i),c.$emit("$translateChangeSuccess",{language:a}),H.setLocale(i);var b=function(a,b){T[b].setLocale(i)};b.displayName="eachInterpolatorLocaleSetter",angular.forEach(T,b),c.$emit("$translateChangeEnd",{language:a})},Y=function(a){if(!a)throw"No language key specified for loading.";var e=d.defer();c.$emit("$translateLoadingStart",{language:a}),J=!0;var f=s;"string"==typeof f&&(f=b.get(f));var g=angular.extend({},p,{key:a,$http:angular.extend({},{cache:f},p.$http)}),h=function(b){var d={};c.$emit("$translateLoadingSuccess",{language:a}),angular.isArray(b)?angular.forEach(b,function(a){angular.extend(d,P(a))}):angular.extend(d,P(b)),J=!1,e.resolve({key:a,table:d}),c.$emit("$translateLoadingEnd",{language:a})};h.displayName="onLoaderSuccess";var i=function(a){c.$emit("$translateLoadingError",{language:a}),e.reject(a),c.$emit("$translateLoadingEnd",{language:a})};return i.displayName="onLoaderError",b.get(o)(g).then(h,i),e.promise};if(k&&(f=b.get(k),!f.get||!f.put))throw new Error("Couldn't use storage '"+k+"', missing get() or put() method!");if(x.length){var Z=function(a){var c=b.get(a);c.setLocale(e||i),T[c.getInterpolationIdentifier()]=c};Z.displayName="interpolationFactoryAdder",angular.forEach(x,Z)}var $=function(a){var b=d.defer();if(Object.prototype.hasOwnProperty.call(u,a))b.resolve(u[a]);else if(U[a]){var c=function(a){O(a.key,a.table),b.resolve(a.table)};c.displayName="translationTableResolver",U[a].then(c,b.reject)}else b.reject();return b.promise},_=function(a,b,c,e,f){var g=d.defer(),h=function(d){if(Object.prototype.hasOwnProperty.call(d,b)&&null!==d[b]){e.setLocale(a);var h=d[b];if("@:"===h.substr(0,2))_(a,h.substr(2),c,e,f).then(g.resolve,g.reject);else{var j=e.interpolate(d[b],c,"service",f,b);j=ja(b,d[b],j,c,a),g.resolve(j)}e.setLocale(i)}else g.reject()};return h.displayName="fallbackTranslationResolver",$(a).then(h,g.reject),g.promise},aa=function(a,b,c,d,e){var f,g=u[a];if(g&&Object.prototype.hasOwnProperty.call(g,b)&&null!==g[b]){if(d.setLocale(a),f=d.interpolate(g[b],c,"filter",e,b),f=ja(b,g[b],f,c,a,e),!angular.isString(f)&&angular.isFunction(f.$$unwrapTrustedValue)){var h=f.$$unwrapTrustedValue();if("@:"===h.substr(0,2))return aa(a,h.substr(2),c,d,e)}else if("@:"===f.substr(0,2))return aa(a,f.substr(2),c,d,e);d.setLocale(i)}return f},ba=function(a,c,d,e){return m?b.get(m)(a,i,c,d,e):a},ca=function(a,b,c,e,f,h){var i=d.defer();if(a<g.length){var j=g[a];_(j,b,c,e,h).then(function(a){i.resolve(a)},function(){return ca(a+1,b,c,e,f,h).then(i.resolve,i.reject)})}else if(f)i.resolve(f);else{var k=ba(b,c,f);m&&k?i.resolve(k):i.reject(W(b))}return i.promise},da=function(a,b,c,d,e){var f;if(a<g.length){var h=g[a];f=aa(h,b,c,d,e),f||""===f||(f=da(a+1,b,c,d))}return f},ea=function(a,b,c,d,e){return ca(G>0?G:l,a,b,c,d,e)},fa=function(a,b,c,d){return da(G>0?G:l,a,b,c,d)},ga=function(a,b,c,e,f,h){var i=d.defer(),j=f?u[f]:u,k=c?T[c]:H;if(j&&Object.prototype.hasOwnProperty.call(j,a)&&null!==j[a]){var l=j[a];if("@:"===l.substr(0,2))V(l.substr(2),b,c,e,f).then(i.resolve,i.reject);else{var n=k.interpolate(l,b,"service",h,a);n=ja(a,l,n,b,f),i.resolve(n)}}else{var o;m&&!J&&(o=ba(a,b,e)),f&&g&&g.length?ea(a,b,k,e,h).then(function(a){i.resolve(a)},function(a){i.reject(W(a))}):m&&!J&&o?e?i.resolve(e):i.resolve(o):e?i.resolve(e):i.reject(W(a))}return i.promise},ha=function(a,b,c,d,e){var f,h=d?u[d]:u,i=H;if(T&&Object.prototype.hasOwnProperty.call(T,c)&&(i=T[c]),h&&Object.prototype.hasOwnProperty.call(h,a)&&null!==h[a]){var j=h[a];"@:"===j.substr(0,2)?f=ha(j.substr(2),b,c,d,e):(f=i.interpolate(j,b,"filter",e,a),f=ja(a,j,f,b,d,e))}else{var k;m&&!J&&(k=ba(a,b,e)),d&&g&&g.length?(l=0,f=fa(a,b,i,e)):f=m&&!J&&k?k:W(a)}return f},ia=function(a){j===a&&(j=void 0),U[a]=void 0},ja=function(a,c,d,e,f,g){var h=t;return h&&("string"==typeof h&&(h=b.get(h)),h)?h(a,c,d,e,f,g):d},ka=function(a){u[a]||!o||U[a]||(U[a]=Y(a).then(function(a){return O(a.key,a.table),a}))};V.preferredLanguage=function(a){return a&&Q(a),e},V.cloakClassName=function(){return y},V.nestedObjectDelimeter=function(){return B},V.fallbackLanguage=function(a){if(void 0!==a&&null!==a){if(R(a),o&&g&&g.length)for(var b=0,c=g.length;b<c;b++)U[g[b]]||(U[g[b]]=Y(g[b]));V.use(V.use())}return h?g[0]:g},V.useFallbackLanguage=function(a){if(void 0!==a&&null!==a)if(a){var b=L(g,a);b>-1&&(G=b)}else G=0},V.proposedLanguage=function(){return j},V.storage=function(){return f},V.negotiateLocale=N,V.use=function(a){if(!a)return i;var b=d.defer();b.promise.then(null,angular.noop),c.$emit("$translateChangeStart",{language:a});var e=N(a);return v.length>0&&!e?d.reject(a):(e&&(a=e),j=a,!A&&u[a]||!o||U[a]?U[a]?U[a].then(function(a){return j===a.key&&X(a.key),b.resolve(a.key),a},function(a){return!i&&g&&g.length>0&&g[0]!==a?V.use(g[0]).then(b.resolve,b.reject):b.reject(a)}):(b.resolve(a),X(a)):(U[a]=Y(a).then(function(c){return O(c.key,c.table),b.resolve(c.key),j===a&&X(c.key),c},function(a){return c.$emit("$translateChangeError",{language:a}),b.reject(a),c.$emit("$translateChangeEnd",{language:a}),d.reject(a)}),U[a].finally(function(){ia(a)}).catch(angular.noop)),b.promise)},V.resolveClientLocale=function(){return K()},V.storageKey=function(){return S()},V.isPostCompilingEnabled=function(){return z},V.isForceAsyncReloadEnabled=function(){return A},V.isKeepContent=function(){return D},V.refresh=function(a){function b(a){var b=Y(a);return U[a]=b,b.then(function(b){u[a]={},O(a,b.table),f[a]=!0},angular.noop),b}if(!o)throw new Error("Couldn't refresh translation table, no loader registered!");c.$emit("$translateRefreshStart",{language:a});var e=d.defer(),f={};if(e.promise.then(function(){for(var a in u)u.hasOwnProperty(a)&&(a in f||delete u[a]);i&&X(i)},angular.noop).finally(function(){c.$emit("$translateRefreshEnd",{language:a})}),a)u[a]?b(a).then(e.resolve,e.reject):e.reject();else{var h=g&&g.slice()||[];i&&h.indexOf(i)===-1&&h.push(i),d.all(h.map(b)).then(e.resolve,e.reject)}return e.promise},V.instant=function(a,b,c,d,f){var h=d&&d!==i?N(d)||d:i;if(null===a||angular.isUndefined(a))return a;if(d&&ka(d),angular.isArray(a)){for(var j={},k=0,l=a.length;k<l;k++)j[a[k]]=V.instant(a[k],b,c,d,f);return j}if(angular.isString(a)&&a.length<1)return a;a&&(a=M.apply(a));var n,o=[];e&&o.push(e),h&&o.push(h),g&&g.length&&(o=o.concat(g));for(var p=0,s=o.length;p<s;p++){var t=o[p];if(u[t]&&"undefined"!=typeof u[t][a]&&(n=ha(a,b,c,h,f)),"undefined"!=typeof n)break}if(!n&&""!==n)if(q||r)n=W(a);else{n=H.interpolate(a,b,"filter",f);var v;m&&!J&&(v=ba(a,b,f)),m&&!J&&v&&(n=v)}return n},V.versionInfo=function(){return I},V.loaderCache=function(){return s},V.directivePriority=function(){return E},V.statefulFilter=function(){return F},V.isReady=function(){return C};var la=d.defer();la.promise.then(function(){C=!0}),V.onReady=function(a){var b=d.defer();return angular.isFunction(a)&&b.promise.then(a),C?b.resolve():la.promise.then(b.resolve),b.promise},V.getAvailableLanguageKeys=function(){return v.length>0?v:null},V.getTranslationTable=function(a){return a=a||V.use(),a&&u[a]?angular.copy(u[a]):null};var ma=c.$on("$translateReady",function(){la.resolve(),ma(),ma=null}),na=c.$on("$translateChangeEnd",function(){la.resolve(),na(),na=null});if(o){if(angular.equals(u,{})&&V.use()&&V.use(V.use()),g&&g.length)for(var oa=function(a){return O(a.key,a.table),c.$emit("$translateChangeEnd",{language:a.key}),a},pa=0,qa=g.length;pa<qa;pa++){var ra=g[pa];!A&&u[ra]||(U[ra]=Y(ra).then(oa))}}else c.$emit("$translateReady",{language:V.use()});return V}]}function d(a,b){"use strict";var c,d={},e="default";return d.setLocale=function(a){c=a},d.getInterpolationIdentifier=function(){return e},d.useSanitizeValueStrategy=function(a){return b.useStrategy(a),this},d.interpolate=function(c,d,e,f){d=d||{},d=b.sanitize(d,"params",f,e);var g;return angular.isNumber(c)?g=""+c:angular.isString(c)?(g=a(c)(d),g=b.sanitize(g,"text",f,e)):g="",g},d}function e(a,b,c,d,e){"use strict";var g=function(){return this.toString().replace(/^\s+|\s+$/g,"")};return{restrict:"AE",scope:!0,priority:a.directivePriority(),compile:function(h,i){var j=i.translateValues?i.translateValues:void 0,k=i.translateInterpolation?i.translateInterpolation:void 0,l=h[0].outerHTML.match(/translate-value-+/i),m="^(.*)("+b.startSymbol()+".*"+b.endSymbol()+")(.*)",n="^(.*)"+b.startSymbol()+"(.*)"+b.endSymbol()+"(.*)";return function(h,o,p){h.interpolateParams={},h.preText="",h.postText="",h.translateNamespace=f(h);var q={},r=function(a,b,c){if(b.translateValues&&angular.extend(a,d(b.translateValues)(h.$parent)),l)for(var e in c)if(Object.prototype.hasOwnProperty.call(b,e)&&"translateValue"===e.substr(0,14)&&"translateValues"!==e){var f=angular.lowercase(e.substr(14,1))+e.substr(15);a[f]=c[e]}},s=function(a){if(angular.isFunction(s._unwatchOld)&&(s._unwatchOld(),s._unwatchOld=void 0),angular.equals(a,"")||!angular.isDefined(a)){var c=g.apply(o.text()),d=c.match(m);if(angular.isArray(d)){h.preText=d[1],h.postText=d[3],q.translate=b(d[2])(h.$parent);var e=c.match(n);angular.isArray(e)&&e[2]&&e[2].length&&(s._unwatchOld=h.$watch(e[2],function(a){q.translate=a,y()}))}else q.translate=c?c:void 0}else q.translate=a;y()},t=function(a){p.$observe(a,function(b){q[a]=b,y()})};r(h.interpolateParams,p,i);var u=!0;p.$observe("translate",function(a){"undefined"==typeof a?s(""):""===a&&u||(q.translate=a,y()),u=!1});for(var v in p)p.hasOwnProperty(v)&&"translateAttr"===v.substr(0,13)&&v.length>13&&t(v);if(p.$observe("translateDefault",function(a){h.defaultText=a,y()}),j&&p.$observe("translateValues",function(a){a&&h.$parent.$watch(function(){angular.extend(h.interpolateParams,d(a)(h.$parent))})}),l){var w=function(a){p.$observe(a,function(b){var c=angular.lowercase(a.substr(14,1))+a.substr(15);h.interpolateParams[c]=b})};for(var x in p)Object.prototype.hasOwnProperty.call(p,x)&&"translateValue"===x.substr(0,14)&&"translateValues"!==x&&w(x)}var y=function(){for(var a in q)q.hasOwnProperty(a)&&void 0!==q[a]&&z(a,q[a],h,h.interpolateParams,h.defaultText,h.translateNamespace)},z=function(b,c,d,e,f,g){c?(g&&"."===c.charAt(0)&&(c=g+c),a(c,e,k,f,d.translateLanguage).then(function(a){A(a,d,!0,b)},function(a){A(a,d,!1,b)})):A(c,d,!1,b)},A=function(b,d,e,f){if(e||"undefined"!=typeof d.defaultText&&(b=d.defaultText),"translate"===f){(e||!e&&!a.isKeepContent()&&"undefined"==typeof p.translateKeepContent)&&o.empty().append(d.preText+b+d.postText);var g=a.isPostCompilingEnabled(),h="undefined"!=typeof i.translateCompile,j=h&&"false"!==i.translateCompile;(g&&!h||j)&&c(o.contents())(d)}else{var k=p.$attr[f];"data-"===k.substr(0,5)&&(k=k.substr(5)),k=k.substr(15),o.attr(k,b)}};(j||l||p.translateDefault)&&h.$watch("interpolateParams",y,!0),h.$on("translateLanguageChanged",y);var B=e.$on("$translateChangeSuccess",y);o.text().length?s(p.translate?p.translate:""):p.translate&&s(p.translate),y(),h.$on("$destroy",B)}}}}function f(a){"use strict";return a.translateNamespace?a.translateNamespace:a.$parent?f(a.$parent):void 0}function g(a,b){"use strict";return{restrict:"A",priority:a.directivePriority(),link:function(c,d,e){var f,g,i={},j=function(){angular.forEach(f,function(b,f){b&&(i[f]=!0,c.translateNamespace&&"."===b.charAt(0)&&(b=c.translateNamespace+b),a(b,g,e.translateInterpolation,void 0,c.translateLanguage).then(function(a){d.attr(f,a)},function(a){d.attr(f,a)}))}),angular.forEach(i,function(a,b){f[b]||(d.removeAttr(b),delete i[b])})};h(c,e.translateAttr,function(a){f=a},j),h(c,e.translateValues,function(a){g=a},j),e.translateValues&&c.$watch(e.translateValues,j,!0),c.$on("translateLanguageChanged",j);var k=b.$on("$translateChangeSuccess",j);j(),c.$on("$destroy",k)}}}function h(a,b,c,d){"use strict";b&&("::"===b.substr(0,2)?b=b.substr(2):a.$watch(b,function(a){c(a),d()},!0),c(a.$eval(b)))}function i(a){"use strict";return{compile:function(b){var c=function(b){b.addClass(a.cloakClassName())},d=function(b){b.removeClass(a.cloakClassName())};return c(b),function(b,e,f){var g=d.bind(this,e),h=c.bind(this,e);f.translateCloak&&f.translateCloak.length?f.$observe("translateCloak",function(b){a(b).then(g,h)}):a.onReady(g)}}}}function j(){"use strict";return{restrict:"A",scope:!0,compile:function(){return{pre:function(a,b,c){a.translateNamespace=f(a),a.translateNamespace&&"."===c.translateNamespace.charAt(0)?a.translateNamespace+=c.translateNamespace:a.translateNamespace=c.translateNamespace}}}}}function f(a){"use strict";return a.translateNamespace?a.translateNamespace:a.$parent?f(a.$parent):void 0}function k(){"use strict";return{restrict:"A",scope:!0,compile:function(){return function(a,b,c){c.$observe("translateLanguage",function(b){a.translateLanguage=b}),a.$watch("translateLanguage",function(){a.$broadcast("translateLanguageChanged")})}}}}function l(a,b){"use strict";var c=function(c,d,e,f){return angular.isObject(d)||(d=a(d)(this)),b.instant(c,d,e,f)};return b.statefulFilter()&&(c.$stateful=!0),c}function m(a){"use strict";return a("translations")}return a.$inject=["$translate"],c.$inject=["$STORAGE_KEY","$windowProvider","$translateSanitizationProvider","pascalprechtTranslateOverrider"],d.$inject=["$interpolate","$translateSanitization"],e.$inject=["$translate","$interpolate","$compile","$parse","$rootScope"],g.$inject=["$translate","$rootScope"],i.$inject=["$translate"],l.$inject=["$parse","$translate"],m.$inject=["$cacheFactory"],angular.module("pascalprecht.translate",["ng"]).run(a),a.displayName="runTranslate",angular.module("pascalprecht.translate").provider("$translateSanitization",b),angular.module("pascalprecht.translate").constant("pascalprechtTranslateOverrider",{}).provider("$translate",c),c.displayName="displayName",angular.module("pascalprecht.translate").factory("$translateDefaultInterpolation",d),d.displayName="$translateDefaultInterpolation",angular.module("pascalprecht.translate").constant("$STORAGE_KEY","NG_TRANSLATE_LANG_KEY"),angular.module("pascalprecht.translate").directive("translate",e),e.displayName="translateDirective",angular.module("pascalprecht.translate").directive("translateAttr",g),g.displayName="translateAttrDirective",angular.module("pascalprecht.translate").directive("translateCloak",i),i.displayName="translateCloakDirective",angular.module("pascalprecht.translate").directive("translateNamespace",j),j.displayName="translateNamespaceDirective",angular.module("pascalprecht.translate").directive("translateLanguage",k),k.displayName="translateLanguageDirective",angular.module("pascalprecht.translate").filter("translate",l),l.displayName="translateFilterFactory",angular.module("pascalprecht.translate").factory("$translationCache",m),m.displayName="$translationCache","pascalprecht.translate"}); \ No newline at end of file
diff --git a/vnfmarket/common/thirdparty/angular-translate/bower.json b/vnfmarket/common/thirdparty/angular-translate/bower.json
new file mode 100644
index 00000000..e92aae6a
--- /dev/null
+++ b/vnfmarket/common/thirdparty/angular-translate/bower.json
@@ -0,0 +1,12 @@
+{
+ "name": "angular-translate",
+ "description": "A translation module for AngularJS",
+ "version": "2.14.0",
+ "main": "./angular-translate.js",
+ "ignore": [],
+ "author": "Pascal Precht",
+ "license": "MIT",
+ "dependencies": {
+ "angular": ">=1.2.26 <1.7"
+ }
+}