From 5e20e243bae43e70c75714f1d037f1916b33447c Mon Sep 17 00:00:00 2001 From: Pascal Precht Date: Thu, 18 Jul 2013 13:45:09 +0200 Subject: [PATCH] feat(translateService): implements usage of different interpolation services --- bower.json | 6 +- src/translate.js | 42 +++++++++-- test/unit/translateServiceSpec.js | 118 ++++++++++++++++++++++++++++++ 3 files changed, 157 insertions(+), 9 deletions(-) diff --git a/bower.json b/bower.json index e1f6fe87c..a4c327a07 100644 --- a/bower.json +++ b/bower.json @@ -13,11 +13,11 @@ "angular": "1.0.7", "angular-mocks": "1.0.7", "ngMidwayTester": "yearofmoo/ngMidwayTester#*", - "angular-translate-interpolation-default": "~0.1.0" + "angular-translate-interpolation-default": "~0.1.1" }, "devDependencies": { "angular-mocks": "1.0.7", "ngMidwayTester": "yearofmoo/ngMidwayTester", - "angular-translate-interpolation-messageformat": "~0.1.0" + "angular-translate-interpolation-messageformat": "~0.1.1" } -} \ No newline at end of file +} diff --git a/src/translate.js b/src/translate.js index 485f0c0f9..e4a7c92dd 100644 --- a/src/translate.js +++ b/src/translate.js @@ -46,6 +46,7 @@ angular.module('pascalprecht.translate').provider('$translate', ['$STORAGE_KEY', $storagePrefix, $missingTranslationHandlerFactory, $interpolationFactory, + $interpolatorFactories = [], $loaderFactory, $loaderOptions, $notFoundIndicatorLeft, @@ -147,6 +148,20 @@ angular.module('pascalprecht.translate').provider('$translate', ['$STORAGE_KEY', this.translations = translations; + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#addInterpolation + * @methodOf pascalprecht.$translateProvider + * + * @description + * Adds interpolation services to angular-translate, so it can manage them. + * + * @param {object} factory Interpolation service factory + */ + this.addInterpolation = function (factory) { + $interpolatorFactories.push(factory); + }; + /** * @ngdoc function * @name pascalprecht.translate.$translateProvider#useMessageFormatInterpolation @@ -491,8 +506,21 @@ angular.module('pascalprecht.translate').provider('$translate', ['$STORAGE_KEY', function ($log, $injector, $rootScope, $q) { var Storage, - interpolate = $injector.get($interpolationFactory || '$translateDefaultInterpolation'), - pendingLoader = false; + interpolateFn = $injector.get($interpolationFactory || '$translateDefaultInterpolation').interpolate, + pendingLoader = false, + interpolatorHashMap = {}; + + // if we have additional interpolations that were added via + // $translateProvider.addInterpolation(), we have to map'em + if ($interpolatorFactories.length) { + angular.forEach($interpolatorFactories, function (interpolatorFactory) { + var interpolator = $injector.get(interpolatorFactory); + // setting initial locale for each interpolation service + interpolator.setLocale($preferredLanguage || $uses); + // make'em recognizable through id + interpolatorHashMap[interpolator.getInterpolationIdentifier()] = interpolator; + }); + } if ($storageFactory) { Storage = $injector.get($storageFactory); @@ -502,17 +530,19 @@ angular.module('pascalprecht.translate').provider('$translate', ['$STORAGE_KEY', } } - var $translate = function (translationId, interpolateParams) { - var table = $uses ? $translationTable[$uses] : $translationTable; + var $translate = function (translationId, interpolateParams, interpolationId) { + var table = $uses ? $translationTable[$uses] : $translationTable, + interpolate = (interpolationId) ? interpolatorHashMap[interpolationId].interpolate : interpolateFn; + if (table && table.hasOwnProperty(translationId)) { - return interpolate(table[translationId], interpolateParams, $uses); + return interpolate(table[translationId], interpolateParams); } if ($uses && $fallbackLanguage && $uses !== $fallbackLanguage){ var translation = $translationTable[$fallbackLanguage][translationId]; if (translation) { - return interpolate(translation, interpolateParams, $fallbackLanguage); + return interpolate(translation, interpolateParams); } } diff --git a/test/unit/translateServiceSpec.js b/test/unit/translateServiceSpec.js index a82338991..4194c77ae 100644 --- a/test/unit/translateServiceSpec.js +++ b/test/unit/translateServiceSpec.js @@ -643,4 +643,122 @@ describe('pascalprecht.translate', function () { }); }); + + describe('interpolations', function () { + + describe('addInterpolation', function () { + + var $translate; + + beforeEach(module('pascalprecht.translate', function ($translateProvider, $provide) { + + // building custom interpolation service + $provide.factory('customInterpolation', function () { + + var translateInterpolator = {}, + $locale; + + // provide a method to set locale + translateInterpolator.setLocale = function (locale) { + $locale = locale; + }; + + // provide a method to return an interpolation identifier + translateInterpolator.getInterpolationIdentifier = function () { + return 'custom'; + } + + // defining the actual interpolate function + translateInterpolator.interpolate = function (string, interpolateParams) { + return 'custom interpolation'; + }; + + return translateInterpolator; + }); + + // tell angular-translate to optionally use customInterpolation + $translateProvider.addInterpolation('customInterpolation'); + + // register translations + $translateProvider.translations('en', { + 'FOO': 'Some text' + }); + + // set default language + $translateProvider.preferredLanguage('en'); + })); + + beforeEach(inject(function (_$translate_) { + $translate = _$translate_; + })); + + it('should translate', function () { + expect($translate('FOO')).toEqual('Some text'); + }); + + it('should use custom interpolation', function () { + expect($translate('FOO', {}, 'custom')).toEqual('custom interpolation'); + }); + }); + + describe('addInterpolation messageformat', function () { + + var $translate; + + beforeEach(module('pascalprecht.translate', function ($translateProvider) { + + $translateProvider.translations('en', { + 'REPLACE_VARS': 'Foo bar {value}', + 'SELECT_FORMAT': '{GENDER, select, male{He} female{She} other{They}} liked this.', + 'PLURAL_FORMAT': 'There {NUM_RESULTS, plural, one{is one result} other{are # results}}.', + 'PLURAL_FORMAT_OFFSET': 'You {NUM_ADDS, plural, offset:1' + + '=0{didnt add this to your profile}' + // Number literals, with a `=` do **NOT** use + 'zero{added this to your profile}' + // the offset value + 'one{and one other person added this to their profile}' + + 'other{and # others added this to their profiles}' + + '}.', + }); + + $translateProvider.addInterpolation('$translateMessageFormatInterpolation'); + $translateProvider.preferredLanguage('en'); + })); + + beforeEach(inject(function (_$translate_) { + $translate = _$translate_; + })); + + it('should replace interpolateParams with concrete values', function () { + expect($translate('REPLACE_VARS', { value: 5 }, 'messageformat')).toEqual('Foo bar 5'); + }); + + it('should support SelectFormat', function () { + expect($translate('SELECT_FORMAT', { GENDER: 'male'}, 'messageformat')) + .toEqual('He liked this.'); + expect($translate('SELECT_FORMAT', { GENDER: 'female'}, 'messageformat')) + .toEqual('She liked this.'); + expect($translate('SELECT_FORMAT', {}, 'messageformat')) + .toEqual('They liked this.'); + }); + + it('should support PluralFormat', function () { + expect($translate('PLURAL_FORMAT', { + 'NUM_RESULTS': 0 + }, 'messageformat')).toEqual('There are 0 results.'); + + expect($translate('PLURAL_FORMAT', { + 'NUM_RESULTS': 1 + }, 'messageformat')).toEqual('There is one result.'); + + expect($translate('PLURAL_FORMAT', { + 'NUM_RESULTS': 100 + }, 'messageformat')).toEqual('There are 100 results.'); + }); + + it('should support PluralFormat - offset extension', function () { + expect($translate('PLURAL_FORMAT_OFFSET', { 'NUM_ADDS': 0 }, 'messageformat')).toEqual('You didnt add this to your profile.'); + expect($translate('PLURAL_FORMAT_OFFSET', { 'NUM_ADDS': 2 }, 'messageformat')).toEqual('You and one other person added this to their profile.'); + expect($translate('PLURAL_FORMAT_OFFSET', { 'NUM_ADDS': 3 }, 'messageformat')).toEqual('You and 2 others added this to their profiles.'); + }); + }); + }); });