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

Commit

Permalink
feat($translateProvider): add a new option to force async reload
Browse files Browse the repository at this point in the history
  • Loading branch information
acourtiol authored and knalli committed Jun 1, 2015
1 parent 89e2569 commit bdee77f
Show file tree
Hide file tree
Showing 5 changed files with 263 additions and 2 deletions.
26 changes: 26 additions & 0 deletions docs/content/guide/de/12_asynchronous-loading.ngdoc
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,32 @@ $translateProvider.preferredLanguage('en');
$translateProvider.useLocalStorage();
</pre>

## Asynchrones Laden erzwingen

Wenn eine Kombination von `$translateProvider.translations()` und `$translateProvider.{{whatever}}Loader`
genutzt wird, erfolgt KEIN Aufruf des asynchrone Lademechanismus für alle Sprachen, bei denen schon
Übersetzungen per `$translateProvider.translations()` erzeugt wurden.

Um dieses Verhalten zu verhindern, muss `$translateProvider.forceAsyncReload()` initialisiert werden:

<pre>
$translateProvider.translations('en', {
'HELLO_TEXT': 'Hello World!'
});
$translateProvider.useStaticFilesLoader({
'prefix': 'locale-',
'suffix': '.json'
});
$translateProvider.preferredLanguage('en');
$translateProvider.forceAsyncReload(true);
</pre>

Durch diese Änderung wird bewirkt, das beide Datenquellen / Sprachtabellen genutzt werden und somit
der asynchrone Lademechanismus aufgerufen wird. Das Ergebnis ist eine zusammengesetzte Sprachtabelle.

**Anmerkung:** Falls derselbe Sprachschlüssel in beiden Quellen definiert ist, wird ausschließlich der
Schlüssel aus der asynchronen Datenquelle genutzt!

Da wir keine Änderungen im HTML oder unseren Controllern machen müssen, sind wir
schon fertig! Hier ist die funktionierende App:

Expand Down
29 changes: 29 additions & 0 deletions docs/content/guide/en/12_asynchronous-loading.ngdoc
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,35 @@ $translateProvider.useStaticFilesLoader({
$translateProvider.preferredLanguage('en');
</pre>

## Force asynchronous reloading

When using a combination of `$translateProvider.translations()` and
`$translateProvider.{{whatever}}Loader`, for each language keys declared
using `$translateProvider.translations()`, the asynchronous loader will
not be called.

To get around this, you can enable the `$translateProvider.forceAsyncReload()`
like this:

<pre>
$translateProvider.translations('en', {
'HELLO_TEXT': 'Hello World!'
});
$translateProvider.useStaticFilesLoader({
'prefix': 'locale-',
'suffix': '.json'
});
$translateProvider.preferredLanguage('en');
$translateProvider.forceAsyncReload(true);
</pre>

This way, even if the language key is already declared using
`$translateProvider.translations()` the asynchronous loader will be called
and translations from both sources will be merged.

**Note:** If a same translation id is declared in both sources, the translation
from the asynchronous loader will be used.

Since we don't have to make any changes in our controllers or HTML, we are done!
Take a look at the working app:

Expand Down
29 changes: 29 additions & 0 deletions docs/content/guide/fr/12_asynchronous-loading.ngdoc
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,35 @@ $translateProvider.useStaticFilesLoader({
$translateProvider.preferredLanguage('fr');
</pre>

## Forcer le rechargement asynchrone

Lors de l'utilisation d'une combinaison de `$translateProvider.translations()` et
`$translateProvider.{{peu importe}}Loader`, pour chaque clé de langue déclarée à
l'aide de `$translateProvider.translations()`, le chargeur asynchrone ne sera
jamais appelé.

Pour contourner ce problème, vous pouvez activer `$translateProvider.forceAsyncReload()`
comme ceci:

<pre>
$translateProvider.translations('en', {
'HELLO_TEXT': 'Salut tout le monde !!'
});
$translateProvider.useStaticFilesLoader({
'prefix': 'locale-',
'suffix': '.json'
});
$translateProvider.preferredLanguage('fr');
$translateProvider.forceAsyncReload(true);
</pre>

De cette façon, même si la clé de la langue est déjà déclarée à l'aide de
`$translateProvider.translations()` le chargeur asynchrone sera appelé
et les traductions des deux sources seront fusionnés.

**Note:** Si un même identifiant de traduction est déclaré dans les deux sources,
la traduction du chargeur asynchrone sera utilisée.

Étant donné que nous n'avons pas à faire de changements dans nos contrôleurs ou notre HTML,
nous avons fini ! Jetez un oeil à l'application :

Expand Down
43 changes: 41 additions & 2 deletions src/service/translate.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ function $translate($STORAGE_KEY, $windowProvider, $translateSanitizationProvide
$notFoundIndicatorLeft,
$notFoundIndicatorRight,
$postCompilingEnabled = false,
$forceAsyncReloadEnabled = false,
NESTED_OBJECT_DELIMITER = '.',
loaderCache,
directivePriority = 0,
Expand Down Expand Up @@ -707,6 +708,30 @@ function $translate($STORAGE_KEY, $windowProvider, $translateSanitizationProvide
return this;
};

/**
* @ngdoc function
* @name pascalprecht.translate.$translateProvider#forceAsyncReload
* @methodOf pascalprecht.translate.$translateProvider
*
* @description
* If force async reload is enabled, async loader will always be called
* even if $translationTable already contains the language key, adding
* possible new entries to the $translationTable.
*
* Example:
* <pre>
* app.config(function ($translateProvider) {
* $translateProvider.forceAsyncReload(true);
* });
* </pre>
*
* @param {boolean} value - valid values are true or false
*/
this.forceAsyncReload = function (value) {
$forceAsyncReloadEnabled = !(!value);
return this;
};

/**
* @ngdoc function
* @name pascalprecht.translate.$translateProvider#uniformLanguageTag
Expand Down Expand Up @@ -1663,7 +1688,7 @@ function $translate($STORAGE_KEY, $windowProvider, $translateSanitizationProvide

// if there isn't a translation table for the language we've requested,
// we load it asynchronously
if (!$translationTable[key] && $loaderFactory && !langPromises[key]) {
if (($forceAsyncReloadEnabled || !$translationTable[key]) && $loaderFactory && !langPromises[key]) {
$nextLang = key;
langPromises[key] = loadAsync(key).then(function (translation) {
translations(translation.key, translation.table);
Expand Down Expand Up @@ -1725,6 +1750,20 @@ function $translate($STORAGE_KEY, $windowProvider, $translateSanitizationProvide
return $postCompilingEnabled;
};

/**
* @ngdoc function
* @name pascalprecht.translate.$translate#isForceAsyncReloadEnabled
* @methodOf pascalprecht.translate.$translate
*
* @description
* Returns whether force async reload is enabled or not
*
* @return {boolean} forceAsyncReload value
*/
$translate.isForceAsyncReloadEnabled = function () {
return $forceAsyncReloadEnabled;
};

/**
* @ngdoc function
* @name pascalprecht.translate.$translate#refresh
Expand Down Expand Up @@ -1961,7 +2000,7 @@ function $translate($STORAGE_KEY, $windowProvider, $translateSanitizationProvide
};
for (var i = 0, len = $fallbackLanguage.length; i < len; i++) {
var fallbackLanguageId = $fallbackLanguage[i];
if (!$translationTable[fallbackLanguageId]) {
if ($forceAsyncReloadEnabled || !$translationTable[fallbackLanguageId]) {
langPromises[fallbackLanguageId] = loadAsync(fallbackLanguageId).then(processAsyncResult);
}
}
Expand Down
138 changes: 138 additions & 0 deletions test/unit/service/translate.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,22 @@ describe('pascalprecht.translate', function () {
expect($translate.instant).toBeDefined();
});

it('should have a method isForceAsyncReloadEnabled()', function () {
expect($translate.isForceAsyncReloadEnabled).toBeDefined();
});

describe('$translate#isForceAsyncReloadEnabled()', function () {

it('should be a function', function () {
expect(typeof $translate.isForceAsyncReloadEnabled).toBe('function');
});

it('should return false by default', function () {
expect($translate.isForceAsyncReloadEnabled()).toBe(false);
});

});

describe('$translate#preferredLanguage()', function () {

it('should be a function', function () {
Expand Down Expand Up @@ -1817,4 +1833,126 @@ describe('pascalprecht.translate', function () {

});

describe('$translateProvider.forceAsyncReload', function () {

describe('Enabled', function () {
beforeEach(module('pascalprecht.translate', function ($translateProvider, $provide) {
$translateProvider
.translations('en', {
'FOO': 'bar'
})
.forceAsyncReload(true)
.useLoader('customLoader');

$provide.factory('customLoader', ['$q', '$timeout', function ($q, $timeout) {
return function (options) {
var deferred = $q.defer();

$timeout(function () {
deferred.resolve({
'BAR': 'foo'
});
});

return deferred.promise;
};
}]);
}));

var $translate, $timeout, $rootScope;

beforeEach(inject(function (_$translate_, _$timeout_, _$rootScope_) {
$translate = _$translate_;
$timeout = _$timeout_;
$rootScope = _$rootScope_;
}));

it('should have forceAsyncReload enabled', function () {
expect($translate.isForceAsyncReloadEnabled()).toBe(true);
});

it('should return translation if translation id exist', function () {
var firstValue, secondValue;

function fetchTranslation() {
$translate(['FOO', 'BAR']).then(function (translations) {
firstValue = translations.FOO;
secondValue = translations.BAR;
});
}

function changeLanguage(lang) {
$translate.use(lang);
}

changeLanguage('en');
$timeout.flush(); // Expect the `en` language to be loaded
$rootScope.$digest();

fetchTranslation();
$rootScope.$digest();
expect(firstValue).toEqual('bar'); // found
expect(secondValue).toEqual('foo'); // found
});
});

describe('Disabled (default)', function () {
beforeEach(module('pascalprecht.translate', function ($translateProvider, $provide) {
$translateProvider
.translations('en', {
'FOO': 'bar'
})
.useLoader('customLoader');

$provide.factory('customLoader', ['$q', '$timeout', function ($q, $timeout) {
return function (options) {
var deferred = $q.defer();

$timeout(function () {
deferred.resolve({
'BAR': 'foo'
});
});

return deferred.promise;
};
}]);
}));

var $translate, $rootScope;

beforeEach(inject(function (_$translate_, _$rootScope_) {
$translate = _$translate_;
$rootScope = _$rootScope_;
}));

it('should have forceAsyncReload disabled', function () {
expect($translate.isForceAsyncReloadEnabled()).toBe(false);
});

it('should return translation if translation id exist', function () {
var firstValue, secondValue;

function fetchTranslation() {
$translate(['FOO', 'BAR']).then(function (translations) {
firstValue = translations.FOO;
secondValue = translations.BAR;
});
}

function changeLanguage(lang) {
$translate.use(lang);
}

changeLanguage('en');
$rootScope.$digest();

fetchTranslation();
$rootScope.$digest();
expect(firstValue).toEqual('bar'); // found
expect(secondValue).toEqual('BAR'); // not found
});
});
});

});

0 comments on commit bdee77f

Please sign in to comment.