Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
Loading items

Target

Select target project
  • to/keycloak-theme-pirati
  • marek.krejpsky/keycloak-theme-pirati
2 results
Select Git revision
  • 3.4.1
  • master
  • v11
3 results
Show changes
Showing
with 0 additions and 5150 deletions
/*!
* angular-translate - v2.18.2 - 2020-01-04
*
* Copyright (c) 2020 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 module === 'object' && module.exports) {
// Node. Does not work with strict CommonJS, but
// only CommonJS-like environments that support module.exports,
// like Node.
module.exports = factory();
} else {
factory();
}
}(this, function () {
angular.module('pascalprecht.translate')
/**
* @ngdoc object
* @name pascalprecht.translate.$translatePartialLoaderProvider
*
* @description
* By using a $translatePartialLoaderProvider you can configure a list of a needed
* translation parts directly during the configuration phase of your application's
* lifetime. All parts you add by using this provider would be loaded by
* angular-translate at the startup as soon as possible.
*/
.provider('$translatePartialLoader', $translatePartialLoader);
function $translatePartialLoader() {
'use strict';
/**
* @constructor
* @name Part
*
* @description
* Represents Part object to add and set parts at runtime.
*/
function Part(name, priority, urlTemplate) {
this.name = name;
this.isActive = true;
this.tables = {};
this.priority = priority || 0;
this.langPromises = {};
this.urlTemplate = urlTemplate;
}
/**
* @name parseUrl
* @method
*
* @description
* Returns a parsed url template string and replaces given target lang
* and part name it.
*
* @param {string|function} urlTemplate - Either a string containing an url pattern (with
* '{part}' and '{lang}') or a function(part, lang)
* returning a string.
* @param {string} targetLang - Language key for language to be used.
* @return {string} Parsed url template string
*/
Part.prototype.parseUrl = function (urlTemplate, targetLang) {
if (angular.isFunction(urlTemplate)) {
return urlTemplate(this.name, targetLang);
}
return urlTemplate.replace(/\{part\}/g, this.name).replace(/\{lang\}/g, targetLang);
};
Part.prototype.getTable = function (lang, $q, $http, $httpOptions, urlTemplate, errorHandler) {
//locals
var self = this;
var lastLangPromise = this.langPromises[lang];
var deferred = $q.defer();
//private helper helpers
var fetchData = function () {
return $http(
angular.extend({
method : 'GET',
url : self.parseUrl(self.urlTemplate || urlTemplate, lang)
},
$httpOptions)
);
};
//private helper
var handleNewData = function (data) {
self.tables[lang] = data;
deferred.resolve(data);
};
//private helper
var rejectDeferredWithPartName = function () {
deferred.reject(self.name);
};
//private helper
var tryGettingThisTable = function () {
//data fetching logic
fetchData().then(
function (result) {
handleNewData(result.data);
},
function (errorResponse) {
if (errorHandler) {
errorHandler(self.name, lang, errorResponse).then(handleNewData, rejectDeferredWithPartName);
} else {
rejectDeferredWithPartName();
}
});
};
//loading logic
if (!this.tables[lang]) {
//let's try loading the data
if (!lastLangPromise) {
//this is the first request - just go ahead and hit the server
tryGettingThisTable();
} else {
//this is an additional request after one or more unfinished or failed requests
//chain the deferred off the previous request's promise so that this request conditionally executes
//if the previous request succeeds then the result will be passed through, but if it fails then this request will try again and hit the server
lastLangPromise.then(deferred.resolve, tryGettingThisTable);
}
//retain a reference to the last promise so we can continue the chain if another request is made before any succeed
//you can picture the promise chain as a singly-linked list (formed by the .then handler queues) that's traversed by the execution context
this.langPromises[lang] = deferred.promise;
}
else {
//the part has already been loaded - if lastLangPromise is also undefined then the table has been populated using setPart
//this breaks the promise chain because we're not tying langDeferred's outcome to a previous call's promise handler queues, but we don't care because there's no asynchronous execution context to keep track of anymore
deferred.resolve(this.tables[lang]);
}
return deferred.promise;
};
var parts = {};
function hasPart(name) {
return Object.prototype.hasOwnProperty.call(parts, name);
}
function isStringValid(str) {
return angular.isString(str) && str !== '';
}
function isPartAvailable(name) {
if (!isStringValid(name)) {
throw new TypeError('Invalid type of a first argument, a non-empty string expected.');
}
return (hasPart(name) && parts[name].isActive);
}
function deepExtend(dst, src) {
for (var property in src) {
if (src[property] && src[property].constructor &&
src[property].constructor === Object) {
dst[property] = dst[property] || {};
deepExtend(dst[property], src[property]);
} else {
dst[property] = src[property];
}
}
return dst;
}
function getPrioritizedParts() {
var prioritizedParts = [];
for (var part in parts) {
if (parts[part].isActive) {
prioritizedParts.push(parts[part]);
}
}
prioritizedParts.sort(function (a, b) {
return a.priority - b.priority;
});
return prioritizedParts;
}
/**
* @ngdoc function
* @name pascalprecht.translate.$translatePartialLoaderProvider#addPart
* @methodOf pascalprecht.translate.$translatePartialLoaderProvider
*
* @description
* Registers a new part of the translation table to be loaded once the
* `angular-translate` gets into runtime phase. It does not actually load any
* translation data, but only registers a part to be loaded in the future.
*
* @param {string} name A name of the part to add
* @param {int} [priority=0] Sets the load priority of this part.
* @param {string|function} urlTemplate Either a string containing an url pattern (with
* '{part}' and '{lang}') or a function(part, lang)
* returning a string.
*
* @returns {object} $translatePartialLoaderProvider, so this method is chainable
* @throws {TypeError} The method could throw a **TypeError** if you pass the param
* of the wrong type. Please, note that the `name` param has to be a
* non-empty **string**.
*/
this.addPart = function (name, priority, urlTemplate) {
if (!isStringValid(name)) {
throw new TypeError('Couldn\'t add part, part name has to be a string!');
}
if (!hasPart(name)) {
parts[name] = new Part(name, priority, urlTemplate);
}
parts[name].isActive = true;
return this;
};
/**
* @ngdocs function
* @name pascalprecht.translate.$translatePartialLoaderProvider#setPart
* @methodOf pascalprecht.translate.$translatePartialLoaderProvider
*
* @description
* Sets a translation table to the specified part. This method does not make the
* specified part available, but only avoids loading this part from the server.
*
* @param {string} lang A language of the given translation table
* @param {string} part A name of the target part
* @param {object} table A translation table to set to the specified part
*
* @return {object} $translatePartialLoaderProvider, so this method is chainable
* @throws {TypeError} The method could throw a **TypeError** if you pass params
* of the wrong type. Please, note that the `lang` and `part` params have to be a
* non-empty **string**s and the `table` param has to be an object.
*/
this.setPart = function (lang, part, table) {
if (!isStringValid(lang)) {
throw new TypeError('Couldn\'t set part.`lang` parameter has to be a string!');
}
if (!isStringValid(part)) {
throw new TypeError('Couldn\'t set part.`part` parameter has to be a string!');
}
if (typeof table !== 'object' || table === null) {
throw new TypeError('Couldn\'t set part. `table` parameter has to be an object!');
}
if (!hasPart(part)) {
parts[part] = new Part(part);
parts[part].isActive = false;
}
parts[part].tables[lang] = table;
return this;
};
/**
* @ngdoc function
* @name pascalprecht.translate.$translatePartialLoaderProvider#deletePart
* @methodOf pascalprecht.translate.$translatePartialLoaderProvider
*
* @description
* Removes the previously added part of the translation data. So, `angular-translate` will not
* load it at the startup.
*
* @param {string} name A name of the part to delete
*
* @returns {object} $translatePartialLoaderProvider, so this method is chainable
*
* @throws {TypeError} The method could throw a **TypeError** if you pass the param of the wrong
* type. Please, note that the `name` param has to be a non-empty **string**.
*/
this.deletePart = function (name) {
if (!isStringValid(name)) {
throw new TypeError('Couldn\'t delete part, first arg has to be string.');
}
if (hasPart(name)) {
parts[name].isActive = false;
}
return this;
};
/**
* @ngdoc function
* @name pascalprecht.translate.$translatePartialLoaderProvider#isPartAvailable
* @methodOf pascalprecht.translate.$translatePartialLoaderProvider
*
* @description
* Checks if the specific part is available. A part becomes available after it was added by the
* `addPart` method. Available parts would be loaded from the server once the `angular-translate`
* asks the loader to that.
*
* @param {string} name A name of the part to check
*
* @returns {boolean} Returns **true** if the part is available now and **false** if not.
*
* @throws {TypeError} The method could throw a **TypeError** if you pass the param of the wrong
* type. Please, note that the `name` param has to be a non-empty **string**.
*/
this.isPartAvailable = isPartAvailable;
/**
* @ngdoc object
* @name pascalprecht.translate.$translatePartialLoader
*
* @requires $q
* @requires $http
* @requires $injector
* @requires $rootScope
* @requires $translate
*
* @description
*
* @param {object} options Options object
*
* @throws {TypeError}
*/
this.$get = ['$rootScope', '$injector', '$q', '$http', '$log',
function ($rootScope, $injector, $q, $http, $log) {
/**
* @ngdoc event
* @name pascalprecht.translate.$translatePartialLoader#$translatePartialLoaderStructureChanged
* @eventOf pascalprecht.translate.$translatePartialLoader
* @eventType broadcast on root scope
*
* @description
* A $translatePartialLoaderStructureChanged event is called when a state of the loader was
* changed somehow. It could mean either some part is added or some part is deleted. Anyway when
* you get this event the translation table is not longer current and has to be updated.
*
* @param {string} name A name of the part which is a reason why the event was fired
*/
var service = function (options) {
if (!isStringValid(options.key)) {
throw new TypeError('Unable to load data, a key is not a non-empty string.');
}
if (!isStringValid(options.urlTemplate) && !angular.isFunction(options.urlTemplate)) {
throw new TypeError('Unable to load data, a urlTemplate is not a non-empty string or not a function.');
}
var errorHandler = options.loadFailureHandler;
if (errorHandler !== undefined) {
if (!angular.isString(errorHandler)) {
throw new Error('Unable to load data, a loadFailureHandler is not a string.');
} else {
errorHandler = $injector.get(errorHandler);
}
}
var loaders = [],
prioritizedParts = getPrioritizedParts();
angular.forEach(prioritizedParts, function (part) {
loaders.push(
part.getTable(options.key, $q, $http, options.$http, options.urlTemplate, errorHandler)
);
part.urlTemplate = part.urlTemplate || options.urlTemplate;
});
// workaround for #1781
var structureHasBeenChangedWhileLoading = false;
var dirtyCheckEventCloser = $rootScope.$on('$translatePartialLoaderStructureChanged', function () {
structureHasBeenChangedWhileLoading = true;
});
return $q.all(loaders)
.then(function () {
dirtyCheckEventCloser();
if (structureHasBeenChangedWhileLoading) {
if (!options.__retries) {
// the part structure has been changed while loading (the origin ones)
// this can happen if an addPart/removePart has been invoked right after a $translate.use(lang)
// TODO maybe we can optimize this with the actual list of missing parts
options.__retries = (options.__retries || 0) + 1;
return service(options);
} else {
// the part structure has been changed again while loading (retried one)
// because this could an infinite loop, this will not load another one again
$log.warn('The partial loader has detected a multiple structure change (with addPort/removePart) ' +
'while loading translations. You should consider using promises of $translate.use(lang) and ' +
'$translate.refresh(). Also parts should be added/removed right before an explicit refresh ' +
'if possible.');
}
}
var table = {};
prioritizedParts = getPrioritizedParts();
angular.forEach(prioritizedParts, function (part) {
deepExtend(table, part.tables[options.key]);
});
return table;
}, function () {
dirtyCheckEventCloser();
return $q.reject(options.key);
});
};
/**
* @ngdoc function
* @name pascalprecht.translate.$translatePartialLoader#addPart
* @methodOf pascalprecht.translate.$translatePartialLoader
*
* @description
* Registers a new part of the translation table. This method does not actually perform any xhr
* requests to get translation data. The new parts will be loaded in order of priority from the server next time
* `angular-translate` asks the loader to load translations.
*
* @param {string} name A name of the part to add
* @param {int} [priority=0] Sets the load priority of this part.
*
* @returns {object} $translatePartialLoader, so this method is chainable
*
* @fires {$translatePartialLoaderStructureChanged} The $translatePartialLoaderStructureChanged
* event would be fired by this method in case the new part affected somehow on the loaders
* state. This way it means that there are a new translation data available to be loaded from
* the server.
*
* @throws {TypeError} The method could throw a **TypeError** if you pass the param of the wrong
* type. Please, note that the `name` param has to be a non-empty **string**.
*/
service.addPart = function (name, priority, urlTemplate) {
if (!isStringValid(name)) {
throw new TypeError('Couldn\'t add part, first arg has to be a string');
}
if (!hasPart(name)) {
parts[name] = new Part(name, priority, urlTemplate);
$rootScope.$emit('$translatePartialLoaderStructureChanged', name);
} else if (!parts[name].isActive) {
parts[name].isActive = true;
$rootScope.$emit('$translatePartialLoaderStructureChanged', name);
}
return service;
};
/**
* @ngdoc function
* @name pascalprecht.translate.$translatePartialLoader#deletePart
* @methodOf pascalprecht.translate.$translatePartialLoader
*
* @description
* Deletes the previously added part of the translation data. The target part could be deleted
* either logically or physically. When the data is deleted logically it is not actually deleted
* from the browser, but the loader marks it as not active and prevents it from affecting on the
* translations. If the deleted in such way part is added again, the loader will use the
* previously loaded data rather than loading it from the server once more time. But if the data
* is deleted physically, the loader will completely remove all information about it. So in case
* of recycling this part will be loaded from the server again.
*
* @param {string} name A name of the part to delete
* @param {boolean=} [removeData=false] An indicator if the loader has to remove a loaded
* translation data physically. If the `removeData` if set to **false** the loaded data will not be
* deleted physically and might be reused in the future to prevent an additional xhr requests.
*
* @returns {object} $translatePartialLoader, so this method is chainable
*
* @fires {$translatePartialLoaderStructureChanged} The $translatePartialLoaderStructureChanged
* event would be fired by this method in case a part deletion process affects somehow on the
* loaders state. This way it means that some part of the translation data is now deprecated and
* the translation table has to be recompiled with the remaining translation parts.
*
* @throws {TypeError} The method could throw a **TypeError** if you pass some param of the
* wrong type. Please, note that the `name` param has to be a non-empty **string** and
* the `removeData` param has to be either **undefined** or **boolean**.
*/
service.deletePart = function (name, removeData) {
if (!isStringValid(name)) {
throw new TypeError('Couldn\'t delete part, first arg has to be string');
}
if (removeData === undefined) {
removeData = false;
} else if (typeof removeData !== 'boolean') {
throw new TypeError('Invalid type of a second argument, a boolean expected.');
}
if (hasPart(name)) {
var wasActive = parts[name].isActive;
if (removeData) {
var $translate = $injector.get('$translate');
var cache = $translate.loaderCache();
if (typeof(cache) === 'string') {
// getting on-demand instance of loader
cache = $injector.get(cache);
}
// Purging items from cache...
if (typeof(cache) === 'object') {
angular.forEach(parts[name].tables, function (value, key) {
cache.remove(parts[name].parseUrl(parts[name].urlTemplate, key));
});
}
delete parts[name];
} else {
parts[name].isActive = false;
}
if (wasActive) {
$rootScope.$emit('$translatePartialLoaderStructureChanged', name);
}
}
return service;
};
/**
* @ngdoc function
* @name pascalprecht.translate.$translatePartialLoader#isPartLoaded
* @methodOf pascalprecht.translate.$translatePartialLoader
*
* @description
* Checks if the registered translation part is loaded into the translation table.
*
* @param {string} name A name of the part
* @param {string} lang A key of the language
*
* @returns {boolean} Returns **true** if the translation of the part is loaded to the translation table and **false** if not.
*
* @throws {TypeError} The method could throw a **TypeError** if you pass the param of the wrong
* type. Please, note that the `name` and `lang` params have to be non-empty **string**.
*/
service.isPartLoaded = function (name, lang) {
return angular.isDefined(parts[name]) && angular.isDefined(parts[name].tables[lang]);
};
/**
* @ngdoc function
* @name pascalprecht.translate.$translatePartialLoader#getRegisteredParts
* @methodOf pascalprecht.translate.$translatePartialLoader
*
* @description
* Gets names of the parts that were added with the `addPart`.
*
* @returns {array} Returns array of registered parts, if none were registered then an empty array is returned.
*/
service.getRegisteredParts = function () {
var registeredParts = [];
angular.forEach(parts, function (p) {
if (p.isActive) {
registeredParts.push(p.name);
}
});
return registeredParts;
};
/**
* @ngdoc function
* @name pascalprecht.translate.$translatePartialLoader#isPartAvailable
* @methodOf pascalprecht.translate.$translatePartialLoader
*
* @description
* Checks if a target translation part is available. The part becomes available just after it was
* added by the `addPart` method. Part's availability does not mean that it was loaded from the
* server, but only that it was added to the loader. The available part might be loaded next
* time the loader is called.
*
* @param {string} name A name of the part to delete
*
* @returns {boolean} Returns **true** if the part is available now and **false** if not.
*
* @throws {TypeError} The method could throw a **TypeError** if you pass the param of the wrong
* type. Please, note that the `name` param has to be a non-empty **string**.
*/
service.isPartAvailable = isPartAvailable;
return service;
}];
}
$translatePartialLoader.displayName = '$translatePartialLoader';
return 'pascalprecht.translate';
}));
/*!
* angular-translate - v2.18.2 - 2020-01-04
*
* Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT
*/
!function(t,e){"function"==typeof define&&define.amd?define([],function(){return e()}):"object"==typeof module&&module.exports?module.exports=e():e()}(0,function(){function t(){"use strict";function a(t,e,r){this.name=t,this.isActive=!0,this.tables={},this.priority=e||0,this.langPromises={},this.urlTemplate=r}a.prototype.parseUrl=function(t,e){return angular.isFunction(t)?t(this.name,e):t.replace(/\{part\}/g,this.name).replace(/\{lang\}/g,e)},a.prototype.getTable=function(e,t,r,a,n,i){var o=this,s=this.langPromises[e],l=t.defer(),u=function(t){o.tables[e]=t,l.resolve(t)},c=function(){l.reject(o.name)},p=function(){r(angular.extend({method:"GET",url:o.parseUrl(o.urlTemplate||n,e)},a)).then(function(t){u(t.data)},function(t){i?i(o.name,e,t).then(u,c):c()})};return this.tables[e]?l.resolve(this.tables[e]):(s?s.then(l.resolve,p):p(),this.langPromises[e]=l.promise),l.promise};var n={};function i(t){return Object.prototype.hasOwnProperty.call(n,t)}function f(t){return angular.isString(t)&&""!==t}function t(t){if(!f(t))throw new TypeError("Invalid type of a first argument, a non-empty string expected.");return i(t)&&n[t].isActive}function d(){var t=[];for(var e in n)n[e].isActive&&t.push(n[e]);return t.sort(function(t,e){return t.priority-e.priority}),t}this.addPart=function(t,e,r){if(!f(t))throw new TypeError("Couldn't add part, part name has to be a string!");return i(t)||(n[t]=new a(t,e,r)),n[t].isActive=!0,this},this.setPart=function(t,e,r){if(!f(t))throw new TypeError("Couldn't set part.`lang` parameter has to be a string!");if(!f(e))throw new TypeError("Couldn't set part.`part` parameter has to be a string!");if("object"!=typeof r||null===r)throw new TypeError("Couldn't set part. `table` parameter has to be an object!");return i(e)||(n[e]=new a(e),n[e].isActive=!1),n[e].tables[t]=r,this},this.deletePart=function(t){if(!f(t))throw new TypeError("Couldn't delete part, first arg has to be string.");return i(t)&&(n[t].isActive=!1),this},this.isPartAvailable=t,this.$get=["$rootScope","$injector","$q","$http","$log",function(o,s,l,u,c){var p=function(r){if(!f(r.key))throw new TypeError("Unable to load data, a key is not a non-empty string.");if(!f(r.urlTemplate)&&!angular.isFunction(r.urlTemplate))throw new TypeError("Unable to load data, a urlTemplate is not a non-empty string or not a function.");var e=r.loadFailureHandler;if(void 0!==e){if(!angular.isString(e))throw new Error("Unable to load data, a loadFailureHandler is not a string.");e=s.get(e)}var a=[],t=d();angular.forEach(t,function(t){a.push(t.getTable(r.key,l,u,r.$http,r.urlTemplate,e)),t.urlTemplate=t.urlTemplate||r.urlTemplate});var n=!1,i=o.$on("$translatePartialLoaderStructureChanged",function(){n=!0});return l.all(a).then(function(){if(i(),n){if(!r.__retries)return r.__retries=(r.__retries||0)+1,p(r);c.warn("The partial loader has detected a multiple structure change (with addPort/removePart) while loading translations. You should consider using promises of $translate.use(lang) and $translate.refresh(). Also parts should be added/removed right before an explicit refresh if possible.")}var e={};return t=d(),angular.forEach(t,function(t){!function t(e,r){for(var a in r)r[a]&&r[a].constructor&&r[a].constructor===Object?(e[a]=e[a]||{},t(e[a],r[a])):e[a]=r[a];return e}(e,t.tables[r.key])}),e},function(){return i(),l.reject(r.key)})};return p.addPart=function(t,e,r){if(!f(t))throw new TypeError("Couldn't add part, first arg has to be a string");return i(t)?n[t].isActive||(n[t].isActive=!0,o.$emit("$translatePartialLoaderStructureChanged",t)):(n[t]=new a(t,e,r),o.$emit("$translatePartialLoaderStructureChanged",t)),p},p.deletePart=function(r,t){if(!f(r))throw new TypeError("Couldn't delete part, first arg has to be string");if(void 0===t)t=!1;else if("boolean"!=typeof t)throw new TypeError("Invalid type of a second argument, a boolean expected.");if(i(r)){var e=n[r].isActive;if(t){var a=s.get("$translate").loaderCache();"string"==typeof a&&(a=s.get(a)),"object"==typeof a&&angular.forEach(n[r].tables,function(t,e){a.remove(n[r].parseUrl(n[r].urlTemplate,e))}),delete n[r]}else n[r].isActive=!1;e&&o.$emit("$translatePartialLoaderStructureChanged",r)}return p},p.isPartLoaded=function(t,e){return angular.isDefined(n[t])&&angular.isDefined(n[t].tables[e])},p.getRegisteredParts=function(){var e=[];return angular.forEach(n,function(t){t.isActive&&e.push(t.name)}),e},p.isPartAvailable=t,p}]}return angular.module("pascalprecht.translate").provider("$translatePartialLoader",t),t.displayName="$translatePartialLoader","pascalprecht.translate"});
\ No newline at end of file
/*!
* angular-translate - v2.18.2 - 2020-01-04
*
* Copyright (c) 2020 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 module === 'object' && module.exports) {
// 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 () {
$translateStaticFilesLoader.$inject = ['$q', '$http'];
angular.module('pascalprecht.translate')
/**
* @ngdoc object
* @name pascalprecht.translate.$translateStaticFilesLoader
* @requires $q
* @requires $http
*
* @description
* Creates a loading function for a typical static file url pattern:
* "lang-en_US.json", "lang-de_DE.json", etc. Using this builder,
* the response of these urls must be an object of key-value pairs.
*
* @param {object} options Options object, which gets prefix, suffix, key, and fileMap
*/
.factory('$translateStaticFilesLoader', $translateStaticFilesLoader);
function $translateStaticFilesLoader($q, $http) {
'use strict';
return function (options) {
if (!options || (!angular.isArray(options.files) && (!angular.isString(options.prefix) || !angular.isString(options.suffix)))) {
throw new Error('Couldn\'t load static files, no files and prefix or suffix specified!');
}
if (!options.files) {
options.files = [{
prefix: options.prefix,
suffix: options.suffix
}];
}
var load = function (file) {
if (!file || (!angular.isString(file.prefix) || !angular.isString(file.suffix))) {
throw new Error('Couldn\'t load static file, no prefix or suffix specified!');
}
var fileUrl = [
file.prefix,
options.key,
file.suffix
].join('');
if (angular.isObject(options.fileMap) && options.fileMap[fileUrl]) {
fileUrl = options.fileMap[fileUrl];
}
return $http(angular.extend({
url: fileUrl,
method: 'GET'
}, options.$http))
.then(function(result) {
return result.data;
}, function () {
return $q.reject(options.key);
});
};
var promises = [],
length = options.files.length;
for (var i = 0; i < length; i++) {
promises.push(load({
prefix: options.files[i].prefix,
key: options.key,
suffix: options.files[i].suffix
}));
}
return $q.all(promises)
.then(function (data) {
var length = data.length,
mergedData = {};
for (var i = 0; i < length; i++) {
for (var key in data[i]) {
mergedData[key] = data[i][key];
}
}
return mergedData;
});
};
}
$translateStaticFilesLoader.displayName = '$translateStaticFilesLoader';
return 'pascalprecht.translate';
}));
/*!
* angular-translate - v2.18.2 - 2020-01-04
*
* Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT
*/
!function(e,i){"function"==typeof define&&define.amd?define([],function(){return i()}):"object"==typeof module&&module.exports?module.exports=i():i()}(0,function(){function e(n,a){"use strict";return function(r){if(!(r&&(angular.isArray(r.files)||angular.isString(r.prefix)&&angular.isString(r.suffix))))throw new Error("Couldn't load static files, no files and prefix or suffix specified!");r.files||(r.files=[{prefix:r.prefix,suffix:r.suffix}]);for(var e=function(e){if(!e||!angular.isString(e.prefix)||!angular.isString(e.suffix))throw new Error("Couldn't load static file, no prefix or suffix specified!");var i=[e.prefix,r.key,e.suffix].join("");return angular.isObject(r.fileMap)&&r.fileMap[i]&&(i=r.fileMap[i]),a(angular.extend({url:i,method:"GET"},r.$http)).then(function(e){return e.data},function(){return n.reject(r.key)})},i=[],t=r.files.length,f=0;f<t;f++)i.push(e({prefix:r.files[f].prefix,key:r.key,suffix:r.files[f].suffix}));return n.all(i).then(function(e){for(var i=e.length,r={},t=0;t<i;t++)for(var f in e[t])r[f]=e[t][f];return r})}}return e.$inject=["$q","$http"],angular.module("pascalprecht.translate").factory("$translateStaticFilesLoader",e),e.displayName="$translateStaticFilesLoader","pascalprecht.translate"});
\ No newline at end of file
/*!
* angular-translate - v2.18.2 - 2020-01-04
*
* Copyright (c) 2020 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 module === 'object' && module.exports) {
// 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 () {
$translateUrlLoader.$inject = ['$q', '$http'];
angular.module('pascalprecht.translate')
/**
* @ngdoc object
* @name pascalprecht.translate.$translateUrlLoader
* @requires $q
* @requires $http
*
* @description
* Creates a loading function for a typical dynamic url pattern:
* "locale.php?lang=en_US", "locale.php?lang=de_DE", "locale.php?language=nl_NL" etc.
* Prefixing the specified url, the current requested, language id will be applied
* with "?{queryParameter}={key}".
* Using this service, the response of these urls must be an object of
* key-value pairs.
*
* @param {object} options Options object, which gets the url, key and
* optional queryParameter ('lang' is used by default).
*/
.factory('$translateUrlLoader', $translateUrlLoader);
function $translateUrlLoader($q, $http) {
'use strict';
return function (options) {
if (!options || !options.url) {
throw new Error('Couldn\'t use urlLoader since no url is given!');
}
var requestParams = {};
requestParams[options.queryParameter || 'lang'] = options.key;
return $http(angular.extend({
url: options.url,
params: requestParams,
method: 'GET'
}, options.$http))
.then(function(result) {
return result.data;
}, function () {
return $q.reject(options.key);
});
};
}
$translateUrlLoader.displayName = '$translateUrlLoader';
return 'pascalprecht.translate';
}));
/*!
* angular-translate - v2.18.2 - 2020-01-04
*
* Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT
*/
!function(e,t){"function"==typeof define&&define.amd?define([],function(){return t()}):"object"==typeof module&&module.exports?module.exports=t():t()}(0,function(){function e(r,n){"use strict";return function(e){if(!e||!e.url)throw new Error("Couldn't use urlLoader since no url is given!");var t={};return t[e.queryParameter||"lang"]=e.key,n(angular.extend({url:e.url,params:t,method:"GET"},e.$http)).then(function(e){return e.data},function(){return r.reject(e.key)})}}return e.$inject=["$q","$http"],angular.module("pascalprecht.translate").factory("$translateUrlLoader",e),e.displayName="$translateUrlLoader","pascalprecht.translate"});
\ No newline at end of file
/*!
* angular-translate - v2.18.2 - 2020-01-04
*
* Copyright (c) 2020 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 module === 'object' && module.exports) {
// 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 () {
$translateCookieStorageFactory.$inject = ['$injector'];
angular.module('pascalprecht.translate')
/**
* @ngdoc object
* @name pascalprecht.translate.$translateCookieStorage
* @requires $cookieStore
*
* @description
* Abstraction layer for cookieStore. This service is used when telling angular-translate
* to use cookieStore as storage.
*
*/
.factory('$translateCookieStorage', $translateCookieStorageFactory);
function $translateCookieStorageFactory($injector) {
'use strict';
// Since AngularJS 1.4, $cookieStore is deprecated
var delegate;
if (angular.version.major === 1 && angular.version.minor >= 4) {
var $cookies = $injector.get('$cookies');
delegate = {
get : function (key) {
return $cookies.get(key);
},
put : function (key, value) {
$cookies.put(key, value);
}
};
} else {
var $cookieStore = $injector.get('$cookieStore');
delegate = {
get : function (key) {
return $cookieStore.get(key);
},
put : function (key, value) {
$cookieStore.put(key, value);
}
};
}
var $translateCookieStorage = {
/**
* @ngdoc function
* @name pascalprecht.translate.$translateCookieStorage#get
* @methodOf pascalprecht.translate.$translateCookieStorage
*
* @description
* Returns an item from cookieStorage by given name.
*
* @param {string} name Item name
* @return {string} Value of item name
*/
get : function (name) {
return delegate.get(name);
},
/**
* @ngdoc function
* @name pascalprecht.translate.$translateCookieStorage#set
* @methodOf pascalprecht.translate.$translateCookieStorage
*
* @description
* Sets an item in cookieStorage by given name.
*
* @deprecated use #put
*
* @param {string} name Item name
* @param {string} value Item value
*/
set : function (name, value) {
delegate.put(name, value);
},
/**
* @ngdoc function
* @name pascalprecht.translate.$translateCookieStorage#put
* @methodOf pascalprecht.translate.$translateCookieStorage
*
* @description
* Sets an item in cookieStorage by given name.
*
* @param {string} name Item name
* @param {string} value Item value
*/
put : function (name, value) {
delegate.put(name, value);
}
};
return $translateCookieStorage;
}
$translateCookieStorageFactory.displayName = '$translateCookieStorage';
return 'pascalprecht.translate';
}));
/*!
* angular-translate - v2.18.2 - 2020-01-04
*
* Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT
*/
!function(t,e){"function"==typeof define&&define.amd?define([],function(){return e()}):"object"==typeof module&&module.exports?module.exports=e():e()}(0,function(){function t(t){"use strict";var n;if(1===angular.version.major&&4<=angular.version.minor){var o=t.get("$cookies");n={get:function(t){return o.get(t)},put:function(t,e){o.put(t,e)}}}else{var r=t.get("$cookieStore");n={get:function(t){return r.get(t)},put:function(t,e){r.put(t,e)}}}return{get:function(t){return n.get(t)},set:function(t,e){n.put(t,e)},put:function(t,e){n.put(t,e)}}}return t.$inject=["$injector"],angular.module("pascalprecht.translate").factory("$translateCookieStorage",t),t.displayName="$translateCookieStorage","pascalprecht.translate"});
\ No newline at end of file
/*!
* angular-translate - v2.18.2 - 2020-01-04
*
* Copyright (c) 2020 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 module === 'object' && module.exports) {
// 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 () {
$translateLocalStorageFactory.$inject = ['$window', '$translateCookieStorage'];
angular.module('pascalprecht.translate')
/**
* @ngdoc object
* @name pascalprecht.translate.$translateLocalStorage
* @requires $window
* @requires $translateCookieStorage
*
* @description
* Abstraction layer for localStorage. This service is used when telling angular-translate
* to use localStorage as storage.
*
*/
.factory('$translateLocalStorage', $translateLocalStorageFactory);
function $translateLocalStorageFactory($window, $translateCookieStorage) {
'use strict';
// Setup adapter
var localStorageAdapter = (function(){
var langKey;
return {
/**
* @ngdoc function
* @name pascalprecht.translate.$translateLocalStorage#get
* @methodOf pascalprecht.translate.$translateLocalStorage
*
* @description
* Returns an item from localStorage by given name.
*
* @param {string} name Item name
* @return {string} Value of item name
*/
get: function (name) {
if(!langKey) {
langKey = $window.localStorage.getItem(name);
}
return langKey;
},
/**
* @ngdoc function
* @name pascalprecht.translate.$translateLocalStorage#set
* @methodOf pascalprecht.translate.$translateLocalStorage
*
* @description
* Sets an item in localStorage by given name.
*
* @deprecated use #put
*
* @param {string} name Item name
* @param {string} value Item value
*/
set: function (name, value) {
langKey=value;
$window.localStorage.setItem(name, value);
},
/**
* @ngdoc function
* @name pascalprecht.translate.$translateLocalStorage#put
* @methodOf pascalprecht.translate.$translateLocalStorage
*
* @description
* Sets an item in localStorage by given name.
*
* @param {string} name Item name
* @param {string} value Item value
*/
put: function (name, value) {
langKey=value;
$window.localStorage.setItem(name, value);
}
};
}());
var hasLocalStorageSupport = 'localStorage' in $window;
if (hasLocalStorageSupport) {
var testKey = 'pascalprecht.translate.storageTest';
try {
// this check have to be wrapped within a try/catch because on
// a SecurityError: Dom Exception 18 on iOS
if ($window.localStorage !== null) {
$window.localStorage.setItem(testKey, 'foo');
$window.localStorage.removeItem(testKey);
hasLocalStorageSupport = true;
} else {
hasLocalStorageSupport = false;
}
} catch (e){
hasLocalStorageSupport = false;
}
}
var $translateLocalStorage = hasLocalStorageSupport ? localStorageAdapter : $translateCookieStorage;
return $translateLocalStorage;
}
$translateLocalStorageFactory.displayName = '$translateLocalStorageFactory';
return 'pascalprecht.translate';
}));
/*!
* angular-translate - v2.18.2 - 2020-01-04
*
* Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT
*/
!function(t,e){"function"==typeof define&&define.amd?define([],function(){return e()}):"object"==typeof module&&module.exports?module.exports=e():e()}(0,function(){function t(a,t){"use strict";var o,e={get:function(t){return o||(o=a.localStorage.getItem(t)),o},set:function(t,e){o=e,a.localStorage.setItem(t,e)},put:function(t,e){o=e,a.localStorage.setItem(t,e)}},r="localStorage"in a;if(r){var n="pascalprecht.translate.storageTest";try{r=null!==a.localStorage&&(a.localStorage.setItem(n,"foo"),a.localStorage.removeItem(n),!0)}catch(t){r=!1}}return r?e:t}return t.$inject=["$window","$translateCookieStorage"],angular.module("pascalprecht.translate").factory("$translateLocalStorage",t),t.displayName="$translateLocalStorageFactory","pascalprecht.translate"});
\ No newline at end of file
/*!
* angular-translate - v2.18.2 - 2020-01-04
*
* Copyright (c) 2020 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 module === 'object' && module.exports) {
// 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 if (value === true || value === false) {
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('-');
switch (parts.length) {
case 1: // language only
parts[0] = parts[0].toLowerCase();
break;
case 2: // language-script or language-region
parts[0] = parts[0].toLowerCase();
if (parts[1].length === 4) { // parts[1] is script
parts[1] = parts[1].charAt(0).toUpperCase() + parts[1].slice(1).toLowerCase();
} else { // parts[1] is region
parts[1] = parts[1].toUpperCase();
}
break;
case 3: // language-script-region
parts[0] = parts[0].toLowerCase();
parts[1] = parts[1].charAt(0).toUpperCase() + parts[1].slice(1).toLowerCase();
parts[2] = parts[2].toUpperCase();
break;
default:
return temp;
}
return parts.join('-');
},
'iso639-1' : function (tag) {
var temp = (tag || '').split('_').join('-');
var parts = temp.split('-');
return parts[0].toLowerCase();
}
};
var version = '2.18.2';
// 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, '');
};
/**
* @name lowercase
* @private
*
* @description
* Return the lowercase string only if the type is string
*
* @returns {string} The string all in lowercase
*/
var lowercase = function (string) {
return angular.isString(string) ? string.toLowerCase() : string;
};
var negotiateLocale = function (preferred) {
if (!preferred) {
return;
}
var avail = [],
locale = lowercase(preferred),
i = 0,
n = $availableLanguageKeys.length;
for (; i < n; i++) {
avail.push(lowercase($availableLanguageKeys[i]));
}
// Check for an exact match in our list of available keys
i = indexOf(avail, locale);
if (i > -1) {
return $availableLanguageKeys[i];
}
if ($languageKeyAliases) {
var alias;
for (var langKeyAlias in $languageKeyAliases) {
if ($languageKeyAliases.hasOwnProperty(langKeyAlias)) {
var hasWildcardKey = false;
var hasExactKey = Object.prototype.hasOwnProperty.call($languageKeyAliases, langKeyAlias) &&
lowercase(langKeyAlias) === lowercase(preferred);
if (langKeyAlias.slice(-1) === '*') {
hasWildcardKey = lowercase(langKeyAlias.slice(0, -1)) === lowercase(preferred.slice(0, langKeyAlias.length - 1));
}
if (hasExactKey || hasWildcardKey) {
alias = $languageKeyAliases[langKeyAlias];
if (indexOf(avail, lowercase(alias)) > -1) {
return alias;
}
}
}
}
}
// Check for a language code without region
var parts = preferred.split('_');
if (parts.length > 1 && indexOf(avail, 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**.
* It is recommended to call this after {@link pascalprecht.translate.$translate#fallbackLanguage fallbackLanguage()}.
*
* @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 => en
* en-US => en-US
* en_US => en-US
* en-us => en-US
* sr-latn => sr-Latn
* sr-latn-rs => sr-Latn-RS
*
* 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=undefined] The id of the interpolation to use (use default unless set via useInterpolation())
* @param {string=} [defaultTranslationText=undefined] 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=false] A language to be used instead of the current language
* @param {string=} [sanitizeStrategy=undefined] force sanitize strategy for this call instead of using the configured one (use default unless set)
* @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, sanitizeStrategy) {
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, sanitizeStrategy).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);
} else {
throw new TypeError('translationId must be a not empty string');
}
var promiseToWaitFor = (function () {
var promise = langPromises[uses] || langPromises[$preferredLanguage];
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, sanitizeStrategy).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, sanitizeStrategy).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, sanitizeStrategy)
.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.
* It is recommended to call this before {@link pascalprecht.translate.$translateProvider#preferredLanguage preferredLanguage()}.
*
* @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=undefined] The id of the interpolation to use (use default unless set via useInterpolation())
* @param {string=} [forceLanguage=false] A language to be used instead of the current language
* @param {string=} [sanitizeStrategy=undefined] force sanitize strategy for this call instead of using the configured one (use default unless set)
*
* @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
* Calls the function provided or resolved the returned promise after 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 {string} value translation
* @param {object} [interpolationParams={}] interpolation params
* @param {string} [context=undefined] current context (filter, directive, service)
* @param {string} [sanitizeStrategy=undefined] sanitize strategy (use default unless set)
* @param {string} translationId current translationId
*
* @returns {string} interpolated string
*/
$translateInterpolator.interpolate = function (value, interpolationParams, context, sanitizeStrategy, translationId) { // jshint ignore:line
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 {string=} translate-sanitize-strategy defines locally sanitize strategy
* @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, '');
};
/**
* @name lowercase
* @private
*
* @description
* Return the lowercase string only if the type is string
*
* @returns {string} The string all in lowercase
*/
var lowercase = function (string) {
return angular.isString(string) ? string.toLowerCase() : string;
};
return {
restrict: 'AE',
scope: true,
priority: $translate.directivePriority(),
compile: function (tElement, tAttr) {
var translateValuesExist = (tAttr.translateValues) ?
tAttr.translateValues : undefined;
var translateInterpolation = (tAttr.translateInterpolation) ?
tAttr.translateInterpolation : undefined;
var translateSanitizeStrategyExist = (tAttr.translateSanitizeStrategy) ?
tAttr.translateSanitizeStrategy : undefined;
var translateValueExist = tElement[0].outerHTML.match(/translate-value-+/i);
var interpolateRegExp = '^(.*)(' + $interpolate.startSymbol() + '.*' + $interpolate.endSymbol() + ')(.*)',
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 = 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()).replace(/\n/g, ' ');
// 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 (translateSanitizeStrategyExist) {
iAttr.$observe('translateSanitizeStrategy', function (value) {
scope.sanitizeStrategy = $parse(value)(scope.$parent);
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 = 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, scope.sanitizeStrategy)
.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.
* @param {string=} translate-sanitize-strategy defines locally sanitize strategy
*
* @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,
translateSanitizeStrategy,
previousAttributes = {};
// Main update translations function
var updateTranslations = function () {
angular.forEach(translateAttr, function (translationId, attributeName) {
if (!translationId) {
return;
}
previousAttributes[attributeName] = true;
// if translation id starts with '.' and translateNamespace given, prepend namespace
if (scope.translateNamespace && translationId.charAt(0) === '.') {
translationId = scope.translateNamespace + translationId;
}
$translate(translationId, translateValues, attr.translateInterpolation, undefined, scope.translateLanguage, translateSanitizeStrategy)
.then(function (translation) {
element.attr(attributeName, translation);
}, function (translationId) {
element.attr(attributeName, translationId);
});
});
// Removing unused attributes that were previously used
angular.forEach(previousAttributes, function (flag, attributeName) {
if (!translateAttr[attributeName]) {
element.removeAttr(attributeName);
delete previousAttributes[attributeName];
}
});
};
// Watch for attribute changes
watchAttribute(
scope,
attr.translateAttr,
function (newValue) { translateAttr = newValue; },
updateTranslations
);
// Watch for value changes
watchAttribute(
scope,
attr.translateValues,
function (newValue) { translateValues = newValue; },
updateTranslations
);
// Watch for sanitize strategy changes
watchAttribute(
scope,
attr.translateSanitizeStrategy,
function (newValue) { translateSanitizeStrategy = newValue; },
updateTranslations
);
if (attr.translateValues) {
scope.$watch(attr.translateValues, updateTranslations, true);
}
// Replaced watcher on translateLanguage with event listener
scope.$on('translateLanguageChanged', updateTranslations);
// Ensures the text will be refreshed after the current language was changed
// w/ $translate.use(...)
var unbind = $rootScope.$on('$translateChangeSuccess', updateTranslations);
updateTranslations();
scope.$on('$destroy', unbind);
}
};
}
function watchAttribute(scope, attribute, valueCallback, changeCallback) {
'use strict';
if (!attribute) {
return;
}
if (attribute.substr(0, 2) === '::') {
attribute = attribute.substr(2);
} else {
scope.$watch(attribute, function(newValue) {
valueCallback(newValue);
changeCallback();
}, true);
}
valueCallback(scope.$eval(attribute));
}
translateAttrDirective.displayName = 'translateAttrDirective';
angular.module('pascalprecht.translate')
/**
* @ngdoc directive
* @name pascalprecht.translate.directive:translateCloak
* @requires $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, $rootScope) {
'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);
});
$rootScope.$on('$translateChangeSuccess', function () {
$translate(iAttr.translateCloak).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 is 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)) {
var ctx = this || {
'__SCOPE_IS_NOT_AVAILABLE': 'More info at https://github.com/angular/angular.js/commit/8863b9d04c722b278fa93c5d66ad1e578ad6eb1f'
};
interpolateParams = $parse(interpolateParams)(ctx);
}
return $translate.instant(translationId, interpolateParams, interpolation, forceLanguage);
};
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';
}));
/*!
* angular-translate - v2.18.2 - 2020-01-04
*
* Copyright (c) 2020 The angular-translate team, Pascal Precht; Licensed MIT
*/
!function(t,e){"function"==typeof define&&define.amd?define([],function(){return e()}):"object"==typeof module&&module.exports?module.exports=e():e()}(0,function(){function t(e){"use strict";var n=e.storageKey(),a=e.storage(),t=function(){var t=e.preferredLanguage();angular.isString(t)?e.use(t):a.put(n,e.use())};t.displayName="fallbackFromIncorrectStorageValue",a?a.get(n)?e.use(a.get(n)).catch(t):t():angular.isString(e.preferredLanguage())&&e.use(e.preferredLanguage())}function e(t,r,e,i){"use strict";var T,c,z,x,F,I,_,n,V,R,D,K,U,M,H,G,q={},Y=[],B=t,J=[],Q="translate-cloak",W=!1,X=!1,Z=".",tt=!1,et=!1,nt=0,at=!0,a="default",s={default:function(t){return(t||"").split("-").join("_")},java:function(t){var e=(t||"").split("-").join("_"),n=e.split("_");return 1<n.length?n[0].toLowerCase()+"_"+n[1].toUpperCase():e},bcp47:function(t){var e=(t||"").split("_").join("-"),n=e.split("-");switch(n.length){case 1:n[0]=n[0].toLowerCase();break;case 2:n[0]=n[0].toLowerCase(),4===n[1].length?n[1]=n[1].charAt(0).toUpperCase()+n[1].slice(1).toLowerCase():n[1]=n[1].toUpperCase();break;case 3:n[0]=n[0].toLowerCase(),n[1]=n[1].charAt(0).toUpperCase()+n[1].slice(1).toLowerCase(),n[2]=n[2].toUpperCase();break;default:return e}return n.join("-")},"iso639-1":function(t){return(t||"").split("_").join("-").split("-")[0].toLowerCase()}},o=function(){if(angular.isFunction(i.getLocale))return i.getLocale();var t,e,n=r.$get().navigator,a=["language","browserLanguage","systemLanguage","userLanguage"];if(angular.isArray(n.languages))for(t=0;t<n.languages.length;t++)if((e=n.languages[t])&&e.length)return e;for(t=0;t<a.length;t++)if((e=n[a[t]])&&e.length)return e;return null};o.displayName="angular-translate/service: getFirstBrowserLanguage";var rt=function(){var t=o()||"";return s[a]&&(t=s[a](t)),t};rt.displayName="angular-translate/service: getLocale";var it=function(t,e){for(var n=0,a=t.length;n<a;n++)if(t[n]===e)return n;return-1},st=function(){return this.toString().replace(/^\s+|\s+$/g,"")},f=function(t){return angular.isString(t)?t.toLowerCase():t},ot=function(t){if(t){for(var e,n=[],a=f(t),r=0,i=Y.length;r<i;r++)n.push(f(Y[r]));if(-1<(r=it(n,a)))return Y[r];if(c)for(var s in c)if(c.hasOwnProperty(s)){var o=!1,l=Object.prototype.hasOwnProperty.call(c,s)&&f(s)===f(t);if("*"===s.slice(-1)&&(o=f(s.slice(0,-1))===f(t.slice(0,s.length-1))),(l||o)&&(e=c[s],-1<it(n,f(e))))return e}var u=t.split("_");return 1<u.length&&-1<it(n,f(u[0]))?u[0]:void 0}},lt=function(t,e){if(!t&&!e)return q;if(t&&!e){if(angular.isString(t))return q[t]}else angular.isObject(q[t])||(q[t]={}),angular.extend(q[t],ut(e));return this};this.translations=lt,this.cloakClassName=function(t){return t?(Q=t,this):Q},this.nestedObjectDelimeter=function(t){return t?(Z=t,this):Z};var ut=function(t,e,n,a){var r,i,s;for(r in e||(e=[]),n||(n={}),t)Object.prototype.hasOwnProperty.call(t,r)&&(s=t[r],angular.isObject(s)?ut(s,e.concat(r),n,r):(i=e.length?""+e.join(Z)+Z+r:r,e.length&&r===a&&(n[""+e.join(Z)]="@:"+i),n[i]=s));return n};ut.displayName="flatObject",this.addInterpolation=function(t){return J.push(t),this},this.useMessageFormatInterpolation=function(){return this.useInterpolation("$translateMessageFormatInterpolation")},this.useInterpolation=function(t){return R=t,this},this.useSanitizeValueStrategy=function(t){return e.useStrategy(t),this},this.preferredLanguage=function(t){return t?(ct(t),this):T};var ct=function(t){return t&&(T=t),T};this.translationNotFoundIndicator=function(t){return this.translationNotFoundIndicatorLeft(t),this.translationNotFoundIndicatorRight(t),this},this.translationNotFoundIndicatorLeft=function(t){return t?(U=t,this):U},this.translationNotFoundIndicatorRight=function(t){return t?(M=t,this):M},this.fallbackLanguage=function(t){return ft(t),this};var ft=function(t){return t?(angular.isString(t)?(x=!0,z=[t]):angular.isArray(t)&&(x=!1,z=t),angular.isString(T)&&it(z,T)<0&&z.push(T),this):x?z[0]:z};this.use=function(t){if(t){if(!q[t]&&!D)throw new Error("$translateProvider couldn't find translationTable for langKey: '"+t+"'");return F=t,this}return F},this.resolveClientLocale=function(){return rt()};var gt=function(t){return t?(B=t,this):n?n+B:B};this.storageKey=gt,this.useUrlLoader=function(t,e){return this.useLoader("$translateUrlLoader",angular.extend({url:t},e))},this.useStaticFilesLoader=function(t){return this.useLoader("$translateStaticFilesLoader",t)},this.useLoader=function(t,e){return D=t,K=e||{},this},this.useLocalStorage=function(){return this.useStorage("$translateLocalStorage")},this.useCookieStorage=function(){return this.useStorage("$translateCookieStorage")},this.useStorage=function(t){return _=t,this},this.storagePrefix=function(t){return t?(n=t,this):t},this.useMissingTranslationHandlerLog=function(){return this.useMissingTranslationHandler("$translateMissingTranslationHandlerLog")},this.useMissingTranslationHandler=function(t){return V=t,this},this.usePostCompiling=function(t){return W=!!t,this},this.forceAsyncReload=function(t){return X=!!t,this},this.uniformLanguageTag=function(t){return t?angular.isString(t)&&(t={standard:t}):t={},a=t.standard,this},this.determinePreferredLanguage=function(t){var e=t&&angular.isFunction(t)?t():rt();return T=Y.length&&ot(e)||e,this},this.registerAvailableLanguageKeys=function(t,e){return t?(Y=t,e&&(c=e),this):Y},this.useLoaderCache=function(t){return!1===t?H=void 0:!0===t?H=!0:void 0===t?H="$translationCache":t&&(H=t),this},this.directivePriority=function(t){return void 0===t?nt:(nt=t,this)},this.statefulFilter=function(t){return void 0===t?at:(at=t,this)},this.postProcess=function(t){return G=t||void 0,this},this.keepContent=function(t){return et=!!t,this},this.$get=["$log","$injector","$rootScope","$q",function(t,o,s,m){var i,$,y,b=o.get(R||"$translateDefaultInterpolation"),S=!1,L={},f={},w=function(t,s,o,l,u,c){!F&&T&&(F=T);var a=u&&u!==F?ot(u)||u:F;if(u&&v(u),angular.isArray(t)){return function(t){for(var a={},e=[],n=function(e){var n=m.defer(),t=function(t){a[e]=t,n.resolve([e,t])};return w(e,s,o,l,u,c).then(t,t),n.promise},r=0,i=t.length;r<i;r++)e.push(n(t[r]));return m.all(e).then(function(){return a})}(t)}var e=m.defer();if(!t)throw new TypeError("translationId must be a not empty string");t=st.apply(t);var n=function(){var t=f[a]||f[T];if($=0,_&&!t){var e=i.get(B);if(t=f[e],z&&z.length){var n=it(z,e);$=0===n?1:0,it(z,T)<0&&z.push(T)}}return t}();if(n){var r=function(){u||(a=F),h(t,s,o,l,a,c).then(e.resolve,e.reject)};r.displayName="promiseResolved",n.finally(r).catch(angular.noop)}else h(t,s,o,l,a,c).then(e.resolve,e.reject);return e.promise},j=function(t){return U&&(t=[U,t].join(" ")),M&&(t=[t,M].join(" ")),t},l=function(t){F=t,_&&i.put(w.storageKey(),F),s.$emit("$translateChangeSuccess",{language:t}),b.setLocale(F);var e=function(t,e){L[e].setLocale(F)};e.displayName="eachInterpolatorLocaleSetter",angular.forEach(L,e),s.$emit("$translateChangeEnd",{language:t})},u=function(n){if(!n)throw"No language key specified for loading.";var a=m.defer();s.$emit("$translateLoadingStart",{language:n}),S=!0;var t=H;"string"==typeof t&&(t=o.get(t));var e=angular.extend({},K,{key:n,$http:angular.extend({},{cache:t},K.$http)}),r=function(t){var e={};s.$emit("$translateLoadingSuccess",{language:n}),angular.isArray(t)?angular.forEach(t,function(t){angular.extend(e,ut(t))}):angular.extend(e,ut(t)),S=!1,a.resolve({key:n,table:e}),s.$emit("$translateLoadingEnd",{language:n})};r.displayName="onLoaderSuccess";var i=function(t){s.$emit("$translateLoadingError",{language:t}),a.reject(t),s.$emit("$translateLoadingEnd",{language:t})};return i.displayName="onLoaderError",o.get(D)(e).then(r,i),a.promise};if(_&&(!(i=o.get(_)).get||!i.put))throw new Error("Couldn't use storage '"+_+"', missing get() or put() method!");if(J.length){var e=function(t){var e=o.get(t);e.setLocale(T||F),L[e.getInterpolationIdentifier()]=e};e.displayName="interpolationFactoryAdder",angular.forEach(J,e)}var c=function(a,r,i,s,o){var l=m.defer(),t=function(t){if(Object.prototype.hasOwnProperty.call(t,r)&&null!==t[r]){s.setLocale(a);var e=t[r];if("@:"===e.substr(0,2))c(a,e.substr(2),i,s,o).then(l.resolve,l.reject);else{var n=s.interpolate(t[r],i,"service",o,r);n=O(r,t[r],n,i,a),l.resolve(n)}s.setLocale(F)}else l.reject()};return t.displayName="fallbackTranslationResolver",function(t){var e=m.defer();if(Object.prototype.hasOwnProperty.call(q,t))e.resolve(q[t]);else if(f[t]){var n=function(t){lt(t.key,t.table),e.resolve(t.table)};n.displayName="translationTableResolver",f[t].then(n,e.reject)}else e.reject();return e.promise}(a).then(t,l.reject),l.promise},g=function(t,e,n,a,r){var i,s=q[t];if(s&&Object.prototype.hasOwnProperty.call(s,e)&&null!==s[e]){if(a.setLocale(t),i=a.interpolate(s[e],n,"filter",r,e),i=O(e,s[e],i,n,t,r),!angular.isString(i)&&angular.isFunction(i.$$unwrapTrustedValue)){var o=i.$$unwrapTrustedValue();if("@:"===o.substr(0,2))return g(t,o.substr(2),n,a,r)}else if("@:"===i.substr(0,2))return g(t,i.substr(2),n,a,r);a.setLocale(F)}return i},C=function(t,e,n,a){return V?o.get(V)(t,F,e,n,a):t},N=function(t,e,n,a,r,i){var s=m.defer();if(t<z.length){var o=z[t];c(o,e,n,a,i).then(function(t){s.resolve(t)},function(){return N(t+1,e,n,a,r,i).then(s.resolve,s.reject)})}else if(r)s.resolve(r);else{var l=C(e,n,r);V&&l?s.resolve(l):s.reject(j(e))}return s.promise},p=function(t,e,n,a,r){var i;if(t<z.length){var s=z[t];(i=g(s,e,n,a,r))||""===i||(i=p(t+1,e,n,a))}return i},h=function(t,e,n,a,r,i){var s,o,l,u,c,f=m.defer(),g=r?q[r]:q,p=n?L[n]:b;if(g&&Object.prototype.hasOwnProperty.call(g,t)&&null!==g[t]){var h=g[t];if("@:"===h.substr(0,2))w(h.substr(2),e,n,a,r,i).then(f.resolve,f.reject);else{var d=p.interpolate(h,e,"service",i,t);d=O(t,h,d,e,r),f.resolve(d)}}else{var v;V&&!S&&(v=C(t,e,a)),r&&z&&z.length?(s=t,o=e,l=p,u=a,c=i,N(0<y?y:$,s,o,l,u,c)).then(function(t){f.resolve(t)},function(t){f.reject(j(t))}):V&&!S&&v?a?f.resolve(a):f.resolve(v):a?f.resolve(a):f.reject(j(t))}return f.promise},d=function(t,e,n,a,r){var i,s=a?q[a]:q,o=b;if(L&&Object.prototype.hasOwnProperty.call(L,n)&&(o=L[n]),s&&Object.prototype.hasOwnProperty.call(s,t)&&null!==s[t]){var l=s[t];i="@:"===l.substr(0,2)?d(l.substr(2),e,n,a,r):(i=o.interpolate(l,e,"filter",r,t),O(t,l,i,e,a,r))}else{var u;V&&!S&&(u=C(t,e,r)),i=a&&z&&z.length?p(($=0)<y?y:$,t,e,o,r):V&&!S&&u?u:j(t)}return i},O=function(t,e,n,a,r,i){var s=G;return s&&("string"==typeof s&&(s=o.get(s)),s)?s(t,e,n,a,r,i):n},v=function(t){q[t]||!D||f[t]||(f[t]=u(t).then(function(t){return lt(t.key,t.table),t}))};w.preferredLanguage=function(t){return t&&ct(t),T},w.cloakClassName=function(){return Q},w.nestedObjectDelimeter=function(){return Z},w.fallbackLanguage=function(t){if(null!=t){if(ft(t),D&&z&&z.length)for(var e=0,n=z.length;e<n;e++)f[z[e]]||(f[z[e]]=u(z[e]));w.use(w.use())}return x?z[0]:z},w.useFallbackLanguage=function(t){if(null!=t)if(t){var e=it(z,t);-1<e&&(y=e)}else y=0},w.proposedLanguage=function(){return I},w.storage=function(){return i},w.negotiateLocale=ot,w.use=function(e){if(!e)return F;var n=m.defer();n.promise.then(null,angular.noop),s.$emit("$translateChangeStart",{language:e});var t=ot(e);return 0<Y.length&&!t?m.reject(e):(t&&(e=t),I=e,!X&&q[e]||!D||f[e]?f[e]?f[e].then(function(t){return I===t.key&&l(t.key),n.resolve(t.key),t},function(t){return!F&&z&&0<z.length&&z[0]!==t?w.use(z[0]).then(n.resolve,n.reject):n.reject(t)}):(n.resolve(e),l(e)):(f[e]=u(e).then(function(t){return lt(t.key,t.table),n.resolve(t.key),I===e&&l(t.key),t},function(t){return s.$emit("$translateChangeError",{language:t}),n.reject(t),s.$emit("$translateChangeEnd",{language:t}),m.reject(t)}),f[e].finally(function(){var t;I===(t=e)&&(I=void 0),f[t]=void 0}).catch(angular.noop)),n.promise)},w.resolveClientLocale=function(){return rt()},w.storageKey=function(){return gt()},w.isPostCompilingEnabled=function(){return W},w.isForceAsyncReloadEnabled=function(){return X},w.isKeepContent=function(){return et},w.refresh=function(t){if(!D)throw new Error("Couldn't refresh translation table, no loader registered!");s.$emit("$translateRefreshStart",{language:t});var e=m.defer(),n={};function a(e){var t=u(e);return(f[e]=t).then(function(t){q[e]={},lt(e,t.table),n[e]=!0},angular.noop),t}if(e.promise.then(function(){for(var t in q)q.hasOwnProperty(t)&&(t in n||delete q[t]);F&&l(F)},angular.noop).finally(function(){s.$emit("$translateRefreshEnd",{language:t})}),t)q[t]?a(t).then(e.resolve,e.reject):e.reject();else{var r=z&&z.slice()||[];F&&-1===r.indexOf(F)&&r.push(F),m.all(r.map(a)).then(e.resolve,e.reject)}return e.promise},w.instant=function(t,e,n,a,r){var i=a&&a!==F?ot(a)||a:F;if(null===t||angular.isUndefined(t))return t;if(a&&v(a),angular.isArray(t)){for(var s={},o=0,l=t.length;o<l;o++)s[t[o]]=w.instant(t[o],e,n,a,r);return s}if(angular.isString(t)&&t.length<1)return t;t&&(t=st.apply(t));var u,c,f=[];T&&f.push(T),i&&f.push(i),z&&z.length&&(f=f.concat(z));for(var g=0,p=f.length;g<p;g++){var h=f[g];if(q[h]&&void 0!==q[h][t]&&(u=d(t,e,n,i,r)),void 0!==u)break}u||""===u||(U||M?u=j(t):(u=b.interpolate(t,e,"filter",r),V&&!S&&(c=C(t,e,r)),V&&!S&&c&&(u=c)));return u},w.versionInfo=function(){return"2.18.2"},w.loaderCache=function(){return H},w.directivePriority=function(){return nt},w.statefulFilter=function(){return at},w.isReady=function(){return tt};var n=m.defer();n.promise.then(function(){tt=!0}),w.onReady=function(t){var e=m.defer();return angular.isFunction(t)&&e.promise.then(t),tt?e.resolve():n.promise.then(e.resolve),e.promise},w.getAvailableLanguageKeys=function(){return 0<Y.length?Y:null},w.getTranslationTable=function(t){return(t=t||w.use())&&q[t]?angular.copy(q[t]):null};var a=s.$on("$translateReady",function(){n.resolve(),a(),a=null}),r=s.$on("$translateChangeEnd",function(){n.resolve(),r(),r=null});if(D){if(angular.equals(q,{})&&w.use()&&w.use(w.use()),z&&z.length)for(var E=function(t){return lt(t.key,t.table),s.$emit("$translateChangeEnd",{language:t.key}),t},k=0,P=z.length;k<P;k++){var A=z[k];!X&&q[A]||(f[A]=u(A).then(E))}}else s.$emit("$translateReady",{language:w.use()});return w}]}function n(s,o){"use strict";var t={};return t.setLocale=function(t){t},t.getInterpolationIdentifier=function(){return"default"},t.useSanitizeValueStrategy=function(t){return o.useStrategy(t),this},t.interpolate=function(t,e,n,a,r){var i;return e=e||{},e=o.sanitize(e,"params",a,n),i=angular.isNumber(t)?""+t:angular.isString(t)?(i=s(t)(e),o.sanitize(i,"text",a,n)):""},t}function a(S,L,w,j,C){"use strict";var N=function(t){return angular.isString(t)?t.toLowerCase():t};return{restrict:"AE",scope:!0,priority:S.directivePriority(),compile:function(t,h){var d=h.translateValues?h.translateValues:void 0,v=h.translateInterpolation?h.translateInterpolation:void 0,m=h.translateSanitizeStrategy?h.translateSanitizeStrategy:void 0,$=t[0].outerHTML.match(/translate-value-+/i),y="^(.*)("+L.startSymbol()+".*"+L.endSymbol()+")(.*)",b="^(.*)"+L.startSymbol()+"(.*)"+L.endSymbol()+"(.*)";return function(r,l,u){r.interpolateParams={},r.preText="",r.postText="",r.translateNamespace=function t(e){if(e.translateNamespace)return e.translateNamespace;if(e.$parent)return t(e.$parent)}(r);var i={},s=function(t){if(angular.isFunction(s._unwatchOld)&&(s._unwatchOld(),s._unwatchOld=void 0),angular.equals(t,"")||!angular.isDefined(t)){var e=function(){return this.toString().replace(/^\s+|\s+$/g,"")}.apply(l.text()).replace(/\n/g," "),n=e.match(y);if(angular.isArray(n)){r.preText=n[1],r.postText=n[3],i.translate=L(n[2])(r.$parent);var a=e.match(b);angular.isArray(a)&&a[2]&&a[2].length&&(s._unwatchOld=r.$watch(a[2],function(t){i.translate=t,c()}))}else i.translate=e||void 0}else i.translate=t;c()},t=function(e){u.$observe(e,function(t){i[e]=t,c()})};!function(t,e,n){if(e.translateValues&&angular.extend(t,j(e.translateValues)(r.$parent)),$)for(var a in n)Object.prototype.hasOwnProperty.call(e,a)&&"translateValue"===a.substr(0,14)&&"translateValues"!==a&&(t[N(a.substr(14,1))+a.substr(15)]=n[a])}(r.interpolateParams,u,h);var e=!0;for(var n in u.$observe("translate",function(t){void 0===t?s(""):""===t&&e||(i.translate=t,c()),e=!1}),u)u.hasOwnProperty(n)&&"translateAttr"===n.substr(0,13)&&13<n.length&&t(n);if(u.$observe("translateDefault",function(t){r.defaultText=t,c()}),m&&u.$observe("translateSanitizeStrategy",function(t){r.sanitizeStrategy=j(t)(r.$parent),c()}),d&&u.$observe("translateValues",function(t){t&&r.$parent.$watch(function(){angular.extend(r.interpolateParams,j(t)(r.$parent))})}),$){var a=function(n){u.$observe(n,function(t){var e=N(n.substr(14,1))+n.substr(15);r.interpolateParams[e]=t})};for(var o in u)Object.prototype.hasOwnProperty.call(u,o)&&"translateValue"===o.substr(0,14)&&"translateValues"!==o&&a(o)}var c=function(){for(var t in i)i.hasOwnProperty(t)&&void 0!==i[t]&&f(t,i[t],r,r.interpolateParams,r.defaultText,r.translateNamespace)},f=function(e,t,n,a,r,i){t?(i&&"."===t.charAt(0)&&(t=i+t),S(t,a,v,r,n.translateLanguage,n.sanitizeStrategy).then(function(t){g(t,n,!0,e)},function(t){g(t,n,!1,e)})):g(t,n,!1,e)},g=function(t,e,n,a){if(n||void 0!==e.defaultText&&(t=e.defaultText),"translate"===a){(n||!n&&!S.isKeepContent()&&void 0===u.translateKeepContent)&&l.empty().append(e.preText+t+e.postText);var r=S.isPostCompilingEnabled(),i=void 0!==h.translateCompile,s=i&&"false"!==h.translateCompile;(r&&!i||s)&&w(l.contents())(e)}else{var o=u.$attr[a];"data-"===o.substr(0,5)&&(o=o.substr(5)),o=o.substr(15),l.attr(o,t)}};(d||$||u.translateDefault)&&r.$watch("interpolateParams",c,!0),r.$on("translateLanguageChanged",c);var p=C.$on("$translateChangeSuccess",c);l.text().length?u.translate?s(u.translate):s(""):u.translate&&s(u.translate),c(),r.$on("$destroy",p)}}}}function r(u,c){"use strict";return{restrict:"A",priority:u.directivePriority(),link:function(n,a,r){var i,s,o,l={},t=function(){angular.forEach(i,function(t,e){t&&(l[e]=!0,n.translateNamespace&&"."===t.charAt(0)&&(t=n.translateNamespace+t),u(t,s,r.translateInterpolation,void 0,n.translateLanguage,o).then(function(t){a.attr(e,t)},function(t){a.attr(e,t)}))}),angular.forEach(l,function(t,e){i[e]||(a.removeAttr(e),delete l[e])})};f(n,r.translateAttr,function(t){i=t},t),f(n,r.translateValues,function(t){s=t},t),f(n,r.translateSanitizeStrategy,function(t){o=t},t),r.translateValues&&n.$watch(r.translateValues,t,!0),n.$on("translateLanguageChanged",t);var e=c.$on("$translateChangeSuccess",t);t(),n.$on("$destroy",e)}}}function f(t,e,n,a){"use strict";e&&("::"===e.substr(0,2)?e=e.substr(2):t.$watch(e,function(t){n(t),a()},!0),n(t.$eval(e)))}function i(s,o){"use strict";return{compile:function(t){var i=function(t){t.addClass(s.cloakClassName())};return i(t),function(t,e,n){var a=function(t){t.removeClass(s.cloakClassName())}.bind(this,e),r=i.bind(this,e);n.translateCloak&&n.translateCloak.length?(n.$observe("translateCloak",function(t){s(t).then(a,r)}),o.$on("$translateChangeSuccess",function(){s(n.translateCloak).then(a,r)})):s.onReady(a)}}}}function s(){"use strict";return{restrict:"A",scope:!0,compile:function(){return{pre:function(t,e,n){t.translateNamespace=function t(e){if(e.translateNamespace)return e.translateNamespace;if(e.$parent)return t(e.$parent)}(t),t.translateNamespace&&"."===n.translateNamespace.charAt(0)?t.translateNamespace+=n.translateNamespace:t.translateNamespace=n.translateNamespace}}}}}function o(){"use strict";return{restrict:"A",scope:!0,compile:function(){return function(e,t,n){n.$observe("translateLanguage",function(t){e.translateLanguage=t}),e.$watch("translateLanguage",function(){e.$broadcast("translateLanguageChanged")})}}}}function l(i,s){"use strict";var t=function(t,e,n,a){if(!angular.isObject(e)){var r=this||{__SCOPE_IS_NOT_AVAILABLE:"More info at https://github.com/angular/angular.js/commit/8863b9d04c722b278fa93c5d66ad1e578ad6eb1f"};e=i(e)(r)}return s.instant(t,e,n,a)};return s.statefulFilter()&&(t.$stateful=!0),t}function u(t){"use strict";return t("translations")}return t.$inject=["$translate"],e.$inject=["$STORAGE_KEY","$windowProvider","$translateSanitizationProvider","pascalprechtTranslateOverrider"],n.$inject=["$interpolate","$translateSanitization"],a.$inject=["$translate","$interpolate","$compile","$parse","$rootScope"],r.$inject=["$translate","$rootScope"],i.$inject=["$translate","$rootScope"],l.$inject=["$parse","$translate"],u.$inject=["$cacheFactory"],angular.module("pascalprecht.translate",["ng"]).run(t),t.displayName="runTranslate",angular.module("pascalprecht.translate").provider("$translateSanitization",function(){"use strict";var n,a,g,p=null,h=!1,d=!1;(g={sanitize:function(t,e){return"text"===e&&(t=i(t)),t},escape:function(t,e){return"text"===e&&(t=r(t)),t},sanitizeParameters:function(t,e){return"params"===e&&(t=o(t,i)),t},escapeParameters:function(t,e){return"params"===e&&(t=o(t,r)),t},sce:function(t,e,n){return"text"===e?t=s(t):"params"===e&&"filter"!==n&&(t=o(t,r)),t},sceParameters:function(t,e){return"params"===e&&(t=o(t,s)),t}}).escaped=g.escapeParameters,this.addStrategy=function(t,e){return g[t]=e,this},this.removeStrategy=function(t){return delete g[t],this},this.useStrategy=function(t){return h=!0,p=t,this},this.$get=["$injector","$log",function(u,c){var e,f={};return u.has("$sanitize")&&(n=u.get("$sanitize")),u.has("$sce")&&(a=u.get("$sce")),{useStrategy:(e=this,function(t){e.useStrategy(t)}),sanitize:function(t,e,n,a){if(p||h||d||(c.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."),d=!0),n||null===n||(n=p),!n)return t;a||(a="service");var r,i,s,o,l=angular.isArray(n)?n:[n];return r=t,i=e,s=a,o=l,angular.forEach(o,function(e){if(angular.isFunction(e))r=e(r,i,s);else if(angular.isFunction(g[e]))r=g[e](r,i,s);else{if(!angular.isString(g[e]))throw new Error("pascalprecht.translate.$translateSanitization: Unknown sanitization strategy: '"+e+"'");if(!f[g[e]])try{f[g[e]]=u.get(g[e])}catch(t){throw f[g[e]]=function(){},new Error("pascalprecht.translate.$translateSanitization: Unknown sanitization strategy: '"+e+"'")}r=f[g[e]](r,i,s)}}),r}}}];var r=function(t){var e=angular.element("<div></div>");return e.text(t),e.html()},i=function(t){if(!n)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 n(t)},s=function(t){if(!a)throw new Error("pascalprecht.translate.$translateSanitization: Error cannot find $sce service.");return a.trustAsHtml(t)},o=function(t,n,a){if(angular.isDate(t))return t;if(angular.isObject(t)){var r=angular.isArray(t)?[]:{};if(a){if(-1<a.indexOf(t))throw new Error("pascalprecht.translate.$translateSanitization: Error cannot interpolate parameter due recursive object")}else a=[];return a.push(t),angular.forEach(t,function(t,e){angular.isFunction(t)||(r[e]=o(t,n,a))}),a.splice(-1,1),r}return angular.isNumber(t)?t:!0===t||!1===t?t:angular.isUndefined(t)||null===t?t:n(t)}}),angular.module("pascalprecht.translate").constant("pascalprechtTranslateOverrider",{}).provider("$translate",e),e.displayName="displayName",angular.module("pascalprecht.translate").factory("$translateDefaultInterpolation",n),n.displayName="$translateDefaultInterpolation",angular.module("pascalprecht.translate").constant("$STORAGE_KEY","NG_TRANSLATE_LANG_KEY"),angular.module("pascalprecht.translate").directive("translate",a),a.displayName="translateDirective",angular.module("pascalprecht.translate").directive("translateAttr",r),r.displayName="translateAttrDirective",angular.module("pascalprecht.translate").directive("translateCloak",i),i.displayName="translateCloakDirective",angular.module("pascalprecht.translate").directive("translateNamespace",s),s.displayName="translateNamespaceDirective",angular.module("pascalprecht.translate").directive("translateLanguage",o),o.displayName="translateLanguageDirective",angular.module("pascalprecht.translate").filter("translate",l),l.displayName="translateFilterFactory",angular.module("pascalprecht.translate").factory("$translationCache",u),u.displayName="$translationCache","pascalprecht.translate"});
\ No newline at end of file
{
"_from": "angular-translate@2.18.2",
"_id": "angular-translate@2.18.2",
"_inBundle": false,
"_integrity": "sha512-aAtNieh0fUv6yM6vKuWsdswT0BbOf6kvsu+QZ15Fp10rKEienMs3M8aPWyd9IVZ5pA1GaRJir6T8OvWGG4J+Fw==",
"_location": "/angular-translate",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "angular-translate@2.18.2",
"name": "angular-translate",
"escapedName": "angular-translate",
"rawSpec": "2.18.2",
"saveSpec": null,
"fetchSpec": "2.18.2"
},
"_requiredBy": [
"/",
"/angular-translate-loader-url"
],
"_resolved": "https://registry.npmjs.org/angular-translate/-/angular-translate-2.18.2.tgz",
"_shasum": "2a26653d179f7043c0ffa66fdf65155d01c82e06",
"_spec": "angular-translate@2.18.2",
"_where": "/home/abstractj/github/keycloak/keycloak-server-pull-requests/themes/src/main/resources/theme/keycloak/common/resources",
"author": {
"name": "Pascal Precht"
},
"bugs": {
"url": "https://github.com/angular-translate/angular-translate/issues"
},
"bundleDependencies": false,
"contributors": [
{
"name": "Jan Philipp",
"email": "knallisworld@googlemail.com",
"url": "https://github.com/knalli"
},
{
"name": "Max Prichinenko"
},
{
"name": "Thorsten S"
}
],
"dependencies": {
"angular": "^1.7.9"
},
"deprecated": false,
"description": "A translation module for AngularJS",
"devDependencies": {
"adm-zip": "^0.4.13",
"body-parser": "^1.19.0",
"bower": "^1.8.8",
"errorhandler": "^1.5.1",
"express": "^4.17.1",
"express-session": "^1.17.0",
"fbjs-scripts": "^0.8.3",
"fsevents": "^1.2.11",
"grunt": "^1.0.4",
"grunt-bower-install-simple": "1.2.4",
"grunt-bump": "^0.8.0",
"grunt-cli": "^1.3.2",
"grunt-contrib-clean": "^1.0.0",
"grunt-contrib-concat": "^1.0.0",
"grunt-contrib-copy": "^1.0.0",
"grunt-contrib-jshint": "^1.0.0",
"grunt-contrib-uglify": "^3.4.0",
"grunt-contrib-watch": "^1.1.0",
"grunt-conventional-changelog": "^6.1.0",
"grunt-file-append": "0.0.7",
"grunt-karma": "^2.0.0",
"grunt-ng-annotate": "^3.0.0",
"grunt-ngdocs": "^0.2.11",
"grunt-parallel": "^0.5.1",
"grunt-umd": "^2.3.3",
"grunt-version": "^1.3.2",
"inquirer": "^3.0.1",
"jasmine-core": "^2.99.1",
"karma": "^1.3.0",
"karma-chrome-launcher": "^2.0.0",
"karma-coverage": "^1.1.2",
"karma-firefox-launcher": "~1.0.0",
"karma-jasmine": "^1.1.2",
"karma-phantomjs-launcher": "^1.0.0",
"load-grunt-tasks": "^3.4.1",
"method-override": "^2.3.7",
"morgan": "^1.9.1",
"multer": "^1.4.2",
"phantomjs-prebuilt": "^2.1.16",
"plato": "^1.5.0",
"publish-release": "^1.6.1",
"pug": "^2.0.4",
"serve-favicon": "^2.5.0",
"tar": "^4.4.13"
},
"devEngines": {
"node": ">=12.14",
"npm": ">=6.13"
},
"engines": {
"node": "*"
},
"homepage": "https://github.com/angular-translate/angular-translate#readme",
"keywords": [
"angular-translate",
"angular",
"AngularJS",
"translation"
],
"license": "MIT",
"main": "dist/angular-translate.js",
"name": "angular-translate",
"repository": {
"type": "git",
"url": "git+ssh://git@github.com/angular-translate/angular-translate.git"
},
"scripts": {
"build": "npm run-script -s check-env && grunt build",
"build-site": "npm run -s build-site-all-languages; npm run -s build-site-plato-report",
"build-site-all-languages": "./build_tools/generate_site.sh",
"build-site-by-language": "./build_tools/generate_site_by_language.sh",
"build-site-plato-report": "rm -rf ./site/plato && plato -d plato -l .jshintrc src/*.js src/**/*.js && mv plato site",
"check-env": "node node_modules/fbjs-scripts/node/check-dev-engines.js package.json",
"clean-test-scopes": "for f in test_scopes/*; do (cd $f; rm -rf bower_components); done",
"compile": "npm run-script -s check-env && grunt compile",
"lint": "grunt lint",
"prepare": "bower install",
"shipit": "npm run-script -s check-env && bower install && bower update && grunt prepare-release",
"start-demo": "node build_tools/server.js",
"test": "npm run-script -s check-env && grunt install-test && grunt test",
"test-headless": "npm run-script -s check-env && grunt test-headless",
"test-scopes": "npm run-script -s check-env && grunt install-test && for f in test_scopes/*; do TEST_SCOPE=\"`basename $f`\" grunt test; done",
"upload-github-release": "node build_tools/upload-github-release.js"
},
"version": "2.18.2"
}
# Logs
logs
*.log
npm-debug.log*
# Runtime data
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules
jspm_packages
# Optional npm cache directory
.npm
# Optional REPL history
.node_repl_history
.idea
MIT License
Copyright (c) 2016 it-ailen
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# angular-treeview
\ No newline at end of file
/**
* Created by hyku on 16/9/29.
*/
var path = require("path");
var webpack = require("webpack");
var config = {
entry: {
tree: "./src/tree.js"
},
output: {
path: path.resolve(__dirname, ".."),
filename: "[name].js"
},
// resolve: {
// root: path.resolve(__dirname, "./src")
// },
module: {
loaders: [
{
test: /\.less$/i,
loaders: ["style", "css", "less"]
},
{
test: /\.html$/i,
loaders: ["html"]
},
{
test: /\.css$/i,
loaders: ["style", "css"]
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
loader: "url-loader?limit=10000&name=images/[name].[ext]"
},
{
test: /\.(ttf|eot|woff2?)$/,
loader: 'file?name=etc/[name].[ext]'
}
]
},
plugins: [
new webpack.optimize.DedupePlugin(),
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery"
}),
new webpack.optimize.OccurenceOrderPlugin()
]
};
module.exports = config;
common/resources/node_modules/angular-treeview/images/plus.png

14.4 KiB

/**
* Created by hyku on 2016/10/13.
*/
"use strict";
require("./tree");
module.exports = "angular.tree";
{
"_from": "angular-treeview@0.1.5",
"_id": "angular-treeview@0.1.5",
"_inBundle": false,
"_integrity": "sha1-7Hl9TQAbIBcsmD5l2FXrzYFStPo=",
"_location": "/angular-treeview",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "angular-treeview@0.1.5",
"name": "angular-treeview",
"escapedName": "angular-treeview",
"rawSpec": "0.1.5",
"saveSpec": null,
"fetchSpec": "0.1.5"
},
"_requiredBy": [
"/"
],
"_resolved": "https://registry.npmjs.org/angular-treeview/-/angular-treeview-0.1.5.tgz",
"_shasum": "ec797d4d001b20172c983e65d855ebcd8152b4fa",
"_spec": "angular-treeview@0.1.5",
"_where": "/home/abstractj/github/keycloak/keycloak-server-pull-requests/themes/src/main/resources/theme/keycloak/common/resources",
"author": {
"name": "Allen Zou"
},
"bugs": {
"url": "https://github.com/it-ailen/angular-treeview/issues"
},
"bundleDependencies": false,
"deprecated": false,
"description": "Treeview with angular.",
"devDependencies": {
"css-loader": "^0.25.0",
"html-loader": "^0.4.4",
"less": "^2.7.1",
"less-loader": "^2.2.3",
"style-loader": "^0.13.1",
"url-loader": "^0.5.7",
"webpack": "^1.13.2"
},
"homepage": "https://github.com/it-ailen/angular-treeview#readme",
"keywords": [
"angular",
"treeview"
],
"license": "MIT",
"main": "index.js",
"name": "angular-treeview",
"repository": {
"type": "git",
"url": "git+https://github.com/it-ailen/angular-treeview.git"
},
"scripts": {
"build": "webpack --config build/webpack.config.base.js"
},
"version": "0.1.5"
}