2016-03-28 03:46:51 -07:00
/ * !
* angular - translate - v2 . 9.0 - 2016 - 01 - 24
*
* Copyright ( c ) 2016 The angular - translate team , Pascal Precht ; Licensed MIT
2016-05-17 17:10:50 -07:00
*
* 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 .
*
2016-03-28 03:46:51 -07:00
* /
( function ( root , factory ) {
if ( typeof define === 'function' && define . amd ) {
// AMD. Register as an anonymous module unless amdModuleId is set
define ( [ ] , function ( ) {
return ( factory ( ) ) ;
} ) ;
} else if ( typeof exports === 'object' ) {
// Node. Does not work with strict CommonJS, but
// only CommonJS-like environments that support module.exports,
// like Node.
module . exports = factory ( ) ;
} else {
factory ( ) ;
}
} ( this , function ( ) {
/ * *
* @ ngdoc overview
* @ name pascalprecht . translate
*
* @ description
* The main module which holds everything together .
* /
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 . $inject = [ '$translate' ] ;
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 ,
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 < / d t >
* < dd > Sanitizes HTML in the translation text using $sanitize < / d d >
* < dt > escape < / d t >
* < dd > Escapes HTML in the translation < / d d >
* < dt > sanitizeParameters < / d t >
* < dd > Sanitizes HTML in the values of the interpolation parameters using $sanitize < / d d >
* < dt > escapeParameters < / d t >
* < dd > Escapes HTML in the values of the interpolation parameters < / d d >
* < dt > escaped < / d t >
* < dd > Support legacy strategy name 'escaped' for backwards compatibility ( will be removed in 3.0 ) < / d d >
* < / d l >
*
* /
strategies = {
sanitize : function ( value , mode ) {
if ( mode === 'text' ) {
value = htmlSanitizeValue ( value ) ;
}
return value ;
} ,
escape : function ( value , mode ) {
if ( mode === 'text' ) {
value = htmlEscapeValue ( value ) ;
}
return value ;
} ,
sanitizeParameters : function ( value , mode ) {
if ( mode === 'params' ) {
value = mapInterpolationParameters ( value , htmlSanitizeValue ) ;
}
return value ;
} ,
escapeParameters : function ( value , mode ) {
if ( mode === 'params' ) {
value = mapInterpolationParameters ( value , htmlEscapeValue ) ;
}
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 , selectedStrategies ) {
angular . forEach ( selectedStrategies , function ( selectedStrategy ) {
if ( angular . isFunction ( selectedStrategy ) ) {
value = selectedStrategy ( value , mode ) ;
} else if ( angular . isFunction ( strategies [ selectedStrategy ] ) ) {
value = strategies [ selectedStrategy ] ( value , mode ) ;
} 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 ) ;
} 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' ) ;
}
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 .
* @ returns { string | object } sanitized value
* /
sanitize : function ( value , mode , strategy ) {
if ( ! currentStrategy ) {
showNoStrategyConfiguredWarning ( ) ;
}
if ( arguments . length < 3 ) {
strategy = currentStrategy ;
}
if ( ! strategy ) {
return value ;
}
var selectedStrategies = angular . isArray ( strategy ) ? strategy : [ strategy ] ;
return applyStrategies ( value , mode , 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 mapInterpolationParameters = function ( value , iteratee ) {
if ( angular . isObject ( value ) ) {
var result = angular . isArray ( value ) ? [ ] : { } ;
angular . forEach ( value , function ( propertyValue , propertyKey ) {
result [ propertyKey ] = mapInterpolationParameters ( propertyValue , iteratee ) ;
} ) ;
return result ;
} else if ( angular . isNumber ( value ) ) {
return value ;
} else {
return iteratee ( value ) ;
}
} ;
}
/ * *
* @ ngdoc object
* @ name pascalprecht . translate . $translateProvider
* @ description
*
* $translateProvider allows developers to register translation - tables , asynchronous loaders
* and similar to configure translation behavior directly inside of a module .
*
* /
angular . module ( 'pascalprecht.translate' )
. constant ( 'pascalprechtTranslateOverrider' , { } )
. provider ( '$translate' , $translate ) ;
function $translate ( $STORAGE _KEY , $windowProvider , $translateSanitizationProvider , pascalprechtTranslateOverrider ) {
'use strict' ;
var $translationTable = { } ,
$preferredLanguage ,
$availableLanguageKeys = [ ] ,
$languageKeyAliases ,
$fallbackLanguage ,
$fallbackWasString ,
$uses ,
$nextLang ,
$storageFactory ,
$storageKey = $STORAGE _KEY ,
$storagePrefix ,
$missingTranslationHandlerFactory ,
$interpolationFactory ,
$interpolatorFactories = [ ] ,
$loaderFactory ,
$cloakClassName = 'translate-cloak' ,
$loaderOptions ,
$notFoundIndicatorLeft ,
$notFoundIndicatorRight ,
$postCompilingEnabled = false ,
$forceAsyncReloadEnabled = false ,
$nestedObjectDelimeter = '.' ,
$isReady = false ,
loaderCache ,
directivePriority = 0 ,
statefulFilter = true ,
uniformLanguageTagResolver = 'default' ,
languageTagResolver = {
'default' : function ( tag ) {
return ( tag || '' ) . split ( '-' ) . join ( '_' ) ;
} ,
java : function ( tag ) {
var temp = ( tag || '' ) . split ( '-' ) . join ( '_' ) ;
var parts = temp . split ( '_' ) ;
return parts . length > 1 ? ( parts [ 0 ] . toLowerCase ( ) + '_' + parts [ 1 ] . toUpperCase ( ) ) : temp ;
} ,
bcp47 : function ( tag ) {
var temp = ( tag || '' ) . split ( '_' ) . join ( '-' ) ;
var parts = temp . split ( '-' ) ;
return parts . length > 1 ? ( parts [ 0 ] . toLowerCase ( ) + '-' + parts [ 1 ] . toUpperCase ( ) ) : temp ;
}
} ;
var version = '2.9.0' ;
// tries to determine the browsers language
var getFirstBrowserLanguage = function ( ) {
// internal purpose only
if ( angular . isFunction ( pascalprechtTranslateOverrider . getLocale ) ) {
return pascalprechtTranslateOverrider . getLocale ( ) ;
}
var nav = $windowProvider . $get ( ) . navigator ,
browserLanguagePropertyKeys = [ 'language' , 'browserLanguage' , 'systemLanguage' , 'userLanguage' ] ,
i ,
language ;
// support for HTML 5.1 "navigator.languages"
if ( angular . isArray ( nav . languages ) ) {
for ( i = 0 ; i < nav . languages . length ; i ++ ) {
language = nav . languages [ i ] ;
if ( language && language . length ) {
return language ;
}
}
}
// support for other well known properties in browsers
for ( i = 0 ; i < browserLanguagePropertyKeys . length ; i ++ ) {
language = nav [ browserLanguagePropertyKeys [ i ] ] ;
if ( language && language . length ) {
return language ;
}
}
return null ;
} ;
getFirstBrowserLanguage . displayName = 'angular-translate/service: getFirstBrowserLanguage' ;
// tries to determine the browsers locale
var getLocale = function ( ) {
var locale = getFirstBrowserLanguage ( ) || '' ;
if ( languageTagResolver [ uniformLanguageTagResolver ] ) {
locale = languageTagResolver [ uniformLanguageTagResolver ] ( locale ) ;
}
return locale ;
} ;
getLocale . displayName = 'angular-translate/service: getLocale' ;
/ * *
* @ name indexOf
* @ private
*
* @ description
* indexOf polyfill . Kinda sorta .
*
* @ param { array } array Array to search in .
* @ param { string } searchElement Element to search for .
*
* @ returns { int } Index of search element .
* /
var indexOf = function ( array , searchElement ) {
for ( var i = 0 , len = array . length ; i < len ; i ++ ) {
if ( array [ i ] === searchElement ) {
return i ;
}
}
return - 1 ;
} ;
/ * *
* @ name trim
* @ private
*
* @ description
* trim polyfill
*
* @ returns { string } The string stripped of whitespace from both ends
* /
var trim = function ( ) {
return this . toString ( ) . replace ( /^\s+|\s+$/g , '' ) ;
} ;
var negotiateLocale = function ( preferred ) {
if ( ! preferred ) {
return ;
}
var avail = [ ] ,
locale = angular . lowercase ( preferred ) ,
i = 0 ,
n = $availableLanguageKeys . length ;
for ( ; i < n ; i ++ ) {
avail . push ( angular . lowercase ( $availableLanguageKeys [ i ] ) ) ;
}
// Check for an exact match in our list of available keys
if ( indexOf ( avail , locale ) > - 1 ) {
return preferred ;
}
if ( $languageKeyAliases ) {
var alias ;
for ( var langKeyAlias in $languageKeyAliases ) {
var hasWildcardKey = false ;
var hasExactKey = Object . prototype . hasOwnProperty . call ( $languageKeyAliases , langKeyAlias ) &&
angular . lowercase ( langKeyAlias ) === angular . lowercase ( preferred ) ;
if ( langKeyAlias . slice ( - 1 ) === '*' ) {
hasWildcardKey = langKeyAlias . slice ( 0 , - 1 ) === preferred . slice ( 0 , langKeyAlias . length - 1 ) ;
}
if ( hasExactKey || hasWildcardKey ) {
alias = $languageKeyAliases [ langKeyAlias ] ;
if ( indexOf ( avail , angular . lowercase ( alias ) ) > - 1 ) {
return alias ;
}
}
}
}
// Check for a language code without region
var parts = preferred . split ( '_' ) ;
if ( parts . length > 1 && indexOf ( avail , angular . lowercase ( parts [ 0 ] ) ) > - 1 ) {
return parts [ 0 ] ;
}
// If everything fails, return undefined.
return ;
} ;
/ * *
* @ ngdoc function
* @ name pascalprecht . translate . $translateProvider # translations
* @ methodOf pascalprecht . translate . $translateProvider
*
* @ description
* Registers a new translation table for specific language key .
*
* To register a translation table for specific language , pass a defined language
* key as first parameter .
*
* < pre >
* // register translation table for language: 'de_DE'
* $translateProvider . translations ( 'de_DE' , {
* 'GREETING' : 'Hallo Welt!'
* } ) ;
*
* // register another one
* $translateProvider . translations ( 'en_US' , {
* 'GREETING' : 'Hello world!'
* } ) ;
* < / p r e >
*
* 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 } key A language key .
* @ param { object } translationTable A plain old JavaScript object that represents a translation table .
*
* /
var translations = function ( langKey , translationTable ) {
if ( ! langKey && ! translationTable ) {
return $translationTable ;
}
if ( langKey && ! translationTable ) {
if ( angular . isString ( langKey ) ) {
return $translationTable [ langKey ] ;
}
} else {
if ( ! angular . isObject ( $translationTable [ langKey ] ) ) {
$translationTable [ langKey ] = { } ;
}
angular . extend ( $translationTable [ langKey ] , flatObject ( translationTable ) ) ;
}
return this ;
} ;
this . translations = translations ;
/ * *
* @ ngdoc function
* @ name pascalprecht . translate . $translateProvider # cloakClassName
* @ methodOf pascalprecht . translate . $translateProvider
*
* @ description
*
* Let ' s you change the class name for ` translate-cloak ` directive .
* Default class name is ` translate-cloak ` .
*
* @ param { string } name translate - cloak class name
* /
this . cloakClassName = function ( name ) {
if ( ! name ) {
return $cloakClassName ;
}
$cloakClassName = name ;
return this ;
} ;
/ * *
* @ ngdoc function
* @ name pascalprecht . translate . $translateProvider # nestedObjectDelimeter
* @ methodOf pascalprecht . translate . $translateProvider
*
* @ description
*
* Let ' s you change the delimiter for namespaced translations .
* Default delimiter is ` . ` .
*
* @ param { string } delimiter namespace separator
* /
this . nestedObjectDelimeter = function ( delimiter ) {
if ( ! delimiter ) {
return $nestedObjectDelimeter ;
}
$nestedObjectDelimeter = delimiter ;
return this ;
} ;
/ * *
* @ name flatObject
* @ private
*
* @ description
* Flats an object . This function is used to flatten given translation data with
* namespaces , so they are later accessible via dot notation .
* /
var flatObject = function ( data , path , result , prevKey ) {
var key , keyWithPath , keyWithShortPath , val ;
if ( ! path ) {
path = [ ] ;
}
if ( ! result ) {
result = { } ;
}
for ( key in data ) {
if ( ! Object . prototype . hasOwnProperty . call ( data , key ) ) {
continue ;
}
val = data [ key ] ;
if ( angular . isObject ( val ) ) {
flatObject ( val , path . concat ( key ) , result , key ) ;
} else {
keyWithPath = path . length ? ( '' + path . join ( $nestedObjectDelimeter ) + $nestedObjectDelimeter + key ) : key ;
if ( path . length && key === prevKey ) {
// Create shortcut path (foo.bar == foo.bar.bar)
keyWithShortPath = '' + path . join ( $nestedObjectDelimeter ) ;
// Link it to original path
result [ keyWithShortPath ] = '@:' + keyWithPath ;
}
result [ keyWithPath ] = val ;
}
}
return result ;
} ;
flatObject . displayName = 'flatObject' ;
/ * *
* @ ngdoc function
* @ name pascalprecht . translate . $translateProvider # addInterpolation
* @ methodOf pascalprecht . translate . $translateProvider
*
* @ description
* Adds interpolation services to angular - translate , so it can manage them .
*
* @ param { object } factory Interpolation service factory
* /
this . addInterpolation = function ( factory ) {
$interpolatorFactories . push ( factory ) ;
return this ;
} ;
/ * *
* @ ngdoc function
* @ name pascalprecht . translate . $translateProvider # useMessageFormatInterpolation
* @ methodOf pascalprecht . translate . $translateProvider
*
* @ description
* Tells angular - translate to use interpolation functionality of messageformat . js .
* This is useful when having high level pluralization and gender selection .
* /
this . useMessageFormatInterpolation = function ( ) {
return this . useInterpolation ( '$translateMessageFormatInterpolation' ) ;
} ;
/ * *
* @ ngdoc function
* @ name pascalprecht . translate . $translateProvider # useInterpolation
* @ methodOf pascalprecht . translate . $translateProvider
*
* @ description
* Tells angular - translate which interpolation style to use as default , application - wide .
* Simply pass a factory / service name . The interpolation service has to implement
* the correct interface .
*
* @ param { string } factory Interpolation service name .
* /
this . useInterpolation = function ( factory ) {
$interpolationFactory = factory ;
return this ;
} ;
/ * *
* @ ngdoc function
* @ name pascalprecht . translate . $translateProvider # useSanitizeStrategy
* @ methodOf pascalprecht . translate . $translateProvider
*
* @ description
* Simply sets a sanitation strategy type .
*
* @ param { string } value Strategy type .
* /
this . useSanitizeValueStrategy = function ( value ) {
$translateSanitizationProvider . useStrategy ( value ) ;
return this ;
} ;
/ * *
* @ ngdoc function
* @ name pascalprecht . translate . $translateProvider # preferredLanguage
* @ methodOf pascalprecht . translate . $translateProvider
*
* @ description
* Tells the module which of the registered translation tables to use for translation
* at initial startup by passing a language key . Similar to ` $ translateProvider#use `
* only that it says which language to * * prefer * * .
*
* @ param { string } langKey A language key .
* /
this . preferredLanguage = function ( langKey ) {
if ( langKey ) {
setupPreferredLanguage ( langKey ) ;
return this ;
}
return $preferredLanguage ;
} ;
var setupPreferredLanguage = function ( langKey ) {
if ( langKey ) {
$preferredLanguage = langKey ;
}
return $preferredLanguage ;
} ;
/ * *
* @ ngdoc function
* @ name pascalprecht . translate . $translateProvider # translationNotFoundIndicator
* @ methodOf pascalprecht . translate . $translateProvider
*
* @ description
* Sets an indicator which is used when a translation isn ' t found . E . g . when
* setting the indicator as 'X' and one tries to translate a translation id
* called ` NOT_FOUND ` , this will result in ` X NOT_FOUND X ` .
*
* Internally this methods sets a left indicator and a right indicator using
* ` $ translateProvider.translationNotFoundIndicatorLeft() ` and
* ` $ translateProvider.translationNotFoundIndicatorRight() ` .
*
* * * Note * * : These methods automatically add a whitespace between the indicators
* and the translation id .
*
* @ param { string } indicator An indicator , could be any string .
* /
this . translationNotFoundIndicator = function ( indicator ) {
this . translationNotFoundIndicatorLeft ( indicator ) ;
this . translationNotFoundIndicatorRight ( indicator ) ;
return this ;
} ;
/ * *
* ngdoc function
* @ name pascalprecht . translate . $translateProvider # translationNotFoundIndicatorLeft
* @ methodOf pascalprecht . translate . $translateProvider
*
* @ description
* Sets an indicator which is used when a translation isn ' t found left to the
* translation id .
*
* @ param { string } indicator An indicator .
* /
this . translationNotFoundIndicatorLeft = function ( indicator ) {
if ( ! indicator ) {
return $notFoundIndicatorLeft ;
}
$notFoundIndicatorLeft = indicator ;
return this ;
} ;
/ * *
* ngdoc function
* @ name pascalprecht . translate . $translateProvider # translationNotFoundIndicatorLeft
* @ methodOf pascalprecht . translate . $translateProvider
*
* @ description
* Sets an indicator which is used when a translation isn ' t found right to the
* translation id .
*
* @ param { string } indicator An indicator .
* /
this . translationNotFoundIndicatorRight = function ( indicator ) {
if ( ! indicator ) {
return $notFoundIndicatorRight ;
}
$notFoundIndicatorRight = indicator ;
return this ;
} ;
/ * *
* @ ngdoc function
* @ name pascalprecht . translate . $translateProvider # fallbackLanguage
* @ methodOf pascalprecht . translate . $translateProvider
*
* @ description
* Tells the module which of the registered translation tables to use when missing translations
* at initial startup by passing a language key . Similar to ` $ translateProvider#use `
* only that it says which language to * * fallback * * .
*
* @ param { string || array } langKey A language key .
*
* /
this . fallbackLanguage = function ( langKey ) {
fallbackStack ( langKey ) ;
return this ;
} ;
var fallbackStack = function ( langKey ) {
if ( langKey ) {
if ( angular . isString ( langKey ) ) {
$fallbackWasString = true ;
$fallbackLanguage = [ langKey ] ;
} else if ( angular . isArray ( langKey ) ) {
$fallbackWasString = false ;
$fallbackLanguage = langKey ;
}
if ( angular . isString ( $preferredLanguage ) && indexOf ( $fallbackLanguage , $preferredLanguage ) < 0 ) {
$fallbackLanguage . push ( $preferredLanguage ) ;
}
return this ;
} else {
if ( $fallbackWasString ) {
return $fallbackLanguage [ 0 ] ;
} else {
return $fallbackLanguage ;
}
}
} ;
/ * *
* @ ngdoc function
* @ name pascalprecht . translate . $translateProvider # use
* @ methodOf pascalprecht . translate . $translateProvider
*
* @ description
* Set which translation table to use for translation by given language key . When
* trying to 'use' a language which isn 't provided, it' ll throw an error .
*
* You actually don ' t have to use this method since ` $ translateProvider#preferredLanguage `
* does the job too .
*
* @ param { string } langKey A language key .
* /
this . use = function ( langKey ) {
if ( langKey ) {
if ( ! $translationTable [ langKey ] && ( ! $loaderFactory ) ) {
// only throw an error, when not loading translation data asynchronously
throw new Error ( '$translateProvider couldn\'t find translationTable for langKey: \'' + langKey + '\'' ) ;
}
$uses = langKey ;
return this ;
}
return $uses ;
} ;
/ * *
* @ ngdoc function
* @ name pascalprecht . translate . $translateProvider # 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
* } ;
* } ) ;
* < / p r e >
*
* @ 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 ) ;
* } ) ;
* < / p r e >
*
* @ 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 ) ;
* } ) ;
* < / p r e >
*
* @ 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 ( )
* < / p r e >
*
* The resolver currently supports :
* * default
* ( traditionally : hyphens will be converted into underscores , i . e . en - US => en _US )
* en - US => en _US
* en _US => en _US
* en - us => en _us
* * java
* like default , but the second part will be always in uppercase
* en - US => en _US
* en _US => en _US
* en - us => en _US
* * BCP 47 ( RFC 4646 & 4647 )
* en - US => en - US
* en _US => en - US
* en - us => en - US
*
* See also :
* * http : //en.wikipedia.org/wiki/IETF_language_tag
* * http : //www.w3.org/International/core/langtags/
* * http : //tools.ietf.org/html/bcp47
*
* @ param { string | object } options - options ( or standard )
* @ param { string } options . standard - valid values are 'default' , 'bcp47' , 'java'
* /
this . uniformLanguageTag = function ( options ) {
if ( ! options ) {
options = { } ;
} else if ( angular . isString ( options ) ) {
options = {
standard : options
} ;
}
uniformLanguageTagResolver = options . standard ;
return this ;
} ;
/ * *
* @ ngdoc function
* @ name pascalprecht . translate . $translateProvider # determinePreferredLanguage
* @ methodOf pascalprecht . translate . $translateProvider
*
* @ description
* Tells angular - translate to try to determine on its own which language key
* to set as preferred language . When ` fn ` is given , angular - translate uses it
* to determine a language key , otherwise it uses the built - in ` getLocale() `
* method .
*
* The ` getLocale() ` returns a language key in the format ` [lang]_[country] ` or
* ` [lang] ` depending on what the browser provides .
*
* Use this method at your own risk , since not all browsers return a valid
* locale ( see { @ link pascalprecht . translate . $translateProvider # methods _uniformLanguageTag uniformLanguageTag ( ) } ) .
*
* @ param { Function = } fn Function to determine a browser ' s locale
* /
this . determinePreferredLanguage = function ( fn ) {
var locale = ( fn && angular . isFunction ( fn ) ) ? fn ( ) : getLocale ( ) ;
if ( ! $availableLanguageKeys . length ) {
$preferredLanguage = locale ;
} else {
$preferredLanguage = negotiateLocale ( locale ) || locale ;
}
return this ;
} ;
/ * *
* @ ngdoc function
* @ name pascalprecht . translate . $translateProvider # registerAvailableLanguageKeys
* @ methodOf pascalprecht . translate . $translateProvider
*
* @ description
* Registers a set of language keys the app will work with . Use this method in
* combination with
* { @ link pascalprecht . translate . $translateProvider # determinePreferredLanguage determinePreferredLanguage } .
* When available languages keys are registered , angular - translate
* tries to find the best fitting language key depending on the browsers locale ,
* considering your language key convention .
*
* @ param { object } languageKeys Array of language keys the your app will use
* @ param { object = } aliases Alias map .
* /
this . registerAvailableLanguageKeys = function ( languageKeys , aliases ) {
if ( languageKeys ) {
$availableLanguageKeys = languageKeys ;
if ( aliases ) {
$languageKeyAliases = aliases ;
}
return this ;
}
return $availableLanguageKeys ;
} ;
/ * *
* @ ngdoc function
* @ name pascalprecht . translate . $translateProvider # useLoaderCache
* @ methodOf pascalprecht . translate . $translateProvider
*
* @ description
* Registers a cache for internal $http based loaders .
* { @ link pascalprecht . translate . $translationCache $translationCache } .
* When false the cache will be disabled ( default ) . When true or undefined
* the cache will be a default ( see $cacheFactory ) . When an object it will
* be treat as a cache object itself : the usage is $http ( { cache : cache } )
*
* @ param { object } cache boolean , string or cache - object
* /
this . useLoaderCache = function ( cache ) {
if ( cache === false ) {
// disable cache
loaderCache = undefined ;
} else if ( cache === true ) {
// enable cache using AJS defaults
loaderCache = true ;
} else if ( typeof ( cache ) === 'undefined' ) {
// enable cache using default
loaderCache = '$translationCache' ;
} else if ( cache ) {
// enable cache using given one (see $cacheFactory)
loaderCache = cache ;
}
return this ;
} ;
/ * *
* @ ngdoc function
* @ name pascalprecht . translate . $translateProvider # directivePriority
* @ methodOf pascalprecht . translate . $translateProvider
*
* @ description
* Sets the default priority of the translate directive . The standard value is ` 0 ` .
* Calling this function without an argument will return the current value .
*
* @ param { number } priority for the translate - directive
* /
this . directivePriority = function ( priority ) {
if ( priority === undefined ) {
// getter
return directivePriority ;
} else {
// setter with chaining
directivePriority = priority ;
return this ;
}
} ;
/ * *
* @ ngdoc function
* @ name pascalprecht . translate . $translateProvider # statefulFilter
* @ methodOf pascalprecht . translate . $translateProvider
*
* @ description
* Since AngularJS 1.3 , filters which are not stateless ( depending at the scope )
* have to explicit define this behavior .
* Sets whether the translate filter should be stateful or stateless . The standard value is ` true `
* meaning being stateful .
* Calling this function without an argument will return the current value .
*
* @ param { boolean } state - defines the state of the filter
* /
this . statefulFilter = function ( state ) {
if ( state === undefined ) {
// getter
return statefulFilter ;
} else {
// setter with chaining
statefulFilter = state ;
return this ;
}
} ;
/ * *
* @ ngdoc 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 ;
* } ) ;
* < / p r e >
*
* @ param { string | array } translationId A token which represents a translation id
* This can be optionally an array of translation ids which
* results that the function returns an object where each key
* is the translation id and the value the translation .
* @ param { object = } interpolateParams An object hash for dynamic values
* @ param { string } interpolationId The id of the interpolation to use
* @ param { string } forceLanguage A language to be used instead of the current language
* @ returns { object } promise
* /
this . $get = [
'$log' ,
'$injector' ,
'$rootScope' ,
'$q' ,
function ( $log , $injector , $rootScope , $q ) {
var Storage ,
defaultInterpolator = $injector . get ( $interpolationFactory || '$translateDefaultInterpolation' ) ,
pendingLoader = false ,
interpolatorHashMap = { } ,
langPromises = { } ,
fallbackIndex ,
startFallbackIteration ;
var $translate = function ( translationId , interpolateParams , interpolationId , defaultTranslationText , forceLanguage ) {
var uses = ( forceLanguage && forceLanguage !== $uses ) ? // we don't want to re-negotiate $uses
( negotiateLocale ( forceLanguage ) || forceLanguage ) : $uses ;
// Duck detection: If the first argument is an array, a bunch of translations was requested.
// The result is an object.
if ( angular . isArray ( translationId ) ) {
// Inspired by Q.allSettled by Kris Kowal
// https://github.com/kriskowal/q/blob/b0fa72980717dc202ffc3cbf03b936e10ebbb9d7/q.js#L1553-1563
// This transforms all promises regardless resolved or rejected
var translateAll = function ( translationIds ) {
var results = { } ; // storing the actual results
var promises = [ ] ; // promises to wait for
// Wraps the promise a) being always resolved and b) storing the link id->value
var translate = function ( translationId ) {
var deferred = $q . defer ( ) ;
var regardless = function ( value ) {
results [ translationId ] = value ;
deferred . resolve ( [ translationId , value ] ) ;
} ;
// we don't care whether the promise was resolved or rejected; just store the values
$translate ( translationId , interpolateParams , interpolationId , defaultTranslationText , forceLanguage ) . then ( regardless , regardless ) ;
return deferred . promise ;
} ;
for ( var i = 0 , c = translationIds . length ; i < c ; i ++ ) {
promises . push ( translate ( translationIds [ i ] ) ) ;
}
// wait for all (including storing to results)
return $q . all ( promises ) . then ( function ( ) {
// return the results
return results ;
} ) ;
} ;
return translateAll ( translationId ) ;
}
var deferred = $q . defer ( ) ;
// trim off any whitespace
if ( translationId ) {
translationId = trim . apply ( translationId ) ;
}
var promiseToWaitFor = ( function ( ) {
var promise = $preferredLanguage ?
langPromises [ $preferredLanguage ] :
langPromises [ uses ] ;
fallbackIndex = 0 ;
if ( $storageFactory && ! promise ) {
// looks like there's no pending promise for $preferredLanguage or
// $uses. Maybe there's one pending for a language that comes from
// storage.
var langKey = Storage . get ( $storageKey ) ;
promise = langPromises [ langKey ] ;
if ( $fallbackLanguage && $fallbackLanguage . length ) {
var index = indexOf ( $fallbackLanguage , langKey ) ;
// maybe the language from storage is also defined as fallback language
// we increase the fallback language index to not search in that language
// as fallback, since it's probably the first used language
// in that case the index starts after the first element
fallbackIndex = ( index === 0 ) ? 1 : 0 ;
// but we can make sure to ALWAYS fallback to preferred language at least
if ( indexOf ( $fallbackLanguage , $preferredLanguage ) < 0 ) {
$fallbackLanguage . push ( $preferredLanguage ) ;
}
}
}
return promise ;
} ( ) ) ;
if ( ! promiseToWaitFor ) {
// no promise to wait for? okay. Then there's no loader registered
// nor is a one pending for language that comes from storage.
// We can just translate.
determineTranslation ( translationId , interpolateParams , interpolationId , defaultTranslationText , uses ) . then ( deferred . resolve , deferred . reject ) ;
} else {
var promiseResolved = function ( ) {
// $uses may have changed while waiting
if ( ! forceLanguage ) {
uses = $uses ;
}
determineTranslation ( translationId , interpolateParams , interpolationId , defaultTranslationText , uses ) . then ( deferred . resolve , deferred . reject ) ;
} ;
promiseResolved . displayName = 'promiseResolved' ;
promiseToWaitFor [ 'finally' ] ( promiseResolved , deferred . reject ) ;
}
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 { 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 of 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
* @ returns { Q . promise }
* /
var getFallbackTranslation = function ( langKey , translationId , interpolateParams , Interpolator ) {
var deferred = $q . defer ( ) ;
var onResolve = function ( translationTable ) {
if ( Object . prototype . hasOwnProperty . call ( translationTable , translationId ) ) {
Interpolator . setLocale ( langKey ) ;
var translation = translationTable [ translationId ] ;
if ( translation . substr ( 0 , 2 ) === '@:' ) {
getFallbackTranslation ( langKey , translation . substr ( 2 ) , interpolateParams , Interpolator )
. then ( deferred . resolve , deferred . reject ) ;
} else {
deferred . resolve ( Interpolator . interpolate ( translationTable [ translationId ] , interpolateParams ) ) ;
}
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
* @ returns { string } translation
* /
var getFallbackTranslationInstant = function ( langKey , translationId , interpolateParams , Interpolator ) {
var result , translationTable = $translationTable [ langKey ] ;
if ( translationTable && Object . prototype . hasOwnProperty . call ( translationTable , translationId ) ) {
Interpolator . setLocale ( langKey ) ;
result = Interpolator . interpolate ( translationTable [ translationId ] , interpolateParams ) ;
if ( result . substr ( 0 , 2 ) === '@:' ) {
return getFallbackTranslationInstant ( langKey , result . substr ( 2 ) , interpolateParams , Interpolator ) ;
}
Interpolator . setLocale ( $uses ) ;
}
return result ;
} ;
/ * *
* @ name translateByHandler
* @ private
*
* Translate by missing translation handler .
*
* @ param translationId
* @ returns translation created by $missingTranslationHandler or translationId is $missingTranslationHandler is
* absent
* /
var translateByHandler = function ( translationId , interpolateParams ) {
// 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 ) {
var resultString = $injector . get ( $missingTranslationHandlerFactory ) ( translationId , $uses , interpolateParams ) ;
if ( resultString !== undefined ) {
return resultString ;
} else {
return translationId ;
}
} 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
* @ returns { Q . promise } Promise that will resolve to the translation .
* /
var resolveForFallbackLanguage = function ( fallbackLanguageIndex , translationId , interpolateParams , Interpolator , defaultTranslationText ) {
var deferred = $q . defer ( ) ;
if ( fallbackLanguageIndex < $fallbackLanguage . length ) {
var langKey = $fallbackLanguage [ fallbackLanguageIndex ] ;
getFallbackTranslation ( langKey , translationId , interpolateParams , Interpolator ) . then (
deferred . resolve ,
function ( ) {
// Look in the next fallback language for a translation.
// It delays the resolving by passing another promise to resolve.
resolveForFallbackLanguage ( fallbackLanguageIndex + 1 , translationId , interpolateParams , Interpolator , defaultTranslationText ) . then ( deferred . resolve ) ;
}
) ;
} 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 {
// if no default translation is set and an error handler is defined, send it to the handler
// and then return the result
deferred . resolve ( translateByHandler ( translationId , interpolateParams ) ) ;
}
}
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
* @ returns { string } translation
* /
var resolveForFallbackLanguageInstant = function ( fallbackLanguageIndex , translationId , interpolateParams , Interpolator ) {
var result ;
if ( fallbackLanguageIndex < $fallbackLanguage . length ) {
var langKey = $fallbackLanguage [ fallbackLanguageIndex ] ;
result = getFallbackTranslationInstant ( langKey , translationId , interpolateParams , Interpolator ) ;
if ( ! result ) {
result = resolveForFallbackLanguageInstant ( fallbackLanguageIndex + 1 , translationId , interpolateParams , Interpolator ) ;
}
}
return result ;
} ;
/ * *
* Translates with the usage of the fallback languages .
*
* @ param translationId
* @ param interpolateParams
* @ param Interpolator
* @ returns { Q . promise } Promise , that resolves to the translation .
* /
var fallbackTranslation = function ( translationId , interpolateParams , Interpolator , defaultTranslationText ) {
// Start with the fallbackLanguage with index 0
return resolveForFallbackLanguage ( ( startFallbackIteration > 0 ? startFallbackIteration : fallbackIndex ) , translationId , interpolateParams , Interpolator , defaultTranslationText ) ;
} ;
/ * *
* Translates with the usage of the fallback languages .
*
* @ param translationId
* @ param interpolateParams
* @ param Interpolator
* @ returns { String } translation
* /
var fallbackTranslationInstant = function ( translationId , interpolateParams , Interpolator ) {
// Start with the fallbackLanguage with index 0
return resolveForFallbackLanguageInstant ( ( startFallbackIteration > 0 ? startFallbackIteration : fallbackIndex ) , translationId , interpolateParams , Interpolator ) ;
} ;
var determineTranslation = function ( translationId , interpolateParams , interpolationId , defaultTranslationText , uses ) {
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 ) ) {
var translation = table [ translationId ] ;
// If using link, rerun $translate with linked translationId and return it
if ( translation . substr ( 0 , 2 ) === '@:' ) {
$translate ( translation . substr ( 2 ) , interpolateParams , interpolationId , defaultTranslationText , uses )
. then ( deferred . resolve , deferred . reject ) ;
} else {
deferred . resolve ( Interpolator . interpolate ( translation , interpolateParams ) ) ;
}
} else {
var missingTranslationHandlerTranslation ;
// for logging purposes only (as in $translateMissingTranslationHandlerLog), value is not returned to promise
if ( $missingTranslationHandlerFactory && ! pendingLoader ) {
missingTranslationHandlerTranslation = translateByHandler ( translationId , interpolateParams ) ;
}
// 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 )
. 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 ) {
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 ) ) {
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 ) ;
} else {
result = Interpolator . interpolate ( translation , interpolateParams ) ;
}
} else {
var missingTranslationHandlerTranslation ;
// for logging purposes only (as in $translateMissingTranslationHandlerLog), value is not returned to promise
if ( $missingTranslationHandlerFactory && ! pendingLoader ) {
missingTranslationHandlerTranslation = translateByHandler ( translationId , interpolateParams ) ;
}
// 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 ) ;
} 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 ;
} ;
/ * *
* @ ngdoc function
* @ name pascalprecht . translate . $translate # preferredLanguage
* @ methodOf pascalprecht . translate . $translate
*
* @ description
* Returns the language key for the preferred language .
*
* @ param { string } langKey language String or Array to be used as preferredLanguage ( changing at runtime )
*
* @ return { string } preferred language key
* /
$translate . preferredLanguage = function ( langKey ) {
if ( langKey ) {
setupPreferredLanguage ( langKey ) ;
}
return $preferredLanguage ;
} ;
/ * *
* @ ngdoc function
* @ name pascalprecht . translate . $translate # cloakClassName
* @ methodOf pascalprecht . translate . $translate
*
* @ description
* Returns the configured class name for ` translate-cloak ` directive .
*
* @ return { string } cloakClassName
* /
$translate . cloakClassName = function ( ) {
return $cloakClassName ;
} ;
/ * *
* @ ngdoc function
* @ name pascalprecht . translate . $translate # nestedObjectDelimeter
* @ methodOf pascalprecht . translate . $translate
*
* @ description
* Returns the configured delimiter for nested namespaces .
*
* @ return { string } nestedObjectDelimeter
* /
$translate . nestedObjectDelimeter = function ( ) {
return $nestedObjectDelimeter ;
} ;
/ * *
* @ ngdoc function
* @ name pascalprecht . translate . $translate # fallbackLanguage
* @ methodOf pascalprecht . translate . $translate
*
* @ description
* Returns the language key for the fallback languages or sets a new fallback stack .
*
* @ param { string = } langKey language String or Array of fallback languages to be used ( to change stack at runtime )
*
* @ return { string || array } fallback language key
* /
$translate . fallbackLanguage = function ( langKey ) {
if ( langKey !== undefined && langKey !== null ) {
fallbackStack ( langKey ) ;
// as we might have an async loader initiated and a new translation language might have been defined
// we need to add the promise to the stack also. So - iterate.
if ( $loaderFactory ) {
if ( $fallbackLanguage && $fallbackLanguage . length ) {
for ( var i = 0 , len = $fallbackLanguage . length ; i < len ; i ++ ) {
if ( ! langPromises [ $fallbackLanguage [ i ] ] ) {
langPromises [ $fallbackLanguage [ i ] ] = loadAsync ( $fallbackLanguage [ i ] ) ;
}
}
}
}
$translate . use ( $translate . use ( ) ) ;
}
if ( $fallbackWasString ) {
return $fallbackLanguage [ 0 ] ;
} else {
return $fallbackLanguage ;
}
} ;
/ * *
* @ ngdoc function
* @ name pascalprecht . translate . $translate # useFallbackLanguage
* @ methodOf pascalprecht . translate . $translate
*
* @ description
* Sets the first key of the fallback language stack to be used for translation .
* Therefore all languages in the fallback array BEFORE this key will be skipped !
*
* @ param { string = } langKey Contains the langKey the iteration shall start with . Set to false if you want to
* get back to the whole stack
* /
$translate . useFallbackLanguage = function ( langKey ) {
if ( langKey !== undefined && langKey !== null ) {
if ( ! langKey ) {
startFallbackIteration = 0 ;
} else {
var langKeyPosition = indexOf ( $fallbackLanguage , langKey ) ;
if ( langKeyPosition > - 1 ) {
startFallbackIteration = langKeyPosition ;
}
}
}
} ;
/ * *
* @ ngdoc function
* @ name pascalprecht . translate . $translate # proposedLanguage
* @ methodOf pascalprecht . translate . $translate
*
* @ description
* Returns the language key of language that is currently loaded asynchronously .
*
* @ return { string } language key
* /
$translate . proposedLanguage = function ( ) {
return $nextLang ;
} ;
/ * *
* @ ngdoc function
* @ name pascalprecht . translate . $translate # storage
* @ methodOf pascalprecht . translate . $translate
*
* @ description
* Returns registered storage .
*
* @ return { object } Storage
* /
$translate . storage = function ( ) {
return Storage ;
} ;
/ * *
* @ ngdoc function
* @ name pascalprecht . translate . $translate # negotiateLocale
* @ methodOf pascalprecht . translate . $translate
*
* @ description
* Returns a language key based on available languages and language aliases . If a
* language key cannot be resolved , returns undefined .
*
* If no or a falsy key is given , returns undefined .
*
* @ param { string } [ key ] Language key
* @ return { string | undefined } Language key or undefined if no language key is found .
* /
$translate . negotiateLocale = negotiateLocale ;
/ * *
* @ ngdoc function
* @ name pascalprecht . translate . $translate # use
* @ methodOf pascalprecht . translate . $translate
*
* @ description
* Tells angular - translate which language to use by given language key . This method is
* used to change language at runtime . It also takes care of storing the language
* key in a configured store to let your app remember the choosed language .
*
* When trying to 'use' a language which isn ' t available it tries to load it
* asynchronously with registered loaders .
*
* Returns promise object with loaded language file data or string of the currently used language .
*
* If no or a falsy key is given it returns the currently used language key .
* The returned string will be ` ` ` undefined ` ` ` if setting up $translate hasn ' t finished .
* @ example
* $translate . use ( "en_US" ) . then ( function ( data ) {
* $scope . text = $translate ( "HELLO" ) ;
* } ) ;
*
* @ param { string } [ key ] Language key
* @ return { object | string } Promise with loaded language data or the language key if a falsy param was given .
* /
$translate . use = function ( key ) {
if ( ! key ) {
return $uses ;
}
var deferred = $q . defer ( ) ;
$rootScope . $emit ( '$translateChangeStart' , { language : key } ) ;
// Try to get the aliased language key
var aliasedKey = negotiateLocale ( key ) ;
if ( aliasedKey ) {
key = aliasedKey ;
}
// if there isn't a translation table for the language we've requested,
// we load it asynchronously
if ( ( $forceAsyncReloadEnabled || ! $translationTable [ key ] ) && $loaderFactory && ! langPromises [ key ] ) {
$nextLang = 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 ) ;
} ) ;
} else if ( $nextLang === key && langPromises [ key ] ) {
// we are already loading this asynchronously
// resolve our new deferred when the old langPromise is resolved
langPromises [ key ] . then ( function ( translation ) {
deferred . resolve ( translation . key ) ;
return translation ;
} , function ( key ) {
deferred . reject ( key ) ;
return $q . reject ( key ) ;
} ) ;
} else {
deferred . resolve ( key ) ;
useLanguage ( key ) ;
}
return deferred . promise ;
} ;
/ * *
* @ 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 # 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!' ) ;
}
var deferred = $q . defer ( ) ;
function resolve ( ) {
deferred . resolve ( ) ;
$rootScope . $emit ( '$translateRefreshEnd' , { language : langKey } ) ;
}
function reject ( ) {
deferred . reject ( ) ;
$rootScope . $emit ( '$translateRefreshEnd' , { language : langKey } ) ;
}
$rootScope . $emit ( '$translateRefreshStart' , { language : langKey } ) ;
if ( ! langKey ) {
// if there's no language key specified we refresh ALL THE THINGS!
var tables = [ ] , loadingKeys = { } ;
// reload registered fallback languages
if ( $fallbackLanguage && $fallbackLanguage . length ) {
for ( var i = 0 , len = $fallbackLanguage . length ; i < len ; i ++ ) {
tables . push ( loadAsync ( $fallbackLanguage [ i ] ) ) ;
loadingKeys [ $fallbackLanguage [ i ] ] = true ;
}
}
// reload currently used language
if ( $uses && ! loadingKeys [ $uses ] ) {
tables . push ( loadAsync ( $uses ) ) ;
}
var allTranslationsLoaded = function ( tableData ) {
$translationTable = { } ;
angular . forEach ( tableData , function ( data ) {
translations ( data . key , data . table ) ;
} ) ;
if ( $uses ) {
useLanguage ( $uses ) ;
}
resolve ( ) ;
} ;
allTranslationsLoaded . displayName = 'refreshPostProcessor' ;
$q . all ( tables ) . then ( allTranslationsLoaded , reject ) ;
} else if ( $translationTable [ langKey ] ) {
var oneTranslationsLoaded = function ( data ) {
translations ( data . key , data . table ) ;
if ( langKey === $uses ) {
useLanguage ( $uses ) ;
}
resolve ( ) ;
} ;
oneTranslationsLoaded . displayName = 'refreshPostProcessor' ;
loadAsync ( langKey ) . then ( oneTranslationsLoaded , reject ) ;
} else {
reject ( ) ;
}
return deferred . promise ;
} ;
/ * *
* @ ngdoc function
* @ name pascalprecht . translate . $translate # instant
* @ methodOf pascalprecht . translate . $translate
*
* @ description
* Returns a translation instantly from the internal state of loaded translation . All rules
* regarding the current language , the preferred language of even fallback languages will be
* used except any promise handling . If a language was not found , an asynchronous loading
* will be invoked in the background .
*
* @ param { string | array } translationId A token which represents a translation id
* This can be optionally an array of translation ids which
* results that the function ' s promise returns an object where
* each key is the translation id and the value the translation .
* @ param { object } interpolateParams Params
* @ param { string } interpolationId The id of the interpolation to use
* @ param { string } forceLanguage A language to be used instead of the current language
*
* @ return { string | object } translation
* /
$translate . instant = function ( translationId , interpolateParams , interpolationId , forceLanguage ) {
// 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 ;
}
// 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 ) ;
}
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 ) ;
}
}
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 ) ;
if ( $missingTranslationHandlerFactory && ! pendingLoader ) {
result = translateByHandler ( translationId , interpolateParams ) ;
}
}
}
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 1 st language ) .
*
* See also { @ link pascalprecht . translate . $translate # methods _onReady onReady ( ) } .
*
* @ return { boolean } current value of ready
* /
$translate . isReady = function ( ) {
return $isReady ;
} ;
var $onReadyDeferred = $q . defer ( ) ;
$onReadyDeferred . promise . then ( function ( ) {
$isReady = true ;
} ) ;
/ * *
* @ ngdoc function
* @ name pascalprecht . translate . $translate # onReady
* @ methodOf pascalprecht . translate . $translate
*
* @ description
* Returns whether the service is "ready" to translate ( i . e . loading 1 st 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 ;
} ;
// 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 . $inject = [ '$STORAGE_KEY' , '$windowProvider' , '$translateSanitizationProvider' , 'pascalprechtTranslateOverrider' ] ;
$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 string agains given interpolate params using angulars
* ` $ interpolate ` service .
*
* @ returns { string } interpolated string .
* /
$translateInterpolator . interpolate = function ( string , interpolationParams ) {
interpolationParams = interpolationParams || { } ;
interpolationParams = $translateSanitization . sanitize ( interpolationParams , 'params' ) ;
var interpolatedText = $interpolate ( string ) ( interpolationParams ) ;
interpolatedText = $translateSanitization . sanitize ( interpolatedText , 'text' ) ;
return interpolatedText ;
} ;
return $translateInterpolator ;
}
$translateDefaultInterpolation . $inject = [ '$interpolate' , '$translateSanitization' ] ;
$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 $compile
* @ requires $filter
* @ requires $interpolate
* @ restrict AE
*
* @ description
* Translates given translation id either through attribute or DOM content .
* Internally it uses ` translate ` filter to translate translation id . It possible to
* pass an optional ` translate-values ` object literal as string into translation id .
*
* @ param { string = } translate Translation id which could be either string or interpolated string .
* @ param { string = } translate - values Values to pass into translation id . Can be passed as object literal string or interpolated object .
* @ param { string = } translate - attr - ATTR translate Translation id and put it into ATTR attribute .
* @ param { string = } translate - default will be used unless translation was successful
* @ param { boolean = } translate - compile ( default true if present ) defines locally activation of { @ link pascalprecht . translate . $translateProvider # methods _usePostCompiling }
*
* @ example
< example module = "ngView" >
< file name = "index.html" >
< div ng - controller = "TranslateCtrl" >
< pre translate = "TRANSLATION_ID" > < / p r e >
< pre translate > TRANSLATION _ID < / p r e >
< pre translate translate - attr - title = "TRANSLATION_ID" > < / p r e >
< pre translate = "{{translationId}}" > < / p r e >
< pre translate > { { translationId } } < / p r e >
< pre translate = "WITH_VALUES" translate - values = "{value: 5}" > < / p r e >
< pre translate translate - values = "{value: 5}" > WITH _VALUES < / p r e >
< pre translate = "WITH_VALUES" translate - values = "{{values}}" > < / p r e >
< pre translate translate - values = "{{values}}" > WITH _VALUES < / p r e >
< pre translate translate - attr - title = "WITH_VALUES" translate - values = "{{values}}" > < / p r e >
< / d i v >
< / f i l e >
< 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
} ;
} ) ;
< / f i l e >
< 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!' ) ;
} ) ;
} ) ;
< / f i l e >
< / e x a m p l e >
* /
. directive ( 'translate' , translateDirective ) ;
function translateDirective ( $translate , $q , $interpolate , $compile , $parse , $rootScope ) {
'use strict' ;
/ * *
* @ name trim
* @ private
*
* @ description
* trim polyfill
*
* @ returns { string } The string stripped of whitespace from both ends
* /
var trim = function ( ) {
return this . toString ( ) . replace ( /^\s+|\s+$/g , '' ) ;
} ;
return {
restrict : 'AE' ,
scope : true ,
priority : $translate . directivePriority ( ) ,
compile : function ( tElement , tAttr ) {
var translateValuesExist = ( tAttr . translateValues ) ?
tAttr . translateValues : undefined ;
var translateInterpolation = ( tAttr . translateInterpolation ) ?
tAttr . translateInterpolation : undefined ;
var translateValueExist = tElement [ 0 ] . outerHTML . match ( /translate-value-+/i ) ;
var interpolateRegExp = '^(.*)(' + $interpolate . startSymbol ( ) + '.*' + $interpolate . endSymbol ( ) + ')(.*)' ,
watcherRegExp = '^(.*)' + $interpolate . startSymbol ( ) + '(.*)' + $interpolate . endSymbol ( ) + '(.*)' ;
return function linkFn ( scope , iElement , iAttr ) {
scope . interpolateParams = { } ;
scope . preText = '' ;
scope . postText = '' ;
scope . translateNamespace = getTranslateNamespace ( scope ) ;
var translationIds = { } ;
var initInterpolationParams = function ( interpolateParams , iAttr , tAttr ) {
// initial setup
if ( iAttr . translateValues ) {
angular . extend ( interpolateParams , $parse ( iAttr . translateValues ) ( scope . $parent ) ) ;
}
// initially fetch all attributes if existing and fill the params
if ( translateValueExist ) {
for ( var attr in tAttr ) {
if ( Object . prototype . hasOwnProperty . call ( iAttr , attr ) && attr . substr ( 0 , 14 ) === 'translateValue' && attr !== 'translateValues' ) {
var attributeName = angular . lowercase ( attr . substr ( 14 , 1 ) ) + attr . substr ( 15 ) ;
interpolateParams [ attributeName ] = tAttr [ attr ] ;
}
}
}
} ;
// Ensures any change of the attribute "translate" containing the id will
// be re-stored to the scope's "translationId".
// If the attribute has no content, the element's text value (white spaces trimmed off) will be used.
var observeElementTranslation = function ( translationId ) {
// Remove any old watcher
if ( angular . isFunction ( observeElementTranslation . _unwatchOld ) ) {
observeElementTranslation . _unwatchOld ( ) ;
observeElementTranslation . _unwatchOld = undefined ;
}
if ( angular . equals ( translationId , '' ) || ! angular . isDefined ( translationId ) ) {
var iElementText = trim . apply ( iElement . text ( ) ) ;
// Resolve translation id by inner html if required
var interpolateMatches = iElementText . match ( interpolateRegExp ) ;
// Interpolate translation id if required
if ( angular . isArray ( interpolateMatches ) ) {
scope . preText = interpolateMatches [ 1 ] ;
scope . postText = interpolateMatches [ 3 ] ;
translationIds . translate = $interpolate ( interpolateMatches [ 2 ] ) ( scope . $parent ) ;
var watcherMatches = iElementText . match ( watcherRegExp ) ;
if ( angular . isArray ( watcherMatches ) && watcherMatches [ 2 ] && watcherMatches [ 2 ] . length ) {
observeElementTranslation . _unwatchOld = scope . $watch ( watcherMatches [ 2 ] , function ( newValue ) {
translationIds . translate = newValue ;
updateTranslations ( ) ;
} ) ;
}
} else {
// do not assigne the translation id if it is empty.
translationIds . translate = ! iElementText ? undefined : iElementText ;
}
} else {
translationIds . translate = translationId ;
}
updateTranslations ( ) ;
} ;
var observeAttributeTranslation = function ( translateAttr ) {
iAttr . $observe ( translateAttr , function ( translationId ) {
translationIds [ translateAttr ] = translationId ;
updateTranslations ( ) ;
} ) ;
} ;
// initial setup with values
initInterpolationParams ( scope . interpolateParams , iAttr , tAttr ) ;
var firstAttributeChangedEvent = true ;
iAttr . $observe ( 'translate' , function ( translationId ) {
if ( typeof translationId === 'undefined' ) {
// case of element "<translate>xyz</translate>"
observeElementTranslation ( '' ) ;
} else {
// case of regular attribute
if ( translationId !== '' || ! firstAttributeChangedEvent ) {
translationIds . translate = translationId ;
updateTranslations ( ) ;
}
}
firstAttributeChangedEvent = false ;
} ) ;
for ( var translateAttr in iAttr ) {
if ( iAttr . hasOwnProperty ( translateAttr ) && translateAttr . substr ( 0 , 13 ) === 'translateAttr' ) {
observeAttributeTranslation ( translateAttr ) ;
}
}
iAttr . $observe ( 'translateDefault' , function ( value ) {
scope . defaultText = value ;
updateTranslations ( ) ;
} ) ;
if ( translateValuesExist ) {
iAttr . $observe ( 'translateValues' , function ( interpolateParams ) {
if ( interpolateParams ) {
scope . $parent . $watch ( function ( ) {
angular . extend ( scope . interpolateParams , $parse ( interpolateParams ) ( scope . $parent ) ) ;
} ) ;
}
} ) ;
}
if ( translateValueExist ) {
var observeValueAttribute = function ( attrName ) {
iAttr . $observe ( attrName , function ( value ) {
var attributeName = angular . lowercase ( attrName . substr ( 14 , 1 ) ) + attrName . substr ( 15 ) ;
scope . interpolateParams [ attributeName ] = value ;
} ) ;
} ;
for ( var attr in iAttr ) {
if ( Object . prototype . hasOwnProperty . call ( iAttr , attr ) && attr . substr ( 0 , 14 ) === 'translateValue' && attr !== 'translateValues' ) {
observeValueAttribute ( attr ) ;
}
}
}
// Master update function
var updateTranslations = function ( ) {
for ( var key in translationIds ) {
if ( translationIds . hasOwnProperty ( key ) && translationIds [ key ] !== undefined ) {
updateTranslation ( key , translationIds [ key ] , scope , scope . interpolateParams , scope . defaultText , scope . translateNamespace ) ;
}
}
} ;
// Put translation processing function outside loop
var updateTranslation = function ( translateAttr , translationId , scope , interpolateParams , defaultTranslationText , translateNamespace ) {
if ( translationId ) {
// if translation id starts with '.' and translateNamespace given, prepend namespace
if ( translateNamespace && translationId . charAt ( 0 ) === '.' ) {
translationId = translateNamespace + translationId ;
}
$translate ( translationId , interpolateParams , translateInterpolation , defaultTranslationText , scope . translateLanguage )
. then ( function ( translation ) {
applyTranslation ( translation , scope , true , translateAttr ) ;
} , function ( translationId ) {
applyTranslation ( translationId , scope , false , translateAttr ) ;
} ) ;
} else {
// as an empty string cannot be translated, we can solve this using successful=false
applyTranslation ( translationId , scope , false , translateAttr ) ;
}
} ;
var applyTranslation = function ( value , scope , successful , translateAttr ) {
if ( translateAttr === 'translate' ) {
// default translate into innerHTML
if ( ! successful && typeof scope . defaultText !== 'undefined' ) {
value = scope . defaultText ;
}
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
if ( ! successful && typeof scope . defaultText !== 'undefined' ) {
value = scope . defaultText ;
}
var attributeName = iAttr . $attr [ translateAttr ] ;
if ( attributeName . substr ( 0 , 5 ) === 'data-' ) {
// ensure html5 data prefix is stripped
attributeName = attributeName . substr ( 5 ) ;
}
attributeName = attributeName . substr ( 15 ) ;
iElement . attr ( attributeName , value ) ;
}
} ;
if ( translateValuesExist || translateValueExist || iAttr . translateDefault ) {
scope . $watch ( 'interpolateParams' , updateTranslations , true ) ;
}
scope . $watch ( 'translateLanguage' , 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 ) ;
} ;
}
} ;
}
translateDirective . $inject = [ '$translate' , '$q' , '$interpolate' , '$compile' , '$parse' , '$rootScope' ] ;
/ * *
* 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 : translateCloak
* @ requires $rootScope
* @ 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 ( ) {
tElement . addClass ( $translate . cloakClassName ( ) ) ;
} ,
removeCloak = function ( ) {
tElement . removeClass ( $translate . cloakClassName ( ) ) ;
} ;
$translate . onReady ( function ( ) {
removeCloak ( ) ;
} ) ;
applyCloak ( ) ;
return function linkFn ( scope , iElement , iAttr ) {
if ( iAttr . translateCloak && iAttr . translateCloak . length ) {
// Register a watcher for the defined translation allowing a fine tuned cloak
iAttr . $observe ( 'translateCloak' , function ( translationId ) {
$translate ( translationId ) . then ( removeCloak , applyCloak ) ;
} ) ;
// Register for change events as this is being another indicicator revalidating the cloak)
$rootScope . $on ( '$translateChangeSuccess' , function ( ) {
$translate ( iAttr . translateCloak ) . then ( removeCloak , applyCloak ) ;
} ) ;
}
} ;
}
} ;
}
translateCloakDirective . $inject = [ '$translate' , '$rootScope' ] ;
translateCloakDirective . displayName = 'translateCloakDirective' ;
angular . module ( 'pascalprecht.translate' )
/ * *
* @ ngdoc directive
* @ name pascalprecht . translate . directive : translateNamespace
* @ restrict A
*
* @ description
* Translates given translation id either through attribute or DOM content .
* Internally it uses ` translate ` filter to translate translation id . It possible to
* pass an optional ` translate-values ` object literal as string into translation id .
*
* @ param { string = } translate namespace name which could be either string or interpolated string .
*
* @ example
< example module = "ngView" >
< file name = "index.html" >
< div translate - namespace = "CONTENT" >
< div >
< h1 translate > . HEADERS . TITLE < / h 1 >
< h1 translate > . HEADERS . WELCOME < / h 1 >
< / d i v >
< div translate - namespace = ".HEADERS" >
< h1 translate > . TITLE < / h 1 >
< h1 translate > . WELCOME < / h 1 >
< / d i v >
< / d i v >
< / f i l e >
< 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' ) ;
} ) ;
< / f i l e >
< / e x a m p l e >
* /
. 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 < / h 1 >
< / d i v >
< div translate - language = "de" >
< h1 translate > HELLO < / h 1 >
< / d i v >
< / d i v >
< / f i l e >
< file name = "script.js" >
angular . module ( 'ngView' , [ 'pascalprecht.translate' ] )
. config ( function ( $translateProvider ) {
$translateProvider
. translations ( 'en' , {
'HELLO' : 'Hello world!'
} )
. translations ( 'de' , {
'HELLO' : 'Hallo Welt!'
} )
. translations ( . preferredLanguage ( 'en' ) ;
} ) ;
< / f i l e >
< / e x a m p l e >
* /
. 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 ;
} ) ;
} ;
}
} ;
}
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 } } < / p r e >
< pre > { { translationId | translate } } < / p r e >
< pre > { { 'WITH_VALUES' | translate : '{value: 5}' } } < / p r e >
< pre > { { 'WITH_VALUES' | translate : values } } < / p r e >
< / d i v >
< / f i l e >
< 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
} ;
} ) ;
< / f i l e >
< / e x a m p l e >
* /
. filter ( 'translate' , translateFilterFactory ) ;
function translateFilterFactory ( $parse , $translate ) {
'use strict' ;
var translateFilter = function ( translationId , interpolateParams , interpolation , forceLanguage ) {
if ( ! angular . isObject ( interpolateParams ) ) {
interpolateParams = $parse ( interpolateParams ) ( this ) ;
}
return $translate . instant ( translationId , interpolateParams , interpolation , forceLanguage ) ;
} ;
if ( $translate . statefulFilter ( ) ) {
translateFilter . $stateful = true ;
}
return translateFilter ;
}
translateFilterFactory . $inject = [ '$parse' , '$translate' ] ;
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 . $inject = [ '$cacheFactory' ] ;
$translationCache . displayName = '$translationCache' ;
return 'pascalprecht.translate' ;
} ) ) ;