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

Commit

Permalink
feat(service): add possibility to translate a set of translation ids
Browse files Browse the repository at this point in the history
This enriches both `$translate()` and `$translate.instant()` with the
possibility to call them with an array rather than a string. This makes
the API more comfortable in some situations.

```javascript
// for example...
$translate(['FOO', 'BAR']).then(function(translations){
  console.log(translations.FOO);
  console.log(translations.BAR);
});
// ... and
console.log($translate.instant(['FOO', 'BAR']).FOO);
console.log($translate.instant(['FOO', 'BAR']).BAR);
```
  • Loading branch information
knalli authored and 0x-r4bbit committed Apr 2, 2014
1 parent 7de2ae2 commit 612dc27
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 5 deletions.
18 changes: 18 additions & 0 deletions docs/content/guide/de/03_using-translate-service.ngdoc
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,24 @@ app.controller('Ctrl', ['$scope', '$translate', function ($scope, $translate) {
Das ist alles. Also, falls du darüber nachdenkst deinen `<title>` zu übersetzen,
kannst du dies in deinem Controller machen.

## Mehrere TranslationIds auf einmal
Der Service kann auch mehrere Übersetzungen auf einmal laden.

<pre>
app.controller('Ctrl', ['$scope', '$translate', function ($scope, $translate) {
$translate(['HEADLINE', 'PARAGRAPH', 'NAMESPACE.PARAGRAPH']).then(function (translations) {
$scope.headline = translations.HEADLINE;
$scope.paragraph = translations.PARAGRAPH;
$scope.namespaced_paragraph = translations['NAMESPACE.PARAGRAPH'];
});
}]);
</pre>

Dabei muss jedoch beachtet werden, dass der Service immer ein Objekt mit allen
Übersetzungen zurückgibt. Dabei spielt es keine Rolle, ob eine einzelne
Übersetzung (oder sogar alle) nicht übersetzt werden konnten. Eine mögliche
Fehlerbehandlung muss von Deiner Seite aus geschehen.

## Dinge die Beruecksichtigt werden sollten
Bitte beachte dass `$translate` Service kein Two-Way Data-Binding unterstuetzt.
`$translate` Service arbeitet asynchron, dass bedeteut aber nicht, dass er informiert
Expand Down
17 changes: 17 additions & 0 deletions docs/content/guide/en/03_using-translate-service.ngdoc
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,23 @@ app.controller('Ctrl', ['$scope', '$translate', function ($scope, $translate) {
That's all. Now when you think about translating the contents of a `<title>` you
can do so within your controller.

## Multiple translation IDs
The translation service is also aware of requesting multiple translation at once.

<pre>
app.controller('Ctrl', ['$scope', '$translate', function ($scope, $translate) {
$translate(['HEADLINE', 'PARAGRAPH', 'NAMESPACE.PARAGRAPH']).then(function (translations) {
$scope.headline = translations.HEADLINE;
$scope.paragraph = translations.PARAGRAPH;
$scope.namespaced_paragraph = translations['NAMESPACE.PARAGRAPH'];
});
}]);
</pre>

However, the service will always return an object containing translations -- regardless whether
a translation (or even all of them) has failed. When requesting multiple translations
in one request, it is up to you to deal with the result.

## Things to keep in mind
Please keep in mind that the usage of the `$translate` service doesn't provide a two-way
data binding default! `$translate` service works asynchronously, which means
Expand Down
59 changes: 54 additions & 5 deletions src/service/translate.js
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,10 @@ angular.module('pascalprecht.translate').provider('$translate', ['$STORAGE_KEY',
* $scope.translatedText = $translate('HEADLINE_TEXT');
* </pre>
*
* @param {string} translationId A token which represents a translation id
* @param {string|array} translationId A token which represents a translation id
* This can be optionally an array of translation ids which
* results that the function returns an object where each key
* is the translation id and the value the translation.
* @param {object=} interpolateParams An object hash for dynamic values
*/
this.$get = [
Expand All @@ -691,7 +694,41 @@ angular.module('pascalprecht.translate').provider('$translate', ['$STORAGE_KEY',
startFallbackIteration;

var $translate = function (translationId, interpolateParams, interpolationId) {

// Duck detection: If the first argument is an array, a bunch of translations was requested.
// The result is an object.
if (angular.isArray(translationId)) {
// Inspired by Q.allSettled by Kris Kowal
// https://github.com/kriskowal/q/blob/b0fa72980717dc202ffc3cbf03b936e10ebbb9d7/q.js#L1553-1563
// This transforms all promises regardless resolved or rejected
var translateAll = function (translationIds) {
var results = {}; // storing the actual results
var promises = []; // promises to wait for
// Wraps the promise a) being always resolved and b) storing the link id->value
var translate = function (translationId) {
var deferred = $q.defer();
var regardless = function (value) {
results[translationId] = value;
deferred.resolve([translationId, value]);
};
// we don't care whether the promise was resolved or rejected; just store the values
$translate(translationId, interpolateParams, interpolationId).then(regardless, regardless);
return deferred.promise;
};
for (var i = 0, c = translationIds.length; i < c; i++) {
promises.push(translate(translationIds[i]));
}
// wait for all (including storing to results)
return $q.all(promises).then(function () {
// return the results
return results;
});
};
return translateAll(translationId);
}

var deferred = $q.defer();

// trim off any whitespace
translationId = translationId.trim();

Expand Down Expand Up @@ -1446,14 +1483,26 @@ angular.module('pascalprecht.translate').provider('$translate', ['$STORAGE_KEY',
* used except any promise handling. If a language was not found, an asynchronous loading
* will be invoked in the background.
*
* @param {string} langKey The language to translate to.
* @param {string} translationId Translation ID
* @param {string|array} translationId A token which represents a translation id
* This can be optionally an array of translation ids which
* results that the function's promise returns an object where
* each key is the translation id and the value the translation.
* @param {object} interpolateParams Params
*
* @return {string} translation
*/
$translate.instant = function (translationId, interpolateParams, interpolationId) {

// Duck detection: If the first argument is an array, a bunch of translations was requested.
// The result is an object.
if (angular.isArray(translationId)) {
var results = {};
for (var i = 0, c = translationId.length; i < c; i++) {
results[translationId[i]] = $translate.instant(translationId[i], interpolateParams, interpolationId);
}
return results;
}

if (typeof translationId === 'undefined' || translationId === '') {
return translationId;
}
Expand All @@ -1470,8 +1519,8 @@ angular.module('pascalprecht.translate').provider('$translate', ['$STORAGE_KEY',
if ($fallbackLanguage && $fallbackLanguage.length) {
possibleLangKeys = possibleLangKeys.concat($fallbackLanguage);
}
for (var i = 0, c = possibleLangKeys.length; i < c; i++) {
var possibleLangKey = possibleLangKeys[i];
for (var j = 0, d = possibleLangKeys.length; j < d; j++) {
var possibleLangKey = possibleLangKeys[j];
if ($translationTable[possibleLangKey]) {
if (typeof $translationTable[possibleLangKey][translationId] !== 'undefined') {
result = determineTranslationInstant(translationId, interpolateParams, interpolationId);
Expand Down
25 changes: 25 additions & 0 deletions test/unit/service/translate.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,24 @@ describe('pascalprecht.translate', function () {
expect(value[1]).toEqual('');
});

it('should return translations of multiple translation ids if exists', function () {
var deferred = $q.defer(),
promise = deferred.promise,
value;

promise.then(function (translation) {
value = translation;
});

$translate(["EXISTING_TRANSLATION_ID", "BLANK_VALUE"]).then(function (translations) {
deferred.resolve(translations);
});

$rootScope.$digest();
expect(value.EXISTING_TRANSLATION_ID).toEqual('foo');
expect(value.BLANK_VALUE).toEqual('');
});

it('should return translation, if translation id exists with whitespace', function () {
var deferred = $q.defer(),
promise = deferred.promise,
Expand Down Expand Up @@ -1235,6 +1253,13 @@ describe('pascalprecht.translate', function () {
it('should return empty string if translated string is empty', function () {
expect($translate.instant('BLANK_VALUE')).toEqual('');
});

it('should return translations of multiple translation ids', function () {
var result = $translate.instant(['FOO', 'FOO2', 'BLANK_VALUE']);
expect(result.FOO).toEqual('bar');
expect(result.FOO2).toEqual('FOO2');
expect(result.BLANK_VALUE).toEqual('');
});
});

describe('$translate.instant (with fallback)', function () {
Expand Down

0 comments on commit 612dc27

Please sign in to comment.