angular-translate.js 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883
  1. /*!
  2. * angular-translate - v2.2.0 - 2014-06-03
  3. * http://github.com/PascalPrecht/angular-translate
  4. * Copyright (c) 2014 ; Licensed MIT
  5. */
  6. angular.module('pascalprecht.translate', ['ng']).run([
  7. '$translate',
  8. function ($translate) {
  9. var key = $translate.storageKey(), storage = $translate.storage();
  10. if (storage) {
  11. if (!storage.get(key)) {
  12. if (angular.isString($translate.preferredLanguage())) {
  13. $translate.use($translate.preferredLanguage());
  14. } else {
  15. storage.set(key, $translate.use());
  16. }
  17. } else {
  18. $translate.use(storage.get(key));
  19. }
  20. } else if (angular.isString($translate.preferredLanguage())) {
  21. $translate.use($translate.preferredLanguage());
  22. }
  23. }
  24. ]);
  25. angular.module('pascalprecht.translate').provider('$translate', [
  26. '$STORAGE_KEY',
  27. function ($STORAGE_KEY) {
  28. var $translationTable = {}, $preferredLanguage, $availableLanguageKeys = [], $languageKeyAliases, $fallbackLanguage, $fallbackWasString, $uses, $nextLang, $storageFactory, $storageKey = $STORAGE_KEY, $storagePrefix, $missingTranslationHandlerFactory, $interpolationFactory, $interpolatorFactories = [], $interpolationSanitizationStrategy = false, $loaderFactory, $cloakClassName = 'translate-cloak', $loaderOptions, $notFoundIndicatorLeft, $notFoundIndicatorRight, $postCompilingEnabled = false, NESTED_OBJECT_DELIMITER = '.';
  29. var getLocale = function () {
  30. var nav = window.navigator;
  31. return (nav.language || nav.browserLanguage || nav.systemLanguage || nav.userLanguage || '').split('-').join('_');
  32. };
  33. var negotiateLocale = function (preferred) {
  34. var avail = [], locale = angular.lowercase(preferred), i = 0, n = $availableLanguageKeys.length;
  35. for (; i < n; i++) {
  36. avail.push(angular.lowercase($availableLanguageKeys[i]));
  37. }
  38. if (avail.indexOf(locale) > -1) {
  39. return preferred;
  40. }
  41. if ($languageKeyAliases) {
  42. var alias;
  43. for (var langKeyAlias in $languageKeyAliases) {
  44. var hasWildcardKey = false;
  45. var hasExactKey = $languageKeyAliases.hasOwnProperty(langKeyAlias) && angular.lowercase(langKeyAlias) === angular.lowercase(preferred);
  46. if (langKeyAlias.slice(-1) === '*') {
  47. hasWildcardKey = langKeyAlias.slice(0, -1) === preferred.slice(0, langKeyAlias.length - 1);
  48. }
  49. if (hasExactKey || hasWildcardKey) {
  50. alias = $languageKeyAliases[langKeyAlias];
  51. if (avail.indexOf(angular.lowercase(alias)) > -1) {
  52. return alias;
  53. }
  54. }
  55. }
  56. }
  57. var parts = preferred.split('_');
  58. if (parts.length > 1 && avail.indexOf(angular.lowercase(parts[0])) > -1) {
  59. return parts[0];
  60. }
  61. return preferred;
  62. };
  63. var translations = function (langKey, translationTable) {
  64. if (!langKey && !translationTable) {
  65. return $translationTable;
  66. }
  67. if (langKey && !translationTable) {
  68. if (angular.isString(langKey)) {
  69. return $translationTable[langKey];
  70. }
  71. } else {
  72. if (!angular.isObject($translationTable[langKey])) {
  73. $translationTable[langKey] = {};
  74. }
  75. angular.extend($translationTable[langKey], flatObject(translationTable));
  76. }
  77. return this;
  78. };
  79. this.translations = translations;
  80. this.cloakClassName = function (name) {
  81. if (!name) {
  82. return $cloakClassName;
  83. }
  84. $cloakClassName = name;
  85. return this;
  86. };
  87. var flatObject = function (data, path, result, prevKey) {
  88. var key, keyWithPath, keyWithShortPath, val;
  89. if (!path) {
  90. path = [];
  91. }
  92. if (!result) {
  93. result = {};
  94. }
  95. for (key in data) {
  96. if (!data.hasOwnProperty(key)) {
  97. continue;
  98. }
  99. val = data[key];
  100. if (angular.isObject(val)) {
  101. flatObject(val, path.concat(key), result, key);
  102. } else {
  103. keyWithPath = path.length ? '' + path.join(NESTED_OBJECT_DELIMITER) + NESTED_OBJECT_DELIMITER + key : key;
  104. if (path.length && key === prevKey) {
  105. keyWithShortPath = '' + path.join(NESTED_OBJECT_DELIMITER);
  106. result[keyWithShortPath] = '@:' + keyWithPath;
  107. }
  108. result[keyWithPath] = val;
  109. }
  110. }
  111. return result;
  112. };
  113. this.addInterpolation = function (factory) {
  114. $interpolatorFactories.push(factory);
  115. return this;
  116. };
  117. this.useMessageFormatInterpolation = function () {
  118. return this.useInterpolation('$translateMessageFormatInterpolation');
  119. };
  120. this.useInterpolation = function (factory) {
  121. $interpolationFactory = factory;
  122. return this;
  123. };
  124. this.useSanitizeValueStrategy = function (value) {
  125. $interpolationSanitizationStrategy = value;
  126. return this;
  127. };
  128. this.preferredLanguage = function (langKey) {
  129. if (langKey) {
  130. $preferredLanguage = langKey;
  131. return this;
  132. }
  133. return $preferredLanguage;
  134. };
  135. this.translationNotFoundIndicator = function (indicator) {
  136. this.translationNotFoundIndicatorLeft(indicator);
  137. this.translationNotFoundIndicatorRight(indicator);
  138. return this;
  139. };
  140. this.translationNotFoundIndicatorLeft = function (indicator) {
  141. if (!indicator) {
  142. return $notFoundIndicatorLeft;
  143. }
  144. $notFoundIndicatorLeft = indicator;
  145. return this;
  146. };
  147. this.translationNotFoundIndicatorRight = function (indicator) {
  148. if (!indicator) {
  149. return $notFoundIndicatorRight;
  150. }
  151. $notFoundIndicatorRight = indicator;
  152. return this;
  153. };
  154. this.fallbackLanguage = function (langKey) {
  155. fallbackStack(langKey);
  156. return this;
  157. };
  158. var fallbackStack = function (langKey) {
  159. if (langKey) {
  160. if (angular.isString(langKey)) {
  161. $fallbackWasString = true;
  162. $fallbackLanguage = [langKey];
  163. } else if (angular.isArray(langKey)) {
  164. $fallbackWasString = false;
  165. $fallbackLanguage = langKey;
  166. }
  167. if (angular.isString($preferredLanguage)) {
  168. $fallbackLanguage.push($preferredLanguage);
  169. }
  170. return this;
  171. } else {
  172. if ($fallbackWasString) {
  173. return $fallbackLanguage[0];
  174. } else {
  175. return $fallbackLanguage;
  176. }
  177. }
  178. };
  179. this.use = function (langKey) {
  180. if (langKey) {
  181. if (!$translationTable[langKey] && !$loaderFactory) {
  182. throw new Error('$translateProvider couldn\'t find translationTable for langKey: \'' + langKey + '\'');
  183. }
  184. $uses = langKey;
  185. return this;
  186. }
  187. return $uses;
  188. };
  189. var storageKey = function (key) {
  190. if (!key) {
  191. if ($storagePrefix) {
  192. return $storagePrefix + $storageKey;
  193. }
  194. return $storageKey;
  195. }
  196. $storageKey = key;
  197. };
  198. this.storageKey = storageKey;
  199. this.useUrlLoader = function (url) {
  200. return this.useLoader('$translateUrlLoader', { url: url });
  201. };
  202. this.useStaticFilesLoader = function (options) {
  203. return this.useLoader('$translateStaticFilesLoader', options);
  204. };
  205. this.useLoader = function (loaderFactory, options) {
  206. $loaderFactory = loaderFactory;
  207. $loaderOptions = options || {};
  208. return this;
  209. };
  210. this.useLocalStorage = function () {
  211. return this.useStorage('$translateLocalStorage');
  212. };
  213. this.useCookieStorage = function () {
  214. return this.useStorage('$translateCookieStorage');
  215. };
  216. this.useStorage = function (storageFactory) {
  217. $storageFactory = storageFactory;
  218. return this;
  219. };
  220. this.storagePrefix = function (prefix) {
  221. if (!prefix) {
  222. return prefix;
  223. }
  224. $storagePrefix = prefix;
  225. return this;
  226. };
  227. this.useMissingTranslationHandlerLog = function () {
  228. return this.useMissingTranslationHandler('$translateMissingTranslationHandlerLog');
  229. };
  230. this.useMissingTranslationHandler = function (factory) {
  231. $missingTranslationHandlerFactory = factory;
  232. return this;
  233. };
  234. this.usePostCompiling = function (value) {
  235. $postCompilingEnabled = !!value;
  236. return this;
  237. };
  238. this.determinePreferredLanguage = function (fn) {
  239. var locale = fn && angular.isFunction(fn) ? fn() : getLocale();
  240. if (!$availableLanguageKeys.length) {
  241. $preferredLanguage = locale;
  242. } else {
  243. $preferredLanguage = negotiateLocale(locale);
  244. }
  245. return this;
  246. };
  247. this.registerAvailableLanguageKeys = function (languageKeys, aliases) {
  248. if (languageKeys) {
  249. $availableLanguageKeys = languageKeys;
  250. if (aliases) {
  251. $languageKeyAliases = aliases;
  252. }
  253. return this;
  254. }
  255. return $availableLanguageKeys;
  256. };
  257. this.$get = [
  258. '$log',
  259. '$injector',
  260. '$rootScope',
  261. '$q',
  262. function ($log, $injector, $rootScope, $q) {
  263. var Storage, defaultInterpolator = $injector.get($interpolationFactory || '$translateDefaultInterpolation'), pendingLoader = false, interpolatorHashMap = {}, langPromises = {}, fallbackIndex, startFallbackIteration;
  264. var $translate = function (translationId, interpolateParams, interpolationId) {
  265. if (angular.isArray(translationId)) {
  266. var translateAll = function (translationIds) {
  267. var results = {};
  268. var promises = [];
  269. var translate = function (translationId) {
  270. var deferred = $q.defer();
  271. var regardless = function (value) {
  272. results[translationId] = value;
  273. deferred.resolve([
  274. translationId,
  275. value
  276. ]);
  277. };
  278. $translate(translationId, interpolateParams, interpolationId).then(regardless, regardless);
  279. return deferred.promise;
  280. };
  281. for (var i = 0, c = translationIds.length; i < c; i++) {
  282. promises.push(translate(translationIds[i]));
  283. }
  284. return $q.all(promises).then(function () {
  285. return results;
  286. });
  287. };
  288. return translateAll(translationId);
  289. }
  290. var deferred = $q.defer();
  291. if (translationId) {
  292. translationId = translationId.trim();
  293. }
  294. var promiseToWaitFor = function () {
  295. var promise = $preferredLanguage ? langPromises[$preferredLanguage] : langPromises[$uses];
  296. fallbackIndex = 0;
  297. if ($storageFactory && !promise) {
  298. var langKey = Storage.get($storageKey);
  299. promise = langPromises[langKey];
  300. if ($fallbackLanguage && $fallbackLanguage.length) {
  301. var index = indexOf($fallbackLanguage, langKey);
  302. fallbackIndex = index > -1 ? index += 1 : 0;
  303. $fallbackLanguage.push($preferredLanguage);
  304. }
  305. }
  306. return promise;
  307. }();
  308. if (!promiseToWaitFor) {
  309. determineTranslation(translationId, interpolateParams, interpolationId).then(deferred.resolve, deferred.reject);
  310. } else {
  311. promiseToWaitFor.then(function () {
  312. determineTranslation(translationId, interpolateParams, interpolationId).then(deferred.resolve, deferred.reject);
  313. }, deferred.reject);
  314. }
  315. return deferred.promise;
  316. };
  317. var indexOf = function (array, searchElement) {
  318. for (var i = 0, len = array.length; i < len; i++) {
  319. if (array[i] === searchElement) {
  320. return i;
  321. }
  322. }
  323. return -1;
  324. };
  325. var applyNotFoundIndicators = function (translationId) {
  326. if ($notFoundIndicatorLeft) {
  327. translationId = [
  328. $notFoundIndicatorLeft,
  329. translationId
  330. ].join(' ');
  331. }
  332. if ($notFoundIndicatorRight) {
  333. translationId = [
  334. translationId,
  335. $notFoundIndicatorRight
  336. ].join(' ');
  337. }
  338. return translationId;
  339. };
  340. var useLanguage = function (key) {
  341. $uses = key;
  342. $rootScope.$emit('$translateChangeSuccess');
  343. if ($storageFactory) {
  344. Storage.set($translate.storageKey(), $uses);
  345. }
  346. defaultInterpolator.setLocale($uses);
  347. angular.forEach(interpolatorHashMap, function (interpolator, id) {
  348. interpolatorHashMap[id].setLocale($uses);
  349. });
  350. $rootScope.$emit('$translateChangeEnd');
  351. };
  352. var loadAsync = function (key) {
  353. if (!key) {
  354. throw 'No language key specified for loading.';
  355. }
  356. var deferred = $q.defer();
  357. $rootScope.$emit('$translateLoadingStart');
  358. pendingLoader = true;
  359. $injector.get($loaderFactory)(angular.extend($loaderOptions, { key: key })).then(function (data) {
  360. var translationTable = {};
  361. $rootScope.$emit('$translateLoadingSuccess');
  362. if (angular.isArray(data)) {
  363. angular.forEach(data, function (table) {
  364. angular.extend(translationTable, flatObject(table));
  365. });
  366. } else {
  367. angular.extend(translationTable, flatObject(data));
  368. }
  369. pendingLoader = false;
  370. deferred.resolve({
  371. key: key,
  372. table: translationTable
  373. });
  374. $rootScope.$emit('$translateLoadingEnd');
  375. }, function (key) {
  376. $rootScope.$emit('$translateLoadingError');
  377. deferred.reject(key);
  378. $rootScope.$emit('$translateLoadingEnd');
  379. });
  380. return deferred.promise;
  381. };
  382. if ($storageFactory) {
  383. Storage = $injector.get($storageFactory);
  384. if (!Storage.get || !Storage.set) {
  385. throw new Error('Couldn\'t use storage \'' + $storageFactory + '\', missing get() or set() method!');
  386. }
  387. }
  388. if (angular.isFunction(defaultInterpolator.useSanitizeValueStrategy)) {
  389. defaultInterpolator.useSanitizeValueStrategy($interpolationSanitizationStrategy);
  390. }
  391. if ($interpolatorFactories.length) {
  392. angular.forEach($interpolatorFactories, function (interpolatorFactory) {
  393. var interpolator = $injector.get(interpolatorFactory);
  394. interpolator.setLocale($preferredLanguage || $uses);
  395. if (angular.isFunction(interpolator.useSanitizeValueStrategy)) {
  396. interpolator.useSanitizeValueStrategy($interpolationSanitizationStrategy);
  397. }
  398. interpolatorHashMap[interpolator.getInterpolationIdentifier()] = interpolator;
  399. });
  400. }
  401. var getTranslationTable = function (langKey) {
  402. var deferred = $q.defer();
  403. if ($translationTable.hasOwnProperty(langKey)) {
  404. deferred.resolve($translationTable[langKey]);
  405. return deferred.promise;
  406. } else {
  407. langPromises[langKey].then(function (data) {
  408. translations(data.key, data.table);
  409. deferred.resolve(data.table);
  410. }, deferred.reject);
  411. }
  412. return deferred.promise;
  413. };
  414. var getFallbackTranslation = function (langKey, translationId, interpolateParams, Interpolator) {
  415. var deferred = $q.defer();
  416. getTranslationTable(langKey).then(function (translationTable) {
  417. if (translationTable.hasOwnProperty(translationId)) {
  418. Interpolator.setLocale(langKey);
  419. deferred.resolve(Interpolator.interpolate(translationTable[translationId], interpolateParams));
  420. Interpolator.setLocale($uses);
  421. } else {
  422. deferred.reject();
  423. }
  424. }, deferred.reject);
  425. return deferred.promise;
  426. };
  427. var getFallbackTranslationInstant = function (langKey, translationId, interpolateParams, Interpolator) {
  428. var result, translationTable = $translationTable[langKey];
  429. if (translationTable.hasOwnProperty(translationId)) {
  430. Interpolator.setLocale(langKey);
  431. result = Interpolator.interpolate(translationTable[translationId], interpolateParams);
  432. Interpolator.setLocale($uses);
  433. }
  434. return result;
  435. };
  436. var resolveForFallbackLanguage = function (fallbackLanguageIndex, translationId, interpolateParams, Interpolator) {
  437. var deferred = $q.defer();
  438. if (fallbackLanguageIndex < $fallbackLanguage.length) {
  439. var langKey = $fallbackLanguage[fallbackLanguageIndex];
  440. getFallbackTranslation(langKey, translationId, interpolateParams, Interpolator).then(function (translation) {
  441. deferred.resolve(translation);
  442. }, function () {
  443. var nextFallbackLanguagePromise = resolveForFallbackLanguage(fallbackLanguageIndex + 1, translationId, interpolateParams, Interpolator);
  444. deferred.resolve(nextFallbackLanguagePromise);
  445. });
  446. } else {
  447. if ($missingTranslationHandlerFactory) {
  448. var resultString = $injector.get($missingTranslationHandlerFactory)(translationId, $uses);
  449. if (resultString !== undefined) {
  450. deferred.resolve(resultString);
  451. } else {
  452. deferred.resolve(translationId);
  453. }
  454. } else {
  455. deferred.resolve(translationId);
  456. }
  457. }
  458. return deferred.promise;
  459. };
  460. var resolveForFallbackLanguageInstant = function (fallbackLanguageIndex, translationId, interpolateParams, Interpolator) {
  461. var result;
  462. if (fallbackLanguageIndex < $fallbackLanguage.length) {
  463. var langKey = $fallbackLanguage[fallbackLanguageIndex];
  464. result = getFallbackTranslationInstant(langKey, translationId, interpolateParams, Interpolator);
  465. if (!result) {
  466. result = resolveForFallbackLanguageInstant(fallbackLanguageIndex + 1, translationId, interpolateParams, Interpolator);
  467. }
  468. }
  469. return result;
  470. };
  471. var fallbackTranslation = function (translationId, interpolateParams, Interpolator) {
  472. return resolveForFallbackLanguage(startFallbackIteration > 0 ? startFallbackIteration : fallbackIndex, translationId, interpolateParams, Interpolator);
  473. };
  474. var fallbackTranslationInstant = function (translationId, interpolateParams, Interpolator) {
  475. return resolveForFallbackLanguageInstant(startFallbackIteration > 0 ? startFallbackIteration : fallbackIndex, translationId, interpolateParams, Interpolator);
  476. };
  477. var determineTranslation = function (translationId, interpolateParams, interpolationId) {
  478. var deferred = $q.defer();
  479. var table = $uses ? $translationTable[$uses] : $translationTable, Interpolator = interpolationId ? interpolatorHashMap[interpolationId] : defaultInterpolator;
  480. if (table && table.hasOwnProperty(translationId)) {
  481. var translation = table[translationId];
  482. if (translation.substr(0, 2) === '@:') {
  483. $translate(translation.substr(2), interpolateParams, interpolationId).then(deferred.resolve, deferred.reject);
  484. } else {
  485. deferred.resolve(Interpolator.interpolate(translation, interpolateParams));
  486. }
  487. } else {
  488. if ($missingTranslationHandlerFactory && !pendingLoader) {
  489. $injector.get($missingTranslationHandlerFactory)(translationId, $uses);
  490. }
  491. if ($uses && $fallbackLanguage && $fallbackLanguage.length) {
  492. fallbackTranslation(translationId, interpolateParams, Interpolator).then(function (translation) {
  493. deferred.resolve(translation);
  494. }, function (_translationId) {
  495. deferred.reject(applyNotFoundIndicators(_translationId));
  496. });
  497. } else {
  498. deferred.reject(applyNotFoundIndicators(translationId));
  499. }
  500. }
  501. return deferred.promise;
  502. };
  503. var determineTranslationInstant = function (translationId, interpolateParams, interpolationId) {
  504. var result, table = $uses ? $translationTable[$uses] : $translationTable, Interpolator = interpolationId ? interpolatorHashMap[interpolationId] : defaultInterpolator;
  505. if (table && table.hasOwnProperty(translationId)) {
  506. var translation = table[translationId];
  507. if (translation.substr(0, 2) === '@:') {
  508. result = determineTranslationInstant(translation.substr(2), interpolateParams, interpolationId);
  509. } else {
  510. result = Interpolator.interpolate(translation, interpolateParams);
  511. }
  512. } else {
  513. if ($missingTranslationHandlerFactory && !pendingLoader) {
  514. $injector.get($missingTranslationHandlerFactory)(translationId, $uses);
  515. }
  516. if ($uses && $fallbackLanguage && $fallbackLanguage.length) {
  517. fallbackIndex = 0;
  518. result = fallbackTranslationInstant(translationId, interpolateParams, Interpolator);
  519. } else {
  520. result = applyNotFoundIndicators(translationId);
  521. }
  522. }
  523. return result;
  524. };
  525. $translate.preferredLanguage = function () {
  526. return $preferredLanguage;
  527. };
  528. $translate.cloakClassName = function () {
  529. return $cloakClassName;
  530. };
  531. $translate.fallbackLanguage = function (langKey) {
  532. if (langKey !== undefined && langKey !== null) {
  533. fallbackStack(langKey);
  534. if ($loaderFactory) {
  535. if ($fallbackLanguage && $fallbackLanguage.length) {
  536. for (var i = 0, len = $fallbackLanguage.length; i < len; i++) {
  537. if (!langPromises[$fallbackLanguage[i]]) {
  538. langPromises[$fallbackLanguage[i]] = loadAsync($fallbackLanguage[i]);
  539. }
  540. }
  541. }
  542. }
  543. $translate.use($translate.use());
  544. }
  545. if ($fallbackWasString) {
  546. return $fallbackLanguage[0];
  547. } else {
  548. return $fallbackLanguage;
  549. }
  550. };
  551. $translate.useFallbackLanguage = function (langKey) {
  552. if (langKey !== undefined && langKey !== null) {
  553. if (!langKey) {
  554. startFallbackIteration = 0;
  555. } else {
  556. var langKeyPosition = indexOf($fallbackLanguage, langKey);
  557. if (langKeyPosition > -1) {
  558. startFallbackIteration = langKeyPosition;
  559. }
  560. }
  561. }
  562. };
  563. $translate.proposedLanguage = function () {
  564. return $nextLang;
  565. };
  566. $translate.storage = function () {
  567. return Storage;
  568. };
  569. $translate.use = function (key) {
  570. if (!key) {
  571. return $uses;
  572. }
  573. var deferred = $q.defer();
  574. $rootScope.$emit('$translateChangeStart');
  575. var aliasedKey = negotiateLocale(key);
  576. if (aliasedKey) {
  577. key = aliasedKey;
  578. }
  579. if (!$translationTable[key] && $loaderFactory) {
  580. $nextLang = key;
  581. langPromises[key] = loadAsync(key).then(function (translation) {
  582. translations(translation.key, translation.table);
  583. deferred.resolve(translation.key);
  584. if ($nextLang === key) {
  585. useLanguage(translation.key);
  586. $nextLang = undefined;
  587. }
  588. }, function (key) {
  589. $nextLang = undefined;
  590. $rootScope.$emit('$translateChangeError');
  591. deferred.reject(key);
  592. $rootScope.$emit('$translateChangeEnd');
  593. });
  594. } else {
  595. deferred.resolve(key);
  596. useLanguage(key);
  597. }
  598. return deferred.promise;
  599. };
  600. $translate.storageKey = function () {
  601. return storageKey();
  602. };
  603. $translate.isPostCompilingEnabled = function () {
  604. return $postCompilingEnabled;
  605. };
  606. $translate.refresh = function (langKey) {
  607. if (!$loaderFactory) {
  608. throw new Error('Couldn\'t refresh translation table, no loader registered!');
  609. }
  610. var deferred = $q.defer();
  611. function resolve() {
  612. deferred.resolve();
  613. $rootScope.$emit('$translateRefreshEnd');
  614. }
  615. function reject() {
  616. deferred.reject();
  617. $rootScope.$emit('$translateRefreshEnd');
  618. }
  619. $rootScope.$emit('$translateRefreshStart');
  620. if (!langKey) {
  621. var tables = [];
  622. if ($fallbackLanguage && $fallbackLanguage.length) {
  623. for (var i = 0, len = $fallbackLanguage.length; i < len; i++) {
  624. tables.push(loadAsync($fallbackLanguage[i]));
  625. }
  626. }
  627. if ($uses) {
  628. tables.push(loadAsync($uses));
  629. }
  630. $q.all(tables).then(function (tableData) {
  631. angular.forEach(tableData, function (data) {
  632. if ($translationTable[data.key]) {
  633. delete $translationTable[data.key];
  634. }
  635. translations(data.key, data.table);
  636. });
  637. if ($uses) {
  638. useLanguage($uses);
  639. }
  640. resolve();
  641. });
  642. } else if ($translationTable[langKey]) {
  643. loadAsync(langKey).then(function (data) {
  644. translations(data.key, data.table);
  645. if (langKey === $uses) {
  646. useLanguage($uses);
  647. }
  648. resolve();
  649. }, reject);
  650. } else {
  651. reject();
  652. }
  653. return deferred.promise;
  654. };
  655. $translate.instant = function (translationId, interpolateParams, interpolationId) {
  656. if (translationId === null || angular.isUndefined(translationId)) {
  657. return translationId;
  658. }
  659. if (angular.isArray(translationId)) {
  660. var results = {};
  661. for (var i = 0, c = translationId.length; i < c; i++) {
  662. results[translationId[i]] = $translate.instant(translationId[i], interpolateParams, interpolationId);
  663. }
  664. return results;
  665. }
  666. if (angular.isString(translationId) && translationId.length < 1) {
  667. return translationId;
  668. }
  669. if (translationId) {
  670. translationId = translationId.trim();
  671. }
  672. var result, possibleLangKeys = [];
  673. if ($preferredLanguage) {
  674. possibleLangKeys.push($preferredLanguage);
  675. }
  676. if ($uses) {
  677. possibleLangKeys.push($uses);
  678. }
  679. if ($fallbackLanguage && $fallbackLanguage.length) {
  680. possibleLangKeys = possibleLangKeys.concat($fallbackLanguage);
  681. }
  682. for (var j = 0, d = possibleLangKeys.length; j < d; j++) {
  683. var possibleLangKey = possibleLangKeys[j];
  684. if ($translationTable[possibleLangKey]) {
  685. if (typeof $translationTable[possibleLangKey][translationId] !== 'undefined') {
  686. result = determineTranslationInstant(translationId, interpolateParams, interpolationId);
  687. }
  688. }
  689. if (typeof result !== 'undefined') {
  690. break;
  691. }
  692. }
  693. if (!result && result !== '') {
  694. result = translationId;
  695. if ($missingTranslationHandlerFactory && !pendingLoader) {
  696. $injector.get($missingTranslationHandlerFactory)(translationId, $uses);
  697. }
  698. }
  699. return result;
  700. };
  701. if ($loaderFactory) {
  702. if (angular.equals($translationTable, {})) {
  703. $translate.use($translate.use());
  704. }
  705. if ($fallbackLanguage && $fallbackLanguage.length) {
  706. for (var i = 0, len = $fallbackLanguage.length; i < len; i++) {
  707. langPromises[$fallbackLanguage[i]] = loadAsync($fallbackLanguage[i]);
  708. }
  709. }
  710. }
  711. return $translate;
  712. }
  713. ];
  714. }
  715. ]);
  716. angular.module('pascalprecht.translate').factory('$translateDefaultInterpolation', [
  717. '$interpolate',
  718. function ($interpolate) {
  719. var $translateInterpolator = {}, $locale, $identifier = 'default', $sanitizeValueStrategy = null, sanitizeValueStrategies = {
  720. escaped: function (params) {
  721. var result = {};
  722. for (var key in params) {
  723. if (params.hasOwnProperty(key)) {
  724. result[key] = angular.element('<div></div>').text(params[key]).html();
  725. }
  726. }
  727. return result;
  728. }
  729. };
  730. var sanitizeParams = function (params) {
  731. var result;
  732. if (angular.isFunction(sanitizeValueStrategies[$sanitizeValueStrategy])) {
  733. result = sanitizeValueStrategies[$sanitizeValueStrategy](params);
  734. } else {
  735. result = params;
  736. }
  737. return result;
  738. };
  739. $translateInterpolator.setLocale = function (locale) {
  740. $locale = locale;
  741. };
  742. $translateInterpolator.getInterpolationIdentifier = function () {
  743. return $identifier;
  744. };
  745. $translateInterpolator.useSanitizeValueStrategy = function (value) {
  746. $sanitizeValueStrategy = value;
  747. return this;
  748. };
  749. $translateInterpolator.interpolate = function (string, interpolateParams) {
  750. if ($sanitizeValueStrategy) {
  751. interpolateParams = sanitizeParams(interpolateParams);
  752. }
  753. return $interpolate(string)(interpolateParams || {});
  754. };
  755. return $translateInterpolator;
  756. }
  757. ]);
  758. angular.module('pascalprecht.translate').constant('$STORAGE_KEY', 'NG_TRANSLATE_LANG_KEY');
  759. angular.module('pascalprecht.translate').directive('translate', [
  760. '$translate',
  761. '$q',
  762. '$interpolate',
  763. '$compile',
  764. '$parse',
  765. '$rootScope',
  766. function ($translate, $q, $interpolate, $compile, $parse, $rootScope) {
  767. return {
  768. restrict: 'AE',
  769. scope: true,
  770. compile: function (tElement, tAttr) {
  771. var translateValuesExist = tAttr.translateValues ? tAttr.translateValues : undefined;
  772. var translateInterpolation = tAttr.translateInterpolation ? tAttr.translateInterpolation : undefined;
  773. var translateValueExist = tElement[0].outerHTML.match(/translate-value-+/i);
  774. return function linkFn(scope, iElement, iAttr) {
  775. scope.interpolateParams = {};
  776. iAttr.$observe('translate', function (translationId) {
  777. if (angular.equals(translationId, '') || !angular.isDefined(translationId)) {
  778. scope.translationId = $interpolate(iElement.text().replace(/^\s+|\s+$/g, ''))(scope.$parent);
  779. } else {
  780. scope.translationId = translationId;
  781. }
  782. });
  783. iAttr.$observe('translateDefault', function (value) {
  784. scope.defaultText = value;
  785. });
  786. if (translateValuesExist) {
  787. iAttr.$observe('translateValues', function (interpolateParams) {
  788. if (interpolateParams) {
  789. scope.$parent.$watch(function () {
  790. angular.extend(scope.interpolateParams, $parse(interpolateParams)(scope.$parent));
  791. });
  792. }
  793. });
  794. }
  795. if (translateValueExist) {
  796. var fn = function (attrName) {
  797. iAttr.$observe(attrName, function (value) {
  798. scope.interpolateParams[angular.lowercase(attrName.substr(14, 1)) + attrName.substr(15)] = value;
  799. });
  800. };
  801. for (var attr in iAttr) {
  802. if (iAttr.hasOwnProperty(attr) && attr.substr(0, 14) === 'translateValue' && attr !== 'translateValues') {
  803. fn(attr);
  804. }
  805. }
  806. }
  807. var applyElementContent = function (value, scope, successful) {
  808. if (!successful && typeof scope.defaultText !== 'undefined') {
  809. value = scope.defaultText;
  810. }
  811. iElement.html(value);
  812. var globallyEnabled = $translate.isPostCompilingEnabled();
  813. var locallyDefined = typeof tAttr.translateCompile !== 'undefined';
  814. var locallyEnabled = locallyDefined && tAttr.translateCompile !== 'false';
  815. if (globallyEnabled && !locallyDefined || locallyEnabled) {
  816. $compile(iElement.contents())(scope);
  817. }
  818. };
  819. var updateTranslationFn = function () {
  820. if (!translateValuesExist && !translateValueExist) {
  821. return function () {
  822. var unwatch = scope.$watch('translationId', function (value) {
  823. if (scope.translationId && value) {
  824. $translate(value, {}, translateInterpolation).then(function (translation) {
  825. applyElementContent(translation, scope, true);
  826. unwatch();
  827. }, function (translationId) {
  828. applyElementContent(translationId, scope, false);
  829. unwatch();
  830. });
  831. }
  832. }, true);
  833. };
  834. } else {
  835. return function () {
  836. var updateTranslations = function () {
  837. if (scope.translationId && scope.interpolateParams) {
  838. $translate(scope.translationId, scope.interpolateParams, translateInterpolation).then(function (translation) {
  839. applyElementContent(translation, scope, true);
  840. }, function (translationId) {
  841. applyElementContent(translationId, scope, false);
  842. });
  843. }
  844. };
  845. scope.$watch('interpolateParams', updateTranslations, true);
  846. scope.$watch('translationId', updateTranslations);
  847. };
  848. }
  849. }();
  850. var unbind = $rootScope.$on('$translateChangeSuccess', updateTranslationFn);
  851. updateTranslationFn();
  852. scope.$on('$destroy', unbind);
  853. };
  854. }
  855. };
  856. }
  857. ]);
  858. angular.module('pascalprecht.translate').directive('translateCloak', [
  859. '$rootScope',
  860. '$translate',
  861. function ($rootScope, $translate) {
  862. return {
  863. compile: function (tElement) {
  864. $rootScope.$on('$translateLoadingSuccess', function () {
  865. tElement.removeClass($translate.cloakClassName());
  866. });
  867. tElement.addClass($translate.cloakClassName());
  868. }
  869. };
  870. }
  871. ]);
  872. angular.module('pascalprecht.translate').filter('translate', [
  873. '$parse',
  874. '$translate',
  875. function ($parse, $translate) {
  876. return function (translationId, interpolateParams, interpolation) {
  877. if (!angular.isObject(interpolateParams)) {
  878. interpolateParams = $parse(interpolateParams)(this);
  879. }
  880. return $translate.instant(translationId, interpolateParams, interpolation);
  881. };
  882. }
  883. ]);