diff --git a/src/Umbraco.Web.UI.Client/lib/angular/tmhDynamicLocale.js b/src/Umbraco.Web.UI.Client/lib/angular/tmhDynamicLocale.js new file mode 100644 index 0000000000..325475f951 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/lib/angular/tmhDynamicLocale.js @@ -0,0 +1,186 @@ +( function(window) { +'use strict'; +angular.module('tmh.dynamicLocale', []).provider('tmhDynamicLocale', function() { + + var defaultLocale, + localeLocationPattern = 'angular/i18n/angular-locale_{{locale}}.js', + storageFactory = 'tmhDynamicLocaleStorageCache', + storage, + storeKey = 'tmhDynamicLocale.locale', + promiseCache = {}, + activeLocale; + + /** + * Loads a script asynchronously + * + * @param {string} url The url for the script + @ @param {function) callback A function to be called once the script is loaded + */ + function loadScript(url, callback, errorCallback, $timeout) { + var script = document.createElement('script'), + body = document.getElementsByTagName('body')[0], + removed = false; + + script.type = 'text/javascript'; + if (script.readyState) { // IE + script.onreadystatechange = function () { + if (script.readyState === 'complete' || + script.readyState === 'loaded') { + script.onreadystatechange = null; + $timeout( + function () { + if (removed) return; + removed = true; + body.removeChild(script); + callback(); + }, 30, false); + } + }; + } else { // Others + script.onload = function () { + if (removed) return; + removed = true; + body.removeChild(script); + callback(); + }; + script.onerror = function () { + if (removed) return; + removed = true; + body.removeChild(script); + errorCallback(); + }; + } + script.src = url; + script.async = false; + body.appendChild(script); + } + + /** + * Loads a locale and replaces the properties from the current locale with the new locale information + * + * @param localeUrl The path to the new locale + * @param $locale The locale at the curent scope + */ + function loadLocale(localeUrl, $locale, localeId, $rootScope, $q, localeCache, $timeout) { + + function overrideValues(oldObject, newObject) { + if (activeLocale !== localeId) { + return; + } + angular.forEach(oldObject, function(value, key) { + if (!newObject[key]) { + delete oldObject[key]; + } else if (angular.isArray(newObject[key])) { + oldObject[key].length = newObject[key].length; + } + }); + angular.forEach(newObject, function(value, key) { + if (angular.isArray(newObject[key]) || angular.isObject(newObject[key])) { + if (!oldObject[key]) { + oldObject[key] = angular.isArray(newObject[key]) ? [] : {}; + } + overrideValues(oldObject[key], newObject[key]); + } else { + oldObject[key] = newObject[key]; + } + }); + } + + + if (promiseCache[localeId]) return promiseCache[localeId]; + + var cachedLocale, + deferred = $q.defer(); + if (localeId === activeLocale) { + deferred.resolve($locale); + } else if ((cachedLocale = localeCache.get(localeId))) { + activeLocale = localeId; + $rootScope.$evalAsync(function() { + overrideValues($locale, cachedLocale); + $rootScope.$broadcast('$localeChangeSuccess', localeId, $locale); + storage.put(storeKey, localeId); + deferred.resolve($locale); + }); + } else { + activeLocale = localeId; + promiseCache[localeId] = deferred.promise; + loadScript(localeUrl, function () { + // Create a new injector with the new locale + var localInjector = angular.injector(['ngLocale']), + externalLocale = localInjector.get('$locale'); + + overrideValues($locale, externalLocale); + localeCache.put(localeId, externalLocale); + delete promiseCache[localeId]; + + $rootScope.$apply(function () { + $rootScope.$broadcast('$localeChangeSuccess', localeId, $locale); + storage.put(storeKey, localeId); + deferred.resolve($locale); + }); + }, function () { + delete promiseCache[localeId]; + + $rootScope.$apply(function () { + $rootScope.$broadcast('$localeChangeError', localeId); + deferred.reject(localeId); + }); + }, $timeout); + } + return deferred.promise; + } + + this.localeLocationPattern = function(value) { + if (value) { + localeLocationPattern = value; + return this; + } else { + return localeLocationPattern; + } + }; + + this.useStorage = function(storageName) { + storageFactory = storageName; + }; + + this.useCookieStorage = function() { + this.useStorage('$cookieStore'); + }; + + this.defaultLocale = function (value) { + defaultLocale = value; + }; + + this.$get = ['$rootScope', '$injector', '$interpolate', '$locale', '$q', 'tmhDynamicLocaleCache', '$timeout', function($rootScope, $injector, interpolate, locale, $q, tmhDynamicLocaleCache, $timeout) { + var localeLocation = interpolate(localeLocationPattern); + + storage = $injector.get(storageFactory); + $rootScope.$evalAsync(function () { + var initialLocale; + if ((initialLocale = (storage.get(storeKey) || defaultLocale))) { + loadLocale(localeLocation({locale: initialLocale}), locale, initialLocale, $rootScope, $q, tmhDynamicLocaleCache, $timeout); + } + }); + return { + /** + * @ngdoc method + * @description + * @param {string=} value Sets the locale to the new locale. Changing the locale will trigger + * a background task that will retrieve the new locale and configure the current $locale + * instance with the information from the new locale + */ + set: function(value) { + return loadLocale(localeLocation({locale: value}), locale, value, $rootScope, $q, tmhDynamicLocaleCache, $timeout); + } + }; + }]; +}).provider('tmhDynamicLocaleCache', function() { + this.$get = ['$cacheFactory', function($cacheFactory) { + return $cacheFactory('tmh.dynamicLocales'); + }]; +}).provider('tmhDynamicLocaleStorageCache', function() { + this.$get = ['$cacheFactory', function($cacheFactory) { + return $cacheFactory('tmh.dynamicLocales.store'); + }]; +}).run(['tmhDynamicLocale', angular.noop]); +}(window) ); diff --git a/src/Umbraco.Web.UI.Client/src/app.js b/src/Umbraco.Web.UI.Client/src/app.js index 28018ffa4f..847fc2c57c 100644 --- a/src/Umbraco.Web.UI.Client/src/app.js +++ b/src/Umbraco.Web.UI.Client/src/app.js @@ -7,6 +7,7 @@ var app = angular.module('umbraco', [ 'ngCookies', 'ngSanitize', 'ngMobile', - 'blueimp.fileupload' + 'blueimp.fileupload', + 'tmh.dynamicLocale' ]); var packages = angular.module("umbraco.packages", []); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/controllers/main.controller.js b/src/Umbraco.Web.UI.Client/src/controllers/main.controller.js index fbbb04f15f..cc5dc314d1 100644 --- a/src/Umbraco.Web.UI.Client/src/controllers/main.controller.js +++ b/src/Umbraco.Web.UI.Client/src/controllers/main.controller.js @@ -8,7 +8,7 @@ * The main application controller * */ -function MainController($scope, $rootScope, $location, $routeParams, $timeout, $http, $log, appState, treeService, notificationsService, userService, navigationService, historyService, updateChecker, assetsService, eventsService, umbRequestHelper) { +function MainController($scope, $rootScope, $location, $routeParams, $timeout, $http, $log, appState, treeService, notificationsService, userService, navigationService, historyService, updateChecker, assetsService, eventsService, umbRequestHelper, tmhDynamicLocale) { //the null is important because we do an explicit bool check on this in the view //the avatar is by default the umbraco logo @@ -83,6 +83,11 @@ function MainController($scope, $rootScope, $location, $routeParams, $timeout, $ treeService.clearCache(); } + //Load locale file + if ($scope.user.locale) { + tmhDynamicLocale.set($scope.user.locale); + } + if($scope.user.emailHash){ $timeout(function () { //yes this is wrong.. @@ -105,4 +110,8 @@ function MainController($scope, $rootScope, $location, $routeParams, $timeout, $ //register it -angular.module('umbraco').controller("Umbraco.MainController", MainController); +angular.module('umbraco').controller("Umbraco.MainController", MainController). + config(function (tmhDynamicLocaleProvider) { + //Set url for locale files + tmhDynamicLocaleProvider.localeLocationPattern('lib/angular/1.1.5/i18n/angular-locale_{{locale}}.js'); + }); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/loader.js b/src/Umbraco.Web.UI.Client/src/loader.js index 23d2079edd..735159459f 100644 --- a/src/Umbraco.Web.UI.Client/src/loader.js +++ b/src/Umbraco.Web.UI.Client/src/loader.js @@ -14,6 +14,8 @@ LazyLoad.js( 'lib/angular/angular-ui-sortable.js', + 'lib/angular/tmhDynamicLocale.js', + /* App-wide file-upload helper */ 'lib/jquery/jquery.upload/js/jquery.fileupload.js', 'lib/jquery/jquery.upload/js/jquery.fileupload-process.js', diff --git a/src/Umbraco.Web/UI/JavaScript/JsInitialize.js b/src/Umbraco.Web/UI/JavaScript/JsInitialize.js index 13d0c2eac1..ade47fcd84 100644 --- a/src/Umbraco.Web/UI/JavaScript/JsInitialize.js +++ b/src/Umbraco.Web/UI/JavaScript/JsInitialize.js @@ -11,6 +11,8 @@ 'lib/angular/angular-ui-sortable.js', + 'lib/angular/tmhDynamicLocale.js', + 'lib/jquery/jquery.upload/js/jquery.fileupload.js', 'lib/jquery/jquery.upload/js/load-image.min.js', 'lib/jquery/jquery.upload/js/jquery.fileupload-process.js',