6

I have the following scenario:

I have a JSON file with this kind of data:

"IOS_TABLET_DOWNLOAD_URL": {
  "type": "string",
  "minLength": "5",
  "title": "IOS_TABLET_DOWNLOAD_URL",
  "description": "$filter('translate')('configuration.IOS_TABLET_DOWNLOAD_URL')"
},

The description field needs to be translated using Angular Translate, I'm injecting the service to my controller like this

ConfigController.$inject = ['$scope', '$filter', '$compile', 'MyService'];
function ConfigController($scope, $filter, $compile, MyService) {

  // And using compile
  $scope.schema = elements; // Where element is the object from MyService
  $compile($scope.schema)($scope);

}

However the $filter is being printed unprocessed as the description in the view

"$filter('translate')('configuration.IOS_TABLET_DOWNLOAD_URL')"

EDIT

I'm using Angular Schema Form to generate the forms. So basically I have in the view something like this

<div ng-controller="FormController">
   <form sf-schema="schema" sf-form="form" sf-model="model"></form>
</div>

How can I do it?

Anthropic
  • 681
  • 1
  • 11
  • 29
DJ22T
  • 1,628
  • 3
  • 34
  • 66

2 Answers2

3

Full working fiddle is at https://jsfiddle.net/dqhwzksx/, its a bit long so I'll take apart the relevant sections here.

The main issue is that neither angular-schema-form nor angular-translate know what to do with "description": "$filter('translate')('configuration.IOS_TABLET_DOWNLOAD_URL')" on their own. We need to do the translation ourselves.

First, our schema now no longer needs to deal the filter itself:

var schema = {
    "type": "object",
    "title": "Sample Schema",
    "properties": {
        "IOS_TABLET_DOWNLOAD_URL": {
          "type": "string",
          "minLength": "5",
          "title": "IOS_TABLET_DOWNLOAD_URL_TITLE",
          "description": "IOS_TABLET_DOWNLOAD_URL_DESCRIPTION"
        }
    }
};

The title and description fields can now directly reference the translation tokens. Next, we're going to write an angular service that will retrieve this schema, but with the translations already made. I think this was the intention of your MyService:

.factory('Schema', function ($q, $translate) {
    return {
        elements: function() {
            var a = [];
            var result = angular.copy(schema);
            angular.forEach(result.properties, function (value, key) {
                a.push($translate([value.title, value.description]).then(
                    function (translations) {
                        value.title = translations[value.title];
                        value.description = translations[value.description];
                    }
                ));
            });
            return $q.all(a).then(function() { return result; });
        }
    }
})

Lets break that down a little bit:

var a = [];
var result = angular.copy(schema);

First, we setup an array a into which we're going to put a bunch of promises (one for each field in the schema), and we make a copy of the original schema since we'll be modifying it.

angular.forEach(result.properties, function (value, key) {
    a.push($translate([value.title, value.description]).then(
        function (translations) {
             value.title = translations[value.title];
             value.description = translations[value.description];
        }
    ));
});

Here we're iterating over each property in the schema (just the one in this sample), requesting a translation for that property's title and description fields. Since $translate returns promises, we need to attach a .then handler to apply the translations direct into the copy of the schema once that promise resolves. Finally, the promise is also appended onto the a array whose job it is to remember the list of all of these promises we're running.

return $q.all(a).then(function() { return result; });

Finally, we wait for all of those promises to have resolved (i.e. the translations are all complete), then return the fully translated schema object.

.controller('FormController',function ($scope, Schema) {

    Schema.elements().then(function (elements) {
        $scope.schema = elements;
    })
    $scope.model = {};
    $scope.form = [
        "IOS_TABLET_DOWNLOAD_URL"
    ];

});

The actual controller itself is rather simple, and not much different from your original. The markup in the template is not altered either.

For fun, try changing the preferred language from en to de:

$translateProvider.preferredLanguage('de');

EDIT

If you wanted to retrieve the schema contents from another file or service, replace the elements method with something like:

elements: function() {
    return $http.get('path/to/schema.json').then(function(response) {
        var a = [];
        var schema = response.data;
        angular.forEach(schema.properties, function (value, key) {
            a.push($translate([value.title, value.description]).then(
                function (translations) {
                    value.title = translations[value.title];
                    value.description = translations[value.description];
                }
            ));
        });
        return $q.all(a).then(function() { return schema; });
    });
}
nicknystrom
  • 749
  • 6
  • 15
0

I just realized, the description property is a string. There's no reason that I can see that it would print anything else. JSON isn't really meant to carry functions, just data (otherwise it'd just be plain JS). Just pass the data that you want to filter and replace it with the final result.

Harris
  • 1,775
  • 16
  • 19
  • What do you mean exactly? – DJ22T Dec 15 '15 at 00:09
  • In `IOS_TABLET_DOWNLOAD_URL`, the property `description` is in quotes; JSON can't transmit usable functions unless you're going to use `eval()` (don't do that). I'd suggest that instead of including a literal string of the function call you want to make, transmit keywords that you can either pick apart in a flowchart or perform some predetermined operation on. – Harris Dec 15 '15 at 14:29
  • I thought about the eval function also, but didn't want to use that at all. but you are right, i must think a proper solution – DJ22T Dec 15 '15 at 19:38
  • Do you know for a fact that the `description` might need to be put through a translate filter, or is the possible type of contents very diverse? At the very least, do you have control over the resource that's providing it in the first place? – Harris Dec 15 '15 at 20:24
  • I have to try it as unknown, the idea is that one integration team (some sort of backend, mod the schema and the form, they also have access to modify the json file with the i18n keys, so it can be N quantity of unknown keys – DJ22T Dec 15 '15 at 21:53
  • A few more questions: 1. Is `IOS_TABLET_DOWNLOAD_URL` a placeholder URL you're giving, or does it refer to some property you need to reference? 2. Are all the instances of it in your example referring to the same thing? 3. If it is a URL, is it supposed to translated directly, or is it supposed to be called, and its _contents_ put through translate? – Harris Dec 16 '15 at 15:02
  • In this specific schema I'm not translating the titles but the description tags. That's the title but as it's a technical title it's not being translated – DJ22T Dec 16 '15 at 15:50