diff --git a/README.md b/README.md index 832c0b2..4dc4f27 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,19 @@ I've created a sample app that uses the Resource Localization Service to provide There is a delay loading the resource file, you may need to use the filter instead of the directive on the home page. This is due to the fact that the directive is only called once per instance where a filter is re-evaluated each time the DOM is compiled. +## Scoped Dictionaries + +This feature allow you to use a dictionary for each one of your components. A simple example will follow: + + |_ app + |_ i18n + |_ resources-locale_defaults.js + |_ component-1 + |_ resources-locale_defaults.js + + {{ "clickme" | i18n }} => Click me + {{ "clickme" | i18n:'component-1' }} => Click me, I dare you! + ## Change Log ### 0.1.2 - 09/26/2013 diff --git a/app/i18n/resources-locale_default.js b/app/i18n/resources-locale_default.json similarity index 100% rename from app/i18n/resources-locale_default.js rename to app/i18n/resources-locale_default.json diff --git a/app/i18n/resources-locale_en-US.js b/app/i18n/resources-locale_en-US.json similarity index 100% rename from app/i18n/resources-locale_en-US.js rename to app/i18n/resources-locale_en-US.json diff --git a/app/i18n/resources-locale_es-es.js b/app/i18n/resources-locale_es-es.json similarity index 100% rename from app/i18n/resources-locale_es-es.js rename to app/i18n/resources-locale_es-es.json diff --git a/app/i18n/resources-locale_es.js b/app/i18n/resources-locale_es.json similarity index 100% rename from app/i18n/resources-locale_es.js rename to app/i18n/resources-locale_es.json diff --git a/src/localize.js b/src/localize.js index fbd492f..2fb1a8d 100644 --- a/src/localize.js +++ b/src/localize.js @@ -14,39 +14,48 @@ angular.module('localization', []) .factory('localize', ['$http', '$rootScope', '$window', '$filter', function ($http, $rootScope, $window, $filter) { var localize = { // use the $window service to get the language of the user's browser - language:'', + language: '', // array to hold the localized resource string entries - dictionary:[], + dictionary: [], + // array for scoped dictionaries + scopedDictionary: [], + // avoid multiple XHR issued due to files not loaded + scopeLoading: [], // location of the resource file url: undefined, // flag to indicate if the service hs loaded the resource file - resourceFileLoaded:false, + resourceFileLoaded: false, // success handler for all server communication - successCallback:function (data) { - // store the returned array in the dictionary - localize.dictionary = data; - // set the flag that the resource are loaded + successCallback: function (data, scope) { + if (scope) { + localize.scopedDictionary[scope] = data; + localize.scopeLoading[scope] = false; + } else { + // store the returned array in the dictionary + localize.dictionary = data; + } + // set that the resource are loaded localize.resourceFileLoaded = true; // broadcast that the file has been loaded $rootScope.$broadcast('localizeResourcesUpdated'); }, // allows setting of language on the fly - setLanguage: function(value) { + setLanguage: function (value) { localize.language = value; localize.initLocalizedResources(); }, // allows setting of resource url on the fly - setUrl: function(value) { + setUrl: function (value) { localize.url = value; localize.initLocalizedResources(); }, // builds the url for locating the resource file - buildUrl: function() { - if(!localize.language){ + buildUrl: function (scope) { + if (!localize.language) { var lang, androidLang; // works for earlier version of Android (2.3.x) if ($window.navigator && $window.navigator.userAgent && (androidLang = $window.navigator.userAgent.match(/android.*\W(\w\w)-(\w\w)\W/i))) { @@ -58,38 +67,74 @@ angular.module('localization', []) // set language localize.language = lang; } - return 'i18n/resources-locale_' + localize.language + '.js'; + //return 'i18n/' + (scope ? scope + '/' : '') + 'resources-locale_' + localize.language + '.json'; + return (scope ? 'modules/' + scope + '/i18n' : 'i18n') + '/resources-locale_' + localize.language + '.json'; }, // loads the language resource file from the server - initLocalizedResources:function () { + initLocalizedResources: function (scope) { // build the url to retrieve the localized resource file - var url = localize.url || localize.buildUrl(); + var url = scope ? localize.buildUrl(scope) : localize.url || localize.buildUrl(); // request the resource file - $http({ method:"GET", url:url, cache:false }).success(localize.successCallback).error(function () { - // the request failed set the url to the default resource file - var url = '/i18n/resources-locale_default.js'; - // request the default resource file - $http({ method:"GET", url:url, cache:false }).success(localize.successCallback); - }); + $http({ method: "GET", url: url, cache: false }) + .success(function(data) { + localize.successCallback(data, scope); + }) + .error(function () { + // the request failed set the url to the default resource file + //var url = 'i18n/' + (scope ? scope + '/' : '') + 'resources-locale_default.json'; + var url = (scope ? 'modules/' + scope + '/i18n' : 'i18n') + '/resources-locale_default.json'; + // request the default resource file + $http({ method: "GET", url: url, cache: false }) + .success(function(data) { + localize.successCallback(data, scope); + }) + .error(function() { + // avoid loop of hell in case scopedDic doesn't exists + localize.scopedDictionary[scope] = []; + localize.scopeLoading[scope] = false; + }); + }); + }, + + // returns scoped dic, if not present, issues a loading + getScopedDictionary: function(scope) { + var dic = localize.scopedDictionary[scope]; + if (!dic) { + if (!localize.scopeLoading[scope]) { + localize.scopeLoading[scope] = true; + localize.initLocalizedResources(scope); + } + dic = []; + } + return dic; }, // checks the dictionary for a localized resource string - getLocalizedString: function(value) { + getLocalizedString: function (value, scope) { // default the result to an empty string var result = ''; + var dic; + // + if (!scope) { + dic = localize.dictionary; + } else { + dic = localize.getScopedDictionary(scope); + } + // if something is wrong, bad things will happens without this check.. + if (dic) { + // make sure the dictionary has valid data + if ((dic !== []) && (dic.length > 0)) { + // use the filter service to only return those entries which match the value + // and only take the first result + var entry = $filter('filter')(dic, function (element) { + return element.key === value; + } + )[0]; - // make sure the dictionary has valid data - if ((localize.dictionary !== []) && (localize.dictionary.length > 0)) { - // use the filter service to only return those entries which match the value - // and only take the first result - var entry = $filter('filter')(localize.dictionary, function(element) { - return element.key === value; - } - )[0]; - - // set the result - result = entry.value; + // set the result + result = entry.value; + } } // return the value to the call return result; @@ -104,9 +149,10 @@ angular.module('localization', []) } ]) // simple translation filter // usage {{ TOKEN | i18n }} + // usage {{ TOKEN | i18n:'scopeName' }} .filter('i18n', ['localize', function (localize) { - return function (input) { - return localize.getLocalizedString(input); + return function (input, scope) { + return localize.getLocalizedString(input, scope); }; }]) // translation directive that can handle dynamic strings @@ -114,10 +160,10 @@ angular.module('localization', []) // usage // or // - .directive('i18n', ['localize', function(localize){ + .directive('i18n', ['localize', function (localize) { var i18nDirective = { - restrict:"EAC", - updateText:function(elm, token){ + restrict: "EAC", + updateText: function (elm, token) { var values = token.split('|'); if (values.length >= 1) { // construct the tag to insert into the element @@ -132,12 +178,13 @@ angular.module('localization', []) } // insert the text into the element elm.text(tag); - }; + } + ; } }, - link:function (scope, elm, attrs) { - scope.$on('localizeResourcesUpdated', function() { + link: function (scope, elm, attrs) { + scope.$on('localizeResourcesUpdated', function () { i18nDirective.updateText(elm, attrs.i18n); }); @@ -157,7 +204,7 @@ angular.module('localization', []) .directive('i18nAttr', ['localize', function (localize) { var i18NAttrDirective = { restrict: "EAC", - updateText:function(elm, token){ + updateText: function (elm, token) { var values = token.split('|'); // construct the tag to insert into the element var tag = localize.getLocalizedString(values[0]); @@ -174,7 +221,7 @@ angular.module('localization', []) } }, link: function (scope, elm, attrs) { - scope.$on('localizeResourcesUpdated', function() { + scope.$on('localizeResourcesUpdated', function () { i18NAttrDirective.updateText(elm, attrs.i18nAttr); });