Skip to content
This repository has been archived by the owner on Jan 29, 2024. It is now read-only.

Commit

Permalink
feat(loaders): introduce loader cache
Browse files Browse the repository at this point in the history
It useful if we disable cache for dynamic content, but want enable it for translation files (static content).
Also it useful if we need include translation into build file (cache in advance for production).

```js
app.run(function($translationCache) {
    $translationCache.put('/compiled/module1/locals/en.json', '{"MODULE1.HELLO":"Hi!"}');
    // Other translations string added by Grunt
});
```

feat(cache): introduce customizable loader cache

* `$translationCache` is fully flexible a string (name of an instance) or an instance itself
* `$translationCache` could be `true` for an AJS internal default

New feature usage:

```js
$translateProvider.useLoaderCache(false) // disable any cache (default behaviour)
$translateProvider.useLoaderCache(true) // use `$http({cache: true})
$translateProvider.useLoaderCache() // use our internal default `$translationCache` (actually `$translateProvider.useLoaderCache('$translationCache')`
$translateProvider.useLoaderCache('cacheService') // use the given identifying cacheService
$translateProvider.useLoaderCache(cacheService) // use the cacheService
```

This also introduces the feature loaders are provided with the option `$http` for additional standard params. Currently, only `$http.cache` could be defined.

Closes #529
  • Loading branch information
tamtakoe authored and knalli committed Sep 18, 2014
1 parent 73b289d commit b685601
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 16 deletions.
27 changes: 20 additions & 7 deletions src/service/loader-partial.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,16 @@ angular.module('pascalprecht.translate')
return urlTemplate.replace(/\{part\}/g, this.name).replace(/\{lang\}/g, targetLang);
};

Part.prototype.getTable = function(lang, $q, $http, urlTemplate, errorHandler) {
Part.prototype.getTable = function(lang, $q, $http, $httpOptions, urlTemplate, errorHandler) {
var deferred = $q.defer();

if (!this.tables[lang]) {
var self = this;

$http({
$http(angular.extend({}, $httpOptions, {
method : 'GET',
url : this.parseUrl(urlTemplate, lang)
}).success(function(data){
url: this.parseUrl(urlTemplate, lang)
})).success(function(data){
self.tables[lang] = data;
deferred.resolve(data);
}).error(function() {
Expand Down Expand Up @@ -226,15 +226,16 @@ angular.module('pascalprecht.translate')
* @requires $http
* @requires $injector
* @requires $rootScope
* @requires $translate
*
* @description
*
* @param {object} options Options object
*
* @throws {TypeError}
*/
this.$get = ['$rootScope', '$injector', '$q', '$http',
function($rootScope, $injector, $q, $http) {
this.$get = ['$rootScope', '$injector', '$q', '$http', '$translate',
function($rootScope, $injector, $q, $http, $translate) {

/**
* @ngdoc event
Expand Down Expand Up @@ -278,9 +279,10 @@ angular.module('pascalprecht.translate')
if (hasPart(part) && parts[part].isActive) {
loaders.push(
parts[part]
.getTable(options.key, $q, $http, options.urlTemplate, errorHandler)
.getTable(options.key, $q, $http, options.$http, options.urlTemplate, errorHandler)
.then(addTablePart)
);
parts[part].urlTemplate = options.urlTemplate;
}
}

Expand Down Expand Up @@ -386,6 +388,17 @@ angular.module('pascalprecht.translate')
if (hasPart(name)) {
var wasActive = parts[name].isActive;
if (removeData) {
var cache = $translate.loaderCache();
if (typeof(cache) === 'string') {
// getting on-demand instance of loader
cache = $injector.get(cache);
}
// Purging items from cache...
if (typeof(cache) === 'object') {
angular.forEach(parts[name].tables, function(value, key) {
cache.remove(parts[name].parseUrl(parts[name].urlTemplate, key));
});
}
delete parts[name];
} else {
parts[name].isActive = false;
Expand Down
4 changes: 2 additions & 2 deletions src/service/loader-static-files.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@ angular.module('pascalprecht.translate')

var deferred = $q.defer();

$http({
$http(angular.extend({}, options.$http, {
url: [
options.prefix,
options.key,
options.suffix
].join(''),
method: 'GET',
params: ''
}).success(function (data) {
})).success(function (data) {
deferred.resolve(data);
}).error(function (data) {
deferred.reject(options.key);
Expand Down
4 changes: 2 additions & 2 deletions src/service/loader-url.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ angular.module('pascalprecht.translate')

var deferred = $q.defer();

$http({
$http(angular.extend({}, options.$http, {
url: options.url,
params: { lang: options.key },
method: 'GET'
}).success(function (data) {
})).success(function (data) {
deferred.resolve(data);
}).error(function (data) {
deferred.reject(options.key);
Expand Down
62 changes: 59 additions & 3 deletions src/service/translate.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ angular.module('pascalprecht.translate').provider('$translate', ['$STORAGE_KEY',
$notFoundIndicatorLeft,
$notFoundIndicatorRight,
$postCompilingEnabled = false,
NESTED_OBJECT_DELIMITER = '.';
NESTED_OBJECT_DELIMITER = '.',
loaderCache;

var version = 'x.y.z';

Expand Down Expand Up @@ -705,6 +706,37 @@ angular.module('pascalprecht.translate').provider('$translate', ['$STORAGE_KEY',
return $availableLanguageKeys;
};

/**
* @ngdoc function
* @name pascalprecht.translate.$translateProvider#useLoaderCache
* @methodOf pascalprecht.translate.$translateProvider
*
* @description
* Registers a cache for internal $http based loaders.
* {@link pascalprecht.translate.$translateProvider#determinePreferredLanguage determinePreferredLanguage}.
* When false the cache will be disabled (default). When true or undefined
* the cache will be a default (see $cacheFactory). When an object it will
* be treat as a cache object itself: the usage is $http({cache: cache})
*
* @param {object} cache boolean, string or cache-object
*/
this.useLoaderCache = function (cache) {
if (cache === false) {
// disable cache
loaderCache = undefined;
} else if (cache === true) {
// enable cache using AJS defaults
loaderCache = true;
} else if (typeof(cache) === 'undefined') {
// enable cache using default
loaderCache = '$translationCache';
} else if (cache) {
// enable cache using given one (see $cacheFactory)
loaderCache = cache;
}
return this;
};

/**
* @ngdoc object
* @name pascalprecht.translate.$translate
Expand Down Expand Up @@ -903,8 +935,17 @@ angular.module('pascalprecht.translate').provider('$translate', ['$STORAGE_KEY',
$rootScope.$emit('$translateLoadingStart', {language: key});
pendingLoader = true;

var cache = loaderCache;
if (typeof(cache) === 'string') {
// getting on-demand instance of loader
cache = $injector.get(cache);
}

$injector.get($loaderFactory)(angular.extend($loaderOptions, {
key: key
key: key,
$http: {
cache: cache
}
})).then(function (data) {
var translationTable = {};
$rootScope.$emit('$translateLoadingSuccess', {language: key});
Expand Down Expand Up @@ -1646,6 +1687,20 @@ angular.module('pascalprecht.translate').provider('$translate', ['$STORAGE_KEY',
return version;
};

/**
* @ngdoc function
* @name pascalprecht.translate.$translate#loaderCache
* @methodOf pascalprecht.translate.$translate
*
* @description
* Returns the defined loaderCache.
*
* @return {boolean|string|object} current value of loaderCache
*/
$translate.loaderCache = function () {
return loaderCache;
};

if ($loaderFactory) {

// If at least one async loader is defined and there are no
Expand All @@ -1667,5 +1722,6 @@ angular.module('pascalprecht.translate').provider('$translate', ['$STORAGE_KEY',
}

return $translate;
}];
}
];
}]);
15 changes: 15 additions & 0 deletions src/service/translationCache.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* @ngdoc service
* @name $translationCache
* @requires $cacheFactory
*
* @description
* The first time a translation table is used, it is loaded in the translation cache for quick retrieval. You
* can load translation tables directly into the cache by consuming the
* `$translationCache` service directly.
*
* @return {object} $cacheFactory object.
*/
angular.module('pascalprecht.translate').factory('$translationCache', ['$cacheFactory', function ($cacheFactory) {
return $cacheFactory('translations');
}]);
25 changes: 25 additions & 0 deletions test/unit/service/loader-partial.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -598,5 +598,30 @@ describe('pascalprecht.translate', function() {
expect(counter).toEqual(2);
});
});

it('should put a part into a cache and remove from the cache if the part was deleted', function() {
module(function($httpProvider, $translateProvider) {
$httpProvider.defaults.transformRequest.push(CounterHttpInterceptor);
$translateProvider.useLoaderCache();
});

inject(function($translatePartialLoader, $httpBackend, $translationCache) {
$httpBackend.whenGET('/locales/part-en.json').respond(200, '{}');

$translatePartialLoader.addPart('part');
$translatePartialLoader({
key : 'en',
urlTemplate : '/locales/{part}-{lang}.json',
$http: {
cache: $translationCache
}
});
$httpBackend.flush();
expect($translationCache.info().size).toEqual(1);

$translatePartialLoader.deletePart('part', true);
expect($translationCache.info().size).toEqual(0);
});
});
});
});
17 changes: 16 additions & 1 deletion test/unit/service/loader-static-files.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ describe('pascalprecht.translate', function () {

beforeEach(module('pascalprecht.translate'));

beforeEach(inject(function (_$translate_, _$httpBackend_, _$translateStaticFilesLoader_) {
beforeEach(inject(function (_$translate_, _$httpBackend_, _$translateStaticFilesLoader_, _$translationCache_) {
$httpBackend = _$httpBackend_;
$translate = _$translate_;
$translateStaticFilesLoader = _$translateStaticFilesLoader_;
$translationCache = _$translationCache_;

$httpBackend.when('GET', 'lang_de_DE.json').respond({HEADER: 'Ueberschrift'});
$httpBackend.when('GET', 'lang_en_US.json').respond({HEADER:'Header'});
Expand Down Expand Up @@ -55,5 +56,19 @@ describe('pascalprecht.translate', function () {
expect(typeof promise.then).toBe('function');
$httpBackend.flush();
});

it('should put a translation table into a cache', function() {
$httpBackend.expectGET('lang_de_DE.json');
$translateStaticFilesLoader({
key: 'de_DE',
prefix: 'lang_',
suffix: '.json',
$http: {
cache: $translationCache
}
});
$httpBackend.flush();
expect($translationCache.info().size).toEqual(1);
});
});
});
16 changes: 15 additions & 1 deletion test/unit/service/loader-url.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ describe('pascalprecht.translate', function () {

beforeEach(module('pascalprecht.translate'));

beforeEach(inject(function (_$translate_, _$httpBackend_, _$translateUrlLoader_) {
beforeEach(inject(function (_$translate_, _$httpBackend_, _$translateUrlLoader_, _$translationCache_) {
$translate = _$translate_;
$httpBackend = _$httpBackend_;
$translateUrlLoader = _$translateUrlLoader_;
$translationCache = _$translationCache_;

$httpBackend.when('GET', 'foo/bar.json?lang=de_DE').respond({
it: 'works'
Expand Down Expand Up @@ -44,6 +45,19 @@ describe('pascalprecht.translate', function () {
$httpBackend.flush();
});

it('should put a translation table into a cache', function() {
$httpBackend.expectGET('foo/bar.json?lang=de_DE');
$translateUrlLoader({
key: 'de_DE',
url: 'foo/bar.json',
$http: {
cache: $translationCache
}
});
$httpBackend.flush();
expect($translationCache.info().size).toEqual(1);
});

it('should return a promise', function () {
var promise = $translateUrlLoader({
key: 'de_DE',
Expand Down

0 comments on commit b685601

Please sign in to comment.