Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scoped dictionaries #17

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

<a href="">{{ "clickme" | i18n }}</a> => <a>Click me</a>
<a href="">{{ "clickme" | i18n:'component-1' }}</a> => <a>Click me, I dare you!</a>

## Change Log

### 0.1.2 - 09/26/2013
Expand Down
File renamed without changes.
131 changes: 89 additions & 42 deletions src/localize.js
Original file line number Diff line number Diff line change
Expand Up @@ -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))) {
Expand All @@ -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;
Expand All @@ -104,20 +149,21 @@ 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
// updates the text value of the attached element
// usage <span data-i18n="TOKEN" ></span>
// or
// <span data-i18n="TOKEN|VALUE1|VALUE2" ></span>
.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
Expand All @@ -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);
});

Expand All @@ -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]);
Expand All @@ -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);
});

Expand Down