angular-translate-rails-tf 2.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 48f0076777fbcf6d9711fd95687b7665653e1835
4
+ data.tar.gz: e7b576ef00e88fbf21bc09a0832e76e5973718e7
5
+ SHA512:
6
+ metadata.gz: b34fb0e7b879c19743f5ca9ede714049c1ee971a70af6879c15b6f9050dccc24eac18834b622fc853437ae5c2b215b2c6d712fc72da275d553b65a68676692af
7
+ data.tar.gz: 6bef5dbae974734992ade06be419e8d7c24b8e551685165e8c01ce1d1d35e521a86f545f3d3af927947bce50ed20c79facb3fa351846adeee54c02d6a025ccd2
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ # 2.6.0 (2015-02-26)
2
+
3
+ Initial commit matched with angular-translate version, not really released yet.
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Kanwaldeep Singh Arneja
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,27 @@
1
+ # angular-translate-rails
2
+
3
+ angular-translate-rails wraps the [angular-translate.js](http://angular-translate.github.io) library in a rails engine for simple
4
+ use with the asset pipeline provided by Rails 3.1 and higher. The gem includes the development (non-minified)
5
+ source for ease of exploration. The asset pipeline will minify in production.
6
+
7
+ angular-translate is an AngularJS module that makes your life much easier when it comes
8
+ to i18n and l10n including lazy loading and pluralization Please see the
9
+ [documentation](http://angular-translate.github.io/docs/#/api) for details.
10
+
11
+ ## Usage
12
+
13
+ Add the following to your gemfile:
14
+
15
+ gem 'angular-translate-rails'
16
+
17
+ Add the following directive to your Javascript manifest file (application.js):
18
+
19
+ //= require angular-translate
20
+
21
+ ## Versioning
22
+
23
+ angular-translate-rails 2.6.0 == angular-translate.js 2.6.0
24
+
25
+ Every attempt is made to mirror the currently shipping angular-translate.js version number wherever possible.
26
+ The major, minor, and patch version numbers will always represent the angular-translate.js version. Should a gem
27
+ bug be discovered, a 4th version identifier will be added and incremented.
@@ -0,0 +1,6 @@
1
+ module AngularTranslate
2
+ module Rails
3
+ class Engine < ::Rails::Engine
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,7 @@
1
+ require 'test_helper'
2
+
3
+ class AngularTranslateRailsTest < ActiveSupport::TestCase
4
+ test "truth" do
5
+ assert_kind_of Module, AngularTranslate::Rails
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ require File.expand_path('../config/application', __FILE__)
2
+
3
+ Dummy::Application.load_tasks
@@ -0,0 +1,22 @@
1
+ require File.expand_path('../boot', __FILE__)
2
+
3
+ require "action_mailer/railtie"
4
+ require "sprockets/railtie"
5
+
6
+ Bundler.require
7
+ require "angular-translate-rails"
8
+
9
+ module Dummy
10
+ class Application < Rails::Application
11
+
12
+ config.encoding = "utf-8"
13
+
14
+ config.filter_parameters += [:password]
15
+
16
+ config.active_support.escape_html_entities_in_json = true
17
+
18
+ config.assets.enabled = true
19
+
20
+ config.assets.version = '1.0'
21
+ end
22
+ end
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ gemfile = File.expand_path('../../../../Gemfile', __FILE__)
3
+
4
+ if File.exist?(gemfile)
5
+ ENV['BUNDLE_GEMFILE'] = gemfile
6
+ require 'bundler'
7
+ Bundler.setup
8
+ end
9
+
10
+ $:.unshift File.expand_path('../../../../lib', __FILE__)
@@ -0,0 +1,3 @@
1
+ require File.expand_path('../application', __FILE__)
2
+
3
+ Dummy::Application.initialize!
@@ -0,0 +1,20 @@
1
+ Dummy::Application.configure do
2
+
3
+ config.cache_classes = false
4
+
5
+ config.whiny_nils = true
6
+
7
+ config.consider_all_requests_local = true
8
+
9
+ config.action_controller.perform_caching = false
10
+
11
+ config.action_mailer.raise_delivery_errors = false
12
+
13
+ config.active_support.deprecation = :log
14
+
15
+ config.action_dispatch.best_standards_support = :builtin
16
+
17
+ config.assets.compress = false
18
+
19
+ config.assets.debug = true
20
+ end
@@ -0,0 +1,20 @@
1
+ Dummy::Application.configure do
2
+
3
+ config.cache_classes = true
4
+
5
+ config.consider_all_requests_local = false
6
+
7
+ config.action_controller.perform_caching = true
8
+
9
+ config.serve_static_assets = false
10
+
11
+ config.assets.compress = true
12
+
13
+ config.assets.compile = false
14
+
15
+ config.assets.digest = true
16
+
17
+ config.i18n.fallbacks = true
18
+
19
+ config.active_support.deprecation = :notify
20
+ end
@@ -0,0 +1,22 @@
1
+ Dummy::Application.configure do
2
+
3
+ config.cache_classes = true
4
+
5
+ config.serve_static_assets = true
6
+
7
+ config.static_cache_control = "public, max-age=3600"
8
+
9
+ config.whiny_nils = true
10
+
11
+ config.consider_all_requests_local = true
12
+
13
+ config.action_controller.perform_caching = false
14
+
15
+ config.action_dispatch.show_exceptions = false
16
+
17
+ config.action_controller.allow_forgery_protection = false
18
+
19
+ config.action_mailer.delivery_method = :test
20
+
21
+ config.active_support.deprecation = :stderr
22
+ end
@@ -0,0 +1 @@
1
+ # Be sure to restart your server when you modify this file.
@@ -0,0 +1 @@
1
+ # Be sure to restart your server when you modify this file.
@@ -0,0 +1 @@
1
+ # Be sure to restart your server when you modify this file.
@@ -0,0 +1,3 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ Dummy::Application.config.secret_token = 'a50ecf55a3b3f1ad2e345253fac2d11d774a26018ca9f74577d9a5e688cdddd39e6b1bff1a9188e6cd982f7dfc7ef5d2608ddd31894472d5ef092dc4b0288309'
@@ -0,0 +1 @@
1
+ Dummy::Application.config.session_store :cookie_store, key: '_dummy_session'
@@ -0,0 +1,4 @@
1
+ ActiveSupport.on_load(:action_controller) do
2
+ wrap_parameters format: [:json]
3
+ end
4
+
@@ -0,0 +1,2 @@
1
+ en:
2
+ hello: "Hello world"
@@ -0,0 +1,2 @@
1
+ Rails.application.routes.draw do
2
+ end
@@ -0,0 +1,4 @@
1
+ # This file is used by Rack-based servers to start the application.
2
+
3
+ require ::File.expand_path('../config/environment', __FILE__)
4
+ run Dummy::Application
@@ -0,0 +1,13 @@
1
+ require 'test_helper'
2
+
3
+ class ResourceTest < ActionDispatch::IntegrationTest
4
+ test 'can access angular-translate' do
5
+ get '/assets/angular-translate.js'
6
+ assert_response :success
7
+ end
8
+
9
+ test 'angular-translate response is for the expected version' do
10
+ get '/assets/angular-translate.js'
11
+ assert_match(/VERSION = '2\.6\.0'/, @response.body)
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ ENV["RAILS_ENV"] = "test"
2
+
3
+ require File.expand_path("../dummy/config/environment.rb", __FILE__)
4
+ require "rails/test_help"
5
+
6
+ Rails.backtrace_cleaner.remove_silencers!
7
+
8
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
9
+
10
+ if ActiveSupport::TestCase.method_defined?(:fixture_path=)
11
+ ActiveSupport::TestCase.fixture_path = File.expand_path("../fixtures", __FILE__)
12
+ end
@@ -0,0 +1,2359 @@
1
+ /*!
2
+ * angular-translate - v2.6.1 - 2015-03-01
3
+ * http://github.com/angular-translate/angular-translate
4
+ * Copyright (c) 2015 ; Licensed MIT
5
+ */
6
+ /**
7
+ * @ngdoc overview
8
+ * @name pascalprecht.translate
9
+ *
10
+ * @description
11
+ * The main module which holds everything together.
12
+ */
13
+ angular.module('pascalprecht.translate', ['ng'])
14
+
15
+ .run(['$translate', function ($translate) {
16
+
17
+ var key = $translate.storageKey(),
18
+ storage = $translate.storage();
19
+
20
+ var fallbackFromIncorrectStorageValue = function() {
21
+ var preferred = $translate.preferredLanguage();
22
+ if (angular.isString(preferred)) {
23
+ $translate.use(preferred);
24
+ // $translate.use() will also remember the language.
25
+ // So, we don't need to call storage.put() here.
26
+ } else {
27
+ storage.put(key, $translate.use());
28
+ }
29
+ };
30
+
31
+ if (storage) {
32
+ if (!storage.get(key)) {
33
+ fallbackFromIncorrectStorageValue();
34
+ } else {
35
+ $translate.use(storage.get(key))['catch'](fallbackFromIncorrectStorageValue);
36
+ }
37
+ } else if (angular.isString($translate.preferredLanguage())) {
38
+ $translate.use($translate.preferredLanguage());
39
+ }
40
+ }]);
41
+
42
+ /**
43
+ * @ngdoc object
44
+ * @name pascalprecht.translate.$translateProvider
45
+ * @description
46
+ *
47
+ * $translateProvider allows developers to register translation-tables, asynchronous loaders
48
+ * and similar to configure translation behavior directly inside of a module.
49
+ *
50
+ */
51
+ angular.module('pascalprecht.translate').provider('$translate', ['$STORAGE_KEY', '$windowProvider', function ($STORAGE_KEY, $windowProvider) {
52
+
53
+ var $translationTable = {},
54
+ $preferredLanguage,
55
+ $availableLanguageKeys = [],
56
+ $languageKeyAliases,
57
+ $fallbackLanguage,
58
+ $fallbackWasString,
59
+ $uses,
60
+ $nextLang,
61
+ $storageFactory,
62
+ $storageKey = $STORAGE_KEY,
63
+ $storagePrefix,
64
+ $missingTranslationHandlerFactory,
65
+ $interpolationFactory,
66
+ $interpolatorFactories = [],
67
+ $interpolationSanitizationStrategy = false,
68
+ $loaderFactory,
69
+ $cloakClassName = 'translate-cloak',
70
+ $loaderOptions,
71
+ $notFoundIndicatorLeft,
72
+ $notFoundIndicatorRight,
73
+ $postCompilingEnabled = false,
74
+ NESTED_OBJECT_DELIMITER = '.',
75
+ loaderCache,
76
+ directivePriority = 0;
77
+
78
+ var version = '2.6.1';
79
+
80
+ // tries to determine the browsers language
81
+ var getFirstBrowserLanguage = function () {
82
+ var nav = $windowProvider.$get().navigator,
83
+ browserLanguagePropertyKeys = ['language', 'browserLanguage', 'systemLanguage', 'userLanguage'],
84
+ i,
85
+ language;
86
+
87
+ // support for HTML 5.1 "navigator.languages"
88
+ if (angular.isArray(nav.languages)) {
89
+ for (i = 0; i < nav.languages.length; i++) {
90
+ language = nav.languages[i];
91
+ if (language && language.length) {
92
+ return language;
93
+ }
94
+ }
95
+ }
96
+
97
+ // support for other well known properties in browsers
98
+ for (i = 0; i < browserLanguagePropertyKeys.length; i++) {
99
+ language = nav[browserLanguagePropertyKeys[i]];
100
+ if (language && language.length) {
101
+ return language;
102
+ }
103
+ }
104
+
105
+ return null;
106
+ };
107
+ getFirstBrowserLanguage.displayName = 'angular-translate/service: getFirstBrowserLanguage';
108
+
109
+ // tries to determine the browsers locale
110
+ var getLocale = function () {
111
+ return (getFirstBrowserLanguage() || '').split('-').join('_');
112
+ };
113
+ getLocale.displayName = 'angular-translate/service: getLocale';
114
+
115
+ /**
116
+ * @name indexOf
117
+ * @private
118
+ *
119
+ * @description
120
+ * indexOf polyfill. Kinda sorta.
121
+ *
122
+ * @param {array} array Array to search in.
123
+ * @param {string} searchElement Element to search for.
124
+ *
125
+ * @returns {int} Index of search element.
126
+ */
127
+ var indexOf = function(array, searchElement) {
128
+ for (var i = 0, len = array.length; i < len; i++) {
129
+ if (array[i] === searchElement) {
130
+ return i;
131
+ }
132
+ }
133
+ return -1;
134
+ };
135
+
136
+ /**
137
+ * @name trim
138
+ * @private
139
+ *
140
+ * @description
141
+ * trim polyfill
142
+ *
143
+ * @returns {string} The string stripped of whitespace from both ends
144
+ */
145
+ var trim = function() {
146
+ return this.toString().replace(/^\s+|\s+$/g, '');
147
+ };
148
+
149
+ var negotiateLocale = function (preferred) {
150
+
151
+ var avail = [],
152
+ locale = angular.lowercase(preferred),
153
+ i = 0,
154
+ n = $availableLanguageKeys.length;
155
+
156
+ for (; i < n; i++) {
157
+ avail.push(angular.lowercase($availableLanguageKeys[i]));
158
+ }
159
+
160
+ if (indexOf(avail, locale) > -1) {
161
+ return preferred;
162
+ }
163
+
164
+ if ($languageKeyAliases) {
165
+ var alias;
166
+ for (var langKeyAlias in $languageKeyAliases) {
167
+ var hasWildcardKey = false;
168
+ var hasExactKey = Object.prototype.hasOwnProperty.call($languageKeyAliases, langKeyAlias) &&
169
+ angular.lowercase(langKeyAlias) === angular.lowercase(preferred);
170
+
171
+ if (langKeyAlias.slice(-1) === '*') {
172
+ hasWildcardKey = langKeyAlias.slice(0, -1) === preferred.slice(0, langKeyAlias.length-1);
173
+ }
174
+ if (hasExactKey || hasWildcardKey) {
175
+ alias = $languageKeyAliases[langKeyAlias];
176
+ if (indexOf(avail, angular.lowercase(alias)) > -1) {
177
+ return alias;
178
+ }
179
+ }
180
+ }
181
+ }
182
+
183
+ var parts = preferred.split('_');
184
+
185
+ if (parts.length > 1 && indexOf(avail, angular.lowercase(parts[0])) > -1) {
186
+ return parts[0];
187
+ }
188
+
189
+ // If everything fails, just return the preferred, unchanged.
190
+ return preferred;
191
+ };
192
+
193
+ /**
194
+ * @ngdoc function
195
+ * @name pascalprecht.translate.$translateProvider#translations
196
+ * @methodOf pascalprecht.translate.$translateProvider
197
+ *
198
+ * @description
199
+ * Registers a new translation table for specific language key.
200
+ *
201
+ * To register a translation table for specific language, pass a defined language
202
+ * key as first parameter.
203
+ *
204
+ * <pre>
205
+ * // register translation table for language: 'de_DE'
206
+ * $translateProvider.translations('de_DE', {
207
+ * 'GREETING': 'Hallo Welt!'
208
+ * });
209
+ *
210
+ * // register another one
211
+ * $translateProvider.translations('en_US', {
212
+ * 'GREETING': 'Hello world!'
213
+ * });
214
+ * </pre>
215
+ *
216
+ * When registering multiple translation tables for for the same language key,
217
+ * the actual translation table gets extended. This allows you to define module
218
+ * specific translation which only get added, once a specific module is loaded in
219
+ * your app.
220
+ *
221
+ * Invoking this method with no arguments returns the translation table which was
222
+ * registered with no language key. Invoking it with a language key returns the
223
+ * related translation table.
224
+ *
225
+ * @param {string} key A language key.
226
+ * @param {object} translationTable A plain old JavaScript object that represents a translation table.
227
+ *
228
+ */
229
+ var translations = function (langKey, translationTable) {
230
+
231
+ if (!langKey && !translationTable) {
232
+ return $translationTable;
233
+ }
234
+
235
+ if (langKey && !translationTable) {
236
+ if (angular.isString(langKey)) {
237
+ return $translationTable[langKey];
238
+ }
239
+ } else {
240
+ if (!angular.isObject($translationTable[langKey])) {
241
+ $translationTable[langKey] = {};
242
+ }
243
+ angular.extend($translationTable[langKey], flatObject(translationTable));
244
+ }
245
+ return this;
246
+ };
247
+
248
+ this.translations = translations;
249
+
250
+ /**
251
+ * @ngdoc function
252
+ * @name pascalprecht.translate.$translateProvider#cloakClassName
253
+ * @methodOf pascalprecht.translate.$translateProvider
254
+ *
255
+ * @description
256
+ *
257
+ * Let's you change the class name for `translate-cloak` directive.
258
+ * Default class name is `translate-cloak`.
259
+ *
260
+ * @param {string} name translate-cloak class name
261
+ */
262
+ this.cloakClassName = function (name) {
263
+ if (!name) {
264
+ return $cloakClassName;
265
+ }
266
+ $cloakClassName = name;
267
+ return this;
268
+ };
269
+
270
+ /**
271
+ * @name flatObject
272
+ * @private
273
+ *
274
+ * @description
275
+ * Flats an object. This function is used to flatten given translation data with
276
+ * namespaces, so they are later accessible via dot notation.
277
+ */
278
+ var flatObject = function (data, path, result, prevKey) {
279
+ var key, keyWithPath, keyWithShortPath, val;
280
+
281
+ if (!path) {
282
+ path = [];
283
+ }
284
+ if (!result) {
285
+ result = {};
286
+ }
287
+ for (key in data) {
288
+ if (!Object.prototype.hasOwnProperty.call(data, key)) {
289
+ continue;
290
+ }
291
+ val = data[key];
292
+ if (angular.isObject(val)) {
293
+ flatObject(val, path.concat(key), result, key);
294
+ } else {
295
+ keyWithPath = path.length ? ('' + path.join(NESTED_OBJECT_DELIMITER) + NESTED_OBJECT_DELIMITER + key) : key;
296
+ if(path.length && key === prevKey){
297
+ // Create shortcut path (foo.bar == foo.bar.bar)
298
+ keyWithShortPath = '' + path.join(NESTED_OBJECT_DELIMITER);
299
+ // Link it to original path
300
+ result[keyWithShortPath] = '@:' + keyWithPath;
301
+ }
302
+ result[keyWithPath] = val;
303
+ }
304
+ }
305
+ return result;
306
+ };
307
+
308
+ /**
309
+ * @ngdoc function
310
+ * @name pascalprecht.translate.$translateProvider#addInterpolation
311
+ * @methodOf pascalprecht.translate.$translateProvider
312
+ *
313
+ * @description
314
+ * Adds interpolation services to angular-translate, so it can manage them.
315
+ *
316
+ * @param {object} factory Interpolation service factory
317
+ */
318
+ this.addInterpolation = function (factory) {
319
+ $interpolatorFactories.push(factory);
320
+ return this;
321
+ };
322
+
323
+ /**
324
+ * @ngdoc function
325
+ * @name pascalprecht.translate.$translateProvider#useMessageFormatInterpolation
326
+ * @methodOf pascalprecht.translate.$translateProvider
327
+ *
328
+ * @description
329
+ * Tells angular-translate to use interpolation functionality of messageformat.js.
330
+ * This is useful when having high level pluralization and gender selection.
331
+ */
332
+ this.useMessageFormatInterpolation = function () {
333
+ return this.useInterpolation('$translateMessageFormatInterpolation');
334
+ };
335
+
336
+ /**
337
+ * @ngdoc function
338
+ * @name pascalprecht.translate.$translateProvider#useInterpolation
339
+ * @methodOf pascalprecht.translate.$translateProvider
340
+ *
341
+ * @description
342
+ * Tells angular-translate which interpolation style to use as default, application-wide.
343
+ * Simply pass a factory/service name. The interpolation service has to implement
344
+ * the correct interface.
345
+ *
346
+ * @param {string} factory Interpolation service name.
347
+ */
348
+ this.useInterpolation = function (factory) {
349
+ $interpolationFactory = factory;
350
+ return this;
351
+ };
352
+
353
+ /**
354
+ * @ngdoc function
355
+ * @name pascalprecht.translate.$translateProvider#useSanitizeStrategy
356
+ * @methodOf pascalprecht.translate.$translateProvider
357
+ *
358
+ * @description
359
+ * Simply sets a sanitation strategy type.
360
+ *
361
+ * @param {string} value Strategy type.
362
+ */
363
+ this.useSanitizeValueStrategy = function (value) {
364
+ $interpolationSanitizationStrategy = value;
365
+ return this;
366
+ };
367
+
368
+ /**
369
+ * @ngdoc function
370
+ * @name pascalprecht.translate.$translateProvider#preferredLanguage
371
+ * @methodOf pascalprecht.translate.$translateProvider
372
+ *
373
+ * @description
374
+ * Tells the module which of the registered translation tables to use for translation
375
+ * at initial startup by passing a language key. Similar to `$translateProvider#use`
376
+ * only that it says which language to **prefer**.
377
+ *
378
+ * @param {string} langKey A language key.
379
+ *
380
+ */
381
+ this.preferredLanguage = function(langKey) {
382
+ setupPreferredLanguage(langKey);
383
+ return this;
384
+
385
+ };
386
+ var setupPreferredLanguage = function (langKey) {
387
+ if (langKey) {
388
+ $preferredLanguage = langKey;
389
+ }
390
+ return $preferredLanguage;
391
+ };
392
+ /**
393
+ * @ngdoc function
394
+ * @name pascalprecht.translate.$translateProvider#translationNotFoundIndicator
395
+ * @methodOf pascalprecht.translate.$translateProvider
396
+ *
397
+ * @description
398
+ * Sets an indicator which is used when a translation isn't found. E.g. when
399
+ * setting the indicator as 'X' and one tries to translate a translation id
400
+ * called `NOT_FOUND`, this will result in `X NOT_FOUND X`.
401
+ *
402
+ * Internally this methods sets a left indicator and a right indicator using
403
+ * `$translateProvider.translationNotFoundIndicatorLeft()` and
404
+ * `$translateProvider.translationNotFoundIndicatorRight()`.
405
+ *
406
+ * **Note**: These methods automatically add a whitespace between the indicators
407
+ * and the translation id.
408
+ *
409
+ * @param {string} indicator An indicator, could be any string.
410
+ */
411
+ this.translationNotFoundIndicator = function (indicator) {
412
+ this.translationNotFoundIndicatorLeft(indicator);
413
+ this.translationNotFoundIndicatorRight(indicator);
414
+ return this;
415
+ };
416
+
417
+ /**
418
+ * ngdoc function
419
+ * @name pascalprecht.translate.$translateProvider#translationNotFoundIndicatorLeft
420
+ * @methodOf pascalprecht.translate.$translateProvider
421
+ *
422
+ * @description
423
+ * Sets an indicator which is used when a translation isn't found left to the
424
+ * translation id.
425
+ *
426
+ * @param {string} indicator An indicator.
427
+ */
428
+ this.translationNotFoundIndicatorLeft = function (indicator) {
429
+ if (!indicator) {
430
+ return $notFoundIndicatorLeft;
431
+ }
432
+ $notFoundIndicatorLeft = indicator;
433
+ return this;
434
+ };
435
+
436
+ /**
437
+ * ngdoc function
438
+ * @name pascalprecht.translate.$translateProvider#translationNotFoundIndicatorLeft
439
+ * @methodOf pascalprecht.translate.$translateProvider
440
+ *
441
+ * @description
442
+ * Sets an indicator which is used when a translation isn't found right to the
443
+ * translation id.
444
+ *
445
+ * @param {string} indicator An indicator.
446
+ */
447
+ this.translationNotFoundIndicatorRight = function (indicator) {
448
+ if (!indicator) {
449
+ return $notFoundIndicatorRight;
450
+ }
451
+ $notFoundIndicatorRight = indicator;
452
+ return this;
453
+ };
454
+
455
+ /**
456
+ * @ngdoc function
457
+ * @name pascalprecht.translate.$translateProvider#fallbackLanguage
458
+ * @methodOf pascalprecht.translate.$translateProvider
459
+ *
460
+ * @description
461
+ * Tells the module which of the registered translation tables to use when missing translations
462
+ * at initial startup by passing a language key. Similar to `$translateProvider#use`
463
+ * only that it says which language to **fallback**.
464
+ *
465
+ * @param {string||array} langKey A language key.
466
+ *
467
+ */
468
+ this.fallbackLanguage = function (langKey) {
469
+ fallbackStack(langKey);
470
+ return this;
471
+ };
472
+
473
+ var fallbackStack = function (langKey) {
474
+ if (langKey) {
475
+ if (angular.isString(langKey)) {
476
+ $fallbackWasString = true;
477
+ $fallbackLanguage = [ langKey ];
478
+ } else if (angular.isArray(langKey)) {
479
+ $fallbackWasString = false;
480
+ $fallbackLanguage = langKey;
481
+ }
482
+ if (angular.isString($preferredLanguage) && indexOf($fallbackLanguage, $preferredLanguage) < 0) {
483
+ $fallbackLanguage.push($preferredLanguage);
484
+ }
485
+
486
+ return this;
487
+ } else {
488
+ if ($fallbackWasString) {
489
+ return $fallbackLanguage[0];
490
+ } else {
491
+ return $fallbackLanguage;
492
+ }
493
+ }
494
+ };
495
+
496
+ /**
497
+ * @ngdoc function
498
+ * @name pascalprecht.translate.$translateProvider#use
499
+ * @methodOf pascalprecht.translate.$translateProvider
500
+ *
501
+ * @description
502
+ * Set which translation table to use for translation by given language key. When
503
+ * trying to 'use' a language which isn't provided, it'll throw an error.
504
+ *
505
+ * You actually don't have to use this method since `$translateProvider#preferredLanguage`
506
+ * does the job too.
507
+ *
508
+ * @param {string} langKey A language key.
509
+ */
510
+ this.use = function (langKey) {
511
+ if (langKey) {
512
+ if (!$translationTable[langKey] && (!$loaderFactory)) {
513
+ // only throw an error, when not loading translation data asynchronously
514
+ throw new Error("$translateProvider couldn't find translationTable for langKey: '" + langKey + "'");
515
+ }
516
+ $uses = langKey;
517
+ return this;
518
+ }
519
+ return $uses;
520
+ };
521
+
522
+ /**
523
+ * @ngdoc function
524
+ * @name pascalprecht.translate.$translateProvider#storageKey
525
+ * @methodOf pascalprecht.translate.$translateProvider
526
+ *
527
+ * @description
528
+ * Tells the module which key must represent the choosed language by a user in the storage.
529
+ *
530
+ * @param {string} key A key for the storage.
531
+ */
532
+ var storageKey = function(key) {
533
+ if (!key) {
534
+ if ($storagePrefix) {
535
+ return $storagePrefix + $storageKey;
536
+ }
537
+ return $storageKey;
538
+ }
539
+ $storageKey = key;
540
+ };
541
+
542
+ this.storageKey = storageKey;
543
+
544
+ /**
545
+ * @ngdoc function
546
+ * @name pascalprecht.translate.$translateProvider#useUrlLoader
547
+ * @methodOf pascalprecht.translate.$translateProvider
548
+ *
549
+ * @description
550
+ * Tells angular-translate to use `$translateUrlLoader` extension service as loader.
551
+ *
552
+ * @param {string} url Url
553
+ * @param {Object=} options Optional configuration object
554
+ */
555
+ this.useUrlLoader = function (url, options) {
556
+ return this.useLoader('$translateUrlLoader', angular.extend({ url: url }, options));
557
+ };
558
+
559
+ /**
560
+ * @ngdoc function
561
+ * @name pascalprecht.translate.$translateProvider#useStaticFilesLoader
562
+ * @methodOf pascalprecht.translate.$translateProvider
563
+ *
564
+ * @description
565
+ * Tells angular-translate to use `$translateStaticFilesLoader` extension service as loader.
566
+ *
567
+ * @param {Object=} options Optional configuration object
568
+ */
569
+ this.useStaticFilesLoader = function (options) {
570
+ return this.useLoader('$translateStaticFilesLoader', options);
571
+ };
572
+
573
+ /**
574
+ * @ngdoc function
575
+ * @name pascalprecht.translate.$translateProvider#useLoader
576
+ * @methodOf pascalprecht.translate.$translateProvider
577
+ *
578
+ * @description
579
+ * Tells angular-translate to use any other service as loader.
580
+ *
581
+ * @param {string} loaderFactory Factory name to use
582
+ * @param {Object=} options Optional configuration object
583
+ */
584
+ this.useLoader = function (loaderFactory, options) {
585
+ $loaderFactory = loaderFactory;
586
+ $loaderOptions = options || {};
587
+ return this;
588
+ };
589
+
590
+ /**
591
+ * @ngdoc function
592
+ * @name pascalprecht.translate.$translateProvider#useLocalStorage
593
+ * @methodOf pascalprecht.translate.$translateProvider
594
+ *
595
+ * @description
596
+ * Tells angular-translate to use `$translateLocalStorage` service as storage layer.
597
+ *
598
+ */
599
+ this.useLocalStorage = function () {
600
+ return this.useStorage('$translateLocalStorage');
601
+ };
602
+
603
+ /**
604
+ * @ngdoc function
605
+ * @name pascalprecht.translate.$translateProvider#useCookieStorage
606
+ * @methodOf pascalprecht.translate.$translateProvider
607
+ *
608
+ * @description
609
+ * Tells angular-translate to use `$translateCookieStorage` service as storage layer.
610
+ */
611
+ this.useCookieStorage = function () {
612
+ return this.useStorage('$translateCookieStorage');
613
+ };
614
+
615
+ /**
616
+ * @ngdoc function
617
+ * @name pascalprecht.translate.$translateProvider#useStorage
618
+ * @methodOf pascalprecht.translate.$translateProvider
619
+ *
620
+ * @description
621
+ * Tells angular-translate to use custom service as storage layer.
622
+ */
623
+ this.useStorage = function (storageFactory) {
624
+ $storageFactory = storageFactory;
625
+ return this;
626
+ };
627
+
628
+ /**
629
+ * @ngdoc function
630
+ * @name pascalprecht.translate.$translateProvider#storagePrefix
631
+ * @methodOf pascalprecht.translate.$translateProvider
632
+ *
633
+ * @description
634
+ * Sets prefix for storage key.
635
+ *
636
+ * @param {string} prefix Storage key prefix
637
+ */
638
+ this.storagePrefix = function (prefix) {
639
+ if (!prefix) {
640
+ return prefix;
641
+ }
642
+ $storagePrefix = prefix;
643
+ return this;
644
+ };
645
+
646
+ /**
647
+ * @ngdoc function
648
+ * @name pascalprecht.translate.$translateProvider#useMissingTranslationHandlerLog
649
+ * @methodOf pascalprecht.translate.$translateProvider
650
+ *
651
+ * @description
652
+ * Tells angular-translate to use built-in log handler when trying to translate
653
+ * a translation Id which doesn't exist.
654
+ *
655
+ * This is actually a shortcut method for `useMissingTranslationHandler()`.
656
+ *
657
+ */
658
+ this.useMissingTranslationHandlerLog = function () {
659
+ return this.useMissingTranslationHandler('$translateMissingTranslationHandlerLog');
660
+ };
661
+
662
+ /**
663
+ * @ngdoc function
664
+ * @name pascalprecht.translate.$translateProvider#useMissingTranslationHandler
665
+ * @methodOf pascalprecht.translate.$translateProvider
666
+ *
667
+ * @description
668
+ * Expects a factory name which later gets instantiated with `$injector`.
669
+ * This method can be used to tell angular-translate to use a custom
670
+ * missingTranslationHandler. Just build a factory which returns a function
671
+ * and expects a translation id as argument.
672
+ *
673
+ * Example:
674
+ * <pre>
675
+ * app.config(function ($translateProvider) {
676
+ * $translateProvider.useMissingTranslationHandler('customHandler');
677
+ * });
678
+ *
679
+ * app.factory('customHandler', function (dep1, dep2) {
680
+ * return function (translationId) {
681
+ * // something with translationId and dep1 and dep2
682
+ * };
683
+ * });
684
+ * </pre>
685
+ *
686
+ * @param {string} factory Factory name
687
+ */
688
+ this.useMissingTranslationHandler = function (factory) {
689
+ $missingTranslationHandlerFactory = factory;
690
+ return this;
691
+ };
692
+
693
+ /**
694
+ * @ngdoc function
695
+ * @name pascalprecht.translate.$translateProvider#usePostCompiling
696
+ * @methodOf pascalprecht.translate.$translateProvider
697
+ *
698
+ * @description
699
+ * If post compiling is enabled, all translated values will be processed
700
+ * again with AngularJS' $compile.
701
+ *
702
+ * Example:
703
+ * <pre>
704
+ * app.config(function ($translateProvider) {
705
+ * $translateProvider.usePostCompiling(true);
706
+ * });
707
+ * </pre>
708
+ *
709
+ * @param {string} factory Factory name
710
+ */
711
+ this.usePostCompiling = function (value) {
712
+ $postCompilingEnabled = !(!value);
713
+ return this;
714
+ };
715
+
716
+ /**
717
+ * @ngdoc function
718
+ * @name pascalprecht.translate.$translateProvider#determinePreferredLanguage
719
+ * @methodOf pascalprecht.translate.$translateProvider
720
+ *
721
+ * @description
722
+ * Tells angular-translate to try to determine on its own which language key
723
+ * to set as preferred language. When `fn` is given, angular-translate uses it
724
+ * to determine a language key, otherwise it uses the built-in `getLocale()`
725
+ * method.
726
+ *
727
+ * The `getLocale()` returns a language key in the format `[lang]_[country]` or
728
+ * `[lang]` depending on what the browser provides.
729
+ *
730
+ * Use this method at your own risk, since not all browsers return a valid
731
+ * locale.
732
+ *
733
+ * @param {object=} fn Function to determine a browser's locale
734
+ */
735
+ this.determinePreferredLanguage = function (fn) {
736
+
737
+ var locale = (fn && angular.isFunction(fn)) ? fn() : getLocale();
738
+
739
+ if (!$availableLanguageKeys.length) {
740
+ $preferredLanguage = locale;
741
+ } else {
742
+ $preferredLanguage = negotiateLocale(locale);
743
+ }
744
+
745
+ return this;
746
+ };
747
+
748
+ /**
749
+ * @ngdoc function
750
+ * @name pascalprecht.translate.$translateProvider#registerAvailableLanguageKeys
751
+ * @methodOf pascalprecht.translate.$translateProvider
752
+ *
753
+ * @description
754
+ * Registers a set of language keys the app will work with. Use this method in
755
+ * combination with
756
+ * {@link pascalprecht.translate.$translateProvider#determinePreferredLanguage determinePreferredLanguage}.
757
+ * When available languages keys are registered, angular-translate
758
+ * tries to find the best fitting language key depending on the browsers locale,
759
+ * considering your language key convention.
760
+ *
761
+ * @param {object} languageKeys Array of language keys the your app will use
762
+ * @param {object=} aliases Alias map.
763
+ */
764
+ this.registerAvailableLanguageKeys = function (languageKeys, aliases) {
765
+ if (languageKeys) {
766
+ $availableLanguageKeys = languageKeys;
767
+ if (aliases) {
768
+ $languageKeyAliases = aliases;
769
+ }
770
+ return this;
771
+ }
772
+ return $availableLanguageKeys;
773
+ };
774
+
775
+ /**
776
+ * @ngdoc function
777
+ * @name pascalprecht.translate.$translateProvider#useLoaderCache
778
+ * @methodOf pascalprecht.translate.$translateProvider
779
+ *
780
+ * @description
781
+ * Registers a cache for internal $http based loaders.
782
+ * {@link pascalprecht.translate.$translateProvider#determinePreferredLanguage determinePreferredLanguage}.
783
+ * When false the cache will be disabled (default). When true or undefined
784
+ * the cache will be a default (see $cacheFactory). When an object it will
785
+ * be treat as a cache object itself: the usage is $http({cache: cache})
786
+ *
787
+ * @param {object} cache boolean, string or cache-object
788
+ */
789
+ this.useLoaderCache = function (cache) {
790
+ if (cache === false) {
791
+ // disable cache
792
+ loaderCache = undefined;
793
+ } else if (cache === true) {
794
+ // enable cache using AJS defaults
795
+ loaderCache = true;
796
+ } else if (typeof(cache) === 'undefined') {
797
+ // enable cache using default
798
+ loaderCache = '$translationCache';
799
+ } else if (cache) {
800
+ // enable cache using given one (see $cacheFactory)
801
+ loaderCache = cache;
802
+ }
803
+ return this;
804
+ };
805
+
806
+ /**
807
+ * @ngdoc function
808
+ * @name pascalprecht.translate.$translateProvider#directivePriority
809
+ * @methodOf pascalprecht.translate.$translateProvider
810
+ *
811
+ * @description
812
+ * Sets the default priority of the translate directive. The standard value is `0`.
813
+ * Calling this function without an argument will return the current value.
814
+ *
815
+ * @param {number} priority for the translate-directive
816
+ */
817
+ this.directivePriority = function (priority) {
818
+ if (priority === undefined) {
819
+ // getter
820
+ return directivePriority;
821
+ } else {
822
+ // setter with chaining
823
+ directivePriority = priority;
824
+ return this;
825
+ }
826
+ };
827
+
828
+ /**
829
+ * @ngdoc object
830
+ * @name pascalprecht.translate.$translate
831
+ * @requires $interpolate
832
+ * @requires $log
833
+ * @requires $rootScope
834
+ * @requires $q
835
+ *
836
+ * @description
837
+ * The `$translate` service is the actual core of angular-translate. It expects a translation id
838
+ * and optional interpolate parameters to translate contents.
839
+ *
840
+ * <pre>
841
+ * $translate('HEADLINE_TEXT').then(function (translation) {
842
+ * $scope.translatedText = translation;
843
+ * });
844
+ * </pre>
845
+ *
846
+ * @param {string|array} translationId A token which represents a translation id
847
+ * This can be optionally an array of translation ids which
848
+ * results that the function returns an object where each key
849
+ * is the translation id and the value the translation.
850
+ * @param {object=} interpolateParams An object hash for dynamic values
851
+ * @param {string} interpolationId The id of the interpolation to use
852
+ * @returns {object} promise
853
+ */
854
+ this.$get = [
855
+ '$log',
856
+ '$injector',
857
+ '$rootScope',
858
+ '$q',
859
+ function ($log, $injector, $rootScope, $q) {
860
+
861
+ var Storage,
862
+ defaultInterpolator = $injector.get($interpolationFactory || '$translateDefaultInterpolation'),
863
+ pendingLoader = false,
864
+ interpolatorHashMap = {},
865
+ langPromises = {},
866
+ fallbackIndex,
867
+ startFallbackIteration;
868
+
869
+ var $translate = function (translationId, interpolateParams, interpolationId, defaultTranslationText) {
870
+
871
+ // Duck detection: If the first argument is an array, a bunch of translations was requested.
872
+ // The result is an object.
873
+ if (angular.isArray(translationId)) {
874
+ // Inspired by Q.allSettled by Kris Kowal
875
+ // https://github.com/kriskowal/q/blob/b0fa72980717dc202ffc3cbf03b936e10ebbb9d7/q.js#L1553-1563
876
+ // This transforms all promises regardless resolved or rejected
877
+ var translateAll = function (translationIds) {
878
+ var results = {}; // storing the actual results
879
+ var promises = []; // promises to wait for
880
+ // Wraps the promise a) being always resolved and b) storing the link id->value
881
+ var translate = function (translationId) {
882
+ var deferred = $q.defer();
883
+ var regardless = function (value) {
884
+ results[translationId] = value;
885
+ deferred.resolve([translationId, value]);
886
+ };
887
+ // we don't care whether the promise was resolved or rejected; just store the values
888
+ $translate(translationId, interpolateParams, interpolationId, defaultTranslationText).then(regardless, regardless);
889
+ return deferred.promise;
890
+ };
891
+ for (var i = 0, c = translationIds.length; i < c; i++) {
892
+ promises.push(translate(translationIds[i]));
893
+ }
894
+ // wait for all (including storing to results)
895
+ return $q.all(promises).then(function () {
896
+ // return the results
897
+ return results;
898
+ });
899
+ };
900
+ return translateAll(translationId);
901
+ }
902
+
903
+ var deferred = $q.defer();
904
+
905
+ // trim off any whitespace
906
+ if (translationId) {
907
+ translationId = trim.apply(translationId);
908
+ }
909
+
910
+ var promiseToWaitFor = (function () {
911
+ var promise = $preferredLanguage ?
912
+ langPromises[$preferredLanguage] :
913
+ langPromises[$uses];
914
+
915
+ fallbackIndex = 0;
916
+
917
+ if ($storageFactory && !promise) {
918
+ // looks like there's no pending promise for $preferredLanguage or
919
+ // $uses. Maybe there's one pending for a language that comes from
920
+ // storage.
921
+ var langKey = Storage.get($storageKey);
922
+ promise = langPromises[langKey];
923
+
924
+ if ($fallbackLanguage && $fallbackLanguage.length) {
925
+ var index = indexOf($fallbackLanguage, langKey);
926
+ // maybe the language from storage is also defined as fallback language
927
+ // we increase the fallback language index to not search in that language
928
+ // as fallback, since it's probably the first used language
929
+ // in that case the index starts after the first element
930
+ fallbackIndex = (index === 0) ? 1 : 0;
931
+
932
+ // but we can make sure to ALWAYS fallback to preferred language at least
933
+ if (indexOf($fallbackLanguage, $preferredLanguage) < 0) {
934
+ $fallbackLanguage.push($preferredLanguage);
935
+ }
936
+ }
937
+ }
938
+ return promise;
939
+ }());
940
+
941
+ if (!promiseToWaitFor) {
942
+ // no promise to wait for? okay. Then there's no loader registered
943
+ // nor is a one pending for language that comes from storage.
944
+ // We can just translate.
945
+ determineTranslation(translationId, interpolateParams, interpolationId, defaultTranslationText).then(deferred.resolve, deferred.reject);
946
+ } else {
947
+ promiseToWaitFor.then(function () {
948
+ determineTranslation(translationId, interpolateParams, interpolationId, defaultTranslationText).then(deferred.resolve, deferred.reject);
949
+ }, deferred.reject);
950
+ }
951
+ return deferred.promise;
952
+ };
953
+
954
+ /**
955
+ * @name applyNotFoundIndicators
956
+ * @private
957
+ *
958
+ * @description
959
+ * Applies not fount indicators to given translation id, if needed.
960
+ * This function gets only executed, if a translation id doesn't exist,
961
+ * which is why a translation id is expected as argument.
962
+ *
963
+ * @param {string} translationId Translation id.
964
+ * @returns {string} Same as given translation id but applied with not found
965
+ * indicators.
966
+ */
967
+ var applyNotFoundIndicators = function (translationId) {
968
+ // applying notFoundIndicators
969
+ if ($notFoundIndicatorLeft) {
970
+ translationId = [$notFoundIndicatorLeft, translationId].join(' ');
971
+ }
972
+ if ($notFoundIndicatorRight) {
973
+ translationId = [translationId, $notFoundIndicatorRight].join(' ');
974
+ }
975
+ return translationId;
976
+ };
977
+
978
+ /**
979
+ * @name useLanguage
980
+ * @private
981
+ *
982
+ * @description
983
+ * Makes actual use of a language by setting a given language key as used
984
+ * language and informs registered interpolators to also use the given
985
+ * key as locale.
986
+ *
987
+ * @param {key} Locale key.
988
+ */
989
+ var useLanguage = function (key) {
990
+ $uses = key;
991
+ $rootScope.$emit('$translateChangeSuccess', {language: key});
992
+
993
+ if ($storageFactory) {
994
+ Storage.put($translate.storageKey(), $uses);
995
+ }
996
+ // inform default interpolator
997
+ defaultInterpolator.setLocale($uses);
998
+ // inform all others too!
999
+ angular.forEach(interpolatorHashMap, function (interpolator, id) {
1000
+ interpolatorHashMap[id].setLocale($uses);
1001
+ });
1002
+ $rootScope.$emit('$translateChangeEnd', {language: key});
1003
+ };
1004
+
1005
+ /**
1006
+ * @name loadAsync
1007
+ * @private
1008
+ *
1009
+ * @description
1010
+ * Kicks of registered async loader using `$injector` and applies existing
1011
+ * loader options. When resolved, it updates translation tables accordingly
1012
+ * or rejects with given language key.
1013
+ *
1014
+ * @param {string} key Language key.
1015
+ * @return {Promise} A promise.
1016
+ */
1017
+ var loadAsync = function (key) {
1018
+ if (!key) {
1019
+ throw 'No language key specified for loading.';
1020
+ }
1021
+
1022
+ var deferred = $q.defer();
1023
+
1024
+ $rootScope.$emit('$translateLoadingStart', {language: key});
1025
+ pendingLoader = true;
1026
+
1027
+ var cache = loaderCache;
1028
+ if (typeof(cache) === 'string') {
1029
+ // getting on-demand instance of loader
1030
+ cache = $injector.get(cache);
1031
+ }
1032
+
1033
+ var loaderOptions = angular.extend({}, $loaderOptions, {
1034
+ key: key,
1035
+ $http: angular.extend({}, {
1036
+ cache: cache
1037
+ }, $loaderOptions.$http)
1038
+ });
1039
+
1040
+ $injector.get($loaderFactory)(loaderOptions).then(function (data) {
1041
+ var translationTable = {};
1042
+ $rootScope.$emit('$translateLoadingSuccess', {language: key});
1043
+
1044
+ if (angular.isArray(data)) {
1045
+ angular.forEach(data, function (table) {
1046
+ angular.extend(translationTable, flatObject(table));
1047
+ });
1048
+ } else {
1049
+ angular.extend(translationTable, flatObject(data));
1050
+ }
1051
+ pendingLoader = false;
1052
+ deferred.resolve({
1053
+ key: key,
1054
+ table: translationTable
1055
+ });
1056
+ $rootScope.$emit('$translateLoadingEnd', {language: key});
1057
+ }, function (key) {
1058
+ $rootScope.$emit('$translateLoadingError', {language: key});
1059
+ deferred.reject(key);
1060
+ $rootScope.$emit('$translateLoadingEnd', {language: key});
1061
+ });
1062
+ return deferred.promise;
1063
+ };
1064
+
1065
+ if ($storageFactory) {
1066
+ Storage = $injector.get($storageFactory);
1067
+
1068
+ if (!Storage.get || !Storage.put) {
1069
+ throw new Error('Couldn\'t use storage \'' + $storageFactory + '\', missing get() or put() method!');
1070
+ }
1071
+ }
1072
+
1073
+ // apply additional settings
1074
+ if (angular.isFunction(defaultInterpolator.useSanitizeValueStrategy)) {
1075
+ defaultInterpolator.useSanitizeValueStrategy($interpolationSanitizationStrategy);
1076
+ }
1077
+
1078
+ // if we have additional interpolations that were added via
1079
+ // $translateProvider.addInterpolation(), we have to map'em
1080
+ if ($interpolatorFactories.length) {
1081
+ angular.forEach($interpolatorFactories, function (interpolatorFactory) {
1082
+ var interpolator = $injector.get(interpolatorFactory);
1083
+ // setting initial locale for each interpolation service
1084
+ interpolator.setLocale($preferredLanguage || $uses);
1085
+ // apply additional settings
1086
+ if (angular.isFunction(interpolator.useSanitizeValueStrategy)) {
1087
+ interpolator.useSanitizeValueStrategy($interpolationSanitizationStrategy);
1088
+ }
1089
+ // make'em recognizable through id
1090
+ interpolatorHashMap[interpolator.getInterpolationIdentifier()] = interpolator;
1091
+ });
1092
+ }
1093
+
1094
+ /**
1095
+ * @name getTranslationTable
1096
+ * @private
1097
+ *
1098
+ * @description
1099
+ * Returns a promise that resolves to the translation table
1100
+ * or is rejected if an error occurred.
1101
+ *
1102
+ * @param langKey
1103
+ * @returns {Q.promise}
1104
+ */
1105
+ var getTranslationTable = function (langKey) {
1106
+ var deferred = $q.defer();
1107
+ if (Object.prototype.hasOwnProperty.call($translationTable, langKey)) {
1108
+ deferred.resolve($translationTable[langKey]);
1109
+ } else if (langPromises[langKey]) {
1110
+ langPromises[langKey].then(function (data) {
1111
+ translations(data.key, data.table);
1112
+ deferred.resolve(data.table);
1113
+ }, deferred.reject);
1114
+ } else {
1115
+ deferred.reject();
1116
+ }
1117
+ return deferred.promise;
1118
+ };
1119
+
1120
+ /**
1121
+ * @name getFallbackTranslation
1122
+ * @private
1123
+ *
1124
+ * @description
1125
+ * Returns a promise that will resolve to the translation
1126
+ * or be rejected if no translation was found for the language.
1127
+ * This function is currently only used for fallback language translation.
1128
+ *
1129
+ * @param langKey The language to translate to.
1130
+ * @param translationId
1131
+ * @param interpolateParams
1132
+ * @param Interpolator
1133
+ * @returns {Q.promise}
1134
+ */
1135
+ var getFallbackTranslation = function (langKey, translationId, interpolateParams, Interpolator) {
1136
+ var deferred = $q.defer();
1137
+
1138
+ getTranslationTable(langKey).then(function (translationTable) {
1139
+ if (Object.prototype.hasOwnProperty.call(translationTable, translationId)) {
1140
+ Interpolator.setLocale(langKey);
1141
+ var translation = translationTable[translationId];
1142
+ if (translation.substr(0, 2) === '@:') {
1143
+ getFallbackTranslation(langKey, translation.substr(2), interpolateParams, Interpolator)
1144
+ .then(deferred.resolve, deferred.reject);
1145
+ } else {
1146
+ deferred.resolve(Interpolator.interpolate(translationTable[translationId], interpolateParams));
1147
+ }
1148
+ Interpolator.setLocale($uses);
1149
+ } else {
1150
+ deferred.reject();
1151
+ }
1152
+ }, deferred.reject);
1153
+
1154
+ return deferred.promise;
1155
+ };
1156
+
1157
+ /**
1158
+ * @name getFallbackTranslationInstant
1159
+ * @private
1160
+ *
1161
+ * @description
1162
+ * Returns a translation
1163
+ * This function is currently only used for fallback language translation.
1164
+ *
1165
+ * @param langKey The language to translate to.
1166
+ * @param translationId
1167
+ * @param interpolateParams
1168
+ * @param Interpolator
1169
+ * @returns {string} translation
1170
+ */
1171
+ var getFallbackTranslationInstant = function (langKey, translationId, interpolateParams, Interpolator) {
1172
+ var result, translationTable = $translationTable[langKey];
1173
+
1174
+ if (translationTable && Object.prototype.hasOwnProperty.call(translationTable, translationId)) {
1175
+ Interpolator.setLocale(langKey);
1176
+ result = Interpolator.interpolate(translationTable[translationId], interpolateParams);
1177
+ if (result.substr(0, 2) === '@:') {
1178
+ return getFallbackTranslationInstant(langKey, result.substr(2), interpolateParams, Interpolator);
1179
+ }
1180
+ Interpolator.setLocale($uses);
1181
+ }
1182
+
1183
+ return result;
1184
+ };
1185
+
1186
+
1187
+ /**
1188
+ * @name translateByHandler
1189
+ * @private
1190
+ *
1191
+ * Translate by missing translation handler.
1192
+ *
1193
+ * @param translationId
1194
+ * @returns translation created by $missingTranslationHandler or translationId is $missingTranslationHandler is
1195
+ * absent
1196
+ */
1197
+ var translateByHandler = function (translationId) {
1198
+ // If we have a handler factory - we might also call it here to determine if it provides
1199
+ // a default text for a translationid that can't be found anywhere in our tables
1200
+ if ($missingTranslationHandlerFactory) {
1201
+ var resultString = $injector.get($missingTranslationHandlerFactory)(translationId, $uses);
1202
+ if (resultString !== undefined) {
1203
+ return resultString;
1204
+ } else {
1205
+ return translationId;
1206
+ }
1207
+ } else {
1208
+ return translationId;
1209
+ }
1210
+ };
1211
+
1212
+ /**
1213
+ * @name resolveForFallbackLanguage
1214
+ * @private
1215
+ *
1216
+ * Recursive helper function for fallbackTranslation that will sequentially look
1217
+ * for a translation in the fallbackLanguages starting with fallbackLanguageIndex.
1218
+ *
1219
+ * @param fallbackLanguageIndex
1220
+ * @param translationId
1221
+ * @param interpolateParams
1222
+ * @param Interpolator
1223
+ * @returns {Q.promise} Promise that will resolve to the translation.
1224
+ */
1225
+ var resolveForFallbackLanguage = function (fallbackLanguageIndex, translationId, interpolateParams, Interpolator, defaultTranslationText) {
1226
+ var deferred = $q.defer();
1227
+
1228
+ if (fallbackLanguageIndex < $fallbackLanguage.length) {
1229
+ var langKey = $fallbackLanguage[fallbackLanguageIndex];
1230
+ getFallbackTranslation(langKey, translationId, interpolateParams, Interpolator).then(
1231
+ deferred.resolve,
1232
+ function () {
1233
+ // Look in the next fallback language for a translation.
1234
+ // It delays the resolving by passing another promise to resolve.
1235
+ resolveForFallbackLanguage(fallbackLanguageIndex + 1, translationId, interpolateParams, Interpolator, defaultTranslationText).then(deferred.resolve);
1236
+ }
1237
+ );
1238
+ } else {
1239
+ // No translation found in any fallback language
1240
+ // if a default translation text is set in the directive, then return this as a result
1241
+ if (defaultTranslationText) {
1242
+ deferred.resolve(defaultTranslationText);
1243
+ } else {
1244
+ // if no default translation is set and an error handler is defined, send it to the handler
1245
+ // and then return the result
1246
+ deferred.resolve(translateByHandler(translationId));
1247
+ }
1248
+ }
1249
+ return deferred.promise;
1250
+ };
1251
+
1252
+ /**
1253
+ * @name resolveForFallbackLanguageInstant
1254
+ * @private
1255
+ *
1256
+ * Recursive helper function for fallbackTranslation that will sequentially look
1257
+ * for a translation in the fallbackLanguages starting with fallbackLanguageIndex.
1258
+ *
1259
+ * @param fallbackLanguageIndex
1260
+ * @param translationId
1261
+ * @param interpolateParams
1262
+ * @param Interpolator
1263
+ * @returns {string} translation
1264
+ */
1265
+ var resolveForFallbackLanguageInstant = function (fallbackLanguageIndex, translationId, interpolateParams, Interpolator) {
1266
+ var result;
1267
+
1268
+ if (fallbackLanguageIndex < $fallbackLanguage.length) {
1269
+ var langKey = $fallbackLanguage[fallbackLanguageIndex];
1270
+ result = getFallbackTranslationInstant(langKey, translationId, interpolateParams, Interpolator);
1271
+ if (!result) {
1272
+ result = resolveForFallbackLanguageInstant(fallbackLanguageIndex + 1, translationId, interpolateParams, Interpolator);
1273
+ }
1274
+ }
1275
+ return result;
1276
+ };
1277
+
1278
+ /**
1279
+ * Translates with the usage of the fallback languages.
1280
+ *
1281
+ * @param translationId
1282
+ * @param interpolateParams
1283
+ * @param Interpolator
1284
+ * @returns {Q.promise} Promise, that resolves to the translation.
1285
+ */
1286
+ var fallbackTranslation = function (translationId, interpolateParams, Interpolator, defaultTranslationText) {
1287
+ // Start with the fallbackLanguage with index 0
1288
+ return resolveForFallbackLanguage((startFallbackIteration>0 ? startFallbackIteration : fallbackIndex), translationId, interpolateParams, Interpolator, defaultTranslationText);
1289
+ };
1290
+
1291
+ /**
1292
+ * Translates with the usage of the fallback languages.
1293
+ *
1294
+ * @param translationId
1295
+ * @param interpolateParams
1296
+ * @param Interpolator
1297
+ * @returns {String} translation
1298
+ */
1299
+ var fallbackTranslationInstant = function (translationId, interpolateParams, Interpolator) {
1300
+ // Start with the fallbackLanguage with index 0
1301
+ return resolveForFallbackLanguageInstant((startFallbackIteration>0 ? startFallbackIteration : fallbackIndex), translationId, interpolateParams, Interpolator);
1302
+ };
1303
+
1304
+ var determineTranslation = function (translationId, interpolateParams, interpolationId, defaultTranslationText) {
1305
+
1306
+ var deferred = $q.defer();
1307
+
1308
+ var table = $uses ? $translationTable[$uses] : $translationTable,
1309
+ Interpolator = (interpolationId) ? interpolatorHashMap[interpolationId] : defaultInterpolator;
1310
+
1311
+ // if the translation id exists, we can just interpolate it
1312
+ if (table && Object.prototype.hasOwnProperty.call(table, translationId)) {
1313
+ var translation = table[translationId];
1314
+
1315
+ // If using link, rerun $translate with linked translationId and return it
1316
+ if (translation.substr(0, 2) === '@:') {
1317
+
1318
+ $translate(translation.substr(2), interpolateParams, interpolationId, defaultTranslationText)
1319
+ .then(deferred.resolve, deferred.reject);
1320
+ } else {
1321
+ deferred.resolve(Interpolator.interpolate(translation, interpolateParams));
1322
+ }
1323
+ } else {
1324
+ var missingTranslationHandlerTranslation;
1325
+ // for logging purposes only (as in $translateMissingTranslationHandlerLog), value is not returned to promise
1326
+ if ($missingTranslationHandlerFactory && !pendingLoader) {
1327
+ missingTranslationHandlerTranslation = translateByHandler(translationId);
1328
+ }
1329
+
1330
+ // since we couldn't translate the inital requested translation id,
1331
+ // we try it now with one or more fallback languages, if fallback language(s) is
1332
+ // configured.
1333
+ if ($uses && $fallbackLanguage && $fallbackLanguage.length) {
1334
+ fallbackTranslation(translationId, interpolateParams, Interpolator, defaultTranslationText)
1335
+ .then(function (translation) {
1336
+ deferred.resolve(translation);
1337
+ }, function (_translationId) {
1338
+ deferred.reject(applyNotFoundIndicators(_translationId));
1339
+ });
1340
+ } else if ($missingTranslationHandlerFactory && !pendingLoader && missingTranslationHandlerTranslation) {
1341
+ // looks like the requested translation id doesn't exists.
1342
+ // Now, if there is a registered handler for missing translations and no
1343
+ // asyncLoader is pending, we execute the handler
1344
+ if (defaultTranslationText) {
1345
+ deferred.resolve(defaultTranslationText);
1346
+ } else {
1347
+ deferred.resolve(missingTranslationHandlerTranslation);
1348
+ }
1349
+ } else {
1350
+ if (defaultTranslationText) {
1351
+ deferred.resolve(defaultTranslationText);
1352
+ } else {
1353
+ deferred.reject(applyNotFoundIndicators(translationId));
1354
+ }
1355
+ }
1356
+ }
1357
+ return deferred.promise;
1358
+ };
1359
+
1360
+ var determineTranslationInstant = function (translationId, interpolateParams, interpolationId) {
1361
+
1362
+ var result, table = $uses ? $translationTable[$uses] : $translationTable,
1363
+ Interpolator = defaultInterpolator;
1364
+
1365
+ // if the interpolation id exists use custom interpolator
1366
+ if (interpolatorHashMap && Object.prototype.hasOwnProperty.call(interpolatorHashMap, interpolationId)) {
1367
+ Interpolator = interpolatorHashMap[interpolationId];
1368
+ }
1369
+
1370
+ // if the translation id exists, we can just interpolate it
1371
+ if (table && Object.prototype.hasOwnProperty.call(table, translationId)) {
1372
+ var translation = table[translationId];
1373
+
1374
+ // If using link, rerun $translate with linked translationId and return it
1375
+ if (translation.substr(0, 2) === '@:') {
1376
+ result = determineTranslationInstant(translation.substr(2), interpolateParams, interpolationId);
1377
+ } else {
1378
+ result = Interpolator.interpolate(translation, interpolateParams);
1379
+ }
1380
+ } else {
1381
+ var missingTranslationHandlerTranslation;
1382
+ // for logging purposes only (as in $translateMissingTranslationHandlerLog), value is not returned to promise
1383
+ if ($missingTranslationHandlerFactory && !pendingLoader) {
1384
+ missingTranslationHandlerTranslation = translateByHandler(translationId);
1385
+ }
1386
+
1387
+ // since we couldn't translate the inital requested translation id,
1388
+ // we try it now with one or more fallback languages, if fallback language(s) is
1389
+ // configured.
1390
+ if ($uses && $fallbackLanguage && $fallbackLanguage.length) {
1391
+ fallbackIndex = 0;
1392
+ result = fallbackTranslationInstant(translationId, interpolateParams, Interpolator);
1393
+ } else if ($missingTranslationHandlerFactory && !pendingLoader && missingTranslationHandlerTranslation) {
1394
+ // looks like the requested translation id doesn't exists.
1395
+ // Now, if there is a registered handler for missing translations and no
1396
+ // asyncLoader is pending, we execute the handler
1397
+ result = missingTranslationHandlerTranslation;
1398
+ } else {
1399
+ result = applyNotFoundIndicators(translationId);
1400
+ }
1401
+ }
1402
+
1403
+ return result;
1404
+ };
1405
+
1406
+ /**
1407
+ * @ngdoc function
1408
+ * @name pascalprecht.translate.$translate#preferredLanguage
1409
+ * @methodOf pascalprecht.translate.$translate
1410
+ *
1411
+ * @description
1412
+ * Returns the language key for the preferred language.
1413
+ *
1414
+ * @param {string} langKey language String or Array to be used as preferredLanguage (changing at runtime)
1415
+ *
1416
+ * @return {string} preferred language key
1417
+ */
1418
+ $translate.preferredLanguage = function (langKey) {
1419
+ if(langKey) {
1420
+ setupPreferredLanguage(langKey);
1421
+ }
1422
+ return $preferredLanguage;
1423
+ };
1424
+
1425
+ /**
1426
+ * @ngdoc function
1427
+ * @name pascalprecht.translate.$translate#cloakClassName
1428
+ * @methodOf pascalprecht.translate.$translate
1429
+ *
1430
+ * @description
1431
+ * Returns the configured class name for `translate-cloak` directive.
1432
+ *
1433
+ * @return {string} cloakClassName
1434
+ */
1435
+ $translate.cloakClassName = function () {
1436
+ return $cloakClassName;
1437
+ };
1438
+
1439
+ /**
1440
+ * @ngdoc function
1441
+ * @name pascalprecht.translate.$translate#fallbackLanguage
1442
+ * @methodOf pascalprecht.translate.$translate
1443
+ *
1444
+ * @description
1445
+ * Returns the language key for the fallback languages or sets a new fallback stack.
1446
+ *
1447
+ * @param {string=} langKey language String or Array of fallback languages to be used (to change stack at runtime)
1448
+ *
1449
+ * @return {string||array} fallback language key
1450
+ */
1451
+ $translate.fallbackLanguage = function (langKey) {
1452
+ if (langKey !== undefined && langKey !== null) {
1453
+ fallbackStack(langKey);
1454
+
1455
+ // as we might have an async loader initiated and a new translation language might have been defined
1456
+ // we need to add the promise to the stack also. So - iterate.
1457
+ if ($loaderFactory) {
1458
+ if ($fallbackLanguage && $fallbackLanguage.length) {
1459
+ for (var i = 0, len = $fallbackLanguage.length; i < len; i++) {
1460
+ if (!langPromises[$fallbackLanguage[i]]) {
1461
+ langPromises[$fallbackLanguage[i]] = loadAsync($fallbackLanguage[i]);
1462
+ }
1463
+ }
1464
+ }
1465
+ }
1466
+ $translate.use($translate.use());
1467
+ }
1468
+ if ($fallbackWasString) {
1469
+ return $fallbackLanguage[0];
1470
+ } else {
1471
+ return $fallbackLanguage;
1472
+ }
1473
+
1474
+ };
1475
+
1476
+ /**
1477
+ * @ngdoc function
1478
+ * @name pascalprecht.translate.$translate#useFallbackLanguage
1479
+ * @methodOf pascalprecht.translate.$translate
1480
+ *
1481
+ * @description
1482
+ * Sets the first key of the fallback language stack to be used for translation.
1483
+ * Therefore all languages in the fallback array BEFORE this key will be skipped!
1484
+ *
1485
+ * @param {string=} langKey Contains the langKey the iteration shall start with. Set to false if you want to
1486
+ * get back to the whole stack
1487
+ */
1488
+ $translate.useFallbackLanguage = function (langKey) {
1489
+ if (langKey !== undefined && langKey !== null) {
1490
+ if (!langKey) {
1491
+ startFallbackIteration = 0;
1492
+ } else {
1493
+ var langKeyPosition = indexOf($fallbackLanguage, langKey);
1494
+ if (langKeyPosition > -1) {
1495
+ startFallbackIteration = langKeyPosition;
1496
+ }
1497
+ }
1498
+
1499
+ }
1500
+
1501
+ };
1502
+
1503
+ /**
1504
+ * @ngdoc function
1505
+ * @name pascalprecht.translate.$translate#proposedLanguage
1506
+ * @methodOf pascalprecht.translate.$translate
1507
+ *
1508
+ * @description
1509
+ * Returns the language key of language that is currently loaded asynchronously.
1510
+ *
1511
+ * @return {string} language key
1512
+ */
1513
+ $translate.proposedLanguage = function () {
1514
+ return $nextLang;
1515
+ };
1516
+
1517
+ /**
1518
+ * @ngdoc function
1519
+ * @name pascalprecht.translate.$translate#storage
1520
+ * @methodOf pascalprecht.translate.$translate
1521
+ *
1522
+ * @description
1523
+ * Returns registered storage.
1524
+ *
1525
+ * @return {object} Storage
1526
+ */
1527
+ $translate.storage = function () {
1528
+ return Storage;
1529
+ };
1530
+
1531
+ /**
1532
+ * @ngdoc function
1533
+ * @name pascalprecht.translate.$translate#use
1534
+ * @methodOf pascalprecht.translate.$translate
1535
+ *
1536
+ * @description
1537
+ * Tells angular-translate which language to use by given language key. This method is
1538
+ * used to change language at runtime. It also takes care of storing the language
1539
+ * key in a configured store to let your app remember the choosed language.
1540
+ *
1541
+ * When trying to 'use' a language which isn't available it tries to load it
1542
+ * asynchronously with registered loaders.
1543
+ *
1544
+ * Returns promise object with loaded language file data
1545
+ * @example
1546
+ * $translate.use("en_US").then(function(data){
1547
+ * $scope.text = $translate("HELLO");
1548
+ * });
1549
+ *
1550
+ * @param {string} key Language key
1551
+ * @return {string} Language key
1552
+ */
1553
+ $translate.use = function (key) {
1554
+ if (!key) {
1555
+ return $uses;
1556
+ }
1557
+
1558
+ var deferred = $q.defer();
1559
+
1560
+ $rootScope.$emit('$translateChangeStart', {language: key});
1561
+
1562
+ // Try to get the aliased language key
1563
+ var aliasedKey = negotiateLocale(key);
1564
+ if (aliasedKey) {
1565
+ key = aliasedKey;
1566
+ }
1567
+
1568
+ // if there isn't a translation table for the language we've requested,
1569
+ // we load it asynchronously
1570
+ if (!$translationTable[key] && $loaderFactory && !langPromises[key]) {
1571
+ $nextLang = key;
1572
+ langPromises[key] = loadAsync(key).then(function (translation) {
1573
+ translations(translation.key, translation.table);
1574
+ deferred.resolve(translation.key);
1575
+
1576
+ useLanguage(translation.key);
1577
+ if ($nextLang === key) {
1578
+ $nextLang = undefined;
1579
+ }
1580
+ return translation;
1581
+ }, function (key) {
1582
+ if ($nextLang === key) {
1583
+ $nextLang = undefined;
1584
+ }
1585
+ $rootScope.$emit('$translateChangeError', {language: key});
1586
+ deferred.reject(key);
1587
+ $rootScope.$emit('$translateChangeEnd', {language: key});
1588
+ });
1589
+ } else {
1590
+ deferred.resolve(key);
1591
+ useLanguage(key);
1592
+ }
1593
+
1594
+ return deferred.promise;
1595
+ };
1596
+
1597
+ /**
1598
+ * @ngdoc function
1599
+ * @name pascalprecht.translate.$translate#storageKey
1600
+ * @methodOf pascalprecht.translate.$translate
1601
+ *
1602
+ * @description
1603
+ * Returns the key for the storage.
1604
+ *
1605
+ * @return {string} storage key
1606
+ */
1607
+ $translate.storageKey = function () {
1608
+ return storageKey();
1609
+ };
1610
+
1611
+ /**
1612
+ * @ngdoc function
1613
+ * @name pascalprecht.translate.$translate#isPostCompilingEnabled
1614
+ * @methodOf pascalprecht.translate.$translate
1615
+ *
1616
+ * @description
1617
+ * Returns whether post compiling is enabled or not
1618
+ *
1619
+ * @return {bool} storage key
1620
+ */
1621
+ $translate.isPostCompilingEnabled = function () {
1622
+ return $postCompilingEnabled;
1623
+ };
1624
+
1625
+ /**
1626
+ * @ngdoc function
1627
+ * @name pascalprecht.translate.$translate#refresh
1628
+ * @methodOf pascalprecht.translate.$translate
1629
+ *
1630
+ * @description
1631
+ * Refreshes a translation table pointed by the given langKey. If langKey is not specified,
1632
+ * the module will drop all existent translation tables and load new version of those which
1633
+ * are currently in use.
1634
+ *
1635
+ * Refresh means that the module will drop target translation table and try to load it again.
1636
+ *
1637
+ * In case there are no loaders registered the refresh() method will throw an Error.
1638
+ *
1639
+ * If the module is able to refresh translation tables refresh() method will broadcast
1640
+ * $translateRefreshStart and $translateRefreshEnd events.
1641
+ *
1642
+ * @example
1643
+ * // this will drop all currently existent translation tables and reload those which are
1644
+ * // currently in use
1645
+ * $translate.refresh();
1646
+ * // this will refresh a translation table for the en_US language
1647
+ * $translate.refresh('en_US');
1648
+ *
1649
+ * @param {string} langKey A language key of the table, which has to be refreshed
1650
+ *
1651
+ * @return {promise} Promise, which will be resolved in case a translation tables refreshing
1652
+ * process is finished successfully, and reject if not.
1653
+ */
1654
+ $translate.refresh = function (langKey) {
1655
+ if (!$loaderFactory) {
1656
+ throw new Error('Couldn\'t refresh translation table, no loader registered!');
1657
+ }
1658
+
1659
+ var deferred = $q.defer();
1660
+
1661
+ function resolve() {
1662
+ deferred.resolve();
1663
+ $rootScope.$emit('$translateRefreshEnd', {language: langKey});
1664
+ }
1665
+
1666
+ function reject() {
1667
+ deferred.reject();
1668
+ $rootScope.$emit('$translateRefreshEnd', {language: langKey});
1669
+ }
1670
+
1671
+ $rootScope.$emit('$translateRefreshStart', {language: langKey});
1672
+
1673
+ if (!langKey) {
1674
+ // if there's no language key specified we refresh ALL THE THINGS!
1675
+ var tables = [], loadingKeys = {};
1676
+
1677
+ // reload registered fallback languages
1678
+ if ($fallbackLanguage && $fallbackLanguage.length) {
1679
+ for (var i = 0, len = $fallbackLanguage.length; i < len; i++) {
1680
+ tables.push(loadAsync($fallbackLanguage[i]));
1681
+ loadingKeys[$fallbackLanguage[i]] = true;
1682
+ }
1683
+ }
1684
+
1685
+ // reload currently used language
1686
+ if ($uses && !loadingKeys[$uses]) {
1687
+ tables.push(loadAsync($uses));
1688
+ }
1689
+
1690
+ $q.all(tables).then(function (tableData) {
1691
+ angular.forEach(tableData, function (data) {
1692
+ if ($translationTable[data.key]) {
1693
+ delete $translationTable[data.key];
1694
+ }
1695
+ translations(data.key, data.table);
1696
+ });
1697
+ if ($uses) {
1698
+ useLanguage($uses);
1699
+ }
1700
+ resolve();
1701
+ });
1702
+
1703
+ } else if ($translationTable[langKey]) {
1704
+
1705
+ loadAsync(langKey).then(function (data) {
1706
+ translations(data.key, data.table);
1707
+ if (langKey === $uses) {
1708
+ useLanguage($uses);
1709
+ }
1710
+ resolve();
1711
+ }, reject);
1712
+
1713
+ } else {
1714
+ reject();
1715
+ }
1716
+ return deferred.promise;
1717
+ };
1718
+
1719
+ /**
1720
+ * @ngdoc function
1721
+ * @name pascalprecht.translate.$translate#instant
1722
+ * @methodOf pascalprecht.translate.$translate
1723
+ *
1724
+ * @description
1725
+ * Returns a translation instantly from the internal state of loaded translation. All rules
1726
+ * regarding the current language, the preferred language of even fallback languages will be
1727
+ * used except any promise handling. If a language was not found, an asynchronous loading
1728
+ * will be invoked in the background.
1729
+ *
1730
+ * @param {string|array} translationId A token which represents a translation id
1731
+ * This can be optionally an array of translation ids which
1732
+ * results that the function's promise returns an object where
1733
+ * each key is the translation id and the value the translation.
1734
+ * @param {object} interpolateParams Params
1735
+ * @param {string} interpolationId The id of the interpolation to use
1736
+ *
1737
+ * @return {string} translation
1738
+ */
1739
+ $translate.instant = function (translationId, interpolateParams, interpolationId) {
1740
+
1741
+ // Detect undefined and null values to shorten the execution and prevent exceptions
1742
+ if (translationId === null || angular.isUndefined(translationId)) {
1743
+ return translationId;
1744
+ }
1745
+
1746
+ // Duck detection: If the first argument is an array, a bunch of translations was requested.
1747
+ // The result is an object.
1748
+ if (angular.isArray(translationId)) {
1749
+ var results = {};
1750
+ for (var i = 0, c = translationId.length; i < c; i++) {
1751
+ results[translationId[i]] = $translate.instant(translationId[i], interpolateParams, interpolationId);
1752
+ }
1753
+ return results;
1754
+ }
1755
+
1756
+ // We discarded unacceptable values. So we just need to verify if translationId is empty String
1757
+ if (angular.isString(translationId) && translationId.length < 1) {
1758
+ return translationId;
1759
+ }
1760
+
1761
+ // trim off any whitespace
1762
+ if (translationId) {
1763
+ translationId = trim.apply(translationId);
1764
+ }
1765
+
1766
+ var result, possibleLangKeys = [];
1767
+ if ($preferredLanguage) {
1768
+ possibleLangKeys.push($preferredLanguage);
1769
+ }
1770
+ if ($uses) {
1771
+ possibleLangKeys.push($uses);
1772
+ }
1773
+ if ($fallbackLanguage && $fallbackLanguage.length) {
1774
+ possibleLangKeys = possibleLangKeys.concat($fallbackLanguage);
1775
+ }
1776
+ for (var j = 0, d = possibleLangKeys.length; j < d; j++) {
1777
+ var possibleLangKey = possibleLangKeys[j];
1778
+ if ($translationTable[possibleLangKey]) {
1779
+ if (typeof $translationTable[possibleLangKey][translationId] !== 'undefined') {
1780
+ result = determineTranslationInstant(translationId, interpolateParams, interpolationId);
1781
+ } else if ($notFoundIndicatorLeft || $notFoundIndicatorRight) {
1782
+ result = applyNotFoundIndicators(translationId);
1783
+ }
1784
+ }
1785
+ if (typeof result !== 'undefined') {
1786
+ break;
1787
+ }
1788
+ }
1789
+
1790
+ if (!result && result !== '') {
1791
+ // Return translation of default interpolator if not found anything.
1792
+ result = defaultInterpolator.interpolate(translationId, interpolateParams);
1793
+ if ($missingTranslationHandlerFactory && !pendingLoader) {
1794
+ result = translateByHandler(translationId);
1795
+ }
1796
+ }
1797
+
1798
+ return result;
1799
+ };
1800
+
1801
+ /**
1802
+ * @ngdoc function
1803
+ * @name pascalprecht.translate.$translate#versionInfo
1804
+ * @methodOf pascalprecht.translate.$translate
1805
+ *
1806
+ * @description
1807
+ * Returns the current version information for the angular-translate library
1808
+ *
1809
+ * @return {string} angular-translate version
1810
+ */
1811
+ $translate.versionInfo = function () {
1812
+ return version;
1813
+ };
1814
+
1815
+ /**
1816
+ * @ngdoc function
1817
+ * @name pascalprecht.translate.$translate#loaderCache
1818
+ * @methodOf pascalprecht.translate.$translate
1819
+ *
1820
+ * @description
1821
+ * Returns the defined loaderCache.
1822
+ *
1823
+ * @return {boolean|string|object} current value of loaderCache
1824
+ */
1825
+ $translate.loaderCache = function () {
1826
+ return loaderCache;
1827
+ };
1828
+
1829
+ // internal purpose only
1830
+ $translate.directivePriority = function () {
1831
+ return directivePriority;
1832
+ };
1833
+
1834
+ if ($loaderFactory) {
1835
+
1836
+ // If at least one async loader is defined and there are no
1837
+ // (default) translations available we should try to load them.
1838
+ if (angular.equals($translationTable, {})) {
1839
+ $translate.use($translate.use());
1840
+ }
1841
+
1842
+ // Also, if there are any fallback language registered, we start
1843
+ // loading them asynchronously as soon as we can.
1844
+ if ($fallbackLanguage && $fallbackLanguage.length) {
1845
+ var processAsyncResult = function (translation) {
1846
+ translations(translation.key, translation.table);
1847
+ $rootScope.$emit('$translateChangeEnd', { language: translation.key });
1848
+ return translation;
1849
+ };
1850
+ for (var i = 0, len = $fallbackLanguage.length; i < len; i++) {
1851
+ langPromises[$fallbackLanguage[i]] = loadAsync($fallbackLanguage[i]).then(processAsyncResult);
1852
+ }
1853
+ }
1854
+ }
1855
+
1856
+ return $translate;
1857
+ }
1858
+ ];
1859
+ }]);
1860
+
1861
+ /**
1862
+ * @ngdoc object
1863
+ * @name pascalprecht.translate.$translateDefaultInterpolation
1864
+ * @requires $interpolate
1865
+ *
1866
+ * @description
1867
+ * Uses angular's `$interpolate` services to interpolate strings against some values.
1868
+ *
1869
+ * @return {object} $translateInterpolator Interpolator service
1870
+ */
1871
+ angular.module('pascalprecht.translate').factory('$translateDefaultInterpolation', ['$interpolate', function ($interpolate) {
1872
+
1873
+ var $translateInterpolator = {},
1874
+ $locale,
1875
+ $identifier = 'default',
1876
+ $sanitizeValueStrategy = null,
1877
+ // map of all sanitize strategies
1878
+ sanitizeValueStrategies = {
1879
+ escaped: function (params) {
1880
+ var result = {};
1881
+ for (var key in params) {
1882
+ if (Object.prototype.hasOwnProperty.call(params, key)) {
1883
+ if (angular.isNumber(params[key])) {
1884
+ result[key] = params[key];
1885
+ } else {
1886
+ result[key] = angular.element('<div></div>').text(params[key]).html();
1887
+ }
1888
+ }
1889
+ }
1890
+ return result;
1891
+ }
1892
+ };
1893
+
1894
+ var sanitizeParams = function (params) {
1895
+ var result;
1896
+ if (angular.isFunction(sanitizeValueStrategies[$sanitizeValueStrategy])) {
1897
+ result = sanitizeValueStrategies[$sanitizeValueStrategy](params);
1898
+ } else {
1899
+ result = params;
1900
+ }
1901
+ return result;
1902
+ };
1903
+
1904
+ /**
1905
+ * @ngdoc function
1906
+ * @name pascalprecht.translate.$translateDefaultInterpolation#setLocale
1907
+ * @methodOf pascalprecht.translate.$translateDefaultInterpolation
1908
+ *
1909
+ * @description
1910
+ * Sets current locale (this is currently not use in this interpolation).
1911
+ *
1912
+ * @param {string} locale Language key or locale.
1913
+ */
1914
+ $translateInterpolator.setLocale = function (locale) {
1915
+ $locale = locale;
1916
+ };
1917
+
1918
+ /**
1919
+ * @ngdoc function
1920
+ * @name pascalprecht.translate.$translateDefaultInterpolation#getInterpolationIdentifier
1921
+ * @methodOf pascalprecht.translate.$translateDefaultInterpolation
1922
+ *
1923
+ * @description
1924
+ * Returns an identifier for this interpolation service.
1925
+ *
1926
+ * @returns {string} $identifier
1927
+ */
1928
+ $translateInterpolator.getInterpolationIdentifier = function () {
1929
+ return $identifier;
1930
+ };
1931
+
1932
+ $translateInterpolator.useSanitizeValueStrategy = function (value) {
1933
+ $sanitizeValueStrategy = value;
1934
+ return this;
1935
+ };
1936
+
1937
+ /**
1938
+ * @ngdoc function
1939
+ * @name pascalprecht.translate.$translateDefaultInterpolation#interpolate
1940
+ * @methodOf pascalprecht.translate.$translateDefaultInterpolation
1941
+ *
1942
+ * @description
1943
+ * Interpolates given string agains given interpolate params using angulars
1944
+ * `$interpolate` service.
1945
+ *
1946
+ * @returns {string} interpolated string.
1947
+ */
1948
+ $translateInterpolator.interpolate = function (string, interpolateParams) {
1949
+ if ($sanitizeValueStrategy) {
1950
+ interpolateParams = sanitizeParams(interpolateParams);
1951
+ }
1952
+ return $interpolate(string)(interpolateParams || {});
1953
+ };
1954
+
1955
+ return $translateInterpolator;
1956
+ }]);
1957
+
1958
+ angular.module('pascalprecht.translate').constant('$STORAGE_KEY', 'NG_TRANSLATE_LANG_KEY');
1959
+
1960
+ angular.module('pascalprecht.translate')
1961
+ /**
1962
+ * @ngdoc directive
1963
+ * @name pascalprecht.translate.directive:translate
1964
+ * @requires $compile
1965
+ * @requires $filter
1966
+ * @requires $interpolate
1967
+ * @restrict A
1968
+ *
1969
+ * @description
1970
+ * Translates given translation id either through attribute or DOM content.
1971
+ * Internally it uses `translate` filter to translate translation id. It possible to
1972
+ * pass an optional `translate-values` object literal as string into translation id.
1973
+ *
1974
+ * @param {string=} translate Translation id which could be either string or interpolated string.
1975
+ * @param {string=} translate-values Values to pass into translation id. Can be passed as object literal string or interpolated object.
1976
+ * @param {string=} translate-attr-ATTR translate Translation id and put it into ATTR attribute.
1977
+ * @param {string=} translate-default will be used unless translation was successful
1978
+ * @param {boolean=} translate-compile (default true if present) defines locally activation of {@link pascalprecht.translate.$translate#usePostCompiling}
1979
+ *
1980
+ * @example
1981
+ <example module="ngView">
1982
+ <file name="index.html">
1983
+ <div ng-controller="TranslateCtrl">
1984
+
1985
+ <pre translate="TRANSLATION_ID"></pre>
1986
+ <pre translate>TRANSLATION_ID</pre>
1987
+ <pre translate translate-attr-title="TRANSLATION_ID"></pre>
1988
+ <pre translate="{{translationId}}"></pre>
1989
+ <pre translate>{{translationId}}</pre>
1990
+ <pre translate="WITH_VALUES" translate-values="{value: 5}"></pre>
1991
+ <pre translate translate-values="{value: 5}">WITH_VALUES</pre>
1992
+ <pre translate="WITH_VALUES" translate-values="{{values}}"></pre>
1993
+ <pre translate translate-values="{{values}}">WITH_VALUES</pre>
1994
+ <pre translate translate-attr-title="WITH_VALUES" translate-values="{{values}}"></pre>
1995
+
1996
+ </div>
1997
+ </file>
1998
+ <file name="script.js">
1999
+ angular.module('ngView', ['pascalprecht.translate'])
2000
+
2001
+ .config(function ($translateProvider) {
2002
+
2003
+ $translateProvider.translations('en',{
2004
+ 'TRANSLATION_ID': 'Hello there!',
2005
+ 'WITH_VALUES': 'The following value is dynamic: {{value}}'
2006
+ }).preferredLanguage('en');
2007
+
2008
+ });
2009
+
2010
+ angular.module('ngView').controller('TranslateCtrl', function ($scope) {
2011
+ $scope.translationId = 'TRANSLATION_ID';
2012
+
2013
+ $scope.values = {
2014
+ value: 78
2015
+ };
2016
+ });
2017
+ </file>
2018
+ <file name="scenario.js">
2019
+ it('should translate', function () {
2020
+ inject(function ($rootScope, $compile) {
2021
+ $rootScope.translationId = 'TRANSLATION_ID';
2022
+
2023
+ element = $compile('<p translate="TRANSLATION_ID"></p>')($rootScope);
2024
+ $rootScope.$digest();
2025
+ expect(element.text()).toBe('Hello there!');
2026
+
2027
+ element = $compile('<p translate="{{translationId}}"></p>')($rootScope);
2028
+ $rootScope.$digest();
2029
+ expect(element.text()).toBe('Hello there!');
2030
+
2031
+ element = $compile('<p translate>TRANSLATION_ID</p>')($rootScope);
2032
+ $rootScope.$digest();
2033
+ expect(element.text()).toBe('Hello there!');
2034
+
2035
+ element = $compile('<p translate>{{translationId}}</p>')($rootScope);
2036
+ $rootScope.$digest();
2037
+ expect(element.text()).toBe('Hello there!');
2038
+
2039
+ element = $compile('<p translate translate-attr-title="TRANSLATION_ID"></p>')($rootScope);
2040
+ $rootScope.$digest();
2041
+ expect(element.attr('title')).toBe('Hello there!');
2042
+ });
2043
+ });
2044
+ </file>
2045
+ </example>
2046
+ */
2047
+ .directive('translate', ['$translate', '$q', '$interpolate', '$compile', '$parse', '$rootScope', function ($translate, $q, $interpolate, $compile, $parse, $rootScope) {
2048
+
2049
+ /**
2050
+ * @name trim
2051
+ * @private
2052
+ *
2053
+ * @description
2054
+ * trim polyfill
2055
+ *
2056
+ * @returns {string} The string stripped of whitespace from both ends
2057
+ */
2058
+ var trim = function() {
2059
+ return this.toString().replace(/^\s+|\s+$/g, '');
2060
+ };
2061
+
2062
+ return {
2063
+ restrict: 'AE',
2064
+ scope: true,
2065
+ priority: $translate.directivePriority(),
2066
+ compile: function (tElement, tAttr) {
2067
+
2068
+ var translateValuesExist = (tAttr.translateValues) ?
2069
+ tAttr.translateValues : undefined;
2070
+
2071
+ var translateInterpolation = (tAttr.translateInterpolation) ?
2072
+ tAttr.translateInterpolation : undefined;
2073
+
2074
+ var translateValueExist = tElement[0].outerHTML.match(/translate-value-+/i);
2075
+
2076
+ var interpolateRegExp = '^(.*)(' + $interpolate.startSymbol() + '.*' + $interpolate.endSymbol() + ')(.*)',
2077
+ watcherRegExp = '^(.*)' + $interpolate.startSymbol() + '(.*)' + $interpolate.endSymbol() + '(.*)';
2078
+
2079
+ return function linkFn(scope, iElement, iAttr) {
2080
+
2081
+ scope.interpolateParams = {};
2082
+ scope.preText = '';
2083
+ scope.postText = '';
2084
+ var translationIds = {};
2085
+
2086
+ // Ensures any change of the attribute "translate" containing the id will
2087
+ // be re-stored to the scope's "translationId".
2088
+ // If the attribute has no content, the element's text value (white spaces trimmed off) will be used.
2089
+ var observeElementTranslation = function (translationId) {
2090
+
2091
+ // Remove any old watcher
2092
+ if (angular.isFunction(observeElementTranslation._unwatchOld)) {
2093
+ observeElementTranslation._unwatchOld();
2094
+ observeElementTranslation._unwatchOld = undefined;
2095
+ }
2096
+
2097
+ if (angular.equals(translationId , '') || !angular.isDefined(translationId)) {
2098
+ // Resolve translation id by inner html if required
2099
+ var interpolateMatches = trim.apply(iElement.text()).match(interpolateRegExp);
2100
+ // Interpolate translation id if required
2101
+ if (angular.isArray(interpolateMatches)) {
2102
+ scope.preText = interpolateMatches[1];
2103
+ scope.postText = interpolateMatches[3];
2104
+ translationIds.translate = $interpolate(interpolateMatches[2])(scope.$parent);
2105
+ var watcherMatches = iElement.text().match(watcherRegExp);
2106
+ if (angular.isArray(watcherMatches) && watcherMatches[2] && watcherMatches[2].length) {
2107
+ observeElementTranslation._unwatchOld = scope.$watch(watcherMatches[2], function (newValue) {
2108
+ translationIds.translate = newValue;
2109
+ updateTranslations();
2110
+ });
2111
+ }
2112
+ } else {
2113
+ translationIds.translate = iElement.text().replace(/^\s+|\s+$/g,'');
2114
+ }
2115
+ } else {
2116
+ translationIds.translate = translationId;
2117
+ }
2118
+ updateTranslations();
2119
+ };
2120
+
2121
+ var observeAttributeTranslation = function (translateAttr) {
2122
+ iAttr.$observe(translateAttr, function (translationId) {
2123
+ translationIds[translateAttr] = translationId;
2124
+ updateTranslations();
2125
+ });
2126
+ };
2127
+
2128
+ var firstAttributeChangedEvent = true;
2129
+ iAttr.$observe('translate', function (translationId) {
2130
+ if (typeof translationId === 'undefined') {
2131
+ // case of element "<translate>xyz</translate>"
2132
+ observeElementTranslation('');
2133
+ } else {
2134
+ // case of regular attribute
2135
+ if (translationId !== '' || !firstAttributeChangedEvent) {
2136
+ translationIds.translate = translationId;
2137
+ updateTranslations();
2138
+ }
2139
+ }
2140
+ firstAttributeChangedEvent = false;
2141
+ });
2142
+
2143
+ for (var translateAttr in iAttr) {
2144
+ if (iAttr.hasOwnProperty(translateAttr) && translateAttr.substr(0, 13) === 'translateAttr') {
2145
+ observeAttributeTranslation(translateAttr);
2146
+ }
2147
+ }
2148
+
2149
+ iAttr.$observe('translateDefault', function (value) {
2150
+ scope.defaultText = value;
2151
+ });
2152
+
2153
+ if (translateValuesExist) {
2154
+ iAttr.$observe('translateValues', function (interpolateParams) {
2155
+ if (interpolateParams) {
2156
+ scope.$parent.$watch(function () {
2157
+ angular.extend(scope.interpolateParams, $parse(interpolateParams)(scope.$parent));
2158
+ });
2159
+ }
2160
+ });
2161
+ }
2162
+
2163
+ if (translateValueExist) {
2164
+ var observeValueAttribute = function (attrName) {
2165
+ iAttr.$observe(attrName, function (value) {
2166
+ var attributeName = angular.lowercase(attrName.substr(14, 1)) + attrName.substr(15);
2167
+ scope.interpolateParams[attributeName] = value;
2168
+ });
2169
+ };
2170
+ for (var attr in iAttr) {
2171
+ if (Object.prototype.hasOwnProperty.call(iAttr, attr) && attr.substr(0, 14) === 'translateValue' && attr !== 'translateValues') {
2172
+ observeValueAttribute(attr);
2173
+ }
2174
+ }
2175
+ }
2176
+
2177
+ // Master update function
2178
+ var updateTranslations = function () {
2179
+ for (var key in translationIds) {
2180
+ if (translationIds.hasOwnProperty(key)) {
2181
+ updateTranslation(key, translationIds[key], scope, scope.interpolateParams, scope.defaultText);
2182
+ }
2183
+ }
2184
+ };
2185
+
2186
+ // Put translation processing function outside loop
2187
+ var updateTranslation = function(translateAttr, translationId, scope, interpolateParams, defaultTranslationText) {
2188
+ if (translationId) {
2189
+ $translate(translationId, interpolateParams, translateInterpolation, defaultTranslationText)
2190
+ .then(function (translation) {
2191
+ applyTranslation(translation, scope, true, translateAttr);
2192
+ }, function (translationId) {
2193
+ applyTranslation(translationId, scope, false, translateAttr);
2194
+ });
2195
+ } else {
2196
+ // as an empty string cannot be translated, we can solve this using successful=false
2197
+ applyTranslation(translationId, scope, false, translateAttr);
2198
+ }
2199
+ };
2200
+
2201
+ var applyTranslation = function (value, scope, successful, translateAttr) {
2202
+ if (translateAttr === 'translate') {
2203
+ // default translate into innerHTML
2204
+ if (!successful && typeof scope.defaultText !== 'undefined') {
2205
+ value = scope.defaultText;
2206
+ }
2207
+ iElement.html(scope.preText + value + scope.postText);
2208
+ var globallyEnabled = $translate.isPostCompilingEnabled();
2209
+ var locallyDefined = typeof tAttr.translateCompile !== 'undefined';
2210
+ var locallyEnabled = locallyDefined && tAttr.translateCompile !== 'false';
2211
+ if ((globallyEnabled && !locallyDefined) || locallyEnabled) {
2212
+ $compile(iElement.contents())(scope);
2213
+ }
2214
+ } else {
2215
+ // translate attribute
2216
+ if (!successful && typeof scope.defaultText !== 'undefined') {
2217
+ value = scope.defaultText;
2218
+ }
2219
+ var attributeName = iAttr.$attr[translateAttr].substr(15);
2220
+ iElement.attr(attributeName, value);
2221
+ }
2222
+ };
2223
+
2224
+ scope.$watch('interpolateParams', updateTranslations, true);
2225
+
2226
+ // Ensures the text will be refreshed after the current language was changed
2227
+ // w/ $translate.use(...)
2228
+ var unbind = $rootScope.$on('$translateChangeSuccess', updateTranslations);
2229
+
2230
+ // ensure translation will be looked up at least one
2231
+ if (iElement.text().length) {
2232
+ observeElementTranslation('');
2233
+ }
2234
+ updateTranslations();
2235
+ scope.$on('$destroy', unbind);
2236
+ };
2237
+ }
2238
+ };
2239
+ }]);
2240
+
2241
+ angular.module('pascalprecht.translate')
2242
+ /**
2243
+ * @ngdoc directive
2244
+ * @name pascalprecht.translate.directive:translateCloak
2245
+ * @requires $rootScope
2246
+ * @requires $translate
2247
+ * @restrict A
2248
+ *
2249
+ * $description
2250
+ * Adds a `translate-cloak` class name to the given element where this directive
2251
+ * is applied initially and removes it, once a loader has finished loading.
2252
+ *
2253
+ * This directive can be used to prevent initial flickering when loading translation
2254
+ * data asynchronously.
2255
+ *
2256
+ * The class name is defined in
2257
+ * {@link pascalprecht.translate.$translateProvider#cloakClassName $translate.cloakClassName()}.
2258
+ *
2259
+ * @param {string=} translate-cloak If a translationId is provided, it will be used for showing
2260
+ * or hiding the cloak. Basically it relies on the translation
2261
+ * resolve.
2262
+ */
2263
+ .directive('translateCloak', ['$rootScope', '$translate', function ($rootScope, $translate) {
2264
+
2265
+ return {
2266
+ compile: function (tElement) {
2267
+ var applyCloak = function () {
2268
+ tElement.addClass($translate.cloakClassName());
2269
+ },
2270
+ removeCloak = function () {
2271
+ tElement.removeClass($translate.cloakClassName());
2272
+ },
2273
+ removeListener = $rootScope.$on('$translateChangeEnd', function () {
2274
+ removeCloak();
2275
+ removeListener();
2276
+ removeListener = null;
2277
+ });
2278
+ applyCloak();
2279
+
2280
+ return function linkFn(scope, iElement, iAttr) {
2281
+ // Register a watcher for the defined translation allowing a fine tuned cloak
2282
+ if (iAttr.translateCloak && iAttr.translateCloak.length) {
2283
+ iAttr.$observe('translateCloak', function (translationId) {
2284
+ $translate(translationId).then(removeCloak, applyCloak);
2285
+ });
2286
+ }
2287
+ };
2288
+ }
2289
+ };
2290
+ }]);
2291
+
2292
+ angular.module('pascalprecht.translate')
2293
+ /**
2294
+ * @ngdoc filter
2295
+ * @name pascalprecht.translate.filter:translate
2296
+ * @requires $parse
2297
+ * @requires pascalprecht.translate.$translate
2298
+ * @function
2299
+ *
2300
+ * @description
2301
+ * Uses `$translate` service to translate contents. Accepts interpolate parameters
2302
+ * to pass dynamized values though translation.
2303
+ *
2304
+ * @param {string} translationId A translation id to be translated.
2305
+ * @param {*=} interpolateParams Optional object literal (as hash or string) to pass values into translation.
2306
+ *
2307
+ * @returns {string} Translated text.
2308
+ *
2309
+ * @example
2310
+ <example module="ngView">
2311
+ <file name="index.html">
2312
+ <div ng-controller="TranslateCtrl">
2313
+
2314
+ <pre>{{ 'TRANSLATION_ID' | translate }}</pre>
2315
+ <pre>{{ translationId | translate }}</pre>
2316
+ <pre>{{ 'WITH_VALUES' | translate:'{value: 5}' }}</pre>
2317
+ <pre>{{ 'WITH_VALUES' | translate:values }}</pre>
2318
+
2319
+ </div>
2320
+ </file>
2321
+ <file name="script.js">
2322
+ angular.module('ngView', ['pascalprecht.translate'])
2323
+
2324
+ .config(function ($translateProvider) {
2325
+
2326
+ $translateProvider.translations('en', {
2327
+ 'TRANSLATION_ID': 'Hello there!',
2328
+ 'WITH_VALUES': 'The following value is dynamic: {{value}}'
2329
+ });
2330
+ $translateProvider.preferredLanguage('en');
2331
+
2332
+ });
2333
+
2334
+ angular.module('ngView').controller('TranslateCtrl', function ($scope) {
2335
+ $scope.translationId = 'TRANSLATION_ID';
2336
+
2337
+ $scope.values = {
2338
+ value: 78
2339
+ };
2340
+ });
2341
+ </file>
2342
+ </example>
2343
+ */
2344
+ .filter('translate', ['$parse', '$translate', function ($parse, $translate) {
2345
+ var translateFilter = function (translationId, interpolateParams, interpolation) {
2346
+
2347
+ if (!angular.isObject(interpolateParams)) {
2348
+ interpolateParams = $parse(interpolateParams)(this);
2349
+ }
2350
+
2351
+ return $translate.instant(translationId, interpolateParams, interpolation);
2352
+ };
2353
+
2354
+ // Since AngularJS 1.3, filters which are not stateless (depending at the scope)
2355
+ // have to explicit define this behavior.
2356
+ translateFilter.$stateful = true;
2357
+
2358
+ return translateFilter;
2359
+ }]);