├── .gitignore ├── .travis.yml ├── bower.json ├── CONTRIBUTING.md ├── .jscs.json ├── karma.conf.js ├── karma.min.conf.js ├── LICENSE ├── package.json ├── Gruntfile.js ├── README.md ├── tmhDynamicLocale.min.js ├── tmhDynamicLocale.min.js.map ├── src └── tmhDynamicLocale.js └── test └── tmhDynamicLocaleSpec.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | components 3 | .rcs 4 | *.swp 5 | .idea 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.10 4 | 5 | before_install: 6 | - npm install -g grunt-cli bower 7 | 8 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "Lucas Galfaso", 3 | "name": "angular-dynamic-locale", 4 | "main": "src/tmhDynamicLocale.js", 5 | "description": "Angular Dynamic Locale", 6 | "version": "0.1.23", 7 | } 8 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | CONTRIBUTING 2 | ============ 3 | 4 | * Open a [Pull Request (PR)](https://github.com/lgalfaso/angular-dynamic-locale/pull/new/master) 5 | * Make sure your PR is on a **new branch** you created off of the latest version of master 6 | * Do **not** open a PR from your master branch 7 | * Open a PR to start a discussion even if the code isn't finished (easier to collect feedback this way) 8 | * Make sure all previous tests pass and add new tests for added behaviors 9 | -------------------------------------------------------------------------------- /.jscs.json: -------------------------------------------------------------------------------- 1 | { 2 | "disallowKeywords": ["with"], 3 | "disallowMixedSpacesAndTabs": true, 4 | "disallowMultipleLineStrings": true, 5 | "disallowNewlineBeforeBlockStatements": true, 6 | "disallowSpaceAfterObjectKeys": true, 7 | "disallowSpaceAfterPrefixUnaryOperators": ["!"], 8 | "disallowSpaceBeforeBinaryOperators": [","], 9 | "disallowSpacesInsideParentheses": true, 10 | "disallowTrailingComma": true, 11 | "disallowTrailingWhitespace": true, 12 | "requireSpaceAfterKeywords": ["if", "else", "for", "while", "do", "switch", "return", "try", "catch"], 13 | "validateParameterSeparator": ", " 14 | } 15 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = function(config) { 2 | config.set({ 3 | autoWatch: false, 4 | singleRun: true, 5 | logLevel: config.LOG_INFO, 6 | logColors: true, 7 | browsers: ['Chrome'], 8 | files: [ 9 | 'node_modules/angular/angular.js', 10 | 'node_modules/angular-cookies/angular-cookies.js', 11 | 'node_modules/angular-mocks/angular-mocks.js', 12 | {pattern: 'node_modules/angular-i18n/*.js', included: false, served: true}, 13 | 'src/*.js', 14 | 'test/*Spec.js' 15 | ], 16 | junitReporter: { 17 | outputFile: 'test_out/unit.xml', 18 | suite: 'unit' 19 | }, 20 | frameworks: ['jasmine'] 21 | }); 22 | }; 23 | -------------------------------------------------------------------------------- /karma.min.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = function(config) { 2 | config.set({ 3 | autoWatch: false, 4 | singleRun: true, 5 | logLevel: config.LOG_INFO, 6 | logColors: true, 7 | browsers: ['Chrome'], 8 | files: [ 9 | 'node_modules/angular/angular.js', 10 | 'node_modules/angular-cookies/angular-cookies.js', 11 | 'node_modules/angular-mocks/angular-mocks.js', 12 | {pattern: 'node_modules/angular-i18n/*.js', included: false, served: true}, 13 | '*.min.js', 14 | 'test/*Spec.js' 15 | ], 16 | junitReporter: { 17 | outputFile: 'test_out/unit.xml', 18 | suite: 'unit' 19 | }, 20 | frameworks: ['jasmine'] 21 | }); 22 | }; 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2013 Lucas Galfasó 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-dynamic-locale", 3 | "version": "0.1.23", 4 | "description": "A minimal module that adds the ability to dynamically change the locale", 5 | "license": "MIT License, http://www.opensource.org/licenses/MIT", 6 | "devDependencies": { 7 | "angular": "1.3.0", 8 | "angular-cookies": "1.3.0", 9 | "angular-i18n": "1.3.0", 10 | "angular-mocks": "1.3.0", 11 | "grunt": "^0.4.1", 12 | "grunt-bump": "0.0.13", 13 | "grunt-contrib-clean": "0.5.0", 14 | "grunt-contrib-concat": "0.3.0", 15 | "grunt-contrib-copy": "^0.4.1", 16 | "grunt-contrib-jshint": "^0.8.0", 17 | "grunt-contrib-uglify": "^0.5.0", 18 | "grunt-contrib-watch": "^0.5.1", 19 | "grunt-jscs": "^0.8.1", 20 | "grunt-karma": "^0.8.2", 21 | "grunt-npm": "0.0.2", 22 | "karma": "^0.12.1", 23 | "karma-chrome-launcher": "0.1.2", 24 | "karma-firefox-launcher": "0.1.3", 25 | "karma-jasmine": "0.2.2", 26 | "karma-phantomjs-launcher": "0.1.2" 27 | }, 28 | "main": "./src/tmhDynamicLocale.js", 29 | "scripts": { 30 | "test": "grunt karma:travis" 31 | }, 32 | "repository": { 33 | "type": "git", 34 | "url": "git://github.com/lgalfaso/angular-dynamic-locale.git" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | module.exports = function(grunt) { 5 | //grunt plugins 6 | grunt.loadNpmTasks('grunt-contrib-clean'); 7 | grunt.loadNpmTasks('grunt-contrib-copy'); 8 | grunt.loadNpmTasks('grunt-contrib-jshint'); 9 | grunt.loadNpmTasks('grunt-jscs'); 10 | grunt.loadNpmTasks('grunt-karma'); 11 | grunt.loadNpmTasks('grunt-bump'); 12 | grunt.loadNpmTasks('grunt-npm'); 13 | grunt.loadNpmTasks('grunt-contrib-uglify'); 14 | 15 | grunt.initConfig({ 16 | jshint: { 17 | all: ['Gruntfile.js', 'src/*.js', 'test/*.js'] 18 | }, 19 | jscs: { 20 | src: ['src/**/*.js', 'test/**/*.js'], 21 | options: { 22 | config: ".jscs.json" 23 | } 24 | }, 25 | karma: { 26 | unit: { configFile: 'karma.conf.js' }, 27 | 'unit.min': { 28 | configFile: 'karma.min.conf.js' 29 | }, 30 | autotest: { 31 | configFile: 'karma.conf.js', 32 | autoWatch: true, 33 | singleRun: false 34 | }, 35 | travis: { 36 | configFile: 'karma.conf.js', 37 | reporters: 'dots', 38 | browsers: ['PhantomJS'] 39 | } 40 | }, 41 | uglify: { 42 | all: { 43 | files: { 44 | 'tmhDynamicLocale.min.js': ['src/*.js'] 45 | }, 46 | options: { 47 | sourceMap: true 48 | } 49 | } 50 | }, 51 | bump: { 52 | options: { 53 | files: ['package.json', 'bower.json'], 54 | commitFiles: ['package.json', 'bower.json'], 55 | tagName: '%VERSION%', 56 | pushTo: 'origin' 57 | } 58 | }, 59 | 'npm-publish': { 60 | options: { 61 | requires: ['jshint', 'karma:unit', 'bump'], 62 | abortIfDirty: true 63 | } 64 | } 65 | }); 66 | grunt.registerTask('release', ['jshint', 'jscs', 'karma:unit', 'uglify:all', 'karma:unit.min', 'bump', 'publish']); 67 | }; 68 | }()); 69 | 70 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Angular Dynamic Locale 2 | 3 | *** 4 | 5 | ## Usage 6 | 7 | ### Requirements 8 | 9 | * **AngularJS v1.0.7+** is currently required. 10 | 11 | ### Changing the locale 12 | 13 | This module defines two services, these are `tmhDynamicLocale` and 14 | `tmhDynamicLocaleCache`. 15 | 16 | The service `tmhDynamicLocale` provides has one method `set(newLocale)` to 17 | change the locale. 18 | 19 | ```javascript 20 | tmhDynamicLocale.set('it'); 21 | ``` 22 | 23 | Keep in mind that the locale will be changed asynchronously 24 | 25 | 26 | After the locale is changed, the event `'$localeChangeSuccess'` will be 27 | triggered. 28 | 29 | Calling `tmhDynamicLocale.set` will return a promise that will be resolved 30 | when the locale is loaded and will resolve to the new locale. 31 | 32 | The service `tmhDynamicLocaleCache` is a `$cache` of all the loaded locales, 33 | where the key is the locale id and the value is the locale object. 34 | 35 | 36 | This module expects for the angular locales to be present at 37 | `angular/i18n/angular-locale_{{locale}}.js`. 38 | If the locales are at another URL, this can be changed at 39 | `tmhDynamicLocaleProvider` using `localeLocationPattern(string)`. 40 | 41 | 42 | It is possible to specify a storage location for the locale using 43 | `tmhDynamicLocaleProvider.useStorage(storageName)`, the name of the 44 | storage must follow the same signature as `$cookieStore`. The default 45 | storage location is to use a `$cache`, this default storage is not persistent. 46 | 47 | It is possible to ask the storage to be `$cookieStore` using the shortcut 48 | `tmhDynamicLocaleProvider.useCookieStorage()`, internally this is 49 | exactly as performing `tmhDynamicLocaleProvider.useStorage('$cookieStore')` 50 | 51 | ## Installation 52 | 53 | Add the module to your dependencies 54 | 55 | ```javascript 56 | angular.module('myApp', ['tmh.dynamicLocale', ...]) 57 | ``` 58 | 59 | 60 | ## Development 61 | 62 | ### Requirements 63 | 64 | 0. Install [Node.js](http://nodejs.org/) and NPM (should come with) 65 | 66 | 1. Install global dependencies `grunt-cli` and `bower`: 67 | 68 | ```bash 69 | $ npm install -g grunt-cli bower 70 | ``` 71 | 72 | 2. Install local dependencies: 73 | 74 | ```bash 75 | $ npm install 76 | ``` 77 | 78 | ### Running the tests 79 | 80 | ```bash 81 | $ grunt karma:unit 82 | ``` 83 | to run the test once 84 | 85 | or 86 | 87 | ```bash 88 | $ grunt karma:autotest 89 | ``` 90 | to run the tests continuously 91 | 92 | -------------------------------------------------------------------------------- /tmhDynamicLocale.min.js: -------------------------------------------------------------------------------- 1 | !function(){"use strict";angular.module("tmh.dynamicLocale",[]).config(["$provide",function(a){function b(a){return a.$stateful=!0,a}a.decorator("dateFilter",["$delegate",b]),a.decorator("numberFilter",["$delegate",b]),a.decorator("currencyFilter",["$delegate",b])}]).constant("tmhDynamicLocale.STORAGE_KEY","tmhDynamicLocale.locale").provider("tmhDynamicLocale",["tmhDynamicLocale.STORAGE_KEY",function(a){function b(a,b,c,d){var e=document.createElement("script"),f=document.getElementsByTagName("body")[0],g=!1;e.type="text/javascript",e.readyState?e.onreadystatechange=function(){("complete"===e.readyState||"loaded"===e.readyState)&&(e.onreadystatechange=null,d(function(){g||(g=!0,f.removeChild(e),b())},30,!1))}:(e.onload=function(){g||(g=!0,f.removeChild(e),b())},e.onerror=function(){g||(g=!0,f.removeChild(e),c())}),e.src=a,e.async=!1,f.appendChild(e)}function c(a,c,d,g,h,k,l){function m(a,b){f===d&&(angular.forEach(a,function(c,d){b[d]?angular.isArray(b[d])&&(a[d].length=b[d].length):delete a[d]}),angular.forEach(b,function(c,d){angular.isArray(b[d])||angular.isObject(b[d])?(a[d]||(a[d]=angular.isArray(b[d])?[]:{}),m(a[d],b[d])):a[d]=b[d]}))}if(j[d])return j[d];var n,o=h.defer();return d===f?o.resolve(c):(n=k.get(d))?(f=d,g.$evalAsync(function(){m(c,n),g.$broadcast("$localeChangeSuccess",d,c),e.put(i,d),o.resolve(c)})):(f=d,j[d]=o.promise,b(a,function(){var a=angular.injector(["ngLocale"]),b=a.get("$locale");m(c,b),k.put(d,b),delete j[d],g.$apply(function(){g.$broadcast("$localeChangeSuccess",d,c),e.put(i,d),o.resolve(c)})},function(){delete j[d],g.$apply(function(){f===d&&(f=c.id),g.$broadcast("$localeChangeError",d),o.reject(d)})},l)),o.promise}var d,e,f,g="angular/i18n/angular-locale_{{locale}}.js",h="tmhDynamicLocaleStorageCache",i=a,j={};this.localeLocationPattern=function(a){return a?(g=a,this):g},this.useStorage=function(a){h=a},this.useCookieStorage=function(){this.useStorage("$cookieStore")},this.defaultLocale=function(a){d=a},this.storageKey=function(a){return a?(i=a,this):i},this.$get=["$rootScope","$injector","$interpolate","$locale","$q","tmhDynamicLocaleCache","$timeout",function(a,b,j,k,l,m,n){var o=j(g);return e=b.get(h),a.$evalAsync(function(){var b;(b=e.get(i)||d)&&c(o({locale:b}),k,b,a,l,m,n)}),{set:function(b){return c(o({locale:b}),k,b,a,l,m,n)},get:function(){return f}}}]}]).provider("tmhDynamicLocaleCache",function(){this.$get=["$cacheFactory",function(a){return a("tmh.dynamicLocales")}]}).provider("tmhDynamicLocaleStorageCache",function(){this.$get=["$cacheFactory",function(a){return a("tmh.dynamicLocales.store")}]}).run(["tmhDynamicLocale",angular.noop])}(window); 2 | //# sourceMappingURL=tmhDynamicLocale.min.js.map -------------------------------------------------------------------------------- /tmhDynamicLocale.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"tmhDynamicLocale.min.js","sources":["src/tmhDynamicLocale.js"],"names":["angular","module","config","$provide","makeStateful","$delegate","$stateful","decorator","constant","provider","STORAGE_KEY","loadScript","url","callback","errorCallback","$timeout","script","document","createElement","body","getElementsByTagName","removed","type","readyState","onreadystatechange","removeChild","onload","onerror","src","async","appendChild","loadLocale","localeUrl","$locale","localeId","$rootScope","$q","localeCache","overrideValues","oldObject","newObject","activeLocale","forEach","value","key","isArray","length","isObject","promiseCache","cachedLocale","deferred","defer","resolve","get","$evalAsync","$broadcast","storage","put","storageKey","promise","localInjector","injector","externalLocale","$apply","id","reject","defaultLocale","localeLocationPattern","storageFactory","this","useStorage","storageName","useCookieStorage","$get","$injector","interpolate","locale","tmhDynamicLocaleCache","localeLocation","initialLocale","set","$cacheFactory","run","noop","window"],"mappings":"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"} -------------------------------------------------------------------------------- /src/tmhDynamicLocale.js: -------------------------------------------------------------------------------- 1 | (function(window) { 2 | 'use strict'; 3 | angular.module('tmh.dynamicLocale', []).config(['$provide', function ($provide) { 4 | function makeStateful($delegate) { 5 | $delegate.$stateful = true; 6 | return $delegate; 7 | } 8 | 9 | $provide.decorator('dateFilter', ['$delegate', makeStateful]); 10 | $provide.decorator('numberFilter', ['$delegate', makeStateful]); 11 | $provide.decorator('currencyFilter', ['$delegate', makeStateful]); 12 | 13 | }]) 14 | .constant('tmhDynamicLocale.STORAGE_KEY', 'tmhDynamicLocale.locale') 15 | .provider('tmhDynamicLocale', ['tmhDynamicLocale.STORAGE_KEY', function(STORAGE_KEY) { 16 | 17 | var defaultLocale, 18 | localeLocationPattern = 'angular/i18n/angular-locale_{{locale}}.js', 19 | storageFactory = 'tmhDynamicLocaleStorageCache', 20 | storage, 21 | storageKey = STORAGE_KEY, 22 | promiseCache = {}, 23 | activeLocale; 24 | 25 | /** 26 | * Loads a script asynchronously 27 | * 28 | * @param {string} url The url for the script 29 | @ @param {function) callback A function to be called once the script is loaded 30 | */ 31 | function loadScript(url, callback, errorCallback, $timeout) { 32 | var script = document.createElement('script'), 33 | body = document.getElementsByTagName('body')[0], 34 | removed = false; 35 | 36 | script.type = 'text/javascript'; 37 | if (script.readyState) { // IE 38 | script.onreadystatechange = function () { 39 | if (script.readyState === 'complete' || 40 | script.readyState === 'loaded') { 41 | script.onreadystatechange = null; 42 | $timeout( 43 | function () { 44 | if (removed) return; 45 | removed = true; 46 | body.removeChild(script); 47 | callback(); 48 | }, 30, false); 49 | } 50 | }; 51 | } else { // Others 52 | script.onload = function () { 53 | if (removed) return; 54 | removed = true; 55 | body.removeChild(script); 56 | callback(); 57 | }; 58 | script.onerror = function () { 59 | if (removed) return; 60 | removed = true; 61 | body.removeChild(script); 62 | errorCallback(); 63 | }; 64 | } 65 | script.src = url; 66 | script.async = false; 67 | body.appendChild(script); 68 | } 69 | 70 | /** 71 | * Loads a locale and replaces the properties from the current locale with the new locale information 72 | * 73 | * @param localeUrl The path to the new locale 74 | * @param $locale The locale at the curent scope 75 | */ 76 | function loadLocale(localeUrl, $locale, localeId, $rootScope, $q, localeCache, $timeout) { 77 | 78 | function overrideValues(oldObject, newObject) { 79 | if (activeLocale !== localeId) { 80 | return; 81 | } 82 | angular.forEach(oldObject, function(value, key) { 83 | if (!newObject[key]) { 84 | delete oldObject[key]; 85 | } else if (angular.isArray(newObject[key])) { 86 | oldObject[key].length = newObject[key].length; 87 | } 88 | }); 89 | angular.forEach(newObject, function(value, key) { 90 | if (angular.isArray(newObject[key]) || angular.isObject(newObject[key])) { 91 | if (!oldObject[key]) { 92 | oldObject[key] = angular.isArray(newObject[key]) ? [] : {}; 93 | } 94 | overrideValues(oldObject[key], newObject[key]); 95 | } else { 96 | oldObject[key] = newObject[key]; 97 | } 98 | }); 99 | } 100 | 101 | 102 | if (promiseCache[localeId]) return promiseCache[localeId]; 103 | 104 | var cachedLocale, 105 | deferred = $q.defer(); 106 | if (localeId === activeLocale) { 107 | deferred.resolve($locale); 108 | } else if ((cachedLocale = localeCache.get(localeId))) { 109 | activeLocale = localeId; 110 | $rootScope.$evalAsync(function() { 111 | overrideValues($locale, cachedLocale); 112 | $rootScope.$broadcast('$localeChangeSuccess', localeId, $locale); 113 | storage.put(storageKey, localeId); 114 | deferred.resolve($locale); 115 | }); 116 | } else { 117 | activeLocale = localeId; 118 | promiseCache[localeId] = deferred.promise; 119 | loadScript(localeUrl, function () { 120 | // Create a new injector with the new locale 121 | var localInjector = angular.injector(['ngLocale']), 122 | externalLocale = localInjector.get('$locale'); 123 | 124 | overrideValues($locale, externalLocale); 125 | localeCache.put(localeId, externalLocale); 126 | delete promiseCache[localeId]; 127 | 128 | $rootScope.$apply(function () { 129 | $rootScope.$broadcast('$localeChangeSuccess', localeId, $locale); 130 | storage.put(storageKey, localeId); 131 | deferred.resolve($locale); 132 | }); 133 | }, function () { 134 | delete promiseCache[localeId]; 135 | 136 | $rootScope.$apply(function () { 137 | if (activeLocale === localeId) activeLocale = $locale.id; 138 | $rootScope.$broadcast('$localeChangeError', localeId); 139 | deferred.reject(localeId); 140 | }); 141 | }, $timeout); 142 | } 143 | return deferred.promise; 144 | } 145 | 146 | this.localeLocationPattern = function(value) { 147 | if (value) { 148 | localeLocationPattern = value; 149 | return this; 150 | } else { 151 | return localeLocationPattern; 152 | } 153 | }; 154 | 155 | this.useStorage = function(storageName) { 156 | storageFactory = storageName; 157 | }; 158 | 159 | this.useCookieStorage = function() { 160 | this.useStorage('$cookieStore'); 161 | }; 162 | 163 | this.defaultLocale = function (value) { 164 | defaultLocale = value; 165 | }; 166 | 167 | this.storageKey = function (value) { 168 | if (value) { 169 | storageKey = value; 170 | return this; 171 | } else { 172 | return storageKey; 173 | } 174 | }; 175 | 176 | this.$get = ['$rootScope', '$injector', '$interpolate', '$locale', '$q', 'tmhDynamicLocaleCache', '$timeout', function($rootScope, $injector, interpolate, locale, $q, tmhDynamicLocaleCache, $timeout) { 177 | var localeLocation = interpolate(localeLocationPattern); 178 | 179 | storage = $injector.get(storageFactory); 180 | $rootScope.$evalAsync(function () { 181 | var initialLocale; 182 | if ((initialLocale = (storage.get(storageKey) || defaultLocale))) { 183 | loadLocale(localeLocation({locale: initialLocale}), locale, initialLocale, $rootScope, $q, tmhDynamicLocaleCache, $timeout); 184 | } 185 | }); 186 | return { 187 | /** 188 | * @ngdoc method 189 | * @description 190 | * @param {string=} value Sets the locale to the new locale. Changing the locale will trigger 191 | * a background task that will retrieve the new locale and configure the current $locale 192 | * instance with the information from the new locale 193 | */ 194 | set: function(value) { 195 | return loadLocale(localeLocation({locale: value}), locale, value, $rootScope, $q, tmhDynamicLocaleCache, $timeout); 196 | }, 197 | /** 198 | * @ngdoc method 199 | * @description Returns the configured locale 200 | */ 201 | get: function() { 202 | return activeLocale; 203 | } 204 | }; 205 | }]; 206 | }]).provider('tmhDynamicLocaleCache', function() { 207 | this.$get = ['$cacheFactory', function($cacheFactory) { 208 | return $cacheFactory('tmh.dynamicLocales'); 209 | }]; 210 | }).provider('tmhDynamicLocaleStorageCache', function() { 211 | this.$get = ['$cacheFactory', function($cacheFactory) { 212 | return $cacheFactory('tmh.dynamicLocales.store'); 213 | }]; 214 | }).run(['tmhDynamicLocale', angular.noop]); 215 | }(window)); 216 | -------------------------------------------------------------------------------- /test/tmhDynamicLocaleSpec.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | // Minimal implementation to mock what was removed from Jasmine 1.x 5 | function createAsync(doneFn) { 6 | function Job() { 7 | this.next = []; 8 | } 9 | Job.prototype.done = function () { 10 | return this.runs(doneFn); 11 | }; 12 | Job.prototype.runs = function (fn) { 13 | var newJob = new Job(); 14 | this.next.push(function () { 15 | fn(); 16 | newJob.start(); 17 | }); 18 | return newJob; 19 | }; 20 | Job.prototype.waitsFor = function (fn, error, timeout) { 21 | var newJob = new Job(); 22 | timeout = timeout || 5000; 23 | this.next.push(function () { 24 | var counter = 0, 25 | intervalId = window.setInterval(function () { 26 | if (fn()) { 27 | window.clearInterval(intervalId); 28 | newJob.start(); 29 | } 30 | counter += 5; 31 | if (counter > timeout) { 32 | window.clearInterval(intervalId); 33 | throw new Error(error); 34 | } 35 | }, 5); 36 | }); 37 | return newJob; 38 | }; 39 | Job.prototype.start = function () { 40 | var i; 41 | for (i = 0; i < this.next.length; i += 1) { 42 | this.next[i](); 43 | } 44 | }; 45 | return new Job(); 46 | } 47 | 48 | describe('dynamicLocale', function() { 49 | beforeEach(module('tmh.dynamicLocale')); 50 | beforeEach(module(function(tmhDynamicLocaleProvider) { 51 | tmhDynamicLocaleProvider.localeLocationPattern('/base/node_modules/angular-i18n/angular-locale_{{locale}}.js'); 52 | })); 53 | 54 | afterEach(function (done) { 55 | inject(function($locale, $timeout, tmhDynamicLocale) { 56 | var job = createAsync(done); 57 | job 58 | .runs(function() { 59 | tmhDynamicLocale.set('en-us'); 60 | }) 61 | .waitsFor(function() { 62 | $timeout.flush(50); 63 | return $locale.id === 'en-us'; 64 | }, 'locale not reverted', 2000) 65 | .done(); 66 | job.start(); 67 | }); 68 | }); 69 | 70 | it('should (eventually) be able to change the locale', function(done) { 71 | inject(function($locale, $timeout, tmhDynamicLocale) { 72 | var job = createAsync(done); 73 | job 74 | .runs(function() { 75 | tmhDynamicLocale.set('es'); 76 | }) 77 | .waitsFor(function() { 78 | $timeout.flush(50); 79 | return $locale.id === 'es'; 80 | }, 'locale not updated', 2000) 81 | .runs(function() { 82 | expect($locale.id).toBe('es'); 83 | expect($locale.DATETIME_FORMATS.DAY["0"]).toBe("domingo"); 84 | }) 85 | .done(); 86 | job.start(); 87 | }); 88 | }); 89 | 90 | it('should trigger an event when there it changes the locale', function(done) { 91 | inject(function($timeout, $locale, tmhDynamicLocale, $rootScope) { 92 | var callback = jasmine.createSpy(); 93 | var job = createAsync(done); 94 | job 95 | .runs(function() { 96 | $rootScope.$apply(); 97 | $rootScope.$on('$localeChangeSuccess', callback); 98 | tmhDynamicLocale.set('es'); 99 | expect(callback.calls.count()).toBe(0); 100 | }) 101 | .waitsFor(function() { 102 | $timeout.flush(50); 103 | return $locale.id === 'es'; 104 | }, 'locale not updated', 2000) 105 | .runs(function() { 106 | expect(callback.calls.count()).toBe(1); 107 | expect(callback.calls.argsFor(0)[1]).toEqual('es'); 108 | expect(callback.calls.argsFor(0)[2]).toEqual($locale); 109 | }) 110 | .done(); 111 | job.start(); 112 | }); 113 | }); 114 | 115 | it('should trigger a failure even when the locale change fail', function(done) { 116 | inject(function($timeout, $locale, tmhDynamicLocale, $rootScope) { 117 | var job = createAsync(done); 118 | var callback = jasmine.createSpy(); 119 | 120 | job 121 | .runs(function() { 122 | $rootScope.$apply(); 123 | $rootScope.$on('$localeChangeError', callback); 124 | tmhDynamicLocale.set('invalidLocale'); 125 | expect(callback.calls.count()).toBe(0); 126 | }) 127 | .waitsFor(function() { 128 | $timeout.flush(50); 129 | return callback.calls.count() !== 0; 130 | }, 'error not generated', 2000) 131 | .runs(function() { 132 | expect(callback.calls.count()).toBe(1); 133 | expect(callback.calls.argsFor(0)[1]).toEqual('invalidLocale'); 134 | }) 135 | .done(); 136 | job.start(); 137 | }); 138 | }); 139 | 140 | it('should return a promise that has the new locale', function(done) { 141 | inject(function($timeout, $locale, tmhDynamicLocale, $rootScope) { 142 | var job = createAsync(done); 143 | var callback = jasmine.createSpy(); 144 | 145 | job 146 | .runs(function() { 147 | tmhDynamicLocale.set('es').then(callback); 148 | expect(callback.calls.count()).toBe(0); 149 | }) 150 | .waitsFor(function() { 151 | $timeout.flush(50); 152 | return callback.calls.count() !== 0; 153 | }, 'locale not updated', 2000) 154 | .runs(function() { 155 | expect(callback.calls.argsFor(0)[0].id).toEqual('es'); 156 | expect(callback.calls.argsFor(0)[0]).toEqual($locale); 157 | tmhDynamicLocale.set('it'); 158 | }) 159 | .waitsFor(function() { 160 | $timeout.flush(50); 161 | return $locale.id === 'it'; 162 | }, 'locale not updated', 2000) 163 | .runs(function() { 164 | tmhDynamicLocale.set('es').then(callback); 165 | expect(callback.calls.count()).toBe(1); 166 | $rootScope.$apply(); 167 | expect(callback.calls.count()).toBe(2); 168 | expect(callback.calls.argsFor(1)[0].id).toBe('es'); 169 | expect(callback.calls.argsFor(1)[0]).toBe($locale); 170 | }) 171 | .done(); 172 | job.start(); 173 | }); 174 | }); 175 | 176 | it('should reject the returned promise if it fails to load the locale', function(done) { 177 | inject(function($timeout, $locale, tmhDynamicLocale, $rootScope) { 178 | var callback = jasmine.createSpy(); 179 | var errorCallback = jasmine.createSpy(); 180 | var job = createAsync(done); 181 | 182 | job 183 | .runs(function() { 184 | tmhDynamicLocale.set('invalidLocale').then(callback, errorCallback); 185 | }) 186 | .waitsFor(function() { 187 | $timeout.flush(50); 188 | return errorCallback.calls.count(); 189 | }, 'promise not rejected', 2000) 190 | .runs(function() { 191 | expect(callback.calls.count()).toBe(0); 192 | expect(errorCallback.calls.count()).toBe(1); 193 | expect(errorCallback.calls.argsFor(0)[0]).toBe('invalidLocale'); 194 | expect($locale.id).toBe('en-us'); 195 | }) 196 | .done(); 197 | job.start(); 198 | }); 199 | }); 200 | 201 | it('should be possible to retrieve the locale to be', function(done) { 202 | inject(function($timeout, $locale, tmhDynamicLocale, $rootScope, $compile) { 203 | var job = createAsync(done); 204 | 205 | job 206 | .runs(function() { 207 | tmhDynamicLocale.set('es'); 208 | expect(tmhDynamicLocale.get()).toBe('es'); 209 | }) 210 | .waitsFor(function() { 211 | $timeout.flush(50); 212 | return $locale.id === 'es'; 213 | }, 'locale not updated', 2000) 214 | .runs(function() { 215 | expect(tmhDynamicLocale.get()).toBe('es'); 216 | }) 217 | .done(); 218 | job.start(); 219 | }); 220 | }); 221 | 222 | it('should revert the configured locale when the new locale does not exist', function(done) { 223 | inject(function($timeout, $locale, tmhDynamicLocale, $rootScope) { 224 | var job = createAsync(done); 225 | var errorCallback = jasmine.createSpy(); 226 | 227 | job 228 | .runs(function() { 229 | tmhDynamicLocale.set('es'); 230 | }) 231 | .waitsFor(function() { 232 | $timeout.flush(50); 233 | return $locale.id === 'es'; 234 | }, 'locale not updated', 2000) 235 | .runs(function() { 236 | tmhDynamicLocale.set('invalidLocale').then(undefined, errorCallback); 237 | expect(tmhDynamicLocale.get()).toBe('invalidLocale'); 238 | }) 239 | .waitsFor(function() { 240 | $timeout.flush(50); 241 | return errorCallback.calls.count(); 242 | }, 'promise not rejected', 2000) 243 | .runs(function() { 244 | expect(tmhDynamicLocale.get()).toBe('es'); 245 | }) 246 | .done(); 247 | job.start(); 248 | }); 249 | }); 250 | 251 | it('should change the already formatted numbers in the page', function(done) { 252 | inject(function($timeout, $locale, tmhDynamicLocale, $rootScope, $compile) { 253 | var job = createAsync(done); 254 | var element = null; 255 | 256 | job 257 | .runs(function() { 258 | element = $compile('{{val | number}}')($rootScope); 259 | 260 | $rootScope.val = 1234.5678; 261 | $rootScope.$apply(); 262 | expect(element.text()).toBe('1,234.568'); 263 | 264 | tmhDynamicLocale.set('es'); 265 | }) 266 | .waitsFor(function() { 267 | $timeout.flush(50); 268 | return $locale.id === 'es'; 269 | }, 'locale not updated', 2000) 270 | .runs(function() { 271 | expect(element.text()).toBe('1.234,568'); 272 | }) 273 | .done(); 274 | job.start(); 275 | }); 276 | }); 277 | 278 | it('should keep already loaded locales at tmhDynamicLocaleCache', function(done) { 279 | inject(function($timeout, $locale, tmhDynamicLocale, tmhDynamicLocaleCache, $rootScope) { 280 | var job = createAsync(done); 281 | var callback = jasmine.createSpy(); 282 | var esLocale = null; 283 | 284 | job 285 | .runs(function() { 286 | expect(tmhDynamicLocaleCache.info().size).toBe(0); 287 | tmhDynamicLocale.set('es'); 288 | expect(tmhDynamicLocaleCache.info().size).toBe(0); 289 | }) 290 | .waitsFor(function() { 291 | $timeout.flush(50); 292 | return $locale.id === 'es'; 293 | }, 'locale not updated', 2000) 294 | .runs(function() { 295 | expect(tmhDynamicLocaleCache.info().size).toBe(1); 296 | expect(tmhDynamicLocaleCache.get('es')).toEqual($locale); 297 | esLocale = angular.copy($locale); 298 | tmhDynamicLocale.set('it'); 299 | }) 300 | .waitsFor(function() { 301 | $timeout.flush(50); 302 | return $locale.id === 'it'; 303 | }, 'locale not updated', 2000) 304 | .runs(function() { 305 | expect(tmhDynamicLocaleCache.info().size).toBe(2); 306 | expect(tmhDynamicLocaleCache.get('es')).toEqual(esLocale); 307 | expect(tmhDynamicLocaleCache.get('it')).toEqual($locale); 308 | }) 309 | .done(); 310 | job.start(); 311 | }); 312 | }); 313 | 314 | it('should use the cache when possible', function(done) { 315 | inject(function($timeout, $locale, tmhDynamicLocale, tmhDynamicLocaleCache, $rootScope) { 316 | var job = createAsync(done); 317 | var callback = jasmine.createSpy(); 318 | 319 | job 320 | .runs(function() { 321 | tmhDynamicLocale.set('es'); 322 | }) 323 | .waitsFor(function() { 324 | $timeout.flush(50); 325 | return $locale.id === 'es'; 326 | }, 'locale not updated', 2000) 327 | .runs(function() { 328 | tmhDynamicLocale.set('it'); 329 | }) 330 | .waitsFor(function() { 331 | $timeout.flush(50); 332 | return $locale.id === 'it'; 333 | }, 'locale not updated', 2000) 334 | .runs(function() { 335 | tmhDynamicLocaleCache.get('es').DATETIME_FORMATS.DAY["0"] = "Domingo"; 336 | $rootScope.$on('$localeChangeSuccess', callback); 337 | tmhDynamicLocale.set('es'); 338 | // Changing the locale should be done async even when this is done from the cache 339 | expect(callback.calls.count()).toBe(0); 340 | expect($locale.id).toBe('it'); 341 | $rootScope.$apply(); 342 | expect($locale.id).toBe('es'); 343 | expect($locale.DATETIME_FORMATS.DAY["0"]).toBe("Domingo"); 344 | expect(callback.calls.count()).toBe(1); 345 | }) 346 | .done(); 347 | job.start(); 348 | }); 349 | }); 350 | 351 | it('should do a deep copy of the locale elements', function(done) { 352 | inject(function($timeout, $locale, tmhDynamicLocale, tmhDynamicLocaleCache, $rootScope) { 353 | var job = createAsync(done); 354 | 355 | job 356 | .runs(function() { 357 | tmhDynamicLocale.set('es'); 358 | }) 359 | .waitsFor(function() { 360 | $timeout.flush(50); 361 | return $locale.id === 'es'; 362 | }, 'locale not updated', 2000) 363 | .runs(function() { 364 | $locale.DATETIME_FORMATS.DAY["0"] = "XXX"; 365 | expect($locale.DATETIME_FORMATS.DAY["0"]).not.toBe(tmhDynamicLocaleCache.get('es').DATETIME_FORMATS.DAY["0"]); 366 | }) 367 | .done(); 368 | job.start(); 369 | }); 370 | }); 371 | 372 | it('should be able to handle locales with extra elements', function(done) { 373 | inject(function($timeout, $locale, tmhDynamicLocale, tmhDynamicLocaleCache, $rootScope) { 374 | var job = createAsync(done); 375 | var weirdLocale; 376 | 377 | job 378 | .runs(function() { 379 | tmhDynamicLocale.set('es'); 380 | }) 381 | .waitsFor(function() { 382 | $timeout.flush(50); 383 | return $locale.id === 'es'; 384 | }, 'locale not updated', 2000) 385 | .runs(function() { 386 | weirdLocale = angular.copy($locale); 387 | weirdLocale.id = "xx"; 388 | weirdLocale.EXTRA_PARAMETER = {foo: "FOO"}; 389 | weirdLocale.DATETIME_FORMATS.DAY["7"] = "One More Day"; 390 | tmhDynamicLocaleCache.put('xx', angular.copy(weirdLocale)); 391 | tmhDynamicLocale.set('xx'); 392 | }) 393 | .waitsFor(function() { 394 | $timeout.flush(50); 395 | return $locale.id === 'xx'; 396 | }, 'locale not updated', 2000) 397 | .runs(function() { 398 | expect($locale).toEqual(weirdLocale); 399 | expect($locale.EXTRA_PARAMETER).toEqual({foo: "FOO"}); 400 | tmhDynamicLocale.set('es'); 401 | }) 402 | .waitsFor(function() { 403 | $timeout.flush(50); 404 | return $locale.id === 'es'; 405 | }, 'locale not updated', 2000) 406 | .runs(function() { 407 | expect($locale.EXTRA_PARAMETER).toBeUndefined(); 408 | expect($locale.DATETIME_FORMATS.DAY["7"]).toBeUndefined(); 409 | expect($locale.DATETIME_FORMATS.DAY.length).toBe(7); 410 | }) 411 | .done(); 412 | job.start(); 413 | }); 414 | }); 415 | 416 | describe('having a default locale', function() { 417 | beforeEach(module(function(tmhDynamicLocaleProvider) { 418 | tmhDynamicLocaleProvider.defaultLocale('it'); 419 | })); 420 | it('should set the locale to the default locale', function(done) { 421 | inject(function($timeout, $locale, $rootScope) { 422 | var job = createAsync(done); 423 | 424 | job 425 | .runs(function() { 426 | expect($locale.id).toBe('en-us'); 427 | $rootScope.$apply(); 428 | }) 429 | .waitsFor(function() { 430 | $timeout.flush(50); 431 | return $locale.id === 'it'; 432 | }, 'locale not updated', 2000) 433 | .runs(function() { 434 | expect($locale.id).toBe('it'); 435 | }) 436 | .done(); 437 | job.start(); 438 | }); 439 | }); 440 | }); 441 | 442 | describe('having a cookie storage', function () { 443 | beforeEach(module('ngCookies')); 444 | beforeEach(module(function(tmhDynamicLocaleProvider) { 445 | tmhDynamicLocaleProvider.useCookieStorage(); 446 | })); 447 | 448 | it('should store the change on the cookie store', function(done) { 449 | inject(function ($timeout, $locale, $cookieStore, tmhDynamicLocale) { 450 | var job = createAsync(done); 451 | 452 | job 453 | .runs(function() { 454 | tmhDynamicLocale.set('es'); 455 | expect($cookieStore.get('tmhDynamicLocale.locale')).toBe(undefined); 456 | }) 457 | .waitsFor(function() { 458 | $timeout.flush(50); 459 | return $locale.id === 'es'; 460 | }, 'locale not updated', 2000) 461 | .runs(function() { 462 | expect($cookieStore.get('tmhDynamicLocale.locale')).toBe('es'); 463 | }) 464 | .done(); 465 | job.start(); 466 | }); 467 | }); 468 | describe('reading the locale at initialization', function () { 469 | beforeEach(inject(function ($cookieStore, $rootScope) { 470 | $cookieStore.put('tmhDynamicLocale.locale', 'it'); 471 | $rootScope.$apply(); 472 | })); 473 | 474 | it('should load the locale on initialization', function(done) { 475 | inject(function ($timeout, $locale, $rootScope) { 476 | var job = createAsync(done); 477 | 478 | job 479 | .runs(function() { 480 | expect($locale.id).toBe('en-us'); 481 | }) 482 | .waitsFor(function() { 483 | $timeout.flush(50); 484 | return $locale.id === 'it'; 485 | }, 'locale not updated', 2000) 486 | .runs(function() { 487 | expect($locale.id).toBe('it'); 488 | }) 489 | .done(); 490 | job.start(); 491 | }); 492 | }); 493 | }); 494 | describe('and having a default language', function () { 495 | beforeEach(module(function(tmhDynamicLocaleProvider) { 496 | tmhDynamicLocaleProvider.defaultLocale('es'); 497 | })); 498 | beforeEach(inject(function ($cookieStore, $rootScope) { 499 | $cookieStore.put('tmhDynamicLocale.locale', 'it'); 500 | $rootScope.$apply(); 501 | })); 502 | 503 | it('should load the locale on initialization', function(done) { 504 | inject(function ($timeout, $locale, $rootScope) { 505 | var job = createAsync(done); 506 | 507 | job 508 | .runs(function() { 509 | expect($locale.id).toBe('en-us'); 510 | }) 511 | .waitsFor(function() { 512 | $timeout.flush(50); 513 | return $locale.id === 'it'; 514 | }, 'locale not updated', 2000) 515 | .runs(function() { 516 | expect($locale.id).toBe('it'); 517 | }) 518 | .done(); 519 | job.start(); 520 | }); 521 | }); 522 | }); 523 | describe('and changing the name of the storageKey', function () { 524 | beforeEach(module(function(tmhDynamicLocaleProvider) { 525 | tmhDynamicLocaleProvider.storageKey('customStorageKeyName'); 526 | })); 527 | 528 | it('should change the name of the storageKey', function(done) { 529 | inject(function ($timeout, $locale, $cookieStore, tmhDynamicLocale) { 530 | var job = createAsync(done); 531 | 532 | job 533 | .runs(function() { 534 | tmhDynamicLocale.set('es'); 535 | expect($cookieStore.get('customStorageKeyName')).toBe(undefined); 536 | expect($cookieStore.get('tmhDynamicLocale.locale')).toBe(undefined); 537 | }) 538 | .waitsFor(function() { 539 | $timeout.flush(50); 540 | return $locale.id === 'es'; 541 | }, 'locale not updated', 2000) 542 | .runs(function() { 543 | expect($cookieStore.get('tmhDynamicLocale.locale')).toBe(undefined); 544 | expect($cookieStore.get('customStorageKeyName')).toBe('es'); 545 | }) 546 | .done(); 547 | job.start(); 548 | }); 549 | }); 550 | }); 551 | }); 552 | 553 | describe('loading locales using