Search code examples
angularjsangular-translate

Catch all translated texts on a page before interpolation


Trying to create a possibility for admins to change translations on the current page without editing language files directly.

I'm using angular-translate and I want to catch all translated texts on a current page before interpolation. What I need:

translationId: original-value-without-interpolation

First I changed the translate filter and wrote a custom interpolator to return an object instead of just the interpolated value.

interpolate: function (string, interpolateParams) {
    return {
        string: string,
        interpolateParams: interpolateParams,
        translated: $translateDefaultInterpolation.interpolate(string, interpolateParams)
    };
}

Then inside the translate filter I was able to access both the translationId and original-value.

Soon after that I remembered that I had forgotten everything about directives and who knows what else I might have forgotten that use the same interpolator.

Now it feels like it would be safer to find an alternative where I can catch the translationId and the original-value without editing filters and directives.

Is there perhaps a function that I can hook myself to that I haven't found yet?

Bear in mind that I only want to catch the translations on the current page and I need to get them before {{values}} are replaced.

  • angular 1.2.28
  • angular-translate 1.5.2

Edit: Apparently I can access to the translations table $translateProvider.translations() where I can get values before interpolation. Then I would only need to track down all the translations used on the current page. (Edit2: Unable to access the $translationTable at runtime)


Solution

  • I found a solution.

    First thing I did was to create a custom loader. Which is based on the default one but it also stores all the loaded translations into an object. Which is later passed on.

    Secondly I created a translate filter and directive. Which are also pretty much based on the provided one put with an addition of:

    Filter

    angular.module('app')
    
    .filter('translate', ['$parse', '$translate', 'TranslationsHandler', function ($parse, $translate, TranslationsHandler) {
    
        var translateFilter = function (translationId, interpolateParams, interpolation) {
    
            if ( ! angular.isObject(interpolateParams)) {
                interpolateParams = $parse(interpolateParams)(this);
            }
    
            TranslationsHandler.addViewTranslation($translate.use(), translationId);
    
            return $translate.instant(translationId, interpolateParams, interpolation);
        };
    
        // Since AngularJS 1.3, filters which are not stateless (depending at the scope)
        // have to explicit define this behavior.
        translateFilter.$stateful = true;
    
        return translateFilter;
    }]);
    

    Directive

    angular.module('app')
    
    .directive('translate', ['TranslationsHandler', '$translate', function (TranslationsHandler, $translate) {
    
        return {
            link: function (scope, el, attrs) {
                TranslationsHandler.addViewTranslation($translate.use(), attrs.translate);
            }
        };
    
    }]);
    

    Both of these have the addition of TranslationsHandler.addViewTranslation

    Since I mentioned that I'm trying to make it possible to change translations on page the translations object looks like this:

    var stuff = {
        file: {}, // Data loaded from translation files
        server: {}, // Already changed & saved translations but not yet merged with files
        changed: {}, // Currently changed translations
        current: {}, // Current view translations
        merged: {} // All together in this order: file + server + changed
    }
    // When in translation mode, the merged array is the one passed to angular-translate as the translation table
    // Also on state change I clear the current object so that I can fill that up again
    // And I use  $injector.get('$translate').refresh() this after every blur event on the input to change the translation. This way I am able to display the change on the page.