zettapi_client
Version:
Client side CRUD operations in angular to use with zettapi_server rest api to get started quickly in any CMS project
1,527 lines (1,406 loc) • 127 kB
JavaScript
/*!
* angular-translate - v2.13.0 - 2016-10-30
*
* Copyright (c) 2016 The angular-translate team, Pascal Precht; Licensed MIT
*/
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module unless amdModuleId is set
define([], function () {
return (factory());
});
} else if (typeof exports === 'object') {
// Node. Does not work with strict CommonJS, but
// only CommonJS-like environments that support module.exports,
// like Node.
module.exports = factory();
} else {
factory();
}
}(this, function () {
/**
* @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', '$rootScope'];
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 {
return iteratee(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.13.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