angular-translate-rails-tf 2.7.2 → 2.15.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/vendor/assets/javascripts/angular-translate.js +1879 -1073
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5a8c289c878691e9ef070eb726514e852b9163e9
|
4
|
+
data.tar.gz: f53d2649e6fd7410a1d947a9eeb50c7787166a76
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2a8de09ea84acde418bd28adb4fe5bdfa09800e3fef41f4bda455b00423f9a3db6757c550c2fa5ba174c9eff7c6d95758d6813be105369a6e352fc31f8656059
|
7
|
+
data.tar.gz: aa1f105aaf921c2a6211b8a431f6fa58d6715d6f6595d4bc3a18e20f2f345466ee3e54beaa4bff14ffea6a73955cb7a3d24b3899f3d5c86ae0dcb4bd7dded07c
|
@@ -1,7 +1,7 @@
|
|
1
1
|
/*!
|
2
|
-
* angular-translate - v2.
|
3
|
-
*
|
4
|
-
* Copyright (c)
|
2
|
+
* angular-translate - v2.15.2 - 2017-06-22
|
3
|
+
*
|
4
|
+
* Copyright (c) 2017 The angular-translate team, Pascal Precht; Licensed MIT
|
5
5
|
*/
|
6
6
|
(function (root, factory) {
|
7
7
|
if (typeof define === 'function' && define.amd) {
|
@@ -9,7 +9,7 @@
|
|
9
9
|
define([], function () {
|
10
10
|
return (factory());
|
11
11
|
});
|
12
|
-
} else if (typeof
|
12
|
+
} else if (typeof module === 'object' && module.exports) {
|
13
13
|
// Node. Does not work with strict CommonJS, but
|
14
14
|
// only CommonJS-like environments that support module.exports,
|
15
15
|
// like Node.
|
@@ -26,6 +26,14 @@
|
|
26
26
|
* @description
|
27
27
|
* The main module which holds everything together.
|
28
28
|
*/
|
29
|
+
runTranslate.$inject = ['$translate'];
|
30
|
+
$translate.$inject = ['$STORAGE_KEY', '$windowProvider', '$translateSanitizationProvider', 'pascalprechtTranslateOverrider'];
|
31
|
+
$translateDefaultInterpolation.$inject = ['$interpolate', '$translateSanitization'];
|
32
|
+
translateDirective.$inject = ['$translate', '$interpolate', '$compile', '$parse', '$rootScope'];
|
33
|
+
translateAttrDirective.$inject = ['$translate', '$rootScope'];
|
34
|
+
translateCloakDirective.$inject = ['$translate', '$rootScope'];
|
35
|
+
translateFilterFactory.$inject = ['$parse', '$translate'];
|
36
|
+
$translationCache.$inject = ['$cacheFactory'];
|
29
37
|
angular.module('pascalprecht.translate', ['ng'])
|
30
38
|
.run(runTranslate);
|
31
39
|
|
@@ -59,7 +67,6 @@ function runTranslate($translate) {
|
|
59
67
|
$translate.use($translate.preferredLanguage());
|
60
68
|
}
|
61
69
|
}
|
62
|
-
runTranslate.$inject = ['$translate'];
|
63
70
|
|
64
71
|
runTranslate.displayName = 'runTranslate';
|
65
72
|
|
@@ -78,6 +85,7 @@ function $translateSanitizationProvider () {
|
|
78
85
|
'use strict';
|
79
86
|
|
80
87
|
var $sanitize,
|
88
|
+
$sce,
|
81
89
|
currentStrategy = null, // TODO change to either 'sanitize', 'escape' or ['sanitize', 'escapeParameters'] in 3.0.
|
82
90
|
hasConfiguredStrategy = false,
|
83
91
|
hasShownNoStrategyConfiguredWarning = false,
|
@@ -114,29 +122,46 @@ function $translateSanitizationProvider () {
|
|
114
122
|
*/
|
115
123
|
|
116
124
|
strategies = {
|
117
|
-
sanitize: function (value, mode) {
|
125
|
+
sanitize: function (value, mode/*, context*/) {
|
118
126
|
if (mode === 'text') {
|
119
127
|
value = htmlSanitizeValue(value);
|
120
128
|
}
|
121
129
|
return value;
|
122
130
|
},
|
123
|
-
escape: function (value, mode) {
|
131
|
+
escape: function (value, mode/*, context*/) {
|
124
132
|
if (mode === 'text') {
|
125
133
|
value = htmlEscapeValue(value);
|
126
134
|
}
|
127
135
|
return value;
|
128
136
|
},
|
129
|
-
sanitizeParameters: function (value, mode) {
|
137
|
+
sanitizeParameters: function (value, mode/*, context*/) {
|
130
138
|
if (mode === 'params') {
|
131
139
|
value = mapInterpolationParameters(value, htmlSanitizeValue);
|
132
140
|
}
|
133
141
|
return value;
|
134
142
|
},
|
135
|
-
escapeParameters: function (value, mode) {
|
143
|
+
escapeParameters: function (value, mode/*, context*/) {
|
136
144
|
if (mode === 'params') {
|
137
145
|
value = mapInterpolationParameters(value, htmlEscapeValue);
|
138
146
|
}
|
139
147
|
return value;
|
148
|
+
},
|
149
|
+
sce: function (value, mode, context) {
|
150
|
+
if (mode === 'text') {
|
151
|
+
value = htmlTrustValue(value);
|
152
|
+
} else if (mode === 'params') {
|
153
|
+
if (context !== 'filter') {
|
154
|
+
// do html escape in filter context #1101
|
155
|
+
value = mapInterpolationParameters(value, htmlEscapeValue);
|
156
|
+
}
|
157
|
+
}
|
158
|
+
return value;
|
159
|
+
},
|
160
|
+
sceParameters: function (value, mode/*, context*/) {
|
161
|
+
if (mode === 'params') {
|
162
|
+
value = mapInterpolationParameters(value, htmlTrustValue);
|
163
|
+
}
|
164
|
+
return value;
|
140
165
|
}
|
141
166
|
};
|
142
167
|
// Support legacy strategy name 'escaped' for backwards compatibility.
|
@@ -205,12 +230,24 @@ function $translateSanitizationProvider () {
|
|
205
230
|
*/
|
206
231
|
this.$get = ['$injector', '$log', function ($injector, $log) {
|
207
232
|
|
208
|
-
var
|
233
|
+
var cachedStrategyMap = {};
|
234
|
+
|
235
|
+
var applyStrategies = function (value, mode, context, selectedStrategies) {
|
209
236
|
angular.forEach(selectedStrategies, function (selectedStrategy) {
|
210
237
|
if (angular.isFunction(selectedStrategy)) {
|
211
|
-
value = selectedStrategy(value, mode);
|
238
|
+
value = selectedStrategy(value, mode, context);
|
212
239
|
} else if (angular.isFunction(strategies[selectedStrategy])) {
|
213
|
-
value = strategies[selectedStrategy](value, mode);
|
240
|
+
value = strategies[selectedStrategy](value, mode, context);
|
241
|
+
} else if (angular.isString(strategies[selectedStrategy])) {
|
242
|
+
if (!cachedStrategyMap[strategies[selectedStrategy]]) {
|
243
|
+
try {
|
244
|
+
cachedStrategyMap[strategies[selectedStrategy]] = $injector.get(strategies[selectedStrategy]);
|
245
|
+
} catch (e) {
|
246
|
+
cachedStrategyMap[strategies[selectedStrategy]] = function() {};
|
247
|
+
throw new Error('pascalprecht.translate.$translateSanitization: Unknown sanitization strategy: \'' + selectedStrategy + '\'');
|
248
|
+
}
|
249
|
+
}
|
250
|
+
value = cachedStrategyMap[strategies[selectedStrategy]](value, mode, context);
|
214
251
|
} else {
|
215
252
|
throw new Error('pascalprecht.translate.$translateSanitization: Unknown sanitization strategy: \'' + selectedStrategy + '\'');
|
216
253
|
}
|
@@ -229,6 +266,9 @@ function $translateSanitizationProvider () {
|
|
229
266
|
if ($injector.has('$sanitize')) {
|
230
267
|
$sanitize = $injector.get('$sanitize');
|
231
268
|
}
|
269
|
+
if ($injector.has('$sce')) {
|
270
|
+
$sce = $injector.get('$sce');
|
271
|
+
}
|
232
272
|
|
233
273
|
return {
|
234
274
|
/**
|
@@ -258,14 +298,15 @@ function $translateSanitizationProvider () {
|
|
258
298
|
* @param {string|object} value The value which should be sanitized.
|
259
299
|
* @param {string} mode The current sanitization mode, either 'params' or 'text'.
|
260
300
|
* @param {string|StrategyFunction|array} [strategy] Optional custom strategy which should be used instead of the currently selected strategy.
|
301
|
+
* @param {string} [context] The context of this call: filter, service. Default is service
|
261
302
|
* @returns {string|object} sanitized value
|
262
303
|
*/
|
263
|
-
sanitize: function (value, mode, strategy) {
|
304
|
+
sanitize: function (value, mode, strategy, context) {
|
264
305
|
if (!currentStrategy) {
|
265
306
|
showNoStrategyConfiguredWarning();
|
266
307
|
}
|
267
308
|
|
268
|
-
if (
|
309
|
+
if (!strategy && strategy !== null) {
|
269
310
|
strategy = currentStrategy;
|
270
311
|
}
|
271
312
|
|
@@ -273,8 +314,12 @@ function $translateSanitizationProvider () {
|
|
273
314
|
return value;
|
274
315
|
}
|
275
316
|
|
317
|
+
if (!context) {
|
318
|
+
context = 'service';
|
319
|
+
}
|
320
|
+
|
276
321
|
var selectedStrategies = angular.isArray(strategy) ? strategy : [strategy];
|
277
|
-
return applyStrategies(value, mode, selectedStrategies);
|
322
|
+
return applyStrategies(value, mode, context, selectedStrategies);
|
278
323
|
}
|
279
324
|
};
|
280
325
|
}];
|
@@ -292,19 +337,48 @@ function $translateSanitizationProvider () {
|
|
292
337
|
return $sanitize(value);
|
293
338
|
};
|
294
339
|
|
295
|
-
var
|
296
|
-
if (
|
340
|
+
var htmlTrustValue = function (value) {
|
341
|
+
if (!$sce) {
|
342
|
+
throw new Error('pascalprecht.translate.$translateSanitization: Error cannot find $sce service.');
|
343
|
+
}
|
344
|
+
return $sce.trustAsHtml(value);
|
345
|
+
};
|
346
|
+
|
347
|
+
var mapInterpolationParameters = function (value, iteratee, stack) {
|
348
|
+
if (angular.isDate(value)) {
|
349
|
+
return value;
|
350
|
+
} else if (angular.isObject(value)) {
|
297
351
|
var result = angular.isArray(value) ? [] : {};
|
298
352
|
|
353
|
+
if (!stack) {
|
354
|
+
stack = [];
|
355
|
+
} else {
|
356
|
+
if (stack.indexOf(value) > -1) {
|
357
|
+
throw new Error('pascalprecht.translate.$translateSanitization: Error cannot interpolate parameter due recursive object');
|
358
|
+
}
|
359
|
+
}
|
360
|
+
|
361
|
+
stack.push(value);
|
299
362
|
angular.forEach(value, function (propertyValue, propertyKey) {
|
300
|
-
|
363
|
+
|
364
|
+
/* Skipping function properties. */
|
365
|
+
if (angular.isFunction(propertyValue)) {
|
366
|
+
return;
|
367
|
+
}
|
368
|
+
|
369
|
+
result[propertyKey] = mapInterpolationParameters(propertyValue, iteratee, stack);
|
301
370
|
});
|
371
|
+
stack.splice(-1, 1); // remove last
|
302
372
|
|
303
373
|
return result;
|
304
374
|
} else if (angular.isNumber(value)) {
|
305
375
|
return value;
|
306
|
-
} else {
|
376
|
+
} else if (value === true || value === false) {
|
377
|
+
return value;
|
378
|
+
} else if (!angular.isUndefined(value) && value !== null) {
|
307
379
|
return iteratee(value);
|
380
|
+
} else {
|
381
|
+
return value;
|
308
382
|
}
|
309
383
|
};
|
310
384
|
}
|
@@ -319,56 +393,64 @@ function $translateSanitizationProvider () {
|
|
319
393
|
*
|
320
394
|
*/
|
321
395
|
angular.module('pascalprecht.translate')
|
322
|
-
.constant('pascalprechtTranslateOverrider', {})
|
323
|
-
.provider('$translate', $translate);
|
396
|
+
.constant('pascalprechtTranslateOverrider', {})
|
397
|
+
.provider('$translate', $translate);
|
324
398
|
|
325
399
|
function $translate($STORAGE_KEY, $windowProvider, $translateSanitizationProvider, pascalprechtTranslateOverrider) {
|
326
400
|
|
327
401
|
'use strict';
|
328
402
|
|
329
403
|
var $translationTable = {},
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
404
|
+
$preferredLanguage,
|
405
|
+
$availableLanguageKeys = [],
|
406
|
+
$languageKeyAliases,
|
407
|
+
$fallbackLanguage,
|
408
|
+
$fallbackWasString,
|
409
|
+
$uses,
|
410
|
+
$nextLang,
|
411
|
+
$storageFactory,
|
412
|
+
$storageKey = $STORAGE_KEY,
|
413
|
+
$storagePrefix,
|
414
|
+
$missingTranslationHandlerFactory,
|
415
|
+
$interpolationFactory,
|
416
|
+
$interpolatorFactories = [],
|
417
|
+
$loaderFactory,
|
418
|
+
$cloakClassName = 'translate-cloak',
|
419
|
+
$loaderOptions,
|
420
|
+
$notFoundIndicatorLeft,
|
421
|
+
$notFoundIndicatorRight,
|
422
|
+
$postCompilingEnabled = false,
|
423
|
+
$forceAsyncReloadEnabled = false,
|
424
|
+
$nestedObjectDelimeter = '.',
|
425
|
+
$isReady = false,
|
426
|
+
$keepContent = false,
|
427
|
+
loaderCache,
|
428
|
+
directivePriority = 0,
|
429
|
+
statefulFilter = true,
|
430
|
+
postProcessFn,
|
431
|
+
uniformLanguageTagResolver = 'default',
|
432
|
+
languageTagResolver = {
|
433
|
+
'default' : function (tag) {
|
434
|
+
return (tag || '').split('-').join('_');
|
435
|
+
},
|
436
|
+
java : function (tag) {
|
437
|
+
var temp = (tag || '').split('-').join('_');
|
438
|
+
var parts = temp.split('_');
|
439
|
+
return parts.length > 1 ? (parts[0].toLowerCase() + '_' + parts[1].toUpperCase()) : temp;
|
440
|
+
},
|
441
|
+
bcp47 : function (tag) {
|
442
|
+
var temp = (tag || '').split('_').join('-');
|
443
|
+
var parts = temp.split('-');
|
444
|
+
return parts.length > 1 ? (parts[0].toLowerCase() + '-' + parts[1].toUpperCase()) : temp;
|
445
|
+
},
|
446
|
+
'iso639-1' : function (tag) {
|
447
|
+
var temp = (tag || '').split('_').join('-');
|
448
|
+
var parts = temp.split('-');
|
449
|
+
return parts[0].toLowerCase();
|
450
|
+
}
|
451
|
+
};
|
370
452
|
|
371
|
-
var version = '2.
|
453
|
+
var version = '2.15.2';
|
372
454
|
|
373
455
|
// tries to determine the browsers language
|
374
456
|
var getFirstBrowserLanguage = function () {
|
@@ -379,9 +461,9 @@ function $translate($STORAGE_KEY, $windowProvider, $translateSanitizationProvide
|
|
379
461
|
}
|
380
462
|
|
381
463
|
var nav = $windowProvider.$get().navigator,
|
382
|
-
|
383
|
-
|
384
|
-
|
464
|
+
browserLanguagePropertyKeys = ['language', 'browserLanguage', 'systemLanguage', 'userLanguage'],
|
465
|
+
i,
|
466
|
+
language;
|
385
467
|
|
386
468
|
// support for HTML 5.1 "navigator.languages"
|
387
469
|
if (angular.isArray(nav.languages)) {
|
@@ -427,7 +509,7 @@ function $translate($STORAGE_KEY, $windowProvider, $translateSanitizationProvide
|
|
427
509
|
*
|
428
510
|
* @returns {int} Index of search element.
|
429
511
|
*/
|
430
|
-
var indexOf = function(array, searchElement) {
|
512
|
+
var indexOf = function (array, searchElement) {
|
431
513
|
for (var i = 0, len = array.length; i < len; i++) {
|
432
514
|
if (array[i] === searchElement) {
|
433
515
|
return i;
|
@@ -445,21 +527,25 @@ function $translate($STORAGE_KEY, $windowProvider, $translateSanitizationProvide
|
|
445
527
|
*
|
446
528
|
* @returns {string} The string stripped of whitespace from both ends
|
447
529
|
*/
|
448
|
-
var trim = function() {
|
530
|
+
var trim = function () {
|
449
531
|
return this.toString().replace(/^\s+|\s+$/g, '');
|
450
532
|
};
|
451
533
|
|
452
534
|
var negotiateLocale = function (preferred) {
|
535
|
+
if (!preferred) {
|
536
|
+
return;
|
537
|
+
}
|
453
538
|
|
454
539
|
var avail = [],
|
455
|
-
|
456
|
-
|
457
|
-
|
540
|
+
locale = angular.lowercase(preferred),
|
541
|
+
i = 0,
|
542
|
+
n = $availableLanguageKeys.length;
|
458
543
|
|
459
544
|
for (; i < n; i++) {
|
460
545
|
avail.push(angular.lowercase($availableLanguageKeys[i]));
|
461
546
|
}
|
462
547
|
|
548
|
+
// Check for an exact match in our list of available keys
|
463
549
|
if (indexOf(avail, locale) > -1) {
|
464
550
|
return preferred;
|
465
551
|
}
|
@@ -467,32 +553,33 @@ function $translate($STORAGE_KEY, $windowProvider, $translateSanitizationProvide
|
|
467
553
|
if ($languageKeyAliases) {
|
468
554
|
var alias;
|
469
555
|
for (var langKeyAlias in $languageKeyAliases) {
|
470
|
-
|
471
|
-
|
472
|
-
|
556
|
+
if ($languageKeyAliases.hasOwnProperty(langKeyAlias)) {
|
557
|
+
var hasWildcardKey = false;
|
558
|
+
var hasExactKey = Object.prototype.hasOwnProperty.call($languageKeyAliases, langKeyAlias) &&
|
559
|
+
angular.lowercase(langKeyAlias) === angular.lowercase(preferred);
|
473
560
|
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
561
|
+
if (langKeyAlias.slice(-1) === '*') {
|
562
|
+
hasWildcardKey = langKeyAlias.slice(0, -1) === preferred.slice(0, langKeyAlias.length - 1);
|
563
|
+
}
|
564
|
+
if (hasExactKey || hasWildcardKey) {
|
565
|
+
alias = $languageKeyAliases[langKeyAlias];
|
566
|
+
if (indexOf(avail, angular.lowercase(alias)) > -1) {
|
567
|
+
return alias;
|
568
|
+
}
|
481
569
|
}
|
482
570
|
}
|
483
571
|
}
|
484
572
|
}
|
485
573
|
|
486
|
-
|
487
|
-
|
574
|
+
// Check for a language code without region
|
575
|
+
var parts = preferred.split('_');
|
488
576
|
|
489
|
-
|
490
|
-
|
491
|
-
}
|
577
|
+
if (parts.length > 1 && indexOf(avail, angular.lowercase(parts[0])) > -1) {
|
578
|
+
return parts[0];
|
492
579
|
}
|
493
580
|
|
494
|
-
// If everything fails,
|
495
|
-
return
|
581
|
+
// If everything fails, return undefined.
|
582
|
+
return;
|
496
583
|
};
|
497
584
|
|
498
585
|
/**
|
@@ -527,7 +614,7 @@ function $translate($STORAGE_KEY, $windowProvider, $translateSanitizationProvide
|
|
527
614
|
* registered with no language key. Invoking it with a language key returns the
|
528
615
|
* related translation table.
|
529
616
|
*
|
530
|
-
* @param {string}
|
617
|
+
* @param {string} langKey A language key.
|
531
618
|
* @param {object} translationTable A plain old JavaScript object that represents a translation table.
|
532
619
|
*
|
533
620
|
*/
|
@@ -572,6 +659,26 @@ function $translate($STORAGE_KEY, $windowProvider, $translateSanitizationProvide
|
|
572
659
|
return this;
|
573
660
|
};
|
574
661
|
|
662
|
+
/**
|
663
|
+
* @ngdoc function
|
664
|
+
* @name pascalprecht.translate.$translateProvider#nestedObjectDelimeter
|
665
|
+
* @methodOf pascalprecht.translate.$translateProvider
|
666
|
+
*
|
667
|
+
* @description
|
668
|
+
*
|
669
|
+
* Let's you change the delimiter for namespaced translations.
|
670
|
+
* Default delimiter is `.`.
|
671
|
+
*
|
672
|
+
* @param {string} delimiter namespace separator
|
673
|
+
*/
|
674
|
+
this.nestedObjectDelimeter = function (delimiter) {
|
675
|
+
if (!delimiter) {
|
676
|
+
return $nestedObjectDelimeter;
|
677
|
+
}
|
678
|
+
$nestedObjectDelimeter = delimiter;
|
679
|
+
return this;
|
680
|
+
};
|
681
|
+
|
575
682
|
/**
|
576
683
|
* @name flatObject
|
577
684
|
* @private
|
@@ -597,10 +704,10 @@ function $translate($STORAGE_KEY, $windowProvider, $translateSanitizationProvide
|
|
597
704
|
if (angular.isObject(val)) {
|
598
705
|
flatObject(val, path.concat(key), result, key);
|
599
706
|
} else {
|
600
|
-
keyWithPath = path.length ? ('' + path.join(
|
601
|
-
if(path.length && key === prevKey){
|
707
|
+
keyWithPath = path.length ? ('' + path.join($nestedObjectDelimeter) + $nestedObjectDelimeter + key) : key;
|
708
|
+
if (path.length && key === prevKey) {
|
602
709
|
// Create shortcut path (foo.bar == foo.bar.bar)
|
603
|
-
keyWithShortPath = '' + path.join(
|
710
|
+
keyWithShortPath = '' + path.join($nestedObjectDelimeter);
|
604
711
|
// Link it to original path
|
605
712
|
result[keyWithShortPath] = '@:' + keyWithPath;
|
606
713
|
}
|
@@ -671,7 +778,7 @@ function $translate($STORAGE_KEY, $windowProvider, $translateSanitizationProvide
|
|
671
778
|
return this;
|
672
779
|
};
|
673
780
|
|
674
|
-
|
781
|
+
/**
|
675
782
|
* @ngdoc function
|
676
783
|
* @name pascalprecht.translate.$translateProvider#preferredLanguage
|
677
784
|
* @methodOf pascalprecht.translate.$translateProvider
|
@@ -682,12 +789,13 @@ function $translate($STORAGE_KEY, $windowProvider, $translateSanitizationProvide
|
|
682
789
|
* only that it says which language to **prefer**.
|
683
790
|
*
|
684
791
|
* @param {string} langKey A language key.
|
685
|
-
*
|
686
792
|
*/
|
687
|
-
this.preferredLanguage = function(langKey) {
|
688
|
-
|
689
|
-
|
690
|
-
|
793
|
+
this.preferredLanguage = function (langKey) {
|
794
|
+
if (langKey) {
|
795
|
+
setupPreferredLanguage(langKey);
|
796
|
+
return this;
|
797
|
+
}
|
798
|
+
return $preferredLanguage;
|
691
799
|
};
|
692
800
|
var setupPreferredLanguage = function (langKey) {
|
693
801
|
if (langKey) {
|
@@ -780,12 +888,12 @@ function $translate($STORAGE_KEY, $windowProvider, $translateSanitizationProvide
|
|
780
888
|
if (langKey) {
|
781
889
|
if (angular.isString(langKey)) {
|
782
890
|
$fallbackWasString = true;
|
783
|
-
$fallbackLanguage = [
|
891
|
+
$fallbackLanguage = [langKey];
|
784
892
|
} else if (angular.isArray(langKey)) {
|
785
893
|
$fallbackWasString = false;
|
786
894
|
$fallbackLanguage = langKey;
|
787
895
|
}
|
788
|
-
if (angular.isString($preferredLanguage)
|
896
|
+
if (angular.isString($preferredLanguage) && indexOf($fallbackLanguage, $preferredLanguage) < 0) {
|
789
897
|
$fallbackLanguage.push($preferredLanguage);
|
790
898
|
}
|
791
899
|
|
@@ -825,7 +933,21 @@ function $translate($STORAGE_KEY, $windowProvider, $translateSanitizationProvide
|
|
825
933
|
return $uses;
|
826
934
|
};
|
827
935
|
|
828
|
-
|
936
|
+
/**
|
937
|
+
* @ngdoc function
|
938
|
+
* @name pascalprecht.translate.$translateProvider#resolveClientLocale
|
939
|
+
* @methodOf pascalprecht.translate.$translateProvider
|
940
|
+
*
|
941
|
+
* @description
|
942
|
+
* This returns the current browser/client's language key. The result is processed with the configured uniform tag resolver.
|
943
|
+
*
|
944
|
+
* @returns {string} the current client/browser language key
|
945
|
+
*/
|
946
|
+
this.resolveClientLocale = function () {
|
947
|
+
return getLocale();
|
948
|
+
};
|
949
|
+
|
950
|
+
/**
|
829
951
|
* @ngdoc function
|
830
952
|
* @name pascalprecht.translate.$translateProvider#storageKey
|
831
953
|
* @methodOf pascalprecht.translate.$translateProvider
|
@@ -835,7 +957,7 @@ function $translate($STORAGE_KEY, $windowProvider, $translateSanitizationProvide
|
|
835
957
|
*
|
836
958
|
* @param {string} key A key for the storage.
|
837
959
|
*/
|
838
|
-
var storageKey = function(key) {
|
960
|
+
var storageKey = function (key) {
|
839
961
|
if (!key) {
|
840
962
|
if ($storagePrefix) {
|
841
963
|
return $storagePrefix + $storageKey;
|
@@ -860,7 +982,7 @@ function $translate($STORAGE_KEY, $windowProvider, $translateSanitizationProvide
|
|
860
982
|
* @param {Object=} options Optional configuration object
|
861
983
|
*/
|
862
984
|
this.useUrlLoader = function (url, options) {
|
863
|
-
return this.useLoader('$translateUrlLoader', angular.extend({
|
985
|
+
return this.useLoader('$translateUrlLoader', angular.extend({url : url}, options));
|
864
986
|
};
|
865
987
|
|
866
988
|
/**
|
@@ -1091,7 +1213,7 @@ function $translate($STORAGE_KEY, $windowProvider, $translateSanitizationProvide
|
|
1091
1213
|
options = {};
|
1092
1214
|
} else if (angular.isString(options)) {
|
1093
1215
|
options = {
|
1094
|
-
standard: options
|
1216
|
+
standard : options
|
1095
1217
|
};
|
1096
1218
|
}
|
1097
1219
|
|
@@ -1126,7 +1248,7 @@ function $translate($STORAGE_KEY, $windowProvider, $translateSanitizationProvide
|
|
1126
1248
|
if (!$availableLanguageKeys.length) {
|
1127
1249
|
$preferredLanguage = locale;
|
1128
1250
|
} else {
|
1129
|
-
$preferredLanguage = negotiateLocale(locale);
|
1251
|
+
$preferredLanguage = negotiateLocale(locale) || locale;
|
1130
1252
|
}
|
1131
1253
|
|
1132
1254
|
return this;
|
@@ -1166,7 +1288,7 @@ function $translate($STORAGE_KEY, $windowProvider, $translateSanitizationProvide
|
|
1166
1288
|
*
|
1167
1289
|
* @description
|
1168
1290
|
* Registers a cache for internal $http based loaders.
|
1169
|
-
* {@link pascalprecht.translate.$
|
1291
|
+
* {@link pascalprecht.translate.$translationCache $translationCache}.
|
1170
1292
|
* When false the cache will be disabled (default). When true or undefined
|
1171
1293
|
* the cache will be a default (see $cacheFactory). When an object it will
|
1172
1294
|
* be treat as a cache object itself: the usage is $http({cache: cache})
|
@@ -1237,6 +1359,48 @@ function $translate($STORAGE_KEY, $windowProvider, $translateSanitizationProvide
|
|
1237
1359
|
}
|
1238
1360
|
};
|
1239
1361
|
|
1362
|
+
/**
|
1363
|
+
* @ngdoc function
|
1364
|
+
* @name pascalprecht.translate.$translateProvider#postProcess
|
1365
|
+
* @methodOf pascalprecht.translate.$translateProvider
|
1366
|
+
*
|
1367
|
+
* @description
|
1368
|
+
* The post processor will be intercept right after the translation result. It can modify the result.
|
1369
|
+
*
|
1370
|
+
* @param {object} fn Function or service name (string) to be called after the translation value has been set / resolved. The function itself will enrich every value being processed and then continue the normal resolver process
|
1371
|
+
*/
|
1372
|
+
this.postProcess = function (fn) {
|
1373
|
+
if (fn) {
|
1374
|
+
postProcessFn = fn;
|
1375
|
+
} else {
|
1376
|
+
postProcessFn = undefined;
|
1377
|
+
}
|
1378
|
+
return this;
|
1379
|
+
};
|
1380
|
+
|
1381
|
+
/**
|
1382
|
+
* @ngdoc function
|
1383
|
+
* @name pascalprecht.translate.$translateProvider#keepContent
|
1384
|
+
* @methodOf pascalprecht.translate.$translateProvider
|
1385
|
+
*
|
1386
|
+
* @description
|
1387
|
+
* If keepContent is set to true than translate directive will always use innerHTML
|
1388
|
+
* as a default translation
|
1389
|
+
*
|
1390
|
+
* Example:
|
1391
|
+
* <pre>
|
1392
|
+
* app.config(function ($translateProvider) {
|
1393
|
+
* $translateProvider.keepContent(true);
|
1394
|
+
* });
|
1395
|
+
* </pre>
|
1396
|
+
*
|
1397
|
+
* @param {boolean} value - valid values are true or false
|
1398
|
+
*/
|
1399
|
+
this.keepContent = function (value) {
|
1400
|
+
$keepContent = !(!value);
|
1401
|
+
return this;
|
1402
|
+
};
|
1403
|
+
|
1240
1404
|
/**
|
1241
1405
|
* @ngdoc object
|
1242
1406
|
* @name pascalprecht.translate.$translate
|
@@ -1261,1069 +1425,1344 @@ function $translate($STORAGE_KEY, $windowProvider, $translateSanitizationProvide
|
|
1261
1425
|
* is the translation id and the value the translation.
|
1262
1426
|
* @param {object=} interpolateParams An object hash for dynamic values
|
1263
1427
|
* @param {string} interpolationId The id of the interpolation to use
|
1428
|
+
* @param {string} defaultTranslationText the optional default translation text that is written as
|
1429
|
+
* as default text in case it is not found in any configured language
|
1430
|
+
* @param {string} forceLanguage A language to be used instead of the current language
|
1264
1431
|
* @returns {object} promise
|
1265
1432
|
*/
|
1266
|
-
this.$get = [
|
1267
|
-
|
1268
|
-
|
1269
|
-
|
1270
|
-
|
1271
|
-
|
1272
|
-
|
1273
|
-
|
1274
|
-
|
1275
|
-
|
1276
|
-
|
1277
|
-
|
1278
|
-
|
1279
|
-
|
1280
|
-
|
1281
|
-
|
1282
|
-
|
1283
|
-
|
1284
|
-
|
1285
|
-
|
1286
|
-
|
1287
|
-
|
1288
|
-
|
1289
|
-
|
1290
|
-
|
1291
|
-
|
1292
|
-
|
1293
|
-
|
1294
|
-
|
1295
|
-
|
1296
|
-
|
1297
|
-
|
1298
|
-
|
1299
|
-
|
1300
|
-
|
1301
|
-
|
1433
|
+
this.$get = ['$log', '$injector', '$rootScope', '$q', function ($log, $injector, $rootScope, $q) {
|
1434
|
+
|
1435
|
+
var Storage,
|
1436
|
+
defaultInterpolator = $injector.get($interpolationFactory || '$translateDefaultInterpolation'),
|
1437
|
+
pendingLoader = false,
|
1438
|
+
interpolatorHashMap = {},
|
1439
|
+
langPromises = {},
|
1440
|
+
fallbackIndex,
|
1441
|
+
startFallbackIteration;
|
1442
|
+
|
1443
|
+
var $translate = function (translationId, interpolateParams, interpolationId, defaultTranslationText, forceLanguage) {
|
1444
|
+
if (!$uses && $preferredLanguage) {
|
1445
|
+
$uses = $preferredLanguage;
|
1446
|
+
}
|
1447
|
+
var uses = (forceLanguage && forceLanguage !== $uses) ? // we don't want to re-negotiate $uses
|
1448
|
+
(negotiateLocale(forceLanguage) || forceLanguage) : $uses;
|
1449
|
+
|
1450
|
+
// Check forceLanguage is present
|
1451
|
+
if (forceLanguage) {
|
1452
|
+
loadTranslationsIfMissing(forceLanguage);
|
1453
|
+
}
|
1454
|
+
|
1455
|
+
// Duck detection: If the first argument is an array, a bunch of translations was requested.
|
1456
|
+
// The result is an object.
|
1457
|
+
if (angular.isArray(translationId)) {
|
1458
|
+
// Inspired by Q.allSettled by Kris Kowal
|
1459
|
+
// https://github.com/kriskowal/q/blob/b0fa72980717dc202ffc3cbf03b936e10ebbb9d7/q.js#L1553-1563
|
1460
|
+
// This transforms all promises regardless resolved or rejected
|
1461
|
+
var translateAll = function (translationIds) {
|
1462
|
+
var results = {}; // storing the actual results
|
1463
|
+
var promises = []; // promises to wait for
|
1464
|
+
// Wraps the promise a) being always resolved and b) storing the link id->value
|
1465
|
+
var translate = function (translationId) {
|
1466
|
+
var deferred = $q.defer();
|
1467
|
+
var regardless = function (value) {
|
1468
|
+
results[translationId] = value;
|
1469
|
+
deferred.resolve([translationId, value]);
|
1302
1470
|
};
|
1303
|
-
|
1304
|
-
|
1305
|
-
|
1306
|
-
// wait for all (including storing to results)
|
1307
|
-
return $q.all(promises).then(function () {
|
1308
|
-
// return the results
|
1309
|
-
return results;
|
1310
|
-
});
|
1471
|
+
// we don't care whether the promise was resolved or rejected; just store the values
|
1472
|
+
$translate(translationId, interpolateParams, interpolationId, defaultTranslationText, forceLanguage).then(regardless, regardless);
|
1473
|
+
return deferred.promise;
|
1311
1474
|
};
|
1312
|
-
|
1313
|
-
|
1475
|
+
for (var i = 0, c = translationIds.length; i < c; i++) {
|
1476
|
+
promises.push(translate(translationIds[i]));
|
1477
|
+
}
|
1478
|
+
// wait for all (including storing to results)
|
1479
|
+
return $q.all(promises).then(function () {
|
1480
|
+
// return the results
|
1481
|
+
return results;
|
1482
|
+
});
|
1483
|
+
};
|
1484
|
+
return translateAll(translationId);
|
1485
|
+
}
|
1314
1486
|
|
1315
|
-
|
1487
|
+
var deferred = $q.defer();
|
1316
1488
|
|
1317
|
-
|
1318
|
-
|
1319
|
-
|
1320
|
-
|
1489
|
+
// trim off any whitespace
|
1490
|
+
if (translationId) {
|
1491
|
+
translationId = trim.apply(translationId);
|
1492
|
+
}
|
1321
1493
|
|
1322
|
-
|
1323
|
-
|
1324
|
-
|
1325
|
-
|
1494
|
+
var promiseToWaitFor = (function () {
|
1495
|
+
var promise = $preferredLanguage ?
|
1496
|
+
langPromises[$preferredLanguage] :
|
1497
|
+
langPromises[uses];
|
1326
1498
|
|
1327
|
-
|
1499
|
+
fallbackIndex = 0;
|
1328
1500
|
|
1329
|
-
|
1330
|
-
|
1331
|
-
|
1332
|
-
|
1333
|
-
|
1334
|
-
|
1335
|
-
|
1336
|
-
|
1337
|
-
|
1338
|
-
|
1339
|
-
|
1340
|
-
|
1341
|
-
|
1342
|
-
|
1343
|
-
|
1344
|
-
|
1345
|
-
|
1346
|
-
|
1347
|
-
}
|
1501
|
+
if ($storageFactory && !promise) {
|
1502
|
+
// looks like there's no pending promise for $preferredLanguage or
|
1503
|
+
// $uses. Maybe there's one pending for a language that comes from
|
1504
|
+
// storage.
|
1505
|
+
var langKey = Storage.get($storageKey);
|
1506
|
+
promise = langPromises[langKey];
|
1507
|
+
|
1508
|
+
if ($fallbackLanguage && $fallbackLanguage.length) {
|
1509
|
+
var index = indexOf($fallbackLanguage, langKey);
|
1510
|
+
// maybe the language from storage is also defined as fallback language
|
1511
|
+
// we increase the fallback language index to not search in that language
|
1512
|
+
// as fallback, since it's probably the first used language
|
1513
|
+
// in that case the index starts after the first element
|
1514
|
+
fallbackIndex = (index === 0) ? 1 : 0;
|
1515
|
+
|
1516
|
+
// but we can make sure to ALWAYS fallback to preferred language at least
|
1517
|
+
if (indexOf($fallbackLanguage, $preferredLanguage) < 0) {
|
1518
|
+
$fallbackLanguage.push($preferredLanguage);
|
1348
1519
|
}
|
1349
1520
|
}
|
1350
|
-
return promise;
|
1351
|
-
}());
|
1352
|
-
|
1353
|
-
if (!promiseToWaitFor) {
|
1354
|
-
// no promise to wait for? okay. Then there's no loader registered
|
1355
|
-
// nor is a one pending for language that comes from storage.
|
1356
|
-
// We can just translate.
|
1357
|
-
determineTranslation(translationId, interpolateParams, interpolationId, defaultTranslationText).then(deferred.resolve, deferred.reject);
|
1358
|
-
} else {
|
1359
|
-
var promiseResolved = function () {
|
1360
|
-
determineTranslation(translationId, interpolateParams, interpolationId, defaultTranslationText).then(deferred.resolve, deferred.reject);
|
1361
|
-
};
|
1362
|
-
promiseResolved.displayName = 'promiseResolved';
|
1363
|
-
|
1364
|
-
promiseToWaitFor['finally'](promiseResolved, deferred.reject);
|
1365
1521
|
}
|
1366
|
-
return
|
1367
|
-
};
|
1522
|
+
return promise;
|
1523
|
+
}());
|
1524
|
+
|
1525
|
+
if (!promiseToWaitFor) {
|
1526
|
+
// no promise to wait for? okay. Then there's no loader registered
|
1527
|
+
// nor is a one pending for language that comes from storage.
|
1528
|
+
// We can just translate.
|
1529
|
+
determineTranslation(translationId, interpolateParams, interpolationId, defaultTranslationText, uses).then(deferred.resolve, deferred.reject);
|
1530
|
+
} else {
|
1531
|
+
var promiseResolved = function () {
|
1532
|
+
// $uses may have changed while waiting
|
1533
|
+
if (!forceLanguage) {
|
1534
|
+
uses = $uses;
|
1535
|
+
}
|
1536
|
+
determineTranslation(translationId, interpolateParams, interpolationId, defaultTranslationText, uses).then(deferred.resolve, deferred.reject);
|
1537
|
+
};
|
1538
|
+
promiseResolved.displayName = 'promiseResolved';
|
1368
1539
|
|
1369
|
-
|
1370
|
-
|
1371
|
-
|
1372
|
-
|
1373
|
-
* @description
|
1374
|
-
* Applies not fount indicators to given translation id, if needed.
|
1375
|
-
* This function gets only executed, if a translation id doesn't exist,
|
1376
|
-
* which is why a translation id is expected as argument.
|
1377
|
-
*
|
1378
|
-
* @param {string} translationId Translation id.
|
1379
|
-
* @returns {string} Same as given translation id but applied with not found
|
1380
|
-
* indicators.
|
1381
|
-
*/
|
1382
|
-
var applyNotFoundIndicators = function (translationId) {
|
1383
|
-
// applying notFoundIndicators
|
1384
|
-
if ($notFoundIndicatorLeft) {
|
1385
|
-
translationId = [$notFoundIndicatorLeft, translationId].join(' ');
|
1386
|
-
}
|
1387
|
-
if ($notFoundIndicatorRight) {
|
1388
|
-
translationId = [translationId, $notFoundIndicatorRight].join(' ');
|
1389
|
-
}
|
1390
|
-
return translationId;
|
1391
|
-
};
|
1540
|
+
promiseToWaitFor['finally'](promiseResolved)['catch'](angular.noop); // we don't care about errors here, already handled
|
1541
|
+
}
|
1542
|
+
return deferred.promise;
|
1543
|
+
};
|
1392
1544
|
|
1393
|
-
|
1394
|
-
|
1395
|
-
|
1396
|
-
|
1397
|
-
|
1398
|
-
|
1399
|
-
|
1400
|
-
|
1401
|
-
|
1402
|
-
|
1403
|
-
|
1404
|
-
|
1405
|
-
|
1406
|
-
|
1545
|
+
/**
|
1546
|
+
* @name applyNotFoundIndicators
|
1547
|
+
* @private
|
1548
|
+
*
|
1549
|
+
* @description
|
1550
|
+
* Applies not fount indicators to given translation id, if needed.
|
1551
|
+
* This function gets only executed, if a translation id doesn't exist,
|
1552
|
+
* which is why a translation id is expected as argument.
|
1553
|
+
*
|
1554
|
+
* @param {string} translationId Translation id.
|
1555
|
+
* @returns {string} Same as given translation id but applied with not found
|
1556
|
+
* indicators.
|
1557
|
+
*/
|
1558
|
+
var applyNotFoundIndicators = function (translationId) {
|
1559
|
+
// applying notFoundIndicators
|
1560
|
+
if ($notFoundIndicatorLeft) {
|
1561
|
+
translationId = [$notFoundIndicatorLeft, translationId].join(' ');
|
1562
|
+
}
|
1563
|
+
if ($notFoundIndicatorRight) {
|
1564
|
+
translationId = [translationId, $notFoundIndicatorRight].join(' ');
|
1565
|
+
}
|
1566
|
+
return translationId;
|
1567
|
+
};
|
1407
1568
|
|
1408
|
-
|
1409
|
-
|
1410
|
-
|
1411
|
-
|
1412
|
-
|
1569
|
+
/**
|
1570
|
+
* @name useLanguage
|
1571
|
+
* @private
|
1572
|
+
*
|
1573
|
+
* @description
|
1574
|
+
* Makes actual use of a language by setting a given language key as used
|
1575
|
+
* language and informs registered interpolators to also use the given
|
1576
|
+
* key as locale.
|
1577
|
+
*
|
1578
|
+
* @param {string} key Locale key.
|
1579
|
+
*/
|
1580
|
+
var useLanguage = function (key) {
|
1581
|
+
$uses = key;
|
1582
|
+
|
1583
|
+
// make sure to store new language key before triggering success event
|
1584
|
+
if ($storageFactory) {
|
1585
|
+
Storage.put($translate.storageKey(), $uses);
|
1586
|
+
}
|
1413
1587
|
|
1414
|
-
|
1415
|
-
interpolatorHashMap[id].setLocale($uses);
|
1416
|
-
};
|
1417
|
-
eachInterpolator.displayName = 'eachInterpolatorLocaleSetter';
|
1588
|
+
$rootScope.$emit('$translateChangeSuccess', {language : key});
|
1418
1589
|
|
1419
|
-
|
1420
|
-
|
1421
|
-
|
1590
|
+
// inform default interpolator
|
1591
|
+
defaultInterpolator.setLocale($uses);
|
1592
|
+
|
1593
|
+
var eachInterpolator = function (interpolator, id) {
|
1594
|
+
interpolatorHashMap[id].setLocale($uses);
|
1422
1595
|
};
|
1596
|
+
eachInterpolator.displayName = 'eachInterpolatorLocaleSetter';
|
1423
1597
|
|
1424
|
-
|
1425
|
-
|
1426
|
-
|
1427
|
-
|
1428
|
-
* @description
|
1429
|
-
* Kicks of registered async loader using `$injector` and applies existing
|
1430
|
-
* loader options. When resolved, it updates translation tables accordingly
|
1431
|
-
* or rejects with given language key.
|
1432
|
-
*
|
1433
|
-
* @param {string} key Language key.
|
1434
|
-
* @return {Promise} A promise.
|
1435
|
-
*/
|
1436
|
-
var loadAsync = function (key) {
|
1437
|
-
if (!key) {
|
1438
|
-
throw 'No language key specified for loading.';
|
1439
|
-
}
|
1598
|
+
// inform all others too!
|
1599
|
+
angular.forEach(interpolatorHashMap, eachInterpolator);
|
1600
|
+
$rootScope.$emit('$translateChangeEnd', {language : key});
|
1601
|
+
};
|
1440
1602
|
|
1441
|
-
|
1603
|
+
/**
|
1604
|
+
* @name loadAsync
|
1605
|
+
* @private
|
1606
|
+
*
|
1607
|
+
* @description
|
1608
|
+
* Kicks off registered async loader using `$injector` and applies existing
|
1609
|
+
* loader options. When resolved, it updates translation tables accordingly
|
1610
|
+
* or rejects with given language key.
|
1611
|
+
*
|
1612
|
+
* @param {string} key Language key.
|
1613
|
+
* @return {Promise} A promise.
|
1614
|
+
*/
|
1615
|
+
var loadAsync = function (key) {
|
1616
|
+
if (!key) {
|
1617
|
+
throw 'No language key specified for loading.';
|
1618
|
+
}
|
1442
1619
|
|
1443
|
-
|
1444
|
-
pendingLoader = true;
|
1620
|
+
var deferred = $q.defer();
|
1445
1621
|
|
1446
|
-
|
1447
|
-
|
1448
|
-
// getting on-demand instance of loader
|
1449
|
-
cache = $injector.get(cache);
|
1450
|
-
}
|
1622
|
+
$rootScope.$emit('$translateLoadingStart', {language : key});
|
1623
|
+
pendingLoader = true;
|
1451
1624
|
|
1452
|
-
|
1453
|
-
|
1454
|
-
|
1455
|
-
|
1456
|
-
|
1457
|
-
});
|
1625
|
+
var cache = loaderCache;
|
1626
|
+
if (typeof(cache) === 'string') {
|
1627
|
+
// getting on-demand instance of loader
|
1628
|
+
cache = $injector.get(cache);
|
1629
|
+
}
|
1458
1630
|
|
1459
|
-
|
1460
|
-
|
1461
|
-
|
1631
|
+
var loaderOptions = angular.extend({}, $loaderOptions, {
|
1632
|
+
key : key,
|
1633
|
+
$http : angular.extend({}, {
|
1634
|
+
cache : cache
|
1635
|
+
}, $loaderOptions.$http)
|
1636
|
+
});
|
1462
1637
|
|
1463
|
-
|
1464
|
-
|
1465
|
-
|
1466
|
-
|
1467
|
-
|
1468
|
-
|
1469
|
-
|
1470
|
-
pendingLoader = false;
|
1471
|
-
deferred.resolve({
|
1472
|
-
key: key,
|
1473
|
-
table: translationTable
|
1638
|
+
var onLoaderSuccess = function (data) {
|
1639
|
+
var translationTable = {};
|
1640
|
+
$rootScope.$emit('$translateLoadingSuccess', {language : key});
|
1641
|
+
|
1642
|
+
if (angular.isArray(data)) {
|
1643
|
+
angular.forEach(data, function (table) {
|
1644
|
+
angular.extend(translationTable, flatObject(table));
|
1474
1645
|
});
|
1475
|
-
|
1476
|
-
|
1477
|
-
|
1646
|
+
} else {
|
1647
|
+
angular.extend(translationTable, flatObject(data));
|
1648
|
+
}
|
1649
|
+
pendingLoader = false;
|
1650
|
+
deferred.resolve({
|
1651
|
+
key : key,
|
1652
|
+
table : translationTable
|
1653
|
+
});
|
1654
|
+
$rootScope.$emit('$translateLoadingEnd', {language : key});
|
1655
|
+
};
|
1656
|
+
onLoaderSuccess.displayName = 'onLoaderSuccess';
|
1478
1657
|
|
1479
|
-
|
1480
|
-
|
1481
|
-
|
1482
|
-
|
1483
|
-
|
1484
|
-
|
1658
|
+
var onLoaderError = function (key) {
|
1659
|
+
$rootScope.$emit('$translateLoadingError', {language : key});
|
1660
|
+
deferred.reject(key);
|
1661
|
+
$rootScope.$emit('$translateLoadingEnd', {language : key});
|
1662
|
+
};
|
1663
|
+
onLoaderError.displayName = 'onLoaderError';
|
1485
1664
|
|
1486
|
-
|
1487
|
-
|
1665
|
+
$injector.get($loaderFactory)(loaderOptions)
|
1666
|
+
.then(onLoaderSuccess, onLoaderError);
|
1488
1667
|
|
1489
|
-
|
1490
|
-
|
1668
|
+
return deferred.promise;
|
1669
|
+
};
|
1491
1670
|
|
1492
|
-
|
1493
|
-
|
1671
|
+
if ($storageFactory) {
|
1672
|
+
Storage = $injector.get($storageFactory);
|
1494
1673
|
|
1495
|
-
|
1496
|
-
|
1497
|
-
}
|
1674
|
+
if (!Storage.get || !Storage.put) {
|
1675
|
+
throw new Error('Couldn\'t use storage \'' + $storageFactory + '\', missing get() or put() method!');
|
1498
1676
|
}
|
1677
|
+
}
|
1499
1678
|
|
1500
|
-
|
1501
|
-
|
1502
|
-
|
1503
|
-
|
1504
|
-
|
1505
|
-
|
1506
|
-
|
1507
|
-
|
1508
|
-
|
1509
|
-
|
1510
|
-
|
1679
|
+
// if we have additional interpolations that were added via
|
1680
|
+
// $translateProvider.addInterpolation(), we have to map'em
|
1681
|
+
if ($interpolatorFactories.length) {
|
1682
|
+
var eachInterpolationFactory = function (interpolatorFactory) {
|
1683
|
+
var interpolator = $injector.get(interpolatorFactory);
|
1684
|
+
// setting initial locale for each interpolation service
|
1685
|
+
interpolator.setLocale($preferredLanguage || $uses);
|
1686
|
+
// make'em recognizable through id
|
1687
|
+
interpolatorHashMap[interpolator.getInterpolationIdentifier()] = interpolator;
|
1688
|
+
};
|
1689
|
+
eachInterpolationFactory.displayName = 'interpolationFactoryAdder';
|
1690
|
+
|
1691
|
+
angular.forEach($interpolatorFactories, eachInterpolationFactory);
|
1692
|
+
}
|
1511
1693
|
|
1512
|
-
|
1694
|
+
/**
|
1695
|
+
* @name getTranslationTable
|
1696
|
+
* @private
|
1697
|
+
*
|
1698
|
+
* @description
|
1699
|
+
* Returns a promise that resolves to the translation table
|
1700
|
+
* or is rejected if an error occurred.
|
1701
|
+
*
|
1702
|
+
* @param langKey
|
1703
|
+
* @returns {Q.promise}
|
1704
|
+
*/
|
1705
|
+
var getTranslationTable = function (langKey) {
|
1706
|
+
var deferred = $q.defer();
|
1707
|
+
if (Object.prototype.hasOwnProperty.call($translationTable, langKey)) {
|
1708
|
+
deferred.resolve($translationTable[langKey]);
|
1709
|
+
} else if (langPromises[langKey]) {
|
1710
|
+
var onResolve = function (data) {
|
1711
|
+
translations(data.key, data.table);
|
1712
|
+
deferred.resolve(data.table);
|
1713
|
+
};
|
1714
|
+
onResolve.displayName = 'translationTableResolver';
|
1715
|
+
langPromises[langKey].then(onResolve, deferred.reject);
|
1716
|
+
} else {
|
1717
|
+
deferred.reject();
|
1513
1718
|
}
|
1719
|
+
return deferred.promise;
|
1720
|
+
};
|
1514
1721
|
|
1515
|
-
|
1516
|
-
|
1517
|
-
|
1518
|
-
|
1519
|
-
|
1520
|
-
|
1521
|
-
|
1522
|
-
|
1523
|
-
|
1524
|
-
|
1525
|
-
|
1526
|
-
|
1527
|
-
|
1528
|
-
|
1529
|
-
|
1530
|
-
|
1531
|
-
|
1532
|
-
|
1533
|
-
|
1534
|
-
|
1535
|
-
|
1536
|
-
|
1722
|
+
/**
|
1723
|
+
* @name getFallbackTranslation
|
1724
|
+
* @private
|
1725
|
+
*
|
1726
|
+
* @description
|
1727
|
+
* Returns a promise that will resolve to the translation
|
1728
|
+
* or be rejected if no translation was found for the language.
|
1729
|
+
* This function is currently only used for fallback language translation.
|
1730
|
+
*
|
1731
|
+
* @param langKey The language to translate to.
|
1732
|
+
* @param translationId
|
1733
|
+
* @param interpolateParams
|
1734
|
+
* @param Interpolator
|
1735
|
+
* @param sanitizeStrategy
|
1736
|
+
* @returns {Q.promise}
|
1737
|
+
*/
|
1738
|
+
var getFallbackTranslation = function (langKey, translationId, interpolateParams, Interpolator, sanitizeStrategy) {
|
1739
|
+
var deferred = $q.defer();
|
1740
|
+
|
1741
|
+
var onResolve = function (translationTable) {
|
1742
|
+
if (Object.prototype.hasOwnProperty.call(translationTable, translationId) && translationTable[translationId] !== null) {
|
1743
|
+
Interpolator.setLocale(langKey);
|
1744
|
+
var translation = translationTable[translationId];
|
1745
|
+
if (translation.substr(0, 2) === '@:') {
|
1746
|
+
getFallbackTranslation(langKey, translation.substr(2), interpolateParams, Interpolator, sanitizeStrategy)
|
1747
|
+
.then(deferred.resolve, deferred.reject);
|
1748
|
+
} else {
|
1749
|
+
var interpolatedValue = Interpolator.interpolate(translationTable[translationId], interpolateParams, 'service', sanitizeStrategy, translationId);
|
1750
|
+
interpolatedValue = applyPostProcessing(translationId, translationTable[translationId], interpolatedValue, interpolateParams, langKey);
|
1751
|
+
|
1752
|
+
deferred.resolve(interpolatedValue);
|
1753
|
+
|
1754
|
+
}
|
1755
|
+
Interpolator.setLocale($uses);
|
1537
1756
|
} else {
|
1538
1757
|
deferred.reject();
|
1539
1758
|
}
|
1540
|
-
return deferred.promise;
|
1541
1759
|
};
|
1760
|
+
onResolve.displayName = 'fallbackTranslationResolver';
|
1542
1761
|
|
1543
|
-
|
1544
|
-
* @name getFallbackTranslation
|
1545
|
-
* @private
|
1546
|
-
*
|
1547
|
-
* @description
|
1548
|
-
* Returns a promise that will resolve to the translation
|
1549
|
-
* or be rejected if no translation was found for the language.
|
1550
|
-
* This function is currently only used for fallback language translation.
|
1551
|
-
*
|
1552
|
-
* @param langKey The language to translate to.
|
1553
|
-
* @param translationId
|
1554
|
-
* @param interpolateParams
|
1555
|
-
* @param Interpolator
|
1556
|
-
* @returns {Q.promise}
|
1557
|
-
*/
|
1558
|
-
var getFallbackTranslation = function (langKey, translationId, interpolateParams, Interpolator) {
|
1559
|
-
var deferred = $q.defer();
|
1560
|
-
|
1561
|
-
var onResolve = function (translationTable) {
|
1562
|
-
if (Object.prototype.hasOwnProperty.call(translationTable, translationId)) {
|
1563
|
-
Interpolator.setLocale(langKey);
|
1564
|
-
var translation = translationTable[translationId];
|
1565
|
-
if (translation.substr(0, 2) === '@:') {
|
1566
|
-
getFallbackTranslation(langKey, translation.substr(2), interpolateParams, Interpolator)
|
1567
|
-
.then(deferred.resolve, deferred.reject);
|
1568
|
-
} else {
|
1569
|
-
deferred.resolve(Interpolator.interpolate(translationTable[translationId], interpolateParams));
|
1570
|
-
}
|
1571
|
-
Interpolator.setLocale($uses);
|
1572
|
-
} else {
|
1573
|
-
deferred.reject();
|
1574
|
-
}
|
1575
|
-
};
|
1576
|
-
onResolve.displayName = 'fallbackTranslationResolver';
|
1577
|
-
|
1578
|
-
getTranslationTable(langKey).then(onResolve, deferred.reject);
|
1762
|
+
getTranslationTable(langKey).then(onResolve, deferred.reject);
|
1579
1763
|
|
1580
|
-
|
1581
|
-
|
1582
|
-
|
1583
|
-
/**
|
1584
|
-
* @name getFallbackTranslationInstant
|
1585
|
-
* @private
|
1586
|
-
*
|
1587
|
-
* @description
|
1588
|
-
* Returns a translation
|
1589
|
-
* This function is currently only used for fallback language translation.
|
1590
|
-
*
|
1591
|
-
* @param langKey The language to translate to.
|
1592
|
-
* @param translationId
|
1593
|
-
* @param interpolateParams
|
1594
|
-
* @param Interpolator
|
1595
|
-
* @returns {string} translation
|
1596
|
-
*/
|
1597
|
-
var getFallbackTranslationInstant = function (langKey, translationId, interpolateParams, Interpolator) {
|
1598
|
-
var result, translationTable = $translationTable[langKey];
|
1764
|
+
return deferred.promise;
|
1765
|
+
};
|
1599
1766
|
|
1600
|
-
|
1601
|
-
|
1602
|
-
|
1603
|
-
|
1604
|
-
|
1767
|
+
/**
|
1768
|
+
* @name getFallbackTranslationInstant
|
1769
|
+
* @private
|
1770
|
+
*
|
1771
|
+
* @description
|
1772
|
+
* Returns a translation
|
1773
|
+
* This function is currently only used for fallback language translation.
|
1774
|
+
*
|
1775
|
+
* @param langKey The language to translate to.
|
1776
|
+
* @param translationId
|
1777
|
+
* @param interpolateParams
|
1778
|
+
* @param Interpolator
|
1779
|
+
* @param sanitizeStrategy sanitize strategy override
|
1780
|
+
*
|
1781
|
+
* @returns {string} translation
|
1782
|
+
*/
|
1783
|
+
var getFallbackTranslationInstant = function (langKey, translationId, interpolateParams, Interpolator, sanitizeStrategy) {
|
1784
|
+
var result, translationTable = $translationTable[langKey];
|
1785
|
+
|
1786
|
+
if (translationTable && Object.prototype.hasOwnProperty.call(translationTable, translationId) && translationTable[translationId] !== null) {
|
1787
|
+
Interpolator.setLocale(langKey);
|
1788
|
+
result = Interpolator.interpolate(translationTable[translationId], interpolateParams, 'filter', sanitizeStrategy, translationId);
|
1789
|
+
result = applyPostProcessing(translationId, translationTable[translationId], result, interpolateParams, langKey, sanitizeStrategy);
|
1790
|
+
// workaround for TrustedValueHolderType
|
1791
|
+
if (!angular.isString(result) && angular.isFunction(result.$$unwrapTrustedValue)) {
|
1792
|
+
var result2 = result.$$unwrapTrustedValue();
|
1793
|
+
if (result2.substr(0, 2) === '@:') {
|
1794
|
+
return getFallbackTranslationInstant(langKey, result2.substr(2), interpolateParams, Interpolator, sanitizeStrategy);
|
1605
1795
|
}
|
1606
|
-
|
1796
|
+
} else if (result.substr(0, 2) === '@:') {
|
1797
|
+
return getFallbackTranslationInstant(langKey, result.substr(2), interpolateParams, Interpolator, sanitizeStrategy);
|
1607
1798
|
}
|
1799
|
+
Interpolator.setLocale($uses);
|
1800
|
+
}
|
1608
1801
|
|
1609
|
-
|
1610
|
-
|
1802
|
+
return result;
|
1803
|
+
};
|
1611
1804
|
|
1612
1805
|
|
1613
|
-
|
1614
|
-
|
1615
|
-
|
1616
|
-
|
1617
|
-
|
1618
|
-
|
1619
|
-
|
1620
|
-
|
1621
|
-
|
1622
|
-
|
1623
|
-
|
1624
|
-
|
1625
|
-
|
1626
|
-
|
1627
|
-
|
1628
|
-
|
1629
|
-
|
1630
|
-
|
1631
|
-
|
1806
|
+
/**
|
1807
|
+
* @name translateByHandler
|
1808
|
+
* @private
|
1809
|
+
*
|
1810
|
+
* Translate by missing translation handler.
|
1811
|
+
*
|
1812
|
+
* @param translationId
|
1813
|
+
* @param interpolateParams
|
1814
|
+
* @param defaultTranslationText
|
1815
|
+
* @param sanitizeStrategy sanitize strategy override
|
1816
|
+
*
|
1817
|
+
* @returns translation created by $missingTranslationHandler or translationId is $missingTranslationHandler is
|
1818
|
+
* absent
|
1819
|
+
*/
|
1820
|
+
var translateByHandler = function (translationId, interpolateParams, defaultTranslationText, sanitizeStrategy) {
|
1821
|
+
// If we have a handler factory - we might also call it here to determine if it provides
|
1822
|
+
// a default text for a translationid that can't be found anywhere in our tables
|
1823
|
+
if ($missingTranslationHandlerFactory) {
|
1824
|
+
return $injector.get($missingTranslationHandlerFactory)(translationId, $uses, interpolateParams, defaultTranslationText, sanitizeStrategy);
|
1825
|
+
} else {
|
1826
|
+
return translationId;
|
1827
|
+
}
|
1828
|
+
};
|
1829
|
+
|
1830
|
+
/**
|
1831
|
+
* @name resolveForFallbackLanguage
|
1832
|
+
* @private
|
1833
|
+
*
|
1834
|
+
* Recursive helper function for fallbackTranslation that will sequentially look
|
1835
|
+
* for a translation in the fallbackLanguages starting with fallbackLanguageIndex.
|
1836
|
+
*
|
1837
|
+
* @param fallbackLanguageIndex
|
1838
|
+
* @param translationId
|
1839
|
+
* @param interpolateParams
|
1840
|
+
* @param Interpolator
|
1841
|
+
* @param defaultTranslationText
|
1842
|
+
* @param sanitizeStrategy
|
1843
|
+
* @returns {Q.promise} Promise that will resolve to the translation.
|
1844
|
+
*/
|
1845
|
+
var resolveForFallbackLanguage = function (fallbackLanguageIndex, translationId, interpolateParams, Interpolator, defaultTranslationText, sanitizeStrategy) {
|
1846
|
+
var deferred = $q.defer();
|
1847
|
+
|
1848
|
+
if (fallbackLanguageIndex < $fallbackLanguage.length) {
|
1849
|
+
var langKey = $fallbackLanguage[fallbackLanguageIndex];
|
1850
|
+
getFallbackTranslation(langKey, translationId, interpolateParams, Interpolator, sanitizeStrategy).then(
|
1851
|
+
function (data) {
|
1852
|
+
deferred.resolve(data);
|
1853
|
+
},
|
1854
|
+
function () {
|
1855
|
+
// Look in the next fallback language for a translation.
|
1856
|
+
// It delays the resolving by passing another promise to resolve.
|
1857
|
+
return resolveForFallbackLanguage(fallbackLanguageIndex + 1, translationId, interpolateParams, Interpolator, defaultTranslationText, sanitizeStrategy).then(deferred.resolve, deferred.reject);
|
1632
1858
|
}
|
1859
|
+
);
|
1860
|
+
} else {
|
1861
|
+
// No translation found in any fallback language
|
1862
|
+
// if a default translation text is set in the directive, then return this as a result
|
1863
|
+
if (defaultTranslationText) {
|
1864
|
+
deferred.resolve(defaultTranslationText);
|
1633
1865
|
} else {
|
1634
|
-
|
1635
|
-
}
|
1636
|
-
};
|
1866
|
+
var missingTranslationHandlerTranslation = translateByHandler(translationId, interpolateParams, defaultTranslationText);
|
1637
1867
|
|
1638
|
-
|
1639
|
-
|
1640
|
-
|
1641
|
-
|
1642
|
-
* Recursive helper function for fallbackTranslation that will sequentially look
|
1643
|
-
* for a translation in the fallbackLanguages starting with fallbackLanguageIndex.
|
1644
|
-
*
|
1645
|
-
* @param fallbackLanguageIndex
|
1646
|
-
* @param translationId
|
1647
|
-
* @param interpolateParams
|
1648
|
-
* @param Interpolator
|
1649
|
-
* @returns {Q.promise} Promise that will resolve to the translation.
|
1650
|
-
*/
|
1651
|
-
var resolveForFallbackLanguage = function (fallbackLanguageIndex, translationId, interpolateParams, Interpolator, defaultTranslationText) {
|
1652
|
-
var deferred = $q.defer();
|
1653
|
-
|
1654
|
-
if (fallbackLanguageIndex < $fallbackLanguage.length) {
|
1655
|
-
var langKey = $fallbackLanguage[fallbackLanguageIndex];
|
1656
|
-
getFallbackTranslation(langKey, translationId, interpolateParams, Interpolator).then(
|
1657
|
-
deferred.resolve,
|
1658
|
-
function () {
|
1659
|
-
// Look in the next fallback language for a translation.
|
1660
|
-
// It delays the resolving by passing another promise to resolve.
|
1661
|
-
resolveForFallbackLanguage(fallbackLanguageIndex + 1, translationId, interpolateParams, Interpolator, defaultTranslationText).then(deferred.resolve);
|
1662
|
-
}
|
1663
|
-
);
|
1664
|
-
} else {
|
1665
|
-
// No translation found in any fallback language
|
1666
|
-
// if a default translation text is set in the directive, then return this as a result
|
1667
|
-
if (defaultTranslationText) {
|
1668
|
-
deferred.resolve(defaultTranslationText);
|
1868
|
+
// if no default translation is set and an error handler is defined, send it to the handler
|
1869
|
+
// and then return the result if it isn't undefined
|
1870
|
+
if ($missingTranslationHandlerFactory && missingTranslationHandlerTranslation) {
|
1871
|
+
deferred.resolve(missingTranslationHandlerTranslation);
|
1669
1872
|
} else {
|
1670
|
-
|
1671
|
-
// and then return the result
|
1672
|
-
deferred.resolve(translateByHandler(translationId, interpolateParams));
|
1873
|
+
deferred.reject(applyNotFoundIndicators(translationId));
|
1673
1874
|
}
|
1674
1875
|
}
|
1675
|
-
|
1676
|
-
|
1876
|
+
}
|
1877
|
+
return deferred.promise;
|
1878
|
+
};
|
1677
1879
|
|
1678
|
-
|
1679
|
-
|
1680
|
-
|
1681
|
-
|
1682
|
-
|
1683
|
-
|
1684
|
-
|
1685
|
-
|
1686
|
-
|
1687
|
-
|
1688
|
-
|
1689
|
-
|
1690
|
-
|
1691
|
-
|
1692
|
-
|
1693
|
-
|
1694
|
-
|
1695
|
-
|
1696
|
-
|
1697
|
-
|
1698
|
-
|
1699
|
-
|
1880
|
+
/**
|
1881
|
+
* @name resolveForFallbackLanguageInstant
|
1882
|
+
* @private
|
1883
|
+
*
|
1884
|
+
* Recursive helper function for fallbackTranslation that will sequentially look
|
1885
|
+
* for a translation in the fallbackLanguages starting with fallbackLanguageIndex.
|
1886
|
+
*
|
1887
|
+
* @param fallbackLanguageIndex
|
1888
|
+
* @param translationId
|
1889
|
+
* @param interpolateParams
|
1890
|
+
* @param Interpolator
|
1891
|
+
* @param sanitizeStrategy
|
1892
|
+
* @returns {string} translation
|
1893
|
+
*/
|
1894
|
+
var resolveForFallbackLanguageInstant = function (fallbackLanguageIndex, translationId, interpolateParams, Interpolator, sanitizeStrategy) {
|
1895
|
+
var result;
|
1896
|
+
|
1897
|
+
if (fallbackLanguageIndex < $fallbackLanguage.length) {
|
1898
|
+
var langKey = $fallbackLanguage[fallbackLanguageIndex];
|
1899
|
+
result = getFallbackTranslationInstant(langKey, translationId, interpolateParams, Interpolator, sanitizeStrategy);
|
1900
|
+
if (!result && result !== '') {
|
1901
|
+
result = resolveForFallbackLanguageInstant(fallbackLanguageIndex + 1, translationId, interpolateParams, Interpolator);
|
1700
1902
|
}
|
1701
|
-
|
1702
|
-
|
1903
|
+
}
|
1904
|
+
return result;
|
1905
|
+
};
|
1703
1906
|
|
1704
|
-
|
1705
|
-
|
1706
|
-
|
1707
|
-
|
1708
|
-
|
1709
|
-
|
1710
|
-
|
1711
|
-
|
1712
|
-
|
1713
|
-
|
1714
|
-
|
1715
|
-
|
1907
|
+
/**
|
1908
|
+
* Translates with the usage of the fallback languages.
|
1909
|
+
*
|
1910
|
+
* @param translationId
|
1911
|
+
* @param interpolateParams
|
1912
|
+
* @param Interpolator
|
1913
|
+
* @param defaultTranslationText
|
1914
|
+
* @param sanitizeStrategy
|
1915
|
+
* @returns {Q.promise} Promise, that resolves to the translation.
|
1916
|
+
*/
|
1917
|
+
var fallbackTranslation = function (translationId, interpolateParams, Interpolator, defaultTranslationText, sanitizeStrategy) {
|
1918
|
+
// Start with the fallbackLanguage with index 0
|
1919
|
+
return resolveForFallbackLanguage((startFallbackIteration > 0 ? startFallbackIteration : fallbackIndex), translationId, interpolateParams, Interpolator, defaultTranslationText, sanitizeStrategy);
|
1920
|
+
};
|
1716
1921
|
|
1717
|
-
|
1718
|
-
|
1719
|
-
|
1720
|
-
|
1721
|
-
|
1722
|
-
|
1723
|
-
|
1724
|
-
|
1725
|
-
|
1726
|
-
|
1727
|
-
|
1728
|
-
|
1922
|
+
/**
|
1923
|
+
* Translates with the usage of the fallback languages.
|
1924
|
+
*
|
1925
|
+
* @param translationId
|
1926
|
+
* @param interpolateParams
|
1927
|
+
* @param Interpolator
|
1928
|
+
* @param sanitizeStrategy
|
1929
|
+
* @returns {String} translation
|
1930
|
+
*/
|
1931
|
+
var fallbackTranslationInstant = function (translationId, interpolateParams, Interpolator, sanitizeStrategy) {
|
1932
|
+
// Start with the fallbackLanguage with index 0
|
1933
|
+
return resolveForFallbackLanguageInstant((startFallbackIteration > 0 ? startFallbackIteration : fallbackIndex), translationId, interpolateParams, Interpolator, sanitizeStrategy);
|
1934
|
+
};
|
1729
1935
|
|
1730
|
-
|
1936
|
+
var determineTranslation = function (translationId, interpolateParams, interpolationId, defaultTranslationText, uses, sanitizeStrategy) {
|
1731
1937
|
|
1732
|
-
|
1938
|
+
var deferred = $q.defer();
|
1733
1939
|
|
1734
|
-
|
1735
|
-
|
1940
|
+
var table = uses ? $translationTable[uses] : $translationTable,
|
1941
|
+
Interpolator = (interpolationId) ? interpolatorHashMap[interpolationId] : defaultInterpolator;
|
1736
1942
|
|
1737
|
-
|
1738
|
-
|
1739
|
-
|
1943
|
+
// if the translation id exists, we can just interpolate it
|
1944
|
+
if (table && Object.prototype.hasOwnProperty.call(table, translationId) && table[translationId] !== null) {
|
1945
|
+
var translation = table[translationId];
|
1740
1946
|
|
1741
|
-
|
1742
|
-
|
1947
|
+
// If using link, rerun $translate with linked translationId and return it
|
1948
|
+
if (translation.substr(0, 2) === '@:') {
|
1743
1949
|
|
1744
|
-
|
1745
|
-
|
1950
|
+
$translate(translation.substr(2), interpolateParams, interpolationId, defaultTranslationText, uses)
|
1951
|
+
.then(deferred.resolve, deferred.reject);
|
1952
|
+
} else {
|
1953
|
+
//
|
1954
|
+
var resolvedTranslation = Interpolator.interpolate(translation, interpolateParams, 'service', sanitizeStrategy, translationId);
|
1955
|
+
resolvedTranslation = applyPostProcessing(translationId, translation, resolvedTranslation, interpolateParams, uses);
|
1956
|
+
deferred.resolve(resolvedTranslation);
|
1957
|
+
}
|
1958
|
+
} else {
|
1959
|
+
var missingTranslationHandlerTranslation;
|
1960
|
+
// for logging purposes only (as in $translateMissingTranslationHandlerLog), value is not returned to promise
|
1961
|
+
if ($missingTranslationHandlerFactory && !pendingLoader) {
|
1962
|
+
missingTranslationHandlerTranslation = translateByHandler(translationId, interpolateParams, defaultTranslationText);
|
1963
|
+
}
|
1964
|
+
|
1965
|
+
// since we couldn't translate the inital requested translation id,
|
1966
|
+
// we try it now with one or more fallback languages, if fallback language(s) is
|
1967
|
+
// configured.
|
1968
|
+
if (uses && $fallbackLanguage && $fallbackLanguage.length) {
|
1969
|
+
fallbackTranslation(translationId, interpolateParams, Interpolator, defaultTranslationText, sanitizeStrategy)
|
1970
|
+
.then(function (translation) {
|
1971
|
+
deferred.resolve(translation);
|
1972
|
+
}, function (_translationId) {
|
1973
|
+
deferred.reject(applyNotFoundIndicators(_translationId));
|
1974
|
+
});
|
1975
|
+
} else if ($missingTranslationHandlerFactory && !pendingLoader && missingTranslationHandlerTranslation) {
|
1976
|
+
// looks like the requested translation id doesn't exists.
|
1977
|
+
// Now, if there is a registered handler for missing translations and no
|
1978
|
+
// asyncLoader is pending, we execute the handler
|
1979
|
+
if (defaultTranslationText) {
|
1980
|
+
deferred.resolve(defaultTranslationText);
|
1746
1981
|
} else {
|
1747
|
-
deferred.resolve(
|
1982
|
+
deferred.resolve(missingTranslationHandlerTranslation);
|
1748
1983
|
}
|
1749
1984
|
} else {
|
1750
|
-
|
1751
|
-
|
1752
|
-
if ($missingTranslationHandlerFactory && !pendingLoader) {
|
1753
|
-
missingTranslationHandlerTranslation = translateByHandler(translationId, interpolateParams);
|
1754
|
-
}
|
1755
|
-
|
1756
|
-
// since we couldn't translate the inital requested translation id,
|
1757
|
-
// we try it now with one or more fallback languages, if fallback language(s) is
|
1758
|
-
// configured.
|
1759
|
-
if ($uses && $fallbackLanguage && $fallbackLanguage.length) {
|
1760
|
-
fallbackTranslation(translationId, interpolateParams, Interpolator, defaultTranslationText)
|
1761
|
-
.then(function (translation) {
|
1762
|
-
deferred.resolve(translation);
|
1763
|
-
}, function (_translationId) {
|
1764
|
-
deferred.reject(applyNotFoundIndicators(_translationId));
|
1765
|
-
});
|
1766
|
-
} else if ($missingTranslationHandlerFactory && !pendingLoader && missingTranslationHandlerTranslation) {
|
1767
|
-
// looks like the requested translation id doesn't exists.
|
1768
|
-
// Now, if there is a registered handler for missing translations and no
|
1769
|
-
// asyncLoader is pending, we execute the handler
|
1770
|
-
if (defaultTranslationText) {
|
1771
|
-
deferred.resolve(defaultTranslationText);
|
1772
|
-
} else {
|
1773
|
-
deferred.resolve(missingTranslationHandlerTranslation);
|
1774
|
-
}
|
1985
|
+
if (defaultTranslationText) {
|
1986
|
+
deferred.resolve(defaultTranslationText);
|
1775
1987
|
} else {
|
1776
|
-
|
1777
|
-
deferred.resolve(defaultTranslationText);
|
1778
|
-
} else {
|
1779
|
-
deferred.reject(applyNotFoundIndicators(translationId));
|
1780
|
-
}
|
1988
|
+
deferred.reject(applyNotFoundIndicators(translationId));
|
1781
1989
|
}
|
1782
1990
|
}
|
1783
|
-
|
1784
|
-
|
1991
|
+
}
|
1992
|
+
return deferred.promise;
|
1993
|
+
};
|
1785
1994
|
|
1786
|
-
|
1995
|
+
var determineTranslationInstant = function (translationId, interpolateParams, interpolationId, uses, sanitizeStrategy) {
|
1787
1996
|
|
1788
|
-
|
1789
|
-
|
1997
|
+
var result, table = uses ? $translationTable[uses] : $translationTable,
|
1998
|
+
Interpolator = defaultInterpolator;
|
1790
1999
|
|
1791
|
-
|
1792
|
-
|
1793
|
-
|
1794
|
-
|
2000
|
+
// if the interpolation id exists use custom interpolator
|
2001
|
+
if (interpolatorHashMap && Object.prototype.hasOwnProperty.call(interpolatorHashMap, interpolationId)) {
|
2002
|
+
Interpolator = interpolatorHashMap[interpolationId];
|
2003
|
+
}
|
1795
2004
|
|
1796
|
-
|
1797
|
-
|
1798
|
-
|
2005
|
+
// if the translation id exists, we can just interpolate it
|
2006
|
+
if (table && Object.prototype.hasOwnProperty.call(table, translationId) && table[translationId] !== null) {
|
2007
|
+
var translation = table[translationId];
|
1799
2008
|
|
1800
|
-
|
1801
|
-
|
1802
|
-
|
1803
|
-
} else {
|
1804
|
-
result = Interpolator.interpolate(translation, interpolateParams);
|
1805
|
-
}
|
2009
|
+
// If using link, rerun $translate with linked translationId and return it
|
2010
|
+
if (translation.substr(0, 2) === '@:') {
|
2011
|
+
result = determineTranslationInstant(translation.substr(2), interpolateParams, interpolationId, uses, sanitizeStrategy);
|
1806
2012
|
} else {
|
1807
|
-
|
1808
|
-
|
1809
|
-
|
1810
|
-
|
1811
|
-
|
2013
|
+
result = Interpolator.interpolate(translation, interpolateParams, 'filter', sanitizeStrategy, translationId);
|
2014
|
+
result = applyPostProcessing(translationId, translation, result, interpolateParams, uses, sanitizeStrategy);
|
2015
|
+
}
|
2016
|
+
} else {
|
2017
|
+
var missingTranslationHandlerTranslation;
|
2018
|
+
// for logging purposes only (as in $translateMissingTranslationHandlerLog), value is not returned to promise
|
2019
|
+
if ($missingTranslationHandlerFactory && !pendingLoader) {
|
2020
|
+
missingTranslationHandlerTranslation = translateByHandler(translationId, interpolateParams, sanitizeStrategy);
|
2021
|
+
}
|
1812
2022
|
|
1813
|
-
|
1814
|
-
|
1815
|
-
|
1816
|
-
|
1817
|
-
|
1818
|
-
|
1819
|
-
|
1820
|
-
|
1821
|
-
|
1822
|
-
|
1823
|
-
|
1824
|
-
|
1825
|
-
|
1826
|
-
}
|
2023
|
+
// since we couldn't translate the inital requested translation id,
|
2024
|
+
// we try it now with one or more fallback languages, if fallback language(s) is
|
2025
|
+
// configured.
|
2026
|
+
if (uses && $fallbackLanguage && $fallbackLanguage.length) {
|
2027
|
+
fallbackIndex = 0;
|
2028
|
+
result = fallbackTranslationInstant(translationId, interpolateParams, Interpolator, sanitizeStrategy);
|
2029
|
+
} else if ($missingTranslationHandlerFactory && !pendingLoader && missingTranslationHandlerTranslation) {
|
2030
|
+
// looks like the requested translation id doesn't exists.
|
2031
|
+
// Now, if there is a registered handler for missing translations and no
|
2032
|
+
// asyncLoader is pending, we execute the handler
|
2033
|
+
result = missingTranslationHandlerTranslation;
|
2034
|
+
} else {
|
2035
|
+
result = applyNotFoundIndicators(translationId);
|
1827
2036
|
}
|
2037
|
+
}
|
1828
2038
|
|
1829
|
-
|
1830
|
-
|
2039
|
+
return result;
|
2040
|
+
};
|
1831
2041
|
|
1832
|
-
|
1833
|
-
|
1834
|
-
|
1835
|
-
|
1836
|
-
|
1837
|
-
|
2042
|
+
var clearNextLangAndPromise = function (key) {
|
2043
|
+
if ($nextLang === key) {
|
2044
|
+
$nextLang = undefined;
|
2045
|
+
}
|
2046
|
+
langPromises[key] = undefined;
|
2047
|
+
};
|
1838
2048
|
|
1839
|
-
|
1840
|
-
|
1841
|
-
|
1842
|
-
|
1843
|
-
|
1844
|
-
|
1845
|
-
|
1846
|
-
|
1847
|
-
* @param {string} langKey language String or Array to be used as preferredLanguage (changing at runtime)
|
1848
|
-
*
|
1849
|
-
* @return {string} preferred language key
|
1850
|
-
*/
|
1851
|
-
$translate.preferredLanguage = function (langKey) {
|
1852
|
-
if(langKey) {
|
1853
|
-
setupPreferredLanguage(langKey);
|
2049
|
+
var applyPostProcessing = function (translationId, translation, resolvedTranslation, interpolateParams, uses, sanitizeStrategy) {
|
2050
|
+
var fn = postProcessFn;
|
2051
|
+
|
2052
|
+
if (fn) {
|
2053
|
+
|
2054
|
+
if (typeof(fn) === 'string') {
|
2055
|
+
// getting on-demand instance
|
2056
|
+
fn = $injector.get(fn);
|
1854
2057
|
}
|
1855
|
-
|
1856
|
-
|
2058
|
+
if (fn) {
|
2059
|
+
return fn(translationId, translation, resolvedTranslation, interpolateParams, uses, sanitizeStrategy);
|
2060
|
+
}
|
2061
|
+
}
|
1857
2062
|
|
1858
|
-
|
1859
|
-
|
1860
|
-
* @name pascalprecht.translate.$translate#cloakClassName
|
1861
|
-
* @methodOf pascalprecht.translate.$translate
|
1862
|
-
*
|
1863
|
-
* @description
|
1864
|
-
* Returns the configured class name for `translate-cloak` directive.
|
1865
|
-
*
|
1866
|
-
* @return {string} cloakClassName
|
1867
|
-
*/
|
1868
|
-
$translate.cloakClassName = function () {
|
1869
|
-
return $cloakClassName;
|
1870
|
-
};
|
2063
|
+
return resolvedTranslation;
|
2064
|
+
};
|
1871
2065
|
|
1872
|
-
|
1873
|
-
|
1874
|
-
|
1875
|
-
|
1876
|
-
|
1877
|
-
|
1878
|
-
|
1879
|
-
|
1880
|
-
|
1881
|
-
|
1882
|
-
|
1883
|
-
|
1884
|
-
|
1885
|
-
|
1886
|
-
|
1887
|
-
|
1888
|
-
|
1889
|
-
|
1890
|
-
|
1891
|
-
|
1892
|
-
|
1893
|
-
|
1894
|
-
|
1895
|
-
|
2066
|
+
var loadTranslationsIfMissing = function (key) {
|
2067
|
+
if (!$translationTable[key] && $loaderFactory && !langPromises[key]) {
|
2068
|
+
langPromises[key] = loadAsync(key).then(function (translation) {
|
2069
|
+
translations(translation.key, translation.table);
|
2070
|
+
return translation;
|
2071
|
+
});
|
2072
|
+
}
|
2073
|
+
};
|
2074
|
+
|
2075
|
+
/**
|
2076
|
+
* @ngdoc function
|
2077
|
+
* @name pascalprecht.translate.$translate#preferredLanguage
|
2078
|
+
* @methodOf pascalprecht.translate.$translate
|
2079
|
+
*
|
2080
|
+
* @description
|
2081
|
+
* Returns the language key for the preferred language.
|
2082
|
+
*
|
2083
|
+
* @param {string} langKey language String or Array to be used as preferredLanguage (changing at runtime)
|
2084
|
+
*
|
2085
|
+
* @return {string} preferred language key
|
2086
|
+
*/
|
2087
|
+
$translate.preferredLanguage = function (langKey) {
|
2088
|
+
if (langKey) {
|
2089
|
+
setupPreferredLanguage(langKey);
|
2090
|
+
}
|
2091
|
+
return $preferredLanguage;
|
2092
|
+
};
|
2093
|
+
|
2094
|
+
/**
|
2095
|
+
* @ngdoc function
|
2096
|
+
* @name pascalprecht.translate.$translate#cloakClassName
|
2097
|
+
* @methodOf pascalprecht.translate.$translate
|
2098
|
+
*
|
2099
|
+
* @description
|
2100
|
+
* Returns the configured class name for `translate-cloak` directive.
|
2101
|
+
*
|
2102
|
+
* @return {string} cloakClassName
|
2103
|
+
*/
|
2104
|
+
$translate.cloakClassName = function () {
|
2105
|
+
return $cloakClassName;
|
2106
|
+
};
|
2107
|
+
|
2108
|
+
/**
|
2109
|
+
* @ngdoc function
|
2110
|
+
* @name pascalprecht.translate.$translate#nestedObjectDelimeter
|
2111
|
+
* @methodOf pascalprecht.translate.$translate
|
2112
|
+
*
|
2113
|
+
* @description
|
2114
|
+
* Returns the configured delimiter for nested namespaces.
|
2115
|
+
*
|
2116
|
+
* @return {string} nestedObjectDelimeter
|
2117
|
+
*/
|
2118
|
+
$translate.nestedObjectDelimeter = function () {
|
2119
|
+
return $nestedObjectDelimeter;
|
2120
|
+
};
|
2121
|
+
|
2122
|
+
/**
|
2123
|
+
* @ngdoc function
|
2124
|
+
* @name pascalprecht.translate.$translate#fallbackLanguage
|
2125
|
+
* @methodOf pascalprecht.translate.$translate
|
2126
|
+
*
|
2127
|
+
* @description
|
2128
|
+
* Returns the language key for the fallback languages or sets a new fallback stack.
|
2129
|
+
*
|
2130
|
+
* @param {string=} langKey language String or Array of fallback languages to be used (to change stack at runtime)
|
2131
|
+
*
|
2132
|
+
* @return {string||array} fallback language key
|
2133
|
+
*/
|
2134
|
+
$translate.fallbackLanguage = function (langKey) {
|
2135
|
+
if (langKey !== undefined && langKey !== null) {
|
2136
|
+
fallbackStack(langKey);
|
2137
|
+
|
2138
|
+
// as we might have an async loader initiated and a new translation language might have been defined
|
2139
|
+
// we need to add the promise to the stack also. So - iterate.
|
2140
|
+
if ($loaderFactory) {
|
2141
|
+
if ($fallbackLanguage && $fallbackLanguage.length) {
|
2142
|
+
for (var i = 0, len = $fallbackLanguage.length; i < len; i++) {
|
2143
|
+
if (!langPromises[$fallbackLanguage[i]]) {
|
2144
|
+
langPromises[$fallbackLanguage[i]] = loadAsync($fallbackLanguage[i]);
|
1896
2145
|
}
|
1897
2146
|
}
|
1898
2147
|
}
|
1899
|
-
$translate.use($translate.use());
|
1900
|
-
}
|
1901
|
-
if ($fallbackWasString) {
|
1902
|
-
return $fallbackLanguage[0];
|
1903
|
-
} else {
|
1904
|
-
return $fallbackLanguage;
|
1905
2148
|
}
|
2149
|
+
$translate.use($translate.use());
|
2150
|
+
}
|
2151
|
+
if ($fallbackWasString) {
|
2152
|
+
return $fallbackLanguage[0];
|
2153
|
+
} else {
|
2154
|
+
return $fallbackLanguage;
|
2155
|
+
}
|
1906
2156
|
|
1907
|
-
|
2157
|
+
};
|
1908
2158
|
|
1909
|
-
|
1910
|
-
|
1911
|
-
|
1912
|
-
|
1913
|
-
|
1914
|
-
|
1915
|
-
|
1916
|
-
|
1917
|
-
|
1918
|
-
|
1919
|
-
|
1920
|
-
|
1921
|
-
|
1922
|
-
|
1923
|
-
|
1924
|
-
|
1925
|
-
|
1926
|
-
|
1927
|
-
|
1928
|
-
|
1929
|
-
}
|
2159
|
+
/**
|
2160
|
+
* @ngdoc function
|
2161
|
+
* @name pascalprecht.translate.$translate#useFallbackLanguage
|
2162
|
+
* @methodOf pascalprecht.translate.$translate
|
2163
|
+
*
|
2164
|
+
* @description
|
2165
|
+
* Sets the first key of the fallback language stack to be used for translation.
|
2166
|
+
* Therefore all languages in the fallback array BEFORE this key will be skipped!
|
2167
|
+
*
|
2168
|
+
* @param {string=} langKey Contains the langKey the iteration shall start with. Set to false if you want to
|
2169
|
+
* get back to the whole stack
|
2170
|
+
*/
|
2171
|
+
$translate.useFallbackLanguage = function (langKey) {
|
2172
|
+
if (langKey !== undefined && langKey !== null) {
|
2173
|
+
if (!langKey) {
|
2174
|
+
startFallbackIteration = 0;
|
2175
|
+
} else {
|
2176
|
+
var langKeyPosition = indexOf($fallbackLanguage, langKey);
|
2177
|
+
if (langKeyPosition > -1) {
|
2178
|
+
startFallbackIteration = langKeyPosition;
|
1930
2179
|
}
|
1931
|
-
|
1932
2180
|
}
|
1933
2181
|
|
1934
|
-
}
|
2182
|
+
}
|
1935
2183
|
|
1936
|
-
|
1937
|
-
* @ngdoc function
|
1938
|
-
* @name pascalprecht.translate.$translate#proposedLanguage
|
1939
|
-
* @methodOf pascalprecht.translate.$translate
|
1940
|
-
*
|
1941
|
-
* @description
|
1942
|
-
* Returns the language key of language that is currently loaded asynchronously.
|
1943
|
-
*
|
1944
|
-
* @return {string} language key
|
1945
|
-
*/
|
1946
|
-
$translate.proposedLanguage = function () {
|
1947
|
-
return $nextLang;
|
1948
|
-
};
|
2184
|
+
};
|
1949
2185
|
|
1950
|
-
|
1951
|
-
|
1952
|
-
|
1953
|
-
|
1954
|
-
|
1955
|
-
|
1956
|
-
|
1957
|
-
|
1958
|
-
|
1959
|
-
|
1960
|
-
|
1961
|
-
|
1962
|
-
|
2186
|
+
/**
|
2187
|
+
* @ngdoc function
|
2188
|
+
* @name pascalprecht.translate.$translate#proposedLanguage
|
2189
|
+
* @methodOf pascalprecht.translate.$translate
|
2190
|
+
*
|
2191
|
+
* @description
|
2192
|
+
* Returns the language key of language that is currently loaded asynchronously.
|
2193
|
+
*
|
2194
|
+
* @return {string} language key
|
2195
|
+
*/
|
2196
|
+
$translate.proposedLanguage = function () {
|
2197
|
+
return $nextLang;
|
2198
|
+
};
|
1963
2199
|
|
1964
|
-
|
1965
|
-
|
1966
|
-
|
1967
|
-
|
1968
|
-
|
1969
|
-
|
1970
|
-
|
1971
|
-
|
1972
|
-
|
1973
|
-
|
1974
|
-
|
1975
|
-
|
1976
|
-
|
1977
|
-
|
1978
|
-
|
1979
|
-
|
2200
|
+
/**
|
2201
|
+
* @ngdoc function
|
2202
|
+
* @name pascalprecht.translate.$translate#storage
|
2203
|
+
* @methodOf pascalprecht.translate.$translate
|
2204
|
+
*
|
2205
|
+
* @description
|
2206
|
+
* Returns registered storage.
|
2207
|
+
*
|
2208
|
+
* @return {object} Storage
|
2209
|
+
*/
|
2210
|
+
$translate.storage = function () {
|
2211
|
+
return Storage;
|
2212
|
+
};
|
2213
|
+
|
2214
|
+
/**
|
2215
|
+
* @ngdoc function
|
2216
|
+
* @name pascalprecht.translate.$translate#negotiateLocale
|
2217
|
+
* @methodOf pascalprecht.translate.$translate
|
2218
|
+
*
|
2219
|
+
* @description
|
2220
|
+
* Returns a language key based on available languages and language aliases. If a
|
2221
|
+
* language key cannot be resolved, returns undefined.
|
2222
|
+
*
|
2223
|
+
* If no or a falsy key is given, returns undefined.
|
2224
|
+
*
|
2225
|
+
* @param {string} [key] Language key
|
2226
|
+
* @return {string|undefined} Language key or undefined if no language key is found.
|
2227
|
+
*/
|
2228
|
+
$translate.negotiateLocale = negotiateLocale;
|
2229
|
+
|
2230
|
+
/**
|
2231
|
+
* @ngdoc function
|
2232
|
+
* @name pascalprecht.translate.$translate#use
|
2233
|
+
* @methodOf pascalprecht.translate.$translate
|
2234
|
+
*
|
2235
|
+
* @description
|
2236
|
+
* Tells angular-translate which language to use by given language key. This method is
|
2237
|
+
* used to change language at runtime. It also takes care of storing the language
|
2238
|
+
* key in a configured store to let your app remember the choosed language.
|
2239
|
+
*
|
2240
|
+
* When trying to 'use' a language which isn't available it tries to load it
|
2241
|
+
* asynchronously with registered loaders.
|
2242
|
+
*
|
2243
|
+
* Returns promise object with loaded language file data or string of the currently used language.
|
2244
|
+
*
|
2245
|
+
* If no or a falsy key is given it returns the currently used language key.
|
2246
|
+
* The returned string will be ```undefined``` if setting up $translate hasn't finished.
|
2247
|
+
* @example
|
2248
|
+
* $translate.use("en_US").then(function(data){
|
1980
2249
|
* $scope.text = $translate("HELLO");
|
1981
2250
|
* });
|
1982
|
-
|
1983
|
-
|
1984
|
-
|
1985
|
-
|
1986
|
-
|
1987
|
-
|
1988
|
-
|
1989
|
-
|
1990
|
-
|
1991
|
-
var deferred = $q.defer();
|
2251
|
+
*
|
2252
|
+
* @param {string} [key] Language key
|
2253
|
+
* @return {object|string} Promise with loaded language data or the language key if a falsy param was given.
|
2254
|
+
*/
|
2255
|
+
$translate.use = function (key) {
|
2256
|
+
if (!key) {
|
2257
|
+
return $uses;
|
2258
|
+
}
|
1992
2259
|
|
1993
|
-
|
2260
|
+
var deferred = $q.defer();
|
2261
|
+
deferred.promise.then(null, angular.noop); // AJS "Possibly unhandled rejection"
|
1994
2262
|
|
1995
|
-
|
1996
|
-
var aliasedKey = negotiateLocale(key);
|
1997
|
-
if (aliasedKey) {
|
1998
|
-
key = aliasedKey;
|
1999
|
-
}
|
2263
|
+
$rootScope.$emit('$translateChangeStart', {language : key});
|
2000
2264
|
|
2001
|
-
|
2002
|
-
|
2003
|
-
|
2004
|
-
|
2005
|
-
|
2006
|
-
|
2007
|
-
deferred.resolve(translation.key);
|
2008
|
-
useLanguage(translation.key);
|
2009
|
-
return translation;
|
2010
|
-
}, function (key) {
|
2011
|
-
$rootScope.$emit('$translateChangeError', {language: key});
|
2012
|
-
deferred.reject(key);
|
2013
|
-
$rootScope.$emit('$translateChangeEnd', {language: key});
|
2014
|
-
return $q.reject(key);
|
2015
|
-
});
|
2016
|
-
langPromises[key]['finally'](function () {
|
2017
|
-
clearNextLangAndPromise(key);
|
2018
|
-
});
|
2019
|
-
} else if ($nextLang === key && langPromises[key]) {
|
2020
|
-
// we are already loading this asynchronously
|
2021
|
-
// resolve our new deferred when the old langPromise is resolved
|
2022
|
-
langPromises[key].then(function (translation) {
|
2023
|
-
deferred.resolve(translation.key);
|
2024
|
-
return translation;
|
2025
|
-
}, function (key) {
|
2026
|
-
deferred.reject(key);
|
2027
|
-
return $q.reject(key);
|
2028
|
-
});
|
2029
|
-
} else {
|
2030
|
-
deferred.resolve(key);
|
2031
|
-
useLanguage(key);
|
2032
|
-
}
|
2265
|
+
// Try to get the aliased language key
|
2266
|
+
var aliasedKey = negotiateLocale(key);
|
2267
|
+
// Ensure only registered language keys will be loaded
|
2268
|
+
if ($availableLanguageKeys.length > 0 && !aliasedKey) {
|
2269
|
+
return $q.reject(key);
|
2270
|
+
}
|
2033
2271
|
|
2034
|
-
|
2035
|
-
|
2272
|
+
if (aliasedKey) {
|
2273
|
+
key = aliasedKey;
|
2274
|
+
}
|
2036
2275
|
|
2037
|
-
|
2038
|
-
|
2039
|
-
|
2040
|
-
|
2041
|
-
|
2042
|
-
|
2043
|
-
|
2044
|
-
|
2045
|
-
|
2046
|
-
|
2047
|
-
|
2048
|
-
|
2049
|
-
|
2276
|
+
// if there isn't a translation table for the language we've requested,
|
2277
|
+
// we load it asynchronously
|
2278
|
+
$nextLang = key;
|
2279
|
+
if (($forceAsyncReloadEnabled || !$translationTable[key]) && $loaderFactory && !langPromises[key]) {
|
2280
|
+
langPromises[key] = loadAsync(key).then(function (translation) {
|
2281
|
+
translations(translation.key, translation.table);
|
2282
|
+
deferred.resolve(translation.key);
|
2283
|
+
if ($nextLang === key) {
|
2284
|
+
useLanguage(translation.key);
|
2285
|
+
}
|
2286
|
+
return translation;
|
2287
|
+
}, function (key) {
|
2288
|
+
$rootScope.$emit('$translateChangeError', {language : key});
|
2289
|
+
deferred.reject(key);
|
2290
|
+
$rootScope.$emit('$translateChangeEnd', {language : key});
|
2291
|
+
return $q.reject(key);
|
2292
|
+
});
|
2293
|
+
langPromises[key]['finally'](function () {
|
2294
|
+
clearNextLangAndPromise(key);
|
2295
|
+
})['catch'](angular.noop); // we don't care about errors (clearing)
|
2296
|
+
} else if (langPromises[key]) {
|
2297
|
+
// we are already loading this asynchronously
|
2298
|
+
// resolve our new deferred when the old langPromise is resolved
|
2299
|
+
langPromises[key].then(function (translation) {
|
2300
|
+
if ($nextLang === translation.key) {
|
2301
|
+
useLanguage(translation.key);
|
2302
|
+
}
|
2303
|
+
deferred.resolve(translation.key);
|
2304
|
+
return translation;
|
2305
|
+
}, function (key) {
|
2306
|
+
// find first available fallback language if that request has failed
|
2307
|
+
if (!$uses && $fallbackLanguage && $fallbackLanguage.length > 0 && $fallbackLanguage[0] !== key) {
|
2308
|
+
return $translate.use($fallbackLanguage[0]).then(deferred.resolve, deferred.reject);
|
2309
|
+
} else {
|
2310
|
+
return deferred.reject(key);
|
2311
|
+
}
|
2312
|
+
});
|
2313
|
+
} else {
|
2314
|
+
deferred.resolve(key);
|
2315
|
+
useLanguage(key);
|
2316
|
+
}
|
2050
2317
|
|
2051
|
-
|
2052
|
-
|
2053
|
-
* @name pascalprecht.translate.$translate#isPostCompilingEnabled
|
2054
|
-
* @methodOf pascalprecht.translate.$translate
|
2055
|
-
*
|
2056
|
-
* @description
|
2057
|
-
* Returns whether post compiling is enabled or not
|
2058
|
-
*
|
2059
|
-
* @return {bool} storage key
|
2060
|
-
*/
|
2061
|
-
$translate.isPostCompilingEnabled = function () {
|
2062
|
-
return $postCompilingEnabled;
|
2063
|
-
};
|
2318
|
+
return deferred.promise;
|
2319
|
+
};
|
2064
2320
|
|
2065
|
-
|
2066
|
-
|
2067
|
-
|
2068
|
-
|
2069
|
-
|
2070
|
-
|
2071
|
-
|
2072
|
-
|
2073
|
-
|
2074
|
-
|
2075
|
-
|
2076
|
-
|
2077
|
-
|
2321
|
+
/**
|
2322
|
+
* @ngdoc function
|
2323
|
+
* @name pascalprecht.translate.$translate#resolveClientLocale
|
2324
|
+
* @methodOf pascalprecht.translate.$translate
|
2325
|
+
*
|
2326
|
+
* @description
|
2327
|
+
* This returns the current browser/client's language key. The result is processed with the configured uniform tag resolver.
|
2328
|
+
*
|
2329
|
+
* @returns {string} the current client/browser language key
|
2330
|
+
*/
|
2331
|
+
$translate.resolveClientLocale = function () {
|
2332
|
+
return getLocale();
|
2333
|
+
};
|
2078
2334
|
|
2079
|
-
|
2080
|
-
|
2081
|
-
|
2082
|
-
|
2083
|
-
|
2084
|
-
|
2085
|
-
|
2086
|
-
|
2087
|
-
|
2088
|
-
|
2089
|
-
|
2090
|
-
|
2091
|
-
|
2092
|
-
*
|
2093
|
-
* If the module is able to refresh translation tables refresh() method will broadcast
|
2094
|
-
* $translateRefreshStart and $translateRefreshEnd events.
|
2095
|
-
*
|
2096
|
-
* @example
|
2097
|
-
* // this will drop all currently existent translation tables and reload those which are
|
2098
|
-
* // currently in use
|
2099
|
-
* $translate.refresh();
|
2100
|
-
* // this will refresh a translation table for the en_US language
|
2101
|
-
* $translate.refresh('en_US');
|
2102
|
-
*
|
2103
|
-
* @param {string} langKey A language key of the table, which has to be refreshed
|
2104
|
-
*
|
2105
|
-
* @return {promise} Promise, which will be resolved in case a translation tables refreshing
|
2106
|
-
* process is finished successfully, and reject if not.
|
2107
|
-
*/
|
2108
|
-
$translate.refresh = function (langKey) {
|
2109
|
-
if (!$loaderFactory) {
|
2110
|
-
throw new Error('Couldn\'t refresh translation table, no loader registered!');
|
2111
|
-
}
|
2335
|
+
/**
|
2336
|
+
* @ngdoc function
|
2337
|
+
* @name pascalprecht.translate.$translate#storageKey
|
2338
|
+
* @methodOf pascalprecht.translate.$translate
|
2339
|
+
*
|
2340
|
+
* @description
|
2341
|
+
* Returns the key for the storage.
|
2342
|
+
*
|
2343
|
+
* @return {string} storage key
|
2344
|
+
*/
|
2345
|
+
$translate.storageKey = function () {
|
2346
|
+
return storageKey();
|
2347
|
+
};
|
2112
2348
|
|
2113
|
-
|
2349
|
+
/**
|
2350
|
+
* @ngdoc function
|
2351
|
+
* @name pascalprecht.translate.$translate#isPostCompilingEnabled
|
2352
|
+
* @methodOf pascalprecht.translate.$translate
|
2353
|
+
*
|
2354
|
+
* @description
|
2355
|
+
* Returns whether post compiling is enabled or not
|
2356
|
+
*
|
2357
|
+
* @return {bool} storage key
|
2358
|
+
*/
|
2359
|
+
$translate.isPostCompilingEnabled = function () {
|
2360
|
+
return $postCompilingEnabled;
|
2361
|
+
};
|
2114
2362
|
|
2115
|
-
|
2116
|
-
|
2117
|
-
|
2118
|
-
|
2363
|
+
/**
|
2364
|
+
* @ngdoc function
|
2365
|
+
* @name pascalprecht.translate.$translate#isForceAsyncReloadEnabled
|
2366
|
+
* @methodOf pascalprecht.translate.$translate
|
2367
|
+
*
|
2368
|
+
* @description
|
2369
|
+
* Returns whether force async reload is enabled or not
|
2370
|
+
*
|
2371
|
+
* @return {boolean} forceAsyncReload value
|
2372
|
+
*/
|
2373
|
+
$translate.isForceAsyncReloadEnabled = function () {
|
2374
|
+
return $forceAsyncReloadEnabled;
|
2375
|
+
};
|
2119
2376
|
|
2120
|
-
|
2121
|
-
|
2122
|
-
|
2123
|
-
|
2377
|
+
/**
|
2378
|
+
* @ngdoc function
|
2379
|
+
* @name pascalprecht.translate.$translate#isKeepContent
|
2380
|
+
* @methodOf pascalprecht.translate.$translate
|
2381
|
+
*
|
2382
|
+
* @description
|
2383
|
+
* Returns whether keepContent or not
|
2384
|
+
*
|
2385
|
+
* @return {boolean} keepContent value
|
2386
|
+
*/
|
2387
|
+
$translate.isKeepContent = function () {
|
2388
|
+
return $keepContent;
|
2389
|
+
};
|
2124
2390
|
|
2125
|
-
|
2391
|
+
/**
|
2392
|
+
* @ngdoc function
|
2393
|
+
* @name pascalprecht.translate.$translate#refresh
|
2394
|
+
* @methodOf pascalprecht.translate.$translate
|
2395
|
+
*
|
2396
|
+
* @description
|
2397
|
+
* Refreshes a translation table pointed by the given langKey. If langKey is not specified,
|
2398
|
+
* the module will drop all existent translation tables and load new version of those which
|
2399
|
+
* are currently in use.
|
2400
|
+
*
|
2401
|
+
* Refresh means that the module will drop target translation table and try to load it again.
|
2402
|
+
*
|
2403
|
+
* In case there are no loaders registered the refresh() method will throw an Error.
|
2404
|
+
*
|
2405
|
+
* If the module is able to refresh translation tables refresh() method will broadcast
|
2406
|
+
* $translateRefreshStart and $translateRefreshEnd events.
|
2407
|
+
*
|
2408
|
+
* @example
|
2409
|
+
* // this will drop all currently existent translation tables and reload those which are
|
2410
|
+
* // currently in use
|
2411
|
+
* $translate.refresh();
|
2412
|
+
* // this will refresh a translation table for the en_US language
|
2413
|
+
* $translate.refresh('en_US');
|
2414
|
+
*
|
2415
|
+
* @param {string} langKey A language key of the table, which has to be refreshed
|
2416
|
+
*
|
2417
|
+
* @return {promise} Promise, which will be resolved in case a translation tables refreshing
|
2418
|
+
* process is finished successfully, and reject if not.
|
2419
|
+
*/
|
2420
|
+
$translate.refresh = function (langKey) {
|
2421
|
+
if (!$loaderFactory) {
|
2422
|
+
throw new Error('Couldn\'t refresh translation table, no loader registered!');
|
2423
|
+
}
|
2126
2424
|
|
2127
|
-
|
2128
|
-
|
2129
|
-
|
2425
|
+
$rootScope.$emit('$translateRefreshStart', {language : langKey});
|
2426
|
+
|
2427
|
+
var deferred = $q.defer(), updatedLanguages = {};
|
2428
|
+
|
2429
|
+
//private helper
|
2430
|
+
function loadNewData(languageKey) {
|
2431
|
+
var promise = loadAsync(languageKey);
|
2432
|
+
//update the load promise cache for this language
|
2433
|
+
langPromises[languageKey] = promise;
|
2434
|
+
//register a data handler for the promise
|
2435
|
+
promise.then(function (data) {
|
2436
|
+
//clear the cache for this language
|
2437
|
+
$translationTable[languageKey] = {};
|
2438
|
+
//add the new data for this language
|
2439
|
+
translations(languageKey, data.table);
|
2440
|
+
//track that we updated this language
|
2441
|
+
updatedLanguages[languageKey] = true;
|
2442
|
+
},
|
2443
|
+
//handle rejection to appease the $q validation
|
2444
|
+
angular.noop);
|
2445
|
+
return promise;
|
2446
|
+
}
|
2130
2447
|
|
2131
|
-
|
2132
|
-
|
2133
|
-
|
2134
|
-
|
2135
|
-
|
2448
|
+
//set up post-processing
|
2449
|
+
deferred.promise.then(
|
2450
|
+
function () {
|
2451
|
+
for (var key in $translationTable) {
|
2452
|
+
if ($translationTable.hasOwnProperty(key)) {
|
2453
|
+
//delete cache entries that were not updated
|
2454
|
+
if (!(key in updatedLanguages)) {
|
2455
|
+
delete $translationTable[key];
|
2456
|
+
}
|
2136
2457
|
}
|
2137
2458
|
}
|
2138
|
-
|
2139
|
-
|
2140
|
-
if ($uses && !loadingKeys[$uses]) {
|
2141
|
-
tables.push(loadAsync($uses));
|
2459
|
+
if ($uses) {
|
2460
|
+
useLanguage($uses);
|
2142
2461
|
}
|
2462
|
+
},
|
2463
|
+
//handle rejection to appease the $q validation
|
2464
|
+
angular.noop
|
2465
|
+
)['finally'](
|
2466
|
+
function () {
|
2467
|
+
$rootScope.$emit('$translateRefreshEnd', {language : langKey});
|
2468
|
+
}
|
2469
|
+
);
|
2143
2470
|
|
2144
|
-
|
2145
|
-
|
2146
|
-
|
2147
|
-
|
2148
|
-
|
2149
|
-
|
2150
|
-
|
2151
|
-
}
|
2152
|
-
resolve();
|
2153
|
-
};
|
2154
|
-
allTranslationsLoaded.displayName = 'refreshPostProcessor';
|
2471
|
+
if (!langKey) {
|
2472
|
+
// if there's no language key specified we refresh ALL THE THINGS!
|
2473
|
+
var languagesToReload = $fallbackLanguage && $fallbackLanguage.slice() || [];
|
2474
|
+
if ($uses && languagesToReload.indexOf($uses) === -1) {
|
2475
|
+
languagesToReload.push($uses);
|
2476
|
+
}
|
2477
|
+
$q.all(languagesToReload.map(loadNewData)).then(deferred.resolve, deferred.reject);
|
2155
2478
|
|
2156
|
-
|
2479
|
+
} else if ($translationTable[langKey]) {
|
2480
|
+
//just refresh the specified language cache
|
2481
|
+
loadNewData(langKey).then(deferred.resolve, deferred.reject);
|
2157
2482
|
|
2158
|
-
|
2483
|
+
} else {
|
2484
|
+
deferred.reject();
|
2485
|
+
}
|
2159
2486
|
|
2160
|
-
|
2161
|
-
|
2162
|
-
if (langKey === $uses) {
|
2163
|
-
useLanguage($uses);
|
2164
|
-
}
|
2165
|
-
resolve();
|
2166
|
-
};
|
2167
|
-
oneTranslationsLoaded.displayName = 'refreshPostProcessor';
|
2487
|
+
return deferred.promise;
|
2488
|
+
};
|
2168
2489
|
|
2169
|
-
|
2490
|
+
/**
|
2491
|
+
* @ngdoc function
|
2492
|
+
* @name pascalprecht.translate.$translate#instant
|
2493
|
+
* @methodOf pascalprecht.translate.$translate
|
2494
|
+
*
|
2495
|
+
* @description
|
2496
|
+
* Returns a translation instantly from the internal state of loaded translation. All rules
|
2497
|
+
* regarding the current language, the preferred language of even fallback languages will be
|
2498
|
+
* used except any promise handling. If a language was not found, an asynchronous loading
|
2499
|
+
* will be invoked in the background.
|
2500
|
+
*
|
2501
|
+
* @param {string|array} translationId A token which represents a translation id
|
2502
|
+
* This can be optionally an array of translation ids which
|
2503
|
+
* results that the function's promise returns an object where
|
2504
|
+
* each key is the translation id and the value the translation.
|
2505
|
+
* @param {object} interpolateParams Params
|
2506
|
+
* @param {string} interpolationId The id of the interpolation to use
|
2507
|
+
* @param {string} forceLanguage A language to be used instead of the current language
|
2508
|
+
* @param {string} sanitizeStrategy force sanitize strategy for this call instead of using the configured one
|
2509
|
+
*
|
2510
|
+
* @return {string|object} translation
|
2511
|
+
*/
|
2512
|
+
$translate.instant = function (translationId, interpolateParams, interpolationId, forceLanguage, sanitizeStrategy) {
|
2513
|
+
|
2514
|
+
// we don't want to re-negotiate $uses
|
2515
|
+
var uses = (forceLanguage && forceLanguage !== $uses) ? // we don't want to re-negotiate $uses
|
2516
|
+
(negotiateLocale(forceLanguage) || forceLanguage) : $uses;
|
2517
|
+
|
2518
|
+
// Detect undefined and null values to shorten the execution and prevent exceptions
|
2519
|
+
if (translationId === null || angular.isUndefined(translationId)) {
|
2520
|
+
return translationId;
|
2521
|
+
}
|
2170
2522
|
|
2171
|
-
|
2172
|
-
|
2523
|
+
// Check forceLanguage is present
|
2524
|
+
if (forceLanguage) {
|
2525
|
+
loadTranslationsIfMissing(forceLanguage);
|
2526
|
+
}
|
2527
|
+
|
2528
|
+
// Duck detection: If the first argument is an array, a bunch of translations was requested.
|
2529
|
+
// The result is an object.
|
2530
|
+
if (angular.isArray(translationId)) {
|
2531
|
+
var results = {};
|
2532
|
+
for (var i = 0, c = translationId.length; i < c; i++) {
|
2533
|
+
results[translationId[i]] = $translate.instant(translationId[i], interpolateParams, interpolationId, forceLanguage, sanitizeStrategy);
|
2173
2534
|
}
|
2174
|
-
return
|
2175
|
-
}
|
2535
|
+
return results;
|
2536
|
+
}
|
2176
2537
|
|
2177
|
-
|
2178
|
-
|
2179
|
-
|
2180
|
-
|
2181
|
-
*
|
2182
|
-
* @description
|
2183
|
-
* Returns a translation instantly from the internal state of loaded translation. All rules
|
2184
|
-
* regarding the current language, the preferred language of even fallback languages will be
|
2185
|
-
* used except any promise handling. If a language was not found, an asynchronous loading
|
2186
|
-
* will be invoked in the background.
|
2187
|
-
*
|
2188
|
-
* @param {string|array} translationId A token which represents a translation id
|
2189
|
-
* This can be optionally an array of translation ids which
|
2190
|
-
* results that the function's promise returns an object where
|
2191
|
-
* each key is the translation id and the value the translation.
|
2192
|
-
* @param {object} interpolateParams Params
|
2193
|
-
* @param {string} interpolationId The id of the interpolation to use
|
2194
|
-
*
|
2195
|
-
* @return {string|object} translation
|
2196
|
-
*/
|
2197
|
-
$translate.instant = function (translationId, interpolateParams, interpolationId) {
|
2538
|
+
// We discarded unacceptable values. So we just need to verify if translationId is empty String
|
2539
|
+
if (angular.isString(translationId) && translationId.length < 1) {
|
2540
|
+
return translationId;
|
2541
|
+
}
|
2198
2542
|
|
2199
|
-
|
2200
|
-
|
2201
|
-
|
2202
|
-
|
2543
|
+
// trim off any whitespace
|
2544
|
+
if (translationId) {
|
2545
|
+
translationId = trim.apply(translationId);
|
2546
|
+
}
|
2203
2547
|
|
2204
|
-
|
2205
|
-
|
2206
|
-
|
2207
|
-
|
2208
|
-
|
2209
|
-
|
2548
|
+
var result, possibleLangKeys = [];
|
2549
|
+
if ($preferredLanguage) {
|
2550
|
+
possibleLangKeys.push($preferredLanguage);
|
2551
|
+
}
|
2552
|
+
if (uses) {
|
2553
|
+
possibleLangKeys.push(uses);
|
2554
|
+
}
|
2555
|
+
if ($fallbackLanguage && $fallbackLanguage.length) {
|
2556
|
+
possibleLangKeys = possibleLangKeys.concat($fallbackLanguage);
|
2557
|
+
}
|
2558
|
+
for (var j = 0, d = possibleLangKeys.length; j < d; j++) {
|
2559
|
+
var possibleLangKey = possibleLangKeys[j];
|
2560
|
+
if ($translationTable[possibleLangKey]) {
|
2561
|
+
if (typeof $translationTable[possibleLangKey][translationId] !== 'undefined') {
|
2562
|
+
result = determineTranslationInstant(translationId, interpolateParams, interpolationId, uses, sanitizeStrategy);
|
2210
2563
|
}
|
2211
|
-
return results;
|
2212
2564
|
}
|
2213
|
-
|
2214
|
-
|
2215
|
-
if (angular.isString(translationId) && translationId.length < 1) {
|
2216
|
-
return translationId;
|
2565
|
+
if (typeof result !== 'undefined') {
|
2566
|
+
break;
|
2217
2567
|
}
|
2568
|
+
}
|
2218
2569
|
|
2219
|
-
|
2220
|
-
if (
|
2221
|
-
|
2222
|
-
}
|
2570
|
+
if (!result && result !== '') {
|
2571
|
+
if ($notFoundIndicatorLeft || $notFoundIndicatorRight) {
|
2572
|
+
result = applyNotFoundIndicators(translationId);
|
2573
|
+
} else {
|
2574
|
+
// Return translation of default interpolator if not found anything.
|
2575
|
+
result = defaultInterpolator.interpolate(translationId, interpolateParams, 'filter', sanitizeStrategy);
|
2223
2576
|
|
2224
|
-
|
2225
|
-
|
2226
|
-
|
2227
|
-
|
2228
|
-
|
2229
|
-
|
2230
|
-
}
|
2231
|
-
if ($fallbackLanguage && $fallbackLanguage.length) {
|
2232
|
-
possibleLangKeys = possibleLangKeys.concat($fallbackLanguage);
|
2233
|
-
}
|
2234
|
-
for (var j = 0, d = possibleLangKeys.length; j < d; j++) {
|
2235
|
-
var possibleLangKey = possibleLangKeys[j];
|
2236
|
-
if ($translationTable[possibleLangKey]) {
|
2237
|
-
if (typeof $translationTable[possibleLangKey][translationId] !== 'undefined') {
|
2238
|
-
result = determineTranslationInstant(translationId, interpolateParams, interpolationId);
|
2239
|
-
} else if ($notFoundIndicatorLeft || $notFoundIndicatorRight) {
|
2240
|
-
result = applyNotFoundIndicators(translationId);
|
2241
|
-
}
|
2242
|
-
}
|
2243
|
-
if (typeof result !== 'undefined') {
|
2244
|
-
break;
|
2577
|
+
// looks like the requested translation id doesn't exists.
|
2578
|
+
// Now, if there is a registered handler for missing translations and no
|
2579
|
+
// asyncLoader is pending, we execute the handler
|
2580
|
+
var missingTranslationHandlerTranslation;
|
2581
|
+
if ($missingTranslationHandlerFactory && !pendingLoader) {
|
2582
|
+
missingTranslationHandlerTranslation = translateByHandler(translationId, interpolateParams, sanitizeStrategy);
|
2245
2583
|
}
|
2246
|
-
}
|
2247
2584
|
|
2248
|
-
|
2249
|
-
|
2250
|
-
result = defaultInterpolator.interpolate(translationId, interpolateParams);
|
2251
|
-
if ($missingTranslationHandlerFactory && !pendingLoader) {
|
2252
|
-
result = translateByHandler(translationId, interpolateParams);
|
2585
|
+
if ($missingTranslationHandlerFactory && !pendingLoader && missingTranslationHandlerTranslation) {
|
2586
|
+
result = missingTranslationHandlerTranslation;
|
2253
2587
|
}
|
2254
2588
|
}
|
2589
|
+
}
|
2255
2590
|
|
2256
|
-
|
2257
|
-
|
2591
|
+
return result;
|
2592
|
+
};
|
2258
2593
|
|
2259
|
-
|
2260
|
-
|
2261
|
-
|
2262
|
-
|
2263
|
-
|
2264
|
-
|
2265
|
-
|
2266
|
-
|
2267
|
-
|
2268
|
-
|
2269
|
-
|
2270
|
-
|
2271
|
-
|
2594
|
+
/**
|
2595
|
+
* @ngdoc function
|
2596
|
+
* @name pascalprecht.translate.$translate#versionInfo
|
2597
|
+
* @methodOf pascalprecht.translate.$translate
|
2598
|
+
*
|
2599
|
+
* @description
|
2600
|
+
* Returns the current version information for the angular-translate library
|
2601
|
+
*
|
2602
|
+
* @return {string} angular-translate version
|
2603
|
+
*/
|
2604
|
+
$translate.versionInfo = function () {
|
2605
|
+
return version;
|
2606
|
+
};
|
2607
|
+
|
2608
|
+
/**
|
2609
|
+
* @ngdoc function
|
2610
|
+
* @name pascalprecht.translate.$translate#loaderCache
|
2611
|
+
* @methodOf pascalprecht.translate.$translate
|
2612
|
+
*
|
2613
|
+
* @description
|
2614
|
+
* Returns the defined loaderCache.
|
2615
|
+
*
|
2616
|
+
* @return {boolean|string|object} current value of loaderCache
|
2617
|
+
*/
|
2618
|
+
$translate.loaderCache = function () {
|
2619
|
+
return loaderCache;
|
2620
|
+
};
|
2621
|
+
|
2622
|
+
// internal purpose only
|
2623
|
+
$translate.directivePriority = function () {
|
2624
|
+
return directivePriority;
|
2625
|
+
};
|
2626
|
+
|
2627
|
+
// internal purpose only
|
2628
|
+
$translate.statefulFilter = function () {
|
2629
|
+
return statefulFilter;
|
2630
|
+
};
|
2272
2631
|
|
2273
|
-
|
2274
|
-
|
2275
|
-
|
2276
|
-
|
2277
|
-
|
2278
|
-
|
2279
|
-
|
2280
|
-
|
2281
|
-
|
2282
|
-
|
2283
|
-
|
2284
|
-
|
2285
|
-
|
2632
|
+
/**
|
2633
|
+
* @ngdoc function
|
2634
|
+
* @name pascalprecht.translate.$translate#isReady
|
2635
|
+
* @methodOf pascalprecht.translate.$translate
|
2636
|
+
*
|
2637
|
+
* @description
|
2638
|
+
* Returns whether the service is "ready" to translate (i.e. loading 1st language).
|
2639
|
+
*
|
2640
|
+
* See also {@link pascalprecht.translate.$translate#methods_onReady onReady()}.
|
2641
|
+
*
|
2642
|
+
* @return {boolean} current value of ready
|
2643
|
+
*/
|
2644
|
+
$translate.isReady = function () {
|
2645
|
+
return $isReady;
|
2646
|
+
};
|
2286
2647
|
|
2287
|
-
|
2288
|
-
|
2289
|
-
|
2290
|
-
|
2648
|
+
var $onReadyDeferred = $q.defer();
|
2649
|
+
$onReadyDeferred.promise.then(function () {
|
2650
|
+
$isReady = true;
|
2651
|
+
});
|
2291
2652
|
|
2292
|
-
|
2293
|
-
|
2294
|
-
|
2295
|
-
|
2653
|
+
/**
|
2654
|
+
* @ngdoc function
|
2655
|
+
* @name pascalprecht.translate.$translate#onReady
|
2656
|
+
* @methodOf pascalprecht.translate.$translate
|
2657
|
+
*
|
2658
|
+
* @description
|
2659
|
+
* Calls the function provided or resolved the returned promise after the service is "ready" to translate (i.e. loading 1st language).
|
2660
|
+
*
|
2661
|
+
* See also {@link pascalprecht.translate.$translate#methods_isReady isReady()}.
|
2662
|
+
*
|
2663
|
+
* @param {Function=} fn Function to invoke when service is ready
|
2664
|
+
* @return {object} Promise resolved when service is ready
|
2665
|
+
*/
|
2666
|
+
$translate.onReady = function (fn) {
|
2667
|
+
var deferred = $q.defer();
|
2668
|
+
if (angular.isFunction(fn)) {
|
2669
|
+
deferred.promise.then(fn);
|
2670
|
+
}
|
2671
|
+
if ($isReady) {
|
2672
|
+
deferred.resolve();
|
2673
|
+
} else {
|
2674
|
+
$onReadyDeferred.promise.then(deferred.resolve);
|
2675
|
+
}
|
2676
|
+
return deferred.promise;
|
2677
|
+
};
|
2678
|
+
|
2679
|
+
/**
|
2680
|
+
* @ngdoc function
|
2681
|
+
* @name pascalprecht.translate.$translate#getAvailableLanguageKeys
|
2682
|
+
* @methodOf pascalprecht.translate.$translate
|
2683
|
+
*
|
2684
|
+
* @description
|
2685
|
+
* This function simply returns the registered language keys being defined before in the config phase
|
2686
|
+
* With this, an application can use the array to provide a language selection dropdown or similar
|
2687
|
+
* without any additional effort
|
2688
|
+
*
|
2689
|
+
* @returns {object} returns the list of possibly registered language keys and mapping or null if not defined
|
2690
|
+
*/
|
2691
|
+
$translate.getAvailableLanguageKeys = function () {
|
2692
|
+
if ($availableLanguageKeys.length > 0) {
|
2693
|
+
return $availableLanguageKeys;
|
2694
|
+
}
|
2695
|
+
return null;
|
2696
|
+
};
|
2697
|
+
|
2698
|
+
/**
|
2699
|
+
* @ngdoc function
|
2700
|
+
* @name pascalprecht.translate.$translate#getTranslationTable
|
2701
|
+
* @methodOf pascalprecht.translate.$translate
|
2702
|
+
*
|
2703
|
+
* @description
|
2704
|
+
* Returns translation table by the given language key.
|
2705
|
+
*
|
2706
|
+
* Unless a language is provided it returns a translation table of the current one.
|
2707
|
+
* Note: If translation dictionary is currently downloading or in progress
|
2708
|
+
* it will return null.
|
2709
|
+
*
|
2710
|
+
* @param {string} langKey A token which represents a translation id
|
2711
|
+
*
|
2712
|
+
* @return {object} a copy of angular-translate $translationTable
|
2713
|
+
*/
|
2714
|
+
$translate.getTranslationTable = function (langKey) {
|
2715
|
+
langKey = langKey || $translate.use();
|
2716
|
+
if (langKey && $translationTable[langKey]) {
|
2717
|
+
return angular.copy($translationTable[langKey]);
|
2718
|
+
}
|
2719
|
+
return null;
|
2720
|
+
};
|
2721
|
+
|
2722
|
+
// Whenever $translateReady is being fired, this will ensure the state of $isReady
|
2723
|
+
var globalOnReadyListener = $rootScope.$on('$translateReady', function () {
|
2724
|
+
$onReadyDeferred.resolve();
|
2725
|
+
globalOnReadyListener(); // one time only
|
2726
|
+
globalOnReadyListener = null;
|
2727
|
+
});
|
2728
|
+
var globalOnChangeListener = $rootScope.$on('$translateChangeEnd', function () {
|
2729
|
+
$onReadyDeferred.resolve();
|
2730
|
+
globalOnChangeListener(); // one time only
|
2731
|
+
globalOnChangeListener = null;
|
2732
|
+
});
|
2296
2733
|
|
2297
|
-
|
2734
|
+
if ($loaderFactory) {
|
2298
2735
|
|
2299
|
-
|
2300
|
-
|
2301
|
-
|
2736
|
+
// If at least one async loader is defined and there are no
|
2737
|
+
// (default) translations available we should try to load them.
|
2738
|
+
if (angular.equals($translationTable, {})) {
|
2739
|
+
if ($translate.use()) {
|
2302
2740
|
$translate.use($translate.use());
|
2303
2741
|
}
|
2742
|
+
}
|
2304
2743
|
|
2305
|
-
|
2306
|
-
|
2307
|
-
|
2308
|
-
|
2309
|
-
|
2310
|
-
|
2311
|
-
|
2312
|
-
|
2313
|
-
|
2314
|
-
|
2315
|
-
|
2316
|
-
|
2317
|
-
}
|
2744
|
+
// Also, if there are any fallback language registered, we start
|
2745
|
+
// loading them asynchronously as soon as we can.
|
2746
|
+
if ($fallbackLanguage && $fallbackLanguage.length) {
|
2747
|
+
var processAsyncResult = function (translation) {
|
2748
|
+
translations(translation.key, translation.table);
|
2749
|
+
$rootScope.$emit('$translateChangeEnd', {language : translation.key});
|
2750
|
+
return translation;
|
2751
|
+
};
|
2752
|
+
for (var i = 0, len = $fallbackLanguage.length; i < len; i++) {
|
2753
|
+
var fallbackLanguageId = $fallbackLanguage[i];
|
2754
|
+
if ($forceAsyncReloadEnabled || !$translationTable[fallbackLanguageId]) {
|
2755
|
+
langPromises[fallbackLanguageId] = loadAsync(fallbackLanguageId).then(processAsyncResult);
|
2318
2756
|
}
|
2319
2757
|
}
|
2320
2758
|
}
|
2321
|
-
|
2322
|
-
|
2759
|
+
} else {
|
2760
|
+
$rootScope.$emit('$translateReady', {language : $translate.use()});
|
2323
2761
|
}
|
2324
|
-
|
2762
|
+
|
2763
|
+
return $translate;
|
2764
|
+
}];
|
2325
2765
|
}
|
2326
|
-
$translate.$inject = ['$STORAGE_KEY', '$windowProvider', '$translateSanitizationProvider', 'pascalprechtTranslateOverrider'];
|
2327
2766
|
|
2328
2767
|
$translate.displayName = 'displayName';
|
2329
2768
|
|
@@ -2395,24 +2834,41 @@ function $translateDefaultInterpolation ($interpolate, $translateSanitization) {
|
|
2395
2834
|
* @methodOf pascalprecht.translate.$translateDefaultInterpolation
|
2396
2835
|
*
|
2397
2836
|
* @description
|
2398
|
-
* Interpolates given
|
2837
|
+
* Interpolates given value agains given interpolate params using angulars
|
2399
2838
|
* `$interpolate` service.
|
2400
2839
|
*
|
2401
|
-
*
|
2840
|
+
* Since AngularJS 1.5, `value` must not be a string but can be anything input.
|
2841
|
+
*
|
2842
|
+
* @param {string} value translation
|
2843
|
+
* @param {object} interpolationParams interpolation params
|
2844
|
+
* @param {string} context current context (filter, directive, service)
|
2845
|
+
* @param {string} sanitizeStrategy sanitize strategy
|
2846
|
+
* @param {string} translationId current translationId
|
2847
|
+
*
|
2848
|
+
* @returns {string} interpolated string
|
2402
2849
|
*/
|
2403
|
-
$translateInterpolator.interpolate = function (
|
2850
|
+
$translateInterpolator.interpolate = function (value, interpolationParams, context, sanitizeStrategy, translationId) { // jshint ignore:line
|
2404
2851
|
interpolationParams = interpolationParams || {};
|
2405
|
-
interpolationParams = $translateSanitization.sanitize(interpolationParams, 'params');
|
2406
|
-
|
2407
|
-
var interpolatedText
|
2408
|
-
|
2852
|
+
interpolationParams = $translateSanitization.sanitize(interpolationParams, 'params', sanitizeStrategy, context);
|
2853
|
+
|
2854
|
+
var interpolatedText;
|
2855
|
+
if (angular.isNumber(value)) {
|
2856
|
+
// numbers are safe
|
2857
|
+
interpolatedText = '' + value;
|
2858
|
+
} else if (angular.isString(value)) {
|
2859
|
+
// strings must be interpolated (that's the job here)
|
2860
|
+
interpolatedText = $interpolate(value)(interpolationParams);
|
2861
|
+
interpolatedText = $translateSanitization.sanitize(interpolatedText, 'text', sanitizeStrategy, context);
|
2862
|
+
} else {
|
2863
|
+
// neither a number or a string, cant interpolate => empty string
|
2864
|
+
interpolatedText = '';
|
2865
|
+
}
|
2409
2866
|
|
2410
2867
|
return interpolatedText;
|
2411
2868
|
};
|
2412
2869
|
|
2413
2870
|
return $translateInterpolator;
|
2414
2871
|
}
|
2415
|
-
$translateDefaultInterpolation.$inject = ['$interpolate', '$translateSanitization'];
|
2416
2872
|
|
2417
2873
|
$translateDefaultInterpolation.displayName = '$translateDefaultInterpolation';
|
2418
2874
|
|
@@ -2422,14 +2878,15 @@ angular.module('pascalprecht.translate')
|
|
2422
2878
|
/**
|
2423
2879
|
* @ngdoc directive
|
2424
2880
|
* @name pascalprecht.translate.directive:translate
|
2425
|
-
* @requires $
|
2426
|
-
* @requires $
|
2427
|
-
* @requires $
|
2428
|
-
* @
|
2881
|
+
* @requires $interpolate,
|
2882
|
+
* @requires $compile,
|
2883
|
+
* @requires $parse,
|
2884
|
+
* @requires $rootScope
|
2885
|
+
* @restrict AE
|
2429
2886
|
*
|
2430
2887
|
* @description
|
2431
2888
|
* Translates given translation id either through attribute or DOM content.
|
2432
|
-
* Internally it uses
|
2889
|
+
* Internally it uses $translate service to translate the translation id. It possible to
|
2433
2890
|
* pass an optional `translate-values` object literal as string into translation id.
|
2434
2891
|
*
|
2435
2892
|
* @param {string=} translate Translation id which could be either string or interpolated string.
|
@@ -2437,6 +2894,7 @@ angular.module('pascalprecht.translate')
|
|
2437
2894
|
* @param {string=} translate-attr-ATTR translate Translation id and put it into ATTR attribute.
|
2438
2895
|
* @param {string=} translate-default will be used unless translation was successful
|
2439
2896
|
* @param {boolean=} translate-compile (default true if present) defines locally activation of {@link pascalprecht.translate.$translateProvider#methods_usePostCompiling}
|
2897
|
+
* @param {boolean=} translate-keep-content (default true if present) defines that in case a KEY could not be translated, that the existing content is left in the innerHTML}
|
2440
2898
|
*
|
2441
2899
|
* @example
|
2442
2900
|
<example module="ngView">
|
@@ -2453,6 +2911,7 @@ angular.module('pascalprecht.translate')
|
|
2453
2911
|
<pre translate="WITH_VALUES" translate-values="{{values}}"></pre>
|
2454
2912
|
<pre translate translate-values="{{values}}">WITH_VALUES</pre>
|
2455
2913
|
<pre translate translate-attr-title="WITH_VALUES" translate-values="{{values}}"></pre>
|
2914
|
+
<pre translate="WITH_CAMEL_CASE_KEY" translate-value-camel-case-key="Hi"></pre>
|
2456
2915
|
|
2457
2916
|
</div>
|
2458
2917
|
</file>
|
@@ -2463,7 +2922,8 @@ angular.module('pascalprecht.translate')
|
|
2463
2922
|
|
2464
2923
|
$translateProvider.translations('en',{
|
2465
2924
|
'TRANSLATION_ID': 'Hello there!',
|
2466
|
-
'WITH_VALUES': 'The following value is dynamic: {{value}}'
|
2925
|
+
'WITH_VALUES': 'The following value is dynamic: {{value}}',
|
2926
|
+
'WITH_CAMEL_CASE_KEY': 'The interpolation key is camel cased: {{camelCaseKey}}'
|
2467
2927
|
}).preferredLanguage('en');
|
2468
2928
|
|
2469
2929
|
});
|
@@ -2500,13 +2960,17 @@ angular.module('pascalprecht.translate')
|
|
2500
2960
|
element = $compile('<p translate translate-attr-title="TRANSLATION_ID"></p>')($rootScope);
|
2501
2961
|
$rootScope.$digest();
|
2502
2962
|
expect(element.attr('title')).toBe('Hello there!');
|
2963
|
+
|
2964
|
+
element = $compile('<p translate="WITH_CAMEL_CASE_KEY" translate-value-camel-case-key="Hello"></p>')($rootScope);
|
2965
|
+
$rootScope.$digest();
|
2966
|
+
expect(element.text()).toBe('The interpolation key is camel cased: Hello');
|
2503
2967
|
});
|
2504
2968
|
});
|
2505
2969
|
</file>
|
2506
2970
|
</example>
|
2507
2971
|
*/
|
2508
2972
|
.directive('translate', translateDirective);
|
2509
|
-
function translateDirective($translate, $
|
2973
|
+
function translateDirective($translate, $interpolate, $compile, $parse, $rootScope) {
|
2510
2974
|
|
2511
2975
|
'use strict';
|
2512
2976
|
|
@@ -2545,6 +3009,7 @@ function translateDirective($translate, $q, $interpolate, $compile, $parse, $roo
|
|
2545
3009
|
scope.interpolateParams = {};
|
2546
3010
|
scope.preText = '';
|
2547
3011
|
scope.postText = '';
|
3012
|
+
scope.translateNamespace = getTranslateNamespace(scope);
|
2548
3013
|
var translationIds = {};
|
2549
3014
|
|
2550
3015
|
var initInterpolationParams = function (interpolateParams, iAttr, tAttr) {
|
@@ -2575,14 +3040,16 @@ function translateDirective($translate, $q, $interpolate, $compile, $parse, $roo
|
|
2575
3040
|
}
|
2576
3041
|
|
2577
3042
|
if (angular.equals(translationId , '') || !angular.isDefined(translationId)) {
|
3043
|
+
var iElementText = trim.apply(iElement.text());
|
3044
|
+
|
2578
3045
|
// Resolve translation id by inner html if required
|
2579
|
-
var interpolateMatches =
|
3046
|
+
var interpolateMatches = iElementText.match(interpolateRegExp);
|
2580
3047
|
// Interpolate translation id if required
|
2581
3048
|
if (angular.isArray(interpolateMatches)) {
|
2582
3049
|
scope.preText = interpolateMatches[1];
|
2583
3050
|
scope.postText = interpolateMatches[3];
|
2584
3051
|
translationIds.translate = $interpolate(interpolateMatches[2])(scope.$parent);
|
2585
|
-
var watcherMatches =
|
3052
|
+
var watcherMatches = iElementText.match(watcherRegExp);
|
2586
3053
|
if (angular.isArray(watcherMatches) && watcherMatches[2] && watcherMatches[2].length) {
|
2587
3054
|
observeElementTranslation._unwatchOld = scope.$watch(watcherMatches[2], function (newValue) {
|
2588
3055
|
translationIds.translate = newValue;
|
@@ -2590,7 +3057,8 @@ function translateDirective($translate, $q, $interpolate, $compile, $parse, $roo
|
|
2590
3057
|
});
|
2591
3058
|
}
|
2592
3059
|
} else {
|
2593
|
-
|
3060
|
+
// do not assigne the translation id if it is empty.
|
3061
|
+
translationIds.translate = !iElementText ? undefined : iElementText;
|
2594
3062
|
}
|
2595
3063
|
} else {
|
2596
3064
|
translationIds.translate = translationId;
|
@@ -2624,13 +3092,14 @@ function translateDirective($translate, $q, $interpolate, $compile, $parse, $roo
|
|
2624
3092
|
});
|
2625
3093
|
|
2626
3094
|
for (var translateAttr in iAttr) {
|
2627
|
-
if (iAttr.hasOwnProperty(translateAttr) && translateAttr.substr(0, 13) === 'translateAttr') {
|
3095
|
+
if (iAttr.hasOwnProperty(translateAttr) && translateAttr.substr(0, 13) === 'translateAttr' && translateAttr.length > 13) {
|
2628
3096
|
observeAttributeTranslation(translateAttr);
|
2629
3097
|
}
|
2630
3098
|
}
|
2631
3099
|
|
2632
3100
|
iAttr.$observe('translateDefault', function (value) {
|
2633
3101
|
scope.defaultText = value;
|
3102
|
+
updateTranslations();
|
2634
3103
|
});
|
2635
3104
|
|
2636
3105
|
if (translateValuesExist) {
|
@@ -2660,17 +3129,21 @@ function translateDirective($translate, $q, $interpolate, $compile, $parse, $roo
|
|
2660
3129
|
// Master update function
|
2661
3130
|
var updateTranslations = function () {
|
2662
3131
|
for (var key in translationIds) {
|
2663
|
-
|
2664
3132
|
if (translationIds.hasOwnProperty(key) && translationIds[key] !== undefined) {
|
2665
|
-
updateTranslation(key, translationIds[key], scope, scope.interpolateParams, scope.defaultText);
|
3133
|
+
updateTranslation(key, translationIds[key], scope, scope.interpolateParams, scope.defaultText, scope.translateNamespace);
|
2666
3134
|
}
|
2667
3135
|
}
|
2668
3136
|
};
|
2669
3137
|
|
2670
3138
|
// Put translation processing function outside loop
|
2671
|
-
var updateTranslation = function(translateAttr, translationId, scope, interpolateParams, defaultTranslationText) {
|
3139
|
+
var updateTranslation = function(translateAttr, translationId, scope, interpolateParams, defaultTranslationText, translateNamespace) {
|
2672
3140
|
if (translationId) {
|
2673
|
-
|
3141
|
+
// if translation id starts with '.' and translateNamespace given, prepend namespace
|
3142
|
+
if (translateNamespace && translationId.charAt(0) === '.') {
|
3143
|
+
translationId = translateNamespace + translationId;
|
3144
|
+
}
|
3145
|
+
|
3146
|
+
$translate(translationId, interpolateParams, translateInterpolation, defaultTranslationText, scope.translateLanguage)
|
2674
3147
|
.then(function (translation) {
|
2675
3148
|
applyTranslation(translation, scope, true, translateAttr);
|
2676
3149
|
}, function (translationId) {
|
@@ -2683,12 +3156,16 @@ function translateDirective($translate, $q, $interpolate, $compile, $parse, $roo
|
|
2683
3156
|
};
|
2684
3157
|
|
2685
3158
|
var applyTranslation = function (value, scope, successful, translateAttr) {
|
3159
|
+
if (!successful) {
|
3160
|
+
if (typeof scope.defaultText !== 'undefined') {
|
3161
|
+
value = scope.defaultText;
|
3162
|
+
}
|
3163
|
+
}
|
2686
3164
|
if (translateAttr === 'translate') {
|
2687
3165
|
// default translate into innerHTML
|
2688
|
-
if (!successful && typeof
|
2689
|
-
value
|
3166
|
+
if (successful || (!successful && !$translate.isKeepContent() && typeof iAttr.translateKeepContent === 'undefined')) {
|
3167
|
+
iElement.empty().append(scope.preText + value + scope.postText);
|
2690
3168
|
}
|
2691
|
-
iElement.html(scope.preText + value + scope.postText);
|
2692
3169
|
var globallyEnabled = $translate.isPostCompilingEnabled();
|
2693
3170
|
var locallyDefined = typeof tAttr.translateCompile !== 'undefined';
|
2694
3171
|
var locallyEnabled = locallyDefined && tAttr.translateCompile !== 'false';
|
@@ -2697,9 +3174,6 @@ function translateDirective($translate, $q, $interpolate, $compile, $parse, $roo
|
|
2697
3174
|
}
|
2698
3175
|
} else {
|
2699
3176
|
// translate attribute
|
2700
|
-
if (!successful && typeof scope.defaultText !== 'undefined') {
|
2701
|
-
value = scope.defaultText;
|
2702
|
-
}
|
2703
3177
|
var attributeName = iAttr.$attr[translateAttr];
|
2704
3178
|
if (attributeName.substr(0, 5) === 'data-') {
|
2705
3179
|
// ensure html5 data prefix is stripped
|
@@ -2714,6 +3188,9 @@ function translateDirective($translate, $q, $interpolate, $compile, $parse, $roo
|
|
2714
3188
|
scope.$watch('interpolateParams', updateTranslations, true);
|
2715
3189
|
}
|
2716
3190
|
|
3191
|
+
// Replaced watcher on translateLanguage with event listener
|
3192
|
+
scope.$on('translateLanguageChanged', updateTranslations);
|
3193
|
+
|
2717
3194
|
// Ensures the text will be refreshed after the current language was changed
|
2718
3195
|
// w/ $translate.use(...)
|
2719
3196
|
var unbind = $rootScope.$on('$translateChangeSuccess', updateTranslations);
|
@@ -2735,15 +3212,179 @@ function translateDirective($translate, $q, $interpolate, $compile, $parse, $roo
|
|
2735
3212
|
}
|
2736
3213
|
};
|
2737
3214
|
}
|
2738
|
-
|
3215
|
+
|
3216
|
+
/**
|
3217
|
+
* Returns the scope's namespace.
|
3218
|
+
* @private
|
3219
|
+
* @param scope
|
3220
|
+
* @returns {string}
|
3221
|
+
*/
|
3222
|
+
function getTranslateNamespace(scope) {
|
3223
|
+
'use strict';
|
3224
|
+
if (scope.translateNamespace) {
|
3225
|
+
return scope.translateNamespace;
|
3226
|
+
}
|
3227
|
+
if (scope.$parent) {
|
3228
|
+
return getTranslateNamespace(scope.$parent);
|
3229
|
+
}
|
3230
|
+
}
|
2739
3231
|
|
2740
3232
|
translateDirective.displayName = 'translateDirective';
|
2741
3233
|
|
3234
|
+
angular.module('pascalprecht.translate')
|
3235
|
+
/**
|
3236
|
+
* @ngdoc directive
|
3237
|
+
* @name pascalprecht.translate.directive:translate-attr
|
3238
|
+
* @restrict A
|
3239
|
+
*
|
3240
|
+
* @description
|
3241
|
+
* Translates attributes like translate-attr-ATTR, but with an object like ng-class.
|
3242
|
+
* Internally it uses `translate` service to translate translation id. It possible to
|
3243
|
+
* pass an optional `translate-values` object literal as string into translation id.
|
3244
|
+
*
|
3245
|
+
* @param {string=} translate-attr Object literal mapping attributes to translation ids.
|
3246
|
+
* @param {string=} translate-values Values to pass into the translation ids. Can be passed as object literal string.
|
3247
|
+
*
|
3248
|
+
* @example
|
3249
|
+
<example module="ngView">
|
3250
|
+
<file name="index.html">
|
3251
|
+
<div ng-controller="TranslateCtrl">
|
3252
|
+
|
3253
|
+
<input translate-attr="{ placeholder: translationId, title: 'WITH_VALUES' }" translate-values="{value: 5}" />
|
3254
|
+
|
3255
|
+
</div>
|
3256
|
+
</file>
|
3257
|
+
<file name="script.js">
|
3258
|
+
angular.module('ngView', ['pascalprecht.translate'])
|
3259
|
+
|
3260
|
+
.config(function ($translateProvider) {
|
3261
|
+
|
3262
|
+
$translateProvider.translations('en',{
|
3263
|
+
'TRANSLATION_ID': 'Hello there!',
|
3264
|
+
'WITH_VALUES': 'The following value is dynamic: {{value}}',
|
3265
|
+
}).preferredLanguage('en');
|
3266
|
+
|
3267
|
+
});
|
3268
|
+
|
3269
|
+
angular.module('ngView').controller('TranslateCtrl', function ($scope) {
|
3270
|
+
$scope.translationId = 'TRANSLATION_ID';
|
3271
|
+
|
3272
|
+
$scope.values = {
|
3273
|
+
value: 78
|
3274
|
+
};
|
3275
|
+
});
|
3276
|
+
</file>
|
3277
|
+
<file name="scenario.js">
|
3278
|
+
it('should translate', function () {
|
3279
|
+
inject(function ($rootScope, $compile) {
|
3280
|
+
$rootScope.translationId = 'TRANSLATION_ID';
|
3281
|
+
|
3282
|
+
element = $compile('<input translate-attr="{ placeholder: translationId, title: 'WITH_VALUES' }" translate-values="{ value: 5 }" />')($rootScope);
|
3283
|
+
$rootScope.$digest();
|
3284
|
+
expect(element.attr('placeholder)).toBe('Hello there!');
|
3285
|
+
expect(element.attr('title)).toBe('The following value is dynamic: 5');
|
3286
|
+
});
|
3287
|
+
});
|
3288
|
+
</file>
|
3289
|
+
</example>
|
3290
|
+
*/
|
3291
|
+
.directive('translateAttr', translateAttrDirective);
|
3292
|
+
function translateAttrDirective($translate, $rootScope) {
|
3293
|
+
|
3294
|
+
'use strict';
|
3295
|
+
|
3296
|
+
return {
|
3297
|
+
restrict: 'A',
|
3298
|
+
priority: $translate.directivePriority(),
|
3299
|
+
link: function linkFn(scope, element, attr) {
|
3300
|
+
|
3301
|
+
var translateAttr,
|
3302
|
+
translateValues,
|
3303
|
+
previousAttributes = {};
|
3304
|
+
|
3305
|
+
// Main update translations function
|
3306
|
+
var updateTranslations = function () {
|
3307
|
+
angular.forEach(translateAttr, function (translationId, attributeName) {
|
3308
|
+
if (!translationId) {
|
3309
|
+
return;
|
3310
|
+
}
|
3311
|
+
previousAttributes[attributeName] = true;
|
3312
|
+
|
3313
|
+
// if translation id starts with '.' and translateNamespace given, prepend namespace
|
3314
|
+
if (scope.translateNamespace && translationId.charAt(0) === '.') {
|
3315
|
+
translationId = scope.translateNamespace + translationId;
|
3316
|
+
}
|
3317
|
+
$translate(translationId, translateValues, attr.translateInterpolation, undefined, scope.translateLanguage)
|
3318
|
+
.then(function (translation) {
|
3319
|
+
element.attr(attributeName, translation);
|
3320
|
+
}, function (translationId) {
|
3321
|
+
element.attr(attributeName, translationId);
|
3322
|
+
});
|
3323
|
+
});
|
3324
|
+
|
3325
|
+
// Removing unused attributes that were previously used
|
3326
|
+
angular.forEach(previousAttributes, function (flag, attributeName) {
|
3327
|
+
if (!translateAttr[attributeName]) {
|
3328
|
+
element.removeAttr(attributeName);
|
3329
|
+
delete previousAttributes[attributeName];
|
3330
|
+
}
|
3331
|
+
});
|
3332
|
+
};
|
3333
|
+
|
3334
|
+
// Watch for attribute changes
|
3335
|
+
watchAttribute(
|
3336
|
+
scope,
|
3337
|
+
attr.translateAttr,
|
3338
|
+
function (newValue) { translateAttr = newValue; },
|
3339
|
+
updateTranslations
|
3340
|
+
);
|
3341
|
+
// Watch for value changes
|
3342
|
+
watchAttribute(
|
3343
|
+
scope,
|
3344
|
+
attr.translateValues,
|
3345
|
+
function (newValue) { translateValues = newValue; },
|
3346
|
+
updateTranslations
|
3347
|
+
);
|
3348
|
+
|
3349
|
+
if (attr.translateValues) {
|
3350
|
+
scope.$watch(attr.translateValues, updateTranslations, true);
|
3351
|
+
}
|
3352
|
+
|
3353
|
+
// Replaced watcher on translateLanguage with event listener
|
3354
|
+
scope.$on('translateLanguageChanged', updateTranslations);
|
3355
|
+
|
3356
|
+
// Ensures the text will be refreshed after the current language was changed
|
3357
|
+
// w/ $translate.use(...)
|
3358
|
+
var unbind = $rootScope.$on('$translateChangeSuccess', updateTranslations);
|
3359
|
+
|
3360
|
+
updateTranslations();
|
3361
|
+
scope.$on('$destroy', unbind);
|
3362
|
+
}
|
3363
|
+
};
|
3364
|
+
}
|
3365
|
+
|
3366
|
+
function watchAttribute(scope, attribute, valueCallback, changeCallback) {
|
3367
|
+
'use strict';
|
3368
|
+
if (!attribute) {
|
3369
|
+
return;
|
3370
|
+
}
|
3371
|
+
if (attribute.substr(0, 2) === '::') {
|
3372
|
+
attribute = attribute.substr(2);
|
3373
|
+
} else {
|
3374
|
+
scope.$watch(attribute, function(newValue) {
|
3375
|
+
valueCallback(newValue);
|
3376
|
+
changeCallback();
|
3377
|
+
}, true);
|
3378
|
+
}
|
3379
|
+
valueCallback(scope.$eval(attribute));
|
3380
|
+
}
|
3381
|
+
|
3382
|
+
translateAttrDirective.displayName = 'translateAttrDirective';
|
3383
|
+
|
2742
3384
|
angular.module('pascalprecht.translate')
|
2743
3385
|
/**
|
2744
3386
|
* @ngdoc directive
|
2745
3387
|
* @name pascalprecht.translate.directive:translateCloak
|
2746
|
-
* @requires $rootScope
|
2747
3388
|
* @requires $translate
|
2748
3389
|
* @restrict A
|
2749
3390
|
*
|
@@ -2763,40 +3404,205 @@ angular.module('pascalprecht.translate')
|
|
2763
3404
|
*/
|
2764
3405
|
.directive('translateCloak', translateCloakDirective);
|
2765
3406
|
|
2766
|
-
function translateCloakDirective($
|
3407
|
+
function translateCloakDirective($translate, $rootScope) {
|
2767
3408
|
|
2768
3409
|
'use strict';
|
2769
3410
|
|
2770
3411
|
return {
|
2771
|
-
compile: function (tElement) {
|
2772
|
-
var applyCloak = function () {
|
2773
|
-
|
2774
|
-
|
2775
|
-
|
2776
|
-
|
2777
|
-
|
2778
|
-
|
2779
|
-
removeCloak();
|
2780
|
-
removeListener();
|
2781
|
-
removeListener = null;
|
2782
|
-
});
|
2783
|
-
applyCloak();
|
3412
|
+
compile : function (tElement) {
|
3413
|
+
var applyCloak = function (element) {
|
3414
|
+
element.addClass($translate.cloakClassName());
|
3415
|
+
},
|
3416
|
+
removeCloak = function (element) {
|
3417
|
+
element.removeClass($translate.cloakClassName());
|
3418
|
+
};
|
3419
|
+
applyCloak(tElement);
|
2784
3420
|
|
2785
3421
|
return function linkFn(scope, iElement, iAttr) {
|
2786
|
-
//
|
3422
|
+
//Create bound functions that incorporate the active DOM element.
|
3423
|
+
var iRemoveCloak = removeCloak.bind(this, iElement), iApplyCloak = applyCloak.bind(this, iElement);
|
2787
3424
|
if (iAttr.translateCloak && iAttr.translateCloak.length) {
|
3425
|
+
// Register a watcher for the defined translation allowing a fine tuned cloak
|
2788
3426
|
iAttr.$observe('translateCloak', function (translationId) {
|
2789
|
-
$translate(translationId).then(
|
3427
|
+
$translate(translationId).then(iRemoveCloak, iApplyCloak);
|
2790
3428
|
});
|
3429
|
+
$rootScope.$on('$translateChangeSuccess', function () {
|
3430
|
+
$translate(iAttr.translateCloak).then(iRemoveCloak, iApplyCloak);
|
3431
|
+
});
|
3432
|
+
} else {
|
3433
|
+
$translate.onReady(iRemoveCloak);
|
2791
3434
|
}
|
2792
3435
|
};
|
2793
3436
|
}
|
2794
3437
|
};
|
2795
3438
|
}
|
2796
|
-
translateCloakDirective.$inject = ['$rootScope', '$translate'];
|
2797
3439
|
|
2798
3440
|
translateCloakDirective.displayName = 'translateCloakDirective';
|
2799
3441
|
|
3442
|
+
angular.module('pascalprecht.translate')
|
3443
|
+
/**
|
3444
|
+
* @ngdoc directive
|
3445
|
+
* @name pascalprecht.translate.directive:translateNamespace
|
3446
|
+
* @restrict A
|
3447
|
+
*
|
3448
|
+
* @description
|
3449
|
+
* Translates given translation id either through attribute or DOM content.
|
3450
|
+
* Internally it uses `translate` filter to translate translation id. It possible to
|
3451
|
+
* pass an optional `translate-values` object literal as string into translation id.
|
3452
|
+
*
|
3453
|
+
* @param {string=} translate namespace name which could be either string or interpolated string.
|
3454
|
+
*
|
3455
|
+
* @example
|
3456
|
+
<example module="ngView">
|
3457
|
+
<file name="index.html">
|
3458
|
+
<div translate-namespace="CONTENT">
|
3459
|
+
|
3460
|
+
<div>
|
3461
|
+
<h1 translate>.HEADERS.TITLE</h1>
|
3462
|
+
<h1 translate>.HEADERS.WELCOME</h1>
|
3463
|
+
</div>
|
3464
|
+
|
3465
|
+
<div translate-namespace=".HEADERS">
|
3466
|
+
<h1 translate>.TITLE</h1>
|
3467
|
+
<h1 translate>.WELCOME</h1>
|
3468
|
+
</div>
|
3469
|
+
|
3470
|
+
</div>
|
3471
|
+
</file>
|
3472
|
+
<file name="script.js">
|
3473
|
+
angular.module('ngView', ['pascalprecht.translate'])
|
3474
|
+
|
3475
|
+
.config(function ($translateProvider) {
|
3476
|
+
|
3477
|
+
$translateProvider.translations('en',{
|
3478
|
+
'TRANSLATION_ID': 'Hello there!',
|
3479
|
+
'CONTENT': {
|
3480
|
+
'HEADERS': {
|
3481
|
+
TITLE: 'Title'
|
3482
|
+
}
|
3483
|
+
},
|
3484
|
+
'CONTENT.HEADERS.WELCOME': 'Welcome'
|
3485
|
+
}).preferredLanguage('en');
|
3486
|
+
|
3487
|
+
});
|
3488
|
+
|
3489
|
+
</file>
|
3490
|
+
</example>
|
3491
|
+
*/
|
3492
|
+
.directive('translateNamespace', translateNamespaceDirective);
|
3493
|
+
|
3494
|
+
function translateNamespaceDirective() {
|
3495
|
+
|
3496
|
+
'use strict';
|
3497
|
+
|
3498
|
+
return {
|
3499
|
+
restrict: 'A',
|
3500
|
+
scope: true,
|
3501
|
+
compile: function () {
|
3502
|
+
return {
|
3503
|
+
pre: function (scope, iElement, iAttrs) {
|
3504
|
+
scope.translateNamespace = getTranslateNamespace(scope);
|
3505
|
+
|
3506
|
+
if (scope.translateNamespace && iAttrs.translateNamespace.charAt(0) === '.') {
|
3507
|
+
scope.translateNamespace += iAttrs.translateNamespace;
|
3508
|
+
} else {
|
3509
|
+
scope.translateNamespace = iAttrs.translateNamespace;
|
3510
|
+
}
|
3511
|
+
}
|
3512
|
+
};
|
3513
|
+
}
|
3514
|
+
};
|
3515
|
+
}
|
3516
|
+
|
3517
|
+
/**
|
3518
|
+
* Returns the scope's namespace.
|
3519
|
+
* @private
|
3520
|
+
* @param scope
|
3521
|
+
* @returns {string}
|
3522
|
+
*/
|
3523
|
+
function getTranslateNamespace(scope) {
|
3524
|
+
'use strict';
|
3525
|
+
if (scope.translateNamespace) {
|
3526
|
+
return scope.translateNamespace;
|
3527
|
+
}
|
3528
|
+
if (scope.$parent) {
|
3529
|
+
return getTranslateNamespace(scope.$parent);
|
3530
|
+
}
|
3531
|
+
}
|
3532
|
+
|
3533
|
+
translateNamespaceDirective.displayName = 'translateNamespaceDirective';
|
3534
|
+
|
3535
|
+
angular.module('pascalprecht.translate')
|
3536
|
+
/**
|
3537
|
+
* @ngdoc directive
|
3538
|
+
* @name pascalprecht.translate.directive:translateLanguage
|
3539
|
+
* @restrict A
|
3540
|
+
*
|
3541
|
+
* @description
|
3542
|
+
* Forces the language to the directives in the underlying scope.
|
3543
|
+
*
|
3544
|
+
* @param {string=} translate language that will be negotiated.
|
3545
|
+
*
|
3546
|
+
* @example
|
3547
|
+
<example module="ngView">
|
3548
|
+
<file name="index.html">
|
3549
|
+
<div>
|
3550
|
+
|
3551
|
+
<div>
|
3552
|
+
<h1 translate>HELLO</h1>
|
3553
|
+
</div>
|
3554
|
+
|
3555
|
+
<div translate-language="de">
|
3556
|
+
<h1 translate>HELLO</h1>
|
3557
|
+
</div>
|
3558
|
+
|
3559
|
+
</div>
|
3560
|
+
</file>
|
3561
|
+
<file name="script.js">
|
3562
|
+
angular.module('ngView', ['pascalprecht.translate'])
|
3563
|
+
|
3564
|
+
.config(function ($translateProvider) {
|
3565
|
+
|
3566
|
+
$translateProvider
|
3567
|
+
.translations('en',{
|
3568
|
+
'HELLO': 'Hello world!'
|
3569
|
+
})
|
3570
|
+
.translations('de',{
|
3571
|
+
'HELLO': 'Hallo Welt!'
|
3572
|
+
})
|
3573
|
+
.preferredLanguage('en');
|
3574
|
+
|
3575
|
+
});
|
3576
|
+
|
3577
|
+
</file>
|
3578
|
+
</example>
|
3579
|
+
*/
|
3580
|
+
.directive('translateLanguage', translateLanguageDirective);
|
3581
|
+
|
3582
|
+
function translateLanguageDirective() {
|
3583
|
+
|
3584
|
+
'use strict';
|
3585
|
+
|
3586
|
+
return {
|
3587
|
+
restrict: 'A',
|
3588
|
+
scope: true,
|
3589
|
+
compile: function () {
|
3590
|
+
return function linkFn(scope, iElement, iAttrs) {
|
3591
|
+
|
3592
|
+
iAttrs.$observe('translateLanguage', function (newTranslateLanguage) {
|
3593
|
+
scope.translateLanguage = newTranslateLanguage;
|
3594
|
+
});
|
3595
|
+
|
3596
|
+
scope.$watch('translateLanguage', function(){
|
3597
|
+
scope.$broadcast('translateLanguageChanged');
|
3598
|
+
});
|
3599
|
+
};
|
3600
|
+
}
|
3601
|
+
};
|
3602
|
+
}
|
3603
|
+
|
3604
|
+
translateLanguageDirective.displayName = 'translateLanguageDirective';
|
3605
|
+
|
2800
3606
|
angular.module('pascalprecht.translate')
|
2801
3607
|
/**
|
2802
3608
|
* @ngdoc filter
|
@@ -2855,13 +3661,15 @@ function translateFilterFactory($parse, $translate) {
|
|
2855
3661
|
|
2856
3662
|
'use strict';
|
2857
3663
|
|
2858
|
-
var translateFilter = function (translationId, interpolateParams, interpolation) {
|
2859
|
-
|
3664
|
+
var translateFilter = function (translationId, interpolateParams, interpolation, forceLanguage) {
|
2860
3665
|
if (!angular.isObject(interpolateParams)) {
|
2861
|
-
|
3666
|
+
var ctx = this || {
|
3667
|
+
'__SCOPE_IS_NOT_AVAILABLE': 'More info at https://github.com/angular/angular.js/commit/8863b9d04c722b278fa93c5d66ad1e578ad6eb1f'
|
3668
|
+
};
|
3669
|
+
interpolateParams = $parse(interpolateParams)(ctx);
|
2862
3670
|
}
|
2863
3671
|
|
2864
|
-
return $translate.instant(translationId, interpolateParams, interpolation);
|
3672
|
+
return $translate.instant(translationId, interpolateParams, interpolation, forceLanguage);
|
2865
3673
|
};
|
2866
3674
|
|
2867
3675
|
if ($translate.statefulFilter()) {
|
@@ -2870,7 +3678,6 @@ function translateFilterFactory($parse, $translate) {
|
|
2870
3678
|
|
2871
3679
|
return translateFilter;
|
2872
3680
|
}
|
2873
|
-
translateFilterFactory.$inject = ['$parse', '$translate'];
|
2874
3681
|
|
2875
3682
|
translateFilterFactory.displayName = 'translateFilterFactory';
|
2876
3683
|
|
@@ -2896,7 +3703,6 @@ function $translationCache($cacheFactory) {
|
|
2896
3703
|
|
2897
3704
|
return $cacheFactory('translations');
|
2898
3705
|
}
|
2899
|
-
$translationCache.$inject = ['$cacheFactory'];
|
2900
3706
|
|
2901
3707
|
$translationCache.displayName = '$translationCache';
|
2902
3708
|
return 'pascalprecht.translate';
|